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 <timo.teras@solidboot.com>
Signed-off-by: Juha Yrjola <juha.yrjola@solidboot.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Tento commit je obsažen v:
Timo Teras
2006-06-26 16:16:12 -07:00
odevzdal Tony Lindgren
rodič 6e711ec6d2
revize 77900a2fc3
7 změnil soubory, kde provedl 445 přidání a 335 odebrání

Zobrazit soubor

@@ -91,7 +91,7 @@ config OMAP_32K_TIMER_HZ
config OMAP_DM_TIMER
bool "Use dual-mode timer"
depends on ARCH_OMAP16XX
depends on ARCH_OMAP16XX || ARCH_OMAP24XX
help
Select this option if you want to use OMAP Dual-Mode timers.

Zobrazit soubor

@@ -4,7 +4,8 @@
* OMAP Dual-Mode Timers
*
* Copyright (C) 2005 Nokia Corporation
* Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
* 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 <linux/init.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/list.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <asm/hardware.h>
#include <asm/arch/dmtimer.h>
#include <asm/io.h>
#include <asm/arch/irqs.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#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 */
static struct dmtimer_info_struct {
struct list_head unused_timers;
struct list_head reserved_timers;
} dm_timer_info;
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 },
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 },
};
#elif defined(CONFIG_ARCH_OMAP2)
static struct omap_dm_timer dm_timers[] = {
{ .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;
inline void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value)
static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg)
{
omap_writel(value, timer->base + reg);
return readl(timer->io_base + reg);
}
static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value)
{
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,25 +238,70 @@ 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)
struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
{
return timer->fclk;
}
__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
{
BUG();
}
#endif
void omap_dm_timer_trigger(struct omap_dm_timer *timer)
{
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);
}
}
void omap_dm_timer_stop(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 &= ~0x1;
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
}
}
#ifdef CONFIG_ARCH_OMAP1
void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
{
@@ -133,49 +313,94 @@ void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
omap_writel(l, MOD_CONF_CTRL_1);
}
#else
static void omap_dm_timer_reset(struct omap_dm_timer *timer)
void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
{
/* 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);
static const char *source_timers[] = {
"sys_ck",
"func_32k_ck",
"alt_ck"
};
struct clk *parent;
omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_ARMXOR);
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);
}
#endif
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);
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_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);
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);
}
struct omap_dm_timer * omap_dm_timer_request(void)
void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
int toggle, int trigger)
{
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);
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_set_prescaler(struct omap_dm_timer *timer, int prescaler)
{
u32 l;
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;
}
spin_unlock_irqrestore(&dm_timer_lock, flags);
return timer;
}
void omap_dm_timer_free(struct omap_dm_timer *timer)
{
unsigned long flags;
omap_dm_timer_reset(timer);
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);
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
}
void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
unsigned int value)
unsigned int value)
{
omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value);
}
@@ -190,97 +415,49 @@ 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);
}
void omap_dm_timer_enable_autoreload(struct omap_dm_timer *timer)
{
u32 l;
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
l |= OMAP_TIMER_CTRL_AR;
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
}
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)
{
u32 l;
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
l |= value & 0x3;
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
}
void omap_dm_timer_start(struct omap_dm_timer *timer)
{
u32 l;
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
l |= OMAP_TIMER_CTRL_ST;
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
}
void omap_dm_timer_stop(struct omap_dm_timer *timer)
{
u32 l;
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
l &= ~0x1;
omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
}
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_reset_counter(struct omap_dm_timer *timer)
int omap_dm_timers_active(void)
{
omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, 0);
}
int i;
void omap_dm_timer_set_load(struct omap_dm_timer *timer, unsigned int load)
{
omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
}
for (i = 0; i < dm_timer_count; i++) {
struct omap_dm_timer *timer;
void omap_dm_timer_set_match(struct omap_dm_timer *timer, unsigned int match)
{
omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
}
void omap_dm_timer_enable_compare(struct omap_dm_timer *timer)
{
u32 l;
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);
}
static inline void __dm_timer_init(void)
{
struct omap_dm_timer *timer;
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++;
timer = &dm_timers[i];
if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
OMAP_TIMER_CTRL_ST)
return 1;
}
}
static int __init omap_dm_timer_init(void)
{
if (cpu_is_omap16xx())
__dm_timer_init();
return 0;
}
arch_initcall(omap_dm_timer_init);
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);
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
}
return 0;
}

Zobrazit soubor

@@ -7,6 +7,7 @@
* Partial timer rewrite and additional dynamic tick timer support by
* Tony Lindgen <tony@atomide.com> and
* Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
* OMAP Dual-mode timer framework support by Timo Teras
*
* MPU timer code based on the older MPU timer code for OMAP
* Copyright (C) 2000 RidgeRun, Inc.
@@ -79,18 +80,6 @@ struct sys_timer omap_timer;
#define OMAP1_32K_TIMER_TVR 0x00
#define OMAP1_32K_TIMER_TCR 0x04
/* 24xx specific defines */
#define OMAP2_GP_TIMER_BASE 0x48028000
#define CM_CLKSEL_WKUP 0x48008440
#define GP_TIMER_TIDR 0x00
#define GP_TIMER_TISR 0x18
#define GP_TIMER_TIER 0x1c
#define GP_TIMER_TCLR 0x24
#define GP_TIMER_TCRR 0x28
#define GP_TIMER_TLDR 0x2c
#define GP_TIMER_TTGR 0x30
#define GP_TIMER_TSICR 0x40
#define OMAP_32K_TICKS_PER_HZ (32768 / HZ)
/*
@@ -102,24 +91,57 @@ struct sys_timer omap_timer;
#define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \
(((nr_jiffies) * (clock_rate)) / HZ)
#if defined(CONFIG_ARCH_OMAP1)
static inline void omap_32k_timer_write(int val, int reg)
{
if (cpu_class_is_omap1())
omap_writew(val, OMAP1_32K_TIMER_BASE + reg);
if (cpu_is_omap24xx())
omap_writel(val, OMAP2_GP_TIMER_BASE + reg);
omap_writew(val, OMAP1_32K_TIMER_BASE + reg);
}
static inline unsigned long omap_32k_timer_read(int reg)
{
if (cpu_class_is_omap1())
return omap_readl(OMAP1_32K_TIMER_BASE + reg) & 0xffffff;
if (cpu_is_omap24xx())
return omap_readl(OMAP2_GP_TIMER_BASE + reg);
return omap_readl(OMAP1_32K_TIMER_BASE + reg) & 0xffffff;
}
static inline void omap_32k_timer_start(unsigned long load_val)
{
omap_32k_timer_write(load_val, OMAP1_32K_TIMER_TVR);
omap_32k_timer_write(0x0f, OMAP1_32K_TIMER_CR);
}
static inline void omap_32k_timer_stop(void)
{
omap_32k_timer_write(0x0, OMAP1_32K_TIMER_CR);
}
#define omap_32k_timer_ack_irq()
#elif defined(CONFIG_ARCH_OMAP2)
#include <asm/arch/dmtimer.h>
static struct omap_dm_timer *gptimer;
static inline void omap_32k_timer_start(unsigned long load_val)
{
omap_dm_timer_set_load(gptimer, 1, 0xffffffff - load_val);
omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW);
omap_dm_timer_start(gptimer);
}
static inline void omap_32k_timer_stop(void)
{
omap_dm_timer_stop(gptimer);
}
static inline void omap_32k_timer_ack_irq(void)
{
u32 status = omap_dm_timer_read_status(gptimer);
omap_dm_timer_write_status(gptimer, status);
}
#endif
/*
* The 32KHz synchronized timer is an additional timer on 16xx.
* It is always running.
@@ -129,29 +151,6 @@ static inline unsigned long omap_32k_sync_timer_read(void)
return omap_readl(TIMER_32K_SYNCHRONIZED);
}
static inline void omap_32k_timer_start(unsigned long load_val)
{
if (cpu_class_is_omap1()) {
omap_32k_timer_write(load_val, OMAP1_32K_TIMER_TVR);
omap_32k_timer_write(0x0f, OMAP1_32K_TIMER_CR);
}
if (cpu_is_omap24xx()) {
omap_32k_timer_write(0xffffffff - load_val, GP_TIMER_TCRR);
omap_32k_timer_write((1 << 1), GP_TIMER_TIER);
omap_32k_timer_write((1 << 1) | 1, GP_TIMER_TCLR);
}
}
static inline void omap_32k_timer_stop(void)
{
if (cpu_class_is_omap1())
omap_32k_timer_write(0x0, OMAP1_32K_TIMER_CR);
if (cpu_is_omap24xx())
omap_32k_timer_write(0x0, GP_TIMER_TCLR);
}
/*
* Rounds down to nearest usec. Note that this will overflow for larger values.
*/
@@ -203,11 +202,7 @@ static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id,
write_seqlock_irqsave(&xtime_lock, flags);
if (cpu_is_omap24xx()) {
u32 status = omap_32k_timer_read(GP_TIMER_TISR);
omap_32k_timer_write(status, GP_TIMER_TISR);
}
omap_32k_timer_ack_irq();
now = omap_32k_sync_timer_read();
while ((signed long)(now - omap_32k_last_tick)
@@ -269,9 +264,6 @@ static struct irqaction omap_32k_timer_irq = {
.handler = omap_32k_timer_interrupt,
};
static struct clk * gpt1_ick;
static struct clk * gpt1_fck;
static __init void omap_init_32k_timer(void)
{
#ifdef CONFIG_NO_IDLE_HZ
@@ -280,31 +272,19 @@ static __init void omap_init_32k_timer(void)
if (cpu_class_is_omap1())
setup_irq(INT_OS_TIMER, &omap_32k_timer_irq);
if (cpu_is_omap24xx())
setup_irq(37, &omap_32k_timer_irq);
omap_timer.offset = omap_32k_timer_gettimeoffset;
omap_32k_last_tick = omap_32k_sync_timer_read();
/* REVISIT: Check 24xx TIOCP_CFG settings after idle works */
if (cpu_is_omap24xx()) {
omap_32k_timer_write(0, GP_TIMER_TCLR);
omap_writel(0, CM_CLKSEL_WKUP); /* 32KHz clock source */
gptimer = omap_dm_timer_request_specific(1);
BUG_ON(gptimer == NULL);
gpt1_ick = clk_get(NULL, "gpt1_ick");
if (IS_ERR(gpt1_ick))
printk(KERN_ERR "Could not get gpt1_ick\n");
else
clk_enable(gpt1_ick);
gpt1_fck = clk_get(NULL, "gpt1_fck");
if (IS_ERR(gpt1_fck))
printk(KERN_ERR "Could not get gpt1_fck\n");
else
clk_enable(gpt1_fck);
mdelay(100); /* Wait for clocks to stabilize */
omap_32k_timer_write(0x7, GP_TIMER_TISR);
omap_dm_timer_set_source(gptimer, OMAP_TIMER_SRC_32_KHZ);
setup_irq(omap_dm_timer_get_irq(gptimer), &omap_32k_timer_irq);
omap_dm_timer_set_int_enable(gptimer,
OMAP_TIMER_INT_CAPTURE | OMAP_TIMER_INT_OVERFLOW |
OMAP_TIMER_INT_MATCH);
}
omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
@@ -317,6 +297,9 @@ static __init void omap_init_32k_timer(void)
*/
static void __init omap_timer_init(void)
{
#ifdef CONFIG_OMAP_DM_TIMER
omap_dm_timer_init();
#endif
omap_init_32k_timer();
}