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 <rschur@codeaurora.org>
This commit is contained in:
Romed Schur
2018-09-24 14:00:24 +02:00
parent 53f339b53b
commit c9f4551452

View File

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