Merge branch 'for-3.0' into for-3.1
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Mon, 6 Jun 2011 11:26:02 +0000 (12:26 +0100)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Mon, 6 Jun 2011 11:26:02 +0000 (12:26 +0100)
15 files changed:
sound/soc/atmel/atmel-pcm.c
sound/soc/atmel/atmel-pcm.h
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/codecs/ak4641.c
sound/soc/codecs/cs4270.c
sound/soc/codecs/max98088.c
sound/soc/codecs/max98095.c
sound/soc/codecs/wm8915.c
sound/soc/davinci/davinci-pcm.c
sound/soc/nuc900/nuc900-ac97.c
sound/soc/samsung/speyside.c
sound/soc/sh/fsi.c
sound/soc/soc-cache.c
sound/soc/soc-core.c
sound/soc/tegra/tegra_wm8903.c

index d0e7532..51dde4e 100644 (file)
@@ -382,7 +382,7 @@ static int atmel_pcm_new(struct snd_card *card,
        }
 
        if (dai->driver->capture.channels_min) {
-               pr_debug("at32-pcm:"
+               pr_debug("atmel-pcm:"
                                "Allocating PCM capture DMA buffer\n");
                ret = atmel_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
index 2597329..5e0a95e 100644 (file)
@@ -60,7 +60,7 @@ struct atmel_ssc_mask {
  * This structure, shared between the PCM driver and the interface,
  * contains all information required by the PCM driver to perform the
  * PDC DMA operation.  All fields except dma_intr_handler() are initialized
- * by the interface.  The dms_intr_handler() pointer is set by the PCM
+ * by the interface.  The dma_intr_handler() pointer is set by the PCM
  * driver and called by the interface SSC interrupt handler if it is
  * non-NULL.
  */
index eda955b..f53dc09 100644 (file)
@@ -838,10 +838,8 @@ int atmel_ssc_set_audio(int ssc_id)
        }
 
        ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id);
-       if (!ssc_pdev) {
-               ssc_free(ssc);
+       if (!ssc_pdev)
                return -ENOMEM;
-       }
 
        /* If we can grab the SSC briefly to parent the DAI device off it */
        ssc = ssc_request(ssc_id);
index ed96f24..7a64e58 100644 (file)
@@ -457,7 +457,7 @@ static struct snd_soc_dai_ops ak4641_pcm_dai_ops = {
        .set_sysclk   = ak4641_set_dai_sysclk,
 };
 
-struct snd_soc_dai_driver ak4641_dai[] = {
+static struct snd_soc_dai_driver ak4641_dai[] = {
 {
        .name = "ak4641-hifi",
        .id = 1,
index 0206a17..6cc8678 100644 (file)
@@ -636,10 +636,7 @@ static int cs4270_soc_resume(struct snd_soc_codec *codec)
 #endif /* CONFIG_PM */
 
 /*
- * ASoC codec device structure
- *
- * Assign this variable to the codec_dev field of the machine driver's
- * snd_soc_device structure.
+ * ASoC codec driver structure
  */
 static const struct snd_soc_codec_driver soc_codec_device_cs4270 = {
        .probe =                cs4270_probe,
index 4173b67..ac65a2d 100644 (file)
@@ -1397,8 +1397,6 @@ static int max98088_dai_set_sysclk(struct snd_soc_dai *dai,
        if (freq == max98088->sysclk)
                return 0;
 
-       max98088->sysclk = freq; /* remember current sysclk */
-
        /* Setup clocks for slave mode, and using the PLL
         * PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
         *         0x02 (when master clk is 20MHz to 30MHz)..
index e1d282d..872a5fa 100644 (file)
@@ -1517,8 +1517,6 @@ static int max98095_dai_set_sysclk(struct snd_soc_dai *dai,
        if (freq == max98095->sysclk)
                return 0;
 
-       max98095->sysclk = freq; /* remember current sysclk */
-
        /* Setup clocks for slave mode, and using the PLL
         * PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
         *         0x02 (when master clk is 20MHz to 40MHz)..
index a0b1a72..5a59ef7 100644 (file)
 #define HPOUT2L 4
 #define HPOUT2R 8
 
-#define WM8915_NUM_SUPPLIES 6
+#define WM8915_NUM_SUPPLIES 4
 static const char *wm8915_supply_names[WM8915_NUM_SUPPLIES] = {
-       "DCVDD",
        "DBVDD",
        "AVDD1",
        "AVDD2",
        "CPVDD",
-       "MICVDD",
 };
 
 struct wm8915_priv {
@@ -113,8 +111,6 @@ WM8915_REGULATOR_EVENT(0)
 WM8915_REGULATOR_EVENT(1)
 WM8915_REGULATOR_EVENT(2)
 WM8915_REGULATOR_EVENT(3)
-WM8915_REGULATOR_EVENT(4)
-WM8915_REGULATOR_EVENT(5)
 
 static const u16 wm8915_reg[WM8915_MAX_REGISTER] = {
        [WM8915_SOFTWARE_RESET] = 0x8915,
@@ -2292,6 +2288,12 @@ static void wm8915_micd(struct snd_soc_codec *codec)
                                    SND_JACK_HEADSET | SND_JACK_BTN_0);
                wm8915->jack_mic = true;
                wm8915->detecting = false;
+
+               /* Increase poll rate to give better responsiveness
+                * for buttons */
+               snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
+                                   WM8915_MICD_RATE_MASK,
+                                   5 << WM8915_MICD_RATE_SHIFT);
        }
 
        /* If we detected a lower impedence during initial startup
@@ -2332,15 +2334,17 @@ static void wm8915_micd(struct snd_soc_codec *codec)
                                            SND_JACK_HEADPHONE,
                                            SND_JACK_HEADSET |
                                            SND_JACK_BTN_0);
+
+                       /* Increase the detection rate a bit for
+                        * responsiveness.
+                        */
+                       snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
+                                           WM8915_MICD_RATE_MASK,
+                                           7 << WM8915_MICD_RATE_SHIFT);
+
                        wm8915->detecting = false;
                }
        }
-
-       /* Increase poll rate to give better responsiveness for buttons */
-       if (!wm8915->detecting)
-               snd_soc_update_bits(codec, WM8915_MIC_DETECT_1,
-                                   WM8915_MICD_RATE_MASK,
-                                   5 << WM8915_MICD_RATE_SHIFT);
 }
 
 static irqreturn_t wm8915_irq(int irq, void *data)
@@ -2382,6 +2386,20 @@ static irqreturn_t wm8915_irq(int irq, void *data)
        }
 }
 
+static irqreturn_t wm8915_edge_irq(int irq, void *data)
+{
+       irqreturn_t ret = IRQ_NONE;
+       irqreturn_t val;
+
+       do {
+               val = wm8915_irq(irq, data);
+               if (val != IRQ_NONE)
+                       ret = val;
+       } while (val != IRQ_NONE);
+
+       return ret;
+}
+
 static void wm8915_retune_mobile_pdata(struct snd_soc_codec *codec)
 {
        struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec);
@@ -2481,8 +2499,6 @@ static int wm8915_probe(struct snd_soc_codec *codec)
        wm8915->disable_nb[1].notifier_call = wm8915_regulator_event_1;
        wm8915->disable_nb[2].notifier_call = wm8915_regulator_event_2;
        wm8915->disable_nb[3].notifier_call = wm8915_regulator_event_3;
-       wm8915->disable_nb[4].notifier_call = wm8915_regulator_event_4;
-       wm8915->disable_nb[5].notifier_call = wm8915_regulator_event_5;
 
        /* This should really be moved into the regulator core */
        for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++) {
@@ -2708,8 +2724,14 @@ static int wm8915_probe(struct snd_soc_codec *codec)
 
                irq_flags |= IRQF_ONESHOT;
 
-               ret = request_threaded_irq(i2c->irq, NULL, wm8915_irq,
-                                          irq_flags, "wm8915", codec);
+               if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))
+                       ret = request_threaded_irq(i2c->irq, NULL,
+                                                  wm8915_edge_irq,
+                                                  irq_flags, "wm8915", codec);
+               else
+                       ret = request_threaded_irq(i2c->irq, NULL, wm8915_irq,
+                                                  irq_flags, "wm8915", codec);
+
                if (ret == 0) {
                        /* Unmask the interrupt */
                        snd_soc_update_bits(codec, WM8915_INTERRUPT_CONTROL,
index 9d35b8c..c9e0320 100644 (file)
@@ -46,11 +46,28 @@ static void print_buf_info(int slot, char *name)
 }
 #endif
 
+#define DAVINCI_PCM_FMTBITS    (\
+                               SNDRV_PCM_FMTBIT_S8     |\
+                               SNDRV_PCM_FMTBIT_U8     |\
+                               SNDRV_PCM_FMTBIT_S16_LE |\
+                               SNDRV_PCM_FMTBIT_S16_BE |\
+                               SNDRV_PCM_FMTBIT_U16_LE |\
+                               SNDRV_PCM_FMTBIT_U16_BE |\
+                               SNDRV_PCM_FMTBIT_S24_LE |\
+                               SNDRV_PCM_FMTBIT_S24_BE |\
+                               SNDRV_PCM_FMTBIT_U24_LE |\
+                               SNDRV_PCM_FMTBIT_U24_BE |\
+                               SNDRV_PCM_FMTBIT_S32_LE |\
+                               SNDRV_PCM_FMTBIT_S32_BE |\
+                               SNDRV_PCM_FMTBIT_U32_LE |\
+                               SNDRV_PCM_FMTBIT_U32_BE)
+
 static struct snd_pcm_hardware pcm_hardware_playback = {
        .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
                 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
-                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
-       .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+                SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME|
+                SNDRV_PCM_INFO_BATCH),
+       .formats = DAVINCI_PCM_FMTBITS,
        .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
                  SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
                  SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
@@ -59,7 +76,7 @@ static struct snd_pcm_hardware pcm_hardware_playback = {
        .rate_min = 8000,
        .rate_max = 96000,
        .channels_min = 2,
-       .channels_max = 2,
+       .channels_max = 384,
        .buffer_bytes_max = 128 * 1024,
        .period_bytes_min = 32,
        .period_bytes_max = 8 * 1024,
@@ -71,8 +88,9 @@ static struct snd_pcm_hardware pcm_hardware_playback = {
 static struct snd_pcm_hardware pcm_hardware_capture = {
        .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
                 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
-                SNDRV_PCM_INFO_PAUSE),
-       .formats = (SNDRV_PCM_FMTBIT_S16_LE),
+                SNDRV_PCM_INFO_PAUSE |
+                SNDRV_PCM_INFO_BATCH),
+       .formats = DAVINCI_PCM_FMTBITS,
        .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
                  SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
                  SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
@@ -81,7 +99,7 @@ static struct snd_pcm_hardware pcm_hardware_capture = {
        .rate_min = 8000,
        .rate_max = 96000,
        .channels_min = 2,
-       .channels_max = 2,
+       .channels_max = 384,
        .buffer_bytes_max = 128 * 1024,
        .period_bytes_min = 32,
        .period_bytes_max = 8 * 1024,
@@ -139,6 +157,22 @@ struct davinci_runtime_data {
        struct edmacc_param ram_params;
 };
 
+static void davinci_pcm_period_elapsed(struct snd_pcm_substream *substream)
+{
+       struct davinci_runtime_data *prtd = substream->runtime->private_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       prtd->period++;
+       if (unlikely(prtd->period >= runtime->periods))
+               prtd->period = 0;
+}
+
+static void davinci_pcm_period_reset(struct snd_pcm_substream *substream)
+{
+       struct davinci_runtime_data *prtd = substream->runtime->private_data;
+
+       prtd->period = 0;
+}
 /*
  * Not used with ping/pong
  */
@@ -199,10 +233,6 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
        else
                edma_set_transfer_params(link, acnt, fifo_level, count,
                                                        fifo_level, ABSYNC);
-
-       prtd->period++;
-       if (unlikely(prtd->period >= runtime->periods))
-               prtd->period = 0;
 }
 
 static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data)
@@ -217,12 +247,13 @@ static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data)
                return;
 
        if (snd_pcm_running(substream)) {
+               spin_lock(&prtd->lock);
                if (prtd->ram_channel < 0) {
                        /* No ping/pong must fix up link dma data*/
-                       spin_lock(&prtd->lock);
                        davinci_pcm_enqueue_dma(substream);
-                       spin_unlock(&prtd->lock);
                }
+               davinci_pcm_period_elapsed(substream);
+               spin_unlock(&prtd->lock);
                snd_pcm_period_elapsed(substream);
        }
 }
@@ -425,7 +456,8 @@ static int request_ping_pong(struct snd_pcm_substream *substream,
 
        edma_read_slot(link, &prtd->asp_params);
        prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f) | TCINTEN);
-       prtd->asp_params.opt |= TCCHEN | EDMA_TCC(prtd->ram_channel & 0x3f);
+       prtd->asp_params.opt |= TCCHEN |
+               EDMA_TCC(prtd->ram_channel & 0x3f);
        edma_write_slot(link, &prtd->asp_params);
 
        /* pong */
@@ -439,7 +471,7 @@ static int request_ping_pong(struct snd_pcm_substream *substream,
        prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f));
        /* interrupt after every pong completion */
        prtd->asp_params.opt |= TCINTEN | TCCHEN |
-               EDMA_TCC(EDMA_CHAN_SLOT(prtd->ram_channel));
+               EDMA_TCC(prtd->ram_channel & 0x3f);
        edma_write_slot(link, &prtd->asp_params);
 
        /* ram */
@@ -527,6 +559,13 @@ static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
+               edma_start(prtd->asp_channel);
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
+                   prtd->ram_channel >= 0) {
+                       /* copy 1st iram buffer */
+                       edma_start(prtd->ram_channel);
+               }
+               break;
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                edma_resume(prtd->asp_channel);
@@ -550,6 +589,7 @@ static int davinci_pcm_prepare(struct snd_pcm_substream *substream)
 {
        struct davinci_runtime_data *prtd = substream->runtime->private_data;
 
+       davinci_pcm_period_reset(substream);
        if (prtd->ram_channel >= 0) {
                int ret = ping_pong_dma_setup(substream);
                if (ret < 0)
@@ -565,21 +605,31 @@ static int davinci_pcm_prepare(struct snd_pcm_substream *substream)
                print_buf_info(prtd->asp_link[0], "asp_link[0]");
                print_buf_info(prtd->asp_link[1], "asp_link[1]");
 
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-                       /* copy 1st iram buffer */
-                       edma_start(prtd->ram_channel);
-               }
-               edma_start(prtd->asp_channel);
+               /*
+                * There is a phase offset of 2 periods between the position
+                * used by dma setup and the position reported in the pointer
+                * function.
+                *
+                * The phase offset, when not using ping-pong buffers, is due to
+                * the two consecutive calls to davinci_pcm_enqueue_dma() below.
+                *
+                * Whereas here, with ping-pong buffers, the phase is due to
+                * there being an entire buffer transfer complete before the
+                * first dma completion event triggers davinci_pcm_dma_irq().
+                */
+               davinci_pcm_period_elapsed(substream);
+               davinci_pcm_period_elapsed(substream);
+
                return 0;
        }
-       prtd->period = 0;
        davinci_pcm_enqueue_dma(substream);
+       davinci_pcm_period_elapsed(substream);
 
        /* Copy self-linked parameter RAM entry into master channel */
        edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
        edma_write_slot(prtd->asp_channel, &prtd->asp_params);
        davinci_pcm_enqueue_dma(substream);
-       edma_start(prtd->asp_channel);
+       davinci_pcm_period_elapsed(substream);
 
        return 0;
 }
@@ -591,51 +641,23 @@ davinci_pcm_pointer(struct snd_pcm_substream *substream)
        struct davinci_runtime_data *prtd = runtime->private_data;
        unsigned int offset;
        int asp_count;
-       dma_addr_t asp_src, asp_dst;
-
+       unsigned int period_size = snd_pcm_lib_period_bytes(substream);
+
+       /*
+        * There is a phase offset of 2 periods between the position used by dma
+        * setup and the position reported in the pointer function. Either +2 in
+        * the dma setup or -2 here in the pointer function (with wrapping,
+        * both) accounts for this offset -- choose the latter since it makes
+        * the first-time setup clearer.
+        */
        spin_lock(&prtd->lock);
-       if (prtd->ram_channel >= 0) {
-               int ram_count;
-               int mod_ram;
-               dma_addr_t ram_src, ram_dst;
-               unsigned int period_size = snd_pcm_lib_period_bytes(substream);
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-                       /* reading ram before asp should be safe
-                        * as long as the asp transfers less than a ping size
-                        * of bytes between the 2 reads
-                        */
-                       edma_get_position(prtd->ram_channel,
-                                       &ram_src, &ram_dst);
-                       edma_get_position(prtd->asp_channel,
-                                       &asp_src, &asp_dst);
-                       asp_count = asp_src - prtd->asp_params.src;
-                       ram_count = ram_src - prtd->ram_params.src;
-                       mod_ram = ram_count % period_size;
-                       mod_ram -= asp_count;
-                       if (mod_ram < 0)
-                               mod_ram += period_size;
-                       else if (mod_ram == 0) {
-                               if (snd_pcm_running(substream))
-                                       mod_ram += period_size;
-                       }
-                       ram_count -= mod_ram;
-                       if (ram_count < 0)
-                               ram_count += period_size * runtime->periods;
-               } else {
-                       edma_get_position(prtd->ram_channel,
-                                       &ram_src, &ram_dst);
-                       ram_count = ram_dst - prtd->ram_params.dst;
-               }
-               asp_count = ram_count;
-       } else {
-               edma_get_position(prtd->asp_channel, &asp_src, &asp_dst);
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       asp_count = asp_src - runtime->dma_addr;
-               else
-                       asp_count = asp_dst - runtime->dma_addr;
-       }
+       asp_count = prtd->period - 2;
        spin_unlock(&prtd->lock);
 
+       if (asp_count < 0)
+               asp_count += runtime->periods;
+       asp_count *= period_size;
+
        offset = bytes_to_frames(runtime, asp_count);
        if (offset >= runtime->buffer_size)
                offset = 0;
index dac6732..9c0edad 100644 (file)
@@ -356,7 +356,7 @@ static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev)
        nuc900_audio->irq_num = platform_get_irq(pdev, 0);
        if (!nuc900_audio->irq_num) {
                ret = -EBUSY;
-               goto out2;
+               goto out3;
        }
 
        nuc900_ac97_data = nuc900_audio;
index 360a333..93078b1 100644 (file)
@@ -27,12 +27,12 @@ static int speyside_set_bias_level(struct snd_soc_card *card,
 
        switch (level) {
        case SND_SOC_BIAS_STANDBY:
-               ret = snd_soc_dai_set_sysclk(codec_dai, WM8915_SYSCLK_MCLK1,
+               ret = snd_soc_dai_set_sysclk(codec_dai, WM8915_SYSCLK_MCLK2,
                                             32768, SND_SOC_CLOCK_IN);
                if (ret < 0)
                        return ret;
 
-               ret = snd_soc_dai_set_pll(codec_dai, WM8915_FLL_MCLK1,
+               ret = snd_soc_dai_set_pll(codec_dai, WM8915_FLL_MCLK2,
                                          0, 0, 0);
                if (ret < 0) {
                        pr_err("Failed to stop FLL\n");
@@ -66,7 +66,7 @@ static int speyside_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dai_set_pll(codec_dai, 0, WM8915_FLL_MCLK1,
+       ret = snd_soc_dai_set_pll(codec_dai, 0, WM8915_FLL_MCLK2,
                                  32768, 256 * 48000);
        if (ret < 0)
                return ret;
@@ -127,7 +127,7 @@ static int speyside_wm8915_init(struct snd_soc_pcm_runtime *rtd)
        struct snd_soc_codec *codec = rtd->codec;
        int ret;
 
-       ret = snd_soc_dai_set_sysclk(dai, WM8915_SYSCLK_MCLK1, 32768, 0);
+       ret = snd_soc_dai_set_sysclk(dai, WM8915_SYSCLK_MCLK2, 32768, 0);
        if (ret < 0)
                return ret;
 
index 4a9da6b..d2f17ce 100644 (file)
@@ -118,10 +118,38 @@ typedef int (*set_rate_func)(struct device *dev, int is_porta, int rate, int ena
 /*
  * FSI driver use below type name for variable
  *
- * xxx_len     : data length
- * xxx_width   : data width
- * xxx_offset  : data offset
  * xxx_num     : number of data
+ * xxx_pos     : position of data
+ * xxx_capa    : capacity of data
+ */
+
+/*
+ *     period/frame/sample image
+ *
+ * ex) PCM (2ch)
+ *
+ * period pos                                     period pos
+ *   [n]                                            [n + 1]
+ *   |<-------------------- period--------------------->|
+ * ==|============================================ ... =|==
+ *   |                                                 |
+ *   ||<-----  frame ----->|<------ frame ----->|  ... |
+ *   |+--------------------+--------------------+- ... |
+ *   ||[ sample ][ sample ]|[ sample ][ sample ]|  ... |
+ *   |+--------------------+--------------------+- ... |
+ * ==|============================================ ... =|==
+ */
+
+/*
+ *     FSI FIFO image
+ *
+ *     |            |
+ *     |            |
+ *     | [ sample ] |
+ *     | [ sample ] |
+ *     | [ sample ] |
+ *     | [ sample ] |
+ *             --> go to codecs
  */
 
 /*
@@ -131,12 +159,11 @@ typedef int (*set_rate_func)(struct device *dev, int is_porta, int rate, int ena
 struct fsi_stream {
        struct snd_pcm_substream *substream;
 
-       int fifo_max_num;
-
-       int buff_offset;
-       int buff_len;
-       int period_len;
-       int period_num;
+       int fifo_sample_capa;   /* sample capacity of FSI FIFO */
+       int buff_sample_capa;   /* sample capacity of ALSA buffer */
+       int buff_sample_pos;    /* sample position of ALSA buffer */
+       int period_samples;     /* sample number / 1 period */
+       int period_pos;         /* current period position */
 
        int uerr_num;
        int oerr_num;
@@ -149,17 +176,14 @@ struct fsi_priv {
        struct fsi_stream playback;
        struct fsi_stream capture;
 
+       u32 do_fmt;
+       u32 di_fmt;
+
        int chan_num:16;
        int clk_master:1;
+       int spdif:1;
 
        long rate;
-
-       /* for suspend/resume */
-       u32 saved_do_fmt;
-       u32 saved_di_fmt;
-       u32 saved_ckg1;
-       u32 saved_ckg2;
-       u32 saved_out_sel;
 };
 
 struct fsi_core {
@@ -180,14 +204,6 @@ struct fsi_master {
        struct fsi_core *core;
        struct sh_fsi_platform_info *info;
        spinlock_t lock;
-
-       /* for suspend/resume */
-       u32 saved_a_mclk;
-       u32 saved_b_mclk;
-       u32 saved_iemsk;
-       u32 saved_imsk;
-       u32 saved_clk_rst;
-       u32 saved_soft_rst;
 };
 
 /*
@@ -271,6 +287,11 @@ static int fsi_is_port_a(struct fsi_priv *fsi)
        return fsi->master->base == fsi->base;
 }
 
+static int fsi_is_spdif(struct fsi_priv *fsi)
+{
+       return fsi->spdif;
+}
+
 static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -342,28 +363,59 @@ static u32 fsi_get_port_shift(struct fsi_priv *fsi, int is_play)
        return shift;
 }
 
+static int fsi_frame2sample(struct fsi_priv *fsi, int frames)
+{
+       return frames * fsi->chan_num;
+}
+
+static int fsi_sample2frame(struct fsi_priv *fsi, int samples)
+{
+       return samples / fsi->chan_num;
+}
+
+static int fsi_stream_is_working(struct fsi_priv *fsi,
+                                 int is_play)
+{
+       struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+       struct fsi_master *master = fsi_get_master(fsi);
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&master->lock, flags);
+       ret = !!io->substream;
+       spin_unlock_irqrestore(&master->lock, flags);
+
+       return ret;
+}
+
 static void fsi_stream_push(struct fsi_priv *fsi,
                            int is_play,
-                           struct snd_pcm_substream *substream,
-                           u32 buffer_len,
-                           u32 period_len)
+                           struct snd_pcm_substream *substream)
 {
        struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct fsi_master *master = fsi_get_master(fsi);
+       unsigned long flags;
 
+       spin_lock_irqsave(&master->lock, flags);
        io->substream   = substream;
-       io->buff_len    = buffer_len;
-       io->buff_offset = 0;
-       io->period_len  = period_len;
-       io->period_num  = 0;
+       io->buff_sample_capa    = fsi_frame2sample(fsi, runtime->buffer_size);
+       io->buff_sample_pos     = 0;
+       io->period_samples      = fsi_frame2sample(fsi, runtime->period_size);
+       io->period_pos          = 0;
        io->oerr_num    = -1; /* ignore 1st err */
        io->uerr_num    = -1; /* ignore 1st err */
+       spin_unlock_irqrestore(&master->lock, flags);
 }
 
 static void fsi_stream_pop(struct fsi_priv *fsi, int is_play)
 {
        struct fsi_stream *io = fsi_get_stream(fsi, is_play);
        struct snd_soc_dai *dai = fsi_get_dai(io->substream);
+       struct fsi_master *master = fsi_get_master(fsi);
+       unsigned long flags;
 
+       spin_lock_irqsave(&master->lock, flags);
 
        if (io->oerr_num > 0)
                dev_err(dai->dev, "over_run = %d\n", io->oerr_num);
@@ -372,47 +424,27 @@ static void fsi_stream_pop(struct fsi_priv *fsi, int is_play)
                dev_err(dai->dev, "under_run = %d\n", io->uerr_num);
 
        io->substream   = NULL;
-       io->buff_len    = 0;
-       io->buff_offset = 0;
-       io->period_len  = 0;
-       io->period_num  = 0;
+       io->buff_sample_capa    = 0;
+       io->buff_sample_pos     = 0;
+       io->period_samples      = 0;
+       io->period_pos          = 0;
        io->oerr_num    = 0;
        io->uerr_num    = 0;
+       spin_unlock_irqrestore(&master->lock, flags);
 }
 
-static int fsi_get_fifo_data_num(struct fsi_priv *fsi, int is_play)
+static int fsi_get_current_fifo_samples(struct fsi_priv *fsi, int is_play)
 {
        u32 status;
-       int data_num;
+       int frames;
 
        status = is_play ?
                fsi_reg_read(fsi, DOFF_ST) :
                fsi_reg_read(fsi, DIFF_ST);
 
-       data_num = 0x1ff & (status >> 8);
-       data_num *= fsi->chan_num;
-
-       return data_num;
-}
-
-static int fsi_len2num(int len, int width)
-{
-       return len / width;
-}
-
-#define fsi_num2offset(a, b) fsi_num2len(a, b)
-static int fsi_num2len(int num, int width)
-{
-       return num * width;
-}
-
-static int fsi_get_frame_width(struct fsi_priv *fsi, int is_play)
-{
-       struct fsi_stream *io = fsi_get_stream(fsi, is_play);
-       struct snd_pcm_substream *substream = io->substream;
-       struct snd_pcm_runtime *runtime = substream->runtime;
+       frames = 0x1ff & (status >> 8);
 
-       return frames_to_bytes(runtime, 1) / fsi->chan_num;
+       return fsi_frame2sample(fsi, frames);
 }
 
 static void fsi_count_fifo_err(struct fsi_priv *fsi)
@@ -444,8 +476,10 @@ static u8 *fsi_dma_get_area(struct fsi_priv *fsi, int stream)
 {
        int is_play = fsi_stream_is_play(stream);
        struct fsi_stream *io = fsi_get_stream(fsi, is_play);
+       struct snd_pcm_runtime *runtime = io->substream->runtime;
 
-       return io->substream->runtime->dma_area + io->buff_offset;
+       return runtime->dma_area +
+               samples_to_bytes(runtime, io->buff_sample_pos);
 }
 
 static void fsi_dma_soft_push16(struct fsi_priv *fsi, int num)
@@ -559,37 +593,94 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
 /*
  *             clock function
  */
-#define fsi_module_init(m, d)  __fsi_module_clk_ctrl(m, d, 1)
-#define fsi_module_kill(m, d)  __fsi_module_clk_ctrl(m, d, 0)
-static void __fsi_module_clk_ctrl(struct fsi_master *master,
-                                 struct device *dev,
-                                 int enable)
+static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi,
+                             long rate, int enable)
 {
-       pm_runtime_get_sync(dev);
+       struct fsi_master *master = fsi_get_master(fsi);
+       set_rate_func set_rate = fsi_get_info_set_rate(master);
+       int fsi_ver = master->core->ver;
+       int ret;
 
-       if (enable) {
-               /* enable only SR */
-               fsi_master_mask_set(master, SOFT_RST, FSISR, FSISR);
-               fsi_master_mask_set(master, SOFT_RST, PASR | PBSR, 0);
-       } else {
-               /* clear all registers */
-               fsi_master_mask_set(master, SOFT_RST, FSISR, 0);
+       ret = set_rate(dev, fsi_is_port_a(fsi), rate, enable);
+       if (ret < 0) /* error */
+               return ret;
+
+       if (!enable)
+               return 0;
+
+       if (ret > 0) {
+               u32 data = 0;
+
+               switch (ret & SH_FSI_ACKMD_MASK) {
+               default:
+                       /* FALL THROUGH */
+               case SH_FSI_ACKMD_512:
+                       data |= (0x0 << 12);
+                       break;
+               case SH_FSI_ACKMD_256:
+                       data |= (0x1 << 12);
+                       break;
+               case SH_FSI_ACKMD_128:
+                       data |= (0x2 << 12);
+                       break;
+               case SH_FSI_ACKMD_64:
+                       data |= (0x3 << 12);
+                       break;
+               case SH_FSI_ACKMD_32:
+                       if (fsi_ver < 2)
+                               dev_err(dev, "unsupported ACKMD\n");
+                       else
+                               data |= (0x4 << 12);
+                       break;
+               }
+
+               switch (ret & SH_FSI_BPFMD_MASK) {
+               default:
+                       /* FALL THROUGH */
+               case SH_FSI_BPFMD_32:
+                       data |= (0x0 << 8);
+                       break;
+               case SH_FSI_BPFMD_64:
+                       data |= (0x1 << 8);
+                       break;
+               case SH_FSI_BPFMD_128:
+                       data |= (0x2 << 8);
+                       break;
+               case SH_FSI_BPFMD_256:
+                       data |= (0x3 << 8);
+                       break;
+               case SH_FSI_BPFMD_512:
+                       data |= (0x4 << 8);
+                       break;
+               case SH_FSI_BPFMD_16:
+                       if (fsi_ver < 2)
+                               dev_err(dev, "unsupported ACKMD\n");
+                       else
+                               data |= (0x7 << 8);
+                       break;
+               }
+
+               fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data);
+               udelay(10);
+               ret = 0;
        }
 
-       pm_runtime_put_sync(dev);
+       return ret;
 }
 
-#define fsi_port_start(f)      __fsi_port_clk_ctrl(f, 1)
-#define fsi_port_stop(f)       __fsi_port_clk_ctrl(f, 0)
-static void __fsi_port_clk_ctrl(struct fsi_priv *fsi, int enable)
+#define fsi_port_start(f, i)   __fsi_port_clk_ctrl(f, i, 1)
+#define fsi_port_stop(f, i)    __fsi_port_clk_ctrl(f, i, 0)
+static void __fsi_port_clk_ctrl(struct fsi_priv *fsi, int is_play, int enable)
 {
        struct fsi_master *master = fsi_get_master(fsi);
-       u32 soft = fsi_is_port_a(fsi) ? PASR : PBSR;
        u32 clk  = fsi_is_port_a(fsi) ? CRA  : CRB;
-       int is_master = fsi_is_clk_master(fsi);
 
-       fsi_master_mask_set(master, SOFT_RST, soft, (enable) ? soft : 0);
-       if (is_master)
+       if (enable)
+               fsi_irq_enable(fsi, is_play);
+       else
+               fsi_irq_disable(fsi, is_play);
+
+       if (fsi_is_clk_master(fsi))
                fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
 }
 
@@ -598,18 +689,19 @@ static void __fsi_port_clk_ctrl(struct fsi_priv *fsi, int enable)
  */
 static void fsi_fifo_init(struct fsi_priv *fsi,
                          int is_play,
-                         struct snd_soc_dai *dai)
+                         struct device *dev)
 {
        struct fsi_master *master = fsi_get_master(fsi);
        struct fsi_stream *io = fsi_get_stream(fsi, is_play);
        u32 shift, i;
+       int frame_capa;
 
        /* get on-chip RAM capacity */
        shift = fsi_master_read(master, FIFO_SZ);
        shift >>= fsi_get_port_shift(fsi, is_play);
        shift &= FIFO_SZ_MASK;
-       io->fifo_max_num = 256 << shift;
-       dev_dbg(dai->dev, "fifo = %d words\n", io->fifo_max_num);
+       frame_capa = 256 << shift;
+       dev_dbg(dev, "fifo = %d words\n", frame_capa);
 
        /*
         * The maximum number of sample data varies depending
@@ -631,9 +723,11 @@ static void fsi_fifo_init(struct fsi_priv *fsi,
         * 8 channels:  32 ( 32 x 8 = 256)
         */
        for (i = 1; i < fsi->chan_num; i <<= 1)
-               io->fifo_max_num >>= 1;
-       dev_dbg(dai->dev, "%d channel %d store\n",
-               fsi->chan_num, io->fifo_max_num);
+               frame_capa >>= 1;
+       dev_dbg(dev, "%d channel %d store\n",
+               fsi->chan_num, frame_capa);
+
+       io->fifo_sample_capa = fsi_frame2sample(fsi, frame_capa);
 
        /*
         * set interrupt generation factor
@@ -654,10 +748,10 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream)
        struct snd_pcm_substream *substream = NULL;
        int is_play = fsi_stream_is_play(stream);
        struct fsi_stream *io = fsi_get_stream(fsi, is_play);
-       int data_residue_num;
-       int data_num;
-       int data_num_max;
-       int ch_width;
+       int sample_residues;
+       int sample_width;
+       int samples;
+       int samples_max;
        int over_period;
        void (*fn)(struct fsi_priv *fsi, int size);
 
@@ -673,36 +767,35 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream)
        /* FSI FIFO has limit.
         * So, this driver can not send periods data at a time
         */
-       if (io->buff_offset >=
-           fsi_num2offset(io->period_num + 1, io->period_len)) {
+       if (io->buff_sample_pos >=
+           io->period_samples * (io->period_pos + 1)) {
 
                over_period = 1;
-               io->period_num = (io->period_num + 1) % runtime->periods;
+               io->period_pos = (io->period_pos + 1) % runtime->periods;
 
-               if (0 == io->period_num)
-                       io->buff_offset = 0;
+               if (0 == io->period_pos)
+                       io->buff_sample_pos = 0;
        }
 
-       /* get 1 channel data width */
-       ch_width = fsi_get_frame_width(fsi, is_play);
+       /* get 1 sample data width */
+       sample_width = samples_to_bytes(runtime, 1);
 
-       /* get residue data number of alsa */
-       data_residue_num = fsi_len2num(io->buff_len - io->buff_offset,
-                                      ch_width);
+       /* get number of residue samples */
+       sample_residues = io->buff_sample_capa - io->buff_sample_pos;
 
        if (is_play) {
                /*
                 * for play-back
                 *
-                * data_num_max : number of FSI fifo free space
-                * data_num     : number of ALSA residue data
+                * samples_max  : number of FSI fifo free samples space
+                * samples      : number of ALSA residue samples
                 */
-               data_num_max  = io->fifo_max_num * fsi->chan_num;
-               data_num_max -= fsi_get_fifo_data_num(fsi, is_play);
+               samples_max  = io->fifo_sample_capa;
+               samples_max -= fsi_get_current_fifo_samples(fsi, is_play);
 
-               data_num = data_residue_num;
+               samples = sample_residues;
 
-               switch (ch_width) {
+               switch (sample_width) {
                case 2:
                        fn = fsi_dma_soft_push16;
                        break;
@@ -716,13 +809,13 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream)
                /*
                 * for capture
                 *
-                * data_num_max : number of ALSA free space
-                * data_num     : number of data in FSI fifo
+                * samples_max  : number of ALSA free samples space
+                * samples      : number of samples in FSI fifo
                 */
-               data_num_max = data_residue_num;
-               data_num     = fsi_get_fifo_data_num(fsi, is_play);
+               samples_max = sample_residues;
+               samples     = fsi_get_current_fifo_samples(fsi, is_play);
 
-               switch (ch_width) {
+               switch (sample_width) {
                case 2:
                        fn = fsi_dma_soft_pop16;
                        break;
@@ -734,12 +827,12 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream)
                }
        }
 
-       data_num = min(data_num, data_num_max);
+       samples = min(samples, samples_max);
 
-       fn(fsi, data_num);
+       fn(fsi, samples);
 
-       /* update buff_offset */
-       io->buff_offset += fsi_num2offset(data_num, ch_width);
+       /* update buff_sample_pos */
+       io->buff_sample_pos += samples;
 
        if (over_period)
                snd_pcm_period_elapsed(substream);
@@ -788,16 +881,20 @@ static irqreturn_t fsi_interrupt(int irq, void *data)
  *             dai ops
  */
 
-static int fsi_dai_startup(struct snd_pcm_substream *substream,
-                          struct snd_soc_dai *dai)
+static int fsi_hw_startup(struct fsi_priv *fsi,
+                         int is_play,
+                         struct device *dev)
 {
-       struct fsi_priv *fsi = fsi_get_priv(substream);
        u32 flags = fsi_get_info_flags(fsi);
-       u32 data;
-       int is_play = fsi_is_play(substream);
+       u32 data = 0;
 
-       pm_runtime_get_sync(dai->dev);
+       pm_runtime_get_sync(dev);
 
+       /* clock setting */
+       if (fsi_is_clk_master(fsi))
+               data = DIMD | DOMD;
+
+       fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data);
 
        /* clock inversion (CKG2) */
        data = 0;
@@ -812,54 +909,70 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
 
        fsi_reg_write(fsi, CKG2, data);
 
+       /* set format */
+       fsi_reg_write(fsi, DO_FMT, fsi->do_fmt);
+       fsi_reg_write(fsi, DI_FMT, fsi->di_fmt);
+
+       /* spdif ? */
+       if (fsi_is_spdif(fsi)) {
+               fsi_spdif_clk_ctrl(fsi, 1);
+               fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD);
+       }
+
        /* irq clear */
        fsi_irq_disable(fsi, is_play);
        fsi_irq_clear_status(fsi);
 
        /* fifo init */
-       fsi_fifo_init(fsi, is_play, dai);
+       fsi_fifo_init(fsi, is_play, dev);
 
        return 0;
 }
 
-static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
-                            struct snd_soc_dai *dai)
+static void fsi_hw_shutdown(struct fsi_priv *fsi,
+                           int is_play,
+                           struct device *dev)
+{
+       if (fsi_is_clk_master(fsi))
+               fsi_set_master_clk(dev, fsi, fsi->rate, 0);
+
+       pm_runtime_put_sync(dev);
+}
+
+static int fsi_dai_startup(struct snd_pcm_substream *substream,
+                          struct snd_soc_dai *dai)
 {
        struct fsi_priv *fsi = fsi_get_priv(substream);
        int is_play = fsi_is_play(substream);
-       struct fsi_master *master = fsi_get_master(fsi);
-       set_rate_func set_rate = fsi_get_info_set_rate(master);
 
-       fsi_irq_disable(fsi, is_play);
+       return fsi_hw_startup(fsi, is_play, dai->dev);
+}
 
-       if (fsi_is_clk_master(fsi))
-               set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0);
+static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
+                            struct snd_soc_dai *dai)
+{
+       struct fsi_priv *fsi = fsi_get_priv(substream);
+       int is_play = fsi_is_play(substream);
 
+       fsi_hw_shutdown(fsi, is_play, dai->dev);
        fsi->rate = 0;
-
-       pm_runtime_put_sync(dai->dev);
 }
 
 static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
                           struct snd_soc_dai *dai)
 {
        struct fsi_priv *fsi = fsi_get_priv(substream);
-       struct snd_pcm_runtime *runtime = substream->runtime;
        int is_play = fsi_is_play(substream);
        int ret = 0;
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-               fsi_stream_push(fsi, is_play, substream,
-                               frames_to_bytes(runtime, runtime->buffer_size),
-                               frames_to_bytes(runtime, runtime->period_size));
+               fsi_stream_push(fsi, is_play, substream);
                ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi);
-               fsi_irq_enable(fsi, is_play);
-               fsi_port_start(fsi);
+               fsi_port_start(fsi, is_play);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
-               fsi_port_stop(fsi);
-               fsi_irq_disable(fsi, is_play);
+               fsi_port_stop(fsi, is_play);
                fsi_stream_pop(fsi, is_play);
                break;
        }
@@ -884,8 +997,8 @@ static int fsi_set_fmt_dai(struct fsi_priv *fsi, unsigned int fmt)
                return -EINVAL;
        }
 
-       fsi_reg_write(fsi, DO_FMT, data);
-       fsi_reg_write(fsi, DI_FMT, data);
+       fsi->do_fmt = data;
+       fsi->di_fmt = data;
 
        return 0;
 }
@@ -900,11 +1013,10 @@ static int fsi_set_fmt_spdif(struct fsi_priv *fsi)
 
        data = CR_BWS_16 | CR_DTMD_SPDIF_PCM | CR_PCM;
        fsi->chan_num = 2;
-       fsi_spdif_clk_ctrl(fsi, 1);
-       fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD);
+       fsi->spdif = 1;
 
-       fsi_reg_write(fsi, DO_FMT, data);
-       fsi_reg_write(fsi, DI_FMT, data);
+       fsi->do_fmt = data;
+       fsi->di_fmt = data;
 
        return 0;
 }
@@ -915,32 +1027,24 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        struct fsi_master *master = fsi_get_master(fsi);
        set_rate_func set_rate = fsi_get_info_set_rate(master);
        u32 flags = fsi_get_info_flags(fsi);
-       u32 data = 0;
        int ret;
 
-       pm_runtime_get_sync(dai->dev);
-
        /* set master/slave audio interface */
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBM_CFM:
-               data = DIMD | DOMD;
                fsi->clk_master = 1;
                break;
        case SND_SOC_DAIFMT_CBS_CFS:
                break;
        default:
-               ret = -EINVAL;
-               goto set_fmt_exit;
+               return -EINVAL;
        }
 
        if (fsi_is_clk_master(fsi) && !set_rate) {
                dev_err(dai->dev, "platform doesn't have set_rate\n");
-               ret = -EINVAL;
-               goto set_fmt_exit;
+               return -EINVAL;
        }
 
-       fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data);
-
        /* set format */
        switch (flags & SH_FSI_FMT_MASK) {
        case SH_FSI_FMT_DAI:
@@ -953,9 +1057,6 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                ret = -EINVAL;
        }
 
-set_fmt_exit:
-       pm_runtime_put_sync(dai->dev);
-
        return ret;
 }
 
@@ -964,79 +1065,19 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
        struct fsi_priv *fsi = fsi_get_priv(substream);
-       struct fsi_master *master = fsi_get_master(fsi);
-       set_rate_func set_rate = fsi_get_info_set_rate(master);
-       int fsi_ver = master->core->ver;
        long rate = params_rate(params);
        int ret;
 
        if (!fsi_is_clk_master(fsi))
                return 0;
 
-       ret = set_rate(dai->dev, fsi_is_port_a(fsi), rate, 1);
-       if (ret < 0) /* error */
+       ret = fsi_set_master_clk(dai->dev, fsi, rate, 1);
+       if (ret < 0)
                return ret;
 
        fsi->rate = rate;
-       if (ret > 0) {
-               u32 data = 0;
-
-               switch (ret & SH_FSI_ACKMD_MASK) {
-               default:
-                       /* FALL THROUGH */
-               case SH_FSI_ACKMD_512:
-                       data |= (0x0 << 12);
-                       break;
-               case SH_FSI_ACKMD_256:
-                       data |= (0x1 << 12);
-                       break;
-               case SH_FSI_ACKMD_128:
-                       data |= (0x2 << 12);
-                       break;
-               case SH_FSI_ACKMD_64:
-                       data |= (0x3 << 12);
-                       break;
-               case SH_FSI_ACKMD_32:
-                       if (fsi_ver < 2)
-                               dev_err(dai->dev, "unsupported ACKMD\n");
-                       else
-                               data |= (0x4 << 12);
-                       break;
-               }
-
-               switch (ret & SH_FSI_BPFMD_MASK) {
-               default:
-                       /* FALL THROUGH */
-               case SH_FSI_BPFMD_32:
-                       data |= (0x0 << 8);
-                       break;
-               case SH_FSI_BPFMD_64:
-                       data |= (0x1 << 8);
-                       break;
-               case SH_FSI_BPFMD_128:
-                       data |= (0x2 << 8);
-                       break;
-               case SH_FSI_BPFMD_256:
-                       data |= (0x3 << 8);
-                       break;
-               case SH_FSI_BPFMD_512:
-                       data |= (0x4 << 8);
-                       break;
-               case SH_FSI_BPFMD_16:
-                       if (fsi_ver < 2)
-                               dev_err(dai->dev, "unsupported ACKMD\n");
-                       else
-                               data |= (0x7 << 8);
-                       break;
-               }
-
-               fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data);
-               udelay(10);
-               ret = 0;
-       }
 
        return ret;
-
 }
 
 static struct snd_soc_dai_ops fsi_dai_ops = {
@@ -1097,16 +1138,14 @@ static int fsi_hw_free(struct snd_pcm_substream *substream)
 
 static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream)
 {
-       struct snd_pcm_runtime *runtime = substream->runtime;
        struct fsi_priv *fsi = fsi_get_priv(substream);
        struct fsi_stream *io = fsi_get_stream(fsi, fsi_is_play(substream));
-       long location;
+       int samples_pos = io->buff_sample_pos - 1;
 
-       location = (io->buff_offset - 1);
-       if (location < 0)
-               location = 0;
+       if (samples_pos < 0)
+               samples_pos = 0;
 
-       return bytes_to_frames(runtime, location);
+       return fsi_sample2frame(fsi, samples_pos);
 }
 
 static struct snd_pcm_ops fsi_pcm_ops = {
@@ -1246,8 +1285,6 @@ static int fsi_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
        dev_set_drvdata(&pdev->dev, master);
 
-       fsi_module_init(master, &pdev->dev);
-
        ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED,
                          id_entry->name, master);
        if (ret) {
@@ -1290,8 +1327,6 @@ static int fsi_remove(struct platform_device *pdev)
 
        master = dev_get_drvdata(&pdev->dev);
 
-       fsi_module_kill(master, &pdev->dev);
-
        free_irq(master->irq, master);
        pm_runtime_disable(&pdev->dev);
 
@@ -1305,53 +1340,43 @@ static int fsi_remove(struct platform_device *pdev)
 }
 
 static void __fsi_suspend(struct fsi_priv *fsi,
-                         struct device *dev,
-                         set_rate_func set_rate)
+                         int is_play,
+                         struct device *dev)
 {
-       fsi->saved_do_fmt       = fsi_reg_read(fsi, DO_FMT);
-       fsi->saved_di_fmt       = fsi_reg_read(fsi, DI_FMT);
-       fsi->saved_ckg1         = fsi_reg_read(fsi, CKG1);
-       fsi->saved_ckg2         = fsi_reg_read(fsi, CKG2);
-       fsi->saved_out_sel      = fsi_reg_read(fsi, OUT_SEL);
+       if (!fsi_stream_is_working(fsi, is_play))
+               return;
 
-       if (fsi_is_clk_master(fsi))
-               set_rate(dev, fsi_is_port_a(fsi), fsi->rate, 0);
+       fsi_port_stop(fsi, is_play);
+       fsi_hw_shutdown(fsi, is_play, dev);
 }
 
 static void __fsi_resume(struct fsi_priv *fsi,
-                        struct device *dev,
-                        set_rate_func set_rate)
+                        int is_play,
+                        struct device *dev)
 {
-       fsi_reg_write(fsi, DO_FMT,      fsi->saved_do_fmt);
-       fsi_reg_write(fsi, DI_FMT,      fsi->saved_di_fmt);
-       fsi_reg_write(fsi, CKG1,        fsi->saved_ckg1);
-       fsi_reg_write(fsi, CKG2,        fsi->saved_ckg2);
-       fsi_reg_write(fsi, OUT_SEL,     fsi->saved_out_sel);
+       if (!fsi_stream_is_working(fsi, is_play))
+               return;
+
+       fsi_hw_startup(fsi, is_play, dev);
+
+       if (fsi_is_clk_master(fsi) && fsi->rate)
+               fsi_set_master_clk(dev, fsi, fsi->rate, 1);
+
+       fsi_port_start(fsi, is_play);
 
-       if (fsi_is_clk_master(fsi))
-               set_rate(dev, fsi_is_port_a(fsi), fsi->rate, 1);
 }
 
 static int fsi_suspend(struct device *dev)
 {
        struct fsi_master *master = dev_get_drvdata(dev);
-       set_rate_func set_rate = fsi_get_info_set_rate(master);
-
-       pm_runtime_get_sync(dev);
-
-       __fsi_suspend(&master->fsia, dev, set_rate);
-       __fsi_suspend(&master->fsib, dev, set_rate);
+       struct fsi_priv *fsia = &master->fsia;
+       struct fsi_priv *fsib = &master->fsib;
 
-       master->saved_a_mclk    = fsi_core_read(master, a_mclk);
-       master->saved_b_mclk    = fsi_core_read(master, b_mclk);
-       master->saved_iemsk     = fsi_core_read(master, iemsk);
-       master->saved_imsk      = fsi_core_read(master, imsk);
-       master->saved_clk_rst   = fsi_master_read(master, CLK_RST);
-       master->saved_soft_rst  = fsi_master_read(master, SOFT_RST);
+       __fsi_suspend(fsia, 1, dev);
+       __fsi_suspend(fsia, 0, dev);
 
-       fsi_module_kill(master, dev);
-
-       pm_runtime_put_sync(dev);
+       __fsi_suspend(fsib, 1, dev);
+       __fsi_suspend(fsib, 0, dev);
 
        return 0;
 }
@@ -1359,23 +1384,14 @@ static int fsi_suspend(struct device *dev)
 static int fsi_resume(struct device *dev)
 {
        struct fsi_master *master = dev_get_drvdata(dev);
-       set_rate_func set_rate = fsi_get_info_set_rate(master);
-
-       pm_runtime_get_sync(dev);
-
-       fsi_module_init(master, dev);
+       struct fsi_priv *fsia = &master->fsia;
+       struct fsi_priv *fsib = &master->fsib;
 
-       fsi_master_mask_set(master, SOFT_RST, 0xffff, master->saved_soft_rst);
-       fsi_master_mask_set(master, CLK_RST, 0xffff, master->saved_clk_rst);
-       fsi_core_mask_set(master, a_mclk, 0xffff, master->saved_a_mclk);
-       fsi_core_mask_set(master, b_mclk, 0xffff, master->saved_b_mclk);
-       fsi_core_mask_set(master, iemsk, 0xffff, master->saved_iemsk);
-       fsi_core_mask_set(master, imsk, 0xffff, master->saved_imsk);
+       __fsi_resume(fsia, 1, dev);
+       __fsi_resume(fsia, 0, dev);
 
-       __fsi_resume(&master->fsia, dev, set_rate);
-       __fsi_resume(&master->fsib, dev, set_rate);
-
-       pm_runtime_put_sync(dev);
+       __fsi_resume(fsib, 1, dev);
+       __fsi_resume(fsib, 0, dev);
 
        return 0;
 }
index 06b7b81..d8ce34c 100644 (file)
@@ -107,12 +107,11 @@ static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec,
 static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg,
                             unsigned int value)
 {
-       u8 data[2];
+       u16 data;
 
-       data[0] = (reg << 1) | ((value >> 8) & 0x0001);
-       data[1] = value & 0x00ff;
+       data = cpu_to_be16((reg << 9) | (value & 0x1ff));
 
-       return do_hw_write(codec, reg, value, data, 2);
+       return do_hw_write(codec, reg, value, &data, 2);
 }
 
 static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg,
@@ -137,10 +136,10 @@ static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg,
                              unsigned int value)
 {
        u8 data[3];
+       u16 val = cpu_to_be16(value);
 
        data[0] = reg;
-       data[1] = (value >> 8) & 0xff;
-       data[2] = value & 0xff;
+       memcpy(&data[1], &val, sizeof(val));
 
        return do_hw_write(codec, reg, value, data, 3);
 }
@@ -243,9 +242,9 @@ static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
                              unsigned int value)
 {
        u8 data[3];
+       u16 rval = cpu_to_be16(reg);
 
-       data[0] = (reg >> 8) & 0xff;
-       data[1] = reg & 0xff;
+       memcpy(data, &rval, sizeof(rval));
        data[2] = value;
 
        return do_hw_write(codec, reg, value, data, 3);
@@ -277,14 +276,12 @@ static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec,
 static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg,
                               unsigned int value)
 {
-       u8 data[4];
+       u16 data[2];
 
-       data[0] = (reg >> 8) & 0xff;
-       data[1] = reg & 0xff;
-       data[2] = (value >> 8) & 0xff;
-       data[3] = value & 0xff;
+       data[0] = cpu_to_be16(reg);
+       data[1] = cpu_to_be16(value);
 
-       return do_hw_write(codec, reg, value, data, 4);
+       return do_hw_write(codec, reg, value, data, sizeof(data));
 }
 
 /* Primitive bulk write support for soc-cache.  The data pointed to by
@@ -483,31 +480,86 @@ static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,
 }
 
 struct snd_soc_rbtree_node {
-       struct rb_node node;
-       unsigned int reg;
-       unsigned int value;
-       unsigned int defval;
+       struct rb_node node; /* the actual rbtree node holding this block */
+       unsigned int base_reg; /* base register handled by this block */
+       unsigned int word_size; /* number of bytes needed to represent the register index */
+       void *block; /* block of adjacent registers */
+       unsigned int blklen; /* number of registers available in the block */
 } __attribute__ ((packed));
 
 struct snd_soc_rbtree_ctx {
        struct rb_root root;
+       struct snd_soc_rbtree_node *cached_rbnode;
 };
 
+static inline void snd_soc_rbtree_get_base_top_reg(
+       struct snd_soc_rbtree_node *rbnode,
+       unsigned int *base, unsigned int *top)
+{
+       *base = rbnode->base_reg;
+       *top = rbnode->base_reg + rbnode->blklen - 1;
+}
+
+static unsigned int snd_soc_rbtree_get_register(
+       struct snd_soc_rbtree_node *rbnode, unsigned int idx)
+{
+       unsigned int val;
+
+       switch (rbnode->word_size) {
+       case 1: {
+               u8 *p = rbnode->block;
+               val = p[idx];
+               return val;
+       }
+       case 2: {
+               u16 *p = rbnode->block;
+               val = p[idx];
+               return val;
+       }
+       default:
+               BUG();
+               break;
+       }
+       return -1;
+}
+
+static void snd_soc_rbtree_set_register(struct snd_soc_rbtree_node *rbnode,
+                                       unsigned int idx, unsigned int val)
+{
+       switch (rbnode->word_size) {
+       case 1: {
+               u8 *p = rbnode->block;
+               p[idx] = val;
+               break;
+       }
+       case 2: {
+               u16 *p = rbnode->block;
+               p[idx] = val;
+               break;
+       }
+       default:
+               BUG();
+               break;
+       }
+}
+
 static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup(
        struct rb_root *root, unsigned int reg)
 {
        struct rb_node *node;
        struct snd_soc_rbtree_node *rbnode;
+       unsigned int base_reg, top_reg;
 
        node = root->rb_node;
        while (node) {
                rbnode = container_of(node, struct snd_soc_rbtree_node, node);
-               if (rbnode->reg < reg)
-                       node = node->rb_left;
-               else if (rbnode->reg > reg)
-                       node = node->rb_right;
-               else
+               snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
+               if (reg >= base_reg && reg <= top_reg)
                        return rbnode;
+               else if (reg > top_reg)
+                       node = node->rb_right;
+               else if (reg < base_reg)
+                       node = node->rb_left;
        }
 
        return NULL;
@@ -518,19 +570,28 @@ static int snd_soc_rbtree_insert(struct rb_root *root,
 {
        struct rb_node **new, *parent;
        struct snd_soc_rbtree_node *rbnode_tmp;
+       unsigned int base_reg_tmp, top_reg_tmp;
+       unsigned int base_reg;
 
        parent = NULL;
        new = &root->rb_node;
        while (*new) {
                rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node,
                                          node);
+               /* base and top registers of the current rbnode */
+               snd_soc_rbtree_get_base_top_reg(rbnode_tmp, &base_reg_tmp,
+                                               &top_reg_tmp);
+               /* base register of the rbnode to be added */
+               base_reg = rbnode->base_reg;
                parent = *new;
-               if (rbnode_tmp->reg < rbnode->reg)
-                       new = &((*new)->rb_left);
-               else if (rbnode_tmp->reg > rbnode->reg)
-                       new = &((*new)->rb_right);
-               else
+               /* if this register has already been inserted, just return */
+               if (base_reg >= base_reg_tmp &&
+                   base_reg <= top_reg_tmp)
                        return 0;
+               else if (base_reg > top_reg_tmp)
+                       new = &((*new)->rb_right);
+               else if (base_reg < base_reg_tmp)
+                       new = &((*new)->rb_left);
        }
 
        /* insert the node into the rbtree */
@@ -545,58 +606,141 @@ static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec)
        struct snd_soc_rbtree_ctx *rbtree_ctx;
        struct rb_node *node;
        struct snd_soc_rbtree_node *rbnode;
+       unsigned int regtmp;
        unsigned int val;
        int ret;
+       int i;
 
        rbtree_ctx = codec->reg_cache;
        for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) {
                rbnode = rb_entry(node, struct snd_soc_rbtree_node, node);
-               if (rbnode->value == rbnode->defval)
-                       continue;
-               WARN_ON(codec->writable_register &&
-                       codec->writable_register(codec, rbnode->reg));
-               ret = snd_soc_cache_read(codec, rbnode->reg, &val);
-               if (ret)
-                       return ret;
-               codec->cache_bypass = 1;
-               ret = snd_soc_write(codec, rbnode->reg, val);
-               codec->cache_bypass = 0;
-               if (ret)
-                       return ret;
-               dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
-                       rbnode->reg, val);
+               for (i = 0; i < rbnode->blklen; ++i) {
+                       regtmp = rbnode->base_reg + i;
+                       WARN_ON(codec->writable_register &&
+                               codec->writable_register(codec, regtmp));
+                       val = snd_soc_rbtree_get_register(rbnode, i);
+                       codec->cache_bypass = 1;
+                       ret = snd_soc_write(codec, regtmp, val);
+                       codec->cache_bypass = 0;
+                       if (ret)
+                               return ret;
+                       dev_dbg(codec->dev, "Synced register %#x, value = %#x\n",
+                               regtmp, val);
+               }
        }
 
        return 0;
 }
 
+static int snd_soc_rbtree_insert_to_block(struct snd_soc_rbtree_node *rbnode,
+                                         unsigned int pos, unsigned int reg,
+                                         unsigned int value)
+{
+       u8 *blk;
+
+       blk = krealloc(rbnode->block,
+                      (rbnode->blklen + 1) * rbnode->word_size, GFP_KERNEL);
+       if (!blk)
+               return -ENOMEM;
+
+       /* insert the register value in the correct place in the rbnode block */
+       memmove(blk + (pos + 1) * rbnode->word_size,
+               blk + pos * rbnode->word_size,
+               (rbnode->blklen - pos) * rbnode->word_size);
+
+       /* update the rbnode block, its size and the base register */
+       rbnode->block = blk;
+       rbnode->blklen++;
+       if (!pos)
+               rbnode->base_reg = reg;
+
+       snd_soc_rbtree_set_register(rbnode, pos, value);
+       return 0;
+}
+
 static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec,
                                      unsigned int reg, unsigned int value)
 {
        struct snd_soc_rbtree_ctx *rbtree_ctx;
-       struct snd_soc_rbtree_node *rbnode;
+       struct snd_soc_rbtree_node *rbnode, *rbnode_tmp;
+       struct rb_node *node;
+       unsigned int val;
+       unsigned int reg_tmp;
+       unsigned int base_reg, top_reg;
+       unsigned int pos;
+       int i;
+       int ret;
 
        rbtree_ctx = codec->reg_cache;
+       /* look up the required register in the cached rbnode */
+       rbnode = rbtree_ctx->cached_rbnode;
+       if (rbnode) {
+               snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
+               if (reg >= base_reg && reg <= top_reg) {
+                       reg_tmp = reg - base_reg;
+                       val = snd_soc_rbtree_get_register(rbnode, reg_tmp);
+                       if (val == value)
+                               return 0;
+                       snd_soc_rbtree_set_register(rbnode, reg_tmp, value);
+                       return 0;
+               }
+       }
+       /* if we can't locate it in the cached rbnode we'll have
+        * to traverse the rbtree looking for it.
+        */
        rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
        if (rbnode) {
-               if (rbnode->value == value)
+               reg_tmp = reg - rbnode->base_reg;
+               val = snd_soc_rbtree_get_register(rbnode, reg_tmp);
+               if (val == value)
                        return 0;
-               rbnode->value = value;
+               snd_soc_rbtree_set_register(rbnode, reg_tmp, value);
+               rbtree_ctx->cached_rbnode = rbnode;
        } else {
                /* bail out early, no need to create the rbnode yet */
                if (!value)
                        return 0;
-               /*
-                * for uninitialized registers whose value is changed
-                * from the default zero, create an rbnode and insert
-                * it into the tree.
+               /* look for an adjacent register to the one we are about to add */
+               for (node = rb_first(&rbtree_ctx->root); node;
+                    node = rb_next(node)) {
+                       rbnode_tmp = rb_entry(node, struct snd_soc_rbtree_node, node);
+                       for (i = 0; i < rbnode_tmp->blklen; ++i) {
+                               reg_tmp = rbnode_tmp->base_reg + i;
+                               if (abs(reg_tmp - reg) != 1)
+                                       continue;
+                               /* decide where in the block to place our register */
+                               if (reg_tmp + 1 == reg)
+                                       pos = i + 1;
+                               else
+                                       pos = i;
+                               ret = snd_soc_rbtree_insert_to_block(rbnode_tmp, pos,
+                                                                    reg, value);
+                               if (ret)
+                                       return ret;
+                               rbtree_ctx->cached_rbnode = rbnode_tmp;
+                               return 0;
+                       }
+               }
+               /* we did not manage to find a place to insert it in an existing
+                * block so create a new rbnode with a single register in its block.
+                * This block will get populated further if any other adjacent
+                * registers get modified in the future.
                 */
                rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
                if (!rbnode)
                        return -ENOMEM;
-               rbnode->reg = reg;
-               rbnode->value = value;
+               rbnode->blklen = 1;
+               rbnode->base_reg = reg;
+               rbnode->word_size = codec->driver->reg_word_size;
+               rbnode->block = kmalloc(rbnode->blklen * rbnode->word_size,
+                                       GFP_KERNEL);
+               if (!rbnode->block) {
+                       kfree(rbnode);
+                       return -ENOMEM;
+               }
+               snd_soc_rbtree_set_register(rbnode, 0, value);
                snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode);
+               rbtree_ctx->cached_rbnode = rbnode;
        }
 
        return 0;
@@ -607,11 +751,28 @@ static int snd_soc_rbtree_cache_read(struct snd_soc_codec *codec,
 {
        struct snd_soc_rbtree_ctx *rbtree_ctx;
        struct snd_soc_rbtree_node *rbnode;
+       unsigned int base_reg, top_reg;
+       unsigned int reg_tmp;
 
        rbtree_ctx = codec->reg_cache;
+       /* look up the required register in the cached rbnode */
+       rbnode = rbtree_ctx->cached_rbnode;
+       if (rbnode) {
+               snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg);
+               if (reg >= base_reg && reg <= top_reg) {
+                       reg_tmp = reg - base_reg;
+                       *value = snd_soc_rbtree_get_register(rbnode, reg_tmp);
+                       return 0;
+               }
+       }
+       /* if we can't locate it in the cached rbnode we'll have
+        * to traverse the rbtree looking for it.
+        */
        rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg);
        if (rbnode) {
-               *value = rbnode->value;
+               reg_tmp = reg - rbnode->base_reg;
+               *value = snd_soc_rbtree_get_register(rbnode, reg_tmp);
+               rbtree_ctx->cached_rbnode = rbnode;
        } else {
                /* uninitialized registers default to 0 */
                *value = 0;
@@ -637,6 +798,7 @@ static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec)
                rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node);
                next = rb_next(&rbtree_node->node);
                rb_erase(&rbtree_node->node, &rbtree_ctx->root);
+               kfree(rbtree_node->block);
                kfree(rbtree_node);
        }
 
@@ -649,10 +811,9 @@ static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec)
 
 static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
 {
-       struct snd_soc_rbtree_node *rbtree_node;
        struct snd_soc_rbtree_ctx *rbtree_ctx;
-       unsigned int val;
        unsigned int word_size;
+       unsigned int val;
        int i;
        int ret;
 
@@ -662,32 +823,27 @@ static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec)
 
        rbtree_ctx = codec->reg_cache;
        rbtree_ctx->root = RB_ROOT;
+       rbtree_ctx->cached_rbnode = NULL;
 
        if (!codec->reg_def_copy)
                return 0;
 
-       /*
-        * populate the rbtree with the initialized registers.  All other
-        * registers will be inserted when they are first modified.
-        */
        word_size = codec->driver->reg_word_size;
        for (i = 0; i < codec->driver->reg_cache_size; ++i) {
-               val = snd_soc_get_cache_val(codec->reg_def_copy, i, word_size);
+               val = snd_soc_get_cache_val(codec->reg_def_copy, i,
+                                           word_size);
                if (!val)
                        continue;
-               rbtree_node = kzalloc(sizeof *rbtree_node, GFP_KERNEL);
-               if (!rbtree_node) {
-                       ret = -ENOMEM;
-                       snd_soc_cache_exit(codec);
-                       break;
-               }
-               rbtree_node->reg = i;
-               rbtree_node->value = val;
-               rbtree_node->defval = val;
-               snd_soc_rbtree_insert(&rbtree_ctx->root, rbtree_node);
+               ret = snd_soc_rbtree_cache_write(codec, i, val);
+               if (ret)
+                       goto err;
        }
 
        return 0;
+
+err:
+       snd_soc_cache_exit(codec);
+       return ret;
 }
 
 #ifdef CONFIG_SND_SOC_CACHE_LZO
index d75043e..13a40fc 100644 (file)
@@ -1256,7 +1256,7 @@ static void soc_resume_deferred(struct work_struct *work)
 int snd_soc_resume(struct device *dev)
 {
        struct snd_soc_card *card = dev_get_drvdata(dev);
-       int i;
+       int i, ac97_control = 0;
 
        /* AC97 devices might have other drivers hanging off them so
         * need to resume immediately.  Other drivers don't have that
@@ -1265,14 +1265,15 @@ int snd_soc_resume(struct device *dev)
         */
        for (i = 0; i < card->num_rtd; i++) {
                struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
-               if (cpu_dai->driver->ac97_control) {
-                       dev_dbg(dev, "Resuming AC97 immediately\n");
-                       soc_resume_deferred(&card->deferred_resume_work);
-               } else {
-                       dev_dbg(dev, "Scheduling resume work\n");
-                       if (!schedule_work(&card->deferred_resume_work))
-                               dev_err(dev, "resume work item may be lost\n");
-               }
+               ac97_control |= cpu_dai->driver->ac97_control;
+       }
+       if (ac97_control) {
+               dev_dbg(dev, "Resuming AC97 immediately\n");
+               soc_resume_deferred(&card->deferred_resume_work);
+       } else {
+               dev_dbg(dev, "Scheduling resume work\n");
+               if (!schedule_work(&card->deferred_resume_work))
+                       dev_err(dev, "resume work item may be lost\n");
        }
 
        return 0;
index 0d6738a..a42e9ac 100644 (file)
@@ -267,7 +267,7 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
                }
                machine->gpio_requested |= GPIO_HP_MUTE;
 
-               gpio_direction_output(pdata->gpio_hp_mute, 0);
+               gpio_direction_output(pdata->gpio_hp_mute, 1);
        }
 
        if (gpio_is_valid(pdata->gpio_int_mic_en)) {