summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sound/soc/codecs/wcd-mbhc-v2.c2
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x-dsd.c47
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x-dsd.h5
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x-mbhc.c35
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x-mbhc.h2
-rw-r--r--sound/soc/codecs/wcd934x/wcd934x.c150
6 files changed, 236 insertions, 5 deletions
diff --git a/sound/soc/codecs/wcd-mbhc-v2.c b/sound/soc/codecs/wcd-mbhc-v2.c
index 3cbc1e7821cf..a1f23685beb5 100644
--- a/sound/soc/codecs/wcd-mbhc-v2.c
+++ b/sound/soc/codecs/wcd-mbhc-v2.c
@@ -2593,6 +2593,8 @@ void wcd_mbhc_deinit(struct wcd_mbhc *mbhc)
if (mbhc->mbhc_cb && mbhc->mbhc_cb->register_notifier)
mbhc->mbhc_cb->register_notifier(mbhc, &mbhc->nblock, false);
mutex_destroy(&mbhc->codec_resource_lock);
+ mutex_destroy(&mbhc->hphl_pa_lock);
+ mutex_destroy(&mbhc->hphr_pa_lock);
}
EXPORT_SYMBOL(wcd_mbhc_deinit);
diff --git a/sound/soc/codecs/wcd934x/wcd934x-dsd.c b/sound/soc/codecs/wcd934x/wcd934x-dsd.c
index 4e3e769585e6..580591a32ba1 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-dsd.c
+++ b/sound/soc/codecs/wcd934x/wcd934x-dsd.c
@@ -619,6 +619,53 @@ static const struct snd_soc_dapm_widget tavil_dsd_widgets[] = {
};
/**
+ * tavil_dsd_post_ssr_init - DSD intialization after subsystem restart
+ *
+ * @codec: pointer to snd_soc_codec
+ *
+ * Returns 0 on success or error on failure
+ */
+int tavil_dsd_post_ssr_init(struct tavil_dsd_config *dsd_conf)
+{
+ struct snd_soc_codec *codec;
+
+ if (!dsd_conf || !dsd_conf->codec)
+ return -EINVAL;
+
+ codec = dsd_conf->codec;
+ /* Disable DSD Interrupts */
+ snd_soc_update_bits(codec, WCD934X_INTR_CODEC_MISC_MASK, 0x08, 0x08);
+
+ /* DSD registers init */
+ if (dsd_conf->version == TAVIL_VERSION_1_0) {
+ snd_soc_update_bits(codec, WCD934X_CDC_DSD0_CFG2, 0x02, 0x00);
+ snd_soc_update_bits(codec, WCD934X_CDC_DSD1_CFG2, 0x02, 0x00);
+ }
+ /* DSD0: Mute EN */
+ snd_soc_update_bits(codec, WCD934X_CDC_DSD0_CFG2, 0x04, 0x04);
+ /* DSD1: Mute EN */
+ snd_soc_update_bits(codec, WCD934X_CDC_DSD1_CFG2, 0x04, 0x04);
+ snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG3, 0x10,
+ 0x10);
+ snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG3, 0x10,
+ 0x10);
+ snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG0, 0x0E,
+ 0x0A);
+ snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG0, 0x0E,
+ 0x0A);
+ snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD0_DEBUG_CFG1, 0x07,
+ 0x04);
+ snd_soc_update_bits(codec, WCD934X_CDC_DEBUG_DSD1_DEBUG_CFG1, 0x07,
+ 0x04);
+
+ /* Enable DSD Interrupts */
+ snd_soc_update_bits(codec, WCD934X_INTR_CODEC_MISC_MASK, 0x08, 0x00);
+
+ return 0;
+}
+EXPORT_SYMBOL(tavil_dsd_post_ssr_init);
+
+/**
* tavil_dsd_init - DSD intialization
*
* @codec: pointer to snd_soc_codec
diff --git a/sound/soc/codecs/wcd934x/wcd934x-dsd.h b/sound/soc/codecs/wcd934x/wcd934x-dsd.h
index 21450c90a272..498288335b3b 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-dsd.h
+++ b/sound/soc/codecs/wcd934x/wcd934x-dsd.h
@@ -55,6 +55,7 @@ void tavil_dsd_set_interp_rate(struct tavil_dsd_config *dsd_conf, u16 rx_port,
u32 sample_rate, u8 sample_rate_val);
struct tavil_dsd_config *tavil_dsd_init(struct snd_soc_codec *codec);
void tavil_dsd_deinit(struct tavil_dsd_config *dsd_config);
+int tavil_dsd_post_ssr_init(struct tavil_dsd_config *dsd_config);
#else
int tavil_dsd_set_mixer_value(struct tavil_dsd_config *dsd_conf,
int interp_num, int sw_value)
@@ -88,5 +89,9 @@ struct tavil_dsd_config *tavil_dsd_init(struct snd_soc_codec *codec)
void tavil_dsd_deinit(struct tavil_dsd_config *dsd_config)
{ }
+int tavil_dsd_post_ssr_init(struct tavil_dsd_config *dsd_config)
+{
+ return 0;
+}
#endif
#endif
diff --git a/sound/soc/codecs/wcd934x/wcd934x-mbhc.c b/sound/soc/codecs/wcd934x/wcd934x-mbhc.c
index b3a30eb10b92..d713edbbb355 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-mbhc.c
+++ b/sound/soc/codecs/wcd934x/wcd934x-mbhc.c
@@ -912,6 +912,37 @@ void tavil_mbhc_hs_detect_exit(struct snd_soc_codec *codec)
EXPORT_SYMBOL(tavil_mbhc_hs_detect_exit);
/*
+ * tavil_mbhc_post_ssr_init: initialize mbhc for tavil post subsystem restart
+ * @mbhc: poniter to wcd934x_mbhc structure
+ * @codec: handle to snd_soc_codec *
+ *
+ * return 0 if mbhc_init is success or error code in case of failure
+ */
+int tavil_mbhc_post_ssr_init(struct wcd934x_mbhc *mbhc,
+ struct snd_soc_codec *codec)
+{
+ int ret;
+
+ if (!mbhc || !codec)
+ return -EINVAL;
+
+ wcd_mbhc_deinit(&mbhc->wcd_mbhc);
+ ret = wcd_mbhc_init(&mbhc->wcd_mbhc, codec, &mbhc_cb, &intr_ids,
+ wcd_mbhc_registers, TAVIL_ZDET_SUPPORTED);
+ if (ret) {
+ dev_err(codec->dev, "%s: mbhc initialization failed\n",
+ __func__);
+ goto done;
+ }
+ snd_soc_update_bits(codec, WCD934X_MBHC_NEW_CTL_1, 0x04, 0x04);
+ snd_soc_update_bits(codec, WCD934X_MBHC_CTL_BCS, 0x01, 0x01);
+
+done:
+ return ret;
+}
+EXPORT_SYMBOL(tavil_mbhc_post_ssr_init);
+
+/*
* tavil_mbhc_init: initialize mbhc for tavil
* @mbhc: poniter to wcd934x_mbhc struct pointer to store the configs
* @codec: handle to snd_soc_codec *
@@ -977,7 +1008,9 @@ void tavil_mbhc_deinit(struct snd_soc_codec *codec)
{
struct wcd934x_mbhc *wcd934x_mbhc = tavil_soc_get_mbhc(codec);
- if (!wcd934x_mbhc)
+ if (wcd934x_mbhc) {
+ wcd_mbhc_deinit(&wcd934x_mbhc->wcd_mbhc);
devm_kfree(codec->dev, wcd934x_mbhc);
+ }
}
EXPORT_SYMBOL(tavil_mbhc_deinit);
diff --git a/sound/soc/codecs/wcd934x/wcd934x-mbhc.h b/sound/soc/codecs/wcd934x/wcd934x-mbhc.h
index 120a7b0f8177..3c88a12194af 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-mbhc.h
+++ b/sound/soc/codecs/wcd934x/wcd934x-mbhc.h
@@ -42,6 +42,8 @@ extern void tavil_mbhc_hs_detect_exit(struct snd_soc_codec *codec);
extern int tavil_mbhc_hs_detect(struct snd_soc_codec *codec,
struct wcd_mbhc_config *mbhc_cfg);
extern void tavil_mbhc_deinit(struct snd_soc_codec *codec);
+extern int tavil_mbhc_post_ssr_init(struct wcd934x_mbhc *mbhc,
+ struct snd_soc_codec *codec);
#endif /* __WCD934X_MBHC_H__ */
diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c
index a526e1afdd28..dc557da07186 100644
--- a/sound/soc/codecs/wcd934x/wcd934x.c
+++ b/sound/soc/codecs/wcd934x/wcd934x.c
@@ -652,6 +652,8 @@ static const struct tavil_reg_mask_val tavil_spkr_mode1[] = {
{WCD934X_CDC_BOOST1_BOOST_CTL, 0x7C, 0x44},
};
+static int __tavil_enable_efuse_sensing(struct tavil_priv *tavil);
+
/*
* wcd934x_get_codec_info: Get codec specific information
*
@@ -4150,7 +4152,8 @@ int tavil_micbias_control(struct snd_soc_codec *codec,
snd_soc_update_bits(codec, micb_reg, 0xC0, 0x80);
break;
case MICB_PULLUP_DISABLE:
- tavil->pullup_ref[micb_index]--;
+ if (tavil->pullup_ref[micb_index] > 0)
+ tavil->pullup_ref[micb_index]--;
if ((tavil->pullup_ref[micb_index] == 0) &&
(tavil->micb_ref[micb_index] == 0))
snd_soc_update_bits(codec, micb_reg, 0xC0, 0x00);
@@ -4170,7 +4173,8 @@ int tavil_micbias_control(struct snd_soc_codec *codec,
post_dapm_on, &tavil->mbhc->wcd_mbhc);
break;
case MICB_DISABLE:
- tavil->micb_ref[micb_index]--;
+ if (tavil->pullup_ref[micb_index] > 0)
+ tavil->micb_ref[micb_index]--;
if ((tavil->micb_ref[micb_index] == 0) &&
(tavil->pullup_ref[micb_index] > 0))
snd_soc_update_bits(codec, micb_reg, 0xC0, 0x80);
@@ -8282,6 +8286,7 @@ static void tavil_cleanup_irqs(struct tavil_priv *tavil)
&wcd9xxx->core_res;
wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, tavil);
+ wcd9xxx_free_irq(core_res, WCD934X_IRQ_MISC, tavil);
}
/*
@@ -8533,6 +8538,129 @@ static void tavil_mclk2_reg_defaults(struct tavil_priv *tavil)
}
}
+static int tavil_device_down(struct wcd9xxx *wcd9xxx)
+{
+ struct snd_soc_codec *codec;
+ struct tavil_priv *priv;
+ int count;
+
+ codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
+ priv = snd_soc_codec_get_drvdata(codec);
+ swrm_wcd_notify(priv->swr.ctrl_data[0].swr_pdev,
+ SWR_DEVICE_DOWN, NULL);
+ tavil_dsd_reset(priv->dsd_config);
+ 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;
+ priv->resmgr->sido_input_src = SIDO_SOURCE_INTERNAL;
+
+ return 0;
+}
+
+static int tavil_post_reset_cb(struct wcd9xxx *wcd9xxx)
+{
+ int i, ret = 0;
+ struct wcd9xxx *control;
+ struct snd_soc_codec *codec;
+ struct tavil_priv *tavil;
+ struct wcd9xxx_pdata *pdata;
+ struct wcd_mbhc *mbhc;
+
+ codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
+ tavil = snd_soc_codec_get_drvdata(codec);
+ control = dev_get_drvdata(codec->dev->parent);
+
+ wcd9xxx_set_power_state(tavil->wcd9xxx,
+ WCD_REGION_POWER_COLLAPSE_REMOVE,
+ WCD9XXX_DIG_CORE_REGION_1);
+
+ mutex_lock(&tavil->codec_mutex);
+ /*
+ * Codec hardware by default comes up in SVS mode.
+ * Initialize the svs_ref_cnt to 1 to reflect the hardware
+ * state in the driver.
+ */
+ tavil->svs_ref_cnt = 1;
+
+ tavil_slimbus_slave_port_cfg.slave_dev_intfdev_la =
+ control->slim_slave->laddr;
+ tavil_slimbus_slave_port_cfg.slave_dev_pgd_la =
+ control->slim->laddr;
+ tavil_init_slim_slave_cfg(codec);
+ snd_soc_card_change_online_state(codec->component.card, 1);
+
+ /* Class-H Init */
+ wcd_clsh_init(&tavil->clsh_d);
+ /* Default HPH Mode to Class-H LOHiFi */
+ tavil->hph_mode = CLS_H_LOHIFI;
+
+ for (i = 0; i < TAVIL_MAX_MICBIAS; i++)
+ tavil->micb_ref[i] = 0;
+
+ for (i = 0; i < COMPANDER_MAX; i++)
+ tavil->comp_enabled[i] = 0;
+
+ dev_dbg(codec->dev, "%s: MCLK Rate = %x\n",
+ __func__, control->mclk_rate);
+
+ if (control->mclk_rate == WCD934X_MCLK_CLK_12P288MHZ)
+ snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
+ 0x03, 0x00);
+ else if (control->mclk_rate == WCD934X_MCLK_CLK_9P6MHZ)
+ snd_soc_update_bits(codec, WCD934X_CODEC_RPM_CLK_MCLK_CFG,
+ 0x03, 0x01);
+ wcd_resmgr_post_ssr_v2(tavil->resmgr);
+ tavil_update_reg_defaults(tavil);
+ tavil_codec_init_reg(tavil);
+ __tavil_enable_efuse_sensing(tavil);
+ tavil_mclk2_reg_defaults(tavil);
+
+ __tavil_cdc_mclk_enable(tavil, true);
+ regcache_mark_dirty(codec->component.regmap);
+ regcache_sync(codec->component.regmap);
+ __tavil_cdc_mclk_enable(tavil, false);
+
+ pdata = dev_get_platdata(codec->dev->parent);
+ ret = tavil_handle_pdata(tavil, pdata);
+ if (IS_ERR_VALUE(ret))
+ dev_err(codec->dev, "%s: invalid pdata\n", __func__);
+
+ /* Initialize MBHC module */
+ mbhc = &tavil->mbhc->wcd_mbhc;
+ ret = tavil_mbhc_post_ssr_init(tavil->mbhc, codec);
+ if (ret) {
+ dev_err(codec->dev, "%s: mbhc initialization failed\n",
+ __func__);
+ goto done;
+ } else {
+ tavil_mbhc_hs_detect(codec, mbhc->mbhc_cfg);
+ }
+
+ /* DSD initialization */
+ ret = tavil_dsd_post_ssr_init(tavil->dsd_config);
+ if (ret)
+ dev_dbg(tavil->dev, "%s: DSD init failed\n", __func__);
+
+ tavil_cleanup_irqs(tavil);
+ ret = tavil_setup_irqs(tavil);
+ if (ret) {
+ dev_err(codec->dev, "%s: tavil irq setup failed %d\n",
+ __func__, ret);
+ goto done;
+ }
+
+ tavil_set_spkr_mode(codec, tavil->swr.spkr_mode);
+ /*
+ * Once the codec initialization is completed, the svs vote
+ * can be released allowing the codec to go to SVS2.
+ */
+ tavil_vote_svs(tavil, false);
+
+done:
+ mutex_unlock(&tavil->codec_mutex);
+ return ret;
+}
+
static int tavil_soc_codec_probe(struct snd_soc_codec *codec)
{
struct wcd9xxx *control;
@@ -8548,8 +8676,12 @@ static int tavil_soc_codec_probe(struct snd_soc_codec *codec)
tavil = snd_soc_codec_get_drvdata(codec);
tavil->intf_type = wcd9xxx_get_intf_type();
+ control->dev_down = tavil_device_down;
+ control->post_reset = tavil_post_reset_cb;
+ control->ssr_priv = (void *)codec;
+
/* Resource Manager post Init */
- ret = wcd_resmgr_post_init(tavil->resmgr, NULL, codec);
+ ret = wcd_resmgr_post_init(tavil->resmgr, &tavil_resmgr_cb, codec);
if (ret) {
dev_err(codec->dev, "%s: wcd resmgr post init failed\n",
__func__);
@@ -9160,6 +9292,7 @@ err_mem:
static int __tavil_enable_efuse_sensing(struct tavil_priv *tavil)
{
int val, rc;
+ struct snd_soc_codec *codec;
__tavil_cdc_mclk_enable(tavil, true);
@@ -9176,8 +9309,17 @@ static int __tavil_enable_efuse_sensing(struct tavil_priv *tavil)
rc = regmap_read(tavil->wcd9xxx->regmap,
WCD934X_CHIP_TIER_CTRL_EFUSE_STATUS, &val);
if (rc || (!(val & 0x01)))
- WARN(1, "%s: Efuse sense is not complete\n", __func__);
+ WARN(1, "%s: Efuse sense is not complete val=%x, ret=%d\n",
+ __func__, val, rc);
+ codec = tavil->codec;
+ if (!codec) {
+ pr_debug("%s: codec is not yet registered\n", __func__);
+ goto done;
+ }
+ tavil_enable_sido_buck(codec);
+
+done:
__tavil_cdc_mclk_enable(tavil, false);
return rc;