Commit caf7c1f1 authored by Stefan Binding's avatar Stefan Binding Committed by Takashi Iwai
Browse files

ASoC: cs35l41: Move cs35l41_set_cspl_mbox_cmd to shared code



This function is used to control the DSP Firmware for cs35l41,
and will be needed by the cs35l41 hda driver, when firmware
support is added.

Signed-off-by: default avatarStefan Binding <sbinding@opensource.cirrus.com>
Signed-off-by: default avatarVitaly Rodionov <vitalyr@opensource.cirrus.com>
Acked-by: default avatarCharles Keepax <ckeepax@opensource.cirrus.com>
Link: https://lore.kernel.org/r/20220509214703.4482-7-vitalyr@opensource.cirrus.com


Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent de8cab7b
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -801,6 +801,24 @@ 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
 */
@@ -859,6 +877,8 @@ 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_gpio_config(struct regmap *regmap, struct cs35l41_hw_cfg *hw_cfg);
int cs35l41_set_cspl_mbox_cmd(struct device *dev, struct regmap *regmap,
			      enum cs35l41_cspl_mbox_cmd cmd);
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);
+57 −0
Original line number Diff line number Diff line
@@ -1206,6 +1206,63 @@ int cs35l41_gpio_config(struct regmap *regmap, struct cs35l41_hw_cfg *hw_cfg)
}
EXPORT_SYMBOL_GPL(cs35l41_gpio_config);

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);

MODULE_DESCRIPTION("CS35L41 library");
MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, <david.rhodes@cirrus.com>");
MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, <tanureal@opensource.cirrus.com>");
+5 −64
Original line number Diff line number Diff line
@@ -208,67 +208,6 @@ static int cs35l41_dsp_preload_ev(struct snd_soc_dapm_widget *w,
	}
}

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)
{
@@ -299,9 +238,11 @@ static int cs35l41_dsp_audio_ev(struct snd_soc_dapm_widget *w,
			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;
	}
@@ -1475,7 +1416,7 @@ static int cs35l41_exit_hibernate(struct cs35l41_private *cs35l41)
		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;
+0 −18
Original line number Diff line number Diff line
@@ -23,24 +23,6 @@

extern const struct dev_pm_ops cs35l41_pm_ops;

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,
};

struct cs35l41_private {
	struct wm_adsp dsp; /* needs to be first member */
	struct snd_soc_codec *codec;