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:
Henrik Brix Andersen 2021-06-14 22:58:56 +02:00 committed by Carles Cufí
parent 7e52ee7fe1
commit 588d22a755
17 changed files with 153 additions and 391 deletions

View file

@ -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

View file

@ -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)

View file

@ -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"

View file

@ -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.

View file

@ -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)

View file

@ -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)

View file

@ -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

View 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.

View 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)

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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:

View file

@ -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_ */

View file

@ -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";
};
};
};

View file

@ -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

View file

@ -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);
}
}