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>
16 #include <linux/leds.h>
17 #include <linux/err.h>
18 #include <linux/pwm.h>
19 #include <linux/slab.h>
25 unsigned int max_brightness
;
29 struct led_classdev cdev
;
30 struct pwm_device
*pwm
;
31 struct pwm_state pwmstate
;
32 unsigned int active_low
;
37 struct led_pwm_data leds
[];
40 static int led_pwm_set(struct led_classdev
*led_cdev
,
41 enum led_brightness brightness
)
43 struct led_pwm_data
*led_dat
=
44 container_of(led_cdev
, struct led_pwm_data
, cdev
);
45 unsigned int max
= led_dat
->cdev
.max_brightness
;
46 unsigned long long duty
= led_dat
->pwmstate
.period
;
51 if (led_dat
->active_low
)
52 duty
= led_dat
->pwmstate
.period
- duty
;
54 led_dat
->pwmstate
.duty_cycle
= duty
;
56 * Disabling a PWM doesn't guarantee that it emits the inactive level.
57 * So keep it on. Only for suspending the PWM should be disabled because
58 * otherwise it refuses to suspend. The possible downside is that the
59 * LED might stay (or even go) on.
61 led_dat
->pwmstate
.enabled
= !(led_cdev
->flags
& LED_SUSPENDED
);
62 return pwm_apply_might_sleep(led_dat
->pwm
, &led_dat
->pwmstate
);
65 static int led_pwm_default_brightness_get(struct fwnode_handle
*fwnode
,
68 unsigned int default_brightness
;
71 ret
= fwnode_property_read_u32(fwnode
, "default-brightness",
73 if (ret
< 0 || default_brightness
> max_brightness
)
74 default_brightness
= max_brightness
;
76 return default_brightness
;
79 __attribute__((nonnull
))
80 static int led_pwm_add(struct device
*dev
, struct led_pwm_priv
*priv
,
81 struct led_pwm
*led
, struct fwnode_handle
*fwnode
)
83 struct led_pwm_data
*led_data
= &priv
->leds
[priv
->num_leds
];
84 struct led_init_data init_data
= { .fwnode
= fwnode
};
87 led_data
->active_low
= led
->active_low
;
88 led_data
->cdev
.name
= led
->name
;
89 led_data
->cdev
.brightness
= LED_OFF
;
90 led_data
->cdev
.max_brightness
= led
->max_brightness
;
91 led_data
->cdev
.flags
= LED_CORE_SUSPENDRESUME
;
93 led_data
->pwm
= devm_fwnode_pwm_get(dev
, fwnode
, NULL
);
94 if (IS_ERR(led_data
->pwm
))
95 return dev_err_probe(dev
, PTR_ERR(led_data
->pwm
),
96 "unable to request PWM for %s\n",
99 led_data
->cdev
.brightness_set_blocking
= led_pwm_set
;
102 switch (led
->default_state
) {
103 case LEDS_DEFSTATE_KEEP
:
104 pwm_get_state(led_data
->pwm
, &led_data
->pwmstate
);
105 if (led_data
->pwmstate
.period
)
107 led
->default_state
= LEDS_DEFSTATE_OFF
;
109 "failed to read period for %s, default to off",
113 pwm_init_state(led_data
->pwm
, &led_data
->pwmstate
);
118 switch (led
->default_state
) {
119 case LEDS_DEFSTATE_ON
:
120 led_data
->cdev
.brightness
=
121 led_pwm_default_brightness_get(fwnode
, led
->max_brightness
);
123 case LEDS_DEFSTATE_KEEP
:
127 brightness
= led
->max_brightness
;
128 brightness
*= led_data
->pwmstate
.duty_cycle
;
129 do_div(brightness
, led_data
->pwmstate
.period
);
130 led_data
->cdev
.brightness
= brightness
;
135 ret
= devm_led_classdev_register_ext(dev
, &led_data
->cdev
, &init_data
);
137 dev_err(dev
, "failed to register PWM led for %s: %d\n",
142 if (led
->default_state
!= LEDS_DEFSTATE_KEEP
) {
143 ret
= led_pwm_set(&led_data
->cdev
, led_data
->cdev
.brightness
);
145 dev_err(dev
, "failed to set led PWM value for %s: %d",
155 static int led_pwm_create_fwnode(struct device
*dev
, struct led_pwm_priv
*priv
)
160 device_for_each_child_node_scoped(dev
, fwnode
) {
161 memset(&led
, 0, sizeof(led
));
163 ret
= fwnode_property_read_string(fwnode
, "label", &led
.name
);
164 if (ret
&& is_of_node(fwnode
))
165 led
.name
= to_of_node(fwnode
)->name
;
170 led
.active_low
= fwnode_property_read_bool(fwnode
,
172 fwnode_property_read_u32(fwnode
, "max-brightness",
173 &led
.max_brightness
);
175 led
.default_state
= led_init_default_state_get(fwnode
);
177 ret
= led_pwm_add(dev
, priv
, &led
, fwnode
);
185 static int led_pwm_probe(struct platform_device
*pdev
)
187 struct led_pwm_priv
*priv
;
191 count
= device_get_child_node_count(&pdev
->dev
);
196 priv
= devm_kzalloc(&pdev
->dev
, struct_size(priv
, leds
, count
),
201 ret
= led_pwm_create_fwnode(&pdev
->dev
, priv
);
206 platform_set_drvdata(pdev
, priv
);
211 static const struct of_device_id of_pwm_leds_match
[] = {
212 { .compatible
= "pwm-leds", },
215 MODULE_DEVICE_TABLE(of
, of_pwm_leds_match
);
217 static struct platform_driver led_pwm_driver
= {
218 .probe
= led_pwm_probe
,
221 .of_match_table
= of_pwm_leds_match
,
225 module_platform_driver(led_pwm_driver
);
227 MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
228 MODULE_DESCRIPTION("generic PWM LED driver");
229 MODULE_LICENSE("GPL v2");
230 MODULE_ALIAS("platform:leds-pwm");