diff options
| author | Mikko Perttunen <mperttunen@nvidia.com> | 2026-07-01 12:20:35 +0900 |
|---|---|---|
| committer | Uwe Kleine-König <ukleinek@kernel.org> | 2026-07-14 11:29:26 +0200 |
| commit | 82dcd68f7246eeacbc2ef614b82e284a50b2b8bb (patch) | |
| tree | 08eb5f0fa16381eed8202b675220fb23bbe315b2 /drivers | |
| parent | b9a6f48de9a4816d5f5fc9adacfe7f3433012d2b (diff) | |
| download | linux-next-82dcd68f7246eeacbc2ef614b82e284a50b2b8bb.tar.gz linux-next-82dcd68f7246eeacbc2ef614b82e284a50b2b8bb.zip | |
pwm: tegra: Add support for Tegra264
Tegra264 changes the register layout to accommodate wider fields
for duty and scale, and adds configurable depth which will be
supported in a later patch. The enable bit also moves from CSR_0
to a separate CSR_1 register.
To support the new enable register location, introduce an
enable_reg field in struct tegra_pwm_soc that identifies which
register contains the PWM_ENABLE bit. tegra_pwm_enable() and
tegra_pwm_disable() read/write this field accordingly, and
tegra_pwm_config() skips OR-ing PWM_ENABLE into its CSR_0 write
on SoCs where the enable bit is not in CSR_0.
Update the top comment to describe the register layout in more
detail.
Co-developed-by: Yi-Wei Wang <yiweiw@nvidia.com>
Signed-off-by: Yi-Wei Wang <yiweiw@nvidia.com>
Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
Tested-by: Jon Hunter <jonathanh@nvidia.com>
Reviewed-by: Jon Hunter <jonathanh@nvidia.com>
Link: https://patch.msgid.link/20260701-t264-pwm-v6-6-2718f61f411f@nvidia.com
Signed-off-by: Uwe Kleine-König <ukleinek@kernel.org>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/pwm/pwm-tegra.c | 91 |
1 files changed, 72 insertions, 19 deletions
diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c index ad75e4ee3410..5cdbe120ba2d 100644 --- a/drivers/pwm/pwm-tegra.c +++ b/drivers/pwm/pwm-tegra.c @@ -7,22 +7,61 @@ * Copyright (c) 2010-2020, NVIDIA Corporation. * Based on arch/arm/plat-mxc/pwm.c by Sascha Hauer <s.hauer@pengutronix.de> * - * Overview of Tegra Pulse Width Modulator Register: - * 1. 13-bit: Frequency division (SCALE) - * 2. 8-bit : Pulse division (DUTY) - * 3. 1-bit : Enable bit + * Overview of Tegra Pulse Width Modulator Register + * CSR_0 of Tegra20, Tegra186, and Tegra194: + * +-------+-------+-----------------------------------------------------------+ + * | Bit | Field | Description | + * +-------+-------+-----------------------------------------------------------+ + * | 31 | ENB | Enable Pulse width modulator. | + * | | | 0 = DISABLE, 1 = ENABLE. | + * +-------+-------+-----------------------------------------------------------+ + * | 30:16 | PWM_0 | Pulse width that needs to be programmed. | + * | | | 0 = Always low. | + * | | | 1 = 1 / 256 pulse high. | + * | | | 2 = 2 / 256 pulse high. | + * | | | N = N / 256 pulse high. | + * | | | Only 8 bits are usable [23:16]. | + * | | | Bit[24] can be programmed to 1 to achieve 100% duty | + * | | | cycle. In this case the other bits [23:16] are set to | + * | | | don’t care. | + * +-------+-------+-----------------------------------------------------------+ + * | 12:0 | PFM_0 | Frequency divider that needs to be programmed, also known | + * | | | as SCALE. Division by (1 + PFM_0). | + * +-------+-------+-----------------------------------------------------------+ * - * The PWM clock frequency is divided by 256 before subdividing it based - * on the programmable frequency division value to generate the required - * frequency for PWM output. The maximum output frequency that can be - * achieved is (max rate of source clock) / 256. - * e.g. if source clock rate is 408 MHz, maximum output frequency can be: - * 408 MHz/256 = 1.6 MHz. - * This 1.6 MHz frequency can further be divided using SCALE value in PWM. + * CSR_0 of Tegra264: + * +-------+-------+-----------------------------------------------------------+ + * | Bit | Field | Description | + * +-------+-------+-----------------------------------------------------------+ + * | 31:16 | PWM_0 | Pulse width that needs to be programmed. | + * | | | 0 = Always low. | + * | | | 1 = 1 / (1 + CSR_1.DEPTH) pulse high. | + * | | | 2 = 2 / (1 + CSR_1.DEPTH) pulse high. | + * | | | N = N / (1 + CSR_1.DEPTH) pulse high. | + * +-------+-------+-----------------------------------------------------------+ + * | 15:0 | PFM_0 | Frequency divider that needs to be programmed, also known | + * | | | as SCALE. Division by (1 + PFM_0). | + * +-------+-------+-----------------------------------------------------------+ + * + * CSR_1 of Tegra264: + * +-------+-------+-----------------------------------------------------------+ + * | Bit | Field | Description | + * +-------+-------+-----------------------------------------------------------+ + * | 31 | ENB | Enable Pulse width modulator. | + * | | | 0 = DISABLE, 1 = ENABLE. | + * +-------+-------+-----------------------------------------------------------+ + * | 30:15 | DEPTH | Depth for pulse width modulator. This controls the pulse | + * | | | time generated. Division by (1 + CSR_1.DEPTH). | + * +-------+-------+-----------------------------------------------------------+ * - * PWM pulse width: 8 bits are usable [23:16] for varying pulse width. - * To achieve 100% duty cycle, program Bit [24] of this register to - * 1’b1. In which case the other bits [23:16] are set to don't care. + * The PWM clock frequency is divided by DEPTH = (1 + CSR_1.DEPTH) before + * subdividing it based on the programmable frequency division value to + * generate the required frequency for PWM output. DEPTH is fixed to 256 + * before Tegra264. The maximum output frequency that can be achieved is + * (max rate of source clock) / DEPTH. + * e.g. if source clock rate is 408 MHz, and DEPTH = 256, maximum output + * frequency can be: 408 MHz / 256 ~= 1.6 MHz. + * This 1.6 MHz frequency can further be divided using SCALE value in PWM. * * Limitations: * - When PWM is disabled, the output is driven to inactive. @@ -56,11 +95,13 @@ #define TEGRA_PWM_SCALE_SHIFT 0 #define TEGRA_PWM_CSR_0 0 +#define TEGRA_PWM_CSR_1 4 #define TEGRA_PWM_DEPTH 256 struct tegra_pwm_soc { unsigned int num_channels; + unsigned int enable_reg; unsigned int scale_width; }; @@ -199,8 +240,9 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, err = pm_runtime_resume_and_get(pwmchip_parent(chip)); if (err) return err; - } else + } else if (pc->soc->enable_reg == TEGRA_PWM_CSR_0) { val |= TEGRA_PWM_ENABLE; + } tegra_pwm_writel(pwm, TEGRA_PWM_CSR_0, val); @@ -215,6 +257,7 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, static int tegra_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) { + struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip); int rc = 0; u32 val; @@ -222,20 +265,21 @@ static int tegra_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) if (rc) return rc; - val = tegra_pwm_readl(pwm, TEGRA_PWM_CSR_0); + val = tegra_pwm_readl(pwm, pc->soc->enable_reg); val |= TEGRA_PWM_ENABLE; - tegra_pwm_writel(pwm, TEGRA_PWM_CSR_0, val); + tegra_pwm_writel(pwm, pc->soc->enable_reg, val); return 0; } static void tegra_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) { + struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip); u32 val; - val = tegra_pwm_readl(pwm, TEGRA_PWM_CSR_0); + val = tegra_pwm_readl(pwm, pc->soc->enable_reg); val &= ~TEGRA_PWM_ENABLE; - tegra_pwm_writel(pwm, TEGRA_PWM_CSR_0, val); + tegra_pwm_writel(pwm, pc->soc->enable_reg, val); pm_runtime_put_sync(pwmchip_parent(chip)); } @@ -405,18 +449,27 @@ static int __maybe_unused tegra_pwm_runtime_resume(struct device *dev) static const struct tegra_pwm_soc tegra20_pwm_soc = { .num_channels = 4, + .enable_reg = TEGRA_PWM_CSR_0, .scale_width = 13, }; static const struct tegra_pwm_soc tegra186_pwm_soc = { .num_channels = 1, + .enable_reg = TEGRA_PWM_CSR_0, .scale_width = 13, }; +static const struct tegra_pwm_soc tegra264_pwm_soc = { + .num_channels = 1, + .enable_reg = TEGRA_PWM_CSR_1, + .scale_width = 16, +}; + static const struct of_device_id tegra_pwm_of_match[] = { { .compatible = "nvidia,tegra20-pwm", .data = &tegra20_pwm_soc }, { .compatible = "nvidia,tegra186-pwm", .data = &tegra186_pwm_soc }, { .compatible = "nvidia,tegra194-pwm", .data = &tegra186_pwm_soc }, + { .compatible = "nvidia,tegra264-pwm", .data = &tegra264_pwm_soc }, { } }; MODULE_DEVICE_TABLE(of, tegra_pwm_of_match); |
