OpenWrt – Rev 4

Subversion Repositories:
Rev:
From ab2f33e35e35905a76204138143875251f3e1088 Mon Sep 17 00:00:00 2001
From: Jonas Gorski <jonas.gorski@gmail.com>
Date: Fri, 24 Jun 2016 22:07:42 +0200
Subject: [PATCH 01/13] pinctrl: add bcm63xx base code

Setup directory and add a helper for bcm63xx pinctrl support.

Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
---
 drivers/pinctrl/Kconfig                   |   1 +
 drivers/pinctrl/Makefile                  |   1 +
 drivers/pinctrl/bcm63xx/Kconfig           |   3 +
 drivers/pinctrl/bcm63xx/Makefile          |   1 +
 drivers/pinctrl/bcm63xx/pinctrl-bcm63xx.c | 142 ++++++++++++++++++++++++++++++
 drivers/pinctrl/bcm63xx/pinctrl-bcm63xx.h |  14 +++
 7 files changed, 163 insertions(+)
 create mode 100644 drivers/pinctrl/bcm63xx/Kconfig
 create mode 100644 drivers/pinctrl/bcm63xx/Makefile
 create mode 100644 drivers/pinctrl/bcm63xx/pinctrl-bcm63xx.c
 create mode 100644 drivers/pinctrl/bcm63xx/pinctrl-bcm63xx.h

--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -258,6 +258,7 @@ config PINCTRL_ZYNQ
 
 source "drivers/pinctrl/aspeed/Kconfig"
 source "drivers/pinctrl/bcm/Kconfig"
+source "drivers/pinctrl/bcm63xx/Kconfig"
 source "drivers/pinctrl/berlin/Kconfig"
 source "drivers/pinctrl/freescale/Kconfig"
 source "drivers/pinctrl/intel/Kconfig"
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_PINCTRL_ZYNQ)    += pinctrl-zy
 
 obj-$(CONFIG_ARCH_ASPEED)      += aspeed/
 obj-y                          += bcm/
+obj-y                          += bcm63xx/
 obj-$(CONFIG_PINCTRL_BERLIN)   += berlin/
 obj-y                          += freescale/
 obj-$(CONFIG_X86)              += intel/
--- /dev/null
+++ b/drivers/pinctrl/bcm63xx/Kconfig
@@ -0,0 +1,3 @@
+config PINCTRL_BCM63XX
+       bool
+       select GPIO_GENERIC
--- /dev/null
+++ b/drivers/pinctrl/bcm63xx/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_PINCTRL_BCM63XX)  += pinctrl-bcm63xx.o
--- /dev/null
+++ b/drivers/pinctrl/bcm63xx/pinctrl-bcm63xx.c
@@ -0,0 +1,155 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2016 Jonas Gorski <jonas.gorski@gmail.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/gpio/driver.h>
+#include <linux/of_irq.h>
+
+#include "pinctrl-bcm63xx.h"
+#include "../core.h"
+
+#define BANK_SIZE      sizeof(u32)
+#define PINS_PER_BANK  (BANK_SIZE * BITS_PER_BYTE)
+
+#ifdef CONFIG_OF
+static int bcm63xx_gpio_of_xlate(struct gpio_chip *gc,
+                                const struct of_phandle_args *gpiospec,
+                                u32 *flags)
+{
+       struct gpio_chip *base = gpiochip_get_data(gc);
+       int pin = gpiospec->args[0];
+
+       if (gc != &base[pin / PINS_PER_BANK])
+               return -EINVAL;
+
+       pin = pin % PINS_PER_BANK;
+
+       if (pin >= gc->ngpio)
+               return -EINVAL;
+
+       if (flags)
+               *flags = gpiospec->args[1];
+
+       return pin;
+}
+#endif
+
+static int bcm63xx_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
+{
+       struct gpio_chip *base = gpiochip_get_data(chip);
+       char irq_name[7]; /* "gpioXX" */
+
+       /* FIXME: this is ugly */
+       sprintf(irq_name, "gpio%d", gpio + PINS_PER_BANK * (chip - base));
+       return of_irq_get_byname(chip->of_node, irq_name);
+}
+
+static int bcm63xx_setup_gpio(struct device *dev, struct gpio_chip *gc,
+                             void __iomem *dirout, void __iomem *data,
+                             size_t sz, int ngpio)
+
+{
+       int banks, chips, i, ret = -EINVAL;
+
+       chips = DIV_ROUND_UP(ngpio, PINS_PER_BANK);
+       banks = sz / BANK_SIZE;
+
+       for (i = 0; i < chips; i++) {
+               int offset, pins;
+               int reg_offset;
+               char *label;
+
+               label = devm_kasprintf(dev, GFP_KERNEL, "bcm63xx-gpio.%i", i);
+               if (!label)
+                       return -ENOMEM;
+
+               offset = i * PINS_PER_BANK;
+               pins = min_t(int, ngpio - offset, PINS_PER_BANK);
+
+               /* the registers are treated like a huge big endian register */
+               reg_offset = (banks - i - 1) * BANK_SIZE;
+
+               ret = bgpio_init(&gc[i], dev, BANK_SIZE, data + reg_offset,
+                                NULL, NULL, dirout + reg_offset, NULL,
+                                BGPIOF_BIG_ENDIAN_BYTE_ORDER);
+               if (ret)
+                       return ret;
+
+               gc[i].request = gpiochip_generic_request;
+               gc[i].free = gpiochip_generic_free;
+
+               if (of_get_property(dev->of_node, "interrupt-names", NULL))
+                       gc[i].to_irq = bcm63xx_gpio_to_irq;
+
+#ifdef CONFIG_OF
+               gc[i].of_gpio_n_cells = 2;
+               gc[i].of_xlate = bcm63xx_gpio_of_xlate;
+#endif
+
+               gc[i].label = label;
+               gc[i].ngpio = pins;
+
+               devm_gpiochip_add_data(dev, &gc[i], gc);
+       }
+
+       return 0;
+}
+
+static void bcm63xx_setup_pinranges(struct gpio_chip *gc, const char *name,
+                                   int ngpio)
+{
+       int i, chips = DIV_ROUND_UP(ngpio, PINS_PER_BANK);
+
+       for (i = 0; i < chips; i++) {
+               int offset, pins;
+
+               offset = i * PINS_PER_BANK;
+               pins = min_t(int, ngpio - offset, PINS_PER_BANK);
+
+               gpiochip_add_pin_range(&gc[i], name, 0, offset, pins);
+       }
+}
+
+struct pinctrl_dev *bcm63xx_pinctrl_register(struct platform_device *pdev,
+                                            struct pinctrl_desc *desc,
+                                            void *priv, struct gpio_chip *gc,
+                                            int ngpio)
+{
+       struct pinctrl_dev *pctldev;
+       struct resource *res;
+       void __iomem *dirout, *data;
+       size_t sz;
+       int ret;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dirout");
+       dirout = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(dirout))
+               return ERR_CAST(dirout);
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
+       data = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(data))
+               return ERR_CAST(data);
+
+       sz = resource_size(res);
+
+       ret = bcm63xx_setup_gpio(&pdev->dev, gc, dirout, data, sz, ngpio);
+       if (ret)
+               return ERR_PTR(ret);
+
+       pctldev = devm_pinctrl_register(&pdev->dev, desc, priv);
+       if (IS_ERR(pctldev))
+               return pctldev;
+
+       bcm63xx_setup_pinranges(gc, pinctrl_dev_get_devname(pctldev), ngpio);
+
+       dev_info(&pdev->dev, "registered at mmio %p\n", dirout);
+
+       return pctldev;
+}
--- /dev/null
+++ b/drivers/pinctrl/bcm63xx/pinctrl-bcm63xx.h
@@ -0,0 +1,14 @@
+#ifndef __PINCTRL_BCM63XX
+#define __PINCTRL_BCM63XX
+
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/platform_device.h>
+
+struct pinctrl_dev *bcm63xx_pinctrl_register(struct platform_device *pdev,
+                                            struct pinctrl_desc *desc,
+                                            void *priv, struct gpio_chip *gc,
+                                            int ngpio);
+
+#endif

Generated by GNU Enscript 1.6.5.90.