1 // SPDX-License-Identifier: GPL-2.0-only
3 * linux/drivers/leds-pwm.c
5 * simple PWM based LED control
7 * Copyright 2009 Luotao Fu @ Pengutronix (l.fu@pengutronix.de)
9 * based on leds-gpio.c by Raphael Assenat <raph@8d.com>
12 #include <linux/module.h>
13 #include <linux/kernel.h>
14 #include <linux/platform_device.h>
15 #include <linux/of_platform.h>
16 #include <linux/leds.h>
17 #include <linux/err.h>
18 #include <linux/pwm.h>
19 #include <linux/slab.h>
23 const char *default_trigger
;
25 unsigned int max_brightness
;
28 struct led_pwm_platform_data
{
34 struct led_classdev cdev
;
35 struct pwm_device
*pwm
;
36 struct pwm_state pwmstate
;
37 unsigned int active_low
;
42 struct led_pwm_data leds
[];
45 static int led_pwm_set(struct led_classdev
*led_cdev
,
46 enum led_brightness brightness
)
48 struct led_pwm_data
*led_dat
=
49 container_of(led_cdev
, struct led_pwm_data
, cdev
);
50 unsigned int max
= led_dat
->cdev
.max_brightness
;
51 unsigned long long duty
= led_dat
->pwmstate
.period
;
56 if (led_dat
->active_low
)
57 duty
= led_dat
->pwmstate
.period
- duty
;
59 led_dat
->pwmstate
.duty_cycle
= duty
;
60 led_dat
->pwmstate
.enabled
= duty
> 0;
61 return pwm_apply_state(led_dat
->pwm
, &led_dat
->pwmstate
);
64 static int led_pwm_add(struct device
*dev
, struct led_pwm_priv
*priv
,
65 struct led_pwm
*led
, struct fwnode_handle
*fwnode
)
67 struct led_pwm_data
*led_data
= &priv
->leds
[priv
->num_leds
];
70 led_data
->active_low
= led
->active_low
;
71 led_data
->cdev
.name
= led
->name
;
72 led_data
->cdev
.default_trigger
= led
->default_trigger
;
73 led_data
->cdev
.brightness
= LED_OFF
;
74 led_data
->cdev
.max_brightness
= led
->max_brightness
;
75 led_data
->cdev
.flags
= LED_CORE_SUSPENDRESUME
;
78 led_data
->pwm
= devm_fwnode_pwm_get(dev
, fwnode
, NULL
);
80 led_data
->pwm
= devm_pwm_get(dev
, led
->name
);
81 if (IS_ERR(led_data
->pwm
)) {
82 ret
= PTR_ERR(led_data
->pwm
);
83 if (ret
!= -EPROBE_DEFER
)
84 dev_err(dev
, "unable to request PWM for %s: %d\n",
89 led_data
->cdev
.brightness_set_blocking
= led_pwm_set
;
91 pwm_init_state(led_data
->pwm
, &led_data
->pwmstate
);
93 ret
= devm_led_classdev_register(dev
, &led_data
->cdev
);
96 led_pwm_set(&led_data
->cdev
, led_data
->cdev
.brightness
);
98 dev_err(dev
, "failed to register PWM led for %s: %d\n",
105 static int led_pwm_create_fwnode(struct device
*dev
, struct led_pwm_priv
*priv
)
107 struct fwnode_handle
*fwnode
;
111 memset(&led
, 0, sizeof(led
));
113 device_for_each_child_node(dev
, fwnode
) {
114 ret
= fwnode_property_read_string(fwnode
, "label", &led
.name
);
115 if (ret
&& is_of_node(fwnode
))
116 led
.name
= to_of_node(fwnode
)->name
;
119 fwnode_handle_put(fwnode
);
123 fwnode_property_read_string(fwnode
, "linux,default-trigger",
124 &led
.default_trigger
);
126 led
.active_low
= fwnode_property_read_bool(fwnode
,
128 fwnode_property_read_u32(fwnode
, "max-brightness",
129 &led
.max_brightness
);
131 ret
= led_pwm_add(dev
, priv
, &led
, fwnode
);
133 fwnode_handle_put(fwnode
);
141 static int led_pwm_probe(struct platform_device
*pdev
)
143 struct led_pwm_platform_data
*pdata
= dev_get_platdata(&pdev
->dev
);
144 struct led_pwm_priv
*priv
;
149 count
= pdata
->num_leds
;
151 count
= device_get_child_node_count(&pdev
->dev
);
156 priv
= devm_kzalloc(&pdev
->dev
, struct_size(priv
, leds
, count
),
162 for (i
= 0; i
< count
; i
++) {
163 ret
= led_pwm_add(&pdev
->dev
, priv
, &pdata
->leds
[i
],
169 ret
= led_pwm_create_fwnode(&pdev
->dev
, priv
);
175 platform_set_drvdata(pdev
, priv
);
180 static const struct of_device_id of_pwm_leds_match
[] = {
181 { .compatible
= "pwm-leds", },
184 MODULE_DEVICE_TABLE(of
, of_pwm_leds_match
);
186 static struct platform_driver led_pwm_driver
= {
187 .probe
= led_pwm_probe
,
190 .of_match_table
= of_pwm_leds_match
,
194 module_platform_driver(led_pwm_driver
);
196 MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
197 MODULE_DESCRIPTION("generic PWM LED driver");
198 MODULE_LICENSE("GPL v2");
199 MODULE_ALIAS("platform:leds-pwm");