layerscape: add linux 4.9 support
[oweals/openwrt.git] / target / linux / layerscape / patches-4.9 / 806-flextimer-support-layerscape.patch
1 From a5b3155b532289af793c26251cb087b4a24d5c15 Mon Sep 17 00:00:00 2001
2 From: Yangbo Lu <yangbo.lu@nxp.com>
3 Date: Mon, 25 Sep 2017 12:13:12 +0800
4 Subject: [PATCH] flextimer: support layerscape
5
6 This is a integrated patch for layerscape flextimer support.
7
8 Signed-off-by: Wang Dongsheng <dongsheng.wang@nxp.com>
9 Signed-off-by: Meng Yi <meng.yi@nxp.com>
10 Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
11 ---
12  drivers/clocksource/fsl_ftm_timer.c    |   8 +-
13  drivers/soc/fsl/layerscape/ftm_alarm.c | 286 +++++++++++++++++++++++++++++++++
14  2 files changed, 290 insertions(+), 4 deletions(-)
15  create mode 100644 drivers/soc/fsl/layerscape/ftm_alarm.c
16
17 diff --git a/drivers/clocksource/fsl_ftm_timer.c b/drivers/clocksource/fsl_ftm_timer.c
18 index 738515b8..770bbbca 100644
19 --- a/drivers/clocksource/fsl_ftm_timer.c
20 +++ b/drivers/clocksource/fsl_ftm_timer.c
21 @@ -83,11 +83,11 @@ static inline void ftm_counter_disable(void __iomem *base)
22  
23  static inline void ftm_irq_acknowledge(void __iomem *base)
24  {
25 -       u32 val;
26 +       unsigned int timeout = 100;
27  
28 -       val = ftm_readl(base + FTM_SC);
29 -       val &= ~FTM_SC_TOF;
30 -       ftm_writel(val, base + FTM_SC);
31 +       while ((FTM_SC_TOF & ftm_readl(base + FTM_SC)) && timeout--)
32 +               ftm_writel(ftm_readl(base + FTM_SC) & (~FTM_SC_TOF),
33 +                          base + FTM_SC);
34  }
35  
36  static inline void ftm_irq_enable(void __iomem *base)
37 diff --git a/drivers/soc/fsl/layerscape/ftm_alarm.c b/drivers/soc/fsl/layerscape/ftm_alarm.c
38 new file mode 100644
39 index 00000000..6f9882ff
40 --- /dev/null
41 +++ b/drivers/soc/fsl/layerscape/ftm_alarm.c
42 @@ -0,0 +1,286 @@
43 +/*
44 + * Freescale FlexTimer Module (FTM) Alarm driver.
45 + *
46 + * Copyright 2014 Freescale Semiconductor, Inc.
47 + *
48 + * This program is free software; you can redistribute it and/or
49 + * modify it under the terms of the GNU General Public License
50 + * as published by the Free Software Foundation; either version 2
51 + * of the License, or (at your option) any later version.
52 + */
53 +
54 +#include <linux/device.h>
55 +#include <linux/err.h>
56 +#include <linux/interrupt.h>
57 +#include <linux/io.h>
58 +#include <linux/of_address.h>
59 +#include <linux/of_irq.h>
60 +#include <linux/platform_device.h>
61 +
62 +#define FTM_SC                 0x00
63 +#define FTM_SC_CLK_SHIFT       3
64 +#define FTM_SC_CLK_MASK                (0x3 << FTM_SC_CLK_SHIFT)
65 +#define FTM_SC_CLK(c)          ((c) << FTM_SC_CLK_SHIFT)
66 +#define FTM_SC_PS_MASK         0x7
67 +#define FTM_SC_TOIE            BIT(6)
68 +#define FTM_SC_TOF             BIT(7)
69 +
70 +#define FTM_SC_CLKS_FIXED_FREQ 0x02
71 +
72 +#define FTM_CNT                        0x04
73 +#define FTM_MOD                        0x08
74 +#define FTM_CNTIN              0x4C
75 +
76 +#define FIXED_FREQ_CLK         32000
77 +#define MAX_FREQ_DIV           (1 << FTM_SC_PS_MASK)
78 +#define MAX_COUNT_VAL          0xffff
79 +
80 +static void __iomem *ftm1_base;
81 +static void __iomem *rcpm_ftm_addr;
82 +static u32 alarm_freq;
83 +static bool big_endian;
84 +
85 +static inline u32 ftm_readl(void __iomem *addr)
86 +{
87 +       if (big_endian)
88 +               return ioread32be(addr);
89 +
90 +       return ioread32(addr);
91 +}
92 +
93 +static inline void ftm_writel(u32 val, void __iomem *addr)
94 +{
95 +       if (big_endian)
96 +               iowrite32be(val, addr);
97 +       else
98 +               iowrite32(val, addr);
99 +}
100 +
101 +static inline void ftm_counter_enable(void __iomem *base)
102 +{
103 +       u32 val;
104 +
105 +       /* select and enable counter clock source */
106 +       val = ftm_readl(base + FTM_SC);
107 +       val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK);
108 +       val |= (FTM_SC_PS_MASK | FTM_SC_CLK(FTM_SC_CLKS_FIXED_FREQ));
109 +       ftm_writel(val, base + FTM_SC);
110 +}
111 +
112 +static inline void ftm_counter_disable(void __iomem *base)
113 +{
114 +       u32 val;
115 +
116 +       /* disable counter clock source */
117 +       val = ftm_readl(base + FTM_SC);
118 +       val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK);
119 +       ftm_writel(val, base + FTM_SC);
120 +}
121 +
122 +static inline void ftm_irq_acknowledge(void __iomem *base)
123 +{
124 +       unsigned int timeout = 100;
125 +
126 +       while ((FTM_SC_TOF & ftm_readl(base + FTM_SC)) && timeout--)
127 +               ftm_writel(ftm_readl(base + FTM_SC) & (~FTM_SC_TOF),
128 +                          base + FTM_SC);
129 +}
130 +
131 +static inline void ftm_irq_enable(void __iomem *base)
132 +{
133 +       u32 val;
134 +
135 +       val = ftm_readl(base + FTM_SC);
136 +       val |= FTM_SC_TOIE;
137 +       ftm_writel(val, base + FTM_SC);
138 +}
139 +
140 +static inline void ftm_irq_disable(void __iomem *base)
141 +{
142 +       u32 val;
143 +
144 +       val = ftm_readl(base + FTM_SC);
145 +       val &= ~FTM_SC_TOIE;
146 +       ftm_writel(val, base + FTM_SC);
147 +}
148 +
149 +static inline void ftm_reset_counter(void __iomem *base)
150 +{
151 +       /*
152 +        * The CNT register contains the FTM counter value.
153 +        * Reset clears the CNT register. Writing any value to COUNT
154 +        * updates the counter with its initial value, CNTIN.
155 +        */
156 +       ftm_writel(0x00, base + FTM_CNT);
157 +}
158 +
159 +static u32 time_to_cycle(unsigned long time)
160 +{
161 +       u32 cycle;
162 +
163 +       cycle = time * alarm_freq;
164 +       if (cycle > MAX_COUNT_VAL) {
165 +               pr_err("Out of alarm range.\n");
166 +               cycle = 0;
167 +       }
168 +
169 +       return cycle;
170 +}
171 +
172 +static u32 cycle_to_time(u32 cycle)
173 +{
174 +       return cycle / alarm_freq + 1;
175 +}
176 +
177 +static void ftm_clean_alarm(void)
178 +{
179 +       ftm_counter_disable(ftm1_base);
180 +
181 +       ftm_writel(0x00, ftm1_base + FTM_CNTIN);
182 +       ftm_writel(~0U, ftm1_base + FTM_MOD);
183 +
184 +       ftm_reset_counter(ftm1_base);
185 +}
186 +
187 +static int ftm_set_alarm(u64 cycle)
188 +{
189 +       ftm_irq_disable(ftm1_base);
190 +
191 +       /*
192 +        * The counter increments until the value of MOD is reached,
193 +        * at which point the counter is reloaded with the value of CNTIN.
194 +        * The TOF (the overflow flag) bit is set when the FTM counter
195 +        * changes from MOD to CNTIN. So we should using the cycle - 1.
196 +        */
197 +       ftm_writel(cycle - 1, ftm1_base + FTM_MOD);
198 +
199 +       ftm_counter_enable(ftm1_base);
200 +
201 +       ftm_irq_enable(ftm1_base);
202 +
203 +       return 0;
204 +}
205 +
206 +static irqreturn_t ftm_alarm_interrupt(int irq, void *dev_id)
207 +{
208 +       ftm_irq_acknowledge(ftm1_base);
209 +       ftm_irq_disable(ftm1_base);
210 +       ftm_clean_alarm();
211 +
212 +       return IRQ_HANDLED;
213 +}
214 +
215 +static ssize_t ftm_alarm_show(struct device *dev,
216 +                             struct device_attribute *attr,
217 +                             char *buf)
218 +{
219 +       u32 count, val;
220 +
221 +       count = ftm_readl(ftm1_base + FTM_MOD);
222 +       val = ftm_readl(ftm1_base + FTM_CNT);
223 +       val = (count & MAX_COUNT_VAL) - val;
224 +       val = cycle_to_time(val);
225 +
226 +       return sprintf(buf, "%u\n", val);
227 +}
228 +
229 +static ssize_t ftm_alarm_store(struct device *dev,
230 +                              struct device_attribute *attr,
231 +                              const char *buf, size_t count)
232 +{
233 +       u32 cycle;
234 +       unsigned long time;
235 +
236 +       if (kstrtoul(buf, 0, &time))
237 +               return -EINVAL;
238 +
239 +       ftm_clean_alarm();
240 +
241 +       cycle = time_to_cycle(time);
242 +       if (!cycle)
243 +               return -EINVAL;
244 +
245 +       ftm_set_alarm(cycle);
246 +
247 +       return count;
248 +}
249 +
250 +static struct device_attribute ftm_alarm_attributes = __ATTR(ftm_alarm, 0644,
251 +                       ftm_alarm_show, ftm_alarm_store);
252 +
253 +static int ftm_alarm_probe(struct platform_device *pdev)
254 +{
255 +       struct device_node *np = pdev->dev.of_node;
256 +       struct resource *r;
257 +       int irq;
258 +       int ret;
259 +       u32 ippdexpcr;
260 +
261 +       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
262 +       if (!r)
263 +               return -ENODEV;
264 +
265 +       ftm1_base = devm_ioremap_resource(&pdev->dev, r);
266 +       if (IS_ERR(ftm1_base))
267 +               return PTR_ERR(ftm1_base);
268 +
269 +       r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "FlexTimer1");
270 +       if (r) {
271 +               rcpm_ftm_addr = devm_ioremap_resource(&pdev->dev, r);
272 +               if (IS_ERR(rcpm_ftm_addr))
273 +                       return PTR_ERR(rcpm_ftm_addr);
274 +               ippdexpcr = ioread32be(rcpm_ftm_addr);
275 +               ippdexpcr |= 0x20000;
276 +               iowrite32be(ippdexpcr, rcpm_ftm_addr);
277 +       }
278 +
279 +       irq = irq_of_parse_and_map(np, 0);
280 +       if (irq <= 0) {
281 +               pr_err("ftm: unable to get IRQ from DT, %d\n", irq);
282 +               return -EINVAL;
283 +       }
284 +
285 +       big_endian = of_property_read_bool(np, "big-endian");
286 +
287 +       ret = devm_request_irq(&pdev->dev, irq, ftm_alarm_interrupt,
288 +                              IRQF_NO_SUSPEND, dev_name(&pdev->dev), NULL);
289 +       if (ret < 0) {
290 +               dev_err(&pdev->dev, "failed to request irq\n");
291 +               return ret;
292 +       }
293 +
294 +       ret = device_create_file(&pdev->dev, &ftm_alarm_attributes);
295 +       if (ret) {
296 +               dev_err(&pdev->dev, "create sysfs fail.\n");
297 +               return ret;
298 +       }
299 +
300 +       alarm_freq = (u32)FIXED_FREQ_CLK / (u32)MAX_FREQ_DIV;
301 +
302 +       ftm_clean_alarm();
303 +
304 +       device_init_wakeup(&pdev->dev, true);
305 +
306 +       return ret;
307 +}
308 +
309 +static const struct of_device_id ftm_alarm_match[] = {
310 +       { .compatible = "fsl,ftm-alarm", },
311 +       { .compatible = "fsl,ftm-timer", },
312 +       { },
313 +};
314 +
315 +static struct platform_driver ftm_alarm_driver = {
316 +       .probe          = ftm_alarm_probe,
317 +       .driver         = {
318 +               .name   = "ftm-alarm",
319 +               .owner  = THIS_MODULE,
320 +               .of_match_table = ftm_alarm_match,
321 +       },
322 +};
323 +
324 +static int __init ftm_alarm_init(void)
325 +{
326 +       return platform_driver_register(&ftm_alarm_driver);
327 +}
328 +device_initcall(ftm_alarm_init);
329 -- 
330 2.14.1
331