提交 41652aae 编写于 作者: L Linus Torvalds

Merge tag 'pwm/for-5.17-rc1' of...

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
...@@ -9,6 +9,8 @@ title: PWM controllers (providers) ...@@ -9,6 +9,8 @@ title: PWM controllers (providers)
maintainers: maintainers:
- Thierry Reding <thierry.reding@gmail.com> - Thierry Reding <thierry.reding@gmail.com>
select: false
properties: properties:
$nodename: $nodename:
pattern: "^pwm(@.*|-[0-9a-f])*$" pattern: "^pwm(@.*|-[0-9a-f])*$"
......
...@@ -548,6 +548,73 @@ static void pwm_apply_state_debug(struct pwm_device *pwm, ...@@ -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_apply_state() - atomically apply a new state to a PWM device
* @pwm: PWM device * @pwm: PWM device
...@@ -580,70 +647,22 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state) ...@@ -580,70 +647,22 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
state->usage_power == pwm->state.usage_power) state->usage_power == pwm->state.usage_power)
return 0; return 0;
if (chip->ops->apply) { if (chip->ops->apply)
err = chip->ops->apply(chip, pwm, state); err = chip->ops->apply(chip, pwm, state);
if (err) else
return err; err = pwm_apply_legacy(chip, pwm, state);
if (err)
trace_pwm_apply(pwm, state); return err;
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;
/* trace_pwm_apply(pwm, state);
* 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, pwm->state = *state;
state->polarity);
if (err)
return err;
pwm->state.polarity = state->polarity; /*
} * only do this after pwm->state was applied as some
* implementations of .get_state depend on this
if (state->period != pwm->state.period || */
state->duty_cycle != pwm->state.duty_cycle) { pwm_apply_state_debug(pwm, state);
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;
}
}
return 0; return 0;
} }
......
...@@ -128,11 +128,9 @@ static int img_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -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); duty = DIV_ROUND_UP(timebase * duty_ns, period_ns);
ret = pm_runtime_get_sync(chip->dev); ret = pm_runtime_resume_and_get(chip->dev);
if (ret < 0) { if (ret < 0)
pm_runtime_put_autosuspend(chip->dev);
return ret; return ret;
}
val = img_pwm_readl(pwm_chip, PWM_CTRL_CFG); val = img_pwm_readl(pwm_chip, PWM_CTRL_CFG);
val &= ~(PWM_CTRL_CFG_DIV_MASK << PWM_CTRL_CFG_DIV_SHIFT(pwm->hwpwm)); 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) ...@@ -184,10 +182,33 @@ static void img_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
pm_runtime_put_autosuspend(chip->dev); 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 = { static const struct pwm_ops img_pwm_ops = {
.config = img_pwm_config, .apply = img_pwm_apply,
.enable = img_pwm_enable,
.disable = img_pwm_disable,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
......
...@@ -58,9 +58,9 @@ static inline struct twl_pwm_chip *to_twl(struct pwm_chip *chip) ...@@ -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, 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 }; u8 pwm_config[2] = { 1, 0 };
int base, ret; int base, ret;
...@@ -279,19 +279,65 @@ static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) ...@@ -279,19 +279,65 @@ static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
mutex_unlock(&twl->mutex); 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 = { static const struct pwm_ops twl4030_pwm_ops = {
.config = twl_pwm_config, .apply = twl4030_pwm_apply,
.enable = twl4030_pwm_enable,
.disable = twl4030_pwm_disable,
.request = twl4030_pwm_request, .request = twl4030_pwm_request,
.free = twl4030_pwm_free, .free = twl4030_pwm_free,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
static const struct pwm_ops twl6030_pwm_ops = { static const struct pwm_ops twl6030_pwm_ops = {
.config = twl_pwm_config, .apply = twl6030_pwm_apply,
.enable = twl6030_pwm_enable,
.disable = twl6030_pwm_disable,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
......
...@@ -70,7 +70,7 @@ static inline void vt8500_pwm_busy_wait(struct vt8500_chip *vt8500, int nr, u8 b ...@@ -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, 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); struct vt8500_chip *vt8500 = to_vt8500_chip(chip);
unsigned long long c; unsigned long long c;
...@@ -102,8 +102,8 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, ...@@ -102,8 +102,8 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
} }
c = (unsigned long long)pv * duty_ns; 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)); writel(prescale, vt8500->base + REG_SCALAR(pwm->hwpwm));
vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_SCALAR_UPDATE); vt8500_pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_SCALAR_UPDATE);
...@@ -176,11 +176,54 @@ static int vt8500_pwm_set_polarity(struct pwm_chip *chip, ...@@ -176,11 +176,54 @@ static int vt8500_pwm_set_polarity(struct pwm_chip *chip,
return 0; 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 = { static const struct pwm_ops vt8500_pwm_ops = {
.enable = vt8500_pwm_enable, .apply = vt8500_pwm_apply,
.disable = vt8500_pwm_disable,
.config = vt8500_pwm_config,
.set_polarity = vt8500_pwm_set_polarity,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册