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