|
@@ -2371,6 +2371,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,
|
|
static int rt5645_set_bias_level(struct snd_soc_codec *codec,
|
|
enum snd_soc_bias_level level)
|
|
enum snd_soc_bias_level level)
|
|
{
|
|
{
|
|
|
|
+ struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
|
|
|
|
+
|
|
switch (level) {
|
|
switch (level) {
|
|
case SND_SOC_BIAS_PREPARE:
|
|
case SND_SOC_BIAS_PREPARE:
|
|
if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
|
|
if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
|
|
@@ -2401,8 +2403,9 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
|
|
|
|
|
|
case SND_SOC_BIAS_OFF:
|
|
case SND_SOC_BIAS_OFF:
|
|
snd_soc_write(codec, RT5645_DEPOP_M2, 0x1100);
|
|
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,
|
|
snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
|
|
RT5645_PWR_VREF1 | RT5645_PWR_MB |
|
|
RT5645_PWR_VREF1 | RT5645_PWR_MB |
|
|
RT5645_PWR_BG | RT5645_PWR_VREF2 |
|
|
RT5645_PWR_BG | RT5645_PWR_VREF2 |
|
|
@@ -2417,28 +2420,71 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static int rt5645_jack_detect(struct snd_soc_codec *codec)
|
|
|
|
|
|
+static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec,
|
|
|
|
+ bool enable)
|
|
{
|
|
{
|
|
struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
|
|
struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
|
|
- int gpio_state, jack_type = 0;
|
|
|
|
- unsigned int val;
|
|
|
|
|
|
|
|
- if (!gpio_is_valid(rt5645->pdata.hp_det_gpio)) {
|
|
|
|
- dev_err(codec->dev, "invalid gpio\n");
|
|
|
|
- return -EINVAL;
|
|
|
|
|
|
+ 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);
|
|
|
|
+ pr_debug("%s read %x = %x\n", __func__, RT5650_4BTN_IL_CMD1,
|
|
|
|
+ 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");
|
|
|
|
+ if (rt5645->pdata.jd_mode == 0)
|
|
|
|
+ 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);
|
|
}
|
|
}
|
|
- gpio_state = gpio_get_value(rt5645->pdata.hp_det_gpio);
|
|
|
|
|
|
+}
|
|
|
|
|
|
- dev_dbg(codec->dev, "gpio = %d(%d)\n", rt5645->pdata.hp_det_gpio,
|
|
|
|
- gpio_state);
|
|
|
|
|
|
+static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert)
|
|
|
|
+{
|
|
|
|
+ struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
|
|
|
|
+ unsigned int val;
|
|
|
|
|
|
- if ((rt5645->pdata.gpio_hp_det_active_high && gpio_state) ||
|
|
|
|
- (!rt5645->pdata.gpio_hp_det_active_high && !gpio_state)) {
|
|
|
|
- snd_soc_dapm_force_enable_pin(&codec->dapm, "micbias1");
|
|
|
|
- snd_soc_dapm_force_enable_pin(&codec->dapm, "micbias2");
|
|
|
|
- snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
|
|
|
|
- snd_soc_dapm_force_enable_pin(&codec->dapm, "Mic Det Power");
|
|
|
|
- snd_soc_dapm_sync(&codec->dapm);
|
|
|
|
|
|
+ if (jack_insert) {
|
|
|
|
+ if (codec->component.card->instantiated) {
|
|
|
|
+ snd_soc_dapm_force_enable_pin(&codec->dapm,
|
|
|
|
+ "micbias1");
|
|
|
|
+ snd_soc_dapm_force_enable_pin(&codec->dapm,
|
|
|
|
+ "micbias2");
|
|
|
|
+ snd_soc_dapm_force_enable_pin(&codec->dapm,
|
|
|
|
+ "LDO2");
|
|
|
|
+ snd_soc_dapm_force_enable_pin(&codec->dapm,
|
|
|
|
+ "Mic Det Power");
|
|
|
|
+ snd_soc_dapm_sync(&codec->dapm);
|
|
|
|
+ } else {
|
|
|
|
+ /* Power up necessary bits for JD if dapm is
|
|
|
|
+ not ready yet */
|
|
|
|
+ snd_soc_update_bits(codec, RT5645_PWR_ANLG2,
|
|
|
|
+ RT5645_PWR_MB1 | RT5645_PWR_MB2,
|
|
|
|
+ RT5645_PWR_MB1 | RT5645_PWR_MB2);
|
|
|
|
+ snd_soc_update_bits(codec, RT5645_PWR_MIXER,
|
|
|
|
+ RT5645_PWR_LDO2, RT5645_PWR_LDO2);
|
|
|
|
+ snd_soc_update_bits(codec, RT5645_PWR_VOL,
|
|
|
|
+ RT5645_PWR_MIC_DET, RT5645_PWR_MIC_DET);
|
|
|
|
+ }
|
|
|
|
|
|
snd_soc_write(codec, RT5645_IN1_CTRL1, 0x0006);
|
|
snd_soc_write(codec, RT5645_IN1_CTRL1, 0x0006);
|
|
snd_soc_write(codec, RT5645_JD_CTRL3, 0x00b0);
|
|
snd_soc_write(codec, RT5645_JD_CTRL3, 0x00b0);
|
|
@@ -2452,32 +2498,62 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec)
|
|
val = snd_soc_read(codec, RT5645_IN1_CTRL3) & 0x7;
|
|
val = snd_soc_read(codec, RT5645_IN1_CTRL3) & 0x7;
|
|
dev_dbg(codec->dev, "val = %d\n", val);
|
|
dev_dbg(codec->dev, "val = %d\n", val);
|
|
|
|
|
|
- if (val == 1 || val == 2)
|
|
|
|
- jack_type = SND_JACK_HEADSET;
|
|
|
|
- else
|
|
|
|
- jack_type = SND_JACK_HEADPHONE;
|
|
|
|
|
|
+ if (codec->component.card->instantiated) {
|
|
|
|
+ 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);
|
|
|
|
+ } else {
|
|
|
|
+ snd_soc_update_bits(codec, RT5645_PWR_ANLG2,
|
|
|
|
+ RT5645_PWR_MB1 | RT5645_PWR_MB2, 0);
|
|
|
|
+ if (rt5645->pdata.jd_mode == 0)
|
|
|
|
+ snd_soc_update_bits(codec, RT5645_PWR_MIXER,
|
|
|
|
+ RT5645_PWR_LDO2, 0);
|
|
|
|
+ snd_soc_update_bits(codec, RT5645_PWR_VOL,
|
|
|
|
+ RT5645_PWR_MIC_DET, 0);
|
|
|
|
+ }
|
|
|
|
|
|
- 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) {
|
|
|
|
+ rt5645->jack_type = SND_JACK_HEADSET;
|
|
|
|
+ if (rt5645->en_button_func) {
|
|
|
|
+ msleep(100);
|
|
|
|
+ rt5645_enable_push_button_irq(codec, true);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ rt5645->jack_type = SND_JACK_HEADPHONE;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ } else { /* jack out */
|
|
|
|
+ rt5645->jack_type = 0;
|
|
|
|
+ if (rt5645->en_button_func)
|
|
|
|
+ rt5645_enable_push_button_irq(codec, false);
|
|
}
|
|
}
|
|
|
|
|
|
- snd_soc_jack_report(rt5645->hp_jack, jack_type, SND_JACK_HEADPHONE);
|
|
|
|
- snd_soc_jack_report(rt5645->mic_jack, jack_type, SND_JACK_MICROPHONE);
|
|
|
|
- return 0;
|
|
|
|
|
|
+ return rt5645->jack_type;
|
|
}
|
|
}
|
|
|
|
|
|
int rt5645_set_jack_detect(struct snd_soc_codec *codec,
|
|
int rt5645_set_jack_detect(struct snd_soc_codec *codec,
|
|
- struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack)
|
|
|
|
|
|
+ struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack,
|
|
|
|
+ struct snd_soc_jack *btn_jack)
|
|
{
|
|
{
|
|
struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
|
|
struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
|
|
|
|
|
|
rt5645->hp_jack = hp_jack;
|
|
rt5645->hp_jack = hp_jack;
|
|
rt5645->mic_jack = mic_jack;
|
|
rt5645->mic_jack = mic_jack;
|
|
- rt5645_jack_detect(codec);
|
|
|
|
|
|
+ rt5645->btn_jack = btn_jack;
|
|
|
|
+ if (rt5645->btn_jack && rt5645->codec_type == CODEC_TYPE_RT5650) {
|
|
|
|
+ rt5645->en_button_func = true;
|
|
|
|
+ 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_irq_detection(rt5645);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -2488,7 +2564,7 @@ static void rt5645_jack_detect_work(struct work_struct *work)
|
|
struct rt5645_priv *rt5645 =
|
|
struct rt5645_priv *rt5645 =
|
|
container_of(work, struct rt5645_priv, jack_detect_work.work);
|
|
container_of(work, struct rt5645_priv, jack_detect_work.work);
|
|
|
|
|
|
- rt5645_jack_detect(rt5645->codec);
|
|
|
|
|
|
+ rt5645_irq_detection(rt5645);
|
|
}
|
|
}
|
|
|
|
|
|
static irqreturn_t rt5645_irq(int irq, void *data)
|
|
static irqreturn_t rt5645_irq(int irq, void *data)
|
|
@@ -2501,6 +2577,125 @@ static irqreturn_t rt5645_irq(int irq, void *data)
|
|
return IRQ_HANDLED;
|
|
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(struct rt5645_priv *rt5645)
|
|
|
|
+{
|
|
|
|
+ int val, btn_type, gpio_state = 0, report = 0;
|
|
|
|
+
|
|
|
|
+ switch (rt5645->pdata.jd_mode) {
|
|
|
|
+ case 0: /* Not using rt5645 JD */
|
|
|
|
+ if (gpio_is_valid(rt5645->pdata.hp_det_gpio)) {
|
|
|
|
+ gpio_state = gpio_get_value(rt5645->pdata.hp_det_gpio);
|
|
|
|
+ dev_dbg(rt5645->codec->dev, "gpio = %d(%d)\n",
|
|
|
|
+ rt5645->pdata.hp_det_gpio, gpio_state);
|
|
|
|
+ }
|
|
|
|
+ if ((rt5645->pdata.gpio_hp_det_active_high && gpio_state) ||
|
|
|
|
+ (!rt5645->pdata.gpio_hp_det_active_high &&
|
|
|
|
+ !gpio_state)) {
|
|
|
|
+ report = rt5645_jack_detect(rt5645->codec, 1);
|
|
|
|
+ } else {
|
|
|
|
+ report = rt5645_jack_detect(rt5645->codec, 0);
|
|
|
|
+ }
|
|
|
|
+ snd_soc_jack_report(rt5645->hp_jack,
|
|
|
|
+ report, SND_JACK_HEADPHONE);
|
|
|
|
+ snd_soc_jack_report(rt5645->mic_jack,
|
|
|
|
+ report, SND_JACK_MICROPHONE);
|
|
|
|
+ return report;
|
|
|
|
+ case 1: /* 2 port */
|
|
|
|
+ val = snd_soc_read(rt5645->codec, RT5645_A_JD_CTRL1) & 0x0070;
|
|
|
|
+ break;
|
|
|
|
+ default: /* 1 port */
|
|
|
|
+ val = snd_soc_read(rt5645->codec, RT5645_A_JD_CTRL1) & 0x0020;
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ switch (val) {
|
|
|
|
+ /* jack in */
|
|
|
|
+ case 0x30: /* 2 port */
|
|
|
|
+ case 0x0: /* 1 port or 2 port */
|
|
|
|
+ if (rt5645->jack_type == 0) {
|
|
|
|
+ report = rt5645_jack_detect(rt5645->codec, 1);
|
|
|
|
+ /* for push button and jack out */
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ btn_type = 0;
|
|
|
|
+ if (snd_soc_read(rt5645->codec, RT5645_INT_IRQ_ST) & 0x4) {
|
|
|
|
+ /* button pressed */
|
|
|
|
+ report = SND_JACK_HEADSET;
|
|
|
|
+ btn_type = rt5645_button_detect(rt5645->codec);
|
|
|
|
+ /* rt5650 can report three kinds of button behavior,
|
|
|
|
+ one click, double click and hold. However,
|
|
|
|
+ currently we will report button pressed/released
|
|
|
|
+ event. So all the three button behaviors are
|
|
|
|
+ treated as button pressed. */
|
|
|
|
+ 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);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (btn_type == 0)/* button release */
|
|
|
|
+ report = rt5645->jack_type;
|
|
|
|
+
|
|
|
|
+ break;
|
|
|
|
+ /* jack out */
|
|
|
|
+ case 0x70: /* 2 port */
|
|
|
|
+ case 0x10: /* 2 port */
|
|
|
|
+ case 0x20: /* 1 port */
|
|
|
|
+ report = 0;
|
|
|
|
+ snd_soc_update_bits(rt5645->codec,
|
|
|
|
+ RT5645_INT_IRQ_ST, 0x1, 0x0);
|
|
|
|
+ rt5645_jack_detect(rt5645->codec, 0);
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ snd_soc_jack_report(rt5645->hp_jack, report, SND_JACK_HEADPHONE);
|
|
|
|
+ snd_soc_jack_report(rt5645->mic_jack, report, SND_JACK_MICROPHONE);
|
|
|
|
+ if (rt5645->en_button_func)
|
|
|
|
+ snd_soc_jack_report(rt5645->btn_jack,
|
|
|
|
+ report, SND_JACK_MICROPHONE);
|
|
|
|
+
|
|
|
|
+ return report;
|
|
|
|
+}
|
|
|
|
+
|
|
static int rt5645_probe(struct snd_soc_codec *codec)
|
|
static int rt5645_probe(struct snd_soc_codec *codec)
|
|
{
|
|
{
|
|
struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
|
|
struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
|
|
@@ -2840,8 +3035,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
|
|
|
|
|
|
if (rt5645->pdata.en_jd_func) {
|
|
if (rt5645->pdata.en_jd_func) {
|
|
regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3,
|
|
regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3,
|
|
- RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU,
|
|
|
|
- RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU);
|
|
|
|
|
|
+ RT5645_IRQ_CLK_GATE_CTRL, RT5645_IRQ_CLK_GATE_CTRL);
|
|
regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1,
|
|
regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1,
|
|
RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN);
|
|
RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN);
|
|
regmap_update_bits(rt5645->regmap, RT5645_JD_CTRL3,
|
|
regmap_update_bits(rt5645->regmap, RT5645_JD_CTRL3,
|