[PATCH v1 1/2] ASoC: tac5xx2-sdw: add rev_id 0x30 support

Niranjan H Y <[email protected]>
Newsgroups org.kernel.vger.linux-kernel,org.kernel.vger.linux-sound
Message-ID <[email protected]>
* HID interrupts: SDCA_12/SDCA_17 instead of was SDCA_11/SDCA_16 in
   in older revision.
* UAJ port prepare: write 0xff (jack connected) or 0xdf (disconnected)
  This is required to solve the channel prepare timeout error during
  boot time with the 0x30 silicon.

Signed-off-by: Niranjan H Y <[email protected]>
---
 sound/soc/codecs/tac5xx2-sdw.c | 58 ++++++++++++++++++++++++++++++----
 1 file changed, 51 insertions(+), 7 deletions(-)

diff --git a/sound/soc/codecs/tac5xx2-sdw.c b/sound/soc/codecs/tac5xx2-sdw.c
index ace06f5ab..8fedb5292 100644
--- a/sound/soc/codecs/tac5xx2-sdw.c
+++ b/sound/soc/codecs/tac5xx2-sdw.c
@@ -88,6 +88,9 @@
 #define TAC_FW_FILE_HDR	 20
 #define TAC_MAX_FW_CHUNKS 512
 
+#define TAC_UAJ_PREP_CONNECTED		0xff
+#define TAC_UAJ_PREP_DISCONNECTED	0xdf
+
 struct tac_fw_hdr {
 	u32 size;
 	u32 version_offset;
@@ -138,6 +141,7 @@ struct tac5xx2_prv {
 	bool hw_init;
 	bool first_hw_init_done;
 	u32 part_id;
+	u32 rev_id;
 	struct snd_soc_jack *hs_jack;
 	int jack_type;
 	 /* Custom fw binary. UMP File Download is not used. */
@@ -261,7 +265,6 @@ static const struct reg_default tac_reg_default[] = {
 	{TAC_REG_SDW(0, 0, 0x78), 0x0},
 	{TAC_REG_SDW(0, 0, 0x7b), 0x0},
 	{TAC_REG_SDW(0, 0, 0x7c), 0xd0},
-	{TAC_REG_SDW(0, 0, 0x7d), 0x0},
 	{TAC_REG_SDW(0, 0, 0x7e), 0x0},
 	{TAC_REG_SDW(0, 1, 0x1), 0x0},
 	{TAC_REG_SDW(0, 1, 0x2), 0x0},
@@ -942,6 +945,7 @@ static int tac5xx2_sdca_button_detect(struct tac5xx2_prv *tac_dev)
 static int tac5xx2_sdca_headset_detect(struct tac5xx2_prv *tac_dev)
 {
 	int val, ret;
+	u8 jack_prep;
 
 	ret = regmap_read(tac_dev->regmap,
 			  SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_GE35,
@@ -951,6 +955,8 @@ static int tac5xx2_sdca_headset_detect(struct tac5xx2_prv *tac_dev)
 		return ret;
 	}
 
+	jack_prep = TAC_UAJ_PREP_CONNECTED;
+
 	switch (val) {
 	case 4:
 		tac_dev->jack_type = SND_JACK_MICROPHONE;
@@ -964,6 +970,7 @@ static int tac5xx2_sdca_headset_detect(struct tac5xx2_prv *tac_dev)
 	case 0:
 	default:
 		tac_dev->jack_type = 0;
+		jack_prep = TAC_UAJ_PREP_DISCONNECTED;
 		break;
 	}
 
@@ -973,26 +980,44 @@ static int tac5xx2_sdca_headset_detect(struct tac5xx2_prv *tac_dev)
 	if (ret)
 		dev_err(tac_dev->dev, "Failed to update the jack type to device");
 
+	/*
+	 * When uaj is uplugged and booted, we end up with the channel prepare
+	 * timeout error for the uaj ports. This writes allows the channel prepare
+	 * to succeed when the uaj is not plugged in.
+	 */
+	if (tac_dev->rev_id >= 0x30) {
+		ret = regmap_write(tac_dev->regmap, TAC_REG_SDW(0, 3, 127), jack_prep);
+		if (ret)
+			dev_warn(tac_dev->dev, "Failed to write jack_prep register: %d\n", ret);
+	}
+
 	return 0;
 }
 
 static int tac5xx2_jack_init(struct tac5xx2_prv *tac_dev)
 {
+	u32 jd_int_mask, hid_int_mask;
 	int ret = 0;
 
+	if (tac_dev->rev_id >= 0x30) {
+		jd_int_mask = SDW_SCP_SDCA_INTMASK_SDCA_12;
+		hid_int_mask = SDW_SCP_SDCA_INTMASK_SDCA_17;
+	} else {
+		jd_int_mask = SDW_SCP_SDCA_INTMASK_SDCA_11;
+		hid_int_mask = SDW_SCP_SDCA_INTMASK_SDCA_16;
+	}
+
 	if (!tac_dev->hs_jack)
 		goto disable_interrupts;
 
-	ret = regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK2,
-			   SDW_SCP_SDCA_INTMASK_SDCA_11);
+	ret = regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK2, jd_int_mask);
 	if (ret) {
 		dev_err(tac_dev->dev,
 			"Failed to register jack detection interrupt: %d\n", ret);
 		goto disable_interrupts;
 	}
 
-	ret = regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK3,
-			   SDW_SCP_SDCA_INTMASK_SDCA_16);
+	ret = regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK3, hid_int_mask);
 	if (ret) {
 		dev_err(tac_dev->dev,
 			"Failed to register for button detect interrupt: %d\n", ret);
@@ -1051,6 +1076,7 @@ static int tac_interrupt_callback(struct sdw_slave *slave,
 	unsigned int sdca_int2, sdca_int3, jack_report_mask = 0;
 	struct tac5xx2_prv *tac_dev = dev_get_drvdata(&slave->dev);
 	struct device *dev = &slave->dev;
+	u32 headset_detect_chk, hid_detect_chk;
 	int btn_type = 0;
 	int ret = 0;
 
@@ -1081,14 +1107,22 @@ static int tac_interrupt_callback(struct sdw_slave *slave,
 	dev_dbg(dev, "SDCA_INT2: 0x%02x, SDCA_INT3: 0x%02x\n",
 		sdca_int2, sdca_int3);
 
-	if (sdca_int2 & SDW_SCP_SDCA_INT_SDCA_11) {
+	if (tac_dev->rev_id >= 0x30) {
+		headset_detect_chk = SDW_SCP_SDCA_INT_SDCA_12;
+		hid_detect_chk = SDW_SCP_SDCA_INT_SDCA_17;
+	} else {
+		headset_detect_chk = SDW_SCP_SDCA_INT_SDCA_11;
+		hid_detect_chk = SDW_SCP_SDCA_INT_SDCA_16;
+	}
+
+	if (sdca_int2 & headset_detect_chk) {
 		ret = tac5xx2_sdca_headset_detect(tac_dev);
 		if (ret < 0)
 			goto clear;
 		jack_report_mask |= SND_JACK_HEADSET;
 	}
 
-	if (sdca_int3 & SDW_SCP_SDCA_INT_SDCA_16) {
+	if (sdca_int3 & hid_detect_chk) {
 		btn_type = tac5xx2_sdca_button_detect(tac_dev);
 		if (btn_type < 0)
 			btn_type = 0;
@@ -1695,6 +1729,15 @@ static int tac_io_init(struct device *dev, struct sdw_slave *slave, bool first)
 		goto io_init_err;
 	}
 
+	if (!tac_dev->rev_id) {
+		ret = regmap_read(tac_dev->regmap, TAC_REV_ID, &tac_dev->rev_id);
+		if (ret) {
+			dev_err(tac_dev->dev, "failed to rev id, err=%d\n", ret);
+			goto io_init_err;
+		}
+		dev_dbg(tac_dev->dev, "detected rev_id 0x%x", tac_dev->rev_id);
+	}
+
 	if (tac_dev->fw_files && tac_dev->fw_file_cnt > 0) {
 		ret = tac_download_fw_to_hw(tac_dev);
 		if (ret) {
@@ -1959,6 +2002,7 @@ static s32 tac_sdw_probe(struct sdw_slave *peripheral,
 	tac_dev->hw_init = false;
 	tac_dev->first_hw_init_done = false;
 	tac_dev->part_id = id->part_id;
+	tac_dev->rev_id = 0x0;
 	dev_set_drvdata(dev, tac_dev);
 
 	regmap = devm_regmap_init_sdw_mbq_cfg(&peripheral->dev, peripheral,
-- 
2.34.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.