Skip to content

Commit d30f4dc

Browse files
Kamil GaworKamil Gawor
authored andcommitted
driver: Add LED GPIO driver
Add driver for controlling the LED devices attached to GPIO pins which are declared in devicetree under leds node and generated as static initializer. The driver takes care of configuring the pins to output state before using it. Signed-off-by: Kamil Gawor <Kamil.Gawor@nordicsemi.no>
1 parent a043d48 commit d30f4dc

File tree

6 files changed

+203
-4
lines changed

6 files changed

+203
-4
lines changed

drivers/led/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ zephyr_sources_ifdef(CONFIG_HT16K33 ht16k33.c)
44
zephyr_sources_ifdef(CONFIG_LP3943 lp3943.c)
55
zephyr_sources_ifdef(CONFIG_LP5562 lp5562.c)
66
zephyr_sources_ifdef(CONFIG_PCA9633 pca9633.c)
7+
zephyr_sources_ifdef(CONFIG_LED_GPIO led_gpio.c)
78

89
zephyr_sources_ifdef(CONFIG_USERSPACE led_handlers.c)

drivers/led/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ source "drivers/led/Kconfig.ht16k33"
2424
source "drivers/led/Kconfig.lp3943"
2525
source "drivers/led/Kconfig.lp5562"
2626
source "drivers/led/Kconfig.pca9633"
27+
source "drivers/led/Kconfig.led_gpio"
2728

2829
endif # LED

drivers/led/Kconfig.led_gpio

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Copyright (c) 2019 Nordic Semiconductor ASA
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config LED_GPIO
5+
bool "LED GPIO driver"
6+
depends on GPIO
7+
help
8+
This option enables support for the LEDs connected to GPIO
9+
outputs. To be useful the particular board must have LEDs
10+
and they must be connected to the GPIO lines.
11+
12+
if LED_GPIO
13+
14+
module = LED_GPIO
15+
module-str = LED GPIO
16+
source "${ZEPHYR_BASE}/subsys/logging/Kconfig.template.log_config"
17+
18+
endif # LED_GPIO

drivers/led/led_gpio.c

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
/*
2+
* Copyright (c) 2019 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#include <drivers/gpio.h>
7+
#include <drivers/led.h>
8+
#include <logging/log.h>
9+
10+
LOG_MODULE_REGISTER(led_gpio, CONFIG_LED_GPIO_LOG_LEVEL);
11+
12+
#define DT_DRV_COMPAT gpio_leds
13+
#define LED_DATA(node_id) \
14+
{ \
15+
{ \
16+
DT_GPIO_LABEL(node_id, gpios), \
17+
DT_GPIO_PIN(node_id, gpios), \
18+
DT_GPIO_FLAGS(node_id, gpios) \
19+
}, \
20+
DT_LABEL(node_id), \
21+
DT_PROP(node_id, id) \
22+
},
23+
24+
struct gpio_cfg {
25+
const char *port;
26+
gpio_pin_t pin;
27+
gpio_dt_flags_t flags;
28+
};
29+
30+
struct led_dts_cfg {
31+
struct gpio_cfg gpio;
32+
const char *label;
33+
uint32_t id;
34+
};
35+
36+
struct led_gpio_data {
37+
struct device *gpio_dev;
38+
const struct led_dts_cfg *cfg;
39+
bool state;
40+
};
41+
42+
struct led_gpio_cfg {
43+
const struct led_dts_cfg *led;
44+
uint32_t led_cnt;
45+
};
46+
47+
static inline struct led_gpio_data *get_dev_data(struct device *dev)
48+
{
49+
return dev->driver_data;
50+
}
51+
52+
static inline const struct led_gpio_cfg *get_dev_config(struct device *dev)
53+
{
54+
return dev->config_info;
55+
}
56+
57+
static struct led_gpio_data *led_parameters_get(struct device *dev,
58+
uint32_t led)
59+
{
60+
const struct led_gpio_cfg *cfg = get_dev_config(dev);
61+
struct led_gpio_data *data = get_dev_data(dev);
62+
63+
for (size_t i = 0; i < cfg->led_cnt; i++) {
64+
if (data[i].cfg->id == led) {
65+
return &data[i];
66+
}
67+
}
68+
69+
return NULL;
70+
}
71+
72+
static int gpio_led_set_no_delay(struct led_gpio_data *data, bool state)
73+
{
74+
int err;
75+
76+
data->state = state;
77+
78+
err = gpio_pin_set(data->gpio_dev, data->cfg->gpio.pin,
79+
state);
80+
if (err) {
81+
LOG_DBG("%s turn %s error %d",
82+
data->cfg->label,
83+
state ? "on" : "off",
84+
err);
85+
} else {
86+
LOG_DBG("%s turn %s", data->cfg->label,
87+
state ? "on" : "off");
88+
}
89+
90+
return err;
91+
}
92+
93+
static int gpio_led_set(struct led_gpio_data *data, bool state)
94+
{
95+
return gpio_led_set_no_delay(data, state);
96+
}
97+
98+
static int gpio_led_on(struct device *dev, uint32_t led)
99+
{
100+
struct led_gpio_data *data = led_parameters_get(dev, led);
101+
102+
if (!data) {
103+
return -EINVAL;
104+
}
105+
106+
return gpio_led_set(data, true);
107+
}
108+
109+
static int gpio_led_off(struct device *dev, uint32_t led)
110+
{
111+
struct led_gpio_data *data = led_parameters_get(dev, led);
112+
113+
if (!data) {
114+
return -EINVAL;
115+
}
116+
117+
return gpio_led_set(data, false);
118+
}
119+
120+
static const struct led_driver_api led_api = {
121+
.on = gpio_led_on,
122+
.off = gpio_led_off,
123+
};
124+
125+
static int gpio_led_init(struct device *dev)
126+
{
127+
int err;
128+
const struct led_gpio_cfg *cfg = get_dev_config(dev);
129+
struct led_gpio_data *data = get_dev_data(dev);
130+
131+
for (size_t i = 0; i < cfg->led_cnt; i++) {
132+
data[i].gpio_dev = device_get_binding(cfg->led[i].gpio.port);
133+
if (!data[i].gpio_dev) {
134+
LOG_DBG("Failed to get GPIO device for port %s pin %d",
135+
cfg->led[i].gpio.port, cfg->led[i].gpio.pin);
136+
return -EINVAL;
137+
}
138+
139+
/* Set all leds pin as output */
140+
err = gpio_pin_configure(data[i].gpio_dev,
141+
cfg->led[i].gpio.pin,
142+
(GPIO_OUTPUT_INACTIVE |
143+
cfg->led[i].gpio.flags));
144+
if (err) {
145+
LOG_DBG("Failed to set GPIO port %s pin %d as output",
146+
cfg->led[i].gpio.port, cfg->led[i].gpio.pin);
147+
return err;
148+
}
149+
150+
151+
data[i].cfg = &cfg->led[i];
152+
}
153+
154+
return 0;
155+
}
156+
157+
static const struct led_dts_cfg led_dts[] = {DT_INST_FOREACH_CHILD(0,
158+
LED_DATA)};
159+
static struct led_gpio_data led_data[ARRAY_SIZE(led_dts)];
160+
static const struct led_gpio_cfg led_cfg = {
161+
.led_cnt = ARRAY_SIZE(led_dts),
162+
.led = led_dts
163+
};
164+
165+
DEVICE_AND_API_INIT(gpio_led, DT_PROP(DT_DRV_INST(0), driver),
166+
gpio_led_init, led_data,
167+
&led_cfg, POST_KERNEL, CONFIG_LED_INIT_PRIORITY,
168+
&led_api);

dts/bindings/gpio/gpio-leds.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ description: GPIO LEDs parent node
55

66
compatible: "gpio-leds"
77

8+
properties:
9+
driver:
10+
required: false
11+
type: string
12+
description: GPIO LED driver name
13+
default: "LED_GPIO_0"
14+
815
child-binding:
916
description: GPIO LED child node
1017
properties:
@@ -15,3 +22,7 @@ child-binding:
1522
required: true
1623
type: string
1724
description: Human readable string describing the device (used as device_get_binding() argument)
25+
id:
26+
required: false
27+
type: int
28+
description: Id needed for the GPIO LED driver to identify an LED

include/drivers/led.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ __subsystem struct led_driver_api {
7373
* This routine starts blinking an LED forever with the given time period
7474
*
7575
* @param dev LED device
76-
* @param led LED channel/pin
76+
* @param led LED channel/pin/id
7777
* @param delay_on Time period (in milliseconds) an LED should be ON
7878
* @param delay_off Time period (in milliseconds) an LED should be OFF
7979
* @return 0 on success, negative on error
@@ -97,7 +97,7 @@ static inline int z_impl_led_blink(struct device *dev, uint32_t led,
9797
* Calling this function after led_blink() won't affect blinking.
9898
*
9999
* @param dev LED device
100-
* @param led LED channel/pin
100+
* @param led LED channel/pin/id
101101
* @param value Brightness value to set in percent
102102
* @return 0 on success, negative on error
103103
*/
@@ -119,7 +119,7 @@ static inline int z_impl_led_set_brightness(struct device *dev, uint32_t led,
119119
* This routine turns on an LED
120120
*
121121
* @param dev LED device
122-
* @param led LED channel/pin
122+
* @param led LED channel/pin/id
123123
* @return 0 on success, negative on error
124124
*/
125125
__syscall int led_on(struct device *dev, uint32_t led);
@@ -138,7 +138,7 @@ static inline int z_impl_led_on(struct device *dev, uint32_t led)
138138
* This routine turns off an LED
139139
*
140140
* @param dev LED device
141-
* @param led LED channel/pin
141+
* @param led LED channel/pin/id
142142
* @return 0 on success, negative on error
143143
*/
144144
__syscall int led_off(struct device *dev, uint32_t led);

0 commit comments

Comments
 (0)