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