1 /*
2  * Copyright (c) 2021 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT gpio_leds
8 
9 /**
10  * @file
11  * @brief GPIO driven LEDs
12  */
13 
14 #include <zephyr/drivers/led.h>
15 #include <zephyr/drivers/gpio.h>
16 #include <zephyr/device.h>
17 #include <zephyr/kernel.h>
18 
19 #include <zephyr/logging/log.h>
20 LOG_MODULE_REGISTER(led_gpio, CONFIG_LED_LOG_LEVEL);
21 
22 struct led_gpio_config {
23 	size_t num_leds;
24 	const struct gpio_dt_spec *led;
25 };
26 
led_gpio_set_brightness(const struct device * dev,uint32_t led,uint8_t value)27 static int led_gpio_set_brightness(const struct device *dev, uint32_t led, uint8_t value)
28 {
29 
30 	const struct led_gpio_config *config = dev->config;
31 	const struct gpio_dt_spec *led_gpio;
32 
33 	if ((led >= config->num_leds) || (value > 100)) {
34 		return -EINVAL;
35 	}
36 
37 	led_gpio = &config->led[led];
38 
39 	return gpio_pin_set_dt(led_gpio, value > 0);
40 }
41 
led_gpio_on(const struct device * dev,uint32_t led)42 static int led_gpio_on(const struct device *dev, uint32_t led)
43 {
44 	return led_gpio_set_brightness(dev, led, 100);
45 }
46 
led_gpio_off(const struct device * dev,uint32_t led)47 static int led_gpio_off(const struct device *dev, uint32_t led)
48 {
49 	return led_gpio_set_brightness(dev, led, 0);
50 }
51 
led_gpio_init(const struct device * dev)52 static int led_gpio_init(const struct device *dev)
53 {
54 	const struct led_gpio_config *config = dev->config;
55 	int err = 0;
56 
57 	if (!config->num_leds) {
58 		LOG_ERR("%s: no LEDs found (DT child nodes missing)", dev->name);
59 		err = -ENODEV;
60 	}
61 
62 	for (size_t i = 0; (i < config->num_leds) && !err; i++) {
63 		const struct gpio_dt_spec *led = &config->led[i];
64 
65 		if (device_is_ready(led->port)) {
66 			err = gpio_pin_configure_dt(led, GPIO_OUTPUT_INACTIVE);
67 
68 			if (err) {
69 				LOG_ERR("Cannot configure GPIO (err %d)", err);
70 			}
71 		} else {
72 			LOG_ERR("%s: GPIO device not ready", dev->name);
73 			err = -ENODEV;
74 		}
75 	}
76 
77 	return err;
78 }
79 
80 static const struct led_driver_api led_gpio_api = {
81 	.on		= led_gpio_on,
82 	.off		= led_gpio_off,
83 	.set_brightness	= led_gpio_set_brightness,
84 };
85 
86 #define LED_GPIO_DEVICE(i)					\
87 								\
88 static const struct gpio_dt_spec gpio_dt_spec_##i[] = {		\
89 	DT_INST_FOREACH_CHILD_SEP_VARGS(i, GPIO_DT_SPEC_GET, (,), gpios) \
90 };								\
91 								\
92 static const struct led_gpio_config led_gpio_config_##i = {	\
93 	.num_leds	= ARRAY_SIZE(gpio_dt_spec_##i),	\
94 	.led		= gpio_dt_spec_##i,			\
95 };								\
96 								\
97 DEVICE_DT_INST_DEFINE(i, &led_gpio_init, NULL,			\
98 		      NULL, &led_gpio_config_##i,		\
99 		      POST_KERNEL, CONFIG_LED_INIT_PRIORITY,	\
100 		      &led_gpio_api);
101 
102 DT_INST_FOREACH_STATUS_OKAY(LED_GPIO_DEVICE)
103