1 /*
2  * Copyright (c) 2020 Seagate Technology LLC
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <errno.h>
8 #include <zephyr/device.h>
9 #include <zephyr/devicetree.h>
10 #include <zephyr/drivers/led.h>
11 #include <zephyr/drivers/led/lp50xx.h>
12 #include <zephyr/dt-bindings/led/led.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/sys/util.h>
15 
16 #define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(main);
19 
20 #define MAX_BRIGHTNESS	100
21 
22 #define SLEEP_DELAY_MS	1000
23 #define FADE_DELAY_MS	10
24 
25 #define FADE_DELAY	K_MSEC(FADE_DELAY_MS)
26 #define SLEEP_DELAY	K_MSEC(SLEEP_DELAY_MS)
27 
28 /*
29  * The following colors are shown in the given order. Each row index is sorted
30  * in RGB order.
31  */
32 static uint8_t colors[][3] = {
33 	{ 0xFF, 0x00, 0x00 }, /* Red    */
34 	{ 0x00, 0xFF, 0x00 }, /* Green  */
35 	{ 0x00, 0x00, 0xFF }, /* Blue   */
36 	{ 0xFF, 0xFF, 0xFF }, /* White  */
37 	{ 0xFF, 0xFF, 0x00 }, /* Yellow */
38 	{ 0xFF, 0x00, 0xFF }, /* Purple */
39 	{ 0x00, 0xFF, 0xFF }, /* Cyan   */
40 	{ 0xF4, 0x79, 0x20 }, /* Orange */
41 };
42 
43 /*
44  * Prepare a color buffer for a single LED using its color mapping and the
45  * desired color index.
46  */
prepare_color_buffer(const struct led_info * info,uint8_t * buf,uint8_t color_idx)47 static int prepare_color_buffer(const struct led_info *info, uint8_t *buf,
48 				uint8_t color_idx)
49 {
50 	uint8_t color;
51 
52 	for (color = 0; color < info->num_colors; color++) {
53 		switch (info->color_mapping[color]) {
54 		case LED_COLOR_ID_RED:
55 			buf[color] = colors[color_idx][0];
56 			continue;
57 		case LED_COLOR_ID_GREEN:
58 			buf[color] = colors[color_idx][1];
59 			continue;
60 		case LED_COLOR_ID_BLUE:
61 			buf[color] = colors[color_idx][2];
62 			continue;
63 		default:
64 			LOG_ERR("Invalid color: %d",
65 				info->color_mapping[color]);
66 			return -EINVAL;
67 		}
68 	}
69 
70 	return 0;
71 }
72 
73 /**
74  * @brief Run tests on a single LED using the LED-based API syscalls.
75  *
76  * @param lp50xx_dev LP50XX LED controller device.
77  * @param led Number of the LED to test.
78  */
run_led_test(const struct device * lp50xx_dev,uint8_t led)79 static int run_led_test(const struct device *lp50xx_dev, uint8_t led)
80 {
81 	const struct led_info *info;
82 	uint8_t idx;
83 	int err;
84 
85 	LOG_INF("Testing LED %d (LED API)", led);
86 
87 	err = led_get_info(lp50xx_dev, led, &info);
88 	if (err < 0) {
89 		LOG_ERR("Failed to get LED %d info", led);
90 		return err;
91 	}
92 
93 	for (idx = 0; idx < ARRAY_SIZE(colors); idx++) {
94 		uint16_t level;
95 		uint8_t buf[3];
96 
97 		err = prepare_color_buffer(info, buf, idx);
98 		if (err < 0) {
99 			LOG_ERR("Failed to set color buffer, err=%d", err);
100 			return err;
101 		}
102 
103 		/* Update LED color. */
104 		err = led_set_color(lp50xx_dev, led, 3, buf);
105 		if (err < 0) {
106 			LOG_ERR("Failed to set LED %d color to "
107 				"%02x:%02x:%02x, err=%d", led,
108 				buf[0], buf[1], buf[2], err);
109 			return err;
110 		}
111 		k_sleep(SLEEP_DELAY);
112 
113 		/* Turn LED on. */
114 		err = led_on(lp50xx_dev, led);
115 		if (err < 0) {
116 			LOG_ERR("Failed to turn LED %d on, err=%d", led, err);
117 			return err;
118 		}
119 		k_sleep(SLEEP_DELAY);
120 
121 		/* Turn LED off. */
122 		err = led_off(lp50xx_dev, led);
123 		if (err < 0) {
124 			LOG_ERR("Failed to turn LED %d off, err=%d", led, err);
125 			return err;
126 		}
127 		k_sleep(SLEEP_DELAY);
128 
129 		/* Set LED brightness gradually to the maximum level. */
130 		for (level = 0; level <= MAX_BRIGHTNESS; level++) {
131 			err = led_set_brightness(lp50xx_dev, led, level);
132 			if (err < 0) {
133 				LOG_ERR("Failed to set LED %d brightness to %d"
134 					", err=%d\n", led, level, err);
135 				return err;
136 			}
137 			k_sleep(FADE_DELAY);
138 		}
139 		k_sleep(SLEEP_DELAY);
140 
141 		/* Turn LED off. */
142 		err = led_off(lp50xx_dev, led);
143 		if (err < 0) {
144 			LOG_ERR("Failed to turn LED %d off, err=%d", led, err);
145 			return err;
146 		}
147 		k_sleep(SLEEP_DELAY);
148 	}
149 
150 	return 0;
151 }
152 
153 /**
154  * @brief Run tests on all the LEDs using the channel-based API syscalls.
155  *
156  * @param lp50xx_dev LP50XX LED controller device.
157  */
run_channel_test(const struct device * lp50xx_dev,const uint8_t max_leds,const uint8_t bright_chan,const uint8_t color_chan)158 static int run_channel_test(const struct device *lp50xx_dev,
159 			    const uint8_t max_leds,
160 			    const uint8_t bright_chan,
161 			    const uint8_t color_chan)
162 {
163 	uint8_t idx;
164 	uint8_t buffer[LP50XX_COLORS_PER_LED * max_leds];
165 	int err;
166 
167 	LOG_INF("Testing all LEDs (channel API)");
168 
169 	for (idx = 0; idx < ARRAY_SIZE(colors); idx++) {
170 		uint8_t led;
171 		uint16_t level;
172 
173 		/* Update LEDs colors. */
174 		memset(buffer, 0, sizeof(buffer));
175 		for (led = 0; led < max_leds; led++) {
176 			const struct led_info *info;
177 			uint8_t *col = &buffer[led * 3];
178 
179 			err = led_get_info(lp50xx_dev, led, &info);
180 			if (err < 0) {
181 				continue;
182 			}
183 
184 			col = &buffer[info->index * 3];
185 			err = prepare_color_buffer(info, col, idx);
186 			if (err < 0) {
187 				LOG_ERR("Failed to set color buffer, err=%d",
188 					err);
189 				return err;
190 			}
191 		}
192 
193 		err = led_write_channels(lp50xx_dev, color_chan,
194 					 LP50XX_COLORS_PER_LED *
195 					 max_leds,
196 					 buffer);
197 		if (err < 0) {
198 			LOG_ERR("Failed to write channels, start=%d num=%d"
199 				" err=%d\n", color_chan,
200 				LP50XX_COLORS_PER_LED * max_leds, err);
201 			return err;
202 		}
203 		k_sleep(SLEEP_DELAY);
204 
205 		/* Turn LEDs on. */
206 		memset(buffer, 0, sizeof(buffer));
207 		for (led = 0; led < max_leds; led++) {
208 			buffer[led] = MAX_BRIGHTNESS;
209 		}
210 		err = led_write_channels(lp50xx_dev,
211 					 bright_chan,
212 					 max_leds, buffer);
213 		if (err < 0) {
214 			LOG_ERR("Failed to write channels, start=%d num=%d"
215 				" err=%d\n", bright_chan,
216 				max_leds, err);
217 			return err;
218 		}
219 		k_sleep(SLEEP_DELAY);
220 
221 		/* Turn LEDs off. */
222 		for (led = 0; led < max_leds; led++) {
223 			buffer[led] = 0;
224 		}
225 		err = led_write_channels(lp50xx_dev,
226 					 bright_chan,
227 					 max_leds, buffer);
228 		if (err < 0) {
229 			LOG_ERR("Failed to write channels, start=%d num=%d"
230 				" err=%d\n", bright_chan,
231 				max_leds, err);
232 			return err;
233 		}
234 		k_sleep(SLEEP_DELAY);
235 
236 		/* Set LEDs brightnesses gradually to the maximum level. */
237 		for (level = 0; level <= MAX_BRIGHTNESS; level++) {
238 			for (led = 0; led < max_leds; led++) {
239 				buffer[led] = level;
240 			}
241 			err = led_write_channels(lp50xx_dev,
242 					bright_chan,
243 					max_leds, buffer);
244 			if (err < 0) {
245 				LOG_ERR("Failed to write channels, start=%d"
246 					" num=%d err=%d\n",
247 					bright_chan,
248 					max_leds, err);
249 				return err;
250 			}
251 			k_sleep(FADE_DELAY);
252 		}
253 		k_sleep(SLEEP_DELAY);
254 
255 		/* Turn LEDs off. */
256 		for (led = 0; led < max_leds; led++) {
257 			buffer[led] = 0;
258 		}
259 		err = led_write_channels(lp50xx_dev,
260 					 bright_chan,
261 					 max_leds, buffer);
262 		if (err < 0) {
263 			LOG_ERR("Failed to write channels, start=%d "
264 				"num=%d err=%d\n", bright_chan,
265 				max_leds, err);
266 			return err;
267 		}
268 		k_sleep(SLEEP_DELAY);
269 	}
270 
271 	return 0;
272 }
273 
run_test(const struct device * const lp50xx_dev,const uint8_t max_leds,const uint8_t bright_chan,const uint8_t color_chan)274 static int run_test(const struct device *const lp50xx_dev,
275 		    const uint8_t max_leds,
276 		    const uint8_t bright_chan,
277 		    const uint8_t color_chan)
278 {
279 	int err;
280 	uint8_t led;
281 	uint8_t num_leds = 0;
282 
283 	for (led = 0; led < max_leds; led++) {
284 		int col;
285 		const struct led_info *info;
286 
287 		err = led_get_info(lp50xx_dev, led, &info);
288 		if (err < 0) {
289 			LOG_DBG("Failed to get information for LED %d (err=%d)",
290 				led, err);
291 			break;
292 		}
293 
294 		/* Display LED information. */
295 		printk("Found LED %d", led);
296 		if (info->label) {
297 			printk(" - %s", info->label);
298 		}
299 		printk(" - index:%d", info->index);
300 		printk(" - %d colors", info->num_colors);
301 		if (!info->color_mapping) {
302 			continue;
303 		}
304 		printk(" - %d", info->color_mapping[0]);
305 		for (col = 1; col < info->num_colors; col++) {
306 			printk(":%d", info->color_mapping[col]);
307 		}
308 		printk("\n");
309 	}
310 
311 	num_leds = led;
312 	if (!num_leds) {
313 		LOG_ERR("No LEDs found");
314 		return 0;
315 	}
316 
317 	do {
318 		err = run_channel_test(lp50xx_dev, max_leds, bright_chan,
319 					color_chan);
320 		if (err) {
321 			return 0;
322 		}
323 		for (led = 0; led < num_leds; led++) {
324 			err = run_led_test(lp50xx_dev, led);
325 			if (err) {
326 				return 0;
327 			}
328 		}
329 	} while (true);
330 	return 0;
331 }
332 
main(void)333 int main(void)
334 {
335 	const struct device *lp50xx_dev;
336 	bool found = false;
337 
338 	lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5009);
339 	if (lp50xx_dev) {
340 		LOG_INF("Found LED controller %s", lp50xx_dev->name);
341 		found = true;
342 
343 		if (device_is_ready(lp50xx_dev)) {
344 			run_test(lp50xx_dev,
345 				 LP5009_MAX_LEDS,
346 				 LP50XX_LED_BRIGHT_CHAN_BASE,
347 				 LP5012_LED_COL_CHAN_BASE);
348 		} else {
349 			LOG_ERR("LED controller %s is not ready",
350 				lp50xx_dev->name);
351 		}
352 	}
353 
354 	lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5012);
355 	if (lp50xx_dev) {
356 		LOG_INF("Found LED controller %s", lp50xx_dev->name);
357 		found = true;
358 
359 		if (device_is_ready(lp50xx_dev)) {
360 			run_test(lp50xx_dev,
361 				 LP5012_MAX_LEDS,
362 				 LP50XX_LED_BRIGHT_CHAN_BASE,
363 				 LP5012_LED_COL_CHAN_BASE);
364 		} else {
365 			LOG_ERR("LED controller %s is not ready",
366 				lp50xx_dev->name);
367 		}
368 	}
369 
370 	lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5018);
371 	if (lp50xx_dev) {
372 		LOG_INF("Found LED controller %s", lp50xx_dev->name);
373 		found = true;
374 
375 		if (device_is_ready(lp50xx_dev)) {
376 			run_test(lp50xx_dev,
377 				 LP5018_MAX_LEDS,
378 				 LP50XX_LED_BRIGHT_CHAN_BASE,
379 				 LP5024_LED_COL_CHAN_BASE);
380 		} else {
381 			LOG_ERR("LED controller %s is not ready",
382 				lp50xx_dev->name);
383 		}
384 	}
385 
386 	lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5024);
387 	if (lp50xx_dev) {
388 		LOG_INF("Found LED controller %s", lp50xx_dev->name);
389 		found = true;
390 
391 		if (device_is_ready(lp50xx_dev)) {
392 			run_test(lp50xx_dev,
393 				 LP5024_MAX_LEDS,
394 				 LP50XX_LED_BRIGHT_CHAN_BASE,
395 				 LP5024_LED_COL_CHAN_BASE);
396 		} else {
397 			LOG_ERR("LED controller %s is not ready",
398 				lp50xx_dev->name);
399 		}
400 	}
401 
402 	lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5030);
403 	if (lp50xx_dev) {
404 		LOG_INF("Found LED controller %s", lp50xx_dev->name);
405 		found = true;
406 
407 		if (device_is_ready(lp50xx_dev)) {
408 			run_test(lp50xx_dev,
409 				 LP5030_MAX_LEDS,
410 				 LP50XX_LED_BRIGHT_CHAN_BASE,
411 				 LP5036_LED_COL_CHAN_BASE);
412 		} else {
413 			LOG_ERR("LED controller %s is not ready",
414 				lp50xx_dev->name);
415 		}
416 	}
417 
418 	lp50xx_dev = DEVICE_DT_GET_ANY(ti_lp5036);
419 	if (lp50xx_dev) {
420 		LOG_INF("Found LED controller %s", lp50xx_dev->name);
421 		found = true;
422 
423 		if (device_is_ready(lp50xx_dev)) {
424 			run_test(lp50xx_dev,
425 				 LP5036_MAX_LEDS,
426 				 LP50XX_LED_BRIGHT_CHAN_BASE,
427 				 LP5036_LED_COL_CHAN_BASE);
428 		} else {
429 			LOG_ERR("LED controller %s is not ready",
430 				lp50xx_dev->name);
431 		}
432 	}
433 
434 	if (!found) {
435 		LOG_ERR("No LP50XX LED controller found");
436 	}
437 	return 0;
438 }
439