@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/platform_device.h>
@@ -1621,6 +1622,12 @@ static bool rt5651_jack_inserted(struct snd_soc_component *component)
struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
int val;
+ if (rt5651->gpiod_hp_det) {
+ val = gpiod_get_value_cansleep(rt5651->gpiod_hp_det);
+ dev_dbg(component->dev, "jack-detect gpio %d\n", val);
+ return val;
+ }
+
val = snd_soc_component_read32(component, RT5651_INT_IRQ_ST);
dev_dbg(component->dev, "irq status %#04x\n", val);
@@ -1761,6 +1768,13 @@ static int rt5651_detect_headset(struct snd_soc_component *component)
return SND_JACK_HEADPHONE;
}
+static bool rt5651_support_button_press(struct rt5651_priv *rt5651)
+{
+ /* Button press support only works with internal jack-detection */
+ return (rt5651->hp_jack->status & SND_JACK_MICROPHONE) &&
+ rt5651->gpiod_hp_det == NULL;
+}
+
static void rt5651_jack_detect_work(struct work_struct *work)
{
struct rt5651_priv *rt5651 =
@@ -1785,15 +1799,15 @@ static void rt5651_jack_detect_work(struct work_struct *work)
WARN_ON(rt5651->ovcd_irq_enabled);
rt5651_enable_micbias1_for_ovcd(component);
report = rt5651_detect_headset(component);
- if (report == SND_JACK_HEADSET) {
+ dev_dbg(component->dev, "detect report %#02x\n", report);
+ snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET);
+ if (rt5651_support_button_press(rt5651)) {
/* Enable ovcd IRQ for button press detect. */
rt5651_enable_micbias1_ovcd_irq(component);
} else {
/* No more need for overcurrent detect. */
rt5651_disable_micbias1_for_ovcd(component);
}
- dev_dbg(component->dev, "detect report %#02x\n", report);
- snd_soc_jack_report(rt5651->hp_jack, report, SND_JACK_HEADSET);
} else if (rt5651->ovcd_irq_enabled && rt5651_micbias1_ovcd(component)) {
dev_dbg(component->dev, "OVCD IRQ\n");
@@ -1837,16 +1851,20 @@ static void rt5651_cancel_work(void *data)
}
static void rt5651_enable_jack_detect(struct snd_soc_component *component,
- struct snd_soc_jack *hp_jack)
+ struct snd_soc_jack *hp_jack,
+ struct gpio_desc *gpiod_hp_det)
{
struct rt5651_priv *rt5651 = snd_soc_component_get_drvdata(component);
-
- /* IRQ output on GPIO1 */
- snd_soc_component_update_bits(component, RT5651_GPIO_CTRL1,
- RT5651_GP1_PIN_MASK, RT5651_GP1_PIN_IRQ);
+ bool using_internal_jack_detect = true;
/* Select jack detect source */
switch (rt5651->jd_src) {
+ case RT5651_JD_NULL:
+ rt5651->gpiod_hp_det = gpiod_hp_det;
+ if (!rt5651->gpiod_hp_det)
+ return; /* No jack detect */
+ using_internal_jack_detect = false;
+ break;
case RT5651_JD1_1:
snd_soc_component_update_bits(component, RT5651_JD_CTRL2,
RT5651_JD_TRG_SEL_MASK, RT5651_JD_TRG_SEL_JD1_1);
@@ -1865,16 +1883,20 @@ static void rt5651_enable_jack_detect(struct snd_soc_component *component,
snd_soc_component_update_bits(component, RT5651_IRQ_CTRL1,
RT5651_JD2_IRQ_EN, RT5651_JD2_IRQ_EN);
break;
- case RT5651_JD_NULL:
- return;
default:
dev_err(component->dev, "Currently only JD1_1 / JD1_2 / JD2 are supported\n");
return;
}
- /* Enable jack detect power */
- snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
- RT5651_PWR_JD_M, RT5651_PWR_JD_M);
+ if (using_internal_jack_detect) {
+ /* IRQ output on GPIO1 */
+ snd_soc_component_update_bits(component, RT5651_GPIO_CTRL1,
+ RT5651_GP1_PIN_MASK, RT5651_GP1_PIN_IRQ);
+
+ /* Enable jack detect power */
+ snd_soc_component_update_bits(component, RT5651_PWR_ANLG2,
+ RT5651_PWR_JD_M, RT5651_PWR_JD_M);
+ }
/* Set OVCD threshold current and scale-factor */
snd_soc_component_write(component, RT5651_PR_BASE + RT5651_BIAS_CUR4,
@@ -1903,7 +1925,7 @@ static void rt5651_enable_jack_detect(struct snd_soc_component *component,
RT5651_MB1_OC_STKY_MASK, RT5651_MB1_OC_STKY_EN);
rt5651->hp_jack = hp_jack;
- if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) {
+ if (rt5651_support_button_press(rt5651)) {
rt5651_enable_micbias1_for_ovcd(component);
rt5651_enable_micbias1_ovcd_irq(component);
}
@@ -1920,7 +1942,7 @@ static void rt5651_disable_jack_detect(struct snd_soc_component *component)
disable_irq(rt5651->irq);
rt5651_cancel_work(rt5651);
- if (rt5651->hp_jack->status & SND_JACK_MICROPHONE) {
+ if (rt5651_support_button_press(rt5651)) {
rt5651_disable_micbias1_ovcd_irq(component);
rt5651_disable_micbias1_for_ovcd(component);
snd_soc_jack_report(rt5651->hp_jack, 0, SND_JACK_BTN_0);
@@ -1933,7 +1955,7 @@ static int rt5651_set_jack(struct snd_soc_component *component,
struct snd_soc_jack *jack, void *data)
{
if (jack)
- rt5651_enable_jack_detect(component, jack);
+ rt5651_enable_jack_detect(component, jack, data);
else
rt5651_disable_jack_detect(component);
@@ -2073,6 +2073,7 @@ struct rt5651_priv {
struct regmap *regmap;
/* Jack and button detect data */
struct snd_soc_jack *hp_jack;
+ struct gpio_desc *gpiod_hp_det;
struct work_struct jack_detect_work;
struct delayed_work bp_work;
bool ovcd_irq_enabled;