diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-01-08 10:16:16 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-01-09 05:31:32 -0500 |
commit | a6ba2b2dabb583e7820e567fb309d771b50cb9ff (patch) | |
tree | 3d99d525cc1826810ac56c11f79bd69131e7c68e /sound/soc/codecs/wm8350.c | |
parent | 8a2cd6180f8fa00111843c2f4a4f4361995358e0 (diff) |
ASoC: Implement WM8350 headphone jack detection
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/wm8350.c')
-rw-r--r-- | sound/soc/codecs/wm8350.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index e3989d406f54..47a9dabb5235 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c | |||
@@ -51,10 +51,17 @@ struct wm8350_output { | |||
51 | u16 mute; | 51 | u16 mute; |
52 | }; | 52 | }; |
53 | 53 | ||
54 | struct wm8350_jack_data { | ||
55 | struct snd_soc_jack *jack; | ||
56 | int report; | ||
57 | }; | ||
58 | |||
54 | struct wm8350_data { | 59 | struct wm8350_data { |
55 | struct snd_soc_codec codec; | 60 | struct snd_soc_codec codec; |
56 | struct wm8350_output out1; | 61 | struct wm8350_output out1; |
57 | struct wm8350_output out2; | 62 | struct wm8350_output out2; |
63 | struct wm8350_jack_data hpl; | ||
64 | struct wm8350_jack_data hpr; | ||
58 | struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; | 65 | struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; |
59 | }; | 66 | }; |
60 | 67 | ||
@@ -1328,6 +1335,95 @@ static int wm8350_resume(struct platform_device *pdev) | |||
1328 | return 0; | 1335 | return 0; |
1329 | } | 1336 | } |
1330 | 1337 | ||
1338 | static void wm8350_hp_jack_handler(struct wm8350 *wm8350, int irq, void *data) | ||
1339 | { | ||
1340 | struct wm8350_data *priv = data; | ||
1341 | u16 reg; | ||
1342 | int report; | ||
1343 | int mask; | ||
1344 | struct wm8350_jack_data *jack = NULL; | ||
1345 | |||
1346 | switch (irq) { | ||
1347 | case WM8350_IRQ_CODEC_JCK_DET_L: | ||
1348 | jack = &priv->hpl; | ||
1349 | mask = WM8350_JACK_L_LVL; | ||
1350 | break; | ||
1351 | |||
1352 | case WM8350_IRQ_CODEC_JCK_DET_R: | ||
1353 | jack = &priv->hpr; | ||
1354 | mask = WM8350_JACK_R_LVL; | ||
1355 | break; | ||
1356 | |||
1357 | default: | ||
1358 | BUG(); | ||
1359 | } | ||
1360 | |||
1361 | if (!jack->jack) { | ||
1362 | dev_warn(wm8350->dev, "Jack interrupt called with no jack\n"); | ||
1363 | return; | ||
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 | |||
1375 | snd_soc_jack_report(jack->jack, report, jack->report); | ||
1376 | } | ||
1377 | |||
1378 | /** | ||
1379 | * wm8350_hp_jack_detect - Enable headphone jack detection. | ||
1380 | * | ||
1381 | * @codec: WM8350 codec | ||
1382 | * @which: left or right jack detect signal | ||
1383 | * @jack: jack to report detection events on | ||
1384 | * @report: value to report | ||
1385 | * | ||
1386 | * Enables the headphone jack detection of the WM8350. | ||
1387 | */ | ||
1388 | int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which, | ||
1389 | struct snd_soc_jack *jack, int report) | ||
1390 | { | ||
1391 | struct wm8350_data *priv = codec->private_data; | ||
1392 | struct wm8350 *wm8350 = codec->control_data; | ||
1393 | int irq; | ||
1394 | int ena; | ||
1395 | |||
1396 | switch (which) { | ||
1397 | case WM8350_JDL: | ||
1398 | priv->hpl.jack = jack; | ||
1399 | priv->hpl.report = report; | ||
1400 | irq = WM8350_IRQ_CODEC_JCK_DET_L; | ||
1401 | ena = WM8350_JDL_ENA; | ||
1402 | break; | ||
1403 | |||
1404 | case WM8350_JDR: | ||
1405 | priv->hpr.jack = jack; | ||
1406 | priv->hpr.report = report; | ||
1407 | irq = WM8350_IRQ_CODEC_JCK_DET_R; | ||
1408 | ena = WM8350_JDR_ENA; | ||
1409 | break; | ||
1410 | |||
1411 | default: | ||
1412 | return -EINVAL; | ||
1413 | } | ||
1414 | |||
1415 | wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA); | ||
1416 | wm8350_set_bits(wm8350, WM8350_JACK_DETECT, ena); | ||
1417 | |||
1418 | /* Sync status */ | ||
1419 | wm8350_hp_jack_handler(wm8350, irq, priv); | ||
1420 | |||
1421 | wm8350_unmask_irq(wm8350, irq); | ||
1422 | |||
1423 | return 0; | ||
1424 | } | ||
1425 | EXPORT_SYMBOL_GPL(wm8350_hp_jack_detect); | ||
1426 | |||
1331 | static struct snd_soc_codec *wm8350_codec; | 1427 | static struct snd_soc_codec *wm8350_codec; |
1332 | 1428 | ||
1333 | static int wm8350_probe(struct platform_device *pdev) | 1429 | static int wm8350_probe(struct platform_device *pdev) |
@@ -1381,6 +1477,13 @@ static int wm8350_probe(struct platform_device *pdev) | |||
1381 | wm8350_set_bits(wm8350, WM8350_ROUT2_VOLUME, | 1477 | wm8350_set_bits(wm8350, WM8350_ROUT2_VOLUME, |
1382 | WM8350_OUT2_VU | WM8350_OUT2R_MUTE); | 1478 | WM8350_OUT2_VU | WM8350_OUT2R_MUTE); |
1383 | 1479 | ||
1480 | wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L); | ||
1481 | wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R); | ||
1482 | wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, | ||
1483 | wm8350_hp_jack_handler, priv); | ||
1484 | wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, | ||
1485 | wm8350_hp_jack_handler, priv); | ||
1486 | |||
1384 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 1487 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
1385 | if (ret < 0) { | 1488 | if (ret < 0) { |
1386 | dev_err(&pdev->dev, "failed to create pcms\n"); | 1489 | dev_err(&pdev->dev, "failed to create pcms\n"); |
@@ -1411,8 +1514,21 @@ static int wm8350_remove(struct platform_device *pdev) | |||
1411 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1514 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1412 | struct snd_soc_codec *codec = socdev->codec; | 1515 | struct snd_soc_codec *codec = socdev->codec; |
1413 | struct wm8350 *wm8350 = codec->control_data; | 1516 | struct wm8350 *wm8350 = codec->control_data; |
1517 | struct wm8350_data *priv = codec->private_data; | ||
1414 | int ret; | 1518 | int ret; |
1415 | 1519 | ||
1520 | wm8350_clear_bits(wm8350, WM8350_JACK_DETECT, | ||
1521 | WM8350_JDL_ENA | WM8350_JDR_ENA); | ||
1522 | wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA); | ||
1523 | |||
1524 | wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L); | ||
1525 | wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R); | ||
1526 | wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L); | ||
1527 | wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R); | ||
1528 | |||
1529 | priv->hpl.jack = NULL; | ||
1530 | priv->hpr.jack = NULL; | ||
1531 | |||
1416 | /* cancel any work waiting to be queued. */ | 1532 | /* cancel any work waiting to be queued. */ |
1417 | ret = cancel_delayed_work(&codec->delayed_work); | 1533 | ret = cancel_delayed_work(&codec->delayed_work); |
1418 | 1534 | ||