ASoC: cs35l41: DSP Support
Support for HALO DSP and firmware Signed-off-by: David Rhodes <drhodes@opensource.cirrus.com> Reviewed-by: Charles Keepax <ckeepax@opensource.cirrus.com> Link: https://lore.kernel.org/r/20211029214028.401284-2-drhodes@opensource.cirrus.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
0f9710603e
commit
bae9e13fc5
@ -343,11 +343,15 @@ config SND_SOC_WM_ADSP
|
||||
default y if SND_SOC_WM5102=y
|
||||
default y if SND_SOC_WM5110=y
|
||||
default y if SND_SOC_WM2200=y
|
||||
default y if SND_SOC_CS35L41_SPI=y
|
||||
default y if SND_SOC_CS35L41_I2C=y
|
||||
default m if SND_SOC_MADERA=m
|
||||
default m if SND_SOC_CS47L24=m
|
||||
default m if SND_SOC_WM5102=m
|
||||
default m if SND_SOC_WM5110=m
|
||||
default m if SND_SOC_WM2200=m
|
||||
default m if SND_SOC_CS35L41_SPI=m
|
||||
default m if SND_SOC_CS35L41_I2C=m
|
||||
|
||||
config SND_SOC_AB8500_CODEC
|
||||
tristate
|
||||
|
@ -200,6 +200,83 @@ bool cs35l41_readable_reg(struct device *dev, unsigned int reg)
|
||||
case CS35L41_DIE_STS2:
|
||||
case CS35L41_TEMP_CAL1:
|
||||
case CS35L41_TEMP_CAL2:
|
||||
case CS35L41_DSP1_TIMESTAMP_COUNT:
|
||||
case CS35L41_DSP1_SYS_ID:
|
||||
case CS35L41_DSP1_SYS_VERSION:
|
||||
case CS35L41_DSP1_SYS_CORE_ID:
|
||||
case CS35L41_DSP1_SYS_AHB_ADDR:
|
||||
case CS35L41_DSP1_SYS_XSRAM_SIZE:
|
||||
case CS35L41_DSP1_SYS_YSRAM_SIZE:
|
||||
case CS35L41_DSP1_SYS_PSRAM_SIZE:
|
||||
case CS35L41_DSP1_SYS_PM_BOOT_SIZE:
|
||||
case CS35L41_DSP1_SYS_FEATURES:
|
||||
case CS35L41_DSP1_SYS_FIR_FILTERS:
|
||||
case CS35L41_DSP1_SYS_LMS_FILTERS:
|
||||
case CS35L41_DSP1_SYS_XM_BANK_SIZE:
|
||||
case CS35L41_DSP1_SYS_YM_BANK_SIZE:
|
||||
case CS35L41_DSP1_SYS_PM_BANK_SIZE:
|
||||
case CS35L41_DSP1_RX1_RATE:
|
||||
case CS35L41_DSP1_RX2_RATE:
|
||||
case CS35L41_DSP1_RX3_RATE:
|
||||
case CS35L41_DSP1_RX4_RATE:
|
||||
case CS35L41_DSP1_RX5_RATE:
|
||||
case CS35L41_DSP1_RX6_RATE:
|
||||
case CS35L41_DSP1_RX7_RATE:
|
||||
case CS35L41_DSP1_RX8_RATE:
|
||||
case CS35L41_DSP1_TX1_RATE:
|
||||
case CS35L41_DSP1_TX2_RATE:
|
||||
case CS35L41_DSP1_TX3_RATE:
|
||||
case CS35L41_DSP1_TX4_RATE:
|
||||
case CS35L41_DSP1_TX5_RATE:
|
||||
case CS35L41_DSP1_TX6_RATE:
|
||||
case CS35L41_DSP1_TX7_RATE:
|
||||
case CS35L41_DSP1_TX8_RATE:
|
||||
case CS35L41_DSP1_SCRATCH1:
|
||||
case CS35L41_DSP1_SCRATCH2:
|
||||
case CS35L41_DSP1_SCRATCH3:
|
||||
case CS35L41_DSP1_SCRATCH4:
|
||||
case CS35L41_DSP1_CCM_CORE_CTRL:
|
||||
case CS35L41_DSP1_CCM_CLK_OVERRIDE:
|
||||
case CS35L41_DSP1_XM_MSTR_EN:
|
||||
case CS35L41_DSP1_XM_CORE_PRI:
|
||||
case CS35L41_DSP1_XM_AHB_PACK_PL_PRI:
|
||||
case CS35L41_DSP1_XM_AHB_UP_PL_PRI:
|
||||
case CS35L41_DSP1_XM_ACCEL_PL0_PRI:
|
||||
case CS35L41_DSP1_XM_NPL0_PRI:
|
||||
case CS35L41_DSP1_YM_MSTR_EN:
|
||||
case CS35L41_DSP1_YM_CORE_PRI:
|
||||
case CS35L41_DSP1_YM_AHB_PACK_PL_PRI:
|
||||
case CS35L41_DSP1_YM_AHB_UP_PL_PRI:
|
||||
case CS35L41_DSP1_YM_ACCEL_PL0_PRI:
|
||||
case CS35L41_DSP1_YM_NPL0_PRI:
|
||||
case CS35L41_DSP1_MPU_XM_ACCESS0:
|
||||
case CS35L41_DSP1_MPU_YM_ACCESS0:
|
||||
case CS35L41_DSP1_MPU_WNDW_ACCESS0:
|
||||
case CS35L41_DSP1_MPU_XREG_ACCESS0:
|
||||
case CS35L41_DSP1_MPU_YREG_ACCESS0:
|
||||
case CS35L41_DSP1_MPU_XM_ACCESS1:
|
||||
case CS35L41_DSP1_MPU_YM_ACCESS1:
|
||||
case CS35L41_DSP1_MPU_WNDW_ACCESS1:
|
||||
case CS35L41_DSP1_MPU_XREG_ACCESS1:
|
||||
case CS35L41_DSP1_MPU_YREG_ACCESS1:
|
||||
case CS35L41_DSP1_MPU_XM_ACCESS2:
|
||||
case CS35L41_DSP1_MPU_YM_ACCESS2:
|
||||
case CS35L41_DSP1_MPU_WNDW_ACCESS2:
|
||||
case CS35L41_DSP1_MPU_XREG_ACCESS2:
|
||||
case CS35L41_DSP1_MPU_YREG_ACCESS2:
|
||||
case CS35L41_DSP1_MPU_XM_ACCESS3:
|
||||
case CS35L41_DSP1_MPU_YM_ACCESS3:
|
||||
case CS35L41_DSP1_MPU_WNDW_ACCESS3:
|
||||
case CS35L41_DSP1_MPU_XREG_ACCESS3:
|
||||
case CS35L41_DSP1_MPU_YREG_ACCESS3:
|
||||
case CS35L41_DSP1_MPU_XM_VIO_ADDR:
|
||||
case CS35L41_DSP1_MPU_XM_VIO_STATUS:
|
||||
case CS35L41_DSP1_MPU_YM_VIO_ADDR:
|
||||
case CS35L41_DSP1_MPU_YM_VIO_STATUS:
|
||||
case CS35L41_DSP1_MPU_PM_VIO_ADDR:
|
||||
case CS35L41_DSP1_MPU_PM_VIO_STATUS:
|
||||
case CS35L41_DSP1_MPU_LOCK_CONFIG:
|
||||
case CS35L41_DSP1_MPU_WDT_RST_CTRL:
|
||||
case CS35L41_OTP_TRIM_1:
|
||||
case CS35L41_OTP_TRIM_2:
|
||||
case CS35L41_OTP_TRIM_3:
|
||||
@ -237,6 +314,13 @@ bool cs35l41_readable_reg(struct device *dev, unsigned int reg)
|
||||
case CS35L41_OTP_TRIM_35:
|
||||
case CS35L41_OTP_TRIM_36:
|
||||
case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31:
|
||||
case CS35L41_DSP1_XMEM_PACK_0 ... CS35L41_DSP1_XMEM_PACK_3068:
|
||||
case CS35L41_DSP1_XMEM_UNPACK32_0 ... CS35L41_DSP1_XMEM_UNPACK32_2046:
|
||||
case CS35L41_DSP1_XMEM_UNPACK24_0 ... CS35L41_DSP1_XMEM_UNPACK24_4093:
|
||||
case CS35L41_DSP1_YMEM_PACK_0 ... CS35L41_DSP1_YMEM_PACK_1532:
|
||||
case CS35L41_DSP1_YMEM_UNPACK32_0 ... CS35L41_DSP1_YMEM_UNPACK32_1022:
|
||||
case CS35L41_DSP1_YMEM_UNPACK24_0 ... CS35L41_DSP1_YMEM_UNPACK24_2045:
|
||||
case CS35L41_DSP1_PMEM_0 ... CS35L41_DSP1_PMEM_5114:
|
||||
/*test regs*/
|
||||
case CS35L41_PLL_OVR:
|
||||
case CS35L41_BST_TEST_DUTY:
|
||||
@ -251,6 +335,9 @@ bool cs35l41_precious_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31:
|
||||
case CS35L41_DSP1_XMEM_PACK_0 ... CS35L41_DSP1_XMEM_PACK_3068:
|
||||
case CS35L41_DSP1_YMEM_PACK_0 ... CS35L41_DSP1_YMEM_PACK_1532:
|
||||
case CS35L41_DSP1_PMEM_0 ... CS35L41_DSP1_PMEM_5114:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -342,6 +429,15 @@ bool cs35l41_volatile_reg(struct device *dev, unsigned int reg)
|
||||
case CS35L41_OTP_TRIM_34:
|
||||
case CS35L41_OTP_TRIM_35:
|
||||
case CS35L41_OTP_TRIM_36:
|
||||
case CS35L41_DSP_MBOX_1 ... CS35L41_DSP_VIRT2_MBOX_8:
|
||||
case CS35L41_DSP1_XMEM_PACK_0 ... CS35L41_DSP1_XMEM_PACK_3068:
|
||||
case CS35L41_DSP1_XMEM_UNPACK32_0 ... CS35L41_DSP1_XMEM_UNPACK32_2046:
|
||||
case CS35L41_DSP1_XMEM_UNPACK24_0 ... CS35L41_DSP1_XMEM_UNPACK24_4093:
|
||||
case CS35L41_DSP1_YMEM_PACK_0 ... CS35L41_DSP1_YMEM_PACK_1532:
|
||||
case CS35L41_DSP1_YMEM_UNPACK32_0 ... CS35L41_DSP1_YMEM_UNPACK32_1022:
|
||||
case CS35L41_DSP1_YMEM_UNPACK24_0 ... CS35L41_DSP1_YMEM_UNPACK24_2045:
|
||||
case CS35L41_DSP1_PMEM_0 ... CS35L41_DSP1_PMEM_5114:
|
||||
case CS35L41_DSP1_CCM_CORE_CTRL ... CS35L41_DSP1_WDT_STATUS:
|
||||
case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31:
|
||||
return true;
|
||||
default:
|
||||
|
@ -197,6 +197,122 @@ static SOC_ENUM_SINGLE_DECL(pcm_sft_ramp,
|
||||
CS35L41_AMP_DIG_VOL_CTRL, 0,
|
||||
cs35l41_pcm_sftramp_text);
|
||||
|
||||
static int cs35l41_dsp_preload_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
int ret;
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
return wm_adsp_early_event(w, kcontrol, event);
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
ret = wm_adsp_early_event(w, kcontrol, event);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return wm_adsp_event(w, kcontrol, event);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
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:
|
||||
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) {
|
||||
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)
|
||||
{
|
||||
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
|
||||
struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(component);
|
||||
unsigned int fw_status;
|
||||
int ret;
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
if (!cs35l41->dsp.cs_dsp.running)
|
||||
return wm_adsp_event(w, kcontrol, event);
|
||||
|
||||
ret = regmap_read(cs35l41->regmap, CS35L41_DSP_MBOX_2, &fw_status);
|
||||
if (ret < 0) {
|
||||
dev_err(cs35l41->dev,
|
||||
"Failed to read firmware status: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (fw_status) {
|
||||
case CSPL_MBOX_STS_RUNNING:
|
||||
case CSPL_MBOX_STS_PAUSED:
|
||||
break;
|
||||
default:
|
||||
dev_err(cs35l41->dev, "Firmware status is invalid: %u\n",
|
||||
fw_status);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return cs35l41_set_cspl_mbox_cmd(cs35l41, CSPL_MBOX_CMD_RESUME);
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
return cs35l41_set_cspl_mbox_cmd(cs35l41, CSPL_MBOX_CMD_PAUSE);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const char * const cs35l41_pcm_source_texts[] = {"ASP", "DSP"};
|
||||
static const unsigned int cs35l41_pcm_source_values[] = {0x08, 0x32};
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_pcm_source_enum,
|
||||
@ -255,6 +371,24 @@ static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_asptx4_enum,
|
||||
static const struct snd_kcontrol_new asp_tx4_mux =
|
||||
SOC_DAPM_ENUM("ASPTX4 SRC", cs35l41_asptx4_enum);
|
||||
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_dsprx1_enum,
|
||||
CS35L41_DSP1_RX1_SRC,
|
||||
0, CS35L41_ASP_SOURCE_MASK,
|
||||
cs35l41_tx_input_texts,
|
||||
cs35l41_tx_input_values);
|
||||
|
||||
static const struct snd_kcontrol_new dsp_rx1_mux =
|
||||
SOC_DAPM_ENUM("DSPRX1 SRC", cs35l41_dsprx1_enum);
|
||||
|
||||
static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_dsprx2_enum,
|
||||
CS35L41_DSP1_RX2_SRC,
|
||||
0, CS35L41_ASP_SOURCE_MASK,
|
||||
cs35l41_tx_input_texts,
|
||||
cs35l41_tx_input_values);
|
||||
|
||||
static const struct snd_kcontrol_new dsp_rx2_mux =
|
||||
SOC_DAPM_ENUM("DSPRX2 SRC", cs35l41_dsprx2_enum);
|
||||
|
||||
static const struct snd_kcontrol_new cs35l41_aud_controls[] = {
|
||||
SOC_SINGLE_SX_TLV("Digital PCM Volume", CS35L41_AMP_DIG_VOL_CTRL,
|
||||
3, 0x4CF, 0x391, dig_vol_tlv),
|
||||
@ -282,6 +416,8 @@ static const struct snd_kcontrol_new cs35l41_aud_controls[] = {
|
||||
CS35L41_AMP_INV_PCM_SHIFT, 1, 0),
|
||||
SOC_SINGLE("Amp Gain ZC", CS35L41_AMP_GAIN_CTRL,
|
||||
CS35L41_AMP_GAIN_ZC_SHIFT, 1, 0),
|
||||
WM_ADSP2_PRELOAD_SWITCH("DSP1", 1),
|
||||
WM_ADSP_FW_CONTROL("DSP1", 0),
|
||||
};
|
||||
|
||||
static const struct cs35l41_otp_map_element_t *cs35l41_find_otp_map(u32 otp_id)
|
||||
@ -603,6 +739,14 @@ static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w,
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_widget cs35l41_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SPK("DSP1 Preload", NULL),
|
||||
SND_SOC_DAPM_SUPPLY_S("DSP1 Preloader", 100, SND_SOC_NOPM, 0, 0,
|
||||
cs35l41_dsp_preload_ev,
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
|
||||
SND_SOC_DAPM_OUT_DRV_E("DSP1", SND_SOC_NOPM, 0, 0, NULL, 0,
|
||||
cs35l41_dsp_audio_ev,
|
||||
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("SPK"),
|
||||
|
||||
SND_SOC_DAPM_AIF_IN("ASPRX1", NULL, 0, CS35L41_SP_ENABLES, 16, 0),
|
||||
@ -618,11 +762,18 @@ static const struct snd_soc_dapm_widget cs35l41_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_SIGGEN("VBST"),
|
||||
SND_SOC_DAPM_SIGGEN("TEMP"),
|
||||
|
||||
SND_SOC_DAPM_ADC("VMON ADC", NULL, CS35L41_PWR_CTRL2, 12, 0),
|
||||
SND_SOC_DAPM_ADC("IMON ADC", NULL, CS35L41_PWR_CTRL2, 13, 0),
|
||||
SND_SOC_DAPM_ADC("VPMON ADC", NULL, CS35L41_PWR_CTRL2, 8, 0),
|
||||
SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, CS35L41_PWR_CTRL2, 9, 0),
|
||||
SND_SOC_DAPM_ADC("TEMPMON ADC", NULL, CS35L41_PWR_CTRL2, 10, 0),
|
||||
SND_SOC_DAPM_SUPPLY("VMON", CS35L41_PWR_CTRL2, 12, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("IMON", CS35L41_PWR_CTRL2, 13, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("VPMON", CS35L41_PWR_CTRL2, 8, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("VBSTMON", CS35L41_PWR_CTRL2, 9, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("TEMPMON", CS35L41_PWR_CTRL2, 10, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_ADC("VMON ADC", NULL, SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_ADC("IMON ADC", NULL, SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_ADC("VPMON ADC", NULL, SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_ADC("TEMPMON ADC", NULL, SND_SOC_NOPM, 0, 0),
|
||||
|
||||
SND_SOC_DAPM_ADC("CLASS H", NULL, CS35L41_PWR_CTRL3, 4, 0),
|
||||
|
||||
SND_SOC_DAPM_OUT_DRV_E("Main AMP", CS35L41_PWR_CTRL2, 0, 0, NULL, 0,
|
||||
@ -633,33 +784,51 @@ static const struct snd_soc_dapm_widget cs35l41_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_MUX("ASP TX2 Source", SND_SOC_NOPM, 0, 0, &asp_tx2_mux),
|
||||
SND_SOC_DAPM_MUX("ASP TX3 Source", SND_SOC_NOPM, 0, 0, &asp_tx3_mux),
|
||||
SND_SOC_DAPM_MUX("ASP TX4 Source", SND_SOC_NOPM, 0, 0, &asp_tx4_mux),
|
||||
SND_SOC_DAPM_MUX("DSP RX1 Source", SND_SOC_NOPM, 0, 0, &dsp_rx1_mux),
|
||||
SND_SOC_DAPM_MUX("DSP RX2 Source", SND_SOC_NOPM, 0, 0, &dsp_rx2_mux),
|
||||
SND_SOC_DAPM_MUX("PCM Source", SND_SOC_NOPM, 0, 0, &pcm_source_mux),
|
||||
SND_SOC_DAPM_SWITCH("DRE", SND_SOC_NOPM, 0, 0, &dre_ctrl),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route cs35l41_audio_map[] = {
|
||||
{"DSP RX1 Source", "ASPRX1", "ASPRX1"},
|
||||
{"DSP RX1 Source", "ASPRX2", "ASPRX2"},
|
||||
{"DSP RX2 Source", "ASPRX1", "ASPRX1"},
|
||||
{"DSP RX2 Source", "ASPRX2", "ASPRX2"},
|
||||
|
||||
{"DSP1", NULL, "DSP RX1 Source"},
|
||||
{"DSP1", NULL, "DSP RX2 Source"},
|
||||
|
||||
{"ASP TX1 Source", "VMON", "VMON ADC"},
|
||||
{"ASP TX1 Source", "IMON", "IMON ADC"},
|
||||
{"ASP TX1 Source", "VPMON", "VPMON ADC"},
|
||||
{"ASP TX1 Source", "VBSTMON", "VBSTMON ADC"},
|
||||
{"ASP TX1 Source", "DSPTX1", "DSP1"},
|
||||
{"ASP TX1 Source", "DSPTX2", "DSP1"},
|
||||
{"ASP TX1 Source", "ASPRX1", "ASPRX1" },
|
||||
{"ASP TX1 Source", "ASPRX2", "ASPRX2" },
|
||||
{"ASP TX2 Source", "VMON", "VMON ADC"},
|
||||
{"ASP TX2 Source", "IMON", "IMON ADC"},
|
||||
{"ASP TX2 Source", "VPMON", "VPMON ADC"},
|
||||
{"ASP TX2 Source", "VBSTMON", "VBSTMON ADC"},
|
||||
{"ASP TX2 Source", "DSPTX1", "DSP1"},
|
||||
{"ASP TX2 Source", "DSPTX2", "DSP1"},
|
||||
{"ASP TX2 Source", "ASPRX1", "ASPRX1" },
|
||||
{"ASP TX2 Source", "ASPRX2", "ASPRX2" },
|
||||
{"ASP TX3 Source", "VMON", "VMON ADC"},
|
||||
{"ASP TX3 Source", "IMON", "IMON ADC"},
|
||||
{"ASP TX3 Source", "VPMON", "VPMON ADC"},
|
||||
{"ASP TX3 Source", "VBSTMON", "VBSTMON ADC"},
|
||||
{"ASP TX3 Source", "DSPTX1", "DSP1"},
|
||||
{"ASP TX3 Source", "DSPTX2", "DSP1"},
|
||||
{"ASP TX3 Source", "ASPRX1", "ASPRX1" },
|
||||
{"ASP TX3 Source", "ASPRX2", "ASPRX2" },
|
||||
{"ASP TX4 Source", "VMON", "VMON ADC"},
|
||||
{"ASP TX4 Source", "IMON", "IMON ADC"},
|
||||
{"ASP TX4 Source", "VPMON", "VPMON ADC"},
|
||||
{"ASP TX4 Source", "VBSTMON", "VBSTMON ADC"},
|
||||
{"ASP TX4 Source", "DSPTX1", "DSP1"},
|
||||
{"ASP TX4 Source", "DSPTX2", "DSP1"},
|
||||
{"ASP TX4 Source", "ASPRX1", "ASPRX1" },
|
||||
{"ASP TX4 Source", "ASPRX2", "ASPRX2" },
|
||||
{"ASPTX1", NULL, "ASP TX1 Source"},
|
||||
@ -671,12 +840,27 @@ static const struct snd_soc_dapm_route cs35l41_audio_map[] = {
|
||||
{"AMP Capture", NULL, "ASPTX3"},
|
||||
{"AMP Capture", NULL, "ASPTX4"},
|
||||
|
||||
{"DSP1", NULL, "VMON"},
|
||||
{"DSP1", NULL, "IMON"},
|
||||
{"DSP1", NULL, "VPMON"},
|
||||
{"DSP1", NULL, "VBSTMON"},
|
||||
{"DSP1", NULL, "TEMPMON"},
|
||||
|
||||
{"VMON ADC", NULL, "VMON"},
|
||||
{"IMON ADC", NULL, "IMON"},
|
||||
{"VPMON ADC", NULL, "VPMON"},
|
||||
{"VBSTMON ADC", NULL, "VBSTMON"},
|
||||
{"TEMPMON ADC", NULL, "TEMPMON"},
|
||||
|
||||
{"VMON ADC", NULL, "VSENSE"},
|
||||
{"IMON ADC", NULL, "ISENSE"},
|
||||
{"VPMON ADC", NULL, "VP"},
|
||||
{"VBSTMON ADC", NULL, "VBST"},
|
||||
{"TEMPMON ADC", NULL, "TEMP"},
|
||||
|
||||
{"DSP1 Preload", NULL, "DSP1 Preloader"},
|
||||
{"DSP1", NULL, "DSP1 Preloader"},
|
||||
|
||||
{"ASPRX1", NULL, "AMP Playback"},
|
||||
{"ASPRX2", NULL, "AMP Playback"},
|
||||
{"DRE", "Switch", "CLASS H"},
|
||||
@ -685,9 +869,18 @@ static const struct snd_soc_dapm_route cs35l41_audio_map[] = {
|
||||
{"SPK", NULL, "Main AMP"},
|
||||
|
||||
{"PCM Source", "ASP", "ASPRX1"},
|
||||
{"PCM Source", "DSP", "DSP1"},
|
||||
{"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_num,
|
||||
unsigned int *tx_slot, unsigned int rx_num,
|
||||
unsigned int *rx_slot)
|
||||
@ -1098,6 +1291,20 @@ static int cs35l41_irq_gpio_config(struct cs35l41_private *cs35l41)
|
||||
return irq_pol;
|
||||
}
|
||||
|
||||
static int cs35l41_component_probe(struct snd_soc_component *component)
|
||||
{
|
||||
struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
return wm_adsp2_component_probe(&cs35l41->dsp, component);
|
||||
}
|
||||
|
||||
static void cs35l41_component_remove(struct snd_soc_component *component)
|
||||
{
|
||||
struct cs35l41_private *cs35l41 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
wm_adsp2_component_remove(&cs35l41->dsp, component);
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops cs35l41_ops = {
|
||||
.startup = cs35l41_pcm_startup,
|
||||
.set_fmt = cs35l41_set_dai_fmt,
|
||||
@ -1131,6 +1338,8 @@ static struct snd_soc_dai_driver cs35l41_dai[] = {
|
||||
|
||||
static const struct snd_soc_component_driver soc_component_dev_cs35l41 = {
|
||||
.name = "cs35l41-codec",
|
||||
.probe = cs35l41_component_probe,
|
||||
.remove = cs35l41_component_remove,
|
||||
|
||||
.dapm_widgets = cs35l41_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(cs35l41_dapm_widgets),
|
||||
@ -1237,6 +1446,90 @@ static const struct reg_sequence cs35l41_revb2_errata_patch[] = {
|
||||
{ 0x00000040, 0x00003333 },
|
||||
};
|
||||
|
||||
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;
|
||||
int ret;
|
||||
|
||||
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->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);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = wm_halo_init(dsp);
|
||||
if (ret) {
|
||||
dev_err(cs35l41->dev, "wm_halo_init failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX5_SRC,
|
||||
CS35L41_INPUT_SRC_VPMON);
|
||||
if (ret < 0) {
|
||||
dev_err(cs35l41->dev, "Write INPUT_SRC_VPMON failed: %d\n", ret);
|
||||
goto err_dsp;
|
||||
}
|
||||
ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX6_SRC,
|
||||
CS35L41_INPUT_SRC_CLASSH);
|
||||
if (ret < 0) {
|
||||
dev_err(cs35l41->dev, "Write INPUT_SRC_CLASSH failed: %d\n", ret);
|
||||
goto err_dsp;
|
||||
}
|
||||
ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX7_SRC,
|
||||
CS35L41_INPUT_SRC_TEMPMON);
|
||||
if (ret < 0) {
|
||||
dev_err(cs35l41->dev, "Write INPUT_SRC_TEMPMON failed: %d\n", ret);
|
||||
goto err_dsp;
|
||||
}
|
||||
ret = regmap_write(cs35l41->regmap, CS35L41_DSP1_RX8_SRC,
|
||||
CS35L41_INPUT_SRC_RSVD);
|
||||
if (ret < 0) {
|
||||
dev_err(cs35l41->dev, "Write INPUT_SRC_RSVD failed: %d\n", ret);
|
||||
goto err_dsp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_dsp:
|
||||
wm_adsp2_remove(dsp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cs35l41_probe(struct cs35l41_private *cs35l41,
|
||||
struct cs35l41_platform_data *pdata)
|
||||
{
|
||||
@ -1413,12 +1706,16 @@ int cs35l41_probe(struct cs35l41_private *cs35l41,
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = cs35l41_dsp_init(cs35l41);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
ret = devm_snd_soc_register_component(cs35l41->dev,
|
||||
&soc_component_dev_cs35l41,
|
||||
cs35l41_dai, ARRAY_SIZE(cs35l41_dai));
|
||||
if (ret < 0) {
|
||||
dev_err(cs35l41->dev, "Register codec failed: %d\n", ret);
|
||||
goto err;
|
||||
goto err_dsp;
|
||||
}
|
||||
|
||||
dev_info(cs35l41->dev, "Cirrus Logic CS35L41 (%x), Revision: %02X\n",
|
||||
@ -1426,6 +1723,8 @@ int cs35l41_probe(struct cs35l41_private *cs35l41,
|
||||
|
||||
return 0;
|
||||
|
||||
err_dsp:
|
||||
wm_adsp2_remove(&cs35l41->dsp);
|
||||
err:
|
||||
regulator_bulk_disable(CS35L41_NUM_SUPPLIES, cs35l41->supplies);
|
||||
gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
|
||||
@ -1436,6 +1735,7 @@ int cs35l41_probe(struct cs35l41_private *cs35l41,
|
||||
void cs35l41_remove(struct cs35l41_private *cs35l41)
|
||||
{
|
||||
regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, 0xFFFFFFFF);
|
||||
wm_adsp2_remove(&cs35l41->dsp);
|
||||
regulator_bulk_disable(CS35L41_NUM_SUPPLIES, cs35l41->supplies);
|
||||
gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
|
||||
}
|
||||
|
@ -13,9 +13,12 @@
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/cs35l41.h>
|
||||
|
||||
#include "wm_adsp.h"
|
||||
|
||||
#define CS35L41_FIRSTREG 0x00000000
|
||||
#define CS35L41_LASTREG 0x03804FE8
|
||||
#define CS35L41_DEVID 0x00000000
|
||||
@ -755,7 +758,24 @@ extern const struct cs35l41_otp_map_element_t
|
||||
|
||||
#define CS35L41_REGSTRIDE 4
|
||||
|
||||
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_UNKNOWN_CMD = -1,
|
||||
CSPL_MBOX_CMD_INVALID_SEQUENCE = -2,
|
||||
};
|
||||
|
||||
struct cs35l41_private {
|
||||
struct wm_adsp dsp; /* needs to be first member */
|
||||
struct snd_soc_codec *codec;
|
||||
struct cs35l41_platform_data pdata;
|
||||
struct device *dev;
|
||||
|
Loading…
Reference in New Issue
Block a user