diff options
Diffstat (limited to 'sound/soc/codecs/wm8350.c')
-rw-r--r-- | sound/soc/codecs/wm8350.c | 105 |
1 files changed, 67 insertions, 38 deletions
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 7611add7f8c3..6d6dc9efe914 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c | |||
@@ -24,9 +24,9 @@ | |||
24 | #include <sound/pcm.h> | 24 | #include <sound/pcm.h> |
25 | #include <sound/pcm_params.h> | 25 | #include <sound/pcm_params.h> |
26 | #include <sound/soc.h> | 26 | #include <sound/soc.h> |
27 | #include <sound/soc-dapm.h> | ||
28 | #include <sound/initval.h> | 27 | #include <sound/initval.h> |
29 | #include <sound/tlv.h> | 28 | #include <sound/tlv.h> |
29 | #include <trace/events/asoc.h> | ||
30 | 30 | ||
31 | #include "wm8350.h" | 31 | #include "wm8350.h" |
32 | 32 | ||
@@ -54,6 +54,7 @@ struct wm8350_output { | |||
54 | 54 | ||
55 | struct wm8350_jack_data { | 55 | struct wm8350_jack_data { |
56 | struct snd_soc_jack *jack; | 56 | struct snd_soc_jack *jack; |
57 | struct delayed_work work; | ||
57 | int report; | 58 | int report; |
58 | int short_report; | 59 | int short_report; |
59 | }; | 60 | }; |
@@ -230,8 +231,9 @@ static inline int wm8350_out2_ramp_step(struct snd_soc_codec *codec) | |||
230 | */ | 231 | */ |
231 | static void wm8350_pga_work(struct work_struct *work) | 232 | static void wm8350_pga_work(struct work_struct *work) |
232 | { | 233 | { |
233 | struct snd_soc_codec *codec = | 234 | struct snd_soc_dapm_context *dapm = |
234 | container_of(work, struct snd_soc_codec, delayed_work.work); | 235 | container_of(work, struct snd_soc_dapm_context, delayed_work.work); |
236 | struct snd_soc_codec *codec = dapm->codec; | ||
235 | struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec); | 237 | struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec); |
236 | struct wm8350_output *out1 = &wm8350_data->out1, | 238 | struct wm8350_output *out1 = &wm8350_data->out1, |
237 | *out2 = &wm8350_data->out2; | 239 | *out2 = &wm8350_data->out2; |
@@ -302,8 +304,8 @@ static int pga_event(struct snd_soc_dapm_widget *w, | |||
302 | out->ramp = WM8350_RAMP_UP; | 304 | out->ramp = WM8350_RAMP_UP; |
303 | out->active = 1; | 305 | out->active = 1; |
304 | 306 | ||
305 | if (!delayed_work_pending(&codec->delayed_work)) | 307 | if (!delayed_work_pending(&codec->dapm.delayed_work)) |
306 | schedule_delayed_work(&codec->delayed_work, | 308 | schedule_delayed_work(&codec->dapm.delayed_work, |
307 | msecs_to_jiffies(1)); | 309 | msecs_to_jiffies(1)); |
308 | break; | 310 | break; |
309 | 311 | ||
@@ -311,8 +313,8 @@ static int pga_event(struct snd_soc_dapm_widget *w, | |||
311 | out->ramp = WM8350_RAMP_DOWN; | 313 | out->ramp = WM8350_RAMP_DOWN; |
312 | out->active = 0; | 314 | out->active = 0; |
313 | 315 | ||
314 | if (!delayed_work_pending(&codec->delayed_work)) | 316 | if (!delayed_work_pending(&codec->dapm.delayed_work)) |
315 | schedule_delayed_work(&codec->delayed_work, | 317 | schedule_delayed_work(&codec->dapm.delayed_work, |
316 | msecs_to_jiffies(1)); | 318 | msecs_to_jiffies(1)); |
317 | break; | 319 | break; |
318 | } | 320 | } |
@@ -786,9 +788,10 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
786 | 788 | ||
787 | static int wm8350_add_widgets(struct snd_soc_codec *codec) | 789 | static int wm8350_add_widgets(struct snd_soc_codec *codec) |
788 | { | 790 | { |
791 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
789 | int ret; | 792 | int ret; |
790 | 793 | ||
791 | ret = snd_soc_dapm_new_controls(codec, | 794 | ret = snd_soc_dapm_new_controls(dapm, |
792 | wm8350_dapm_widgets, | 795 | wm8350_dapm_widgets, |
793 | ARRAY_SIZE(wm8350_dapm_widgets)); | 796 | ARRAY_SIZE(wm8350_dapm_widgets)); |
794 | if (ret != 0) { | 797 | if (ret != 0) { |
@@ -797,7 +800,7 @@ static int wm8350_add_widgets(struct snd_soc_codec *codec) | |||
797 | } | 800 | } |
798 | 801 | ||
799 | /* set up audio paths */ | 802 | /* set up audio paths */ |
800 | ret = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | 803 | ret = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
801 | if (ret != 0) { | 804 | if (ret != 0) { |
802 | dev_err(codec->dev, "DAPM route register failed\n"); | 805 | dev_err(codec->dev, "DAPM route register failed\n"); |
803 | return ret; | 806 | return ret; |
@@ -1184,7 +1187,7 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec, | |||
1184 | break; | 1187 | break; |
1185 | 1188 | ||
1186 | case SND_SOC_BIAS_STANDBY: | 1189 | case SND_SOC_BIAS_STANDBY: |
1187 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | 1190 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { |
1188 | ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), | 1191 | ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), |
1189 | priv->supplies); | 1192 | priv->supplies); |
1190 | if (ret != 0) | 1193 | if (ret != 0) |
@@ -1317,7 +1320,7 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec, | |||
1317 | priv->supplies); | 1320 | priv->supplies); |
1318 | break; | 1321 | break; |
1319 | } | 1322 | } |
1320 | codec->bias_level = level; | 1323 | codec->dapm.bias_level = level; |
1321 | return 0; | 1324 | return 0; |
1322 | } | 1325 | } |
1323 | 1326 | ||
@@ -1334,45 +1337,69 @@ static int wm8350_resume(struct snd_soc_codec *codec) | |||
1334 | return 0; | 1337 | return 0; |
1335 | } | 1338 | } |
1336 | 1339 | ||
1337 | static irqreturn_t wm8350_hp_jack_handler(int irq, void *data) | 1340 | static void wm8350_hp_work(struct wm8350_data *priv, |
1341 | struct wm8350_jack_data *jack, | ||
1342 | u16 mask) | ||
1338 | { | 1343 | { |
1339 | struct wm8350_data *priv = data; | ||
1340 | struct wm8350 *wm8350 = priv->codec.control_data; | 1344 | struct wm8350 *wm8350 = priv->codec.control_data; |
1341 | u16 reg; | 1345 | u16 reg; |
1342 | int report; | 1346 | int report; |
1343 | int mask; | 1347 | |
1348 | reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS); | ||
1349 | if (reg & mask) | ||
1350 | report = jack->report; | ||
1351 | else | ||
1352 | report = 0; | ||
1353 | |||
1354 | snd_soc_jack_report(jack->jack, report, jack->report); | ||
1355 | |||
1356 | } | ||
1357 | |||
1358 | static void wm8350_hpl_work(struct work_struct *work) | ||
1359 | { | ||
1360 | struct wm8350_data *priv = | ||
1361 | container_of(work, struct wm8350_data, hpl.work.work); | ||
1362 | |||
1363 | wm8350_hp_work(priv, &priv->hpl, WM8350_JACK_L_LVL); | ||
1364 | } | ||
1365 | |||
1366 | static void wm8350_hpr_work(struct work_struct *work) | ||
1367 | { | ||
1368 | struct wm8350_data *priv = | ||
1369 | container_of(work, struct wm8350_data, hpr.work.work); | ||
1370 | |||
1371 | wm8350_hp_work(priv, &priv->hpr, WM8350_JACK_R_LVL); | ||
1372 | } | ||
1373 | |||
1374 | static irqreturn_t wm8350_hp_jack_handler(int irq, void *data) | ||
1375 | { | ||
1376 | struct wm8350_data *priv = data; | ||
1377 | struct wm8350 *wm8350 = priv->codec.control_data; | ||
1344 | struct wm8350_jack_data *jack = NULL; | 1378 | struct wm8350_jack_data *jack = NULL; |
1345 | 1379 | ||
1346 | switch (irq - wm8350->irq_base) { | 1380 | switch (irq - wm8350->irq_base) { |
1347 | case WM8350_IRQ_CODEC_JCK_DET_L: | 1381 | case WM8350_IRQ_CODEC_JCK_DET_L: |
1382 | #ifndef CONFIG_SND_SOC_WM8350_MODULE | ||
1383 | trace_snd_soc_jack_irq("WM8350 HPL"); | ||
1384 | #endif | ||
1348 | jack = &priv->hpl; | 1385 | jack = &priv->hpl; |
1349 | mask = WM8350_JACK_L_LVL; | ||
1350 | break; | 1386 | break; |
1351 | 1387 | ||
1352 | case WM8350_IRQ_CODEC_JCK_DET_R: | 1388 | case WM8350_IRQ_CODEC_JCK_DET_R: |
1389 | #ifndef CONFIG_SND_SOC_WM8350_MODULE | ||
1390 | trace_snd_soc_jack_irq("WM8350 HPR"); | ||
1391 | #endif | ||
1353 | jack = &priv->hpr; | 1392 | jack = &priv->hpr; |
1354 | mask = WM8350_JACK_R_LVL; | ||
1355 | break; | 1393 | break; |
1356 | 1394 | ||
1357 | default: | 1395 | default: |
1358 | BUG(); | 1396 | BUG(); |
1359 | } | 1397 | } |
1360 | 1398 | ||
1361 | if (!jack->jack) { | 1399 | if (device_may_wakeup(wm8350->dev)) |
1362 | dev_warn(wm8350->dev, "Jack interrupt called with no jack\n"); | 1400 | pm_wakeup_event(wm8350->dev, 250); |
1363 | return IRQ_NONE; | ||
1364 | } | ||
1365 | |||
1366 | /* Debounce */ | ||
1367 | msleep(200); | ||
1368 | |||
1369 | reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS); | ||
1370 | if (reg & mask) | ||
1371 | report = jack->report; | ||
1372 | else | ||
1373 | report = 0; | ||
1374 | 1401 | ||
1375 | snd_soc_jack_report(jack->jack, report, jack->report); | 1402 | schedule_delayed_work(&jack->work, 200); |
1376 | 1403 | ||
1377 | return IRQ_HANDLED; | 1404 | return IRQ_HANDLED; |
1378 | } | 1405 | } |
@@ -1436,6 +1463,10 @@ static irqreturn_t wm8350_mic_handler(int irq, void *data) | |||
1436 | u16 reg; | 1463 | u16 reg; |
1437 | int report = 0; | 1464 | int report = 0; |
1438 | 1465 | ||
1466 | #ifndef CONFIG_SND_SOC_WM8350_MODULE | ||
1467 | trace_snd_soc_jack_irq("WM8350 mic"); | ||
1468 | #endif | ||
1469 | |||
1439 | reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS); | 1470 | reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS); |
1440 | if (reg & WM8350_JACK_MICSCD_LVL) | 1471 | if (reg & WM8350_JACK_MICSCD_LVL) |
1441 | report |= priv->mic.short_report; | 1472 | report |= priv->mic.short_report; |
@@ -1550,7 +1581,9 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec) | |||
1550 | /* Put the codec into reset if it wasn't already */ | 1581 | /* Put the codec into reset if it wasn't already */ |
1551 | wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); | 1582 | wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); |
1552 | 1583 | ||
1553 | INIT_DELAYED_WORK(&codec->delayed_work, wm8350_pga_work); | 1584 | INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8350_pga_work); |
1585 | INIT_DELAYED_WORK(&priv->hpl.work, wm8350_hpl_work); | ||
1586 | INIT_DELAYED_WORK(&priv->hpr.work, wm8350_hpr_work); | ||
1554 | 1587 | ||
1555 | /* Enable the codec */ | 1588 | /* Enable the codec */ |
1556 | wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); | 1589 | wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); |
@@ -1626,7 +1659,6 @@ static int wm8350_codec_remove(struct snd_soc_codec *codec) | |||
1626 | { | 1659 | { |
1627 | struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec); | 1660 | struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec); |
1628 | struct wm8350 *wm8350 = dev_get_platdata(codec->dev); | 1661 | struct wm8350 *wm8350 = dev_get_platdata(codec->dev); |
1629 | int ret; | ||
1630 | 1662 | ||
1631 | wm8350_clear_bits(wm8350, WM8350_JACK_DETECT, | 1663 | wm8350_clear_bits(wm8350, WM8350_JACK_DETECT, |
1632 | WM8350_JDL_ENA | WM8350_JDR_ENA); | 1664 | WM8350_JDL_ENA | WM8350_JDR_ENA); |
@@ -1641,15 +1673,12 @@ static int wm8350_codec_remove(struct snd_soc_codec *codec) | |||
1641 | priv->hpr.jack = NULL; | 1673 | priv->hpr.jack = NULL; |
1642 | priv->mic.jack = NULL; | 1674 | priv->mic.jack = NULL; |
1643 | 1675 | ||
1644 | /* cancel any work waiting to be queued. */ | 1676 | cancel_delayed_work_sync(&priv->hpl.work); |
1645 | ret = cancel_delayed_work(&codec->delayed_work); | 1677 | cancel_delayed_work_sync(&priv->hpr.work); |
1646 | 1678 | ||
1647 | /* if there was any work waiting then we run it now and | 1679 | /* if there was any work waiting then we run it now and |
1648 | * wait for its completion */ | 1680 | * wait for its completion */ |
1649 | if (ret) { | 1681 | flush_delayed_work_sync(&codec->dapm.delayed_work); |
1650 | schedule_delayed_work(&codec->delayed_work, 0); | ||
1651 | flush_scheduled_work(); | ||
1652 | } | ||
1653 | 1682 | ||
1654 | wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1683 | wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1655 | 1684 | ||