drivers/pwm/pwm-spear.c
Source file repositories/reference/linux-study-clean/drivers/pwm/pwm-spear.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/pwm/pwm-spear.c- Extension
.c- Size
- 6592 bytes
- Lines
- 263
- 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.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/clk.hlinux/err.hlinux/io.hlinux/ioport.hlinux/kernel.hlinux/math64.hlinux/module.hlinux/of.hlinux/platform_device.hlinux/pwm.hlinux/slab.hlinux/types.h
Detected Declarations
struct spear_pwm_chipfunction spear_pwm_readlfunction spear_pwm_writelfunction spear_pwm_configfunction spear_pwm_enablefunction spear_pwm_disablefunction spear_pwm_applyfunction spear_pwm_probe
Annotated Snippet
struct spear_pwm_chip {
void __iomem *mmio_base;
struct clk *clk;
};
static inline struct spear_pwm_chip *to_spear_pwm_chip(struct pwm_chip *chip)
{
return pwmchip_get_drvdata(chip);
}
static inline u32 spear_pwm_readl(struct spear_pwm_chip *chip, unsigned int num,
unsigned long offset)
{
return readl_relaxed(chip->mmio_base + (num << 4) + offset);
}
static inline void spear_pwm_writel(struct spear_pwm_chip *chip,
unsigned int num, unsigned long offset,
unsigned long val)
{
writel_relaxed(val, chip->mmio_base + (num << 4) + offset);
}
static int spear_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
u64 duty_ns, u64 period_ns)
{
struct spear_pwm_chip *pc = to_spear_pwm_chip(chip);
u64 val, div, clk_rate;
unsigned long prescale = PWMCR_MIN_PRESCALE, pv, dc;
int ret;
/*
* Find pv, dc and prescale to suit duty_ns and period_ns. This is done
* according to formulas described below:
*
* period_ns = 10^9 * (PRESCALE + 1) * PV / PWM_CLK_RATE
* duty_ns = 10^9 * (PRESCALE + 1) * DC / PWM_CLK_RATE
*
* PV = (PWM_CLK_RATE * period_ns) / (10^9 * (PRESCALE + 1))
* DC = (PWM_CLK_RATE * duty_ns) / (10^9 * (PRESCALE + 1))
*/
clk_rate = clk_get_rate(pc->clk);
while (1) {
div = 1000000000;
div *= 1 + prescale;
val = clk_rate * period_ns;
pv = div64_u64(val, div);
val = clk_rate * duty_ns;
dc = div64_u64(val, div);
/* if duty_ns and period_ns are not achievable then return */
if (pv < PWMPCR_MIN_PERIOD || dc < PWMDCR_MIN_DUTY)
return -EINVAL;
/*
* if pv and dc have crossed their upper limit, then increase
* prescale and recalculate pv and dc.
*/
if (pv > PWMPCR_MAX_PERIOD || dc > PWMDCR_MAX_DUTY) {
if (++prescale > PWMCR_MAX_PRESCALE)
return -EINVAL;
continue;
}
break;
}
/*
* NOTE: the clock to PWM has to be enabled first before writing to the
* registers.
*/
ret = clk_enable(pc->clk);
if (ret)
return ret;
spear_pwm_writel(pc, pwm->hwpwm, PWMCR,
prescale << PWMCR_PRESCALE_SHIFT);
spear_pwm_writel(pc, pwm->hwpwm, PWMDCR, dc);
spear_pwm_writel(pc, pwm->hwpwm, PWMPCR, pv);
clk_disable(pc->clk);
return 0;
}
static int spear_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct spear_pwm_chip *pc = to_spear_pwm_chip(chip);
int rc = 0;
u32 val;
rc = clk_enable(pc->clk);
Annotation
- Immediate include surface: `linux/clk.h`, `linux/err.h`, `linux/io.h`, `linux/ioport.h`, `linux/kernel.h`, `linux/math64.h`, `linux/module.h`, `linux/of.h`.
- Detected declarations: `struct spear_pwm_chip`, `function spear_pwm_readl`, `function spear_pwm_writel`, `function spear_pwm_config`, `function spear_pwm_enable`, `function spear_pwm_disable`, `function spear_pwm_apply`, `function spear_pwm_probe`.
- Atlas domain: Driver Families / drivers/pwm.
- 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.