Browse Source

asoc: wcd937x: add SSR changes for wcd937x codec driver

Add changes to recover audio after SSR on wcd937x driver.

Change-Id: I661605e9b1bd71f08f331d14ae52f89ba8423d4f
Signed-off-by: Rohit kumar <rohitkr@codeaurora.org>
Signed-off-by: Laxminath Kasam <lkasam@codeaurora.org>
Laxminath Kasam 6 years ago
parent
commit
1aab2c064a

+ 2 - 0
asoc/codecs/wcd937x/internal.h

@@ -123,6 +123,8 @@ enum {
 
 enum {
 	BOLERO_WCD_EVT_TX_CH_HOLD_CLEAR = 1,
+	BOLERO_WCD_EVT_SSR_DOWN,
+	BOLERO_WCD_EVT_SSR_UP,
 };
 
 enum {

+ 1 - 0
asoc/codecs/wcd937x/wcd937x-mbhc.c

@@ -974,6 +974,7 @@ int wcd937x_mbhc_post_ssr_init(struct wcd937x_mbhc *mbhc,
 		return -EINVAL;
 	}
 
+	wcd937x_mbhc_hs_detect_exit(codec);
 	wcd_mbhc_deinit(wcd_mbhc);
 	ret = wcd_mbhc_init(wcd_mbhc, codec, &mbhc_cb, &intr_ids,
 			    wcd_mbhc_registers, WCD937X_ZDET_SUPPORTED);

+ 4 - 2
asoc/codecs/wcd937x/wcd937x-regmap.c

@@ -450,8 +450,10 @@ static bool wcd937x_volatile_register(struct device *dev, unsigned int reg)
 {
 	if(reg <= WCD937X_BASE_ADDRESS)
 		return 0;
-	return (wcd937x_reg_access[WCD937X_REG(reg)] & RD_REG)
-		& ~(wcd937x_reg_access[WCD937X_REG(reg)] & WR_REG);
+	if ((wcd937x_reg_access[WCD937X_REG(reg)] & RD_REG)
+		&& !(wcd937x_reg_access[WCD937X_REG(reg)] & WR_REG))
+		return true;
+	return false;
 }
 
 struct regmap_config wcd937x_regmap_config = {

+ 71 - 1
asoc/codecs/wcd937x/wcd937x.c

@@ -48,6 +48,8 @@ static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
 static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
 
 static int wcd937x_handle_post_irq(void *data);
+static int wcd937x_reset(struct device *dev);
+static int wcd937x_reset_low(struct device *dev);
 
 static const struct regmap_irq wcd937x_irqs[WCD937X_NUM_IRQS] = {
 	REGMAP_IRQ_REG(WCD937X_IRQ_MBHC_BUTTON_PRESS_DET, 0, 0x01),
@@ -1216,6 +1218,23 @@ int wcd937x_micbias_control(struct snd_soc_codec *codec,
 }
 EXPORT_SYMBOL(wcd937x_micbias_control);
 
+static int wcd937x_get_logical_addr(struct swr_device *swr_dev)
+{
+	int ret = 0;
+	uint8_t devnum = 0;
+
+	ret = swr_get_logical_dev_num(swr_dev, swr_dev->addr, &devnum);
+	if (ret) {
+		dev_err(&swr_dev->dev,
+			"%s get devnum %d for dev addr %lx failed\n",
+			__func__, devnum, swr_dev->addr);
+		swr_remove_device(swr_dev);
+		return ret;
+	}
+	swr_dev->dev_num = devnum;
+	return 0;
+}
+
 static int wcd937x_event_notify(struct notifier_block *block,
 				unsigned long val,
 				void *data)
@@ -1223,8 +1242,10 @@ static int wcd937x_event_notify(struct notifier_block *block,
 	u16 event = (val & 0xffff);
 	u16 amic = (val >> 0x10);
 	u16 mask = 0x40, reg = 0x0;
+	int ret = 0;
 	struct wcd937x_priv *wcd937x = dev_get_drvdata((struct device *)data);
 	struct snd_soc_codec *codec = wcd937x->codec;
+	struct wcd_mbhc *mbhc;
 
 	switch (event) {
 	case BOLERO_WCD_EVT_TX_CH_HOLD_CLEAR:
@@ -1238,6 +1259,25 @@ static int wcd937x_event_notify(struct notifier_block *block,
 			mask = 0x20;
 		snd_soc_update_bits(codec, reg, mask, 0x00);
 		break;
+	case BOLERO_WCD_EVT_SSR_DOWN:
+		wcd937x_reset_low(wcd937x->dev);
+		break;
+	case BOLERO_WCD_EVT_SSR_UP:
+		wcd937x_reset(wcd937x->dev);
+		wcd937x_get_logical_addr(wcd937x->tx_swr_dev);
+		wcd937x_get_logical_addr(wcd937x->rx_swr_dev);
+		regcache_mark_dirty(wcd937x->regmap);
+		regcache_sync(wcd937x->regmap);
+		/* Initialize MBHC module */
+		mbhc = &wcd937x->mbhc->wcd_mbhc;
+		ret = wcd937x_mbhc_post_ssr_init(wcd937x->mbhc, codec);
+		if (ret) {
+			dev_err(codec->dev, "%s: mbhc initialization failed\n",
+				__func__);
+		} else {
+			wcd937x_mbhc_hs_detect(codec, mbhc->mbhc_cfg);
+		}
+		break;
 	default:
 		dev_err(codec->dev, "%s: invalid event %d\n", __func__, event);
 		break;
@@ -1923,7 +1963,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wcd937x = {
 	},
 };
 
-int wcd937x_reset(struct device *dev)
+static int wcd937x_reset(struct device *dev)
 {
 	struct wcd937x_priv *wcd937x = NULL;
 	int rc = 0;
@@ -2026,6 +2066,36 @@ static void wcd937x_dt_parse_micbias_info(struct device *dev,
 	}
 }
 
+static int wcd937x_reset_low(struct device *dev)
+{
+	struct wcd937x_priv *wcd937x = NULL;
+	int rc = 0;
+
+	if (!dev)
+		return -ENODEV;
+
+	wcd937x = dev_get_drvdata(dev);
+	if (!wcd937x)
+		return -EINVAL;
+
+	if (!wcd937x->rst_np) {
+		dev_err(dev, "%s: reset gpio device node not specified\n",
+				__func__);
+		return -EINVAL;
+	}
+
+	rc = msm_cdc_pinctrl_select_sleep_state(wcd937x->rst_np);
+	if (rc) {
+		dev_err(dev, "%s: wcd sleep state request fail!\n",
+				__func__);
+		return rc;
+	}
+	/* 20ms sleep required after pulling the reset gpio to LOW */
+	usleep_range(20, 30);
+
+	return rc;
+}
+
 struct wcd937x_pdata *wcd937x_populate_dt_data(struct device *dev)
 {
 	struct wcd937x_pdata *pdata = NULL;

+ 18 - 0
asoc/codecs/wcd937x/wcd937x_slave.c

@@ -85,6 +85,21 @@ static const struct component_ops wcd937x_slave_comp_ops = {
 	.unbind = wcd937x_slave_unbind,
 };
 
+static int wcd937x_swr_up(struct swr_device *pdev)
+{
+	return 0;
+}
+
+static int wcd937x_swr_down(struct swr_device *pdev)
+{
+	return 0;
+}
+
+static int wcd937x_swr_reset(struct swr_device *pdev)
+{
+	return 0;
+}
+
 static int wcd937x_swr_probe(struct swr_device *pdev)
 {
 	return component_add(&pdev->dev, &wcd937x_slave_comp_ops);
@@ -105,6 +120,9 @@ static struct swr_driver wcd937x_slave_driver = {
 	.probe = wcd937x_swr_probe,
 	.remove = wcd937x_swr_remove,
 	.id_table = wcd937x_swr_id,
+	.device_up = wcd937x_swr_up,
+	.device_down = wcd937x_swr_down,
+	.reset_device = wcd937x_swr_reset,
 };
 
 static int __init wcd937x_slave_init(void)