static int atmel_pwm_apply()

in pwm-atmel.c [294:357]


static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
			   const struct pwm_state *state)
{
	struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
	struct pwm_state cstate;
	unsigned long cprd, cdty;
	u32 pres, val;
	int ret;

	pwm_get_state(pwm, &cstate);

	if (state->enabled) {
		unsigned long clkrate = clk_get_rate(atmel_pwm->clk);

		if (cstate.enabled &&
		    cstate.polarity == state->polarity &&
		    cstate.period == state->period) {
			u32 cmr = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR);

			cprd = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm,
						  atmel_pwm->data->regs.period);
			pres = cmr & PWM_CMR_CPRE_MSK;

			atmel_pwm_calculate_cdty(state, clkrate, cprd, pres, &cdty);
			atmel_pwm_update_cdty(chip, pwm, cdty);
			return 0;
		}

		ret = atmel_pwm_calculate_cprd_and_pres(chip, clkrate, state, &cprd,
							&pres);
		if (ret) {
			dev_err(chip->dev,
				"failed to calculate cprd and prescaler\n");
			return ret;
		}

		atmel_pwm_calculate_cdty(state, clkrate, cprd, pres, &cdty);

		if (cstate.enabled) {
			atmel_pwm_disable(chip, pwm, false);
		} else {
			ret = clk_enable(atmel_pwm->clk);
			if (ret) {
				dev_err(chip->dev, "failed to enable clock\n");
				return ret;
			}
		}

		/* It is necessary to preserve CPOL, inside CMR */
		val = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR);
		val = (val & ~PWM_CMR_CPRE_MSK) | (pres & PWM_CMR_CPRE_MSK);
		if (state->polarity == PWM_POLARITY_NORMAL)
			val &= ~PWM_CMR_CPOL;
		else
			val |= PWM_CMR_CPOL;
		atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val);
		atmel_pwm_set_cprd_cdty(chip, pwm, cprd, cdty);
		atmel_pwm_writel(atmel_pwm, PWM_ENA, 1 << pwm->hwpwm);
	} else if (cstate.enabled) {
		atmel_pwm_disable(chip, pwm, true);
	}

	return 0;
}