Unverified Commit bae9e13f authored by David Rhodes's avatar David Rhodes Committed by Mark Brown
Browse files
parent 0f971060
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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
+96 −0
Original line number Diff line number Diff line
@@ -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:
+306 −6
Original line number Diff line number Diff line
@@ -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);
}
+20 −0
Original line number Diff line number Diff line
@@ -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;