drivers/pwm/pwm-axi-pwmgen.c
Source file repositories/reference/linux-study-clean/drivers/pwm/pwm-axi-pwmgen.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/pwm/pwm-axi-pwmgen.c- Extension
.c- Size
- 10188 bytes
- Lines
- 342
- 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/adi-axi-common.hlinux/bits.hlinux/clk.hlinux/err.hlinux/io.hlinux/minmax.hlinux/module.hlinux/platform_device.hlinux/pwm.hlinux/regmap.hlinux/slab.h
Detected Declarations
struct axi_pwmgen_ddatastruct axi_pwmgen_waveformfunction axi_pwmgen_round_waveform_tohwfunction axi_pwmgen_round_waveform_fromhwfunction axi_pwmgen_write_waveformfunction axi_pwmgen_read_waveformfunction axi_pwmgen_setupfunction axi_pwmgen_probe
Annotated Snippet
struct axi_pwmgen_ddata {
struct regmap *regmap;
unsigned long clk_rate_hz;
};
static const struct regmap_config axi_pwmgen_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.max_register = 0xFC,
};
/* This represents a hardware configuration for one channel */
struct axi_pwmgen_waveform {
u32 period_cnt;
u32 duty_cycle_cnt;
u32 duty_offset_cnt;
};
static struct axi_pwmgen_ddata *axi_pwmgen_ddata_from_chip(struct pwm_chip *chip)
{
return pwmchip_get_drvdata(chip);
}
static int axi_pwmgen_round_waveform_tohw(struct pwm_chip *chip,
struct pwm_device *pwm,
const struct pwm_waveform *wf,
void *_wfhw)
{
struct axi_pwmgen_waveform *wfhw = _wfhw;
struct axi_pwmgen_ddata *ddata = axi_pwmgen_ddata_from_chip(chip);
int ret = 0;
if (wf->period_length_ns == 0) {
*wfhw = (struct axi_pwmgen_waveform){
.period_cnt = 0,
.duty_cycle_cnt = 0,
.duty_offset_cnt = 0,
};
} else {
/* With ddata->clk_rate_hz < NSEC_PER_SEC this won't overflow. */
wfhw->period_cnt = min_t(u64,
mul_u64_u32_div(wf->period_length_ns, ddata->clk_rate_hz, NSEC_PER_SEC),
U32_MAX);
if (wfhw->period_cnt == 0) {
/*
* The specified period is too short for the hardware.
* So round up .period_cnt to 1 (i.e. the smallest
* possible period). With .duty_cycle and .duty_offset
* being less than or equal to .period, their rounded
* value must be 0.
*/
wfhw->period_cnt = 1;
wfhw->duty_cycle_cnt = 0;
wfhw->duty_offset_cnt = 0;
ret = 1;
} else {
wfhw->duty_cycle_cnt = min_t(u64,
mul_u64_u32_div(wf->duty_length_ns, ddata->clk_rate_hz, NSEC_PER_SEC),
U32_MAX);
wfhw->duty_offset_cnt = min_t(u64,
mul_u64_u32_div(wf->duty_offset_ns, ddata->clk_rate_hz, NSEC_PER_SEC),
U32_MAX);
}
}
dev_dbg(&chip->dev, "pwm#%u: %lld/%lld [+%lld] @%lu -> PERIOD: %08x, DUTY: %08x, OFFSET: %08x\n",
pwm->hwpwm, wf->duty_length_ns, wf->period_length_ns, wf->duty_offset_ns,
ddata->clk_rate_hz, wfhw->period_cnt, wfhw->duty_cycle_cnt, wfhw->duty_offset_cnt);
return ret;
}
static int axi_pwmgen_round_waveform_fromhw(struct pwm_chip *chip, struct pwm_device *pwm,
const void *_wfhw, struct pwm_waveform *wf)
{
const struct axi_pwmgen_waveform *wfhw = _wfhw;
struct axi_pwmgen_ddata *ddata = axi_pwmgen_ddata_from_chip(chip);
wf->period_length_ns = DIV64_U64_ROUND_UP((u64)wfhw->period_cnt * NSEC_PER_SEC,
ddata->clk_rate_hz);
wf->duty_length_ns = DIV64_U64_ROUND_UP((u64)wfhw->duty_cycle_cnt * NSEC_PER_SEC,
ddata->clk_rate_hz);
wf->duty_offset_ns = DIV64_U64_ROUND_UP((u64)wfhw->duty_offset_cnt * NSEC_PER_SEC,
ddata->clk_rate_hz);
return 0;
Annotation
- Immediate include surface: `linux/adi-axi-common.h`, `linux/bits.h`, `linux/clk.h`, `linux/err.h`, `linux/io.h`, `linux/minmax.h`, `linux/module.h`, `linux/platform_device.h`.
- Detected declarations: `struct axi_pwmgen_ddata`, `struct axi_pwmgen_waveform`, `function axi_pwmgen_round_waveform_tohw`, `function axi_pwmgen_round_waveform_fromhw`, `function axi_pwmgen_write_waveform`, `function axi_pwmgen_read_waveform`, `function axi_pwmgen_setup`, `function axi_pwmgen_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.