Commit 77900a2f authored by Timo Teras's avatar Timo Teras Committed by Tony Lindgren

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: default avatarTimo Teras <timo.teras@solidboot.com>
Signed-off-by: default avatarJuha Yrjola <juha.yrjola@solidboot.com>
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
parent 6e711ec6
......@@ -8,6 +8,7 @@ config ARCH_OMAP24XX
config ARCH_OMAP2420
bool "OMAP2420 support"
depends on ARCH_OMAP24XX
select OMAP_DM_TIMER
comment "OMAP Board Type"
depends on ARCH_OMAP2
......
......@@ -6,6 +6,7 @@
* Copyright (C) 2005 Nokia Corporation
* Author: Paul Mundt <paul.mundt@nokia.com>
* Juha Yrjl <juha.yrjola@nokia.com>
* OMAP Dual-mode timer framework support by Timo Teras
*
* Some parts based off of TI's 24xx code:
*
......@@ -22,54 +23,18 @@
#include <linux/interrupt.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <asm/mach/time.h>
#include <asm/delay.h>
#include <asm/io.h>
#include <asm/arch/dmtimer.h>
#define OMAP2_GP_TIMER1_BASE 0x48028000
#define OMAP2_GP_TIMER2_BASE 0x4802a000
#define OMAP2_GP_TIMER3_BASE 0x48078000
#define OMAP2_GP_TIMER4_BASE 0x4807a000
static struct omap_dm_timer *gptimer;
#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_TSICR 0x40
#define OS_TIMER_NR 1 /* GP timer 2 */
static unsigned long timer_base[] = {
IO_ADDRESS(OMAP2_GP_TIMER1_BASE),
IO_ADDRESS(OMAP2_GP_TIMER2_BASE),
IO_ADDRESS(OMAP2_GP_TIMER3_BASE),
IO_ADDRESS(OMAP2_GP_TIMER4_BASE),
};
static inline unsigned int timer_read_reg(int nr, unsigned int reg)
{
return __raw_readl(timer_base[nr] + reg);
}
static inline void timer_write_reg(int nr, unsigned int reg, unsigned int val)
{
__raw_writel(val, timer_base[nr] + reg);
}
/* Note that we always enable the clock prescale divider bit */
static inline void omap2_gp_timer_start(int nr, unsigned long load_val)
static inline void omap2_gp_timer_start(unsigned long load_val)
{
unsigned int tmp;
tmp = 0xffffffff - load_val;
timer_write_reg(nr, GP_TIMER_TLDR, tmp);
timer_write_reg(nr, GP_TIMER_TCRR, tmp);
timer_write_reg(nr, GP_TIMER_TIER, 1 << 1);
timer_write_reg(nr, GP_TIMER_TCLR, (1 << 5) | (1 << 1) | 1);
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 irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id,
......@@ -77,7 +42,7 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id,
{
write_seqlock(&xtime_lock);
timer_write_reg(OS_TIMER_NR, GP_TIMER_TISR, 1 << 1);
omap_dm_timer_write_status(gptimer, OMAP_TIMER_INT_OVERFLOW);
timer_tick(regs);
write_sequnlock(&xtime_lock);
......@@ -87,41 +52,26 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id,
static struct irqaction omap2_gp_timer_irq = {
.name = "gp timer",
.flags = SA_INTERRUPT,
.flags = SA_INTERRUPT | SA_TIMER,
.handler = omap2_gp_timer_interrupt,
};
static void __init omap2_gp_timer_init(void)
{
struct clk * sys_ck;
u32 tick_period = 120000;
u32 l;
u32 tick_period;
/* Reset clock and prescale value */
timer_write_reg(OS_TIMER_NR, GP_TIMER_TCLR, 0);
omap_dm_timer_init();
gptimer = omap_dm_timer_request_specific(2);
BUG_ON(gptimer == NULL);
sys_ck = clk_get(NULL, "sys_ck");
if (IS_ERR(sys_ck))
printk(KERN_ERR "Could not get sys_ck\n");
else {
clk_enable(sys_ck);
tick_period = clk_get_rate(sys_ck) / 100;
clk_put(sys_ck);
}
tick_period /= 2; /* Minimum prescale divider is 2 */
omap_dm_timer_set_source(gptimer, OMAP_TIMER_SRC_SYS_CLK);
tick_period = clk_get_rate(omap_dm_timer_get_fclk(gptimer)) / 100;
tick_period -= 1;
l = timer_read_reg(OS_TIMER_NR, GP_TIMER_TIDR);
printk(KERN_INFO "OMAP2 GP timer (HW version %d.%d)\n",
(l >> 4) & 0x0f, l & 0x0f);
setup_irq(38, &omap2_gp_timer_irq);
omap2_gp_timer_start(OS_TIMER_NR, tick_period);
setup_irq(omap_dm_timer_get_irq(gptimer), &omap2_gp_timer_irq);
omap2_gp_timer_start(tick_period);
}
struct sys_timer omap_timer = {
.init = omap2_gp_timer_init,
};
......@@ -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.
......
This diff is collapsed.
......@@ -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,54 +91,64 @@ 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;
return omap_readl(OMAP1_32K_TIMER_BASE + reg) & 0xffffff;
}
if (cpu_is_omap24xx())
return omap_readl(OMAP2_GP_TIMER_BASE + reg);
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);
}
/*
* The 32KHz synchronized timer is an additional timer on 16xx.
* It is always running.
*/
static inline unsigned long omap_32k_sync_timer_read(void)
static inline void omap_32k_timer_stop(void)
{
return omap_readl(TIMER_32K_SYNCHRONIZED);
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)
{
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);
}
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)
{
if (cpu_class_is_omap1())
omap_32k_timer_write(0x0, OMAP1_32K_TIMER_CR);
omap_dm_timer_stop(gptimer);
}
if (cpu_is_omap24xx())
omap_32k_timer_write(0x0, GP_TIMER_TCLR);
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.
*/
static inline unsigned long omap_32k_sync_timer_read(void)
{
return omap_readl(TIMER_32K_SYNCHRONIZED);
}
/*
......@@ -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 */
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);
gptimer = omap_dm_timer_request_specific(1);
BUG_ON(gptimer == NULL);
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();
}
......
......@@ -5,6 +5,7 @@
*
* 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
......@@ -25,69 +26,55 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __ASM_ARCH_TIMER_H
#define __ASM_ARCH_TIMER_H
#include <linux/list.h>
#define OMAP_TIMER_SRC_ARMXOR 0x00
#define OMAP_TIMER_SRC_32_KHZ 0x01
#define OMAP_TIMER_SRC_EXT_CLK 0x02
/* timer control reg bits */
#define OMAP_TIMER_CTRL_CAPTMODE (1 << 13)
#define OMAP_TIMER_CTRL_PT (1 << 12)
#define OMAP_TIMER_CTRL_TRG_OVERFLOW (0x1 << 10)
#define OMAP_TIMER_CTRL_TRG_OFANDMATCH (0x2 << 10)
#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 */
#ifndef __ASM_ARCH_DMTIMER_H
#define __ASM_ARCH_DMTIMER_H
/* 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)
/* 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)
struct omap_dm_timer {
struct list_head timer_list;
/* trigger types */
#define OMAP_TIMER_TRIGGER_NONE 0x00
#define OMAP_TIMER_TRIGGER_OVERFLOW 0x01
#define OMAP_TIMER_TRIGGER_OVERFLOW_AND_COMPARE 0x02
u32 base;
unsigned int irq;
};
struct omap_dm_timer;
struct clk;
u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg);
void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value);
int omap_dm_timer_init(void);
struct omap_dm_timer * omap_dm_timer_request(void);
struct omap_dm_timer *omap_dm_timer_request(void);
struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id);
void omap_dm_timer_free(struct omap_dm_timer *timer);
void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source);
void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value);
void omap_dm_timer_set_trigger(struct omap_dm_timer *timer, unsigned int value);
void omap_dm_timer_enable_compare(struct omap_dm_timer *timer);
void omap_dm_timer_enable_autoreload(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);
void omap_dm_timer_trigger(struct omap_dm_timer *timer);
void omap_dm_timer_start(struct omap_dm_timer *timer);
void omap_dm_timer_stop(struct omap_dm_timer *timer);
void omap_dm_timer_set_load(struct omap_dm_timer *timer, unsigned int load);
void omap_dm_timer_set_match(struct omap_dm_timer *timer, unsigned int match);
void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source);
void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, unsigned int value);
void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, unsigned int match);
void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, int toggle, int trigger);
void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler);
void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value);
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_reset_counter(struct omap_dm_timer *timer);
int omap_dm_timers_active(void);
u32 omap_dm_timer_modify_idlect_mask(u32 inputmask);
#endif /* __ASM_ARCH_TIMER_H */
#endif /* __ASM_ARCH_DMTIMER_H */
......@@ -242,6 +242,18 @@
#define INT_24XX_GPIO_BANK2 30
#define INT_24XX_GPIO_BANK3 31
#define INT_24XX_GPIO_BANK4 32
#define INT_24XX_GPTIMER1 37
#define INT_24XX_GPTIMER2 38
#define INT_24XX_GPTIMER3 39
#define INT_24XX_GPTIMER4 40
#define INT_24XX_GPTIMER5 41
#define INT_24XX_GPTIMER6 42
#define INT_24XX_GPTIMER7 43
#define INT_24XX_GPTIMER8 44
#define INT_24XX_GPTIMER9 45
#define INT_24XX_GPTIMER10 46
#define INT_24XX_GPTIMER11 47
#define INT_24XX_GPTIMER12 48
#define INT_24XX_MCBSP1_IRQ_TX 59
#define INT_24XX_MCBSP1_IRQ_RX 60
#define INT_24XX_MCBSP2_IRQ_TX 62
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment