add pinctrl driver support
authorluowei <lw@rock-chips.com>
Tue, 3 Dec 2013 03:48:30 +0000 (11:48 +0800)
committerluowei <lw@rock-chips.com>
Tue, 3 Dec 2013 03:48:30 +0000 (11:48 +0800)
arch/arm/boot/dts/rk3188.dtsi [changed mode: 0644->0755]
arch/arm/mach-rockchip/rk3188.c
drivers/pinctrl/Kconfig
drivers/pinctrl/Makefile
drivers/pinctrl/pinctrl-rockchip.c [new file with mode: 0755]
include/dt-bindings/pinctrl/rockchip.h [new file with mode: 0755]

old mode 100644 (file)
new mode 100755 (executable)
index 26b05e0..b662681
@@ -1,4 +1,6 @@
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/rockchip.h>
 
 #include "skeleton.dtsi"
 
                interrupts = <GIC_SPI 60 IRQ_TYPE_LEVEL_HIGH>;
        };
 
+       pinctrl@20008000 {
+                       compatible = "rockchip,rk3188-pinctrl";
+                       reg = <0x20008000 0xa0>,
+                             <0x20008164 0x1a0>;
+                       reg-names = "base", "pull";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       gpio0: gpio0@0x2000a000 {
+                               compatible = "rockchip,rk3188-gpio-bank0";
+                               reg = <0x2000a000 0x100>,
+                                     <0x20004064 0x8>;
+                               interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
+                               /*clocks = <&clk_gates8 9>;*/
+
+                               gpio-controller;
+                               #gpio-cells = <2>;
+
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                       };
+
+                       gpio1: gpio1@0x2003c000 {
+                               compatible = "rockchip,gpio-bank";
+                               reg = <0x2003c000 0x100>;
+                               interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
+                               /*clocks = <&clk_gates8 10>;*/
+
+                               gpio-controller;
+                               #gpio-cells = <2>;
+
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                       };
+
+                       gpio2: gpio2@2003e000 {
+                               compatible = "rockchip,gpio-bank";
+                               reg = <0x2003e000 0x100>;
+                               interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
+                               /*clocks = <&clk_gates8 11>;*/
+
+                               gpio-controller;
+                               #gpio-cells = <2>;
+
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                       };
+
+                       gpio3: gpio3@20080000 {
+                               compatible = "rockchip,gpio-bank";
+                               reg = <0x20080000 0x100>;
+                               interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
+                               /*clocks = <&clk_gates8 12>;*/
+
+                               gpio-controller;
+                               #gpio-cells = <2>;
+
+                               interrupt-controller;
+                               #interrupt-cells = <2>;
+                       };
+
+                       pcfg_pull_up: pcfg_pull_up {
+                               bias-pull-up;
+                       };
+
+                       pcfg_pull_down: pcfg_pull_down {
+                               bias-pull-down;
+                       };
+
+                       pcfg_pull_none: pcfg_pull_none {
+                               bias-disable;
+                       };
+
+                       uart0 {
+                               uart0_xfer: uart0-xfer {
+                                       rockchip,pins = <RK_GPIO1 0 RK_FUNC_1 &pcfg_pull_none>,
+                                                       <RK_GPIO1 1 RK_FUNC_1 &pcfg_pull_none>;
+                               };
+
+                               uart0_cts: uart0-cts {
+                                       rockchip,pins = <RK_GPIO1 2 RK_FUNC_1 &pcfg_pull_none>;
+                               };
+
+                               uart0_rts: uart0-rts {
+                                       rockchip,pins = <RK_GPIO1 3 RK_FUNC_1 &pcfg_pull_none>;
+                               };
+                       };
+
+                       uart1 {
+                               uart1_xfer: uart1-xfer {
+                                       rockchip,pins = <RK_GPIO1 4 RK_FUNC_1 &pcfg_pull_none>,
+                                                       <RK_GPIO1 5 RK_FUNC_1 &pcfg_pull_none>;
+                               };
+
+                               uart1_cts: uart1-cts {
+                                       rockchip,pins = <RK_GPIO1 6 RK_FUNC_1 &pcfg_pull_none>;
+                               };
+
+                               uart1_rts: uart1-rts {
+                                       rockchip,pins = <RK_GPIO1 7 RK_FUNC_1 &pcfg_pull_none>;
+                               };
+                       };
+
+                       uart2 {
+                               uart2_xfer: uart2-xfer {
+                                       rockchip,pins = <RK_GPIO1 8 RK_FUNC_1 &pcfg_pull_none>,
+                                                       <RK_GPIO1 9 RK_FUNC_1 &pcfg_pull_none>;
+                               };
+                               /* no rts / cts for uart2 */
+                       };
+
+                       uart3 {
+                               uart3_xfer: uart3-xfer {
+                                       rockchip,pins = <RK_GPIO1 10 RK_FUNC_1 &pcfg_pull_none>,
+                                                       <RK_GPIO1 11 RK_FUNC_1 &pcfg_pull_none>;
+                               };
+
+                               uart3_cts: uart3-cts {
+                                       rockchip,pins = <RK_GPIO1 12 RK_FUNC_1 &pcfg_pull_none>;
+                               };
+
+                               uart3_rts: uart3-rts {
+                                       rockchip,pins = <RK_GPIO1 13 RK_FUNC_1 &pcfg_pull_none>;
+                               };
+                       };
+
+                       sd0 {
+                               sd0_clk: sd0-clk {
+                                       rockchip,pins = <RK_GPIO3 2 RK_FUNC_1 &pcfg_pull_none>;
+                               };
+
+                               sd0_cmd: sd0-cmd {
+                                       rockchip,pins = <RK_GPIO3 3 RK_FUNC_1 &pcfg_pull_none>;
+                               };
+
+                               sd0_cd: sd0-cd {
+                                       rockchip,pins = <RK_GPIO3 8 RK_FUNC_1 &pcfg_pull_none>;
+                               };
+
+                               sd0_wp: sd0-wp {
+                                       rockchip,pins = <RK_GPIO3 9 RK_FUNC_1 &pcfg_pull_none>;
+                               };
+
+                               sd0_pwr: sd0-pwr {
+                                       rockchip,pins = <RK_GPIO3 1 RK_FUNC_1 &pcfg_pull_none>;
+                               };
+
+                               sd0_bus1: sd0-bus-width1 {
+                                       rockchip,pins = <RK_GPIO3 4 RK_FUNC_1 &pcfg_pull_none>;
+                               };
+
+                               sd0_bus4: sd0-bus-width4 {
+                                       rockchip,pins = <RK_GPIO3 4 RK_FUNC_1 &pcfg_pull_none>,
+                                                       <RK_GPIO3 5 RK_FUNC_1 &pcfg_pull_none>,
+                                                       <RK_GPIO3 6 RK_FUNC_1 &pcfg_pull_none>,
+                                                       <RK_GPIO3 7 RK_FUNC_1 &pcfg_pull_none>;
+                               };
+                       };
+
+                       sd1 {
+                               sd1_clk: sd1-clk {
+                                       rockchip,pins = <RK_GPIO3 21 RK_FUNC_1 &pcfg_pull_none>;
+                               };
+
+                               sd1_cmd: sd1-cmd {
+                                       rockchip,pins = <RK_GPIO3 16 RK_FUNC_1 &pcfg_pull_none>;
+                               };
+
+                               sd1_cd: sd1-cd {
+                                       rockchip,pins = <RK_GPIO3 22 RK_FUNC_1 &pcfg_pull_none>;
+                               };
+
+                               sd1_wp: sd1-wp {
+                                       rockchip,pins = <RK_GPIO3 23 RK_FUNC_1 &pcfg_pull_none>;
+                               };
+
+                               sd1_bus1: sd1-bus-width1 {
+                                       rockchip,pins = <RK_GPIO3 17 RK_FUNC_1 &pcfg_pull_none>;
+                               };
+
+                               sd1_bus4: sd1-bus-width4 {
+                                       rockchip,pins = <RK_GPIO3 17 RK_FUNC_1 &pcfg_pull_none>,
+                                                       <RK_GPIO3 18 RK_FUNC_1 &pcfg_pull_none>,
+                                                       <RK_GPIO3 19 RK_FUNC_1 &pcfg_pull_none>,
+                                                       <RK_GPIO3 20 RK_FUNC_1 &pcfg_pull_none>;
+                               };
+                       };
+               };
+
+
        uart0: serial@10124000 {
                compatible = "rockchip,serial";
                reg = <0x10124000 0x100>;
index 16ebe854d34909d8e3fd40c2f479801e276e58d0..9d8dc8906385bc53f1888f2f92c783a3561dfadf 100644 (file)
@@ -49,6 +49,7 @@ static const char * const rk3188_dt_compat[] = {
 };
 
 DT_MACHINE_START(RK3188_DT, "Rockchip RK3188 (Flattened Device Tree)")
+       .nr_irqs        = 32*10,
        .smp            = smp_ops(rockchip_smp_ops),
        .map_io         = rk3188_dt_map_io,
        .init_machine   = rk3188_dt_init,
index 8f669243814935c3df4544e8d61127997cde2332..a808bf56e271c2c2014035fe14313c423450fb24 100644 (file)
@@ -150,6 +150,12 @@ config PINCTRL_DB8540
        bool "DB8540 pin controller driver"
        depends on PINCTRL_NOMADIK && ARCH_U8500
 
+config PINCTRL_ROCKCHIP
+       bool
+       select PINMUX
+       select GENERIC_PINCONF
+       select GENERIC_IRQ_CHIP
+
 config PINCTRL_SINGLE
        tristate "One-register-per-pin type device tree based pinctrl driver"
        depends on OF
index 9bdaeb8785ce5336d9eb174c73e989dac8418022..2cee8407e7bc9a2b0379fcdeac97513d85008574 100644 (file)
@@ -30,6 +30,7 @@ obj-$(CONFIG_PINCTRL_NOMADIK) += pinctrl-nomadik.o
 obj-$(CONFIG_PINCTRL_STN8815)  += pinctrl-nomadik-stn8815.o
 obj-$(CONFIG_PINCTRL_DB8500)   += pinctrl-nomadik-db8500.o
 obj-$(CONFIG_PINCTRL_DB8540)   += pinctrl-nomadik-db8540.o
+obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o
 obj-$(CONFIG_PINCTRL_SINGLE)   += pinctrl-single.o
 obj-$(CONFIG_PINCTRL_SIRF)     += pinctrl-sirf.o
 obj-$(CONFIG_PINCTRL_SUNXI)    += pinctrl-sunxi.o
diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
new file mode 100755 (executable)
index 0000000..17cdc62
--- /dev/null
@@ -0,0 +1,1894 @@
+/*
+ * Pinctrl driver for Rockchip SoCs
+ *
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * With some ideas taken from pinctrl-samsung:
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ * Copyright (c) 2012 Linaro Ltd
+ *             http://www.linaro.org
+ *
+ * and pinctrl-at91:
+ * Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/clk.h>
+#include <dt-bindings/pinctrl/rockchip.h>
+
+#include "core.h"
+#include "pinconf.h"
+
+
+#if 1
+#define DBG_PINCTRL(x...)  if(atomic_read(&bank->drvdata->debug_flag) == 1) printk(x)
+#else
+#define DBG_PINCTRL(x...)
+#endif
+
+
+/* GPIO control registers */
+#define GPIO_SWPORT_DR         0x00
+#define GPIO_SWPORT_DDR                0x04
+#define GPIO_INTEN             0x30
+#define GPIO_INTMASK           0x34
+#define GPIO_INTTYPE_LEVEL     0x38
+#define GPIO_INT_POLARITY      0x3c
+#define GPIO_INT_STATUS                0x40
+#define GPIO_INT_RAWSTATUS     0x44
+#define GPIO_DEBOUNCE          0x48
+#define GPIO_PORTS_EOI         0x4c
+#define GPIO_EXT_PORT          0x50
+#define GPIO_LS_SYNC           0x60
+
+enum rockchip_pinctrl_type {
+       RK2928,
+       RK3066B,
+       RK3188,
+};
+
+enum rockchip_pin_bank_type {
+       COMMON_BANK,
+       RK3188_BANK0,
+};
+
+/**
+ * @reg_base: register base of the gpio bank
+ * @reg_pull: optional separate register for additional pull settings
+ * @clk: clock of the gpio bank
+ * @irq: interrupt of the gpio bank
+ * @pin_base: first pin number
+ * @nr_pins: number of pins in this bank
+ * @name: name of the bank
+ * @bank_num: number of the bank, to account for holes
+ * @valid: are all necessary informations present
+ * @of_node: dt node of this bank
+ * @drvdata: common pinctrl basedata
+ * @domain: irqdomain of the gpio bank
+ * @gpio_chip: gpiolib chip
+ * @grange: gpio range
+ * @slock: spinlock for the gpio bank
+ */
+struct rockchip_pin_bank {
+       void __iomem                    *reg_base;
+       void __iomem                    *reg_pull;
+       struct clk                      *clk;
+       int                             irq;
+       u32                             pin_base;
+       u8                              nr_pins;
+       char                            *name;
+       u8                              bank_num;
+       enum rockchip_pin_bank_type     bank_type;
+       bool                            valid;
+       struct device_node              *of_node;
+       struct rockchip_pinctrl         *drvdata;
+       struct irq_domain               *domain;
+       struct gpio_chip                gpio_chip;
+       struct pinctrl_gpio_range       grange;
+       spinlock_t                      slock;
+       u32                             toggle_edge_mode;
+       u32                             suspend_wakeup;
+       u32                             saved_wakeup;   
+};
+
+#define PIN_BANK(id, pins, label)                      \
+       {                                               \
+               .bank_num       = id,                   \
+               .nr_pins        = pins,                 \
+               .name           = label,                \
+       }
+
+/**
+ */
+struct rockchip_pin_ctrl {
+       struct rockchip_pin_bank        *pin_banks;
+       u32                             nr_banks;
+       u32                             nr_pins;
+       char                            *label;
+       enum rockchip_pinctrl_type      type;
+       int                             mux_offset;
+       void    (*pull_calc_reg)(struct rockchip_pin_bank *bank, int pin_num,
+                                void __iomem **reg, u8 *bit);
+};
+
+struct rockchip_pin_config {
+       unsigned int            func;
+       unsigned long           *configs;
+       unsigned int            nconfigs;
+};
+
+/**
+ * struct rockchip_pin_group: represent group of pins of a pinmux function.
+ * @name: name of the pin group, used to lookup the group.
+ * @pins: the pins included in this group.
+ * @npins: number of pins included in this group.
+ * @func: the mux function number to be programmed when selected.
+ * @configs: the config values to be set for each pin
+ * @nconfigs: number of configs for each pin
+ */
+struct rockchip_pin_group {
+       const char                      *name;
+       unsigned int                    npins;
+       unsigned int                    *pins;
+       struct rockchip_pin_config      *data;
+};
+
+/**
+ * struct rockchip_pmx_func: represent a pin function.
+ * @name: name of the pin function, used to lookup the function.
+ * @groups: one or more names of pin groups that provide this function.
+ * @num_groups: number of groups included in @groups.
+ */
+struct rockchip_pmx_func {
+       const char              *name;
+       const char              **groups;
+       u8                      ngroups;
+};
+
+struct rockchip_pinctrl {
+       void __iomem                    *reg_base;
+       void __iomem                    *reg_pull;
+       struct device                   *dev;
+       struct rockchip_pin_ctrl        *ctrl;
+       struct pinctrl_desc             pctl;
+       struct pinctrl_dev              *pctl_dev;
+       struct rockchip_pin_group       *groups;
+       unsigned int                    ngroups;
+       struct rockchip_pmx_func        *functions;
+       unsigned int                    nfunctions;
+       
+       atomic_t                        debug_flag;     
+};
+
+static inline struct rockchip_pin_bank *gc_to_pin_bank(struct gpio_chip *gc)
+{
+       return container_of(gc, struct rockchip_pin_bank, gpio_chip);
+}
+
+static const inline struct rockchip_pin_group *pinctrl_name_to_group(
+                                       const struct rockchip_pinctrl *info,
+                                       const char *name)
+{
+       int i;
+
+       for (i = 0; i < info->ngroups; i++) {
+               if (!strcmp(info->groups[i].name, name))
+                       return &info->groups[i];
+       }
+
+       return NULL;
+}
+
+/*
+ * given a pin number that is local to a pin controller, find out the pin bank
+ * and the register base of the pin bank.
+ */
+static struct rockchip_pin_bank *pin_to_bank(struct rockchip_pinctrl *info,
+                                                               unsigned pin)
+{
+       struct rockchip_pin_bank *b = info->ctrl->pin_banks;
+
+       while (pin >= (b->pin_base + b->nr_pins))
+               b++;
+
+       return b;
+}
+
+static struct rockchip_pin_bank *bank_num_to_bank(
+                                       struct rockchip_pinctrl *info,
+                                       unsigned num)
+{
+       struct rockchip_pin_bank *b = info->ctrl->pin_banks;
+       int i;
+
+       for (i = 0; i < info->ctrl->nr_banks; i++, b++) {
+               if (b->bank_num == num)
+                       return b;
+       }
+
+       return ERR_PTR(-EINVAL);
+}
+
+/*
+ * Pinctrl_ops handling
+ */
+
+static int rockchip_get_groups_count(struct pinctrl_dev *pctldev)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+       return info->ngroups;
+}
+
+static const char *rockchip_get_group_name(struct pinctrl_dev *pctldev,
+                                                       unsigned selector)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+       return info->groups[selector].name;
+}
+
+static int rockchip_get_group_pins(struct pinctrl_dev *pctldev,
+                                     unsigned selector, const unsigned **pins,
+                                     unsigned *npins)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+       if (selector >= info->ngroups)
+               return -EINVAL;
+
+       *pins = info->groups[selector].pins;
+       *npins = info->groups[selector].npins;
+
+       return 0;
+}
+
+static int rockchip_dt_node_to_map(struct pinctrl_dev *pctldev,
+                                struct device_node *np,
+                                struct pinctrl_map **map, unsigned *num_maps)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       const struct rockchip_pin_group *grp;
+       struct pinctrl_map *new_map;
+       struct device_node *parent;
+       int map_num = 1;
+       int i;
+
+       /*
+        * first find the group of this node and check if we need to create
+        * config maps for pins
+        */
+       grp = pinctrl_name_to_group(info, np->name);
+       if (!grp) {
+               dev_err(info->dev, "unable to find group for node %s\n",
+                       np->name);
+               return -EINVAL;
+       }
+
+       map_num += grp->npins;
+       new_map = devm_kzalloc(pctldev->dev, sizeof(*new_map) * map_num,
+                                                               GFP_KERNEL);
+       if (!new_map)
+               return -ENOMEM;
+
+       *map = new_map;
+       *num_maps = map_num;
+
+       /* create mux map */
+       parent = of_get_parent(np);
+       if (!parent) {
+               devm_kfree(pctldev->dev, new_map);
+               return -EINVAL;
+       }
+       new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
+       new_map[0].data.mux.function = parent->name;
+       new_map[0].data.mux.group = np->name;
+       of_node_put(parent);
+
+       /* create config map */
+       new_map++;
+       for (i = 0; i < grp->npins; i++) {
+               new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN;
+               new_map[i].data.configs.group_or_pin =
+                               pin_get_name(pctldev, grp->pins[i]);
+               new_map[i].data.configs.configs = grp->data[i].configs;
+               new_map[i].data.configs.num_configs = grp->data[i].nconfigs;
+       }
+
+       dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n",
+               (*map)->data.mux.function, (*map)->data.mux.group, map_num);
+
+       return 0;
+}
+
+static void rockchip_dt_free_map(struct pinctrl_dev *pctldev,
+                                   struct pinctrl_map *map, unsigned num_maps)
+{
+}
+
+static const struct pinctrl_ops rockchip_pctrl_ops = {
+       .get_groups_count       = rockchip_get_groups_count,
+       .get_group_name         = rockchip_get_group_name,
+       .get_group_pins         = rockchip_get_group_pins,
+       .dt_node_to_map         = rockchip_dt_node_to_map,
+       .dt_free_map            = rockchip_dt_free_map,
+};
+
+/*
+ * Hardware access
+ */
+
+/*
+ * Set a new mux function for a pin.
+ *
+ * The register is divided into the upper and lower 16 bit. When changing
+ * a value, the previous register value is not read and changed. Instead
+ * it seems the changed bits are marked in the upper 16 bit, while the
+ * changed value gets set in the same offset in the lower 16 bit.
+ * All pin settings seem to be 2 bit wide in both the upper and lower
+ * parts.
+ * @bank: pin bank to change
+ * @pin: pin to change
+ * @mux: new mux function to set
+ */
+static void rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
+{
+       struct rockchip_pinctrl *info = bank->drvdata;
+       void __iomem *reg = info->reg_base + info->ctrl->mux_offset;
+       unsigned long flags;
+       u8 bit;
+       u32 data;
+
+       dev_dbg(info->dev, "setting mux of GPIO%d-%d to %d\n",
+                                               bank->bank_num, pin, mux);
+
+       /* get basic quadrupel of mux registers and the correct reg inside */
+       reg += bank->bank_num * 0x10;
+       reg += (pin / 8) * 4;
+       bit = (pin % 8) * 2;
+
+       spin_lock_irqsave(&bank->slock, flags);
+
+       data = (3 << (bit + 16));
+       data |= (mux & 3) << bit;
+       writel(data, reg);
+
+       spin_unlock_irqrestore(&bank->slock, flags);
+}
+
+#define RK2928_PULL_OFFSET             0x118
+#define RK2928_PULL_PINS_PER_REG       16
+#define RK2928_PULL_BANK_STRIDE                8
+
+static void rk2928_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
+                                   int pin_num, void __iomem **reg, u8 *bit)
+{
+       struct rockchip_pinctrl *info = bank->drvdata;
+
+       *reg = info->reg_base + RK2928_PULL_OFFSET;
+       *reg += bank->bank_num * RK2928_PULL_BANK_STRIDE;
+       *reg += (pin_num / RK2928_PULL_PINS_PER_REG) * 4;
+
+       *bit = pin_num % RK2928_PULL_PINS_PER_REG;
+};
+
+#define RK3188_PULL_BITS_PER_PIN       2
+#define RK3188_PULL_PINS_PER_REG       8
+#define RK3188_PULL_BANK_STRIDE                16
+
+static void rk3188_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
+                                   int pin_num, void __iomem **reg, u8 *bit)
+{
+       struct rockchip_pinctrl *info = bank->drvdata;
+
+       /* The first 12 pins of the first bank are located elsewhere */
+       if (bank->bank_type == RK3188_BANK0 && pin_num < 12) {
+               *reg = bank->reg_pull +
+                               ((pin_num / RK3188_PULL_PINS_PER_REG) * 4);
+               *bit = pin_num % RK3188_PULL_PINS_PER_REG;
+               *bit *= RK3188_PULL_BITS_PER_PIN;
+       } else {
+               *reg = info->reg_pull - 4;
+               *reg += bank->bank_num * RK3188_PULL_BANK_STRIDE;
+               *reg += ((pin_num / RK3188_PULL_PINS_PER_REG) * 4);
+
+               /*
+                * The bits in these registers have an inverse ordering
+                * with the lowest pin being in bits 15:14 and the highest
+                * pin in bits 1:0
+                */
+               *bit = 7 - (pin_num % RK3188_PULL_PINS_PER_REG);
+               *bit *= RK3188_PULL_BITS_PER_PIN;
+       }
+}
+
+static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num)
+{
+       struct rockchip_pinctrl *info = bank->drvdata;
+       struct rockchip_pin_ctrl *ctrl = info->ctrl;
+       void __iomem *reg;
+       u8 bit;
+       u32 data;
+
+       /* rk3066b does support any pulls */
+       if (ctrl->type == RK3066B)
+               return PIN_CONFIG_BIAS_DISABLE;
+
+       ctrl->pull_calc_reg(bank, pin_num, &reg, &bit);
+
+       switch (ctrl->type) {
+       case RK2928:
+               return !(readl_relaxed(reg) & BIT(bit))
+                               ? PIN_CONFIG_BIAS_PULL_PIN_DEFAULT
+                               : PIN_CONFIG_BIAS_DISABLE;
+       case RK3188:
+               data = readl_relaxed(reg) >> bit;
+               data &= (1 << RK3188_PULL_BITS_PER_PIN) - 1;
+
+               switch (data) {
+               case 0:
+                       return PIN_CONFIG_BIAS_DISABLE;
+               case 1:
+                       return PIN_CONFIG_BIAS_PULL_UP;
+               case 2:
+                       return PIN_CONFIG_BIAS_PULL_DOWN;
+               case 3:
+                       return PIN_CONFIG_BIAS_BUS_HOLD;
+               }
+
+               dev_err(info->dev, "unknown pull setting\n");
+               return -EIO;
+       default:
+               dev_err(info->dev, "unsupported pinctrl type\n");
+               return -EINVAL;
+       };
+}
+
+static int rockchip_set_pull(struct rockchip_pin_bank *bank,
+                                       int pin_num, int pull)
+{
+       struct rockchip_pinctrl *info = bank->drvdata;
+       struct rockchip_pin_ctrl *ctrl = info->ctrl;
+       void __iomem *reg;
+       unsigned long flags;
+       u8 bit;
+       u32 data;
+
+       dev_dbg(info->dev, "setting pull of GPIO%d-%d to %d\n",
+                bank->bank_num, pin_num, pull);
+
+       /* rk3066b does support any pulls */
+       if (ctrl->type == RK3066B)
+               return pull ? -EINVAL : 0;
+
+       ctrl->pull_calc_reg(bank, pin_num, &reg, &bit);
+
+       switch (ctrl->type) {
+       case RK2928:
+               spin_lock_irqsave(&bank->slock, flags);
+
+               data = BIT(bit + 16);
+               if (pull == PIN_CONFIG_BIAS_DISABLE)
+                       data |= BIT(bit);
+               writel(data, reg);
+
+               spin_unlock_irqrestore(&bank->slock, flags);
+               break;
+       case RK3188:
+               spin_lock_irqsave(&bank->slock, flags);
+
+               /* enable the write to the equivalent lower bits */
+               data = ((1 << RK3188_PULL_BITS_PER_PIN) - 1) << (bit + 16);
+
+               switch (pull) {
+               case PIN_CONFIG_BIAS_DISABLE:
+                       break;
+               case PIN_CONFIG_BIAS_PULL_UP:
+                       data |= (1 << bit);
+                       break;
+               case PIN_CONFIG_BIAS_PULL_DOWN:
+                       data |= (2 << bit);
+                       break;
+               case PIN_CONFIG_BIAS_BUS_HOLD:
+                       data |= (3 << bit);
+                       break;
+               default:
+                       dev_err(info->dev, "unsupported pull setting %d\n",
+                               pull);
+                       return -EINVAL;
+               }
+
+               writel(data, reg);
+
+               spin_unlock_irqrestore(&bank->slock, flags);
+               break;
+       default:
+               dev_err(info->dev, "unsupported pinctrl type\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * Pinmux_ops handling
+ */
+
+static int rockchip_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+       return info->nfunctions;
+}
+
+static const char *rockchip_pmx_get_func_name(struct pinctrl_dev *pctldev,
+                                         unsigned selector)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+       return info->functions[selector].name;
+}
+
+static int rockchip_pmx_get_groups(struct pinctrl_dev *pctldev,
+                               unsigned selector, const char * const **groups,
+                               unsigned * const num_groups)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+       *groups = info->functions[selector].groups;
+       *num_groups = info->functions[selector].ngroups;
+
+       return 0;
+}
+
+static int rockchip_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector,
+                                                           unsigned group)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       const unsigned int *pins = info->groups[group].pins;
+       const struct rockchip_pin_config *data = info->groups[group].data;
+       struct rockchip_pin_bank *bank;
+       int cnt;
+
+       dev_dbg(info->dev, "enable function %s group %s\n",
+               info->functions[selector].name, info->groups[group].name);
+
+       /*
+        * for each pin in the pin group selected, program the correspoding pin
+        * pin function number in the config register.
+        */
+       for (cnt = 0; cnt < info->groups[group].npins; cnt++) {
+               bank = pin_to_bank(info, pins[cnt]);
+               rockchip_set_mux(bank, pins[cnt] - bank->pin_base,
+                                data[cnt].func);
+       }
+
+       return 0;
+}
+
+static void rockchip_pmx_disable(struct pinctrl_dev *pctldev,
+                                       unsigned selector, unsigned group)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       const unsigned int *pins = info->groups[group].pins;
+       struct rockchip_pin_bank *bank;
+       int cnt;
+
+       dev_dbg(info->dev, "disable function %s group %s\n",
+               info->functions[selector].name, info->groups[group].name);
+
+       for (cnt = 0; cnt < info->groups[group].npins; cnt++) {
+               bank = pin_to_bank(info, pins[cnt]);
+               rockchip_set_mux(bank, pins[cnt] - bank->pin_base, 0);
+       }
+}
+
+/*
+ * The calls to gpio_direction_output() and gpio_direction_input()
+ * leads to this function call (via the pinctrl_gpio_direction_{input|output}()
+ * function called from the gpiolib interface).
+ */
+static int rockchip_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
+                                             struct pinctrl_gpio_range *range,
+                                             unsigned offset, bool input)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       struct rockchip_pin_bank *bank;
+       struct gpio_chip *chip;
+       int pin;
+       u32 data;
+
+       chip = range->gc;
+       bank = gc_to_pin_bank(chip);
+       pin = offset - chip->base;
+
+       dev_dbg(info->dev, "gpio_direction for pin %u as %s-%d to %s\n",
+                offset, range->name, pin, input ? "input" : "output");
+
+       rockchip_set_mux(bank, pin, RK_FUNC_GPIO);
+
+       data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR);
+       /* set bit to 1 for output, 0 for input */
+       if (!input)
+               data |= BIT(pin);
+       else
+               data &= ~BIT(pin);
+       writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR);
+
+       return 0;
+}
+
+static const struct pinmux_ops rockchip_pmx_ops = {
+       .get_functions_count    = rockchip_pmx_get_funcs_count,
+       .get_function_name      = rockchip_pmx_get_func_name,
+       .get_function_groups    = rockchip_pmx_get_groups,
+       .enable                 = rockchip_pmx_enable,
+       .disable                = rockchip_pmx_disable,
+       .gpio_set_direction     = rockchip_pmx_gpio_set_direction,
+};
+
+/*
+ * Pinconf_ops handling
+ */
+
+static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl,
+                                       enum pin_config_param pull)
+{
+       switch (ctrl->type) {
+       case RK2928:
+               return (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT ||
+                                       pull == PIN_CONFIG_BIAS_DISABLE);
+       case RK3066B:
+               return pull ? false : true;
+       case RK3188:
+               return (pull != PIN_CONFIG_BIAS_PULL_PIN_DEFAULT);
+       }
+
+       return false;
+}
+
+/* set the pin config settings for a specified pin */
+static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
+                               unsigned long *configs, unsigned num_configs)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       struct rockchip_pin_bank *bank = pin_to_bank(info, pin);
+       enum pin_config_param param;
+       u16 arg;
+       int i;
+       int rc;
+
+       for (i = 0; i < num_configs; i++) {
+               param = pinconf_to_config_param(configs[i]);
+               arg = pinconf_to_config_argument(configs[i]);
+
+               switch (param) {
+               case PIN_CONFIG_BIAS_DISABLE:
+                       rc =  rockchip_set_pull(bank, pin - bank->pin_base,
+                               param);
+                       if (rc)
+                               return rc;
+                       break;
+               case PIN_CONFIG_BIAS_PULL_UP:
+               case PIN_CONFIG_BIAS_PULL_DOWN:
+               case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
+               case PIN_CONFIG_BIAS_BUS_HOLD:
+                       if (!rockchip_pinconf_pull_valid(info->ctrl, param))
+                               return -ENOTSUPP;
+
+                       if (!arg)
+                               return -EINVAL;
+
+                       rc = rockchip_set_pull(bank, pin - bank->pin_base,
+                               param);
+                       if (rc)
+                               return rc;
+                       break;
+               default:
+                       return -ENOTSUPP;
+                       break;
+               }
+       } /* for each config */
+
+       return 0;
+}
+
+/* get the pin config settings for a specified pin */
+static int rockchip_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
+                                                       unsigned long *config)
+{
+       struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+       struct rockchip_pin_bank *bank = pin_to_bank(info, pin);
+       enum pin_config_param param = pinconf_to_config_param(*config);
+
+       switch (param) {
+       case PIN_CONFIG_BIAS_DISABLE:
+               if (rockchip_get_pull(bank, pin - bank->pin_base) != param)
+                       return -EINVAL;
+
+               *config = 0;
+               break;
+       case PIN_CONFIG_BIAS_PULL_UP:
+       case PIN_CONFIG_BIAS_PULL_DOWN:
+       case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
+       case PIN_CONFIG_BIAS_BUS_HOLD:
+               if (!rockchip_pinconf_pull_valid(info->ctrl, param))
+                       return -ENOTSUPP;
+
+               if (rockchip_get_pull(bank, pin - bank->pin_base) != param)
+                       return -EINVAL;
+
+               *config = 1;
+               break;
+       default:
+               return -ENOTSUPP;
+               break;
+       }
+
+       return 0;
+}
+
+static const struct pinconf_ops rockchip_pinconf_ops = {
+       .pin_config_get                 = rockchip_pinconf_get,
+       .pin_config_set                 = rockchip_pinconf_set,
+};
+
+static const struct of_device_id rockchip_bank_match[] = {
+       { .compatible = "rockchip,gpio-bank" },
+       { .compatible = "rockchip,rk3188-gpio-bank0" },
+       {},
+};
+
+static void rockchip_pinctrl_child_count(struct rockchip_pinctrl *info,
+                                               struct device_node *np)
+{
+       struct device_node *child;
+
+       for_each_child_of_node(np, child) {
+               if (of_match_node(rockchip_bank_match, child))
+                       continue;
+
+               info->nfunctions++;
+               info->ngroups += of_get_child_count(child);
+       }
+}
+
+static int rockchip_pinctrl_parse_groups(struct device_node *np,
+                                             struct rockchip_pin_group *grp,
+                                             struct rockchip_pinctrl *info,
+                                             u32 index)
+{
+       struct rockchip_pin_bank *bank;
+       int size;
+       const __be32 *list;
+       int num;
+       int i, j;
+       int ret;
+
+       dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
+
+       /* Initialise group */
+       grp->name = np->name;
+
+       /*
+        * the binding format is rockchip,pins = <bank pin mux CONFIG>,
+        * do sanity check and calculate pins number
+        */
+       list = of_get_property(np, "rockchip,pins", &size);
+       /* we do not check return since it's safe node passed down */
+       size /= sizeof(*list);
+       if (!size || size % 4) {
+               dev_err(info->dev, "wrong pins number or pins and configs should be by 4\n");
+               return -EINVAL;
+       }
+
+       grp->npins = size / 4;
+
+       grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
+                                               GFP_KERNEL);
+       grp->data = devm_kzalloc(info->dev, grp->npins *
+                                         sizeof(struct rockchip_pin_config),
+                                       GFP_KERNEL);
+       if (!grp->pins || !grp->data)
+               return -ENOMEM;
+
+       for (i = 0, j = 0; i < size; i += 4, j++) {
+               const __be32 *phandle;
+               struct device_node *np_config;
+
+               num = be32_to_cpu(*list++);
+               bank = bank_num_to_bank(info, num);
+               if (IS_ERR(bank))
+                       return PTR_ERR(bank);
+
+               grp->pins[j] = bank->pin_base + be32_to_cpu(*list++);
+               grp->data[j].func = be32_to_cpu(*list++);
+
+               phandle = list++;
+               if (!phandle)
+                       return -EINVAL;
+
+               np_config = of_find_node_by_phandle(be32_to_cpup(phandle));
+               ret = pinconf_generic_parse_dt_config(np_config,
+                               &grp->data[j].configs, &grp->data[j].nconfigs);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int rockchip_pinctrl_parse_functions(struct device_node *np,
+                                               struct rockchip_pinctrl *info,
+                                               u32 index)
+{
+       struct device_node *child;
+       struct rockchip_pmx_func *func;
+       struct rockchip_pin_group *grp;
+       int ret;
+       static u32 grp_index;
+       u32 i = 0;
+
+       dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name);
+
+       func = &info->functions[index];
+
+       /* Initialise function */
+       func->name = np->name;
+       func->ngroups = of_get_child_count(np);
+       if (func->ngroups <= 0)
+               return 0;
+
+       func->groups = devm_kzalloc(info->dev,
+                       func->ngroups * sizeof(char *), GFP_KERNEL);
+       if (!func->groups)
+               return -ENOMEM;
+
+       for_each_child_of_node(np, child) {
+               func->groups[i] = child->name;
+               grp = &info->groups[grp_index++];
+               ret = rockchip_pinctrl_parse_groups(child, grp, info, i++);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int rockchip_pinctrl_parse_dt(struct platform_device *pdev,
+                                             struct rockchip_pinctrl *info)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct device_node *child;
+       int ret;
+       int i;
+
+       rockchip_pinctrl_child_count(info, np);
+
+       dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions);
+       dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups);
+
+       info->functions = devm_kzalloc(dev, info->nfunctions *
+                                             sizeof(struct rockchip_pmx_func),
+                                             GFP_KERNEL);
+       if (!info->functions) {
+               dev_err(dev, "failed to allocate memory for function list\n");
+               return -EINVAL;
+       }
+
+       info->groups = devm_kzalloc(dev, info->ngroups *
+                                           sizeof(struct rockchip_pin_group),
+                                           GFP_KERNEL);
+       if (!info->groups) {
+               dev_err(dev, "failed allocate memory for ping group list\n");
+               return -EINVAL;
+       }
+
+       i = 0;
+
+       for_each_child_of_node(np, child) {
+               if (of_match_node(rockchip_bank_match, child))
+                       continue;
+
+               ret = rockchip_pinctrl_parse_functions(child, info, i++);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to parse function\n");
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int rockchip_pinctrl_register(struct platform_device *pdev,
+                                       struct rockchip_pinctrl *info)
+{
+       struct pinctrl_desc *ctrldesc = &info->pctl;
+       struct pinctrl_pin_desc *pindesc, *pdesc;
+       struct rockchip_pin_bank *pin_bank;
+       int pin, bank, ret;
+       int k;
+
+       ctrldesc->name = "rockchip-pinctrl";
+       ctrldesc->owner = THIS_MODULE;
+       ctrldesc->pctlops = &rockchip_pctrl_ops;
+       ctrldesc->pmxops = &rockchip_pmx_ops;
+       ctrldesc->confops = &rockchip_pinconf_ops;
+
+       pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) *
+                       info->ctrl->nr_pins, GFP_KERNEL);
+       if (!pindesc) {
+               dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n");
+               return -ENOMEM;
+       }
+       ctrldesc->pins = pindesc;
+       ctrldesc->npins = info->ctrl->nr_pins;
+
+       pdesc = pindesc;
+       for (bank = 0 , k = 0; bank < info->ctrl->nr_banks; bank++) {
+               pin_bank = &info->ctrl->pin_banks[bank];
+               for (pin = 0; pin < pin_bank->nr_pins; pin++, k++) {
+                       pdesc->number = k;
+                       pdesc->name = kasprintf(GFP_KERNEL, "%s-%d",
+                                               pin_bank->name, pin);
+                       pdesc++;
+               }
+       }
+
+       info->pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, info);
+       if (!info->pctl_dev) {
+               dev_err(&pdev->dev, "could not register pinctrl driver\n");
+               return -EINVAL;
+       }
+
+       for (bank = 0; bank < info->ctrl->nr_banks; ++bank) {
+               pin_bank = &info->ctrl->pin_banks[bank];
+               pin_bank->grange.name = pin_bank->name;
+               pin_bank->grange.id = bank;
+               pin_bank->grange.pin_base = pin_bank->pin_base;
+               pin_bank->grange.base = pin_bank->gpio_chip.base;
+               pin_bank->grange.npins = pin_bank->gpio_chip.ngpio;
+               pin_bank->grange.gc = &pin_bank->gpio_chip;
+               pinctrl_add_gpio_range(info->pctl_dev, &pin_bank->grange);
+       }
+
+       ret = rockchip_pinctrl_parse_dt(pdev, info);
+       if (ret) {
+               pinctrl_unregister(info->pctl_dev);
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * GPIO handling
+ */
+
+static int rockchip_gpio_request(struct gpio_chip *chip, unsigned offset)
+{      
+       printk("%s:offset=%d\n",__func__,offset);
+       return pinctrl_request_gpio(chip->base + offset);
+}
+
+static void rockchip_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+       pinctrl_free_gpio(chip->base + offset);
+}
+
+static void rockchip_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
+{
+       struct rockchip_pin_bank *bank = gc_to_pin_bank(gc);
+       void __iomem *reg = bank->reg_base + GPIO_SWPORT_DR;
+       unsigned long flags;
+       u32 data;
+
+       spin_lock_irqsave(&bank->slock, flags);
+
+       data = readl(reg);
+       data &= ~BIT(offset);
+       if (value)
+               data |= BIT(offset);
+       writel(data, reg);
+
+       spin_unlock_irqrestore(&bank->slock, flags);
+
+       
+       DBG_PINCTRL("%s:offset=%d\n",__func__,offset);
+}
+
+/*
+ * Returns the level of the pin for input direction and setting of the DR
+ * register for output gpios.
+ */
+static int rockchip_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+       struct rockchip_pin_bank *bank = gc_to_pin_bank(gc);
+       u32 data;
+
+       data = readl(bank->reg_base + GPIO_EXT_PORT);
+       data >>= offset;
+       data &= 1;
+       return data;
+}
+
+/*
+ * gpiolib gpio_direction_input callback function. The setting of the pin
+ * mux function as 'gpio input' will be handled by the pinctrl susbsystem
+ * interface.
+ */
+static int rockchip_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
+{
+       struct rockchip_pin_bank *bank = gc_to_pin_bank(gc);
+       
+       DBG_PINCTRL("%s:offset=%d\n",__func__,offset);
+       return pinctrl_gpio_direction_input(gc->base + offset);
+}
+
+/*
+ * gpiolib gpio_direction_output callback function. The setting of the pin
+ * mux function as 'gpio output' will be handled by the pinctrl susbsystem
+ * interface.
+ */
+static int rockchip_gpio_direction_output(struct gpio_chip *gc,
+                                         unsigned offset, int value)
+{
+       struct rockchip_pin_bank *bank = gc_to_pin_bank(gc);
+       rockchip_gpio_set(gc, offset, value);
+       
+       DBG_PINCTRL("%s:irq=%d, bank_num=%d, pin_base=%d, offset=%d,value=%d\n",__func__, bank->irq, bank->bank_num, bank->pin_base, offset, value);
+       return pinctrl_gpio_direction_output(gc->base + offset);
+}
+
+/*
+ * gpiolib gpio_to_irq callback function. Creates a mapping between a GPIO pin
+ * and a virtual IRQ, if not already present.
+ */
+static int rockchip_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+       struct rockchip_pin_bank *bank = gc_to_pin_bank(gc);
+       unsigned int virq;
+
+       if (!bank->domain)
+               return -ENXIO;
+
+       virq = irq_create_mapping(bank->domain, offset);
+
+       DBG_PINCTRL("%s:virq=%d, offset=%d\n",__func__, virq, offset);
+
+       return (virq) ? : -ENXIO;
+}
+
+static const struct gpio_chip rockchip_gpiolib_chip = {
+       .request = rockchip_gpio_request,
+       .free = rockchip_gpio_free,
+       .set = rockchip_gpio_set,
+       .get = rockchip_gpio_get,
+       .direction_input = rockchip_gpio_direction_input,
+       .direction_output = rockchip_gpio_direction_output,
+       .to_irq = rockchip_gpio_to_irq,
+       .owner = THIS_MODULE,
+};
+
+/*
+ * Interrupt handling
+ */
+
+static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc)
+{
+       struct irq_chip *chip = irq_get_chip(irq);
+       struct rockchip_pin_bank *bank = irq_get_handler_data(irq);
+       u32 polarity = 0, data = 0;
+       u32 pend;
+       bool edge_changed = false;
+
+       dev_dbg(bank->drvdata->dev, "got irq for bank %s\n", bank->name);
+
+       chained_irq_enter(chip, desc);
+
+       pend = readl_relaxed(bank->reg_base + GPIO_INT_STATUS);
+
+       if (bank->toggle_edge_mode) {
+               polarity = readl_relaxed(bank->reg_base +
+                                        GPIO_INT_POLARITY);
+               data = readl_relaxed(bank->reg_base + GPIO_EXT_PORT);
+       }
+
+       while (pend) {
+               unsigned int virq;
+
+               irq = __ffs(pend);
+               pend &= ~BIT(irq);
+               virq = irq_linear_revmap(bank->domain, irq);
+
+               if (!virq) {
+                       dev_err(bank->drvdata->dev, "unmapped irq %d\n", irq);
+                       continue;
+               }
+
+               dev_dbg(bank->drvdata->dev, "handling irq %d\n", irq);
+
+               /*
+                * Triggering IRQ on both rising and falling edge
+                * needs manual intervention.
+                */
+               if (bank->toggle_edge_mode & BIT(irq)) {
+                       if (data & BIT(irq))
+                               polarity &= ~BIT(irq);
+                       else
+                               polarity |= BIT(irq);
+
+                       edge_changed = true;
+               }
+
+               generic_handle_irq(virq);
+
+               
+               DBG_PINCTRL("%s:irq=%d\n",__func__,irq);
+       }
+
+       if (bank->toggle_edge_mode && edge_changed) {
+               /* Interrupt params should only be set with ints disabled */
+               data = readl_relaxed(bank->reg_base + GPIO_INTEN);
+               writel_relaxed(0, bank->reg_base + GPIO_INTEN);
+               writel(polarity, bank->reg_base + GPIO_INT_POLARITY);
+               writel(data, bank->reg_base + GPIO_INTEN);
+       }
+
+       chained_irq_exit(chip, desc);
+}
+
+static int rockchip_gpio_irq_set_type(struct irq_data *d, unsigned int type)
+{
+       struct rockchip_pin_bank *bank = irq_data_get_irq_chip_data(d);
+       u32 mask = BIT(d->hwirq);
+       u32 polarity;
+       u32 level;
+       u32 data;
+       
+       unsigned long flags;
+       
+       DBG_PINCTRL("%s:type=%d,irq=%d,hwirq=%d\n",__func__,type, d->irq, d->hwirq);
+       
+       /* make sure the pin is configured as gpio input */
+       rockchip_set_mux(bank, d->hwirq, RK_FUNC_GPIO);
+       data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR);
+       data &= ~mask;
+       writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR);
+
+       if (type & IRQ_TYPE_EDGE_BOTH)
+               __irq_set_handler_locked(d->irq, handle_edge_irq);
+       else
+               __irq_set_handler_locked(d->irq, handle_level_irq);
+       
+       spin_lock_irqsave(&bank->slock, flags);
+       
+       level = readl_relaxed(bank->reg_base + GPIO_INTTYPE_LEVEL);
+       polarity = readl_relaxed(bank->reg_base + GPIO_INT_POLARITY);
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_BOTH:
+               bank->toggle_edge_mode |= mask;
+               level |= mask;
+
+               /*
+                * Determine gpio state. If 1 next interrupt should be falling
+                * otherwise rising.
+                */
+               data = readl(bank->reg_base + GPIO_EXT_PORT);
+               if (data & mask)
+                       polarity &= ~mask;
+               else
+                       polarity |= mask;
+               break;
+       case IRQ_TYPE_EDGE_RISING:
+               bank->toggle_edge_mode &= ~mask;
+               level |= mask;
+               polarity |= mask;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               bank->toggle_edge_mode &= ~mask;
+               level |= mask;
+               polarity &= ~mask;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               bank->toggle_edge_mode &= ~mask;
+               level &= ~mask;
+               polarity |= mask;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               bank->toggle_edge_mode &= ~mask;
+               level &= ~mask;
+               polarity &= ~mask;
+               break;
+       default:
+               //spin_unlock_irqrestore(&bank->slock, flags);
+               return -EINVAL;
+       }
+
+       writel_relaxed(level, bank->reg_base + GPIO_INTTYPE_LEVEL);
+       writel_relaxed(polarity, bank->reg_base + GPIO_INT_POLARITY);
+       
+       spin_unlock_irqrestore(&bank->slock, flags);
+       
+       DBG_PINCTRL("%s:type=%d,irq=%d,hwirq=%d,ok\n",__func__,type, d->irq, d->hwirq);
+       return 0;
+}
+#if 0
+static int rockchip_interrupts_register(struct platform_device *pdev,
+                                               struct rockchip_pinctrl *info)
+{
+       struct rockchip_pin_ctrl *ctrl = info->ctrl;
+       struct rockchip_pin_bank *bank = ctrl->pin_banks;
+       unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
+       struct irq_chip_generic *gc;
+       int ret;
+       int i;
+
+       for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
+               if (!bank->valid) {
+                       dev_warn(&pdev->dev, "bank %s is not valid\n",
+                                bank->name);
+                       continue;
+               }
+
+               bank->domain = irq_domain_add_linear(bank->of_node, 32,
+                                               &irq_generic_chip_ops, NULL);
+               if (!bank->domain) {
+                       dev_warn(&pdev->dev, "could not initialize irq domain for bank %s\n",
+                                bank->name);
+                       continue;
+               }
+
+               ret = irq_alloc_domain_generic_chips(bank->domain, 32, 1,
+                                        "rockchip_gpio_irq", handle_level_irq,
+                                        clr, 0, IRQ_GC_INIT_MASK_CACHE);
+               if (ret) {
+                       dev_err(&pdev->dev, "could not alloc generic chips for bank %s\n",
+                               bank->name);
+                       irq_domain_remove(bank->domain);
+                       continue;
+               }
+
+               gc = irq_get_domain_generic_chip(bank->domain, 0);
+               gc->reg_base = bank->reg_base;
+               gc->private = bank;
+               gc->chip_types[0].regs.mask = GPIO_INTEN;
+               gc->chip_types[0].regs.ack = GPIO_PORTS_EOI;
+               gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
+               gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+               gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+               gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake;
+               gc->chip_types[0].chip.irq_set_type = rockchip_gpio_irq_set_type;
+
+               irq_set_handler_data(bank->irq, bank);
+               irq_set_chained_handler(bank->irq, rockchip_irq_demux);
+       }
+
+       return 0;
+}
+#else
+
+static inline void rockchip_gpio_bit_op(void __iomem *reg_base, unsigned int offset, u32 bit, unsigned char flag)
+{
+       u32 val = __raw_readl(reg_base + offset);
+       if (flag)
+               val |= bit;
+       else
+               val &= ~bit;
+       __raw_writel(val, reg_base + offset);
+}
+
+static inline unsigned gpio_to_bit(struct rockchip_pin_bank *bank, unsigned gpio)
+{
+       while (gpio >= (bank->pin_base + bank->nr_pins))
+               bank++;
+
+       return gpio - bank->pin_base;
+}
+
+static inline unsigned offset_to_bit(unsigned offset)
+{
+       return 1u << offset;
+}
+#if 0
+static void GPIOSetPinLevel(void __iomem *reg_base, unsigned int bit, eGPIOPinLevel_t level)
+{
+       rockchip_gpio_bit_op(reg_base, GPIO_SWPORT_DDR, bit, 1);
+       rockchip_gpio_bit_op(reg_base, GPIO_SWPORT_DR, bit, level);
+}
+
+static int GPIOGetPinLevel(void __iomem *reg_base, unsigned int bit)
+{
+       return ((__raw_readl(reg_base + GPIO_EXT_PORT) & bit) != 0);
+}
+
+static void GPIOSetPinDirection(void __iomem *reg_base, unsigned int bit, eGPIOPinDirection_t direction)
+{
+       rockchip_gpio_bit_op(reg_base, GPIO_SWPORT_DDR, bit, direction);
+       /* Enable debounce may halt cpu on wfi, disable it by default */
+       //rockchip_gpio_bit_op(reg_base, GPIO_DEBOUNCE, bit, 1);
+}
+#endif
+static void GPIOEnableIntr(void __iomem *reg_base, unsigned int bit)
+{
+       rockchip_gpio_bit_op(reg_base, GPIO_INTEN, bit, 1);
+}
+
+static void GPIODisableIntr(void __iomem *reg_base, unsigned int bit)
+{
+       rockchip_gpio_bit_op(reg_base, GPIO_INTEN, bit, 0);
+}
+
+static void GPIOAckIntr(void __iomem *reg_base, unsigned int bit)
+{
+       rockchip_gpio_bit_op(reg_base, GPIO_PORTS_EOI, bit, 1);
+}
+#if 0
+static void GPIOSetIntrType(void __iomem *reg_base, unsigned int bit, eGPIOIntType_t type)
+{
+       switch (type) {
+       case GPIOLevelLow:
+               rockchip_gpio_bit_op(reg_base, GPIO_INT_POLARITY, bit, 0);
+               rockchip_gpio_bit_op(reg_base, GPIO_INTTYPE_LEVEL, bit, 0);
+               break;
+       case GPIOLevelHigh:
+               rockchip_gpio_bit_op(reg_base, GPIO_INTTYPE_LEVEL, bit, 0);
+               rockchip_gpio_bit_op(reg_base, GPIO_INT_POLARITY, bit, 1);
+               break;
+       case GPIOEdgelFalling:
+               rockchip_gpio_bit_op(reg_base, GPIO_INTTYPE_LEVEL, bit, 1);
+               rockchip_gpio_bit_op(reg_base, GPIO_INT_POLARITY, bit, 0);
+               break;
+       case GPIOEdgelRising:
+               rockchip_gpio_bit_op(reg_base, GPIO_INTTYPE_LEVEL, bit, 1);
+               rockchip_gpio_bit_op(reg_base, GPIO_INT_POLARITY, bit, 1);
+               break;
+       }
+}
+
+static int rockchip_gpio_irq_set_type(struct irq_data *d, unsigned int type)
+{
+       struct rockchip_pin_bank *bank = irq_data_get_irq_chip_data(d);
+       u32 bit = gpio_to_bit(irq_to_gpio(d->irq));
+       eGPIOIntType_t int_type;
+       unsigned long flags;
+
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               int_type = GPIOEdgelRising;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               int_type = GPIOEdgelFalling;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               int_type = GPIOLevelHigh;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               int_type = GPIOLevelLow;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&bank->slock, flags);
+       //ÉèÖÃΪÖжÏ֮ǰ£¬±ØÐëÏÈÉèÖÃΪÊäÈë״̬
+       GPIOSetPinDirection(bank->reg_base, bit, 0);
+       GPIOSetIntrType(bank->reg_base, bit, int_type);
+       spin_unlock_irqrestore(&bank->slock, flags);
+
+       if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
+               __irq_set_handler_locked(d->irq, handle_level_irq);
+       else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
+               __irq_set_handler_locked(d->irq, handle_edge_irq);
+
+       return 0;
+}
+#endif
+static int rockchip_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+       struct rockchip_pin_bank *bank = irq_data_get_irq_chip_data(d);
+       //u32 bit = gpio_to_bit(bank, d->irq);  
+       u32 bit = d->hwirq;
+       unsigned long flags;
+
+       spin_lock_irqsave(&bank->slock, flags);
+       
+       if (on)
+               bank->suspend_wakeup |= bit;
+       else
+               bank->suspend_wakeup &= ~bit;
+       spin_unlock_irqrestore(&bank->slock, flags);
+       
+       DBG_PINCTRL("%s:irq=%d,hwirq=%d\n",__func__,d->irq, d->hwirq);
+       return 0;
+}
+
+static void rockchip_gpio_irq_unmask(struct irq_data *d)
+{
+       struct rockchip_pin_bank *bank = irq_data_get_irq_chip_data(d);
+       //u32 bit = gpio_to_bit(bank, d->irq);  
+       u32 bit = d->hwirq;
+       unsigned long flags;
+
+       spin_lock_irqsave(&bank->slock, flags);
+       GPIOEnableIntr(bank->reg_base, bit);
+       spin_unlock_irqrestore(&bank->slock, flags);
+
+       DBG_PINCTRL("%s:irq=%d,hwirq=%d\n",__func__,d->irq, d->hwirq);
+}
+
+static void rockchip_gpio_irq_mask(struct irq_data *d)
+{
+       struct rockchip_pin_bank *bank = irq_data_get_irq_chip_data(d);
+       //u32 bit = gpio_to_bit(bank, d->irq);
+       u32 bit = d->hwirq;
+       unsigned long flags;
+
+       spin_lock_irqsave(&bank->slock, flags);
+       GPIODisableIntr(bank->reg_base, bit);
+       spin_unlock_irqrestore(&bank->slock, flags);
+       
+       DBG_PINCTRL("%s:irq=%d,hwirq=%d\n",__func__,d->irq, d->hwirq);
+}
+
+static void rockchip_gpio_irq_ack(struct irq_data *d)
+{
+       struct rockchip_pin_bank *bank = irq_data_get_irq_chip_data(d);
+       //u32 bit = gpio_to_bit(bank, d->irq);
+       u32 bit = d->hwirq;
+
+       GPIOAckIntr(bank->reg_base, bit);
+       
+       DBG_PINCTRL("%s:irq=%d,hwirq=%d\n",__func__,d->irq, d->hwirq);
+}
+
+
+static struct irq_chip rockchip_gpio_irq_chip = {
+       .name           = "GPIO",
+       .irq_ack        = rockchip_gpio_irq_ack,
+       .irq_disable    = rockchip_gpio_irq_mask,
+       .irq_mask       = rockchip_gpio_irq_mask,
+       .irq_unmask     = rockchip_gpio_irq_unmask,
+       .irq_set_type   = rockchip_gpio_irq_set_type,
+       .irq_set_wake   = rockchip_gpio_irq_set_wake,
+};
+
+
+static int rockchip_gpio_irq_map(struct irq_domain *d, unsigned int irq,
+                               irq_hw_number_t hwirq)
+{
+       struct rockchip_pin_bank *bank = d->host_data;  
+       struct irq_data *irq_data = irq_get_irq_data(irq);
+       
+       if (!bank)
+       {
+               printk("%s:bank=0x%p,irq=%d\n",__func__,bank, irq);
+               return -EINVAL;
+       }
+       
+       irq_set_chip_and_handler(irq, &rockchip_gpio_irq_chip, handle_level_irq);
+       irq_set_chip_data(irq, bank);
+       set_irq_flags(irq, IRQF_VALID);
+       
+       irq_data->hwirq = hwirq;
+       irq_data->irq = irq;
+               
+       DBG_PINCTRL("%s:irq=%d\n",__func__,irq);
+       return 0;
+}
+
+const struct irq_domain_ops rockchip_gpio_irq_ops = {
+       .map = rockchip_gpio_irq_map,
+       .xlate = irq_domain_xlate_twocell,
+};
+
+
+static struct lock_class_key gpio_lock_class;
+
+static int rockchip_interrupts_register(struct platform_device *pdev,
+                                               struct rockchip_pinctrl *info)
+{
+       struct rockchip_pin_ctrl *ctrl = info->ctrl;
+       struct rockchip_pin_bank *bank = ctrl->pin_banks;
+       unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
+       int ret;
+       int i,j;
+
+       for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
+               if (!bank->valid) {
+                       dev_warn(&pdev->dev, "bank %s is not valid\n",
+                                bank->name);
+                       continue;
+               }
+               
+               __raw_writel(0, bank->reg_base + GPIO_INTEN);
+               
+#if 1          
+               bank->drvdata = info;
+               bank->domain = irq_domain_add_linear(bank->of_node, 32,
+                               &rockchip_gpio_irq_ops, bank);
+               if (!bank->domain) {
+                       dev_warn(&pdev->dev, "could not initialize irq domain for bank %s\n",
+                                bank->name);
+                       continue;
+               }
+
+               for(j=0; j<32; j++)
+               {
+                       if(bank->domain->ops->map)
+                       bank->domain->ops->map(bank->domain, 6*32+bank->pin_base+j, j);
+               }
+#else
+               
+               for (j = 0; j < 32; j++) {
+                       irq_set_lockdep_class(bank->pin_base+j, &gpio_lock_class);
+                       irq_set_chip_and_handler(bank->pin_base+j, &rockchip_gpio_irq_chip, handle_level_irq);
+                       irq_set_chip_data(bank->pin_base+j, bank);
+                       set_irq_flags(bank->pin_base+j, IRQF_VALID);
+               }
+#endif
+               
+               DBG_PINCTRL("%s:i=%d\n",__func__,i);
+
+               irq_set_handler_data(bank->irq, bank);
+               irq_set_chained_handler(bank->irq, rockchip_irq_demux);
+       }
+
+
+       return 0;
+}
+
+
+#endif
+static int rockchip_gpiolib_register(struct platform_device *pdev,
+                                               struct rockchip_pinctrl *info)
+{
+       struct rockchip_pin_ctrl *ctrl = info->ctrl;
+       struct rockchip_pin_bank *bank = ctrl->pin_banks;
+       struct gpio_chip *gc;
+       int ret;
+       int i;
+
+       for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
+               if (!bank->valid) {
+                       dev_warn(&pdev->dev, "bank %s is not valid\n",
+                                bank->name);
+                       continue;
+               }
+
+               bank->gpio_chip = rockchip_gpiolib_chip;
+
+               gc = &bank->gpio_chip;
+               gc->base = bank->pin_base;
+               gc->ngpio = bank->nr_pins;
+               gc->dev = &pdev->dev;
+               gc->of_node = bank->of_node;
+               gc->label = bank->name;
+
+               ret = gpiochip_add(gc);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n",
+                                                       gc->label, ret);
+                       goto fail;
+               }
+       }
+
+       rockchip_interrupts_register(pdev, info);
+
+       return 0;
+
+fail:
+       for (--i, --bank; i >= 0; --i, --bank) {
+               if (!bank->valid)
+                       continue;
+
+               if (gpiochip_remove(&bank->gpio_chip))
+                       dev_err(&pdev->dev, "gpio chip %s remove failed\n",
+                                                       bank->gpio_chip.label);
+       }
+       return ret;
+}
+
+static int rockchip_gpiolib_unregister(struct platform_device *pdev,
+                                               struct rockchip_pinctrl *info)
+{
+       struct rockchip_pin_ctrl *ctrl = info->ctrl;
+       struct rockchip_pin_bank *bank = ctrl->pin_banks;
+       int ret = 0;
+       int i;
+
+       for (i = 0; !ret && i < ctrl->nr_banks; ++i, ++bank) {
+               if (!bank->valid)
+                       continue;
+
+               ret = gpiochip_remove(&bank->gpio_chip);
+       }
+
+       if (ret)
+               dev_err(&pdev->dev, "gpio chip remove failed\n");
+
+       return ret;
+}
+
+static int rockchip_get_bank_data(struct rockchip_pin_bank *bank,
+                                 struct device *dev)
+{
+       struct resource res;
+
+       if (of_address_to_resource(bank->of_node, 0, &res)) {
+               dev_err(dev, "cannot find IO resource for bank\n");
+               return -ENOENT;
+       }
+
+       bank->reg_base = devm_ioremap_resource(dev, &res);
+       if (IS_ERR(bank->reg_base))
+               return PTR_ERR(bank->reg_base);
+
+       /*
+        * special case, where parts of the pull setting-registers are
+        * part of the PMU register space
+        */
+       if (of_device_is_compatible(bank->of_node,
+                                   "rockchip,rk3188-gpio-bank0")) {
+               bank->bank_type = RK3188_BANK0;
+
+               if (of_address_to_resource(bank->of_node, 1, &res)) {
+                       dev_err(dev, "cannot find IO resource for bank\n");
+                       return -ENOENT;
+               }
+
+               bank->reg_pull = devm_ioremap_resource(dev, &res);
+               if (IS_ERR(bank->reg_pull))
+                       return PTR_ERR(bank->reg_pull);
+       } else {
+               bank->bank_type = COMMON_BANK;
+       }
+
+       bank->irq = irq_of_parse_and_map(bank->of_node, 0);
+
+       bank->clk = of_clk_get(bank->of_node, 0);
+       //if (IS_ERR(bank->clk))
+               //return PTR_ERR(bank->clk);
+       return 0;
+       //return clk_prepare_enable(bank->clk);
+}
+
+static const struct of_device_id rockchip_pinctrl_dt_match[];
+
+/* retrieve the soc specific data */
+static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(
+                                               struct rockchip_pinctrl *d,
+                                               struct platform_device *pdev)
+{
+       const struct of_device_id *match;
+       struct device_node *node = pdev->dev.of_node;
+       struct device_node *np;
+       struct rockchip_pin_ctrl *ctrl;
+       struct rockchip_pin_bank *bank;
+       int i;
+
+       match = of_match_node(rockchip_pinctrl_dt_match, node);
+       ctrl = (struct rockchip_pin_ctrl *)match->data;
+
+       for_each_child_of_node(node, np) {
+               if (!of_find_property(np, "gpio-controller", NULL))
+                       continue;
+
+               bank = ctrl->pin_banks;
+               for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
+                       if (!strcmp(bank->name, np->name)) {
+                               bank->of_node = np;
+
+                               if (!rockchip_get_bank_data(bank, &pdev->dev))
+                                       bank->valid = true;
+
+                               break;
+                       }
+               }
+       }
+
+       bank = ctrl->pin_banks;
+       for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
+               spin_lock_init(&bank->slock);
+               bank->drvdata = d;
+               bank->pin_base = ctrl->nr_pins;
+               ctrl->nr_pins += bank->nr_pins;
+       }
+
+       return ctrl;
+}
+
+static irqreturn_t pinctrl_interrupt_test(int irq, void *dev_id)
+{
+       printk("%s:line=%d\n",__func__, __LINE__);
+       return IRQ_HANDLED;
+}
+
+static int rockchip_pinctrl_probe(struct platform_device *pdev)
+{
+       struct rockchip_pinctrl *info;
+       struct device *dev = &pdev->dev;
+       struct rockchip_pin_ctrl *ctrl;
+       struct resource *res;
+       int ret;
+       
+       if (!dev->of_node) {
+               dev_err(dev, "device tree node not found\n");
+               return -ENODEV;
+       }
+
+       info = devm_kzalloc(dev, sizeof(struct rockchip_pinctrl), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       ctrl = rockchip_pinctrl_get_soc_data(info, pdev);
+       if (!ctrl) {
+               dev_err(dev, "driver data not available\n");
+               return -EINVAL;
+       }
+       info->ctrl = ctrl;
+       info->dev = dev;
+       
+       atomic_set(&info->debug_flag, 0);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       info->reg_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(info->reg_base))
+               return PTR_ERR(info->reg_base);
+
+       /* The RK3188 has its pull registers in a separate place */
+       if (ctrl->type == RK3188) {
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+               info->reg_pull = devm_ioremap_resource(&pdev->dev, res);
+               if (IS_ERR(info->reg_base))
+                       return PTR_ERR(info->reg_base);
+       }
+
+       ret = rockchip_gpiolib_register(pdev, info);
+       if (ret)
+               return ret;
+
+       ret = rockchip_pinctrl_register(pdev, info);
+       if (ret) {
+               rockchip_gpiolib_unregister(pdev, info);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, info);
+#if 0
+       gpio_request(110, NULL);        
+       gpio_direction_output(110, 1);
+
+       gpio_request(111, NULL);
+       gpio_direction_output(111, 1);
+       
+       ret = request_irq(112, pinctrl_interrupt_test, IRQ_TYPE_EDGE_RISING, "test", info);
+       disable_irq(112);
+#endif
+       printk("%s:init ok\n",__func__);
+       return 0;
+}
+
+static struct rockchip_pin_bank rk2928_pin_banks[] = {
+       PIN_BANK(0, 32, "gpio0"),
+       PIN_BANK(1, 32, "gpio1"),
+       PIN_BANK(2, 32, "gpio2"),
+       PIN_BANK(3, 32, "gpio3"),
+};
+
+static struct rockchip_pin_ctrl rk2928_pin_ctrl = {
+               .pin_banks              = rk2928_pin_banks,
+               .nr_banks               = ARRAY_SIZE(rk2928_pin_banks),
+               .label                  = "RK2928-GPIO",
+               .type                   = RK2928,
+               .mux_offset             = 0xa8,
+               .pull_calc_reg          = rk2928_calc_pull_reg_and_bit,
+};
+
+static struct rockchip_pin_bank rk3066a_pin_banks[] = {
+       PIN_BANK(0, 32, "gpio0"),
+       PIN_BANK(1, 32, "gpio1"),
+       PIN_BANK(2, 32, "gpio2"),
+       PIN_BANK(3, 32, "gpio3"),
+       PIN_BANK(4, 32, "gpio4"),
+       PIN_BANK(6, 16, "gpio6"),
+};
+
+static struct rockchip_pin_ctrl rk3066a_pin_ctrl = {
+               .pin_banks              = rk3066a_pin_banks,
+               .nr_banks               = ARRAY_SIZE(rk3066a_pin_banks),
+               .label                  = "RK3066a-GPIO",
+               .type                   = RK2928,
+               .mux_offset             = 0xa8,
+               .pull_calc_reg          = rk2928_calc_pull_reg_and_bit,
+};
+
+static struct rockchip_pin_bank rk3066b_pin_banks[] = {
+       PIN_BANK(0, 32, "gpio0"),
+       PIN_BANK(1, 32, "gpio1"),
+       PIN_BANK(2, 32, "gpio2"),
+       PIN_BANK(3, 32, "gpio3"),
+};
+
+static struct rockchip_pin_ctrl rk3066b_pin_ctrl = {
+               .pin_banks      = rk3066b_pin_banks,
+               .nr_banks       = ARRAY_SIZE(rk3066b_pin_banks),
+               .label          = "RK3066b-GPIO",
+               .type           = RK3066B,
+               .mux_offset     = 0x60,
+};
+
+static struct rockchip_pin_bank rk3188_pin_banks[] = {
+       PIN_BANK(0, 32, "gpio0"),
+       PIN_BANK(1, 32, "gpio1"),
+       PIN_BANK(2, 32, "gpio2"),
+       PIN_BANK(3, 32, "gpio3"),
+};
+
+static struct rockchip_pin_ctrl rk3188_pin_ctrl = {
+               .pin_banks              = rk3188_pin_banks,
+               .nr_banks               = ARRAY_SIZE(rk3188_pin_banks),
+               .label                  = "RK3188-GPIO",
+               .type                   = RK3188,
+               .mux_offset             = 0x68,
+               .pull_calc_reg          = rk3188_calc_pull_reg_and_bit,
+};
+
+static const struct of_device_id rockchip_pinctrl_dt_match[] = {
+       { .compatible = "rockchip,rk2928-pinctrl",
+               .data = (void *)&rk2928_pin_ctrl },
+       { .compatible = "rockchip,rk3066a-pinctrl",
+               .data = (void *)&rk3066a_pin_ctrl },
+       { .compatible = "rockchip,rk3066b-pinctrl",
+               .data = (void *)&rk3066b_pin_ctrl },
+       { .compatible = "rockchip,rk3188-pinctrl",
+               .data = (void *)&rk3188_pin_ctrl },
+       {},
+};
+MODULE_DEVICE_TABLE(of, rockchip_pinctrl_dt_match);
+
+static struct platform_driver rockchip_pinctrl_driver = {
+       .probe          = rockchip_pinctrl_probe,
+       .driver = {
+               .name   = "rockchip-pinctrl",
+               .owner  = THIS_MODULE,
+               .of_match_table = rockchip_pinctrl_dt_match,
+       },
+};
+
+static int __init rockchip_pinctrl_drv_register(void)
+{
+       return platform_driver_register(&rockchip_pinctrl_driver);
+}
+postcore_initcall(rockchip_pinctrl_drv_register);
+
+MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
+MODULE_DESCRIPTION("Rockchip pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/dt-bindings/pinctrl/rockchip.h b/include/dt-bindings/pinctrl/rockchip.h
new file mode 100755 (executable)
index 0000000..cd5788b
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Header providing constants for Rockchip pinctrl bindings.
+ *
+ * Copyright (c) 2013 MundoReader S.L.
+ * Author: Heiko Stuebner <heiko@sntech.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __DT_BINDINGS_ROCKCHIP_PINCTRL_H__
+#define __DT_BINDINGS_ROCKCHIP_PINCTRL_H__
+
+#define RK_GPIO0       0
+#define RK_GPIO1       1
+#define RK_GPIO2       2
+#define RK_GPIO3       3
+#define RK_GPIO4       4
+#define RK_GPIO6       6
+
+#define RK_FUNC_GPIO   0
+#define RK_FUNC_1      1
+#define RK_FUNC_2      2
+
+#endif