[alsa-devel] [PATCH] ASoC: rt5645: Adds push button support for rt5650
This patch exports rt5650_set_button_detect function for machine driver to support rt5650 headset button detection function.
Signed-off-by: Bard Liao bardliao@realtek.com --- sound/soc/codecs/rt5645.c | 147 +++++++++++++++++++++++++++++++++++++++++++--- sound/soc/codecs/rt5645.h | 7 ++- 2 files changed, 146 insertions(+), 8 deletions(-)
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 69528ae..e547a994 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2368,6 +2368,8 @@ static int rt5645_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, static int rt5645_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); + switch (level) { case SND_SOC_BIAS_PREPARE: if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) { @@ -2398,8 +2400,9 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_OFF: snd_soc_write(codec, RT5645_DEPOP_M2, 0x1100); - snd_soc_update_bits(codec, RT5645_GEN_CTRL1, - RT5645_DIG_GATE_CTRL, 0); + if (!rt5645->en_button_func) + snd_soc_update_bits(codec, RT5645_GEN_CTRL1, + RT5645_DIG_GATE_CTRL, 0); snd_soc_update_bits(codec, RT5645_PWR_ANLG1, RT5645_PWR_VREF1 | RT5645_PWR_MB | RT5645_PWR_BG | RT5645_PWR_VREF2 | @@ -2414,6 +2417,37 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec, return 0; }
+static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec, + bool enable) +{ + if (enable) { + snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm, + "ADC L power"); + snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm, + "ADC R power"); + snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm, + "LDO2"); + snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm, + "Mic Det Power"); + snd_soc_dapm_sync_unlocked(&codec->dapm); + snd_soc_update_bits(codec, RT5645_INT_IRQ_ST, 0x8, 0x8); + snd_soc_update_bits(codec, RT5650_4BTN_IL_CMD2, 0x8000, 0x8000); + snd_soc_read(codec, RT5650_4BTN_IL_CMD1); + } else { + snd_soc_update_bits(codec, RT5650_4BTN_IL_CMD2, 0x8000, 0x0); + snd_soc_update_bits(codec, RT5645_INT_IRQ_ST, 0x8, 0x0); + snd_soc_dapm_disable_pin_unlocked(&codec->dapm, + "ADC L power"); + snd_soc_dapm_disable_pin_unlocked(&codec->dapm, + "ADC R power"); + snd_soc_dapm_disable_pin_unlocked(&codec->dapm, + "LDO2"); + snd_soc_dapm_disable_pin_unlocked(&codec->dapm, + "Mic Det Power"); + snd_soc_dapm_sync_unlocked(&codec->dapm); + } +} + static int rt5645_jack_detect(struct snd_soc_codec *codec) { struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); @@ -2449,17 +2483,24 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec) val = snd_soc_read(codec, RT5645_IN1_CTRL3) & 0x7; dev_dbg(codec->dev, "val = %d\n", val);
- if (val == 1 || val == 2) - jack_type = SND_JACK_HEADSET; - else - jack_type = SND_JACK_HEADPHONE; - snd_soc_dapm_disable_pin(&codec->dapm, "micbias1"); snd_soc_dapm_disable_pin(&codec->dapm, "micbias2"); if (rt5645->pdata.jd_mode == 0) snd_soc_dapm_disable_pin(&codec->dapm, "LDO2"); snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power"); snd_soc_dapm_sync(&codec->dapm); + + if (val == 1 || val == 2) { + jack_type = SND_JACK_HEADSET; + if (rt5645->en_button_func) + rt5645_enable_push_button_irq(codec, true); + } else { + jack_type = SND_JACK_HEADPHONE; + } + + } else { /* jack out */ + if (rt5645->en_button_func) + rt5645_enable_push_button_irq(codec, false); }
snd_soc_jack_report(rt5645->hp_jack, jack_type, SND_JACK_HEADPHONE); @@ -2480,6 +2521,42 @@ int rt5645_set_jack_detect(struct snd_soc_codec *codec, } EXPORT_SYMBOL_GPL(rt5645_set_jack_detect);
+int rt5650_set_button_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *jack) +{ + struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); + int ret; + + rt5645->jack = jack; + rt5645->codec_irq.gpiod_dev = codec->dev; + rt5645->codec_irq.name = "rt5650 irq"; + rt5645->codec_irq.report = SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3; + rt5645->codec_irq.debounce_time = 150; + rt5645->codec_irq.wake = true; + rt5645->codec_irq.data = (struct rt5645_priv *)rt5645; + rt5645->codec_irq.jack_status_check = rt5645_irq_detection; + + ret = snd_soc_jack_add_gpios(rt5645->jack, 1, + &rt5645->codec_irq); + if (ret) { + dev_err(codec->dev, "Adding jack GPIO failed\n"); + return ret; + } + + regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, + RT5645_GP1_PIN_IRQ, RT5645_GP1_PIN_IRQ); + regmap_update_bits(rt5645->regmap, RT5645_DEPOP_M1, + RT5645_HP_CB_MASK, RT5645_HP_CB_PU); + regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL1, + RT5645_DIG_GATE_CTRL, RT5645_DIG_GATE_CTRL); + rt5645->en_button_func = true; + + return 0; +} +EXPORT_SYMBOL_GPL(rt5650_set_button_detect); + static void rt5645_jack_detect_work(struct work_struct *work) { struct rt5645_priv *rt5645 = @@ -2498,6 +2575,62 @@ static irqreturn_t rt5645_irq(int irq, void *data) return IRQ_HANDLED; }
+static int rt5645_button_detect(struct snd_soc_codec *codec) +{ + int btn_type, val; + + val = snd_soc_read(codec, RT5650_4BTN_IL_CMD1); + pr_debug("val=0x%x\n", val); + btn_type = val & 0xfff0; + snd_soc_write(codec, RT5650_4BTN_IL_CMD1, val); + + return btn_type; +} + +static int rt5645_irq_detection(void *data) +{ + struct rt5645_priv *rt5645 = (struct rt5645_priv *)data; + struct snd_soc_jack *jack = &rt5645->jack; + int btn_type, report = SND_JACK_HEADSET; + + btn_type = rt5645_button_detect(rt5645->codec); + switch (btn_type) { + case 0x8000: + case 0x4000: + case 0x2000: + report |= SND_JACK_BTN_0; + break; + case 0x1000: + case 0x0800: + case 0x0400: + report |= SND_JACK_BTN_1; + break; + case 0x0200: + case 0x0100: + case 0x0080: + report |= SND_JACK_BTN_2; + break; + case 0x0040: + case 0x0020: + case 0x0010: + report |= SND_JACK_BTN_3; + break; + case 0x0000: /* unpressed */ + break; + default: + dev_err(rt5645->codec->dev, + "Unexpected button code 0x%04x\n", + btn_type); + /* keep the jack status */ + report = jack->status; + break; + } + + pr_debug("report=%x\n", report); + + return report; +} + static int rt5645_probe(struct snd_soc_codec *codec) { struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h index db78e94..bf29d8b 100644 --- a/sound/soc/codecs/rt5645.h +++ b/sound/soc/codecs/rt5645.h @@ -2184,7 +2184,9 @@ struct rt5645_priv { struct i2c_client *i2c; struct snd_soc_jack *hp_jack; struct snd_soc_jack *mic_jack; + struct snd_soc_jack *jack; struct delayed_work jack_detect_work; + struct snd_soc_jack_gpio codec_irq;
int codec_type; int sysclk; @@ -2196,9 +2198,12 @@ struct rt5645_priv { int pll_src; int pll_in; int pll_out; + + bool en_button_func; };
int rt5645_set_jack_detect(struct snd_soc_codec *codec, struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack); - +int rt5650_set_button_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *jack); #endif /* __RT5645_H__ */
participants (2)
-
Bard Liao
-
Mark Brown