aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
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 /drivers/misc
parent3925e6fc1f774048404fdd910b0345b06c699eb4 (diff)
parent3ee08aea72f44a6d176af7a97f3ad0c67bc65a44 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/hskinnemoen/tclib into base
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/Kconfig33
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/atmel_tclib.c161
3 files changed, 195 insertions, 0 deletions
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);