Blame view

drivers/clocksource/timer-atmel-st.c 6.19 KB
1a59d1b8e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
73a59c1c4   SAN People   [ARM] 3240/2: AT9...
2
  /*
9d0412680   Andrew Victor   [ARM] 4124/1: Ren...
3
   * linux/arch/arm/mach-at91/at91rm9200_time.c
73a59c1c4   SAN People   [ARM] 3240/2: AT9...
4
5
6
   *
   *  Copyright (C) 2003 SAN People
   *  Copyright (C) 2003 ATMEL
73a59c1c4   SAN People   [ARM] 3240/2: AT9...
7
   */
5e802dfab   David Brownell   [ARM] 4539/1: clo...
8
  #include <linux/kernel.h>
73a59c1c4   SAN People   [ARM] 3240/2: AT9...
9
  #include <linux/interrupt.h>
07d265dd5   Thomas Gleixner   [ARM] 3683/2: AR...
10
  #include <linux/irq.h>
216ab8f15   Alexandre Belloni   clocksource: atme...
11
  #include <linux/clk.h>
5e802dfab   David Brownell   [ARM] 4539/1: clo...
12
  #include <linux/clockchips.h>
9fce85c7e   Joachim Eastwood   ARM: at91: Export...
13
  #include <linux/export.h>
adf2edfd6   Alexandre Belloni   clocksource: atme...
14
15
  #include <linux/mfd/syscon.h>
  #include <linux/mfd/syscon/atmel-st.h>
454c46df8   Joachim Eastwood   ARM: AT91: Add DT...
16
  #include <linux/of_irq.h>
adf2edfd6   Alexandre Belloni   clocksource: atme...
17
  #include <linux/regmap.h>
73a59c1c4   SAN People   [ARM] 3240/2: AT9...
18

963151f24   Andrew Victor   [ARM] 3579/1: AT9...
19
  static unsigned long last_crtr;
5e802dfab   David Brownell   [ARM] 4539/1: clo...
20
21
  static u32 irqmask;
  static struct clock_event_device clkevt;
adf2edfd6   Alexandre Belloni   clocksource: atme...
22
  static struct regmap *regmap_st;
216ab8f15   Alexandre Belloni   clocksource: atme...
23
  static int timer_latch;
2f5893cf4   Jean-Christophe PLAGNIOL-VILLARD   ARM: at91: define...
24

73a59c1c4   SAN People   [ARM] 3240/2: AT9...
25
  /*
5e802dfab   David Brownell   [ARM] 4539/1: clo...
26
27
28
   * The ST_CRTR is updated asynchronously to the master clock ... but
   * the updates as seen by the CPU don't seem to be strictly monotonic.
   * Waiting until we read the same value twice avoids glitching.
73a59c1c4   SAN People   [ARM] 3240/2: AT9...
29
   */
5e802dfab   David Brownell   [ARM] 4539/1: clo...
30
31
  static inline unsigned long read_CRTR(void)
  {
adf2edfd6   Alexandre Belloni   clocksource: atme...
32
  	unsigned int x1, x2;
73a59c1c4   SAN People   [ARM] 3240/2: AT9...
33

adf2edfd6   Alexandre Belloni   clocksource: atme...
34
  	regmap_read(regmap_st, AT91_ST_CRTR, &x1);
73a59c1c4   SAN People   [ARM] 3240/2: AT9...
35
  	do {
adf2edfd6   Alexandre Belloni   clocksource: atme...
36
  		regmap_read(regmap_st, AT91_ST_CRTR, &x2);
5e802dfab   David Brownell   [ARM] 4539/1: clo...
37
38
39
40
  		if (x1 == x2)
  			break;
  		x1 = x2;
  	} while (1);
73a59c1c4   SAN People   [ARM] 3240/2: AT9...
41
42
43
44
  	return x1;
  }
  
  /*
73a59c1c4   SAN People   [ARM] 3240/2: AT9...
45
46
   * IRQ handler for the timer.
   */
0cd61b68c   Linus Torvalds   Initial blind fix...
47
  static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id)
73a59c1c4   SAN People   [ARM] 3240/2: AT9...
48
  {
adf2edfd6   Alexandre Belloni   clocksource: atme...
49
50
51
52
  	u32 sr;
  
  	regmap_read(regmap_st, AT91_ST_SR, &sr);
  	sr &= irqmask;
73a59c1c4   SAN People   [ARM] 3240/2: AT9...
53

501d70383   Uwe Kleine-König   arm/at91: Don't d...
54
55
56
57
58
  	/*
  	 * irqs should be disabled here, but as the irq is shared they are only
  	 * guaranteed to be off if the timer irq is registered first.
  	 */
  	WARN_ON_ONCE(!irqs_disabled());
5e802dfab   David Brownell   [ARM] 4539/1: clo...
59
60
61
62
63
  	/* simulate "oneshot" timer with alarm */
  	if (sr & AT91_ST_ALMS) {
  		clkevt.event_handler(&clkevt);
  		return IRQ_HANDLED;
  	}
73a59c1c4   SAN People   [ARM] 3240/2: AT9...
64

5e802dfab   David Brownell   [ARM] 4539/1: clo...
65
66
67
  	/* periodic mode should handle delayed ticks */
  	if (sr & AT91_ST_PITS) {
  		u32	crtr = read_CRTR();
73a59c1c4   SAN People   [ARM] 3240/2: AT9...
68

216ab8f15   Alexandre Belloni   clocksource: atme...
69
70
  		while (((crtr - last_crtr) & AT91_ST_CRTV) >= timer_latch) {
  			last_crtr += timer_latch;
5e802dfab   David Brownell   [ARM] 4539/1: clo...
71
72
  			clkevt.event_handler(&clkevt);
  		}
73a59c1c4   SAN People   [ARM] 3240/2: AT9...
73
74
  		return IRQ_HANDLED;
  	}
5e802dfab   David Brownell   [ARM] 4539/1: clo...
75
76
77
  
  	/* this irq is shared ... */
  	return IRQ_NONE;
73a59c1c4   SAN People   [ARM] 3240/2: AT9...
78
  }
a5a1d1c29   Thomas Gleixner   clocksource: Use ...
79
  static u64 read_clk32k(struct clocksource *cs)
2a6f9902c   Andrew Victor   [ARM] 3580/1: AT9...
80
  {
5e802dfab   David Brownell   [ARM] 4539/1: clo...
81
82
  	return read_CRTR();
  }
2a6f9902c   Andrew Victor   [ARM] 3580/1: AT9...
83

5e802dfab   David Brownell   [ARM] 4539/1: clo...
84
85
86
87
88
  static struct clocksource clk32k = {
  	.name		= "32k_counter",
  	.rating		= 150,
  	.read		= read_clk32k,
  	.mask		= CLOCKSOURCE_MASK(20),
5e802dfab   David Brownell   [ARM] 4539/1: clo...
89
90
  	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
  };
8ab282305   Viresh Kumar   clockevents/drive...
91
  static void clkdev32k_disable_and_flush_irq(void)
5e802dfab   David Brownell   [ARM] 4539/1: clo...
92
  {
adf2edfd6   Alexandre Belloni   clocksource: atme...
93
  	unsigned int val;
5e802dfab   David Brownell   [ARM] 4539/1: clo...
94
  	/* Disable and flush pending timer interrupts */
adf2edfd6   Alexandre Belloni   clocksource: atme...
95
96
  	regmap_write(regmap_st, AT91_ST_IDR, AT91_ST_PITS | AT91_ST_ALMS);
  	regmap_read(regmap_st, AT91_ST_SR, &val);
5e802dfab   David Brownell   [ARM] 4539/1: clo...
97
  	last_crtr = read_CRTR();
8ab282305   Viresh Kumar   clockevents/drive...
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
  }
  
  static int clkevt32k_shutdown(struct clock_event_device *evt)
  {
  	clkdev32k_disable_and_flush_irq();
  	irqmask = 0;
  	regmap_write(regmap_st, AT91_ST_IER, irqmask);
  	return 0;
  }
  
  static int clkevt32k_set_oneshot(struct clock_event_device *dev)
  {
  	clkdev32k_disable_and_flush_irq();
  
  	/*
  	 * ALM for oneshot irqs, set by next_event()
  	 * before 32 seconds have passed.
  	 */
  	irqmask = AT91_ST_ALMS;
  	regmap_write(regmap_st, AT91_ST_RTAR, last_crtr);
adf2edfd6   Alexandre Belloni   clocksource: atme...
118
  	regmap_write(regmap_st, AT91_ST_IER, irqmask);
8ab282305   Viresh Kumar   clockevents/drive...
119
120
121
122
123
124
125
126
127
  	return 0;
  }
  
  static int clkevt32k_set_periodic(struct clock_event_device *dev)
  {
  	clkdev32k_disable_and_flush_irq();
  
  	/* PIT for periodic irqs; fixed rate of 1/HZ */
  	irqmask = AT91_ST_PITS;
216ab8f15   Alexandre Belloni   clocksource: atme...
128
  	regmap_write(regmap_st, AT91_ST_PIMR, timer_latch);
8ab282305   Viresh Kumar   clockevents/drive...
129
130
  	regmap_write(regmap_st, AT91_ST_IER, irqmask);
  	return 0;
5e802dfab   David Brownell   [ARM] 4539/1: clo...
131
  }
2a6f9902c   Andrew Victor   [ARM] 3580/1: AT9...
132

5e802dfab   David Brownell   [ARM] 4539/1: clo...
133
134
135
  static int
  clkevt32k_next_event(unsigned long delta, struct clock_event_device *dev)
  {
5e802dfab   David Brownell   [ARM] 4539/1: clo...
136
137
  	u32		alm;
  	int		status = 0;
adf2edfd6   Alexandre Belloni   clocksource: atme...
138
  	unsigned int	val;
5e802dfab   David Brownell   [ARM] 4539/1: clo...
139
140
  
  	BUG_ON(delta < 2);
5e802dfab   David Brownell   [ARM] 4539/1: clo...
141
142
143
144
145
146
147
148
149
150
151
152
  	/* The alarm IRQ uses absolute time (now+delta), not the relative
  	 * time (delta) in our calling convention.  Like all clockevents
  	 * using such "match" hardware, we have a race to defend against.
  	 *
  	 * Our defense here is to have set up the clockevent device so the
  	 * delta is at least two.  That way we never end up writing RTAR
  	 * with the value then held in CRTR ... which would mean the match
  	 * wouldn't trigger until 32 seconds later, after CRTR wraps.
  	 */
  	alm = read_CRTR();
  
  	/* Cancel any pending alarm; flush any pending IRQ */
adf2edfd6   Alexandre Belloni   clocksource: atme...
153
154
  	regmap_write(regmap_st, AT91_ST_RTAR, alm);
  	regmap_read(regmap_st, AT91_ST_SR, &val);
d100f2595   Andrew Victor   [ARM] 3955/1: AT9...
155

5e802dfab   David Brownell   [ARM] 4539/1: clo...
156
157
  	/* Schedule alarm by writing RTAR. */
  	alm += delta;
adf2edfd6   Alexandre Belloni   clocksource: atme...
158
  	regmap_write(regmap_st, AT91_ST_RTAR, alm);
5e802dfab   David Brownell   [ARM] 4539/1: clo...
159

5e802dfab   David Brownell   [ARM] 4539/1: clo...
160
  	return status;
2a6f9902c   Andrew Victor   [ARM] 3580/1: AT9...
161
  }
5e802dfab   David Brownell   [ARM] 4539/1: clo...
162
  static struct clock_event_device clkevt = {
8ab282305   Viresh Kumar   clockevents/drive...
163
164
165
166
167
168
169
170
171
  	.name			= "at91_tick",
  	.features		= CLOCK_EVT_FEAT_PERIODIC |
  				  CLOCK_EVT_FEAT_ONESHOT,
  	.rating			= 150,
  	.set_next_event		= clkevt32k_next_event,
  	.set_state_shutdown	= clkevt32k_shutdown,
  	.set_state_periodic	= clkevt32k_set_periodic,
  	.set_state_oneshot	= clkevt32k_set_oneshot,
  	.tick_resume		= clkevt32k_shutdown,
5e802dfab   David Brownell   [ARM] 4539/1: clo...
172
  };
73a59c1c4   SAN People   [ARM] 3240/2: AT9...
173
  /*
5e802dfab   David Brownell   [ARM] 4539/1: clo...
174
   * ST (system timer) module supports both clockevents and clocksource.
73a59c1c4   SAN People   [ARM] 3240/2: AT9...
175
   */
adbaf5254   Daniel Lezcano   clocksource/drive...
176
  static int __init atmel_st_timer_init(struct device_node *node)
73a59c1c4   SAN People   [ARM] 3240/2: AT9...
177
  {
216ab8f15   Alexandre Belloni   clocksource: atme...
178
179
  	struct clk *sclk;
  	unsigned int sclk_rate, val;
0afb46b24   Alexandre Belloni   clocksource: atme...
180
  	int irq, ret;
adf2edfd6   Alexandre Belloni   clocksource: atme...
181
182
  
  	regmap_st = syscon_node_to_regmap(node);
adbaf5254   Daniel Lezcano   clocksource/drive...
183
184
185
186
187
  	if (IS_ERR(regmap_st)) {
  		pr_err("Unable to get regmap
  ");
  		return PTR_ERR(regmap_st);
  	}
454c46df8   Joachim Eastwood   ARM: AT91: Add DT...
188

5e802dfab   David Brownell   [ARM] 4539/1: clo...
189
  	/* Disable all timer interrupts, and clear any pending ones */
adf2edfd6   Alexandre Belloni   clocksource: atme...
190
  	regmap_write(regmap_st, AT91_ST_IDR,
5e802dfab   David Brownell   [ARM] 4539/1: clo...
191
  		AT91_ST_PITS | AT91_ST_WDOVF | AT91_ST_RTTINC | AT91_ST_ALMS);
adf2edfd6   Alexandre Belloni   clocksource: atme...
192
193
194
  	regmap_read(regmap_st, AT91_ST_SR, &val);
  
  	/* Get the interrupts property */
0afb46b24   Alexandre Belloni   clocksource: atme...
195
  	irq  = irq_of_parse_and_map(node, 0);
adbaf5254   Daniel Lezcano   clocksource/drive...
196
197
198
199
200
  	if (!irq) {
  		pr_err("Unable to get IRQ from DT
  ");
  		return -EINVAL;
  	}
73a59c1c4   SAN People   [ARM] 3240/2: AT9...
201

2a6f9902c   Andrew Victor   [ARM] 3580/1: AT9...
202
  	/* Make IRQs happen for the system timer */
0afb46b24   Alexandre Belloni   clocksource: atme...
203
204
205
  	ret = request_irq(irq, at91rm9200_timer_interrupt,
  			  IRQF_SHARED | IRQF_TIMER | IRQF_IRQPOLL,
  			  "at91_tick", regmap_st);
adbaf5254   Daniel Lezcano   clocksource/drive...
206
207
208
209
210
  	if (ret) {
  		pr_err("Unable to setup IRQ
  ");
  		return ret;
  	}
73a59c1c4   SAN People   [ARM] 3240/2: AT9...
211

216ab8f15   Alexandre Belloni   clocksource: atme...
212
  	sclk = of_clk_get(node, 0);
adbaf5254   Daniel Lezcano   clocksource/drive...
213
214
215
216
217
  	if (IS_ERR(sclk)) {
  		pr_err("Unable to get slow clock
  ");
  		return PTR_ERR(sclk);
  	}
216ab8f15   Alexandre Belloni   clocksource: atme...
218

adbaf5254   Daniel Lezcano   clocksource/drive...
219
220
221
222
223
224
  	ret = clk_prepare_enable(sclk);
  	if (ret) {
  		pr_err("Could not enable slow clock
  ");
  		return ret;
  	}
216ab8f15   Alexandre Belloni   clocksource: atme...
225
226
  
  	sclk_rate = clk_get_rate(sclk);
adbaf5254   Daniel Lezcano   clocksource/drive...
227
228
229
230
231
  	if (!sclk_rate) {
  		pr_err("Invalid slow clock rate
  ");
  		return -EINVAL;
  	}
216ab8f15   Alexandre Belloni   clocksource: atme...
232
  	timer_latch = (sclk_rate + HZ / 2) / HZ;
5e802dfab   David Brownell   [ARM] 4539/1: clo...
233
234
235
236
  	/* The 32KiHz "Slow Clock" (tick every 30517.58 nanoseconds) is used
  	 * directly for the clocksource and all clockevents, after adjusting
  	 * its prescaler from the 1 Hz default.
  	 */
adf2edfd6   Alexandre Belloni   clocksource: atme...
237
  	regmap_write(regmap_st, AT91_ST_RTMR, 1);
73a59c1c4   SAN People   [ARM] 3240/2: AT9...
238

5e802dfab   David Brownell   [ARM] 4539/1: clo...
239
  	/* Setup timer clockevent, with minimum of two ticks (important!!) */
320ab2b0b   Rusty Russell   cpumask: convert ...
240
  	clkevt.cpumask = cpumask_of(0);
216ab8f15   Alexandre Belloni   clocksource: atme...
241
  	clockevents_config_and_register(&clkevt, sclk_rate,
1c2835311   Uwe Kleine-König   ARM: at91: rm9200...
242
  					2, AT91_ST_ALMV);
2a6f9902c   Andrew Victor   [ARM] 3580/1: AT9...
243

5e802dfab   David Brownell   [ARM] 4539/1: clo...
244
  	/* register clocksource */
adbaf5254   Daniel Lezcano   clocksource/drive...
245
  	return clocksource_register_hz(&clk32k, sclk_rate);
73a59c1c4   SAN People   [ARM] 3240/2: AT9...
246
  }
172733959   Daniel Lezcano   clocksource/drive...
247
  TIMER_OF_DECLARE(atmel_st_timer, "atmel,at91rm9200-st",
bbfc97e1b   Alexandre Belloni   ARM: at91: proper...
248
  		       atmel_st_timer_init);