diff options
author | Alexandre Belloni <alexandre.belloni@bootlin.com> | 2020-10-30 19:36:57 +0100 |
---|---|---|
committer | Thierry Reding <thierry.reding@gmail.com> | 2020-12-17 14:18:55 +0100 |
commit | 34cbcd72588f40e58d7db5aa8c125068dd735765 (patch) | |
tree | ac9009955b703ca253eed6ec790b4acf36896416 /drivers/pwm | |
parent | 061f8572a31c0da6621aacfc70ed16e1a6d1d33b (diff) |
pwm: atmel-tcb: Add sama5d2 support
Add sama5d2 support. The sama5d2 has a new clock input, its gclk. Index 0
of the clock selector is the gclk instead of the peripheral clock divided
by 2.
For now, the gclk is not used because the peripheral clock divided by 8
already gives a 9.6ns resolution which is enough for most use cases.
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
Diffstat (limited to 'drivers/pwm')
-rw-r--r-- | drivers/pwm/pwm-atmel-tcb.c | 23 |
1 files changed, 20 insertions, 3 deletions
diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c index 82edb44fbbd8..5ccc3e7420e9 100644 --- a/drivers/pwm/pwm-atmel-tcb.c +++ b/drivers/pwm/pwm-atmel-tcb.c @@ -55,6 +55,7 @@ struct atmel_tcb_pwm_chip { u8 width; struct regmap *regmap; struct clk *clk; + struct clk *gclk; struct clk *slow_clk; struct atmel_tcb_pwm_device *pwms[NPWM]; struct atmel_tcb_channel bkup; @@ -292,7 +293,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip); struct atmel_tcb_pwm_device *tcbpwm = pwm_get_chip_data(pwm); struct atmel_tcb_pwm_device *atcbpwm = NULL; - int i; + int i = 0; int slowclk = 0; unsigned period; unsigned duty; @@ -303,8 +304,11 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, /* * Find best clk divisor: * the smallest divisor which can fulfill the period_ns requirements. + * If there is a gclk, the first divisor is actuallly the gclk selector */ - for (i = 0; i < ARRAY_SIZE(atmel_tcb_divisors); ++i) { + if (tcbpwmc->gclk) + i = 1; + for (; i < ARRAY_SIZE(atmel_tcb_divisors); ++i) { if (atmel_tcb_divisors[i] == 0) { slowclk = i; continue; @@ -383,9 +387,15 @@ static struct atmel_tcb_config tcb_sam9x5_config = { .counter_width = 32, }; +static struct atmel_tcb_config tcb_sama5d2_config = { + .counter_width = 32, + .has_gclk = 1, +}; + static const struct of_device_id atmel_tcb_of_match[] = { { .compatible = "atmel,at91rm9200-tcb", .data = &tcb_rm9200_config, }, { .compatible = "atmel,at91sam9x5-tcb", .data = &tcb_sam9x5_config, }, + { .compatible = "atmel,sama5d2-tcb", .data = &tcb_sama5d2_config, }, { /* sentinel */ } }; @@ -396,7 +406,7 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev) const struct atmel_tcb_config *config; struct device_node *np = pdev->dev.of_node; struct regmap *regmap; - struct clk *clk; + struct clk *clk, *gclk = NULL; struct clk *slow_clk; char clk_name[] = "t0_clk"; int err; @@ -428,6 +438,12 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev) match = of_match_node(atmel_tcb_of_match, np->parent); config = match->data; + if (config->has_gclk) { + gclk = of_clk_get_by_name(np->parent, "gclk"); + if (IS_ERR(gclk)) + return PTR_ERR(gclk); + } + tcbpwm = devm_kzalloc(&pdev->dev, sizeof(*tcbpwm), GFP_KERNEL); if (tcbpwm == NULL) { err = -ENOMEM; @@ -443,6 +459,7 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev) tcbpwm->channel = channel; tcbpwm->regmap = regmap; tcbpwm->clk = clk; + tcbpwm->gclk = gclk; tcbpwm->slow_clk = slow_clk; tcbpwm->width = config->counter_width; |