summaryrefslogtreecommitdiff
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.c95
1 files changed, 88 insertions, 7 deletions
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 82231a75abd6..9dca23e4d6b0 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -40,6 +40,8 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <plat/dmtimer.h>
@@ -209,6 +211,13 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id)
unsigned long flags;
int ret = 0;
+ /* Requesting timer by ID is not supported when device tree is used */
+ if (of_have_populated_dt()) {
+ pr_warn("%s: Please use omap_dm_timer_request_by_cap()\n",
+ __func__);
+ return NULL;
+ }
+
spin_lock_irqsave(&dm_timer_lock, flags);
list_for_each_entry(t, &omap_timer_list, node) {
if (t->pdev->id == id && !t->reserved) {
@@ -234,6 +243,58 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id)
}
EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific);
+/**
+ * omap_dm_timer_request_by_cap - Request a timer by capability
+ * @cap: Bit mask of capabilities to match
+ *
+ * Find a timer based upon capabilities bit mask. Callers of this function
+ * should use the definitions found in the plat/dmtimer.h file under the
+ * comment "timer capabilities used in hwmod database". Returns pointer to
+ * timer handle on success and a NULL pointer on failure.
+ */
+struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap)
+{
+ struct omap_dm_timer *timer = NULL, *t;
+ unsigned long flags;
+
+ if (!cap)
+ return NULL;
+
+ spin_lock_irqsave(&dm_timer_lock, flags);
+ list_for_each_entry(t, &omap_timer_list, node) {
+ if ((!t->reserved) && ((t->capability & cap) == cap)) {
+ /*
+ * If timer is not NULL, we have already found one timer
+ * but it was not an exact match because it had more
+ * capabilites that what was required. Therefore,
+ * unreserve the last timer found and see if this one
+ * is a better match.
+ */
+ if (timer)
+ timer->reserved = 0;
+
+ timer = t;
+ timer->reserved = 1;
+
+ /* Exit loop early if we find an exact match */
+ if (t->capability == cap)
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&dm_timer_lock, flags);
+
+ if (timer && omap_dm_timer_prepare(timer)) {
+ timer->reserved = 0;
+ timer = NULL;
+ }
+
+ if (!timer)
+ pr_debug("%s: timer request failed!\n", __func__);
+
+ return timer;
+}
+EXPORT_SYMBOL_GPL(omap_dm_timer_request_by_cap);
+
int omap_dm_timer_free(struct omap_dm_timer *timer)
{
if (unlikely(!timer))
@@ -414,7 +475,7 @@ int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
* use the clock framework to set the parent clock. To be removed
* once OMAP1 migrated to using clock framework for dmtimers
*/
- if (pdata->set_timer_src)
+ if (pdata && pdata->set_timer_src)
return pdata->set_timer_src(timer->pdev, source);
fclk = clk_get(&timer->pdev->dev, "fck");
@@ -696,7 +757,7 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct dmtimer_platform_data *pdata = pdev->dev.platform_data;
- if (!pdata) {
+ if (!pdata && !dev->of_node) {
dev_err(dev, "%s: no platform data.\n", __func__);
return -ENODEV;
}
@@ -725,12 +786,24 @@ static int __devinit omap_dm_timer_probe(struct platform_device *pdev)
return -ENOMEM;
}
- timer->id = pdev->id;
+ if (dev->of_node) {
+ if (of_find_property(dev->of_node, "ti,timer-alwon", NULL))
+ timer->capability |= OMAP_TIMER_ALWON;
+ if (of_find_property(dev->of_node, "ti,timer-dsp", NULL))
+ timer->capability |= OMAP_TIMER_HAS_DSP_IRQ;
+ if (of_find_property(dev->of_node, "ti,timer-pwm", NULL))
+ timer->capability |= OMAP_TIMER_HAS_PWM;
+ if (of_find_property(dev->of_node, "ti,timer-secure", NULL))
+ timer->capability |= OMAP_TIMER_SECURE;
+ } else {
+ timer->id = pdev->id;
+ timer->capability = pdata->timer_capability;
+ timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
+ timer->get_context_loss_count = pdata->get_context_loss_count;
+ }
+
timer->irq = irq->start;
- timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
timer->pdev = pdev;
- timer->capability = pdata->timer_capability;
- timer->get_context_loss_count = pdata->get_context_loss_count;
/* Skip pm_runtime_enable for OMAP1 */
if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
@@ -770,7 +843,8 @@ static int __devexit omap_dm_timer_remove(struct platform_device *pdev)
spin_lock_irqsave(&dm_timer_lock, flags);
list_for_each_entry(timer, &omap_timer_list, node)
- if (timer->pdev->id == pdev->id) {
+ if (!strcmp(dev_name(&timer->pdev->dev),
+ dev_name(&pdev->dev))) {
list_del(&timer->node);
ret = 0;
break;
@@ -780,11 +854,18 @@ static int __devexit omap_dm_timer_remove(struct platform_device *pdev)
return ret;
}
+static const struct of_device_id omap_timer_match[] = {
+ { .compatible = "ti,omap2-timer", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, omap_timer_match);
+
static struct platform_driver omap_dm_timer_driver = {
.probe = omap_dm_timer_probe,
.remove = __devexit_p(omap_dm_timer_remove),
.driver = {
.name = "omap_timer",
+ .of_match_table = of_match_ptr(omap_timer_match),
},
};