summaryrefslogtreecommitdiff
path: root/sound/soc/codecs/rt5640.c
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2022-01-06 14:01:26 +0300
committerMark Brown <broonie@kernel.org>2022-01-06 16:55:50 +0300
commit701d636a224a77a4371f57ca2d4322ab0401a866 (patch)
tree9512208d0bf7fb3a7dad83e291ad67ffde933c45 /sound/soc/codecs/rt5640.c
parentb35a9ab4904973a68b4473c2985b8ac0b6d57089 (diff)
downloadlinux-701d636a224a77a4371f57ca2d4322ab0401a866.tar.xz
ASoC: rt5640: Add support for boards with an external jack-detect GPIO
Some boards have the codec IRQ hooked-up as normally, so the driver can still do things like headset vs headphones and button-press detection, but instead of using one of the JD pins of the codec, an external GPIO is used to report the jack-presence switch status of the jack. Add support for this. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Link: https://lore.kernel.org/r/20220106110128.66049-5-hdegoede@redhat.com Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/codecs/rt5640.c')
-rw-r--r--sound/soc/codecs/rt5640.c45
1 files changed, 41 insertions, 4 deletions
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c
index fabc6e44b4a6..e7a82565b905 100644
--- a/sound/soc/codecs/rt5640.c
+++ b/sound/soc/codecs/rt5640.c
@@ -2160,7 +2160,11 @@ static bool rt5640_jack_inserted(struct snd_soc_component *component)
struct rt5640_priv *rt5640 = snd_soc_component_get_drvdata(component);
int val;
- val = snd_soc_component_read(component, RT5640_INT_IRQ_ST);
+ if (rt5640->jd_gpio)
+ val = gpiod_get_value(rt5640->jd_gpio) ? RT5640_JD_STATUS : 0;
+ else
+ val = snd_soc_component_read(component, RT5640_INT_IRQ_ST);
+
dev_dbg(component->dev, "irq status %#04x\n", val);
if (rt5640->jd_inverted)
@@ -2395,6 +2399,16 @@ static irqreturn_t rt5640_irq(int irq, void *data)
return IRQ_HANDLED;
}
+static irqreturn_t rt5640_jd_gpio_irq(int irq, void *data)
+{
+ struct rt5640_priv *rt5640 = data;
+
+ queue_delayed_work(system_long_wq, &rt5640->jack_work,
+ msecs_to_jiffies(JACK_SETTLE_TIME));
+
+ return IRQ_HANDLED;
+}
+
static void rt5640_cancel_work(void *data)
{
struct rt5640_priv *rt5640 = data;
@@ -2439,7 +2453,12 @@ static void rt5640_disable_jack_detect(struct snd_soc_component *component)
if (!rt5640->jack)
return;
- free_irq(rt5640->irq, rt5640);
+ if (rt5640->jd_gpio_irq_requested)
+ free_irq(rt5640->jd_gpio_irq, rt5640);
+
+ if (rt5640->irq_requested)
+ free_irq(rt5640->irq, rt5640);
+
rt5640_cancel_work(rt5640);
if (rt5640->jack->status & SND_JACK_MICROPHONE) {
@@ -2448,6 +2467,9 @@ static void rt5640_disable_jack_detect(struct snd_soc_component *component)
snd_soc_jack_report(rt5640->jack, 0, SND_JACK_BTN_0);
}
+ rt5640->jd_gpio_irq_requested = false;
+ rt5640->irq_requested = false;
+ rt5640->jd_gpio = NULL;
rt5640->jack = NULL;
}
@@ -2500,16 +2522,31 @@ static void rt5640_enable_jack_detect(struct snd_soc_component *component,
if (jack_data && jack_data->codec_irq_override)
rt5640->irq = jack_data->codec_irq_override;
+ if (jack_data && jack_data->jd_gpio) {
+ rt5640->jd_gpio = jack_data->jd_gpio;
+ rt5640->jd_gpio_irq = gpiod_to_irq(rt5640->jd_gpio);
+
+ ret = request_irq(rt5640->jd_gpio_irq, rt5640_jd_gpio_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "rt5640-jd-gpio", rt5640);
+ if (ret) {
+ dev_warn(component->dev, "Failed to request jd GPIO IRQ %d: %d\n",
+ rt5640->jd_gpio_irq, ret);
+ rt5640_disable_jack_detect(component);
+ return;
+ }
+ rt5640->jd_gpio_irq_requested = true;
+ }
+
ret = request_irq(rt5640->irq, rt5640_irq,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"rt5640", rt5640);
if (ret) {
dev_warn(component->dev, "Failed to reguest IRQ %d: %d\n", rt5640->irq, ret);
- rt5640->irq = -ENXIO;
- /* Undo above settings */
rt5640_disable_jack_detect(component);
return;
}
+ rt5640->irq_requested = true;
/* sync initial jack state */
queue_delayed_work(system_long_wq, &rt5640->jack_work, 0);