Merge remote-tracking branches 'asoc/topic/fsl-easi', 'asoc/topic/fsl-sai', 'asoc...
authorMark Brown <broonie@kernel.org>
Mon, 6 Oct 2014 11:48:59 +0000 (12:48 +0100)
committerMark Brown <broonie@kernel.org>
Mon, 6 Oct 2014 11:48:59 +0000 (12:48 +0100)
13 files changed:
Documentation/devicetree/bindings/sound/fsl,ssi.txt
Documentation/devicetree/bindings/sound/fsl-sai.txt
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5640.h
sound/soc/fsl/fsl_sai.c
sound/soc/fsl/fsl_sai.h
sound/soc/fsl/fsl_ssi.c
sound/soc/intel/byt-max98090.c
sound/soc/intel/byt-rt5640.c
sound/soc/intel/sst-atom-controls.c
sound/soc/intel/sst-atom-controls.h
sound/soc/intel/sst-mfld-platform-pcm.c
sound/soc/intel/sst-mfld-platform.h

index 3aa4a8f528f486b1b647e3720adbfef6068bbf6c..5b76be45d18bfecce403bf4b1f09730bb74a3c0c 100644 (file)
@@ -58,13 +58,7 @@ Optional properties:
                    Documentation/devicetree/bindings/dma/dma.txt.
 - dma-names:       Two dmas have to be defined, "tx" and "rx", if fsl,imx-fiq
                    is not defined.
-- fsl,mode:         The operating mode for the SSI interface.
-                    "i2s-slave" - I2S mode, SSI is clock slave
-                    "i2s-master" - I2S mode, SSI is clock master
-                    "lj-slave" - left-justified mode, SSI is clock slave
-                    "lj-master" - l.j. mode, SSI is clock master
-                    "rj-slave" - right-justified mode, SSI is clock slave
-                    "rj-master" - r.j., SSI is clock master
+- fsl,mode:         The operating mode for the AC97 interface only.
                     "ac97-slave" - AC97 mode, SSI is clock slave
                     "ac97-master" - AC97 mode, SSI is clock master
 
index 5f239b8bcdddffa81a7f274a8f973c1b80dd6672..4956b14d4b06175a1d9ba5df9cdb9f72b0813ec5 100644 (file)
@@ -20,9 +20,24 @@ Required properties:
   See ../pinctrl/pinctrl-bindings.txt for details of the property values.
 - big-endian: Boolean property, required if all the FTM_PWM registers
   are big-endian rather than little-endian.
-- big-endian-data: If this property is absent, the little endian mode will
-  be in use as default, or the big endian mode will be in use for all the
-  fifo data.
+- lsb-first: Configures whether the LSB or the MSB is transmitted first for
+  the fifo data. If this property is absent, the MSB is transmitted first as
+  default, or the LSB is transmitted first.
+- fsl,sai-synchronous-rx: This is a boolean property. If present, indicating
+  that SAI will work in the synchronous mode (sync Tx with Rx) which means
+  both the transimitter and receiver will send and receive data by following
+  receiver's bit clocks and frame sync clocks.
+- fsl,sai-asynchronous: This is a boolean property. If present, indicating
+  that SAI will work in the asynchronous mode, which means both transimitter
+  and receiver will send and receive data by following their own bit clocks
+  and frame sync clocks separately.
+
+Note:
+- If both fsl,sai-asynchronous and fsl,sai-synchronous-rx are absent, the
+  default synchronous mode (sync Rx with Tx) will be used, which means both
+  transimitter and receiver will send and receive data by following clocks
+  of transimitter.
+- fsl,sai-asynchronous and fsl,sai-synchronous-rx are exclusive.
 
 Example:
 sai2: sai@40031000 {
@@ -38,5 +53,5 @@ sai2: sai@40031000 {
              dmas = <&edma0 0 VF610_EDMA_MUXID0_SAI2_TX>,
                   <&edma0 0 VF610_EDMA_MUXID0_SAI2_RX>;
              big-endian;
-             big-endian-data;
+             lsb-first;
 };
index f1ec6e6bd08aced4be7c38d868ccba94a655c5f7..c3f2decd643c9ba7eb57eec8a644091bc440376d 100644 (file)
@@ -1906,6 +1906,32 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
+int rt5640_dmic_enable(struct snd_soc_codec *codec,
+                      bool dmic1_data_pin, bool dmic2_data_pin)
+{
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+
+       regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
+               RT5640_GP2_PIN_MASK, RT5640_GP2_PIN_DMIC1_SCL);
+
+       if (dmic1_data_pin) {
+               regmap_update_bits(rt5640->regmap, RT5640_DMIC,
+                       RT5640_DMIC_1_DP_MASK, RT5640_DMIC_1_DP_GPIO3);
+               regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
+                       RT5640_GP3_PIN_MASK, RT5640_GP3_PIN_DMIC1_SDA);
+       }
+
+       if (dmic2_data_pin) {
+               regmap_update_bits(rt5640->regmap, RT5640_DMIC,
+                       RT5640_DMIC_2_DP_MASK, RT5640_DMIC_2_DP_GPIO4);
+               regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
+                       RT5640_GP4_PIN_MASK, RT5640_GP4_PIN_DMIC2_SDA);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rt5640_dmic_enable);
+
 static int rt5640_probe(struct snd_soc_codec *codec)
 {
        struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
@@ -1945,6 +1971,10 @@ static int rt5640_probe(struct snd_soc_codec *codec)
                return -ENODEV;
        }
 
+       if (rt5640->pdata.dmic_en)
+               rt5640_dmic_enable(codec, rt5640->pdata.dmic1_data_pin,
+                                         rt5640->pdata.dmic2_data_pin);
+
        return 0;
 }
 
@@ -2195,25 +2225,6 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
                regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4,
                                        RT5640_IN_DF2, RT5640_IN_DF2);
 
-       if (rt5640->pdata.dmic_en) {
-               regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
-                       RT5640_GP2_PIN_MASK, RT5640_GP2_PIN_DMIC1_SCL);
-
-               if (rt5640->pdata.dmic1_data_pin) {
-                       regmap_update_bits(rt5640->regmap, RT5640_DMIC,
-                               RT5640_DMIC_1_DP_MASK, RT5640_DMIC_1_DP_GPIO3);
-                       regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
-                               RT5640_GP3_PIN_MASK, RT5640_GP3_PIN_DMIC1_SDA);
-               }
-
-               if (rt5640->pdata.dmic2_data_pin) {
-                       regmap_update_bits(rt5640->regmap, RT5640_DMIC,
-                               RT5640_DMIC_2_DP_MASK, RT5640_DMIC_2_DP_GPIO4);
-                       regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1,
-                               RT5640_GP4_PIN_MASK, RT5640_GP4_PIN_DMIC2_SDA);
-               }
-       }
-
        rt5640->hp_mute = 1;
 
        return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640,
index 58ebe96b86dae452165fc679ce424017e9088833..3deb8babeabb691d37a314bb3ab19c84d5c9cd1f 100644 (file)
@@ -2097,4 +2097,7 @@ struct rt5640_priv {
        bool hp_mute;
 };
 
+int rt5640_dmic_enable(struct snd_soc_codec *codec,
+                      bool dmic1_data_pin, bool dmic2_data_pin);
+
 #endif
index 52d1e9982639f14dc823165c07a25474a3f0352f..7eeb1dd8ce27339e05305552aa7f3cc34240ca29 100644 (file)
@@ -175,7 +175,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
        bool tx = fsl_dir == FSL_FMT_TRANSMITTER;
        u32 val_cr2 = 0, val_cr4 = 0;
 
-       if (!sai->big_endian_data)
+       if (!sai->is_lsb_first)
                val_cr4 |= FSL_SAI_CR4_MF;
 
        /* DAI mode */
@@ -304,7 +304,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
        val_cr5 |= FSL_SAI_CR5_WNW(word_width);
        val_cr5 |= FSL_SAI_CR5_W0W(word_width);
 
-       if (sai->big_endian_data)
+       if (sai->is_lsb_first)
                val_cr5 |= FSL_SAI_CR5_FBT(0);
        else
                val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
@@ -330,13 +330,13 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
        u32 xcsr, count = 100;
 
        /*
-        * The transmitter bit clock and frame sync are to be
-        * used by both the transmitter and receiver.
+        * Asynchronous mode: Clear SYNC for both Tx and Rx.
+        * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx.
+        * Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx.
         */
-       regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC,
-                          ~FSL_SAI_CR2_SYNC);
+       regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, 0);
        regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC,
-                          FSL_SAI_CR2_SYNC);
+                          sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0);
 
        /*
         * It is recommended that the transmitter is the last enabled
@@ -437,8 +437,13 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 {
        struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
 
-       regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0);
-       regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0);
+       /* Software Reset for both Tx and Rx */
+       regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR);
+       regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR);
+       /* Clear SR bit to finish the reset */
+       regmap_write(sai->regmap, FSL_SAI_TCSR, 0);
+       regmap_write(sai->regmap, FSL_SAI_RCSR, 0);
+
        regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK,
                           FSL_SAI_MAXBURST_TX * 2);
        regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK,
@@ -568,7 +573,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
        if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai"))
                sai->sai_on_imx = true;
 
-       sai->big_endian_data = of_property_read_bool(np, "big-endian-data");
+       sai->is_lsb_first = of_property_read_bool(np, "lsb-first");
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        base = devm_ioremap_resource(&pdev->dev, res);
@@ -617,6 +622,33 @@ static int fsl_sai_probe(struct platform_device *pdev)
                return ret;
        }
 
+       /* Sync Tx with Rx as default by following old DT binding */
+       sai->synchronous[RX] = true;
+       sai->synchronous[TX] = false;
+       fsl_sai_dai.symmetric_rates = 1;
+       fsl_sai_dai.symmetric_channels = 1;
+       fsl_sai_dai.symmetric_samplebits = 1;
+
+       if (of_find_property(np, "fsl,sai-synchronous-rx", NULL) &&
+           of_find_property(np, "fsl,sai-asynchronous", NULL)) {
+               /* error out if both synchronous and asynchronous are present */
+               dev_err(&pdev->dev, "invalid binding for synchronous mode\n");
+               return -EINVAL;
+       }
+
+       if (of_find_property(np, "fsl,sai-synchronous-rx", NULL)) {
+               /* Sync Rx with Tx */
+               sai->synchronous[RX] = false;
+               sai->synchronous[TX] = true;
+       } else if (of_find_property(np, "fsl,sai-asynchronous", NULL)) {
+               /* Discard all settings for asynchronous mode */
+               sai->synchronous[RX] = false;
+               sai->synchronous[TX] = false;
+               fsl_sai_dai.symmetric_rates = 0;
+               fsl_sai_dai.symmetric_channels = 0;
+               fsl_sai_dai.symmetric_samplebits = 0;
+       }
+
        sai->dma_params_rx.addr = res->start + FSL_SAI_RDR;
        sai->dma_params_tx.addr = res->start + FSL_SAI_TDR;
        sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
index 20e3e53ce6ea65c184c8ceed8bab507640e3dab0..34667209b607d435d3abd9ac10bbfe6e8cf9a64c 100644 (file)
@@ -48,6 +48,7 @@
 /* SAI Transmit/Recieve Control Register */
 #define FSL_SAI_CSR_TERE       BIT(31)
 #define FSL_SAI_CSR_FR         BIT(25)
+#define FSL_SAI_CSR_SR         BIT(24)
 #define FSL_SAI_CSR_xF_SHIFT   16
 #define FSL_SAI_CSR_xF_W_SHIFT 18
 #define FSL_SAI_CSR_xF_MASK    (0x1f << FSL_SAI_CSR_xF_SHIFT)
@@ -131,12 +132,16 @@ struct fsl_sai {
        struct clk *bus_clk;
        struct clk *mclk_clk[FSL_SAI_MCLK_MAX];
 
-       bool big_endian_data;
+       bool is_lsb_first;
        bool is_dsp_mode;
        bool sai_on_imx;
+       bool synchronous[2];
 
        struct snd_dmaengine_dai_dma_data dma_params_rx;
        struct snd_dmaengine_dai_dma_data dma_params_tx;
 };
 
+#define TX 1
+#define RX 0
+
 #endif /* __FSL_SAI_H */
index de6ab06f58a54dbd32b871273a530db6e8d9fbed..e6955170dc42c8b805d6aa654a5eadebc437b27e 100644 (file)
@@ -169,6 +169,7 @@ struct fsl_ssi_private {
        u8 i2s_mode;
        bool use_dma;
        bool use_dual_fifo;
+       bool has_ipg_clk_name;
        unsigned int fifo_depth;
        struct fsl_ssi_rxtx_reg_val rxtx_reg_val;
 
@@ -259,6 +260,11 @@ static bool fsl_ssi_is_i2s_master(struct fsl_ssi_private *ssi_private)
                SND_SOC_DAIFMT_CBS_CFS;
 }
 
+static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi_private *ssi_private)
+{
+       return (ssi_private->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) ==
+               SND_SOC_DAIFMT_CBM_CFS;
+}
 /**
  * fsl_ssi_isr: SSI interrupt handler
  *
@@ -525,6 +531,11 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct fsl_ssi_private *ssi_private =
                snd_soc_dai_get_drvdata(rtd->cpu_dai);
+       int ret;
+
+       ret = clk_prepare_enable(ssi_private->clk);
+       if (ret)
+               return ret;
 
        /* When using dual fifo mode, it is safer to ensure an even period
         * size. If appearing to an odd number while DMA always starts its
@@ -538,6 +549,21 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
        return 0;
 }
 
+/**
+ * fsl_ssi_shutdown: shutdown the SSI
+ *
+ */
+static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct fsl_ssi_private *ssi_private =
+               snd_soc_dai_get_drvdata(rtd->cpu_dai);
+
+       clk_disable_unprepare(ssi_private->clk);
+
+}
+
 /**
  * fsl_ssi_set_bclk - configure Digital Audio Interface bit clock
  *
@@ -705,6 +731,23 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
                }
        }
 
+       if (!fsl_ssi_is_ac97(ssi_private)) {
+               u8 i2smode;
+               /*
+                * Switch to normal net mode in order to have a frame sync
+                * signal every 32 bits instead of 16 bits
+                */
+               if (fsl_ssi_is_i2s_cbm_cfs(ssi_private) && sample_size == 16)
+                       i2smode = CCSR_SSI_SCR_I2S_MODE_NORMAL |
+                               CCSR_SSI_SCR_NET;
+               else
+                       i2smode = ssi_private->i2s_mode;
+
+               regmap_update_bits(regs, CCSR_SSI_SCR,
+                               CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK,
+                               channels == 1 ? 0 : i2smode);
+       }
+
        /*
         * FIXME: The documentation says that SxCCR[WL] should not be
         * modified while the SSI is enabled.  The only time this can
@@ -724,11 +767,6 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
                regmap_update_bits(regs, CCSR_SSI_SRCCR, CCSR_SSI_SxCCR_WL_MASK,
                                wl);
 
-       if (!fsl_ssi_is_ac97(ssi_private))
-               regmap_update_bits(regs, CCSR_SSI_SCR,
-                               CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK,
-                               channels == 1 ? 0 : ssi_private->i2s_mode);
-
        return 0;
 }
 
@@ -781,6 +819,7 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
                switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+               case SND_SOC_DAIFMT_CBM_CFS:
                case SND_SOC_DAIFMT_CBS_CFS:
                        ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_MASTER;
                        regmap_update_bits(regs, CCSR_SSI_STCCR,
@@ -854,6 +893,11 @@ static int _fsl_ssi_set_dai_fmt(struct device *dev,
        case SND_SOC_DAIFMT_CBM_CFM:
                scr &= ~CCSR_SSI_SCR_SYS_CLK_EN;
                break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               strcr &= ~CCSR_SSI_STCR_TXDIR;
+               strcr |= CCSR_SSI_STCR_TFDIR;
+               scr &= ~CCSR_SSI_SCR_SYS_CLK_EN;
+               break;
        default:
                return -EINVAL;
        }
@@ -1021,6 +1065,7 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
 
 static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
        .startup        = fsl_ssi_startup,
+       .shutdown       = fsl_ssi_shutdown,
        .hw_params      = fsl_ssi_hw_params,
        .hw_free        = fsl_ssi_hw_free,
        .set_fmt        = fsl_ssi_set_dai_fmt,
@@ -1146,17 +1191,22 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
        u32 dmas[4];
        int ret;
 
-       ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
+       if (ssi_private->has_ipg_clk_name)
+               ssi_private->clk = devm_clk_get(&pdev->dev, "ipg");
+       else
+               ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(ssi_private->clk)) {
                ret = PTR_ERR(ssi_private->clk);
                dev_err(&pdev->dev, "could not get clock: %d\n", ret);
                return ret;
        }
 
-       ret = clk_prepare_enable(ssi_private->clk);
-       if (ret) {
-               dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
-               return ret;
+       if (!ssi_private->has_ipg_clk_name) {
+               ret = clk_prepare_enable(ssi_private->clk);
+               if (ret) {
+                       dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
+                       return ret;
+               }
        }
 
        /* For those SLAVE implementations, we ingore non-baudclk cases
@@ -1214,8 +1264,9 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev,
        return 0;
 
 error_pcm:
-       clk_disable_unprepare(ssi_private->clk);
 
+       if (!ssi_private->has_ipg_clk_name)
+               clk_disable_unprepare(ssi_private->clk);
        return ret;
 }
 
@@ -1224,7 +1275,8 @@ static void fsl_ssi_imx_clean(struct platform_device *pdev,
 {
        if (!ssi_private->use_dma)
                imx_pcm_fiq_exit(pdev);
-       clk_disable_unprepare(ssi_private->clk);
+       if (!ssi_private->has_ipg_clk_name)
+               clk_disable_unprepare(ssi_private->clk);
 }
 
 static int fsl_ssi_probe(struct platform_device *pdev)
@@ -1263,9 +1315,6 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        if (sprop) {
                if (!strcmp(sprop, "ac97-slave"))
                        ssi_private->dai_fmt = SND_SOC_DAIFMT_AC97;
-               else if (!strcmp(sprop, "i2s-slave"))
-                       ssi_private->dai_fmt = SND_SOC_DAIFMT_I2S |
-                               SND_SOC_DAIFMT_CBM_CFM;
        }
 
        ssi_private->use_dma = !of_property_read_bool(np,
@@ -1299,8 +1348,16 @@ static int fsl_ssi_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
-       ssi_private->regs = devm_regmap_init_mmio(&pdev->dev, iomem,
+       ret = of_property_match_string(np, "clock-names", "ipg");
+       if (ret < 0) {
+               ssi_private->has_ipg_clk_name = false;
+               ssi_private->regs = devm_regmap_init_mmio(&pdev->dev, iomem,
                        &fsl_ssi_regconfig);
+       } else {
+               ssi_private->has_ipg_clk_name = true;
+               ssi_private->regs = devm_regmap_init_mmio_clk(&pdev->dev,
+                       "ipg", iomem, &fsl_ssi_regconfig);
+       }
        if (IS_ERR(ssi_private->regs)) {
                dev_err(&pdev->dev, "Failed to init register map\n");
                return PTR_ERR(ssi_private->regs);
index b8b8af571ef169307e8b0e1efb68b5435c97df66..d52681e7225e72737145463f5db7664f6c6037af 100644 (file)
@@ -139,6 +139,7 @@ static struct snd_soc_card byt_max98090_card = {
        .num_dapm_routes = ARRAY_SIZE(byt_max98090_audio_map),
        .controls = byt_max98090_controls,
        .num_controls = ARRAY_SIZE(byt_max98090_controls),
+       .fully_routed = true,
 };
 
 static int byt_max98090_probe(struct platform_device *pdev)
index 234a58de3c53b0f4e758fa04e93db5012fcfda0b..e03abdf21c1bc3f4dbff62f4cd46d80327dbadd1 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/acpi.h>
 #include <linux/device.h>
+#include <linux/dmi.h>
 #include <linux/slab.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -36,8 +37,6 @@ static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = {
 static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
        {"Headset Mic", NULL, "MICBIAS1"},
        {"IN2P", NULL, "Headset Mic"},
-       {"IN2N", NULL, "Headset Mic"},
-       {"DMIC1", NULL, "Internal Mic"},
        {"Headphone", NULL, "HPOL"},
        {"Headphone", NULL, "HPOR"},
        {"Speaker", NULL, "SPOLP"},
@@ -46,6 +45,31 @@ static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
        {"Speaker", NULL, "SPORN"},
 };
 
+static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = {
+       {"DMIC1", NULL, "Internal Mic"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic2_map[] = {
+       {"DMIC2", NULL, "Internal Mic"},
+};
+
+static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = {
+       {"Internal Mic", NULL, "MICBIAS1"},
+       {"IN1P", NULL, "Internal Mic"},
+};
+
+enum {
+       BYT_RT5640_DMIC1_MAP,
+       BYT_RT5640_DMIC2_MAP,
+       BYT_RT5640_IN1_MAP,
+};
+
+#define BYT_RT5640_MAP(quirk)  ((quirk) & 0xff)
+#define BYT_RT5640_DMIC_EN     BIT(16)
+
+static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP |
+                                       BYT_RT5640_DMIC_EN;
+
 static const struct snd_kcontrol_new byt_rt5640_controls[] = {
        SOC_DAPM_PIN_SWITCH("Headphone"),
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
@@ -77,12 +101,41 @@ static int byt_rt5640_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
+static int byt_rt5640_quirk_cb(const struct dmi_system_id *id)
+{
+       byt_rt5640_quirk = (unsigned long)id->driver_data;
+       return 1;
+}
+
+static const struct dmi_system_id byt_rt5640_quirk_table[] = {
+       {
+               .callback = byt_rt5640_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"),
+               },
+               .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP,
+       },
+       {
+               .callback = byt_rt5640_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "DellInc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"),
+               },
+               .driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP |
+                                                BYT_RT5640_DMIC_EN),
+       },
+       {}
+};
+
 static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
 {
        int ret;
        struct snd_soc_codec *codec = runtime->codec;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
        struct snd_soc_card *card = runtime->card;
+       const struct snd_soc_dapm_route *custom_map;
+       int num_routes;
 
        card->dapm.idle_bias_off = true;
 
@@ -93,6 +146,31 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
                return ret;
        }
 
+       dmi_check_system(byt_rt5640_quirk_table);
+       switch (BYT_RT5640_MAP(byt_rt5640_quirk)) {
+       case BYT_RT5640_IN1_MAP:
+               custom_map = byt_rt5640_intmic_in1_map;
+               num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map);
+               break;
+       case BYT_RT5640_DMIC2_MAP:
+               custom_map = byt_rt5640_intmic_dmic2_map;
+               num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map);
+               break;
+       default:
+               custom_map = byt_rt5640_intmic_dmic1_map;
+               num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map);
+       }
+
+       ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes);
+       if (ret)
+               return ret;
+
+       if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) {
+               ret = rt5640_dmic_enable(codec, 0, 0);
+               if (ret)
+                       return ret;
+       }
+
        snd_soc_dapm_ignore_suspend(dapm, "HPOL");
        snd_soc_dapm_ignore_suspend(dapm, "HPOR");
 
@@ -131,6 +209,7 @@ static struct snd_soc_card byt_rt5640_card = {
        .num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets),
        .dapm_routes = byt_rt5640_audio_map,
        .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map),
+       .fully_routed = true,
 };
 
 static int byt_rt5640_probe(struct platform_device *pdev)
index ace3c4a59b1467091b3a86f8dae24530364cd99e..7104a34181a922473c7d967f721120dae757891f 100644 (file)
 #include "sst-mfld-platform.h"
 #include "sst-atom-controls.h"
 
+static int sst_fill_byte_control(struct sst_data *drv,
+                                        u8 ipc_msg, u8 block,
+                                        u8 task_id, u8 pipe_id,
+                                        u16 len, void *cmd_data)
+{
+       struct snd_sst_bytes_v2 *byte_data = drv->byte_stream;
+
+       byte_data->type = SST_CMD_BYTES_SET;
+       byte_data->ipc_msg = ipc_msg;
+       byte_data->block = block;
+       byte_data->task_id = task_id;
+       byte_data->pipe_id = pipe_id;
+
+       if (len > SST_MAX_BIN_BYTES - sizeof(*byte_data)) {
+               dev_err(&drv->pdev->dev, "command length too big (%u)", len);
+               return -EINVAL;
+       }
+       byte_data->len = len;
+       memcpy(byte_data->bytes, cmd_data, len);
+       print_hex_dump_bytes("writing to lpe: ", DUMP_PREFIX_OFFSET,
+                            byte_data, len + sizeof(*byte_data));
+       return 0;
+}
+
+static int sst_fill_and_send_cmd_unlocked(struct sst_data *drv,
+                                u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id,
+                                void *cmd_data, u16 len)
+{
+       int ret = 0;
+
+       ret = sst_fill_byte_control(drv, ipc_msg,
+                               block, task_id, pipe_id, len, cmd_data);
+       if (ret < 0)
+               return ret;
+       return sst->ops->send_byte_stream(sst->dev, drv->byte_stream);
+}
+
+/**
+ * sst_fill_and_send_cmd - generate the IPC message and send it to the FW
+ * @ipc_msg:   type of IPC (CMD, SET_PARAMS, GET_PARAMS)
+ * @cmd_data:  the IPC payload
+ */
+static int sst_fill_and_send_cmd(struct sst_data *drv,
+                                u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id,
+                                void *cmd_data, u16 len)
+{
+       int ret;
+
+       mutex_lock(&drv->lock);
+       ret = sst_fill_and_send_cmd_unlocked(drv, ipc_msg, block,
+                                       task_id, pipe_id, cmd_data, len);
+       mutex_unlock(&drv->lock);
+
+       return ret;
+}
+
+static int sst_send_algo_cmd(struct sst_data *drv,
+                             struct sst_algo_control *bc)
+{
+       int len, ret = 0;
+       struct sst_cmd_set_params *cmd;
+
+       /*bc->max includes sizeof algos + length field*/
+       len = sizeof(cmd->dst) + sizeof(cmd->command_id) + bc->max;
+
+       cmd = kzalloc(len, GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       SST_FILL_DESTINATION(2, cmd->dst, bc->pipe_id, bc->module_id);
+       cmd->command_id = bc->cmd_id;
+       memcpy(cmd->params, bc->params, bc->max);
+
+       ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_SET_PARAMS,
+                               SST_FLAG_BLOCKED, bc->task_id, 0, cmd, len);
+       kfree(cmd);
+       return ret;
+}
+
+static int sst_algo_bytes_ctl_info(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_info *uinfo)
+{
+       struct sst_algo_control *bc = (void *)kcontrol->private_value;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+       uinfo->count = bc->max;
+
+       return 0;
+}
+
+static int sst_algo_control_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct sst_algo_control *bc = (void *)kcontrol->private_value;
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+
+       switch (bc->type) {
+       case SST_ALGO_PARAMS:
+               memcpy(ucontrol->value.bytes.data, bc->params, bc->max);
+               break;
+       default:
+               dev_err(component->dev, "Invalid Input- algo type:%d\n",
+                               bc->type);
+               return -EINVAL;
+
+       }
+       return 0;
+}
+
+static int sst_algo_control_set(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       int ret = 0;
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt);
+       struct sst_algo_control *bc = (void *)kcontrol->private_value;
+
+       dev_dbg(cmpnt->dev, "control_name=%s\n", kcontrol->id.name);
+       mutex_lock(&drv->lock);
+       switch (bc->type) {
+       case SST_ALGO_PARAMS:
+               memcpy(bc->params, ucontrol->value.bytes.data, bc->max);
+               break;
+       default:
+               mutex_unlock(&drv->lock);
+               dev_err(cmpnt->dev, "Invalid Input- algo type:%d\n",
+                               bc->type);
+               return -EINVAL;
+       }
+       /*if pipe is enabled, need to send the algo params from here*/
+       if (bc->w && bc->w->power)
+               ret = sst_send_algo_cmd(drv, bc);
+       mutex_unlock(&drv->lock);
+
+       return ret;
+}
+
+static const struct snd_kcontrol_new sst_algo_controls[] = {
+       SST_ALGO_KCONTROL_BYTES("media_loop1_out", "fir", 272, SST_MODULE_ID_FIR_24,
+                SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR),
+       SST_ALGO_KCONTROL_BYTES("media_loop1_out", "iir", 300, SST_MODULE_ID_IIR_24,
+               SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
+       SST_ALGO_KCONTROL_BYTES("media_loop1_out", "mdrp", 286, SST_MODULE_ID_MDRP,
+               SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP),
+       SST_ALGO_KCONTROL_BYTES("media_loop2_out", "fir", 272, SST_MODULE_ID_FIR_24,
+               SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR),
+       SST_ALGO_KCONTROL_BYTES("media_loop2_out", "iir", 300, SST_MODULE_ID_IIR_24,
+               SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
+       SST_ALGO_KCONTROL_BYTES("media_loop2_out", "mdrp", 286, SST_MODULE_ID_MDRP,
+               SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP),
+       SST_ALGO_KCONTROL_BYTES("sprot_loop_out", "lpro", 192, SST_MODULE_ID_SPROT,
+               SST_PATH_INDEX_SPROT_LOOP_OUT, 0, SST_TASK_SBA, SBA_VB_LPRO),
+       SST_ALGO_KCONTROL_BYTES("codec_in0", "dcr", 52, SST_MODULE_ID_FILT_DCR,
+               SST_PATH_INDEX_CODEC_IN0, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
+       SST_ALGO_KCONTROL_BYTES("codec_in1", "dcr", 52, SST_MODULE_ID_FILT_DCR,
+               SST_PATH_INDEX_CODEC_IN1, 0, SST_TASK_SBA, SBA_VB_SET_IIR),
+
+};
+
+static int sst_algo_control_init(struct device *dev)
+{
+       int i = 0;
+       struct sst_algo_control *bc;
+       /*allocate space to cache the algo parameters in the driver*/
+       for (i = 0; i < ARRAY_SIZE(sst_algo_controls); i++) {
+               bc = (struct sst_algo_control *)sst_algo_controls[i].private_value;
+               bc->params = devm_kzalloc(dev, bc->max, GFP_KERNEL);
+               if (bc->params == NULL)
+                       return -ENOMEM;
+       }
+       return 0;
+}
+
 int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform)
 {
        int ret = 0;
@@ -35,5 +208,11 @@ int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform)
        if (!drv->byte_stream)
                return -ENOMEM;
 
+       /*Initialize algo control params*/
+       ret = sst_algo_control_init(platform->dev);
+       if (ret)
+               return ret;
+       ret = snd_soc_add_platform_controls(platform, sst_algo_controls,
+                       ARRAY_SIZE(sst_algo_controls));
        return ret;
 }
index 8554889c0694006e21f4441efbfb2a3d9b1e18b8..a73e894b175c03836e4aa8d437a6fe3ee35de907 100644 (file)
@@ -309,4 +309,134 @@ enum sst_swm_state {
        SST_SWM_ON = 3,
 };
 
+#define SST_FILL_LOCATION_IDS(dst, cell_idx, pipe_id)          do {    \
+               dst.location_id.p.cell_nbr_idx = (cell_idx);            \
+               dst.location_id.p.path_id = (pipe_id);                  \
+       } while (0)
+#define SST_FILL_LOCATION_ID(dst, loc_id)                              (\
+       dst.location_id.f = (loc_id))
+#define SST_FILL_MODULE_ID(dst, mod_id)                                        (\
+       dst.module_id = (mod_id))
+
+#define SST_FILL_DESTINATION1(dst, id)                         do {    \
+               SST_FILL_LOCATION_ID(dst, (id) & 0xFFFF);               \
+               SST_FILL_MODULE_ID(dst, ((id) & 0xFFFF0000) >> 16);     \
+       } while (0)
+#define SST_FILL_DESTINATION2(dst, loc_id, mod_id)             do {    \
+               SST_FILL_LOCATION_ID(dst, loc_id);                      \
+               SST_FILL_MODULE_ID(dst, mod_id);                        \
+       } while (0)
+#define SST_FILL_DESTINATION3(dst, cell_idx, path_id, mod_id)  do {    \
+               SST_FILL_LOCATION_IDS(dst, cell_idx, path_id);          \
+               SST_FILL_MODULE_ID(dst, mod_id);                        \
+       } while (0)
+
+#define SST_FILL_DESTINATION(level, dst, ...)                          \
+       SST_FILL_DESTINATION##level(dst, __VA_ARGS__)
+#define SST_FILL_DEFAULT_DESTINATION(dst)                              \
+       SST_FILL_DESTINATION(2, dst, SST_DEFAULT_LOCATION_ID, SST_DEFAULT_MODULE_ID)
+
+struct sst_destination_id {
+       union sst_location_id {
+               struct {
+                       u8 cell_nbr_idx;        /* module index */
+                       u8 path_id;             /* pipe_id */
+               } __packed      p;              /* part */
+               u16             f;              /* full */
+       } __packed location_id;
+       u16        module_id;
+} __packed;
+struct sst_dsp_header {
+       struct sst_destination_id dst;
+       u16 command_id;
+       u16 length;
+} __packed;
+
+/*
+ *
+ * Common Commands
+ *
+ */
+struct sst_cmd_generic {
+       struct sst_dsp_header header;
+} __packed;
+struct sst_cmd_set_params {
+       struct sst_destination_id dst;
+       u16 command_id;
+       char params[0];
+} __packed;
+#define SST_CONTROL_NAME(xpname, xmname, xinstance, xtype) \
+       xpname " " xmname " " #xinstance " " xtype
+
+#define SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, xtype, xsubmodule) \
+       xpname " " xmname " " #xinstance " " xtype " " xsubmodule
+enum sst_algo_kcontrol_type {
+       SST_ALGO_PARAMS,
+       SST_ALGO_BYPASS,
+};
+
+struct sst_algo_control {
+       enum sst_algo_kcontrol_type type;
+       int max;
+       u16 module_id;
+       u16 pipe_id;
+       u16 task_id;
+       u16 cmd_id;
+       bool bypass;
+       unsigned char *params;
+       struct snd_soc_dapm_widget *w;
+};
+
+/* size of the control = size of params + size of length field */
+#define SST_ALGO_CTL_VALUE(xcount, xtype, xpipe, xmod, xtask, xcmd)                    \
+       (struct sst_algo_control){                                                      \
+               .max = xcount + sizeof(u16), .type = xtype, .module_id = xmod,                  \
+               .pipe_id = xpipe, .task_id = xtask, .cmd_id = xcmd,                     \
+       }
+
+#define SST_ALGO_KCONTROL(xname, xcount, xmod, xpipe,                                  \
+                         xtask, xcmd, xtype, xinfo, xget, xput)                        \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER,                                            \
+       .name =  xname,                                                                 \
+       .info = xinfo, .get = xget, .put = xput,                                        \
+       .private_value = (unsigned long)&                                               \
+                       SST_ALGO_CTL_VALUE(xcount, xtype, xpipe,                        \
+                                          xmod, xtask, xcmd),                          \
+}
+
+#define SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod,                          \
+                               xpipe, xinstance, xtask, xcmd)                          \
+       SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "params"),        \
+                         xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS,            \
+                         sst_algo_bytes_ctl_info,                                      \
+                         sst_algo_control_get, sst_algo_control_set)
+
+#define SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask)          \
+       SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "bypass"),        \
+                         0, xmod, xpipe, xtask, 0, SST_ALGO_BYPASS,                    \
+                         snd_soc_info_bool_ext,                                        \
+                         sst_algo_control_get, sst_algo_control_set)
+
+#define SST_ALGO_BYPASS_PARAMS(xpname, xmname, xcount, xmod, xpipe,                    \
+                               xinstance, xtask, xcmd)                                 \
+       SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask),          \
+       SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod, xpipe, xinstance, xtask, xcmd)
+
+#define SST_COMBO_ALGO_KCONTROL_BYTES(xpname, xmname, xsubmod, xcount, xmod,           \
+                                     xpipe, xinstance, xtask, xcmd)                    \
+       SST_ALGO_KCONTROL(SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, "params",   \
+                                                xsubmod),                              \
+                         xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS,            \
+                         sst_algo_bytes_ctl_info,                                      \
+                         sst_algo_control_get, sst_algo_control_set)
+
+
+struct sst_enum {
+       bool tx;
+       unsigned short reg;
+       unsigned int max;
+       const char * const *texts;
+       struct snd_soc_dapm_widget *w;
+};
+
 #endif
index 8e1e9bc27642ce38841754364757e27b7478baf7..aa9b600dfc9bfd1468c280ff61b1b7c5f728f159 100644 (file)
@@ -43,12 +43,12 @@ int sst_register_dsp(struct sst_device *dev)
                return -ENODEV;
        mutex_lock(&sst_lock);
        if (sst) {
-               pr_err("we already have a device %s\n", sst->name);
+               dev_err(dev->dev, "we already have a device %s\n", sst->name);
                module_put(dev->dev->driver->owner);
                mutex_unlock(&sst_lock);
                return -EEXIST;
        }
-       pr_debug("registering device %s\n", dev->name);
+       dev_dbg(dev->dev, "registering device %s\n", dev->name);
        sst = dev;
        mutex_unlock(&sst_lock);
        return 0;
@@ -70,7 +70,7 @@ int sst_unregister_dsp(struct sst_device *dev)
        }
 
        module_put(sst->dev->driver->owner);
-       pr_debug("unreg %s\n", sst->name);
+       dev_dbg(dev->dev, "unreg %s\n", sst->name);
        sst = NULL;
        mutex_unlock(&sst_lock);
        return 0;
@@ -252,7 +252,7 @@ int sst_fill_stream_params(void *substream,
 }
 
 static int sst_platform_alloc_stream(struct snd_pcm_substream *substream,
-               struct snd_soc_platform *platform)
+               struct snd_soc_dai *dai)
 {
        struct sst_runtime_stream *stream =
                        substream->runtime->private_data;
@@ -260,7 +260,7 @@ static int sst_platform_alloc_stream(struct snd_pcm_substream *substream,
        struct snd_sst_params str_params = {0};
        struct snd_sst_alloc_params_ext alloc_params = {0};
        int ret_val = 0;
-       struct sst_data *ctx = snd_soc_platform_get_drvdata(platform);
+       struct sst_data *ctx = snd_soc_dai_get_drvdata(dai);
 
        /* set codec params and inform SST driver the same */
        sst_fill_pcm_params(substream, &param);
@@ -306,9 +306,10 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream)
 {
        struct sst_runtime_stream *stream =
                        substream->runtime->private_data;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
        int ret_val;
 
-       pr_debug("setting buffer ptr param\n");
+       dev_dbg(rtd->dev, "setting buffer ptr param\n");
        sst_set_stream_status(stream, SST_PLATFORM_INIT);
        stream->stream_info.period_elapsed = sst_period_elapsed;
        stream->stream_info.arg = substream;
@@ -316,11 +317,21 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream)
        stream->stream_info.sfreq = substream->runtime->rate;
        ret_val = stream->ops->stream_init(sst->dev, &stream->stream_info);
        if (ret_val)
-               pr_err("control_set ret error %d\n", ret_val);
+               dev_err(rtd->dev, "control_set ret error %d\n", ret_val);
        return ret_val;
 
 }
 
+static int power_up_sst(struct sst_runtime_stream *stream)
+{
+       return stream->ops->power(sst->dev, true);
+}
+
+static void power_down_sst(struct sst_runtime_stream *stream)
+{
+       stream->ops->power(sst->dev, false);
+}
+
 static int sst_media_open(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
@@ -337,7 +348,7 @@ static int sst_media_open(struct snd_pcm_substream *substream,
        mutex_lock(&sst_lock);
        if (!sst ||
            !try_module_get(sst->dev->driver->owner)) {
-               pr_err("no device available to run\n");
+               dev_err(dai->dev, "no device available to run\n");
                ret_val = -ENODEV;
                goto out_ops;
        }
@@ -350,6 +361,10 @@ static int sst_media_open(struct snd_pcm_substream *substream,
        /* allocate memory for SST API set */
        runtime->private_data = stream;
 
+       ret_val = power_up_sst(stream);
+       if (ret_val < 0)
+               return ret_val;
+
        /* Make sure, that the period size is always even */
        snd_pcm_hw_constraint_step(substream->runtime, 0,
                           SNDRV_PCM_HW_PARAM_PERIODS, 2);
@@ -369,6 +384,8 @@ static void sst_media_close(struct snd_pcm_substream *substream,
        int ret_val = 0, str_id;
 
        stream = substream->runtime->private_data;
+       power_down_sst(stream);
+
        str_id = stream->stream_info.str_id;
        if (str_id)
                ret_val = stream->ops->close(sst->dev, str_id);
@@ -376,19 +393,20 @@ static void sst_media_close(struct snd_pcm_substream *substream,
        kfree(stream);
 }
 
-static inline unsigned int get_current_pipe_id(struct snd_soc_platform *platform,
+static inline unsigned int get_current_pipe_id(struct snd_soc_dai *dai,
                                               struct snd_pcm_substream *substream)
 {
-       struct sst_data *sst = snd_soc_platform_get_drvdata(platform);
+       struct sst_data *sst = snd_soc_dai_get_drvdata(dai);
        struct sst_dev_stream_map *map = sst->pdata->pdev_strm_map;
        struct sst_runtime_stream *stream =
                        substream->runtime->private_data;
        u32 str_id = stream->stream_info.str_id;
        unsigned int pipe_id;
+
        pipe_id = map[str_id].device_id;
 
-       pr_debug("%s: got pipe_id = %#x for str_id = %d\n",
-                __func__, pipe_id, str_id);
+       dev_dbg(dai->dev, "got pipe_id = %#x for str_id = %d\n",
+                       pipe_id, str_id);
        return pipe_id;
 }
 
@@ -405,7 +423,7 @@ static int sst_media_prepare(struct snd_pcm_substream *substream,
                return ret_val;
        }
 
-       ret_val = sst_platform_alloc_stream(substream, dai->platform);
+       ret_val = sst_platform_alloc_stream(substream, dai);
        if (ret_val <= 0)
                return ret_val;
        snprintf(substream->pcm->id, sizeof(substream->pcm->id),
@@ -459,29 +477,32 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream,
        int ret_val = 0, str_id;
        struct sst_runtime_stream *stream;
        int status;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
-       pr_debug("sst_platform_pcm_trigger called\n");
+       dev_dbg(rtd->dev, "sst_platform_pcm_trigger called\n");
+       if (substream->pcm->internal)
+               return 0;
        stream = substream->runtime->private_data;
        str_id = stream->stream_info.str_id;
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-               pr_debug("sst: Trigger Start\n");
+               dev_dbg(rtd->dev, "sst: Trigger Start\n");
                status = SST_PLATFORM_RUNNING;
                stream->stream_info.arg = substream;
                ret_val = stream->ops->stream_start(sst->dev, str_id);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
-               pr_debug("sst: in stop\n");
+               dev_dbg(rtd->dev, "sst: in stop\n");
                status = SST_PLATFORM_DROPPED;
                ret_val = stream->ops->stream_drop(sst->dev, str_id);
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               pr_debug("sst: in pause\n");
+               dev_dbg(rtd->dev, "sst: in pause\n");
                status = SST_PLATFORM_PAUSED;
                ret_val = stream->ops->stream_pause(sst->dev, str_id);
                break;
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               pr_debug("sst: in pause release\n");
+               dev_dbg(rtd->dev, "sst: in pause release\n");
                status = SST_PLATFORM_RUNNING;
                ret_val = stream->ops->stream_pause_release(sst->dev, str_id);
                break;
@@ -502,6 +523,7 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer
        struct sst_runtime_stream *stream;
        int ret_val, status;
        struct pcm_stream_info *str_info;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
        stream = substream->runtime->private_data;
        status = sst_get_stream_status(stream);
@@ -510,7 +532,7 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer
        str_info = &stream->stream_info;
        ret_val = stream->ops->stream_read_tstamp(sst->dev, str_info);
        if (ret_val) {
-               pr_err("sst: error code = %d\n", ret_val);
+               dev_err(rtd->dev, "sst: error code = %d\n", ret_val);
                return ret_val;
        }
        substream->runtime->delay = str_info->pcm_delay;
@@ -526,7 +548,7 @@ static struct snd_pcm_ops sst_platform_ops = {
 
 static void sst_pcm_free(struct snd_pcm *pcm)
 {
-       pr_debug("sst_pcm_free called\n");
+       dev_dbg(pcm->dev, "sst_pcm_free called\n");
        snd_pcm_lib_preallocate_free_for_all(pcm);
 }
 
@@ -543,7 +565,7 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
                        snd_dma_continuous_data(GFP_DMA),
                        SST_MIN_BUFFER, SST_MAX_BUFFER);
                if (retval) {
-                       pr_err("dma buffer allocationf fail\n");
+                       dev_err(rtd->dev, "dma buffer allocationf fail\n");
                        return retval;
                }
        }
@@ -576,13 +598,11 @@ static int sst_platform_probe(struct platform_device *pdev)
 
        drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
        if (drv == NULL) {
-               pr_err("kzalloc failed\n");
                return -ENOMEM;
        }
 
        pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
        if (pdata == NULL) {
-               pr_err("kzalloc failed for pdata\n");
                return -ENOMEM;
        }
 
@@ -594,14 +614,14 @@ static int sst_platform_probe(struct platform_device *pdev)
 
        ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv);
        if (ret) {
-               pr_err("registering soc platform failed\n");
+               dev_err(&pdev->dev, "registering soc platform failed\n");
                return ret;
        }
 
        ret = snd_soc_register_component(&pdev->dev, &sst_component,
                                sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
        if (ret) {
-               pr_err("registering cpu dais failed\n");
+               dev_err(&pdev->dev, "registering cpu dais failed\n");
                snd_soc_unregister_platform(&pdev->dev);
        }
        return ret;
@@ -612,7 +632,7 @@ static int sst_platform_remove(struct platform_device *pdev)
 
        snd_soc_unregister_component(&pdev->dev);
        snd_soc_unregister_platform(&pdev->dev);
-       pr_debug("sst_platform_remove success\n");
+       dev_dbg(&pdev->dev, "sst_platform_remove success\n");
        return 0;
 }
 
index 0c5b943daff3bfe85b654cb2ffe026a187d50f12..19f83ec51613a3ba46ddeab431dadd6ae7d12854 100644 (file)
@@ -120,15 +120,16 @@ struct compress_sst_ops {
 };
 
 struct sst_ops {
-       int (*open) (struct device *dev, struct snd_sst_params *str_param);
-       int (*stream_init) (struct device *dev, struct pcm_stream_info *str_info);
-       int (*stream_start) (struct device *dev, int str_id);
-       int (*stream_drop) (struct device *dev, int str_id);
-       int (*stream_pause) (struct device *dev, int str_id);
-       int (*stream_pause_release) (struct device *dev, int str_id);
-       int (*stream_read_tstamp) (struct device *dev, struct pcm_stream_info *str_info);
+       int (*open)(struct device *dev, struct snd_sst_params *str_param);
+       int (*stream_init)(struct device *dev, struct pcm_stream_info *str_info);
+       int (*stream_start)(struct device *dev, int str_id);
+       int (*stream_drop)(struct device *dev, int str_id);
+       int (*stream_pause)(struct device *dev, int str_id);
+       int (*stream_pause_release)(struct device *dev, int str_id);
+       int (*stream_read_tstamp)(struct device *dev, struct pcm_stream_info *str_info);
        int (*send_byte_stream)(struct device *dev, struct snd_sst_bytes_v2 *bytes);
-       int (*close) (struct device *dev, unsigned int str_id);
+       int (*close)(struct device *dev, unsigned int str_id);
+       int (*power)(struct device *dev, bool state);
 };
 
 struct sst_runtime_stream {
@@ -166,7 +167,7 @@ struct sst_algo_int_control_v2 {
 struct sst_data {
        struct platform_device *pdev;
        struct sst_platform_data *pdata;
-       char *byte_stream;
+       struct snd_sst_bytes_v2 *byte_stream;
        struct mutex lock;
 };
 int sst_register_dsp(struct sst_device *sst);