pwm: Changes for v5.17-rc1
This contains a number of nice cleanups and improvements for the core and various drivers as well as a minor tweak to the json-schema device tree bindings. -----BEGIN PGP SIGNATURE----- iQJNBAABCAA3FiEEiOrDCAFJzPfAjcif3SOs138+s6EFAmHn9jsZHHRoaWVycnku cmVkaW5nQGdtYWlsLmNvbQAKCRDdI6zXfz6zofJxEACUZbZ7IcJoq2zQ+TbP6DPW DN8UyT41JsvHmHwWOv1Y3LZkHFE2HN9novJWxTx9tS0aUjwizKpJpBC3up7NC9gj 67vnHdyISAqdRGsrgGkza0q2h3nA0rgz3EINj+XeCdvtU+3wCYHahaiy0hH8GSjN XnqBOJQDLKqC3a5MGtZZ+oGUIARyCVVhbDlUrXUU+6Q71SjmjbVUtt/RjjYl0qsO RKHR5Wz8wg6reR9eJDOST2HvYoi2Z1Zf8M+i4kSF+dwHcRzbCEu7VZLGiz8lovBO l9+2jU/11Lqqr7a3qIw7/xeBF3WSL31QQTFaDq+hX/xWFa4fmtyvw2J68ZoLAKib eEjx6lfrbAx/9dlfs7l0IQLsPgty/JBJE760vwDXYpQ5VqAqhCRWHPABQjpGi/nB CSvXw1ZJrxnMUISwfkrEZxQzsKLDKBjqTaTHQ8VK8nmwjHvktE/5wfuTAIfipuj4 8JCNSX8JzfHkhATv7TBepNxJh1JEjrqeQ2abFgmRqJrGNeoN4wgRSg6OWxIiBXCj XQNhxfmEmPguJ85XHIvMqSt8d+9o/DCdOB5y9IKGFTrAJZVBhdxw06qxTCiXasar 31mQYDCejzxVVsPRfN5q0fZXlz6Sskzcoj7fKKpsyNtik71ONxv3XPLuq5JOLuwv Z1wMLELztSo/3AFELNi25Q== =T47H -----END PGP SIGNATURE----- Merge tag 'pwm/for-5.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm Pull pwm updates from Thierry Reding: "This contains a number of nice cleanups and improvements for the core and various drivers, as well as a minor tweak to the json-schema device tree bindings" * tag 'pwm/for-5.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: dt-bindings: pwm: Avoid selecting schema on node name match pwm: img: Use only a single idiom to get a runtime PM reference pwm: vt8500: Implement .apply() callback pwm: img: Implement .apply() callback pwm: twl: Implement .apply() callback pwm: Restore initial state if a legacy callback fails pwm: Prevent a glitch for legacy drivers pwm: Move legacy driver handling into a dedicated function
This commit is contained in:
commit
41652aae67
|
@ -9,6 +9,8 @@ title: PWM controllers (providers)
|
|||
maintainers:
|
||||
- Thierry Reding <thierry.reding@gmail.com>
|
||||
|
||||
select: false
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^pwm(@.*|-[0-9a-f])*$"
|
||||
|
|
|
@ -548,6 +548,73 @@ static void pwm_apply_state_debug(struct pwm_device *pwm,
|
|||
}
|
||||
}
|
||||
|
||||
static int pwm_apply_legacy(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
int err;
|
||||
struct pwm_state initial_state = pwm->state;
|
||||
|
||||
if (state->polarity != pwm->state.polarity) {
|
||||
if (!chip->ops->set_polarity)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Changing the polarity of a running PWM is only allowed when
|
||||
* the PWM driver implements ->apply().
|
||||
*/
|
||||
if (pwm->state.enabled) {
|
||||
chip->ops->disable(chip, pwm);
|
||||
|
||||
/*
|
||||
* Update pwm->state already here in case
|
||||
* .set_polarity() or another callback depend on that.
|
||||
*/
|
||||
pwm->state.enabled = false;
|
||||
}
|
||||
|
||||
err = chip->ops->set_polarity(chip, pwm, state->polarity);
|
||||
if (err)
|
||||
goto rollback;
|
||||
|
||||
pwm->state.polarity = state->polarity;
|
||||
}
|
||||
|
||||
if (!state->enabled) {
|
||||
if (pwm->state.enabled)
|
||||
chip->ops->disable(chip, pwm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We cannot skip calling ->config even if state->period ==
|
||||
* pwm->state.period && state->duty_cycle == pwm->state.duty_cycle
|
||||
* because we might have exited early in the last call to
|
||||
* pwm_apply_state because of !state->enabled and so the two values in
|
||||
* pwm->state might not be configured in hardware.
|
||||
*/
|
||||
err = chip->ops->config(pwm->chip, pwm,
|
||||
state->duty_cycle,
|
||||
state->period);
|
||||
if (err)
|
||||
goto rollback;
|
||||
|
||||
pwm->state.period = state->period;
|
||||
pwm->state.duty_cycle = state->duty_cycle;
|
||||
|
||||
if (!pwm->state.enabled) {
|
||||
err = chip->ops->enable(chip, pwm);
|
||||
if (err)
|
||||
goto rollback;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
rollback:
|
||||
pwm->state = initial_state;
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* pwm_apply_state() - atomically apply a new state to a PWM device
|
||||
* @pwm: PWM device
|
||||
|
@ -580,70 +647,22 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
|
|||
state->usage_power == pwm->state.usage_power)
|
||||
return 0;
|
||||
|
||||
if (chip->ops->apply) {
|
||||
if (chip->ops->apply)
|
||||
err = chip->ops->apply(chip, pwm, state);
|
||||
if (err)
|
||||
return err;
|
||||
else
|
||||
err = pwm_apply_legacy(chip, pwm, state);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
trace_pwm_apply(pwm, state);
|
||||
trace_pwm_apply(pwm, state);
|
||||
|
||||
pwm->state = *state;
|
||||
pwm->state = *state;
|
||||
|
||||
/*
|
||||
* only do this after pwm->state was applied as some
|
||||
* implementations of .get_state depend on this
|
||||
*/
|
||||
pwm_apply_state_debug(pwm, state);
|
||||
} else {
|
||||
/*
|
||||
* FIXME: restore the initial state in case of error.
|
||||
*/
|
||||
if (state->polarity != pwm->state.polarity) {
|
||||
if (!chip->ops->set_polarity)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Changing the polarity of a running PWM is
|
||||
* only allowed when the PWM driver implements
|
||||
* ->apply().
|
||||
*/
|
||||
if (pwm->state.enabled) {
|
||||
chip->ops->disable(chip, pwm);
|
||||
pwm->state.enabled = false;
|
||||
}
|
||||
|
||||
err = chip->ops->set_polarity(chip, pwm,
|
||||
state->polarity);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
pwm->state.polarity = state->polarity;
|
||||
}
|
||||
|
||||
if (state->period != pwm->state.period ||
|
||||
state->duty_cycle != pwm->state.duty_cycle) {
|
||||
err = chip->ops->config(pwm->chip, pwm,
|
||||
state->duty_cycle,
|
||||
state->period);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
pwm->state.duty_cycle = state->duty_cycle;
|
||||
pwm->state.period = state->period;
|
||||
}
|
||||
|
||||
if (state->enabled != pwm->state.enabled) {
|
||||
if (state->enabled) {
|
||||
err = chip->ops->enable(chip, pwm);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
chip->ops->disable(chip, pwm);
|
||||
}
|
||||
|
||||
pwm->state.enabled = state->enabled;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* only do this after pwm->state was applied as some
|
||||
* implementations of .get_state depend on this
|
||||
*/
|
||||
pwm_apply_state_debug(pwm, state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -128,11 +128,9 @@ static int img_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
|||
|
||||
duty = DIV_ROUND_UP(timebase * duty_ns, period_ns);
|
||||
|
||||
ret = pm_runtime_get_sync(chip->dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_autosuspend(chip->dev);
|
||||
ret = pm_runtime_resume_and_get(chip->dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
val = img_pwm_readl(pwm_chip, PWM_CTRL_CFG);
|
||||
val &= ~(PWM_CTRL_CFG_DIV_MASK << PWM_CTRL_CFG_DIV_SHIFT(pwm->hwpwm));
|
||||
|
@ -184,10 +182,33 @@ static void img_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
|
|||
pm_runtime_put_autosuspend(chip->dev);
|
||||
}
|
||||
|
||||
static int img_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (state->polarity != PWM_POLARITY_NORMAL)
|
||||
return -EINVAL;
|
||||
|
||||
if (!state->enabled) {
|
||||
if (pwm->state.enabled)
|
||||
img_pwm_disable(chip, pwm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = img_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!pwm->state.enabled)
|
||||
err = img_pwm_enable(chip, pwm);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct pwm_ops img_pwm_ops = {
|
||||
.config = img_pwm_config,
|
||||
.enable = img_pwm_enable,
|
||||
.disable = img_pwm_disable,
|
||||
.apply = img_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
|
|
@ -58,9 +58,9 @@ static inline struct twl_pwm_chip *to_twl(struct pwm_chip *chip)
|
|||
}
|
||||
|
||||
static int twl_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
int duty_ns, int period_ns)
|
||||
u64 duty_ns, u64 period_ns)
|
||||
{
|
||||
int duty_cycle = DIV_ROUND_UP(duty_ns * TWL_PWM_MAX, period_ns) + 1;
|
||||
int duty_cycle = DIV64_U64_ROUND_UP(duty_ns * TWL_PWM_MAX, period_ns) + 1;
|
||||
u8 pwm_config[2] = { 1, 0 };
|
||||
int base, ret;
|
||||
|
||||
|
@ -279,19 +279,65 @@ out:
|
|||
mutex_unlock(&twl->mutex);
|
||||
}
|
||||
|
||||
static int twl4030_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (state->polarity != PWM_POLARITY_NORMAL)
|
||||
return -EINVAL;
|
||||
|
||||
if (!state->enabled) {
|
||||
if (pwm->state.enabled)
|
||||
twl4030_pwm_disable(chip, pwm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = twl_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!pwm->state.enabled)
|
||||
err = twl4030_pwm_enable(chip, pwm);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int twl6030_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (state->polarity != PWM_POLARITY_NORMAL)
|
||||
return -EINVAL;
|
||||
|
||||
if (!state->enabled) {
|
||||
if (pwm->state.enabled)
|
||||
twl6030_pwm_disable(chip, pwm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = twl_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!pwm->state.enabled)
|
||||
err = twl6030_pwm_enable(chip, pwm);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct pwm_ops twl4030_pwm_ops = {
|
||||
.config = twl_pwm_config,
|
||||
.enable = twl4030_pwm_enable,
|
||||
.disable = twl4030_pwm_disable,
|
||||
.apply = twl4030_pwm_apply,
|
||||
.request = twl4030_pwm_request,
|
||||
.free = twl4030_pwm_free,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct pwm_ops twl6030_pwm_ops = {
|
||||
.config = twl_pwm_config,
|
||||
.enable = twl6030_pwm_enable,
|
||||
.disable = twl6030_pwm_disable,
|
||||
.apply = twl6030_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ static inline void vt8500_pwm_busy_wait(struct vt8500_chip *vt8500, int nr, u8 b
|
|||
}
|
||||
|
||||
static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
int duty_ns, int period_ns)
|
||||
u64 duty_ns, u64 period_ns)
|
||||
{
|
||||
struct vt8500_chip *vt8500 = to_vt8500_chip(chip);
|
||||
unsigned long long c;
|
||||
|
@ -102,8 +102,8 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
|||
}
|
||||
|
||||
c = (unsigned long long)pv * duty_ns;
|
||||
do_div(c, period_ns);
|
||||
dc = c;
|
||||
|
||||
dc = div64_u64(c, period_ns);
|
||||
|
||||
writel(prescale, vt8500->base + REG_SCALAR(pwm->hwpwm));
|
||||
vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_SCALAR_UPDATE);
|
||||
|
@ -176,11 +176,54 @@ static int vt8500_pwm_set_polarity(struct pwm_chip *chip,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int vt8500_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
int err;
|
||||
bool enabled = pwm->state.enabled;
|
||||
|
||||
if (state->polarity != pwm->state.polarity) {
|
||||
/*
|
||||
* Changing the polarity of a running PWM is only allowed when
|
||||
* the PWM driver implements ->apply().
|
||||
*/
|
||||
if (enabled) {
|
||||
vt8500_pwm_disable(chip, pwm);
|
||||
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
err = vt8500_pwm_set_polarity(chip, pwm, state->polarity);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!state->enabled) {
|
||||
if (enabled)
|
||||
vt8500_pwm_disable(chip, pwm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We cannot skip calling ->config even if state->period ==
|
||||
* pwm->state.period && state->duty_cycle == pwm->state.duty_cycle
|
||||
* because we might have exited early in the last call to
|
||||
* pwm_apply_state because of !state->enabled and so the two values in
|
||||
* pwm->state might not be configured in hardware.
|
||||
*/
|
||||
err = vt8500_pwm_config(pwm->chip, pwm, state->duty_cycle, state->period);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!enabled)
|
||||
err = vt8500_pwm_enable(chip, pwm);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct pwm_ops vt8500_pwm_ops = {
|
||||
.enable = vt8500_pwm_enable,
|
||||
.disable = vt8500_pwm_disable,
|
||||
.config = vt8500_pwm_config,
|
||||
.set_polarity = vt8500_pwm_set_polarity,
|
||||
.apply = vt8500_pwm_apply,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue