aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHaavard Skinnemoen <haavard.skinnemoen@atmel.com>2008-04-19 20:38:13 -0400
committerHaavard Skinnemoen <haavard.skinnemoen@atmel.com>2008-04-19 20:38:13 -0400
commit03414e57ad9875d0c8bfa5a4a65813cb2157372e (patch)
tree836db238d42a6282a5ac2241363eb8b6db190ab7
parent3925e6fc1f774048404fdd910b0345b06c699eb4 (diff)
parent3ee08aea72f44a6d176af7a97f3ad0c67bc65a44 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/hskinnemoen/tclib into base
-rw-r--r--drivers/clocksource/Makefile1
-rw-r--r--drivers/clocksource/tcb_clksrc.c302
-rw-r--r--drivers/misc/Kconfig33
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/atmel_tclib.c161
-rw-r--r--include/linux/atmel_tc.h252
6 files changed, 750 insertions, 0 deletions
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index a52225470225..1525882190fd 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -1,3 +1,4 @@
1obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o
1obj-$(CONFIG_X86_CYCLONE_TIMER) += cyclone.o 2obj-$(CONFIG_X86_CYCLONE_TIMER) += cyclone.o
2obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o 3obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o
3obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o 4obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o
diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c
new file mode 100644
index 000000000000..f450588e5858
--- /dev/null
+++ b/drivers/clocksource/tcb_clksrc.c
@@ -0,0 +1,302 @@
1#include <linux/init.h>
2#include <linux/clocksource.h>
3#include <linux/clockchips.h>
4#include <linux/interrupt.h>
5#include <linux/irq.h>
6
7#include <linux/clk.h>
8#include <linux/err.h>
9#include <linux/ioport.h>
10#include <linux/io.h>
11#include <linux/platform_device.h>
12#include <linux/atmel_tc.h>
13
14
15/*
16 * We're configured to use a specific TC block, one that's not hooked
17 * up to external hardware, to provide a time solution:
18 *
19 * - Two channels combine to create a free-running 32 bit counter
20 * with a base rate of 5+ MHz, packaged as a clocksource (with
21 * resolution better than 200 nsec).
22 *
23 * - The third channel may be used to provide a 16-bit clockevent
24 * source, used in either periodic or oneshot mode. This runs
25 * at 32 KiHZ, and can handle delays of up to two seconds.
26 *
27 * A boot clocksource and clockevent source are also currently needed,
28 * unless the relevant platforms (ARM/AT91, AVR32/AT32) are changed so
29 * this code can be used when init_timers() is called, well before most
30 * devices are set up. (Some low end AT91 parts, which can run uClinux,
31 * have only the timers in one TC block... they currently don't support
32 * the tclib code, because of that initialization issue.)
33 *
34 * REVISIT behavior during system suspend states... we should disable
35 * all clocks and save the power. Easily done for clockevent devices,
36 * but clocksources won't necessarily get the needed notifications.
37 * For deeper system sleep states, this will be mandatory...
38 */
39
40static void __iomem *tcaddr;
41
42static cycle_t tc_get_cycles(void)
43{
44 unsigned long flags;
45 u32 lower, upper;
46
47 raw_local_irq_save(flags);
48 do {
49 upper = __raw_readl(tcaddr + ATMEL_TC_REG(1, CV));
50 lower = __raw_readl(tcaddr + ATMEL_TC_REG(0, CV));
51 } while (upper != __raw_readl(tcaddr + ATMEL_TC_REG(1, CV)));
52
53 raw_local_irq_restore(flags);
54 return (upper << 16) | lower;
55}
56
57static struct clocksource clksrc = {
58 .name = "tcb_clksrc",
59 .rating = 200,
60 .read = tc_get_cycles,
61 .mask = CLOCKSOURCE_MASK(32),
62 .shift = 18,
63 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
64};
65
66#ifdef CONFIG_GENERIC_CLOCKEVENTS
67
68struct tc_clkevt_device {
69 struct clock_event_device clkevt;
70 struct clk *clk;
71 void __iomem *regs;
72};
73
74static struct tc_clkevt_device *to_tc_clkevt(struct clock_event_device *clkevt)
75{
76 return container_of(clkevt, struct tc_clkevt_device, clkevt);
77}
78
79/* For now, we always use the 32K clock ... this optimizes for NO_HZ,
80 * because using one of the divided clocks would usually mean the
81 * tick rate can never be less than several dozen Hz (vs 0.5 Hz).
82 *
83 * A divided clock could be good for high resolution timers, since
84 * 30.5 usec resolution can seem "low".
85 */
86static u32 timer_clock;
87
88static void tc_mode(enum clock_event_mode m, struct clock_event_device *d)
89{
90 struct tc_clkevt_device *tcd = to_tc_clkevt(d);
91 void __iomem *regs = tcd->regs;
92
93 if (tcd->clkevt.mode == CLOCK_EVT_MODE_PERIODIC
94 || tcd->clkevt.mode == CLOCK_EVT_MODE_ONESHOT) {
95 __raw_writel(0xff, regs + ATMEL_TC_REG(2, IDR));
96 __raw_writel(ATMEL_TC_CLKDIS, regs + ATMEL_TC_REG(2, CCR));
97 clk_disable(tcd->clk);
98 }
99
100 switch (m) {
101
102 /* By not making the gentime core emulate periodic mode on top
103 * of oneshot, we get lower overhead and improved accuracy.
104 */
105 case CLOCK_EVT_MODE_PERIODIC:
106 clk_enable(tcd->clk);
107
108 /* slow clock, count up to RC, then irq and restart */
109 __raw_writel(timer_clock
110 | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO,
111 regs + ATMEL_TC_REG(2, CMR));
112 __raw_writel((32768 + HZ/2) / HZ, tcaddr + ATMEL_TC_REG(2, RC));
113
114 /* Enable clock and interrupts on RC compare */
115 __raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));
116
117 /* go go gadget! */
118 __raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG,
119 regs + ATMEL_TC_REG(2, CCR));
120 break;
121
122 case CLOCK_EVT_MODE_ONESHOT:
123 clk_enable(tcd->clk);
124
125 /* slow clock, count up to RC, then irq and stop */
126 __raw_writel(timer_clock | ATMEL_TC_CPCSTOP
127 | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO,
128 regs + ATMEL_TC_REG(2, CMR));
129 __raw_writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER));
130
131 /* set_next_event() configures and starts the timer */
132 break;
133
134 default:
135 break;
136 }
137}
138
139static int tc_next_event(unsigned long delta, struct clock_event_device *d)
140{
141 __raw_writel(delta, tcaddr + ATMEL_TC_REG(2, RC));
142
143 /* go go gadget! */
144 __raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG,
145 tcaddr + ATMEL_TC_REG(2, CCR));
146 return 0;
147}
148
149static struct tc_clkevt_device clkevt = {
150 .clkevt = {
151 .name = "tc_clkevt",
152 .features = CLOCK_EVT_FEAT_PERIODIC
153 | CLOCK_EVT_FEAT_ONESHOT,
154 .shift = 32,
155 /* Should be lower than at91rm9200's system timer */
156 .rating = 125,
157 .cpumask = CPU_MASK_CPU0,
158 .set_next_event = tc_next_event,
159 .set_mode = tc_mode,
160 },
161};
162
163static irqreturn_t ch2_irq(int irq, void *handle)
164{
165 struct tc_clkevt_device *dev = handle;
166 unsigned int sr;
167
168 sr = __raw_readl(dev->regs + ATMEL_TC_REG(2, SR));
169 if (sr & ATMEL_TC_CPCS) {
170 dev->clkevt.event_handler(&dev->clkevt);
171 return IRQ_HANDLED;
172 }
173
174 return IRQ_NONE;
175}
176
177static struct irqaction tc_irqaction = {
178 .name = "tc_clkevt",
179 .flags = IRQF_TIMER | IRQF_DISABLED,
180 .handler = ch2_irq,
181};
182
183static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
184{
185 struct clk *t2_clk = tc->clk[2];
186 int irq = tc->irq[2];
187
188 clkevt.regs = tc->regs;
189 clkevt.clk = t2_clk;
190 tc_irqaction.dev_id = &clkevt;
191
192 timer_clock = clk32k_divisor_idx;
193
194 clkevt.clkevt.mult = div_sc(32768, NSEC_PER_SEC, clkevt.clkevt.shift);
195 clkevt.clkevt.max_delta_ns
196 = clockevent_delta2ns(0xffff, &clkevt.clkevt);
197 clkevt.clkevt.min_delta_ns = clockevent_delta2ns(1, &clkevt.clkevt) + 1;
198
199 setup_irq(irq, &tc_irqaction);
200
201 clockevents_register_device(&clkevt.clkevt);
202}
203
204#else /* !CONFIG_GENERIC_CLOCKEVENTS */
205
206static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
207{
208 /* NOTHING */
209}
210
211#endif
212
213static int __init tcb_clksrc_init(void)
214{
215 static char bootinfo[] __initdata
216 = KERN_DEBUG "%s: tc%d at %d.%03d MHz\n";
217
218 struct platform_device *pdev;
219 struct atmel_tc *tc;
220 struct clk *t0_clk;
221 u32 rate, divided_rate = 0;
222 int best_divisor_idx = -1;
223 int clk32k_divisor_idx = -1;
224 int i;
225
226 tc = atmel_tc_alloc(CONFIG_ATMEL_TCB_CLKSRC_BLOCK, clksrc.name);
227 if (!tc) {
228 pr_debug("can't alloc TC for clocksource\n");
229 return -ENODEV;
230 }
231 tcaddr = tc->regs;
232 pdev = tc->pdev;
233
234 t0_clk = tc->clk[0];
235 clk_enable(t0_clk);
236
237 /* How fast will we be counting? Pick something over 5 MHz. */
238 rate = (u32) clk_get_rate(t0_clk);
239 for (i = 0; i < 5; i++) {
240 unsigned divisor = atmel_tc_divisors[i];
241 unsigned tmp;
242
243 /* remember 32 KiHz clock for later */
244 if (!divisor) {
245 clk32k_divisor_idx = i;
246 continue;
247 }
248
249 tmp = rate / divisor;
250 pr_debug("TC: %u / %-3u [%d] --> %u\n", rate, divisor, i, tmp);
251 if (best_divisor_idx > 0) {
252 if (tmp < 5 * 1000 * 1000)
253 continue;
254 }
255 divided_rate = tmp;
256 best_divisor_idx = i;
257 }
258
259 clksrc.mult = clocksource_hz2mult(divided_rate, clksrc.shift);
260
261 printk(bootinfo, clksrc.name, CONFIG_ATMEL_TCB_CLKSRC_BLOCK,
262 divided_rate / 1000000,
263 ((divided_rate + 500000) % 1000000) / 1000);
264
265 /* tclib will give us three clocks no matter what the
266 * underlying platform supports.
267 */
268 clk_enable(tc->clk[1]);
269
270 /* channel 0: waveform mode, input mclk/8, clock TIOA0 on overflow */
271 __raw_writel(best_divisor_idx /* likely divide-by-8 */
272 | ATMEL_TC_WAVE
273 | ATMEL_TC_WAVESEL_UP /* free-run */
274 | ATMEL_TC_ACPA_SET /* TIOA0 rises at 0 */
275 | ATMEL_TC_ACPC_CLEAR, /* (duty cycle 50%) */
276 tcaddr + ATMEL_TC_REG(0, CMR));
277 __raw_writel(0x0000, tcaddr + ATMEL_TC_REG(0, RA));
278 __raw_writel(0x8000, tcaddr + ATMEL_TC_REG(0, RC));
279 __raw_writel(0xff, tcaddr + ATMEL_TC_REG(0, IDR)); /* no irqs */
280 __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(0, CCR));
281
282 /* channel 1: waveform mode, input TIOA0 */
283 __raw_writel(ATMEL_TC_XC1 /* input: TIOA0 */
284 | ATMEL_TC_WAVE
285 | ATMEL_TC_WAVESEL_UP, /* free-run */
286 tcaddr + ATMEL_TC_REG(1, CMR));
287 __raw_writel(0xff, tcaddr + ATMEL_TC_REG(1, IDR)); /* no irqs */
288 __raw_writel(ATMEL_TC_CLKEN, tcaddr + ATMEL_TC_REG(1, CCR));
289
290 /* chain channel 0 to channel 1, then reset all the timers */
291 __raw_writel(ATMEL_TC_TC1XC1S_TIOA0, tcaddr + ATMEL_TC_BMR);
292 __raw_writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR);
293
294 /* and away we go! */
295 clocksource_register(&clksrc);
296
297 /* channel 2: periodic and oneshot timer support */
298 setup_clkevents(tc, clk32k_divisor_idx);
299
300 return 0;
301}
302arch_initcall(tcb_clksrc_init);
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 962817e49fba..bb94ce78a6d0 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -22,6 +22,39 @@ config ATMEL_PWM
22 purposes including software controlled power-efficent backlights 22 purposes including software controlled power-efficent backlights
23 on LCD displays, motor control, and waveform generation. 23 on LCD displays, motor control, and waveform generation.
24 24
25config ATMEL_TCLIB
26 bool "Atmel AT32/AT91 Timer/Counter Library"
27 depends on (AVR32 || ARCH_AT91)
28 help
29 Select this if you want a library to allocate the Timer/Counter
30 blocks found on many Atmel processors. This facilitates using
31 these blocks by different drivers despite processor differences.
32
33config ATMEL_TCB_CLKSRC
34 bool "TC Block Clocksource"
35 depends on ATMEL_TCLIB && GENERIC_TIME
36 default y
37 help
38 Select this to get a high precision clocksource based on a
39 TC block with a 5+ MHz base clock rate. Two timer channels
40 are combined to make a single 32-bit timer.
41
42 When GENERIC_CLOCKEVENTS is defined, the third timer channel
43 may be used as a clock event device supporting oneshot mode
44 (delays of up to two seconds) based on the 32 KiHz clock.
45
46config ATMEL_TCB_CLKSRC_BLOCK
47 int
48 depends on ATMEL_TCB_CLKSRC
49 prompt "TC Block" if ARCH_AT91RM9200 || ARCH_AT91SAM9260 || CPU_AT32AP700X
50 default 0
51 range 0 1
52 help
53 Some chips provide more than one TC block, so you have the
54 choice of which one to use for the clock framework. The other
55 TC can be used for other purposes, such as PWM generation and
56 interval timing.
57
25config IBM_ASM 58config IBM_ASM
26 tristate "Device driver for IBM RSA service processor" 59 tristate "Device driver for IBM RSA service processor"
27 depends on X86 && PCI && INPUT && EXPERIMENTAL 60 depends on X86 && PCI && INPUT && EXPERIMENTAL
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index bbc69fdd1b9d..4581b2533111 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_ACER_WMI) += acer-wmi.o
10obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o 10obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
11obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o 11obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o
12obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o 12obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
13obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
13obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o 14obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
14obj-$(CONFIG_LKDTM) += lkdtm.o 15obj-$(CONFIG_LKDTM) += lkdtm.o
15obj-$(CONFIG_TIFM_CORE) += tifm_core.o 16obj-$(CONFIG_TIFM_CORE) += tifm_core.o
diff --git a/drivers/misc/atmel_tclib.c b/drivers/misc/atmel_tclib.c
new file mode 100644
index 000000000000..05dc8a31f280
--- /dev/null
+++ b/drivers/misc/atmel_tclib.c
@@ -0,0 +1,161 @@
1#include <linux/atmel_tc.h>
2#include <linux/clk.h>
3#include <linux/err.h>
4#include <linux/init.h>
5#include <linux/io.h>
6#include <linux/ioport.h>
7#include <linux/kernel.h>
8#include <linux/platform_device.h>
9
10/* Number of bytes to reserve for the iomem resource */
11#define ATMEL_TC_IOMEM_SIZE 256
12
13
14/*
15 * This is a thin library to solve the problem of how to portably allocate
16 * one of the TC blocks. For simplicity, it doesn't currently expect to
17 * share individual timers between different drivers.
18 */
19
20#if defined(CONFIG_AVR32)
21/* AVR32 has these divide PBB */
22const u8 atmel_tc_divisors[5] = { 0, 4, 8, 16, 32, };
23EXPORT_SYMBOL(atmel_tc_divisors);
24
25#elif defined(CONFIG_ARCH_AT91)
26/* AT91 has these divide MCK */
27const u8 atmel_tc_divisors[5] = { 2, 8, 32, 128, 0, };
28EXPORT_SYMBOL(atmel_tc_divisors);
29
30#endif
31
32static DEFINE_SPINLOCK(tc_list_lock);
33static LIST_HEAD(tc_list);
34
35/**
36 * atmel_tc_alloc - allocate a specified TC block
37 * @block: which block to allocate
38 * @name: name to be associated with the iomem resource
39 *
40 * Caller allocates a block. If it is available, a pointer to a
41 * pre-initialized struct atmel_tc is returned. The caller can access
42 * the registers directly through the "regs" field.
43 */
44struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name)
45{
46 struct atmel_tc *tc;
47 struct platform_device *pdev = NULL;
48 struct resource *r;
49
50 spin_lock(&tc_list_lock);
51 list_for_each_entry(tc, &tc_list, node) {
52 if (tc->pdev->id == block) {
53 pdev = tc->pdev;
54 break;
55 }
56 }
57
58 if (!pdev || tc->iomem)
59 goto fail;
60
61 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
62 r = request_mem_region(r->start, ATMEL_TC_IOMEM_SIZE, name);
63 if (!r)
64 goto fail;
65
66 tc->regs = ioremap(r->start, ATMEL_TC_IOMEM_SIZE);
67 if (!tc->regs)
68 goto fail_ioremap;
69
70 tc->iomem = r;
71
72out:
73 spin_unlock(&tc_list_lock);
74 return tc;
75
76fail_ioremap:
77 release_resource(r);
78fail:
79 tc = NULL;
80 goto out;
81}
82EXPORT_SYMBOL_GPL(atmel_tc_alloc);
83
84/**
85 * atmel_tc_free - release a specified TC block
86 * @tc: Timer/counter block that was returned by atmel_tc_alloc()
87 *
88 * This reverses the effect of atmel_tc_alloc(), unmapping the I/O
89 * registers, invalidating the resource returned by that routine and
90 * making the TC available to other drivers.
91 */
92void atmel_tc_free(struct atmel_tc *tc)
93{
94 spin_lock(&tc_list_lock);
95 if (tc->regs) {
96 iounmap(tc->regs);
97 release_resource(tc->iomem);
98 tc->regs = NULL;
99 tc->iomem = NULL;
100 }
101 spin_unlock(&tc_list_lock);
102}
103EXPORT_SYMBOL_GPL(atmel_tc_free);
104
105static int __init tc_probe(struct platform_device *pdev)
106{
107 struct atmel_tc *tc;
108 struct clk *clk;
109 int irq;
110
111 if (!platform_get_resource(pdev, IORESOURCE_MEM, 0))
112 return -EINVAL;
113
114 irq = platform_get_irq(pdev, 0);
115 if (irq < 0)
116 return -EINVAL;
117
118 tc = kzalloc(sizeof(struct atmel_tc), GFP_KERNEL);
119 if (!tc)
120 return -ENOMEM;
121
122 tc->pdev = pdev;
123
124 clk = clk_get(&pdev->dev, "t0_clk");
125 if (IS_ERR(clk)) {
126 kfree(tc);
127 return -EINVAL;
128 }
129
130 tc->clk[0] = clk;
131 tc->clk[1] = clk_get(&pdev->dev, "t1_clk");
132 if (IS_ERR(tc->clk[1]))
133 tc->clk[1] = clk;
134 tc->clk[2] = clk_get(&pdev->dev, "t2_clk");
135 if (IS_ERR(tc->clk[2]))
136 tc->clk[2] = clk;
137
138 tc->irq[0] = irq;
139 tc->irq[1] = platform_get_irq(pdev, 1);
140 if (tc->irq[1] < 0)
141 tc->irq[1] = irq;
142 tc->irq[2] = platform_get_irq(pdev, 2);
143 if (tc->irq[2] < 0)
144 tc->irq[2] = irq;
145
146 spin_lock(&tc_list_lock);
147 list_add_tail(&tc->node, &tc_list);
148 spin_unlock(&tc_list_lock);
149
150 return 0;
151}
152
153static struct platform_driver tc_driver = {
154 .driver.name = "atmel_tcb",
155};
156
157static int __init tc_init(void)
158{
159 return platform_driver_probe(&tc_driver, tc_probe);
160}
161arch_initcall(tc_init);
diff --git a/include/linux/atmel_tc.h b/include/linux/atmel_tc.h
new file mode 100644
index 000000000000..53ba65e30caa
--- /dev/null
+++ b/include/linux/atmel_tc.h
@@ -0,0 +1,252 @@
1/*
2 * Timer/Counter Unit (TC) registers.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 */
9
10#ifndef ATMEL_TC_H
11#define ATMEL_TC_H
12
13#include <linux/compiler.h>
14#include <linux/list.h>
15
16/*
17 * Many 32-bit Atmel SOCs include one or more TC blocks, each of which holds
18 * three general-purpose 16-bit timers. These timers share one register bank.
19 * Depending on the SOC, each timer may have its own clock and IRQ, or those
20 * may be shared by the whole TC block.
21 *
22 * These TC blocks may have up to nine external pins: TCLK0..2 signals for
23 * clocks or clock gates, and per-timer TIOA and TIOB signals used for PWM
24 * or triggering. Those pins need to be set up for use with the TC block,
25 * else they will be used as GPIOs or for a different controller.
26 *
27 * Although we expect each TC block to have a platform_device node, those
28 * nodes are not what drivers bind to. Instead, they ask for a specific
29 * TC block, by number ... which is a common approach on systems with many
30 * timers. Then they use clk_get() and platform_get_irq() to get clock and
31 * IRQ resources.
32 */
33
34struct clk;
35
36/**
37 * struct atmel_tc - information about a Timer/Counter Block
38 * @pdev: physical device
39 * @iomem: resource associated with the I/O register
40 * @regs: mapping through which the I/O registers can be accessed
41 * @irq: irq for each of the three channels
42 * @clk: internal clock source for each of the three channels
43 * @node: list node, for tclib internal use
44 *
45 * On some platforms, each TC channel has its own clocks and IRQs,
46 * while on others, all TC channels share the same clock and IRQ.
47 * Drivers should clk_enable() all the clocks they need even though
48 * all the entries in @clk may point to the same physical clock.
49 * Likewise, drivers should request irqs independently for each
50 * channel, but they must use IRQF_SHARED in case some of the entries
51 * in @irq are actually the same IRQ.
52 */
53struct atmel_tc {
54 struct platform_device *pdev;
55 struct resource *iomem;
56 void __iomem *regs;
57 int irq[3];
58 struct clk *clk[3];
59 struct list_head node;
60};
61
62extern struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name);
63extern void atmel_tc_free(struct atmel_tc *tc);
64
65/* platform-specific ATMEL_TC_TIMER_CLOCKx divisors (0 means 32KiHz) */
66extern const u8 atmel_tc_divisors[5];
67
68
69/*
70 * Two registers have block-wide controls. These are: configuring the three
71 * "external" clocks (or event sources) used by the timer channels; and
72 * synchronizing the timers by resetting them all at once.
73 *
74 * "External" can mean "external to chip" using the TCLK0, TCLK1, or TCLK2
75 * signals. Or, it can mean "external to timer", using the TIOA output from
76 * one of the other two timers that's being run in waveform mode.
77 */
78
79#define ATMEL_TC_BCR 0xc0 /* TC Block Control Register */
80#define ATMEL_TC_SYNC (1 << 0) /* synchronize timers */
81
82#define ATMEL_TC_BMR 0xc4 /* TC Block Mode Register */
83#define ATMEL_TC_TC0XC0S (3 << 0) /* external clock 0 source */
84#define ATMEL_TC_TC0XC0S_TCLK0 (0 << 0)
85#define ATMEL_TC_TC0XC0S_NONE (1 << 0)
86#define ATMEL_TC_TC0XC0S_TIOA1 (2 << 0)
87#define ATMEL_TC_TC0XC0S_TIOA2 (3 << 0)
88#define ATMEL_TC_TC1XC1S (3 << 2) /* external clock 1 source */
89#define ATMEL_TC_TC1XC1S_TCLK1 (0 << 2)
90#define ATMEL_TC_TC1XC1S_NONE (1 << 2)
91#define ATMEL_TC_TC1XC1S_TIOA0 (2 << 2)
92#define ATMEL_TC_TC1XC1S_TIOA2 (3 << 2)
93#define ATMEL_TC_TC2XC2S (3 << 4) /* external clock 2 source */
94#define ATMEL_TC_TC2XC2S_TCLK2 (0 << 4)
95#define ATMEL_TC_TC2XC2S_NONE (1 << 4)
96#define ATMEL_TC_TC2XC2S_TIOA0 (2 << 4)
97#define ATMEL_TC_TC2XC2S_TIOA1 (3 << 4)
98
99
100/*
101 * Each TC block has three "channels", each with one counter and controls.
102 *
103 * Note that the semantics of ATMEL_TC_TIMER_CLOCKx (input clock selection
104 * when it's not "external") is silicon-specific. AT91 platforms use one
105 * set of definitions; AVR32 platforms use a different set. Don't hard-wire
106 * such knowledge into your code, use the global "atmel_tc_divisors" ...
107 * where index N is the divisor for clock N+1, else zero to indicate it uses
108 * the 32 KiHz clock.
109 *
110 * The timers can be chained in various ways, and operated in "waveform"
111 * generation mode (including PWM) or "capture" mode (to time events). In
112 * both modes, behavior can be configured in many ways.
113 *
114 * Each timer has two I/O pins, TIOA and TIOB. Waveform mode uses TIOA as a
115 * PWM output, and TIOB as either another PWM or as a trigger. Capture mode
116 * uses them only as inputs.
117 */
118#define ATMEL_TC_CHAN(idx) ((idx)*0x40)
119#define ATMEL_TC_REG(idx, reg) (ATMEL_TC_CHAN(idx) + ATMEL_TC_ ## reg)
120
121#define ATMEL_TC_CCR 0x00 /* Channel Control Register */
122#define ATMEL_TC_CLKEN (1 << 0) /* clock enable */
123#define ATMEL_TC_CLKDIS (1 << 1) /* clock disable */
124#define ATMEL_TC_SWTRG (1 << 2) /* software trigger */
125
126#define ATMEL_TC_CMR 0x04 /* Channel Mode Register */
127
128/* Both modes share some CMR bits */
129#define ATMEL_TC_TCCLKS (7 << 0) /* clock source */
130#define ATMEL_TC_TIMER_CLOCK1 (0 << 0)
131#define ATMEL_TC_TIMER_CLOCK2 (1 << 0)
132#define ATMEL_TC_TIMER_CLOCK3 (2 << 0)
133#define ATMEL_TC_TIMER_CLOCK4 (3 << 0)
134#define ATMEL_TC_TIMER_CLOCK5 (4 << 0)
135#define ATMEL_TC_XC0 (5 << 0)
136#define ATMEL_TC_XC1 (6 << 0)
137#define ATMEL_TC_XC2 (7 << 0)
138#define ATMEL_TC_CLKI (1 << 3) /* clock invert */
139#define ATMEL_TC_BURST (3 << 4) /* clock gating */
140#define ATMEL_TC_GATE_NONE (0 << 4)
141#define ATMEL_TC_GATE_XC0 (1 << 4)
142#define ATMEL_TC_GATE_XC1 (2 << 4)
143#define ATMEL_TC_GATE_XC2 (3 << 4)
144#define ATMEL_TC_WAVE (1 << 15) /* true = Waveform mode */
145
146/* CAPTURE mode CMR bits */
147#define ATMEL_TC_LDBSTOP (1 << 6) /* counter stops on RB load */
148#define ATMEL_TC_LDBDIS (1 << 7) /* counter disable on RB load */
149#define ATMEL_TC_ETRGEDG (3 << 8) /* external trigger edge */
150#define ATMEL_TC_ETRGEDG_NONE (0 << 8)
151#define ATMEL_TC_ETRGEDG_RISING (1 << 8)
152#define ATMEL_TC_ETRGEDG_FALLING (2 << 8)
153#define ATMEL_TC_ETRGEDG_BOTH (3 << 8)
154#define ATMEL_TC_ABETRG (1 << 10) /* external trigger is TIOA? */
155#define ATMEL_TC_CPCTRG (1 << 14) /* RC compare trigger enable */
156#define ATMEL_TC_LDRA (3 << 16) /* RA loading edge (of TIOA) */
157#define ATMEL_TC_LDRA_NONE (0 << 16)
158#define ATMEL_TC_LDRA_RISING (1 << 16)
159#define ATMEL_TC_LDRA_FALLING (2 << 16)
160#define ATMEL_TC_LDRA_BOTH (3 << 16)
161#define ATMEL_TC_LDRB (3 << 18) /* RB loading edge (of TIOA) */
162#define ATMEL_TC_LDRB_NONE (0 << 18)
163#define ATMEL_TC_LDRB_RISING (1 << 18)
164#define ATMEL_TC_LDRB_FALLING (2 << 18)
165#define ATMEL_TC_LDRB_BOTH (3 << 18)
166
167/* WAVEFORM mode CMR bits */
168#define ATMEL_TC_CPCSTOP (1 << 6) /* RC compare stops counter */
169#define ATMEL_TC_CPCDIS (1 << 7) /* RC compare disables counter */
170#define ATMEL_TC_EEVTEDG (3 << 8) /* external event edge */
171#define ATMEL_TC_EEVTEDG_NONE (0 << 8)
172#define ATMEL_TC_EEVTEDG_RISING (1 << 8)
173#define ATMEL_TC_EEVTEDG_FALLING (2 << 8)
174#define ATMEL_TC_EEVTEDG_BOTH (3 << 8)
175#define ATMEL_TC_EEVT (3 << 10) /* external event source */
176#define ATMEL_TC_EEVT_TIOB (0 << 10)
177#define ATMEL_TC_EEVT_XC0 (1 << 10)
178#define ATMEL_TC_EEVT_XC1 (2 << 10)
179#define ATMEL_TC_EEVT_XC2 (3 << 10)
180#define ATMEL_TC_ENETRG (1 << 12) /* external event is trigger */
181#define ATMEL_TC_WAVESEL (3 << 13) /* waveform type */
182#define ATMEL_TC_WAVESEL_UP (0 << 13)
183#define ATMEL_TC_WAVESEL_UPDOWN (1 << 13)
184#define ATMEL_TC_WAVESEL_UP_AUTO (2 << 13)
185#define ATMEL_TC_WAVESEL_UPDOWN_AUTO (3 << 13)
186#define ATMEL_TC_ACPA (3 << 16) /* RA compare changes TIOA */
187#define ATMEL_TC_ACPA_NONE (0 << 16)
188#define ATMEL_TC_ACPA_SET (1 << 16)
189#define ATMEL_TC_ACPA_CLEAR (2 << 16)
190#define ATMEL_TC_ACPA_TOGGLE (3 << 16)
191#define ATMEL_TC_ACPC (3 << 18) /* RC compare changes TIOA */
192#define ATMEL_TC_ACPC_NONE (0 << 18)
193#define ATMEL_TC_ACPC_SET (1 << 18)
194#define ATMEL_TC_ACPC_CLEAR (2 << 18)
195#define ATMEL_TC_ACPC_TOGGLE (3 << 18)
196#define ATMEL_TC_AEEVT (3 << 20) /* external event changes TIOA */
197#define ATMEL_TC_AEEVT_NONE (0 << 20)
198#define ATMEL_TC_AEEVT_SET (1 << 20)
199#define ATMEL_TC_AEEVT_CLEAR (2 << 20)
200#define ATMEL_TC_AEEVT_TOGGLE (3 << 20)
201#define ATMEL_TC_ASWTRG (3 << 22) /* software trigger changes TIOA */
202#define ATMEL_TC_ASWTRG_NONE (0 << 22)
203#define ATMEL_TC_ASWTRG_SET (1 << 22)
204#define ATMEL_TC_ASWTRG_CLEAR (2 << 22)
205#define ATMEL_TC_ASWTRG_TOGGLE (3 << 22)
206#define ATMEL_TC_BCPB (3 << 24) /* RB compare changes TIOB */
207#define ATMEL_TC_BCPB_NONE (0 << 24)
208#define ATMEL_TC_BCPB_SET (1 << 24)
209#define ATMEL_TC_BCPB_CLEAR (2 << 24)
210#define ATMEL_TC_BCPB_TOGGLE (3 << 24)
211#define ATMEL_TC_BCPC (3 << 26) /* RC compare changes TIOB */
212#define ATMEL_TC_BCPC_NONE (0 << 26)
213#define ATMEL_TC_BCPC_SET (1 << 26)
214#define ATMEL_TC_BCPC_CLEAR (2 << 26)
215#define ATMEL_TC_BCPC_TOGGLE (3 << 26)
216#define ATMEL_TC_BEEVT (3 << 28) /* external event changes TIOB */
217#define ATMEL_TC_BEEVT_NONE (0 << 28)
218#define ATMEL_TC_BEEVT_SET (1 << 28)
219#define ATMEL_TC_BEEVT_CLEAR (2 << 28)
220#define ATMEL_TC_BEEVT_TOGGLE (3 << 28)
221#define ATMEL_TC_BSWTRG (3 << 30) /* software trigger changes TIOB */
222#define ATMEL_TC_BSWTRG_NONE (0 << 30)
223#define ATMEL_TC_BSWTRG_SET (1 << 30)
224#define ATMEL_TC_BSWTRG_CLEAR (2 << 30)
225#define ATMEL_TC_BSWTRG_TOGGLE (3 << 30)
226
227#define ATMEL_TC_CV 0x10 /* counter Value */
228#define ATMEL_TC_RA 0x14 /* register A */
229#define ATMEL_TC_RB 0x18 /* register B */
230#define ATMEL_TC_RC 0x1c /* register C */
231
232#define ATMEL_TC_SR 0x20 /* status (read-only) */
233/* Status-only flags */
234#define ATMEL_TC_CLKSTA (1 << 16) /* clock enabled */
235#define ATMEL_TC_MTIOA (1 << 17) /* TIOA mirror */
236#define ATMEL_TC_MTIOB (1 << 18) /* TIOB mirror */
237
238#define ATMEL_TC_IER 0x24 /* interrupt enable (write-only) */
239#define ATMEL_TC_IDR 0x28 /* interrupt disable (write-only) */
240#define ATMEL_TC_IMR 0x2c /* interrupt mask (read-only) */
241
242/* Status and IRQ flags */
243#define ATMEL_TC_COVFS (1 << 0) /* counter overflow */
244#define ATMEL_TC_LOVRS (1 << 1) /* load overrun */
245#define ATMEL_TC_CPAS (1 << 2) /* RA compare */
246#define ATMEL_TC_CPBS (1 << 3) /* RB compare */
247#define ATMEL_TC_CPCS (1 << 4) /* RC compare */
248#define ATMEL_TC_LDRAS (1 << 5) /* RA loading */
249#define ATMEL_TC_LDRBS (1 << 6) /* RB loading */
250#define ATMEL_TC_ETRGS (1 << 7) /* external trigger */
251
252#endif