diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/at91/Makefile | 4 | ||||
-rw-r--r-- | drivers/clk/at91/clk-main.c | 577 | ||||
-rw-r--r-- | drivers/clk/at91/clk-slow.c | 467 | ||||
-rw-r--r-- | drivers/clk/at91/pmc.c | 17 | ||||
-rw-r--r-- | drivers/clk/at91/pmc.h | 9 | ||||
-rw-r--r-- | drivers/clk/at91/sckc.c | 57 | ||||
-rw-r--r-- | drivers/clk/at91/sckc.h | 22 | ||||
-rw-r--r-- | drivers/iio/adc/at91_adc.c | 340 | ||||
-rw-r--r-- | drivers/input/touchscreen/Kconfig | 12 | ||||
-rw-r--r-- | drivers/input/touchscreen/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/touchscreen/atmel_tsadcc.c | 358 |
11 files changed, 1380 insertions, 484 deletions
diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 46c1d3d0d66b..4998aee59267 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile | |||
@@ -2,8 +2,8 @@ | |||
2 | # Makefile for at91 specific clk | 2 | # Makefile for at91 specific clk |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y += pmc.o | 5 | obj-y += pmc.o sckc.o |
6 | obj-y += clk-main.o clk-pll.o clk-plldiv.o clk-master.o | 6 | obj-y += clk-slow.o clk-main.o clk-pll.o clk-plldiv.o clk-master.o |
7 | obj-y += clk-system.o clk-peripheral.o clk-programmable.o | 7 | obj-y += clk-system.o clk-peripheral.o clk-programmable.o |
8 | 8 | ||
9 | obj-$(CONFIG_HAVE_AT91_UTMI) += clk-utmi.o | 9 | obj-$(CONFIG_HAVE_AT91_UTMI) += clk-utmi.o |
diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c index 8e9e8cc0412d..733306131b99 100644 --- a/drivers/clk/at91/clk-main.c +++ b/drivers/clk/at91/clk-main.c | |||
@@ -30,99 +30,546 @@ | |||
30 | #define MAINF_LOOP_MIN_WAIT (USEC_PER_SEC / SLOW_CLOCK_FREQ) | 30 | #define MAINF_LOOP_MIN_WAIT (USEC_PER_SEC / SLOW_CLOCK_FREQ) |
31 | #define MAINF_LOOP_MAX_WAIT MAINFRDY_TIMEOUT | 31 | #define MAINF_LOOP_MAX_WAIT MAINFRDY_TIMEOUT |
32 | 32 | ||
33 | struct clk_main { | 33 | #define MOR_KEY_MASK (0xff << 16) |
34 | |||
35 | struct clk_main_osc { | ||
34 | struct clk_hw hw; | 36 | struct clk_hw hw; |
35 | struct at91_pmc *pmc; | 37 | struct at91_pmc *pmc; |
36 | unsigned long rate; | ||
37 | unsigned int irq; | 38 | unsigned int irq; |
38 | wait_queue_head_t wait; | 39 | wait_queue_head_t wait; |
39 | }; | 40 | }; |
40 | 41 | ||
41 | #define to_clk_main(hw) container_of(hw, struct clk_main, hw) | 42 | #define to_clk_main_osc(hw) container_of(hw, struct clk_main_osc, hw) |
43 | |||
44 | struct clk_main_rc_osc { | ||
45 | struct clk_hw hw; | ||
46 | struct at91_pmc *pmc; | ||
47 | unsigned int irq; | ||
48 | wait_queue_head_t wait; | ||
49 | unsigned long frequency; | ||
50 | unsigned long accuracy; | ||
51 | }; | ||
52 | |||
53 | #define to_clk_main_rc_osc(hw) container_of(hw, struct clk_main_rc_osc, hw) | ||
54 | |||
55 | struct clk_rm9200_main { | ||
56 | struct clk_hw hw; | ||
57 | struct at91_pmc *pmc; | ||
58 | }; | ||
59 | |||
60 | #define to_clk_rm9200_main(hw) container_of(hw, struct clk_rm9200_main, hw) | ||
42 | 61 | ||
43 | static irqreturn_t clk_main_irq_handler(int irq, void *dev_id) | 62 | struct clk_sam9x5_main { |
63 | struct clk_hw hw; | ||
64 | struct at91_pmc *pmc; | ||
65 | unsigned int irq; | ||
66 | wait_queue_head_t wait; | ||
67 | u8 parent; | ||
68 | }; | ||
69 | |||
70 | #define to_clk_sam9x5_main(hw) container_of(hw, struct clk_sam9x5_main, hw) | ||
71 | |||
72 | static irqreturn_t clk_main_osc_irq_handler(int irq, void *dev_id) | ||
44 | { | 73 | { |
45 | struct clk_main *clkmain = (struct clk_main *)dev_id; | 74 | struct clk_main_osc *osc = dev_id; |
46 | 75 | ||
47 | wake_up(&clkmain->wait); | 76 | wake_up(&osc->wait); |
48 | disable_irq_nosync(clkmain->irq); | 77 | disable_irq_nosync(osc->irq); |
49 | 78 | ||
50 | return IRQ_HANDLED; | 79 | return IRQ_HANDLED; |
51 | } | 80 | } |
52 | 81 | ||
53 | static int clk_main_prepare(struct clk_hw *hw) | 82 | static int clk_main_osc_prepare(struct clk_hw *hw) |
54 | { | 83 | { |
55 | struct clk_main *clkmain = to_clk_main(hw); | 84 | struct clk_main_osc *osc = to_clk_main_osc(hw); |
56 | struct at91_pmc *pmc = clkmain->pmc; | 85 | struct at91_pmc *pmc = osc->pmc; |
57 | unsigned long halt_time, timeout; | ||
58 | u32 tmp; | 86 | u32 tmp; |
59 | 87 | ||
88 | tmp = pmc_read(pmc, AT91_CKGR_MOR) & ~MOR_KEY_MASK; | ||
89 | if (tmp & AT91_PMC_OSCBYPASS) | ||
90 | return 0; | ||
91 | |||
92 | if (!(tmp & AT91_PMC_MOSCEN)) { | ||
93 | tmp |= AT91_PMC_MOSCEN | AT91_PMC_KEY; | ||
94 | pmc_write(pmc, AT91_CKGR_MOR, tmp); | ||
95 | } | ||
96 | |||
60 | while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS)) { | 97 | while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS)) { |
61 | enable_irq(clkmain->irq); | 98 | enable_irq(osc->irq); |
62 | wait_event(clkmain->wait, | 99 | wait_event(osc->wait, |
63 | pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS); | 100 | pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS); |
64 | } | 101 | } |
65 | 102 | ||
66 | if (clkmain->rate) | 103 | return 0; |
67 | return 0; | 104 | } |
105 | |||
106 | static void clk_main_osc_unprepare(struct clk_hw *hw) | ||
107 | { | ||
108 | struct clk_main_osc *osc = to_clk_main_osc(hw); | ||
109 | struct at91_pmc *pmc = osc->pmc; | ||
110 | u32 tmp = pmc_read(pmc, AT91_CKGR_MOR); | ||
111 | |||
112 | if (tmp & AT91_PMC_OSCBYPASS) | ||
113 | return; | ||
114 | |||
115 | if (!(tmp & AT91_PMC_MOSCEN)) | ||
116 | return; | ||
117 | |||
118 | tmp &= ~(AT91_PMC_KEY | AT91_PMC_MOSCEN); | ||
119 | pmc_write(pmc, AT91_CKGR_MOR, tmp | AT91_PMC_KEY); | ||
120 | } | ||
121 | |||
122 | static int clk_main_osc_is_prepared(struct clk_hw *hw) | ||
123 | { | ||
124 | struct clk_main_osc *osc = to_clk_main_osc(hw); | ||
125 | struct at91_pmc *pmc = osc->pmc; | ||
126 | u32 tmp = pmc_read(pmc, AT91_CKGR_MOR); | ||
127 | |||
128 | if (tmp & AT91_PMC_OSCBYPASS) | ||
129 | return 1; | ||
130 | |||
131 | return !!((pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCS) && | ||
132 | (pmc_read(pmc, AT91_CKGR_MOR) & AT91_PMC_MOSCEN)); | ||
133 | } | ||
134 | |||
135 | static const struct clk_ops main_osc_ops = { | ||
136 | .prepare = clk_main_osc_prepare, | ||
137 | .unprepare = clk_main_osc_unprepare, | ||
138 | .is_prepared = clk_main_osc_is_prepared, | ||
139 | }; | ||
140 | |||
141 | static struct clk * __init | ||
142 | at91_clk_register_main_osc(struct at91_pmc *pmc, | ||
143 | unsigned int irq, | ||
144 | const char *name, | ||
145 | const char *parent_name, | ||
146 | bool bypass) | ||
147 | { | ||
148 | int ret; | ||
149 | struct clk_main_osc *osc; | ||
150 | struct clk *clk = NULL; | ||
151 | struct clk_init_data init; | ||
152 | |||
153 | if (!pmc || !irq || !name || !parent_name) | ||
154 | return ERR_PTR(-EINVAL); | ||
155 | |||
156 | osc = kzalloc(sizeof(*osc), GFP_KERNEL); | ||
157 | if (!osc) | ||
158 | return ERR_PTR(-ENOMEM); | ||
159 | |||
160 | init.name = name; | ||
161 | init.ops = &main_osc_ops; | ||
162 | init.parent_names = &parent_name; | ||
163 | init.num_parents = 1; | ||
164 | init.flags = CLK_IGNORE_UNUSED; | ||
165 | |||
166 | osc->hw.init = &init; | ||
167 | osc->pmc = pmc; | ||
168 | osc->irq = irq; | ||
169 | |||
170 | init_waitqueue_head(&osc->wait); | ||
171 | irq_set_status_flags(osc->irq, IRQ_NOAUTOEN); | ||
172 | ret = request_irq(osc->irq, clk_main_osc_irq_handler, | ||
173 | IRQF_TRIGGER_HIGH, name, osc); | ||
174 | if (ret) | ||
175 | return ERR_PTR(ret); | ||
176 | |||
177 | if (bypass) | ||
178 | pmc_write(pmc, AT91_CKGR_MOR, | ||
179 | (pmc_read(pmc, AT91_CKGR_MOR) & | ||
180 | ~(MOR_KEY_MASK | AT91_PMC_MOSCEN)) | | ||
181 | AT91_PMC_OSCBYPASS | AT91_PMC_KEY); | ||
182 | |||
183 | clk = clk_register(NULL, &osc->hw); | ||
184 | if (IS_ERR(clk)) { | ||
185 | free_irq(irq, osc); | ||
186 | kfree(osc); | ||
187 | } | ||
188 | |||
189 | return clk; | ||
190 | } | ||
191 | |||
192 | void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np, | ||
193 | struct at91_pmc *pmc) | ||
194 | { | ||
195 | struct clk *clk; | ||
196 | unsigned int irq; | ||
197 | const char *name = np->name; | ||
198 | const char *parent_name; | ||
199 | bool bypass; | ||
200 | |||
201 | of_property_read_string(np, "clock-output-names", &name); | ||
202 | bypass = of_property_read_bool(np, "atmel,osc-bypass"); | ||
203 | parent_name = of_clk_get_parent_name(np, 0); | ||
204 | |||
205 | irq = irq_of_parse_and_map(np, 0); | ||
206 | if (!irq) | ||
207 | return; | ||
208 | |||
209 | clk = at91_clk_register_main_osc(pmc, irq, name, parent_name, bypass); | ||
210 | if (IS_ERR(clk)) | ||
211 | return; | ||
212 | |||
213 | of_clk_add_provider(np, of_clk_src_simple_get, clk); | ||
214 | } | ||
215 | |||
216 | static irqreturn_t clk_main_rc_osc_irq_handler(int irq, void *dev_id) | ||
217 | { | ||
218 | struct clk_main_rc_osc *osc = dev_id; | ||
219 | |||
220 | wake_up(&osc->wait); | ||
221 | disable_irq_nosync(osc->irq); | ||
222 | |||
223 | return IRQ_HANDLED; | ||
224 | } | ||
225 | |||
226 | static int clk_main_rc_osc_prepare(struct clk_hw *hw) | ||
227 | { | ||
228 | struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw); | ||
229 | struct at91_pmc *pmc = osc->pmc; | ||
230 | u32 tmp; | ||
231 | |||
232 | tmp = pmc_read(pmc, AT91_CKGR_MOR) & ~MOR_KEY_MASK; | ||
233 | |||
234 | if (!(tmp & AT91_PMC_MOSCRCEN)) { | ||
235 | tmp |= AT91_PMC_MOSCRCEN | AT91_PMC_KEY; | ||
236 | pmc_write(pmc, AT91_CKGR_MOR, tmp); | ||
237 | } | ||
238 | |||
239 | while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCRCS)) { | ||
240 | enable_irq(osc->irq); | ||
241 | wait_event(osc->wait, | ||
242 | pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCRCS); | ||
243 | } | ||
244 | |||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static void clk_main_rc_osc_unprepare(struct clk_hw *hw) | ||
249 | { | ||
250 | struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw); | ||
251 | struct at91_pmc *pmc = osc->pmc; | ||
252 | u32 tmp = pmc_read(pmc, AT91_CKGR_MOR); | ||
253 | |||
254 | if (!(tmp & AT91_PMC_MOSCRCEN)) | ||
255 | return; | ||
256 | |||
257 | tmp &= ~(MOR_KEY_MASK | AT91_PMC_MOSCRCEN); | ||
258 | pmc_write(pmc, AT91_CKGR_MOR, tmp | AT91_PMC_KEY); | ||
259 | } | ||
260 | |||
261 | static int clk_main_rc_osc_is_prepared(struct clk_hw *hw) | ||
262 | { | ||
263 | struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw); | ||
264 | struct at91_pmc *pmc = osc->pmc; | ||
265 | |||
266 | return !!((pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCRCS) && | ||
267 | (pmc_read(pmc, AT91_CKGR_MOR) & AT91_PMC_MOSCRCEN)); | ||
268 | } | ||
269 | |||
270 | static unsigned long clk_main_rc_osc_recalc_rate(struct clk_hw *hw, | ||
271 | unsigned long parent_rate) | ||
272 | { | ||
273 | struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw); | ||
274 | |||
275 | return osc->frequency; | ||
276 | } | ||
277 | |||
278 | static unsigned long clk_main_rc_osc_recalc_accuracy(struct clk_hw *hw, | ||
279 | unsigned long parent_acc) | ||
280 | { | ||
281 | struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw); | ||
282 | |||
283 | return osc->accuracy; | ||
284 | } | ||
285 | |||
286 | static const struct clk_ops main_rc_osc_ops = { | ||
287 | .prepare = clk_main_rc_osc_prepare, | ||
288 | .unprepare = clk_main_rc_osc_unprepare, | ||
289 | .is_prepared = clk_main_rc_osc_is_prepared, | ||
290 | .recalc_rate = clk_main_rc_osc_recalc_rate, | ||
291 | .recalc_accuracy = clk_main_rc_osc_recalc_accuracy, | ||
292 | }; | ||
293 | |||
294 | static struct clk * __init | ||
295 | at91_clk_register_main_rc_osc(struct at91_pmc *pmc, | ||
296 | unsigned int irq, | ||
297 | const char *name, | ||
298 | u32 frequency, u32 accuracy) | ||
299 | { | ||
300 | int ret; | ||
301 | struct clk_main_rc_osc *osc; | ||
302 | struct clk *clk = NULL; | ||
303 | struct clk_init_data init; | ||
304 | |||
305 | if (!pmc || !irq || !name || !frequency) | ||
306 | return ERR_PTR(-EINVAL); | ||
307 | |||
308 | osc = kzalloc(sizeof(*osc), GFP_KERNEL); | ||
309 | if (!osc) | ||
310 | return ERR_PTR(-ENOMEM); | ||
311 | |||
312 | init.name = name; | ||
313 | init.ops = &main_rc_osc_ops; | ||
314 | init.parent_names = NULL; | ||
315 | init.num_parents = 0; | ||
316 | init.flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED; | ||
317 | |||
318 | osc->hw.init = &init; | ||
319 | osc->pmc = pmc; | ||
320 | osc->irq = irq; | ||
321 | osc->frequency = frequency; | ||
322 | osc->accuracy = accuracy; | ||
323 | |||
324 | init_waitqueue_head(&osc->wait); | ||
325 | irq_set_status_flags(osc->irq, IRQ_NOAUTOEN); | ||
326 | ret = request_irq(osc->irq, clk_main_rc_osc_irq_handler, | ||
327 | IRQF_TRIGGER_HIGH, name, osc); | ||
328 | if (ret) | ||
329 | return ERR_PTR(ret); | ||
330 | |||
331 | clk = clk_register(NULL, &osc->hw); | ||
332 | if (IS_ERR(clk)) { | ||
333 | free_irq(irq, osc); | ||
334 | kfree(osc); | ||
335 | } | ||
336 | |||
337 | return clk; | ||
338 | } | ||
339 | |||
340 | void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np, | ||
341 | struct at91_pmc *pmc) | ||
342 | { | ||
343 | struct clk *clk; | ||
344 | unsigned int irq; | ||
345 | u32 frequency = 0; | ||
346 | u32 accuracy = 0; | ||
347 | const char *name = np->name; | ||
348 | |||
349 | of_property_read_string(np, "clock-output-names", &name); | ||
350 | of_property_read_u32(np, "clock-frequency", &frequency); | ||
351 | of_property_read_u32(np, "clock-accuracy", &accuracy); | ||
352 | |||
353 | irq = irq_of_parse_and_map(np, 0); | ||
354 | if (!irq) | ||
355 | return; | ||
356 | |||
357 | clk = at91_clk_register_main_rc_osc(pmc, irq, name, frequency, | ||
358 | accuracy); | ||
359 | if (IS_ERR(clk)) | ||
360 | return; | ||
361 | |||
362 | of_clk_add_provider(np, of_clk_src_simple_get, clk); | ||
363 | } | ||
364 | |||
365 | |||
366 | static int clk_main_probe_frequency(struct at91_pmc *pmc) | ||
367 | { | ||
368 | unsigned long prep_time, timeout; | ||
369 | u32 tmp; | ||
68 | 370 | ||
69 | timeout = jiffies + usecs_to_jiffies(MAINFRDY_TIMEOUT); | 371 | timeout = jiffies + usecs_to_jiffies(MAINFRDY_TIMEOUT); |
70 | do { | 372 | do { |
71 | halt_time = jiffies; | 373 | prep_time = jiffies; |
72 | tmp = pmc_read(pmc, AT91_CKGR_MCFR); | 374 | tmp = pmc_read(pmc, AT91_CKGR_MCFR); |
73 | if (tmp & AT91_PMC_MAINRDY) | 375 | if (tmp & AT91_PMC_MAINRDY) |
74 | return 0; | 376 | return 0; |
75 | usleep_range(MAINF_LOOP_MIN_WAIT, MAINF_LOOP_MAX_WAIT); | 377 | usleep_range(MAINF_LOOP_MIN_WAIT, MAINF_LOOP_MAX_WAIT); |
76 | } while (time_before(halt_time, timeout)); | 378 | } while (time_before(prep_time, timeout)); |
77 | 379 | ||
78 | return 0; | 380 | return -ETIMEDOUT; |
79 | } | 381 | } |
80 | 382 | ||
81 | static int clk_main_is_prepared(struct clk_hw *hw) | 383 | static unsigned long clk_main_recalc_rate(struct at91_pmc *pmc, |
384 | unsigned long parent_rate) | ||
82 | { | 385 | { |
83 | struct clk_main *clkmain = to_clk_main(hw); | 386 | u32 tmp; |
387 | |||
388 | if (parent_rate) | ||
389 | return parent_rate; | ||
390 | |||
391 | tmp = pmc_read(pmc, AT91_CKGR_MCFR); | ||
392 | if (!(tmp & AT91_PMC_MAINRDY)) | ||
393 | return 0; | ||
84 | 394 | ||
85 | return !!(pmc_read(clkmain->pmc, AT91_PMC_SR) & AT91_PMC_MOSCS); | 395 | return ((tmp & AT91_PMC_MAINF) * SLOW_CLOCK_FREQ) / MAINF_DIV; |
86 | } | 396 | } |
87 | 397 | ||
88 | static unsigned long clk_main_recalc_rate(struct clk_hw *hw, | 398 | static int clk_rm9200_main_prepare(struct clk_hw *hw) |
89 | unsigned long parent_rate) | ||
90 | { | 399 | { |
91 | u32 tmp; | 400 | struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw); |
92 | struct clk_main *clkmain = to_clk_main(hw); | 401 | |
402 | return clk_main_probe_frequency(clkmain->pmc); | ||
403 | } | ||
404 | |||
405 | static int clk_rm9200_main_is_prepared(struct clk_hw *hw) | ||
406 | { | ||
407 | struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw); | ||
408 | |||
409 | return !!(pmc_read(clkmain->pmc, AT91_CKGR_MCFR) & AT91_PMC_MAINRDY); | ||
410 | } | ||
411 | |||
412 | static unsigned long clk_rm9200_main_recalc_rate(struct clk_hw *hw, | ||
413 | unsigned long parent_rate) | ||
414 | { | ||
415 | struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw); | ||
416 | |||
417 | return clk_main_recalc_rate(clkmain->pmc, parent_rate); | ||
418 | } | ||
419 | |||
420 | static const struct clk_ops rm9200_main_ops = { | ||
421 | .prepare = clk_rm9200_main_prepare, | ||
422 | .is_prepared = clk_rm9200_main_is_prepared, | ||
423 | .recalc_rate = clk_rm9200_main_recalc_rate, | ||
424 | }; | ||
425 | |||
426 | static struct clk * __init | ||
427 | at91_clk_register_rm9200_main(struct at91_pmc *pmc, | ||
428 | const char *name, | ||
429 | const char *parent_name) | ||
430 | { | ||
431 | struct clk_rm9200_main *clkmain; | ||
432 | struct clk *clk = NULL; | ||
433 | struct clk_init_data init; | ||
434 | |||
435 | if (!pmc || !name) | ||
436 | return ERR_PTR(-EINVAL); | ||
437 | |||
438 | if (!parent_name) | ||
439 | return ERR_PTR(-EINVAL); | ||
440 | |||
441 | clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL); | ||
442 | if (!clkmain) | ||
443 | return ERR_PTR(-ENOMEM); | ||
444 | |||
445 | init.name = name; | ||
446 | init.ops = &rm9200_main_ops; | ||
447 | init.parent_names = &parent_name; | ||
448 | init.num_parents = 1; | ||
449 | init.flags = 0; | ||
450 | |||
451 | clkmain->hw.init = &init; | ||
452 | clkmain->pmc = pmc; | ||
453 | |||
454 | clk = clk_register(NULL, &clkmain->hw); | ||
455 | if (IS_ERR(clk)) | ||
456 | kfree(clkmain); | ||
457 | |||
458 | return clk; | ||
459 | } | ||
460 | |||
461 | void __init of_at91rm9200_clk_main_setup(struct device_node *np, | ||
462 | struct at91_pmc *pmc) | ||
463 | { | ||
464 | struct clk *clk; | ||
465 | const char *parent_name; | ||
466 | const char *name = np->name; | ||
467 | |||
468 | parent_name = of_clk_get_parent_name(np, 0); | ||
469 | of_property_read_string(np, "clock-output-names", &name); | ||
470 | |||
471 | clk = at91_clk_register_rm9200_main(pmc, name, parent_name); | ||
472 | if (IS_ERR(clk)) | ||
473 | return; | ||
474 | |||
475 | of_clk_add_provider(np, of_clk_src_simple_get, clk); | ||
476 | } | ||
477 | |||
478 | static irqreturn_t clk_sam9x5_main_irq_handler(int irq, void *dev_id) | ||
479 | { | ||
480 | struct clk_sam9x5_main *clkmain = dev_id; | ||
481 | |||
482 | wake_up(&clkmain->wait); | ||
483 | disable_irq_nosync(clkmain->irq); | ||
484 | |||
485 | return IRQ_HANDLED; | ||
486 | } | ||
487 | |||
488 | static int clk_sam9x5_main_prepare(struct clk_hw *hw) | ||
489 | { | ||
490 | struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw); | ||
93 | struct at91_pmc *pmc = clkmain->pmc; | 491 | struct at91_pmc *pmc = clkmain->pmc; |
94 | 492 | ||
95 | if (clkmain->rate) | 493 | while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS)) { |
96 | return clkmain->rate; | 494 | enable_irq(clkmain->irq); |
495 | wait_event(clkmain->wait, | ||
496 | pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS); | ||
497 | } | ||
498 | |||
499 | return clk_main_probe_frequency(pmc); | ||
500 | } | ||
97 | 501 | ||
98 | tmp = pmc_read(pmc, AT91_CKGR_MCFR) & AT91_PMC_MAINF; | 502 | static int clk_sam9x5_main_is_prepared(struct clk_hw *hw) |
99 | clkmain->rate = (tmp * parent_rate) / MAINF_DIV; | 503 | { |
504 | struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw); | ||
100 | 505 | ||
101 | return clkmain->rate; | 506 | return !!(pmc_read(clkmain->pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS); |
102 | } | 507 | } |
103 | 508 | ||
104 | static const struct clk_ops main_ops = { | 509 | static unsigned long clk_sam9x5_main_recalc_rate(struct clk_hw *hw, |
105 | .prepare = clk_main_prepare, | 510 | unsigned long parent_rate) |
106 | .is_prepared = clk_main_is_prepared, | 511 | { |
107 | .recalc_rate = clk_main_recalc_rate, | 512 | struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw); |
513 | |||
514 | return clk_main_recalc_rate(clkmain->pmc, parent_rate); | ||
515 | } | ||
516 | |||
517 | static int clk_sam9x5_main_set_parent(struct clk_hw *hw, u8 index) | ||
518 | { | ||
519 | struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw); | ||
520 | struct at91_pmc *pmc = clkmain->pmc; | ||
521 | u32 tmp; | ||
522 | |||
523 | if (index > 1) | ||
524 | return -EINVAL; | ||
525 | |||
526 | tmp = pmc_read(pmc, AT91_CKGR_MOR) & ~MOR_KEY_MASK; | ||
527 | |||
528 | if (index && !(tmp & AT91_PMC_MOSCSEL)) | ||
529 | pmc_write(pmc, AT91_CKGR_MOR, tmp | AT91_PMC_MOSCSEL); | ||
530 | else if (!index && (tmp & AT91_PMC_MOSCSEL)) | ||
531 | pmc_write(pmc, AT91_CKGR_MOR, tmp & ~AT91_PMC_MOSCSEL); | ||
532 | |||
533 | while (!(pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS)) { | ||
534 | enable_irq(clkmain->irq); | ||
535 | wait_event(clkmain->wait, | ||
536 | pmc_read(pmc, AT91_PMC_SR) & AT91_PMC_MOSCSELS); | ||
537 | } | ||
538 | |||
539 | return 0; | ||
540 | } | ||
541 | |||
542 | static u8 clk_sam9x5_main_get_parent(struct clk_hw *hw) | ||
543 | { | ||
544 | struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw); | ||
545 | |||
546 | return !!(pmc_read(clkmain->pmc, AT91_CKGR_MOR) & AT91_PMC_MOSCEN); | ||
547 | } | ||
548 | |||
549 | static const struct clk_ops sam9x5_main_ops = { | ||
550 | .prepare = clk_sam9x5_main_prepare, | ||
551 | .is_prepared = clk_sam9x5_main_is_prepared, | ||
552 | .recalc_rate = clk_sam9x5_main_recalc_rate, | ||
553 | .set_parent = clk_sam9x5_main_set_parent, | ||
554 | .get_parent = clk_sam9x5_main_get_parent, | ||
108 | }; | 555 | }; |
109 | 556 | ||
110 | static struct clk * __init | 557 | static struct clk * __init |
111 | at91_clk_register_main(struct at91_pmc *pmc, | 558 | at91_clk_register_sam9x5_main(struct at91_pmc *pmc, |
112 | unsigned int irq, | 559 | unsigned int irq, |
113 | const char *name, | 560 | const char *name, |
114 | const char *parent_name, | 561 | const char **parent_names, |
115 | unsigned long rate) | 562 | int num_parents) |
116 | { | 563 | { |
117 | int ret; | 564 | int ret; |
118 | struct clk_main *clkmain; | 565 | struct clk_sam9x5_main *clkmain; |
119 | struct clk *clk = NULL; | 566 | struct clk *clk = NULL; |
120 | struct clk_init_data init; | 567 | struct clk_init_data init; |
121 | 568 | ||
122 | if (!pmc || !irq || !name) | 569 | if (!pmc || !irq || !name) |
123 | return ERR_PTR(-EINVAL); | 570 | return ERR_PTR(-EINVAL); |
124 | 571 | ||
125 | if (!rate && !parent_name) | 572 | if (!parent_names || !num_parents) |
126 | return ERR_PTR(-EINVAL); | 573 | return ERR_PTR(-EINVAL); |
127 | 574 | ||
128 | clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL); | 575 | clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL); |
@@ -130,19 +577,20 @@ at91_clk_register_main(struct at91_pmc *pmc, | |||
130 | return ERR_PTR(-ENOMEM); | 577 | return ERR_PTR(-ENOMEM); |
131 | 578 | ||
132 | init.name = name; | 579 | init.name = name; |
133 | init.ops = &main_ops; | 580 | init.ops = &sam9x5_main_ops; |
134 | init.parent_names = parent_name ? &parent_name : NULL; | 581 | init.parent_names = parent_names; |
135 | init.num_parents = parent_name ? 1 : 0; | 582 | init.num_parents = num_parents; |
136 | init.flags = parent_name ? 0 : CLK_IS_ROOT; | 583 | init.flags = CLK_SET_PARENT_GATE; |
137 | 584 | ||
138 | clkmain->hw.init = &init; | 585 | clkmain->hw.init = &init; |
139 | clkmain->rate = rate; | ||
140 | clkmain->pmc = pmc; | 586 | clkmain->pmc = pmc; |
141 | clkmain->irq = irq; | 587 | clkmain->irq = irq; |
588 | clkmain->parent = !!(pmc_read(clkmain->pmc, AT91_CKGR_MOR) & | ||
589 | AT91_PMC_MOSCEN); | ||
142 | init_waitqueue_head(&clkmain->wait); | 590 | init_waitqueue_head(&clkmain->wait); |
143 | irq_set_status_flags(clkmain->irq, IRQ_NOAUTOEN); | 591 | irq_set_status_flags(clkmain->irq, IRQ_NOAUTOEN); |
144 | ret = request_irq(clkmain->irq, clk_main_irq_handler, | 592 | ret = request_irq(clkmain->irq, clk_sam9x5_main_irq_handler, |
145 | IRQF_TRIGGER_HIGH, "clk-main", clkmain); | 593 | IRQF_TRIGGER_HIGH, name, clkmain); |
146 | if (ret) | 594 | if (ret) |
147 | return ERR_PTR(ret); | 595 | return ERR_PTR(ret); |
148 | 596 | ||
@@ -155,33 +603,36 @@ at91_clk_register_main(struct at91_pmc *pmc, | |||
155 | return clk; | 603 | return clk; |
156 | } | 604 | } |
157 | 605 | ||
158 | 606 | void __init of_at91sam9x5_clk_main_setup(struct device_node *np, | |
159 | 607 | struct at91_pmc *pmc) | |
160 | static void __init | ||
161 | of_at91_clk_main_setup(struct device_node *np, struct at91_pmc *pmc) | ||
162 | { | 608 | { |
163 | struct clk *clk; | 609 | struct clk *clk; |
610 | const char *parent_names[2]; | ||
611 | int num_parents; | ||
164 | unsigned int irq; | 612 | unsigned int irq; |
165 | const char *parent_name; | ||
166 | const char *name = np->name; | 613 | const char *name = np->name; |
167 | u32 rate = 0; | 614 | int i; |
615 | |||
616 | num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells"); | ||
617 | if (num_parents <= 0 || num_parents > 2) | ||
618 | return; | ||
619 | |||
620 | for (i = 0; i < num_parents; ++i) { | ||
621 | parent_names[i] = of_clk_get_parent_name(np, i); | ||
622 | if (!parent_names[i]) | ||
623 | return; | ||
624 | } | ||
168 | 625 | ||
169 | parent_name = of_clk_get_parent_name(np, 0); | ||
170 | of_property_read_string(np, "clock-output-names", &name); | 626 | of_property_read_string(np, "clock-output-names", &name); |
171 | of_property_read_u32(np, "clock-frequency", &rate); | 627 | |
172 | irq = irq_of_parse_and_map(np, 0); | 628 | irq = irq_of_parse_and_map(np, 0); |
173 | if (!irq) | 629 | if (!irq) |
174 | return; | 630 | return; |
175 | 631 | ||
176 | clk = at91_clk_register_main(pmc, irq, name, parent_name, rate); | 632 | clk = at91_clk_register_sam9x5_main(pmc, irq, name, parent_names, |
633 | num_parents); | ||
177 | if (IS_ERR(clk)) | 634 | if (IS_ERR(clk)) |
178 | return; | 635 | return; |
179 | 636 | ||
180 | of_clk_add_provider(np, of_clk_src_simple_get, clk); | 637 | of_clk_add_provider(np, of_clk_src_simple_get, clk); |
181 | } | 638 | } |
182 | |||
183 | void __init of_at91rm9200_clk_main_setup(struct device_node *np, | ||
184 | struct at91_pmc *pmc) | ||
185 | { | ||
186 | of_at91_clk_main_setup(np, pmc); | ||
187 | } | ||
diff --git a/drivers/clk/at91/clk-slow.c b/drivers/clk/at91/clk-slow.c new file mode 100644 index 000000000000..0300c46ee247 --- /dev/null +++ b/drivers/clk/at91/clk-slow.c | |||
@@ -0,0 +1,467 @@ | |||
1 | /* | ||
2 | * drivers/clk/at91/clk-slow.c | ||
3 | * | ||
4 | * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/clk-provider.h> | ||
14 | #include <linux/clkdev.h> | ||
15 | #include <linux/clk/at91_pmc.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/of.h> | ||
18 | #include <linux/of_address.h> | ||
19 | #include <linux/of_irq.h> | ||
20 | #include <linux/io.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/irq.h> | ||
23 | #include <linux/sched.h> | ||
24 | #include <linux/wait.h> | ||
25 | |||
26 | #include "pmc.h" | ||
27 | #include "sckc.h" | ||
28 | |||
29 | #define SLOW_CLOCK_FREQ 32768 | ||
30 | #define SLOWCK_SW_CYCLES 5 | ||
31 | #define SLOWCK_SW_TIME_USEC ((SLOWCK_SW_CYCLES * USEC_PER_SEC) / \ | ||
32 | SLOW_CLOCK_FREQ) | ||
33 | |||
34 | #define AT91_SCKC_CR 0x00 | ||
35 | #define AT91_SCKC_RCEN (1 << 0) | ||
36 | #define AT91_SCKC_OSC32EN (1 << 1) | ||
37 | #define AT91_SCKC_OSC32BYP (1 << 2) | ||
38 | #define AT91_SCKC_OSCSEL (1 << 3) | ||
39 | |||
40 | struct clk_slow_osc { | ||
41 | struct clk_hw hw; | ||
42 | void __iomem *sckcr; | ||
43 | unsigned long startup_usec; | ||
44 | }; | ||
45 | |||
46 | #define to_clk_slow_osc(hw) container_of(hw, struct clk_slow_osc, hw) | ||
47 | |||
48 | struct clk_slow_rc_osc { | ||
49 | struct clk_hw hw; | ||
50 | void __iomem *sckcr; | ||
51 | unsigned long frequency; | ||
52 | unsigned long accuracy; | ||
53 | unsigned long startup_usec; | ||
54 | }; | ||
55 | |||
56 | #define to_clk_slow_rc_osc(hw) container_of(hw, struct clk_slow_rc_osc, hw) | ||
57 | |||
58 | struct clk_sam9260_slow { | ||
59 | struct clk_hw hw; | ||
60 | struct at91_pmc *pmc; | ||
61 | }; | ||
62 | |||
63 | #define to_clk_sam9260_slow(hw) container_of(hw, struct clk_sam9260_slow, hw) | ||
64 | |||
65 | struct clk_sam9x5_slow { | ||
66 | struct clk_hw hw; | ||
67 | void __iomem *sckcr; | ||
68 | u8 parent; | ||
69 | }; | ||
70 | |||
71 | #define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw) | ||
72 | |||
73 | |||
74 | static int clk_slow_osc_prepare(struct clk_hw *hw) | ||
75 | { | ||
76 | struct clk_slow_osc *osc = to_clk_slow_osc(hw); | ||
77 | void __iomem *sckcr = osc->sckcr; | ||
78 | u32 tmp = readl(sckcr); | ||
79 | |||
80 | if (tmp & AT91_SCKC_OSC32BYP) | ||
81 | return 0; | ||
82 | |||
83 | writel(tmp | AT91_SCKC_OSC32EN, sckcr); | ||
84 | |||
85 | usleep_range(osc->startup_usec, osc->startup_usec + 1); | ||
86 | |||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static void clk_slow_osc_unprepare(struct clk_hw *hw) | ||
91 | { | ||
92 | struct clk_slow_osc *osc = to_clk_slow_osc(hw); | ||
93 | void __iomem *sckcr = osc->sckcr; | ||
94 | u32 tmp = readl(sckcr); | ||
95 | |||
96 | if (tmp & AT91_SCKC_OSC32BYP) | ||
97 | return; | ||
98 | |||
99 | writel(tmp & ~AT91_SCKC_OSC32EN, sckcr); | ||
100 | } | ||
101 | |||
102 | static int clk_slow_osc_is_prepared(struct clk_hw *hw) | ||
103 | { | ||
104 | struct clk_slow_osc *osc = to_clk_slow_osc(hw); | ||
105 | void __iomem *sckcr = osc->sckcr; | ||
106 | u32 tmp = readl(sckcr); | ||
107 | |||
108 | if (tmp & AT91_SCKC_OSC32BYP) | ||
109 | return 1; | ||
110 | |||
111 | return !!(tmp & AT91_SCKC_OSC32EN); | ||
112 | } | ||
113 | |||
114 | static const struct clk_ops slow_osc_ops = { | ||
115 | .prepare = clk_slow_osc_prepare, | ||
116 | .unprepare = clk_slow_osc_unprepare, | ||
117 | .is_prepared = clk_slow_osc_is_prepared, | ||
118 | }; | ||
119 | |||
120 | static struct clk * __init | ||
121 | at91_clk_register_slow_osc(void __iomem *sckcr, | ||
122 | const char *name, | ||
123 | const char *parent_name, | ||
124 | unsigned long startup, | ||
125 | bool bypass) | ||
126 | { | ||
127 | struct clk_slow_osc *osc; | ||
128 | struct clk *clk = NULL; | ||
129 | struct clk_init_data init; | ||
130 | |||
131 | if (!sckcr || !name || !parent_name) | ||
132 | return ERR_PTR(-EINVAL); | ||
133 | |||
134 | osc = kzalloc(sizeof(*osc), GFP_KERNEL); | ||
135 | if (!osc) | ||
136 | return ERR_PTR(-ENOMEM); | ||
137 | |||
138 | init.name = name; | ||
139 | init.ops = &slow_osc_ops; | ||
140 | init.parent_names = &parent_name; | ||
141 | init.num_parents = 1; | ||
142 | init.flags = CLK_IGNORE_UNUSED; | ||
143 | |||
144 | osc->hw.init = &init; | ||
145 | osc->sckcr = sckcr; | ||
146 | osc->startup_usec = startup; | ||
147 | |||
148 | if (bypass) | ||
149 | writel((readl(sckcr) & ~AT91_SCKC_OSC32EN) | AT91_SCKC_OSC32BYP, | ||
150 | sckcr); | ||
151 | |||
152 | clk = clk_register(NULL, &osc->hw); | ||
153 | if (IS_ERR(clk)) | ||
154 | kfree(osc); | ||
155 | |||
156 | return clk; | ||
157 | } | ||
158 | |||
159 | void __init of_at91sam9x5_clk_slow_osc_setup(struct device_node *np, | ||
160 | void __iomem *sckcr) | ||
161 | { | ||
162 | struct clk *clk; | ||
163 | const char *parent_name; | ||
164 | const char *name = np->name; | ||
165 | u32 startup; | ||
166 | bool bypass; | ||
167 | |||
168 | parent_name = of_clk_get_parent_name(np, 0); | ||
169 | of_property_read_string(np, "clock-output-names", &name); | ||
170 | of_property_read_u32(np, "atmel,startup-time-usec", &startup); | ||
171 | bypass = of_property_read_bool(np, "atmel,osc-bypass"); | ||
172 | |||
173 | clk = at91_clk_register_slow_osc(sckcr, name, parent_name, startup, | ||
174 | bypass); | ||
175 | if (IS_ERR(clk)) | ||
176 | return; | ||
177 | |||
178 | of_clk_add_provider(np, of_clk_src_simple_get, clk); | ||
179 | } | ||
180 | |||
181 | static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw, | ||
182 | unsigned long parent_rate) | ||
183 | { | ||
184 | struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); | ||
185 | |||
186 | return osc->frequency; | ||
187 | } | ||
188 | |||
189 | static unsigned long clk_slow_rc_osc_recalc_accuracy(struct clk_hw *hw, | ||
190 | unsigned long parent_acc) | ||
191 | { | ||
192 | struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); | ||
193 | |||
194 | return osc->accuracy; | ||
195 | } | ||
196 | |||
197 | static int clk_slow_rc_osc_prepare(struct clk_hw *hw) | ||
198 | { | ||
199 | struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); | ||
200 | void __iomem *sckcr = osc->sckcr; | ||
201 | |||
202 | writel(readl(sckcr) | AT91_SCKC_RCEN, sckcr); | ||
203 | |||
204 | usleep_range(osc->startup_usec, osc->startup_usec + 1); | ||
205 | |||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static void clk_slow_rc_osc_unprepare(struct clk_hw *hw) | ||
210 | { | ||
211 | struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); | ||
212 | void __iomem *sckcr = osc->sckcr; | ||
213 | |||
214 | writel(readl(sckcr) & ~AT91_SCKC_RCEN, sckcr); | ||
215 | } | ||
216 | |||
217 | static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw) | ||
218 | { | ||
219 | struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); | ||
220 | |||
221 | return !!(readl(osc->sckcr) & AT91_SCKC_RCEN); | ||
222 | } | ||
223 | |||
224 | static const struct clk_ops slow_rc_osc_ops = { | ||
225 | .prepare = clk_slow_rc_osc_prepare, | ||
226 | .unprepare = clk_slow_rc_osc_unprepare, | ||
227 | .is_prepared = clk_slow_rc_osc_is_prepared, | ||
228 | .recalc_rate = clk_slow_rc_osc_recalc_rate, | ||
229 | .recalc_accuracy = clk_slow_rc_osc_recalc_accuracy, | ||
230 | }; | ||
231 | |||
232 | static struct clk * __init | ||
233 | at91_clk_register_slow_rc_osc(void __iomem *sckcr, | ||
234 | const char *name, | ||
235 | unsigned long frequency, | ||
236 | unsigned long accuracy, | ||
237 | unsigned long startup) | ||
238 | { | ||
239 | struct clk_slow_rc_osc *osc; | ||
240 | struct clk *clk = NULL; | ||
241 | struct clk_init_data init; | ||
242 | |||
243 | if (!sckcr || !name) | ||
244 | return ERR_PTR(-EINVAL); | ||
245 | |||
246 | osc = kzalloc(sizeof(*osc), GFP_KERNEL); | ||
247 | if (!osc) | ||
248 | return ERR_PTR(-ENOMEM); | ||
249 | |||
250 | init.name = name; | ||
251 | init.ops = &slow_rc_osc_ops; | ||
252 | init.parent_names = NULL; | ||
253 | init.num_parents = 0; | ||
254 | init.flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED; | ||
255 | |||
256 | osc->hw.init = &init; | ||
257 | osc->sckcr = sckcr; | ||
258 | osc->frequency = frequency; | ||
259 | osc->accuracy = accuracy; | ||
260 | osc->startup_usec = startup; | ||
261 | |||
262 | clk = clk_register(NULL, &osc->hw); | ||
263 | if (IS_ERR(clk)) | ||
264 | kfree(osc); | ||
265 | |||
266 | return clk; | ||
267 | } | ||
268 | |||
269 | void __init of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np, | ||
270 | void __iomem *sckcr) | ||
271 | { | ||
272 | struct clk *clk; | ||
273 | u32 frequency = 0; | ||
274 | u32 accuracy = 0; | ||
275 | u32 startup = 0; | ||
276 | const char *name = np->name; | ||
277 | |||
278 | of_property_read_string(np, "clock-output-names", &name); | ||
279 | of_property_read_u32(np, "clock-frequency", &frequency); | ||
280 | of_property_read_u32(np, "clock-accuracy", &accuracy); | ||
281 | of_property_read_u32(np, "atmel,startup-time-usec", &startup); | ||
282 | |||
283 | clk = at91_clk_register_slow_rc_osc(sckcr, name, frequency, accuracy, | ||
284 | startup); | ||
285 | if (IS_ERR(clk)) | ||
286 | return; | ||
287 | |||
288 | of_clk_add_provider(np, of_clk_src_simple_get, clk); | ||
289 | } | ||
290 | |||
291 | static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index) | ||
292 | { | ||
293 | struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw); | ||
294 | void __iomem *sckcr = slowck->sckcr; | ||
295 | u32 tmp; | ||
296 | |||
297 | if (index > 1) | ||
298 | return -EINVAL; | ||
299 | |||
300 | tmp = readl(sckcr); | ||
301 | |||
302 | if ((!index && !(tmp & AT91_SCKC_OSCSEL)) || | ||
303 | (index && (tmp & AT91_SCKC_OSCSEL))) | ||
304 | return 0; | ||
305 | |||
306 | if (index) | ||
307 | tmp |= AT91_SCKC_OSCSEL; | ||
308 | else | ||
309 | tmp &= ~AT91_SCKC_OSCSEL; | ||
310 | |||
311 | writel(tmp, sckcr); | ||
312 | |||
313 | usleep_range(SLOWCK_SW_TIME_USEC, SLOWCK_SW_TIME_USEC + 1); | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw) | ||
319 | { | ||
320 | struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw); | ||
321 | |||
322 | return !!(readl(slowck->sckcr) & AT91_SCKC_OSCSEL); | ||
323 | } | ||
324 | |||
325 | static const struct clk_ops sam9x5_slow_ops = { | ||
326 | .set_parent = clk_sam9x5_slow_set_parent, | ||
327 | .get_parent = clk_sam9x5_slow_get_parent, | ||
328 | }; | ||
329 | |||
330 | static struct clk * __init | ||
331 | at91_clk_register_sam9x5_slow(void __iomem *sckcr, | ||
332 | const char *name, | ||
333 | const char **parent_names, | ||
334 | int num_parents) | ||
335 | { | ||
336 | struct clk_sam9x5_slow *slowck; | ||
337 | struct clk *clk = NULL; | ||
338 | struct clk_init_data init; | ||
339 | |||
340 | if (!sckcr || !name || !parent_names || !num_parents) | ||
341 | return ERR_PTR(-EINVAL); | ||
342 | |||
343 | slowck = kzalloc(sizeof(*slowck), GFP_KERNEL); | ||
344 | if (!slowck) | ||
345 | return ERR_PTR(-ENOMEM); | ||
346 | |||
347 | init.name = name; | ||
348 | init.ops = &sam9x5_slow_ops; | ||
349 | init.parent_names = parent_names; | ||
350 | init.num_parents = num_parents; | ||
351 | init.flags = 0; | ||
352 | |||
353 | slowck->hw.init = &init; | ||
354 | slowck->sckcr = sckcr; | ||
355 | slowck->parent = !!(readl(sckcr) & AT91_SCKC_OSCSEL); | ||
356 | |||
357 | clk = clk_register(NULL, &slowck->hw); | ||
358 | if (IS_ERR(clk)) | ||
359 | kfree(slowck); | ||
360 | |||
361 | return clk; | ||
362 | } | ||
363 | |||
364 | void __init of_at91sam9x5_clk_slow_setup(struct device_node *np, | ||
365 | void __iomem *sckcr) | ||
366 | { | ||
367 | struct clk *clk; | ||
368 | const char *parent_names[2]; | ||
369 | int num_parents; | ||
370 | const char *name = np->name; | ||
371 | int i; | ||
372 | |||
373 | num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells"); | ||
374 | if (num_parents <= 0 || num_parents > 2) | ||
375 | return; | ||
376 | |||
377 | for (i = 0; i < num_parents; ++i) { | ||
378 | parent_names[i] = of_clk_get_parent_name(np, i); | ||
379 | if (!parent_names[i]) | ||
380 | return; | ||
381 | } | ||
382 | |||
383 | of_property_read_string(np, "clock-output-names", &name); | ||
384 | |||
385 | clk = at91_clk_register_sam9x5_slow(sckcr, name, parent_names, | ||
386 | num_parents); | ||
387 | if (IS_ERR(clk)) | ||
388 | return; | ||
389 | |||
390 | of_clk_add_provider(np, of_clk_src_simple_get, clk); | ||
391 | } | ||
392 | |||
393 | static u8 clk_sam9260_slow_get_parent(struct clk_hw *hw) | ||
394 | { | ||
395 | struct clk_sam9260_slow *slowck = to_clk_sam9260_slow(hw); | ||
396 | |||
397 | return !!(pmc_read(slowck->pmc, AT91_PMC_SR) & AT91_PMC_OSCSEL); | ||
398 | } | ||
399 | |||
400 | static const struct clk_ops sam9260_slow_ops = { | ||
401 | .get_parent = clk_sam9260_slow_get_parent, | ||
402 | }; | ||
403 | |||
404 | static struct clk * __init | ||
405 | at91_clk_register_sam9260_slow(struct at91_pmc *pmc, | ||
406 | const char *name, | ||
407 | const char **parent_names, | ||
408 | int num_parents) | ||
409 | { | ||
410 | struct clk_sam9260_slow *slowck; | ||
411 | struct clk *clk = NULL; | ||
412 | struct clk_init_data init; | ||
413 | |||
414 | if (!pmc || !name) | ||
415 | return ERR_PTR(-EINVAL); | ||
416 | |||
417 | if (!parent_names || !num_parents) | ||
418 | return ERR_PTR(-EINVAL); | ||
419 | |||
420 | slowck = kzalloc(sizeof(*slowck), GFP_KERNEL); | ||
421 | if (!slowck) | ||
422 | return ERR_PTR(-ENOMEM); | ||
423 | |||
424 | init.name = name; | ||
425 | init.ops = &sam9260_slow_ops; | ||
426 | init.parent_names = parent_names; | ||
427 | init.num_parents = num_parents; | ||
428 | init.flags = 0; | ||
429 | |||
430 | slowck->hw.init = &init; | ||
431 | slowck->pmc = pmc; | ||
432 | |||
433 | clk = clk_register(NULL, &slowck->hw); | ||
434 | if (IS_ERR(clk)) | ||
435 | kfree(slowck); | ||
436 | |||
437 | return clk; | ||
438 | } | ||
439 | |||
440 | void __init of_at91sam9260_clk_slow_setup(struct device_node *np, | ||
441 | struct at91_pmc *pmc) | ||
442 | { | ||
443 | struct clk *clk; | ||
444 | const char *parent_names[2]; | ||
445 | int num_parents; | ||
446 | const char *name = np->name; | ||
447 | int i; | ||
448 | |||
449 | num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells"); | ||
450 | if (num_parents <= 0 || num_parents > 1) | ||
451 | return; | ||
452 | |||
453 | for (i = 0; i < num_parents; ++i) { | ||
454 | parent_names[i] = of_clk_get_parent_name(np, i); | ||
455 | if (!parent_names[i]) | ||
456 | return; | ||
457 | } | ||
458 | |||
459 | of_property_read_string(np, "clock-output-names", &name); | ||
460 | |||
461 | clk = at91_clk_register_sam9260_slow(pmc, name, parent_names, | ||
462 | num_parents); | ||
463 | if (IS_ERR(clk)) | ||
464 | return; | ||
465 | |||
466 | of_clk_add_provider(np, of_clk_src_simple_get, clk); | ||
467 | } | ||
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c index 6a61477a57e0..524196bb35a5 100644 --- a/drivers/clk/at91/pmc.c +++ b/drivers/clk/at91/pmc.c | |||
@@ -229,11 +229,28 @@ out_free_pmc: | |||
229 | } | 229 | } |
230 | 230 | ||
231 | static const struct of_device_id pmc_clk_ids[] __initconst = { | 231 | static const struct of_device_id pmc_clk_ids[] __initconst = { |
232 | /* Slow oscillator */ | ||
233 | { | ||
234 | .compatible = "atmel,at91sam9260-clk-slow", | ||
235 | .data = of_at91sam9260_clk_slow_setup, | ||
236 | }, | ||
232 | /* Main clock */ | 237 | /* Main clock */ |
233 | { | 238 | { |
239 | .compatible = "atmel,at91rm9200-clk-main-osc", | ||
240 | .data = of_at91rm9200_clk_main_osc_setup, | ||
241 | }, | ||
242 | { | ||
243 | .compatible = "atmel,at91sam9x5-clk-main-rc-osc", | ||
244 | .data = of_at91sam9x5_clk_main_rc_osc_setup, | ||
245 | }, | ||
246 | { | ||
234 | .compatible = "atmel,at91rm9200-clk-main", | 247 | .compatible = "atmel,at91rm9200-clk-main", |
235 | .data = of_at91rm9200_clk_main_setup, | 248 | .data = of_at91rm9200_clk_main_setup, |
236 | }, | 249 | }, |
250 | { | ||
251 | .compatible = "atmel,at91sam9x5-clk-main", | ||
252 | .data = of_at91sam9x5_clk_main_setup, | ||
253 | }, | ||
237 | /* PLL clocks */ | 254 | /* PLL clocks */ |
238 | { | 255 | { |
239 | .compatible = "atmel,at91rm9200-clk-pll", | 256 | .compatible = "atmel,at91rm9200-clk-pll", |
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 441350983ccb..6c7625976113 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h | |||
@@ -58,8 +58,17 @@ static inline void pmc_write(struct at91_pmc *pmc, int offset, u32 value) | |||
58 | int of_at91_get_clk_range(struct device_node *np, const char *propname, | 58 | int of_at91_get_clk_range(struct device_node *np, const char *propname, |
59 | struct clk_range *range); | 59 | struct clk_range *range); |
60 | 60 | ||
61 | extern void __init of_at91sam9260_clk_slow_setup(struct device_node *np, | ||
62 | struct at91_pmc *pmc); | ||
63 | |||
64 | extern void __init of_at91rm9200_clk_main_osc_setup(struct device_node *np, | ||
65 | struct at91_pmc *pmc); | ||
66 | extern void __init of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np, | ||
67 | struct at91_pmc *pmc); | ||
61 | extern void __init of_at91rm9200_clk_main_setup(struct device_node *np, | 68 | extern void __init of_at91rm9200_clk_main_setup(struct device_node *np, |
62 | struct at91_pmc *pmc); | 69 | struct at91_pmc *pmc); |
70 | extern void __init of_at91sam9x5_clk_main_setup(struct device_node *np, | ||
71 | struct at91_pmc *pmc); | ||
63 | 72 | ||
64 | extern void __init of_at91rm9200_clk_pll_setup(struct device_node *np, | 73 | extern void __init of_at91rm9200_clk_pll_setup(struct device_node *np, |
65 | struct at91_pmc *pmc); | 74 | struct at91_pmc *pmc); |
diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c new file mode 100644 index 000000000000..1184d76a7ab7 --- /dev/null +++ b/drivers/clk/at91/sckc.c | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | * drivers/clk/at91/sckc.c | ||
3 | * | ||
4 | * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/clk-provider.h> | ||
14 | #include <linux/clkdev.h> | ||
15 | #include <linux/of.h> | ||
16 | #include <linux/of_address.h> | ||
17 | #include <linux/io.h> | ||
18 | |||
19 | #include "sckc.h" | ||
20 | |||
21 | static const struct of_device_id sckc_clk_ids[] __initconst = { | ||
22 | /* Slow clock */ | ||
23 | { | ||
24 | .compatible = "atmel,at91sam9x5-clk-slow-osc", | ||
25 | .data = of_at91sam9x5_clk_slow_osc_setup, | ||
26 | }, | ||
27 | { | ||
28 | .compatible = "atmel,at91sam9x5-clk-slow-rc-osc", | ||
29 | .data = of_at91sam9x5_clk_slow_rc_osc_setup, | ||
30 | }, | ||
31 | { | ||
32 | .compatible = "atmel,at91sam9x5-clk-slow", | ||
33 | .data = of_at91sam9x5_clk_slow_setup, | ||
34 | }, | ||
35 | { /*sentinel*/ } | ||
36 | }; | ||
37 | |||
38 | static void __init of_at91sam9x5_sckc_setup(struct device_node *np) | ||
39 | { | ||
40 | struct device_node *childnp; | ||
41 | void (*clk_setup)(struct device_node *, void __iomem *); | ||
42 | const struct of_device_id *clk_id; | ||
43 | void __iomem *regbase = of_iomap(np, 0); | ||
44 | |||
45 | if (!regbase) | ||
46 | return; | ||
47 | |||
48 | for_each_child_of_node(np, childnp) { | ||
49 | clk_id = of_match_node(sckc_clk_ids, childnp); | ||
50 | if (!clk_id) | ||
51 | continue; | ||
52 | clk_setup = clk_id->data; | ||
53 | clk_setup(childnp, regbase); | ||
54 | } | ||
55 | } | ||
56 | CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc", | ||
57 | of_at91sam9x5_sckc_setup); | ||
diff --git a/drivers/clk/at91/sckc.h b/drivers/clk/at91/sckc.h new file mode 100644 index 000000000000..836fcf59820f --- /dev/null +++ b/drivers/clk/at91/sckc.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * drivers/clk/at91/sckc.h | ||
3 | * | ||
4 | * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #ifndef __AT91_SCKC_H_ | ||
13 | #define __AT91_SCKC_H_ | ||
14 | |||
15 | extern void __init of_at91sam9x5_clk_slow_osc_setup(struct device_node *np, | ||
16 | void __iomem *sckcr); | ||
17 | extern void __init of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np, | ||
18 | void __iomem *sckcr); | ||
19 | extern void __init of_at91sam9x5_clk_slow_setup(struct device_node *np, | ||
20 | void __iomem *sckcr); | ||
21 | |||
22 | #endif /* __AT91_SCKC_H_ */ | ||
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 89777ed9abd8..3b5bacd4d8da 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c | |||
@@ -31,7 +31,108 @@ | |||
31 | #include <linux/iio/trigger_consumer.h> | 31 | #include <linux/iio/trigger_consumer.h> |
32 | #include <linux/iio/triggered_buffer.h> | 32 | #include <linux/iio/triggered_buffer.h> |
33 | 33 | ||
34 | #include <mach/at91_adc.h> | 34 | /* Registers */ |
35 | #define AT91_ADC_CR 0x00 /* Control Register */ | ||
36 | #define AT91_ADC_SWRST (1 << 0) /* Software Reset */ | ||
37 | #define AT91_ADC_START (1 << 1) /* Start Conversion */ | ||
38 | |||
39 | #define AT91_ADC_MR 0x04 /* Mode Register */ | ||
40 | #define AT91_ADC_TSAMOD (3 << 0) /* ADC mode */ | ||
41 | #define AT91_ADC_TSAMOD_ADC_ONLY_MODE (0 << 0) /* ADC Mode */ | ||
42 | #define AT91_ADC_TSAMOD_TS_ONLY_MODE (1 << 0) /* Touch Screen Only Mode */ | ||
43 | #define AT91_ADC_TRGEN (1 << 0) /* Trigger Enable */ | ||
44 | #define AT91_ADC_TRGSEL (7 << 1) /* Trigger Selection */ | ||
45 | #define AT91_ADC_TRGSEL_TC0 (0 << 1) | ||
46 | #define AT91_ADC_TRGSEL_TC1 (1 << 1) | ||
47 | #define AT91_ADC_TRGSEL_TC2 (2 << 1) | ||
48 | #define AT91_ADC_TRGSEL_EXTERNAL (6 << 1) | ||
49 | #define AT91_ADC_LOWRES (1 << 4) /* Low Resolution */ | ||
50 | #define AT91_ADC_SLEEP (1 << 5) /* Sleep Mode */ | ||
51 | #define AT91_ADC_PENDET (1 << 6) /* Pen contact detection enable */ | ||
52 | #define AT91_ADC_PRESCAL_9260 (0x3f << 8) /* Prescalar Rate Selection */ | ||
53 | #define AT91_ADC_PRESCAL_9G45 (0xff << 8) | ||
54 | #define AT91_ADC_PRESCAL_(x) ((x) << 8) | ||
55 | #define AT91_ADC_STARTUP_9260 (0x1f << 16) /* Startup Up Time */ | ||
56 | #define AT91_ADC_STARTUP_9G45 (0x7f << 16) | ||
57 | #define AT91_ADC_STARTUP_9X5 (0xf << 16) | ||
58 | #define AT91_ADC_STARTUP_(x) ((x) << 16) | ||
59 | #define AT91_ADC_SHTIM (0xf << 24) /* Sample & Hold Time */ | ||
60 | #define AT91_ADC_SHTIM_(x) ((x) << 24) | ||
61 | #define AT91_ADC_PENDBC (0x0f << 28) /* Pen Debounce time */ | ||
62 | #define AT91_ADC_PENDBC_(x) ((x) << 28) | ||
63 | |||
64 | #define AT91_ADC_TSR 0x0C | ||
65 | #define AT91_ADC_TSR_SHTIM (0xf << 24) /* Sample & Hold Time */ | ||
66 | #define AT91_ADC_TSR_SHTIM_(x) ((x) << 24) | ||
67 | |||
68 | #define AT91_ADC_CHER 0x10 /* Channel Enable Register */ | ||
69 | #define AT91_ADC_CHDR 0x14 /* Channel Disable Register */ | ||
70 | #define AT91_ADC_CHSR 0x18 /* Channel Status Register */ | ||
71 | #define AT91_ADC_CH(n) (1 << (n)) /* Channel Number */ | ||
72 | |||
73 | #define AT91_ADC_SR 0x1C /* Status Register */ | ||
74 | #define AT91_ADC_EOC(n) (1 << (n)) /* End of Conversion on Channel N */ | ||
75 | #define AT91_ADC_OVRE(n) (1 << ((n) + 8))/* Overrun Error on Channel N */ | ||
76 | #define AT91_ADC_DRDY (1 << 16) /* Data Ready */ | ||
77 | #define AT91_ADC_GOVRE (1 << 17) /* General Overrun Error */ | ||
78 | #define AT91_ADC_ENDRX (1 << 18) /* End of RX Buffer */ | ||
79 | #define AT91_ADC_RXFUFF (1 << 19) /* RX Buffer Full */ | ||
80 | |||
81 | #define AT91_ADC_SR_9X5 0x30 /* Status Register for 9x5 */ | ||
82 | #define AT91_ADC_SR_DRDY_9X5 (1 << 24) /* Data Ready */ | ||
83 | |||
84 | #define AT91_ADC_LCDR 0x20 /* Last Converted Data Register */ | ||
85 | #define AT91_ADC_LDATA (0x3ff) | ||
86 | |||
87 | #define AT91_ADC_IER 0x24 /* Interrupt Enable Register */ | ||
88 | #define AT91_ADC_IDR 0x28 /* Interrupt Disable Register */ | ||
89 | #define AT91_ADC_IMR 0x2C /* Interrupt Mask Register */ | ||
90 | #define AT91RL_ADC_IER_PEN (1 << 20) | ||
91 | #define AT91RL_ADC_IER_NOPEN (1 << 21) | ||
92 | #define AT91_ADC_IER_PEN (1 << 29) | ||
93 | #define AT91_ADC_IER_NOPEN (1 << 30) | ||
94 | #define AT91_ADC_IER_XRDY (1 << 20) | ||
95 | #define AT91_ADC_IER_YRDY (1 << 21) | ||
96 | #define AT91_ADC_IER_PRDY (1 << 22) | ||
97 | #define AT91_ADC_ISR_PENS (1 << 31) | ||
98 | |||
99 | #define AT91_ADC_CHR(n) (0x30 + ((n) * 4)) /* Channel Data Register N */ | ||
100 | #define AT91_ADC_DATA (0x3ff) | ||
101 | |||
102 | #define AT91_ADC_CDR0_9X5 (0x50) /* Channel Data Register 0 for 9X5 */ | ||
103 | |||
104 | #define AT91_ADC_ACR 0x94 /* Analog Control Register */ | ||
105 | #define AT91_ADC_ACR_PENDETSENS (0x3 << 0) /* pull-up resistor */ | ||
106 | |||
107 | #define AT91_ADC_TSMR 0xB0 | ||
108 | #define AT91_ADC_TSMR_TSMODE (3 << 0) /* Touch Screen Mode */ | ||
109 | #define AT91_ADC_TSMR_TSMODE_NONE (0 << 0) | ||
110 | #define AT91_ADC_TSMR_TSMODE_4WIRE_NO_PRESS (1 << 0) | ||
111 | #define AT91_ADC_TSMR_TSMODE_4WIRE_PRESS (2 << 0) | ||
112 | #define AT91_ADC_TSMR_TSMODE_5WIRE (3 << 0) | ||
113 | #define AT91_ADC_TSMR_TSAV (3 << 4) /* Averages samples */ | ||
114 | #define AT91_ADC_TSMR_TSAV_(x) ((x) << 4) | ||
115 | #define AT91_ADC_TSMR_SCTIM (0x0f << 16) /* Switch closure time */ | ||
116 | #define AT91_ADC_TSMR_PENDBC (0x0f << 28) /* Pen Debounce time */ | ||
117 | #define AT91_ADC_TSMR_PENDBC_(x) ((x) << 28) | ||
118 | #define AT91_ADC_TSMR_NOTSDMA (1 << 22) /* No Touchscreen DMA */ | ||
119 | #define AT91_ADC_TSMR_PENDET_DIS (0 << 24) /* Pen contact detection disable */ | ||
120 | #define AT91_ADC_TSMR_PENDET_ENA (1 << 24) /* Pen contact detection enable */ | ||
121 | |||
122 | #define AT91_ADC_TSXPOSR 0xB4 | ||
123 | #define AT91_ADC_TSYPOSR 0xB8 | ||
124 | #define AT91_ADC_TSPRESSR 0xBC | ||
125 | |||
126 | #define AT91_ADC_TRGR_9260 AT91_ADC_MR | ||
127 | #define AT91_ADC_TRGR_9G45 0x08 | ||
128 | #define AT91_ADC_TRGR_9X5 0xC0 | ||
129 | |||
130 | /* Trigger Register bit field */ | ||
131 | #define AT91_ADC_TRGR_TRGPER (0xffff << 16) | ||
132 | #define AT91_ADC_TRGR_TRGPER_(x) ((x) << 16) | ||
133 | #define AT91_ADC_TRGR_TRGMOD (0x7 << 0) | ||
134 | #define AT91_ADC_TRGR_NONE (0 << 0) | ||
135 | #define AT91_ADC_TRGR_MOD_PERIOD_TRIG (5 << 0) | ||
35 | 136 | ||
36 | #define AT91_ADC_CHAN(st, ch) \ | 137 | #define AT91_ADC_CHAN(st, ch) \ |
37 | (st->registers->channel_base + (ch * 4)) | 138 | (st->registers->channel_base + (ch * 4)) |
@@ -46,6 +147,29 @@ | |||
46 | #define TOUCH_SAMPLE_PERIOD_US 2000 /* 2ms */ | 147 | #define TOUCH_SAMPLE_PERIOD_US 2000 /* 2ms */ |
47 | #define TOUCH_PEN_DETECT_DEBOUNCE_US 200 | 148 | #define TOUCH_PEN_DETECT_DEBOUNCE_US 200 |
48 | 149 | ||
150 | #define MAX_RLPOS_BITS 10 | ||
151 | #define TOUCH_SAMPLE_PERIOD_US_RL 10000 /* 10ms, the SoC can't keep up with 2ms */ | ||
152 | #define TOUCH_SHTIM 0xa | ||
153 | |||
154 | /** | ||
155 | * struct at91_adc_reg_desc - Various informations relative to registers | ||
156 | * @channel_base: Base offset for the channel data registers | ||
157 | * @drdy_mask: Mask of the DRDY field in the relevant registers | ||
158 | (Interruptions registers mostly) | ||
159 | * @status_register: Offset of the Interrupt Status Register | ||
160 | * @trigger_register: Offset of the Trigger setup register | ||
161 | * @mr_prescal_mask: Mask of the PRESCAL field in the adc MR register | ||
162 | * @mr_startup_mask: Mask of the STARTUP field in the adc MR register | ||
163 | */ | ||
164 | struct at91_adc_reg_desc { | ||
165 | u8 channel_base; | ||
166 | u32 drdy_mask; | ||
167 | u8 status_register; | ||
168 | u8 trigger_register; | ||
169 | u32 mr_prescal_mask; | ||
170 | u32 mr_startup_mask; | ||
171 | }; | ||
172 | |||
49 | struct at91_adc_caps { | 173 | struct at91_adc_caps { |
50 | bool has_ts; /* Support touch screen */ | 174 | bool has_ts; /* Support touch screen */ |
51 | bool has_tsmr; /* only at91sam9x5, sama5d3 have TSMR reg */ | 175 | bool has_tsmr; /* only at91sam9x5, sama5d3 have TSMR reg */ |
@@ -64,12 +188,6 @@ struct at91_adc_caps { | |||
64 | struct at91_adc_reg_desc registers; | 188 | struct at91_adc_reg_desc registers; |
65 | }; | 189 | }; |
66 | 190 | ||
67 | enum atmel_adc_ts_type { | ||
68 | ATMEL_ADC_TOUCHSCREEN_NONE = 0, | ||
69 | ATMEL_ADC_TOUCHSCREEN_4WIRE = 4, | ||
70 | ATMEL_ADC_TOUCHSCREEN_5WIRE = 5, | ||
71 | }; | ||
72 | |||
73 | struct at91_adc_state { | 191 | struct at91_adc_state { |
74 | struct clk *adc_clk; | 192 | struct clk *adc_clk; |
75 | u16 *buffer; | 193 | u16 *buffer; |
@@ -114,6 +232,11 @@ struct at91_adc_state { | |||
114 | 232 | ||
115 | u16 ts_sample_period_val; | 233 | u16 ts_sample_period_val; |
116 | u32 ts_pressure_threshold; | 234 | u32 ts_pressure_threshold; |
235 | u16 ts_pendbc; | ||
236 | |||
237 | bool ts_bufferedmeasure; | ||
238 | u32 ts_prev_absx; | ||
239 | u32 ts_prev_absy; | ||
117 | }; | 240 | }; |
118 | 241 | ||
119 | static irqreturn_t at91_adc_trigger_handler(int irq, void *p) | 242 | static irqreturn_t at91_adc_trigger_handler(int irq, void *p) |
@@ -220,7 +343,72 @@ static int at91_ts_sample(struct at91_adc_state *st) | |||
220 | return 0; | 343 | return 0; |
221 | } | 344 | } |
222 | 345 | ||
223 | static irqreturn_t at91_adc_interrupt(int irq, void *private) | 346 | static irqreturn_t at91_adc_rl_interrupt(int irq, void *private) |
347 | { | ||
348 | struct iio_dev *idev = private; | ||
349 | struct at91_adc_state *st = iio_priv(idev); | ||
350 | u32 status = at91_adc_readl(st, st->registers->status_register); | ||
351 | unsigned int reg; | ||
352 | |||
353 | status &= at91_adc_readl(st, AT91_ADC_IMR); | ||
354 | if (status & st->registers->drdy_mask) | ||
355 | handle_adc_eoc_trigger(irq, idev); | ||
356 | |||
357 | if (status & AT91RL_ADC_IER_PEN) { | ||
358 | /* Disabling pen debounce is required to get a NOPEN irq */ | ||
359 | reg = at91_adc_readl(st, AT91_ADC_MR); | ||
360 | reg &= ~AT91_ADC_PENDBC; | ||
361 | at91_adc_writel(st, AT91_ADC_MR, reg); | ||
362 | |||
363 | at91_adc_writel(st, AT91_ADC_IDR, AT91RL_ADC_IER_PEN); | ||
364 | at91_adc_writel(st, AT91_ADC_IER, AT91RL_ADC_IER_NOPEN | ||
365 | | AT91_ADC_EOC(3)); | ||
366 | /* Set up period trigger for sampling */ | ||
367 | at91_adc_writel(st, st->registers->trigger_register, | ||
368 | AT91_ADC_TRGR_MOD_PERIOD_TRIG | | ||
369 | AT91_ADC_TRGR_TRGPER_(st->ts_sample_period_val)); | ||
370 | } else if (status & AT91RL_ADC_IER_NOPEN) { | ||
371 | reg = at91_adc_readl(st, AT91_ADC_MR); | ||
372 | reg |= AT91_ADC_PENDBC_(st->ts_pendbc) & AT91_ADC_PENDBC; | ||
373 | at91_adc_writel(st, AT91_ADC_MR, reg); | ||
374 | at91_adc_writel(st, st->registers->trigger_register, | ||
375 | AT91_ADC_TRGR_NONE); | ||
376 | |||
377 | at91_adc_writel(st, AT91_ADC_IDR, AT91RL_ADC_IER_NOPEN | ||
378 | | AT91_ADC_EOC(3)); | ||
379 | at91_adc_writel(st, AT91_ADC_IER, AT91RL_ADC_IER_PEN); | ||
380 | st->ts_bufferedmeasure = false; | ||
381 | input_report_key(st->ts_input, BTN_TOUCH, 0); | ||
382 | input_sync(st->ts_input); | ||
383 | } else if (status & AT91_ADC_EOC(3)) { | ||
384 | /* Conversion finished */ | ||
385 | if (st->ts_bufferedmeasure) { | ||
386 | /* | ||
387 | * Last measurement is always discarded, since it can | ||
388 | * be erroneous. | ||
389 | * Always report previous measurement | ||
390 | */ | ||
391 | input_report_abs(st->ts_input, ABS_X, st->ts_prev_absx); | ||
392 | input_report_abs(st->ts_input, ABS_Y, st->ts_prev_absy); | ||
393 | input_report_key(st->ts_input, BTN_TOUCH, 1); | ||
394 | input_sync(st->ts_input); | ||
395 | } else | ||
396 | st->ts_bufferedmeasure = true; | ||
397 | |||
398 | /* Now make new measurement */ | ||
399 | st->ts_prev_absx = at91_adc_readl(st, AT91_ADC_CHAN(st, 3)) | ||
400 | << MAX_RLPOS_BITS; | ||
401 | st->ts_prev_absx /= at91_adc_readl(st, AT91_ADC_CHAN(st, 2)); | ||
402 | |||
403 | st->ts_prev_absy = at91_adc_readl(st, AT91_ADC_CHAN(st, 1)) | ||
404 | << MAX_RLPOS_BITS; | ||
405 | st->ts_prev_absy /= at91_adc_readl(st, AT91_ADC_CHAN(st, 0)); | ||
406 | } | ||
407 | |||
408 | return IRQ_HANDLED; | ||
409 | } | ||
410 | |||
411 | static irqreturn_t at91_adc_9x5_interrupt(int irq, void *private) | ||
224 | { | 412 | { |
225 | struct iio_dev *idev = private; | 413 | struct iio_dev *idev = private; |
226 | struct at91_adc_state *st = iio_priv(idev); | 414 | struct at91_adc_state *st = iio_priv(idev); |
@@ -653,6 +841,8 @@ static int at91_adc_probe_dt_ts(struct device_node *node, | |||
653 | return -EINVAL; | 841 | return -EINVAL; |
654 | } | 842 | } |
655 | 843 | ||
844 | if (!st->caps->has_tsmr) | ||
845 | return 0; | ||
656 | prop = 0; | 846 | prop = 0; |
657 | of_property_read_u32(node, "atmel,adc-ts-pressure-threshold", &prop); | 847 | of_property_read_u32(node, "atmel,adc-ts-pressure-threshold", &prop); |
658 | st->ts_pressure_threshold = prop; | 848 | st->ts_pressure_threshold = prop; |
@@ -776,6 +966,7 @@ static int at91_adc_probe_pdata(struct at91_adc_state *st, | |||
776 | st->trigger_number = pdata->trigger_number; | 966 | st->trigger_number = pdata->trigger_number; |
777 | st->trigger_list = pdata->trigger_list; | 967 | st->trigger_list = pdata->trigger_list; |
778 | st->registers = &st->caps->registers; | 968 | st->registers = &st->caps->registers; |
969 | st->touchscreen_type = pdata->touchscreen_type; | ||
779 | 970 | ||
780 | return 0; | 971 | return 0; |
781 | } | 972 | } |
@@ -790,7 +981,10 @@ static int atmel_ts_open(struct input_dev *dev) | |||
790 | { | 981 | { |
791 | struct at91_adc_state *st = input_get_drvdata(dev); | 982 | struct at91_adc_state *st = input_get_drvdata(dev); |
792 | 983 | ||
793 | at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN); | 984 | if (st->caps->has_tsmr) |
985 | at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN); | ||
986 | else | ||
987 | at91_adc_writel(st, AT91_ADC_IER, AT91RL_ADC_IER_PEN); | ||
794 | return 0; | 988 | return 0; |
795 | } | 989 | } |
796 | 990 | ||
@@ -798,45 +992,61 @@ static void atmel_ts_close(struct input_dev *dev) | |||
798 | { | 992 | { |
799 | struct at91_adc_state *st = input_get_drvdata(dev); | 993 | struct at91_adc_state *st = input_get_drvdata(dev); |
800 | 994 | ||
801 | at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN); | 995 | if (st->caps->has_tsmr) |
996 | at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN); | ||
997 | else | ||
998 | at91_adc_writel(st, AT91_ADC_IDR, AT91RL_ADC_IER_PEN); | ||
802 | } | 999 | } |
803 | 1000 | ||
804 | static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz) | 1001 | static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz) |
805 | { | 1002 | { |
806 | u32 reg = 0, pendbc; | 1003 | u32 reg = 0; |
807 | int i = 0; | 1004 | int i = 0; |
808 | 1005 | ||
809 | if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE) | ||
810 | reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS; | ||
811 | else | ||
812 | reg = AT91_ADC_TSMR_TSMODE_5WIRE; | ||
813 | |||
814 | /* a Pen Detect Debounce Time is necessary for the ADC Touch to avoid | 1006 | /* a Pen Detect Debounce Time is necessary for the ADC Touch to avoid |
815 | * pen detect noise. | 1007 | * pen detect noise. |
816 | * The formula is : Pen Detect Debounce Time = (2 ^ pendbc) / ADCClock | 1008 | * The formula is : Pen Detect Debounce Time = (2 ^ pendbc) / ADCClock |
817 | */ | 1009 | */ |
818 | pendbc = round_up(TOUCH_PEN_DETECT_DEBOUNCE_US * adc_clk_khz / 1000, 1); | 1010 | st->ts_pendbc = round_up(TOUCH_PEN_DETECT_DEBOUNCE_US * adc_clk_khz / |
1011 | 1000, 1); | ||
819 | 1012 | ||
820 | while (pendbc >> ++i) | 1013 | while (st->ts_pendbc >> ++i) |
821 | ; /* Empty! Find the shift offset */ | 1014 | ; /* Empty! Find the shift offset */ |
822 | if (abs(pendbc - (1 << i)) < abs(pendbc - (1 << (i - 1)))) | 1015 | if (abs(st->ts_pendbc - (1 << i)) < abs(st->ts_pendbc - (1 << (i - 1)))) |
823 | pendbc = i; | 1016 | st->ts_pendbc = i; |
824 | else | 1017 | else |
825 | pendbc = i - 1; | 1018 | st->ts_pendbc = i - 1; |
826 | 1019 | ||
827 | if (st->caps->has_tsmr) { | 1020 | if (!st->caps->has_tsmr) { |
828 | reg |= AT91_ADC_TSMR_TSAV_(st->caps->ts_filter_average) | 1021 | reg = at91_adc_readl(st, AT91_ADC_MR); |
829 | & AT91_ADC_TSMR_TSAV; | 1022 | reg |= AT91_ADC_TSAMOD_TS_ONLY_MODE | AT91_ADC_PENDET; |
830 | reg |= AT91_ADC_TSMR_PENDBC_(pendbc) & AT91_ADC_TSMR_PENDBC; | 1023 | |
831 | reg |= AT91_ADC_TSMR_NOTSDMA; | 1024 | reg |= AT91_ADC_PENDBC_(st->ts_pendbc) & AT91_ADC_PENDBC; |
832 | reg |= AT91_ADC_TSMR_PENDET_ENA; | 1025 | at91_adc_writel(st, AT91_ADC_MR, reg); |
833 | reg |= 0x03 << 8; /* TSFREQ, need bigger than TSAV */ | 1026 | |
834 | 1027 | reg = AT91_ADC_TSR_SHTIM_(TOUCH_SHTIM) & AT91_ADC_TSR_SHTIM; | |
835 | at91_adc_writel(st, AT91_ADC_TSMR, reg); | 1028 | at91_adc_writel(st, AT91_ADC_TSR, reg); |
836 | } else { | 1029 | |
837 | /* TODO: for 9g45 which has no TSMR */ | 1030 | st->ts_sample_period_val = round_up((TOUCH_SAMPLE_PERIOD_US_RL * |
1031 | adc_clk_khz / 1000) - 1, 1); | ||
1032 | |||
1033 | return 0; | ||
838 | } | 1034 | } |
839 | 1035 | ||
1036 | if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE) | ||
1037 | reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS; | ||
1038 | else | ||
1039 | reg = AT91_ADC_TSMR_TSMODE_5WIRE; | ||
1040 | |||
1041 | reg |= AT91_ADC_TSMR_TSAV_(st->caps->ts_filter_average) | ||
1042 | & AT91_ADC_TSMR_TSAV; | ||
1043 | reg |= AT91_ADC_TSMR_PENDBC_(st->ts_pendbc) & AT91_ADC_TSMR_PENDBC; | ||
1044 | reg |= AT91_ADC_TSMR_NOTSDMA; | ||
1045 | reg |= AT91_ADC_TSMR_PENDET_ENA; | ||
1046 | reg |= 0x03 << 8; /* TSFREQ, needs to be bigger than TSAV */ | ||
1047 | |||
1048 | at91_adc_writel(st, AT91_ADC_TSMR, reg); | ||
1049 | |||
840 | /* Change adc internal resistor value for better pen detection, | 1050 | /* Change adc internal resistor value for better pen detection, |
841 | * default value is 100 kOhm. | 1051 | * default value is 100 kOhm. |
842 | * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm | 1052 | * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm |
@@ -845,7 +1055,7 @@ static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz) | |||
845 | at91_adc_writel(st, AT91_ADC_ACR, st->caps->ts_pen_detect_sensitivity | 1055 | at91_adc_writel(st, AT91_ADC_ACR, st->caps->ts_pen_detect_sensitivity |
846 | & AT91_ADC_ACR_PENDETSENS); | 1056 | & AT91_ADC_ACR_PENDETSENS); |
847 | 1057 | ||
848 | /* Sample Peroid Time = (TRGPER + 1) / ADCClock */ | 1058 | /* Sample Period Time = (TRGPER + 1) / ADCClock */ |
849 | st->ts_sample_period_val = round_up((TOUCH_SAMPLE_PERIOD_US * | 1059 | st->ts_sample_period_val = round_up((TOUCH_SAMPLE_PERIOD_US * |
850 | adc_clk_khz / 1000) - 1, 1); | 1060 | adc_clk_khz / 1000) - 1, 1); |
851 | 1061 | ||
@@ -874,18 +1084,38 @@ static int at91_ts_register(struct at91_adc_state *st, | |||
874 | __set_bit(EV_ABS, input->evbit); | 1084 | __set_bit(EV_ABS, input->evbit); |
875 | __set_bit(EV_KEY, input->evbit); | 1085 | __set_bit(EV_KEY, input->evbit); |
876 | __set_bit(BTN_TOUCH, input->keybit); | 1086 | __set_bit(BTN_TOUCH, input->keybit); |
877 | input_set_abs_params(input, ABS_X, 0, (1 << MAX_POS_BITS) - 1, 0, 0); | 1087 | if (st->caps->has_tsmr) { |
878 | input_set_abs_params(input, ABS_Y, 0, (1 << MAX_POS_BITS) - 1, 0, 0); | 1088 | input_set_abs_params(input, ABS_X, 0, (1 << MAX_POS_BITS) - 1, |
879 | input_set_abs_params(input, ABS_PRESSURE, 0, 0xffffff, 0, 0); | 1089 | 0, 0); |
1090 | input_set_abs_params(input, ABS_Y, 0, (1 << MAX_POS_BITS) - 1, | ||
1091 | 0, 0); | ||
1092 | input_set_abs_params(input, ABS_PRESSURE, 0, 0xffffff, 0, 0); | ||
1093 | } else { | ||
1094 | if (st->touchscreen_type != ATMEL_ADC_TOUCHSCREEN_4WIRE) { | ||
1095 | dev_err(&pdev->dev, | ||
1096 | "This touchscreen controller only support 4 wires\n"); | ||
1097 | ret = -EINVAL; | ||
1098 | goto err; | ||
1099 | } | ||
1100 | |||
1101 | input_set_abs_params(input, ABS_X, 0, (1 << MAX_RLPOS_BITS) - 1, | ||
1102 | 0, 0); | ||
1103 | input_set_abs_params(input, ABS_Y, 0, (1 << MAX_RLPOS_BITS) - 1, | ||
1104 | 0, 0); | ||
1105 | } | ||
880 | 1106 | ||
881 | st->ts_input = input; | 1107 | st->ts_input = input; |
882 | input_set_drvdata(input, st); | 1108 | input_set_drvdata(input, st); |
883 | 1109 | ||
884 | ret = input_register_device(input); | 1110 | ret = input_register_device(input); |
885 | if (ret) | 1111 | if (ret) |
886 | input_free_device(st->ts_input); | 1112 | goto err; |
887 | 1113 | ||
888 | return ret; | 1114 | return ret; |
1115 | |||
1116 | err: | ||
1117 | input_free_device(st->ts_input); | ||
1118 | return ret; | ||
889 | } | 1119 | } |
890 | 1120 | ||
891 | static void at91_ts_unregister(struct at91_adc_state *st) | 1121 | static void at91_ts_unregister(struct at91_adc_state *st) |
@@ -943,11 +1173,13 @@ static int at91_adc_probe(struct platform_device *pdev) | |||
943 | */ | 1173 | */ |
944 | at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST); | 1174 | at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST); |
945 | at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF); | 1175 | at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF); |
946 | ret = request_irq(st->irq, | 1176 | |
947 | at91_adc_interrupt, | 1177 | if (st->caps->has_tsmr) |
948 | 0, | 1178 | ret = request_irq(st->irq, at91_adc_9x5_interrupt, 0, |
949 | pdev->dev.driver->name, | 1179 | pdev->dev.driver->name, idev); |
950 | idev); | 1180 | else |
1181 | ret = request_irq(st->irq, at91_adc_rl_interrupt, 0, | ||
1182 | pdev->dev.driver->name, idev); | ||
951 | if (ret) { | 1183 | if (ret) { |
952 | dev_err(&pdev->dev, "Failed to allocate IRQ.\n"); | 1184 | dev_err(&pdev->dev, "Failed to allocate IRQ.\n"); |
953 | return ret; | 1185 | return ret; |
@@ -1051,12 +1283,6 @@ static int at91_adc_probe(struct platform_device *pdev) | |||
1051 | goto error_disable_adc_clk; | 1283 | goto error_disable_adc_clk; |
1052 | } | 1284 | } |
1053 | } else { | 1285 | } else { |
1054 | if (!st->caps->has_tsmr) { | ||
1055 | dev_err(&pdev->dev, "We don't support non-TSMR adc\n"); | ||
1056 | ret = -ENODEV; | ||
1057 | goto error_disable_adc_clk; | ||
1058 | } | ||
1059 | |||
1060 | ret = at91_ts_register(st, pdev); | 1286 | ret = at91_ts_register(st, pdev); |
1061 | if (ret) | 1287 | if (ret) |
1062 | goto error_disable_adc_clk; | 1288 | goto error_disable_adc_clk; |
@@ -1120,6 +1346,20 @@ static struct at91_adc_caps at91sam9260_caps = { | |||
1120 | }, | 1346 | }, |
1121 | }; | 1347 | }; |
1122 | 1348 | ||
1349 | static struct at91_adc_caps at91sam9rl_caps = { | ||
1350 | .has_ts = true, | ||
1351 | .calc_startup_ticks = calc_startup_ticks_9260, /* same as 9260 */ | ||
1352 | .num_channels = 6, | ||
1353 | .registers = { | ||
1354 | .channel_base = AT91_ADC_CHR(0), | ||
1355 | .drdy_mask = AT91_ADC_DRDY, | ||
1356 | .status_register = AT91_ADC_SR, | ||
1357 | .trigger_register = AT91_ADC_TRGR_9G45, | ||
1358 | .mr_prescal_mask = AT91_ADC_PRESCAL_9260, | ||
1359 | .mr_startup_mask = AT91_ADC_STARTUP_9G45, | ||
1360 | }, | ||
1361 | }; | ||
1362 | |||
1123 | static struct at91_adc_caps at91sam9g45_caps = { | 1363 | static struct at91_adc_caps at91sam9g45_caps = { |
1124 | .has_ts = true, | 1364 | .has_ts = true, |
1125 | .calc_startup_ticks = calc_startup_ticks_9260, /* same as 9260 */ | 1365 | .calc_startup_ticks = calc_startup_ticks_9260, /* same as 9260 */ |
@@ -1154,6 +1394,7 @@ static struct at91_adc_caps at91sam9x5_caps = { | |||
1154 | 1394 | ||
1155 | static const struct of_device_id at91_adc_dt_ids[] = { | 1395 | static const struct of_device_id at91_adc_dt_ids[] = { |
1156 | { .compatible = "atmel,at91sam9260-adc", .data = &at91sam9260_caps }, | 1396 | { .compatible = "atmel,at91sam9260-adc", .data = &at91sam9260_caps }, |
1397 | { .compatible = "atmel,at91sam9rl-adc", .data = &at91sam9rl_caps }, | ||
1157 | { .compatible = "atmel,at91sam9g45-adc", .data = &at91sam9g45_caps }, | 1398 | { .compatible = "atmel,at91sam9g45-adc", .data = &at91sam9g45_caps }, |
1158 | { .compatible = "atmel,at91sam9x5-adc", .data = &at91sam9x5_caps }, | 1399 | { .compatible = "atmel,at91sam9x5-adc", .data = &at91sam9x5_caps }, |
1159 | {}, | 1400 | {}, |
@@ -1165,6 +1406,9 @@ static const struct platform_device_id at91_adc_ids[] = { | |||
1165 | .name = "at91sam9260-adc", | 1406 | .name = "at91sam9260-adc", |
1166 | .driver_data = (unsigned long)&at91sam9260_caps, | 1407 | .driver_data = (unsigned long)&at91sam9260_caps, |
1167 | }, { | 1408 | }, { |
1409 | .name = "at91sam9rl-adc", | ||
1410 | .driver_data = (unsigned long)&at91sam9rl_caps, | ||
1411 | }, { | ||
1168 | .name = "at91sam9g45-adc", | 1412 | .name = "at91sam9g45-adc", |
1169 | .driver_data = (unsigned long)&at91sam9g45_caps, | 1413 | .driver_data = (unsigned long)&at91sam9g45_caps, |
1170 | }, { | 1414 | }, { |
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 68edc9db2c64..0b5965ba51bc 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
@@ -550,18 +550,6 @@ config TOUCHSCREEN_TI_AM335X_TSC | |||
550 | To compile this driver as a module, choose M here: the | 550 | To compile this driver as a module, choose M here: the |
551 | module will be called ti_am335x_tsc. | 551 | module will be called ti_am335x_tsc. |
552 | 552 | ||
553 | config TOUCHSCREEN_ATMEL_TSADCC | ||
554 | tristate "Atmel Touchscreen Interface" | ||
555 | depends on ARCH_AT91 | ||
556 | help | ||
557 | Say Y here if you have a 4-wire touchscreen connected to the | ||
558 | ADC Controller on your Atmel SoC. | ||
559 | |||
560 | If unsure, say N. | ||
561 | |||
562 | To compile this driver as a module, choose M here: the | ||
563 | module will be called atmel_tsadcc. | ||
564 | |||
565 | config TOUCHSCREEN_UCB1400 | 553 | config TOUCHSCREEN_UCB1400 |
566 | tristate "Philips UCB1400 touchscreen" | 554 | tristate "Philips UCB1400 touchscreen" |
567 | depends on AC97_BUS | 555 | depends on AC97_BUS |
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 4bc954b7c7c3..03f12a1f2218 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile | |||
@@ -13,7 +13,6 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C) += ad7879-i2c.o | |||
13 | obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o | 13 | obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o |
14 | obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o | 14 | obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o |
15 | obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o | 15 | obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o |
16 | obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o | ||
17 | obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o | 16 | obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o |
18 | obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o | 17 | obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o |
19 | obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o | 18 | obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o |
diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c deleted file mode 100644 index a7c9d6967d1e..000000000000 --- a/drivers/input/touchscreen/atmel_tsadcc.c +++ /dev/null | |||
@@ -1,358 +0,0 @@ | |||
1 | /* | ||
2 | * Atmel Touch Screen Driver | ||
3 | * | ||
4 | * Copyright (c) 2008 ATMEL | ||
5 | * Copyright (c) 2008 Dan Liang | ||
6 | * Copyright (c) 2008 TimeSys Corporation | ||
7 | * Copyright (c) 2008 Justin Waters | ||
8 | * | ||
9 | * Based on touchscreen code from Atmel Corporation. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/input.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/clk.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/io.h> | ||
24 | #include <linux/platform_data/atmel.h> | ||
25 | #include <mach/cpu.h> | ||
26 | |||
27 | /* Register definitions based on AT91SAM9RL64 preliminary draft datasheet */ | ||
28 | |||
29 | #define ATMEL_TSADCC_CR 0x00 /* Control register */ | ||
30 | #define ATMEL_TSADCC_SWRST (1 << 0) /* Software Reset*/ | ||
31 | #define ATMEL_TSADCC_START (1 << 1) /* Start conversion */ | ||
32 | |||
33 | #define ATMEL_TSADCC_MR 0x04 /* Mode register */ | ||
34 | #define ATMEL_TSADCC_TSAMOD (3 << 0) /* ADC mode */ | ||
35 | #define ATMEL_TSADCC_TSAMOD_ADC_ONLY_MODE (0x0) /* ADC Mode */ | ||
36 | #define ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE (0x1) /* Touch Screen Only Mode */ | ||
37 | #define ATMEL_TSADCC_LOWRES (1 << 4) /* Resolution selection */ | ||
38 | #define ATMEL_TSADCC_SLEEP (1 << 5) /* Sleep mode */ | ||
39 | #define ATMEL_TSADCC_PENDET (1 << 6) /* Pen Detect selection */ | ||
40 | #define ATMEL_TSADCC_PRES (1 << 7) /* Pressure Measurement Selection */ | ||
41 | #define ATMEL_TSADCC_PRESCAL (0x3f << 8) /* Prescalar Rate Selection */ | ||
42 | #define ATMEL_TSADCC_EPRESCAL (0xff << 8) /* Prescalar Rate Selection (Extended) */ | ||
43 | #define ATMEL_TSADCC_STARTUP (0x7f << 16) /* Start Up time */ | ||
44 | #define ATMEL_TSADCC_SHTIM (0xf << 24) /* Sample & Hold time */ | ||
45 | #define ATMEL_TSADCC_PENDBC (0xf << 28) /* Pen Detect debouncing time */ | ||
46 | |||
47 | #define ATMEL_TSADCC_TRGR 0x08 /* Trigger register */ | ||
48 | #define ATMEL_TSADCC_TRGMOD (7 << 0) /* Trigger mode */ | ||
49 | #define ATMEL_TSADCC_TRGMOD_NONE (0 << 0) | ||
50 | #define ATMEL_TSADCC_TRGMOD_EXT_RISING (1 << 0) | ||
51 | #define ATMEL_TSADCC_TRGMOD_EXT_FALLING (2 << 0) | ||
52 | #define ATMEL_TSADCC_TRGMOD_EXT_ANY (3 << 0) | ||
53 | #define ATMEL_TSADCC_TRGMOD_PENDET (4 << 0) | ||
54 | #define ATMEL_TSADCC_TRGMOD_PERIOD (5 << 0) | ||
55 | #define ATMEL_TSADCC_TRGMOD_CONTINUOUS (6 << 0) | ||
56 | #define ATMEL_TSADCC_TRGPER (0xffff << 16) /* Trigger period */ | ||
57 | |||
58 | #define ATMEL_TSADCC_TSR 0x0C /* Touch Screen register */ | ||
59 | #define ATMEL_TSADCC_TSFREQ (0xf << 0) /* TS Frequency in Interleaved mode */ | ||
60 | #define ATMEL_TSADCC_TSSHTIM (0xf << 24) /* Sample & Hold time */ | ||
61 | |||
62 | #define ATMEL_TSADCC_CHER 0x10 /* Channel Enable register */ | ||
63 | #define ATMEL_TSADCC_CHDR 0x14 /* Channel Disable register */ | ||
64 | #define ATMEL_TSADCC_CHSR 0x18 /* Channel Status register */ | ||
65 | #define ATMEL_TSADCC_CH(n) (1 << (n)) /* Channel number */ | ||
66 | |||
67 | #define ATMEL_TSADCC_SR 0x1C /* Status register */ | ||
68 | #define ATMEL_TSADCC_EOC(n) (1 << ((n)+0)) /* End of conversion for channel N */ | ||
69 | #define ATMEL_TSADCC_OVRE(n) (1 << ((n)+8)) /* Overrun error for channel N */ | ||
70 | #define ATMEL_TSADCC_DRDY (1 << 16) /* Data Ready */ | ||
71 | #define ATMEL_TSADCC_GOVRE (1 << 17) /* General Overrun Error */ | ||
72 | #define ATMEL_TSADCC_ENDRX (1 << 18) /* End of RX Buffer */ | ||
73 | #define ATMEL_TSADCC_RXBUFF (1 << 19) /* TX Buffer full */ | ||
74 | #define ATMEL_TSADCC_PENCNT (1 << 20) /* Pen contact */ | ||
75 | #define ATMEL_TSADCC_NOCNT (1 << 21) /* No contact */ | ||
76 | |||
77 | #define ATMEL_TSADCC_LCDR 0x20 /* Last Converted Data register */ | ||
78 | #define ATMEL_TSADCC_DATA (0x3ff << 0) /* Channel data */ | ||
79 | |||
80 | #define ATMEL_TSADCC_IER 0x24 /* Interrupt Enable register */ | ||
81 | #define ATMEL_TSADCC_IDR 0x28 /* Interrupt Disable register */ | ||
82 | #define ATMEL_TSADCC_IMR 0x2C /* Interrupt Mask register */ | ||
83 | #define ATMEL_TSADCC_CDR0 0x30 /* Channel Data 0 */ | ||
84 | #define ATMEL_TSADCC_CDR1 0x34 /* Channel Data 1 */ | ||
85 | #define ATMEL_TSADCC_CDR2 0x38 /* Channel Data 2 */ | ||
86 | #define ATMEL_TSADCC_CDR3 0x3C /* Channel Data 3 */ | ||
87 | #define ATMEL_TSADCC_CDR4 0x40 /* Channel Data 4 */ | ||
88 | #define ATMEL_TSADCC_CDR5 0x44 /* Channel Data 5 */ | ||
89 | |||
90 | #define ATMEL_TSADCC_XPOS 0x50 | ||
91 | #define ATMEL_TSADCC_Z1DAT 0x54 | ||
92 | #define ATMEL_TSADCC_Z2DAT 0x58 | ||
93 | |||
94 | #define PRESCALER_VAL(x) ((x) >> 8) | ||
95 | |||
96 | #define ADC_DEFAULT_CLOCK 100000 | ||
97 | |||
98 | struct atmel_tsadcc { | ||
99 | struct input_dev *input; | ||
100 | char phys[32]; | ||
101 | struct clk *clk; | ||
102 | int irq; | ||
103 | unsigned int prev_absx; | ||
104 | unsigned int prev_absy; | ||
105 | unsigned char bufferedmeasure; | ||
106 | }; | ||
107 | |||
108 | static void __iomem *tsc_base; | ||
109 | |||
110 | #define atmel_tsadcc_read(reg) __raw_readl(tsc_base + (reg)) | ||
111 | #define atmel_tsadcc_write(reg, val) __raw_writel((val), tsc_base + (reg)) | ||
112 | |||
113 | static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev) | ||
114 | { | ||
115 | struct atmel_tsadcc *ts_dev = (struct atmel_tsadcc *)dev; | ||
116 | struct input_dev *input_dev = ts_dev->input; | ||
117 | |||
118 | unsigned int status; | ||
119 | unsigned int reg; | ||
120 | |||
121 | status = atmel_tsadcc_read(ATMEL_TSADCC_SR); | ||
122 | status &= atmel_tsadcc_read(ATMEL_TSADCC_IMR); | ||
123 | |||
124 | if (status & ATMEL_TSADCC_NOCNT) { | ||
125 | /* Contact lost */ | ||
126 | reg = atmel_tsadcc_read(ATMEL_TSADCC_MR) | ATMEL_TSADCC_PENDBC; | ||
127 | |||
128 | atmel_tsadcc_write(ATMEL_TSADCC_MR, reg); | ||
129 | atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE); | ||
130 | atmel_tsadcc_write(ATMEL_TSADCC_IDR, | ||
131 | ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT); | ||
132 | atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT); | ||
133 | |||
134 | input_report_key(input_dev, BTN_TOUCH, 0); | ||
135 | ts_dev->bufferedmeasure = 0; | ||
136 | input_sync(input_dev); | ||
137 | |||
138 | } else if (status & ATMEL_TSADCC_PENCNT) { | ||
139 | /* Pen detected */ | ||
140 | reg = atmel_tsadcc_read(ATMEL_TSADCC_MR); | ||
141 | reg &= ~ATMEL_TSADCC_PENDBC; | ||
142 | |||
143 | atmel_tsadcc_write(ATMEL_TSADCC_IDR, ATMEL_TSADCC_PENCNT); | ||
144 | atmel_tsadcc_write(ATMEL_TSADCC_MR, reg); | ||
145 | atmel_tsadcc_write(ATMEL_TSADCC_IER, | ||
146 | ATMEL_TSADCC_EOC(3) | ATMEL_TSADCC_NOCNT); | ||
147 | atmel_tsadcc_write(ATMEL_TSADCC_TRGR, | ||
148 | ATMEL_TSADCC_TRGMOD_PERIOD | (0x0FFF << 16)); | ||
149 | |||
150 | } else if (status & ATMEL_TSADCC_EOC(3)) { | ||
151 | /* Conversion finished */ | ||
152 | |||
153 | if (ts_dev->bufferedmeasure) { | ||
154 | /* Last measurement is always discarded, since it can | ||
155 | * be erroneous. | ||
156 | * Always report previous measurement */ | ||
157 | input_report_abs(input_dev, ABS_X, ts_dev->prev_absx); | ||
158 | input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy); | ||
159 | input_report_key(input_dev, BTN_TOUCH, 1); | ||
160 | input_sync(input_dev); | ||
161 | } else | ||
162 | ts_dev->bufferedmeasure = 1; | ||
163 | |||
164 | /* Now make new measurement */ | ||
165 | ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10; | ||
166 | ts_dev->prev_absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2); | ||
167 | |||
168 | ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10; | ||
169 | ts_dev->prev_absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0); | ||
170 | } | ||
171 | |||
172 | return IRQ_HANDLED; | ||
173 | } | ||
174 | |||
175 | /* | ||
176 | * The functions for inserting/removing us as a module. | ||
177 | */ | ||
178 | |||
179 | static int atmel_tsadcc_probe(struct platform_device *pdev) | ||
180 | { | ||
181 | struct atmel_tsadcc *ts_dev; | ||
182 | struct input_dev *input_dev; | ||
183 | struct resource *res; | ||
184 | struct at91_tsadcc_data *pdata = dev_get_platdata(&pdev->dev); | ||
185 | int err; | ||
186 | unsigned int prsc; | ||
187 | unsigned int reg; | ||
188 | |||
189 | if (!pdata) | ||
190 | return -EINVAL; | ||
191 | |||
192 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
193 | if (!res) { | ||
194 | dev_err(&pdev->dev, "no mmio resource defined.\n"); | ||
195 | return -ENXIO; | ||
196 | } | ||
197 | |||
198 | /* Allocate memory for device */ | ||
199 | ts_dev = kzalloc(sizeof(struct atmel_tsadcc), GFP_KERNEL); | ||
200 | if (!ts_dev) { | ||
201 | dev_err(&pdev->dev, "failed to allocate memory.\n"); | ||
202 | return -ENOMEM; | ||
203 | } | ||
204 | platform_set_drvdata(pdev, ts_dev); | ||
205 | |||
206 | input_dev = input_allocate_device(); | ||
207 | if (!input_dev) { | ||
208 | dev_err(&pdev->dev, "failed to allocate input device.\n"); | ||
209 | err = -EBUSY; | ||
210 | goto err_free_mem; | ||
211 | } | ||
212 | |||
213 | ts_dev->irq = platform_get_irq(pdev, 0); | ||
214 | if (ts_dev->irq < 0) { | ||
215 | dev_err(&pdev->dev, "no irq ID is designated.\n"); | ||
216 | err = -ENODEV; | ||
217 | goto err_free_dev; | ||
218 | } | ||
219 | |||
220 | if (!request_mem_region(res->start, resource_size(res), | ||
221 | "atmel tsadcc regs")) { | ||
222 | dev_err(&pdev->dev, "resources is unavailable.\n"); | ||
223 | err = -EBUSY; | ||
224 | goto err_free_dev; | ||
225 | } | ||
226 | |||
227 | tsc_base = ioremap(res->start, resource_size(res)); | ||
228 | if (!tsc_base) { | ||
229 | dev_err(&pdev->dev, "failed to map registers.\n"); | ||
230 | err = -ENOMEM; | ||
231 | goto err_release_mem; | ||
232 | } | ||
233 | |||
234 | err = request_irq(ts_dev->irq, atmel_tsadcc_interrupt, 0, | ||
235 | pdev->dev.driver->name, ts_dev); | ||
236 | if (err) { | ||
237 | dev_err(&pdev->dev, "failed to allocate irq.\n"); | ||
238 | goto err_unmap_regs; | ||
239 | } | ||
240 | |||
241 | ts_dev->clk = clk_get(&pdev->dev, "tsc_clk"); | ||
242 | if (IS_ERR(ts_dev->clk)) { | ||
243 | dev_err(&pdev->dev, "failed to get ts_clk\n"); | ||
244 | err = PTR_ERR(ts_dev->clk); | ||
245 | goto err_free_irq; | ||
246 | } | ||
247 | |||
248 | ts_dev->input = input_dev; | ||
249 | ts_dev->bufferedmeasure = 0; | ||
250 | |||
251 | snprintf(ts_dev->phys, sizeof(ts_dev->phys), | ||
252 | "%s/input0", dev_name(&pdev->dev)); | ||
253 | |||
254 | input_dev->name = "atmel touch screen controller"; | ||
255 | input_dev->phys = ts_dev->phys; | ||
256 | input_dev->dev.parent = &pdev->dev; | ||
257 | |||
258 | __set_bit(EV_ABS, input_dev->evbit); | ||
259 | input_set_abs_params(input_dev, ABS_X, 0, 0x3FF, 0, 0); | ||
260 | input_set_abs_params(input_dev, ABS_Y, 0, 0x3FF, 0, 0); | ||
261 | |||
262 | input_set_capability(input_dev, EV_KEY, BTN_TOUCH); | ||
263 | |||
264 | /* clk_enable() always returns 0, no need to check it */ | ||
265 | clk_enable(ts_dev->clk); | ||
266 | |||
267 | prsc = clk_get_rate(ts_dev->clk); | ||
268 | dev_info(&pdev->dev, "Master clock is set at: %d Hz\n", prsc); | ||
269 | |||
270 | if (!pdata->adc_clock) | ||
271 | pdata->adc_clock = ADC_DEFAULT_CLOCK; | ||
272 | |||
273 | prsc = (prsc / (2 * pdata->adc_clock)) - 1; | ||
274 | |||
275 | /* saturate if this value is too high */ | ||
276 | if (cpu_is_at91sam9rl()) { | ||
277 | if (prsc > PRESCALER_VAL(ATMEL_TSADCC_PRESCAL)) | ||
278 | prsc = PRESCALER_VAL(ATMEL_TSADCC_PRESCAL); | ||
279 | } else { | ||
280 | if (prsc > PRESCALER_VAL(ATMEL_TSADCC_EPRESCAL)) | ||
281 | prsc = PRESCALER_VAL(ATMEL_TSADCC_EPRESCAL); | ||
282 | } | ||
283 | |||
284 | dev_info(&pdev->dev, "Prescaler is set at: %d\n", prsc); | ||
285 | |||
286 | reg = ATMEL_TSADCC_TSAMOD_TS_ONLY_MODE | | ||
287 | ((0x00 << 5) & ATMEL_TSADCC_SLEEP) | /* Normal Mode */ | ||
288 | ((0x01 << 6) & ATMEL_TSADCC_PENDET) | /* Enable Pen Detect */ | ||
289 | (prsc << 8) | | ||
290 | ((0x26 << 16) & ATMEL_TSADCC_STARTUP) | | ||
291 | ((pdata->pendet_debounce << 28) & ATMEL_TSADCC_PENDBC); | ||
292 | |||
293 | atmel_tsadcc_write(ATMEL_TSADCC_CR, ATMEL_TSADCC_SWRST); | ||
294 | atmel_tsadcc_write(ATMEL_TSADCC_MR, reg); | ||
295 | atmel_tsadcc_write(ATMEL_TSADCC_TRGR, ATMEL_TSADCC_TRGMOD_NONE); | ||
296 | atmel_tsadcc_write(ATMEL_TSADCC_TSR, | ||
297 | (pdata->ts_sample_hold_time << 24) & ATMEL_TSADCC_TSSHTIM); | ||
298 | |||
299 | atmel_tsadcc_read(ATMEL_TSADCC_SR); | ||
300 | atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT); | ||
301 | |||
302 | /* All went ok, so register to the input system */ | ||
303 | err = input_register_device(input_dev); | ||
304 | if (err) | ||
305 | goto err_fail; | ||
306 | |||
307 | return 0; | ||
308 | |||
309 | err_fail: | ||
310 | clk_disable(ts_dev->clk); | ||
311 | clk_put(ts_dev->clk); | ||
312 | err_free_irq: | ||
313 | free_irq(ts_dev->irq, ts_dev); | ||
314 | err_unmap_regs: | ||
315 | iounmap(tsc_base); | ||
316 | err_release_mem: | ||
317 | release_mem_region(res->start, resource_size(res)); | ||
318 | err_free_dev: | ||
319 | input_free_device(input_dev); | ||
320 | err_free_mem: | ||
321 | kfree(ts_dev); | ||
322 | return err; | ||
323 | } | ||
324 | |||
325 | static int atmel_tsadcc_remove(struct platform_device *pdev) | ||
326 | { | ||
327 | struct atmel_tsadcc *ts_dev = platform_get_drvdata(pdev); | ||
328 | struct resource *res; | ||
329 | |||
330 | free_irq(ts_dev->irq, ts_dev); | ||
331 | |||
332 | input_unregister_device(ts_dev->input); | ||
333 | |||
334 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
335 | iounmap(tsc_base); | ||
336 | release_mem_region(res->start, resource_size(res)); | ||
337 | |||
338 | clk_disable(ts_dev->clk); | ||
339 | clk_put(ts_dev->clk); | ||
340 | |||
341 | kfree(ts_dev); | ||
342 | |||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | static struct platform_driver atmel_tsadcc_driver = { | ||
347 | .probe = atmel_tsadcc_probe, | ||
348 | .remove = atmel_tsadcc_remove, | ||
349 | .driver = { | ||
350 | .name = "atmel_tsadcc", | ||
351 | }, | ||
352 | }; | ||
353 | module_platform_driver(atmel_tsadcc_driver); | ||
354 | |||
355 | MODULE_LICENSE("GPL"); | ||
356 | MODULE_DESCRIPTION("Atmel TouchScreen Driver"); | ||
357 | MODULE_AUTHOR("Dan Liang <dan.liang@atmel.com>"); | ||
358 | |||