Commit 2f81b51d authored by Lino Sanfilippo's avatar Lino Sanfilippo Committed by Thierry Reding

pwm: bcm2835: Support apply function for atomic configuration

Use the newer .apply function of pwm_ops instead of .config, .enable,
.disable and .set_polarity. This guarantees atomic changes of the pwm
controller configuration. It also reduces the size of the driver.

Since now period is a 64 bit value, add an extra check to reject periods
that exceed the possible max value for the 32 bit register.

This has been tested on a Raspberry PI 4.
Signed-off-by: default avatarLino Sanfilippo <LinoSanfilippo@gmx.de>
Reviewed-by: default avatarUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: default avatarThierry Reding <thierry.reding@gmail.com>
parent bb72e1db
...@@ -58,13 +58,15 @@ static void bcm2835_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) ...@@ -58,13 +58,15 @@ static void bcm2835_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
writel(value, pc->base + PWM_CONTROL); writel(value, pc->base + PWM_CONTROL);
} }
static int bcm2835_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, static int bcm2835_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
int duty_ns, int period_ns) const struct pwm_state *state)
{ {
struct bcm2835_pwm *pc = to_bcm2835_pwm(chip); struct bcm2835_pwm *pc = to_bcm2835_pwm(chip);
unsigned long rate = clk_get_rate(pc->clk); unsigned long rate = clk_get_rate(pc->clk);
unsigned long long period;
unsigned long scaler; unsigned long scaler;
u32 period; u32 val;
if (!rate) { if (!rate) {
dev_err(pc->dev, "failed to get clock rate\n"); dev_err(pc->dev, "failed to get clock rate\n");
...@@ -72,54 +74,34 @@ static int bcm2835_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -72,54 +74,34 @@ static int bcm2835_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
} }
scaler = DIV_ROUND_CLOSEST(NSEC_PER_SEC, rate); scaler = DIV_ROUND_CLOSEST(NSEC_PER_SEC, rate);
period = DIV_ROUND_CLOSEST(period_ns, scaler); /* set period */
period = DIV_ROUND_CLOSEST_ULL(state->period, scaler);
if (period < PERIOD_MIN) /* dont accept a period that is too small or has been truncated */
if ((period < PERIOD_MIN) || (period > U32_MAX))
return -EINVAL; return -EINVAL;
writel(DIV_ROUND_CLOSEST(duty_ns, scaler),
pc->base + DUTY(pwm->hwpwm));
writel(period, pc->base + PERIOD(pwm->hwpwm)); writel(period, pc->base + PERIOD(pwm->hwpwm));
return 0; /* set duty cycle */
} val = DIV_ROUND_CLOSEST_ULL(state->duty_cycle, scaler);
writel(val, pc->base + DUTY(pwm->hwpwm));
static int bcm2835_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct bcm2835_pwm *pc = to_bcm2835_pwm(chip);
u32 value;
value = readl(pc->base + PWM_CONTROL);
value |= PWM_ENABLE << PWM_CONTROL_SHIFT(pwm->hwpwm);
writel(value, pc->base + PWM_CONTROL);
return 0; /* set polarity */
} val = readl(pc->base + PWM_CONTROL);
static void bcm2835_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) if (state->polarity == PWM_POLARITY_NORMAL)
{ val &= ~(PWM_POLARITY << PWM_CONTROL_SHIFT(pwm->hwpwm));
struct bcm2835_pwm *pc = to_bcm2835_pwm(chip); else
u32 value; val |= PWM_POLARITY << PWM_CONTROL_SHIFT(pwm->hwpwm);
value = readl(pc->base + PWM_CONTROL);
value &= ~(PWM_ENABLE << PWM_CONTROL_SHIFT(pwm->hwpwm));
writel(value, pc->base + PWM_CONTROL);
}
static int bcm2835_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
enum pwm_polarity polarity)
{
struct bcm2835_pwm *pc = to_bcm2835_pwm(chip);
u32 value;
value = readl(pc->base + PWM_CONTROL);
if (polarity == PWM_POLARITY_NORMAL) /* enable/disable */
value &= ~(PWM_POLARITY << PWM_CONTROL_SHIFT(pwm->hwpwm)); if (state->enabled)
val |= PWM_ENABLE << PWM_CONTROL_SHIFT(pwm->hwpwm);
else else
value |= PWM_POLARITY << PWM_CONTROL_SHIFT(pwm->hwpwm); val &= ~(PWM_ENABLE << PWM_CONTROL_SHIFT(pwm->hwpwm));
writel(value, pc->base + PWM_CONTROL); writel(val, pc->base + PWM_CONTROL);
return 0; return 0;
} }
...@@ -127,10 +109,7 @@ static int bcm2835_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -127,10 +109,7 @@ static int bcm2835_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
static const struct pwm_ops bcm2835_pwm_ops = { static const struct pwm_ops bcm2835_pwm_ops = {
.request = bcm2835_pwm_request, .request = bcm2835_pwm_request,
.free = bcm2835_pwm_free, .free = bcm2835_pwm_free,
.config = bcm2835_pwm_config, .apply = bcm2835_pwm_apply,
.enable = bcm2835_pwm_enable,
.disable = bcm2835_pwm_disable,
.set_polarity = bcm2835_set_polarity,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment