Browse Source

asoc: csra66x0: Fix interrupt in multichannel case

If interrupt indicates a fault in multichannel case,
reset all cluster devices in a specific order.

Change-Id: I077ff65c5f2b5e656fcdf6533fde04eba426e322
Signed-off-by: Romed Schur <[email protected]>
Romed Schur 6 years ago
parent
commit
c9f4551452
1 changed files with 154 additions and 74 deletions
  1. 154 74
      asoc/codecs/csra66x0/csra66x0.c

+ 154 - 74
asoc/codecs/csra66x0/csra66x0.c

@@ -214,6 +214,9 @@ static bool csra66x0_volatile_register(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
 	case CSRA66X0_CHIP_ID_FA:
+	case CSRA66X0_ROM_VER_FA:
+	case CSRA66X0_CHIP_REV_0_FA:
+	case CSRA66X0_CHIP_REV_1_FA:
 	case CSRA66X0_TEMP_READ0_FA:
 	case CSRA66X0_TEMP_READ1_FA:
 	case CSRA66X0_MISC_CONTROL_STATUS_1_FA:
@@ -267,6 +270,20 @@ struct csra66x0_priv {
 #endif /* CONFIG_DEBUG_FS */
 };
 
+struct csra66x0_cluster_device {
+	struct csra66x0_priv *csra66x0_ptr;
+	const char *csra66x0_prefix;
+};
+
+struct csra66x0_cluster_device csra_clust_dev_tbl[] = {
+	{NULL, "CSRA_12"},
+	{NULL, "CSRA_34"},
+	{NULL, "CSRA_56"},
+	{NULL, "CSRA_78"},
+	{NULL, "CSRA_9A"},
+	{NULL, "CSRA_BC"}
+};
+
 #if IS_ENABLED(CONFIG_DEBUG_FS)
 static int debugfs_codec_open_op(struct inode *inode, struct file *file)
 {
@@ -515,9 +532,12 @@ static const struct snd_soc_dapm_route csra66x0_dapm_routes[] = {
 	{"SPKR", NULL, "POWER"},
 };
 
-static int csra66x0_init(struct snd_soc_codec *codec,
-			struct csra66x0_priv *csra66x0)
+static int csra66x0_init(struct csra66x0_priv *csra66x0)
 {
+	struct snd_soc_codec  *codec = csra66x0->codec;
+
+	dev_dbg(codec->dev, "%s: initialize %s\n",
+		__func__, codec->component.name);
 	/* config */
 	snd_soc_write(codec, CSRA66X0_CHIP_STATE_CTRL_FA, CONFIG_STATE);
 	/* settle time in HW is min. 500ms before proceeding */
@@ -565,35 +585,106 @@ static int csra66x0_init(struct snd_soc_codec *codec,
 	return 0;
 }
 
+static int csra66x0_reset(struct csra66x0_priv *csra66x0)
+{
+	struct snd_soc_codec  *codec = csra66x0->codec;
+	u16 val;
+
+	val = snd_soc_read(codec, CSRA66X0_FAULT_STATUS_FA);
+	if (val & FAULT_STATUS_INTERNAL)
+		dev_dbg(codec->dev, "%s: FAULT_STATUS_INTERNAL 0x%X\n",
+			__func__, val);
+	if (val & FAULT_STATUS_OTP_INTEGRITY)
+		dev_dbg(codec->dev, "%s: FAULT_STATUS_OTP_INTEGRITY 0x%X\n",
+			__func__, val);
+	if (val & FAULT_STATUS_PADS2)
+		dev_dbg(codec->dev, "%s: FAULT_STATUS_PADS2 0x%X\n",
+			__func__, val);
+	if (val & FAULT_STATUS_SMPS)
+		dev_dbg(codec->dev, "%s: FAULT_STATUS_SMPS 0x%X\n",
+			__func__, val);
+	if (val & FAULT_STATUS_TEMP)
+		dev_dbg(codec->dev, "%s: FAULT_STATUS_TEMP 0x%X\n",
+			__func__, val);
+	if (val & FAULT_STATUS_PROTECT)
+		dev_dbg(codec->dev, "%s: FAULT_STATUS_PROTECT 0x%X\n",
+			__func__, val);
+
+	dev_dbg(codec->dev, "%s: reset %s\n",
+		__func__, codec->component.name);
+	/* clear fault state and re-init */
+	snd_soc_write(codec, CSRA66X0_FAULT_STATUS_FA, 0x00);
+	snd_soc_write(codec, CSRA66X0_IRQ_OUTPUT_STATUS_FA, 0x00);
+	/* apply reset to CSRA66X0 */
+	val = snd_soc_read(codec, CSRA66X0_MISC_CONTROL_STATUS_1_FA);
+	snd_soc_write(codec, CSRA66X0_MISC_CONTROL_STATUS_1_FA, val | 0x08);
+	/* wait 500ms after reset to recover CSRA66X0 */
+	msleep(500);
+	return 0;
+}
+
+static int csra66x0_msconfig(struct csra66x0_priv *csra66x0)
+{
+	struct snd_soc_codec  *codec = csra66x0->codec;
+
+	dev_dbg(codec->dev, "%s: configure %s\n",
+		__func__, codec->component.name);
+	/* config */
+	snd_soc_write(codec, CSRA66X0_CHIP_STATE_CTRL_FA,
+		CONFIG_STATE);
+	/* settle time in HW is min. 500ms before proceeding */
+	msleep(500);
+	snd_soc_write(codec, CSRA66X0_PIO7_SELECT, 0x04);
+	snd_soc_write(codec, CSRA66X0_PIO8_SELECT, 0x04);
+	if (csra66x0->is_master) {
+		/* Master specific config */
+		snd_soc_write(codec, CSRA66X0_PIO_PULL_EN0, 0xFF);
+		snd_soc_write(codec, CSRA66X0_PIO_PULL_DIR0, 0x80);
+		snd_soc_write(codec, CSRA66X0_PIO_PULL_EN1, 0x01);
+		snd_soc_write(codec, CSRA66X0_PIO_PULL_DIR1, 0x01);
+	} else {
+		/* Slave specific config */
+		snd_soc_write(codec, CSRA66X0_PIO_PULL_EN0, 0x7F);
+		snd_soc_write(codec, CSRA66X0_PIO_PULL_EN1, 0x00);
+	}
+	snd_soc_write(codec, CSRA66X0_DCA_CTRL, 0x05);
+	return 0;
+}
+
 static int csra66x0_soc_probe(struct snd_soc_codec *codec)
 {
 	struct csra66x0_priv *csra66x0 = snd_soc_codec_get_drvdata(codec);
 	struct snd_soc_dapm_context *dapm;
 	char name[50];
+	unsigned int i, max_num_cluster_devices;
 
+	csra66x0->codec = codec;
 	if (csra66x0->in_cluster) {
 		dapm = snd_soc_codec_get_dapm(codec);
 		dev_dbg(codec->dev, "%s: assign prefix %s to codec device %s\n",
 			__func__, codec->component.name_prefix,
 			codec->component.name);
-		snd_soc_write(codec, CSRA66X0_CHIP_STATE_CTRL_FA,
-			CONFIG_STATE);
-		/* settle time in HW is min. 500ms before proceeding */
-		msleep(500);
-		snd_soc_write(codec, CSRA66X0_PIO7_SELECT, 0x04);
-		snd_soc_write(codec, CSRA66X0_PIO8_SELECT, 0x04);
-		if (csra66x0->is_master) {
-			/* Master specific config */
-			snd_soc_write(codec, CSRA66X0_PIO_PULL_EN0, 0xFF);
-			snd_soc_write(codec, CSRA66X0_PIO_PULL_DIR0, 0x80);
-			snd_soc_write(codec, CSRA66X0_PIO_PULL_EN1, 0x01);
-			snd_soc_write(codec, CSRA66X0_PIO_PULL_DIR1, 0x01);
-		} else {
-			/* Slave specific config */
-			snd_soc_write(codec, CSRA66X0_PIO_PULL_EN0, 0x7F);
-			snd_soc_write(codec, CSRA66X0_PIO_PULL_EN1, 0x00);
+
+		/* add device to cluster table */
+		max_num_cluster_devices = sizeof(csra_clust_dev_tbl)/
+			sizeof(csra_clust_dev_tbl[0]);
+		for (i = 0; i < max_num_cluster_devices; i++) {
+			if (!strncmp(codec->component.name_prefix,
+				  csra_clust_dev_tbl[i].csra66x0_prefix,
+				  strlen(
+				  csra_clust_dev_tbl[i].csra66x0_prefix))) {
+				csra_clust_dev_tbl[i].csra66x0_ptr = csra66x0;
+				break;
+			}
+			if (i == max_num_cluster_devices-1)
+				dev_warn(codec->dev,
+					"%s: Unknown prefix %s of cluster device %s\n",
+					__func__, codec->component.name_prefix,
+					codec->component.name);
 		}
-		snd_soc_write(codec, CSRA66X0_DCA_CTRL, 0x05);
+
+		/* master slave config */
+		csra66x0_msconfig(csra66x0);
 		if (dapm->component) {
 			strlcpy(name, dapm->component->name_prefix,
 				sizeof(name));
@@ -606,10 +697,8 @@ static int csra66x0_soc_probe(struct snd_soc_codec *codec)
 		}
 	}
 
-	csra66x0->codec = codec;
-
-	/* common configuration */
-	csra66x0_init(codec, csra66x0);
+	/* common initialization */
+	csra66x0_init(csra66x0);
 	return 0;
 }
 
@@ -679,66 +768,56 @@ static irqreturn_t csra66x0_irq(int irq, void *data)
 	struct csra66x0_priv *csra66x0 = (struct csra66x0_priv *) data;
 	struct snd_soc_codec  *codec = csra66x0->codec;
 	u16    val;
+	unsigned int i, max_num_cluster_devices;
 
 	/* Treat interrupt before codec is initialized as spurious */
 	if (codec == NULL)
 		return IRQ_NONE;
 
-	dev_dbg(codec->dev, "%s: csra66x0_interrupt\n", __func__);
+	dev_dbg(codec->dev, "%s: csra66x0_interrupt triggered by %s\n",
+		__func__, codec->component.name);
 
 	/* fault  indication */
 	val = snd_soc_read(codec, CSRA66X0_IRQ_OUTPUT_STATUS_FA) & 0x1;
-	if (val) {
-		val = snd_soc_read(codec, CSRA66X0_FAULT_STATUS_FA);
-		if (val & FAULT_STATUS_INTERNAL)
-			dev_dbg(codec->dev, "%s: FAULT_STATUS_INTERNAL 0x%X\n",
-				__func__, val);
-		if (val & FAULT_STATUS_OTP_INTEGRITY)
-			dev_dbg(codec->dev, "%s: FAULT_STATUS_OTP_INTEGRITY 0x%X\n",
-				__func__, val);
-		if (val & FAULT_STATUS_PADS2)
-			dev_dbg(codec->dev, "%s: FAULT_STATUS_PADS2 0x%X\n",
-				__func__, val);
-		if (val & FAULT_STATUS_SMPS)
-			dev_dbg(codec->dev, "%s: FAULT_STATUS_SMPS 0x%X\n",
-				__func__, val);
-		if (val & FAULT_STATUS_TEMP)
-			dev_dbg(codec->dev, "%s: FAULT_STATUS_TEMP 0x%X\n",
-				__func__, val);
-		if (val & FAULT_STATUS_PROTECT)
-			dev_dbg(codec->dev, "%s: FAULT_STATUS_PROTECT 0x%X\n",
-				__func__, val);
-
-		/* clear fault state and re-init */
-		snd_soc_write(codec, CSRA66X0_FAULT_STATUS_FA, 0x00);
-		snd_soc_write(codec, CSRA66X0_IRQ_OUTPUT_STATUS_FA, 0x00);
-		/* apply reset to CSRA66X0 */
-		val = snd_soc_read(codec, CSRA66X0_MISC_CONTROL_STATUS_1_FA);
-		snd_soc_write(codec, CSRA66X0_MISC_CONTROL_STATUS_1_FA, val | 0x08);
-		/* wait 2s after reset to recover CSRA66X0 */
-		msleep(2000);
-		/* re-init */
-		snd_soc_write(codec, CSRA66X0_CHIP_STATE_CTRL_FA,
-			CONFIG_STATE);
-		/* settle time in HW is min. 500ms before proceeding */
-		msleep(500);
-		snd_soc_write(codec, CSRA66X0_PIO7_SELECT, 0x04);
-		snd_soc_write(codec, CSRA66X0_PIO8_SELECT, 0x04);
-		if (csra66x0->is_master) {
-			/* Master specific config */
-			snd_soc_write(codec, CSRA66X0_PIO_PULL_EN0, 0xFF);
-			snd_soc_write(codec, CSRA66X0_PIO_PULL_DIR0, 0x80);
-			snd_soc_write(codec, CSRA66X0_PIO_PULL_EN1, 0x01);
-			snd_soc_write(codec, CSRA66X0_PIO_PULL_DIR1, 0x01);
-		} else {
-			/* Slave specific config */
-			snd_soc_write(codec, CSRA66X0_PIO_PULL_EN0, 0x7F);
-			snd_soc_write(codec, CSRA66X0_PIO_PULL_EN1, 0x00);
+	if (!val)
+		return IRQ_HANDLED;
+
+	if (csra66x0->in_cluster) {
+		/* reset all slave codecs */
+		max_num_cluster_devices =
+			sizeof(csra_clust_dev_tbl) /
+			sizeof(csra_clust_dev_tbl[0]);
+		for (i = 0; i < max_num_cluster_devices; i++) {
+			if (i >= codec->component.card->num_aux_devs)
+				break;
+			if (csra_clust_dev_tbl[i].csra66x0_ptr == NULL)
+				continue;
+			if (csra_clust_dev_tbl[i].csra66x0_ptr->is_master)
+				continue;
+			csra66x0_reset(csra_clust_dev_tbl[i].csra66x0_ptr);
+		}
+		/* reset all master codecs */
+		for (i = 0; i < max_num_cluster_devices; i++) {
+			if (i >= codec->component.card->num_aux_devs)
+				break;
+			if (csra_clust_dev_tbl[i].csra66x0_ptr == NULL)
+				continue;
+			if (csra_clust_dev_tbl[i].csra66x0_ptr->is_master)
+				csra66x0_reset(
+					csra_clust_dev_tbl[i].csra66x0_ptr);
+		}
+		/* recover all codecs */
+		for (i = 0; i < max_num_cluster_devices; i++) {
+			if (i >= codec->component.card->num_aux_devs)
+				break;
+			if (csra_clust_dev_tbl[i].csra66x0_ptr == NULL)
+				continue;
+			csra66x0_msconfig(csra_clust_dev_tbl[i].csra66x0_ptr);
+			csra66x0_init(csra_clust_dev_tbl[i].csra66x0_ptr);
 		}
-		snd_soc_write(codec, CSRA66X0_DCA_CTRL, 0x05);
-		csra66x0_init(codec, csra66x0);
 	} else {
-		return IRQ_NONE;
+		csra66x0_reset(csra66x0);
+		csra66x0_init(csra66x0);
 	}
 	return IRQ_HANDLED;
 };
@@ -791,7 +870,8 @@ static int csra66x0_i2c_probe(struct i2c_client *client_i2c,
 			&csra66x0->is_master);
 		if (ret) {
 			dev_info(&client_i2c->dev,
-			"%s: qcom,csra-cluster-master property not defined in DT\n", __func__);
+			"%s: qcom,csra-cluster-master property not defined in DT, slave assumed\n",
+			__func__);
 			csra66x0->is_master = 0;
 		}