aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-omap/dmtimer.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-omap/dmtimer.c')
-rw-r--r--arch/arm/plat-omap/dmtimer.c236
1 files changed, 174 insertions, 62 deletions
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 938b50a33439..89585c293554 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -35,16 +35,18 @@
35 * 675 Mass Ave, Cambridge, MA 02139, USA. 35 * 675 Mass Ave, Cambridge, MA 02139, USA.
36 */ 36 */
37 37
38#include <linux/clk.h>
38#include <linux/module.h> 39#include <linux/module.h>
39#include <linux/io.h> 40#include <linux/io.h>
40#include <linux/device.h> 41#include <linux/device.h>
41#include <linux/err.h> 42#include <linux/err.h>
42#include <linux/pm_runtime.h> 43#include <linux/pm_runtime.h>
44#include <linux/of.h>
45#include <linux/of_device.h>
46#include <linux/platform_device.h>
47#include <linux/platform_data/dmtimer-omap.h>
43 48
44#include <plat/dmtimer.h> 49#include <plat/dmtimer.h>
45#include <plat/omap-pm.h>
46
47#include <mach/hardware.h>
48 50
49static u32 omap_reserved_systimers; 51static u32 omap_reserved_systimers;
50static LIST_HEAD(omap_timer_list); 52static LIST_HEAD(omap_timer_list);
@@ -84,10 +86,6 @@ static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
84 86
85static void omap_timer_restore_context(struct omap_dm_timer *timer) 87static void omap_timer_restore_context(struct omap_dm_timer *timer)
86{ 88{
87 if (timer->revision == 1)
88 __raw_writel(timer->context.tistat, timer->sys_stat);
89
90 __raw_writel(timer->context.tisr, timer->irq_stat);
91 omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, 89 omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
92 timer->context.twer); 90 timer->context.twer);
93 omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, 91 omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
@@ -103,39 +101,38 @@ static void omap_timer_restore_context(struct omap_dm_timer *timer)
103 timer->context.tclr); 101 timer->context.tclr);
104} 102}
105 103
106static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) 104static int omap_dm_timer_reset(struct omap_dm_timer *timer)
107{ 105{
108 int c; 106 u32 l, timeout = 100000;
109 107
110 if (!timer->sys_stat) 108 if (timer->revision != 1)
111 return; 109 return -EINVAL;
112 110
113 c = 0; 111 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
114 while (!(__raw_readl(timer->sys_stat) & 1)) {
115 c++;
116 if (c > 100000) {
117 printk(KERN_ERR "Timer failed to reset\n");
118 return;
119 }
120 }
121}
122 112
123static void omap_dm_timer_reset(struct omap_dm_timer *timer) 113 do {
124{ 114 l = __omap_dm_timer_read(timer,
125 omap_dm_timer_enable(timer); 115 OMAP_TIMER_V1_SYS_STAT_OFFSET, 0);
126 if (timer->pdev->id != 1) { 116 } while (!l && timeout--);
127 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); 117
128 omap_dm_timer_wait_for_reset(timer); 118 if (!timeout) {
119 dev_err(&timer->pdev->dev, "Timer failed to reset\n");
120 return -ETIMEDOUT;
129 } 121 }
130 122
131 __omap_dm_timer_reset(timer, 0, 0); 123 /* Configure timer for smart-idle mode */
132 omap_dm_timer_disable(timer); 124 l = __omap_dm_timer_read(timer, OMAP_TIMER_OCP_CFG_OFFSET, 0);
133 timer->posted = 1; 125 l |= 0x2 << 0x3;
126 __omap_dm_timer_write(timer, OMAP_TIMER_OCP_CFG_OFFSET, l, 0);
127
128 timer->posted = 0;
129
130 return 0;
134} 131}
135 132
136int omap_dm_timer_prepare(struct omap_dm_timer *timer) 133static int omap_dm_timer_prepare(struct omap_dm_timer *timer)
137{ 134{
138 int ret; 135 int rc;
139 136
140 /* 137 /*
141 * FIXME: OMAP1 devices do not use the clock framework for dmtimers so 138 * FIXME: OMAP1 devices do not use the clock framework for dmtimers so
@@ -150,13 +147,20 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer)
150 } 147 }
151 } 148 }
152 149
153 if (timer->capability & OMAP_TIMER_NEEDS_RESET) 150 omap_dm_timer_enable(timer);
154 omap_dm_timer_reset(timer);
155 151
156 ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ); 152 if (timer->capability & OMAP_TIMER_NEEDS_RESET) {
153 rc = omap_dm_timer_reset(timer);
154 if (rc) {
155 omap_dm_timer_disable(timer);
156 return rc;
157 }
158 }
157 159
158 timer->posted = 1; 160 __omap_dm_timer_enable_posted(timer);
159 return ret; 161 omap_dm_timer_disable(timer);
162
163 return omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
160} 164}
161 165
162static inline u32 omap_dm_timer_reserved_systimer(int id) 166static inline u32 omap_dm_timer_reserved_systimer(int id)
@@ -212,6 +216,13 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id)
212 unsigned long flags; 216 unsigned long flags;
213 int ret = 0; 217 int ret = 0;
214 218
219 /* Requesting timer by ID is not supported when device tree is used */
220 if (of_have_populated_dt()) {
221 pr_warn("%s: Please use omap_dm_timer_request_by_cap()\n",
222 __func__);
223 return NULL;
224 }
225
215 spin_lock_irqsave(&dm_timer_lock, flags); 226 spin_lock_irqsave(&dm_timer_lock, flags);
216 list_for_each_entry(t, &omap_timer_list, node) { 227 list_for_each_entry(t, &omap_timer_list, node) {
217 if (t->pdev->id == id && !t->reserved) { 228 if (t->pdev->id == id && !t->reserved) {
@@ -237,6 +248,58 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id)
237} 248}
238EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific); 249EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
239 250
251/**
252 * omap_dm_timer_request_by_cap - Request a timer by capability
253 * @cap: Bit mask of capabilities to match
254 *
255 * Find a timer based upon capabilities bit mask. Callers of this function
256 * should use the definitions found in the plat/dmtimer.h file under the
257 * comment "timer capabilities used in hwmod database". Returns pointer to
258 * timer handle on success and a NULL pointer on failure.
259 */
260struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap)
261{
262 struct omap_dm_timer *timer = NULL, *t;
263 unsigned long flags;
264
265 if (!cap)
266 return NULL;
267
268 spin_lock_irqsave(&dm_timer_lock, flags);
269 list_for_each_entry(t, &omap_timer_list, node) {
270 if ((!t->reserved) && ((t->capability & cap) == cap)) {
271 /*
272 * If timer is not NULL, we have already found one timer
273 * but it was not an exact match because it had more
274 * capabilites that what was required. Therefore,
275 * unreserve the last timer found and see if this one
276 * is a better match.
277 */
278 if (timer)
279 timer->reserved = 0;
280
281 timer = t;
282 timer->reserved = 1;
283
284 /* Exit loop early if we find an exact match */
285 if (t->capability == cap)
286 break;
287 }
288 }
289 spin_unlock_irqrestore(&dm_timer_lock, flags);
290
291 if (timer && omap_dm_timer_prepare(timer)) {
292 timer->reserved = 0;
293 timer = NULL;
294 }
295
296 if (!timer)
297 pr_debug("%s: timer request failed!\n", __func__);
298
299 return timer;
300}
301EXPORT_SYMBOL_GPL(omap_dm_timer_request_by_cap);
302
240int omap_dm_timer_free(struct omap_dm_timer *timer) 303int omap_dm_timer_free(struct omap_dm_timer *timer)
241{ 304{
242 if (unlikely(!timer)) 305 if (unlikely(!timer))
@@ -271,7 +334,7 @@ int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
271EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq); 334EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq);
272 335
273#if defined(CONFIG_ARCH_OMAP1) 336#if defined(CONFIG_ARCH_OMAP1)
274 337#include <mach/hardware.h>
275/** 338/**
276 * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR 339 * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
277 * @inputmask: current value of idlect mask 340 * @inputmask: current value of idlect mask
@@ -348,7 +411,8 @@ int omap_dm_timer_start(struct omap_dm_timer *timer)
348 omap_dm_timer_enable(timer); 411 omap_dm_timer_enable(timer);
349 412
350 if (!(timer->capability & OMAP_TIMER_ALWON)) { 413 if (!(timer->capability & OMAP_TIMER_ALWON)) {
351 if (omap_pm_get_dev_context_loss_count(&timer->pdev->dev) != 414 if (timer->get_context_loss_count &&
415 timer->get_context_loss_count(&timer->pdev->dev) !=
352 timer->ctx_loss_count) 416 timer->ctx_loss_count)
353 omap_timer_restore_context(timer); 417 omap_timer_restore_context(timer);
354 } 418 }
@@ -377,9 +441,11 @@ int omap_dm_timer_stop(struct omap_dm_timer *timer)
377 441
378 __omap_dm_timer_stop(timer, timer->posted, rate); 442 __omap_dm_timer_stop(timer, timer->posted, rate);
379 443
380 if (!(timer->capability & OMAP_TIMER_ALWON)) 444 if (!(timer->capability & OMAP_TIMER_ALWON)) {
381 timer->ctx_loss_count = 445 if (timer->get_context_loss_count)
382 omap_pm_get_dev_context_loss_count(&timer->pdev->dev); 446 timer->ctx_loss_count =
447 timer->get_context_loss_count(&timer->pdev->dev);
448 }
383 449
384 /* 450 /*
385 * Since the register values are computed and written within 451 * Since the register values are computed and written within
@@ -388,7 +454,6 @@ int omap_dm_timer_stop(struct omap_dm_timer *timer)
388 */ 454 */
389 timer->context.tclr = 455 timer->context.tclr =
390 omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); 456 omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
391 timer->context.tisr = __raw_readl(timer->irq_stat);
392 omap_dm_timer_disable(timer); 457 omap_dm_timer_disable(timer);
393 return 0; 458 return 0;
394} 459}
@@ -398,7 +463,7 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
398{ 463{
399 int ret; 464 int ret;
400 char *parent_name = NULL; 465 char *parent_name = NULL;
401 struct clk *fclk, *parent; 466 struct clk *parent;
402 struct dmtimer_platform_data *pdata; 467 struct dmtimer_platform_data *pdata;
403 468
404 if (unlikely(!timer)) 469 if (unlikely(!timer))
@@ -414,14 +479,11 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
414 * use the clock framework to set the parent clock. To be removed 479 * use the clock framework to set the parent clock. To be removed
415 * once OMAP1 migrated to using clock framework for dmtimers 480 * once OMAP1 migrated to using clock framework for dmtimers
416 */ 481 */
417 if (pdata->set_timer_src) 482 if (pdata && pdata->set_timer_src)
418 return pdata->set_timer_src(timer->pdev, source); 483 return pdata->set_timer_src(timer->pdev, source);
419 484
420 fclk = clk_get(&timer->pdev->dev, "fck"); 485 if (!timer->fclk)
421 if (IS_ERR_OR_NULL(fclk)) {
422 pr_err("%s: fck not found\n", __func__);
423 return -EINVAL; 486 return -EINVAL;
424 }
425 487
426 switch (source) { 488 switch (source) {
427 case OMAP_TIMER_SRC_SYS_CLK: 489 case OMAP_TIMER_SRC_SYS_CLK:
@@ -440,18 +502,15 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
440 parent = clk_get(&timer->pdev->dev, parent_name); 502 parent = clk_get(&timer->pdev->dev, parent_name);
441 if (IS_ERR_OR_NULL(parent)) { 503 if (IS_ERR_OR_NULL(parent)) {
442 pr_err("%s: %s not found\n", __func__, parent_name); 504 pr_err("%s: %s not found\n", __func__, parent_name);
443 ret = -EINVAL; 505 return -EINVAL;
444 goto out;
445 } 506 }
446 507
447 ret = clk_set_parent(fclk, parent); 508 ret = clk_set_parent(timer->fclk, parent);
448 if (IS_ERR_VALUE(ret)) 509 if (IS_ERR_VALUE(ret))
449 pr_err("%s: failed to set %s as parent\n", __func__, 510 pr_err("%s: failed to set %s as parent\n", __func__,
450 parent_name); 511 parent_name);
451 512
452 clk_put(parent); 513 clk_put(parent);
453out:
454 clk_put(fclk);
455 514
456 return ret; 515 return ret;
457} 516}
@@ -495,7 +554,8 @@ int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload,
495 omap_dm_timer_enable(timer); 554 omap_dm_timer_enable(timer);
496 555
497 if (!(timer->capability & OMAP_TIMER_ALWON)) { 556 if (!(timer->capability & OMAP_TIMER_ALWON)) {
498 if (omap_pm_get_dev_context_loss_count(&timer->pdev->dev) != 557 if (timer->get_context_loss_count &&
558 timer->get_context_loss_count(&timer->pdev->dev) !=
499 timer->ctx_loss_count) 559 timer->ctx_loss_count)
500 omap_timer_restore_context(timer); 560 omap_timer_restore_context(timer);
501 } 561 }
@@ -533,8 +593,8 @@ int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
533 l |= OMAP_TIMER_CTRL_CE; 593 l |= OMAP_TIMER_CTRL_CE;
534 else 594 else
535 l &= ~OMAP_TIMER_CTRL_CE; 595 l &= ~OMAP_TIMER_CTRL_CE;
536 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
537 omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); 596 omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
597 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
538 598
539 /* Save the context */ 599 /* Save the context */
540 timer->context.tclr = l; 600 timer->context.tclr = l;
@@ -610,6 +670,37 @@ int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
610} 670}
611EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable); 671EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
612 672
673/**
674 * omap_dm_timer_set_int_disable - disable timer interrupts
675 * @timer: pointer to timer handle
676 * @mask: bit mask of interrupts to be disabled
677 *
678 * Disables the specified timer interrupts for a timer.
679 */
680int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask)
681{
682 u32 l = mask;
683
684 if (unlikely(!timer))
685 return -EINVAL;
686
687 omap_dm_timer_enable(timer);
688
689 if (timer->revision == 1)
690 l = __raw_readl(timer->irq_ena) & ~mask;
691
692 __raw_writel(l, timer->irq_dis);
693 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG) & ~mask;
694 omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, l);
695
696 /* Save the context */
697 timer->context.tier &= ~mask;
698 timer->context.twer &= ~mask;
699 omap_dm_timer_disable(timer);
700 return 0;
701}
702EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_disable);
703
613unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) 704unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
614{ 705{
615 unsigned int l; 706 unsigned int l;
@@ -631,8 +722,7 @@ int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
631 return -EINVAL; 722 return -EINVAL;
632 723
633 __omap_dm_timer_write_status(timer, value); 724 __omap_dm_timer_write_status(timer, value);
634 /* Save the context */ 725
635 timer->context.tisr = value;
636 return 0; 726 return 0;
637} 727}
638EXPORT_SYMBOL_GPL(omap_dm_timer_write_status); 728EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
@@ -695,7 +785,7 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
695 struct device *dev = &pdev->dev; 785 struct device *dev = &pdev->dev;
696 struct dmtimer_platform_data *pdata = pdev->dev.platform_data; 786 struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
697 787
698 if (!pdata) { 788 if (!pdata && !dev->of_node) {
699 dev_err(dev, "%s: no platform data.\n", __func__); 789 dev_err(dev, "%s: no platform data.\n", __func__);
700 return -ENODEV; 790 return -ENODEV;
701 } 791 }
@@ -724,11 +814,25 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
724 return -ENOMEM; 814 return -ENOMEM;
725 } 815 }
726 816
727 timer->id = pdev->id; 817 if (dev->of_node) {
818 if (of_find_property(dev->of_node, "ti,timer-alwon", NULL))
819 timer->capability |= OMAP_TIMER_ALWON;
820 if (of_find_property(dev->of_node, "ti,timer-dsp", NULL))
821 timer->capability |= OMAP_TIMER_HAS_DSP_IRQ;
822 if (of_find_property(dev->of_node, "ti,timer-pwm", NULL))
823 timer->capability |= OMAP_TIMER_HAS_PWM;
824 if (of_find_property(dev->of_node, "ti,timer-secure", NULL))
825 timer->capability |= OMAP_TIMER_SECURE;
826 } else {
827 timer->id = pdev->id;
828 timer->errata = pdata->timer_errata;
829 timer->capability = pdata->timer_capability;
830 timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
831 timer->get_context_loss_count = pdata->get_context_loss_count;
832 }
833
728 timer->irq = irq->start; 834 timer->irq = irq->start;
729 timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
730 timer->pdev = pdev; 835 timer->pdev = pdev;
731 timer->capability = pdata->timer_capability;
732 836
733 /* Skip pm_runtime_enable for OMAP1 */ 837 /* Skip pm_runtime_enable for OMAP1 */
734 if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) { 838 if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
@@ -768,7 +872,8 @@ static int __devexit omap_dm_timer_remove(struct platform_device *pdev)
768 872
769 spin_lock_irqsave(&dm_timer_lock, flags); 873 spin_lock_irqsave(&dm_timer_lock, flags);
770 list_for_each_entry(timer, &omap_timer_list, node) 874 list_for_each_entry(timer, &omap_timer_list, node)
771 if (timer->pdev->id == pdev->id) { 875 if (!strcmp(dev_name(&timer->pdev->dev),
876 dev_name(&pdev->dev))) {
772 list_del(&timer->node); 877 list_del(&timer->node);
773 ret = 0; 878 ret = 0;
774 break; 879 break;
@@ -778,11 +883,18 @@ static int __devexit omap_dm_timer_remove(struct platform_device *pdev)
778 return ret; 883 return ret;
779} 884}
780 885
886static const struct of_device_id omap_timer_match[] = {
887 { .compatible = "ti,omap2-timer", },
888 {},
889};
890MODULE_DEVICE_TABLE(of, omap_timer_match);
891
781static struct platform_driver omap_dm_timer_driver = { 892static struct platform_driver omap_dm_timer_driver = {
782 .probe = omap_dm_timer_probe, 893 .probe = omap_dm_timer_probe,
783 .remove = __devexit_p(omap_dm_timer_remove), 894 .remove = __devexit_p(omap_dm_timer_remove),
784 .driver = { 895 .driver = {
785 .name = "omap_timer", 896 .name = "omap_timer",
897 .of_match_table = of_match_ptr(omap_timer_match),
786 }, 898 },
787}; 899};
788 900