summaryrefslogtreecommitdiffstats
path: root/drivers/pwm
diff options
context:
space:
mode:
authorUwe Kleine-König <uwe@kleine-koenig.org>2019-08-24 02:10:38 +0200
committerThierry Reding <thierry.reding@gmail.com>2020-01-08 13:43:39 +0100
commit2101c878f767fc6341ce0057e3b53d6129e76d99 (patch)
treec26d5ea2989b9d27f49bfab18b6db7b27836cd32 /drivers/pwm
parentpwm: atmel: Use a constant for maximum prescale value (diff)
downloadlinux-2101c878f767fc6341ce0057e3b53d6129e76d99.tar.xz
linux-2101c878f767fc6341ce0057e3b53d6129e76d99.zip
pwm: atmel: Replace loop in prescale calculation by ad-hoc calculation
The calculated values are the same with the modified algorithm. The only difference is that the calculation is a bit more efficient. Acked-by: Claudiu Beznea <claudiu.beznea@microchip.com> Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org> Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
Diffstat (limited to 'drivers/pwm')
-rw-r--r--drivers/pwm/pwm-atmel.c24
1 files changed, 17 insertions, 7 deletions
diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
index 199255b26aaa..c9fdf1671bb3 100644
--- a/drivers/pwm/pwm-atmel.c
+++ b/drivers/pwm/pwm-atmel.c
@@ -60,7 +60,7 @@ struct atmel_pwm_registers {
};
struct atmel_pwm_config {
- u32 max_period;
+ u32 period_bits;
};
struct atmel_pwm_data {
@@ -119,17 +119,27 @@ static int atmel_pwm_calculate_cprd_and_pres(struct pwm_chip *chip,
{
struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
unsigned long long cycles = state->period;
+ int shift;
/* Calculate the period cycles and prescale value */
cycles *= clk_get_rate(atmel_pwm->clk);
do_div(cycles, NSEC_PER_SEC);
- for (*pres = 0; cycles > atmel_pwm->data->cfg.max_period; cycles >>= 1)
- (*pres)++;
+ /*
+ * The register for the period length is cfg.period_bits bits wide.
+ * So for each bit the number of clock cycles is wider divide the input
+ * clock frequency by two using pres and shift cprd accordingly.
+ */
+ shift = fls(cycles) - atmel_pwm->data->cfg.period_bits;
- if (*pres > PWM_MAX_PRES) {
+ if (shift > PWM_MAX_PRES) {
dev_err(chip->dev, "pres exceeds the maximum value\n");
return -EINVAL;
+ } else if (shift > 0) {
+ *pres = shift;
+ cycles >>= *pres;
+ } else {
+ *pres = 0;
}
*cprd = cycles;
@@ -289,7 +299,7 @@ static const struct atmel_pwm_data atmel_sam9rl_pwm_data = {
},
.cfg = {
/* 16 bits to keep period and duty. */
- .max_period = 0xffff,
+ .period_bits = 16,
},
};
@@ -302,7 +312,7 @@ static const struct atmel_pwm_data atmel_sama5_pwm_data = {
},
.cfg = {
/* 16 bits to keep period and duty. */
- .max_period = 0xffff,
+ .period_bits = 16,
},
};
@@ -315,7 +325,7 @@ static const struct atmel_pwm_data mchp_sam9x60_pwm_data = {
},
.cfg = {
/* 32 bits to keep period and duty. */
- .max_period = 0xffffffff,
+ .period_bits = 32,
},
};