diff options
Diffstat (limited to 'arch/arm/plat-omap')
21 files changed, 1005 insertions, 545 deletions
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig index 6e6735f04ee..49a4c75243f 100644 --- a/arch/arm/plat-omap/Kconfig +++ b/arch/arm/plat-omap/Kconfig @@ -211,6 +211,9 @@ choice depends on ARCH_OMAP default OMAP_PM_NOOP +config OMAP_PM_NONE + bool "No PM layer" + config OMAP_PM_NOOP bool "No-op/debug PM layer" diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c index 156b27dd581..c9122dd6ee8 100644 --- a/arch/arm/plat-omap/clock.c +++ b/arch/arm/plat-omap/clock.c @@ -475,41 +475,8 @@ int __init clk_init(struct clk_functions * custom_clocks) /* * debugfs support to trace clock tree hierarchy and attributes */ - -#include <linux/debugfs.h> -#include <linux/seq_file.h> - static struct dentry *clk_debugfs_root; -static int clk_dbg_show_summary(struct seq_file *s, void *unused) -{ - struct clk *c; - struct clk *pa; - - seq_printf(s, "%-30s %-30s %-10s %s\n", - "clock-name", "parent-name", "rate", "use-count"); - - list_for_each_entry(c, &clocks, node) { - pa = c->parent; - seq_printf(s, "%-30s %-30s %-10lu %d\n", - c->name, pa ? pa->name : "none", c->rate, c->usecount); - } - - return 0; -} - -static int clk_dbg_open(struct inode *inode, struct file *file) -{ - return single_open(file, clk_dbg_show_summary, inode->i_private); -} - -static const struct file_operations debug_clock_fops = { - .open = clk_dbg_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int clk_debugfs_register_one(struct clk *c) { int err; @@ -584,12 +551,6 @@ static int __init clk_debugfs_init(void) if (err) goto err_out; } - - d = debugfs_create_file("summary", S_IRUGO, - d, NULL, &debug_clock_fops); - if (!d) - return -ENOMEM; - return 0; err_out: debugfs_remove_recursive(clk_debugfs_root); diff --git a/arch/arm/plat-omap/counter_32k.c b/arch/arm/plat-omap/counter_32k.c index a6cbb712da5..f7fed608019 100644 --- a/arch/arm/plat-omap/counter_32k.c +++ b/arch/arm/plat-omap/counter_32k.c @@ -18,7 +18,6 @@ #include <linux/err.h> #include <linux/io.h> #include <linux/sched.h> -#include <linux/clocksource.h> #include <asm/sched_clock.h> @@ -27,16 +26,87 @@ #include <plat/clock.h> + /* * 32KHz clocksource ... always available, on pretty most chips except * OMAP 730 and 1510. Other timers could be used as clocksources, with * higher resolution in free-running counter modes (e.g. 12 MHz xtal), * but systems won't necessarily want to spend resources that way. */ -static void __iomem *timer_32k_base; #define OMAP16XX_TIMER_32K_SYNCHRONIZED 0xfffbc410 +#include <linux/clocksource.h> + +/* + * offset_32k holds the init time counter value. It is then subtracted + * from every counter read to achieve a counter that counts time from the + * kernel boot (needed for sched_clock()). + */ +static u32 offset_32k __read_mostly; + +#ifdef CONFIG_ARCH_OMAP16XX +static cycle_t notrace omap16xx_32k_read(struct clocksource *cs) +{ + return omap_readl(OMAP16XX_TIMER_32K_SYNCHRONIZED) - offset_32k; +} +#else +#define omap16xx_32k_read NULL +#endif + +#ifdef CONFIG_SOC_OMAP2420 +static cycle_t notrace omap2420_32k_read(struct clocksource *cs) +{ + return omap_readl(OMAP2420_32KSYNCT_BASE + 0x10) - offset_32k; +} +#else +#define omap2420_32k_read NULL +#endif + +#ifdef CONFIG_SOC_OMAP2430 +static cycle_t notrace omap2430_32k_read(struct clocksource *cs) +{ + return omap_readl(OMAP2430_32KSYNCT_BASE + 0x10) - offset_32k; +} +#else +#define omap2430_32k_read NULL +#endif + +#ifdef CONFIG_ARCH_OMAP3 +static cycle_t notrace omap34xx_32k_read(struct clocksource *cs) +{ + return omap_readl(OMAP3430_32KSYNCT_BASE + 0x10) - offset_32k; +} +#else +#define omap34xx_32k_read NULL +#endif + +#ifdef CONFIG_ARCH_OMAP4 +static cycle_t notrace omap44xx_32k_read(struct clocksource *cs) +{ + return omap_readl(OMAP4430_32KSYNCT_BASE + 0x10) - offset_32k; +} +#else +#define omap44xx_32k_read NULL +#endif + +/* + * Kernel assumes that sched_clock can be called early but may not have + * things ready yet. + */ +static cycle_t notrace omap_32k_read_dummy(struct clocksource *cs) +{ + return 0; +} + +static struct clocksource clocksource_32k = { + .name = "32k_counter", + .rating = 250, + .read = omap_32k_read_dummy, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + /* * Returns current time from boot in nsecs. It's OK for this to wrap * around for now, as it's just a relative time stamp. @@ -52,11 +122,11 @@ static DEFINE_CLOCK_DATA(cd); static inline unsigned long long notrace _omap_32k_sched_clock(void) { - u32 cyc = timer_32k_base ? __raw_readl(timer_32k_base) : 0; + u32 cyc = clocksource_32k.read(&clocksource_32k); return cyc_to_fixed_sched_clock(&cd, cyc, (u32)~0, SC_MULT, SC_SHIFT); } -#if defined(CONFIG_OMAP_32K_TIMER) && !defined(CONFIG_OMAP_MPU_TIMER) +#ifndef CONFIG_OMAP_MPU_TIMER unsigned long long notrace sched_clock(void) { return _omap_32k_sched_clock(); @@ -70,7 +140,7 @@ unsigned long long notrace omap_32k_sched_clock(void) static void notrace omap_update_sched_clock(void) { - u32 cyc = timer_32k_base ? __raw_readl(timer_32k_base) : 0; + u32 cyc = clocksource_32k.read(&clocksource_32k); update_sched_clock(&cd, cyc, (u32)~0); } @@ -83,7 +153,6 @@ static void notrace omap_update_sched_clock(void) */ static struct timespec persistent_ts; static cycles_t cycles, last_cycles; -static unsigned int persistent_mult, persistent_shift; void read_persistent_clock(struct timespec *ts) { unsigned long long nsecs; @@ -91,10 +160,11 @@ void read_persistent_clock(struct timespec *ts) struct timespec *tsp = &persistent_ts; last_cycles = cycles; - cycles = timer_32k_base ? __raw_readl(timer_32k_base) : 0; + cycles = clocksource_32k.read(&clocksource_32k); delta = cycles - last_cycles; - nsecs = clocksource_cyc2ns(delta, persistent_mult, persistent_shift); + nsecs = clocksource_cyc2ns(delta, + clocksource_32k.mult, clocksource_32k.shift); timespec_add_ns(tsp, nsecs); *ts = *tsp; @@ -106,46 +176,29 @@ int __init omap_init_clocksource_32k(void) "%s: can't register clocksource!\n"; if (cpu_is_omap16xx() || cpu_class_is_omap2()) { - u32 pbase; - unsigned long size = SZ_4K; - void __iomem *base; struct clk *sync_32k_ick; - if (cpu_is_omap16xx()) { - pbase = OMAP16XX_TIMER_32K_SYNCHRONIZED; - size = SZ_1K; - } else if (cpu_is_omap2420()) - pbase = OMAP2420_32KSYNCT_BASE + 0x10; + if (cpu_is_omap16xx()) + clocksource_32k.read = omap16xx_32k_read; + else if (cpu_is_omap2420()) + clocksource_32k.read = omap2420_32k_read; else if (cpu_is_omap2430()) - pbase = OMAP2430_32KSYNCT_BASE + 0x10; + clocksource_32k.read = omap2430_32k_read; else if (cpu_is_omap34xx()) - pbase = OMAP3430_32KSYNCT_BASE + 0x10; + clocksource_32k.read = omap34xx_32k_read; else if (cpu_is_omap44xx()) - pbase = OMAP4430_32KSYNCT_BASE + 0x10; + clocksource_32k.read = omap44xx_32k_read; else return -ENODEV; - /* For this to work we must have a static mapping in io.c for this area */ - base = ioremap(pbase, size); - if (!base) - return -ENODEV; - sync_32k_ick = clk_get(NULL, "omap_32ksync_ick"); if (!IS_ERR(sync_32k_ick)) clk_enable(sync_32k_ick); - timer_32k_base = base; - - /* - * 120000 rough estimate from the calculations in - * __clocksource_updatefreq_scale. - */ - clocks_calc_mult_shift(&persistent_mult, &persistent_shift, - 32768, NSEC_PER_SEC, 120000); + offset_32k = clocksource_32k.read(&clocksource_32k); - if (clocksource_mmio_init(base, "32k_counter", 32768, 250, 32, - clocksource_mmio_readl_up)) - printk(err, "32k_counter"); + if (clocksource_register_hz(&clocksource_32k, 32768)) + printk(err, clocksource_32k.name); init_fixed_sched_clock(&cd, omap_update_sched_clock, 32, 32768, SC_MULT, SC_SHIFT); diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c index 75a847dd776..ee9f6ebba29 100644 --- a/arch/arm/plat-omap/dmtimer.c +++ b/arch/arm/plat-omap/dmtimer.c @@ -41,6 +41,127 @@ #include <plat/dmtimer.h> #include <mach/irqs.h> +/* register offsets */ +#define _OMAP_TIMER_ID_OFFSET 0x00 +#define _OMAP_TIMER_OCP_CFG_OFFSET 0x10 +#define _OMAP_TIMER_SYS_STAT_OFFSET 0x14 +#define _OMAP_TIMER_STAT_OFFSET 0x18 +#define _OMAP_TIMER_INT_EN_OFFSET 0x1c +#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_ID_REG (_OMAP_TIMER_ID_OFFSET \ + | (WP_NONE << WPSHIFT)) + +#define OMAP_TIMER_OCP_CFG_REG (_OMAP_TIMER_OCP_CFG_OFFSET \ + | (WP_NONE << WPSHIFT)) + +#define OMAP_TIMER_SYS_STAT_REG (_OMAP_TIMER_SYS_STAT_OFFSET \ + | (WP_NONE << WPSHIFT)) + +#define OMAP_TIMER_STAT_REG (_OMAP_TIMER_STAT_OFFSET \ + | (WP_NONE << WPSHIFT)) + +#define OMAP_TIMER_INT_EN_REG (_OMAP_TIMER_INT_EN_OFFSET \ + | (WP_NONE << WPSHIFT)) + +#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)) + +struct omap_dm_timer { + unsigned long phys_base; + int irq; +#ifdef CONFIG_ARCH_OMAP2PLUS + struct clk *iclk, *fclk; +#endif + void __iomem *io_base; + unsigned reserved:1; + unsigned enabled:1; + unsigned posted:1; +}; + static int dm_timer_count; #ifdef CONFIG_ARCH_OMAP1 @@ -170,7 +291,11 @@ static spinlock_t dm_timer_lock; */ static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg) { - return __omap_dm_timer_read(timer->io_base, reg, timer->posted); + if (timer->posted) + while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff)) + & (reg >> WPSHIFT)) + cpu_relax(); + return readl(timer->io_base + (reg & 0xff)); } /* @@ -182,7 +307,11 @@ static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, u32 reg) static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, u32 reg, u32 value) { - __omap_dm_timer_write(timer->io_base, reg, value, timer->posted); + if (timer->posted) + while (readl(timer->io_base + (OMAP_TIMER_WRITE_PEND_REG & 0xff)) + & (reg >> WPSHIFT)) + cpu_relax(); + writel(value, timer->io_base + (reg & 0xff)); } static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) @@ -201,7 +330,7 @@ static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) static void omap_dm_timer_reset(struct omap_dm_timer *timer) { - int autoidle = 0, wakeup = 0; + u32 l; if (!cpu_class_is_omap2() || timer != &dm_timers[0]) { omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); @@ -209,21 +338,28 @@ static void omap_dm_timer_reset(struct omap_dm_timer *timer) } omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ); - /* Enable autoidle on OMAP2+ */ - if (cpu_class_is_omap2()) - autoidle = 1; + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_OCP_CFG_REG); + l |= 0x02 << 3; /* Set to smart-idle mode */ + l |= 0x2 << 8; /* Set clock activity to perserve f-clock on idle */ + + /* Enable autoidle on OMAP2 / OMAP3 */ + if (cpu_is_omap24xx() || cpu_is_omap34xx()) + l |= 0x1 << 0; /* * Enable wake-up on OMAP2 CPUs. */ if (cpu_class_is_omap2()) - wakeup = 1; + l |= 1 << 2; + omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l); - __omap_dm_timer_reset(timer->io_base, autoidle, wakeup); + /* Match hardware reset default of posted mode */ + omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, + OMAP_TIMER_CTRL_POSTED); timer->posted = 1; } -void omap_dm_timer_prepare(struct omap_dm_timer *timer) +static void omap_dm_timer_prepare(struct omap_dm_timer *timer) { omap_dm_timer_enable(timer); omap_dm_timer_reset(timer); @@ -395,13 +531,25 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_start); void omap_dm_timer_stop(struct omap_dm_timer *timer) { - unsigned long rate = 0; + 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_OMAP2PLUS - rate = clk_get_rate(timer->fclk); + /* Readback to make sure write has completed */ + omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); + /* + * Wait for functional clock period x 3.5 to make sure that + * timer is stopped + */ + udelay(3500000 / clk_get_rate(timer->fclk) + 1); #endif - - __omap_dm_timer_stop(timer->io_base, timer->posted, rate); + } + /* Ack possibly pending interrupt */ + omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, + OMAP_TIMER_INT_OVERFLOW); } EXPORT_SYMBOL_GPL(omap_dm_timer_stop); @@ -424,11 +572,22 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_set_source); int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) { + int ret = -EINVAL; + if (source < 0 || source >= 3) return -EINVAL; - return __omap_dm_timer_set_source(timer->fclk, - dm_source_clocks[source]); + clk_disable(timer->fclk); + ret = clk_set_parent(timer->fclk, dm_source_clocks[source]); + clk_enable(timer->fclk); + + /* + * When the functional clock disappears, too quick writes seem + * to cause an abort. XXX Is this still necessary? + */ + __delay(300000); + + return ret; } EXPORT_SYMBOL_GPL(omap_dm_timer_set_source); @@ -466,7 +625,8 @@ void omap_dm_timer_set_load_start(struct omap_dm_timer *timer, int autoreload, } l |= OMAP_TIMER_CTRL_ST; - __omap_dm_timer_load_start(timer->io_base, l, load, timer->posted); + omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, load); + omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); } EXPORT_SYMBOL_GPL(omap_dm_timer_set_load_start); @@ -519,7 +679,8 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_set_prescaler); void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value) { - __omap_dm_timer_int_enable(timer->io_base, value); + omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value); + omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, value); } EXPORT_SYMBOL_GPL(omap_dm_timer_set_int_enable); @@ -535,13 +696,17 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_read_status); void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) { - __omap_dm_timer_write_status(timer->io_base, value); + omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value); } EXPORT_SYMBOL_GPL(omap_dm_timer_write_status); unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) { - return __omap_dm_timer_read_counter(timer->io_base, timer->posted); + unsigned int l; + + l = omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG); + + return l; } EXPORT_SYMBOL_GPL(omap_dm_timer_read_counter); @@ -572,7 +737,7 @@ int omap_dm_timers_active(void) } EXPORT_SYMBOL_GPL(omap_dm_timers_active); -static int __init omap_dm_timer_init(void) +int __init omap_dm_timer_init(void) { struct omap_dm_timer *timer; int i, map_size = SZ_8K; /* Module 4KB + L4 4KB except on omap1 */ @@ -625,16 +790,8 @@ static int __init omap_dm_timer_init(void) sprintf(clk_name, "gpt%d_fck", i + 1); timer->fclk = clk_get(NULL, clk_name); } - - /* One or two timers may be set up early for sys_timer */ - if (sys_timer_reserved & (1 << i)) { - timer->reserved = 1; - timer->posted = 1; - } #endif } return 0; } - -arch_initcall(omap_dm_timer_init); diff --git a/arch/arm/plat-omap/include/plat/clkdev_omap.h b/arch/arm/plat-omap/include/plat/clkdev_omap.h index 387a9638991..f1899a3e417 100644 --- a/arch/arm/plat-omap/include/plat/clkdev_omap.h +++ b/arch/arm/plat-omap/include/plat/clkdev_omap.h @@ -39,7 +39,6 @@ struct omap_clk { #define CK_36XX (1 << 10) /* 36xx/37xx-specific clocks */ #define CK_443X (1 << 11) #define CK_TI816X (1 << 12) -#define CK_446X (1 << 13) #define CK_34XX (CK_3430ES1 | CK_3430ES2PLUS) diff --git a/arch/arm/plat-omap/include/plat/clock.h b/arch/arm/plat-omap/include/plat/clock.h index df4b9683f17..006e599c661 100644 --- a/arch/arm/plat-omap/include/plat/clock.h +++ b/arch/arm/plat-omap/include/plat/clock.h @@ -58,12 +58,10 @@ struct clkops { #define RATE_IN_36XX (1 << 4) #define RATE_IN_4430 (1 << 5) #define RATE_IN_TI816X (1 << 6) -#define RATE_IN_4460 (1 << 7) #define RATE_IN_24XX (RATE_IN_242X | RATE_IN_243X) #define RATE_IN_34XX (RATE_IN_3430ES1 | RATE_IN_3430ES2PLUS) #define RATE_IN_3XXX (RATE_IN_34XX | RATE_IN_36XX) -#define RATE_IN_44XX (RATE_IN_4430 | RATE_IN_4460) /* RATE_IN_3430ES2PLUS_36XX includes 34xx/35xx with ES >=2, and all 36xx/37xx */ #define RATE_IN_3430ES2PLUS_36XX (RATE_IN_3430ES2PLUS | RATE_IN_36XX) @@ -154,7 +152,7 @@ struct dpll_data { u16 max_multiplier; u8 last_rounded_n; u8 min_divider; - u16 max_divider; + u8 max_divider; u8 modes; #if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) void __iomem *autoidle_reg; diff --git a/arch/arm/plat-omap/include/plat/common.h b/arch/arm/plat-omap/include/plat/common.h index 4564cc697d7..5288130be96 100644 --- a/arch/arm/plat-omap/include/plat/common.h +++ b/arch/arm/plat-omap/include/plat/common.h @@ -34,11 +34,7 @@ struct sys_timer; extern void omap_map_common_io(void); -extern struct sys_timer omap1_timer; -extern struct sys_timer omap2_timer; -extern struct sys_timer omap3_timer; -extern struct sys_timer omap3_secure_timer; -extern struct sys_timer omap4_timer; +extern struct sys_timer omap_timer; extern bool omap_32k_timer_init(void); extern int __init omap_init_clocksource_32k(void); extern unsigned long long notrace omap_32k_sched_clock(void); diff --git a/arch/arm/plat-omap/include/plat/cpu.h b/arch/arm/plat-omap/include/plat/cpu.h index 67b3d75884c..8198bb6cdb5 100644 --- a/arch/arm/plat-omap/include/plat/cpu.h +++ b/arch/arm/plat-omap/include/plat/cpu.h @@ -88,7 +88,6 @@ unsigned int omap_rev(void); * cpu_is_omap243x(): True for OMAP2430 * cpu_is_omap343x(): True for OMAP3430 * cpu_is_omap443x(): True for OMAP4430 - * cpu_is_omap446x(): True for OMAP4460 */ #define GET_OMAP_CLASS (omap_rev() & 0xff) @@ -124,7 +123,6 @@ IS_OMAP_SUBCLASS(243x, 0x243) IS_OMAP_SUBCLASS(343x, 0x343) IS_OMAP_SUBCLASS(363x, 0x363) IS_OMAP_SUBCLASS(443x, 0x443) -IS_OMAP_SUBCLASS(446x, 0x446) IS_TI_SUBCLASS(816x, 0x816) @@ -139,7 +137,6 @@ IS_TI_SUBCLASS(816x, 0x816) #define cpu_is_ti816x() 0 #define cpu_is_omap44xx() 0 #define cpu_is_omap443x() 0 -#define cpu_is_omap446x() 0 #if defined(MULTI_OMAP1) # if defined(CONFIG_ARCH_OMAP730) @@ -364,10 +361,8 @@ IS_OMAP_TYPE(3517, 0x3517) # if defined(CONFIG_ARCH_OMAP4) # undef cpu_is_omap44xx # undef cpu_is_omap443x -# undef cpu_is_omap446x # define cpu_is_omap44xx() is_omap44xx() # define cpu_is_omap443x() is_omap443x() -# define cpu_is_omap446x() is_omap446x() # endif /* Macros to detect if we have OMAP1 or OMAP2 */ @@ -415,9 +410,6 @@ IS_OMAP_TYPE(3517, 0x3517) #define OMAP4430_REV_ES2_1 (OMAP443X_CLASS | (0x21 << 8)) #define OMAP4430_REV_ES2_2 (OMAP443X_CLASS | (0x22 << 8)) -#define OMAP446X_CLASS 0x44600044 -#define OMAP4460_REV_ES1_0 (OMAP446X_CLASS | (0x10 << 8)) - /* * omap_chip bits * @@ -447,15 +439,13 @@ IS_OMAP_TYPE(3517, 0x3517) #define CHIP_IS_OMAP4430ES2_1 (1 << 12) #define CHIP_IS_OMAP4430ES2_2 (1 << 13) #define CHIP_IS_TI816X (1 << 14) -#define CHIP_IS_OMAP4460ES1_0 (1 << 15) #define CHIP_IS_OMAP24XX (CHIP_IS_OMAP2420 | CHIP_IS_OMAP2430) #define CHIP_IS_OMAP4430 (CHIP_IS_OMAP4430ES1 | \ CHIP_IS_OMAP4430ES2 | \ CHIP_IS_OMAP4430ES2_1 | \ - CHIP_IS_OMAP4430ES2_2 | \ - CHIP_IS_OMAP4460ES1_0) + CHIP_IS_OMAP4430ES2_2) /* * "GE" here represents "greater than or equal to" in terms of ES @@ -478,7 +468,7 @@ void omap2_check_revision(void); /* * Runtime detection of OMAP3 features */ -extern u32 omap_features; +extern u32 omap3_features; #define OMAP3_HAS_L2CACHE BIT(0) #define OMAP3_HAS_IVA BIT(1) @@ -488,15 +478,11 @@ extern u32 omap_features; #define OMAP3_HAS_192MHZ_CLK BIT(5) #define OMAP3_HAS_IO_WAKEUP BIT(6) #define OMAP3_HAS_SDRC BIT(7) -#define OMAP4_HAS_MPU_1GHZ BIT(8) -#define OMAP4_HAS_MPU_1_2GHZ BIT(9) -#define OMAP4_HAS_MPU_1_5GHZ BIT(10) - #define OMAP3_HAS_FEATURE(feat,flag) \ static inline unsigned int omap3_has_ ##feat(void) \ { \ - return omap_features & OMAP3_HAS_ ##flag; \ + return (omap3_features & OMAP3_HAS_ ##flag); \ } \ OMAP3_HAS_FEATURE(l2cache, L2CACHE) @@ -508,19 +494,4 @@ OMAP3_HAS_FEATURE(192mhz_clk, 192MHZ_CLK) OMAP3_HAS_FEATURE(io_wakeup, IO_WAKEUP) OMAP3_HAS_FEATURE(sdrc, SDRC) -/* - * Runtime detection of OMAP4 features - */ -extern u32 omap_features; - -#define OMAP4_HAS_FEATURE(feat, flag) \ -static inline unsigned int omap4_has_ ##feat(void) \ -{ \ - return omap_features & OMAP4_HAS_ ##flag; \ -} \ - -OMAP4_HAS_FEATURE(mpu_1ghz, MPU_1GHZ) -OMAP4_HAS_FEATURE(mpu_1_2ghz, MPU_1_2GHZ) -OMAP4_HAS_FEATURE(mpu_1_5ghz, MPU_1_5GHZ) - #endif diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h index eb5d16c60cd..d6c70d2f403 100644 --- a/arch/arm/plat-omap/include/plat/dmtimer.h +++ b/arch/arm/plat-omap/include/plat/dmtimer.h @@ -32,10 +32,6 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/clk.h> -#include <linux/delay.h> -#include <linux/io.h> - #ifndef __ASM_ARCH_DMTIMER_H #define __ASM_ARCH_DMTIMER_H @@ -60,8 +56,12 @@ */ #define OMAP_TIMER_IP_VERSION_1 0x1 struct omap_dm_timer; +extern struct omap_dm_timer *gptimer_wakeup; +extern struct sys_timer omap_timer; struct clk; +int omap_dm_timer_init(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); @@ -93,248 +93,5 @@ void 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. - */ - -/* register offsets */ -#define _OMAP_TIMER_ID_OFFSET 0x00 -#define _OMAP_TIMER_OCP_CFG_OFFSET 0x10 -#define _OMAP_TIMER_SYS_STAT_OFFSET 0x14 -#define _OMAP_TIMER_STAT_OFFSET 0x18 -#define _OMAP_TIMER_INT_EN_OFFSET 0x1c -#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_ID_REG (_OMAP_TIMER_ID_OFFSET \ - | (WP_NONE << WPSHIFT)) - -#define OMAP_TIMER_OCP_CFG_REG (_OMAP_TIMER_OCP_CFG_OFFSET \ - | (WP_NONE << WPSHIFT)) - -#define OMAP_TIMER_SYS_STAT_REG (_OMAP_TIMER_SYS_STAT_OFFSET \ - | (WP_NONE << WPSHIFT)) - -#define OMAP_TIMER_STAT_REG (_OMAP_TIMER_STAT_OFFSET \ - | (WP_NONE << WPSHIFT)) - -#define OMAP_TIMER_INT_EN_REG (_OMAP_TIMER_INT_EN_OFFSET \ - | (WP_NONE << WPSHIFT)) - -#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)) - -struct omap_dm_timer { - unsigned long phys_base; - int irq; -#ifdef CONFIG_ARCH_OMAP2PLUS - struct clk *iclk, *fclk; -#endif - void __iomem *io_base; - unsigned long rate; - unsigned reserved:1; - unsigned enabled:1; - unsigned posted:1; -}; - -extern u32 sys_timer_reserved; -void omap_dm_timer_prepare(struct omap_dm_timer *timer); - -static inline u32 __omap_dm_timer_read(void __iomem *base, u32 reg, - int posted) -{ - if (posted) - while (__raw_readl(base + (OMAP_TIMER_WRITE_PEND_REG & 0xff)) - & (reg >> WPSHIFT)) - cpu_relax(); - - return __raw_readl(base + (reg & 0xff)); -} - -static inline void __omap_dm_timer_write(void __iomem *base, u32 reg, u32 val, - int posted) -{ - if (posted) - while (__raw_readl(base + (OMAP_TIMER_WRITE_PEND_REG & 0xff)) - & (reg >> WPSHIFT)) - cpu_relax(); - - __raw_writel(val, base + (reg & 0xff)); -} - -/* Assumes the source clock has been set by caller */ -static inline void __omap_dm_timer_reset(void __iomem *base, int autoidle, - int wakeup) -{ - u32 l; - - l = __omap_dm_timer_read(base, OMAP_TIMER_OCP_CFG_REG, 0); - l |= 0x02 << 3; /* Set to smart-idle mode */ - l |= 0x2 << 8; /* Set clock activity to perserve f-clock on idle */ - - if (autoidle) - l |= 0x1 << 0; - - if (wakeup) - l |= 1 << 2; - - __omap_dm_timer_write(base, OMAP_TIMER_OCP_CFG_REG, l, 0); - - /* Match hardware reset default of posted mode */ - __omap_dm_timer_write(base, OMAP_TIMER_IF_CTRL_REG, - OMAP_TIMER_CTRL_POSTED, 0); -} - -static inline int __omap_dm_timer_set_source(struct clk *timer_fck, - struct clk *parent) -{ - int ret; - - clk_disable(timer_fck); - ret = clk_set_parent(timer_fck, parent); - clk_enable(timer_fck); - - /* - * When the functional clock disappears, too quick writes seem - * to cause an abort. XXX Is this still necessary? - */ - __delay(300000); - - return ret; -} - -static inline void __omap_dm_timer_stop(void __iomem *base, int posted, - unsigned long rate) -{ - u32 l; - - l = __omap_dm_timer_read(base, OMAP_TIMER_CTRL_REG, posted); - if (l & OMAP_TIMER_CTRL_ST) { - l &= ~0x1; - __omap_dm_timer_write(base, OMAP_TIMER_CTRL_REG, l, posted); -#ifdef CONFIG_ARCH_OMAP2PLUS - /* Readback to make sure write has completed */ - __omap_dm_timer_read(base, 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 */ - __omap_dm_timer_write(base, OMAP_TIMER_STAT_REG, - OMAP_TIMER_INT_OVERFLOW, 0); -} - -static inline void __omap_dm_timer_load_start(void __iomem *base, u32 ctrl, - unsigned int load, int posted) -{ - __omap_dm_timer_write(base, OMAP_TIMER_COUNTER_REG, load, posted); - __omap_dm_timer_write(base, OMAP_TIMER_CTRL_REG, ctrl, posted); -} - -static inline void __omap_dm_timer_int_enable(void __iomem *base, - unsigned int value) -{ - __omap_dm_timer_write(base, OMAP_TIMER_INT_EN_REG, value, 0); - __omap_dm_timer_write(base, OMAP_TIMER_WAKEUP_EN_REG, value, 0); -} - -static inline unsigned int __omap_dm_timer_read_counter(void __iomem *base, - int posted) -{ - return __omap_dm_timer_read(base, OMAP_TIMER_COUNTER_REG, posted); -} - -static inline void __omap_dm_timer_write_status(void __iomem *base, - unsigned int value) -{ - __omap_dm_timer_write(base, OMAP_TIMER_STAT_REG, value, 0); -} #endif /* __ASM_ARCH_DMTIMER_H */ diff --git a/arch/arm/plat-omap/include/plat/gpio.h b/arch/arm/plat-omap/include/plat/gpio.h index 91e8de3db08..ec97e00cb58 100644 --- a/arch/arm/plat-omap/include/plat/gpio.h +++ b/arch/arm/plat-omap/include/plat/gpio.h @@ -174,32 +174,12 @@ struct omap_gpio_dev_attr { bool dbck_flag; /* dbck required or not - True for OMAP3&4 */ }; -struct omap_gpio_reg_offs { - u16 revision; - u16 direction; - u16 datain; - u16 dataout; - u16 set_dataout; - u16 clr_dataout; - u16 irqstatus; - u16 irqstatus2; - u16 irqenable; - u16 set_irqenable; - u16 clr_irqenable; - u16 debounce; - u16 debounce_en; - - bool irqenable_inv; -}; - struct omap_gpio_platform_data { u16 virtual_irq_start; int bank_type; int bank_width; /* GPIO bank width */ int bank_stride; /* Only needed for omap1 MPUIO */ bool dbck_flag; /* dbck required or not - True for OMAP3&4 */ - - struct omap_gpio_reg_offs *regs; }; /* TODO: Analyze removing gpio_bank_count usage from driver code */ diff --git a/arch/arm/plat-omap/include/plat/i2c.h b/arch/arm/plat-omap/include/plat/i2c.h index 7c22b9e10dc..878d632c409 100644 --- a/arch/arm/plat-omap/include/plat/i2c.h +++ b/arch/arm/plat-omap/include/plat/i2c.h @@ -22,7 +22,6 @@ #define __ASM__ARCH_OMAP_I2C_H #include <linux/i2c.h> -#include <linux/i2c-omap.h> #if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE) extern int omap_register_i2c_bus(int bus_id, u32 clkrate, @@ -47,13 +46,10 @@ static inline int omap_register_i2c_bus(int bus_id, u32 clkrate, */ struct omap_i2c_dev_attr { u8 fifo_depth; - u32 flags; + u8 flags; }; void __init omap1_i2c_mux_pins(int bus_id); void __init omap2_i2c_mux_pins(int bus_id); -struct omap_hwmod; -int omap_i2c_reset(struct omap_hwmod *oh); - #endif /* __ASM__ARCH_OMAP_I2C_H */ diff --git a/arch/arm/plat-omap/include/plat/irqs.h b/arch/arm/plat-omap/include/plat/irqs.h index 926d25c780f..5a25098ea7e 100644 --- a/arch/arm/plat-omap/include/plat/irqs.h +++ b/arch/arm/plat-omap/include/plat/irqs.h @@ -407,19 +407,11 @@ #endif #define TWL6030_IRQ_END (TWL6030_IRQ_BASE + TWL6030_BASE_NR_IRQS) -#define TWL6040_CODEC_IRQ_BASE TWL6030_IRQ_END -#ifdef CONFIG_TWL6040_CODEC -#define TWL6040_CODEC_NR_IRQS 6 -#else -#define TWL6040_CODEC_NR_IRQS 0 -#endif -#define TWL6040_CODEC_IRQ_END (TWL6040_CODEC_IRQ_BASE + TWL6040_CODEC_NR_IRQS) - /* Total number of interrupts depends on the enabled blocks above */ -#if (TWL4030_GPIO_IRQ_END > TWL6040_CODEC_IRQ_END) +#if (TWL4030_GPIO_IRQ_END > TWL6030_IRQ_END) #define TWL_IRQ_END TWL4030_GPIO_IRQ_END #else -#define TWL_IRQ_END TWL6040_CODEC_IRQ_END +#define TWL_IRQ_END TWL6030_IRQ_END #endif /* GPMC related */ @@ -436,11 +428,7 @@ #define INTCPS_NR_IRQS 96 #ifndef __ASSEMBLY__ -extern void __iomem *omap_irq_base; -void omap1_init_irq(void); -void omap2_init_irq(void); -void omap3_init_irq(void); -void ti816x_init_irq(void); +extern void omap_init_irq(void); extern int omap_irq_pending(void); void omap_intc_save_context(void); void omap_intc_restore_context(void); diff --git a/arch/arm/plat-omap/include/plat/mcbsp.h b/arch/arm/plat-omap/include/plat/mcbsp.h index 9882c657b2d..f8f690ab299 100644 --- a/arch/arm/plat-omap/include/plat/mcbsp.h +++ b/arch/arm/plat-omap/include/plat/mcbsp.h @@ -24,6 +24,7 @@ #ifndef __ASM_ARCH_OMAP_MCBSP_H #define __ASM_ARCH_OMAP_MCBSP_H +#include <linux/completion.h> #include <linux/spinlock.h> #include <mach/hardware.h> @@ -33,7 +34,7 @@ #define OMAP_MCBSP_PLATFORM_DEVICE(port_nr) \ static struct platform_device omap_mcbsp##port_nr = { \ .name = "omap-mcbsp-dai", \ - .id = port_nr - 1, \ + .id = OMAP_MCBSP##port_nr, \ } #define MCBSP_CONFIG_TYPE2 0x2 @@ -332,6 +333,18 @@ struct omap_mcbsp_reg_cfg { }; typedef enum { + OMAP_MCBSP1 = 0, + OMAP_MCBSP2, + OMAP_MCBSP3, + OMAP_MCBSP4, + OMAP_MCBSP5 +} omap_mcbsp_id; + +typedef int __bitwise omap_mcbsp_io_type_t; +#define OMAP_MCBSP_IRQ_IO ((__force omap_mcbsp_io_type_t) 1) +#define OMAP_MCBSP_POLL_IO ((__force omap_mcbsp_io_type_t) 2) + +typedef enum { OMAP_MCBSP_WORD_8 = 0, OMAP_MCBSP_WORD_12, OMAP_MCBSP_WORD_16, @@ -340,6 +353,38 @@ typedef enum { OMAP_MCBSP_WORD_32, } omap_mcbsp_word_length; +typedef enum { + OMAP_MCBSP_CLK_RISING = 0, + OMAP_MCBSP_CLK_FALLING, +} omap_mcbsp_clk_polarity; + +typedef enum { + OMAP_MCBSP_FS_ACTIVE_HIGH = 0, + OMAP_MCBSP_FS_ACTIVE_LOW, +} omap_mcbsp_fs_polarity; + +typedef enum { + OMAP_MCBSP_CLK_STP_MODE_NO_DELAY = 0, + OMAP_MCBSP_CLK_STP_MODE_DELAY, +} omap_mcbsp_clk_stp_mode; + + +/******* SPI specific mode **********/ +typedef enum { + OMAP_MCBSP_SPI_MASTER = 0, + OMAP_MCBSP_SPI_SLAVE, +} omap_mcbsp_spi_mode; + +struct omap_mcbsp_spi_cfg { + omap_mcbsp_spi_mode spi_mode; + omap_mcbsp_clk_polarity rx_clock_polarity; + omap_mcbsp_clk_polarity tx_clock_polarity; + omap_mcbsp_fs_polarity fsx_polarity; + u8 clk_div; + omap_mcbsp_clk_stp_mode clk_stp_mode; + omap_mcbsp_word_length word_length; +}; + /* Platform specific configuration */ struct omap_mcbsp_ops { void (*request)(unsigned int); @@ -377,13 +422,25 @@ struct omap_mcbsp { void __iomem *io_base; u8 id; u8 free; + omap_mcbsp_word_length rx_word_length; + omap_mcbsp_word_length tx_word_length; + omap_mcbsp_io_type_t io_type; /* IRQ or poll */ + /* IRQ based TX/RX */ int rx_irq; int tx_irq; /* DMA stuff */ u8 dma_rx_sync; + short dma_rx_lch; u8 dma_tx_sync; + short dma_tx_lch; + + /* Completion queues */ + struct completion tx_irq_completion; + struct completion rx_irq_completion; + struct completion tx_dma_completion; + struct completion rx_dma_completion; /* Protect the field .free, while checking if the mcbsp is in use */ spinlock_t lock; @@ -442,9 +499,24 @@ int omap_mcbsp_request(unsigned int id); void omap_mcbsp_free(unsigned int id); void omap_mcbsp_start(unsigned int id, int tx, int rx); void omap_mcbsp_stop(unsigned int id, int tx, int rx); +void omap_mcbsp_xmit_word(unsigned int id, u32 word); +u32 omap_mcbsp_recv_word(unsigned int id); + +int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int length); +int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int length); +int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word); +int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 * word); + /* McBSP functional clock source changing function */ extern int omap2_mcbsp_set_clks_src(u8 id, u8 fck_src_id); +/* SPI specific API */ +void omap_mcbsp_set_spi_mode(unsigned int id, const struct omap_mcbsp_spi_cfg * spi_cfg); + +/* Polled read/write functions */ +int omap_mcbsp_pollread(unsigned int id, u16 * buf); +int omap_mcbsp_pollwrite(unsigned int id, u16 buf); +int omap_mcbsp_set_io_type(unsigned int id, omap_mcbsp_io_type_t io_type); /* McBSP signal muxing API */ void omap2_mcbsp1_mux_clkr_src(u8 mux); diff --git a/arch/arm/plat-omap/include/plat/nand.h b/arch/arm/plat-omap/include/plat/nand.h index 67fc5060183..d86d1ecf006 100644 --- a/arch/arm/plat-omap/include/plat/nand.h +++ b/arch/arm/plat-omap/include/plat/nand.h @@ -19,11 +19,15 @@ enum nand_io { }; struct omap_nand_platform_data { + unsigned int options; int cs; + int gpio_irq; struct mtd_partition *parts; struct gpmc_timings *gpmc_t; int nr_parts; - bool dev_ready; + int (*nand_setup)(void); + int (*dev_ready)(struct omap_nand_platform_data *); + int dma_channel; int gpmc_irq; enum nand_io xfer_type; unsigned long phys_base; diff --git a/arch/arm/plat-omap/include/plat/omap-pm.h b/arch/arm/plat-omap/include/plat/omap-pm.h index 0840df813f4..c0a75205303 100644 --- a/arch/arm/plat-omap/include/plat/omap-pm.h +++ b/arch/arm/plat-omap/include/plat/omap-pm.h @@ -40,7 +40,11 @@ * framework starts. The "_if_" is to avoid name collisions with the * PM idle-loop code. */ +#ifdef CONFIG_OMAP_PM_NONE +#define omap_pm_if_early_init() 0 +#else int __init omap_pm_if_early_init(void); +#endif /** * omap_pm_if_init - OMAP PM init code called after clock fw init @@ -48,7 +52,11 @@ int __init omap_pm_if_early_init(void); * The main initialization code. OPP tables are passed in here. The * "_if_" is to avoid name collisions with the PM idle-loop code. */ +#ifdef CONFIG_OMAP_PM_NONE +#define omap_pm_if_init() 0 +#else int __init omap_pm_if_init(void); +#endif /** * omap_pm_if_exit - OMAP PM exit code diff --git a/arch/arm/plat-omap/include/plat/omap4-keypad.h b/arch/arm/plat-omap/include/plat/omap4-keypad.h index 9fe6c878323..2b1d9bc1eeb 100644 --- a/arch/arm/plat-omap/include/plat/omap4-keypad.h +++ b/arch/arm/plat-omap/include/plat/omap4-keypad.h @@ -10,6 +10,5 @@ struct omap4_keypad_platform_data { u8 cols; }; -extern int omap4_keyboard_init(struct omap4_keypad_platform_data *, - struct omap_board_data *); +extern int omap4_keyboard_init(struct omap4_keypad_platform_data *); #endif diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h index 0e329ca88a7..1adea9c6298 100644 --- a/arch/arm/plat-omap/include/plat/omap_hwmod.h +++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h @@ -2,7 +2,6 @@ * omap_hwmod macros, structures * * Copyright (C) 2009-2011 Nokia Corporation - * Copyright (C) 2011 Texas Instruments, Inc. * Paul Walmsley * * Created in collaboration with (alphabetical order): BenoƮt Cousson, @@ -78,13 +77,9 @@ extern struct omap_hwmod_sysc_fields omap_hwmod_sysc_type2; #define HWMOD_IDLEMODE_FORCE (1 << 0) #define HWMOD_IDLEMODE_NO (1 << 1) #define HWMOD_IDLEMODE_SMART (1 << 2) +/* Slave idle mode flag only */ #define HWMOD_IDLEMODE_SMART_WKUP (1 << 3) -/* modulemode control type (SW or HW) */ -#define MODULEMODE_HWCTRL 1 -#define MODULEMODE_SWCTRL 2 - - /** * struct omap_hwmod_mux_info - hwmod specific mux configuration * @pads: array of omap_device_pad entries @@ -103,7 +98,7 @@ struct omap_hwmod_mux_info { /** * struct omap_hwmod_irq_info - MPU IRQs used by the hwmod * @name: name of the IRQ channel (module local name) - * @irq: IRQ channel ID (should be non-negative except -1 = terminator) + * @irq_ch: IRQ channel ID * * @name should be something short, e.g., "tx" or "rx". It is for use * by platform_get_resource_byname(). It is defined locally to the @@ -111,13 +106,13 @@ struct omap_hwmod_mux_info { */ struct omap_hwmod_irq_info { const char *name; - s16 irq; + u16 irq; }; /** * struct omap_hwmod_dma_info - DMA channels used by the hwmod * @name: name of the DMA channel (module local name) - * @dma_req: DMA request ID (should be non-negative except -1 = terminator) + * @dma_req: DMA request ID * * @name should be something short, e.g., "tx" or "rx". It is for use * by platform_get_resource_byname(). It is defined locally to the @@ -125,7 +120,7 @@ struct omap_hwmod_irq_info { */ struct omap_hwmod_dma_info { const char *name; - s16 dma_req; + u16 dma_req; }; /** @@ -225,6 +220,7 @@ struct omap_hwmod_addr_space { * @clk: interface clock: OMAP clock name * @_clk: pointer to the interface struct clk (filled in at runtime) * @fw: interface firewall data + * @addr_cnt: ARRAY_SIZE(@addr) * @width: OCP data width * @user: initiators using this interface (see OCP_USER_* macros above) * @flags: OCP interface flags (see OCPIF_* macros above) @@ -243,6 +239,7 @@ struct omap_hwmod_ocp_if { union { struct omap_hwmod_omap2_firewall omap2; } fw; + u8 addr_cnt; u8 width; u8 user; u8 flags; @@ -261,7 +258,6 @@ struct omap_hwmod_ocp_if { #define MSTANDBY_FORCE (HWMOD_IDLEMODE_FORCE << MASTER_STANDBY_SHIFT) #define MSTANDBY_NO (HWMOD_IDLEMODE_NO << MASTER_STANDBY_SHIFT) #define MSTANDBY_SMART (HWMOD_IDLEMODE_SMART << MASTER_STANDBY_SHIFT) -#define MSTANDBY_SMART_WKUP (HWMOD_IDLEMODE_SMART_WKUP << MASTER_STANDBY_SHIFT) /* omap_hwmod_sysconfig.sysc_flags capability flags */ #define SYSC_HAS_AUTOIDLE (1 << 0) @@ -366,11 +362,9 @@ struct omap_hwmod_omap2_prcm { * @submodule_wkdep_bit: bit shift of the WKDEP range */ struct omap_hwmod_omap4_prcm { - u16 clkctrl_offs; - u16 rstctrl_offs; - u16 context_offs; + void __iomem *clkctrl_reg; + void __iomem *rstctrl_reg; u8 submodule_wkdep_bit; - u8 modulemode; }; @@ -474,8 +468,8 @@ struct omap_hwmod_class { * @name: name of the hwmod * @class: struct omap_hwmod_class * to the class of this hwmod * @od: struct omap_device currently associated with this hwmod (internal use) - * @mpu_irqs: ptr to an array of MPU IRQs - * @sdma_reqs: ptr to an array of System DMA request IDs + * @mpu_irqs: ptr to an array of MPU IRQs (see also mpu_irqs_cnt) + * @sdma_reqs: ptr to an array of System DMA request IDs (see sdma_reqs_cnt) * @prcm: PRCM data pertaining to this hwmod * @main_clk: main clock: OMAP clock name * @_clk: pointer to the main struct clk (filled in at runtime) @@ -488,6 +482,8 @@ struct omap_hwmod_class { * @_sysc_cache: internal-use hwmod flags * @_mpu_rt_va: cached register target start address (internal use) * @_mpu_port_index: cached MPU register target slave ID (internal use) + * @mpu_irqs_cnt: number of @mpu_irqs + * @sdma_reqs_cnt: number of @sdma_reqs * @opt_clks_cnt: number of @opt_clks * @master_cnt: number of @master entries * @slaves_cnt: number of @slave entries @@ -523,8 +519,6 @@ struct omap_hwmod { const char *main_clk; struct clk *_clk; struct omap_hwmod_opt_clk *opt_clks; - char *clkdm_name; - struct clockdomain *clkdm; char *vdd_name; struct voltagedomain *voltdm; struct omap_hwmod_ocp_if **masters; /* connect to *_IA */ @@ -537,6 +531,8 @@ struct omap_hwmod { u16 flags; u8 _mpu_port_index; u8 response_lat; + u8 mpu_irqs_cnt; + u8 sdma_reqs_cnt; u8 rst_lines_cnt; u8 opt_clks_cnt; u8 masters_cnt; @@ -576,7 +572,6 @@ void omap_hwmod_ocp_barrier(struct omap_hwmod *oh); void omap_hwmod_write(u32 v, struct omap_hwmod *oh, u16 reg_offs); u32 omap_hwmod_read(struct omap_hwmod *oh, u16 reg_offs); -int omap_hwmod_softreset(struct omap_hwmod *oh); int omap_hwmod_count_resources(struct omap_hwmod *oh); int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res); diff --git a/arch/arm/plat-omap/include/plat/uncompress.h b/arch/arm/plat-omap/include/plat/uncompress.h index a067484cc4a..ac4b60d9aa2 100644 --- a/arch/arm/plat-omap/include/plat/uncompress.h +++ b/arch/arm/plat-omap/include/plat/uncompress.h @@ -148,7 +148,6 @@ static inline void __arch_decomp_setup(unsigned long arch_id) /* omap3 based boards using UART3 */ DEBUG_LL_OMAP3(3, cm_t35); DEBUG_LL_OMAP3(3, cm_t3517); - DEBUG_LL_OMAP3(3, cm_t3730); DEBUG_LL_OMAP3(3, craneboard); DEBUG_LL_OMAP3(3, devkit8000); DEBUG_LL_OMAP3(3, igep0020); diff --git a/arch/arm/plat-omap/iovmm.c b/arch/arm/plat-omap/iovmm.c index c60737c49a3..83a37c54342 100644 --- a/arch/arm/plat-omap/iovmm.c +++ b/arch/arm/plat-omap/iovmm.c @@ -72,7 +72,7 @@ static size_t sgtable_len(const struct sg_table *sgt) for_each_sg(sgt->sgl, sg, sgt->nents, i) { size_t bytes; - bytes = sg->length; + bytes = sg_dma_len(sg); if (!iopgsz_ok(bytes)) { pr_err("%s: sg[%d] not iommu pagesize(%x)\n", @@ -198,7 +198,7 @@ static void *vmap_sg(const struct sg_table *sgt) int err; pa = sg_phys(sg); - bytes = sg->length; + bytes = sg_dma_len(sg); BUG_ON(bytes != PAGE_SIZE); @@ -476,7 +476,7 @@ static int map_iovm_area(struct iommu *obj, struct iovm_struct *new, struct iotlb_entry e; pa = sg_phys(sg); - bytes = sg->length; + bytes = sg_dma_len(sg); flags &= ~IOVMF_PGSZ_MASK; pgsz = bytes_to_iopgsz(bytes); diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index 6c62af10871..5587acf0eb2 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -16,6 +16,8 @@ #include <linux/init.h> #include <linux/device.h> #include <linux/platform_device.h> +#include <linux/wait.h> +#include <linux/completion.h> #include <linux/interrupt.h> #include <linux/err.h> #include <linux/clk.h> @@ -23,6 +25,7 @@ #include <linux/io.h> #include <linux/slab.h> +#include <plat/dma.h> #include <plat/mcbsp.h> #include <plat/omap_device.h> #include <linux/pm_runtime.h> @@ -133,6 +136,8 @@ static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id) irqst_spcr2); /* Writing zero to XSYNC_ERR clears the IRQ */ MCBSP_WRITE(mcbsp_tx, SPCR2, MCBSP_READ_CACHE(mcbsp_tx, SPCR2)); + } else { + complete(&mcbsp_tx->tx_irq_completion); } return IRQ_HANDLED; @@ -151,11 +156,41 @@ static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id) irqst_spcr1); /* Writing zero to RSYNC_ERR clears the IRQ */ MCBSP_WRITE(mcbsp_rx, SPCR1, MCBSP_READ_CACHE(mcbsp_rx, SPCR1)); + } else { + complete(&mcbsp_rx->rx_irq_completion); } return IRQ_HANDLED; } +static void omap_mcbsp_tx_dma_callback(int lch, u16 ch_status, void *data) +{ + struct omap_mcbsp *mcbsp_dma_tx = data; + + dev_dbg(mcbsp_dma_tx->dev, "TX DMA callback : 0x%x\n", + MCBSP_READ(mcbsp_dma_tx, SPCR2)); + + /* We can free the channels */ + omap_free_dma(mcbsp_dma_tx->dma_tx_lch); + mcbsp_dma_tx->dma_tx_lch = -1; + + complete(&mcbsp_dma_tx->tx_dma_completion); +} + +static void omap_mcbsp_rx_dma_callback(int lch, u16 ch_status, void *data) +{ + struct omap_mcbsp *mcbsp_dma_rx = data; + + dev_dbg(mcbsp_dma_rx->dev, "RX DMA callback : 0x%x\n", + MCBSP_READ(mcbsp_dma_rx, SPCR2)); + + /* We can free the channels */ + omap_free_dma(mcbsp_dma_rx->dma_rx_lch); + mcbsp_dma_rx->dma_rx_lch = -1; + + complete(&mcbsp_dma_rx->rx_dma_completion); +} + /* * omap_mcbsp_config simply write a config to the * appropriate McBSP. @@ -723,6 +758,37 @@ static inline void omap_st_start(struct omap_mcbsp *mcbsp) {} static inline void omap_st_stop(struct omap_mcbsp *mcbsp) {} #endif +/* + * We can choose between IRQ based or polled IO. + * This needs to be called before omap_mcbsp_request(). + */ +int omap_mcbsp_set_io_type(unsigned int id, omap_mcbsp_io_type_t io_type) +{ + struct omap_mcbsp *mcbsp; + + if (!omap_mcbsp_check_valid_id(id)) { + printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); + return -ENODEV; + } + mcbsp = id_to_mcbsp_ptr(id); + + spin_lock(&mcbsp->lock); + + if (!mcbsp->free) { + dev_err(mcbsp->dev, "McBSP%d is currently in use\n", + mcbsp->id); + spin_unlock(&mcbsp->lock); + return -EINVAL; + } + + mcbsp->io_type = io_type; + + spin_unlock(&mcbsp->lock); + + return 0; +} +EXPORT_SYMBOL(omap_mcbsp_set_io_type); + int omap_mcbsp_request(unsigned int id) { struct omap_mcbsp *mcbsp; @@ -767,24 +833,29 @@ int omap_mcbsp_request(unsigned int id) MCBSP_WRITE(mcbsp, SPCR1, 0); MCBSP_WRITE(mcbsp, SPCR2, 0); - err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler, - 0, "McBSP", (void *)mcbsp); - if (err != 0) { - dev_err(mcbsp->dev, "Unable to request TX IRQ %d " - "for McBSP%d\n", mcbsp->tx_irq, - mcbsp->id); - goto err_clk_disable; - } - - if (mcbsp->rx_irq) { - err = request_irq(mcbsp->rx_irq, - omap_mcbsp_rx_irq_handler, - 0, "McBSP", (void *)mcbsp); + if (mcbsp->io_type == OMAP_MCBSP_IRQ_IO) { + /* We need to get IRQs here */ + init_completion(&mcbsp->tx_irq_completion); + err = request_irq(mcbsp->tx_irq, omap_mcbsp_tx_irq_handler, + 0, "McBSP", (void *)mcbsp); if (err != 0) { - dev_err(mcbsp->dev, "Unable to request RX IRQ %d " - "for McBSP%d\n", mcbsp->rx_irq, + dev_err(mcbsp->dev, "Unable to request TX IRQ %d " + "for McBSP%d\n", mcbsp->tx_irq, mcbsp->id); - goto err_free_irq; + goto err_clk_disable; + } + + if (mcbsp->rx_irq) { + init_completion(&mcbsp->rx_irq_completion); + err = request_irq(mcbsp->rx_irq, + omap_mcbsp_rx_irq_handler, + 0, "McBSP", (void *)mcbsp); + if (err != 0) { + dev_err(mcbsp->dev, "Unable to request RX IRQ %d " + "for McBSP%d\n", mcbsp->rx_irq, + mcbsp->id); + goto err_free_irq; + } } } @@ -830,9 +901,12 @@ void omap_mcbsp_free(unsigned int id) pm_runtime_put_sync(mcbsp->dev); - if (mcbsp->rx_irq) - free_irq(mcbsp->rx_irq, (void *)mcbsp); - free_irq(mcbsp->tx_irq, (void *)mcbsp); + if (mcbsp->io_type == OMAP_MCBSP_IRQ_IO) { + /* Free IRQs */ + if (mcbsp->rx_irq) + free_irq(mcbsp->rx_irq, (void *)mcbsp); + free_irq(mcbsp->tx_irq, (void *)mcbsp); + } reg_cache = mcbsp->reg_cache; @@ -869,6 +943,9 @@ void omap_mcbsp_start(unsigned int id, int tx, int rx) if (cpu_is_omap34xx()) omap_st_start(mcbsp); + mcbsp->rx_word_length = (MCBSP_READ_CACHE(mcbsp, RCR1) >> 5) & 0x7; + mcbsp->tx_word_length = (MCBSP_READ_CACHE(mcbsp, XCR1) >> 5) & 0x7; + /* Only enable SRG, if McBSP is master */ w = MCBSP_READ_CACHE(mcbsp, PCR0); if (w & (FSXM | FSRM | CLKXM | CLKRM)) @@ -966,32 +1043,484 @@ void omap_mcbsp_stop(unsigned int id, int tx, int rx) } EXPORT_SYMBOL(omap_mcbsp_stop); +/* polled mcbsp i/o operations */ +int omap_mcbsp_pollwrite(unsigned int id, u16 buf) +{ + struct omap_mcbsp *mcbsp; + + if (!omap_mcbsp_check_valid_id(id)) { + printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); + return -ENODEV; + } + + mcbsp = id_to_mcbsp_ptr(id); + + MCBSP_WRITE(mcbsp, DXR1, buf); + /* if frame sync error - clear the error */ + if (MCBSP_READ(mcbsp, SPCR2) & XSYNC_ERR) { + /* clear error */ + MCBSP_WRITE(mcbsp, SPCR2, MCBSP_READ_CACHE(mcbsp, SPCR2)); + /* resend */ + return -1; + } else { + /* wait for transmit confirmation */ + int attemps = 0; + while (!(MCBSP_READ(mcbsp, SPCR2) & XRDY)) { + if (attemps++ > 1000) { + MCBSP_WRITE(mcbsp, SPCR2, + MCBSP_READ_CACHE(mcbsp, SPCR2) & + (~XRST)); + udelay(10); + MCBSP_WRITE(mcbsp, SPCR2, + MCBSP_READ_CACHE(mcbsp, SPCR2) | + (XRST)); + udelay(10); + dev_err(mcbsp->dev, "Could not write to" + " McBSP%d Register\n", mcbsp->id); + return -2; + } + } + } + + return 0; +} +EXPORT_SYMBOL(omap_mcbsp_pollwrite); + +int omap_mcbsp_pollread(unsigned int id, u16 *buf) +{ + struct omap_mcbsp *mcbsp; + + if (!omap_mcbsp_check_valid_id(id)) { + printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); + return -ENODEV; + } + mcbsp = id_to_mcbsp_ptr(id); + + /* if frame sync error - clear the error */ + if (MCBSP_READ(mcbsp, SPCR1) & RSYNC_ERR) { + /* clear error */ + MCBSP_WRITE(mcbsp, SPCR1, MCBSP_READ_CACHE(mcbsp, SPCR1)); + /* resend */ + return -1; + } else { + /* wait for receive confirmation */ + int attemps = 0; + while (!(MCBSP_READ(mcbsp, SPCR1) & RRDY)) { + if (attemps++ > 1000) { + MCBSP_WRITE(mcbsp, SPCR1, + MCBSP_READ_CACHE(mcbsp, SPCR1) & + (~RRST)); + udelay(10); + MCBSP_WRITE(mcbsp, SPCR1, + MCBSP_READ_CACHE(mcbsp, SPCR1) | + (RRST)); + udelay(10); + dev_err(mcbsp->dev, "Could not read from" + " McBSP%d Register\n", mcbsp->id); + return -2; + } + } + } + *buf = MCBSP_READ(mcbsp, DRR1); + + return 0; +} +EXPORT_SYMBOL(omap_mcbsp_pollread); + +/* + * IRQ based word transmission. + */ +void omap_mcbsp_xmit_word(unsigned int id, u32 word) +{ + struct omap_mcbsp *mcbsp; + omap_mcbsp_word_length word_length; + + if (!omap_mcbsp_check_valid_id(id)) { + printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); + return; + } + + mcbsp = id_to_mcbsp_ptr(id); + word_length = mcbsp->tx_word_length; + + wait_for_completion(&mcbsp->tx_irq_completion); + + if (word_length > OMAP_MCBSP_WORD_16) + MCBSP_WRITE(mcbsp, DXR2, word >> 16); + MCBSP_WRITE(mcbsp, DXR1, word & 0xffff); +} +EXPORT_SYMBOL(omap_mcbsp_xmit_word); + +u32 omap_mcbsp_recv_word(unsigned int id) +{ + struct omap_mcbsp *mcbsp; + u16 word_lsb, word_msb = 0; + omap_mcbsp_word_length word_length; + + if (!omap_mcbsp_check_valid_id(id)) { + printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); + return -ENODEV; + } + mcbsp = id_to_mcbsp_ptr(id); + + word_length = mcbsp->rx_word_length; + + wait_for_completion(&mcbsp->rx_irq_completion); + + if (word_length > OMAP_MCBSP_WORD_16) + word_msb = MCBSP_READ(mcbsp, DRR2); + word_lsb = MCBSP_READ(mcbsp, DRR1); + + return (word_lsb | (word_msb << 16)); +} +EXPORT_SYMBOL(omap_mcbsp_recv_word); + +int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word) +{ + struct omap_mcbsp *mcbsp; + omap_mcbsp_word_length tx_word_length; + omap_mcbsp_word_length rx_word_length; + u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0; + + if (!omap_mcbsp_check_valid_id(id)) { + printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); + return -ENODEV; + } + mcbsp = id_to_mcbsp_ptr(id); + tx_word_length = mcbsp->tx_word_length; + rx_word_length = mcbsp->rx_word_length; + + if (tx_word_length != rx_word_length) + return -EINVAL; + + /* First we wait for the transmitter to be ready */ + spcr2 = MCBSP_READ(mcbsp, SPCR2); + while (!(spcr2 & XRDY)) { + spcr2 = MCBSP_READ(mcbsp, SPCR2); + if (attempts++ > 1000) { + /* We must reset the transmitter */ + MCBSP_WRITE(mcbsp, SPCR2, + MCBSP_READ_CACHE(mcbsp, SPCR2) & (~XRST)); + udelay(10); + MCBSP_WRITE(mcbsp, SPCR2, + MCBSP_READ_CACHE(mcbsp, SPCR2) | XRST); + udelay(10); + dev_err(mcbsp->dev, "McBSP%d transmitter not " + "ready\n", mcbsp->id); + return -EAGAIN; + } + } + + /* Now we can push the data */ + if (tx_word_length > OMAP_MCBSP_WORD_16) + MCBSP_WRITE(mcbsp, DXR2, word >> 16); + MCBSP_WRITE(mcbsp, DXR1, word & 0xffff); + + /* We wait for the receiver to be ready */ + spcr1 = MCBSP_READ(mcbsp, SPCR1); + while (!(spcr1 & RRDY)) { + spcr1 = MCBSP_READ(mcbsp, SPCR1); + if (attempts++ > 1000) { + /* We must reset the receiver */ + MCBSP_WRITE(mcbsp, SPCR1, + MCBSP_READ_CACHE(mcbsp, SPCR1) & (~RRST)); + udelay(10); + MCBSP_WRITE(mcbsp, SPCR1, + MCBSP_READ_CACHE(mcbsp, SPCR1) | RRST); + udelay(10); + dev_err(mcbsp->dev, "McBSP%d receiver not " + "ready\n", mcbsp->id); + return -EAGAIN; + } + } + + /* Receiver is ready, let's read the dummy data */ + if (rx_word_length > OMAP_MCBSP_WORD_16) + word_msb = MCBSP_READ(mcbsp, DRR2); + word_lsb = MCBSP_READ(mcbsp, DRR1); + + return 0; +} +EXPORT_SYMBOL(omap_mcbsp_spi_master_xmit_word_poll); + +int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 *word) +{ + struct omap_mcbsp *mcbsp; + u32 clock_word = 0; + omap_mcbsp_word_length tx_word_length; + omap_mcbsp_word_length rx_word_length; + u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0; + + if (!omap_mcbsp_check_valid_id(id)) { + printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); + return -ENODEV; + } + + mcbsp = id_to_mcbsp_ptr(id); + + tx_word_length = mcbsp->tx_word_length; + rx_word_length = mcbsp->rx_word_length; + + if (tx_word_length != rx_word_length) + return -EINVAL; + + /* First we wait for the transmitter to be ready */ + spcr2 = MCBSP_READ(mcbsp, SPCR2); + while (!(spcr2 & XRDY)) { + spcr2 = MCBSP_READ(mcbsp, SPCR2); + if (attempts++ > 1000) { + /* We must reset the transmitter */ + MCBSP_WRITE(mcbsp, SPCR2, + MCBSP_READ_CACHE(mcbsp, SPCR2) & (~XRST)); + udelay(10); + MCBSP_WRITE(mcbsp, SPCR2, + MCBSP_READ_CACHE(mcbsp, SPCR2) | XRST); + udelay(10); + dev_err(mcbsp->dev, "McBSP%d transmitter not " + "ready\n", mcbsp->id); + return -EAGAIN; + } + } + + /* We first need to enable the bus clock */ + if (tx_word_length > OMAP_MCBSP_WORD_16) + MCBSP_WRITE(mcbsp, DXR2, clock_word >> 16); + MCBSP_WRITE(mcbsp, DXR1, clock_word & 0xffff); + + /* We wait for the receiver to be ready */ + spcr1 = MCBSP_READ(mcbsp, SPCR1); + while (!(spcr1 & RRDY)) { + spcr1 = MCBSP_READ(mcbsp, SPCR1); + if (attempts++ > 1000) { + /* We must reset the receiver */ + MCBSP_WRITE(mcbsp, SPCR1, + MCBSP_READ_CACHE(mcbsp, SPCR1) & (~RRST)); + udelay(10); + MCBSP_WRITE(mcbsp, SPCR1, + MCBSP_READ_CACHE(mcbsp, SPCR1) | RRST); + udelay(10); + dev_err(mcbsp->dev, "McBSP%d receiver not " + "ready\n", mcbsp->id); + return -EAGAIN; + } + } + + /* Receiver is ready, there is something for us */ + if (rx_word_length > OMAP_MCBSP_WORD_16) + word_msb = MCBSP_READ(mcbsp, DRR2); + word_lsb = MCBSP_READ(mcbsp, DRR1); + + word[0] = (word_lsb | (word_msb << 16)); + + return 0; +} +EXPORT_SYMBOL(omap_mcbsp_spi_master_recv_word_poll); + /* - * The following functions are only required on an OMAP1-only build. - * mach-omap2/mcbsp.c contains the real functions + * Simple DMA based buffer rx/tx routines. + * Nothing fancy, just a single buffer tx/rx through DMA. + * The DMA resources are released once the transfer is done. + * For anything fancier, you should use your own customized DMA + * routines and callbacks. */ -#ifndef CONFIG_ARCH_OMAP2PLUS -int omap2_mcbsp_set_clks_src(u8 id, u8 fck_src_id) +int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, + unsigned int length) { - WARN(1, "%s: should never be called on an OMAP1-only kernel\n", - __func__); - return -EINVAL; + struct omap_mcbsp *mcbsp; + int dma_tx_ch; + int src_port = 0; + int dest_port = 0; + int sync_dev = 0; + + if (!omap_mcbsp_check_valid_id(id)) { + printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); + return -ENODEV; + } + mcbsp = id_to_mcbsp_ptr(id); + + if (omap_request_dma(mcbsp->dma_tx_sync, "McBSP TX", + omap_mcbsp_tx_dma_callback, + mcbsp, + &dma_tx_ch)) { + dev_err(mcbsp->dev, " Unable to request DMA channel for " + "McBSP%d TX. Trying IRQ based TX\n", + mcbsp->id); + return -EAGAIN; + } + mcbsp->dma_tx_lch = dma_tx_ch; + + dev_err(mcbsp->dev, "McBSP%d TX DMA on channel %d\n", mcbsp->id, + dma_tx_ch); + + init_completion(&mcbsp->tx_dma_completion); + + if (cpu_class_is_omap1()) { + src_port = OMAP_DMA_PORT_TIPB; + dest_port = OMAP_DMA_PORT_EMIFF; + } + if (cpu_class_is_omap2()) + sync_dev = mcbsp->dma_tx_sync; + + omap_set_dma_transfer_params(mcbsp->dma_tx_lch, + OMAP_DMA_DATA_TYPE_S16, + length >> 1, 1, + OMAP_DMA_SYNC_ELEMENT, + sync_dev, 0); + + omap_set_dma_dest_params(mcbsp->dma_tx_lch, + src_port, + OMAP_DMA_AMODE_CONSTANT, + mcbsp->phys_base + OMAP_MCBSP_REG_DXR1, + 0, 0); + + omap_set_dma_src_params(mcbsp->dma_tx_lch, + dest_port, + OMAP_DMA_AMODE_POST_INC, + buffer, + 0, 0); + + omap_start_dma(mcbsp->dma_tx_lch); + wait_for_completion(&mcbsp->tx_dma_completion); + + return 0; } +EXPORT_SYMBOL(omap_mcbsp_xmit_buffer); -void omap2_mcbsp1_mux_clkr_src(u8 mux) +int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, + unsigned int length) { - WARN(1, "%s: should never be called on an OMAP1-only kernel\n", - __func__); - return; + struct omap_mcbsp *mcbsp; + int dma_rx_ch; + int src_port = 0; + int dest_port = 0; + int sync_dev = 0; + + if (!omap_mcbsp_check_valid_id(id)) { + printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); + return -ENODEV; + } + mcbsp = id_to_mcbsp_ptr(id); + + if (omap_request_dma(mcbsp->dma_rx_sync, "McBSP RX", + omap_mcbsp_rx_dma_callback, + mcbsp, + &dma_rx_ch)) { + dev_err(mcbsp->dev, "Unable to request DMA channel for " + "McBSP%d RX. Trying IRQ based RX\n", + mcbsp->id); + return -EAGAIN; + } + mcbsp->dma_rx_lch = dma_rx_ch; + + dev_err(mcbsp->dev, "McBSP%d RX DMA on channel %d\n", mcbsp->id, + dma_rx_ch); + + init_completion(&mcbsp->rx_dma_completion); + + if (cpu_class_is_omap1()) { + src_port = OMAP_DMA_PORT_TIPB; + dest_port = OMAP_DMA_PORT_EMIFF; + } + if (cpu_class_is_omap2()) + sync_dev = mcbsp->dma_rx_sync; + + omap_set_dma_transfer_params(mcbsp->dma_rx_lch, + OMAP_DMA_DATA_TYPE_S16, + length >> 1, 1, + OMAP_DMA_SYNC_ELEMENT, + sync_dev, 0); + + omap_set_dma_src_params(mcbsp->dma_rx_lch, + src_port, + OMAP_DMA_AMODE_CONSTANT, + mcbsp->phys_base + OMAP_MCBSP_REG_DRR1, + 0, 0); + + omap_set_dma_dest_params(mcbsp->dma_rx_lch, + dest_port, + OMAP_DMA_AMODE_POST_INC, + buffer, + 0, 0); + + omap_start_dma(mcbsp->dma_rx_lch); + wait_for_completion(&mcbsp->rx_dma_completion); + + return 0; } +EXPORT_SYMBOL(omap_mcbsp_recv_buffer); -void omap2_mcbsp1_mux_fsr_src(u8 mux) +/* + * SPI wrapper. + * Since SPI setup is much simpler than the generic McBSP one, + * this wrapper just need an omap_mcbsp_spi_cfg structure as an input. + * Once this is done, you can call omap_mcbsp_start(). + */ +void omap_mcbsp_set_spi_mode(unsigned int id, + const struct omap_mcbsp_spi_cfg *spi_cfg) { - WARN(1, "%s: should never be called on an OMAP1-only kernel\n", - __func__); - return; + struct omap_mcbsp *mcbsp; + struct omap_mcbsp_reg_cfg mcbsp_cfg; + + if (!omap_mcbsp_check_valid_id(id)) { + printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); + return; + } + mcbsp = id_to_mcbsp_ptr(id); + + memset(&mcbsp_cfg, 0, sizeof(struct omap_mcbsp_reg_cfg)); + + /* SPI has only one frame */ + mcbsp_cfg.rcr1 |= (RWDLEN1(spi_cfg->word_length) | RFRLEN1(0)); + mcbsp_cfg.xcr1 |= (XWDLEN1(spi_cfg->word_length) | XFRLEN1(0)); + + /* Clock stop mode */ + if (spi_cfg->clk_stp_mode == OMAP_MCBSP_CLK_STP_MODE_NO_DELAY) + mcbsp_cfg.spcr1 |= (1 << 12); + else + mcbsp_cfg.spcr1 |= (3 << 11); + + /* Set clock parities */ + if (spi_cfg->rx_clock_polarity == OMAP_MCBSP_CLK_RISING) + mcbsp_cfg.pcr0 |= CLKRP; + else + mcbsp_cfg.pcr0 &= ~CLKRP; + + if (spi_cfg->tx_clock_polarity == OMAP_MCBSP_CLK_RISING) + mcbsp_cfg.pcr0 &= ~CLKXP; + else + mcbsp_cfg.pcr0 |= CLKXP; + + /* Set SCLKME to 0 and CLKSM to 1 */ + mcbsp_cfg.pcr0 &= ~SCLKME; + mcbsp_cfg.srgr2 |= CLKSM; + + /* Set FSXP */ + if (spi_cfg->fsx_polarity == OMAP_MCBSP_FS_ACTIVE_HIGH) + mcbsp_cfg.pcr0 &= ~FSXP; + else + mcbsp_cfg.pcr0 |= FSXP; + + if (spi_cfg->spi_mode == OMAP_MCBSP_SPI_MASTER) { + mcbsp_cfg.pcr0 |= CLKXM; + mcbsp_cfg.srgr1 |= CLKGDV(spi_cfg->clk_div - 1); + mcbsp_cfg.pcr0 |= FSXM; + mcbsp_cfg.srgr2 &= ~FSGM; + mcbsp_cfg.xcr2 |= XDATDLY(1); + mcbsp_cfg.rcr2 |= RDATDLY(1); + } else { + mcbsp_cfg.pcr0 &= ~CLKXM; + mcbsp_cfg.srgr1 |= CLKGDV(1); + mcbsp_cfg.pcr0 &= ~FSXM; + mcbsp_cfg.xcr2 &= ~XDATDLY(3); + mcbsp_cfg.rcr2 &= ~RDATDLY(3); + } + + mcbsp_cfg.xcr2 &= ~XPHASE; + mcbsp_cfg.rcr2 &= ~RPHASE; + + omap_mcbsp_config(id, &mcbsp_cfg); } -#endif +EXPORT_SYMBOL(omap_mcbsp_set_spi_mode); #ifdef CONFIG_ARCH_OMAP3 #define max_thres(m) (mcbsp->pdata->buffer_size) @@ -1304,6 +1833,8 @@ static int __devinit omap_mcbsp_probe(struct platform_device *pdev) spin_lock_init(&mcbsp->lock); mcbsp->id = id + 1; mcbsp->free = true; + mcbsp->dma_tx_lch = -1; + mcbsp->dma_rx_lch = -1; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); if (!res) { @@ -1329,6 +1860,9 @@ static int __devinit omap_mcbsp_probe(struct platform_device *pdev) else mcbsp->phys_dma_base = res->start; + /* Default I/O is IRQ based */ + mcbsp->io_type = OMAP_MCBSP_IRQ_IO; + mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx"); mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx"); diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c index be45147651c..49fc0df0c21 100644 --- a/arch/arm/plat-omap/omap_device.c +++ b/arch/arm/plat-omap/omap_device.c @@ -236,71 +236,61 @@ static int _omap_device_deactivate(struct omap_device *od, u8 ignore_lat) return 0; } -static void _add_clkdev(struct omap_device *od, const char *clk_alias, - const char *clk_name) +static inline struct omap_device *_find_by_pdev(struct platform_device *pdev) { - struct clk *r; - struct clk_lookup *l; - - if (!clk_alias || !clk_name) - return; - - pr_debug("omap_device: %s: Creating %s -> %s\n", - dev_name(&od->pdev.dev), clk_alias, clk_name); - - r = clk_get_sys(dev_name(&od->pdev.dev), clk_alias); - if (!IS_ERR(r)) { - pr_warning("omap_device: %s: alias %s already exists\n", - dev_name(&od->pdev.dev), clk_alias); - clk_put(r); - return; - } - - r = omap_clk_get_by_name(clk_name); - if (IS_ERR(r)) { - pr_err("omap_device: %s: omap_clk_get_by_name for %s failed\n", - dev_name(&od->pdev.dev), clk_name); - return; - } - - l = clkdev_alloc(r, clk_alias, dev_name(&od->pdev.dev)); - if (!l) { - pr_err("omap_device: %s: clkdev_alloc for %s failed\n", - dev_name(&od->pdev.dev), clk_alias); - return; - } - - clkdev_add(l); + return container_of(pdev, struct omap_device, pdev); } /** - * _add_hwmod_clocks_clkdev - Add clkdev entry for hwmod optional clocks - * and main clock + * _add_optional_clock_clkdev - Add clkdev entry for hwmod optional clocks * @od: struct omap_device *od - * @oh: struct omap_hwmod *oh * - * For the main clock and every optional clock present per hwmod per - * omap_device, this function adds an entry in the clkdev table of the - * form <dev-id=dev_name, con-id=role> if it does not exist already. + * For every optional clock present per hwmod per omap_device, this function + * adds an entry in the clkdev table of the form <dev-id=dev_name, con-id=role> + * if it does not exist already. * * The function is called from inside omap_device_build_ss(), after * omap_device_register. * * This allows drivers to get a pointer to its optional clocks based on its role * by calling clk_get(<dev*>, <role>). - * In the case of the main clock, a "fck" alias is used. * * No return value. */ -static void _add_hwmod_clocks_clkdev(struct omap_device *od, - struct omap_hwmod *oh) +static void _add_optional_clock_clkdev(struct omap_device *od, + struct omap_hwmod *oh) { int i; - _add_clkdev(od, "fck", oh->main_clk); + for (i = 0; i < oh->opt_clks_cnt; i++) { + struct omap_hwmod_opt_clk *oc; + struct clk *r; + struct clk_lookup *l; + + oc = &oh->opt_clks[i]; + + if (!oc->_clk) + continue; + + r = clk_get_sys(dev_name(&od->pdev.dev), oc->role); + if (!IS_ERR(r)) + continue; /* clkdev entry exists */ - for (i = 0; i < oh->opt_clks_cnt; i++) - _add_clkdev(od, oh->opt_clks[i].role, oh->opt_clks[i].clk); + r = omap_clk_get_by_name((char *)oc->clk); + if (IS_ERR(r)) { + pr_err("omap_device: %s: omap_clk_get_by_name for %s failed\n", + dev_name(&od->pdev.dev), oc->clk); + continue; + } + + l = clkdev_alloc(r, oc->role, dev_name(&od->pdev.dev)); + if (!l) { + pr_err("omap_device: %s: clkdev_alloc for %s failed\n", + dev_name(&od->pdev.dev), oc->role); + return; + } + clkdev_add(l); + } } @@ -326,7 +316,7 @@ u32 omap_device_get_context_loss_count(struct platform_device *pdev) struct omap_device *od; u32 ret = 0; - od = to_omap_device(pdev); + od = _find_by_pdev(pdev); if (od->hwmods_cnt) ret = omap_hwmod_get_context_loss_count(od->hwmods[0]); @@ -507,7 +497,7 @@ struct omap_device *omap_device_build_ss(const char *pdev_name, int pdev_id, for (i = 0; i < oh_cnt; i++) { hwmods[i]->od = od; - _add_hwmod_clocks_clkdev(od, hwmods[i]); + _add_optional_clock_clkdev(od, hwmods[i]); } if (ret) @@ -621,7 +611,7 @@ int omap_device_enable(struct platform_device *pdev) int ret; struct omap_device *od; - od = to_omap_device(pdev); + od = _find_by_pdev(pdev); if (od->_state == OMAP_DEVICE_STATE_ENABLED) { WARN(1, "omap_device: %s.%d: %s() called from invalid state %d\n", @@ -660,7 +650,7 @@ int omap_device_idle(struct platform_device *pdev) int ret; struct omap_device *od; - od = to_omap_device(pdev); + od = _find_by_pdev(pdev); if (od->_state != OMAP_DEVICE_STATE_ENABLED) { WARN(1, "omap_device: %s.%d: %s() called from invalid state %d\n", @@ -691,7 +681,7 @@ int omap_device_shutdown(struct platform_device *pdev) int ret, i; struct omap_device *od; - od = to_omap_device(pdev); + od = _find_by_pdev(pdev); if (od->_state != OMAP_DEVICE_STATE_ENABLED && od->_state != OMAP_DEVICE_STATE_IDLE) { @@ -732,7 +722,7 @@ int omap_device_align_pm_lat(struct platform_device *pdev, int ret = -EINVAL; struct omap_device *od; - od = to_omap_device(pdev); + od = _find_by_pdev(pdev); if (new_wakeup_lat_limit == od->dev_wakeup_lat) return 0; |