Root/
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 | #include <linux/slab.h> |
10 | |
11 | /* Number of bytes to reserve for the iomem resource */ |
12 | #define ATMEL_TC_IOMEM_SIZE 256 |
13 | |
14 | |
15 | /* |
16 | * This is a thin library to solve the problem of how to portably allocate |
17 | * one of the TC blocks. For simplicity, it doesn't currently expect to |
18 | * share individual timers between different drivers. |
19 | */ |
20 | |
21 | #if defined(CONFIG_AVR32) |
22 | /* AVR32 has these divide PBB */ |
23 | const u8 atmel_tc_divisors[5] = { 0, 4, 8, 16, 32, }; |
24 | EXPORT_SYMBOL(atmel_tc_divisors); |
25 | |
26 | #elif defined(CONFIG_ARCH_AT91) |
27 | /* AT91 has these divide MCK */ |
28 | const u8 atmel_tc_divisors[5] = { 2, 8, 32, 128, 0, }; |
29 | EXPORT_SYMBOL(atmel_tc_divisors); |
30 | |
31 | #endif |
32 | |
33 | static DEFINE_SPINLOCK(tc_list_lock); |
34 | static LIST_HEAD(tc_list); |
35 | |
36 | /** |
37 | * atmel_tc_alloc - allocate a specified TC block |
38 | * @block: which block to allocate |
39 | * @name: name to be associated with the iomem resource |
40 | * |
41 | * Caller allocates a block. If it is available, a pointer to a |
42 | * pre-initialized struct atmel_tc is returned. The caller can access |
43 | * the registers directly through the "regs" field. |
44 | */ |
45 | struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name) |
46 | { |
47 | struct atmel_tc *tc; |
48 | struct platform_device *pdev = NULL; |
49 | struct resource *r; |
50 | |
51 | spin_lock(&tc_list_lock); |
52 | list_for_each_entry(tc, &tc_list, node) { |
53 | if (tc->pdev->id == block) { |
54 | pdev = tc->pdev; |
55 | break; |
56 | } |
57 | } |
58 | |
59 | if (!pdev || tc->iomem) |
60 | goto fail; |
61 | |
62 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
63 | r = request_mem_region(r->start, ATMEL_TC_IOMEM_SIZE, name); |
64 | if (!r) |
65 | goto fail; |
66 | |
67 | tc->regs = ioremap(r->start, ATMEL_TC_IOMEM_SIZE); |
68 | if (!tc->regs) |
69 | goto fail_ioremap; |
70 | |
71 | tc->iomem = r; |
72 | |
73 | out: |
74 | spin_unlock(&tc_list_lock); |
75 | return tc; |
76 | |
77 | fail_ioremap: |
78 | release_resource(r); |
79 | fail: |
80 | tc = NULL; |
81 | goto out; |
82 | } |
83 | EXPORT_SYMBOL_GPL(atmel_tc_alloc); |
84 | |
85 | /** |
86 | * atmel_tc_free - release a specified TC block |
87 | * @tc: Timer/counter block that was returned by atmel_tc_alloc() |
88 | * |
89 | * This reverses the effect of atmel_tc_alloc(), unmapping the I/O |
90 | * registers, invalidating the resource returned by that routine and |
91 | * making the TC available to other drivers. |
92 | */ |
93 | void atmel_tc_free(struct atmel_tc *tc) |
94 | { |
95 | spin_lock(&tc_list_lock); |
96 | if (tc->regs) { |
97 | iounmap(tc->regs); |
98 | release_resource(tc->iomem); |
99 | tc->regs = NULL; |
100 | tc->iomem = NULL; |
101 | } |
102 | spin_unlock(&tc_list_lock); |
103 | } |
104 | EXPORT_SYMBOL_GPL(atmel_tc_free); |
105 | |
106 | static int __init tc_probe(struct platform_device *pdev) |
107 | { |
108 | struct atmel_tc *tc; |
109 | struct clk *clk; |
110 | int irq; |
111 | |
112 | if (!platform_get_resource(pdev, IORESOURCE_MEM, 0)) |
113 | return -EINVAL; |
114 | |
115 | irq = platform_get_irq(pdev, 0); |
116 | if (irq < 0) |
117 | return -EINVAL; |
118 | |
119 | tc = kzalloc(sizeof(struct atmel_tc), GFP_KERNEL); |
120 | if (!tc) |
121 | return -ENOMEM; |
122 | |
123 | tc->pdev = pdev; |
124 | |
125 | clk = clk_get(&pdev->dev, "t0_clk"); |
126 | if (IS_ERR(clk)) { |
127 | kfree(tc); |
128 | return -EINVAL; |
129 | } |
130 | |
131 | tc->clk[0] = clk; |
132 | tc->clk[1] = clk_get(&pdev->dev, "t1_clk"); |
133 | if (IS_ERR(tc->clk[1])) |
134 | tc->clk[1] = clk; |
135 | tc->clk[2] = clk_get(&pdev->dev, "t2_clk"); |
136 | if (IS_ERR(tc->clk[2])) |
137 | tc->clk[2] = clk; |
138 | |
139 | tc->irq[0] = irq; |
140 | tc->irq[1] = platform_get_irq(pdev, 1); |
141 | if (tc->irq[1] < 0) |
142 | tc->irq[1] = irq; |
143 | tc->irq[2] = platform_get_irq(pdev, 2); |
144 | if (tc->irq[2] < 0) |
145 | tc->irq[2] = irq; |
146 | |
147 | spin_lock(&tc_list_lock); |
148 | list_add_tail(&tc->node, &tc_list); |
149 | spin_unlock(&tc_list_lock); |
150 | |
151 | return 0; |
152 | } |
153 | |
154 | static struct platform_driver tc_driver = { |
155 | .driver.name = "atmel_tcb", |
156 | }; |
157 | |
158 | static int __init tc_init(void) |
159 | { |
160 | return platform_driver_probe(&tc_driver, tc_probe); |
161 | } |
162 | arch_initcall(tc_init); |
163 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9