drivers/pwm/pwm-gpio.c
Source file repositories/reference/linux-study-clean/drivers/pwm/pwm-gpio.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/pwm/pwm-gpio.c- Extension
.c- Size
- 5727 bytes
- Lines
- 241
- Domain
- Driver Families
- Bucket
- drivers/pwm
- 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.
- Uses kernel synchronization; read lock ordering, sleepability, and interrupt context assumptions before translating.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/cleanup.hlinux/container_of.hlinux/device.hlinux/err.hlinux/gpio/consumer.hlinux/hrtimer.hlinux/math.hlinux/module.hlinux/mod_devicetable.hlinux/platform_device.hlinux/property.hlinux/pwm.hlinux/spinlock.hlinux/time.hlinux/types.h
Detected Declarations
struct pwm_gpiofunction pwm_gpio_roundfunction pwm_gpio_togglefunction pwm_gpio_timerfunction pwm_gpio_applyfunction pwm_gpio_get_statefunction pwm_gpio_disable_hrtimerfunction pwm_gpio_probe
Annotated Snippet
struct pwm_gpio {
struct hrtimer gpio_timer;
struct gpio_desc *gpio;
struct pwm_state state;
struct pwm_state next_state;
/* Protect internal state between pwm_ops and hrtimer */
spinlock_t lock;
bool changing;
bool running;
bool level;
};
static void pwm_gpio_round(struct pwm_state *dest, const struct pwm_state *src)
{
u64 dividend;
u32 remainder;
*dest = *src;
/* Round down to hrtimer resolution */
dividend = dest->period;
remainder = do_div(dividend, hrtimer_resolution);
dest->period -= remainder;
dividend = dest->duty_cycle;
remainder = do_div(dividend, hrtimer_resolution);
dest->duty_cycle -= remainder;
}
static u64 pwm_gpio_toggle(struct pwm_gpio *gpwm, bool level)
{
const struct pwm_state *state = &gpwm->state;
bool invert = state->polarity == PWM_POLARITY_INVERSED;
gpwm->level = level;
gpiod_set_value(gpwm->gpio, gpwm->level ^ invert);
if (!state->duty_cycle || state->duty_cycle == state->period) {
gpwm->running = false;
return 0;
}
gpwm->running = true;
return level ? state->duty_cycle : state->period - state->duty_cycle;
}
static enum hrtimer_restart pwm_gpio_timer(struct hrtimer *gpio_timer)
{
struct pwm_gpio *gpwm = container_of(gpio_timer, struct pwm_gpio,
gpio_timer);
u64 next_toggle;
bool new_level;
guard(spinlock_irqsave)(&gpwm->lock);
/* Apply new state at end of current period */
if (!gpwm->level && gpwm->changing) {
gpwm->changing = false;
gpwm->state = gpwm->next_state;
new_level = !!gpwm->state.duty_cycle;
} else {
new_level = !gpwm->level;
}
next_toggle = pwm_gpio_toggle(gpwm, new_level);
if (next_toggle)
hrtimer_forward(gpio_timer, hrtimer_get_expires(gpio_timer),
ns_to_ktime(next_toggle));
return next_toggle ? HRTIMER_RESTART : HRTIMER_NORESTART;
}
static int pwm_gpio_apply(struct pwm_chip *chip, struct pwm_device *pwm,
const struct pwm_state *state)
{
struct pwm_gpio *gpwm = pwmchip_get_drvdata(chip);
bool invert = state->polarity == PWM_POLARITY_INVERSED;
if (state->duty_cycle && state->duty_cycle < hrtimer_resolution)
return -EINVAL;
if (state->duty_cycle != state->period &&
(state->period - state->duty_cycle < hrtimer_resolution))
return -EINVAL;
if (!state->enabled) {
hrtimer_cancel(&gpwm->gpio_timer);
} else if (!gpwm->running) {
Annotation
- Immediate include surface: `linux/cleanup.h`, `linux/container_of.h`, `linux/device.h`, `linux/err.h`, `linux/gpio/consumer.h`, `linux/hrtimer.h`, `linux/math.h`, `linux/module.h`.
- Detected declarations: `struct pwm_gpio`, `function pwm_gpio_round`, `function pwm_gpio_toggle`, `function pwm_gpio_timer`, `function pwm_gpio_apply`, `function pwm_gpio_get_state`, `function pwm_gpio_disable_hrtimer`, `function pwm_gpio_probe`.
- Atlas domain: Driver Families / drivers/pwm.
- Implementation status: source implementation candidate.
- Synchronization appears in or near this file; preserve lock ordering, sleepability, and interrupt-context constraints.
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.