Merge tag 'pinctrl-v4.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 7 Jun 2018 20:56:45 +0000 (13:56 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 7 Jun 2018 20:56:45 +0000 (13:56 -0700)
Pull pin control updates from Linus Walleij:
 "This is the bulk of pin control changes for v4.18.

  No core changes this time! Just a calm all-over-the-place drivers,
  updates and fixes cycle as it seems.

  New drivers/subdrivers:

   - Actions Semiconductor S900 driver with more Actions variants for
     S700, S500 in the pipe. Also generic GPIO support on top of the
     same driver and IRQ support is in the pipe.

   - Renesas r8a77470 PFC support.

   - Renesas r8a77990 PFC support.

   - Allwinner Sunxi H6 R_PIO support.

   - Rockchip PX30 support.

   - Meson Meson8m2 support.

   - Remove support for the ill-fated Samsung Exynos 5440 SoC.

  Improvements:

   - Context save/restore support in pinctrl-single.

   - External interrupt support for the Mediatek MT7622.

   - Qualcomm ACPI HID QCOM8002 supported.

  Fixes:

   - Fix up suspend/resume support for Exynos 5433.

   - Fix Strago DMI fixes on the Intel Cherryview"

* tag 'pinctrl-v4.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (72 commits)
  pinctrl: cherryview: limit Strago DMI workarounds to version 1.0
  pinctrl: at91-pio4: add missing of_node_put
  pinctrl: armada-37xx: Fix spurious irq management
  gpiolib: discourage gpiochip_add_pin[group]_range for DT pinctrls
  pinctrl: msm: fix gpio-hog related boot issues
  MAINTAINERS: update entry for Mediatek pin controller
  pinctrl: mediatek: remove unused fields in struct mtk_eint_hw
  pinctrl: mediatek: use generic EINT register maps for each SoC
  pinctrl: mediatek: add EINT support to MT7622 SoC
  pinctrl: mediatek: refactor EINT related code for all MediaTek pinctrl can fit
  dt-bindings: pinctrl: add external interrupt support to MT7622 pinctrl
  pinctrl: freescale: Switch to SPDX identifier
  pinctrl: samsung: Fix suspend/resume for Exynos5433 GPF1..5 banks
  pinctrl: sh-pfc: rcar-gen3: Fix grammar in static pin comments
  pinctrl: sh-pfc: r8a77965: Add I2C pin support
  pinctrl: sh-pfc: r8a77990: Add EthernetAVB pins, groups and functions
  pinctrl: sh-pfc: r8a77990: Add I2C{1,2,4,5,6,7} pins, groups and functions
  pinctrl: sh-pfc: r8a77990: Add SCIF pins, groups and functions
  pinctrl: sh-pfc: r8a77990: Add bias pinconf support
  pinctrl: sh-pfc: Initial R8A77990 PFC support
  ...

102 files changed:
Documentation/devicetree/bindings/pinctrl/actions,s900-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/brcm,bcm2835-gpio.txt
Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt
Documentation/devicetree/bindings/pinctrl/pinctrl-mcp23s08.txt
Documentation/devicetree/bindings/pinctrl/pinctrl-mt7622.txt
Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt
Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt
MAINTAINERS
drivers/gpio/gpiolib.c
drivers/pinctrl/Kconfig
drivers/pinctrl/Makefile
drivers/pinctrl/actions/Kconfig [new file with mode: 0644]
drivers/pinctrl/actions/Makefile [new file with mode: 0644]
drivers/pinctrl/actions/pinctrl-owl.c [new file with mode: 0644]
drivers/pinctrl/actions/pinctrl-owl.h [new file with mode: 0644]
drivers/pinctrl/actions/pinctrl-s900.c [new file with mode: 0644]
drivers/pinctrl/bcm/Kconfig
drivers/pinctrl/bcm/pinctrl-bcm2835.c
drivers/pinctrl/berlin/berlin-bg2.c
drivers/pinctrl/berlin/berlin-bg2cd.c
drivers/pinctrl/berlin/berlin-bg2q.c
drivers/pinctrl/berlin/berlin-bg4ct.c
drivers/pinctrl/berlin/berlin.c
drivers/pinctrl/berlin/berlin.h
drivers/pinctrl/freescale/pinctrl-imx.c
drivers/pinctrl/freescale/pinctrl-imx.h
drivers/pinctrl/freescale/pinctrl-imx1-core.c
drivers/pinctrl/freescale/pinctrl-imx1.c
drivers/pinctrl/freescale/pinctrl-imx1.h
drivers/pinctrl/freescale/pinctrl-imx21.c
drivers/pinctrl/freescale/pinctrl-imx23.c
drivers/pinctrl/freescale/pinctrl-imx25.c
drivers/pinctrl/freescale/pinctrl-imx27.c
drivers/pinctrl/freescale/pinctrl-imx28.c
drivers/pinctrl/freescale/pinctrl-imx35.c
drivers/pinctrl/freescale/pinctrl-imx50.c
drivers/pinctrl/freescale/pinctrl-imx51.c
drivers/pinctrl/freescale/pinctrl-imx53.c
drivers/pinctrl/freescale/pinctrl-imx6dl.c
drivers/pinctrl/freescale/pinctrl-imx6q.c
drivers/pinctrl/freescale/pinctrl-imx6sl.c
drivers/pinctrl/freescale/pinctrl-imx6sll.c
drivers/pinctrl/freescale/pinctrl-imx6sx.c
drivers/pinctrl/freescale/pinctrl-imx6ul.c
drivers/pinctrl/freescale/pinctrl-imx7d.c
drivers/pinctrl/freescale/pinctrl-imx7ulp.c
drivers/pinctrl/freescale/pinctrl-mxs.c
drivers/pinctrl/freescale/pinctrl-mxs.h
drivers/pinctrl/freescale/pinctrl-vf610.c
drivers/pinctrl/intel/pinctrl-cherryview.c
drivers/pinctrl/mediatek/Kconfig
drivers/pinctrl/mediatek/Makefile
drivers/pinctrl/mediatek/mtk-eint.c [new file with mode: 0644]
drivers/pinctrl/mediatek/mtk-eint.h [new file with mode: 0644]
drivers/pinctrl/mediatek/pinctrl-mt2701.c
drivers/pinctrl/mediatek/pinctrl-mt2712.c
drivers/pinctrl/mediatek/pinctrl-mt7622.c
drivers/pinctrl/mediatek/pinctrl-mt8127.c
drivers/pinctrl/mediatek/pinctrl-mt8135.c
drivers/pinctrl/mediatek/pinctrl-mt8173.c
drivers/pinctrl/mediatek/pinctrl-mtk-common.c
drivers/pinctrl/mediatek/pinctrl-mtk-common.h
drivers/pinctrl/meson/pinctrl-meson-axg.c
drivers/pinctrl/meson/pinctrl-meson-gxbb.c
drivers/pinctrl/meson/pinctrl-meson-gxl.c
drivers/pinctrl/meson/pinctrl-meson8.c
drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
drivers/pinctrl/mvebu/pinctrl-armada-xp.c
drivers/pinctrl/pinctrl-at91-pio4.c
drivers/pinctrl/pinctrl-rockchip.c
drivers/pinctrl/pinctrl-single.c
drivers/pinctrl/qcom/pinctrl-msm.c
drivers/pinctrl/qcom/pinctrl-qdf2xxx.c
drivers/pinctrl/samsung/Kconfig
drivers/pinctrl/samsung/Makefile
drivers/pinctrl/samsung/pinctrl-exynos-arm.c
drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
drivers/pinctrl/samsung/pinctrl-exynos.h
drivers/pinctrl/samsung/pinctrl-exynos5440.c [deleted file]
drivers/pinctrl/samsung/pinctrl-samsung.c
drivers/pinctrl/sh-pfc/Kconfig
drivers/pinctrl/sh-pfc/Makefile
drivers/pinctrl/sh-pfc/core.c
drivers/pinctrl/sh-pfc/pfc-r8a77470.c [new file with mode: 0644]
drivers/pinctrl/sh-pfc/pfc-r8a7795-es1.c
drivers/pinctrl/sh-pfc/pfc-r8a7795.c
drivers/pinctrl/sh-pfc/pfc-r8a7796.c
drivers/pinctrl/sh-pfc/pfc-r8a77965.c
drivers/pinctrl/sh-pfc/pfc-r8a77970.c
drivers/pinctrl/sh-pfc/pfc-r8a77980.c
drivers/pinctrl/sh-pfc/pfc-r8a77990.c [new file with mode: 0644]
drivers/pinctrl/sh-pfc/sh_pfc.h
drivers/pinctrl/sunxi/Kconfig
drivers/pinctrl/sunxi/Makefile
drivers/pinctrl/sunxi/pinctrl-sun50i-h6-r.c [new file with mode: 0644]
drivers/pinctrl/tegra/pinctrl-tegra.c
drivers/pinctrl/tegra/pinctrl-tegra.h
drivers/pinctrl/tegra/pinctrl-tegra20.c
drivers/pinctrl/uniphier/pinctrl-uniphier-ld11.c
drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c
include/dt-bindings/pinctrl/mt7623-pinfunc.h

index fb87c7d74f2e56eea0192c183287bec56a97e70c..8fb5a53775e88afea215e3318ec352278e53624e 100644 (file)
@@ -8,6 +8,17 @@ Required Properties:
 - reg:          Should contain the register base address and size of
                 the pin controller.
 - clocks:       phandle of the clock feeding the pin controller
+- gpio-controller: Marks the device node as a GPIO controller.
+- gpio-ranges: Specifies the mapping between gpio controller and
+               pin-controller pins.
+- #gpio-cells: Should be two. The first cell is the gpio pin number
+               and the second cell is used for optional parameters.
+- interrupt-controller: Marks the device node as an interrupt controller.
+- #interrupt-cells: Specifies the number of cells needed to encode an
+                    interrupt.  Shall be set to 2.  The first cell
+                    defines the interrupt number, the second encodes
+                    the trigger flags described in
+                    bindings/interrupt-controller/interrupts.txt
 
 Please refer to pinctrl-bindings.txt in this directory for details of the
 common pinctrl bindings used by client devices, including the meaning of the
@@ -164,6 +175,11 @@ Example:
                   compatible = "actions,s900-pinctrl";
                   reg = <0x0 0xe01b0000 0x0 0x1000>;
                   clocks = <&cmu CLK_GPIO>;
+                  gpio-controller;
+                  gpio-ranges = <&pinctrl 0 0 146>;
+                  #gpio-cells = <2>;
+                  interrupt-controller;
+                  #interrupt-cells = <2>;
 
                   uart2-default: uart2-default {
                           pinmux {
index 64bc5c2a76da613609b3c4db8f3bc00bf9a38107..258a4648ab813304b9008daf7572c32ee7b973ca 100644 (file)
@@ -28,6 +28,7 @@ Required properties:
   "allwinner,sun50i-a64-r-pinctrl"
   "allwinner,sun50i-h5-pinctrl"
   "allwinner,sun50i-h6-pinctrl"
+  "allwinner,sun50i-h6-r-pinctrl"
   "nextthing,gr8-pinctrl"
 
 - reg: Should contain the register physical address and length for the
index 2569866c692f4a8c90b2641953deb41ef370d3db..3fac0a061bcc7c5b1cc6dbfa76b4b006e6876f48 100644 (file)
@@ -36,6 +36,24 @@ listed. In other words, a subnode that lists only a mux function implies no
 information about any pull configuration. Similarly, a subnode that lists only
 a pul parameter implies no information about the mux function.
 
+The BCM2835 pin configuration and multiplexing supports the generic bindings.
+For details on each properties, you can refer to ./pinctrl-bindings.txt.
+
+Required sub-node properties:
+  - pins
+  - function
+
+Optional sub-node properties:
+  - bias-disable
+  - bias-pull-up
+  - bias-pull-down
+  - output-high
+  - output-low
+
+Legacy pin configuration and multiplexing binding:
+*** (Its use is deprecated, use generic multiplexing and configuration
+bindings instead)
+
 Required subnode-properties:
 - brcm,pins: An array of cells. Each cell contains the ID of a pin. Valid IDs
   are the integer GPIO IDs; 0==GPIO0, 1==GPIO1, ... 53==GPIO53.
index 2c12f9789116c38afb6a2e23e69bd533788862e8..54ecb8ab778836e7c6d6b95641b64a01d0ca3485 100644 (file)
@@ -3,8 +3,10 @@
 Required properties for the root node:
  - compatible: one of "amlogic,meson8-cbus-pinctrl"
                      "amlogic,meson8b-cbus-pinctrl"
+                     "amlogic,meson8m2-cbus-pinctrl"
                      "amlogic,meson8-aobus-pinctrl"
                      "amlogic,meson8b-aobus-pinctrl"
+                     "amlogic,meson8m2-aobus-pinctrl"
                      "amlogic,meson-gxbb-periphs-pinctrl"
                      "amlogic,meson-gxbb-aobus-pinctrl"
                      "amlogic,meson-gxl-periphs-pinctrl"
index a5a8322a31bda245497776187a4d393e091c7349..a677145ae6d1f6f69a765f785ccaeaf25f49912b 100644 (file)
@@ -18,7 +18,9 @@ Required properties:
     removed.
 - #gpio-cells : Should be two.
   - first cell is the pin number
-  - second cell is used to specify flags. Flags are currently unused.
+  - second cell is used to specify flags as described in
+    'Documentation/devicetree/bindings/gpio/gpio.txt'. Allowed values defined by
+    'include/dt-bindings/gpio/gpio.h' (e.g. GPIO_ACTIVE_LOW).
 - gpio-controller : Marks the device node as a GPIO controller.
 - reg : For an address on its bus. I2C uses this a the I2C address of the chip.
         SPI uses this to specify the chipselect line which the chip is
index f18ed99f6e1455d0082327c0dde5797f589bb6a1..def8fcad894147ed4e7d4ea14b974e902c7baab7 100644 (file)
@@ -9,6 +9,16 @@ Required properties for the root node:
  - #gpio-cells: Should be two. The first cell is the pin number and the
    second is the GPIO flags.
 
+Optional properties:
+- interrupt-controller  : Marks the device node as an interrupt controller
+
+If the property interrupt-controller is defined, following property is required
+- reg-names: A string describing the "reg" entries. Must contain "eint".
+- interrupts : The interrupt output from the controller.
+- #interrupt-cells: Should be two.
+- interrupt-parent: Phandle of the interrupt parent to which the external
+  GPIO interrupts are forwarded to.
+
 Please refer to pinctrl-bindings.txt in this directory for details of the
 common pinctrl bindings used by client devices, including the meaning of the
 phrase "pin configuration node".
index 892d8fd7b70036a8beef8eab75a08bf8d555384a..abd8fbcf1e62d480562a0fb9d1471020c0c29d75 100644 (file)
@@ -15,6 +15,7 @@ Required Properties:
     - "renesas,pfc-r8a7740": for R8A7740 (R-Mobile A1) compatible pin-controller.
     - "renesas,pfc-r8a7743": for R8A7743 (RZ/G1M) compatible pin-controller.
     - "renesas,pfc-r8a7745": for R8A7745 (RZ/G1E) compatible pin-controller.
+    - "renesas,pfc-r8a77470": for R8A77470 (RZ/G1C) compatible pin-controller.
     - "renesas,pfc-r8a7778": for R8A7778 (R-Car M1) compatible pin-controller.
     - "renesas,pfc-r8a7779": for R8A7779 (R-Car H1) compatible pin-controller.
     - "renesas,pfc-r8a7790": for R8A7790 (R-Car H2) compatible pin-controller.
@@ -27,6 +28,7 @@ Required Properties:
     - "renesas,pfc-r8a77965": for R8A77965 (R-Car M3-N) compatible pin-controller.
     - "renesas,pfc-r8a77970": for R8A77970 (R-Car V3M) compatible pin-controller.
     - "renesas,pfc-r8a77980": for R8A77980 (R-Car V3H) compatible pin-controller.
+    - "renesas,pfc-r8a77990": for R8A77990 (R-Car E3) compatible pin-controller.
     - "renesas,pfc-r8a77995": for R8A77995 (R-Car D3) compatible pin-controller.
     - "renesas,pfc-sh73a0": for SH73A0 (SH-Mobile AG5) compatible pin-controller.
 
index a01a3b8a23632a8707ff9e528c6c010500d8da9a..0919db294c174e66710280d8d6688f78d436e3cd 100644 (file)
@@ -20,6 +20,7 @@ defined as gpio sub-nodes of the pinmux controller.
 
 Required properties for iomux controller:
   - compatible: should be
+               "rockchip,px30-pinctrl":    for Rockchip PX30
                "rockchip,rv1108-pinctrl":  for Rockchip RV1108
                "rockchip,rk2928-pinctrl":  for Rockchip RK2928
                "rockchip,rk3066a-pinctrl": for Rockchip RK3066a
index b4a564213cdf0eff056ed90d2b7dcca4263bdd04..d96c613d777d91f70c1e4e17228906460de862ee 100644 (file)
@@ -1135,10 +1135,12 @@ F:      arch/arm/mach-actions/
 F:     arch/arm/boot/dts/owl-*
 F:     arch/arm64/boot/dts/actions/
 F:     drivers/clocksource/owl-*
+F:     drivers/pinctrl/actions/*
 F:     drivers/soc/actions/
 F:     include/dt-bindings/power/owl-*
 F:     include/linux/soc/actions/
 F:     Documentation/devicetree/bindings/arm/actions.txt
+F:     Documentation/devicetree/bindings/pinctrl/actions,s900-pinctrl.txt
 F:     Documentation/devicetree/bindings/power/actions,owl-sps.txt
 F:     Documentation/devicetree/bindings/timer/actions,owl-timer.txt
 
@@ -11225,6 +11227,7 @@ L:      linux-mediatek@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt
 F:     Documentation/devicetree/bindings/pinctrl/pinctrl-mt7622.txt
+F:     drivers/pinctrl/mediatek/mtk-eint.*
 F:     drivers/pinctrl/mediatek/pinctrl-mtk-common.*
 F:     drivers/pinctrl/mediatek/pinctrl-mt2701.c
 F:     drivers/pinctrl/mediatek/pinctrl-mt7622.c
index 55d596f3035e5656fb1269dedd8b22bd67778897..5dfd3c17fffc90fe999be8091ec59a2bec88185a 100644 (file)
@@ -2078,6 +2078,11 @@ EXPORT_SYMBOL_GPL(gpiochip_generic_config);
  * @pctldev: the pin controller to map to
  * @gpio_offset: the start offset in the current gpio_chip number space
  * @pin_group: name of the pin group inside the pin controller
+ *
+ * Calling this function directly from a DeviceTree-supported
+ * pinctrl driver is DEPRECATED. Please see Section 2.1 of
+ * Documentation/devicetree/bindings/gpio/gpio.txt on how to
+ * bind pinctrl and gpio drivers via the "gpio-ranges" property.
  */
 int gpiochip_add_pingroup_range(struct gpio_chip *chip,
                        struct pinctrl_dev *pctldev,
@@ -2131,6 +2136,11 @@ EXPORT_SYMBOL_GPL(gpiochip_add_pingroup_range);
  *
  * Returns:
  * 0 on success, or a negative error-code on failure.
+ *
+ * Calling this function directly from a DeviceTree-supported
+ * pinctrl driver is DEPRECATED. Please see Section 2.1 of
+ * Documentation/devicetree/bindings/gpio/gpio.txt on how to
+ * bind pinctrl and gpio drivers via the "gpio-ranges" property.
  */
 int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
                           unsigned int gpio_offset, unsigned int pin_offset,
index 01fe8e0455a04766f6822b8361d5dc44dbc19886..dd50371225bcc74e9b58df691301f35c810594df 100644 (file)
@@ -337,6 +337,7 @@ config PINCTRL_OCELOT
        select GENERIC_PINMUX_FUNCTIONS
        select REGMAP_MMIO
 
+source "drivers/pinctrl/actions/Kconfig"
 source "drivers/pinctrl/aspeed/Kconfig"
 source "drivers/pinctrl/bcm/Kconfig"
 source "drivers/pinctrl/berlin/Kconfig"
index 657332b121fb79e1fdb7692f7c61f7ae30446f0d..de40863e729782b652c9d844b5c135726c439852 100644 (file)
@@ -43,6 +43,7 @@ obj-$(CONFIG_PINCTRL_INGENIC) += pinctrl-ingenic.o
 obj-$(CONFIG_PINCTRL_RK805)    += pinctrl-rk805.o
 obj-$(CONFIG_PINCTRL_OCELOT)   += pinctrl-ocelot.o
 
+obj-y                          += actions/
 obj-$(CONFIG_ARCH_ASPEED)      += aspeed/
 obj-y                          += bcm/
 obj-$(CONFIG_PINCTRL_BERLIN)   += berlin/
diff --git a/drivers/pinctrl/actions/Kconfig b/drivers/pinctrl/actions/Kconfig
new file mode 100644 (file)
index 0000000..490927b
--- /dev/null
@@ -0,0 +1,15 @@
+config PINCTRL_OWL
+       bool "Actions Semi OWL pinctrl driver"
+       depends on (ARCH_ACTIONS || COMPILE_TEST) && OF
+       select PINMUX
+       select PINCONF
+       select GENERIC_PINCONF
+       select GPIOLIB
+       help
+         Say Y here to enable Actions Semi OWL pinctrl driver
+
+config PINCTRL_S900
+       bool "Actions Semi S900 pinctrl driver"
+       depends on PINCTRL_OWL
+       help
+         Say Y here to enable Actions Semi S900 pinctrl driver
diff --git a/drivers/pinctrl/actions/Makefile b/drivers/pinctrl/actions/Makefile
new file mode 100644 (file)
index 0000000..bd232d2
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_PINCTRL_OWL)      += pinctrl-owl.o
+obj-$(CONFIG_PINCTRL_S900)     += pinctrl-s900.o
diff --git a/drivers/pinctrl/actions/pinctrl-owl.c b/drivers/pinctrl/actions/pinctrl-owl.c
new file mode 100644 (file)
index 0000000..76243ca
--- /dev/null
@@ -0,0 +1,785 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * OWL SoC's Pinctrl driver
+ *
+ * Copyright (c) 2014 Actions Semi Inc.
+ * Author: David Liu <liuwei@actions-semi.com>
+ *
+ * Copyright (c) 2018 Linaro Ltd.
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/gpio/driver.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "../core.h"
+#include "../pinctrl-utils.h"
+#include "pinctrl-owl.h"
+
+/**
+ * struct owl_pinctrl - pinctrl state of the device
+ * @dev: device handle
+ * @pctrldev: pinctrl handle
+ * @chip: gpio chip
+ * @lock: spinlock to protect registers
+ * @soc: reference to soc_data
+ * @base: pinctrl register base address
+ */
+struct owl_pinctrl {
+       struct device *dev;
+       struct pinctrl_dev *pctrldev;
+       struct gpio_chip chip;
+       raw_spinlock_t lock;
+       struct clk *clk;
+       const struct owl_pinctrl_soc_data *soc;
+       void __iomem *base;
+};
+
+static void owl_update_bits(void __iomem *base, u32 mask, u32 val)
+{
+       u32 reg_val;
+
+       reg_val = readl_relaxed(base);
+
+       reg_val = (reg_val & ~mask) | (val & mask);
+
+       writel_relaxed(reg_val, base);
+}
+
+static u32 owl_read_field(struct owl_pinctrl *pctrl, u32 reg,
+                               u32 bit, u32 width)
+{
+       u32 tmp, mask;
+
+       tmp = readl_relaxed(pctrl->base + reg);
+       mask = (1 << width) - 1;
+
+       return (tmp >> bit) & mask;
+}
+
+static void owl_write_field(struct owl_pinctrl *pctrl, u32 reg, u32 arg,
+                               u32 bit, u32 width)
+{
+       u32 mask;
+
+       mask = (1 << width) - 1;
+       mask = mask << bit;
+
+       owl_update_bits(pctrl->base + reg, mask, (arg << bit));
+}
+
+static int owl_get_groups_count(struct pinctrl_dev *pctrldev)
+{
+       struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+
+       return pctrl->soc->ngroups;
+}
+
+static const char *owl_get_group_name(struct pinctrl_dev *pctrldev,
+                               unsigned int group)
+{
+       struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+
+       return pctrl->soc->groups[group].name;
+}
+
+static int owl_get_group_pins(struct pinctrl_dev *pctrldev,
+                               unsigned int group,
+                               const unsigned int **pins,
+                               unsigned int *num_pins)
+{
+       struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+
+       *pins = pctrl->soc->groups[group].pads;
+       *num_pins = pctrl->soc->groups[group].npads;
+
+       return 0;
+}
+
+static void owl_pin_dbg_show(struct pinctrl_dev *pctrldev,
+                               struct seq_file *s,
+                               unsigned int offset)
+{
+       struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+
+       seq_printf(s, "%s", dev_name(pctrl->dev));
+}
+
+static struct pinctrl_ops owl_pinctrl_ops = {
+       .get_groups_count = owl_get_groups_count,
+       .get_group_name = owl_get_group_name,
+       .get_group_pins = owl_get_group_pins,
+       .pin_dbg_show = owl_pin_dbg_show,
+       .dt_node_to_map = pinconf_generic_dt_node_to_map_all,
+       .dt_free_map = pinctrl_utils_free_map,
+};
+
+static int owl_get_funcs_count(struct pinctrl_dev *pctrldev)
+{
+       struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+
+       return pctrl->soc->nfunctions;
+}
+
+static const char *owl_get_func_name(struct pinctrl_dev *pctrldev,
+                               unsigned int function)
+{
+       struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+
+       return pctrl->soc->functions[function].name;
+}
+
+static int owl_get_func_groups(struct pinctrl_dev *pctrldev,
+                               unsigned int function,
+                               const char * const **groups,
+                               unsigned int * const num_groups)
+{
+       struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+
+       *groups = pctrl->soc->functions[function].groups;
+       *num_groups = pctrl->soc->functions[function].ngroups;
+
+       return 0;
+}
+
+static inline int get_group_mfp_mask_val(const struct owl_pingroup *g,
+                               int function,
+                               u32 *mask,
+                               u32 *val)
+{
+       int id;
+       u32 option_num;
+       u32 option_mask;
+
+       for (id = 0; id < g->nfuncs; id++) {
+               if (g->funcs[id] == function)
+                       break;
+       }
+       if (WARN_ON(id == g->nfuncs))
+               return -EINVAL;
+
+       option_num = (1 << g->mfpctl_width);
+       if (id > option_num)
+               id -= option_num;
+
+       option_mask = option_num - 1;
+       *mask = (option_mask  << g->mfpctl_shift);
+       *val = (id << g->mfpctl_shift);
+
+       return 0;
+}
+
+static int owl_set_mux(struct pinctrl_dev *pctrldev,
+                               unsigned int function,
+                               unsigned int group)
+{
+       struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+       const struct owl_pingroup *g;
+       unsigned long flags;
+       u32 val, mask;
+
+       g = &pctrl->soc->groups[group];
+
+       if (get_group_mfp_mask_val(g, function, &mask, &val))
+               return -EINVAL;
+
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
+
+       owl_update_bits(pctrl->base + g->mfpctl_reg, mask, val);
+
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+
+       return 0;
+}
+
+static struct pinmux_ops owl_pinmux_ops = {
+       .get_functions_count = owl_get_funcs_count,
+       .get_function_name = owl_get_func_name,
+       .get_function_groups = owl_get_func_groups,
+       .set_mux = owl_set_mux,
+};
+
+static int owl_pad_pinconf_reg(const struct owl_padinfo *info,
+                               unsigned int param,
+                               u32 *reg,
+                               u32 *bit,
+                               u32 *width)
+{
+       switch (param) {
+       case PIN_CONFIG_BIAS_BUS_HOLD:
+       case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+       case PIN_CONFIG_BIAS_PULL_DOWN:
+       case PIN_CONFIG_BIAS_PULL_UP:
+               if (!info->pullctl)
+                       return -EINVAL;
+               *reg = info->pullctl->reg;
+               *bit = info->pullctl->shift;
+               *width = info->pullctl->width;
+               break;
+       case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+               if (!info->st)
+                       return -EINVAL;
+               *reg = info->st->reg;
+               *bit = info->st->shift;
+               *width = info->st->width;
+               break;
+       default:
+               return -ENOTSUPP;
+       }
+
+       return 0;
+}
+
+static int owl_pad_pinconf_arg2val(const struct owl_padinfo *info,
+                               unsigned int param,
+                               u32 *arg)
+{
+       switch (param) {
+       case PIN_CONFIG_BIAS_BUS_HOLD:
+               *arg = OWL_PINCONF_PULL_HOLD;
+               break;
+       case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+               *arg = OWL_PINCONF_PULL_HIZ;
+               break;
+       case PIN_CONFIG_BIAS_PULL_DOWN:
+               *arg = OWL_PINCONF_PULL_DOWN;
+               break;
+       case PIN_CONFIG_BIAS_PULL_UP:
+               *arg = OWL_PINCONF_PULL_UP;
+               break;
+       case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+               *arg = (*arg >= 1 ? 1 : 0);
+               break;
+       default:
+               return -ENOTSUPP;
+       }
+
+       return 0;
+}
+
+static int owl_pad_pinconf_val2arg(const struct owl_padinfo *padinfo,
+                               unsigned int param,
+                               u32 *arg)
+{
+       switch (param) {
+       case PIN_CONFIG_BIAS_BUS_HOLD:
+               *arg = *arg == OWL_PINCONF_PULL_HOLD;
+               break;
+       case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+               *arg = *arg == OWL_PINCONF_PULL_HIZ;
+               break;
+       case PIN_CONFIG_BIAS_PULL_DOWN:
+               *arg = *arg == OWL_PINCONF_PULL_DOWN;
+               break;
+       case PIN_CONFIG_BIAS_PULL_UP:
+               *arg = *arg == OWL_PINCONF_PULL_UP;
+               break;
+       case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+               *arg = *arg == 1;
+               break;
+       default:
+               return -ENOTSUPP;
+       }
+
+       return 0;
+}
+
+static int owl_pin_config_get(struct pinctrl_dev *pctrldev,
+                               unsigned int pin,
+                               unsigned long *config)
+{
+       int ret = 0;
+       struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+       const struct owl_padinfo *info;
+       unsigned int param = pinconf_to_config_param(*config);
+       u32 reg, bit, width, arg;
+
+       info = &pctrl->soc->padinfo[pin];
+
+       ret = owl_pad_pinconf_reg(info, param, &reg, &bit, &width);
+       if (ret)
+               return ret;
+
+       arg = owl_read_field(pctrl, reg, bit, width);
+
+       ret = owl_pad_pinconf_val2arg(info, param, &arg);
+       if (ret)
+               return ret;
+
+       *config = pinconf_to_config_packed(param, arg);
+
+       return ret;
+}
+
+static int owl_pin_config_set(struct pinctrl_dev *pctrldev,
+                               unsigned int pin,
+                               unsigned long *configs,
+                               unsigned int num_configs)
+{
+       struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+       const struct owl_padinfo *info;
+       unsigned long flags;
+       unsigned int param;
+       u32 reg, bit, width, arg;
+       int ret, i;
+
+       info = &pctrl->soc->padinfo[pin];
+
+       for (i = 0; i < num_configs; i++) {
+               param = pinconf_to_config_param(configs[i]);
+               arg = pinconf_to_config_argument(configs[i]);
+
+               ret = owl_pad_pinconf_reg(info, param, &reg, &bit, &width);
+               if (ret)
+                       return ret;
+
+               ret = owl_pad_pinconf_arg2val(info, param, &arg);
+               if (ret)
+                       return ret;
+
+               raw_spin_lock_irqsave(&pctrl->lock, flags);
+
+               owl_write_field(pctrl, reg, arg, bit, width);
+
+               raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       }
+
+       return ret;
+}
+
+static int owl_group_pinconf_reg(const struct owl_pingroup *g,
+                               unsigned int param,
+                               u32 *reg,
+                               u32 *bit,
+                               u32 *width)
+{
+       switch (param) {
+       case PIN_CONFIG_DRIVE_STRENGTH:
+               if (g->drv_reg < 0)
+                       return -EINVAL;
+               *reg = g->drv_reg;
+               *bit = g->drv_shift;
+               *width = g->drv_width;
+               break;
+       case PIN_CONFIG_SLEW_RATE:
+               if (g->sr_reg < 0)
+                       return -EINVAL;
+               *reg = g->sr_reg;
+               *bit = g->sr_shift;
+               *width = g->sr_width;
+               break;
+       default:
+               return -ENOTSUPP;
+       }
+
+       return 0;
+}
+
+static int owl_group_pinconf_arg2val(const struct owl_pingroup *g,
+                               unsigned int param,
+                               u32 *arg)
+{
+       switch (param) {
+       case PIN_CONFIG_DRIVE_STRENGTH:
+               switch (*arg) {
+               case 2:
+                       *arg = OWL_PINCONF_DRV_2MA;
+                       break;
+               case 4:
+                       *arg = OWL_PINCONF_DRV_4MA;
+                       break;
+               case 8:
+                       *arg = OWL_PINCONF_DRV_8MA;
+                       break;
+               case 12:
+                       *arg = OWL_PINCONF_DRV_12MA;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case PIN_CONFIG_SLEW_RATE:
+               if (*arg)
+                       *arg = OWL_PINCONF_SLEW_FAST;
+               else
+                       *arg = OWL_PINCONF_SLEW_SLOW;
+               break;
+       default:
+               return -ENOTSUPP;
+       }
+
+       return 0;
+}
+
+static int owl_group_pinconf_val2arg(const struct owl_pingroup *g,
+                               unsigned int param,
+                               u32 *arg)
+{
+       switch (param) {
+       case PIN_CONFIG_DRIVE_STRENGTH:
+               switch (*arg) {
+               case OWL_PINCONF_DRV_2MA:
+                       *arg = 2;
+                       break;
+               case OWL_PINCONF_DRV_4MA:
+                       *arg = 4;
+                       break;
+               case OWL_PINCONF_DRV_8MA:
+                       *arg = 8;
+                       break;
+               case OWL_PINCONF_DRV_12MA:
+                       *arg = 12;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case PIN_CONFIG_SLEW_RATE:
+               if (*arg)
+                       *arg = 1;
+               else
+                       *arg = 0;
+               break;
+       default:
+               return -ENOTSUPP;
+       }
+
+       return 0;
+}
+
+static int owl_group_config_get(struct pinctrl_dev *pctrldev,
+                               unsigned int group,
+                               unsigned long *config)
+{
+       const struct owl_pingroup *g;
+       struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+       unsigned int param = pinconf_to_config_param(*config);
+       u32 reg, bit, width, arg;
+       int ret;
+
+       g = &pctrl->soc->groups[group];
+
+       ret = owl_group_pinconf_reg(g, param, &reg, &bit, &width);
+       if (ret)
+               return ret;
+
+       arg = owl_read_field(pctrl, reg, bit, width);
+
+       ret = owl_group_pinconf_val2arg(g, param, &arg);
+       if (ret)
+               return ret;
+
+       *config = pinconf_to_config_packed(param, arg);
+
+       return ret;
+
+}
+
+static int owl_group_config_set(struct pinctrl_dev *pctrldev,
+                               unsigned int group,
+                               unsigned long *configs,
+                               unsigned int num_configs)
+{
+       const struct owl_pingroup *g;
+       struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+       unsigned long flags;
+       unsigned int param;
+       u32 reg, bit, width, arg;
+       int ret, i;
+
+       g = &pctrl->soc->groups[group];
+
+       for (i = 0; i < num_configs; i++) {
+               param = pinconf_to_config_param(configs[i]);
+               arg = pinconf_to_config_argument(configs[i]);
+
+               ret = owl_group_pinconf_reg(g, param, &reg, &bit, &width);
+               if (ret)
+                       return ret;
+
+               ret = owl_group_pinconf_arg2val(g, param, &arg);
+               if (ret)
+                       return ret;
+
+               /* Update register */
+               raw_spin_lock_irqsave(&pctrl->lock, flags);
+
+               owl_write_field(pctrl, reg, arg, bit, width);
+
+               raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+       }
+
+       return 0;
+}
+
+static const struct pinconf_ops owl_pinconf_ops = {
+       .is_generic = true,
+       .pin_config_get = owl_pin_config_get,
+       .pin_config_set = owl_pin_config_set,
+       .pin_config_group_get = owl_group_config_get,
+       .pin_config_group_set = owl_group_config_set,
+};
+
+static struct pinctrl_desc owl_pinctrl_desc = {
+       .pctlops = &owl_pinctrl_ops,
+       .pmxops = &owl_pinmux_ops,
+       .confops = &owl_pinconf_ops,
+       .owner = THIS_MODULE,
+};
+
+static const struct owl_gpio_port *
+owl_gpio_get_port(struct owl_pinctrl *pctrl, unsigned int *pin)
+{
+       unsigned int start = 0, i;
+
+       for (i = 0; i < pctrl->soc->nports; i++) {
+               const struct owl_gpio_port *port = &pctrl->soc->ports[i];
+
+               if (*pin >= start && *pin < start + port->pins) {
+                       *pin -= start;
+                       return port;
+               }
+
+               start += port->pins;
+       }
+
+       return NULL;
+}
+
+static void owl_gpio_update_reg(void __iomem *base, unsigned int pin, int flag)
+{
+       u32 val;
+
+       val = readl_relaxed(base);
+
+       if (flag)
+               val |= BIT(pin);
+       else
+               val &= ~BIT(pin);
+
+       writel_relaxed(val, base);
+}
+
+static int owl_gpio_request(struct gpio_chip *chip, unsigned int offset)
+{
+       struct owl_pinctrl *pctrl = gpiochip_get_data(chip);
+       const struct owl_gpio_port *port;
+       void __iomem *gpio_base;
+       unsigned long flags;
+
+       port = owl_gpio_get_port(pctrl, &offset);
+       if (WARN_ON(port == NULL))
+               return -ENODEV;
+
+       gpio_base = pctrl->base + port->offset;
+
+       /*
+        * GPIOs have higher priority over other modules, so either setting
+        * them as OUT or IN is sufficient
+        */
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       owl_gpio_update_reg(gpio_base + port->outen, offset, true);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+
+       return 0;
+}
+
+static void owl_gpio_free(struct gpio_chip *chip, unsigned int offset)
+{
+       struct owl_pinctrl *pctrl = gpiochip_get_data(chip);
+       const struct owl_gpio_port *port;
+       void __iomem *gpio_base;
+       unsigned long flags;
+
+       port = owl_gpio_get_port(pctrl, &offset);
+       if (WARN_ON(port == NULL))
+               return;
+
+       gpio_base = pctrl->base + port->offset;
+
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       /* disable gpio output */
+       owl_gpio_update_reg(gpio_base + port->outen, offset, false);
+
+       /* disable gpio input */
+       owl_gpio_update_reg(gpio_base + port->inen, offset, false);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+}
+
+static int owl_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+       struct owl_pinctrl *pctrl = gpiochip_get_data(chip);
+       const struct owl_gpio_port *port;
+       void __iomem *gpio_base;
+       unsigned long flags;
+       u32 val;
+
+       port = owl_gpio_get_port(pctrl, &offset);
+       if (WARN_ON(port == NULL))
+               return -ENODEV;
+
+       gpio_base = pctrl->base + port->offset;
+
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       val = readl_relaxed(gpio_base + port->dat);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+
+       return !!(val & BIT(offset));
+}
+
+static void owl_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
+{
+       struct owl_pinctrl *pctrl = gpiochip_get_data(chip);
+       const struct owl_gpio_port *port;
+       void __iomem *gpio_base;
+       unsigned long flags;
+
+       port = owl_gpio_get_port(pctrl, &offset);
+       if (WARN_ON(port == NULL))
+               return;
+
+       gpio_base = pctrl->base + port->offset;
+
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       owl_gpio_update_reg(gpio_base + port->dat, offset, value);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+}
+
+static int owl_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
+{
+       struct owl_pinctrl *pctrl = gpiochip_get_data(chip);
+       const struct owl_gpio_port *port;
+       void __iomem *gpio_base;
+       unsigned long flags;
+
+       port = owl_gpio_get_port(pctrl, &offset);
+       if (WARN_ON(port == NULL))
+               return -ENODEV;
+
+       gpio_base = pctrl->base + port->offset;
+
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       owl_gpio_update_reg(gpio_base + port->outen, offset, false);
+       owl_gpio_update_reg(gpio_base + port->inen, offset, true);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+
+       return 0;
+}
+
+static int owl_gpio_direction_output(struct gpio_chip *chip,
+                               unsigned int offset, int value)
+{
+       struct owl_pinctrl *pctrl = gpiochip_get_data(chip);
+       const struct owl_gpio_port *port;
+       void __iomem *gpio_base;
+       unsigned long flags;
+
+       port = owl_gpio_get_port(pctrl, &offset);
+       if (WARN_ON(port == NULL))
+               return -ENODEV;
+
+       gpio_base = pctrl->base + port->offset;
+
+       raw_spin_lock_irqsave(&pctrl->lock, flags);
+       owl_gpio_update_reg(gpio_base + port->inen, offset, false);
+       owl_gpio_update_reg(gpio_base + port->outen, offset, true);
+       owl_gpio_update_reg(gpio_base + port->dat, offset, value);
+       raw_spin_unlock_irqrestore(&pctrl->lock, flags);
+
+       return 0;
+}
+
+static int owl_gpio_init(struct owl_pinctrl *pctrl)
+{
+       struct gpio_chip *chip;
+       int ret;
+
+       chip = &pctrl->chip;
+       chip->base = -1;
+       chip->ngpio = pctrl->soc->ngpios;
+       chip->label = dev_name(pctrl->dev);
+       chip->parent = pctrl->dev;
+       chip->owner = THIS_MODULE;
+       chip->of_node = pctrl->dev->of_node;
+
+       ret = gpiochip_add_data(&pctrl->chip, pctrl);
+       if (ret) {
+               dev_err(pctrl->dev, "failed to register gpiochip\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+int owl_pinctrl_probe(struct platform_device *pdev,
+                               struct owl_pinctrl_soc_data *soc_data)
+{
+       struct resource *res;
+       struct owl_pinctrl *pctrl;
+       int ret;
+
+       pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
+       if (!pctrl)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       pctrl->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(pctrl->base))
+               return PTR_ERR(pctrl->base);
+
+       /* enable GPIO/MFP clock */
+       pctrl->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(pctrl->clk)) {
+               dev_err(&pdev->dev, "no clock defined\n");
+               return PTR_ERR(pctrl->clk);
+       }
+
+       ret = clk_prepare_enable(pctrl->clk);
+       if (ret) {
+               dev_err(&pdev->dev, "clk enable failed\n");
+               return ret;
+       }
+
+       raw_spin_lock_init(&pctrl->lock);
+
+       owl_pinctrl_desc.name = dev_name(&pdev->dev);
+       owl_pinctrl_desc.pins = soc_data->pins;
+       owl_pinctrl_desc.npins = soc_data->npins;
+
+       pctrl->chip.direction_input  = owl_gpio_direction_input;
+       pctrl->chip.direction_output = owl_gpio_direction_output;
+       pctrl->chip.get = owl_gpio_get;
+       pctrl->chip.set = owl_gpio_set;
+       pctrl->chip.request = owl_gpio_request;
+       pctrl->chip.free = owl_gpio_free;
+
+       pctrl->soc = soc_data;
+       pctrl->dev = &pdev->dev;
+
+       pctrl->pctrldev = devm_pinctrl_register(&pdev->dev,
+                                       &owl_pinctrl_desc, pctrl);
+       if (IS_ERR(pctrl->pctrldev)) {
+               dev_err(&pdev->dev, "could not register Actions OWL pinmux driver\n");
+               return PTR_ERR(pctrl->pctrldev);
+       }
+
+       ret = owl_gpio_init(pctrl);
+       if (ret)
+               return ret;
+
+       platform_set_drvdata(pdev, pctrl);
+
+       return 0;
+}
diff --git a/drivers/pinctrl/actions/pinctrl-owl.h b/drivers/pinctrl/actions/pinctrl-owl.h
new file mode 100644 (file)
index 0000000..7434237
--- /dev/null
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * OWL SoC's Pinctrl definitions
+ *
+ * Copyright (c) 2014 Actions Semi Inc.
+ * Author: David Liu <liuwei@actions-semi.com>
+ *
+ * Copyright (c) 2018 Linaro Ltd.
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ */
+
+#ifndef __PINCTRL_OWL_H__
+#define __PINCTRL_OWL_H__
+
+#define OWL_PINCONF_SLEW_SLOW 0
+#define OWL_PINCONF_SLEW_FAST 1
+
+enum owl_pinconf_pull {
+       OWL_PINCONF_PULL_HIZ,
+       OWL_PINCONF_PULL_DOWN,
+       OWL_PINCONF_PULL_UP,
+       OWL_PINCONF_PULL_HOLD,
+};
+
+enum owl_pinconf_drv {
+       OWL_PINCONF_DRV_2MA,
+       OWL_PINCONF_DRV_4MA,
+       OWL_PINCONF_DRV_8MA,
+       OWL_PINCONF_DRV_12MA,
+};
+
+/**
+ * struct owl_pullctl - Actions pad pull control register
+ * @reg: offset to the pull control register
+ * @shift: shift value of the register
+ * @width: width of the register
+ */
+struct owl_pullctl {
+       int reg;
+       unsigned int shift;
+       unsigned int width;
+};
+
+/**
+ * struct owl_st - Actions pad schmitt trigger enable register
+ * @reg: offset to the schmitt trigger enable register
+ * @shift: shift value of the register
+ * @width: width of the register
+ */
+struct owl_st {
+       int reg;
+       unsigned int shift;
+       unsigned int width;
+};
+
+/**
+ * struct owl_pingroup - Actions pingroup definition
+ * @name: name of the  pin group
+ * @pads: list of pins assigned to this pingroup
+ * @npads: size of @pads array
+ * @funcs: list of pinmux functions for this pingroup
+ * @nfuncs: size of @funcs array
+ * @mfpctl_reg: multiplexing control register offset
+ * @mfpctl_shift: multiplexing control register bit mask
+ * @mfpctl_width: multiplexing control register width
+ * @drv_reg: drive control register offset
+ * @drv_shift: drive control register bit mask
+ * @drv_width: driver control register width
+ * @sr_reg: slew rate control register offset
+ * @sr_shift: slew rate control register bit mask
+ * @sr_width: slew rate control register width
+ */
+struct owl_pingroup {
+       const char *name;
+       unsigned int *pads;
+       unsigned int npads;
+       unsigned int *funcs;
+       unsigned int nfuncs;
+
+       int mfpctl_reg;
+       unsigned int mfpctl_shift;
+       unsigned int mfpctl_width;
+
+       int drv_reg;
+       unsigned int drv_shift;
+       unsigned int drv_width;
+
+       int sr_reg;
+       unsigned int sr_shift;
+       unsigned int sr_width;
+};
+
+/**
+ * struct owl_padinfo - Actions pinctrl pad info
+ * @pad: pad name of the SoC
+ * @pullctl: pull control register info
+ * @st: schmitt trigger register info
+ */
+struct owl_padinfo {
+       int pad;
+       struct owl_pullctl *pullctl;
+       struct owl_st *st;
+};
+
+/**
+ * struct owl_pinmux_func - Actions pinctrl mux functions
+ * @name: name of the pinmux function.
+ * @groups: array of pin groups that may select this function.
+ * @ngroups: number of entries in @groups.
+ */
+struct owl_pinmux_func {
+       const char *name;
+       const char * const *groups;
+       unsigned int ngroups;
+};
+
+/**
+ * struct owl_gpio_port - Actions GPIO port info
+ * @offset: offset of the GPIO port.
+ * @pins: number of pins belongs to the GPIO port.
+ * @outen: offset of the output enable register.
+ * @inen: offset of the input enable register.
+ * @dat: offset of the data register.
+ */
+struct owl_gpio_port {
+       unsigned int offset;
+       unsigned int pins;
+       unsigned int outen;
+       unsigned int inen;
+       unsigned int dat;
+};
+
+/**
+ * struct owl_pinctrl_soc_data - Actions pin controller driver configuration
+ * @pins: array describing all pins of the pin controller.
+ * @npins: number of entries in @pins.
+ * @functions: array describing all mux functions of this SoC.
+ * @nfunction: number of entries in @functions.
+ * @groups: array describing all pin groups of this SoC.
+ * @ngroups: number of entries in @groups.
+ * @padinfo: array describing the pad info of this SoC.
+ * @ngpios: number of pingroups the driver should expose as GPIOs.
+ * @port: array describing all GPIO ports of this SoC.
+ * @nports: number of GPIO ports in this SoC.
+ */
+struct owl_pinctrl_soc_data {
+       const struct pinctrl_pin_desc *pins;
+       unsigned int npins;
+       const struct owl_pinmux_func *functions;
+       unsigned int nfunctions;
+       const struct owl_pingroup *groups;
+       unsigned int ngroups;
+       const struct owl_padinfo *padinfo;
+       unsigned int ngpios;
+       const struct owl_gpio_port *ports;
+       unsigned int nports;
+};
+
+int owl_pinctrl_probe(struct platform_device *pdev,
+               struct owl_pinctrl_soc_data *soc_data);
+
+#endif /* __PINCTRL_OWL_H__ */
diff --git a/drivers/pinctrl/actions/pinctrl-s900.c b/drivers/pinctrl/actions/pinctrl-s900.c
new file mode 100644 (file)
index 0000000..5503c79
--- /dev/null
@@ -0,0 +1,1888 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * OWL S900 Pinctrl driver
+ *
+ * Copyright (c) 2014 Actions Semi Inc.
+ * Author: David Liu <liuwei@actions-semi.com>
+ *
+ * Copyright (c) 2018 Linaro Ltd.
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include "pinctrl-owl.h"
+
+/* Pinctrl registers offset */
+#define MFCTL0                 (0x0040)
+#define MFCTL1                 (0x0044)
+#define MFCTL2                 (0x0048)
+#define MFCTL3                 (0x004C)
+#define PAD_PULLCTL0           (0x0060)
+#define PAD_PULLCTL1           (0x0064)
+#define PAD_PULLCTL2           (0x0068)
+#define PAD_ST0                        (0x006C)
+#define PAD_ST1                        (0x0070)
+#define PAD_CTL                        (0x0074)
+#define PAD_DRV0               (0x0080)
+#define PAD_DRV1               (0x0084)
+#define PAD_DRV2               (0x0088)
+#define PAD_SR0                        (0x0270)
+#define PAD_SR1                        (0x0274)
+#define PAD_SR2                        (0x0278)
+
+#define OWL_GPIO_PORT_A                0
+#define OWL_GPIO_PORT_B                1
+#define OWL_GPIO_PORT_C                2
+#define OWL_GPIO_PORT_D                3
+#define OWL_GPIO_PORT_E                4
+#define OWL_GPIO_PORT_F                5
+
+#define _GPIOA(offset)         (offset)
+#define _GPIOB(offset)         (32 + (offset))
+#define _GPIOC(offset)         (64 + (offset))
+#define _GPIOD(offset)         (76 + (offset))
+#define _GPIOE(offset)         (106 + (offset))
+#define _GPIOF(offset)         (138 + (offset))
+
+#define NUM_GPIOS              (_GPIOF(7) + 1)
+#define _PIN(offset)           (NUM_GPIOS + (offset))
+
+#define ETH_TXD0               _GPIOA(0)
+#define ETH_TXD1               _GPIOA(1)
+#define ETH_TXEN               _GPIOA(2)
+#define ETH_RXER               _GPIOA(3)
+#define ETH_CRS_DV             _GPIOA(4)
+#define ETH_RXD1               _GPIOA(5)
+#define ETH_RXD0               _GPIOA(6)
+#define ETH_REF_CLK            _GPIOA(7)
+#define ETH_MDC                        _GPIOA(8)
+#define ETH_MDIO               _GPIOA(9)
+#define SIRQ0                  _GPIOA(10)
+#define SIRQ1                  _GPIOA(11)
+#define SIRQ2                  _GPIOA(12)
+#define I2S_D0                 _GPIOA(13)
+#define I2S_BCLK0              _GPIOA(14)
+#define I2S_LRCLK0             _GPIOA(15)
+#define I2S_MCLK0              _GPIOA(16)
+#define I2S_D1                 _GPIOA(17)
+#define I2S_BCLK1              _GPIOA(18)
+#define I2S_LRCLK1             _GPIOA(19)
+#define I2S_MCLK1              _GPIOA(20)
+#define ERAM_A5                        _GPIOA(21)
+#define ERAM_A6                        _GPIOA(22)
+#define ERAM_A7                        _GPIOA(23)
+#define ERAM_A8                        _GPIOA(24)
+#define ERAM_A9                        _GPIOA(25)
+#define ERAM_A10               _GPIOA(26)
+#define ERAM_A11               _GPIOA(27)
+#define SD0_D0                 _GPIOA(28)
+#define SD0_D1                 _GPIOA(29)
+#define SD0_D2                 _GPIOA(30)
+#define SD0_D3                 _GPIOA(31)
+
+#define SD1_D0                 _GPIOB(0)
+#define SD1_D1                 _GPIOB(1)
+#define SD1_D2                 _GPIOB(2)
+#define SD1_D3                 _GPIOB(3)
+#define SD0_CMD                        _GPIOB(4)
+#define SD0_CLK                        _GPIOB(5)
+#define SD1_CMD                        _GPIOB(6)
+#define SD1_CLK                        _GPIOB(7)
+#define SPI0_SCLK              _GPIOB(8)
+#define SPI0_SS                        _GPIOB(9)
+#define SPI0_MISO              _GPIOB(10)
+#define SPI0_MOSI              _GPIOB(11)
+#define UART0_RX               _GPIOB(12)
+#define UART0_TX               _GPIOB(13)
+#define UART2_RX               _GPIOB(14)
+#define UART2_TX               _GPIOB(15)
+#define UART2_RTSB             _GPIOB(16)
+#define UART2_CTSB             _GPIOB(17)
+#define UART4_RX               _GPIOB(18)
+#define UART4_TX               _GPIOB(19)
+#define I2C0_SCLK              _GPIOB(20)
+#define I2C0_SDATA             _GPIOB(21)
+#define I2C1_SCLK              _GPIOB(22)
+#define I2C1_SDATA             _GPIOB(23)
+#define I2C2_SCLK              _GPIOB(24)
+#define I2C2_SDATA             _GPIOB(25)
+#define CSI0_DN0               _GPIOB(26)
+#define CSI0_DP0               _GPIOB(27)
+#define CSI0_DN1               _GPIOB(28)
+#define CSI0_DP1               _GPIOB(29)
+#define CSI0_CN                        _GPIOB(30)
+#define CSI0_CP                        _GPIOB(31)
+
+#define CSI0_DN2               _GPIOC(0)
+#define CSI0_DP2               _GPIOC(1)
+#define CSI0_DN3               _GPIOC(2)
+#define CSI0_DP3               _GPIOC(3)
+#define SENSOR0_PCLK           _GPIOC(4)
+#define CSI1_DN0               _GPIOC(5)
+#define CSI1_DP0               _GPIOC(6)
+#define CSI1_DN1               _GPIOC(7)
+#define CSI1_DP1               _GPIOC(8)
+#define CSI1_CN                        _GPIOC(9)
+#define CSI1_CP                        _GPIOC(10)
+#define SENSOR0_CKOUT          _GPIOC(11)
+
+#define LVDS_OEP               _GPIOD(0)
+#define LVDS_OEN               _GPIOD(1)
+#define LVDS_ODP               _GPIOD(2)
+#define LVDS_ODN               _GPIOD(3)
+#define LVDS_OCP               _GPIOD(4)
+#define LVDS_OCN               _GPIOD(5)
+#define LVDS_OBP               _GPIOD(6)
+#define LVDS_OBN               _GPIOD(7)
+#define LVDS_OAP               _GPIOD(8)
+#define LVDS_OAN               _GPIOD(9)
+#define LVDS_EEP               _GPIOD(10)
+#define LVDS_EEN               _GPIOD(11)
+#define LVDS_EDP               _GPIOD(12)
+#define LVDS_EDN               _GPIOD(13)
+#define LVDS_ECP               _GPIOD(14)
+#define LVDS_ECN               _GPIOD(15)
+#define LVDS_EBP               _GPIOD(16)
+#define LVDS_EBN               _GPIOD(17)
+#define LVDS_EAP               _GPIOD(18)
+#define LVDS_EAN               _GPIOD(19)
+#define DSI_DP3                        _GPIOD(20)
+#define DSI_DN3                        _GPIOD(21)
+#define DSI_DP1                        _GPIOD(22)
+#define DSI_DN1                        _GPIOD(23)
+#define DSI_CP                 _GPIOD(24)
+#define DSI_CN                 _GPIOD(25)
+#define DSI_DP0                        _GPIOD(26)
+#define DSI_DN0                        _GPIOD(27)
+#define DSI_DP2                        _GPIOD(28)
+#define DSI_DN2                        _GPIOD(29)
+
+#define NAND0_D0               _GPIOE(0)
+#define NAND0_D1               _GPIOE(1)
+#define NAND0_D2               _GPIOE(2)
+#define NAND0_D3               _GPIOE(3)
+#define NAND0_D4               _GPIOE(4)
+#define NAND0_D5               _GPIOE(5)
+#define NAND0_D6               _GPIOE(6)
+#define NAND0_D7               _GPIOE(7)
+#define NAND0_DQS              _GPIOE(8)
+#define NAND0_DQSN             _GPIOE(9)
+#define NAND0_ALE              _GPIOE(10)
+#define NAND0_CLE              _GPIOE(11)
+#define NAND0_CEB0             _GPIOE(12)
+#define NAND0_CEB1             _GPIOE(13)
+#define NAND0_CEB2             _GPIOE(14)
+#define NAND0_CEB3             _GPIOE(15)
+#define NAND1_D0               _GPIOE(16)
+#define NAND1_D1               _GPIOE(17)
+#define NAND1_D2               _GPIOE(18)
+#define NAND1_D3               _GPIOE(19)
+#define NAND1_D4               _GPIOE(20)
+#define NAND1_D5               _GPIOE(21)
+#define NAND1_D6               _GPIOE(22)
+#define NAND1_D7               _GPIOE(23)
+#define NAND1_DQS              _GPIOE(24)
+#define NAND1_DQSN             _GPIOE(25)
+#define NAND1_ALE              _GPIOE(26)
+#define NAND1_CLE              _GPIOE(27)
+#define NAND1_CEB0             _GPIOE(28)
+#define NAND1_CEB1             _GPIOE(29)
+#define NAND1_CEB2             _GPIOE(30)
+#define NAND1_CEB3             _GPIOE(31)
+
+#define PCM1_IN                        _GPIOF(0)
+#define PCM1_CLK               _GPIOF(1)
+#define PCM1_SYNC              _GPIOF(2)
+#define PCM1_OUT               _GPIOF(3)
+#define UART3_RX               _GPIOF(4)
+#define UART3_TX               _GPIOF(5)
+#define UART3_RTSB             _GPIOF(6)
+#define UART3_CTSB             _GPIOF(7)
+
+/* System */
+#define SGPIO0                 _PIN(0)
+#define SGPIO1                 _PIN(1)
+#define SGPIO2                 _PIN(2)
+#define SGPIO3                 _PIN(3)
+
+#define NUM_PADS               (_PIN(3) + 1)
+
+/* Pad names as specified in datasheet */
+static const struct pinctrl_pin_desc s900_pads[] = {
+       PINCTRL_PIN(ETH_TXD0, "eth_txd0"),
+       PINCTRL_PIN(ETH_TXD1, "eth_txd1"),
+       PINCTRL_PIN(ETH_TXEN, "eth_txen"),
+       PINCTRL_PIN(ETH_RXER, "eth_rxer"),
+       PINCTRL_PIN(ETH_CRS_DV, "eth_crs_dv"),
+       PINCTRL_PIN(ETH_RXD1, "eth_rxd1"),
+       PINCTRL_PIN(ETH_RXD0, "eth_rxd0"),
+       PINCTRL_PIN(ETH_REF_CLK, "eth_ref_clk"),
+       PINCTRL_PIN(ETH_MDC, "eth_mdc"),
+       PINCTRL_PIN(ETH_MDIO, "eth_mdio"),
+       PINCTRL_PIN(SIRQ0, "sirq0"),
+       PINCTRL_PIN(SIRQ1, "sirq1"),
+       PINCTRL_PIN(SIRQ2, "sirq2"),
+       PINCTRL_PIN(I2S_D0, "i2s_d0"),
+       PINCTRL_PIN(I2S_BCLK0, "i2s_bclk0"),
+       PINCTRL_PIN(I2S_LRCLK0, "i2s_lrclk0"),
+       PINCTRL_PIN(I2S_MCLK0, "i2s_mclk0"),
+       PINCTRL_PIN(I2S_D1, "i2s_d1"),
+       PINCTRL_PIN(I2S_BCLK1, "i2s_bclk1"),
+       PINCTRL_PIN(I2S_LRCLK1, "i2s_lrclk1"),
+       PINCTRL_PIN(I2S_MCLK1, "i2s_mclk1"),
+       PINCTRL_PIN(PCM1_IN, "pcm1_in"),
+       PINCTRL_PIN(PCM1_CLK, "pcm1_clk"),
+       PINCTRL_PIN(PCM1_SYNC, "pcm1_sync"),
+       PINCTRL_PIN(PCM1_OUT, "pcm1_out"),
+       PINCTRL_PIN(ERAM_A5, "eram_a5"),
+       PINCTRL_PIN(ERAM_A6, "eram_a6"),
+       PINCTRL_PIN(ERAM_A7, "eram_a7"),
+       PINCTRL_PIN(ERAM_A8, "eram_a8"),
+       PINCTRL_PIN(ERAM_A9, "eram_a9"),
+       PINCTRL_PIN(ERAM_A10, "eram_a10"),
+       PINCTRL_PIN(ERAM_A11, "eram_a11"),
+       PINCTRL_PIN(LVDS_OEP, "lvds_oep"),
+       PINCTRL_PIN(LVDS_OEN, "lvds_oen"),
+       PINCTRL_PIN(LVDS_ODP, "lvds_odp"),
+       PINCTRL_PIN(LVDS_ODN, "lvds_odn"),
+       PINCTRL_PIN(LVDS_OCP, "lvds_ocp"),
+       PINCTRL_PIN(LVDS_OCN, "lvds_ocn"),
+       PINCTRL_PIN(LVDS_OBP, "lvds_obp"),
+       PINCTRL_PIN(LVDS_OBN, "lvds_obn"),
+       PINCTRL_PIN(LVDS_OAP, "lvds_oap"),
+       PINCTRL_PIN(LVDS_OAN, "lvds_oan"),
+       PINCTRL_PIN(LVDS_EEP, "lvds_eep"),
+       PINCTRL_PIN(LVDS_EEN, "lvds_een"),
+       PINCTRL_PIN(LVDS_EDP, "lvds_edp"),
+       PINCTRL_PIN(LVDS_EDN, "lvds_edn"),
+       PINCTRL_PIN(LVDS_ECP, "lvds_ecp"),
+       PINCTRL_PIN(LVDS_ECN, "lvds_ecn"),
+       PINCTRL_PIN(LVDS_EBP, "lvds_ebp"),
+       PINCTRL_PIN(LVDS_EBN, "lvds_ebn"),
+       PINCTRL_PIN(LVDS_EAP, "lvds_eap"),
+       PINCTRL_PIN(LVDS_EAN, "lvds_ean"),
+       PINCTRL_PIN(SD0_D0, "sd0_d0"),
+       PINCTRL_PIN(SD0_D1, "sd0_d1"),
+       PINCTRL_PIN(SD0_D2, "sd0_d2"),
+       PINCTRL_PIN(SD0_D3, "sd0_d3"),
+       PINCTRL_PIN(SD1_D0, "sd1_d0"),
+       PINCTRL_PIN(SD1_D1, "sd1_d1"),
+       PINCTRL_PIN(SD1_D2, "sd1_d2"),
+       PINCTRL_PIN(SD1_D3, "sd1_d3"),
+       PINCTRL_PIN(SD0_CMD, "sd0_cmd"),
+       PINCTRL_PIN(SD0_CLK, "sd0_clk"),
+       PINCTRL_PIN(SD1_CMD, "sd1_cmd"),
+       PINCTRL_PIN(SD1_CLK, "sd1_clk"),
+       PINCTRL_PIN(SPI0_SCLK, "spi0_sclk"),
+       PINCTRL_PIN(SPI0_SS, "spi0_ss"),
+       PINCTRL_PIN(SPI0_MISO, "spi0_miso"),
+       PINCTRL_PIN(SPI0_MOSI, "spi0_mosi"),
+       PINCTRL_PIN(UART0_RX, "uart0_rx"),
+       PINCTRL_PIN(UART0_TX, "uart0_tx"),
+       PINCTRL_PIN(UART2_RX, "uart2_rx"),
+       PINCTRL_PIN(UART2_TX, "uart2_tx"),
+       PINCTRL_PIN(UART2_RTSB, "uart2_rtsb"),
+       PINCTRL_PIN(UART2_CTSB, "uart2_ctsb"),
+       PINCTRL_PIN(UART3_RX, "uart3_rx"),
+       PINCTRL_PIN(UART3_TX, "uart3_tx"),
+       PINCTRL_PIN(UART3_RTSB, "uart3_rtsb"),
+       PINCTRL_PIN(UART3_CTSB, "uart3_ctsb"),
+       PINCTRL_PIN(UART4_RX, "uart4_rx"),
+       PINCTRL_PIN(UART4_TX, "uart4_tx"),
+       PINCTRL_PIN(I2C0_SCLK, "i2c0_sclk"),
+       PINCTRL_PIN(I2C0_SDATA, "i2c0_sdata"),
+       PINCTRL_PIN(I2C1_SCLK, "i2c1_sclk"),
+       PINCTRL_PIN(I2C1_SDATA, "i2c1_sdata"),
+       PINCTRL_PIN(I2C2_SCLK, "i2c2_sclk"),
+       PINCTRL_PIN(I2C2_SDATA, "i2c2_sdata"),
+       PINCTRL_PIN(CSI0_DN0, "csi0_dn0"),
+       PINCTRL_PIN(CSI0_DP0, "csi0_dp0"),
+       PINCTRL_PIN(CSI0_DN1, "csi0_dn1"),
+       PINCTRL_PIN(CSI0_DP1, "csi0_dp1"),
+       PINCTRL_PIN(CSI0_CN, "csi0_cn"),
+       PINCTRL_PIN(CSI0_CP, "csi0_cp"),
+       PINCTRL_PIN(CSI0_DN2, "csi0_dn2"),
+       PINCTRL_PIN(CSI0_DP2, "csi0_dp2"),
+       PINCTRL_PIN(CSI0_DN3, "csi0_dn3"),
+       PINCTRL_PIN(CSI0_DP3, "csi0_dp3"),
+       PINCTRL_PIN(DSI_DP3, "dsi_dp3"),
+       PINCTRL_PIN(DSI_DN3, "dsi_dn3"),
+       PINCTRL_PIN(DSI_DP1, "dsi_dp1"),
+       PINCTRL_PIN(DSI_DN1, "dsi_dn1"),
+       PINCTRL_PIN(DSI_CP, "dsi_cp"),
+       PINCTRL_PIN(DSI_CN, "dsi_cn"),
+       PINCTRL_PIN(DSI_DP0, "dsi_dp0"),
+       PINCTRL_PIN(DSI_DN0, "dsi_dn0"),
+       PINCTRL_PIN(DSI_DP2, "dsi_dp2"),
+       PINCTRL_PIN(DSI_DN2, "dsi_dn2"),
+       PINCTRL_PIN(SENSOR0_PCLK, "sensor0_pclk"),
+       PINCTRL_PIN(CSI1_DN0, "csi1_dn0"),
+       PINCTRL_PIN(CSI1_DP0, "csi1_dp0"),
+       PINCTRL_PIN(CSI1_DN1, "csi1_dn1"),
+       PINCTRL_PIN(CSI1_DP1, "csi1_dp1"),
+       PINCTRL_PIN(CSI1_CN, "csi1_cn"),
+       PINCTRL_PIN(CSI1_CP, "csi1_cp"),
+       PINCTRL_PIN(SENSOR0_CKOUT, "sensor0_ckout"),
+       PINCTRL_PIN(NAND0_D0, "nand0_d0"),
+       PINCTRL_PIN(NAND0_D1, "nand0_d1"),
+       PINCTRL_PIN(NAND0_D2, "nand0_d2"),
+       PINCTRL_PIN(NAND0_D3, "nand0_d3"),
+       PINCTRL_PIN(NAND0_D4, "nand0_d4"),
+       PINCTRL_PIN(NAND0_D5, "nand0_d5"),
+       PINCTRL_PIN(NAND0_D6, "nand0_d6"),
+       PINCTRL_PIN(NAND0_D7, "nand0_d7"),
+       PINCTRL_PIN(NAND0_DQS, "nand0_dqs"),
+       PINCTRL_PIN(NAND0_DQSN, "nand0_dqsn"),
+       PINCTRL_PIN(NAND0_ALE, "nand0_ale"),
+       PINCTRL_PIN(NAND0_CLE, "nand0_cle"),
+       PINCTRL_PIN(NAND0_CEB0, "nand0_ceb0"),
+       PINCTRL_PIN(NAND0_CEB1, "nand0_ceb1"),
+       PINCTRL_PIN(NAND0_CEB2, "nand0_ceb2"),
+       PINCTRL_PIN(NAND0_CEB3, "nand0_ceb3"),
+       PINCTRL_PIN(NAND1_D0, "nand1_d0"),
+       PINCTRL_PIN(NAND1_D1, "nand1_d1"),
+       PINCTRL_PIN(NAND1_D2, "nand1_d2"),
+       PINCTRL_PIN(NAND1_D3, "nand1_d3"),
+       PINCTRL_PIN(NAND1_D4, "nand1_d4"),
+       PINCTRL_PIN(NAND1_D5, "nand1_d5"),
+       PINCTRL_PIN(NAND1_D6, "nand1_d6"),
+       PINCTRL_PIN(NAND1_D7, "nand1_d7"),
+       PINCTRL_PIN(NAND1_DQS, "nand1_dqs"),
+       PINCTRL_PIN(NAND1_DQSN, "nand1_dqsn"),
+       PINCTRL_PIN(NAND1_ALE, "nand1_ale"),
+       PINCTRL_PIN(NAND1_CLE, "nand1_cle"),
+       PINCTRL_PIN(NAND1_CEB0, "nand1_ceb0"),
+       PINCTRL_PIN(NAND1_CEB1, "nand1_ceb1"),
+       PINCTRL_PIN(NAND1_CEB2, "nand1_ceb2"),
+       PINCTRL_PIN(NAND1_CEB3, "nand1_ceb3"),
+       PINCTRL_PIN(SGPIO0, "sgpio0"),
+       PINCTRL_PIN(SGPIO1, "sgpio1"),
+       PINCTRL_PIN(SGPIO2, "sgpio2"),
+       PINCTRL_PIN(SGPIO3, "sgpio3")
+};
+
+enum s900_pinmux_functions {
+       S900_MUX_ERAM,
+       S900_MUX_ETH_RMII,
+       S900_MUX_ETH_SMII,
+       S900_MUX_SPI0,
+       S900_MUX_SPI1,
+       S900_MUX_SPI2,
+       S900_MUX_SPI3,
+       S900_MUX_SENS0,
+       S900_MUX_UART0,
+       S900_MUX_UART1,
+       S900_MUX_UART2,
+       S900_MUX_UART3,
+       S900_MUX_UART4,
+       S900_MUX_UART5,
+       S900_MUX_UART6,
+       S900_MUX_I2S0,
+       S900_MUX_I2S1,
+       S900_MUX_PCM0,
+       S900_MUX_PCM1,
+       S900_MUX_JTAG,
+       S900_MUX_PWM0,
+       S900_MUX_PWM1,
+       S900_MUX_PWM2,
+       S900_MUX_PWM3,
+       S900_MUX_PWM4,
+       S900_MUX_PWM5,
+       S900_MUX_SD0,
+       S900_MUX_SD1,
+       S900_MUX_SD2,
+       S900_MUX_SD3,
+       S900_MUX_I2C0,
+       S900_MUX_I2C1,
+       S900_MUX_I2C2,
+       S900_MUX_I2C3,
+       S900_MUX_I2C4,
+       S900_MUX_I2C5,
+       S900_MUX_LVDS,
+       S900_MUX_USB20,
+       S900_MUX_USB30,
+       S900_MUX_GPU,
+       S900_MUX_MIPI_CSI0,
+       S900_MUX_MIPI_CSI1,
+       S900_MUX_MIPI_DSI,
+       S900_MUX_NAND0,
+       S900_MUX_NAND1,
+       S900_MUX_SPDIF,
+       S900_MUX_SIRQ0,
+       S900_MUX_SIRQ1,
+       S900_MUX_SIRQ2,
+       S900_MUX_AUX_START,
+       S900_MUX_MAX,
+       S900_MUX_RESERVED
+};
+
+/* mfp0_22 */
+static unsigned int lvds_oxx_uart4_mfp_pads[]  = { LVDS_OAP, LVDS_OAN };
+static unsigned int lvds_oxx_uart4_mfp_funcs[] = { S900_MUX_ERAM,
+                                                   S900_MUX_UART4 };
+/* mfp0_21_20 */
+static unsigned int rmii_mdc_mfp_pads[]                = { ETH_MDC };
+static unsigned int rmii_mdc_mfp_funcs[]       = { S900_MUX_ETH_RMII,
+                                                   S900_MUX_PWM2,
+                                                   S900_MUX_UART2,
+                                                   S900_MUX_RESERVED };
+static unsigned int rmii_mdio_mfp_pads[]       = { ETH_MDIO };
+static unsigned int rmii_mdio_mfp_funcs[]      = { S900_MUX_ETH_RMII,
+                                                   S900_MUX_PWM3,
+                                                   S900_MUX_UART2,
+                                                   S900_MUX_RESERVED };
+/* mfp0_19 */
+static unsigned int sirq0_mfp_pads[]           = { SIRQ0 };
+static unsigned int sirq0_mfp_funcs[]          = { S900_MUX_SIRQ0,
+                                                   S900_MUX_PWM0 };
+static unsigned int sirq1_mfp_pads[]           = { SIRQ1 };
+static unsigned int sirq1_mfp_funcs[]          = { S900_MUX_SIRQ1,
+                                                   S900_MUX_PWM1 };
+/* mfp0_18_16 */
+static unsigned int rmii_txd0_mfp_pads[]       = { ETH_TXD0 };
+static unsigned int rmii_txd0_mfp_funcs[]      = { S900_MUX_ETH_RMII,
+                                                   S900_MUX_ETH_SMII,
+                                                   S900_MUX_SPI2,
+                                                   S900_MUX_UART6,
+                                                   S900_MUX_SENS0,
+                                                   S900_MUX_PWM0 };
+static unsigned int rmii_txd1_mfp_pads[]       = { ETH_TXD1 };
+static unsigned int rmii_txd1_mfp_funcs[]      = { S900_MUX_ETH_RMII,
+                                                   S900_MUX_ETH_SMII,
+                                                   S900_MUX_SPI2,
+                                                   S900_MUX_UART6,
+                                                   S900_MUX_SENS0,
+                                                   S900_MUX_PWM1 };
+/* mfp0_15_13 */
+static unsigned int rmii_txen_mfp_pads[]       = { ETH_TXEN };
+static unsigned int rmii_txen_mfp_funcs[]      = { S900_MUX_ETH_RMII,
+                                                   S900_MUX_UART2,
+                                                   S900_MUX_SPI3,
+                                                   S900_MUX_RESERVED,
+                                                   S900_MUX_RESERVED,
+                                                   S900_MUX_PWM2,
+                                                   S900_MUX_SENS0 };
+
+static unsigned int rmii_rxer_mfp_pads[]       = { ETH_RXER };
+static unsigned int rmii_rxer_mfp_funcs[]      = { S900_MUX_ETH_RMII,
+                                                   S900_MUX_UART2,
+                                                   S900_MUX_SPI3,
+                                                   S900_MUX_RESERVED,
+                                                   S900_MUX_RESERVED,
+                                                   S900_MUX_PWM3,
+                                                   S900_MUX_SENS0 };
+/* mfp0_12_11 */
+static unsigned int rmii_crs_dv_mfp_pads[]     = { ETH_CRS_DV };
+static unsigned int rmii_crs_dv_mfp_funcs[]    = { S900_MUX_ETH_RMII,
+                                                   S900_MUX_ETH_SMII,
+                                                   S900_MUX_SPI2,
+                                                   S900_MUX_UART4 };
+/* mfp0_10_8 */
+static unsigned int rmii_rxd1_mfp_pads[]       = { ETH_RXD1 };
+static unsigned int rmii_rxd1_mfp_funcs[]      = { S900_MUX_ETH_RMII,
+                                                   S900_MUX_UART2,
+                                                   S900_MUX_SPI3,
+                                                   S900_MUX_RESERVED,
+                                                   S900_MUX_UART5,
+                                                   S900_MUX_PWM0,
+                                                   S900_MUX_SENS0 };
+static unsigned int rmii_rxd0_mfp_pads[]       = { ETH_RXD0 };
+static unsigned int rmii_rxd0_mfp_funcs[]      = { S900_MUX_ETH_RMII,
+                                                   S900_MUX_UART2,
+                                                   S900_MUX_SPI3,
+                                                   S900_MUX_RESERVED,
+                                                   S900_MUX_UART5,
+                                                   S900_MUX_PWM1,
+                                                   S900_MUX_SENS0 };
+/* mfp0_7_6 */
+static unsigned int rmii_ref_clk_mfp_pads[]    = { ETH_REF_CLK };
+static unsigned int rmii_ref_clk_mfp_funcs[]   = { S900_MUX_ETH_RMII,
+                                                   S900_MUX_UART4,
+                                                   S900_MUX_SPI2,
+                                                   S900_MUX_RESERVED };
+/* mfp0_5 */
+static unsigned int i2s_d0_mfp_pads[]          = { I2S_D0 };
+static unsigned int i2s_d0_mfp_funcs[]         = { S900_MUX_I2S0,
+                                                   S900_MUX_PCM0 };
+static unsigned int i2s_d1_mfp_pads[]          = { I2S_D1 };
+static unsigned int i2s_d1_mfp_funcs[]         = { S900_MUX_I2S1,
+                                                   S900_MUX_PCM0 };
+
+/* mfp0_4_3 */
+static unsigned int i2s_lr_m_clk0_mfp_pads[]   = { I2S_LRCLK0,
+                                                   I2S_MCLK0 };
+static unsigned int i2s_lr_m_clk0_mfp_funcs[]  = { S900_MUX_I2S0,
+                                                   S900_MUX_PCM0,
+                                                   S900_MUX_PCM1,
+                                                   S900_MUX_RESERVED };
+/* mfp0_2 */
+static unsigned int i2s_bclk0_mfp_pads[]       = { I2S_BCLK0 };
+static unsigned int i2s_bclk0_mfp_funcs[]      = { S900_MUX_I2S0,
+                                                   S900_MUX_PCM0 };
+static unsigned int i2s_bclk1_mclk1_mfp_pads[] = { I2S_BCLK1,
+                                                   I2S_LRCLK1,
+                                                   I2S_MCLK1 };
+static unsigned int i2s_bclk1_mclk1_mfp_funcs[] = { S900_MUX_I2S1,
+                                                   S900_MUX_PCM0 };
+/* mfp0_1_0 */
+static unsigned int pcm1_in_out_mfp_pads[]     = { PCM1_IN,
+                                                   PCM1_OUT };
+static unsigned int pcm1_in_out_mfp_funcs[]    = { S900_MUX_PCM1,
+                                                   S900_MUX_SPI1,
+                                                   S900_MUX_I2C3,
+                                                   S900_MUX_UART4 };
+static unsigned int pcm1_clk_mfp_pads[]                = { PCM1_CLK };
+static unsigned int pcm1_clk_mfp_funcs[]       = { S900_MUX_PCM1,
+                                                   S900_MUX_SPI1,
+                                                   S900_MUX_PWM4,
+                                                   S900_MUX_UART4 };
+static unsigned int pcm1_sync_mfp_pads[]       = { PCM1_SYNC };
+static unsigned int pcm1_sync_mfp_funcs[]      = { S900_MUX_PCM1,
+                                                   S900_MUX_SPI1,
+                                                   S900_MUX_PWM5,
+                                                   S900_MUX_UART4 };
+/* mfp1_31_29 */
+static unsigned int eram_a5_mfp_pads[]         = { ERAM_A5 };
+static unsigned int eram_a5_mfp_funcs[]                = { S900_MUX_UART4,
+                                                   S900_MUX_JTAG,
+                                                   S900_MUX_ERAM,
+                                                   S900_MUX_PWM0,
+                                                   S900_MUX_RESERVED,
+                                                   S900_MUX_SENS0 };
+static unsigned int eram_a6_mfp_pads[]         = { ERAM_A6 };
+static unsigned int eram_a6_mfp_funcs[]                = { S900_MUX_UART4,
+                                                   S900_MUX_JTAG,
+                                                   S900_MUX_ERAM,
+                                                   S900_MUX_PWM1,
+                                                   S900_MUX_RESERVED,
+                                                   S900_MUX_SENS0,
+};
+static unsigned int eram_a7_mfp_pads[]         = { ERAM_A7 };
+static unsigned int eram_a7_mfp_funcs[]                = { S900_MUX_RESERVED,
+                                                   S900_MUX_JTAG,
+                                                   S900_MUX_ERAM,
+                                                   S900_MUX_RESERVED,
+                                                   S900_MUX_RESERVED,
+                                                   S900_MUX_SENS0 };
+/* mfp1_28_26 */
+static unsigned int eram_a8_mfp_pads[]         = { ERAM_A8 };
+static unsigned int eram_a8_mfp_funcs[]                = { S900_MUX_RESERVED,
+                                                   S900_MUX_JTAG,
+                                                   S900_MUX_ERAM,
+                                                   S900_MUX_PWM1,
+                                                   S900_MUX_RESERVED,
+                                                   S900_MUX_SENS0 };
+static unsigned int eram_a9_mfp_pads[]         = { ERAM_A9 };
+static unsigned int eram_a9_mfp_funcs[]                = { S900_MUX_USB20,
+                                                   S900_MUX_UART5,
+                                                   S900_MUX_ERAM,
+                                                   S900_MUX_PWM2,
+                                                   S900_MUX_RESERVED,
+                                                   S900_MUX_SENS0 };
+static unsigned int eram_a10_mfp_pads[]                = { ERAM_A10 };
+static unsigned int eram_a10_mfp_funcs[]       = { S900_MUX_USB30,
+                                                   S900_MUX_JTAG,
+                                                   S900_MUX_ERAM,
+                                                   S900_MUX_PWM3,
+                                                   S900_MUX_RESERVED,
+                                                   S900_MUX_SENS0,
+                                                   S900_MUX_RESERVED,
+                                                   S900_MUX_RESERVED };
+/* mfp1_25_23 */
+static unsigned int eram_a11_mfp_pads[]                = { ERAM_A11 };
+static unsigned int eram_a11_mfp_funcs[]       = { S900_MUX_RESERVED,
+                                                   S900_MUX_RESERVED,
+                                                   S900_MUX_ERAM,
+                                                   S900_MUX_PWM2,
+                                                   S900_MUX_UART5,
+                                                   S900_MUX_RESERVED,
+                                                   S900_MUX_SENS0,
+                                                   S900_MUX_RESERVED };
+/* mfp1_22 */
+static unsigned int lvds_oep_odn_mfp_pads[]    = { LVDS_OEP,
+                                                   LVDS_OEN,
+                                                   LVDS_ODP,
+                                                   LVDS_ODN };
+static unsigned int lvds_oep_odn_mfp_funcs[]   = { S900_MUX_LVDS,
+                                                   S900_MUX_UART2 };
+static unsigned int lvds_ocp_obn_mfp_pads[]    = { LVDS_OCP,
+                                                   LVDS_OCN,
+                                                   LVDS_OBP,
+                                                   LVDS_OBN };
+static unsigned int lvds_ocp_obn_mfp_funcs[]   = { S900_MUX_LVDS,
+                                                   S900_MUX_PCM1 };
+static unsigned int lvds_oap_oan_mfp_pads[]    = { LVDS_OAP,
+                                                   LVDS_OAN };
+static unsigned int lvds_oap_oan_mfp_funcs[]   = { S900_MUX_LVDS,
+                                                   S900_MUX_ERAM };
+/* mfp1_21 */
+static unsigned int lvds_e_mfp_pads[]          = { LVDS_EEP,
+                                                   LVDS_EEN,
+                                                   LVDS_EDP,
+                                                   LVDS_EDN,
+                                                   LVDS_ECP,
+                                                   LVDS_ECN,
+                                                   LVDS_EBP,
+                                                   LVDS_EBN,
+                                                   LVDS_EAP,
+                                                   LVDS_EAN };
+static unsigned int lvds_e_mfp_funcs[]         = { S900_MUX_LVDS,
+                                                   S900_MUX_ERAM };
+/* mfp1_5_4 */
+static unsigned int spi0_sclk_mosi_mfp_pads[]  = { SPI0_SCLK,
+                                                   SPI0_MOSI };
+static unsigned int spi0_sclk_mosi_mfp_funcs[] = { S900_MUX_SPI0,
+                                                   S900_MUX_ERAM,
+                                                   S900_MUX_I2C3,
+                                                   S900_MUX_PCM0 };
+/* mfp1_3_1 */
+static unsigned int spi0_ss_mfp_pads[]         = { SPI0_SS };
+static unsigned int spi0_ss_mfp_funcs[]                = { S900_MUX_SPI0,
+                                                   S900_MUX_ERAM,
+                                                   S900_MUX_I2S1,
+                                                   S900_MUX_PCM1,
+                                                   S900_MUX_PCM0,
+                                                   S900_MUX_PWM4 };
+static unsigned int spi0_miso_mfp_pads[]       = { SPI0_MISO };
+static unsigned int spi0_miso_mfp_funcs[]      = { S900_MUX_SPI0,
+                                                   S900_MUX_ERAM,
+                                                   S900_MUX_I2S1,
+                                                   S900_MUX_PCM1,
+                                                   S900_MUX_PCM0,
+                                                   S900_MUX_PWM5 };
+/* mfp2_23 */
+static unsigned int uart2_rtsb_mfp_pads[]      = { UART2_RTSB };
+static unsigned int uart2_rtsb_mfp_funcs[]     = { S900_MUX_UART2,
+                                                   S900_MUX_UART0 };
+/* mfp2_22 */
+static unsigned int uart2_ctsb_mfp_pads[]      = { UART2_CTSB };
+static unsigned int uart2_ctsb_mfp_funcs[]     = { S900_MUX_UART2,
+                                                   S900_MUX_UART0 };
+/* mfp2_21 */
+static unsigned int uart3_rtsb_mfp_pads[]      = { UART3_RTSB };
+static unsigned int uart3_rtsb_mfp_funcs[]     = { S900_MUX_UART3,
+                                                   S900_MUX_UART5 };
+/* mfp2_20 */
+static unsigned int uart3_ctsb_mfp_pads[]      = { UART3_CTSB };
+static unsigned int uart3_ctsb_mfp_funcs[]     = { S900_MUX_UART3,
+                                                   S900_MUX_UART5 };
+/* mfp2_19_17 */
+static unsigned int sd0_d0_mfp_pads[]          = { SD0_D0 };
+static unsigned int sd0_d0_mfp_funcs[]         = { S900_MUX_SD0,
+                                                   S900_MUX_ERAM,
+                                                   S900_MUX_RESERVED,
+                                                   S900_MUX_JTAG,
+                                                   S900_MUX_UART2,
+                                                   S900_MUX_UART5,
+                                                   S900_MUX_GPU };
+/* mfp2_16_14 */
+static unsigned int sd0_d1_mfp_pads[]          = { SD0_D1 };
+static unsigned int sd0_d1_mfp_funcs[]         = { S900_MUX_SD0,
+                                                   S900_MUX_ERAM,
+                                                   S900_MUX_GPU,
+                                                   S900_MUX_RESERVED,
+                                                   S900_MUX_UART2,
+                                                   S900_MUX_UART5 };
+/* mfp_13_11 */
+static unsigned int sd0_d2_d3_mfp_pads[]       = { SD0_D2,
+                                                   SD0_D3 };
+static unsigned int sd0_d2_d3_mfp_funcs[]      = { S900_MUX_SD0,
+                                                   S900_MUX_ERAM,
+                                                   S900_MUX_RESERVED,
+                                                   S900_MUX_JTAG,
+                                                   S900_MUX_UART2,
+                                                   S900_MUX_UART1,
+                                                   S900_MUX_GPU };
+/* mfp2_10_9 */
+static unsigned int sd1_d0_d3_mfp_pads[]       = { SD1_D0, SD1_D1,
+                                                   SD1_D2, SD1_D3 };
+static unsigned int sd1_d0_d3_mfp_funcs[]      = { S900_MUX_SD1,
+                                                   S900_MUX_ERAM };
+/* mfp2_8_7 */
+static unsigned int sd0_cmd_mfp_pads[]         = { SD0_CMD };
+static unsigned int sd0_cmd_mfp_funcs[]                = { S900_MUX_SD0,
+                                                   S900_MUX_ERAM,
+                                                   S900_MUX_GPU,
+                                                   S900_MUX_JTAG };
+/* mfp2_6_5 */
+static unsigned int sd0_clk_mfp_pads[]         = { SD0_CLK };
+static unsigned int sd0_clk_mfp_funcs[]                = { S900_MUX_SD0,
+                                                   S900_MUX_ERAM,
+                                                   S900_MUX_JTAG,
+                                                   S900_MUX_GPU };
+/* mfp2_4_3 */
+static unsigned int sd1_cmd_clk_mfp_pads[]     = { SD1_CMD, SD1_CLK };
+static unsigned int sd1_cmd_clk_mfp_funcs[]    = { S900_MUX_SD1,
+                                                   S900_MUX_ERAM };
+/* mfp2_2_0 */
+static unsigned int uart0_rx_mfp_pads[]                = { UART0_RX };
+static unsigned int uart0_rx_mfp_funcs[]       = { S900_MUX_UART0,
+                                                   S900_MUX_UART2,
+                                                   S900_MUX_SPI1,
+                                                   S900_MUX_I2C5,
+                                                   S900_MUX_PCM1,
+                                                   S900_MUX_I2S1 };
+/* mfp3_27 */
+static unsigned int nand0_d0_ceb3_mfp_pads[]   = { NAND0_D0, NAND0_D1,
+                                                   NAND0_D2, NAND0_D3,
+                                                   NAND0_D4, NAND0_D5,
+                                                   NAND0_D6, NAND0_D7,
+                                                   NAND0_DQSN, NAND0_CEB3 };
+static unsigned int nand0_d0_ceb3_mfp_funcs[]  = { S900_MUX_NAND0,
+                                                   S900_MUX_SD2 };
+/* mfp3_21_19 */
+static unsigned int uart0_tx_mfp_pads[]                = { UART0_TX };
+static unsigned int uart0_tx_mfp_funcs[]       = { S900_MUX_UART0,
+                                                   S900_MUX_UART2,
+                                                   S900_MUX_SPI1,
+                                                   S900_MUX_I2C5,
+                                                   S900_MUX_SPDIF,
+                                                   S900_MUX_PCM1,
+                                                   S900_MUX_I2S1 };
+/* mfp3_18_16 */
+static unsigned int i2c0_mfp_pads[]            = { I2C0_SCLK, I2C0_SDATA };
+static unsigned int i2c0_mfp_funcs[]           = { S900_MUX_I2C0,
+                                                   S900_MUX_UART2,
+                                                   S900_MUX_I2C1,
+                                                   S900_MUX_UART1,
+                                                   S900_MUX_SPI1 };
+/* mfp3_15 */
+static unsigned int csi0_cn_cp_mfp_pads[]      = { CSI0_CN, CSI0_CP };
+static unsigned int csi0_cn_cp_mfp_funcs[]     = { S900_MUX_SENS0,
+                                                   S900_MUX_SENS0 };
+/* mfp3_14 */
+static unsigned int csi0_dn0_dp3_mfp_pads[]    = { CSI0_DN0, CSI0_DP0,
+                                                   CSI0_DN1, CSI0_DP1,
+                                                   CSI0_CN, CSI0_CP,
+                                                   CSI0_DP2, CSI0_DN2,
+                                                   CSI0_DN3, CSI0_DP3 };
+static unsigned int csi0_dn0_dp3_mfp_funcs[]   = { S900_MUX_MIPI_CSI0,
+                                                   S900_MUX_SENS0 };
+/* mfp3_13 */
+static unsigned int csi1_dn0_cp_mfp_pads[]     = { CSI1_DN0, CSI1_DP0,
+                                                   CSI1_DN1, CSI1_DP1,
+                                                   CSI1_CN, CSI1_CP };
+static unsigned int csi1_dn0_cp_mfp_funcs[]    = { S900_MUX_MIPI_CSI1,
+                                                   S900_MUX_SENS0 };
+/* mfp3_12_dsi */
+static unsigned int dsi_dp3_dn1_mfp_pads[]     = { DSI_DP3, DSI_DN2,
+                                                   DSI_DP1, DSI_DN1 };
+static unsigned int dsi_dp3_dn1_mfp_funcs[]    = { S900_MUX_MIPI_DSI,
+                                                   S900_MUX_UART2 };
+static unsigned int dsi_cp_dn0_mfp_pads[]      = { DSI_CP, DSI_CN,
+                                                   DSI_DP0, DSI_DN0 };
+static unsigned int dsi_cp_dn0_mfp_funcs[]     = { S900_MUX_MIPI_DSI,
+                                                   S900_MUX_PCM1 };
+static unsigned int dsi_dp2_dn2_mfp_pads[]     = { DSI_DP2, DSI_DN2 };
+static unsigned int dsi_dp2_dn2_mfp_funcs[]    = { S900_MUX_MIPI_DSI,
+                                                   S900_MUX_UART4 };
+/* mfp3_11 */
+static unsigned int nand1_d0_ceb1_mfp_pads[]   = { NAND1_D0, NAND1_D1,
+                                                   NAND1_D2, NAND1_D3,
+                                                   NAND1_D4, NAND1_D5,
+                                                   NAND1_D6, NAND1_D7,
+                                                   NAND1_DQSN, NAND1_CEB1 };
+static unsigned int nand1_d0_ceb1_mfp_funcs[]  = { S900_MUX_NAND1,
+                                                   S900_MUX_SD3 };
+/* mfp3_10 */
+static unsigned int nand1_ceb3_mfp_pads[]      = { NAND1_CEB3 };
+static unsigned int nand1_ceb3_mfp_funcs[]     = { S900_MUX_NAND1,
+                                                   S900_MUX_PWM0 };
+static unsigned int nand1_ceb0_mfp_pads[]      = { NAND1_CEB0 };
+static unsigned int nand1_ceb0_mfp_funcs[]     = { S900_MUX_NAND1,
+                                                   S900_MUX_PWM1 };
+/* mfp3_9 */
+static unsigned int csi1_dn0_dp0_mfp_pads[]    = { CSI1_DN0, CSI1_DP0 };
+static unsigned int csi1_dn0_dp0_mfp_funcs[]   = { S900_MUX_SENS0,
+                                                   S900_MUX_SENS0 };
+/* mfp3_8 */
+static unsigned int uart4_rx_tx_mfp_pads[]     = { UART4_RX, UART4_TX };
+static unsigned int uart4_rx_tx_mfp_funcs[]    = { S900_MUX_UART4,
+                                                   S900_MUX_I2C4 };
+/* PADDRV group data */
+/* drv0 */
+static unsigned int sgpio3_drv_pads[]          = { SGPIO3 };
+static unsigned int sgpio2_drv_pads[]          = { SGPIO2 };
+static unsigned int sgpio1_drv_pads[]          = { SGPIO1 };
+static unsigned int sgpio0_drv_pads[]          = { SGPIO0 };
+static unsigned int rmii_tx_d0_d1_drv_pads[]   = { ETH_TXD0, ETH_TXD1 };
+static unsigned int rmii_txen_rxer_drv_pads[]  = { ETH_TXEN, ETH_RXER };
+static unsigned int rmii_crs_dv_drv_pads[]     = { ETH_CRS_DV };
+static unsigned int rmii_rx_d1_d0_drv_pads[]   = { ETH_RXD1, ETH_RXD0 };
+static unsigned int rmii_ref_clk_drv_pads[]    = { ETH_REF_CLK };
+static unsigned int rmii_mdc_mdio_drv_pads[]   = { ETH_MDC, ETH_MDIO };
+static unsigned int sirq_0_1_drv_pads[]                = { SIRQ0, SIRQ1 };
+static unsigned int sirq2_drv_pads[]           = { SIRQ2 };
+static unsigned int i2s_d0_d1_drv_pads[]       = { I2S_D0, I2S_D1 };
+static unsigned int i2s_lr_m_clk0_drv_pads[]   = { I2S_LRCLK0, I2S_MCLK0 };
+static unsigned int i2s_blk1_mclk1_drv_pads[]  = { I2S_BCLK0, I2S_BCLK1,
+                                                   I2S_LRCLK1, I2S_MCLK1 };
+static unsigned int pcm1_in_out_drv_pads[]     = { PCM1_IN, PCM1_CLK,
+                                                   PCM1_SYNC, PCM1_OUT };
+/* drv1 */
+static unsigned int lvds_oap_oan_drv_pads[]    = { LVDS_OAP, LVDS_OAN };
+static unsigned int lvds_oep_odn_drv_pads[]    = { LVDS_OEP, LVDS_OEN,
+                                                   LVDS_ODP, LVDS_ODN };
+static unsigned int lvds_ocp_obn_drv_pads[]    = { LVDS_OCP, LVDS_OCN,
+                                                   LVDS_OBP, LVDS_OBN };
+static unsigned int lvds_e_drv_pads[]          = { LVDS_EEP, LVDS_EEN,
+                                                   LVDS_EDP, LVDS_EDN,
+                                                   LVDS_ECP, LVDS_ECN,
+                                                   LVDS_EBP, LVDS_EBN };
+static unsigned int sd0_d3_d0_drv_pads[]       = { SD0_D3, SD0_D2,
+                                                   SD0_D1, SD0_D0 };
+static unsigned int sd1_d3_d0_drv_pads[]       = { SD1_D3, SD1_D2,
+                                                   SD1_D1, SD1_D0 };
+static unsigned int sd0_sd1_cmd_clk_drv_pads[] = { SD0_CLK, SD0_CMD,
+                                                   SD1_CLK, SD1_CMD };
+static unsigned int spi0_sclk_mosi_drv_pads[]  = { SPI0_SCLK, SPI0_MOSI };
+static unsigned int spi0_ss_miso_drv_pads[]    = { SPI0_SS, SPI0_MISO };
+static unsigned int uart0_rx_tx_drv_pads[]     = { UART0_RX, UART0_TX };
+static unsigned int uart4_rx_tx_drv_pads[]     = { UART4_RX, UART4_TX };
+static unsigned int uart2_drv_pads[]           = { UART2_RX, UART2_TX,
+                                                   UART2_RTSB, UART2_CTSB };
+static unsigned int uart3_drv_pads[]           = { UART3_RX, UART3_TX,
+                                                   UART3_RTSB, UART3_CTSB };
+/* drv2 */
+static unsigned int i2c0_drv_pads[]            = { I2C0_SCLK, I2C0_SDATA };
+static unsigned int i2c1_drv_pads[]            = { I2C1_SCLK, I2C1_SDATA };
+static unsigned int i2c2_drv_pads[]            = { I2C2_SCLK, I2C2_SDATA };
+static unsigned int sensor0_drv_pads[]         = { SENSOR0_PCLK,
+                                                   SENSOR0_CKOUT };
+/* SR group data */
+/* sr0 */
+static unsigned int sgpio3_sr_pads[]           = { SGPIO3 };
+static unsigned int sgpio2_sr_pads[]           = { SGPIO2 };
+static unsigned int sgpio1_sr_pads[]           = { SGPIO1 };
+static unsigned int sgpio0_sr_pads[]           = { SGPIO0 };
+static unsigned int rmii_tx_d0_d1_sr_pads[]    = { ETH_TXD0, ETH_TXD1 };
+static unsigned int rmii_txen_rxer_sr_pads[]   = { ETH_TXEN, ETH_RXER };
+static unsigned int rmii_crs_dv_sr_pads[]      = { ETH_CRS_DV };
+static unsigned int rmii_rx_d1_d0_sr_pads[]    = { ETH_RXD1, ETH_RXD0 };
+static unsigned int rmii_ref_clk_sr_pads[]     = { ETH_REF_CLK };
+static unsigned int rmii_mdc_mdio_sr_pads[]    = { ETH_MDC, ETH_MDIO };
+static unsigned int sirq_0_1_sr_pads[]         = { SIRQ0, SIRQ1 };
+static unsigned int sirq2_sr_pads[]            = { SIRQ2 };
+static unsigned int i2s_do_d1_sr_pads[]                = { I2S_D0, I2S_D1 };
+static unsigned int i2s_lr_m_clk0_sr_pads[]    = { I2S_LRCLK0, I2S_MCLK0 };
+static unsigned int i2s_bclk0_mclk1_sr_pads[]  = { I2S_BCLK0, I2S_BCLK1,
+                                                   I2S_LRCLK1, I2S_MCLK1 };
+static unsigned int pcm1_in_out_sr_pads[]      = { PCM1_IN, PCM1_CLK,
+                                                   PCM1_SYNC, PCM1_OUT };
+/* sr1 */
+static unsigned int sd1_d3_d0_sr_pads[]                = { SD1_D3, SD1_D2,
+                                                   SD1_D1, SD1_D0 };
+static unsigned int sd0_sd1_clk_cmd_sr_pads[]  = { SD0_CLK, SD0_CMD,
+                                                   SD1_CLK, SD1_CMD };
+static unsigned int spi0_sclk_mosi_sr_pads[]   = { SPI0_SCLK, SPI0_MOSI };
+static unsigned int spi0_ss_miso_sr_pads[]     = { SPI0_SS, SPI0_MISO };
+static unsigned int uart0_rx_tx_sr_pads[]      = { UART0_RX, UART0_TX };
+static unsigned int uart4_rx_tx_sr_pads[]      = { UART4_RX, UART4_TX };
+static unsigned int uart2_sr_pads[]            = { UART2_RX, UART2_TX,
+                                                   UART2_RTSB, UART2_CTSB };
+static unsigned int uart3_sr_pads[]            = { UART3_RX, UART3_TX,
+                                                   UART3_RTSB, UART3_CTSB };
+/* sr2 */
+static unsigned int i2c0_sr_pads[]             = { I2C0_SCLK, I2C0_SDATA };
+static unsigned int i2c1_sr_pads[]             = { I2C1_SCLK, I2C1_SDATA };
+static unsigned int i2c2_sr_pads[]             = { I2C2_SCLK, I2C2_SDATA };
+static unsigned int sensor0_sr_pads[]          = { SENSOR0_PCLK,
+                                                   SENSOR0_CKOUT };
+
+#define MUX_PG(group_name, reg, shift, width)                          \
+       {                                                               \
+               .name = #group_name,                                    \
+               .pads = group_name##_pads,                              \
+               .npads = ARRAY_SIZE(group_name##_pads),                 \
+               .funcs = group_name##_funcs,                            \
+               .nfuncs = ARRAY_SIZE(group_name##_funcs),               \
+               .mfpctl_reg  = MFCTL##reg,                              \
+               .mfpctl_shift = shift,                                  \
+               .mfpctl_width = width,                                  \
+               .drv_reg = -1,                                          \
+               .drv_shift = -1,                                        \
+               .drv_width = -1,                                        \
+               .sr_reg = -1,                                           \
+               .sr_shift = -1,                                         \
+               .sr_width = -1,                                         \
+       }
+
+#define DRV_PG(group_name, reg, shift, width)                          \
+       {                                                               \
+               .name = #group_name,                                    \
+               .pads = group_name##_pads,                              \
+               .npads = ARRAY_SIZE(group_name##_pads),                 \
+               .mfpctl_reg  = -1,                                      \
+               .mfpctl_shift = -1,                                     \
+               .mfpctl_width = -1,                                     \
+               .drv_reg = PAD_DRV##reg,                                \
+               .drv_shift = shift,                                     \
+               .drv_width = width,                                     \
+               .sr_reg = -1,                                           \
+               .sr_shift = -1,                                         \
+               .sr_width = -1,                                         \
+       }
+
+#define SR_PG(group_name, reg, shift, width)                           \
+       {                                                               \
+               .name = #group_name,                                    \
+               .pads = group_name##_pads,                              \
+               .npads = ARRAY_SIZE(group_name##_pads),                 \
+               .mfpctl_reg  = -1,                                      \
+               .mfpctl_shift = -1,                                     \
+               .mfpctl_width = -1,                                     \
+               .drv_reg = -1,                                          \
+               .drv_shift = -1,                                        \
+               .drv_width = -1,                                        \
+               .sr_reg = PAD_SR##reg,                                  \
+               .sr_shift = shift,                                      \
+               .sr_width = width,                                      \
+       }
+
+/* Pinctrl groups */
+static const struct owl_pingroup s900_groups[] = {
+       MUX_PG(lvds_oxx_uart4_mfp, 0, 22, 1),
+       MUX_PG(rmii_mdc_mfp, 0, 20, 2),
+       MUX_PG(rmii_mdio_mfp, 0, 20, 2),
+       MUX_PG(sirq0_mfp, 0, 19, 1),
+       MUX_PG(sirq1_mfp, 0, 19, 1),
+       MUX_PG(rmii_txd0_mfp, 0, 16, 3),
+       MUX_PG(rmii_txd1_mfp, 0, 16, 3),
+       MUX_PG(rmii_txen_mfp, 0, 13, 3),
+       MUX_PG(rmii_rxer_mfp, 0, 13, 3),
+       MUX_PG(rmii_crs_dv_mfp, 0, 11, 2),
+       MUX_PG(rmii_rxd1_mfp, 0, 8, 3),
+       MUX_PG(rmii_rxd0_mfp, 0, 8, 3),
+       MUX_PG(rmii_ref_clk_mfp, 0, 6, 2),
+       MUX_PG(i2s_d0_mfp, 0, 5, 1),
+       MUX_PG(i2s_d1_mfp, 0, 5, 1),
+       MUX_PG(i2s_lr_m_clk0_mfp, 0, 3, 2),
+       MUX_PG(i2s_bclk0_mfp, 0, 2, 1),
+       MUX_PG(i2s_bclk1_mclk1_mfp, 0, 2, 1),
+       MUX_PG(pcm1_in_out_mfp, 0, 0, 2),
+       MUX_PG(pcm1_clk_mfp, 0, 0, 2),
+       MUX_PG(pcm1_sync_mfp, 0, 0, 2),
+       MUX_PG(eram_a5_mfp, 1, 29, 3),
+       MUX_PG(eram_a6_mfp, 1, 29, 3),
+       MUX_PG(eram_a7_mfp, 1, 29, 3),
+       MUX_PG(eram_a8_mfp, 1, 26, 3),
+       MUX_PG(eram_a9_mfp, 1, 26, 3),
+       MUX_PG(eram_a10_mfp, 1, 26, 3),
+       MUX_PG(eram_a11_mfp, 1, 23, 3),
+       MUX_PG(lvds_oep_odn_mfp, 1, 22, 1),
+       MUX_PG(lvds_ocp_obn_mfp, 1, 22, 1),
+       MUX_PG(lvds_oap_oan_mfp, 1, 22, 1),
+       MUX_PG(lvds_e_mfp, 1, 21, 1),
+       MUX_PG(spi0_sclk_mosi_mfp, 1, 4, 2),
+       MUX_PG(spi0_ss_mfp, 1, 1, 3),
+       MUX_PG(spi0_miso_mfp, 1, 1, 3),
+       MUX_PG(uart2_rtsb_mfp, 2, 23, 1),
+       MUX_PG(uart2_ctsb_mfp, 2, 22, 1),
+       MUX_PG(uart3_rtsb_mfp, 2, 21, 1),
+       MUX_PG(uart3_ctsb_mfp, 2, 20, 1),
+       MUX_PG(sd0_d0_mfp, 2, 17, 3),
+       MUX_PG(sd0_d1_mfp, 2, 14, 3),
+       MUX_PG(sd0_d2_d3_mfp, 2, 11, 3),
+       MUX_PG(sd1_d0_d3_mfp, 2, 9, 2),
+       MUX_PG(sd0_cmd_mfp, 2, 7, 2),
+       MUX_PG(sd0_clk_mfp, 2, 5, 2),
+       MUX_PG(sd1_cmd_clk_mfp, 2, 3, 2),
+       MUX_PG(uart0_rx_mfp, 2, 0, 3),
+       MUX_PG(nand0_d0_ceb3_mfp, 3, 27, 1),
+       MUX_PG(uart0_tx_mfp, 3, 19, 3),
+       MUX_PG(i2c0_mfp, 3, 16, 3),
+       MUX_PG(csi0_cn_cp_mfp, 3, 15, 1),
+       MUX_PG(csi0_dn0_dp3_mfp, 3, 14, 1),
+       MUX_PG(csi1_dn0_cp_mfp, 3, 13, 1),
+       MUX_PG(dsi_dp3_dn1_mfp, 3, 12, 1),
+       MUX_PG(dsi_cp_dn0_mfp, 3, 12, 1),
+       MUX_PG(dsi_dp2_dn2_mfp, 3, 12, 1),
+       MUX_PG(nand1_d0_ceb1_mfp, 3, 11, 1),
+       MUX_PG(nand1_ceb3_mfp, 3, 10, 1),
+       MUX_PG(nand1_ceb0_mfp, 3, 10, 1),
+       MUX_PG(csi1_dn0_dp0_mfp, 3, 9, 1),
+       MUX_PG(uart4_rx_tx_mfp, 3, 8, 1),
+
+       DRV_PG(sgpio3_drv, 0, 30, 2),
+       DRV_PG(sgpio2_drv, 0, 28, 2),
+       DRV_PG(sgpio1_drv, 0, 26, 2),
+       DRV_PG(sgpio0_drv, 0, 24, 2),
+       DRV_PG(rmii_tx_d0_d1_drv, 0, 22, 2),
+       DRV_PG(rmii_txen_rxer_drv, 0, 20, 2),
+       DRV_PG(rmii_crs_dv_drv, 0, 18, 2),
+       DRV_PG(rmii_rx_d1_d0_drv, 0, 16, 2),
+       DRV_PG(rmii_ref_clk_drv, 0, 14, 2),
+       DRV_PG(rmii_mdc_mdio_drv, 0, 12, 2),
+       DRV_PG(sirq_0_1_drv, 0, 10, 2),
+       DRV_PG(sirq2_drv, 0, 8, 2),
+       DRV_PG(i2s_d0_d1_drv, 0, 6, 2),
+       DRV_PG(i2s_lr_m_clk0_drv, 0, 4, 2),
+       DRV_PG(i2s_blk1_mclk1_drv, 0, 2, 2),
+       DRV_PG(pcm1_in_out_drv, 0, 0, 2),
+       DRV_PG(lvds_oap_oan_drv, 1, 28, 2),
+       DRV_PG(lvds_oep_odn_drv, 1, 26, 2),
+       DRV_PG(lvds_ocp_obn_drv, 1, 24, 2),
+       DRV_PG(lvds_e_drv, 1, 22, 2),
+       DRV_PG(sd0_d3_d0_drv, 1, 20, 2),
+       DRV_PG(sd1_d3_d0_drv, 1, 18, 2),
+       DRV_PG(sd0_sd1_cmd_clk_drv, 1, 16, 2),
+       DRV_PG(spi0_sclk_mosi_drv, 1, 14, 2),
+       DRV_PG(spi0_ss_miso_drv, 1, 12, 2),
+       DRV_PG(uart0_rx_tx_drv, 1, 10, 2),
+       DRV_PG(uart4_rx_tx_drv, 1, 8, 2),
+       DRV_PG(uart2_drv, 1, 6, 2),
+       DRV_PG(uart3_drv, 1, 4, 2),
+       DRV_PG(i2c0_drv, 2, 30, 2),
+       DRV_PG(i2c1_drv, 2, 28, 2),
+       DRV_PG(i2c2_drv, 2, 26, 2),
+       DRV_PG(sensor0_drv, 2, 20, 2),
+
+       SR_PG(sgpio3_sr, 0, 15, 1),
+       SR_PG(sgpio2_sr, 0, 14, 1),
+       SR_PG(sgpio1_sr, 0, 13, 1),
+       SR_PG(sgpio0_sr, 0, 12, 1),
+       SR_PG(rmii_tx_d0_d1_sr, 0, 11, 1),
+       SR_PG(rmii_txen_rxer_sr, 0, 10, 1),
+       SR_PG(rmii_crs_dv_sr, 0, 9, 1),
+       SR_PG(rmii_rx_d1_d0_sr, 0, 8, 1),
+       SR_PG(rmii_ref_clk_sr, 0, 7, 1),
+       SR_PG(rmii_mdc_mdio_sr, 0, 6, 1),
+       SR_PG(sirq_0_1_sr, 0, 5, 1),
+       SR_PG(sirq2_sr, 0, 4, 1),
+       SR_PG(i2s_do_d1_sr, 0, 3, 1),
+       SR_PG(i2s_lr_m_clk0_sr, 0, 2, 1),
+       SR_PG(i2s_bclk0_mclk1_sr, 0, 1, 1),
+       SR_PG(pcm1_in_out_sr, 0, 0, 1),
+       SR_PG(sd1_d3_d0_sr, 1, 25, 1),
+       SR_PG(sd0_sd1_clk_cmd_sr, 1, 24, 1),
+       SR_PG(spi0_sclk_mosi_sr, 1, 23, 1),
+       SR_PG(spi0_ss_miso_sr, 1, 22, 1),
+       SR_PG(uart0_rx_tx_sr, 1, 21, 1),
+       SR_PG(uart4_rx_tx_sr, 1, 20, 1),
+       SR_PG(uart2_sr, 1, 19, 1),
+       SR_PG(uart3_sr, 1, 18, 1),
+       SR_PG(i2c0_sr, 2, 31, 1),
+       SR_PG(i2c1_sr, 2, 30, 1),
+       SR_PG(i2c2_sr, 2, 29, 1),
+       SR_PG(sensor0_sr, 2, 25, 1)
+};
+
+static const char * const eram_groups[] = {
+       "lvds_oxx_uart4_mfp",
+       "eram_a5_mfp",
+       "eram_a6_mfp",
+       "eram_a7_mfp",
+       "eram_a8_mfp",
+       "eram_a9_mfp",
+       "eram_a10_mfp",
+       "eram_a11_mfp",
+       "lvds_oap_oan_mfp",
+       "lvds_e_mfp",
+       "spi0_sclk_mosi_mfp",
+       "spi0_ss_mfp",
+       "spi0_miso_mfp",
+       "sd0_d0_mfp",
+       "sd0_d1_mfp",
+       "sd0_d2_d3_mfp",
+       "sd1_d0_d3_mfp",
+       "sd0_cmd_mfp",
+       "sd0_clk_mfp",
+       "sd1_cmd_clk_mfp",
+};
+
+static const char * const eth_rmii_groups[] = {
+       "rmii_mdc_mfp",
+       "rmii_mdio_mfp",
+       "rmii_txd0_mfp",
+       "rmii_txd1_mfp",
+       "rmii_txen_mfp",
+       "rmii_rxer_mfp",
+       "rmii_crs_dv_mfp",
+       "rmii_rxd1_mfp",
+       "rmii_rxd0_mfp",
+       "rmii_ref_clk_mfp",
+       "eth_smi_dummy",
+};
+
+static const char * const eth_smii_groups[] = {
+       "rmii_txd0_mfp",
+       "rmii_txd1_mfp",
+       "rmii_crs_dv_mfp",
+       "eth_smi_dummy",
+};
+
+static const char * const spi0_groups[] = {
+       "spi0_sclk_mosi_mfp",
+       "spi0_ss_mfp",
+       "spi0_miso_mfp",
+       "spi0_sclk_mosi_mfp",
+       "spi0_ss_mfp",
+       "spi0_miso_mfp",
+};
+
+static const char * const spi1_groups[] = {
+       "pcm1_in_out_mfp",
+       "pcm1_clk_mfp",
+       "pcm1_sync_mfp",
+       "uart0_rx_mfp",
+       "uart0_tx_mfp",
+       "i2c0_mfp",
+};
+
+static const char * const spi2_groups[] = {
+       "rmii_txd0_mfp",
+       "rmii_txd1_mfp",
+       "rmii_crs_dv_mfp",
+       "rmii_ref_clk_mfp",
+};
+
+static const char * const spi3_groups[] = {
+       "rmii_txen_mfp",
+       "rmii_rxer_mfp",
+};
+
+static const char * const sens0_groups[] = {
+       "rmii_txd0_mfp",
+       "rmii_txd1_mfp",
+       "rmii_txen_mfp",
+       "rmii_rxer_mfp",
+       "rmii_rxd1_mfp",
+       "rmii_rxd0_mfp",
+       "eram_a5_mfp",
+       "eram_a6_mfp",
+       "eram_a7_mfp",
+       "eram_a8_mfp",
+       "eram_a9_mfp",
+       "csi0_cn_cp_mfp",
+       "csi0_dn0_dp3_mfp",
+       "csi1_dn0_cp_mfp",
+       "csi1_dn0_dp0_mfp",
+};
+
+static const char * const uart0_groups[] = {
+       "uart2_rtsb_mfp",
+       "uart2_ctsb_mfp",
+       "uart0_rx_mfp",
+       "uart0_tx_mfp",
+};
+
+static const char * const uart1_groups[] = {
+       "sd0_d2_d3_mfp",
+       "i2c0_mfp",
+};
+
+static const char * const uart2_groups[] = {
+       "rmii_mdc_mfp",
+       "rmii_mdio_mfp",
+       "rmii_txen_mfp",
+       "rmii_rxer_mfp",
+       "rmii_rxd1_mfp",
+       "rmii_rxd0_mfp",
+       "lvds_oep_odn_mfp",
+       "uart2_rtsb_mfp",
+       "uart2_ctsb_mfp",
+       "sd0_d0_mfp",
+       "sd0_d1_mfp",
+       "sd0_d2_d3_mfp",
+       "uart0_rx_mfp",
+       "uart0_tx_mfp_pads",
+       "i2c0_mfp_pads",
+       "dsi_dp3_dn1_mfp",
+       "uart2_dummy"
+};
+
+static const char * const uart3_groups[] = {
+       "uart3_rtsb_mfp",
+       "uart3_ctsb_mfp",
+       "uart3_dummy"
+};
+
+static const char * const uart4_groups[] = {
+       "lvds_oxx_uart4_mfp",
+       "rmii_crs_dv_mfp",
+       "rmii_ref_clk_mfp",
+       "pcm1_in_out_mfp",
+       "pcm1_clk_mfp",
+       "pcm1_sync_mfp",
+       "eram_a5_mfp",
+       "eram_a6_mfp",
+       "dsi_dp2_dn2_mfp",
+       "uart4_rx_tx_mfp_pads",
+       "uart4_dummy"
+};
+
+static const char * const uart5_groups[] = {
+       "rmii_rxd1_mfp",
+       "rmii_rxd0_mfp",
+       "eram_a9_mfp",
+       "eram_a11_mfp",
+       "uart3_rtsb_mfp",
+       "uart3_ctsb_mfp",
+       "sd0_d0_mfp",
+       "sd0_d1_mfp",
+};
+
+static const char * const uart6_groups[] = {
+       "rmii_txd0_mfp",
+       "rmii_txd1_mfp",
+};
+
+static const char * const i2s0_groups[] = {
+       "i2s_d0_mfp",
+       "i2s_lr_m_clk0_mfp",
+       "i2s_bclk0_mfp",
+       "i2s0_dummy",
+};
+
+static const char * const i2s1_groups[] = {
+       "i2s_d1_mfp",
+       "i2s_bclk1_mclk1_mfp",
+       "spi0_ss_mfp",
+       "spi0_miso_mfp",
+       "uart0_rx_mfp",
+       "uart0_tx_mfp",
+       "i2s1_dummy",
+};
+
+static const char * const pcm0_groups[] = {
+       "i2s_d0_mfp",
+       "i2s_d1_mfp",
+       "i2s_lr_m_clk0_mfp",
+       "i2s_bclk0_mfp",
+       "i2s_bclk1_mclk1_mfp",
+       "spi0_sclk_mosi_mfp",
+       "spi0_ss_mfp",
+       "spi0_miso_mfp",
+};
+
+static const char * const pcm1_groups[] = {
+       "i2s_lr_m_clk0_mfp",
+       "pcm1_in_out_mfp",
+       "pcm1_clk_mfp",
+       "pcm1_sync_mfp",
+       "lvds_oep_odn_mfp",
+       "spi0_ss_mfp",
+       "spi0_miso_mfp",
+       "uart0_rx_mfp",
+       "uart0_tx_mfp",
+       "dsi_cp_dn0_mfp",
+       "pcm1_dummy",
+};
+
+static const char * const jtag_groups[] = {
+       "eram_a5_mfp",
+       "eram_a6_mfp",
+       "eram_a7_mfp",
+       "eram_a8_mfp",
+       "eram_a10_mfp",
+       "eram_a10_mfp",
+       "sd0_d2_d3_mfp",
+       "sd0_cmd_mfp",
+       "sd0_clk_mfp",
+};
+
+static const char * const pwm0_groups[] = {
+       "sirq0_mfp",
+       "rmii_txd0_mfp",
+       "rmii_rxd1_mfp",
+       "eram_a5_mfp",
+       "nand1_ceb3_mfp",
+};
+
+static const char * const pwm1_groups[] = {
+       "sirq1_mfp",
+       "rmii_txd1_mfp",
+       "rmii_rxd0_mfp",
+       "eram_a6_mfp",
+       "eram_a8_mfp",
+       "nand1_ceb0_mfp",
+};
+
+static const char * const pwm2_groups[] = {
+       "rmii_mdc_mfp",
+       "rmii_txen_mfp",
+       "eram_a9_mfp",
+       "eram_a11_mfp",
+};
+
+static const char * const pwm3_groups[] = {
+       "rmii_mdio_mfp",
+       "rmii_rxer_mfp",
+       "eram_a10_mfp",
+};
+
+static const char * const pwm4_groups[] = {
+       "pcm1_clk_mfp",
+       "spi0_ss_mfp",
+};
+
+static const char * const pwm5_groups[] = {
+       "pcm1_sync_mfp",
+       "spi0_miso_mfp",
+};
+
+static const char * const sd0_groups[] = {
+       "sd0_d0_mfp",
+       "sd0_d1_mfp",
+       "sd0_d2_d3_mfp",
+       "sd0_cmd_mfp",
+       "sd0_clk_mfp",
+};
+
+static const char * const sd1_groups[] = {
+       "sd1_d0_d3_mfp",
+       "sd1_cmd_clk_mfp",
+       "sd1_dummy",
+};
+
+static const char * const sd2_groups[] = {
+       "nand0_d0_ceb3_mfp",
+};
+
+static const char * const sd3_groups[] = {
+       "nand1_d0_ceb1_mfp",
+};
+
+static const char * const i2c0_groups[] = {
+       "i2c0_mfp",
+};
+
+static const char * const i2c1_groups[] = {
+       "i2c0_mfp",
+       "i2c1_dummy"
+};
+
+static const char * const i2c2_groups[] = {
+       "i2c2_dummy"
+};
+
+static const char * const i2c3_groups[] = {
+       "pcm1_in_out_mfp",
+       "spi0_sclk_mosi_mfp",
+};
+
+static const char * const i2c4_groups[] = {
+       "uart4_rx_tx_mfp",
+};
+
+static const char * const i2c5_groups[] = {
+       "uart0_rx_mfp",
+       "uart0_tx_mfp",
+};
+
+
+static const char * const lvds_groups[] = {
+       "lvds_oep_odn_mfp",
+       "lvds_ocp_obn_mfp",
+       "lvds_oap_oan_mfp",
+       "lvds_e_mfp",
+};
+
+static const char * const usb20_groups[] = {
+       "eram_a9_mfp",
+};
+
+static const char * const usb30_groups[] = {
+       "eram_a10_mfp",
+};
+
+static const char * const gpu_groups[] = {
+       "sd0_d0_mfp",
+       "sd0_d1_mfp",
+       "sd0_d2_d3_mfp",
+       "sd0_cmd_mfp",
+       "sd0_clk_mfp",
+};
+
+static const char * const mipi_csi0_groups[] = {
+       "csi0_dn0_dp3_mfp",
+};
+
+static const char * const mipi_csi1_groups[] = {
+       "csi1_dn0_cp_mfp",
+};
+
+static const char * const mipi_dsi_groups[] = {
+       "dsi_dp3_dn1_mfp",
+       "dsi_cp_dn0_mfp",
+       "dsi_dp2_dn2_mfp",
+       "mipi_dsi_dummy",
+};
+
+static const char * const nand0_groups[] = {
+       "nand0_d0_ceb3_mfp",
+       "nand0_dummy",
+};
+
+static const char * const nand1_groups[] = {
+       "nand1_d0_ceb1_mfp",
+       "nand1_ceb3_mfp",
+       "nand1_ceb0_mfp",
+       "nand1_dummy",
+};
+
+static const char * const spdif_groups[] = {
+       "uart0_tx_mfp",
+};
+
+static const char * const sirq0_groups[] = {
+       "sirq0_mfp",
+       "sirq0_dummy",
+};
+
+static const char * const sirq1_groups[] = {
+       "sirq1_mfp",
+       "sirq1_dummy",
+};
+
+static const char * const sirq2_groups[] = {
+       "sirq2_dummy",
+};
+
+#define FUNCTION(fname)                                        \
+       {                                               \
+               .name = #fname,                         \
+               .groups = fname##_groups,               \
+               .ngroups = ARRAY_SIZE(fname##_groups),  \
+       }
+
+static const struct owl_pinmux_func s900_functions[] = {
+       [S900_MUX_ERAM] = FUNCTION(eram),
+       [S900_MUX_ETH_RMII] = FUNCTION(eth_rmii),
+       [S900_MUX_ETH_SMII] = FUNCTION(eth_smii),
+       [S900_MUX_SPI0] = FUNCTION(spi0),
+       [S900_MUX_SPI1] = FUNCTION(spi1),
+       [S900_MUX_SPI2] = FUNCTION(spi2),
+       [S900_MUX_SPI3] = FUNCTION(spi3),
+       [S900_MUX_SENS0] = FUNCTION(sens0),
+       [S900_MUX_UART0] = FUNCTION(uart0),
+       [S900_MUX_UART1] = FUNCTION(uart1),
+       [S900_MUX_UART2] = FUNCTION(uart2),
+       [S900_MUX_UART3] = FUNCTION(uart3),
+       [S900_MUX_UART4] = FUNCTION(uart4),
+       [S900_MUX_UART5] = FUNCTION(uart5),
+       [S900_MUX_UART6] = FUNCTION(uart6),
+       [S900_MUX_I2S0] = FUNCTION(i2s0),
+       [S900_MUX_I2S1] = FUNCTION(i2s1),
+       [S900_MUX_PCM0] = FUNCTION(pcm0),
+       [S900_MUX_PCM1] = FUNCTION(pcm1),
+       [S900_MUX_JTAG] = FUNCTION(jtag),
+       [S900_MUX_PWM0] = FUNCTION(pwm0),
+       [S900_MUX_PWM1] = FUNCTION(pwm1),
+       [S900_MUX_PWM2] = FUNCTION(pwm2),
+       [S900_MUX_PWM3] = FUNCTION(pwm3),
+       [S900_MUX_PWM4] = FUNCTION(pwm4),
+       [S900_MUX_PWM5] = FUNCTION(pwm5),
+       [S900_MUX_SD0] = FUNCTION(sd0),
+       [S900_MUX_SD1] = FUNCTION(sd1),
+       [S900_MUX_SD2] = FUNCTION(sd2),
+       [S900_MUX_SD3] = FUNCTION(sd3),
+       [S900_MUX_I2C0] = FUNCTION(i2c0),
+       [S900_MUX_I2C1] = FUNCTION(i2c1),
+       [S900_MUX_I2C2] = FUNCTION(i2c2),
+       [S900_MUX_I2C3] = FUNCTION(i2c3),
+       [S900_MUX_I2C4] = FUNCTION(i2c4),
+       [S900_MUX_I2C5] = FUNCTION(i2c5),
+       [S900_MUX_LVDS] = FUNCTION(lvds),
+       [S900_MUX_USB30] = FUNCTION(usb30),
+       [S900_MUX_USB20] = FUNCTION(usb20),
+       [S900_MUX_GPU] = FUNCTION(gpu),
+       [S900_MUX_MIPI_CSI0] = FUNCTION(mipi_csi0),
+       [S900_MUX_MIPI_CSI1] = FUNCTION(mipi_csi1),
+       [S900_MUX_MIPI_DSI] = FUNCTION(mipi_dsi),
+       [S900_MUX_NAND0] = FUNCTION(nand0),
+       [S900_MUX_NAND1] = FUNCTION(nand1),
+       [S900_MUX_SPDIF] = FUNCTION(spdif),
+       [S900_MUX_SIRQ0] = FUNCTION(sirq0),
+       [S900_MUX_SIRQ1] = FUNCTION(sirq1),
+       [S900_MUX_SIRQ2] = FUNCTION(sirq2)
+};
+/* PAD PULL UP/DOWN CONFIGURES */
+#define PULLCTL_CONF(pull_reg, pull_sft, pull_wdt)                     \
+       {                                                               \
+               .reg = PAD_PULLCTL##pull_reg,                           \
+               .shift = pull_sft,                                      \
+               .width = pull_wdt,                                      \
+       }
+
+#define PAD_PULLCTL_CONF(pad_name, pull_reg, pull_sft, pull_wdt)       \
+       struct owl_pullctl pad_name##_pullctl_conf                      \
+               = PULLCTL_CONF(pull_reg, pull_sft, pull_wdt)
+
+#define ST_CONF(st_reg, st_sft, st_wdt)                                        \
+       {                                                               \
+               .reg = PAD_ST##st_reg,                                  \
+               .shift = st_sft,                                        \
+               .width = st_wdt,                                        \
+       }
+
+#define PAD_ST_CONF(pad_name, st_reg, st_sft, st_wdt)                  \
+       struct owl_st pad_name##_st_conf                                \
+               = ST_CONF(st_reg, st_sft, st_wdt)
+
+/* PAD_PULLCTL0 */
+static PAD_PULLCTL_CONF(ETH_RXER, 0, 18, 2);
+static PAD_PULLCTL_CONF(SIRQ0, 0, 16, 2);
+static PAD_PULLCTL_CONF(SIRQ1, 0, 14, 2);
+static PAD_PULLCTL_CONF(SIRQ2, 0, 12, 2);
+static PAD_PULLCTL_CONF(I2C0_SDATA, 0, 10, 2);
+static PAD_PULLCTL_CONF(I2C0_SCLK, 0, 8, 2);
+static PAD_PULLCTL_CONF(ERAM_A5, 0, 6, 2);
+static PAD_PULLCTL_CONF(ERAM_A6, 0, 4, 2);
+static PAD_PULLCTL_CONF(ERAM_A7, 0, 2, 2);
+static PAD_PULLCTL_CONF(ERAM_A10, 0, 0, 2);
+
+/* PAD_PULLCTL1 */
+static PAD_PULLCTL_CONF(PCM1_IN, 1, 30, 2);
+static PAD_PULLCTL_CONF(PCM1_OUT, 1, 28, 2);
+static PAD_PULLCTL_CONF(SD0_D0, 1, 26, 2);
+static PAD_PULLCTL_CONF(SD0_D1, 1, 24, 2);
+static PAD_PULLCTL_CONF(SD0_D2, 1, 22, 2);
+static PAD_PULLCTL_CONF(SD0_D3, 1, 20, 2);
+static PAD_PULLCTL_CONF(SD0_CMD, 1, 18, 2);
+static PAD_PULLCTL_CONF(SD0_CLK, 1, 16, 2);
+static PAD_PULLCTL_CONF(SD1_CMD, 1, 14, 2);
+static PAD_PULLCTL_CONF(SD1_D0, 1, 12, 2);
+static PAD_PULLCTL_CONF(SD1_D1, 1, 10, 2);
+static PAD_PULLCTL_CONF(SD1_D2, 1, 8, 2);
+static PAD_PULLCTL_CONF(SD1_D3, 1, 6, 2);
+static PAD_PULLCTL_CONF(UART0_RX, 1, 4, 2);
+static PAD_PULLCTL_CONF(UART0_TX, 1, 2, 2);
+
+/* PAD_PULLCTL2 */
+static PAD_PULLCTL_CONF(I2C2_SDATA, 2, 26, 2);
+static PAD_PULLCTL_CONF(I2C2_SCLK, 2, 24, 2);
+static PAD_PULLCTL_CONF(SPI0_SCLK, 2, 22, 2);
+static PAD_PULLCTL_CONF(SPI0_MOSI, 2, 20, 2);
+static PAD_PULLCTL_CONF(I2C1_SDATA, 2, 18, 2);
+static PAD_PULLCTL_CONF(I2C1_SCLK, 2, 16, 2);
+static PAD_PULLCTL_CONF(NAND0_D0, 2, 15, 1);
+static PAD_PULLCTL_CONF(NAND0_D1, 2, 15, 1);
+static PAD_PULLCTL_CONF(NAND0_D2, 2, 15, 1);
+static PAD_PULLCTL_CONF(NAND0_D3, 2, 15, 1);
+static PAD_PULLCTL_CONF(NAND0_D4, 2, 15, 1);
+static PAD_PULLCTL_CONF(NAND0_D5, 2, 15, 1);
+static PAD_PULLCTL_CONF(NAND0_D6, 2, 15, 1);
+static PAD_PULLCTL_CONF(NAND0_D7, 2, 15, 1);
+static PAD_PULLCTL_CONF(NAND0_DQSN, 2, 14, 1);
+static PAD_PULLCTL_CONF(NAND0_DQS, 2, 13, 1);
+static PAD_PULLCTL_CONF(NAND1_D0, 2, 12, 1);
+static PAD_PULLCTL_CONF(NAND1_D1, 2, 12, 1);
+static PAD_PULLCTL_CONF(NAND1_D2, 2, 12, 1);
+static PAD_PULLCTL_CONF(NAND1_D3, 2, 12, 1);
+static PAD_PULLCTL_CONF(NAND1_D4, 2, 12, 1);
+static PAD_PULLCTL_CONF(NAND1_D5, 2, 12, 1);
+static PAD_PULLCTL_CONF(NAND1_D6, 2, 12, 1);
+static PAD_PULLCTL_CONF(NAND1_D7, 2, 12, 1);
+static PAD_PULLCTL_CONF(NAND1_DQSN, 2, 11, 1);
+static PAD_PULLCTL_CONF(NAND1_DQS, 2, 10, 1);
+static PAD_PULLCTL_CONF(SGPIO2, 2, 8, 2);
+static PAD_PULLCTL_CONF(SGPIO3, 2, 6, 2);
+static PAD_PULLCTL_CONF(UART4_RX, 2, 4, 2);
+static PAD_PULLCTL_CONF(UART4_TX, 2, 2, 2);
+
+/* PAD_ST0 */
+static PAD_ST_CONF(I2C0_SDATA, 0, 30, 1);
+static PAD_ST_CONF(UART0_RX, 0, 29, 1);
+static PAD_ST_CONF(ETH_MDC, 0, 28, 1);
+static PAD_ST_CONF(I2S_MCLK1, 0, 23, 1);
+static PAD_ST_CONF(ETH_REF_CLK, 0, 22, 1);
+static PAD_ST_CONF(ETH_TXEN, 0, 21, 1);
+static PAD_ST_CONF(ETH_TXD0, 0, 20, 1);
+static PAD_ST_CONF(I2S_LRCLK1, 0, 19, 1);
+static PAD_ST_CONF(SGPIO2, 0, 18, 1);
+static PAD_ST_CONF(SGPIO3, 0, 17, 1);
+static PAD_ST_CONF(UART4_TX, 0, 16, 1);
+static PAD_ST_CONF(I2S_D1, 0, 15, 1);
+static PAD_ST_CONF(UART0_TX, 0, 14, 1);
+static PAD_ST_CONF(SPI0_SCLK, 0, 13, 1);
+static PAD_ST_CONF(SD0_CLK, 0, 12, 1);
+static PAD_ST_CONF(ERAM_A5, 0, 11, 1);
+static PAD_ST_CONF(I2C0_SCLK, 0, 7, 1);
+static PAD_ST_CONF(ERAM_A9, 0, 6, 1);
+static PAD_ST_CONF(LVDS_OEP, 0, 5, 1);
+static PAD_ST_CONF(LVDS_ODN, 0, 4, 1);
+static PAD_ST_CONF(LVDS_OAP, 0, 3, 1);
+static PAD_ST_CONF(I2S_BCLK1, 0, 2, 1);
+
+/* PAD_ST1 */
+static PAD_ST_CONF(I2S_LRCLK0, 1, 29, 1);
+static PAD_ST_CONF(UART4_RX, 1, 28, 1);
+static PAD_ST_CONF(UART3_CTSB, 1, 27, 1);
+static PAD_ST_CONF(UART3_RTSB, 1, 26, 1);
+static PAD_ST_CONF(UART3_RX, 1, 25, 1);
+static PAD_ST_CONF(UART2_RTSB, 1, 24, 1);
+static PAD_ST_CONF(UART2_CTSB, 1, 23, 1);
+static PAD_ST_CONF(UART2_RX, 1, 22, 1);
+static PAD_ST_CONF(ETH_RXD0, 1, 21, 1);
+static PAD_ST_CONF(ETH_RXD1, 1, 20, 1);
+static PAD_ST_CONF(ETH_CRS_DV, 1, 19, 1);
+static PAD_ST_CONF(ETH_RXER, 1, 18, 1);
+static PAD_ST_CONF(ETH_TXD1, 1, 17, 1);
+static PAD_ST_CONF(LVDS_OCP, 1, 16, 1);
+static PAD_ST_CONF(LVDS_OBP, 1, 15, 1);
+static PAD_ST_CONF(LVDS_OBN, 1, 14, 1);
+static PAD_ST_CONF(PCM1_OUT, 1, 12, 1);
+static PAD_ST_CONF(PCM1_CLK, 1, 11, 1);
+static PAD_ST_CONF(PCM1_IN, 1, 10, 1);
+static PAD_ST_CONF(PCM1_SYNC, 1, 9, 1);
+static PAD_ST_CONF(I2C1_SCLK, 1, 8, 1);
+static PAD_ST_CONF(I2C1_SDATA, 1, 7, 1);
+static PAD_ST_CONF(I2C2_SCLK, 1, 6, 1);
+static PAD_ST_CONF(I2C2_SDATA, 1, 5, 1);
+static PAD_ST_CONF(SPI0_MOSI, 1, 4, 1);
+static PAD_ST_CONF(SPI0_MISO, 1, 3, 1);
+static PAD_ST_CONF(SPI0_SS, 1, 2, 1);
+static PAD_ST_CONF(I2S_BCLK0, 1, 1, 1);
+static PAD_ST_CONF(I2S_MCLK0, 1, 0, 1);
+
+#define PAD_INFO(name)                                                 \
+       {                                                               \
+               .pad = name,                                            \
+               .pullctl = NULL,                                        \
+               .st = NULL,                                             \
+       }
+
+#define PAD_INFO_ST(name)                                              \
+       {                                                               \
+               .pad = name,                                            \
+               .pullctl = NULL,                                        \
+               .st = &name##_st_conf,                                  \
+       }
+
+#define PAD_INFO_PULLCTL(name)                                         \
+       {                                                               \
+               .pad = name,                                            \
+               .pullctl = &name##_pullctl_conf,                        \
+               .st = NULL,                                             \
+       }
+
+#define PAD_INFO_PULLCTL_ST(name)                                      \
+       {                                                               \
+               .pad = name,                                            \
+               .pullctl = &name##_pullctl_conf,                        \
+               .st = &name##_st_conf,                                  \
+       }
+
+/* Pad info table */
+static struct owl_padinfo s900_padinfo[NUM_PADS] = {
+       [ETH_TXD0] = PAD_INFO_ST(ETH_TXD0),
+       [ETH_TXD1] = PAD_INFO_ST(ETH_TXD1),
+       [ETH_TXEN] = PAD_INFO_ST(ETH_TXEN),
+       [ETH_RXER] = PAD_INFO_PULLCTL_ST(ETH_RXER),
+       [ETH_CRS_DV] = PAD_INFO_ST(ETH_CRS_DV),
+       [ETH_RXD1] = PAD_INFO_ST(ETH_RXD1),
+       [ETH_RXD0] = PAD_INFO_ST(ETH_RXD0),
+       [ETH_REF_CLK] = PAD_INFO_ST(ETH_REF_CLK),
+       [ETH_MDC] = PAD_INFO_ST(ETH_MDC),
+       [ETH_MDIO] = PAD_INFO(ETH_MDIO),
+       [SIRQ0] = PAD_INFO_PULLCTL(SIRQ0),
+       [SIRQ1] = PAD_INFO_PULLCTL(SIRQ1),
+       [SIRQ2] = PAD_INFO_PULLCTL(SIRQ2),
+       [I2S_D0] = PAD_INFO(I2S_D0),
+       [I2S_BCLK0] = PAD_INFO_ST(I2S_BCLK0),
+       [I2S_LRCLK0] = PAD_INFO_ST(I2S_LRCLK0),
+       [I2S_MCLK0] = PAD_INFO_ST(I2S_MCLK0),
+       [I2S_D1] = PAD_INFO_ST(I2S_D1),
+       [I2S_BCLK1] = PAD_INFO_ST(I2S_BCLK1),
+       [I2S_LRCLK1] = PAD_INFO_ST(I2S_LRCLK1),
+       [I2S_MCLK1] = PAD_INFO_ST(I2S_MCLK1),
+       [PCM1_IN] = PAD_INFO_PULLCTL_ST(PCM1_IN),
+       [PCM1_CLK] = PAD_INFO_ST(PCM1_CLK),
+       [PCM1_SYNC] = PAD_INFO_ST(PCM1_SYNC),
+       [PCM1_OUT] = PAD_INFO_PULLCTL_ST(PCM1_OUT),
+       [ERAM_A5] = PAD_INFO_PULLCTL_ST(ERAM_A5),
+       [ERAM_A6] = PAD_INFO_PULLCTL(ERAM_A6),
+       [ERAM_A7] = PAD_INFO_PULLCTL(ERAM_A7),
+       [ERAM_A8] = PAD_INFO(ERAM_A8),
+       [ERAM_A9] = PAD_INFO_ST(ERAM_A9),
+       [ERAM_A10] = PAD_INFO_PULLCTL(ERAM_A10),
+       [ERAM_A11] = PAD_INFO(ERAM_A11),
+       [LVDS_OEP] = PAD_INFO_ST(LVDS_OEP),
+       [LVDS_OEN] = PAD_INFO(LVDS_OEN),
+       [LVDS_ODP] = PAD_INFO(LVDS_ODP),
+       [LVDS_ODN] = PAD_INFO_ST(LVDS_ODN),
+       [LVDS_OCP] = PAD_INFO_ST(LVDS_OCP),
+       [LVDS_OCN] = PAD_INFO(LVDS_OCN),
+       [LVDS_OBP] = PAD_INFO_ST(LVDS_OBP),
+       [LVDS_OBN] = PAD_INFO_ST(LVDS_OBN),
+       [LVDS_OAP] = PAD_INFO_ST(LVDS_OAP),
+       [LVDS_OAN] = PAD_INFO(LVDS_OAN),
+       [LVDS_EEP] = PAD_INFO(LVDS_EEP),
+       [LVDS_EEN] = PAD_INFO(LVDS_EEN),
+       [LVDS_EDP] = PAD_INFO(LVDS_EDP),
+       [LVDS_EDN] = PAD_INFO(LVDS_EDN),
+       [LVDS_ECP] = PAD_INFO(LVDS_ECP),
+       [LVDS_ECN] = PAD_INFO(LVDS_ECN),
+       [LVDS_EBP] = PAD_INFO(LVDS_EBP),
+       [LVDS_EBN] = PAD_INFO(LVDS_EBN),
+       [LVDS_EAP] = PAD_INFO(LVDS_EAP),
+       [LVDS_EAN] = PAD_INFO(LVDS_EAN),
+       [SD0_D0] = PAD_INFO_PULLCTL(SD0_D0),
+       [SD0_D1] = PAD_INFO_PULLCTL(SD0_D1),
+       [SD0_D2] = PAD_INFO_PULLCTL(SD0_D2),
+       [SD0_D3] = PAD_INFO_PULLCTL(SD0_D3),
+       [SD1_D0] = PAD_INFO_PULLCTL(SD1_D0),
+       [SD1_D1] = PAD_INFO_PULLCTL(SD1_D1),
+       [SD1_D2] = PAD_INFO_PULLCTL(SD1_D2),
+       [SD1_D3] = PAD_INFO_PULLCTL(SD1_D3),
+       [SD0_CMD] = PAD_INFO_PULLCTL(SD0_CMD),
+       [SD0_CLK] = PAD_INFO_PULLCTL_ST(SD0_CLK),
+       [SD1_CMD] = PAD_INFO_PULLCTL(SD1_CMD),
+       [SD1_CLK] = PAD_INFO(SD1_CLK),
+       [SPI0_SCLK] = PAD_INFO_PULLCTL_ST(SPI0_SCLK),
+       [SPI0_SS] = PAD_INFO_ST(SPI0_SS),
+       [SPI0_MISO] = PAD_INFO_ST(SPI0_MISO),
+       [SPI0_MOSI] = PAD_INFO_PULLCTL_ST(SPI0_MOSI),
+       [UART0_RX] = PAD_INFO_PULLCTL_ST(UART0_RX),
+       [UART0_TX] = PAD_INFO_PULLCTL_ST(UART0_TX),
+       [UART2_RX] = PAD_INFO_ST(UART2_RX),
+       [UART2_TX] = PAD_INFO(UART2_TX),
+       [UART2_RTSB] = PAD_INFO_ST(UART2_RTSB),
+       [UART2_CTSB] = PAD_INFO_ST(UART2_CTSB),
+       [UART3_RX] = PAD_INFO_ST(UART3_RX),
+       [UART3_TX] = PAD_INFO(UART3_TX),
+       [UART3_RTSB] = PAD_INFO_ST(UART3_RTSB),
+       [UART3_CTSB] = PAD_INFO_ST(UART3_CTSB),
+       [UART4_RX] = PAD_INFO_PULLCTL_ST(UART4_RX),
+       [UART4_TX] = PAD_INFO_PULLCTL_ST(UART4_TX),
+       [I2C0_SCLK] = PAD_INFO_PULLCTL_ST(I2C0_SCLK),
+       [I2C0_SDATA] = PAD_INFO_PULLCTL_ST(I2C0_SDATA),
+       [I2C1_SCLK] = PAD_INFO_PULLCTL_ST(I2C1_SCLK),
+       [I2C1_SDATA] = PAD_INFO_PULLCTL_ST(I2C1_SDATA),
+       [I2C2_SCLK] = PAD_INFO_PULLCTL_ST(I2C2_SCLK),
+       [I2C2_SDATA] = PAD_INFO_PULLCTL_ST(I2C2_SDATA),
+       [CSI0_DN0] = PAD_INFO(CSI0_DN0),
+       [CSI0_DP0] = PAD_INFO(CSI0_DP0),
+       [CSI0_DN1] = PAD_INFO(CSI0_DN1),
+       [CSI0_DP1] = PAD_INFO(CSI0_DP1),
+       [CSI0_CN] = PAD_INFO(CSI0_CN),
+       [CSI0_CP] = PAD_INFO(CSI0_CP),
+       [CSI0_DN2] = PAD_INFO(CSI0_DN2),
+       [CSI0_DP2] = PAD_INFO(CSI0_DP2),
+       [CSI0_DN3] = PAD_INFO(CSI0_DN3),
+       [CSI0_DP3] = PAD_INFO(CSI0_DP3),
+       [DSI_DP3] = PAD_INFO(DSI_DP3),
+       [DSI_DN3] = PAD_INFO(DSI_DN3),
+       [DSI_DP1] = PAD_INFO(DSI_DP1),
+       [DSI_DN1] = PAD_INFO(DSI_DN1),
+       [DSI_CP] = PAD_INFO(DSI_CP),
+       [DSI_CN] = PAD_INFO(DSI_CN),
+       [DSI_DP0] = PAD_INFO(DSI_DP0),
+       [DSI_DN0] = PAD_INFO(DSI_DN0),
+       [DSI_DP2] = PAD_INFO(DSI_DP2),
+       [DSI_DN2] = PAD_INFO(DSI_DN2),
+       [SENSOR0_PCLK] = PAD_INFO(SENSOR0_PCLK),
+       [CSI1_DN0] = PAD_INFO(CSI1_DN0),
+       [CSI1_DP0] = PAD_INFO(CSI1_DP0),
+       [CSI1_DN1] = PAD_INFO(CSI1_DN1),
+       [CSI1_DP1] = PAD_INFO(CSI1_DP1),
+       [CSI1_CN] = PAD_INFO(CSI1_CN),
+       [CSI1_CP] = PAD_INFO(CSI1_CP),
+       [SENSOR0_CKOUT] = PAD_INFO(SENSOR0_CKOUT),
+       [NAND0_D0] = PAD_INFO_PULLCTL(NAND0_D0),
+       [NAND0_D1] = PAD_INFO_PULLCTL(NAND0_D1),
+       [NAND0_D2] = PAD_INFO_PULLCTL(NAND0_D2),
+       [NAND0_D3] = PAD_INFO_PULLCTL(NAND0_D3),
+       [NAND0_D4] = PAD_INFO_PULLCTL(NAND0_D4),
+       [NAND0_D5] = PAD_INFO_PULLCTL(NAND0_D5),
+       [NAND0_D6] = PAD_INFO_PULLCTL(NAND0_D6),
+       [NAND0_D7] = PAD_INFO_PULLCTL(NAND0_D7),
+       [NAND0_DQS] = PAD_INFO_PULLCTL(NAND0_DQS),
+       [NAND0_DQSN] = PAD_INFO_PULLCTL(NAND0_DQSN),
+       [NAND0_ALE] = PAD_INFO(NAND0_ALE),
+       [NAND0_CLE] = PAD_INFO(NAND0_CLE),
+       [NAND0_CEB0] = PAD_INFO(NAND0_CEB0),
+       [NAND0_CEB1] = PAD_INFO(NAND0_CEB1),
+       [NAND0_CEB2] = PAD_INFO(NAND0_CEB2),
+       [NAND0_CEB3] = PAD_INFO(NAND0_CEB3),
+       [NAND1_D0] = PAD_INFO_PULLCTL(NAND1_D0),
+       [NAND1_D1] = PAD_INFO_PULLCTL(NAND1_D1),
+       [NAND1_D2] = PAD_INFO_PULLCTL(NAND1_D2),
+       [NAND1_D3] = PAD_INFO_PULLCTL(NAND1_D3),
+       [NAND1_D4] = PAD_INFO_PULLCTL(NAND1_D4),
+       [NAND1_D5] = PAD_INFO_PULLCTL(NAND1_D5),
+       [NAND1_D6] = PAD_INFO_PULLCTL(NAND1_D6),
+       [NAND1_D7] = PAD_INFO_PULLCTL(NAND1_D7),
+       [NAND1_DQS] = PAD_INFO_PULLCTL(NAND1_DQS),
+       [NAND1_DQSN] = PAD_INFO_PULLCTL(NAND1_DQSN),
+       [NAND1_ALE] = PAD_INFO(NAND1_ALE),
+       [NAND1_CLE] = PAD_INFO(NAND1_CLE),
+       [NAND1_CEB0] = PAD_INFO(NAND1_CEB0),
+       [NAND1_CEB1] = PAD_INFO(NAND1_CEB1),
+       [NAND1_CEB2] = PAD_INFO(NAND1_CEB2),
+       [NAND1_CEB3] = PAD_INFO(NAND1_CEB3),
+       [SGPIO0] = PAD_INFO(SGPIO0),
+       [SGPIO1] = PAD_INFO(SGPIO1),
+       [SGPIO2] = PAD_INFO_PULLCTL_ST(SGPIO2),
+       [SGPIO3] = PAD_INFO_PULLCTL_ST(SGPIO3)
+};
+
+#define OWL_GPIO_PORT(port, base, count, _outen, _inen, _dat)  \
+       [OWL_GPIO_PORT_##port] = {                              \
+               .offset = base,                                 \
+               .pins = count,                                  \
+               .outen = _outen,                                \
+               .inen = _inen,                                  \
+               .dat = _dat,                                    \
+       }
+
+static const struct owl_gpio_port s900_gpio_ports[] = {
+       OWL_GPIO_PORT(A, 0x0000, 32, 0x0, 0x4, 0x8),
+       OWL_GPIO_PORT(B, 0x000C, 32, 0x0, 0x4, 0x8),
+       OWL_GPIO_PORT(C, 0x0018, 12, 0x0, 0x4, 0x8),
+       OWL_GPIO_PORT(D, 0x0024, 30, 0x0, 0x4, 0x8),
+       OWL_GPIO_PORT(E, 0x0030, 32, 0x0, 0x4, 0x8),
+       OWL_GPIO_PORT(F, 0x00F0, 8, 0x0, 0x4, 0x8)
+};
+
+static struct owl_pinctrl_soc_data s900_pinctrl_data = {
+       .padinfo = s900_padinfo,
+       .pins = (const struct pinctrl_pin_desc *)s900_pads,
+       .npins = ARRAY_SIZE(s900_pads),
+       .functions = s900_functions,
+       .nfunctions = ARRAY_SIZE(s900_functions),
+       .groups = s900_groups,
+       .ngroups = ARRAY_SIZE(s900_groups),
+       .ngpios = NUM_GPIOS,
+       .ports = s900_gpio_ports,
+       .nports = ARRAY_SIZE(s900_gpio_ports)
+};
+
+static int s900_pinctrl_probe(struct platform_device *pdev)
+{
+       return owl_pinctrl_probe(pdev, &s900_pinctrl_data);
+}
+
+static const struct of_device_id s900_pinctrl_of_match[] = {
+       { .compatible = "actions,s900-pinctrl", },
+       { }
+};
+
+static struct platform_driver s900_pinctrl_driver = {
+       .driver = {
+               .name = "pinctrl-s900",
+               .of_match_table = of_match_ptr(s900_pinctrl_of_match),
+       },
+       .probe = s900_pinctrl_probe,
+};
+
+static int __init s900_pinctrl_init(void)
+{
+       return platform_driver_register(&s900_pinctrl_driver);
+}
+arch_initcall(s900_pinctrl_init);
+
+static void __exit s900_pinctrl_exit(void)
+{
+       platform_driver_unregister(&s900_pinctrl_driver);
+}
+module_exit(s900_pinctrl_exit);
+
+MODULE_AUTHOR("Actions Semi Inc.");
+MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
+MODULE_DESCRIPTION("Actions Semi S900 SoC Pinctrl Driver");
+MODULE_LICENSE("GPL");
index e8c4e4f934a6d388bef3e77b89dc19d1e3a6db66..0f38d51f47c64cf33f4918918056c4da1da5dfd3 100644 (file)
@@ -20,6 +20,7 @@ config PINCTRL_BCM2835
        bool
        select PINMUX
        select PINCONF
+       select GENERIC_PINCONF
        select GPIOLIB_IRQCHIP
 
 config PINCTRL_IPROC_GPIO
index 785c366fd6d60b62bf976bd2d6b436c84e2b94f7..136ccaf53df8d88cc5cc409f01cea24b40c50edd 100644 (file)
 #include <linux/pinctrl/pinconf.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf-generic.h>
 #include <linux/platform_device.h>
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
+#include <dt-bindings/pinctrl/bcm2835.h>
 
 #define MODULE_NAME "pinctrl-bcm2835"
 #define BCM2835_NUM_GPIOS 54
 
 enum bcm2835_pinconf_param {
        /* argument: bcm2835_pinconf_pull */
-       BCM2835_PINCONF_PARAM_PULL,
+       BCM2835_PINCONF_PARAM_PULL = (PIN_CONFIG_END + 1),
 };
 
-#define BCM2835_PINCONF_PACK(_param_, _arg_) ((_param_) << 16 | (_arg_))
-#define BCM2835_PINCONF_UNPACK_PARAM(_conf_) ((_conf_) >> 16)
-#define BCM2835_PINCONF_UNPACK_ARG(_conf_) ((_conf_) & 0xffff)
-
 struct bcm2835_pinctrl {
        struct device *dev;
        void __iomem *base;
@@ -213,14 +211,6 @@ static const char * const bcm2835_gpio_groups[] = {
 };
 
 enum bcm2835_fsel {
-       BCM2835_FSEL_GPIO_IN = 0,
-       BCM2835_FSEL_GPIO_OUT = 1,
-       BCM2835_FSEL_ALT0 = 4,
-       BCM2835_FSEL_ALT1 = 5,
-       BCM2835_FSEL_ALT2 = 6,
-       BCM2835_FSEL_ALT3 = 7,
-       BCM2835_FSEL_ALT4 = 3,
-       BCM2835_FSEL_ALT5 = 2,
        BCM2835_FSEL_COUNT = 8,
        BCM2835_FSEL_MASK = 0x7,
 };
@@ -714,7 +704,7 @@ static int bcm2835_pctl_dt_node_to_map_pull(struct bcm2835_pinctrl *pc,
        configs = kzalloc(sizeof(*configs), GFP_KERNEL);
        if (!configs)
                return -ENOMEM;
-       configs[0] = BCM2835_PINCONF_PACK(BCM2835_PINCONF_PARAM_PULL, pull);
+       configs[0] = pinconf_to_config_packed(BCM2835_PINCONF_PARAM_PULL, pull);
 
        map->type = PIN_MAP_TYPE_CONFIGS_PIN;
        map->data.configs.group_or_pin = bcm2835_gpio_pins[pin].name;
@@ -727,7 +717,7 @@ static int bcm2835_pctl_dt_node_to_map_pull(struct bcm2835_pinctrl *pc,
 
 static int bcm2835_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
                struct device_node *np,
-               struct pinctrl_map **map, unsigned *num_maps)
+               struct pinctrl_map **map, unsigned int *num_maps)
 {
        struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
        struct property *pins, *funcs, *pulls;
@@ -736,6 +726,12 @@ static int bcm2835_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
        int i, err;
        u32 pin, func, pull;
 
+       /* Check for generic binding in this node */
+       err = pinconf_generic_dt_node_to_map_all(pctldev, np, map, num_maps);
+       if (err || *num_maps)
+               return err;
+
+       /* Generic binding did not find anything continue with legacy parse */
        pins = of_find_property(np, "brcm,pins", NULL);
        if (!pins) {
                dev_err(pc->dev, "%pOF: missing brcm,pins property\n", np);
@@ -917,37 +913,67 @@ static int bcm2835_pinconf_get(struct pinctrl_dev *pctldev,
        return -ENOTSUPP;
 }
 
+static void bcm2835_pull_config_set(struct bcm2835_pinctrl *pc,
+               unsigned int pin, unsigned int arg)
+{
+       u32 off, bit;
+
+       off = GPIO_REG_OFFSET(pin);
+       bit = GPIO_REG_SHIFT(pin);
+
+       bcm2835_gpio_wr(pc, GPPUD, arg & 3);
+       /*
+        * BCM2835 datasheet say to wait 150 cycles, but not of what.
+        * But the VideoCore firmware delay for this operation
+        * based nearly on the same amount of VPU cycles and this clock
+        * runs at 250 MHz.
+        */
+       udelay(1);
+       bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), BIT(bit));
+       udelay(1);
+       bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), 0);
+}
+
 static int bcm2835_pinconf_set(struct pinctrl_dev *pctldev,
-                       unsigned pin, unsigned long *configs,
-                       unsigned num_configs)
+                       unsigned int pin, unsigned long *configs,
+                       unsigned int num_configs)
 {
        struct bcm2835_pinctrl *pc = pinctrl_dev_get_drvdata(pctldev);
-       enum bcm2835_pinconf_param param;
-       u16 arg;
-       u32 off, bit;
+       u32 param, arg;
        int i;
 
        for (i = 0; i < num_configs; i++) {
-               param = BCM2835_PINCONF_UNPACK_PARAM(configs[i]);
-               arg = BCM2835_PINCONF_UNPACK_ARG(configs[i]);
+               param = pinconf_to_config_param(configs[i]);
+               arg = pinconf_to_config_argument(configs[i]);
 
-               if (param != BCM2835_PINCONF_PARAM_PULL)
-                       return -EINVAL;
+               switch (param) {
+               /* Set legacy brcm,pull */
+               case BCM2835_PINCONF_PARAM_PULL:
+                       bcm2835_pull_config_set(pc, pin, arg);
+                       break;
 
-               off = GPIO_REG_OFFSET(pin);
-               bit = GPIO_REG_SHIFT(pin);
+               /* Set pull generic bindings */
+               case PIN_CONFIG_BIAS_DISABLE:
+                       bcm2835_pull_config_set(pc, pin, BCM2835_PUD_OFF);
+                       break;
 
-               bcm2835_gpio_wr(pc, GPPUD, arg & 3);
-               /*
-                * BCM2835 datasheet say to wait 150 cycles, but not of what.
-                * But the VideoCore firmware delay for this operation
-                * based nearly on the same amount of VPU cycles and this clock
-                * runs at 250 MHz.
-                */
-               udelay(1);
-               bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), BIT(bit));
-               udelay(1);
-               bcm2835_gpio_wr(pc, GPPUDCLK0 + (off * 4), 0);
+               case PIN_CONFIG_BIAS_PULL_DOWN:
+                       bcm2835_pull_config_set(pc, pin, BCM2835_PUD_DOWN);
+                       break;
+
+               case PIN_CONFIG_BIAS_PULL_UP:
+                       bcm2835_pull_config_set(pc, pin, BCM2835_PUD_UP);
+                       break;
+
+               /* Set output-high or output-low */
+               case PIN_CONFIG_OUTPUT:
+                       bcm2835_gpio_set_bit(pc, arg ? GPSET0 : GPCLR0, pin);
+                       break;
+
+               default:
+                       return -EINVAL;
+
+               } /* switch param type */
        } /* for each config */
 
        return 0;
index bf2e17d0d6e41cb23cb31b83b69da6c1a56ccf18..acbd413340e8be3fcd381ab1cb66c9b642b96214 100644 (file)
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Marvell Berlin BG2 pinctrl driver.
  *
  * Copyright (C) 2014 Marvell Technology Group Ltd.
  *
  * Antoine Ténart <antoine.tenart@free-electrons.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
  */
 
 #include <linux/init.h>
index 9bee7bd1650fa18b718de0f63e8e43bab7e5dda8..c0f5d86d5d01d9970e7628de21012d6ff641bbf5 100644 (file)
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Marvell Berlin BG2CD pinctrl driver.
  *
  * Copyright (C) 2014 Marvell Technology Group Ltd.
  *
  * Antoine Ténart <antoine.tenart@free-electrons.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
  */
 
 #include <linux/init.h>
index eee6763f114c054493800442d70e06378032d7ed..20a3216ede07a7681e05bc2742815940ebc09a38 100644 (file)
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Marvell Berlin BG2Q pinctrl driver
  *
  * Copyright (C) 2014 Marvell Technology Group Ltd.
  *
  * Antoine Ténart <antoine.tenart@free-electrons.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
  */
 
 #include <linux/init.h>
index e6740656ee7c4e3c505356718ca9b412527d2e6e..6a7fe929a68bd5bcca4558347c1f70fef39fc950 100644 (file)
@@ -1,21 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Marvell berlin4ct pinctrl driver
  *
  * Copyright (C) 2015 Marvell Technology Group Ltd.
  *
  * Author: Jisheng Zhang <jszhang@marvell.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <linux/init.h>
index cc3bd2efafe3f0b4660f9df520b7a7f930161dbd..a620a8e8fa7877a62d7a258eb2732d9dbcf56266 100644 (file)
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Marvell Berlin SoC pinctrl core driver
  *
  * Copyright (C) 2014 Marvell Technology Group Ltd.
  *
  * Antoine Ténart <antoine.tenart@free-electrons.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
  */
 
 #include <linux/io.h>
index e9b30f95b03e3c72c68d0dd1ffa1957d930416c9..d7787754d1edf8642b37ef9eed9f8a41264fb7f5 100644 (file)
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Marvell Berlin SoC pinctrl driver.
  *
  * Copyright (C) 2014 Marvell Technology Group Ltd.
  *
  * Antoine Ténart <antoine.tenart@free-electrons.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
  */
 
 #ifndef __PINCTRL_BERLIN_H
index 24aaddd760a08d3c562da937fd895d037a2a4b51..e582a21cfe549640f8e2b07b67401644b89f3bea 100644 (file)
@@ -1,16 +1,11 @@
-/*
- * Core driver for the imx pin controller
- *
- * Copyright (C) 2012 Freescale Semiconductor, Inc.
- * Copyright (C) 2012 Linaro Ltd.
- *
- * Author: Dong Aisheng <dong.aisheng@linaro.org>
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Core driver for the imx pin controller
+//
+// Copyright (C) 2012 Freescale Semiconductor, Inc.
+// Copyright (C) 2012 Linaro Ltd.
+//
+// Author: Dong Aisheng <dong.aisheng@linaro.org>
 
 #include <linux/err.h>
 #include <linux/init.h>
@@ -371,7 +366,7 @@ static void imx_pinconf_dbg_show(struct pinctrl_dev *pctldev,
        unsigned long config;
 
        if (!pin_reg || pin_reg->conf_reg == -1) {
-               seq_printf(s, "N/A");
+               seq_puts(s, "N/A");
                return;
        }
 
@@ -390,7 +385,7 @@ static void imx_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
        if (group > pctldev->num_groups)
                return;
 
-       seq_printf(s, "\n");
+       seq_puts(s, "\n");
        grp = pinctrl_generic_get_group(pctldev, group);
        if (!grp)
                return;
@@ -414,11 +409,18 @@ static const struct pinconf_ops imx_pinconf_ops = {
 };
 
 /*
- * Each pin represented in fsl,pins consists of 5 u32 PIN_FUNC_ID and
- * 1 u32 CONFIG, so 24 types in total for each pin.
+ * Each pin represented in fsl,pins consists of a number of u32 PIN_FUNC_ID
+ * and 1 u32 CONFIG, the total size is PIN_FUNC_ID + CONFIG for each pin.
+ * For generic_pinconf case, there's no extra u32 CONFIG.
+ *
+ * PIN_FUNC_ID format:
+ * Default:
+ *     <mux_reg conf_reg input_reg mux_mode input_val>
+ * SHARE_MUX_CONF_REG:
+ *     <mux_conf_reg input_reg mux_mode input_val>
  */
 #define FSL_PIN_SIZE 24
-#define SHARE_FSL_PIN_SIZE 20
+#define FSL_PIN_SHARE_SIZE 20
 
 static int imx_pinctrl_parse_groups(struct device_node *np,
                                    struct group_desc *grp,
@@ -434,7 +436,7 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
        dev_dbg(ipctl->dev, "group(%d): %s\n", index, np->name);
 
        if (info->flags & SHARE_MUX_CONF_REG)
-               pin_size = SHARE_FSL_PIN_SIZE;
+               pin_size = FSL_PIN_SHARE_SIZE;
        else
                pin_size = FSL_PIN_SIZE;
 
@@ -617,7 +619,7 @@ static int imx_pinctrl_probe_dt(struct platform_device *pdev,
                nfuncs = 1;
        } else {
                nfuncs = of_get_child_count(np);
-               if (nfuncs <= 0) {
+               if (nfuncs == 0) {
                        dev_err(&pdev->dev, "no functions defined\n");
                        return -EINVAL;
                }
index 038e8c0e5b969a11fa2bd1d3aec62c5c319e4438..4b8225ccb03a4b6ceccbfc687349fbf11beb50ae 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * IMX pinmux core definitions
  *
@@ -5,11 +6,6 @@
  * Copyright (C) 2012 Linaro Ltd.
  *
  * Author: Dong Aisheng <dong.aisheng@linaro.org>
- *
- * 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.
  */
 
 #ifndef __DRIVERS_PINCTRL_IMX_H
index a4e9f430d45269c45367cacc1010087971c5596b..5af89de0ff02c91c44bedf866ba8728749653d1c 100644 (file)
@@ -1,19 +1,14 @@
-/*
- * Core driver for the imx pin controller in imx1/21/27
- *
- * Copyright (C) 2013 Pengutronix
- * Author: Markus Pargmann <mpa@pengutronix.de>
- *
- * Based on pinctrl-imx.c:
- *     Author: Dong Aisheng <dong.aisheng@linaro.org>
- *     Copyright (C) 2012 Freescale Semiconductor, Inc.
- *     Copyright (C) 2012 Linaro Ltd.
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Core driver for the imx pin controller in imx1/21/27
+//
+// Copyright (C) 2013 Pengutronix
+// Author: Markus Pargmann <mpa@pengutronix.de>
+//
+// Based on pinctrl-imx.c:
+//     Author: Dong Aisheng <dong.aisheng@linaro.org>
+//     Copyright (C) 2012 Freescale Semiconductor, Inc.
+//     Copyright (C) 2012 Linaro Ltd.
 
 #include <linux/bitops.h>
 #include <linux/err.h>
index fc8efc74873422a2cac3be2d3dabb0b4c4a662b6..faf770f13bc73127782f6d4b1191cb3dcacb19d5 100644 (file)
@@ -1,13 +1,8 @@
-/*
- * i.MX1 pinctrl driver based on imx pinmux core
- *
- * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// i.MX1 pinctrl driver based on imx pinmux core
+//
+// Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
 
 #include <linux/init.h>
 #include <linux/of.h>
index 174074308d6cfe5bec267b05a1d8a23f84183539..f1b9dabf76014a277c0c0a23cde315b8f28fcf21 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * IMX pinmux core definitions
  *
@@ -5,11 +6,6 @@
  * Copyright (C) 2012 Linaro Ltd.
  *
  * Author: Dong Aisheng <dong.aisheng@linaro.org>
- *
- * 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.
  */
 
 #ifndef __DRIVERS_PINCTRL_IMX1_H
index 73e26bc12f09743ff2837ff6a18b78c2489fa640..8a102275a053745abf50d0184b9756d59f44ce7d 100644 (file)
@@ -1,13 +1,8 @@
-/*
- * i.MX21 pinctrl driver based on imx pinmux core
- *
- * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// i.MX21 pinctrl driver based on imx pinmux core
+//
+// Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
 
 #include <linux/init.h>
 #include <linux/of.h>
index c9405685971b03753adc4d177028486bed36597e..144020764a4b036f271ca350fed414a19f278c8c 100644 (file)
@@ -1,16 +1,9 @@
-/*
- * Freescale i.MX23 pinctrl driver
- *
- * Author: Shawn Guo <shawn.guo@linaro.org>
- * Copyright 2012 Freescale Semiconductor, Inc.
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Freescale i.MX23 pinctrl driver
+//
+// Author: Shawn Guo <shawn.guo@linaro.org>
+// Copyright 2012 Freescale Semiconductor, Inc.
 
 #include <linux/init.h>
 #include <linux/of_device.h>
index db6d9d1382f979a624665b39f0cf8b6ab971e41c..a899a398b6bb5f19d78bc80ebe447772a2975984 100644 (file)
@@ -1,19 +1,15 @@
-/*
- * imx25 pinctrl driver.
- *
- * Copyright 2013 Eukréa Electromatique <denis@eukrea.com>
- *
- * This driver was mostly copied from the imx51 pinctrl driver which has:
- *
- * Copyright (C) 2012 Freescale Semiconductor, Inc.
- * Copyright (C) 2012 Linaro, Inc.
- *
- * Author: Denis Carikli <denis@eukrea.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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// imx25 pinctrl driver.
+//
+// Copyright 2013 Eukréa Electromatique <denis@eukrea.com>
+//
+// This driver was mostly copied from the imx51 pinctrl driver which has:
+//
+// Copyright (C) 2012 Freescale Semiconductor, Inc.
+// Copyright (C) 2012 Linaro, Inc.
+//
+// Author: Denis Carikli <denis@eukrea.com>
 
 #include <linux/err.h>
 #include <linux/init.h>
index e5992036fc6c02b2e6a352bfc20356d8df30ba22..b4dfc1676cbc6be1918686028057a1e30f52d01f 100644 (file)
@@ -1,15 +1,10 @@
-/*
- * imx27 pinctrl driver based on imx pinmux core
- *
- * Copyright (C) 2013 Pengutronix
- *
- * Author: Markus Pargmann <mpa@pengutronix.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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// imx27 pinctrl driver based on imx pinmux core
+//
+// Copyright (C) 2013 Pengutronix
+//
+// Author: Markus Pargmann <mpa@pengutronix.de>
 
 #include <linux/err.h>
 #include <linux/init.h>
index 87deb9ec938a7597626ed6fbf1eb9804cb17e9ac..13730dd193f1683cb77cd14b447c5898c5db2e0f 100644 (file)
@@ -1,16 +1,9 @@
-/*
- * Freescale i.MX28 pinctrl driver
- *
- * Author: Shawn Guo <shawn.guo@linaro.org>
- * Copyright 2012 Freescale Semiconductor, Inc.
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Freescale i.MX28 pinctrl driver
+//
+// Author: Shawn Guo <shawn.guo@linaro.org>
+// Copyright 2012 Freescale Semiconductor, Inc.
 
 #include <linux/init.h>
 #include <linux/of_device.h>
index 6927946ae4b59b39daa2b95212c3c6518ac7ee3a..871bb419e2f0cce9f1bc3b2a8e198db7d4904f9b 100644 (file)
@@ -1,17 +1,13 @@
-/*
- * imx35 pinctrl driver.
- *
- * This driver was mostly copied from the imx51 pinctrl driver which has:
- *
- * Copyright (C) 2012 Freescale Semiconductor, Inc.
- * Copyright (C) 2012 Linaro, Inc.
- *
- * Author: Dong Aisheng <dong.aisheng@linaro.org>
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// imx35 pinctrl driver.
+//
+// This driver was mostly copied from the imx51 pinctrl driver which has:
+//
+// Copyright (C) 2012 Freescale Semiconductor, Inc.
+// Copyright (C) 2012 Linaro, Inc.
+//
+// Author: Dong Aisheng <dong.aisheng@linaro.org>
 
 #include <linux/err.h>
 #include <linux/init.h>
index eb349b97290f9a6dcdd6fedcd1d53dd133f44f65..cf182c040e0b2e9215129e38e3e01701d4c00471 100644 (file)
@@ -1,15 +1,10 @@
-/*
- * imx50 pinctrl driver based on imx pinmux core
- *
- * Copyright (C) 2013 Greg Ungerer <gerg@uclinux.org>
- * Copyright (C) 2012 Freescale Semiconductor, Inc.
- * Copyright (C) 2012 Linaro, Inc.
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// imx50 pinctrl driver based on imx pinmux core
+//
+// Copyright (C) 2013 Greg Ungerer <gerg@uclinux.org>
+// Copyright (C) 2012 Freescale Semiconductor, Inc.
+// Copyright (C) 2012 Linaro, Inc.
 
 #include <linux/err.h>
 #include <linux/init.h>
index 49acd991b5fb3037323bedb3f72485139d98fd6a..e5c261e2bf1ebb2d589a8bbfa1581b82b776827c 100644 (file)
@@ -1,16 +1,11 @@
-/*
- * imx51 pinctrl driver based on imx pinmux core
- *
- * Copyright (C) 2012 Freescale Semiconductor, Inc.
- * Copyright (C) 2012 Linaro, Inc.
- *
- * Author: Dong Aisheng <dong.aisheng@linaro.org>
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// imx51 pinctrl driver based on imx pinmux core
+//
+// Copyright (C) 2012 Freescale Semiconductor, Inc.
+// Copyright (C) 2012 Linaro, Inc.
+//
+// Author: Dong Aisheng <dong.aisheng@linaro.org>
 
 #include <linux/err.h>
 #include <linux/init.h>
index 6dd0c60eaea4dc83158e30100c13b4bb64b2e619..64c97aaf20c7457ad0feb8354f82dfa85d7f4ac2 100644 (file)
@@ -1,16 +1,11 @@
-/*
- * imx53 pinctrl driver based on imx pinmux core
- *
- * Copyright (C) 2012 Freescale Semiconductor, Inc.
- * Copyright (C) 2012 Linaro, Inc.
- *
- * Author: Dong Aisheng <dong.aisheng@linaro.org>
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// imx53 pinctrl driver based on imx pinmux core
+//
+// Copyright (C) 2012 Freescale Semiconductor, Inc.
+// Copyright (C) 2012 Linaro, Inc.
+//
+// Author: Dong Aisheng <dong.aisheng@linaro.org>
 
 #include <linux/err.h>
 #include <linux/init.h>
index 91b85fc01de8be3f2bf894c0d6422195bbda49fb..0858b4d79ed2ca9f79020c907d64aad147decb01 100644 (file)
@@ -1,13 +1,9 @@
-/*
- * Freescale imx6dl pinctrl driver
- *
- * Author: Shawn Guo <shawn.guo@linaro.org>
- * Copyright (C) 2013 Freescale Semiconductor, Inc.
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Freescale imx6dl pinctrl driver
+//
+// Author: Shawn Guo <shawn.guo@linaro.org>
+// Copyright (C) 2013 Freescale Semiconductor, Inc.
 
 #include <linux/err.h>
 #include <linux/init.h>
index 5f653d69d0f51843f7406b267d42f26ac0a5dc5d..078ed6a331fd8b7a82250db3340f86d88d6c94eb 100644 (file)
@@ -1,16 +1,11 @@
-/*
- * imx6q pinctrl driver based on imx pinmux core
- *
- * Copyright (C) 2012 Freescale Semiconductor, Inc.
- * Copyright (C) 2012 Linaro, Inc.
- *
- * Author: Dong Aisheng <dong.aisheng@linaro.org>
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// imx6q pinctrl driver based on imx pinmux core
+//
+// Copyright (C) 2012 Freescale Semiconductor, Inc.
+// Copyright (C) 2012 Linaro, Inc.
+//
+// Author: Dong Aisheng <dong.aisheng@linaro.org>
 
 #include <linux/err.h>
 #include <linux/init.h>
index 1167dc273c045793247bed823ad1452b2a2a215f..9d2e6f987aa7f45328bbf6f679542ce04023f181 100644 (file)
@@ -1,13 +1,9 @@
-/*
- * Freescale imx6sl pinctrl driver
- *
- * Author: Shawn Guo <shawn.guo@linaro.org>
- * Copyright (C) 2013 Freescale Semiconductor, Inc.
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Freescale imx6sl pinctrl driver
+//
+// Author: Shawn Guo <shawn.guo@linaro.org>
+// Copyright (C) 2013 Freescale Semiconductor, Inc.
 
 #include <linux/err.h>
 #include <linux/init.h>
index 0fbea9cf536da54666d7bf75c7bbb90a0c7cfd39..0618f4d887fd9c88680d61efcb02be698e0a4f6c 100644 (file)
@@ -1,9 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
-/*
- * Copyright (C) 2016 Freescale Semiconductor, Inc.
- * Copyright 2017-2018 NXP.
- *
- */
+//
+// Copyright (C) 2016 Freescale Semiconductor, Inc.
+// Copyright 2017-2018 NXP.
 
 #include <linux/err.h>
 #include <linux/init.h>
index 15ea56c75f687daddb5d1265d67e7cb308363725..c7e2b1f94f01daca9c9139558280c7ef6c320b55 100644 (file)
@@ -1,13 +1,9 @@
-/*
- * Freescale imx6sx pinctrl driver
- *
- * Author: Anson Huang <Anson.Huang@freescale.com>
- * Copyright (C) 2014 Freescale Semiconductor, Inc.
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Freescale imx6sx pinctrl driver
+//
+// Author: Anson Huang <Anson.Huang@freescale.com>
+// Copyright (C) 2014 Freescale Semiconductor, Inc.
 
 #include <linux/err.h>
 #include <linux/init.h>
index 4580717ade19f8f527a7ee294972f7a144c3ba22..7e37627c63f5fa8e474d03d06c45cd79a07542e2 100644 (file)
@@ -1,13 +1,9 @@
-/*
- * Freescale imx6ul pinctrl driver
- *
- * Author: Anson Huang <Anson.Huang@freescale.com>
- * Copyright (C) 2015 Freescale Semiconductor, Inc.
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Freescale imx6ul pinctrl driver
+//
+// Author: Anson Huang <Anson.Huang@freescale.com>
+// Copyright (C) 2015 Freescale Semiconductor, Inc.
 
 #include <linux/err.h>
 #include <linux/init.h>
index 0b0a2f33b06a969ff132236bb7afed0e6f8e337e..369d3e59fdd69f60ff0d570be32542e8c90e85be 100644 (file)
@@ -1,13 +1,9 @@
-/*
- * Freescale imx7d pinctrl driver
- *
- * Author: Anson Huang <Anson.Huang@freescale.com>
- * Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Freescale imx7d pinctrl driver
+//
+// Author: Anson Huang <Anson.Huang@freescale.com>
+// Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
 
 #include <linux/err.h>
 #include <linux/init.h>
index f363e45fd2465f6add5b57cb36178e7a8f80cff1..f521bdb53f62d6a658cc90cdee169d52aa21d51d 100644 (file)
@@ -1,14 +1,9 @@
-/*
- * Copyright (C) 2016 Freescale Semiconductor, Inc.
- * Copyright (C) 2017 NXP
- *
- * Author: Dong Aisheng <aisheng.dong@nxp.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.
- *
- */
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (C) 2016 Freescale Semiconductor, Inc.
+// Copyright (C) 2017 NXP
+//
+// Author: Dong Aisheng <aisheng.dong@nxp.com>
 
 #include <linux/err.h>
 #include <linux/init.h>
index 6852010a6d708b5010555cbb141bf57ac31de077..594f3e5ce9a9e81d63e7d60dbd35cca9e97d46f7 100644 (file)
@@ -1,13 +1,6 @@
-/*
- * Copyright 2012 Freescale Semiconductor, Inc.
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright 2012 Freescale Semiconductor, Inc.
 
 #include <linux/err.h>
 #include <linux/init.h>
index 34dbf75208dc7beb854e82607b59d2ed1030c71a..ab9f834b03e6bfd37e16888f4857332ad7a465ab 100644 (file)
@@ -1,12 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * Copyright 2012 Freescale Semiconductor, Inc.
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
  */
 
 #ifndef __PINCTRL_MXS_H
index c078f859ae15e7dcca2f93edce91672d96cb20f2..37602b053ed287b3a511b573b8228bbef92ad0cc 100644 (file)
@@ -1,13 +1,8 @@
-/*
- * VF610 pinctrl driver based on imx pinmux and pinconf core
- *
- * Copyright 2013 Freescale Semiconductor, Inc.
- *
- * 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.
- */
+// SPDX-License-Identifier: GPL-2.0+
+//
+// VF610 pinctrl driver based on imx pinmux and pinconf core
+//
+// Copyright 2013 Freescale Semiconductor, Inc.
 
 #include <linux/err.h>
 #include <linux/init.h>
index fee9225ca559e6860bf28adc7d746d56fb499c34..0f1019ae399301095152296ed792ae4ae3c3044d 100644 (file)
@@ -1527,6 +1527,7 @@ static const struct dmi_system_id chv_no_valid_mask[] = {
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
                        DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_Strago"),
+                       DMI_MATCH(DMI_BOARD_VERSION, "1.0"),
                },
        },
        {
@@ -1534,6 +1535,7 @@ static const struct dmi_system_id chv_no_valid_mask[] = {
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "HP"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Setzer"),
+                       DMI_MATCH(DMI_BOARD_VERSION, "1.0"),
                },
        },
        {
@@ -1541,6 +1543,7 @@ static const struct dmi_system_id chv_no_valid_mask[] = {
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Cyan"),
+                       DMI_MATCH(DMI_BOARD_VERSION, "1.0"),
                },
        },
        {
@@ -1548,6 +1551,7 @@ static const struct dmi_system_id chv_no_valid_mask[] = {
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Celes"),
+                       DMI_MATCH(DMI_BOARD_VERSION, "1.0"),
                },
        },
        {}
index 862c5dbc6977496ac495ff37a592581a6f635209..9905dc672f6bea8acbca58357b029dac219dbc83 100644 (file)
@@ -1,12 +1,18 @@
 menu "MediaTek pinctrl drivers"
        depends on ARCH_MEDIATEK || COMPILE_TEST
 
+config EINT_MTK
+       bool "MediaTek External Interrupt Support"
+       depends on PINCTRL_MTK || PINCTRL_MT7622 || COMPILE_TEST
+       select IRQ_DOMAIN
+
 config PINCTRL_MTK
        bool
        depends on OF
        select PINMUX
        select GENERIC_PINCONF
        select GPIOLIB
+       select EINT_MTK
        select OF_GPIO
 
 # For ARMv7 SoCs
index 7959e773533f4cd0cfecdc28cdb1e5cd6bb163fe..3de7156df3454165b9fca68064772506a8e68602 100644 (file)
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 # Core
+obj-$(CONFIG_EINT_MTK)         += mtk-eint.o
 obj-$(CONFIG_PINCTRL_MTK)      += pinctrl-mtk-common.o
 
 # SoC Drivers
diff --git a/drivers/pinctrl/mediatek/mtk-eint.c b/drivers/pinctrl/mediatek/mtk-eint.c
new file mode 100644 (file)
index 0000000..30f3316
--- /dev/null
@@ -0,0 +1,492 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2014-2018 MediaTek Inc.
+
+/*
+ * Library for MediaTek External Interrupt Support
+ *
+ * Author: Maoguang Meng <maoguang.meng@mediatek.com>
+ *        Sean Wang <sean.wang@mediatek.com>
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+
+#include "mtk-eint.h"
+
+#define MTK_EINT_EDGE_SENSITIVE           0
+#define MTK_EINT_LEVEL_SENSITIVE          1
+#define MTK_EINT_DBNC_SET_DBNC_BITS      4
+#define MTK_EINT_DBNC_RST_BIT            (0x1 << 1)
+#define MTK_EINT_DBNC_SET_EN             (0x1 << 0)
+
+static const struct mtk_eint_regs mtk_generic_eint_regs = {
+       .stat      = 0x000,
+       .ack       = 0x040,
+       .mask      = 0x080,
+       .mask_set  = 0x0c0,
+       .mask_clr  = 0x100,
+       .sens      = 0x140,
+       .sens_set  = 0x180,
+       .sens_clr  = 0x1c0,
+       .soft      = 0x200,
+       .soft_set  = 0x240,
+       .soft_clr  = 0x280,
+       .pol       = 0x300,
+       .pol_set   = 0x340,
+       .pol_clr   = 0x380,
+       .dom_en    = 0x400,
+       .dbnc_ctrl = 0x500,
+       .dbnc_set  = 0x600,
+       .dbnc_clr  = 0x700,
+};
+
+static void __iomem *mtk_eint_get_offset(struct mtk_eint *eint,
+                                        unsigned int eint_num,
+                                        unsigned int offset)
+{
+       unsigned int eint_base = 0;
+       void __iomem *reg;
+
+       if (eint_num >= eint->hw->ap_num)
+               eint_base = eint->hw->ap_num;
+
+       reg = eint->base + offset + ((eint_num - eint_base) / 32) * 4;
+
+       return reg;
+}
+
+static unsigned int mtk_eint_can_en_debounce(struct mtk_eint *eint,
+                                            unsigned int eint_num)
+{
+       unsigned int sens;
+       unsigned int bit = BIT(eint_num % 32);
+       void __iomem *reg = mtk_eint_get_offset(eint, eint_num,
+                                               eint->regs->sens);
+
+       if (readl(reg) & bit)
+               sens = MTK_EINT_LEVEL_SENSITIVE;
+       else
+               sens = MTK_EINT_EDGE_SENSITIVE;
+
+       if (eint_num < eint->hw->db_cnt && sens != MTK_EINT_EDGE_SENSITIVE)
+               return 1;
+       else
+               return 0;
+}
+
+static int mtk_eint_flip_edge(struct mtk_eint *eint, int hwirq)
+{
+       int start_level, curr_level;
+       unsigned int reg_offset;
+       u32 mask = BIT(hwirq & 0x1f);
+       u32 port = (hwirq >> 5) & eint->hw->port_mask;
+       void __iomem *reg = eint->base + (port << 2);
+
+       curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl, hwirq);
+
+       do {
+               start_level = curr_level;
+               if (start_level)
+                       reg_offset = eint->regs->pol_clr;
+               else
+                       reg_offset = eint->regs->pol_set;
+               writel(mask, reg + reg_offset);
+
+               curr_level = eint->gpio_xlate->get_gpio_state(eint->pctl,
+                                                             hwirq);
+       } while (start_level != curr_level);
+
+       return start_level;
+}
+
+static void mtk_eint_mask(struct irq_data *d)
+{
+       struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
+       u32 mask = BIT(d->hwirq & 0x1f);
+       void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
+                                               eint->regs->mask_set);
+
+       writel(mask, reg);
+}
+
+static void mtk_eint_unmask(struct irq_data *d)
+{
+       struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
+       u32 mask = BIT(d->hwirq & 0x1f);
+       void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
+                                               eint->regs->mask_clr);
+
+       writel(mask, reg);
+
+       if (eint->dual_edge[d->hwirq])
+               mtk_eint_flip_edge(eint, d->hwirq);
+}
+
+static unsigned int mtk_eint_get_mask(struct mtk_eint *eint,
+                                     unsigned int eint_num)
+{
+       unsigned int bit = BIT(eint_num % 32);
+       void __iomem *reg = mtk_eint_get_offset(eint, eint_num,
+                                               eint->regs->mask);
+
+       return !!(readl(reg) & bit);
+}
+
+static void mtk_eint_ack(struct irq_data *d)
+{
+       struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
+       u32 mask = BIT(d->hwirq & 0x1f);
+       void __iomem *reg = mtk_eint_get_offset(eint, d->hwirq,
+                                               eint->regs->ack);
+
+       writel(mask, reg);
+}
+
+static int mtk_eint_set_type(struct irq_data *d, unsigned int type)
+{
+       struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
+       u32 mask = BIT(d->hwirq & 0x1f);
+       void __iomem *reg;
+
+       if (((type & IRQ_TYPE_EDGE_BOTH) && (type & IRQ_TYPE_LEVEL_MASK)) ||
+           ((type & IRQ_TYPE_LEVEL_MASK) == IRQ_TYPE_LEVEL_MASK)) {
+               dev_err(eint->dev,
+                       "Can't configure IRQ%d (EINT%lu) for type 0x%X\n",
+                       d->irq, d->hwirq, type);
+               return -EINVAL;
+       }
+
+       if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
+               eint->dual_edge[d->hwirq] = 1;
+       else
+               eint->dual_edge[d->hwirq] = 0;
+
+       if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING)) {
+               reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->pol_clr);
+               writel(mask, reg);
+       } else {
+               reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->pol_set);
+               writel(mask, reg);
+       }
+
+       if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
+               reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->sens_clr);
+               writel(mask, reg);
+       } else {
+               reg = mtk_eint_get_offset(eint, d->hwirq, eint->regs->sens_set);
+               writel(mask, reg);
+       }
+
+       if (eint->dual_edge[d->hwirq])
+               mtk_eint_flip_edge(eint, d->hwirq);
+
+       return 0;
+}
+
+static int mtk_eint_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+       struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
+       int shift = d->hwirq & 0x1f;
+       int reg = d->hwirq >> 5;
+
+       if (on)
+               eint->wake_mask[reg] |= BIT(shift);
+       else
+               eint->wake_mask[reg] &= ~BIT(shift);
+
+       return 0;
+}
+
+static void mtk_eint_chip_write_mask(const struct mtk_eint *eint,
+                                    void __iomem *base, u32 *buf)
+{
+       int port;
+       void __iomem *reg;
+
+       for (port = 0; port < eint->hw->ports; port++) {
+               reg = base + (port << 2);
+               writel_relaxed(~buf[port], reg + eint->regs->mask_set);
+               writel_relaxed(buf[port], reg + eint->regs->mask_clr);
+       }
+}
+
+static void mtk_eint_chip_read_mask(const struct mtk_eint *eint,
+                                   void __iomem *base, u32 *buf)
+{
+       int port;
+       void __iomem *reg;
+
+       for (port = 0; port < eint->hw->ports; port++) {
+               reg = base + eint->regs->mask + (port << 2);
+               buf[port] = ~readl_relaxed(reg);
+               /* Mask is 0 when irq is enabled, and 1 when disabled. */
+       }
+}
+
+static int mtk_eint_irq_request_resources(struct irq_data *d)
+{
+       struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
+       struct gpio_chip *gpio_c;
+       unsigned int gpio_n;
+       int err;
+
+       err = eint->gpio_xlate->get_gpio_n(eint->pctl, d->hwirq,
+                                          &gpio_n, &gpio_c);
+       if (err < 0) {
+               dev_err(eint->dev, "Can not find pin\n");
+               return err;
+       }
+
+       err = gpiochip_lock_as_irq(gpio_c, gpio_n);
+       if (err < 0) {
+               dev_err(eint->dev, "unable to lock HW IRQ %lu for IRQ\n",
+                       irqd_to_hwirq(d));
+               return err;
+       }
+
+       err = eint->gpio_xlate->set_gpio_as_eint(eint->pctl, d->hwirq);
+       if (err < 0) {
+               dev_err(eint->dev, "Can not eint mode\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static void mtk_eint_irq_release_resources(struct irq_data *d)
+{
+       struct mtk_eint *eint = irq_data_get_irq_chip_data(d);
+       struct gpio_chip *gpio_c;
+       unsigned int gpio_n;
+
+       eint->gpio_xlate->get_gpio_n(eint->pctl, d->hwirq, &gpio_n,
+                                    &gpio_c);
+
+       gpiochip_unlock_as_irq(gpio_c, gpio_n);
+}
+
+static struct irq_chip mtk_eint_irq_chip = {
+       .name = "mt-eint",
+       .irq_disable = mtk_eint_mask,
+       .irq_mask = mtk_eint_mask,
+       .irq_unmask = mtk_eint_unmask,
+       .irq_ack = mtk_eint_ack,
+       .irq_set_type = mtk_eint_set_type,
+       .irq_set_wake = mtk_eint_irq_set_wake,
+       .irq_request_resources = mtk_eint_irq_request_resources,
+       .irq_release_resources = mtk_eint_irq_release_resources,
+};
+
+static unsigned int mtk_eint_hw_init(struct mtk_eint *eint)
+{
+       void __iomem *reg = eint->base + eint->regs->dom_en;
+       unsigned int i;
+
+       for (i = 0; i < eint->hw->ap_num; i += 32) {
+               writel(0xffffffff, reg);
+               reg += 4;
+       }
+
+       return 0;
+}
+
+static inline void
+mtk_eint_debounce_process(struct mtk_eint *eint, int index)
+{
+       unsigned int rst, ctrl_offset;
+       unsigned int bit, dbnc;
+
+       ctrl_offset = (index / 4) * 4 + eint->regs->dbnc_ctrl;
+       dbnc = readl(eint->base + ctrl_offset);
+       bit = MTK_EINT_DBNC_SET_EN << ((index % 4) * 8);
+       if ((bit & dbnc) > 0) {
+               ctrl_offset = (index / 4) * 4 + eint->regs->dbnc_set;
+               rst = MTK_EINT_DBNC_RST_BIT << ((index % 4) * 8);
+               writel(rst, eint->base + ctrl_offset);
+       }
+}
+
+static void mtk_eint_irq_handler(struct irq_desc *desc)
+{
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       struct mtk_eint *eint = irq_desc_get_handler_data(desc);
+       unsigned int status, eint_num;
+       int offset, index, virq;
+       void __iomem *reg =  mtk_eint_get_offset(eint, 0, eint->regs->stat);
+       int dual_edge, start_level, curr_level;
+
+       chained_irq_enter(chip, desc);
+       for (eint_num = 0; eint_num < eint->hw->ap_num; eint_num += 32,
+            reg += 4) {
+               status = readl(reg);
+               while (status) {
+                       offset = __ffs(status);
+                       index = eint_num + offset;
+                       virq = irq_find_mapping(eint->domain, index);
+                       status &= ~BIT(offset);
+
+                       dual_edge = eint->dual_edge[index];
+                       if (dual_edge) {
+                               /*
+                                * Clear soft-irq in case we raised it last
+                                * time.
+                                */
+                               writel(BIT(offset), reg - eint->regs->stat +
+                                      eint->regs->soft_clr);
+
+                               start_level =
+                               eint->gpio_xlate->get_gpio_state(eint->pctl,
+                                                                index);
+                       }
+
+                       generic_handle_irq(virq);
+
+                       if (dual_edge) {
+                               curr_level = mtk_eint_flip_edge(eint, index);
+
+                               /*
+                                * If level changed, we might lost one edge
+                                * interrupt, raised it through soft-irq.
+                                */
+                               if (start_level != curr_level)
+                                       writel(BIT(offset), reg -
+                                              eint->regs->stat +
+                                              eint->regs->soft_set);
+                       }
+
+                       if (index < eint->hw->db_cnt)
+                               mtk_eint_debounce_process(eint, index);
+               }
+       }
+       chained_irq_exit(chip, desc);
+}
+
+int mtk_eint_do_suspend(struct mtk_eint *eint)
+{
+       mtk_eint_chip_read_mask(eint, eint->base, eint->cur_mask);
+       mtk_eint_chip_write_mask(eint, eint->base, eint->wake_mask);
+
+       return 0;
+}
+
+int mtk_eint_do_resume(struct mtk_eint *eint)
+{
+       mtk_eint_chip_write_mask(eint, eint->base, eint->cur_mask);
+
+       return 0;
+}
+
+int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_num,
+                         unsigned int debounce)
+{
+       int virq, eint_offset;
+       unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask,
+                    dbnc;
+       static const unsigned int debounce_time[] = {500, 1000, 16000, 32000,
+                                                    64000, 128000, 256000};
+       struct irq_data *d;
+
+       virq = irq_find_mapping(eint->domain, eint_num);
+       eint_offset = (eint_num % 4) * 8;
+       d = irq_get_irq_data(virq);
+
+       set_offset = (eint_num / 4) * 4 + eint->regs->dbnc_set;
+       clr_offset = (eint_num / 4) * 4 + eint->regs->dbnc_clr;
+
+       if (!mtk_eint_can_en_debounce(eint, eint_num))
+               return -EINVAL;
+
+       dbnc = ARRAY_SIZE(debounce_time);
+       for (i = 0; i < ARRAY_SIZE(debounce_time); i++) {
+               if (debounce <= debounce_time[i]) {
+                       dbnc = i;
+                       break;
+               }
+       }
+
+       if (!mtk_eint_get_mask(eint, eint_num)) {
+               mtk_eint_mask(d);
+               unmask = 1;
+       } else {
+               unmask = 0;
+       }
+
+       clr_bit = 0xff << eint_offset;
+       writel(clr_bit, eint->base + clr_offset);
+
+       bit = ((dbnc << MTK_EINT_DBNC_SET_DBNC_BITS) | MTK_EINT_DBNC_SET_EN) <<
+               eint_offset;
+       rst = MTK_EINT_DBNC_RST_BIT << eint_offset;
+       writel(rst | bit, eint->base + set_offset);
+
+       /*
+        * Delay a while (more than 2T) to wait for hw debounce counter reset
+        * work correctly.
+        */
+       udelay(1);
+       if (unmask == 1)
+               mtk_eint_unmask(d);
+
+       return 0;
+}
+
+int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
+{
+       int irq;
+
+       irq = irq_find_mapping(eint->domain, eint_n);
+       if (!irq)
+               return -EINVAL;
+
+       return irq;
+}
+
+int mtk_eint_do_init(struct mtk_eint *eint)
+{
+       int i;
+
+       /* If clients don't assign a specific regs, let's use generic one */
+       if (!eint->regs)
+               eint->regs = &mtk_generic_eint_regs;
+
+       eint->wake_mask = devm_kcalloc(eint->dev, eint->hw->ports,
+                                      sizeof(*eint->wake_mask), GFP_KERNEL);
+       if (!eint->wake_mask)
+               return -ENOMEM;
+
+       eint->cur_mask = devm_kcalloc(eint->dev, eint->hw->ports,
+                                     sizeof(*eint->cur_mask), GFP_KERNEL);
+       if (!eint->cur_mask)
+               return -ENOMEM;
+
+       eint->dual_edge = devm_kcalloc(eint->dev, eint->hw->ap_num,
+                                      sizeof(int), GFP_KERNEL);
+       if (!eint->dual_edge)
+               return -ENOMEM;
+
+       eint->domain = irq_domain_add_linear(eint->dev->of_node,
+                                            eint->hw->ap_num,
+                                            &irq_domain_simple_ops, NULL);
+       if (!eint->domain)
+               return -ENOMEM;
+
+       mtk_eint_hw_init(eint);
+       for (i = 0; i < eint->hw->ap_num; i++) {
+               int virq = irq_create_mapping(eint->domain, i);
+
+               irq_set_chip_and_handler(virq, &mtk_eint_irq_chip,
+                                        handle_level_irq);
+               irq_set_chip_data(virq, eint);
+       }
+
+       irq_set_chained_handler_and_data(eint->irq, mtk_eint_irq_handler,
+                                        eint);
+
+       return 0;
+}
diff --git a/drivers/pinctrl/mediatek/mtk-eint.h b/drivers/pinctrl/mediatek/mtk-eint.h
new file mode 100644 (file)
index 0000000..c286a9b
--- /dev/null
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2014-2018 MediaTek Inc.
+ *
+ * Author: Maoguang Meng <maoguang.meng@mediatek.com>
+ *        Sean Wang <sean.wang@mediatek.com>
+ *
+ */
+#ifndef __MTK_EINT_H
+#define __MTK_EINT_H
+
+#include <linux/irqdomain.h>
+
+struct mtk_eint_regs {
+       unsigned int    stat;
+       unsigned int    ack;
+       unsigned int    mask;
+       unsigned int    mask_set;
+       unsigned int    mask_clr;
+       unsigned int    sens;
+       unsigned int    sens_set;
+       unsigned int    sens_clr;
+       unsigned int    soft;
+       unsigned int    soft_set;
+       unsigned int    soft_clr;
+       unsigned int    pol;
+       unsigned int    pol_set;
+       unsigned int    pol_clr;
+       unsigned int    dom_en;
+       unsigned int    dbnc_ctrl;
+       unsigned int    dbnc_set;
+       unsigned int    dbnc_clr;
+};
+
+struct mtk_eint_hw {
+       u8              port_mask;
+       u8              ports;
+       unsigned int    ap_num;
+       unsigned int    db_cnt;
+};
+
+struct mtk_eint;
+
+struct mtk_eint_xt {
+       int (*get_gpio_n)(void *data, unsigned long eint_n,
+                         unsigned int *gpio_n,
+                         struct gpio_chip **gpio_chip);
+       int (*get_gpio_state)(void *data, unsigned long eint_n);
+       int (*set_gpio_as_eint)(void *data, unsigned long eint_n);
+};
+
+struct mtk_eint {
+       struct device *dev;
+       void __iomem *base;
+       struct irq_domain *domain;
+       int irq;
+
+       int *dual_edge;
+       u32 *wake_mask;
+       u32 *cur_mask;
+
+       /* Used to fit into various EINT device */
+       const struct mtk_eint_hw *hw;
+       const struct mtk_eint_regs *regs;
+
+       /* Used to fit into various pinctrl device */
+       void *pctl;
+       const struct mtk_eint_xt *gpio_xlate;
+};
+
+#if IS_ENABLED(CONFIG_EINT_MTK)
+int mtk_eint_do_init(struct mtk_eint *eint);
+int mtk_eint_do_suspend(struct mtk_eint *eint);
+int mtk_eint_do_resume(struct mtk_eint *eint);
+int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_n,
+                         unsigned int debounce);
+int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n);
+
+#else
+static inline int mtk_eint_do_init(struct mtk_eint *eint)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline int mtk_eint_do_suspend(struct mtk_eint *eint)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline int mtk_eint_do_resume(struct mtk_eint *eint)
+{
+       return -EOPNOTSUPP;
+}
+
+int mtk_eint_set_debounce(struct mtk_eint *eint, unsigned long eint_n,
+                         unsigned int debounce)
+{
+       return -EOPNOTSUPP;
+}
+
+int mtk_eint_find_irq(struct mtk_eint *eint, unsigned long eint_n)
+{
+       return -EOPNOTSUPP;
+}
+#endif
+#endif /* __MTK_EINT_H */
index f86f3b379607dbb9cf0b7084af7a1c87b57162dc..e91c314f3b750e694d4d674b2866cbd428c96028 100644 (file)
@@ -531,31 +531,12 @@ static const struct mtk_pinctrl_devdata mt2701_pinctrl_data = {
        .port_shf = 4,
        .port_mask = 0x1f,
        .port_align = 4,
-       .eint_offsets = {
-               .name = "mt2701_eint",
-               .stat      = 0x000,
-               .ack       = 0x040,
-               .mask      = 0x080,
-               .mask_set  = 0x0c0,
-               .mask_clr  = 0x100,
-               .sens      = 0x140,
-               .sens_set  = 0x180,
-               .sens_clr  = 0x1c0,
-               .soft      = 0x200,
-               .soft_set  = 0x240,
-               .soft_clr  = 0x280,
-               .pol       = 0x300,
-               .pol_set   = 0x340,
-               .pol_clr   = 0x380,
-               .dom_en    = 0x400,
-               .dbnc_ctrl = 0x500,
-               .dbnc_set  = 0x600,
-               .dbnc_clr  = 0x700,
+       .eint_hw = {
                .port_mask = 6,
                .ports     = 6,
+               .ap_num    = 169,
+               .db_cnt    = 16,
        },
-       .ap_num = 169,
-       .db_cnt = 16,
 };
 
 static int mt2701_pinctrl_probe(struct platform_device *pdev)
index 81e11f9e70f11d0060d20b538f2a0a8506793b62..8398d55c01cb49b82d1097853ab3ae0646eea36d 100644 (file)
@@ -576,31 +576,12 @@ static const struct mtk_pinctrl_devdata mt2712_pinctrl_data = {
        .port_shf = 4,
        .port_mask = 0xf,
        .port_align = 4,
-       .eint_offsets = {
-               .name = "mt2712_eint",
-               .stat      = 0x000,
-               .ack       = 0x040,
-               .mask      = 0x080,
-               .mask_set  = 0x0c0,
-               .mask_clr  = 0x100,
-               .sens      = 0x140,
-               .sens_set  = 0x180,
-               .sens_clr  = 0x1c0,
-               .soft      = 0x200,
-               .soft_set  = 0x240,
-               .soft_clr  = 0x280,
-               .pol       = 0x300,
-               .pol_set   = 0x340,
-               .pol_clr   = 0x380,
-               .dom_en    = 0x400,
-               .dbnc_ctrl = 0x500,
-               .dbnc_set  = 0x600,
-               .dbnc_clr  = 0x700,
+       .eint_hw = {
                .port_mask = 0xf,
                .ports     = 8,
+               .ap_num    = 229,
+               .db_cnt    = 40,
        },
-       .ap_num = 229,
-       .db_cnt = 40,
 };
 
 static int mt2712_pinctrl_probe(struct platform_device *pdev)
index 06e8406c444032f5ca3b9bb8ec809f2ec02ddb62..ad6da1184c9f0b1117275df587f502d78abbe904 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/mfd/syscon.h>
 #include <linux/of.h>
+#include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -30,6 +31,7 @@
 #include "../core.h"
 #include "../pinconf.h"
 #include "../pinmux.h"
+#include "mtk-eint.h"
 
 #define PINCTRL_PINCTRL_DEV            KBUILD_MODNAME
 #define MTK_RANGE(_a)          { .range = (_a), .nranges = ARRAY_SIZE(_a), }
@@ -123,6 +125,8 @@ struct mtk_pin_soc {
        unsigned int                    ngrps;
        const struct function_desc      *funcs;
        unsigned int                    nfuncs;
+       const struct mtk_eint_regs      *eint_regs;
+       const struct mtk_eint_hw        *eint_hw;
 };
 
 struct mtk_pinctrl {
@@ -131,6 +135,7 @@ struct mtk_pinctrl {
        struct device                   *dev;
        struct gpio_chip                chip;
        const struct mtk_pin_soc        *soc;
+       struct mtk_eint                 *eint;
 };
 
 static const struct mtk_pin_field_calc mt7622_pin_mode_range[] = {
@@ -913,6 +918,13 @@ static const struct pin_config_item mtk_conf_items[] = {
 };
 #endif
 
+static const struct mtk_eint_hw mt7622_eint_hw = {
+       .port_mask = 7,
+       .ports     = 7,
+       .ap_num    = ARRAY_SIZE(mt7622_pins),
+       .db_cnt    = 20,
+};
+
 static const struct mtk_pin_soc mt7622_data = {
        .reg_cal = mt7622_reg_cals,
        .pins = mt7622_pins,
@@ -921,6 +933,7 @@ static const struct mtk_pin_soc mt7622_data = {
        .ngrps = ARRAY_SIZE(mt7622_groups),
        .funcs = mt7622_functions,
        .nfuncs = ARRAY_SIZE(mt7622_functions),
+       .eint_hw = &mt7622_eint_hw,
 };
 
 static void mtk_w32(struct mtk_pinctrl *pctl, u32 reg, u32 val)
@@ -1441,6 +1454,32 @@ static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
        return pinctrl_gpio_direction_output(chip->base + gpio);
 }
 
+static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
+{
+       struct mtk_pinctrl *hw = gpiochip_get_data(chip);
+       unsigned long eint_n;
+
+       eint_n = offset;
+
+       return mtk_eint_find_irq(hw->eint, eint_n);
+}
+
+static int mtk_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
+                              unsigned long config)
+{
+       struct mtk_pinctrl *hw = gpiochip_get_data(chip);
+       unsigned long eint_n;
+       u32 debounce;
+
+       if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
+               return -ENOTSUPP;
+
+       debounce = pinconf_to_config_argument(config);
+       eint_n = offset;
+
+       return mtk_eint_set_debounce(hw->eint, eint_n, debounce);
+}
+
 static int mtk_build_gpiochip(struct mtk_pinctrl *hw, struct device_node *np)
 {
        struct gpio_chip *chip = &hw->chip;
@@ -1454,6 +1493,8 @@ static int mtk_build_gpiochip(struct mtk_pinctrl *hw, struct device_node *np)
        chip->direction_output  = mtk_gpio_direction_output;
        chip->get               = mtk_gpio_get;
        chip->set               = mtk_gpio_set;
+       chip->to_irq            = mtk_gpio_to_irq,
+       chip->set_config        = mtk_gpio_set_config,
        chip->base              = -1;
        chip->ngpio             = hw->soc->npins;
        chip->of_node           = np;
@@ -1514,6 +1555,103 @@ static int mtk_build_functions(struct mtk_pinctrl *hw)
        return 0;
 }
 
+static int mtk_xt_get_gpio_n(void *data, unsigned long eint_n,
+                            unsigned int *gpio_n,
+                            struct gpio_chip **gpio_chip)
+{
+       struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
+
+       *gpio_chip = &hw->chip;
+       *gpio_n = eint_n;
+
+       return 0;
+}
+
+static int mtk_xt_get_gpio_state(void *data, unsigned long eint_n)
+{
+       struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
+       struct gpio_chip *gpio_chip;
+       unsigned int gpio_n;
+       int err;
+
+       err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip);
+       if (err)
+               return err;
+
+       return mtk_gpio_get(gpio_chip, gpio_n);
+}
+
+static int mtk_xt_set_gpio_as_eint(void *data, unsigned long eint_n)
+{
+       struct mtk_pinctrl *hw = (struct mtk_pinctrl *)data;
+       struct gpio_chip *gpio_chip;
+       unsigned int gpio_n;
+       int err;
+
+       err = mtk_xt_get_gpio_n(hw, eint_n, &gpio_n, &gpio_chip);
+       if (err)
+               return err;
+
+       err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_MODE,
+                              MTK_GPIO_MODE);
+       if (err)
+               return err;
+
+       err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_DIR, MTK_INPUT);
+       if (err)
+               return err;
+
+       err = mtk_hw_set_value(hw, gpio_n, PINCTRL_PIN_REG_SMT, MTK_ENABLE);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static const struct mtk_eint_xt mtk_eint_xt = {
+       .get_gpio_n = mtk_xt_get_gpio_n,
+       .get_gpio_state = mtk_xt_get_gpio_state,
+       .set_gpio_as_eint = mtk_xt_set_gpio_as_eint,
+};
+
+static int
+mtk_build_eint(struct mtk_pinctrl *hw, struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct resource *res;
+
+       if (!IS_ENABLED(CONFIG_EINT_MTK))
+               return 0;
+
+       if (!of_property_read_bool(np, "interrupt-controller"))
+               return -ENODEV;
+
+       hw->eint = devm_kzalloc(hw->dev, sizeof(*hw->eint), GFP_KERNEL);
+       if (!hw->eint)
+               return -ENOMEM;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eint");
+       if (!res) {
+               dev_err(&pdev->dev, "Unable to get eint resource\n");
+               return -ENODEV;
+       }
+
+       hw->eint->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(hw->eint->base))
+               return PTR_ERR(hw->eint->base);
+
+       hw->eint->irq = irq_of_parse_and_map(np, 0);
+       if (!hw->eint->irq)
+               return -EINVAL;
+
+       hw->eint->dev = &pdev->dev;
+       hw->eint->hw = hw->soc->eint_hw;
+       hw->eint->pctl = hw;
+       hw->eint->gpio_xlate = &mtk_eint_xt;
+
+       return mtk_eint_do_init(hw->eint);
+}
+
 static const struct of_device_id mtk_pinctrl_of_match[] = {
        { .compatible = "mediatek,mt7622-pinctrl", .data = &mt7622_data},
        { }
@@ -1577,6 +1715,11 @@ static int mtk_pinctrl_probe(struct platform_device *pdev)
                return err;
        }
 
+       err = mtk_build_eint(hw, pdev);
+       if (err)
+               dev_warn(&pdev->dev,
+                        "Failed to add EINT, but pinctrl still can work\n");
+
        platform_set_drvdata(pdev, hw);
 
        return 0;
index d76491574841fc525f548a8b70b3d7f2db39ffb0..2e4cc9257e00c2d975788ea8dd57babfc9337846 100644 (file)
@@ -300,31 +300,12 @@ static const struct mtk_pinctrl_devdata mt8127_pinctrl_data = {
        .port_shf = 4,
        .port_mask = 0xf,
        .port_align = 4,
-       .eint_offsets = {
-               .name = "mt8127_eint",
-               .stat      = 0x000,
-               .ack       = 0x040,
-               .mask      = 0x080,
-               .mask_set  = 0x0c0,
-               .mask_clr  = 0x100,
-               .sens      = 0x140,
-               .sens_set  = 0x180,
-               .sens_clr  = 0x1c0,
-               .soft      = 0x200,
-               .soft_set  = 0x240,
-               .soft_clr  = 0x280,
-               .pol       = 0x300,
-               .pol_set   = 0x340,
-               .pol_clr   = 0x380,
-               .dom_en    = 0x400,
-               .dbnc_ctrl = 0x500,
-               .dbnc_set  = 0x600,
-               .dbnc_clr  = 0x700,
+       .eint_hw = {
                .port_mask = 7,
                .ports     = 6,
+               .ap_num    = 143,
+               .db_cnt    = 16,
        },
-       .ap_num = 143,
-       .db_cnt = 16,
 };
 
 static int mt8127_pinctrl_probe(struct platform_device *pdev)
index d8c645f16f21e6131ca4d6c9478fefffbb4c7264..7f5edfaffdc57e5b5213512b26d7082065c0dcd3 100644 (file)
@@ -313,31 +313,12 @@ static const struct mtk_pinctrl_devdata mt8135_pinctrl_data = {
        .port_shf = 4,
        .port_mask = 0xf,
        .port_align = 4,
-       .eint_offsets = {
-               .name = "mt8135_eint",
-               .stat      = 0x000,
-               .ack       = 0x040,
-               .mask      = 0x080,
-               .mask_set  = 0x0c0,
-               .mask_clr  = 0x100,
-               .sens      = 0x140,
-               .sens_set  = 0x180,
-               .sens_clr  = 0x1c0,
-               .soft      = 0x200,
-               .soft_set  = 0x240,
-               .soft_clr  = 0x280,
-               .pol       = 0x300,
-               .pol_set   = 0x340,
-               .pol_clr   = 0x380,
-               .dom_en    = 0x400,
-               .dbnc_ctrl = 0x500,
-               .dbnc_set  = 0x600,
-               .dbnc_clr  = 0x700,
+       .eint_hw = {
                .port_mask = 7,
                .ports     = 6,
+               .ap_num    = 192,
+               .db_cnt    = 16,
        },
-       .ap_num = 192,
-       .db_cnt = 16,
 };
 
 static int mt8135_pinctrl_probe(struct platform_device *pdev)
index 8bfd427b9135bb692659607837deda34a2b63811..c449c9a043da9847f648bca5aeccd75f418187e6 100644 (file)
@@ -340,31 +340,12 @@ static const struct mtk_pinctrl_devdata mt8173_pinctrl_data = {
        .port_shf = 4,
        .port_mask = 0xf,
        .port_align = 4,
-       .eint_offsets = {
-               .name = "mt8173_eint",
-               .stat      = 0x000,
-               .ack       = 0x040,
-               .mask      = 0x080,
-               .mask_set  = 0x0c0,
-               .mask_clr  = 0x100,
-               .sens      = 0x140,
-               .sens_set  = 0x180,
-               .sens_clr  = 0x1c0,
-               .soft      = 0x200,
-               .soft_set  = 0x240,
-               .soft_clr  = 0x280,
-               .pol       = 0x300,
-               .pol_set   = 0x340,
-               .pol_clr   = 0x380,
-               .dom_en    = 0x400,
-               .dbnc_ctrl = 0x500,
-               .dbnc_set  = 0x600,
-               .dbnc_clr  = 0x700,
+       .eint_hw = {
                .port_mask = 7,
                .ports     = 6,
+               .ap_num    = 224,
+               .db_cnt    = 16,
        },
-       .ap_num = 224,
-       .db_cnt = 16,
 };
 
 static int mt8173_pinctrl_probe(struct platform_device *pdev)
index c3975a04d1cdd976b578bc301834c7ea757e25e7..b3799695d8db8264ce917232cb3b1439793fe845 100644 (file)
@@ -38,6 +38,7 @@
 #include "../core.h"
 #include "../pinconf.h"
 #include "../pinctrl-utils.h"
+#include "mtk-eint.h"
 #include "pinctrl-mtk-common.h"
 
 #define MAX_GPIO_MODE_PER_REG 5
@@ -831,243 +832,38 @@ static int mtk_gpio_get(struct gpio_chip *chip, unsigned offset)
 
 static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-       const struct mtk_desc_pin *pin;
        struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
-       int irq;
-
-       pin = pctl->devdata->pins + offset;
-       if (pin->eint.eintnum == NO_EINT_SUPPORT)
-               return -EINVAL;
-
-       irq = irq_find_mapping(pctl->domain, pin->eint.eintnum);
-       if (!irq)
-               return -EINVAL;
-
-       return irq;
-}
-
-static int mtk_pinctrl_irq_request_resources(struct irq_data *d)
-{
-       struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d);
-       const struct mtk_desc_pin *pin;
-       int ret;
-
-       pin = mtk_find_pin_by_eint_num(pctl, d->hwirq);
-
-       if (!pin) {
-               dev_err(pctl->dev, "Can not find pin\n");
-               return -EINVAL;
-       }
-
-       ret = gpiochip_lock_as_irq(pctl->chip, pin->pin.number);
-       if (ret) {
-               dev_err(pctl->dev, "unable to lock HW IRQ %lu for IRQ\n",
-                       irqd_to_hwirq(d));
-               return ret;
-       }
-
-       /* set mux to INT mode */
-       mtk_pmx_set_mode(pctl->pctl_dev, pin->pin.number, pin->eint.eintmux);
-       /* set gpio direction to input */
-       mtk_pmx_gpio_set_direction(pctl->pctl_dev, NULL, pin->pin.number, true);
-       /* set input-enable */
-       mtk_pconf_set_ies_smt(pctl, pin->pin.number, 1, PIN_CONFIG_INPUT_ENABLE);
-
-       return 0;
-}
-
-static void mtk_pinctrl_irq_release_resources(struct irq_data *d)
-{
-       struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d);
-       const struct mtk_desc_pin *pin;
-
-       pin = mtk_find_pin_by_eint_num(pctl, d->hwirq);
-
-       if (!pin) {
-               dev_err(pctl->dev, "Can not find pin\n");
-               return;
-       }
-
-       gpiochip_unlock_as_irq(pctl->chip, pin->pin.number);
-}
-
-static void __iomem *mtk_eint_get_offset(struct mtk_pinctrl *pctl,
-       unsigned int eint_num, unsigned int offset)
-{
-       unsigned int eint_base = 0;
-       void __iomem *reg;
-
-       if (eint_num >= pctl->devdata->ap_num)
-               eint_base = pctl->devdata->ap_num;
-
-       reg = pctl->eint_reg_base + offset + ((eint_num - eint_base) / 32) * 4;
-
-       return reg;
-}
-
-/*
- * mtk_can_en_debounce: Check the EINT number is able to enable debounce or not
- * @eint_num: the EINT number to setmtk_pinctrl
- */
-static unsigned int mtk_eint_can_en_debounce(struct mtk_pinctrl *pctl,
-       unsigned int eint_num)
-{
-       unsigned int sens;
-       unsigned int bit = BIT(eint_num % 32);
-       const struct mtk_eint_offsets *eint_offsets =
-               &pctl->devdata->eint_offsets;
-
-       void __iomem *reg = mtk_eint_get_offset(pctl, eint_num,
-                       eint_offsets->sens);
-
-       if (readl(reg) & bit)
-               sens = MT_LEVEL_SENSITIVE;
-       else
-               sens = MT_EDGE_SENSITIVE;
-
-       if ((eint_num < pctl->devdata->db_cnt) && (sens != MT_EDGE_SENSITIVE))
-               return 1;
-       else
-               return 0;
-}
-
-/*
- * mtk_eint_get_mask: To get the eint mask
- * @eint_num: the EINT number to get
- */
-static unsigned int mtk_eint_get_mask(struct mtk_pinctrl *pctl,
-       unsigned int eint_num)
-{
-       unsigned int bit = BIT(eint_num % 32);
-       const struct mtk_eint_offsets *eint_offsets =
-               &pctl->devdata->eint_offsets;
-
-       void __iomem *reg = mtk_eint_get_offset(pctl, eint_num,
-                       eint_offsets->mask);
-
-       return !!(readl(reg) & bit);
-}
-
-static int mtk_eint_flip_edge(struct mtk_pinctrl *pctl, int hwirq)
-{
-       int start_level, curr_level;
-       unsigned int reg_offset;
-       const struct mtk_eint_offsets *eint_offsets = &(pctl->devdata->eint_offsets);
-       u32 mask = BIT(hwirq & 0x1f);
-       u32 port = (hwirq >> 5) & eint_offsets->port_mask;
-       void __iomem *reg = pctl->eint_reg_base + (port << 2);
        const struct mtk_desc_pin *pin;
-
-       pin = mtk_find_pin_by_eint_num(pctl, hwirq);
-       curr_level = mtk_gpio_get(pctl->chip, pin->pin.number);
-       do {
-               start_level = curr_level;
-               if (start_level)
-                       reg_offset = eint_offsets->pol_clr;
-               else
-                       reg_offset = eint_offsets->pol_set;
-               writel(mask, reg + reg_offset);
-
-               curr_level = mtk_gpio_get(pctl->chip, pin->pin.number);
-       } while (start_level != curr_level);
-
-       return start_level;
-}
-
-static void mtk_eint_mask(struct irq_data *d)
-{
-       struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d);
-       const struct mtk_eint_offsets *eint_offsets =
-                       &pctl->devdata->eint_offsets;
-       u32 mask = BIT(d->hwirq & 0x1f);
-       void __iomem *reg = mtk_eint_get_offset(pctl, d->hwirq,
-                       eint_offsets->mask_set);
-
-       writel(mask, reg);
-}
-
-static void mtk_eint_unmask(struct irq_data *d)
-{
-       struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d);
-       const struct mtk_eint_offsets *eint_offsets =
-               &pctl->devdata->eint_offsets;
-       u32 mask = BIT(d->hwirq & 0x1f);
-       void __iomem *reg = mtk_eint_get_offset(pctl, d->hwirq,
-                       eint_offsets->mask_clr);
-
-       writel(mask, reg);
-
-       if (pctl->eint_dual_edges[d->hwirq])
-               mtk_eint_flip_edge(pctl, d->hwirq);
-}
-
-static int mtk_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
-       unsigned debounce)
-{
-       struct mtk_pinctrl *pctl = dev_get_drvdata(chip->parent);
-       int eint_num, virq, eint_offset;
-       unsigned int set_offset, bit, clr_bit, clr_offset, rst, i, unmask, dbnc;
-       static const unsigned int debounce_time[] = {500, 1000, 16000, 32000, 64000,
-                                               128000, 256000};
-       const struct mtk_desc_pin *pin;
-       struct irq_data *d;
+       unsigned long eint_n;
 
        pin = pctl->devdata->pins + offset;
        if (pin->eint.eintnum == NO_EINT_SUPPORT)
                return -EINVAL;
 
-       eint_num = pin->eint.eintnum;
-       virq = irq_find_mapping(pctl->domain, eint_num);
-       eint_offset = (eint_num % 4) * 8;
-       d = irq_get_irq_data(virq);
+       eint_n = pin->eint.eintnum;
 
-       set_offset = (eint_num / 4) * 4 + pctl->devdata->eint_offsets.dbnc_set;
-       clr_offset = (eint_num / 4) * 4 + pctl->devdata->eint_offsets.dbnc_clr;
-       if (!mtk_eint_can_en_debounce(pctl, eint_num))
-               return -ENOSYS;
-
-       dbnc = ARRAY_SIZE(debounce_time);
-       for (i = 0; i < ARRAY_SIZE(debounce_time); i++) {
-               if (debounce <= debounce_time[i]) {
-                       dbnc = i;
-                       break;
-               }
-       }
-
-       if (!mtk_eint_get_mask(pctl, eint_num)) {
-               mtk_eint_mask(d);
-               unmask = 1;
-       } else {
-               unmask = 0;
-       }
-
-       clr_bit = 0xff << eint_offset;
-       writel(clr_bit, pctl->eint_reg_base + clr_offset);
-
-       bit = ((dbnc << EINT_DBNC_SET_DBNC_BITS) | EINT_DBNC_SET_EN) <<
-               eint_offset;
-       rst = EINT_DBNC_RST_BIT << eint_offset;
-       writel(rst | bit, pctl->eint_reg_base + set_offset);
-
-       /* Delay a while (more than 2T) to wait for hw debounce counter reset
-       work correctly */
-       udelay(1);
-       if (unmask == 1)
-               mtk_eint_unmask(d);
-
-       return 0;
+       return mtk_eint_find_irq(pctl->eint, eint_n);
 }
 
 static int mtk_gpio_set_config(struct gpio_chip *chip, unsigned offset,
                               unsigned long config)
 {
+       struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
+       const struct mtk_desc_pin *pin;
+       unsigned long eint_n;
        u32 debounce;
 
        if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
                return -ENOTSUPP;
 
+       pin = pctl->devdata->pins + offset;
+       if (pin->eint.eintnum == NO_EINT_SUPPORT)
+               return -EINVAL;
+
        debounce = pinconf_to_config_argument(config);
-       return mtk_gpio_set_debounce(chip, offset, debounce);
+       eint_n = pin->eint.eintnum;
+
+       return mtk_eint_set_debounce(pctl->eint, eint_n, debounce);
 }
 
 static const struct gpio_chip mtk_gpio_chip = {
@@ -1084,117 +880,18 @@ static const struct gpio_chip mtk_gpio_chip = {
        .of_gpio_n_cells        = 2,
 };
 
-static int mtk_eint_set_type(struct irq_data *d,
-                                     unsigned int type)
-{
-       struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d);
-       const struct mtk_eint_offsets *eint_offsets =
-               &pctl->devdata->eint_offsets;
-       u32 mask = BIT(d->hwirq & 0x1f);
-       void __iomem *reg;
-
-       if (((type & IRQ_TYPE_EDGE_BOTH) && (type & IRQ_TYPE_LEVEL_MASK)) ||
-               ((type & IRQ_TYPE_LEVEL_MASK) == IRQ_TYPE_LEVEL_MASK)) {
-               dev_err(pctl->dev, "Can't configure IRQ%d (EINT%lu) for type 0x%X\n",
-                       d->irq, d->hwirq, type);
-               return -EINVAL;
-       }
-
-       if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
-               pctl->eint_dual_edges[d->hwirq] = 1;
-       else
-               pctl->eint_dual_edges[d->hwirq] = 0;
-
-       if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING)) {
-               reg = mtk_eint_get_offset(pctl, d->hwirq,
-                       eint_offsets->pol_clr);
-               writel(mask, reg);
-       } else {
-               reg = mtk_eint_get_offset(pctl, d->hwirq,
-                       eint_offsets->pol_set);
-               writel(mask, reg);
-       }
-
-       if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
-               reg = mtk_eint_get_offset(pctl, d->hwirq,
-                       eint_offsets->sens_clr);
-               writel(mask, reg);
-       } else {
-               reg = mtk_eint_get_offset(pctl, d->hwirq,
-                       eint_offsets->sens_set);
-               writel(mask, reg);
-       }
-
-       if (pctl->eint_dual_edges[d->hwirq])
-               mtk_eint_flip_edge(pctl, d->hwirq);
-
-       return 0;
-}
-
-static int mtk_eint_irq_set_wake(struct irq_data *d, unsigned int on)
-{
-       struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d);
-       int shift = d->hwirq & 0x1f;
-       int reg = d->hwirq >> 5;
-
-       if (on)
-               pctl->wake_mask[reg] |= BIT(shift);
-       else
-               pctl->wake_mask[reg] &= ~BIT(shift);
-
-       return 0;
-}
-
-static void mtk_eint_chip_write_mask(const struct mtk_eint_offsets *chip,
-               void __iomem *eint_reg_base, u32 *buf)
-{
-       int port;
-       void __iomem *reg;
-
-       for (port = 0; port < chip->ports; port++) {
-               reg = eint_reg_base + (port << 2);
-               writel_relaxed(~buf[port], reg + chip->mask_set);
-               writel_relaxed(buf[port], reg + chip->mask_clr);
-       }
-}
-
-static void mtk_eint_chip_read_mask(const struct mtk_eint_offsets *chip,
-               void __iomem *eint_reg_base, u32 *buf)
-{
-       int port;
-       void __iomem *reg;
-
-       for (port = 0; port < chip->ports; port++) {
-               reg = eint_reg_base + chip->mask + (port << 2);
-               buf[port] = ~readl_relaxed(reg);
-               /* Mask is 0 when irq is enabled, and 1 when disabled. */
-       }
-}
-
 static int mtk_eint_suspend(struct device *device)
 {
-       void __iomem *reg;
        struct mtk_pinctrl *pctl = dev_get_drvdata(device);
-       const struct mtk_eint_offsets *eint_offsets =
-                       &pctl->devdata->eint_offsets;
-
-       reg = pctl->eint_reg_base;
-       mtk_eint_chip_read_mask(eint_offsets, reg, pctl->cur_mask);
-       mtk_eint_chip_write_mask(eint_offsets, reg, pctl->wake_mask);
 
-       return 0;
+       return mtk_eint_do_suspend(pctl->eint);
 }
 
 static int mtk_eint_resume(struct device *device)
 {
        struct mtk_pinctrl *pctl = dev_get_drvdata(device);
-       const struct mtk_eint_offsets *eint_offsets =
-                       &pctl->devdata->eint_offsets;
-
-       mtk_eint_chip_write_mask(eint_offsets,
-                       pctl->eint_reg_base, pctl->cur_mask);
 
-       return 0;
+       return mtk_eint_do_resume(pctl->eint);
 }
 
 const struct dev_pm_ops mtk_eint_pm_ops = {
@@ -1202,117 +899,6 @@ const struct dev_pm_ops mtk_eint_pm_ops = {
        .resume_noirq = mtk_eint_resume,
 };
 
-static void mtk_eint_ack(struct irq_data *d)
-{
-       struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d);
-       const struct mtk_eint_offsets *eint_offsets =
-               &pctl->devdata->eint_offsets;
-       u32 mask = BIT(d->hwirq & 0x1f);
-       void __iomem *reg = mtk_eint_get_offset(pctl, d->hwirq,
-                       eint_offsets->ack);
-
-       writel(mask, reg);
-}
-
-static struct irq_chip mtk_pinctrl_irq_chip = {
-       .name = "mt-eint",
-       .irq_disable = mtk_eint_mask,
-       .irq_mask = mtk_eint_mask,
-       .irq_unmask = mtk_eint_unmask,
-       .irq_ack = mtk_eint_ack,
-       .irq_set_type = mtk_eint_set_type,
-       .irq_set_wake = mtk_eint_irq_set_wake,
-       .irq_request_resources = mtk_pinctrl_irq_request_resources,
-       .irq_release_resources = mtk_pinctrl_irq_release_resources,
-};
-
-static unsigned int mtk_eint_init(struct mtk_pinctrl *pctl)
-{
-       const struct mtk_eint_offsets *eint_offsets =
-               &pctl->devdata->eint_offsets;
-       void __iomem *reg = pctl->eint_reg_base + eint_offsets->dom_en;
-       unsigned int i;
-
-       for (i = 0; i < pctl->devdata->ap_num; i += 32) {
-               writel(0xffffffff, reg);
-               reg += 4;
-       }
-       return 0;
-}
-
-static inline void
-mtk_eint_debounce_process(struct mtk_pinctrl *pctl, int index)
-{
-       unsigned int rst, ctrl_offset;
-       unsigned int bit, dbnc;
-       const struct mtk_eint_offsets *eint_offsets =
-               &pctl->devdata->eint_offsets;
-
-       ctrl_offset = (index / 4) * 4 + eint_offsets->dbnc_ctrl;
-       dbnc = readl(pctl->eint_reg_base + ctrl_offset);
-       bit = EINT_DBNC_SET_EN << ((index % 4) * 8);
-       if ((bit & dbnc) > 0) {
-               ctrl_offset = (index / 4) * 4 + eint_offsets->dbnc_set;
-               rst = EINT_DBNC_RST_BIT << ((index % 4) * 8);
-               writel(rst, pctl->eint_reg_base + ctrl_offset);
-       }
-}
-
-static void mtk_eint_irq_handler(struct irq_desc *desc)
-{
-       struct irq_chip *chip = irq_desc_get_chip(desc);
-       struct mtk_pinctrl *pctl = irq_desc_get_handler_data(desc);
-       unsigned int status, eint_num;
-       int offset, index, virq;
-       const struct mtk_eint_offsets *eint_offsets =
-               &pctl->devdata->eint_offsets;
-       void __iomem *reg =  mtk_eint_get_offset(pctl, 0, eint_offsets->stat);
-       int dual_edges, start_level, curr_level;
-       const struct mtk_desc_pin *pin;
-
-       chained_irq_enter(chip, desc);
-       for (eint_num = 0;
-            eint_num < pctl->devdata->ap_num;
-            eint_num += 32, reg += 4) {
-               status = readl(reg);
-               while (status) {
-                       offset = __ffs(status);
-                       index = eint_num + offset;
-                       virq = irq_find_mapping(pctl->domain, index);
-                       status &= ~BIT(offset);
-
-                       dual_edges = pctl->eint_dual_edges[index];
-                       if (dual_edges) {
-                               /* Clear soft-irq in case we raised it
-                                  last time */
-                               writel(BIT(offset), reg - eint_offsets->stat +
-                                       eint_offsets->soft_clr);
-
-                               pin = mtk_find_pin_by_eint_num(pctl, index);
-                               start_level = mtk_gpio_get(pctl->chip,
-                                                          pin->pin.number);
-                       }
-
-                       generic_handle_irq(virq);
-
-                       if (dual_edges) {
-                               curr_level = mtk_eint_flip_edge(pctl, index);
-
-                               /* If level changed, we might lost one edge
-                                  interrupt, raised it through soft-irq */
-                               if (start_level != curr_level)
-                                       writel(BIT(offset), reg -
-                                               eint_offsets->stat +
-                                               eint_offsets->soft_set);
-                       }
-
-                       if (index < pctl->devdata->db_cnt)
-                               mtk_eint_debounce_process(pctl , index);
-               }
-       }
-       chained_irq_exit(chip, desc);
-}
-
 static int mtk_pctrl_build_state(struct platform_device *pdev)
 {
        struct mtk_pinctrl *pctl = platform_get_drvdata(pdev);
@@ -1345,6 +931,101 @@ static int mtk_pctrl_build_state(struct platform_device *pdev)
        return 0;
 }
 
+static int
+mtk_xt_get_gpio_n(void *data, unsigned long eint_n, unsigned int *gpio_n,
+                 struct gpio_chip **gpio_chip)
+{
+       struct mtk_pinctrl *pctl = (struct mtk_pinctrl *)data;
+       const struct mtk_desc_pin *pin;
+
+       pin = mtk_find_pin_by_eint_num(pctl, eint_n);
+       if (!pin)
+               return -EINVAL;
+
+       *gpio_chip = pctl->chip;
+       *gpio_n = pin->pin.number;
+
+       return 0;
+}
+
+static int mtk_xt_get_gpio_state(void *data, unsigned long eint_n)
+{
+       struct mtk_pinctrl *pctl = (struct mtk_pinctrl *)data;
+       const struct mtk_desc_pin *pin;
+
+       pin = mtk_find_pin_by_eint_num(pctl, eint_n);
+       if (!pin)
+               return -EINVAL;
+
+       return mtk_gpio_get(pctl->chip, pin->pin.number);
+}
+
+static int mtk_xt_set_gpio_as_eint(void *data, unsigned long eint_n)
+{
+       struct mtk_pinctrl *pctl = (struct mtk_pinctrl *)data;
+       const struct mtk_desc_pin *pin;
+
+       pin = mtk_find_pin_by_eint_num(pctl, eint_n);
+       if (!pin)
+               return -EINVAL;
+
+       /* set mux to INT mode */
+       mtk_pmx_set_mode(pctl->pctl_dev, pin->pin.number, pin->eint.eintmux);
+       /* set gpio direction to input */
+       mtk_pmx_gpio_set_direction(pctl->pctl_dev, NULL, pin->pin.number,
+                                  true);
+       /* set input-enable */
+       mtk_pconf_set_ies_smt(pctl, pin->pin.number, 1,
+                             PIN_CONFIG_INPUT_ENABLE);
+
+       return 0;
+}
+
+static const struct mtk_eint_xt mtk_eint_xt = {
+       .get_gpio_n = mtk_xt_get_gpio_n,
+       .get_gpio_state = mtk_xt_get_gpio_state,
+       .set_gpio_as_eint = mtk_xt_set_gpio_as_eint,
+};
+
+static int mtk_eint_init(struct mtk_pinctrl *pctl, struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct resource *res;
+
+       if (!of_property_read_bool(np, "interrupt-controller"))
+               return -ENODEV;
+
+       pctl->eint = devm_kzalloc(pctl->dev, sizeof(*pctl->eint), GFP_KERNEL);
+       if (!pctl->eint)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "Unable to get eint resource\n");
+               return -ENODEV;
+       }
+
+       pctl->eint->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(pctl->eint->base))
+               return PTR_ERR(pctl->eint->base);
+
+       pctl->eint->irq = irq_of_parse_and_map(np, 0);
+       if (!pctl->eint->irq)
+               return -EINVAL;
+
+       pctl->eint->dev = &pdev->dev;
+       /*
+        * If pctl->eint->regs == NULL, it would fall back into using a generic
+        * register map in mtk_eint_do_init calls.
+        */
+       pctl->eint->regs = pctl->devdata->eint_regs;
+       pctl->eint->hw = &pctl->devdata->eint_hw;
+       pctl->eint->pctl = pctl;
+       pctl->eint->gpio_xlate = &mtk_eint_xt;
+
+       return mtk_eint_do_init(pctl->eint);
+}
+
 int mtk_pctrl_init(struct platform_device *pdev,
                const struct mtk_pinctrl_devdata *data,
                struct regmap *regmap)
@@ -1353,8 +1034,7 @@ int mtk_pctrl_init(struct platform_device *pdev,
        struct mtk_pinctrl *pctl;
        struct device_node *np = pdev->dev.of_node, *node;
        struct property *prop;
-       struct resource *res;
-       int i, ret, irq, ports_buf;
+       int ret, i;
 
        pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
        if (!pctl)
@@ -1441,70 +1121,10 @@ int mtk_pctrl_init(struct platform_device *pdev,
                goto chip_error;
        }
 
-       if (!of_property_read_bool(np, "interrupt-controller"))
-               return 0;
-
-       /* Get EINT register base from dts. */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "Unable to get Pinctrl resource\n");
-               ret = -EINVAL;
-               goto chip_error;
-       }
-
-       pctl->eint_reg_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(pctl->eint_reg_base)) {
-               ret = -EINVAL;
-               goto chip_error;
-       }
-
-       ports_buf = pctl->devdata->eint_offsets.ports;
-       pctl->wake_mask = devm_kcalloc(&pdev->dev, ports_buf,
-                                       sizeof(*pctl->wake_mask), GFP_KERNEL);
-       if (!pctl->wake_mask) {
-               ret = -ENOMEM;
-               goto chip_error;
-       }
-
-       pctl->cur_mask = devm_kcalloc(&pdev->dev, ports_buf,
-                                       sizeof(*pctl->cur_mask), GFP_KERNEL);
-       if (!pctl->cur_mask) {
-               ret = -ENOMEM;
-               goto chip_error;
-       }
-
-       pctl->eint_dual_edges = devm_kcalloc(&pdev->dev, pctl->devdata->ap_num,
-                                            sizeof(int), GFP_KERNEL);
-       if (!pctl->eint_dual_edges) {
-               ret = -ENOMEM;
-               goto chip_error;
-       }
-
-       irq = irq_of_parse_and_map(np, 0);
-       if (!irq) {
-               dev_err(&pdev->dev, "couldn't parse and map irq\n");
-               ret = -EINVAL;
-               goto chip_error;
-       }
-
-       pctl->domain = irq_domain_add_linear(np,
-               pctl->devdata->ap_num, &irq_domain_simple_ops, NULL);
-       if (!pctl->domain) {
-               dev_err(&pdev->dev, "Couldn't register IRQ domain\n");
-               ret = -ENOMEM;
+       ret = mtk_eint_init(pctl, pdev);
+       if (ret)
                goto chip_error;
-       }
-
-       mtk_eint_init(pctl);
-       for (i = 0; i < pctl->devdata->ap_num; i++) {
-               int virq = irq_create_mapping(pctl->domain, i);
-
-               irq_set_chip_and_handler(virq, &mtk_pinctrl_irq_chip,
-                       handle_level_irq);
-               irq_set_chip_data(virq, pctl);
-       }
 
-       irq_set_chained_handler_and_data(irq, mtk_eint_irq_handler, pctl);
        return 0;
 
 chip_error:
index 8543bc478a1ec15f3b82f316b9ccb4a0c561a463..bf13eb0a68d6243e51971c5a389f5cb579df3a94 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/regmap.h>
 #include <linux/pinctrl/pinconf-generic.h>
 
+#include "mtk-eint.h"
+
 #define NO_EINT_SUPPORT    255
 #define MT_EDGE_SENSITIVE           0
 #define MT_LEVEL_SENSITIVE          1
@@ -258,9 +260,8 @@ struct mtk_pinctrl_devdata {
        unsigned char  port_shf;
        unsigned char  port_mask;
        unsigned char  port_align;
-       struct mtk_eint_offsets eint_offsets;
-       unsigned int    ap_num;
-       unsigned int    db_cnt;
+       struct mtk_eint_hw eint_hw;
+       struct mtk_eint_regs *eint_regs;
 };
 
 struct mtk_pinctrl {
@@ -274,11 +275,7 @@ struct mtk_pinctrl {
        const char          **grp_names;
        struct pinctrl_dev      *pctl_dev;
        const struct mtk_pinctrl_devdata  *devdata;
-       void __iomem            *eint_reg_base;
-       struct irq_domain       *domain;
-       int                     *eint_dual_edges;
-       u32 *wake_mask;
-       u32 *cur_mask;
+       struct mtk_eint *eint;
 };
 
 int mtk_pctrl_init(struct platform_device *pdev,
index 99a6ceac8e53ca680eb14f681d3f247622d8eda4..46a0918bd284c0d847558b87c6145461477d411d 100644 (file)
@@ -312,6 +312,47 @@ static const unsigned int pdm_din1_pins[] = {GPIOA_16};
 static const unsigned int pdm_din2_pins[] = {GPIOA_17};
 static const unsigned int pdm_din3_pins[] = {GPIOA_18};
 
+/* mclk */
+static const unsigned int mclk_c_pins[] = {GPIOA_0};
+static const unsigned int mclk_b_pins[] = {GPIOA_1};
+
+/* tdm */
+static const unsigned int tdma_sclk_pins[] = {GPIOX_12};
+static const unsigned int tdma_sclk_slv_pins[] = {GPIOX_12};
+static const unsigned int tdma_fs_pins[] = {GPIOX_13};
+static const unsigned int tdma_fs_slv_pins[] = {GPIOX_13};
+static const unsigned int tdma_din0_pins[] = {GPIOX_14};
+static const unsigned int tdma_dout0_x14_pins[] = {GPIOX_14};
+static const unsigned int tdma_dout0_x15_pins[] = {GPIOX_15};
+static const unsigned int tdma_dout1_pins[] = {GPIOX_15};
+static const unsigned int tdma_din1_pins[] = {GPIOX_15};
+
+static const unsigned int tdmc_sclk_pins[] = {GPIOA_2};
+static const unsigned int tdmc_sclk_slv_pins[] = {GPIOA_2};
+static const unsigned int tdmc_fs_pins[] = {GPIOA_3};
+static const unsigned int tdmc_fs_slv_pins[] = {GPIOA_3};
+static const unsigned int tdmc_din0_pins[] = {GPIOA_4};
+static const unsigned int tdmc_dout0_pins[] = {GPIOA_4};
+static const unsigned int tdmc_din1_pins[] = {GPIOA_5};
+static const unsigned int tdmc_dout1_pins[] = {GPIOA_5};
+static const unsigned int tdmc_din2_pins[] = {GPIOA_6};
+static const unsigned int tdmc_dout2_pins[] = {GPIOA_6};
+static const unsigned int tdmc_din3_pins[] = {GPIOA_7};
+static const unsigned int tdmc_dout3_pins[] = {GPIOA_7};
+
+static const unsigned int tdmb_sclk_pins[] = {GPIOA_8};
+static const unsigned int tdmb_sclk_slv_pins[] = {GPIOA_8};
+static const unsigned int tdmb_fs_pins[] = {GPIOA_9};
+static const unsigned int tdmb_fs_slv_pins[] = {GPIOA_9};
+static const unsigned int tdmb_din0_pins[] = {GPIOA_10};
+static const unsigned int tdmb_dout0_pins[] = {GPIOA_10};
+static const unsigned int tdmb_din1_pins[] = {GPIOA_11};
+static const unsigned int tdmb_dout1_pins[] = {GPIOA_11};
+static const unsigned int tdmb_din2_pins[] = {GPIOA_12};
+static const unsigned int tdmb_dout2_pins[] = {GPIOA_12};
+static const unsigned int tdmb_din3_pins[] = {GPIOA_13};
+static const unsigned int tdmb_dout3_pins[] = {GPIOA_13};
+
 static struct meson_pmx_group meson_axg_periphs_groups[] = {
        GPIO_GROUP(GPIOZ_0),
        GPIO_GROUP(GPIOZ_1),
@@ -495,6 +536,15 @@ static struct meson_pmx_group meson_axg_periphs_groups[] = {
        GROUP(eth_rx_dv_x, 4),
        GROUP(eth_mdio_x, 4),
        GROUP(eth_mdc_x, 4),
+       GROUP(tdma_sclk, 1),
+       GROUP(tdma_sclk_slv, 2),
+       GROUP(tdma_fs, 1),
+       GROUP(tdma_fs_slv, 2),
+       GROUP(tdma_din0, 1),
+       GROUP(tdma_dout0_x14, 2),
+       GROUP(tdma_dout0_x15, 1),
+       GROUP(tdma_dout1, 2),
+       GROUP(tdma_din1, 3),
 
        /* bank GPIOY */
        GROUP(eth_txd0_y, 1),
@@ -544,6 +594,32 @@ static struct meson_pmx_group meson_axg_periphs_groups[] = {
        GROUP(pdm_din1, 1),
        GROUP(pdm_din2, 1),
        GROUP(pdm_din3, 1),
+       GROUP(mclk_c, 1),
+       GROUP(mclk_b, 1),
+       GROUP(tdmc_sclk, 1),
+       GROUP(tdmc_sclk_slv, 2),
+       GROUP(tdmc_fs, 1),
+       GROUP(tdmc_fs_slv, 2),
+       GROUP(tdmc_din0, 2),
+       GROUP(tdmc_dout0, 1),
+       GROUP(tdmc_din1, 2),
+       GROUP(tdmc_dout1, 1),
+       GROUP(tdmc_din2, 2),
+       GROUP(tdmc_dout2, 1),
+       GROUP(tdmc_din3, 2),
+       GROUP(tdmc_dout3, 1),
+       GROUP(tdmb_sclk, 1),
+       GROUP(tdmb_sclk_slv, 2),
+       GROUP(tdmb_fs, 1),
+       GROUP(tdmb_fs_slv, 2),
+       GROUP(tdmb_din0, 2),
+       GROUP(tdmb_dout0, 1),
+       GROUP(tdmb_din1, 2),
+       GROUP(tdmb_dout1, 1),
+       GROUP(tdmb_din2, 2),
+       GROUP(tdmb_dout2, 1),
+       GROUP(tdmb_din3, 2),
+       GROUP(tdmb_dout3, 1),
 };
 
 /* uart_ao_a */
@@ -845,6 +921,32 @@ static const char * const jtag_ao_groups[] = {
        "jtag_ao_tdi", "jtag_ao_tdo", "jtag_ao_clk", "jtag_ao_tms",
 };
 
+static const char * const mclk_c_groups[] = {
+       "mclk_c",
+};
+
+static const char * const mclk_b_groups[] = {
+       "mclk_b",
+};
+
+static const char * const tdma_groups[] = {
+       "tdma_sclk", "tdma_sclk_slv", "tdma_fs", "tdma_fs_slv",
+       "tdma_din0", "tdma_dout0_x14", "tdma_dout0_x15", "tdma_dout1",
+       "tdma_din1",
+};
+
+static const char * const tdmc_groups[] = {
+       "tdmc_sclk", "tdmc_sclk_slv", "tdmc_fs", "tdmc_fs_slv",
+       "tdmc_din0", "tdmc_dout0", "tdmc_din1", "tdmc_dout1",
+       "tdmc_din2", "tdmc_dout2", "tdmc_din3", "tdmc_dout3",
+};
+
+static const char * const tdmb_groups[] = {
+       "tdmb_sclk", "tdmb_sclk_slv", "tdmb_fs", "tdmb_fs_slv",
+       "tdmb_din0", "tdmb_dout0", "tdmb_din1", "tdmb_dout1",
+       "tdmb_din2", "tdmb_dout2", "tdmb_din3", "tdmb_dout3",
+};
+
 static struct meson_pmx_func meson_axg_periphs_functions[] = {
        FUNCTION(gpio_periphs),
        FUNCTION(emmc),
@@ -870,6 +972,11 @@ static struct meson_pmx_func meson_axg_periphs_functions[] = {
        FUNCTION(spdif_in),
        FUNCTION(jtag_ee),
        FUNCTION(pdm),
+       FUNCTION(mclk_b),
+       FUNCTION(mclk_c),
+       FUNCTION(tdma),
+       FUNCTION(tdmb),
+       FUNCTION(tdmc),
 };
 
 static struct meson_pmx_func meson_axg_aobus_functions[] = {
index 9079020259c5a531596a4cc965e28a73d7b468fa..2c97a2e07a5fc508ab6d6350a48a28d3da6df797 100644 (file)
@@ -627,8 +627,8 @@ static const char * const sdio_groups[] = {
 };
 
 static const char * const nand_groups[] = {
-       "nand_ce0", "nand_ce1", "nand_rb0", "nand_ale", "nand_cle",
-       "nand_wen_clk", "nand_ren_wr", "nand_dqs",
+       "emmc_nand_d07", "nand_ce0", "nand_ce1", "nand_rb0", "nand_ale",
+       "nand_cle", "nand_wen_clk", "nand_ren_wr", "nand_dqs",
 };
 
 static const char * const uart_a_groups[] = {
index b3786cde963d526ea44743421e2162ffe49426bc..7dae1d7bf6b0a50f75c9d104f43f93972abaf27d 100644 (file)
@@ -617,8 +617,8 @@ static const char * const sdio_groups[] = {
 };
 
 static const char * const nand_groups[] = {
-       "nand_ce0", "nand_ce1", "nand_rb0", "nand_ale", "nand_cle",
-       "nand_wen_clk", "nand_ren_wr", "nand_dqs",
+       "emmc_nand_d07", "nand_ce0", "nand_ce1", "nand_rb0", "nand_ale",
+       "nand_cle", "nand_wen_clk", "nand_ren_wr", "nand_dqs",
 };
 
 static const char * const uart_a_groups[] = {
index 49c7ce03547bf065eecc9f1b3f19072497f0710e..c6d79315218fa69cadcdde9aa49d657d6916f5bb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Pin controller and GPIO driver for Amlogic Meson8.
+ * Pin controller and GPIO driver for Amlogic Meson8 and Meson8m2.
  *
  * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
  *
@@ -299,6 +299,10 @@ static const unsigned int spi_mosi_1_pins[]        = { GPIOZ_12 };
 static const unsigned int spi_miso_1_pins[]    = { GPIOZ_13 };
 static const unsigned int spi_ss2_1_pins[]     = { GPIOZ_14 };
 
+static const unsigned int eth_txd3_pins[]      = { GPIOZ_0 };
+static const unsigned int eth_txd2_pins[]      = { GPIOZ_1 };
+static const unsigned int eth_rxd3_pins[]      = { GPIOZ_2 };
+static const unsigned int eth_rxd2_pins[]      = { GPIOZ_3 };
 static const unsigned int eth_tx_clk_50m_pins[]        = { GPIOZ_4 };
 static const unsigned int eth_tx_en_pins[]     = { GPIOZ_5 };
 static const unsigned int eth_txd1_pins[]      = { GPIOZ_6 };
@@ -650,6 +654,12 @@ static struct meson_pmx_group meson8_cbus_groups[] = {
        GROUP(eth_mdio,         6,      6),
        GROUP(eth_mdc,          6,      5),
 
+       /* NOTE: the following four groups are only available on Meson8m2: */
+       GROUP(eth_rxd2,         6,      3),
+       GROUP(eth_rxd3,         6,      2),
+       GROUP(eth_txd2,         6,      1),
+       GROUP(eth_txd3,         6,      0),
+
        GROUP(i2c_sda_a0,       5,      31),
        GROUP(i2c_sck_a0,       5,      30),
 
@@ -877,7 +887,8 @@ static const char * const spi_groups[] = {
 static const char * const ethernet_groups[] = {
        "eth_tx_clk_50m", "eth_tx_en", "eth_txd1",
        "eth_txd0", "eth_rx_clk_in", "eth_rx_dv",
-       "eth_rxd1", "eth_rxd0", "eth_mdio", "eth_mdc"
+       "eth_rxd1", "eth_rxd0", "eth_mdio", "eth_mdc", "eth_rxd2",
+       "eth_rxd3", "eth_txd2", "eth_txd3"
 };
 
 static const char * const i2c_a_groups[] = {
@@ -1080,6 +1091,14 @@ static const struct of_device_id meson8_pinctrl_dt_match[] = {
                .compatible = "amlogic,meson8-aobus-pinctrl",
                .data = &meson8_aobus_pinctrl_data,
        },
+       {
+               .compatible = "amlogic,meson8m2-cbus-pinctrl",
+               .data = &meson8_cbus_pinctrl_data,
+       },
+       {
+               .compatible = "amlogic,meson8m2-aobus-pinctrl",
+               .data = &meson8_aobus_pinctrl_data,
+       },
        { },
 };
 
index 5b63248c82090a4fbc681bf33a43ac05f3f12b5d..674ffdf8103c3f3a875621f55f192576cc72ccfa 100644 (file)
@@ -214,18 +214,6 @@ static inline void armada_37xx_update_reg(unsigned int *reg,
        }
 }
 
-static int armada_37xx_get_func_reg(struct armada_37xx_pin_group *grp,
-                                   const char *func)
-{
-       int f;
-
-       for (f = 0; (f < NB_FUNCS) && grp->funcs[f]; f++)
-               if (!strcmp(grp->funcs[f], func))
-                       return f;
-
-       return -ENOTSUPP;
-}
-
 static struct armada_37xx_pin_group *armada_37xx_find_next_grp_by_pin(
        struct armada_37xx_pinctrl *info, int pin, int *grp)
 {
@@ -344,10 +332,9 @@ static int armada_37xx_pmx_set_by_name(struct pinctrl_dev *pctldev,
        dev_dbg(info->dev, "enable function %s group %s\n",
                name, grp->name);
 
-       func = armada_37xx_get_func_reg(grp, name);
-
+       func = match_string(grp->funcs, NB_FUNCS, name);
        if (func < 0)
-               return func;
+               return -ENOTSUPP;
 
        val = grp->val[func];
 
@@ -679,12 +666,13 @@ static void armada_37xx_irq_handler(struct irq_desc *desc)
                                        writel(1 << hwirq,
                                               info->base +
                                               IRQ_STATUS + 4 * i);
-                                       continue;
+                                       goto update_status;
                                }
                        }
 
                        generic_handle_irq(virq);
 
+update_status:
                        /* Update status in case a new IRQ appears */
                        spin_lock_irqsave(&info->irq_lock, flags);
                        status = readl_relaxed(info->base +
@@ -932,12 +920,12 @@ static int armada_37xx_fill_func(struct armada_37xx_pinctrl *info)
                        struct armada_37xx_pin_group *gp = &info->groups[g];
                        int f;
 
-                       for (f = 0; (f < NB_FUNCS) && gp->funcs[f]; f++) {
-                               if (strcmp(gp->funcs[f], name) == 0) {
-                                       *groups = gp->name;
-                                       groups++;
-                               }
-                       }
+                       f = match_string(gp->funcs, NB_FUNCS, name);
+                       if (f < 0)
+                               continue;
+
+                       *groups = gp->name;
+                       groups++;
                }
        }
        return 0;
index b854f1ee5de579b3fb4934de30ff0bf3272d2b9c..5e828468e43da2243582da0b8c52cc3557f9beb0 100644 (file)
@@ -431,40 +431,40 @@ static struct mvebu_mpp_mode mv98dx3236_mpp_modes[] = {
        MPP_MODE(19,
                 MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
                 MPP_VAR_FUNCTION(0x3, "uart1", "rxd",       V_98DX3236_PLUS),
-                MPP_VAR_FUNCTION(0x4, "dev", "rb",          V_98DX3236_PLUS)),
+                MPP_VAR_FUNCTION(0x4, "nand", "rb",         V_98DX3236_PLUS)),
        MPP_MODE(20,
                 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
                 MPP_VAR_FUNCTION(0x4, "dev", "we0",         V_98DX3236_PLUS)),
        MPP_MODE(21,
                 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
-                MPP_VAR_FUNCTION(0x1, "dev", "ad0",         V_98DX3236_PLUS)),
+                MPP_VAR_FUNCTION(0x4, "dev", "ad0",         V_98DX3236_PLUS)),
        MPP_MODE(22,
                 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
-                MPP_VAR_FUNCTION(0x1, "dev", "ad1",         V_98DX3236_PLUS)),
+                MPP_VAR_FUNCTION(0x4, "dev", "ad1",         V_98DX3236_PLUS)),
        MPP_MODE(23,
                 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
-                MPP_VAR_FUNCTION(0x1, "dev", "ad2",         V_98DX3236_PLUS)),
+                MPP_VAR_FUNCTION(0x4, "dev", "ad2",         V_98DX3236_PLUS)),
        MPP_MODE(24,
                 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
-                MPP_VAR_FUNCTION(0x1, "dev", "ad3",         V_98DX3236_PLUS)),
+                MPP_VAR_FUNCTION(0x4, "dev", "ad3",         V_98DX3236_PLUS)),
        MPP_MODE(25,
                 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
-                MPP_VAR_FUNCTION(0x1, "dev", "ad4",         V_98DX3236_PLUS)),
+                MPP_VAR_FUNCTION(0x4, "dev", "ad4",         V_98DX3236_PLUS)),
        MPP_MODE(26,
                 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
-                MPP_VAR_FUNCTION(0x1, "dev", "ad5",         V_98DX3236_PLUS)),
+                MPP_VAR_FUNCTION(0x4, "dev", "ad5",         V_98DX3236_PLUS)),
        MPP_MODE(27,
                 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
-                MPP_VAR_FUNCTION(0x1, "dev", "ad6",         V_98DX3236_PLUS)),
+                MPP_VAR_FUNCTION(0x4, "dev", "ad6",         V_98DX3236_PLUS)),
        MPP_MODE(28,
                 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
-                MPP_VAR_FUNCTION(0x1, "dev", "ad7",         V_98DX3236_PLUS)),
+                MPP_VAR_FUNCTION(0x4, "dev", "ad7",         V_98DX3236_PLUS)),
        MPP_MODE(29,
                 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
-                MPP_VAR_FUNCTION(0x1, "dev", "a0",          V_98DX3236_PLUS)),
+                MPP_VAR_FUNCTION(0x4, "dev", "a0",          V_98DX3236_PLUS)),
        MPP_MODE(30,
                 MPP_VAR_FUNCTION(0x0, "gpo", NULL,          V_98DX3236_PLUS),
-                MPP_VAR_FUNCTION(0x1, "dev", "a1",          V_98DX3236_PLUS)),
+                MPP_VAR_FUNCTION(0x4, "dev", "a1",          V_98DX3236_PLUS)),
        MPP_MODE(31,
                 MPP_VAR_FUNCTION(0x0, "gpio", NULL,         V_98DX3236_PLUS),
                 MPP_VAR_FUNCTION(0x1, "slv_smi", "mdc",     V_98DX3236_PLUS),
index 4b57a13758a43b49020e8d728662f1dbd5cbf7a3..bafb3d40545e4fd5ddf26d8010601e916603097c 100644 (file)
@@ -576,8 +576,10 @@ static int atmel_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
                for_each_child_of_node(np_config, np) {
                        ret = atmel_pctl_dt_subnode_to_map(pctldev, np, map,
                                                    &reserved_maps, num_maps);
-                       if (ret < 0)
+                       if (ret < 0) {
+                               of_node_put(np);
                                break;
+                       }
                }
        }
 
index 3924779f55785695ec8a8a719ac3f2434a9e5192..1882713e68f932c7074d9d06a2eeaa91c7ad108f 100644 (file)
@@ -59,6 +59,7 @@
 #define GPIO_LS_SYNC           0x60
 
 enum rockchip_pinctrl_type {
+       PX30,
        RV1108,
        RK2928,
        RK3066B,
@@ -701,6 +702,66 @@ static void rockchip_get_recalced_mux(struct rockchip_pin_bank *bank, int pin,
        *bit = data->bit;
 }
 
+static struct rockchip_mux_route_data px30_mux_route_data[] = {
+       {
+               /* cif-d2m0 */
+               .bank_num = 2,
+               .pin = 0,
+               .func = 1,
+               .route_offset = 0x184,
+               .route_val = BIT(16 + 7),
+       }, {
+               /* cif-d2m1 */
+               .bank_num = 3,
+               .pin = 3,
+               .func = 3,
+               .route_offset = 0x184,
+               .route_val = BIT(16 + 7) | BIT(7),
+       }, {
+               /* pdm-m0 */
+               .bank_num = 3,
+               .pin = 22,
+               .func = 2,
+               .route_offset = 0x184,
+               .route_val = BIT(16 + 8),
+       }, {
+               /* pdm-m1 */
+               .bank_num = 2,
+               .pin = 22,
+               .func = 1,
+               .route_offset = 0x184,
+               .route_val = BIT(16 + 8) | BIT(8),
+       }, {
+               /* uart2-rxm0 */
+               .bank_num = 1,
+               .pin = 27,
+               .func = 2,
+               .route_offset = 0x184,
+               .route_val = BIT(16 + 10),
+       }, {
+               /* uart2-rxm1 */
+               .bank_num = 2,
+               .pin = 14,
+               .func = 2,
+               .route_offset = 0x184,
+               .route_val = BIT(16 + 10) | BIT(10),
+       }, {
+               /* uart3-rxm0 */
+               .bank_num = 0,
+               .pin = 17,
+               .func = 2,
+               .route_offset = 0x184,
+               .route_val = BIT(16 + 9),
+       }, {
+               /* uart3-rxm1 */
+               .bank_num = 1,
+               .pin = 15,
+               .func = 2,
+               .route_offset = 0x184,
+               .route_val = BIT(16 + 9) | BIT(9),
+       },
+};
+
 static struct rockchip_mux_route_data rk3128_mux_route_data[] = {
        {
                /* spi-0 */
@@ -1202,6 +1263,97 @@ static int rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
        return ret;
 }
 
+#define PX30_PULL_PMU_OFFSET           0x10
+#define PX30_PULL_GRF_OFFSET           0x60
+#define PX30_PULL_BITS_PER_PIN         2
+#define PX30_PULL_PINS_PER_REG         8
+#define PX30_PULL_BANK_STRIDE          16
+
+static void px30_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
+                                      int pin_num, struct regmap **regmap,
+                                      int *reg, u8 *bit)
+{
+       struct rockchip_pinctrl *info = bank->drvdata;
+
+       /* The first 32 pins of the first bank are located in PMU */
+       if (bank->bank_num == 0) {
+               *regmap = info->regmap_pmu;
+               *reg = PX30_PULL_PMU_OFFSET;
+       } else {
+               *regmap = info->regmap_base;
+               *reg = PX30_PULL_GRF_OFFSET;
+
+               /* correct the offset, as we're starting with the 2nd bank */
+               *reg -= 0x10;
+               *reg += bank->bank_num * PX30_PULL_BANK_STRIDE;
+       }
+
+       *reg += ((pin_num / PX30_PULL_PINS_PER_REG) * 4);
+       *bit = (pin_num % PX30_PULL_PINS_PER_REG);
+       *bit *= PX30_PULL_BITS_PER_PIN;
+}
+
+#define PX30_DRV_PMU_OFFSET            0x20
+#define PX30_DRV_GRF_OFFSET            0xf0
+#define PX30_DRV_BITS_PER_PIN          2
+#define PX30_DRV_PINS_PER_REG          8
+#define PX30_DRV_BANK_STRIDE           16
+
+static void px30_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
+                                     int pin_num, struct regmap **regmap,
+                                     int *reg, u8 *bit)
+{
+       struct rockchip_pinctrl *info = bank->drvdata;
+
+       /* The first 32 pins of the first bank are located in PMU */
+       if (bank->bank_num == 0) {
+               *regmap = info->regmap_pmu;
+               *reg = PX30_DRV_PMU_OFFSET;
+       } else {
+               *regmap = info->regmap_base;
+               *reg = PX30_DRV_GRF_OFFSET;
+
+               /* correct the offset, as we're starting with the 2nd bank */
+               *reg -= 0x10;
+               *reg += bank->bank_num * PX30_DRV_BANK_STRIDE;
+       }
+
+       *reg += ((pin_num / PX30_DRV_PINS_PER_REG) * 4);
+       *bit = (pin_num % PX30_DRV_PINS_PER_REG);
+       *bit *= PX30_DRV_BITS_PER_PIN;
+}
+
+#define PX30_SCHMITT_PMU_OFFSET                        0x38
+#define PX30_SCHMITT_GRF_OFFSET                        0xc0
+#define PX30_SCHMITT_PINS_PER_PMU_REG          16
+#define PX30_SCHMITT_BANK_STRIDE               16
+#define PX30_SCHMITT_PINS_PER_GRF_REG          8
+
+static int px30_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank,
+                                        int pin_num,
+                                        struct regmap **regmap,
+                                        int *reg, u8 *bit)
+{
+       struct rockchip_pinctrl *info = bank->drvdata;
+       int pins_per_reg;
+
+       if (bank->bank_num == 0) {
+               *regmap = info->regmap_pmu;
+               *reg = PX30_SCHMITT_PMU_OFFSET;
+               pins_per_reg = PX30_SCHMITT_PINS_PER_PMU_REG;
+       } else {
+               *regmap = info->regmap_base;
+               *reg = PX30_SCHMITT_GRF_OFFSET;
+               pins_per_reg = PX30_SCHMITT_PINS_PER_GRF_REG;
+               *reg += (bank->bank_num  - 1) * PX30_SCHMITT_BANK_STRIDE;
+       }
+
+       *reg += ((pin_num / pins_per_reg) * 4);
+       *bit = pin_num % pins_per_reg;
+
+       return 0;
+}
+
 #define RV1108_PULL_PMU_OFFSET         0x10
 #define RV1108_PULL_OFFSET             0x110
 #define RV1108_PULL_PINS_PER_REG       8
@@ -1798,6 +1950,7 @@ static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num)
                return !(data & BIT(bit))
                                ? PIN_CONFIG_BIAS_PULL_PIN_DEFAULT
                                : PIN_CONFIG_BIAS_DISABLE;
+       case PX30:
        case RV1108:
        case RK3188:
        case RK3288:
@@ -1841,6 +1994,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank,
                        data |= BIT(bit);
                ret = regmap_write(regmap, reg, data);
                break;
+       case PX30:
        case RV1108:
        case RK3188:
        case RK3288:
@@ -2103,6 +2257,7 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl,
                                        pull == PIN_CONFIG_BIAS_DISABLE);
        case RK3066B:
                return pull ? false : true;
+       case PX30:
        case RV1108:
        case RK3188:
        case RK3288:
@@ -2555,6 +2710,57 @@ static int rockchip_gpio_direction_output(struct gpio_chip *gc,
        return pinctrl_gpio_direction_output(gc->base + offset);
 }
 
+static void rockchip_gpio_set_debounce(struct gpio_chip *gc,
+                                      unsigned int offset, bool enable)
+{
+       struct rockchip_pin_bank *bank = gpiochip_get_data(gc);
+       void __iomem *reg = bank->reg_base + GPIO_DEBOUNCE;
+       unsigned long flags;
+       u32 data;
+
+       clk_enable(bank->clk);
+       raw_spin_lock_irqsave(&bank->slock, flags);
+
+       data = readl(reg);
+       if (enable)
+               data |= BIT(offset);
+       else
+               data &= ~BIT(offset);
+       writel(data, reg);
+
+       raw_spin_unlock_irqrestore(&bank->slock, flags);
+       clk_disable(bank->clk);
+}
+
+/*
+ * gpiolib set_config callback function. The setting of the pin
+ * mux function as 'gpio output' will be handled by the pinctrl subsystem
+ * interface.
+ */
+static int rockchip_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
+                                 unsigned long config)
+{
+       enum pin_config_param param = pinconf_to_config_param(config);
+
+       switch (param) {
+       case PIN_CONFIG_INPUT_DEBOUNCE:
+               rockchip_gpio_set_debounce(gc, offset, true);
+               /*
+                * Rockchip's gpio could only support up to one period
+                * of the debounce clock(pclk), which is far away from
+                * satisftying the requirement, as pclk is usually near
+                * 100MHz shared by all peripherals. So the fact is it
+                * has crippled debounce capability could only be useful
+                * to prevent any spurious glitches from waking up the system
+                * if the gpio is conguired as wakeup interrupt source. Let's
+                * still return -ENOTSUPP as before, to make sure the caller
+                * of gpiod_set_debounce won't change its behaviour.
+                */
+       default:
+               return -ENOTSUPP;
+       }
+}
+
 /*
  * gpiolib gpio_to_irq callback function. Creates a mapping between a GPIO pin
  * and a virtual IRQ, if not already present.
@@ -2580,6 +2786,7 @@ static const struct gpio_chip rockchip_gpiolib_chip = {
        .get_direction  = rockchip_gpio_get_direction,
        .direction_input = rockchip_gpio_direction_input,
        .direction_output = rockchip_gpio_direction_output,
+       .set_config = rockchip_gpio_set_config,
        .to_irq = rockchip_gpio_to_irq,
        .owner = THIS_MODULE,
 };
@@ -3237,6 +3444,43 @@ static int rockchip_pinctrl_probe(struct platform_device *pdev)
        return 0;
 }
 
+static struct rockchip_pin_bank px30_pin_banks[] = {
+       PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", IOMUX_SOURCE_PMU,
+                                            IOMUX_SOURCE_PMU,
+                                            IOMUX_SOURCE_PMU,
+                                            IOMUX_SOURCE_PMU
+                           ),
+       PIN_BANK_IOMUX_FLAGS(1, 32, "gpio1", IOMUX_WIDTH_4BIT,
+                                            IOMUX_WIDTH_4BIT,
+                                            IOMUX_WIDTH_4BIT,
+                                            IOMUX_WIDTH_4BIT
+                           ),
+       PIN_BANK_IOMUX_FLAGS(2, 32, "gpio2", IOMUX_WIDTH_4BIT,
+                                            IOMUX_WIDTH_4BIT,
+                                            IOMUX_WIDTH_4BIT,
+                                            IOMUX_WIDTH_4BIT
+                           ),
+       PIN_BANK_IOMUX_FLAGS(3, 32, "gpio3", IOMUX_WIDTH_4BIT,
+                                            IOMUX_WIDTH_4BIT,
+                                            IOMUX_WIDTH_4BIT,
+                                            IOMUX_WIDTH_4BIT
+                           ),
+};
+
+static struct rockchip_pin_ctrl px30_pin_ctrl = {
+               .pin_banks              = px30_pin_banks,
+               .nr_banks               = ARRAY_SIZE(px30_pin_banks),
+               .label                  = "PX30-GPIO",
+               .type                   = PX30,
+               .grf_mux_offset         = 0x0,
+               .pmu_mux_offset         = 0x0,
+               .iomux_routes           = px30_mux_route_data,
+               .niomux_routes          = ARRAY_SIZE(px30_mux_route_data),
+               .pull_calc_reg          = px30_calc_pull_reg_and_bit,
+               .drv_calc_reg           = px30_calc_drv_reg_and_bit,
+               .schmitt_calc_reg       = px30_calc_schmitt_reg_and_bit,
+};
+
 static struct rockchip_pin_bank rv1108_pin_banks[] = {
        PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", IOMUX_SOURCE_PMU,
                                             IOMUX_SOURCE_PMU,
@@ -3545,6 +3789,8 @@ static struct rockchip_pin_ctrl rk3399_pin_ctrl = {
 };
 
 static const struct of_device_id rockchip_pinctrl_dt_match[] = {
+       { .compatible = "rockchip,px30-pinctrl",
+               .data = &px30_pin_ctrl },
        { .compatible = "rockchip,rv1108-pinctrl",
                .data = &rv1108_pin_ctrl },
        { .compatible = "rockchip,rk2928-pinctrl",
index a7c5eb39b1eb412a97294d43aad88f5b19f9860e..9c3c00515aa0fe20619fa7d2832d28ccee62c0db 100644 (file)
@@ -144,6 +144,7 @@ struct pcs_soc_data {
  * struct pcs_device - pinctrl device instance
  * @res:       resources
  * @base:      virtual address of the controller
+ * @saved_vals: saved values for the controller
  * @size:      size of the ioremapped area
  * @dev:       device entry
  * @np:                device tree node
@@ -172,11 +173,13 @@ struct pcs_soc_data {
 struct pcs_device {
        struct resource *res;
        void __iomem *base;
+       void *saved_vals;
        unsigned size;
        struct device *dev;
        struct device_node *np;
        struct pinctrl_dev *pctl;
        unsigned flags;
+#define PCS_CONTEXT_LOSS_OFF   (1 << 3)
 #define PCS_QUIRK_SHARED_IRQ   (1 << 2)
 #define PCS_FEAT_IRQ           (1 << 1)
 #define PCS_FEAT_PINCONF       (1 << 0)
@@ -1576,6 +1579,67 @@ static int pcs_irq_init_chained_handler(struct pcs_device *pcs,
 }
 
 #ifdef CONFIG_PM
+static int pcs_save_context(struct pcs_device *pcs)
+{
+       int i, mux_bytes;
+       u64 *regsl;
+       u32 *regsw;
+       u16 *regshw;
+
+       mux_bytes = pcs->width / BITS_PER_BYTE;
+
+       if (!pcs->saved_vals)
+               pcs->saved_vals = devm_kzalloc(pcs->dev, pcs->size, GFP_ATOMIC);
+
+       switch (pcs->width) {
+       case 64:
+               regsl = (u64 *)pcs->saved_vals;
+               for (i = 0; i < pcs->size / mux_bytes; i++)
+                       regsl[i] = pcs->read(pcs->base + i * mux_bytes);
+               break;
+       case 32:
+               regsw = (u32 *)pcs->saved_vals;
+               for (i = 0; i < pcs->size / mux_bytes; i++)
+                       regsw[i] = pcs->read(pcs->base + i * mux_bytes);
+               break;
+       case 16:
+               regshw = (u16 *)pcs->saved_vals;
+               for (i = 0; i < pcs->size / mux_bytes; i++)
+                       regshw[i] = pcs->read(pcs->base + i * mux_bytes);
+               break;
+       }
+
+       return 0;
+}
+
+static void pcs_restore_context(struct pcs_device *pcs)
+{
+       int i, mux_bytes;
+       u64 *regsl;
+       u32 *regsw;
+       u16 *regshw;
+
+       mux_bytes = pcs->width / BITS_PER_BYTE;
+
+       switch (pcs->width) {
+       case 64:
+               regsl = (u64 *)pcs->saved_vals;
+               for (i = 0; i < pcs->size / mux_bytes; i++)
+                       pcs->write(regsl[i], pcs->base + i * mux_bytes);
+               break;
+       case 32:
+               regsw = (u32 *)pcs->saved_vals;
+               for (i = 0; i < pcs->size / mux_bytes; i++)
+                       pcs->write(regsw[i], pcs->base + i * mux_bytes);
+               break;
+       case 16:
+               regshw = (u16 *)pcs->saved_vals;
+               for (i = 0; i < pcs->size / mux_bytes; i++)
+                       pcs->write(regshw[i], pcs->base + i * mux_bytes);
+               break;
+       }
+}
+
 static int pinctrl_single_suspend(struct platform_device *pdev,
                                        pm_message_t state)
 {
@@ -1585,6 +1649,9 @@ static int pinctrl_single_suspend(struct platform_device *pdev,
        if (!pcs)
                return -EINVAL;
 
+       if (pcs->flags & PCS_CONTEXT_LOSS_OFF)
+               pcs_save_context(pcs);
+
        return pinctrl_force_sleep(pcs->pctl);
 }
 
@@ -1596,6 +1663,9 @@ static int pinctrl_single_resume(struct platform_device *pdev)
        if (!pcs)
                return -EINVAL;
 
+       if (pcs->flags & PCS_CONTEXT_LOSS_OFF)
+               pcs_restore_context(pcs);
+
        return pinctrl_force_default(pcs->pctl);
 }
 #endif
@@ -1824,7 +1894,7 @@ static const struct pcs_soc_data pinctrl_single_dra7 = {
 };
 
 static const struct pcs_soc_data pinctrl_single_am437x = {
-       .flags = PCS_QUIRK_SHARED_IRQ,
+       .flags = PCS_QUIRK_SHARED_IRQ | PCS_CONTEXT_LOSS_OFF,
        .irq_enable_mask = (1 << 29),   /* OMAP_WAKEUP_EN */
        .irq_status_mask = (1 << 30),   /* OMAP_WAKEUP_EVENT */
 };
index ad80a17c9990d76efe1cb725bd26a38f310967c3..0e22f52b2a19983b97b95954141f90bf4d7aafa9 100644 (file)
@@ -58,7 +58,10 @@ struct msm_pinctrl {
        struct device *dev;
        struct pinctrl_dev *pctrl;
        struct gpio_chip chip;
+       struct pinctrl_desc desc;
        struct notifier_block restart_nb;
+
+       struct irq_chip irq_chip;
        int irq;
 
        raw_spinlock_t lock;
@@ -390,13 +393,6 @@ static const struct pinconf_ops msm_pinconf_ops = {
        .pin_config_group_set   = msm_config_group_set,
 };
 
-static struct pinctrl_desc msm_pinctrl_desc = {
-       .pctlops = &msm_pinctrl_ops,
-       .pmxops = &msm_pinmux_ops,
-       .confops = &msm_pinconf_ops,
-       .owner = THIS_MODULE,
-};
-
 static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
        const struct msm_pingroup *g;
@@ -506,29 +502,46 @@ static void msm_gpio_dbg_show_one(struct seq_file *s,
        int is_out;
        int drive;
        int pull;
-       u32 ctl_reg;
+       int val;
+       u32 ctl_reg, io_reg;
 
-       static const char * const pulls[] = {
+       static const char * const pulls_keeper[] = {
                "no pull",
                "pull down",
                "keeper",
                "pull up"
        };
 
+       static const char * const pulls_no_keeper[] = {
+               "no pull",
+               "pull down",
+               "pull up",
+       };
+
        if (!gpiochip_line_is_valid(chip, offset))
                return;
 
        g = &pctrl->soc->groups[offset];
        ctl_reg = readl(pctrl->regs + g->ctl_reg);
+       io_reg = readl(pctrl->regs + g->io_reg);
 
        is_out = !!(ctl_reg & BIT(g->oe_bit));
        func = (ctl_reg >> g->mux_bit) & 7;
        drive = (ctl_reg >> g->drv_bit) & 7;
        pull = (ctl_reg >> g->pull_bit) & 3;
 
-       seq_printf(s, " %-8s: %-3s %d", g->name, is_out ? "out" : "in", func);
+       if (is_out)
+               val = !!(io_reg & BIT(g->out_bit));
+       else
+               val = !!(io_reg & BIT(g->in_bit));
+
+       seq_printf(s, " %-8s: %-3s", g->name, is_out ? "out" : "in");
+       seq_printf(s, " %-4s func%d", val ? "high" : "low", func);
        seq_printf(s, " %dmA", msm_regval_to_drive(drive));
-       seq_printf(s, " %s", pulls[pull]);
+       if (pctrl->soc->pull_no_keeper)
+               seq_printf(s, " %s", pulls_no_keeper[pull]);
+       else
+               seq_printf(s, " %s", pulls_keeper[pull]);
        seq_puts(s, "\n");
 }
 
@@ -776,15 +789,6 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
        return 0;
 }
 
-static struct irq_chip msm_gpio_irq_chip = {
-       .name           = "msmgpio",
-       .irq_mask       = msm_gpio_irq_mask,
-       .irq_unmask     = msm_gpio_irq_unmask,
-       .irq_ack        = msm_gpio_irq_ack,
-       .irq_set_type   = msm_gpio_irq_set_type,
-       .irq_set_wake   = msm_gpio_irq_set_wake,
-};
-
 static void msm_gpio_irq_handler(struct irq_desc *desc)
 {
        struct gpio_chip *gc = irq_desc_get_handler_data(desc);
@@ -877,6 +881,13 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
        chip->of_node = pctrl->dev->of_node;
        chip->need_valid_mask = msm_gpio_needs_valid_mask(pctrl);
 
+       pctrl->irq_chip.name = "msmgpio";
+       pctrl->irq_chip.irq_mask = msm_gpio_irq_mask;
+       pctrl->irq_chip.irq_unmask = msm_gpio_irq_unmask;
+       pctrl->irq_chip.irq_ack = msm_gpio_irq_ack;
+       pctrl->irq_chip.irq_set_type = msm_gpio_irq_set_type;
+       pctrl->irq_chip.irq_set_wake = msm_gpio_irq_set_wake;
+
        ret = gpiochip_add_data(&pctrl->chip, pctrl);
        if (ret) {
                dev_err(pctrl->dev, "Failed register gpiochip\n");
@@ -890,15 +901,28 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
                return ret;
        }
 
-       ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), 0, 0, chip->ngpio);
-       if (ret) {
-               dev_err(pctrl->dev, "Failed to add pin range\n");
-               gpiochip_remove(&pctrl->chip);
-               return ret;
+       /*
+        * For DeviceTree-supported systems, the gpio core checks the
+        * pinctrl's device node for the "gpio-ranges" property.
+        * If it is present, it takes care of adding the pin ranges
+        * for the driver. In this case the driver can skip ahead.
+        *
+        * In order to remain compatible with older, existing DeviceTree
+        * files which don't set the "gpio-ranges" property or systems that
+        * utilize ACPI the driver has to call gpiochip_add_pin_range().
+        */
+       if (!of_property_read_bool(pctrl->dev->of_node, "gpio-ranges")) {
+               ret = gpiochip_add_pin_range(&pctrl->chip,
+                       dev_name(pctrl->dev), 0, 0, chip->ngpio);
+               if (ret) {
+                       dev_err(pctrl->dev, "Failed to add pin range\n");
+                       gpiochip_remove(&pctrl->chip);
+                       return ret;
+               }
        }
 
        ret = gpiochip_irqchip_add(chip,
-                                  &msm_gpio_irq_chip,
+                                  &pctrl->irq_chip,
                                   0,
                                   handle_edge_irq,
                                   IRQ_TYPE_NONE);
@@ -908,7 +932,7 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl)
                return -ENOSYS;
        }
 
-       gpiochip_set_chained_irqchip(chip, &msm_gpio_irq_chip, pctrl->irq,
+       gpiochip_set_chained_irqchip(chip, &pctrl->irq_chip, pctrl->irq,
                                     msm_gpio_irq_handler);
 
        return 0;
@@ -979,11 +1003,15 @@ int msm_pinctrl_probe(struct platform_device *pdev,
                return pctrl->irq;
        }
 
-     &n