ARM: OMAP: dmtimer: switch-over to platform device driver
[pandora-kernel.git] / arch / arm / plat-omap / dmtimer.c
1 /*
2  * linux/arch/arm/plat-omap/dmtimer.c
3  *
4  * OMAP Dual-Mode Timers
5  *
6  * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
7  * Tarun Kanti DebBarma <tarun.kanti@ti.com>
8  * Thara Gopinath <thara@ti.com>
9  *
10  * dmtimer adaptation to platform_driver.
11  *
12  * Copyright (C) 2005 Nokia Corporation
13  * OMAP2 support by Juha Yrjola
14  * API improvements and OMAP2 clock framework support by Timo Teras
15  *
16  * Copyright (C) 2009 Texas Instruments
17  * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
18  *
19  * This program is free software; you can redistribute it and/or modify it
20  * under the terms of the GNU General Public License as published by the
21  * Free Software Foundation; either version 2 of the License, or (at your
22  * option) any later version.
23  *
24  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
25  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
27  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * You should have received a copy of the  GNU General Public License along
34  * with this program; if not, write  to the Free Software Foundation, Inc.,
35  * 675 Mass Ave, Cambridge, MA 02139, USA.
36  */
37
38 #include <linux/io.h>
39 #include <linux/slab.h>
40 #include <linux/err.h>
41
42 #include <plat/dmtimer.h>
43
44 static LIST_HEAD(omap_timer_list);
45 static DEFINE_SPINLOCK(dm_timer_lock);
46
47 /**
48  * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode
49  * @timer:      timer pointer over which read operation to perform
50  * @reg:        lowest byte holds the register offset
51  *
52  * The posted mode bit is encoded in reg. Note that in posted mode write
53  * pending bit must be checked. Otherwise a read of a non completed write
54  * will produce an error.
55  */
56 static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg)
57 {
58         WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
59         return __omap_dm_timer_read(timer, reg, timer->posted);
60 }
61
62 /**
63  * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode
64  * @timer:      timer pointer over which write operation is to perform
65  * @reg:        lowest byte holds the register offset
66  * @value:      data to write into the register
67  *
68  * The posted mode bit is encoded in reg. Note that in posted mode the write
69  * pending bit must be checked. Otherwise a write on a register which has a
70  * pending write will be lost.
71  */
72 static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
73                                                 u32 value)
74 {
75         WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET);
76         __omap_dm_timer_write(timer, reg, value, timer->posted);
77 }
78
79 static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer)
80 {
81         int c;
82
83         if (!timer->sys_stat)
84                 return;
85
86         c = 0;
87         while (!(__raw_readl(timer->sys_stat) & 1)) {
88                 c++;
89                 if (c > 100000) {
90                         printk(KERN_ERR "Timer failed to reset\n");
91                         return;
92                 }
93         }
94 }
95
96 static void omap_dm_timer_reset(struct omap_dm_timer *timer)
97 {
98         if (timer->pdev->id != 1) {
99                 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
100                 omap_dm_timer_wait_for_reset(timer);
101         }
102
103         __omap_dm_timer_reset(timer, 0, 0);
104         timer->posted = 1;
105 }
106
107 int omap_dm_timer_prepare(struct omap_dm_timer *timer)
108 {
109         struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
110         int ret;
111
112         timer->fclk = clk_get(&timer->pdev->dev, "fck");
113         if (WARN_ON_ONCE(IS_ERR_OR_NULL(timer->fclk))) {
114                 timer->fclk = NULL;
115                 dev_err(&timer->pdev->dev, ": No fclk handle.\n");
116                 return -EINVAL;
117         }
118
119         omap_dm_timer_enable(timer);
120
121         if (pdata->needs_manual_reset)
122                 omap_dm_timer_reset(timer);
123
124         ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
125
126         timer->posted = 1;
127         return ret;
128 }
129
130 struct omap_dm_timer *omap_dm_timer_request(void)
131 {
132         struct omap_dm_timer *timer = NULL, *t;
133         unsigned long flags;
134         int ret = 0;
135
136         spin_lock_irqsave(&dm_timer_lock, flags);
137         list_for_each_entry(t, &omap_timer_list, node) {
138                 if (t->reserved)
139                         continue;
140
141                 timer = t;
142                 timer->reserved = 1;
143                 break;
144         }
145
146         if (timer) {
147                 ret = omap_dm_timer_prepare(timer);
148                 if (ret) {
149                         timer->reserved = 0;
150                         timer = NULL;
151                 }
152         }
153         spin_unlock_irqrestore(&dm_timer_lock, flags);
154
155         if (!timer)
156                 pr_debug("%s: timer request failed!\n", __func__);
157
158         return timer;
159 }
160 EXPORT_SYMBOL_GPL(omap_dm_timer_request);
161
162 struct omap_dm_timer *omap_dm_timer_request_specific(int id)
163 {
164         struct omap_dm_timer *timer = NULL, *t;
165         unsigned long flags;
166         int ret = 0;
167
168         spin_lock_irqsave(&dm_timer_lock, flags);
169         list_for_each_entry(t, &omap_timer_list, node) {
170                 if (t->pdev->id == id && !t->reserved) {
171                         timer = t;
172                         timer->reserved = 1;
173                         break;
174                 }
175         }
176
177         if (timer) {
178                 ret = omap_dm_timer_prepare(timer);
179                 if (ret) {
180                         timer->reserved = 0;
181                         timer = NULL;
182                 }
183         }
184         spin_unlock_irqrestore(&dm_timer_lock, flags);
185
186         if (!timer)
187                 pr_debug("%s: timer%d request failed!\n", __func__, id);
188
189         return timer;
190 }
191 EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
192
193 void omap_dm_timer_free(struct omap_dm_timer *timer)
194 {
195         omap_dm_timer_disable(timer);
196         clk_put(timer->fclk);
197
198         WARN_ON(!timer->reserved);
199         timer->reserved = 0;
200 }
201 EXPORT_SYMBOL_GPL(omap_dm_timer_free);
202
203 void omap_dm_timer_enable(struct omap_dm_timer *timer)
204 {
205         struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
206
207         if (timer->enabled)
208                 return;
209
210         if (!pdata->needs_manual_reset) {
211                 clk_enable(timer->fclk);
212                 clk_enable(timer->iclk);
213         }
214
215         timer->enabled = 1;
216 }
217 EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
218
219 void omap_dm_timer_disable(struct omap_dm_timer *timer)
220 {
221         struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
222
223         if (!timer->enabled)
224                 return;
225
226         if (!pdata->needs_manual_reset) {
227                 clk_disable(timer->iclk);
228                 clk_disable(timer->fclk);
229         }
230
231         timer->enabled = 0;
232 }
233 EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
234
235 int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
236 {
237         return timer->irq;
238 }
239 EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
240
241 #if defined(CONFIG_ARCH_OMAP1)
242
243 /**
244  * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
245  * @inputmask: current value of idlect mask
246  */
247 __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
248 {
249         int i = 0;
250         struct omap_dm_timer *timer = NULL;
251         unsigned long flags;
252
253         /* If ARMXOR cannot be idled this function call is unnecessary */
254         if (!(inputmask & (1 << 1)))
255                 return inputmask;
256
257         /* If any active timer is using ARMXOR return modified mask */
258         spin_lock_irqsave(&dm_timer_lock, flags);
259         list_for_each_entry(timer, &omap_timer_list, node) {
260                 u32 l;
261
262                 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
263                 if (l & OMAP_TIMER_CTRL_ST) {
264                         if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0)
265                                 inputmask &= ~(1 << 1);
266                         else
267                                 inputmask &= ~(1 << 2);
268                 }
269                 i++;
270         }
271         spin_unlock_irqrestore(&dm_timer_lock, flags);
272
273         return inputmask;
274 }
275 EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
276
277 #else
278
279 struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
280 {
281         return timer->fclk;
282 }
283 EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk);
284
285 __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
286 {
287         BUG();
288
289         return 0;
290 }
291 EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask);
292
293 #endif
294
295 void omap_dm_timer_trigger(struct omap_dm_timer *timer)
296 {
297         omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
298 }
299 EXPORT_SYMBOL_GPL(omap_dm_timer_trigger);
300
301 void omap_dm_timer_start(struct omap_dm_timer *timer)
302 {
303         u32 l;
304
305         l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
306         if (!(l & OMAP_TIMER_CTRL_ST)) {
307                 l |= OMAP_TIMER_CTRL_ST;
308                 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
309         }
310 }
311 EXPORT_SYMBOL_GPL(omap_dm_timer_start);
312
313 void omap_dm_timer_stop(struct omap_dm_timer *timer)
314 {
315         unsigned long rate = 0;
316         struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
317
318         if (!pdata->needs_manual_reset)
319                 rate = clk_get_rate(timer->fclk);
320
321         __omap_dm_timer_stop(timer, timer->posted, rate);
322 }
323 EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
324
325 int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
326 {
327         int ret;
328         struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
329
330         if (source < 0 || source >= 3)
331                 return -EINVAL;
332
333         omap_dm_timer_disable(timer);
334         ret = pdata->set_timer_src(timer->pdev, source);
335         omap_dm_timer_enable(timer);
336
337         return ret;
338 }
339 EXPORT_SYMBOL_GPL(omap_dm_timer_set_source);
340
341 void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
342                             unsigned int load)
343 {
344         u32 l;
345
346         l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
347         if (autoreload)
348                 l |= OMAP_TIMER_CTRL_AR;
349         else
350                 l &= ~OMAP_TIMER_CTRL_AR;
351         omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
352         omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
353
354         omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0);
355 }
356 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load);
357
358 /* Optimized set_load which removes costly spin wait in timer_start */
359 void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
360                             unsigned int load)
361 {
362         u32 l;
363
364         l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
365         if (autoreload) {
366                 l |= OMAP_TIMER_CTRL_AR;
367                 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
368         } else {
369                 l &= ~OMAP_TIMER_CTRL_AR;
370         }
371         l |= OMAP_TIMER_CTRL_ST;
372
373         __omap_dm_timer_load_start(timer, l, load, timer->posted);
374 }
375 EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start);
376
377 void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
378                              unsigned int match)
379 {
380         u32 l;
381
382         l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
383         if (enable)
384                 l |= OMAP_TIMER_CTRL_CE;
385         else
386                 l &= ~OMAP_TIMER_CTRL_CE;
387         omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
388         omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
389 }
390 EXPORT_SYMBOL_GPL(omap_dm_timer_set_match);
391
392 void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
393                            int toggle, int trigger)
394 {
395         u32 l;
396
397         l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
398         l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
399                OMAP_TIMER_CTRL_PT | (0x03 << 10));
400         if (def_on)
401                 l |= OMAP_TIMER_CTRL_SCPWM;
402         if (toggle)
403                 l |= OMAP_TIMER_CTRL_PT;
404         l |= trigger << 10;
405         omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
406 }
407 EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm);
408
409 void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler)
410 {
411         u32 l;
412
413         l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
414         l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2));
415         if (prescaler >= 0x00 && prescaler <= 0x07) {
416                 l |= OMAP_TIMER_CTRL_PRE;
417                 l |= prescaler << 2;
418         }
419         omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
420 }
421 EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler);
422
423 void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
424                                   unsigned int value)
425 {
426         __omap_dm_timer_int_enable(timer, value);
427 }
428 EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
429
430 unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
431 {
432         unsigned int l;
433
434         l = __raw_readl(timer->irq_stat);
435
436         return l;
437 }
438 EXPORT_SYMBOL_GPL(omap_dm_timer_read_status);
439
440 void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
441 {
442         __omap_dm_timer_write_status(timer, value);
443 }
444 EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
445
446 unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
447 {
448         return __omap_dm_timer_read_counter(timer, timer->posted);
449 }
450 EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter);
451
452 void omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
453 {
454         omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
455 }
456 EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter);
457
458 int omap_dm_timers_active(void)
459 {
460         struct omap_dm_timer *timer;
461
462         list_for_each_entry(timer, &omap_timer_list, node) {
463                 if (!timer->enabled)
464                         continue;
465
466                 if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
467                     OMAP_TIMER_CTRL_ST) {
468                         return 1;
469                 }
470         }
471         return 0;
472 }
473 EXPORT_SYMBOL_GPL(omap_dm_timers_active);
474
475 /**
476  * omap_dm_timer_probe - probe function called for every registered device
477  * @pdev:       pointer to current timer platform device
478  *
479  * Called by driver framework at the end of device registration for all
480  * timer devices.
481  */
482 static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
483 {
484         int ret;
485         unsigned long flags;
486         struct omap_dm_timer *timer;
487         struct resource *mem, *irq, *ioarea;
488         struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
489
490         if (!pdata) {
491                 dev_err(&pdev->dev, "%s: no platform data.\n", __func__);
492                 return -ENODEV;
493         }
494
495         irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
496         if (unlikely(!irq)) {
497                 dev_err(&pdev->dev, "%s: no IRQ resource.\n", __func__);
498                 return -ENODEV;
499         }
500
501         mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
502         if (unlikely(!mem)) {
503                 dev_err(&pdev->dev, "%s: no memory resource.\n", __func__);
504                 return -ENODEV;
505         }
506
507         ioarea = request_mem_region(mem->start, resource_size(mem),
508                         pdev->name);
509         if (!ioarea) {
510                 dev_err(&pdev->dev, "%s: region already claimed.\n", __func__);
511                 return -EBUSY;
512         }
513
514         timer = kzalloc(sizeof(struct omap_dm_timer), GFP_KERNEL);
515         if (!timer) {
516                 dev_err(&pdev->dev, "%s: no memory for omap_dm_timer.\n",
517                         __func__);
518                 ret = -ENOMEM;
519                 goto err_free_ioregion;
520         }
521
522         timer->io_base = ioremap(mem->start, resource_size(mem));
523         if (!timer->io_base) {
524                 dev_err(&pdev->dev, "%s: ioremap failed.\n", __func__);
525                 ret = -ENOMEM;
526                 goto err_free_mem;
527         }
528
529         timer->id = pdev->id;
530         timer->irq = irq->start;
531         timer->pdev = pdev;
532
533         /* add the timer element to the list */
534         spin_lock_irqsave(&dm_timer_lock, flags);
535         list_add_tail(&timer->node, &omap_timer_list);
536         spin_unlock_irqrestore(&dm_timer_lock, flags);
537
538         dev_dbg(&pdev->dev, "Device Probed.\n");
539
540         return 0;
541
542 err_free_mem:
543         kfree(timer);
544
545 err_free_ioregion:
546         release_mem_region(mem->start, resource_size(mem));
547
548         return ret;
549 }
550
551 /**
552  * omap_dm_timer_remove - cleanup a registered timer device
553  * @pdev:       pointer to current timer platform device
554  *
555  * Called by driver framework whenever a timer device is unregistered.
556  * In addition to freeing platform resources it also deletes the timer
557  * entry from the local list.
558  */
559 static int __devexit omap_dm_timer_remove(struct platform_device *pdev)
560 {
561         struct omap_dm_timer *timer;
562         unsigned long flags;
563         int ret = -EINVAL;
564
565         spin_lock_irqsave(&dm_timer_lock, flags);
566         list_for_each_entry(timer, &omap_timer_list, node)
567                 if (timer->pdev->id == pdev->id) {
568                         list_del(&timer->node);
569                         kfree(timer);
570                         ret = 0;
571                         break;
572                 }
573         spin_unlock_irqrestore(&dm_timer_lock, flags);
574
575         return ret;
576 }
577
578 static struct platform_driver omap_dm_timer_driver = {
579         .probe  = omap_dm_timer_probe,
580         .remove = omap_dm_timer_remove,
581         .driver = {
582                 .name   = "omap_timer",
583         },
584 };
585
586 static int __init omap_dm_timer_driver_init(void)
587 {
588         return platform_driver_register(&omap_dm_timer_driver);
589 }
590
591 static void __exit omap_dm_timer_driver_exit(void)
592 {
593         platform_driver_unregister(&omap_dm_timer_driver);
594 }
595
596 early_platform_init("earlytimer", &omap_dm_timer_driver);
597 module_init(omap_dm_timer_driver_init);
598 module_exit(omap_dm_timer_driver_exit);
599
600 MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver");
601 MODULE_LICENSE("GPL");
602 MODULE_ALIAS("platform:" DRIVER_NAME);
603 MODULE_AUTHOR("Texas Instruments Inc");