| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * drivers/pwm/pwm-tegra.c |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Tegra pulse-width-modulation controller driver |
|---|
| 5 | 6 | * |
|---|
| 6 | | - * Copyright (c) 2010, NVIDIA Corporation. |
|---|
| 7 | + * Copyright (c) 2010-2020, NVIDIA Corporation. |
|---|
| 7 | 8 | * Based on arch/arm/plat-mxc/pwm.c by Sascha Hauer <s.hauer@pengutronix.de> |
|---|
| 8 | 9 | * |
|---|
| 9 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 10 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 11 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 12 | | - * (at your option) any later version. |
|---|
| 10 | + * Overview of Tegra Pulse Width Modulator Register: |
|---|
| 11 | + * 1. 13-bit: Frequency division (SCALE) |
|---|
| 12 | + * 2. 8-bit : Pulse division (DUTY) |
|---|
| 13 | + * 3. 1-bit : Enable bit |
|---|
| 13 | 14 | * |
|---|
| 14 | | - * This program is distributed in the hope that it will be useful, but WITHOUT |
|---|
| 15 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 16 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
|---|
| 17 | | - * more details. |
|---|
| 15 | + * The PWM clock frequency is divided by 256 before subdividing it based |
|---|
| 16 | + * on the programmable frequency division value to generate the required |
|---|
| 17 | + * frequency for PWM output. The maximum output frequency that can be |
|---|
| 18 | + * achieved is (max rate of source clock) / 256. |
|---|
| 19 | + * e.g. if source clock rate is 408 MHz, maximum output frequency can be: |
|---|
| 20 | + * 408 MHz/256 = 1.6 MHz. |
|---|
| 21 | + * This 1.6 MHz frequency can further be divided using SCALE value in PWM. |
|---|
| 18 | 22 | * |
|---|
| 19 | | - * You should have received a copy of the GNU General Public License along |
|---|
| 20 | | - * with this program; if not, write to the Free Software Foundation, Inc., |
|---|
| 21 | | - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|---|
| 23 | + * PWM pulse width: 8 bits are usable [23:16] for varying pulse width. |
|---|
| 24 | + * To achieve 100% duty cycle, program Bit [24] of this register to |
|---|
| 25 | + * 1’b1. In which case the other bits [23:16] are set to don't care. |
|---|
| 26 | + * |
|---|
| 27 | + * Limitations: |
|---|
| 28 | + * - When PWM is disabled, the output is driven to inactive. |
|---|
| 29 | + * - It does not allow the current PWM period to complete and |
|---|
| 30 | + * stops abruptly. |
|---|
| 31 | + * |
|---|
| 32 | + * - If the register is reconfigured while PWM is running, |
|---|
| 33 | + * it does not complete the currently running period. |
|---|
| 34 | + * |
|---|
| 35 | + * - If the user input duty is beyond acceptible limits, |
|---|
| 36 | + * -EINVAL is returned. |
|---|
| 22 | 37 | */ |
|---|
| 23 | 38 | |
|---|
| 24 | 39 | #include <linux/clk.h> |
|---|
| .. | .. |
|---|
| 54 | 69 | struct reset_control*rst; |
|---|
| 55 | 70 | |
|---|
| 56 | 71 | unsigned long clk_rate; |
|---|
| 72 | + unsigned long min_period_ns; |
|---|
| 57 | 73 | |
|---|
| 58 | 74 | void __iomem *regs; |
|---|
| 59 | 75 | |
|---|
| .. | .. |
|---|
| 81 | 97 | { |
|---|
| 82 | 98 | struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip); |
|---|
| 83 | 99 | unsigned long long c = duty_ns, hz; |
|---|
| 84 | | - unsigned long rate; |
|---|
| 100 | + unsigned long rate, required_clk_rate; |
|---|
| 85 | 101 | u32 val = 0; |
|---|
| 86 | 102 | int err; |
|---|
| 87 | 103 | |
|---|
| .. | .. |
|---|
| 96 | 112 | val = (u32)c << PWM_DUTY_SHIFT; |
|---|
| 97 | 113 | |
|---|
| 98 | 114 | /* |
|---|
| 115 | + * min period = max clock limit >> PWM_DUTY_WIDTH |
|---|
| 116 | + */ |
|---|
| 117 | + if (period_ns < pc->min_period_ns) |
|---|
| 118 | + return -EINVAL; |
|---|
| 119 | + |
|---|
| 120 | + /* |
|---|
| 99 | 121 | * Compute the prescaler value for which (1 << PWM_DUTY_WIDTH) |
|---|
| 100 | 122 | * cycles at the PWM clock rate will take period_ns nanoseconds. |
|---|
| 123 | + * |
|---|
| 124 | + * num_channels: If single instance of PWM controller has multiple |
|---|
| 125 | + * channels (e.g. Tegra210 or older) then it is not possible to |
|---|
| 126 | + * configure separate clock rates to each of the channels, in such |
|---|
| 127 | + * case the value stored during probe will be referred. |
|---|
| 128 | + * |
|---|
| 129 | + * If every PWM controller instance has one channel respectively, i.e. |
|---|
| 130 | + * nums_channels == 1 then only the clock rate can be modified |
|---|
| 131 | + * dynamically (e.g. Tegra186 or Tegra194). |
|---|
| 101 | 132 | */ |
|---|
| 133 | + if (pc->soc->num_channels == 1) { |
|---|
| 134 | + /* |
|---|
| 135 | + * Rate is multiplied with 2^PWM_DUTY_WIDTH so that it matches |
|---|
| 136 | + * with the maximum possible rate that the controller can |
|---|
| 137 | + * provide. Any further lower value can be derived by setting |
|---|
| 138 | + * PFM bits[0:12]. |
|---|
| 139 | + * |
|---|
| 140 | + * required_clk_rate is a reference rate for source clock and |
|---|
| 141 | + * it is derived based on user requested period. By setting the |
|---|
| 142 | + * source clock rate as required_clk_rate, PWM controller will |
|---|
| 143 | + * be able to configure the requested period. |
|---|
| 144 | + */ |
|---|
| 145 | + required_clk_rate = DIV_ROUND_UP_ULL((u64)NSEC_PER_SEC << PWM_DUTY_WIDTH, |
|---|
| 146 | + period_ns); |
|---|
| 147 | + |
|---|
| 148 | + err = clk_set_rate(pc->clk, required_clk_rate); |
|---|
| 149 | + if (err < 0) |
|---|
| 150 | + return -EINVAL; |
|---|
| 151 | + |
|---|
| 152 | + /* Store the new rate for further references */ |
|---|
| 153 | + pc->clk_rate = clk_get_rate(pc->clk); |
|---|
| 154 | + } |
|---|
| 155 | + |
|---|
| 102 | 156 | rate = pc->clk_rate >> PWM_DUTY_WIDTH; |
|---|
| 103 | 157 | |
|---|
| 104 | 158 | /* Consider precision in PWM_SCALE_WIDTH rate calculation */ |
|---|
| .. | .. |
|---|
| 107 | 161 | |
|---|
| 108 | 162 | /* |
|---|
| 109 | 163 | * Since the actual PWM divider is the register's frequency divider |
|---|
| 110 | | - * field minus 1, we need to decrement to get the correct value to |
|---|
| 164 | + * field plus 1, we need to decrement to get the correct value to |
|---|
| 111 | 165 | * write to the register. |
|---|
| 112 | 166 | */ |
|---|
| 113 | 167 | if (rate > 0) |
|---|
| .. | .. |
|---|
| 218 | 272 | */ |
|---|
| 219 | 273 | pwm->clk_rate = clk_get_rate(pwm->clk); |
|---|
| 220 | 274 | |
|---|
| 275 | + /* Set minimum limit of PWM period for the IP */ |
|---|
| 276 | + pwm->min_period_ns = |
|---|
| 277 | + (NSEC_PER_SEC / (pwm->soc->max_frequency >> PWM_DUTY_WIDTH)) + 1; |
|---|
| 278 | + |
|---|
| 221 | 279 | pwm->rst = devm_reset_control_get_exclusive(&pdev->dev, "pwm"); |
|---|
| 222 | 280 | if (IS_ERR(pwm->rst)) { |
|---|
| 223 | 281 | ret = PTR_ERR(pwm->rst); |
|---|
| .. | .. |
|---|
| 282 | 340 | .max_frequency = 102000000UL, |
|---|
| 283 | 341 | }; |
|---|
| 284 | 342 | |
|---|
| 343 | +static const struct tegra_pwm_soc tegra194_pwm_soc = { |
|---|
| 344 | + .num_channels = 1, |
|---|
| 345 | + .max_frequency = 408000000UL, |
|---|
| 346 | +}; |
|---|
| 347 | + |
|---|
| 285 | 348 | static const struct of_device_id tegra_pwm_of_match[] = { |
|---|
| 286 | 349 | { .compatible = "nvidia,tegra20-pwm", .data = &tegra20_pwm_soc }, |
|---|
| 287 | 350 | { .compatible = "nvidia,tegra186-pwm", .data = &tegra186_pwm_soc }, |
|---|
| 351 | + { .compatible = "nvidia,tegra194-pwm", .data = &tegra194_pwm_soc }, |
|---|
| 288 | 352 | { } |
|---|
| 289 | 353 | }; |
|---|
| 290 | | - |
|---|
| 291 | 354 | MODULE_DEVICE_TABLE(of, tegra_pwm_of_match); |
|---|
| 292 | 355 | |
|---|
| 293 | 356 | static const struct dev_pm_ops tegra_pwm_pm_ops = { |
|---|
| .. | .. |
|---|
| 307 | 370 | module_platform_driver(tegra_pwm_driver); |
|---|
| 308 | 371 | |
|---|
| 309 | 372 | MODULE_LICENSE("GPL"); |
|---|
| 310 | | -MODULE_AUTHOR("NVIDIA Corporation"); |
|---|
| 373 | +MODULE_AUTHOR("Sandipan Patra <spatra@nvidia.com>"); |
|---|
| 374 | +MODULE_DESCRIPTION("Tegra PWM controller driver"); |
|---|
| 311 | 375 | MODULE_ALIAS("platform:tegra-pwm"); |
|---|