| .. | .. |
|---|
| 1 | 1 | // SPDX-License-Identifier: GPL-2.0 |
|---|
| 2 | | -#include <linux/clk.h> |
|---|
| 3 | | -#include <linux/clockchips.h> |
|---|
| 2 | +#include <linux/init.h> |
|---|
| 4 | 3 | #include <linux/clocksource.h> |
|---|
| 4 | +#include <linux/clockchips.h> |
|---|
| 5 | 5 | #include <linux/interrupt.h> |
|---|
| 6 | | -#include <linux/kernel.h> |
|---|
| 7 | | -#include <linux/mfd/syscon.h> |
|---|
| 6 | +#include <linux/irq.h> |
|---|
| 7 | + |
|---|
| 8 | +#include <linux/clk.h> |
|---|
| 9 | +#include <linux/delay.h> |
|---|
| 10 | +#include <linux/err.h> |
|---|
| 11 | +#include <linux/ioport.h> |
|---|
| 12 | +#include <linux/io.h> |
|---|
| 8 | 13 | #include <linux/of_address.h> |
|---|
| 9 | 14 | #include <linux/of_irq.h> |
|---|
| 10 | | -#include <linux/regmap.h> |
|---|
| 11 | 15 | #include <linux/sched_clock.h> |
|---|
| 16 | +#include <linux/syscore_ops.h> |
|---|
| 12 | 17 | #include <soc/at91/atmel_tcb.h> |
|---|
| 13 | 18 | |
|---|
| 14 | | -struct atmel_tcb_clksrc { |
|---|
| 15 | | - struct clocksource clksrc; |
|---|
| 16 | | - struct clock_event_device clkevt; |
|---|
| 17 | | - struct regmap *regmap; |
|---|
| 18 | | - void __iomem *base; |
|---|
| 19 | | - struct clk *clk[2]; |
|---|
| 20 | | - char name[20]; |
|---|
| 21 | | - int channels[2]; |
|---|
| 22 | | - int bits; |
|---|
| 23 | | - int irq; |
|---|
| 24 | | - struct { |
|---|
| 25 | | - u32 cmr; |
|---|
| 26 | | - u32 imr; |
|---|
| 27 | | - u32 rc; |
|---|
| 28 | | - bool clken; |
|---|
| 29 | | - } cache[2]; |
|---|
| 30 | | - u32 bmr_cache; |
|---|
| 31 | | - bool registered; |
|---|
| 32 | | - bool clk_enabled; |
|---|
| 33 | | -}; |
|---|
| 34 | | - |
|---|
| 35 | | -static struct atmel_tcb_clksrc tc, tce; |
|---|
| 36 | | - |
|---|
| 37 | | -static struct clk *tcb_clk_get(struct device_node *node, int channel) |
|---|
| 38 | | -{ |
|---|
| 39 | | - struct clk *clk; |
|---|
| 40 | | - char clk_name[] = "t0_clk"; |
|---|
| 41 | | - |
|---|
| 42 | | - clk_name[1] += channel; |
|---|
| 43 | | - clk = of_clk_get_by_name(node->parent, clk_name); |
|---|
| 44 | | - if (!IS_ERR(clk)) |
|---|
| 45 | | - return clk; |
|---|
| 46 | | - |
|---|
| 47 | | - return of_clk_get_by_name(node->parent, "t0_clk"); |
|---|
| 48 | | -} |
|---|
| 49 | 19 | |
|---|
| 50 | 20 | /* |
|---|
| 51 | | - * Clockevent device using its own channel |
|---|
| 52 | | - */ |
|---|
| 53 | | - |
|---|
| 54 | | -static void tc_clkevt2_clk_disable(struct clock_event_device *d) |
|---|
| 55 | | -{ |
|---|
| 56 | | - clk_disable(tce.clk[0]); |
|---|
| 57 | | - tce.clk_enabled = false; |
|---|
| 58 | | -} |
|---|
| 59 | | - |
|---|
| 60 | | -static void tc_clkevt2_clk_enable(struct clock_event_device *d) |
|---|
| 61 | | -{ |
|---|
| 62 | | - if (tce.clk_enabled) |
|---|
| 63 | | - return; |
|---|
| 64 | | - clk_enable(tce.clk[0]); |
|---|
| 65 | | - tce.clk_enabled = true; |
|---|
| 66 | | -} |
|---|
| 67 | | - |
|---|
| 68 | | -static int tc_clkevt2_stop(struct clock_event_device *d) |
|---|
| 69 | | -{ |
|---|
| 70 | | - writel(0xff, tce.base + ATMEL_TC_IDR(tce.channels[0])); |
|---|
| 71 | | - writel(ATMEL_TC_CCR_CLKDIS, tce.base + ATMEL_TC_CCR(tce.channels[0])); |
|---|
| 72 | | - |
|---|
| 73 | | - return 0; |
|---|
| 74 | | -} |
|---|
| 75 | | - |
|---|
| 76 | | -static int tc_clkevt2_shutdown(struct clock_event_device *d) |
|---|
| 77 | | -{ |
|---|
| 78 | | - tc_clkevt2_stop(d); |
|---|
| 79 | | - if (!clockevent_state_detached(d)) |
|---|
| 80 | | - tc_clkevt2_clk_disable(d); |
|---|
| 81 | | - |
|---|
| 82 | | - return 0; |
|---|
| 83 | | -} |
|---|
| 84 | | - |
|---|
| 85 | | -/* For now, we always use the 32K clock ... this optimizes for NO_HZ, |
|---|
| 86 | | - * because using one of the divided clocks would usually mean the |
|---|
| 87 | | - * tick rate can never be less than several dozen Hz (vs 0.5 Hz). |
|---|
| 21 | + * We're configured to use a specific TC block, one that's not hooked |
|---|
| 22 | + * up to external hardware, to provide a time solution: |
|---|
| 88 | 23 | * |
|---|
| 89 | | - * A divided clock could be good for high resolution timers, since |
|---|
| 90 | | - * 30.5 usec resolution can seem "low". |
|---|
| 24 | + * - Two channels combine to create a free-running 32 bit counter |
|---|
| 25 | + * with a base rate of 5+ MHz, packaged as a clocksource (with |
|---|
| 26 | + * resolution better than 200 nsec). |
|---|
| 27 | + * - Some chips support 32 bit counter. A single channel is used for |
|---|
| 28 | + * this 32 bit free-running counter. the second channel is not used. |
|---|
| 29 | + * |
|---|
| 30 | + * - The third channel may be used to provide a clockevent source, used in |
|---|
| 31 | + * either periodic or oneshot mode. For 16-bit counter its runs at 32 KiHZ, |
|---|
| 32 | + * and can handle delays of up to two seconds. For 32-bit counters, it runs at |
|---|
| 33 | + * the same rate as the clocksource |
|---|
| 34 | + * |
|---|
| 35 | + * REVISIT behavior during system suspend states... we should disable |
|---|
| 36 | + * all clocks and save the power. Easily done for clockevent devices, |
|---|
| 37 | + * but clocksources won't necessarily get the needed notifications. |
|---|
| 38 | + * For deeper system sleep states, this will be mandatory... |
|---|
| 91 | 39 | */ |
|---|
| 92 | | -static int tc_clkevt2_set_oneshot(struct clock_event_device *d) |
|---|
| 40 | + |
|---|
| 41 | +static void __iomem *tcaddr; |
|---|
| 42 | +static struct |
|---|
| 93 | 43 | { |
|---|
| 94 | | - if (clockevent_state_oneshot(d) || clockevent_state_periodic(d)) |
|---|
| 95 | | - tc_clkevt2_stop(d); |
|---|
| 44 | + u32 cmr; |
|---|
| 45 | + u32 imr; |
|---|
| 46 | + u32 rc; |
|---|
| 47 | + bool clken; |
|---|
| 48 | +} tcb_cache[3]; |
|---|
| 49 | +static u32 bmr_cache; |
|---|
| 96 | 50 | |
|---|
| 97 | | - tc_clkevt2_clk_enable(d); |
|---|
| 51 | +static const u8 atmel_tcb_divisors[] = { 2, 8, 32, 128 }; |
|---|
| 98 | 52 | |
|---|
| 99 | | - /* slow clock, count up to RC, then irq and stop */ |
|---|
| 100 | | - writel(ATMEL_TC_CMR_TCLK(4) | ATMEL_TC_CMR_CPCSTOP | |
|---|
| 101 | | - ATMEL_TC_CMR_WAVE | ATMEL_TC_CMR_WAVESEL_UPRC, |
|---|
| 102 | | - tce.base + ATMEL_TC_CMR(tce.channels[0])); |
|---|
| 103 | | - writel(ATMEL_TC_CPCS, tce.base + ATMEL_TC_IER(tce.channels[0])); |
|---|
| 104 | | - |
|---|
| 105 | | - return 0; |
|---|
| 106 | | -} |
|---|
| 107 | | - |
|---|
| 108 | | -static int tc_clkevt2_set_periodic(struct clock_event_device *d) |
|---|
| 109 | | -{ |
|---|
| 110 | | - if (clockevent_state_oneshot(d) || clockevent_state_periodic(d)) |
|---|
| 111 | | - tc_clkevt2_stop(d); |
|---|
| 112 | | - |
|---|
| 113 | | - /* By not making the gentime core emulate periodic mode on top |
|---|
| 114 | | - * of oneshot, we get lower overhead and improved accuracy. |
|---|
| 115 | | - */ |
|---|
| 116 | | - tc_clkevt2_clk_enable(d); |
|---|
| 117 | | - |
|---|
| 118 | | - /* slow clock, count up to RC, then irq and restart */ |
|---|
| 119 | | - writel(ATMEL_TC_CMR_TCLK(4) | ATMEL_TC_CMR_WAVE | |
|---|
| 120 | | - ATMEL_TC_CMR_WAVESEL_UPRC, |
|---|
| 121 | | - tce.base + ATMEL_TC_CMR(tce.channels[0])); |
|---|
| 122 | | - writel((32768 + HZ / 2) / HZ, tce.base + ATMEL_TC_RC(tce.channels[0])); |
|---|
| 123 | | - |
|---|
| 124 | | - /* Enable clock and interrupts on RC compare */ |
|---|
| 125 | | - writel(ATMEL_TC_CPCS, tce.base + ATMEL_TC_IER(tce.channels[0])); |
|---|
| 126 | | - writel(ATMEL_TC_CCR_CLKEN | ATMEL_TC_CCR_SWTRG, |
|---|
| 127 | | - tce.base + ATMEL_TC_CCR(tce.channels[0])); |
|---|
| 128 | | - |
|---|
| 129 | | - return 0; |
|---|
| 130 | | -} |
|---|
| 131 | | - |
|---|
| 132 | | -static int tc_clkevt2_next_event(unsigned long delta, |
|---|
| 133 | | - struct clock_event_device *d) |
|---|
| 134 | | -{ |
|---|
| 135 | | - writel(delta, tce.base + ATMEL_TC_RC(tce.channels[0])); |
|---|
| 136 | | - writel(ATMEL_TC_CCR_CLKEN | ATMEL_TC_CCR_SWTRG, |
|---|
| 137 | | - tce.base + ATMEL_TC_CCR(tce.channels[0])); |
|---|
| 138 | | - |
|---|
| 139 | | - return 0; |
|---|
| 140 | | -} |
|---|
| 141 | | - |
|---|
| 142 | | -static irqreturn_t tc_clkevt2_irq(int irq, void *handle) |
|---|
| 143 | | -{ |
|---|
| 144 | | - unsigned int sr; |
|---|
| 145 | | - |
|---|
| 146 | | - sr = readl(tce.base + ATMEL_TC_SR(tce.channels[0])); |
|---|
| 147 | | - if (sr & ATMEL_TC_CPCS) { |
|---|
| 148 | | - tce.clkevt.event_handler(&tce.clkevt); |
|---|
| 149 | | - return IRQ_HANDLED; |
|---|
| 150 | | - } |
|---|
| 151 | | - |
|---|
| 152 | | - return IRQ_NONE; |
|---|
| 153 | | -} |
|---|
| 154 | | - |
|---|
| 155 | | -static void tc_clkevt2_suspend(struct clock_event_device *d) |
|---|
| 156 | | -{ |
|---|
| 157 | | - tce.cache[0].cmr = readl(tce.base + ATMEL_TC_CMR(tce.channels[0])); |
|---|
| 158 | | - tce.cache[0].imr = readl(tce.base + ATMEL_TC_IMR(tce.channels[0])); |
|---|
| 159 | | - tce.cache[0].rc = readl(tce.base + ATMEL_TC_RC(tce.channels[0])); |
|---|
| 160 | | - tce.cache[0].clken = !!(readl(tce.base + ATMEL_TC_SR(tce.channels[0])) & |
|---|
| 161 | | - ATMEL_TC_CLKSTA); |
|---|
| 162 | | -} |
|---|
| 163 | | - |
|---|
| 164 | | -static void tc_clkevt2_resume(struct clock_event_device *d) |
|---|
| 165 | | -{ |
|---|
| 166 | | - /* Restore registers for the channel, RA and RB are not used */ |
|---|
| 167 | | - writel(tce.cache[0].cmr, tc.base + ATMEL_TC_CMR(tce.channels[0])); |
|---|
| 168 | | - writel(tce.cache[0].rc, tc.base + ATMEL_TC_RC(tce.channels[0])); |
|---|
| 169 | | - writel(0, tc.base + ATMEL_TC_RA(tce.channels[0])); |
|---|
| 170 | | - writel(0, tc.base + ATMEL_TC_RB(tce.channels[0])); |
|---|
| 171 | | - /* Disable all the interrupts */ |
|---|
| 172 | | - writel(0xff, tc.base + ATMEL_TC_IDR(tce.channels[0])); |
|---|
| 173 | | - /* Reenable interrupts that were enabled before suspending */ |
|---|
| 174 | | - writel(tce.cache[0].imr, tc.base + ATMEL_TC_IER(tce.channels[0])); |
|---|
| 175 | | - |
|---|
| 176 | | - /* Start the clock if it was used */ |
|---|
| 177 | | - if (tce.cache[0].clken) |
|---|
| 178 | | - writel(ATMEL_TC_CCR_CLKEN | ATMEL_TC_CCR_SWTRG, |
|---|
| 179 | | - tc.base + ATMEL_TC_CCR(tce.channels[0])); |
|---|
| 180 | | -} |
|---|
| 181 | | - |
|---|
| 182 | | -static int __init tc_clkevt_register(struct device_node *node, |
|---|
| 183 | | - struct regmap *regmap, void __iomem *base, |
|---|
| 184 | | - int channel, int irq, int bits) |
|---|
| 185 | | -{ |
|---|
| 186 | | - int ret; |
|---|
| 187 | | - struct clk *slow_clk; |
|---|
| 188 | | - |
|---|
| 189 | | - tce.regmap = regmap; |
|---|
| 190 | | - tce.base = base; |
|---|
| 191 | | - tce.channels[0] = channel; |
|---|
| 192 | | - tce.irq = irq; |
|---|
| 193 | | - |
|---|
| 194 | | - slow_clk = of_clk_get_by_name(node->parent, "slow_clk"); |
|---|
| 195 | | - if (IS_ERR(slow_clk)) |
|---|
| 196 | | - return PTR_ERR(slow_clk); |
|---|
| 197 | | - |
|---|
| 198 | | - ret = clk_prepare_enable(slow_clk); |
|---|
| 199 | | - if (ret) |
|---|
| 200 | | - return ret; |
|---|
| 201 | | - |
|---|
| 202 | | - tce.clk[0] = tcb_clk_get(node, tce.channels[0]); |
|---|
| 203 | | - if (IS_ERR(tce.clk[0])) { |
|---|
| 204 | | - ret = PTR_ERR(tce.clk[0]); |
|---|
| 205 | | - goto err_slow; |
|---|
| 206 | | - } |
|---|
| 207 | | - |
|---|
| 208 | | - snprintf(tce.name, sizeof(tce.name), "%s:%d", |
|---|
| 209 | | - kbasename(node->parent->full_name), channel); |
|---|
| 210 | | - tce.clkevt.cpumask = cpumask_of(0); |
|---|
| 211 | | - tce.clkevt.name = tce.name; |
|---|
| 212 | | - tce.clkevt.set_next_event = tc_clkevt2_next_event, |
|---|
| 213 | | - tce.clkevt.set_state_shutdown = tc_clkevt2_shutdown, |
|---|
| 214 | | - tce.clkevt.set_state_periodic = tc_clkevt2_set_periodic, |
|---|
| 215 | | - tce.clkevt.set_state_oneshot = tc_clkevt2_set_oneshot, |
|---|
| 216 | | - tce.clkevt.suspend = tc_clkevt2_suspend, |
|---|
| 217 | | - tce.clkevt.resume = tc_clkevt2_resume, |
|---|
| 218 | | - tce.clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; |
|---|
| 219 | | - tce.clkevt.rating = 140; |
|---|
| 220 | | - |
|---|
| 221 | | - /* try to enable clk to avoid future errors in mode change */ |
|---|
| 222 | | - ret = clk_prepare_enable(tce.clk[0]); |
|---|
| 223 | | - if (ret) |
|---|
| 224 | | - goto err_slow; |
|---|
| 225 | | - clk_disable(tce.clk[0]); |
|---|
| 226 | | - |
|---|
| 227 | | - clockevents_config_and_register(&tce.clkevt, 32768, 1, |
|---|
| 228 | | - CLOCKSOURCE_MASK(bits)); |
|---|
| 229 | | - |
|---|
| 230 | | - ret = request_irq(tce.irq, tc_clkevt2_irq, IRQF_TIMER | IRQF_SHARED, |
|---|
| 231 | | - tce.clkevt.name, &tce); |
|---|
| 232 | | - if (ret) |
|---|
| 233 | | - goto err_clk; |
|---|
| 234 | | - |
|---|
| 235 | | - tce.registered = true; |
|---|
| 236 | | - |
|---|
| 237 | | - return 0; |
|---|
| 238 | | - |
|---|
| 239 | | -err_clk: |
|---|
| 240 | | - clk_unprepare(tce.clk[0]); |
|---|
| 241 | | -err_slow: |
|---|
| 242 | | - clk_disable_unprepare(slow_clk); |
|---|
| 243 | | - |
|---|
| 244 | | - return ret; |
|---|
| 245 | | -} |
|---|
| 246 | | - |
|---|
| 247 | | -/* |
|---|
| 248 | | - * Clocksource and clockevent using the same channel(s) |
|---|
| 249 | | - */ |
|---|
| 250 | 53 | static u64 tc_get_cycles(struct clocksource *cs) |
|---|
| 251 | 54 | { |
|---|
| 252 | | - u32 lower, upper; |
|---|
| 55 | + unsigned long flags; |
|---|
| 56 | + u32 lower, upper; |
|---|
| 253 | 57 | |
|---|
| 58 | + raw_local_irq_save(flags); |
|---|
| 254 | 59 | do { |
|---|
| 255 | | - upper = readl_relaxed(tc.base + ATMEL_TC_CV(tc.channels[1])); |
|---|
| 256 | | - lower = readl_relaxed(tc.base + ATMEL_TC_CV(tc.channels[0])); |
|---|
| 257 | | - } while (upper != readl_relaxed(tc.base + ATMEL_TC_CV(tc.channels[1]))); |
|---|
| 60 | + upper = readl_relaxed(tcaddr + ATMEL_TC_REG(1, CV)); |
|---|
| 61 | + lower = readl_relaxed(tcaddr + ATMEL_TC_REG(0, CV)); |
|---|
| 62 | + } while (upper != readl_relaxed(tcaddr + ATMEL_TC_REG(1, CV))); |
|---|
| 258 | 63 | |
|---|
| 64 | + raw_local_irq_restore(flags); |
|---|
| 259 | 65 | return (upper << 16) | lower; |
|---|
| 260 | 66 | } |
|---|
| 261 | 67 | |
|---|
| 262 | 68 | static u64 tc_get_cycles32(struct clocksource *cs) |
|---|
| 263 | 69 | { |
|---|
| 264 | | - return readl_relaxed(tc.base + ATMEL_TC_CV(tc.channels[0])); |
|---|
| 265 | | -} |
|---|
| 266 | | - |
|---|
| 267 | | -static u64 notrace tc_sched_clock_read(void) |
|---|
| 268 | | -{ |
|---|
| 269 | | - return tc_get_cycles(&tc.clksrc); |
|---|
| 270 | | -} |
|---|
| 271 | | - |
|---|
| 272 | | -static u64 notrace tc_sched_clock_read32(void) |
|---|
| 273 | | -{ |
|---|
| 274 | | - return tc_get_cycles32(&tc.clksrc); |
|---|
| 275 | | -} |
|---|
| 276 | | - |
|---|
| 277 | | -static int tcb_clkevt_next_event(unsigned long delta, |
|---|
| 278 | | - struct clock_event_device *d) |
|---|
| 279 | | -{ |
|---|
| 280 | | - u32 old, next, cur; |
|---|
| 281 | | - |
|---|
| 282 | | - old = readl(tc.base + ATMEL_TC_CV(tc.channels[0])); |
|---|
| 283 | | - next = old + delta; |
|---|
| 284 | | - writel(next, tc.base + ATMEL_TC_RC(tc.channels[0])); |
|---|
| 285 | | - cur = readl(tc.base + ATMEL_TC_CV(tc.channels[0])); |
|---|
| 286 | | - |
|---|
| 287 | | - /* check whether the delta elapsed while setting the register */ |
|---|
| 288 | | - if ((next < old && cur < old && cur > next) || |
|---|
| 289 | | - (next > old && (cur < old || cur > next))) { |
|---|
| 290 | | - /* |
|---|
| 291 | | - * Clear the CPCS bit in the status register to avoid |
|---|
| 292 | | - * generating a spurious interrupt next time a valid |
|---|
| 293 | | - * timer event is configured. |
|---|
| 294 | | - */ |
|---|
| 295 | | - old = readl(tc.base + ATMEL_TC_SR(tc.channels[0])); |
|---|
| 296 | | - return -ETIME; |
|---|
| 297 | | - } |
|---|
| 298 | | - |
|---|
| 299 | | - writel(ATMEL_TC_CPCS, tc.base + ATMEL_TC_IER(tc.channels[0])); |
|---|
| 300 | | - |
|---|
| 301 | | - return 0; |
|---|
| 302 | | -} |
|---|
| 303 | | - |
|---|
| 304 | | -static irqreturn_t tc_clkevt_irq(int irq, void *handle) |
|---|
| 305 | | -{ |
|---|
| 306 | | - unsigned int sr; |
|---|
| 307 | | - |
|---|
| 308 | | - sr = readl(tc.base + ATMEL_TC_SR(tc.channels[0])); |
|---|
| 309 | | - if (sr & ATMEL_TC_CPCS) { |
|---|
| 310 | | - tc.clkevt.event_handler(&tc.clkevt); |
|---|
| 311 | | - return IRQ_HANDLED; |
|---|
| 312 | | - } |
|---|
| 313 | | - |
|---|
| 314 | | - return IRQ_NONE; |
|---|
| 315 | | -} |
|---|
| 316 | | - |
|---|
| 317 | | -static int tcb_clkevt_oneshot(struct clock_event_device *dev) |
|---|
| 318 | | -{ |
|---|
| 319 | | - if (clockevent_state_oneshot(dev)) |
|---|
| 320 | | - return 0; |
|---|
| 321 | | - |
|---|
| 322 | | - /* |
|---|
| 323 | | - * Because both clockevent devices may share the same IRQ, we don't want |
|---|
| 324 | | - * the less likely one to stay requested |
|---|
| 325 | | - */ |
|---|
| 326 | | - return request_irq(tc.irq, tc_clkevt_irq, IRQF_TIMER | IRQF_SHARED, |
|---|
| 327 | | - tc.name, &tc); |
|---|
| 328 | | -} |
|---|
| 329 | | - |
|---|
| 330 | | -static int tcb_clkevt_shutdown(struct clock_event_device *dev) |
|---|
| 331 | | -{ |
|---|
| 332 | | - writel(0xff, tc.base + ATMEL_TC_IDR(tc.channels[0])); |
|---|
| 333 | | - if (tc.bits == 16) |
|---|
| 334 | | - writel(0xff, tc.base + ATMEL_TC_IDR(tc.channels[1])); |
|---|
| 335 | | - |
|---|
| 336 | | - if (!clockevent_state_detached(dev)) |
|---|
| 337 | | - free_irq(tc.irq, &tc); |
|---|
| 338 | | - |
|---|
| 339 | | - return 0; |
|---|
| 340 | | -} |
|---|
| 341 | | - |
|---|
| 342 | | -static void __init tcb_setup_dual_chan(struct atmel_tcb_clksrc *tc, |
|---|
| 343 | | - int mck_divisor_idx) |
|---|
| 344 | | -{ |
|---|
| 345 | | - /* first channel: waveform mode, input mclk/8, clock TIOA on overflow */ |
|---|
| 346 | | - writel(mck_divisor_idx /* likely divide-by-8 */ |
|---|
| 347 | | - | ATMEL_TC_CMR_WAVE |
|---|
| 348 | | - | ATMEL_TC_CMR_WAVESEL_UP /* free-run */ |
|---|
| 349 | | - | ATMEL_TC_CMR_ACPA(SET) /* TIOA rises at 0 */ |
|---|
| 350 | | - | ATMEL_TC_CMR_ACPC(CLEAR), /* (duty cycle 50%) */ |
|---|
| 351 | | - tc->base + ATMEL_TC_CMR(tc->channels[0])); |
|---|
| 352 | | - writel(0x0000, tc->base + ATMEL_TC_RA(tc->channels[0])); |
|---|
| 353 | | - writel(0x8000, tc->base + ATMEL_TC_RC(tc->channels[0])); |
|---|
| 354 | | - writel(0xff, tc->base + ATMEL_TC_IDR(tc->channels[0])); /* no irqs */ |
|---|
| 355 | | - writel(ATMEL_TC_CCR_CLKEN, tc->base + ATMEL_TC_CCR(tc->channels[0])); |
|---|
| 356 | | - |
|---|
| 357 | | - /* second channel: waveform mode, input TIOA */ |
|---|
| 358 | | - writel(ATMEL_TC_CMR_XC(tc->channels[1]) /* input: TIOA */ |
|---|
| 359 | | - | ATMEL_TC_CMR_WAVE |
|---|
| 360 | | - | ATMEL_TC_CMR_WAVESEL_UP, /* free-run */ |
|---|
| 361 | | - tc->base + ATMEL_TC_CMR(tc->channels[1])); |
|---|
| 362 | | - writel(0xff, tc->base + ATMEL_TC_IDR(tc->channels[1])); /* no irqs */ |
|---|
| 363 | | - writel(ATMEL_TC_CCR_CLKEN, tc->base + ATMEL_TC_CCR(tc->channels[1])); |
|---|
| 364 | | - |
|---|
| 365 | | - /* chain both channel, we assume the previous channel */ |
|---|
| 366 | | - regmap_write(tc->regmap, ATMEL_TC_BMR, |
|---|
| 367 | | - ATMEL_TC_BMR_TCXC(1 + tc->channels[1], tc->channels[1])); |
|---|
| 368 | | - /* then reset all the timers */ |
|---|
| 369 | | - regmap_write(tc->regmap, ATMEL_TC_BCR, ATMEL_TC_BCR_SYNC); |
|---|
| 370 | | -} |
|---|
| 371 | | - |
|---|
| 372 | | -static void __init tcb_setup_single_chan(struct atmel_tcb_clksrc *tc, |
|---|
| 373 | | - int mck_divisor_idx) |
|---|
| 374 | | -{ |
|---|
| 375 | | - /* channel 0: waveform mode, input mclk/8 */ |
|---|
| 376 | | - writel(mck_divisor_idx /* likely divide-by-8 */ |
|---|
| 377 | | - | ATMEL_TC_CMR_WAVE |
|---|
| 378 | | - | ATMEL_TC_CMR_WAVESEL_UP, /* free-run */ |
|---|
| 379 | | - tc->base + ATMEL_TC_CMR(tc->channels[0])); |
|---|
| 380 | | - writel(0xff, tc->base + ATMEL_TC_IDR(tc->channels[0])); /* no irqs */ |
|---|
| 381 | | - writel(ATMEL_TC_CCR_CLKEN, tc->base + ATMEL_TC_CCR(tc->channels[0])); |
|---|
| 382 | | - |
|---|
| 383 | | - /* then reset all the timers */ |
|---|
| 384 | | - regmap_write(tc->regmap, ATMEL_TC_BCR, ATMEL_TC_BCR_SYNC); |
|---|
| 70 | + return readl_relaxed(tcaddr + ATMEL_TC_REG(0, CV)); |
|---|
| 385 | 71 | } |
|---|
| 386 | 72 | |
|---|
| 387 | 73 | static void tc_clksrc_suspend(struct clocksource *cs) |
|---|
| 388 | 74 | { |
|---|
| 389 | 75 | int i; |
|---|
| 390 | 76 | |
|---|
| 391 | | - for (i = 0; i < 1 + (tc.bits == 16); i++) { |
|---|
| 392 | | - tc.cache[i].cmr = readl(tc.base + ATMEL_TC_CMR(tc.channels[i])); |
|---|
| 393 | | - tc.cache[i].imr = readl(tc.base + ATMEL_TC_IMR(tc.channels[i])); |
|---|
| 394 | | - tc.cache[i].rc = readl(tc.base + ATMEL_TC_RC(tc.channels[i])); |
|---|
| 395 | | - tc.cache[i].clken = !!(readl(tc.base + |
|---|
| 396 | | - ATMEL_TC_SR(tc.channels[i])) & |
|---|
| 397 | | - ATMEL_TC_CLKSTA); |
|---|
| 77 | + for (i = 0; i < ARRAY_SIZE(tcb_cache); i++) { |
|---|
| 78 | + tcb_cache[i].cmr = readl(tcaddr + ATMEL_TC_REG(i, CMR)); |
|---|
| 79 | + tcb_cache[i].imr = readl(tcaddr + ATMEL_TC_REG(i, IMR)); |
|---|
| 80 | + tcb_cache[i].rc = readl(tcaddr + ATMEL_TC_REG(i, RC)); |
|---|
| 81 | + tcb_cache[i].clken = !!(readl(tcaddr + ATMEL_TC_REG(i, SR)) & |
|---|
| 82 | + ATMEL_TC_CLKSTA); |
|---|
| 398 | 83 | } |
|---|
| 399 | 84 | |
|---|
| 400 | | - if (tc.bits == 16) |
|---|
| 401 | | - regmap_read(tc.regmap, ATMEL_TC_BMR, &tc.bmr_cache); |
|---|
| 85 | + bmr_cache = readl(tcaddr + ATMEL_TC_BMR); |
|---|
| 402 | 86 | } |
|---|
| 403 | 87 | |
|---|
| 404 | 88 | static void tc_clksrc_resume(struct clocksource *cs) |
|---|
| 405 | 89 | { |
|---|
| 406 | 90 | int i; |
|---|
| 407 | 91 | |
|---|
| 408 | | - for (i = 0; i < 1 + (tc.bits == 16); i++) { |
|---|
| 92 | + for (i = 0; i < ARRAY_SIZE(tcb_cache); i++) { |
|---|
| 409 | 93 | /* Restore registers for the channel, RA and RB are not used */ |
|---|
| 410 | | - writel(tc.cache[i].cmr, tc.base + ATMEL_TC_CMR(tc.channels[i])); |
|---|
| 411 | | - writel(tc.cache[i].rc, tc.base + ATMEL_TC_RC(tc.channels[i])); |
|---|
| 412 | | - writel(0, tc.base + ATMEL_TC_RA(tc.channels[i])); |
|---|
| 413 | | - writel(0, tc.base + ATMEL_TC_RB(tc.channels[i])); |
|---|
| 94 | + writel(tcb_cache[i].cmr, tcaddr + ATMEL_TC_REG(i, CMR)); |
|---|
| 95 | + writel(tcb_cache[i].rc, tcaddr + ATMEL_TC_REG(i, RC)); |
|---|
| 96 | + writel(0, tcaddr + ATMEL_TC_REG(i, RA)); |
|---|
| 97 | + writel(0, tcaddr + ATMEL_TC_REG(i, RB)); |
|---|
| 414 | 98 | /* Disable all the interrupts */ |
|---|
| 415 | | - writel(0xff, tc.base + ATMEL_TC_IDR(tc.channels[i])); |
|---|
| 99 | + writel(0xff, tcaddr + ATMEL_TC_REG(i, IDR)); |
|---|
| 416 | 100 | /* Reenable interrupts that were enabled before suspending */ |
|---|
| 417 | | - writel(tc.cache[i].imr, tc.base + ATMEL_TC_IER(tc.channels[i])); |
|---|
| 418 | | - |
|---|
| 101 | + writel(tcb_cache[i].imr, tcaddr + ATMEL_TC_REG(i, IER)); |
|---|
| 419 | 102 | /* Start the clock if it was used */ |
|---|
| 420 | | - if (tc.cache[i].clken) |
|---|
| 421 | | - writel(ATMEL_TC_CCR_CLKEN, tc.base + |
|---|
| 422 | | - ATMEL_TC_CCR(tc.channels[i])); |
|---|
| 103 | + if (tcb_cache[i].clken) |
|---|
| 104 | + writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(i, CCR)); |
|---|
| 423 | 105 | } |
|---|
| 424 | 106 | |
|---|
| 425 | | - /* in case of dual channel, chain channels */ |
|---|
| 426 | | - if (tc.bits == 16) |
|---|
| 427 | | - regmap_write(tc.regmap, ATMEL_TC_BMR, tc.bmr_cache); |
|---|
| 107 | + /* Dual channel, chain channels */ |
|---|
| 108 | + writel(bmr_cache, tcaddr + ATMEL_TC_BMR); |
|---|
| 428 | 109 | /* Finally, trigger all the channels*/ |
|---|
| 429 | | - regmap_write(tc.regmap, ATMEL_TC_BCR, ATMEL_TC_BCR_SYNC); |
|---|
| 110 | + writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR); |
|---|
| 430 | 111 | } |
|---|
| 431 | 112 | |
|---|
| 432 | | -static int __init tcb_clksrc_register(struct device_node *node, |
|---|
| 433 | | - struct regmap *regmap, void __iomem *base, |
|---|
| 434 | | - int channel, int channel1, int irq, |
|---|
| 435 | | - int bits) |
|---|
| 113 | +static struct clocksource clksrc = { |
|---|
| 114 | + .rating = 200, |
|---|
| 115 | + .read = tc_get_cycles, |
|---|
| 116 | + .mask = CLOCKSOURCE_MASK(32), |
|---|
| 117 | + .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
|---|
| 118 | + .suspend = tc_clksrc_suspend, |
|---|
| 119 | + .resume = tc_clksrc_resume, |
|---|
| 120 | +}; |
|---|
| 121 | + |
|---|
| 122 | +static u64 notrace tc_sched_clock_read(void) |
|---|
| 436 | 123 | { |
|---|
| 124 | + return tc_get_cycles(&clksrc); |
|---|
| 125 | +} |
|---|
| 126 | + |
|---|
| 127 | +static u64 notrace tc_sched_clock_read32(void) |
|---|
| 128 | +{ |
|---|
| 129 | + return tc_get_cycles32(&clksrc); |
|---|
| 130 | +} |
|---|
| 131 | + |
|---|
| 132 | +static struct delay_timer tc_delay_timer; |
|---|
| 133 | + |
|---|
| 134 | +static unsigned long tc_delay_timer_read(void) |
|---|
| 135 | +{ |
|---|
| 136 | + return tc_get_cycles(&clksrc); |
|---|
| 137 | +} |
|---|
| 138 | + |
|---|
| 139 | +static unsigned long notrace tc_delay_timer_read32(void) |
|---|
| 140 | +{ |
|---|
| 141 | + return tc_get_cycles32(&clksrc); |
|---|
| 142 | +} |
|---|
| 143 | + |
|---|
| 144 | +#ifdef CONFIG_GENERIC_CLOCKEVENTS |
|---|
| 145 | + |
|---|
| 146 | +struct tc_clkevt_device { |
|---|
| 147 | + struct clock_event_device clkevt; |
|---|
| 148 | + struct clk *clk; |
|---|
| 149 | + u32 rate; |
|---|
| 150 | + void __iomem *regs; |
|---|
| 151 | +}; |
|---|
| 152 | + |
|---|
| 153 | +static struct tc_clkevt_device *to_tc_clkevt(struct clock_event_device *clkevt) |
|---|
| 154 | +{ |
|---|
| 155 | + return container_of(clkevt, struct tc_clkevt_device, clkevt); |
|---|
| 156 | +} |
|---|
| 157 | + |
|---|
| 158 | +static u32 timer_clock; |
|---|
| 159 | + |
|---|
| 160 | +static int tc_shutdown(struct clock_event_device *d) |
|---|
| 161 | +{ |
|---|
| 162 | + struct tc_clkevt_device *tcd = to_tc_clkevt(d); |
|---|
| 163 | + void __iomem *regs = tcd->regs; |
|---|
| 164 | + |
|---|
| 165 | + writel(0xff, regs + ATMEL_TC_REG(2, IDR)); |
|---|
| 166 | + writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR)); |
|---|
| 167 | + if (!clockevent_state_detached(d)) |
|---|
| 168 | + clk_disable(tcd->clk); |
|---|
| 169 | + |
|---|
| 170 | + return 0; |
|---|
| 171 | +} |
|---|
| 172 | + |
|---|
| 173 | +static int tc_set_oneshot(struct clock_event_device *d) |
|---|
| 174 | +{ |
|---|
| 175 | + struct tc_clkevt_device *tcd = to_tc_clkevt(d); |
|---|
| 176 | + void __iomem *regs = tcd->regs; |
|---|
| 177 | + |
|---|
| 178 | + if (clockevent_state_oneshot(d) || clockevent_state_periodic(d)) |
|---|
| 179 | + tc_shutdown(d); |
|---|
| 180 | + |
|---|
| 181 | + clk_enable(tcd->clk); |
|---|
| 182 | + |
|---|
| 183 | + /* count up to RC, then irq and stop */ |
|---|
| 184 | + writel(timer_clock | ATMEL_TC_CPCSTOP | ATMEL_TC_WAVE | |
|---|
| 185 | + ATMEL_TC_WAVESEL_UP_AUTO, regs + ATMEL_TC_REG(2, CMR)); |
|---|
| 186 | + writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER)); |
|---|
| 187 | + |
|---|
| 188 | + /* set_next_event() configures and starts the timer */ |
|---|
| 189 | + return 0; |
|---|
| 190 | +} |
|---|
| 191 | + |
|---|
| 192 | +static int tc_set_periodic(struct clock_event_device *d) |
|---|
| 193 | +{ |
|---|
| 194 | + struct tc_clkevt_device *tcd = to_tc_clkevt(d); |
|---|
| 195 | + void __iomem *regs = tcd->regs; |
|---|
| 196 | + |
|---|
| 197 | + if (clockevent_state_oneshot(d) || clockevent_state_periodic(d)) |
|---|
| 198 | + tc_shutdown(d); |
|---|
| 199 | + |
|---|
| 200 | + /* By not making the gentime core emulate periodic mode on top |
|---|
| 201 | + * of oneshot, we get lower overhead and improved accuracy. |
|---|
| 202 | + */ |
|---|
| 203 | + clk_enable(tcd->clk); |
|---|
| 204 | + |
|---|
| 205 | + /* count up to RC, then irq and restart */ |
|---|
| 206 | + writel(timer_clock | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO, |
|---|
| 207 | + regs + ATMEL_TC_REG(2, CMR)); |
|---|
| 208 | + writel((tcd->rate + HZ / 2) / HZ, tcaddr + ATMEL_TC_REG(2, RC)); |
|---|
| 209 | + |
|---|
| 210 | + /* Enable clock and interrupts on RC compare */ |
|---|
| 211 | + writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER)); |
|---|
| 212 | + |
|---|
| 213 | + /* go go gadget! */ |
|---|
| 214 | + writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, regs + |
|---|
| 215 | + ATMEL_TC_REG(2, CCR)); |
|---|
| 216 | + return 0; |
|---|
| 217 | +} |
|---|
| 218 | + |
|---|
| 219 | +static int tc_next_event(unsigned long delta, struct clock_event_device *d) |
|---|
| 220 | +{ |
|---|
| 221 | + writel_relaxed(delta, tcaddr + ATMEL_TC_REG(2, RC)); |
|---|
| 222 | + |
|---|
| 223 | + /* go go gadget! */ |
|---|
| 224 | + writel_relaxed(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, |
|---|
| 225 | + tcaddr + ATMEL_TC_REG(2, CCR)); |
|---|
| 226 | + return 0; |
|---|
| 227 | +} |
|---|
| 228 | + |
|---|
| 229 | +static struct tc_clkevt_device clkevt = { |
|---|
| 230 | + .clkevt = { |
|---|
| 231 | + .features = CLOCK_EVT_FEAT_PERIODIC | |
|---|
| 232 | + CLOCK_EVT_FEAT_ONESHOT, |
|---|
| 233 | + /* Should be lower than at91rm9200's system timer */ |
|---|
| 234 | + .rating = 125, |
|---|
| 235 | + .set_next_event = tc_next_event, |
|---|
| 236 | + .set_state_shutdown = tc_shutdown, |
|---|
| 237 | + .set_state_periodic = tc_set_periodic, |
|---|
| 238 | + .set_state_oneshot = tc_set_oneshot, |
|---|
| 239 | + }, |
|---|
| 240 | +}; |
|---|
| 241 | + |
|---|
| 242 | +static irqreturn_t ch2_irq(int irq, void *handle) |
|---|
| 243 | +{ |
|---|
| 244 | + struct tc_clkevt_device *dev = handle; |
|---|
| 245 | + unsigned int sr; |
|---|
| 246 | + |
|---|
| 247 | + sr = readl_relaxed(dev->regs + ATMEL_TC_REG(2, SR)); |
|---|
| 248 | + if (sr & ATMEL_TC_CPCS) { |
|---|
| 249 | + dev->clkevt.event_handler(&dev->clkevt); |
|---|
| 250 | + return IRQ_HANDLED; |
|---|
| 251 | + } |
|---|
| 252 | + |
|---|
| 253 | + return IRQ_NONE; |
|---|
| 254 | +} |
|---|
| 255 | + |
|---|
| 256 | +static int __init setup_clkevents(struct atmel_tc *tc, int divisor_idx) |
|---|
| 257 | +{ |
|---|
| 258 | + int ret; |
|---|
| 259 | + struct clk *t2_clk = tc->clk[2]; |
|---|
| 260 | + int irq = tc->irq[2]; |
|---|
| 261 | + int bits = tc->tcb_config->counter_width; |
|---|
| 262 | + |
|---|
| 263 | + /* try to enable t2 clk to avoid future errors in mode change */ |
|---|
| 264 | + ret = clk_prepare_enable(t2_clk); |
|---|
| 265 | + if (ret) |
|---|
| 266 | + return ret; |
|---|
| 267 | + |
|---|
| 268 | + clkevt.regs = tc->regs; |
|---|
| 269 | + clkevt.clk = t2_clk; |
|---|
| 270 | + |
|---|
| 271 | + if (bits == 32) { |
|---|
| 272 | + timer_clock = divisor_idx; |
|---|
| 273 | + clkevt.rate = clk_get_rate(t2_clk) / atmel_tcb_divisors[divisor_idx]; |
|---|
| 274 | + } else { |
|---|
| 275 | + ret = clk_prepare_enable(tc->slow_clk); |
|---|
| 276 | + if (ret) { |
|---|
| 277 | + clk_disable_unprepare(t2_clk); |
|---|
| 278 | + return ret; |
|---|
| 279 | + } |
|---|
| 280 | + |
|---|
| 281 | + clkevt.rate = clk_get_rate(tc->slow_clk); |
|---|
| 282 | + timer_clock = ATMEL_TC_TIMER_CLOCK5; |
|---|
| 283 | + } |
|---|
| 284 | + |
|---|
| 285 | + clk_disable(t2_clk); |
|---|
| 286 | + |
|---|
| 287 | + clkevt.clkevt.cpumask = cpumask_of(0); |
|---|
| 288 | + |
|---|
| 289 | + ret = request_irq(irq, ch2_irq, IRQF_TIMER, "tc_clkevt", &clkevt); |
|---|
| 290 | + if (ret) { |
|---|
| 291 | + clk_unprepare(t2_clk); |
|---|
| 292 | + if (bits != 32) |
|---|
| 293 | + clk_disable_unprepare(tc->slow_clk); |
|---|
| 294 | + return ret; |
|---|
| 295 | + } |
|---|
| 296 | + |
|---|
| 297 | + clockevents_config_and_register(&clkevt.clkevt, clkevt.rate, 1, BIT(bits) - 1); |
|---|
| 298 | + |
|---|
| 299 | + return ret; |
|---|
| 300 | +} |
|---|
| 301 | + |
|---|
| 302 | +#else /* !CONFIG_GENERIC_CLOCKEVENTS */ |
|---|
| 303 | + |
|---|
| 304 | +static int __init setup_clkevents(struct atmel_tc *tc, int divisor_idx) |
|---|
| 305 | +{ |
|---|
| 306 | + /* NOTHING */ |
|---|
| 307 | + return 0; |
|---|
| 308 | +} |
|---|
| 309 | + |
|---|
| 310 | +#endif |
|---|
| 311 | + |
|---|
| 312 | +static void __init tcb_setup_dual_chan(struct atmel_tc *tc, int mck_divisor_idx) |
|---|
| 313 | +{ |
|---|
| 314 | + /* channel 0: waveform mode, input mclk/8, clock TIOA0 on overflow */ |
|---|
| 315 | + writel(mck_divisor_idx /* likely divide-by-8 */ |
|---|
| 316 | + | ATMEL_TC_WAVE |
|---|
| 317 | + | ATMEL_TC_WAVESEL_UP /* free-run */ |
|---|
| 318 | + | ATMEL_TC_ACPA_SET /* TIOA0 rises at 0 */ |
|---|
| 319 | + | ATMEL_TC_ACPC_CLEAR, /* (duty cycle 50%) */ |
|---|
| 320 | + tcaddr + ATMEL_TC_REG(0, CMR)); |
|---|
| 321 | + writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA)); |
|---|
| 322 | + writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC)); |
|---|
| 323 | + writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR)); /* no irqs */ |
|---|
| 324 | + writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR)); |
|---|
| 325 | + |
|---|
| 326 | + /* channel 1: waveform mode, input TIOA0 */ |
|---|
| 327 | + writel(ATMEL_TC_XC1 /* input: TIOA0 */ |
|---|
| 328 | + | ATMEL_TC_WAVE |
|---|
| 329 | + | ATMEL_TC_WAVESEL_UP, /* free-run */ |
|---|
| 330 | + tcaddr + ATMEL_TC_REG(1, CMR)); |
|---|
| 331 | + writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR)); /* no irqs */ |
|---|
| 332 | + writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR)); |
|---|
| 333 | + |
|---|
| 334 | + /* chain channel 0 to channel 1*/ |
|---|
| 335 | + writel(ATMEL_TC_TC1XC1S_TIOA0, tcaddr + ATMEL_TC_BMR); |
|---|
| 336 | + /* then reset all the timers */ |
|---|
| 337 | + writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR); |
|---|
| 338 | +} |
|---|
| 339 | + |
|---|
| 340 | +static void __init tcb_setup_single_chan(struct atmel_tc *tc, int mck_divisor_idx) |
|---|
| 341 | +{ |
|---|
| 342 | + /* channel 0: waveform mode, input mclk/8 */ |
|---|
| 343 | + writel(mck_divisor_idx /* likely divide-by-8 */ |
|---|
| 344 | + | ATMEL_TC_WAVE |
|---|
| 345 | + | ATMEL_TC_WAVESEL_UP, /* free-run */ |
|---|
| 346 | + tcaddr + ATMEL_TC_REG(0, CMR)); |
|---|
| 347 | + writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR)); /* no irqs */ |
|---|
| 348 | + writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR)); |
|---|
| 349 | + |
|---|
| 350 | + /* then reset all the timers */ |
|---|
| 351 | + writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR); |
|---|
| 352 | +} |
|---|
| 353 | + |
|---|
| 354 | +static struct atmel_tcb_config tcb_rm9200_config = { |
|---|
| 355 | + .counter_width = 16, |
|---|
| 356 | +}; |
|---|
| 357 | + |
|---|
| 358 | +static struct atmel_tcb_config tcb_sam9x5_config = { |
|---|
| 359 | + .counter_width = 32, |
|---|
| 360 | +}; |
|---|
| 361 | + |
|---|
| 362 | +static struct atmel_tcb_config tcb_sama5d2_config = { |
|---|
| 363 | + .counter_width = 32, |
|---|
| 364 | + .has_gclk = 1, |
|---|
| 365 | +}; |
|---|
| 366 | + |
|---|
| 367 | +static const struct of_device_id atmel_tcb_of_match[] = { |
|---|
| 368 | + { .compatible = "atmel,at91rm9200-tcb", .data = &tcb_rm9200_config, }, |
|---|
| 369 | + { .compatible = "atmel,at91sam9x5-tcb", .data = &tcb_sam9x5_config, }, |
|---|
| 370 | + { .compatible = "atmel,sama5d2-tcb", .data = &tcb_sama5d2_config, }, |
|---|
| 371 | + { /* sentinel */ } |
|---|
| 372 | +}; |
|---|
| 373 | + |
|---|
| 374 | +static int __init tcb_clksrc_init(struct device_node *node) |
|---|
| 375 | +{ |
|---|
| 376 | + struct atmel_tc tc; |
|---|
| 377 | + struct clk *t0_clk; |
|---|
| 378 | + const struct of_device_id *match; |
|---|
| 379 | + u64 (*tc_sched_clock)(void); |
|---|
| 437 | 380 | u32 rate, divided_rate = 0; |
|---|
| 438 | 381 | int best_divisor_idx = -1; |
|---|
| 439 | | - int i, err = -1; |
|---|
| 440 | | - u64 (*tc_sched_clock)(void); |
|---|
| 382 | + int bits; |
|---|
| 383 | + int i; |
|---|
| 384 | + int ret; |
|---|
| 441 | 385 | |
|---|
| 442 | | - tc.regmap = regmap; |
|---|
| 443 | | - tc.base = base; |
|---|
| 444 | | - tc.channels[0] = channel; |
|---|
| 445 | | - tc.channels[1] = channel1; |
|---|
| 446 | | - tc.irq = irq; |
|---|
| 447 | | - tc.bits = bits; |
|---|
| 386 | + /* Protect against multiple calls */ |
|---|
| 387 | + if (tcaddr) |
|---|
| 388 | + return 0; |
|---|
| 448 | 389 | |
|---|
| 449 | | - tc.clk[0] = tcb_clk_get(node, tc.channels[0]); |
|---|
| 450 | | - if (IS_ERR(tc.clk[0])) |
|---|
| 451 | | - return PTR_ERR(tc.clk[0]); |
|---|
| 452 | | - err = clk_prepare_enable(tc.clk[0]); |
|---|
| 453 | | - if (err) { |
|---|
| 390 | + tc.regs = of_iomap(node->parent, 0); |
|---|
| 391 | + if (!tc.regs) |
|---|
| 392 | + return -ENXIO; |
|---|
| 393 | + |
|---|
| 394 | + t0_clk = of_clk_get_by_name(node->parent, "t0_clk"); |
|---|
| 395 | + if (IS_ERR(t0_clk)) |
|---|
| 396 | + return PTR_ERR(t0_clk); |
|---|
| 397 | + |
|---|
| 398 | + tc.slow_clk = of_clk_get_by_name(node->parent, "slow_clk"); |
|---|
| 399 | + if (IS_ERR(tc.slow_clk)) |
|---|
| 400 | + return PTR_ERR(tc.slow_clk); |
|---|
| 401 | + |
|---|
| 402 | + tc.clk[0] = t0_clk; |
|---|
| 403 | + tc.clk[1] = of_clk_get_by_name(node->parent, "t1_clk"); |
|---|
| 404 | + if (IS_ERR(tc.clk[1])) |
|---|
| 405 | + tc.clk[1] = t0_clk; |
|---|
| 406 | + tc.clk[2] = of_clk_get_by_name(node->parent, "t2_clk"); |
|---|
| 407 | + if (IS_ERR(tc.clk[2])) |
|---|
| 408 | + tc.clk[2] = t0_clk; |
|---|
| 409 | + |
|---|
| 410 | + tc.irq[2] = of_irq_get(node->parent, 2); |
|---|
| 411 | + if (tc.irq[2] <= 0) { |
|---|
| 412 | + tc.irq[2] = of_irq_get(node->parent, 0); |
|---|
| 413 | + if (tc.irq[2] <= 0) |
|---|
| 414 | + return -EINVAL; |
|---|
| 415 | + } |
|---|
| 416 | + |
|---|
| 417 | + match = of_match_node(atmel_tcb_of_match, node->parent); |
|---|
| 418 | + if (!match) |
|---|
| 419 | + return -ENODEV; |
|---|
| 420 | + |
|---|
| 421 | + tc.tcb_config = match->data; |
|---|
| 422 | + bits = tc.tcb_config->counter_width; |
|---|
| 423 | + |
|---|
| 424 | + for (i = 0; i < ARRAY_SIZE(tc.irq); i++) |
|---|
| 425 | + writel(ATMEL_TC_ALL_IRQ, tc.regs + ATMEL_TC_REG(i, IDR)); |
|---|
| 426 | + |
|---|
| 427 | + ret = clk_prepare_enable(t0_clk); |
|---|
| 428 | + if (ret) { |
|---|
| 454 | 429 | pr_debug("can't enable T0 clk\n"); |
|---|
| 455 | | - goto err_clk; |
|---|
| 430 | + return ret; |
|---|
| 456 | 431 | } |
|---|
| 457 | 432 | |
|---|
| 458 | 433 | /* How fast will we be counting? Pick something over 5 MHz. */ |
|---|
| 459 | | - rate = (u32)clk_get_rate(tc.clk[0]); |
|---|
| 460 | | - for (i = 0; i < 5; i++) { |
|---|
| 461 | | - unsigned int divisor = atmel_tc_divisors[i]; |
|---|
| 462 | | - unsigned int tmp; |
|---|
| 463 | | - |
|---|
| 464 | | - if (!divisor) |
|---|
| 465 | | - continue; |
|---|
| 434 | + rate = (u32) clk_get_rate(t0_clk); |
|---|
| 435 | + i = 0; |
|---|
| 436 | + if (tc.tcb_config->has_gclk) |
|---|
| 437 | + i = 1; |
|---|
| 438 | + for (; i < ARRAY_SIZE(atmel_tcb_divisors); i++) { |
|---|
| 439 | + unsigned divisor = atmel_tcb_divisors[i]; |
|---|
| 440 | + unsigned tmp; |
|---|
| 466 | 441 | |
|---|
| 467 | 442 | tmp = rate / divisor; |
|---|
| 468 | 443 | pr_debug("TC: %u / %-3u [%d] --> %u\n", rate, divisor, i, tmp); |
|---|
| 469 | | - if (best_divisor_idx > 0) { |
|---|
| 470 | | - if (tmp < 5 * 1000 * 1000) |
|---|
| 471 | | - continue; |
|---|
| 472 | | - } |
|---|
| 444 | + if ((best_divisor_idx >= 0) && (tmp < 5 * 1000 * 1000)) |
|---|
| 445 | + break; |
|---|
| 473 | 446 | divided_rate = tmp; |
|---|
| 474 | 447 | best_divisor_idx = i; |
|---|
| 475 | 448 | } |
|---|
| 476 | 449 | |
|---|
| 477 | | - if (tc.bits == 32) { |
|---|
| 478 | | - tc.clksrc.read = tc_get_cycles32; |
|---|
| 450 | + clksrc.name = kbasename(node->parent->full_name); |
|---|
| 451 | + clkevt.clkevt.name = kbasename(node->parent->full_name); |
|---|
| 452 | + pr_debug("%s at %d.%03d MHz\n", clksrc.name, divided_rate / 1000000, |
|---|
| 453 | + ((divided_rate % 1000000) + 500) / 1000); |
|---|
| 454 | + |
|---|
| 455 | + tcaddr = tc.regs; |
|---|
| 456 | + |
|---|
| 457 | + if (bits == 32) { |
|---|
| 458 | + /* use apropriate function to read 32 bit counter */ |
|---|
| 459 | + clksrc.read = tc_get_cycles32; |
|---|
| 460 | + /* setup ony channel 0 */ |
|---|
| 479 | 461 | tcb_setup_single_chan(&tc, best_divisor_idx); |
|---|
| 480 | 462 | tc_sched_clock = tc_sched_clock_read32; |
|---|
| 481 | | - snprintf(tc.name, sizeof(tc.name), "%s:%d", |
|---|
| 482 | | - kbasename(node->parent->full_name), tc.channels[0]); |
|---|
| 463 | + tc_delay_timer.read_current_timer = tc_delay_timer_read32; |
|---|
| 483 | 464 | } else { |
|---|
| 484 | | - tc.clk[1] = tcb_clk_get(node, tc.channels[1]); |
|---|
| 485 | | - if (IS_ERR(tc.clk[1])) |
|---|
| 486 | | - goto err_disable_t0; |
|---|
| 487 | | - |
|---|
| 488 | | - err = clk_prepare_enable(tc.clk[1]); |
|---|
| 489 | | - if (err) { |
|---|
| 465 | + /* we have three clocks no matter what the |
|---|
| 466 | + * underlying platform supports. |
|---|
| 467 | + */ |
|---|
| 468 | + ret = clk_prepare_enable(tc.clk[1]); |
|---|
| 469 | + if (ret) { |
|---|
| 490 | 470 | pr_debug("can't enable T1 clk\n"); |
|---|
| 491 | | - goto err_clk1; |
|---|
| 471 | + goto err_disable_t0; |
|---|
| 492 | 472 | } |
|---|
| 493 | | - tc.clksrc.read = tc_get_cycles, |
|---|
| 473 | + /* setup both channel 0 & 1 */ |
|---|
| 494 | 474 | tcb_setup_dual_chan(&tc, best_divisor_idx); |
|---|
| 495 | 475 | tc_sched_clock = tc_sched_clock_read; |
|---|
| 496 | | - snprintf(tc.name, sizeof(tc.name), "%s:%d,%d", |
|---|
| 497 | | - kbasename(node->parent->full_name), tc.channels[0], |
|---|
| 498 | | - tc.channels[1]); |
|---|
| 476 | + tc_delay_timer.read_current_timer = tc_delay_timer_read; |
|---|
| 499 | 477 | } |
|---|
| 500 | 478 | |
|---|
| 501 | | - pr_debug("%s at %d.%03d MHz\n", tc.name, |
|---|
| 502 | | - divided_rate / 1000000, |
|---|
| 503 | | - ((divided_rate + 500000) % 1000000) / 1000); |
|---|
| 504 | | - |
|---|
| 505 | | - tc.clksrc.name = tc.name; |
|---|
| 506 | | - tc.clksrc.suspend = tc_clksrc_suspend; |
|---|
| 507 | | - tc.clksrc.resume = tc_clksrc_resume; |
|---|
| 508 | | - tc.clksrc.rating = 200; |
|---|
| 509 | | - tc.clksrc.mask = CLOCKSOURCE_MASK(32); |
|---|
| 510 | | - tc.clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS; |
|---|
| 511 | | - |
|---|
| 512 | | - err = clocksource_register_hz(&tc.clksrc, divided_rate); |
|---|
| 513 | | - if (err) |
|---|
| 479 | + /* and away we go! */ |
|---|
| 480 | + ret = clocksource_register_hz(&clksrc, divided_rate); |
|---|
| 481 | + if (ret) |
|---|
| 514 | 482 | goto err_disable_t1; |
|---|
| 483 | + |
|---|
| 484 | + /* channel 2: periodic and oneshot timer support */ |
|---|
| 485 | + ret = setup_clkevents(&tc, best_divisor_idx); |
|---|
| 486 | + if (ret) |
|---|
| 487 | + goto err_unregister_clksrc; |
|---|
| 515 | 488 | |
|---|
| 516 | 489 | sched_clock_register(tc_sched_clock, 32, divided_rate); |
|---|
| 517 | 490 | |
|---|
| 518 | | - tc.registered = true; |
|---|
| 519 | | - |
|---|
| 520 | | - /* Set up and register clockevents */ |
|---|
| 521 | | - tc.clkevt.name = tc.name; |
|---|
| 522 | | - tc.clkevt.cpumask = cpumask_of(0); |
|---|
| 523 | | - tc.clkevt.set_next_event = tcb_clkevt_next_event; |
|---|
| 524 | | - tc.clkevt.set_state_oneshot = tcb_clkevt_oneshot; |
|---|
| 525 | | - tc.clkevt.set_state_shutdown = tcb_clkevt_shutdown; |
|---|
| 526 | | - tc.clkevt.features = CLOCK_EVT_FEAT_ONESHOT; |
|---|
| 527 | | - tc.clkevt.rating = 125; |
|---|
| 528 | | - |
|---|
| 529 | | - clockevents_config_and_register(&tc.clkevt, divided_rate, 1, |
|---|
| 530 | | - BIT(tc.bits) - 1); |
|---|
| 491 | + tc_delay_timer.freq = divided_rate; |
|---|
| 492 | + register_current_timer_delay(&tc_delay_timer); |
|---|
| 531 | 493 | |
|---|
| 532 | 494 | return 0; |
|---|
| 533 | 495 | |
|---|
| 496 | +err_unregister_clksrc: |
|---|
| 497 | + clocksource_unregister(&clksrc); |
|---|
| 498 | + |
|---|
| 534 | 499 | err_disable_t1: |
|---|
| 535 | | - if (tc.bits == 16) |
|---|
| 500 | + if (bits != 32) |
|---|
| 536 | 501 | clk_disable_unprepare(tc.clk[1]); |
|---|
| 537 | 502 | |
|---|
| 538 | | -err_clk1: |
|---|
| 539 | | - if (tc.bits == 16) |
|---|
| 540 | | - clk_put(tc.clk[1]); |
|---|
| 541 | | - |
|---|
| 542 | 503 | err_disable_t0: |
|---|
| 543 | | - clk_disable_unprepare(tc.clk[0]); |
|---|
| 504 | + clk_disable_unprepare(t0_clk); |
|---|
| 544 | 505 | |
|---|
| 545 | | -err_clk: |
|---|
| 546 | | - clk_put(tc.clk[0]); |
|---|
| 506 | + tcaddr = NULL; |
|---|
| 547 | 507 | |
|---|
| 548 | | - pr_err("%s: unable to register clocksource/clockevent\n", |
|---|
| 549 | | - tc.clksrc.name); |
|---|
| 550 | | - |
|---|
| 551 | | - return err; |
|---|
| 552 | | -} |
|---|
| 553 | | - |
|---|
| 554 | | -static int __init tcb_clksrc_init(struct device_node *node) |
|---|
| 555 | | -{ |
|---|
| 556 | | - const struct of_device_id *match; |
|---|
| 557 | | - struct regmap *regmap; |
|---|
| 558 | | - void __iomem *tcb_base; |
|---|
| 559 | | - u32 channel; |
|---|
| 560 | | - int irq, err, chan1 = -1; |
|---|
| 561 | | - unsigned bits; |
|---|
| 562 | | - |
|---|
| 563 | | - if (tc.registered && tce.registered) |
|---|
| 564 | | - return -ENODEV; |
|---|
| 565 | | - |
|---|
| 566 | | - /* |
|---|
| 567 | | - * The regmap has to be used to access registers that are shared |
|---|
| 568 | | - * between channels on the same TCB but we keep direct IO access for |
|---|
| 569 | | - * the counters to avoid the impact on performance |
|---|
| 570 | | - */ |
|---|
| 571 | | - regmap = syscon_node_to_regmap(node->parent); |
|---|
| 572 | | - if (IS_ERR(regmap)) |
|---|
| 573 | | - return PTR_ERR(regmap); |
|---|
| 574 | | - |
|---|
| 575 | | - tcb_base = of_iomap(node->parent, 0); |
|---|
| 576 | | - if (!tcb_base) { |
|---|
| 577 | | - pr_err("%s +%d %s\n", __FILE__, __LINE__, __func__); |
|---|
| 578 | | - return -ENXIO; |
|---|
| 579 | | - } |
|---|
| 580 | | - |
|---|
| 581 | | - match = of_match_node(atmel_tcb_dt_ids, node->parent); |
|---|
| 582 | | - bits = (uintptr_t)match->data; |
|---|
| 583 | | - |
|---|
| 584 | | - err = of_property_read_u32_index(node, "reg", 0, &channel); |
|---|
| 585 | | - if (err) |
|---|
| 586 | | - return err; |
|---|
| 587 | | - |
|---|
| 588 | | - irq = of_irq_get(node->parent, channel); |
|---|
| 589 | | - if (irq < 0) { |
|---|
| 590 | | - irq = of_irq_get(node->parent, 0); |
|---|
| 591 | | - if (irq < 0) |
|---|
| 592 | | - return irq; |
|---|
| 593 | | - } |
|---|
| 594 | | - |
|---|
| 595 | | - if (tc.registered) |
|---|
| 596 | | - return tc_clkevt_register(node, regmap, tcb_base, channel, irq, |
|---|
| 597 | | - bits); |
|---|
| 598 | | - |
|---|
| 599 | | - if (bits == 16) { |
|---|
| 600 | | - of_property_read_u32_index(node, "reg", 1, &chan1); |
|---|
| 601 | | - if (chan1 == -1) { |
|---|
| 602 | | - if (tce.registered) { |
|---|
| 603 | | - pr_err("%s: clocksource needs two channels\n", |
|---|
| 604 | | - node->parent->full_name); |
|---|
| 605 | | - return -EINVAL; |
|---|
| 606 | | - } else { |
|---|
| 607 | | - return tc_clkevt_register(node, regmap, |
|---|
| 608 | | - tcb_base, channel, |
|---|
| 609 | | - irq, bits); |
|---|
| 610 | | - } |
|---|
| 611 | | - } |
|---|
| 612 | | - } |
|---|
| 613 | | - |
|---|
| 614 | | - return tcb_clksrc_register(node, regmap, tcb_base, channel, chan1, irq, |
|---|
| 615 | | - bits); |
|---|
| 508 | + return ret; |
|---|
| 616 | 509 | } |
|---|
| 617 | 510 | TIMER_OF_DECLARE(atmel_tcb_clksrc, "atmel,tcb-timer", tcb_clksrc_init); |
|---|