Commit 41652aae authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents fa2e1ba3 3f056545
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -9,6 +9,8 @@ title: PWM controllers (providers)
maintainers:
  - Thierry Reding <thierry.reding@gmail.com>

select: false

properties:
  $nodename:
    pattern: "^pwm(@.*|-[0-9a-f])*$"
+79 −60
Original line number Diff line number Diff line
@@ -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,8 +647,10 @@ 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);
	else
		err = pwm_apply_legacy(chip, pwm, state);
	if (err)
		return err;

@@ -594,56 +663,6 @@ int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
	 * 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;
		}
	}

	return 0;
}
+28 −7
Original line number Diff line number Diff line
@@ -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,
};

+54 −8
Original line number Diff line number Diff line
@@ -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 @@ static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
	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,
};

+50 −7
Original line number Diff line number Diff line
@@ -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,
};