aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/twl6040.c
diff options
context:
space:
mode:
authorJorge Eduardo Candelaria <jorge.candelaria@ti.com>2010-12-10 21:45:17 -0500
committerLiam Girdwood <lrg@slimlogic.co.uk>2010-12-14 15:31:54 -0500
commita2d2362edf9f068bdee7d0411e0603b322f8415d (patch)
treee1cd6c0a6627add28700cbbc564b9a5c199f2292 /sound/soc/codecs/twl6040.c
parentdcdeda4a60b2046dd18d3dd20cbd888f25d8916b (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.c67
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
45struct twl6040_jack_data {
46 struct snd_soc_jack *jack;
47 int report;
48};
49
45/* codec private data */ 50/* codec private data */
46struct twl6040_data { 51struct 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
394void 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
412void 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}
423EXPORT_SYMBOL_GPL(twl6040_hs_jack_detect);
424
425static 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 */
385static irqreturn_t twl6040_naudint_handler(int irq, void *data) 436static 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);
1091gpio1_err: 1155gpio1_err:
1156 destroy_workqueue(priv->workqueue);
1157work_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;