aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/rt286.c
diff options
context:
space:
mode:
authorBard Liao <bardliao@realtek.com>2014-07-29 01:50:57 -0400
committerMark Brown <broonie@linaro.org>2014-07-29 08:00:08 -0400
commit90f601efc886ee5881594c5d931b76775975e155 (patch)
tree10030644654a509c2418a99472a0e56deb251f3e /sound/soc/codecs/rt286.c
parent23c4fd5c9719e8fc60d589b9f9c7451120f4f3e9 (diff)
ASoC: rt286: Fix null pointer issue
To make the interrupt safe if it happens to be called before the card is ready, we use regmap read/write in the interrupt handler. Also, we try to prevent the interrupt happen before the card is ready by enabling codec's IRQ in the ASoC probe. Signed-off-by: Bard Liao <bardliao@realtek.com> Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'sound/soc/codecs/rt286.c')
-rw-r--r--sound/soc/codecs/rt286.c74
1 files changed, 36 insertions, 38 deletions
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index 218f86efd196..e4f6102efc1a 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -36,7 +36,6 @@
36 36
37struct rt286_priv { 37struct rt286_priv {
38 struct regmap *regmap; 38 struct regmap *regmap;
39 struct snd_soc_codec *codec;
40 struct rt286_platform_data pdata; 39 struct rt286_platform_data pdata;
41 struct i2c_client *i2c; 40 struct i2c_client *i2c;
42 struct snd_soc_jack *jack; 41 struct snd_soc_jack *jack;
@@ -295,9 +294,8 @@ static int rt286_support_power_controls[] = {
295}; 294};
296#define RT286_POWER_REG_LEN ARRAY_SIZE(rt286_support_power_controls) 295#define RT286_POWER_REG_LEN ARRAY_SIZE(rt286_support_power_controls)
297 296
298static int rt286_jack_detect(struct snd_soc_codec *codec, bool *hp, bool *mic) 297static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
299{ 298{
300 struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
301 unsigned int val, buf; 299 unsigned int val, buf;
302 int i; 300 int i;
303 301
@@ -305,23 +303,23 @@ static int rt286_jack_detect(struct snd_soc_codec *codec, bool *hp, bool *mic)
305 *mic = false; 303 *mic = false;
306 304
307 if (rt286->pdata.cbj_en) { 305 if (rt286->pdata.cbj_en) {
308 buf = snd_soc_read(codec, RT286_GET_HP_SENSE); 306 regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf);
309 *hp = buf & 0x80000000; 307 *hp = buf & 0x80000000;
310 if (*hp) { 308 if (*hp) {
311 /* power on HV,VERF */ 309 /* power on HV,VERF */
312 snd_soc_update_bits(codec, 310 regmap_update_bits(rt286->regmap,
313 RT286_POWER_CTRL1, 0x1001, 0x0); 311 RT286_POWER_CTRL1, 0x1001, 0x0);
314 /* power LDO1 */ 312 /* power LDO1 */
315 snd_soc_update_bits(codec, 313 regmap_update_bits(rt286->regmap,
316 RT286_POWER_CTRL2, 0x4, 0x4); 314 RT286_POWER_CTRL2, 0x4, 0x4);
317 snd_soc_write(codec, RT286_SET_MIC1, 0x24); 315 regmap_write(rt286->regmap, RT286_SET_MIC1, 0x24);
318 val = snd_soc_read(codec, RT286_CBJ_CTRL2); 316 regmap_read(rt286->regmap, RT286_CBJ_CTRL2, &val);
319 317
320 msleep(200); 318 msleep(200);
321 i = 40; 319 i = 40;
322 while (((val & 0x0800) == 0) && (i > 0)) { 320 while (((val & 0x0800) == 0) && (i > 0)) {
323 val = snd_soc_read(codec, 321 regmap_read(rt286->regmap,
324 RT286_CBJ_CTRL2); 322 RT286_CBJ_CTRL2, &val);
325 i--; 323 i--;
326 msleep(20); 324 msleep(20);
327 } 325 }
@@ -329,53 +327,53 @@ static int rt286_jack_detect(struct snd_soc_codec *codec, bool *hp, bool *mic)
329 if (0x0400 == (val & 0x0700)) { 327 if (0x0400 == (val & 0x0700)) {
330 *mic = false; 328 *mic = false;
331 329
332 snd_soc_write(codec, 330 regmap_write(rt286->regmap,
333 RT286_SET_MIC1, 0x20); 331 RT286_SET_MIC1, 0x20);
334 /* power off HV,VERF */ 332 /* power off HV,VERF */
335 snd_soc_update_bits(codec, 333 regmap_update_bits(rt286->regmap,
336 RT286_POWER_CTRL1, 0x1001, 0x1001); 334 RT286_POWER_CTRL1, 0x1001, 0x1001);
337 snd_soc_update_bits(codec, 335 regmap_update_bits(rt286->regmap,
338 RT286_A_BIAS_CTRL3, 0xc000, 0x0000); 336 RT286_A_BIAS_CTRL3, 0xc000, 0x0000);
339 snd_soc_update_bits(codec, 337 regmap_update_bits(rt286->regmap,
340 RT286_CBJ_CTRL1, 0x0030, 0x0000); 338 RT286_CBJ_CTRL1, 0x0030, 0x0000);
341 snd_soc_update_bits(codec, 339 regmap_update_bits(rt286->regmap,
342 RT286_A_BIAS_CTRL2, 0xc000, 0x0000); 340 RT286_A_BIAS_CTRL2, 0xc000, 0x0000);
343 } else if ((0x0200 == (val & 0x0700)) || 341 } else if ((0x0200 == (val & 0x0700)) ||
344 (0x0100 == (val & 0x0700))) { 342 (0x0100 == (val & 0x0700))) {
345 *mic = true; 343 *mic = true;
346 snd_soc_update_bits(codec, 344 regmap_update_bits(rt286->regmap,
347 RT286_A_BIAS_CTRL3, 0xc000, 0x8000); 345 RT286_A_BIAS_CTRL3, 0xc000, 0x8000);
348 snd_soc_update_bits(codec, 346 regmap_update_bits(rt286->regmap,
349 RT286_CBJ_CTRL1, 0x0030, 0x0020); 347 RT286_CBJ_CTRL1, 0x0030, 0x0020);
350 snd_soc_update_bits(codec, 348 regmap_update_bits(rt286->regmap,
351 RT286_A_BIAS_CTRL2, 0xc000, 0x8000); 349 RT286_A_BIAS_CTRL2, 0xc000, 0x8000);
352 } else { 350 } else {
353 *mic = false; 351 *mic = false;
354 } 352 }
355 353
356 snd_soc_update_bits(codec, 354 regmap_update_bits(rt286->regmap,
357 RT286_MISC_CTRL1, 355 RT286_MISC_CTRL1,
358 0x0060, 0x0000); 356 0x0060, 0x0000);
359 } else { 357 } else {
360 snd_soc_update_bits(codec, 358 regmap_update_bits(rt286->regmap,
361 RT286_MISC_CTRL1, 359 RT286_MISC_CTRL1,
362 0x0060, 0x0020); 360 0x0060, 0x0020);
363 snd_soc_update_bits(codec, 361 regmap_update_bits(rt286->regmap,
364 RT286_A_BIAS_CTRL3, 362 RT286_A_BIAS_CTRL3,
365 0xc000, 0x8000); 363 0xc000, 0x8000);
366 snd_soc_update_bits(codec, 364 regmap_update_bits(rt286->regmap,
367 RT286_CBJ_CTRL1, 365 RT286_CBJ_CTRL1,
368 0x0030, 0x0020); 366 0x0030, 0x0020);
369 snd_soc_update_bits(codec, 367 regmap_update_bits(rt286->regmap,
370 RT286_A_BIAS_CTRL2, 368 RT286_A_BIAS_CTRL2,
371 0xc000, 0x8000); 369 0xc000, 0x8000);
372 370
373 *mic = false; 371 *mic = false;
374 } 372 }
375 } else { 373 } else {
376 buf = snd_soc_read(codec, RT286_GET_HP_SENSE); 374 regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf);
377 *hp = buf & 0x80000000; 375 *hp = buf & 0x80000000;
378 buf = snd_soc_read(codec, RT286_GET_MIC1_SENSE); 376 regmap_read(rt286->regmap, RT286_GET_MIC1_SENSE, &buf);
379 *mic = buf & 0x80000000; 377 *mic = buf & 0x80000000;
380 } 378 }
381 379
@@ -390,7 +388,7 @@ static void rt286_jack_detect_work(struct work_struct *work)
390 bool hp = false; 388 bool hp = false;
391 bool mic = false; 389 bool mic = false;
392 390
393 rt286_jack_detect(rt286->codec, &hp, &mic); 391 rt286_jack_detect(rt286, &hp, &mic);
394 392
395 if (hp == true) 393 if (hp == true)
396 status |= SND_JACK_HEADPHONE; 394 status |= SND_JACK_HEADPHONE;
@@ -940,11 +938,10 @@ static irqreturn_t rt286_irq(int irq, void *data)
940 bool mic = false; 938 bool mic = false;
941 int status = 0; 939 int status = 0;
942 940
943 rt286_jack_detect(rt286->codec, &hp, &mic); 941 rt286_jack_detect(rt286, &hp, &mic);
944 942
945 /* Clear IRQ */ 943 /* Clear IRQ */
946 snd_soc_update_bits(rt286->codec, 944 regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x1, 0x1);
947 RT286_IRQ_CTRL, 0x1, 0x1);
948 945
949 if (hp == true) 946 if (hp == true)
950 status |= SND_JACK_HEADPHONE; 947 status |= SND_JACK_HEADPHONE;
@@ -965,7 +962,16 @@ static int rt286_probe(struct snd_soc_codec *codec)
965 struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); 962 struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
966 963
967 codec->dapm.bias_level = SND_SOC_BIAS_OFF; 964 codec->dapm.bias_level = SND_SOC_BIAS_OFF;
968 rt286->codec = codec; 965
966 if (rt286->i2c->irq) {
967 regmap_update_bits(rt286->regmap,
968 RT286_IRQ_CTRL, 0x2, 0x2);
969
970 INIT_DELAYED_WORK(&rt286->jack_detect_work,
971 rt286_jack_detect_work);
972 schedule_delayed_work(&rt286->jack_detect_work,
973 msecs_to_jiffies(1250));
974 }
969 975
970 return 0; 976 return 0;
971} 977}
@@ -1171,14 +1177,6 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
1171 regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f); 1177 regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f);
1172 1178
1173 if (rt286->i2c->irq) { 1179 if (rt286->i2c->irq) {
1174 regmap_update_bits(rt286->regmap,
1175 RT286_IRQ_CTRL, 0x2, 0x2);
1176
1177 INIT_DELAYED_WORK(&rt286->jack_detect_work,
1178 rt286_jack_detect_work);
1179 schedule_delayed_work(&rt286->jack_detect_work,
1180 msecs_to_jiffies(1250));
1181
1182 ret = request_threaded_irq(rt286->i2c->irq, NULL, rt286_irq, 1180 ret = request_threaded_irq(rt286->i2c->irq, NULL, rt286_irq,
1183 IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "rt286", rt286); 1181 IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "rt286", rt286);
1184 if (ret != 0) { 1182 if (ret != 0) {