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