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@xxxxxxxxxx> --- sound/soc/codecs/rt5640.c | 45 +++++++++++++++++++++++++++++++++++---- sound/soc/codecs/rt5640.h | 5 +++++ 2 files changed, 46 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); diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 2f4da5a8ecb2..9e49b9a0ccaa 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -2124,6 +2124,7 @@ struct rt5640_priv { int ldo1_en; /* GPIO for LDO1_EN */ int irq; + int jd_gpio_irq; int sysclk; int sysclk_src; int lrck[RT5640_AIFS]; @@ -2136,6 +2137,8 @@ struct rt5640_priv { bool hp_mute; bool asrc_en; + bool irq_requested; + bool jd_gpio_irq_requested; /* Jack and button detect data */ bool ovcd_irq_enabled; @@ -2147,6 +2150,7 @@ struct rt5640_priv { struct delayed_work bp_work; struct delayed_work jack_work; struct snd_soc_jack *jack; + struct gpio_desc *jd_gpio; unsigned int jd_src; bool jd_inverted; unsigned int ovcd_th; @@ -2155,6 +2159,7 @@ struct rt5640_priv { struct rt5640_set_jack_data { int codec_irq_override; + struct gpio_desc *jd_gpio; }; int rt5640_dmic_enable(struct snd_soc_component *component, -- 2.33.1