Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b14e8cef authored by Andy Shevchenko's avatar Andy Shevchenko Committed by Thierry Reding
Browse files

pwm: lpss: Switch to new atomic API



Instead of doing things separately, which is not so reliable on some platforms,
switch the driver to use new atomic API, i.e. ->apply() callback.

The change has been tested on Intel platforms such as Broxton, BayTrail, and
Merrifield.

Reviewed-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: default avatarThierry Reding <thierry.reding@gmail.com>
parent b5c050c7
Loading
Loading
Loading
Loading
+29 −35
Original line number Diff line number Diff line
@@ -82,15 +82,20 @@ static inline void pwm_lpss_write(const struct pwm_device *pwm, u32 value)

static void pwm_lpss_update(struct pwm_device *pwm)
{
	/*
	 * Set a limit for busyloop since not all implementations correctly
	 * clear PWM_SW_UPDATE bit (at least it's not visible on OS side).
	 */
	unsigned int count = 10;

	pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_SW_UPDATE);
	/* Give it some time to propagate */
	usleep_range(10, 50);
	while (pwm_lpss_read(pwm) & PWM_SW_UPDATE && --count)
		usleep_range(10, 20);
}

static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, struct pwm_device *pwm,
			     int duty_ns, int period_ns)
{
	struct pwm_lpss_chip *lpwm = to_lpwm(chip);
	unsigned long long on_time_div;
	unsigned long c = lpwm->info->clk_rate, base_unit_range;
	unsigned long long base_unit, freq = NSEC_PER_SEC;
@@ -111,8 +116,6 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
	do_div(on_time_div, period_ns);
	on_time_div = 255ULL - on_time_div;

	pm_runtime_get_sync(chip->dev);

	ctrl = pwm_lpss_read(pwm);
	ctrl &= ~PWM_ON_TIME_DIV_MASK;
	ctrl &= ~(base_unit_range << PWM_BASE_UNIT_SHIFT);
@@ -120,42 +123,33 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
	ctrl |= (u32) base_unit << PWM_BASE_UNIT_SHIFT;
	ctrl |= on_time_div;
	pwm_lpss_write(pwm, ctrl);

	/*
	 * If the PWM is already enabled we need to notify the hardware
	 * about the change by setting PWM_SW_UPDATE.
	 */
	if (pwm_is_enabled(pwm))
		pwm_lpss_update(pwm);

	pm_runtime_put(chip->dev);

	return 0;
}

static int pwm_lpss_enable(struct pwm_chip *chip, struct pwm_device *pwm)
static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm,
			  struct pwm_state *state)
{
	pm_runtime_get_sync(chip->dev);
	struct pwm_lpss_chip *lpwm = to_lpwm(chip);

	/*
	 * Hardware must first see PWM_SW_UPDATE before the PWM can be
	 * enabled.
	 */
	if (state->enabled) {
		if (!pwm_is_enabled(pwm)) {
			pm_runtime_get_sync(chip->dev);
			pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period);
			pwm_lpss_update(pwm);
			pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE);
	return 0;
		} else {
			pwm_lpss_prepare(lpwm, pwm, state->duty_cycle, state->period);
			pwm_lpss_update(pwm);
		}

static void pwm_lpss_disable(struct pwm_chip *chip, struct pwm_device *pwm)
{
	} else if (pwm_is_enabled(pwm)) {
		pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE);
		pm_runtime_put(chip->dev);
	}

	return 0;
}

static const struct pwm_ops pwm_lpss_ops = {
	.config = pwm_lpss_config,
	.enable = pwm_lpss_enable,
	.disable = pwm_lpss_disable,
	.apply = pwm_lpss_apply,
	.owner = THIS_MODULE,
};