drivers/leds/leds-pwm.c
Source file repositories/reference/linux-study-clean/drivers/leds/leds-pwm.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/leds/leds-pwm.c- Extension
.c- Size
- 6195 bytes
- Lines
- 250
- Domain
- Driver Families
- Bucket
- drivers/leds
- Inferred role
- Driver Families: implementation source
- Status
- source implementation candidate
Why This File Exists
Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Allocates kernel memory; connect allocation flags and lifetime to context constraints.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/err.hlinux/gpio/consumer.hlinux/kernel.hlinux/leds.hlinux/module.hlinux/of.hlinux/platform_device.hlinux/pwm.hlinux/slab.h
Detected Declarations
struct led_pwmstruct led_pwm_datastruct led_pwm_privfunction led_pwm_setfunction led_pwm_default_brightness_getfunction led_pwm_addfunction led_pwm_create_fwnodefunction device_for_each_child_node_scopedfunction led_pwm_probe
Annotated Snippet
struct led_pwm {
const char *name;
u8 active_low;
u8 default_state;
unsigned int max_brightness;
};
struct led_pwm_data {
struct gpio_desc *enable_gpio;
struct led_classdev cdev;
struct pwm_device *pwm;
struct pwm_state pwmstate;
unsigned int active_low;
};
struct led_pwm_priv {
int num_leds;
struct led_pwm_data leds[];
};
static int led_pwm_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct led_pwm_data *led_dat =
container_of(led_cdev, struct led_pwm_data, cdev);
unsigned int max = led_dat->cdev.max_brightness;
unsigned long long duty = led_dat->pwmstate.period;
duty *= brightness;
do_div(duty, max);
if (led_dat->active_low)
duty = led_dat->pwmstate.period - duty;
gpiod_set_value_cansleep(led_dat->enable_gpio, !!brightness);
led_dat->pwmstate.duty_cycle = duty;
/*
* Disabling a PWM doesn't guarantee that it emits the inactive level.
* So keep it on. Only for suspending the PWM should be disabled because
* otherwise it refuses to suspend. The possible downside is that the
* LED might stay (or even go) on.
*/
led_dat->pwmstate.enabled = !(led_cdev->flags & LED_SUSPENDED);
return pwm_apply_might_sleep(led_dat->pwm, &led_dat->pwmstate);
}
static int led_pwm_default_brightness_get(struct fwnode_handle *fwnode,
int max_brightness)
{
unsigned int default_brightness;
int ret;
ret = fwnode_property_read_u32(fwnode, "default-brightness",
&default_brightness);
if (ret < 0 || default_brightness > max_brightness)
default_brightness = max_brightness;
return default_brightness;
}
__attribute__((nonnull))
static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
struct led_pwm *led, struct fwnode_handle *fwnode)
{
struct led_pwm_data *led_data = &priv->leds[priv->num_leds];
struct led_init_data init_data = { .fwnode = fwnode };
int ret;
led_data->active_low = led->active_low;
led_data->cdev.name = led->name;
led_data->cdev.brightness = LED_OFF;
led_data->cdev.max_brightness = led->max_brightness;
led_data->cdev.flags = LED_CORE_SUSPENDRESUME;
led_data->pwm = devm_fwnode_pwm_get(dev, fwnode, NULL);
if (IS_ERR(led_data->pwm))
return dev_err_probe(dev, PTR_ERR(led_data->pwm),
"unable to request PWM for %s\n",
led->name);
led_data->cdev.brightness_set_blocking = led_pwm_set;
/* init PWM state */
switch (led->default_state) {
case LEDS_DEFSTATE_KEEP:
pwm_get_state(led_data->pwm, &led_data->pwmstate);
if (led_data->pwmstate.period)
break;
led->default_state = LEDS_DEFSTATE_OFF;
Annotation
- Immediate include surface: `linux/err.h`, `linux/gpio/consumer.h`, `linux/kernel.h`, `linux/leds.h`, `linux/module.h`, `linux/of.h`, `linux/platform_device.h`, `linux/pwm.h`.
- Detected declarations: `struct led_pwm`, `struct led_pwm_data`, `struct led_pwm_priv`, `function led_pwm_set`, `function led_pwm_default_brightness_get`, `function led_pwm_add`, `function led_pwm_create_fwnode`, `function device_for_each_child_node_scoped`, `function led_pwm_probe`.
- Atlas domain: Driver Families / drivers/leds.
- Implementation status: source implementation candidate.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.