Re: [PATCH v4 4/6] ASoC: es9356-sdca: Add ES9356 SDCA driver

Charles Keepax
2026-03-27T13:25:23Z

On Fri, Mar 27, 2026 at 05:59:52PM +0800, Zhang Yi wrote:
> This is the codec driver for es9356-sdca.
>
> Signed-off-by: Zhang Yi <zhangyi@everest-semi.com>
> ---
> +
> + regmap_read(es9356->regmap, mc->reg, &read_ll);
> + regmap_read(es9356->regmap, SDW_SDCA_REG_MBQ(mc->reg), &read_l);
> + regmap_read(es9356->regmap, mc->rreg, &read_rl);
> + regmap_read(es9356->regmap, SDW_SDCA_REG_MBQ(mc->rreg), &read_r);
> +
> + if (gain_ll_val != read_ll || gain_rl_val != read_rl
> + || gain_l_val != read_l || gain_r_val != read_r)
> + changed = 1;
> + else
> + goto out;
> +
> + regmap_write(es9356->regmap, SDW_SDCA_REG_MBQ(mc->reg), gain_l_val);
> + regmap_write(es9356->regmap, mc->reg, gain_ll_val);
> + regmap_write(es9356->regmap, SDW_SDCA_REG_MBQ(mc->rreg), gain_r_val);
> + regmap_write(es9356->regmap, mc->rreg, gain_rl_val);
> +
> + regmap_read(es9356->regmap, mc->reg, &read_ll);
> + regmap_read(es9356->regmap, SDW_SDCA_REG_MBQ(mc->reg), &read_l);
> + regmap_read(es9356->regmap, mc->rreg, &read_rl);
> + regmap_read(es9356->regmap, SDW_SDCA_REG_MBQ(mc->rreg), &read_r);

Is there a reason to not use the MBQ regmap (regmap-sdw-mbq.c),
it would mean you only need a single transaction for each of the
MBQs?

> +
> +out:
> + if (ret >= 0) {
> + pm_runtime_mark_last_busy(&es9356->slave->dev);
> + pm_runtime_put_autosuspend(&es9356->slave->dev);
> + } else if (ret == -EACCES) {
> + pm_runtime_mark_last_busy(&es9356->slave->dev);
> + }
> +
> + if (gain_ll_val == read_ll && gain_rl_val == read_rl
> + && gain_l_val == read_l && gain_r_val == read_r) {
> + return changed;
> + }
> + return -EIO;
> +}

Also in general for the volumes it is probably worth seeing if
you can use the SDCA volume helpers, some work is on going to
export these to help custom drivers re-use them:

https://lore.kernel.org/linux-sound/acZgyKuKns2wAZ1R@opensource.cirrus.com/T/#t

You will likely still need wrappers if you genuinely require the
pm_runtime gets in here but at least streamline the volume
handling a little.

> +static void es9356_pde_transition_delay(struct es9356_sdw_priv *es9356, unsigned char func,
> + unsigned char entity, unsigned char ps)
> +{
> + unsigned int retries = 1000, val;
> +
> + pm_runtime_mark_last_busy(&es9356->slave->dev);
> +
> + /* waiting for Actual PDE becomes to PS0/PS3 */
> + while (retries) {
> + regmap_read(es9356->regmap,
> + SDW_SDCA_HCTL(func, entity, ES9356_SDCA_CTL_ACTUAL_POWER_STATE, 0), &val);
> + if (val == ps)
> + break;
> +
> + usleep_range(1000, 1500);
> + retries--;
> + }
> + if (!retries) {
> + dev_dbg(&es9356->slave->dev, "%s PDE to %s is NOT ready", __func__, ps?"PS3":"PS0");
> + }
> +}
> +
> +static int es9356_sdca_pde23_event(struct snd_soc_dapm_widget *w,
> + struct snd_kcontrol *kcontrol, int event)
> +{
> + struct snd_soc_component *component =
> + snd_soc_dapm_to_component(w->dapm);
> + struct es9356_sdw_priv *es9356 = snd_soc_component_get_drvdata(component);
> + unsigned char ps0 = 0x0, ps3 = 0x3;
> +
> + switch (event) {
> + case SND_SOC_DAPM_POST_PMU:
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_AMP, ES9356_SDCA_ENT_PDE23, ES9356_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
> + es9356_pde_transition_delay(es9356, FUNC_NUM_AMP, ES9356_SDCA_ENT_PDE23, ps0);
> + break;
> + case SND_SOC_DAPM_PRE_PMD:
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_AMP, ES9356_SDCA_ENT_PDE23, ES9356_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
> + es9356_pde_transition_delay(es9356, FUNC_NUM_AMP, ES9356_SDCA_ENT_PDE23, ps3);
> + break;
> + }
> + return 0;
> +}
> +
> +static int es9356_sdca_pde11_event(struct snd_soc_dapm_widget *w,
> + struct snd_kcontrol *kcontrol, int event)
> +{
> + struct snd_soc_component *component =
> + snd_soc_dapm_to_component(w->dapm);
> + struct es9356_sdw_priv *es9356 = snd_soc_component_get_drvdata(component);
> + unsigned char ps0 = 0x0, ps3 = 0x3;
> +
> + switch (event) {
> + case SND_SOC_DAPM_POST_PMU:
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT_PDE11, ES9356_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
> + es9356_pde_transition_delay(es9356, FUNC_NUM_MIC, ES9356_SDCA_ENT_PDE11, ps0);
> + break;
> + case SND_SOC_DAPM_PRE_PMD:
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT_PDE11, ES9356_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
> + es9356_pde_transition_delay(es9356, FUNC_NUM_MIC, ES9356_SDCA_ENT_PDE11, ps3);
> + break;
> + }
> + return 0;
> +}
> +
> +static int es9356_sdca_pde47_event(struct snd_soc_dapm_widget *w,
> + struct snd_kcontrol *kcontrol, int event)
> +{
> + struct snd_soc_component *component =
> + snd_soc_dapm_to_component(w->dapm);
> + struct es9356_sdw_priv *es9356 = snd_soc_component_get_drvdata(component);
> + unsigned char ps0 = 0x0, ps3 = 0x3;
> +
> + switch (event) {
> + case SND_SOC_DAPM_POST_PMU:
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_PDE47, ES9356_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
> + es9356_pde_transition_delay(es9356, FUNC_NUM_UAJ, ES9356_SDCA_ENT_PDE47, ps0);
> + break;
> + case SND_SOC_DAPM_PRE_PMD:
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_PDE47, ES9356_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
> + es9356_pde_transition_delay(es9356, FUNC_NUM_UAJ, ES9356_SDCA_ENT_PDE47, ps3);
> + break;
> + }
> + return 0;
> +}
> +
> +static int es9356_sdca_pde34_event(struct snd_soc_dapm_widget *w,
> + struct snd_kcontrol *kcontrol, int event)
> +{
> + struct snd_soc_component *component =
> + snd_soc_dapm_to_component(w->dapm);
> + struct es9356_sdw_priv *es9356 = snd_soc_component_get_drvdata(component);
> + unsigned char ps0 = 0x0, ps3 = 0x3;
> +
> + switch (event) {
> + case SND_SOC_DAPM_POST_PMU:
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_PDE34, ES9356_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
> + es9356_pde_transition_delay(es9356, FUNC_NUM_UAJ, ES9356_SDCA_ENT_PDE34, ps0);
> + break;
> + case SND_SOC_DAPM_PRE_PMD:
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_PDE34, ES9356_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
> + es9356_pde_transition_delay(es9356, FUNC_NUM_UAJ, ES9356_SDCA_ENT_PDE34, ps3);
> + break;
> + }
> + return 0;
> +}

An additional helper function here that takes the register for
the PDE and does the regmap_writes would make sense, lot of
duplication between all these functions.

> +static int es9356_sdca_fu21_event(struct snd_soc_dapm_widget *w,
> + struct snd_kcontrol *kcontrol, int event)
> +{
> + struct snd_soc_component *component =
> + snd_soc_dapm_to_component(w->dapm);
> + struct es9356_sdw_priv *es9356 = snd_soc_component_get_drvdata(component);
> + unsigned char unmute = 0x0, mute = 0x1;
> +
> + switch (event) {
> + case SND_SOC_DAPM_POST_PMU:
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_AMP, ES9356_SDCA_ENT_FU21, ES9356_SDCA_CTL_FU_MUTE, CH_L), unmute);
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_AMP, ES9356_SDCA_ENT_FU21, ES9356_SDCA_CTL_FU_MUTE, CH_R), unmute);
> + break;
> + case SND_SOC_DAPM_PRE_PMD:
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_AMP, ES9356_SDCA_ENT_FU21, ES9356_SDCA_CTL_FU_MUTE, CH_L), mute);
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_AMP, ES9356_SDCA_ENT_FU21, ES9356_SDCA_CTL_FU_MUTE, CH_R), mute);
> + break;
> + }
> + return 0;
> +}
> +
> +static int es9356_sdca_fu41_event(struct snd_soc_dapm_widget *w,
> + struct snd_kcontrol *kcontrol, int event)
> +{
> + struct snd_soc_component *component =
> + snd_soc_dapm_to_component(w->dapm);
> + struct es9356_sdw_priv *es9356 = snd_soc_component_get_drvdata(component);
> + unsigned char unmute = 0x0, mute = 0x1;
> +
> + switch (event) {
> + case SND_SOC_DAPM_POST_PMU:
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU41, ES9356_SDCA_CTL_FU_MUTE, CH_L), unmute);
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU41, ES9356_SDCA_CTL_FU_MUTE, CH_R), unmute);
> + break;
> + case SND_SOC_DAPM_PRE_PMD:
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU41, ES9356_SDCA_CTL_FU_MUTE, CH_L), mute);
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU41, ES9356_SDCA_CTL_FU_MUTE, CH_R), mute);
> + break;
> + }
> + return 0;
> +}
> +
> +static int es9356_sdca_fu113_event(struct snd_soc_dapm_widget *w,
> + struct snd_kcontrol *kcontrol, int event)
> +{
> + struct snd_soc_component *component =
> + snd_soc_dapm_to_component(w->dapm);
> + struct es9356_sdw_priv *es9356 = snd_soc_component_get_drvdata(component);
> + unsigned char unmute = 0x0, mute = 0x1;
> +
> + switch (event) {
> + case SND_SOC_DAPM_POST_PMU:
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT_FU113, ES9356_SDCA_CTL_FU_MUTE, CH_L), unmute);
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT_FU113, ES9356_SDCA_CTL_FU_MUTE, CH_R), unmute);
> + break;
> + case SND_SOC_DAPM_PRE_PMD:
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT_FU113, ES9356_SDCA_CTL_FU_MUTE, CH_L), mute);
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT_FU113, ES9356_SDCA_CTL_FU_MUTE, CH_R), mute);
> + break;
> + }
> + return 0;
> +}
> +
> +static int es9356_sdca_fu36_event(struct snd_soc_dapm_widget *w,
> + struct snd_kcontrol *kcontrol, int event)
> +{
> + struct snd_soc_component *component =
> + snd_soc_dapm_to_component(w->dapm);
> + struct es9356_sdw_priv *es9356 = snd_soc_component_get_drvdata(component);
> + unsigned char unmute = 0x0, mute = 0x1;
> +
> + switch (event) {
> + case SND_SOC_DAPM_POST_PMU:
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU36, ES9356_SDCA_CTL_FU_MUTE, CH_L), unmute);
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU36, ES9356_SDCA_CTL_FU_MUTE, CH_R), unmute);
> + break;
> + case SND_SOC_DAPM_PRE_PMD:
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU36, ES9356_SDCA_CTL_FU_MUTE, CH_L), mute);
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU36, ES9356_SDCA_CTL_FU_MUTE, CH_R), mute);
> + break;
> + }
> + return 0;
> +}

If you used the MBQ regmap you wouldn't need callbacks for any of
the FUs you could just specify the register to DAPM.

> +static void es9356_regcache_sync_volume(struct device *dev, struct regmap *regmap)
> +{
> + struct sdw_slave *slave = dev_to_sdw_dev(dev);
> + struct es9356_sdw_priv *es9356 = dev_get_drvdata(dev);
> + unsigned int reg, i;
> +
> + mutex_lock(&es9356->volume_sync_lock);
> + for (i = 0; i < ARRAY_SIZE(es9356_volume_register); i++) {
> + regcache_sync_region(regmap, SDW_SDCA_REG_MBQ(es9356_volume_register[i]),
> + SDW_SDCA_REG_MBQ(es9356_volume_register[i]));
> + regcache_sync_region(regmap, es9356_volume_register[i],
> + es9356_volume_register[i]);
> + }
> + mutex_unlock(&es9356->volume_sync_lock);

Does this lock acheive anything? It is only used in here which is
only called from resume but you can't have 2 resumes happening at
once.

> +static void es9356_register_init(struct es9356_sdw_priv *es9356)
> +{
> + regmap_write(es9356->regmap, ES9356_STATE, 0x02);
> + regmap_write(es9356->regmap, ES9356_ENDPOINT_MODE, 0x24);
> + regmap_write(es9356->regmap, ES9356_PRE_DIV_CTL, 0x00);
> + regmap_write(es9356->regmap, ES9356_ADC_OSR, 0x18);
> + regmap_write(es9356->regmap, ES9356_ADC_OSRGAIN, 0x13);
> + regmap_write(es9356->regmap, ES9356_DAC_OSR, 0x16);
> + regmap_write(es9356->regmap, ES9356_CLK_CTL, 0x0f);
> + regmap_write(es9356->regmap, ES9356_CSM_RESET, 0x01);
> + regmap_write(es9356->regmap, ES9356_CLK_SEL, 0x30);
> +
> + regmap_write(es9356->regmap, ES9356_DETCLK_CTL, 0x51);
> + regmap_write(es9356->regmap, ES9356_HP_TYPE, 0x10);
> + regmap_write(es9356->regmap, ES9356_MICBIAS_CTL, 0x10);
> + regmap_write(es9356->regmap, ES9356_HPDETECT_CTL, 0x07);
> + regmap_write(es9356->regmap, ES9356_ADC_ANA, 0x30);
> + regmap_write(es9356->regmap, ES9356_PGA_CTL, 0xa8);
> + regmap_write(es9356->regmap, ES9356_ADC_INT, 0xaa);
> + regmap_write(es9356->regmap, ES9356_ADC_LP, 0x19);
> + regmap_write(es9356->regmap, ES9356_VMID1SEL, 0xbc);
> + regmap_write(es9356->regmap, ES9356_VMID_TIME, 0x0b);
> + regmap_write(es9356->regmap, ES9356_STATE_TIME, 0xbb);
> + regmap_write(es9356->regmap, ES9356_HP_SPK_TIME, 0x77);
> + regmap_write(es9356->regmap, ES9356_HP_DETECTTIME, 0xa4);
> + regmap_write(es9356->regmap, ES9356_MICBIAS_SEL, 0x15);
> + regmap_write(es9356->regmap, ES9356_KEY_PRESS_TIME, 0xff);
> + regmap_write(es9356->regmap, ES9356_KEY_RELEASE_TIME, 0xff);
> + regmap_write(es9356->regmap, ES9356_KEY_HOLD_TIME, 0x0f);
> + regmap_write(es9356->regmap, ES9356_BTSEL_REF, 0x00);
> + regmap_write(es9356->regmap, ES9356_KEYD_DETECT, 0x18);
> + regmap_write(es9356->regmap, ES9356_MICBIAS_RES, 0x03);
> + regmap_write(es9356->regmap, ES9356_BUTTON_CHARGE, 0x00);
> + regmap_write(es9356->regmap, ES9356_CALIBRATION_TIME, 0x13);
> + regmap_write(es9356->regmap, ES9356_CALIBRATION_SETTING, 0xf4);
> +
> + regmap_write(es9356->regmap, ES9356_SPK_VOLUME, 0x33);
> + regmap_write(es9356->regmap, ES9356_DAC_VROI, 0x01);
> + regmap_write(es9356->regmap, ES9356_DAC_LP, 0x00);
> + regmap_write(es9356->regmap, ES9356_HP_IBIAS, 0x04);
> + regmap_write(es9356->regmap, ES9356_HP_LP, 0x03);
> + regmap_write(es9356->regmap, ES9356_SPKLDO_CTL, 0x65);
> + regmap_write(es9356->regmap, ES9356_SPKBIAS_COMP, 0x09);
> + regmap_write(es9356->regmap, ES9356_VMID1STL, 0x00);
> + regmap_write(es9356->regmap, ES9356_VMID2STL, 0x00);
> + regmap_write(es9356->regmap, ES9356_VSEL, 0xfc);
> +
> + regmap_write(es9356->regmap, ES9356_IBIASGEN, 0x10);
> + regmap_write(es9356->regmap, ES9356_ADC_AMIC_CTL, 0x0d);
> + regmap_write(es9356->regmap, ES9356_STATE, 0x0e);
> + regmap_write(es9356->regmap, ES9356_CSM_RESET, 0x00);
> + regmap_write(es9356->regmap, ES9356_HP_TYPE, 0x08);
> +
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL_MBQ(FUNC_NUM_MIC, ES9356_SDCA_ENT_FU113, ES9356_SDCA_CTL_FU_VOLUME, CH_L), ES9356_DEFAULT_VOLUME);
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT_FU113, ES9356_SDCA_CTL_FU_VOLUME, CH_L), ES9356_DEFAULT_VOLUME);
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL_MBQ(FUNC_NUM_MIC, ES9356_SDCA_ENT_FU113, ES9356_SDCA_CTL_FU_VOLUME, CH_R), ES9356_DEFAULT_VOLUME);
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT_FU113, ES9356_SDCA_CTL_FU_VOLUME, CH_R), ES9356_DEFAULT_VOLUME);
> +
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL_MBQ(FUNC_NUM_AMP, ES9356_SDCA_ENT_FU21, ES9356_SDCA_CTL_FU_VOLUME, CH_L), ES9356_DEFAULT_VOLUME);
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_AMP, ES9356_SDCA_ENT_FU21, ES9356_SDCA_CTL_FU_VOLUME, CH_L), ES9356_DEFAULT_VOLUME);
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL_MBQ(FUNC_NUM_AMP, ES9356_SDCA_ENT_FU21, ES9356_SDCA_CTL_FU_VOLUME, CH_R), ES9356_DEFAULT_VOLUME);
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_AMP, ES9356_SDCA_ENT_FU21, ES9356_SDCA_CTL_FU_VOLUME, CH_R), ES9356_DEFAULT_VOLUME);
> +
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL_MBQ(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU41, ES9356_SDCA_CTL_FU_VOLUME, CH_L), ES9356_DEFAULT_VOLUME);
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU41, ES9356_SDCA_CTL_FU_VOLUME, CH_L), ES9356_DEFAULT_VOLUME);
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL_MBQ(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU41, ES9356_SDCA_CTL_FU_VOLUME, CH_R), ES9356_DEFAULT_VOLUME);
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU41, ES9356_SDCA_CTL_FU_VOLUME, CH_R), ES9356_DEFAULT_VOLUME);
> +
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL_MBQ(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU36, ES9356_SDCA_CTL_FU_VOLUME, CH_L), ES9356_DEFAULT_VOLUME);
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU36, ES9356_SDCA_CTL_FU_VOLUME, CH_L), ES9356_DEFAULT_VOLUME);
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL_MBQ(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU36, ES9356_SDCA_CTL_FU_VOLUME, CH_R), ES9356_DEFAULT_VOLUME);
> + regmap_write(es9356->regmap,
> + SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU36, ES9356_SDCA_CTL_FU_VOLUME, CH_R), ES9356_DEFAULT_VOLUME);

If these are in DisCo you could use the class driver
sdca_regmap_write_init function rather than having to open code
them all. But fine if they are not in DisCo.

> +#define SDW_SDCA_CTL_MBQ(fun, ent, ctl, ch) (SDW_SDCA_CTL(fun, ent, ctl, ch) | MBQ)
> +#define SDW_SDCA_HCTL(fun, ent, ctl, ch) (SDW_SDCA_CTL(fun, ent, ctl, ch) | 0x80000)
> +#define SDW_SDCA_REG_MBQ(reg) (reg | MBQ)

There is a core function which does exactly this called
SDW_SDCA_MBQ_CTL() use that if you really need to do the MBQ
stuff in the driver.

Not that I am pushing for this now on this driver but would be
good for you guys to perhaps poke what happens binding your parts
with the class driver itself (sdca_class.c). The hope would be
in time we can support all new SDCA parts out of there by just
adding the slave entry. So good to start finding out what does
and doesn't work for you guys. At the moment the class driver is
still in active development and a lot of shipping products have
dodgy DisCo or hardware issues that make use difficult, so
this is more of a long term goal. From scanning the driver here
it does look like a few things might be slightly not standard so
I am not sure how well things will work but be interesting to
find out.

Thanks,
Charles