aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCharles Keepax <ckeepax@opensource.wolfsonmicro.com>2017-03-17 11:44:55 -0400
committerMark Brown <broonie@kernel.org>2017-03-17 17:40:31 -0400
commit5d3d0ad688eacf9567d7d67a5eec3c436cc1064c (patch)
treeab16d17469e43309973a6499fb6659ff36ed8e3d
parentbfe41c678d49f440de3ae80b945f7f94d5dbd340 (diff)
ASoC: cs35l35: Stash dev pointer directly rather than CODEC pointer
The driver stashes a CODEC pointer in the cs35l35_private structure, which is used to obtain a struct device pointer for error messages in the interrupt handler. However, doing so is not very safe as the interrupt is registered, as it should be in bus probe, but the CODEC pointer can't be safely stored until the ASoC level probe. This leaves a window between the two probes where if any interrupts are received a NULL pointer will be deferenced in the IRQ handler. Fix this issue by saving a pointer to the device directly and passing that to the error messages in the interrupt handler rather than using the CODEC pointer to access the device pointer. Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/codecs/cs35l35.c29
-rw-r--r--sound/soc/codecs/cs35l35.h2
2 files changed, 15 insertions, 16 deletions
diff --git a/sound/soc/codecs/cs35l35.c b/sound/soc/codecs/cs35l35.c
index 05117fca7e3c..1d9f332b2eec 100644
--- a/sound/soc/codecs/cs35l35.c
+++ b/sound/soc/codecs/cs35l35.c
@@ -741,8 +741,6 @@ static int cs35l35_codec_probe(struct snd_soc_codec *codec)
741 struct monitor_cfg *monitor_config = &cs35l35->pdata.mon_cfg; 741 struct monitor_cfg *monitor_config = &cs35l35->pdata.mon_cfg;
742 int ret; 742 int ret;
743 743
744 cs35l35->codec = codec;
745
746 /* Set Platform Data */ 744 /* Set Platform Data */
747 if (cs35l35->pdata.bst_vctl) 745 if (cs35l35->pdata.bst_vctl)
748 regmap_update_bits(cs35l35->regmap, CS35L35_BST_CVTR_V_CTL, 746 regmap_update_bits(cs35l35->regmap, CS35L35_BST_CVTR_V_CTL,
@@ -1004,7 +1002,6 @@ static struct regmap_config cs35l35_regmap = {
1004static irqreturn_t cs35l35_irq(int irq, void *data) 1002static irqreturn_t cs35l35_irq(int irq, void *data)
1005{ 1003{
1006 struct cs35l35_private *cs35l35 = data; 1004 struct cs35l35_private *cs35l35 = data;
1007 struct snd_soc_codec *codec = cs35l35->codec;
1008 unsigned int sticky1, sticky2, sticky3, sticky4; 1005 unsigned int sticky1, sticky2, sticky3, sticky4;
1009 unsigned int mask1, mask2, mask3, mask4, current1; 1006 unsigned int mask1, mask2, mask3, mask4, current1;
1010 1007
@@ -1032,7 +1029,7 @@ static irqreturn_t cs35l35_irq(int irq, void *data)
1032 1029
1033 /* handle the interrupts */ 1030 /* handle the interrupts */
1034 if (sticky1 & CS35L35_CAL_ERR) { 1031 if (sticky1 & CS35L35_CAL_ERR) {
1035 dev_crit(codec->dev, "Calibration Error\n"); 1032 dev_crit(cs35l35->dev, "Calibration Error\n");
1036 1033
1037 /* error is no longer asserted; safe to reset */ 1034 /* error is no longer asserted; safe to reset */
1038 if (!(current1 & CS35L35_CAL_ERR)) { 1035 if (!(current1 & CS35L35_CAL_ERR)) {
@@ -1051,10 +1048,10 @@ static irqreturn_t cs35l35_irq(int irq, void *data)
1051 } 1048 }
1052 1049
1053 if (sticky1 & CS35L35_AMP_SHORT) { 1050 if (sticky1 & CS35L35_AMP_SHORT) {
1054 dev_crit(codec->dev, "AMP Short Error\n"); 1051 dev_crit(cs35l35->dev, "AMP Short Error\n");
1055 /* error is no longer asserted; safe to reset */ 1052 /* error is no longer asserted; safe to reset */
1056 if (!(current1 & CS35L35_AMP_SHORT)) { 1053 if (!(current1 & CS35L35_AMP_SHORT)) {
1057 dev_dbg(codec->dev, "Amp short error release\n"); 1054 dev_dbg(cs35l35->dev, "Amp short error release\n");
1058 regmap_update_bits(cs35l35->regmap, 1055 regmap_update_bits(cs35l35->regmap,
1059 CS35L35_PROT_RELEASE_CTL, 1056 CS35L35_PROT_RELEASE_CTL,
1060 CS35L35_SHORT_RLS, 0); 1057 CS35L35_SHORT_RLS, 0);
@@ -1069,11 +1066,11 @@ static irqreturn_t cs35l35_irq(int irq, void *data)
1069 } 1066 }
1070 1067
1071 if (sticky1 & CS35L35_OTW) { 1068 if (sticky1 & CS35L35_OTW) {
1072 dev_warn(codec->dev, "Over temperature warning\n"); 1069 dev_warn(cs35l35->dev, "Over temperature warning\n");
1073 1070
1074 /* error is no longer asserted; safe to reset */ 1071 /* error is no longer asserted; safe to reset */
1075 if (!(current1 & CS35L35_OTW)) { 1072 if (!(current1 & CS35L35_OTW)) {
1076 dev_dbg(codec->dev, "Over temperature warn release\n"); 1073 dev_dbg(cs35l35->dev, "Over temperature warn release\n");
1077 regmap_update_bits(cs35l35->regmap, 1074 regmap_update_bits(cs35l35->regmap,
1078 CS35L35_PROT_RELEASE_CTL, 1075 CS35L35_PROT_RELEASE_CTL,
1079 CS35L35_OTW_RLS, 0); 1076 CS35L35_OTW_RLS, 0);
@@ -1088,10 +1085,10 @@ static irqreturn_t cs35l35_irq(int irq, void *data)
1088 } 1085 }
1089 1086
1090 if (sticky1 & CS35L35_OTE) { 1087 if (sticky1 & CS35L35_OTE) {
1091 dev_crit(codec->dev, "Over temperature error\n"); 1088 dev_crit(cs35l35->dev, "Over temperature error\n");
1092 /* error is no longer asserted; safe to reset */ 1089 /* error is no longer asserted; safe to reset */
1093 if (!(current1 & CS35L35_OTE)) { 1090 if (!(current1 & CS35L35_OTE)) {
1094 dev_dbg(codec->dev, "Over temperature error release\n"); 1091 dev_dbg(cs35l35->dev, "Over temperature error release\n");
1095 regmap_update_bits(cs35l35->regmap, 1092 regmap_update_bits(cs35l35->regmap,
1096 CS35L35_PROT_RELEASE_CTL, 1093 CS35L35_PROT_RELEASE_CTL,
1097 CS35L35_OTE_RLS, 0); 1094 CS35L35_OTE_RLS, 0);
@@ -1106,7 +1103,7 @@ static irqreturn_t cs35l35_irq(int irq, void *data)
1106 } 1103 }
1107 1104
1108 if (sticky3 & CS35L35_BST_HIGH) { 1105 if (sticky3 & CS35L35_BST_HIGH) {
1109 dev_crit(codec->dev, "VBST error: powering off!\n"); 1106 dev_crit(cs35l35->dev, "VBST error: powering off!\n");
1110 regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 1107 regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2,
1111 CS35L35_PDN_AMP, CS35L35_PDN_AMP); 1108 CS35L35_PDN_AMP, CS35L35_PDN_AMP);
1112 regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 1109 regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1,
@@ -1114,7 +1111,7 @@ static irqreturn_t cs35l35_irq(int irq, void *data)
1114 } 1111 }
1115 1112
1116 if (sticky3 & CS35L35_LBST_SHORT) { 1113 if (sticky3 & CS35L35_LBST_SHORT) {
1117 dev_crit(codec->dev, "LBST error: powering off!\n"); 1114 dev_crit(cs35l35->dev, "LBST error: powering off!\n");
1118 regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2, 1115 regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL2,
1119 CS35L35_PDN_AMP, CS35L35_PDN_AMP); 1116 CS35L35_PDN_AMP, CS35L35_PDN_AMP);
1120 regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1, 1117 regmap_update_bits(cs35l35->regmap, CS35L35_PWRCTL1,
@@ -1122,13 +1119,13 @@ static irqreturn_t cs35l35_irq(int irq, void *data)
1122 } 1119 }
1123 1120
1124 if (sticky2 & CS35L35_VPBR_ERR) 1121 if (sticky2 & CS35L35_VPBR_ERR)
1125 dev_dbg(codec->dev, "Error: Reactive Brownout\n"); 1122 dev_dbg(cs35l35->dev, "Error: Reactive Brownout\n");
1126 1123
1127 if (sticky4 & CS35L35_VMON_OVFL) 1124 if (sticky4 & CS35L35_VMON_OVFL)
1128 dev_dbg(codec->dev, "Error: VMON overflow\n"); 1125 dev_dbg(cs35l35->dev, "Error: VMON overflow\n");
1129 1126
1130 if (sticky4 & CS35L35_IMON_OVFL) 1127 if (sticky4 & CS35L35_IMON_OVFL)
1131 dev_dbg(codec->dev, "Error: IMON overflow\n"); 1128 dev_dbg(cs35l35->dev, "Error: IMON overflow\n");
1132 1129
1133 return IRQ_HANDLED; 1130 return IRQ_HANDLED;
1134} 1131}
@@ -1365,6 +1362,8 @@ static int cs35l35_i2c_probe(struct i2c_client *i2c_client,
1365 if (!cs35l35) 1362 if (!cs35l35)
1366 return -ENOMEM; 1363 return -ENOMEM;
1367 1364
1365 cs35l35->dev = dev;
1366
1368 i2c_set_clientdata(i2c_client, cs35l35); 1367 i2c_set_clientdata(i2c_client, cs35l35);
1369 cs35l35->regmap = devm_regmap_init_i2c(i2c_client, &cs35l35_regmap); 1368 cs35l35->regmap = devm_regmap_init_i2c(i2c_client, &cs35l35_regmap);
1370 if (IS_ERR(cs35l35->regmap)) { 1369 if (IS_ERR(cs35l35->regmap)) {
diff --git a/sound/soc/codecs/cs35l35.h b/sound/soc/codecs/cs35l35.h
index c203081fc94c..156d2f0e6fd8 100644
--- a/sound/soc/codecs/cs35l35.h
+++ b/sound/soc/codecs/cs35l35.h
@@ -265,7 +265,7 @@
265 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) 265 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
266 266
267struct cs35l35_private { 267struct cs35l35_private {
268 struct snd_soc_codec *codec; 268 struct device *dev;
269 struct cs35l35_platform_data pdata; 269 struct cs35l35_platform_data pdata;
270 struct regmap *regmap; 270 struct regmap *regmap;
271 struct regulator_bulk_data supplies[2]; 271 struct regulator_bulk_data supplies[2];