drivers: led: ht16k33: reprocess keyscan events in case of i2c error
Reprocess keyscan event processing in case of an I2C bus read error. Otherwise, the HT16K33 will be stuck (when used in IRQ mode, not in polling mode) and no new IRQs will be delivered. Signed-off-by: Henrik Brix Andersen <henrik@brixandersen.dk>
This commit is contained in:
parent
588d22a755
commit
93587e9178
1 changed files with 28 additions and 39 deletions
|
@ -62,18 +62,15 @@ LOG_MODULE_REGISTER(ht16k33, CONFIG_LED_LOG_LEVEL);
|
|||
#define HT16K33_KEYSCAN_DATA_SIZE 6
|
||||
|
||||
struct ht16k33_cfg {
|
||||
char *i2c_dev_name;
|
||||
const struct device *i2c_dev;
|
||||
uint16_t i2c_addr;
|
||||
bool irq_enabled;
|
||||
#ifdef CONFIG_HT16K33_KEYSCAN
|
||||
char *irq_dev_name;
|
||||
uint32_t irq_pin;
|
||||
int irq_flags;
|
||||
struct gpio_dt_spec irq;
|
||||
#endif /* CONFIG_HT16K33_KEYSCAN */
|
||||
};
|
||||
|
||||
struct ht16k33_data {
|
||||
const struct device *i2c;
|
||||
const struct device *dev;
|
||||
struct led_data dev_data;
|
||||
/* Shadow buffer for the display data RAM */
|
||||
|
@ -121,7 +118,7 @@ static int ht16k33_led_blink(const struct device *dev, uint32_t led,
|
|||
cmd |= HT16K33_OPT_BLINK_2HZ;
|
||||
}
|
||||
|
||||
if (i2c_write(data->i2c, &cmd, sizeof(cmd), config->i2c_addr)) {
|
||||
if (i2c_write(config->i2c_dev, &cmd, sizeof(cmd), config->i2c_addr)) {
|
||||
LOG_ERR("Setting HT16K33 blink frequency failed");
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -148,7 +145,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, sizeof(cmd), config->i2c_addr)) {
|
||||
if (i2c_write(config->i2c_dev, &cmd, sizeof(cmd), config->i2c_addr)) {
|
||||
LOG_ERR("Setting HT16K33 brightness failed");
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -183,7 +180,7 @@ static int ht16k33_led_set_state(const struct device *dev, uint32_t led,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (i2c_write(data->i2c, cmd, sizeof(cmd), config->i2c_addr)) {
|
||||
if (i2c_write(config->i2c_dev, cmd, sizeof(cmd), config->i2c_addr)) {
|
||||
LOG_ERR("Setting HT16K33 LED %s failed", on ? "on" : "off");
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -216,12 +213,13 @@ static bool ht16k33_process_keyscan_data(const struct device *dev)
|
|||
int col;
|
||||
int err;
|
||||
|
||||
err = i2c_burst_read(data->i2c, config->i2c_addr,
|
||||
err = i2c_burst_read(config->i2c_dev, 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;
|
||||
LOG_WRN("Failed to to read HT16K33 key data (err %d)", err);
|
||||
/* Reprocess */
|
||||
return true;
|
||||
}
|
||||
|
||||
k_mutex_lock(&data->lock, K_FOREVER);
|
||||
|
@ -312,9 +310,8 @@ static int ht16k33_init(const struct device *dev)
|
|||
|
||||
data->dev = dev;
|
||||
|
||||
data->i2c = device_get_binding(config->i2c_dev_name);
|
||||
if (data->i2c == NULL) {
|
||||
LOG_ERR("Failed to get I2C device");
|
||||
if (!device_is_ready(config->i2c_dev)) {
|
||||
LOG_ERR("I2C bus device not ready");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -328,7 +325,7 @@ static int ht16k33_init(const struct device *dev)
|
|||
|
||||
/* System oscillator on */
|
||||
cmd[0] = HT16K33_CMD_SYSTEM_SETUP | HT16K33_OPT_S;
|
||||
err = i2c_write(data->i2c, cmd, 1, config->i2c_addr);
|
||||
err = i2c_write(config->i2c_dev, cmd, 1, config->i2c_addr);
|
||||
if (err) {
|
||||
LOG_ERR("Enabling HT16K33 system oscillator failed (err %d)",
|
||||
err);
|
||||
|
@ -338,7 +335,7 @@ static int ht16k33_init(const struct device *dev)
|
|||
/* Clear display RAM */
|
||||
memset(cmd, 0, sizeof(cmd));
|
||||
cmd[0] = HT16K33_CMD_DISP_DATA_ADDR;
|
||||
err = i2c_write(data->i2c, cmd, sizeof(cmd), config->i2c_addr);
|
||||
err = i2c_write(config->i2c_dev, cmd, sizeof(cmd), config->i2c_addr);
|
||||
if (err) {
|
||||
LOG_ERR("Clearing HT16K33 display RAM failed (err %d)", err);
|
||||
return -EIO;
|
||||
|
@ -346,7 +343,7 @@ static int ht16k33_init(const struct device *dev)
|
|||
|
||||
/* Full brightness */
|
||||
cmd[0] = HT16K33_CMD_DIMMING_SET | 0x0f;
|
||||
err = i2c_write(data->i2c, cmd, 1, config->i2c_addr);
|
||||
err = i2c_write(config->i2c_dev, cmd, 1, config->i2c_addr);
|
||||
if (err) {
|
||||
LOG_ERR("Setting HT16K33 brightness failed (err %d)", err);
|
||||
return -EIO;
|
||||
|
@ -354,7 +351,7 @@ static int ht16k33_init(const struct device *dev)
|
|||
|
||||
/* Display on, blinking off */
|
||||
cmd[0] = HT16K33_CMD_DISP_SETUP | HT16K33_OPT_D | HT16K33_OPT_BLINK_OFF;
|
||||
err = i2c_write(data->i2c, cmd, 1, config->i2c_addr);
|
||||
err = i2c_write(config->i2c_dev, cmd, 1, config->i2c_addr);
|
||||
if (err) {
|
||||
LOG_ERR("Enabling HT16K33 display failed (err %d)", err);
|
||||
return -EIO;
|
||||
|
@ -366,27 +363,23 @@ static int ht16k33_init(const struct device *dev)
|
|||
|
||||
/* Configure interrupt */
|
||||
if (config->irq_enabled) {
|
||||
const struct device *irq_dev;
|
||||
uint8_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);
|
||||
if (!device_is_ready(config->irq.port)) {
|
||||
LOG_ERR("IRQ device not ready");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = gpio_pin_configure(irq_dev, config->irq_pin,
|
||||
GPIO_INPUT | config->irq_flags);
|
||||
err = gpio_pin_configure_dt(&config->irq, GPIO_INPUT);
|
||||
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));
|
||||
BIT(config->irq.pin));
|
||||
|
||||
err = gpio_add_callback(irq_dev, &data->irq_cb);
|
||||
err = gpio_add_callback(config->irq.port, &data->irq_cb);
|
||||
if (err) {
|
||||
LOG_ERR("Failed to add IRQ callback (err %d)", err);
|
||||
return -EINVAL;
|
||||
|
@ -394,21 +387,21 @@ static int ht16k33_init(const struct device *dev)
|
|||
|
||||
/* Enable interrupt pin */
|
||||
cmd[0] = HT16K33_CMD_ROW_INT_SET | HT16K33_OPT_INT_LOW;
|
||||
if (i2c_write(data->i2c, cmd, 1, config->i2c_addr)) {
|
||||
if (i2c_write(config->i2c_dev, 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,
|
||||
err = i2c_burst_read(config->i2c_dev, 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_interrupt_configure(irq_dev, config->irq_pin,
|
||||
GPIO_INT_EDGE_FALLING);
|
||||
err = gpio_pin_interrupt_configure_dt(&config->irq,
|
||||
GPIO_INT_EDGE_FALLING);
|
||||
if (err) {
|
||||
LOG_ERR("Failed to configure IRQ pin flags (err %d)",
|
||||
err);
|
||||
|
@ -417,7 +410,7 @@ static int ht16k33_init(const struct device *dev)
|
|||
} 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)) {
|
||||
if (i2c_write(config->i2c_dev, cmd, 1, config->i2c_addr)) {
|
||||
LOG_ERR("Enabling HT16K33 ROW15 output failed");
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -447,7 +440,7 @@ static const struct led_driver_api ht16k33_leds_api = {
|
|||
|
||||
#define HT16K33_DEVICE(id) \
|
||||
static const struct ht16k33_cfg ht16k33_##id##_cfg = { \
|
||||
.i2c_dev_name = DT_INST_BUS_LABEL(id), \
|
||||
.i2c_dev = DEVICE_DT_GET(DT_INST_BUS(id)), \
|
||||
.i2c_addr = DT_INST_REG_ADDR(id), \
|
||||
.irq_enabled = false, \
|
||||
}; \
|
||||
|
@ -462,14 +455,10 @@ static const struct led_driver_api 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_INST_BUS_LABEL(id), \
|
||||
.i2c_dev = DEVICE_DT_GET(DT_INST_BUS(id)), \
|
||||
.i2c_addr = DT_INST_REG_ADDR(id), \
|
||||
.irq_enabled = true, \
|
||||
.irq_dev_name = \
|
||||
DT_INST_GPIO_LABEL(id, irq_gpios), \
|
||||
.irq_pin = DT_INST_GPIO_PIN(id, irq_gpios), \
|
||||
.irq_flags = \
|
||||
DT_INST_GPIO_FLAGS(id, irq_gpios), \
|
||||
.irq = GPIO_DT_SPEC_INST_GET(id, irq_gpios), \
|
||||
}; \
|
||||
\
|
||||
static struct ht16k33_data ht16k33_##id##_data; \
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue