1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #define DT_DRV_COMPAT nordic_npm1300_led
7 
8 #include <errno.h>
9 
10 #include <zephyr/device.h>
11 #include <zephyr/drivers/led.h>
12 #include <zephyr/drivers/mfd/npm1300.h>
13 
14 /* nPM1300 LED base address */
15 #define NPM_LED_BASE 0x0AU
16 
17 /* nPM1300 LED register offsets */
18 #define NPM_LED_OFFSET_MODE 0x00U
19 #define NPM_LED_OFFSET_SET  0x03U
20 #define NPM_LED_OFFSET_CLR  0x04U
21 
22 /* nPM1300 Channel counts */
23 #define NPM1300_LED_PINS 3U
24 
25 /* nPM1300 LED modes */
26 #define NPM_LED_HOST 2U
27 
28 struct led_npm1300_config {
29 	const struct device *mfd;
30 	uint8_t mode[NPM1300_LED_PINS];
31 };
32 
led_npm1300_on(const struct device * dev,uint32_t led)33 static int led_npm1300_on(const struct device *dev, uint32_t led)
34 {
35 	const struct led_npm1300_config *config = dev->config;
36 
37 	if (led >= NPM1300_LED_PINS) {
38 		return -EINVAL;
39 	}
40 
41 	if (config->mode[led] != NPM_LED_HOST) {
42 		return -EPERM;
43 	}
44 
45 	return mfd_npm1300_reg_write(config->mfd, NPM_LED_BASE, NPM_LED_OFFSET_SET + (led * 2U),
46 				     1U);
47 }
48 
led_npm1300_off(const struct device * dev,uint32_t led)49 static int led_npm1300_off(const struct device *dev, uint32_t led)
50 {
51 	const struct led_npm1300_config *config = dev->config;
52 
53 	if (led >= NPM1300_LED_PINS) {
54 		return -EINVAL;
55 	}
56 
57 	if (config->mode[led] != NPM_LED_HOST) {
58 		return -EPERM;
59 	}
60 
61 	return mfd_npm1300_reg_write(config->mfd, NPM_LED_BASE, NPM_LED_OFFSET_CLR + (led * 2U),
62 				     1U);
63 }
64 
65 static const struct led_driver_api led_npm1300_api = {
66 	.on = led_npm1300_on,
67 	.off = led_npm1300_off,
68 };
69 
led_npm1300_init(const struct device * dev)70 static int led_npm1300_init(const struct device *dev)
71 {
72 	const struct led_npm1300_config *config = dev->config;
73 
74 	if (!device_is_ready(config->mfd)) {
75 		return -ENODEV;
76 	}
77 
78 	for (uint8_t led = 0U; led < NPM1300_LED_PINS; led++) {
79 		int ret = mfd_npm1300_reg_write(config->mfd, NPM_LED_BASE,
80 						NPM_LED_OFFSET_MODE + led, config->mode[led]);
81 
82 		if (ret < 0) {
83 			return ret;
84 		}
85 	}
86 
87 	return 0;
88 }
89 
90 #define LED_NPM1300_DEFINE(n)                                                                      \
91 	static const struct led_npm1300_config led_npm1300_config##n = {                           \
92 		.mfd = DEVICE_DT_GET(DT_INST_PARENT(n)),                                           \
93 		.mode = {DT_INST_ENUM_IDX(n, nordic_led0_mode),                                    \
94 			 DT_INST_ENUM_IDX(n, nordic_led1_mode),                                    \
95 			 DT_INST_ENUM_IDX(n, nordic_led2_mode)}};                                  \
96                                                                                                    \
97 	DEVICE_DT_INST_DEFINE(n, &led_npm1300_init, NULL, NULL, &led_npm1300_config##n,            \
98 			      POST_KERNEL, CONFIG_LED_INIT_PRIORITY, &led_npm1300_api);
99 
100 DT_INST_FOREACH_STATUS_OKAY(LED_NPM1300_DEFINE)
101