Commit a2d2362edf9f068bdee7d0411e0603b322f8415d

Authored by Jorge Eduardo Candelaria
Committed by Liam Girdwood
1 parent dcdeda4a60

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__ */