Merge remote-tracking branch 'asoc/topic/mxs' into asoc-next
authorMark Brown <broonie@linaro.org>
Fri, 8 Nov 2013 10:43:32 +0000 (10:43 +0000)
committerMark Brown <broonie@linaro.org>
Fri, 8 Nov 2013 10:43:32 +0000 (10:43 +0000)
include/sound/soc-dai.h
sound/soc/mxs/mxs-saif.c
sound/soc/mxs/mxs-saif.h
sound/soc/mxs/mxs-sgtl5000.c

index b0ee6590b8baa25de6d85af8caeb097190adb0d5..800c101bb096fd6f5c1170ebbdce1ab06cead062 100644 (file)
@@ -169,6 +169,13 @@ struct snd_soc_dai_ops {
                struct snd_soc_dai *);
        int (*prepare)(struct snd_pcm_substream *,
                struct snd_soc_dai *);
+       /*
+        * NOTE: Commands passed to the trigger function are not necessarily
+        * compatible with the current state of the dai. For example this
+        * sequence of commands is possible: START STOP STOP.
+        * So do not unconditionally use refcounting functions in the trigger
+        * function, e.g. clk_enable/disable.
+        */
        int (*trigger)(struct snd_pcm_substream *, int,
                struct snd_soc_dai *);
        int (*bespoke_trigger)(struct snd_pcm_substream *, int,
index 14152f6f70ddccaada89a26176c6b9437e814b06..54e622acac330d82a92d95164ae79e89cfb461e4 100644 (file)
@@ -494,6 +494,7 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
        struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
        struct mxs_saif *master_saif;
        u32 delay;
+       int ret;
 
        master_saif = mxs_saif_get_master(saif);
        if (!master_saif)
@@ -503,23 +504,37 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (saif->state == MXS_SAIF_STATE_RUNNING)
+                       return 0;
+
                dev_dbg(cpu_dai->dev, "start\n");
 
-               clk_enable(master_saif->clk);
-               if (!master_saif->mclk_in_use)
-                       __raw_writel(BM_SAIF_CTRL_RUN,
-                               master_saif->base + SAIF_CTRL + MXS_SET_ADDR);
+               ret = clk_enable(master_saif->clk);
+               if (ret) {
+                       dev_err(saif->dev, "Failed to enable master clock\n");
+                       return ret;
+               }
 
                /*
                 * If the saif's master is not himself, we also need to enable
                 * itself clk for its internal basic logic to work.
                 */
                if (saif != master_saif) {
-                       clk_enable(saif->clk);
+                       ret = clk_enable(saif->clk);
+                       if (ret) {
+                               dev_err(saif->dev, "Failed to enable master clock\n");
+                               clk_disable(master_saif->clk);
+                               return ret;
+                       }
+
                        __raw_writel(BM_SAIF_CTRL_RUN,
                                saif->base + SAIF_CTRL + MXS_SET_ADDR);
                }
 
+               if (!master_saif->mclk_in_use)
+                       __raw_writel(BM_SAIF_CTRL_RUN,
+                               master_saif->base + SAIF_CTRL + MXS_SET_ADDR);
+
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                        /*
                         * write data to saif data register to trigger
@@ -543,6 +558,7 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
                }
 
                master_saif->ongoing = 1;
+               saif->state = MXS_SAIF_STATE_RUNNING;
 
                dev_dbg(saif->dev, "CTRL 0x%x STAT 0x%x\n",
                        __raw_readl(saif->base + SAIF_CTRL),
@@ -555,6 +571,9 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (saif->state == MXS_SAIF_STATE_STOPPED)
+                       return 0;
+
                dev_dbg(cpu_dai->dev, "stop\n");
 
                /* wait a while for the current sample to complete */
@@ -575,6 +594,7 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
                }
 
                master_saif->ongoing = 0;
+               saif->state = MXS_SAIF_STATE_STOPPED;
 
                break;
        default:
index 53eaa4bf0e2726b04c593d9c083895aece2becd6..fbaf7badfdfb03b7d26eb84fd5c1be5850d06d1a 100644 (file)
@@ -124,6 +124,11 @@ struct mxs_saif {
 
        u32 fifo_underrun;
        u32 fifo_overrun;
+
+       enum {
+               MXS_SAIF_STATE_STOPPED,
+               MXS_SAIF_STATE_RUNNING,
+       } state;
 };
 
 extern int mxs_saif_put_mclk(unsigned int saif_id);
index 4bb273786ff336aef16c08122915520f69467ef6..61822cc53bd3e9b53b63042dd6ea986b681a7d1b 100644 (file)
@@ -122,14 +122,12 @@ static struct snd_soc_card mxs_sgtl5000 = {
        .num_links      = ARRAY_SIZE(mxs_sgtl5000_dai),
 };
 
-static int mxs_sgtl5000_probe_dt(struct platform_device *pdev)
+static int mxs_sgtl5000_probe(struct platform_device *pdev)
 {
+       struct snd_soc_card *card = &mxs_sgtl5000;
+       int ret, i;
        struct device_node *np = pdev->dev.of_node;
        struct device_node *saif_np[2], *codec_np;
-       int i;
-
-       if (!np)
-               return 1; /* no device tree */
 
        saif_np[0] = of_parse_phandle(np, "saif-controllers", 0);
        saif_np[1] = of_parse_phandle(np, "saif-controllers", 1);
@@ -152,18 +150,6 @@ static int mxs_sgtl5000_probe_dt(struct platform_device *pdev)
        of_node_put(saif_np[0]);
        of_node_put(saif_np[1]);
 
-       return 0;
-}
-
-static int mxs_sgtl5000_probe(struct platform_device *pdev)
-{
-       struct snd_soc_card *card = &mxs_sgtl5000;
-       int ret;
-
-       ret = mxs_sgtl5000_probe_dt(pdev);
-       if (ret < 0)
-               return ret;
-
        /*
         * Set an init clock(11.28Mhz) for sgtl5000 initialization(i2c r/w).
         * The Sgtl5000 sysclk is derived from saif0 mclk and it's range