drivers: ht16k33: convert keyscan driver from gpio API to kscan API
Convert the keyscan portion of the Holtek HT16K33 driver to adhere to the kscan API instead of the GPIO API. When this driver was introduced the kscan API was not present. The keyscan driver was therefore implemented as a GPIO interrupt driver. Signed-off-by: Henrik Brix Andersen <henrik@brixandersen.dk>
This commit is contained in:
parent
7e52ee7fe1
commit
588d22a755
|
@ -219,7 +219,6 @@
|
|||
/drivers/flash/ @nashif @nvlsianpu
|
||||
/drivers/flash/*nrf* @nvlsianpu
|
||||
/drivers/gpio/ @mnkp
|
||||
/drivers/gpio/*ht16k33* @henrikbrixandersen
|
||||
/drivers/gpio/*lmp90xxx* @henrikbrixandersen
|
||||
/drivers/gpio/*stm32* @erwango
|
||||
/drivers/gpio/*eos_s3* @wtatarski @kowalewskijan @kgugala
|
||||
|
@ -250,6 +249,7 @@
|
|||
/drivers/ipm/ipm_nrfx_ipc.h @masz-nordic @ioannisg
|
||||
/drivers/ipm/ipm_stm32_ipcc.c @arnopo
|
||||
/drivers/kscan/ @albertofloyd @franciscomunoz @scottwcpg
|
||||
/drivers/kscan/*ht16k33* @henrikbrixandersen
|
||||
/drivers/led/ @Mani-Sadhasivam
|
||||
/drivers/led_strip/ @mbolivar-nordic
|
||||
/drivers/lora/ @Mani-Sadhasivam
|
||||
|
|
|
@ -27,7 +27,6 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_SX1509B gpio_sx1509b.c)
|
|||
zephyr_library_sources_ifdef(CONFIG_GPIO_INTEL gpio_intel.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_HT16K33 gpio_ht16k33.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_GPIO_LMP90XXX gpio_lmp90xxx.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_GPIO_LITEX gpio_litex.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_GPIO_LPC11U6X gpio_lpc11u6x.c)
|
||||
|
|
|
@ -69,8 +69,6 @@ source "drivers/gpio/Kconfig.stellaris"
|
|||
|
||||
source "drivers/gpio/Kconfig.rv32m1"
|
||||
|
||||
source "drivers/gpio/Kconfig.ht16k33"
|
||||
|
||||
source "drivers/gpio/Kconfig.lmp90xxx"
|
||||
|
||||
source "drivers/gpio/Kconfig.litex"
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
# 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
|
||||
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.
|
||||
|
||||
config GPIO_HT16K33_INIT_PRIORITY
|
||||
int "Driver init priority"
|
||||
default 99
|
||||
depends on GPIO_HT16K33
|
||||
help
|
||||
Device driver initialization priority. This driver must be
|
||||
initialized after the HT16K33 LED driver.
|
|
@ -1,204 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Henrik Brix Andersen <henrik@brixandersen.dk>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT holtek_ht16k33_keyscan
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief GPIO driver for the HT16K33 I2C LED driver with keyscan
|
||||
*/
|
||||
|
||||
#include <drivers/gpio.h>
|
||||
#include <zephyr.h>
|
||||
|
||||
#define LOG_LEVEL CONFIG_GPIO_LOG_LEVEL
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_REGISTER(gpio_ht16k33);
|
||||
|
||||
#include <drivers/led/ht16k33.h>
|
||||
|
||||
#include "gpio_utils.h"
|
||||
|
||||
/* HT16K33 size definitions */
|
||||
#define HT16K33_KEYSCAN_ROWS 3
|
||||
|
||||
struct gpio_ht16k33_cfg {
|
||||
/* gpio_driver_config needs to be first */
|
||||
struct gpio_driver_config common;
|
||||
char *parent_dev_name;
|
||||
uint8_t keyscan_idx;
|
||||
};
|
||||
|
||||
struct gpio_ht16k33_data {
|
||||
/* gpio_driver_data needs to be first */
|
||||
struct gpio_driver_data common;
|
||||
const struct device *parent;
|
||||
sys_slist_t callbacks;
|
||||
};
|
||||
|
||||
static int gpio_ht16k33_cfg(const struct device *dev,
|
||||
gpio_pin_t pin,
|
||||
gpio_flags_t flags)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
ARG_UNUSED(pin);
|
||||
|
||||
/* Keyscan is input-only */
|
||||
if (((flags & (GPIO_INPUT | GPIO_OUTPUT)) == GPIO_DISCONNECTED)
|
||||
|| ((flags & GPIO_OUTPUT) != 0)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_ht16k33_port_get_raw(const struct device *port,
|
||||
gpio_port_value_t *value)
|
||||
{
|
||||
ARG_UNUSED(port);
|
||||
ARG_UNUSED(value);
|
||||
|
||||
/* Keyscan only supports interrupt mode */
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int gpio_ht16k33_port_set_masked_raw(const struct device *port,
|
||||
gpio_port_pins_t mask,
|
||||
gpio_port_value_t value)
|
||||
{
|
||||
ARG_UNUSED(port);
|
||||
ARG_UNUSED(mask);
|
||||
ARG_UNUSED(value);
|
||||
|
||||
/* Keyscan is input-only */
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int gpio_ht16k33_port_set_bits_raw(const struct device *port,
|
||||
gpio_port_pins_t pins)
|
||||
{
|
||||
ARG_UNUSED(port);
|
||||
ARG_UNUSED(pins);
|
||||
|
||||
/* Keyscan is input-only */
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int gpio_ht16k33_port_clear_bits_raw(const struct device *port,
|
||||
gpio_port_pins_t pins)
|
||||
{
|
||||
ARG_UNUSED(port);
|
||||
ARG_UNUSED(pins);
|
||||
|
||||
/* Keyscan is input-only */
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int gpio_ht16k33_port_toggle_bits(const struct device *port,
|
||||
gpio_port_pins_t pins)
|
||||
{
|
||||
ARG_UNUSED(port);
|
||||
ARG_UNUSED(pins);
|
||||
|
||||
/* Keyscan is input-only */
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int gpio_ht16k33_pin_interrupt_configure(const struct device *port,
|
||||
gpio_pin_t pin,
|
||||
enum gpio_int_mode int_mode,
|
||||
enum gpio_int_trig int_trig)
|
||||
{
|
||||
ARG_UNUSED(port);
|
||||
ARG_UNUSED(pin);
|
||||
ARG_UNUSED(int_mode);
|
||||
ARG_UNUSED(int_trig);
|
||||
|
||||
/* Interrupts are always enabled */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ht16k33_process_keyscan_row_data(const struct device *dev,
|
||||
uint32_t keys)
|
||||
{
|
||||
struct gpio_ht16k33_data *data = dev->data;
|
||||
|
||||
gpio_fire_callbacks(&data->callbacks, dev, keys);
|
||||
}
|
||||
|
||||
static int gpio_ht16k33_manage_callback(const struct device *dev,
|
||||
struct gpio_callback *callback,
|
||||
bool set)
|
||||
{
|
||||
struct gpio_ht16k33_data *data = dev->data;
|
||||
|
||||
return gpio_manage_callback(&data->callbacks, callback, set);
|
||||
}
|
||||
|
||||
static uint32_t gpio_ht16k33_get_pending_int(const struct device *dev)
|
||||
{
|
||||
struct gpio_ht16k33_data *data = dev->data;
|
||||
|
||||
return ht16k33_get_pending_int(data->parent);
|
||||
}
|
||||
|
||||
static int gpio_ht16k33_init(const struct device *dev)
|
||||
{
|
||||
const struct gpio_ht16k33_cfg *config = dev->config;
|
||||
struct gpio_ht16k33_data *data = dev->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 = {
|
||||
.pin_configure = gpio_ht16k33_cfg,
|
||||
.port_get_raw = gpio_ht16k33_port_get_raw,
|
||||
.port_set_masked_raw = gpio_ht16k33_port_set_masked_raw,
|
||||
.port_set_bits_raw = gpio_ht16k33_port_set_bits_raw,
|
||||
.port_clear_bits_raw = gpio_ht16k33_port_clear_bits_raw,
|
||||
.port_toggle_bits = gpio_ht16k33_port_toggle_bits,
|
||||
.pin_interrupt_configure = gpio_ht16k33_pin_interrupt_configure,
|
||||
.manage_callback = gpio_ht16k33_manage_callback,
|
||||
.get_pending_int = gpio_ht16k33_get_pending_int,
|
||||
};
|
||||
|
||||
#define GPIO_HT16K33_DEVICE(id) \
|
||||
static const struct gpio_ht16k33_cfg gpio_ht16k33_##id##_cfg = {\
|
||||
.common = { \
|
||||
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_NGPIOS(13), \
|
||||
}, \
|
||||
.parent_dev_name = \
|
||||
DT_INST_BUS_LABEL(id), \
|
||||
.keyscan_idx = \
|
||||
DT_INST_REG_ADDR(id), \
|
||||
}; \
|
||||
\
|
||||
static struct gpio_ht16k33_data gpio_ht16k33_##id##_data; \
|
||||
\
|
||||
DEVICE_DT_INST_DEFINE(id, \
|
||||
&gpio_ht16k33_init, \
|
||||
NULL, \
|
||||
&gpio_ht16k33_##id##_data, \
|
||||
&gpio_ht16k33_##id##_cfg, POST_KERNEL, \
|
||||
CONFIG_GPIO_HT16K33_INIT_PRIORITY, \
|
||||
&gpio_ht16k33_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(GPIO_HT16K33_DEVICE)
|
|
@ -5,5 +5,6 @@ zephyr_library()
|
|||
zephyr_library_sources_ifdef(CONFIG_KSCAN_FT5336 kscan_ft5336.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_KSCAN_XEC kscan_mchp_xec.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_KSCAN_SDL kscan_sdl.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_KSCAN_HT16K33 kscan_ht16k33.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_USERSPACE kscan_handlers.c)
|
||||
|
|
|
@ -13,6 +13,7 @@ if KSCAN
|
|||
source "drivers/kscan/Kconfig.ft5336"
|
||||
source "drivers/kscan/Kconfig.xec"
|
||||
source "drivers/kscan/Kconfig.sdl"
|
||||
source "drivers/kscan/Kconfig.ht16k33"
|
||||
|
||||
module = KSCAN
|
||||
module-str = kscan
|
||||
|
|
12
drivers/kscan/Kconfig.ht16k33
Normal file
12
drivers/kscan/Kconfig.ht16k33
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Copyright (c) 2019 - 2021 Henrik Brix Andersen <henrik@brixandersen.dk>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config KSCAN_HT16K33
|
||||
bool "HT16K33 keyscan driver"
|
||||
depends on HT16K33_KEYSCAN
|
||||
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.
|
63
drivers/kscan/kscan_ht16k33.c
Normal file
63
drivers/kscan/kscan_ht16k33.c
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2019 - 2021 Henrik Brix Andersen <henrik@brixandersen.dk>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT holtek_ht16k33_keyscan
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Keyscan driver for the HT16K33 I2C LED driver
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <drivers/kscan.h>
|
||||
#include <drivers/led/ht16k33.h>
|
||||
#include <logging/log.h>
|
||||
|
||||
LOG_MODULE_REGISTER(kscan_ht16k33, CONFIG_KSCAN_LOG_LEVEL);
|
||||
|
||||
BUILD_ASSERT(CONFIG_KSCAN_INIT_PRIORITY > CONFIG_LED_INIT_PRIORITY,
|
||||
"HT16K33 keyscan driver must be initialized after HT16K33 LED driver");
|
||||
|
||||
struct kscan_ht16k33_cfg {
|
||||
const struct device *parent;
|
||||
};
|
||||
|
||||
static int kscan_ht16k33_config(const struct device *dev,
|
||||
kscan_callback_t callback)
|
||||
{
|
||||
const struct kscan_ht16k33_cfg *config = dev->config;
|
||||
|
||||
return ht16k33_register_keyscan_callback(config->parent, dev, callback);
|
||||
}
|
||||
|
||||
static int kscan_ht16k33_init(const struct device *dev)
|
||||
{
|
||||
const struct kscan_ht16k33_cfg *config = dev->config;
|
||||
|
||||
if (!device_is_ready(config->parent)) {
|
||||
LOG_ERR("HT16K33 parent device not ready");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct kscan_driver_api kscan_ht16k33_api = {
|
||||
.config = kscan_ht16k33_config,
|
||||
};
|
||||
|
||||
#define KSCAN_HT16K33_DEVICE(id) \
|
||||
static const struct kscan_ht16k33_cfg kscan_ht16k33_##id##_cfg = { \
|
||||
.parent = DEVICE_DT_GET(DT_INST_BUS(id)), \
|
||||
}; \
|
||||
\
|
||||
DEVICE_DT_INST_DEFINE(id, &kscan_ht16k33_init, \
|
||||
NULL, NULL, \
|
||||
&kscan_ht16k33_##id##_cfg, POST_KERNEL, \
|
||||
CONFIG_KSCAN_INIT_PRIORITY, \
|
||||
&kscan_ht16k33_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(KSCAN_HT16K33_DEVICE)
|
|
@ -13,14 +13,14 @@ menuconfig HT16K33
|
|||
|
||||
config HT16K33_KEYSCAN
|
||||
bool "Enable keyscan support"
|
||||
depends on (HT16K33 && GPIO)
|
||||
select GPIO_HT16K33
|
||||
depends on (HT16K33 && KSCAN)
|
||||
select KSCAN_HT16K33
|
||||
help
|
||||
Enable keyscan child device support in the HT16K33 LED
|
||||
driver.
|
||||
|
||||
The keyscan functionality itself is handled by the
|
||||
HT16K33 GPIO driver.
|
||||
HT16K33 keyscan driver.
|
||||
|
||||
if HT16K33_KEYSCAN
|
||||
|
||||
|
|
|
@ -15,14 +15,11 @@
|
|||
#include <drivers/i2c.h>
|
||||
#include <kernel.h>
|
||||
#include <drivers/led.h>
|
||||
#include <sys/byteorder.h>
|
||||
#include <zephyr.h>
|
||||
|
||||
#define LOG_LEVEL CONFIG_LED_LOG_LEVEL
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_REGISTER(ht16k33);
|
||||
|
||||
#include <drivers/led/ht16k33.h>
|
||||
#include <sys/byteorder.h>
|
||||
#include <logging/log.h>
|
||||
|
||||
LOG_MODULE_REGISTER(ht16k33, CONFIG_LED_LOG_LEVEL);
|
||||
|
||||
#include "led_context.h"
|
||||
|
||||
|
@ -83,7 +80,8 @@ struct ht16k33_data {
|
|||
uint8_t buffer[HT16K33_DISP_DATA_SIZE];
|
||||
#ifdef CONFIG_HT16K33_KEYSCAN
|
||||
struct k_mutex lock;
|
||||
const struct device *children[HT16K33_KEYSCAN_ROWS];
|
||||
const struct device *child;
|
||||
kscan_callback_t kscan_cb;
|
||||
struct gpio_callback irq_cb;
|
||||
struct k_thread irq_thread;
|
||||
struct k_sem irq_sem;
|
||||
|
@ -123,7 +121,7 @@ static int ht16k33_led_blink(const struct device *dev, uint32_t led,
|
|||
cmd |= HT16K33_OPT_BLINK_2HZ;
|
||||
}
|
||||
|
||||
if (i2c_write(data->i2c, &cmd, 1, config->i2c_addr)) {
|
||||
if (i2c_write(data->i2c, &cmd, sizeof(cmd), config->i2c_addr)) {
|
||||
LOG_ERR("Setting HT16K33 blink frequency failed");
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -150,7 +148,7 @@ static int ht16k33_led_set_brightness(const struct device *dev, uint32_t led,
|
|||
dim = (value * (HT16K33_DIMMING_LEVELS - 1)) / dev_data->max_brightness;
|
||||
cmd = HT16K33_CMD_DIMMING_SET | dim;
|
||||
|
||||
if (i2c_write(data->i2c, &cmd, 1, config->i2c_addr)) {
|
||||
if (i2c_write(data->i2c, &cmd, sizeof(cmd), config->i2c_addr)) {
|
||||
LOG_ERR("Setting HT16K33 brightness failed");
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -206,35 +204,17 @@ static int ht16k33_led_off(const struct device *dev, uint32_t led)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_HT16K33_KEYSCAN
|
||||
uint32_t ht16k33_get_pending_int(const struct device *dev)
|
||||
{
|
||||
const struct ht16k33_cfg *config = dev->config;
|
||||
struct ht16k33_data *data = dev->data;
|
||||
uint8_t cmd;
|
||||
uint8_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 read HT16K33 IRQ flag");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (flag ? 1 : 0);
|
||||
}
|
||||
|
||||
static bool ht16k33_process_keyscan_data(const struct device *dev)
|
||||
{
|
||||
const struct ht16k33_cfg *config = dev->config;
|
||||
struct ht16k33_data *data = dev->data;
|
||||
uint8_t keys[HT16K33_KEYSCAN_DATA_SIZE];
|
||||
bool pressed = false;
|
||||
uint16_t row;
|
||||
uint16_t new;
|
||||
uint16_t state;
|
||||
uint16_t changed;
|
||||
int row;
|
||||
int col;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
err = i2c_burst_read(data->i2c, config->i2c_addr,
|
||||
HT16K33_CMD_KEY_DATA_ADDR, keys,
|
||||
|
@ -245,19 +225,28 @@ static bool ht16k33_process_keyscan_data(const struct device *dev)
|
|||
}
|
||||
|
||||
k_mutex_lock(&data->lock, K_FOREVER);
|
||||
for (i = 0; i < HT16K33_KEYSCAN_ROWS; i++) {
|
||||
row = sys_get_le16(&keys[i * 2]);
|
||||
if (row) {
|
||||
|
||||
for (row = 0; row < HT16K33_KEYSCAN_ROWS; row++) {
|
||||
state = sys_get_le16(&keys[row * 2]);
|
||||
changed = data->key_state[row] ^ state;
|
||||
data->key_state[row] = state;
|
||||
|
||||
if (state) {
|
||||
pressed = true;
|
||||
new = data->key_state[i] ^ row;
|
||||
new &= row;
|
||||
if (data->children[i] && new) {
|
||||
ht16k33_process_keyscan_row_data(
|
||||
data->children[i], new);
|
||||
}
|
||||
|
||||
if (data->kscan_cb == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (col = 0; col < HT16K33_KEYSCAN_COLS; col++) {
|
||||
if (changed & BIT(col)) {
|
||||
data->kscan_cb(data->child, row, col,
|
||||
state & BIT(col));
|
||||
}
|
||||
}
|
||||
data->key_state[i] = row;
|
||||
}
|
||||
|
||||
k_mutex_unlock(&data->lock);
|
||||
|
||||
return pressed;
|
||||
|
@ -298,22 +287,15 @@ static void ht16k33_timer_callback(struct k_timer *timer)
|
|||
k_sem_give(&data->irq_sem);
|
||||
}
|
||||
|
||||
int ht16k33_register_keyscan_device(const struct device *parent,
|
||||
const struct device *child,
|
||||
uint8_t keyscan_idx)
|
||||
int ht16k33_register_keyscan_callback(const struct device *parent,
|
||||
const struct device *child,
|
||||
kscan_callback_t callback)
|
||||
{
|
||||
struct ht16k33_data *data = parent->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;
|
||||
data->child = child;
|
||||
data->kscan_cb = callback;
|
||||
k_mutex_unlock(&data->lock);
|
||||
|
||||
return 0;
|
||||
|
@ -379,7 +361,6 @@ static int ht16k33_init(const struct device *dev)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_HT16K33_KEYSCAN
|
||||
memset(&data->children, 0, sizeof(data->children));
|
||||
k_mutex_init(&data->lock);
|
||||
k_sem_init(&data->irq_sem, 0, 1);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
description: Holtek HT16K33 LED driver with keyscan
|
||||
description: Holtek HT16K33 keyscan
|
||||
|
||||
compatible: "holtek,ht16k33-keyscan"
|
||||
|
||||
|
@ -7,11 +7,5 @@ include: base.yaml
|
|||
on-bus: ht16k33
|
||||
|
||||
properties:
|
||||
reg:
|
||||
required: true
|
||||
label:
|
||||
required: true
|
||||
|
||||
gpio-cells:
|
||||
- pin
|
||||
- flags
|
|
@ -7,12 +7,6 @@ include: i2c-device.yaml
|
|||
bus: ht16k33
|
||||
|
||||
properties:
|
||||
"#address-cells":
|
||||
required: true
|
||||
const: 1
|
||||
"#size-cells":
|
||||
required: true
|
||||
const: 0
|
||||
label:
|
||||
required: true
|
||||
irq-gpios:
|
||||
|
|
|
@ -8,40 +8,20 @@
|
|||
#ifndef ZEPHYR_INCLUDE_DRIVERS_LED_HT16K33_H_
|
||||
#define ZEPHYR_INCLUDE_DRIVERS_LED_HT16K33_H_
|
||||
|
||||
#include <device.h>
|
||||
#include <zephyr/types.h>
|
||||
#include <drivers/kscan.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).
|
||||
* @param parent HT16K33 parent device.
|
||||
* @param child HT16K33 child device.
|
||||
* @param callback Keyscan callback function.
|
||||
* @return 0 if successful, negative errno code on failure.
|
||||
*/
|
||||
int ht16k33_register_keyscan_device(const struct device *parent,
|
||||
const struct device *child,
|
||||
uint8_t keyscan_idx);
|
||||
|
||||
/**
|
||||
* Check if a HT16K33 keyscan interrupt is pending.
|
||||
*
|
||||
* @param parent HT16K33 parent device.
|
||||
* @return status != 0 if an interrupt is pending.
|
||||
*/
|
||||
uint32_t ht16k33_get_pending_int(const 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(const struct device *child,
|
||||
uint32_t keys);
|
||||
int ht16k33_register_keyscan_callback(const struct device *parent,
|
||||
const struct device *child,
|
||||
kscan_callback_t callback);
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_DRIVERS_LED_HT16K33_H_ */
|
||||
|
|
|
@ -13,23 +13,10 @@
|
|||
label = "HT16K33";
|
||||
/* Uncomment to use IRQ instead of polling: */
|
||||
/* irq-gpios = <&gpio1 8 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; */
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
ks@0 {
|
||||
keyscan {
|
||||
compatible = "holtek,ht16k33-keyscan";
|
||||
reg = <0x0>;
|
||||
label = "KS0";
|
||||
};
|
||||
ks@1 {
|
||||
compatible = "holtek,ht16k33-keyscan";
|
||||
reg = <0x1>;
|
||||
label = "KS1";
|
||||
};
|
||||
ks@2 {
|
||||
compatible = "holtek,ht16k33-keyscan";
|
||||
reg = <0x2>;
|
||||
label = "KS2";
|
||||
label = "KEYSCAN";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
CONFIG_LOG=y
|
||||
CONFIG_I2C=y
|
||||
CONFIG_GPIO=y
|
||||
CONFIG_LED=y
|
||||
CONFIG_KSCAN=y
|
||||
CONFIG_KSCAN_INIT_PRIORITY=95
|
||||
CONFIG_HT16K33=y
|
||||
CONFIG_HT16K33_KEYSCAN=y
|
||||
|
|
|
@ -4,90 +4,69 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <device.h>
|
||||
#include <drivers/led.h>
|
||||
#include <drivers/gpio.h>
|
||||
#include <zephyr.h>
|
||||
|
||||
#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
|
||||
#include <drivers/kscan.h>
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_REGISTER(main);
|
||||
|
||||
#define LED_DEV_NAME DT_LABEL(DT_INST(0, holtek_ht16k33))
|
||||
#define KS0_DEV_NAME DT_LABEL(DT_INST(0, holtek_ht16k33_keyscan))
|
||||
#define KS1_DEV_NAME DT_LABEL(DT_INST(1, holtek_ht16k33_keyscan))
|
||||
#define KS2_DEV_NAME DT_LABEL(DT_INST(2, holtek_ht16k33_keyscan))
|
||||
LOG_MODULE_REGISTER(main, CONFIG_LOG_DEFAULT_LEVEL);
|
||||
|
||||
#define KEYSCAN_DEVICES 3
|
||||
#define LED_NODE DT_INST(0, holtek_ht16k33)
|
||||
#define KEY_NODE DT_INST(0, holtek_ht16k33_keyscan)
|
||||
|
||||
const struct device *led_dev;
|
||||
const struct device *ks_dev[KEYSCAN_DEVICES];
|
||||
static struct gpio_callback ks_cb[KEYSCAN_DEVICES];
|
||||
|
||||
static void keyscan_callback(const struct device *gpiob,
|
||||
struct gpio_callback *cb, uint32_t pins)
|
||||
static void keyscan_callback(const struct device *dev, uint32_t row,
|
||||
uint32_t column, bool pressed)
|
||||
{
|
||||
LOG_INF("%s: 0x%08x", gpiob->name, pins);
|
||||
LOG_INF("Row %d, column %d %s", row, column,
|
||||
pressed ? "pressed" : "released");
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
const struct device *led = DEVICE_DT_GET(LED_NODE);
|
||||
const struct device *key = DEVICE_DT_GET(KEY_NODE);
|
||||
int err;
|
||||
int i;
|
||||
|
||||
/* LED device binding */
|
||||
led_dev = device_get_binding(LED_DEV_NAME);
|
||||
if (!led_dev) {
|
||||
LOG_ERR("LED device %s not found", LED_DEV_NAME);
|
||||
if (!device_is_ready(led)) {
|
||||
LOG_ERR("LED device not ready");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Keyscan device bindings */
|
||||
ks_dev[0] = device_get_binding(KS0_DEV_NAME);
|
||||
ks_dev[1] = device_get_binding(KS1_DEV_NAME);
|
||||
ks_dev[2] = device_get_binding(KS2_DEV_NAME);
|
||||
for (i = 0; i < ARRAY_SIZE(ks_dev); i++) {
|
||||
if (!ks_dev[i]) {
|
||||
LOG_ERR("KS%d device not found", i);
|
||||
return;
|
||||
}
|
||||
if (!device_is_ready(key)) {
|
||||
LOG_ERR("Keyscan device not ready");
|
||||
return;
|
||||
}
|
||||
|
||||
gpio_init_callback(&ks_cb[i], &keyscan_callback,
|
||||
GENMASK(12, 0));
|
||||
|
||||
err = gpio_add_callback(ks_dev[i], &ks_cb[i]);
|
||||
if (err) {
|
||||
LOG_ERR("Failed to add KS%d GPIO callback (err %d)", i,
|
||||
err);
|
||||
return;
|
||||
}
|
||||
err = kscan_config(key, keyscan_callback);
|
||||
if (err) {
|
||||
LOG_ERR("Failed to add keyscan callback (err %d)", err);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
LOG_INF("Iterating through all LEDs, turning them on "
|
||||
"one-by-one");
|
||||
for (i = 0; i < 128; i++) {
|
||||
led_on(led_dev, i);
|
||||
led_on(led, i);
|
||||
k_sleep(K_MSEC(100));
|
||||
}
|
||||
|
||||
for (i = 500; i <= 2000; i *= 2) {
|
||||
LOG_INF("Blinking LEDs with a period of %d ms", i);
|
||||
led_blink(led_dev, 0, i / 2, i / 2);
|
||||
led_blink(led, 0, i / 2, i / 2);
|
||||
k_msleep(10 * i);
|
||||
}
|
||||
led_blink(led_dev, 0, 0, 0);
|
||||
led_blink(led, 0, 0, 0);
|
||||
|
||||
for (i = 100; i >= 0; i -= 10) {
|
||||
LOG_INF("Setting LED brightness to %d%%", i);
|
||||
led_set_brightness(led_dev, 0, i);
|
||||
led_set_brightness(led, 0, i);
|
||||
k_sleep(K_MSEC(1000));
|
||||
}
|
||||
|
||||
LOG_INF("Turning all LEDs off and restoring 100%% brightness");
|
||||
for (i = 0; i < 128; i++) {
|
||||
led_off(led_dev, i);
|
||||
led_off(led, i);
|
||||
}
|
||||
led_set_brightness(led_dev, 0, 100);
|
||||
led_set_brightness(led, 0, 100);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue