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/input/input.h>
17 #include <zephyr/kernel.h>
18 #include <zephyr/drivers/led.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 struct gpio_callback irq_cb;
81 struct k_thread irq_thread;
82 struct k_sem irq_sem;
83 struct k_timer timer;
84 uint16_t key_state[HT16K33_KEYSCAN_ROWS];
85
86 K_KERNEL_STACK_MEMBER(irq_thread_stack,
87 CONFIG_HT16K33_KEYSCAN_IRQ_THREAD_STACK_SIZE);
88 #endif /* CONFIG_HT16K33_KEYSCAN */
89 };
90
ht16k33_led_blink(const struct device * dev,uint32_t led,uint32_t delay_on,uint32_t delay_off)91 static int ht16k33_led_blink(const struct device *dev, uint32_t led,
92 uint32_t delay_on, uint32_t delay_off)
93 {
94 /* The HT16K33 blinks all LEDs at the same frequency */
95 ARG_UNUSED(led);
96
97 const struct ht16k33_cfg *config = dev->config;
98 struct ht16k33_data *data = dev->data;
99 struct led_data *dev_data = &data->dev_data;
100 uint32_t period;
101 uint8_t cmd;
102
103 period = delay_on + delay_off;
104 if (period < dev_data->min_period || period > dev_data->max_period) {
105 return -EINVAL;
106 }
107
108 cmd = HT16K33_CMD_DISP_SETUP | HT16K33_OPT_D;
109 if (delay_off == 0) {
110 cmd |= HT16K33_OPT_BLINK_OFF;
111 } else if (period > 1500) {
112 cmd |= HT16K33_OPT_BLINK_05HZ;
113 } else if (period > 750) {
114 cmd |= HT16K33_OPT_BLINK_1HZ;
115 } else {
116 cmd |= HT16K33_OPT_BLINK_2HZ;
117 }
118
119 if (i2c_write_dt(&config->i2c, &cmd, sizeof(cmd))) {
120 LOG_ERR("Setting HT16K33 blink frequency failed");
121 return -EIO;
122 }
123
124 return 0;
125 }
126
ht16k33_led_set_brightness(const struct device * dev,uint32_t led,uint8_t value)127 static int ht16k33_led_set_brightness(const struct device *dev, uint32_t led,
128 uint8_t value)
129 {
130 ARG_UNUSED(led);
131
132 const struct ht16k33_cfg *config = dev->config;
133 struct ht16k33_data *data = dev->data;
134 struct led_data *dev_data = &data->dev_data;
135 uint8_t dim;
136 uint8_t cmd;
137
138 if (value < dev_data->min_brightness ||
139 value > dev_data->max_brightness) {
140 return -EINVAL;
141 }
142
143 dim = (value * (HT16K33_DIMMING_LEVELS - 1)) / dev_data->max_brightness;
144 cmd = HT16K33_CMD_DIMMING_SET | dim;
145
146 if (i2c_write_dt(&config->i2c, &cmd, sizeof(cmd))) {
147 LOG_ERR("Setting HT16K33 brightness failed");
148 return -EIO;
149 }
150
151 return 0;
152 }
153
ht16k33_led_set_state(const struct device * dev,uint32_t led,bool on)154 static int ht16k33_led_set_state(const struct device *dev, uint32_t led,
155 bool on)
156 {
157 const struct ht16k33_cfg *config = dev->config;
158 struct ht16k33_data *data = dev->data;
159 uint8_t cmd[2];
160 uint8_t addr;
161 uint8_t bit;
162
163 if (led >= HT16K33_DISP_SEGMENTS) {
164 return -EINVAL;
165 }
166
167 addr = led / HT16K33_DISP_COLS;
168 bit = led % HT16K33_DISP_COLS;
169
170 cmd[0] = HT16K33_CMD_DISP_DATA_ADDR | addr;
171 if (on) {
172 cmd[1] = data->buffer[addr] | BIT(bit);
173 } else {
174 cmd[1] = data->buffer[addr] & ~BIT(bit);
175 }
176
177 if (data->buffer[addr] == cmd[1]) {
178 return 0;
179 }
180
181 if (i2c_write_dt(&config->i2c, cmd, sizeof(cmd))) {
182 LOG_ERR("Setting HT16K33 LED %s failed", on ? "on" : "off");
183 return -EIO;
184 }
185
186 data->buffer[addr] = cmd[1];
187
188 return 0;
189 }
190
ht16k33_led_on(const struct device * dev,uint32_t led)191 static int ht16k33_led_on(const struct device *dev, uint32_t led)
192 {
193 return ht16k33_led_set_state(dev, led, true);
194 }
195
ht16k33_led_off(const struct device * dev,uint32_t led)196 static int ht16k33_led_off(const struct device *dev, uint32_t led)
197 {
198 return ht16k33_led_set_state(dev, led, false);
199 }
200
201 #ifdef CONFIG_HT16K33_KEYSCAN
ht16k33_process_keyscan_data(const struct device * dev)202 static bool ht16k33_process_keyscan_data(const struct device *dev)
203 {
204 const struct ht16k33_cfg *config = dev->config;
205 struct ht16k33_data *data = dev->data;
206 uint8_t keys[HT16K33_KEYSCAN_DATA_SIZE];
207 bool pressed = false;
208 uint16_t state;
209 uint16_t changed;
210 int row;
211 int col;
212 int err;
213
214 err = i2c_burst_read_dt(&config->i2c, HT16K33_CMD_KEY_DATA_ADDR, keys, sizeof(keys));
215 if (err) {
216 LOG_WRN("Failed to read HT16K33 key data (err %d)", err);
217 /* Reprocess */
218 return true;
219 }
220
221 k_mutex_lock(&data->lock, K_FOREVER);
222
223 for (row = 0; row < HT16K33_KEYSCAN_ROWS; row++) {
224 state = sys_get_le16(&keys[row * 2]);
225 changed = data->key_state[row] ^ state;
226 data->key_state[row] = state;
227
228 if (state) {
229 pressed = true;
230 }
231
232 for (col = 0; col < HT16K33_KEYSCAN_COLS; col++) {
233 if ((changed & BIT(col)) == 0) {
234 continue;
235 }
236 input_report_abs(dev, INPUT_ABS_X, col, false, K_FOREVER);
237 input_report_abs(dev, INPUT_ABS_Y, row, false, K_FOREVER);
238 input_report_key(dev, INPUT_BTN_TOUCH, state & BIT(col), true, K_FOREVER);
239 }
240 }
241
242 k_mutex_unlock(&data->lock);
243
244 return pressed;
245 }
246
ht16k33_irq_thread(void * p1,void * p2,void * p3)247 static void ht16k33_irq_thread(void *p1, void *p2, void *p3)
248 {
249 ARG_UNUSED(p2);
250 ARG_UNUSED(p3);
251
252 struct ht16k33_data *data = p1;
253 bool pressed;
254
255 while (true) {
256 k_sem_take(&data->irq_sem, K_FOREVER);
257
258 do {
259 k_sem_reset(&data->irq_sem);
260 pressed = ht16k33_process_keyscan_data(data->dev);
261 k_msleep(CONFIG_HT16K33_KEYSCAN_DEBOUNCE_MSEC);
262 } while (pressed);
263 }
264 }
265
ht16k33_irq_callback(const struct device * gpiob,struct gpio_callback * cb,uint32_t pins)266 static void ht16k33_irq_callback(const struct device *gpiob,
267 struct gpio_callback *cb, uint32_t pins)
268 {
269 struct ht16k33_data *data;
270
271 ARG_UNUSED(gpiob);
272 ARG_UNUSED(pins);
273
274 data = CONTAINER_OF(cb, struct ht16k33_data, irq_cb);
275 k_sem_give(&data->irq_sem);
276 }
277
ht16k33_timer_callback(struct k_timer * timer)278 static void ht16k33_timer_callback(struct k_timer *timer)
279 {
280 struct ht16k33_data *data;
281
282 data = CONTAINER_OF(timer, struct ht16k33_data, timer);
283 k_sem_give(&data->irq_sem);
284 }
285 #endif /* CONFIG_HT16K33_KEYSCAN */
286
ht16k33_init(const struct device * dev)287 static int ht16k33_init(const struct device *dev)
288 {
289 const struct ht16k33_cfg *config = dev->config;
290 struct ht16k33_data *data = dev->data;
291 struct led_data *dev_data = &data->dev_data;
292 uint8_t cmd[1 + HT16K33_DISP_DATA_SIZE]; /* 1 byte command + data */
293 int err;
294
295 data->dev = dev;
296
297 if (!device_is_ready(config->i2c.bus)) {
298 LOG_ERR("I2C bus device not ready");
299 return -EINVAL;
300 }
301
302 memset(&data->buffer, 0, sizeof(data->buffer));
303
304 /* Hardware specific limits */
305 dev_data->min_period = 0U;
306 dev_data->max_period = 2000U;
307 dev_data->min_brightness = 0U;
308 dev_data->max_brightness = 100U;
309
310 /* System oscillator on */
311 cmd[0] = HT16K33_CMD_SYSTEM_SETUP | HT16K33_OPT_S;
312 err = i2c_write_dt(&config->i2c, cmd, 1);
313 if (err) {
314 LOG_ERR("Enabling HT16K33 system oscillator failed (err %d)",
315 err);
316 return -EIO;
317 }
318
319 /* Clear display RAM */
320 memset(cmd, 0, sizeof(cmd));
321 cmd[0] = HT16K33_CMD_DISP_DATA_ADDR;
322 err = i2c_write_dt(&config->i2c, cmd, sizeof(cmd));
323 if (err) {
324 LOG_ERR("Clearing HT16K33 display RAM failed (err %d)", err);
325 return -EIO;
326 }
327
328 /* Full brightness */
329 cmd[0] = HT16K33_CMD_DIMMING_SET | 0x0f;
330 err = i2c_write_dt(&config->i2c, cmd, 1);
331 if (err) {
332 LOG_ERR("Setting HT16K33 brightness failed (err %d)", err);
333 return -EIO;
334 }
335
336 /* Display on, blinking off */
337 cmd[0] = HT16K33_CMD_DISP_SETUP | HT16K33_OPT_D | HT16K33_OPT_BLINK_OFF;
338 err = i2c_write_dt(&config->i2c, cmd, 1);
339 if (err) {
340 LOG_ERR("Enabling HT16K33 display failed (err %d)", err);
341 return -EIO;
342 }
343
344 #ifdef CONFIG_HT16K33_KEYSCAN
345 k_mutex_init(&data->lock);
346 k_sem_init(&data->irq_sem, 0, 1);
347
348 /* Configure interrupt */
349 if (config->irq_enabled) {
350 uint8_t keys[HT16K33_KEYSCAN_DATA_SIZE];
351
352 if (!gpio_is_ready_dt(&config->irq)) {
353 LOG_ERR("IRQ device not ready");
354 return -EINVAL;
355 }
356
357 err = gpio_pin_configure_dt(&config->irq, GPIO_INPUT);
358 if (err) {
359 LOG_ERR("Failed to configure IRQ pin (err %d)", err);
360 return -EINVAL;
361 }
362
363 gpio_init_callback(&data->irq_cb, &ht16k33_irq_callback,
364 BIT(config->irq.pin));
365
366 err = gpio_add_callback(config->irq.port, &data->irq_cb);
367 if (err) {
368 LOG_ERR("Failed to add IRQ callback (err %d)", err);
369 return -EINVAL;
370 }
371
372 /* Enable interrupt pin */
373 cmd[0] = HT16K33_CMD_ROW_INT_SET | HT16K33_OPT_INT_LOW;
374 if (i2c_write_dt(&config->i2c, cmd, 1)) {
375 LOG_ERR("Enabling HT16K33 IRQ output failed");
376 return -EIO;
377 }
378
379 /* Flush key data before enabling interrupt */
380 err = i2c_burst_read_dt(&config->i2c, HT16K33_CMD_KEY_DATA_ADDR, keys,
381 sizeof(keys));
382 if (err) {
383 LOG_ERR("Failed to read HT16K33 key data");
384 return -EIO;
385 }
386
387 err = gpio_pin_interrupt_configure_dt(&config->irq,
388 GPIO_INT_EDGE_FALLING);
389 if (err) {
390 LOG_ERR("Failed to configure IRQ pin flags (err %d)",
391 err);
392 return -EINVAL;
393 }
394 } else {
395 /* No interrupt pin, enable ROW15 */
396 cmd[0] = HT16K33_CMD_ROW_INT_SET | HT16K33_OPT_ROW;
397 if (i2c_write_dt(&config->i2c, cmd, 1)) {
398 LOG_ERR("Enabling HT16K33 ROW15 output failed");
399 return -EIO;
400 }
401
402 /* Setup timer for polling key data */
403 k_timer_init(&data->timer, ht16k33_timer_callback, NULL);
404 k_timer_start(&data->timer, K_NO_WAIT,
405 K_MSEC(CONFIG_HT16K33_KEYSCAN_POLL_MSEC));
406 }
407
408 k_thread_create(&data->irq_thread, data->irq_thread_stack,
409 CONFIG_HT16K33_KEYSCAN_IRQ_THREAD_STACK_SIZE,
410 ht16k33_irq_thread, data, NULL, NULL,
411 K_PRIO_COOP(CONFIG_HT16K33_KEYSCAN_IRQ_THREAD_PRIO),
412 0, K_NO_WAIT);
413 #endif /* CONFIG_HT16K33_KEYSCAN */
414
415 return 0;
416 }
417
418 static DEVICE_API(led, ht16k33_leds_api) = {
419 .blink = ht16k33_led_blink,
420 .set_brightness = ht16k33_led_set_brightness,
421 .on = ht16k33_led_on,
422 .off = ht16k33_led_off,
423 };
424
425 #define HT16K33_DEVICE(id) \
426 static const struct ht16k33_cfg ht16k33_##id##_cfg = { \
427 .i2c = I2C_DT_SPEC_INST_GET(id), \
428 .irq_enabled = false, \
429 }; \
430 \
431 static struct ht16k33_data ht16k33_##id##_data; \
432 \
433 DEVICE_DT_INST_DEFINE(id, &ht16k33_init, NULL, \
434 &ht16k33_##id##_data, \
435 &ht16k33_##id##_cfg, POST_KERNEL, \
436 CONFIG_LED_INIT_PRIORITY, &ht16k33_leds_api)
437
438 #ifdef CONFIG_HT16K33_KEYSCAN
439 #define HT16K33_DEVICE_WITH_IRQ(id) \
440 static const struct ht16k33_cfg ht16k33_##id##_cfg = { \
441 .i2c = I2C_DT_SPEC_INST_GET(id), \
442 .irq_enabled = true, \
443 .irq = GPIO_DT_SPEC_INST_GET(id, irq_gpios), \
444 }; \
445 \
446 static struct ht16k33_data ht16k33_##id##_data; \
447 \
448 DEVICE_DT_INST_DEFINE(id, &ht16k33_init, NULL, \
449 &ht16k33_##id##_data, \
450 &ht16k33_##id##_cfg, POST_KERNEL, \
451 CONFIG_LED_INIT_PRIORITY, &ht16k33_leds_api)
452 #else /* ! CONFIG_HT16K33_KEYSCAN */
453 #define HT16K33_DEVICE_WITH_IRQ(id) HT16K33_DEVICE(id)
454 #endif /* ! CONFIG_HT16K33_KEYSCAN */
455
456 #define HT16K33_INSTANTIATE(id) \
457 COND_CODE_1(DT_INST_NODE_HAS_PROP(id, irq_gpios), \
458 (HT16K33_DEVICE_WITH_IRQ(id)), \
459 (HT16K33_DEVICE(id)));
460
461 DT_INST_FOREACH_STATUS_OKAY(HT16K33_INSTANTIATE)
462