@@ -92,166 +92,138 @@ static inline void pwm_writel(struct tegra_pwm_chip *chip, unsigned int num,
writel(val, chip->regs + (num << 4));
}
-static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
- int duty_ns, int period_ns)
+static int tegra_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ const struct pwm_state *state)
{
struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip);
- unsigned long long c = duty_ns, hz;
- unsigned long rate, required_clk_rate;
- u32 val = 0;
int err;
+ u32 val;
- /*
- * 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);
+ if (state->polarity != PWM_POLARITY_INVERSED)
+ return -EINVAL;
- val = (u32)c << PWM_DUTY_SHIFT;
+ if (!state->enabled) {
+ if (pwm->state.enabled) {
+ val = pwm_readl(pc, pwm->hwpwm);
+ val &= ~PWM_ENABLE;
+ pwm_writel(pc, pwm->hwpwm, val);
+ clk_disable_unprepare(pc->clk);
+ }
+ return 0;
+ }
- /*
- * min period = max clock limit >> PWM_DUTY_WIDTH
- */
- if (period_ns < pc->min_period_ns)
- return -EINVAL;
+ if (state->period != pwm->state.period ||
+ state->duty_cycle != pwm->state.duty_cycle) {
+ int period_ns = state->period;
+ int duty_ns = state->duty_cycle;
+ unsigned long long c = duty_ns, hz;
+ unsigned long rate, required_clk_rate;
- /*
- * 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.
+ * 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.
*/
- required_clk_rate =
- (NSEC_PER_SEC / period_ns) << PWM_DUTY_WIDTH;
+ c *= (1 << PWM_DUTY_WIDTH);
+ c = DIV_ROUND_CLOSEST_ULL(c, period_ns);
- err = clk_set_rate(pc->clk, required_clk_rate);
- if (err < 0)
+ val = (u32)c << PWM_DUTY_SHIFT;
+
+ /*
+ * min period = max clock limit >> PWM_DUTY_WIDTH
+ */
+ if (period_ns < pc->min_period_ns)
return -EINVAL;
- /* Store the new rate for further references */
- pc->clk_rate = clk_get_rate(pc->clk);
- }
+ /*
+ * 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 =
+ (NSEC_PER_SEC / period_ns) << PWM_DUTY_WIDTH;
+
+ err = clk_set_rate(pc->clk, required_clk_rate);
+ if (err < 0)
+ return -EINVAL;
+
+ /* Store the new rate for further references */
+ pc->clk_rate = clk_get_rate(pc->clk);
+ }
+
+ rate = pc->clk_rate >> PWM_DUTY_WIDTH;
+
+ /* Consider precision in PWM_SCALE_WIDTH rate calculation */
+ hz = DIV_ROUND_CLOSEST_ULL(100ULL * NSEC_PER_SEC, period_ns);
+ rate = DIV_ROUND_CLOSEST_ULL(100ULL * rate, hz);
- rate = pc->clk_rate >> PWM_DUTY_WIDTH;
+ /*
+ * Since the actual PWM divider is the register's frequency divider
+ * field plus 1, we need to decrement to get the correct value to
+ * write to the register.
+ */
+ if (rate > 0)
+ rate--;
- /* Consider precision in PWM_SCALE_WIDTH rate calculation */
- hz = DIV_ROUND_CLOSEST_ULL(100ULL * NSEC_PER_SEC, period_ns);
- rate = DIV_ROUND_CLOSEST_ULL(100ULL * rate, hz);
+ /*
+ * Make sure that the rate will fit in the register's frequency
+ * divider field.
+ */
+ if (rate >> PWM_SCALE_WIDTH)
+ return -EINVAL;
- /*
- * Since the actual PWM divider is the register's frequency divider
- * field plus 1, we need to decrement to get the correct value to
- * write to the register.
- */
- if (rate > 0)
- rate--;
+ val |= rate << PWM_SCALE_SHIFT;
- /*
- * Make sure that the rate will fit in the register's frequency
- * divider field.
- */
- if (rate >> PWM_SCALE_WIDTH)
- return -EINVAL;
+ /*
+ * If the PWM channel is disabled, make sure to turn on the clock
+ * before writing the register. Otherwise, keep it enabled.
+ */
+ if (!pwm_is_enabled(pwm)) {
+ err = clk_prepare_enable(pc->clk);
+ if (err < 0)
+ return err;
+ } else
+ val |= PWM_ENABLE;
- val |= rate << PWM_SCALE_SHIFT;
+ pwm_writel(pc, pwm->hwpwm, val);
- /*
- * If the PWM channel is disabled, make sure to turn on the clock
- * before writing the register. Otherwise, keep it enabled.
- */
- if (!pwm_is_enabled(pwm)) {
+ /*
+ * If the PWM is not enabled, turn the clock off again to save power.
+ */
+ if (!pwm_is_enabled(pwm))
+ clk_disable_unprepare(pc->clk);
+ }
+
+ if (!pwm->state.enabled) {
err = clk_prepare_enable(pc->clk);
if (err < 0)
return err;
- } else
- val |= PWM_ENABLE;
-
- pwm_writel(pc, pwm->hwpwm, val);
-
- /*
- * If the PWM is not enabled, turn the clock off again to save power.
- */
- if (!pwm_is_enabled(pwm))
- clk_disable_unprepare(pc->clk);
-
- return 0;
-}
-
-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;
- rc = clk_prepare_enable(pc->clk);
- if (rc < 0)
- return rc;
-
- val = pwm_readl(pc, pwm->hwpwm);
- val |= PWM_ENABLE;
- pwm_writel(pc, pwm->hwpwm, 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 = pwm_readl(pc, pwm->hwpwm);
- val &= ~PWM_ENABLE;
- pwm_writel(pc, pwm->hwpwm, val);
-
- clk_disable_unprepare(pc->clk);
-}
-
-static int tegra_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
- const struct pwm_state *state)
-{
- int err;
-
- if (state->polarity != PWM_POLARITY_INVERSED)
- return -EINVAL;
-
- if (!state->enabled) {
- if (pwm->state.enabled)
- tegra_pwm_disable(chip, pwm);
- return 0;
- }
-
- if (state->period != pwm->state.period ||
- state->duty_cycle != pwm->state.duty_cycle) {
- err = tegra_pwm_config(pwm->chip, pwm, (int)state->duty_cycle,
- (int)state->period);
- if (err)
- return err;
+ val = pwm_readl(pc, pwm->hwpwm);
+ val |= PWM_ENABLE;
+ pwm_writel(pc, pwm->hwpwm, val);
}
- if (!pwm->state.enabled)
- return tegra_pwm_enable(chip, pwm);
-
return 0;
}
This just puts the implementation of tegra_pwm_disable(), tegra_pwm_enable() and tegra_pwm_config() into their only caller. Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> --- drivers/pwm/pwm-tegra.c | 244 ++++++++++++++++++---------------------- 1 file changed, 108 insertions(+), 136 deletions(-)