]> Pileus Git - ~andy/linux/blobdiff - sound/soc/omap/omap-mcbsp.c
ASoC: omap-mcbsp: Single function CLKR/FSR source mux configuration
[~andy/linux] / sound / soc / omap / omap-mcbsp.c
index 4314647e735eff71a8f038263e2f0e4a640d8d24..d8409b00843183cd1a537184151e1ab6ce98f8e7 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/device.h>
+#include <linux/pm_runtime.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -33,6 +34,7 @@
 
 #include <plat/dma.h>
 #include <plat/mcbsp.h>
+#include "mcbsp.h"
 #include "omap-mcbsp.h"
 #include "omap-pcm.h"
 
        .private_value = (unsigned long) &(struct soc_mixer_control) \
        {.min = xmin, .max = xmax} }
 
-struct omap_mcbsp_data {
-       unsigned int                    bus_id;
-       struct omap_mcbsp_reg_cfg       regs;
-       unsigned int                    fmt;
-       /*
-        * Flags indicating is the bus already activated and configured by
-        * another substream
-        */
-       int                             active;
-       int                             configured;
-       unsigned int                    in_freq;
-       int                             clk_div;
-       int                             wlen;
+enum {
+       OMAP_MCBSP_WORD_8 = 0,
+       OMAP_MCBSP_WORD_12,
+       OMAP_MCBSP_WORD_16,
+       OMAP_MCBSP_WORD_20,
+       OMAP_MCBSP_WORD_24,
+       OMAP_MCBSP_WORD_32,
 };
 
-static struct omap_mcbsp_data mcbsp_data[NUM_LINKS];
-
 /*
  * Stream DMA parameters. DMA request line and port address are set runtime
  * since they are different between OMAP1 and later OMAPs
  */
-static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2];
-
 static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
        struct omap_pcm_dma_data *dma_data;
-       int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id);
        int words;
 
        dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
        /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
-       if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
+       if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
                /*
                 * Configure McBSP threshold based on either:
                 * packet_size, when the sDMA is in packet mode, or
@@ -91,15 +82,15 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
                        words = dma_data->packet_size;
                else
                        words = snd_pcm_lib_period_bytes(substream) /
-                                                       (mcbsp_data->wlen / 8);
+                                                       (mcbsp->wlen / 8);
        else
                words = 1;
 
        /* Configure McBSP internal buffer usage */
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               omap_mcbsp_set_tx_threshold(mcbsp_data->bus_id, words);
+               omap_mcbsp_set_tx_threshold(mcbsp, words);
        else
-               omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, words);
+               omap_mcbsp_set_rx_threshold(mcbsp, words);
 }
 
 static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params,
@@ -109,12 +100,12 @@ static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params,
                                        SNDRV_PCM_HW_PARAM_BUFFER_SIZE);
        struct snd_interval *channels = hw_param_interval(params,
                                        SNDRV_PCM_HW_PARAM_CHANNELS);
-       struct omap_mcbsp_data *mcbsp_data = rule->private;
+       struct omap_mcbsp *mcbsp = rule->private;
        struct snd_interval frames;
        int size;
 
        snd_interval_any(&frames);
-       size = omap_mcbsp_get_fifo_size(mcbsp_data->bus_id);
+       size = mcbsp->pdata->buffer_size;
 
        frames.min = size / channels->min;
        frames.integer = 1;
@@ -124,12 +115,11 @@ static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params,
 static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
                                  struct snd_soc_dai *cpu_dai)
 {
-       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
-       int bus_id = mcbsp_data->bus_id;
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
        int err = 0;
 
        if (!cpu_dai->active)
-               err = omap_mcbsp_request(bus_id);
+               err = omap_mcbsp_request(mcbsp);
 
        /*
         * OMAP3 McBSP FIFO is word structured.
@@ -146,7 +136,7 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
         * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words)
         * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words)
         */
-       if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
+       if (mcbsp->pdata->buffer_size) {
                /*
                * Rule for the buffer size. We should not allow
                * smaller buffer than the FIFO size to avoid underruns
@@ -154,7 +144,7 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
                snd_pcm_hw_rule_add(substream->runtime, 0,
                                    SNDRV_PCM_HW_PARAM_CHANNELS,
                                    omap_mcbsp_hwrule_min_buffersize,
-                                   mcbsp_data,
+                                   mcbsp,
                                    SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1);
 
                /* Make sure, that the period size is always even */
@@ -168,33 +158,33 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
 static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream,
                                    struct snd_soc_dai *cpu_dai)
 {
-       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
 
        if (!cpu_dai->active) {
-               omap_mcbsp_free(mcbsp_data->bus_id);
-               mcbsp_data->configured = 0;
+               omap_mcbsp_free(mcbsp);
+               mcbsp->configured = 0;
        }
 }
 
 static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd,
                                  struct snd_soc_dai *cpu_dai)
 {
-       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
        int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               mcbsp_data->active++;
-               omap_mcbsp_start(mcbsp_data->bus_id, play, !play);
+               mcbsp->active++;
+               omap_mcbsp_start(mcbsp, play, !play);
                break;
 
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               omap_mcbsp_stop(mcbsp_data->bus_id, play, !play);
-               mcbsp_data->active--;
+               omap_mcbsp_stop(mcbsp, play, !play);
+               mcbsp->active--;
                break;
        default:
                err = -EINVAL;
@@ -209,14 +199,14 @@ static snd_pcm_sframes_t omap_mcbsp_dai_delay(
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
        u16 fifo_use;
        snd_pcm_sframes_t delay;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               fifo_use = omap_mcbsp_get_tx_delay(mcbsp_data->bus_id);
+               fifo_use = omap_mcbsp_get_tx_delay(mcbsp);
        else
-               fifo_use = omap_mcbsp_get_rx_delay(mcbsp_data->bus_id);
+               fifo_use = omap_mcbsp_get_rx_delay(mcbsp);
 
        /*
         * Divide the used locations with the channel count to get the
@@ -232,19 +222,14 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
                                    struct snd_pcm_hw_params *params,
                                    struct snd_soc_dai *cpu_dai)
 {
-       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
-       struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+       struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
        struct omap_pcm_dma_data *dma_data;
-       int dma, bus_id = mcbsp_data->bus_id;
        int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT;
        int pkt_size = 0;
-       unsigned long port;
        unsigned int format, div, framesize, master;
 
-       dma_data = &omap_mcbsp_dai_dma_params[cpu_dai->id][substream->stream];
-
-       dma = omap_mcbsp_dma_ch_params(bus_id, substream->stream);
-       port = omap_mcbsp_dma_reg_params(bus_id, substream->stream);
+       dma_data = &mcbsp->dma_data[substream->stream];
 
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
@@ -258,20 +243,17 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
        default:
                return -EINVAL;
        }
-       if (cpu_is_omap34xx()) {
+       if (mcbsp->pdata->buffer_size) {
                dma_data->set_threshold = omap_mcbsp_set_threshold;
                /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
-               if (omap_mcbsp_get_dma_op_mode(bus_id) ==
-                                               MCBSP_DMA_MODE_THRESHOLD) {
+               if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) {
                        int period_words, max_thrsh;
 
                        period_words = params_period_bytes(params) / (wlen / 8);
                        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                               max_thrsh = omap_mcbsp_get_max_tx_threshold(
-                                                           mcbsp_data->bus_id);
+                               max_thrsh = mcbsp->max_tx_thres;
                        else
-                               max_thrsh = omap_mcbsp_get_max_rx_threshold(
-                                                           mcbsp_data->bus_id);
+                               max_thrsh = mcbsp->max_rx_thres;
                        /*
                         * If the period contains less or equal number of words,
                         * we are using the original threshold mode setup:
@@ -304,15 +286,12 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
                }
        }
 
-       dma_data->name = substream->stream ? "Audio Capture" : "Audio Playback";
-       dma_data->dma_req = dma;
-       dma_data->port_addr = port;
        dma_data->sync_mode = sync_mode;
        dma_data->packet_size = pkt_size;
 
        snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
 
-       if (mcbsp_data->configured) {
+       if (mcbsp->configured) {
                /* McBSP already configured by another stream */
                return 0;
        }
@@ -321,7 +300,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
        regs->xcr2      &= ~(RPHASE | XFRLEN2(0x7f) | XWDLEN2(7));
        regs->rcr1      &= ~(RFRLEN1(0x7f) | RWDLEN1(7));
        regs->xcr1      &= ~(XFRLEN1(0x7f) | XWDLEN1(7));
-       format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+       format = mcbsp->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
        wpf = channels = params_channels(params);
        if (channels == 2 && (format == SND_SOC_DAIFMT_I2S ||
                              format == SND_SOC_DAIFMT_LEFT_J)) {
@@ -359,10 +338,10 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
 
        /* In McBSP master modes, FRAME (i.e. sample rate) is generated
         * by _counting_ BCLKs. Calculate frame size in BCLKs */
-       master = mcbsp_data->fmt & SND_SOC_DAIFMT_MASTER_MASK;
+       master = mcbsp->fmt & SND_SOC_DAIFMT_MASTER_MASK;
        if (master ==   SND_SOC_DAIFMT_CBS_CFS) {
-               div = mcbsp_data->clk_div ? mcbsp_data->clk_div : 1;
-               framesize = (mcbsp_data->in_freq / div) / params_rate(params);
+               div = mcbsp->clk_div ? mcbsp->clk_div : 1;
+               framesize = (mcbsp->in_freq / div) / params_rate(params);
 
                if (framesize < wlen * channels) {
                        printk(KERN_ERR "%s: not enough bandwidth for desired rate and "
@@ -388,9 +367,9 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
                break;
        }
 
-       omap_mcbsp_config(bus_id, &mcbsp_data->regs);
-       mcbsp_data->wlen = wlen;
-       mcbsp_data->configured = 1;
+       omap_mcbsp_config(mcbsp, &mcbsp->cfg_regs);
+       mcbsp->wlen = wlen;
+       mcbsp->configured = 1;
 
        return 0;
 }
@@ -402,14 +381,14 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
 static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                                      unsigned int fmt)
 {
-       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
-       struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+       struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
        bool inv_fs = false;
 
-       if (mcbsp_data->configured)
+       if (mcbsp->configured)
                return 0;
 
-       mcbsp_data->fmt = fmt;
+       mcbsp->fmt = fmt;
        memset(regs, 0, sizeof(*regs));
        /* Generic McBSP register settings */
        regs->spcr2     |= XINTM(3) | FREE;
@@ -504,13 +483,13 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
 static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
                                     int div_id, int div)
 {
-       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
-       struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+       struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
 
        if (div_id != OMAP_MCBSP_CLKGDV)
                return -ENODEV;
 
-       mcbsp_data->clk_div = div;
+       mcbsp->clk_div = div;
        regs->srgr1     &= ~CLKGDV(0xff);
        regs->srgr1     |= CLKGDV(div - 1);
 
@@ -521,12 +500,12 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
                                         int clk_id, unsigned int freq,
                                         int dir)
 {
-       struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
-       struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+       struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
        int err = 0;
 
-       if (mcbsp_data->active) {
-               if (freq == mcbsp_data->in_freq)
+       if (mcbsp->active) {
+               if (freq == mcbsp->in_freq)
                        return 0;
                else
                        return -EBUSY;
@@ -537,10 +516,10 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
            clk_id == OMAP_MCBSP_CLKR_SRC_CLKX ||
            clk_id == OMAP_MCBSP_FSR_SRC_FSR ||
            clk_id == OMAP_MCBSP_FSR_SRC_FSX)
-               if (cpu_class_is_omap1() || mcbsp_data->bus_id != 0)
+               if (cpu_class_is_omap1() || cpu_dai->id != 1)
                        return -EINVAL;
 
-       mcbsp_data->in_freq = freq;
+       mcbsp->in_freq = freq;
        regs->srgr2     &= ~CLKSM;
        regs->pcr0      &= ~SCLKME;
 
@@ -553,7 +532,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
                        err = -EINVAL;
                        break;
                }
-               err = omap2_mcbsp_set_clks_src(mcbsp_data->bus_id,
+               err = omap2_mcbsp_set_clks_src(mcbsp,
                                               MCBSP_CLKS_PRCM_SRC);
                break;
        case OMAP_MCBSP_SYSCLK_CLKS_EXT:
@@ -561,7 +540,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
                        err = 0;
                        break;
                }
-               err = omap2_mcbsp_set_clks_src(mcbsp_data->bus_id,
+               err = omap2_mcbsp_set_clks_src(mcbsp,
                                               MCBSP_CLKS_PAD_SRC);
                break;
 
@@ -575,22 +554,22 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
        case OMAP_MCBSP_CLKR_SRC_CLKR:
                if (cpu_class_is_omap1())
                        break;
-               omap2_mcbsp1_mux_clkr_src(CLKR_SRC_CLKR);
+               err = omap_mcbsp_6pin_src_mux(mcbsp, CLKR_SRC_CLKR);
                break;
        case OMAP_MCBSP_CLKR_SRC_CLKX:
                if (cpu_class_is_omap1())
                        break;
-               omap2_mcbsp1_mux_clkr_src(CLKR_SRC_CLKX);
+               err = omap_mcbsp_6pin_src_mux(mcbsp, CLKR_SRC_CLKX);
                break;
        case OMAP_MCBSP_FSR_SRC_FSR:
                if (cpu_class_is_omap1())
                        break;
-               omap2_mcbsp1_mux_fsr_src(FSR_SRC_FSR);
+               err = omap_mcbsp_6pin_src_mux(mcbsp, FSR_SRC_FSR);
                break;
        case OMAP_MCBSP_FSR_SRC_FSX:
                if (cpu_class_is_omap1())
                        break;
-               omap2_mcbsp1_mux_fsr_src(FSR_SRC_FSX);
+               err = omap_mcbsp_6pin_src_mux(mcbsp, FSR_SRC_FSX);
                break;
        default:
                err = -ENODEV;
@@ -599,7 +578,7 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
        return err;
 }
 
-static struct snd_soc_dai_ops mcbsp_dai_ops = {
+static const struct snd_soc_dai_ops mcbsp_dai_ops = {
        .startup        = omap_mcbsp_dai_startup,
        .shutdown       = omap_mcbsp_dai_shutdown,
        .trigger        = omap_mcbsp_dai_trigger,
@@ -610,15 +589,27 @@ static struct snd_soc_dai_ops mcbsp_dai_ops = {
        .set_sysclk     = omap_mcbsp_dai_set_dai_sysclk,
 };
 
-static int mcbsp_dai_probe(struct snd_soc_dai *dai)
+static int omap_mcbsp_probe(struct snd_soc_dai *dai)
+{
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai);
+
+       pm_runtime_enable(mcbsp->dev);
+
+       return 0;
+}
+
+static int omap_mcbsp_remove(struct snd_soc_dai *dai)
 {
-       mcbsp_data[dai->id].bus_id = dai->id;
-       snd_soc_dai_set_drvdata(dai, &mcbsp_data[dai->id].bus_id);
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai);
+
+       pm_runtime_disable(mcbsp->dev);
+
        return 0;
 }
 
 static struct snd_soc_dai_driver omap_mcbsp_dai = {
-       .probe = mcbsp_dai_probe,
+       .probe = omap_mcbsp_probe,
+       .remove = omap_mcbsp_remove,
        .playback = {
                .channels_min = 1,
                .channels_max = 16,
@@ -649,11 +640,13 @@ static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-#define OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(id, channel)                  \
+#define OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(channel)                      \
 static int                                                             \
-omap_mcbsp##id##_set_st_ch##channel##_volume(struct snd_kcontrol *kc,  \
+omap_mcbsp_set_st_ch##channel##_volume(struct snd_kcontrol *kc,        \
                                        struct snd_ctl_elem_value *uc)  \
 {                                                                      \
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc);            \
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);    \
        struct soc_mixer_control *mc =                                  \
                (struct soc_mixer_control *)kc->private_value;          \
        int max = mc->max;                                              \
@@ -664,46 +657,44 @@ omap_mcbsp##id##_set_st_ch##channel##_volume(struct snd_kcontrol *kc,     \
                return -EINVAL;                                         \
                                                                        \
        /* OMAP McBSP implementation uses index values 0..4 */          \
-       return omap_st_set_chgain((id)-1, channel, val);                \
+       return omap_st_set_chgain(mcbsp, channel, val);                 \
 }
 
-#define OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(id, channel)                  \
+#define OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(channel)                      \
 static int                                                             \
-omap_mcbsp##id##_get_st_ch##channel##_volume(struct snd_kcontrol *kc,  \
+omap_mcbsp_get_st_ch##channel##_volume(struct snd_kcontrol *kc,        \
                                        struct snd_ctl_elem_value *uc)  \
 {                                                                      \
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kc);            \
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);    \
        s16 chgain;                                                     \
                                                                        \
-       if (omap_st_get_chgain((id)-1, channel, &chgain))               \
+       if (omap_st_get_chgain(mcbsp, channel, &chgain))                \
                return -EAGAIN;                                         \
                                                                        \
        uc->value.integer.value[0] = chgain;                            \
        return 0;                                                       \
 }
 
-OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(2, 0)
-OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(2, 1)
-OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(3, 0)
-OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(3, 1)
-OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(2, 0)
-OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(2, 1)
-OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(3, 0)
-OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(3, 1)
+OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(0)
+OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(1)
+OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(0)
+OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(1)
 
 static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
        u8 value = ucontrol->value.integer.value[0];
 
-       if (value == omap_st_is_enabled(mc->reg))
+       if (value == omap_st_is_enabled(mcbsp))
                return 0;
 
        if (value)
-               omap_st_enable(mc->reg);
+               omap_st_enable(mcbsp);
        else
-               omap_st_disable(mc->reg);
+               omap_st_disable(mcbsp);
 
        return 1;
 }
@@ -711,10 +702,10 @@ static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol,
 static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
 {
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
 
-       ucontrol->value.integer.value[0] = omap_st_is_enabled(mc->reg);
+       ucontrol->value.integer.value[0] = omap_st_is_enabled(mcbsp);
        return 0;
 }
 
@@ -723,12 +714,12 @@ static const struct snd_kcontrol_new omap_mcbsp2_st_controls[] = {
                        omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode),
        OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 0 Volume",
                                      -32768, 32767,
-                                     omap_mcbsp2_get_st_ch0_volume,
-                                     omap_mcbsp2_set_st_ch0_volume),
+                                     omap_mcbsp_get_st_ch0_volume,
+                                     omap_mcbsp_set_st_ch0_volume),
        OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 1 Volume",
                                      -32768, 32767,
-                                     omap_mcbsp2_get_st_ch1_volume,
-                                     omap_mcbsp2_set_st_ch1_volume),
+                                     omap_mcbsp_get_st_ch1_volume,
+                                     omap_mcbsp_set_st_ch1_volume),
 };
 
 static const struct snd_kcontrol_new omap_mcbsp3_st_controls[] = {
@@ -736,25 +727,30 @@ static const struct snd_kcontrol_new omap_mcbsp3_st_controls[] = {
                        omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode),
        OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 0 Volume",
                                      -32768, 32767,
-                                     omap_mcbsp3_get_st_ch0_volume,
-                                     omap_mcbsp3_set_st_ch0_volume),
+                                     omap_mcbsp_get_st_ch0_volume,
+                                     omap_mcbsp_set_st_ch0_volume),
        OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 1 Volume",
                                      -32768, 32767,
-                                     omap_mcbsp3_get_st_ch1_volume,
-                                     omap_mcbsp3_set_st_ch1_volume),
+                                     omap_mcbsp_get_st_ch1_volume,
+                                     omap_mcbsp_set_st_ch1_volume),
 };
 
-int omap_mcbsp_st_add_controls(struct snd_soc_codec *codec, int mcbsp_id)
+int omap_mcbsp_st_add_controls(struct snd_soc_pcm_runtime *rtd)
 {
-       if (!cpu_is_omap34xx())
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
+
+       if (!mcbsp->st_data)
                return -ENODEV;
 
-       switch (mcbsp_id) {
-       case 1: /* McBSP 2 */
-               return snd_soc_add_controls(codec, omap_mcbsp2_st_controls,
+       switch (cpu_dai->id) {
+       case 2: /* McBSP 2 */
+               return snd_soc_add_dai_controls(cpu_dai,
+                                       omap_mcbsp2_st_controls,
                                        ARRAY_SIZE(omap_mcbsp2_st_controls));
-       case 2: /* McBSP 3 */
-               return snd_soc_add_controls(codec, omap_mcbsp3_st_controls,
+       case 3: /* McBSP 3 */
+               return snd_soc_add_dai_controls(cpu_dai,
+                                       omap_mcbsp3_st_controls,
                                        ARRAY_SIZE(omap_mcbsp3_st_controls));
        default:
                break;
@@ -766,18 +762,51 @@ EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls);
 
 static __devinit int asoc_mcbsp_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_dai(&pdev->dev, &omap_mcbsp_dai);
+       struct omap_mcbsp_platform_data *pdata = dev_get_platdata(&pdev->dev);
+       struct omap_mcbsp *mcbsp;
+       int ret;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "missing platform data.\n");
+               return -EINVAL;
+       }
+       mcbsp = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcbsp), GFP_KERNEL);
+       if (!mcbsp)
+               return -ENOMEM;
+
+       mcbsp->id = pdev->id;
+       mcbsp->pdata = pdata;
+       mcbsp->dev = &pdev->dev;
+       platform_set_drvdata(pdev, mcbsp);
+
+       ret = omap_mcbsp_init(pdev);
+       if (!ret)
+               return snd_soc_register_dai(&pdev->dev, &omap_mcbsp_dai);
+
+       return ret;
 }
 
 static int __devexit asoc_mcbsp_remove(struct platform_device *pdev)
 {
+       struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
+
        snd_soc_unregister_dai(&pdev->dev);
+
+       if (mcbsp->pdata->ops && mcbsp->pdata->ops->free)
+               mcbsp->pdata->ops->free(mcbsp->id);
+
+       omap_mcbsp_sysfs_remove(mcbsp);
+
+       clk_put(mcbsp->fclk);
+
+       platform_set_drvdata(pdev, NULL);
+
        return 0;
 }
 
 static struct platform_driver asoc_mcbsp_driver = {
        .driver = {
-                       .name = "omap-mcbsp-dai",
+                       .name = "omap-mcbsp",
                        .owner = THIS_MODULE,
        },
 
@@ -785,17 +814,7 @@ static struct platform_driver asoc_mcbsp_driver = {
        .remove = __devexit_p(asoc_mcbsp_remove),
 };
 
-static int __init snd_omap_mcbsp_init(void)
-{
-       return platform_driver_register(&asoc_mcbsp_driver);
-}
-module_init(snd_omap_mcbsp_init);
-
-static void __exit snd_omap_mcbsp_exit(void)
-{
-       platform_driver_unregister(&asoc_mcbsp_driver);
-}
-module_exit(snd_omap_mcbsp_exit);
+module_platform_driver(asoc_mcbsp_driver);
 
 MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
 MODULE_DESCRIPTION("OMAP I2S SoC Interface");