[alsa-devel] [PATCH] ASoC: rt5645: Adds push button support for rt5650
Bard Liao
bardliao at realtek.com
Tue Apr 7 13:55:18 CEST 2015
This patch exports rt5650_set_button_detect function for machine
driver to support rt5650 headset button detection function.
Signed-off-by: Bard Liao <bardliao at 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__ */
--
1.8.1.1.439.g50a6b54
More information about the Alsa-devel
mailing list