mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 21:38:32 +08:00
pwm: bcm-kona: Implement .apply() callback
To eventually get rid of all legacy drivers convert this driver to the modern world implementing .apply(). The conversion wasn't quite straight forward because .config() and .enable() were special to effectively swap their usual order. This resulted in calculating the required values twice in some cases when pwm_apply_state() was called. This is optimized en passant, and the order of the callbacks is preserved without special jumping through hoops. Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
This commit is contained in:
parent
5f027d9b83
commit
1c1283db07
@ -109,10 +109,10 @@ static void kona_pwmc_apply_settings(struct kona_pwmc *kp, unsigned int chan)
|
||||
}
|
||||
|
||||
static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
int duty_ns, int period_ns)
|
||||
u64 duty_ns, u64 period_ns)
|
||||
{
|
||||
struct kona_pwmc *kp = to_kona_pwmc(chip);
|
||||
u64 val, div, rate;
|
||||
u64 div, rate;
|
||||
unsigned long prescale = PRESCALE_MIN, pc, dc;
|
||||
unsigned int value, chan = pwm->hwpwm;
|
||||
|
||||
@ -132,10 +132,8 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
while (1) {
|
||||
div = 1000000000;
|
||||
div *= 1 + prescale;
|
||||
val = rate * period_ns;
|
||||
pc = div64_u64(val, div);
|
||||
val = rate * duty_ns;
|
||||
dc = div64_u64(val, div);
|
||||
pc = mul_u64_u64_div_u64(rate, period_ns, div);
|
||||
dc = mul_u64_u64_div_u64(rate, duty_ns, div);
|
||||
|
||||
/* If duty_ns or period_ns are not achievable then return */
|
||||
if (pc < PERIOD_COUNT_MIN)
|
||||
@ -150,25 +148,18 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't apply settings if disabled. The period and duty cycle are
|
||||
* always calculated above to ensure the new values are
|
||||
* validated immediately instead of on enable.
|
||||
*/
|
||||
if (pwm_is_enabled(pwm)) {
|
||||
kona_pwmc_prepare_for_settings(kp, chan);
|
||||
kona_pwmc_prepare_for_settings(kp, chan);
|
||||
|
||||
value = readl(kp->base + PRESCALE_OFFSET);
|
||||
value &= ~PRESCALE_MASK(chan);
|
||||
value |= prescale << PRESCALE_SHIFT(chan);
|
||||
writel(value, kp->base + PRESCALE_OFFSET);
|
||||
value = readl(kp->base + PRESCALE_OFFSET);
|
||||
value &= ~PRESCALE_MASK(chan);
|
||||
value |= prescale << PRESCALE_SHIFT(chan);
|
||||
writel(value, kp->base + PRESCALE_OFFSET);
|
||||
|
||||
writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
|
||||
writel(pc, kp->base + PERIOD_COUNT_OFFSET(chan));
|
||||
|
||||
writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
|
||||
writel(dc, kp->base + DUTY_CYCLE_HIGH_OFFSET(chan));
|
||||
|
||||
kona_pwmc_apply_settings(kp, chan);
|
||||
}
|
||||
kona_pwmc_apply_settings(kp, chan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -216,13 +207,6 @@ static int kona_pwmc_enable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = kona_pwmc_config(chip, pwm, pwm_get_duty_cycle(pwm),
|
||||
pwm_get_period(pwm));
|
||||
if (ret < 0) {
|
||||
clk_disable_unprepare(kp->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -248,11 +232,53 @@ static void kona_pwmc_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
clk_disable_unprepare(kp->clk);
|
||||
}
|
||||
|
||||
static int kona_pwmc_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
int err;
|
||||
struct kona_pwmc *kp = to_kona_pwmc(chip);
|
||||
bool enabled = pwm->state.enabled;
|
||||
|
||||
if (state->polarity != pwm->state.polarity) {
|
||||
if (enabled) {
|
||||
kona_pwmc_disable(chip, pwm);
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
err = kona_pwmc_set_polarity(chip, pwm, state->polarity);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
pwm->state.polarity = state->polarity;
|
||||
}
|
||||
|
||||
if (!state->enabled) {
|
||||
if (enabled)
|
||||
kona_pwmc_disable(chip, pwm);
|
||||
return 0;
|
||||
} else if (!enabled) {
|
||||
/*
|
||||
* This is a bit special here, usually the PWM should only be
|
||||
* enabled when duty and period are setup. But before this
|
||||
* driver was converted to .apply it was done the other way
|
||||
* around and so this behaviour was kept even though this might
|
||||
* result in a glitch. This might be improvable by someone with
|
||||
* hardware and/or documentation.
|
||||
*/
|
||||
err = kona_pwmc_enable(chip, pwm);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = kona_pwmc_config(pwm->chip, pwm, state->duty_cycle, state->period);
|
||||
if (err && !pwm->state.enabled)
|
||||
clk_disable_unprepare(kp->clk);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct pwm_ops kona_pwm_ops = {
|
||||
.config = kona_pwmc_config,
|
||||
.set_polarity = kona_pwmc_set_polarity,
|
||||
.enable = kona_pwmc_enable,
|
||||
.disable = kona_pwmc_disable,
|
||||
.apply = kona_pwmc_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user