aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pwm/pwm-atmel-hlcdc.c
diff options
context:
space:
mode:
authorBoris BREZILLON <boris.brezillon@free-electrons.com>2014-11-19 09:33:09 -0500
committerThierry Reding <thierry.reding@gmail.com>2014-12-04 05:32:36 -0500
commit39e046f2c1dd0742976d7ee6e464744cf2122f41 (patch)
treecd2e044d7b76473eace7179f4b30d00890339776 /drivers/pwm/pwm-atmel-hlcdc.c
parent97d0b42e39a73c7e0683927ee4b3775c7411b7bf (diff)
pwm: atmel-hlcdc: add at91sam9x5 and sama5d3 errata handling
at91sam9x5 has an errata forbidding the use of slow clk as a clk source and sama5d3 SoCs has another errata forbidding the use of div1 prescaler. Take both of these erratas into account. Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com> Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
Diffstat (limited to 'drivers/pwm/pwm-atmel-hlcdc.c')
-rw-r--r--drivers/pwm/pwm-atmel-hlcdc.c50
1 files changed, 45 insertions, 5 deletions
diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c
index eaf8b12ce1e5..e7a785fadcdf 100644
--- a/drivers/pwm/pwm-atmel-hlcdc.c
+++ b/drivers/pwm/pwm-atmel-hlcdc.c
@@ -32,10 +32,16 @@
32#define ATMEL_HLCDC_PWMPS_MAX 0x6 32#define ATMEL_HLCDC_PWMPS_MAX 0x6
33#define ATMEL_HLCDC_PWMPS(x) ((x) & ATMEL_HLCDC_PWMPS_MASK) 33#define ATMEL_HLCDC_PWMPS(x) ((x) & ATMEL_HLCDC_PWMPS_MASK)
34 34
35struct atmel_hlcdc_pwm_errata {
36 bool slow_clk_erratum;
37 bool div1_clk_erratum;
38};
39
35struct atmel_hlcdc_pwm { 40struct atmel_hlcdc_pwm {
36 struct pwm_chip chip; 41 struct pwm_chip chip;
37 struct atmel_hlcdc *hlcdc; 42 struct atmel_hlcdc *hlcdc;
38 struct clk *cur_clk; 43 struct clk *cur_clk;
44 const struct atmel_hlcdc_pwm_errata *errata;
39}; 45};
40 46
41static inline struct atmel_hlcdc_pwm *to_atmel_hlcdc_pwm(struct pwm_chip *chip) 47static inline struct atmel_hlcdc_pwm *to_atmel_hlcdc_pwm(struct pwm_chip *chip)
@@ -56,20 +62,29 @@ static int atmel_hlcdc_pwm_config(struct pwm_chip *c,
56 u32 pwmcfg; 62 u32 pwmcfg;
57 int pres; 63 int pres;
58 64
59 clk_freq = clk_get_rate(new_clk); 65 if (!chip->errata || !chip->errata->slow_clk_erratum) {
60 clk_period_ns = (u64)NSEC_PER_SEC * 256; 66 clk_freq = clk_get_rate(new_clk);
61 do_div(clk_period_ns, clk_freq); 67 clk_period_ns = (u64)NSEC_PER_SEC * 256;
68 do_div(clk_period_ns, clk_freq);
69 }
62 70
63 if (clk_period_ns > period_ns) { 71 /* Errata: cannot use slow clk on some IP revisions */
72 if ((chip->errata && chip->errata->slow_clk_erratum) ||
73 clk_period_ns > period_ns) {
64 new_clk = hlcdc->sys_clk; 74 new_clk = hlcdc->sys_clk;
65 clk_freq = clk_get_rate(new_clk); 75 clk_freq = clk_get_rate(new_clk);
66 clk_period_ns = (u64)NSEC_PER_SEC * 256; 76 clk_period_ns = (u64)NSEC_PER_SEC * 256;
67 do_div(clk_period_ns, clk_freq); 77 do_div(clk_period_ns, clk_freq);
68 } 78 }
69 79
70 for (pres = 0; pres <= ATMEL_HLCDC_PWMPS_MAX; pres++) 80 for (pres = 0; pres <= ATMEL_HLCDC_PWMPS_MAX; pres++) {
81 /* Errata: cannot divide by 1 on some IP revisions */
82 if (!pres && chip->errata && chip->errata->div1_clk_erratum)
83 continue;
84
71 if ((clk_period_ns << pres) >= period_ns) 85 if ((clk_period_ns << pres) >= period_ns)
72 break; 86 break;
87 }
73 88
74 if (pres > ATMEL_HLCDC_PWMPS_MAX) 89 if (pres > ATMEL_HLCDC_PWMPS_MAX)
75 return -EINVAL; 90 return -EINVAL;
@@ -187,8 +202,29 @@ static const struct pwm_ops atmel_hlcdc_pwm_ops = {
187 .owner = THIS_MODULE, 202 .owner = THIS_MODULE,
188}; 203};
189 204
205static const struct atmel_hlcdc_pwm_errata atmel_hlcdc_pwm_at91sam9x5_errata = {
206 .slow_clk_erratum = true,
207};
208
209static const struct atmel_hlcdc_pwm_errata atmel_hlcdc_pwm_sama5d3_errata = {
210 .div1_clk_erratum = true,
211};
212
213static const struct of_device_id atmel_hlcdc_dt_ids[] = {
214 {
215 .compatible = "atmel,at91sam9x5-hlcdc",
216 .data = &atmel_hlcdc_pwm_at91sam9x5_errata,
217 },
218 {
219 .compatible = "atmel,sama5d3-hlcdc",
220 .data = &atmel_hlcdc_pwm_sama5d3_errata,
221 },
222 { /* sentinel */ },
223};
224
190static int atmel_hlcdc_pwm_probe(struct platform_device *pdev) 225static int atmel_hlcdc_pwm_probe(struct platform_device *pdev)
191{ 226{
227 const struct of_device_id *match;
192 struct device *dev = &pdev->dev; 228 struct device *dev = &pdev->dev;
193 struct atmel_hlcdc_pwm *chip; 229 struct atmel_hlcdc_pwm *chip;
194 struct atmel_hlcdc *hlcdc; 230 struct atmel_hlcdc *hlcdc;
@@ -204,6 +240,10 @@ static int atmel_hlcdc_pwm_probe(struct platform_device *pdev)
204 if (ret) 240 if (ret)
205 return ret; 241 return ret;
206 242
243 match = of_match_node(atmel_hlcdc_dt_ids, dev->parent->of_node);
244 if (match)
245 chip->errata = match->data;
246
207 chip->hlcdc = hlcdc; 247 chip->hlcdc = hlcdc;
208 chip->chip.ops = &atmel_hlcdc_pwm_ops; 248 chip->chip.ops = &atmel_hlcdc_pwm_ops;
209 chip->chip.dev = dev; 249 chip->chip.dev = dev;