drivers/pwm/pwm-brcmstb.c
Source file repositories/reference/linux-study-clean/drivers/pwm/pwm-brcmstb.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/pwm/pwm-brcmstb.c- Extension
.c- Size
- 7384 bytes
- Lines
- 294
- 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/export.hlinux/init.hlinux/io.hlinux/kernel.hlinux/module.hlinux/of.hlinux/platform_device.hlinux/pwm.hlinux/spinlock.h
Detected Declarations
struct brcmstb_pwmfunction brcmstb_pwm_readlfunction brcmstb_pwm_writelfunction brcmstb_pwm_configfunction brcmstb_pwm_enable_setfunction brcmstb_pwm_applyfunction brcmstb_pwm_probefunction brcmstb_pwm_suspendfunction brcmstb_pwm_resume
Annotated Snippet
struct brcmstb_pwm {
void __iomem *base;
struct clk *clk;
};
static inline u32 brcmstb_pwm_readl(struct brcmstb_pwm *p,
unsigned int offset)
{
if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
return __raw_readl(p->base + offset);
else
return readl_relaxed(p->base + offset);
}
static inline void brcmstb_pwm_writel(struct brcmstb_pwm *p, u32 value,
unsigned int offset)
{
if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
__raw_writel(value, p->base + offset);
else
writel_relaxed(value, p->base + offset);
}
static inline struct brcmstb_pwm *to_brcmstb_pwm(struct pwm_chip *chip)
{
return pwmchip_get_drvdata(chip);
}
/*
* Fv is derived from the variable frequency output. The variable frequency
* output is configured using this formula:
*
* W = cword, if cword < 2 ^ 15 else 16-bit 2's complement of cword
*
* Fv = W x 2 ^ -16 x 27Mhz (reference clock)
*
* The period is: (period + 1) / Fv and "on" time is on / (period + 1)
*
* The PWM core framework specifies that the "duty_ns" parameter is in fact the
* "on" time, so this translates directly into our HW programming here.
*/
static int brcmstb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
u64 duty_ns, u64 period_ns)
{
struct brcmstb_pwm *p = to_brcmstb_pwm(chip);
unsigned long pc, dc, cword = CONST_VAR_F_MAX;
unsigned int channel = pwm->hwpwm;
u32 value;
/*
* If asking for a duty_ns equal to period_ns, we need to substract
* the period value by 1 to make it shorter than the "on" time and
* produce a flat 100% duty cycle signal, and max out the "on" time
*/
if (duty_ns == period_ns) {
dc = PWM_ON_PERIOD_MAX;
pc = PWM_ON_PERIOD_MAX - 1;
goto done;
}
while (1) {
u64 rate;
/*
* Calculate the base rate from base frequency and current
* cword
*/
rate = (u64)clk_get_rate(p->clk) * (u64)cword;
rate >>= CWORD_BIT_SIZE;
pc = mul_u64_u64_div_u64(period_ns, rate, NSEC_PER_SEC);
dc = mul_u64_u64_div_u64(duty_ns + 1, rate, NSEC_PER_SEC);
/*
* We can be called with separate duty and period updates,
* so do not reject dc == 0 right away
*/
if (pc == PWM_PERIOD_MIN || (dc < PWM_ON_MIN && duty_ns))
return -EINVAL;
/* We converged on a calculation */
if (pc <= PWM_ON_PERIOD_MAX && dc <= PWM_ON_PERIOD_MAX)
break;
/*
* The cword needs to be a power of 2 for the variable
* frequency generator to output a 50% duty cycle variable
* frequency which is used as input clock to the fixed
* frequency generator.
*/
Annotation
- Immediate include surface: `linux/clk.h`, `linux/export.h`, `linux/init.h`, `linux/io.h`, `linux/kernel.h`, `linux/module.h`, `linux/of.h`, `linux/platform_device.h`.
- Detected declarations: `struct brcmstb_pwm`, `function brcmstb_pwm_readl`, `function brcmstb_pwm_writel`, `function brcmstb_pwm_config`, `function brcmstb_pwm_enable_set`, `function brcmstb_pwm_apply`, `function brcmstb_pwm_probe`, `function brcmstb_pwm_suspend`, `function brcmstb_pwm_resume`.
- 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.