diff options
author | Jorge Eduardo Candelaria <jorge.candelaria@ti.com> | 2010-12-10 21:45:17 -0500 |
---|---|---|
committer | Liam Girdwood <lrg@slimlogic.co.uk> | 2010-12-14 15:31:54 -0500 |
commit | a2d2362edf9f068bdee7d0411e0603b322f8415d (patch) | |
tree | e1cd6c0a6627add28700cbbc564b9a5c199f2292 /sound/soc/codecs/twl6040.c | |
parent | dcdeda4a60b2046dd18d3dd20cbd888f25d8916b (diff) |
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>
Diffstat (limited to 'sound/soc/codecs/twl6040.c')
-rw-r--r-- | sound/soc/codecs/twl6040.c | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index b92f2b737e4c..5d7e2f7b194c 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c | |||
@@ -42,6 +42,11 @@ | |||
42 | #define TWL6040_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | 42 | #define TWL6040_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) |
43 | #define TWL6040_FORMATS (SNDRV_PCM_FMTBIT_S32_LE) | 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 | /* codec private data */ | 50 | /* codec private data */ |
46 | struct twl6040_data { | 51 | struct twl6040_data { |
47 | int audpwron; | 52 | int audpwron; |
@@ -52,6 +57,11 @@ struct twl6040_data { | |||
52 | unsigned int sysclk; | 57 | unsigned int sysclk; |
53 | struct snd_pcm_hw_constraint_list *sysclk_constraints; | 58 | struct snd_pcm_hw_constraint_list *sysclk_constraints; |
54 | struct completion ready; | 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 @@ static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w, | |||
381 | return 0; | 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 | /* audio interrupt handler */ | 435 | /* audio interrupt handler */ |
385 | static irqreturn_t twl6040_naudint_handler(int irq, void *data) | 436 | static irqreturn_t twl6040_naudint_handler(int irq, void *data) |
386 | { | 437 | { |
@@ -396,6 +447,9 @@ static irqreturn_t twl6040_naudint_handler(int irq, void *data) | |||
396 | break; | 447 | break; |
397 | case TWL6040_PLUGINT: | 448 | case TWL6040_PLUGINT: |
398 | case TWL6040_UNPLUGINT: | 449 | case TWL6040_UNPLUGINT: |
450 | queue_delayed_work(priv->workqueue, &priv->delayed_work, | ||
451 | msecs_to_jiffies(200)); | ||
452 | break; | ||
399 | case TWL6040_HOOKINT: | 453 | case TWL6040_HOOKINT: |
400 | break; | 454 | break; |
401 | case TWL6040_HFINT: | 455 | case TWL6040_HFINT: |
@@ -1023,6 +1077,8 @@ static int twl6040_probe(struct snd_soc_codec *codec) | |||
1023 | return -ENOMEM; | 1077 | return -ENOMEM; |
1024 | snd_soc_codec_set_drvdata(codec, priv); | 1078 | snd_soc_codec_set_drvdata(codec, priv); |
1025 | 1079 | ||
1080 | priv->codec = codec; | ||
1081 | |||
1026 | if (twl_codec) { | 1082 | if (twl_codec) { |
1027 | audpwron = twl_codec->audpwron_gpio; | 1083 | audpwron = twl_codec->audpwron_gpio; |
1028 | naudint = twl_codec->naudint_irq; | 1084 | naudint = twl_codec->naudint_irq; |
@@ -1033,6 +1089,14 @@ static int twl6040_probe(struct snd_soc_codec *codec) | |||
1033 | 1089 | ||
1034 | priv->audpwron = audpwron; | 1090 | priv->audpwron = audpwron; |
1035 | priv->naudint = naudint; | 1091 | priv->naudint = naudint; |
1092 | priv->workqueue = create_singlethread_workqueue("twl6040-codec"); | ||
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); | ||
1036 | 1100 | ||
1037 | init_completion(&priv->ready); | 1101 | init_completion(&priv->ready); |
1038 | 1102 | ||
@@ -1089,6 +1153,8 @@ gpio2_err: | |||
1089 | if (gpio_is_valid(audpwron)) | 1153 | if (gpio_is_valid(audpwron)) |
1090 | gpio_free(audpwron); | 1154 | gpio_free(audpwron); |
1091 | gpio1_err: | 1155 | gpio1_err: |
1156 | destroy_workqueue(priv->workqueue); | ||
1157 | work_err: | ||
1092 | kfree(priv); | 1158 | kfree(priv); |
1093 | return ret; | 1159 | return ret; |
1094 | } | 1160 | } |
@@ -1107,6 +1173,7 @@ static int twl6040_remove(struct snd_soc_codec *codec) | |||
1107 | if (naudint) | 1173 | if (naudint) |
1108 | free_irq(naudint, codec); | 1174 | free_irq(naudint, codec); |
1109 | 1175 | ||
1176 | destroy_workqueue(priv->workqueue); | ||
1110 | kfree(priv); | 1177 | kfree(priv); |
1111 | 1178 | ||
1112 | return 0; | 1179 | return 0; |