Merge branch 'for-next' into for-linus
authorTakashi Iwai <tiwai@suse.de>
Wed, 5 Jan 2022 14:38:11 +0000 (15:38 +0100)
committerTakashi Iwai <tiwai@suse.de>
Wed, 5 Jan 2022 14:38:34 +0000 (15:38 +0100)
Pull 5.17 materials.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
79 files changed:
Documentation/devicetree/bindings/sound/wlf,wm8962.yaml
Documentation/sound/hd-audio/models.rst
include/sound/soc-acpi.h
sound/core/control_compat.c
sound/core/jack.c
sound/core/oss/pcm_oss.c
sound/core/rawmidi.c
sound/drivers/opl3/opl3_midi.c
sound/hda/intel-dsp-config.c
sound/hda/intel-sdw-acpi.c
sound/pci/cmipci.c
sound/pci/ctxfi/ctamixer.c
sound/pci/ctxfi/ctdaio.c
sound/pci/ctxfi/ctresource.c
sound/pci/ctxfi/ctresource.h
sound/pci/ctxfi/ctsrc.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_local.h
sound/pci/hda/patch_cs8409.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/soc/amd/yc/pci-acp6x.c
sound/soc/codecs/cs35l41-spi.c
sound/soc/codecs/cs35l41.c
sound/soc/codecs/cs35l41.h
sound/soc/codecs/lpass-rx-macro.c
sound/soc/codecs/rk817_codec.c
sound/soc/codecs/rt1011.c
sound/soc/codecs/rt1011.h
sound/soc/codecs/rt5682-i2c.c
sound/soc/codecs/rt5682.c
sound/soc/codecs/rt5682.h
sound/soc/codecs/rt5682s.c
sound/soc/codecs/rt9120.c
sound/soc/codecs/tas2770.c
sound/soc/codecs/wcd934x.c
sound/soc/codecs/wcd938x.c
sound/soc/codecs/wm_adsp.c
sound/soc/codecs/wsa881x.c
sound/soc/intel/boards/sof_sdw.c
sound/soc/intel/common/soc-acpi-intel-adl-match.c
sound/soc/intel/common/soc-acpi-intel-cml-match.c
sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
sound/soc/mediatek/mt8173/mt8173-rt5650.c
sound/soc/meson/aiu-encoder-i2s.c
sound/soc/meson/aiu-fifo-i2s.c
sound/soc/meson/aiu-fifo.c
sound/soc/qcom/qdsp6/audioreach.h
sound/soc/qcom/qdsp6/q6adm.c
sound/soc/qcom/qdsp6/q6asm-dai.c
sound/soc/qcom/qdsp6/q6prm.c
sound/soc/qcom/qdsp6/q6routing.c
sound/soc/rockchip/rockchip_i2s_tdm.c
sound/soc/sh/rcar/dma.c
sound/soc/soc-acpi.c
sound/soc/soc-dapm.c
sound/soc/soc-topology.c
sound/soc/sof/Kconfig
sound/soc/sof/control.c
sound/soc/sof/intel/hda-bus.c
sound/soc/sof/intel/hda-codec.c
sound/soc/sof/intel/hda-dsp.c
sound/soc/sof/intel/hda.c
sound/soc/sof/intel/pci-tgl.c
sound/soc/stm/stm32_i2s.c
sound/soc/tegra/tegra186_dspk.c
sound/soc/tegra/tegra210_admaif.c
sound/soc/tegra/tegra210_adx.c
sound/soc/tegra/tegra210_ahub.c
sound/soc/tegra/tegra210_amx.c
sound/soc/tegra/tegra210_dmic.c
sound/soc/tegra/tegra210_i2s.c
sound/soc/tegra/tegra210_mixer.c
sound/soc/tegra/tegra210_mvc.c
sound/soc/tegra/tegra210_sfc.c
sound/soc/tegra/tegra_asoc_machine.c
sound/soc/tegra/tegra_asoc_machine.h
sound/usb/mixer_quirks.c
sound/usb/pcm.c

index 0e6249d..5e172e9 100644 (file)
@@ -19,6 +19,9 @@ properties:
   clocks:
     maxItems: 1
 
+  interrupts:
+    maxItems: 1
+
   "#sound-dai-cells":
     const: 0
 
index 0ea967d..d253359 100644 (file)
@@ -326,6 +326,8 @@ usi-headset
     Headset support on USI machines
 dual-codecs
     Lenovo laptops with dual codecs
+alc285-hp-amp-init
+    HP laptops which require speaker amplifier initialization (ALC285)
 
 ALC680
 ======
index 31f4c4f..ac0893d 100644 (file)
@@ -147,7 +147,7 @@ struct snd_soc_acpi_link_adr {
  */
 /* Descriptor for SST ASoC machine driver */
 struct snd_soc_acpi_mach {
-       const u8 id[ACPI_ID_LEN];
+       u8 id[ACPI_ID_LEN];
        const struct snd_soc_acpi_codecs *comp_ids;
        const u32 link_mask;
        const struct snd_soc_acpi_link_adr *links;
index 470dabc..edff063 100644 (file)
@@ -264,6 +264,7 @@ static int copy_ctl_value_to_user(void __user *userdata,
                                  struct snd_ctl_elem_value *data,
                                  int type, int count)
 {
+       struct snd_ctl_elem_value32 __user *data32 = userdata;
        int i, size;
 
        if (type == SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
@@ -280,6 +281,8 @@ static int copy_ctl_value_to_user(void __user *userdata,
                if (copy_to_user(valuep, data->value.bytes.data, size))
                        return -EFAULT;
        }
+       if (copy_to_user(&data32->id, &data->id, sizeof(data32->id)))
+               return -EFAULT;
        return 0;
 }
 
index f50a1e9..d1e3055 100644 (file)
@@ -512,6 +512,10 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
                return -ENOMEM;
 
        jack->id = kstrdup(id, GFP_KERNEL);
+       if (jack->id == NULL) {
+               kfree(jack);
+               return -ENOMEM;
+       }
 
        /* don't creat input device for phantom jack */
        if (!phantom_jack) {
index bb37665..3ee9edf 100644 (file)
@@ -147,7 +147,7 @@ snd_pcm_hw_param_value_min(const struct snd_pcm_hw_params *params,
  *
  * Return the maximum value for field PAR.
  */
-static unsigned int
+static int
 snd_pcm_hw_param_value_max(const struct snd_pcm_hw_params *params,
                           snd_pcm_hw_param_t var, int *dir)
 {
@@ -682,18 +682,24 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
                                   struct snd_pcm_hw_params *oss_params,
                                   struct snd_pcm_hw_params *slave_params)
 {
-       size_t s;
-       size_t oss_buffer_size, oss_period_size, oss_periods;
-       size_t min_period_size, max_period_size;
+       ssize_t s;
+       ssize_t oss_buffer_size;
+       ssize_t oss_period_size, oss_periods;
+       ssize_t min_period_size, max_period_size;
        struct snd_pcm_runtime *runtime = substream->runtime;
        size_t oss_frame_size;
 
        oss_frame_size = snd_pcm_format_physical_width(params_format(oss_params)) *
                         params_channels(oss_params) / 8;
 
+       oss_buffer_size = snd_pcm_hw_param_value_max(slave_params,
+                                                    SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+                                                    NULL);
+       if (oss_buffer_size <= 0)
+               return -EINVAL;
        oss_buffer_size = snd_pcm_plug_client_size(substream,
-                                                  snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, NULL)) * oss_frame_size;
-       if (!oss_buffer_size)
+                                                  oss_buffer_size * oss_frame_size);
+       if (oss_buffer_size <= 0)
                return -EINVAL;
        oss_buffer_size = rounddown_pow_of_two(oss_buffer_size);
        if (atomic_read(&substream->mmap_count)) {
@@ -730,7 +736,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
 
        min_period_size = snd_pcm_plug_client_size(substream,
                                                   snd_pcm_hw_param_value_min(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
-       if (min_period_size) {
+       if (min_period_size > 0) {
                min_period_size *= oss_frame_size;
                min_period_size = roundup_pow_of_two(min_period_size);
                if (oss_period_size < min_period_size)
@@ -739,7 +745,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
 
        max_period_size = snd_pcm_plug_client_size(substream,
                                                   snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, NULL));
-       if (max_period_size) {
+       if (max_period_size > 0) {
                max_period_size *= oss_frame_size;
                max_period_size = rounddown_pow_of_two(max_period_size);
                if (oss_period_size > max_period_size)
@@ -752,7 +758,7 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream,
                oss_periods = substream->oss.setup.periods;
 
        s = snd_pcm_hw_param_value_max(slave_params, SNDRV_PCM_HW_PARAM_PERIODS, NULL);
-       if (runtime->oss.maxfrags && s > runtime->oss.maxfrags)
+       if (s > 0 && runtime->oss.maxfrags && s > runtime->oss.maxfrags)
                s = runtime->oss.maxfrags;
        if (oss_periods > s)
                oss_periods = s;
@@ -878,8 +884,15 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
                err = -EINVAL;
                goto failure;
        }
-       choose_rate(substream, sparams, runtime->oss.rate);
-       snd_pcm_hw_param_near(substream, sparams, SNDRV_PCM_HW_PARAM_CHANNELS, runtime->oss.channels, NULL);
+
+       err = choose_rate(substream, sparams, runtime->oss.rate);
+       if (err < 0)
+               goto failure;
+       err = snd_pcm_hw_param_near(substream, sparams,
+                                   SNDRV_PCM_HW_PARAM_CHANNELS,
+                                   runtime->oss.channels, NULL);
+       if (err < 0)
+               goto failure;
 
        format = snd_pcm_oss_format_from(runtime->oss.format);
 
@@ -1956,7 +1969,7 @@ static int snd_pcm_oss_set_fragment1(struct snd_pcm_substream *substream, unsign
        if (runtime->oss.subdivision || runtime->oss.fragshift)
                return -EINVAL;
        fragshift = val & 0xffff;
-       if (fragshift >= 31)
+       if (fragshift >= 25) /* should be large enough */
                return -EINVAL;
        runtime->oss.fragshift = fragshift;
        runtime->oss.maxfrags = (val >> 16) & 0xffff;
index 6f30231..befa980 100644 (file)
@@ -447,6 +447,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
                err = -ENOMEM;
                goto __error;
        }
+       rawmidi_file->user_pversion = 0;
        init_waitqueue_entry(&wait, current);
        add_wait_queue(&rmidi->open_wait, &wait);
        while (1) {
index e1b69c6..e2b7be6 100644 (file)
@@ -397,7 +397,7 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
        }
        if (instr_4op) {
                vp2 = &opl3->voices[voice + 3];
-               if (vp->state > 0) {
+               if (vp2->state > 0) {
                        opl3_reg = reg_side | (OPL3_REG_KEYON_BLOCK +
                                               voice_offset + 3);
                        reg_val = vp->keyon_reg & ~OPL3_KEYON_BIT;
index 8a92d66..c26229e 100644 (file)
@@ -252,6 +252,11 @@ static const struct config_entry config_table[] = {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
                .device = 0x02c8,
        },
+       {
+               .flags = FLAG_SOF,
+               .device = 0x02c8,
+               .codec_hid = "ESSX8336",
+       },
 /* Cometlake-H */
        {
                .flags = FLAG_SOF,
@@ -276,6 +281,11 @@ static const struct config_entry config_table[] = {
                .flags = FLAG_SOF | FLAG_SOF_ONLY_IF_DMIC_OR_SOUNDWIRE,
                .device = 0x06c8,
        },
+               {
+               .flags = FLAG_SOF,
+               .device = 0x06c8,
+               .codec_hid = "ESSX8336",
+       },
 #endif
 
 /* Icelake */
@@ -299,6 +309,15 @@ static const struct config_entry config_table[] = {
        },
 #endif
 
+/* JasperLake */
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE)
+       {
+               .flags = FLAG_SOF,
+               .device = 0x4dc8,
+               .codec_hid = "ESSX8336",
+       },
+#endif
+
 /* Tigerlake */
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE)
        {
index c0123bc..b7758db 100644 (file)
@@ -132,8 +132,6 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
                return AE_NOT_FOUND;
        }
 
-       info->handle = handle;
-
        /*
         * On some Intel platforms, multiple children of the HDAS
         * device can be found, but only one of them is the SoundWire
@@ -144,6 +142,9 @@ static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level,
        if (FIELD_GET(GENMASK(31, 28), adr) != SDW_LINK_TYPE)
                return AE_OK; /* keep going */
 
+       /* found the correct SoundWire controller */
+       info->handle = handle;
+
        /* device found, stop namespace walk */
        return AE_CTRL_TERMINATE;
 }
@@ -164,8 +165,14 @@ int sdw_intel_acpi_scan(acpi_handle *parent_handle,
        acpi_status status;
 
        info->handle = NULL;
+       /*
+        * In the HDAS ACPI scope, 'SNDW' may be either the child of
+        * 'HDAS' or the grandchild of 'HDAS'. So let's go through
+        * the ACPI from 'HDAS' at max depth of 2 to find the 'SNDW'
+        * device.
+        */
        status = acpi_walk_namespace(ACPI_TYPE_DEVICE,
-                                    parent_handle, 1,
+                                    parent_handle, 2,
                                     sdw_intel_acpi_cb,
                                     NULL, info, NULL);
        if (ACPI_FAILURE(status) || info->handle == NULL)
index ea20236..9a678b5 100644 (file)
@@ -3218,7 +3218,6 @@ static int snd_cmipci_probe(struct pci_dev *pci,
 {
        static int dev;
        struct snd_card *card;
-       struct cmipci *cm;
        int err;
 
        if (dev >= SNDRV_CARDS)
@@ -3229,10 +3228,9 @@ static int snd_cmipci_probe(struct pci_dev *pci,
        }
 
        err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
-                               sizeof(*cm), &card);
+                               sizeof(struct cmipci), &card);
        if (err < 0)
                return err;
-       cm = card->private_data;
        
        switch (pci->device) {
        case PCI_DEVICE_ID_CMEDIA_CM8738:
index da6e635..d074727 100644 (file)
 
 #define BLANK_SLOT             4094
 
-static int amixer_master(struct rsc *rsc)
+static void amixer_master(struct rsc *rsc)
 {
        rsc->conj = 0;
-       return rsc->idx = container_of(rsc, struct amixer, rsc)->idx[0];
+       rsc->idx = container_of(rsc, struct amixer, rsc)->idx[0];
 }
 
-static int amixer_next_conj(struct rsc *rsc)
+static void amixer_next_conj(struct rsc *rsc)
 {
        rsc->conj++;
-       return container_of(rsc, struct amixer, rsc)->idx[rsc->conj];
 }
 
 static int amixer_index(const struct rsc *rsc)
@@ -331,16 +330,15 @@ int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr)
 
 /* SUM resource management */
 
-static int sum_master(struct rsc *rsc)
+static void sum_master(struct rsc *rsc)
 {
        rsc->conj = 0;
-       return rsc->idx = container_of(rsc, struct sum, rsc)->idx[0];
+       rsc->idx = container_of(rsc, struct sum, rsc)->idx[0];
 }
 
-static int sum_next_conj(struct rsc *rsc)
+static void sum_next_conj(struct rsc *rsc)
 {
        rsc->conj++;
-       return container_of(rsc, struct sum, rsc)->idx[rsc->conj];
 }
 
 static int sum_index(const struct rsc *rsc)
index f589da0..7fc7200 100644 (file)
@@ -51,12 +51,12 @@ static const struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = {
        [SPDIFIO] = {.left = 0x05, .right = 0x85},
 };
 
-static int daio_master(struct rsc *rsc)
+static void daio_master(struct rsc *rsc)
 {
        /* Actually, this is not the resource index of DAIO.
         * For DAO, it is the input mapper index. And, for DAI,
         * it is the output time-slot index. */
-       return rsc->conj = rsc->idx;
+       rsc->conj = rsc->idx;
 }
 
 static int daio_index(const struct rsc *rsc)
@@ -64,19 +64,19 @@ static int daio_index(const struct rsc *rsc)
        return rsc->conj;
 }
 
-static int daio_out_next_conj(struct rsc *rsc)
+static void daio_out_next_conj(struct rsc *rsc)
 {
-       return rsc->conj += 2;
+       rsc->conj += 2;
 }
 
-static int daio_in_next_conj_20k1(struct rsc *rsc)
+static void daio_in_next_conj_20k1(struct rsc *rsc)
 {
-       return rsc->conj += 0x200;
+       rsc->conj += 0x200;
 }
 
-static int daio_in_next_conj_20k2(struct rsc *rsc)
+static void daio_in_next_conj_20k2(struct rsc *rsc)
 {
-       return rsc->conj += 0x100;
+       rsc->conj += 0x100;
 }
 
 static const struct rsc_ops daio_out_rsc_ops = {
index 81ad269..be1d3e6 100644 (file)
@@ -109,18 +109,17 @@ static int audio_ring_slot(const struct rsc *rsc)
     return (rsc->conj << 4) + offset_in_audio_slot_block[rsc->type];
 }
 
-static int rsc_next_conj(struct rsc *rsc)
+static void rsc_next_conj(struct rsc *rsc)
 {
        unsigned int i;
        for (i = 0; (i < 8) && (!(rsc->msr & (0x1 << i))); )
                i++;
        rsc->conj += (AUDIO_SLOT_BLOCK_NUM >> i);
-       return rsc->conj;
 }
 
-static int rsc_master(struct rsc *rsc)
+static void rsc_master(struct rsc *rsc)
 {
-       return rsc->conj = rsc->idx;
+       rsc->conj = rsc->idx;
 }
 
 static const struct rsc_ops rsc_generic_ops = {
index fdbfd80..58553bd 100644 (file)
@@ -39,8 +39,8 @@ struct rsc {
 };
 
 struct rsc_ops {
-       int (*master)(struct rsc *rsc); /* Move to master resource */
-       int (*next_conj)(struct rsc *rsc); /* Move to next conjugate resource */
+       void (*master)(struct rsc *rsc); /* Move to master resource */
+       void (*next_conj)(struct rsc *rsc); /* Move to next conjugate resource */
        int (*index)(const struct rsc *rsc); /* Return the index of resource */
        /* Return the output slot number */
        int (*output_slot)(const struct rsc *rsc);
index bd4697b..4a94b47 100644 (file)
@@ -590,16 +590,15 @@ int src_mgr_destroy(struct src_mgr *src_mgr)
 
 /* SRCIMP resource manager operations */
 
-static int srcimp_master(struct rsc *rsc)
+static void srcimp_master(struct rsc *rsc)
 {
        rsc->conj = 0;
-       return rsc->idx = container_of(rsc, struct srcimp, rsc)->idx[0];
+       rsc->idx = container_of(rsc, struct srcimp, rsc)->idx[0];
 }
 
-static int srcimp_next_conj(struct rsc *rsc)
+static void srcimp_next_conj(struct rsc *rsc)
 {
        rsc->conj++;
-       return container_of(rsc, struct srcimp, rsc)->idx[rsc->conj];
 }
 
 static int srcimp_index(const struct rsc *rsc)
index de0c2df..4b0338c 100644 (file)
@@ -335,7 +335,10 @@ enum {
                                        ((pci)->device == 0x0c0c) || \
                                        ((pci)->device == 0x0d0c) || \
                                        ((pci)->device == 0x160c) || \
-                                       ((pci)->device == 0x490d))
+                                       ((pci)->device == 0x490d) || \
+                                       ((pci)->device == 0x4f90) || \
+                                       ((pci)->device == 0x4f91) || \
+                                       ((pci)->device == 0x4f92))
 
 #define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98)
 
@@ -2477,6 +2480,13 @@ static const struct pci_device_id azx_ids[] = {
        /* DG1 */
        { PCI_DEVICE(0x8086, 0x490d),
          .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+       /* DG2 */
+       { PCI_DEVICE(0x8086, 0x4f90),
+         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+       { PCI_DEVICE(0x8086, 0x4f91),
+         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
+       { PCI_DEVICE(0x8086, 0x4f92),
+         .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
        /* Alderlake-S */
        { PCI_DEVICE(0x8086, 0x7ad0),
          .driver_data = AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE},
index 4662a47..8621f57 100644 (file)
@@ -439,6 +439,15 @@ int snd_hda_codec_set_pin_target(struct hda_codec *codec, hda_nid_t nid,
 #define for_each_hda_codec_node(nid, codec) \
        for ((nid) = (codec)->core.start_nid; (nid) < (codec)->core.end_nid; (nid)++)
 
+/* Set the codec power_state flag to indicate to allow unsol event handling;
+ * see hda_codec_unsol_event() in hda_bind.c.  Calling this might confuse the
+ * state tracking, so use with care.
+ */
+static inline void snd_hda_codec_allow_unsol_events(struct hda_codec *codec)
+{
+       codec->core.dev.power.power_state = PMSG_ON;
+}
+
 /*
  * get widget capabilities
  */
index 9319ca8..aff2b5a 100644 (file)
@@ -752,6 +752,11 @@ static void cs42l42_resume(struct sub_codec *cs42l42)
        if (cs42l42->full_scale_vol)
                cs8409_i2c_write(cs42l42, 0x2001, 0x01);
 
+       /* we have to explicitly allow unsol event handling even during the
+        * resume phase so that the jack event is processed properly
+        */
+       snd_hda_codec_allow_unsol_events(cs42l42->codec);
+
        cs42l42_enable_jack_detect(cs42l42);
 }
 
index 4ac2a28..92df4f2 100644 (file)
@@ -4389,10 +4389,11 @@ HDA_CODEC_ENTRY(0x8086280f, "Icelake HDMI",     patch_i915_icl_hdmi),
 HDA_CODEC_ENTRY(0x80862812, "Tigerlake HDMI",  patch_i915_tgl_hdmi),
 HDA_CODEC_ENTRY(0x80862814, "DG1 HDMI",        patch_i915_tgl_hdmi),
 HDA_CODEC_ENTRY(0x80862815, "Alderlake HDMI",  patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x8086281c, "Alderlake-P HDMI", patch_i915_tgl_hdmi),
 HDA_CODEC_ENTRY(0x80862816, "Rocketlake HDMI", patch_i915_tgl_hdmi),
+HDA_CODEC_ENTRY(0x80862819, "DG2 HDMI",        patch_i915_tgl_hdmi),
 HDA_CODEC_ENTRY(0x8086281a, "Jasperlake HDMI", patch_i915_icl_hdmi),
 HDA_CODEC_ENTRY(0x8086281b, "Elkhartlake HDMI",        patch_i915_icl_hdmi),
+HDA_CODEC_ENTRY(0x8086281c, "Alderlake-P HDMI", patch_i915_tgl_hdmi),
 HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi),
 HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI",        patch_i915_byt_hdmi),
 HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI",   patch_i915_byt_hdmi),
index 2eea706..98736f2 100644 (file)
@@ -6531,22 +6531,64 @@ static void alc287_fixup_legion_15imhg05_speakers(struct hda_codec *codec,
 /* for alc285_fixup_ideapad_s740_coef() */
 #include "ideapad_s740_helper.c"
 
-static void alc256_fixup_tongfang_reset_persistent_settings(struct hda_codec *codec,
-                                                           const struct hda_fixup *fix,
-                                                           int action)
+static const struct coef_fw alc256_fixup_set_coef_defaults_coefs[] = {
+       WRITE_COEF(0x10, 0x0020), WRITE_COEF(0x24, 0x0000),
+       WRITE_COEF(0x26, 0x0000), WRITE_COEF(0x29, 0x3000),
+       WRITE_COEF(0x37, 0xfe05), WRITE_COEF(0x45, 0x5089),
+       {}
+};
+
+static void alc256_fixup_set_coef_defaults(struct hda_codec *codec,
+                                          const struct hda_fixup *fix,
+                                          int action)
 {
        /*
-       * A certain other OS sets these coeffs to different values. On at least one TongFang
-       * barebone these settings might survive even a cold reboot. So to restore a clean slate the
-       * values are explicitly reset to default here. Without this, the external microphone is
-       * always in a plugged-in state, while the internal microphone is always in an unplugged
-       * state, breaking the ability to use the internal microphone.
-       */
-       alc_write_coef_idx(codec, 0x24, 0x0000);
-       alc_write_coef_idx(codec, 0x26, 0x0000);
-       alc_write_coef_idx(codec, 0x29, 0x3000);
-       alc_write_coef_idx(codec, 0x37, 0xfe05);
-       alc_write_coef_idx(codec, 0x45, 0x5089);
+        * A certain other OS sets these coeffs to different values. On at least
+        * one TongFang barebone these settings might survive even a cold
+        * reboot. So to restore a clean slate the values are explicitly reset
+        * to default here. Without this, the external microphone is always in a
+        * plugged-in state, while the internal microphone is always in an
+        * unplugged state, breaking the ability to use the internal microphone.
+        */
+       alc_process_coef_fw(codec, alc256_fixup_set_coef_defaults_coefs);
+}
+
+static const struct coef_fw alc233_fixup_no_audio_jack_coefs[] = {
+       WRITE_COEF(0x1a, 0x9003), WRITE_COEF(0x1b, 0x0e2b), WRITE_COEF(0x37, 0xfe06),
+       WRITE_COEF(0x38, 0x4981), WRITE_COEF(0x45, 0xd489), WRITE_COEF(0x46, 0x0074),
+       WRITE_COEF(0x49, 0x0149),
+       {}
+};
+
+static void alc233_fixup_no_audio_jack(struct hda_codec *codec,
+                                      const struct hda_fixup *fix,
+                                      int action)
+{
+       /*
+        * The audio jack input and output is not detected on the ASRock NUC Box
+        * 1100 series when cold booting without this fix. Warm rebooting from a
+        * certain other OS makes the audio functional, as COEF settings are
+        * preserved in this case. This fix sets these altered COEF values as
+        * the default.
+        */
+       alc_process_coef_fw(codec, alc233_fixup_no_audio_jack_coefs);
+}
+
+static void alc256_fixup_mic_no_presence_and_resume(struct hda_codec *codec,
+                                                   const struct hda_fixup *fix,
+                                                   int action)
+{
+       /*
+        * The Clevo NJ51CU comes either with the ALC293 or the ALC256 codec,
+        * but uses the 0x8686 subproduct id in both cases. The ALC256 codec
+        * needs an additional quirk for sound working after suspend and resume.
+        */
+       if (codec->core.vendor_id == 0x10ec0256) {
+               alc_update_coef_idx(codec, 0x10, 1<<9, 0);
+               snd_hda_codec_set_pincfg(codec, 0x19, 0x04a11120);
+       } else {
+               snd_hda_codec_set_pincfg(codec, 0x1a, 0x04a1113c);
+       }
 }
 
 enum {
@@ -6766,8 +6808,10 @@ enum {
        ALC287_FIXUP_LEGION_15IMHG05_AUTOMUTE,
        ALC287_FIXUP_YOGA7_14ITL_SPEAKERS,
        ALC287_FIXUP_13S_GEN2_SPEAKERS,
-       ALC256_FIXUP_TONGFANG_RESET_PERSISTENT_SETTINGS,
+       ALC256_FIXUP_SET_COEF_DEFAULTS,
        ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE,
+       ALC233_FIXUP_NO_AUDIO_JACK,
+       ALC256_FIXUP_MIC_NO_PRESENCE_AND_RESUME,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -8471,9 +8515,9 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC269_FIXUP_HEADSET_MODE,
        },
-       [ALC256_FIXUP_TONGFANG_RESET_PERSISTENT_SETTINGS] = {
+       [ALC256_FIXUP_SET_COEF_DEFAULTS] = {
                .type = HDA_FIXUP_FUNC,
-               .v.func = alc256_fixup_tongfang_reset_persistent_settings,
+               .v.func = alc256_fixup_set_coef_defaults,
        },
        [ALC245_FIXUP_HP_GPIO_LED] = {
                .type = HDA_FIXUP_FUNC,
@@ -8488,6 +8532,16 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC,
        },
+       [ALC233_FIXUP_NO_AUDIO_JACK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc233_fixup_no_audio_jack,
+       },
+       [ALC256_FIXUP_MIC_NO_PRESENCE_AND_RESUME] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc256_fixup_mic_no_presence_and_resume,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -8658,6 +8712,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x84da, "HP OMEN dc0019-ur", ALC295_FIXUP_HP_OMEN),
        SND_PCI_QUIRK(0x103c, 0x84e7, "HP Pavilion 15", ALC269_FIXUP_HP_MUTE_LED_MIC3),
        SND_PCI_QUIRK(0x103c, 0x8519, "HP Spectre x360 15-df0xxx", ALC285_FIXUP_HP_SPECTRE_X360),
+       SND_PCI_QUIRK(0x103c, 0x860f, "HP ZBook 15 G6", ALC285_FIXUP_HP_GPIO_AMP_INIT),
        SND_PCI_QUIRK(0x103c, 0x861f, "HP Elite Dragonfly G1", ALC285_FIXUP_HP_GPIO_AMP_INIT),
        SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED),
        SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO),
@@ -8667,6 +8722,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x8728, "HP EliteBook 840 G7", ALC285_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8729, "HP", ALC285_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8730, "HP ProBook 445 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8735, "HP ProBook 435 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x8736, "HP", ALC285_FIXUP_HP_GPIO_AMP_INIT),
        SND_PCI_QUIRK(0x103c, 0x8760, "HP", ALC285_FIXUP_HP_MUTE_LED),
        SND_PCI_QUIRK(0x103c, 0x877a, "HP", ALC285_FIXUP_HP_MUTE_LED),
@@ -8702,6 +8758,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x8896, "HP EliteBook 855 G8 Notebook PC", ALC285_FIXUP_HP_MUTE_LED),
        SND_PCI_QUIRK(0x103c, 0x8898, "HP EliteBook 845 G8 Notebook PC", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x103c, 0x88d0, "HP Pavilion 15-eh1xxx (mainboard 88D0)", ALC287_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x89c3, "HP", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x89ca, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
        SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -8826,7 +8884,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1558, 0x8562, "Clevo NH[57][0-9]RZ[Q]", ALC269_FIXUP_DMIC),
        SND_PCI_QUIRK(0x1558, 0x8668, "Clevo NP50B[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x8680, "Clevo NJ50LU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x8686, "Clevo NH50[CZ]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x8686, "Clevo NH50[CZ]U", ALC256_FIXUP_MIC_NO_PRESENCE_AND_RESUME),
        SND_PCI_QUIRK(0x1558, 0x8a20, "Clevo NH55DCQ-Y", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x8a51, "Clevo NH70RCQ-Y", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x8d50, "Clevo NH55RCQ-M", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
@@ -8898,6 +8956,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x3813, "Legion 7i 15IMHG05", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS),
        SND_PCI_QUIRK(0x17aa, 0x3852, "Lenovo Yoga 7 14ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
        SND_PCI_QUIRK(0x17aa, 0x3853, "Lenovo Yoga 7 15ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
+       SND_PCI_QUIRK(0x17aa, 0x384a, "Lenovo Yoga 7 15ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
        SND_PCI_QUIRK(0x17aa, 0x3819, "Lenovo 13s Gen2 ITL", ALC287_FIXUP_13S_GEN2_SPEAKERS),
        SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
        SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
@@ -8922,6 +8981,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x511e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
+       SND_PCI_QUIRK(0x1849, 0x1233, "ASRock NUC Box 1100", ALC233_FIXUP_NO_AUDIO_JACK),
        SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MACH-WX9", ALC256_FIXUP_HUAWEI_MACH_WX9_PINS),
        SND_PCI_QUIRK(0x1b35, 0x1235, "CZC B20", ALC269_FIXUP_CZC_B20),
        SND_PCI_QUIRK(0x1b35, 0x1236, "CZC TMI", ALC269_FIXUP_CZC_TMI),
@@ -8929,7 +8989,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
        SND_PCI_QUIRK(0x1c06, 0x2013, "Lemote A1802", ALC269_FIXUP_LEMOTE_A1802),
        SND_PCI_QUIRK(0x1c06, 0x2015, "Lemote A190X", ALC269_FIXUP_LEMOTE_A190X),
-       SND_PCI_QUIRK(0x1d05, 0x1132, "TongFang PHxTxX1", ALC256_FIXUP_TONGFANG_RESET_PERSISTENT_SETTINGS),
+       SND_PCI_QUIRK(0x1d05, 0x1132, "TongFang PHxTxX1", ALC256_FIXUP_SET_COEF_DEFAULTS),
        SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
        SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC),
@@ -9119,6 +9179,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {.id = ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP, .name = "alc287-ideapad-bass-spk-amp"},
        {.id = ALC623_FIXUP_LENOVO_THINKSTATION_P340, .name = "alc623-lenovo-thinkstation-p340"},
        {.id = ALC255_FIXUP_ACER_HEADPHONE_AND_MIC, .name = "alc255-acer-headphone-and-mic"},
+       {.id = ALC285_FIXUP_HP_GPIO_AMP_INIT, .name = "alc285-hp-amp-init"},
        {}
 };
 #define ALC225_STANDARD_PINS \
@@ -10231,6 +10292,27 @@ static void alc671_fixup_hp_headset_mic2(struct hda_codec *codec,
        }
 }
 
+static void alc897_hp_automute_hook(struct hda_codec *codec,
+                                        struct hda_jack_callback *jack)
+{
+       struct alc_spec *spec = codec->spec;
+       int vref;
+
+       snd_hda_gen_hp_automute(codec, jack);
+       vref = spec->gen.hp_jack_present ? (PIN_HP | AC_PINCTL_VREF_100) : PIN_HP;
+       snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           vref);
+}
+
+static void alc897_fixup_lenovo_headset_mic(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->gen.hp_automute_hook = alc897_hp_automute_hook;
+       }
+}
+
 static const struct coef_fw alc668_coefs[] = {
        WRITE_COEF(0x01, 0xbebe), WRITE_COEF(0x02, 0xaaaa), WRITE_COEF(0x03,    0x0),
        WRITE_COEF(0x04, 0x0180), WRITE_COEF(0x06,    0x0), WRITE_COEF(0x07, 0x0f80),
@@ -10311,6 +10393,8 @@ enum {
        ALC668_FIXUP_ASUS_NO_HEADSET_MIC,
        ALC668_FIXUP_HEADSET_MIC,
        ALC668_FIXUP_MIC_DET_COEF,
+       ALC897_FIXUP_LENOVO_HEADSET_MIC,
+       ALC897_FIXUP_HEADSET_MIC_PIN,
 };
 
 static const struct hda_fixup alc662_fixups[] = {
@@ -10717,6 +10801,19 @@ static const struct hda_fixup alc662_fixups[] = {
                        {}
                },
        },
+       [ALC897_FIXUP_LENOVO_HEADSET_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc897_fixup_lenovo_headset_mic,
+       },
+       [ALC897_FIXUP_HEADSET_MIC_PIN] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x03a11050 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC897_FIXUP_LENOVO_HEADSET_MIC
+       },
 };
 
 static const struct snd_pci_quirk alc662_fixup_tbl[] = {
@@ -10761,6 +10858,10 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
        SND_PCI_QUIRK(0x14cd, 0x5003, "USI", ALC662_FIXUP_USI_HEADSET_MODE),
        SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC662_FIXUP_LENOVO_MULTI_CODECS),
+       SND_PCI_QUIRK(0x17aa, 0x32ca, "Lenovo ThinkCentre M80", ALC897_FIXUP_HEADSET_MIC_PIN),
+       SND_PCI_QUIRK(0x17aa, 0x32cb, "Lenovo ThinkCentre M70", ALC897_FIXUP_HEADSET_MIC_PIN),
+       SND_PCI_QUIRK(0x17aa, 0x32cf, "Lenovo ThinkCentre M950", ALC897_FIXUP_HEADSET_MIC_PIN),
+       SND_PCI_QUIRK(0x17aa, 0x32f7, "Lenovo ThinkCentre M90", ALC897_FIXUP_HEADSET_MIC_PIN),
        SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
        SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
        SND_PCI_QUIRK(0x1849, 0x5892, "ASRock B150M", ALC892_FIXUP_ASROCK_MOBO),
index 957eeb6..7e9a9a9 100644 (file)
@@ -146,10 +146,11 @@ static int snd_acp6x_probe(struct pci_dev *pci,
 {
        struct acp6x_dev_data *adata;
        struct platform_device_info pdevinfo[ACP6x_DEVS];
-       int ret, index;
+       int index = 0;
        int val = 0x00;
        u32 addr;
        unsigned int irqflags;
+       int ret;
 
        irqflags = IRQF_SHARED;
        /* Yellow Carp device check */
index 90a921f..3fa9974 100644 (file)
@@ -42,34 +42,6 @@ static const struct spi_device_id cs35l41_id_spi[] = {
 
 MODULE_DEVICE_TABLE(spi, cs35l41_id_spi);
 
-static void cs35l41_spi_otp_setup(struct cs35l41_private *cs35l41,
-                                 bool is_pre_setup, unsigned int *freq)
-{
-       struct spi_device *spi;
-       u32 orig_spi_freq;
-
-       spi = to_spi_device(cs35l41->dev);
-
-       if (!spi) {
-               dev_err(cs35l41->dev, "%s: No SPI device\n", __func__);
-               return;
-       }
-
-       if (is_pre_setup) {
-               orig_spi_freq = spi->max_speed_hz;
-               if (orig_spi_freq > CS35L41_SPI_MAX_FREQ_OTP) {
-                       spi->max_speed_hz = CS35L41_SPI_MAX_FREQ_OTP;
-                       spi_setup(spi);
-               }
-               *freq = orig_spi_freq;
-       } else {
-               if (spi->max_speed_hz != *freq) {
-                       spi->max_speed_hz = *freq;
-                       spi_setup(spi);
-               }
-       }
-}
-
 static int cs35l41_spi_probe(struct spi_device *spi)
 {
        const struct regmap_config *regmap_config = &cs35l41_regmap_spi;
@@ -81,6 +53,9 @@ static int cs35l41_spi_probe(struct spi_device *spi)
        if (!cs35l41)
                return -ENOMEM;
 
+       spi->max_speed_hz = CS35L41_SPI_MAX_FREQ;
+       spi_setup(spi);
+
        spi_set_drvdata(spi, cs35l41);
        cs35l41->regmap = devm_regmap_init_spi(spi, regmap_config);
        if (IS_ERR(cs35l41->regmap)) {
@@ -91,7 +66,6 @@ static int cs35l41_spi_probe(struct spi_device *spi)
 
        cs35l41->dev = &spi->dev;
        cs35l41->irq = spi->irq;
-       cs35l41->otp_setup = cs35l41_spi_otp_setup;
 
        return cs35l41_probe(cs35l41, pdata);
 }
index 94ed21d..9c4d481 100644 (file)
@@ -302,7 +302,6 @@ static int cs35l41_otp_unpack(void *data)
        const struct cs35l41_otp_packed_element_t *otp_map;
        struct cs35l41_private *cs35l41 = data;
        int bit_offset, word_offset, ret, i;
-       unsigned int orig_spi_freq;
        unsigned int bit_sum = 8;
        u32 otp_val, otp_id_reg;
        u32 *otp_mem;
@@ -326,9 +325,6 @@ static int cs35l41_otp_unpack(void *data)
                goto err_otp_unpack;
        }
 
-       if (cs35l41->otp_setup)
-               cs35l41->otp_setup(cs35l41, true, &orig_spi_freq);
-
        ret = regmap_bulk_read(cs35l41->regmap, CS35L41_OTP_MEM0, otp_mem,
                               CS35L41_OTP_SIZE_WORDS);
        if (ret < 0) {
@@ -336,9 +332,6 @@ static int cs35l41_otp_unpack(void *data)
                goto err_otp_unpack;
        }
 
-       if (cs35l41->otp_setup)
-               cs35l41->otp_setup(cs35l41, false, &orig_spi_freq);
-
        otp_map = otp_map_match->map;
 
        bit_offset = otp_map_match->bit_offset;
@@ -612,6 +605,12 @@ static const struct snd_soc_dapm_widget cs35l41_dapm_widgets[] = {
        SND_SOC_DAPM_AIF_OUT("ASPTX3", NULL, 0, CS35L41_SP_ENABLES, 2, 0),
        SND_SOC_DAPM_AIF_OUT("ASPTX4", NULL, 0, CS35L41_SP_ENABLES, 3, 0),
 
+       SND_SOC_DAPM_SIGGEN("VSENSE"),
+       SND_SOC_DAPM_SIGGEN("ISENSE"),
+       SND_SOC_DAPM_SIGGEN("VP"),
+       SND_SOC_DAPM_SIGGEN("VBST"),
+       SND_SOC_DAPM_SIGGEN("TEMP"),
+
        SND_SOC_DAPM_ADC("VMON ADC", NULL, CS35L41_PWR_CTRL2, 12, 0),
        SND_SOC_DAPM_ADC("IMON ADC", NULL, CS35L41_PWR_CTRL2, 13, 0),
        SND_SOC_DAPM_ADC("VPMON ADC", NULL, CS35L41_PWR_CTRL2, 8, 0),
@@ -623,12 +622,6 @@ static const struct snd_soc_dapm_widget cs35l41_dapm_widgets[] = {
                               cs35l41_main_amp_event,
                               SND_SOC_DAPM_POST_PMD |  SND_SOC_DAPM_POST_PMU),
 
-       SND_SOC_DAPM_INPUT("VP"),
-       SND_SOC_DAPM_INPUT("VBST"),
-       SND_SOC_DAPM_INPUT("ISENSE"),
-       SND_SOC_DAPM_INPUT("VSENSE"),
-       SND_SOC_DAPM_INPUT("TEMP"),
-
        SND_SOC_DAPM_MUX("ASP TX1 Source", SND_SOC_NOPM, 0, 0, &asp_tx1_mux),
        SND_SOC_DAPM_MUX("ASP TX2 Source", SND_SOC_NOPM, 0, 0, &asp_tx2_mux),
        SND_SOC_DAPM_MUX("ASP TX3 Source", SND_SOC_NOPM, 0, 0, &asp_tx3_mux),
@@ -674,8 +667,8 @@ static const struct snd_soc_dapm_route cs35l41_audio_map[] = {
        {"VMON ADC", NULL, "VSENSE"},
        {"IMON ADC", NULL, "ISENSE"},
        {"VPMON ADC", NULL, "VP"},
-       {"TEMPMON ADC", NULL, "TEMP"},
        {"VBSTMON ADC", NULL, "VBST"},
+       {"TEMPMON ADC", NULL, "TEMP"},
 
        {"ASPRX1", NULL, "AMP Playback"},
        {"ASPRX2", NULL, "AMP Playback"},
index 6cffe8a..48485b0 100644 (file)
 #define CS35L41_FS2_WINDOW_MASK                0x00FFF800
 #define CS35L41_FS2_WINDOW_SHIFT       12
 
-#define CS35L41_SPI_MAX_FREQ_OTP       4000000
+#define CS35L41_SPI_MAX_FREQ           4000000
 
 #define CS35L41_RX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
 #define CS35L41_TX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
@@ -764,8 +764,6 @@ struct cs35l41_private {
        int irq;
        /* GPIO for /RST */
        struct gpio_desc *reset_gpio;
-       void (*otp_setup)(struct cs35l41_private *cs35l41, bool is_pre_setup,
-                         unsigned int *freq);
 };
 
 int cs35l41_probe(struct cs35l41_private *cs35l41,
index 2bed5cf..aec5127 100644 (file)
@@ -2188,7 +2188,7 @@ static int rx_macro_config_classh(struct snd_soc_component *component,
                snd_soc_component_update_bits(component,
                                CDC_RX_CLSH_DECAY_CTRL,
                                CDC_RX_CLSH_DECAY_RATE_MASK, 0x0);
-               snd_soc_component_update_bits(component,
+               snd_soc_component_write_field(component,
                                CDC_RX_RX1_RX_PATH_CFG0,
                                CDC_RX_RXn_CLSH_EN_MASK, 0x1);
                break;
index 943d7d9..03f24ed 100644 (file)
@@ -539,3 +539,4 @@ module_platform_driver(rk817_codec_driver);
 MODULE_DESCRIPTION("ASoC RK817 codec driver");
 MODULE_AUTHOR("binyuan <kevan.lan@rock-chips.com>");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:rk817-codec");
index 297af7f..b62301a 100644 (file)
@@ -1311,13 +1311,54 @@ static int rt1011_r0_load_info(struct snd_kcontrol *kcontrol,
        .put = rt1011_r0_load_mode_put \
 }
 
-static const char * const rt1011_i2s_ref_texts[] = {
-       "Left Channel", "Right Channel"
+static const char * const rt1011_i2s_ref[] = {
+       "None", "Left Channel", "Right Channel"
 };
 
-static SOC_ENUM_SINGLE_DECL(rt1011_i2s_ref_enum,
-                           RT1011_TDM1_SET_1, 7,
-                           rt1011_i2s_ref_texts);
+static SOC_ENUM_SINGLE_DECL(rt1011_i2s_ref_enum, 0, 0,
+       rt1011_i2s_ref);
+
+static int rt1011_i2s_ref_put(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component =
+               snd_soc_kcontrol_component(kcontrol);
+       struct rt1011_priv *rt1011 =
+               snd_soc_component_get_drvdata(component);
+
+       rt1011->i2s_ref = ucontrol->value.enumerated.item[0];
+       switch (rt1011->i2s_ref) {
+       case RT1011_I2S_REF_LEFT_CH:
+               regmap_write(rt1011->regmap, RT1011_TDM_TOTAL_SET, 0x0240);
+               regmap_write(rt1011->regmap, RT1011_TDM1_SET_2, 0x8);
+               regmap_write(rt1011->regmap, RT1011_TDM1_SET_1, 0x1022);
+               regmap_write(rt1011->regmap, RT1011_ADCDAT_OUT_SOURCE, 0x4);
+               break;
+       case RT1011_I2S_REF_RIGHT_CH:
+               regmap_write(rt1011->regmap, RT1011_TDM_TOTAL_SET, 0x0240);
+               regmap_write(rt1011->regmap, RT1011_TDM1_SET_2, 0x8);
+               regmap_write(rt1011->regmap, RT1011_TDM1_SET_1, 0x10a2);
+               regmap_write(rt1011->regmap, RT1011_ADCDAT_OUT_SOURCE, 0x4);
+               break;
+       default:
+               dev_info(component->dev, "I2S Reference: Do nothing\n");
+       }
+
+       return 0;
+}
+
+static int rt1011_i2s_ref_get(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *component =
+               snd_soc_kcontrol_component(kcontrol);
+       struct rt1011_priv *rt1011 =
+               snd_soc_component_get_drvdata(component);
+
+       ucontrol->value.enumerated.item[0] = rt1011->i2s_ref;
+
+       return 0;
+}
 
 static const struct snd_kcontrol_new rt1011_snd_controls[] = {
        /* I2S Data In Selection */
@@ -1358,7 +1399,8 @@ static const struct snd_kcontrol_new rt1011_snd_controls[] = {
        SOC_SINGLE("R0 Temperature", RT1011_STP_INITIAL_RESISTANCE_TEMP,
                2, 255, 0),
        /* I2S Reference */
-       SOC_ENUM("I2S Reference", rt1011_i2s_ref_enum),
+       SOC_ENUM_EXT("I2S Reference", rt1011_i2s_ref_enum,
+               rt1011_i2s_ref_get, rt1011_i2s_ref_put),
 };
 
 static int rt1011_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
@@ -2017,6 +2059,7 @@ static int rt1011_probe(struct snd_soc_component *component)
 
        schedule_work(&rt1011->cali_work);
 
+       rt1011->i2s_ref = 0;
        rt1011->bq_drc_params = devm_kcalloc(component->dev,
                RT1011_ADVMODE_NUM, sizeof(struct rt1011_bq_drc_params *),
                GFP_KERNEL);
index 68fadc1..4d6e749 100644 (file)
@@ -654,6 +654,12 @@ enum {
        RT1011_AIFS
 };
 
+enum {
+       RT1011_I2S_REF_NONE,
+       RT1011_I2S_REF_LEFT_CH,
+       RT1011_I2S_REF_RIGHT_CH,
+};
+
 /* BiQual & DRC related settings */
 #define RT1011_BQ_DRC_NUM 128
 struct rt1011_bq_drc_params {
@@ -692,6 +698,7 @@ struct rt1011_priv {
        unsigned int r0_reg, cali_done;
        unsigned int r0_calib, temperature_calib;
        int recv_spk_mode;
+       int i2s_ref;
 };
 
 #endif         /* end of _RT1011_H_ */
index 983347b..20e0f90 100644 (file)
@@ -198,6 +198,7 @@ static int rt5682_i2c_probe(struct i2c_client *i2c,
        }
 
        mutex_init(&rt5682->calibrate_mutex);
+       mutex_init(&rt5682->jdet_mutex);
        rt5682_calibrate(rt5682);
 
        rt5682_apply_patch_list(rt5682, &i2c->dev);
index 78b4cb5..b34a854 100644 (file)
@@ -48,6 +48,8 @@ static const struct reg_sequence patch_list[] = {
        {RT5682_SAR_IL_CMD_6, 0x0110},
        {RT5682_CHARGE_PUMP_1, 0x0210},
        {RT5682_HP_LOGIC_CTRL_2, 0x0007},
+       {RT5682_SAR_IL_CMD_2, 0xac00},
+       {RT5682_CBJ_CTRL_7, 0x0104},
 };
 
 void rt5682_apply_patch_list(struct rt5682_priv *rt5682, struct device *dev)
@@ -927,6 +929,8 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
        unsigned int val, count;
 
        if (jack_insert) {
+               snd_soc_dapm_mutex_lock(dapm);
+
                snd_soc_component_update_bits(component, RT5682_PWR_ANLG_1,
                        RT5682_PWR_VREF2 | RT5682_PWR_MB,
                        RT5682_PWR_VREF2 | RT5682_PWR_MB);
@@ -940,6 +944,10 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
                snd_soc_component_update_bits(component,
                        RT5682_HP_CHARGE_PUMP_1,
                        RT5682_OSW_L_MASK | RT5682_OSW_R_MASK, 0);
+               rt5682_enable_push_button_irq(component, false);
+               snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
+                       RT5682_TRIG_JD_MASK, RT5682_TRIG_JD_LOW);
+               usleep_range(55000, 60000);
                snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
                        RT5682_TRIG_JD_MASK, RT5682_TRIG_JD_HIGH);
 
@@ -973,6 +981,8 @@ int rt5682_headset_detect(struct snd_soc_component *component, int jack_insert)
                snd_soc_component_update_bits(component, RT5682_MICBIAS_2,
                        RT5682_PWR_CLK25M_MASK | RT5682_PWR_CLK1M_MASK,
                        RT5682_PWR_CLK25M_PU | RT5682_PWR_CLK1M_PU);
+
+               snd_soc_dapm_mutex_unlock(dapm);
        } else {
                rt5682_enable_push_button_irq(component, false);
                snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
@@ -1092,6 +1102,7 @@ void rt5682_jack_detect_handler(struct work_struct *work)
        while (!rt5682->component->card->instantiated)
                usleep_range(10000, 15000);
 
+       mutex_lock(&rt5682->jdet_mutex);
        mutex_lock(&rt5682->calibrate_mutex);
 
        val = snd_soc_component_read(rt5682->component, RT5682_AJD1_CTRL)
@@ -1165,6 +1176,7 @@ void rt5682_jack_detect_handler(struct work_struct *work)
        }
 
        mutex_unlock(&rt5682->calibrate_mutex);
+       mutex_unlock(&rt5682->jdet_mutex);
 }
 EXPORT_SYMBOL_GPL(rt5682_jack_detect_handler);
 
@@ -1514,6 +1526,7 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
 {
        struct snd_soc_component *component =
                snd_soc_dapm_to_component(w->dapm);
+       struct rt5682_priv *rt5682 = snd_soc_component_get_drvdata(component);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
@@ -1525,12 +1538,17 @@ static int rt5682_hp_event(struct snd_soc_dapm_widget *w,
                        RT5682_DEPOP_1, 0x60, 0x60);
                snd_soc_component_update_bits(component,
                        RT5682_DAC_ADC_DIG_VOL1, 0x00c0, 0x0080);
+
+               mutex_lock(&rt5682->jdet_mutex);
+
                snd_soc_component_update_bits(component, RT5682_HP_CTRL_2,
                        RT5682_HP_C2_DAC_L_EN | RT5682_HP_C2_DAC_R_EN,
                        RT5682_HP_C2_DAC_L_EN | RT5682_HP_C2_DAC_R_EN);
                usleep_range(5000, 10000);
                snd_soc_component_update_bits(component, RT5682_CHARGE_PUMP_1,
                        RT5682_CP_SW_SIZE_MASK, RT5682_CP_SW_SIZE_L);
+
+               mutex_unlock(&rt5682->jdet_mutex);
                break;
 
        case SND_SOC_DAPM_POST_PMD:
@@ -2844,6 +2862,8 @@ int rt5682_register_dai_clks(struct rt5682_priv *rt5682)
 
        for (i = 0; i < RT5682_DAI_NUM_CLKS; ++i) {
                struct clk_init_data init = { };
+               struct clk_parent_data parent_data;
+               const struct clk_hw *parent;
 
                dai_clk_hw = &rt5682->dai_clks_hw[i];
 
@@ -2851,17 +2871,17 @@ int rt5682_register_dai_clks(struct rt5682_priv *rt5682)
                case RT5682_DAI_WCLK_IDX:
                        /* Make MCLK the parent of WCLK */
                        if (rt5682->mclk) {
-                               init.parent_data = &(struct clk_parent_data){
+                               parent_data = (struct clk_parent_data){
                                        .fw_name = "mclk",
                                };
+                               init.parent_data = &parent_data;
                                init.num_parents = 1;
                        }
                        break;
                case RT5682_DAI_BCLK_IDX:
                        /* Make WCLK the parent of BCLK */
-                       init.parent_hws = &(const struct clk_hw *){
-                               &rt5682->dai_clks_hw[RT5682_DAI_WCLK_IDX]
-                       };
+                       parent = &rt5682->dai_clks_hw[RT5682_DAI_WCLK_IDX];
+                       init.parent_hws = &parent;
                        init.num_parents = 1;
                        break;
                default:
@@ -2942,10 +2962,7 @@ static int rt5682_suspend(struct snd_soc_component *component)
 
        cancel_delayed_work_sync(&rt5682->jack_detect_work);
        cancel_delayed_work_sync(&rt5682->jd_check_work);
-       if (rt5682->hs_jack && rt5682->jack_type == SND_JACK_HEADSET) {
-               snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
-                       RT5682_MB1_PATH_MASK | RT5682_MB2_PATH_MASK,
-                       RT5682_CTRL_MB1_REG | RT5682_CTRL_MB2_REG);
+       if (rt5682->hs_jack && (rt5682->jack_type & SND_JACK_HEADSET) == SND_JACK_HEADSET) {
                val = snd_soc_component_read(component,
                                RT5682_CBJ_CTRL_2) & RT5682_JACK_TYPE_MASK;
 
@@ -2967,10 +2984,17 @@ static int rt5682_suspend(struct snd_soc_component *component)
                /* enter SAR ADC power saving mode */
                snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
                        RT5682_SAR_BUTT_DET_MASK | RT5682_SAR_BUTDET_MODE_MASK |
-                       RT5682_SAR_BUTDET_RST_MASK | RT5682_SAR_SEL_MB1_MB2_MASK, 0);
+                       RT5682_SAR_SEL_MB1_MB2_MASK, 0);
+               usleep_range(5000, 6000);
+               snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
+                       RT5682_MB1_PATH_MASK | RT5682_MB2_PATH_MASK,
+                       RT5682_CTRL_MB1_REG | RT5682_CTRL_MB2_REG);
+               usleep_range(10000, 12000);
                snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
-                       RT5682_SAR_BUTT_DET_MASK | RT5682_SAR_BUTDET_MODE_MASK | RT5682_SAR_BUTDET_RST_MASK,
-                       RT5682_SAR_BUTT_DET_EN | RT5682_SAR_BUTDET_POW_SAV | RT5682_SAR_BUTDET_RST_NORMAL);
+                       RT5682_SAR_BUTT_DET_MASK | RT5682_SAR_BUTDET_MODE_MASK,
+                       RT5682_SAR_BUTT_DET_EN | RT5682_SAR_BUTDET_POW_SAV);
+               snd_soc_component_update_bits(component, RT5682_HP_CHARGE_PUMP_1,
+                       RT5682_OSW_L_MASK | RT5682_OSW_R_MASK, 0);
        }
 
        regcache_cache_only(rt5682->regmap, true);
@@ -2988,10 +3012,11 @@ static int rt5682_resume(struct snd_soc_component *component)
        regcache_cache_only(rt5682->regmap, false);
        regcache_sync(rt5682->regmap);
 
-       if (rt5682->hs_jack && rt5682->jack_type == SND_JACK_HEADSET) {
+       if (rt5682->hs_jack && (rt5682->jack_type & SND_JACK_HEADSET) == SND_JACK_HEADSET) {
                snd_soc_component_update_bits(component, RT5682_SAR_IL_CMD_1,
                        RT5682_SAR_BUTDET_MODE_MASK | RT5682_SAR_SEL_MB1_MB2_MASK,
                        RT5682_SAR_BUTDET_POW_NORM | RT5682_SAR_SEL_MB1_MB2_AUTO);
+               usleep_range(5000, 6000);
                snd_soc_component_update_bits(component, RT5682_CBJ_CTRL_1,
                        RT5682_MB1_PATH_MASK | RT5682_MB2_PATH_MASK,
                        RT5682_CTRL_MB1_FSM | RT5682_CTRL_MB2_FSM);
@@ -2999,8 +3024,9 @@ static int rt5682_resume(struct snd_soc_component *component)
                        RT5682_PWR_CBJ, RT5682_PWR_CBJ);
        }
 
+       rt5682->jack_type = 0;
        mod_delayed_work(system_power_efficient_wq,
-               &rt5682->jack_detect_work, msecs_to_jiffies(250));
+               &rt5682->jack_detect_work, msecs_to_jiffies(0));
 
        return 0;
 }
index d93829c..c917c76 100644 (file)
@@ -1463,6 +1463,7 @@ struct rt5682_priv {
 
        int jack_type;
        int irq_work_delay_time;
+       struct mutex jdet_mutex;
 };
 
 extern const char *rt5682_supply_names[RT5682_NUM_SUPPLIES];
index 470957f..d49a4f6 100644 (file)
@@ -2693,6 +2693,8 @@ static int rt5682s_register_dai_clks(struct snd_soc_component *component)
 
        for (i = 0; i < RT5682S_DAI_NUM_CLKS; ++i) {
                struct clk_init_data init = { };
+               struct clk_parent_data parent_data;
+               const struct clk_hw *parent;
 
                dai_clk_hw = &rt5682s->dai_clks_hw[i];
 
@@ -2700,17 +2702,17 @@ static int rt5682s_register_dai_clks(struct snd_soc_component *component)
                case RT5682S_DAI_WCLK_IDX:
                        /* Make MCLK the parent of WCLK */
                        if (rt5682s->mclk) {
-                               init.parent_data = &(struct clk_parent_data){
+                               parent_data = (struct clk_parent_data){
                                        .fw_name = "mclk",
                                };
+                               init.parent_data = &parent_data;
                                init.num_parents = 1;
                        }
                        break;
                case RT5682S_DAI_BCLK_IDX:
                        /* Make WCLK the parent of BCLK */
-                       init.parent_hws = &(const struct clk_hw *){
-                               &rt5682s->dai_clks_hw[RT5682S_DAI_WCLK_IDX]
-                       };
+                       parent = &rt5682s->dai_clks_hw[RT5682S_DAI_WCLK_IDX];
+                       init.parent_hws = &parent;
                        init.num_parents = 1;
                        break;
                default:
index f957498..7aa1772 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 
 #include <linux/bits.h>
+#include <linux/bitfield.h>
 #include <linux/delay.h>
 #include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
 #define RT9120_REG_ERRRPT      0x10
 #define RT9120_REG_MSVOL       0x20
 #define RT9120_REG_SWRESET     0x40
+#define RT9120_REG_INTERCFG    0x63
 #define RT9120_REG_INTERNAL0   0x65
 #define RT9120_REG_INTERNAL1   0x69
 #define RT9120_REG_UVPOPT      0x6C
+#define RT9120_REG_DIGCFG      0xF8
 
 #define RT9120_VID_MASK                GENMASK(15, 8)
 #define RT9120_SWRST_MASK      BIT(7)
 #define RT9120_CFG_WORDLEN_24  24
 #define RT9120_CFG_WORDLEN_32  32
 #define RT9120_DVDD_UVSEL_MASK GENMASK(5, 4)
+#define RT9120_AUTOSYNC_MASK   BIT(6)
 
-#define RT9120_VENDOR_ID       0x4200
+#define RT9120_VENDOR_ID       0x42
+#define RT9120S_VENDOR_ID      0x43
 #define RT9120_RESET_WAITMS    20
 #define RT9120_CHIPON_WAITMS   20
 #define RT9120_AMPON_WAITMS    50
                                 SNDRV_PCM_FMTBIT_S24_LE |\
                                 SNDRV_PCM_FMTBIT_S32_LE)
 
+enum {
+       CHIP_IDX_RT9120 = 0,
+       CHIP_IDX_RT9120S,
+       CHIP_IDX_MAX
+};
+
 struct rt9120_data {
        struct device *dev;
        struct regmap *regmap;
+       int chip_idx;
 };
 
 /* 11bit [min,max,step] = [-103.9375dB, 24dB, 0.0625dB] */
@@ -149,8 +161,12 @@ static int rt9120_codec_probe(struct snd_soc_component *comp)
        snd_soc_component_init_regmap(comp, data->regmap);
 
        /* Internal setting */
-       snd_soc_component_write(comp, RT9120_REG_INTERNAL1, 0x03);
-       snd_soc_component_write(comp, RT9120_REG_INTERNAL0, 0x69);
+       if (data->chip_idx == CHIP_IDX_RT9120S) {
+               snd_soc_component_write(comp, RT9120_REG_INTERCFG, 0xde);
+               snd_soc_component_write(comp, RT9120_REG_INTERNAL0, 0x66);
+       } else
+               snd_soc_component_write(comp, RT9120_REG_INTERNAL0, 0x04);
+
        return 0;
 }
 
@@ -201,8 +217,8 @@ static int rt9120_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_component *comp = dai->component;
-       unsigned int param_width, param_slot_width;
-       int width;
+       unsigned int param_width, param_slot_width, auto_sync;
+       int width, fs;
 
        switch (width = params_width(param)) {
        case 16:
@@ -240,6 +256,16 @@ static int rt9120_hw_params(struct snd_pcm_substream *substream,
 
        snd_soc_component_update_bits(comp, RT9120_REG_I2SWL,
                                      RT9120_AUDWL_MASK, param_slot_width);
+
+       fs = width * params_channels(param);
+       /* If fs is divided by 48, disable auto sync */
+       if (fs % 48 == 0)
+               auto_sync = 0;
+       else
+               auto_sync = RT9120_AUTOSYNC_MASK;
+
+       snd_soc_component_update_bits(comp, RT9120_REG_DIGCFG,
+                                     RT9120_AUTOSYNC_MASK, auto_sync);
        return 0;
 }
 
@@ -279,9 +305,11 @@ static const struct regmap_range rt9120_rd_yes_ranges[] = {
        regmap_reg_range(0x20, 0x27),
        regmap_reg_range(0x30, 0x38),
        regmap_reg_range(0x3A, 0x40),
+       regmap_reg_range(0x63, 0x63),
        regmap_reg_range(0x65, 0x65),
        regmap_reg_range(0x69, 0x69),
-       regmap_reg_range(0x6C, 0x6C)
+       regmap_reg_range(0x6C, 0x6C),
+       regmap_reg_range(0xF8, 0xF8)
 };
 
 static const struct regmap_access_table rt9120_rd_table = {
@@ -297,9 +325,11 @@ static const struct regmap_range rt9120_wr_yes_ranges[] = {
        regmap_reg_range(0x30, 0x38),
        regmap_reg_range(0x3A, 0x3D),
        regmap_reg_range(0x40, 0x40),
+       regmap_reg_range(0x63, 0x63),
        regmap_reg_range(0x65, 0x65),
        regmap_reg_range(0x69, 0x69),
-       regmap_reg_range(0x6C, 0x6C)
+       regmap_reg_range(0x6C, 0x6C),
+       regmap_reg_range(0xF8, 0xF8)
 };
 
 static const struct regmap_access_table rt9120_wr_table = {
@@ -370,7 +400,7 @@ static int rt9120_reg_write(void *context, unsigned int reg, unsigned int val)
 static const struct regmap_config rt9120_regmap_config = {
        .reg_bits = 8,
        .val_bits = 32,
-       .max_register = RT9120_REG_UVPOPT,
+       .max_register = RT9120_REG_DIGCFG,
 
        .reg_read = rt9120_reg_read,
        .reg_write = rt9120_reg_write,
@@ -388,8 +418,16 @@ static int rt9120_check_vendor_info(struct rt9120_data *data)
        if (ret)
                return ret;
 
-       if ((devid & RT9120_VID_MASK) != RT9120_VENDOR_ID) {
-               dev_err(data->dev, "DEVID not correct [0x%04x]\n", devid);
+       devid = FIELD_GET(RT9120_VID_MASK, devid);
+       switch (devid) {
+       case RT9120_VENDOR_ID:
+               data->chip_idx = CHIP_IDX_RT9120;
+               break;
+       case RT9120S_VENDOR_ID:
+               data->chip_idx = CHIP_IDX_RT9120S;
+               break;
+       default:
+               dev_err(data->dev, "DEVID not correct [0x%0x]\n", devid);
                return -ENODEV;
        }
 
index 172e79c..6549e7f 100644 (file)
@@ -291,11 +291,11 @@ static int tas2770_set_samplerate(struct tas2770_priv *tas2770, int samplerate)
                ramp_rate_val = TAS2770_TDM_CFG_REG0_SMP_44_1KHZ |
                                TAS2770_TDM_CFG_REG0_31_88_2_96KHZ;
                break;
-       case 19200:
+       case 192000:
                ramp_rate_val = TAS2770_TDM_CFG_REG0_SMP_48KHZ |
                                TAS2770_TDM_CFG_REG0_31_176_4_192KHZ;
                break;
-       case 17640:
+       case 176400:
                ramp_rate_val = TAS2770_TDM_CFG_REG0_SMP_44_1KHZ |
                                TAS2770_TDM_CFG_REG0_31_176_4_192KHZ;
                break;
index c496b35..e63c6b7 100644 (file)
@@ -1896,9 +1896,8 @@ static int wcd934x_hw_params(struct snd_pcm_substream *substream,
        }
 
        wcd->dai[dai->id].sconfig.rate = params_rate(params);
-       wcd934x_slim_set_hw_params(wcd, &wcd->dai[dai->id], substream->stream);
 
-       return 0;
+       return wcd934x_slim_set_hw_params(wcd, &wcd->dai[dai->id], substream->stream);
 }
 
 static int wcd934x_hw_free(struct snd_pcm_substream *substream,
@@ -3257,6 +3256,9 @@ static int wcd934x_compander_set(struct snd_kcontrol *kc,
        int value = ucontrol->value.integer.value[0];
        int sel;
 
+       if (wcd->comp_enabled[comp] == value)
+               return 0;
+
        wcd->comp_enabled[comp] = value;
        sel = value ? WCD934X_HPH_GAIN_SRC_SEL_COMPANDER :
                WCD934X_HPH_GAIN_SRC_SEL_REGISTER;
@@ -3280,10 +3282,10 @@ static int wcd934x_compander_set(struct snd_kcontrol *kc,
        case COMPANDER_8:
                break;
        default:
-               break;
+               return 0;
        }
 
-       return 0;
+       return 1;
 }
 
 static int wcd934x_rx_hph_mode_get(struct snd_kcontrol *kc,
@@ -3327,6 +3329,31 @@ static int slim_rx_mux_get(struct snd_kcontrol *kc,
        return 0;
 }
 
+static int slim_rx_mux_to_dai_id(int mux)
+{
+       int aif_id;
+
+       switch (mux) {
+       case 1:
+               aif_id = AIF1_PB;
+               break;
+       case 2:
+               aif_id = AIF2_PB;
+               break;
+       case 3:
+               aif_id = AIF3_PB;
+               break;
+       case 4:
+               aif_id = AIF4_PB;
+               break;
+       default:
+               aif_id = -1;
+               break;
+       }
+
+       return aif_id;
+}
+
 static int slim_rx_mux_put(struct snd_kcontrol *kc,
                           struct snd_ctl_elem_value *ucontrol)
 {
@@ -3334,43 +3361,59 @@ static int slim_rx_mux_put(struct snd_kcontrol *kc,
        struct wcd934x_codec *wcd = dev_get_drvdata(w->dapm->dev);
        struct soc_enum *e = (struct soc_enum *)kc->private_value;
        struct snd_soc_dapm_update *update = NULL;
+       struct wcd934x_slim_ch *ch, *c;
        u32 port_id = w->shift;
+       bool found = false;
+       int mux_idx;
+       int prev_mux_idx = wcd->rx_port_value[port_id];
+       int aif_id;
 
-       if (wcd->rx_port_value[port_id] == ucontrol->value.enumerated.item[0])
-               return 0;
+       mux_idx = ucontrol->value.enumerated.item[0];
 
-       wcd->rx_port_value[port_id] = ucontrol->value.enumerated.item[0];
+       if (mux_idx == prev_mux_idx)
+               return 0;
 
-       switch (wcd->rx_port_value[port_id]) {
+       switch(mux_idx) {
        case 0:
-               list_del_init(&wcd->rx_chs[port_id].list);
-               break;
-       case 1:
-               list_add_tail(&wcd->rx_chs[port_id].list,
-                             &wcd->dai[AIF1_PB].slim_ch_list);
-               break;
-       case 2:
-               list_add_tail(&wcd->rx_chs[port_id].list,
-                             &wcd->dai[AIF2_PB].slim_ch_list);
-               break;
-       case 3:
-               list_add_tail(&wcd->rx_chs[port_id].list,
-                             &wcd->dai[AIF3_PB].slim_ch_list);
+               aif_id = slim_rx_mux_to_dai_id(prev_mux_idx);
+               if (aif_id < 0)
+                       return 0;
+
+               list_for_each_entry_safe(ch, c, &wcd->dai[aif_id].slim_ch_list, list) {
+                       if (ch->port == port_id + WCD934X_RX_START) {
+                               found = true;
+                               list_del_init(&ch->list);
+                               break;
+                       }
+               }
+               if (!found)
+                       return 0;
+
                break;
-       case 4:
-               list_add_tail(&wcd->rx_chs[port_id].list,
-                             &wcd->dai[AIF4_PB].slim_ch_list);
+       case 1 ... 4:
+               aif_id = slim_rx_mux_to_dai_id(mux_idx);
+               if (aif_id < 0)
+                       return 0;
+
+               if (list_empty(&wcd->rx_chs[port_id].list)) {
+                       list_add_tail(&wcd->rx_chs[port_id].list,
+                                     &wcd->dai[aif_id].slim_ch_list);
+               } else {
+                       dev_err(wcd->dev ,"SLIM_RX%d PORT is busy\n", port_id);
+                       return 0;
+               }
                break;
+
        default:
-               dev_err(wcd->dev, "Unknown AIF %d\n",
-                       wcd->rx_port_value[port_id]);
+               dev_err(wcd->dev, "Unknown AIF %d\n", mux_idx);
                goto err;
        }
 
+       wcd->rx_port_value[port_id] = mux_idx;
        snd_soc_dapm_mux_update_power(w->dapm, kc, wcd->rx_port_value[port_id],
                                      e, update);
 
-       return 0;
+       return 1;
 err:
        return -EINVAL;
 }
@@ -3816,6 +3859,7 @@ static int slim_tx_mixer_put(struct snd_kcontrol *kc,
        struct soc_mixer_control *mixer =
                        (struct soc_mixer_control *)kc->private_value;
        int enable = ucontrol->value.integer.value[0];
+       struct wcd934x_slim_ch *ch, *c;
        int dai_id = widget->shift;
        int port_id = mixer->shift;
 
@@ -3823,17 +3867,32 @@ static int slim_tx_mixer_put(struct snd_kcontrol *kc,
        if (enable == wcd->tx_port_value[port_id])
                return 0;
 
-       wcd->tx_port_value[port_id] = enable;
-
-       if (enable)
-               list_add_tail(&wcd->tx_chs[port_id].list,
-                             &wcd->dai[dai_id].slim_ch_list);
-       else
-               list_del_init(&wcd->tx_chs[port_id].list);
+       if (enable) {
+               if (list_empty(&wcd->tx_chs[port_id].list)) {
+                       list_add_tail(&wcd->tx_chs[port_id].list,
+                                     &wcd->dai[dai_id].slim_ch_list);
+               } else {
+                       dev_err(wcd->dev ,"SLIM_TX%d PORT is busy\n", port_id);
+                       return 0;
+               }
+        } else {
+               bool found = false;
+
+               list_for_each_entry_safe(ch, c, &wcd->dai[dai_id].slim_ch_list, list) {
+                       if (ch->port == port_id) {
+                               found = true;
+                               list_del_init(&wcd->tx_chs[port_id].list);
+                               break;
+                       }
+               }
+               if (!found)
+                       return 0;
+        }
 
+       wcd->tx_port_value[port_id] = enable;
        snd_soc_dapm_mixer_update_power(widget->dapm, kc, enable, update);
 
-       return 0;
+       return 1;
 }
 
 static const struct snd_kcontrol_new aif1_slim_cap_mixer[] = {
index 52de7d1..67151c7 100644 (file)
@@ -1174,6 +1174,9 @@ static bool wcd938x_readonly_register(struct device *dev, unsigned int reg)
        case WCD938X_DIGITAL_INTR_STATUS_0:
        case WCD938X_DIGITAL_INTR_STATUS_1:
        case WCD938X_DIGITAL_INTR_STATUS_2:
+       case WCD938X_DIGITAL_INTR_CLEAR_0:
+       case WCD938X_DIGITAL_INTR_CLEAR_1:
+       case WCD938X_DIGITAL_INTR_CLEAR_2:
        case WCD938X_DIGITAL_SWR_HM_TEST_0:
        case WCD938X_DIGITAL_SWR_HM_TEST_1:
        case WCD938X_DIGITAL_EFUSE_T_DATA_0:
index d4f0d72..6cb01a8 100644 (file)
@@ -617,8 +617,9 @@ static int wm_adsp_control_add(struct cs_dsp_coeff_ctl *cs_ctl)
        switch (cs_dsp->fw_ver) {
        case 0:
        case 1:
-               snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s %x",
-                        cs_dsp->name, region_name, cs_ctl->alg_region.alg);
+               ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
+                               "%s %s %x", cs_dsp->name, region_name,
+                               cs_ctl->alg_region.alg);
                break;
        case 2:
                ret = scnprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN,
index 2da4a5f..564b78f 100644 (file)
@@ -772,7 +772,8 @@ static int wsa881x_put_pa_gain(struct snd_kcontrol *kc,
 
                usleep_range(1000, 1010);
        }
-       return 0;
+
+       return 1;
 }
 
 static int wsa881x_get_port(struct snd_kcontrol *kcontrol,
@@ -816,15 +817,22 @@ static int wsa881x_set_port(struct snd_kcontrol *kcontrol,
                (struct soc_mixer_control *)kcontrol->private_value;
        int portidx = mixer->reg;
 
-       if (ucontrol->value.integer.value[0])
+       if (ucontrol->value.integer.value[0]) {
+               if (data->port_enable[portidx])
+                       return 0;
+
                data->port_enable[portidx] = true;
-       else
+       } else {
+               if (!data->port_enable[portidx])
+                       return 0;
+
                data->port_enable[portidx] = false;
+       }
 
        if (portidx == WSA881X_PORT_BOOST) /* Boost Switch */
                wsa881x_boost_ctrl(comp, data->port_enable[portidx]);
 
-       return 0;
+       return 1;
 }
 
 static const char * const smart_boost_lvl_text[] = {
index f104962..77219c3 100644 (file)
@@ -248,6 +248,75 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
                                        SOF_BT_OFFLOAD_SSP(2) |
                                        SOF_SSP_BT_OFFLOAD_PRESENT),
        },
+       {
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF3"),
+               },
+               /* No Jack */
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       SOF_SDW_FOUR_SPK),
+       },
+       {
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00")
+               },
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       RT711_JD2 |
+                                       SOF_SDW_FOUR_SPK),
+       },
+       {
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01")
+               },
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       RT711_JD2 |
+                                       SOF_SDW_FOUR_SPK),
+       },
+       {
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B11")
+               },
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       RT711_JD2 |
+                                       SOF_SDW_FOUR_SPK),
+       },
+       {
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B12")
+               },
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       RT711_JD2 |
+                                       SOF_SDW_FOUR_SPK),
+       },
+       {
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B13"),
+               },
+               /* No Jack */
+               .driver_data = (void *)SOF_SDW_TGL_HDMI,
+       },
+       {
+               .callback = sof_sdw_quirk_cb,
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B29"),
+               },
+               .driver_data = (void *)(SOF_SDW_TGL_HDMI |
+                                       RT711_JD2 |
+                                       SOF_SDW_FOUR_SPK),
+       },
        {}
 };
 
index 06f5034..b61a778 100644 (file)
@@ -74,6 +74,15 @@ static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = {
        }
 };
 
+static const struct snd_soc_acpi_adr_device rt711_sdca_2_adr[] = {
+       {
+               .adr = 0x000230025D071101ull,
+               .num_endpoints = 1,
+               .endpoints = &single_endpoint,
+               .name_prefix = "rt711"
+       }
+};
+
 static const struct snd_soc_acpi_adr_device rt1316_1_group1_adr[] = {
        {
                .adr = 0x000131025D131601ull, /* unique ID is set for some reason */
@@ -101,6 +110,24 @@ static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = {
        }
 };
 
+static const struct snd_soc_acpi_adr_device rt1316_0_group2_adr[] = {
+       {
+               .adr = 0x000031025D131601ull,
+               .num_endpoints = 1,
+               .endpoints = &spk_l_endpoint,
+               .name_prefix = "rt1316-1"
+       }
+};
+
+static const struct snd_soc_acpi_adr_device rt1316_1_group2_adr[] = {
+       {
+               .adr = 0x000130025D131601ull,
+               .num_endpoints = 1,
+               .endpoints = &spk_r_endpoint,
+               .name_prefix = "rt1316-2"
+       }
+};
+
 static const struct snd_soc_acpi_adr_device rt1316_2_single_adr[] = {
        {
                .adr = 0x000230025D131601ull,
@@ -209,6 +236,63 @@ static const struct snd_soc_acpi_link_adr adl_sdca_3_in_1[] = {
        {}
 };
 
+static const struct snd_soc_acpi_link_adr adl_sdw_rt711_link2_rt1316_link01_rt714_link3[] = {
+       {
+               .mask = BIT(2),
+               .num_adr = ARRAY_SIZE(rt711_sdca_2_adr),
+               .adr_d = rt711_sdca_2_adr,
+       },
+       {
+               .mask = BIT(0),
+               .num_adr = ARRAY_SIZE(rt1316_0_group2_adr),
+               .adr_d = rt1316_0_group2_adr,
+       },
+       {
+               .mask = BIT(1),
+               .num_adr = ARRAY_SIZE(rt1316_1_group2_adr),
+               .adr_d = rt1316_1_group2_adr,
+       },
+       {
+               .mask = BIT(3),
+               .num_adr = ARRAY_SIZE(rt714_3_adr),
+               .adr_d = rt714_3_adr,
+       },
+       {}
+};
+
+static const struct snd_soc_acpi_link_adr adl_sdw_rt1316_link12_rt714_link0[] = {
+       {
+               .mask = BIT(1),
+               .num_adr = ARRAY_SIZE(rt1316_1_group1_adr),
+               .adr_d = rt1316_1_group1_adr,
+       },
+       {
+               .mask = BIT(2),
+               .num_adr = ARRAY_SIZE(rt1316_2_group1_adr),
+               .adr_d = rt1316_2_group1_adr,
+       },
+       {
+               .mask = BIT(0),
+               .num_adr = ARRAY_SIZE(rt714_0_adr),
+               .adr_d = rt714_0_adr,
+       },
+       {}
+};
+
+static const struct snd_soc_acpi_link_adr adl_sdw_rt1316_link2_rt714_link3[] = {
+       {
+               .mask = BIT(2),
+               .num_adr = ARRAY_SIZE(rt1316_2_single_adr),
+               .adr_d = rt1316_2_single_adr,
+       },
+       {
+               .mask = BIT(3),
+               .num_adr = ARRAY_SIZE(rt714_3_adr),
+               .adr_d = rt714_3_adr,
+       },
+       {}
+};
+
 static const struct snd_soc_acpi_link_adr adl_sdw_rt1316_link2_rt714_link0[] = {
        {
                .mask = BIT(2),
@@ -340,6 +424,27 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = {
                .sof_tplg_filename = "sof-adl-rt711-l0-rt1316-l13-rt714-l2.tplg",
        },
        {
+               .link_mask = 0xF, /* 4 active links required */
+               .links = adl_sdw_rt711_link2_rt1316_link01_rt714_link3,
+               .drv_name = "sof_sdw",
+               .sof_fw_filename = "sof-adl.ri",
+               .sof_tplg_filename = "sof-adl-rt711-l2-rt1316-l01-rt714-l3.tplg",
+       },
+       {
+               .link_mask = 0xC, /* rt1316 on link2 & rt714 on link3 */
+               .links = adl_sdw_rt1316_link2_rt714_link3,
+               .drv_name = "sof_sdw",
+               .sof_fw_filename = "sof-adl.ri",
+               .sof_tplg_filename = "sof-adl-rt1316-l2-mono-rt714-l3.tplg",
+       },
+       {
+               .link_mask = 0x7, /* rt714 on link0 & two rt1316s on link1 and link2 */
+               .links = adl_sdw_rt1316_link12_rt714_link0,
+               .drv_name = "sof_sdw",
+               .sof_fw_filename = "sof-adl.ri",
+               .sof_tplg_filename = "sof-adl-rt1316-l12-rt714-l0.tplg",
+       },
+       {
                .link_mask = 0x5, /* 2 active links required */
                .links = adl_sdw_rt1316_link2_rt714_link0,
                .drv_name = "sof_sdw",
index b4eb0c9..4eebc79 100644 (file)
@@ -81,6 +81,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_machines[] = {
                .sof_fw_filename = "sof-cml.ri",
                .sof_tplg_filename = "sof-cml-da7219-max98390.tplg",
        },
+       {
+               .id = "ESSX8336",
+               .drv_name = "sof-essx8336",
+               .sof_fw_filename = "sof-cml.ri",
+               .sof_tplg_filename = "sof-cml-es8336.tplg",
+       },
        {},
 };
 EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cml_machines);
index 6350390..3149493 100644 (file)
@@ -1054,6 +1054,7 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
        int irq_id;
        struct mtk_base_afe *afe;
        struct mt8173_afe_private *afe_priv;
+       struct snd_soc_component *comp_pcm, *comp_hdmi;
 
        ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(33));
        if (ret)
@@ -1142,23 +1143,55 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
        if (ret)
                goto err_pm_disable;
 
-       ret = devm_snd_soc_register_component(&pdev->dev,
-                                        &mt8173_afe_pcm_dai_component,
-                                        mt8173_afe_pcm_dais,
-                                        ARRAY_SIZE(mt8173_afe_pcm_dais));
+       comp_pcm = devm_kzalloc(&pdev->dev, sizeof(*comp_pcm), GFP_KERNEL);
+       if (!comp_pcm) {
+               ret = -ENOMEM;
+               goto err_pm_disable;
+       }
+
+       ret = snd_soc_component_initialize(comp_pcm,
+                                          &mt8173_afe_pcm_dai_component,
+                                          &pdev->dev);
        if (ret)
                goto err_pm_disable;
 
-       ret = devm_snd_soc_register_component(&pdev->dev,
-                                        &mt8173_afe_hdmi_dai_component,
-                                        mt8173_afe_hdmi_dais,
-                                        ARRAY_SIZE(mt8173_afe_hdmi_dais));
+#ifdef CONFIG_DEBUG_FS
+       comp_pcm->debugfs_prefix = "pcm";
+#endif
+
+       ret = snd_soc_add_component(comp_pcm,
+                                   mt8173_afe_pcm_dais,
+                                   ARRAY_SIZE(mt8173_afe_pcm_dais));
+       if (ret)
+               goto err_pm_disable;
+
+       comp_hdmi = devm_kzalloc(&pdev->dev, sizeof(*comp_hdmi), GFP_KERNEL);
+       if (!comp_hdmi) {
+               ret = -ENOMEM;
+               goto err_pm_disable;
+       }
+
+       ret = snd_soc_component_initialize(comp_hdmi,
+                                          &mt8173_afe_hdmi_dai_component,
+                                          &pdev->dev);
        if (ret)
                goto err_pm_disable;
 
+#ifdef CONFIG_DEBUG_FS
+       comp_hdmi->debugfs_prefix = "hdmi";
+#endif
+
+       ret = snd_soc_add_component(comp_hdmi,
+                                   mt8173_afe_hdmi_dais,
+                                   ARRAY_SIZE(mt8173_afe_hdmi_dais));
+       if (ret)
+               goto err_cleanup_components;
+
        dev_info(&pdev->dev, "MT8173 AFE driver initialized.\n");
        return 0;
 
+err_cleanup_components:
+       snd_soc_unregister_component(&pdev->dev);
 err_pm_disable:
        pm_runtime_disable(&pdev->dev);
        return ret;
@@ -1166,6 +1199,8 @@ err_pm_disable:
 
 static int mt8173_afe_pcm_dev_remove(struct platform_device *pdev)
 {
+       snd_soc_unregister_component(&pdev->dev);
+
        pm_runtime_disable(&pdev->dev);
        if (!pm_runtime_status_suspended(&pdev->dev))
                mt8173_afe_runtime_suspend(&pdev->dev);
index c28ebf8..2cbf679 100644 (file)
@@ -30,15 +30,15 @@ static struct mt8173_rt5650_platform_data mt8173_rt5650_priv = {
 };
 
 static const struct snd_soc_dapm_widget mt8173_rt5650_widgets[] = {
-       SND_SOC_DAPM_SPK("Speaker", NULL),
+       SND_SOC_DAPM_SPK("Ext Spk", NULL),
        SND_SOC_DAPM_MIC("Int Mic", NULL),
        SND_SOC_DAPM_HP("Headphone", NULL),
        SND_SOC_DAPM_MIC("Headset Mic", NULL),
 };
 
 static const struct snd_soc_dapm_route mt8173_rt5650_routes[] = {
-       {"Speaker", NULL, "SPOL"},
-       {"Speaker", NULL, "SPOR"},
+       {"Ext Spk", NULL, "SPOL"},
+       {"Ext Spk", NULL, "SPOR"},
        {"DMIC L1", NULL, "Int Mic"},
        {"DMIC R1", NULL, "Int Mic"},
        {"Headphone", NULL, "HPOL"},
@@ -48,7 +48,7 @@ static const struct snd_soc_dapm_route mt8173_rt5650_routes[] = {
 };
 
 static const struct snd_kcontrol_new mt8173_rt5650_controls[] = {
-       SOC_DAPM_PIN_SWITCH("Speaker"),
+       SOC_DAPM_PIN_SWITCH("Ext Spk"),
        SOC_DAPM_PIN_SWITCH("Int Mic"),
        SOC_DAPM_PIN_SWITCH("Headphone"),
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
index 9322245..67729de 100644 (file)
@@ -18,7 +18,6 @@
 #define AIU_RST_SOFT_I2S_FAST          BIT(0)
 
 #define AIU_I2S_DAC_CFG_MSB_FIRST      BIT(2)
-#define AIU_I2S_MISC_HOLD_EN           BIT(2)
 #define AIU_CLK_CTRL_I2S_DIV_EN                BIT(0)
 #define AIU_CLK_CTRL_I2S_DIV           GENMASK(3, 2)
 #define AIU_CLK_CTRL_AOCLK_INVERT      BIT(6)
@@ -36,37 +35,6 @@ static void aiu_encoder_i2s_divider_enable(struct snd_soc_component *component,
                                      enable ? AIU_CLK_CTRL_I2S_DIV_EN : 0);
 }
 
-static void aiu_encoder_i2s_hold(struct snd_soc_component *component,
-                                bool enable)
-{
-       snd_soc_component_update_bits(component, AIU_I2S_MISC,
-                                     AIU_I2S_MISC_HOLD_EN,
-                                     enable ? AIU_I2S_MISC_HOLD_EN : 0);
-}
-
-static int aiu_encoder_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
-                                  struct snd_soc_dai *dai)
-{
-       struct snd_soc_component *component = dai->component;
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               aiu_encoder_i2s_hold(component, false);
-               return 0;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               aiu_encoder_i2s_hold(component, true);
-               return 0;
-
-       default:
-               return -EINVAL;
-       }
-}
-
 static int aiu_encoder_i2s_setup_desc(struct snd_soc_component *component,
                                      struct snd_pcm_hw_params *params)
 {
@@ -353,7 +321,6 @@ static void aiu_encoder_i2s_shutdown(struct snd_pcm_substream *substream,
 }
 
 const struct snd_soc_dai_ops aiu_encoder_i2s_dai_ops = {
-       .trigger        = aiu_encoder_i2s_trigger,
        .hw_params      = aiu_encoder_i2s_hw_params,
        .hw_free        = aiu_encoder_i2s_hw_free,
        .set_fmt        = aiu_encoder_i2s_set_fmt,
index 2388a2d..57e6e71 100644 (file)
@@ -20,6 +20,8 @@
 #define AIU_MEM_I2S_CONTROL_MODE_16BIT BIT(6)
 #define AIU_MEM_I2S_BUF_CNTL_INIT      BIT(0)
 #define AIU_RST_SOFT_I2S_FAST          BIT(0)
+#define AIU_I2S_MISC_HOLD_EN           BIT(2)
+#define AIU_I2S_MISC_FORCE_LEFT_RIGHT  BIT(4)
 
 #define AIU_FIFO_I2S_BLOCK             256
 
@@ -90,6 +92,10 @@ static int aiu_fifo_i2s_hw_params(struct snd_pcm_substream *substream,
        unsigned int val;
        int ret;
 
+       snd_soc_component_update_bits(component, AIU_I2S_MISC,
+                                     AIU_I2S_MISC_HOLD_EN,
+                                     AIU_I2S_MISC_HOLD_EN);
+
        ret = aiu_fifo_hw_params(substream, params, dai);
        if (ret)
                return ret;
@@ -117,6 +123,19 @@ static int aiu_fifo_i2s_hw_params(struct snd_pcm_substream *substream,
        snd_soc_component_update_bits(component, AIU_MEM_I2S_MASKS,
                                      AIU_MEM_I2S_MASKS_IRQ_BLOCK, val);
 
+       /*
+        * Most (all?) supported SoCs have this bit set by default. The vendor
+        * driver however sets it manually (depending on the version either
+        * while un-setting AIU_I2S_MISC_HOLD_EN or right before that). Follow
+        * the same approach for consistency with the vendor driver.
+        */
+       snd_soc_component_update_bits(component, AIU_I2S_MISC,
+                                     AIU_I2S_MISC_FORCE_LEFT_RIGHT,
+                                     AIU_I2S_MISC_FORCE_LEFT_RIGHT);
+
+       snd_soc_component_update_bits(component, AIU_I2S_MISC,
+                                     AIU_I2S_MISC_HOLD_EN, 0);
+
        return 0;
 }
 
index 4ad2326..d67ff4c 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <linux/bitfield.h>
 #include <linux/clk.h>
+#include <linux/dma-mapping.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/soc-dai.h>
@@ -179,6 +180,11 @@ int aiu_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd,
        struct snd_card *card = rtd->card->snd_card;
        struct aiu_fifo *fifo = dai->playback_dma_data;
        size_t size = fifo->pcm->buffer_bytes_max;
+       int ret;
+
+       ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
+       if (ret)
+               return ret;
 
        snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV,
                                       card->dev, size, size);
index 4f693a2..3ee8bfc 100644 (file)
@@ -550,6 +550,10 @@ struct audio_hw_clk_cfg {
        uint32_t clock_root;
 } __packed;
 
+struct audio_hw_clk_rel_cfg {
+       uint32_t clock_id;
+} __packed;
+
 #define PARAM_ID_HW_EP_POWER_MODE_CFG  0x8001176
 #define AR_HW_EP_POWER_MODE_0  0 /* default */
 #define AR_HW_EP_POWER_MODE_1  1 /* XO Shutdown allowed */
index 3d831b6..72c5719 100644 (file)
@@ -390,7 +390,7 @@ struct q6copp *q6adm_open(struct device *dev, int port_id, int path, int rate,
        int ret = 0;
 
        if (port_id < 0) {
-               dev_err(dev, "Invalid port_id 0x%x\n", port_id);
+               dev_err(dev, "Invalid port_id %d\n", port_id);
                return ERR_PTR(-EINVAL);
        }
 
@@ -508,7 +508,7 @@ int q6adm_matrix_map(struct device *dev, int path,
                int port_idx = payload_map.port_id[i];
 
                if (port_idx < 0) {
-                       dev_err(dev, "Invalid port_id 0x%x\n",
+                       dev_err(dev, "Invalid port_id %d\n",
                                payload_map.port_id[i]);
                        kfree(pkt);
                        return -EINVAL;
index 46f3655..b74b677 100644 (file)
@@ -269,9 +269,7 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
 
        if (ret < 0) {
                dev_err(dev, "%s: q6asm_open_write failed\n", __func__);
-               q6asm_audio_client_free(prtd->audio_client);
-               prtd->audio_client = NULL;
-               return -ENOMEM;
+               goto open_err;
        }
 
        prtd->session_id = q6asm_get_session_id(prtd->audio_client);
@@ -279,7 +277,7 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
                              prtd->session_id, substream->stream);
        if (ret) {
                dev_err(dev, "%s: stream reg failed ret:%d\n", __func__, ret);
-               return ret;
+               goto routing_err;
        }
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -301,10 +299,19 @@ static int q6asm_dai_prepare(struct snd_soc_component *component,
        }
        if (ret < 0)
                dev_info(dev, "%s: CMD Format block failed\n", __func__);
+       else
+               prtd->state = Q6ASM_STREAM_RUNNING;
 
-       prtd->state = Q6ASM_STREAM_RUNNING;
+       return ret;
 
-       return 0;
+routing_err:
+       q6asm_cmd(prtd->audio_client, prtd->stream_id,  CMD_CLOSE);
+open_err:
+       q6asm_unmap_memory_regions(substream->stream, prtd->audio_client);
+       q6asm_audio_client_free(prtd->audio_client);
+       prtd->audio_client = NULL;
+
+       return ret;
 }
 
 static int q6asm_dai_trigger(struct snd_soc_component *component,
index 82c40f2..cda33de 100644 (file)
@@ -42,6 +42,12 @@ struct prm_cmd_request_rsc {
        struct audio_hw_clk_cfg clock_id;
 } __packed;
 
+struct prm_cmd_release_rsc {
+       struct apm_module_param_data param_data;
+       uint32_t num_clk_id;
+       struct audio_hw_clk_rel_cfg clock_id;
+} __packed;
+
 static int q6prm_send_cmd_sync(struct q6prm *prm, struct gpr_pkt *pkt, uint32_t rsp_opcode)
 {
        return audioreach_send_cmd_sync(prm->dev, prm->gdev, &prm->result, &prm->lock,
@@ -102,8 +108,8 @@ int q6prm_unvote_lpass_core_hw(struct device *dev, uint32_t hw_block_id, uint32_
 }
 EXPORT_SYMBOL_GPL(q6prm_unvote_lpass_core_hw);
 
-int q6prm_set_lpass_clock(struct device *dev, int clk_id, int clk_attr, int clk_root,
-                         unsigned int freq)
+static int q6prm_request_lpass_clock(struct device *dev, int clk_id, int clk_attr, int clk_root,
+                                    unsigned int freq)
 {
        struct q6prm *prm = dev_get_drvdata(dev->parent);
        struct apm_module_param_data *param_data;
@@ -138,6 +144,49 @@ int q6prm_set_lpass_clock(struct device *dev, int clk_id, int clk_attr, int clk_
 
        return rc;
 }
+
+static int q6prm_release_lpass_clock(struct device *dev, int clk_id, int clk_attr, int clk_root,
+                         unsigned int freq)
+{
+       struct q6prm *prm = dev_get_drvdata(dev->parent);
+       struct apm_module_param_data *param_data;
+       struct prm_cmd_release_rsc *rel;
+       gpr_device_t *gdev = prm->gdev;
+       struct gpr_pkt *pkt;
+       int rc;
+
+       pkt = audioreach_alloc_cmd_pkt(sizeof(*rel), PRM_CMD_RELEASE_HW_RSC, 0, gdev->svc.id,
+                                      GPR_PRM_MODULE_IID);
+       if (IS_ERR(pkt))
+               return PTR_ERR(pkt);
+
+       rel = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
+
+       param_data = &rel->param_data;
+
+       param_data->module_instance_id = GPR_PRM_MODULE_IID;
+       param_data->error_code = 0;
+       param_data->param_id = PARAM_ID_RSC_AUDIO_HW_CLK;
+       param_data->param_size = sizeof(*rel) - APM_MODULE_PARAM_DATA_SIZE;
+
+       rel->num_clk_id = 1;
+       rel->clock_id.clock_id = clk_id;
+
+       rc = q6prm_send_cmd_sync(prm, pkt, PRM_CMD_RSP_RELEASE_HW_RSC);
+
+       kfree(pkt);
+
+       return rc;
+}
+
+int q6prm_set_lpass_clock(struct device *dev, int clk_id, int clk_attr, int clk_root,
+                         unsigned int freq)
+{
+       if (freq)
+               return q6prm_request_lpass_clock(dev, clk_id, clk_attr, clk_attr, freq);
+
+       return q6prm_release_lpass_clock(dev, clk_id, clk_attr, clk_attr, freq);
+}
 EXPORT_SYMBOL_GPL(q6prm_set_lpass_clock);
 
 static int prm_callback(struct gpr_resp_pkt *data, void *priv, int op)
index 3390ebe..928fd23 100644 (file)
@@ -372,6 +372,12 @@ int q6routing_stream_open(int fedai_id, int perf_mode,
        }
 
        session = &routing_data->sessions[stream_id - 1];
+       if (session->port_id < 0) {
+               dev_err(routing_data->dev, "Routing not setup for MultiMedia%d Session\n",
+                       session->fedai_id);
+               return -EINVAL;
+       }
+
        pdata = &routing_data->port_data[session->port_id];
 
        mutex_lock(&routing_data->lock);
@@ -492,9 +498,15 @@ static int msm_routing_put_audio_mixer(struct snd_kcontrol *kcontrol,
        struct session_data *session = &data->sessions[session_id];
 
        if (ucontrol->value.integer.value[0]) {
+               if (session->port_id == be_id)
+                       return 0;
+
                session->port_id = be_id;
                snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, update);
        } else {
+               if (session->port_id == -1 || session->port_id != be_id)
+                       return 0;
+
                session->port_id = -1;
                snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, update);
        }
index 17b9b28..5f9cb5c 100644 (file)
@@ -95,6 +95,7 @@ struct rk_i2s_tdm_dev {
        spinlock_t lock; /* xfer lock */
        bool has_playback;
        bool has_capture;
+       struct snd_soc_dai_driver *dai;
 };
 
 static int to_ch_num(unsigned int val)
@@ -1310,19 +1311,14 @@ static const struct of_device_id rockchip_i2s_tdm_match[] = {
        {},
 };
 
-static struct snd_soc_dai_driver i2s_tdm_dai = {
+static const struct snd_soc_dai_driver i2s_tdm_dai = {
        .probe = rockchip_i2s_tdm_dai_probe,
-       .playback = {
-               .stream_name  = "Playback",
-       },
-       .capture = {
-               .stream_name  = "Capture",
-       },
        .ops = &rockchip_i2s_tdm_dai_ops,
 };
 
-static void rockchip_i2s_tdm_init_dai(struct rk_i2s_tdm_dev *i2s_tdm)
+static int rockchip_i2s_tdm_init_dai(struct rk_i2s_tdm_dev *i2s_tdm)
 {
+       struct snd_soc_dai_driver *dai;
        struct property *dma_names;
        const char *dma_name;
        u64 formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |
@@ -1337,19 +1333,33 @@ static void rockchip_i2s_tdm_init_dai(struct rk_i2s_tdm_dev *i2s_tdm)
                        i2s_tdm->has_capture = true;
        }
 
+       dai = devm_kmemdup(i2s_tdm->dev, &i2s_tdm_dai,
+                          sizeof(*dai), GFP_KERNEL);
+       if (!dai)
+               return -ENOMEM;
+
        if (i2s_tdm->has_playback) {
-               i2s_tdm_dai.playback.channels_min = 2;
-               i2s_tdm_dai.playback.channels_max = 8;
-               i2s_tdm_dai.playback.rates = SNDRV_PCM_RATE_8000_192000;
-               i2s_tdm_dai.playback.formats = formats;
+               dai->playback.stream_name  = "Playback";
+               dai->playback.channels_min = 2;
+               dai->playback.channels_max = 8;
+               dai->playback.rates = SNDRV_PCM_RATE_8000_192000;
+               dai->playback.formats = formats;
        }
 
        if (i2s_tdm->has_capture) {
-               i2s_tdm_dai.capture.channels_min = 2;
-               i2s_tdm_dai.capture.channels_max = 8;
-               i2s_tdm_dai.capture.rates = SNDRV_PCM_RATE_8000_192000;
-               i2s_tdm_dai.capture.formats = formats;
+               dai->capture.stream_name  = "Capture";
+               dai->capture.channels_min = 2;
+               dai->capture.channels_max = 8;
+               dai->capture.rates = SNDRV_PCM_RATE_8000_192000;
+               dai->capture.formats = formats;
        }
+
+       if (i2s_tdm->clk_trcm != TRCM_TXRX)
+               dai->symmetric_rate = 1;
+
+       i2s_tdm->dai = dai;
+
+       return 0;
 }
 
 static int rockchip_i2s_tdm_path_check(struct rk_i2s_tdm_dev *i2s_tdm,
@@ -1541,8 +1551,6 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev)
        spin_lock_init(&i2s_tdm->lock);
        i2s_tdm->soc_data = (struct rk_i2s_soc_data *)of_id->data;
 
-       rockchip_i2s_tdm_init_dai(i2s_tdm);
-
        i2s_tdm->frame_width = 64;
 
        i2s_tdm->clk_trcm = TRCM_TXRX;
@@ -1555,8 +1563,10 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev)
                }
                i2s_tdm->clk_trcm = TRCM_RX;
        }
-       if (i2s_tdm->clk_trcm != TRCM_TXRX)
-               i2s_tdm_dai.symmetric_rate = 1;
+
+       ret = rockchip_i2s_tdm_init_dai(i2s_tdm);
+       if (ret)
+               return ret;
 
        i2s_tdm->grf = syscon_regmap_lookup_by_phandle(node, "rockchip,grf");
        if (IS_ERR(i2s_tdm->grf))
@@ -1678,7 +1688,7 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev)
 
        ret = devm_snd_soc_register_component(&pdev->dev,
                                              &rockchip_i2s_tdm_component,
-                                             &i2s_tdm_dai, 1);
+                                             i2s_tdm->dai, 1);
 
        if (ret) {
                dev_err(&pdev->dev, "Could not register DAI\n");
index 16c6e02..03e0d4e 100644 (file)
@@ -102,7 +102,7 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod,
        struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma);
 
        if (dmaen->chan)
-               dmaengine_terminate_sync(dmaen->chan);
+               dmaengine_terminate_async(dmaen->chan);
 
        return 0;
 }
index 2ae99b4..cbd7ea4 100644 (file)
@@ -20,8 +20,10 @@ static bool snd_soc_acpi_id_present(struct snd_soc_acpi_mach *machine)
 
        if (comp_ids) {
                for (i = 0; i < comp_ids->num_codecs; i++) {
-                       if (acpi_dev_present(comp_ids->codecs[i], NULL, -1))
+                       if (acpi_dev_present(comp_ids->codecs[i], NULL, -1)) {
+                               strscpy(machine->id, comp_ids->codecs[i], ACPI_ID_LEN);
                                return true;
+                       }
                }
        }
 
index 2892b0a..b06c568 100644 (file)
@@ -2559,8 +2559,13 @@ static struct snd_soc_dapm_widget *dapm_find_widget(
        return NULL;
 }
 
-static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
-                               const char *pin, int status)
+/*
+ * set the DAPM pin status:
+ * returns 1 when the value has been updated, 0 when unchanged, or a negative
+ * error code; called from kcontrol put callback
+ */
+static int __snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
+                                 const char *pin, int status)
 {
        struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true);
        int ret = 0;
@@ -2586,6 +2591,18 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
        return ret;
 }
 
+/*
+ * similar as __snd_soc_dapm_set_pin(), but returns 0 when successful;
+ * called from several API functions below
+ */
+static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
+                               const char *pin, int status)
+{
+       int ret = __snd_soc_dapm_set_pin(dapm, pin, status);
+
+       return ret < 0 ? ret : 0;
+}
+
 /**
  * snd_soc_dapm_sync_unlocked - scan and power dapm paths
  * @dapm: DAPM context
@@ -3589,10 +3606,10 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
        const char *pin = (const char *)kcontrol->private_value;
        int ret;
 
-       if (ucontrol->value.integer.value[0])
-               ret = snd_soc_dapm_enable_pin(&card->dapm, pin);
-       else
-               ret = snd_soc_dapm_disable_pin(&card->dapm, pin);
+       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+       ret = __snd_soc_dapm_set_pin(&card->dapm, pin,
+                                    !!ucontrol->value.integer.value[0]);
+       mutex_unlock(&card->dapm_mutex);
 
        snd_soc_dapm_sync(&card->dapm);
        return ret;
index 557e22c..f5b9e66 100644 (file)
@@ -2700,6 +2700,7 @@ EXPORT_SYMBOL_GPL(snd_soc_tplg_component_load);
 /* remove dynamic controls from the component driver */
 int snd_soc_tplg_component_remove(struct snd_soc_component *comp)
 {
+       struct snd_card *card = comp->card->snd_card;
        struct snd_soc_dobj *dobj, *next_dobj;
        int pass = SOC_TPLG_PASS_END;
 
@@ -2707,6 +2708,7 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp)
        while (pass >= SOC_TPLG_PASS_START) {
 
                /* remove mixer controls */
+               down_write(&card->controls_rwsem);
                list_for_each_entry_safe(dobj, next_dobj, &comp->dobj_list,
                        list) {
 
@@ -2745,6 +2747,7 @@ int snd_soc_tplg_component_remove(struct snd_soc_component *comp)
                                break;
                        }
                }
+               up_write(&card->controls_rwsem);
                pass--;
        }
 
index 6bb4db8..041c546 100644 (file)
@@ -47,7 +47,7 @@ config SND_SOC_SOF_OF
          Say Y if you need this option. If unsure select "N".
 
 config SND_SOC_SOF_COMPRESS
-       tristate
+       bool
        select SND_SOC_COMPRESS
 
 config SND_SOC_SOF_DEBUG_PROBES
index 58bb89a..bb1dfe4 100644 (file)
@@ -69,7 +69,7 @@ static void snd_sof_refresh_control(struct snd_sof_control *scontrol)
 {
        struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
        struct snd_soc_component *scomp = scontrol->scomp;
-       enum sof_ipc_ctrl_type ctrl_type;
+       u32 ipc_cmd;
        int ret;
 
        if (!scontrol->comp_data_dirty)
@@ -79,9 +79,9 @@ static void snd_sof_refresh_control(struct snd_sof_control *scontrol)
                return;
 
        if (scontrol->cmd == SOF_CTRL_CMD_BINARY)
-               ctrl_type = SOF_IPC_COMP_GET_DATA;
+               ipc_cmd = SOF_IPC_COMP_GET_DATA;
        else
-               ctrl_type = SOF_IPC_COMP_GET_VALUE;
+               ipc_cmd = SOF_IPC_COMP_GET_VALUE;
 
        /* set the ABI header values */
        cdata->data->magic = SOF_ABI_MAGIC;
@@ -89,7 +89,7 @@ static void snd_sof_refresh_control(struct snd_sof_control *scontrol)
 
        /* refresh the component data from DSP */
        scontrol->comp_data_dirty = false;
-       ret = snd_sof_ipc_set_get_comp_data(scontrol, ctrl_type,
+       ret = snd_sof_ipc_set_get_comp_data(scontrol, ipc_cmd,
                                            SOF_CTRL_TYPE_VALUE_CHAN_GET,
                                            scontrol->cmd, false);
        if (ret < 0) {
index 30025d3..0862ff8 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/io.h>
 #include <sound/hdaudio.h>
 #include <sound/hda_i915.h>
+#include <sound/hda_codec.h>
+#include <sound/hda_register.h>
 #include "../sof-priv.h"
 #include "hda.h"
 
 #endif
 
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+static void update_codec_wake_enable(struct hdac_bus *bus, unsigned int addr, bool link_power)
+{
+       unsigned int mask = snd_hdac_chip_readw(bus, WAKEEN);
+
+       if (link_power)
+               mask &= ~BIT(addr);
+       else
+               mask |= BIT(addr);
+
+       snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, mask);
+}
+
 static void sof_hda_bus_link_power(struct hdac_device *codec, bool enable)
 {
        struct hdac_bus *bus = codec->bus;
@@ -41,6 +55,9 @@ static void sof_hda_bus_link_power(struct hdac_device *codec, bool enable)
         */
        if (codec->addr == HDA_IDISP_ADDR && !enable)
                snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false);
+
+       /* WAKEEN needs to be set for disabled links */
+       update_codec_wake_enable(bus, codec->addr, enable);
 }
 
 static const struct hdac_bus_ops bus_core_ops = {
index 6744318..13cd96e 100644 (file)
@@ -22,6 +22,7 @@
 
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
 #define IDISP_VID_INTEL        0x80860000
+#define CODEC_PROBE_RETRIES 3
 
 /* load the legacy HDA codec driver */
 static int request_codec_module(struct hda_codec *codec)
@@ -121,12 +122,15 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address,
        u32 hda_cmd = (address << 28) | (AC_NODE_ROOT << 20) |
                (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID;
        u32 resp = -1;
-       int ret;
+       int ret, retry = 0;
+
+       do {
+               mutex_lock(&hbus->core.cmd_mutex);
+               snd_hdac_bus_send_cmd(&hbus->core, hda_cmd);
+               snd_hdac_bus_get_response(&hbus->core, address, &resp);
+               mutex_unlock(&hbus->core.cmd_mutex);
+       } while (resp == -1 && retry++ < CODEC_PROBE_RETRIES);
 
-       mutex_lock(&hbus->core.cmd_mutex);
-       snd_hdac_bus_send_cmd(&hbus->core, hda_cmd);
-       snd_hdac_bus_get_response(&hbus->core, address, &resp);
-       mutex_unlock(&hbus->core.cmd_mutex);
        if (resp == -1)
                return -EIO;
        dev_dbg(sdev->dev, "HDA codec #%d probed OK: response: %x\n",
index 058baca..287dc0e 100644 (file)
@@ -622,8 +622,7 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
        hda_dsp_ipc_int_disable(sdev);
 
 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
-       if (runtime_suspend)
-               hda_codec_jack_wake_enable(sdev, true);
+       hda_codec_jack_wake_enable(sdev, runtime_suspend);
 
        /* power down all hda link */
        snd_hdac_ext_bus_link_power_down_all(bus);
index 883d78d..2c0d4d0 100644 (file)
@@ -58,6 +58,13 @@ int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w)
                return -EINVAL;
        }
 
+       /* DAI already configured, reset it before reconfiguring it */
+       if (sof_dai->configured) {
+               ret = hda_ctrl_dai_widget_free(w);
+               if (ret < 0)
+                       return ret;
+       }
+
        config = &sof_dai->dai_config[sof_dai->current_config];
 
        /*
@@ -810,6 +817,20 @@ skip_soundwire:
        return 0;
 }
 
+static void hda_check_for_state_change(struct snd_sof_dev *sdev)
+{
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+       struct hdac_bus *bus = sof_to_bus(sdev);
+       unsigned int codec_mask;
+
+       codec_mask = snd_hdac_chip_readw(bus, STATESTS);
+       if (codec_mask) {
+               hda_codec_jack_check(sdev);
+               snd_hdac_chip_writew(bus, STATESTS, codec_mask);
+       }
+#endif
+}
+
 static irqreturn_t hda_dsp_interrupt_handler(int irq, void *context)
 {
        struct snd_sof_dev *sdev = context;
@@ -851,6 +872,8 @@ static irqreturn_t hda_dsp_interrupt_thread(int irq, void *context)
        if (hda_sdw_check_wakeen_irq(sdev))
                hda_sdw_process_wakeen(sdev);
 
+       hda_check_for_state_change(sdev);
+
        /* enable GIE interrupt */
        snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
                                SOF_HDA_INTCTL,
index f2ea34d..fd46210 100644 (file)
@@ -112,8 +112,12 @@ static const struct pci_device_id sof_pci_ids[] = {
                .driver_data = (unsigned long)&adls_desc},
        { PCI_DEVICE(0x8086, 0x51c8), /* ADL-P */
                .driver_data = (unsigned long)&adl_desc},
+       { PCI_DEVICE(0x8086, 0x51cd), /* ADL-P */
+               .driver_data = (unsigned long)&adl_desc},
        { PCI_DEVICE(0x8086, 0x51cc), /* ADL-M */
                .driver_data = (unsigned long)&adl_desc},
+       { PCI_DEVICE(0x8086, 0x54c8), /* ADL-N */
+               .driver_data = (unsigned long)&adl_desc},
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, sof_pci_ids);
index 6254bac..717f45a 100644 (file)
@@ -700,7 +700,7 @@ static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai,
                if (ret < 0)
                        return ret;
 
-               nb_bits = frame_len * ((cgfr & I2S_CGFR_CHLEN) + 1);
+               nb_bits = frame_len * (FIELD_GET(I2S_CGFR_CHLEN, cgfr) + 1);
                ret = stm32_i2s_calc_clk_div(i2s, i2s_clock_rate,
                                             (nb_bits * rate));
                if (ret)
index 8ee9a77..a74c980 100644 (file)
@@ -26,51 +26,162 @@ static const struct reg_default tegra186_dspk_reg_defaults[] = {
        { TEGRA186_DSPK_CODEC_CTRL,  0x03000000 },
 };
 
-static int tegra186_dspk_get_control(struct snd_kcontrol *kcontrol,
+static int tegra186_dspk_get_fifo_th(struct snd_kcontrol *kcontrol,
                                     struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
        struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
 
-       if (strstr(kcontrol->id.name, "FIFO Threshold"))
-               ucontrol->value.integer.value[0] = dspk->rx_fifo_th;
-       else if (strstr(kcontrol->id.name, "OSR Value"))
-               ucontrol->value.integer.value[0] = dspk->osr_val;
-       else if (strstr(kcontrol->id.name, "LR Polarity Select"))
-               ucontrol->value.integer.value[0] = dspk->lrsel;
-       else if (strstr(kcontrol->id.name, "Channel Select"))
-               ucontrol->value.integer.value[0] = dspk->ch_sel;
-       else if (strstr(kcontrol->id.name, "Mono To Stereo"))
-               ucontrol->value.integer.value[0] = dspk->mono_to_stereo;
-       else if (strstr(kcontrol->id.name, "Stereo To Mono"))
-               ucontrol->value.integer.value[0] = dspk->stereo_to_mono;
+       ucontrol->value.integer.value[0] = dspk->rx_fifo_th;
 
        return 0;
 }
 
-static int tegra186_dspk_put_control(struct snd_kcontrol *kcontrol,
+static int tegra186_dspk_put_fifo_th(struct snd_kcontrol *kcontrol,
                                     struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
        struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
-       int val = ucontrol->value.integer.value[0];
-
-       if (strstr(kcontrol->id.name, "FIFO Threshold"))
-               dspk->rx_fifo_th = val;
-       else if (strstr(kcontrol->id.name, "OSR Value"))
-               dspk->osr_val = val;
-       else if (strstr(kcontrol->id.name, "LR Polarity Select"))
-               dspk->lrsel = val;
-       else if (strstr(kcontrol->id.name, "Channel Select"))
-               dspk->ch_sel = val;
-       else if (strstr(kcontrol->id.name, "Mono To Stereo"))
-               dspk->mono_to_stereo = val;
-       else if (strstr(kcontrol->id.name, "Stereo To Mono"))
-               dspk->stereo_to_mono = val;
+       int value = ucontrol->value.integer.value[0];
+
+       if (value == dspk->rx_fifo_th)
+               return 0;
+
+       dspk->rx_fifo_th = value;
+
+       return 1;
+}
+
+static int tegra186_dspk_get_osr_val(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+       struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = dspk->osr_val;
 
        return 0;
 }
 
+static int tegra186_dspk_put_osr_val(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+       struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
+       unsigned int value = ucontrol->value.enumerated.item[0];
+
+       if (value == dspk->osr_val)
+               return 0;
+
+       dspk->osr_val = value;
+
+       return 1;
+}
+
+static int tegra186_dspk_get_pol_sel(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+       struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = dspk->lrsel;
+
+       return 0;
+}
+
+static int tegra186_dspk_put_pol_sel(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+       struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
+       unsigned int value = ucontrol->value.enumerated.item[0];
+
+       if (value == dspk->lrsel)
+               return 0;
+
+       dspk->lrsel = value;
+
+       return 1;
+}
+
+static int tegra186_dspk_get_ch_sel(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+       struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = dspk->ch_sel;
+
+       return 0;
+}
+
+static int tegra186_dspk_put_ch_sel(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+       struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
+       unsigned int value = ucontrol->value.enumerated.item[0];
+
+       if (value == dspk->ch_sel)
+               return 0;
+
+       dspk->ch_sel = value;
+
+       return 1;
+}
+
+static int tegra186_dspk_get_mono_to_stereo(struct snd_kcontrol *kcontrol,
+                                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+       struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = dspk->mono_to_stereo;
+
+       return 0;
+}
+
+static int tegra186_dspk_put_mono_to_stereo(struct snd_kcontrol *kcontrol,
+                                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+       struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
+       unsigned int value = ucontrol->value.enumerated.item[0];
+
+       if (value == dspk->mono_to_stereo)
+               return 0;
+
+       dspk->mono_to_stereo = value;
+
+       return 1;
+}
+
+static int tegra186_dspk_get_stereo_to_mono(struct snd_kcontrol *kcontrol,
+                                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+       struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = dspk->stereo_to_mono;
+
+       return 0;
+}
+
+static int tegra186_dspk_put_stereo_to_mono(struct snd_kcontrol *kcontrol,
+                                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol);
+       struct tegra186_dspk *dspk = snd_soc_component_get_drvdata(codec);
+       unsigned int value = ucontrol->value.enumerated.item[0];
+
+       if (value == dspk->stereo_to_mono)
+               return 0;
+
+       dspk->stereo_to_mono = value;
+
+       return 1;
+}
+
 static int __maybe_unused tegra186_dspk_runtime_suspend(struct device *dev)
 {
        struct tegra186_dspk *dspk = dev_get_drvdata(dev);
@@ -279,17 +390,19 @@ static const struct soc_enum tegra186_dspk_lrsel_enum =
 static const struct snd_kcontrol_new tegrat186_dspk_controls[] = {
        SOC_SINGLE_EXT("FIFO Threshold", SND_SOC_NOPM, 0,
                       TEGRA186_DSPK_RX_FIFO_DEPTH - 1, 0,
-                      tegra186_dspk_get_control, tegra186_dspk_put_control),
+                      tegra186_dspk_get_fifo_th, tegra186_dspk_put_fifo_th),
        SOC_ENUM_EXT("OSR Value", tegra186_dspk_osr_enum,
-                    tegra186_dspk_get_control, tegra186_dspk_put_control),
+                    tegra186_dspk_get_osr_val, tegra186_dspk_put_osr_val),
        SOC_ENUM_EXT("LR Polarity Select", tegra186_dspk_lrsel_enum,
-                    tegra186_dspk_get_control, tegra186_dspk_put_control),
+                    tegra186_dspk_get_pol_sel, tegra186_dspk_put_pol_sel),
        SOC_ENUM_EXT("Channel Select", tegra186_dspk_ch_sel_enum,
-                    tegra186_dspk_get_control, tegra186_dspk_put_control),
+                    tegra186_dspk_get_ch_sel, tegra186_dspk_put_ch_sel),
        SOC_ENUM_EXT("Mono To Stereo", tegra186_dspk_mono_conv_enum,
-                    tegra186_dspk_get_control, tegra186_dspk_put_control),
+                    tegra186_dspk_get_mono_to_stereo,
+                    tegra186_dspk_put_mono_to_stereo),
        SOC_ENUM_EXT("Stereo To Mono", tegra186_dspk_stereo_conv_enum,
-                    tegra186_dspk_get_control, tegra186_dspk_put_control),
+                    tegra186_dspk_get_stereo_to_mono,
+                    tegra186_dspk_put_stereo_to_mono),
 };
 
 static const struct snd_soc_component_driver tegra186_dspk_cmpnt = {
index bcccdf3..1a2e868 100644 (file)
@@ -424,46 +424,122 @@ static const struct snd_soc_dai_ops tegra_admaif_dai_ops = {
        .trigger        = tegra_admaif_trigger,
 };
 
-static int tegra_admaif_get_control(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_value *ucontrol)
+static int tegra210_admaif_pget_mono_to_stereo(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
+       struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
+
+       ucontrol->value.enumerated.item[0] =
+               admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg];
+
+       return 0;
+}
+
+static int tegra210_admaif_pput_mono_to_stereo(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
+       struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
+       unsigned int value = ucontrol->value.enumerated.item[0];
+
+       if (value == admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg])
+               return 0;
+
+       admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg] = value;
+
+       return 1;
+}
+
+static int tegra210_admaif_cget_mono_to_stereo(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
+       struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
+
+       ucontrol->value.enumerated.item[0] =
+               admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg];
+
+       return 0;
+}
+
+static int tegra210_admaif_cput_mono_to_stereo(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
        struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
+       unsigned int value = ucontrol->value.enumerated.item[0];
+
+       if (value == admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg])
+               return 0;
+
+       admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg] = value;
+
+       return 1;
+}
+
+static int tegra210_admaif_pget_stereo_to_mono(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
        struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
-       long *uctl_val = &ucontrol->value.integer.value[0];
+       struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
 
-       if (strstr(kcontrol->id.name, "Playback Mono To Stereo"))
-               *uctl_val = admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg];
-       else if (strstr(kcontrol->id.name, "Capture Mono To Stereo"))
-               *uctl_val = admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg];
-       else if (strstr(kcontrol->id.name, "Playback Stereo To Mono"))
-               *uctl_val = admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg];
-       else if (strstr(kcontrol->id.name, "Capture Stereo To Mono"))
-               *uctl_val = admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg];
+       ucontrol->value.enumerated.item[0] =
+               admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg];
 
        return 0;
 }
 
-static int tegra_admaif_put_control(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_value *ucontrol)
+static int tegra210_admaif_pput_stereo_to_mono(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
        struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
+       unsigned int value = ucontrol->value.enumerated.item[0];
+
+       if (value == admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg])
+               return 0;
+
+       admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg] = value;
+
+       return 1;
+}
+
+static int tegra210_admaif_cget_stereo_to_mono(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
        struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
-       int value = ucontrol->value.integer.value[0];
+       struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
 
-       if (strstr(kcontrol->id.name, "Playback Mono To Stereo"))
-               admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg] = value;
-       else if (strstr(kcontrol->id.name, "Capture Mono To Stereo"))
-               admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg] = value;
-       else if (strstr(kcontrol->id.name, "Playback Stereo To Mono"))
-               admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg] = value;
-       else if (strstr(kcontrol->id.name, "Capture Stereo To Mono"))
-               admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg] = value;
+       ucontrol->value.enumerated.item[0] =
+               admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg];
 
        return 0;
 }
 
+static int tegra210_admaif_cput_stereo_to_mono(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra_admaif *admaif = snd_soc_component_get_drvdata(cmpnt);
+       struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
+       unsigned int value = ucontrol->value.enumerated.item[0];
+
+       if (value == admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg])
+               return 0;
+
+       admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg] = value;
+
+       return 1;
+}
+
 static int tegra_admaif_dai_probe(struct snd_soc_dai *dai)
 {
        struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai);
@@ -559,17 +635,21 @@ static const char * const tegra_admaif_mono_conv_text[] = {
 }
 
 #define TEGRA_ADMAIF_CIF_CTRL(reg)                                            \
-       NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Mono To Stereo", reg - 1,\
-                       tegra_admaif_get_control, tegra_admaif_put_control,    \
+       NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Mono To Stereo", reg - 1,     \
+                       tegra210_admaif_pget_mono_to_stereo,                   \
+                       tegra210_admaif_pput_mono_to_stereo,                   \
                        tegra_admaif_mono_conv_text),                          \
-       NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Stereo To Mono", reg - 1,\
-                       tegra_admaif_get_control, tegra_admaif_put_control,    \
+       NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback Stereo To Mono", reg - 1,     \
+                       tegra210_admaif_pget_stereo_to_mono,                   \
+                       tegra210_admaif_pput_stereo_to_mono,                   \
                        tegra_admaif_stereo_conv_text),                        \
-       NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Mono To Stereo", reg - 1, \
-                       tegra_admaif_get_control, tegra_admaif_put_control,    \
+       NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Mono To Stereo", reg - 1,      \
+                       tegra210_admaif_cget_mono_to_stereo,                   \
+                       tegra210_admaif_cput_mono_to_stereo,                   \
                        tegra_admaif_mono_conv_text),                          \
-       NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Stereo To Mono", reg - 1, \
-                       tegra_admaif_get_control, tegra_admaif_put_control,    \
+       NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture Stereo To Mono", reg - 1,      \
+                       tegra210_admaif_cget_stereo_to_mono,                   \
+                       tegra210_admaif_cput_stereo_to_mono,                   \
                        tegra_admaif_stereo_conv_text)
 
 static struct snd_kcontrol_new tegra210_admaif_controls[] = {
index d7c7849..3785cad 100644 (file)
@@ -193,6 +193,9 @@ static int tegra210_adx_put_byte_map(struct snd_kcontrol *kcontrol,
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;;
 
+       if (value == bytes_map[mc->reg])
+               return 0;
+
        if (value >= 0 && value <= 255) {
                /* update byte map and enable slot */
                bytes_map[mc->reg] = value;
@@ -511,8 +514,8 @@ static int tegra210_adx_platform_remove(struct platform_device *pdev)
 static const struct dev_pm_ops tegra210_adx_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra210_adx_runtime_suspend,
                           tegra210_adx_runtime_resume, NULL)
-       SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-                                    pm_runtime_force_resume)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
 };
 
 static struct platform_driver tegra210_adx_driver = {
index a1989ea..388b815 100644 (file)
@@ -62,6 +62,7 @@ static int tegra_ahub_put_value_enum(struct snd_kcontrol *kctl,
        unsigned int *item = uctl->value.enumerated.item;
        unsigned int value = e->values[item[0]];
        unsigned int i, bit_pos, reg_idx = 0, reg_val = 0;
+       int change = 0;
 
        if (item[0] >= e->items)
                return -EINVAL;
@@ -86,12 +87,14 @@ static int tegra_ahub_put_value_enum(struct snd_kcontrol *kctl,
 
                /* Update widget power if state has changed */
                if (snd_soc_component_test_bits(cmpnt, update[i].reg,
-                                               update[i].mask, update[i].val))
-                       snd_soc_dapm_mux_update_power(dapm, kctl, item[0], e,
-                                                     &update[i]);
+                                               update[i].mask,
+                                               update[i].val))
+                       change |= snd_soc_dapm_mux_update_power(dapm, kctl,
+                                                               item[0], e,
+                                                               &update[i]);
        }
 
-       return 0;
+       return change;
 }
 
 static struct snd_soc_dai_driver tegra210_ahub_dais[] = {
index af9bddf..d064cc6 100644 (file)
@@ -222,6 +222,9 @@ static int tegra210_amx_put_byte_map(struct snd_kcontrol *kcontrol,
        int reg = mc->reg;
        int value = ucontrol->value.integer.value[0];
 
+       if (value == bytes_map[reg])
+               return 0;
+
        if (value >= 0 && value <= 255) {
                /* Update byte map and enable slot */
                bytes_map[reg] = value;
@@ -580,8 +583,8 @@ static int tegra210_amx_platform_remove(struct platform_device *pdev)
 static const struct dev_pm_ops tegra210_amx_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra210_amx_runtime_suspend,
                           tegra210_amx_runtime_resume, NULL)
-       SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-                                    pm_runtime_force_resume)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
 };
 
 static struct platform_driver tegra210_amx_driver = {
index b096478..db95794 100644 (file)
@@ -156,51 +156,162 @@ static int tegra210_dmic_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int tegra210_dmic_get_control(struct snd_kcontrol *kcontrol,
+static int tegra210_dmic_get_boost_gain(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
+
+       ucontrol->value.integer.value[0] = dmic->boost_gain;
+
+       return 0;
+}
+
+static int tegra210_dmic_put_boost_gain(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
+       int value = ucontrol->value.integer.value[0];
+
+       if (value == dmic->boost_gain)
+               return 0;
+
+       dmic->boost_gain = value;
+
+       return 1;
+}
+
+static int tegra210_dmic_get_ch_select(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
+
+       ucontrol->value.enumerated.item[0] = dmic->ch_select;
+
+       return 0;
+}
+
+static int tegra210_dmic_put_ch_select(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
+       unsigned int value = ucontrol->value.enumerated.item[0];
+
+       if (value == dmic->ch_select)
+               return 0;
+
+       dmic->ch_select = value;
+
+       return 1;
+}
+
+static int tegra210_dmic_get_mono_to_stereo(struct snd_kcontrol *kcontrol,
+                                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
+
+       ucontrol->value.enumerated.item[0] = dmic->mono_to_stereo;
+
+       return 0;
+}
+
+static int tegra210_dmic_put_mono_to_stereo(struct snd_kcontrol *kcontrol,
+                                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
+       unsigned int value = ucontrol->value.enumerated.item[0];
+
+       if (value == dmic->mono_to_stereo)
+               return 0;
+
+       dmic->mono_to_stereo = value;
+
+       return 1;
+}
+
+static int tegra210_dmic_get_stereo_to_mono(struct snd_kcontrol *kcontrol,
+                                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
+
+       ucontrol->value.enumerated.item[0] = dmic->stereo_to_mono;
+
+       return 0;
+}
+
+static int tegra210_dmic_put_stereo_to_mono(struct snd_kcontrol *kcontrol,
+                                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
+       unsigned int value = ucontrol->value.enumerated.item[0];
+
+       if (value == dmic->stereo_to_mono)
+               return 0;
+
+       dmic->stereo_to_mono = value;
+
+       return 1;
+}
+
+static int tegra210_dmic_get_osr_val(struct snd_kcontrol *kcontrol,
                                     struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
        struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
 
-       if (strstr(kcontrol->id.name, "Boost Gain Volume"))
-               ucontrol->value.integer.value[0] = dmic->boost_gain;
-       else if (strstr(kcontrol->id.name, "Channel Select"))
-               ucontrol->value.integer.value[0] = dmic->ch_select;
-       else if (strstr(kcontrol->id.name, "Mono To Stereo"))
-               ucontrol->value.integer.value[0] = dmic->mono_to_stereo;
-       else if (strstr(kcontrol->id.name, "Stereo To Mono"))
-               ucontrol->value.integer.value[0] = dmic->stereo_to_mono;
-       else if (strstr(kcontrol->id.name, "OSR Value"))
-               ucontrol->value.integer.value[0] = dmic->osr_val;
-       else if (strstr(kcontrol->id.name, "LR Polarity Select"))
-               ucontrol->value.integer.value[0] = dmic->lrsel;
+       ucontrol->value.enumerated.item[0] = dmic->osr_val;
 
        return 0;
 }
 
-static int tegra210_dmic_put_control(struct snd_kcontrol *kcontrol,
+static int tegra210_dmic_put_osr_val(struct snd_kcontrol *kcontrol,
                                     struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
        struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
-       int value = ucontrol->value.integer.value[0];
+       unsigned int value = ucontrol->value.enumerated.item[0];
 
-       if (strstr(kcontrol->id.name, "Boost Gain Volume"))
-               dmic->boost_gain = value;
-       else if (strstr(kcontrol->id.name, "Channel Select"))
-               dmic->ch_select = ucontrol->value.integer.value[0];
-       else if (strstr(kcontrol->id.name, "Mono To Stereo"))
-               dmic->mono_to_stereo = value;
-       else if (strstr(kcontrol->id.name, "Stereo To Mono"))
-               dmic->stereo_to_mono = value;
-       else if (strstr(kcontrol->id.name, "OSR Value"))
-               dmic->osr_val = value;
-       else if (strstr(kcontrol->id.name, "LR Polarity Select"))
-               dmic->lrsel = value;
+       if (value == dmic->osr_val)
+               return 0;
+
+       dmic->osr_val = value;
+
+       return 1;
+}
+
+static int tegra210_dmic_get_pol_sel(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
+
+       ucontrol->value.enumerated.item[0] = dmic->lrsel;
 
        return 0;
 }
 
+static int tegra210_dmic_put_pol_sel(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_dmic *dmic = snd_soc_component_get_drvdata(comp);
+       unsigned int value = ucontrol->value.enumerated.item[0];
+
+       if (value == dmic->lrsel)
+               return 0;
+
+       dmic->lrsel = value;
+
+       return 1;
+}
+
 static const struct snd_soc_dai_ops tegra210_dmic_dai_ops = {
        .hw_params      = tegra210_dmic_hw_params,
 };
@@ -287,19 +398,22 @@ static const struct soc_enum tegra210_dmic_lrsel_enum =
 
 static const struct snd_kcontrol_new tegra210_dmic_controls[] = {
        SOC_SINGLE_EXT("Boost Gain Volume", 0, 0, MAX_BOOST_GAIN, 0,
-                      tegra210_dmic_get_control, tegra210_dmic_put_control),
+                      tegra210_dmic_get_boost_gain,
+                      tegra210_dmic_put_boost_gain),
        SOC_ENUM_EXT("Channel Select", tegra210_dmic_ch_enum,
-                    tegra210_dmic_get_control, tegra210_dmic_put_control),
+                    tegra210_dmic_get_ch_select, tegra210_dmic_put_ch_select),
        SOC_ENUM_EXT("Mono To Stereo",
-                    tegra210_dmic_mono_conv_enum, tegra210_dmic_get_control,
-                    tegra210_dmic_put_control),
+                    tegra210_dmic_mono_conv_enum,
+                    tegra210_dmic_get_mono_to_stereo,
+                    tegra210_dmic_put_mono_to_stereo),
        SOC_ENUM_EXT("Stereo To Mono",
-                    tegra210_dmic_stereo_conv_enum, tegra210_dmic_get_control,
-                    tegra210_dmic_put_control),
+                    tegra210_dmic_stereo_conv_enum,
+                    tegra210_dmic_get_stereo_to_mono,
+                    tegra210_dmic_put_stereo_to_mono),
        SOC_ENUM_EXT("OSR Value", tegra210_dmic_osr_enum,
-                    tegra210_dmic_get_control, tegra210_dmic_put_control),
+                    tegra210_dmic_get_osr_val, tegra210_dmic_put_osr_val),
        SOC_ENUM_EXT("LR Polarity Select", tegra210_dmic_lrsel_enum,
-                    tegra210_dmic_get_control, tegra210_dmic_put_control),
+                    tegra210_dmic_get_pol_sel, tegra210_dmic_put_pol_sel),
 };
 
 static const struct snd_soc_component_driver tegra210_dmic_compnt = {
index 45f31cc..9552bbb 100644 (file)
@@ -302,85 +302,235 @@ static int tegra210_i2s_set_tdm_slot(struct snd_soc_dai *dai,
        return 0;
 }
 
-static int tegra210_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai,
-                                          unsigned int ratio)
+static int tegra210_i2s_get_loopback(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
 {
-       struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+       struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
 
-       i2s->bclk_ratio = ratio;
+       ucontrol->value.integer.value[0] = i2s->loopback;
 
        return 0;
 }
 
-static int tegra210_i2s_get_control(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_value *ucontrol)
+static int tegra210_i2s_put_loopback(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+       int value = ucontrol->value.integer.value[0];
+
+       if (value == i2s->loopback)
+               return 0;
+
+       i2s->loopback = value;
+
+       regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL, I2S_CTRL_LPBK_MASK,
+                          i2s->loopback << I2S_CTRL_LPBK_SHIFT);
+
+       return 1;
+}
+
+static int tegra210_i2s_get_fsync_width(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
        struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
-       long *uctl_val = &ucontrol->value.integer.value[0];
-
-       if (strstr(kcontrol->id.name, "Loopback"))
-               *uctl_val = i2s->loopback;
-       else if (strstr(kcontrol->id.name, "FSYNC Width"))
-               *uctl_val = i2s->fsync_width;
-       else if (strstr(kcontrol->id.name, "Capture Stereo To Mono"))
-               *uctl_val = i2s->stereo_to_mono[I2S_TX_PATH];
-       else if (strstr(kcontrol->id.name, "Capture Mono To Stereo"))
-               *uctl_val = i2s->mono_to_stereo[I2S_TX_PATH];
-       else if (strstr(kcontrol->id.name, "Playback Stereo To Mono"))
-               *uctl_val = i2s->stereo_to_mono[I2S_RX_PATH];
-       else if (strstr(kcontrol->id.name, "Playback Mono To Stereo"))
-               *uctl_val = i2s->mono_to_stereo[I2S_RX_PATH];
-       else if (strstr(kcontrol->id.name, "Playback FIFO Threshold"))
-               *uctl_val = i2s->rx_fifo_th;
-       else if (strstr(kcontrol->id.name, "BCLK Ratio"))
-               *uctl_val = i2s->bclk_ratio;
+
+       ucontrol->value.integer.value[0] = i2s->fsync_width;
 
        return 0;
 }
 
-static int tegra210_i2s_put_control(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_value *ucontrol)
+static int tegra210_i2s_put_fsync_width(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
        struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
        int value = ucontrol->value.integer.value[0];
 
-       if (strstr(kcontrol->id.name, "Loopback")) {
-               i2s->loopback = value;
+       if (value == i2s->fsync_width)
+               return 0;
 
-               regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
-                                  I2S_CTRL_LPBK_MASK,
-                                  i2s->loopback << I2S_CTRL_LPBK_SHIFT);
+       i2s->fsync_width = value;
 
-       } else if (strstr(kcontrol->id.name, "FSYNC Width")) {
-               /*
-                * Frame sync width is used only for FSYNC modes and not
-                * applicable for LRCK modes. Reset value for this field is "0",
-                * which means the width is one bit clock wide.
-                * The width requirement may depend on the codec and in such
-                * cases mixer control is used to update custom values. A value
-                * of "N" here means, width is "N + 1" bit clock wide.
-                */
-               i2s->fsync_width = value;
-
-               regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
-                                  I2S_CTRL_FSYNC_WIDTH_MASK,
-                                  i2s->fsync_width << I2S_FSYNC_WIDTH_SHIFT);
-
-       } else if (strstr(kcontrol->id.name, "Capture Stereo To Mono")) {
-               i2s->stereo_to_mono[I2S_TX_PATH] = value;
-       } else if (strstr(kcontrol->id.name, "Capture Mono To Stereo")) {
-               i2s->mono_to_stereo[I2S_TX_PATH] = value;
-       } else if (strstr(kcontrol->id.name, "Playback Stereo To Mono")) {
-               i2s->stereo_to_mono[I2S_RX_PATH] = value;
-       } else if (strstr(kcontrol->id.name, "Playback Mono To Stereo")) {
-               i2s->mono_to_stereo[I2S_RX_PATH] = value;
-       } else if (strstr(kcontrol->id.name, "Playback FIFO Threshold")) {
-               i2s->rx_fifo_th = value;
-       } else if (strstr(kcontrol->id.name, "BCLK Ratio")) {
-               i2s->bclk_ratio = value;
-       }
+       /*
+        * Frame sync width is used only for FSYNC modes and not
+        * applicable for LRCK modes. Reset value for this field is "0",
+        * which means the width is one bit clock wide.
+        * The width requirement may depend on the codec and in such
+        * cases mixer control is used to update custom values. A value
+        * of "N" here means, width is "N + 1" bit clock wide.
+        */
+       regmap_update_bits(i2s->regmap, TEGRA210_I2S_CTRL,
+                          I2S_CTRL_FSYNC_WIDTH_MASK,
+                          i2s->fsync_width << I2S_FSYNC_WIDTH_SHIFT);
+
+       return 1;
+}
+
+static int tegra210_i2s_cget_stereo_to_mono(struct snd_kcontrol *kcontrol,
+                                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+
+       ucontrol->value.enumerated.item[0] = i2s->stereo_to_mono[I2S_TX_PATH];
+
+       return 0;
+}
+
+static int tegra210_i2s_cput_stereo_to_mono(struct snd_kcontrol *kcontrol,
+                                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+       unsigned int value = ucontrol->value.enumerated.item[0];
+
+       if (value == i2s->stereo_to_mono[I2S_TX_PATH])
+               return 0;
+
+       i2s->stereo_to_mono[I2S_TX_PATH] = value;
+
+       return 1;
+}
+
+static int tegra210_i2s_cget_mono_to_stereo(struct snd_kcontrol *kcontrol,
+                                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+
+       ucontrol->value.enumerated.item[0] = i2s->mono_to_stereo[I2S_TX_PATH];
+
+       return 0;
+}
+
+static int tegra210_i2s_cput_mono_to_stereo(struct snd_kcontrol *kcontrol,
+                                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+       unsigned int value = ucontrol->value.enumerated.item[0];
+
+       if (value == i2s->mono_to_stereo[I2S_TX_PATH])
+               return 0;
+
+       i2s->mono_to_stereo[I2S_TX_PATH] = value;
+
+       return 1;
+}
+
+static int tegra210_i2s_pget_stereo_to_mono(struct snd_kcontrol *kcontrol,
+                                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+
+       ucontrol->value.enumerated.item[0] = i2s->stereo_to_mono[I2S_RX_PATH];
+
+       return 0;
+}
+
+static int tegra210_i2s_pput_stereo_to_mono(struct snd_kcontrol *kcontrol,
+                                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+       unsigned int value = ucontrol->value.enumerated.item[0];
+
+       if (value == i2s->stereo_to_mono[I2S_RX_PATH])
+               return 0;
+
+       i2s->stereo_to_mono[I2S_RX_PATH] = value;
+
+       return 1;
+}
+
+static int tegra210_i2s_pget_mono_to_stereo(struct snd_kcontrol *kcontrol,
+                                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+
+       ucontrol->value.enumerated.item[0] = i2s->mono_to_stereo[I2S_RX_PATH];
+
+       return 0;
+}
+
+static int tegra210_i2s_pput_mono_to_stereo(struct snd_kcontrol *kcontrol,
+                                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+       unsigned int value = ucontrol->value.enumerated.item[0];
+
+       if (value == i2s->mono_to_stereo[I2S_RX_PATH])
+               return 0;
+
+       i2s->mono_to_stereo[I2S_RX_PATH] = value;
+
+       return 1;
+}
+
+static int tegra210_i2s_pget_fifo_th(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+
+       ucontrol->value.integer.value[0] = i2s->rx_fifo_th;
+
+       return 0;
+}
+
+static int tegra210_i2s_pput_fifo_th(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+       int value = ucontrol->value.integer.value[0];
+
+       if (value == i2s->rx_fifo_th)
+               return 0;
+
+       i2s->rx_fifo_th = value;
+
+       return 1;
+}
+
+static int tegra210_i2s_get_bclk_ratio(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+
+       ucontrol->value.integer.value[0] = i2s->bclk_ratio;
+
+       return 0;
+}
+
+static int tegra210_i2s_put_bclk_ratio(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *compnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_i2s *i2s = snd_soc_component_get_drvdata(compnt);
+       int value = ucontrol->value.integer.value[0];
+
+       if (value == i2s->bclk_ratio)
+               return 0;
+
+       i2s->bclk_ratio = value;
+
+       return 1;
+}
+
+static int tegra210_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai,
+                                          unsigned int ratio)
+{
+       struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+       i2s->bclk_ratio = ratio;
 
        return 0;
 }
@@ -598,22 +748,28 @@ static const struct soc_enum tegra210_i2s_stereo_conv_enum =
                        tegra210_i2s_stereo_conv_text);
 
 static const struct snd_kcontrol_new tegra210_i2s_controls[] = {
-       SOC_SINGLE_EXT("Loopback", 0, 0, 1, 0, tegra210_i2s_get_control,
-                      tegra210_i2s_put_control),
-       SOC_SINGLE_EXT("FSYNC Width", 0, 0, 255, 0, tegra210_i2s_get_control,
-                      tegra210_i2s_put_control),
+       SOC_SINGLE_EXT("Loopback", 0, 0, 1, 0, tegra210_i2s_get_loopback,
+                      tegra210_i2s_put_loopback),
+       SOC_SINGLE_EXT("FSYNC Width", 0, 0, 255, 0,
+                      tegra210_i2s_get_fsync_width,
+                      tegra210_i2s_put_fsync_width),
        SOC_ENUM_EXT("Capture Stereo To Mono", tegra210_i2s_stereo_conv_enum,
-                    tegra210_i2s_get_control, tegra210_i2s_put_control),
+                    tegra210_i2s_cget_stereo_to_mono,
+                    tegra210_i2s_cput_stereo_to_mono),
        SOC_ENUM_EXT("Capture Mono To Stereo", tegra210_i2s_mono_conv_enum,
-                    tegra210_i2s_get_control, tegra210_i2s_put_control),
+                    tegra210_i2s_cget_mono_to_stereo,
+                    tegra210_i2s_cput_mono_to_stereo),
        SOC_ENUM_EXT("Playback Stereo To Mono", tegra210_i2s_stereo_conv_enum,
-                    tegra210_i2s_get_control, tegra210_i2s_put_control),
+                    tegra210_i2s_pget_mono_to_stereo,
+                    tegra210_i2s_pput_mono_to_stereo),
        SOC_ENUM_EXT("Playback Mono To Stereo", tegra210_i2s_mono_conv_enum,
-                    tegra210_i2s_get_control, tegra210_i2s_put_control),
+                    tegra210_i2s_pget_stereo_to_mono,
+                    tegra210_i2s_pput_stereo_to_mono),
        SOC_SINGLE_EXT("Playback FIFO Threshold", 0, 0, I2S_RX_FIFO_DEPTH - 1,
-                      0, tegra210_i2s_get_control, tegra210_i2s_put_control),
-       SOC_SINGLE_EXT("BCLK Ratio", 0, 0, INT_MAX, 0, tegra210_i2s_get_control,
-                      tegra210_i2s_put_control),
+                      0, tegra210_i2s_pget_fifo_th, tegra210_i2s_pput_fifo_th),
+       SOC_SINGLE_EXT("BCLK Ratio", 0, 0, INT_MAX, 0,
+                      tegra210_i2s_get_bclk_ratio,
+                      tegra210_i2s_put_bclk_ratio),
 };
 
 static const struct snd_soc_dapm_widget tegra210_i2s_widgets[] = {
index 55e6177..16e679a 100644 (file)
@@ -192,24 +192,24 @@ static int tegra210_mixer_get_gain(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-static int tegra210_mixer_put_gain(struct snd_kcontrol *kcontrol,
-                                  struct snd_ctl_elem_value *ucontrol)
+static int tegra210_mixer_apply_gain(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol,
+                                    bool instant_gain)
 {
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
        struct tegra210_mixer *mixer = snd_soc_component_get_drvdata(cmpnt);
        unsigned int reg = mc->reg, id;
-       bool instant_gain = false;
        int err;
 
-       if (strstr(kcontrol->id.name, "Instant Gain Volume"))
-               instant_gain = true;
-
        /* Save gain value for specific MIXER input */
        id = (reg - TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_0) /
             TEGRA210_MIXER_GAIN_CFG_RAM_ADDR_STRIDE;
 
+       if (mixer->gain_value[id] == ucontrol->value.integer.value[0])
+               return 0;
+
        mixer->gain_value[id] = ucontrol->value.integer.value[0];
 
        err = tegra210_mixer_configure_gain(cmpnt, id, instant_gain);
@@ -221,6 +221,18 @@ static int tegra210_mixer_put_gain(struct snd_kcontrol *kcontrol,
        return 1;
 }
 
+static int tegra210_mixer_put_gain(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       return tegra210_mixer_apply_gain(kcontrol, ucontrol, false);
+}
+
+static int tegra210_mixer_put_instant_gain(struct snd_kcontrol *kcontrol,
+                                          struct snd_ctl_elem_value *ucontrol)
+{
+       return tegra210_mixer_apply_gain(kcontrol, ucontrol, true);
+}
+
 static int tegra210_mixer_set_audio_cif(struct tegra210_mixer *mixer,
                                        struct snd_pcm_hw_params *params,
                                        unsigned int reg,
@@ -388,7 +400,7 @@ ADDER_CTRL_DECL(adder5, TEGRA210_MIXER_TX5_ADDER_CONFIG);
        SOC_SINGLE_EXT("RX" #id " Instant Gain Volume",         \
                       MIXER_GAIN_CFG_RAM_ADDR((id) - 1), 0,    \
                       0x20000, 0, tegra210_mixer_get_gain,     \
-                      tegra210_mixer_put_gain),
+                      tegra210_mixer_put_instant_gain),
 
 /* Volume controls for all MIXER inputs */
 static const struct snd_kcontrol_new tegra210_mixer_gain_ctls[] = {
@@ -654,8 +666,8 @@ static int tegra210_mixer_platform_remove(struct platform_device *pdev)
 static const struct dev_pm_ops tegra210_mixer_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra210_mixer_runtime_suspend,
                           tegra210_mixer_runtime_resume, NULL)
-       SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-                                    pm_runtime_force_resume)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
 };
 
 static struct platform_driver tegra210_mixer_driver = {
index 7b9c700..acf5932 100644 (file)
@@ -136,7 +136,7 @@ static int tegra210_mvc_put_mute(struct snd_kcontrol *kcontrol,
        struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
        struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt);
        unsigned int value;
-       u8 mute_mask;
+       u8 new_mask, old_mask;
        int err;
 
        pm_runtime_get_sync(cmpnt->dev);
@@ -148,15 +148,23 @@ static int tegra210_mvc_put_mute(struct snd_kcontrol *kcontrol,
        if (err < 0)
                goto end;
 
-       mute_mask = ucontrol->value.integer.value[0];
+       regmap_read(mvc->regmap, TEGRA210_MVC_CTRL, &value);
+
+       old_mask = (value >> TEGRA210_MVC_MUTE_SHIFT) & TEGRA210_MUTE_MASK_EN;
+       new_mask = ucontrol->value.integer.value[0];
+
+       if (new_mask == old_mask) {
+               err = 0;
+               goto end;
+       }
 
        err = regmap_update_bits(mvc->regmap, mc->reg,
                                 TEGRA210_MVC_MUTE_MASK,
-                                mute_mask << TEGRA210_MVC_MUTE_SHIFT);
+                                new_mask << TEGRA210_MVC_MUTE_SHIFT);
        if (err < 0)
                goto end;
 
-       return 1;
+       err = 1;
 
 end:
        pm_runtime_put(cmpnt->dev);
@@ -195,7 +203,7 @@ static int tegra210_mvc_put_vol(struct snd_kcontrol *kcontrol,
        unsigned int reg = mc->reg;
        unsigned int value;
        u8 chan;
-       int err;
+       int err, old_volume;
 
        pm_runtime_get_sync(cmpnt->dev);
 
@@ -207,10 +215,16 @@ static int tegra210_mvc_put_vol(struct snd_kcontrol *kcontrol,
                goto end;
 
        chan = (reg - TEGRA210_MVC_TARGET_VOL) / REG_SIZE;
+       old_volume = mvc->volume[chan];
 
        tegra210_mvc_conv_vol(mvc, chan,
                              ucontrol->value.integer.value[0]);
 
+       if (mvc->volume[chan] == old_volume) {
+               err = 0;
+               goto end;
+       }
+
        /* Configure init volume same as target volume */
        regmap_write(mvc->regmap,
                TEGRA210_MVC_REG_OFFSET(TEGRA210_MVC_INIT_VOL, chan),
@@ -222,7 +236,7 @@ static int tegra210_mvc_put_vol(struct snd_kcontrol *kcontrol,
                           TEGRA210_MVC_VOLUME_SWITCH_MASK,
                           TEGRA210_MVC_VOLUME_SWITCH_TRIGGER);
 
-       return 1;
+       err = 1;
 
 end:
        pm_runtime_put(cmpnt->dev);
@@ -275,7 +289,7 @@ static int tegra210_mvc_get_curve_type(struct snd_kcontrol *kcontrol,
        struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
        struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt);
 
-       ucontrol->value.integer.value[0] = mvc->curve_type;
+       ucontrol->value.enumerated.item[0] = mvc->curve_type;
 
        return 0;
 }
@@ -285,7 +299,7 @@ static int tegra210_mvc_put_curve_type(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
        struct tegra210_mvc *mvc = snd_soc_component_get_drvdata(cmpnt);
-       int value;
+       unsigned int value;
 
        regmap_read(mvc->regmap, TEGRA210_MVC_ENABLE, &value);
        if (value & TEGRA210_MVC_EN) {
@@ -294,10 +308,10 @@ static int tegra210_mvc_put_curve_type(struct snd_kcontrol *kcontrol,
                return -EINVAL;
        }
 
-       if (mvc->curve_type == ucontrol->value.integer.value[0])
+       if (mvc->curve_type == ucontrol->value.enumerated.item[0])
                return 0;
 
-       mvc->curve_type = ucontrol->value.integer.value[0];
+       mvc->curve_type = ucontrol->value.enumerated.item[0];
 
        tegra210_mvc_reset_vol_settings(mvc, cmpnt->dev);
 
@@ -625,8 +639,8 @@ static int tegra210_mvc_platform_remove(struct platform_device *pdev)
 static const struct dev_pm_ops tegra210_mvc_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra210_mvc_runtime_suspend,
                           tegra210_mvc_runtime_resume, NULL)
-       SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-                                    pm_runtime_force_resume)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
 };
 
 static struct platform_driver tegra210_mvc_driver = {
index dc477ee..368f077 100644 (file)
@@ -3244,46 +3244,107 @@ static int tegra210_sfc_init(struct snd_soc_dapm_widget *w,
        return tegra210_sfc_write_coeff_ram(cmpnt);
 }
 
-static int tegra210_sfc_get_control(struct snd_kcontrol *kcontrol,
+static int tegra210_sfc_iget_stereo_to_mono(struct snd_kcontrol *kcontrol,
                                    struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
        struct tegra210_sfc *sfc = snd_soc_component_get_drvdata(cmpnt);
 
-       if (strstr(kcontrol->id.name, "Input Stereo To Mono"))
-               ucontrol->value.integer.value[0] =
-                       sfc->stereo_to_mono[SFC_RX_PATH];
-       else if (strstr(kcontrol->id.name, "Input Mono To Stereo"))
-               ucontrol->value.integer.value[0] =
-                       sfc->mono_to_stereo[SFC_RX_PATH];
-       else if (strstr(kcontrol->id.name, "Output Stereo To Mono"))
-               ucontrol->value.integer.value[0] =
-                       sfc->stereo_to_mono[SFC_TX_PATH];
-       else if (strstr(kcontrol->id.name, "Output Mono To Stereo"))
-               ucontrol->value.integer.value[0] =
-                       sfc->mono_to_stereo[SFC_TX_PATH];
+       ucontrol->value.enumerated.item[0] = sfc->stereo_to_mono[SFC_RX_PATH];
 
        return 0;
 }
 
-static int tegra210_sfc_put_control(struct snd_kcontrol *kcontrol,
+static int tegra210_sfc_iput_stereo_to_mono(struct snd_kcontrol *kcontrol,
                                    struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
        struct tegra210_sfc *sfc = snd_soc_component_get_drvdata(cmpnt);
-       int value = ucontrol->value.integer.value[0];
-
-       if (strstr(kcontrol->id.name, "Input Stereo To Mono"))
-               sfc->stereo_to_mono[SFC_RX_PATH] = value;
-       else if (strstr(kcontrol->id.name, "Input Mono To Stereo"))
-               sfc->mono_to_stereo[SFC_RX_PATH] = value;
-       else if (strstr(kcontrol->id.name, "Output Stereo To Mono"))
-               sfc->stereo_to_mono[SFC_TX_PATH] = value;
-       else if (strstr(kcontrol->id.name, "Output Mono To Stereo"))
-               sfc->mono_to_stereo[SFC_TX_PATH] = value;
-       else
+       unsigned int value = ucontrol->value.enumerated.item[0];
+
+       if (value == sfc->stereo_to_mono[SFC_RX_PATH])
+               return 0;
+
+       sfc->stereo_to_mono[SFC_RX_PATH] = value;
+
+       return 1;
+}
+
+static int tegra210_sfc_iget_mono_to_stereo(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_sfc *sfc = snd_soc_component_get_drvdata(cmpnt);
+
+       ucontrol->value.enumerated.item[0] = sfc->mono_to_stereo[SFC_RX_PATH];
+
+       return 0;
+}
+
+static int tegra210_sfc_iput_mono_to_stereo(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_sfc *sfc = snd_soc_component_get_drvdata(cmpnt);
+       unsigned int value = ucontrol->value.enumerated.item[0];
+
+       if (value == sfc->mono_to_stereo[SFC_RX_PATH])
                return 0;
 
+       sfc->mono_to_stereo[SFC_RX_PATH] = value;
+
+       return 1;
+}
+
+static int tegra210_sfc_oget_stereo_to_mono(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_sfc *sfc = snd_soc_component_get_drvdata(cmpnt);
+
+       ucontrol->value.enumerated.item[0] = sfc->stereo_to_mono[SFC_TX_PATH];
+
+       return 0;
+}
+
+static int tegra210_sfc_oput_stereo_to_mono(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_sfc *sfc = snd_soc_component_get_drvdata(cmpnt);
+       unsigned int value = ucontrol->value.enumerated.item[0];
+
+       if (value == sfc->stereo_to_mono[SFC_TX_PATH])
+               return 0;
+
+       sfc->stereo_to_mono[SFC_TX_PATH] = value;
+
+       return 1;
+}
+
+static int tegra210_sfc_oget_mono_to_stereo(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_sfc *sfc = snd_soc_component_get_drvdata(cmpnt);
+
+       ucontrol->value.enumerated.item[0] = sfc->mono_to_stereo[SFC_TX_PATH];
+
+       return 0;
+}
+
+static int tegra210_sfc_oput_mono_to_stereo(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+       struct tegra210_sfc *sfc = snd_soc_component_get_drvdata(cmpnt);
+       unsigned int value = ucontrol->value.enumerated.item[0];
+
+       if (value == sfc->mono_to_stereo[SFC_TX_PATH])
+               return 0;
+
+       sfc->mono_to_stereo[SFC_TX_PATH] = value;
+
        return 1;
 }
 
@@ -3384,13 +3445,17 @@ static const struct soc_enum tegra210_sfc_mono_conv_enum =
 
 static const struct snd_kcontrol_new tegra210_sfc_controls[] = {
        SOC_ENUM_EXT("Input Stereo To Mono", tegra210_sfc_stereo_conv_enum,
-               tegra210_sfc_get_control, tegra210_sfc_put_control),
+                    tegra210_sfc_iget_stereo_to_mono,
+                    tegra210_sfc_iput_stereo_to_mono),
        SOC_ENUM_EXT("Input Mono To Stereo", tegra210_sfc_mono_conv_enum,
-               tegra210_sfc_get_control, tegra210_sfc_put_control),
+                    tegra210_sfc_iget_mono_to_stereo,
+                    tegra210_sfc_iput_mono_to_stereo),
        SOC_ENUM_EXT("Output Stereo To Mono", tegra210_sfc_stereo_conv_enum,
-               tegra210_sfc_get_control, tegra210_sfc_put_control),
+                    tegra210_sfc_oget_stereo_to_mono,
+                    tegra210_sfc_oput_stereo_to_mono),
        SOC_ENUM_EXT("Output Mono To Stereo", tegra210_sfc_mono_conv_enum,
-               tegra210_sfc_get_control, tegra210_sfc_put_control),
+                    tegra210_sfc_oget_mono_to_stereo,
+                    tegra210_sfc_oput_mono_to_stereo),
 };
 
 static const struct snd_soc_component_driver tegra210_sfc_cmpnt = {
@@ -3529,8 +3594,8 @@ static int tegra210_sfc_platform_remove(struct platform_device *pdev)
 static const struct dev_pm_ops tegra210_sfc_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra210_sfc_runtime_suspend,
                           tegra210_sfc_runtime_resume, NULL)
-       SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
-                                    pm_runtime_force_resume)
+       SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                               pm_runtime_force_resume)
 };
 
 static struct platform_driver tegra210_sfc_driver = {
index b95438c..a734048 100644 (file)
@@ -116,16 +116,24 @@ static const struct snd_kcontrol_new tegra_machine_controls[] = {
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
        SOC_DAPM_PIN_SWITCH("Internal Mic 1"),
        SOC_DAPM_PIN_SWITCH("Internal Mic 2"),
+       SOC_DAPM_PIN_SWITCH("Headphones"),
+       SOC_DAPM_PIN_SWITCH("Mic Jack"),
 };
 
 int tegra_asoc_machine_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_card *card = rtd->card;
        struct tegra_machine *machine = snd_soc_card_get_drvdata(card);
+       const char *jack_name;
        int err;
 
        if (machine->gpiod_hp_det && machine->asoc->add_hp_jack) {
-               err = snd_soc_card_jack_new(card, "Headphones Jack",
+               if (machine->asoc->hp_jack_name)
+                       jack_name = machine->asoc->hp_jack_name;
+               else
+                       jack_name = "Headphones Jack";
+
+               err = snd_soc_card_jack_new(card, jack_name,
                                            SND_JACK_HEADPHONE,
                                            &tegra_machine_hp_jack,
                                            tegra_machine_hp_jack_pins,
@@ -658,6 +666,7 @@ static struct snd_soc_card snd_soc_tegra_max98090 = {
 static const struct tegra_asoc_data tegra_max98090_data = {
        .mclk_rate = tegra_machine_mclk_rate_12mhz,
        .card = &snd_soc_tegra_max98090,
+       .hp_jack_name = "Headphones",
        .add_common_dapm_widgets = true,
        .add_common_controls = true,
        .add_common_snd_ops = true,
index d6a8d13..6f795d7 100644 (file)
@@ -14,6 +14,7 @@ struct snd_soc_pcm_runtime;
 struct tegra_asoc_data {
        unsigned int (*mclk_rate)(unsigned int srate);
        const char *codec_dev_name;
+       const char *hp_jack_name;
        struct snd_soc_card *card;
        unsigned int mclk_id;
        bool hp_jack_gpio_active_low;
index 1f98637..e447ddd 100644 (file)
@@ -3016,11 +3016,11 @@ static const struct snd_djm_ctl snd_djm_ctls_750mk2[] = {
 
 
 static const struct snd_djm_device snd_djm_devices[] = {
-       SND_DJM_DEVICE(250mk2),
-       SND_DJM_DEVICE(750),
-       SND_DJM_DEVICE(750mk2),
-       SND_DJM_DEVICE(850),
-       SND_DJM_DEVICE(900nxs2)
+       [SND_DJM_250MK2_IDX] = SND_DJM_DEVICE(250mk2),
+       [SND_DJM_750_IDX] = SND_DJM_DEVICE(750),
+       [SND_DJM_850_IDX] = SND_DJM_DEVICE(850),
+       [SND_DJM_900NXS2_IDX] = SND_DJM_DEVICE(900nxs2),
+       [SND_DJM_750MK2_IDX] = SND_DJM_DEVICE(750mk2),
 };
 
 
index 95ec8ee..cec6e91 100644 (file)
@@ -581,6 +581,12 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
        return 0;
 }
 
+/* free-wheeling mode? (e.g. dmix) */
+static int in_free_wheeling_mode(struct snd_pcm_runtime *runtime)
+{
+       return runtime->stop_threshold > runtime->buffer_size;
+}
+
 /* check whether early start is needed for playback stream */
 static int lowlatency_playback_available(struct snd_pcm_runtime *runtime,
                                         struct snd_usb_substream *subs)
@@ -592,8 +598,7 @@ static int lowlatency_playback_available(struct snd_pcm_runtime *runtime,
        /* disabled via module option? */
        if (!chip->lowlatency)
                return false;
-       /* free-wheeling mode? (e.g. dmix) */
-       if (runtime->stop_threshold > runtime->buffer_size)
+       if (in_free_wheeling_mode(runtime))
                return false;
        /* implicit feedback mode has own operation mode */
        if (snd_usb_endpoint_implicit_feedback_sink(subs->data_endpoint))
@@ -635,7 +640,8 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
        runtime->delay = 0;
 
        subs->lowlatency_playback = lowlatency_playback_available(runtime, subs);
-       if (!subs->lowlatency_playback)
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
+           !subs->lowlatency_playback)
                ret = start_endpoints(subs);
 
  unlock:
@@ -1552,6 +1558,8 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea
                                              subs);
                if (subs->lowlatency_playback &&
                    cmd == SNDRV_PCM_TRIGGER_START) {
+                       if (in_free_wheeling_mode(substream->runtime))
+                               subs->lowlatency_playback = false;
                        err = start_endpoints(subs);
                        if (err < 0) {
                                snd_usb_endpoint_set_callback(subs->data_endpoint,