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

Commit 2267517c authored by Boris Brezillon's avatar Boris Brezillon Committed by Thierry Reding
Browse files

pwm: atmel-hlcdc: Convert to the atomic PWM API



Implement the ->apply() hook and drop the ->enable(), ->disable,
->set_polarity and ->config() ones.

Signed-off-by: default avatarBoris Brezillon <boris.brezillon@free-electrons.com>
Acked-by: default avatarNicolas Ferre <nicolas.ferre@microchip.com>
Signed-off-by: default avatarThierry Reding <thierry.reding@gmail.com>
parent c1ae3cfa
Loading
Loading
Loading
Loading
+101 −126
Original line number Original line Diff line number Diff line
@@ -49,14 +49,17 @@ static inline struct atmel_hlcdc_pwm *to_atmel_hlcdc_pwm(struct pwm_chip *chip)
	return container_of(chip, struct atmel_hlcdc_pwm, chip);
	return container_of(chip, struct atmel_hlcdc_pwm, chip);
}
}


static int atmel_hlcdc_pwm_config(struct pwm_chip *c,
static int atmel_hlcdc_pwm_apply(struct pwm_chip *c, struct pwm_device *pwm,
				  struct pwm_device *pwm,
				 struct pwm_state *state)
				  int duty_ns, int period_ns)
{
{
	struct atmel_hlcdc_pwm *chip = to_atmel_hlcdc_pwm(c);
	struct atmel_hlcdc_pwm *chip = to_atmel_hlcdc_pwm(c);
	struct atmel_hlcdc *hlcdc = chip->hlcdc;
	struct atmel_hlcdc *hlcdc = chip->hlcdc;
	unsigned int status;
	int ret;

	if (state->enabled) {
		struct clk *new_clk = hlcdc->slow_clk;
		struct clk *new_clk = hlcdc->slow_clk;
	u64 pwmcval = duty_ns * 256;
		u64 pwmcval = state->duty_cycle * 256;
		unsigned long clk_freq;
		unsigned long clk_freq;
		u64 clk_period_ns;
		u64 clk_period_ns;
		u32 pwmcfg;
		u32 pwmcfg;
@@ -73,7 +76,7 @@ static int atmel_hlcdc_pwm_config(struct pwm_chip *c,


		/* Errata: cannot use slow clk on some IP revisions */
		/* Errata: cannot use slow clk on some IP revisions */
		if ((chip->errata && chip->errata->slow_clk_erratum) ||
		if ((chip->errata && chip->errata->slow_clk_erratum) ||
	    clk_period_ns > period_ns) {
		    clk_period_ns > state->period) {
			new_clk = hlcdc->sys_clk;
			new_clk = hlcdc->sys_clk;
			clk_freq = clk_get_rate(new_clk);
			clk_freq = clk_get_rate(new_clk);
			if (!clk_freq)
			if (!clk_freq)
@@ -85,10 +88,11 @@ static int atmel_hlcdc_pwm_config(struct pwm_chip *c,


		for (pres = 0; pres <= ATMEL_HLCDC_PWMPS_MAX; pres++) {
		for (pres = 0; pres <= ATMEL_HLCDC_PWMPS_MAX; pres++) {
		/* Errata: cannot divide by 1 on some IP revisions */
		/* Errata: cannot divide by 1 on some IP revisions */
		if (!pres && chip->errata && chip->errata->div1_clk_erratum)
			if (!pres && chip->errata &&
			    chip->errata->div1_clk_erratum)
				continue;
				continue;


		if ((clk_period_ns << pres) >= period_ns)
			if ((clk_period_ns << pres) >= state->period)
				break;
				break;
		}
		}


@@ -111,18 +115,20 @@ static int atmel_hlcdc_pwm_config(struct pwm_chip *c,
			if (new_clk == hlcdc->sys_clk)
			if (new_clk == hlcdc->sys_clk)
				gencfg = ATMEL_HLCDC_CLKPWMSEL;
				gencfg = ATMEL_HLCDC_CLKPWMSEL;


		ret = regmap_update_bits(hlcdc->regmap, ATMEL_HLCDC_CFG(0),
			ret = regmap_update_bits(hlcdc->regmap,
					 ATMEL_HLCDC_CLKPWMSEL, gencfg);
						 ATMEL_HLCDC_CFG(0),
						 ATMEL_HLCDC_CLKPWMSEL,
						 gencfg);
			if (ret)
			if (ret)
				return ret;
				return ret;
		}
		}


	do_div(pwmcval, period_ns);
		do_div(pwmcval, state->period);


		/*
		/*
	 * The PWM duty cycle is configurable from 0/256 to 255/256 of the
		 * The PWM duty cycle is configurable from 0/256 to 255/256 of
	 * period cycle. Hence we can't set a duty cycle occupying the
		 * the period cycle. Hence we can't set a duty cycle occupying
	 * whole period cycle if we're asked to.
		 * the whole period cycle if we're asked to.
		 * Set it to 255 if pwmcval is greater than 256.
		 * Set it to 255 if pwmcval is greater than 256.
		 */
		 */
		if (pwmcval > 255)
		if (pwmcval > 255)
@@ -130,81 +136,50 @@ static int atmel_hlcdc_pwm_config(struct pwm_chip *c,


		pwmcfg |= ATMEL_HLCDC_PWMCVAL(pwmcval);
		pwmcfg |= ATMEL_HLCDC_PWMCVAL(pwmcval);


	return regmap_update_bits(hlcdc->regmap, ATMEL_HLCDC_CFG(6),
		if (state->polarity == PWM_POLARITY_NORMAL)
			pwmcfg |= ATMEL_HLCDC_PWMPOL;

		ret = regmap_update_bits(hlcdc->regmap, ATMEL_HLCDC_CFG(6),
					 ATMEL_HLCDC_PWMCVAL_MASK |
					 ATMEL_HLCDC_PWMCVAL_MASK |
				  ATMEL_HLCDC_PWMPS_MASK,
					 ATMEL_HLCDC_PWMPS_MASK |
					 ATMEL_HLCDC_PWMPOL,
					 pwmcfg);
					 pwmcfg);
}

static int atmel_hlcdc_pwm_set_polarity(struct pwm_chip *c,
					struct pwm_device *pwm,
					enum pwm_polarity polarity)
{
	struct atmel_hlcdc_pwm *chip = to_atmel_hlcdc_pwm(c);
	struct atmel_hlcdc *hlcdc = chip->hlcdc;
	u32 cfg = 0;

	if (polarity == PWM_POLARITY_NORMAL)
		cfg = ATMEL_HLCDC_PWMPOL;

	return regmap_update_bits(hlcdc->regmap, ATMEL_HLCDC_CFG(6),
				  ATMEL_HLCDC_PWMPOL, cfg);
}

static int atmel_hlcdc_pwm_enable(struct pwm_chip *c, struct pwm_device *pwm)
{
	struct atmel_hlcdc_pwm *chip = to_atmel_hlcdc_pwm(c);
	struct atmel_hlcdc *hlcdc = chip->hlcdc;
	u32 status;
	int ret;

	ret = regmap_write(hlcdc->regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_PWM);
		if (ret)
		if (ret)
			return ret;
			return ret;


	while (true) {
		ret = regmap_write(hlcdc->regmap, ATMEL_HLCDC_EN,
		ret = regmap_read(hlcdc->regmap, ATMEL_HLCDC_SR, &status);
				   ATMEL_HLCDC_PWM);
		if (ret)
		if (ret)
			return ret;
			return ret;


		if ((status & ATMEL_HLCDC_PWM) != 0)
		ret = regmap_read_poll_timeout(hlcdc->regmap, ATMEL_HLCDC_SR,
			break;
					       status,

					       status & ATMEL_HLCDC_PWM,
		usleep_range(1, 10);
					       10, 0);
	}

	return 0;
}

static void atmel_hlcdc_pwm_disable(struct pwm_chip *c,
				    struct pwm_device *pwm)
{
	struct atmel_hlcdc_pwm *chip = to_atmel_hlcdc_pwm(c);
	struct atmel_hlcdc *hlcdc = chip->hlcdc;
	u32 status;
	int ret;

	ret = regmap_write(hlcdc->regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_PWM);
		if (ret)
		if (ret)
		return;
			return ret;

	} else {
	while (true) {
		ret = regmap_write(hlcdc->regmap, ATMEL_HLCDC_DIS,
		ret = regmap_read(hlcdc->regmap, ATMEL_HLCDC_SR, &status);
				   ATMEL_HLCDC_PWM);
		if (ret)
		if (ret)
			return;
			return ret;


		if ((status & ATMEL_HLCDC_PWM) == 0)
		ret = regmap_read_poll_timeout(hlcdc->regmap, ATMEL_HLCDC_SR,
			break;
					       status,
					       !(status & ATMEL_HLCDC_PWM),
					       10, 0);
		if (ret)
			return ret;


		usleep_range(1, 10);
		clk_disable_unprepare(chip->cur_clk);
		chip->cur_clk = NULL;
	}
	}

	return 0;
}
}


static const struct pwm_ops atmel_hlcdc_pwm_ops = {
static const struct pwm_ops atmel_hlcdc_pwm_ops = {
	.config = atmel_hlcdc_pwm_config,
	.apply = atmel_hlcdc_pwm_apply,
	.set_polarity = atmel_hlcdc_pwm_set_polarity,
	.enable = atmel_hlcdc_pwm_enable,
	.disable = atmel_hlcdc_pwm_disable,
	.owner = THIS_MODULE,
	.owner = THIS_MODULE,
};
};