diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-07 20:06:17 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-07 20:06:17 +0200 |
commit | 38f56f33ca381751f9b8910f67e7a805ec0b68cb (patch) | |
tree | 202f2ce60f3f43a948607ec76c8cc48c1cf73a4b /arch/arm/plat-omap/dmtimer.c | |
parent | Merge tag 'soc-for-linus-3' of git://git.kernel.org/pub/scm/linux/kernel/git/... (diff) | |
parent | Merge branch 'late/dt' into next/dt2 (diff) | |
download | linux-38f56f33ca381751f9b8910f67e7a805ec0b68cb.tar.xz linux-38f56f33ca381751f9b8910f67e7a805ec0b68cb.zip |
Merge tag 'dt-for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC device tree updates (part 2) from Arnd Bergmann:
"These are mostly new device tree bindings for existing drivers, as
well as changes to the device tree source files to add support for
those devices, and a couple of new boards, most notably Samsung's
Exynos5 based Chromebook.
The changes depend on earlier platform specific updates and touch the
usual platforms: omap, exynos, tegra, mxs, mvebu and davinci."
* tag 'dt-for-linus-2' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (169 commits)
ARM: exynos: dts: cros5250: add EC device
ARM: dts: Add sbs-battery for exynos5250-snow
ARM: dts: Add i2c-arbitrator bus for exynos5250-snow
ARM: dts: add mshc controller node for Exynos4x12 SoCs
ARM: dts: Add chip-id controller node on Exynos4/5 SoC
ARM: EXYNOS: Create virtual I/O mapping for Chip-ID controller using device tree
ARM: davinci: da850-evm: add SPI flash support
ARM: davinci: da850: override SPI DT node device name
ARM: davinci: da850: add SPI1 DT node
spi/davinci: add DT binding documentation
spi/davinci: no wildcards in DT compatible property
ARM: dts: mvebu: Convert mvebu device tree files to 64 bits
ARM: dts: mvebu: introduce internal-regs node
ARM: dts: mvebu: Convert all the mvebu files to use the range property
ARM: dts: mvebu: move all peripherals inside soc
ARM: dts: mvebu: fix cpus section indentation
ARM: davinci: da850: add EHRPWM & ECAP DT node
ARM/dts: OMAP3: fix pinctrl-single configuration
ARM: dts: Add OMAP3430 SDP NOR flash memory binding
ARM: dts: Add NOR flash bindings for OMAP2420 H4
...
Diffstat (limited to 'arch/arm/plat-omap/dmtimer.c')
-rw-r--r-- | arch/arm/plat-omap/dmtimer.c | 241 |
1 files changed, 144 insertions, 97 deletions
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index e6dbc8dbe6a6..869254cebf84 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -52,6 +52,13 @@ static u32 omap_reserved_systimers; static LIST_HEAD(omap_timer_list); static DEFINE_SPINLOCK(dm_timer_lock); +enum { + REQUEST_ANY = 0, + REQUEST_BY_ID, + REQUEST_BY_CAP, + REQUEST_BY_NODE, +}; + /** * omap_dm_timer_read_reg - read timer registers in posted and non-posted mode * @timer: timer pointer over which read operation to perform @@ -177,29 +184,82 @@ int omap_dm_timer_reserve_systimer(int id) return 0; } -struct omap_dm_timer *omap_dm_timer_request(void) +static struct omap_dm_timer *_omap_dm_timer_request(int req_type, void *data) { struct omap_dm_timer *timer = NULL, *t; + struct device_node *np = NULL; unsigned long flags; - int ret = 0; + u32 cap = 0; + int id = 0; + + switch (req_type) { + case REQUEST_BY_ID: + id = *(int *)data; + break; + case REQUEST_BY_CAP: + cap = *(u32 *)data; + break; + case REQUEST_BY_NODE: + np = (struct device_node *)data; + break; + default: + /* REQUEST_ANY */ + break; + } spin_lock_irqsave(&dm_timer_lock, flags); list_for_each_entry(t, &omap_timer_list, node) { if (t->reserved) continue; - timer = t; - timer->reserved = 1; - break; + switch (req_type) { + case REQUEST_BY_ID: + if (id == t->pdev->id) { + timer = t; + timer->reserved = 1; + goto found; + } + break; + case REQUEST_BY_CAP: + if (cap == (t->capability & 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) + goto found; + } + break; + case REQUEST_BY_NODE: + if (np == t->pdev->dev.of_node) { + timer = t; + timer->reserved = 1; + goto found; + } + break; + default: + /* REQUEST_ANY */ + timer = t; + timer->reserved = 1; + goto found; + } } +found: spin_unlock_irqrestore(&dm_timer_lock, flags); - if (timer) { - ret = omap_dm_timer_prepare(timer); - if (ret) { - timer->reserved = 0; - timer = NULL; - } + if (timer && omap_dm_timer_prepare(timer)) { + timer->reserved = 0; + timer = NULL; } if (!timer) @@ -207,43 +267,23 @@ struct omap_dm_timer *omap_dm_timer_request(void) return timer; } + +struct omap_dm_timer *omap_dm_timer_request(void) +{ + return _omap_dm_timer_request(REQUEST_ANY, NULL); +} EXPORT_SYMBOL_GPL(omap_dm_timer_request); struct omap_dm_timer *omap_dm_timer_request_specific(int id) { - struct omap_dm_timer *timer = NULL, *t; - 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", + pr_warn("%s: Please use omap_dm_timer_request_by_cap/node()\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) { - timer = t; - timer->reserved = 1; - break; - } - } - spin_unlock_irqrestore(&dm_timer_lock, flags); - - if (timer) { - ret = omap_dm_timer_prepare(timer); - if (ret) { - timer->reserved = 0; - timer = NULL; - } - } - - if (!timer) - pr_debug("%s: timer%d request failed!\n", __func__, id); - - return timer; + return _omap_dm_timer_request(REQUEST_BY_ID, &id); } EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific); @@ -258,46 +298,25 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_request_specific); */ struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap) { - struct omap_dm_timer *timer = NULL, *t; - unsigned long flags; + return _omap_dm_timer_request(REQUEST_BY_CAP, &cap); +} +EXPORT_SYMBOL_GPL(omap_dm_timer_request_by_cap); - if (!cap) +/** + * omap_dm_timer_request_by_node - Request a timer by device-tree node + * @np: Pointer to device-tree timer node + * + * Request a timer based upon a device node pointer. Returns pointer to + * timer handle on success and a NULL pointer on failure. + */ +struct omap_dm_timer *omap_dm_timer_request_by_node(struct device_node *np) +{ + if (!np) 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; + return _omap_dm_timer_request(REQUEST_BY_NODE, np); } -EXPORT_SYMBOL_GPL(omap_dm_timer_request_by_cap); +EXPORT_SYMBOL_GPL(omap_dm_timer_request_by_node); int omap_dm_timer_free(struct omap_dm_timer *timer) { @@ -314,7 +333,21 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_free); void omap_dm_timer_enable(struct omap_dm_timer *timer) { + int c; + pm_runtime_get_sync(&timer->pdev->dev); + + if (!(timer->capability & OMAP_TIMER_ALWON)) { + if (timer->get_context_loss_count) { + c = timer->get_context_loss_count(&timer->pdev->dev); + if (c != timer->ctx_loss_count) { + omap_timer_restore_context(timer); + timer->ctx_loss_count = c; + } + } else { + omap_timer_restore_context(timer); + } + } } EXPORT_SYMBOL_GPL(omap_dm_timer_enable); @@ -409,13 +442,6 @@ int omap_dm_timer_start(struct omap_dm_timer *timer) omap_dm_timer_enable(timer); - if (!(timer->capability & OMAP_TIMER_ALWON)) { - if (timer->get_context_loss_count && - timer->get_context_loss_count(&timer->pdev->dev) != - timer->ctx_loss_count) - omap_timer_restore_context(timer); - } - l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); if (!(l & OMAP_TIMER_CTRL_ST)) { l |= OMAP_TIMER_CTRL_ST; @@ -440,12 +466,6 @@ int omap_dm_timer_stop(struct omap_dm_timer *timer) __omap_dm_timer_stop(timer, timer->posted, rate); - if (!(timer->capability & OMAP_TIMER_ALWON)) { - if (timer->get_context_loss_count) - timer->ctx_loss_count = - timer->get_context_loss_count(&timer->pdev->dev); - } - /* * Since the register values are computed and written within * __omap_dm_timer_stop, we need to use read to retrieve the @@ -552,13 +572,6 @@ int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, omap_dm_timer_enable(timer); - if (!(timer->capability & OMAP_TIMER_ALWON)) { - if (timer->get_context_loss_count && - timer->get_context_loss_count(&timer->pdev->dev) != - timer->ctx_loss_count) - omap_timer_restore_context(timer); - } - l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); if (autoreload) { l |= OMAP_TIMER_CTRL_AR; @@ -769,6 +782,8 @@ int omap_dm_timers_active(void) } EXPORT_SYMBOL_GPL(omap_dm_timers_active); +static const struct of_device_id omap_timer_match[]; + /** * omap_dm_timer_probe - probe function called for every registered device * @pdev: pointer to current timer platform device @@ -782,7 +797,11 @@ static int omap_dm_timer_probe(struct platform_device *pdev) struct omap_dm_timer *timer; struct resource *mem, *irq; struct device *dev = &pdev->dev; - struct dmtimer_platform_data *pdata = pdev->dev.platform_data; + const struct of_device_id *match; + const struct dmtimer_platform_data *pdata; + + match = of_match_device(of_match_ptr(omap_timer_match), dev); + pdata = match ? match->data : dev->platform_data; if (!pdata && !dev->of_node) { dev_err(dev, "%s: no platform data.\n", __func__); @@ -823,12 +842,14 @@ static int omap_dm_timer_probe(struct platform_device *pdev) timer->capability |= OMAP_TIMER_SECURE; } else { timer->id = pdev->id; - timer->errata = pdata->timer_errata; timer->capability = pdata->timer_capability; timer->reserved = omap_dm_timer_reserved_systimer(timer->id); timer->get_context_loss_count = pdata->get_context_loss_count; } + if (pdata) + timer->errata = pdata->timer_errata; + timer->irq = irq->start; timer->pdev = pdev; @@ -881,8 +902,34 @@ static int omap_dm_timer_remove(struct platform_device *pdev) return ret; } +static const struct dmtimer_platform_data omap3plus_pdata = { + .timer_errata = OMAP_TIMER_ERRATA_I103_I767, +}; + static const struct of_device_id omap_timer_match[] = { - { .compatible = "ti,omap2-timer", }, + { + .compatible = "ti,omap2420-timer", + }, + { + .compatible = "ti,omap3430-timer", + .data = &omap3plus_pdata, + }, + { + .compatible = "ti,omap4430-timer", + .data = &omap3plus_pdata, + }, + { + .compatible = "ti,omap5430-timer", + .data = &omap3plus_pdata, + }, + { + .compatible = "ti,am335x-timer", + .data = &omap3plus_pdata, + }, + { + .compatible = "ti,am335x-timer-1ms", + .data = &omap3plus_pdata, + }, {}, }; MODULE_DEVICE_TABLE(of, omap_timer_match); |