1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Freescale FlexTimer Module (FTM) timer driver. 4 * 5 * Copyright 2014 Freescale Semiconductor, Inc. 6 */ 7 8 #include <linux/clk.h> 9 #include <linux/clockchips.h> 10 #include <linux/clocksource.h> 11 #include <linux/err.h> 12 #include <linux/interrupt.h> 13 #include <linux/io.h> 14 #include <linux/of_address.h> 15 #include <linux/of_irq.h> 16 #include <linux/sched_clock.h> 17 #include <linux/slab.h> 18 #include <linux/fsl/ftm.h> 19 20 #define FTM_SC_CLK(c) ((c) << FTM_SC_CLK_MASK_SHIFT) 21 22 struct ftm_clock_device { 23 void __iomem *clksrc_base; 24 void __iomem *clkevt_base; 25 unsigned long periodic_cyc; 26 unsigned long ps; 27 bool big_endian; 28 }; 29 30 static struct ftm_clock_device *priv; 31 32 static inline u32 ftm_readl(void __iomem *addr) 33 { 34 if (priv->big_endian) 35 return ioread32be(addr); 36 else 37 return ioread32(addr); 38 } 39 40 static inline void ftm_writel(u32 val, void __iomem *addr) 41 { 42 if (priv->big_endian) 43 iowrite32be(val, addr); 44 else 45 iowrite32(val, addr); 46 } 47 48 static inline void ftm_counter_enable(void __iomem *base) 49 { 50 u32 val; 51 52 /* select and enable counter clock source */ 53 val = ftm_readl(base + FTM_SC); 54 val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK); 55 val |= priv->ps | FTM_SC_CLK(1); 56 ftm_writel(val, base + FTM_SC); 57 } 58 59 static inline void ftm_counter_disable(void __iomem *base) 60 { 61 u32 val; 62 63 /* disable counter clock source */ 64 val = ftm_readl(base + FTM_SC); 65 val &= ~(FTM_SC_PS_MASK | FTM_SC_CLK_MASK); 66 ftm_writel(val, base + FTM_SC); 67 } 68 69 static inline void ftm_irq_acknowledge(void __iomem *base) 70 { 71 u32 val; 72 73 val = ftm_readl(base + FTM_SC); 74 val &= ~FTM_SC_TOF; 75 ftm_writel(val, base + FTM_SC); 76 } 77 78 static inline void ftm_irq_enable(void __iomem *base) 79 { 80 u32 val; 81 82 val = ftm_readl(base + FTM_SC); 83 val |= FTM_SC_TOIE; 84 ftm_writel(val, base + FTM_SC); 85 } 86 87 static inline void ftm_irq_disable(void __iomem *base) 88 { 89 u32 val; 90 91 val = ftm_readl(base + FTM_SC); 92 val &= ~FTM_SC_TOIE; 93 ftm_writel(val, base + FTM_SC); 94 } 95 96 static inline void ftm_reset_counter(void __iomem *base) 97 { 98 /* 99 * The CNT register contains the FTM counter value. 100 * Reset clears the CNT register. Writing any value to COUNT 101 * updates the counter with its initial value, CNTIN. 102 */ 103 ftm_writel(0x00, base + FTM_CNT); 104 } 105 106 static u64 notrace ftm_read_sched_clock(void) 107 { 108 return ftm_readl(priv->clksrc_base + FTM_CNT); 109 } 110 111 static int ftm_set_next_event(unsigned long delta, 112 struct clock_event_device *unused) 113 { 114 /* 115 * The CNNIN and MOD are all double buffer registers, writing 116 * to the MOD register latches the value into a buffer. The MOD 117 * register is updated with the value of its write buffer with 118 * the following scenario: 119 * a, the counter source clock is diabled. 120 */ 121 ftm_counter_disable(priv->clkevt_base); 122 123 /* Force the value of CNTIN to be loaded into the FTM counter */ 124 ftm_reset_counter(priv->clkevt_base); 125 126 /* 127 * The counter increments until the value of MOD is reached, 128 * at which point the counter is reloaded with the value of CNTIN. 129 * The TOF (the overflow flag) bit is set when the FTM counter 130 * changes from MOD to CNTIN. So we should using the delta - 1. 131 */ 132 ftm_writel(delta - 1, priv->clkevt_base + FTM_MOD); 133 134 ftm_counter_enable(priv->clkevt_base); 135 136 ftm_irq_enable(priv->clkevt_base); 137 138 return 0; 139 } 140 141 static int ftm_set_oneshot(struct clock_event_device *evt) 142 { 143 ftm_counter_disable(priv->clkevt_base); 144 return 0; 145 } 146 147 static int ftm_set_periodic(struct clock_event_device *evt) 148 { 149 ftm_set_next_event(priv->periodic_cyc, evt); 150 return 0; 151 } 152 153 static irqreturn_t ftm_evt_interrupt(int irq, void *dev_id) 154 { 155 struct clock_event_device *evt = dev_id; 156 157 ftm_irq_acknowledge(priv->clkevt_base); 158 159 if (likely(clockevent_state_oneshot(evt))) { 160 ftm_irq_disable(priv->clkevt_base); 161 ftm_counter_disable(priv->clkevt_base); 162 } 163 164 evt->event_handler(evt); 165 166 return IRQ_HANDLED; 167 } 168 169 static struct clock_event_device ftm_clockevent = { 170 .name = "Freescale ftm timer", 171 .features = CLOCK_EVT_FEAT_PERIODIC | 172 CLOCK_EVT_FEAT_ONESHOT, 173 .set_state_periodic = ftm_set_periodic, 174 .set_state_oneshot = ftm_set_oneshot, 175 .set_next_event = ftm_set_next_event, 176 .rating = 300, 177 }; 178 179 static struct irqaction ftm_timer_irq = { 180 .name = "Freescale ftm timer", 181 .flags = IRQF_TIMER | IRQF_IRQPOLL, 182 .handler = ftm_evt_interrupt, 183 .dev_id = &ftm_clockevent, 184 }; 185 186 static int __init ftm_clockevent_init(unsigned long freq, int irq) 187 { 188 int err; 189 190 ftm_writel(0x00, priv->clkevt_base + FTM_CNTIN); 191 ftm_writel(~0u, priv->clkevt_base + FTM_MOD); 192 193 ftm_reset_counter(priv->clkevt_base); 194 195 err = setup_irq(irq, &ftm_timer_irq); 196 if (err) { 197 pr_err("ftm: setup irq failed: %d\n", err); 198 return err; 199 } 200 201 ftm_clockevent.cpumask = cpumask_of(0); 202 ftm_clockevent.irq = irq; 203 204 clockevents_config_and_register(&ftm_clockevent, 205 freq / (1 << priv->ps), 206 1, 0xffff); 207 208 ftm_counter_enable(priv->clkevt_base); 209 210 return 0; 211 } 212 213 static int __init ftm_clocksource_init(unsigned long freq) 214 { 215 int err; 216 217 ftm_writel(0x00, priv->clksrc_base + FTM_CNTIN); 218 ftm_writel(~0u, priv->clksrc_base + FTM_MOD); 219 220 ftm_reset_counter(priv->clksrc_base); 221 222 sched_clock_register(ftm_read_sched_clock, 16, freq / (1 << priv->ps)); 223 err = clocksource_mmio_init(priv->clksrc_base + FTM_CNT, "fsl-ftm", 224 freq / (1 << priv->ps), 300, 16, 225 clocksource_mmio_readl_up); 226 if (err) { 227 pr_err("ftm: init clock source mmio failed: %d\n", err); 228 return err; 229 } 230 231 ftm_counter_enable(priv->clksrc_base); 232 233 return 0; 234 } 235 236 static int __init __ftm_clk_init(struct device_node *np, char *cnt_name, 237 char *ftm_name) 238 { 239 struct clk *clk; 240 int err; 241 242 clk = of_clk_get_by_name(np, cnt_name); 243 if (IS_ERR(clk)) { 244 pr_err("ftm: Cannot get \"%s\": %ld\n", cnt_name, PTR_ERR(clk)); 245 return PTR_ERR(clk); 246 } 247 err = clk_prepare_enable(clk); 248 if (err) { 249 pr_err("ftm: clock failed to prepare+enable \"%s\": %d\n", 250 cnt_name, err); 251 return err; 252 } 253 254 clk = of_clk_get_by_name(np, ftm_name); 255 if (IS_ERR(clk)) { 256 pr_err("ftm: Cannot get \"%s\": %ld\n", ftm_name, PTR_ERR(clk)); 257 return PTR_ERR(clk); 258 } 259 err = clk_prepare_enable(clk); 260 if (err) 261 pr_err("ftm: clock failed to prepare+enable \"%s\": %d\n", 262 ftm_name, err); 263 264 return clk_get_rate(clk); 265 } 266 267 static unsigned long __init ftm_clk_init(struct device_node *np) 268 { 269 long freq; 270 271 freq = __ftm_clk_init(np, "ftm-evt-counter-en", "ftm-evt"); 272 if (freq <= 0) 273 return 0; 274 275 freq = __ftm_clk_init(np, "ftm-src-counter-en", "ftm-src"); 276 if (freq <= 0) 277 return 0; 278 279 return freq; 280 } 281 282 static int __init ftm_calc_closest_round_cyc(unsigned long freq) 283 { 284 priv->ps = 0; 285 286 /* The counter register is only using the lower 16 bits, and 287 * if the 'freq' value is to big here, then the periodic_cyc 288 * may exceed 0xFFFF. 289 */ 290 do { 291 priv->periodic_cyc = DIV_ROUND_CLOSEST(freq, 292 HZ * (1 << priv->ps++)); 293 } while (priv->periodic_cyc > 0xFFFF); 294 295 if (priv->ps > FTM_PS_MAX) { 296 pr_err("ftm: the prescaler is %lu > %d\n", 297 priv->ps, FTM_PS_MAX); 298 return -EINVAL; 299 } 300 301 return 0; 302 } 303 304 static int __init ftm_timer_init(struct device_node *np) 305 { 306 unsigned long freq; 307 int ret, irq; 308 309 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 310 if (!priv) 311 return -ENOMEM; 312 313 ret = -ENXIO; 314 priv->clkevt_base = of_iomap(np, 0); 315 if (!priv->clkevt_base) { 316 pr_err("ftm: unable to map event timer registers\n"); 317 goto err_clkevt; 318 } 319 320 priv->clksrc_base = of_iomap(np, 1); 321 if (!priv->clksrc_base) { 322 pr_err("ftm: unable to map source timer registers\n"); 323 goto err_clksrc; 324 } 325 326 ret = -EINVAL; 327 irq = irq_of_parse_and_map(np, 0); 328 if (irq <= 0) { 329 pr_err("ftm: unable to get IRQ from DT, %d\n", irq); 330 goto err; 331 } 332 333 priv->big_endian = of_property_read_bool(np, "big-endian"); 334 335 freq = ftm_clk_init(np); 336 if (!freq) 337 goto err; 338 339 ret = ftm_calc_closest_round_cyc(freq); 340 if (ret) 341 goto err; 342 343 ret = ftm_clocksource_init(freq); 344 if (ret) 345 goto err; 346 347 ret = ftm_clockevent_init(freq, irq); 348 if (ret) 349 goto err; 350 351 return 0; 352 353 err: 354 iounmap(priv->clksrc_base); 355 err_clksrc: 356 iounmap(priv->clkevt_base); 357 err_clkevt: 358 kfree(priv); 359 return ret; 360 } 361 TIMER_OF_DECLARE(flextimer, "fsl,ftm-timer", ftm_timer_init); 362