diff options
Diffstat (limited to 'drivers/pwm/pwm-atmel.c')
| -rw-r--r-- | drivers/pwm/pwm-atmel.c | 30 | 
1 files changed, 20 insertions, 10 deletions
| diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index 5813339b597b..29b5ad03f715 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -124,6 +124,7 @@ static inline void atmel_pwm_ch_writel(struct atmel_pwm_chip *chip,  }  static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip, +					     unsigned long clkrate,  					     const struct pwm_state *state,  					     unsigned long *cprd, u32 *pres)  { @@ -132,7 +133,7 @@ static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip,  	int shift;  	/* Calculate the period cycles and prescale value */ -	cycles *= clk_get_rate(atmel_pwm->clk); +	cycles *= clkrate;  	do_div(cycles, NSEC_PER_SEC);  	/* @@ -158,12 +159,14 @@ static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip,  }  static void atmel_pwm_calculate_cdty(const struct pwm_state *state, -				     unsigned long cprd, unsigned long *cdty) +				     unsigned long clkrate, unsigned long cprd, +				     u32 pres, unsigned long *cdty)  {  	unsigned long long cycles = state->duty_cycle; -	cycles *= cprd; -	do_div(cycles, state->period); +	cycles *= clkrate; +	do_div(cycles, NSEC_PER_SEC); +	cycles >>= pres;  	*cdty = cprd - cycles;  } @@ -244,17 +247,23 @@ static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,  	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); -			atmel_pwm_calculate_cdty(state, cprd, &cdty); +			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, state, &cprd, +		ret = atmel_pwm_calculate_cprd_and_pres(chip, clkrate, state, &cprd,  							&pres);  		if (ret) {  			dev_err(chip->dev, @@ -262,7 +271,7 @@ static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,  			return ret;  		} -		atmel_pwm_calculate_cdty(state, cprd, &cdty); +		atmel_pwm_calculate_cdty(state, clkrate, cprd, pres, &cdty);  		if (cstate.enabled) {  			atmel_pwm_disable(chip, pwm, false); @@ -319,7 +328,7 @@ static void atmel_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,  		cdty = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm,  					  atmel_pwm->data->regs.duty); -		tmp = (u64)cdty * NSEC_PER_SEC; +		tmp = (u64)(cprd - cdty) * NSEC_PER_SEC;  		tmp <<= pres;  		state->duty_cycle = DIV64_U64_ROUND_UP(tmp, rate); @@ -429,7 +438,6 @@ static int atmel_pwm_probe(struct platform_device *pdev)  	atmel_pwm->chip.ops = &atmel_pwm_ops;  	atmel_pwm->chip.of_xlate = of_pwm_xlate_with_flags;  	atmel_pwm->chip.of_pwm_n_cells = 3; -	atmel_pwm->chip.base = -1;  	atmel_pwm->chip.npwm = 4;  	ret = pwmchip_add(&atmel_pwm->chip); @@ -451,10 +459,12 @@ static int atmel_pwm_remove(struct platform_device *pdev)  {  	struct atmel_pwm_chip *atmel_pwm = platform_get_drvdata(pdev); +	pwmchip_remove(&atmel_pwm->chip); +  	clk_unprepare(atmel_pwm->clk);  	mutex_destroy(&atmel_pwm->isr_lock); -	return pwmchip_remove(&atmel_pwm->chip); +	return 0;  }  static struct platform_driver atmel_pwm_driver = { | 
