rk29_phone: fix heatset main mic Call Features
[firefly-linux-kernel-4.4.55.git] / drivers / gpio / wm831x-gpio.c
old mode 100644 (file)
new mode 100755 (executable)
index f9c09a5..382ae87
@@ -13,6 +13,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/gpio.h>
 #include <linux/mfd/core.h>
@@ -22,8 +23,7 @@
 #include <linux/mfd/wm831x/core.h>
 #include <linux/mfd/wm831x/pdata.h>
 #include <linux/mfd/wm831x/gpio.h>
-
-#define WM831X_GPIO_MAX 16
+#include <linux/mfd/wm831x/irq.h>
 
 struct wm831x_gpio {
        struct wm831x *wm831x;
@@ -35,14 +35,34 @@ static inline struct wm831x_gpio *to_wm831x_gpio(struct gpio_chip *chip)
        return container_of(chip, struct wm831x_gpio, gpio_chip);
 }
 
+static int wm831x_gpio_pull_up_down(struct gpio_chip *chip, unsigned offset, unsigned value)
+{
+       struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
+       struct wm831x *wm831x = wm831x_gpio->wm831x;
+
+       if(value == GPIOPullUp)
+               value = WM831X_GPIO_PULL_UP;
+       else if(value == GPIOPullDown)
+               value = WM831X_GPIO_PULL_DOWN;
+       else if(value == GPIONormal)
+               value = WM831X_GPIO_PULL_NONE;
+       //printk("wm831x_gpio_pull_up_down=%x,%x\n",WM831X_GPIO1_CONTROL + offset,value);
+       return wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + offset, 
+               WM831X_GPN_PULL_MASK, value);
+}
+
 static int wm831x_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
 {
        struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
        struct wm831x *wm831x = wm831x_gpio->wm831x;
+       int val = WM831X_GPN_DIR;
 
+       if (wm831x->has_gpio_ena)
+               val |= WM831X_GPN_TRI;
+       //printk("wm831x_gpio_direction_in=%x,%x\n",WM831X_GPIO1_CONTROL + offset,val);
        return wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + offset,
-                              WM831X_GPN_DIR | WM831X_GPN_TRI,
-                              WM831X_GPN_DIR);
+                              WM831X_GPN_DIR | WM831X_GPN_TRI |
+                              WM831X_GPN_FN_MASK, val);
 }
 
 static int wm831x_gpio_get(struct gpio_chip *chip, unsigned offset)
@@ -50,15 +70,28 @@ static int wm831x_gpio_get(struct gpio_chip *chip, unsigned offset)
        struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
        struct wm831x *wm831x = wm831x_gpio->wm831x;
        int ret;
-
+       int gpn_pol;
+       
+       ret = wm831x_reg_read(wm831x, WM831X_GPIO1_CONTROL + offset);
+       if (ret < 0)
+               return ret;
+       gpn_pol = (ret & WM831X_GPN_POL_MASK) >> WM831X_GPN_POL_SHIFT;
+       
        ret = wm831x_reg_read(wm831x, WM831X_GPIO_LEVEL);
+       //printk("wm831x_gpio_get=%x,%d,%d\n",ret,offset,gpn_pol);
        if (ret < 0)
                return ret;
+       
+       return !((ret>>offset)^gpn_pol);
+}
 
-       if (ret & 1 << offset)
-               return 1;
-       else
-               return 0;
+static void wm831x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
+       struct wm831x *wm831x = wm831x_gpio->wm831x;
+
+       wm831x_set_bits(wm831x, WM831X_GPIO_LEVEL, 1 << offset,
+                       value << offset);
 }
 
 static int wm831x_gpio_direction_out(struct gpio_chip *chip,
@@ -66,18 +99,64 @@ static int wm831x_gpio_direction_out(struct gpio_chip *chip,
 {
        struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
        struct wm831x *wm831x = wm831x_gpio->wm831x;
+       int val = 0;
+       int ret;
 
-       return wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + offset,
-                              WM831X_GPN_DIR | WM831X_GPN_TRI, 0);
+       if (wm831x->has_gpio_ena)
+               val |= WM831X_GPN_TRI;
+       //printk("wm831x_gpio_direction_out=%x,%x\n",WM831X_GPIO1_CONTROL + offset,val);
+       ret = wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + offset,
+                             WM831X_GPN_DIR | WM831X_GPN_TRI |
+                             WM831X_GPN_FN_MASK | WM831X_GPN_POL_MASK, val|WM831X_GPN_POL);
+       if (ret < 0)
+               return ret;
+
+       /* Can only set GPIO state once it's in output mode */
+       wm831x_gpio_set(chip, offset, value);
+
+       return 0;
 }
 
-static void wm831x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+static int wm831x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
        struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
        struct wm831x *wm831x = wm831x_gpio->wm831x;
 
-       wm831x_set_bits(wm831x, WM831X_GPIO_LEVEL, 1 << offset,
-                       value << offset);
+       if (!wm831x->irq_base)
+               return -EINVAL;
+
+       return wm831x->irq_base + WM831X_IRQ_GPIO_1 + offset;
+}
+
+static int wm831x_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
+                                   unsigned debounce)
+{
+       struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
+       struct wm831x *wm831x = wm831x_gpio->wm831x;
+       int reg = WM831X_GPIO1_CONTROL + offset;
+       int ret, fn;
+
+       ret = wm831x_reg_read(wm831x, reg);
+       if (ret < 0)
+               return ret;
+
+       switch (ret & WM831X_GPN_FN_MASK) {
+       case 0:
+       case 1:
+               break;
+       default:
+               /* Not in GPIO mode */
+               return -EBUSY;
+       }
+
+       if (debounce >= 32 && debounce <= 64)
+               fn = 0;
+       else if (debounce >= 4000 && debounce <= 8000)
+               fn = 1;
+       else
+               return -EINVAL;
+       //printk("wm831x_gpio_set_debounce=%x,%x\n",WM831X_GPIO1_CONTROL + offset,fn);
+       return wm831x_set_bits(wm831x, reg, WM831X_GPN_FN_MASK, fn);
 }
 
 #ifdef CONFIG_DEBUG_FS
@@ -85,7 +164,7 @@ static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
 {
        struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
        struct wm831x *wm831x = wm831x_gpio->wm831x;
-       int i;
+       int i, tristated;
 
        for (i = 0; i < chip->ngpio; i++) {
                int gpio = i + chip->base;
@@ -152,15 +231,19 @@ static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
                        break;
                }
 
+               tristated = reg & WM831X_GPN_TRI;
+               if (wm831x->has_gpio_ena)
+                       tristated = !tristated;
+
                seq_printf(s, " %s %s %s %s%s\n"
                           "                                  %s%s (0x%4x)\n",
                           reg & WM831X_GPN_DIR ? "in" : "out",
                           wm831x_gpio_get(chip, i) ? "high" : "low",
                           pull,
                           powerdomain,
-                          reg & WM831X_GPN_POL ? " inverted" : "",
+                          reg & WM831X_GPN_POL ? "" : " inverted",
                           reg & WM831X_GPN_OD ? "open-drain" : "CMOS",
-                          reg & WM831X_GPN_TRI ? " tristated" : "",
+                          tristated ? " tristated" : "",
                           reg);
        }
 }
@@ -175,6 +258,9 @@ static struct gpio_chip template_chip = {
        .get                    = wm831x_gpio_get,
        .direction_output       = wm831x_gpio_direction_out,
        .set                    = wm831x_gpio_set,
+       .pull_updown    = wm831x_gpio_pull_up_down,
+       .to_irq                 = wm831x_gpio_to_irq,
+       .set_debounce           = wm831x_gpio_set_debounce,
        .dbg_show               = wm831x_gpio_dbg_show,
        .can_sleep              = 1,
 };
@@ -185,14 +271,14 @@ static int __devinit wm831x_gpio_probe(struct platform_device *pdev)
        struct wm831x_pdata *pdata = wm831x->dev->platform_data;
        struct wm831x_gpio *wm831x_gpio;
        int ret;
-
+       printk("%s\n",__FUNCTION__);
        wm831x_gpio = kzalloc(sizeof(*wm831x_gpio), GFP_KERNEL);
        if (wm831x_gpio == NULL)
                return -ENOMEM;
-
+       
        wm831x_gpio->wm831x = wm831x;
        wm831x_gpio->gpio_chip = template_chip;
-       wm831x_gpio->gpio_chip.ngpio = WM831X_GPIO_MAX;
+       wm831x_gpio->gpio_chip.ngpio = wm831x->num_gpio;
        wm831x_gpio->gpio_chip.dev = &pdev->dev;
        if (pdata && pdata->gpio_base)
                wm831x_gpio->gpio_chip.base = pdata->gpio_base;