Merge tag 'asoc-v5.19' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie...
authorTakashi Iwai <tiwai@suse.de>
Mon, 23 May 2022 14:03:04 +0000 (16:03 +0200)
committerTakashi Iwai <tiwai@suse.de>
Mon, 23 May 2022 14:03:04 +0000 (16:03 +0200)
ASoC: Updates for v5.19

This is quite a big update, partly due to the addition of some larger
drivers (more of which is to follow since at least the AVS driver is
still a work in progress) and partly due to Charles' work sorting out
our handling of endianness.  As has been the case recently it's much
more about drivers than the core.

 - Overhaul of endianness specification for data formats, avoiding
   needless restrictions due to CODECs.
 - Initial stages of Intel AVS driver merge.
 - Introduction of v4 IPC mechanism for SOF.
 - TDM mode support for AK4613.
 - Support for Analog Devices ADAU1361, Cirrus Logic CS35L45, Maxim
   MAX98396, MediaTek MT8186, NXP i.MX8 micfil and SAI interfaces,
   nVidia Tegra186 ASRC, and Texas Instruments TAS2764 and TAS2780

1  2 
MAINTAINERS
include/sound/cs35l41.h
sound/soc/codecs/cs35l41-i2c.c
sound/soc/codecs/cs35l41-lib.c
sound/soc/codecs/cs35l41.c

diff --combined MAINTAINERS
@@@ -4688,10 -4688,12 +4688,12 @@@ CIRRUS LOGIC AUDIO CODEC DRIVER
  M:    James Schulman <james.schulman@cirrus.com>
  M:    David Rhodes <david.rhodes@cirrus.com>
  M:    Lucas Tanure <tanureal@opensource.cirrus.com>
+ M:    Richard Fitzgerald <rf@opensource.cirrus.com>
  L:    alsa-devel@alsa-project.org (moderated for non-subscribers)
  L:    patches@opensource.cirrus.com
  S:    Maintained
  F:    Documentation/devicetree/bindings/sound/cirrus,cs*
+ F:    include/dt-bindings/sound/cs*
  F:    sound/pci/hda/cs*
  F:    sound/soc/codecs/cs*
  
@@@ -4791,7 -4793,6 +4793,7 @@@ F:      .clang-forma
  CLANG/LLVM BUILD SUPPORT
  M:    Nathan Chancellor <nathan@kernel.org>
  M:    Nick Desaulniers <ndesaulniers@google.com>
 +R:    Tom Rix <trix@redhat.com>
  L:    llvm@lists.linux.dev
  S:    Supported
  W:    https://clangbuiltlinux.github.io/
@@@ -5716,7 -5717,7 +5718,7 @@@ W:      http://lanana.org/docs/device-list/i
  
  DEVICE RESOURCE MANAGEMENT HELPERS
  M:    Hans de Goede <hdegoede@redhat.com>
 -R:    Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
 +R:    Matti Vaittinen <mazziesaccount@gmail.com>
  S:    Maintained
  F:    include/linux/devm-helpers.h
  
@@@ -8676,6 -8677,7 +8678,6 @@@ F:      include/linux/cciss*.
  F:    include/uapi/linux/cciss*.h
  
  HFI1 DRIVER
 -M:    Mike Marciniszyn <mike.marciniszyn@cornelisnetworks.com>
  M:    Dennis Dalessandro <dennis.dalessandro@cornelisnetworks.com>
  L:    linux-rdma@vger.kernel.org
  S:    Supported
@@@ -9598,7 -9600,6 +9600,7 @@@ F:      drivers/iio/pressure/dps310.
  
  INFINIBAND SUBSYSTEM
  M:    Jason Gunthorpe <jgg@nvidia.com>
 +M:    Leon Romanovsky <leonro@nvidia.com>
  L:    linux-rdma@vger.kernel.org
  S:    Supported
  W:    https://github.com/linux-rdma/rdma-core
@@@ -11209,7 -11210,7 +11211,7 @@@ F:   scripts/spdxcheck.p
  
  LINEAR RANGES HELPERS
  M:    Mark Brown <broonie@kernel.org>
 -R:    Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
 +R:    Matti Vaittinen <mazziesaccount@gmail.com>
  F:    lib/linear_ranges.c
  F:    lib/test_linear_ranges.c
  F:    include/linux/linear_range.h
@@@ -14657,6 -14658,7 +14659,6 @@@ F:   drivers/rtc/rtc-optee.
  
  OPA-VNIC DRIVER
  M:    Dennis Dalessandro <dennis.dalessandro@cornelisnetworks.com>
 -M:    Mike Marciniszyn <mike.marciniszyn@cornelisnetworks.com>
  L:    linux-rdma@vger.kernel.org
  S:    Supported
  F:    drivers/infiniband/ulp/opa_vnic
@@@ -16098,6 -16100,7 +16100,6 @@@ F:   include/uapi/linux/qemu_fw_cfg.
  
  QIB DRIVER
  M:    Dennis Dalessandro <dennis.dalessandro@cornelisnetworks.com>
 -M:    Mike Marciniszyn <mike.marciniszyn@cornelisnetworks.com>
  L:    linux-rdma@vger.kernel.org
  S:    Supported
  F:    drivers/infiniband/hw/qib/
@@@ -16615,6 -16618,7 +16617,6 @@@ F:   drivers/net/ethernet/rdc/r6040.
  
  RDMAVT - RDMA verbs software
  M:    Dennis Dalessandro <dennis.dalessandro@cornelisnetworks.com>
 -M:    Mike Marciniszyn <mike.marciniszyn@cornelisnetworks.com>
  L:    linux-rdma@vger.kernel.org
  S:    Supported
  F:    drivers/infiniband/sw/rdmavt
@@@ -17009,7 -17013,8 +17011,7 @@@ S:   Odd Fixe
  F:    drivers/tty/serial/rp2.*
  
  ROHM BD99954 CHARGER IC
 -R:    Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
 -L:    linux-power@fi.rohmeurope.com
 +R:    Matti Vaittinen <mazziesaccount@gmail.com>
  S:    Supported
  F:    drivers/power/supply/bd99954-charger.c
  F:    drivers/power/supply/bd99954-charger.h
@@@ -17032,7 -17037,8 +17034,7 @@@ F:   drivers/regulator/bd9571mwv-regulato
  F:    include/linux/mfd/bd9571mwv.h
  
  ROHM POWER MANAGEMENT IC DEVICE DRIVERS
 -R:    Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
 -L:    linux-power@fi.rohmeurope.com
 +R:    Matti Vaittinen <mazziesaccount@gmail.com>
  S:    Supported
  F:    drivers/clk/clk-bd718x7.c
  F:    drivers/gpio/gpio-bd71815.c
@@@ -21114,7 -21120,7 +21116,7 @@@ F:   include/linux/regulator
  K:    regulator_get_optional
  
  VOLTAGE AND CURRENT REGULATOR IRQ HELPERS
 -R:    Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
 +R:    Matti Vaittinen <mazziesaccount@gmail.com>
  F:    drivers/regulator/irq_helpers.c
  
  VRF
diff --combined include/sound/cs35l41.h
@@@ -11,7 -11,6 +11,7 @@@
  #define __CS35L41_H
  
  #include <linux/regmap.h>
 +#include <linux/firmware/cirrus/cs_dsp.h>
  
  #define CS35L41_FIRSTREG              0x00000000
  #define CS35L41_LASTREG                       0x03804FE8
  
  #define CS35L41_MAX_CACHE_REG         36
  #define CS35L41_OTP_SIZE_WORDS                32
- #define CS35L41_NUM_OTP_ELEM          100
  
 -#define CS35L41_VALID_PDATA           0x80000000
  #define CS35L41_NUM_SUPPLIES            2
  
  #define CS35L41_SCLK_MSTR_MASK                0x10
  #define CS35L41_GLOBAL_EN_SHIFT               0
  #define CS35L41_BST_EN_MASK           0x0030
  #define CS35L41_BST_EN_SHIFT          4
 +#define CS35L41_BST_DIS_FET_OFF               0x00
  #define CS35L41_BST_EN_DEFAULT                0x2
  #define CS35L41_AMP_EN_SHIFT          0
  #define CS35L41_AMP_EN_MASK           1
  #define CS35L41_TEMP_WARN_ERR_RLS     0x20
  #define CS35L41_TEMP_ERR_RLS          0x40
  
 +#define CS35L41_AMP_SHORT_ERR_RLS_SHIFT       1
 +#define CS35L41_BST_SHORT_ERR_RLS_SHIFT       2
 +#define CS35L41_BST_OVP_ERR_RLS_SHIFT 3
 +#define CS35L41_BST_UVP_ERR_RLS_SHIFT 4
 +#define CS35L41_TEMP_WARN_ERR_RLS_SHIFT       5
 +#define CS35L41_TEMP_ERR_RLS_SHIFT    6
 +
  #define CS35L41_INT1_MASK_DEFAULT     0x7FFCFE3F
  #define CS35L41_INT1_UNMASK_PUP               0xFEFFFFFF
  #define CS35L41_INT1_UNMASK_PDN               0xFF7FFFFF
  #define CS35L41_GPIO1_CTRL_SHIFT      16
  #define CS35L41_GPIO2_CTRL_MASK               0x07000000
  #define CS35L41_GPIO2_CTRL_SHIFT      24
 -#define CS35L41_GPIO_CTRL_OPEN_INT    2
 -#define CS35L41_GPIO_CTRL_ACTV_LO     4
 -#define CS35L41_GPIO_CTRL_ACTV_HI     5
 +#define CS35L41_GPIO_LVL_SHIFT                15
 +#define CS35L41_GPIO_LVL_MASK         BIT(CS35L41_GPIO_LVL_SHIFT)
  #define CS35L41_GPIO_POL_MASK         0x1000
  #define CS35L41_GPIO_POL_SHIFT                12
  
  #define CS35L41_SPI_MAX_FREQ          4000000
  #define CS35L41_REGSTRIDE             4
  
 +enum cs35l41_boost_type {
 +      CS35L41_INT_BOOST,
 +      CS35L41_EXT_BOOST,
 +      CS35L41_EXT_BOOST_NO_VSPK_SWITCH,
 +};
 +
  enum cs35l41_clk_ids {
        CS35L41_CLKID_SCLK = 0,
        CS35L41_CLKID_LRCLK = 1,
        CS35L41_CLKID_MCLK = 4,
  };
  
 -struct cs35l41_irq_cfg {
 -      bool irq_pol_inv;
 -      bool irq_out_en;
 -      int irq_src_sel;
 +enum cs35l41_gpio1_func {
 +      CS35L41_GPIO1_HIZ,
 +      CS35L41_GPIO1_GPIO,
 +      CS35L41_GPIO1_MDSYNC,
 +      CS35L41_GPIO1_MCLK,
 +      CS35L41_GPIO1_PDM_CLK,
 +      CS35L41_GPIO1_PDM_DATA,
 +};
 +
 +enum cs35l41_gpio2_func {
 +      CS35L41_GPIO2_HIZ,
 +      CS35L41_GPIO2_GPIO,
 +      CS35L41_GPIO2_INT_OPEN_DRAIN,
 +      CS35L41_GPIO2_MCLK,
 +      CS35L41_GPIO2_INT_PUSH_PULL_LOW,
 +      CS35L41_GPIO2_INT_PUSH_PULL_HIGH,
 +      CS35L41_GPIO2_PDM_CLK,
 +      CS35L41_GPIO2_PDM_DATA,
  };
  
 -struct cs35l41_platform_data {
 +struct cs35l41_gpio_cfg {
 +      bool valid;
 +      bool pol_inv;
 +      bool out_en;
 +      unsigned int func;
 +};
 +
 +struct cs35l41_hw_cfg {
 +      bool valid;
        int bst_ind;
        int bst_ipk;
        int bst_cap;
        int dout_hiz;
 -      struct cs35l41_irq_cfg irq_config1;
 -      struct cs35l41_irq_cfg irq_config2;
 +      struct cs35l41_gpio_cfg gpio1;
 +      struct cs35l41_gpio_cfg gpio2;
 +      unsigned int spk_pos;
 +
 +      enum cs35l41_boost_type bst_type;
  };
  
  struct cs35l41_otp_packed_element_t {
@@@ -802,71 -763,6 +801,71 @@@ struct cs35l41_otp_map_element_t 
        u32 word_offset;
  };
  
 +enum cs35l41_cspl_mbox_status {
 +      CSPL_MBOX_STS_RUNNING = 0,
 +      CSPL_MBOX_STS_PAUSED = 1,
 +      CSPL_MBOX_STS_RDY_FOR_REINIT = 2,
 +};
 +
 +enum cs35l41_cspl_mbox_cmd {
 +      CSPL_MBOX_CMD_NONE = 0,
 +      CSPL_MBOX_CMD_PAUSE = 1,
 +      CSPL_MBOX_CMD_RESUME = 2,
 +      CSPL_MBOX_CMD_REINIT = 3,
 +      CSPL_MBOX_CMD_STOP_PRE_REINIT = 4,
 +      CSPL_MBOX_CMD_HIBERNATE = 5,
 +      CSPL_MBOX_CMD_OUT_OF_HIBERNATE = 6,
 +      CSPL_MBOX_CMD_UNKNOWN_CMD = -1,
 +      CSPL_MBOX_CMD_INVALID_SEQUENCE = -2,
 +};
 +
 +/*
 + * IRQs
 + */
 +#define CS35L41_IRQ(_irq, _name, _hand)               \
 +      {                                       \
 +              .irq = CS35L41_ ## _irq ## _IRQ,\
 +              .name = _name,                  \
 +              .handler = _hand,               \
 +      }
 +
 +struct cs35l41_irq {
 +      int irq;
 +      const char *name;
 +      irqreturn_t (*handler)(int irq, void *data);
 +};
 +
 +#define CS35L41_REG_IRQ(_reg, _irq)                                   \
 +      [CS35L41_ ## _irq ## _IRQ] = {                                  \
 +              .reg_offset = (CS35L41_ ## _reg) - CS35L41_IRQ1_STATUS1,\
 +              .mask = CS35L41_ ## _irq ## _MASK                       \
 +      }
 +
 +/* (0x0000E010) CS35L41_IRQ1_STATUS1 */
 +#define CS35L41_BST_OVP_ERR_SHIFT             6
 +#define CS35L41_BST_OVP_ERR_MASK              BIT(CS35L41_BST_OVP_ERR_SHIFT)
 +#define CS35L41_BST_DCM_UVP_ERR_SHIFT         7
 +#define CS35L41_BST_DCM_UVP_ERR_MASK          BIT(CS35L41_BST_DCM_UVP_ERR_SHIFT)
 +#define CS35L41_BST_SHORT_ERR_SHIFT           8
 +#define CS35L41_BST_SHORT_ERR_MASK            BIT(CS35L41_BST_SHORT_ERR_SHIFT)
 +#define CS35L41_TEMP_WARN_SHIFT                       15
 +#define CS35L41_TEMP_WARN_MASK                        BIT(CS35L41_TEMP_WARN_SHIFT)
 +#define CS35L41_TEMP_ERR_SHIFT                        17
 +#define CS35L41_TEMP_ERR_MASK                 BIT(CS35L41_TEMP_ERR_SHIFT)
 +#define CS35L41_AMP_SHORT_ERR_SHIFT           31
 +#define CS35L41_AMP_SHORT_ERR_MASK            BIT(CS35L41_AMP_SHORT_ERR_SHIFT)
 +
 +enum cs35l41_irq_list {
 +      CS35L41_BST_OVP_ERR_IRQ,
 +      CS35L41_BST_DCM_UVP_ERR_IRQ,
 +      CS35L41_BST_SHORT_ERR_IRQ,
 +      CS35L41_TEMP_WARN_IRQ,
 +      CS35L41_TEMP_ERR_IRQ,
 +      CS35L41_AMP_SHORT_ERR_IRQ,
 +
 +      CS35L41_NUM_IRQ
 +};
 +
  extern struct regmap_config cs35l41_regmap_i2c;
  extern struct regmap_config cs35l41_regmap_spi;
  
@@@ -877,14 -773,7 +876,14 @@@ int cs35l41_register_errata_patch(struc
  int cs35l41_set_channels(struct device *dev, struct regmap *reg,
                         unsigned int tx_num, unsigned int *tx_slot,
                         unsigned int rx_num, unsigned int *rx_slot);
 -int cs35l41_boost_config(struct device *dev, struct regmap *regmap, int boost_ind, int boost_cap,
 -                       int boost_ipk);
 +int cs35l41_gpio_config(struct regmap *regmap, struct cs35l41_hw_cfg *hw_cfg);
 +void cs35l41_configure_cs_dsp(struct device *dev, struct regmap *reg, struct cs_dsp *dsp);
 +int cs35l41_set_cspl_mbox_cmd(struct device *dev, struct regmap *regmap,
 +                            enum cs35l41_cspl_mbox_cmd cmd);
 +int cs35l41_write_fs_errata(struct device *dev, struct regmap *regmap);
 +int cs35l41_init_boost(struct device *dev, struct regmap *regmap,
 +                     struct cs35l41_hw_cfg *hw_cfg);
 +bool cs35l41_safe_reset(struct regmap *regmap, enum cs35l41_boost_type b_type);
 +int cs35l41_global_enable(struct regmap *regmap, enum cs35l41_boost_type b_type, int enable);
  
  #endif /* __CS35L41_H */
@@@ -29,12 -29,11 +29,11 @@@ static const struct i2c_device_id cs35l
  
  MODULE_DEVICE_TABLE(i2c, cs35l41_id_i2c);
  
- static int cs35l41_i2c_probe(struct i2c_client *client,
-                            const struct i2c_device_id *id)
+ static int cs35l41_i2c_probe(struct i2c_client *client)
  {
        struct cs35l41_private *cs35l41;
        struct device *dev = &client->dev;
 -      struct cs35l41_platform_data *pdata = dev_get_platdata(dev);
 +      struct cs35l41_hw_cfg *hw_cfg = dev_get_platdata(dev);
        const struct regmap_config *regmap_config = &cs35l41_regmap_i2c;
        int ret;
  
@@@ -54,7 -53,7 +53,7 @@@
                return ret;
        }
  
 -      return cs35l41_probe(cs35l41, pdata);
 +      return cs35l41_probe(cs35l41, hw_cfg);
  }
  
  static int cs35l41_i2c_remove(struct i2c_client *client)
@@@ -91,7 -90,7 +90,7 @@@ static struct i2c_driver cs35l41_i2c_dr
                .acpi_match_table = ACPI_PTR(cs35l41_acpi_match),
        },
        .id_table       = cs35l41_id_i2c,
-       .probe          = cs35l41_i2c_probe,
+       .probe_new      = cs35l41_i2c_probe,
        .remove         = cs35l41_i2c_remove,
  };
  
@@@ -12,7 -12,6 +12,7 @@@
  #include <linux/regmap.h>
  #include <linux/regulator/consumer.h>
  #include <linux/slab.h>
 +#include <linux/firmware/cirrus/wmfw.h>
  
  #include <sound/cs35l41.h>
  
@@@ -423,7 -422,7 +423,7 @@@ static bool cs35l41_volatile_reg(struc
        }
  }
  
- static const struct cs35l41_otp_packed_element_t otp_map_1[CS35L41_NUM_OTP_ELEM] = {
+ static const struct cs35l41_otp_packed_element_t otp_map_1[] = {
        /* addr         shift   size */
        { 0x00002030,   0,      4 }, /*TRIM_OSC_FREQ_TRIM*/
        { 0x00002030,   7,      1 }, /*TRIM_OSC_TRIM_DONE*/
        { 0x00017044,   0,      24 }, /*LOT_NUMBER*/
  };
  
- static const struct cs35l41_otp_packed_element_t otp_map_2[CS35L41_NUM_OTP_ELEM] = {
+ static const struct cs35l41_otp_packed_element_t otp_map_2[] = {
        /* addr         shift   size */
        { 0x00002030,   0,      4 }, /*TRIM_OSC_FREQ_TRIM*/
        { 0x00002030,   7,      1 }, /*TRIM_OSC_TRIM_DONE*/
@@@ -668,58 -667,39 +668,58 @@@ static const struct reg_sequence cs35l4
        { CS35L41_AMP_GAIN_CTRL,         0x00000000 },
  };
  
 +static const struct reg_sequence cs35l41_fs_errata_patch[] = {
 +      { CS35L41_DSP1_RX1_RATE,        0x00000001 },
 +      { CS35L41_DSP1_RX2_RATE,        0x00000001 },
 +      { CS35L41_DSP1_RX3_RATE,        0x00000001 },
 +      { CS35L41_DSP1_RX4_RATE,        0x00000001 },
 +      { CS35L41_DSP1_RX5_RATE,        0x00000001 },
 +      { CS35L41_DSP1_RX6_RATE,        0x00000001 },
 +      { CS35L41_DSP1_RX7_RATE,        0x00000001 },
 +      { CS35L41_DSP1_RX8_RATE,        0x00000001 },
 +      { CS35L41_DSP1_TX1_RATE,        0x00000001 },
 +      { CS35L41_DSP1_TX2_RATE,        0x00000001 },
 +      { CS35L41_DSP1_TX3_RATE,        0x00000001 },
 +      { CS35L41_DSP1_TX4_RATE,        0x00000001 },
 +      { CS35L41_DSP1_TX5_RATE,        0x00000001 },
 +      { CS35L41_DSP1_TX6_RATE,        0x00000001 },
 +      { CS35L41_DSP1_TX7_RATE,        0x00000001 },
 +      { CS35L41_DSP1_TX8_RATE,        0x00000001 },
 +};
 +
  static const struct cs35l41_otp_map_element_t cs35l41_otp_map_map[] = {
        {
                .id = 0x01,
                .map = otp_map_1,
-               .num_elements = CS35L41_NUM_OTP_ELEM,
+               .num_elements = ARRAY_SIZE(otp_map_1),
                .bit_offset = 16,
                .word_offset = 2,
        },
        {
                .id = 0x02,
                .map = otp_map_2,
-               .num_elements = CS35L41_NUM_OTP_ELEM,
+               .num_elements = ARRAY_SIZE(otp_map_2),
                .bit_offset = 16,
                .word_offset = 2,
        },
        {
                .id = 0x03,
                .map = otp_map_2,
-               .num_elements = CS35L41_NUM_OTP_ELEM,
+               .num_elements = ARRAY_SIZE(otp_map_2),
                .bit_offset = 16,
                .word_offset = 2,
        },
        {
                .id = 0x06,
                .map = otp_map_2,
-               .num_elements = CS35L41_NUM_OTP_ELEM,
+               .num_elements = ARRAY_SIZE(otp_map_2),
                .bit_offset = 16,
                .word_offset = 2,
        },
        {
                .id = 0x08,
                .map = otp_map_1,
-               .num_elements = CS35L41_NUM_OTP_ELEM,
+               .num_elements = ARRAY_SIZE(otp_map_1),
                .bit_offset = 16,
                .word_offset = 2,
        },
@@@ -842,7 -822,7 +842,7 @@@ int cs35l41_otp_unpack(struct device *d
        word_offset = otp_map_match->word_offset;
  
        for (i = 0; i < otp_map_match->num_elements; i++) {
-               dev_dbg(dev, "bitoffset= %d, word_offset=%d, bit_sum mod 32=%d otp_map[i].size = %d\n",
+               dev_dbg(dev, "bitoffset= %d, word_offset=%d, bit_sum mod 32=%d, otp_map[i].size = %u\n",
                        bit_offset, word_offset, bit_sum % 32, otp_map[i].size);
                if (bit_offset + otp_map[i].size - 1 >= 32) {
                        otp_val = (otp_mem[word_offset] &
@@@ -976,8 -956,9 +976,8 @@@ static const unsigned char cs35l41_bst_
        0x75, 0x6B, 0x3B, 0x28
  };
  
 -
 -int cs35l41_boost_config(struct device *dev, struct regmap *regmap, int boost_ind, int boost_cap,
 -                       int boost_ipk)
 +static int cs35l41_boost_config(struct device *dev, struct regmap *regmap, int boost_ind,
 +                              int boost_cap, int boost_ipk)
  {
        unsigned char bst_lbst_val, bst_cbst_range, bst_ipk_scaled;
        int ret;
        case 101 ... 200:
                bst_cbst_range = 3;
                break;
 -      default:        /* 201 uF and greater */
 +      default:
 +              if (boost_cap < 0) {
 +                      dev_err(dev, "Invalid boost capacitor value: %d nH\n", boost_cap);
 +                      return -EINVAL;
 +              }
 +              /* 201 uF and greater */
                bst_cbst_range = 4;
        }
  
 +      if (boost_ipk < 1600 || boost_ipk > 4500) {
 +              dev_err(dev, "Invalid boost inductor peak current: %d mA\n", boost_ipk);
 +              return -EINVAL;
 +      }
 +
        ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_COEFF,
                                 CS35L41_BST_K1_MASK | CS35L41_BST_K2_MASK,
                                 cs35l41_bst_k1_table[bst_lbst_val][bst_cbst_range]
                return ret;
        }
  
 -      if (boost_ipk < 1600 || boost_ipk > 4500) {
 -              dev_err(dev, "Invalid boost inductor peak current: %d mA\n", boost_ipk);
 -              return -EINVAL;
 -      }
        bst_ipk_scaled = ((boost_ipk - 1600) / 50) + 0x10;
  
        ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_PEAK_CUR, CS35L41_BST_IPK_MASK,
                return ret;
        }
  
 +      regmap_update_bits(regmap, CS35L41_PWR_CTRL2, CS35L41_BST_EN_MASK,
 +                         CS35L41_BST_EN_DEFAULT << CS35L41_BST_EN_SHIFT);
 +
        return 0;
  }
 -EXPORT_SYMBOL_GPL(cs35l41_boost_config);
 +
 +static const struct reg_sequence cs35l41_safe_to_reset[] = {
 +      { 0x00000040,                   0x00000055 },
 +      { 0x00000040,                   0x000000AA },
 +      { 0x0000393C,                   0x000000C0, 6000},
 +      { 0x0000393C,                   0x00000000 },
 +      { 0x00007414,                   0x00C82222 },
 +      { 0x0000742C,                   0x00000000 },
 +      { 0x00000040,                   0x000000CC },
 +      { 0x00000040,                   0x00000033 },
 +};
 +
 +static const struct reg_sequence cs35l41_active_to_safe[] = {
 +      { 0x00000040,                   0x00000055 },
 +      { 0x00000040,                   0x000000AA },
 +      { 0x00007438,                   0x00585941 },
 +      { CS35L41_PWR_CTRL1,            0x00000000 },
 +      { 0x0000742C,                   0x00000009, 3000 },
 +      { 0x00007438,                   0x00580941 },
 +      { 0x00000040,                   0x000000CC },
 +      { 0x00000040,                   0x00000033 },
 +};
 +
 +static const struct reg_sequence cs35l41_safe_to_active[] = {
 +      { 0x00000040,                   0x00000055 },
 +      { 0x00000040,                   0x000000AA },
 +      { 0x0000742C,                   0x0000000F },
 +      { 0x0000742C,                   0x00000079 },
 +      { 0x00007438,                   0x00585941 },
 +      { CS35L41_PWR_CTRL1,            0x00000001, 3000 }, // GLOBAL_EN = 1
 +      { 0x0000742C,                   0x000000F9 },
 +      { 0x00007438,                   0x00580941 },
 +      { 0x00000040,                   0x000000CC },
 +      { 0x00000040,                   0x00000033 },
 +};
 +
 +static const struct reg_sequence cs35l41_reset_to_safe[] = {
 +      { 0x00000040,                   0x00000055 },
 +      { 0x00000040,                   0x000000AA },
 +      { 0x00007438,                   0x00585941 },
 +      { 0x00007414,                   0x08C82222 },
 +      { 0x0000742C,                   0x00000009 },
 +      { 0x00000040,                   0x000000CC },
 +      { 0x00000040,                   0x00000033 },
 +};
 +
 +int cs35l41_init_boost(struct device *dev, struct regmap *regmap,
 +                     struct cs35l41_hw_cfg *hw_cfg)
 +{
 +      int ret;
 +
 +      switch (hw_cfg->bst_type) {
 +      case CS35L41_INT_BOOST:
 +              ret = cs35l41_boost_config(dev, regmap, hw_cfg->bst_ind,
 +                                         hw_cfg->bst_cap, hw_cfg->bst_ipk);
 +              if (ret)
 +                      dev_err(dev, "Error in Boost DT config: %d\n", ret);
 +              break;
 +      case CS35L41_EXT_BOOST:
 +      case CS35L41_EXT_BOOST_NO_VSPK_SWITCH:
 +              /* Only CLSA0100 doesn't use GPIO as VSPK switch, but even on that laptop we can
 +               * toggle GPIO1 as is not connected to anything.
 +               * There will be no other device without VSPK switch.
 +               */
 +              regmap_write(regmap, CS35L41_GPIO1_CTRL1, 0x00000001);
 +              regmap_multi_reg_write(regmap, cs35l41_reset_to_safe,
 +                                     ARRAY_SIZE(cs35l41_reset_to_safe));
 +              ret = regmap_update_bits(regmap, CS35L41_PWR_CTRL2, CS35L41_BST_EN_MASK,
 +                                       CS35L41_BST_DIS_FET_OFF << CS35L41_BST_EN_SHIFT);
 +              break;
 +      default:
 +              dev_err(dev, "Boost type %d not supported\n", hw_cfg->bst_type);
 +              ret = -EINVAL;
 +              break;
 +      }
 +
 +      return ret;
 +}
 +EXPORT_SYMBOL_GPL(cs35l41_init_boost);
 +
 +bool cs35l41_safe_reset(struct regmap *regmap, enum cs35l41_boost_type b_type)
 +{
 +      switch (b_type) {
 +      /* There is only one laptop that doesn't have VSPK switch. */
 +      case CS35L41_EXT_BOOST_NO_VSPK_SWITCH:
 +              return false;
 +      case CS35L41_EXT_BOOST:
 +              regmap_write(regmap, CS35L41_GPIO1_CTRL1, 0x00000001);
 +              regmap_multi_reg_write(regmap, cs35l41_safe_to_reset,
 +                                     ARRAY_SIZE(cs35l41_safe_to_reset));
 +              return true;
 +      default:
 +              return true;
 +      }
 +}
 +EXPORT_SYMBOL_GPL(cs35l41_safe_reset);
 +
 +int cs35l41_global_enable(struct regmap *regmap, enum cs35l41_boost_type b_type, int enable)
 +{
 +      int ret;
 +
 +      switch (b_type) {
 +      case CS35L41_INT_BOOST:
 +              ret = regmap_update_bits(regmap, CS35L41_PWR_CTRL1, CS35L41_GLOBAL_EN_MASK,
 +                                       enable << CS35L41_GLOBAL_EN_SHIFT);
 +              usleep_range(3000, 3100);
 +              break;
 +      case CS35L41_EXT_BOOST:
 +      case CS35L41_EXT_BOOST_NO_VSPK_SWITCH:
 +              if (enable)
 +                      ret = regmap_multi_reg_write(regmap, cs35l41_safe_to_active,
 +                                                   ARRAY_SIZE(cs35l41_safe_to_active));
 +              else
 +                      ret = regmap_multi_reg_write(regmap, cs35l41_active_to_safe,
 +                                                   ARRAY_SIZE(cs35l41_active_to_safe));
 +              break;
 +      default:
 +              ret = -EINVAL;
 +              break;
 +      }
 +
 +      return ret;
 +}
 +EXPORT_SYMBOL_GPL(cs35l41_global_enable);
 +
 +int cs35l41_gpio_config(struct regmap *regmap, struct cs35l41_hw_cfg *hw_cfg)
 +{
 +      struct cs35l41_gpio_cfg *gpio1 = &hw_cfg->gpio1;
 +      struct cs35l41_gpio_cfg *gpio2 = &hw_cfg->gpio2;
 +      int irq_pol = IRQF_TRIGGER_NONE;
 +
 +      regmap_update_bits(regmap, CS35L41_GPIO1_CTRL1,
 +                         CS35L41_GPIO_POL_MASK | CS35L41_GPIO_DIR_MASK,
 +                         gpio1->pol_inv << CS35L41_GPIO_POL_SHIFT |
 +                         !gpio1->out_en << CS35L41_GPIO_DIR_SHIFT);
 +
 +      regmap_update_bits(regmap, CS35L41_GPIO2_CTRL1,
 +                         CS35L41_GPIO_POL_MASK | CS35L41_GPIO_DIR_MASK,
 +                         gpio2->pol_inv << CS35L41_GPIO_POL_SHIFT |
 +                         !gpio2->out_en << CS35L41_GPIO_DIR_SHIFT);
 +
 +      if (gpio1->valid)
 +              regmap_update_bits(regmap, CS35L41_GPIO_PAD_CONTROL, CS35L41_GPIO1_CTRL_MASK,
 +                                 gpio1->func << CS35L41_GPIO1_CTRL_SHIFT);
 +
 +      if (gpio2->valid) {
 +              regmap_update_bits(regmap, CS35L41_GPIO_PAD_CONTROL, CS35L41_GPIO2_CTRL_MASK,
 +                                 gpio2->func << CS35L41_GPIO2_CTRL_SHIFT);
 +
 +              switch (gpio2->func) {
 +              case CS35L41_GPIO2_INT_PUSH_PULL_LOW:
 +              case CS35L41_GPIO2_INT_OPEN_DRAIN:
 +                      irq_pol = IRQF_TRIGGER_LOW;
 +                      break;
 +              case CS35L41_GPIO2_INT_PUSH_PULL_HIGH:
 +                      irq_pol = IRQF_TRIGGER_HIGH;
 +                      break;
 +              default:
 +                      break;
 +              }
 +      }
 +
 +      return irq_pol;
 +}
 +EXPORT_SYMBOL_GPL(cs35l41_gpio_config);
 +
 +static const struct cs_dsp_region cs35l41_dsp1_regions[] = {
 +      { .type = WMFW_HALO_PM_PACKED,  .base = CS35L41_DSP1_PMEM_0 },
 +      { .type = WMFW_HALO_XM_PACKED,  .base = CS35L41_DSP1_XMEM_PACK_0 },
 +      { .type = WMFW_HALO_YM_PACKED,  .base = CS35L41_DSP1_YMEM_PACK_0 },
 +      {. type = WMFW_ADSP2_XM,        .base = CS35L41_DSP1_XMEM_UNPACK24_0},
 +      {. type = WMFW_ADSP2_YM,        .base = CS35L41_DSP1_YMEM_UNPACK24_0},
 +};
 +
 +void cs35l41_configure_cs_dsp(struct device *dev, struct regmap *reg, struct cs_dsp *dsp)
 +{
 +      dsp->num = 1;
 +      dsp->type = WMFW_HALO;
 +      dsp->rev = 0;
 +      dsp->dev = dev;
 +      dsp->regmap = reg;
 +      dsp->base = CS35L41_DSP1_CTRL_BASE;
 +      dsp->base_sysinfo = CS35L41_DSP1_SYS_ID;
 +      dsp->mem = cs35l41_dsp1_regions;
 +      dsp->num_mems = ARRAY_SIZE(cs35l41_dsp1_regions);
 +      dsp->lock_regions = 0xFFFFFFFF;
 +}
 +EXPORT_SYMBOL_GPL(cs35l41_configure_cs_dsp);
 +
 +static bool cs35l41_check_cspl_mbox_sts(enum cs35l41_cspl_mbox_cmd cmd,
 +                                      enum cs35l41_cspl_mbox_status sts)
 +{
 +      switch (cmd) {
 +      case CSPL_MBOX_CMD_NONE:
 +      case CSPL_MBOX_CMD_UNKNOWN_CMD:
 +              return true;
 +      case CSPL_MBOX_CMD_PAUSE:
 +      case CSPL_MBOX_CMD_OUT_OF_HIBERNATE:
 +              return (sts == CSPL_MBOX_STS_PAUSED);
 +      case CSPL_MBOX_CMD_RESUME:
 +              return (sts == CSPL_MBOX_STS_RUNNING);
 +      case CSPL_MBOX_CMD_REINIT:
 +              return (sts == CSPL_MBOX_STS_RUNNING);
 +      case CSPL_MBOX_CMD_STOP_PRE_REINIT:
 +              return (sts == CSPL_MBOX_STS_RDY_FOR_REINIT);
 +      default:
 +              return false;
 +      }
 +}
 +
 +int cs35l41_set_cspl_mbox_cmd(struct device *dev, struct regmap *regmap,
 +                            enum cs35l41_cspl_mbox_cmd cmd)
 +{
 +      unsigned int sts = 0, i;
 +      int ret;
 +
 +      // Set mailbox cmd
 +      ret = regmap_write(regmap, CS35L41_DSP_VIRT1_MBOX_1, cmd);
 +      if (ret < 0) {
 +              if (cmd != CSPL_MBOX_CMD_OUT_OF_HIBERNATE)
 +                      dev_err(dev, "Failed to write MBOX: %d\n", ret);
 +              return ret;
 +      }
 +
 +      // Read mailbox status and verify it is appropriate for the given cmd
 +      for (i = 0; i < 5; i++) {
 +              usleep_range(1000, 1100);
 +
 +              ret = regmap_read(regmap, CS35L41_DSP_MBOX_2, &sts);
 +              if (ret < 0) {
 +                      dev_err(dev, "Failed to read MBOX STS: %d\n", ret);
 +                      continue;
 +              }
 +
 +              if (!cs35l41_check_cspl_mbox_sts(cmd, sts))
 +                      dev_dbg(dev, "[%u] cmd %u returned invalid sts %u", i, cmd, sts);
 +              else
 +                      return 0;
 +      }
 +
 +      dev_err(dev, "Failed to set mailbox cmd %u (status %u)\n", cmd, sts);
 +
 +      return -ENOMSG;
 +}
 +EXPORT_SYMBOL_GPL(cs35l41_set_cspl_mbox_cmd);
 +
 +int cs35l41_write_fs_errata(struct device *dev, struct regmap *regmap)
 +{
 +      int ret;
 +
 +      ret = regmap_multi_reg_write(regmap, cs35l41_fs_errata_patch,
 +                                   ARRAY_SIZE(cs35l41_fs_errata_patch));
 +      if (ret < 0)
 +              dev_err(dev, "Failed to write fs errata: %d\n", ret);
 +
 +      return ret;
 +}
 +EXPORT_SYMBOL_GPL(cs35l41_write_fs_errata);
  
  MODULE_DESCRIPTION("CS35L41 library");
  MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, <david.rhodes@cirrus.com>");
@@@ -208,6 -208,67 +208,6 @@@ static int cs35l41_dsp_preload_ev(struc
        }
  }
  
 -static bool cs35l41_check_cspl_mbox_sts(enum cs35l41_cspl_mbox_cmd cmd,
 -                                      enum cs35l41_cspl_mbox_status sts)
 -{
 -      switch (cmd) {
 -      case CSPL_MBOX_CMD_NONE:
 -      case CSPL_MBOX_CMD_UNKNOWN_CMD:
 -              return true;
 -      case CSPL_MBOX_CMD_PAUSE:
 -      case CSPL_MBOX_CMD_OUT_OF_HIBERNATE:
 -              return (sts == CSPL_MBOX_STS_PAUSED);
 -      case CSPL_MBOX_CMD_RESUME:
 -              return (sts == CSPL_MBOX_STS_RUNNING);
 -      case CSPL_MBOX_CMD_REINIT:
 -              return (sts == CSPL_MBOX_STS_RUNNING);
 -      case CSPL_MBOX_CMD_STOP_PRE_REINIT:
 -              return (sts == CSPL_MBOX_STS_RDY_FOR_REINIT);
 -      default:
 -              return false;
 -      }
 -}
 -
 -static int cs35l41_set_cspl_mbox_cmd(struct cs35l41_private *cs35l41,
 -                                   enum cs35l41_cspl_mbox_cmd cmd)
 -{
 -      unsigned int sts = 0, i;
 -      int ret;
 -
 -      // Set mailbox cmd
 -      ret = regmap_write(cs35l41->regmap, CS35L41_DSP_VIRT1_MBOX_1, cmd);
 -      if (ret < 0) {
 -              if (cmd != CSPL_MBOX_CMD_OUT_OF_HIBERNATE)
 -                      dev_err(cs35l41->dev, "Failed to write MBOX: %d\n", ret);
 -              return ret;
 -      }
 -
 -      // Read mailbox status and verify it is appropriate for the given cmd
 -      for (i = 0; i < 5; i++) {
 -              usleep_range(1000, 1100);
 -
 -              ret = regmap_read(cs35l41->regmap, CS35L41_DSP_MBOX_2, &sts);
 -              if (ret < 0) {
 -                      dev_err(cs35l41->dev, "Failed to read MBOX STS: %d\n", ret);
 -                      continue;
 -              }
 -
 -              if (!cs35l41_check_cspl_mbox_sts(cmd, sts)) {
 -                      dev_dbg(cs35l41->dev,
 -                              "[%u] cmd %u returned invalid sts %u",
 -                              i, cmd, sts);
 -              } else {
 -                      return 0;
 -              }
 -      }
 -
 -      dev_err(cs35l41->dev,
 -              "Failed to set mailbox cmd %u (status %u)\n",
 -              cmd, sts);
 -
 -      return -ENOMSG;
 -}
 -
  static int cs35l41_dsp_audio_ev(struct snd_soc_dapm_widget *w,
                                struct snd_kcontrol *kcontrol, int event)
  {
                        return -EINVAL;
                }
  
 -              return cs35l41_set_cspl_mbox_cmd(cs35l41, CSPL_MBOX_CMD_RESUME);
 +              return cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap,
 +                                               CSPL_MBOX_CMD_RESUME);
        case SND_SOC_DAPM_PRE_PMD:
 -              return cs35l41_set_cspl_mbox_cmd(cs35l41, CSPL_MBOX_CMD_PAUSE);
 +              return cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap,
 +                                               CSPL_MBOX_CMD_PAUSE);
        default:
                return 0;
        }
@@@ -519,10 -578,15 +519,10 @@@ static int cs35l41_main_amp_event(struc
                                                cs35l41_pup_patch,
                                                ARRAY_SIZE(cs35l41_pup_patch));
  
 -              regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL1,
 -                                 CS35L41_GLOBAL_EN_MASK,
 -                                 1 << CS35L41_GLOBAL_EN_SHIFT);
 -
 -              usleep_range(1000, 1100);
 +              cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 1);
                break;
        case SND_SOC_DAPM_POST_PMD:
 -              regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL1,
 -                                 CS35L41_GLOBAL_EN_MASK, 0);
 +              cs35l41_global_enable(cs35l41->regmap, cs35l41->hw_cfg.bst_type, 0);
  
                ret = regmap_read_poll_timeout(cs35l41->regmap, CS35L41_IRQ1_STATUS1,
                                               val, val &  CS35L41_PDN_DONE_MASK,
@@@ -680,6 -744,14 +680,6 @@@ static const struct snd_soc_dapm_route 
        {"CLASS H", NULL, "PCM Source"},
  };
  
 -static const struct cs_dsp_region cs35l41_dsp1_regions[] = {
 -      { .type = WMFW_HALO_PM_PACKED,  .base = CS35L41_DSP1_PMEM_0 },
 -      { .type = WMFW_HALO_XM_PACKED,  .base = CS35L41_DSP1_XMEM_PACK_0 },
 -      { .type = WMFW_HALO_YM_PACKED,  .base = CS35L41_DSP1_YMEM_PACK_0 },
 -      {. type = WMFW_ADSP2_XM,        .base = CS35L41_DSP1_XMEM_UNPACK24_0},
 -      {. type = WMFW_ADSP2_YM,        .base = CS35L41_DSP1_YMEM_UNPACK24_0},
 -};
 -
  static int cs35l41_set_channel_map(struct snd_soc_dai *dai, unsigned int tx_n,
                                   unsigned int *tx_slot, unsigned int rx_n, unsigned int *rx_slot)
  {
@@@ -923,53 -995,69 +923,53 @@@ static int cs35l41_dai_set_sysclk(struc
  
  static int cs35l41_set_pdata(struct cs35l41_private *cs35l41)
  {
 +      struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
        int ret;
  
 -      /* Set Platform Data */
 -      /* Required */
 -      if (cs35l41->pdata.bst_ipk &&
 -          cs35l41->pdata.bst_ind && cs35l41->pdata.bst_cap) {
 -              ret = cs35l41_boost_config(cs35l41->dev, cs35l41->regmap, cs35l41->pdata.bst_ind,
 -                                         cs35l41->pdata.bst_cap, cs35l41->pdata.bst_ipk);
 -              if (ret) {
 -                      dev_err(cs35l41->dev, "Error in Boost DT config: %d\n", ret);
 -                      return ret;
 -              }
 -      } else {
 -              dev_err(cs35l41->dev, "Incomplete Boost component DT config\n");
 +      if (!hw_cfg->valid)
 +              return -EINVAL;
 +
 +      if (hw_cfg->bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH)
                return -EINVAL;
 -      }
 +
 +      /* Required */
 +      ret = cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, hw_cfg);
 +      if (ret)
 +              return ret;
  
        /* Optional */
 -      if (cs35l41->pdata.dout_hiz <= CS35L41_ASP_DOUT_HIZ_MASK &&
 -          cs35l41->pdata.dout_hiz >= 0)
 -              regmap_update_bits(cs35l41->regmap, CS35L41_SP_HIZ_CTRL,
 -                                 CS35L41_ASP_DOUT_HIZ_MASK,
 -                                 cs35l41->pdata.dout_hiz);
 +      if (hw_cfg->dout_hiz <= CS35L41_ASP_DOUT_HIZ_MASK && hw_cfg->dout_hiz >= 0)
 +              regmap_update_bits(cs35l41->regmap, CS35L41_SP_HIZ_CTRL, CS35L41_ASP_DOUT_HIZ_MASK,
 +                                 hw_cfg->dout_hiz);
  
        return 0;
  }
  
 -static int cs35l41_irq_gpio_config(struct cs35l41_private *cs35l41)
 -{
 -      struct cs35l41_irq_cfg *irq_gpio_cfg1 = &cs35l41->pdata.irq_config1;
 -      struct cs35l41_irq_cfg *irq_gpio_cfg2 = &cs35l41->pdata.irq_config2;
 -      int irq_pol = IRQF_TRIGGER_NONE;
 -
 -      regmap_update_bits(cs35l41->regmap, CS35L41_GPIO1_CTRL1,
 -                         CS35L41_GPIO_POL_MASK | CS35L41_GPIO_DIR_MASK,
 -                         irq_gpio_cfg1->irq_pol_inv << CS35L41_GPIO_POL_SHIFT |
 -                         !irq_gpio_cfg1->irq_out_en << CS35L41_GPIO_DIR_SHIFT);
 -
 -      regmap_update_bits(cs35l41->regmap, CS35L41_GPIO2_CTRL1,
 -                         CS35L41_GPIO_POL_MASK | CS35L41_GPIO_DIR_MASK,
 -                         irq_gpio_cfg2->irq_pol_inv << CS35L41_GPIO_POL_SHIFT |
 -                         !irq_gpio_cfg2->irq_out_en << CS35L41_GPIO_DIR_SHIFT);
 -
 -      regmap_update_bits(cs35l41->regmap, CS35L41_GPIO_PAD_CONTROL,
 -                         CS35L41_GPIO1_CTRL_MASK | CS35L41_GPIO2_CTRL_MASK,
 -                         irq_gpio_cfg1->irq_src_sel << CS35L41_GPIO1_CTRL_SHIFT |
 -                         irq_gpio_cfg2->irq_src_sel << CS35L41_GPIO2_CTRL_SHIFT);
 -
 -      if ((irq_gpio_cfg2->irq_src_sel ==
 -                      (CS35L41_GPIO_CTRL_ACTV_LO | CS35L41_VALID_PDATA)) ||
 -              (irq_gpio_cfg2->irq_src_sel ==
 -                      (CS35L41_GPIO_CTRL_OPEN_INT | CS35L41_VALID_PDATA)))
 -              irq_pol = IRQF_TRIGGER_LOW;
 -      else if (irq_gpio_cfg2->irq_src_sel ==
 -                      (CS35L41_GPIO_CTRL_ACTV_HI | CS35L41_VALID_PDATA))
 -              irq_pol = IRQF_TRIGGER_HIGH;
 -
 -      return irq_pol;
 -}
 +static const struct snd_soc_dapm_route cs35l41_ext_bst_routes[] = {
 +      {"Main AMP", NULL, "VSPK"},
 +};
 +
 +static const struct snd_soc_dapm_widget cs35l41_ext_bst_widget[] = {
 +      SND_SOC_DAPM_SUPPLY("VSPK", CS35L41_GPIO1_CTRL1, CS35L41_GPIO_LVL_SHIFT, 0, NULL, 0),
 +};
  
  static int cs35l41_component_probe(struct snd_soc_component *component)
  {
        struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(component);
 +      struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
 +      int ret;
 +
 +      if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST) {
 +              ret = snd_soc_dapm_new_controls(dapm, cs35l41_ext_bst_widget,
 +                                              ARRAY_SIZE(cs35l41_ext_bst_widget));
 +              if (ret)
 +                      return ret;
 +
 +              ret = snd_soc_dapm_add_routes(dapm, cs35l41_ext_bst_routes,
 +                                            ARRAY_SIZE(cs35l41_ext_bst_routes));
 +              if (ret)
 +                      return ret;
 +      }
  
        return wm_adsp2_component_probe(&cs35l41->dsp, component);
  }
@@@ -1025,66 -1113,77 +1025,68 @@@ static const struct snd_soc_component_d
        .controls = cs35l41_aud_controls,
        .num_controls = ARRAY_SIZE(cs35l41_aud_controls),
        .set_sysclk = cs35l41_component_set_sysclk,
+       .endianness = 1,
  };
  
 -static int cs35l41_handle_pdata(struct device *dev, struct cs35l41_platform_data *pdata)
 +static int cs35l41_handle_pdata(struct device *dev, struct cs35l41_hw_cfg *hw_cfg)
  {
 -      struct cs35l41_irq_cfg *irq_gpio1_config = &pdata->irq_config1;
 -      struct cs35l41_irq_cfg *irq_gpio2_config = &pdata->irq_config2;
 +      struct cs35l41_gpio_cfg *gpio1 = &hw_cfg->gpio1;
 +      struct cs35l41_gpio_cfg *gpio2 = &hw_cfg->gpio2;
        unsigned int val;
        int ret;
  
 +      ret = device_property_read_u32(dev, "cirrus,boost-type", &val);
 +      if (ret >= 0)
 +              hw_cfg->bst_type = val;
 +
        ret = device_property_read_u32(dev, "cirrus,boost-peak-milliamp", &val);
        if (ret >= 0)
 -              pdata->bst_ipk = val;
 +              hw_cfg->bst_ipk = val;
 +      else
 +              hw_cfg->bst_ipk = -1;
  
        ret = device_property_read_u32(dev, "cirrus,boost-ind-nanohenry", &val);
        if (ret >= 0)
 -              pdata->bst_ind = val;
 +              hw_cfg->bst_ind = val;
 +      else
 +              hw_cfg->bst_ind = -1;
  
        ret = device_property_read_u32(dev, "cirrus,boost-cap-microfarad", &val);
        if (ret >= 0)
 -              pdata->bst_cap = val;
 +              hw_cfg->bst_cap = val;
 +      else
 +              hw_cfg->bst_cap = -1;
  
        ret = device_property_read_u32(dev, "cirrus,asp-sdout-hiz", &val);
        if (ret >= 0)
 -              pdata->dout_hiz = val;
 +              hw_cfg->dout_hiz = val;
        else
 -              pdata->dout_hiz = -1;
 +              hw_cfg->dout_hiz = -1;
  
        /* GPIO1 Pin Config */
 -      irq_gpio1_config->irq_pol_inv = device_property_read_bool(dev,
 -                                      "cirrus,gpio1-polarity-invert");
 -      irq_gpio1_config->irq_out_en = device_property_read_bool(dev,
 -                                      "cirrus,gpio1-output-enable");
 -      ret = device_property_read_u32(dev, "cirrus,gpio1-src-select",
 -                                     &val);
 -      if (ret >= 0)
 -              irq_gpio1_config->irq_src_sel = val | CS35L41_VALID_PDATA;
 +      gpio1->pol_inv = device_property_read_bool(dev, "cirrus,gpio1-polarity-invert");
 +      gpio1->out_en = device_property_read_bool(dev, "cirrus,gpio1-output-enable");
 +      ret = device_property_read_u32(dev, "cirrus,gpio1-src-select", &val);
 +      if (ret >= 0) {
 +              gpio1->func = val;
 +              gpio1->valid = true;
 +      }
  
        /* GPIO2 Pin Config */
 -      irq_gpio2_config->irq_pol_inv = device_property_read_bool(dev,
 -                                      "cirrus,gpio2-polarity-invert");
 -      irq_gpio2_config->irq_out_en = device_property_read_bool(dev,
 -                                      "cirrus,gpio2-output-enable");
 -      ret = device_property_read_u32(dev, "cirrus,gpio2-src-select",
 -                                     &val);
 -      if (ret >= 0)
 -              irq_gpio2_config->irq_src_sel = val | CS35L41_VALID_PDATA;
 +      gpio2->pol_inv = device_property_read_bool(dev, "cirrus,gpio2-polarity-invert");
 +      gpio2->out_en = device_property_read_bool(dev, "cirrus,gpio2-output-enable");
 +      ret = device_property_read_u32(dev, "cirrus,gpio2-src-select", &val);
 +      if (ret >= 0) {
 +              gpio2->func = val;
 +              gpio2->valid = true;
 +      }
 +
 +      hw_cfg->valid = true;
  
        return 0;
  }
  
 -static const struct reg_sequence cs35l41_fs_errata_patch[] = {
 -      { CS35L41_DSP1_RX1_RATE,        0x00000001 },
 -      { CS35L41_DSP1_RX2_RATE,        0x00000001 },
 -      { CS35L41_DSP1_RX3_RATE,        0x00000001 },
 -      { CS35L41_DSP1_RX4_RATE,        0x00000001 },
 -      { CS35L41_DSP1_RX5_RATE,        0x00000001 },
 -      { CS35L41_DSP1_RX6_RATE,        0x00000001 },
 -      { CS35L41_DSP1_RX7_RATE,        0x00000001 },
 -      { CS35L41_DSP1_RX8_RATE,        0x00000001 },
 -      { CS35L41_DSP1_TX1_RATE,        0x00000001 },
 -      { CS35L41_DSP1_TX2_RATE,        0x00000001 },
 -      { CS35L41_DSP1_TX3_RATE,        0x00000001 },
 -      { CS35L41_DSP1_TX4_RATE,        0x00000001 },
 -      { CS35L41_DSP1_TX5_RATE,        0x00000001 },
 -      { CS35L41_DSP1_TX6_RATE,        0x00000001 },
 -      { CS35L41_DSP1_TX7_RATE,        0x00000001 },
 -      { CS35L41_DSP1_TX8_RATE,        0x00000001 },
 -};
 -
  static int cs35l41_dsp_init(struct cs35l41_private *cs35l41)
  {
        struct wm_adsp *dsp;
  
        dsp = &cs35l41->dsp;
        dsp->part = "cs35l41";
 -      dsp->cs_dsp.num = 1;
 -      dsp->cs_dsp.type = WMFW_HALO;
 -      dsp->cs_dsp.rev = 0;
        dsp->fw = 9; /* 9 is WM_ADSP_FW_SPK_PROT in wm_adsp.c */
        dsp->toggle_preload = true;
 -      dsp->cs_dsp.dev = cs35l41->dev;
 -      dsp->cs_dsp.regmap = cs35l41->regmap;
 -      dsp->cs_dsp.base = CS35L41_DSP1_CTRL_BASE;
 -      dsp->cs_dsp.base_sysinfo = CS35L41_DSP1_SYS_ID;
 -      dsp->cs_dsp.mem = cs35l41_dsp1_regions;
 -      dsp->cs_dsp.num_mems = ARRAY_SIZE(cs35l41_dsp1_regions);
 -      dsp->cs_dsp.lock_regions = 0xFFFFFFFF;
 -
 -      ret = regmap_multi_reg_write(cs35l41->regmap, cs35l41_fs_errata_patch,
 -                                   ARRAY_SIZE(cs35l41_fs_errata_patch));
 -      if (ret < 0) {
 -              dev_err(cs35l41->dev, "Failed to write fs errata: %d\n", ret);
 +
 +      cs35l41_configure_cs_dsp(cs35l41->dev, cs35l41->regmap, &dsp->cs_dsp);
 +
 +      ret = cs35l41_write_fs_errata(cs35l41->dev, cs35l41->regmap);
 +      if (ret < 0)
                return ret;
 -      }
  
        ret = wm_halo_init(dsp);
        if (ret) {
@@@ -1140,16 -1250,17 +1142,16 @@@ err_dsp
        return ret;
  }
  
 -int cs35l41_probe(struct cs35l41_private *cs35l41,
 -                struct cs35l41_platform_data *pdata)
 +int cs35l41_probe(struct cs35l41_private *cs35l41, const struct cs35l41_hw_cfg *hw_cfg)
  {
        u32 regid, reg_revid, i, mtl_revid, int_status, chipid_match;
        int irq_pol = 0;
        int ret;
  
 -      if (pdata) {
 -              cs35l41->pdata = *pdata;
 +      if (hw_cfg) {
 +              cs35l41->hw_cfg = *hw_cfg;
        } else {
 -              ret = cs35l41_handle_pdata(cs35l41->dev, &cs35l41->pdata);
 +              ret = cs35l41_handle_pdata(cs35l41->dev, &cs35l41->hw_cfg);
                if (ret != 0)
                        return ret;
        }
  
        cs35l41_test_key_lock(cs35l41->dev, cs35l41->regmap);
  
 -      irq_pol = cs35l41_irq_gpio_config(cs35l41);
 +      irq_pol = cs35l41_gpio_config(cs35l41->regmap, &cs35l41->hw_cfg);
  
        /* Set interrupt masks for critical errors */
        regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1,
@@@ -1300,7 -1411,6 +1302,7 @@@ err_pm
  
        wm_adsp2_remove(&cs35l41->dsp);
  err:
 +      cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type);
        regulator_bulk_disable(CS35L41_NUM_SUPPLIES, cs35l41->supplies);
        gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
  
@@@ -1315,7 -1425,6 +1317,7 @@@ void cs35l41_remove(struct cs35l41_priv
  
        regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, 0xFFFFFFFF);
        wm_adsp2_remove(&cs35l41->dsp);
 +      cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type);
  
        pm_runtime_put_noidle(cs35l41->dev);
  
@@@ -1335,7 -1444,6 +1337,7 @@@ static int __maybe_unused cs35l41_runti
  
        dev_dbg(cs35l41->dev, "Enter hibernate\n");
  
 +      cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type);
        regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0088);
        regmap_write(cs35l41->regmap, CS35L41_WAKESRC_CTL, 0x0188);
  
@@@ -1378,7 -1486,7 +1380,7 @@@ static int cs35l41_exit_hibernate(struc
                dev_dbg(cs35l41->dev, "Exit hibernate\n");
  
                for (j = 0; j < wake_retries; j++) {
 -                      ret = cs35l41_set_cspl_mbox_cmd(cs35l41,
 +                      ret = cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap,
                                                        CSPL_MBOX_CMD_OUT_OF_HIBERNATE);
                        if (!ret)
                                break;
@@@ -1432,7 -1540,6 +1434,7 @@@ static int __maybe_unused cs35l41_runti
                dev_err(cs35l41->dev, "Failed to restore register cache: %d\n", ret);
                return ret;
        }
 +      cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, &cs35l41->hw_cfg);
  
        return 0;
  }