drivers/pwm/pwm-tegra.c
Source file repositories/reference/linux-study-clean/drivers/pwm/pwm-tegra.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/pwm/pwm-tegra.c- Extension
.c- Size
- 11488 bytes
- Lines
- 444
- 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/module.hlinux/of.hlinux/pm_opp.hlinux/pwm.hlinux/platform_device.hlinux/pinctrl/consumer.hlinux/pm_runtime.hlinux/slab.hlinux/reset.hsoc/tegra/common.h
Detected Declarations
struct tegra_pwm_socstruct tegra_pwm_chipfunction pwm_readlfunction pwm_writelfunction tegra_pwm_configfunction whichfunction tegra_pwm_enablefunction tegra_pwm_disablefunction tegra_pwm_applyfunction tegra_pwm_probefunction tegra_pwm_removefunction tegra_pwm_runtime_suspendfunction tegra_pwm_runtime_resume
Annotated Snippet
struct tegra_pwm_soc {
unsigned int num_channels;
/* Maximum IP frequency for given SoCs */
unsigned long max_frequency;
};
struct tegra_pwm_chip {
struct clk *clk;
struct reset_control*rst;
unsigned long clk_rate;
unsigned long min_period_ns;
void __iomem *regs;
const struct tegra_pwm_soc *soc;
};
static inline struct tegra_pwm_chip *to_tegra_pwm_chip(struct pwm_chip *chip)
{
return pwmchip_get_drvdata(chip);
}
static inline u32 pwm_readl(struct tegra_pwm_chip *pc, unsigned int offset)
{
return readl(pc->regs + (offset << 4));
}
static inline void pwm_writel(struct tegra_pwm_chip *pc, unsigned int offset, u32 value)
{
writel(value, pc->regs + (offset << 4));
}
static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
int duty_ns, int period_ns)
{
struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip);
unsigned long long c = duty_ns;
unsigned long rate, required_clk_rate;
u32 val = 0;
int err;
/*
* Convert from duty_ns / period_ns to a fixed number of duty ticks
* per (1 << PWM_DUTY_WIDTH) cycles and make sure to round to the
* nearest integer during division.
*/
c *= (1 << PWM_DUTY_WIDTH);
c = DIV_ROUND_CLOSEST_ULL(c, period_ns);
val = (u32)c << PWM_DUTY_SHIFT;
/*
* min period = max clock limit >> PWM_DUTY_WIDTH
*/
if (period_ns < pc->min_period_ns)
return -EINVAL;
/*
* Compute the prescaler value for which (1 << PWM_DUTY_WIDTH)
* cycles at the PWM clock rate will take period_ns nanoseconds.
*
* num_channels: If single instance of PWM controller has multiple
* channels (e.g. Tegra210 or older) then it is not possible to
* configure separate clock rates to each of the channels, in such
* case the value stored during probe will be referred.
*
* If every PWM controller instance has one channel respectively, i.e.
* nums_channels == 1 then only the clock rate can be modified
* dynamically (e.g. Tegra186 or Tegra194).
*/
if (pc->soc->num_channels == 1) {
/*
* Rate is multiplied with 2^PWM_DUTY_WIDTH so that it matches
* with the maximum possible rate that the controller can
* provide. Any further lower value can be derived by setting
* PFM bits[0:12].
*
* required_clk_rate is a reference rate for source clock and
* it is derived based on user requested period. By setting the
* source clock rate as required_clk_rate, PWM controller will
* be able to configure the requested period.
*/
required_clk_rate = DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC << PWM_DUTY_WIDTH,
period_ns);
if (required_clk_rate > clk_round_rate(pc->clk, required_clk_rate))
/*
* required_clk_rate is a lower bound for the input
Annotation
- Immediate include surface: `linux/clk.h`, `linux/err.h`, `linux/io.h`, `linux/module.h`, `linux/of.h`, `linux/pm_opp.h`, `linux/pwm.h`, `linux/platform_device.h`.
- Detected declarations: `struct tegra_pwm_soc`, `struct tegra_pwm_chip`, `function pwm_readl`, `function pwm_writel`, `function tegra_pwm_config`, `function which`, `function tegra_pwm_enable`, `function tegra_pwm_disable`, `function tegra_pwm_apply`, `function tegra_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.