ASoC: SOF: start using tracing instead of dev_dbg
authorMark Brown <broonie@kernel.org>
Mon, 19 Sep 2022 23:07:42 +0000 (00:07 +0100)
committerMark Brown <broonie@kernel.org>
Mon, 19 Sep 2022 23:07:42 +0000 (00:07 +0100)
Merge series from Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>:

Multiple maintainers have told us to start using the tracing
subsystem. Wish granted, this patchset suggested by Noah Klayman
removes a number of verbose and arguably useless dev_dbg or dev_vdbg
logs.

Beyond higher efficiency and less intrusive instrumentation, the use
of bpftrace scripts bring new functionality and helps gather
statistics on usage count on a running system, see how we can get
information on suspend/resume times with [1]

[1] https://github.com/thesofproject/sof-test/blob/main/kernel_tracing/bpftrace_scripts/suspend_resume_time.bt

30 files changed:
Documentation/devicetree/bindings/sound/allwinner,sun50i-h6-dmic.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/sound/qcom,sm8250.yaml
MAINTAINERS
sound/hda/intel-dsp-config.c
sound/soc/amd/acp/acp-mach-common.c
sound/soc/amd/acp/acp-pci.c
sound/soc/codecs/max98390.c
sound/soc/codecs/rt5682s.c
sound/soc/codecs/rt5682s.h
sound/soc/fsl/fsl_spdif.c
sound/soc/intel/avs/boards/hdaudio.c
sound/soc/intel/boards/sof_cs42l42.c
sound/soc/intel/boards/sof_es8336.c
sound/soc/intel/boards/sof_nau8825.c
sound/soc/intel/boards/sof_rt5682.c
sound/soc/intel/boards/sof_ssp_amp.c
sound/soc/qcom/Kconfig
sound/soc/qcom/Makefile
sound/soc/qcom/common.c
sound/soc/qcom/common.h
sound/soc/qcom/sc8280xp.c [new file with mode: 0644]
sound/soc/qcom/sm8250.c
sound/soc/soc-core.c
sound/soc/soc-topology.c
sound/soc/sof/nocodec.c
sound/soc/sof/sof-pci-dev.c
sound/soc/sunxi/Kconfig
sound/soc/sunxi/Makefile
sound/soc/sunxi/sun4i-codec.c
sound/soc/sunxi/sun50i-dmic.c [new file with mode: 0644]

diff --git a/Documentation/devicetree/bindings/sound/allwinner,sun50i-h6-dmic.yaml b/Documentation/devicetree/bindings/sound/allwinner,sun50i-h6-dmic.yaml
new file mode 100644 (file)
index 0000000..2f12cab
--- /dev/null
@@ -0,0 +1,79 @@
+# SPDX-License-Identifier: (GPL-2.0+ OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/sound/allwinner,sun50i-h6-dmic.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner H6 DMIC
+
+maintainers:
+  - Ban Tao <fengzheng923@gmail.com>
+
+properties:
+  compatible:
+    const: allwinner,sun50i-h6-dmic
+
+  "#sound-dai-cells":
+    const: 0
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Bus Clock
+      - description: Module Clock
+
+  clock-names:
+    items:
+      - const: bus
+      - const: mod
+
+  dmas:
+    items:
+      - description: RX DMA Channel
+
+  dma-names:
+    items:
+      - const: rx
+
+  resets:
+    maxItems: 1
+
+required:
+  - "#sound-dai-cells"
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - dmas
+  - dma-names
+  - resets
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    #include <dt-bindings/clock/sun50i-h6-ccu.h>
+    #include <dt-bindings/reset/sun50i-h6-ccu.h>
+
+    dmic: dmic@5095000 {
+      #sound-dai-cells = <0>;
+      compatible = "allwinner,sun50i-h6-dmic";
+      reg = <0x05095000 0x400>;
+      interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
+      clocks = <&ccu CLK_BUS_DMIC>, <&ccu CLK_DMIC>;
+      clock-names = "bus", "mod";
+      dmas = <&dma 7>;
+      dma-names = "rx";
+      resets = <&ccu RST_BUS_DMIC>;
+    };
+
+...
index a3a4289..70080d0 100644 (file)
@@ -20,9 +20,11 @@ properties:
       - qcom,apq8016-sbc-sndcard
       - qcom,db845c-sndcard
       - qcom,msm8916-qdsp6-sndcard
+      - qcom,qrb5165-rb5-sndcard
+      - qcom,sc8280xp-sndcard
       - qcom,sdm845-sndcard
       - qcom,sm8250-sndcard
-      - qcom,qrb5165-rb5-sndcard
+      - qcom,sm8450-sndcard
 
   audio-routing:
     $ref: /schemas/types.yaml#/definitions/non-unique-string-array
index 5e3f515..bda993e 100644 (file)
@@ -820,6 +820,13 @@ L: linux-media@vger.kernel.org
 S:     Maintained
 F:     drivers/staging/media/sunxi/cedrus/
 
+ALLWINNER DMIC DRIVERS
+M:     Ban Tao <fengzheng923@gmail.com>
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:     Maintained
+F:     Documentation/devicetree/bindings/sound/allwinner,sun50i-h6-dmic.yaml
+F:     sound/soc/sunxi/sun50i-dmic.c
+
 ALPHA PORT
 M:     Richard Henderson <richard.henderson@linaro.org>
 M:     Ivan Kokshaysky <ink@jurassic.park.msu.ru>
index d84ffdf..1997ffc 100644 (file)
@@ -428,6 +428,11 @@ static const struct config_entry config_table[] = {
        },
        /* Alderlake-PS */
        {
+               .flags = FLAG_SOF,
+               .device = 0x51c9,
+               .codec_hid =  &essx_83x6,
+       },
+       {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
                .device = 0x51c9,
        },
index f0c4912..4c69cb6 100644 (file)
@@ -584,7 +584,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
        if (drv_data->dmic_cpu_id)
                num_links++;
 
-       links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * num_links, GFP_KERNEL);
+       links = devm_kcalloc(dev, num_links, sizeof(struct snd_soc_dai_link), GFP_KERNEL);
        if (!links)
                return -ENOMEM;
 
@@ -749,7 +749,7 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
        if (drv_data->dmic_cpu_id)
                num_links++;
 
-       links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * num_links, GFP_KERNEL);
+       links = devm_kcalloc(dev, num_links, sizeof(struct snd_soc_dai_link), GFP_KERNEL);
        if (!links)
                return -ENOMEM;
 
index ef2ce08..a0c84cd 100644 (file)
@@ -107,7 +107,7 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id
                goto unregister_dmic_dev;
        }
 
-       res = devm_kzalloc(&pci->dev, sizeof(struct resource) * num_res, GFP_KERNEL);
+       res = devm_kcalloc(&pci->dev, num_res, sizeof(struct resource), GFP_KERNEL);
        if (!res) {
                ret = -ENOMEM;
                goto unregister_dmic_dev;
index 4ef8cd1..7a5260f 100644 (file)
@@ -161,8 +161,6 @@ static struct reg_default max98390_reg_defaults[] = {
        {MAX98390_R23FF_GLOBAL_EN, 0x00},
 };
 
-static int max98390_dsm_calibrate(struct snd_soc_component *component);
-
 static int max98390_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
        struct snd_soc_component *component = codec_dai->component;
@@ -635,20 +633,49 @@ static int max98390_dsm_calib_get(struct snd_kcontrol *kcontrol,
 static int max98390_dsm_calib_put(struct snd_kcontrol *kcontrol,
                struct snd_ctl_elem_value *ucontrol)
 {
-       unsigned int val;
-       struct snd_soc_component *component =
-               snd_soc_kcontrol_component(kcontrol);
-       struct max98390_priv *max98390 =
-               snd_soc_component_get_drvdata(component);
+       struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+       struct max98390_priv *max98390 = snd_soc_component_get_drvdata(component);
+       struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+       unsigned int rdc, rdc_cal_result, rdc_integer, rdc_factor, temp, val;
+
+       snd_soc_dapm_mutex_lock(dapm);
 
        regmap_read(max98390->regmap, MAX98390_R23FF_GLOBAL_EN, &val);
-       if (val == 0x1)
-               max98390_dsm_calibrate(component);
-       else {
-               dev_err(component->dev, "AMP is not ready to run calibration\n");
-               return -ECANCELED;
+       if (!val) {
+               /* Enable the codec for the duration of calibration readout */
+               regmap_update_bits(max98390->regmap, MAX98390_R203A_AMP_EN,
+                                  MAX98390_AMP_EN_MASK, 1);
+               regmap_update_bits(max98390->regmap, MAX98390_R23FF_GLOBAL_EN,
+                                  MAX98390_GLOBAL_EN_MASK, 1);
+       }
+
+       regmap_read(max98390->regmap, THERMAL_RDC_RD_BACK_BYTE1, &rdc);
+       regmap_read(max98390->regmap, THERMAL_RDC_RD_BACK_BYTE0, &rdc_cal_result);
+       regmap_read(max98390->regmap, MAX98390_MEAS_ADC_CH2_READ, &temp);
+
+       if (!val) {
+               /* Disable the codec if it was disabled */
+               regmap_update_bits(max98390->regmap, MAX98390_R23FF_GLOBAL_EN,
+                                  MAX98390_GLOBAL_EN_MASK, 0);
+               regmap_update_bits(max98390->regmap, MAX98390_R203A_AMP_EN,
+                                  MAX98390_AMP_EN_MASK, 0);
        }
 
+       snd_soc_dapm_mutex_unlock(dapm);
+
+       rdc_cal_result |= (rdc << 8) & 0x0000FFFF;
+       if (rdc_cal_result)
+               max98390->ref_rdc_value = 268435456U / rdc_cal_result;
+
+       max98390->ambient_temp_value = temp * 52 - 1188;
+
+       rdc_integer =  rdc_cal_result * 937  / 65536;
+       rdc_factor = ((rdc_cal_result * 937 * 100) / 65536) - (rdc_integer * 100);
+
+       dev_info(component->dev,
+                "rdc resistance about %d.%02d ohm, reg=0x%X temp reg=0x%X\n",
+                rdc_integer, rdc_factor, rdc_cal_result, temp);
+
        return 0;
 }
 
@@ -828,34 +855,6 @@ err:
        return ret;
 }
 
-static int max98390_dsm_calibrate(struct snd_soc_component *component)
-{
-       unsigned int rdc, rdc_cal_result, temp;
-       unsigned int rdc_integer, rdc_factor;
-       struct max98390_priv *max98390 =
-               snd_soc_component_get_drvdata(component);
-
-       regmap_read(max98390->regmap,
-               THERMAL_RDC_RD_BACK_BYTE1, &rdc);
-       regmap_read(max98390->regmap,
-               THERMAL_RDC_RD_BACK_BYTE0, &rdc_cal_result);
-       rdc_cal_result |= (rdc << 8) & 0x0000FFFF;
-       if (rdc_cal_result)
-               max98390->ref_rdc_value = 268435456U / rdc_cal_result;
-
-       regmap_read(max98390->regmap, MAX98390_MEAS_ADC_CH2_READ, &temp);
-       max98390->ambient_temp_value = temp * 52 - 1188;
-
-       rdc_integer =  rdc_cal_result * 937  / 65536;
-       rdc_factor = ((rdc_cal_result * 937 * 100) / 65536)
-                                       - (rdc_integer * 100);
-
-       dev_info(component->dev, "rdc resistance about %d.%02d ohm, reg=0x%X temp reg=0x%X\n",
-                rdc_integer, rdc_factor, rdc_cal_result, temp);
-
-       return 0;
-}
-
 static void max98390_init_regs(struct snd_soc_component *component)
 {
        struct max98390_priv *max98390 =
index eb47e7c..2831f2f 100644 (file)
@@ -739,6 +739,7 @@ static void rt5682s_disable_push_button_irq(struct snd_soc_component *component)
  */
 static int rt5682s_headset_detect(struct snd_soc_component *component, int jack_insert)
 {
+       struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component);
        unsigned int val, count;
        int jack_type = 0;
 
@@ -805,12 +806,10 @@ static int rt5682s_headset_detect(struct snd_soc_component *component, int jack_
                snd_soc_component_update_bits(component, RT5682S_CBJ_CTRL_1,
                        RT5682S_TRIG_JD_MASK, RT5682S_TRIG_JD_LOW);
 
-               if (!snd_soc_dapm_get_pin_status(&component->dapm, "MICBIAS"))
-                       snd_soc_component_update_bits(component,
-                               RT5682S_PWR_ANLG_1, RT5682S_PWR_MB, 0);
-               if (!snd_soc_dapm_get_pin_status(&component->dapm, "Vref2"))
+               if (!rt5682s->wclk_enabled) {
                        snd_soc_component_update_bits(component,
-                               RT5682S_PWR_ANLG_1, RT5682S_PWR_VREF2, 0);
+                               RT5682S_PWR_ANLG_1, RT5682S_PWR_VREF2 | RT5682S_PWR_MB, 0);
+               }
 
                snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_3,
                        RT5682S_PWR_CBJ, 0);
@@ -845,6 +844,7 @@ static void rt5682s_jack_detect_handler(struct work_struct *work)
 
        snd_soc_dapm_mutex_lock(dapm);
        mutex_lock(&rt5682s->calibrate_mutex);
+       mutex_lock(&rt5682s->wclk_mutex);
 
        val = snd_soc_component_read(rt5682s->component, RT5682S_AJD1_CTRL)
                & RT5682S_JDH_RS_MASK;
@@ -900,6 +900,7 @@ static void rt5682s_jack_detect_handler(struct work_struct *work)
                rt5682s->irq_work_delay_time = 50;
        }
 
+       mutex_unlock(&rt5682s->wclk_mutex);
        mutex_unlock(&rt5682s->calibrate_mutex);
        snd_soc_dapm_mutex_unlock(dapm);
 
@@ -1154,29 +1155,52 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
-static int set_filter_clk(struct snd_soc_dapm_widget *w,
+
+static int rt5682s_set_pllb_power(struct rt5682s_priv *rt5682s, int on)
+{
+       struct snd_soc_component *component = rt5682s->component;
+
+       if (on) {
+               snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_3,
+                       RT5682S_PWR_LDO_PLLB | RT5682S_PWR_BIAS_PLLB | RT5682S_PWR_PLLB,
+                       RT5682S_PWR_LDO_PLLB | RT5682S_PWR_BIAS_PLLB | RT5682S_PWR_PLLB);
+               snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_3,
+                       RT5682S_RSTB_PLLB, RT5682S_RSTB_PLLB);
+       } else {
+               snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_3,
+                       RT5682S_PWR_LDO_PLLB | RT5682S_PWR_BIAS_PLLB |
+                       RT5682S_RSTB_PLLB | RT5682S_PWR_PLLB, 0);
+       }
+
+       return 0;
+}
+
+static int set_pllb_event(struct snd_soc_dapm_widget *w,
                struct snd_kcontrol *kcontrol, int event)
 {
        struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
        struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component);
-       int ref, val, reg, idx;
-       static const int div_f[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48};
-       static const int div_o[] = {1, 2, 4, 6, 8, 12, 16, 24, 32, 48};
+       int on = 0;
 
-       val = snd_soc_component_read(component, RT5682S_GPIO_CTRL_1)
-                       & RT5682S_GP4_PIN_MASK;
+       if (rt5682s->wclk_enabled)
+               return 0;
 
-       if (w->shift == RT5682S_PWR_ADC_S1F_BIT && val == RT5682S_GP4_PIN_ADCDAT2)
-               ref = 256 * rt5682s->lrck[RT5682S_AIF2];
-       else
-               ref = 256 * rt5682s->lrck[RT5682S_AIF1];
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               on = 1;
 
-       idx = rt5682s_div_sel(rt5682s, ref, div_f, ARRAY_SIZE(div_f));
+       rt5682s_set_pllb_power(rt5682s, on);
 
-       if (w->shift == RT5682S_PWR_ADC_S1F_BIT)
-               reg = RT5682S_PLL_TRACK_3;
-       else
-               reg = RT5682S_PLL_TRACK_2;
+       return 0;
+}
+
+static void rt5682s_set_filter_clk(struct rt5682s_priv *rt5682s, int reg, int ref)
+{
+       struct snd_soc_component *component = rt5682s->component;
+       int idx;
+       static const int div_f[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48};
+       static const int div_o[] = {1, 2, 4, 6, 8, 12, 16, 24, 32, 48};
+
+       idx = rt5682s_div_sel(rt5682s, ref, div_f, ARRAY_SIZE(div_f));
 
        snd_soc_component_update_bits(component, reg,
                RT5682S_FILTER_CLK_DIV_MASK, idx << RT5682S_FILTER_CLK_DIV_SFT);
@@ -1190,6 +1214,29 @@ static int set_filter_clk(struct snd_soc_dapm_widget *w,
        snd_soc_component_update_bits(component, RT5682S_ADDA_CLK_1,
                RT5682S_ADC_OSR_MASK | RT5682S_DAC_OSR_MASK,
                (idx << RT5682S_ADC_OSR_SFT) | (idx << RT5682S_DAC_OSR_SFT));
+}
+
+static int set_filter_clk(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component);
+       int ref, reg, val;
+
+       val = snd_soc_component_read(component, RT5682S_GPIO_CTRL_1)
+                       & RT5682S_GP4_PIN_MASK;
+
+       if (w->shift == RT5682S_PWR_ADC_S1F_BIT && val == RT5682S_GP4_PIN_ADCDAT2)
+               ref = 256 * rt5682s->lrck[RT5682S_AIF2];
+       else
+               ref = 256 * rt5682s->lrck[RT5682S_AIF1];
+
+       if (w->shift == RT5682S_PWR_ADC_S1F_BIT)
+               reg = RT5682S_PLL_TRACK_3;
+       else
+               reg = RT5682S_PLL_TRACK_2;
+
+       rt5682s_set_filter_clk(rt5682s, reg, ref);
 
        return 0;
 }
@@ -1218,13 +1265,9 @@ static int set_dmic_power(struct snd_soc_dapm_widget *w,
                break;
 
        case SND_SOC_DAPM_POST_PMD:
-               if (!rt5682s->jack_type) {
-                       if (!snd_soc_dapm_get_pin_status(w->dapm, "MICBIAS"))
-                               snd_soc_component_update_bits(component,
-                                       RT5682S_PWR_ANLG_1, RT5682S_PWR_MB, 0);
-                       if (!snd_soc_dapm_get_pin_status(w->dapm, "Vref2"))
-                               snd_soc_component_update_bits(component,
-                                       RT5682S_PWR_ANLG_1, RT5682S_PWR_VREF2, 0);
+               if (!rt5682s->jack_type && !rt5682s->wclk_enabled) {
+                       snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1,
+                               RT5682S_PWR_VREF2 | RT5682S_PWR_MB, 0);
                }
                break;
        }
@@ -1232,41 +1275,58 @@ static int set_dmic_power(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
-static int set_i2s_clk(struct snd_soc_dapm_widget *w,
-               struct snd_kcontrol *kcontrol, int event)
+static void rt5682s_set_i2s(struct rt5682s_priv *rt5682s, int id, int on)
 {
-       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
-       struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component);
-       int pre_div, id;
-       unsigned int reg, mask, sft;
-
-       if (event != SND_SOC_DAPM_PRE_PMU)
-               return 0;
-
-       if (w->shift == RT5682S_PWR_I2S2_BIT) {
-               id = RT5682S_AIF2;
-               reg = RT5682S_I2S2_M_CLK_CTRL_1;
-               mask = RT5682S_I2S2_M_D_MASK;
-               sft = RT5682S_I2S2_M_D_SFT;
+       struct snd_soc_component *component = rt5682s->component;
+       int pre_div;
+       unsigned int p_reg, p_mask, p_sft;
+       unsigned int c_reg, c_mask, c_sft;
+
+       if (id == RT5682S_AIF1) {
+               c_reg = RT5682S_ADDA_CLK_1;
+               c_mask = RT5682S_I2S_M_D_MASK;
+               c_sft = RT5682S_I2S_M_D_SFT;
+               p_reg = RT5682S_PWR_DIG_1;
+               p_mask = RT5682S_PWR_I2S1;
+               p_sft = RT5682S_PWR_I2S1_BIT;
        } else {
-               id = RT5682S_AIF1;
-               reg = RT5682S_ADDA_CLK_1;
-               mask = RT5682S_I2S_M_D_MASK;
-               sft = RT5682S_I2S_M_D_SFT;
+               c_reg = RT5682S_I2S2_M_CLK_CTRL_1;
+               c_mask = RT5682S_I2S2_M_D_MASK;
+               c_sft = RT5682S_I2S2_M_D_SFT;
+               p_reg = RT5682S_PWR_DIG_1;
+               p_mask = RT5682S_PWR_I2S2;
+               p_sft = RT5682S_PWR_I2S2_BIT;
        }
 
-       if (!rt5682s->master[id])
-               return 0;
+       if (on && rt5682s->master[id]) {
+               pre_div = get_clk_info(rt5682s->sysclk, rt5682s->lrck[id]);
+               if (pre_div < 0) {
+                       dev_err(component->dev, "get pre_div failed\n");
+                       return;
+               }
 
-       pre_div = get_clk_info(rt5682s->sysclk, rt5682s->lrck[id]);
-       if (pre_div < 0) {
-               dev_err(component->dev, "get pre_div failed\n");
-               return -EINVAL;
+               dev_dbg(component->dev, "lrck is %dHz and pre_div is %d for iis %d master\n",
+                       rt5682s->lrck[id], pre_div, id);
+               snd_soc_component_update_bits(component, c_reg, c_mask, pre_div << c_sft);
        }
 
-       dev_dbg(component->dev, "lrck is %dHz and pre_div is %d for iis %d master\n",
-               rt5682s->lrck[id], pre_div, id);
-       snd_soc_component_update_bits(component, reg, mask, pre_div << sft);
+       snd_soc_component_update_bits(component, p_reg, p_mask, on << p_sft);
+}
+
+static int set_i2s_event(struct snd_soc_dapm_widget *w,
+               struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component);
+       int on = 0;
+
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               on = 1;
+
+       if (!strcmp(w->name, "I2S1") && !rt5682s->wclk_enabled)
+               rt5682s_set_i2s(rt5682s, RT5682S_AIF1, on);
+       else if (!strcmp(w->name, "I2S2"))
+               rt5682s_set_i2s(rt5682s, RT5682S_AIF2, on);
 
        return 0;
 }
@@ -1615,26 +1675,18 @@ static const struct snd_soc_dapm_widget rt5682s_dapm_widgets[] = {
                RT5682S_PWR_LDO_MB2_BIT, 0, NULL, 0),
        SND_SOC_DAPM_SUPPLY("LDO", RT5682S_PWR_ANLG_3,
                RT5682S_PWR_LDO_BIT, 0, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("Vref2", SND_SOC_NOPM, 0, 0, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("MICBIAS", SND_SOC_NOPM, 0, 0, NULL, 0),
 
        /* PLL Powers */
        SND_SOC_DAPM_SUPPLY_S("PLLA_LDO", 0, RT5682S_PWR_ANLG_3,
                RT5682S_PWR_LDO_PLLA_BIT, 0, NULL, 0),
-       SND_SOC_DAPM_SUPPLY_S("PLLB_LDO", 0, RT5682S_PWR_ANLG_3,
-               RT5682S_PWR_LDO_PLLB_BIT, 0, NULL, 0),
        SND_SOC_DAPM_SUPPLY_S("PLLA_BIAS", 0, RT5682S_PWR_ANLG_3,
                RT5682S_PWR_BIAS_PLLA_BIT, 0, NULL, 0),
-       SND_SOC_DAPM_SUPPLY_S("PLLB_BIAS", 0, RT5682S_PWR_ANLG_3,
-               RT5682S_PWR_BIAS_PLLB_BIT, 0, NULL, 0),
        SND_SOC_DAPM_SUPPLY_S("PLLA", 0, RT5682S_PWR_ANLG_3,
                RT5682S_PWR_PLLA_BIT, 0, NULL, 0),
-       SND_SOC_DAPM_SUPPLY_S("PLLB", 0, RT5682S_PWR_ANLG_3,
-               RT5682S_PWR_PLLB_BIT, 0, set_filter_clk, SND_SOC_DAPM_PRE_PMU),
        SND_SOC_DAPM_SUPPLY_S("PLLA_RST", 1, RT5682S_PWR_ANLG_3,
                RT5682S_RSTB_PLLA_BIT, 0, NULL, 0),
-       SND_SOC_DAPM_SUPPLY_S("PLLB_RST", 1, RT5682S_PWR_ANLG_3,
-               RT5682S_RSTB_PLLB_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("PLLB", SND_SOC_NOPM, 0, 0,
+               set_pllb_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
        /* ASRC */
        SND_SOC_DAPM_SUPPLY_S("DAC STO1 ASRC", 1, RT5682S_PLL_TRACK_1,
@@ -1720,10 +1772,10 @@ static const struct snd_soc_dapm_widget rt5682s_dapm_widgets[] = {
        SND_SOC_DAPM_PGA("Stereo1 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
 
        /* Digital Interface */
-       SND_SOC_DAPM_SUPPLY("I2S1", RT5682S_PWR_DIG_1, RT5682S_PWR_I2S1_BIT,
-               0, set_i2s_clk, SND_SOC_DAPM_PRE_PMU),
-       SND_SOC_DAPM_SUPPLY("I2S2", RT5682S_PWR_DIG_1, RT5682S_PWR_I2S2_BIT,
-               0, set_i2s_clk, SND_SOC_DAPM_PRE_PMU),
+       SND_SOC_DAPM_SUPPLY("I2S1", SND_SOC_NOPM, 0, 0,
+               set_i2s_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_SUPPLY("I2S2", SND_SOC_NOPM, 0, 0,
+               set_i2s_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
        SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0),
        SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0),
 
@@ -1801,9 +1853,6 @@ static const struct snd_soc_dapm_route rt5682s_dapm_routes[] = {
        {"PLLA", NULL, "PLLA_LDO"},
        {"PLLA", NULL, "PLLA_BIAS"},
        {"PLLA", NULL, "PLLA_RST"},
-       {"PLLB", NULL, "PLLB_LDO"},
-       {"PLLB", NULL, "PLLB_BIAS"},
-       {"PLLB", NULL, "PLLB_RST"},
 
        /*ASRC*/
        {"ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc},
@@ -2431,12 +2480,15 @@ static int rt5682s_set_bias_level(struct snd_soc_component *component,
                        RT5682S_PWR_LDO, RT5682S_PWR_LDO);
                break;
        case SND_SOC_BIAS_STANDBY:
-               regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1,
-                       RT5682S_DIG_GATE_CTRL, RT5682S_DIG_GATE_CTRL);
+               if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
+                       regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1,
+                               RT5682S_DIG_GATE_CTRL, RT5682S_DIG_GATE_CTRL);
                break;
        case SND_SOC_BIAS_OFF:
-               regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1,
-                       RT5682S_DIG_GATE_CTRL | RT5682S_PWR_LDO, 0);
+               regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1, RT5682S_PWR_LDO, 0);
+               if (!rt5682s->wclk_enabled)
+                       regmap_update_bits(rt5682s->regmap, RT5682S_PWR_DIG_1,
+                               RT5682S_DIG_GATE_CTRL, 0);
                break;
        case SND_SOC_BIAS_ON:
                break;
@@ -2464,30 +2516,34 @@ static int rt5682s_wclk_prepare(struct clk_hw *hw)
        struct rt5682s_priv *rt5682s =
                container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_WCLK_IDX]);
        struct snd_soc_component *component = rt5682s->component;
-       struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+       int ref, reg;
 
        if (!rt5682s_clk_check(rt5682s))
                return -EINVAL;
 
-       snd_soc_dapm_mutex_lock(dapm);
-
-       snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS");
-       snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1,
-               RT5682S_PWR_MB, RT5682S_PWR_MB);
+       mutex_lock(&rt5682s->wclk_mutex);
 
-       snd_soc_dapm_force_enable_pin_unlocked(dapm, "Vref2");
        snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1,
-               RT5682S_PWR_VREF2 | RT5682S_PWR_FV2, RT5682S_PWR_VREF2);
+               RT5682S_PWR_VREF2 | RT5682S_PWR_FV2 | RT5682S_PWR_MB,
+               RT5682S_PWR_VREF2 | RT5682S_PWR_MB);
        usleep_range(15000, 20000);
        snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1,
                RT5682S_PWR_FV2, RT5682S_PWR_FV2);
 
-       snd_soc_dapm_force_enable_pin_unlocked(dapm, "I2S1");
-       /* Only need to power PLLB due to the rate set restriction */
-       snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLLB");
-       snd_soc_dapm_sync_unlocked(dapm);
+       /* Set and power on I2S1 */
+       snd_soc_component_update_bits(component, RT5682S_PWR_DIG_1,
+               RT5682S_DIG_GATE_CTRL, RT5682S_DIG_GATE_CTRL);
+       rt5682s_set_i2s(rt5682s, RT5682S_AIF1, 1);
 
-       snd_soc_dapm_mutex_unlock(dapm);
+       /* Only need to power on PLLB due to the rate set restriction */
+       reg = RT5682S_PLL_TRACK_2;
+       ref = 256 * rt5682s->lrck[RT5682S_AIF1];
+       rt5682s_set_filter_clk(rt5682s, reg, ref);
+       rt5682s_set_pllb_power(rt5682s, 1);
+
+       rt5682s->wclk_enabled = 1;
+
+       mutex_unlock(&rt5682s->wclk_mutex);
 
        return 0;
 }
@@ -2497,24 +2553,27 @@ static void rt5682s_wclk_unprepare(struct clk_hw *hw)
        struct rt5682s_priv *rt5682s =
                container_of(hw, struct rt5682s_priv, dai_clks_hw[RT5682S_DAI_WCLK_IDX]);
        struct snd_soc_component *component = rt5682s->component;
-       struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 
        if (!rt5682s_clk_check(rt5682s))
                return;
 
-       snd_soc_dapm_mutex_lock(dapm);
+       mutex_lock(&rt5682s->wclk_mutex);
 
-       snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS");
-       snd_soc_dapm_disable_pin_unlocked(dapm, "Vref2");
        if (!rt5682s->jack_type)
                snd_soc_component_update_bits(component, RT5682S_PWR_ANLG_1,
                        RT5682S_PWR_VREF2 | RT5682S_PWR_FV2 | RT5682S_PWR_MB, 0);
 
-       snd_soc_dapm_disable_pin_unlocked(dapm, "I2S1");
-       snd_soc_dapm_disable_pin_unlocked(dapm, "PLLB");
-       snd_soc_dapm_sync_unlocked(dapm);
+       /* Power down I2S1 */
+       rt5682s_set_i2s(rt5682s, RT5682S_AIF1, 0);
+       snd_soc_component_update_bits(component, RT5682S_PWR_DIG_1,
+               RT5682S_DIG_GATE_CTRL, 0);
 
-       snd_soc_dapm_mutex_unlock(dapm);
+       /* Power down PLLB */
+       rt5682s_set_pllb_power(rt5682s, 0);
+
+       rt5682s->wclk_enabled = 0;
+
+       mutex_unlock(&rt5682s->wclk_mutex);
 }
 
 static unsigned long rt5682s_wclk_recalc_rate(struct clk_hw *hw,
@@ -2805,7 +2864,6 @@ static inline int rt5682s_dai_probe_clks(struct snd_soc_component *component)
 static int rt5682s_probe(struct snd_soc_component *component)
 {
        struct rt5682s_priv *rt5682s = snd_soc_component_get_drvdata(component);
-       struct snd_soc_dapm_context *dapm = &component->dapm;
        int ret;
 
        rt5682s->component = component;
@@ -2814,9 +2872,6 @@ static int rt5682s_probe(struct snd_soc_component *component)
        if (ret)
                return ret;
 
-       snd_soc_dapm_disable_pin(dapm, "MICBIAS");
-       snd_soc_dapm_disable_pin(dapm, "Vref2");
-       snd_soc_dapm_sync(dapm);
        return 0;
 }
 
@@ -3113,6 +3168,7 @@ static int rt5682s_i2c_probe(struct i2c_client *i2c)
 
        mutex_init(&rt5682s->calibrate_mutex);
        mutex_init(&rt5682s->sar_mutex);
+       mutex_init(&rt5682s->wclk_mutex);
        rt5682s_calibrate(rt5682s);
 
        regmap_update_bits(rt5682s->regmap, RT5682S_MICBIAS_2,
index 7353831..824dc65 100644 (file)
@@ -1450,6 +1450,7 @@ struct rt5682s_priv {
        struct delayed_work jd_check_work;
        struct mutex calibrate_mutex;
        struct mutex sar_mutex;
+       struct mutex wclk_mutex;
 
 #ifdef CONFIG_COMMON_CLK
        struct clk_hw dai_clks_hw[RT5682S_DAI_NUM_CLKS];
@@ -1469,6 +1470,7 @@ struct rt5682s_priv {
 
        int jack_type;
        int irq_work_delay_time;
+       int wclk_enabled;
 };
 
 int rt5682s_sel_asrc_clk_src(struct snd_soc_component *component,
index 7fc1c96..275aba8 100644 (file)
@@ -44,6 +44,8 @@ static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb };
 
 #define DEFAULT_RXCLK_SRC      1
 
+#define RX_SAMPLE_RATE_KCONTROL "RX Sample Rate"
+
 /**
  * struct fsl_spdif_soc_data: soc specific data
  *
@@ -98,6 +100,8 @@ struct spdif_mixer_control {
  * @soc: SPDIF soc data
  * @fsl_spdif_control: SPDIF control data
  * @cpu_dai_drv: cpu dai driver
+ * @snd_card: sound card pointer
+ * @rxrate_kcontrol: kcontrol for RX Sample Rate
  * @pdev: platform device pointer
  * @regmap: regmap handler
  * @dpll_locked: dpll lock flag
@@ -122,6 +126,8 @@ struct fsl_spdif_priv {
        const struct fsl_spdif_soc_data *soc;
        struct spdif_mixer_control fsl_spdif_control;
        struct snd_soc_dai_driver cpu_dai_drv;
+       struct snd_card *snd_card;
+       struct snd_kcontrol *rxrate_kcontrol;
        struct platform_device *pdev;
        struct regmap *regmap;
        bool dpll_locked;
@@ -226,6 +232,12 @@ static void spdif_irq_dpll_lock(struct fsl_spdif_priv *spdif_priv)
                        locked ? "locked" : "loss lock");
 
        spdif_priv->dpll_locked = locked ? true : false;
+
+       if (spdif_priv->snd_card && spdif_priv->rxrate_kcontrol) {
+               snd_ctl_notify(spdif_priv->snd_card,
+                              SNDRV_CTL_EVENT_MASK_VALUE,
+                              &spdif_priv->rxrate_kcontrol->id);
+       }
 }
 
 /* Receiver found illegal symbol interrupt handler */
@@ -1197,7 +1209,7 @@ static struct snd_kcontrol_new fsl_spdif_ctrls[] = {
        /* DPLL lock info get controller */
        {
                .iface = SNDRV_CTL_ELEM_IFACE_PCM,
-               .name = "RX Sample Rate",
+               .name = RX_SAMPLE_RATE_KCONTROL,
                .access = SNDRV_CTL_ELEM_ACCESS_READ |
                        SNDRV_CTL_ELEM_ACCESS_VOLATILE,
                .info = fsl_spdif_rxrate_info,
@@ -1251,6 +1263,13 @@ static int fsl_spdif_dai_probe(struct snd_soc_dai *dai)
                snd_soc_add_dai_controls(dai, fsl_spdif_ctrls_rcm,
                                         ARRAY_SIZE(fsl_spdif_ctrls_rcm));
 
+       spdif_private->snd_card = dai->component->card->snd_card;
+       spdif_private->rxrate_kcontrol = snd_soc_card_get_kcontrol(dai->component->card,
+                                                                  RX_SAMPLE_RATE_KCONTROL);
+       if (!spdif_private->rxrate_kcontrol)
+               dev_err(&spdif_private->pdev->dev, "failed to get %s kcontrol\n",
+                       RX_SAMPLE_RATE_KCONTROL);
+
        /*Clear the val bit for Tx*/
        regmap_update_bits(spdif_private->regmap, REG_SPDIF_SCR,
                           SCR_VAL_MASK, SCR_VAL_CLEAR);
index d2fc41d..073663b 100644 (file)
@@ -42,6 +42,7 @@ static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int
                dl[i].dpcm_capture = 1;
                dl[i].platforms = platform;
                dl[i].num_platforms = 1;
+               dl[i].ignore_pmdown_time = 1;
 
                dl[i].codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);
                dl[i].cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);
index 85ffd06..e38bd28 100644 (file)
@@ -445,9 +445,9 @@ static int create_hdmi_dai_links(struct device *dev,
        if (hdmi_num <= 0)
                return 0;
 
-       idisp_components = devm_kzalloc(dev,
-                                       sizeof(struct snd_soc_dai_link_component) *
-                                       hdmi_num, GFP_KERNEL);
+       idisp_components = devm_kcalloc(dev,
+                                       hdmi_num,
+                                       sizeof(struct snd_soc_dai_link_component), GFP_KERNEL);
        if (!idisp_components)
                goto devm_err;
 
@@ -543,10 +543,10 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
        struct snd_soc_dai_link *links;
        int ret, id = 0, link_seq;
 
-       links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) *
-                            sof_audio_card_cs42l42.num_links, GFP_KERNEL);
-       cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) *
-                            sof_audio_card_cs42l42.num_links, GFP_KERNEL);
+       links = devm_kcalloc(dev, sof_audio_card_cs42l42.num_links,
+                           sizeof(struct snd_soc_dai_link), GFP_KERNEL);
+       cpus = devm_kcalloc(dev, sof_audio_card_cs42l42.num_links,
+                           sizeof(struct snd_soc_dai_link_component), GFP_KERNEL);
        if (!links || !cpus)
                goto devm_err;
 
index 606cc32..fbb42e5 100644 (file)
@@ -481,9 +481,10 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
 
        /* HDMI */
        if (hdmi_num > 0) {
-               idisp_components = devm_kzalloc(dev,
-                                               sizeof(struct snd_soc_dai_link_component) *
-                                               hdmi_num, GFP_KERNEL);
+               idisp_components = devm_kcalloc(dev,
+                                               hdmi_num,
+                                               sizeof(struct snd_soc_dai_link_component),
+                                               GFP_KERNEL);
                if (!idisp_components)
                        goto devm_err;
        }
index 8d7e5ba..5585c21 100644 (file)
@@ -355,10 +355,10 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
        struct snd_soc_dai_link *links;
        int i, id = 0;
 
-       links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) *
-                            sof_audio_card_nau8825.num_links, GFP_KERNEL);
-       cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) *
-                            sof_audio_card_nau8825.num_links, GFP_KERNEL);
+       links = devm_kcalloc(dev, sof_audio_card_nau8825.num_links,
+                           sizeof(struct snd_soc_dai_link), GFP_KERNEL);
+       cpus = devm_kcalloc(dev, sof_audio_card_nau8825.num_links,
+                           sizeof(struct snd_soc_dai_link_component), GFP_KERNEL);
        if (!links || !cpus)
                goto devm_err;
 
@@ -421,9 +421,10 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
 
        /* HDMI */
        if (hdmi_num > 0) {
-               idisp_components = devm_kzalloc(dev,
-                                               sizeof(struct snd_soc_dai_link_component) *
-                                               hdmi_num, GFP_KERNEL);
+               idisp_components = devm_kcalloc(dev,
+                                               hdmi_num,
+                                               sizeof(struct snd_soc_dai_link_component),
+                                               GFP_KERNEL);
                if (!idisp_components)
                        goto devm_err;
        }
index 0459653..1bf9455 100644 (file)
@@ -600,10 +600,10 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
        struct snd_soc_dai_link *links;
        int i, id = 0;
 
-       links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) *
-                            sof_audio_card_rt5682.num_links, GFP_KERNEL);
-       cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) *
-                            sof_audio_card_rt5682.num_links, GFP_KERNEL);
+       links = devm_kcalloc(dev, sof_audio_card_rt5682.num_links,
+                           sizeof(struct snd_soc_dai_link), GFP_KERNEL);
+       cpus = devm_kcalloc(dev, sof_audio_card_rt5682.num_links,
+                           sizeof(struct snd_soc_dai_link_component), GFP_KERNEL);
        if (!links || !cpus)
                goto devm_err;
 
@@ -687,9 +687,10 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
 
        /* HDMI */
        if (hdmi_num > 0) {
-               idisp_components = devm_kzalloc(dev,
-                                  sizeof(struct snd_soc_dai_link_component) *
-                                  hdmi_num, GFP_KERNEL);
+               idisp_components = devm_kcalloc(dev,
+                                  hdmi_num,
+                                  sizeof(struct snd_soc_dai_link_component),
+                                  GFP_KERNEL);
                if (!idisp_components)
                        goto devm_err;
        }
index 4a762e0..94d25ae 100644 (file)
@@ -210,10 +210,10 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
        struct snd_soc_dai_link *links;
        int i, id = 0;
 
-       links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) *
-                                       sof_ssp_amp_card.num_links, GFP_KERNEL);
-       cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) *
-                                       sof_ssp_amp_card.num_links, GFP_KERNEL);
+       links = devm_kcalloc(dev, sof_ssp_amp_card.num_links,
+                                       sizeof(struct snd_soc_dai_link), GFP_KERNEL);
+       cpus = devm_kcalloc(dev, sof_ssp_amp_card.num_links,
+                                       sizeof(struct snd_soc_dai_link_component), GFP_KERNEL);
        if (!links || !cpus)
                return NULL;
 
@@ -306,9 +306,10 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev,
        if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) {
                /* HDMI */
                if (hdmi_num > 0) {
-                       idisp_components = devm_kzalloc(dev,
-                                          sizeof(struct snd_soc_dai_link_component) *
-                                          hdmi_num, GFP_KERNEL);
+                       idisp_components = devm_kcalloc(dev,
+                                          hdmi_num,
+                                          sizeof(struct snd_soc_dai_link_component),
+                                          GFP_KERNEL);
                        if (!idisp_components)
                                goto devm_err;
                }
index 7506534..1b0252e 100644 (file)
@@ -173,6 +173,18 @@ config SND_SOC_SM8250
          SM8250 SoC-based systems.
          Say Y if you want to use audio device on this SoCs.
 
+config SND_SOC_SC8280XP
+       tristate "SoC Machine driver for SC8280XP boards"
+       depends on QCOM_APR || COMPILE_TEST
+       depends on SOUNDWIRE
+       depends on COMMON_CLK
+       select SND_SOC_QDSP6
+       select SND_SOC_QCOM_COMMON
+       help
+         To add support for audio on Qualcomm Technologies Inc.
+         SC8280XP SoC-based systems.
+         Say Y if you want to use audio device on this SoCs.
+
 config SND_SOC_SC7180
        tristate "SoC Machine driver for SC7180 boards"
        depends on I2C && GPIOLIB
index 8b7b876..8b97172 100644 (file)
@@ -26,6 +26,7 @@ snd-soc-sc7180-objs := sc7180.o
 snd-soc-sc7280-objs := sc7280.o
 snd-soc-sdm845-objs := sdm845.o
 snd-soc-sm8250-objs := sm8250.o
+snd-soc-sc8280xp-objs := sc8280xp.o
 snd-soc-qcom-common-objs := common.o
 
 obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o
@@ -33,6 +34,7 @@ obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o
 obj-$(CONFIG_SND_SOC_MSM8996) += snd-soc-apq8096.o
 obj-$(CONFIG_SND_SOC_SC7180) += snd-soc-sc7180.o
 obj-$(CONFIG_SND_SOC_SC7280) += snd-soc-sc7280.o
+obj-$(CONFIG_SND_SOC_SC8280XP) += snd-soc-sc8280xp.o
 obj-$(CONFIG_SND_SOC_SDM845) += snd-soc-sdm845.o
 obj-$(CONFIG_SND_SOC_SM8250) += snd-soc-sm8250.o
 obj-$(CONFIG_SND_SOC_QCOM_COMMON) += snd-soc-qcom-common.o
index c407684..69dd3b5 100644 (file)
@@ -3,6 +3,9 @@
 // Copyright (c) 2018, The Linux Foundation. All rights reserved.
 
 #include <linux/module.h>
+#include <sound/jack.h>
+#include <linux/input-event-codes.h>
+#include "qdsp6/q6afe.h"
 #include "common.h"
 
 int qcom_snd_parse_of(struct snd_soc_card *card)
@@ -175,6 +178,174 @@ err_put_np:
        of_node_put(np);
        return ret;
 }
-EXPORT_SYMBOL(qcom_snd_parse_of);
+EXPORT_SYMBOL_GPL(qcom_snd_parse_of);
 
+#if IS_ENABLED(CONFIG_SOUNDWIRE)
+int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
+                        struct sdw_stream_runtime *sruntime,
+                        bool *stream_prepared)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       int ret;
+
+       if (!sruntime)
+               return 0;
+
+       switch (cpu_dai->id) {
+       case WSA_CODEC_DMA_RX_0:
+       case WSA_CODEC_DMA_RX_1:
+       case RX_CODEC_DMA_RX_0:
+       case RX_CODEC_DMA_RX_1:
+       case TX_CODEC_DMA_TX_0:
+       case TX_CODEC_DMA_TX_1:
+       case TX_CODEC_DMA_TX_2:
+       case TX_CODEC_DMA_TX_3:
+               break;
+       default:
+               return 0;
+       }
+
+       if (*stream_prepared) {
+               sdw_disable_stream(sruntime);
+               sdw_deprepare_stream(sruntime);
+               *stream_prepared = false;
+       }
+
+       ret = sdw_prepare_stream(sruntime);
+       if (ret)
+               return ret;
+
+       /**
+        * NOTE: there is a strict hw requirement about the ordering of port
+        * enables and actual WSA881x PA enable. PA enable should only happen
+        * after soundwire ports are enabled if not DC on the line is
+        * accumulated resulting in Click/Pop Noise
+        * PA enable/mute are handled as part of codec DAPM and digital mute.
+        */
+
+       ret = sdw_enable_stream(sruntime);
+       if (ret) {
+               sdw_deprepare_stream(sruntime);
+               return ret;
+       }
+       *stream_prepared  = true;
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(qcom_snd_sdw_prepare);
+
+int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
+                          struct snd_pcm_hw_params *params,
+                          struct sdw_stream_runtime **psruntime)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai;
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       struct sdw_stream_runtime *sruntime;
+       int i;
+
+       switch (cpu_dai->id) {
+       case WSA_CODEC_DMA_RX_0:
+       case RX_CODEC_DMA_RX_0:
+       case RX_CODEC_DMA_RX_1:
+       case TX_CODEC_DMA_TX_0:
+       case TX_CODEC_DMA_TX_1:
+       case TX_CODEC_DMA_TX_2:
+       case TX_CODEC_DMA_TX_3:
+               for_each_rtd_codec_dais(rtd, i, codec_dai) {
+                       sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream);
+                       if (sruntime != ERR_PTR(-ENOTSUPP))
+                               *psruntime = sruntime;
+               }
+               break;
+       }
+
+       return 0;
+
+}
+EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_params);
+
+int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
+                        struct sdw_stream_runtime *sruntime, bool *stream_prepared)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+
+       switch (cpu_dai->id) {
+       case WSA_CODEC_DMA_RX_0:
+       case WSA_CODEC_DMA_RX_1:
+       case RX_CODEC_DMA_RX_0:
+       case RX_CODEC_DMA_RX_1:
+       case TX_CODEC_DMA_TX_0:
+       case TX_CODEC_DMA_TX_1:
+       case TX_CODEC_DMA_TX_2:
+       case TX_CODEC_DMA_TX_3:
+               if (sruntime && *stream_prepared) {
+                       sdw_disable_stream(sruntime);
+                       sdw_deprepare_stream(sruntime);
+                       *stream_prepared = false;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(qcom_snd_sdw_hw_free);
+#endif
+
+int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
+                           struct snd_soc_jack *jack, bool *jack_setup)
+{
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+       struct snd_soc_card *card = rtd->card;
+       int rval, i;
+
+       if (!*jack_setup) {
+               rval = snd_soc_card_jack_new(card, "Headset Jack",
+                                            SND_JACK_HEADSET | SND_JACK_LINEOUT |
+                                            SND_JACK_MECHANICAL |
+                                            SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+                                            SND_JACK_BTN_2 | SND_JACK_BTN_3 |
+                                            SND_JACK_BTN_4 | SND_JACK_BTN_5,
+                                            jack);
+
+               if (rval < 0) {
+                       dev_err(card->dev, "Unable to add Headphone Jack\n");
+                       return rval;
+               }
+
+               snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA);
+               snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+               snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+               snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+               *jack_setup = true;
+       }
+
+       switch (cpu_dai->id) {
+       case TX_CODEC_DMA_TX_0:
+       case TX_CODEC_DMA_TX_1:
+       case TX_CODEC_DMA_TX_2:
+       case TX_CODEC_DMA_TX_3:
+               for_each_rtd_codec_dais(rtd, i, codec_dai) {
+                       rval = snd_soc_component_set_jack(codec_dai->component,
+                                                         jack, NULL);
+                       if (rval != 0 && rval != -ENOTSUPP) {
+                               dev_warn(card->dev, "Failed to set jack: %d\n", rval);
+                               return rval;
+                       }
+               }
+
+               break;
+       default:
+               break;
+       }
+
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(qcom_snd_wcd_jack_setup);
 MODULE_LICENSE("GPL v2");
index f05c05b..c5472a6 100644 (file)
@@ -5,7 +5,42 @@
 #define __QCOM_SND_COMMON_H__
 
 #include <sound/soc.h>
+#include <linux/soundwire/sdw.h>
 
 int qcom_snd_parse_of(struct snd_soc_card *card);
+int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
+                           struct snd_soc_jack *jack, bool *jack_setup);
 
+#if IS_ENABLED(CONFIG_SOUNDWIRE)
+int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
+                        struct sdw_stream_runtime *runtime,
+                        bool *stream_prepared);
+int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
+                          struct snd_pcm_hw_params *params,
+                          struct sdw_stream_runtime **psruntime);
+int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
+                        struct sdw_stream_runtime *sruntime,
+                        bool *stream_prepared);
+#else
+static inline int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
+                                      struct sdw_stream_runtime *runtime,
+                                      bool *stream_prepared)
+{
+       return -ENOTSUPP;
+}
+
+static inline int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
+                                        struct snd_pcm_hw_params *params,
+                                        struct sdw_stream_runtime **psruntime)
+{
+       return -ENOTSUPP;
+}
+
+static inline int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
+                                      struct sdw_stream_runtime *sruntime,
+                                      bool *stream_prepared)
+{
+       return -ENOTSUPP;
+}
+#endif
 #endif
diff --git a/sound/soc/qcom/sc8280xp.c b/sound/soc/qcom/sc8280xp.c
new file mode 100644 (file)
index 0000000..ade44ad
--- /dev/null
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2022, Linaro Limited
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <linux/soundwire/sdw.h>
+#include <sound/jack.h>
+#include <linux/input-event-codes.h>
+#include "qdsp6/q6afe.h"
+#include "common.h"
+
+#define DRIVER_NAME            "sc8280xp"
+
+struct sc8280xp_snd_data {
+       bool stream_prepared[AFE_PORT_MAX];
+       struct snd_soc_card *card;
+       struct sdw_stream_runtime *sruntime[AFE_PORT_MAX];
+       struct snd_soc_jack jack;
+       bool jack_setup;
+};
+
+static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
+
+       return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
+}
+
+static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+                                    struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       struct snd_interval *rate = hw_param_interval(params,
+                                       SNDRV_PCM_HW_PARAM_RATE);
+       struct snd_interval *channels = hw_param_interval(params,
+                                       SNDRV_PCM_HW_PARAM_CHANNELS);
+
+       rate->min = rate->max = 48000;
+       channels->min = 2;
+       channels->max = 2;
+       switch (cpu_dai->id) {
+       case TX_CODEC_DMA_TX_0:
+       case TX_CODEC_DMA_TX_1:
+       case TX_CODEC_DMA_TX_2:
+       case TX_CODEC_DMA_TX_3:
+               channels->min = 1;
+               break;
+       default:
+               break;
+       }
+
+
+       return 0;
+}
+
+static int sc8280xp_snd_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       struct sc8280xp_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card);
+
+       return qcom_snd_sdw_hw_params(substream, params, &pdata->sruntime[cpu_dai->id]);
+}
+
+static int sc8280xp_snd_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
+       struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
+
+       return qcom_snd_sdw_prepare(substream, sruntime,
+                                   &data->stream_prepared[cpu_dai->id]);
+}
+
+static int sc8280xp_snd_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sc8280xp_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
+       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+       struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
+
+       return qcom_snd_sdw_hw_free(substream, sruntime,
+                                   &data->stream_prepared[cpu_dai->id]);
+}
+
+static const struct snd_soc_ops sc8280xp_be_ops = {
+       .hw_params = sc8280xp_snd_hw_params,
+       .hw_free = sc8280xp_snd_hw_free,
+       .prepare = sc8280xp_snd_prepare,
+};
+
+static void sc8280xp_add_be_ops(struct snd_soc_card *card)
+{
+       struct snd_soc_dai_link *link;
+       int i;
+
+       for_each_card_prelinks(card, i, link) {
+               if (link->no_pcm == 1) {
+                       link->init = sc8280xp_snd_init;
+                       link->be_hw_params_fixup = sc8280xp_be_hw_params_fixup;
+                       link->ops = &sc8280xp_be_ops;
+               }
+       }
+}
+
+static int sc8280xp_platform_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card;
+       struct sc8280xp_snd_data *data;
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+       if (!card)
+               return -ENOMEM;
+       card->owner = THIS_MODULE;
+       /* Allocate the private data */
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       card->dev = dev;
+       dev_set_drvdata(dev, card);
+       snd_soc_card_set_drvdata(card, data);
+       ret = qcom_snd_parse_of(card);
+       if (ret)
+               return ret;
+
+       card->driver_name = DRIVER_NAME;
+       sc8280xp_add_be_ops(card);
+       return devm_snd_soc_register_card(dev, card);
+}
+
+static const struct of_device_id snd_sc8280xp_dt_match[] = {
+       {.compatible = "qcom,sc8280xp-sndcard",},
+       {}
+};
+
+MODULE_DEVICE_TABLE(of, snd_sc8280xp_dt_match);
+
+static struct platform_driver snd_sc8280xp_driver = {
+       .probe  = sc8280xp_platform_probe,
+       .driver = {
+               .name = "snd-sc8280xp",
+               .of_match_table = snd_sc8280xp_dt_match,
+       },
+};
+module_platform_driver(snd_sc8280xp_driver);
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
+MODULE_DESCRIPTION("SC8280XP ASoC Machine Driver");
+MODULE_LICENSE("GPL v2");
index 98a2fde..8dbe9ef 100644 (file)
@@ -27,57 +27,8 @@ struct sm8250_snd_data {
 static int sm8250_snd_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
-       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
-       struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
-       struct snd_soc_card *card = rtd->card;
-       int rval, i;
-
-       if (!data->jack_setup) {
-               struct snd_jack *jack;
-
-               rval = snd_soc_card_jack_new(card, "Headset Jack",
-                                            SND_JACK_HEADSET | SND_JACK_LINEOUT |
-                                            SND_JACK_MECHANICAL |
-                                            SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-                                            SND_JACK_BTN_2 | SND_JACK_BTN_3 |
-                                            SND_JACK_BTN_4 | SND_JACK_BTN_5,
-                                            &data->jack);
-
-               if (rval < 0) {
-                       dev_err(card->dev, "Unable to add Headphone Jack\n");
-                       return rval;
-               }
-
-               jack = data->jack.jack;
-
-               snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_MEDIA);
-               snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
-               snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
-               snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
-               data->jack_setup = true;
-       }
-
-       switch (cpu_dai->id) {
-       case TX_CODEC_DMA_TX_0:
-       case TX_CODEC_DMA_TX_1:
-       case TX_CODEC_DMA_TX_2:
-       case TX_CODEC_DMA_TX_3:
-               for_each_rtd_codec_dais(rtd, i, codec_dai) {
-                       rval = snd_soc_component_set_jack(codec_dai->component,
-                                                         &data->jack, NULL);
-                       if (rval != 0 && rval != -ENOTSUPP) {
-                               dev_warn(card->dev, "Failed to set jack: %d\n", rval);
-                               return rval;
-                       }
-               }
-
-               break;
-       default:
-               break;
-       }
 
-
-       return 0;
+       return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
 }
 
 static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
@@ -121,92 +72,21 @@ static int sm8250_snd_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai;
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
        struct sm8250_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card);
-       struct sdw_stream_runtime *sruntime;
-       int i;
-
-       switch (cpu_dai->id) {
-       case WSA_CODEC_DMA_RX_0:
-       case RX_CODEC_DMA_RX_0:
-       case RX_CODEC_DMA_RX_1:
-       case TX_CODEC_DMA_TX_0:
-       case TX_CODEC_DMA_TX_1:
-       case TX_CODEC_DMA_TX_2:
-       case TX_CODEC_DMA_TX_3:
-               for_each_rtd_codec_dais(rtd, i, codec_dai) {
-                       sruntime = snd_soc_dai_get_stream(codec_dai,
-                                                         substream->stream);
-                       if (sruntime != ERR_PTR(-ENOTSUPP))
-                               pdata->sruntime[cpu_dai->id] = sruntime;
-               }
-               break;
-       }
-
-       return 0;
 
+       return qcom_snd_sdw_hw_params(substream, params, &pdata->sruntime[cpu_dai->id]);
 }
 
-static int sm8250_snd_wsa_dma_prepare(struct snd_pcm_substream *substream)
+static int sm8250_snd_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
        struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
        struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
-       int ret;
-
-       if (!sruntime)
-               return 0;
 
-       if (data->stream_prepared[cpu_dai->id]) {
-               sdw_disable_stream(sruntime);
-               sdw_deprepare_stream(sruntime);
-               data->stream_prepared[cpu_dai->id] = false;
-       }
-
-       ret = sdw_prepare_stream(sruntime);
-       if (ret)
-               return ret;
-
-       /**
-        * NOTE: there is a strict hw requirement about the ordering of port
-        * enables and actual WSA881x PA enable. PA enable should only happen
-        * after soundwire ports are enabled if not DC on the line is
-        * accumulated resulting in Click/Pop Noise
-        * PA enable/mute are handled as part of codec DAPM and digital mute.
-        */
-
-       ret = sdw_enable_stream(sruntime);
-       if (ret) {
-               sdw_deprepare_stream(sruntime);
-               return ret;
-       }
-       data->stream_prepared[cpu_dai->id]  = true;
-
-       return ret;
-}
-
-static int sm8250_snd_prepare(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
-
-       switch (cpu_dai->id) {
-       case WSA_CODEC_DMA_RX_0:
-       case WSA_CODEC_DMA_RX_1:
-       case RX_CODEC_DMA_RX_0:
-       case RX_CODEC_DMA_RX_1:
-       case TX_CODEC_DMA_TX_0:
-       case TX_CODEC_DMA_TX_1:
-       case TX_CODEC_DMA_TX_2:
-       case TX_CODEC_DMA_TX_3:
-               return sm8250_snd_wsa_dma_prepare(substream);
-       default:
-               break;
-       }
-
-       return 0;
+       return qcom_snd_sdw_prepare(substream, sruntime,
+                                   &data->stream_prepared[cpu_dai->id]);
 }
 
 static int sm8250_snd_hw_free(struct snd_pcm_substream *substream)
@@ -216,26 +96,8 @@ static int sm8250_snd_hw_free(struct snd_pcm_substream *substream)
        struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
        struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
 
-       switch (cpu_dai->id) {
-       case WSA_CODEC_DMA_RX_0:
-       case WSA_CODEC_DMA_RX_1:
-       case RX_CODEC_DMA_RX_0:
-       case RX_CODEC_DMA_RX_1:
-       case TX_CODEC_DMA_TX_0:
-       case TX_CODEC_DMA_TX_1:
-       case TX_CODEC_DMA_TX_2:
-       case TX_CODEC_DMA_TX_3:
-               if (sruntime && data->stream_prepared[cpu_dai->id]) {
-                       sdw_disable_stream(sruntime);
-                       sdw_deprepare_stream(sruntime);
-                       data->stream_prepared[cpu_dai->id] = false;
-               }
-               break;
-       default:
-               break;
-       }
-
-       return 0;
+       return qcom_snd_sdw_hw_free(substream, sruntime,
+                                   &data->stream_prepared[cpu_dai->id]);
 }
 
 static const struct snd_soc_ops sm8250_be_ops = {
index e020ab4..df2bd80 100644 (file)
@@ -487,6 +487,7 @@ static struct snd_soc_pcm_runtime *soc_new_pcm_runtime(
        rtd->card       = card;
        rtd->dai_link   = dai_link;
        rtd->num        = card->num_rtd++;
+       rtd->pmdown_time = pmdown_time;                 /* default power off timeout */
 
        /* see for_each_card_rtds */
        list_add_tail(&rtd->list, &card->rtd_list);
@@ -1247,9 +1248,6 @@ static int soc_init_pcm_runtime(struct snd_soc_card *card,
        struct snd_soc_component *component;
        int ret, num, i;
 
-       /* set default power off timeout */
-       rtd->pmdown_time = pmdown_time;
-
        /* do machine specific initialization */
        ret = snd_soc_link_init(rtd);
        if (ret < 0)
index b101db8..c3be24b 100644 (file)
@@ -1755,6 +1755,7 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
 
        /* enable DPCM */
        link->dynamic = 1;
+       link->ignore_pmdown_time = 1;
        link->dpcm_playback = le32_to_cpu(pcm->playback);
        link->dpcm_capture = le32_to_cpu(pcm->capture);
        if (pcm->flag_mask)
index 356497f..3537805 100644 (file)
@@ -32,7 +32,7 @@ static int sof_nocodec_bes_setup(struct device *dev,
 
        /* set up BE dai_links */
        for (i = 0; i < link_num; i++) {
-               dlc = devm_kzalloc(dev, 3 * sizeof(*dlc), GFP_KERNEL);
+               dlc = devm_kcalloc(dev, 3, sizeof(*dlc), GFP_KERNEL);
                if (!dlc)
                        return -ENOMEM;
 
@@ -78,7 +78,7 @@ static int sof_nocodec_setup(struct device *dev,
        struct snd_soc_dai_link *links;
 
        /* create dummy BE dai_links */
-       links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * num_dai_drivers, GFP_KERNEL);
+       links = devm_kcalloc(dev, num_dai_drivers, sizeof(struct snd_soc_dai_link), GFP_KERNEL);
        if (!links)
                return -ENOMEM;
 
index d627092..643fd10 100644 (file)
@@ -138,7 +138,7 @@ static const struct dmi_system_id community_key_platforms[] = {
                .ident = "Google Chromebooks",
                .callback = chromebook_use_community_key,
                .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Google"),
+                       DMI_MATCH(DMI_PRODUCT_FAMILY, "Google"),
                }
        },
        {},
index ddcaaa9..1f18f01 100644 (file)
@@ -56,6 +56,13 @@ config SND_SUN4I_SPDIF
          Say Y or M to add support for the S/PDIF audio block in the Allwinner
          A10 and affiliated SoCs.
 
+config SND_SUN50I_DMIC
+       tristate "Allwinner H6 DMIC Support"
+       select SND_SOC_GENERIC_DMAENGINE_PCM
+       help
+         Say Y or M to add support for the DMIC audio block in the Allwinner
+         H6 and affiliated SoCs.
+
 config SND_SUN8I_ADDA_PR_REGMAP
        tristate
        select REGMAP
index a86be34..4483fe9 100644 (file)
@@ -6,3 +6,4 @@ obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o
 obj-$(CONFIG_SND_SUN50I_CODEC_ANALOG) += sun50i-codec-analog.o
 obj-$(CONFIG_SND_SUN8I_CODEC) += sun8i-codec.o
 obj-$(CONFIG_SND_SUN8I_ADDA_PR_REGMAP) += sun8i-adda-pr-regmap.o
+obj-$(CONFIG_SND_SUN50I_DMIC) += sun50i-dmic.o
index 3a7075d..835dc34 100644 (file)
@@ -1232,6 +1232,9 @@ static const struct snd_soc_component_driver sun8i_a23_codec_codec = {
 static const struct snd_soc_component_driver sun4i_codec_component = {
        .name                   = "sun4i-codec",
        .legacy_dai_naming      = 1,
+#ifdef CONFIG_DEBUG_FS
+       .debugfs_prefix         = "cpu",
+#endif
 };
 
 #define SUN4I_CODEC_RATES      SNDRV_PCM_RATE_CONTINUOUS
diff --git a/sound/soc/sunxi/sun50i-dmic.c b/sound/soc/sunxi/sun50i-dmic.c
new file mode 100644 (file)
index 0000000..cd3c07f
--- /dev/null
@@ -0,0 +1,406 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// This driver supports the DMIC in Allwinner's H6 SoCs.
+//
+// Copyright 2021 Ban Tao <fengzheng923@gmail.com>
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/of_device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <sound/dmaengine_pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#define SUN50I_DMIC_EN_CTL                     (0x00)
+       #define SUN50I_DMIC_EN_CTL_GLOBE                        BIT(8)
+       #define SUN50I_DMIC_EN_CTL_CHAN(v)                      ((v) << 0)
+       #define SUN50I_DMIC_EN_CTL_CHAN_MASK                    GENMASK(7, 0)
+#define SUN50I_DMIC_SR                         (0x04)
+       #define SUN50I_DMIC_SR_SAMPLE_RATE(v)                   ((v) << 0)
+       #define SUN50I_DMIC_SR_SAMPLE_RATE_MASK                 GENMASK(2, 0)
+#define SUN50I_DMIC_CTL                                (0x08)
+       #define SUN50I_DMIC_CTL_OVERSAMPLE_RATE                 BIT(0)
+#define SUN50I_DMIC_DATA                       (0x10)
+#define SUN50I_DMIC_INTC                       (0x14)
+       #define SUN50I_DMIC_FIFO_DRQ_EN                         BIT(2)
+#define SUN50I_DMIC_INT_STA                    (0x18)
+       #define SUN50I_DMIC_INT_STA_OVERRUN_IRQ_PENDING         BIT(1)
+       #define SUN50I_DMIC_INT_STA_DATA_IRQ_PENDING            BIT(0)
+#define SUN50I_DMIC_RXFIFO_CTL                 (0x1c)
+       #define SUN50I_DMIC_RXFIFO_CTL_FLUSH                    BIT(31)
+       #define SUN50I_DMIC_RXFIFO_CTL_MODE_MASK                BIT(9)
+       #define SUN50I_DMIC_RXFIFO_CTL_MODE_LSB                 (0 << 9)
+       #define SUN50I_DMIC_RXFIFO_CTL_MODE_MSB                 (1 << 9)
+       #define SUN50I_DMIC_RXFIFO_CTL_SAMPLE_MASK              BIT(8)
+       #define SUN50I_DMIC_RXFIFO_CTL_SAMPLE_16                (0 << 8)
+       #define SUN50I_DMIC_RXFIFO_CTL_SAMPLE_24                (1 << 8)
+#define SUN50I_DMIC_CH_NUM                     (0x24)
+       #define SUN50I_DMIC_CH_NUM_N(v)                         ((v) << 0)
+       #define SUN50I_DMIC_CH_NUM_N_MASK                       GENMASK(2, 0)
+#define SUN50I_DMIC_CNT                                (0x2c)
+       #define SUN50I_DMIC_CNT_N                               (1 << 0)
+#define SUN50I_DMIC_HPF_CTRL                   (0x38)
+#define SUN50I_DMIC_VERSION                    (0x50)
+
+struct sun50i_dmic_dev {
+       struct clk *dmic_clk;
+       struct clk *bus_clk;
+       struct reset_control *rst;
+       struct regmap *regmap;
+       struct snd_dmaengine_dai_dma_data dma_params_rx;
+};
+
+struct dmic_rate {
+       unsigned int samplerate;
+       unsigned int rate_bit;
+};
+
+const static struct dmic_rate dmic_rate_s[] = {
+       {48000, 0x0},
+       {44100, 0x0},
+       {32000, 0x1},
+       {24000, 0x2},
+       {22050, 0x2},
+       {16000, 0x3},
+       {12000, 0x4},
+       {11025, 0x4},
+       {8000,  0x5},
+};
+
+static int sun50i_dmic_startup(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *cpu_dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct sun50i_dmic_dev *host = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
+
+       /* only support capture */
+       if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
+               return -EINVAL;
+
+       regmap_update_bits(host->regmap, SUN50I_DMIC_RXFIFO_CTL,
+                       SUN50I_DMIC_RXFIFO_CTL_FLUSH,
+                       SUN50I_DMIC_RXFIFO_CTL_FLUSH);
+       regmap_write(host->regmap, SUN50I_DMIC_CNT, SUN50I_DMIC_CNT_N);
+
+       return 0;
+}
+
+static int sun50i_dmic_hw_params(struct snd_pcm_substream *substream,
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *cpu_dai)
+{
+       int i = 0;
+       unsigned long rate = params_rate(params);
+       unsigned int mclk = 0;
+       unsigned int channels = params_channels(params);
+       unsigned int chan_en = (1 << channels) - 1;
+       struct sun50i_dmic_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
+
+       /* DMIC num is N+1 */
+       regmap_update_bits(host->regmap, SUN50I_DMIC_CH_NUM,
+                          SUN50I_DMIC_CH_NUM_N_MASK,
+                          SUN50I_DMIC_CH_NUM_N(channels - 1));
+       regmap_write(host->regmap, SUN50I_DMIC_HPF_CTRL, chan_en);
+       regmap_update_bits(host->regmap, SUN50I_DMIC_EN_CTL,
+                          SUN50I_DMIC_EN_CTL_CHAN_MASK,
+                          SUN50I_DMIC_EN_CTL_CHAN(chan_en));
+
+       switch (params_format(params)) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               regmap_update_bits(host->regmap, SUN50I_DMIC_RXFIFO_CTL,
+                                  SUN50I_DMIC_RXFIFO_CTL_SAMPLE_MASK,
+                                  SUN50I_DMIC_RXFIFO_CTL_SAMPLE_16);
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+               regmap_update_bits(host->regmap, SUN50I_DMIC_RXFIFO_CTL,
+                                  SUN50I_DMIC_RXFIFO_CTL_SAMPLE_MASK,
+                                  SUN50I_DMIC_RXFIFO_CTL_SAMPLE_24);
+               break;
+       default:
+               dev_err(cpu_dai->dev, "Invalid format!\n");
+               return -EINVAL;
+       }
+       /* The hardware supports FIFO mode 1 for 24-bit samples */
+       regmap_update_bits(host->regmap, SUN50I_DMIC_RXFIFO_CTL,
+                          SUN50I_DMIC_RXFIFO_CTL_MODE_MASK,
+                          SUN50I_DMIC_RXFIFO_CTL_MODE_MSB);
+
+       switch (rate) {
+       case 11025:
+       case 22050:
+       case 44100:
+               mclk = 22579200;
+               break;
+       case 8000:
+       case 12000:
+       case 16000:
+       case 24000:
+       case 32000:
+       case 48000:
+               mclk = 24576000;
+               break;
+       default:
+               dev_err(cpu_dai->dev, "Invalid rate!\n");
+               return -EINVAL;
+       }
+
+       if (clk_set_rate(host->dmic_clk, mclk)) {
+               dev_err(cpu_dai->dev, "mclk : %u not support\n", mclk);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(dmic_rate_s); i++) {
+               if (dmic_rate_s[i].samplerate == rate) {
+                       regmap_update_bits(host->regmap, SUN50I_DMIC_SR,
+                                          SUN50I_DMIC_SR_SAMPLE_RATE_MASK,
+                                          SUN50I_DMIC_SR_SAMPLE_RATE(dmic_rate_s[i].rate_bit));
+                       break;
+               }
+       }
+
+       switch (params_physical_width(params)) {
+       case 16:
+               host->dma_params_rx.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+               break;
+       case 32:
+               host->dma_params_rx.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+               break;
+       default:
+               dev_err(cpu_dai->dev, "Unsupported physical sample width: %d\n",
+                       params_physical_width(params));
+               return -EINVAL;
+       }
+
+       /* oversamplerate adjust */
+       if (params_rate(params) >= 24000)
+               regmap_update_bits(host->regmap, SUN50I_DMIC_CTL,
+                                  SUN50I_DMIC_CTL_OVERSAMPLE_RATE,
+                                  SUN50I_DMIC_CTL_OVERSAMPLE_RATE);
+       else
+               regmap_update_bits(host->regmap, SUN50I_DMIC_CTL,
+                                  SUN50I_DMIC_CTL_OVERSAMPLE_RATE, 0);
+
+       return 0;
+}
+
+static int sun50i_dmic_trigger(struct snd_pcm_substream *substream, int cmd,
+                              struct snd_soc_dai *dai)
+{
+       int ret = 0;
+       struct sun50i_dmic_dev *host = snd_soc_dai_get_drvdata(dai);
+
+       if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
+               return -EINVAL;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               /* DRQ ENABLE */
+               regmap_update_bits(host->regmap, SUN50I_DMIC_INTC,
+                                  SUN50I_DMIC_FIFO_DRQ_EN,
+                                  SUN50I_DMIC_FIFO_DRQ_EN);
+               /* Global enable */
+               regmap_update_bits(host->regmap, SUN50I_DMIC_EN_CTL,
+                                  SUN50I_DMIC_EN_CTL_GLOBE,
+                                  SUN50I_DMIC_EN_CTL_GLOBE);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               /* DRQ DISABLE */
+               regmap_update_bits(host->regmap, SUN50I_DMIC_INTC,
+                                  SUN50I_DMIC_FIFO_DRQ_EN, 0);
+               /* Global disable */
+               regmap_update_bits(host->regmap, SUN50I_DMIC_EN_CTL,
+                                  SUN50I_DMIC_EN_CTL_GLOBE, 0);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       return ret;
+}
+
+static int sun50i_dmic_soc_dai_probe(struct snd_soc_dai *dai)
+{
+       struct sun50i_dmic_dev *host = snd_soc_dai_get_drvdata(dai);
+
+       snd_soc_dai_init_dma_data(dai, NULL, &host->dma_params_rx);
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops sun50i_dmic_dai_ops = {
+       .startup        = sun50i_dmic_startup,
+       .trigger        = sun50i_dmic_trigger,
+       .hw_params      = sun50i_dmic_hw_params,
+};
+
+static const struct regmap_config sun50i_dmic_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+       .max_register = SUN50I_DMIC_VERSION,
+       .cache_type = REGCACHE_NONE,
+};
+
+#define SUN50I_DMIC_RATES (SNDRV_PCM_RATE_8000_48000)
+#define SUN50I_DMIC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver sun50i_dmic_dai = {
+       .capture = {
+               .channels_min = 1,
+               .channels_max = 8,
+               .rates = SUN50I_DMIC_RATES,
+               .formats = SUN50I_DMIC_FORMATS,
+               .sig_bits = 21,
+       },
+       .probe = sun50i_dmic_soc_dai_probe,
+       .ops = &sun50i_dmic_dai_ops,
+       .name = "dmic",
+};
+
+static const struct of_device_id sun50i_dmic_of_match[] = {
+       {
+               .compatible = "allwinner,sun50i-h6-dmic",
+       },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sun50i_dmic_of_match);
+
+static const struct snd_soc_component_driver sun50i_dmic_component = {
+       .name           = "sun50i-dmic",
+};
+
+static int sun50i_dmic_runtime_suspend(struct device *dev)
+{
+       struct sun50i_dmic_dev *host  = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(host->dmic_clk);
+       clk_disable_unprepare(host->bus_clk);
+
+       return 0;
+}
+
+static int sun50i_dmic_runtime_resume(struct device *dev)
+{
+       struct sun50i_dmic_dev *host  = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(host->dmic_clk);
+       if (ret)
+               return ret;
+
+       ret = clk_prepare_enable(host->bus_clk);
+       if (ret) {
+               clk_disable_unprepare(host->dmic_clk);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int sun50i_dmic_probe(struct platform_device *pdev)
+{
+       struct sun50i_dmic_dev *host;
+       struct resource *res;
+       int ret;
+       void __iomem *base;
+
+       host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
+       if (!host)
+               return -ENOMEM;
+
+       /* Get the addresses */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base))
+               return dev_err_probe(&pdev->dev, PTR_ERR(base),
+                                    "get resource failed.\n");
+
+       host->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+                                            &sun50i_dmic_regmap_config);
+
+       /* Clocks */
+       host->bus_clk = devm_clk_get(&pdev->dev, "bus");
+       if (IS_ERR(host->bus_clk))
+               return dev_err_probe(&pdev->dev, PTR_ERR(host->bus_clk),
+                                    "failed to get bus clock.\n");
+
+       host->dmic_clk = devm_clk_get(&pdev->dev, "mod");
+       if (IS_ERR(host->dmic_clk))
+               return dev_err_probe(&pdev->dev, PTR_ERR(host->dmic_clk),
+                                    "failed to get dmic clock.\n");
+
+       host->dma_params_rx.addr = res->start + SUN50I_DMIC_DATA;
+       host->dma_params_rx.maxburst = 8;
+
+       platform_set_drvdata(pdev, host);
+
+       host->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
+       if (IS_ERR(host->rst))
+               return dev_err_probe(&pdev->dev, PTR_ERR(host->rst),
+                                    "Failed to get reset.\n");
+       reset_control_deassert(host->rst);
+
+       ret = devm_snd_soc_register_component(&pdev->dev, &sun50i_dmic_component,
+                                             &sun50i_dmic_dai, 1);
+       if (ret)
+               return dev_err_probe(&pdev->dev, ret,
+                                    "failed to register component.\n");
+
+       pm_runtime_enable(&pdev->dev);
+       if (!pm_runtime_enabled(&pdev->dev)) {
+               ret = sun50i_dmic_runtime_resume(&pdev->dev);
+               if (ret)
+                       goto err_disable_runtime_pm;
+       }
+
+       ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+       if (ret)
+               goto err_suspend;
+
+       return 0;
+err_suspend:
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               sun50i_dmic_runtime_suspend(&pdev->dev);
+err_disable_runtime_pm:
+       pm_runtime_disable(&pdev->dev);
+       return ret;
+}
+
+static int sun50i_dmic_remove(struct platform_device *pdev)
+{
+       pm_runtime_disable(&pdev->dev);
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               sun50i_dmic_runtime_suspend(&pdev->dev);
+
+       return 0;
+}
+
+static const struct dev_pm_ops sun50i_dmic_pm = {
+       SET_RUNTIME_PM_OPS(sun50i_dmic_runtime_suspend,
+                          sun50i_dmic_runtime_resume, NULL)
+};
+
+static struct platform_driver sun50i_dmic_driver = {
+       .driver         = {
+               .name   = "sun50i-dmic",
+               .of_match_table = of_match_ptr(sun50i_dmic_of_match),
+               .pm     = &sun50i_dmic_pm,
+       },
+       .probe          = sun50i_dmic_probe,
+       .remove         = sun50i_dmic_remove,
+};
+
+module_platform_driver(sun50i_dmic_driver);
+
+MODULE_DESCRIPTION("Allwinner sun50i DMIC SoC Interface");
+MODULE_AUTHOR("Ban Tao <fengzheng923@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:sun50i-dmic");