ASoC: Merge up fixes
authorMark Brown <broonie@kernel.org>
Thu, 17 Aug 2023 18:18:58 +0000 (19:18 +0100)
committerMark Brown <broonie@kernel.org>
Thu, 17 Aug 2023 21:38:42 +0000 (22:38 +0100)
For the benefit of CI.

1  2 
sound/soc/codecs/cs35l56-i2c.c
sound/soc/codecs/cs35l56-spi.c
sound/soc/codecs/cs35l56.c
sound/soc/codecs/rt1308-sdw.c
sound/soc/sof/ipc4-pcm.c

index 888fdfa5f5dbe8dc6f8deff966c4f0618813fff1,40666e6698ba99d58d5f4be3992751178cbcefc1..9f4f2f4f23f5668c846f2a051eee64c533deb38f
@@@ -26,14 -26,14 +26,14 @@@ static int cs35l56_i2c_probe(struct i2c
        if (!cs35l56)
                return -ENOMEM;
  
 -      cs35l56->dev = dev;
 -      cs35l56->can_hibernate = true;
 +      cs35l56->base.dev = dev;
 +      cs35l56->base.can_hibernate = true;
  
        i2c_set_clientdata(client, cs35l56);
 -      cs35l56->regmap = devm_regmap_init_i2c(client, regmap_config);
 -      if (IS_ERR(cs35l56->regmap)) {
 -              ret = PTR_ERR(cs35l56->regmap);
 -              return dev_err_probe(cs35l56->dev, ret, "Failed to allocate register map\n");
 +      cs35l56->base.regmap = devm_regmap_init_i2c(client, regmap_config);
 +      if (IS_ERR(cs35l56->base.regmap)) {
 +              ret = PTR_ERR(cs35l56->base.regmap);
 +              return dev_err_probe(cs35l56->base.dev, ret, "Failed to allocate register map\n");
        }
  
        ret = cs35l56_common_probe(cs35l56);
@@@ -42,7 -42,7 +42,7 @@@
  
        ret = cs35l56_init(cs35l56);
        if (ret == 0)
 -              ret = cs35l56_irq_request(cs35l56, client->irq);
 +              ret = cs35l56_irq_request(&cs35l56->base, client->irq);
        if (ret < 0)
                cs35l56_remove(cs35l56);
  
@@@ -62,10 -62,19 +62,19 @@@ static const struct i2c_device_id cs35l
  };
  MODULE_DEVICE_TABLE(i2c, cs35l56_id_i2c);
  
+ #ifdef CONFIG_ACPI
+ static const struct acpi_device_id cs35l56_asoc_acpi_match[] = {
+       { "CSC355C", 0 },
+       {},
+ };
+ MODULE_DEVICE_TABLE(acpi, cs35l56_asoc_acpi_match);
+ #endif
  static struct i2c_driver cs35l56_i2c_driver = {
        .driver = {
                .name           = "cs35l56",
                .pm = &cs35l56_pm_ops_i2c_spi,
+               .acpi_match_table = ACPI_PTR(cs35l56_asoc_acpi_match),
        },
        .id_table       = cs35l56_id_i2c,
        .probe          = cs35l56_i2c_probe,
index 2057fce435be6ba43675a15a7bd852b852f4223b,302f9c47407a404b756cf9a394b26c32eab95278..9962703915e1f146d682af2b05a2175014dcee9a
@@@ -25,13 -25,13 +25,13 @@@ static int cs35l56_spi_probe(struct spi
                return -ENOMEM;
  
        spi_set_drvdata(spi, cs35l56);
 -      cs35l56->regmap = devm_regmap_init_spi(spi, regmap_config);
 -      if (IS_ERR(cs35l56->regmap)) {
 -              ret = PTR_ERR(cs35l56->regmap);
 +      cs35l56->base.regmap = devm_regmap_init_spi(spi, regmap_config);
 +      if (IS_ERR(cs35l56->base.regmap)) {
 +              ret = PTR_ERR(cs35l56->base.regmap);
                return dev_err_probe(&spi->dev, ret, "Failed to allocate register map\n");
        }
  
 -      cs35l56->dev = &spi->dev;
 +      cs35l56->base.dev = &spi->dev;
  
        ret = cs35l56_common_probe(cs35l56);
        if (ret != 0)
@@@ -39,7 -39,7 +39,7 @@@
  
        ret = cs35l56_init(cs35l56);
        if (ret == 0)
 -              ret = cs35l56_irq_request(cs35l56, spi->irq);
 +              ret = cs35l56_irq_request(&cs35l56->base, spi->irq);
        if (ret < 0)
                cs35l56_remove(cs35l56);
  
@@@ -59,10 -59,19 +59,19 @@@ static const struct spi_device_id cs35l
  };
  MODULE_DEVICE_TABLE(spi, cs35l56_id_spi);
  
+ #ifdef CONFIG_ACPI
+ static const struct acpi_device_id cs35l56_asoc_acpi_match[] = {
+       { "CSC355C", 0 },
+       {},
+ };
+ MODULE_DEVICE_TABLE(acpi, cs35l56_asoc_acpi_match);
+ #endif
  static struct spi_driver cs35l56_spi_driver = {
        .driver = {
                .name           = "cs35l56",
                .pm = &cs35l56_pm_ops_i2c_spi,
+               .acpi_match_table = ACPI_PTR(cs35l56_asoc_acpi_match),
        },
        .id_table       = cs35l56_id_spi,
        .probe          = cs35l56_spi_probe,
index 3a9ec8724cc1e76c26e7d0622db757bc81a9bad1,fd06b9f9d496d6727cdfadc24ad659185cc9b98e..600b79c62ec48a5dec9d843cb036477c7867f20a
@@@ -5,7 -5,6 +5,6 @@@
  // Copyright (C) 2023 Cirrus Logic, Inc. and
  //                    Cirrus Logic International Semiconductor Ltd.
  
- #include <linux/acpi.h>
  #include <linux/completion.h>
  #include <linux/debugfs.h>
  #include <linux/delay.h>
  static int cs35l56_dsp_event(struct snd_soc_dapm_widget *w,
                             struct snd_kcontrol *kcontrol, int event);
  
 -static int cs35l56_mbox_send(struct cs35l56_private *cs35l56, unsigned int command)
 -{
 -      unsigned int val;
 -      int ret;
 -
 -      regmap_write(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, command);
 -      ret = regmap_read_poll_timeout(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
 -                                     val, (val == 0),
 -                                     CS35L56_MBOX_POLL_US, CS35L56_MBOX_TIMEOUT_US);
 -      if (ret) {
 -              dev_warn(cs35l56->dev, "MBOX command %#x failed: %d\n", command, ret);
 -              return ret;
 -      }
 -
 -      return 0;
 -}
 -
  static void cs35l56_wait_dsp_ready(struct cs35l56_private *cs35l56)
  {
        /* Wait for patching to complete */
@@@ -157,25 -173,25 +156,25 @@@ static int cs35l56_play_event(struct sn
        unsigned int val;
        int ret;
  
 -      dev_dbg(cs35l56->dev, "play: %d\n", event);
 +      dev_dbg(cs35l56->base.dev, "play: %d\n", event);
  
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
                /* Don't wait for ACK, we check in POST_PMU that it completed */
 -              return regmap_write(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
 +              return regmap_write(cs35l56->base.regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
                                    CS35L56_MBOX_CMD_AUDIO_PLAY);
        case SND_SOC_DAPM_POST_PMU:
                /* Wait for firmware to enter PS0 power state */
 -              ret = regmap_read_poll_timeout(cs35l56->regmap,
 +              ret = regmap_read_poll_timeout(cs35l56->base.regmap,
                                               CS35L56_TRANSDUCER_ACTUAL_PS,
                                               val, (val == CS35L56_PS0),
                                               CS35L56_PS0_POLL_US,
                                               CS35L56_PS0_TIMEOUT_US);
                if (ret)
 -                      dev_err(cs35l56->dev, "PS0 wait failed: %d\n", ret);
 +                      dev_err(cs35l56->base.dev, "PS0 wait failed: %d\n", ret);
                return ret;
        case SND_SOC_DAPM_POST_PMD:
 -              return cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_AUDIO_PAUSE);
 +              return cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PAUSE);
        default:
                return 0;
        }
@@@ -293,23 -309,109 +292,23 @@@ static int cs35l56_dsp_event(struct snd
        struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
        struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(component);
  
 -      dev_dbg(cs35l56->dev, "%s: %d\n", __func__, event);
 +      dev_dbg(cs35l56->base.dev, "%s: %d\n", __func__, event);
  
        return wm_adsp_event(w, kcontrol, event);
  }
  
 -irqreturn_t cs35l56_irq(int irq, void *data)
 -{
 -      struct cs35l56_private *cs35l56 = data;
 -      unsigned int status1 = 0, status8 = 0, status20 = 0;
 -      unsigned int mask1, mask8, mask20;
 -      unsigned int val;
 -      int rv;
 -
 -      irqreturn_t ret = IRQ_NONE;
 -
 -      if (!cs35l56->init_done)
 -              return IRQ_NONE;
 -
 -      mutex_lock(&cs35l56->irq_lock);
 -
 -      rv = pm_runtime_resume_and_get(cs35l56->dev);
 -      if (rv < 0) {
 -              dev_err(cs35l56->dev, "irq: failed to get pm_runtime: %d\n", rv);
 -              goto err_unlock;
 -      }
 -
 -      regmap_read(cs35l56->regmap, CS35L56_IRQ1_STATUS, &val);
 -      if ((val & CS35L56_IRQ1_STS_MASK) == 0) {
 -              dev_dbg(cs35l56->dev, "Spurious IRQ: no pending interrupt\n");
 -              goto err;
 -      }
 -
 -      /* Ack interrupts */
 -      regmap_read(cs35l56->regmap, CS35L56_IRQ1_EINT_1, &status1);
 -      regmap_read(cs35l56->regmap, CS35L56_IRQ1_MASK_1, &mask1);
 -      status1 &= ~mask1;
 -      regmap_write(cs35l56->regmap, CS35L56_IRQ1_EINT_1, status1);
 -
 -      regmap_read(cs35l56->regmap, CS35L56_IRQ1_EINT_8, &status8);
 -      regmap_read(cs35l56->regmap, CS35L56_IRQ1_MASK_8, &mask8);
 -      status8 &= ~mask8;
 -      regmap_write(cs35l56->regmap, CS35L56_IRQ1_EINT_8, status8);
 -
 -      regmap_read(cs35l56->regmap, CS35L56_IRQ1_EINT_20, &status20);
 -      regmap_read(cs35l56->regmap, CS35L56_IRQ1_MASK_20, &mask20);
 -      status20 &= ~mask20;
 -      /* We don't want EINT20 but they default to unmasked: force mask */
 -      regmap_write(cs35l56->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff);
 -
 -      dev_dbg(cs35l56->dev, "%s: %#x %#x\n", __func__, status1, status8);
 -
 -      /* Check to see if unmasked bits are active */
 -      if (!status1 && !status8 && !status20)
 -              goto err;
 -
 -      if (status1 & CS35L56_AMP_SHORT_ERR_EINT1_MASK)
 -              dev_crit(cs35l56->dev, "Amp short error\n");
 -
 -      if (status8 & CS35L56_TEMP_ERR_EINT1_MASK)
 -              dev_crit(cs35l56->dev, "Overtemp error\n");
 -
 -      ret = IRQ_HANDLED;
 -
 -err:
 -      pm_runtime_put(cs35l56->dev);
 -err_unlock:
 -      mutex_unlock(&cs35l56->irq_lock);
 -
 -      return ret;
 -}
 -EXPORT_SYMBOL_NS_GPL(cs35l56_irq, SND_SOC_CS35L56_CORE);
 -
 -int cs35l56_irq_request(struct cs35l56_private *cs35l56, int irq)
 -{
 -      int ret;
 -
 -      if (!irq)
 -              return 0;
 -
 -      ret = devm_request_threaded_irq(cs35l56->dev, irq, NULL, cs35l56_irq,
 -                                      IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_LOW,
 -                                      "cs35l56", cs35l56);
 -      if (!ret)
 -              cs35l56->irq = irq;
 -      else
 -              dev_err(cs35l56->dev, "Failed to get IRQ: %d\n", ret);
 -
 -      return ret;
 -}
 -EXPORT_SYMBOL_NS_GPL(cs35l56_irq_request, SND_SOC_CS35L56_CORE);
 -
  static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
  {
        struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(codec_dai->component);
        unsigned int val;
  
 -      dev_dbg(cs35l56->dev, "%s: %#x\n", __func__, fmt);
 +      dev_dbg(cs35l56->base.dev, "%s: %#x\n", __func__, fmt);
  
        switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
        case SND_SOC_DAIFMT_CBC_CFC:
                break;
        default:
 -              dev_err(cs35l56->dev, "Unsupported clock source mode\n");
 +              dev_err(cs35l56->base.dev, "Unsupported clock source mode\n");
                return -EINVAL;
        }
  
                cs35l56->tdm_mode = false;
                break;
        default:
 -              dev_err(cs35l56->dev, "Unsupported DAI format\n");
 +              dev_err(cs35l56->base.dev, "Unsupported DAI format\n");
                return -EINVAL;
        }
  
        case SND_SOC_DAIFMT_NB_NF:
                break;
        default:
 -              dev_err(cs35l56->dev, "Invalid clock invert\n");
 +              dev_err(cs35l56->base.dev, "Invalid clock invert\n");
                return -EINVAL;
        }
  
 -      regmap_update_bits(cs35l56->regmap,
 +      regmap_update_bits(cs35l56->base.regmap,
                           CS35L56_ASP1_CONTROL2,
                           CS35L56_ASP_FMT_MASK |
                           CS35L56_ASP_BCLK_INV_MASK | CS35L56_ASP_FSYNC_INV_MASK,
                           val);
  
        /* Hi-Z DOUT in unused slots and when all TX are disabled */
 -      regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL3,
 +      regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL3,
                           CS35L56_ASP1_DOUT_HIZ_CTRL_MASK,
                           CS35L56_ASP_UNUSED_HIZ_OFF_HIZ);
  
        return 0;
  }
  
 -static void cs35l56_set_asp_slot_positions(struct cs35l56_private *cs35l56,
 -                                         unsigned int reg, unsigned long mask)
 +static unsigned int cs35l56_make_tdm_config_word(unsigned int reg_val, unsigned long mask)
  {
 -      unsigned int reg_val, channel_shift;
 +      unsigned int channel_shift;
        int bit_num;
  
 -      /* Init all slots to 63 */
 -      switch (reg) {
 -      case CS35L56_ASP1_FRAME_CONTROL1:
 -              reg_val = 0x3f3f3f3f;
 -              break;
 -      case CS35L56_ASP1_FRAME_CONTROL5:
 -              reg_val = 0x3f3f3f;
 -              break;
 -      }
 -
        /* Enable consecutive TX1..TXn for each of the slots set in mask */
        channel_shift = 0;
        for_each_set_bit(bit_num, &mask, 32) {
                channel_shift += 8;
        }
  
 -      regmap_write(cs35l56->regmap, reg, reg_val);
 +      return reg_val;
  }
  
  static int cs35l56_asp_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
        struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(dai->component);
  
        if ((slots == 0) || (slot_width == 0)) {
 -              dev_dbg(cs35l56->dev, "tdm config cleared\n");
 +              dev_dbg(cs35l56->base.dev, "tdm config cleared\n");
                cs35l56->asp_slot_width = 0;
                cs35l56->asp_slot_count = 0;
                return 0;
        }
  
        if (slot_width > (CS35L56_ASP_RX_WIDTH_MASK >> CS35L56_ASP_RX_WIDTH_SHIFT)) {
 -              dev_err(cs35l56->dev, "tdm invalid slot width %d\n", slot_width);
 +              dev_err(cs35l56->base.dev, "tdm invalid slot width %d\n", slot_width);
                return -EINVAL;
        }
  
        /* More than 32 slots would give an unsupportable BCLK frequency */
        if (slots > 32) {
 -              dev_err(cs35l56->dev, "tdm invalid slot count %d\n", slots);
 +              dev_err(cs35l56->base.dev, "tdm invalid slot count %d\n", slots);
                return -EINVAL;
        }
  
        if (rx_mask == 0)
                rx_mask = 0xf;  // ASPTX1..TX4 in slots 0..3
  
 -      cs35l56_set_asp_slot_positions(cs35l56, CS35L56_ASP1_FRAME_CONTROL1, rx_mask);
 -      cs35l56_set_asp_slot_positions(cs35l56, CS35L56_ASP1_FRAME_CONTROL5, tx_mask);
 +      /* Default unused slots to 63 */
 +      regmap_write(cs35l56->base.regmap, CS35L56_ASP1_FRAME_CONTROL1,
 +                   cs35l56_make_tdm_config_word(0x3f3f3f3f, rx_mask));
 +      regmap_write(cs35l56->base.regmap, CS35L56_ASP1_FRAME_CONTROL5,
 +                   cs35l56_make_tdm_config_word(0x3f3f3f, tx_mask));
  
 -      dev_dbg(cs35l56->dev, "tdm slot width: %u count: %u tx_mask: %#x rx_mask: %#x\n",
 +      dev_dbg(cs35l56->base.dev, "tdm slot width: %u count: %u tx_mask: %#x rx_mask: %#x\n",
                cs35l56->asp_slot_width, cs35l56->asp_slot_count, tx_mask, rx_mask);
  
        return 0;
@@@ -433,8 -543,7 +432,8 @@@ static int cs35l56_asp_dai_hw_params(st
        else
                asp_width = asp_wl;
  
 -      dev_dbg(cs35l56->dev, "%s: wl=%d, width=%d, rate=%d", __func__, asp_wl, asp_width, rate);
 +      dev_dbg(cs35l56->base.dev, "%s: wl=%d, width=%d, rate=%d",
 +              __func__, asp_wl, asp_width, rate);
  
        if (!cs35l56->sysclk_set) {
                unsigned int slots = cs35l56->asp_slot_count;
                bclk_freq = asp_width * slots * rate;
                freq_id = cs35l56_get_bclk_freq_id(bclk_freq);
                if (freq_id < 0) {
 -                      dev_err(cs35l56->dev, "%s: Invalid BCLK %u\n", __func__, bclk_freq);
 +                      dev_err(cs35l56->base.dev, "%s: Invalid BCLK %u\n", __func__, bclk_freq);
                        return -EINVAL;
                }
  
 -              regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL1,
 +              regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL1,
                                   CS35L56_ASP_BCLK_FREQ_MASK,
                                   freq_id << CS35L56_ASP_BCLK_FREQ_SHIFT);
        }
  
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 -              regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL2,
 +              regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL2,
                                   CS35L56_ASP_RX_WIDTH_MASK, asp_width <<
                                   CS35L56_ASP_RX_WIDTH_SHIFT);
 -              regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_DATA_CONTROL5,
 +              regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_DATA_CONTROL5,
                                   CS35L56_ASP_RX_WL_MASK, asp_wl);
        } else {
 -              regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL2,
 +              regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL2,
                                   CS35L56_ASP_TX_WIDTH_MASK, asp_width <<
                                   CS35L56_ASP_TX_WIDTH_SHIFT);
 -              regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_DATA_CONTROL1,
 +              regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_DATA_CONTROL1,
                                   CS35L56_ASP_TX_WL_MASK, asp_wl);
        }
  
@@@ -493,7 -602,7 +492,7 @@@ static int cs35l56_asp_dai_set_sysclk(s
        if (freq_id < 0)
                return freq_id;
  
 -      regmap_update_bits(cs35l56->regmap, CS35L56_ASP1_CONTROL1,
 +      regmap_update_bits(cs35l56->base.regmap, CS35L56_ASP1_CONTROL1,
                           CS35L56_ASP_BCLK_FREQ_MASK,
                           freq_id << CS35L56_ASP_BCLK_FREQ_SHIFT);
        cs35l56->sysclk_set = true;
@@@ -536,9 -645,9 +535,9 @@@ static int cs35l56_sdw_dai_hw_params(st
        struct sdw_port_config pconfig;
        int ret;
  
 -      dev_dbg(cs35l56->dev, "%s: rate %d\n", __func__, params_rate(params));
 +      dev_dbg(cs35l56->base.dev, "%s: rate %d\n", __func__, params_rate(params));
  
 -      if (!cs35l56->init_done)
 +      if (!cs35l56->base.init_done)
                return -ENODEV;
  
        if (!sdw_stream)
@@@ -651,31 -760,85 +650,31 @@@ static struct snd_soc_dai_driver cs35l5
        }
  };
  
 -static int cs35l56_wait_for_firmware_boot(struct cs35l56_private *cs35l56)
 -{
 -      unsigned int reg;
 -      unsigned int val;
 -      int ret;
 -
 -      if (cs35l56->rev < CS35L56_REVID_B0)
 -              reg = CS35L56_DSP1_HALO_STATE_A1;
 -      else
 -              reg = CS35L56_DSP1_HALO_STATE;
 -
 -      ret = regmap_read_poll_timeout(cs35l56->regmap, reg,
 -                                     val,
 -                                     (val < 0xFFFF) && (val >= CS35L56_HALO_STATE_BOOT_DONE),
 -                                     CS35L56_HALO_STATE_POLL_US,
 -                                     CS35L56_HALO_STATE_TIMEOUT_US);
 -
 -      if ((ret < 0) && (ret != -ETIMEDOUT)) {
 -              dev_err(cs35l56->dev, "Failed to read HALO_STATE: %d\n", ret);
 -              return ret;
 -      }
 -
 -      if ((ret == -ETIMEDOUT) || (val != CS35L56_HALO_STATE_BOOT_DONE)) {
 -              dev_err(cs35l56->dev, "Firmware boot fail: HALO_STATE=%#x\n", val);
 -              return -EIO;
 -      }
 -
 -      return 0;
 -}
 -
 -static inline void cs35l56_wait_min_reset_pulse(void)
 -{
 -      /* Satisfy minimum reset pulse width spec */
 -      usleep_range(CS35L56_RESET_PULSE_MIN_US, 2 * CS35L56_RESET_PULSE_MIN_US);
 -}
 -
 -static const struct reg_sequence cs35l56_system_reset_seq[] = {
 -      REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_SYSTEM_RESET),
 -};
 -
 -static void cs35l56_system_reset(struct cs35l56_private *cs35l56)
 -{
 -      cs35l56->soft_resetting = true;
 -
 -      /*
 -       * Must enter cache-only first so there can't be any more register
 -       * accesses other than the controlled system reset sequence below.
 -       */
 -      regcache_cache_only(cs35l56->regmap, true);
 -      regmap_multi_reg_write_bypassed(cs35l56->regmap,
 -                                      cs35l56_system_reset_seq,
 -                                      ARRAY_SIZE(cs35l56_system_reset_seq));
 -
 -      /* On SoundWire the registers won't be accessible until it re-enumerates. */
 -      if (cs35l56->sdw_peripheral)
 -              return;
 -
 -      usleep_range(CS35L56_CONTROL_PORT_READY_US, CS35L56_CONTROL_PORT_READY_US + 400);
 -      regcache_cache_only(cs35l56->regmap, false);
 -}
 -
  static void cs35l56_secure_patch(struct cs35l56_private *cs35l56)
  {
        int ret;
  
        /* Use wm_adsp to load and apply the firmware patch and coefficient files */
 -      ret = wm_adsp_power_up(&cs35l56->dsp);
 +      ret = wm_adsp_power_up(&cs35l56->dsp, true);
        if (ret)
 -              dev_dbg(cs35l56->dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret);
 +              dev_dbg(cs35l56->base.dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret);
        else
 -              cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_AUDIO_REINIT);
 +              cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT);
  }
  
  static void cs35l56_patch(struct cs35l56_private *cs35l56)
  {
 -      unsigned int reg;
 -      unsigned int val;
 +      unsigned int firmware_missing;
        int ret;
  
 +      ret = regmap_read(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS, &firmware_missing);
 +      if (ret) {
 +              dev_err(cs35l56->base.dev, "Failed to read PROTECTION_STATUS: %d\n", ret);
 +              return;
 +      }
 +
 +      firmware_missing &= CS35L56_FIRMWARE_MISSING;
 +
        /*
         * Disable SoundWire interrupts to prevent race with IRQ work.
         * Setting sdw_irq_no_unmask prevents the handler re-enabling
                flush_work(&cs35l56->sdw_irq_work);
        }
  
 -      ret = cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_SHUTDOWN);
 +      ret = cs35l56_firmware_shutdown(&cs35l56->base);
        if (ret)
                goto err;
  
 -      if (cs35l56->rev < CS35L56_REVID_B0)
 -              reg = CS35L56_DSP1_PM_CUR_STATE_A1;
 -      else
 -              reg = CS35L56_DSP1_PM_CUR_STATE;
 -
 -      ret = regmap_read_poll_timeout(cs35l56->regmap, reg,
 -                                     val, (val == CS35L56_HALO_STATE_SHUTDOWN),
 -                                     CS35L56_HALO_STATE_POLL_US,
 -                                     CS35L56_HALO_STATE_TIMEOUT_US);
 -      if (ret < 0)
 -              dev_err(cs35l56->dev, "Failed to poll PM_CUR_STATE to 1 is %d (ret %d)\n",
 -                      val, ret);
 -
 -      /* Use wm_adsp to load and apply the firmware patch and coefficient files */
 -      ret = wm_adsp_power_up(&cs35l56->dsp);
 +      /*
 +       * Use wm_adsp to load and apply the firmware patch and coefficient files,
 +       * but only if firmware is missing. If firmware is already patched just
 +       * power-up wm_adsp without downloading firmware.
 +       */
 +      ret = wm_adsp_power_up(&cs35l56->dsp, !!firmware_missing);
        if (ret) {
 -              dev_dbg(cs35l56->dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret);
 +              dev_dbg(cs35l56->base.dev, "%s: wm_adsp_power_up ret %d\n", __func__, ret);
                goto err;
        }
  
 -      mutex_lock(&cs35l56->irq_lock);
 +      mutex_lock(&cs35l56->base.irq_lock);
  
        init_completion(&cs35l56->init_completion);
  
 -      cs35l56_system_reset(cs35l56);
 +      cs35l56->soft_resetting = true;
 +      cs35l56_system_reset(&cs35l56->base, !!cs35l56->sdw_peripheral);
  
        if (cs35l56->sdw_peripheral) {
                /*
                 */
                if (!wait_for_completion_timeout(&cs35l56->init_completion,
                                                 msecs_to_jiffies(5000))) {
 -                      dev_err(cs35l56->dev, "%s: init_completion timed out (SDW)\n", __func__);
 +                      dev_err(cs35l56->base.dev, "%s: init_completion timed out (SDW)\n",
 +                              __func__);
                        goto err_unlock;
                }
        } else if (cs35l56_init(cs35l56)) {
                goto err_unlock;
        }
  
 -      regmap_clear_bits(cs35l56->regmap, CS35L56_PROTECTION_STATUS, CS35L56_FIRMWARE_MISSING);
 -      cs35l56->fw_patched = true;
 +      regmap_clear_bits(cs35l56->base.regmap, CS35L56_PROTECTION_STATUS,
 +                        CS35L56_FIRMWARE_MISSING);
 +      cs35l56->base.fw_patched = true;
  
  err_unlock:
 -      mutex_unlock(&cs35l56->irq_lock);
 +      mutex_unlock(&cs35l56->base.irq_lock);
  err:
        /* Re-enable SoundWire interrupts */
        if (cs35l56->sdw_peripheral) {
@@@ -749,10 -918,10 +748,10 @@@ static void cs35l56_dsp_work(struct wor
                                                       struct cs35l56_private,
                                                       dsp_work);
  
 -      if (!cs35l56->init_done)
 +      if (!cs35l56->base.init_done)
                return;
  
 -      pm_runtime_get_sync(cs35l56->dev);
 +      pm_runtime_get_sync(cs35l56->base.dev);
  
        /*
         * When the device is running in secure mode the firmware files can
         * shutdown the firmware to apply them and can use the lower cost
         * reinit sequence instead.
         */
 -      if (cs35l56->secured)
 +      if (cs35l56->base.secured)
                cs35l56_secure_patch(cs35l56);
        else
                cs35l56_patch(cs35l56);
  
 -      pm_runtime_mark_last_busy(cs35l56->dev);
 -      pm_runtime_put_autosuspend(cs35l56->dev);
 +      pm_runtime_mark_last_busy(cs35l56->base.dev);
 +      pm_runtime_put_autosuspend(cs35l56->base.dev);
  }
  
  static int cs35l56_component_probe(struct snd_soc_component *component)
  
        if (!wait_for_completion_timeout(&cs35l56->init_completion,
                                         msecs_to_jiffies(5000))) {
 -              dev_err(cs35l56->dev, "%s: init_completion timed out\n", __func__);
 +              dev_err(cs35l56->base.dev, "%s: init_completion timed out\n", __func__);
                return -ENODEV;
        }
  
        cs35l56->component = component;
        wm_adsp2_component_probe(&cs35l56->dsp, component);
  
 -      debugfs_create_bool("init_done", 0444, debugfs_root, &cs35l56->init_done);
 -      debugfs_create_bool("can_hibernate", 0444, debugfs_root, &cs35l56->can_hibernate);
 -      debugfs_create_bool("fw_patched", 0444, debugfs_root, &cs35l56->fw_patched);
 +      debugfs_create_bool("init_done", 0444, debugfs_root, &cs35l56->base.init_done);
 +      debugfs_create_bool("can_hibernate", 0444, debugfs_root, &cs35l56->base.can_hibernate);
 +      debugfs_create_bool("fw_patched", 0444, debugfs_root, &cs35l56->base.fw_patched);
  
        queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work);
  
@@@ -839,18 -1008,171 +838,18 @@@ static const struct snd_soc_component_d
        .suspend_bias_off = 1, /* see cs35l56_system_resume() */
  };
  
 -static const struct reg_sequence cs35l56_hibernate_seq[] = {
 -      /* This must be the last register access */
 -      REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_HIBERNATE_NOW),
 -};
 -
 -static const struct reg_sequence cs35l56_hibernate_wake_seq[] = {
 -      REG_SEQ0(CS35L56_DSP_VIRTUAL1_MBOX_1, CS35L56_MBOX_CMD_WAKEUP),
 -};
 -
 -int cs35l56_runtime_suspend(struct device *dev)
 +static int __maybe_unused cs35l56_runtime_suspend_i2c_spi(struct device *dev)
  {
        struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
 -      unsigned int val;
 -      int ret;
 -
 -      if (!cs35l56->init_done)
 -              return 0;
 -
 -      /* Firmware must have entered a power-save state */
 -      ret = regmap_read_poll_timeout(cs35l56->regmap,
 -                                     CS35L56_TRANSDUCER_ACTUAL_PS,
 -                                     val, (val >= CS35L56_PS3),
 -                                     CS35L56_PS3_POLL_US,
 -                                     CS35L56_PS3_TIMEOUT_US);
 -      if (ret)
 -              dev_warn(cs35l56->dev, "PS3 wait failed: %d\n", ret);
 -
 -      /* Clear BOOT_DONE so it can be used to detect a reboot */
 -      regmap_write(cs35l56->regmap, CS35L56_IRQ1_EINT_4, CS35L56_OTP_BOOT_DONE_MASK);
 -
 -      if (!cs35l56->can_hibernate) {
 -              regcache_cache_only(cs35l56->regmap, true);
 -              dev_dbg(dev, "Suspended: no hibernate");
 -
 -              return 0;
 -      }
 -
 -      /*
 -       * Enable auto-hibernate. If it is woken by some other wake source
 -       * it will automatically return to hibernate.
 -       */
 -      cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE);
 -
 -      /*
 -       * Must enter cache-only first so there can't be any more register
 -       * accesses other than the controlled hibernate sequence below.
 -       */
 -      regcache_cache_only(cs35l56->regmap, true);
 -
 -      regmap_multi_reg_write_bypassed(cs35l56->regmap,
 -                                      cs35l56_hibernate_seq,
 -                                      ARRAY_SIZE(cs35l56_hibernate_seq));
 -
 -      dev_dbg(dev, "Suspended: hibernate");
  
 -      return 0;
 +      return cs35l56_runtime_suspend_common(&cs35l56->base);
  }
 -EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_suspend, SND_SOC_CS35L56_CORE);
  
  static int __maybe_unused cs35l56_runtime_resume_i2c_spi(struct device *dev)
  {
        struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
  
 -      if (!cs35l56->init_done)
 -              return 0;
 -
 -      return cs35l56_runtime_resume_common(cs35l56);
 -}
 -
 -int cs35l56_runtime_resume_common(struct cs35l56_private *cs35l56)
 -{
 -      unsigned int val;
 -      int ret;
 -
 -      if (!cs35l56->can_hibernate)
 -              goto out_sync;
 -
 -      if (!cs35l56->sdw_peripheral) {
 -              /*
 -               * Dummy transaction to trigger I2C/SPI auto-wake. This will NAK on I2C.
 -               * Must be done before releasing cache-only.
 -               */
 -              regmap_multi_reg_write_bypassed(cs35l56->regmap,
 -                                              cs35l56_hibernate_wake_seq,
 -                                              ARRAY_SIZE(cs35l56_hibernate_wake_seq));
 -
 -              usleep_range(CS35L56_CONTROL_PORT_READY_US,
 -                           CS35L56_CONTROL_PORT_READY_US + 400);
 -      }
 -
 -out_sync:
 -      regcache_cache_only(cs35l56->regmap, false);
 -
 -      ret = cs35l56_wait_for_firmware_boot(cs35l56);
 -      if (ret) {
 -              dev_err(cs35l56->dev, "Hibernate wake failed: %d\n", ret);
 -              goto err;
 -      }
 -
 -      ret = cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
 -      if (ret)
 -              goto err;
 -
 -      /* BOOT_DONE will be 1 if the amp reset */
 -      regmap_read(cs35l56->regmap, CS35L56_IRQ1_EINT_4, &val);
 -      if (val & CS35L56_OTP_BOOT_DONE_MASK) {
 -              dev_dbg(cs35l56->dev, "Registers reset in suspend\n");
 -              regcache_mark_dirty(cs35l56->regmap);
 -      }
 -
 -      regcache_sync(cs35l56->regmap);
 -
 -      dev_dbg(cs35l56->dev, "Resumed");
 -
 -      return 0;
 -
 -err:
 -      regmap_write(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
 -                   CS35L56_MBOX_CMD_HIBERNATE_NOW);
 -
 -      regcache_cache_only(cs35l56->regmap, true);
 -
 -      return ret;
 -}
 -EXPORT_SYMBOL_NS_GPL(cs35l56_runtime_resume_common, SND_SOC_CS35L56_CORE);
 -
 -static int cs35l56_is_fw_reload_needed(struct cs35l56_private *cs35l56)
 -{
 -      unsigned int val;
 -      int ret;
 -
 -      /* Nothing to re-patch if we haven't done any patching yet. */
 -      if (!cs35l56->fw_patched)
 -              return false;
 -
 -      /*
 -       * If we have control of RESET we will have asserted it so the firmware
 -       * will need re-patching.
 -       */
 -      if (cs35l56->reset_gpio)
 -              return true;
 -
 -      /*
 -       * In secure mode FIRMWARE_MISSING is cleared by the BIOS loader so
 -       * can't be used here to test for memory retention.
 -       * Assume that tuning must be re-loaded.
 -       */
 -      if (cs35l56->secured)
 -              return true;
 -
 -      ret = pm_runtime_resume_and_get(cs35l56->dev);
 -      if (ret) {
 -              dev_err(cs35l56->dev, "Failed to runtime_get: %d\n", ret);
 -              return ret;
 -      }
 -
 -      ret = regmap_read(cs35l56->regmap, CS35L56_PROTECTION_STATUS, &val);
 -      if (ret)
 -              dev_err(cs35l56->dev, "Failed to read PROTECTION_STATUS: %d\n", ret);
 -      else
 -              ret = !!(val & CS35L56_FIRMWARE_MISSING);
 -
 -      pm_runtime_put_autosuspend(cs35l56->dev);
 -
 -      return ret;
 +      return cs35l56_runtime_resume_common(&cs35l56->base, false);
  }
  
  int cs35l56_system_suspend(struct device *dev)
         * clear it. Prevent this race by temporarily disabling the parent irq
         * until we reach _no_irq.
         */
 -      if (cs35l56->irq)
 -              disable_irq(cs35l56->irq);
 +      if (cs35l56->base.irq)
 +              disable_irq(cs35l56->base.irq);
  
        return pm_runtime_force_suspend(dev);
  }
@@@ -886,8 -1208,8 +885,8 @@@ int cs35l56_system_suspend_late(struct 
         * RESET is usually shared by all amps so it must not be asserted until
         * all driver instances have done their suspend() stage.
         */
 -      if (cs35l56->reset_gpio) {
 -              gpiod_set_value_cansleep(cs35l56->reset_gpio, 0);
 +      if (cs35l56->base.reset_gpio) {
 +              gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
                cs35l56_wait_min_reset_pulse();
        }
  
@@@ -904,8 -1226,8 +903,8 @@@ int cs35l56_system_suspend_no_irq(struc
        dev_dbg(dev, "system_suspend_no_irq\n");
  
        /* Handlers are now disabled so the parent IRQ can safely be re-enabled. */
 -      if (cs35l56->irq)
 -              enable_irq(cs35l56->irq);
 +      if (cs35l56->base.irq)
 +              enable_irq(cs35l56->base.irq);
  
        return 0;
  }
@@@ -924,8 -1246,8 +923,8 @@@ int cs35l56_system_resume_no_irq(struc
         * clear it, until it has fully resumed. Prevent this race by temporarily
         * disabling the parent irq until we complete resume().
         */
 -      if (cs35l56->irq)
 -              disable_irq(cs35l56->irq);
 +      if (cs35l56->base.irq)
 +              disable_irq(cs35l56->base.irq);
  
        return 0;
  }
@@@ -939,8 -1261,8 +938,8 @@@ int cs35l56_system_resume_early(struct 
        dev_dbg(dev, "system_resume_early\n");
  
        /* Ensure a spec-compliant RESET pulse. */
 -      if (cs35l56->reset_gpio) {
 -              gpiod_set_value_cansleep(cs35l56->reset_gpio, 0);
 +      if (cs35l56->base.reset_gpio) {
 +              gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
                cs35l56_wait_min_reset_pulse();
        }
  
        }
  
        /* Release shared RESET before drivers start resume(). */
 -      gpiod_set_value_cansleep(cs35l56->reset_gpio, 1);
 +      gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);
  
        return 0;
  }
@@@ -965,16 -1287,10 +964,16 @@@ int cs35l56_system_resume(struct devic
  
        dev_dbg(dev, "system_resume\n");
  
 +      /*
 +       * We might have done a hard reset or the CS35L56 was power-cycled
 +       * so wait for control port to be ready.
 +       */
 +      cs35l56_wait_control_port_ready();
 +
        /* Undo pm_runtime_force_suspend() before re-enabling the irq */
        ret = pm_runtime_force_resume(dev);
 -      if (cs35l56->irq)
 -              enable_irq(cs35l56->irq);
 +      if (cs35l56->base.irq)
 +              enable_irq(cs35l56->base.irq);
  
        if (ret)
                return ret;
        if (!cs35l56->component)
                return 0;
  
 -      ret = cs35l56_is_fw_reload_needed(cs35l56);
 -      dev_dbg(cs35l56->dev, "fw_reload_needed: %d\n", ret);
 +      ret = cs35l56_is_fw_reload_needed(&cs35l56->base);
 +      dev_dbg(cs35l56->base.dev, "fw_reload_needed: %d\n", ret);
        if (ret < 1)
                return ret;
  
 -      cs35l56->fw_patched = false;
 +      cs35l56->base.fw_patched = false;
 +      wm_adsp_power_down(&cs35l56->dsp);
        queue_work(cs35l56->dsp_wq, &cs35l56->dsp_work);
  
        /*
@@@ -1013,42 -1328,47 +1012,38 @@@ static int cs35l56_dsp_init(struct cs35
        INIT_WORK(&cs35l56->dsp_work, cs35l56_dsp_work);
  
        dsp = &cs35l56->dsp;
 +      cs35l56_init_cs_dsp(&cs35l56->base, &dsp->cs_dsp);
        dsp->part = "cs35l56";
 -      dsp->cs_dsp.num = 1;
 -      dsp->cs_dsp.type = WMFW_HALO;
 -      dsp->cs_dsp.rev = 0;
        dsp->fw = 12;
 -      dsp->cs_dsp.dev = cs35l56->dev;
 -      dsp->cs_dsp.regmap = cs35l56->regmap;
 -      dsp->cs_dsp.base = CS35L56_DSP1_CORE_BASE;
 -      dsp->cs_dsp.base_sysinfo = CS35L56_DSP1_SYS_INFO_ID;
 -      dsp->cs_dsp.mem = cs35l56_dsp1_regions;
 -      dsp->cs_dsp.num_mems = ARRAY_SIZE(cs35l56_dsp1_regions);
 -      dsp->cs_dsp.no_core_startstop = true;
        dsp->wmfw_optional = true;
  
 -      dev_dbg(cs35l56->dev, "DSP system name: '%s'\n", dsp->system_name);
 +      dev_dbg(cs35l56->base.dev, "DSP system name: '%s'\n", dsp->system_name);
  
        ret = wm_halo_init(dsp);
        if (ret != 0) {
 -              dev_err(cs35l56->dev, "wm_halo_init failed\n");
 +              dev_err(cs35l56->base.dev, "wm_halo_init failed\n");
                return ret;
        }
  
        return 0;
  }
  
- static int cs35l56_acpi_get_name(struct cs35l56_private *cs35l56)
+ static int cs35l56_get_firmware_uid(struct cs35l56_private *cs35l56)
  {
-       acpi_handle handle = ACPI_HANDLE(cs35l56->base.dev);
-       const char *sub;
 -      struct device *dev = cs35l56->dev;
++      struct device *dev = cs35l56->base.dev;
+       const char *prop;
+       int ret;
  
-       /* If there is no ACPI_HANDLE, there is no ACPI for this system, return 0 */
-       if (!handle)
+       ret = device_property_read_string(dev, "cirrus,firmware-uid", &prop);
+       /* If bad sw node property, return 0 and fallback to legacy firmware path */
+       if (ret < 0)
                return 0;
  
-       sub = acpi_get_subsystem_id(handle);
-       if (IS_ERR(sub)) {
-               /* If bad ACPI, return 0 and fallback to legacy firmware path, otherwise fail */
-               if (PTR_ERR(sub) == -ENODATA)
-                       return 0;
-               else
-                       return PTR_ERR(sub);
-       }
+       cs35l56->dsp.system_name = devm_kstrdup(dev, prop, GFP_KERNEL);
+       if (cs35l56->dsp.system_name == NULL)
+               return -ENOMEM;
  
-       cs35l56->dsp.system_name = sub;
-       dev_dbg(cs35l56->base.dev, "Subsystem ID: %s\n", cs35l56->dsp.system_name);
+       dev_dbg(dev, "Firmware UID: %s\n", cs35l56->dsp.system_name);
  
        return 0;
  }
@@@ -1058,65 -1378,62 +1053,65 @@@ int cs35l56_common_probe(struct cs35l56
        int ret;
  
        init_completion(&cs35l56->init_completion);
 -      mutex_init(&cs35l56->irq_lock);
 +      mutex_init(&cs35l56->base.irq_lock);
  
 -      dev_set_drvdata(cs35l56->dev, cs35l56);
 +      dev_set_drvdata(cs35l56->base.dev, cs35l56);
  
        cs35l56_fill_supply_names(cs35l56->supplies);
 -      ret = devm_regulator_bulk_get(cs35l56->dev, ARRAY_SIZE(cs35l56->supplies),
 +      ret = devm_regulator_bulk_get(cs35l56->base.dev, ARRAY_SIZE(cs35l56->supplies),
                                      cs35l56->supplies);
        if (ret != 0)
 -              return dev_err_probe(cs35l56->dev, ret, "Failed to request supplies\n");
 +              return dev_err_probe(cs35l56->base.dev, ret, "Failed to request supplies\n");
  
        /* Reset could be controlled by the BIOS or shared by multiple amps */
 -      cs35l56->reset_gpio = devm_gpiod_get_optional(cs35l56->dev, "reset", GPIOD_OUT_LOW);
 -      if (IS_ERR(cs35l56->reset_gpio)) {
 -              ret = PTR_ERR(cs35l56->reset_gpio);
 +      cs35l56->base.reset_gpio = devm_gpiod_get_optional(cs35l56->base.dev, "reset",
 +                                                         GPIOD_OUT_LOW);
 +      if (IS_ERR(cs35l56->base.reset_gpio)) {
 +              ret = PTR_ERR(cs35l56->base.reset_gpio);
                /*
                 * If RESET is shared the first amp to probe will grab the reset
                 * line and reset all the amps
                 */
                if (ret != -EBUSY)
 -                      return dev_err_probe(cs35l56->dev, ret, "Failed to get reset GPIO\n");
 +                      return dev_err_probe(cs35l56->base.dev, ret, "Failed to get reset GPIO\n");
  
 -              dev_info(cs35l56->dev, "Reset GPIO busy, assume shared reset\n");
 -              cs35l56->reset_gpio = NULL;
 +              dev_info(cs35l56->base.dev, "Reset GPIO busy, assume shared reset\n");
 +              cs35l56->base.reset_gpio = NULL;
        }
  
        ret = regulator_bulk_enable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies);
        if (ret != 0)
 -              return dev_err_probe(cs35l56->dev, ret, "Failed to enable supplies\n");
 +              return dev_err_probe(cs35l56->base.dev, ret, "Failed to enable supplies\n");
  
 -      if (cs35l56->reset_gpio) {
 +      if (cs35l56->base.reset_gpio) {
 +              /* ACPI can override GPIOD_OUT_LOW flag so force it to start low */
 +              gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
                cs35l56_wait_min_reset_pulse();
 -              gpiod_set_value_cansleep(cs35l56->reset_gpio, 1);
 +              gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);
        }
  
-       ret = cs35l56_acpi_get_name(cs35l56);
+       ret = cs35l56_get_firmware_uid(cs35l56);
        if (ret != 0)
                goto err;
  
        ret = cs35l56_dsp_init(cs35l56);
        if (ret < 0) {
 -              dev_err_probe(cs35l56->dev, ret, "DSP init failed\n");
 +              dev_err_probe(cs35l56->base.dev, ret, "DSP init failed\n");
                goto err;
        }
  
 -      ret = devm_snd_soc_register_component(cs35l56->dev,
 +      ret = devm_snd_soc_register_component(cs35l56->base.dev,
                                              &soc_component_dev_cs35l56,
                                              cs35l56_dai, ARRAY_SIZE(cs35l56_dai));
        if (ret < 0) {
 -              dev_err_probe(cs35l56->dev, ret, "Register codec failed\n");
 +              dev_err_probe(cs35l56->base.dev, ret, "Register codec failed\n");
                goto err;
        }
  
        return 0;
  
  err:
 -      gpiod_set_value_cansleep(cs35l56->reset_gpio, 0);
 +      gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
        regulator_bulk_disable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies);
  
        return ret;
@@@ -1126,6 -1443,7 +1121,6 @@@ EXPORT_SYMBOL_NS_GPL(cs35l56_common_pro
  int cs35l56_init(struct cs35l56_private *cs35l56)
  {
        int ret;
 -      unsigned int devid, revid, otpid, secured;
  
        /*
         * Check whether the actions associated with soft reset or one time
        if (cs35l56->soft_resetting)
                goto post_soft_reset;
  
 -      if (cs35l56->init_done)
 +      if (cs35l56->base.init_done)
                return 0;
  
 -      pm_runtime_set_autosuspend_delay(cs35l56->dev, 100);
 -      pm_runtime_use_autosuspend(cs35l56->dev);
 -      pm_runtime_set_active(cs35l56->dev);
 -      pm_runtime_enable(cs35l56->dev);
 -
 -      /*
 -       * If the system is not using a reset_gpio then issue a
 -       * dummy read to force a wakeup.
 -       */
 -      if (!cs35l56->reset_gpio)
 -              regmap_read(cs35l56->regmap, CS35L56_DSP_VIRTUAL1_MBOX_1, &devid);
 -
 -      /* Wait for control port to be ready (datasheet tIRS). */
 -      usleep_range(CS35L56_CONTROL_PORT_READY_US,
 -                   CS35L56_CONTROL_PORT_READY_US + 400);
 -
 -      /*
 -       * The HALO_STATE register is in different locations on Ax and B0
 -       * devices so the REVID needs to be determined before waiting for the
 -       * firmware to boot.
 -       */
 -      ret = regmap_read(cs35l56->regmap, CS35L56_REVID, &revid);
 -      if (ret < 0) {
 -              dev_err(cs35l56->dev, "Get Revision ID failed\n");
 -              return ret;
 -      }
 -      cs35l56->rev = revid & (CS35L56_AREVID_MASK | CS35L56_MTLREVID_MASK);
 -
 -      ret = cs35l56_wait_for_firmware_boot(cs35l56);
 -      if (ret)
 -              return ret;
 -
 -      ret = regmap_read(cs35l56->regmap, CS35L56_DEVID, &devid);
 -      if (ret < 0) {
 -              dev_err(cs35l56->dev, "Get Device ID failed\n");
 -              return ret;
 -      }
 -      devid &= CS35L56_DEVID_MASK;
 -
 -      switch (devid) {
 -      case 0x35A56:
 -              break;
 -      default:
 -              dev_err(cs35l56->dev, "Unknown device %x\n", devid);
 -              return ret;
 -      }
 -
 -      ret = regmap_read(cs35l56->regmap, CS35L56_DSP_RESTRICT_STS1, &secured);
 -      if (ret) {
 -              dev_err(cs35l56->dev, "Get Secure status failed\n");
 -              return ret;
 -      }
 -
 -      /* When any bus is restricted treat the device as secured */
 -      if (secured & CS35L56_RESTRICTED_MASK)
 -              cs35l56->secured = true;
 +      pm_runtime_set_autosuspend_delay(cs35l56->base.dev, 100);
 +      pm_runtime_use_autosuspend(cs35l56->base.dev);
 +      pm_runtime_set_active(cs35l56->base.dev);
 +      pm_runtime_enable(cs35l56->base.dev);
  
 -      ret = regmap_read(cs35l56->regmap, CS35L56_OTPID, &otpid);
 -      if (ret < 0) {
 -              dev_err(cs35l56->dev, "Get OTP ID failed\n");
 +      ret = cs35l56_hw_init(&cs35l56->base);
 +      if (ret < 0)
                return ret;
 -      }
 -
 -      dev_info(cs35l56->dev, "Cirrus Logic CS35L56%s Rev %02X OTP%d\n",
 -               cs35l56->secured ? "s" : "", cs35l56->rev, otpid);
  
        /* Populate the DSP information with the revision and security state */
 -      cs35l56->dsp.part = devm_kasprintf(cs35l56->dev, GFP_KERNEL, "cs35l56%s-%02x",
 -                                         cs35l56->secured ? "s" : "", cs35l56->rev);
 +      cs35l56->dsp.part = devm_kasprintf(cs35l56->base.dev, GFP_KERNEL, "cs35l56%s-%02x",
 +                                         cs35l56->base.secured ? "s" : "", cs35l56->base.rev);
        if (!cs35l56->dsp.part)
                return -ENOMEM;
  
 -      /* Wake source and *_BLOCKED interrupts default to unmasked, so mask them */
 -      regmap_write(cs35l56->regmap, CS35L56_IRQ1_MASK_20, 0xffffffff);
 -      regmap_update_bits(cs35l56->regmap, CS35L56_IRQ1_MASK_1,
 -                         CS35L56_AMP_SHORT_ERR_EINT1_MASK,
 -                         0);
 -      regmap_update_bits(cs35l56->regmap, CS35L56_IRQ1_MASK_8,
 -                         CS35L56_TEMP_ERR_EINT1_MASK,
 -                         0);
 -
 -      if (!cs35l56->reset_gpio) {
 -              dev_dbg(cs35l56->dev, "No reset gpio: using soft reset\n");
 -              cs35l56_system_reset(cs35l56);
 +      if (!cs35l56->base.reset_gpio) {
 +              dev_dbg(cs35l56->base.dev, "No reset gpio: using soft reset\n");
 +              cs35l56->soft_resetting = true;
 +              cs35l56_system_reset(&cs35l56->base, !!cs35l56->sdw_peripheral);
                if (cs35l56->sdw_peripheral) {
                        /* Keep alive while we wait for re-enumeration */
 -                      pm_runtime_get_noresume(cs35l56->dev);
 +                      pm_runtime_get_noresume(cs35l56->base.dev);
                        return 0;
                }
        }
@@@ -1168,30 -1551,29 +1163,30 @@@ post_soft_reset
                cs35l56->soft_resetting = false;
  
                /* Done re-enumerating after one-time init so release the keep-alive */
 -              if (cs35l56->sdw_peripheral && !cs35l56->init_done)
 -                      pm_runtime_put_noidle(cs35l56->dev);
 +              if (cs35l56->sdw_peripheral && !cs35l56->base.init_done)
 +                      pm_runtime_put_noidle(cs35l56->base.dev);
  
 -              regcache_mark_dirty(cs35l56->regmap);
 -              ret = cs35l56_wait_for_firmware_boot(cs35l56);
 +              regcache_mark_dirty(cs35l56->base.regmap);
 +              ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);
                if (ret)
                        return ret;
  
 -              dev_dbg(cs35l56->dev, "Firmware rebooted after soft reset\n");
 +              dev_dbg(cs35l56->base.dev, "Firmware rebooted after soft reset\n");
        }
  
        /* Disable auto-hibernate so that runtime_pm has control */
 -      ret = cs35l56_mbox_send(cs35l56, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
 +      ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
        if (ret)
                return ret;
  
 -      /* Populate soft registers in the regmap cache */
 -      cs35l56_reread_firmware_registers(cs35l56->dev, cs35l56->regmap);
 +      ret = cs35l56_set_patch(&cs35l56->base);
 +      if (ret)
 +              return ret;
  
        /* Registers could be dirty after soft reset or SoundWire enumeration */
 -      regcache_sync(cs35l56->regmap);
 +      regcache_sync(cs35l56->base.regmap);
  
 -      cs35l56->init_done = true;
 +      cs35l56->base.init_done = true;
        complete(&cs35l56->init_completion);
  
        return 0;
@@@ -1200,32 -1582,30 +1195,30 @@@ EXPORT_SYMBOL_NS_GPL(cs35l56_init, SND_
  
  void cs35l56_remove(struct cs35l56_private *cs35l56)
  {
 -      cs35l56->init_done = false;
 +      cs35l56->base.init_done = false;
  
        /*
         * WAKE IRQs unmask if CS35L56 hibernates so free the handler to
         * prevent it racing with remove().
         */
 -      if (cs35l56->irq)
 -              devm_free_irq(cs35l56->dev, cs35l56->irq, cs35l56);
 +      if (cs35l56->base.irq)
 +              devm_free_irq(cs35l56->base.dev, cs35l56->base.irq, &cs35l56->base);
  
        flush_workqueue(cs35l56->dsp_wq);
        destroy_workqueue(cs35l56->dsp_wq);
  
 -      pm_runtime_suspend(cs35l56->dev);
 -      pm_runtime_disable(cs35l56->dev);
 +      pm_runtime_suspend(cs35l56->base.dev);
 +      pm_runtime_disable(cs35l56->base.dev);
  
 -      regcache_cache_only(cs35l56->regmap, true);
 +      regcache_cache_only(cs35l56->base.regmap, true);
  
-       kfree(cs35l56->dsp.system_name);
 -      gpiod_set_value_cansleep(cs35l56->reset_gpio, 0);
 +      gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
        regulator_bulk_disable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies);
  }
  EXPORT_SYMBOL_NS_GPL(cs35l56_remove, SND_SOC_CS35L56_CORE);
  
  const struct dev_pm_ops cs35l56_pm_ops_i2c_spi = {
 -      SET_RUNTIME_PM_OPS(cs35l56_runtime_suspend, cs35l56_runtime_resume_i2c_spi, NULL)
 +      SET_RUNTIME_PM_OPS(cs35l56_runtime_suspend_i2c_spi, cs35l56_runtime_resume_i2c_spi, NULL)
        SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend, cs35l56_system_resume)
        LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend_late, cs35l56_system_resume_early)
        NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend_no_irq, cs35l56_system_resume_no_irq)
index c98cd7abef6a6bb60623e4d562cbb8409fcc961a,e566c8ddd3e97b94129a4ac535344a49b7c75e19..63d4abf964d45cdc36938adb97b67ba8b98a4cdd
@@@ -52,6 -52,7 +52,7 @@@ static bool rt1308_volatile_register(st
        case 0x300a:
        case 0xc000:
        case 0xc710:
+       case 0xcf01:
        case 0xc860 ... 0xc863:
        case 0xc870 ... 0xc873:
                return true;
@@@ -213,24 -214,39 +214,28 @@@ static int rt1308_io_init(struct devic
  {
        struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev);
        int ret = 0;
-       unsigned int tmp;
+       unsigned int tmp, hibernation_flag;
  
        if (rt1308->hw_init)
                return 0;
  
 -      if (rt1308->first_hw_init) {
 -              regcache_cache_only(rt1308->regmap, false);
 +      regcache_cache_only(rt1308->regmap, false);
 +      if (rt1308->first_hw_init)
                regcache_cache_bypass(rt1308->regmap, true);
 -      }
  
        /*
 -       * PM runtime is only enabled when a Slave reports as Attached
 +       * PM runtime status is marked as 'active' only when a Slave reports as Attached
         */
 -      if (!rt1308->first_hw_init) {
 -              /* set autosuspend parameters */
 -              pm_runtime_set_autosuspend_delay(&slave->dev, 3000);
 -              pm_runtime_use_autosuspend(&slave->dev);
 -
 +      if (!rt1308->first_hw_init)
                /* update count of parent 'active' children */
                pm_runtime_set_active(&slave->dev);
  
 -              /* make sure the device does not suspend immediately */
 -              pm_runtime_mark_last_busy(&slave->dev);
 -
 -              pm_runtime_enable(&slave->dev);
 -      }
 -
        pm_runtime_get_noresume(&slave->dev);
  
+       regmap_read(rt1308->regmap, 0xcf01, &hibernation_flag);
+       if ((hibernation_flag != 0x00) && rt1308->first_hw_init)
+               goto _preset_ready_;
        /* sw reset */
        regmap_write(rt1308->regmap, RT1308_SDW_RESET, 0);
  
        regmap_write(rt1308->regmap, 0xc100, 0xd7);
        regmap_write(rt1308->regmap, 0xc101, 0xd7);
  
+       /* apply BQ params */
+       rt1308_apply_bq_params(rt1308);
+       regmap_write(rt1308->regmap, 0xcf01, 0x01);
+ _preset_ready_:
        if (rt1308->first_hw_init) {
                regcache_cache_bypass(rt1308->regmap, false);
                regcache_mark_dirty(rt1308->regmap);
@@@ -615,9 -637,6 +626,9 @@@ static int rt1308_sdw_component_probe(s
        rt1308->component = component;
        rt1308_sdw_parse_dt(rt1308, &rt1308->sdw_slave->dev);
  
 +      if (!rt1308->first_hw_init)
 +              return 0;
 +
        ret = pm_runtime_resume(component->dev);
        if (ret < 0 && ret != -EACCES)
                return ret;
@@@ -680,8 -699,6 +691,8 @@@ static int rt1308_sdw_init(struct devic
        rt1308->sdw_slave = slave;
        rt1308->regmap = regmap;
  
 +      regcache_cache_only(rt1308->regmap, true);
 +
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
                                &soc_component_sdw_rt1308,
                                rt1308_sdw_dai,
                                ARRAY_SIZE(rt1308_sdw_dai));
 +      if (ret < 0)
 +              return ret;
  
 -      dev_dbg(&slave->dev, "%s\n", __func__);
 +      /* set autosuspend parameters */
 +      pm_runtime_set_autosuspend_delay(dev, 3000);
 +      pm_runtime_use_autosuspend(dev);
  
 -      return ret;
 +      /* make sure the device does not suspend immediately */
 +      pm_runtime_mark_last_busy(dev);
 +
 +      pm_runtime_enable(dev);
 +
 +      /* important note: the device is NOT tagged as 'active' and will remain
 +       * 'suspended' until the hardware is enumerated/initialized. This is required
 +       * to make sure the ASoC framework use of pm_runtime_get_sync() does not silently
 +       * fail with -EACCESS because of race conditions between card creation and enumeration
 +       */
 +
 +      dev_dbg(dev, "%s\n", __func__);
 +
 +      return 0;
  }
  
  static int rt1308_sdw_probe(struct sdw_slave *slave,
        if (IS_ERR(regmap))
                return PTR_ERR(regmap);
  
 -      rt1308_sdw_init(&slave->dev, regmap, slave);
 -
 -      return 0;
 +      return rt1308_sdw_init(&slave->dev, regmap, slave);
  }
  
  static int rt1308_sdw_remove(struct sdw_slave *slave)
  {
 -      struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(&slave->dev);
 -
 -      if (rt1308->first_hw_init)
 -              pm_runtime_disable(&slave->dev);
 +      pm_runtime_disable(&slave->dev);
  
        return 0;
  }
diff --combined sound/soc/sof/ipc4-pcm.c
index 802cbf73594e45ce52fcafd3a349a85507fc53b7,027416eb2f504095f9d8a1a649d4591702f701fc..db19cd03ecad8a91f327c7c0c7d63879a52aa315
@@@ -23,8 -23,7 +23,8 @@@ static int sof_ipc4_set_multi_pipeline_
  
        /* trigger a single pipeline */
        if (trigger_list->count == 1)
 -              return sof_ipc4_set_pipeline_state(sdev, trigger_list->pipeline_ids[0], state);
 +              return sof_ipc4_set_pipeline_state(sdev, trigger_list->pipeline_instance_ids[0],
 +                                                 state);
  
        primary = state;
        primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE);
        return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, ipc_size);
  }
  
 -int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state)
 +int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 instance_id, u32 state)
  {
        struct sof_ipc4_msg msg = {{ 0 }};
        u32 primary;
  
 -      dev_dbg(sdev->dev, "ipc4 set pipeline %d state %d", id, state);
 +      dev_dbg(sdev->dev, "ipc4 set pipeline instance %d state %d", instance_id, state);
  
        primary = state;
 -      primary |= SOF_IPC4_GLB_PIPE_STATE_ID(id);
 +      primary |= SOF_IPC4_GLB_PIPE_STATE_ID(instance_id);
        primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE);
        primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
        primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
@@@ -80,19 -79,19 +80,19 @@@ sof_ipc4_add_pipeline_to_trigger_list(s
                 * for the first time
                 */
                if (spipe->started_count == spipe->paused_count)
 -                      trigger_list->pipeline_ids[trigger_list->count++] =
 +                      trigger_list->pipeline_instance_ids[trigger_list->count++] =
                                pipe_widget->instance_id;
                break;
        case SOF_IPC4_PIPE_RESET:
                /* RESET if the pipeline is neither running nor paused */
                if (!spipe->started_count && !spipe->paused_count)
 -                      trigger_list->pipeline_ids[trigger_list->count++] =
 +                      trigger_list->pipeline_instance_ids[trigger_list->count++] =
                                pipe_widget->instance_id;
                break;
        case SOF_IPC4_PIPE_PAUSED:
                /* Pause the pipeline only when its started_count is 1 more than paused_count */
                if (spipe->paused_count == (spipe->started_count - 1))
 -                      trigger_list->pipeline_ids[trigger_list->count++] =
 +                      trigger_list->pipeline_instance_ids[trigger_list->count++] =
                                pipe_widget->instance_id;
                break;
        default:
@@@ -114,7 -113,7 +114,7 @@@ sof_ipc4_update_pipeline_state(struct s
  
        /* set state for pipeline if it was just triggered */
        for (i = 0; i < trigger_list->count; i++) {
 -              if (trigger_list->pipeline_ids[i] == pipe_widget->instance_id) {
 +              if (trigger_list->pipeline_instance_ids[i] == pipe_widget->instance_id) {
                        pipeline->state = state;
                        break;
                }
@@@ -315,8 -314,8 +315,8 @@@ static int sof_ipc4_trigger_pipelines(s
                return sof_ipc4_chain_dma_trigger(sdev, pipeline_list, state, cmd);
  
        /* allocate memory for the pipeline data */
 -      trigger_list = kzalloc(struct_size(trigger_list, pipeline_ids, pipeline_list->count),
 -                             GFP_KERNEL);
 +      trigger_list = kzalloc(struct_size(trigger_list, pipeline_instance_ids,
 +                                         pipeline_list->count), GFP_KERNEL);
        if (!trigger_list)
                return -ENOMEM;
  
@@@ -709,6 -708,9 +709,9 @@@ static int sof_ipc4_pcm_hw_params(struc
        struct snd_sof_pcm *spcm;
  
        spcm = snd_sof_find_spcm_dai(component, rtd);
+       if (!spcm)
+               return -EINVAL;
        time_info = spcm->stream[substream->stream].private;
        /* delay calculation is not supported by current fw_reg ABI */
        if (!time_info)