]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
mfd: cs42l43: Add support for the B variant
authorMaciej Strozek <mstrozek@opensource.cirrus.com>
Fri, 6 Mar 2026 15:28:10 +0000 (15:28 +0000)
committerMark Brown <broonie@kernel.org>
Mon, 9 Mar 2026 10:29:32 +0000 (10:29 +0000)
Introducing CS42L43B codec, a variant of CS42L43 which can be driven by
the same driver.

Changes in CS42L43 driver specific for CS42L43B:
- Decimator 1 and 2 are dedicated to ADC, can't be selected for PDM
- Decimators 3 and 4 are connected to PDM1
- Added Decimator 5 and 6 for PDM2
- Supports SoundWire Clock Gearing
- Updated ROM requiring no patching
- Reduced RAM space
- Each ISRC has 4 decimators now

Signed-off-by: Maciej Strozek <mstrozek@opensource.cirrus.com>
Acked-by: Lee Jones <lee@kernel.org>
Reviewed-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Link: https://patch.msgid.link/20260306152829.3130530-4-mstrozek@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/mfd/cs42l43-i2c.c
drivers/mfd/cs42l43-sdw.c
drivers/mfd/cs42l43.c
drivers/mfd/cs42l43.h
include/linux/mfd/cs42l43-regs.h
include/linux/mfd/cs42l43.h

index a2ab001a600aefe5f079df9d3bc0b5b98259e6ce..0a0ab5e549a5a2f65619e074a398ab6ab542725b 100644 (file)
@@ -47,6 +47,7 @@ static int cs42l43_i2c_probe(struct i2c_client *i2c)
        cs42l43->irq = i2c->irq;
        /* A device on an I2C is always attached by definition. */
        cs42l43->attached = true;
+       cs42l43->variant_id = (long)device_get_match_data(cs42l43->dev);
 
        cs42l43->regmap = devm_regmap_init_i2c(i2c, &cs42l43_i2c_regmap);
        if (IS_ERR(cs42l43->regmap))
@@ -58,7 +59,8 @@ static int cs42l43_i2c_probe(struct i2c_client *i2c)
 
 #if IS_ENABLED(CONFIG_OF)
 static const struct of_device_id cs42l43_of_match[] = {
-       { .compatible = "cirrus,cs42l43", },
+       { .compatible = "cirrus,cs42l43", .data = (void *)CS42L43_DEVID_VAL },
+       { .compatible = "cirrus,cs42l43b", .data = (void *)CS42L43B_DEVID_VAL },
        {}
 };
 MODULE_DEVICE_TABLE(of, cs42l43_of_match);
@@ -66,7 +68,8 @@ MODULE_DEVICE_TABLE(of, cs42l43_of_match);
 
 #if IS_ENABLED(CONFIG_ACPI)
 static const struct acpi_device_id cs42l43_acpi_match[] = {
-       { "CSC4243", 0 },
+       { "CSC4243", CS42L43_DEVID_VAL },
+       { "CSC2A3B", CS42L43B_DEVID_VAL },
        {}
 };
 MODULE_DEVICE_TABLE(acpi, cs42l43_acpi_match);
index 023f7e1a30f8c74a14471713d1aebe44adf5b036..794c983781750c40818e7c7b311d093040fc1b56 100644 (file)
@@ -178,6 +178,7 @@ static int cs42l43_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *
 
        cs42l43->dev = dev;
        cs42l43->sdw = sdw;
+       cs42l43->variant_id = (long)id->driver_data;
 
        cs42l43->regmap = devm_regmap_init_sdw(sdw, &cs42l43_sdw_regmap);
        if (IS_ERR(cs42l43->regmap))
@@ -188,7 +189,8 @@ static int cs42l43_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *
 }
 
 static const struct sdw_device_id cs42l43_sdw_id[] = {
-       SDW_SLAVE_ENTRY(0x01FA, 0x4243, 0),
+       SDW_SLAVE_ENTRY(0x01FA, 0x4243, (void *) CS42L43_DEVID_VAL),
+       SDW_SLAVE_ENTRY(0x01FA, 0x2A3B, (void *) CS42L43B_DEVID_VAL),
        {}
 };
 MODULE_DEVICE_TABLE(sdw, cs42l43_sdw_id);
index 107cfb983fec416bbdd31caa1e6a569026467735..166881751e698a78eecaf8bcf33839327dcf672b 100644 (file)
@@ -115,9 +115,14 @@ const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS] = {
        { CS42L43_DECIM_HPF_WNF_CTRL2,                  0x00000001 },
        { CS42L43_DECIM_HPF_WNF_CTRL3,                  0x00000001 },
        { CS42L43_DECIM_HPF_WNF_CTRL4,                  0x00000001 },
+       { CS42L43B_DECIM_HPF_WNF_CTRL5,                 0x00000001 },
+       { CS42L43B_DECIM_HPF_WNF_CTRL6,                 0x00000001 },
        { CS42L43_DMIC_PDM_CTRL,                        0x00000000 },
        { CS42L43_DECIM_VOL_CTRL_CH1_CH2,               0x20122012 },
        { CS42L43_DECIM_VOL_CTRL_CH3_CH4,               0x20122012 },
+       { CS42L43B_DECIM_VOL_CTRL_CH1_CH2,              0x20122012 },
+       { CS42L43B_DECIM_VOL_CTRL_CH3_CH4,              0x20122012 },
+       { CS42L43B_DECIM_VOL_CTRL_CH5_CH6,              0x20122012 },
        { CS42L43_INTP_VOLUME_CTRL1,                    0x00000180 },
        { CS42L43_INTP_VOLUME_CTRL2,                    0x00000180 },
        { CS42L43_AMP1_2_VOL_RAMP,                      0x00000022 },
@@ -155,8 +160,12 @@ const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS] = {
        { CS42L43_SWIRE_DP2_CH2_INPUT,                  0x00000000 },
        { CS42L43_SWIRE_DP3_CH1_INPUT,                  0x00000000 },
        { CS42L43_SWIRE_DP3_CH2_INPUT,                  0x00000000 },
+       { CS42L43B_SWIRE_DP3_CH3_INPUT,                 0x00000000 },
+       { CS42L43B_SWIRE_DP3_CH4_INPUT,                 0x00000000 },
        { CS42L43_SWIRE_DP4_CH1_INPUT,                  0x00000000 },
        { CS42L43_SWIRE_DP4_CH2_INPUT,                  0x00000000 },
+       { CS42L43B_SWIRE_DP4_CH3_INPUT,                 0x00000000 },
+       { CS42L43B_SWIRE_DP4_CH4_INPUT,                 0x00000000 },
        { CS42L43_ASRC_INT1_INPUT1,                     0x00000000 },
        { CS42L43_ASRC_INT2_INPUT1,                     0x00000000 },
        { CS42L43_ASRC_INT3_INPUT1,                     0x00000000 },
@@ -169,10 +178,14 @@ const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS] = {
        { CS42L43_ISRC1INT2_INPUT1,                     0x00000000 },
        { CS42L43_ISRC1DEC1_INPUT1,                     0x00000000 },
        { CS42L43_ISRC1DEC2_INPUT1,                     0x00000000 },
+       { CS42L43B_ISRC1DEC3_INPUT1,                    0x00000000 },
+       { CS42L43B_ISRC1DEC4_INPUT1,                    0x00000000 },
        { CS42L43_ISRC2INT1_INPUT1,                     0x00000000 },
        { CS42L43_ISRC2INT2_INPUT1,                     0x00000000 },
        { CS42L43_ISRC2DEC1_INPUT1,                     0x00000000 },
        { CS42L43_ISRC2DEC2_INPUT1,                     0x00000000 },
+       { CS42L43B_ISRC2DEC3_INPUT1,                    0x00000000 },
+       { CS42L43B_ISRC2DEC4_INPUT1,                    0x00000000 },
        { CS42L43_EQ1MIX_INPUT1,                        0x00800000 },
        { CS42L43_EQ1MIX_INPUT2,                        0x00800000 },
        { CS42L43_EQ1MIX_INPUT3,                        0x00800000 },
@@ -269,6 +282,8 @@ EXPORT_SYMBOL_NS_GPL(cs42l43_reg_default, "MFD_CS42L43");
 
 bool cs42l43_readable_register(struct device *dev, unsigned int reg)
 {
+       struct cs42l43 *cs42l43 = dev_get_drvdata(dev);
+
        switch (reg) {
        case CS42L43_DEVID:
        case CS42L43_REVID:
@@ -292,7 +307,6 @@ bool cs42l43_readable_register(struct device *dev, unsigned int reg)
        case CS42L43_ADC_B_CTRL1 ...  CS42L43_ADC_B_CTRL2:
        case CS42L43_DECIM_HPF_WNF_CTRL1 ... CS42L43_DECIM_HPF_WNF_CTRL4:
        case CS42L43_DMIC_PDM_CTRL:
-       case CS42L43_DECIM_VOL_CTRL_CH1_CH2 ... CS42L43_DECIM_VOL_CTRL_CH3_CH4:
        case CS42L43_INTP_VOLUME_CTRL1 ... CS42L43_INTP_VOLUME_CTRL2:
        case CS42L43_AMP1_2_VOL_RAMP:
        case CS42L43_ASP_CTRL:
@@ -387,8 +401,16 @@ bool cs42l43_readable_register(struct device *dev, unsigned int reg)
        case CS42L43_BOOT_CONTROL:
        case CS42L43_BLOCK_EN:
        case CS42L43_SHUTTER_CONTROL:
-       case CS42L43_MCU_SW_REV ... CS42L43_MCU_RAM_MAX:
-               return true;
+       case CS42L43B_MCU_SW_REV ... CS42L43B_MCU_RAM_MAX:
+               return true; // registers present on all variants
+       case CS42L43_MCU_SW_REV ... CS42L43B_MCU_SW_REV - 1:
+       case CS42L43B_MCU_RAM_MAX + 1 ... CS42L43_MCU_RAM_MAX:
+       case CS42L43_DECIM_VOL_CTRL_CH1_CH2 ... CS42L43_DECIM_VOL_CTRL_CH3_CH4:
+               return cs42l43->variant_id == CS42L43_DEVID_VAL; // regs only in CS42L43 variant
+       case CS42L43B_DECIM_VOL_CTRL_CH1_CH2 ... CS42L43B_DECIM_HPF_WNF_CTRL6:
+       case CS42L43B_SWIRE_DP3_CH3_INPUT ... CS42L43B_SWIRE_DP4_CH4_INPUT:
+       case CS42L43B_ISRC1DEC3_INPUT1 ... CS42L43B_ISRC2DEC4_INPUT1:
+               return cs42l43->variant_id == CS42L43B_DEVID_VAL; // regs only in CS42L43B variant
        default:
                return false;
        }
@@ -597,15 +619,27 @@ static int cs42l43_wait_for_attach(struct cs42l43 *cs42l43)
 static int cs42l43_mcu_stage_2_3(struct cs42l43 *cs42l43, bool shadow)
 {
        unsigned int need_reg = CS42L43_NEED_CONFIGS;
+       unsigned int boot_reg;
        unsigned int val;
        int ret;
 
-       if (shadow)
-               need_reg = CS42L43_FW_SH_BOOT_CFG_NEED_CONFIGS;
+       switch (cs42l43->variant_id) {
+       case CS42L43_DEVID_VAL:
+               if (shadow)
+                       need_reg = CS42L43_FW_SH_BOOT_CFG_NEED_CONFIGS;
+               boot_reg = CS42L43_BOOT_STATUS;
+               break;
+       case CS42L43B_DEVID_VAL:
+               need_reg = CS42L43B_NEED_CONFIGS;
+               boot_reg = CS42L43B_BOOT_STATUS;
+               break;
+       default:
+               return -EINVAL;
+       }
 
        regmap_write(cs42l43->regmap, need_reg, 0);
 
-       ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_BOOT_STATUS,
+       ret = regmap_read_poll_timeout(cs42l43->regmap, boot_reg,
                                       val, (val == CS42L43_MCU_BOOT_STAGE3),
                                       CS42L43_MCU_POLL_US, CS42L43_MCU_CMD_TIMEOUT_US);
        if (ret) {
@@ -644,13 +678,25 @@ static int cs42l43_mcu_stage_3_2(struct cs42l43 *cs42l43)
  */
 static int cs42l43_mcu_disable(struct cs42l43 *cs42l43)
 {
-       unsigned int val;
+       unsigned int val, cfg_reg, ctrl_reg;
        int ret;
 
-       regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_REG,
-                    CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_DISABLE_VAL);
-       regmap_write(cs42l43->regmap, CS42L43_FW_MISSION_CTRL_MM_CTRL_SELECTION,
-                    CS42L43_FW_MM_CTRL_MCU_SEL_MASK);
+       switch (cs42l43->variant_id) {
+       case CS42L43_DEVID_VAL:
+               cfg_reg = CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_REG;
+               ctrl_reg = CS42L43_FW_MISSION_CTRL_MM_CTRL_SELECTION;
+               break;
+       case CS42L43B_DEVID_VAL:
+               cfg_reg = CS42L43B_FW_MISSION_CTRL_MM_MCU_CFG_REG;
+               ctrl_reg = CS42L43B_FW_MISSION_CTRL_MM_CTRL_SELECTION;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       regmap_write(cs42l43->regmap, cfg_reg, CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_DISABLE_VAL);
+       regmap_write(cs42l43->regmap, ctrl_reg, CS42L43_FW_MM_CTRL_MCU_SEL_MASK);
+
        regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, CS42L43_CONTROL_IND_MASK);
        regmap_write(cs42l43->regmap, CS42L43_MCU_SW_INTERRUPT, 0);
 
@@ -740,18 +786,32 @@ static int cs42l43_mcu_update_step(struct cs42l43 *cs42l43)
 {
        unsigned int mcu_rev, bios_rev, boot_status, secure_cfg;
        bool patched, shadow;
+       int boot_status_reg, mcu_sw_rev_reg;
        int ret;
 
+       switch (cs42l43->variant_id) {
+       case CS42L43_DEVID_VAL:
+               boot_status_reg = CS42L43_BOOT_STATUS;
+               mcu_sw_rev_reg = CS42L43_MCU_SW_REV;
+               break;
+       case CS42L43B_DEVID_VAL:
+               boot_status_reg = CS42L43B_BOOT_STATUS;
+               mcu_sw_rev_reg = CS42L43B_MCU_SW_REV;
+               break;
+       default:
+               return -EINVAL;
+       }
+
        /* Clear any stale software interrupt bits. */
        regmap_read(cs42l43->regmap, CS42L43_SOFT_INT, &mcu_rev);
 
-       ret = regmap_read(cs42l43->regmap, CS42L43_BOOT_STATUS, &boot_status);
+       ret = regmap_read(cs42l43->regmap, boot_status_reg, &boot_status);
        if (ret) {
                dev_err(cs42l43->dev, "Failed to read boot status: %d\n", ret);
                return ret;
        }
 
-       ret = regmap_read(cs42l43->regmap, CS42L43_MCU_SW_REV, &mcu_rev);
+       ret = regmap_read(cs42l43->regmap, mcu_sw_rev_reg, &mcu_rev);
        if (ret) {
                dev_err(cs42l43->dev, "Failed to read firmware revision: %d\n", ret);
                return ret;
@@ -918,6 +978,13 @@ static void cs42l43_boot_work(struct work_struct *work)
 
        switch (devid) {
        case CS42L43_DEVID_VAL:
+       case CS42L43B_DEVID_VAL:
+               if (devid != cs42l43->variant_id) {
+                       dev_err(cs42l43->dev,
+                               "Device ID (0x%06x) does not match variant ID (0x%06lx)\n",
+                               devid, cs42l43->variant_id);
+                       goto err;
+               }
                break;
        default:
                dev_err(cs42l43->dev, "Unrecognised devid: 0x%06x\n", devid);
index f3da783930f53404d7bc7731eb03f582a9ee8710..a0068f6572e2c306b8ae43841758c1b6ad87b390 100644 (file)
@@ -9,7 +9,7 @@
 #ifndef CS42L43_CORE_INT_H
 #define CS42L43_CORE_INT_H
 
-#define CS42L43_N_DEFAULTS 176
+#define CS42L43_N_DEFAULTS 189
 
 struct dev_pm_ops;
 struct device;
index c39a49269cb7d163838059c8062b55a63373a368..68831f113589dfc45197e5f94464dac30cc2769d 100644 (file)
 /* CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_REG */
 #define CS42L43_FW_MISSION_CTRL_MM_MCU_CFG_DISABLE_VAL         0xF05AA50F
 
+/* CS42L43B VARIANT REGISTERS */
+#define CS42L43B_DEVID_VAL                                     0x0042A43B
+
+#define CS42L43B_DECIM_VOL_CTRL_CH1_CH2                                0x00008280
+#define CS42L43B_DECIM_VOL_CTRL_CH3_CH4                                0x00008284
+
+#define CS42L43B_DECIM_VOL_CTRL_CH5_CH6                                0x00008290
+#define CS42L43B_DECIM_VOL_CTRL_UPDATE                         0x0000829C
+
+#define CS42L43B_DECIM_HPF_WNF_CTRL5                           0x000082A0
+#define CS42L43B_DECIM_HPF_WNF_CTRL6                           0x000082A4
+
+#define CS42L43B_SWIRE_DP3_CH3_INPUT                           0x0000C320
+#define CS42L43B_SWIRE_DP3_CH4_INPUT                           0x0000C330
+#define CS42L43B_SWIRE_DP4_CH3_INPUT                           0x0000C340
+#define CS42L43B_SWIRE_DP4_CH4_INPUT                           0x0000C350
+
+#define CS42L43B_ISRC1DEC3_INPUT1                              0x0000C780
+#define CS42L43B_ISRC1DEC4_INPUT1                              0x0000C790
+#define CS42L43B_ISRC2DEC3_INPUT1                              0x0000C7A0
+#define CS42L43B_ISRC2DEC4_INPUT1                              0x0000C7B0
+
+#define CS42L43B_FW_MISSION_CTRL_NEED_CONFIGS                  0x00117E00
+#define CS42L43B_FW_MISSION_CTRL_HAVE_CONFIGS                  0x00117E04
+#define CS42L43B_FW_MISSION_CTRL_PATCH_START_ADDR_REG          0x00117E08
+#define CS42L43B_FW_MISSION_CTRL_MM_CTRL_SELECTION             0x00117E0C
+#define CS42L43B_FW_MISSION_CTRL_MM_MCU_CFG_REG                        0x00117E10
+
+#define CS42L43B_MCU_SW_REV                                    0x00117314
+#define CS42L43B_PATCH_START_ADDR                              0x00117318
+#define CS42L43B_CONFIG_SELECTION                              0x0011731C
+#define CS42L43B_NEED_CONFIGS                                  0x00117320
+#define CS42L43B_BOOT_STATUS                                   0x00117330
+
+#define CS42L43B_FW_MISSION_CTRL_NEED_CONFIGS                  0x00117E00
+#define CS42L43B_FW_MISSION_CTRL_HAVE_CONFIGS                  0x00117E04
+#define CS42L43B_FW_MISSION_CTRL_PATCH_START_ADDR_REG          0x00117E08
+#define CS42L43B_FW_MISSION_CTRL_MM_CTRL_SELECTION             0x00117E0C
+#define CS42L43B_FW_MISSION_CTRL_MM_MCU_CFG_REG                        0x00117E10
+
+#define CS42L43B_MCU_RAM_MAX                                   0x00117FFF
+
+/* CS42L43B_DECIM_DECIM_VOL_CTRL_CH5_CH6 */
+#define CS42L43B_DECIM6_MUTE_MASK                              0x80000000
+#define CS42L43B_DECIM6_MUTE_SHIFT                             31
+#define CS42L43B_DECIM6_VOL_MASK                               0x3FC00000
+#define CS42L43B_DECIM6_VOL_SHIFT                              22
+#define CS42L43B_DECIM6_PATH1_VOL_FALL_RATE_MASK               0x00380000
+#define CS42L43B_DECIM6_PATH1_VOL_FALL_RATE_SHIFT              19
+#define CS42L43B_DECIM6_PATH1_VOL_RISE_RATE_MASK               0x00070000
+#define CS42L43B_DECIM6_PATH1_VOL_RISE_RATE_SHIFT              16
+#define CS42L43B_DECIM5_MUTE_MASK                              0x00008000
+#define CS42L43B_DECIM5_MUTE_SHIFT                             15
+#define CS42L43B_DECIM5_VOL_MASK                               0x00003FC0
+#define CS42L43B_DECIM5_VOL_SHIFT                              6
+#define CS42L43B_DECIM5_PATH1_VOL_FALL_RATE_MASK               0x00000038
+#define CS42L43B_DECIM5_PATH1_VOL_FALL_RATE_SHIFT              3
+#define CS42L43B_DECIM5_PATH1_VOL_RISE_RATE_MASK               0x00000007
+#define CS42L43B_DECIM5_PATH1_VOL_RISE_RATE_SHIFT              0
+
+/* CS42L43B_DECIM_VOL_CTRL_UPDATE */
+#define CS42L43B_DECIM6_PATH1_VOL_TRIG_MASK                    0x00000800
+#define CS42L43B_DECIM6_PATH1_VOL_TRIG_SHIFT                   11
+#define CS42L43B_DECIM5_PATH1_VOL_TRIG_MASK                    0x00000100
+#define CS42L43B_DECIM5_PATH1_VOL_TRIG_SHIFT                   8
+#define CS42L43B_DECIM4_VOL_UPDATE_MASK                                0x00000020
+#define CS42L43B_DECIM4_VOL_UPDATE_SHIFT                       5
+
+/* CS42L43_ISRC1_CTRL..CS42L43_ISRC2_CTRL */
+#define CS42L43B_ISRC_DEC4_EN_MASK                             0x00000008
+#define CS42L43B_ISRC_DEC4_EN_SHIFT                            3
+#define CS42L43B_ISRC_DEC4_EN_WIDTH                            1
+#define CS42L43B_ISRC_DEC3_EN_MASK                             0x00000004
+#define CS42L43B_ISRC_DEC3_EN_SHIFT                            2
+#define CS42L43B_ISRC_DEC3_EN_WIDTH                            1
+
 #endif /* CS42L43_CORE_REGS_H */
index 2239d8585e785642e3a502d15b6d297d1e89a8b1..ff0f7e365a19f732970e8284a6485ca19ac6afab 100644 (file)
@@ -98,6 +98,7 @@ struct cs42l43 {
        bool sdw_pll_active;
        bool attached;
        bool hw_lock;
+       long variant_id;
 };
 
 #endif /* CS42L43_CORE_EXT_H */