rk3368 codec : add support for headset detection of es8316
authorsmj <smj@rock-chips.com>
Fri, 6 Mar 2015 04:09:26 +0000 (12:09 +0800)
committersmj <smj@rock-chips.com>
Fri, 6 Mar 2015 04:09:55 +0000 (12:09 +0800)
Signed-off-by: smj <smj@rock-chips.com>
arch/arm64/boot/dts/rk3368-p9_818.dts
sound/soc/codecs/es8316.c

index 3b0a7130331b9c17654c92ef075ddc5740bf5d07..ef661fbffc985ef1d63300cf941bf3aaa0ad8f6d 100755 (executable)
                        gpio0_c2: gpio0-c2 {
                                rockchip,pins = <0 GPIO_C2 RK_FUNC_GPIO &pcfg_pull_down>;
                        };
-
+                       gpio0_c3: gpio0-c3{
+                               rockchip,pins = <0 GPIO_C3 RK_FUNC_GPIO &pcfg_pull_down>;
+                       };
                        //to add
                };
 
        es8316: es8316@10 {
                compatible = "es8316";
                reg = <0x10>;
+               spk-con-gpio = <&gpio0 GPIO_C3 GPIO_ACTIVE_HIGH>;
+               hp-det-gpio = <&gpio0 GPIO_C7 GPIO_ACTIVE_HIGH>;
                status = "okay";
        };
 };
index 9873e9500c87b13043a2aaf90d676ec4e62c5a05..e6f982691b2a048883d974d61b33cc1cb8429577 100644 (file)
 #define amic_used  0
 
 #define INVALID_GPIO -1
-int es8316_spk_con_gpio = INVALID_GPIO;
-int es8316_hp_con_gpio = INVALID_GPIO;
-int es8316_hp_det_gpio = INVALID_GPIO;
+
+#define ES8316_CODEC_SET_SPK   1
+#define ES8316_CODEC_SET_HP    2
+
+
 int HP_IRQ = 0;
 int hp_irq_flag = 0;
 int es8316_init_reg = 0;
@@ -107,8 +109,73 @@ struct es8316_priv {
        unsigned int dmic_amic;
        unsigned int sysclk;
        struct snd_pcm_hw_constraint_list *sysclk_constraints;
+
+       int spk_ctl_gpio;
+       int hp_ctl_gpio;
+       int hp_det_gpio;
+
+       bool spk_gpio_level;
+       bool hp_gpio_level;
+       bool hp_det_level;
 };
 
+struct es8316_priv *es8316_private;
+static int es8316_set_gpio(int gpio, bool level)
+{
+       struct es8316_priv *es8316 = es8316_private;
+
+       if (!es8316) {
+               DBG("%s : es8316_priv is NULL\n", __func__);
+               return 0;
+       }
+       DBG("%s : set %s %s ctl gpio %s\n", __func__,
+           gpio & ES8316_CODEC_SET_SPK ? "spk" : "",
+           gpio & ES8316_CODEC_SET_HP ? "hp" : "",
+           level ? "HIGH" : "LOW");
+       if ((gpio & ES8316_CODEC_SET_SPK)
+           && es8316 && es8316->spk_ctl_gpio != INVALID_GPIO) {
+               DBG("%d,set_value%s\n", es8316->spk_ctl_gpio, level ?
+                   "HIGH" : "LOW");
+               gpio_set_value(es8316->spk_ctl_gpio, level);
+       }
+       return 0;
+}
+
+static char mute_flag = 1;
+static irqreturn_t hp_det_irq_handler(int irq, void *dev_id)
+{
+       int ret;
+       unsigned int type;
+       struct es8316_priv *es8316 = es8316_private;
+
+       disable_irq_nosync(irq);
+
+       type = gpio_get_value(es8316->hp_det_gpio) ?
+               IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING;
+       ret = irq_set_irq_type(irq, type);
+       if (ret < 0) {
+               DBG("%s: irq_set_irq_type(%d, %d) failed\n",
+                   __func__, irq, type);
+               return -1;
+       }
+
+       if (type == IRQ_TYPE_EDGE_FALLING)
+               hp_irq_flag = 0;
+       else
+               hp_irq_flag = 1;
+       if (mute_flag == 0) {
+               if (es8316->hp_det_level == gpio_get_value(es8316->hp_det_gpio))
+                       es8316_set_gpio(ES8316_CODEC_SET_SPK,
+                                       !es8316->spk_gpio_level);
+               else
+                       es8316_set_gpio(ES8316_CODEC_SET_SPK,
+                                       es8316->spk_gpio_level);
+       }
+       enable_irq(irq);
+
+       return IRQ_HANDLED;
+}
+
 /*
 * es8316S Controls
 */
@@ -795,12 +862,21 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream,
 static int es8316_mute(struct snd_soc_dai *dai, int mute)
 {
        struct snd_soc_codec *codec = dai->codec;
+       struct es8316_priv *es8316 = es8316_private;
 
-       dev_dbg(codec->dev, "%s %d\n", __func__, mute);
-       if (mute)
+       mute_flag = mute;
+       if (mute) {
+               es8316_set_gpio(ES8316_CODEC_SET_SPK, !es8316->spk_gpio_level);
+               msleep(100);
                snd_soc_write(codec, ES8316_DAC_SET1_REG30, 0x20);
-       else if (dai->playback_active)
+       } else if (dai->playback_active) {
                snd_soc_write(codec, ES8316_DAC_SET1_REG30, 0x00);
+               msleep(130);
+               if (hp_irq_flag == 0)
+                       es8316_set_gpio(ES8316_CODEC_SET_SPK,
+                                       es8316->spk_gpio_level);
+               msleep(150);
+       }
        return 0;
 }
 
@@ -1092,9 +1168,15 @@ static struct spi_driver es8316_spi_driver = {
 static void es8316_i2c_shutdown(struct i2c_client *i2c)
 {
        struct snd_soc_codec *codec;
+       struct es8316_priv *es8316 = es8316_private;
 
        if (!es8316_codec)
                goto err;
+
+       es8316_set_gpio(ES8316_CODEC_SET_SPK, !es8316->spk_gpio_level);
+       mdelay(150);
+
+
        codec = es8316_codec;
        snd_soc_write(codec, ES8316_CPHP_ICAL_VOL_REG18, 0x33);
        snd_soc_write(codec, ES8316_CPHP_OUTEN_REG17, 0x00);
@@ -1118,14 +1200,68 @@ static int es8316_i2c_probe(struct i2c_client *i2c_client,
 {
        struct es8316_priv *es8316;
        int ret = -1;
+       unsigned long irq_flag = 0;
+       int hp_irq = 0;
+       enum of_gpio_flags flags;
+       struct device_node *np = i2c_client->dev.of_node;
 
        DBG("---%s---probe start\n", __func__);
 
        es8316 = kzalloc(sizeof(*es8316), GFP_KERNEL);
        if (es8316 == NULL)
                return -ENOMEM;
+       else
+               es8316_private = es8316;
+
        es8316->dmic_amic = amic_used;     /*if internal mic is amic*/
        i2c_set_clientdata(i2c_client, es8316);
+
+
+       es8316->spk_ctl_gpio = of_get_named_gpio_flags(np,
+                                       "spk-con-gpio", 0, &flags);
+       if (es8316->spk_ctl_gpio < 0) {
+               DBG("%s() Can not read property spk codec-en-gpio\n", __func__);
+               es8316->spk_ctl_gpio = INVALID_GPIO;
+       } else {
+           es8316->spk_gpio_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
+           ret = gpio_request(es8316->spk_ctl_gpio, NULL);
+           gpio_direction_output(es8316->spk_ctl_gpio,
+                                 !es8316->spk_gpio_level);
+       }
+
+       es8316->hp_ctl_gpio = of_get_named_gpio_flags(np,
+                                       "hp-con-gpio", 0, &flags);
+       if (es8316->hp_ctl_gpio < 0) {
+               DBG("%s() Can not read property hp codec-en-gpio\n", __func__);
+               es8316->hp_ctl_gpio = INVALID_GPIO;
+       } else {
+           es8316->hp_gpio_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
+           ret = gpio_request(es8316->hp_ctl_gpio, NULL);
+           gpio_direction_output(es8316->hp_ctl_gpio, !es8316->hp_gpio_level);
+       }
+
+       es8316->hp_det_gpio = of_get_named_gpio_flags(np,
+                                       "hp-det-gpio", 0, &flags);
+       if (es8316->hp_det_gpio < 0) {
+               DBG("%s() Can not read property hp_det gpio\n", __func__);
+               es8316->hp_det_gpio = INVALID_GPIO;
+       } else {
+               es8316->hp_det_level = (flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
+               ret = gpio_request(es8316->hp_det_gpio, NULL);
+               if (ret != 0) {
+                       DBG("%s request HP_DET error", __func__);
+                       return ret;
+               }
+               gpio_direction_input(es8316->hp_det_gpio);
+
+               irq_flag = IRQF_TRIGGER_LOW | IRQF_ONESHOT;
+               hp_irq = gpio_to_irq(es8316->hp_det_gpio);
+
+               if (hp_irq)
+                       ret = request_threaded_irq(hp_irq, NULL,
+                               hp_det_irq_handler, irq_flag, "ES8316", NULL);
+       }
+
        ret = snd_soc_register_codec(&i2c_client->dev,
                                     &soc_codec_dev_es8316,
                                     &es8316_dai, 1);
@@ -1134,6 +1270,8 @@ static int es8316_i2c_probe(struct i2c_client *i2c_client,
                return ret;
        }
 
+
+
        return ret;
 }