diff options
author | Arnd Bergmann <arnd@arndb.de> | 2018-03-07 18:16:07 +0300 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2018-03-07 18:16:07 +0300 |
commit | 6f566c4f304de8a90d520f7ca1925b4ea7dc3581 (patch) | |
tree | dee0e7650ce7896509fd3d47f45d1da3ec59094f /arch/arm | |
parent | 7b80bd29482e692a7286897f4a684ee18dee0f36 (diff) | |
parent | 58a54f03e73d67432216931854363e4ba15839b9 (diff) | |
download | linux-6f566c4f304de8a90d520f7ca1925b4ea7dc3581.tar.xz |
Merge tag 'omap-for-v4.17/timer-signed' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into next/soc
Pull "Move omap timer to drivers for 4.17" from Tony Lindgren:
This series from Keerthy and Ladislav Michl move omap dmtimer code
to drivers. As we don't want to export custom timer functions to
random drivers, we also need to update the related PWM driver to
pass the timer specific functions in platform data.
Note that this series is based on a merge of omap1 specific timer
fix and omap2+ platform data clean-up to keep things working and
make the move a bit simpler.
* tag 'omap-for-v4.17/timer-signed' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap:
clocksource: timer-ti-dm: Check prescaler value
clocksource: timer-ti-dm: Consolidate set source
clocksource: timer-ti-dm: Make unexported functions static
ARM: OMAP: pdata-quirks: Remove unused timer pdata
pwm: pwm-omap-dmtimer: Adapt driver to utilize dmtimer pdata ops
clocksource: timer-ti-dm: Hook device platform data if not already assigned
clocksource: timer-ti-dm: Populate the timer ops to the pdata
clocksource: timer-ti-dm: Add timer ops to the platform data structure
ARM: OMAP: Move dmtimer driver out of plat-omap to drivers under clocksource
clocksource: timer-ti-dm: Replace architecture
ARM: OMAP: Move dmtimer.h out of plat-omap
ARM: OMAP: timer: Wrap the inline functions under OMAP2PLUS define
ARM: OMAP: dmtimer: Remove all the exports
ARM: OMAP: Fix dmtimer init for omap1
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-omap1/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-omap1/pm.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-omap1/timer.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-omap2/pdata-quirks.c | 32 | ||||
-rw-r--r-- | arch/arm/mach-omap2/timer.c | 2 | ||||
-rw-r--r-- | arch/arm/plat-omap/Kconfig | 6 | ||||
-rw-r--r-- | arch/arm/plat-omap/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/plat-omap/dmtimer.c | 1003 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/dmtimer.h | 414 |
9 files changed, 4 insertions, 1459 deletions
diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig index 45c6b733c881..c4694f26b5c4 100644 --- a/arch/arm/mach-omap1/Kconfig +++ b/arch/arm/mach-omap1/Kconfig @@ -30,6 +30,7 @@ config ARCH_OMAP16XX bool "OMAP16xx Based System" select ARCH_OMAP_OTG select CPU_ARM926T + select OMAP_DM_TIMER config OMAP_MUX bool "OMAP multiplexing support" diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c index f1135bf8940e..3e1de14805e4 100644 --- a/arch/arm/mach-omap1/pm.c +++ b/arch/arm/mach-omap1/pm.c @@ -55,7 +55,7 @@ #include <mach/tc.h> #include <mach/mux.h> #include <linux/omap-dma.h> -#include <plat/dmtimer.h> +#include <clocksource/timer-ti-dm.h> #include <mach/irqs.h> diff --git a/arch/arm/mach-omap1/timer.c b/arch/arm/mach-omap1/timer.c index 8fb1ec6fa999..4447210c9b0d 100644 --- a/arch/arm/mach-omap1/timer.c +++ b/arch/arm/mach-omap1/timer.c @@ -27,7 +27,7 @@ #include <linux/platform_device.h> #include <linux/platform_data/dmtimer-omap.h> -#include <plat/dmtimer.h> +#include <clocksource/timer-ti-dm.h> #include "soc.h" diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c index 6b433fce65a5..e7d7fc7ddaa2 100644 --- a/arch/arm/mach-omap2/pdata-quirks.c +++ b/arch/arm/mach-omap2/pdata-quirks.c @@ -24,10 +24,8 @@ #include <linux/platform_data/hsmmc-omap.h> #include <linux/platform_data/iommu-omap.h> #include <linux/platform_data/wkup_m3.h> -#include <linux/platform_data/pwm_omap_dmtimer.h> #include <linux/platform_data/media/ir-rx51.h> #include <linux/platform_data/asoc-ti-mcbsp.h> -#include <plat/dmtimer.h> #include "common.h" #include "common-board-devices.h" @@ -477,33 +475,6 @@ void omap_auxdata_legacy_init(struct device *dev) dev->platform_data = &twl_gpio_auxdata; } -/* Dual mode timer PWM callbacks platdata */ -#if IS_ENABLED(CONFIG_OMAP_DM_TIMER) -static struct pwm_omap_dmtimer_pdata pwm_dmtimer_pdata = { - .request_by_node = omap_dm_timer_request_by_node, - .request_specific = omap_dm_timer_request_specific, - .request = omap_dm_timer_request, - .set_source = omap_dm_timer_set_source, - .get_irq = omap_dm_timer_get_irq, - .set_int_enable = omap_dm_timer_set_int_enable, - .set_int_disable = omap_dm_timer_set_int_disable, - .free = omap_dm_timer_free, - .enable = omap_dm_timer_enable, - .disable = omap_dm_timer_disable, - .get_fclk = omap_dm_timer_get_fclk, - .start = omap_dm_timer_start, - .stop = omap_dm_timer_stop, - .set_load = omap_dm_timer_set_load, - .set_match = omap_dm_timer_set_match, - .set_pwm = omap_dm_timer_set_pwm, - .set_prescaler = omap_dm_timer_set_prescaler, - .read_counter = omap_dm_timer_read_counter, - .write_counter = omap_dm_timer_write_counter, - .read_status = omap_dm_timer_read_status, - .write_status = omap_dm_timer_write_status, -}; -#endif - static struct ir_rx51_platform_data __maybe_unused rx51_ir_data = { .set_max_mpu_wakeup_lat = omap_pm_set_max_mpu_wakeup_lat, }; @@ -572,9 +543,6 @@ static struct of_dev_auxdata omap_auxdata_lookup[] __initdata = { OF_DEV_AUXDATA("ti,am4372-wkup-m3", 0x44d00000, "44d00000.wkup_m3", &wkup_m3_data), #endif -#if IS_ENABLED(CONFIG_OMAP_DM_TIMER) - OF_DEV_AUXDATA("ti,omap-dmtimer-pwm", 0, NULL, &pwm_dmtimer_pdata), -#endif #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) OF_DEV_AUXDATA("ti,omap4-iommu", 0x4a066000, "4a066000.mmu", &omap4_iommu_pdata), diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index d61fbd7a2840..4fb4dc24e5e9 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c @@ -49,7 +49,7 @@ #include "omap_hwmod.h" #include "omap_device.h" #include <plat/counter-32k.h> -#include <plat/dmtimer.h> +#include <clocksource/timer-ti-dm.h> #include "omap-pm.h" #include "soc.h" diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index 7276afee30b3..afc1a1d4f7a5 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -106,12 +106,6 @@ config OMAP3_L2_AUX_SECURE_SERVICE_SET_ID help PPA routine service ID for setting L2 auxiliary control register. -config OMAP_DM_TIMER - bool "Use dual-mode timer" - depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS - help - Select this option if you want to use OMAP Dual-Mode timers. - config OMAP_SERIAL_WAKE bool "Enable wake-up events for serial ports" depends on ARCH_OMAP1 && OMAP_MUX diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile index 47e186729d44..7215ada707e4 100644 --- a/arch/arm/plat-omap/Makefile +++ b/arch/arm/plat-omap/Makefile @@ -9,5 +9,4 @@ obj-y := sram.o dma.o counter_32k.o # omap_device support (OMAP2+ only at the moment) -obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c deleted file mode 100644 index d443e481c3e9..000000000000 --- a/arch/arm/plat-omap/dmtimer.c +++ /dev/null @@ -1,1003 +0,0 @@ -/* - * linux/arch/arm/plat-omap/dmtimer.c - * - * OMAP Dual-Mode Timers - * - * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ - * Tarun Kanti DebBarma <tarun.kanti@ti.com> - * Thara Gopinath <thara@ti.com> - * - * dmtimer adaptation to platform_driver. - * - * Copyright (C) 2005 Nokia Corporation - * OMAP2 support by Juha Yrjola - * API improvements and OMAP2 clock framework support by Timo Teras - * - * Copyright (C) 2009 Texas Instruments - * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/clk.h> -#include <linux/clk-provider.h> -#include <linux/module.h> -#include <linux/io.h> -#include <linux/device.h> -#include <linux/err.h> -#include <linux/pm_runtime.h> -#include <linux/of.h> -#include <linux/of_device.h> -#include <linux/platform_device.h> -#include <linux/platform_data/dmtimer-omap.h> - -#include <plat/dmtimer.h> - -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 - * @reg: lowest byte holds the register offset - * - * The posted mode bit is encoded in reg. Note that in posted mode write - * pending bit must be checked. Otherwise a read of a non completed write - * will produce an error. - */ -static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg) -{ - WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET); - return __omap_dm_timer_read(timer, reg, timer->posted); -} - -/** - * omap_dm_timer_write_reg - write timer registers in posted and non-posted mode - * @timer: timer pointer over which write operation is to perform - * @reg: lowest byte holds the register offset - * @value: data to write into the register - * - * The posted mode bit is encoded in reg. Note that in posted mode the write - * pending bit must be checked. Otherwise a write on a register which has a - * pending write will be lost. - */ -static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg, - u32 value) -{ - WARN_ON((reg & 0xff) < _OMAP_TIMER_WAKEUP_EN_OFFSET); - __omap_dm_timer_write(timer, reg, value, timer->posted); -} - -static void omap_timer_restore_context(struct omap_dm_timer *timer) -{ - omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, - timer->context.twer); - omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, - timer->context.tcrr); - omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, - timer->context.tldr); - omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, - timer->context.tmar); - omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, - timer->context.tsicr); - writel_relaxed(timer->context.tier, timer->irq_ena); - omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, - timer->context.tclr); -} - -static int omap_dm_timer_reset(struct omap_dm_timer *timer) -{ - u32 l, timeout = 100000; - - if (timer->revision != 1) - return -EINVAL; - - omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); - - do { - l = __omap_dm_timer_read(timer, - OMAP_TIMER_V1_SYS_STAT_OFFSET, 0); - } while (!l && timeout--); - - if (!timeout) { - dev_err(&timer->pdev->dev, "Timer failed to reset\n"); - return -ETIMEDOUT; - } - - /* Configure timer for smart-idle mode */ - l = __omap_dm_timer_read(timer, OMAP_TIMER_OCP_CFG_OFFSET, 0); - l |= 0x2 << 0x3; - __omap_dm_timer_write(timer, OMAP_TIMER_OCP_CFG_OFFSET, l, 0); - - timer->posted = 0; - - return 0; -} - -static int omap_dm_timer_of_set_source(struct omap_dm_timer *timer) -{ - int ret; - struct clk *parent; - - /* - * FIXME: OMAP1 devices do not use the clock framework for dmtimers so - * do not call clk_get() for these devices. - */ - if (!timer->fclk) - return -ENODEV; - - parent = clk_get(&timer->pdev->dev, NULL); - if (IS_ERR(parent)) - return -ENODEV; - - ret = clk_set_parent(timer->fclk, parent); - if (ret < 0) - pr_err("%s: failed to set parent\n", __func__); - - clk_put(parent); - - return ret; -} - -static int omap_dm_timer_prepare(struct omap_dm_timer *timer) -{ - int rc; - - /* - * FIXME: OMAP1 devices do not use the clock framework for dmtimers so - * do not call clk_get() for these devices. - */ - if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) { - timer->fclk = clk_get(&timer->pdev->dev, "fck"); - if (WARN_ON_ONCE(IS_ERR(timer->fclk))) { - dev_err(&timer->pdev->dev, ": No fclk handle.\n"); - return -EINVAL; - } - } - - omap_dm_timer_enable(timer); - - if (timer->capability & OMAP_TIMER_NEEDS_RESET) { - rc = omap_dm_timer_reset(timer); - if (rc) { - omap_dm_timer_disable(timer); - return rc; - } - } - - __omap_dm_timer_enable_posted(timer); - omap_dm_timer_disable(timer); - - rc = omap_dm_timer_of_set_source(timer); - if (rc == -ENODEV) - return omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ); - - return rc; -} - -static inline u32 omap_dm_timer_reserved_systimer(int id) -{ - return (omap_reserved_systimers & (1 << (id - 1))) ? 1 : 0; -} - -int omap_dm_timer_reserve_systimer(int id) -{ - if (omap_dm_timer_reserved_systimer(id)) - return -ENODEV; - - omap_reserved_systimers |= (1 << (id - 1)); - - return 0; -} - -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; - 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; - - 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 capabilities than 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 && omap_dm_timer_prepare(timer)) { - timer->reserved = 0; - timer = NULL; - } - - if (!timer) - pr_debug("%s: timer request failed!\n", __func__); - - 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) -{ - /* 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/node()\n", - __func__); - return NULL; - } - - return _omap_dm_timer_request(REQUEST_BY_ID, &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) -{ - return _omap_dm_timer_request(REQUEST_BY_CAP, &cap); -} -EXPORT_SYMBOL_GPL(omap_dm_timer_request_by_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; - - return _omap_dm_timer_request(REQUEST_BY_NODE, np); -} -EXPORT_SYMBOL_GPL(omap_dm_timer_request_by_node); - -int omap_dm_timer_free(struct omap_dm_timer *timer) -{ - if (unlikely(!timer)) - return -EINVAL; - - clk_put(timer->fclk); - - WARN_ON(!timer->reserved); - timer->reserved = 0; - return 0; -} -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); - -void omap_dm_timer_disable(struct omap_dm_timer *timer) -{ - pm_runtime_put_sync(&timer->pdev->dev); -} -EXPORT_SYMBOL_GPL(omap_dm_timer_disable); - -int omap_dm_timer_get_irq(struct omap_dm_timer *timer) -{ - if (timer) - return timer->irq; - return -EINVAL; -} -EXPORT_SYMBOL_GPL(omap_dm_timer_get_irq); - -#if defined(CONFIG_ARCH_OMAP1) -#include <mach/hardware.h> -/** - * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR - * @inputmask: current value of idlect mask - */ -__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) -{ - int i = 0; - struct omap_dm_timer *timer = NULL; - unsigned long flags; - - /* If ARMXOR cannot be idled this function call is unnecessary */ - if (!(inputmask & (1 << 1))) - return inputmask; - - /* If any active timer is using ARMXOR return modified mask */ - spin_lock_irqsave(&dm_timer_lock, flags); - list_for_each_entry(timer, &omap_timer_list, node) { - u32 l; - - l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); - if (l & OMAP_TIMER_CTRL_ST) { - if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0) - inputmask &= ~(1 << 1); - else - inputmask &= ~(1 << 2); - } - i++; - } - spin_unlock_irqrestore(&dm_timer_lock, flags); - - return inputmask; -} -EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask); - -#else - -struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer) -{ - if (timer && !IS_ERR(timer->fclk)) - return timer->fclk; - return NULL; -} -EXPORT_SYMBOL_GPL(omap_dm_timer_get_fclk); - -__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) -{ - BUG(); - - return 0; -} -EXPORT_SYMBOL_GPL(omap_dm_timer_modify_idlect_mask); - -#endif - -int omap_dm_timer_trigger(struct omap_dm_timer *timer) -{ - if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { - pr_err("%s: timer not available or enabled.\n", __func__); - return -EINVAL; - } - - omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); - return 0; -} -EXPORT_SYMBOL_GPL(omap_dm_timer_trigger); - -int omap_dm_timer_start(struct omap_dm_timer *timer) -{ - u32 l; - - if (unlikely(!timer)) - return -EINVAL; - - omap_dm_timer_enable(timer); - - l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); - if (!(l & OMAP_TIMER_CTRL_ST)) { - l |= OMAP_TIMER_CTRL_ST; - omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); - } - - /* Save the context */ - timer->context.tclr = l; - return 0; -} -EXPORT_SYMBOL_GPL(omap_dm_timer_start); - -int omap_dm_timer_stop(struct omap_dm_timer *timer) -{ - unsigned long rate = 0; - - if (unlikely(!timer)) - return -EINVAL; - - if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) - rate = clk_get_rate(timer->fclk); - - __omap_dm_timer_stop(timer, timer->posted, rate); - - /* - * Since the register values are computed and written within - * __omap_dm_timer_stop, we need to use read to retrieve the - * context. - */ - timer->context.tclr = - omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); - omap_dm_timer_disable(timer); - return 0; -} -EXPORT_SYMBOL_GPL(omap_dm_timer_stop); - -int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) -{ - int ret; - char *parent_name = NULL; - struct clk *parent; - struct dmtimer_platform_data *pdata; - - if (unlikely(!timer)) - return -EINVAL; - - pdata = timer->pdev->dev.platform_data; - - if (source < 0 || source >= 3) - return -EINVAL; - - /* - * FIXME: Used for OMAP1 devices only because they do not currently - * use the clock framework to set the parent clock. To be removed - * once OMAP1 migrated to using clock framework for dmtimers - */ - if (pdata && pdata->set_timer_src) - return pdata->set_timer_src(timer->pdev, source); - - if (IS_ERR(timer->fclk)) - return -EINVAL; - -#if defined(CONFIG_COMMON_CLK) - /* Check if the clock has configurable parents */ - if (clk_hw_get_num_parents(__clk_get_hw(timer->fclk)) < 2) - return 0; -#endif - - switch (source) { - case OMAP_TIMER_SRC_SYS_CLK: - parent_name = "timer_sys_ck"; - break; - - case OMAP_TIMER_SRC_32_KHZ: - parent_name = "timer_32k_ck"; - break; - - case OMAP_TIMER_SRC_EXT_CLK: - parent_name = "timer_ext_ck"; - break; - } - - parent = clk_get(&timer->pdev->dev, parent_name); - if (IS_ERR(parent)) { - pr_err("%s: %s not found\n", __func__, parent_name); - return -EINVAL; - } - - ret = clk_set_parent(timer->fclk, parent); - if (ret < 0) - pr_err("%s: failed to set %s as parent\n", __func__, - parent_name); - - clk_put(parent); - - return ret; -} -EXPORT_SYMBOL_GPL(omap_dm_timer_set_source); - -int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, - unsigned int load) -{ - u32 l; - - if (unlikely(!timer)) - return -EINVAL; - - omap_dm_timer_enable(timer); - l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); - if (autoreload) - l |= OMAP_TIMER_CTRL_AR; - else - l &= ~OMAP_TIMER_CTRL_AR; - omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); - omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); - - omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); - /* Save the context */ - timer->context.tclr = l; - timer->context.tldr = load; - omap_dm_timer_disable(timer); - return 0; -} -EXPORT_SYMBOL_GPL(omap_dm_timer_set_load); - -/* Optimized set_load which removes costly spin wait in timer_start */ -int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, - unsigned int load) -{ - u32 l; - - if (unlikely(!timer)) - return -EINVAL; - - omap_dm_timer_enable(timer); - - l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); - if (autoreload) { - l |= OMAP_TIMER_CTRL_AR; - omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); - } else { - l &= ~OMAP_TIMER_CTRL_AR; - } - l |= OMAP_TIMER_CTRL_ST; - - __omap_dm_timer_load_start(timer, l, load, timer->posted); - - /* Save the context */ - timer->context.tclr = l; - timer->context.tldr = load; - timer->context.tcrr = load; - return 0; -} -EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start); - -int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, - unsigned int match) -{ - u32 l; - - if (unlikely(!timer)) - return -EINVAL; - - omap_dm_timer_enable(timer); - l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); - if (enable) - l |= OMAP_TIMER_CTRL_CE; - else - l &= ~OMAP_TIMER_CTRL_CE; - omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); - omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); - - /* Save the context */ - timer->context.tclr = l; - timer->context.tmar = match; - omap_dm_timer_disable(timer); - return 0; -} -EXPORT_SYMBOL_GPL(omap_dm_timer_set_match); - -int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, - int toggle, int trigger) -{ - u32 l; - - if (unlikely(!timer)) - return -EINVAL; - - omap_dm_timer_enable(timer); - l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); - l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM | - OMAP_TIMER_CTRL_PT | (0x03 << 10)); - if (def_on) - l |= OMAP_TIMER_CTRL_SCPWM; - if (toggle) - l |= OMAP_TIMER_CTRL_PT; - l |= trigger << 10; - omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); - - /* Save the context */ - timer->context.tclr = l; - omap_dm_timer_disable(timer); - return 0; -} -EXPORT_SYMBOL_GPL(omap_dm_timer_set_pwm); - -int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler) -{ - u32 l; - - if (unlikely(!timer)) - return -EINVAL; - - omap_dm_timer_enable(timer); - l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); - l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2)); - if (prescaler >= 0x00 && prescaler <= 0x07) { - l |= OMAP_TIMER_CTRL_PRE; - l |= prescaler << 2; - } - omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); - - /* Save the context */ - timer->context.tclr = l; - omap_dm_timer_disable(timer); - return 0; -} -EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler); - -int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, - unsigned int value) -{ - if (unlikely(!timer)) - return -EINVAL; - - omap_dm_timer_enable(timer); - __omap_dm_timer_int_enable(timer, value); - - /* Save the context */ - timer->context.tier = value; - timer->context.twer = value; - omap_dm_timer_disable(timer); - return 0; -} -EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable); - -/** - * omap_dm_timer_set_int_disable - disable timer interrupts - * @timer: pointer to timer handle - * @mask: bit mask of interrupts to be disabled - * - * Disables the specified timer interrupts for a timer. - */ -int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask) -{ - u32 l = mask; - - if (unlikely(!timer)) - return -EINVAL; - - omap_dm_timer_enable(timer); - - if (timer->revision == 1) - l = readl_relaxed(timer->irq_ena) & ~mask; - - writel_relaxed(l, timer->irq_dis); - l = omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG) & ~mask; - omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, l); - - /* Save the context */ - timer->context.tier &= ~mask; - timer->context.twer &= ~mask; - omap_dm_timer_disable(timer); - return 0; -} -EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_disable); - -unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) -{ - unsigned int l; - - if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { - pr_err("%s: timer not available or enabled.\n", __func__); - return 0; - } - - l = readl_relaxed(timer->irq_stat); - - return l; -} -EXPORT_SYMBOL_GPL(omap_dm_timer_read_status); - -int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) -{ - if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) - return -EINVAL; - - __omap_dm_timer_write_status(timer, value); - - return 0; -} -EXPORT_SYMBOL_GPL(omap_dm_timer_write_status); - -unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) -{ - if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { - pr_err("%s: timer not iavailable or enabled.\n", __func__); - return 0; - } - - return __omap_dm_timer_read_counter(timer, timer->posted); -} -EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter); - -int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value) -{ - if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) { - pr_err("%s: timer not available or enabled.\n", __func__); - return -EINVAL; - } - - omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value); - - /* Save the context */ - timer->context.tcrr = value; - return 0; -} -EXPORT_SYMBOL_GPL(omap_dm_timer_write_counter); - -int omap_dm_timers_active(void) -{ - struct omap_dm_timer *timer; - - list_for_each_entry(timer, &omap_timer_list, node) { - if (!timer->reserved) - continue; - - if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) & - OMAP_TIMER_CTRL_ST) { - return 1; - } - } - return 0; -} -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 - * - * Called by driver framework at the end of device registration for all - * timer devices. - */ -static int omap_dm_timer_probe(struct platform_device *pdev) -{ - unsigned long flags; - struct omap_dm_timer *timer; - struct resource *mem, *irq; - struct device *dev = &pdev->dev; - const struct of_device_id *match; - const struct dmtimer_platform_data *pdata; - int ret; - - 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__); - return -ENODEV; - } - - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (unlikely(!irq)) { - dev_err(dev, "%s: no IRQ resource.\n", __func__); - return -ENODEV; - } - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (unlikely(!mem)) { - dev_err(dev, "%s: no memory resource.\n", __func__); - return -ENODEV; - } - - timer = devm_kzalloc(dev, sizeof(*timer), GFP_KERNEL); - if (!timer) - return -ENOMEM; - - timer->fclk = ERR_PTR(-ENODEV); - timer->io_base = devm_ioremap_resource(dev, mem); - if (IS_ERR(timer->io_base)) - return PTR_ERR(timer->io_base); - - 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; - } - - if (pdata) - timer->errata = pdata->timer_errata; - - timer->irq = irq->start; - timer->pdev = pdev; - - /* Skip pm_runtime_enable for OMAP1 */ - if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) { - pm_runtime_enable(dev); - pm_runtime_irq_safe(dev); - } - - if (!timer->reserved) { - ret = pm_runtime_get_sync(dev); - if (ret < 0) { - dev_err(dev, "%s: pm_runtime_get_sync failed!\n", - __func__); - goto err_get_sync; - } - __omap_dm_timer_init_regs(timer); - pm_runtime_put(dev); - } - - /* add the timer element to the list */ - spin_lock_irqsave(&dm_timer_lock, flags); - list_add_tail(&timer->node, &omap_timer_list); - spin_unlock_irqrestore(&dm_timer_lock, flags); - - dev_dbg(dev, "Device Probed.\n"); - - return 0; - -err_get_sync: - pm_runtime_put_noidle(dev); - pm_runtime_disable(dev); - return ret; -} - -/** - * omap_dm_timer_remove - cleanup a registered timer device - * @pdev: pointer to current timer platform device - * - * Called by driver framework whenever a timer device is unregistered. - * In addition to freeing platform resources it also deletes the timer - * entry from the local list. - */ -static int omap_dm_timer_remove(struct platform_device *pdev) -{ - struct omap_dm_timer *timer; - unsigned long flags; - int ret = -EINVAL; - - spin_lock_irqsave(&dm_timer_lock, flags); - list_for_each_entry(timer, &omap_timer_list, node) - if (!strcmp(dev_name(&timer->pdev->dev), - dev_name(&pdev->dev))) { - list_del(&timer->node); - ret = 0; - break; - } - spin_unlock_irqrestore(&dm_timer_lock, flags); - - pm_runtime_disable(&pdev->dev); - - 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,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, - }, - { - .compatible = "ti,dm816-timer", - .data = &omap3plus_pdata, - }, - {}, -}; -MODULE_DEVICE_TABLE(of, omap_timer_match); - -static struct platform_driver omap_dm_timer_driver = { - .probe = omap_dm_timer_probe, - .remove = omap_dm_timer_remove, - .driver = { - .name = "omap_timer", - .of_match_table = of_match_ptr(omap_timer_match), - }, -}; - -early_platform_init("earlytimer", &omap_dm_timer_driver); -module_platform_driver(omap_dm_timer_driver); - -MODULE_DESCRIPTION("OMAP Dual-Mode Timer Driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRIVER_NAME); -MODULE_AUTHOR("Texas Instruments Inc"); diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h deleted file mode 100644 index 8b7d8a6e02cc..000000000000 --- a/arch/arm/plat-omap/include/plat/dmtimer.h +++ /dev/null @@ -1,414 +0,0 @@ -/* - * arch/arm/plat-omap/include/plat/dmtimer.h - * - * OMAP Dual-Mode Timers - * - * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ - * Tarun Kanti DebBarma <tarun.kanti@ti.com> - * Thara Gopinath <thara@ti.com> - * - * Platform device conversion and hwmod support. - * - * Copyright (C) 2005 Nokia Corporation - * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com> - * PWM and clock framwork support by Timo Teras. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/platform_device.h> - -#ifndef __ASM_ARCH_DMTIMER_H -#define __ASM_ARCH_DMTIMER_H - -/* clock sources */ -#define OMAP_TIMER_SRC_SYS_CLK 0x00 -#define OMAP_TIMER_SRC_32_KHZ 0x01 -#define OMAP_TIMER_SRC_EXT_CLK 0x02 - -/* timer interrupt enable bits */ -#define OMAP_TIMER_INT_CAPTURE (1 << 2) -#define OMAP_TIMER_INT_OVERFLOW (1 << 1) -#define OMAP_TIMER_INT_MATCH (1 << 0) - -/* trigger types */ -#define OMAP_TIMER_TRIGGER_NONE 0x00 -#define OMAP_TIMER_TRIGGER_OVERFLOW 0x01 -#define OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE 0x02 - -/* posted mode types */ -#define OMAP_TIMER_NONPOSTED 0x00 -#define OMAP_TIMER_POSTED 0x01 - -/* timer capabilities used in hwmod database */ -#define OMAP_TIMER_SECURE 0x80000000 -#define OMAP_TIMER_ALWON 0x40000000 -#define OMAP_TIMER_HAS_PWM 0x20000000 -#define OMAP_TIMER_NEEDS_RESET 0x10000000 -#define OMAP_TIMER_HAS_DSP_IRQ 0x08000000 - -/* - * timer errata flags - * - * Errata i103/i767 impacts all OMAP3/4/5 devices including AM33xx. This - * errata prevents us from using posted mode on these devices, unless the - * timer counter register is never read. For more details please refer to - * the OMAP3/4/5 errata documents. - */ -#define OMAP_TIMER_ERRATA_I103_I767 0x80000000 - -struct timer_regs { - u32 tidr; - u32 tier; - u32 twer; - u32 tclr; - u32 tcrr; - u32 tldr; - u32 ttrg; - u32 twps; - u32 tmar; - u32 tcar1; - u32 tsicr; - u32 tcar2; - u32 tpir; - u32 tnir; - u32 tcvr; - u32 tocr; - u32 towr; -}; - -struct omap_dm_timer { - int id; - int irq; - struct clk *fclk; - - void __iomem *io_base; - void __iomem *irq_stat; /* TISR/IRQSTATUS interrupt status */ - void __iomem *irq_ena; /* irq enable */ - void __iomem *irq_dis; /* irq disable, only on v2 ip */ - void __iomem *pend; /* write pending */ - void __iomem *func_base; /* function register base */ - - unsigned long rate; - unsigned reserved:1; - unsigned posted:1; - struct timer_regs context; - int (*get_context_loss_count)(struct device *); - int ctx_loss_count; - int revision; - u32 capability; - u32 errata; - struct platform_device *pdev; - struct list_head node; -}; - -int omap_dm_timer_reserve_systimer(int id); -struct omap_dm_timer *omap_dm_timer_request(void); -struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id); -struct omap_dm_timer *omap_dm_timer_request_by_cap(u32 cap); -struct omap_dm_timer *omap_dm_timer_request_by_node(struct device_node *np); -int omap_dm_timer_free(struct omap_dm_timer *timer); -void omap_dm_timer_enable(struct omap_dm_timer *timer); -void omap_dm_timer_disable(struct omap_dm_timer *timer); - -int omap_dm_timer_get_irq(struct omap_dm_timer *timer); - -u32 omap_dm_timer_modify_idlect_mask(u32 inputmask); -struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer); - -int omap_dm_timer_trigger(struct omap_dm_timer *timer); -int omap_dm_timer_start(struct omap_dm_timer *timer); -int omap_dm_timer_stop(struct omap_dm_timer *timer); - -int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source); -int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, unsigned int value); -int omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, unsigned int value); -int omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, unsigned int match); -int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, int toggle, int trigger); -int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler); - -int omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value); -int omap_dm_timer_set_int_disable(struct omap_dm_timer *timer, u32 mask); - -unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer); -int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value); -unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer); -int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value); - -int omap_dm_timers_active(void); - -/* - * Do not use the defines below, they are not needed. They should be only - * used by dmtimer.c and sys_timer related code. - */ - -/* - * The interrupt registers are different between v1 and v2 ip. - * These registers are offsets from timer->iobase. - */ -#define OMAP_TIMER_ID_OFFSET 0x00 -#define OMAP_TIMER_OCP_CFG_OFFSET 0x10 - -#define OMAP_TIMER_V1_SYS_STAT_OFFSET 0x14 -#define OMAP_TIMER_V1_STAT_OFFSET 0x18 -#define OMAP_TIMER_V1_INT_EN_OFFSET 0x1c - -#define OMAP_TIMER_V2_IRQSTATUS_RAW 0x24 -#define OMAP_TIMER_V2_IRQSTATUS 0x28 -#define OMAP_TIMER_V2_IRQENABLE_SET 0x2c -#define OMAP_TIMER_V2_IRQENABLE_CLR 0x30 - -/* - * The functional registers have a different base on v1 and v2 ip. - * These registers are offsets from timer->func_base. The func_base - * is samae as io_base for v1 and io_base + 0x14 for v2 ip. - * - */ -#define OMAP_TIMER_V2_FUNC_OFFSET 0x14 - -#define _OMAP_TIMER_WAKEUP_EN_OFFSET 0x20 -#define _OMAP_TIMER_CTRL_OFFSET 0x24 -#define OMAP_TIMER_CTRL_GPOCFG (1 << 14) -#define OMAP_TIMER_CTRL_CAPTMODE (1 << 13) -#define OMAP_TIMER_CTRL_PT (1 << 12) -#define OMAP_TIMER_CTRL_TCM_LOWTOHIGH (0x1 << 8) -#define OMAP_TIMER_CTRL_TCM_HIGHTOLOW (0x2 << 8) -#define OMAP_TIMER_CTRL_TCM_BOTHEDGES (0x3 << 8) -#define OMAP_TIMER_CTRL_SCPWM (1 << 7) -#define OMAP_TIMER_CTRL_CE (1 << 6) /* compare enable */ -#define OMAP_TIMER_CTRL_PRE (1 << 5) /* prescaler enable */ -#define OMAP_TIMER_CTRL_PTV_SHIFT 2 /* prescaler value shift */ -#define OMAP_TIMER_CTRL_POSTED (1 << 2) -#define OMAP_TIMER_CTRL_AR (1 << 1) /* auto-reload enable */ -#define OMAP_TIMER_CTRL_ST (1 << 0) /* start timer */ -#define _OMAP_TIMER_COUNTER_OFFSET 0x28 -#define _OMAP_TIMER_LOAD_OFFSET 0x2c -#define _OMAP_TIMER_TRIGGER_OFFSET 0x30 -#define _OMAP_TIMER_WRITE_PEND_OFFSET 0x34 -#define WP_NONE 0 /* no write pending bit */ -#define WP_TCLR (1 << 0) -#define WP_TCRR (1 << 1) -#define WP_TLDR (1 << 2) -#define WP_TTGR (1 << 3) -#define WP_TMAR (1 << 4) -#define WP_TPIR (1 << 5) -#define WP_TNIR (1 << 6) -#define WP_TCVR (1 << 7) -#define WP_TOCR (1 << 8) -#define WP_TOWR (1 << 9) -#define _OMAP_TIMER_MATCH_OFFSET 0x38 -#define _OMAP_TIMER_CAPTURE_OFFSET 0x3c -#define _OMAP_TIMER_IF_CTRL_OFFSET 0x40 -#define _OMAP_TIMER_CAPTURE2_OFFSET 0x44 /* TCAR2, 34xx only */ -#define _OMAP_TIMER_TICK_POS_OFFSET 0x48 /* TPIR, 34xx only */ -#define _OMAP_TIMER_TICK_NEG_OFFSET 0x4c /* TNIR, 34xx only */ -#define _OMAP_TIMER_TICK_COUNT_OFFSET 0x50 /* TCVR, 34xx only */ -#define _OMAP_TIMER_TICK_INT_MASK_SET_OFFSET 0x54 /* TOCR, 34xx only */ -#define _OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET 0x58 /* TOWR, 34xx only */ - -/* register offsets with the write pending bit encoded */ -#define WPSHIFT 16 - -#define OMAP_TIMER_WAKEUP_EN_REG (_OMAP_TIMER_WAKEUP_EN_OFFSET \ - | (WP_NONE << WPSHIFT)) - -#define OMAP_TIMER_CTRL_REG (_OMAP_TIMER_CTRL_OFFSET \ - | (WP_TCLR << WPSHIFT)) - -#define OMAP_TIMER_COUNTER_REG (_OMAP_TIMER_COUNTER_OFFSET \ - | (WP_TCRR << WPSHIFT)) - -#define OMAP_TIMER_LOAD_REG (_OMAP_TIMER_LOAD_OFFSET \ - | (WP_TLDR << WPSHIFT)) - -#define OMAP_TIMER_TRIGGER_REG (_OMAP_TIMER_TRIGGER_OFFSET \ - | (WP_TTGR << WPSHIFT)) - -#define OMAP_TIMER_WRITE_PEND_REG (_OMAP_TIMER_WRITE_PEND_OFFSET \ - | (WP_NONE << WPSHIFT)) - -#define OMAP_TIMER_MATCH_REG (_OMAP_TIMER_MATCH_OFFSET \ - | (WP_TMAR << WPSHIFT)) - -#define OMAP_TIMER_CAPTURE_REG (_OMAP_TIMER_CAPTURE_OFFSET \ - | (WP_NONE << WPSHIFT)) - -#define OMAP_TIMER_IF_CTRL_REG (_OMAP_TIMER_IF_CTRL_OFFSET \ - | (WP_NONE << WPSHIFT)) - -#define OMAP_TIMER_CAPTURE2_REG (_OMAP_TIMER_CAPTURE2_OFFSET \ - | (WP_NONE << WPSHIFT)) - -#define OMAP_TIMER_TICK_POS_REG (_OMAP_TIMER_TICK_POS_OFFSET \ - | (WP_TPIR << WPSHIFT)) - -#define OMAP_TIMER_TICK_NEG_REG (_OMAP_TIMER_TICK_NEG_OFFSET \ - | (WP_TNIR << WPSHIFT)) - -#define OMAP_TIMER_TICK_COUNT_REG (_OMAP_TIMER_TICK_COUNT_OFFSET \ - | (WP_TCVR << WPSHIFT)) - -#define OMAP_TIMER_TICK_INT_MASK_SET_REG \ - (_OMAP_TIMER_TICK_INT_MASK_SET_OFFSET | (WP_TOCR << WPSHIFT)) - -#define OMAP_TIMER_TICK_INT_MASK_COUNT_REG \ - (_OMAP_TIMER_TICK_INT_MASK_COUNT_OFFSET | (WP_TOWR << WPSHIFT)) - -static inline u32 __omap_dm_timer_read(struct omap_dm_timer *timer, u32 reg, - int posted) -{ - if (posted) - while (readl_relaxed(timer->pend) & (reg >> WPSHIFT)) - cpu_relax(); - - return readl_relaxed(timer->func_base + (reg & 0xff)); -} - -static inline void __omap_dm_timer_write(struct omap_dm_timer *timer, - u32 reg, u32 val, int posted) -{ - if (posted) - while (readl_relaxed(timer->pend) & (reg >> WPSHIFT)) - cpu_relax(); - - writel_relaxed(val, timer->func_base + (reg & 0xff)); -} - -static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer) -{ - u32 tidr; - - /* Assume v1 ip if bits [31:16] are zero */ - tidr = readl_relaxed(timer->io_base); - if (!(tidr >> 16)) { - timer->revision = 1; - timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET; - timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET; - timer->irq_dis = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET; - timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET; - timer->func_base = timer->io_base; - } else { - timer->revision = 2; - timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS; - timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET; - timer->irq_dis = timer->io_base + OMAP_TIMER_V2_IRQENABLE_CLR; - timer->pend = timer->io_base + - _OMAP_TIMER_WRITE_PEND_OFFSET + - OMAP_TIMER_V2_FUNC_OFFSET; - timer->func_base = timer->io_base + OMAP_TIMER_V2_FUNC_OFFSET; - } -} - -/* - * __omap_dm_timer_enable_posted - enables write posted mode - * @timer: pointer to timer instance handle - * - * Enables the write posted mode for the timer. When posted mode is enabled - * writes to certain timer registers are immediately acknowledged by the - * internal bus and hence prevents stalling the CPU waiting for the write to - * complete. Enabling this feature can improve performance for writing to the - * timer registers. - */ -static inline void __omap_dm_timer_enable_posted(struct omap_dm_timer *timer) -{ - if (timer->posted) - return; - - if (timer->errata & OMAP_TIMER_ERRATA_I103_I767) { - timer->posted = OMAP_TIMER_NONPOSTED; - __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG, 0, 0); - return; - } - - __omap_dm_timer_write(timer, OMAP_TIMER_IF_CTRL_REG, - OMAP_TIMER_CTRL_POSTED, 0); - timer->context.tsicr = OMAP_TIMER_CTRL_POSTED; - timer->posted = OMAP_TIMER_POSTED; -} - -/** - * __omap_dm_timer_override_errata - override errata flags for a timer - * @timer: pointer to timer handle - * @errata: errata flags to be ignored - * - * For a given timer, override a timer errata by clearing the flags - * specified by the errata argument. A specific erratum should only be - * overridden for a timer if the timer is used in such a way the erratum - * has no impact. - */ -static inline void __omap_dm_timer_override_errata(struct omap_dm_timer *timer, - u32 errata) -{ - timer->errata &= ~errata; -} - -static inline void __omap_dm_timer_stop(struct omap_dm_timer *timer, - int posted, unsigned long rate) -{ - u32 l; - - l = __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted); - if (l & OMAP_TIMER_CTRL_ST) { - l &= ~0x1; - __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, l, posted); -#ifdef CONFIG_ARCH_OMAP2PLUS - /* Readback to make sure write has completed */ - __omap_dm_timer_read(timer, OMAP_TIMER_CTRL_REG, posted); - /* - * Wait for functional clock period x 3.5 to make sure that - * timer is stopped - */ - udelay(3500000 / rate + 1); -#endif - } - - /* Ack possibly pending interrupt */ - writel_relaxed(OMAP_TIMER_INT_OVERFLOW, timer->irq_stat); -} - -static inline void __omap_dm_timer_load_start(struct omap_dm_timer *timer, - u32 ctrl, unsigned int load, - int posted) -{ - __omap_dm_timer_write(timer, OMAP_TIMER_COUNTER_REG, load, posted); - __omap_dm_timer_write(timer, OMAP_TIMER_CTRL_REG, ctrl, posted); -} - -static inline void __omap_dm_timer_int_enable(struct omap_dm_timer *timer, - unsigned int value) -{ - writel_relaxed(value, timer->irq_ena); - __omap_dm_timer_write(timer, OMAP_TIMER_WAKEUP_EN_REG, value, 0); -} - -static inline unsigned int -__omap_dm_timer_read_counter(struct omap_dm_timer *timer, int posted) -{ - return __omap_dm_timer_read(timer, OMAP_TIMER_COUNTER_REG, posted); -} - -static inline void __omap_dm_timer_write_status(struct omap_dm_timer *timer, - unsigned int value) -{ - writel_relaxed(value, timer->irq_stat); -} - -#endif /* __ASM_ARCH_DMTIMER_H */ |