Skip to content

Commit 737bc5b

Browse files
committed
[DM][LED] Update LED common drivers
1. PWM-LED 2. Syscon-LED Signed-off-by: GuEe-GUI <2991707448@qq.com>
1 parent 68dcb4c commit 737bc5b

File tree

4 files changed

+511
-0
lines changed

4 files changed

+511
-0
lines changed

components/drivers/led/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,19 @@ config RT_LED_GPIO
1010
depends on RT_USING_OFW
1111
default n
1212

13+
config RT_LED_PWM
14+
bool "PWM driven LEDs Support"
15+
depends on RT_USING_LED
16+
depends on RT_USING_PWM
17+
depends on RT_USING_OFW
18+
default n
19+
20+
config RT_LED_SYSCON
21+
bool "System controllers connected LEDs Support"
22+
depends on RT_USING_LED
23+
depends on RT_MFD_SYSCON
24+
default n
25+
1326
if RT_USING_LED
1427
osource "$(SOC_DM_LED_DIR)/Kconfig"
1528
endif

components/drivers/led/SConscript

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ src = ['led.c']
1313
if GetDepend(['RT_LED_GPIO']):
1414
src += ['led-gpio.c']
1515

16+
if GetDepend(['RT_LED_PWM']):
17+
src += ['led-pwm.c']
18+
19+
if GetDepend(['RT_LED_SYSCON']):
20+
src += ['led-syscon.c']
21+
1622
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
1723

1824
Return('group')

components/drivers/led/led-pwm.c

Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
/*
2+
* Copyright (c) 2006-2022, RT-Thread Development Team
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Change Logs:
7+
* Date Author Notes
8+
* 2022-3-08 GuEe-GUI the first version
9+
*/
10+
11+
#include <rtthread.h>
12+
#include <rtdevice.h>
13+
14+
#define DBG_TAG "led.pwm"
15+
#define DBG_LVL DBG_INFO
16+
#include <rtdbg.h>
17+
18+
struct pwm_led
19+
{
20+
struct rt_led_device parent;
21+
22+
struct rt_device_pwm *pwm_dev;
23+
struct rt_pwm_configuration pwm_conf;
24+
25+
rt_uint32_t max_brightness;
26+
rt_uint32_t brightness;
27+
rt_bool_t active_low;
28+
rt_bool_t enabled;
29+
};
30+
31+
#define raw_to_pwm_led(raw) rt_container_of(raw, struct pwm_led, parent)
32+
33+
static rt_err_t pwm_led_set_state(struct rt_led_device *led, enum rt_led_state state)
34+
{
35+
rt_err_t err = RT_EOK;
36+
struct rt_pwm_configuration pwm_conf = {};
37+
struct pwm_led *pled = raw_to_pwm_led(led);
38+
39+
switch (state)
40+
{
41+
case RT_LED_S_OFF:
42+
if ((err = rt_pwm_set(pled->pwm_dev,
43+
pled->pwm_conf.period, pled->pwm_conf.channel, 0)))
44+
{
45+
break;
46+
}
47+
48+
if (!(err = rt_pwm_disable(pled->pwm_dev, pled->pwm_conf.channel)))
49+
{
50+
pled->enabled = RT_FALSE;
51+
}
52+
break;
53+
54+
case RT_LED_S_ON:
55+
pwm_conf.channel = pled->pwm_conf.channel;
56+
pwm_conf.period = pled->pwm_conf.period;
57+
pwm_conf.pulse = pled->pwm_conf.pulse;
58+
pwm_conf.complementary = pled->active_low;
59+
60+
if ((err = rt_device_control(&pled->pwm_dev->parent, PWM_CMD_SET, &pwm_conf)))
61+
{
62+
break;
63+
}
64+
65+
if (!(err = rt_pwm_enable(pled->pwm_dev, pled->pwm_conf.channel)))
66+
{
67+
pled->enabled = RT_TRUE;
68+
}
69+
break;
70+
71+
case RT_LED_S_TOGGLE:
72+
err = led->ops->get_state(led, &state);
73+
74+
if (!err)
75+
{
76+
err = led->ops->set_state(led, state == RT_LED_S_OFF ? RT_LED_S_ON : RT_LED_S_OFF);
77+
}
78+
break;
79+
80+
default:
81+
return -RT_ENOSYS;
82+
}
83+
84+
return err;
85+
}
86+
87+
static rt_err_t pwm_led_get_state(struct rt_led_device *led, enum rt_led_state *out_state)
88+
{
89+
struct pwm_led *pled = raw_to_pwm_led(led);
90+
91+
*out_state = pled->enabled ? RT_LED_S_ON : RT_LED_S_OFF;
92+
93+
return RT_EOK;
94+
}
95+
96+
static rt_err_t pwm_led_set_brightness(struct rt_led_device *led, rt_uint32_t brightness)
97+
{
98+
struct pwm_led *pled = raw_to_pwm_led(led);
99+
rt_uint64_t duty = pled->pwm_conf.period;
100+
101+
duty *= brightness;
102+
rt_do_div(duty, pled->max_brightness);
103+
104+
if (pled->active_low)
105+
{
106+
duty = pled->pwm_conf.period - duty;
107+
}
108+
109+
pled->pwm_conf.pulse = duty;
110+
111+
return rt_pwm_set(pled->pwm_dev,
112+
pled->pwm_conf.channel, pled->pwm_conf.period, pled->pwm_conf.pulse);
113+
}
114+
115+
const static struct rt_led_ops pwm_led_ops =
116+
{
117+
.set_state = pwm_led_set_state,
118+
.get_state = pwm_led_get_state,
119+
.set_brightness = pwm_led_set_brightness,
120+
};
121+
122+
static rt_err_t ofw_append_pwm_led(struct rt_ofw_node *np)
123+
{
124+
rt_err_t err;
125+
rt_bool_t need_set_brightness = RT_TRUE;
126+
enum rt_led_state led_state = RT_LED_S_OFF;
127+
const char *propname, *state, *trigger;
128+
struct rt_ofw_node *pwm_np;
129+
struct rt_ofw_cell_args pwm_args;
130+
struct pwm_led *pled = rt_calloc(1, sizeof(*pled));
131+
132+
if (!pled)
133+
{
134+
return -RT_ENOMEM;
135+
}
136+
137+
pled->active_low = rt_ofw_prop_read_bool(np, "active-low");
138+
139+
if (rt_ofw_prop_read_u32(np, "max-brightness", &pled->max_brightness))
140+
{
141+
err = -RT_EINVAL;
142+
goto _fail;
143+
}
144+
145+
if (rt_ofw_parse_phandle_cells(np, "pwms", "#pwm-cells", 0, &pwm_args))
146+
{
147+
err = -RT_EINVAL;
148+
goto _fail;
149+
}
150+
151+
pwm_np = pwm_args.data;
152+
153+
if (!rt_ofw_data(pwm_np))
154+
{
155+
rt_platform_ofw_request(pwm_np);
156+
}
157+
158+
pled->pwm_dev = rt_ofw_data(pwm_np);
159+
rt_ofw_node_put(pwm_np);
160+
161+
if (!pled->pwm_dev)
162+
{
163+
err = -RT_EINVAL;
164+
goto _fail;
165+
}
166+
167+
pled->pwm_conf.channel = pwm_args.args[0];
168+
pled->pwm_conf.period = pwm_args.args[1];
169+
170+
pled->parent.ops = &pwm_led_ops;
171+
172+
if ((err = rt_led_register(&pled->parent)))
173+
{
174+
goto _fail;
175+
}
176+
177+
if (!rt_ofw_prop_read_string(np, "default-state", &state))
178+
{
179+
rt_pwm_get(pled->pwm_dev, &pled->pwm_conf);
180+
181+
if (!rt_strcmp(state, "on"))
182+
{
183+
led_state = RT_LED_S_ON;
184+
pled->brightness = pled->max_brightness;
185+
}
186+
else if (!rt_strcmp(state, "keep"))
187+
{
188+
if (pled->pwm_conf.period)
189+
{
190+
rt_uint64_t brightness;
191+
192+
brightness = pled->max_brightness;
193+
brightness *= pled->pwm_conf.pulse;
194+
rt_do_div(brightness, pled->pwm_conf.period);
195+
196+
pled->brightness = brightness;
197+
198+
need_set_brightness = RT_FALSE;
199+
}
200+
else
201+
{
202+
goto _out_state_check;
203+
}
204+
}
205+
206+
pled->pwm_conf.period = pwm_args.args[1];
207+
}
208+
209+
_out_state_check:
210+
if ((propname = rt_ofw_get_prop_fuzzy_name(np, "default-trigger$")))
211+
{
212+
if (!rt_ofw_prop_read_string(np, propname, &trigger))
213+
{
214+
if (!rt_strcmp(trigger, "heartbeat") ||
215+
!rt_strcmp(trigger, "timer"))
216+
{
217+
led_state = RT_LED_S_BLINK;
218+
}
219+
}
220+
}
221+
222+
rt_led_set_state(&pled->parent, led_state);
223+
224+
if (need_set_brightness)
225+
{
226+
pwm_led_set_brightness(&pled->parent, pled->brightness);
227+
}
228+
229+
rt_ofw_data(np) = &pled->parent;
230+
231+
return RT_EOK;
232+
233+
_fail:
234+
rt_free(pled);
235+
236+
return err;
237+
}
238+
239+
static rt_err_t pwm_led_probe(struct rt_platform_device *pdev)
240+
{
241+
struct rt_ofw_node *led_np, *np = pdev->parent.ofw_node;
242+
243+
rt_ofw_foreach_available_child_node(np, led_np)
244+
{
245+
rt_err_t err = ofw_append_pwm_led(led_np);
246+
247+
if (err == -RT_ENOMEM)
248+
{
249+
rt_ofw_node_put(led_np);
250+
251+
return err;
252+
}
253+
else if (err)
254+
{
255+
LOG_E("%s: create LED fail", rt_ofw_node_full_name(led_np));
256+
}
257+
}
258+
259+
return RT_EOK;
260+
}
261+
262+
static rt_err_t pwm_led_remove(struct rt_platform_device *pdev)
263+
{
264+
struct pwm_led *pled;
265+
struct rt_led_device *led_dev;
266+
struct rt_ofw_node *led_np, *np = pdev->parent.ofw_node;
267+
268+
rt_ofw_foreach_available_child_node(np, led_np)
269+
{
270+
led_dev = rt_ofw_data(led_np);
271+
272+
if (!led_dev)
273+
{
274+
continue;
275+
}
276+
277+
pled = rt_container_of(led_dev, struct pwm_led, parent);
278+
279+
rt_ofw_data(led_np) = RT_NULL;
280+
281+
rt_led_unregister(&pled->parent);
282+
283+
rt_free(pled);
284+
}
285+
286+
return RT_EOK;
287+
}
288+
289+
static const struct rt_ofw_node_id pwm_led_ofw_ids[] =
290+
{
291+
{ .compatible = "pwm-leds" },
292+
{ /* sentinel */ }
293+
};
294+
295+
static struct rt_platform_driver pwm_led_driver =
296+
{
297+
.name = "led-pwm",
298+
.ids = pwm_led_ofw_ids,
299+
300+
.probe = pwm_led_probe,
301+
.remove = pwm_led_remove,
302+
};
303+
RT_PLATFORM_DRIVER_EXPORT(pwm_led_driver);

0 commit comments

Comments
 (0)