* Ilkka Koskinen <[email protected]> [100217 06:41]:
> From: Eero Nurkkala <[email protected]>
> 
> Add sidetone feature to McBSP instances 2 and 3 on OMAP3 based devices.
> 
> Signed-off-by: Ilkka Koskinen <[email protected]>

This one looks good to me and can be merged via Alsa list along with
the other patch.

Acked-by: Tony Lindgren <[email protected]>


> ---
>  arch/arm/mach-omap2/mcbsp.c             |    2 +
>  arch/arm/plat-omap/include/plat/mcbsp.h |   63 +++++
>  arch/arm/plat-omap/mcbsp.c              |  396 
> ++++++++++++++++++++++++++++++-
>  3 files changed, 460 insertions(+), 1 deletions(-)
> 
> diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c
> index d601f94..be8fce3 100644
> --- a/arch/arm/mach-omap2/mcbsp.c
> +++ b/arch/arm/mach-omap2/mcbsp.c
> @@ -136,6 +136,7 @@ static struct omap_mcbsp_platform_data 
> omap34xx_mcbsp_pdata[] = {
>       },
>       {
>               .phys_base      = OMAP34XX_MCBSP2_BASE,
> +             .phys_base_st   = OMAP34XX_MCBSP2_ST_BASE,
>               .dma_rx_sync    = OMAP24XX_DMA_MCBSP2_RX,
>               .dma_tx_sync    = OMAP24XX_DMA_MCBSP2_TX,
>               .rx_irq         = INT_24XX_MCBSP2_IRQ_RX,
> @@ -145,6 +146,7 @@ static struct omap_mcbsp_platform_data 
> omap34xx_mcbsp_pdata[] = {
>       },
>       {
>               .phys_base      = OMAP34XX_MCBSP3_BASE,
> +             .phys_base_st   = OMAP34XX_MCBSP3_ST_BASE,
>               .dma_rx_sync    = OMAP24XX_DMA_MCBSP3_RX,
>               .dma_tx_sync    = OMAP24XX_DMA_MCBSP3_TX,
>               .rx_irq         = INT_24XX_MCBSP3_IRQ_RX,
> diff --git a/arch/arm/plat-omap/include/plat/mcbsp.h 
> b/arch/arm/plat-omap/include/plat/mcbsp.h
> index 4df957b..5db1653 100644
> --- a/arch/arm/plat-omap/include/plat/mcbsp.h
> +++ b/arch/arm/plat-omap/include/plat/mcbsp.h
> @@ -49,6 +49,9 @@
>  
>  #define OMAP34XX_MCBSP1_BASE 0x48074000
>  #define OMAP34XX_MCBSP2_BASE 0x49022000
> +#define OMAP34XX_MCBSP2_ST_BASE      0x49028000
> +#define OMAP34XX_MCBSP3_BASE 0x49024000
> +#define OMAP34XX_MCBSP3_ST_BASE      0x4902A000
>  #define OMAP34XX_MCBSP3_BASE 0x49024000
>  #define OMAP34XX_MCBSP4_BASE 0x49026000
>  #define OMAP34XX_MCBSP5_BASE 0x48096000
> @@ -146,6 +149,15 @@
>  #define OMAP_MCBSP_REG_WAKEUPEN      0xA8
>  #define OMAP_MCBSP_REG_XCCR  0xAC
>  #define OMAP_MCBSP_REG_RCCR  0xB0
> +#define OMAP_MCBSP_REG_SSELCR        0xBC
> +
> +#define OMAP_ST_REG_REV              0x00
> +#define OMAP_ST_REG_SYSCONFIG        0x10
> +#define OMAP_ST_REG_IRQSTATUS        0x18
> +#define OMAP_ST_REG_IRQENABLE        0x1C
> +#define OMAP_ST_REG_SGAINCR  0x24
> +#define OMAP_ST_REG_SFIRCR   0x28
> +#define OMAP_ST_REG_SSELCR   0x2C
>  
>  #define AUDIO_MCBSP_DATAWRITE        (OMAP24XX_MCBSP2_BASE + 
> OMAP_MCBSP_REG_DXR1)
>  #define AUDIO_MCBSP_DATAREAD (OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1)
> @@ -264,6 +276,24 @@
>  #define ENAWAKEUP            0x0004
>  #define SOFTRST                      0x0002
>  
> +/********************** McBSP SSELCR bit definitions ***********************/
> +#define SIDETONEEN           0x0400
> +
> +/********************** McBSP Sidetone SYSCONFIG bit definitions ***********/
> +#define ST_AUTOIDLE          0x0001
> +
> +/********************** McBSP Sidetone SGAINCR bit definitions *************/
> +#define ST_CH1GAIN(value)    ((value<<16))   /* Bits 16:31 */
> +#define ST_CH0GAIN(value)    (value)         /* Bits 0:15 */
> +
> +/********************** McBSP Sidetone SFIRCR bit definitions **************/
> +#define ST_FIRCOEFF(value)   (value)         /* Bits 0:15 */
> +
> +/********************** McBSP Sidetone SSELCR bit definitions **************/
> +#define ST_COEFFWRDONE               0x0004
> +#define ST_COEFFWREN         0x0002
> +#define ST_SIDETONEEN                0x0001
> +
>  /********************** McBSP DMA operating modes **************************/
>  #define MCBSP_DMA_MODE_ELEMENT               0
>  #define MCBSP_DMA_MODE_THRESHOLD     1
> @@ -374,10 +404,25 @@ struct omap_mcbsp_platform_data {
>       u16 rx_irq, tx_irq;
>       struct omap_mcbsp_ops *ops;
>  #ifdef CONFIG_ARCH_OMAP3
> +     /* Sidetone block for McBSP 2 and 3 */
> +     unsigned long phys_base_st;
>       u16 buffer_size;
>  #endif
>  };
>  
> +#define OMAP_MCBSP_ST_CHANNEL_0 (1 << 0)
> +#define OMAP_MCBSP_ST_CHANNEL_1 (1 << 1)
> +
> +struct omap_mcbsp_st_data {
> +     void __iomem *io_base_st;
> +     bool running;
> +     bool enabled;
> +     s16 taps[128];  /* Sidetone filter coefficients */
> +     int nr_taps;    /* Number of filter coefficients in use */
> +     s16 ch0gain;
> +     s16 ch1gain;
> +};
> +
>  struct omap_mcbsp {
>       struct device *dev;
>       unsigned long phys_base;
> @@ -410,6 +455,7 @@ struct omap_mcbsp {
>       struct clk *iclk;
>       struct clk *fclk;
>  #ifdef CONFIG_ARCH_OMAP3
> +     struct omap_mcbsp_st_data *st_data;
>       int dma_op_mode;
>       u16 max_tx_thres;
>       u16 max_rx_thres;
> @@ -459,4 +505,21 @@ 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);
>  
> +#ifdef CONFIG_ARCH_OMAP3
> +/* Sidetone specific API */
> +int omap_st_set_chgain(unsigned int id, s16 ch0gain, s16 ch1gain, int 
> channels);
> +int omap_st_get_chgain(unsigned int id, s16 *ch0gain, s16 *ch1gain);
> +int omap_st_enable(unsigned int id);
> +int omap_st_disable(unsigned int id);
> +int omap_st_is_enabled(unsigned int id);
> +#else
> +static inline int omap_st_set_chgain(unsigned int id, s16 ch0gain,
> +                                  s16 ch1gain, int channels) { return 0; }
> +static inline int omap_st_get_chgain(unsigned int id, s16 *ch0gain,
> +                                  s16 *ch1gain) { return 0; }
> +static inline int omap_st_enable(unsigned int id) { return 0; }
> +static inline int omap_st_disable(unsigned int id) { return 0; }
> +static inline int omap_st_is_enabled(unsigned int id) {  return 0; }
> +#endif
> +
>  #endif
> diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
> index 473be3d..921a5c1 100644
> --- a/arch/arm/plat-omap/mcbsp.c
> +++ b/arch/arm/plat-omap/mcbsp.c
> @@ -27,6 +27,8 @@
>  #include <plat/dma.h>
>  #include <plat/mcbsp.h>
>  
> +#include "../mach-omap2/cm-regbits-34xx.h"
> +
>  struct omap_mcbsp **mcbsp_ptr;
>  int omap_mcbsp_count, omap_mcbsp_cache_size;
>  
> @@ -58,6 +60,18 @@ int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, 
> bool from_cache)
>       }
>  }
>  
> +#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 MCBSP_READ(mcbsp, reg) \
>               omap_mcbsp_read(mcbsp, OMAP_MCBSP_REG_##reg, 0)
>  #define MCBSP_WRITE(mcbsp, reg, val) \
> @@ -68,6 +82,11 @@ int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg, 
> bool from_cache)
>  #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);
> @@ -211,6 +230,251 @@ void omap_mcbsp_config(unsigned int id, const struct 
> omap_mcbsp_reg_cfg *config)
>  EXPORT_SYMBOL(omap_mcbsp_config);
>  
>  #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, s16 ch0gain, s16 ch1gain,
> +                    int channels)
> +{
> +     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 -ENOENT;
> +
> +     spin_lock_irq(&mcbsp->lock);
> +     if (channels & OMAP_MCBSP_ST_CHANNEL_0)
> +             st_data->ch0gain = ch0gain;
> +
> +     if (channels &  OMAP_MCBSP_ST_CHANNEL_1)
> +             st_data->ch1gain = ch1gain;
> +
> +     if (st_data->enabled)
> +             omap_st_chgain(mcbsp);
> +     spin_unlock_irq(&mcbsp->lock);
> +
> +     return 0;
> +}
> +EXPORT_SYMBOL(omap_st_set_chgain);
> +
> +int omap_st_get_chgain(unsigned int id, s16 *ch0gain, s16 *ch1gain)
> +{
> +     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 -ENOENT;
> +
> +     spin_lock_irq(&mcbsp->lock);
> +     *ch0gain = st_data->ch0gain;
> +     *ch1gain = st_data->ch1gain;
> +     spin_unlock_irq(&mcbsp->lock);
> +
> +     return 0;
> +}
> +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
> @@ -363,6 +627,8 @@ static inline void omap34xx_mcbsp_free(struct omap_mcbsp 
> *mcbsp)
>  #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
>  
>  /*
> @@ -546,6 +812,9 @@ void omap_mcbsp_start(unsigned int id, int tx, int rx)
>       }
>       mcbsp = id_to_mcbsp_ptr(id);
>  
> +     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;
>  
> @@ -637,6 +906,9 @@ void omap_mcbsp_stop(unsigned int id, int tx, int rx)
>               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);
>  
> @@ -1212,6 +1484,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,
> @@ -1233,6 +1563,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;
> @@ -1246,6 +1630,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;
> @@ -1254,8 +1644,12 @@ 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) 
> {}
> -- 
> 1.6.0.4
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to