Merge branch 'acpi-scan'
[firefly-linux-kernel-4.4.55.git] / drivers / pinctrl / pinctrl-sirf.c
index a4f0c5e487d5eae6c2b1f29c5aebf596df2f40d2..d02498b30c6ef1f4a0eb33a6f3dd23ea46850324 100644 (file)
@@ -1246,7 +1246,23 @@ static void __iomem *sirfsoc_rsc_of_iomap(void)
        return of_iomap(np, 0);
 }
 
-static int __devinit sirfsoc_pinmux_probe(struct platform_device *pdev)
+static int sirfsoc_gpio_of_xlate(struct gpio_chip *gc,
+       const struct of_phandle_args *gpiospec,
+       u32 *flags)
+{
+       if (gpiospec->args[0] > SIRFSOC_GPIO_NO_OF_BANKS * SIRFSOC_GPIO_BANK_SIZE)
+               return -EINVAL;
+
+       if (gc != &sgpio_bank[gpiospec->args[0] / SIRFSOC_GPIO_BANK_SIZE].chip.gc)
+               return -EINVAL;
+
+       if (flags)
+               *flags = gpiospec->args[1];
+
+       return gpiospec->args[0] % SIRFSOC_GPIO_BANK_SIZE;
+}
+
+static int sirfsoc_pinmux_probe(struct platform_device *pdev)
 {
        int ret;
        struct sirfsoc_pmx *spmx;
@@ -1663,7 +1679,45 @@ const struct irq_domain_ops sirfsoc_gpio_irq_simple_ops = {
        .xlate = irq_domain_xlate_twocell,
 };
 
-static int __devinit sirfsoc_gpio_probe(struct device_node *np)
+static void sirfsoc_gpio_set_pullup(const u32 *pullups)
+{
+       int i, n;
+       const unsigned long *p = (const unsigned long *)pullups;
+
+       for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
+               n = find_first_bit(p + i, BITS_PER_LONG);
+               while (n < BITS_PER_LONG) {
+                       u32 offset = SIRFSOC_GPIO_CTRL(i, n);
+                       u32 val = readl(sgpio_bank[i].chip.regs + offset);
+                       val |= SIRFSOC_GPIO_CTL_PULL_MASK;
+                       val |= SIRFSOC_GPIO_CTL_PULL_HIGH;
+                       writel(val, sgpio_bank[i].chip.regs + offset);
+
+                       n = find_next_bit(p + i, BITS_PER_LONG, n + 1);
+               }
+       }
+}
+
+static void sirfsoc_gpio_set_pulldown(const u32 *pulldowns)
+{
+       int i, n;
+       const unsigned long *p = (const unsigned long *)pulldowns;
+
+       for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
+               n = find_first_bit(p + i, BITS_PER_LONG);
+               while (n < BITS_PER_LONG) {
+                       u32 offset = SIRFSOC_GPIO_CTRL(i, n);
+                       u32 val = readl(sgpio_bank[i].chip.regs + offset);
+                       val |= SIRFSOC_GPIO_CTL_PULL_MASK;
+                       val &= ~SIRFSOC_GPIO_CTL_PULL_HIGH;
+                       writel(val, sgpio_bank[i].chip.regs + offset);
+
+                       n = find_next_bit(p + i, BITS_PER_LONG, n + 1);
+               }
+       }
+}
+
+static int sirfsoc_gpio_probe(struct device_node *np)
 {
        int i, err = 0;
        struct sirfsoc_gpio_bank *bank;
@@ -1671,6 +1725,8 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np)
        struct platform_device *pdev;
        bool is_marco = false;
 
+       u32 pullups[SIRFSOC_GPIO_NO_OF_BANKS], pulldowns[SIRFSOC_GPIO_NO_OF_BANKS];
+
        pdev = of_find_device_by_node(np);
        if (!pdev)
                return -ENODEV;
@@ -1696,6 +1752,8 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np)
                bank->chip.gc.ngpio = SIRFSOC_GPIO_BANK_SIZE;
                bank->chip.gc.label = kstrdup(np->full_name, GFP_KERNEL);
                bank->chip.gc.of_node = np;
+               bank->chip.gc.of_xlate = sirfsoc_gpio_of_xlate;
+               bank->chip.gc.of_gpio_n_cells = 2;
                bank->chip.regs = regs;
                bank->id = i;
                bank->is_marco = is_marco;
@@ -1726,6 +1784,14 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np)
                irq_set_handler_data(bank->parent_irq, bank);
        }
 
+       if (!of_property_read_u32_array(np, "sirf,pullups", pullups,
+               SIRFSOC_GPIO_NO_OF_BANKS))
+               sirfsoc_gpio_set_pullup(pullups);
+
+       if (!of_property_read_u32_array(np, "sirf,pulldowns", pulldowns,
+               SIRFSOC_GPIO_NO_OF_BANKS))
+               sirfsoc_gpio_set_pulldown(pulldowns);
+
        return 0;
 
 out: