1 /*
2 * Copyright (c) 2019 Henrik Brix Andersen <henrik@brixandersen.dk>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT holtek_ht16k33
8
9 /**
10 * @file
11 * @brief LED driver for the HT16K33 I2C LED driver with keyscan
12 */
13
14 #include <zephyr/drivers/gpio.h>
15 #include <zephyr/drivers/i2c.h>
16 #include <zephyr/kernel.h>
17 #include <zephyr/drivers/led.h>
18 #include <zephyr/drivers/led/ht16k33.h>
19 #include <zephyr/sys/byteorder.h>
20 #include <zephyr/logging/log.h>
21
22 LOG_MODULE_REGISTER(ht16k33, CONFIG_LED_LOG_LEVEL);
23
24 #include "led_context.h"
25
26 /* HT16K33 commands and options */
27 #define HT16K33_CMD_DISP_DATA_ADDR 0x00
28
29 #define HT16K33_CMD_SYSTEM_SETUP 0x20
30 #define HT16K33_OPT_S BIT(0)
31
32 #define HT16K33_CMD_KEY_DATA_ADDR 0x40
33
34 #define HT16K33_CMD_INT_FLAG_ADDR 0x60
35
36 #define HT16K33_CMD_DISP_SETUP 0x80
37 #define HT16K33_OPT_D BIT(0)
38 #define HT16K33_OPT_B0 BIT(1)
39 #define HT16K33_OPT_B1 BIT(2)
40 #define HT16K33_OPT_BLINK_OFF 0
41 #define HT16K33_OPT_BLINK_2HZ HT16K33_OPT_B0
42 #define HT16K33_OPT_BLINK_1HZ HT16K33_OPT_B1
43 #define HT16K33_OPT_BLINK_05HZ (HT16K33_OPT_B1 | HT16K33_OPT_B0)
44
45 #define HT16K33_CMD_ROW_INT_SET 0xa0
46 #define HT16K33_OPT_ROW_INT BIT(0)
47 #define HT16K33_OPT_ACT BIT(1)
48 #define HT16K33_OPT_ROW 0
49 #define HT16K33_OPT_INT_LOW HT16K33_OPT_ROW_INT
50 #define HT16K33_OPT_INT_HIGH (HT16K33_OPT_ACT | HT16K33_OPT_ROW_INT)
51
52 #define HT16K33_CMD_DIMMING_SET 0xe0
53
54 /* HT16K33 size definitions */
55 #define HT16K33_DISP_ROWS 16
56 #define HT16K33_DISP_COLS 8
57 #define HT16K33_DISP_DATA_SIZE HT16K33_DISP_ROWS
58 #define HT16K33_DISP_SEGMENTS (HT16K33_DISP_ROWS * HT16K33_DISP_COLS)
59 #define HT16K33_DIMMING_LEVELS 16
60 #define HT16K33_KEYSCAN_ROWS 3
61 #define HT16K33_KEYSCAN_COLS 13
62 #define HT16K33_KEYSCAN_DATA_SIZE 6
63
64 struct ht16k33_cfg {
65 struct i2c_dt_spec i2c;
66 bool irq_enabled;
67 #ifdef CONFIG_HT16K33_KEYSCAN
68 struct gpio_dt_spec irq;
69 #endif /* CONFIG_HT16K33_KEYSCAN */
70 };
71
72 struct ht16k33_data {
73 const struct device *dev;
74 struct led_data dev_data;
75 /* Shadow buffer for the display data RAM */
76 uint8_t buffer[HT16K33_DISP_DATA_SIZE];
77 #ifdef CONFIG_HT16K33_KEYSCAN
78 struct k_mutex lock;
79 const struct device *child;
80 kscan_callback_t kscan_cb;
81 struct gpio_callback irq_cb;
82 struct k_thread irq_thread;
83 struct k_sem irq_sem;
84 struct k_timer timer;
85 uint16_t key_state[HT16K33_KEYSCAN_ROWS];
86
87 K_KERNEL_STACK_MEMBER(irq_thread_stack,
88 CONFIG_HT16K33_KEYSCAN_IRQ_THREAD_STACK_SIZE);
89 #endif /* CONFIG_HT16K33_KEYSCAN */
90 };
91
ht16k33_led_blink(const struct device * dev,uint32_t led,uint32_t delay_on,uint32_t delay_off)92 static int ht16k33_led_blink(const struct device *dev, uint32_t led,
93 uint32_t delay_on, uint32_t delay_off)
94 {
95 /* The HT16K33 blinks all LEDs at the same frequency */
96 ARG_UNUSED(led);
97
98 const struct ht16k33_cfg *config = dev->config;
99 struct ht16k33_data *data = dev->data;
100 struct led_data *dev_data = &data->dev_data;
101 uint32_t period;
102 uint8_t cmd;
103
104 period = delay_on + delay_off;
105 if (period < dev_data->min_period || period > dev_data->max_period) {
106 return -EINVAL;
107 }
108
109 cmd = HT16K33_CMD_DISP_SETUP | HT16K33_OPT_D;
110 if (delay_off == 0) {
111 cmd |= HT16K33_OPT_BLINK_OFF;
112 } else if (period > 1500) {
113 cmd |= HT16K33_OPT_BLINK_05HZ;
114 } else if (period > 750) {
115 cmd |= HT16K33_OPT_BLINK_1HZ;
116 } else {
117 cmd |= HT16K33_OPT_BLINK_2HZ;
118 }
119
120 if (i2c_write_dt(&config->i2c, &cmd, sizeof(cmd))) {
121 LOG_ERR("Setting HT16K33 blink frequency failed");
122 return -EIO;
123 }
124
125 return 0;
126 }
127
ht16k33_led_set_brightness(const struct device * dev,uint32_t led,uint8_t value)128 static int ht16k33_led_set_brightness(const struct device *dev, uint32_t led,
129 uint8_t value)
130 {
131 ARG_UNUSED(led);
132
133 const struct ht16k33_cfg *config = dev->config;
134 struct ht16k33_data *data = dev->data;
135 struct led_data *dev_data = &data->dev_data;
136 uint8_t dim;
137 uint8_t cmd;
138
139 if (value < dev_data->min_brightness ||
140 value > dev_data->max_brightness) {
141 return -EINVAL;
142 }
143
144 dim = (value * (HT16K33_DIMMING_LEVELS - 1)) / dev_data->max_brightness;
145 cmd = HT16K33_CMD_DIMMING_SET | dim;
146
147 if (i2c_write_dt(&config->i2c, &cmd, sizeof(cmd))) {
148 LOG_ERR("Setting HT16K33 brightness failed");
149 return -EIO;
150 }
151
152 return 0;
153 }
154
ht16k33_led_set_state(const struct device * dev,uint32_t led,bool on)155 static int ht16k33_led_set_state(const struct device *dev, uint32_t led,
156 bool on)
157 {
158 const struct ht16k33_cfg *config = dev->config;
159 struct ht16k33_data *data = dev->data;
160 uint8_t cmd[2];
161 uint8_t addr;
162 uint8_t bit;
163
164 if (led >= HT16K33_DISP_SEGMENTS) {
165 return -EINVAL;
166 }
167
168 addr = led / HT16K33_DISP_COLS;
169 bit = led % HT16K33_DISP_COLS;
170
171 cmd[0] = HT16K33_CMD_DISP_DATA_ADDR | addr;
172 if (on) {
173 cmd[1] = data->buffer[addr] | BIT(bit);
174 } else {
175 cmd[1] = data->buffer[addr] & ~BIT(bit);
176 }
177
178 if (data->buffer[addr] == cmd[1]) {
179 return 0;
180 }
181
182 if (i2c_write_dt(&config->i2c, cmd, sizeof(cmd))) {
183 LOG_ERR("Setting HT16K33 LED %s failed", on ? "on" : "off");
184 return -EIO;
185 }
186
187 data->buffer[addr] = cmd[1];
188
189 return 0;
190 }
191
ht16k33_led_on(const struct device * dev,uint32_t led)192 static int ht16k33_led_on(const struct device *dev, uint32_t led)
193 {
194 return ht16k33_led_set_state(dev, led, true);
195 }
196
ht16k33_led_off(const struct device * dev,uint32_t led)197 static int ht16k33_led_off(const struct device *dev, uint32_t led)
198 {
199 return ht16k33_led_set_state(dev, led, false);
200 }
201
202 #ifdef CONFIG_HT16K33_KEYSCAN
ht16k33_process_keyscan_data(const struct device * dev)203 static bool ht16k33_process_keyscan_data(const struct device *dev)
204 {
205 const struct ht16k33_cfg *config = dev->config;
206 struct ht16k33_data *data = dev->data;
207 uint8_t keys[HT16K33_KEYSCAN_DATA_SIZE];
208 bool pressed = false;
209 uint16_t state;
210 uint16_t changed;
211 int row;
212 int col;
213 int err;
214
215 err = i2c_burst_read_dt(&config->i2c, HT16K33_CMD_KEY_DATA_ADDR, keys, sizeof(keys));
216 if (err) {
217 LOG_WRN("Failed to to read HT16K33 key data (err %d)", err);
218 /* Reprocess */
219 return true;
220 }
221
222 k_mutex_lock(&data->lock, K_FOREVER);
223
224 for (row = 0; row < HT16K33_KEYSCAN_ROWS; row++) {
225 state = sys_get_le16(&keys[row * 2]);
226 changed = data->key_state[row] ^ state;
227 data->key_state[row] = state;
228
229 if (state) {
230 pressed = true;
231 }
232
233 if (data->kscan_cb == NULL) {
234 continue;
235 }
236
237 for (col = 0; col < HT16K33_KEYSCAN_COLS; col++) {
238 if (changed & BIT(col)) {
239 data->kscan_cb(data->child, row, col,
240 state & BIT(col));
241 }
242 }
243 }
244
245 k_mutex_unlock(&data->lock);
246
247 return pressed;
248 }
249
ht16k33_irq_thread(struct ht16k33_data * data)250 static void ht16k33_irq_thread(struct ht16k33_data *data)
251 {
252 bool pressed;
253
254 while (true) {
255 k_sem_take(&data->irq_sem, K_FOREVER);
256
257 do {
258 k_sem_reset(&data->irq_sem);
259 pressed = ht16k33_process_keyscan_data(data->dev);
260 k_msleep(CONFIG_HT16K33_KEYSCAN_DEBOUNCE_MSEC);
261 } while (pressed);
262 }
263 }
264
ht16k33_irq_callback(const struct device * gpiob,struct gpio_callback * cb,uint32_t pins)265 static void ht16k33_irq_callback(const struct device *gpiob,
266 struct gpio_callback *cb, uint32_t pins)
267 {
268 struct ht16k33_data *data;
269
270 ARG_UNUSED(gpiob);
271 ARG_UNUSED(pins);
272
273 data = CONTAINER_OF(cb, struct ht16k33_data, irq_cb);
274 k_sem_give(&data->irq_sem);
275 }
276
ht16k33_timer_callback(struct k_timer * timer)277 static void ht16k33_timer_callback(struct k_timer *timer)
278 {
279 struct ht16k33_data *data;
280
281 data = CONTAINER_OF(timer, struct ht16k33_data, timer);
282 k_sem_give(&data->irq_sem);
283 }
284
ht16k33_register_keyscan_callback(const struct device * parent,const struct device * child,kscan_callback_t callback)285 int ht16k33_register_keyscan_callback(const struct device *parent,
286 const struct device *child,
287 kscan_callback_t callback)
288 {
289 struct ht16k33_data *data = parent->data;
290
291 k_mutex_lock(&data->lock, K_FOREVER);
292 data->child = child;
293 data->kscan_cb = callback;
294 k_mutex_unlock(&data->lock);
295
296 return 0;
297 }
298 #endif /* CONFIG_HT16K33_KEYSCAN */
299
ht16k33_init(const struct device * dev)300 static int ht16k33_init(const struct device *dev)
301 {
302 const struct ht16k33_cfg *config = dev->config;
303 struct ht16k33_data *data = dev->data;
304 struct led_data *dev_data = &data->dev_data;
305 uint8_t cmd[1 + HT16K33_DISP_DATA_SIZE]; /* 1 byte command + data */
306 int err;
307
308 data->dev = dev;
309
310 if (!device_is_ready(config->i2c.bus)) {
311 LOG_ERR("I2C bus device not ready");
312 return -EINVAL;
313 }
314
315 memset(&data->buffer, 0, sizeof(data->buffer));
316
317 /* Hardware specific limits */
318 dev_data->min_period = 0U;
319 dev_data->max_period = 2000U;
320 dev_data->min_brightness = 0U;
321 dev_data->max_brightness = 100U;
322
323 /* System oscillator on */
324 cmd[0] = HT16K33_CMD_SYSTEM_SETUP | HT16K33_OPT_S;
325 err = i2c_write_dt(&config->i2c, cmd, 1);
326 if (err) {
327 LOG_ERR("Enabling HT16K33 system oscillator failed (err %d)",
328 err);
329 return -EIO;
330 }
331
332 /* Clear display RAM */
333 memset(cmd, 0, sizeof(cmd));
334 cmd[0] = HT16K33_CMD_DISP_DATA_ADDR;
335 err = i2c_write_dt(&config->i2c, cmd, sizeof(cmd));
336 if (err) {
337 LOG_ERR("Clearing HT16K33 display RAM failed (err %d)", err);
338 return -EIO;
339 }
340
341 /* Full brightness */
342 cmd[0] = HT16K33_CMD_DIMMING_SET | 0x0f;
343 err = i2c_write_dt(&config->i2c, cmd, 1);
344 if (err) {
345 LOG_ERR("Setting HT16K33 brightness failed (err %d)", err);
346 return -EIO;
347 }
348
349 /* Display on, blinking off */
350 cmd[0] = HT16K33_CMD_DISP_SETUP | HT16K33_OPT_D | HT16K33_OPT_BLINK_OFF;
351 err = i2c_write_dt(&config->i2c, cmd, 1);
352 if (err) {
353 LOG_ERR("Enabling HT16K33 display failed (err %d)", err);
354 return -EIO;
355 }
356
357 #ifdef CONFIG_HT16K33_KEYSCAN
358 k_mutex_init(&data->lock);
359 k_sem_init(&data->irq_sem, 0, 1);
360
361 /* Configure interrupt */
362 if (config->irq_enabled) {
363 uint8_t keys[HT16K33_KEYSCAN_DATA_SIZE];
364
365 if (!gpio_is_ready_dt(&config->irq)) {
366 LOG_ERR("IRQ device not ready");
367 return -EINVAL;
368 }
369
370 err = gpio_pin_configure_dt(&config->irq, GPIO_INPUT);
371 if (err) {
372 LOG_ERR("Failed to configure IRQ pin (err %d)", err);
373 return -EINVAL;
374 }
375
376 gpio_init_callback(&data->irq_cb, &ht16k33_irq_callback,
377 BIT(config->irq.pin));
378
379 err = gpio_add_callback(config->irq.port, &data->irq_cb);
380 if (err) {
381 LOG_ERR("Failed to add IRQ callback (err %d)", err);
382 return -EINVAL;
383 }
384
385 /* Enable interrupt pin */
386 cmd[0] = HT16K33_CMD_ROW_INT_SET | HT16K33_OPT_INT_LOW;
387 if (i2c_write_dt(&config->i2c, cmd, 1)) {
388 LOG_ERR("Enabling HT16K33 IRQ output failed");
389 return -EIO;
390 }
391
392 /* Flush key data before enabling interrupt */
393 err = i2c_burst_read_dt(&config->i2c, HT16K33_CMD_KEY_DATA_ADDR, keys,
394 sizeof(keys));
395 if (err) {
396 LOG_ERR("Failed to to read HT16K33 key data");
397 return -EIO;
398 }
399
400 err = gpio_pin_interrupt_configure_dt(&config->irq,
401 GPIO_INT_EDGE_FALLING);
402 if (err) {
403 LOG_ERR("Failed to configure IRQ pin flags (err %d)",
404 err);
405 return -EINVAL;
406 }
407 } else {
408 /* No interrupt pin, enable ROW15 */
409 cmd[0] = HT16K33_CMD_ROW_INT_SET | HT16K33_OPT_ROW;
410 if (i2c_write_dt(&config->i2c, cmd, 1)) {
411 LOG_ERR("Enabling HT16K33 ROW15 output failed");
412 return -EIO;
413 }
414
415 /* Setup timer for polling key data */
416 k_timer_init(&data->timer, ht16k33_timer_callback, NULL);
417 k_timer_start(&data->timer, K_NO_WAIT,
418 K_MSEC(CONFIG_HT16K33_KEYSCAN_POLL_MSEC));
419 }
420
421 k_thread_create(&data->irq_thread, data->irq_thread_stack,
422 CONFIG_HT16K33_KEYSCAN_IRQ_THREAD_STACK_SIZE,
423 (k_thread_entry_t)ht16k33_irq_thread, data, NULL, NULL,
424 K_PRIO_COOP(CONFIG_HT16K33_KEYSCAN_IRQ_THREAD_PRIO),
425 0, K_NO_WAIT);
426 #endif /* CONFIG_HT16K33_KEYSCAN */
427
428 return 0;
429 }
430
431 static const struct led_driver_api ht16k33_leds_api = {
432 .blink = ht16k33_led_blink,
433 .set_brightness = ht16k33_led_set_brightness,
434 .on = ht16k33_led_on,
435 .off = ht16k33_led_off,
436 };
437
438 #define HT16K33_DEVICE(id) \
439 static const struct ht16k33_cfg ht16k33_##id##_cfg = { \
440 .i2c = I2C_DT_SPEC_INST_GET(id), \
441 .irq_enabled = false, \
442 }; \
443 \
444 static struct ht16k33_data ht16k33_##id##_data; \
445 \
446 DEVICE_DT_INST_DEFINE(id, &ht16k33_init, NULL, \
447 &ht16k33_##id##_data, \
448 &ht16k33_##id##_cfg, POST_KERNEL, \
449 CONFIG_LED_INIT_PRIORITY, &ht16k33_leds_api)
450
451 #ifdef CONFIG_HT16K33_KEYSCAN
452 #define HT16K33_DEVICE_WITH_IRQ(id) \
453 static const struct ht16k33_cfg ht16k33_##id##_cfg = { \
454 .i2c = I2C_DT_SPEC_INST_GET(id), \
455 .irq_enabled = true, \
456 .irq = GPIO_DT_SPEC_INST_GET(id, irq_gpios), \
457 }; \
458 \
459 static struct ht16k33_data ht16k33_##id##_data; \
460 \
461 DEVICE_DT_INST_DEFINE(id, &ht16k33_init, NULL, \
462 &ht16k33_##id##_data, \
463 &ht16k33_##id##_cfg, POST_KERNEL, \
464 CONFIG_LED_INIT_PRIORITY, &ht16k33_leds_api)
465 #else /* ! CONFIG_HT16K33_KEYSCAN */
466 #define HT16K33_DEVICE_WITH_IRQ(id) HT16K33_DEVICE(id)
467 #endif /* ! CONFIG_HT16K33_KEYSCAN */
468
469 #define HT16K33_INSTANTIATE(id) \
470 COND_CODE_1(DT_INST_NODE_HAS_PROP(id, irq_gpios), \
471 (HT16K33_DEVICE_WITH_IRQ(id)), \
472 (HT16K33_DEVICE(id)));
473
474 DT_INST_FOREACH_STATUS_OKAY(HT16K33_INSTANTIATE)
475