diff options
Diffstat (limited to 'arch/arm/plat-omap/mcbsp.c')
-rw-r--r-- | arch/arm/plat-omap/mcbsp.c | 774 |
1 files changed, 594 insertions, 180 deletions
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c index f75767278fc3..e47686e0a633 100644 --- a/arch/arm/plat-omap/mcbsp.c +++ b/arch/arm/plat-omap/mcbsp.c @@ -27,64 +27,97 @@ #include <plat/dma.h> #include <plat/mcbsp.h> +#include "../mach-omap2/cm-regbits-34xx.h" + struct omap_mcbsp **mcbsp_ptr; -int omap_mcbsp_count; +int omap_mcbsp_count, omap_mcbsp_cache_size; -void omap_mcbsp_write(void __iomem *io_base, u16 reg, u32 val) +void omap_mcbsp_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val) { - if (cpu_class_is_omap1() || cpu_is_omap2420()) - __raw_writew((u16)val, io_base + reg); - else - __raw_writel(val, io_base + reg); + if (cpu_class_is_omap1()) { + ((u16 *)mcbsp->reg_cache)[reg / sizeof(u16)] = (u16)val; + __raw_writew((u16)val, mcbsp->io_base + reg); + } else if (cpu_is_omap2420()) { + ((u16 *)mcbsp->reg_cache)[reg / sizeof(u32)] = (u16)val; + __raw_writew((u16)val, mcbsp->io_base + reg); + } else { + ((u32 *)mcbsp->reg_cache)[reg / sizeof(u32)] = val; + __raw_writel(val, mcbsp->io_base + reg); + } } -int omap_mcbsp_read(void __iomem *io_base, u16 reg) +int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, bool from_cache) { - if (cpu_class_is_omap1() || cpu_is_omap2420()) - return __raw_readw(io_base + reg); - else - return __raw_readl(io_base + reg); + if (cpu_class_is_omap1()) { + return !from_cache ? __raw_readw(mcbsp->io_base + reg) : + ((u16 *)mcbsp->reg_cache)[reg / sizeof(u16)]; + } else if (cpu_is_omap2420()) { + return !from_cache ? __raw_readw(mcbsp->io_base + reg) : + ((u16 *)mcbsp->reg_cache)[reg / sizeof(u32)]; + } else { + return !from_cache ? __raw_readl(mcbsp->io_base + reg) : + ((u32 *)mcbsp->reg_cache)[reg / sizeof(u32)]; + } +} + +#ifdef CONFIG_ARCH_OMAP3 +void omap_mcbsp_st_write(struct omap_mcbsp *mcbsp, u16 reg, u32 val) +{ + __raw_writel(val, mcbsp->st_data->io_base_st + reg); +} + +int omap_mcbsp_st_read(struct omap_mcbsp *mcbsp, u16 reg) +{ + return __raw_readl(mcbsp->st_data->io_base_st + reg); } +#endif -#define OMAP_MCBSP_READ(base, reg) \ - omap_mcbsp_read(base, OMAP_MCBSP_REG_##reg) -#define OMAP_MCBSP_WRITE(base, reg, val) \ - omap_mcbsp_write(base, OMAP_MCBSP_REG_##reg, val) +#define MCBSP_READ(mcbsp, reg) \ + omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0) +#define MCBSP_WRITE(mcbsp, reg, val) \ + omap_mcbsp_write(mcbsp, OMAP_MCBSP_REG_##reg, val) +#define MCBSP_READ_CACHE(mcbsp, reg) \ + omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 1) #define omap_mcbsp_check_valid_id(id) (id < omap_mcbsp_count) #define id_to_mcbsp_ptr(id) mcbsp_ptr[id]; +#define MCBSP_ST_READ(mcbsp, reg) \ + omap_mcbsp_st_read(mcbsp, OMAP_ST_REG_##reg) +#define MCBSP_ST_WRITE(mcbsp, reg, val) \ + omap_mcbsp_st_write(mcbsp, OMAP_ST_REG_##reg, val) + static void omap_mcbsp_dump_reg(u8 id) { struct omap_mcbsp *mcbsp = id_to_mcbsp_ptr(id); dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n", mcbsp->id); dev_dbg(mcbsp->dev, "DRR2: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, DRR2)); + MCBSP_READ(mcbsp, DRR2)); dev_dbg(mcbsp->dev, "DRR1: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, DRR1)); + MCBSP_READ(mcbsp, DRR1)); dev_dbg(mcbsp->dev, "DXR2: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, DXR2)); + MCBSP_READ(mcbsp, DXR2)); dev_dbg(mcbsp->dev, "DXR1: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, DXR1)); + MCBSP_READ(mcbsp, DXR1)); dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, SPCR2)); + MCBSP_READ(mcbsp, SPCR2)); dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, SPCR1)); + MCBSP_READ(mcbsp, SPCR1)); dev_dbg(mcbsp->dev, "RCR2: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, RCR2)); + MCBSP_READ(mcbsp, RCR2)); dev_dbg(mcbsp->dev, "RCR1: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, RCR1)); + MCBSP_READ(mcbsp, RCR1)); dev_dbg(mcbsp->dev, "XCR2: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, XCR2)); + MCBSP_READ(mcbsp, XCR2)); dev_dbg(mcbsp->dev, "XCR1: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, XCR1)); + MCBSP_READ(mcbsp, XCR1)); dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, SRGR2)); + MCBSP_READ(mcbsp, SRGR2)); dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, SRGR1)); + MCBSP_READ(mcbsp, SRGR1)); dev_dbg(mcbsp->dev, "PCR0: 0x%04x\n", - OMAP_MCBSP_READ(mcbsp->io_base, PCR0)); + MCBSP_READ(mcbsp, PCR0)); dev_dbg(mcbsp->dev, "***********************\n"); } @@ -93,15 +126,15 @@ static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id) struct omap_mcbsp *mcbsp_tx = dev_id; u16 irqst_spcr2; - irqst_spcr2 = OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2); + irqst_spcr2 = MCBSP_READ(mcbsp_tx, SPCR2); dev_dbg(mcbsp_tx->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2); if (irqst_spcr2 & XSYNC_ERR) { dev_err(mcbsp_tx->dev, "TX Frame Sync Error! : 0x%x\n", irqst_spcr2); /* Writing zero to XSYNC_ERR clears the IRQ */ - OMAP_MCBSP_WRITE(mcbsp_tx->io_base, SPCR2, - irqst_spcr2 & ~(XSYNC_ERR)); + MCBSP_WRITE(mcbsp_tx, SPCR2, + MCBSP_READ_CACHE(mcbsp_tx, SPCR2) & ~(XSYNC_ERR)); } else { complete(&mcbsp_tx->tx_irq_completion); } @@ -114,15 +147,15 @@ static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id) struct omap_mcbsp *mcbsp_rx = dev_id; u16 irqst_spcr1; - irqst_spcr1 = OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR1); + irqst_spcr1 = MCBSP_READ(mcbsp_rx, SPCR1); dev_dbg(mcbsp_rx->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1); if (irqst_spcr1 & RSYNC_ERR) { dev_err(mcbsp_rx->dev, "RX Frame Sync Error! : 0x%x\n", irqst_spcr1); /* Writing zero to RSYNC_ERR clears the IRQ */ - OMAP_MCBSP_WRITE(mcbsp_rx->io_base, SPCR1, - irqst_spcr1 & ~(RSYNC_ERR)); + MCBSP_WRITE(mcbsp_rx, SPCR1, + MCBSP_READ_CACHE(mcbsp_rx, SPCR1) & ~(RSYNC_ERR)); } else { complete(&mcbsp_rx->tx_irq_completion); } @@ -135,7 +168,7 @@ 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", - OMAP_MCBSP_READ(mcbsp_dma_tx->io_base, SPCR2)); + MCBSP_READ(mcbsp_dma_tx, SPCR2)); /* We can free the channels */ omap_free_dma(mcbsp_dma_tx->dma_tx_lch); @@ -149,7 +182,7 @@ 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", - OMAP_MCBSP_READ(mcbsp_dma_rx->io_base, SPCR2)); + MCBSP_READ(mcbsp_dma_rx, SPCR2)); /* We can free the channels */ omap_free_dma(mcbsp_dma_rx->dma_rx_lch); @@ -167,7 +200,6 @@ static void omap_mcbsp_rx_dma_callback(int lch, u16 ch_status, void *data) void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg *config) { struct omap_mcbsp *mcbsp; - void __iomem *io_base; if (!omap_mcbsp_check_valid_id(id)) { printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); @@ -175,30 +207,280 @@ void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg *config) } mcbsp = id_to_mcbsp_ptr(id); - io_base = mcbsp->io_base; dev_dbg(mcbsp->dev, "Configuring McBSP%d phys_base: 0x%08lx\n", mcbsp->id, mcbsp->phys_base); /* We write the given config */ - OMAP_MCBSP_WRITE(io_base, SPCR2, config->spcr2); - OMAP_MCBSP_WRITE(io_base, SPCR1, config->spcr1); - OMAP_MCBSP_WRITE(io_base, RCR2, config->rcr2); - OMAP_MCBSP_WRITE(io_base, RCR1, config->rcr1); - OMAP_MCBSP_WRITE(io_base, XCR2, config->xcr2); - OMAP_MCBSP_WRITE(io_base, XCR1, config->xcr1); - OMAP_MCBSP_WRITE(io_base, SRGR2, config->srgr2); - OMAP_MCBSP_WRITE(io_base, SRGR1, config->srgr1); - OMAP_MCBSP_WRITE(io_base, MCR2, config->mcr2); - OMAP_MCBSP_WRITE(io_base, MCR1, config->mcr1); - OMAP_MCBSP_WRITE(io_base, PCR0, config->pcr0); + MCBSP_WRITE(mcbsp, SPCR2, config->spcr2); + MCBSP_WRITE(mcbsp, SPCR1, config->spcr1); + MCBSP_WRITE(mcbsp, RCR2, config->rcr2); + MCBSP_WRITE(mcbsp, RCR1, config->rcr1); + MCBSP_WRITE(mcbsp, XCR2, config->xcr2); + MCBSP_WRITE(mcbsp, XCR1, config->xcr1); + MCBSP_WRITE(mcbsp, SRGR2, config->srgr2); + MCBSP_WRITE(mcbsp, SRGR1, config->srgr1); + MCBSP_WRITE(mcbsp, MCR2, config->mcr2); + MCBSP_WRITE(mcbsp, MCR1, config->mcr1); + MCBSP_WRITE(mcbsp, PCR0, config->pcr0); if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap44xx()) { - OMAP_MCBSP_WRITE(io_base, XCCR, config->xccr); - OMAP_MCBSP_WRITE(io_base, RCCR, config->rccr); + MCBSP_WRITE(mcbsp, XCCR, config->xccr); + MCBSP_WRITE(mcbsp, RCCR, config->rccr); } } EXPORT_SYMBOL(omap_mcbsp_config); -#ifdef CONFIG_ARCH_OMAP34XX +#ifdef CONFIG_ARCH_OMAP3 +static void omap_st_on(struct omap_mcbsp *mcbsp) +{ + unsigned int w; + + /* + * Sidetone uses McBSP ICLK - which must not idle when sidetones + * are enabled or sidetones start sounding ugly. + */ + w = cm_read_mod_reg(OMAP3430_PER_MOD, CM_AUTOIDLE); + w &= ~(1 << (mcbsp->id - 2)); + cm_write_mod_reg(w, OMAP3430_PER_MOD, CM_AUTOIDLE); + + /* Enable McBSP Sidetone */ + w = MCBSP_READ(mcbsp, SSELCR); + MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN); + + w = MCBSP_ST_READ(mcbsp, SYSCONFIG); + MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE)); + + /* Enable Sidetone from Sidetone Core */ + w = MCBSP_ST_READ(mcbsp, SSELCR); + MCBSP_ST_WRITE(mcbsp, SSELCR, w | ST_SIDETONEEN); +} + +static void omap_st_off(struct omap_mcbsp *mcbsp) +{ + unsigned int w; + + w = MCBSP_ST_READ(mcbsp, SSELCR); + MCBSP_ST_WRITE(mcbsp, SSELCR, w & ~(ST_SIDETONEEN)); + + w = MCBSP_ST_READ(mcbsp, SYSCONFIG); + MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w | ST_AUTOIDLE); + + w = MCBSP_READ(mcbsp, SSELCR); + MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN)); + + w = cm_read_mod_reg(OMAP3430_PER_MOD, CM_AUTOIDLE); + w |= 1 << (mcbsp->id - 2); + cm_write_mod_reg(w, OMAP3430_PER_MOD, CM_AUTOIDLE); +} + +static void omap_st_fir_write(struct omap_mcbsp *mcbsp, s16 *fir) +{ + u16 val, i; + + val = MCBSP_ST_READ(mcbsp, SYSCONFIG); + MCBSP_ST_WRITE(mcbsp, SYSCONFIG, val & ~(ST_AUTOIDLE)); + + val = MCBSP_ST_READ(mcbsp, SSELCR); + + if (val & ST_COEFFWREN) + MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN)); + + MCBSP_ST_WRITE(mcbsp, SSELCR, val | ST_COEFFWREN); + + for (i = 0; i < 128; i++) + MCBSP_ST_WRITE(mcbsp, SFIRCR, fir[i]); + + i = 0; + + val = MCBSP_ST_READ(mcbsp, SSELCR); + while (!(val & ST_COEFFWRDONE) && (++i < 1000)) + val = MCBSP_ST_READ(mcbsp, SSELCR); + + MCBSP_ST_WRITE(mcbsp, SSELCR, val & ~(ST_COEFFWREN)); + + if (i == 1000) + dev_err(mcbsp->dev, "McBSP FIR load error!\n"); +} + +static void omap_st_chgain(struct omap_mcbsp *mcbsp) +{ + u16 w; + struct omap_mcbsp_st_data *st_data = mcbsp->st_data; + + w = MCBSP_ST_READ(mcbsp, SYSCONFIG); + MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE)); + + w = MCBSP_ST_READ(mcbsp, SSELCR); + + MCBSP_ST_WRITE(mcbsp, SGAINCR, ST_CH0GAIN(st_data->ch0gain) | \ + ST_CH1GAIN(st_data->ch1gain)); +} + +int omap_st_set_chgain(unsigned int id, int channel, s16 chgain) +{ + struct omap_mcbsp *mcbsp; + struct omap_mcbsp_st_data *st_data; + int ret = 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); + st_data = mcbsp->st_data; + + if (!st_data) + return -ENOENT; + + spin_lock_irq(&mcbsp->lock); + if (channel == 0) + st_data->ch0gain = chgain; + else if (channel == 1) + st_data->ch1gain = chgain; + else + ret = -EINVAL; + + if (st_data->enabled) + omap_st_chgain(mcbsp); + spin_unlock_irq(&mcbsp->lock); + + return ret; +} +EXPORT_SYMBOL(omap_st_set_chgain); + +int omap_st_get_chgain(unsigned int id, int channel, s16 *chgain) +{ + struct omap_mcbsp *mcbsp; + struct omap_mcbsp_st_data *st_data; + int ret = 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); + st_data = mcbsp->st_data; + + if (!st_data) + return -ENOENT; + + spin_lock_irq(&mcbsp->lock); + if (channel == 0) + *chgain = st_data->ch0gain; + else if (channel == 1) + *chgain = st_data->ch1gain; + else + ret = -EINVAL; + spin_unlock_irq(&mcbsp->lock); + + return ret; +} +EXPORT_SYMBOL(omap_st_get_chgain); + +static int omap_st_start(struct omap_mcbsp *mcbsp) +{ + struct omap_mcbsp_st_data *st_data = mcbsp->st_data; + + if (st_data && st_data->enabled && !st_data->running) { + omap_st_fir_write(mcbsp, st_data->taps); + omap_st_chgain(mcbsp); + + if (!mcbsp->free) { + omap_st_on(mcbsp); + st_data->running = 1; + } + } + + return 0; +} + +int omap_st_enable(unsigned int id) +{ + struct omap_mcbsp *mcbsp; + struct omap_mcbsp_st_data *st_data; + + 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); + st_data = mcbsp->st_data; + + if (!st_data) + return -ENODEV; + + spin_lock_irq(&mcbsp->lock); + st_data->enabled = 1; + omap_st_start(mcbsp); + spin_unlock_irq(&mcbsp->lock); + + return 0; +} +EXPORT_SYMBOL(omap_st_enable); + +static int omap_st_stop(struct omap_mcbsp *mcbsp) +{ + struct omap_mcbsp_st_data *st_data = mcbsp->st_data; + + if (st_data && st_data->running) { + if (!mcbsp->free) { + omap_st_off(mcbsp); + st_data->running = 0; + } + } + + return 0; +} + +int omap_st_disable(unsigned int id) +{ + struct omap_mcbsp *mcbsp; + struct omap_mcbsp_st_data *st_data; + int ret = 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); + st_data = mcbsp->st_data; + + if (!st_data) + return -ENODEV; + + spin_lock_irq(&mcbsp->lock); + omap_st_stop(mcbsp); + st_data->enabled = 0; + spin_unlock_irq(&mcbsp->lock); + + return ret; +} +EXPORT_SYMBOL(omap_st_disable); + +int omap_st_is_enabled(unsigned int id) +{ + struct omap_mcbsp *mcbsp; + struct omap_mcbsp_st_data *st_data; + + 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); + st_data = mcbsp->st_data; + + if (!st_data) + return -ENODEV; + + + return st_data->enabled; +} +EXPORT_SYMBOL(omap_st_is_enabled); + /* * omap_mcbsp_set_tx_threshold configures how to deal * with transmit threshold. the threshold value and handler can be @@ -207,7 +489,6 @@ EXPORT_SYMBOL(omap_mcbsp_config); void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold) { struct omap_mcbsp *mcbsp; - void __iomem *io_base; if (!cpu_is_omap34xx()) return; @@ -217,9 +498,8 @@ void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold) return; } mcbsp = id_to_mcbsp_ptr(id); - io_base = mcbsp->io_base; - OMAP_MCBSP_WRITE(io_base, THRSH2, threshold); + MCBSP_WRITE(mcbsp, THRSH2, threshold); } EXPORT_SYMBOL(omap_mcbsp_set_tx_threshold); @@ -231,7 +511,6 @@ EXPORT_SYMBOL(omap_mcbsp_set_tx_threshold); void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold) { struct omap_mcbsp *mcbsp; - void __iomem *io_base; if (!cpu_is_omap34xx()) return; @@ -241,9 +520,8 @@ void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold) return; } mcbsp = id_to_mcbsp_ptr(id); - io_base = mcbsp->io_base; - OMAP_MCBSP_WRITE(io_base, THRSH1, threshold); + MCBSP_WRITE(mcbsp, THRSH1, threshold); } EXPORT_SYMBOL(omap_mcbsp_set_rx_threshold); @@ -313,19 +591,18 @@ static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp) if (cpu_is_omap34xx()) { u16 syscon; - syscon = OMAP_MCBSP_READ(mcbsp->io_base, SYSCON); + syscon = MCBSP_READ(mcbsp, SYSCON); syscon &= ~(ENAWAKEUP | SIDLEMODE(0x03) | CLOCKACTIVITY(0x03)); if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) { syscon |= (ENAWAKEUP | SIDLEMODE(0x02) | CLOCKACTIVITY(0x02)); - OMAP_MCBSP_WRITE(mcbsp->io_base, WAKEUPEN, - XRDYEN | RRDYEN); + MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN); } else { syscon |= SIDLEMODE(0x01); } - OMAP_MCBSP_WRITE(mcbsp->io_base, SYSCON, syscon); + MCBSP_WRITE(mcbsp, SYSCON, syscon); } } @@ -337,7 +614,7 @@ static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp) if (cpu_is_omap34xx()) { u16 syscon; - syscon = OMAP_MCBSP_READ(mcbsp->io_base, SYSCON); + syscon = MCBSP_READ(mcbsp, SYSCON); syscon &= ~(ENAWAKEUP | SIDLEMODE(0x03) | CLOCKACTIVITY(0x03)); /* * HW bug workaround - If no_idle mode is taken, we need to @@ -345,17 +622,19 @@ static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp) * device will not hit retention anymore. */ syscon |= SIDLEMODE(0x02); - OMAP_MCBSP_WRITE(mcbsp->io_base, SYSCON, syscon); + MCBSP_WRITE(mcbsp, SYSCON, syscon); syscon &= ~(SIDLEMODE(0x03)); - OMAP_MCBSP_WRITE(mcbsp->io_base, SYSCON, syscon); + MCBSP_WRITE(mcbsp, SYSCON, syscon); - OMAP_MCBSP_WRITE(mcbsp->io_base, WAKEUPEN, 0); + MCBSP_WRITE(mcbsp, WAKEUPEN, 0); } } #else static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp) {} static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp) {} +static inline void omap_st_start(struct omap_mcbsp *mcbsp) {} +static inline void omap_st_stop(struct omap_mcbsp *mcbsp) {} #endif /* @@ -392,6 +671,7 @@ EXPORT_SYMBOL(omap_mcbsp_set_io_type); int omap_mcbsp_request(unsigned int id) { struct omap_mcbsp *mcbsp; + void *reg_cache; int err; if (!omap_mcbsp_check_valid_id(id)) { @@ -400,15 +680,21 @@ int omap_mcbsp_request(unsigned int id) } mcbsp = id_to_mcbsp_ptr(id); + reg_cache = kzalloc(omap_mcbsp_cache_size, GFP_KERNEL); + if (!reg_cache) { + return -ENOMEM; + } + 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 -EBUSY; + err = -EBUSY; + goto err_kfree; } mcbsp->free = 0; + mcbsp->reg_cache = reg_cache; spin_unlock(&mcbsp->lock); if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->request) @@ -424,8 +710,8 @@ int omap_mcbsp_request(unsigned int id) * Make sure that transmitter, receiver and sample-rate generator are * not running before activating IRQs. */ - OMAP_MCBSP_WRITE(mcbsp->io_base, SPCR1, 0); - OMAP_MCBSP_WRITE(mcbsp->io_base, SPCR2, 0); + MCBSP_WRITE(mcbsp, SPCR1, 0); + MCBSP_WRITE(mcbsp, SPCR2, 0); if (mcbsp->io_type == OMAP_MCBSP_IRQ_IO) { /* We need to get IRQs here */ @@ -436,7 +722,7 @@ int omap_mcbsp_request(unsigned int id) dev_err(mcbsp->dev, "Unable to request TX IRQ %d " "for McBSP%d\n", mcbsp->tx_irq, mcbsp->id); - goto error; + goto err_clk_disable; } init_completion(&mcbsp->rx_irq_completion); @@ -446,16 +732,16 @@ int omap_mcbsp_request(unsigned int id) dev_err(mcbsp->dev, "Unable to request RX IRQ %d " "for McBSP%d\n", mcbsp->rx_irq, mcbsp->id); - goto tx_irq; + goto err_free_irq; } } return 0; -tx_irq: +err_free_irq: free_irq(mcbsp->tx_irq, (void *)mcbsp); -error: +err_clk_disable: if (mcbsp->pdata && mcbsp->pdata->ops && mcbsp->pdata->ops->free) - mcbsp->pdata->ops->free(id); + mcbsp->pdata->ops->free(id); /* Do procedure specific to omap34xx arch, if applicable */ omap34xx_mcbsp_free(mcbsp); @@ -463,7 +749,12 @@ error: clk_disable(mcbsp->fclk); clk_disable(mcbsp->iclk); + spin_lock(&mcbsp->lock); mcbsp->free = 1; + mcbsp->reg_cache = NULL; +err_kfree: + spin_unlock(&mcbsp->lock); + kfree(reg_cache); return err; } @@ -472,6 +763,7 @@ EXPORT_SYMBOL(omap_mcbsp_request); void omap_mcbsp_free(unsigned int id) { struct omap_mcbsp *mcbsp; + void *reg_cache; if (!omap_mcbsp_check_valid_id(id)) { printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); @@ -494,16 +786,18 @@ void omap_mcbsp_free(unsigned int id) free_irq(mcbsp->tx_irq, (void *)mcbsp); } - spin_lock(&mcbsp->lock); - if (mcbsp->free) { - dev_err(mcbsp->dev, "McBSP%d was not reserved\n", - mcbsp->id); - spin_unlock(&mcbsp->lock); - return; - } + reg_cache = mcbsp->reg_cache; - mcbsp->free = 1; + spin_lock(&mcbsp->lock); + if (mcbsp->free) + dev_err(mcbsp->dev, "McBSP%d was not reserved\n", mcbsp->id); + else + mcbsp->free = 1; + mcbsp->reg_cache = NULL; spin_unlock(&mcbsp->lock); + + if (reg_cache) + kfree(reg_cache); } EXPORT_SYMBOL(omap_mcbsp_free); @@ -515,7 +809,6 @@ EXPORT_SYMBOL(omap_mcbsp_free); void omap_mcbsp_start(unsigned int id, int tx, int rx) { struct omap_mcbsp *mcbsp; - void __iomem *io_base; int idle; u16 w; @@ -524,28 +817,30 @@ void omap_mcbsp_start(unsigned int id, int tx, int rx) return; } mcbsp = id_to_mcbsp_ptr(id); - io_base = mcbsp->io_base; - mcbsp->rx_word_length = (OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7; - mcbsp->tx_word_length = (OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7; + 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; - idle = !((OMAP_MCBSP_READ(io_base, SPCR2) | - OMAP_MCBSP_READ(io_base, SPCR1)) & 1); + idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) | + MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1); if (idle) { /* Start the sample generator */ - w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6)); + w = MCBSP_READ_CACHE(mcbsp, SPCR2); + MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6)); } /* Enable transmitter and receiver */ tx &= 1; - w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w | tx); + w = MCBSP_READ_CACHE(mcbsp, SPCR2); + MCBSP_WRITE(mcbsp, SPCR2, w | tx); rx &= 1; - w = OMAP_MCBSP_READ(io_base, SPCR1); - OMAP_MCBSP_WRITE(io_base, SPCR1, w | rx); + w = MCBSP_READ_CACHE(mcbsp, SPCR1); + MCBSP_WRITE(mcbsp, SPCR1, w | rx); /* * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec @@ -557,18 +852,18 @@ void omap_mcbsp_start(unsigned int id, int tx, int rx) if (idle) { /* Start frame sync */ - w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7)); + w = MCBSP_READ_CACHE(mcbsp, SPCR2); + MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7)); } if (cpu_is_omap2430() || cpu_is_omap34xx()) { /* Release the transmitter and receiver */ - w = OMAP_MCBSP_READ(io_base, XCCR); + w = MCBSP_READ_CACHE(mcbsp, XCCR); w &= ~(tx ? XDISABLE : 0); - OMAP_MCBSP_WRITE(io_base, XCCR, w); - w = OMAP_MCBSP_READ(io_base, RCCR); + MCBSP_WRITE(mcbsp, XCCR, w); + w = MCBSP_READ_CACHE(mcbsp, RCCR); w &= ~(rx ? RDISABLE : 0); - OMAP_MCBSP_WRITE(io_base, RCCR, w); + MCBSP_WRITE(mcbsp, RCCR, w); } /* Dump McBSP Regs */ @@ -579,7 +874,6 @@ EXPORT_SYMBOL(omap_mcbsp_start); void omap_mcbsp_stop(unsigned int id, int tx, int rx) { struct omap_mcbsp *mcbsp; - void __iomem *io_base; int idle; u16 w; @@ -589,36 +883,38 @@ void omap_mcbsp_stop(unsigned int id, int tx, int rx) } mcbsp = id_to_mcbsp_ptr(id); - io_base = mcbsp->io_base; /* Reset transmitter */ tx &= 1; if (cpu_is_omap2430() || cpu_is_omap34xx()) { - w = OMAP_MCBSP_READ(io_base, XCCR); + w = MCBSP_READ_CACHE(mcbsp, XCCR); w |= (tx ? XDISABLE : 0); - OMAP_MCBSP_WRITE(io_base, XCCR, w); + MCBSP_WRITE(mcbsp, XCCR, w); } - w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~tx); + w = MCBSP_READ_CACHE(mcbsp, SPCR2); + MCBSP_WRITE(mcbsp, SPCR2, w & ~tx); /* Reset receiver */ rx &= 1; if (cpu_is_omap2430() || cpu_is_omap34xx()) { - w = OMAP_MCBSP_READ(io_base, RCCR); + w = MCBSP_READ_CACHE(mcbsp, RCCR); w |= (rx ? RDISABLE : 0); - OMAP_MCBSP_WRITE(io_base, RCCR, w); + MCBSP_WRITE(mcbsp, RCCR, w); } - w = OMAP_MCBSP_READ(io_base, SPCR1); - OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~rx); + w = MCBSP_READ_CACHE(mcbsp, SPCR1); + MCBSP_WRITE(mcbsp, SPCR1, w & ~rx); - idle = !((OMAP_MCBSP_READ(io_base, SPCR2) | - OMAP_MCBSP_READ(io_base, SPCR1)) & 1); + idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) | + MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1); if (idle) { /* Reset the sample rate generator */ - w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6)); + w = MCBSP_READ_CACHE(mcbsp, SPCR2); + MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6)); } + + if (cpu_is_omap34xx()) + omap_st_stop(mcbsp); } EXPORT_SYMBOL(omap_mcbsp_stop); @@ -626,7 +922,6 @@ EXPORT_SYMBOL(omap_mcbsp_stop); int omap_mcbsp_pollwrite(unsigned int id, u16 buf) { struct omap_mcbsp *mcbsp; - void __iomem *base; if (!omap_mcbsp_check_valid_id(id)) { printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); @@ -634,28 +929,27 @@ int omap_mcbsp_pollwrite(unsigned int id, u16 buf) } mcbsp = id_to_mcbsp_ptr(id); - base = mcbsp->io_base; - writew(buf, base + OMAP_MCBSP_REG_DXR1); + MCBSP_WRITE(mcbsp, DXR1, buf); /* if frame sync error - clear the error */ - if (readw(base + OMAP_MCBSP_REG_SPCR2) & XSYNC_ERR) { + if (MCBSP_READ(mcbsp, SPCR2) & XSYNC_ERR) { /* clear error */ - writew(readw(base + OMAP_MCBSP_REG_SPCR2) & (~XSYNC_ERR), - base + OMAP_MCBSP_REG_SPCR2); + MCBSP_WRITE(mcbsp, SPCR2, + MCBSP_READ_CACHE(mcbsp, SPCR2) & (~XSYNC_ERR)); /* resend */ return -1; } else { /* wait for transmit confirmation */ int attemps = 0; - while (!(readw(base + OMAP_MCBSP_REG_SPCR2) & XRDY)) { + while (!(MCBSP_READ(mcbsp, SPCR2) & XRDY)) { if (attemps++ > 1000) { - writew(readw(base + OMAP_MCBSP_REG_SPCR2) & - (~XRST), - base + OMAP_MCBSP_REG_SPCR2); + MCBSP_WRITE(mcbsp, SPCR2, + MCBSP_READ_CACHE(mcbsp, SPCR2) & + (~XRST)); udelay(10); - writew(readw(base + OMAP_MCBSP_REG_SPCR2) | - (XRST), - base + OMAP_MCBSP_REG_SPCR2); + 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); @@ -671,7 +965,6 @@ EXPORT_SYMBOL(omap_mcbsp_pollwrite); int omap_mcbsp_pollread(unsigned int id, u16 *buf) { struct omap_mcbsp *mcbsp; - void __iomem *base; if (!omap_mcbsp_check_valid_id(id)) { printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1); @@ -679,26 +972,25 @@ int omap_mcbsp_pollread(unsigned int id, u16 *buf) } mcbsp = id_to_mcbsp_ptr(id); - base = mcbsp->io_base; /* if frame sync error - clear the error */ - if (readw(base + OMAP_MCBSP_REG_SPCR1) & RSYNC_ERR) { + if (MCBSP_READ(mcbsp, SPCR1) & RSYNC_ERR) { /* clear error */ - writew(readw(base + OMAP_MCBSP_REG_SPCR1) & (~RSYNC_ERR), - base + OMAP_MCBSP_REG_SPCR1); + MCBSP_WRITE(mcbsp, SPCR1, + MCBSP_READ_CACHE(mcbsp, SPCR1) & (~RSYNC_ERR)); /* resend */ return -1; } else { /* wait for recieve confirmation */ int attemps = 0; - while (!(readw(base + OMAP_MCBSP_REG_SPCR1) & RRDY)) { + while (!(MCBSP_READ(mcbsp, SPCR1) & RRDY)) { if (attemps++ > 1000) { - writew(readw(base + OMAP_MCBSP_REG_SPCR1) & - (~RRST), - base + OMAP_MCBSP_REG_SPCR1); + MCBSP_WRITE(mcbsp, SPCR1, + MCBSP_READ_CACHE(mcbsp, SPCR1) & + (~RRST)); udelay(10); - writew(readw(base + OMAP_MCBSP_REG_SPCR1) | - (RRST), - base + OMAP_MCBSP_REG_SPCR1); + 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); @@ -706,7 +998,7 @@ int omap_mcbsp_pollread(unsigned int id, u16 *buf) } } } - *buf = readw(base + OMAP_MCBSP_REG_DRR1); + *buf = MCBSP_READ(mcbsp, DRR1); return 0; } @@ -718,7 +1010,6 @@ EXPORT_SYMBOL(omap_mcbsp_pollread); void omap_mcbsp_xmit_word(unsigned int id, u32 word) { struct omap_mcbsp *mcbsp; - void __iomem *io_base; omap_mcbsp_word_length word_length; if (!omap_mcbsp_check_valid_id(id)) { @@ -727,21 +1018,19 @@ void omap_mcbsp_xmit_word(unsigned int id, u32 word) } mcbsp = id_to_mcbsp_ptr(id); - io_base = mcbsp->io_base; word_length = mcbsp->tx_word_length; wait_for_completion(&mcbsp->tx_irq_completion); if (word_length > OMAP_MCBSP_WORD_16) - OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16); - OMAP_MCBSP_WRITE(io_base, DXR1, word & 0xffff); + 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; - void __iomem *io_base; u16 word_lsb, word_msb = 0; omap_mcbsp_word_length word_length; @@ -752,13 +1041,12 @@ u32 omap_mcbsp_recv_word(unsigned int id) mcbsp = id_to_mcbsp_ptr(id); word_length = mcbsp->rx_word_length; - io_base = mcbsp->io_base; wait_for_completion(&mcbsp->rx_irq_completion); if (word_length > OMAP_MCBSP_WORD_16) - word_msb = OMAP_MCBSP_READ(io_base, DRR2); - word_lsb = OMAP_MCBSP_READ(io_base, DRR1); + word_msb = MCBSP_READ(mcbsp, DRR2); + word_lsb = MCBSP_READ(mcbsp, DRR1); return (word_lsb | (word_msb << 16)); } @@ -767,7 +1055,6 @@ EXPORT_SYMBOL(omap_mcbsp_recv_word); int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word) { struct omap_mcbsp *mcbsp; - void __iomem *io_base; omap_mcbsp_word_length tx_word_length; omap_mcbsp_word_length rx_word_length; u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0; @@ -777,7 +1064,6 @@ int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word) return -ENODEV; } mcbsp = id_to_mcbsp_ptr(id); - io_base = mcbsp->io_base; tx_word_length = mcbsp->tx_word_length; rx_word_length = mcbsp->rx_word_length; @@ -785,14 +1071,16 @@ int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word) return -EINVAL; /* First we wait for the transmitter to be ready */ - spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); + spcr2 = MCBSP_READ(mcbsp, SPCR2); while (!(spcr2 & XRDY)) { - spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); + spcr2 = MCBSP_READ(mcbsp, SPCR2); if (attempts++ > 1000) { /* We must reset the transmitter */ - OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 & (~XRST)); + MCBSP_WRITE(mcbsp, SPCR2, + MCBSP_READ_CACHE(mcbsp, SPCR2) & (~XRST)); udelay(10); - OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST); + MCBSP_WRITE(mcbsp, SPCR2, + MCBSP_READ_CACHE(mcbsp, SPCR2) | XRST); udelay(10); dev_err(mcbsp->dev, "McBSP%d transmitter not " "ready\n", mcbsp->id); @@ -802,18 +1090,20 @@ int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word) /* Now we can push the data */ if (tx_word_length > OMAP_MCBSP_WORD_16) - OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16); - OMAP_MCBSP_WRITE(io_base, DXR1, word & 0xffff); + MCBSP_WRITE(mcbsp, DXR2, word >> 16); + MCBSP_WRITE(mcbsp, DXR1, word & 0xffff); /* We wait for the receiver to be ready */ - spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); + spcr1 = MCBSP_READ(mcbsp, SPCR1); while (!(spcr1 & RRDY)) { - spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); + spcr1 = MCBSP_READ(mcbsp, SPCR1); if (attempts++ > 1000) { /* We must reset the receiver */ - OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 & (~RRST)); + MCBSP_WRITE(mcbsp, SPCR1, + MCBSP_READ_CACHE(mcbsp, SPCR1) & (~RRST)); udelay(10); - OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST); + MCBSP_WRITE(mcbsp, SPCR1, + MCBSP_READ_CACHE(mcbsp, SPCR1) | RRST); udelay(10); dev_err(mcbsp->dev, "McBSP%d receiver not " "ready\n", mcbsp->id); @@ -823,8 +1113,8 @@ int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word) /* Receiver is ready, let's read the dummy data */ if (rx_word_length > OMAP_MCBSP_WORD_16) - word_msb = OMAP_MCBSP_READ(io_base, DRR2); - word_lsb = OMAP_MCBSP_READ(io_base, DRR1); + word_msb = MCBSP_READ(mcbsp, DRR2); + word_lsb = MCBSP_READ(mcbsp, DRR1); return 0; } @@ -834,7 +1124,6 @@ int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 *word) { struct omap_mcbsp *mcbsp; u32 clock_word = 0; - void __iomem *io_base; omap_mcbsp_word_length tx_word_length; omap_mcbsp_word_length rx_word_length; u16 spcr2, spcr1, attempts = 0, word_lsb, word_msb = 0; @@ -845,7 +1134,6 @@ int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 *word) } mcbsp = id_to_mcbsp_ptr(id); - io_base = mcbsp->io_base; tx_word_length = mcbsp->tx_word_length; rx_word_length = mcbsp->rx_word_length; @@ -854,14 +1142,16 @@ int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 *word) return -EINVAL; /* First we wait for the transmitter to be ready */ - spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); + spcr2 = MCBSP_READ(mcbsp, SPCR2); while (!(spcr2 & XRDY)) { - spcr2 = OMAP_MCBSP_READ(io_base, SPCR2); + spcr2 = MCBSP_READ(mcbsp, SPCR2); if (attempts++ > 1000) { /* We must reset the transmitter */ - OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 & (~XRST)); + MCBSP_WRITE(mcbsp, SPCR2, + MCBSP_READ_CACHE(mcbsp, SPCR2) & (~XRST)); udelay(10); - OMAP_MCBSP_WRITE(io_base, SPCR2, spcr2 | XRST); + MCBSP_WRITE(mcbsp, SPCR2, + MCBSP_READ_CACHE(mcbsp, SPCR2) | XRST); udelay(10); dev_err(mcbsp->dev, "McBSP%d transmitter not " "ready\n", mcbsp->id); @@ -871,18 +1161,20 @@ int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 *word) /* We first need to enable the bus clock */ if (tx_word_length > OMAP_MCBSP_WORD_16) - OMAP_MCBSP_WRITE(io_base, DXR2, clock_word >> 16); - OMAP_MCBSP_WRITE(io_base, DXR1, clock_word & 0xffff); + MCBSP_WRITE(mcbsp, DXR2, clock_word >> 16); + MCBSP_WRITE(mcbsp, DXR1, clock_word & 0xffff); /* We wait for the receiver to be ready */ - spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); + spcr1 = MCBSP_READ(mcbsp, SPCR1); while (!(spcr1 & RRDY)) { - spcr1 = OMAP_MCBSP_READ(io_base, SPCR1); + spcr1 = MCBSP_READ(mcbsp, SPCR1); if (attempts++ > 1000) { /* We must reset the receiver */ - OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 & (~RRST)); + MCBSP_WRITE(mcbsp, SPCR1, + MCBSP_READ_CACHE(mcbsp, SPCR1) & (~RRST)); udelay(10); - OMAP_MCBSP_WRITE(io_base, SPCR1, spcr1 | RRST); + MCBSP_WRITE(mcbsp, SPCR1, + MCBSP_READ_CACHE(mcbsp, SPCR1) | RRST); udelay(10); dev_err(mcbsp->dev, "McBSP%d receiver not " "ready\n", mcbsp->id); @@ -892,8 +1184,8 @@ int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 *word) /* Receiver is ready, there is something for us */ if (rx_word_length > OMAP_MCBSP_WORD_16) - word_msb = OMAP_MCBSP_READ(io_base, DRR2); - word_lsb = OMAP_MCBSP_READ(io_base, DRR1); + word_msb = MCBSP_READ(mcbsp, DRR2); + word_lsb = MCBSP_READ(mcbsp, DRR1); word[0] = (word_lsb | (word_msb << 16)); @@ -1107,7 +1399,7 @@ void omap_mcbsp_set_spi_mode(unsigned int id, } EXPORT_SYMBOL(omap_mcbsp_set_spi_mode); -#ifdef CONFIG_ARCH_OMAP34XX +#ifdef CONFIG_ARCH_OMAP3 #define max_thres(m) (mcbsp->pdata->buffer_size) #define valid_threshold(m, val) ((val) <= max_thres(m)) #define THRESHOLD_PROP_BUILDER(prop) \ @@ -1198,6 +1490,64 @@ unlock: static DEVICE_ATTR(dma_op_mode, 0644, dma_op_mode_show, dma_op_mode_store); +static ssize_t st_taps_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); + struct omap_mcbsp_st_data *st_data = mcbsp->st_data; + ssize_t status = 0; + int i; + + spin_lock_irq(&mcbsp->lock); + for (i = 0; i < st_data->nr_taps; i++) + status += sprintf(&buf[status], (i ? ", %d" : "%d"), + st_data->taps[i]); + if (i) + status += sprintf(&buf[status], "\n"); + spin_unlock_irq(&mcbsp->lock); + + return status; +} + +static ssize_t st_taps_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); + struct omap_mcbsp_st_data *st_data = mcbsp->st_data; + int val, tmp, status, i = 0; + + spin_lock_irq(&mcbsp->lock); + memset(st_data->taps, 0, sizeof(st_data->taps)); + st_data->nr_taps = 0; + + do { + status = sscanf(buf, "%d%n", &val, &tmp); + if (status < 0 || status == 0) { + size = -EINVAL; + goto out; + } + if (val < -32768 || val > 32767) { + size = -EINVAL; + goto out; + } + st_data->taps[i++] = val; + buf += tmp; + if (*buf != ',') + break; + buf++; + } while (1); + + st_data->nr_taps = i; + +out: + spin_unlock_irq(&mcbsp->lock); + + return size; +} + +static DEVICE_ATTR(st_taps, 0644, st_taps_show, st_taps_store); + static const struct attribute *additional_attrs[] = { &dev_attr_max_tx_thres.attr, &dev_attr_max_rx_thres.attr, @@ -1219,6 +1569,60 @@ static inline void __devexit omap_additional_remove(struct device *dev) sysfs_remove_group(&dev->kobj, &additional_attr_group); } +static const struct attribute *sidetone_attrs[] = { + &dev_attr_st_taps.attr, + NULL, +}; + +static const struct attribute_group sidetone_attr_group = { + .attrs = (struct attribute **)sidetone_attrs, +}; + +int __devinit omap_st_add(struct omap_mcbsp *mcbsp) +{ + struct omap_mcbsp_platform_data *pdata = mcbsp->pdata; + struct omap_mcbsp_st_data *st_data; + int err; + + st_data = kzalloc(sizeof(*mcbsp->st_data), GFP_KERNEL); + if (!st_data) { + err = -ENOMEM; + goto err1; + } + + st_data->io_base_st = ioremap(pdata->phys_base_st, SZ_4K); + if (!st_data->io_base_st) { + err = -ENOMEM; + goto err2; + } + + err = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group); + if (err) + goto err3; + + mcbsp->st_data = st_data; + return 0; + +err3: + iounmap(st_data->io_base_st); +err2: + kfree(st_data); +err1: + return err; + +} + +static void __devexit omap_st_remove(struct omap_mcbsp *mcbsp) +{ + struct omap_mcbsp_st_data *st_data = mcbsp->st_data; + + if (st_data) { + sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group); + iounmap(st_data->io_base_st); + kfree(st_data); + } +} + static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) { mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT; @@ -1232,6 +1636,12 @@ static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) if (omap_additional_add(mcbsp->dev)) dev_warn(mcbsp->dev, "Unable to create additional controls\n"); + + if (mcbsp->id == 2 || mcbsp->id == 3) + if (omap_st_add(mcbsp)) + dev_warn(mcbsp->dev, + "Unable to create sidetone controls\n"); + } else { mcbsp->max_tx_thres = -EINVAL; mcbsp->max_rx_thres = -EINVAL; @@ -1240,13 +1650,17 @@ static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) static inline void __devexit omap34xx_device_exit(struct omap_mcbsp *mcbsp) { - if (cpu_is_omap34xx()) + if (cpu_is_omap34xx()) { omap_additional_remove(mcbsp->dev); + + if (mcbsp->id == 2 || mcbsp->id == 3) + omap_st_remove(mcbsp); + } } #else static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp) {} static inline void __devexit omap34xx_device_exit(struct omap_mcbsp *mcbsp) {} -#endif /* CONFIG_ARCH_OMAP34XX */ +#endif /* CONFIG_ARCH_OMAP3 */ /* * McBSP1 and McBSP3 are directly mapped on 1610 and 1510. |