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>
This commit is contained in:
parent
dcdeda4a60
commit
a2d2362edf
@ -42,6 +42,11 @@
|
|||||||
#define TWL6040_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
|
#define TWL6040_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
|
||||||
#define TWL6040_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
|
#define TWL6040_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
|
||||||
|
|
||||||
|
struct twl6040_jack_data {
|
||||||
|
struct snd_soc_jack *jack;
|
||||||
|
int report;
|
||||||
|
};
|
||||||
|
|
||||||
/* codec private data */
|
/* codec private data */
|
||||||
struct twl6040_data {
|
struct twl6040_data {
|
||||||
int audpwron;
|
int audpwron;
|
||||||
@ -52,6 +57,11 @@ struct twl6040_data {
|
|||||||
unsigned int sysclk;
|
unsigned int sysclk;
|
||||||
struct snd_pcm_hw_constraint_list *sysclk_constraints;
|
struct snd_pcm_hw_constraint_list *sysclk_constraints;
|
||||||
struct completion ready;
|
struct completion ready;
|
||||||
|
struct twl6040_jack_data hs_jack;
|
||||||
|
struct snd_soc_codec *codec;
|
||||||
|
struct workqueue_struct *workqueue;
|
||||||
|
struct delayed_work delayed_work;
|
||||||
|
struct mutex mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -381,6 +391,47 @@ static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void twl6040_hs_jack_report(struct snd_soc_codec *codec,
|
||||||
|
struct snd_soc_jack *jack, int report)
|
||||||
|
{
|
||||||
|
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||||
|
int status;
|
||||||
|
|
||||||
|
mutex_lock(&priv->mutex);
|
||||||
|
|
||||||
|
/* Sync status */
|
||||||
|
status = twl6040_read_reg_volatile(codec, TWL6040_REG_STATUS);
|
||||||
|
if (status & TWL6040_PLUGCOMP)
|
||||||
|
snd_soc_jack_report(jack, report, report);
|
||||||
|
else
|
||||||
|
snd_soc_jack_report(jack, 0, report);
|
||||||
|
|
||||||
|
mutex_unlock(&priv->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void twl6040_hs_jack_detect(struct snd_soc_codec *codec,
|
||||||
|
struct snd_soc_jack *jack, int report)
|
||||||
|
{
|
||||||
|
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||||
|
struct twl6040_jack_data *hs_jack = &priv->hs_jack;
|
||||||
|
|
||||||
|
hs_jack->jack = jack;
|
||||||
|
hs_jack->report = report;
|
||||||
|
|
||||||
|
twl6040_hs_jack_report(codec, hs_jack->jack, hs_jack->report);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(twl6040_hs_jack_detect);
|
||||||
|
|
||||||
|
static void twl6040_accessory_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct twl6040_data *priv = container_of(work,
|
||||||
|
struct twl6040_data, delayed_work.work);
|
||||||
|
struct snd_soc_codec *codec = priv->codec;
|
||||||
|
struct twl6040_jack_data *hs_jack = &priv->hs_jack;
|
||||||
|
|
||||||
|
twl6040_hs_jack_report(codec, hs_jack->jack, hs_jack->report);
|
||||||
|
}
|
||||||
|
|
||||||
/* audio interrupt handler */
|
/* audio interrupt handler */
|
||||||
static irqreturn_t twl6040_naudint_handler(int irq, void *data)
|
static irqreturn_t twl6040_naudint_handler(int irq, void *data)
|
||||||
{
|
{
|
||||||
@ -396,6 +447,9 @@ static irqreturn_t twl6040_naudint_handler(int irq, void *data)
|
|||||||
break;
|
break;
|
||||||
case TWL6040_PLUGINT:
|
case TWL6040_PLUGINT:
|
||||||
case TWL6040_UNPLUGINT:
|
case TWL6040_UNPLUGINT:
|
||||||
|
queue_delayed_work(priv->workqueue, &priv->delayed_work,
|
||||||
|
msecs_to_jiffies(200));
|
||||||
|
break;
|
||||||
case TWL6040_HOOKINT:
|
case TWL6040_HOOKINT:
|
||||||
break;
|
break;
|
||||||
case TWL6040_HFINT:
|
case TWL6040_HFINT:
|
||||||
@ -1023,6 +1077,8 @@ static int twl6040_probe(struct snd_soc_codec *codec)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
snd_soc_codec_set_drvdata(codec, priv);
|
snd_soc_codec_set_drvdata(codec, priv);
|
||||||
|
|
||||||
|
priv->codec = codec;
|
||||||
|
|
||||||
if (twl_codec) {
|
if (twl_codec) {
|
||||||
audpwron = twl_codec->audpwron_gpio;
|
audpwron = twl_codec->audpwron_gpio;
|
||||||
naudint = twl_codec->naudint_irq;
|
naudint = twl_codec->naudint_irq;
|
||||||
@ -1033,6 +1089,14 @@ static int twl6040_probe(struct snd_soc_codec *codec)
|
|||||||
|
|
||||||
priv->audpwron = audpwron;
|
priv->audpwron = audpwron;
|
||||||
priv->naudint = naudint;
|
priv->naudint = naudint;
|
||||||
|
priv->workqueue = create_singlethread_workqueue("twl6040-codec");
|
||||||
|
|
||||||
|
if (!priv->workqueue)
|
||||||
|
goto work_err;
|
||||||
|
|
||||||
|
INIT_DELAYED_WORK(&priv->delayed_work, twl6040_accessory_work);
|
||||||
|
|
||||||
|
mutex_init(&priv->mutex);
|
||||||
|
|
||||||
init_completion(&priv->ready);
|
init_completion(&priv->ready);
|
||||||
|
|
||||||
@ -1089,6 +1153,8 @@ gpio2_err:
|
|||||||
if (gpio_is_valid(audpwron))
|
if (gpio_is_valid(audpwron))
|
||||||
gpio_free(audpwron);
|
gpio_free(audpwron);
|
||||||
gpio1_err:
|
gpio1_err:
|
||||||
|
destroy_workqueue(priv->workqueue);
|
||||||
|
work_err:
|
||||||
kfree(priv);
|
kfree(priv);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1107,6 +1173,7 @@ static int twl6040_remove(struct snd_soc_codec *codec)
|
|||||||
if (naudint)
|
if (naudint)
|
||||||
free_irq(naudint, codec);
|
free_irq(naudint, codec);
|
||||||
|
|
||||||
|
destroy_workqueue(priv->workqueue);
|
||||||
kfree(priv);
|
kfree(priv);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -135,4 +135,11 @@
|
|||||||
#define TWL6040_HPPLL_ID 1
|
#define TWL6040_HPPLL_ID 1
|
||||||
#define TWL6040_LPPLL_ID 2
|
#define TWL6040_LPPLL_ID 2
|
||||||
|
|
||||||
|
/* STATUS (0x2E) fields */
|
||||||
|
|
||||||
|
#define TWL6040_PLUGCOMP 0x02
|
||||||
|
|
||||||
|
void twl6040_hs_jack_detect(struct snd_soc_codec *codec,
|
||||||
|
struct snd_soc_jack *jack, int report);
|
||||||
|
|
||||||
#endif /* End of __TWL6040_H__ */
|
#endif /* End of __TWL6040_H__ */
|
||||||
|
Loading…
Reference in New Issue
Block a user