1 /*
2  * Copyright (c) 2020 Seagate Technology LLC
3  * Copyright (c) 2022 Grinn
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 /**
9  * @file
10  * @brief LP50xx LED controller
11  */
12 #include <errno.h>
13 #include <zephyr/device.h>
14 #include <zephyr/devicetree.h>
15 #include <zephyr/drivers/gpio.h>
16 #include <zephyr/drivers/i2c.h>
17 #include <zephyr/drivers/led.h>
18 #include <zephyr/drivers/led/lp50xx.h>
19 #include <zephyr/kernel.h>
20 #include <zephyr/pm/device.h>
21 #include <zephyr/sys/util.h>
22 
23 #include <zephyr/logging/log.h>
24 LOG_MODULE_REGISTER(lp50xx, CONFIG_LED_LOG_LEVEL);
25 
26 #define LP50XX_MAX_BRIGHTNESS		100U
27 
28 /*
29  * Number of supported RGB led modules per chipset.
30  *
31  * For each module, there are 4 associated registers:
32  *   - 1 brightness register
33  *   - 3 color registers (RGB)
34  *
35  * A chipset can have more modules than leds. In this case, the
36  * associated registers will simply be inactive.
37  */
38 #define LP5012_NUM_MODULES		4
39 #define LP5024_NUM_MODULES		8
40 #define LP5036_NUM_MODULES		12
41 
42 /* Maximum number of channels */
43 #define LP50XX_MAX_CHANNELS(nmodules)	\
44 	((LP50XX_COLORS_PER_LED + 1) * ((nmodules) + 1))
45 
46 #define LP50XX_DISABLE_DELAY_US		3
47 #define LP50XX_ENABLE_DELAY_US		500
48 
49 /* Base registers */
50 #define LP50XX_DEVICE_CONFIG0		0x00
51 #define LP50XX_DEVICE_CONFIG1		0x01
52 #define LP50XX_LED_CONFIG0		0x02
53 
54 #define LP50XX_BANK_BASE(nmodules)		\
55 	(0x03 + (((nmodules) - 1) / 8))
56 
57 #define LP50XX_LED0_BRIGHTNESS(nmodules)	\
58 	((LP50XX_BANK_BASE(nmodules)) + 4)
59 
60 #define LP50XX_OUT0_COLOR(nmodules)		\
61 	(LP50XX_LED0_BRIGHTNESS(nmodules) + (nmodules))
62 
63 #define LP50XX_RESET(nmodules)			\
64 	(LP50XX_OUT0_COLOR(nmodules) + LP50XX_COLORS_PER_LED * (nmodules))
65 
66 /* Register values */
67 #define CONFIG0_CHIP_EN			BIT(6)
68 
69 #define CONFIG1_LED_GLOBAL_OFF		BIT(0)
70 #define CONFIG1_MAX_CURRENT_OPT		BIT(1)
71 #define CONFIG1_PWM_DITHERING_EN	BIT(2)
72 #define CONFIG1_AUTO_INCR_EN		BIT(3)
73 #define CONFIG1_POWER_SAVE_EN		BIT(4)
74 #define CONFIG1_LOG_SCALE_EN		BIT(5)
75 
76 #define RESET_SW			0xFF
77 
78 struct lp50xx_config {
79 	struct i2c_dt_spec bus;
80 	const struct gpio_dt_spec gpio_enable;
81 	uint8_t num_modules;
82 	uint8_t max_leds;
83 	uint8_t num_leds;
84 	bool log_scale_en;
85 	bool max_curr_opt;
86 	const struct led_info *leds_info;
87 };
88 
89 struct lp50xx_data {
90 	uint8_t *chan_buf;
91 };
92 
lp50xx_led_to_info(const struct lp50xx_config * config,uint32_t led)93 static const struct led_info *lp50xx_led_to_info(
94 			const struct lp50xx_config *config, uint32_t led)
95 {
96 	if (led < config->num_leds) {
97 		return &config->leds_info[led];
98 	}
99 
100 	return NULL;
101 }
102 
lp50xx_get_info(const struct device * dev,uint32_t led,const struct led_info ** info)103 static int lp50xx_get_info(const struct device *dev, uint32_t led,
104 			   const struct led_info **info)
105 {
106 	const struct lp50xx_config *config = dev->config;
107 	const struct led_info *led_info = lp50xx_led_to_info(config, led);
108 
109 	if (!led_info) {
110 		return -EINVAL;
111 	}
112 
113 	*info = led_info;
114 
115 	return 0;
116 }
117 
lp50xx_set_brightness(const struct device * dev,uint32_t led,uint8_t value)118 static int lp50xx_set_brightness(const struct device *dev,
119 				 uint32_t led, uint8_t value)
120 {
121 	const struct lp50xx_config *config = dev->config;
122 	const struct led_info *led_info = lp50xx_led_to_info(config, led);
123 	uint8_t buf[2];
124 
125 	if (!led_info) {
126 		return -ENODEV;
127 	}
128 
129 	if (value > LP50XX_MAX_BRIGHTNESS) {
130 		LOG_ERR("%s: brightness value out of bounds: val=%d, max=%d",
131 			dev->name, value, LP50XX_MAX_BRIGHTNESS);
132 		return -EINVAL;
133 	}
134 
135 	buf[0] = LP50XX_LED0_BRIGHTNESS(config->num_modules) + led_info->index;
136 	buf[1] = (value * 0xff) / 100;
137 
138 	return i2c_write_dt(&config->bus, buf, sizeof(buf));
139 }
140 
lp50xx_on(const struct device * dev,uint32_t led)141 static int lp50xx_on(const struct device *dev, uint32_t led)
142 {
143 	return lp50xx_set_brightness(dev, led, 100);
144 }
145 
lp50xx_off(const struct device * dev,uint32_t led)146 static int lp50xx_off(const struct device *dev, uint32_t led)
147 {
148 	return lp50xx_set_brightness(dev, led, 0);
149 }
150 
lp50xx_set_color(const struct device * dev,uint32_t led,uint8_t num_colors,const uint8_t * color)151 static int lp50xx_set_color(const struct device *dev, uint32_t led,
152 			    uint8_t num_colors, const uint8_t *color)
153 {
154 	const struct lp50xx_config *config = dev->config;
155 	const struct led_info *led_info = lp50xx_led_to_info(config, led);
156 	uint8_t buf[LP50XX_COLORS_PER_LED + 1];
157 	uint8_t i;
158 
159 	if (!led_info) {
160 		return -ENODEV;
161 	}
162 
163 	if (num_colors != led_info->num_colors) {
164 		LOG_ERR("%s: invalid number of colors: got=%d, expected=%d",
165 			dev->name,
166 			num_colors,
167 			led_info->num_colors);
168 		return -EINVAL;
169 	}
170 
171 	buf[0] = LP50XX_OUT0_COLOR(config->num_modules);
172 	buf[0] += LP50XX_COLORS_PER_LED * led_info->index;
173 
174 	for (i = 0; i < led_info->num_colors; i++) {
175 		buf[1 + i] = color[i];
176 	}
177 
178 	return i2c_write_dt(&config->bus, buf, led_info->num_colors + 1);
179 }
180 
lp50xx_write_channels(const struct device * dev,uint32_t start_channel,uint32_t num_channels,const uint8_t * buf)181 static int lp50xx_write_channels(const struct device *dev,
182 				 uint32_t start_channel,
183 				 uint32_t num_channels, const uint8_t *buf)
184 {
185 	const struct lp50xx_config *config = dev->config;
186 	struct lp50xx_data *data = dev->data;
187 	uint8_t base_channel, end_channel, max_channels;
188 
189 	base_channel = LP50XX_BANK_BASE(config->num_modules);
190 	end_channel = base_channel + start_channel + num_channels;
191 	max_channels = base_channel + LP50XX_MAX_CHANNELS(config->num_modules);
192 
193 	if (end_channel > max_channels) {
194 		return -EINVAL;
195 	}
196 
197 	/*
198 	 * Unfortunately this controller doesn't support commands split into
199 	 * two I2C messages.
200 	 */
201 	data->chan_buf[0] = base_channel + start_channel;
202 	memcpy(data->chan_buf + 1, buf, num_channels);
203 
204 	return i2c_write_dt(&config->bus, data->chan_buf, num_channels + 1);
205 }
206 
lp50xx_reset(const struct device * dev)207 static int lp50xx_reset(const struct device *dev)
208 {
209 	const struct lp50xx_config *config = dev->config;
210 	uint8_t buf[2];
211 	int err;
212 
213 	/* Software reset */
214 	buf[0] = LP50XX_RESET(config->num_modules);
215 	buf[1] = RESET_SW;
216 	err = i2c_write_dt(&config->bus, buf, 2);
217 	if (err < 0) {
218 		return err;
219 	}
220 
221 	/* After reset, apply configuration since all registers are reset. */
222 	buf[0] = LP50XX_DEVICE_CONFIG1;
223 	buf[1] = CONFIG1_PWM_DITHERING_EN | CONFIG1_AUTO_INCR_EN
224 		| CONFIG1_POWER_SAVE_EN;
225 	if (config->max_curr_opt) {
226 		buf[1] |= CONFIG1_MAX_CURRENT_OPT;
227 	}
228 	if (config->log_scale_en) {
229 		buf[1] |= CONFIG1_LOG_SCALE_EN;
230 	}
231 
232 	return i2c_write_dt(&config->bus, buf, 2);
233 }
234 
lp50xx_hw_enable(const struct device * dev,bool enable)235 static int lp50xx_hw_enable(const struct device *dev, bool enable)
236 {
237 	const struct lp50xx_config *config = dev->config;
238 	int err;
239 
240 	if (config->gpio_enable.port == NULL) {
241 		/* Nothing to do */
242 		return 0;
243 	}
244 
245 	err = gpio_pin_set_dt(&config->gpio_enable, enable);
246 	if (err < 0) {
247 		LOG_ERR("%s: failed to set enable gpio", dev->name);
248 		return err;
249 	}
250 
251 	k_usleep(enable ? LP50XX_ENABLE_DELAY_US : LP50XX_DISABLE_DELAY_US);
252 
253 	return 0;
254 }
255 
lp50xx_enable(const struct device * dev,bool enable)256 static int lp50xx_enable(const struct device *dev, bool enable)
257 {
258 	const struct lp50xx_config *config = dev->config;
259 	uint8_t value = enable ? CONFIG0_CHIP_EN : 0;
260 
261 	return i2c_reg_update_byte_dt(&config->bus,
262 				      LP50XX_DEVICE_CONFIG0,
263 				      CONFIG0_CHIP_EN,
264 				      value);
265 }
266 
lp50xx_init(const struct device * dev)267 static int lp50xx_init(const struct device *dev)
268 {
269 	const struct lp50xx_config *config = dev->config;
270 	uint8_t led;
271 	int err;
272 
273 	if (!i2c_is_ready_dt(&config->bus)) {
274 		LOG_ERR("%s: I2C device not ready", dev->name);
275 		return -ENODEV;
276 	}
277 
278 	/* Check LED configuration found in DT */
279 	if (config->num_leds > config->max_leds) {
280 		LOG_ERR("%s: invalid number of LEDs %d (max %d)",
281 			dev->name,
282 			config->num_leds,
283 			config->max_leds);
284 		return -EINVAL;
285 	}
286 	for (led = 0; led < config->num_leds; led++) {
287 		const struct led_info *led_info =
288 			lp50xx_led_to_info(config, led);
289 
290 		if (led_info->num_colors > LP50XX_COLORS_PER_LED) {
291 			LOG_ERR("%s: LED %d: invalid number of colors (max %d)",
292 				dev->name, led, LP50XX_COLORS_PER_LED);
293 			return -EINVAL;
294 		}
295 	}
296 
297 	/* Configure GPIO if present */
298 	if (config->gpio_enable.port != NULL) {
299 		if (!gpio_is_ready_dt(&config->gpio_enable)) {
300 			LOG_ERR("%s: enable gpio is not ready", dev->name);
301 			return -ENODEV;
302 		}
303 
304 		err = gpio_pin_configure_dt(&config->gpio_enable,
305 					    GPIO_OUTPUT_INACTIVE);
306 		if (err < 0) {
307 			LOG_ERR("%s: failed to initialize enable gpio",
308 				dev->name);
309 			return err;
310 		}
311 	}
312 
313 	/* Enable hardware */
314 	err = lp50xx_hw_enable(dev, true);
315 	if (err < 0) {
316 		LOG_ERR("%s: failed to enable hardware", dev->name);
317 		return err;
318 	}
319 
320 	/* Reset device */
321 	err = lp50xx_reset(dev);
322 	if (err < 0) {
323 		LOG_ERR("%s: failed to reset", dev->name);
324 		return err;
325 	}
326 
327 	/* Enable device */
328 	err = lp50xx_enable(dev, true);
329 	if (err < 0) {
330 		LOG_ERR("%s: failed to enable", dev->name);
331 		return err;
332 	}
333 
334 	return 0;
335 }
336 
337 #ifdef CONFIG_PM_DEVICE
lp50xx_pm_action(const struct device * dev,enum pm_device_action action)338 static int lp50xx_pm_action(const struct device *dev,
339 			    enum pm_device_action action)
340 {
341 	switch (action) {
342 	case PM_DEVICE_ACTION_SUSPEND:
343 		return lp50xx_enable(dev, false);
344 	case PM_DEVICE_ACTION_RESUME:
345 		return lp50xx_enable(dev, true);
346 	default:
347 		return -ENOTSUP;
348 	}
349 
350 	return 0;
351 }
352 #endif /* CONFIG_PM_DEVICE */
353 
354 static DEVICE_API(led, lp50xx_led_api) = {
355 	.on		= lp50xx_on,
356 	.off		= lp50xx_off,
357 	.get_info	= lp50xx_get_info,
358 	.set_brightness	= lp50xx_set_brightness,
359 	.set_color	= lp50xx_set_color,
360 	.write_channels	= lp50xx_write_channels,
361 };
362 
363 #define COLOR_MAPPING(led_node_id)						\
364 	const uint8_t color_mapping_##led_node_id[] =				\
365 		DT_PROP(led_node_id, color_mapping);
366 
367 #define LED_INFO(led_node_id)							\
368 	{									\
369 		.label		= DT_PROP(led_node_id, label),			\
370 		.index		= DT_PROP(led_node_id, index),			\
371 		.num_colors	=						\
372 			DT_PROP_LEN(led_node_id, color_mapping),		\
373 		.color_mapping	= color_mapping_##led_node_id,			\
374 	},
375 
376 #define LP50XX_DEVICE(n, id, nmodules)						\
377 	DT_INST_FOREACH_CHILD(n, COLOR_MAPPING)					\
378 										\
379 	static const struct led_info lp##id##_leds_##n[] = {			\
380 		DT_INST_FOREACH_CHILD(n, LED_INFO)				\
381 	};									\
382 										\
383 	static const struct lp50xx_config lp##id##_config_##n = {		\
384 		.bus			= I2C_DT_SPEC_INST_GET(n),		\
385 		.gpio_enable		=					\
386 			GPIO_DT_SPEC_INST_GET_OR(n, enable_gpios, {0}),		\
387 		.num_modules		= nmodules,				\
388 		.max_leds		= LP##id##_MAX_LEDS,			\
389 		.num_leds		= ARRAY_SIZE(lp##id##_leds_##n),	\
390 		.log_scale_en		= DT_INST_PROP(n, log_scale_en),	\
391 		.max_curr_opt		= DT_INST_PROP(n, max_curr_opt),	\
392 		.leds_info		= lp##id##_leds_##n,			\
393 	};									\
394 										\
395 	static uint8_t lp##id##_chan_buf_##n[LP50XX_MAX_CHANNELS(nmodules) + 1];\
396 										\
397 	static struct lp50xx_data lp##id##_data_##n = {				\
398 		.chan_buf	= lp##id##_chan_buf_##n,			\
399 	};									\
400 										\
401 	PM_DEVICE_DT_INST_DEFINE(n, lp50xx_pm_action);				\
402 										\
403 	DEVICE_DT_INST_DEFINE(n,						\
404 			      lp50xx_init,					\
405 			      PM_DEVICE_DT_INST_GET(n),				\
406 			      &lp##id##_data_##n,				\
407 			      &lp##id##_config_##n,				\
408 			      POST_KERNEL, CONFIG_LED_INIT_PRIORITY,		\
409 			      &lp50xx_led_api);
410 
411 #undef DT_DRV_COMPAT
412 #define DT_DRV_COMPAT ti_lp5009
413 DT_INST_FOREACH_STATUS_OKAY_VARGS(LP50XX_DEVICE, 5009, LP5012_NUM_MODULES)
414 
415 #undef DT_DRV_COMPAT
416 #define DT_DRV_COMPAT ti_lp5012
417 DT_INST_FOREACH_STATUS_OKAY_VARGS(LP50XX_DEVICE, 5012, LP5012_NUM_MODULES)
418 
419 #undef DT_DRV_COMPAT
420 #define DT_DRV_COMPAT ti_lp5018
421 DT_INST_FOREACH_STATUS_OKAY_VARGS(LP50XX_DEVICE, 5018, LP5024_NUM_MODULES)
422 
423 #undef DT_DRV_COMPAT
424 #define DT_DRV_COMPAT ti_lp5024
425 DT_INST_FOREACH_STATUS_OKAY_VARGS(LP50XX_DEVICE, 5024, LP5024_NUM_MODULES)
426 
427 #undef DT_DRV_COMPAT
428 #define DT_DRV_COMPAT ti_lp5030
429 DT_INST_FOREACH_STATUS_OKAY_VARGS(LP50XX_DEVICE, 5030, LP5036_NUM_MODULES)
430 
431 #undef DT_DRV_COMPAT
432 #define DT_DRV_COMPAT ti_lp5036
433 DT_INST_FOREACH_STATUS_OKAY_VARGS(LP50XX_DEVICE, 5036, LP5036_NUM_MODULES)
434