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.c218
1 files changed, 164 insertions, 54 deletions
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 82231a75abd6..89585c293554 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -35,11 +35,16 @@
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 50
@@ -81,10 +86,6 @@ static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg,
81 86
82static void omap_timer_restore_context(struct omap_dm_timer *timer) 87static void omap_timer_restore_context(struct omap_dm_timer *timer)
83{ 88{
84 if (timer->revision == 1)
85 __raw_writel(timer->context.tistat, timer->sys_stat);
86
87 __raw_writel(timer->context.tisr, timer->irq_stat);
88 omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, 89 omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG,
89 timer->context.twer); 90 timer->context.twer);
90 omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, 91 omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG,
@@ -100,39 +101,38 @@ static void omap_timer_restore_context(struct omap_dm_timer *timer)
100 timer->context.tclr); 101 timer->context.tclr);
101} 102}
102 103
103static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) 104static int omap_dm_timer_reset(struct omap_dm_timer *timer)
104{ 105{
105 int c; 106 u32 l, timeout = 100000;
106 107
107 if (!timer->sys_stat) 108 if (timer->revision != 1)
108 return; 109 return -EINVAL;
109 110
110 c = 0; 111 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
111 while (!(__raw_readl(timer->sys_stat) & 1)) {
112 c++;
113 if (c > 100000) {
114 printk(KERN_ERR "Timer failed to reset\n");
115 return;
116 }
117 }
118}
119 112
120static void omap_dm_timer_reset(struct omap_dm_timer *timer) 113 do {
121{ 114 l = __omap_dm_timer_read(timer,
122 omap_dm_timer_enable(timer); 115 OMAP_TIMER_V1_SYS_STAT_OFFSET, 0);
123 if (timer->pdev->id != 1) { 116 } while (!l && timeout--);
124 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); 117
125 omap_dm_timer_wait_for_reset(timer); 118 if (!timeout) {
119 dev_err(&timer->pdev->dev, "Timer failed to reset\n");
120 return -ETIMEDOUT;
126 } 121 }
127 122
128 __omap_dm_timer_reset(timer, 0, 0); 123 /* Configure timer for smart-idle mode */
129 omap_dm_timer_disable(timer); 124 l = __omap_dm_timer_read(timer, OMAP_TIMER_OCP_CFG_OFFSET, 0);
130 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;
131} 131}
132 132
133int omap_dm_timer_prepare(struct omap_dm_timer *timer) 133static int omap_dm_timer_prepare(struct omap_dm_timer *timer)
134{ 134{
135 int ret; 135 int rc;
136 136
137 /* 137 /*
138 * 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
@@ -147,13 +147,20 @@ int omap_dm_timer_prepare(struct omap_dm_timer *timer)
147 } 147 }
148 } 148 }
149 149
150 if (timer->capability & OMAP_TIMER_NEEDS_RESET) 150 omap_dm_timer_enable(timer);
151 omap_dm_timer_reset(timer); 151
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 }
152 159
153 ret = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ); 160 __omap_dm_timer_enable_posted(timer);
161 omap_dm_timer_disable(timer);
154 162
155 timer->posted = 1; 163 return omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
156 return ret;
157} 164}
158 165
159static inline u32 omap_dm_timer_reserved_systimer(int id) 166static inline u32 omap_dm_timer_reserved_systimer(int id)
@@ -209,6 +216,13 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id)
209 unsigned long flags; 216 unsigned long flags;
210 int ret = 0; 217 int ret = 0;
211 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
212 spin_lock_irqsave(&dm_timer_lock, flags); 226 spin_lock_irqsave(&dm_timer_lock, flags);
213 list_for_each_entry(t, &omap_timer_list, node) { 227 list_for_each_entry(t, &omap_timer_list, node) {
214 if (t->pdev->id == id && !t->reserved) { 228 if (t->pdev->id == id && !t->reserved) {
@@ -234,6 +248,58 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id)
234} 248}
235EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific); 249EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
236 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
237int omap_dm_timer_free(struct omap_dm_timer *timer) 303int omap_dm_timer_free(struct omap_dm_timer *timer)
238{ 304{
239 if (unlikely(!timer)) 305 if (unlikely(!timer))
@@ -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}
@@ -534,8 +593,8 @@ int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable,
534 l |= OMAP_TIMER_CTRL_CE; 593 l |= OMAP_TIMER_CTRL_CE;
535 else 594 else
536 l &= ~OMAP_TIMER_CTRL_CE; 595 l &= ~OMAP_TIMER_CTRL_CE;
537 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
538 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);
539 598
540 /* Save the context */ 599 /* Save the context */
541 timer->context.tclr = l; 600 timer->context.tclr = l;
@@ -611,6 +670,37 @@ int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
611} 670}
612EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable); 671EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable);
613 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
614unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) 704unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
615{ 705{
616 unsigned int l; 706 unsigned int l;
@@ -632,8 +722,7 @@ int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
632 return -EINVAL; 722 return -EINVAL;
633 723
634 __omap_dm_timer_write_status(timer, value); 724 __omap_dm_timer_write_status(timer, value);
635 /* Save the context */ 725
636 timer->context.tisr = value;
637 return 0; 726 return 0;
638} 727}
639EXPORT_SYMBOL_GPL(omap_dm_timer_write_status); 728EXPORT_SYMBOL_GPL(omap_dm_timer_write_status);
@@ -696,7 +785,7 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
696 struct device *dev = &pdev->dev; 785 struct device *dev = &pdev->dev;
697 struct dmtimer_platform_data *pdata = pdev->dev.platform_data; 786 struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
698 787
699 if (!pdata) { 788 if (!pdata && !dev->of_node) {
700 dev_err(dev, "%s: no platform data.\n", __func__); 789 dev_err(dev, "%s: no platform data.\n", __func__);
701 return -ENODEV; 790 return -ENODEV;
702 } 791 }
@@ -725,12 +814,25 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
725 return -ENOMEM; 814 return -ENOMEM;
726 } 815 }
727 816
728 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
729 timer->irq = irq->start; 834 timer->irq = irq->start;
730 timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
731 timer->pdev = pdev; 835 timer->pdev = pdev;
732 timer->capability = pdata->timer_capability;
733 timer->get_context_loss_count = pdata->get_context_loss_count;
734 836
735 /* Skip pm_runtime_enable for OMAP1 */ 837 /* Skip pm_runtime_enable for OMAP1 */
736 if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) { 838 if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
@@ -770,7 +872,8 @@ static int __devexit omap_dm_timer_remove(struct platform_device *pdev)
770 872
771 spin_lock_irqsave(&dm_timer_lock, flags); 873 spin_lock_irqsave(&dm_timer_lock, flags);
772 list_for_each_entry(timer, &omap_timer_list, node) 874 list_for_each_entry(timer, &omap_timer_list, node)
773 if (timer->pdev->id == pdev->id) { 875 if (!strcmp(dev_name(&timer->pdev->dev),
876 dev_name(&pdev->dev))) {
774 list_del(&timer->node); 877 list_del(&timer->node);
775 ret = 0; 878 ret = 0;
776 break; 879 break;
@@ -780,11 +883,18 @@ static int __devexit omap_dm_timer_remove(struct platform_device *pdev)
780 return ret; 883 return ret;
781} 884}
782 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
783static struct platform_driver omap_dm_timer_driver = { 892static struct platform_driver omap_dm_timer_driver = {
784 .probe = omap_dm_timer_probe, 893 .probe = omap_dm_timer_probe,
785 .remove = __devexit_p(omap_dm_timer_remove), 894 .remove = __devexit_p(omap_dm_timer_remove),
786 .driver = { 895 .driver = {
787 .name = "omap_timer", 896 .name = "omap_timer",
897 .of_match_table = of_match_ptr(omap_timer_match),
788 }, 898 },
789}; 899};
790 900