ASoC: rt5677: add GPIO IRQ support
authorOder Chiou <oder_chiou@realtek.com>
Thu, 16 Oct 2014 18:24:26 +0000 (11:24 -0700)
committerMark Brown <broonie@kernel.org>
Wed, 22 Oct 2014 10:43:14 +0000 (11:43 +0100)
This allows to enable Mic Jack detection feature

Signed-off-by: Oder Chiou <oder_chiou@realtek.com>
Modified-by: Anatol Pomozov <anatol.pomozov@gmail.com>
Signed-off-by: Anatol Pomozov <anatol.pomozov@gmail.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Documentation/devicetree/bindings/sound/rt5677.txt
include/sound/rt5677.h
sound/soc/codecs/rt5677.c
sound/soc/codecs/rt5677.h

index f82f0e906cd91e4d1ce467c7e9085016415c9550..740ff771aa8b319ceeb1b282635534859cdec1db 100644 (file)
@@ -33,6 +33,15 @@ Optional properties:
     1 - pull down
     2 - pull up
 
+- realtek,jd1-gpio
+  Configures GPIO Mic Jack detection 1.
+  Select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively.
+
+- realtek,jd2-gpio
+- realtek,jd3-gpio
+  Configures GPIO Mic Jack detection 2 and 3.
+  Select 0 ~ 3 as OFF, GPIO4, GPIO5 and GPIO6 respectively.
+
 Pins on the device (for linking into audio routes):
 
   * IN1P
@@ -63,4 +72,5 @@ rt5677 {
                <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
        realtek,in1-differential = "true";
        realtek,gpio-config = /bits/ 8  <0 0 0 0 0 2>;   /* pull up GPIO6 */
+       realtek,jd2-gpio = <3>;  /* Enables Jack detection for GPIO6 */
 };
index a56b429a1dbc649e20a20a3d59182053ec051865..d9eb7d861cd0da77722e178b3c3f94ee88ba9b99 100644 (file)
@@ -30,6 +30,13 @@ struct rt5677_platform_data {
 
        /* configures GPIO, 0 - floating, 1 - pulldown, 2 - pullup */
        u8 gpio_config[6];
+
+       /* jd1 can select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively */
+       unsigned int jd1_gpio;
+       /* jd2 and jd3 can select 0 ~ 3 as
+               OFF, GPIO4, GPIO5 and GPIO6 respectively */
+       unsigned int jd2_gpio;
+       unsigned int jd3_gpio;
 };
 
 #endif
index d17d079fdcf3c01d932b64ba738f636043d767a8..6c73dfd22a0c5dbdbb1025dbdf1055ca23095624 100644 (file)
@@ -3614,6 +3614,46 @@ static void rt5677_gpio_config(struct rt5677_priv *rt5677, unsigned offset,
        }
 }
 
+static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       struct rt5677_priv *rt5677 = gpio_to_rt5677(chip);
+       struct regmap_irq_chip_data *data = rt5677->irq_data;
+       int irq;
+
+       if (offset >= RT5677_GPIO1 && offset <= RT5677_GPIO3) {
+               if ((rt5677->pdata.jd1_gpio == 1 && offset == RT5677_GPIO1) ||
+                       (rt5677->pdata.jd1_gpio == 2 &&
+                               offset == RT5677_GPIO2) ||
+                       (rt5677->pdata.jd1_gpio == 3 &&
+                               offset == RT5677_GPIO3)) {
+                       irq = RT5677_IRQ_JD1;
+               } else {
+                       return -ENXIO;
+               }
+       }
+
+       if (offset >= RT5677_GPIO4 && offset <= RT5677_GPIO6) {
+               if ((rt5677->pdata.jd2_gpio == 1 && offset == RT5677_GPIO4) ||
+                       (rt5677->pdata.jd2_gpio == 2 &&
+                               offset == RT5677_GPIO5) ||
+                       (rt5677->pdata.jd2_gpio == 3 &&
+                               offset == RT5677_GPIO6)) {
+                       irq = RT5677_IRQ_JD2;
+               } else if ((rt5677->pdata.jd3_gpio == 1 &&
+                               offset == RT5677_GPIO4) ||
+                       (rt5677->pdata.jd3_gpio == 2 &&
+                               offset == RT5677_GPIO5) ||
+                       (rt5677->pdata.jd3_gpio == 3 &&
+                               offset == RT5677_GPIO6)) {
+                       irq = RT5677_IRQ_JD3;
+               } else {
+                       return -ENXIO;
+               }
+       }
+
+       return regmap_irq_get_virq(data, irq);
+}
+
 static struct gpio_chip rt5677_template_chip = {
        .label                  = "rt5677",
        .owner                  = THIS_MODULE,
@@ -3621,6 +3661,7 @@ static struct gpio_chip rt5677_template_chip = {
        .set                    = rt5677_gpio_set,
        .direction_input        = rt5677_gpio_direction_in,
        .get                    = rt5677_gpio_get,
+       .to_irq                 = rt5677_to_irq,
        .can_sleep              = 1,
 };
 
@@ -3685,6 +3726,31 @@ static int rt5677_probe(struct snd_soc_codec *codec)
        for (i = 0; i < RT5677_GPIO_NUM; i++)
                rt5677_gpio_config(rt5677, i, rt5677->pdata.gpio_config[i]);
 
+       if (rt5677->irq_data) {
+               regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, 0x8000,
+                       0x8000);
+               regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x0018,
+                       0x0008);
+
+               if (rt5677->pdata.jd1_gpio)
+                       regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1,
+                               RT5677_SEL_GPIO_JD1_MASK,
+                               rt5677->pdata.jd1_gpio <<
+                               RT5677_SEL_GPIO_JD1_SFT);
+
+               if (rt5677->pdata.jd2_gpio)
+                       regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1,
+                               RT5677_SEL_GPIO_JD2_MASK,
+                               rt5677->pdata.jd2_gpio <<
+                               RT5677_SEL_GPIO_JD2_SFT);
+
+               if (rt5677->pdata.jd3_gpio)
+                       regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1,
+                               RT5677_SEL_GPIO_JD3_MASK,
+                               rt5677->pdata.jd3_gpio <<
+                               RT5677_SEL_GPIO_JD3_SFT);
+       }
+
        mutex_init(&rt5677->dsp_cmd_lock);
 
        return 0;
@@ -3915,9 +3981,74 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np)
        of_property_read_u8_array(np, "realtek,gpio-config",
                rt5677->pdata.gpio_config, RT5677_GPIO_NUM);
 
+       of_property_read_u32(np, "realtek,jd1-gpio", &rt5677->pdata.jd1_gpio);
+       of_property_read_u32(np, "realtek,jd2-gpio", &rt5677->pdata.jd2_gpio);
+       of_property_read_u32(np, "realtek,jd3-gpio", &rt5677->pdata.jd3_gpio);
+
        return 0;
 }
 
+static struct regmap_irq rt5677_irqs[] = {
+       [RT5677_IRQ_JD1] = {
+               .reg_offset = 0,
+               .mask = RT5677_EN_IRQ_GPIO_JD1,
+       },
+       [RT5677_IRQ_JD2] = {
+               .reg_offset = 0,
+               .mask = RT5677_EN_IRQ_GPIO_JD2,
+       },
+       [RT5677_IRQ_JD3] = {
+               .reg_offset = 0,
+               .mask = RT5677_EN_IRQ_GPIO_JD3,
+       },
+};
+
+static struct regmap_irq_chip rt5677_irq_chip = {
+       .name = "rt5677",
+       .irqs = rt5677_irqs,
+       .num_irqs = ARRAY_SIZE(rt5677_irqs),
+
+       .num_regs = 1,
+       .status_base = RT5677_IRQ_CTRL1,
+       .mask_base = RT5677_IRQ_CTRL1,
+       .mask_invert = 1,
+};
+
+int rt5677_irq_init(struct i2c_client *i2c)
+{
+       int ret;
+       struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c);
+
+       if (!rt5677->pdata.jd1_gpio &&
+               !rt5677->pdata.jd2_gpio &&
+               !rt5677->pdata.jd3_gpio)
+               return 0;
+
+       if (!i2c->irq) {
+               dev_err(&i2c->dev, "No interrupt specified\n");
+               return -EINVAL;
+       }
+
+       ret = regmap_add_irq_chip(rt5677->regmap, i2c->irq,
+               IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0,
+               &rt5677_irq_chip, &rt5677->irq_data);
+
+       if (ret != 0) {
+               dev_err(&i2c->dev, "Failed to register IRQ chip: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+void rt5677_irq_exit(struct i2c_client *i2c)
+{
+       struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c);
+
+       if (rt5677->irq_data)
+               regmap_del_irq_chip(i2c->irq, rt5677->irq_data);
+}
+
 static int rt5677_i2c_probe(struct i2c_client *i2c,
                    const struct i2c_device_id *id)
 {
@@ -4015,6 +4146,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
        }
 
        rt5677_init_gpio(i2c);
+       rt5677_irq_init(i2c);
 
        return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677,
                                      rt5677_dai, ARRAY_SIZE(rt5677_dai));
@@ -4022,6 +4154,8 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
 
 static int rt5677_i2c_remove(struct i2c_client *i2c)
 {
+       rt5677_irq_exit(i2c);
+
        snd_soc_unregister_codec(&i2c->dev);
        rt5677_free_gpio(i2c);
 
index 20efa4a4c82c2aaa628419f8e1b89986089b67ba..d2c743c255a14ff353ba902aa94ead33e1f52528 100644 (file)
 #define RT5677_SEL_SRC_IB01                    (0x1 << 0)
 #define RT5677_SEL_SRC_IB01_SFT                        0
 
+/* Jack Detect Control 1 (0xb5) */
+#define RT5677_SEL_GPIO_JD1_MASK               (0x3 << 14)
+#define RT5677_SEL_GPIO_JD1_SFT                        14
+#define RT5677_SEL_GPIO_JD2_MASK               (0x3 << 12)
+#define RT5677_SEL_GPIO_JD2_SFT                        12
+#define RT5677_SEL_GPIO_JD3_MASK               (0x3 << 10)
+#define RT5677_SEL_GPIO_JD3_SFT                        10
+
+/* IRQ Control 1 (0xbd) */
+#define RT5677_STA_GPIO_JD1                    (0x1 << 15)
+#define RT5677_STA_GPIO_JD1_SFT                        15
+#define RT5677_EN_IRQ_GPIO_JD1                 (0x1 << 14)
+#define RT5677_EN_IRQ_GPIO_JD1_SFT             14
+#define RT5677_EN_GPIO_JD1_STICKY              (0x1 << 13)
+#define RT5677_EN_GPIO_JD1_STICKY_SFT          13
+#define RT5677_INV_GPIO_JD1                    (0x1 << 12)
+#define RT5677_INV_GPIO_JD1_SFT                        12
+#define RT5677_STA_GPIO_JD2                    (0x1 << 11)
+#define RT5677_STA_GPIO_JD2_SFT                        11
+#define RT5677_EN_IRQ_GPIO_JD2                 (0x1 << 10)
+#define RT5677_EN_IRQ_GPIO_JD2_SFT             10
+#define RT5677_EN_GPIO_JD2_STICKY              (0x1 << 9)
+#define RT5677_EN_GPIO_JD2_STICKY_SFT          9
+#define RT5677_INV_GPIO_JD2                    (0x1 << 8)
+#define RT5677_INV_GPIO_JD2_SFT                        8
+#define RT5677_STA_MICBIAS1_OVCD               (0x1 << 7)
+#define RT5677_STA_MICBIAS1_OVCD_SFT           7
+#define RT5677_EN_IRQ_MICBIAS1_OVCD            (0x1 << 6)
+#define RT5677_EN_IRQ_MICBIAS1_OVCD_SFT                6
+#define RT5677_EN_MICBIAS1_OVCD_STICKY         (0x1 << 5)
+#define RT5677_EN_MICBIAS1_OVCD_STICKY_SFT     5
+#define RT5677_INV_MICBIAS1_OVCD               (0x1 << 4)
+#define RT5677_INV_MICBIAS1_OVCD_SFT           4
+#define RT5677_STA_GPIO_JD3                    (0x1 << 3)
+#define RT5677_STA_GPIO_JD3_SFT                        3
+#define RT5677_EN_IRQ_GPIO_JD3                 (0x1 << 2)
+#define RT5677_EN_IRQ_GPIO_JD3_SFT             2
+#define RT5677_EN_GPIO_JD3_STICKY              (0x1 << 1)
+#define RT5677_EN_GPIO_JD3_STICKY_SFT          1
+#define RT5677_INV_GPIO_JD3                    (0x1 << 0)
+#define RT5677_INV_GPIO_JD3_SFT                        0
+
 /* GPIO status (0xbf) */
 #define RT5677_GPIO6_STATUS_MASK               (0x1 << 5)
 #define RT5677_GPIO6_STATUS_SFT                        5
@@ -1545,6 +1587,12 @@ enum {
        RT5677_GPIO_NUM,
 };
 
+enum {
+       RT5677_IRQ_JD1,
+       RT5677_IRQ_JD2,
+       RT5677_IRQ_JD3,
+};
+
 struct rt5677_priv {
        struct snd_soc_codec *codec;
        struct rt5677_platform_data pdata;
@@ -1565,6 +1613,7 @@ struct rt5677_priv {
        struct gpio_chip gpio_chip;
 #endif
        bool dsp_vad_en;
+       struct regmap_irq_chip_data *irq_data;
 };
 
 #endif /* __RT5677_H__ */