Staging: phison: depends on ATA_BMDMA
[safe/jmp/linux-2.6] / drivers / gpio / wm831x-gpio.c
index f5e4934..1fa449a 100644 (file)
@@ -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,6 +23,7 @@
 #include <linux/mfd/wm831x/core.h>
 #include <linux/mfd/wm831x/pdata.h>
 #include <linux/mfd/wm831x/gpio.h>
+#include <linux/mfd/wm831x/irq.h>
 
 struct wm831x_gpio {
        struct wm831x *wm831x;
@@ -37,10 +39,14 @@ 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;
 
        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)
@@ -59,23 +65,47 @@ static int wm831x_gpio_get(struct gpio_chip *chip, unsigned offset)
                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,
                                     unsigned offset, int value)
 {
        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;
+
+       ret = wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + offset,
+                             WM831X_GPN_DIR | WM831X_GPN_TRI |
+                             WM831X_GPN_FN_MASK, val);
+       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;
 }
 
 #ifdef CONFIG_DEBUG_FS
@@ -83,7 +113,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;
@@ -150,15 +180,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);
        }
 }
@@ -173,6 +207,7 @@ static struct gpio_chip template_chip = {
        .get                    = wm831x_gpio_get,
        .direction_output       = wm831x_gpio_direction_out,
        .set                    = wm831x_gpio_set,
+       .to_irq                 = wm831x_gpio_to_irq,
        .dbg_show               = wm831x_gpio_dbg_show,
        .can_sleep              = 1,
 };