From 77900a2fc3bfb1eb6eaa6d43eef4591e1f7c600d Mon Sep 17 00:00:00 2001 From: Timo Teras Date: Mon, 26 Jun 2006 16:16:12 -0700 Subject: ARM: OMAP: Port dmtimers to OMAP2 and implement PWM support Port dmtimer framework to OMAP2. Modify the dmtimers API to support setting of PWM configuration and prescaler. Convert 32 kHz timer and GP timer to use the dmtimer framework. Signed-off-by: Timo Teras Signed-off-by: Juha Yrjola Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/dmtimer.c | 413 ++++++++++++++++++++++++++++++------------- 1 file changed, 295 insertions(+), 118 deletions(-) (limited to 'arch/arm/plat-omap/dmtimer.c') diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index eba3cb52ad87..c25a1a6d2b03 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -4,7 +4,8 @@ * OMAP Dual-Mode Timers * * Copyright (C) 2005 Nokia Corporation - * Author: Lauri Leukkunen + * OMAP2 support by Juha Yrjola + * API improvements and OMAP2 clock framework 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 @@ -26,15 +27,17 @@ */ #include +#include +#include +#include +#include +#include #include #include #include #include -#include -#include - -#define OMAP_TIMER_COUNT 8 +/* register offsets */ #define OMAP_TIMER_ID_REG 0x00 #define OMAP_TIMER_OCP_CFG_REG 0x10 #define OMAP_TIMER_SYS_STAT_REG 0x14 @@ -50,52 +53,184 @@ #define OMAP_TIMER_CAPTURE_REG 0x3c #define OMAP_TIMER_IF_CTRL_REG 0x40 +/* timer control reg bits */ +#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 /* how much to shift the prescaler value */ +#define OMAP_TIMER_CTRL_AR (1 << 1) /* auto-reload enable */ +#define OMAP_TIMER_CTRL_ST (1 << 0) /* start timer */ + +struct omap_dm_timer { + unsigned long phys_base; + int irq; +#ifdef CONFIG_ARCH_OMAP2 + struct clk *iclk, *fclk; +#endif + void __iomem *io_base; + unsigned reserved:1; +}; + +#ifdef CONFIG_ARCH_OMAP1 + +static struct omap_dm_timer dm_timers[] = { + { .phys_base = 0xfffb1400, .irq = INT_1610_GPTIMER1 }, + { .phys_base = 0xfffb1c00, .irq = INT_1610_GPTIMER2 }, + { .phys_base = 0xfffb2400, .irq = INT_1610_GPTIMER3 }, + { .phys_base = 0xfffb2c00, .irq = INT_1610_GPTIMER4 }, + { .phys_base = 0xfffb3400, .irq = INT_1610_GPTIMER5 }, + { .phys_base = 0xfffb3c00, .irq = INT_1610_GPTIMER6 }, + { .phys_base = 0xfffb4400, .irq = INT_1610_GPTIMER7 }, + { .phys_base = 0xfffb4c00, .irq = INT_1610_GPTIMER8 }, +}; -static struct dmtimer_info_struct { - struct list_head unused_timers; - struct list_head reserved_timers; -} dm_timer_info; +#elif defined(CONFIG_ARCH_OMAP2) static struct omap_dm_timer dm_timers[] = { - { .base=0xfffb1400, .irq=INT_1610_GPTIMER1 }, - { .base=0xfffb1c00, .irq=INT_1610_GPTIMER2 }, - { .base=0xfffb2400, .irq=INT_1610_GPTIMER3 }, - { .base=0xfffb2c00, .irq=INT_1610_GPTIMER4 }, - { .base=0xfffb3400, .irq=INT_1610_GPTIMER5 }, - { .base=0xfffb3c00, .irq=INT_1610_GPTIMER6 }, - { .base=0xfffb4400, .irq=INT_1610_GPTIMER7 }, - { .base=0xfffb4c00, .irq=INT_1610_GPTIMER8 }, - { .base=0x0 }, + { .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 }, + { .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 }, + { .phys_base = 0x48078000, .irq = INT_24XX_GPTIMER3 }, + { .phys_base = 0x4807a000, .irq = INT_24XX_GPTIMER4 }, + { .phys_base = 0x4807c000, .irq = INT_24XX_GPTIMER5 }, + { .phys_base = 0x4807e000, .irq = INT_24XX_GPTIMER6 }, + { .phys_base = 0x48080000, .irq = INT_24XX_GPTIMER7 }, + { .phys_base = 0x48082000, .irq = INT_24XX_GPTIMER8 }, + { .phys_base = 0x48084000, .irq = INT_24XX_GPTIMER9 }, + { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 }, + { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 }, + { .phys_base = 0x4808a000, .irq = INT_24XX_GPTIMER12 }, }; +#else + +#error OMAP architecture not supported! + +#endif + +static const int dm_timer_count = ARRAY_SIZE(dm_timers); static spinlock_t dm_timer_lock; +static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg) +{ + return readl(timer->io_base + reg); +} -inline void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value) +static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value) { - omap_writel(value, timer->base + reg); + writel(value, timer->io_base + reg); while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG)) ; } -u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg) +static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) { - return omap_readl(timer->base + reg); + int c; + + c = 0; + while (!(omap_dm_timer_read_reg(timer, OMAP_TIMER_SYS_STAT_REG) & 1)) { + c++; + if (c > 100000) { + printk(KERN_ERR "Timer failed to reset\n"); + return; + } + } } -int omap_dm_timers_active(void) +static void omap_dm_timer_reset(struct omap_dm_timer *timer) +{ + u32 l; + + omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); + omap_dm_timer_wait_for_reset(timer); + + omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_SYS_CLK); + + /* Set to smart-idle mode */ + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_OCP_CFG_REG); + l |= 0x02 << 3; + omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l); +} + +static void omap_dm_timer_reserve(struct omap_dm_timer *timer) +{ + timer->reserved = 1; +#ifdef CONFIG_ARCH_OMAP2 + clk_enable(timer->iclk); + clk_enable(timer->fclk); +#endif + omap_dm_timer_reset(timer); +} + +struct omap_dm_timer *omap_dm_timer_request(void) +{ + struct omap_dm_timer *timer = NULL; + unsigned long flags; + int i; + + spin_lock_irqsave(&dm_timer_lock, flags); + for (i = 0; i < dm_timer_count; i++) { + if (dm_timers[i].reserved) + continue; + + timer = &dm_timers[i]; + omap_dm_timer_reserve(timer); + break; + } + spin_unlock_irqrestore(&dm_timer_lock, flags); + + return timer; +} + +struct omap_dm_timer *omap_dm_timer_request_specific(int id) { struct omap_dm_timer *timer; + unsigned long flags; - for (timer = &dm_timers[0]; timer->base; ++timer) - if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) & - OMAP_TIMER_CTRL_ST) - return 1; + spin_lock_irqsave(&dm_timer_lock, flags); + if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) { + spin_unlock_irqrestore(&dm_timer_lock, flags); + printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n", + __FILE__, __LINE__, __FUNCTION__, id); + dump_stack(); + return NULL; + } - return 0; + timer = &dm_timers[id-1]; + omap_dm_timer_reserve(timer); + spin_unlock_irqrestore(&dm_timer_lock, flags); + + return timer; } +void omap_dm_timer_free(struct omap_dm_timer *timer) +{ + omap_dm_timer_reset(timer); +#ifdef CONFIG_ARCH_OMAP2 + clk_disable(timer->iclk); + clk_disable(timer->fclk); +#endif + WARN_ON(!timer->reserved); + timer->reserved = 0; +} + +int omap_dm_timer_get_irq(struct omap_dm_timer *timer) +{ + return timer->irq; +} + +#if defined(CONFIG_ARCH_OMAP1) + +struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer) +{ + BUG(); +} /** * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR @@ -103,184 +238,226 @@ int omap_dm_timers_active(void) */ __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) { - int n; + int i; /* 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 */ - for (n = 0; dm_timers[n].base; ++n) - if (omap_dm_timer_read_reg(&dm_timers[n], OMAP_TIMER_CTRL_REG)& - OMAP_TIMER_CTRL_ST) { - if (((omap_readl(MOD_CONF_CTRL_1)>>(n*2)) & 0x03) == 0) + for (i = 0; i < dm_timer_count; i++) { + u32 l; + + l = omap_dm_timer_read_reg(&dm_timers[n], 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); } + } return inputmask; } +#elif defined(CONFIG_ARCH_OMAP2) -void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) +struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer) { - int n = (timer - dm_timers) << 1; - u32 l; + return timer->fclk; +} - l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n); - l |= source << n; - omap_writel(l, MOD_CONF_CTRL_1); +__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) +{ + BUG(); } +#endif -static void omap_dm_timer_reset(struct omap_dm_timer *timer) +void omap_dm_timer_trigger(struct omap_dm_timer *timer) { - /* Reset and set posted mode */ - omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); - omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, 0x02); - - omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_ARMXOR); + omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); } +void omap_dm_timer_start(struct omap_dm_timer *timer) +{ + u32 l; + 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); + } +} -struct omap_dm_timer * omap_dm_timer_request(void) +void omap_dm_timer_stop(struct omap_dm_timer *timer) { - struct omap_dm_timer *timer = NULL; - unsigned long flags; + u32 l; - spin_lock_irqsave(&dm_timer_lock, flags); - if (!list_empty(&dm_timer_info.unused_timers)) { - timer = (struct omap_dm_timer *) - dm_timer_info.unused_timers.next; - list_move_tail((struct list_head *)timer, - &dm_timer_info.reserved_timers); + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); + if (l & OMAP_TIMER_CTRL_ST) { + l &= ~0x1; + omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); } - spin_unlock_irqrestore(&dm_timer_lock, flags); - - return timer; } +#ifdef CONFIG_ARCH_OMAP1 -void omap_dm_timer_free(struct omap_dm_timer *timer) +void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) { - unsigned long flags; - - omap_dm_timer_reset(timer); + int n = (timer - dm_timers) << 1; + u32 l; - spin_lock_irqsave(&dm_timer_lock, flags); - list_move_tail((struct list_head *)timer, &dm_timer_info.unused_timers); - spin_unlock_irqrestore(&dm_timer_lock, flags); + l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n); + l |= source << n; + omap_writel(l, MOD_CONF_CTRL_1); } -void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, - unsigned int value) -{ - omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value); -} +#else -unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) +void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) { - return omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG); + static const char *source_timers[] = { + "sys_ck", + "func_32k_ck", + "alt_ck" + }; + struct clk *parent; + + if (source < 0 || source >= 3) + return; + + parent = clk_get(NULL, source_timers[source]); + clk_disable(timer->fclk); + clk_set_parent(timer->fclk, parent); + clk_enable(timer->fclk); + clk_put(parent); + + /* When the functional clock disappears, too quick writes seem to + * cause an abort. */ + udelay(50); } -void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) -{ - omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value); -} +#endif -void omap_dm_timer_enable_autoreload(struct omap_dm_timer *timer) +void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, + unsigned int load) { u32 l; + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); - l |= OMAP_TIMER_CTRL_AR; + 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); } -void omap_dm_timer_trigger(struct omap_dm_timer *timer) -{ - omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 1); -} - -void omap_dm_timer_set_trigger(struct omap_dm_timer *timer, unsigned int value) +void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, + unsigned int match) { u32 l; l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); - l |= value & 0x3; + if (enable) + l |= OMAP_TIMER_CTRL_CE; + else + l &= ~OMAP_TIMER_CTRL_CE; omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); + omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); } -void omap_dm_timer_start(struct omap_dm_timer *timer) + +void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, + int toggle, int trigger) { u32 l; l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); - l |= OMAP_TIMER_CTRL_ST; + 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); } -void omap_dm_timer_stop(struct omap_dm_timer *timer) +void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler) { u32 l; l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); - l &= ~0x1; + 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); } -unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) +void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, + unsigned int value) { - return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG); + omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value); } -void omap_dm_timer_reset_counter(struct omap_dm_timer *timer) +unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) { - omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, 0); + return omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG); } -void omap_dm_timer_set_load(struct omap_dm_timer *timer, unsigned int load) +void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) { - omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); + omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value); } -void omap_dm_timer_set_match(struct omap_dm_timer *timer, unsigned int match) +unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) { - omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); + return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG); } -void omap_dm_timer_enable_compare(struct omap_dm_timer *timer) +int omap_dm_timers_active(void) { - u32 l; + int i; - l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); - l |= OMAP_TIMER_CTRL_CE; - omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); -} + for (i = 0; i < dm_timer_count; i++) { + struct omap_dm_timer *timer; + timer = &dm_timers[i]; + if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) & + OMAP_TIMER_CTRL_ST) + return 1; + } + return 0; +} -static inline void __dm_timer_init(void) +int omap_dm_timer_init(void) { struct omap_dm_timer *timer; + int i; + + if (!(cpu_is_omap16xx() || cpu_is_omap24xx())) + return -ENODEV; spin_lock_init(&dm_timer_lock); - INIT_LIST_HEAD(&dm_timer_info.unused_timers); - INIT_LIST_HEAD(&dm_timer_info.reserved_timers); - - timer = &dm_timers[0]; - while (timer->base) { - list_add_tail((struct list_head *)timer, &dm_timer_info.unused_timers); - omap_dm_timer_reset(timer); - timer++; + for (i = 0; i < dm_timer_count; i++) { +#ifdef CONFIG_ARCH_OMAP2 + char clk_name[16]; +#endif + + timer = &dm_timers[i]; + timer->io_base = (void __iomem *) io_p2v(timer->phys_base); +#ifdef CONFIG_ARCH_OMAP2 + sprintf(clk_name, "gpt%d_ick", i + 1); + timer->iclk = clk_get(NULL, clk_name); + sprintf(clk_name, "gpt%d_fck", i + 1); + timer->fclk = clk_get(NULL, clk_name); +#endif } -} -static int __init omap_dm_timer_init(void) -{ - if (cpu_is_omap16xx()) - __dm_timer_init(); return 0; } - -arch_initcall(omap_dm_timer_init); -- cgit v1.2.3 From e32f7ec2e8bf00756c74a5e6a80bc59e949dd81d Mon Sep 17 00:00:00 2001 From: Timo Teras Date: Mon, 26 Jun 2006 16:16:13 -0700 Subject: ARM: OMAP: Fix 32 kHz timer and modify GP timer to use GPT1 The dmtimer framework update broke 32 kHz timer as udelay() does not work before system timer is started (and GPT1 should not be reset). This also makes the GP timer use GPT1. This requires a fix in clock framework. Signed-off-by: Timo Teras Signed-off-by: Juha Yrjola Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/clock.c | 2 +- arch/arm/mach-omap2/timer-gp.c | 2 +- arch/arm/plat-omap/dmtimer.c | 9 +++++---- 3 files changed, 7 insertions(+), 6 deletions(-) (limited to 'arch/arm/plat-omap/dmtimer.c') diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 242d8f925e9e..6789dd4029a1 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c @@ -753,7 +753,7 @@ static u32 omap2_get_src_field(u32 *type_to_addr, u32 reg_offset, val = 0x2; break; case CM_WKUP_SEL1: - src_reg_addr = (u32)&CM_CLKSEL2_CORE; + src_reg_addr = (u32)&CM_CLKSEL_WKUP; mask = 0x3; if (src_clk == &func_32k_ck) val = 0x0; diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c index 3358c0d47b1a..cf78e6c5a277 100644 --- a/arch/arm/mach-omap2/timer-gp.c +++ b/arch/arm/mach-omap2/timer-gp.c @@ -61,7 +61,7 @@ static void __init omap2_gp_timer_init(void) u32 tick_period; omap_dm_timer_init(); - gptimer = omap_dm_timer_request_specific(2); + gptimer = omap_dm_timer_request_specific(1); BUG_ON(gptimer == NULL); omap_dm_timer_set_source(gptimer, OMAP_TIMER_SRC_SYS_CLK); diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index c25a1a6d2b03..bfccebc77515 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -147,9 +147,10 @@ static void omap_dm_timer_reset(struct omap_dm_timer *timer) { u32 l; - omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); - omap_dm_timer_wait_for_reset(timer); - + if (timer != &dm_timers[0]) { + omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); + omap_dm_timer_wait_for_reset(timer); + } omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_SYS_CLK); /* Set to smart-idle mode */ @@ -335,7 +336,7 @@ void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) /* When the functional clock disappears, too quick writes seem to * cause an abort. */ - udelay(50); + __delay(15000); } #endif -- cgit v1.2.3 From 83379c81f6f05a6e80db66ae33378feb4cbca6b3 Mon Sep 17 00:00:00 2001 From: Timo Teras Date: Mon, 26 Jun 2006 16:16:23 -0700 Subject: ARM: OMAP: Update dmtimers - Initialize timer outside of spinlock to reduce the time the spinlock is held - Do clk_get to the source clocks during initialization to avoid sleeping later - New function to set counter register Signed-off-by: Timo Teras Signed-off-by: Juha Yrjola Signed-off-by: Tony Lindgren --- arch/arm/plat-omap/dmtimer.c | 46 ++++++++++++++++++++++++------------- include/asm-arm/arch-omap/dmtimer.h | 1 + 2 files changed, 31 insertions(+), 16 deletions(-) (limited to 'arch/arm/plat-omap/dmtimer.c') diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index bfccebc77515..804a53534370 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -107,6 +107,14 @@ static struct omap_dm_timer dm_timers[] = { { .phys_base = 0x4808a000, .irq = INT_24XX_GPTIMER12 }, }; +static const char *dm_source_names[] = { + "sys_ck", + "func_32k_ck", + "alt_ck" +}; + +static struct clk *dm_source_clocks[3]; + #else #error OMAP architecture not supported! @@ -114,7 +122,6 @@ static struct omap_dm_timer dm_timers[] = { #endif static const int dm_timer_count = ARRAY_SIZE(dm_timers); - static spinlock_t dm_timer_lock; static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg) @@ -159,9 +166,8 @@ static void omap_dm_timer_reset(struct omap_dm_timer *timer) omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l); } -static void omap_dm_timer_reserve(struct omap_dm_timer *timer) +static void omap_dm_timer_prepare(struct omap_dm_timer *timer) { - timer->reserved = 1; #ifdef CONFIG_ARCH_OMAP2 clk_enable(timer->iclk); clk_enable(timer->fclk); @@ -181,11 +187,14 @@ struct omap_dm_timer *omap_dm_timer_request(void) continue; timer = &dm_timers[i]; - omap_dm_timer_reserve(timer); + timer->reserved = 1; break; } spin_unlock_irqrestore(&dm_timer_lock, flags); + if (timer != NULL) + omap_dm_timer_prepare(timer); + return timer; } @@ -204,9 +213,11 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id) } timer = &dm_timers[id-1]; - omap_dm_timer_reserve(timer); + timer->reserved = 1; spin_unlock_irqrestore(&dm_timer_lock, flags); + omap_dm_timer_prepare(timer); + return timer; } @@ -318,21 +329,12 @@ void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) { - static const char *source_timers[] = { - "sys_ck", - "func_32k_ck", - "alt_ck" - }; - struct clk *parent; - if (source < 0 || source >= 3) return; - parent = clk_get(NULL, source_timers[source]); clk_disable(timer->fclk); - clk_set_parent(timer->fclk, parent); + clk_set_parent(timer->fclk, dm_source_clocks[source]); clk_enable(timer->fclk); - clk_put(parent); /* When the functional clock disappears, too quick writes seem to * cause an abort. */ @@ -362,7 +364,7 @@ void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, u32 l; l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); - if (enable) + if (enable) l |= OMAP_TIMER_CTRL_CE; else l &= ~OMAP_TIMER_CTRL_CE; @@ -421,6 +423,11 @@ unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG); } +void omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value) +{ + return omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value); +} + int omap_dm_timers_active(void) { int i; @@ -445,6 +452,13 @@ int omap_dm_timer_init(void) return -ENODEV; spin_lock_init(&dm_timer_lock); +#ifdef CONFIG_ARCH_OMAP2 + for (i = 0; i < ARRAY_SIZE(dm_source_names); i++) { + dm_source_clocks[i] = clk_get(NULL, dm_source_names[i]); + BUG_ON(dm_source_clocks[i] == NULL); + } +#endif + for (i = 0; i < dm_timer_count; i++) { #ifdef CONFIG_ARCH_OMAP2 char clk_name[16]; diff --git a/include/asm-arm/arch-omap/dmtimer.h b/include/asm-arm/arch-omap/dmtimer.h index 5b58e3d62742..7a289ff07404 100644 --- a/include/asm-arm/arch-omap/dmtimer.h +++ b/include/asm-arm/arch-omap/dmtimer.h @@ -73,6 +73,7 @@ void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int valu unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer); void 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); +void omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value); int omap_dm_timers_active(void); -- cgit v1.2.3 From 35912c799722f0c63b8c2c49c7650d4516a5fe8a Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Sat, 1 Jul 2006 19:56:42 +0100 Subject: [ARM] 3676/1: ARM: OMAP: Fix dmtimers and timer32k to compile on OMAP1 Patch from Tony Lindgren Fixes compilation errors on OMAP1. Patch from Timo Teras. Signed-off-by: Timo Teras Signed-off-by: Juha Yrjola Signed-off-by: Tony Lindgren Signed-off-by: Russell King --- arch/arm/plat-omap/dmtimer.c | 2 +- arch/arm/plat-omap/timer32k.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'arch/arm/plat-omap/dmtimer.c') diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index 804a53534370..50524436de63 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -260,7 +260,7 @@ __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) for (i = 0; i < dm_timer_count; i++) { u32 l; - l = omap_dm_timer_read_reg(&dm_timers[n], OMAP_TIMER_CTRL_REG); + l = omap_dm_timer_read_reg(&dm_timers[i], OMAP_TIMER_CTRL_REG); if (l & OMAP_TIMER_CTRL_ST) { if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0) inputmask &= ~(1 << 1); diff --git a/arch/arm/plat-omap/timer32k.c b/arch/arm/plat-omap/timer32k.c index f028e182215a..ea9f3732630b 100644 --- a/arch/arm/plat-omap/timer32k.c +++ b/arch/arm/plat-omap/timer32k.c @@ -51,6 +51,7 @@ #include #include #include +#include struct sys_timer omap_timer; @@ -118,8 +119,6 @@ static inline void omap_32k_timer_stop(void) #elif defined(CONFIG_ARCH_OMAP2) -#include - static struct omap_dm_timer *gptimer; static inline void omap_32k_timer_start(unsigned long load_val) @@ -275,6 +274,7 @@ static __init void omap_init_32k_timer(void) omap_timer.offset = omap_32k_timer_gettimeoffset; omap_32k_last_tick = omap_32k_sync_timer_read(); +#ifdef CONFIG_ARCH_OMAP2 /* REVISIT: Check 24xx TIOCP_CFG settings after idle works */ if (cpu_is_omap24xx()) { gptimer = omap_dm_timer_request_specific(1); @@ -286,6 +286,7 @@ static __init void omap_init_32k_timer(void) OMAP_TIMER_INT_CAPTURE | OMAP_TIMER_INT_OVERFLOW | OMAP_TIMER_INT_MATCH); } +#endif omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD); } -- cgit v1.2.3