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