Commit a2d2362edf9f068bdee7d0411e0603b322f8415d
Committed by
Liam Girdwood
1 parent
dcdeda4a60
Exists in
master
and in
39 other branches
ASoC: twl6040: Add jack support for headset and handset
This patch adds support for reporting twl6040 headset and handset jack events. The machine driver retrieves and report the status through twl6040_hs_jack_detect. A workq is used to debounce of the irq. Signed-off-by: Jorge Eduardo Candelaria <jorge.candelaria@ti.com> Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com> Signed-off-by: Margarita Olaya Cabrera <magi.olaya@ti.com> Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Showing 2 changed files with 74 additions and 0 deletions Side-by-side Diff
sound/soc/codecs/twl6040.c
... | ... | @@ -42,6 +42,11 @@ |
42 | 42 | #define TWL6040_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) |
43 | 43 | #define TWL6040_FORMATS (SNDRV_PCM_FMTBIT_S32_LE) |
44 | 44 | |
45 | +struct twl6040_jack_data { | |
46 | + struct snd_soc_jack *jack; | |
47 | + int report; | |
48 | +}; | |
49 | + | |
45 | 50 | /* codec private data */ |
46 | 51 | struct twl6040_data { |
47 | 52 | int audpwron; |
... | ... | @@ -52,6 +57,11 @@ |
52 | 57 | unsigned int sysclk; |
53 | 58 | struct snd_pcm_hw_constraint_list *sysclk_constraints; |
54 | 59 | struct completion ready; |
60 | + struct twl6040_jack_data hs_jack; | |
61 | + struct snd_soc_codec *codec; | |
62 | + struct workqueue_struct *workqueue; | |
63 | + struct delayed_work delayed_work; | |
64 | + struct mutex mutex; | |
55 | 65 | }; |
56 | 66 | |
57 | 67 | /* |
... | ... | @@ -381,6 +391,47 @@ |
381 | 391 | return 0; |
382 | 392 | } |
383 | 393 | |
394 | +void twl6040_hs_jack_report(struct snd_soc_codec *codec, | |
395 | + struct snd_soc_jack *jack, int report) | |
396 | +{ | |
397 | + struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); | |
398 | + int status; | |
399 | + | |
400 | + mutex_lock(&priv->mutex); | |
401 | + | |
402 | + /* Sync status */ | |
403 | + status = twl6040_read_reg_volatile(codec, TWL6040_REG_STATUS); | |
404 | + if (status & TWL6040_PLUGCOMP) | |
405 | + snd_soc_jack_report(jack, report, report); | |
406 | + else | |
407 | + snd_soc_jack_report(jack, 0, report); | |
408 | + | |
409 | + mutex_unlock(&priv->mutex); | |
410 | +} | |
411 | + | |
412 | +void twl6040_hs_jack_detect(struct snd_soc_codec *codec, | |
413 | + struct snd_soc_jack *jack, int report) | |
414 | +{ | |
415 | + struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); | |
416 | + struct twl6040_jack_data *hs_jack = &priv->hs_jack; | |
417 | + | |
418 | + hs_jack->jack = jack; | |
419 | + hs_jack->report = report; | |
420 | + | |
421 | + twl6040_hs_jack_report(codec, hs_jack->jack, hs_jack->report); | |
422 | +} | |
423 | +EXPORT_SYMBOL_GPL(twl6040_hs_jack_detect); | |
424 | + | |
425 | +static void twl6040_accessory_work(struct work_struct *work) | |
426 | +{ | |
427 | + struct twl6040_data *priv = container_of(work, | |
428 | + struct twl6040_data, delayed_work.work); | |
429 | + struct snd_soc_codec *codec = priv->codec; | |
430 | + struct twl6040_jack_data *hs_jack = &priv->hs_jack; | |
431 | + | |
432 | + twl6040_hs_jack_report(codec, hs_jack->jack, hs_jack->report); | |
433 | +} | |
434 | + | |
384 | 435 | /* audio interrupt handler */ |
385 | 436 | static irqreturn_t twl6040_naudint_handler(int irq, void *data) |
386 | 437 | { |
... | ... | @@ -396,6 +447,9 @@ |
396 | 447 | break; |
397 | 448 | case TWL6040_PLUGINT: |
398 | 449 | case TWL6040_UNPLUGINT: |
450 | + queue_delayed_work(priv->workqueue, &priv->delayed_work, | |
451 | + msecs_to_jiffies(200)); | |
452 | + break; | |
399 | 453 | case TWL6040_HOOKINT: |
400 | 454 | break; |
401 | 455 | case TWL6040_HFINT: |
... | ... | @@ -1023,6 +1077,8 @@ |
1023 | 1077 | return -ENOMEM; |
1024 | 1078 | snd_soc_codec_set_drvdata(codec, priv); |
1025 | 1079 | |
1080 | + priv->codec = codec; | |
1081 | + | |
1026 | 1082 | if (twl_codec) { |
1027 | 1083 | audpwron = twl_codec->audpwron_gpio; |
1028 | 1084 | naudint = twl_codec->naudint_irq; |
1029 | 1085 | |
... | ... | @@ -1033,7 +1089,15 @@ |
1033 | 1089 | |
1034 | 1090 | priv->audpwron = audpwron; |
1035 | 1091 | priv->naudint = naudint; |
1092 | + priv->workqueue = create_singlethread_workqueue("twl6040-codec"); | |
1036 | 1093 | |
1094 | + if (!priv->workqueue) | |
1095 | + goto work_err; | |
1096 | + | |
1097 | + INIT_DELAYED_WORK(&priv->delayed_work, twl6040_accessory_work); | |
1098 | + | |
1099 | + mutex_init(&priv->mutex); | |
1100 | + | |
1037 | 1101 | init_completion(&priv->ready); |
1038 | 1102 | |
1039 | 1103 | if (gpio_is_valid(audpwron)) { |
... | ... | @@ -1089,6 +1153,8 @@ |
1089 | 1153 | if (gpio_is_valid(audpwron)) |
1090 | 1154 | gpio_free(audpwron); |
1091 | 1155 | gpio1_err: |
1156 | + destroy_workqueue(priv->workqueue); | |
1157 | +work_err: | |
1092 | 1158 | kfree(priv); |
1093 | 1159 | return ret; |
1094 | 1160 | } |
... | ... | @@ -1107,6 +1173,7 @@ |
1107 | 1173 | if (naudint) |
1108 | 1174 | free_irq(naudint, codec); |
1109 | 1175 | |
1176 | + destroy_workqueue(priv->workqueue); | |
1110 | 1177 | kfree(priv); |
1111 | 1178 | |
1112 | 1179 | return 0; |
sound/soc/codecs/twl6040.h
... | ... | @@ -135,5 +135,12 @@ |
135 | 135 | #define TWL6040_HPPLL_ID 1 |
136 | 136 | #define TWL6040_LPPLL_ID 2 |
137 | 137 | |
138 | +/* STATUS (0x2E) fields */ | |
139 | + | |
140 | +#define TWL6040_PLUGCOMP 0x02 | |
141 | + | |
142 | +void twl6040_hs_jack_detect(struct snd_soc_codec *codec, | |
143 | + struct snd_soc_jack *jack, int report); | |
144 | + | |
138 | 145 | #endif /* End of __TWL6040_H__ */ |