drivers: gpio: ht16k33: add GPIO driver for Holtek HT16K33 LED driver
The HT16K33 is a memory mapping, multifunction LED controller driver. The controller supports up to 128 LEDs (up to 16 rows and 8 commons) and matrix key scan circuit of up to 13x3 keys. This commit adds support for the keyscan functionality of the HT16K33. Signed-off-by: Henrik Brix Andersen <henrik@brixandersen.dk>
This commit is contained in:
parent
f9dd53624c
commit
98cecb3681
10 changed files with 718 additions and 1 deletions
|
@ -110,6 +110,7 @@
|
||||||
/drivers/ethernet/ @jukkar @tbursztyka @pfalcon
|
/drivers/ethernet/ @jukkar @tbursztyka @pfalcon
|
||||||
/drivers/flash/ @nashif
|
/drivers/flash/ @nashif
|
||||||
/drivers/flash/*stm32* @superna9999
|
/drivers/flash/*stm32* @superna9999
|
||||||
|
/drivers/gpio/*ht16k33* @henrikbrixandersen
|
||||||
/drivers/gpio/*stm32* @rsalveti @idlethread
|
/drivers/gpio/*stm32* @rsalveti @idlethread
|
||||||
/drivers/hwinfo/ @alexanderwachter
|
/drivers/hwinfo/ @alexanderwachter
|
||||||
/drivers/i2s/i2s_ll_stm32* @avisconti
|
/drivers/i2s/i2s_ll_stm32* @avisconti
|
||||||
|
@ -195,6 +196,7 @@
|
||||||
/include/display.h @vanwinkeljan
|
/include/display.h @vanwinkeljan
|
||||||
/include/display/ @vanwinkeljan
|
/include/display/ @vanwinkeljan
|
||||||
/include/drivers/bluetooth/ @joerchan @jhedberg @Vudentz
|
/include/drivers/bluetooth/ @joerchan @jhedberg @Vudentz
|
||||||
|
/include/drivers/led/ht16k33.h @henrikbrixandersen
|
||||||
/include/drivers/modem/ @mike-scott
|
/include/drivers/modem/ @mike-scott
|
||||||
/include/drivers/ioapic.h @andrewboie
|
/include/drivers/ioapic.h @andrewboie
|
||||||
/include/drivers/loapic.h @andrewboie
|
/include/drivers/loapic.h @andrewboie
|
||||||
|
|
|
@ -29,6 +29,7 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_SX1509B gpio_sx1509b.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_GPIO_INTEL_APL gpio_intel_apl.c)
|
zephyr_library_sources_ifdef(CONFIG_GPIO_INTEL_APL gpio_intel_apl.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_GPIO_STELLARIS gpio_stellaris.c)
|
zephyr_library_sources_ifdef(CONFIG_GPIO_STELLARIS gpio_stellaris.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_GPIO_RV32M1 gpio_rv32m1.c)
|
zephyr_library_sources_ifdef(CONFIG_GPIO_RV32M1 gpio_rv32m1.c)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_GPIO_HT16K33 gpio_ht16k33.c)
|
||||||
|
|
||||||
zephyr_library_sources_ifdef(CONFIG_GPIO_SHELL gpio_shell.c)
|
zephyr_library_sources_ifdef(CONFIG_GPIO_SHELL gpio_shell.c)
|
||||||
|
|
||||||
|
|
|
@ -74,4 +74,6 @@ source "drivers/gpio/Kconfig.stellaris"
|
||||||
|
|
||||||
source "drivers/gpio/Kconfig.rv32m1"
|
source "drivers/gpio/Kconfig.rv32m1"
|
||||||
|
|
||||||
|
source "drivers/gpio/Kconfig.ht16k33"
|
||||||
|
|
||||||
endif # GPIO
|
endif # GPIO
|
||||||
|
|
30
drivers/gpio/Kconfig.ht16k33
Normal file
30
drivers/gpio/Kconfig.ht16k33
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2019 Henrik Brix Andersen <henrik@brixandersen.dk>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
menuconfig GPIO_HT16K33
|
||||||
|
bool "HT16K33 keyscan driver"
|
||||||
|
depends on HT16K33_KEYSCAN && GPIO
|
||||||
|
help
|
||||||
|
Enable keyscan driver for HT16K33.
|
||||||
|
|
||||||
|
The HT16K33 is a memory mapping, multifunction LED
|
||||||
|
controller driver. The controller supports matrix key scan
|
||||||
|
circuit of up to 13x3 keys.
|
||||||
|
|
||||||
|
The keyscan functionality is exposed as up to 3 GPIO
|
||||||
|
controller drivers, each supporting GPIO callbacks for
|
||||||
|
keyscan event notifications.
|
||||||
|
|
||||||
|
if GPIO_HT16K33
|
||||||
|
|
||||||
|
config GPIO_HT16K33_INIT_PRIORITY
|
||||||
|
int "Driver init priority"
|
||||||
|
default 99
|
||||||
|
help
|
||||||
|
Device driver initialization priority. This driver must be
|
||||||
|
initilized after the HT16K33 LED driver.
|
||||||
|
|
||||||
|
endif #GPIO_HT16K33
|
263
drivers/gpio/gpio_ht16k33.c
Normal file
263
drivers/gpio/gpio_ht16k33.c
Normal file
|
@ -0,0 +1,263 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Henrik Brix Andersen <henrik@brixandersen.dk>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief GPIO driver for the HT16K33 I2C LED driver with keyscan
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gpio.h>
|
||||||
|
#include <zephyr.h>
|
||||||
|
|
||||||
|
#define LOG_LEVEL CONFIG_GPIO_LOG_LEVEL
|
||||||
|
#include <logging/log.h>
|
||||||
|
LOG_MODULE_REGISTER(gpio_ht16k33);
|
||||||
|
|
||||||
|
#include <led/ht16k33.h>
|
||||||
|
|
||||||
|
#include "gpio_utils.h"
|
||||||
|
|
||||||
|
/* HT16K33 size definitions */
|
||||||
|
#define HT16K33_KEYSCAN_ROWS 3
|
||||||
|
|
||||||
|
struct gpio_ht16k33_cfg {
|
||||||
|
char *parent_dev_name;
|
||||||
|
u8_t keyscan_idx;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct gpio_ht16k33_data {
|
||||||
|
struct device *parent;
|
||||||
|
sys_slist_t callbacks;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int gpio_ht16k33_cfg(struct device *dev, int access_op,
|
||||||
|
u32_t pin, int flags)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(dev);
|
||||||
|
ARG_UNUSED(access_op);
|
||||||
|
ARG_UNUSED(pin);
|
||||||
|
|
||||||
|
/* Keyscan is input-only */
|
||||||
|
if ((flags & GPIO_DIR_MASK) != GPIO_DIR_IN) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gpio_ht16k33_write(struct device *dev, int access_op,
|
||||||
|
u32_t pin, u32_t value)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(dev);
|
||||||
|
ARG_UNUSED(access_op);
|
||||||
|
ARG_UNUSED(pin);
|
||||||
|
ARG_UNUSED(value);
|
||||||
|
|
||||||
|
/* Keyscan is input-only */
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gpio_ht16k33_read(struct device *dev, int access_op,
|
||||||
|
u32_t pin, u32_t *value)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(dev);
|
||||||
|
ARG_UNUSED(access_op);
|
||||||
|
ARG_UNUSED(pin);
|
||||||
|
ARG_UNUSED(value);
|
||||||
|
|
||||||
|
/* Keyscan only supports interrupt mode */
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ht16k33_process_keyscan_row_data(struct device *dev,
|
||||||
|
u32_t keys)
|
||||||
|
{
|
||||||
|
struct gpio_ht16k33_data *data = dev->driver_data;
|
||||||
|
|
||||||
|
gpio_fire_callbacks(&data->callbacks, dev, keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gpio_ht16k33_manage_callback(struct device *dev,
|
||||||
|
struct gpio_callback *callback,
|
||||||
|
bool set)
|
||||||
|
{
|
||||||
|
struct gpio_ht16k33_data *data = dev->driver_data;
|
||||||
|
|
||||||
|
return gpio_manage_callback(&data->callbacks, callback, set);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gpio_ht16k33_enable_callback(struct device *dev,
|
||||||
|
int access_op,
|
||||||
|
u32_t pin)
|
||||||
|
{
|
||||||
|
/* All callbacks are always enabled */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gpio_ht16k33_disable_callback(struct device *dev,
|
||||||
|
int access_op,
|
||||||
|
u32_t pin)
|
||||||
|
{
|
||||||
|
/* Individual callbacks can not be disabled */
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32_t gpio_ht16k33_get_pending_int(struct device *dev)
|
||||||
|
{
|
||||||
|
struct gpio_ht16k33_data *data = dev->driver_data;
|
||||||
|
|
||||||
|
return ht16k33_get_pending_int(data->parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gpio_ht16k33_init(struct device *dev)
|
||||||
|
{
|
||||||
|
const struct gpio_ht16k33_cfg *config = dev->config->config_info;
|
||||||
|
struct gpio_ht16k33_data *data = dev->driver_data;
|
||||||
|
|
||||||
|
if (config->keyscan_idx >= HT16K33_KEYSCAN_ROWS) {
|
||||||
|
LOG_ERR("HT16K33 keyscan index out of bounds (%d)",
|
||||||
|
config->keyscan_idx);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Establish reference to parent and vice versa */
|
||||||
|
data->parent = device_get_binding(config->parent_dev_name);
|
||||||
|
if (!data->parent) {
|
||||||
|
LOG_ERR("HT16K33 parent device '%s' not found",
|
||||||
|
config->parent_dev_name);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ht16k33_register_keyscan_device(data->parent, dev,
|
||||||
|
config->keyscan_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct gpio_driver_api gpio_ht16k33_api = {
|
||||||
|
.config = gpio_ht16k33_cfg,
|
||||||
|
.write = gpio_ht16k33_write,
|
||||||
|
.read = gpio_ht16k33_read,
|
||||||
|
.manage_callback = gpio_ht16k33_manage_callback,
|
||||||
|
.enable_callback = gpio_ht16k33_enable_callback,
|
||||||
|
.disable_callback = gpio_ht16k33_disable_callback,
|
||||||
|
.get_pending_int = gpio_ht16k33_get_pending_int,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define GPIO_HT16K33_DEVICE(id) \
|
||||||
|
static const struct gpio_ht16k33_cfg gpio_ht16k33_##id##_cfg = {\
|
||||||
|
.parent_dev_name = \
|
||||||
|
DT_HOLTEK_HT16K33_KEYSCAN_##id##_BUS_NAME, \
|
||||||
|
.keyscan_idx = \
|
||||||
|
DT_HOLTEK_HT16K33_KEYSCAN_##id##_BASE_ADDRESS, \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
static struct gpio_ht16k33_data gpio_ht16k33_##id##_data; \
|
||||||
|
\
|
||||||
|
DEVICE_AND_API_INIT(gpio_ht16k33_##id, \
|
||||||
|
DT_HOLTEK_HT16K33_KEYSCAN_##id##_LABEL, \
|
||||||
|
&gpio_ht16k33_init, \
|
||||||
|
&gpio_ht16k33_##id##_data, \
|
||||||
|
&gpio_ht16k33_##id##_cfg, POST_KERNEL, \
|
||||||
|
CONFIG_GPIO_HT16K33_INIT_PRIORITY, \
|
||||||
|
&gpio_ht16k33_api)
|
||||||
|
|
||||||
|
/* Support up to eight HT16K33 devices, each with three keyscan devices */
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_0
|
||||||
|
GPIO_HT16K33_DEVICE(0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_1
|
||||||
|
GPIO_HT16K33_DEVICE(1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_2
|
||||||
|
GPIO_HT16K33_DEVICE(2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_3
|
||||||
|
GPIO_HT16K33_DEVICE(3);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_4
|
||||||
|
GPIO_HT16K33_DEVICE(4);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_5
|
||||||
|
GPIO_HT16K33_DEVICE(5);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_6
|
||||||
|
GPIO_HT16K33_DEVICE(6);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_7
|
||||||
|
GPIO_HT16K33_DEVICE(7);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_8
|
||||||
|
GPIO_HT16K33_DEVICE(8);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_9
|
||||||
|
GPIO_HT16K33_DEVICE(9);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_10
|
||||||
|
GPIO_HT16K33_DEVICE(10);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_11
|
||||||
|
GPIO_HT16K33_DEVICE(11);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_12
|
||||||
|
GPIO_HT16K33_DEVICE(12);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_13
|
||||||
|
GPIO_HT16K33_DEVICE(13);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_14
|
||||||
|
GPIO_HT16K33_DEVICE(14);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_15
|
||||||
|
GPIO_HT16K33_DEVICE(15);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_16
|
||||||
|
GPIO_HT16K33_DEVICE(16);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_17
|
||||||
|
GPIO_HT16K33_DEVICE(17);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_18
|
||||||
|
GPIO_HT16K33_DEVICE(18);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_19
|
||||||
|
GPIO_HT16K33_DEVICE(19);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_20
|
||||||
|
GPIO_HT16K33_DEVICE(20);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_21
|
||||||
|
GPIO_HT16K33_DEVICE(21);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_22
|
||||||
|
GPIO_HT16K33_DEVICE(22);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_KEYSCAN_23
|
||||||
|
GPIO_HT16K33_DEVICE(23);
|
||||||
|
#endif
|
||||||
|
|
|
@ -13,3 +13,47 @@ menuconfig HT16K33
|
||||||
The HT16K33 is a memory mapping, multifunction LED
|
The HT16K33 is a memory mapping, multifunction LED
|
||||||
controller driver. The controller supports up to 128 LEDs
|
controller driver. The controller supports up to 128 LEDs
|
||||||
(up to 16 rows and 8 commons).
|
(up to 16 rows and 8 commons).
|
||||||
|
|
||||||
|
config HT16K33_KEYSCAN
|
||||||
|
bool "Enable keyscan support"
|
||||||
|
depends on (HT16K33 && GPIO)
|
||||||
|
select GPIO_HT16K33
|
||||||
|
help
|
||||||
|
Enable keyscan child device support in the HT16K33 LED
|
||||||
|
driver.
|
||||||
|
|
||||||
|
The keyscan functionality itself is handled by the
|
||||||
|
HT16K33 GPIO driver.
|
||||||
|
|
||||||
|
if HT16K33_KEYSCAN
|
||||||
|
|
||||||
|
config HT16K33_KEYSCAN_IRQ_THREAD_STACK_SIZE
|
||||||
|
int "Stack size for keyscan interrupt request handler thread"
|
||||||
|
default 400
|
||||||
|
help
|
||||||
|
Size of the stack used for internal thread for keyscan
|
||||||
|
interrupt processing.
|
||||||
|
|
||||||
|
config HT16K33_KEYSCAN_IRQ_THREAD_PRIO
|
||||||
|
int "Priority for keyscan interrupt request handler thread"
|
||||||
|
default 2
|
||||||
|
help
|
||||||
|
Priority level for internal thread for keyscan interrupt
|
||||||
|
processing.
|
||||||
|
|
||||||
|
config HT16K33_KEYSCAN_DEBOUNCE_MSEC
|
||||||
|
int "Keyscan debounce interval in milliseconds"
|
||||||
|
default 50
|
||||||
|
range 20 1000
|
||||||
|
help
|
||||||
|
Keyscan debounce interval in milliseconds.
|
||||||
|
|
||||||
|
config HT16K33_KEYSCAN_POLL_MSEC
|
||||||
|
int "Keyscan poll interval in milliseconds"
|
||||||
|
default 200
|
||||||
|
range 20 10000
|
||||||
|
help
|
||||||
|
Keyscan poll interval in milliseconds. Polling is only used
|
||||||
|
if no interrupt line is present.
|
||||||
|
|
||||||
|
endif #HT16K33_KEYSCAN
|
||||||
|
|
|
@ -9,14 +9,19 @@
|
||||||
* @brief LED driver for the HT16K33 I2C LED driver with keyscan
|
* @brief LED driver for the HT16K33 I2C LED driver with keyscan
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <gpio.h>
|
||||||
#include <i2c.h>
|
#include <i2c.h>
|
||||||
|
#include <kernel.h>
|
||||||
#include <led.h>
|
#include <led.h>
|
||||||
|
#include <misc/byteorder.h>
|
||||||
#include <zephyr.h>
|
#include <zephyr.h>
|
||||||
|
|
||||||
#define LOG_LEVEL CONFIG_LED_LOG_LEVEL
|
#define LOG_LEVEL CONFIG_LED_LOG_LEVEL
|
||||||
#include <logging/log.h>
|
#include <logging/log.h>
|
||||||
LOG_MODULE_REGISTER(ht16k33);
|
LOG_MODULE_REGISTER(ht16k33);
|
||||||
|
|
||||||
|
#include <led/ht16k33.h>
|
||||||
|
|
||||||
#include "led_context.h"
|
#include "led_context.h"
|
||||||
|
|
||||||
/* HT16K33 commands and options */
|
/* HT16K33 commands and options */
|
||||||
|
@ -53,10 +58,19 @@ LOG_MODULE_REGISTER(ht16k33);
|
||||||
#define HT16K33_DISP_DATA_SIZE HT16K33_DISP_ROWS
|
#define HT16K33_DISP_DATA_SIZE HT16K33_DISP_ROWS
|
||||||
#define HT16K33_DISP_SEGMENTS (HT16K33_DISP_ROWS * HT16K33_DISP_COLS)
|
#define HT16K33_DISP_SEGMENTS (HT16K33_DISP_ROWS * HT16K33_DISP_COLS)
|
||||||
#define HT16K33_DIMMING_LEVELS 16
|
#define HT16K33_DIMMING_LEVELS 16
|
||||||
|
#define HT16K33_KEYSCAN_ROWS 3
|
||||||
|
#define HT16K33_KEYSCAN_COLS 13
|
||||||
|
#define HT16K33_KEYSCAN_DATA_SIZE 6
|
||||||
|
|
||||||
struct ht16k33_cfg {
|
struct ht16k33_cfg {
|
||||||
char *i2c_dev_name;
|
char *i2c_dev_name;
|
||||||
u16_t i2c_addr;
|
u16_t i2c_addr;
|
||||||
|
bool irq_enabled;
|
||||||
|
#ifdef CONFIG_HT16K33_KEYSCAN
|
||||||
|
char *irq_dev_name;
|
||||||
|
u32_t irq_pin;
|
||||||
|
int irq_flags;
|
||||||
|
#endif /* CONFIG_HT16K33_KEYSCAN */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ht16k33_data {
|
struct ht16k33_data {
|
||||||
|
@ -64,6 +78,18 @@ struct ht16k33_data {
|
||||||
struct led_data dev_data;
|
struct led_data dev_data;
|
||||||
/* Shadow buffer for the display data RAM */
|
/* Shadow buffer for the display data RAM */
|
||||||
u8_t buffer[HT16K33_DISP_DATA_SIZE];
|
u8_t buffer[HT16K33_DISP_DATA_SIZE];
|
||||||
|
#ifdef CONFIG_HT16K33_KEYSCAN
|
||||||
|
struct k_mutex lock;
|
||||||
|
struct device *children[HT16K33_KEYSCAN_ROWS];
|
||||||
|
struct gpio_callback irq_cb;
|
||||||
|
struct k_thread irq_thread;
|
||||||
|
struct k_sem irq_sem;
|
||||||
|
struct k_timer timer;
|
||||||
|
u16_t key_state[HT16K33_KEYSCAN_ROWS];
|
||||||
|
|
||||||
|
K_THREAD_STACK_MEMBER(irq_thread_stack,
|
||||||
|
CONFIG_HT16K33_KEYSCAN_IRQ_THREAD_STACK_SIZE);
|
||||||
|
#endif /* CONFIG_HT16K33_KEYSCAN */
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ht16k33_led_blink(struct device *dev, u32_t led,
|
static int ht16k33_led_blink(struct device *dev, u32_t led,
|
||||||
|
@ -175,6 +201,122 @@ static int ht16k33_led_off(struct device *dev, u32_t led)
|
||||||
return ht16k33_led_set_state(dev, led, false);
|
return ht16k33_led_set_state(dev, led, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_HT16K33_KEYSCAN
|
||||||
|
u32_t ht16k33_get_pending_int(struct device *dev)
|
||||||
|
{
|
||||||
|
const struct ht16k33_cfg *config = dev->config->config_info;
|
||||||
|
struct ht16k33_data *data = dev->driver_data;
|
||||||
|
u8_t cmd;
|
||||||
|
u8_t flag;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
cmd = HT16K33_CMD_INT_FLAG_ADDR;
|
||||||
|
err = i2c_write_read(data->i2c, config->i2c_addr, &cmd, sizeof(cmd),
|
||||||
|
&flag, sizeof(flag));
|
||||||
|
if (err) {
|
||||||
|
LOG_ERR("Failed to to read HT16K33 IRQ flag");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (flag ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ht16k33_process_keyscan_data(struct device *dev)
|
||||||
|
{
|
||||||
|
const struct ht16k33_cfg *config = dev->config->config_info;
|
||||||
|
struct ht16k33_data *data = dev->driver_data;
|
||||||
|
u8_t keys[HT16K33_KEYSCAN_DATA_SIZE];
|
||||||
|
bool pressed;
|
||||||
|
u16_t row;
|
||||||
|
u16_t new;
|
||||||
|
int err;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
err = i2c_burst_read(data->i2c, config->i2c_addr,
|
||||||
|
HT16K33_CMD_KEY_DATA_ADDR, keys,
|
||||||
|
sizeof(keys));
|
||||||
|
if (err) {
|
||||||
|
LOG_ERR("Failed to to read HT16K33 key data (err %d)", err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
k_mutex_lock(&data->lock, K_FOREVER);
|
||||||
|
for (i = 0; i < HT16K33_KEYSCAN_ROWS; i++) {
|
||||||
|
row = sys_get_le16(&keys[i * 2]);
|
||||||
|
if (row) {
|
||||||
|
pressed = true;
|
||||||
|
new = data->key_state[i] ^ row;
|
||||||
|
new &= row;
|
||||||
|
if (data->children[i] && new) {
|
||||||
|
ht16k33_process_keyscan_row_data(
|
||||||
|
data->children[i], new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data->key_state[i] = row;
|
||||||
|
}
|
||||||
|
k_mutex_unlock(&data->lock);
|
||||||
|
|
||||||
|
return pressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ht16k33_irq_thread(struct device *dev)
|
||||||
|
{
|
||||||
|
struct ht16k33_data *data = dev->driver_data;
|
||||||
|
bool pressed;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
k_sem_take(&data->irq_sem, K_FOREVER);
|
||||||
|
|
||||||
|
do {
|
||||||
|
k_sem_reset(&data->irq_sem);
|
||||||
|
pressed = ht16k33_process_keyscan_data(dev);
|
||||||
|
k_sleep(CONFIG_HT16K33_KEYSCAN_DEBOUNCE_MSEC);
|
||||||
|
} while (pressed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ht16k33_irq_callback(struct device *gpiob,
|
||||||
|
struct gpio_callback *cb, u32_t pins)
|
||||||
|
{
|
||||||
|
struct ht16k33_data *data;
|
||||||
|
|
||||||
|
ARG_UNUSED(gpiob);
|
||||||
|
ARG_UNUSED(pins);
|
||||||
|
|
||||||
|
data = CONTAINER_OF(cb, struct ht16k33_data, irq_cb);
|
||||||
|
k_sem_give(&data->irq_sem);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ht16k33_timer_callback(struct k_timer *timer)
|
||||||
|
{
|
||||||
|
struct ht16k33_data *data;
|
||||||
|
|
||||||
|
data = CONTAINER_OF(timer, struct ht16k33_data, timer);
|
||||||
|
k_sem_give(&data->irq_sem);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ht16k33_register_keyscan_device(struct device *parent,
|
||||||
|
struct device *child,
|
||||||
|
u8_t keyscan_idx)
|
||||||
|
{
|
||||||
|
struct ht16k33_data *data = parent->driver_data;
|
||||||
|
|
||||||
|
k_mutex_lock(&data->lock, K_FOREVER);
|
||||||
|
|
||||||
|
if (data->children[keyscan_idx]) {
|
||||||
|
k_mutex_unlock(&data->lock);
|
||||||
|
LOG_ERR("HT16K33 keyscan device %d already registered",
|
||||||
|
keyscan_idx);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->children[keyscan_idx] = child;
|
||||||
|
k_mutex_unlock(&data->lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_HT16K33_KEYSCAN */
|
||||||
|
|
||||||
static int ht16k33_init(struct device *dev)
|
static int ht16k33_init(struct device *dev)
|
||||||
{
|
{
|
||||||
const struct ht16k33_cfg *config = dev->config->config_info;
|
const struct ht16k33_cfg *config = dev->config->config_info;
|
||||||
|
@ -231,6 +373,86 @@ static int ht16k33_init(struct device *dev)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_HT16K33_KEYSCAN
|
||||||
|
memset(&data->children, 0, sizeof(data->children));
|
||||||
|
k_mutex_init(&data->lock);
|
||||||
|
k_sem_init(&data->irq_sem, 0, 1);
|
||||||
|
|
||||||
|
/* Configure interrupt */
|
||||||
|
if (config->irq_enabled) {
|
||||||
|
struct device *irq_dev;
|
||||||
|
u8_t keys[HT16K33_KEYSCAN_DATA_SIZE];
|
||||||
|
|
||||||
|
irq_dev = device_get_binding(config->irq_dev_name);
|
||||||
|
if (!irq_dev) {
|
||||||
|
LOG_ERR("IRQ device '%s' not found",
|
||||||
|
config->irq_dev_name);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gpio_pin_configure(irq_dev, config->irq_pin,
|
||||||
|
GPIO_DIR_IN | GPIO_INT |
|
||||||
|
GPIO_INT_EDGE | config->irq_flags);
|
||||||
|
if (err) {
|
||||||
|
LOG_ERR("Failed to configure IRQ pin (err %d)", err);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_init_callback(&data->irq_cb, &ht16k33_irq_callback,
|
||||||
|
BIT(config->irq_pin));
|
||||||
|
|
||||||
|
err = gpio_add_callback(irq_dev, &data->irq_cb);
|
||||||
|
if (err) {
|
||||||
|
LOG_ERR("Failed to add IRQ callback (err %d)", err);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable interrupt pin */
|
||||||
|
cmd[0] = HT16K33_CMD_ROW_INT_SET;
|
||||||
|
if (config->irq_flags & GPIO_INT_ACTIVE_HIGH) {
|
||||||
|
cmd[0] |= HT16K33_OPT_INT_HIGH;
|
||||||
|
} else {
|
||||||
|
cmd[0] |= HT16K33_OPT_INT_LOW;
|
||||||
|
}
|
||||||
|
if (i2c_write(data->i2c, cmd, 1, config->i2c_addr)) {
|
||||||
|
LOG_ERR("Enabling HT16K33 IRQ output failed");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flush key data before enabling interrupt */
|
||||||
|
err = i2c_burst_read(data->i2c, config->i2c_addr,
|
||||||
|
HT16K33_CMD_KEY_DATA_ADDR, keys, sizeof(keys));
|
||||||
|
if (err) {
|
||||||
|
LOG_ERR("Failed to to read HT16K33 key data");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gpio_pin_enable_callback(irq_dev, config->irq_pin);
|
||||||
|
if (err) {
|
||||||
|
LOG_ERR("Failed to enable IRQ callback (err %d)", err);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* No interrupt pin, enable ROW15 */
|
||||||
|
cmd[0] = HT16K33_CMD_ROW_INT_SET | HT16K33_OPT_ROW;
|
||||||
|
if (i2c_write(data->i2c, cmd, 1, config->i2c_addr)) {
|
||||||
|
LOG_ERR("Enabling HT16K33 ROW15 output failed");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup timer for polling key data */
|
||||||
|
k_timer_init(&data->timer, ht16k33_timer_callback, NULL);
|
||||||
|
k_timer_start(&data->timer, 0,
|
||||||
|
CONFIG_HT16K33_KEYSCAN_POLL_MSEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
k_thread_create(&data->irq_thread, data->irq_thread_stack,
|
||||||
|
CONFIG_HT16K33_KEYSCAN_IRQ_THREAD_STACK_SIZE,
|
||||||
|
(k_thread_entry_t)ht16k33_irq_thread, dev, NULL, NULL,
|
||||||
|
K_PRIO_COOP(CONFIG_HT16K33_KEYSCAN_IRQ_THREAD_PRIO),
|
||||||
|
0, K_NO_WAIT);
|
||||||
|
#endif /* CONFIG_HT16K33_KEYSCAN */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,6 +467,7 @@ static const struct led_driver_api ht16k33_leds_api = {
|
||||||
static const struct ht16k33_cfg ht16k33_##id##_cfg = { \
|
static const struct ht16k33_cfg ht16k33_##id##_cfg = { \
|
||||||
.i2c_dev_name = DT_HOLTEK_HT16K33_##id##_BUS_NAME, \
|
.i2c_dev_name = DT_HOLTEK_HT16K33_##id##_BUS_NAME, \
|
||||||
.i2c_addr = DT_HOLTEK_HT16K33_##id##_BASE_ADDRESS, \
|
.i2c_addr = DT_HOLTEK_HT16K33_##id##_BASE_ADDRESS, \
|
||||||
|
.irq_enabled = false, \
|
||||||
}; \
|
}; \
|
||||||
\
|
\
|
||||||
static struct ht16k33_data ht16k33_##id##_data; \
|
static struct ht16k33_data ht16k33_##id##_data; \
|
||||||
|
@ -254,36 +477,91 @@ DEVICE_AND_API_INIT(ht16k33_##id, DT_HOLTEK_HT16K33_##id##_LABEL, \
|
||||||
&ht16k33_##id##_cfg, POST_KERNEL, \
|
&ht16k33_##id##_cfg, POST_KERNEL, \
|
||||||
CONFIG_LED_INIT_PRIORITY, &ht16k33_leds_api)
|
CONFIG_LED_INIT_PRIORITY, &ht16k33_leds_api)
|
||||||
|
|
||||||
|
#ifdef CONFIG_HT16K33_KEYSCAN
|
||||||
|
#define HT16K33_DEVICE_WITH_IRQ(id) \
|
||||||
|
static const struct ht16k33_cfg ht16k33_##id##_cfg = { \
|
||||||
|
.i2c_dev_name = DT_HOLTEK_HT16K33_##id##_BUS_NAME, \
|
||||||
|
.i2c_addr = DT_HOLTEK_HT16K33_##id##_BASE_ADDRESS, \
|
||||||
|
.irq_enabled = true, \
|
||||||
|
.irq_dev_name = \
|
||||||
|
DT_HOLTEK_HT16K33_##id##_IRQ_GPIOS_CONTROLLER, \
|
||||||
|
.irq_pin = DT_HOLTEK_HT16K33_##id##_IRQ_GPIOS_PIN, \
|
||||||
|
.irq_flags = \
|
||||||
|
DT_HOLTEK_HT16K33_##id##_IRQ_GPIOS_FLAGS, \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
static struct ht16k33_data ht16k33_##id##_data; \
|
||||||
|
\
|
||||||
|
DEVICE_AND_API_INIT(ht16k33_##id, DT_HOLTEK_HT16K33_##id##_LABEL, \
|
||||||
|
&ht16k33_init, &ht16k33_##id##_data, \
|
||||||
|
&ht16k33_##id##_cfg, POST_KERNEL, \
|
||||||
|
CONFIG_LED_INIT_PRIORITY, &ht16k33_leds_api)
|
||||||
|
#else /* ! CONFIG_HT16K33_KEYSCAN */
|
||||||
|
#define HT16K33_DEVICE_WITH_IRQ(id) HT16K33_DEVICE(id)
|
||||||
|
#endif /* ! CONFIG_HT16K33_KEYSCAN */
|
||||||
|
|
||||||
/* Support up to eight HT16K33 devices */
|
/* Support up to eight HT16K33 devices */
|
||||||
|
|
||||||
#ifdef DT_HOLTEK_HT16K33_0
|
#ifdef DT_HOLTEK_HT16K33_0
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_0_IRQ_GPIOS_CONTROLLER
|
||||||
|
HT16K33_DEVICE_WITH_IRQ(0);
|
||||||
|
#else
|
||||||
HT16K33_DEVICE(0);
|
HT16K33_DEVICE(0);
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DT_HOLTEK_HT16K33_1
|
#ifdef DT_HOLTEK_HT16K33_1
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_1_IRQ_GPIOS_CONTROLLER
|
||||||
|
HT16K33_DEVICE_WITH_IRQ(1);
|
||||||
|
#else
|
||||||
HT16K33_DEVICE(1);
|
HT16K33_DEVICE(1);
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DT_HOLTEK_HT16K33_2
|
#ifdef DT_HOLTEK_HT16K33_2
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_2_IRQ_GPIOS_CONTROLLER
|
||||||
|
HT16K33_DEVICE_WITH_IRQ(2);
|
||||||
|
#else
|
||||||
HT16K33_DEVICE(2);
|
HT16K33_DEVICE(2);
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DT_HOLTEK_HT16K33_3
|
#ifdef DT_HOLTEK_HT16K33_3
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_3_IRQ_GPIOS_CONTROLLER
|
||||||
|
HT16K33_DEVICE_WITH_IRQ(3);
|
||||||
|
#else
|
||||||
HT16K33_DEVICE(3);
|
HT16K33_DEVICE(3);
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DT_HOLTEK_HT16K33_4
|
#ifdef DT_HOLTEK_HT16K33_4
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_4_IRQ_GPIOS_CONTROLLER
|
||||||
|
HT16K33_DEVICE_WITH_IRQ(4);
|
||||||
|
#else
|
||||||
HT16K33_DEVICE(4);
|
HT16K33_DEVICE(4);
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DT_HOLTEK_HT16K33_5
|
#ifdef DT_HOLTEK_HT16K33_5
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_5_IRQ_GPIOS_CONTROLLER
|
||||||
|
HT16K33_DEVICE_WITH_IRQ(5);
|
||||||
|
#else
|
||||||
HT16K33_DEVICE(5);
|
HT16K33_DEVICE(5);
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DT_HOLTEK_HT16K33_6
|
#ifdef DT_HOLTEK_HT16K33_6
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_6_IRQ_GPIOS_CONTROLLER
|
||||||
|
HT16K33_DEVICE_WITH_IRQ(6);
|
||||||
|
#else
|
||||||
HT16K33_DEVICE(6);
|
HT16K33_DEVICE(6);
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef DT_HOLTEK_HT16K33_7
|
#ifdef DT_HOLTEK_HT16K33_7
|
||||||
|
#ifdef DT_HOLTEK_HT16K33_7_IRQ_GPIOS_CONTROLLER
|
||||||
|
HT16K33_DEVICE_WITH_IRQ(7);
|
||||||
|
#else
|
||||||
HT16K33_DEVICE(7);
|
HT16K33_DEVICE(7);
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
34
dts/bindings/gpio/holtek,ht16k33-keyscan.yaml
Normal file
34
dts/bindings/gpio/holtek,ht16k33-keyscan.yaml
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
---
|
||||||
|
title: Holtek HT16K33 LED Driver With Keyscan
|
||||||
|
version: 0.1
|
||||||
|
|
||||||
|
description: Holtek HT16K33 Keyscan binding
|
||||||
|
|
||||||
|
parent:
|
||||||
|
bus: ht16k33
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
type: string
|
||||||
|
category: required
|
||||||
|
description: compatible strings
|
||||||
|
constraint: "holtek,ht16k33-keyscan"
|
||||||
|
generation: define
|
||||||
|
reg:
|
||||||
|
type: array
|
||||||
|
description: Keyscan row on the HT16K33 (KSx)
|
||||||
|
generation: define
|
||||||
|
category: required
|
||||||
|
label:
|
||||||
|
type: string
|
||||||
|
category: required
|
||||||
|
description: Human readable string describing the device (used by Zephyr for API name)
|
||||||
|
generation: define
|
||||||
|
|
||||||
|
cell_string: GPIO
|
||||||
|
|
||||||
|
"#cells":
|
||||||
|
- pin
|
||||||
|
- flags
|
||||||
|
|
||||||
|
...
|
|
@ -7,6 +7,9 @@ description: Holtek HT16K33 LEDs binding
|
||||||
inherits:
|
inherits:
|
||||||
!include i2c-device.yaml
|
!include i2c-device.yaml
|
||||||
|
|
||||||
|
child:
|
||||||
|
bus: ht16k33
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
type: string
|
type: string
|
||||||
|
@ -14,10 +17,23 @@ properties:
|
||||||
description: compatible strings
|
description: compatible strings
|
||||||
constraint: "holtek,ht16k33"
|
constraint: "holtek,ht16k33"
|
||||||
generation: define
|
generation: define
|
||||||
|
"#address-cells":
|
||||||
|
type: int
|
||||||
|
category: required
|
||||||
|
description: should be 1.
|
||||||
|
"#size-cells":
|
||||||
|
type: int
|
||||||
|
category: required
|
||||||
|
description: should be 0.
|
||||||
label:
|
label:
|
||||||
type: string
|
type: string
|
||||||
category: required
|
category: required
|
||||||
description: Human readable string describing the device (used by Zephyr for API name)
|
description: Human readable string describing the device (used by Zephyr for API name)
|
||||||
generation: define
|
generation: define
|
||||||
|
irq-gpios:
|
||||||
|
type: compound
|
||||||
|
category: optional
|
||||||
|
description: IRQ pin
|
||||||
|
generation: define, use-prop-name
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
47
include/drivers/led/ht16k33.h
Normal file
47
include/drivers/led/ht16k33.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Henrik Brix Andersen <henrik@brixandersen.dk>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef ZEPHYR_INCLUDE_DRIVERS_LED_HT16K33_H_
|
||||||
|
#define ZEPHYR_INCLUDE_DRIVERS_LED_HT16K33_H_
|
||||||
|
|
||||||
|
#include <device.h>
|
||||||
|
#include <zephyr/types.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a HT16K33 keyscan device to be notified of relevant
|
||||||
|
* keyscan events by the keyscan interrupt thread in the HT16K33
|
||||||
|
* parent driver.
|
||||||
|
*
|
||||||
|
* @param parent HT16K33 parent device.
|
||||||
|
* @param child HT16K33 keyscan child device.
|
||||||
|
* @param keyscan_idx Index of the keyscan line handled by the keyscan
|
||||||
|
* child device (0, 1, or 2).
|
||||||
|
* @return 0 if successful, negative errne code on failure.
|
||||||
|
*/
|
||||||
|
int ht16k33_register_keyscan_device(struct device *parent,
|
||||||
|
struct device *child,
|
||||||
|
u8_t keyscan_idx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a HT16K33 keyscan interrupt is pending.
|
||||||
|
*
|
||||||
|
* @param parent HT16K33 parent device.
|
||||||
|
* @return status != 0 if an interrupt is pending.
|
||||||
|
*/
|
||||||
|
u32_t ht16k33_get_pending_int(struct device *parent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatch keyscan row data from a keyscan event to be handled by a
|
||||||
|
* HT16K33 keyscan GPIO child device.
|
||||||
|
*
|
||||||
|
* @param child HT16K33 keyscan child device.
|
||||||
|
* @param keys Bitmask of key state for the row.
|
||||||
|
*/
|
||||||
|
void ht16k33_process_keyscan_row_data(struct device *child,
|
||||||
|
u32_t keys);
|
||||||
|
|
||||||
|
#endif /* ZEPHYR_INCLUDE_DRIVERS_LED_HT16K33_H_ */
|
Loading…
Add table
Add a link
Reference in a new issue