gpio: langwell: ensure alternate function is cleared
authorAdrian Hunter <adrian.hunter@intel.com>
Mon, 3 Oct 2011 11:36:07 +0000 (14:36 +0300)
committerGrant Likely <grant.likely@secretlab.ca>
Thu, 6 Oct 2011 10:14:52 +0000 (04:14 -0600)
Alternate function must be zero for the pin to act as
a GPIO.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
drivers/gpio/gpio-langwell.c

index d2eb57c..00692e8 100644 (file)
@@ -59,6 +59,7 @@ enum GPIO_REG {
        GRER,           /* rising edge detect */
        GFER,           /* falling edge detect */
        GEDR,           /* edge detect result */
+       GAFR,           /* alt function */
 };
 
 struct lnw_gpio {
@@ -81,6 +82,31 @@ static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
        return ptr;
 }
 
+static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset,
+                                  enum GPIO_REG reg_type)
+{
+       struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
+       unsigned nreg = chip->ngpio / 32;
+       u8 reg = offset / 16;
+       void __iomem *ptr;
+
+       ptr = (void __iomem *)(lnw->reg_base + reg_type * nreg * 4 + reg * 4);
+       return ptr;
+}
+
+static int lnw_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       void __iomem *gafr = gpio_reg_2bit(chip, offset, GAFR);
+       u32 value = readl(gafr);
+       int shift = (offset % 16) << 1, af = (value >> shift) & 3;
+
+       if (af) {
+               value &= ~(3 << shift);
+               writel(value, gafr);
+       }
+       return 0;
+}
+
 static int lnw_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
        void __iomem *gplr = gpio_reg(chip, offset, GPLR);
@@ -321,6 +347,7 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
        lnw->reg_base = base;
        lnw->irq_base = irq_base;
        lnw->chip.label = dev_name(&pdev->dev);
+       lnw->chip.request = lnw_gpio_request;
        lnw->chip.direction_input = lnw_gpio_direction_input;
        lnw->chip.direction_output = lnw_gpio_direction_output;
        lnw->chip.get = lnw_gpio_get;