|
@@ -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;
|
|
|
}
|
|
|
|