Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0468c753 authored by Banajit Goswami's avatar Banajit Goswami
Browse files

ASoC: wcd9335: add support for ADSP sub-system restart



Enable support for ADSP sub-system restart feature on
WCD9335 codec.

Change-Id: I113ba4d7c07562c8327df05603e7370b3247f3fb
Signed-off-by: default avatarFred Oh <fred@codeaurora.org>
Signed-off-by: default avatarBanajit Goswami <bgoswami@codeaurora.org>
parent f47b4920
Loading
Loading
Loading
Loading
+159 −5
Original line number Diff line number Diff line
@@ -598,6 +598,9 @@ struct tasha_priv {
	struct snd_info_entry *entry;
	struct snd_info_entry *version_entry;
	int power_active_ref;

	int (*machine_codec_event_cb)(struct snd_soc_codec *codec,
				      enum wcd9335_codec_event);
};

int tasha_enable_efuse_sensing(struct snd_soc_codec *codec)
@@ -650,6 +653,31 @@ void *tasha_get_afe_config(struct snd_soc_codec *codec,
}
EXPORT_SYMBOL(tasha_get_afe_config);

/*
 * tasha_event_register: Registers a machine driver callback
 * function with codec private data for post ADSP sub-system
 * restart (SSR). This callback function will be called from
 * codec driver once codec comes out of reset after ADSP SSR.
 *
 * @machine_event_cb: callback function from machine driver
 * @codec: Codec instance
 *
 * Return: none
 */
void tasha_event_register(
	int (*machine_event_cb)(struct snd_soc_codec *codec,
				enum wcd9335_codec_event),
	struct snd_soc_codec *codec)
{
	struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);

	if (tasha)
		tasha->machine_codec_event_cb = machine_event_cb;
	else
		dev_dbg(codec->dev, "%s: Invalid tasha_priv data\n", __func__);
}
EXPORT_SYMBOL(tasha_event_register);

static int tasha_mbhc_request_irq(struct snd_soc_codec *codec,
				   int irq, irq_handler_t handler,
				   const char *name, void *data)
@@ -2014,6 +2042,7 @@ static int tasha_codec_enable_slimrx(struct snd_soc_dapm_widget *w,

	switch (event) {
	case SND_SOC_DAPM_POST_PMU:
		dai->bus_down_in_recovery = false;
		tasha_codec_enable_int_port(dai, codec);
		(void) tasha_codec_enable_slim_chmask(dai, true);
		ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
@@ -2027,7 +2056,12 @@ static int tasha_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
			__func__, ret);
		ret = wcd9xxx_close_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
						dai->grph);
		if (!dai->bus_down_in_recovery)
			ret = tasha_codec_enable_slim_chmask(dai, false);
		else
			dev_dbg(codec->dev,
				"%s: bus in recovery skip enable slim_chmask",
				__func__);
		break;
	}
	return ret;
@@ -2100,6 +2134,7 @@ static int tasha_codec_enable_slimvi_feedback(struct snd_soc_dapm_widget *w,
				WCD9335_CDC_TX12_SPKR_PROT_PATH_CTL, 0x10,
				0x10);
		}
		dai->bus_down_in_recovery = false;
		tasha_codec_enable_int_port(dai, codec);
		(void) tasha_codec_enable_slim_chmask(dai, true);
		ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
@@ -2112,6 +2147,7 @@ static int tasha_codec_enable_slimvi_feedback(struct snd_soc_dapm_widget *w,
		if (ret)
			dev_err(codec->dev, "%s error in close_slim_sch_tx %d\n",
				__func__, ret);
		if (!dai->bus_down_in_recovery)
			ret = tasha_codec_enable_slim_chmask(dai, false);
		if (ret < 0) {
			ret = wcd9xxx_disconnect_port(core,
@@ -2169,6 +2205,7 @@ static int __tasha_codec_enable_slimtx(struct snd_soc_codec *codec,

	switch (event) {
	case SND_SOC_DAPM_POST_PMU:
		dai->bus_down_in_recovery = false;
		tasha_codec_enable_int_port(dai, codec);
		(void) tasha_codec_enable_slim_chmask(dai, true);
		ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
@@ -2178,6 +2215,7 @@ static int __tasha_codec_enable_slimtx(struct snd_soc_codec *codec,
	case SND_SOC_DAPM_POST_PMD:
		ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
						dai->grph);
		if (!dai->bus_down_in_recovery)
			ret = tasha_codec_enable_slim_chmask(dai, false);
		if (ret < 0) {
			ret = wcd9xxx_disconnect_port(core,
@@ -9189,6 +9227,116 @@ static int tasha_cpe_initialize(struct snd_soc_codec *codec)
	return 0;
}

static const struct wcd_resmgr_cb tasha_resmgr_cb = {
	.cdc_rco_ctrl = tasha_codec_internal_rco_ctrl,
};

static int tasha_device_down(struct wcd9xxx *wcd9xxx)
{
	struct snd_soc_codec *codec;
	struct tasha_priv *priv;
	int count;

	codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
	priv = snd_soc_codec_get_drvdata(codec);
	wcd_cpe_ssr_event(priv->cpe_core, WCD_CPE_BUS_DOWN_EVENT);
	snd_soc_card_change_online_state(codec->component.card, 0);
	for (count = 0; count < NUM_CODEC_DAIS; count++)
		priv->dai[count].bus_down_in_recovery = true;

	return 0;
}

static int tasha_post_reset_cb(struct wcd9xxx *wcd9xxx)
{
	int i, ret = 0;
	struct wcd9xxx *control;
	struct snd_soc_codec *codec;
	struct tasha_priv *tasha;
	struct wcd9xxx_pdata *pdata;

	codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
	tasha = snd_soc_codec_get_drvdata(codec);
	control = dev_get_drvdata(codec->dev->parent);

	wcd9xxx_set_power_state(tasha->wcd9xxx,
				WCD_REGION_POWER_COLLAPSE_REMOVE,
				WCD9XXX_DIG_CORE_REGION_1);
	snd_soc_card_change_online_state(codec->component.card, 1);

	mutex_lock(&codec->mutex);

	/* Class-H Init*/
	wcd_clsh_init(&tasha->clsh_d);
	/* Default HPH Mode to Class-H HiFi */
	tasha->hph_mode = CLS_H_HIFI;

	tasha_update_reg_defaults(tasha);

	tasha->codec = codec;
	for (i = 0; i < COMPANDER_MAX; i++)
		tasha->comp_enabled[i] = 0;

	dev_dbg(codec->dev, "%s: MCLK Rate = %x\n",
		__func__, control->mclk_rate);

	if (control->mclk_rate == TASHA_MCLK_CLK_12P288MHZ)
		snd_soc_update_bits(codec, WCD9335_CODEC_RPM_CLK_MCLK_CFG,
				    0x03, 0x00);
	else if (control->mclk_rate == TASHA_MCLK_CLK_9P6MHZ)
		snd_soc_update_bits(codec, WCD9335_CODEC_RPM_CLK_MCLK_CFG,
				    0x03, 0x01);
	tasha_codec_init_reg(codec);

	regcache_mark_dirty(codec->component.regmap);
	regcache_sync(codec->component.regmap);

	pdata = dev_get_platdata(codec->dev->parent);
	ret = tasha_handle_pdata(tasha, pdata);
	if (IS_ERR_VALUE(ret))
		dev_err(codec->dev, "%s: invalid pdata\n", __func__);

	tasha_slimbus_slave_port_cfg.slave_dev_intfdev_la =
		control->slim_slave->laddr;
	tasha_slimbus_slave_port_cfg.slave_dev_pgd_la =
		control->slim->laddr;
	tasha_init_slim_slave_cfg(codec);

	wcd_resmgr_post_ssr_v2(tasha->resmgr);

	/* MBHC Init */
	wcd_mbhc_deinit(&tasha->mbhc);
	tasha->mbhc_started = false;

	/* Initialize MBHC module */
	ret = wcd_mbhc_init(&tasha->mbhc, codec, &mbhc_cb, &intr_ids,
		      wcd_mbhc_registers, TASHA_ZDET_SUPPORTED);
	if (ret)
		dev_err(codec->dev, "%s: mbhc initialization failed\n",
			__func__);
	else
		tasha_mbhc_hs_detect(codec, tasha->mbhc.mbhc_cfg);

	if (tasha->machine_codec_event_cb)
		tasha->machine_codec_event_cb(codec,
				       WCD9335_CODEC_EVENT_CODEC_UP);

	tasha_cleanup_irqs(tasha);
	ret = tasha_setup_irqs(tasha);
	if (ret) {
		dev_err(codec->dev, "%s: tasha irq setup failed %d\n",
			__func__, ret);
		goto err;
	}

	tasha_enable_efuse_sensing(codec);
	wcd_cpe_ssr_event(tasha->cpe_core, WCD_CPE_BUS_UP_EVENT);

err:
	mutex_unlock(&codec->mutex);
	return ret;
}

static int tasha_codec_probe(struct snd_soc_codec *codec)
{
	struct wcd9xxx *control;
@@ -9202,9 +9350,16 @@ static int tasha_codec_probe(struct snd_soc_codec *codec)

	dev_info(codec->dev, "%s()\n", __func__);
	tasha = snd_soc_codec_get_drvdata(codec);
	tasha->intf_type = wcd9xxx_get_intf_type();

	if (tasha->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
		control->dev_down = tasha_device_down;
		control->post_reset = tasha_post_reset_cb;
		control->ssr_priv = (void *)codec;
	}

	/* Resource Manager post Init */
	ret = wcd_resmgr_post_init(tasha->resmgr, codec);
	ret = wcd_resmgr_post_init(tasha->resmgr, &tasha_resmgr_cb, codec);
	if (ret) {
		dev_err(codec->dev, "%s: wcd resmgr post init failed\n",
			__func__);
@@ -9220,7 +9375,6 @@ static int tasha_codec_probe(struct snd_soc_codec *codec)
		tasha->comp_enabled[i] = 0;

	tasha_update_reg_reset_values(codec);
	tasha->intf_type = wcd9xxx_get_intf_type();
	pr_debug("%s: MCLK Rate = %x\n", __func__, control->mclk_rate);
	if (control->mclk_rate == TASHA_MCLK_CLK_12P288MHZ)
		snd_soc_update_bits(codec, WCD9335_CODEC_RPM_CLK_MCLK_CFG,
+8 −0
Original line number Diff line number Diff line
@@ -75,6 +75,10 @@ enum {
	TASHA_TX_MAX,
};

enum wcd9335_codec_event {
	WCD9335_CODEC_EVENT_CODEC_UP = 0,
};

/* Dai data structure holds the
 * dai specific info like rate,
 * channel number etc.
@@ -108,4 +112,8 @@ extern void tasha_mbhc_zdet_gpio_ctrl(
		struct snd_soc_codec *codec);
extern int tasha_codec_info_create_codec_entry(struct snd_info_entry *,
					       struct snd_soc_codec *);
extern void tasha_event_register(
	int (*machine_event_cb)(struct snd_soc_codec *codec,
				enum wcd9335_codec_event),
	struct snd_soc_codec *codec);
#endif
+3 −3
Original line number Diff line number Diff line
@@ -22,7 +22,7 @@

#define WCD_USLEEP_RANGE 50

static void (*clsh_state_fp[NUM_CLSH_STATES])(struct snd_soc_codec *,
static void (*clsh_state_fp[NUM_CLSH_STATES_V2])(struct snd_soc_codec *,
					      struct wcd_clsh_cdc_data *,
					      u8 req_state, bool en, int mode);

@@ -725,7 +725,7 @@ void wcd_clsh_fsm(struct snd_soc_codec *codec,
	case WCD_CLSH_EVENT_POST_PA:
		old_state = cdc_clsh_d->state;
		new_state = old_state & (~req_state);
		if (new_state < NUM_CLSH_STATES) {
		if (new_state < NUM_CLSH_STATES_V2) {
			if (!wcd_clsh_is_state_valid(old_state)) {
				dev_err(codec->dev,
					"%s:Invalid old state:%s\n",
@@ -762,7 +762,7 @@ void wcd_clsh_init(struct wcd_clsh_cdc_data *clsh)
	int i;
	clsh->state = WCD_CLSH_STATE_IDLE;

	for (i = 0; i < NUM_CLSH_STATES; i++)
	for (i = 0; i < NUM_CLSH_STATES_V2; i++)
		clsh_state_fp[i] = wcd_clsh_state_err;

	clsh_state_fp[WCD_CLSH_STATE_EAR] = wcd_clsh_state_ear;
+1 −1
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@
#define	WCD_CLSH_STATE_HPHR (0x01 << 2)
#define	WCD_CLSH_STATE_LO (0x01 << 3)
#define WCD_CLSH_STATE_MAX 4
#define NUM_CLSH_STATES (0x01 << WCD_CLSH_STATE_MAX)
#define NUM_CLSH_STATES_V2 (0x01 << WCD_CLSH_STATE_MAX)


/* Derived State: Bits 1 and 2 should be set for Headphone stereo */
+55 −0
Original line number Diff line number Diff line
@@ -58,6 +58,59 @@ int wcd_resmgr_get_clk_type(struct wcd9xxx_resmgr_v2 *resmgr)
	return resmgr->clk_type;
}

static void wcd_resmgr_cdc_specific_get_clk(struct wcd9xxx_resmgr_v2 *resmgr,
						int clk_users)
{
	/* Caller of this function should have acquired BG_CLK lock */
	WCD9XXX_V2_BG_CLK_UNLOCK(resmgr);
	if (clk_users) {
		if (resmgr->resmgr_cb &&
		    resmgr->resmgr_cb->cdc_rco_ctrl) {
			while (clk_users--)
				resmgr->resmgr_cb->cdc_rco_ctrl(resmgr->codec,
								true);
		}
	}
	/* Acquire BG_CLK lock before return */
	WCD9XXX_V2_BG_CLK_LOCK(resmgr);
}

void wcd_resmgr_post_ssr_v2(struct wcd9xxx_resmgr_v2 *resmgr)
{
	int old_bg_audio_users;
	int old_clk_rco_users, old_clk_mclk_users;

	WCD9XXX_V2_BG_CLK_LOCK(resmgr);

	old_bg_audio_users = resmgr->master_bias_users;
	old_clk_mclk_users = resmgr->clk_mclk_users;
	old_clk_rco_users = resmgr->clk_rco_users;
	resmgr->master_bias_users = 0;
	resmgr->clk_mclk_users = 0;
	resmgr->clk_rco_users = 0;
	resmgr->clk_type = WCD_CLK_OFF;

	pr_debug("%s: old_bg_audio_users=%d old_clk_mclk_users=%d old_clk_rco_users=%d\n",
		 __func__, old_bg_audio_users,
		 old_clk_mclk_users, old_clk_rco_users);

	if (old_bg_audio_users) {
		while (old_bg_audio_users--)
			wcd_resmgr_enable_master_bias(resmgr);
	}

	if (old_clk_mclk_users) {
		while (old_clk_mclk_users--)
			wcd_resmgr_enable_clk_block(resmgr, WCD_CLK_MCLK);
	}

	if (old_clk_rco_users)
		wcd_resmgr_cdc_specific_get_clk(resmgr, old_clk_rco_users);

	WCD9XXX_V2_BG_CLK_UNLOCK(resmgr);
}


/*
 * wcd_resmgr_enable_master_bias: enable codec master bias
 * @resmgr: handle to struct wcd9xxx_resmgr_v2
@@ -388,9 +441,11 @@ void wcd_resmgr_remove(struct wcd9xxx_resmgr_v2 *resmgr)
/*
 * wcd_resmgr_post_init: post init call to assign codec handle
 * @resmgr: handle to struct wcd9xxx_resmgr_v2 created during early init
 * @resmgr_cb: codec callback function for resmgr
 * @codec: handle to struct snd_soc_codec
 */
int wcd_resmgr_post_init(struct wcd9xxx_resmgr_v2 *resmgr,
			 const struct wcd_resmgr_cb *resmgr_cb,
			 struct snd_soc_codec *codec)
{
	if (!resmgr) {
Loading