linux-mips.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver
@ 2017-01-17 23:14 Paul Cercueil
  2017-01-17 23:14 ` [PATCH 01/13] Documentation: dt/bindings: Document pinctrl-ingenic Paul Cercueil
                   ` (14 more replies)
  0 siblings, 15 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-17 23:14 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton
  Cc: linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, james.hogan

Hi,

This set of patches introduces a new pinctrl driver for the Ingenic
JZ4740 and JZ4780, which handles pin configuration, pin muxing and
GPIO config for those MIPS SoCs.

The initial driver was developed by to Paul Burton, so I'll expect his
Signed-Off-By to be added to each patch. It has been severely modified
and improved by myself, notably to add support for the JZ4740 (the
initial non-upstream driver only handled the JZ4780).

I successfully tested it on Imagination Technologies' CI20 board (JZ4780),
as well as on the Dingoo A320 chinese handheld console (JZ4740).

One patch in this series add a pinctrl configuration for some drivers
instanciated in the QI LB60 devicetree. Since I don't own this device,
this one patch was not tested.

Some words about the driver itself:
- pinctrl-ingenic.c contains the core functions that can be shared
  across all Ingenic SoCs,
- pinctrl-jz4740.c contains the JZ4740-specific low-level functions and
  the jz4740-pinctrl driver,
- pinctrl-jz4780.c contains the JZ4780-specific low-level functions and
  the jz4780-pinctrl driver.

The reason behind using a common file sharing core functions and backend
ops for each SoC version, is that the pin/GPIO controllers of the Ingenic
SoCs are extremely similar across SoC versions, except that some have the
registers shuffled around. Making a distinct separation permits the reuse
of large parts of the driver to support the two SoC versions.

One problem still unresolved: the pinctrl framework does not allow us to
configure each pin on demand (someone please prove me wrong), when the
various PWM channels are requested or released. For instance, the PWM
channels can be configured from sysfs, which would require all PWM pins
to be configured properly beforehand for the PWM function, eventually
causing conflicts with other platform or board drivers.

The proper solution here would be to modify the pwm-jz4740 driver to
handle only one PWM channel, and create an instance of this driver
for each one of the 8 PWM channels. Then, it could use the pinctrl
framework to dynamically configure the PWM pin it controls.

Until this can be done, the only jz4740 board supported upstream
(Qi lb60) could configure all of its connected PWM pins in PWM function
mode, if those are not used by other drivers nor by GPIOs on the
board. The only jz4780 board upstream (CI20) does not yet support the
PWM driver.

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH 01/13] Documentation: dt/bindings: Document pinctrl-ingenic
  2017-01-17 23:14 [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
@ 2017-01-17 23:14 ` Paul Cercueil
  2017-01-18 23:45   ` Linus Walleij
  2017-01-17 23:14 ` [PATCH 02/13] pinctrl-jz4740: add a pinctrl driver for the Ingenic jz4740 SoC Paul Cercueil
                   ` (13 subsequent siblings)
  14 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-01-17 23:14 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton
  Cc: linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

From: Paul Burton <paul.burton@imgtec.com>

This commit adds documentation for the devicetree bidings of the
pinctrl-ingenic driver, which handles pin configuration, pin muxing
and GPIOs of the Ingenic SoCs currently supported by the Linux kernel.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 .../bindings/pinctrl/ingenic,pinctrl.txt           | 173 +++++++++++++++++++++
 1 file changed, 173 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt

diff --git a/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
new file mode 100644
index 000000000000..e59f7e7b6a49
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
@@ -0,0 +1,173 @@
+Ingenic jz47xx pin controller
+
+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".
+
+For the jz47xx SoCs, pin control is tightly bound with GPIO ports. All pins may
+be used as GPIOs, multiplexed device functions are configured within the
+GPIO port configuration registers and it is typical to refer to pins using the
+naming scheme "PxN" where x is a character identifying the GPIO port with
+which the pin is associated and N is an integer from 0 to 31 identifying the
+pin within that GPIO port. For example PA0 is the first pin in GPIO port A, and
+PB31 is the last pin in GPIO port B. The jz4740 contains 4 GPIO ports, PA to
+PD, for a total of 128 pins. The jz4780 contains 6 GPIO ports, PA to PF, for a
+total of 192 pins.
+
+
+##### Pin controller node #####
+
+Required properties:
+- compatible: One of:
+  - "ingenic,jz4740-pinctrl"
+  - "ingenic,jz4780-pinctrl"
+- #address-cells: Should contain the integer 1.
+- #size-cells: Should contain the integer 1.
+- ranges: Should be empty.
+
+Required sub-nodes:
+  - gpio-chips (see below)
+  - functions (see below)
+
+The pin controller node must have two sub-nodes, 'gpio-chips' and 'functions'.
+
+
+##### 'gpio-chips' sub-node #####
+
+The gpio-chips node will contain sub-nodes that correspond to GPIO controllers
+(one sub-node per GPIO controller).
+
+Required properties:
+- #address-cells: Should contain the integer 1.
+- #size-cells: Should contain the integer 1.
+- ranges: Should be empty.
+
+
+##### 'functions' sub-node #####
+
+The "functions" node will contain sub-nodes that correspond to pin function
+nodes.
+
+Required properties:
+- None.
+
+
+##### GPIO controller node #####
+
+Each subnode of the 'gpio-chips' node is a GPIO controller node.
+
+Required properties:
+- gpio-controller: Identifies this node as a GPIO controller.
+- #gpio-cells: Should contain the integer 2.
+- reg: Should contain the physical address and length of the GPIO controller's
+  configuration registers.
+
+Optional properties:
+- interrupt-controller: The GPIO controllers can optionally configure the
+  GPIOs as interrupt sources. In this case, the 'interrupt-controller'
+  standalone property should be supplied.
+- #interrupt-cells: Required if 'interrupt-controller' is also specified.
+  In that case, it should contain the integer 2.
+- interrupts: Required if 'interrupt-controller' is also specified.
+  In that case, it should contain the IRQ number of this GPIO controller.
+- ingenic,pull-ups: A bit mask identifying the pins associated with this GPIO
+  port which feature a pull-up resistor. The default mask is 0x0.
+- ingenic,pull-downs: A bit mask identifying the pins associated with this GPIO
+  port which feature a pull-down resistor. The default mask is 0x0.
+  Each pin of the jz47xx SoCs may feature a single bias resistor, thus there
+  should be no bits which are set in both ingenic,pull-ups & ingenic,pull-downs.
+
+
+##### Pin function node #####
+
+Each subnode of the 'functions' node is a pin function node.
+
+These subnodes represent a functionality of the SoC which may be exposed
+through one or more groups of pins, represented as subnodes of the pin
+function node. For example a function may be uart0, which may be exposed
+through the group of pins PF0 to PF3.
+
+Required pin function node properties:
+- None.
+
+
+##### Pin group node #####
+
+Each subnode of a pin function node is a pin group node.
+
+Required pin group node properties:
+- ingenic,pins: A set of values representing the pins within this pin group and
+  their configuration. Four values should be provided for each pin:
+  - The phandle of the GPIO controller node for the GPIO port within which the
+    pin is found.
+  - The index of the pin within its GPIO port (an integer in the range 0 to 31
+    inclusive).
+  - The index of the shared function port to be programmed in the GPIO port
+    registers for this pin.
+    Tables of these may be found in the jz4740 and jz4780 programming
+    manuals within the "General-Purpose I/O Ports" -> "Overview" section.
+    The value can either be supplied directly (0 for function 0, 1 for
+    function 1, etc.) or using the macros present in
+    <dt-bindings/pinctrl/ingenic.h>.
+    The special macro JZ_PIN_MODE_GPIO can be used to specify that the pin is
+    to be used as a GPIO. This is useful, for instance, when you just want to
+    set the electrical configuration of a pin used as GPIO.
+  - The phandle of a pin configuration node specifying the electrical
+    configuration that should be applied to the pin.
+
+For example the function 'msc0' may be exposed through 2 different pin groups,
+one in GPIO port A and one in GPIO port E:
+
+  bias-configs {
+    nobias: nobias {
+      bias-disable;
+    };
+  };
+
+  functions {
+    pinfunc_msc0: msc0 {
+      pins_msc0_pa: msc0-pa {
+        ingenic,pins = <&gpa  4 1 &nobias   /* d4 */
+                        &gpa  5 1 &nobias   /* d5 */
+                        &gpa  6 1 &nobias   /* d6 */
+                        &gpa  7 1 &nobias   /* d7 */
+                        &gpa 18 1 &nobias   /* clk */
+                        &gpa 19 1 &nobias   /* cmd */
+                        &gpa 20 1 &nobias   /* d0 */
+                        &gpa 21 1 &nobias   /* d1 */
+                        &gpa 22 1 &nobias   /* d2 */
+                        &gpa 23 1 &nobias   /* d3 */
+                        &gpa 24 1 &nobias>; /* rst */
+      };
+
+      pins_msc0_pe: msc0-pe {
+        ingenic,pins = <&gpe 20 0 &nobias   /* d0 */
+                        &gpe 21 0 &nobias   /* d1 */
+                        &gpe 22 0 &nobias   /* d2 */
+                        &gpe 23 0 &nobias   /* d3 */
+                        &gpe 28 0 &nobias   /* clk */
+                        &gpe 29 0 &nobias>; /* cmd */
+      };
+    };
+  };
+
+
+##### Pin configuration node #####
+
+The pin configuration nodes are referenced by phandle, and can be placed
+anywhere in the device tree (including in the pin controller node, or in a
+sub-node that is not 'gpio-chips' or 'functions').
+
+Pin configuration nodes use generic pinconf properties to specify an electrical
+configuration of a pin. The only configurable property for a pin of the jz47xx
+SoCs is whether to enable its bias resistor. Thus the only supported pinconf
+properties are:
+
+- bias-disable
+- bias-pull-up
+- bias-pull-down
+
+No arguments are supported for any of these properties.
+
+For more information about generic pinconfig properties, see
+Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH 02/13] pinctrl-jz4740: add a pinctrl driver for the Ingenic jz4740 SoC
  2017-01-17 23:14 [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
  2017-01-17 23:14 ` [PATCH 01/13] Documentation: dt/bindings: Document pinctrl-ingenic Paul Cercueil
@ 2017-01-17 23:14 ` Paul Cercueil
  2017-01-18 10:16   ` Linus Walleij
  2017-01-17 23:14 ` [PATCH 03/13] pinctrl-jz4780: add a pinctrl driver for the Ingenic jz4780 SoC Paul Cercueil
                   ` (12 subsequent siblings)
  14 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-01-17 23:14 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton
  Cc: linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

From: Paul Burton <paul.burton@imgtec.com>

This driver handles pin configuration, pin muxing, and GPIOs of the
jz4740 SoC from Ingenic.

It is separated into two files:
- pinctrl-ingenic.c, which contains the core functions that can be
  shared across all Ingenic SoCs,
- pinctrl-jz4740.c, which contains the jz4740-pinctrl driver.

The reason behind separating some functions out of the jz4740-pinctrl
driver, is that the pin/GPIO controllers of the Ingenic SoCs are
extremely similar across SoC versions, except that some have the
registers shuffled around. Making a distinct separation will permit the
reuse of large parts of the driver to support the other SoCs from
Ingenic.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/pinctrl/Kconfig                   |   1 +
 drivers/pinctrl/Makefile                  |   1 +
 drivers/pinctrl/ingenic/Kconfig           |  14 +
 drivers/pinctrl/ingenic/Makefile          |   2 +
 drivers/pinctrl/ingenic/pinctrl-ingenic.c | 847 ++++++++++++++++++++++++++++++
 drivers/pinctrl/ingenic/pinctrl-ingenic.h |  42 ++
 drivers/pinctrl/ingenic/pinctrl-jz4740.c  | 190 +++++++
 include/dt-bindings/pinctrl/ingenic.h     |  11 +
 8 files changed, 1108 insertions(+)
 create mode 100644 drivers/pinctrl/ingenic/Kconfig
 create mode 100644 drivers/pinctrl/ingenic/Makefile
 create mode 100644 drivers/pinctrl/ingenic/pinctrl-ingenic.c
 create mode 100644 drivers/pinctrl/ingenic/pinctrl-ingenic.h
 create mode 100644 drivers/pinctrl/ingenic/pinctrl-jz4740.c
 create mode 100644 include/dt-bindings/pinctrl/ingenic.h

diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 54044a8ecbd7..e13ca8cc1cde 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -282,6 +282,7 @@ source "drivers/pinctrl/aspeed/Kconfig"
 source "drivers/pinctrl/bcm/Kconfig"
 source "drivers/pinctrl/berlin/Kconfig"
 source "drivers/pinctrl/freescale/Kconfig"
+source "drivers/pinctrl/ingenic/Kconfig"
 source "drivers/pinctrl/intel/Kconfig"
 source "drivers/pinctrl/mvebu/Kconfig"
 source "drivers/pinctrl/nomadik/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 25d50a86981d..93b6837af7bb 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_ARCH_ASPEED)	+= aspeed/
 obj-y				+= bcm/
 obj-$(CONFIG_PINCTRL_BERLIN)	+= berlin/
 obj-y				+= freescale/
+obj-$(CONFIG_PINCTRL_INGENIC)	+= ingenic/
 obj-$(CONFIG_X86)		+= intel/
 obj-$(CONFIG_PINCTRL_MVEBU)	+= mvebu/
 obj-y				+= nomadik/
diff --git a/drivers/pinctrl/ingenic/Kconfig b/drivers/pinctrl/ingenic/Kconfig
new file mode 100644
index 000000000000..9923ce127183
--- /dev/null
+++ b/drivers/pinctrl/ingenic/Kconfig
@@ -0,0 +1,14 @@
+#
+# Ingenic SoCs pin control drivers
+#
+config PINCTRL_INGENIC
+	bool
+	select PINMUX
+	select GPIOLIB_IRQCHIP
+	select GENERIC_PINCONF
+
+config PINCTRL_JZ4740
+	bool "Pinctrl driver for the Ingenic JZ4740 SoC"
+	default y
+	depends on MACH_JZ4740 || COMPILE_TEST
+	select PINCTRL_INGENIC
diff --git a/drivers/pinctrl/ingenic/Makefile b/drivers/pinctrl/ingenic/Makefile
new file mode 100644
index 000000000000..8b2c8b789dc9
--- /dev/null
+++ b/drivers/pinctrl/ingenic/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_PINCTRL_INGENIC)	+= pinctrl-ingenic.o
+obj-$(CONFIG_PINCTRL_JZ4740)	+= pinctrl-jz4740.o
diff --git a/drivers/pinctrl/ingenic/pinctrl-ingenic.c b/drivers/pinctrl/ingenic/pinctrl-ingenic.c
new file mode 100644
index 000000000000..22a2be6d72f1
--- /dev/null
+++ b/drivers/pinctrl/ingenic/pinctrl-ingenic.c
@@ -0,0 +1,847 @@
+/*
+ * Ingenic SoCs pinctrl driver
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Copyright (c) 2017 Paul Cercueil <paul@crapouillou.net>
+ *
+ * Authors: Paul Burton <paul.burton@imgtec.com>,
+ *          Paul Cercueil <paul@crapouillou.net>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/compiler.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/pinctrl/ingenic.h>
+
+#include "../core.h"
+#include "../pinconf.h"
+#include "pinctrl-ingenic.h"
+
+struct ingenic_pinctrl;
+
+struct ingenic_pinctrl_pin {
+	struct ingenic_gpio_chip *gpio_chip;
+	unsigned int idx;
+	unsigned int func;
+	unsigned long *configs;
+	unsigned int num_configs;
+};
+
+struct ingenic_pinctrl_group {
+	const char *name;
+	struct device_node *of_node;
+
+	unsigned int num_pins;
+	struct ingenic_pinctrl_pin *pins;
+	unsigned int *pin_indices;
+};
+
+struct ingenic_pinctrl_func {
+	const char *name;
+	struct device_node *of_node;
+
+	unsigned int num_groups;
+	struct ingenic_pinctrl_group **groups;
+	const char **group_names;
+};
+
+struct ingenic_gpio_chip {
+	char name[3];
+	unsigned int idx;
+	void __iomem *base;
+	struct gpio_chip gc;
+	struct irq_chip irq_chip;
+	struct ingenic_pinctrl *pinctrl;
+	const struct ingenic_pinctrl_ops *ops;
+	uint32_t pull_ups;
+	uint32_t pull_downs;
+	unsigned int irq;
+	struct pinctrl_gpio_range grange;
+};
+
+struct ingenic_pinctrl {
+	struct device *dev;
+	uint32_t base;
+	struct pinctrl_dev *pctl;
+	struct pinctrl_pin_desc *pdesc;
+
+	unsigned int num_gpio_chips;
+	struct ingenic_gpio_chip *gpio_chips;
+
+	unsigned int num_groups;
+	struct ingenic_pinctrl_group *groups;
+
+	unsigned int num_funcs;
+	struct ingenic_pinctrl_func *funcs;
+};
+
+#define gc_to_jzgc(gpiochip) \
+	container_of(gpiochip, struct ingenic_gpio_chip, gc)
+
+#define PINS_PER_GPIO_PORT 32
+
+static struct ingenic_pinctrl_group *find_group_by_of_node(
+		struct ingenic_pinctrl *jzpc, struct device_node *np)
+{
+	int i;
+
+	for (i = 0; i < jzpc->num_groups; i++)
+		if (jzpc->groups[i].of_node == np)
+			return &jzpc->groups[i];
+
+	return NULL;
+}
+
+static struct ingenic_pinctrl_func *find_func_by_of_node(
+		struct ingenic_pinctrl *jzpc, struct device_node *np)
+{
+	int i;
+
+	for (i = 0; i < jzpc->num_funcs; i++)
+		if (jzpc->funcs[i].of_node == np)
+			return &jzpc->funcs[i];
+
+	return NULL;
+}
+
+static void ingenic_gpio_set(struct gpio_chip *gc,
+		unsigned int offset, int value)
+{
+	struct ingenic_gpio_chip *jzgc = gc_to_jzgc(gc);
+
+	jzgc->ops->gpio_set_value(jzgc->base, offset, value);
+}
+
+static int ingenic_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+	struct ingenic_gpio_chip *jzgc = gc_to_jzgc(gc);
+
+	return jzgc->ops->gpio_get_value(jzgc->base, offset);
+}
+
+static int ingenic_gpio_direction_input(struct gpio_chip *gc,
+		unsigned int offset)
+{
+	return pinctrl_gpio_direction_input(gc->base + offset);
+}
+
+static int ingenic_gpio_direction_output(struct gpio_chip *gc,
+		unsigned int offset, int value)
+{
+	ingenic_gpio_set(gc, offset, value);
+	return pinctrl_gpio_direction_output(gc->base + offset);
+}
+
+static void ingenic_gpio_irq_mask(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gc_to_jzgc(gc);
+
+	jzgc->ops->irq_mask(jzgc->base, irqd->hwirq, true);
+}
+
+static void ingenic_gpio_irq_unmask(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gc_to_jzgc(gc);
+
+	jzgc->ops->irq_mask(jzgc->base, irqd->hwirq, false);
+}
+
+static void ingenic_gpio_irq_ack(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gc_to_jzgc(gc);
+	unsigned int high;
+	int irq = irqd->hwirq;
+
+	if (irqd_get_trigger_type(irqd) == IRQ_TYPE_EDGE_BOTH) {
+		/*
+		 * Switch to an interrupt for the opposite edge to the one that
+		 * triggered the interrupt being ACKed.
+		 */
+		high = jzgc->ops->gpio_get_value(jzgc->base, irq);
+		if (high)
+			jzgc->ops->irq_set_type(jzgc->base, irq,
+					IRQ_TYPE_EDGE_FALLING);
+		else
+			jzgc->ops->irq_set_type(jzgc->base, irq,
+					IRQ_TYPE_EDGE_RISING);
+	}
+
+	jzgc->ops->irq_ack(jzgc->base, irq);
+}
+
+static int ingenic_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gc_to_jzgc(gc);
+
+	switch (type) {
+	case IRQ_TYPE_EDGE_BOTH:
+	case IRQ_TYPE_EDGE_RISING:
+	case IRQ_TYPE_EDGE_FALLING:
+	case IRQ_TYPE_LEVEL_HIGH:
+	case IRQ_TYPE_LEVEL_LOW:
+		break;
+	default:
+		pr_err("unsupported external interrupt type\n");
+		return -EINVAL;
+	}
+
+	if (type & IRQ_TYPE_EDGE_BOTH)
+		irq_set_handler_locked(irqd, handle_edge_irq);
+	else
+		irq_set_handler_locked(irqd, handle_level_irq);
+
+	if (type == IRQ_TYPE_EDGE_BOTH) {
+		/*
+		 * The hardware does not support interrupts on both edges. The
+		 * best we can do is to set up a single-edge interrupt and then
+		 * switch to the opposing edge when ACKing the interrupt.
+		 */
+		int value = jzgc->ops->gpio_get_value(jzgc->base, irqd->hwirq);
+
+		type = value ? IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING;
+	}
+
+	jzgc->ops->irq_set_type(jzgc->base, irqd->hwirq, type);
+	return 0;
+}
+
+static int ingenic_gpio_irq_set_wake(struct irq_data *irqd, unsigned int on)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gc_to_jzgc(gc);
+
+	return irq_set_irq_wake(jzgc->irq, on);
+}
+
+static void ingenic_gpio_irq_handler(struct irq_desc *desc)
+{
+	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+	struct ingenic_gpio_chip *jzgc = gc_to_jzgc(gc);
+	struct irq_chip *irq_chip = irq_data_get_irq_chip(&desc->irq_data);
+	unsigned long flag, i;
+
+	chained_irq_enter(irq_chip, desc);
+	flag = jzgc->ops->irq_read(jzgc->base);
+
+	for_each_set_bit(i, &flag, 32)
+		generic_handle_irq(irq_linear_revmap(gc->irqdomain, i));
+	chained_irq_exit(irq_chip, desc);
+}
+
+static int ingenic_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+
+	return jzpc->num_groups;
+}
+
+static const char *ingenic_pinctrl_get_group_name(
+		struct pinctrl_dev *pctldev, unsigned int selector)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+
+	return jzpc->groups[selector].name;
+}
+
+static int ingenic_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+		unsigned int selector, const unsigned int **pins,
+		unsigned int *num_pins)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+
+	if (selector >= jzpc->num_groups)
+		return -EINVAL;
+
+	*pins = jzpc->groups[selector].pin_indices;
+	*num_pins = jzpc->groups[selector].num_pins;
+	return 0;
+}
+
+static int ingenic_pinctrl_dt_node_to_map(
+		struct pinctrl_dev *pctldev, struct device_node *np,
+		struct pinctrl_map **map, unsigned int *num_maps)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	struct ingenic_pinctrl_func *func;
+	struct ingenic_pinctrl_group *group;
+	struct pinctrl_map *new_map;
+	unsigned int map_num, i;
+
+	group = find_group_by_of_node(jzpc, np);
+	if (!group)
+		return -EINVAL;
+
+	func = find_func_by_of_node(jzpc, of_get_parent(np));
+	if (!func)
+		return -EINVAL;
+
+	map_num = 1 + group->num_pins;
+	new_map = devm_kzalloc(jzpc->dev,
+				sizeof(*new_map) * map_num, GFP_KERNEL);
+	if (!new_map)
+		return -ENOMEM;
+
+	new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
+	new_map[0].data.mux.function = func->name;
+	new_map[0].data.mux.group = group->name;
+
+	for (i = 0; i < group->num_pins; i++) {
+		new_map[i + 1].type = PIN_MAP_TYPE_CONFIGS_PIN;
+		new_map[i + 1].data.configs.group_or_pin =
+			jzpc->pdesc[group->pins[i].idx].name;
+		new_map[i + 1].data.configs.configs = group->pins[i].configs;
+		new_map[i + 1].data.configs.num_configs =
+			group->pins[i].num_configs;
+	}
+
+	*map = new_map;
+	*num_maps = map_num;
+	return 0;
+}
+
+static void ingenic_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
+		struct pinctrl_map *map, unsigned int num_maps)
+{
+}
+
+static struct pinctrl_ops ingenic_pctlops = {
+	.get_groups_count = ingenic_pinctrl_get_groups_count,
+	.get_group_name = ingenic_pinctrl_get_group_name,
+	.get_group_pins = ingenic_pinctrl_get_group_pins,
+	.dt_node_to_map = ingenic_pinctrl_dt_node_to_map,
+	.dt_free_map = ingenic_pinctrl_dt_free_map,
+};
+
+static int ingenic_pinmux_get_functions_count(struct pinctrl_dev *pctldev)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+
+	return jzpc->num_funcs;
+}
+
+static const char *ingenic_pinmux_get_function_name(
+		struct pinctrl_dev *pctldev, unsigned int selector)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+
+	return jzpc->funcs[selector].name;
+}
+
+static int ingenic_pinmux_get_function_groups(struct pinctrl_dev *pctldev,
+		unsigned int selector, const char * const **groups,
+		unsigned int * const num_groups)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+
+	if (selector >= jzpc->num_funcs)
+		return -EINVAL;
+
+	*groups = jzpc->funcs[selector].group_names;
+	*num_groups = jzpc->funcs[selector].num_groups;
+
+	return 0;
+}
+
+static int ingenic_pinmux_set_pin_fn(struct ingenic_pinctrl *jzpc,
+		struct ingenic_pinctrl_pin *pin)
+{
+	struct ingenic_gpio_chip *jzgc = &jzpc->gpio_chips[
+		pin->idx / PINS_PER_GPIO_PORT];
+	unsigned int idx = pin->idx % PINS_PER_GPIO_PORT;
+
+	if (pin->func == JZ_PIN_MODE_GPIO) {
+		dev_dbg(jzpc->dev, "set pin P%c%u to GPIO\n",
+				'A' + pin->gpio_chip->idx, idx);
+
+		jzgc->ops->set_gpio(jzgc->base, idx, false);
+	} else if (pin->func < jzgc->ops->nb_functions) {
+		dev_dbg(jzpc->dev, "set pin P%c%u to function %u\n",
+				'A' + pin->gpio_chip->idx, idx, pin->func);
+
+		jzgc->ops->set_function(jzgc->base, idx, pin->func);
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ingenic_pinmux_set_mux(struct pinctrl_dev *pctldev,
+		unsigned int selector, unsigned int group)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	struct ingenic_pinctrl_group *grp = &jzpc->groups[group];
+	unsigned int i;
+	int err = 0;
+
+	if (selector >= jzpc->num_funcs || group >= jzpc->num_groups)
+		return -EINVAL;
+
+	for (i = 0; i < grp->num_pins; i++) {
+		err = ingenic_pinmux_set_pin_fn(jzpc, &grp->pins[i]);
+		if (err)
+			break;
+	}
+
+	return err;
+}
+
+static int ingenic_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
+		struct pinctrl_gpio_range *range,
+		unsigned int offset, bool input)
+{
+	struct ingenic_gpio_chip *jzgc = gc_to_jzgc(range->gc);
+	unsigned int idx;
+
+	idx = offset - (jzgc->idx * PINS_PER_GPIO_PORT);
+
+	jzgc->ops->set_gpio(jzgc->base, idx, !input);
+	return 0;
+}
+
+static struct pinmux_ops ingenic_pmxops = {
+	.get_functions_count = ingenic_pinmux_get_functions_count,
+	.get_function_name = ingenic_pinmux_get_function_name,
+	.get_function_groups = ingenic_pinmux_get_function_groups,
+	.set_mux = ingenic_pinmux_set_mux,
+	.gpio_set_direction = ingenic_pinmux_gpio_set_direction,
+};
+
+static int ingenic_pinconf_get(struct pinctrl_dev *pctldev,
+		unsigned int pin, unsigned long *config)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	struct ingenic_gpio_chip *jzgc;
+	enum pin_config_param param = pinconf_to_config_param(*config);
+	unsigned int idx, pull;
+
+	if (pin >= (jzpc->num_gpio_chips * PINS_PER_GPIO_PORT))
+		return -EINVAL;
+	jzgc = &jzpc->gpio_chips[pin / PINS_PER_GPIO_PORT];
+	idx = pin % PINS_PER_GPIO_PORT;
+
+	pull = jzgc->ops->get_bias(jzgc->base, idx);
+
+	switch (param) {
+	case PIN_CONFIG_BIAS_DISABLE:
+		if (pull)
+			return -EINVAL;
+		break;
+
+	case PIN_CONFIG_BIAS_PULL_UP:
+		if (!pull || !(jzgc->pull_ups & (1 << idx)))
+			return -EINVAL;
+		break;
+
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		if (!pull || !(jzgc->pull_downs & (1 << idx)))
+			return -EINVAL;
+		break;
+
+	default:
+		return -ENOTSUPP;
+	}
+
+	*config = pinconf_to_config_packed(param, 1);
+	return 0;
+}
+
+static int ingenic_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
+		unsigned long *configs, unsigned int num_configs)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	struct ingenic_gpio_chip *jzgc;
+	unsigned int idx, cfg;
+
+	if (pin >= (jzpc->num_gpio_chips * PINS_PER_GPIO_PORT))
+		return -EINVAL;
+
+	jzgc = &jzpc->gpio_chips[pin / PINS_PER_GPIO_PORT];
+	idx = pin % PINS_PER_GPIO_PORT;
+
+	for (cfg = 0; cfg < num_configs; cfg++) {
+		switch (pinconf_to_config_param(configs[cfg])) {
+		case PIN_CONFIG_BIAS_DISABLE:
+		case PIN_CONFIG_BIAS_PULL_UP:
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			continue;
+		default:
+			return -ENOTSUPP;
+		}
+	}
+
+	for (cfg = 0; cfg < num_configs; cfg++) {
+		switch (pinconf_to_config_param(configs[cfg])) {
+		case PIN_CONFIG_BIAS_DISABLE:
+			jzgc->ops->set_bias(jzgc->base, idx, false);
+			break;
+
+		case PIN_CONFIG_BIAS_PULL_UP:
+			if (!(jzgc->pull_ups & (1 << idx)))
+				return -EINVAL;
+			jzgc->ops->set_bias(jzgc->base, idx, true);
+			break;
+
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			if (!(jzgc->pull_downs & (1 << idx)))
+				return -EINVAL;
+			jzgc->ops->set_bias(jzgc->base, idx, true);
+			break;
+
+		default:
+			unreachable();
+		}
+	}
+
+	return 0;
+}
+
+static struct pinconf_ops ingenic_confops = {
+	.is_generic = true,
+	.pin_config_get = ingenic_pinconf_get,
+	.pin_config_set = ingenic_pinconf_set,
+};
+
+static int ingenic_pinctrl_parse_dt_gpio(struct ingenic_pinctrl *jzpc,
+		struct ingenic_gpio_chip *jzgc, struct device_node *np)
+{
+	int err;
+
+	jzgc->pinctrl = jzpc;
+	snprintf(jzgc->name, sizeof(jzgc->name), "P%c", 'A' + jzgc->idx);
+
+	jzgc->base = of_iomap(np, 0);
+	if (!jzgc->base) {
+		dev_err(jzpc->dev, "failed to map IO memory\n");
+		return -ENXIO;
+	}
+
+	jzgc->gc.base = jzpc->base + (jzgc->idx * PINS_PER_GPIO_PORT);
+	jzgc->gc.ngpio = PINS_PER_GPIO_PORT;
+	jzgc->gc.parent = jzpc->dev;
+	jzgc->gc.of_node = np;
+	jzgc->gc.label = np->name;
+	jzgc->gc.owner = THIS_MODULE;
+
+	jzgc->gc.set = ingenic_gpio_set;
+	jzgc->gc.get = ingenic_gpio_get;
+	jzgc->gc.direction_input = ingenic_gpio_direction_input;
+	jzgc->gc.direction_output = ingenic_gpio_direction_output;
+
+	if (of_property_read_u32_index(np, "ingenic,pull-ups", 0,
+				&jzgc->pull_ups))
+		jzgc->pull_ups = 0;
+	if (of_property_read_u32_index(np, "ingenic,pull-downs", 0,
+				&jzgc->pull_downs))
+		jzgc->pull_downs = 0;
+
+	if (jzgc->pull_ups & jzgc->pull_downs) {
+		dev_err(jzpc->dev, "GPIO port %c has overlapping pull ups & pull downs\n",
+			'A' + jzgc->idx);
+		return -EINVAL;
+	}
+
+	err = devm_gpiochip_add_data(jzpc->dev, &jzgc->gc, NULL);
+	if (err)
+		return err;
+
+	if (!of_find_property(np, "interrupt-controller", NULL))
+		return 0;
+
+	jzgc->irq = irq_of_parse_and_map(np, 0);
+	if (!jzgc->irq)
+		return -EINVAL;
+
+	jzgc->irq_chip.name = jzgc->name;
+	jzgc->irq_chip.irq_unmask = ingenic_gpio_irq_unmask;
+	jzgc->irq_chip.irq_mask = ingenic_gpio_irq_mask;
+	jzgc->irq_chip.irq_ack = ingenic_gpio_irq_ack;
+	jzgc->irq_chip.irq_set_type = ingenic_gpio_irq_set_type;
+	jzgc->irq_chip.irq_set_wake = ingenic_gpio_irq_set_wake;
+	jzgc->irq_chip.flags = IRQCHIP_MASK_ON_SUSPEND;
+
+	err = gpiochip_irqchip_add(&jzgc->gc, &jzgc->irq_chip, 0,
+			handle_level_irq, IRQ_TYPE_NONE);
+	if (err)
+		return err;
+
+	gpiochip_set_chained_irqchip(&jzgc->gc, &jzgc->irq_chip,
+			jzgc->irq, ingenic_gpio_irq_handler);
+	return 0;
+}
+
+static int find_gpio_chip_by_of_node(struct gpio_chip *chip, void *data)
+{
+	return chip->of_node == data;
+}
+
+static int ingenic_pinctrl_parse_dt_pincfg(struct ingenic_pinctrl *jzpc,
+		struct ingenic_pinctrl_pin *pin, phandle cfg_handle)
+{
+	struct device_node *cfg_node;
+	int err;
+
+	cfg_node = of_find_node_by_phandle(cfg_handle);
+	if (!cfg_node)
+		return -EINVAL;
+
+	err = pinconf_generic_parse_dt_config(cfg_node, NULL,
+			&pin->configs, &pin->num_configs);
+	if (err)
+		return err;
+
+	err = devm_add_action(jzpc->dev, (void (*)(void *))kfree, pin->configs);
+	if (err) {
+		kfree(pin->configs);
+		return err;
+	}
+
+	return 0;
+}
+
+static int ingenic_pinctrl_parse_dt_func(struct ingenic_pinctrl *jzpc,
+		struct device_node *np, unsigned int *ifunc,
+		unsigned int *igroup)
+{
+	struct ingenic_pinctrl_func *func;
+	struct ingenic_pinctrl_group *grp;
+	struct device_node *group_node, *gpio_node;
+	struct gpio_chip *gpio_chip;
+	phandle gpio_handle, cfg_handle;
+	struct property *pp;
+	__be32 *plist;
+	unsigned int i, j;
+	int err;
+	const unsigned int vals_per_pin = 4;
+
+	func = &jzpc->funcs[(*ifunc)++];
+	func->of_node = np;
+	func->name = np->name;
+
+	func->num_groups = of_get_child_count(np);
+	func->groups = devm_kzalloc(jzpc->dev, sizeof(*func->groups) *
+			func->num_groups, GFP_KERNEL);
+	func->group_names = devm_kzalloc(jzpc->dev,
+			sizeof(*func->group_names) * func->num_groups,
+			GFP_KERNEL);
+	if (!func->groups || !func->group_names)
+		return -ENOMEM;
+
+	i = 0;
+	for_each_child_of_node(np, group_node) {
+		pp = of_find_property(group_node, "ingenic,pins", NULL);
+		if (!pp)
+			return -EINVAL;
+		if ((pp->length / sizeof(__be32)) % vals_per_pin)
+			return -EINVAL;
+
+		grp = &jzpc->groups[(*igroup)++];
+		grp->of_node = group_node;
+		grp->name = group_node->name;
+		grp->num_pins = (pp->length / sizeof(__be32)) / vals_per_pin;
+		grp->pins = devm_kzalloc(jzpc->dev, sizeof(*grp->pins) *
+				grp->num_pins, GFP_KERNEL);
+		grp->pin_indices = devm_kzalloc(jzpc->dev,
+				sizeof(*grp->pin_indices) * grp->num_pins,
+				GFP_KERNEL);
+		if (!grp->pins)
+			return -EINVAL;
+
+		plist = pp->value;
+		for (j = 0; j < grp->num_pins; j++) {
+			gpio_handle = be32_to_cpup(plist++);
+			grp->pins[j].idx = be32_to_cpup(plist++);
+			grp->pins[j].func = be32_to_cpup(plist++);
+			cfg_handle = be32_to_cpup(plist++);
+
+			gpio_node = of_find_node_by_phandle(gpio_handle);
+			if (!gpio_node)
+				return -EINVAL;
+
+			gpio_chip = gpiochip_find(gpio_node,
+					find_gpio_chip_by_of_node);
+			if (!gpio_chip)
+				return -EINVAL;
+
+			grp->pins[j].gpio_chip = gc_to_jzgc(gpio_chip);
+
+			err = ingenic_pinctrl_parse_dt_pincfg(jzpc,
+					&grp->pins[j], cfg_handle);
+			if (err)
+				return err;
+
+			grp->pins[j].idx += grp->pins[j].gpio_chip->idx *
+				PINS_PER_GPIO_PORT;
+			grp->pin_indices[j] = grp->pins[j].idx;
+		}
+
+		func->groups[i] = grp;
+		func->group_names[i] = grp->name;
+		i++;
+	}
+
+	return 0;
+}
+
+int ingenic_pinctrl_probe(struct platform_device *pdev,
+		const struct ingenic_pinctrl_ops *ops)
+{
+	struct device *dev = &pdev->dev;
+	struct ingenic_pinctrl *jzpc;
+	struct ingenic_gpio_chip *jzgc;
+	struct pinctrl_desc *pctl_desc;
+	struct device_node *np, *chips_node, *functions_node;
+	unsigned int i, j;
+	int err;
+
+	if (!dev->of_node) {
+		dev_err(dev, "device tree node not found\n");
+		return -ENODEV;
+	}
+
+	jzpc = devm_kzalloc(dev, sizeof(*jzpc), GFP_KERNEL);
+	if (!jzpc)
+		return -ENOMEM;
+
+	jzpc->dev = dev;
+	platform_set_drvdata(pdev, jzpc);
+
+	jzpc->base = 0;
+	of_property_read_u32(dev->of_node, "base", &jzpc->base);
+
+	chips_node = of_find_node_by_name(dev->of_node, "gpio-chips");
+	if (!chips_node) {
+		dev_err(dev, "Missing \"chips\" devicetree node\n");
+		return -EINVAL;
+	}
+
+	jzpc->num_gpio_chips = of_get_available_child_count(chips_node);
+	if (!jzpc->num_gpio_chips) {
+		dev_err(dev, "No GPIO chips found\n");
+		return -EINVAL;
+	}
+
+	functions_node = of_find_node_by_name(dev->of_node, "functions");
+	if (!functions_node) {
+		dev_err(dev, "Missing \"functions\" devicetree node\n");
+		return -EINVAL;
+	}
+
+	jzpc->num_funcs = of_get_available_child_count(functions_node);
+	if (!jzpc->num_funcs) {
+		dev_err(dev, "No functions found\n");
+		return -EINVAL;
+	}
+
+	for_each_child_of_node(functions_node, np) {
+		jzpc->num_groups += of_get_available_child_count(np);
+	}
+
+	if (!jzpc->num_groups) {
+		dev_err(dev, "No groups found\n");
+		return -EINVAL;
+	}
+
+	/* allocate memory for GPIO chips, pin groups & functions */
+	jzpc->gpio_chips = devm_kzalloc(jzpc->dev, sizeof(*jzpc->gpio_chips) *
+			jzpc->num_gpio_chips, GFP_KERNEL);
+	jzpc->groups = devm_kzalloc(jzpc->dev, sizeof(*jzpc->groups) *
+			jzpc->num_groups, GFP_KERNEL);
+	jzpc->funcs = devm_kzalloc(jzpc->dev, sizeof(*jzpc->funcs) *
+			jzpc->num_funcs, GFP_KERNEL);
+	pctl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctl_desc), GFP_KERNEL);
+	if (!jzpc->gpio_chips || !jzpc->groups || !jzpc->funcs || !pctl_desc)
+		return -ENOMEM;
+
+	/* fill in pinctrl_desc structure */
+	pctl_desc->name = dev_name(dev);
+	pctl_desc->owner = THIS_MODULE;
+	pctl_desc->pctlops = &ingenic_pctlops;
+	pctl_desc->pmxops = &ingenic_pmxops;
+	pctl_desc->confops = &ingenic_confops;
+	pctl_desc->npins = jzpc->num_gpio_chips * PINS_PER_GPIO_PORT;
+	pctl_desc->pins = jzpc->pdesc = devm_kzalloc(&pdev->dev,
+			sizeof(*jzpc->pdesc) * pctl_desc->npins, GFP_KERNEL);
+	if (!jzpc->pdesc)
+		return -ENOMEM;
+
+	for (i = 0; i < pctl_desc->npins; i++) {
+		jzpc->pdesc[i].number = i;
+		jzpc->pdesc[i].name = kasprintf(GFP_KERNEL, "P%c%d",
+						'A' + (i / PINS_PER_GPIO_PORT),
+						i % PINS_PER_GPIO_PORT);
+	}
+
+	/* Register GPIO chips */
+
+	i = 0;
+	for_each_child_of_node(chips_node, np) {
+		if (!of_find_property(np, "gpio-controller", NULL)) {
+			dev_err(dev, "GPIO chip missing \"gpio-controller\" flag\n");
+			return -EINVAL;
+		}
+
+		jzpc->gpio_chips[i].idx = i;
+		jzpc->gpio_chips[i].ops = ops;
+
+		err = ingenic_pinctrl_parse_dt_gpio(jzpc,
+				&jzpc->gpio_chips[i++], np);
+		if (err) {
+			dev_err(dev, "failed to register GPIO chip: %d\n", err);
+			return err;
+		}
+	}
+
+	i = 0;
+	j = 0;
+	for_each_child_of_node(functions_node, np) {
+		err = ingenic_pinctrl_parse_dt_func(jzpc, np, &i, &j);
+		if (err) {
+			dev_err(dev, "failed to parse function %s\n",
+					np->full_name);
+			return err;
+		}
+	}
+
+	for (i = 0; i < jzpc->num_groups; i++)
+		dev_dbg(dev, "group '%s'\n", jzpc->groups[i].name);
+	for (i = 0; i < jzpc->num_funcs; i++)
+		dev_dbg(dev, "func '%s'\n", jzpc->funcs[i].name);
+
+	jzpc->pctl = pinctrl_register(pctl_desc, dev, jzpc);
+	if (!jzpc->pctl) {
+		dev_err(dev, "Failed pinctrl registration\n");
+		return -EINVAL;
+	}
+
+	/* register pinctrl GPIO ranges */
+	for (i = 0; i < jzpc->num_gpio_chips; i++) {
+		jzgc = &jzpc->gpio_chips[i];
+
+		jzgc->grange.name = jzgc->name;
+		jzgc->grange.id = jzgc->idx;
+		jzgc->grange.pin_base = jzgc->idx * PINS_PER_GPIO_PORT;
+		jzgc->grange.base = jzgc->gc.base;
+		jzgc->grange.npins = jzgc->gc.ngpio;
+		jzgc->grange.gc = &jzgc->gc;
+		pinctrl_add_gpio_range(jzpc->pctl, &jzgc->grange);
+	}
+
+	return 0;
+}
diff --git a/drivers/pinctrl/ingenic/pinctrl-ingenic.h b/drivers/pinctrl/ingenic/pinctrl-ingenic.h
new file mode 100644
index 000000000000..76cb7ffa68e5
--- /dev/null
+++ b/drivers/pinctrl/ingenic/pinctrl-ingenic.h
@@ -0,0 +1,42 @@
+/*
+ * Ingenic SoCs pinctrl driver
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Copyright (c) 2017 Paul Cercueil <paul@crapouillou.net>
+ *
+ * Authors: Paul Burton <paul.burton@imgtec.com>,
+ *          Paul Cercueil <paul@crapouillou.net>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef PINCTRL_INGENIC_H
+#define PINCTRL_INGENIC_H
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+struct platform_device;
+
+struct ingenic_pinctrl_ops {
+	unsigned int nb_functions;
+
+	void (*set_function)(void __iomem *base,
+			unsigned int offset, unsigned int function);
+	void (*set_gpio)(void __iomem *base, unsigned int offset, bool output);
+	int  (*get_bias)(void __iomem *base, unsigned int offset);
+	void (*set_bias)(void __iomem *base, unsigned int offset, bool enable);
+	void (*gpio_set_value)(void __iomem *base,
+			unsigned int offset, int value);
+	int  (*gpio_get_value)(void __iomem *base, unsigned int offset);
+	u32  (*irq_read)(void __iomem *base);
+	void (*irq_mask)(void __iomem *base, unsigned int irq, bool mask);
+	void (*irq_ack)(void __iomem *base, unsigned int irq);
+	void (*irq_set_type)(void __iomem *base,
+			unsigned int irq, unsigned int type);
+};
+
+int ingenic_pinctrl_probe(struct platform_device *pdev,
+		const struct ingenic_pinctrl_ops *ops);
+
+#endif /* PINCTRL_INGENIC_H */
diff --git a/drivers/pinctrl/ingenic/pinctrl-jz4740.c b/drivers/pinctrl/ingenic/pinctrl-jz4740.c
new file mode 100644
index 000000000000..ae0b9d903258
--- /dev/null
+++ b/drivers/pinctrl/ingenic/pinctrl-jz4740.c
@@ -0,0 +1,190 @@
+/*
+ * Ingenic jz4740 pinctrl driver
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Copyright (c) 2017 Paul Cercueil <paul@crapouillou.net>
+ *
+ * Authors: Paul Burton <paul.burton@imgtec.com>,
+ *          Paul Cercueil <paul@crapouillou.net>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include "pinctrl-ingenic.h"
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+/* GPIO port register offsets */
+#define GPIO_PIN	0x00
+#define GPIO_DATA	0x10
+#define GPIO_DATAS	0x14
+#define GPIO_DATAC	0x18
+#define GPIO_MASK	0x20
+#define GPIO_MASKS	0x24
+#define GPIO_MASKC	0x28
+#define GPIO_PULL_DIS	0x30
+#define GPIO_PULL_DISS	0x34
+#define GPIO_PULL_DISC	0x38
+#define GPIO_FUNC	0x40
+#define GPIO_FUNCS	0x44
+#define GPIO_FUNCC	0x48
+#define GPIO_SELECT	0x50
+#define GPIO_SELECTS	0x54
+#define GPIO_SELECTC	0x58
+#define GPIO_DIR	0x60
+#define GPIO_DIRS	0x64
+#define GPIO_DIRC	0x68
+#define GPIO_TRIG	0x70
+#define GPIO_TRIGS	0x74
+#define GPIO_TRIGC	0x78
+#define GPIO_FLAG	0x80
+#define GPIO_FLAGC	0x14
+#define GPIO_REGS_SIZE	0x100
+
+static void jz4740_set_gpio(void __iomem *base,
+		unsigned int offset, bool output)
+{
+	writel(1 << offset, base + GPIO_FUNCC);
+	writel(1 << offset, base + GPIO_SELECTC);
+	writel(1 << offset, base + GPIO_TRIGC);
+
+	if (output)
+		writel(1 << offset, base + GPIO_DIRS);
+	else
+		writel(1 << offset, base + GPIO_DIRC);
+}
+
+static int jz4740_get_bias(void __iomem *base, unsigned int offset)
+{
+	return !((readl(base + GPIO_PULL_DIS) >> offset) & 0x1);
+}
+
+static void jz4740_set_bias(void __iomem *base,
+		unsigned int offset, bool enable)
+{
+	if (enable)
+		writel(1 << offset, base + GPIO_PULL_DISC);
+	else
+		writel(1 << offset, base + GPIO_PULL_DISS);
+}
+
+static void jz4740_gpio_set_value(void __iomem *base,
+		unsigned int offset, int value)
+{
+	if (value)
+		writel(1 << offset, base + GPIO_DATAS);
+	else
+		writel(1 << offset, base + GPIO_DATAC);
+}
+
+static int jz4740_gpio_get_value(void __iomem *base, unsigned int offset)
+{
+	return (readl(base + GPIO_DATA) >> offset) & 0x1;
+}
+
+static u32 jz4740_irq_read(void __iomem *base)
+{
+	return readl(base + GPIO_FLAG);
+}
+
+static void jz4740_irq_mask(void __iomem *base, unsigned int irq, bool mask)
+{
+	if (mask)
+		writel(1 << irq, base + GPIO_MASKS);
+	else
+		writel(1 << irq, base + GPIO_MASKC);
+}
+
+static void jz4740_irq_ack(void __iomem *base, unsigned int irq)
+{
+	writel(1 << irq, base + GPIO_FLAGC);
+}
+
+static void jz4740_irq_set_type(void __iomem *base,
+		unsigned int offset, unsigned int type)
+{
+	switch (type) {
+	case IRQ_TYPE_EDGE_RISING:
+		writel(1 << offset, base + GPIO_DIRS);
+		writel(1 << offset, base + GPIO_TRIGS);
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		writel(1 << offset, base + GPIO_DIRC);
+		writel(1 << offset, base + GPIO_TRIGS);
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		writel(1 << offset, base + GPIO_DIRS);
+		writel(1 << offset, base + GPIO_TRIGC);
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+	default:
+		writel(1 << offset, base + GPIO_DIRC);
+		writel(1 << offset, base + GPIO_TRIGC);
+		break;
+	}
+}
+
+static void jz4740_set_function(void __iomem *base,
+		unsigned int offset, unsigned int func)
+{
+	writel(1 << offset, base + GPIO_FUNCS);
+	writel(1 << offset, base + GPIO_TRIGC);
+
+	switch (func) {
+	case 2:
+		writel(1 << offset, base + GPIO_TRIGS);
+	case 1: /* fallthrough */
+		writel(1 << offset, base + GPIO_SELECTS);
+		break;
+	case 0:
+	default:
+		writel(1 << offset, base + GPIO_SELECTC);
+		break;
+	}
+}
+
+static const struct ingenic_pinctrl_ops jz4740_pinctrl_ops = {
+	.nb_functions	= 3,
+	.set_function	= jz4740_set_function,
+	.set_gpio	= jz4740_set_gpio,
+	.set_bias	= jz4740_set_bias,
+	.get_bias	= jz4740_get_bias,
+	.gpio_set_value	= jz4740_gpio_set_value,
+	.gpio_get_value	= jz4740_gpio_get_value,
+	.irq_read	= jz4740_irq_read,
+	.irq_mask	= jz4740_irq_mask,
+	.irq_ack	= jz4740_irq_ack,
+	.irq_set_type	= jz4740_irq_set_type,
+};
+
+static int jz4740_pinctrl_probe(struct platform_device *pdev)
+{
+	return ingenic_pinctrl_probe(pdev, &jz4740_pinctrl_ops);
+}
+
+static const struct of_device_id jz4740_pinctrl_dt_match[] = {
+	{ .compatible = "ingenic,jz4740-pinctrl", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, jz4740_pinctrl_dt_match);
+
+
+static struct platform_driver jz4740_pinctrl_driver = {
+	.driver = {
+		.name = "jz4740-pinctrl",
+		.of_match_table = of_match_ptr(jz4740_pinctrl_dt_match),
+		.suppress_bind_attrs = true,
+	},
+	.probe = jz4740_pinctrl_probe,
+};
+
+static int __init jz4740_pinctrl_drv_register(void)
+{
+	return platform_driver_register(&jz4740_pinctrl_driver);
+}
+postcore_initcall(jz4740_pinctrl_drv_register);
diff --git a/include/dt-bindings/pinctrl/ingenic.h b/include/dt-bindings/pinctrl/ingenic.h
new file mode 100644
index 000000000000..19eb173844b1
--- /dev/null
+++ b/include/dt-bindings/pinctrl/ingenic.h
@@ -0,0 +1,11 @@
+#ifndef DT_BINDINGS_PINCTRL_INGENIC_H
+#define DT_BINDINGS_PINCTRL_INGENIC_H
+
+#define JZ_PIN_MODE_FUNCTION_0	0
+#define JZ_PIN_MODE_FUNCTION_1	1
+#define JZ_PIN_MODE_FUNCTION_2	2
+#define JZ_PIN_MODE_FUNCTION_3	3
+
+#define JZ_PIN_MODE_GPIO	255
+
+#endif /* DT_BINDINGS_PINCTRL_INGENIC_H */
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH 03/13] pinctrl-jz4780: add a pinctrl driver for the Ingenic jz4780 SoC
  2017-01-17 23:14 [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
  2017-01-17 23:14 ` [PATCH 01/13] Documentation: dt/bindings: Document pinctrl-ingenic Paul Cercueil
  2017-01-17 23:14 ` [PATCH 02/13] pinctrl-jz4740: add a pinctrl driver for the Ingenic jz4740 SoC Paul Cercueil
@ 2017-01-17 23:14 ` Paul Cercueil
  2017-01-17 23:14 ` [PATCH 04/13] MIPS: ingenic: Enable pinctrl for all ingenic SoCs Paul Cercueil
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-17 23:14 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton
  Cc: linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

This driver reuses the core of the driver already present in
pinctrl-ingenic.c, and just supplies callbacks to perform the low-level
operations.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/pinctrl/ingenic/Kconfig          |   6 ++
 drivers/pinctrl/ingenic/Makefile         |   1 +
 drivers/pinctrl/ingenic/pinctrl-jz4780.c | 179 +++++++++++++++++++++++++++++++
 3 files changed, 186 insertions(+)
 create mode 100644 drivers/pinctrl/ingenic/pinctrl-jz4780.c

diff --git a/drivers/pinctrl/ingenic/Kconfig b/drivers/pinctrl/ingenic/Kconfig
index 9923ce127183..15b6514c1948 100644
--- a/drivers/pinctrl/ingenic/Kconfig
+++ b/drivers/pinctrl/ingenic/Kconfig
@@ -12,3 +12,9 @@ config PINCTRL_JZ4740
 	default y
 	depends on MACH_JZ4740 || COMPILE_TEST
 	select PINCTRL_INGENIC
+
+config PINCTRL_JZ4780
+	bool "Pinctrl driver for the Ingenic JZ4780 SoC"
+	default y
+	depends on MACH_JZ4780 || COMPILE_TEST
+	select PINCTRL_INGENIC
diff --git a/drivers/pinctrl/ingenic/Makefile b/drivers/pinctrl/ingenic/Makefile
index 8b2c8b789dc9..ad691f053207 100644
--- a/drivers/pinctrl/ingenic/Makefile
+++ b/drivers/pinctrl/ingenic/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_PINCTRL_INGENIC)	+= pinctrl-ingenic.o
 obj-$(CONFIG_PINCTRL_JZ4740)	+= pinctrl-jz4740.o
+obj-$(CONFIG_PINCTRL_JZ4780)	+= pinctrl-jz4780.o
diff --git a/drivers/pinctrl/ingenic/pinctrl-jz4780.c b/drivers/pinctrl/ingenic/pinctrl-jz4780.c
new file mode 100644
index 000000000000..a191cd1711e7
--- /dev/null
+++ b/drivers/pinctrl/ingenic/pinctrl-jz4780.c
@@ -0,0 +1,179 @@
+/*
+ * Ingenic jz4780 pinctrl driver
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Copyright (c) 2017 Paul Cercueil <paul@crapouillou.net>
+ *
+ * Authors: Paul Burton <paul.burton@imgtec.com>,
+ *          Paul Cercueil <paul@crapouillou.net>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include "pinctrl-ingenic.h"
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+/* GPIO port register offsets */
+#define GPIO_PIN	0x00
+#define GPIO_INT	0x10
+#define GPIO_INTS	0x14
+#define GPIO_INTC	0x18
+#define GPIO_MSK	0x20
+#define GPIO_MSKS	0x24
+#define GPIO_MSKC	0x28
+#define GPIO_PAT1	0x30
+#define GPIO_PAT1S	0x34
+#define GPIO_PAT1C	0x38
+#define GPIO_PAT0	0x40
+#define GPIO_PAT0S	0x44
+#define GPIO_PAT0C	0x48
+#define GPIO_FLG	0x50
+#define GPIO_FLGC	0x58
+#define GPIO_PEN	0x70
+#define GPIO_PENS	0x74
+#define GPIO_PENC	0x78
+
+static void jz4780_set_gpio(void __iomem *base,
+		unsigned int offset, bool output)
+{
+	writel(1 << offset, base + GPIO_INTC);
+	writel(1 << offset, base + GPIO_MSKS);
+
+	if (output)
+		writel(1 << offset, base + GPIO_PAT1C);
+	else
+		writel(1 << offset, base + GPIO_PAT1S);
+}
+
+static int jz4780_get_bias(void __iomem *base, unsigned int offset)
+{
+	return !((readl(base + GPIO_PEN) >> offset) & 0x1);
+}
+
+static void jz4780_set_bias(void __iomem *base,
+		unsigned int offset, bool enable)
+{
+	if (enable)
+		writel(1 << offset, base + GPIO_PENC);
+	else
+		writel(1 << offset, base + GPIO_PENS);
+}
+
+static void jz4780_gpio_set_value(void __iomem *base,
+		unsigned int offset, int value)
+{
+	if (value)
+		writel(1 << offset, base + GPIO_PAT0S);
+	else
+		writel(1 << offset, base + GPIO_PAT0C);
+}
+
+static int jz4780_gpio_get_value(void __iomem *base, unsigned int offset)
+{
+	return (readl(base + GPIO_PIN) >> offset) & 0x1;
+}
+
+static u32 jz4780_irq_read(void __iomem *base)
+{
+	return readl(base + GPIO_FLG);
+}
+
+static void jz4780_irq_mask(void __iomem *base, unsigned int offset, bool mask)
+{
+	if (mask)
+		writel(1 << offset, base + GPIO_MSKS);
+	else
+		writel(1 << offset, base + GPIO_MSKC);
+}
+
+static void jz4780_irq_ack(void __iomem *base, unsigned int offset)
+{
+	writel(1 << offset, base + GPIO_FLGC);
+}
+
+static void jz4780_irq_set_type(void __iomem *base,
+		unsigned int offset, unsigned int type)
+{
+	enum {
+		PAT_EDGE_RISING		= 0x3,
+		PAT_EDGE_FALLING	= 0x2,
+		PAT_LEVEL_HIGH		= 0x1,
+		PAT_LEVEL_LOW		= 0x0,
+	} pat;
+
+	switch (type) {
+	case IRQ_TYPE_EDGE_RISING:
+		pat = PAT_EDGE_RISING;
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		pat = PAT_EDGE_FALLING;
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		pat = PAT_LEVEL_HIGH;
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+	default:
+		pat = PAT_LEVEL_LOW;
+		break;
+	};
+
+	writel(1 << offset, base + ((pat & 0x2) ? GPIO_PAT1S : GPIO_PAT1C));
+	writel(1 << offset, base + ((pat & 0x1) ? GPIO_PAT0S : GPIO_PAT0C));
+	writel(1 << offset, base + GPIO_INTS);
+}
+
+static void jz4780_set_function(void __iomem *base,
+		unsigned int offset, unsigned int func)
+{
+	writel(1 << offset, base + GPIO_INTC);
+	writel(1 << offset, base + GPIO_MSKC);
+	writel(1 << offset, base + ((func & 0x2) ? GPIO_PAT1S : GPIO_PAT1C));
+	writel(1 << offset, base + ((func & 0x1) ? GPIO_PAT0S : GPIO_PAT0C));
+}
+
+static const struct ingenic_pinctrl_ops jz4780_pinctrl_ops = {
+	.nb_functions	= 4,
+	.set_function	= jz4780_set_function,
+	.set_gpio	= jz4780_set_gpio,
+	.set_bias	= jz4780_set_bias,
+	.get_bias	= jz4780_get_bias,
+	.gpio_set_value	= jz4780_gpio_set_value,
+	.gpio_get_value	= jz4780_gpio_get_value,
+	.irq_read	= jz4780_irq_read,
+	.irq_mask	= jz4780_irq_mask,
+	.irq_ack	= jz4780_irq_ack,
+	.irq_set_type	= jz4780_irq_set_type,
+};
+
+static int jz4780_pinctrl_probe(struct platform_device *pdev)
+{
+	return ingenic_pinctrl_probe(pdev, &jz4780_pinctrl_ops);
+}
+
+static const struct of_device_id jz4780_pinctrl_dt_match[] = {
+	{ .compatible = "ingenic,jz4780-pinctrl", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, jz4780_pinctrl_dt_match);
+
+
+static struct platform_driver jz4780_pinctrl_driver = {
+	.driver = {
+		.name = "jz4780-pinctrl",
+		.of_match_table = of_match_ptr(jz4780_pinctrl_dt_match),
+		.suppress_bind_attrs = true,
+	},
+	.probe = jz4780_pinctrl_probe,
+};
+
+static int __init jz4780_pinctrl_drv_register(void)
+{
+	return platform_driver_register(&jz4780_pinctrl_driver);
+}
+postcore_initcall(jz4780_pinctrl_drv_register);
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH 04/13] MIPS: ingenic: Enable pinctrl for all ingenic SoCs
  2017-01-17 23:14 [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                   ` (2 preceding siblings ...)
  2017-01-17 23:14 ` [PATCH 03/13] pinctrl-jz4780: add a pinctrl driver for the Ingenic jz4780 SoC Paul Cercueil
@ 2017-01-17 23:14 ` Paul Cercueil
  2017-01-17 23:14 ` [PATCH 05/13] MIPS: jz4740: DTS: Add node for the jz4740-pinctrl driver Paul Cercueil
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-17 23:14 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton
  Cc: linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

There is a pinctrl driver for each of the Ingenic SoCs supported by the
upstream Linux kernel. In order to switch away from the old GPIO
platform code, we now enable the pinctrl drivers by default for the
Ingenic SoCs.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index b3c5bde43d34..fc720e37661e 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -359,6 +359,7 @@ config MACH_INGENIC
 	select SYS_SUPPORTS_ZBOOT_UART16550
 	select DMA_NONCOHERENT
 	select IRQ_MIPS_CPU
+	select PINCTRL
 	select GPIOLIB
 	select COMMON_CLK
 	select GENERIC_IRQ_CHIP
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH 05/13] MIPS: jz4740: DTS: Add node for the jz4740-pinctrl driver
  2017-01-17 23:14 [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                   ` (3 preceding siblings ...)
  2017-01-17 23:14 ` [PATCH 04/13] MIPS: ingenic: Enable pinctrl for all ingenic SoCs Paul Cercueil
@ 2017-01-17 23:14 ` Paul Cercueil
  2017-01-18 23:50   ` Linus Walleij
  2017-01-17 23:14 ` [PATCH 06/13] MIPS: jz4780: DTS: Add node for the jz4780-pinctrl driver Paul Cercueil
                   ` (9 subsequent siblings)
  14 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-01-17 23:14 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton
  Cc: linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

For a description of the devicetree node, please read
Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/boot/dts/ingenic/jz4740.dtsi | 275 +++++++++++++++++++++++++++++++++
 1 file changed, 275 insertions(+)

diff --git a/arch/mips/boot/dts/ingenic/jz4740.dtsi b/arch/mips/boot/dts/ingenic/jz4740.dtsi
index 3e1587f1f77a..c014a7159a2a 100644
--- a/arch/mips/boot/dts/ingenic/jz4740.dtsi
+++ b/arch/mips/boot/dts/ingenic/jz4740.dtsi
@@ -55,6 +55,281 @@
 		clock-names = "rtc";
 	};
 
+	pinctrl: ingenic-pinctrl@10010000 {
+		compatible = "ingenic,jz4740-pinctrl";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		gpio-chips {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+
+			gpa: gpa {
+				reg = <0x10010000 0x100>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+
+				interrupt-parent = <&intc>;
+				interrupts = <28>;
+
+				ingenic,pull-ups = <0xffffffff>;
+			};
+
+			gpb: gpb {
+				reg = <0x10010100 0x100>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+
+				interrupt-parent = <&intc>;
+				interrupts = <27>;
+
+				ingenic,pull-ups = <0xffffffff>;
+			};
+
+			gpc: gpc {
+				reg = <0x10010200 0x100>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+
+				interrupt-parent = <&intc>;
+				interrupts = <26>;
+
+				ingenic,pull-ups = <0xffffffff>;
+			};
+
+			gpd: gpd {
+				reg = <0x10010300 0x100>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+
+				interrupt-parent = <&intc>;
+				interrupts = <25>;
+
+				ingenic,pull-ups = <0xdfffffff>;
+			};
+		};
+
+		bias-configs {
+			nobias: pincfg-nobias {
+				bias-disable;
+			};
+
+			pull_up: pincfg-pull-up {
+				bias-pull-up;
+			};
+
+			pull_down: pincfg-pull-down {
+				bias-pull-down;
+			};
+		};
+
+		functions {
+			pinfunc-msc {
+				pins_msc_4bit: pins-msc-4bit {
+					ingenic,pins = <&gpd 8 0 &nobias
+							&gpa 9 0 &nobias
+							&gpa 10 0 &nobias
+							&gpa 11 0 &nobias
+							&gpa 12 0 &nobias
+							&gpa 13 0 &nobias>;
+				};
+			};
+
+			pinfunc-uart0 {
+				pins_uart0_data: pins-uart0-data {
+					ingenic,pins = <&gpd 26 1 &pull_up  /* rxd */
+							&gpd 25 1 &nobias>; /* txd */
+				};
+
+				pins_uart0_dataplusflow: uart0-dataplusflow {
+					ingenic,pins = <&gpd 26 1 &pull_up  /* rxd */
+							&gpd 25 1 &nobias   /* txd */
+							&gpd 31 0 &nobias   /* rts */
+							&gpd 30 0 &nobias>; /* cts */
+				};
+			};
+
+			pinfunc-uart1 {
+				pins_uart1_data: uart1-data {
+					ingenic,pins = <&gpd 30 2 &pull_up   /* rxd */
+							&gpd 31 2 &nobias>;  /* txd */
+				};
+			};
+
+			pinfunc-lcd {
+				pins_lcd_8bit: pins-lcd-8bit {
+					ingenic,pins = <&gpc  0 0 &nobias	/* LCD_DATA0 */
+							&gpc  1 0 &nobias
+							&gpc  2 0 &nobias
+							&gpc  3 0 &nobias
+							&gpc  4 0 &nobias
+							&gpc  5 0 &nobias
+							&gpc  6 0 &nobias
+							&gpc  7 0 &nobias	/* LCD_DATA7 */
+							&gpc 18 0 &nobias	/* PCLK */
+							&gpc 19 0 &nobias	/* HSYNC */
+							&gpc 20 0 &nobias>;	/* VSYNC */
+				};
+
+				pins_lcd_16bit: pins-lcd-16bit {
+					ingenic,pins = <&gpc  0 0 &nobias	/* LCD_DATA0 */
+							&gpc  1 0 &nobias
+							&gpc  2 0 &nobias
+							&gpc  3 0 &nobias
+							&gpc  4 0 &nobias
+							&gpc  5 0 &nobias
+							&gpc  6 0 &nobias
+							&gpc  7 0 &nobias
+							&gpc  8 0 &nobias
+							&gpc  9 0 &nobias
+							&gpc 10 0 &nobias
+							&gpc 11 0 &nobias
+							&gpc 12 0 &nobias
+							&gpc 13 0 &nobias
+							&gpc 14 0 &nobias
+							&gpc 15 0 &nobias	/* LCD_DATA15 */
+							&gpc 18 0 &nobias	/* PCLK */
+							&gpc 19 0 &nobias	/* HSYNC */
+							&gpc 20 0 &nobias	/* VSYNC */
+							&gpc 21 0 &nobias>;	/* DE */
+				};
+
+				pins_lcd_18bit: pins-lcd-18bit {
+					ingenic,pins = <&gpc  0 0 &nobias	/* LCD_DATA0 */
+							&gpc  1 0 &nobias
+							&gpc  2 0 &nobias
+							&gpc  3 0 &nobias
+							&gpc  4 0 &nobias
+							&gpc  5 0 &nobias
+							&gpc  6 0 &nobias
+							&gpc  7 0 &nobias
+							&gpc  8 0 &nobias
+							&gpc  9 0 &nobias
+							&gpc 10 0 &nobias
+							&gpc 11 0 &nobias
+							&gpc 12 0 &nobias
+							&gpc 13 0 &nobias
+							&gpc 14 0 &nobias
+							&gpc 15 0 &nobias
+							&gpc 16 0 &nobias
+							&gpc 17 0 &nobias	/* LCD_DATA17 */
+							&gpc 18 0 &nobias	/* PCLK */
+							&gpc 19 0 &nobias	/* HSYNC */
+							&gpc 20 0 &nobias	/* VSYNC */
+							&gpc 21 0 &nobias>;	/* DE */
+				};
+
+				pins_lcd_special_tft: pins-lcd-special-tft {
+					ingenic,pins = <&gpc  0 0 &nobias	/* LCD_DATA0 */
+							&gpc  1 0 &nobias
+							&gpc  2 0 &nobias
+							&gpc  3 0 &nobias
+							&gpc  4 0 &nobias
+							&gpc  5 0 &nobias
+							&gpc  6 0 &nobias
+							&gpc  7 0 &nobias
+							&gpc  8 0 &nobias
+							&gpc  9 0 &nobias
+							&gpc 10 0 &nobias
+							&gpc 11 0 &nobias
+							&gpc 12 0 &nobias
+							&gpc 13 0 &nobias
+							&gpc 14 0 &nobias
+							&gpc 15 0 &nobias
+							&gpc 16 0 &nobias
+							&gpc 17 0 &nobias	/* LCD_DATA17 */
+							&gpc 18 0 &nobias	/* PCLK */
+							&gpc 19 0 &nobias	/* HSYNC */
+							&gpc 20 0 &nobias	/* VSYNC */
+							&gpc 21 0 &nobias	/* DE */
+							&gpc 22 0 &nobias	/* PS */
+							&gpc 23 0 &nobias	/* REV */
+							&gpb 17 0 &nobias	/* CLS */
+							&gpb 18 0 &nobias>;	/* SPL */
+				};
+
+				pinfunc_lcd_nopins: pins-lcd-no-pins {
+					ingenic,pins = <>;
+				};
+			};
+
+			pinfunc-nand {
+				pins_nand: pins-nand {
+					ingenic,pins = <&gpb 25 0 &nobias
+							&gpb 26 0 &nobias
+							&gpb 27 0 &nobias
+							&gpb 28 0 &nobias>;
+				};
+			};
+
+			pinfunc-pwm0 {
+				pins_pwm0: pins-pwm0 {
+					ingenic,pins = <&gpd 23 0 &nobias>;
+				};
+			};
+
+			pinfunc-pwm1 {
+				pins_pwm1: pins-pwm1 {
+					ingenic,pins = <&gpd 24 0 &nobias>;
+				};
+			};
+
+			pinfunc-pwm2 {
+				pins_pwm2: pins-pwm2 {
+					ingenic,pins = <&gpd 25 0 &nobias>;
+				};
+			};
+
+			pinfunc-pwm3 {
+				pins_pwm3: pins-pwm3 {
+					ingenic,pins = <&gpd 26 0 &nobias>;
+				};
+			};
+
+			pinfunc-pwm4 {
+				pins_pwm4: pins-pwm4 {
+					ingenic,pins = <&gpd 27 0 &nobias>;
+				};
+			};
+
+			pinfunc-pwm5 {
+				pins_pwm5: pins-pwm5 {
+					ingenic,pins = <&gpd 28 0 &nobias>;
+				};
+			};
+
+			pinfunc-pwm6 {
+				pins_pwm6: pins-pwm6 {
+					ingenic,pins = <&gpd 30 0 &nobias>;
+				};
+			};
+
+			pinfunc-pwm7 {
+				pins_pwm7: pins-pwm7 {
+					ingenic,pins = <&gpd 31 0 &nobias>;
+				};
+			};
+		};
+	};
+
 	uart0: serial@10030000 {
 		compatible = "ingenic,jz4740-uart";
 		reg = <0x10030000 0x100>;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH 06/13] MIPS: jz4780: DTS: Add node for the jz4780-pinctrl driver
  2017-01-17 23:14 [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                   ` (4 preceding siblings ...)
  2017-01-17 23:14 ` [PATCH 05/13] MIPS: jz4740: DTS: Add node for the jz4740-pinctrl driver Paul Cercueil
@ 2017-01-17 23:14 ` Paul Cercueil
  2017-01-17 23:14 ` [PATCH 07/13] MIPS: JZ4740: Qi LB60: Add pinctrl configuration for several drivers Paul Cercueil
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-17 23:14 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton
  Cc: linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

For a description of the devicetree node, please read
Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/boot/dts/ingenic/jz4780.dtsi | 333 +++++++++++++++++++++++++++++++++
 1 file changed, 333 insertions(+)

diff --git a/arch/mips/boot/dts/ingenic/jz4780.dtsi b/arch/mips/boot/dts/ingenic/jz4780.dtsi
index b868b429add2..0135b2b0c6ad 100644
--- a/arch/mips/boot/dts/ingenic/jz4780.dtsi
+++ b/arch/mips/boot/dts/ingenic/jz4780.dtsi
@@ -44,6 +44,339 @@
 		#clock-cells = <1>;
 	};
 
+	pinctrl: ingenic-pinctrl@10010000 {
+		compatible = "ingenic,jz4780-pinctrl";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		gpio-chips {
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges;
+
+			gpa: gpa {
+				reg = <0x10010000 0x100>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+
+				interrupt-parent = <&intc>;
+				interrupts = <17>;
+
+				ingenic,pull-ups = <0x3fffffff>;
+			};
+
+			gpb: gpb {
+				reg = <0x10010100 0x100>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+
+				interrupt-parent = <&intc>;
+				interrupts = <16>;
+
+				ingenic,pull-downs = <0x000f0c03>;
+				ingenic,pull-ups   = <0xfff0030c>;
+			};
+
+			gpc: gpc {
+				reg = <0x10010200 0x100>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+
+				interrupt-parent = <&intc>;
+				interrupts = <15>;
+
+				ingenic,pull-ups = <0xffffffff>;
+			};
+
+			gpd: gpd {
+				reg = <0x10010300 0x100>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+
+				interrupt-parent = <&intc>;
+				interrupts = <14>;
+
+				ingenic,pull-downs = <0x0000b000>;
+				ingenic,pull-ups   = <0xffff4fff>;
+			};
+
+			gpe: gpe {
+				reg = <0x10010400 0x100>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+
+				interrupt-parent = <&intc>;
+				interrupts = <13>;
+
+				ingenic,pull-downs = <0x00000483>;
+				ingenic,pull-ups   = <0xfffffb7c>;
+			};
+
+			gpf: gpf {
+				reg = <0x10010500 0x100>;
+
+				gpio-controller;
+				#gpio-cells = <2>;
+
+				interrupt-controller;
+				#interrupt-cells = <2>;
+
+				interrupt-parent = <&intc>;
+				interrupts = <12>;
+
+				ingenic,pull-downs = <0x00580ff0>;
+				ingenic,pull-ups   = <0xffa7f00f>;
+			};
+		};
+
+		bias-configs {
+			nobias: nobias {
+				bias-disable;
+			};
+
+			pull_up: pull_up {
+				bias-pull-up;
+			};
+
+			pull_down: pull_down {
+				bias-pull-down;
+			};
+		};
+
+		functions {
+			pinfunc-uart0 {
+				pins_uart0_data: uart0-data {
+					ingenic,pins = <&gpf  0 0 &pull_up  /* rxd */
+							&gpf  3 0 &nobias>; /* txd */
+				};
+
+				pins_uart0_dataplusflow: uart0-dataplusflow {
+					ingenic,pins = <&gpf  0 0 &pull_up  /* rxd */
+							&gpf  1 0 &nobias   /* cts */
+							&gpf  2 0 &nobias   /* rts */
+							&gpf  3 0 &nobias>; /* txd */
+				};
+			};
+
+			pinfunc-uart1 {
+				pins_uart1_data: uart1-data {
+					ingenic,pins = <&gpd  26 0 &pull_up  /* rxd */
+							&gpd  28 0 &nobias>; /* txd */
+				};
+
+				pins_uart1_dataplusflow: uart1-dataplusflow {
+					ingenic,pins = <&gpd  26 0 &pull_up  /* rxd */
+							&gpd  27 0 &nobias   /* cts */
+							&gpd  29 0 &nobias   /* rts */
+							&gpd  28 0 &nobias>; /* txd */
+				};
+			};
+
+			pinfunc-uart2 {
+				pins_uart2_data: uart2-data {
+					ingenic,pins = <&gpd  6 1 &nobias  /* rxd */
+							&gpd  7 1 &nobias>; /* txd */
+				};
+
+				pins_uart2_dataplusflow: uart2-dataplusflow {
+					ingenic,pins = <&gpd  6 1 &nobias  /* rxd */
+							&gpd  5 1 &nobias   /* cts */
+							&gpd  4 1 &nobias   /* rts */
+							&gpd  7 1 &nobias>; /* txd */
+				};
+			};
+
+			pinfunc-uart3 {
+				pins_uart3_data: uart3-data {
+					ingenic,pins = <&gpd 12 0 &pull_down /* rxd */
+							&gpe  5 1 &nobias>;  /* txd */
+				};
+
+				pins_uart3_dataplusflow: uart3-dataplusflow {
+					ingenic,pins = <&gpd 12 0 &pull_down /* rxd */
+							&gpe  5 1 &nobias    /* txd */
+							&gpe  8 0 &nobias    /* cts */
+							&gpe  9 0 &nobias>;  /* rts */
+				};
+			};
+
+			pinfunc-uart4 {
+				pins_uart4_data: uart4-data {
+					ingenic,pins = <&gpc 20 2 &pull_up   /* rxd */
+							&gpc 10 2 &nobias>;  /* txd */
+				};
+			};
+
+			pinfunc-msc0 {
+				pins_msc0_pa: msc0-pa {
+					ingenic,pins = <&gpa  4 1 &nobias   /* d4 */
+							&gpa  5 1 &nobias   /* d5 */
+							&gpa  6 1 &nobias   /* d6 */
+							&gpa  7 1 &nobias   /* d7 */
+							&gpa 18 1 &nobias   /* clk */
+							&gpa 19 1 &nobias   /* cmd */
+							&gpa 20 1 &nobias   /* d0 */
+							&gpa 21 1 &nobias   /* d1 */
+							&gpa 22 1 &nobias   /* d2 */
+							&gpa 23 1 &nobias   /* d3 */
+							&gpa 24 1 &nobias>; /* rst */
+				};
+
+				pins_msc0_pe: msc0-pe {
+					ingenic,pins = <&gpe 20 0 &nobias   /* d0 */
+							&gpe 21 0 &nobias   /* d1 */
+							&gpe 22 0 &nobias   /* d2 */
+							&gpe 23 0 &nobias   /* d3 */
+							&gpe 28 0 &nobias   /* clk */
+							&gpe 29 0 &nobias>; /* cmd */
+				};
+			};
+
+			pinfunc-msc1 {
+				pins_msc1_pd: msc1-pd {
+					ingenic,pins = <&gpd 20 0 &nobias   /* d0 */
+							&gpd 21 0 &nobias   /* d1 */
+							&gpd 22 0 &nobias   /* d2 */
+							&gpd 23 0 &nobias   /* d3 */
+							&gpd 24 0 &nobias   /* clk */
+							&gpd 25 0 &nobias>; /* cmd */
+				};
+
+				pins_msc1_pe: msc1-pe {
+					ingenic,pins = <&gpe 20 1 &nobias   /* d0 */
+							&gpe 21 1 &nobias   /* d1 */
+							&gpe 22 1 &nobias   /* d2 */
+							&gpe 23 1 &nobias   /* d3 */
+							&gpe 28 1 &nobias   /* clk */
+							&gpe 29 1 &nobias>; /* cmd */
+				};
+			};
+
+			pinfunc-nemc {
+				pins_nemc_data: nemc-data {
+					ingenic,pins = <&gpa 0 0 &nobias    /* sd0 */
+							&gpa 1 0 &nobias    /* sd1 */
+							&gpa 2 0 &nobias    /* sd2 */
+							&gpa 3 0 &nobias    /* sd3 */
+							&gpa 4 0 &nobias    /* sd4 */
+							&gpa 5 0 &nobias    /* sd5 */
+							&gpa 6 0 &nobias    /* sd6 */
+							&gpa 7 0 &nobias>;  /* sd7 */
+				};
+
+				pins_nemc_cle_ale: nemc-cle-ale {
+					ingenic,pins = <&gpb 0 0 &nobias    /* sa0_cl */
+							&gpb 1 0 &nobias>;  /* sa1_al */
+				};
+
+				pins_nemc_addr: nemc-addr {
+					ingenic,pins = <&gpb 0 0 &nobias    /* sa0_cl */
+							&gpb 1 0 &nobias    /* sa1_al */
+							&gpb 2 0 &nobias    /* sa2 */
+							&gpb 3 0 &nobias    /* sa3 */
+							&gpb 4 0 &nobias    /* sa4 */
+							&gpb 5 0 &nobias>;  /* sa5 */
+				};
+
+				pins_nemc_rd_we: nemc-rd-we {
+					ingenic,pins = <&gpa 16 0 &nobias   /* rd */
+							&gpa 17 0 &nobias>; /* we */
+				};
+
+				pins_nemc_frd_fwe: nemc-frd-fwe {
+					ingenic,pins = <&gpa 18 0 &nobias   /* rd */
+							&gpa 19 0 &nobias>; /* we */
+				};
+
+				pins_nemc_cs1: nemc-cs1 {
+					ingenic,pins = <&gpa 21 0 &nobias>; /* cs1 */
+				};
+
+				pins_nemc_cs6: nemc-cs6 {
+					ingenic,pins = <&gpa 26 0 &nobias>; /* cs6 */
+				};
+			};
+
+			pinfunc-i2c0 {
+				pins_i2c0_data: i2c0-data{
+					ingenic,pins = <&gpd  30 0 &nobias  /* sda */
+							&gpd  31 0 &nobias>; /* sck */
+				};
+			};
+
+			pinfunc-i2c1 {
+				pins_i2c1_data: i2c1-data{
+					ingenic,pins = <&gpe  30 0 &nobias  /* sda */
+							&gpe  31 0 &nobias>; /* sck */
+				};
+			};
+
+			pinfunc-i2c2 {
+				pins_i2c2_data: i2c2-data{
+					ingenic,pins = <&gpf  16 2 &nobias  /* sda */
+							&gpf  17 2 &nobias>; /* sck */
+				};
+			};
+
+			pinfunc-i2c3 {
+				pins_i2c3_data: i2c3-data{
+					ingenic,pins = <&gpd  10 1 &nobias  /* sda */
+							&gpd  11 1 &nobias>; /* sck */
+				};
+			};
+
+			pinfunc-i2c4 {
+				pins_i2c4_data: i2c4-data-pe{
+					ingenic,pins = <&gpe  12 1 &nobias  /* sda */
+							&gpe  13 1 &nobias>; /* sck */
+				};
+
+				pins_i2c4_data_pf: i2c4-data-pf{
+					ingenic,pins = <&gpf 25 1 &nobias /* hdmi_sda */
+							&gpf 24 1 &nobias>; /* hdmi_sck */
+				};
+			};
+
+			pinfunc-cim {
+				pins_cim: cim-pb {
+					ingenic,pins = <&gpb   6 0 &nobias
+							&gpb   7 0 &nobias
+							&gpb   8 0 &nobias
+							&gpb   9 0 &nobias
+							&gpb  10 0 &nobias
+							&gpb  11 0 &nobias
+							&gpb  12 0 &nobias
+							&gpb  13 0 &nobias
+							&gpb  14 0 &nobias
+							&gpb  15 0 &nobias
+							&gpb  16 0 &nobias
+							&gpb  17 0 &nobias>;
+				};
+			};
+		};
+	};
+
 	uart0: serial@10030000 {
 		compatible = "ingenic,jz4780-uart";
 		reg = <0x10030000 0x100>;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH 07/13] MIPS: JZ4740: Qi LB60: Add pinctrl configuration for several drivers
  2017-01-17 23:14 [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                   ` (5 preceding siblings ...)
  2017-01-17 23:14 ` [PATCH 06/13] MIPS: jz4780: DTS: Add node for the jz4780-pinctrl driver Paul Cercueil
@ 2017-01-17 23:14 ` Paul Cercueil
  2017-01-17 23:14 ` [PATCH 08/13] MIPS: JZ4780: CI20: " Paul Cercueil
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-17 23:14 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton
  Cc: linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

We set the pin configuration for the jz4740-nand, jz4740-mmc,
jz4740-fb, jz4740-pwm and jz4740-uart drivers.

This will permit those drivers to be cleaned out of the custom GPIO code
that they currently use.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/boot/dts/ingenic/qi_lb60.dts |  5 ++++
 arch/mips/jz4740/board-qi_lb60.c       | 47 +++++++++++++++++++++++++++-------
 2 files changed, 43 insertions(+), 9 deletions(-)

diff --git a/arch/mips/boot/dts/ingenic/qi_lb60.dts b/arch/mips/boot/dts/ingenic/qi_lb60.dts
index be1a7d3a3e1b..7b98c4f57b1c 100644
--- a/arch/mips/boot/dts/ingenic/qi_lb60.dts
+++ b/arch/mips/boot/dts/ingenic/qi_lb60.dts
@@ -17,3 +17,8 @@
 &rtc_dev {
 	system-power-controller;
 };
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart0_data>;
+};
diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c
index a5bd94b95263..c6ee50a44cb3 100644
--- a/arch/mips/jz4740/board-qi_lb60.c
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -22,6 +22,8 @@
 #include <linux/input/matrix_keypad.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_gpio.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf-generic.h>
 #include <linux/power_supply.h>
 #include <linux/power/jz4740-battery.h>
 #include <linux/power/gpio-charger.h>
@@ -447,13 +449,41 @@ static struct platform_device *jz_platform_devices[] __initdata = {
 	&qi_lb60_audio_device,
 };
 
-static void __init board_gpio_setup(void)
-{
-	/* We only need to enable/disable pullup here for pins used in generic
-	 * drivers. Everything else is done by the drivers themselves. */
-	jz_gpio_disable_pullup(QI_LB60_GPIO_SD_VCC_EN_N);
-	jz_gpio_disable_pullup(QI_LB60_GPIO_SD_CD);
-}
+static unsigned long pin_cfg_bias_disable[] = {
+	    PIN_CONFIG_BIAS_DISABLE,
+};
+
+static struct pinctrl_map pin_map[] __initdata = {
+	/* NAND pin configuration */
+	PIN_MAP_MUX_GROUP_DEFAULT("jz4740-nand",
+			"10010000.jz4740-pinctrl",
+			"pinfunc-nand", "pins-nand"),
+
+	/* fbdev pin configuration */
+	PIN_MAP_MUX_GROUP("jz4740-fb", PINCTRL_STATE_DEFAULT,
+			"10010000.jz4740-pinctrl",
+			"pinfunc-lcd", "pins-lcd-8bit"),
+	PIN_MAP_MUX_GROUP("jz4740-fb", PINCTRL_STATE_SLEEP,
+			"10010000.jz4740-pinctrl",
+			"pinfunc-lcd", "pins-lcd-no-pins"),
+
+	/* MMC pin configuration */
+	PIN_MAP_MUX_GROUP_DEFAULT("jz4740-mmc.0",
+			"10010000.jz4740-pinctrl",
+			"pinfunc-msc", "pins-msc-4bit"),
+	PIN_MAP_CONFIGS_PIN_DEFAULT("jz4740-mmc.0",
+			"10010000.jz4740-pinctrl",
+			"PD0", pin_cfg_bias_disable),
+	PIN_MAP_CONFIGS_PIN_DEFAULT("jz4740-mmc.0",
+			"10010000.jz4740-pinctrl",
+			"PD2", pin_cfg_bias_disable),
+
+	/* PWM pin configuration */
+	PIN_MAP_MUX_GROUP_DEFAULT("jz4740-pwm",
+			"10010000.jz4740-pinctrl",
+			"pinfunc-pwm4", "pins-pwm4"),
+};
+
 
 static int __init qi_lb60_init_platform_devices(void)
 {
@@ -469,6 +499,7 @@ static int __init qi_lb60_init_platform_devices(void)
 				ARRAY_SIZE(qi_lb60_spi_board_info));
 
 	pwm_add_table(qi_lb60_pwm_lookup, ARRAY_SIZE(qi_lb60_pwm_lookup));
+	pinctrl_register_mappings(pin_map, ARRAY_SIZE(pin_map));
 
 	return platform_add_devices(jz_platform_devices,
 					ARRAY_SIZE(jz_platform_devices));
@@ -479,8 +510,6 @@ static int __init qi_lb60_board_setup(void)
 {
 	printk(KERN_INFO "Qi Hardware JZ4740 QI LB60 setup\n");
 
-	board_gpio_setup();
-
 	if (qi_lb60_init_platform_devices())
 		panic("Failed to initialize platform devices");
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH 08/13] MIPS: JZ4780: CI20: Add pinctrl configuration for several drivers
  2017-01-17 23:14 [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                   ` (6 preceding siblings ...)
  2017-01-17 23:14 ` [PATCH 07/13] MIPS: JZ4740: Qi LB60: Add pinctrl configuration for several drivers Paul Cercueil
@ 2017-01-17 23:14 ` Paul Cercueil
  2017-01-17 23:14 ` [PATCH 09/13] mmc: jz4740: Let the pinctrl driver configure the pins Paul Cercueil
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-17 23:14 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton
  Cc: linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

We set the pin configuration for the jz4780-nand and jz4780-uart
drivers.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/boot/dts/ingenic/ci20.dts | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/arch/mips/boot/dts/ingenic/ci20.dts b/arch/mips/boot/dts/ingenic/ci20.dts
index 1652d8d60b1e..e2cd3ebb7be8 100644
--- a/arch/mips/boot/dts/ingenic/ci20.dts
+++ b/arch/mips/boot/dts/ingenic/ci20.dts
@@ -29,18 +29,30 @@
 
 &uart0 {
 	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart0_data>;
 };
 
 &uart1 {
 	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart1_data>;
 };
 
 &uart3 {
 	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart2_dataplusflow>;
 };
 
 &uart4 {
 	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart4_data>;
 };
 
 &nemc {
@@ -61,6 +73,16 @@
 		ingenic,nemc-tAW = <15>;
 		ingenic,nemc-tSTRV = <100>;
 
+		/*
+		 * Only CLE/ALE are needed for the devices that are connected, rather
+		 * than the full address line set.
+		 */
+		pinctrl-names = "default";
+		pinctrl-0 = <&pins_nemc_data
+				 &pins_nemc_cle_ale
+				 &pins_nemc_rd_we
+				 &pins_nemc_frd_fwe>;
+
 		nand@1 {
 			reg = <1>;
 
@@ -69,6 +91,9 @@
 			nand-ecc-mode = "hw";
 			nand-on-flash-bbt;
 
+			pinctrl-names = "default";
+			pinctrl-0 = <&pins_nemc_cs1>;
+
 			partitions {
 				compatible = "fixed-partitions";
 				#address-cells = <2>;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH 09/13] mmc: jz4740: Let the pinctrl driver configure the pins
  2017-01-17 23:14 [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                   ` (7 preceding siblings ...)
  2017-01-17 23:14 ` [PATCH 08/13] MIPS: JZ4780: CI20: " Paul Cercueil
@ 2017-01-17 23:14 ` Paul Cercueil
  2017-01-19 10:55   ` Ulf Hansson
  2017-01-17 23:14 ` [PATCH 10/13] mtd: nand: " Paul Cercueil
                   ` (5 subsequent siblings)
  14 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-01-17 23:14 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton
  Cc: linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
the pins being properly configured before the driver probes.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/mmc/host/jz4740_mmc.c | 59 ++-----------------------------------------
 1 file changed, 2 insertions(+), 57 deletions(-)

diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c
index 819ad32964fc..28a8e0acd70a 100644
--- a/drivers/mmc/host/jz4740_mmc.c
+++ b/drivers/mmc/host/jz4740_mmc.c
@@ -27,7 +27,6 @@
 
 #include <linux/bitops.h>
 #include <linux/gpio.h>
-#include <asm/mach-jz4740/gpio.h>
 #include <asm/cacheflush.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
@@ -906,15 +905,6 @@ static const struct mmc_host_ops jz4740_mmc_ops = {
 	.enable_sdio_irq = jz4740_mmc_enable_sdio_irq,
 };
 
-static const struct jz_gpio_bulk_request jz4740_mmc_pins[] = {
-	JZ_GPIO_BULK_PIN(MSC_CMD),
-	JZ_GPIO_BULK_PIN(MSC_CLK),
-	JZ_GPIO_BULK_PIN(MSC_DATA0),
-	JZ_GPIO_BULK_PIN(MSC_DATA1),
-	JZ_GPIO_BULK_PIN(MSC_DATA2),
-	JZ_GPIO_BULK_PIN(MSC_DATA3),
-};
-
 static int jz4740_mmc_request_gpio(struct device *dev, int gpio,
 	const char *name, bool output, int value)
 {
@@ -978,15 +968,6 @@ static void jz4740_mmc_free_gpios(struct platform_device *pdev)
 		gpio_free(pdata->gpio_power);
 }
 
-static inline size_t jz4740_mmc_num_pins(struct jz4740_mmc_host *host)
-{
-	size_t num_pins = ARRAY_SIZE(jz4740_mmc_pins);
-	if (host->pdata && host->pdata->data_1bit)
-		num_pins -= 3;
-
-	return num_pins;
-}
-
 static int jz4740_mmc_probe(struct platform_device* pdev)
 {
 	int ret;
@@ -1027,15 +1008,9 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
 		goto err_free_host;
 	}
 
-	ret = jz_gpio_bulk_request(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
-	if (ret) {
-		dev_err(&pdev->dev, "Failed to request mmc pins: %d\n", ret);
-		goto err_free_host;
-	}
-
 	ret = jz4740_mmc_request_gpios(mmc, pdev);
 	if (ret)
-		goto err_gpio_bulk_free;
+		goto err_release_dma;
 
 	mmc->ops = &jz4740_mmc_ops;
 	mmc->f_min = JZ_MMC_CLK_RATE / 128;
@@ -1091,10 +1066,9 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
 	free_irq(host->irq, host);
 err_free_gpios:
 	jz4740_mmc_free_gpios(pdev);
-err_gpio_bulk_free:
+err_release_dma:
 	if (host->use_dma)
 		jz4740_mmc_release_dma_channels(host);
-	jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
 err_free_host:
 	mmc_free_host(mmc);
 
@@ -1114,7 +1088,6 @@ static int jz4740_mmc_remove(struct platform_device *pdev)
 	free_irq(host->irq, host);
 
 	jz4740_mmc_free_gpios(pdev);
-	jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
 
 	if (host->use_dma)
 		jz4740_mmc_release_dma_channels(host);
@@ -1124,39 +1097,11 @@ static int jz4740_mmc_remove(struct platform_device *pdev)
 	return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-
-static int jz4740_mmc_suspend(struct device *dev)
-{
-	struct jz4740_mmc_host *host = dev_get_drvdata(dev);
-
-	jz_gpio_bulk_suspend(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
-
-	return 0;
-}
-
-static int jz4740_mmc_resume(struct device *dev)
-{
-	struct jz4740_mmc_host *host = dev_get_drvdata(dev);
-
-	jz_gpio_bulk_resume(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
-
-	return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend,
-	jz4740_mmc_resume);
-#define JZ4740_MMC_PM_OPS (&jz4740_mmc_pm_ops)
-#else
-#define JZ4740_MMC_PM_OPS NULL
-#endif
-
 static struct platform_driver jz4740_mmc_driver = {
 	.probe = jz4740_mmc_probe,
 	.remove = jz4740_mmc_remove,
 	.driver = {
 		.name = "jz4740-mmc",
-		.pm = JZ4740_MMC_PM_OPS,
 	},
 };
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH 10/13] mtd: nand: jz4740: Let the pinctrl driver configure the pins
  2017-01-17 23:14 [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                   ` (8 preceding siblings ...)
  2017-01-17 23:14 ` [PATCH 09/13] mmc: jz4740: Let the pinctrl driver configure the pins Paul Cercueil
@ 2017-01-17 23:14 ` Paul Cercueil
  2017-01-27 17:33   ` Boris Brezillon
  2017-01-17 23:14 ` [PATCH 11/13] fbdev: jz4740-fb: " Paul Cercueil
                   ` (4 subsequent siblings)
  14 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-01-17 23:14 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton
  Cc: linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

Before, this NAND driver would set itself the configuration of the
chip-select pins for the various NAND banks.

Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
the pins being properly configured before the driver probes.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/mtd/nand/jz4740_nand.c | 23 +----------------------
 1 file changed, 1 insertion(+), 22 deletions(-)

diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
index 5551c36adbdf..0d06a1f07d82 100644
--- a/drivers/mtd/nand/jz4740_nand.c
+++ b/drivers/mtd/nand/jz4740_nand.c
@@ -25,7 +25,6 @@
 
 #include <linux/gpio.h>
 
-#include <asm/mach-jz4740/gpio.h>
 #include <asm/mach-jz4740/jz4740_nand.h>
 
 #define JZ_REG_NAND_CTRL	0x50
@@ -310,34 +309,20 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
 			       uint8_t *nand_dev_id)
 {
 	int ret;
-	int gpio;
-	char gpio_name[9];
 	char res_name[6];
 	uint32_t ctrl;
 	struct nand_chip *chip = &nand->chip;
 	struct mtd_info *mtd = nand_to_mtd(chip);
 
-	/* Request GPIO port. */
-	gpio = JZ_GPIO_MEM_CS0 + bank - 1;
-	sprintf(gpio_name, "NAND CS%d", bank);
-	ret = gpio_request(gpio, gpio_name);
-	if (ret) {
-		dev_warn(&pdev->dev,
-			"Failed to request %s gpio %d: %d\n",
-			gpio_name, gpio, ret);
-		goto notfound_gpio;
-	}
-
 	/* Request I/O resource. */
 	sprintf(res_name, "bank%d", bank);
 	ret = jz_nand_ioremap_resource(pdev, res_name,
 					&nand->bank_mem[bank - 1],
 					&nand->bank_base[bank - 1]);
 	if (ret)
-		goto notfound_resource;
+		return ret;
 
 	/* Enable chip in bank. */
-	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_MEM_CS0);
 	ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
 	ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1);
 	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
@@ -377,12 +362,8 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
 	dev_info(&pdev->dev, "No chip found on bank %i\n", bank);
 	ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1));
 	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
-	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE);
 	jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
 				 nand->bank_base[bank - 1]);
-notfound_resource:
-	gpio_free(gpio);
-notfound_gpio:
 	return ret;
 }
 
@@ -503,7 +484,6 @@ static int jz_nand_probe(struct platform_device *pdev)
 err_unclaim_banks:
 	while (chipnr--) {
 		unsigned char bank = nand->banks[chipnr];
-		gpio_free(JZ_GPIO_MEM_CS0 + bank - 1);
 		jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
 					 nand->bank_base[bank - 1]);
 	}
@@ -530,7 +510,6 @@ static int jz_nand_remove(struct platform_device *pdev)
 		if (bank != 0) {
 			jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
 						 nand->bank_base[bank - 1]);
-			gpio_free(JZ_GPIO_MEM_CS0 + bank - 1);
 		}
 	}
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH 11/13] fbdev: jz4740-fb: Let the pinctrl driver configure the pins
  2017-01-17 23:14 [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                   ` (9 preceding siblings ...)
  2017-01-17 23:14 ` [PATCH 10/13] mtd: nand: " Paul Cercueil
@ 2017-01-17 23:14 ` Paul Cercueil
  2017-01-17 23:14 ` [PATCH 12/13] pwm: jz4740: " Paul Cercueil
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-17 23:14 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton
  Cc: linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
the pins being properly configured before the driver probes.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/video/fbdev/jz4740_fb.c | 104 ++--------------------------------------
 1 file changed, 3 insertions(+), 101 deletions(-)

diff --git a/drivers/video/fbdev/jz4740_fb.c b/drivers/video/fbdev/jz4740_fb.c
index 87790e9644d0..b57df83fdbd3 100644
--- a/drivers/video/fbdev/jz4740_fb.c
+++ b/drivers/video/fbdev/jz4740_fb.c
@@ -17,6 +17,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
 
 #include <linux/clk.h>
 #include <linux/delay.h>
@@ -27,7 +28,6 @@
 #include <linux/dma-mapping.h>
 
 #include <asm/mach-jz4740/jz4740_fb.h>
-#include <asm/mach-jz4740/gpio.h>
 
 #define JZ_REG_LCD_CFG		0x00
 #define JZ_REG_LCD_VSYNC	0x04
@@ -146,93 +146,6 @@ static const struct fb_fix_screeninfo jzfb_fix = {
 	.accel		= FB_ACCEL_NONE,
 };
 
-static const struct jz_gpio_bulk_request jz_lcd_ctrl_pins[] = {
-	JZ_GPIO_BULK_PIN(LCD_PCLK),
-	JZ_GPIO_BULK_PIN(LCD_HSYNC),
-	JZ_GPIO_BULK_PIN(LCD_VSYNC),
-	JZ_GPIO_BULK_PIN(LCD_DE),
-	JZ_GPIO_BULK_PIN(LCD_PS),
-	JZ_GPIO_BULK_PIN(LCD_REV),
-	JZ_GPIO_BULK_PIN(LCD_CLS),
-	JZ_GPIO_BULK_PIN(LCD_SPL),
-};
-
-static const struct jz_gpio_bulk_request jz_lcd_data_pins[] = {
-	JZ_GPIO_BULK_PIN(LCD_DATA0),
-	JZ_GPIO_BULK_PIN(LCD_DATA1),
-	JZ_GPIO_BULK_PIN(LCD_DATA2),
-	JZ_GPIO_BULK_PIN(LCD_DATA3),
-	JZ_GPIO_BULK_PIN(LCD_DATA4),
-	JZ_GPIO_BULK_PIN(LCD_DATA5),
-	JZ_GPIO_BULK_PIN(LCD_DATA6),
-	JZ_GPIO_BULK_PIN(LCD_DATA7),
-	JZ_GPIO_BULK_PIN(LCD_DATA8),
-	JZ_GPIO_BULK_PIN(LCD_DATA9),
-	JZ_GPIO_BULK_PIN(LCD_DATA10),
-	JZ_GPIO_BULK_PIN(LCD_DATA11),
-	JZ_GPIO_BULK_PIN(LCD_DATA12),
-	JZ_GPIO_BULK_PIN(LCD_DATA13),
-	JZ_GPIO_BULK_PIN(LCD_DATA14),
-	JZ_GPIO_BULK_PIN(LCD_DATA15),
-	JZ_GPIO_BULK_PIN(LCD_DATA16),
-	JZ_GPIO_BULK_PIN(LCD_DATA17),
-};
-
-static unsigned int jzfb_num_ctrl_pins(struct jzfb *jzfb)
-{
-	unsigned int num;
-
-	switch (jzfb->pdata->lcd_type) {
-	case JZ_LCD_TYPE_GENERIC_16_BIT:
-		num = 4;
-		break;
-	case JZ_LCD_TYPE_GENERIC_18_BIT:
-		num = 4;
-		break;
-	case JZ_LCD_TYPE_8BIT_SERIAL:
-		num = 3;
-		break;
-	case JZ_LCD_TYPE_SPECIAL_TFT_1:
-	case JZ_LCD_TYPE_SPECIAL_TFT_2:
-	case JZ_LCD_TYPE_SPECIAL_TFT_3:
-		num = 8;
-		break;
-	default:
-		num = 0;
-		break;
-	}
-	return num;
-}
-
-static unsigned int jzfb_num_data_pins(struct jzfb *jzfb)
-{
-	unsigned int num;
-
-	switch (jzfb->pdata->lcd_type) {
-	case JZ_LCD_TYPE_GENERIC_16_BIT:
-		num = 16;
-		break;
-	case JZ_LCD_TYPE_GENERIC_18_BIT:
-		num = 18;
-		break;
-	case JZ_LCD_TYPE_8BIT_SERIAL:
-		num = 8;
-		break;
-	case JZ_LCD_TYPE_SPECIAL_TFT_1:
-	case JZ_LCD_TYPE_SPECIAL_TFT_2:
-	case JZ_LCD_TYPE_SPECIAL_TFT_3:
-		if (jzfb->pdata->bpp == 18)
-			num = 18;
-		else
-			num = 16;
-		break;
-	default:
-		num = 0;
-		break;
-	}
-	return num;
-}
-
 /* Based on CNVT_TOHW macro from skeletonfb.c */
 static inline uint32_t jzfb_convert_color_to_hw(unsigned val,
 	struct fb_bitfield *bf)
@@ -487,8 +400,7 @@ static void jzfb_enable(struct jzfb *jzfb)
 
 	clk_prepare_enable(jzfb->ldclk);
 
-	jz_gpio_bulk_resume(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_resume(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
+	pinctrl_pm_select_default_state(&jzfb->pdev->dev);
 
 	writel(0, jzfb->base + JZ_REG_LCD_STATE);
 
@@ -511,8 +423,7 @@ static void jzfb_disable(struct jzfb *jzfb)
 		ctrl = readl(jzfb->base + JZ_REG_LCD_STATE);
 	} while (!(ctrl & JZ_LCD_STATE_DISABLED));
 
-	jz_gpio_bulk_suspend(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_suspend(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
+	pinctrl_pm_select_sleep_state(&jzfb->pdev->dev);
 
 	clk_disable_unprepare(jzfb->ldclk);
 }
@@ -701,9 +612,6 @@ static int jzfb_probe(struct platform_device *pdev)
 	fb->mode = NULL;
 	jzfb_set_par(fb);
 
-	jz_gpio_bulk_request(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_request(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
-
 	ret = register_framebuffer(fb);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to register framebuffer: %d\n", ret);
@@ -715,9 +623,6 @@ static int jzfb_probe(struct platform_device *pdev)
 	return 0;
 
 err_free_devmem:
-	jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
-
 	fb_dealloc_cmap(&fb->cmap);
 	jzfb_free_devmem(jzfb);
 err_framebuffer_release:
@@ -731,9 +636,6 @@ static int jzfb_remove(struct platform_device *pdev)
 
 	jzfb_blank(FB_BLANK_POWERDOWN, jzfb->fb);
 
-	jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
-
 	fb_dealloc_cmap(&jzfb->fb->cmap);
 	jzfb_free_devmem(jzfb);
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH 12/13] pwm: jz4740: Let the pinctrl driver configure the pins
  2017-01-17 23:14 [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                   ` (10 preceding siblings ...)
  2017-01-17 23:14 ` [PATCH 11/13] fbdev: jz4740-fb: " Paul Cercueil
@ 2017-01-17 23:14 ` Paul Cercueil
  2017-01-18  7:20   ` Thierry Reding
  2017-01-17 23:14 ` [PATCH 13/13] MIPS: jz4740: Remove custom GPIO code Paul Cercueil
                   ` (2 subsequent siblings)
  14 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-01-17 23:14 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton
  Cc: linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
the pins being properly configured before the driver probes.

One inherent problem of this new approach is that the pinctrl framework
does not allow us to configure each pin on demand, when the various PWM
channels are requested or released. For instance, the PWM channels can
be configured from sysfs, which would require all PWM pins to be configured
properly beforehand for the PWM function, eventually causing conflicts
with other platform or board drivers.

The proper solution here would be to modify the pwm-jz4740 driver to
handle only one PWM channel, and create an instance of this driver
for each one of the 8 PWM channels. Then, it could use the pinctrl
framework to dynamically configure the PWM pin it controls.

Until this can be done, the only jz4740 board supported upstream
(Qi lb60) could configure all of its connected PWM pins in PWM function
mode, if those are not used by other drivers nor by GPIOs on the
board.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/pwm/pwm-jz4740.c | 29 -----------------------------
 1 file changed, 29 deletions(-)

diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c
index 76d13150283f..a75ff3622450 100644
--- a/drivers/pwm/pwm-jz4740.c
+++ b/drivers/pwm/pwm-jz4740.c
@@ -21,22 +21,10 @@
 #include <linux/platform_device.h>
 #include <linux/pwm.h>
 
-#include <asm/mach-jz4740/gpio.h>
 #include <asm/mach-jz4740/timer.h>
 
 #define NUM_PWM 8
 
-static const unsigned int jz4740_pwm_gpio_list[NUM_PWM] = {
-	JZ_GPIO_PWM0,
-	JZ_GPIO_PWM1,
-	JZ_GPIO_PWM2,
-	JZ_GPIO_PWM3,
-	JZ_GPIO_PWM4,
-	JZ_GPIO_PWM5,
-	JZ_GPIO_PWM6,
-	JZ_GPIO_PWM7,
-};
-
 struct jz4740_pwm_chip {
 	struct pwm_chip chip;
 	struct clk *clk;
@@ -49,9 +37,6 @@ static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip)
 
 static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-	unsigned int gpio = jz4740_pwm_gpio_list[pwm->hwpwm];
-	int ret;
-
 	/*
 	 * Timers 0 and 1 are used for system tasks, so they are unavailable
 	 * for use as PWMs.
@@ -59,15 +44,6 @@ static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 	if (pwm->hwpwm < 2)
 		return -EBUSY;
 
-	ret = gpio_request(gpio, pwm->label);
-	if (ret) {
-		dev_err(chip->dev, "Failed to request GPIO#%u for PWM: %d\n",
-			gpio, ret);
-		return ret;
-	}
-
-	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_PWM);
-
 	jz4740_timer_start(pwm->hwpwm);
 
 	return 0;
@@ -75,13 +51,8 @@ static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 
 static void jz4740_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-	unsigned int gpio = jz4740_pwm_gpio_list[pwm->hwpwm];
-
 	jz4740_timer_set_ctrl(pwm->hwpwm, 0);
 
-	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE);
-	gpio_free(gpio);
-
 	jz4740_timer_stop(pwm->hwpwm);
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH 13/13] MIPS: jz4740: Remove custom GPIO code
  2017-01-17 23:14 [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                   ` (11 preceding siblings ...)
  2017-01-17 23:14 ` [PATCH 12/13] pwm: jz4740: " Paul Cercueil
@ 2017-01-17 23:14 ` Paul Cercueil
  2017-01-18  7:27   ` Thierry Reding
  2017-01-19  9:07   ` Linus Walleij
  2017-01-18  7:15 ` [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver Thierry Reding
  2017-01-19  6:38 ` [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver Linus Walleij
  14 siblings, 2 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-17 23:14 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton
  Cc: linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

All the drivers for the various hardware elements of the jz4740 SoC have
been modified to use the pinctrl framework for their pin configuration
needs.
As such, this platform code is now unused and can be deleted.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/include/asm/mach-jz4740/gpio.h | 371 ----------------------
 arch/mips/jz4740/Makefile                |   2 -
 arch/mips/jz4740/gpio.c                  | 519 -------------------------------
 3 files changed, 892 deletions(-)
 delete mode 100644 arch/mips/jz4740/gpio.c

diff --git a/arch/mips/include/asm/mach-jz4740/gpio.h b/arch/mips/include/asm/mach-jz4740/gpio.h
index 7c7708a23baa..fd847c984701 100644
--- a/arch/mips/include/asm/mach-jz4740/gpio.h
+++ b/arch/mips/include/asm/mach-jz4740/gpio.h
@@ -16,380 +16,9 @@
 #ifndef _JZ_GPIO_H
 #define _JZ_GPIO_H
 
-#include <linux/types.h>
-
-enum jz_gpio_function {
-    JZ_GPIO_FUNC_NONE,
-    JZ_GPIO_FUNC1,
-    JZ_GPIO_FUNC2,
-    JZ_GPIO_FUNC3,
-};
-
-/*
- Usually a driver for a SoC component has to request several gpio pins and
- configure them as function pins.
- jz_gpio_bulk_request can be used to ease this process.
- Usually one would do something like:
-
- static const struct jz_gpio_bulk_request i2c_pins[] = {
-	JZ_GPIO_BULK_PIN(I2C_SDA),
-	JZ_GPIO_BULK_PIN(I2C_SCK),
- };
-
- inside the probe function:
-
-    ret = jz_gpio_bulk_request(i2c_pins, ARRAY_SIZE(i2c_pins));
-    if (ret) {
-	...
-
- inside the remove function:
-
-    jz_gpio_bulk_free(i2c_pins, ARRAY_SIZE(i2c_pins));
-
-*/
-
-struct jz_gpio_bulk_request {
-	int gpio;
-	const char *name;
-	enum jz_gpio_function function;
-};
-
-#define JZ_GPIO_BULK_PIN(pin) { \
-    .gpio = JZ_GPIO_ ## pin, \
-    .name = #pin, \
-    .function = JZ_GPIO_FUNC_ ## pin \
-}
-
-int jz_gpio_bulk_request(const struct jz_gpio_bulk_request *request, size_t num);
-void jz_gpio_bulk_free(const struct jz_gpio_bulk_request *request, size_t num);
-void jz_gpio_bulk_suspend(const struct jz_gpio_bulk_request *request, size_t num);
-void jz_gpio_bulk_resume(const struct jz_gpio_bulk_request *request, size_t num);
-void jz_gpio_enable_pullup(unsigned gpio);
-void jz_gpio_disable_pullup(unsigned gpio);
-int jz_gpio_set_function(int gpio, enum jz_gpio_function function);
-
-int jz_gpio_port_direction_input(int port, uint32_t mask);
-int jz_gpio_port_direction_output(int port, uint32_t mask);
-void jz_gpio_port_set_value(int port, uint32_t value, uint32_t mask);
-uint32_t jz_gpio_port_get_value(int port, uint32_t mask);
-
 #define JZ_GPIO_PORTA(x) ((x) + 32 * 0)
 #define JZ_GPIO_PORTB(x) ((x) + 32 * 1)
 #define JZ_GPIO_PORTC(x) ((x) + 32 * 2)
 #define JZ_GPIO_PORTD(x) ((x) + 32 * 3)
 
-/* Port A function pins */
-#define JZ_GPIO_MEM_DATA0		JZ_GPIO_PORTA(0)
-#define JZ_GPIO_MEM_DATA1		JZ_GPIO_PORTA(1)
-#define JZ_GPIO_MEM_DATA2		JZ_GPIO_PORTA(2)
-#define JZ_GPIO_MEM_DATA3		JZ_GPIO_PORTA(3)
-#define JZ_GPIO_MEM_DATA4		JZ_GPIO_PORTA(4)
-#define JZ_GPIO_MEM_DATA5		JZ_GPIO_PORTA(5)
-#define JZ_GPIO_MEM_DATA6		JZ_GPIO_PORTA(6)
-#define JZ_GPIO_MEM_DATA7		JZ_GPIO_PORTA(7)
-#define JZ_GPIO_MEM_DATA8		JZ_GPIO_PORTA(8)
-#define JZ_GPIO_MEM_DATA9		JZ_GPIO_PORTA(9)
-#define JZ_GPIO_MEM_DATA10		JZ_GPIO_PORTA(10)
-#define JZ_GPIO_MEM_DATA11		JZ_GPIO_PORTA(11)
-#define JZ_GPIO_MEM_DATA12		JZ_GPIO_PORTA(12)
-#define JZ_GPIO_MEM_DATA13		JZ_GPIO_PORTA(13)
-#define JZ_GPIO_MEM_DATA14		JZ_GPIO_PORTA(14)
-#define JZ_GPIO_MEM_DATA15		JZ_GPIO_PORTA(15)
-#define JZ_GPIO_MEM_DATA16		JZ_GPIO_PORTA(16)
-#define JZ_GPIO_MEM_DATA17		JZ_GPIO_PORTA(17)
-#define JZ_GPIO_MEM_DATA18		JZ_GPIO_PORTA(18)
-#define JZ_GPIO_MEM_DATA19		JZ_GPIO_PORTA(19)
-#define JZ_GPIO_MEM_DATA20		JZ_GPIO_PORTA(20)
-#define JZ_GPIO_MEM_DATA21		JZ_GPIO_PORTA(21)
-#define JZ_GPIO_MEM_DATA22		JZ_GPIO_PORTA(22)
-#define JZ_GPIO_MEM_DATA23		JZ_GPIO_PORTA(23)
-#define JZ_GPIO_MEM_DATA24		JZ_GPIO_PORTA(24)
-#define JZ_GPIO_MEM_DATA25		JZ_GPIO_PORTA(25)
-#define JZ_GPIO_MEM_DATA26		JZ_GPIO_PORTA(26)
-#define JZ_GPIO_MEM_DATA27		JZ_GPIO_PORTA(27)
-#define JZ_GPIO_MEM_DATA28		JZ_GPIO_PORTA(28)
-#define JZ_GPIO_MEM_DATA29		JZ_GPIO_PORTA(29)
-#define JZ_GPIO_MEM_DATA30		JZ_GPIO_PORTA(30)
-#define JZ_GPIO_MEM_DATA31		JZ_GPIO_PORTA(31)
-
-#define JZ_GPIO_FUNC_MEM_DATA0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA4		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA5		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA6		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA7		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA8		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA9		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA10		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA11		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA12		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA13		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA14		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA15		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA16		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA17		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA18		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA19		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA20		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA21		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA22		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA23		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA24		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA25		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA26		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA27		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA28		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA29		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA30		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA31		JZ_GPIO_FUNC1
-
-/* Port B function pins */
-#define JZ_GPIO_MEM_ADDR0		JZ_GPIO_PORTB(0)
-#define JZ_GPIO_MEM_ADDR1		JZ_GPIO_PORTB(1)
-#define JZ_GPIO_MEM_ADDR2		JZ_GPIO_PORTB(2)
-#define JZ_GPIO_MEM_ADDR3		JZ_GPIO_PORTB(3)
-#define JZ_GPIO_MEM_ADDR4		JZ_GPIO_PORTB(4)
-#define JZ_GPIO_MEM_ADDR5		JZ_GPIO_PORTB(5)
-#define JZ_GPIO_MEM_ADDR6		JZ_GPIO_PORTB(6)
-#define JZ_GPIO_MEM_ADDR7		JZ_GPIO_PORTB(7)
-#define JZ_GPIO_MEM_ADDR8		JZ_GPIO_PORTB(8)
-#define JZ_GPIO_MEM_ADDR9		JZ_GPIO_PORTB(9)
-#define JZ_GPIO_MEM_ADDR10		JZ_GPIO_PORTB(10)
-#define JZ_GPIO_MEM_ADDR11		JZ_GPIO_PORTB(11)
-#define JZ_GPIO_MEM_ADDR12		JZ_GPIO_PORTB(12)
-#define JZ_GPIO_MEM_ADDR13		JZ_GPIO_PORTB(13)
-#define JZ_GPIO_MEM_ADDR14		JZ_GPIO_PORTB(14)
-#define JZ_GPIO_MEM_ADDR15		JZ_GPIO_PORTB(15)
-#define JZ_GPIO_MEM_ADDR16		JZ_GPIO_PORTB(16)
-#define JZ_GPIO_LCD_CLS			JZ_GPIO_PORTB(17)
-#define JZ_GPIO_LCD_SPL			JZ_GPIO_PORTB(18)
-#define JZ_GPIO_MEM_DCS			JZ_GPIO_PORTB(19)
-#define JZ_GPIO_MEM_RAS			JZ_GPIO_PORTB(20)
-#define JZ_GPIO_MEM_CAS			JZ_GPIO_PORTB(21)
-#define JZ_GPIO_MEM_SDWE		JZ_GPIO_PORTB(22)
-#define JZ_GPIO_MEM_CKE			JZ_GPIO_PORTB(23)
-#define JZ_GPIO_MEM_CKO			JZ_GPIO_PORTB(24)
-#define JZ_GPIO_MEM_CS0			JZ_GPIO_PORTB(25)
-#define JZ_GPIO_MEM_CS1			JZ_GPIO_PORTB(26)
-#define JZ_GPIO_MEM_CS2			JZ_GPIO_PORTB(27)
-#define JZ_GPIO_MEM_CS3			JZ_GPIO_PORTB(28)
-#define JZ_GPIO_MEM_RD			JZ_GPIO_PORTB(29)
-#define JZ_GPIO_MEM_WR			JZ_GPIO_PORTB(30)
-#define JZ_GPIO_MEM_WE0			JZ_GPIO_PORTB(31)
-
-#define JZ_GPIO_FUNC_MEM_ADDR0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR4		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR5		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR6		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR7		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR8		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR9		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR10		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR11		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR12		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR13		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR14		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR15		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR16		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_CLS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_SPL		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DCS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_RAS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CAS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_SDWE		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CKE		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CKO		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CS0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CS1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CS2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CS3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_RD		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WR		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WE0		JZ_GPIO_FUNC1
-
-
-#define JZ_GPIO_MEM_ADDR21		JZ_GPIO_PORTB(17)
-#define JZ_GPIO_MEM_ADDR22		JZ_GPIO_PORTB(18)
-
-#define JZ_GPIO_FUNC_MEM_ADDR21		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_ADDR22		JZ_GPIO_FUNC2
-
-/* Port C function pins */
-#define JZ_GPIO_LCD_DATA0		JZ_GPIO_PORTC(0)
-#define JZ_GPIO_LCD_DATA1		JZ_GPIO_PORTC(1)
-#define JZ_GPIO_LCD_DATA2		JZ_GPIO_PORTC(2)
-#define JZ_GPIO_LCD_DATA3		JZ_GPIO_PORTC(3)
-#define JZ_GPIO_LCD_DATA4		JZ_GPIO_PORTC(4)
-#define JZ_GPIO_LCD_DATA5		JZ_GPIO_PORTC(5)
-#define JZ_GPIO_LCD_DATA6		JZ_GPIO_PORTC(6)
-#define JZ_GPIO_LCD_DATA7		JZ_GPIO_PORTC(7)
-#define JZ_GPIO_LCD_DATA8		JZ_GPIO_PORTC(8)
-#define JZ_GPIO_LCD_DATA9		JZ_GPIO_PORTC(9)
-#define JZ_GPIO_LCD_DATA10		JZ_GPIO_PORTC(10)
-#define JZ_GPIO_LCD_DATA11		JZ_GPIO_PORTC(11)
-#define JZ_GPIO_LCD_DATA12		JZ_GPIO_PORTC(12)
-#define JZ_GPIO_LCD_DATA13		JZ_GPIO_PORTC(13)
-#define JZ_GPIO_LCD_DATA14		JZ_GPIO_PORTC(14)
-#define JZ_GPIO_LCD_DATA15		JZ_GPIO_PORTC(15)
-#define JZ_GPIO_LCD_DATA16		JZ_GPIO_PORTC(16)
-#define JZ_GPIO_LCD_DATA17		JZ_GPIO_PORTC(17)
-#define JZ_GPIO_LCD_PCLK		JZ_GPIO_PORTC(18)
-#define JZ_GPIO_LCD_HSYNC		JZ_GPIO_PORTC(19)
-#define JZ_GPIO_LCD_VSYNC		JZ_GPIO_PORTC(20)
-#define JZ_GPIO_LCD_DE			JZ_GPIO_PORTC(21)
-#define JZ_GPIO_LCD_PS			JZ_GPIO_PORTC(22)
-#define JZ_GPIO_LCD_REV			JZ_GPIO_PORTC(23)
-#define JZ_GPIO_MEM_WE1			JZ_GPIO_PORTC(24)
-#define JZ_GPIO_MEM_WE2			JZ_GPIO_PORTC(25)
-#define JZ_GPIO_MEM_WE3			JZ_GPIO_PORTC(26)
-#define JZ_GPIO_MEM_WAIT		JZ_GPIO_PORTC(27)
-#define JZ_GPIO_MEM_FRE			JZ_GPIO_PORTC(28)
-#define JZ_GPIO_MEM_FWE			JZ_GPIO_PORTC(29)
-
-#define JZ_GPIO_FUNC_LCD_DATA0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA4		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA5		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA6		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA7		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA8		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA9		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA10		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA11		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA12		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA13		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA14		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA15		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA16		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA17		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_PCLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_VSYNC		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_HSYNC		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DE		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_PS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_REV		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WE1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WE2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WE3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WAIT		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_FRE		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_FWE		JZ_GPIO_FUNC1
-
-
-#define JZ_GPIO_MEM_ADDR19		JZ_GPIO_PORTB(22)
-#define JZ_GPIO_MEM_ADDR20		JZ_GPIO_PORTB(23)
-
-#define JZ_GPIO_FUNC_MEM_ADDR19		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_ADDR20		JZ_GPIO_FUNC2
-
-/* Port D function pins */
-#define JZ_GPIO_CIM_DATA0		JZ_GPIO_PORTD(0)
-#define JZ_GPIO_CIM_DATA1		JZ_GPIO_PORTD(1)
-#define JZ_GPIO_CIM_DATA2		JZ_GPIO_PORTD(2)
-#define JZ_GPIO_CIM_DATA3		JZ_GPIO_PORTD(3)
-#define JZ_GPIO_CIM_DATA4		JZ_GPIO_PORTD(4)
-#define JZ_GPIO_CIM_DATA5		JZ_GPIO_PORTD(5)
-#define JZ_GPIO_CIM_DATA6		JZ_GPIO_PORTD(6)
-#define JZ_GPIO_CIM_DATA7		JZ_GPIO_PORTD(7)
-#define JZ_GPIO_MSC_CMD			JZ_GPIO_PORTD(8)
-#define JZ_GPIO_MSC_CLK			JZ_GPIO_PORTD(9)
-#define JZ_GPIO_MSC_DATA0		JZ_GPIO_PORTD(10)
-#define JZ_GPIO_MSC_DATA1		JZ_GPIO_PORTD(11)
-#define JZ_GPIO_MSC_DATA2		JZ_GPIO_PORTD(12)
-#define JZ_GPIO_MSC_DATA3		JZ_GPIO_PORTD(13)
-#define JZ_GPIO_CIM_MCLK		JZ_GPIO_PORTD(14)
-#define JZ_GPIO_CIM_PCLK		JZ_GPIO_PORTD(15)
-#define JZ_GPIO_CIM_VSYNC		JZ_GPIO_PORTD(16)
-#define JZ_GPIO_CIM_HSYNC		JZ_GPIO_PORTD(17)
-#define JZ_GPIO_SPI_CLK			JZ_GPIO_PORTD(18)
-#define JZ_GPIO_SPI_CE0			JZ_GPIO_PORTD(19)
-#define JZ_GPIO_SPI_DT			JZ_GPIO_PORTD(20)
-#define JZ_GPIO_SPI_DR			JZ_GPIO_PORTD(21)
-#define JZ_GPIO_SPI_CE1			JZ_GPIO_PORTD(22)
-#define JZ_GPIO_PWM0			JZ_GPIO_PORTD(23)
-#define JZ_GPIO_PWM1			JZ_GPIO_PORTD(24)
-#define JZ_GPIO_PWM2			JZ_GPIO_PORTD(25)
-#define JZ_GPIO_PWM3			JZ_GPIO_PORTD(26)
-#define JZ_GPIO_PWM4			JZ_GPIO_PORTD(27)
-#define JZ_GPIO_PWM5			JZ_GPIO_PORTD(28)
-#define JZ_GPIO_PWM6			JZ_GPIO_PORTD(30)
-#define JZ_GPIO_PWM7			JZ_GPIO_PORTD(31)
-
-#define JZ_GPIO_FUNC_CIM_DATA		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_CIM_DATA0		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA1		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA2		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA3		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA4		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA5		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA6		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA7		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_MSC_CMD		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MSC_CLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MSC_DATA		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MSC_DATA0		JZ_GPIO_FUNC_MSC_DATA
-#define JZ_GPIO_FUNC_MSC_DATA1		JZ_GPIO_FUNC_MSC_DATA
-#define JZ_GPIO_FUNC_MSC_DATA2		JZ_GPIO_FUNC_MSC_DATA
-#define JZ_GPIO_FUNC_MSC_DATA3		JZ_GPIO_FUNC_MSC_DATA
-#define JZ_GPIO_FUNC_CIM_MCLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_CIM_PCLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_CIM_VSYNC		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_CIM_HSYNC		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_CLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_CE0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_DT		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_DR		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_CE1		JZ_GPIO_FUNC1
-
-#define JZ_GPIO_FUNC_PWM		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_PWM0		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM1		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM2		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM3		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM4		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM5		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM6		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM7		JZ_GPIO_FUNC_PWM
-
-#define JZ_GPIO_MEM_SCLK_RSTN		JZ_GPIO_PORTD(18)
-#define JZ_GPIO_MEM_BCLK		JZ_GPIO_PORTD(19)
-#define JZ_GPIO_MEM_SDATO		JZ_GPIO_PORTD(20)
-#define JZ_GPIO_MEM_SDATI		JZ_GPIO_PORTD(21)
-#define JZ_GPIO_MEM_SYNC		JZ_GPIO_PORTD(22)
-#define JZ_GPIO_I2C_SDA			JZ_GPIO_PORTD(23)
-#define JZ_GPIO_I2C_SCK			JZ_GPIO_PORTD(24)
-#define JZ_GPIO_UART0_TXD		JZ_GPIO_PORTD(25)
-#define JZ_GPIO_UART0_RXD		JZ_GPIO_PORTD(26)
-#define JZ_GPIO_MEM_ADDR17		JZ_GPIO_PORTD(27)
-#define JZ_GPIO_MEM_ADDR18		JZ_GPIO_PORTD(28)
-#define JZ_GPIO_UART0_CTS		JZ_GPIO_PORTD(30)
-#define JZ_GPIO_UART0_RTS		JZ_GPIO_PORTD(31)
-
-#define JZ_GPIO_FUNC_MEM_SCLK_RSTN	JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_BCLK		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_SDATO		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_SDATI		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_SYNC		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_I2C_SDA		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_I2C_SCK		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_UART0_TXD		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_UART0_RXD		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_ADDR17		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_ADDR18		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_UART0_CTS		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_UART0_RTS		JZ_GPIO_FUNC2
-
-#define JZ_GPIO_UART1_RXD		JZ_GPIO_PORTD(30)
-#define JZ_GPIO_UART1_TXD		JZ_GPIO_PORTD(31)
-
-#define JZ_GPIO_FUNC_UART1_RXD		JZ_GPIO_FUNC3
-#define JZ_GPIO_FUNC_UART1_TXD		JZ_GPIO_FUNC3
-
 #endif
diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
index 39d70bde8cfe..6b9c1f7c31c9 100644
--- a/arch/mips/jz4740/Makefile
+++ b/arch/mips/jz4740/Makefile
@@ -7,8 +7,6 @@
 obj-y += prom.o time.o reset.o setup.o \
 	platform.o timer.o
 
-obj-$(CONFIG_MACH_JZ4740) += gpio.o
-
 CFLAGS_setup.o = -I$(src)/../../../scripts/dtc/libfdt
 
 # board specific support
diff --git a/arch/mips/jz4740/gpio.c b/arch/mips/jz4740/gpio.c
deleted file mode 100644
index b765773ab8aa..000000000000
--- a/arch/mips/jz4740/gpio.c
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- *  Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
- *  JZ4740 platform GPIO support
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <linux/io.h>
-#include <linux/gpio/driver.h>
-/* FIXME: needed for gpio_request(), try to remove consumer API from driver */
-#include <linux/gpio.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/irqchip/ingenic.h>
-#include <linux/bitops.h>
-
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-
-#include <asm/mach-jz4740/base.h>
-#include <asm/mach-jz4740/gpio.h>
-
-#define JZ4740_GPIO_BASE_A (32*0)
-#define JZ4740_GPIO_BASE_B (32*1)
-#define JZ4740_GPIO_BASE_C (32*2)
-#define JZ4740_GPIO_BASE_D (32*3)
-
-#define JZ4740_GPIO_NUM_A 32
-#define JZ4740_GPIO_NUM_B 32
-#define JZ4740_GPIO_NUM_C 31
-#define JZ4740_GPIO_NUM_D 32
-
-#define JZ4740_IRQ_GPIO_BASE_A (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_A)
-#define JZ4740_IRQ_GPIO_BASE_B (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_B)
-#define JZ4740_IRQ_GPIO_BASE_C (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_C)
-#define JZ4740_IRQ_GPIO_BASE_D (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_D)
-
-#define JZ_REG_GPIO_PIN			0x00
-#define JZ_REG_GPIO_DATA		0x10
-#define JZ_REG_GPIO_DATA_SET		0x14
-#define JZ_REG_GPIO_DATA_CLEAR		0x18
-#define JZ_REG_GPIO_MASK		0x20
-#define JZ_REG_GPIO_MASK_SET		0x24
-#define JZ_REG_GPIO_MASK_CLEAR		0x28
-#define JZ_REG_GPIO_PULL		0x30
-#define JZ_REG_GPIO_PULL_SET		0x34
-#define JZ_REG_GPIO_PULL_CLEAR		0x38
-#define JZ_REG_GPIO_FUNC		0x40
-#define JZ_REG_GPIO_FUNC_SET		0x44
-#define JZ_REG_GPIO_FUNC_CLEAR		0x48
-#define JZ_REG_GPIO_SELECT		0x50
-#define JZ_REG_GPIO_SELECT_SET		0x54
-#define JZ_REG_GPIO_SELECT_CLEAR	0x58
-#define JZ_REG_GPIO_DIRECTION		0x60
-#define JZ_REG_GPIO_DIRECTION_SET	0x64
-#define JZ_REG_GPIO_DIRECTION_CLEAR	0x68
-#define JZ_REG_GPIO_TRIGGER		0x70
-#define JZ_REG_GPIO_TRIGGER_SET		0x74
-#define JZ_REG_GPIO_TRIGGER_CLEAR	0x78
-#define JZ_REG_GPIO_FLAG		0x80
-#define JZ_REG_GPIO_FLAG_CLEAR		0x14
-
-#define GPIO_TO_BIT(gpio) BIT(gpio & 0x1f)
-#define GPIO_TO_REG(gpio, reg) (gpio_to_jz_gpio_chip(gpio)->base + (reg))
-#define CHIP_TO_REG(chip, reg) (gpio_chip_to_jz_gpio_chip(chip)->base + (reg))
-
-struct jz_gpio_chip {
-	unsigned int irq;
-	unsigned int irq_base;
-	uint32_t edge_trigger_both;
-
-	void __iomem *base;
-
-	struct gpio_chip gpio_chip;
-};
-
-static struct jz_gpio_chip jz4740_gpio_chips[];
-
-static inline struct jz_gpio_chip *gpio_to_jz_gpio_chip(unsigned int gpio)
-{
-	return &jz4740_gpio_chips[gpio >> 5];
-}
-
-static inline struct jz_gpio_chip *gpio_chip_to_jz_gpio_chip(struct gpio_chip *gc)
-{
-	return gpiochip_get_data(gc);
-}
-
-static inline struct jz_gpio_chip *irq_to_jz_gpio_chip(struct irq_data *data)
-{
-	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
-	return gc->private;
-}
-
-static inline void jz_gpio_write_bit(unsigned int gpio, unsigned int reg)
-{
-	writel(GPIO_TO_BIT(gpio), GPIO_TO_REG(gpio, reg));
-}
-
-int jz_gpio_set_function(int gpio, enum jz_gpio_function function)
-{
-	if (function == JZ_GPIO_FUNC_NONE) {
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_FUNC_CLEAR);
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_CLEAR);
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_CLEAR);
-	} else {
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_FUNC_SET);
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_CLEAR);
-		switch (function) {
-		case JZ_GPIO_FUNC1:
-			jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_CLEAR);
-			break;
-		case JZ_GPIO_FUNC3:
-			jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_SET);
-		case JZ_GPIO_FUNC2: /* Falltrough */
-			jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_SET);
-			break;
-		default:
-			BUG();
-			break;
-		}
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(jz_gpio_set_function);
-
-int jz_gpio_bulk_request(const struct jz_gpio_bulk_request *request, size_t num)
-{
-	size_t i;
-	int ret;
-
-	for (i = 0; i < num; ++i, ++request) {
-		ret = gpio_request(request->gpio, request->name);
-		if (ret)
-			goto err;
-		jz_gpio_set_function(request->gpio, request->function);
-	}
-
-	return 0;
-
-err:
-	for (--request; i > 0; --i, --request) {
-		gpio_free(request->gpio);
-		jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
-	}
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(jz_gpio_bulk_request);
-
-void jz_gpio_bulk_free(const struct jz_gpio_bulk_request *request, size_t num)
-{
-	size_t i;
-
-	for (i = 0; i < num; ++i, ++request) {
-		gpio_free(request->gpio);
-		jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
-	}
-
-}
-EXPORT_SYMBOL_GPL(jz_gpio_bulk_free);
-
-void jz_gpio_bulk_suspend(const struct jz_gpio_bulk_request *request, size_t num)
-{
-	size_t i;
-
-	for (i = 0; i < num; ++i, ++request) {
-		jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
-		jz_gpio_write_bit(request->gpio, JZ_REG_GPIO_DIRECTION_CLEAR);
-		jz_gpio_write_bit(request->gpio, JZ_REG_GPIO_PULL_SET);
-	}
-}
-EXPORT_SYMBOL_GPL(jz_gpio_bulk_suspend);
-
-void jz_gpio_bulk_resume(const struct jz_gpio_bulk_request *request, size_t num)
-{
-	size_t i;
-
-	for (i = 0; i < num; ++i, ++request)
-		jz_gpio_set_function(request->gpio, request->function);
-}
-EXPORT_SYMBOL_GPL(jz_gpio_bulk_resume);
-
-void jz_gpio_enable_pullup(unsigned gpio)
-{
-	jz_gpio_write_bit(gpio, JZ_REG_GPIO_PULL_CLEAR);
-}
-EXPORT_SYMBOL_GPL(jz_gpio_enable_pullup);
-
-void jz_gpio_disable_pullup(unsigned gpio)
-{
-	jz_gpio_write_bit(gpio, JZ_REG_GPIO_PULL_SET);
-}
-EXPORT_SYMBOL_GPL(jz_gpio_disable_pullup);
-
-static int jz_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
-{
-	return !!(readl(CHIP_TO_REG(chip, JZ_REG_GPIO_PIN)) & BIT(gpio));
-}
-
-static void jz_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
-{
-	uint32_t __iomem *reg = CHIP_TO_REG(chip, JZ_REG_GPIO_DATA_SET);
-	reg += !value;
-	writel(BIT(gpio), reg);
-}
-
-static int jz_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
-	int value)
-{
-	writel(BIT(gpio), CHIP_TO_REG(chip, JZ_REG_GPIO_DIRECTION_SET));
-	jz_gpio_set_value(chip, gpio, value);
-
-	return 0;
-}
-
-static int jz_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
-{
-	writel(BIT(gpio), CHIP_TO_REG(chip, JZ_REG_GPIO_DIRECTION_CLEAR));
-
-	return 0;
-}
-
-static int jz_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
-{
-	struct jz_gpio_chip *jz_gpio = gpiochip_get_data(chip);
-
-	return jz_gpio->irq_base + gpio;
-}
-
-int jz_gpio_port_direction_input(int port, uint32_t mask)
-{
-	writel(mask, GPIO_TO_REG(port, JZ_REG_GPIO_DIRECTION_CLEAR));
-
-	return 0;
-}
-EXPORT_SYMBOL(jz_gpio_port_direction_input);
-
-int jz_gpio_port_direction_output(int port, uint32_t mask)
-{
-	writel(mask, GPIO_TO_REG(port, JZ_REG_GPIO_DIRECTION_SET));
-
-	return 0;
-}
-EXPORT_SYMBOL(jz_gpio_port_direction_output);
-
-void jz_gpio_port_set_value(int port, uint32_t value, uint32_t mask)
-{
-	writel(~value & mask, GPIO_TO_REG(port, JZ_REG_GPIO_DATA_CLEAR));
-	writel(value & mask, GPIO_TO_REG(port, JZ_REG_GPIO_DATA_SET));
-}
-EXPORT_SYMBOL(jz_gpio_port_set_value);
-
-uint32_t jz_gpio_port_get_value(int port, uint32_t mask)
-{
-	uint32_t value = readl(GPIO_TO_REG(port, JZ_REG_GPIO_PIN));
-
-	return value & mask;
-}
-EXPORT_SYMBOL(jz_gpio_port_get_value);
-
-#define IRQ_TO_BIT(irq) BIT((irq - JZ4740_IRQ_GPIO(0)) & 0x1f)
-
-static void jz_gpio_check_trigger_both(struct jz_gpio_chip *chip, unsigned int irq)
-{
-	uint32_t value;
-	void __iomem *reg;
-	uint32_t mask = IRQ_TO_BIT(irq);
-
-	if (!(chip->edge_trigger_both & mask))
-		return;
-
-	reg = chip->base;
-
-	value = readl(chip->base + JZ_REG_GPIO_PIN);
-	if (value & mask)
-		reg += JZ_REG_GPIO_DIRECTION_CLEAR;
-	else
-		reg += JZ_REG_GPIO_DIRECTION_SET;
-
-	writel(mask, reg);
-}
-
-static void jz_gpio_irq_demux_handler(struct irq_desc *desc)
-{
-	uint32_t flag;
-	unsigned int gpio_irq;
-	struct jz_gpio_chip *chip = irq_desc_get_handler_data(desc);
-
-	flag = readl(chip->base + JZ_REG_GPIO_FLAG);
-	if (!flag)
-		return;
-
-	gpio_irq = chip->irq_base + __fls(flag);
-
-	jz_gpio_check_trigger_both(chip, gpio_irq);
-
-	generic_handle_irq(gpio_irq);
-};
-
-static inline void jz_gpio_set_irq_bit(struct irq_data *data, unsigned int reg)
-{
-	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
-	writel(IRQ_TO_BIT(data->irq), chip->base + reg);
-}
-
-static void jz_gpio_irq_unmask(struct irq_data *data)
-{
-	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
-
-	jz_gpio_check_trigger_both(chip, data->irq);
-	irq_gc_unmask_enable_reg(data);
-};
-
-/* TODO: Check if function is gpio */
-static unsigned int jz_gpio_irq_startup(struct irq_data *data)
-{
-	jz_gpio_set_irq_bit(data, JZ_REG_GPIO_SELECT_SET);
-	jz_gpio_irq_unmask(data);
-	return 0;
-}
-
-static void jz_gpio_irq_shutdown(struct irq_data *data)
-{
-	irq_gc_mask_disable_reg(data);
-
-	/* Set direction to input */
-	jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR);
-	jz_gpio_set_irq_bit(data, JZ_REG_GPIO_SELECT_CLEAR);
-}
-
-static int jz_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type)
-{
-	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
-	unsigned int irq = data->irq;
-
-	if (flow_type == IRQ_TYPE_EDGE_BOTH) {
-		uint32_t value = readl(chip->base + JZ_REG_GPIO_PIN);
-		if (value & IRQ_TO_BIT(irq))
-			flow_type = IRQ_TYPE_EDGE_FALLING;
-		else
-			flow_type = IRQ_TYPE_EDGE_RISING;
-		chip->edge_trigger_both |= IRQ_TO_BIT(irq);
-	} else {
-		chip->edge_trigger_both &= ~IRQ_TO_BIT(irq);
-	}
-
-	switch (flow_type) {
-	case IRQ_TYPE_EDGE_RISING:
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_SET);
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_SET);
-		break;
-	case IRQ_TYPE_EDGE_FALLING:
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR);
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_SET);
-		break;
-	case IRQ_TYPE_LEVEL_HIGH:
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_SET);
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_CLEAR);
-		break;
-	case IRQ_TYPE_LEVEL_LOW:
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR);
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_CLEAR);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int jz_gpio_irq_set_wake(struct irq_data *data, unsigned int on)
-{
-	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
-
-	irq_gc_set_wake(data, on);
-	irq_set_irq_wake(chip->irq, on);
-
-	return 0;
-}
-
-#define JZ4740_GPIO_CHIP(_bank) { \
-	.irq_base = JZ4740_IRQ_GPIO_BASE_ ## _bank, \
-	.gpio_chip = { \
-		.label = "Bank " # _bank, \
-		.owner = THIS_MODULE, \
-		.set = jz_gpio_set_value, \
-		.get = jz_gpio_get_value, \
-		.direction_output = jz_gpio_direction_output, \
-		.direction_input = jz_gpio_direction_input, \
-		.to_irq = jz_gpio_to_irq, \
-		.base = JZ4740_GPIO_BASE_ ## _bank, \
-		.ngpio = JZ4740_GPIO_NUM_ ## _bank, \
-	}, \
-}
-
-static struct jz_gpio_chip jz4740_gpio_chips[] = {
-	JZ4740_GPIO_CHIP(A),
-	JZ4740_GPIO_CHIP(B),
-	JZ4740_GPIO_CHIP(C),
-	JZ4740_GPIO_CHIP(D),
-};
-
-static void jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id)
-{
-	struct irq_chip_generic *gc;
-	struct irq_chip_type *ct;
-
-	chip->base = ioremap(JZ4740_GPIO_BASE_ADDR + (id * 0x100), 0x100);
-
-	chip->irq = JZ4740_IRQ_INTC_GPIO(id);
-	irq_set_chained_handler_and_data(chip->irq,
-					 jz_gpio_irq_demux_handler, chip);
-
-	gc = irq_alloc_generic_chip(chip->gpio_chip.label, 1, chip->irq_base,
-		chip->base, handle_level_irq);
-
-	gc->wake_enabled = IRQ_MSK(chip->gpio_chip.ngpio);
-	gc->private = chip;
-
-	ct = gc->chip_types;
-	ct->regs.enable = JZ_REG_GPIO_MASK_CLEAR;
-	ct->regs.disable = JZ_REG_GPIO_MASK_SET;
-	ct->regs.ack = JZ_REG_GPIO_FLAG_CLEAR;
-
-	ct->chip.name = "GPIO";
-	ct->chip.irq_mask = irq_gc_mask_disable_reg;
-	ct->chip.irq_unmask = jz_gpio_irq_unmask;
-	ct->chip.irq_ack = irq_gc_ack_set_bit;
-	ct->chip.irq_suspend = ingenic_intc_irq_suspend;
-	ct->chip.irq_resume = ingenic_intc_irq_resume;
-	ct->chip.irq_startup = jz_gpio_irq_startup;
-	ct->chip.irq_shutdown = jz_gpio_irq_shutdown;
-	ct->chip.irq_set_type = jz_gpio_irq_set_type;
-	ct->chip.irq_set_wake = jz_gpio_irq_set_wake;
-	ct->chip.flags = IRQCHIP_SET_TYPE_MASKED;
-
-	irq_setup_generic_chip(gc, IRQ_MSK(chip->gpio_chip.ngpio),
-		IRQ_GC_INIT_NESTED_LOCK, 0, IRQ_NOPROBE | IRQ_LEVEL);
-
-	gpiochip_add_data(&chip->gpio_chip, chip);
-}
-
-static int __init jz4740_gpio_init(void)
-{
-	unsigned int i;
-
-	for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i)
-		jz4740_gpio_chip_init(&jz4740_gpio_chips[i], i);
-
-	printk(KERN_INFO "JZ4740 GPIO initialized\n");
-
-	return 0;
-}
-arch_initcall(jz4740_gpio_init);
-
-#ifdef CONFIG_DEBUG_FS
-
-static inline void gpio_seq_reg(struct seq_file *s, struct jz_gpio_chip *chip,
-	const char *name, unsigned int reg)
-{
-	seq_printf(s, "\t%s: %08x\n", name, readl(chip->base + reg));
-}
-
-static int gpio_regs_show(struct seq_file *s, void *unused)
-{
-	struct jz_gpio_chip *chip = jz4740_gpio_chips;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i, ++chip) {
-		seq_printf(s, "==GPIO %d==\n", i);
-		gpio_seq_reg(s, chip, "Pin", JZ_REG_GPIO_PIN);
-		gpio_seq_reg(s, chip, "Data", JZ_REG_GPIO_DATA);
-		gpio_seq_reg(s, chip, "Mask", JZ_REG_GPIO_MASK);
-		gpio_seq_reg(s, chip, "Pull", JZ_REG_GPIO_PULL);
-		gpio_seq_reg(s, chip, "Func", JZ_REG_GPIO_FUNC);
-		gpio_seq_reg(s, chip, "Select", JZ_REG_GPIO_SELECT);
-		gpio_seq_reg(s, chip, "Direction", JZ_REG_GPIO_DIRECTION);
-		gpio_seq_reg(s, chip, "Trigger", JZ_REG_GPIO_TRIGGER);
-		gpio_seq_reg(s, chip, "Flag", JZ_REG_GPIO_FLAG);
-	}
-
-	return 0;
-}
-
-static int gpio_regs_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, gpio_regs_show, NULL);
-}
-
-static const struct file_operations gpio_regs_operations = {
-	.open		= gpio_regs_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static int __init gpio_debugfs_init(void)
-{
-	(void) debugfs_create_file("jz_regs_gpio", S_IFREG | S_IRUGO,
-				NULL, NULL, &gpio_regs_operations);
-	return 0;
-}
-subsys_initcall(gpio_debugfs_init);
-
-#endif
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver
  2017-01-17 23:14 [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                   ` (12 preceding siblings ...)
  2017-01-17 23:14 ` [PATCH 13/13] MIPS: jz4740: Remove custom GPIO code Paul Cercueil
@ 2017-01-18  7:15 ` Thierry Reding
  2017-01-19 11:19   ` Paul Cercueil
  2017-01-19  6:38 ` [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver Linus Walleij
  14 siblings, 1 reply; 162+ messages in thread
From: Thierry Reding @ 2017-01-18  7:15 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan

[-- Attachment #1: Type: text/plain, Size: 2322 bytes --]

On Wed, Jan 18, 2017 at 12:14:08AM +0100, Paul Cercueil wrote:
[...]
> One problem still unresolved: the pinctrl framework does not allow us to
> configure each pin on demand (someone please prove me wrong), when the
> various PWM channels are requested or released. For instance, the PWM
> channels can be configured from sysfs, which would require all PWM pins
> to be configured properly beforehand for the PWM function, eventually
> causing conflicts with other platform or board drivers.

Still catching up on a lot of email, so I haven't gone through the
entire series. But I don't think the above is true.

My understanding is that you can have separate pin groups for each
pin (provided the hardware supports that) and then control each of
these groups dynamically at runtime.

That is you could have the PWM driver's ->request() and ->free()
call into the pinctrl framework to select the correct pinmux
configuration as necessary.

> The proper solution here would be to modify the pwm-jz4740 driver to
> handle only one PWM channel, and create an instance of this driver
> for each one of the 8 PWM channels. Then, it could use the pinctrl
> framework to dynamically configure the PWM pin it controls.

That could probably work. From only looking at the JZ4740 PWM driver
there's no separate IP block to deal with the PWM outputs, but they are
merely GPIOs controller via a timer, so one instance per GPIO seems like
a fine solution to me.

> Until this can be done, the only jz4740 board supported upstream
> (Qi lb60) could configure all of its connected PWM pins in PWM function
> mode, if those are not used by other drivers nor by GPIOs on the
> board. The only jz4780 board upstream (CI20) does not yet support the
> PWM driver.

Typically all of the pinmux is pre-determined by the board design. That
is if you've got 8 pins that can be driven by a PWM signal, not all of
those might be exposed by the design. If, say, only 0-4 and 6 expose the
PWM signal while 5 and 7 expose a different function then you can simply
use a static pinmux configuration and ignore PWMs 5 and 7. Even if
someone were to configure them, the signal would simply go nowhere.

Of course you'd have to check that your hardware actually matches those
assumptions. They certainly apply to many SoCs that I've come across.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH 12/13] pwm: jz4740: Let the pinctrl driver configure the pins
  2017-01-17 23:14 ` [PATCH 12/13] pwm: jz4740: " Paul Cercueil
@ 2017-01-18  7:20   ` Thierry Reding
  0 siblings, 0 replies; 162+ messages in thread
From: Thierry Reding @ 2017-01-18  7:20 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan

[-- Attachment #1: Type: text/plain, Size: 1857 bytes --]

On Wed, Jan 18, 2017 at 12:14:20AM +0100, Paul Cercueil wrote:
> Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
> the pins being properly configured before the driver probes.
> 
> One inherent problem of this new approach is that the pinctrl framework
> does not allow us to configure each pin on demand, when the various PWM
> channels are requested or released. For instance, the PWM channels can
> be configured from sysfs, which would require all PWM pins to be configured
> properly beforehand for the PWM function, eventually causing conflicts
> with other platform or board drivers.
> 
> The proper solution here would be to modify the pwm-jz4740 driver to
> handle only one PWM channel, and create an instance of this driver
> for each one of the 8 PWM channels. Then, it could use the pinctrl
> framework to dynamically configure the PWM pin it controls.
> 
> Until this can be done, the only jz4740 board supported upstream
> (Qi lb60) could configure all of its connected PWM pins in PWM function
> mode, if those are not used by other drivers nor by GPIOs on the
> board.
> 
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
> ---
>  drivers/pwm/pwm-jz4740.c | 29 -----------------------------
>  1 file changed, 29 deletions(-)
> 
> diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c
> index 76d13150283f..a75ff3622450 100644
> --- a/drivers/pwm/pwm-jz4740.c
> +++ b/drivers/pwm/pwm-jz4740.c
> @@ -21,22 +21,10 @@
>  #include <linux/platform_device.h>
>  #include <linux/pwm.h>
>  
> -#include <asm/mach-jz4740/gpio.h>

What about the linux/gpio.h header? It seems to me like that would be no
longer needed after this patch either.

Other than that this looks like the patch I'd expect if the pinmux was
configured statically, based on board design.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH 13/13] MIPS: jz4740: Remove custom GPIO code
  2017-01-17 23:14 ` [PATCH 13/13] MIPS: jz4740: Remove custom GPIO code Paul Cercueil
@ 2017-01-18  7:27   ` Thierry Reding
  2017-01-19 11:24     ` Paul Cercueil
  2017-01-19  9:07   ` Linus Walleij
  1 sibling, 1 reply; 162+ messages in thread
From: Thierry Reding @ 2017-01-18  7:27 UTC (permalink / raw)
  To: Paul Cercueil, Ralf Baechle
  Cc: Linus Walleij, Rob Herring, Mark Rutland, Ulf Hansson,
	Boris Brezillon, Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton, linux-gpio, devicetree,
	linux-kernel, linux-mips, linux-mmc, linux-mtd, linux-pwm,
	linux-fbdev, james.hogan

[-- Attachment #1: Type: text/plain, Size: 1641 bytes --]

On Wed, Jan 18, 2017 at 12:14:21AM +0100, Paul Cercueil wrote:
> All the drivers for the various hardware elements of the jz4740 SoC have
> been modified to use the pinctrl framework for their pin configuration
> needs.
> As such, this platform code is now unused and can be deleted.
> 
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
> ---
>  arch/mips/include/asm/mach-jz4740/gpio.h | 371 ----------------------
>  arch/mips/jz4740/Makefile                |   2 -
>  arch/mips/jz4740/gpio.c                  | 519 -------------------------------
>  3 files changed, 892 deletions(-)
>  delete mode 100644 arch/mips/jz4740/gpio.c

Have you considered how this could best be merged? It's probably easiest
to take all of this through the MIPS tree because we have an addition of
the pinctrl that would be a replacement for the GPIO code, while at the
same time a bunch of drivers rely on the JZ4740 GPIO code for successful
compilation.

That's slightly complicated by the number of drivers, so needs a lot of
coordination, but it's not the worst I've seen.

Maybe one other solution that would make the transition easier would be
to stub out the GPIO functions if the pinctrl driver is enabled, and do
the removal of the mach-jz4740/gpio.h after all drivers have been merged
through their corresponding subsystem trees. That way all drivers should
remain compilable and functional at runtime, while still having the
possibility to merge through the subsystem trees.

That said, the whole series is fairly simple, so merging everything
through the MIPS tree sounds like the easiest way to go.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH 02/13] pinctrl-jz4740: add a pinctrl driver for the Ingenic jz4740 SoC
  2017-01-17 23:14 ` [PATCH 02/13] pinctrl-jz4740: add a pinctrl driver for the Ingenic jz4740 SoC Paul Cercueil
@ 2017-01-18 10:16   ` Linus Walleij
  0 siblings, 0 replies; 162+ messages in thread
From: Linus Walleij @ 2017-01-18 10:16 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

n Wed, Jan 18, 2017 at 12:14 AM, Paul Cercueil <paul@crapouillou.net> wrote:

> From: Paul Burton <paul.burton@imgtec.com>
>
> This driver handles pin configuration, pin muxing, and GPIOs of the
> jz4740 SoC from Ingenic.
>
> It is separated into two files:
> - pinctrl-ingenic.c, which contains the core functions that can be
>   shared across all Ingenic SoCs,
> - pinctrl-jz4740.c, which contains the jz4740-pinctrl driver.
>
> The reason behind separating some functions out of the jz4740-pinctrl
> driver, is that the pin/GPIO controllers of the Ingenic SoCs are
> extremely similar across SoC versions, except that some have the
> registers shuffled around. Making a distinct separation will permit the
> reuse of large parts of the driver to support the other SoCs from
> Ingenic.
>
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>

> diff --git a/drivers/pinctrl/ingenic/Kconfig b/drivers/pinctrl/ingenic/Kconfig
> new file mode 100644
> index 000000000000..9923ce127183
> --- /dev/null
> +++ b/drivers/pinctrl/ingenic/Kconfig
> @@ -0,0 +1,14 @@
> +#
> +# Ingenic SoCs pin control drivers
> +#
> +config PINCTRL_INGENIC
> +       bool
> +       select PINMUX
> +       select GPIOLIB_IRQCHIP
> +       select GENERIC_PINCONF

I like it already when it looks like that :D

> +#include <linux/compiler.h>
> +#include <linux/gpio.h>

For drivers, just
#include <linux/gpio/driver.h>

> +struct ingenic_gpio_chip {
> +       char name[3];
> +       unsigned int idx;
> +       void __iomem *base;
> +       struct gpio_chip gc;
> +       struct irq_chip irq_chip;
> +       struct ingenic_pinctrl *pinctrl;
> +       const struct ingenic_pinctrl_ops *ops;
> +       uint32_t pull_ups;
> +       uint32_t pull_downs;
> +       unsigned int irq;
> +       struct pinctrl_gpio_range grange;

Usually we add GPIO ranges from the device tree for device tree
drivers, look at the syntax in:
Documentation/devicetree/bindings/gpio/gpio.txt

git grep gpio-ranges arch/arm/boot/dts/
gives you a few examples.

> +#define gc_to_jzgc(gpiochip) \
> +       container_of(gpiochip, struct ingenic_gpio_chip, gc)

Unless you must have this, please switch to using
struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
and use [devm_]gpiochip_add_data() in the probe so
you can get the data from the gpiochip directly.

> +static void ingenic_gpio_set(struct gpio_chip *gc,
> +               unsigned int offset, int value)
> +{
> +       struct ingenic_gpio_chip *jzgc = gc_to_jzgc(gc);
> +
> +       jzgc->ops->gpio_set_value(jzgc->base, offset, value);
> +}

struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
etc everywhere.

> +static void ingenic_gpio_irq_ack(struct irq_data *irqd)
> +{
> +       struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
> +       struct ingenic_gpio_chip *jzgc = gc_to_jzgc(gc);
> +       unsigned int high;
> +       int irq = irqd->hwirq;
> +
> +       if (irqd_get_trigger_type(irqd) == IRQ_TYPE_EDGE_BOTH) {
> +               /*
> +                * Switch to an interrupt for the opposite edge to the one that
> +                * triggered the interrupt being ACKed.
> +                */
> +               high = jzgc->ops->gpio_get_value(jzgc->base, irq);
> +               if (high)
> +                       jzgc->ops->irq_set_type(jzgc->base, irq,
> +                                       IRQ_TYPE_EDGE_FALLING);
> +               else
> +                       jzgc->ops->irq_set_type(jzgc->base, irq,
> +                                       IRQ_TYPE_EDGE_RISING);

Neat hack. This is often how you have to do it indeed.

> +static int ingenic_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
> +{
> +       struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
> +       struct ingenic_gpio_chip *jzgc = gc_to_jzgc(gc);
> +
> +       switch (type) {
> +       case IRQ_TYPE_EDGE_BOTH:
> +       case IRQ_TYPE_EDGE_RISING:
> +       case IRQ_TYPE_EDGE_FALLING:
> +       case IRQ_TYPE_LEVEL_HIGH:
> +       case IRQ_TYPE_LEVEL_LOW:
> +               break;
> +       default:
> +               pr_err("unsupported external interrupt type\n");

Should you set the irq handlet to handle_bad_irq() in this case?
That's what I usually do.

> +               return -EINVAL;
> +       }
> +
> +       if (type & IRQ_TYPE_EDGE_BOTH)
> +               irq_set_handler_locked(irqd, handle_edge_irq);
> +       else
> +               irq_set_handler_locked(irqd, handle_level_irq);

Nice.

> +       jzgc->ops->irq_set_type(jzgc->base, irqd->hwirq, type);

Getting a bit of feeling that it's a bit much indirection vtable
business going on here, but depends on the series as a whole.

> +static int ingenic_gpio_irq_set_wake(struct irq_data *irqd, unsigned int on)
> +{
> +       struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
> +       struct ingenic_gpio_chip *jzgc = gc_to_jzgc(gc);
> +
> +       return irq_set_irq_wake(jzgc->irq, on);
> +}

I'm uncertain with these. Allright I guess, I'm just too bad at understanding
wakeup IRQs.

> +static void ingenic_gpio_irq_handler(struct irq_desc *desc)
> +{
> +       struct gpio_chip *gc = irq_desc_get_handler_data(desc);
> +       struct ingenic_gpio_chip *jzgc = gc_to_jzgc(gc);
> +       struct irq_chip *irq_chip = irq_data_get_irq_chip(&desc->irq_data);
> +       unsigned long flag, i;
> +
> +       chained_irq_enter(irq_chip, desc);
> +       flag = jzgc->ops->irq_read(jzgc->base);
> +
> +       for_each_set_bit(i, &flag, 32)
> +               generic_handle_irq(irq_linear_revmap(gc->irqdomain, i));
> +       chained_irq_exit(irq_chip, desc);
> +}

Clean & nice.

> +static int ingenic_pinctrl_dt_node_to_map(
> +               struct pinctrl_dev *pctldev, struct device_node *np,
> +               struct pinctrl_map **map, unsigned int *num_maps)
> +{
> +       struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
> +       struct ingenic_pinctrl_func *func;
> +       struct ingenic_pinctrl_group *group;
> +       struct pinctrl_map *new_map;
> +       unsigned int map_num, i;
> +
> +       group = find_group_by_of_node(jzpc, np);
> +       if (!group)
> +               return -EINVAL;
> +
> +       func = find_func_by_of_node(jzpc, of_get_parent(np));
> +       if (!func)
> +               return -EINVAL;
> +
> +       map_num = 1 + group->num_pins;
> +       new_map = devm_kzalloc(jzpc->dev,
> +                               sizeof(*new_map) * map_num, GFP_KERNEL);
> +       if (!new_map)
> +               return -ENOMEM;
> +
> +       new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
> +       new_map[0].data.mux.function = func->name;
> +       new_map[0].data.mux.group = group->name;
> +
> +       for (i = 0; i < group->num_pins; i++) {
> +               new_map[i + 1].type = PIN_MAP_TYPE_CONFIGS_PIN;
> +               new_map[i + 1].data.configs.group_or_pin =
> +                       jzpc->pdesc[group->pins[i].idx].name;
> +               new_map[i + 1].data.configs.configs = group->pins[i].configs;
> +               new_map[i + 1].data.configs.num_configs =
> +                       group->pins[i].num_configs;
> +       }
> +
> +       *map = new_map;
> +       *num_maps = map_num;
> +       return 0;
> +}

This may change due to DT bindings reviews. I would prefer if you use
generic functions.

> +static int ingenic_pinctrl_parse_dt_gpio(struct ingenic_pinctrl *jzpc,
> +               struct ingenic_gpio_chip *jzgc, struct device_node *np)

Naming here: parse or probe or init. This function is certainly not just
parsing the DT. init() or probe() is better.

> +       jzgc->gc.base = jzpc->base + (jzgc->idx * PINS_PER_GPIO_PORT);

No. No hard-coded GPIO bases on new GPIO driver.
Set this to -1 so it uses dynamic allocation of GPIO numbers.

> +       if (of_property_read_u32_index(np, "ingenic,pull-ups", 0,
> +                               &jzgc->pull_ups))
> +               jzgc->pull_ups = 0;
> +       if (of_property_read_u32_index(np, "ingenic,pull-downs", 0,
> +                               &jzgc->pull_downs))
> +               jzgc->pull_downs = 0;
> +
> +       if (jzgc->pull_ups & jzgc->pull_downs) {
> +               dev_err(jzpc->dev, "GPIO port %c has overlapping pull ups & pull downs\n",
> +                       'A' + jzgc->idx);
> +               return -EINVAL;
> +       }

These bindings look suspicious. But I will review them in the binding
document.

> +static int ingenic_pinctrl_parse_dt_pincfg(struct ingenic_pinctrl *jzpc,
> +               struct ingenic_pinctrl_pin *pin, phandle cfg_handle)
> +{
> +       struct device_node *cfg_node;
> +       int err;
> +
> +       cfg_node = of_find_node_by_phandle(cfg_handle);
> +       if (!cfg_node)
> +               return -EINVAL;
> +
> +       err = pinconf_generic_parse_dt_config(cfg_node, NULL,
> +                       &pin->configs, &pin->num_configs);
> +       if (err)
> +               return err;
> +
> +       err = devm_add_action(jzpc->dev, (void (*)(void *))kfree, pin->configs);

That looks very clever.

But when we have pinctrl_utils_free_map() and other helpers already
this free:ing looks like some reinvented wheel.

Can we create something that free:s the maps from
pinctrl_utils_reserve_map() in a similar way and use that?
Just thinking aloud.

> +static int ingenic_pinctrl_parse_dt_func(struct ingenic_pinctrl *jzpc,
> +               struct device_node *np, unsigned int *ifunc,
> +               unsigned int *igroup)
> +{
> +       struct ingenic_pinctrl_func *func;
> +       struct ingenic_pinctrl_group *grp;
> +       struct device_node *group_node, *gpio_node;
> +       struct gpio_chip *gpio_chip;
> +       phandle gpio_handle, cfg_handle;
> +       struct property *pp;
> +       __be32 *plist;
> +       unsigned int i, j;
> +       int err;
> +       const unsigned int vals_per_pin = 4;
> +
> +       func = &jzpc->funcs[(*ifunc)++];
> +       func->of_node = np;
> +       func->name = np->name;
> +
> +       func->num_groups = of_get_child_count(np);
> +       func->groups = devm_kzalloc(jzpc->dev, sizeof(*func->groups) *
> +                       func->num_groups, GFP_KERNEL);
> +       func->group_names = devm_kzalloc(jzpc->dev,
> +                       sizeof(*func->group_names) * func->num_groups,
> +                       GFP_KERNEL);
> +       if (!func->groups || !func->group_names)
> +               return -ENOMEM;
> +
> +       i = 0;
> +       for_each_child_of_node(np, group_node) {
> +               pp = of_find_property(group_node, "ingenic,pins", NULL);
> +               if (!pp)
> +                       return -EINVAL;
> +               if ((pp->length / sizeof(__be32)) % vals_per_pin)
> +                       return -EINVAL;
> +
> +               grp = &jzpc->groups[(*igroup)++];
> +               grp->of_node = group_node;
> +               grp->name = group_node->name;
> +               grp->num_pins = (pp->length / sizeof(__be32)) / vals_per_pin;
> +               grp->pins = devm_kzalloc(jzpc->dev, sizeof(*grp->pins) *
> +                               grp->num_pins, GFP_KERNEL);
> +               grp->pin_indices = devm_kzalloc(jzpc->dev,
> +                               sizeof(*grp->pin_indices) * grp->num_pins,
> +                               GFP_KERNEL);
> +               if (!grp->pins)
> +                       return -EINVAL;
> +
> +               plist = pp->value;
> +               for (j = 0; j < grp->num_pins; j++) {
> +                       gpio_handle = be32_to_cpup(plist++);
> +                       grp->pins[j].idx = be32_to_cpup(plist++);
> +                       grp->pins[j].func = be32_to_cpup(plist++);
> +                       cfg_handle = be32_to_cpup(plist++);
> +
> +                       gpio_node = of_find_node_by_phandle(gpio_handle);
> +                       if (!gpio_node)
> +                               return -EINVAL;
> +
> +                       gpio_chip = gpiochip_find(gpio_node,
> +                                       find_gpio_chip_by_of_node);
> +                       if (!gpio_chip)
> +                               return -EINVAL;
> +
> +                       grp->pins[j].gpio_chip = gc_to_jzgc(gpio_chip);
> +
> +                       err = ingenic_pinctrl_parse_dt_pincfg(jzpc,
> +                                       &grp->pins[j], cfg_handle);
> +                       if (err)
> +                               return err;
> +
> +                       grp->pins[j].idx += grp->pins[j].gpio_chip->idx *
> +                               PINS_PER_GPIO_PORT;
> +                       grp->pin_indices[j] = grp->pins[j].idx;
> +               }
> +
> +               func->groups[i] = grp;
> +               func->group_names[i] = grp->name;
> +               i++;
> +       }
> +
> +       return 0;
> +}

Tony Lindgren has added generic function and group parsing for drivers
that keep functions and groups in the device tree. This code is committed
and available in the pinctrl git tree.

Look at commits:
commit c7059c5ac70aea194b07b2d811df433eb0ca81b5
pinctrl: core: Add generic pinctrl functions for managing groups
commit a76edc89b100e4fefb2a5c00cd8cd557437659e7
pinctrl: core: Add generic pinctrl functions for managing groups
commit caeb774ea3b1bc25dc2f24681c27543aba6ca7ae
pinctrl: single: Use generic pinctrl helpers for managing groups
commit 571aec4df5b72a80f80d1e524da8fbd7ff525c98
pinctrl: single: Use generic pinmux helpers for managing functions
commit 3fd6d6ad73af90522321451a2d10b0a8967d47d1
pinctrl: imx: use generic pinmux helpers for managing functions

So two drivers already switch to generic code handling this.

Please investigate and try out the above.

> +int ingenic_pinctrl_probe(struct platform_device *pdev,
> +               const struct ingenic_pinctrl_ops *ops)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct ingenic_pinctrl *jzpc;
> +       struct ingenic_gpio_chip *jzgc;
> +       struct pinctrl_desc *pctl_desc;
> +       struct device_node *np, *chips_node, *functions_node;
> +       unsigned int i, j;
> +       int err;
> +
> +       if (!dev->of_node) {
> +               dev_err(dev, "device tree node not found\n");
> +               return -ENODEV;
> +       }

I think this check is not necessary since you only probe from device tree.
We usually skip it these days.

> +       jzpc->base = 0;
> +       of_property_read_u32(dev->of_node, "base", &jzpc->base);

If this is the Linux GPIO number base then NACK, we don't define
Linux-specific things in the device tree.

Please use dynamic allocation of GPIO base anyways, as stated
above.

> +       chips_node = of_find_node_by_name(dev->of_node, "gpio-chips");

This looks like a very dubious new DT bindings. Will review in that
document.

> +       jzpc->num_gpio_chips = of_get_available_child_count(chips_node);
> +       if (!jzpc->num_gpio_chips) {
> +               dev_err(dev, "No GPIO chips found\n");
> +               return -EINVAL;
> +       }

Usually it is better to create one device per gpiochip.

> +       /* register pinctrl GPIO ranges */
> +       for (i = 0; i < jzpc->num_gpio_chips; i++) {
> +               jzgc = &jzpc->gpio_chips[i];
> +
> +               jzgc->grange.name = jzgc->name;
> +               jzgc->grange.id = jzgc->idx;
> +               jzgc->grange.pin_base = jzgc->idx * PINS_PER_GPIO_PORT;
> +               jzgc->grange.base = jzgc->gc.base;
> +               jzgc->grange.npins = jzgc->gc.ngpio;
> +               jzgc->grange.gc = &jzgc->gc;
> +               pinctrl_add_gpio_range(jzpc->pctl, &jzgc->grange);
> +       }

I strongly recommend defining the GPIO ranges in the device tree
and if not possible, to add the GPIO range from the gpiochip
side and not the pinctrl side.

> +struct ingenic_pinctrl_ops {
> +       unsigned int nb_functions;
> +
> +       void (*set_function)(void __iomem *base,
> +                       unsigned int offset, unsigned int function);
> +       void (*set_gpio)(void __iomem *base, unsigned int offset, bool output);
> +       int  (*get_bias)(void __iomem *base, unsigned int offset);
> +       void (*set_bias)(void __iomem *base, unsigned int offset, bool enable);
> +       void (*gpio_set_value)(void __iomem *base,
> +                       unsigned int offset, int value);
> +       int  (*gpio_get_value)(void __iomem *base, unsigned int offset);
> +       u32  (*irq_read)(void __iomem *base);
> +       void (*irq_mask)(void __iomem *base, unsigned int irq, bool mask);
> +       void (*irq_ack)(void __iomem *base, unsigned int irq);
> +       void (*irq_set_type)(void __iomem *base,
> +                       unsigned int irq, unsigned int type);
> +};

This is a *lot* of vtable indirections. Are you sure this is a good
idea?

> +static void jz4740_set_gpio(void __iomem *base,
> +               unsigned int offset, bool output)
> +{
> +       writel(1 << offset, base + GPIO_FUNCC);
> +       writel(1 << offset, base + GPIO_SELECTC);
> +       writel(1 << offset, base + GPIO_TRIGC);
> +
> +       if (output)
> +               writel(1 << offset, base + GPIO_DIRS);
> +       else
> +               writel(1 << offset, base + GPIO_DIRC);
> +}

Replace all (1 << offset) things with:

#include <linux/bitops.h>

BIT(offset)

Simple and clean.

> +static int jz4740_get_bias(void __iomem *base, unsigned int offset)
> +{
> +       return !((readl(base + GPIO_PULL_DIS) >> offset) & 0x1);
> +}

Similarly:
return !((readl(base + GPIO_PULL_DIR) & BIT(offset));

Follow these patterns everywhere.

> +static int jz4740_gpio_get_value(void __iomem *base, unsigned int offset)
> +{
> +       return (readl(base + GPIO_DATA) >> offset) & 0x1;
> +}

return !!(readl(base + GPIO_DATA) & BIT(offset));

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH 01/13] Documentation: dt/bindings: Document pinctrl-ingenic
  2017-01-17 23:14 ` [PATCH 01/13] Documentation: dt/bindings: Document pinctrl-ingenic Paul Cercueil
@ 2017-01-18 23:45   ` Linus Walleij
  0 siblings, 0 replies; 162+ messages in thread
From: Linus Walleij @ 2017-01-18 23:45 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

On Wed, Jan 18, 2017 at 12:14 AM, Paul Cercueil <paul@crapouillou.net> wrote:

> From: Paul Burton <paul.burton@imgtec.com>
>
> This commit adds documentation for the devicetree bidings of the
> pinctrl-ingenic driver, which handles pin configuration, pin muxing
> and GPIOs of the Ingenic SoCs currently supported by the Linux kernel.
>
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>

(...)

> +##### 'gpio-chips' sub-node #####
> +
> +The gpio-chips node will contain sub-nodes that correspond to GPIO controllers
> +(one sub-node per GPIO controller).
> +
> +Required properties:
> +- #address-cells: Should contain the integer 1.
> +- #size-cells: Should contain the integer 1.
> +- ranges: Should be empty.

I do not see why the GPIO needs a special subnode. Can the pin controller
and the GPIO not simply spawn from a single node?

> +##### GPIO controller node #####
> +
> +Each subnode of the 'gpio-chips' node is a GPIO controller node.
> +
> +Required properties:
> +- gpio-controller: Identifies this node as a GPIO controller.
> +- #gpio-cells: Should contain the integer 2.
> +- reg: Should contain the physical address and length of the GPIO controller's
> +  configuration registers.
> +
> +Optional properties:
> +- interrupt-controller: The GPIO controllers can optionally configure the
> +  GPIOs as interrupt sources. In this case, the 'interrupt-controller'
> +  standalone property should be supplied.
> +- #interrupt-cells: Required if 'interrupt-controller' is also specified.
> +  In that case, it should contain the integer 2.
> +- interrupts: Required if 'interrupt-controller' is also specified.
> +  In that case, it should contain the IRQ number of this GPIO controller.
> +- ingenic,pull-ups: A bit mask identifying the pins associated with this GPIO
> +  port which feature a pull-up resistor. The default mask is 0x0.
> +- ingenic,pull-downs: A bit mask identifying the pins associated with this GPIO
> +  port which feature a pull-down resistor. The default mask is 0x0.

So these bits tell us which lines have a pull up and pull down resistor?

Isn't that readily know from the compatible string? Then just hardcode
that into the driver for each variant, there is no need to define that in
the device tree.

> +##### Pin function node #####
> +
> +Each subnode of the 'functions' node is a pin function node.
> +
> +These subnodes represent a functionality of the SoC which may be exposed
> +through one or more groups of pins, represented as subnodes of the pin
> +function node. For example a function may be uart0, which may be exposed
> +through the group of pins PF0 to PF3.
> +
> +Required pin function node properties:
> +- None.
> +
> +
> +##### Pin group node #####
> +
> +Each subnode of a pin function node is a pin group node.
> +
> +Required pin group node properties:
> +- ingenic,pins: A set of values representing the pins within this pin group and
> +  their configuration.

Look into using the standard pins property from the pinctrl bindings
if yoy want to do this.

> Four values should be provided for each pin:
> +  - The phandle of the GPIO controller node for the GPIO port within which the
> +    pin is found.
> +  - The index of the pin within its GPIO port (an integer in the range 0 to 31
> +    inclusive).

This is already supported by gpio ranges, please do not reimplement
stuff we already have.

> +  - The index of the shared function port to be programmed in the GPIO port
> +    registers for this pin.

I don't see why this can not be stored in the driver.
But some people prefer to shovel everything into the device
tree, I don't know. Can you elaborate why this should be in the
device tree?

> +  - The phandle of a pin configuration node specifying the electrical
> +    configuration that should be applied to the pin.

Why? This is something the standard pin control states handles.
I'm confused.

> +For example the function 'msc0' may be exposed through 2 different pin groups,
> +one in GPIO port A and one in GPIO port E:
> +
> +  bias-configs {
> +    nobias: nobias {
> +      bias-disable;
> +    };
> +  };
> +
> +  functions {
> +    pinfunc_msc0: msc0 {
> +      pins_msc0_pa: msc0-pa {
> +        ingenic,pins = <&gpa  4 1 &nobias   /* d4 */
> +                        &gpa  5 1 &nobias   /* d5 */
> +                        &gpa  6 1 &nobias   /* d6 */
> +                        &gpa  7 1 &nobias   /* d7 */
> +                        &gpa 18 1 &nobias   /* clk */
> +                        &gpa 19 1 &nobias   /* cmd */
> +                        &gpa 20 1 &nobias   /* d0 */
> +                        &gpa 21 1 &nobias   /* d1 */
> +                        &gpa 22 1 &nobias   /* d2 */
> +                        &gpa 23 1 &nobias   /* d3 */
> +                        &gpa 24 1 &nobias>; /* rst */
> +      };

Please look at other bindings and drivers and read pinctrl.txt
closely. This makes no sense to me compared to other
examples.

This is something that seems to cross-mix gpio ranges
and pin config, that doesn't work for me, we can't have an
idiomatic binding like this. I understand that it may fit your
single usecase perfectly but it will be a maintenance nightmare
for me.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH 05/13] MIPS: jz4740: DTS: Add node for the jz4740-pinctrl driver
  2017-01-17 23:14 ` [PATCH 05/13] MIPS: jz4740: DTS: Add node for the jz4740-pinctrl driver Paul Cercueil
@ 2017-01-18 23:50   ` Linus Walleij
  0 siblings, 0 replies; 162+ messages in thread
From: Linus Walleij @ 2017-01-18 23:50 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

On Wed, Jan 18, 2017 at 12:14 AM, Paul Cercueil <paul@crapouillou.net> wrote:

> For a description of the devicetree node, please read
> Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
>
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>

(...)

> +       pinctrl: ingenic-pinctrl@10010000 {
> +               compatible = "ingenic,jz4740-pinctrl";
> +               #address-cells = <1>;
> +               #size-cells = <1>;
> +               ranges;
> +
> +               gpio-chips {
> +                       #address-cells = <1>;
> +                       #size-cells = <1>;
> +                       ranges;
> +
> +                       gpa: gpa {
> +                               reg = <0x10010000 0x100>;
> +
> +                               gpio-controller;
> +                               #gpio-cells = <2>;
> +
> +                               interrupt-controller;
> +                               #interrupt-cells = <2>;
> +
> +                               interrupt-parent = <&intc>;
> +                               interrupts = <28>;
> +
> +                               ingenic,pull-ups = <0xffffffff>;
> +                       };
> +
> +                       gpb: gpb {
> +                               reg = <0x10010100 0x100>;
> +
> +                               gpio-controller;
> +                               #gpio-cells = <2>;
> +
> +                               interrupt-controller;
> +                               #interrupt-cells = <2>;
> +
> +                               interrupt-parent = <&intc>;
> +                               interrupts = <27>;
> +
> +                               ingenic,pull-ups = <0xffffffff>;
> +                       };
> +
> +                       gpc: gpc {
> +                               reg = <0x10010200 0x100>;
> +
> +                               gpio-controller;
> +                               #gpio-cells = <2>;
> +
> +                               interrupt-controller;
> +                               #interrupt-cells = <2>;
> +
> +                               interrupt-parent = <&intc>;
> +                               interrupts = <26>;
> +
> +                               ingenic,pull-ups = <0xffffffff>;
> +                       };
> +
> +                       gpd: gpd {
> +                               reg = <0x10010300 0x100>;
> +
> +                               gpio-controller;
> +                               #gpio-cells = <2>;
> +
> +                               interrupt-controller;
> +                               #interrupt-cells = <2>;
> +
> +                               interrupt-parent = <&intc>;
> +                               interrupts = <25>;
> +
> +                               ingenic,pull-ups = <0xdfffffff>;
> +                       };
> +               };

Just pull all these down two levels and make them one device
each instead of having them inside the pin controller node
like this.

Then make a pin controller node separately, it can reference the
pin controller by phandles if necessary, and use the standard
gpio-ranges property to cross make GPIO and pin control.

It seems you driver is similar to for example the
drivers/pinctrl/nomadik/* pin controller.

Look in arch/arm/boot/dts/ste-dbx500.dtsi for examples,
NB: I'm not fully using standard bindings in it, because they
were not invented at the time.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver
  2017-01-17 23:14 [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                   ` (13 preceding siblings ...)
  2017-01-18  7:15 ` [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver Thierry Reding
@ 2017-01-19  6:38 ` Linus Walleij
  14 siblings, 0 replies; 162+ messages in thread
From: Linus Walleij @ 2017-01-19  6:38 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

On Wed, Jan 18, 2017 at 12:14 AM, Paul Cercueil <paul@crapouillou.net> wrote:

> One problem still unresolved: the pinctrl framework does not allow us to
> configure each pin on demand (someone please prove me wrong), when the
> various PWM channels are requested or released. For instance, the PWM
> channels can be configured from sysfs, which would require all PWM pins
> to be configured properly beforehand for the PWM function, eventually
> causing conflicts with other platform or board drivers.

Why do you think this?

- Pincontrol handles can be obtained at runtime.
- Pincontrol states can be changed at runtime.

The fact that a the handle is retrived by the device core and set to
the states named "init" or "default" during boot is just a convenience.

You can have as many and as fine-grained states as you want. They
can pertain to just one pin too.

Linus Walleij

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH 13/13] MIPS: jz4740: Remove custom GPIO code
  2017-01-17 23:14 ` [PATCH 13/13] MIPS: jz4740: Remove custom GPIO code Paul Cercueil
  2017-01-18  7:27   ` Thierry Reding
@ 2017-01-19  9:07   ` Linus Walleij
  2017-01-20 10:01     ` Paul Cercueil
  1 sibling, 1 reply; 162+ messages in thread
From: Linus Walleij @ 2017-01-19  9:07 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

On Wed, Jan 18, 2017 at 12:14 AM, Paul Cercueil <paul@crapouillou.net> wrote:

> All the drivers for the various hardware elements of the jz4740 SoC have
> been modified to use the pinctrl framework for their pin configuration
> needs.
> As such, this platform code is now unused and can be deleted.
>
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>

I feel I might have come across as a bit harsh in the previous review of the
patches leading up to this one. In that case I'm sorry.

I can clearly see that the intent of the series is to remove this hopelessly
idiomatic code from the MIPS hurdle, and move these systems over
to standard frameworks.

In a way, if I look at the kernel as a whole, it would likely look better
after these patches were merged, than before. Even with the
shortcomings I painted out in the previous review comments.

A very complicated piece of messy code is cut from MIPS.

I think this is very valuable work and well worth persuing, so please
go ahead and work with the series, your effort is very much appreciated!

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH 09/13] mmc: jz4740: Let the pinctrl driver configure the pins
  2017-01-17 23:14 ` [PATCH 09/13] mmc: jz4740: Let the pinctrl driver configure the pins Paul Cercueil
@ 2017-01-19 10:55   ` Ulf Hansson
  2017-01-20 11:59     ` Paul Cercueil
  0 siblings, 1 reply; 162+ messages in thread
From: Ulf Hansson @ 2017-01-19 10:55 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, Linux Fbdev development list, James Hogan

[...]

>
> -#ifdef CONFIG_PM_SLEEP
> -
> -static int jz4740_mmc_suspend(struct device *dev)
> -{
> -       struct jz4740_mmc_host *host = dev_get_drvdata(dev);
> -
> -       jz_gpio_bulk_suspend(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
> -

Shouldn't this be replaced with a call to:
pinctrl_pm_select_sleep_state();

> -       return 0;
> -}
> -
> -static int jz4740_mmc_resume(struct device *dev)
> -{
> -       struct jz4740_mmc_host *host = dev_get_drvdata(dev);
> -
> -       jz_gpio_bulk_resume(jz4740_mmc_pins, jz4740_mmc_num_pins(host));

Shouldn't this be replaced with a call to:
pinctrl_pm_select_default_state();

[...]

Kind regards
Uffe

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver
  2017-01-18  7:15 ` [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver Thierry Reding
@ 2017-01-19 11:19   ` Paul Cercueil
  2017-01-20  8:40     ` Linus Walleij
                       ` (2 more replies)
  0 siblings, 3 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-19 11:19 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan

Le 2017-01-18 08:15, Thierry Reding a écrit :

> On Wed, Jan 18, 2017 at 12:14:08AM +0100, Paul Cercueil wrote:
> [...]
> 
>> One problem still unresolved: the pinctrl framework does not allow us 
>> to configure each pin on demand (someone please prove me wrong), when 
>> the various PWM channels are requested or released. For instance, the 
>> PWM channels can be configured from sysfs, which would require all PWM 
>> pins to be configured properly beforehand for the PWM function, 
>> eventually causing conflicts with other platform or board drivers.
> 
> Still catching up on a lot of email, so I haven't gone through the
> entire series. But I don't think the above is true.
> 
> My understanding is that you can have separate pin groups for each
> pin (provided the hardware supports that) and then control each of
> these groups dynamically at runtime.
> 
> That is you could have the PWM driver's ->request() and ->free()
> call into the pinctrl framework to select the correct pinmux
> configuration as necessary.

Thanks for the feedback.

The problem with pinctrl and PWM, is that the pinctrl API works by 
"states".
A default state, sleep state, and basically any custom state that the 
devicetree
provides. This works well until you need to control individually each 
pin; with
8 pins, you would need 2^8 states, each one corresponding to a given 
configuration.

-Paul

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH 13/13] MIPS: jz4740: Remove custom GPIO code
  2017-01-18  7:27   ` Thierry Reding
@ 2017-01-19 11:24     ` Paul Cercueil
  0 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-19 11:24 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Ralf Baechle, Linus Walleij, Rob Herring, Mark Rutland,
	Ulf Hansson, Boris Brezillon, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan

Le 2017-01-18 08:27, Thierry Reding a écrit :

> On Wed, Jan 18, 2017 at 12:14:21AM +0100, Paul Cercueil wrote:
> 
>> All the drivers for the various hardware elements of the jz4740 SoC 
>> have been modified to use the pinctrl framework for their pin 
>> configuration needs. As such, this platform code is now unused and can 
>> be deleted. Signed-off-by: Paul Cercueil <paul@crapouillou.net> --- 
>> arch/mips/include/asm/mach-jz4740/gpio.h | 371 ---------------------- 
>> arch/mips/jz4740/Makefile | 2 - arch/mips/jz4740/gpio.c | 519 
>> ------------------------------- 3 files changed, 892 deletions(-) 
>> delete mode 100644 arch/mips/jz4740/gpio.c
> 
> Have you considered how this could best be merged? It's probably 
> easiest
> to take all of this through the MIPS tree because we have an addition 
> of
> the pinctrl that would be a replacement for the GPIO code, while at the
> same time a bunch of drivers rely on the JZ4740 GPIO code for 
> successful
> compilation.
> 
> That's slightly complicated by the number of drivers, so needs a lot of
> coordination, but it's not the worst I've seen.
> 
> Maybe one other solution that would make the transition easier would be
> to stub out the GPIO functions if the pinctrl driver is enabled, and do
> the removal of the mach-jz4740/gpio.h after all drivers have been 
> merged
> through their corresponding subsystem trees. That way all drivers 
> should
> remain compilable and functional at runtime, while still having the
> possibility to merge through the subsystem trees.
> 
> That said, the whole series is fairly simple, so merging everything
> through the MIPS tree sounds like the easiest way to go.
> 
> Thierry

I think it would make sense to merge it through the MIPS tree, yes,
considering that the patches for the drivers in the other subsystems are
quite small, and that they just remove code (well, except the pinctrl
driver itself). Besides, the files modified are not touched very often
so the chances of breakage are pretty low.

-Paul

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver
  2017-01-19 11:19   ` Paul Cercueil
@ 2017-01-20  8:40     ` Linus Walleij
  2017-01-20 10:17       ` Paul Cercueil
  2017-01-22 14:49     ` [PATCH v2 00/14] " Paul Cercueil
  2017-01-25 18:51     ` [PATCH v3 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
  2 siblings, 1 reply; 162+ messages in thread
From: Linus Walleij @ 2017-01-20  8:40 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Thierry Reding, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

On Thu, Jan 19, 2017 at 12:19 PM, Paul Cercueil <paul@crapouillou.net> wrote:

> The problem with pinctrl and PWM, is that the pinctrl API works by "states".
> A default state, sleep state, and basically any custom state that the
> devicetree
> provides. This works well until you need to control individually each pin;
> with
> 8 pins, you would need 2^8 states, each one corresponding to a given
> configuration.

I do not really understand, do you really use all 2^8 states in a given
system?

The pin control states are to be used for practical situations, not
for all theoretical situations.

You should define in your device tree the states that your
particular system will use. Not all possible states on all possible
systems.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH 13/13] MIPS: jz4740: Remove custom GPIO code
  2017-01-19  9:07   ` Linus Walleij
@ 2017-01-20 10:01     ` Paul Cercueil
  0 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-20 10:01 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

Le 2017-01-19 10:07, Linus Walleij a écrit :

> On Wed, Jan 18, 2017 at 12:14 AM, Paul Cercueil <paul@crapouillou.net> 
> wrote:
> 
>> All the drivers for the various hardware elements of the jz4740 SoC 
>> have been modified to use the pinctrl framework for their pin 
>> configuration needs. As such, this platform code is now unused and can 
>> be deleted. Signed-off-by: Paul Cercueil <paul@crapouillou.net>
> 
> I feel I might have come across as a bit harsh in the previous review 
> of the
> patches leading up to this one. In that case I'm sorry.
> 
> I can clearly see that the intent of the series is to remove this 
> hopelessly
> idiomatic code from the MIPS hurdle, and move these systems over
> to standard frameworks.
> 
> In a way, if I look at the kernel as a whole, it would likely look 
> better
> after these patches were merged, than before. Even with the
> shortcomings I painted out in the previous review comments.
> 
> A very complicated piece of messy code is cut from MIPS.
> 
> I think this is very valuable work and well worth persuing, so please
> go ahead and work with the series, your effort is very much 
> appreciated!
> 
> Yours,
> Linus Walleij

Well thank you for your very constructive criticism ;) And for your 
review.
I'll submit a v2 very soon - I don't want to miss the 4.11 merge.

Regards,
-Paul

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH 00/13] Ingenic JZ4740 / JZ4780 pinctrl driver
  2017-01-20  8:40     ` Linus Walleij
@ 2017-01-20 10:17       ` Paul Cercueil
  0 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-20 10:17 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Thierry Reding, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

Le 2017-01-20 09:40, Linus Walleij a écrit :

> On Thu, Jan 19, 2017 at 12:19 PM, Paul Cercueil <paul@crapouillou.net> 
> wrote:
> 
>> The problem with pinctrl and PWM, is that the pinctrl API works by 
>> "states". A default state, sleep state, and basically any custom state 
>> that the devicetree provides. This works well until you need to 
>> control individually each pin; with 8 pins, you would need 2^8 states, 
>> each one corresponding to a given configuration.
> 
> I do not really understand, do you really use all 2^8 states in a given
> system?
> 
> The pin control states are to be used for practical situations, not
> for all theoretical situations.
> 
> You should define in your device tree the states that your
> particular system will use. Not all possible states on all possible
> systems.
> 

Well, that was if I wanted to dynamically set/unset the pin mux and
configuration when requesting/freeing a PWM. Then I'd need 2^x states
for X PWM pins.

Anyway, a static configuration works for me too. If at some point I
want dynamic configuration of the pins then I'll make the PWM driver
handle only one PWM pin and create one driver instance for each pin.

Regards,
-Paul

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH 09/13] mmc: jz4740: Let the pinctrl driver configure the  pins
  2017-01-19 10:55   ` Ulf Hansson
@ 2017-01-20 11:59     ` Paul Cercueil
  0 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-20 11:59 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, Linux Fbdev development list, James Hogan

Le 2017-01-19 11:55, Ulf Hansson a écrit :

> Shouldn't this be replaced with a call to:
> pinctrl_pm_select_sleep_state();

You're totally right. I'll change it.

Thanks,
-Paul

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v2 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver
  2017-01-19 11:19   ` Paul Cercueil
  2017-01-20  8:40     ` Linus Walleij
@ 2017-01-22 14:49     ` Paul Cercueil
  2017-01-22 14:49       ` [PATCH v2 01/14] Documentation: dt/bindings: Document pinctrl-ingenic Paul Cercueil
                         ` (13 more replies)
  2017-01-25 18:51     ` [PATCH v3 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
  2 siblings, 14 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-22 14:49 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan

Hi,

This is the v2 of my ingenic pinctrl patch series.
Huge changes in there, the pinctrl driver was completely rewritten, and the
GPIO code was split into a separate driver.

It now uses the generic functions to handle pin groups, as well as generic
devicetree bindings.

Best regards,
- Paul

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v2 01/14] Documentation: dt/bindings: Document pinctrl-ingenic
  2017-01-22 14:49     ` [PATCH v2 00/14] " Paul Cercueil
@ 2017-01-22 14:49       ` Paul Cercueil
  2017-01-27 11:18         ` Linus Walleij
  2017-01-22 14:49       ` [PATCH v2 02/14] Documentation: dt/bindings: Document pinctrl-gpio Paul Cercueil
                         ` (12 subsequent siblings)
  13 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-01-22 14:49 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

This commit adds documentation for the devicetree bidings of the
pinctrl-ingenic driver, which handles pin configuration and pin
muxing of the Ingenic SoCs currently supported by the Linux kernel.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 .../bindings/pinctrl/ingenic,pinctrl.txt           | 77 ++++++++++++++++++++++
 1 file changed, 77 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt

v2: Rewrote the documentation for the new pinctrl-ingenic driver

diff --git a/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
new file mode 100644
index 000000000000..ead5b01ad471
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
@@ -0,0 +1,77 @@
+Ingenic jz47xx pin controller
+
+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".
+
+For the jz47xx SoCs, pin control is tightly bound with GPIO ports. All pins may
+be used as GPIOs, multiplexed device functions are configured within the
+GPIO port configuration registers and it is typical to refer to pins using the
+naming scheme "PxN" where x is a character identifying the GPIO port with
+which the pin is associated and N is an integer from 0 to 31 identifying the
+pin within that GPIO port. For example PA0 is the first pin in GPIO port A, and
+PB31 is the last pin in GPIO port B. The jz4740 contains 4 GPIO ports, PA to
+PD, for a total of 128 pins. The jz4780 contains 6 GPIO ports, PA to PF, for a
+total of 192 pins.
+
+
+Pin controller node
+===================
+
+Required properties:
+- compatible: One of:
+  - "ingenic,jz4740-pinctrl"
+  - "ingenic,jz4780-pinctrl"
+
+Optional properties:
+- ingenic,pull-ups: A list of 32-bit bit fields, where each bit set tells the
+  driver that a pull-up resistor is available for this pin.
+  By default, the driver considers that all pins feature a pull-up resistor.
+- ingenic,pull-downs: A list of 32-bit bit fields, where each bit set tells
+  the driver that a pull-down resistor is available for this pin.
+  By default, the driver considers that all pins feature a pull-down
+  resistor.
+
+
+'functions' sub-node
+====================
+
+The 'functions' node will contain sub-nodes that correspond to pin function
+nodes, and no properties. Pin function nodes will contain sub-nodes that
+correspond to pin groups, and no properties.
+
+The names of the pin function nodes will end up being the available functions
+provided by the pinctrl driver.
+The names of the pin group nodes will end up being the available groups
+provided by the pinctrl driver.
+
+Required properties for pin groups:
+- ingenic,pins: <pin mode [pin mode ...]>;
+  where 'pin' is the number of the pin, and 'mode' is the function mode of the
+  pin that should be enabled for this group.
+
+
+Example:
+=======
+
+pinctrl: ingenic-pinctrl@10010000 {
+	compatible = "ingenic,jz4740-pinctrl";
+	reg = <0x10010000 0x400>;
+
+	ingenic,pull-ups   = <0xffffffff 0xffffffff 0xffffffff 0xdfffffff>;
+	ingenic,pull-downs = <0x00000000 0x00000000 0x00000000 0x00000000>;
+
+	functions {
+		mmc {
+			mmc-1bit {
+				/* CLK, CMD, D0 */
+				ingenic,pins = <0x69 0 0x68 0 0x6a 0>;
+			};
+
+			mmc-4bit {
+				/* D1, D2, D3 */
+				ingenic,pins = <0x6b 0 0x6c 0 0x6d 0>;
+			};
+		};
+	};
+};
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v2 02/14] Documentation: dt/bindings: Document pinctrl-gpio
  2017-01-22 14:49     ` [PATCH v2 00/14] " Paul Cercueil
  2017-01-22 14:49       ` [PATCH v2 01/14] Documentation: dt/bindings: Document pinctrl-ingenic Paul Cercueil
@ 2017-01-22 14:49       ` Paul Cercueil
  2017-01-22 14:49       ` [PATCH v2 03/14] pinctrl-ingenic: add a pinctrl driver for the Ingenic jz47xx SoCs Paul Cercueil
                         ` (11 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-22 14:49 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

This commit adds documentation for the devicetree bidings of the
pinctrl-gpio driver, which handles GPIOs of the Ingenic SoCs
currently supported by the Linux kernel.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 .../devicetree/bindings/gpio/ingenic,gpio.txt      | 45 ++++++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/gpio/ingenic,gpio.txt

v2: New patch

diff --git a/Documentation/devicetree/bindings/gpio/ingenic,gpio.txt b/Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
new file mode 100644
index 000000000000..b2eb20494365
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
@@ -0,0 +1,45 @@
+Ingenic jz47xx GPIO controller
+
+Required properties:
+  - compatible:
+    - "ingenic,jz4740-gpio" for the JZ4740 SoC
+    - "ingenic,jz4780-gpio" for the JZ4780 SoC
+
+  - reg: Base address and length of each memory resource used by the GPIO
+    controller hardware module.
+
+  - gpio-controller: Marks the device node as a GPIO controller.
+  - #gpio-cells: Should be 2. The first cell is the GPIO number and the second
+    cell specifies GPIO flags, as defined in <dt-bindings/gpio/gpio.h>. Only the
+    GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported.
+  - gpio-ranges: Range of pins managed by the GPIO controller.
+
+Optional properties:
+  - base: The GPIO number to use as the base for this driver.
+  - interrupt-controller: Marks the device node as an interrupt controller.
+  - interrupts: Interrupt specifier for the controllers interrupt.
+    Required if 'interrupt-controller' is specified.
+
+Please refer to gpio.txt in this directory for details of gpio-ranges property
+and the common GPIO bindings used by client devices.
+
+The GPIO controller also acts as an interrupt controller. It uses the default
+two cells specifier as described in Documentation/devicetree/bindings/
+interrupt-controller/interrupts.txt.
+
+Example:
+
+gpa: gpio-controller@10010000 {
+	compatible = "ingenic,jz4740-gpio";
+	reg = <0x10010000 0x100>;
+
+	gpio-controller;
+	gpio-ranges = <&pinctrl 0 0 32>;
+	#gpio-cells = <2>;
+
+	interrupt-controller;
+	#interrupt-cells = <2>;
+
+	interrupt-parent = <&intc>;
+	interrupts = <28>;
+};
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v2 03/14] pinctrl-ingenic: add a pinctrl driver for the Ingenic jz47xx SoCs
  2017-01-22 14:49     ` [PATCH v2 00/14] " Paul Cercueil
  2017-01-22 14:49       ` [PATCH v2 01/14] Documentation: dt/bindings: Document pinctrl-ingenic Paul Cercueil
  2017-01-22 14:49       ` [PATCH v2 02/14] Documentation: dt/bindings: Document pinctrl-gpio Paul Cercueil
@ 2017-01-22 14:49       ` Paul Cercueil
  2017-01-22 14:49       ` [PATCH v2 04/14] GPIO: Add gpio-ingenic driver Paul Cercueil
                         ` (10 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-22 14:49 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

This driver handles pin configuration and pin muxing for the
JZ4740 and JZ4780 SoCs from Ingenic.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/pinctrl/Kconfig           |   8 +
 drivers/pinctrl/Makefile          |   1 +
 drivers/pinctrl/pinctrl-ingenic.c | 488 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 497 insertions(+)
 create mode 100644 drivers/pinctrl/pinctrl-ingenic.c

v2: Consider it's a new patch. Completely rewritten from v1.

diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 8f8c2af45781..2312e21ca48d 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -285,6 +285,14 @@ config PINCTRL_ZYNQ
 	help
 	  This selects the pinctrl driver for Xilinx Zynq.
 
+config PINCTRL_INGENIC
+	bool "Pinctrl driver for the Ingenic JZ47xx SoCs"
+	default y
+	depends on MACH_INGENIC || COMPILE_TEST
+	select GENERIC_PINCONF
+	select GENERIC_PINCTRL_GROUPS
+	select GENERIC_PINMUX_FUNCTIONS
+
 source "drivers/pinctrl/aspeed/Kconfig"
 source "drivers/pinctrl/bcm/Kconfig"
 source "drivers/pinctrl/berlin/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index a251f439626f..80f327239d4b 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_PINCTRL_LPC18XX)	+= pinctrl-lpc18xx.o
 obj-$(CONFIG_PINCTRL_TB10X)	+= pinctrl-tb10x.o
 obj-$(CONFIG_PINCTRL_ST) 	+= pinctrl-st.o
 obj-$(CONFIG_PINCTRL_ZYNQ)	+= pinctrl-zynq.o
+obj-$(CONFIG_PINCTRL_INGENIC)	+= pinctrl-ingenic.o
 
 obj-$(CONFIG_ARCH_ASPEED)	+= aspeed/
 obj-y				+= bcm/
diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-ingenic.c
new file mode 100644
index 000000000000..ce36cf509eb1
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-ingenic.c
@@ -0,0 +1,488 @@
+/*
+ * Ingenic SoCs pinctrl driver
+ *
+ * Copyright (c) 2017 Paul Cercueil <paul@crapouillou.net>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/compiler.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "core.h"
+#include "pinconf.h"
+#include "pinmux.h"
+
+#define JZ4740_GPIO_DATA	0x10
+#define JZ4740_GPIO_PULL_DIS	0x30
+#define JZ4740_GPIO_FUNC	0x40
+#define JZ4740_GPIO_SELECT	0x50
+#define JZ4740_GPIO_DIR		0x60
+#define JZ4740_GPIO_TRIG	0x70
+#define JZ4740_GPIO_FLAG	0x80
+
+#define JZ4780_GPIO_INT		0x10
+#define JZ4780_GPIO_MSK		0x20
+#define JZ4780_GPIO_PAT1	0x30
+#define JZ4780_GPIO_PAT0	0x40
+#define JZ4780_GPIO_FLAG	0x50
+#define JZ4780_GPIO_PEN		0x70
+
+#define REG_SET(x) ((x) + 0x4)
+#define REG_CLEAR(x) ((x) + 0x8)
+
+#define PINS_PER_GPIO_CHIP 32
+#define NUM_MAX_GPIO_CHIPS 6
+
+enum jz_version {
+	ID_JZ4740,
+	ID_JZ4780,
+};
+
+struct ingenic_pinctrl {
+	struct device *dev;
+	void __iomem *base;
+	struct pinctrl_dev *pctl;
+	struct pinctrl_pin_desc *pdesc;
+	enum jz_version version;
+
+	u32 pull_ups[NUM_MAX_GPIO_CHIPS];
+	u32 pull_downs[NUM_MAX_GPIO_CHIPS];
+};
+
+static inline void ingenic_config_pin(struct ingenic_pinctrl *jzpc,
+		unsigned int pin, u8 reg, bool set)
+{
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+
+	writel(BIT(idx), jzpc->base + offt * 0x100 +
+			(set ? REG_SET(reg) : REG_CLEAR(reg)));
+}
+
+static inline bool ingenic_get_pin_config(struct ingenic_pinctrl *jzpc,
+		unsigned int pin, u8 reg)
+{
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+
+	return readl(jzpc->base + offt * 0x100 + reg) & BIT(idx);
+}
+
+static struct pinctrl_ops ingenic_pctlops = {
+	.get_groups_count = pinctrl_generic_get_group_count,
+	.get_group_name = pinctrl_generic_get_group_name,
+	.get_group_pins = pinctrl_generic_get_group_pins,
+	.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
+	.dt_free_map = pinconf_generic_dt_free_map,
+};
+
+static int ingenic_pinmux_set_pin_fn(struct ingenic_pinctrl *jzpc,
+		int pin, int func)
+{
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+
+	dev_dbg(jzpc->dev, "set pin P%c%u to function %u\n",
+			'A' + offt, idx, func);
+
+	if (jzpc->version >= ID_JZ4780) {
+		ingenic_config_pin(jzpc, pin, JZ4780_GPIO_INT, false);
+		ingenic_config_pin(jzpc, pin, JZ4780_GPIO_MSK, false);
+		ingenic_config_pin(jzpc, pin, JZ4780_GPIO_PAT1, func & 0x2);
+		ingenic_config_pin(jzpc, pin, JZ4780_GPIO_PAT0, func & 0x1);
+	} else {
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_FUNC, true);
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_TRIG, func & 0x2);
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_SELECT, func > 0);
+	}
+
+	return 0;
+}
+
+static int ingenic_pinmux_set_mux(struct pinctrl_dev *pctldev,
+		unsigned int selector, unsigned int group)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	struct function_desc *func;
+	struct group_desc *grp;
+	unsigned int i;
+
+	func = pinmux_generic_get_function(pctldev, selector);
+	if (!func)
+		return -EINVAL;
+
+	grp = pinctrl_generic_get_group(pctldev, group);
+	if (!grp)
+		return -EINVAL;
+
+	dev_dbg(pctldev->dev, "enable function %s group %s\n",
+		func->name, grp->name);
+
+	for (i = 0; i < grp->num_pins; i++) {
+		int *pin_modes = grp->data;
+
+		ingenic_pinmux_set_pin_fn(jzpc, grp->pins[i], pin_modes[i]);
+	}
+
+	return 0;
+}
+
+static int ingenic_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
+		struct pinctrl_gpio_range *range,
+		unsigned int pin, bool input)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+
+	dev_dbg(pctldev->dev, "set pin P%c%u to %sput\n",
+			'A' + offt, idx, input ? "in" : "out");
+
+	if (jzpc->version >= ID_JZ4780) {
+		ingenic_config_pin(jzpc, pin, JZ4780_GPIO_INT, false);
+		ingenic_config_pin(jzpc, pin, JZ4780_GPIO_MSK, true);
+		ingenic_config_pin(jzpc, pin, JZ4780_GPIO_PAT1, input);
+	} else {
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_SELECT, false);
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_DIR, input);
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_FUNC, false);
+	}
+
+	return 0;
+}
+
+static struct pinmux_ops ingenic_pmxops = {
+	.get_functions_count = pinmux_generic_get_function_count,
+	.get_function_name = pinmux_generic_get_function_name,
+	.get_function_groups = pinmux_generic_get_function_groups,
+	.set_mux = ingenic_pinmux_set_mux,
+	.gpio_set_direction = ingenic_pinmux_gpio_set_direction,
+};
+
+static int ingenic_pinconf_get(struct pinctrl_dev *pctldev,
+		unsigned int pin, unsigned long *config)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	enum pin_config_param param = pinconf_to_config_param(*config);
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+	bool pull;
+
+	if (jzpc->version >= ID_JZ4780)
+		pull = !ingenic_get_pin_config(jzpc, pin, JZ4780_GPIO_PEN);
+	else
+		pull = !ingenic_get_pin_config(jzpc, pin, JZ4740_GPIO_PULL_DIS);
+
+	switch (param) {
+	case PIN_CONFIG_BIAS_DISABLE:
+		if (pull)
+			return -EINVAL;
+		break;
+
+	case PIN_CONFIG_BIAS_PULL_UP:
+		if (!pull || !(jzpc->pull_ups[offt] & BIT(idx)))
+			return -EINVAL;
+		break;
+
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		if (!pull || !(jzpc->pull_downs[offt] & BIT(idx)))
+			return -EINVAL;
+		break;
+
+	default:
+		return -ENOTSUPP;
+	}
+
+	*config = pinconf_to_config_packed(param, 1);
+	return 0;
+}
+
+static void ingenic_set_bias(struct ingenic_pinctrl *jzpc,
+		unsigned int pin, bool enabled)
+{
+	if (jzpc->version >= ID_JZ4780)
+		ingenic_config_pin(jzpc, pin, JZ4780_GPIO_PEN, !enabled);
+	else
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_PULL_DIS, !enabled);
+}
+
+static int ingenic_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
+		unsigned long *configs, unsigned int num_configs)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+	unsigned int cfg;
+
+	for (cfg = 0; cfg < num_configs; cfg++) {
+		switch (pinconf_to_config_param(configs[cfg])) {
+		case PIN_CONFIG_BIAS_DISABLE:
+		case PIN_CONFIG_BIAS_PULL_UP:
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			continue;
+		default:
+			return -ENOTSUPP;
+		}
+	}
+
+	for (cfg = 0; cfg < num_configs; cfg++) {
+		switch (pinconf_to_config_param(configs[cfg])) {
+		case PIN_CONFIG_BIAS_DISABLE:
+			dev_dbg(jzpc->dev, "disable pull-over for pin P%c%u\n",
+					'A' + offt, idx);
+			ingenic_set_bias(jzpc, pin, false);
+			break;
+
+		case PIN_CONFIG_BIAS_PULL_UP:
+			if (!(jzpc->pull_ups[offt] & BIT(idx)))
+				return -EINVAL;
+			dev_dbg(jzpc->dev, "set pull-up for pin P%c%u\n",
+					'A' + offt, idx);
+			ingenic_set_bias(jzpc, pin, true);
+			break;
+
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			if (!(jzpc->pull_downs[offt] & BIT(idx)))
+				return -EINVAL;
+			dev_dbg(jzpc->dev, "set pull-down for pin P%c%u\n",
+					'A' + offt, idx);
+			ingenic_set_bias(jzpc, pin, true);
+			break;
+
+		default:
+			unreachable();
+		}
+	}
+
+	return 0;
+}
+
+static int ingenic_pinconf_group_get(struct pinctrl_dev *pctldev,
+		unsigned int group, unsigned long *config)
+{
+	const unsigned *pins;
+	unsigned int i, npins, old = 0;
+	int ret;
+
+	ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < npins; i++) {
+		if (ingenic_pinconf_get(pctldev, pins[i], config))
+			return -ENOTSUPP;
+
+		/* configs do not match between two pins */
+		if (i && (old != *config))
+			return -ENOTSUPP;
+
+		old = *config;
+	}
+
+	return 0;
+}
+
+static int ingenic_pinconf_group_set(struct pinctrl_dev *pctldev,
+		unsigned int group, unsigned long *configs,
+		unsigned int num_configs)
+{
+	const unsigned *pins;
+	unsigned int i, npins;
+	int ret;
+
+	ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < npins; i++) {
+		ret = ingenic_pinconf_set(pctldev,
+				pins[i], configs, num_configs);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static struct pinconf_ops ingenic_confops = {
+	.is_generic = true,
+	.pin_config_get = ingenic_pinconf_get,
+	.pin_config_set = ingenic_pinconf_set,
+	.pin_config_group_get = ingenic_pinconf_group_get,
+	.pin_config_group_set = ingenic_pinconf_group_set,
+};
+
+static int ingenic_pinctrl_parse_dt_func(struct ingenic_pinctrl *jzpc,
+		struct device_node *np)
+{
+	unsigned int num_groups;
+	struct device_node *group_node;
+	unsigned int i, j;
+	int err, npins, *pins, *confs;
+	const char **groups;
+
+	num_groups = of_get_child_count(np);
+	groups = devm_kzalloc(jzpc->dev,
+			sizeof(*groups) * num_groups, GFP_KERNEL);
+	if (!groups)
+		return -ENOMEM;
+
+	i = 0;
+	for_each_child_of_node(np, group_node) {
+		groups[i++] = group_node->name;
+
+		npins = of_property_count_elems_of_size(group_node,
+				"ingenic,pins", 8);
+		if (npins < 0)
+			return npins;
+
+		pins = devm_kzalloc(jzpc->dev,
+				sizeof(*pins) * npins, GFP_KERNEL);
+		confs = devm_kzalloc(jzpc->dev,
+				sizeof(*confs) * npins, GFP_KERNEL);
+		if (!pins || !confs)
+			return -ENOMEM;
+
+		for (j = 0; j < npins; j++) {
+			of_property_read_u32_index(group_node,
+					"ingenic,pins", j * 2, &pins[j]);
+
+			of_property_read_u32_index(group_node,
+					"ingenic,pins", j * 2 + 1, &confs[j]);
+		}
+
+		err = pinctrl_generic_add_group(jzpc->pctl, group_node->name,
+				pins, npins, confs);
+		if (err)
+			return err;
+	}
+
+	return pinmux_generic_add_function(jzpc->pctl, np->name,
+			groups, num_groups, NULL);
+}
+
+static const struct of_device_id ingenic_pinctrl_of_match[] = {
+	{ .compatible = "ingenic,jz4740-pinctrl", .data = (void *) ID_JZ4740 },
+	{ .compatible = "ingenic,jz4780-pinctrl", .data = (void *) ID_JZ4780 },
+	{},
+};
+
+int ingenic_pinctrl_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct ingenic_pinctrl *jzpc;
+	struct pinctrl_desc *pctl_desc;
+	struct device_node *np, *functions_node;
+	const struct of_device_id *of_id = of_match_device(
+			ingenic_pinctrl_of_match, dev);
+	unsigned int i, num_chips;
+	int err;
+
+	jzpc = devm_kzalloc(dev, sizeof(*jzpc), GFP_KERNEL);
+	if (!jzpc)
+		return -ENOMEM;
+
+	jzpc->base = of_iomap(dev->of_node, 0);
+	if (!jzpc->base) {
+		dev_err(dev, "failed to map IO memory\n");
+		return -ENXIO;
+	}
+
+	jzpc->dev = dev;
+	dev_set_drvdata(dev, jzpc);
+
+	jzpc->version = (enum jz_version)of_id->data;
+
+	if (jzpc->version >= ID_JZ4780)
+		num_chips = 6;
+	else
+		num_chips = 4;
+
+	/*
+	 * Read the ingenic,pull-ups and ingenic,pull-downs arrays if present in
+	 * the devicetree. Otherwise set all bits to 0xff to consider that
+	 * pull-over resistors are available on all pins.
+	 */
+	err = of_property_read_u32_array(dev->of_node, "ingenic,pull-ups",
+			jzpc->pull_ups, num_chips);
+	if (err)
+		memset(jzpc->pull_ups, 0xff, sizeof(jzpc->pull_ups));
+
+	err = of_property_read_u32_array(dev->of_node, "ingenic,pull-downs",
+			jzpc->pull_downs, num_chips);
+	if (err)
+		memset(jzpc->pull_downs, 0xff, sizeof(jzpc->pull_downs));
+
+	functions_node = of_find_node_by_name(dev->of_node, "functions");
+	if (!functions_node) {
+		dev_err(dev, "Missing \"functions\" devicetree node\n");
+		return -EINVAL;
+	}
+
+	pctl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctl_desc), GFP_KERNEL);
+	if (!pctl_desc)
+		return -ENOMEM;
+
+	/* fill in pinctrl_desc structure */
+	pctl_desc->name = dev_name(dev);
+	pctl_desc->owner = THIS_MODULE;
+	pctl_desc->pctlops = &ingenic_pctlops;
+	pctl_desc->pmxops = &ingenic_pmxops;
+	pctl_desc->confops = &ingenic_confops;
+	pctl_desc->npins = num_chips * PINS_PER_GPIO_CHIP;
+	pctl_desc->pins = jzpc->pdesc = devm_kzalloc(&pdev->dev,
+			sizeof(*jzpc->pdesc) * pctl_desc->npins, GFP_KERNEL);
+	if (!jzpc->pdesc)
+		return -ENOMEM;
+
+	for (i = 0; i < pctl_desc->npins; i++) {
+		jzpc->pdesc[i].number = i;
+		jzpc->pdesc[i].name = kasprintf(GFP_KERNEL, "P%c%d",
+						'A' + (i / PINS_PER_GPIO_CHIP),
+						i % PINS_PER_GPIO_CHIP);
+	}
+
+	jzpc->pctl = devm_pinctrl_register(dev, pctl_desc, jzpc);
+	if (!jzpc->pctl) {
+		dev_err(dev, "Failed pinctrl registration\n");
+		return -EINVAL;
+	}
+
+	for_each_child_of_node(functions_node, np) {
+		err = ingenic_pinctrl_parse_dt_func(jzpc, np);
+		if (err) {
+			dev_err(dev, "failed to parse function %s\n",
+					np->full_name);
+			continue;
+		}
+	}
+
+	return 0;
+}
+
+static struct platform_driver ingenic_pinctrl_driver = {
+	.driver = {
+		.name = "pinctrl-ingenic",
+		.of_match_table = of_match_ptr(ingenic_pinctrl_of_match),
+		.suppress_bind_attrs = true,
+	},
+	.probe = ingenic_pinctrl_probe,
+};
+
+static int __init ingenic_pinctrl_drv_register(void)
+{
+	return platform_driver_register(&ingenic_pinctrl_driver);
+}
+postcore_initcall(ingenic_pinctrl_drv_register);
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v2 04/14] GPIO: Add gpio-ingenic driver
  2017-01-22 14:49     ` [PATCH v2 00/14] " Paul Cercueil
                         ` (2 preceding siblings ...)
  2017-01-22 14:49       ` [PATCH v2 03/14] pinctrl-ingenic: add a pinctrl driver for the Ingenic jz47xx SoCs Paul Cercueil
@ 2017-01-22 14:49       ` Paul Cercueil
  2017-01-22 16:21         ` kbuild test robot
                           ` (2 more replies)
  2017-01-22 14:49       ` [PATCH v2 05/14] MIPS: ingenic: Enable pinctrl for all ingenic SoCs Paul Cercueil
                         ` (9 subsequent siblings)
  13 siblings, 3 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-22 14:49 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

This driver handles the GPIOs of all the Ingenic JZ47xx SoCs
currently supported by the upsteam Linux kernel.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/gpio/Kconfig        |  10 ++
 drivers/gpio/Makefile       |   1 +
 drivers/gpio/gpio-ingenic.c | 367 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 378 insertions(+)
 create mode 100644 drivers/gpio/gpio-ingenic.c

v2: Consider it's a new patch. Completely rewritten from v1.

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index d5d36549ecc1..21992ca29342 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -225,6 +225,16 @@ config GPIO_ICH
 
 	  If unsure, say N.
 
+config GPIO_INGENIC
+	tristate "Ingenic JZ47xx SoCs GPIO support"
+	depends on MACH_INGENIC || COMPILE_TEST
+	select GPIOLIB_IRQCHIP
+	help
+	  Say yes here to support the GPIO functionality present on the
+	  JZ4740 and JZ4780 SoCs from Ingenic.
+
+	  If unsure, say N.
+
 config GPIO_IOP
 	tristate "Intel IOP GPIO"
 	depends on ARCH_IOP32X || ARCH_IOP33X || COMPILE_TEST
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index a7676b82de6f..3c5412ae56f0 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_GPIO_GPIO_MM)	+= gpio-gpio-mm.o
 obj-$(CONFIG_GPIO_GRGPIO)	+= gpio-grgpio.o
 obj-$(CONFIG_HTC_EGPIO)		+= gpio-htc-egpio.o
 obj-$(CONFIG_GPIO_ICH)		+= gpio-ich.o
+obj-$(CONFIG_GPIO_INGENIC)	+= gpio-ingenic.o
 obj-$(CONFIG_GPIO_IOP)		+= gpio-iop.o
 obj-$(CONFIG_GPIO_IT87)		+= gpio-it87.o
 obj-$(CONFIG_GPIO_JANZ_TTL)	+= gpio-janz-ttl.o
diff --git a/drivers/gpio/gpio-ingenic.c b/drivers/gpio/gpio-ingenic.c
new file mode 100644
index 000000000000..aa9e0cb794c3
--- /dev/null
+++ b/drivers/gpio/gpio-ingenic.c
@@ -0,0 +1,367 @@
+/*
+ * Ingenic JZ47xx GPIO driver
+ *
+ * Copyright (c) 2017 Paul Cercueil <paul@crapouillou.net>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+
+#define GPIO_PIN	0x00
+#define GPIO_MSK	0x20
+
+#define JZ4740_GPIO_DATA	0x10
+#define JZ4740_GPIO_SELECT	0x50
+#define JZ4740_GPIO_DIR		0x60
+#define JZ4740_GPIO_TRIG	0x70
+#define JZ4740_GPIO_FLAG	0x80
+
+#define JZ4780_GPIO_INT		0x10
+#define JZ4780_GPIO_PAT1	0x30
+#define JZ4780_GPIO_PAT0	0x40
+#define JZ4780_GPIO_FLAG	0x50
+
+#define REG_SET(x) ((x) + 0x4)
+#define REG_CLEAR(x) ((x) + 0x8)
+
+enum jz_version {
+	ID_JZ4740,
+	ID_JZ4780,
+};
+
+struct ingenic_gpio_chip {
+	void __iomem *base;
+	struct gpio_chip gc;
+	struct irq_chip irq_chip;
+	unsigned int irq;
+	enum jz_version version;
+};
+
+static inline bool gpio_get_value(struct ingenic_gpio_chip *jzgc, u8 offset)
+{
+	if (jzgc->version >= ID_JZ4780)
+		return readl(jzgc->base + GPIO_PIN) & BIT(offset);
+	else
+		return readl(jzgc->base + JZ4740_GPIO_DATA) & BIT(offset);
+}
+
+static void gpio_set_value(struct ingenic_gpio_chip *jzgc, u8 offset, int value)
+{
+	u8 reg;
+
+	if (jzgc->version >= ID_JZ4780)
+		reg = JZ4780_GPIO_PAT0;
+	else
+		reg = JZ4740_GPIO_DATA;
+
+	if (value)
+		writel(BIT(offset), jzgc->base + REG_SET(reg));
+	else
+		writel(BIT(offset), jzgc->base + REG_CLEAR(reg));
+}
+
+static void irq_set_type(struct ingenic_gpio_chip *jzgc,
+		u8 offset, unsigned int type)
+{
+	u8 reg1, reg2;
+
+	if (jzgc->version >= ID_JZ4780) {
+		reg1 = JZ4780_GPIO_PAT1;
+		reg2 = JZ4780_GPIO_PAT0;
+	} else {
+		reg1 = JZ4740_GPIO_TRIG;
+		reg2 = JZ4740_GPIO_DIR;
+	}
+
+	switch (type) {
+	case IRQ_TYPE_EDGE_RISING:
+		writel(BIT(offset), jzgc->base + REG_SET(reg2));
+		writel(BIT(offset), jzgc->base + REG_SET(reg1));
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		writel(BIT(offset), jzgc->base + REG_CLEAR(reg2));
+		writel(BIT(offset), jzgc->base + REG_SET(reg1));
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		writel(BIT(offset), jzgc->base + REG_SET(reg2));
+		writel(BIT(offset), jzgc->base + REG_CLEAR(reg1));
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+	default:
+		writel(BIT(offset), jzgc->base + REG_CLEAR(reg2));
+		writel(BIT(offset), jzgc->base + REG_CLEAR(reg1));
+		break;
+	};
+
+}
+
+static void ingenic_gpio_irq_mask(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	writel(BIT(irqd->hwirq), jzgc->base + REG_SET(GPIO_MSK));
+}
+
+static void ingenic_gpio_irq_unmask(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	writel(BIT(irqd->hwirq), jzgc->base + REG_CLEAR(GPIO_MSK));
+}
+
+static void ingenic_gpio_irq_enable(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+	int irq = irqd->hwirq;
+
+	if (jzgc->version >= ID_JZ4780)
+		writel(BIT(irq), jzgc->base + REG_SET(JZ4780_GPIO_INT));
+	else
+		writel(BIT(irq), jzgc->base + REG_SET(JZ4740_GPIO_SELECT));
+
+	ingenic_gpio_irq_unmask(irqd);
+}
+
+static void ingenic_gpio_irq_disable(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+	int irq = irqd->hwirq;
+
+	ingenic_gpio_irq_mask(irqd);
+
+	if (jzgc->version >= ID_JZ4780)
+		writel(BIT(irq), jzgc->base + REG_CLEAR(JZ4780_GPIO_INT));
+	else
+		writel(BIT(irq), jzgc->base + REG_CLEAR(JZ4740_GPIO_SELECT));
+}
+
+static void ingenic_gpio_irq_ack(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+	int irq = irqd->hwirq;
+	bool high;
+
+	if (irqd_get_trigger_type(irqd) == IRQ_TYPE_EDGE_BOTH) {
+		/*
+		 * Switch to an interrupt for the opposite edge to the one that
+		 * triggered the interrupt being ACKed.
+		 */
+		high = gpio_get_value(jzgc, irq);
+		if (high)
+			irq_set_type(jzgc, irq, IRQ_TYPE_EDGE_FALLING);
+		else
+			irq_set_type(jzgc, irq, IRQ_TYPE_EDGE_RISING);
+	}
+
+	if (jzgc->version >= ID_JZ4780)
+		writel(BIT(irq), jzgc->base + REG_CLEAR(JZ4780_GPIO_FLAG));
+	else
+		writel(BIT(irq), jzgc->base + REG_SET(JZ4740_GPIO_DATA));
+}
+
+static int ingenic_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	switch (type) {
+	case IRQ_TYPE_EDGE_BOTH:
+	case IRQ_TYPE_EDGE_RISING:
+	case IRQ_TYPE_EDGE_FALLING:
+		irq_set_handler_locked(irqd, handle_edge_irq);
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+	case IRQ_TYPE_LEVEL_LOW:
+		irq_set_handler_locked(irqd, handle_level_irq);
+		break;
+	default:
+		irq_set_handler_locked(irqd, handle_bad_irq);
+	}
+
+	if (type == IRQ_TYPE_EDGE_BOTH) {
+		/*
+		 * The hardware does not support interrupts on both edges. The
+		 * best we can do is to set up a single-edge interrupt and then
+		 * switch to the opposing edge when ACKing the interrupt.
+		 */
+		bool high = gpio_get_value(jzgc, irqd->hwirq);
+
+		type = high ? IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING;
+	}
+
+	irq_set_type(jzgc, irqd->hwirq, type);
+	return 0;
+}
+
+static int ingenic_gpio_irq_set_wake(struct irq_data *irqd, unsigned int on)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	return irq_set_irq_wake(jzgc->irq, on);
+}
+
+static void ingenic_gpio_irq_handler(struct irq_desc *desc)
+{
+	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+	struct irq_chip *irq_chip = irq_data_get_irq_chip(&desc->irq_data);
+	unsigned long flag, i;
+
+	chained_irq_enter(irq_chip, desc);
+
+	if (jzgc->version >= ID_JZ4780)
+		flag = readl(jzgc->base + JZ4780_GPIO_FLAG);
+	else
+		flag = readl(jzgc->base + JZ4740_GPIO_FLAG);
+
+	for_each_set_bit(i, &flag, 32)
+		generic_handle_irq(irq_linear_revmap(gc->irqdomain, i));
+	chained_irq_exit(irq_chip, desc);
+}
+
+static void ingenic_gpio_set(struct gpio_chip *gc,
+		unsigned int offset, int value)
+{
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	gpio_set_value(jzgc, offset, value);
+}
+
+static int ingenic_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	return (int) gpio_get_value(jzgc, offset);
+}
+
+static int ingenic_gpio_direction_input(struct gpio_chip *gc,
+		unsigned int offset)
+{
+	return pinctrl_gpio_direction_input(gc->base + offset);
+}
+
+static int ingenic_gpio_direction_output(struct gpio_chip *gc,
+		unsigned int offset, int value)
+{
+	ingenic_gpio_set(gc, offset, value);
+	return pinctrl_gpio_direction_output(gc->base + offset);
+}
+
+static const struct of_device_id ingenic_gpio_of_match[] = {
+	{ .compatible = "ingenic,jz4740-gpio", .data = (void *)ID_JZ4740 },
+	{ .compatible = "ingenic,jz4780-gpio", .data = (void *)ID_JZ4780 },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ingenic_gpio_of_match);
+
+static int ingenic_gpio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	const struct of_device_id *of_id = of_match_device(
+			ingenic_gpio_of_match, dev);
+	struct ingenic_gpio_chip *jzgc;
+	int err;
+
+	jzgc = devm_kzalloc(dev, sizeof(*jzgc), GFP_KERNEL);
+	if (!jzgc)
+		return -ENOMEM;
+
+	jzgc->base = of_iomap(dev->of_node, 0);
+	if (!jzgc->base) {
+		dev_err(dev, "failed to map IO memory\n");
+		return -ENXIO;
+	}
+
+	jzgc->gc.base = -1;
+	jzgc->gc.ngpio = 32;
+	jzgc->gc.parent = dev;
+	jzgc->gc.of_node = dev->of_node;
+	jzgc->gc.label = "";
+	jzgc->gc.owner = THIS_MODULE;
+	jzgc->version = (enum jz_version)of_id->data;
+
+	jzgc->gc.set = ingenic_gpio_set;
+	jzgc->gc.get = ingenic_gpio_get;
+	jzgc->gc.direction_input = ingenic_gpio_direction_input;
+	jzgc->gc.direction_output = ingenic_gpio_direction_output;
+
+	if (of_property_read_bool(dev->of_node, "gpio-ranges")) {
+		jzgc->gc.request = gpiochip_generic_request;
+		jzgc->gc.free = gpiochip_generic_free;
+	}
+
+	of_property_read_u32(dev->of_node, "base", &jzgc->gc.base);
+
+	err = devm_gpiochip_add_data(dev, &jzgc->gc, jzgc);
+	if (err)
+		return err;
+
+	if (!of_property_read_bool(dev->of_node, "interrupt-controller"))
+		return 0;
+
+	jzgc->irq = irq_of_parse_and_map(dev->of_node, 0);
+	if (!jzgc->irq)
+		return -EINVAL;
+
+	jzgc->irq_chip.name = dev->of_node->name;
+	jzgc->irq_chip.irq_enable = ingenic_gpio_irq_enable;
+	jzgc->irq_chip.irq_disable = ingenic_gpio_irq_disable;
+	jzgc->irq_chip.irq_unmask = ingenic_gpio_irq_unmask;
+	jzgc->irq_chip.irq_mask = ingenic_gpio_irq_mask;
+	jzgc->irq_chip.irq_ack = ingenic_gpio_irq_ack;
+	jzgc->irq_chip.irq_set_type = ingenic_gpio_irq_set_type;
+	jzgc->irq_chip.irq_set_wake = ingenic_gpio_irq_set_wake;
+	jzgc->irq_chip.flags = IRQCHIP_MASK_ON_SUSPEND;
+
+	err = gpiochip_irqchip_add(&jzgc->gc, &jzgc->irq_chip, 0,
+			handle_level_irq, IRQ_TYPE_NONE);
+	if (err)
+		return err;
+
+	gpiochip_set_chained_irqchip(&jzgc->gc, &jzgc->irq_chip,
+			jzgc->irq, ingenic_gpio_irq_handler);
+	return 0;
+}
+
+static int ingenic_gpio_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver ingenic_gpio_driver = {
+	.driver = {
+		.name = "gpio-ingenic",
+		.of_match_table = of_match_ptr(ingenic_gpio_of_match),
+	},
+	.probe = ingenic_gpio_probe,
+	.remove = ingenic_gpio_remove,
+};
+
+static int __init ingenic_gpio_drv_register(void)
+{
+	return platform_driver_register(&ingenic_gpio_driver);
+}
+subsys_initcall(ingenic_gpio_drv_register);
+
+static void __exit ingenic_gpio_drv_unregister(void)
+{
+	platform_driver_unregister(&ingenic_gpio_driver);
+}
+module_exit(ingenic_gpio_drv_unregister);
+
+MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
+MODULE_DESCRIPTION("Ingenic JZ47xx GPIO driver");
+MODULE_LICENSE("GPL");
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v2 05/14] MIPS: ingenic: Enable pinctrl for all ingenic SoCs
  2017-01-22 14:49     ` [PATCH v2 00/14] " Paul Cercueil
                         ` (3 preceding siblings ...)
  2017-01-22 14:49       ` [PATCH v2 04/14] GPIO: Add gpio-ingenic driver Paul Cercueil
@ 2017-01-22 14:49       ` Paul Cercueil
  2017-01-22 14:49       ` [PATCH v2 06/14] MIPS: jz4740: DTS: Add nodes for ingenic pinctrl and gpio drivers Paul Cercueil
                         ` (8 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-22 14:49 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

There is a pinctrl driver for each of the Ingenic SoCs supported by the
upstream Linux kernel. In order to switch away from the old GPIO
platform code, we now enable the pinctrl drivers by default for the
Ingenic SoCs.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/Kconfig | 1 +
 1 file changed, 1 insertion(+)

v2: No changes

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index b3c5bde43d34..fc720e37661e 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -359,6 +359,7 @@ config MACH_INGENIC
 	select SYS_SUPPORTS_ZBOOT_UART16550
 	select DMA_NONCOHERENT
 	select IRQ_MIPS_CPU
+	select PINCTRL
 	select GPIOLIB
 	select COMMON_CLK
 	select GENERIC_IRQ_CHIP
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v2 06/14] MIPS: jz4740: DTS: Add nodes for ingenic pinctrl and gpio drivers
  2017-01-22 14:49     ` [PATCH v2 00/14] " Paul Cercueil
                         ` (4 preceding siblings ...)
  2017-01-22 14:49       ` [PATCH v2 05/14] MIPS: ingenic: Enable pinctrl for all ingenic SoCs Paul Cercueil
@ 2017-01-22 14:49       ` Paul Cercueil
  2017-01-22 14:49       ` [PATCH v2 07/14] MIPS: jz4780: " Paul Cercueil
                         ` (7 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-22 14:49 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

For a description of the pinctrl devicetree node, please read
Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt

For a description of the gpio devicetree nodes, please read
Documentation/devicetree/bindings/gpio/ingenic,gpio.txt

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/boot/dts/ingenic/jz4740.dtsi | 194 +++++++++++++++++++++++++++++++++
 1 file changed, 194 insertions(+)

v2: Changed the devicetree bindings to match the new driver

diff --git a/arch/mips/boot/dts/ingenic/jz4740.dtsi b/arch/mips/boot/dts/ingenic/jz4740.dtsi
index 3e1587f1f77a..960e060eb725 100644
--- a/arch/mips/boot/dts/ingenic/jz4740.dtsi
+++ b/arch/mips/boot/dts/ingenic/jz4740.dtsi
@@ -55,6 +55,200 @@
 		clock-names = "rtc";
 	};
 
+	pinctrl: ingenic-pinctrl@10010000 {
+		compatible = "ingenic,jz4740-pinctrl";
+		reg = <0x10010000 0x400>;
+
+		ingenic,pull-ups   = <0xffffffff 0xffffffff 0xffffffff 0xdfffffff>;
+		ingenic,pull-downs = <0x00000000 0x00000000 0x00000000 0x00000000>;
+
+		functions {
+			mmc {
+				mmc-1bit {
+					/* CLK, CMD, D0 */
+					ingenic,pins = <0x69 0 0x68 0 0x6a 0>;
+				};
+
+				mmc-4bit {
+					/* D1, D2, D3 */
+					ingenic,pins = <0x6b 0 0x6c 0 0x6d 0>;
+				};
+			};
+
+			uart0 {
+				uart0-data {
+					/* RXD, TXD */
+					ingenic,pins = <0x7a 1 0x79 1>;
+				};
+
+				uart0-hwflow {
+					/* CTS, RTS */
+					ingenic,pins = <0x7e 1 0x7f 1>;
+				};
+			};
+
+			uart1 {
+				uart1-data {
+					/* RXD, TXD */
+					ingenic,pins = <0x7e 2 0x7f 2>;
+				};
+			};
+
+			lcd {
+				lcd-8bit {
+					/* LCD_DATA0 ... LCD_DATA7, PCLK, HSYNC, VSYNC */
+					ingenic,pins = <0x40 0 0x41 0 0x42 0 0x43 0
+									0x44 0 0x45 0 0x46 0 0x47 0
+									0x52 0 0x53 0 0x54 0>;
+				};
+
+				lcd-16bit {
+					/* LCD_DATA8 ... LCD_DATA15, DE */
+					ingenic,pins = <0x48 0 0x49 0 0x4a 0 0x4b 0
+									0x4c 0 0x4d 0 0x4e 0 0x4f 0
+									0x55 0>;
+				};
+
+				lcd-18bit {
+					/* LCD_DATA16, LCD_DATA17 */
+					ingenic,pins = <0x50 0 0x51 0>;
+				};
+
+				lcd-18bit-tft {
+					/* PS, REV, CLS, SPL */
+					ingenic,pins = <0x56 0 0x57 0 0x31 0 0x32 0>;
+				};
+
+				lcd-no-pins {
+					ingenic,pins = <>;
+				};
+			};
+
+			nand {
+				nand {
+					/* CS1, CS2, CS3, CS4 */
+					ingenic,pins = <0x39 0 0x3a 0 0x3b 0 0x3c 0>;
+				};
+			};
+
+			pwm0 {
+				pwm0 {
+					ingenic,pins = <0x77 0>;
+				};
+			};
+
+			pwm1 {
+				pwm1 {
+					ingenic,pins = <0x78 0>;
+				};
+			};
+
+			pwm2 {
+				pwm2 {
+					ingenic,pins = <0x79 0>;
+				};
+			};
+
+			pwm3 {
+				pwm3 {
+					ingenic,pins = <0x7a 0>;
+				};
+			};
+
+			pwm4 {
+				pwm4 {
+					ingenic,pins = <0x7b 0>;
+				};
+			};
+
+			pwm5 {
+				pwm5 {
+					ingenic,pins = <0x7c 0>;
+				};
+			};
+
+			pwm6 {
+				pwm6 {
+					ingenic,pins = <0x7e 0>;
+				};
+			};
+
+			pwm7 {
+				pwm7 {
+					ingenic,pins = <0x7f 0>;
+				};
+			};
+		};
+	};
+
+	gpa: gpio-controller@10010000 {
+		compatible = "ingenic,jz4740-gpio";
+		reg = <0x10010000 0x100>;
+
+		gpio-controller;
+		gpio-ranges = <&pinctrl 0 0 32>;
+		#gpio-cells = <2>;
+
+		base = <0x00>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <28>;
+	};
+
+	gpb: gpio-controller@10010100 {
+		compatible = "ingenic,jz4740-gpio";
+		reg = <0x10010100 0x100>;
+
+		gpio-controller;
+		gpio-ranges = <&pinctrl 0 32 32>;
+		#gpio-cells = <2>;
+
+		base = <0x20>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <27>;
+	};
+
+	gpc: gpio-controller@10010200 {
+		compatible = "ingenic,jz4740-gpio";
+		reg = <0x10010200 0x100>;
+
+		gpio-controller;
+		gpio-ranges = <&pinctrl 0 64 32>;
+		#gpio-cells = <2>;
+
+		base = <0x40>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <26>;
+	};
+
+	gpd: gpio-controller@10010300 {
+		compatible = "ingenic,jz4740-gpio";
+		reg = <0x10010300 0x100>;
+
+		gpio-controller;
+		gpio-ranges = <&pinctrl 0 96 32>;
+		#gpio-cells = <2>;
+
+		base = <0x60>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <25>;
+	};
+
 	uart0: serial@10030000 {
 		compatible = "ingenic,jz4740-uart";
 		reg = <0x10030000 0x100>;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v2 07/14] MIPS: jz4780: DTS: Add nodes for ingenic pinctrl and gpio drivers
  2017-01-22 14:49     ` [PATCH v2 00/14] " Paul Cercueil
                         ` (5 preceding siblings ...)
  2017-01-22 14:49       ` [PATCH v2 06/14] MIPS: jz4740: DTS: Add nodes for ingenic pinctrl and gpio drivers Paul Cercueil
@ 2017-01-22 14:49       ` Paul Cercueil
  2017-01-22 14:49       ` [PATCH v2 08/14] MIPS: JZ4740: Qi LB60: Add pinctrl configuration for several drivers Paul Cercueil
                         ` (6 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-22 14:49 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

For a description of the devicetree node, please read
Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt

For a description of the gpio devicetree nodes, please read
Documentation/devicetree/bindings/gpio/ingenic,gpio.txt

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/boot/dts/ingenic/jz4780.dtsi | 297 +++++++++++++++++++++++++++++++++
 1 file changed, 297 insertions(+)

v2: Changed the devicetree bindings to match the new driver

diff --git a/arch/mips/boot/dts/ingenic/jz4780.dtsi b/arch/mips/boot/dts/ingenic/jz4780.dtsi
index b868b429add2..47e079e9236e 100644
--- a/arch/mips/boot/dts/ingenic/jz4780.dtsi
+++ b/arch/mips/boot/dts/ingenic/jz4780.dtsi
@@ -44,6 +44,303 @@
 		#clock-cells = <1>;
 	};
 
+	pinctrl: ingenic-pinctrl@10010000 {
+		compatible = "ingenic,jz4780-pinctrl";
+		reg = <0x10010000 0x600>;
+
+		ingenic,pull-ups   = <0x3fffffff 0xfff0030c 0xffffffff
+							  0xffff4fff 0xfffffb7c 0xffa7f00f>;
+		ingenic,pull-downs = <0x00000000 0x000f0c03 0x00000000
+							  0x0000b000 0x00000483 0x00580ff0>;
+
+		functions {
+			uart0 {
+				uart0-data {
+					/* RXD, TXD */
+					ingenic,pins = <0xa0 0 0xa3 0>;
+				};
+
+				uart0-hwflow {
+					/* CTS, RTS */
+					ingenic,pins = <0xa1 0 0xa2 0>;
+				};
+			};
+
+			uart1 {
+				uart1-data {
+					/* RXD, TXD */
+					ingenic,pins = <0x7a 0 0x7c 0>;
+				};
+
+				uart1-hwflow {
+					/* CTS, RTS */
+					ingenic,pins = <0x7b 0 0x7d 0>;
+				};
+			};
+
+			uart2 {
+				uart2-data {
+					/* RXD, TXD */
+					ingenic,pins = <0x66 1 0x67 1>;
+				};
+
+				uart2-hwflow {
+					/* CTS, RTS */
+					ingenic,pins = <0x65 1 0x64 1>;
+				};
+			};
+
+			uart3 {
+				uart3-data {
+					/* RXD, TXD */
+					ingenic,pins = <0x6c 0 0x85 1>;
+				};
+
+				uart3-hwflow {
+					/* CTS, RTS */
+					ingenic,pins = <0x88 0 0x89 0>;
+				};
+			};
+
+			uart4 {
+				uart4-data {
+					/* RXD, TXD */
+					ingenic,pins = <0x54 2 0x4a 2>;
+				};
+			};
+
+			msc0 {
+				msc0-8bit-a {
+					/* D4, D5, D6, D7, RST */
+					ingenic,pins = <0x04 1 0x05 1 0x06 1 0x07 1
+									0x18 1>;
+				};
+
+				msc0-4bit-a {
+					/* D1, D2, D3 */
+					ingenic,pins = <0x15 1 0x16 1 0x17 1>;
+				};
+
+				msc0-1bit-a {
+					/* CLK, CMD, D0 */
+					ingenic,pins = <0x12 1 0x13 1 0x14 1>;
+				};
+
+				msc0-1bit-e {
+					/* CLK, CMD, D0 */
+					ingenic,pins = <0x9c 0 0x9d 0 0x94 0>;
+				};
+
+				msc0-4bit-e {
+					/* D1, D2, D3 */
+					ingenic,pins = <0x95 0 0x96 0 0x97 0>;
+				};
+			};
+
+			msc1 {
+				msc1-1bit-d {
+					/* CLK, CMD, D0 */
+					ingenic,pins = <0x78 0 0x79 0 0x74 0>;
+				};
+
+				msc1-4bit-d {
+					/* D1, D2, D3 */
+					ingenic,pins = <0x75 0 0x76 0 0x77 0>;
+				};
+
+				msc1-1bit-e {
+					/* CLK, CMD, D0 */
+					ingenic,pins = <0x9c 1 0x9d 1 0x94 1>;
+				};
+
+				msc1-4bit-e {
+					/* D1, D2, D3 */
+					ingenic,pins = <0x95 1 0x96 1 0x97 1>;
+				};
+			};
+
+			nemc {
+				nemc-data {
+					/* SD0, SD1, SD2, SD3, SD4, SD5, SD6, SD7 */
+					ingenic,pins = <0x00 0 0x01 0 0x02 0 0x03 0
+									0x04 0 0x05 0 0x06 0 0x07 0>;
+				};
+
+				nemc-cle-ale {
+					/* SA0_CL, SA1_AL */
+					ingenic,pins = <0x20 0 0x21 0>;
+				};
+
+				nemc-addr {
+					/* SA2, SA3, SA4, SA5 */
+					ingenic,pins = <0x22 0 0x23 0 0x24 0 0x25 0>;
+				};
+
+				nemc-rd-we {
+					/* RD, WE */
+					ingenic,pins = <0x10 0 0x11 0>;
+				};
+
+				nemc-frd-fwe {
+					/* RD, WE */
+					ingenic,pins = <0x12 0 0x13 0>;
+				};
+			};
+
+			nemc-cs1 {
+				nemc-cs1 {
+					/* CS1 */
+					ingenic,pins = <0x15 0>;
+				};
+			};
+
+			nemc-cs6 {
+				nemc-cs6 {
+					/* CS6 */
+					ingenic,pins = <0x1a 0>;
+				};
+			};
+
+			i2c0 {
+				i2c0-data {
+					/* SDA, SCL */
+					ingenic,pins = <0x6e 0 0x6f 0>;
+				};
+			};
+
+			i2c1 {
+				i2c1-data {
+					/* SDA, SCL */
+					ingenic,pins = <0x8e 0 0x8f 0>;
+				};
+			};
+
+			i2c2 {
+				i2c2-data {
+					/* SDA, SCL */
+					ingenic,pins = <0xb0 2 0xb1 2>;
+				};
+			};
+
+			i2c3 {
+				i2c3-data {
+					/* SDA, SCL */
+					ingenic,pins = <0x6a 1 0x6b 1>;
+				};
+			};
+
+			i2c4 {
+				i2c4-data-pe {
+					/* SDA, SCL */
+					ingenic,pins = <0x8c 1 0x8d 1>;
+				};
+
+				i2c4-data-pf {
+					/* HDMI_SDA, HDMI_SCL */
+					ingenic,pins = <0xb9 1 0xb8 1>;
+				};
+			};
+
+			cim {
+				cim-pb {
+					ingenic,pins = <0x26 0 0x27 0 0x28 0 0x29 0
+									0x2a 0 0x2b 0 0x2c 0 0x2d 0
+									0x2e 0 0x2f 0 0x30 0 0x31 0>;
+				};
+			};
+		};
+	};
+
+	gpa: gpio-controller@10010000 {
+		compatible = "ingenic,jz4780-gpio";
+		reg = <0x10010000 0x100>;
+
+		gpio-controller;
+		gpio-ranges = <&pinctrl 0 0 32>;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <17>;
+	};
+
+	gpb: gpio-controller@10010100 {
+		compatible = "ingenic,jz4780-gpio";
+		reg = <0x10010100 0x100>;
+
+		gpio-controller;
+		gpio-ranges = <&pinctrl 0 32 32>;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <16>;
+	};
+
+	gpc: gpio-controller@10010200 {
+		compatible = "ingenic,jz4780-gpio";
+		reg = <0x10010200 0x100>;
+
+		gpio-controller;
+		gpio-ranges = <&pinctrl 0 64 32>;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <15>;
+	};
+
+	gpd: gpio-controller@10010300 {
+		compatible = "ingenic,jz4780-gpio";
+		reg = <0x10010300 0x100>;
+
+		gpio-controller;
+		gpio-ranges = <&pinctrl 0 96 32>;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <14>;
+	};
+
+	gpe: gpio-controller@10010400 {
+		compatible = "ingenic,jz4780-gpio";
+		reg = <0x10010400 0x100>;
+
+		gpio-controller;
+		gpio-ranges = <&pinctrl 0 128 32>;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <13>;
+	};
+
+	gpf: gpio-controller@10010500 {
+		compatible = "ingenic,jz4780-gpio";
+		reg = <0x10010500 0x100>;
+
+		gpio-controller;
+		gpio-ranges = <&pinctrl 0 160 32>;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <12>;
+	};
+
 	uart0: serial@10030000 {
 		compatible = "ingenic,jz4780-uart";
 		reg = <0x10030000 0x100>;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v2 08/14] MIPS: JZ4740: Qi LB60: Add pinctrl configuration for several drivers
  2017-01-22 14:49     ` [PATCH v2 00/14] " Paul Cercueil
                         ` (6 preceding siblings ...)
  2017-01-22 14:49       ` [PATCH v2 07/14] MIPS: jz4780: " Paul Cercueil
@ 2017-01-22 14:49       ` Paul Cercueil
  2017-01-22 14:49       ` [PATCH v2 09/14] MIPS: JZ4780: CI20: " Paul Cercueil
                         ` (5 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-22 14:49 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

We set the pin configuration for the jz4740-nand, jz4740-mmc,
jz4740-fb, jz4740-pwm and jz4740-uart drivers.

This will permit those drivers to be cleaned out of the custom GPIO code
that they currently use.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/boot/dts/ingenic/qi_lb60.dts | 13 +++++++++++
 arch/mips/jz4740/board-qi_lb60.c       | 42 ++++++++++++++++++++++++++--------
 2 files changed, 46 insertions(+), 9 deletions(-)

v2: Changed the devicetree bindings to match the new driver

diff --git a/arch/mips/boot/dts/ingenic/qi_lb60.dts b/arch/mips/boot/dts/ingenic/qi_lb60.dts
index be1a7d3a3e1b..b715ee2ac2ee 100644
--- a/arch/mips/boot/dts/ingenic/qi_lb60.dts
+++ b/arch/mips/boot/dts/ingenic/qi_lb60.dts
@@ -17,3 +17,16 @@
 &rtc_dev {
 	system-power-controller;
 };
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart0>;
+};
+
+&pinctrl {
+	pins_uart0: uart0 {
+		function = "uart0";
+		groups = "uart0-data";
+		bias-disable;
+	};
+};
diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c
index a5bd94b95263..bf3dcc9ee9f8 100644
--- a/arch/mips/jz4740/board-qi_lb60.c
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -22,6 +22,8 @@
 #include <linux/input/matrix_keypad.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_gpio.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf-generic.h>
 #include <linux/power_supply.h>
 #include <linux/power/jz4740-battery.h>
 #include <linux/power/gpio-charger.h>
@@ -447,13 +449,36 @@ static struct platform_device *jz_platform_devices[] __initdata = {
 	&qi_lb60_audio_device,
 };
 
-static void __init board_gpio_setup(void)
-{
-	/* We only need to enable/disable pullup here for pins used in generic
-	 * drivers. Everything else is done by the drivers themselves. */
-	jz_gpio_disable_pullup(QI_LB60_GPIO_SD_VCC_EN_N);
-	jz_gpio_disable_pullup(QI_LB60_GPIO_SD_CD);
-}
+static unsigned long pin_cfg_bias_disable[] = {
+	    PIN_CONFIG_BIAS_DISABLE,
+};
+
+static struct pinctrl_map pin_map[] __initdata = {
+	/* NAND pin configuration */
+	PIN_MAP_MUX_GROUP_DEFAULT("jz4740-nand",
+			"10010000.jz4740-pinctrl", "nand", "nand"),
+
+	/* fbdev pin configuration */
+	PIN_MAP_MUX_GROUP("jz4740-fb", PINCTRL_STATE_DEFAULT,
+			"10010000.jz4740-pinctrl", "lcd", "lcd-8bit"),
+	PIN_MAP_MUX_GROUP("jz4740-fb", PINCTRL_STATE_SLEEP,
+			"10010000.jz4740-pinctrl", "lcd", "lcd-no-pins"),
+
+	/* MMC pin configuration */
+	PIN_MAP_MUX_GROUP_DEFAULT("jz4740-mmc.0",
+			"10010000.jz4740-pinctrl", "mmc", "mmc-1bit"),
+	PIN_MAP_MUX_GROUP_DEFAULT("jz4740-mmc.0",
+			"10010000.jz4740-pinctrl", "mmc", "mmc-4bit"),
+	PIN_MAP_CONFIGS_PIN_DEFAULT("jz4740-mmc.0",
+			"10010000.jz4740-pinctrl", "PD0", pin_cfg_bias_disable),
+	PIN_MAP_CONFIGS_PIN_DEFAULT("jz4740-mmc.0",
+			"10010000.jz4740-pinctrl", "PD2", pin_cfg_bias_disable),
+
+	/* PWM pin configuration */
+	PIN_MAP_MUX_GROUP_DEFAULT("jz4740-pwm",
+			"10010000.jz4740-pinctrl", "pwm4", "pwm4"),
+};
+
 
 static int __init qi_lb60_init_platform_devices(void)
 {
@@ -469,6 +494,7 @@ static int __init qi_lb60_init_platform_devices(void)
 				ARRAY_SIZE(qi_lb60_spi_board_info));
 
 	pwm_add_table(qi_lb60_pwm_lookup, ARRAY_SIZE(qi_lb60_pwm_lookup));
+	pinctrl_register_mappings(pin_map, ARRAY_SIZE(pin_map));
 
 	return platform_add_devices(jz_platform_devices,
 					ARRAY_SIZE(jz_platform_devices));
@@ -479,8 +505,6 @@ static int __init qi_lb60_board_setup(void)
 {
 	printk(KERN_INFO "Qi Hardware JZ4740 QI LB60 setup\n");
 
-	board_gpio_setup();
-
 	if (qi_lb60_init_platform_devices())
 		panic("Failed to initialize platform devices");
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v2 09/14] MIPS: JZ4780: CI20: Add pinctrl configuration for several drivers
  2017-01-22 14:49     ` [PATCH v2 00/14] " Paul Cercueil
                         ` (7 preceding siblings ...)
  2017-01-22 14:49       ` [PATCH v2 08/14] MIPS: JZ4740: Qi LB60: Add pinctrl configuration for several drivers Paul Cercueil
@ 2017-01-22 14:49       ` Paul Cercueil
  2017-01-22 14:49       ` [PATCH v2 10/14] mmc: jz4740: Let the pinctrl driver configure the pins Paul Cercueil
                         ` (4 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-22 14:49 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

We set the pin configuration for the jz4780-nand and jz4780-uart
drivers.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/boot/dts/ingenic/ci20.dts | 60 +++++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

v2: Changed the devicetree bindings to match the new driver

diff --git a/arch/mips/boot/dts/ingenic/ci20.dts b/arch/mips/boot/dts/ingenic/ci20.dts
index 1652d8d60b1e..fd138d9978c1 100644
--- a/arch/mips/boot/dts/ingenic/ci20.dts
+++ b/arch/mips/boot/dts/ingenic/ci20.dts
@@ -29,18 +29,30 @@
 
 &uart0 {
 	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart0>;
 };
 
 &uart1 {
 	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart1>;
 };
 
 &uart3 {
 	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart2>;
 };
 
 &uart4 {
 	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart4>;
 };
 
 &nemc {
@@ -61,6 +73,13 @@
 		ingenic,nemc-tAW = <15>;
 		ingenic,nemc-tSTRV = <100>;
 
+		/*
+		 * Only CLE/ALE are needed for the devices that are connected, rather
+		 * than the full address line set.
+		 */
+		pinctrl-names = "default";
+		pinctrl-0 = <&pins_nemc>;
+
 		nand@1 {
 			reg = <1>;
 
@@ -69,6 +88,9 @@
 			nand-ecc-mode = "hw";
 			nand-on-flash-bbt;
 
+			pinctrl-names = "default";
+			pinctrl-0 = <&pins_nemc_cs1>;
+
 			partitions {
 				compatible = "fixed-partitions";
 				#address-cells = <2>;
@@ -106,3 +128,41 @@
 &bch {
 	status = "okay";
 };
+
+&pinctrl {
+	pins_uart0: uart0 {
+		function = "uart0";
+		groups = "uart0-data";
+		bias-disable;
+	};
+
+	pins_uart1: uart1 {
+		function = "uart1";
+		groups = "uart1-data";
+		bias-disable;
+	};
+
+	pins_uart2: uart2 {
+		function = "uart2";
+		groups = "uart2-data", "uart2-hwflow";
+		bias-disable;
+	};
+
+	pins_uart4: uart4 {
+		function = "uart4";
+		groups = "uart4-data";
+		bias-disable;
+	};
+
+	pins_nemc: nemc {
+		function = "nemc";
+		groups = "nemc-data", "nemc-cle-ale", "nemc-rd-we", "nemc-frd-fwe";
+		bias-disable;
+	};
+
+	pins_nemc_cs1: nemc-cs1 {
+		function = "nemc-cs1";
+		groups = "nemc-cs1";
+		bias-disable;
+	};
+};
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v2 10/14] mmc: jz4740: Let the pinctrl driver configure the pins
  2017-01-22 14:49     ` [PATCH v2 00/14] " Paul Cercueil
                         ` (8 preceding siblings ...)
  2017-01-22 14:49       ` [PATCH v2 09/14] MIPS: JZ4780: CI20: " Paul Cercueil
@ 2017-01-22 14:49       ` Paul Cercueil
  2017-01-23 10:40         ` Ulf Hansson
  2017-01-22 14:49       ` [PATCH v2 11/14] mtd: nand: " Paul Cercueil
                         ` (3 subsequent siblings)
  13 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-01-22 14:49 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
the pins being properly configured before the driver probes.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/mmc/host/jz4740_mmc.c | 45 +++++--------------------------------------
 1 file changed, 5 insertions(+), 40 deletions(-)

v2: Set pin sleep/default state in suspend/resume callbacks

diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c
index 819ad32964fc..b5fec5b7ee7b 100644
--- a/drivers/mmc/host/jz4740_mmc.c
+++ b/drivers/mmc/host/jz4740_mmc.c
@@ -20,14 +20,13 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/scatterlist.h>
 #include <linux/clk.h>
 
 #include <linux/bitops.h>
-#include <linux/gpio.h>
-#include <asm/mach-jz4740/gpio.h>
 #include <asm/cacheflush.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
@@ -906,15 +905,6 @@ static const struct mmc_host_ops jz4740_mmc_ops = {
 	.enable_sdio_irq = jz4740_mmc_enable_sdio_irq,
 };
 
-static const struct jz_gpio_bulk_request jz4740_mmc_pins[] = {
-	JZ_GPIO_BULK_PIN(MSC_CMD),
-	JZ_GPIO_BULK_PIN(MSC_CLK),
-	JZ_GPIO_BULK_PIN(MSC_DATA0),
-	JZ_GPIO_BULK_PIN(MSC_DATA1),
-	JZ_GPIO_BULK_PIN(MSC_DATA2),
-	JZ_GPIO_BULK_PIN(MSC_DATA3),
-};
-
 static int jz4740_mmc_request_gpio(struct device *dev, int gpio,
 	const char *name, bool output, int value)
 {
@@ -978,15 +968,6 @@ static void jz4740_mmc_free_gpios(struct platform_device *pdev)
 		gpio_free(pdata->gpio_power);
 }
 
-static inline size_t jz4740_mmc_num_pins(struct jz4740_mmc_host *host)
-{
-	size_t num_pins = ARRAY_SIZE(jz4740_mmc_pins);
-	if (host->pdata && host->pdata->data_1bit)
-		num_pins -= 3;
-
-	return num_pins;
-}
-
 static int jz4740_mmc_probe(struct platform_device* pdev)
 {
 	int ret;
@@ -1027,15 +1008,9 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
 		goto err_free_host;
 	}
 
-	ret = jz_gpio_bulk_request(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
-	if (ret) {
-		dev_err(&pdev->dev, "Failed to request mmc pins: %d\n", ret);
-		goto err_free_host;
-	}
-
 	ret = jz4740_mmc_request_gpios(mmc, pdev);
 	if (ret)
-		goto err_gpio_bulk_free;
+		goto err_release_dma;
 
 	mmc->ops = &jz4740_mmc_ops;
 	mmc->f_min = JZ_MMC_CLK_RATE / 128;
@@ -1091,10 +1066,9 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
 	free_irq(host->irq, host);
 err_free_gpios:
 	jz4740_mmc_free_gpios(pdev);
-err_gpio_bulk_free:
+err_release_dma:
 	if (host->use_dma)
 		jz4740_mmc_release_dma_channels(host);
-	jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
 err_free_host:
 	mmc_free_host(mmc);
 
@@ -1114,7 +1088,6 @@ static int jz4740_mmc_remove(struct platform_device *pdev)
 	free_irq(host->irq, host);
 
 	jz4740_mmc_free_gpios(pdev);
-	jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
 
 	if (host->use_dma)
 		jz4740_mmc_release_dma_channels(host);
@@ -1128,20 +1101,12 @@ static int jz4740_mmc_remove(struct platform_device *pdev)
 
 static int jz4740_mmc_suspend(struct device *dev)
 {
-	struct jz4740_mmc_host *host = dev_get_drvdata(dev);
-
-	jz_gpio_bulk_suspend(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
-
-	return 0;
+	return pinctrl_pm_select_sleep_state(dev);
 }
 
 static int jz4740_mmc_resume(struct device *dev)
 {
-	struct jz4740_mmc_host *host = dev_get_drvdata(dev);
-
-	jz_gpio_bulk_resume(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
-
-	return 0;
+	return pinctrl_pm_select_default_state(dev);
 }
 
 static SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend,
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v2 11/14] mtd: nand: jz4740: Let the pinctrl driver configure the pins
  2017-01-22 14:49     ` [PATCH v2 00/14] " Paul Cercueil
                         ` (9 preceding siblings ...)
  2017-01-22 14:49       ` [PATCH v2 10/14] mmc: jz4740: Let the pinctrl driver configure the pins Paul Cercueil
@ 2017-01-22 14:49       ` Paul Cercueil
  2017-01-22 14:49       ` [PATCH v2 12/14] fbdev: jz4740-fb: " Paul Cercueil
                         ` (2 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-22 14:49 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

Before, this NAND driver would set itself the configuration of the
chip-select pins for the various NAND banks.

Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
the pins being properly configured before the driver probes.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/mtd/nand/jz4740_nand.c | 23 +----------------------
 1 file changed, 1 insertion(+), 22 deletions(-)

v2: No changes

diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
index 5551c36adbdf..0d06a1f07d82 100644
--- a/drivers/mtd/nand/jz4740_nand.c
+++ b/drivers/mtd/nand/jz4740_nand.c
@@ -25,7 +25,6 @@
 
 #include <linux/gpio.h>
 
-#include <asm/mach-jz4740/gpio.h>
 #include <asm/mach-jz4740/jz4740_nand.h>
 
 #define JZ_REG_NAND_CTRL	0x50
@@ -310,34 +309,20 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
 			       uint8_t *nand_dev_id)
 {
 	int ret;
-	int gpio;
-	char gpio_name[9];
 	char res_name[6];
 	uint32_t ctrl;
 	struct nand_chip *chip = &nand->chip;
 	struct mtd_info *mtd = nand_to_mtd(chip);
 
-	/* Request GPIO port. */
-	gpio = JZ_GPIO_MEM_CS0 + bank - 1;
-	sprintf(gpio_name, "NAND CS%d", bank);
-	ret = gpio_request(gpio, gpio_name);
-	if (ret) {
-		dev_warn(&pdev->dev,
-			"Failed to request %s gpio %d: %d\n",
-			gpio_name, gpio, ret);
-		goto notfound_gpio;
-	}
-
 	/* Request I/O resource. */
 	sprintf(res_name, "bank%d", bank);
 	ret = jz_nand_ioremap_resource(pdev, res_name,
 					&nand->bank_mem[bank - 1],
 					&nand->bank_base[bank - 1]);
 	if (ret)
-		goto notfound_resource;
+		return ret;
 
 	/* Enable chip in bank. */
-	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_MEM_CS0);
 	ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
 	ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1);
 	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
@@ -377,12 +362,8 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
 	dev_info(&pdev->dev, "No chip found on bank %i\n", bank);
 	ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1));
 	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
-	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE);
 	jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
 				 nand->bank_base[bank - 1]);
-notfound_resource:
-	gpio_free(gpio);
-notfound_gpio:
 	return ret;
 }
 
@@ -503,7 +484,6 @@ static int jz_nand_probe(struct platform_device *pdev)
 err_unclaim_banks:
 	while (chipnr--) {
 		unsigned char bank = nand->banks[chipnr];
-		gpio_free(JZ_GPIO_MEM_CS0 + bank - 1);
 		jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
 					 nand->bank_base[bank - 1]);
 	}
@@ -530,7 +510,6 @@ static int jz_nand_remove(struct platform_device *pdev)
 		if (bank != 0) {
 			jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
 						 nand->bank_base[bank - 1]);
-			gpio_free(JZ_GPIO_MEM_CS0 + bank - 1);
 		}
 	}
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v2 12/14] fbdev: jz4740-fb: Let the pinctrl driver configure the pins
  2017-01-22 14:49     ` [PATCH v2 00/14] " Paul Cercueil
                         ` (10 preceding siblings ...)
  2017-01-22 14:49       ` [PATCH v2 11/14] mtd: nand: " Paul Cercueil
@ 2017-01-22 14:49       ` Paul Cercueil
  2017-01-22 14:49       ` [PATCH v2 13/14] pwm: jz4740: " Paul Cercueil
  2017-01-22 14:49       ` [PATCH v2 14/14] MIPS: jz4740: Remove custom GPIO code Paul Cercueil
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-22 14:49 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
the pins being properly configured before the driver probes.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/video/fbdev/jz4740_fb.c | 104 ++--------------------------------------
 1 file changed, 3 insertions(+), 101 deletions(-)

v2: No changes

diff --git a/drivers/video/fbdev/jz4740_fb.c b/drivers/video/fbdev/jz4740_fb.c
index 87790e9644d0..b57df83fdbd3 100644
--- a/drivers/video/fbdev/jz4740_fb.c
+++ b/drivers/video/fbdev/jz4740_fb.c
@@ -17,6 +17,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
 
 #include <linux/clk.h>
 #include <linux/delay.h>
@@ -27,7 +28,6 @@
 #include <linux/dma-mapping.h>
 
 #include <asm/mach-jz4740/jz4740_fb.h>
-#include <asm/mach-jz4740/gpio.h>
 
 #define JZ_REG_LCD_CFG		0x00
 #define JZ_REG_LCD_VSYNC	0x04
@@ -146,93 +146,6 @@ static const struct fb_fix_screeninfo jzfb_fix = {
 	.accel		= FB_ACCEL_NONE,
 };
 
-static const struct jz_gpio_bulk_request jz_lcd_ctrl_pins[] = {
-	JZ_GPIO_BULK_PIN(LCD_PCLK),
-	JZ_GPIO_BULK_PIN(LCD_HSYNC),
-	JZ_GPIO_BULK_PIN(LCD_VSYNC),
-	JZ_GPIO_BULK_PIN(LCD_DE),
-	JZ_GPIO_BULK_PIN(LCD_PS),
-	JZ_GPIO_BULK_PIN(LCD_REV),
-	JZ_GPIO_BULK_PIN(LCD_CLS),
-	JZ_GPIO_BULK_PIN(LCD_SPL),
-};
-
-static const struct jz_gpio_bulk_request jz_lcd_data_pins[] = {
-	JZ_GPIO_BULK_PIN(LCD_DATA0),
-	JZ_GPIO_BULK_PIN(LCD_DATA1),
-	JZ_GPIO_BULK_PIN(LCD_DATA2),
-	JZ_GPIO_BULK_PIN(LCD_DATA3),
-	JZ_GPIO_BULK_PIN(LCD_DATA4),
-	JZ_GPIO_BULK_PIN(LCD_DATA5),
-	JZ_GPIO_BULK_PIN(LCD_DATA6),
-	JZ_GPIO_BULK_PIN(LCD_DATA7),
-	JZ_GPIO_BULK_PIN(LCD_DATA8),
-	JZ_GPIO_BULK_PIN(LCD_DATA9),
-	JZ_GPIO_BULK_PIN(LCD_DATA10),
-	JZ_GPIO_BULK_PIN(LCD_DATA11),
-	JZ_GPIO_BULK_PIN(LCD_DATA12),
-	JZ_GPIO_BULK_PIN(LCD_DATA13),
-	JZ_GPIO_BULK_PIN(LCD_DATA14),
-	JZ_GPIO_BULK_PIN(LCD_DATA15),
-	JZ_GPIO_BULK_PIN(LCD_DATA16),
-	JZ_GPIO_BULK_PIN(LCD_DATA17),
-};
-
-static unsigned int jzfb_num_ctrl_pins(struct jzfb *jzfb)
-{
-	unsigned int num;
-
-	switch (jzfb->pdata->lcd_type) {
-	case JZ_LCD_TYPE_GENERIC_16_BIT:
-		num = 4;
-		break;
-	case JZ_LCD_TYPE_GENERIC_18_BIT:
-		num = 4;
-		break;
-	case JZ_LCD_TYPE_8BIT_SERIAL:
-		num = 3;
-		break;
-	case JZ_LCD_TYPE_SPECIAL_TFT_1:
-	case JZ_LCD_TYPE_SPECIAL_TFT_2:
-	case JZ_LCD_TYPE_SPECIAL_TFT_3:
-		num = 8;
-		break;
-	default:
-		num = 0;
-		break;
-	}
-	return num;
-}
-
-static unsigned int jzfb_num_data_pins(struct jzfb *jzfb)
-{
-	unsigned int num;
-
-	switch (jzfb->pdata->lcd_type) {
-	case JZ_LCD_TYPE_GENERIC_16_BIT:
-		num = 16;
-		break;
-	case JZ_LCD_TYPE_GENERIC_18_BIT:
-		num = 18;
-		break;
-	case JZ_LCD_TYPE_8BIT_SERIAL:
-		num = 8;
-		break;
-	case JZ_LCD_TYPE_SPECIAL_TFT_1:
-	case JZ_LCD_TYPE_SPECIAL_TFT_2:
-	case JZ_LCD_TYPE_SPECIAL_TFT_3:
-		if (jzfb->pdata->bpp == 18)
-			num = 18;
-		else
-			num = 16;
-		break;
-	default:
-		num = 0;
-		break;
-	}
-	return num;
-}
-
 /* Based on CNVT_TOHW macro from skeletonfb.c */
 static inline uint32_t jzfb_convert_color_to_hw(unsigned val,
 	struct fb_bitfield *bf)
@@ -487,8 +400,7 @@ static void jzfb_enable(struct jzfb *jzfb)
 
 	clk_prepare_enable(jzfb->ldclk);
 
-	jz_gpio_bulk_resume(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_resume(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
+	pinctrl_pm_select_default_state(&jzfb->pdev->dev);
 
 	writel(0, jzfb->base + JZ_REG_LCD_STATE);
 
@@ -511,8 +423,7 @@ static void jzfb_disable(struct jzfb *jzfb)
 		ctrl = readl(jzfb->base + JZ_REG_LCD_STATE);
 	} while (!(ctrl & JZ_LCD_STATE_DISABLED));
 
-	jz_gpio_bulk_suspend(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_suspend(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
+	pinctrl_pm_select_sleep_state(&jzfb->pdev->dev);
 
 	clk_disable_unprepare(jzfb->ldclk);
 }
@@ -701,9 +612,6 @@ static int jzfb_probe(struct platform_device *pdev)
 	fb->mode = NULL;
 	jzfb_set_par(fb);
 
-	jz_gpio_bulk_request(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_request(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
-
 	ret = register_framebuffer(fb);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to register framebuffer: %d\n", ret);
@@ -715,9 +623,6 @@ static int jzfb_probe(struct platform_device *pdev)
 	return 0;
 
 err_free_devmem:
-	jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
-
 	fb_dealloc_cmap(&fb->cmap);
 	jzfb_free_devmem(jzfb);
 err_framebuffer_release:
@@ -731,9 +636,6 @@ static int jzfb_remove(struct platform_device *pdev)
 
 	jzfb_blank(FB_BLANK_POWERDOWN, jzfb->fb);
 
-	jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
-
 	fb_dealloc_cmap(&jzfb->fb->cmap);
 	jzfb_free_devmem(jzfb);
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v2 13/14] pwm: jz4740: Let the pinctrl driver configure the pins
  2017-01-22 14:49     ` [PATCH v2 00/14] " Paul Cercueil
                         ` (11 preceding siblings ...)
  2017-01-22 14:49       ` [PATCH v2 12/14] fbdev: jz4740-fb: " Paul Cercueil
@ 2017-01-22 14:49       ` Paul Cercueil
  2017-01-22 14:49       ` [PATCH v2 14/14] MIPS: jz4740: Remove custom GPIO code Paul Cercueil
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-22 14:49 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
the pins being properly configured before the driver probes.

One inherent problem of this new approach is that the pinctrl framework
does not allow us to configure each pin on demand, when the various PWM
channels are requested or released. For instance, the PWM channels can
be configured from sysfs, which would require all PWM pins to be configured
properly beforehand for the PWM function, eventually causing conflicts
with other platform or board drivers.

The proper solution here would be to modify the pwm-jz4740 driver to
handle only one PWM channel, and create an instance of this driver
for each one of the 8 PWM channels. Then, it could use the pinctrl
framework to dynamically configure the PWM pin it controls.

Until this can be done, the only jz4740 board supported upstream
(Qi lb60) can configure all of its connected PWM pins in PWM function
mode, since those are not used by other drivers nor by GPIOs on the
board.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/pwm/pwm-jz4740.c | 29 -----------------------------
 1 file changed, 29 deletions(-)

v2: No changes

diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c
index 76d13150283f..a75ff3622450 100644
--- a/drivers/pwm/pwm-jz4740.c
+++ b/drivers/pwm/pwm-jz4740.c
@@ -21,22 +21,10 @@
 #include <linux/platform_device.h>
 #include <linux/pwm.h>
 
-#include <asm/mach-jz4740/gpio.h>
 #include <asm/mach-jz4740/timer.h>
 
 #define NUM_PWM 8
 
-static const unsigned int jz4740_pwm_gpio_list[NUM_PWM] = {
-	JZ_GPIO_PWM0,
-	JZ_GPIO_PWM1,
-	JZ_GPIO_PWM2,
-	JZ_GPIO_PWM3,
-	JZ_GPIO_PWM4,
-	JZ_GPIO_PWM5,
-	JZ_GPIO_PWM6,
-	JZ_GPIO_PWM7,
-};
-
 struct jz4740_pwm_chip {
 	struct pwm_chip chip;
 	struct clk *clk;
@@ -49,9 +37,6 @@ static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip)
 
 static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-	unsigned int gpio = jz4740_pwm_gpio_list[pwm->hwpwm];
-	int ret;
-
 	/*
 	 * Timers 0 and 1 are used for system tasks, so they are unavailable
 	 * for use as PWMs.
@@ -59,15 +44,6 @@ static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 	if (pwm->hwpwm < 2)
 		return -EBUSY;
 
-	ret = gpio_request(gpio, pwm->label);
-	if (ret) {
-		dev_err(chip->dev, "Failed to request GPIO#%u for PWM: %d\n",
-			gpio, ret);
-		return ret;
-	}
-
-	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_PWM);
-
 	jz4740_timer_start(pwm->hwpwm);
 
 	return 0;
@@ -75,13 +51,8 @@ static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 
 static void jz4740_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-	unsigned int gpio = jz4740_pwm_gpio_list[pwm->hwpwm];
-
 	jz4740_timer_set_ctrl(pwm->hwpwm, 0);
 
-	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE);
-	gpio_free(gpio);
-
 	jz4740_timer_stop(pwm->hwpwm);
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v2 14/14] MIPS: jz4740: Remove custom GPIO code
  2017-01-22 14:49     ` [PATCH v2 00/14] " Paul Cercueil
                         ` (12 preceding siblings ...)
  2017-01-22 14:49       ` [PATCH v2 13/14] pwm: jz4740: " Paul Cercueil
@ 2017-01-22 14:49       ` Paul Cercueil
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-22 14:49 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

All the drivers for the various hardware elements of the jz4740 SoC have
been modified to use the pinctrl framework for their pin configuration
needs.
As such, this platform code is now unused and can be deleted.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/include/asm/mach-jz4740/gpio.h | 371 ----------------------
 arch/mips/jz4740/Makefile                |   2 -
 arch/mips/jz4740/gpio.c                  | 519 -------------------------------
 3 files changed, 892 deletions(-)
 delete mode 100644 arch/mips/jz4740/gpio.c

v2: No changes

diff --git a/arch/mips/include/asm/mach-jz4740/gpio.h b/arch/mips/include/asm/mach-jz4740/gpio.h
index 7c7708a23baa..fd847c984701 100644
--- a/arch/mips/include/asm/mach-jz4740/gpio.h
+++ b/arch/mips/include/asm/mach-jz4740/gpio.h
@@ -16,380 +16,9 @@
 #ifndef _JZ_GPIO_H
 #define _JZ_GPIO_H
 
-#include <linux/types.h>
-
-enum jz_gpio_function {
-    JZ_GPIO_FUNC_NONE,
-    JZ_GPIO_FUNC1,
-    JZ_GPIO_FUNC2,
-    JZ_GPIO_FUNC3,
-};
-
-/*
- Usually a driver for a SoC component has to request several gpio pins and
- configure them as function pins.
- jz_gpio_bulk_request can be used to ease this process.
- Usually one would do something like:
-
- static const struct jz_gpio_bulk_request i2c_pins[] = {
-	JZ_GPIO_BULK_PIN(I2C_SDA),
-	JZ_GPIO_BULK_PIN(I2C_SCK),
- };
-
- inside the probe function:
-
-    ret = jz_gpio_bulk_request(i2c_pins, ARRAY_SIZE(i2c_pins));
-    if (ret) {
-	...
-
- inside the remove function:
-
-    jz_gpio_bulk_free(i2c_pins, ARRAY_SIZE(i2c_pins));
-
-*/
-
-struct jz_gpio_bulk_request {
-	int gpio;
-	const char *name;
-	enum jz_gpio_function function;
-};
-
-#define JZ_GPIO_BULK_PIN(pin) { \
-    .gpio = JZ_GPIO_ ## pin, \
-    .name = #pin, \
-    .function = JZ_GPIO_FUNC_ ## pin \
-}
-
-int jz_gpio_bulk_request(const struct jz_gpio_bulk_request *request, size_t num);
-void jz_gpio_bulk_free(const struct jz_gpio_bulk_request *request, size_t num);
-void jz_gpio_bulk_suspend(const struct jz_gpio_bulk_request *request, size_t num);
-void jz_gpio_bulk_resume(const struct jz_gpio_bulk_request *request, size_t num);
-void jz_gpio_enable_pullup(unsigned gpio);
-void jz_gpio_disable_pullup(unsigned gpio);
-int jz_gpio_set_function(int gpio, enum jz_gpio_function function);
-
-int jz_gpio_port_direction_input(int port, uint32_t mask);
-int jz_gpio_port_direction_output(int port, uint32_t mask);
-void jz_gpio_port_set_value(int port, uint32_t value, uint32_t mask);
-uint32_t jz_gpio_port_get_value(int port, uint32_t mask);
-
 #define JZ_GPIO_PORTA(x) ((x) + 32 * 0)
 #define JZ_GPIO_PORTB(x) ((x) + 32 * 1)
 #define JZ_GPIO_PORTC(x) ((x) + 32 * 2)
 #define JZ_GPIO_PORTD(x) ((x) + 32 * 3)
 
-/* Port A function pins */
-#define JZ_GPIO_MEM_DATA0		JZ_GPIO_PORTA(0)
-#define JZ_GPIO_MEM_DATA1		JZ_GPIO_PORTA(1)
-#define JZ_GPIO_MEM_DATA2		JZ_GPIO_PORTA(2)
-#define JZ_GPIO_MEM_DATA3		JZ_GPIO_PORTA(3)
-#define JZ_GPIO_MEM_DATA4		JZ_GPIO_PORTA(4)
-#define JZ_GPIO_MEM_DATA5		JZ_GPIO_PORTA(5)
-#define JZ_GPIO_MEM_DATA6		JZ_GPIO_PORTA(6)
-#define JZ_GPIO_MEM_DATA7		JZ_GPIO_PORTA(7)
-#define JZ_GPIO_MEM_DATA8		JZ_GPIO_PORTA(8)
-#define JZ_GPIO_MEM_DATA9		JZ_GPIO_PORTA(9)
-#define JZ_GPIO_MEM_DATA10		JZ_GPIO_PORTA(10)
-#define JZ_GPIO_MEM_DATA11		JZ_GPIO_PORTA(11)
-#define JZ_GPIO_MEM_DATA12		JZ_GPIO_PORTA(12)
-#define JZ_GPIO_MEM_DATA13		JZ_GPIO_PORTA(13)
-#define JZ_GPIO_MEM_DATA14		JZ_GPIO_PORTA(14)
-#define JZ_GPIO_MEM_DATA15		JZ_GPIO_PORTA(15)
-#define JZ_GPIO_MEM_DATA16		JZ_GPIO_PORTA(16)
-#define JZ_GPIO_MEM_DATA17		JZ_GPIO_PORTA(17)
-#define JZ_GPIO_MEM_DATA18		JZ_GPIO_PORTA(18)
-#define JZ_GPIO_MEM_DATA19		JZ_GPIO_PORTA(19)
-#define JZ_GPIO_MEM_DATA20		JZ_GPIO_PORTA(20)
-#define JZ_GPIO_MEM_DATA21		JZ_GPIO_PORTA(21)
-#define JZ_GPIO_MEM_DATA22		JZ_GPIO_PORTA(22)
-#define JZ_GPIO_MEM_DATA23		JZ_GPIO_PORTA(23)
-#define JZ_GPIO_MEM_DATA24		JZ_GPIO_PORTA(24)
-#define JZ_GPIO_MEM_DATA25		JZ_GPIO_PORTA(25)
-#define JZ_GPIO_MEM_DATA26		JZ_GPIO_PORTA(26)
-#define JZ_GPIO_MEM_DATA27		JZ_GPIO_PORTA(27)
-#define JZ_GPIO_MEM_DATA28		JZ_GPIO_PORTA(28)
-#define JZ_GPIO_MEM_DATA29		JZ_GPIO_PORTA(29)
-#define JZ_GPIO_MEM_DATA30		JZ_GPIO_PORTA(30)
-#define JZ_GPIO_MEM_DATA31		JZ_GPIO_PORTA(31)
-
-#define JZ_GPIO_FUNC_MEM_DATA0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA4		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA5		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA6		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA7		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA8		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA9		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA10		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA11		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA12		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA13		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA14		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA15		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA16		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA17		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA18		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA19		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA20		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA21		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA22		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA23		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA24		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA25		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA26		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA27		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA28		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA29		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA30		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA31		JZ_GPIO_FUNC1
-
-/* Port B function pins */
-#define JZ_GPIO_MEM_ADDR0		JZ_GPIO_PORTB(0)
-#define JZ_GPIO_MEM_ADDR1		JZ_GPIO_PORTB(1)
-#define JZ_GPIO_MEM_ADDR2		JZ_GPIO_PORTB(2)
-#define JZ_GPIO_MEM_ADDR3		JZ_GPIO_PORTB(3)
-#define JZ_GPIO_MEM_ADDR4		JZ_GPIO_PORTB(4)
-#define JZ_GPIO_MEM_ADDR5		JZ_GPIO_PORTB(5)
-#define JZ_GPIO_MEM_ADDR6		JZ_GPIO_PORTB(6)
-#define JZ_GPIO_MEM_ADDR7		JZ_GPIO_PORTB(7)
-#define JZ_GPIO_MEM_ADDR8		JZ_GPIO_PORTB(8)
-#define JZ_GPIO_MEM_ADDR9		JZ_GPIO_PORTB(9)
-#define JZ_GPIO_MEM_ADDR10		JZ_GPIO_PORTB(10)
-#define JZ_GPIO_MEM_ADDR11		JZ_GPIO_PORTB(11)
-#define JZ_GPIO_MEM_ADDR12		JZ_GPIO_PORTB(12)
-#define JZ_GPIO_MEM_ADDR13		JZ_GPIO_PORTB(13)
-#define JZ_GPIO_MEM_ADDR14		JZ_GPIO_PORTB(14)
-#define JZ_GPIO_MEM_ADDR15		JZ_GPIO_PORTB(15)
-#define JZ_GPIO_MEM_ADDR16		JZ_GPIO_PORTB(16)
-#define JZ_GPIO_LCD_CLS			JZ_GPIO_PORTB(17)
-#define JZ_GPIO_LCD_SPL			JZ_GPIO_PORTB(18)
-#define JZ_GPIO_MEM_DCS			JZ_GPIO_PORTB(19)
-#define JZ_GPIO_MEM_RAS			JZ_GPIO_PORTB(20)
-#define JZ_GPIO_MEM_CAS			JZ_GPIO_PORTB(21)
-#define JZ_GPIO_MEM_SDWE		JZ_GPIO_PORTB(22)
-#define JZ_GPIO_MEM_CKE			JZ_GPIO_PORTB(23)
-#define JZ_GPIO_MEM_CKO			JZ_GPIO_PORTB(24)
-#define JZ_GPIO_MEM_CS0			JZ_GPIO_PORTB(25)
-#define JZ_GPIO_MEM_CS1			JZ_GPIO_PORTB(26)
-#define JZ_GPIO_MEM_CS2			JZ_GPIO_PORTB(27)
-#define JZ_GPIO_MEM_CS3			JZ_GPIO_PORTB(28)
-#define JZ_GPIO_MEM_RD			JZ_GPIO_PORTB(29)
-#define JZ_GPIO_MEM_WR			JZ_GPIO_PORTB(30)
-#define JZ_GPIO_MEM_WE0			JZ_GPIO_PORTB(31)
-
-#define JZ_GPIO_FUNC_MEM_ADDR0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR4		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR5		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR6		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR7		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR8		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR9		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR10		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR11		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR12		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR13		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR14		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR15		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR16		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_CLS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_SPL		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DCS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_RAS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CAS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_SDWE		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CKE		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CKO		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CS0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CS1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CS2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CS3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_RD		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WR		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WE0		JZ_GPIO_FUNC1
-
-
-#define JZ_GPIO_MEM_ADDR21		JZ_GPIO_PORTB(17)
-#define JZ_GPIO_MEM_ADDR22		JZ_GPIO_PORTB(18)
-
-#define JZ_GPIO_FUNC_MEM_ADDR21		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_ADDR22		JZ_GPIO_FUNC2
-
-/* Port C function pins */
-#define JZ_GPIO_LCD_DATA0		JZ_GPIO_PORTC(0)
-#define JZ_GPIO_LCD_DATA1		JZ_GPIO_PORTC(1)
-#define JZ_GPIO_LCD_DATA2		JZ_GPIO_PORTC(2)
-#define JZ_GPIO_LCD_DATA3		JZ_GPIO_PORTC(3)
-#define JZ_GPIO_LCD_DATA4		JZ_GPIO_PORTC(4)
-#define JZ_GPIO_LCD_DATA5		JZ_GPIO_PORTC(5)
-#define JZ_GPIO_LCD_DATA6		JZ_GPIO_PORTC(6)
-#define JZ_GPIO_LCD_DATA7		JZ_GPIO_PORTC(7)
-#define JZ_GPIO_LCD_DATA8		JZ_GPIO_PORTC(8)
-#define JZ_GPIO_LCD_DATA9		JZ_GPIO_PORTC(9)
-#define JZ_GPIO_LCD_DATA10		JZ_GPIO_PORTC(10)
-#define JZ_GPIO_LCD_DATA11		JZ_GPIO_PORTC(11)
-#define JZ_GPIO_LCD_DATA12		JZ_GPIO_PORTC(12)
-#define JZ_GPIO_LCD_DATA13		JZ_GPIO_PORTC(13)
-#define JZ_GPIO_LCD_DATA14		JZ_GPIO_PORTC(14)
-#define JZ_GPIO_LCD_DATA15		JZ_GPIO_PORTC(15)
-#define JZ_GPIO_LCD_DATA16		JZ_GPIO_PORTC(16)
-#define JZ_GPIO_LCD_DATA17		JZ_GPIO_PORTC(17)
-#define JZ_GPIO_LCD_PCLK		JZ_GPIO_PORTC(18)
-#define JZ_GPIO_LCD_HSYNC		JZ_GPIO_PORTC(19)
-#define JZ_GPIO_LCD_VSYNC		JZ_GPIO_PORTC(20)
-#define JZ_GPIO_LCD_DE			JZ_GPIO_PORTC(21)
-#define JZ_GPIO_LCD_PS			JZ_GPIO_PORTC(22)
-#define JZ_GPIO_LCD_REV			JZ_GPIO_PORTC(23)
-#define JZ_GPIO_MEM_WE1			JZ_GPIO_PORTC(24)
-#define JZ_GPIO_MEM_WE2			JZ_GPIO_PORTC(25)
-#define JZ_GPIO_MEM_WE3			JZ_GPIO_PORTC(26)
-#define JZ_GPIO_MEM_WAIT		JZ_GPIO_PORTC(27)
-#define JZ_GPIO_MEM_FRE			JZ_GPIO_PORTC(28)
-#define JZ_GPIO_MEM_FWE			JZ_GPIO_PORTC(29)
-
-#define JZ_GPIO_FUNC_LCD_DATA0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA4		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA5		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA6		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA7		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA8		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA9		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA10		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA11		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA12		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA13		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA14		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA15		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA16		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA17		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_PCLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_VSYNC		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_HSYNC		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DE		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_PS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_REV		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WE1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WE2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WE3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WAIT		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_FRE		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_FWE		JZ_GPIO_FUNC1
-
-
-#define JZ_GPIO_MEM_ADDR19		JZ_GPIO_PORTB(22)
-#define JZ_GPIO_MEM_ADDR20		JZ_GPIO_PORTB(23)
-
-#define JZ_GPIO_FUNC_MEM_ADDR19		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_ADDR20		JZ_GPIO_FUNC2
-
-/* Port D function pins */
-#define JZ_GPIO_CIM_DATA0		JZ_GPIO_PORTD(0)
-#define JZ_GPIO_CIM_DATA1		JZ_GPIO_PORTD(1)
-#define JZ_GPIO_CIM_DATA2		JZ_GPIO_PORTD(2)
-#define JZ_GPIO_CIM_DATA3		JZ_GPIO_PORTD(3)
-#define JZ_GPIO_CIM_DATA4		JZ_GPIO_PORTD(4)
-#define JZ_GPIO_CIM_DATA5		JZ_GPIO_PORTD(5)
-#define JZ_GPIO_CIM_DATA6		JZ_GPIO_PORTD(6)
-#define JZ_GPIO_CIM_DATA7		JZ_GPIO_PORTD(7)
-#define JZ_GPIO_MSC_CMD			JZ_GPIO_PORTD(8)
-#define JZ_GPIO_MSC_CLK			JZ_GPIO_PORTD(9)
-#define JZ_GPIO_MSC_DATA0		JZ_GPIO_PORTD(10)
-#define JZ_GPIO_MSC_DATA1		JZ_GPIO_PORTD(11)
-#define JZ_GPIO_MSC_DATA2		JZ_GPIO_PORTD(12)
-#define JZ_GPIO_MSC_DATA3		JZ_GPIO_PORTD(13)
-#define JZ_GPIO_CIM_MCLK		JZ_GPIO_PORTD(14)
-#define JZ_GPIO_CIM_PCLK		JZ_GPIO_PORTD(15)
-#define JZ_GPIO_CIM_VSYNC		JZ_GPIO_PORTD(16)
-#define JZ_GPIO_CIM_HSYNC		JZ_GPIO_PORTD(17)
-#define JZ_GPIO_SPI_CLK			JZ_GPIO_PORTD(18)
-#define JZ_GPIO_SPI_CE0			JZ_GPIO_PORTD(19)
-#define JZ_GPIO_SPI_DT			JZ_GPIO_PORTD(20)
-#define JZ_GPIO_SPI_DR			JZ_GPIO_PORTD(21)
-#define JZ_GPIO_SPI_CE1			JZ_GPIO_PORTD(22)
-#define JZ_GPIO_PWM0			JZ_GPIO_PORTD(23)
-#define JZ_GPIO_PWM1			JZ_GPIO_PORTD(24)
-#define JZ_GPIO_PWM2			JZ_GPIO_PORTD(25)
-#define JZ_GPIO_PWM3			JZ_GPIO_PORTD(26)
-#define JZ_GPIO_PWM4			JZ_GPIO_PORTD(27)
-#define JZ_GPIO_PWM5			JZ_GPIO_PORTD(28)
-#define JZ_GPIO_PWM6			JZ_GPIO_PORTD(30)
-#define JZ_GPIO_PWM7			JZ_GPIO_PORTD(31)
-
-#define JZ_GPIO_FUNC_CIM_DATA		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_CIM_DATA0		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA1		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA2		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA3		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA4		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA5		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA6		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA7		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_MSC_CMD		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MSC_CLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MSC_DATA		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MSC_DATA0		JZ_GPIO_FUNC_MSC_DATA
-#define JZ_GPIO_FUNC_MSC_DATA1		JZ_GPIO_FUNC_MSC_DATA
-#define JZ_GPIO_FUNC_MSC_DATA2		JZ_GPIO_FUNC_MSC_DATA
-#define JZ_GPIO_FUNC_MSC_DATA3		JZ_GPIO_FUNC_MSC_DATA
-#define JZ_GPIO_FUNC_CIM_MCLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_CIM_PCLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_CIM_VSYNC		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_CIM_HSYNC		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_CLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_CE0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_DT		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_DR		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_CE1		JZ_GPIO_FUNC1
-
-#define JZ_GPIO_FUNC_PWM		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_PWM0		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM1		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM2		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM3		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM4		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM5		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM6		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM7		JZ_GPIO_FUNC_PWM
-
-#define JZ_GPIO_MEM_SCLK_RSTN		JZ_GPIO_PORTD(18)
-#define JZ_GPIO_MEM_BCLK		JZ_GPIO_PORTD(19)
-#define JZ_GPIO_MEM_SDATO		JZ_GPIO_PORTD(20)
-#define JZ_GPIO_MEM_SDATI		JZ_GPIO_PORTD(21)
-#define JZ_GPIO_MEM_SYNC		JZ_GPIO_PORTD(22)
-#define JZ_GPIO_I2C_SDA			JZ_GPIO_PORTD(23)
-#define JZ_GPIO_I2C_SCK			JZ_GPIO_PORTD(24)
-#define JZ_GPIO_UART0_TXD		JZ_GPIO_PORTD(25)
-#define JZ_GPIO_UART0_RXD		JZ_GPIO_PORTD(26)
-#define JZ_GPIO_MEM_ADDR17		JZ_GPIO_PORTD(27)
-#define JZ_GPIO_MEM_ADDR18		JZ_GPIO_PORTD(28)
-#define JZ_GPIO_UART0_CTS		JZ_GPIO_PORTD(30)
-#define JZ_GPIO_UART0_RTS		JZ_GPIO_PORTD(31)
-
-#define JZ_GPIO_FUNC_MEM_SCLK_RSTN	JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_BCLK		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_SDATO		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_SDATI		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_SYNC		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_I2C_SDA		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_I2C_SCK		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_UART0_TXD		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_UART0_RXD		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_ADDR17		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_ADDR18		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_UART0_CTS		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_UART0_RTS		JZ_GPIO_FUNC2
-
-#define JZ_GPIO_UART1_RXD		JZ_GPIO_PORTD(30)
-#define JZ_GPIO_UART1_TXD		JZ_GPIO_PORTD(31)
-
-#define JZ_GPIO_FUNC_UART1_RXD		JZ_GPIO_FUNC3
-#define JZ_GPIO_FUNC_UART1_TXD		JZ_GPIO_FUNC3
-
 #endif
diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
index 39d70bde8cfe..6b9c1f7c31c9 100644
--- a/arch/mips/jz4740/Makefile
+++ b/arch/mips/jz4740/Makefile
@@ -7,8 +7,6 @@
 obj-y += prom.o time.o reset.o setup.o \
 	platform.o timer.o
 
-obj-$(CONFIG_MACH_JZ4740) += gpio.o
-
 CFLAGS_setup.o = -I$(src)/../../../scripts/dtc/libfdt
 
 # board specific support
diff --git a/arch/mips/jz4740/gpio.c b/arch/mips/jz4740/gpio.c
deleted file mode 100644
index b765773ab8aa..000000000000
--- a/arch/mips/jz4740/gpio.c
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- *  Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
- *  JZ4740 platform GPIO support
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <linux/io.h>
-#include <linux/gpio/driver.h>
-/* FIXME: needed for gpio_request(), try to remove consumer API from driver */
-#include <linux/gpio.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/irqchip/ingenic.h>
-#include <linux/bitops.h>
-
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-
-#include <asm/mach-jz4740/base.h>
-#include <asm/mach-jz4740/gpio.h>
-
-#define JZ4740_GPIO_BASE_A (32*0)
-#define JZ4740_GPIO_BASE_B (32*1)
-#define JZ4740_GPIO_BASE_C (32*2)
-#define JZ4740_GPIO_BASE_D (32*3)
-
-#define JZ4740_GPIO_NUM_A 32
-#define JZ4740_GPIO_NUM_B 32
-#define JZ4740_GPIO_NUM_C 31
-#define JZ4740_GPIO_NUM_D 32
-
-#define JZ4740_IRQ_GPIO_BASE_A (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_A)
-#define JZ4740_IRQ_GPIO_BASE_B (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_B)
-#define JZ4740_IRQ_GPIO_BASE_C (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_C)
-#define JZ4740_IRQ_GPIO_BASE_D (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_D)
-
-#define JZ_REG_GPIO_PIN			0x00
-#define JZ_REG_GPIO_DATA		0x10
-#define JZ_REG_GPIO_DATA_SET		0x14
-#define JZ_REG_GPIO_DATA_CLEAR		0x18
-#define JZ_REG_GPIO_MASK		0x20
-#define JZ_REG_GPIO_MASK_SET		0x24
-#define JZ_REG_GPIO_MASK_CLEAR		0x28
-#define JZ_REG_GPIO_PULL		0x30
-#define JZ_REG_GPIO_PULL_SET		0x34
-#define JZ_REG_GPIO_PULL_CLEAR		0x38
-#define JZ_REG_GPIO_FUNC		0x40
-#define JZ_REG_GPIO_FUNC_SET		0x44
-#define JZ_REG_GPIO_FUNC_CLEAR		0x48
-#define JZ_REG_GPIO_SELECT		0x50
-#define JZ_REG_GPIO_SELECT_SET		0x54
-#define JZ_REG_GPIO_SELECT_CLEAR	0x58
-#define JZ_REG_GPIO_DIRECTION		0x60
-#define JZ_REG_GPIO_DIRECTION_SET	0x64
-#define JZ_REG_GPIO_DIRECTION_CLEAR	0x68
-#define JZ_REG_GPIO_TRIGGER		0x70
-#define JZ_REG_GPIO_TRIGGER_SET		0x74
-#define JZ_REG_GPIO_TRIGGER_CLEAR	0x78
-#define JZ_REG_GPIO_FLAG		0x80
-#define JZ_REG_GPIO_FLAG_CLEAR		0x14
-
-#define GPIO_TO_BIT(gpio) BIT(gpio & 0x1f)
-#define GPIO_TO_REG(gpio, reg) (gpio_to_jz_gpio_chip(gpio)->base + (reg))
-#define CHIP_TO_REG(chip, reg) (gpio_chip_to_jz_gpio_chip(chip)->base + (reg))
-
-struct jz_gpio_chip {
-	unsigned int irq;
-	unsigned int irq_base;
-	uint32_t edge_trigger_both;
-
-	void __iomem *base;
-
-	struct gpio_chip gpio_chip;
-};
-
-static struct jz_gpio_chip jz4740_gpio_chips[];
-
-static inline struct jz_gpio_chip *gpio_to_jz_gpio_chip(unsigned int gpio)
-{
-	return &jz4740_gpio_chips[gpio >> 5];
-}
-
-static inline struct jz_gpio_chip *gpio_chip_to_jz_gpio_chip(struct gpio_chip *gc)
-{
-	return gpiochip_get_data(gc);
-}
-
-static inline struct jz_gpio_chip *irq_to_jz_gpio_chip(struct irq_data *data)
-{
-	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
-	return gc->private;
-}
-
-static inline void jz_gpio_write_bit(unsigned int gpio, unsigned int reg)
-{
-	writel(GPIO_TO_BIT(gpio), GPIO_TO_REG(gpio, reg));
-}
-
-int jz_gpio_set_function(int gpio, enum jz_gpio_function function)
-{
-	if (function == JZ_GPIO_FUNC_NONE) {
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_FUNC_CLEAR);
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_CLEAR);
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_CLEAR);
-	} else {
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_FUNC_SET);
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_CLEAR);
-		switch (function) {
-		case JZ_GPIO_FUNC1:
-			jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_CLEAR);
-			break;
-		case JZ_GPIO_FUNC3:
-			jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_SET);
-		case JZ_GPIO_FUNC2: /* Falltrough */
-			jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_SET);
-			break;
-		default:
-			BUG();
-			break;
-		}
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(jz_gpio_set_function);
-
-int jz_gpio_bulk_request(const struct jz_gpio_bulk_request *request, size_t num)
-{
-	size_t i;
-	int ret;
-
-	for (i = 0; i < num; ++i, ++request) {
-		ret = gpio_request(request->gpio, request->name);
-		if (ret)
-			goto err;
-		jz_gpio_set_function(request->gpio, request->function);
-	}
-
-	return 0;
-
-err:
-	for (--request; i > 0; --i, --request) {
-		gpio_free(request->gpio);
-		jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
-	}
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(jz_gpio_bulk_request);
-
-void jz_gpio_bulk_free(const struct jz_gpio_bulk_request *request, size_t num)
-{
-	size_t i;
-
-	for (i = 0; i < num; ++i, ++request) {
-		gpio_free(request->gpio);
-		jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
-	}
-
-}
-EXPORT_SYMBOL_GPL(jz_gpio_bulk_free);
-
-void jz_gpio_bulk_suspend(const struct jz_gpio_bulk_request *request, size_t num)
-{
-	size_t i;
-
-	for (i = 0; i < num; ++i, ++request) {
-		jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
-		jz_gpio_write_bit(request->gpio, JZ_REG_GPIO_DIRECTION_CLEAR);
-		jz_gpio_write_bit(request->gpio, JZ_REG_GPIO_PULL_SET);
-	}
-}
-EXPORT_SYMBOL_GPL(jz_gpio_bulk_suspend);
-
-void jz_gpio_bulk_resume(const struct jz_gpio_bulk_request *request, size_t num)
-{
-	size_t i;
-
-	for (i = 0; i < num; ++i, ++request)
-		jz_gpio_set_function(request->gpio, request->function);
-}
-EXPORT_SYMBOL_GPL(jz_gpio_bulk_resume);
-
-void jz_gpio_enable_pullup(unsigned gpio)
-{
-	jz_gpio_write_bit(gpio, JZ_REG_GPIO_PULL_CLEAR);
-}
-EXPORT_SYMBOL_GPL(jz_gpio_enable_pullup);
-
-void jz_gpio_disable_pullup(unsigned gpio)
-{
-	jz_gpio_write_bit(gpio, JZ_REG_GPIO_PULL_SET);
-}
-EXPORT_SYMBOL_GPL(jz_gpio_disable_pullup);
-
-static int jz_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
-{
-	return !!(readl(CHIP_TO_REG(chip, JZ_REG_GPIO_PIN)) & BIT(gpio));
-}
-
-static void jz_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
-{
-	uint32_t __iomem *reg = CHIP_TO_REG(chip, JZ_REG_GPIO_DATA_SET);
-	reg += !value;
-	writel(BIT(gpio), reg);
-}
-
-static int jz_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
-	int value)
-{
-	writel(BIT(gpio), CHIP_TO_REG(chip, JZ_REG_GPIO_DIRECTION_SET));
-	jz_gpio_set_value(chip, gpio, value);
-
-	return 0;
-}
-
-static int jz_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
-{
-	writel(BIT(gpio), CHIP_TO_REG(chip, JZ_REG_GPIO_DIRECTION_CLEAR));
-
-	return 0;
-}
-
-static int jz_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
-{
-	struct jz_gpio_chip *jz_gpio = gpiochip_get_data(chip);
-
-	return jz_gpio->irq_base + gpio;
-}
-
-int jz_gpio_port_direction_input(int port, uint32_t mask)
-{
-	writel(mask, GPIO_TO_REG(port, JZ_REG_GPIO_DIRECTION_CLEAR));
-
-	return 0;
-}
-EXPORT_SYMBOL(jz_gpio_port_direction_input);
-
-int jz_gpio_port_direction_output(int port, uint32_t mask)
-{
-	writel(mask, GPIO_TO_REG(port, JZ_REG_GPIO_DIRECTION_SET));
-
-	return 0;
-}
-EXPORT_SYMBOL(jz_gpio_port_direction_output);
-
-void jz_gpio_port_set_value(int port, uint32_t value, uint32_t mask)
-{
-	writel(~value & mask, GPIO_TO_REG(port, JZ_REG_GPIO_DATA_CLEAR));
-	writel(value & mask, GPIO_TO_REG(port, JZ_REG_GPIO_DATA_SET));
-}
-EXPORT_SYMBOL(jz_gpio_port_set_value);
-
-uint32_t jz_gpio_port_get_value(int port, uint32_t mask)
-{
-	uint32_t value = readl(GPIO_TO_REG(port, JZ_REG_GPIO_PIN));
-
-	return value & mask;
-}
-EXPORT_SYMBOL(jz_gpio_port_get_value);
-
-#define IRQ_TO_BIT(irq) BIT((irq - JZ4740_IRQ_GPIO(0)) & 0x1f)
-
-static void jz_gpio_check_trigger_both(struct jz_gpio_chip *chip, unsigned int irq)
-{
-	uint32_t value;
-	void __iomem *reg;
-	uint32_t mask = IRQ_TO_BIT(irq);
-
-	if (!(chip->edge_trigger_both & mask))
-		return;
-
-	reg = chip->base;
-
-	value = readl(chip->base + JZ_REG_GPIO_PIN);
-	if (value & mask)
-		reg += JZ_REG_GPIO_DIRECTION_CLEAR;
-	else
-		reg += JZ_REG_GPIO_DIRECTION_SET;
-
-	writel(mask, reg);
-}
-
-static void jz_gpio_irq_demux_handler(struct irq_desc *desc)
-{
-	uint32_t flag;
-	unsigned int gpio_irq;
-	struct jz_gpio_chip *chip = irq_desc_get_handler_data(desc);
-
-	flag = readl(chip->base + JZ_REG_GPIO_FLAG);
-	if (!flag)
-		return;
-
-	gpio_irq = chip->irq_base + __fls(flag);
-
-	jz_gpio_check_trigger_both(chip, gpio_irq);
-
-	generic_handle_irq(gpio_irq);
-};
-
-static inline void jz_gpio_set_irq_bit(struct irq_data *data, unsigned int reg)
-{
-	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
-	writel(IRQ_TO_BIT(data->irq), chip->base + reg);
-}
-
-static void jz_gpio_irq_unmask(struct irq_data *data)
-{
-	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
-
-	jz_gpio_check_trigger_both(chip, data->irq);
-	irq_gc_unmask_enable_reg(data);
-};
-
-/* TODO: Check if function is gpio */
-static unsigned int jz_gpio_irq_startup(struct irq_data *data)
-{
-	jz_gpio_set_irq_bit(data, JZ_REG_GPIO_SELECT_SET);
-	jz_gpio_irq_unmask(data);
-	return 0;
-}
-
-static void jz_gpio_irq_shutdown(struct irq_data *data)
-{
-	irq_gc_mask_disable_reg(data);
-
-	/* Set direction to input */
-	jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR);
-	jz_gpio_set_irq_bit(data, JZ_REG_GPIO_SELECT_CLEAR);
-}
-
-static int jz_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type)
-{
-	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
-	unsigned int irq = data->irq;
-
-	if (flow_type == IRQ_TYPE_EDGE_BOTH) {
-		uint32_t value = readl(chip->base + JZ_REG_GPIO_PIN);
-		if (value & IRQ_TO_BIT(irq))
-			flow_type = IRQ_TYPE_EDGE_FALLING;
-		else
-			flow_type = IRQ_TYPE_EDGE_RISING;
-		chip->edge_trigger_both |= IRQ_TO_BIT(irq);
-	} else {
-		chip->edge_trigger_both &= ~IRQ_TO_BIT(irq);
-	}
-
-	switch (flow_type) {
-	case IRQ_TYPE_EDGE_RISING:
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_SET);
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_SET);
-		break;
-	case IRQ_TYPE_EDGE_FALLING:
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR);
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_SET);
-		break;
-	case IRQ_TYPE_LEVEL_HIGH:
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_SET);
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_CLEAR);
-		break;
-	case IRQ_TYPE_LEVEL_LOW:
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR);
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_CLEAR);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int jz_gpio_irq_set_wake(struct irq_data *data, unsigned int on)
-{
-	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
-
-	irq_gc_set_wake(data, on);
-	irq_set_irq_wake(chip->irq, on);
-
-	return 0;
-}
-
-#define JZ4740_GPIO_CHIP(_bank) { \
-	.irq_base = JZ4740_IRQ_GPIO_BASE_ ## _bank, \
-	.gpio_chip = { \
-		.label = "Bank " # _bank, \
-		.owner = THIS_MODULE, \
-		.set = jz_gpio_set_value, \
-		.get = jz_gpio_get_value, \
-		.direction_output = jz_gpio_direction_output, \
-		.direction_input = jz_gpio_direction_input, \
-		.to_irq = jz_gpio_to_irq, \
-		.base = JZ4740_GPIO_BASE_ ## _bank, \
-		.ngpio = JZ4740_GPIO_NUM_ ## _bank, \
-	}, \
-}
-
-static struct jz_gpio_chip jz4740_gpio_chips[] = {
-	JZ4740_GPIO_CHIP(A),
-	JZ4740_GPIO_CHIP(B),
-	JZ4740_GPIO_CHIP(C),
-	JZ4740_GPIO_CHIP(D),
-};
-
-static void jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id)
-{
-	struct irq_chip_generic *gc;
-	struct irq_chip_type *ct;
-
-	chip->base = ioremap(JZ4740_GPIO_BASE_ADDR + (id * 0x100), 0x100);
-
-	chip->irq = JZ4740_IRQ_INTC_GPIO(id);
-	irq_set_chained_handler_and_data(chip->irq,
-					 jz_gpio_irq_demux_handler, chip);
-
-	gc = irq_alloc_generic_chip(chip->gpio_chip.label, 1, chip->irq_base,
-		chip->base, handle_level_irq);
-
-	gc->wake_enabled = IRQ_MSK(chip->gpio_chip.ngpio);
-	gc->private = chip;
-
-	ct = gc->chip_types;
-	ct->regs.enable = JZ_REG_GPIO_MASK_CLEAR;
-	ct->regs.disable = JZ_REG_GPIO_MASK_SET;
-	ct->regs.ack = JZ_REG_GPIO_FLAG_CLEAR;
-
-	ct->chip.name = "GPIO";
-	ct->chip.irq_mask = irq_gc_mask_disable_reg;
-	ct->chip.irq_unmask = jz_gpio_irq_unmask;
-	ct->chip.irq_ack = irq_gc_ack_set_bit;
-	ct->chip.irq_suspend = ingenic_intc_irq_suspend;
-	ct->chip.irq_resume = ingenic_intc_irq_resume;
-	ct->chip.irq_startup = jz_gpio_irq_startup;
-	ct->chip.irq_shutdown = jz_gpio_irq_shutdown;
-	ct->chip.irq_set_type = jz_gpio_irq_set_type;
-	ct->chip.irq_set_wake = jz_gpio_irq_set_wake;
-	ct->chip.flags = IRQCHIP_SET_TYPE_MASKED;
-
-	irq_setup_generic_chip(gc, IRQ_MSK(chip->gpio_chip.ngpio),
-		IRQ_GC_INIT_NESTED_LOCK, 0, IRQ_NOPROBE | IRQ_LEVEL);
-
-	gpiochip_add_data(&chip->gpio_chip, chip);
-}
-
-static int __init jz4740_gpio_init(void)
-{
-	unsigned int i;
-
-	for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i)
-		jz4740_gpio_chip_init(&jz4740_gpio_chips[i], i);
-
-	printk(KERN_INFO "JZ4740 GPIO initialized\n");
-
-	return 0;
-}
-arch_initcall(jz4740_gpio_init);
-
-#ifdef CONFIG_DEBUG_FS
-
-static inline void gpio_seq_reg(struct seq_file *s, struct jz_gpio_chip *chip,
-	const char *name, unsigned int reg)
-{
-	seq_printf(s, "\t%s: %08x\n", name, readl(chip->base + reg));
-}
-
-static int gpio_regs_show(struct seq_file *s, void *unused)
-{
-	struct jz_gpio_chip *chip = jz4740_gpio_chips;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i, ++chip) {
-		seq_printf(s, "==GPIO %d==\n", i);
-		gpio_seq_reg(s, chip, "Pin", JZ_REG_GPIO_PIN);
-		gpio_seq_reg(s, chip, "Data", JZ_REG_GPIO_DATA);
-		gpio_seq_reg(s, chip, "Mask", JZ_REG_GPIO_MASK);
-		gpio_seq_reg(s, chip, "Pull", JZ_REG_GPIO_PULL);
-		gpio_seq_reg(s, chip, "Func", JZ_REG_GPIO_FUNC);
-		gpio_seq_reg(s, chip, "Select", JZ_REG_GPIO_SELECT);
-		gpio_seq_reg(s, chip, "Direction", JZ_REG_GPIO_DIRECTION);
-		gpio_seq_reg(s, chip, "Trigger", JZ_REG_GPIO_TRIGGER);
-		gpio_seq_reg(s, chip, "Flag", JZ_REG_GPIO_FLAG);
-	}
-
-	return 0;
-}
-
-static int gpio_regs_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, gpio_regs_show, NULL);
-}
-
-static const struct file_operations gpio_regs_operations = {
-	.open		= gpio_regs_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static int __init gpio_debugfs_init(void)
-{
-	(void) debugfs_create_file("jz_regs_gpio", S_IFREG | S_IRUGO,
-				NULL, NULL, &gpio_regs_operations);
-	return 0;
-}
-subsys_initcall(gpio_debugfs_init);
-
-#endif
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v2 04/14] GPIO: Add gpio-ingenic driver
  2017-01-22 14:49       ` [PATCH v2 04/14] GPIO: Add gpio-ingenic driver Paul Cercueil
@ 2017-01-22 16:21         ` kbuild test robot
  2017-01-22 16:21           ` kbuild test robot
  2017-01-22 17:49         ` kbuild test robot
  2017-01-22 17:49         ` [PATCH] GPIO: fix semicolon.cocci warnings kbuild test robot
  2 siblings, 1 reply; 162+ messages in thread
From: kbuild test robot @ 2017-01-22 16:21 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: kbuild-all, Linus Walleij, Rob Herring, Mark Rutland,
	Ralf Baechle, Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton, linux-gpio, devicetree,
	linux-kernel, linux-mips, linux-mmc, linux-mtd, linux-pwm,
	linux-fbdev, james.hogan, Paul Cercueil

[-- Attachment #1: Type: text/plain, Size: 2198 bytes --]

Hi Paul,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.10-rc4 next-20170120]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Paul-Cercueil/Ingenic-JZ4740-JZ4780-pinctrl-driver/20170122-232326
config: ia64-allmodconfig (attached as .config)
compiler: ia64-linux-gcc (GCC) 6.2.0
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=ia64 

All errors (new ones prefixed by >>):

   drivers/gpio/gpio-ingenic.c: In function 'ingenic_gpio_direction_input':
>> drivers/gpio/gpio-ingenic.c:253:9: error: implicit declaration of function 'pinctrl_gpio_direction_input' [-Werror=implicit-function-declaration]
     return pinctrl_gpio_direction_input(gc->base + offset);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpio/gpio-ingenic.c: In function 'ingenic_gpio_direction_output':
>> drivers/gpio/gpio-ingenic.c:260:9: error: implicit declaration of function 'pinctrl_gpio_direction_output' [-Werror=implicit-function-declaration]
     return pinctrl_gpio_direction_output(gc->base + offset);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors

vim +/pinctrl_gpio_direction_input +253 drivers/gpio/gpio-ingenic.c

   247		return (int) gpio_get_value(jzgc, offset);
   248	}
   249	
   250	static int ingenic_gpio_direction_input(struct gpio_chip *gc,
   251			unsigned int offset)
   252	{
 > 253		return pinctrl_gpio_direction_input(gc->base + offset);
   254	}
   255	
   256	static int ingenic_gpio_direction_output(struct gpio_chip *gc,
   257			unsigned int offset, int value)
   258	{
   259		ingenic_gpio_set(gc, offset, value);
 > 260		return pinctrl_gpio_direction_output(gc->base + offset);
   261	}
   262	
   263	static const struct of_device_id ingenic_gpio_of_match[] = {

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 45837 bytes --]

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v2 04/14] GPIO: Add gpio-ingenic driver
  2017-01-22 16:21         ` kbuild test robot
@ 2017-01-22 16:21           ` kbuild test robot
  0 siblings, 0 replies; 162+ messages in thread
From: kbuild test robot @ 2017-01-22 16:21 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: kbuild-all, Linus Walleij, Rob Herring, Mark Rutland,
	Ralf Baechle, Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton, linux-gpio, devicetree,
	linux-kernel, linux-mips, linux-mmc, linux-mtd, linux-pwm,
	linux-fbdev, james.hogan

[-- Attachment #1: Type: text/plain, Size: 2198 bytes --]

Hi Paul,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.10-rc4 next-20170120]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Paul-Cercueil/Ingenic-JZ4740-JZ4780-pinctrl-driver/20170122-232326
config: ia64-allmodconfig (attached as .config)
compiler: ia64-linux-gcc (GCC) 6.2.0
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=ia64 

All errors (new ones prefixed by >>):

   drivers/gpio/gpio-ingenic.c: In function 'ingenic_gpio_direction_input':
>> drivers/gpio/gpio-ingenic.c:253:9: error: implicit declaration of function 'pinctrl_gpio_direction_input' [-Werror=implicit-function-declaration]
     return pinctrl_gpio_direction_input(gc->base + offset);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/gpio/gpio-ingenic.c: In function 'ingenic_gpio_direction_output':
>> drivers/gpio/gpio-ingenic.c:260:9: error: implicit declaration of function 'pinctrl_gpio_direction_output' [-Werror=implicit-function-declaration]
     return pinctrl_gpio_direction_output(gc->base + offset);
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors

vim +/pinctrl_gpio_direction_input +253 drivers/gpio/gpio-ingenic.c

   247		return (int) gpio_get_value(jzgc, offset);
   248	}
   249	
   250	static int ingenic_gpio_direction_input(struct gpio_chip *gc,
   251			unsigned int offset)
   252	{
 > 253		return pinctrl_gpio_direction_input(gc->base + offset);
   254	}
   255	
   256	static int ingenic_gpio_direction_output(struct gpio_chip *gc,
   257			unsigned int offset, int value)
   258	{
   259		ingenic_gpio_set(gc, offset, value);
 > 260		return pinctrl_gpio_direction_output(gc->base + offset);
   261	}
   262	
   263	static const struct of_device_id ingenic_gpio_of_match[] = {

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 45837 bytes --]

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v2 04/14] GPIO: Add gpio-ingenic driver
  2017-01-22 14:49       ` [PATCH v2 04/14] GPIO: Add gpio-ingenic driver Paul Cercueil
  2017-01-22 16:21         ` kbuild test robot
@ 2017-01-22 17:49         ` kbuild test robot
  2017-01-22 17:49           ` kbuild test robot
  2017-01-22 17:49         ` [PATCH] GPIO: fix semicolon.cocci warnings kbuild test robot
  2 siblings, 1 reply; 162+ messages in thread
From: kbuild test robot @ 2017-01-22 17:49 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: kbuild-all, Linus Walleij, Rob Herring, Mark Rutland,
	Ralf Baechle, Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton, linux-gpio, devicetree,
	linux-kernel, linux-mips, linux-mmc, linux-mtd, linux-pwm,
	linux-fbdev, james.hogan, Paul Cercueil

Hi Paul,

[auto build test WARNING on linus/master]
[also build test WARNING on v4.10-rc4 next-20170120]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Paul-Cercueil/Ingenic-JZ4740-JZ4780-pinctrl-driver/20170122-232326


coccinelle warnings: (new ones prefixed by >>)

>> drivers/gpio/gpio-ingenic.c:101:2-3: Unneeded semicolon

Please review and possibly fold the followup patch.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v2 04/14] GPIO: Add gpio-ingenic driver
  2017-01-22 17:49         ` kbuild test robot
@ 2017-01-22 17:49           ` kbuild test robot
  0 siblings, 0 replies; 162+ messages in thread
From: kbuild test robot @ 2017-01-22 17:49 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: kbuild-all, Linus Walleij, Rob Herring, Mark Rutland,
	Ralf Baechle, Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton, linux-gpio, devicetree,
	linux-kernel, linux-mips, linux-mmc, linux-mtd, linux-pwm,
	linux-fbdev, james.hogan

Hi Paul,

[auto build test WARNING on linus/master]
[also build test WARNING on v4.10-rc4 next-20170120]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Paul-Cercueil/Ingenic-JZ4740-JZ4780-pinctrl-driver/20170122-232326


coccinelle warnings: (new ones prefixed by >>)

>> drivers/gpio/gpio-ingenic.c:101:2-3: Unneeded semicolon

Please review and possibly fold the followup patch.

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH] GPIO: fix semicolon.cocci warnings
  2017-01-22 14:49       ` [PATCH v2 04/14] GPIO: Add gpio-ingenic driver Paul Cercueil
  2017-01-22 16:21         ` kbuild test robot
  2017-01-22 17:49         ` kbuild test robot
@ 2017-01-22 17:49         ` kbuild test robot
  2017-01-22 17:49           ` kbuild test robot
  2 siblings, 1 reply; 162+ messages in thread
From: kbuild test robot @ 2017-01-22 17:49 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: kbuild-all, Linus Walleij, Rob Herring, Mark Rutland,
	Ralf Baechle, Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton, linux-gpio, devicetree,
	linux-kernel, linux-mips, linux-mmc, linux-mtd, linux-pwm,
	linux-fbdev, james.hogan, Paul Cercueil

drivers/gpio/gpio-ingenic.c:101:2-3: Unneeded semicolon


 Remove unneeded semicolon.

Generated by: scripts/coccinelle/misc/semicolon.cocci

CC: Paul Cercueil <paul@crapouillou.net>
Signed-off-by: Fengguang Wu <fengguang.wu@intel.com>
---

 gpio-ingenic.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- a/drivers/gpio/gpio-ingenic.c
+++ b/drivers/gpio/gpio-ingenic.c
@@ -98,7 +98,7 @@ static void irq_set_type(struct ingenic_
 		writel(BIT(offset), jzgc->base + REG_CLEAR(reg2));
 		writel(BIT(offset), jzgc->base + REG_CLEAR(reg1));
 		break;
-	};
+	}
 
 }
 

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH] GPIO: fix semicolon.cocci warnings
  2017-01-22 17:49         ` [PATCH] GPIO: fix semicolon.cocci warnings kbuild test robot
@ 2017-01-22 17:49           ` kbuild test robot
  0 siblings, 0 replies; 162+ messages in thread
From: kbuild test robot @ 2017-01-22 17:49 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: kbuild-all, Linus Walleij, Rob Herring, Mark Rutland,
	Ralf Baechle, Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton, linux-gpio, devicetree,
	linux-kernel, linux-mips, linux-mmc, linux-mtd, linux-pwm,
	linux-fbdev, james.hogan

drivers/gpio/gpio-ingenic.c:101:2-3: Unneeded semicolon


 Remove unneeded semicolon.

Generated by: scripts/coccinelle/misc/semicolon.cocci

CC: Paul Cercueil <paul@crapouillou.net>
Signed-off-by: Fengguang Wu <fengguang.wu@intel.com>
---

 gpio-ingenic.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- a/drivers/gpio/gpio-ingenic.c
+++ b/drivers/gpio/gpio-ingenic.c
@@ -98,7 +98,7 @@ static void irq_set_type(struct ingenic_
 		writel(BIT(offset), jzgc->base + REG_CLEAR(reg2));
 		writel(BIT(offset), jzgc->base + REG_CLEAR(reg1));
 		break;
-	};
+	}
 
 }
 

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v2 10/14] mmc: jz4740: Let the pinctrl driver configure the pins
  2017-01-22 14:49       ` [PATCH v2 10/14] mmc: jz4740: Let the pinctrl driver configure the pins Paul Cercueil
@ 2017-01-23 10:40         ` Ulf Hansson
  0 siblings, 0 replies; 162+ messages in thread
From: Ulf Hansson @ 2017-01-23 10:40 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, Linux Fbdev development list, James Hogan

On 22 January 2017 at 15:49, Paul Cercueil <paul@crapouillou.net> wrote:
> Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
> the pins being properly configured before the driver probes.
>
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>

Acked-by: Ulf Hansson <ulf.hansson@linaro.org>

Kind regards
Uffe

> ---
>  drivers/mmc/host/jz4740_mmc.c | 45 +++++--------------------------------------
>  1 file changed, 5 insertions(+), 40 deletions(-)
>
> v2: Set pin sleep/default state in suspend/resume callbacks
>
> diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c
> index 819ad32964fc..b5fec5b7ee7b 100644
> --- a/drivers/mmc/host/jz4740_mmc.c
> +++ b/drivers/mmc/host/jz4740_mmc.c
> @@ -20,14 +20,13 @@
>  #include <linux/irq.h>
>  #include <linux/interrupt.h>
>  #include <linux/module.h>
> +#include <linux/pinctrl/consumer.h>
>  #include <linux/platform_device.h>
>  #include <linux/delay.h>
>  #include <linux/scatterlist.h>
>  #include <linux/clk.h>
>
>  #include <linux/bitops.h>
> -#include <linux/gpio.h>
> -#include <asm/mach-jz4740/gpio.h>
>  #include <asm/cacheflush.h>
>  #include <linux/dma-mapping.h>
>  #include <linux/dmaengine.h>
> @@ -906,15 +905,6 @@ static const struct mmc_host_ops jz4740_mmc_ops = {
>         .enable_sdio_irq = jz4740_mmc_enable_sdio_irq,
>  };
>
> -static const struct jz_gpio_bulk_request jz4740_mmc_pins[] = {
> -       JZ_GPIO_BULK_PIN(MSC_CMD),
> -       JZ_GPIO_BULK_PIN(MSC_CLK),
> -       JZ_GPIO_BULK_PIN(MSC_DATA0),
> -       JZ_GPIO_BULK_PIN(MSC_DATA1),
> -       JZ_GPIO_BULK_PIN(MSC_DATA2),
> -       JZ_GPIO_BULK_PIN(MSC_DATA3),
> -};
> -
>  static int jz4740_mmc_request_gpio(struct device *dev, int gpio,
>         const char *name, bool output, int value)
>  {
> @@ -978,15 +968,6 @@ static void jz4740_mmc_free_gpios(struct platform_device *pdev)
>                 gpio_free(pdata->gpio_power);
>  }
>
> -static inline size_t jz4740_mmc_num_pins(struct jz4740_mmc_host *host)
> -{
> -       size_t num_pins = ARRAY_SIZE(jz4740_mmc_pins);
> -       if (host->pdata && host->pdata->data_1bit)
> -               num_pins -= 3;
> -
> -       return num_pins;
> -}
> -
>  static int jz4740_mmc_probe(struct platform_device* pdev)
>  {
>         int ret;
> @@ -1027,15 +1008,9 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
>                 goto err_free_host;
>         }
>
> -       ret = jz_gpio_bulk_request(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
> -       if (ret) {
> -               dev_err(&pdev->dev, "Failed to request mmc pins: %d\n", ret);
> -               goto err_free_host;
> -       }
> -
>         ret = jz4740_mmc_request_gpios(mmc, pdev);
>         if (ret)
> -               goto err_gpio_bulk_free;
> +               goto err_release_dma;
>
>         mmc->ops = &jz4740_mmc_ops;
>         mmc->f_min = JZ_MMC_CLK_RATE / 128;
> @@ -1091,10 +1066,9 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
>         free_irq(host->irq, host);
>  err_free_gpios:
>         jz4740_mmc_free_gpios(pdev);
> -err_gpio_bulk_free:
> +err_release_dma:
>         if (host->use_dma)
>                 jz4740_mmc_release_dma_channels(host);
> -       jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
>  err_free_host:
>         mmc_free_host(mmc);
>
> @@ -1114,7 +1088,6 @@ static int jz4740_mmc_remove(struct platform_device *pdev)
>         free_irq(host->irq, host);
>
>         jz4740_mmc_free_gpios(pdev);
> -       jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
>
>         if (host->use_dma)
>                 jz4740_mmc_release_dma_channels(host);
> @@ -1128,20 +1101,12 @@ static int jz4740_mmc_remove(struct platform_device *pdev)
>
>  static int jz4740_mmc_suspend(struct device *dev)
>  {
> -       struct jz4740_mmc_host *host = dev_get_drvdata(dev);
> -
> -       jz_gpio_bulk_suspend(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
> -
> -       return 0;
> +       return pinctrl_pm_select_sleep_state(dev);
>  }
>
>  static int jz4740_mmc_resume(struct device *dev)
>  {
> -       struct jz4740_mmc_host *host = dev_get_drvdata(dev);
> -
> -       jz_gpio_bulk_resume(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
> -
> -       return 0;
> +       return pinctrl_pm_select_default_state(dev);
>  }
>
>  static SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend,
> --
> 2.11.0
>

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v3 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver
  2017-01-19 11:19   ` Paul Cercueil
  2017-01-20  8:40     ` Linus Walleij
  2017-01-22 14:49     ` [PATCH v2 00/14] " Paul Cercueil
@ 2017-01-25 18:51     ` Paul Cercueil
  2017-01-25 18:51       ` [PATCH v3 01/14] Documentation: dt/bindings: Document pinctrl-ingenic Paul Cercueil
                         ` (13 more replies)
  2 siblings, 14 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-25 18:51 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan

Hi,

This is my v3 of my ingenic pinctrl patch series.
Not much is changed here, just cosmetic changes reported by coccinelle
as well as a missing header include.

To clear up any doubts: I left the GPIO base for the gpio-ingenic driver
configurable, for the reason that the QI_LB60 platform still uses global
GPIO numbers. When this code will eventually be cleaned up I will send
a patch to remove this mechanism.

Best regards,
- Paul

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v3 01/14] Documentation: dt/bindings: Document pinctrl-ingenic
  2017-01-25 18:51     ` [PATCH v3 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
@ 2017-01-25 18:51       ` Paul Cercueil
  2017-01-30 20:36         ` Rob Herring
  2017-04-02 20:42         ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
  2017-01-25 18:51       ` [PATCH v3 02/14] Documentation: dt/bindings: Document pinctrl-gpio Paul Cercueil
                         ` (12 subsequent siblings)
  13 siblings, 2 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-25 18:51 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

This commit adds documentation for the devicetree bidings of the
pinctrl-ingenic driver, which handles pin configuration and pin
muxing of the Ingenic SoCs currently supported by the Linux kernel.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 .../bindings/pinctrl/ingenic,pinctrl.txt           | 77 ++++++++++++++++++++++
 1 file changed, 77 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt

v2: Rewrote the documentation for the new pinctrl-ingenic driver
v3: No changes

diff --git a/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
new file mode 100644
index 000000000000..ead5b01ad471
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
@@ -0,0 +1,77 @@
+Ingenic jz47xx pin controller
+
+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".
+
+For the jz47xx SoCs, pin control is tightly bound with GPIO ports. All pins may
+be used as GPIOs, multiplexed device functions are configured within the
+GPIO port configuration registers and it is typical to refer to pins using the
+naming scheme "PxN" where x is a character identifying the GPIO port with
+which the pin is associated and N is an integer from 0 to 31 identifying the
+pin within that GPIO port. For example PA0 is the first pin in GPIO port A, and
+PB31 is the last pin in GPIO port B. The jz4740 contains 4 GPIO ports, PA to
+PD, for a total of 128 pins. The jz4780 contains 6 GPIO ports, PA to PF, for a
+total of 192 pins.
+
+
+Pin controller node
+===================
+
+Required properties:
+- compatible: One of:
+  - "ingenic,jz4740-pinctrl"
+  - "ingenic,jz4780-pinctrl"
+
+Optional properties:
+- ingenic,pull-ups: A list of 32-bit bit fields, where each bit set tells the
+  driver that a pull-up resistor is available for this pin.
+  By default, the driver considers that all pins feature a pull-up resistor.
+- ingenic,pull-downs: A list of 32-bit bit fields, where each bit set tells
+  the driver that a pull-down resistor is available for this pin.
+  By default, the driver considers that all pins feature a pull-down
+  resistor.
+
+
+'functions' sub-node
+====================
+
+The 'functions' node will contain sub-nodes that correspond to pin function
+nodes, and no properties. Pin function nodes will contain sub-nodes that
+correspond to pin groups, and no properties.
+
+The names of the pin function nodes will end up being the available functions
+provided by the pinctrl driver.
+The names of the pin group nodes will end up being the available groups
+provided by the pinctrl driver.
+
+Required properties for pin groups:
+- ingenic,pins: <pin mode [pin mode ...]>;
+  where 'pin' is the number of the pin, and 'mode' is the function mode of the
+  pin that should be enabled for this group.
+
+
+Example:
+=======
+
+pinctrl: ingenic-pinctrl@10010000 {
+	compatible = "ingenic,jz4740-pinctrl";
+	reg = <0x10010000 0x400>;
+
+	ingenic,pull-ups   = <0xffffffff 0xffffffff 0xffffffff 0xdfffffff>;
+	ingenic,pull-downs = <0x00000000 0x00000000 0x00000000 0x00000000>;
+
+	functions {
+		mmc {
+			mmc-1bit {
+				/* CLK, CMD, D0 */
+				ingenic,pins = <0x69 0 0x68 0 0x6a 0>;
+			};
+
+			mmc-4bit {
+				/* D1, D2, D3 */
+				ingenic,pins = <0x6b 0 0x6c 0 0x6d 0>;
+			};
+		};
+	};
+};
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v3 02/14] Documentation: dt/bindings: Document pinctrl-gpio
  2017-01-25 18:51     ` [PATCH v3 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
  2017-01-25 18:51       ` [PATCH v3 01/14] Documentation: dt/bindings: Document pinctrl-ingenic Paul Cercueil
@ 2017-01-25 18:51       ` Paul Cercueil
  2017-01-30 20:33         ` Rob Herring
  2017-01-25 18:51       ` [PATCH v3 03/14] pinctrl-ingenic: add a pinctrl driver for the Ingenic jz47xx SoCs Paul Cercueil
                         ` (11 subsequent siblings)
  13 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-01-25 18:51 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

This commit adds documentation for the devicetree bidings of the
pinctrl-gpio driver, which handles GPIOs of the Ingenic SoCs
currently supported by the Linux kernel.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 .../devicetree/bindings/gpio/ingenic,gpio.txt      | 45 ++++++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/gpio/ingenic,gpio.txt

v2: New patch
v3: No changes

diff --git a/Documentation/devicetree/bindings/gpio/ingenic,gpio.txt b/Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
new file mode 100644
index 000000000000..b2eb20494365
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
@@ -0,0 +1,45 @@
+Ingenic jz47xx GPIO controller
+
+Required properties:
+  - compatible:
+    - "ingenic,jz4740-gpio" for the JZ4740 SoC
+    - "ingenic,jz4780-gpio" for the JZ4780 SoC
+
+  - reg: Base address and length of each memory resource used by the GPIO
+    controller hardware module.
+
+  - gpio-controller: Marks the device node as a GPIO controller.
+  - #gpio-cells: Should be 2. The first cell is the GPIO number and the second
+    cell specifies GPIO flags, as defined in <dt-bindings/gpio/gpio.h>. Only the
+    GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported.
+  - gpio-ranges: Range of pins managed by the GPIO controller.
+
+Optional properties:
+  - base: The GPIO number to use as the base for this driver.
+  - interrupt-controller: Marks the device node as an interrupt controller.
+  - interrupts: Interrupt specifier for the controllers interrupt.
+    Required if 'interrupt-controller' is specified.
+
+Please refer to gpio.txt in this directory for details of gpio-ranges property
+and the common GPIO bindings used by client devices.
+
+The GPIO controller also acts as an interrupt controller. It uses the default
+two cells specifier as described in Documentation/devicetree/bindings/
+interrupt-controller/interrupts.txt.
+
+Example:
+
+gpa: gpio-controller@10010000 {
+	compatible = "ingenic,jz4740-gpio";
+	reg = <0x10010000 0x100>;
+
+	gpio-controller;
+	gpio-ranges = <&pinctrl 0 0 32>;
+	#gpio-cells = <2>;
+
+	interrupt-controller;
+	#interrupt-cells = <2>;
+
+	interrupt-parent = <&intc>;
+	interrupts = <28>;
+};
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v3 03/14] pinctrl-ingenic: add a pinctrl driver for the Ingenic jz47xx SoCs
  2017-01-25 18:51     ` [PATCH v3 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
  2017-01-25 18:51       ` [PATCH v3 01/14] Documentation: dt/bindings: Document pinctrl-ingenic Paul Cercueil
  2017-01-25 18:51       ` [PATCH v3 02/14] Documentation: dt/bindings: Document pinctrl-gpio Paul Cercueil
@ 2017-01-25 18:51       ` Paul Cercueil
  2017-01-31 14:05         ` Linus Walleij
  2017-01-25 18:51       ` [PATCH v3 04/14] GPIO: Add gpio-ingenic driver Paul Cercueil
                         ` (10 subsequent siblings)
  13 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-01-25 18:51 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

This driver handles pin configuration and pin muxing for the
JZ4740 and JZ4780 SoCs from Ingenic.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/pinctrl/Kconfig           |   8 +
 drivers/pinctrl/Makefile          |   1 +
 drivers/pinctrl/pinctrl-ingenic.c | 488 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 497 insertions(+)
 create mode 100644 drivers/pinctrl/pinctrl-ingenic.c

v2: Consider it's a new patch. Completely rewritten from v1.
v3: 'unsigned' -> 'unsigned int'

diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 8f8c2af45781..2312e21ca48d 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -285,6 +285,14 @@ config PINCTRL_ZYNQ
 	help
 	  This selects the pinctrl driver for Xilinx Zynq.
 
+config PINCTRL_INGENIC
+	bool "Pinctrl driver for the Ingenic JZ47xx SoCs"
+	default y
+	depends on MACH_INGENIC || COMPILE_TEST
+	select GENERIC_PINCONF
+	select GENERIC_PINCTRL_GROUPS
+	select GENERIC_PINMUX_FUNCTIONS
+
 source "drivers/pinctrl/aspeed/Kconfig"
 source "drivers/pinctrl/bcm/Kconfig"
 source "drivers/pinctrl/berlin/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index a251f439626f..80f327239d4b 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_PINCTRL_LPC18XX)	+= pinctrl-lpc18xx.o
 obj-$(CONFIG_PINCTRL_TB10X)	+= pinctrl-tb10x.o
 obj-$(CONFIG_PINCTRL_ST) 	+= pinctrl-st.o
 obj-$(CONFIG_PINCTRL_ZYNQ)	+= pinctrl-zynq.o
+obj-$(CONFIG_PINCTRL_INGENIC)	+= pinctrl-ingenic.o
 
 obj-$(CONFIG_ARCH_ASPEED)	+= aspeed/
 obj-y				+= bcm/
diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-ingenic.c
new file mode 100644
index 000000000000..ce36cf509eb1
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-ingenic.c
@@ -0,0 +1,488 @@
+/*
+ * Ingenic SoCs pinctrl driver
+ *
+ * Copyright (c) 2017 Paul Cercueil <paul@crapouillou.net>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/compiler.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "core.h"
+#include "pinconf.h"
+#include "pinmux.h"
+
+#define JZ4740_GPIO_DATA	0x10
+#define JZ4740_GPIO_PULL_DIS	0x30
+#define JZ4740_GPIO_FUNC	0x40
+#define JZ4740_GPIO_SELECT	0x50
+#define JZ4740_GPIO_DIR		0x60
+#define JZ4740_GPIO_TRIG	0x70
+#define JZ4740_GPIO_FLAG	0x80
+
+#define JZ4780_GPIO_INT		0x10
+#define JZ4780_GPIO_MSK		0x20
+#define JZ4780_GPIO_PAT1	0x30
+#define JZ4780_GPIO_PAT0	0x40
+#define JZ4780_GPIO_FLAG	0x50
+#define JZ4780_GPIO_PEN		0x70
+
+#define REG_SET(x) ((x) + 0x4)
+#define REG_CLEAR(x) ((x) + 0x8)
+
+#define PINS_PER_GPIO_CHIP 32
+#define NUM_MAX_GPIO_CHIPS 6
+
+enum jz_version {
+	ID_JZ4740,
+	ID_JZ4780,
+};
+
+struct ingenic_pinctrl {
+	struct device *dev;
+	void __iomem *base;
+	struct pinctrl_dev *pctl;
+	struct pinctrl_pin_desc *pdesc;
+	enum jz_version version;
+
+	u32 pull_ups[NUM_MAX_GPIO_CHIPS];
+	u32 pull_downs[NUM_MAX_GPIO_CHIPS];
+};
+
+static inline void ingenic_config_pin(struct ingenic_pinctrl *jzpc,
+		unsigned int pin, u8 reg, bool set)
+{
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+
+	writel(BIT(idx), jzpc->base + offt * 0x100 +
+			(set ? REG_SET(reg) : REG_CLEAR(reg)));
+}
+
+static inline bool ingenic_get_pin_config(struct ingenic_pinctrl *jzpc,
+		unsigned int pin, u8 reg)
+{
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+
+	return readl(jzpc->base + offt * 0x100 + reg) & BIT(idx);
+}
+
+static struct pinctrl_ops ingenic_pctlops = {
+	.get_groups_count = pinctrl_generic_get_group_count,
+	.get_group_name = pinctrl_generic_get_group_name,
+	.get_group_pins = pinctrl_generic_get_group_pins,
+	.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
+	.dt_free_map = pinconf_generic_dt_free_map,
+};
+
+static int ingenic_pinmux_set_pin_fn(struct ingenic_pinctrl *jzpc,
+		int pin, int func)
+{
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+
+	dev_dbg(jzpc->dev, "set pin P%c%u to function %u\n",
+			'A' + offt, idx, func);
+
+	if (jzpc->version >= ID_JZ4780) {
+		ingenic_config_pin(jzpc, pin, JZ4780_GPIO_INT, false);
+		ingenic_config_pin(jzpc, pin, JZ4780_GPIO_MSK, false);
+		ingenic_config_pin(jzpc, pin, JZ4780_GPIO_PAT1, func & 0x2);
+		ingenic_config_pin(jzpc, pin, JZ4780_GPIO_PAT0, func & 0x1);
+	} else {
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_FUNC, true);
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_TRIG, func & 0x2);
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_SELECT, func > 0);
+	}
+
+	return 0;
+}
+
+static int ingenic_pinmux_set_mux(struct pinctrl_dev *pctldev,
+		unsigned int selector, unsigned int group)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	struct function_desc *func;
+	struct group_desc *grp;
+	unsigned int i;
+
+	func = pinmux_generic_get_function(pctldev, selector);
+	if (!func)
+		return -EINVAL;
+
+	grp = pinctrl_generic_get_group(pctldev, group);
+	if (!grp)
+		return -EINVAL;
+
+	dev_dbg(pctldev->dev, "enable function %s group %s\n",
+		func->name, grp->name);
+
+	for (i = 0; i < grp->num_pins; i++) {
+		int *pin_modes = grp->data;
+
+		ingenic_pinmux_set_pin_fn(jzpc, grp->pins[i], pin_modes[i]);
+	}
+
+	return 0;
+}
+
+static int ingenic_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
+		struct pinctrl_gpio_range *range,
+		unsigned int pin, bool input)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+
+	dev_dbg(pctldev->dev, "set pin P%c%u to %sput\n",
+			'A' + offt, idx, input ? "in" : "out");
+
+	if (jzpc->version >= ID_JZ4780) {
+		ingenic_config_pin(jzpc, pin, JZ4780_GPIO_INT, false);
+		ingenic_config_pin(jzpc, pin, JZ4780_GPIO_MSK, true);
+		ingenic_config_pin(jzpc, pin, JZ4780_GPIO_PAT1, input);
+	} else {
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_SELECT, false);
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_DIR, input);
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_FUNC, false);
+	}
+
+	return 0;
+}
+
+static struct pinmux_ops ingenic_pmxops = {
+	.get_functions_count = pinmux_generic_get_function_count,
+	.get_function_name = pinmux_generic_get_function_name,
+	.get_function_groups = pinmux_generic_get_function_groups,
+	.set_mux = ingenic_pinmux_set_mux,
+	.gpio_set_direction = ingenic_pinmux_gpio_set_direction,
+};
+
+static int ingenic_pinconf_get(struct pinctrl_dev *pctldev,
+		unsigned int pin, unsigned long *config)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	enum pin_config_param param = pinconf_to_config_param(*config);
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+	bool pull;
+
+	if (jzpc->version >= ID_JZ4780)
+		pull = !ingenic_get_pin_config(jzpc, pin, JZ4780_GPIO_PEN);
+	else
+		pull = !ingenic_get_pin_config(jzpc, pin, JZ4740_GPIO_PULL_DIS);
+
+	switch (param) {
+	case PIN_CONFIG_BIAS_DISABLE:
+		if (pull)
+			return -EINVAL;
+		break;
+
+	case PIN_CONFIG_BIAS_PULL_UP:
+		if (!pull || !(jzpc->pull_ups[offt] & BIT(idx)))
+			return -EINVAL;
+		break;
+
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		if (!pull || !(jzpc->pull_downs[offt] & BIT(idx)))
+			return -EINVAL;
+		break;
+
+	default:
+		return -ENOTSUPP;
+	}
+
+	*config = pinconf_to_config_packed(param, 1);
+	return 0;
+}
+
+static void ingenic_set_bias(struct ingenic_pinctrl *jzpc,
+		unsigned int pin, bool enabled)
+{
+	if (jzpc->version >= ID_JZ4780)
+		ingenic_config_pin(jzpc, pin, JZ4780_GPIO_PEN, !enabled);
+	else
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_PULL_DIS, !enabled);
+}
+
+static int ingenic_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
+		unsigned long *configs, unsigned int num_configs)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+	unsigned int cfg;
+
+	for (cfg = 0; cfg < num_configs; cfg++) {
+		switch (pinconf_to_config_param(configs[cfg])) {
+		case PIN_CONFIG_BIAS_DISABLE:
+		case PIN_CONFIG_BIAS_PULL_UP:
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			continue;
+		default:
+			return -ENOTSUPP;
+		}
+	}
+
+	for (cfg = 0; cfg < num_configs; cfg++) {
+		switch (pinconf_to_config_param(configs[cfg])) {
+		case PIN_CONFIG_BIAS_DISABLE:
+			dev_dbg(jzpc->dev, "disable pull-over for pin P%c%u\n",
+					'A' + offt, idx);
+			ingenic_set_bias(jzpc, pin, false);
+			break;
+
+		case PIN_CONFIG_BIAS_PULL_UP:
+			if (!(jzpc->pull_ups[offt] & BIT(idx)))
+				return -EINVAL;
+			dev_dbg(jzpc->dev, "set pull-up for pin P%c%u\n",
+					'A' + offt, idx);
+			ingenic_set_bias(jzpc, pin, true);
+			break;
+
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			if (!(jzpc->pull_downs[offt] & BIT(idx)))
+				return -EINVAL;
+			dev_dbg(jzpc->dev, "set pull-down for pin P%c%u\n",
+					'A' + offt, idx);
+			ingenic_set_bias(jzpc, pin, true);
+			break;
+
+		default:
+			unreachable();
+		}
+	}
+
+	return 0;
+}
+
+static int ingenic_pinconf_group_get(struct pinctrl_dev *pctldev,
+		unsigned int group, unsigned long *config)
+{
+	const unsigned int *pins;
+	unsigned int i, npins, old = 0;
+	int ret;
+
+	ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < npins; i++) {
+		if (ingenic_pinconf_get(pctldev, pins[i], config))
+			return -ENOTSUPP;
+
+		/* configs do not match between two pins */
+		if (i && (old != *config))
+			return -ENOTSUPP;
+
+		old = *config;
+	}
+
+	return 0;
+}
+
+static int ingenic_pinconf_group_set(struct pinctrl_dev *pctldev,
+		unsigned int group, unsigned long *configs,
+		unsigned int num_configs)
+{
+	const unsigned int *pins;
+	unsigned int i, npins;
+	int ret;
+
+	ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < npins; i++) {
+		ret = ingenic_pinconf_set(pctldev,
+				pins[i], configs, num_configs);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static struct pinconf_ops ingenic_confops = {
+	.is_generic = true,
+	.pin_config_get = ingenic_pinconf_get,
+	.pin_config_set = ingenic_pinconf_set,
+	.pin_config_group_get = ingenic_pinconf_group_get,
+	.pin_config_group_set = ingenic_pinconf_group_set,
+};
+
+static int ingenic_pinctrl_parse_dt_func(struct ingenic_pinctrl *jzpc,
+		struct device_node *np)
+{
+	unsigned int num_groups;
+	struct device_node *group_node;
+	unsigned int i, j;
+	int err, npins, *pins, *confs;
+	const char **groups;
+
+	num_groups = of_get_child_count(np);
+	groups = devm_kzalloc(jzpc->dev,
+			sizeof(*groups) * num_groups, GFP_KERNEL);
+	if (!groups)
+		return -ENOMEM;
+
+	i = 0;
+	for_each_child_of_node(np, group_node) {
+		groups[i++] = group_node->name;
+
+		npins = of_property_count_elems_of_size(group_node,
+				"ingenic,pins", 8);
+		if (npins < 0)
+			return npins;
+
+		pins = devm_kzalloc(jzpc->dev,
+				sizeof(*pins) * npins, GFP_KERNEL);
+		confs = devm_kzalloc(jzpc->dev,
+				sizeof(*confs) * npins, GFP_KERNEL);
+		if (!pins || !confs)
+			return -ENOMEM;
+
+		for (j = 0; j < npins; j++) {
+			of_property_read_u32_index(group_node,
+					"ingenic,pins", j * 2, &pins[j]);
+
+			of_property_read_u32_index(group_node,
+					"ingenic,pins", j * 2 + 1, &confs[j]);
+		}
+
+		err = pinctrl_generic_add_group(jzpc->pctl, group_node->name,
+				pins, npins, confs);
+		if (err)
+			return err;
+	}
+
+	return pinmux_generic_add_function(jzpc->pctl, np->name,
+			groups, num_groups, NULL);
+}
+
+static const struct of_device_id ingenic_pinctrl_of_match[] = {
+	{ .compatible = "ingenic,jz4740-pinctrl", .data = (void *) ID_JZ4740 },
+	{ .compatible = "ingenic,jz4780-pinctrl", .data = (void *) ID_JZ4780 },
+	{},
+};
+
+int ingenic_pinctrl_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct ingenic_pinctrl *jzpc;
+	struct pinctrl_desc *pctl_desc;
+	struct device_node *np, *functions_node;
+	const struct of_device_id *of_id = of_match_device(
+			ingenic_pinctrl_of_match, dev);
+	unsigned int i, num_chips;
+	int err;
+
+	jzpc = devm_kzalloc(dev, sizeof(*jzpc), GFP_KERNEL);
+	if (!jzpc)
+		return -ENOMEM;
+
+	jzpc->base = of_iomap(dev->of_node, 0);
+	if (!jzpc->base) {
+		dev_err(dev, "failed to map IO memory\n");
+		return -ENXIO;
+	}
+
+	jzpc->dev = dev;
+	dev_set_drvdata(dev, jzpc);
+
+	jzpc->version = (enum jz_version)of_id->data;
+
+	if (jzpc->version >= ID_JZ4780)
+		num_chips = 6;
+	else
+		num_chips = 4;
+
+	/*
+	 * Read the ingenic,pull-ups and ingenic,pull-downs arrays if present in
+	 * the devicetree. Otherwise set all bits to 0xff to consider that
+	 * pull-over resistors are available on all pins.
+	 */
+	err = of_property_read_u32_array(dev->of_node, "ingenic,pull-ups",
+			jzpc->pull_ups, num_chips);
+	if (err)
+		memset(jzpc->pull_ups, 0xff, sizeof(jzpc->pull_ups));
+
+	err = of_property_read_u32_array(dev->of_node, "ingenic,pull-downs",
+			jzpc->pull_downs, num_chips);
+	if (err)
+		memset(jzpc->pull_downs, 0xff, sizeof(jzpc->pull_downs));
+
+	functions_node = of_find_node_by_name(dev->of_node, "functions");
+	if (!functions_node) {
+		dev_err(dev, "Missing \"functions\" devicetree node\n");
+		return -EINVAL;
+	}
+
+	pctl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctl_desc), GFP_KERNEL);
+	if (!pctl_desc)
+		return -ENOMEM;
+
+	/* fill in pinctrl_desc structure */
+	pctl_desc->name = dev_name(dev);
+	pctl_desc->owner = THIS_MODULE;
+	pctl_desc->pctlops = &ingenic_pctlops;
+	pctl_desc->pmxops = &ingenic_pmxops;
+	pctl_desc->confops = &ingenic_confops;
+	pctl_desc->npins = num_chips * PINS_PER_GPIO_CHIP;
+	pctl_desc->pins = jzpc->pdesc = devm_kzalloc(&pdev->dev,
+			sizeof(*jzpc->pdesc) * pctl_desc->npins, GFP_KERNEL);
+	if (!jzpc->pdesc)
+		return -ENOMEM;
+
+	for (i = 0; i < pctl_desc->npins; i++) {
+		jzpc->pdesc[i].number = i;
+		jzpc->pdesc[i].name = kasprintf(GFP_KERNEL, "P%c%d",
+						'A' + (i / PINS_PER_GPIO_CHIP),
+						i % PINS_PER_GPIO_CHIP);
+	}
+
+	jzpc->pctl = devm_pinctrl_register(dev, pctl_desc, jzpc);
+	if (!jzpc->pctl) {
+		dev_err(dev, "Failed pinctrl registration\n");
+		return -EINVAL;
+	}
+
+	for_each_child_of_node(functions_node, np) {
+		err = ingenic_pinctrl_parse_dt_func(jzpc, np);
+		if (err) {
+			dev_err(dev, "failed to parse function %s\n",
+					np->full_name);
+			continue;
+		}
+	}
+
+	return 0;
+}
+
+static struct platform_driver ingenic_pinctrl_driver = {
+	.driver = {
+		.name = "pinctrl-ingenic",
+		.of_match_table = of_match_ptr(ingenic_pinctrl_of_match),
+		.suppress_bind_attrs = true,
+	},
+	.probe = ingenic_pinctrl_probe,
+};
+
+static int __init ingenic_pinctrl_drv_register(void)
+{
+	return platform_driver_register(&ingenic_pinctrl_driver);
+}
+postcore_initcall(ingenic_pinctrl_drv_register);
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v3 04/14] GPIO: Add gpio-ingenic driver
  2017-01-25 18:51     ` [PATCH v3 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                         ` (2 preceding siblings ...)
  2017-01-25 18:51       ` [PATCH v3 03/14] pinctrl-ingenic: add a pinctrl driver for the Ingenic jz47xx SoCs Paul Cercueil
@ 2017-01-25 18:51       ` Paul Cercueil
  2017-01-31 14:13         ` Linus Walleij
  2017-01-31 14:20         ` Linus Walleij
  2017-01-25 18:51       ` [PATCH v3 05/14] MIPS: ingenic: Enable pinctrl for all ingenic SoCs Paul Cercueil
                         ` (9 subsequent siblings)
  13 siblings, 2 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-25 18:51 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

This driver handles the GPIOs of all the Ingenic JZ47xx SoCs
currently supported by the upsteam Linux kernel.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/gpio/Kconfig        |  10 ++
 drivers/gpio/Makefile       |   1 +
 drivers/gpio/gpio-ingenic.c | 367 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 378 insertions(+)
 create mode 100644 drivers/gpio/gpio-ingenic.c

v2: Consider it's a new patch. Completely rewritten from v1.
v3: Add missing include <linux/pinctrl/consumer.h> and drop semicolon after }

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index d5d36549ecc1..21992ca29342 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -225,6 +225,16 @@ config GPIO_ICH
 
 	  If unsure, say N.
 
+config GPIO_INGENIC
+	tristate "Ingenic JZ47xx SoCs GPIO support"
+	depends on MACH_INGENIC || COMPILE_TEST
+	select GPIOLIB_IRQCHIP
+	help
+	  Say yes here to support the GPIO functionality present on the
+	  JZ4740 and JZ4780 SoCs from Ingenic.
+
+	  If unsure, say N.
+
 config GPIO_IOP
 	tristate "Intel IOP GPIO"
 	depends on ARCH_IOP32X || ARCH_IOP33X || COMPILE_TEST
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index a7676b82de6f..3c5412ae56f0 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_GPIO_GPIO_MM)	+= gpio-gpio-mm.o
 obj-$(CONFIG_GPIO_GRGPIO)	+= gpio-grgpio.o
 obj-$(CONFIG_HTC_EGPIO)		+= gpio-htc-egpio.o
 obj-$(CONFIG_GPIO_ICH)		+= gpio-ich.o
+obj-$(CONFIG_GPIO_INGENIC)	+= gpio-ingenic.o
 obj-$(CONFIG_GPIO_IOP)		+= gpio-iop.o
 obj-$(CONFIG_GPIO_IT87)		+= gpio-it87.o
 obj-$(CONFIG_GPIO_JANZ_TTL)	+= gpio-janz-ttl.o
diff --git a/drivers/gpio/gpio-ingenic.c b/drivers/gpio/gpio-ingenic.c
new file mode 100644
index 000000000000..1bb6c4d5b8ba
--- /dev/null
+++ b/drivers/gpio/gpio-ingenic.c
@@ -0,0 +1,367 @@
+/*
+ * Ingenic JZ47xx GPIO driver
+ *
+ * Copyright (c) 2017 Paul Cercueil <paul@crapouillou.net>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/pinctrl/consumer.h>
+
+#define GPIO_PIN	0x00
+#define GPIO_MSK	0x20
+
+#define JZ4740_GPIO_DATA	0x10
+#define JZ4740_GPIO_SELECT	0x50
+#define JZ4740_GPIO_DIR		0x60
+#define JZ4740_GPIO_TRIG	0x70
+#define JZ4740_GPIO_FLAG	0x80
+
+#define JZ4780_GPIO_INT		0x10
+#define JZ4780_GPIO_PAT1	0x30
+#define JZ4780_GPIO_PAT0	0x40
+#define JZ4780_GPIO_FLAG	0x50
+
+#define REG_SET(x) ((x) + 0x4)
+#define REG_CLEAR(x) ((x) + 0x8)
+
+enum jz_version {
+	ID_JZ4740,
+	ID_JZ4780,
+};
+
+struct ingenic_gpio_chip {
+	void __iomem *base;
+	struct gpio_chip gc;
+	struct irq_chip irq_chip;
+	unsigned int irq;
+	enum jz_version version;
+};
+
+static inline bool gpio_get_value(struct ingenic_gpio_chip *jzgc, u8 offset)
+{
+	if (jzgc->version >= ID_JZ4780)
+		return readl(jzgc->base + GPIO_PIN) & BIT(offset);
+	else
+		return readl(jzgc->base + JZ4740_GPIO_DATA) & BIT(offset);
+}
+
+static void gpio_set_value(struct ingenic_gpio_chip *jzgc, u8 offset, int value)
+{
+	u8 reg;
+
+	if (jzgc->version >= ID_JZ4780)
+		reg = JZ4780_GPIO_PAT0;
+	else
+		reg = JZ4740_GPIO_DATA;
+
+	if (value)
+		writel(BIT(offset), jzgc->base + REG_SET(reg));
+	else
+		writel(BIT(offset), jzgc->base + REG_CLEAR(reg));
+}
+
+static void irq_set_type(struct ingenic_gpio_chip *jzgc,
+		u8 offset, unsigned int type)
+{
+	u8 reg1, reg2;
+
+	if (jzgc->version >= ID_JZ4780) {
+		reg1 = JZ4780_GPIO_PAT1;
+		reg2 = JZ4780_GPIO_PAT0;
+	} else {
+		reg1 = JZ4740_GPIO_TRIG;
+		reg2 = JZ4740_GPIO_DIR;
+	}
+
+	switch (type) {
+	case IRQ_TYPE_EDGE_RISING:
+		writel(BIT(offset), jzgc->base + REG_SET(reg2));
+		writel(BIT(offset), jzgc->base + REG_SET(reg1));
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		writel(BIT(offset), jzgc->base + REG_CLEAR(reg2));
+		writel(BIT(offset), jzgc->base + REG_SET(reg1));
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		writel(BIT(offset), jzgc->base + REG_SET(reg2));
+		writel(BIT(offset), jzgc->base + REG_CLEAR(reg1));
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+	default:
+		writel(BIT(offset), jzgc->base + REG_CLEAR(reg2));
+		writel(BIT(offset), jzgc->base + REG_CLEAR(reg1));
+		break;
+	}
+}
+
+static void ingenic_gpio_irq_mask(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	writel(BIT(irqd->hwirq), jzgc->base + REG_SET(GPIO_MSK));
+}
+
+static void ingenic_gpio_irq_unmask(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	writel(BIT(irqd->hwirq), jzgc->base + REG_CLEAR(GPIO_MSK));
+}
+
+static void ingenic_gpio_irq_enable(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+	int irq = irqd->hwirq;
+
+	if (jzgc->version >= ID_JZ4780)
+		writel(BIT(irq), jzgc->base + REG_SET(JZ4780_GPIO_INT));
+	else
+		writel(BIT(irq), jzgc->base + REG_SET(JZ4740_GPIO_SELECT));
+
+	ingenic_gpio_irq_unmask(irqd);
+}
+
+static void ingenic_gpio_irq_disable(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+	int irq = irqd->hwirq;
+
+	ingenic_gpio_irq_mask(irqd);
+
+	if (jzgc->version >= ID_JZ4780)
+		writel(BIT(irq), jzgc->base + REG_CLEAR(JZ4780_GPIO_INT));
+	else
+		writel(BIT(irq), jzgc->base + REG_CLEAR(JZ4740_GPIO_SELECT));
+}
+
+static void ingenic_gpio_irq_ack(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+	int irq = irqd->hwirq;
+	bool high;
+
+	if (irqd_get_trigger_type(irqd) == IRQ_TYPE_EDGE_BOTH) {
+		/*
+		 * Switch to an interrupt for the opposite edge to the one that
+		 * triggered the interrupt being ACKed.
+		 */
+		high = gpio_get_value(jzgc, irq);
+		if (high)
+			irq_set_type(jzgc, irq, IRQ_TYPE_EDGE_FALLING);
+		else
+			irq_set_type(jzgc, irq, IRQ_TYPE_EDGE_RISING);
+	}
+
+	if (jzgc->version >= ID_JZ4780)
+		writel(BIT(irq), jzgc->base + REG_CLEAR(JZ4780_GPIO_FLAG));
+	else
+		writel(BIT(irq), jzgc->base + REG_SET(JZ4740_GPIO_DATA));
+}
+
+static int ingenic_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	switch (type) {
+	case IRQ_TYPE_EDGE_BOTH:
+	case IRQ_TYPE_EDGE_RISING:
+	case IRQ_TYPE_EDGE_FALLING:
+		irq_set_handler_locked(irqd, handle_edge_irq);
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+	case IRQ_TYPE_LEVEL_LOW:
+		irq_set_handler_locked(irqd, handle_level_irq);
+		break;
+	default:
+		irq_set_handler_locked(irqd, handle_bad_irq);
+	}
+
+	if (type == IRQ_TYPE_EDGE_BOTH) {
+		/*
+		 * The hardware does not support interrupts on both edges. The
+		 * best we can do is to set up a single-edge interrupt and then
+		 * switch to the opposing edge when ACKing the interrupt.
+		 */
+		bool high = gpio_get_value(jzgc, irqd->hwirq);
+
+		type = high ? IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING;
+	}
+
+	irq_set_type(jzgc, irqd->hwirq, type);
+	return 0;
+}
+
+static int ingenic_gpio_irq_set_wake(struct irq_data *irqd, unsigned int on)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	return irq_set_irq_wake(jzgc->irq, on);
+}
+
+static void ingenic_gpio_irq_handler(struct irq_desc *desc)
+{
+	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+	struct irq_chip *irq_chip = irq_data_get_irq_chip(&desc->irq_data);
+	unsigned long flag, i;
+
+	chained_irq_enter(irq_chip, desc);
+
+	if (jzgc->version >= ID_JZ4780)
+		flag = readl(jzgc->base + JZ4780_GPIO_FLAG);
+	else
+		flag = readl(jzgc->base + JZ4740_GPIO_FLAG);
+
+	for_each_set_bit(i, &flag, 32)
+		generic_handle_irq(irq_linear_revmap(gc->irqdomain, i));
+	chained_irq_exit(irq_chip, desc);
+}
+
+static void ingenic_gpio_set(struct gpio_chip *gc,
+		unsigned int offset, int value)
+{
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	gpio_set_value(jzgc, offset, value);
+}
+
+static int ingenic_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	return (int) gpio_get_value(jzgc, offset);
+}
+
+static int ingenic_gpio_direction_input(struct gpio_chip *gc,
+		unsigned int offset)
+{
+	return pinctrl_gpio_direction_input(gc->base + offset);
+}
+
+static int ingenic_gpio_direction_output(struct gpio_chip *gc,
+		unsigned int offset, int value)
+{
+	ingenic_gpio_set(gc, offset, value);
+	return pinctrl_gpio_direction_output(gc->base + offset);
+}
+
+static const struct of_device_id ingenic_gpio_of_match[] = {
+	{ .compatible = "ingenic,jz4740-gpio", .data = (void *)ID_JZ4740 },
+	{ .compatible = "ingenic,jz4780-gpio", .data = (void *)ID_JZ4780 },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ingenic_gpio_of_match);
+
+static int ingenic_gpio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	const struct of_device_id *of_id = of_match_device(
+			ingenic_gpio_of_match, dev);
+	struct ingenic_gpio_chip *jzgc;
+	int err;
+
+	jzgc = devm_kzalloc(dev, sizeof(*jzgc), GFP_KERNEL);
+	if (!jzgc)
+		return -ENOMEM;
+
+	jzgc->base = of_iomap(dev->of_node, 0);
+	if (!jzgc->base) {
+		dev_err(dev, "failed to map IO memory\n");
+		return -ENXIO;
+	}
+
+	jzgc->gc.base = -1;
+	jzgc->gc.ngpio = 32;
+	jzgc->gc.parent = dev;
+	jzgc->gc.of_node = dev->of_node;
+	jzgc->gc.label = "";
+	jzgc->gc.owner = THIS_MODULE;
+	jzgc->version = (enum jz_version)of_id->data;
+
+	jzgc->gc.set = ingenic_gpio_set;
+	jzgc->gc.get = ingenic_gpio_get;
+	jzgc->gc.direction_input = ingenic_gpio_direction_input;
+	jzgc->gc.direction_output = ingenic_gpio_direction_output;
+
+	if (of_property_read_bool(dev->of_node, "gpio-ranges")) {
+		jzgc->gc.request = gpiochip_generic_request;
+		jzgc->gc.free = gpiochip_generic_free;
+	}
+
+	of_property_read_u32(dev->of_node, "base", &jzgc->gc.base);
+
+	err = devm_gpiochip_add_data(dev, &jzgc->gc, jzgc);
+	if (err)
+		return err;
+
+	if (!of_property_read_bool(dev->of_node, "interrupt-controller"))
+		return 0;
+
+	jzgc->irq = irq_of_parse_and_map(dev->of_node, 0);
+	if (!jzgc->irq)
+		return -EINVAL;
+
+	jzgc->irq_chip.name = dev->of_node->name;
+	jzgc->irq_chip.irq_enable = ingenic_gpio_irq_enable;
+	jzgc->irq_chip.irq_disable = ingenic_gpio_irq_disable;
+	jzgc->irq_chip.irq_unmask = ingenic_gpio_irq_unmask;
+	jzgc->irq_chip.irq_mask = ingenic_gpio_irq_mask;
+	jzgc->irq_chip.irq_ack = ingenic_gpio_irq_ack;
+	jzgc->irq_chip.irq_set_type = ingenic_gpio_irq_set_type;
+	jzgc->irq_chip.irq_set_wake = ingenic_gpio_irq_set_wake;
+	jzgc->irq_chip.flags = IRQCHIP_MASK_ON_SUSPEND;
+
+	err = gpiochip_irqchip_add(&jzgc->gc, &jzgc->irq_chip, 0,
+			handle_level_irq, IRQ_TYPE_NONE);
+	if (err)
+		return err;
+
+	gpiochip_set_chained_irqchip(&jzgc->gc, &jzgc->irq_chip,
+			jzgc->irq, ingenic_gpio_irq_handler);
+	return 0;
+}
+
+static int ingenic_gpio_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver ingenic_gpio_driver = {
+	.driver = {
+		.name = "gpio-ingenic",
+		.of_match_table = of_match_ptr(ingenic_gpio_of_match),
+	},
+	.probe = ingenic_gpio_probe,
+	.remove = ingenic_gpio_remove,
+};
+
+static int __init ingenic_gpio_drv_register(void)
+{
+	return platform_driver_register(&ingenic_gpio_driver);
+}
+subsys_initcall(ingenic_gpio_drv_register);
+
+static void __exit ingenic_gpio_drv_unregister(void)
+{
+	platform_driver_unregister(&ingenic_gpio_driver);
+}
+module_exit(ingenic_gpio_drv_unregister);
+
+MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
+MODULE_DESCRIPTION("Ingenic JZ47xx GPIO driver");
+MODULE_LICENSE("GPL");
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v3 05/14] MIPS: ingenic: Enable pinctrl for all ingenic SoCs
  2017-01-25 18:51     ` [PATCH v3 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                         ` (3 preceding siblings ...)
  2017-01-25 18:51       ` [PATCH v3 04/14] GPIO: Add gpio-ingenic driver Paul Cercueil
@ 2017-01-25 18:51       ` Paul Cercueil
  2017-01-25 18:51       ` [PATCH v3 06/14] MIPS: jz4740: DTS: Add nodes for ingenic pinctrl and gpio drivers Paul Cercueil
                         ` (8 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-25 18:51 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

There is a pinctrl driver for each of the Ingenic SoCs supported by the
upstream Linux kernel. In order to switch away from the old GPIO
platform code, we now enable the pinctrl drivers by default for the
Ingenic SoCs.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/Kconfig | 1 +
 1 file changed, 1 insertion(+)

v2: No changes
v3: No changes

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index b3c5bde43d34..fc720e37661e 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -359,6 +359,7 @@ config MACH_INGENIC
 	select SYS_SUPPORTS_ZBOOT_UART16550
 	select DMA_NONCOHERENT
 	select IRQ_MIPS_CPU
+	select PINCTRL
 	select GPIOLIB
 	select COMMON_CLK
 	select GENERIC_IRQ_CHIP
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v3 06/14] MIPS: jz4740: DTS: Add nodes for ingenic pinctrl and gpio drivers
  2017-01-25 18:51     ` [PATCH v3 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                         ` (4 preceding siblings ...)
  2017-01-25 18:51       ` [PATCH v3 05/14] MIPS: ingenic: Enable pinctrl for all ingenic SoCs Paul Cercueil
@ 2017-01-25 18:51       ` Paul Cercueil
  2017-01-31 14:16         ` Linus Walleij
  2017-01-25 18:52       ` [PATCH v3 07/14] MIPS: jz4780: " Paul Cercueil
                         ` (7 subsequent siblings)
  13 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-01-25 18:51 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

For a description of the pinctrl devicetree node, please read
Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt

For a description of the gpio devicetree nodes, please read
Documentation/devicetree/bindings/gpio/ingenic,gpio.txt

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/boot/dts/ingenic/jz4740.dtsi | 194 +++++++++++++++++++++++++++++++++
 1 file changed, 194 insertions(+)

v2: Changed the devicetree bindings to match the new driver
v3: No changes

diff --git a/arch/mips/boot/dts/ingenic/jz4740.dtsi b/arch/mips/boot/dts/ingenic/jz4740.dtsi
index 3e1587f1f77a..960e060eb725 100644
--- a/arch/mips/boot/dts/ingenic/jz4740.dtsi
+++ b/arch/mips/boot/dts/ingenic/jz4740.dtsi
@@ -55,6 +55,200 @@
 		clock-names = "rtc";
 	};
 
+	pinctrl: ingenic-pinctrl@10010000 {
+		compatible = "ingenic,jz4740-pinctrl";
+		reg = <0x10010000 0x400>;
+
+		ingenic,pull-ups   = <0xffffffff 0xffffffff 0xffffffff 0xdfffffff>;
+		ingenic,pull-downs = <0x00000000 0x00000000 0x00000000 0x00000000>;
+
+		functions {
+			mmc {
+				mmc-1bit {
+					/* CLK, CMD, D0 */
+					ingenic,pins = <0x69 0 0x68 0 0x6a 0>;
+				};
+
+				mmc-4bit {
+					/* D1, D2, D3 */
+					ingenic,pins = <0x6b 0 0x6c 0 0x6d 0>;
+				};
+			};
+
+			uart0 {
+				uart0-data {
+					/* RXD, TXD */
+					ingenic,pins = <0x7a 1 0x79 1>;
+				};
+
+				uart0-hwflow {
+					/* CTS, RTS */
+					ingenic,pins = <0x7e 1 0x7f 1>;
+				};
+			};
+
+			uart1 {
+				uart1-data {
+					/* RXD, TXD */
+					ingenic,pins = <0x7e 2 0x7f 2>;
+				};
+			};
+
+			lcd {
+				lcd-8bit {
+					/* LCD_DATA0 ... LCD_DATA7, PCLK, HSYNC, VSYNC */
+					ingenic,pins = <0x40 0 0x41 0 0x42 0 0x43 0
+									0x44 0 0x45 0 0x46 0 0x47 0
+									0x52 0 0x53 0 0x54 0>;
+				};
+
+				lcd-16bit {
+					/* LCD_DATA8 ... LCD_DATA15, DE */
+					ingenic,pins = <0x48 0 0x49 0 0x4a 0 0x4b 0
+									0x4c 0 0x4d 0 0x4e 0 0x4f 0
+									0x55 0>;
+				};
+
+				lcd-18bit {
+					/* LCD_DATA16, LCD_DATA17 */
+					ingenic,pins = <0x50 0 0x51 0>;
+				};
+
+				lcd-18bit-tft {
+					/* PS, REV, CLS, SPL */
+					ingenic,pins = <0x56 0 0x57 0 0x31 0 0x32 0>;
+				};
+
+				lcd-no-pins {
+					ingenic,pins = <>;
+				};
+			};
+
+			nand {
+				nand {
+					/* CS1, CS2, CS3, CS4 */
+					ingenic,pins = <0x39 0 0x3a 0 0x3b 0 0x3c 0>;
+				};
+			};
+
+			pwm0 {
+				pwm0 {
+					ingenic,pins = <0x77 0>;
+				};
+			};
+
+			pwm1 {
+				pwm1 {
+					ingenic,pins = <0x78 0>;
+				};
+			};
+
+			pwm2 {
+				pwm2 {
+					ingenic,pins = <0x79 0>;
+				};
+			};
+
+			pwm3 {
+				pwm3 {
+					ingenic,pins = <0x7a 0>;
+				};
+			};
+
+			pwm4 {
+				pwm4 {
+					ingenic,pins = <0x7b 0>;
+				};
+			};
+
+			pwm5 {
+				pwm5 {
+					ingenic,pins = <0x7c 0>;
+				};
+			};
+
+			pwm6 {
+				pwm6 {
+					ingenic,pins = <0x7e 0>;
+				};
+			};
+
+			pwm7 {
+				pwm7 {
+					ingenic,pins = <0x7f 0>;
+				};
+			};
+		};
+	};
+
+	gpa: gpio-controller@10010000 {
+		compatible = "ingenic,jz4740-gpio";
+		reg = <0x10010000 0x100>;
+
+		gpio-controller;
+		gpio-ranges = <&pinctrl 0 0 32>;
+		#gpio-cells = <2>;
+
+		base = <0x00>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <28>;
+	};
+
+	gpb: gpio-controller@10010100 {
+		compatible = "ingenic,jz4740-gpio";
+		reg = <0x10010100 0x100>;
+
+		gpio-controller;
+		gpio-ranges = <&pinctrl 0 32 32>;
+		#gpio-cells = <2>;
+
+		base = <0x20>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <27>;
+	};
+
+	gpc: gpio-controller@10010200 {
+		compatible = "ingenic,jz4740-gpio";
+		reg = <0x10010200 0x100>;
+
+		gpio-controller;
+		gpio-ranges = <&pinctrl 0 64 32>;
+		#gpio-cells = <2>;
+
+		base = <0x40>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <26>;
+	};
+
+	gpd: gpio-controller@10010300 {
+		compatible = "ingenic,jz4740-gpio";
+		reg = <0x10010300 0x100>;
+
+		gpio-controller;
+		gpio-ranges = <&pinctrl 0 96 32>;
+		#gpio-cells = <2>;
+
+		base = <0x60>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <25>;
+	};
+
 	uart0: serial@10030000 {
 		compatible = "ingenic,jz4740-uart";
 		reg = <0x10030000 0x100>;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v3 07/14] MIPS: jz4780: DTS: Add nodes for ingenic pinctrl and gpio drivers
  2017-01-25 18:51     ` [PATCH v3 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                         ` (5 preceding siblings ...)
  2017-01-25 18:51       ` [PATCH v3 06/14] MIPS: jz4740: DTS: Add nodes for ingenic pinctrl and gpio drivers Paul Cercueil
@ 2017-01-25 18:52       ` Paul Cercueil
  2017-01-25 18:52       ` [PATCH v3 08/14] MIPS: JZ4740: Qi LB60: Add pinctrl configuration for several drivers Paul Cercueil
                         ` (6 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-25 18:52 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

For a description of the devicetree node, please read
Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt

For a description of the gpio devicetree nodes, please read
Documentation/devicetree/bindings/gpio/ingenic,gpio.txt

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/boot/dts/ingenic/jz4780.dtsi | 297 +++++++++++++++++++++++++++++++++
 1 file changed, 297 insertions(+)

v2: Changed the devicetree bindings to match the new driver
v3: No changes

diff --git a/arch/mips/boot/dts/ingenic/jz4780.dtsi b/arch/mips/boot/dts/ingenic/jz4780.dtsi
index b868b429add2..47e079e9236e 100644
--- a/arch/mips/boot/dts/ingenic/jz4780.dtsi
+++ b/arch/mips/boot/dts/ingenic/jz4780.dtsi
@@ -44,6 +44,303 @@
 		#clock-cells = <1>;
 	};
 
+	pinctrl: ingenic-pinctrl@10010000 {
+		compatible = "ingenic,jz4780-pinctrl";
+		reg = <0x10010000 0x600>;
+
+		ingenic,pull-ups   = <0x3fffffff 0xfff0030c 0xffffffff
+							  0xffff4fff 0xfffffb7c 0xffa7f00f>;
+		ingenic,pull-downs = <0x00000000 0x000f0c03 0x00000000
+							  0x0000b000 0x00000483 0x00580ff0>;
+
+		functions {
+			uart0 {
+				uart0-data {
+					/* RXD, TXD */
+					ingenic,pins = <0xa0 0 0xa3 0>;
+				};
+
+				uart0-hwflow {
+					/* CTS, RTS */
+					ingenic,pins = <0xa1 0 0xa2 0>;
+				};
+			};
+
+			uart1 {
+				uart1-data {
+					/* RXD, TXD */
+					ingenic,pins = <0x7a 0 0x7c 0>;
+				};
+
+				uart1-hwflow {
+					/* CTS, RTS */
+					ingenic,pins = <0x7b 0 0x7d 0>;
+				};
+			};
+
+			uart2 {
+				uart2-data {
+					/* RXD, TXD */
+					ingenic,pins = <0x66 1 0x67 1>;
+				};
+
+				uart2-hwflow {
+					/* CTS, RTS */
+					ingenic,pins = <0x65 1 0x64 1>;
+				};
+			};
+
+			uart3 {
+				uart3-data {
+					/* RXD, TXD */
+					ingenic,pins = <0x6c 0 0x85 1>;
+				};
+
+				uart3-hwflow {
+					/* CTS, RTS */
+					ingenic,pins = <0x88 0 0x89 0>;
+				};
+			};
+
+			uart4 {
+				uart4-data {
+					/* RXD, TXD */
+					ingenic,pins = <0x54 2 0x4a 2>;
+				};
+			};
+
+			msc0 {
+				msc0-8bit-a {
+					/* D4, D5, D6, D7, RST */
+					ingenic,pins = <0x04 1 0x05 1 0x06 1 0x07 1
+									0x18 1>;
+				};
+
+				msc0-4bit-a {
+					/* D1, D2, D3 */
+					ingenic,pins = <0x15 1 0x16 1 0x17 1>;
+				};
+
+				msc0-1bit-a {
+					/* CLK, CMD, D0 */
+					ingenic,pins = <0x12 1 0x13 1 0x14 1>;
+				};
+
+				msc0-1bit-e {
+					/* CLK, CMD, D0 */
+					ingenic,pins = <0x9c 0 0x9d 0 0x94 0>;
+				};
+
+				msc0-4bit-e {
+					/* D1, D2, D3 */
+					ingenic,pins = <0x95 0 0x96 0 0x97 0>;
+				};
+			};
+
+			msc1 {
+				msc1-1bit-d {
+					/* CLK, CMD, D0 */
+					ingenic,pins = <0x78 0 0x79 0 0x74 0>;
+				};
+
+				msc1-4bit-d {
+					/* D1, D2, D3 */
+					ingenic,pins = <0x75 0 0x76 0 0x77 0>;
+				};
+
+				msc1-1bit-e {
+					/* CLK, CMD, D0 */
+					ingenic,pins = <0x9c 1 0x9d 1 0x94 1>;
+				};
+
+				msc1-4bit-e {
+					/* D1, D2, D3 */
+					ingenic,pins = <0x95 1 0x96 1 0x97 1>;
+				};
+			};
+
+			nemc {
+				nemc-data {
+					/* SD0, SD1, SD2, SD3, SD4, SD5, SD6, SD7 */
+					ingenic,pins = <0x00 0 0x01 0 0x02 0 0x03 0
+									0x04 0 0x05 0 0x06 0 0x07 0>;
+				};
+
+				nemc-cle-ale {
+					/* SA0_CL, SA1_AL */
+					ingenic,pins = <0x20 0 0x21 0>;
+				};
+
+				nemc-addr {
+					/* SA2, SA3, SA4, SA5 */
+					ingenic,pins = <0x22 0 0x23 0 0x24 0 0x25 0>;
+				};
+
+				nemc-rd-we {
+					/* RD, WE */
+					ingenic,pins = <0x10 0 0x11 0>;
+				};
+
+				nemc-frd-fwe {
+					/* RD, WE */
+					ingenic,pins = <0x12 0 0x13 0>;
+				};
+			};
+
+			nemc-cs1 {
+				nemc-cs1 {
+					/* CS1 */
+					ingenic,pins = <0x15 0>;
+				};
+			};
+
+			nemc-cs6 {
+				nemc-cs6 {
+					/* CS6 */
+					ingenic,pins = <0x1a 0>;
+				};
+			};
+
+			i2c0 {
+				i2c0-data {
+					/* SDA, SCL */
+					ingenic,pins = <0x6e 0 0x6f 0>;
+				};
+			};
+
+			i2c1 {
+				i2c1-data {
+					/* SDA, SCL */
+					ingenic,pins = <0x8e 0 0x8f 0>;
+				};
+			};
+
+			i2c2 {
+				i2c2-data {
+					/* SDA, SCL */
+					ingenic,pins = <0xb0 2 0xb1 2>;
+				};
+			};
+
+			i2c3 {
+				i2c3-data {
+					/* SDA, SCL */
+					ingenic,pins = <0x6a 1 0x6b 1>;
+				};
+			};
+
+			i2c4 {
+				i2c4-data-pe {
+					/* SDA, SCL */
+					ingenic,pins = <0x8c 1 0x8d 1>;
+				};
+
+				i2c4-data-pf {
+					/* HDMI_SDA, HDMI_SCL */
+					ingenic,pins = <0xb9 1 0xb8 1>;
+				};
+			};
+
+			cim {
+				cim-pb {
+					ingenic,pins = <0x26 0 0x27 0 0x28 0 0x29 0
+									0x2a 0 0x2b 0 0x2c 0 0x2d 0
+									0x2e 0 0x2f 0 0x30 0 0x31 0>;
+				};
+			};
+		};
+	};
+
+	gpa: gpio-controller@10010000 {
+		compatible = "ingenic,jz4780-gpio";
+		reg = <0x10010000 0x100>;
+
+		gpio-controller;
+		gpio-ranges = <&pinctrl 0 0 32>;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <17>;
+	};
+
+	gpb: gpio-controller@10010100 {
+		compatible = "ingenic,jz4780-gpio";
+		reg = <0x10010100 0x100>;
+
+		gpio-controller;
+		gpio-ranges = <&pinctrl 0 32 32>;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <16>;
+	};
+
+	gpc: gpio-controller@10010200 {
+		compatible = "ingenic,jz4780-gpio";
+		reg = <0x10010200 0x100>;
+
+		gpio-controller;
+		gpio-ranges = <&pinctrl 0 64 32>;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <15>;
+	};
+
+	gpd: gpio-controller@10010300 {
+		compatible = "ingenic,jz4780-gpio";
+		reg = <0x10010300 0x100>;
+
+		gpio-controller;
+		gpio-ranges = <&pinctrl 0 96 32>;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <14>;
+	};
+
+	gpe: gpio-controller@10010400 {
+		compatible = "ingenic,jz4780-gpio";
+		reg = <0x10010400 0x100>;
+
+		gpio-controller;
+		gpio-ranges = <&pinctrl 0 128 32>;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <13>;
+	};
+
+	gpf: gpio-controller@10010500 {
+		compatible = "ingenic,jz4780-gpio";
+		reg = <0x10010500 0x100>;
+
+		gpio-controller;
+		gpio-ranges = <&pinctrl 0 160 32>;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <12>;
+	};
+
 	uart0: serial@10030000 {
 		compatible = "ingenic,jz4780-uart";
 		reg = <0x10030000 0x100>;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v3 08/14] MIPS: JZ4740: Qi LB60: Add pinctrl configuration for several drivers
  2017-01-25 18:51     ` [PATCH v3 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                         ` (6 preceding siblings ...)
  2017-01-25 18:52       ` [PATCH v3 07/14] MIPS: jz4780: " Paul Cercueil
@ 2017-01-25 18:52       ` Paul Cercueil
  2017-01-25 18:52       ` [PATCH v3 09/14] MIPS: JZ4780: CI20: " Paul Cercueil
                         ` (5 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-25 18:52 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

We set the pin configuration for the jz4740-nand, jz4740-mmc,
jz4740-fb, jz4740-pwm and jz4740-uart drivers.

This will permit those drivers to be cleaned out of the custom GPIO code
that they currently use.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/boot/dts/ingenic/qi_lb60.dts | 13 +++++++++++
 arch/mips/jz4740/board-qi_lb60.c       | 42 ++++++++++++++++++++++++++--------
 2 files changed, 46 insertions(+), 9 deletions(-)

v2: Changed the devicetree bindings to match the new driver
v3: No changes

diff --git a/arch/mips/boot/dts/ingenic/qi_lb60.dts b/arch/mips/boot/dts/ingenic/qi_lb60.dts
index be1a7d3a3e1b..b715ee2ac2ee 100644
--- a/arch/mips/boot/dts/ingenic/qi_lb60.dts
+++ b/arch/mips/boot/dts/ingenic/qi_lb60.dts
@@ -17,3 +17,16 @@
 &rtc_dev {
 	system-power-controller;
 };
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart0>;
+};
+
+&pinctrl {
+	pins_uart0: uart0 {
+		function = "uart0";
+		groups = "uart0-data";
+		bias-disable;
+	};
+};
diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c
index a5bd94b95263..bf3dcc9ee9f8 100644
--- a/arch/mips/jz4740/board-qi_lb60.c
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -22,6 +22,8 @@
 #include <linux/input/matrix_keypad.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_gpio.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf-generic.h>
 #include <linux/power_supply.h>
 #include <linux/power/jz4740-battery.h>
 #include <linux/power/gpio-charger.h>
@@ -447,13 +449,36 @@ static struct platform_device *jz_platform_devices[] __initdata = {
 	&qi_lb60_audio_device,
 };
 
-static void __init board_gpio_setup(void)
-{
-	/* We only need to enable/disable pullup here for pins used in generic
-	 * drivers. Everything else is done by the drivers themselves. */
-	jz_gpio_disable_pullup(QI_LB60_GPIO_SD_VCC_EN_N);
-	jz_gpio_disable_pullup(QI_LB60_GPIO_SD_CD);
-}
+static unsigned long pin_cfg_bias_disable[] = {
+	    PIN_CONFIG_BIAS_DISABLE,
+};
+
+static struct pinctrl_map pin_map[] __initdata = {
+	/* NAND pin configuration */
+	PIN_MAP_MUX_GROUP_DEFAULT("jz4740-nand",
+			"10010000.jz4740-pinctrl", "nand", "nand"),
+
+	/* fbdev pin configuration */
+	PIN_MAP_MUX_GROUP("jz4740-fb", PINCTRL_STATE_DEFAULT,
+			"10010000.jz4740-pinctrl", "lcd", "lcd-8bit"),
+	PIN_MAP_MUX_GROUP("jz4740-fb", PINCTRL_STATE_SLEEP,
+			"10010000.jz4740-pinctrl", "lcd", "lcd-no-pins"),
+
+	/* MMC pin configuration */
+	PIN_MAP_MUX_GROUP_DEFAULT("jz4740-mmc.0",
+			"10010000.jz4740-pinctrl", "mmc", "mmc-1bit"),
+	PIN_MAP_MUX_GROUP_DEFAULT("jz4740-mmc.0",
+			"10010000.jz4740-pinctrl", "mmc", "mmc-4bit"),
+	PIN_MAP_CONFIGS_PIN_DEFAULT("jz4740-mmc.0",
+			"10010000.jz4740-pinctrl", "PD0", pin_cfg_bias_disable),
+	PIN_MAP_CONFIGS_PIN_DEFAULT("jz4740-mmc.0",
+			"10010000.jz4740-pinctrl", "PD2", pin_cfg_bias_disable),
+
+	/* PWM pin configuration */
+	PIN_MAP_MUX_GROUP_DEFAULT("jz4740-pwm",
+			"10010000.jz4740-pinctrl", "pwm4", "pwm4"),
+};
+
 
 static int __init qi_lb60_init_platform_devices(void)
 {
@@ -469,6 +494,7 @@ static int __init qi_lb60_init_platform_devices(void)
 				ARRAY_SIZE(qi_lb60_spi_board_info));
 
 	pwm_add_table(qi_lb60_pwm_lookup, ARRAY_SIZE(qi_lb60_pwm_lookup));
+	pinctrl_register_mappings(pin_map, ARRAY_SIZE(pin_map));
 
 	return platform_add_devices(jz_platform_devices,
 					ARRAY_SIZE(jz_platform_devices));
@@ -479,8 +505,6 @@ static int __init qi_lb60_board_setup(void)
 {
 	printk(KERN_INFO "Qi Hardware JZ4740 QI LB60 setup\n");
 
-	board_gpio_setup();
-
 	if (qi_lb60_init_platform_devices())
 		panic("Failed to initialize platform devices");
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v3 09/14] MIPS: JZ4780: CI20: Add pinctrl configuration for several drivers
  2017-01-25 18:51     ` [PATCH v3 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                         ` (7 preceding siblings ...)
  2017-01-25 18:52       ` [PATCH v3 08/14] MIPS: JZ4740: Qi LB60: Add pinctrl configuration for several drivers Paul Cercueil
@ 2017-01-25 18:52       ` Paul Cercueil
  2017-01-25 18:52       ` [PATCH v3 10/14] mmc: jz4740: Let the pinctrl driver configure the pins Paul Cercueil
                         ` (4 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-25 18:52 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

We set the pin configuration for the jz4780-nand and jz4780-uart
drivers.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/boot/dts/ingenic/ci20.dts | 60 +++++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

v2: Changed the devicetree bindings to match the new driver
v3: No changes

diff --git a/arch/mips/boot/dts/ingenic/ci20.dts b/arch/mips/boot/dts/ingenic/ci20.dts
index 1652d8d60b1e..fd138d9978c1 100644
--- a/arch/mips/boot/dts/ingenic/ci20.dts
+++ b/arch/mips/boot/dts/ingenic/ci20.dts
@@ -29,18 +29,30 @@
 
 &uart0 {
 	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart0>;
 };
 
 &uart1 {
 	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart1>;
 };
 
 &uart3 {
 	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart2>;
 };
 
 &uart4 {
 	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart4>;
 };
 
 &nemc {
@@ -61,6 +73,13 @@
 		ingenic,nemc-tAW = <15>;
 		ingenic,nemc-tSTRV = <100>;
 
+		/*
+		 * Only CLE/ALE are needed for the devices that are connected, rather
+		 * than the full address line set.
+		 */
+		pinctrl-names = "default";
+		pinctrl-0 = <&pins_nemc>;
+
 		nand@1 {
 			reg = <1>;
 
@@ -69,6 +88,9 @@
 			nand-ecc-mode = "hw";
 			nand-on-flash-bbt;
 
+			pinctrl-names = "default";
+			pinctrl-0 = <&pins_nemc_cs1>;
+
 			partitions {
 				compatible = "fixed-partitions";
 				#address-cells = <2>;
@@ -106,3 +128,41 @@
 &bch {
 	status = "okay";
 };
+
+&pinctrl {
+	pins_uart0: uart0 {
+		function = "uart0";
+		groups = "uart0-data";
+		bias-disable;
+	};
+
+	pins_uart1: uart1 {
+		function = "uart1";
+		groups = "uart1-data";
+		bias-disable;
+	};
+
+	pins_uart2: uart2 {
+		function = "uart2";
+		groups = "uart2-data", "uart2-hwflow";
+		bias-disable;
+	};
+
+	pins_uart4: uart4 {
+		function = "uart4";
+		groups = "uart4-data";
+		bias-disable;
+	};
+
+	pins_nemc: nemc {
+		function = "nemc";
+		groups = "nemc-data", "nemc-cle-ale", "nemc-rd-we", "nemc-frd-fwe";
+		bias-disable;
+	};
+
+	pins_nemc_cs1: nemc-cs1 {
+		function = "nemc-cs1";
+		groups = "nemc-cs1";
+		bias-disable;
+	};
+};
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v3 10/14] mmc: jz4740: Let the pinctrl driver configure the pins
  2017-01-25 18:51     ` [PATCH v3 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                         ` (8 preceding siblings ...)
  2017-01-25 18:52       ` [PATCH v3 09/14] MIPS: JZ4780: CI20: " Paul Cercueil
@ 2017-01-25 18:52       ` Paul Cercueil
  2017-01-26  6:11         ` kbuild test robot
  2017-01-25 18:52       ` [PATCH v3 11/14] mtd: nand: " Paul Cercueil
                         ` (3 subsequent siblings)
  13 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-01-25 18:52 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
the pins being properly configured before the driver probes.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/host/jz4740_mmc.c | 45 +++++--------------------------------------
 1 file changed, 5 insertions(+), 40 deletions(-)

v2: Set pin sleep/default state in suspend/resume callbacks
v3: No changes

diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c
index 819ad32964fc..b5fec5b7ee7b 100644
--- a/drivers/mmc/host/jz4740_mmc.c
+++ b/drivers/mmc/host/jz4740_mmc.c
@@ -20,14 +20,13 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/scatterlist.h>
 #include <linux/clk.h>
 
 #include <linux/bitops.h>
-#include <linux/gpio.h>
-#include <asm/mach-jz4740/gpio.h>
 #include <asm/cacheflush.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
@@ -906,15 +905,6 @@ static const struct mmc_host_ops jz4740_mmc_ops = {
 	.enable_sdio_irq = jz4740_mmc_enable_sdio_irq,
 };
 
-static const struct jz_gpio_bulk_request jz4740_mmc_pins[] = {
-	JZ_GPIO_BULK_PIN(MSC_CMD),
-	JZ_GPIO_BULK_PIN(MSC_CLK),
-	JZ_GPIO_BULK_PIN(MSC_DATA0),
-	JZ_GPIO_BULK_PIN(MSC_DATA1),
-	JZ_GPIO_BULK_PIN(MSC_DATA2),
-	JZ_GPIO_BULK_PIN(MSC_DATA3),
-};
-
 static int jz4740_mmc_request_gpio(struct device *dev, int gpio,
 	const char *name, bool output, int value)
 {
@@ -978,15 +968,6 @@ static void jz4740_mmc_free_gpios(struct platform_device *pdev)
 		gpio_free(pdata->gpio_power);
 }
 
-static inline size_t jz4740_mmc_num_pins(struct jz4740_mmc_host *host)
-{
-	size_t num_pins = ARRAY_SIZE(jz4740_mmc_pins);
-	if (host->pdata && host->pdata->data_1bit)
-		num_pins -= 3;
-
-	return num_pins;
-}
-
 static int jz4740_mmc_probe(struct platform_device* pdev)
 {
 	int ret;
@@ -1027,15 +1008,9 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
 		goto err_free_host;
 	}
 
-	ret = jz_gpio_bulk_request(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
-	if (ret) {
-		dev_err(&pdev->dev, "Failed to request mmc pins: %d\n", ret);
-		goto err_free_host;
-	}
-
 	ret = jz4740_mmc_request_gpios(mmc, pdev);
 	if (ret)
-		goto err_gpio_bulk_free;
+		goto err_release_dma;
 
 	mmc->ops = &jz4740_mmc_ops;
 	mmc->f_min = JZ_MMC_CLK_RATE / 128;
@@ -1091,10 +1066,9 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
 	free_irq(host->irq, host);
 err_free_gpios:
 	jz4740_mmc_free_gpios(pdev);
-err_gpio_bulk_free:
+err_release_dma:
 	if (host->use_dma)
 		jz4740_mmc_release_dma_channels(host);
-	jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
 err_free_host:
 	mmc_free_host(mmc);
 
@@ -1114,7 +1088,6 @@ static int jz4740_mmc_remove(struct platform_device *pdev)
 	free_irq(host->irq, host);
 
 	jz4740_mmc_free_gpios(pdev);
-	jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
 
 	if (host->use_dma)
 		jz4740_mmc_release_dma_channels(host);
@@ -1128,20 +1101,12 @@ static int jz4740_mmc_remove(struct platform_device *pdev)
 
 static int jz4740_mmc_suspend(struct device *dev)
 {
-	struct jz4740_mmc_host *host = dev_get_drvdata(dev);
-
-	jz_gpio_bulk_suspend(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
-
-	return 0;
+	return pinctrl_pm_select_sleep_state(dev);
 }
 
 static int jz4740_mmc_resume(struct device *dev)
 {
-	struct jz4740_mmc_host *host = dev_get_drvdata(dev);
-
-	jz_gpio_bulk_resume(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
-
-	return 0;
+	return pinctrl_pm_select_default_state(dev);
 }
 
 static SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend,
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v3 11/14] mtd: nand: jz4740: Let the pinctrl driver configure the pins
  2017-01-25 18:51     ` [PATCH v3 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                         ` (9 preceding siblings ...)
  2017-01-25 18:52       ` [PATCH v3 10/14] mmc: jz4740: Let the pinctrl driver configure the pins Paul Cercueil
@ 2017-01-25 18:52       ` Paul Cercueil
  2017-01-25 18:52       ` [PATCH v3 12/14] fbdev: jz4740-fb: " Paul Cercueil
                         ` (2 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-25 18:52 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

Before, this NAND driver would set itself the configuration of the
chip-select pins for the various NAND banks.

Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
the pins being properly configured before the driver probes.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/mtd/nand/jz4740_nand.c | 23 +----------------------
 1 file changed, 1 insertion(+), 22 deletions(-)

v2: No changes
v3: No changes

diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
index 5551c36adbdf..0d06a1f07d82 100644
--- a/drivers/mtd/nand/jz4740_nand.c
+++ b/drivers/mtd/nand/jz4740_nand.c
@@ -25,7 +25,6 @@
 
 #include <linux/gpio.h>
 
-#include <asm/mach-jz4740/gpio.h>
 #include <asm/mach-jz4740/jz4740_nand.h>
 
 #define JZ_REG_NAND_CTRL	0x50
@@ -310,34 +309,20 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
 			       uint8_t *nand_dev_id)
 {
 	int ret;
-	int gpio;
-	char gpio_name[9];
 	char res_name[6];
 	uint32_t ctrl;
 	struct nand_chip *chip = &nand->chip;
 	struct mtd_info *mtd = nand_to_mtd(chip);
 
-	/* Request GPIO port. */
-	gpio = JZ_GPIO_MEM_CS0 + bank - 1;
-	sprintf(gpio_name, "NAND CS%d", bank);
-	ret = gpio_request(gpio, gpio_name);
-	if (ret) {
-		dev_warn(&pdev->dev,
-			"Failed to request %s gpio %d: %d\n",
-			gpio_name, gpio, ret);
-		goto notfound_gpio;
-	}
-
 	/* Request I/O resource. */
 	sprintf(res_name, "bank%d", bank);
 	ret = jz_nand_ioremap_resource(pdev, res_name,
 					&nand->bank_mem[bank - 1],
 					&nand->bank_base[bank - 1]);
 	if (ret)
-		goto notfound_resource;
+		return ret;
 
 	/* Enable chip in bank. */
-	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_MEM_CS0);
 	ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
 	ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1);
 	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
@@ -377,12 +362,8 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
 	dev_info(&pdev->dev, "No chip found on bank %i\n", bank);
 	ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1));
 	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
-	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE);
 	jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
 				 nand->bank_base[bank - 1]);
-notfound_resource:
-	gpio_free(gpio);
-notfound_gpio:
 	return ret;
 }
 
@@ -503,7 +484,6 @@ static int jz_nand_probe(struct platform_device *pdev)
 err_unclaim_banks:
 	while (chipnr--) {
 		unsigned char bank = nand->banks[chipnr];
-		gpio_free(JZ_GPIO_MEM_CS0 + bank - 1);
 		jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
 					 nand->bank_base[bank - 1]);
 	}
@@ -530,7 +510,6 @@ static int jz_nand_remove(struct platform_device *pdev)
 		if (bank != 0) {
 			jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
 						 nand->bank_base[bank - 1]);
-			gpio_free(JZ_GPIO_MEM_CS0 + bank - 1);
 		}
 	}
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v3 12/14] fbdev: jz4740-fb: Let the pinctrl driver configure the pins
  2017-01-25 18:51     ` [PATCH v3 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                         ` (10 preceding siblings ...)
  2017-01-25 18:52       ` [PATCH v3 11/14] mtd: nand: " Paul Cercueil
@ 2017-01-25 18:52       ` Paul Cercueil
  2017-01-30 16:10         ` Bartlomiej Zolnierkiewicz
  2017-01-25 18:52       ` [PATCH v3 13/14] pwm: jz4740: " Paul Cercueil
  2017-01-25 18:52       ` [PATCH v3 14/14] MIPS: jz4740: Remove custom GPIO code Paul Cercueil
  13 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-01-25 18:52 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
the pins being properly configured before the driver probes.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/video/fbdev/jz4740_fb.c | 104 ++--------------------------------------
 1 file changed, 3 insertions(+), 101 deletions(-)

v2: No changes
v3: No changes

diff --git a/drivers/video/fbdev/jz4740_fb.c b/drivers/video/fbdev/jz4740_fb.c
index 87790e9644d0..b57df83fdbd3 100644
--- a/drivers/video/fbdev/jz4740_fb.c
+++ b/drivers/video/fbdev/jz4740_fb.c
@@ -17,6 +17,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
 
 #include <linux/clk.h>
 #include <linux/delay.h>
@@ -27,7 +28,6 @@
 #include <linux/dma-mapping.h>
 
 #include <asm/mach-jz4740/jz4740_fb.h>
-#include <asm/mach-jz4740/gpio.h>
 
 #define JZ_REG_LCD_CFG		0x00
 #define JZ_REG_LCD_VSYNC	0x04
@@ -146,93 +146,6 @@ static const struct fb_fix_screeninfo jzfb_fix = {
 	.accel		= FB_ACCEL_NONE,
 };
 
-static const struct jz_gpio_bulk_request jz_lcd_ctrl_pins[] = {
-	JZ_GPIO_BULK_PIN(LCD_PCLK),
-	JZ_GPIO_BULK_PIN(LCD_HSYNC),
-	JZ_GPIO_BULK_PIN(LCD_VSYNC),
-	JZ_GPIO_BULK_PIN(LCD_DE),
-	JZ_GPIO_BULK_PIN(LCD_PS),
-	JZ_GPIO_BULK_PIN(LCD_REV),
-	JZ_GPIO_BULK_PIN(LCD_CLS),
-	JZ_GPIO_BULK_PIN(LCD_SPL),
-};
-
-static const struct jz_gpio_bulk_request jz_lcd_data_pins[] = {
-	JZ_GPIO_BULK_PIN(LCD_DATA0),
-	JZ_GPIO_BULK_PIN(LCD_DATA1),
-	JZ_GPIO_BULK_PIN(LCD_DATA2),
-	JZ_GPIO_BULK_PIN(LCD_DATA3),
-	JZ_GPIO_BULK_PIN(LCD_DATA4),
-	JZ_GPIO_BULK_PIN(LCD_DATA5),
-	JZ_GPIO_BULK_PIN(LCD_DATA6),
-	JZ_GPIO_BULK_PIN(LCD_DATA7),
-	JZ_GPIO_BULK_PIN(LCD_DATA8),
-	JZ_GPIO_BULK_PIN(LCD_DATA9),
-	JZ_GPIO_BULK_PIN(LCD_DATA10),
-	JZ_GPIO_BULK_PIN(LCD_DATA11),
-	JZ_GPIO_BULK_PIN(LCD_DATA12),
-	JZ_GPIO_BULK_PIN(LCD_DATA13),
-	JZ_GPIO_BULK_PIN(LCD_DATA14),
-	JZ_GPIO_BULK_PIN(LCD_DATA15),
-	JZ_GPIO_BULK_PIN(LCD_DATA16),
-	JZ_GPIO_BULK_PIN(LCD_DATA17),
-};
-
-static unsigned int jzfb_num_ctrl_pins(struct jzfb *jzfb)
-{
-	unsigned int num;
-
-	switch (jzfb->pdata->lcd_type) {
-	case JZ_LCD_TYPE_GENERIC_16_BIT:
-		num = 4;
-		break;
-	case JZ_LCD_TYPE_GENERIC_18_BIT:
-		num = 4;
-		break;
-	case JZ_LCD_TYPE_8BIT_SERIAL:
-		num = 3;
-		break;
-	case JZ_LCD_TYPE_SPECIAL_TFT_1:
-	case JZ_LCD_TYPE_SPECIAL_TFT_2:
-	case JZ_LCD_TYPE_SPECIAL_TFT_3:
-		num = 8;
-		break;
-	default:
-		num = 0;
-		break;
-	}
-	return num;
-}
-
-static unsigned int jzfb_num_data_pins(struct jzfb *jzfb)
-{
-	unsigned int num;
-
-	switch (jzfb->pdata->lcd_type) {
-	case JZ_LCD_TYPE_GENERIC_16_BIT:
-		num = 16;
-		break;
-	case JZ_LCD_TYPE_GENERIC_18_BIT:
-		num = 18;
-		break;
-	case JZ_LCD_TYPE_8BIT_SERIAL:
-		num = 8;
-		break;
-	case JZ_LCD_TYPE_SPECIAL_TFT_1:
-	case JZ_LCD_TYPE_SPECIAL_TFT_2:
-	case JZ_LCD_TYPE_SPECIAL_TFT_3:
-		if (jzfb->pdata->bpp == 18)
-			num = 18;
-		else
-			num = 16;
-		break;
-	default:
-		num = 0;
-		break;
-	}
-	return num;
-}
-
 /* Based on CNVT_TOHW macro from skeletonfb.c */
 static inline uint32_t jzfb_convert_color_to_hw(unsigned val,
 	struct fb_bitfield *bf)
@@ -487,8 +400,7 @@ static void jzfb_enable(struct jzfb *jzfb)
 
 	clk_prepare_enable(jzfb->ldclk);
 
-	jz_gpio_bulk_resume(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_resume(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
+	pinctrl_pm_select_default_state(&jzfb->pdev->dev);
 
 	writel(0, jzfb->base + JZ_REG_LCD_STATE);
 
@@ -511,8 +423,7 @@ static void jzfb_disable(struct jzfb *jzfb)
 		ctrl = readl(jzfb->base + JZ_REG_LCD_STATE);
 	} while (!(ctrl & JZ_LCD_STATE_DISABLED));
 
-	jz_gpio_bulk_suspend(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_suspend(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
+	pinctrl_pm_select_sleep_state(&jzfb->pdev->dev);
 
 	clk_disable_unprepare(jzfb->ldclk);
 }
@@ -701,9 +612,6 @@ static int jzfb_probe(struct platform_device *pdev)
 	fb->mode = NULL;
 	jzfb_set_par(fb);
 
-	jz_gpio_bulk_request(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_request(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
-
 	ret = register_framebuffer(fb);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to register framebuffer: %d\n", ret);
@@ -715,9 +623,6 @@ static int jzfb_probe(struct platform_device *pdev)
 	return 0;
 
 err_free_devmem:
-	jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
-
 	fb_dealloc_cmap(&fb->cmap);
 	jzfb_free_devmem(jzfb);
 err_framebuffer_release:
@@ -731,9 +636,6 @@ static int jzfb_remove(struct platform_device *pdev)
 
 	jzfb_blank(FB_BLANK_POWERDOWN, jzfb->fb);
 
-	jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
-
 	fb_dealloc_cmap(&jzfb->fb->cmap);
 	jzfb_free_devmem(jzfb);
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v3 13/14] pwm: jz4740: Let the pinctrl driver configure the pins
  2017-01-25 18:51     ` [PATCH v3 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                         ` (11 preceding siblings ...)
  2017-01-25 18:52       ` [PATCH v3 12/14] fbdev: jz4740-fb: " Paul Cercueil
@ 2017-01-25 18:52       ` Paul Cercueil
  2017-01-25 18:52       ` [PATCH v3 14/14] MIPS: jz4740: Remove custom GPIO code Paul Cercueil
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-25 18:52 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
the pins being properly configured before the driver probes.

One inherent problem of this new approach is that the pinctrl framework
does not allow us to configure each pin on demand, when the various PWM
channels are requested or released. For instance, the PWM channels can
be configured from sysfs, which would require all PWM pins to be configured
properly beforehand for the PWM function, eventually causing conflicts
with other platform or board drivers.

The proper solution here would be to modify the pwm-jz4740 driver to
handle only one PWM channel, and create an instance of this driver
for each one of the 8 PWM channels. Then, it could use the pinctrl
framework to dynamically configure the PWM pin it controls.

Until this can be done, the only jz4740 board supported upstream
(Qi lb60) can configure all of its connected PWM pins in PWM function
mode, since those are not used by other drivers nor by GPIOs on the
board.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/pwm/pwm-jz4740.c | 29 -----------------------------
 1 file changed, 29 deletions(-)

v2: No changes
v3: No changes

diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c
index 76d13150283f..a75ff3622450 100644
--- a/drivers/pwm/pwm-jz4740.c
+++ b/drivers/pwm/pwm-jz4740.c
@@ -21,22 +21,10 @@
 #include <linux/platform_device.h>
 #include <linux/pwm.h>
 
-#include <asm/mach-jz4740/gpio.h>
 #include <asm/mach-jz4740/timer.h>
 
 #define NUM_PWM 8
 
-static const unsigned int jz4740_pwm_gpio_list[NUM_PWM] = {
-	JZ_GPIO_PWM0,
-	JZ_GPIO_PWM1,
-	JZ_GPIO_PWM2,
-	JZ_GPIO_PWM3,
-	JZ_GPIO_PWM4,
-	JZ_GPIO_PWM5,
-	JZ_GPIO_PWM6,
-	JZ_GPIO_PWM7,
-};
-
 struct jz4740_pwm_chip {
 	struct pwm_chip chip;
 	struct clk *clk;
@@ -49,9 +37,6 @@ static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip)
 
 static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-	unsigned int gpio = jz4740_pwm_gpio_list[pwm->hwpwm];
-	int ret;
-
 	/*
 	 * Timers 0 and 1 are used for system tasks, so they are unavailable
 	 * for use as PWMs.
@@ -59,15 +44,6 @@ static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 	if (pwm->hwpwm < 2)
 		return -EBUSY;
 
-	ret = gpio_request(gpio, pwm->label);
-	if (ret) {
-		dev_err(chip->dev, "Failed to request GPIO#%u for PWM: %d\n",
-			gpio, ret);
-		return ret;
-	}
-
-	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_PWM);
-
 	jz4740_timer_start(pwm->hwpwm);
 
 	return 0;
@@ -75,13 +51,8 @@ static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 
 static void jz4740_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-	unsigned int gpio = jz4740_pwm_gpio_list[pwm->hwpwm];
-
 	jz4740_timer_set_ctrl(pwm->hwpwm, 0);
 
-	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE);
-	gpio_free(gpio);
-
 	jz4740_timer_stop(pwm->hwpwm);
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v3 14/14] MIPS: jz4740: Remove custom GPIO code
  2017-01-25 18:51     ` [PATCH v3 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                         ` (12 preceding siblings ...)
  2017-01-25 18:52       ` [PATCH v3 13/14] pwm: jz4740: " Paul Cercueil
@ 2017-01-25 18:52       ` Paul Cercueil
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-25 18:52 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan, Paul Cercueil

All the drivers for the various hardware elements of the jz4740 SoC have
been modified to use the pinctrl framework for their pin configuration
needs.
As such, this platform code is now unused and can be deleted.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/include/asm/mach-jz4740/gpio.h | 371 ----------------------
 arch/mips/jz4740/Makefile                |   2 -
 arch/mips/jz4740/gpio.c                  | 519 -------------------------------
 3 files changed, 892 deletions(-)
 delete mode 100644 arch/mips/jz4740/gpio.c

v2: No changes
v3: No changes

diff --git a/arch/mips/include/asm/mach-jz4740/gpio.h b/arch/mips/include/asm/mach-jz4740/gpio.h
index 7c7708a23baa..fd847c984701 100644
--- a/arch/mips/include/asm/mach-jz4740/gpio.h
+++ b/arch/mips/include/asm/mach-jz4740/gpio.h
@@ -16,380 +16,9 @@
 #ifndef _JZ_GPIO_H
 #define _JZ_GPIO_H
 
-#include <linux/types.h>
-
-enum jz_gpio_function {
-    JZ_GPIO_FUNC_NONE,
-    JZ_GPIO_FUNC1,
-    JZ_GPIO_FUNC2,
-    JZ_GPIO_FUNC3,
-};
-
-/*
- Usually a driver for a SoC component has to request several gpio pins and
- configure them as function pins.
- jz_gpio_bulk_request can be used to ease this process.
- Usually one would do something like:
-
- static const struct jz_gpio_bulk_request i2c_pins[] = {
-	JZ_GPIO_BULK_PIN(I2C_SDA),
-	JZ_GPIO_BULK_PIN(I2C_SCK),
- };
-
- inside the probe function:
-
-    ret = jz_gpio_bulk_request(i2c_pins, ARRAY_SIZE(i2c_pins));
-    if (ret) {
-	...
-
- inside the remove function:
-
-    jz_gpio_bulk_free(i2c_pins, ARRAY_SIZE(i2c_pins));
-
-*/
-
-struct jz_gpio_bulk_request {
-	int gpio;
-	const char *name;
-	enum jz_gpio_function function;
-};
-
-#define JZ_GPIO_BULK_PIN(pin) { \
-    .gpio = JZ_GPIO_ ## pin, \
-    .name = #pin, \
-    .function = JZ_GPIO_FUNC_ ## pin \
-}
-
-int jz_gpio_bulk_request(const struct jz_gpio_bulk_request *request, size_t num);
-void jz_gpio_bulk_free(const struct jz_gpio_bulk_request *request, size_t num);
-void jz_gpio_bulk_suspend(const struct jz_gpio_bulk_request *request, size_t num);
-void jz_gpio_bulk_resume(const struct jz_gpio_bulk_request *request, size_t num);
-void jz_gpio_enable_pullup(unsigned gpio);
-void jz_gpio_disable_pullup(unsigned gpio);
-int jz_gpio_set_function(int gpio, enum jz_gpio_function function);
-
-int jz_gpio_port_direction_input(int port, uint32_t mask);
-int jz_gpio_port_direction_output(int port, uint32_t mask);
-void jz_gpio_port_set_value(int port, uint32_t value, uint32_t mask);
-uint32_t jz_gpio_port_get_value(int port, uint32_t mask);
-
 #define JZ_GPIO_PORTA(x) ((x) + 32 * 0)
 #define JZ_GPIO_PORTB(x) ((x) + 32 * 1)
 #define JZ_GPIO_PORTC(x) ((x) + 32 * 2)
 #define JZ_GPIO_PORTD(x) ((x) + 32 * 3)
 
-/* Port A function pins */
-#define JZ_GPIO_MEM_DATA0		JZ_GPIO_PORTA(0)
-#define JZ_GPIO_MEM_DATA1		JZ_GPIO_PORTA(1)
-#define JZ_GPIO_MEM_DATA2		JZ_GPIO_PORTA(2)
-#define JZ_GPIO_MEM_DATA3		JZ_GPIO_PORTA(3)
-#define JZ_GPIO_MEM_DATA4		JZ_GPIO_PORTA(4)
-#define JZ_GPIO_MEM_DATA5		JZ_GPIO_PORTA(5)
-#define JZ_GPIO_MEM_DATA6		JZ_GPIO_PORTA(6)
-#define JZ_GPIO_MEM_DATA7		JZ_GPIO_PORTA(7)
-#define JZ_GPIO_MEM_DATA8		JZ_GPIO_PORTA(8)
-#define JZ_GPIO_MEM_DATA9		JZ_GPIO_PORTA(9)
-#define JZ_GPIO_MEM_DATA10		JZ_GPIO_PORTA(10)
-#define JZ_GPIO_MEM_DATA11		JZ_GPIO_PORTA(11)
-#define JZ_GPIO_MEM_DATA12		JZ_GPIO_PORTA(12)
-#define JZ_GPIO_MEM_DATA13		JZ_GPIO_PORTA(13)
-#define JZ_GPIO_MEM_DATA14		JZ_GPIO_PORTA(14)
-#define JZ_GPIO_MEM_DATA15		JZ_GPIO_PORTA(15)
-#define JZ_GPIO_MEM_DATA16		JZ_GPIO_PORTA(16)
-#define JZ_GPIO_MEM_DATA17		JZ_GPIO_PORTA(17)
-#define JZ_GPIO_MEM_DATA18		JZ_GPIO_PORTA(18)
-#define JZ_GPIO_MEM_DATA19		JZ_GPIO_PORTA(19)
-#define JZ_GPIO_MEM_DATA20		JZ_GPIO_PORTA(20)
-#define JZ_GPIO_MEM_DATA21		JZ_GPIO_PORTA(21)
-#define JZ_GPIO_MEM_DATA22		JZ_GPIO_PORTA(22)
-#define JZ_GPIO_MEM_DATA23		JZ_GPIO_PORTA(23)
-#define JZ_GPIO_MEM_DATA24		JZ_GPIO_PORTA(24)
-#define JZ_GPIO_MEM_DATA25		JZ_GPIO_PORTA(25)
-#define JZ_GPIO_MEM_DATA26		JZ_GPIO_PORTA(26)
-#define JZ_GPIO_MEM_DATA27		JZ_GPIO_PORTA(27)
-#define JZ_GPIO_MEM_DATA28		JZ_GPIO_PORTA(28)
-#define JZ_GPIO_MEM_DATA29		JZ_GPIO_PORTA(29)
-#define JZ_GPIO_MEM_DATA30		JZ_GPIO_PORTA(30)
-#define JZ_GPIO_MEM_DATA31		JZ_GPIO_PORTA(31)
-
-#define JZ_GPIO_FUNC_MEM_DATA0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA4		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA5		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA6		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA7		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA8		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA9		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA10		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA11		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA12		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA13		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA14		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA15		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA16		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA17		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA18		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA19		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA20		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA21		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA22		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA23		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA24		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA25		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA26		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA27		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA28		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA29		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA30		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA31		JZ_GPIO_FUNC1
-
-/* Port B function pins */
-#define JZ_GPIO_MEM_ADDR0		JZ_GPIO_PORTB(0)
-#define JZ_GPIO_MEM_ADDR1		JZ_GPIO_PORTB(1)
-#define JZ_GPIO_MEM_ADDR2		JZ_GPIO_PORTB(2)
-#define JZ_GPIO_MEM_ADDR3		JZ_GPIO_PORTB(3)
-#define JZ_GPIO_MEM_ADDR4		JZ_GPIO_PORTB(4)
-#define JZ_GPIO_MEM_ADDR5		JZ_GPIO_PORTB(5)
-#define JZ_GPIO_MEM_ADDR6		JZ_GPIO_PORTB(6)
-#define JZ_GPIO_MEM_ADDR7		JZ_GPIO_PORTB(7)
-#define JZ_GPIO_MEM_ADDR8		JZ_GPIO_PORTB(8)
-#define JZ_GPIO_MEM_ADDR9		JZ_GPIO_PORTB(9)
-#define JZ_GPIO_MEM_ADDR10		JZ_GPIO_PORTB(10)
-#define JZ_GPIO_MEM_ADDR11		JZ_GPIO_PORTB(11)
-#define JZ_GPIO_MEM_ADDR12		JZ_GPIO_PORTB(12)
-#define JZ_GPIO_MEM_ADDR13		JZ_GPIO_PORTB(13)
-#define JZ_GPIO_MEM_ADDR14		JZ_GPIO_PORTB(14)
-#define JZ_GPIO_MEM_ADDR15		JZ_GPIO_PORTB(15)
-#define JZ_GPIO_MEM_ADDR16		JZ_GPIO_PORTB(16)
-#define JZ_GPIO_LCD_CLS			JZ_GPIO_PORTB(17)
-#define JZ_GPIO_LCD_SPL			JZ_GPIO_PORTB(18)
-#define JZ_GPIO_MEM_DCS			JZ_GPIO_PORTB(19)
-#define JZ_GPIO_MEM_RAS			JZ_GPIO_PORTB(20)
-#define JZ_GPIO_MEM_CAS			JZ_GPIO_PORTB(21)
-#define JZ_GPIO_MEM_SDWE		JZ_GPIO_PORTB(22)
-#define JZ_GPIO_MEM_CKE			JZ_GPIO_PORTB(23)
-#define JZ_GPIO_MEM_CKO			JZ_GPIO_PORTB(24)
-#define JZ_GPIO_MEM_CS0			JZ_GPIO_PORTB(25)
-#define JZ_GPIO_MEM_CS1			JZ_GPIO_PORTB(26)
-#define JZ_GPIO_MEM_CS2			JZ_GPIO_PORTB(27)
-#define JZ_GPIO_MEM_CS3			JZ_GPIO_PORTB(28)
-#define JZ_GPIO_MEM_RD			JZ_GPIO_PORTB(29)
-#define JZ_GPIO_MEM_WR			JZ_GPIO_PORTB(30)
-#define JZ_GPIO_MEM_WE0			JZ_GPIO_PORTB(31)
-
-#define JZ_GPIO_FUNC_MEM_ADDR0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR4		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR5		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR6		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR7		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR8		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR9		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR10		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR11		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR12		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR13		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR14		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR15		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR16		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_CLS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_SPL		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DCS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_RAS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CAS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_SDWE		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CKE		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CKO		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CS0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CS1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CS2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CS3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_RD		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WR		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WE0		JZ_GPIO_FUNC1
-
-
-#define JZ_GPIO_MEM_ADDR21		JZ_GPIO_PORTB(17)
-#define JZ_GPIO_MEM_ADDR22		JZ_GPIO_PORTB(18)
-
-#define JZ_GPIO_FUNC_MEM_ADDR21		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_ADDR22		JZ_GPIO_FUNC2
-
-/* Port C function pins */
-#define JZ_GPIO_LCD_DATA0		JZ_GPIO_PORTC(0)
-#define JZ_GPIO_LCD_DATA1		JZ_GPIO_PORTC(1)
-#define JZ_GPIO_LCD_DATA2		JZ_GPIO_PORTC(2)
-#define JZ_GPIO_LCD_DATA3		JZ_GPIO_PORTC(3)
-#define JZ_GPIO_LCD_DATA4		JZ_GPIO_PORTC(4)
-#define JZ_GPIO_LCD_DATA5		JZ_GPIO_PORTC(5)
-#define JZ_GPIO_LCD_DATA6		JZ_GPIO_PORTC(6)
-#define JZ_GPIO_LCD_DATA7		JZ_GPIO_PORTC(7)
-#define JZ_GPIO_LCD_DATA8		JZ_GPIO_PORTC(8)
-#define JZ_GPIO_LCD_DATA9		JZ_GPIO_PORTC(9)
-#define JZ_GPIO_LCD_DATA10		JZ_GPIO_PORTC(10)
-#define JZ_GPIO_LCD_DATA11		JZ_GPIO_PORTC(11)
-#define JZ_GPIO_LCD_DATA12		JZ_GPIO_PORTC(12)
-#define JZ_GPIO_LCD_DATA13		JZ_GPIO_PORTC(13)
-#define JZ_GPIO_LCD_DATA14		JZ_GPIO_PORTC(14)
-#define JZ_GPIO_LCD_DATA15		JZ_GPIO_PORTC(15)
-#define JZ_GPIO_LCD_DATA16		JZ_GPIO_PORTC(16)
-#define JZ_GPIO_LCD_DATA17		JZ_GPIO_PORTC(17)
-#define JZ_GPIO_LCD_PCLK		JZ_GPIO_PORTC(18)
-#define JZ_GPIO_LCD_HSYNC		JZ_GPIO_PORTC(19)
-#define JZ_GPIO_LCD_VSYNC		JZ_GPIO_PORTC(20)
-#define JZ_GPIO_LCD_DE			JZ_GPIO_PORTC(21)
-#define JZ_GPIO_LCD_PS			JZ_GPIO_PORTC(22)
-#define JZ_GPIO_LCD_REV			JZ_GPIO_PORTC(23)
-#define JZ_GPIO_MEM_WE1			JZ_GPIO_PORTC(24)
-#define JZ_GPIO_MEM_WE2			JZ_GPIO_PORTC(25)
-#define JZ_GPIO_MEM_WE3			JZ_GPIO_PORTC(26)
-#define JZ_GPIO_MEM_WAIT		JZ_GPIO_PORTC(27)
-#define JZ_GPIO_MEM_FRE			JZ_GPIO_PORTC(28)
-#define JZ_GPIO_MEM_FWE			JZ_GPIO_PORTC(29)
-
-#define JZ_GPIO_FUNC_LCD_DATA0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA4		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA5		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA6		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA7		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA8		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA9		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA10		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA11		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA12		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA13		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA14		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA15		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA16		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA17		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_PCLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_VSYNC		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_HSYNC		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DE		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_PS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_REV		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WE1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WE2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WE3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WAIT		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_FRE		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_FWE		JZ_GPIO_FUNC1
-
-
-#define JZ_GPIO_MEM_ADDR19		JZ_GPIO_PORTB(22)
-#define JZ_GPIO_MEM_ADDR20		JZ_GPIO_PORTB(23)
-
-#define JZ_GPIO_FUNC_MEM_ADDR19		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_ADDR20		JZ_GPIO_FUNC2
-
-/* Port D function pins */
-#define JZ_GPIO_CIM_DATA0		JZ_GPIO_PORTD(0)
-#define JZ_GPIO_CIM_DATA1		JZ_GPIO_PORTD(1)
-#define JZ_GPIO_CIM_DATA2		JZ_GPIO_PORTD(2)
-#define JZ_GPIO_CIM_DATA3		JZ_GPIO_PORTD(3)
-#define JZ_GPIO_CIM_DATA4		JZ_GPIO_PORTD(4)
-#define JZ_GPIO_CIM_DATA5		JZ_GPIO_PORTD(5)
-#define JZ_GPIO_CIM_DATA6		JZ_GPIO_PORTD(6)
-#define JZ_GPIO_CIM_DATA7		JZ_GPIO_PORTD(7)
-#define JZ_GPIO_MSC_CMD			JZ_GPIO_PORTD(8)
-#define JZ_GPIO_MSC_CLK			JZ_GPIO_PORTD(9)
-#define JZ_GPIO_MSC_DATA0		JZ_GPIO_PORTD(10)
-#define JZ_GPIO_MSC_DATA1		JZ_GPIO_PORTD(11)
-#define JZ_GPIO_MSC_DATA2		JZ_GPIO_PORTD(12)
-#define JZ_GPIO_MSC_DATA3		JZ_GPIO_PORTD(13)
-#define JZ_GPIO_CIM_MCLK		JZ_GPIO_PORTD(14)
-#define JZ_GPIO_CIM_PCLK		JZ_GPIO_PORTD(15)
-#define JZ_GPIO_CIM_VSYNC		JZ_GPIO_PORTD(16)
-#define JZ_GPIO_CIM_HSYNC		JZ_GPIO_PORTD(17)
-#define JZ_GPIO_SPI_CLK			JZ_GPIO_PORTD(18)
-#define JZ_GPIO_SPI_CE0			JZ_GPIO_PORTD(19)
-#define JZ_GPIO_SPI_DT			JZ_GPIO_PORTD(20)
-#define JZ_GPIO_SPI_DR			JZ_GPIO_PORTD(21)
-#define JZ_GPIO_SPI_CE1			JZ_GPIO_PORTD(22)
-#define JZ_GPIO_PWM0			JZ_GPIO_PORTD(23)
-#define JZ_GPIO_PWM1			JZ_GPIO_PORTD(24)
-#define JZ_GPIO_PWM2			JZ_GPIO_PORTD(25)
-#define JZ_GPIO_PWM3			JZ_GPIO_PORTD(26)
-#define JZ_GPIO_PWM4			JZ_GPIO_PORTD(27)
-#define JZ_GPIO_PWM5			JZ_GPIO_PORTD(28)
-#define JZ_GPIO_PWM6			JZ_GPIO_PORTD(30)
-#define JZ_GPIO_PWM7			JZ_GPIO_PORTD(31)
-
-#define JZ_GPIO_FUNC_CIM_DATA		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_CIM_DATA0		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA1		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA2		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA3		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA4		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA5		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA6		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA7		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_MSC_CMD		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MSC_CLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MSC_DATA		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MSC_DATA0		JZ_GPIO_FUNC_MSC_DATA
-#define JZ_GPIO_FUNC_MSC_DATA1		JZ_GPIO_FUNC_MSC_DATA
-#define JZ_GPIO_FUNC_MSC_DATA2		JZ_GPIO_FUNC_MSC_DATA
-#define JZ_GPIO_FUNC_MSC_DATA3		JZ_GPIO_FUNC_MSC_DATA
-#define JZ_GPIO_FUNC_CIM_MCLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_CIM_PCLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_CIM_VSYNC		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_CIM_HSYNC		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_CLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_CE0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_DT		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_DR		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_CE1		JZ_GPIO_FUNC1
-
-#define JZ_GPIO_FUNC_PWM		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_PWM0		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM1		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM2		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM3		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM4		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM5		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM6		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM7		JZ_GPIO_FUNC_PWM
-
-#define JZ_GPIO_MEM_SCLK_RSTN		JZ_GPIO_PORTD(18)
-#define JZ_GPIO_MEM_BCLK		JZ_GPIO_PORTD(19)
-#define JZ_GPIO_MEM_SDATO		JZ_GPIO_PORTD(20)
-#define JZ_GPIO_MEM_SDATI		JZ_GPIO_PORTD(21)
-#define JZ_GPIO_MEM_SYNC		JZ_GPIO_PORTD(22)
-#define JZ_GPIO_I2C_SDA			JZ_GPIO_PORTD(23)
-#define JZ_GPIO_I2C_SCK			JZ_GPIO_PORTD(24)
-#define JZ_GPIO_UART0_TXD		JZ_GPIO_PORTD(25)
-#define JZ_GPIO_UART0_RXD		JZ_GPIO_PORTD(26)
-#define JZ_GPIO_MEM_ADDR17		JZ_GPIO_PORTD(27)
-#define JZ_GPIO_MEM_ADDR18		JZ_GPIO_PORTD(28)
-#define JZ_GPIO_UART0_CTS		JZ_GPIO_PORTD(30)
-#define JZ_GPIO_UART0_RTS		JZ_GPIO_PORTD(31)
-
-#define JZ_GPIO_FUNC_MEM_SCLK_RSTN	JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_BCLK		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_SDATO		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_SDATI		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_SYNC		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_I2C_SDA		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_I2C_SCK		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_UART0_TXD		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_UART0_RXD		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_ADDR17		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_ADDR18		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_UART0_CTS		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_UART0_RTS		JZ_GPIO_FUNC2
-
-#define JZ_GPIO_UART1_RXD		JZ_GPIO_PORTD(30)
-#define JZ_GPIO_UART1_TXD		JZ_GPIO_PORTD(31)
-
-#define JZ_GPIO_FUNC_UART1_RXD		JZ_GPIO_FUNC3
-#define JZ_GPIO_FUNC_UART1_TXD		JZ_GPIO_FUNC3
-
 #endif
diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
index 39d70bde8cfe..6b9c1f7c31c9 100644
--- a/arch/mips/jz4740/Makefile
+++ b/arch/mips/jz4740/Makefile
@@ -7,8 +7,6 @@
 obj-y += prom.o time.o reset.o setup.o \
 	platform.o timer.o
 
-obj-$(CONFIG_MACH_JZ4740) += gpio.o
-
 CFLAGS_setup.o = -I$(src)/../../../scripts/dtc/libfdt
 
 # board specific support
diff --git a/arch/mips/jz4740/gpio.c b/arch/mips/jz4740/gpio.c
deleted file mode 100644
index b765773ab8aa..000000000000
--- a/arch/mips/jz4740/gpio.c
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- *  Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
- *  JZ4740 platform GPIO support
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <linux/io.h>
-#include <linux/gpio/driver.h>
-/* FIXME: needed for gpio_request(), try to remove consumer API from driver */
-#include <linux/gpio.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/irqchip/ingenic.h>
-#include <linux/bitops.h>
-
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-
-#include <asm/mach-jz4740/base.h>
-#include <asm/mach-jz4740/gpio.h>
-
-#define JZ4740_GPIO_BASE_A (32*0)
-#define JZ4740_GPIO_BASE_B (32*1)
-#define JZ4740_GPIO_BASE_C (32*2)
-#define JZ4740_GPIO_BASE_D (32*3)
-
-#define JZ4740_GPIO_NUM_A 32
-#define JZ4740_GPIO_NUM_B 32
-#define JZ4740_GPIO_NUM_C 31
-#define JZ4740_GPIO_NUM_D 32
-
-#define JZ4740_IRQ_GPIO_BASE_A (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_A)
-#define JZ4740_IRQ_GPIO_BASE_B (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_B)
-#define JZ4740_IRQ_GPIO_BASE_C (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_C)
-#define JZ4740_IRQ_GPIO_BASE_D (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_D)
-
-#define JZ_REG_GPIO_PIN			0x00
-#define JZ_REG_GPIO_DATA		0x10
-#define JZ_REG_GPIO_DATA_SET		0x14
-#define JZ_REG_GPIO_DATA_CLEAR		0x18
-#define JZ_REG_GPIO_MASK		0x20
-#define JZ_REG_GPIO_MASK_SET		0x24
-#define JZ_REG_GPIO_MASK_CLEAR		0x28
-#define JZ_REG_GPIO_PULL		0x30
-#define JZ_REG_GPIO_PULL_SET		0x34
-#define JZ_REG_GPIO_PULL_CLEAR		0x38
-#define JZ_REG_GPIO_FUNC		0x40
-#define JZ_REG_GPIO_FUNC_SET		0x44
-#define JZ_REG_GPIO_FUNC_CLEAR		0x48
-#define JZ_REG_GPIO_SELECT		0x50
-#define JZ_REG_GPIO_SELECT_SET		0x54
-#define JZ_REG_GPIO_SELECT_CLEAR	0x58
-#define JZ_REG_GPIO_DIRECTION		0x60
-#define JZ_REG_GPIO_DIRECTION_SET	0x64
-#define JZ_REG_GPIO_DIRECTION_CLEAR	0x68
-#define JZ_REG_GPIO_TRIGGER		0x70
-#define JZ_REG_GPIO_TRIGGER_SET		0x74
-#define JZ_REG_GPIO_TRIGGER_CLEAR	0x78
-#define JZ_REG_GPIO_FLAG		0x80
-#define JZ_REG_GPIO_FLAG_CLEAR		0x14
-
-#define GPIO_TO_BIT(gpio) BIT(gpio & 0x1f)
-#define GPIO_TO_REG(gpio, reg) (gpio_to_jz_gpio_chip(gpio)->base + (reg))
-#define CHIP_TO_REG(chip, reg) (gpio_chip_to_jz_gpio_chip(chip)->base + (reg))
-
-struct jz_gpio_chip {
-	unsigned int irq;
-	unsigned int irq_base;
-	uint32_t edge_trigger_both;
-
-	void __iomem *base;
-
-	struct gpio_chip gpio_chip;
-};
-
-static struct jz_gpio_chip jz4740_gpio_chips[];
-
-static inline struct jz_gpio_chip *gpio_to_jz_gpio_chip(unsigned int gpio)
-{
-	return &jz4740_gpio_chips[gpio >> 5];
-}
-
-static inline struct jz_gpio_chip *gpio_chip_to_jz_gpio_chip(struct gpio_chip *gc)
-{
-	return gpiochip_get_data(gc);
-}
-
-static inline struct jz_gpio_chip *irq_to_jz_gpio_chip(struct irq_data *data)
-{
-	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
-	return gc->private;
-}
-
-static inline void jz_gpio_write_bit(unsigned int gpio, unsigned int reg)
-{
-	writel(GPIO_TO_BIT(gpio), GPIO_TO_REG(gpio, reg));
-}
-
-int jz_gpio_set_function(int gpio, enum jz_gpio_function function)
-{
-	if (function == JZ_GPIO_FUNC_NONE) {
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_FUNC_CLEAR);
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_CLEAR);
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_CLEAR);
-	} else {
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_FUNC_SET);
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_CLEAR);
-		switch (function) {
-		case JZ_GPIO_FUNC1:
-			jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_CLEAR);
-			break;
-		case JZ_GPIO_FUNC3:
-			jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_SET);
-		case JZ_GPIO_FUNC2: /* Falltrough */
-			jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_SET);
-			break;
-		default:
-			BUG();
-			break;
-		}
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(jz_gpio_set_function);
-
-int jz_gpio_bulk_request(const struct jz_gpio_bulk_request *request, size_t num)
-{
-	size_t i;
-	int ret;
-
-	for (i = 0; i < num; ++i, ++request) {
-		ret = gpio_request(request->gpio, request->name);
-		if (ret)
-			goto err;
-		jz_gpio_set_function(request->gpio, request->function);
-	}
-
-	return 0;
-
-err:
-	for (--request; i > 0; --i, --request) {
-		gpio_free(request->gpio);
-		jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
-	}
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(jz_gpio_bulk_request);
-
-void jz_gpio_bulk_free(const struct jz_gpio_bulk_request *request, size_t num)
-{
-	size_t i;
-
-	for (i = 0; i < num; ++i, ++request) {
-		gpio_free(request->gpio);
-		jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
-	}
-
-}
-EXPORT_SYMBOL_GPL(jz_gpio_bulk_free);
-
-void jz_gpio_bulk_suspend(const struct jz_gpio_bulk_request *request, size_t num)
-{
-	size_t i;
-
-	for (i = 0; i < num; ++i, ++request) {
-		jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
-		jz_gpio_write_bit(request->gpio, JZ_REG_GPIO_DIRECTION_CLEAR);
-		jz_gpio_write_bit(request->gpio, JZ_REG_GPIO_PULL_SET);
-	}
-}
-EXPORT_SYMBOL_GPL(jz_gpio_bulk_suspend);
-
-void jz_gpio_bulk_resume(const struct jz_gpio_bulk_request *request, size_t num)
-{
-	size_t i;
-
-	for (i = 0; i < num; ++i, ++request)
-		jz_gpio_set_function(request->gpio, request->function);
-}
-EXPORT_SYMBOL_GPL(jz_gpio_bulk_resume);
-
-void jz_gpio_enable_pullup(unsigned gpio)
-{
-	jz_gpio_write_bit(gpio, JZ_REG_GPIO_PULL_CLEAR);
-}
-EXPORT_SYMBOL_GPL(jz_gpio_enable_pullup);
-
-void jz_gpio_disable_pullup(unsigned gpio)
-{
-	jz_gpio_write_bit(gpio, JZ_REG_GPIO_PULL_SET);
-}
-EXPORT_SYMBOL_GPL(jz_gpio_disable_pullup);
-
-static int jz_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
-{
-	return !!(readl(CHIP_TO_REG(chip, JZ_REG_GPIO_PIN)) & BIT(gpio));
-}
-
-static void jz_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
-{
-	uint32_t __iomem *reg = CHIP_TO_REG(chip, JZ_REG_GPIO_DATA_SET);
-	reg += !value;
-	writel(BIT(gpio), reg);
-}
-
-static int jz_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
-	int value)
-{
-	writel(BIT(gpio), CHIP_TO_REG(chip, JZ_REG_GPIO_DIRECTION_SET));
-	jz_gpio_set_value(chip, gpio, value);
-
-	return 0;
-}
-
-static int jz_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
-{
-	writel(BIT(gpio), CHIP_TO_REG(chip, JZ_REG_GPIO_DIRECTION_CLEAR));
-
-	return 0;
-}
-
-static int jz_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
-{
-	struct jz_gpio_chip *jz_gpio = gpiochip_get_data(chip);
-
-	return jz_gpio->irq_base + gpio;
-}
-
-int jz_gpio_port_direction_input(int port, uint32_t mask)
-{
-	writel(mask, GPIO_TO_REG(port, JZ_REG_GPIO_DIRECTION_CLEAR));
-
-	return 0;
-}
-EXPORT_SYMBOL(jz_gpio_port_direction_input);
-
-int jz_gpio_port_direction_output(int port, uint32_t mask)
-{
-	writel(mask, GPIO_TO_REG(port, JZ_REG_GPIO_DIRECTION_SET));
-
-	return 0;
-}
-EXPORT_SYMBOL(jz_gpio_port_direction_output);
-
-void jz_gpio_port_set_value(int port, uint32_t value, uint32_t mask)
-{
-	writel(~value & mask, GPIO_TO_REG(port, JZ_REG_GPIO_DATA_CLEAR));
-	writel(value & mask, GPIO_TO_REG(port, JZ_REG_GPIO_DATA_SET));
-}
-EXPORT_SYMBOL(jz_gpio_port_set_value);
-
-uint32_t jz_gpio_port_get_value(int port, uint32_t mask)
-{
-	uint32_t value = readl(GPIO_TO_REG(port, JZ_REG_GPIO_PIN));
-
-	return value & mask;
-}
-EXPORT_SYMBOL(jz_gpio_port_get_value);
-
-#define IRQ_TO_BIT(irq) BIT((irq - JZ4740_IRQ_GPIO(0)) & 0x1f)
-
-static void jz_gpio_check_trigger_both(struct jz_gpio_chip *chip, unsigned int irq)
-{
-	uint32_t value;
-	void __iomem *reg;
-	uint32_t mask = IRQ_TO_BIT(irq);
-
-	if (!(chip->edge_trigger_both & mask))
-		return;
-
-	reg = chip->base;
-
-	value = readl(chip->base + JZ_REG_GPIO_PIN);
-	if (value & mask)
-		reg += JZ_REG_GPIO_DIRECTION_CLEAR;
-	else
-		reg += JZ_REG_GPIO_DIRECTION_SET;
-
-	writel(mask, reg);
-}
-
-static void jz_gpio_irq_demux_handler(struct irq_desc *desc)
-{
-	uint32_t flag;
-	unsigned int gpio_irq;
-	struct jz_gpio_chip *chip = irq_desc_get_handler_data(desc);
-
-	flag = readl(chip->base + JZ_REG_GPIO_FLAG);
-	if (!flag)
-		return;
-
-	gpio_irq = chip->irq_base + __fls(flag);
-
-	jz_gpio_check_trigger_both(chip, gpio_irq);
-
-	generic_handle_irq(gpio_irq);
-};
-
-static inline void jz_gpio_set_irq_bit(struct irq_data *data, unsigned int reg)
-{
-	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
-	writel(IRQ_TO_BIT(data->irq), chip->base + reg);
-}
-
-static void jz_gpio_irq_unmask(struct irq_data *data)
-{
-	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
-
-	jz_gpio_check_trigger_both(chip, data->irq);
-	irq_gc_unmask_enable_reg(data);
-};
-
-/* TODO: Check if function is gpio */
-static unsigned int jz_gpio_irq_startup(struct irq_data *data)
-{
-	jz_gpio_set_irq_bit(data, JZ_REG_GPIO_SELECT_SET);
-	jz_gpio_irq_unmask(data);
-	return 0;
-}
-
-static void jz_gpio_irq_shutdown(struct irq_data *data)
-{
-	irq_gc_mask_disable_reg(data);
-
-	/* Set direction to input */
-	jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR);
-	jz_gpio_set_irq_bit(data, JZ_REG_GPIO_SELECT_CLEAR);
-}
-
-static int jz_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type)
-{
-	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
-	unsigned int irq = data->irq;
-
-	if (flow_type == IRQ_TYPE_EDGE_BOTH) {
-		uint32_t value = readl(chip->base + JZ_REG_GPIO_PIN);
-		if (value & IRQ_TO_BIT(irq))
-			flow_type = IRQ_TYPE_EDGE_FALLING;
-		else
-			flow_type = IRQ_TYPE_EDGE_RISING;
-		chip->edge_trigger_both |= IRQ_TO_BIT(irq);
-	} else {
-		chip->edge_trigger_both &= ~IRQ_TO_BIT(irq);
-	}
-
-	switch (flow_type) {
-	case IRQ_TYPE_EDGE_RISING:
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_SET);
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_SET);
-		break;
-	case IRQ_TYPE_EDGE_FALLING:
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR);
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_SET);
-		break;
-	case IRQ_TYPE_LEVEL_HIGH:
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_SET);
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_CLEAR);
-		break;
-	case IRQ_TYPE_LEVEL_LOW:
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR);
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_CLEAR);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int jz_gpio_irq_set_wake(struct irq_data *data, unsigned int on)
-{
-	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
-
-	irq_gc_set_wake(data, on);
-	irq_set_irq_wake(chip->irq, on);
-
-	return 0;
-}
-
-#define JZ4740_GPIO_CHIP(_bank) { \
-	.irq_base = JZ4740_IRQ_GPIO_BASE_ ## _bank, \
-	.gpio_chip = { \
-		.label = "Bank " # _bank, \
-		.owner = THIS_MODULE, \
-		.set = jz_gpio_set_value, \
-		.get = jz_gpio_get_value, \
-		.direction_output = jz_gpio_direction_output, \
-		.direction_input = jz_gpio_direction_input, \
-		.to_irq = jz_gpio_to_irq, \
-		.base = JZ4740_GPIO_BASE_ ## _bank, \
-		.ngpio = JZ4740_GPIO_NUM_ ## _bank, \
-	}, \
-}
-
-static struct jz_gpio_chip jz4740_gpio_chips[] = {
-	JZ4740_GPIO_CHIP(A),
-	JZ4740_GPIO_CHIP(B),
-	JZ4740_GPIO_CHIP(C),
-	JZ4740_GPIO_CHIP(D),
-};
-
-static void jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id)
-{
-	struct irq_chip_generic *gc;
-	struct irq_chip_type *ct;
-
-	chip->base = ioremap(JZ4740_GPIO_BASE_ADDR + (id * 0x100), 0x100);
-
-	chip->irq = JZ4740_IRQ_INTC_GPIO(id);
-	irq_set_chained_handler_and_data(chip->irq,
-					 jz_gpio_irq_demux_handler, chip);
-
-	gc = irq_alloc_generic_chip(chip->gpio_chip.label, 1, chip->irq_base,
-		chip->base, handle_level_irq);
-
-	gc->wake_enabled = IRQ_MSK(chip->gpio_chip.ngpio);
-	gc->private = chip;
-
-	ct = gc->chip_types;
-	ct->regs.enable = JZ_REG_GPIO_MASK_CLEAR;
-	ct->regs.disable = JZ_REG_GPIO_MASK_SET;
-	ct->regs.ack = JZ_REG_GPIO_FLAG_CLEAR;
-
-	ct->chip.name = "GPIO";
-	ct->chip.irq_mask = irq_gc_mask_disable_reg;
-	ct->chip.irq_unmask = jz_gpio_irq_unmask;
-	ct->chip.irq_ack = irq_gc_ack_set_bit;
-	ct->chip.irq_suspend = ingenic_intc_irq_suspend;
-	ct->chip.irq_resume = ingenic_intc_irq_resume;
-	ct->chip.irq_startup = jz_gpio_irq_startup;
-	ct->chip.irq_shutdown = jz_gpio_irq_shutdown;
-	ct->chip.irq_set_type = jz_gpio_irq_set_type;
-	ct->chip.irq_set_wake = jz_gpio_irq_set_wake;
-	ct->chip.flags = IRQCHIP_SET_TYPE_MASKED;
-
-	irq_setup_generic_chip(gc, IRQ_MSK(chip->gpio_chip.ngpio),
-		IRQ_GC_INIT_NESTED_LOCK, 0, IRQ_NOPROBE | IRQ_LEVEL);
-
-	gpiochip_add_data(&chip->gpio_chip, chip);
-}
-
-static int __init jz4740_gpio_init(void)
-{
-	unsigned int i;
-
-	for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i)
-		jz4740_gpio_chip_init(&jz4740_gpio_chips[i], i);
-
-	printk(KERN_INFO "JZ4740 GPIO initialized\n");
-
-	return 0;
-}
-arch_initcall(jz4740_gpio_init);
-
-#ifdef CONFIG_DEBUG_FS
-
-static inline void gpio_seq_reg(struct seq_file *s, struct jz_gpio_chip *chip,
-	const char *name, unsigned int reg)
-{
-	seq_printf(s, "\t%s: %08x\n", name, readl(chip->base + reg));
-}
-
-static int gpio_regs_show(struct seq_file *s, void *unused)
-{
-	struct jz_gpio_chip *chip = jz4740_gpio_chips;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i, ++chip) {
-		seq_printf(s, "==GPIO %d==\n", i);
-		gpio_seq_reg(s, chip, "Pin", JZ_REG_GPIO_PIN);
-		gpio_seq_reg(s, chip, "Data", JZ_REG_GPIO_DATA);
-		gpio_seq_reg(s, chip, "Mask", JZ_REG_GPIO_MASK);
-		gpio_seq_reg(s, chip, "Pull", JZ_REG_GPIO_PULL);
-		gpio_seq_reg(s, chip, "Func", JZ_REG_GPIO_FUNC);
-		gpio_seq_reg(s, chip, "Select", JZ_REG_GPIO_SELECT);
-		gpio_seq_reg(s, chip, "Direction", JZ_REG_GPIO_DIRECTION);
-		gpio_seq_reg(s, chip, "Trigger", JZ_REG_GPIO_TRIGGER);
-		gpio_seq_reg(s, chip, "Flag", JZ_REG_GPIO_FLAG);
-	}
-
-	return 0;
-}
-
-static int gpio_regs_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, gpio_regs_show, NULL);
-}
-
-static const struct file_operations gpio_regs_operations = {
-	.open		= gpio_regs_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static int __init gpio_debugfs_init(void)
-{
-	(void) debugfs_create_file("jz_regs_gpio", S_IFREG | S_IRUGO,
-				NULL, NULL, &gpio_regs_operations);
-	return 0;
-}
-subsys_initcall(gpio_debugfs_init);
-
-#endif
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v3 10/14] mmc: jz4740: Let the pinctrl driver configure the pins
  2017-01-25 18:52       ` [PATCH v3 10/14] mmc: jz4740: Let the pinctrl driver configure the pins Paul Cercueil
@ 2017-01-26  6:11         ` kbuild test robot
  2017-01-26  6:11           ` kbuild test robot
  2017-01-26 10:10           ` Paul Cercueil
  0 siblings, 2 replies; 162+ messages in thread
From: kbuild test robot @ 2017-01-26  6:11 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: kbuild-all, Linus Walleij, Rob Herring, Mark Rutland,
	Ralf Baechle, Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton, linux-gpio, devicetree,
	linux-kernel, linux-mips, linux-mmc, linux-mtd, linux-pwm,
	linux-fbdev, james.hogan, Paul Cercueil

[-- Attachment #1: Type: text/plain, Size: 10470 bytes --]

Hi Paul,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.10-rc5 next-20170125]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Paul-Cercueil/Ingenic-JZ4740-JZ4780-pinctrl-driver/20170126-030028
config: mips-qi_lb60_defconfig (attached as .config)
compiler: mipsel-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=mips 

All errors (new ones prefixed by >>):

   drivers/mmc/host/jz4740_mmc.c: In function 'jz4740_mmc_set_ios':
>> drivers/mmc/host/jz4740_mmc.c:864:7: error: implicit declaration of function 'gpio_is_valid' [-Werror=implicit-function-declaration]
      if (gpio_is_valid(host->pdata->gpio_power))
          ^~~~~~~~~~~~~
>> drivers/mmc/host/jz4740_mmc.c:865:4: error: implicit declaration of function 'gpio_set_value' [-Werror=implicit-function-declaration]
       gpio_set_value(host->pdata->gpio_power,
       ^~~~~~~~~~~~~~
   drivers/mmc/host/jz4740_mmc.c: In function 'jz4740_mmc_request_gpio':
>> drivers/mmc/host/jz4740_mmc.c:916:8: error: implicit declaration of function 'gpio_request' [-Werror=implicit-function-declaration]
     ret = gpio_request(gpio, name);
           ^~~~~~~~~~~~
>> drivers/mmc/host/jz4740_mmc.c:923:3: error: implicit declaration of function 'gpio_direction_output' [-Werror=implicit-function-declaration]
      gpio_direction_output(gpio, value);
      ^~~~~~~~~~~~~~~~~~~~~
>> drivers/mmc/host/jz4740_mmc.c:925:3: error: implicit declaration of function 'gpio_direction_input' [-Werror=implicit-function-declaration]
      gpio_direction_input(gpio);
      ^~~~~~~~~~~~~~~~~~~~
   drivers/mmc/host/jz4740_mmc.c: In function 'jz4740_mmc_free_gpios':
>> drivers/mmc/host/jz4740_mmc.c:968:3: error: implicit declaration of function 'gpio_free' [-Werror=implicit-function-declaration]
      gpio_free(pdata->gpio_power);
      ^~~~~~~~~
   cc1: some warnings being treated as errors

vim +/gpio_is_valid +864 drivers/mmc/host/jz4740_mmc.c

61bfbdb8 Lars-Peter Clausen 2010-07-15  858  	if (ios->clock)
61bfbdb8 Lars-Peter Clausen 2010-07-15  859  		jz4740_mmc_set_clock_rate(host, ios->clock);
61bfbdb8 Lars-Peter Clausen 2010-07-15  860  
61bfbdb8 Lars-Peter Clausen 2010-07-15  861  	switch (ios->power_mode) {
61bfbdb8 Lars-Peter Clausen 2010-07-15  862  	case MMC_POWER_UP:
61bfbdb8 Lars-Peter Clausen 2010-07-15  863  		jz4740_mmc_reset(host);
61bfbdb8 Lars-Peter Clausen 2010-07-15 @864  		if (gpio_is_valid(host->pdata->gpio_power))
61bfbdb8 Lars-Peter Clausen 2010-07-15 @865  			gpio_set_value(host->pdata->gpio_power,
61bfbdb8 Lars-Peter Clausen 2010-07-15  866  					!host->pdata->power_active_low);
61bfbdb8 Lars-Peter Clausen 2010-07-15  867  		host->cmdat |= JZ_MMC_CMDAT_INIT;
fca9661c Lars-Peter Clausen 2013-05-12  868  		clk_prepare_enable(host->clk);
61bfbdb8 Lars-Peter Clausen 2010-07-15  869  		break;
61bfbdb8 Lars-Peter Clausen 2010-07-15  870  	case MMC_POWER_ON:
61bfbdb8 Lars-Peter Clausen 2010-07-15  871  		break;
61bfbdb8 Lars-Peter Clausen 2010-07-15  872  	default:
61bfbdb8 Lars-Peter Clausen 2010-07-15  873  		if (gpio_is_valid(host->pdata->gpio_power))
61bfbdb8 Lars-Peter Clausen 2010-07-15  874  			gpio_set_value(host->pdata->gpio_power,
61bfbdb8 Lars-Peter Clausen 2010-07-15  875  					host->pdata->power_active_low);
fca9661c Lars-Peter Clausen 2013-05-12  876  		clk_disable_unprepare(host->clk);
61bfbdb8 Lars-Peter Clausen 2010-07-15  877  		break;
61bfbdb8 Lars-Peter Clausen 2010-07-15  878  	}
61bfbdb8 Lars-Peter Clausen 2010-07-15  879  
61bfbdb8 Lars-Peter Clausen 2010-07-15  880  	switch (ios->bus_width) {
61bfbdb8 Lars-Peter Clausen 2010-07-15  881  	case MMC_BUS_WIDTH_1:
61bfbdb8 Lars-Peter Clausen 2010-07-15  882  		host->cmdat &= ~JZ_MMC_CMDAT_BUS_WIDTH_4BIT;
61bfbdb8 Lars-Peter Clausen 2010-07-15  883  		break;
61bfbdb8 Lars-Peter Clausen 2010-07-15  884  	case MMC_BUS_WIDTH_4:
61bfbdb8 Lars-Peter Clausen 2010-07-15  885  		host->cmdat |= JZ_MMC_CMDAT_BUS_WIDTH_4BIT;
61bfbdb8 Lars-Peter Clausen 2010-07-15  886  		break;
61bfbdb8 Lars-Peter Clausen 2010-07-15  887  	default:
61bfbdb8 Lars-Peter Clausen 2010-07-15  888  		break;
61bfbdb8 Lars-Peter Clausen 2010-07-15  889  	}
61bfbdb8 Lars-Peter Clausen 2010-07-15  890  }
61bfbdb8 Lars-Peter Clausen 2010-07-15  891  
61bfbdb8 Lars-Peter Clausen 2010-07-15  892  static void jz4740_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
61bfbdb8 Lars-Peter Clausen 2010-07-15  893  {
61bfbdb8 Lars-Peter Clausen 2010-07-15  894  	struct jz4740_mmc_host *host = mmc_priv(mmc);
61bfbdb8 Lars-Peter Clausen 2010-07-15  895  	jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_SDIO, enable);
61bfbdb8 Lars-Peter Clausen 2010-07-15  896  }
61bfbdb8 Lars-Peter Clausen 2010-07-15  897  
61bfbdb8 Lars-Peter Clausen 2010-07-15  898  static const struct mmc_host_ops jz4740_mmc_ops = {
61bfbdb8 Lars-Peter Clausen 2010-07-15  899  	.request	= jz4740_mmc_request,
bb2f4592 Apelete Seketeli   2014-07-21  900  	.pre_req	= jz4740_mmc_pre_request,
bb2f4592 Apelete Seketeli   2014-07-21  901  	.post_req	= jz4740_mmc_post_request,
61bfbdb8 Lars-Peter Clausen 2010-07-15  902  	.set_ios	= jz4740_mmc_set_ios,
58e300af Lars-Peter Clausen 2013-06-09  903  	.get_ro		= mmc_gpio_get_ro,
58e300af Lars-Peter Clausen 2013-06-09  904  	.get_cd		= mmc_gpio_get_cd,
61bfbdb8 Lars-Peter Clausen 2010-07-15  905  	.enable_sdio_irq = jz4740_mmc_enable_sdio_irq,
61bfbdb8 Lars-Peter Clausen 2010-07-15  906  };
61bfbdb8 Lars-Peter Clausen 2010-07-15  907  
c3be1efd Bill Pemberton     2012-11-19  908  static int jz4740_mmc_request_gpio(struct device *dev, int gpio,
61bfbdb8 Lars-Peter Clausen 2010-07-15  909  	const char *name, bool output, int value)
61bfbdb8 Lars-Peter Clausen 2010-07-15  910  {
61bfbdb8 Lars-Peter Clausen 2010-07-15  911  	int ret;
61bfbdb8 Lars-Peter Clausen 2010-07-15  912  
61bfbdb8 Lars-Peter Clausen 2010-07-15  913  	if (!gpio_is_valid(gpio))
61bfbdb8 Lars-Peter Clausen 2010-07-15  914  		return 0;
61bfbdb8 Lars-Peter Clausen 2010-07-15  915  
61bfbdb8 Lars-Peter Clausen 2010-07-15 @916  	ret = gpio_request(gpio, name);
61bfbdb8 Lars-Peter Clausen 2010-07-15  917  	if (ret) {
61bfbdb8 Lars-Peter Clausen 2010-07-15  918  		dev_err(dev, "Failed to request %s gpio: %d\n", name, ret);
61bfbdb8 Lars-Peter Clausen 2010-07-15  919  		return ret;
61bfbdb8 Lars-Peter Clausen 2010-07-15  920  	}
61bfbdb8 Lars-Peter Clausen 2010-07-15  921  
61bfbdb8 Lars-Peter Clausen 2010-07-15  922  	if (output)
61bfbdb8 Lars-Peter Clausen 2010-07-15 @923  		gpio_direction_output(gpio, value);
61bfbdb8 Lars-Peter Clausen 2010-07-15  924  	else
61bfbdb8 Lars-Peter Clausen 2010-07-15 @925  		gpio_direction_input(gpio);
61bfbdb8 Lars-Peter Clausen 2010-07-15  926  
61bfbdb8 Lars-Peter Clausen 2010-07-15  927  	return 0;
61bfbdb8 Lars-Peter Clausen 2010-07-15  928  }
61bfbdb8 Lars-Peter Clausen 2010-07-15  929  
58e300af Lars-Peter Clausen 2013-06-09  930  static int jz4740_mmc_request_gpios(struct mmc_host *mmc,
58e300af Lars-Peter Clausen 2013-06-09  931  	struct platform_device *pdev)
61bfbdb8 Lars-Peter Clausen 2010-07-15  932  {
61bfbdb8 Lars-Peter Clausen 2010-07-15  933  	struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data;
58e300af Lars-Peter Clausen 2013-06-09  934  	int ret = 0;
61bfbdb8 Lars-Peter Clausen 2010-07-15  935  
61bfbdb8 Lars-Peter Clausen 2010-07-15  936  	if (!pdata)
61bfbdb8 Lars-Peter Clausen 2010-07-15  937  		return 0;
61bfbdb8 Lars-Peter Clausen 2010-07-15  938  
58e300af Lars-Peter Clausen 2013-06-09  939  	if (!pdata->card_detect_active_low)
58e300af Lars-Peter Clausen 2013-06-09  940  		mmc->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
58e300af Lars-Peter Clausen 2013-06-09  941  	if (!pdata->read_only_active_low)
58e300af Lars-Peter Clausen 2013-06-09  942  		mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
61bfbdb8 Lars-Peter Clausen 2010-07-15  943  
58e300af Lars-Peter Clausen 2013-06-09  944  	if (gpio_is_valid(pdata->gpio_card_detect)) {
214fc309 Laurent Pinchart   2013-08-08  945  		ret = mmc_gpio_request_cd(mmc, pdata->gpio_card_detect, 0);
61bfbdb8 Lars-Peter Clausen 2010-07-15  946  		if (ret)
61bfbdb8 Lars-Peter Clausen 2010-07-15  947  			return ret;
61bfbdb8 Lars-Peter Clausen 2010-07-15  948  	}
61bfbdb8 Lars-Peter Clausen 2010-07-15  949  
58e300af Lars-Peter Clausen 2013-06-09  950  	if (gpio_is_valid(pdata->gpio_read_only)) {
58e300af Lars-Peter Clausen 2013-06-09  951  		ret = mmc_gpio_request_ro(mmc, pdata->gpio_read_only);
58e300af Lars-Peter Clausen 2013-06-09  952  		if (ret)
58e300af Lars-Peter Clausen 2013-06-09  953  			return ret;
61bfbdb8 Lars-Peter Clausen 2010-07-15  954  	}
61bfbdb8 Lars-Peter Clausen 2010-07-15  955  
58e300af Lars-Peter Clausen 2013-06-09  956  	return jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_power,
58e300af Lars-Peter Clausen 2013-06-09  957  			"MMC read only", true, pdata->power_active_low);
61bfbdb8 Lars-Peter Clausen 2010-07-15  958  }
61bfbdb8 Lars-Peter Clausen 2010-07-15  959  
61bfbdb8 Lars-Peter Clausen 2010-07-15  960  static void jz4740_mmc_free_gpios(struct platform_device *pdev)
61bfbdb8 Lars-Peter Clausen 2010-07-15  961  {
61bfbdb8 Lars-Peter Clausen 2010-07-15  962  	struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data;
61bfbdb8 Lars-Peter Clausen 2010-07-15  963  
61bfbdb8 Lars-Peter Clausen 2010-07-15  964  	if (!pdata)
61bfbdb8 Lars-Peter Clausen 2010-07-15  965  		return;
61bfbdb8 Lars-Peter Clausen 2010-07-15  966  
61bfbdb8 Lars-Peter Clausen 2010-07-15  967  	if (gpio_is_valid(pdata->gpio_power))
61bfbdb8 Lars-Peter Clausen 2010-07-15 @968  		gpio_free(pdata->gpio_power);
61bfbdb8 Lars-Peter Clausen 2010-07-15  969  }
61bfbdb8 Lars-Peter Clausen 2010-07-15  970  
c3be1efd Bill Pemberton     2012-11-19  971  static int jz4740_mmc_probe(struct platform_device* pdev)

:::::: The code at line 864 was first introduced by commit
:::::: 61bfbdb856879cff583fe53b2ab6ae907faedee7 MMC: Add support for the controller on JZ4740 SoCs.

:::::: TO: Lars-Peter Clausen <lars@metafoo.de>
:::::: CC: Ralf Baechle <ralf@linux-mips.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 14755 bytes --]

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v3 10/14] mmc: jz4740: Let the pinctrl driver configure the pins
  2017-01-26  6:11         ` kbuild test robot
@ 2017-01-26  6:11           ` kbuild test robot
  2017-01-26 10:10           ` Paul Cercueil
  1 sibling, 0 replies; 162+ messages in thread
From: kbuild test robot @ 2017-01-26  6:11 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: kbuild-all, Linus Walleij, Rob Herring, Mark Rutland,
	Ralf Baechle, Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton, linux-gpio, devicetree,
	linux-kernel, linux-mips, linux-mmc, linux-mtd, linux-pwm,
	linux-fbdev, james.hogan

[-- Attachment #1: Type: text/plain, Size: 10470 bytes --]

Hi Paul,

[auto build test ERROR on linus/master]
[also build test ERROR on v4.10-rc5 next-20170125]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Paul-Cercueil/Ingenic-JZ4740-JZ4780-pinctrl-driver/20170126-030028
config: mips-qi_lb60_defconfig (attached as .config)
compiler: mipsel-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=mips 

All errors (new ones prefixed by >>):

   drivers/mmc/host/jz4740_mmc.c: In function 'jz4740_mmc_set_ios':
>> drivers/mmc/host/jz4740_mmc.c:864:7: error: implicit declaration of function 'gpio_is_valid' [-Werror=implicit-function-declaration]
      if (gpio_is_valid(host->pdata->gpio_power))
          ^~~~~~~~~~~~~
>> drivers/mmc/host/jz4740_mmc.c:865:4: error: implicit declaration of function 'gpio_set_value' [-Werror=implicit-function-declaration]
       gpio_set_value(host->pdata->gpio_power,
       ^~~~~~~~~~~~~~
   drivers/mmc/host/jz4740_mmc.c: In function 'jz4740_mmc_request_gpio':
>> drivers/mmc/host/jz4740_mmc.c:916:8: error: implicit declaration of function 'gpio_request' [-Werror=implicit-function-declaration]
     ret = gpio_request(gpio, name);
           ^~~~~~~~~~~~
>> drivers/mmc/host/jz4740_mmc.c:923:3: error: implicit declaration of function 'gpio_direction_output' [-Werror=implicit-function-declaration]
      gpio_direction_output(gpio, value);
      ^~~~~~~~~~~~~~~~~~~~~
>> drivers/mmc/host/jz4740_mmc.c:925:3: error: implicit declaration of function 'gpio_direction_input' [-Werror=implicit-function-declaration]
      gpio_direction_input(gpio);
      ^~~~~~~~~~~~~~~~~~~~
   drivers/mmc/host/jz4740_mmc.c: In function 'jz4740_mmc_free_gpios':
>> drivers/mmc/host/jz4740_mmc.c:968:3: error: implicit declaration of function 'gpio_free' [-Werror=implicit-function-declaration]
      gpio_free(pdata->gpio_power);
      ^~~~~~~~~
   cc1: some warnings being treated as errors

vim +/gpio_is_valid +864 drivers/mmc/host/jz4740_mmc.c

61bfbdb8 Lars-Peter Clausen 2010-07-15  858  	if (ios->clock)
61bfbdb8 Lars-Peter Clausen 2010-07-15  859  		jz4740_mmc_set_clock_rate(host, ios->clock);
61bfbdb8 Lars-Peter Clausen 2010-07-15  860  
61bfbdb8 Lars-Peter Clausen 2010-07-15  861  	switch (ios->power_mode) {
61bfbdb8 Lars-Peter Clausen 2010-07-15  862  	case MMC_POWER_UP:
61bfbdb8 Lars-Peter Clausen 2010-07-15  863  		jz4740_mmc_reset(host);
61bfbdb8 Lars-Peter Clausen 2010-07-15 @864  		if (gpio_is_valid(host->pdata->gpio_power))
61bfbdb8 Lars-Peter Clausen 2010-07-15 @865  			gpio_set_value(host->pdata->gpio_power,
61bfbdb8 Lars-Peter Clausen 2010-07-15  866  					!host->pdata->power_active_low);
61bfbdb8 Lars-Peter Clausen 2010-07-15  867  		host->cmdat |= JZ_MMC_CMDAT_INIT;
fca9661c Lars-Peter Clausen 2013-05-12  868  		clk_prepare_enable(host->clk);
61bfbdb8 Lars-Peter Clausen 2010-07-15  869  		break;
61bfbdb8 Lars-Peter Clausen 2010-07-15  870  	case MMC_POWER_ON:
61bfbdb8 Lars-Peter Clausen 2010-07-15  871  		break;
61bfbdb8 Lars-Peter Clausen 2010-07-15  872  	default:
61bfbdb8 Lars-Peter Clausen 2010-07-15  873  		if (gpio_is_valid(host->pdata->gpio_power))
61bfbdb8 Lars-Peter Clausen 2010-07-15  874  			gpio_set_value(host->pdata->gpio_power,
61bfbdb8 Lars-Peter Clausen 2010-07-15  875  					host->pdata->power_active_low);
fca9661c Lars-Peter Clausen 2013-05-12  876  		clk_disable_unprepare(host->clk);
61bfbdb8 Lars-Peter Clausen 2010-07-15  877  		break;
61bfbdb8 Lars-Peter Clausen 2010-07-15  878  	}
61bfbdb8 Lars-Peter Clausen 2010-07-15  879  
61bfbdb8 Lars-Peter Clausen 2010-07-15  880  	switch (ios->bus_width) {
61bfbdb8 Lars-Peter Clausen 2010-07-15  881  	case MMC_BUS_WIDTH_1:
61bfbdb8 Lars-Peter Clausen 2010-07-15  882  		host->cmdat &= ~JZ_MMC_CMDAT_BUS_WIDTH_4BIT;
61bfbdb8 Lars-Peter Clausen 2010-07-15  883  		break;
61bfbdb8 Lars-Peter Clausen 2010-07-15  884  	case MMC_BUS_WIDTH_4:
61bfbdb8 Lars-Peter Clausen 2010-07-15  885  		host->cmdat |= JZ_MMC_CMDAT_BUS_WIDTH_4BIT;
61bfbdb8 Lars-Peter Clausen 2010-07-15  886  		break;
61bfbdb8 Lars-Peter Clausen 2010-07-15  887  	default:
61bfbdb8 Lars-Peter Clausen 2010-07-15  888  		break;
61bfbdb8 Lars-Peter Clausen 2010-07-15  889  	}
61bfbdb8 Lars-Peter Clausen 2010-07-15  890  }
61bfbdb8 Lars-Peter Clausen 2010-07-15  891  
61bfbdb8 Lars-Peter Clausen 2010-07-15  892  static void jz4740_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
61bfbdb8 Lars-Peter Clausen 2010-07-15  893  {
61bfbdb8 Lars-Peter Clausen 2010-07-15  894  	struct jz4740_mmc_host *host = mmc_priv(mmc);
61bfbdb8 Lars-Peter Clausen 2010-07-15  895  	jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_SDIO, enable);
61bfbdb8 Lars-Peter Clausen 2010-07-15  896  }
61bfbdb8 Lars-Peter Clausen 2010-07-15  897  
61bfbdb8 Lars-Peter Clausen 2010-07-15  898  static const struct mmc_host_ops jz4740_mmc_ops = {
61bfbdb8 Lars-Peter Clausen 2010-07-15  899  	.request	= jz4740_mmc_request,
bb2f4592 Apelete Seketeli   2014-07-21  900  	.pre_req	= jz4740_mmc_pre_request,
bb2f4592 Apelete Seketeli   2014-07-21  901  	.post_req	= jz4740_mmc_post_request,
61bfbdb8 Lars-Peter Clausen 2010-07-15  902  	.set_ios	= jz4740_mmc_set_ios,
58e300af Lars-Peter Clausen 2013-06-09  903  	.get_ro		= mmc_gpio_get_ro,
58e300af Lars-Peter Clausen 2013-06-09  904  	.get_cd		= mmc_gpio_get_cd,
61bfbdb8 Lars-Peter Clausen 2010-07-15  905  	.enable_sdio_irq = jz4740_mmc_enable_sdio_irq,
61bfbdb8 Lars-Peter Clausen 2010-07-15  906  };
61bfbdb8 Lars-Peter Clausen 2010-07-15  907  
c3be1efd Bill Pemberton     2012-11-19  908  static int jz4740_mmc_request_gpio(struct device *dev, int gpio,
61bfbdb8 Lars-Peter Clausen 2010-07-15  909  	const char *name, bool output, int value)
61bfbdb8 Lars-Peter Clausen 2010-07-15  910  {
61bfbdb8 Lars-Peter Clausen 2010-07-15  911  	int ret;
61bfbdb8 Lars-Peter Clausen 2010-07-15  912  
61bfbdb8 Lars-Peter Clausen 2010-07-15  913  	if (!gpio_is_valid(gpio))
61bfbdb8 Lars-Peter Clausen 2010-07-15  914  		return 0;
61bfbdb8 Lars-Peter Clausen 2010-07-15  915  
61bfbdb8 Lars-Peter Clausen 2010-07-15 @916  	ret = gpio_request(gpio, name);
61bfbdb8 Lars-Peter Clausen 2010-07-15  917  	if (ret) {
61bfbdb8 Lars-Peter Clausen 2010-07-15  918  		dev_err(dev, "Failed to request %s gpio: %d\n", name, ret);
61bfbdb8 Lars-Peter Clausen 2010-07-15  919  		return ret;
61bfbdb8 Lars-Peter Clausen 2010-07-15  920  	}
61bfbdb8 Lars-Peter Clausen 2010-07-15  921  
61bfbdb8 Lars-Peter Clausen 2010-07-15  922  	if (output)
61bfbdb8 Lars-Peter Clausen 2010-07-15 @923  		gpio_direction_output(gpio, value);
61bfbdb8 Lars-Peter Clausen 2010-07-15  924  	else
61bfbdb8 Lars-Peter Clausen 2010-07-15 @925  		gpio_direction_input(gpio);
61bfbdb8 Lars-Peter Clausen 2010-07-15  926  
61bfbdb8 Lars-Peter Clausen 2010-07-15  927  	return 0;
61bfbdb8 Lars-Peter Clausen 2010-07-15  928  }
61bfbdb8 Lars-Peter Clausen 2010-07-15  929  
58e300af Lars-Peter Clausen 2013-06-09  930  static int jz4740_mmc_request_gpios(struct mmc_host *mmc,
58e300af Lars-Peter Clausen 2013-06-09  931  	struct platform_device *pdev)
61bfbdb8 Lars-Peter Clausen 2010-07-15  932  {
61bfbdb8 Lars-Peter Clausen 2010-07-15  933  	struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data;
58e300af Lars-Peter Clausen 2013-06-09  934  	int ret = 0;
61bfbdb8 Lars-Peter Clausen 2010-07-15  935  
61bfbdb8 Lars-Peter Clausen 2010-07-15  936  	if (!pdata)
61bfbdb8 Lars-Peter Clausen 2010-07-15  937  		return 0;
61bfbdb8 Lars-Peter Clausen 2010-07-15  938  
58e300af Lars-Peter Clausen 2013-06-09  939  	if (!pdata->card_detect_active_low)
58e300af Lars-Peter Clausen 2013-06-09  940  		mmc->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
58e300af Lars-Peter Clausen 2013-06-09  941  	if (!pdata->read_only_active_low)
58e300af Lars-Peter Clausen 2013-06-09  942  		mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
61bfbdb8 Lars-Peter Clausen 2010-07-15  943  
58e300af Lars-Peter Clausen 2013-06-09  944  	if (gpio_is_valid(pdata->gpio_card_detect)) {
214fc309 Laurent Pinchart   2013-08-08  945  		ret = mmc_gpio_request_cd(mmc, pdata->gpio_card_detect, 0);
61bfbdb8 Lars-Peter Clausen 2010-07-15  946  		if (ret)
61bfbdb8 Lars-Peter Clausen 2010-07-15  947  			return ret;
61bfbdb8 Lars-Peter Clausen 2010-07-15  948  	}
61bfbdb8 Lars-Peter Clausen 2010-07-15  949  
58e300af Lars-Peter Clausen 2013-06-09  950  	if (gpio_is_valid(pdata->gpio_read_only)) {
58e300af Lars-Peter Clausen 2013-06-09  951  		ret = mmc_gpio_request_ro(mmc, pdata->gpio_read_only);
58e300af Lars-Peter Clausen 2013-06-09  952  		if (ret)
58e300af Lars-Peter Clausen 2013-06-09  953  			return ret;
61bfbdb8 Lars-Peter Clausen 2010-07-15  954  	}
61bfbdb8 Lars-Peter Clausen 2010-07-15  955  
58e300af Lars-Peter Clausen 2013-06-09  956  	return jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_power,
58e300af Lars-Peter Clausen 2013-06-09  957  			"MMC read only", true, pdata->power_active_low);
61bfbdb8 Lars-Peter Clausen 2010-07-15  958  }
61bfbdb8 Lars-Peter Clausen 2010-07-15  959  
61bfbdb8 Lars-Peter Clausen 2010-07-15  960  static void jz4740_mmc_free_gpios(struct platform_device *pdev)
61bfbdb8 Lars-Peter Clausen 2010-07-15  961  {
61bfbdb8 Lars-Peter Clausen 2010-07-15  962  	struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data;
61bfbdb8 Lars-Peter Clausen 2010-07-15  963  
61bfbdb8 Lars-Peter Clausen 2010-07-15  964  	if (!pdata)
61bfbdb8 Lars-Peter Clausen 2010-07-15  965  		return;
61bfbdb8 Lars-Peter Clausen 2010-07-15  966  
61bfbdb8 Lars-Peter Clausen 2010-07-15  967  	if (gpio_is_valid(pdata->gpio_power))
61bfbdb8 Lars-Peter Clausen 2010-07-15 @968  		gpio_free(pdata->gpio_power);
61bfbdb8 Lars-Peter Clausen 2010-07-15  969  }
61bfbdb8 Lars-Peter Clausen 2010-07-15  970  
c3be1efd Bill Pemberton     2012-11-19  971  static int jz4740_mmc_probe(struct platform_device* pdev)

:::::: The code at line 864 was first introduced by commit
:::::: 61bfbdb856879cff583fe53b2ab6ae907faedee7 MMC: Add support for the controller on JZ4740 SoCs.

:::::: TO: Lars-Peter Clausen <lars@metafoo.de>
:::::: CC: Ralf Baechle <ralf@linux-mips.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 14755 bytes --]

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v3 10/14] mmc: jz4740: Let the pinctrl driver configure  the pins
  2017-01-26  6:11         ` kbuild test robot
  2017-01-26  6:11           ` kbuild test robot
@ 2017-01-26 10:10           ` Paul Cercueil
  1 sibling, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-26 10:10 UTC (permalink / raw)
  To: kbuild test robot
  Cc: kbuild-all, Linus Walleij, Rob Herring, Mark Rutland,
	Ralf Baechle, Ulf Hansson, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton, linux-gpio, devicetree,
	linux-kernel, linux-mips, linux-mmc, linux-mtd, linux-pwm,
	linux-fbdev, james.hogan

Hi Kbuild Test Robot,

> 
> drivers/mmc/host/jz4740_mmc.c: In function 'jz4740_mmc_set_ios':
> drivers/mmc/host/jz4740_mmc.c:864:7: error: implicit declaration of 
> function 'gpio_is_valid' [-Werror=implicit-function-declaration]

  if (gpio_is_valid(host->pdata->gpio_power))
  ^~~~~~~~~~~~~

Uuh, I'm sorry about that. Looks like I removed one header too much 
(<linux/gpio.h>).
My fault, lately I was testing with ci20_defconfig which doesn't enable 
this driver.

Should I send a v4?

Apologies,
-Paul

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v2 01/14] Documentation: dt/bindings: Document pinctrl-ingenic
  2017-01-22 14:49       ` [PATCH v2 01/14] Documentation: dt/bindings: Document pinctrl-ingenic Paul Cercueil
@ 2017-01-27 11:18         ` Linus Walleij
  2017-01-27 15:27           ` Paul Cercueil
  0 siblings, 1 reply; 162+ messages in thread
From: Linus Walleij @ 2017-01-27 11:18 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

On Sun, Jan 22, 2017 at 3:49 PM, Paul Cercueil <paul@crapouillou.net> wrote:


> +Required properties:
> +- compatible: One of:
> +  - "ingenic,jz4740-pinctrl"
> +  - "ingenic,jz4780-pinctrl"
> +
> +Optional properties:
> +- ingenic,pull-ups: A list of 32-bit bit fields, where each bit set tells the
> +  driver that a pull-up resistor is available for this pin.
> +  By default, the driver considers that all pins feature a pull-up resistor.
> +- ingenic,pull-downs: A list of 32-bit bit fields, where each bit set tells
> +  the driver that a pull-down resistor is available for this pin.
> +  By default, the driver considers that all pins feature a pull-down
> +  resistor.

So I still don't understand these properties.

Does this mean that there is a pull-up *inside* the SoC or *outside*
on the board where it is mounted?

If it is *outside* the SoC, on the board, the pulls should be set on
the consumers, not on the controller.

In the former case, if this pertains to the *inside* of the SoC:
is it just different between jz4740 and jz4780?
In that case, just code this into the driver as .data to the .compatible
in the DT match. No special DT properties needed.

If it is different between e.g. different versions of jz4740, why not
make different compatible-properties? If there are different versions
of the circuit, with different hard-wired hardware configuration, they
are different devices and should have different compatible strings.

> +                               /* CLK, CMD, D0 */
> +                               ingenic,pins = <0x69 0 0x68 0 0x6a 0>;

Standard bindings use just "pins". Why the custom ingenic,
prefix?

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v2 01/14] Documentation: dt/bindings: Document  pinctrl-ingenic
  2017-01-27 11:18         ` Linus Walleij
@ 2017-01-27 15:27           ` Paul Cercueil
  2017-01-31 12:59             ` Linus Walleij
  0 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-01-27 15:27 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

Hi,

> So I still don't understand these properties.
> 
> Does this mean that there is a pull-up *inside* the SoC or *outside*
> on the board where it is mounted?

The pull-up resistors are inside the SoCs.

> In the former case, if this pertains to the *inside* of the SoC:
> is it just different between jz4740 and jz4780?
> In that case, just code this into the driver as .data to the 
> .compatible
> in the DT match. No special DT properties needed.

Well, I've been taught that devicetree is for describing the hardware, 
and
the driver code is for functionality. So that's why I put it in 
devicetree.

That's also the reason why I put the list of functions and groups in
devicetree and not in the driver code.

> Standard bindings use just "pins". Why the custom ingenic,
> prefix?

I can change that.

Regards,
-Paul

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH 10/13] mtd: nand: jz4740: Let the pinctrl driver configure the pins
  2017-01-17 23:14 ` [PATCH 10/13] mtd: nand: " Paul Cercueil
@ 2017-01-27 17:33   ` Boris Brezillon
  0 siblings, 0 replies; 162+ messages in thread
From: Boris Brezillon @ 2017-01-27 17:33 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan

On Wed, 18 Jan 2017 00:14:18 +0100
Paul Cercueil <paul@crapouillou.net> wrote:

> Before, this NAND driver would set itself the configuration of the
> chip-select pins for the various NAND banks.
> 
> Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
> the pins being properly configured before the driver probes.
> 
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>

Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com>

> ---
>  drivers/mtd/nand/jz4740_nand.c | 23 +----------------------
>  1 file changed, 1 insertion(+), 22 deletions(-)
> 
> diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
> index 5551c36adbdf..0d06a1f07d82 100644
> --- a/drivers/mtd/nand/jz4740_nand.c
> +++ b/drivers/mtd/nand/jz4740_nand.c
> @@ -25,7 +25,6 @@
>  
>  #include <linux/gpio.h>
>  
> -#include <asm/mach-jz4740/gpio.h>
>  #include <asm/mach-jz4740/jz4740_nand.h>
>  
>  #define JZ_REG_NAND_CTRL	0x50
> @@ -310,34 +309,20 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
>  			       uint8_t *nand_dev_id)
>  {
>  	int ret;
> -	int gpio;
> -	char gpio_name[9];
>  	char res_name[6];
>  	uint32_t ctrl;
>  	struct nand_chip *chip = &nand->chip;
>  	struct mtd_info *mtd = nand_to_mtd(chip);
>  
> -	/* Request GPIO port. */
> -	gpio = JZ_GPIO_MEM_CS0 + bank - 1;
> -	sprintf(gpio_name, "NAND CS%d", bank);
> -	ret = gpio_request(gpio, gpio_name);
> -	if (ret) {
> -		dev_warn(&pdev->dev,
> -			"Failed to request %s gpio %d: %d\n",
> -			gpio_name, gpio, ret);
> -		goto notfound_gpio;
> -	}
> -
>  	/* Request I/O resource. */
>  	sprintf(res_name, "bank%d", bank);
>  	ret = jz_nand_ioremap_resource(pdev, res_name,
>  					&nand->bank_mem[bank - 1],
>  					&nand->bank_base[bank - 1]);
>  	if (ret)
> -		goto notfound_resource;
> +		return ret;
>  
>  	/* Enable chip in bank. */
> -	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_MEM_CS0);
>  	ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
>  	ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1);
>  	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
> @@ -377,12 +362,8 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
>  	dev_info(&pdev->dev, "No chip found on bank %i\n", bank);
>  	ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1));
>  	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
> -	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE);
>  	jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
>  				 nand->bank_base[bank - 1]);
> -notfound_resource:
> -	gpio_free(gpio);
> -notfound_gpio:
>  	return ret;
>  }
>  
> @@ -503,7 +484,6 @@ static int jz_nand_probe(struct platform_device *pdev)
>  err_unclaim_banks:
>  	while (chipnr--) {
>  		unsigned char bank = nand->banks[chipnr];
> -		gpio_free(JZ_GPIO_MEM_CS0 + bank - 1);
>  		jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
>  					 nand->bank_base[bank - 1]);
>  	}
> @@ -530,7 +510,6 @@ static int jz_nand_remove(struct platform_device *pdev)
>  		if (bank != 0) {
>  			jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
>  						 nand->bank_base[bank - 1]);
> -			gpio_free(JZ_GPIO_MEM_CS0 + bank - 1);
>  		}
>  	}
>  

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v3 12/14] fbdev: jz4740-fb: Let the pinctrl driver configure the pins
  2017-01-25 18:52       ` [PATCH v3 12/14] fbdev: jz4740-fb: " Paul Cercueil
@ 2017-01-30 16:10         ` Bartlomiej Zolnierkiewicz
  0 siblings, 0 replies; 162+ messages in thread
From: Bartlomiej Zolnierkiewicz @ 2017-01-30 16:10 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Linus Walleij, Rob Herring, Mark Rutland, Ralf Baechle,
	Ulf Hansson, Boris Brezillon, Thierry Reding, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton, linux-gpio, devicetree,
	linux-kernel, linux-mips, linux-mmc, linux-mtd, linux-pwm,
	linux-fbdev, james.hogan


Hi,

On Wednesday, January 25, 2017 07:52:05 PM Paul Cercueil wrote:
> Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
> the pins being properly configured before the driver probes.
> 
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>

Acked-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>

Best regards,
--
Bartlomiej Zolnierkiewicz
Samsung R&D Institute Poland
Samsung Electronics

> ---
>  drivers/video/fbdev/jz4740_fb.c | 104 ++--------------------------------------
>  1 file changed, 3 insertions(+), 101 deletions(-)
> 
> v2: No changes
> v3: No changes
> 
> diff --git a/drivers/video/fbdev/jz4740_fb.c b/drivers/video/fbdev/jz4740_fb.c
> index 87790e9644d0..b57df83fdbd3 100644
> --- a/drivers/video/fbdev/jz4740_fb.c
> +++ b/drivers/video/fbdev/jz4740_fb.c
> @@ -17,6 +17,7 @@
>  #include <linux/module.h>
>  #include <linux/mutex.h>
>  #include <linux/platform_device.h>
> +#include <linux/pinctrl/consumer.h>
>  
>  #include <linux/clk.h>
>  #include <linux/delay.h>
> @@ -27,7 +28,6 @@
>  #include <linux/dma-mapping.h>
>  
>  #include <asm/mach-jz4740/jz4740_fb.h>
> -#include <asm/mach-jz4740/gpio.h>
>  
>  #define JZ_REG_LCD_CFG		0x00
>  #define JZ_REG_LCD_VSYNC	0x04
> @@ -146,93 +146,6 @@ static const struct fb_fix_screeninfo jzfb_fix = {
>  	.accel		= FB_ACCEL_NONE,
>  };
>  
> -static const struct jz_gpio_bulk_request jz_lcd_ctrl_pins[] = {
> -	JZ_GPIO_BULK_PIN(LCD_PCLK),
> -	JZ_GPIO_BULK_PIN(LCD_HSYNC),
> -	JZ_GPIO_BULK_PIN(LCD_VSYNC),
> -	JZ_GPIO_BULK_PIN(LCD_DE),
> -	JZ_GPIO_BULK_PIN(LCD_PS),
> -	JZ_GPIO_BULK_PIN(LCD_REV),
> -	JZ_GPIO_BULK_PIN(LCD_CLS),
> -	JZ_GPIO_BULK_PIN(LCD_SPL),
> -};
> -
> -static const struct jz_gpio_bulk_request jz_lcd_data_pins[] = {
> -	JZ_GPIO_BULK_PIN(LCD_DATA0),
> -	JZ_GPIO_BULK_PIN(LCD_DATA1),
> -	JZ_GPIO_BULK_PIN(LCD_DATA2),
> -	JZ_GPIO_BULK_PIN(LCD_DATA3),
> -	JZ_GPIO_BULK_PIN(LCD_DATA4),
> -	JZ_GPIO_BULK_PIN(LCD_DATA5),
> -	JZ_GPIO_BULK_PIN(LCD_DATA6),
> -	JZ_GPIO_BULK_PIN(LCD_DATA7),
> -	JZ_GPIO_BULK_PIN(LCD_DATA8),
> -	JZ_GPIO_BULK_PIN(LCD_DATA9),
> -	JZ_GPIO_BULK_PIN(LCD_DATA10),
> -	JZ_GPIO_BULK_PIN(LCD_DATA11),
> -	JZ_GPIO_BULK_PIN(LCD_DATA12),
> -	JZ_GPIO_BULK_PIN(LCD_DATA13),
> -	JZ_GPIO_BULK_PIN(LCD_DATA14),
> -	JZ_GPIO_BULK_PIN(LCD_DATA15),
> -	JZ_GPIO_BULK_PIN(LCD_DATA16),
> -	JZ_GPIO_BULK_PIN(LCD_DATA17),
> -};
> -
> -static unsigned int jzfb_num_ctrl_pins(struct jzfb *jzfb)
> -{
> -	unsigned int num;
> -
> -	switch (jzfb->pdata->lcd_type) {
> -	case JZ_LCD_TYPE_GENERIC_16_BIT:
> -		num = 4;
> -		break;
> -	case JZ_LCD_TYPE_GENERIC_18_BIT:
> -		num = 4;
> -		break;
> -	case JZ_LCD_TYPE_8BIT_SERIAL:
> -		num = 3;
> -		break;
> -	case JZ_LCD_TYPE_SPECIAL_TFT_1:
> -	case JZ_LCD_TYPE_SPECIAL_TFT_2:
> -	case JZ_LCD_TYPE_SPECIAL_TFT_3:
> -		num = 8;
> -		break;
> -	default:
> -		num = 0;
> -		break;
> -	}
> -	return num;
> -}
> -
> -static unsigned int jzfb_num_data_pins(struct jzfb *jzfb)
> -{
> -	unsigned int num;
> -
> -	switch (jzfb->pdata->lcd_type) {
> -	case JZ_LCD_TYPE_GENERIC_16_BIT:
> -		num = 16;
> -		break;
> -	case JZ_LCD_TYPE_GENERIC_18_BIT:
> -		num = 18;
> -		break;
> -	case JZ_LCD_TYPE_8BIT_SERIAL:
> -		num = 8;
> -		break;
> -	case JZ_LCD_TYPE_SPECIAL_TFT_1:
> -	case JZ_LCD_TYPE_SPECIAL_TFT_2:
> -	case JZ_LCD_TYPE_SPECIAL_TFT_3:
> -		if (jzfb->pdata->bpp == 18)
> -			num = 18;
> -		else
> -			num = 16;
> -		break;
> -	default:
> -		num = 0;
> -		break;
> -	}
> -	return num;
> -}
> -
>  /* Based on CNVT_TOHW macro from skeletonfb.c */
>  static inline uint32_t jzfb_convert_color_to_hw(unsigned val,
>  	struct fb_bitfield *bf)
> @@ -487,8 +400,7 @@ static void jzfb_enable(struct jzfb *jzfb)
>  
>  	clk_prepare_enable(jzfb->ldclk);
>  
> -	jz_gpio_bulk_resume(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
> -	jz_gpio_bulk_resume(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
> +	pinctrl_pm_select_default_state(&jzfb->pdev->dev);
>  
>  	writel(0, jzfb->base + JZ_REG_LCD_STATE);
>  
> @@ -511,8 +423,7 @@ static void jzfb_disable(struct jzfb *jzfb)
>  		ctrl = readl(jzfb->base + JZ_REG_LCD_STATE);
>  	} while (!(ctrl & JZ_LCD_STATE_DISABLED));
>  
> -	jz_gpio_bulk_suspend(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
> -	jz_gpio_bulk_suspend(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
> +	pinctrl_pm_select_sleep_state(&jzfb->pdev->dev);
>  
>  	clk_disable_unprepare(jzfb->ldclk);
>  }
> @@ -701,9 +612,6 @@ static int jzfb_probe(struct platform_device *pdev)
>  	fb->mode = NULL;
>  	jzfb_set_par(fb);
>  
> -	jz_gpio_bulk_request(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
> -	jz_gpio_bulk_request(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
> -
>  	ret = register_framebuffer(fb);
>  	if (ret) {
>  		dev_err(&pdev->dev, "Failed to register framebuffer: %d\n", ret);
> @@ -715,9 +623,6 @@ static int jzfb_probe(struct platform_device *pdev)
>  	return 0;
>  
>  err_free_devmem:
> -	jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
> -	jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
> -
>  	fb_dealloc_cmap(&fb->cmap);
>  	jzfb_free_devmem(jzfb);
>  err_framebuffer_release:
> @@ -731,9 +636,6 @@ static int jzfb_remove(struct platform_device *pdev)
>  
>  	jzfb_blank(FB_BLANK_POWERDOWN, jzfb->fb);
>  
> -	jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
> -	jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
> -
>  	fb_dealloc_cmap(&jzfb->fb->cmap);
>  	jzfb_free_devmem(jzfb);

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v3 02/14] Documentation: dt/bindings: Document pinctrl-gpio
  2017-01-25 18:51       ` [PATCH v3 02/14] Documentation: dt/bindings: Document pinctrl-gpio Paul Cercueil
@ 2017-01-30 20:33         ` Rob Herring
  0 siblings, 0 replies; 162+ messages in thread
From: Rob Herring @ 2017-01-30 20:33 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Linus Walleij, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan

On Wed, Jan 25, 2017 at 07:51:55PM +0100, Paul Cercueil wrote:
> This commit adds documentation for the devicetree bidings of the

s/biding/bindings/

> pinctrl-gpio driver, which handles GPIOs of the Ingenic SoCs
> currently supported by the Linux kernel.

The subject makes no reference that this binding is for Ingenic GPIO. 
Also, drop the "Documentation: " part. It's redundant.

> 
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
> ---
>  .../devicetree/bindings/gpio/ingenic,gpio.txt      | 45 ++++++++++++++++++++++
>  1 file changed, 45 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
> 
> v2: New patch
> v3: No changes
> 
> diff --git a/Documentation/devicetree/bindings/gpio/ingenic,gpio.txt b/Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
> new file mode 100644
> index 000000000000..b2eb20494365
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
> @@ -0,0 +1,45 @@
> +Ingenic jz47xx GPIO controller
> +
> +Required properties:
> +  - compatible:
> +    - "ingenic,jz4740-gpio" for the JZ4740 SoC
> +    - "ingenic,jz4780-gpio" for the JZ4780 SoC
> +
> +  - reg: Base address and length of each memory resource used by the GPIO
> +    controller hardware module.
> +
> +  - gpio-controller: Marks the device node as a GPIO controller.
> +  - #gpio-cells: Should be 2. The first cell is the GPIO number and the second
> +    cell specifies GPIO flags, as defined in <dt-bindings/gpio/gpio.h>. Only the
> +    GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported.
> +  - gpio-ranges: Range of pins managed by the GPIO controller.
> +
> +Optional properties:
> +  - base: The GPIO number to use as the base for this driver.

Drop this please. This is a Linuxism.

> +  - interrupt-controller: Marks the device node as an interrupt controller.
> +  - interrupts: Interrupt specifier for the controllers interrupt.
> +    Required if 'interrupt-controller' is specified.

Some h/w doesn't have interrupt capability? If not, this should not be 
optional.

> +
> +Please refer to gpio.txt in this directory for details of gpio-ranges property
> +and the common GPIO bindings used by client devices.
> +
> +The GPIO controller also acts as an interrupt controller. It uses the default
> +two cells specifier as described in Documentation/devicetree/bindings/
> +interrupt-controller/interrupts.txt.

Just document #interrupt-cells and its value and drop this paragraph.

> +
> +Example:
> +
> +gpa: gpio-controller@10010000 {
> +	compatible = "ingenic,jz4740-gpio";
> +	reg = <0x10010000 0x100>;
> +
> +	gpio-controller;
> +	gpio-ranges = <&pinctrl 0 0 32>;
> +	#gpio-cells = <2>;
> +
> +	interrupt-controller;
> +	#interrupt-cells = <2>;
> +
> +	interrupt-parent = <&intc>;
> +	interrupts = <28>;
> +};
> -- 
> 2.11.0
> 

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v3 01/14] Documentation: dt/bindings: Document pinctrl-ingenic
  2017-01-25 18:51       ` [PATCH v3 01/14] Documentation: dt/bindings: Document pinctrl-ingenic Paul Cercueil
@ 2017-01-30 20:36         ` Rob Herring
  2017-01-30 20:36           ` Rob Herring
  2017-01-31 10:31           ` Paul Cercueil
  2017-04-02 20:42         ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
  1 sibling, 2 replies; 162+ messages in thread
From: Rob Herring @ 2017-01-30 20:36 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Linus Walleij, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan

On Wed, Jan 25, 2017 at 07:51:54PM +0100, Paul Cercueil wrote:
> This commit adds documentation for the devicetree bidings of the
> pinctrl-ingenic driver, which handles pin configuration and pin
> muxing of the Ingenic SoCs currently supported by the Linux kernel.
> 
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
> ---
>  .../bindings/pinctrl/ingenic,pinctrl.txt           | 77 ++++++++++++++++++++++
>  1 file changed, 77 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
> 
> v2: Rewrote the documentation for the new pinctrl-ingenic driver
> v3: No changes
> 
> diff --git a/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
> new file mode 100644
> index 000000000000..ead5b01ad471
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
> @@ -0,0 +1,77 @@
> +Ingenic jz47xx pin controller
> +
> +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".
> +
> +For the jz47xx SoCs, pin control is tightly bound with GPIO ports. All pins may
> +be used as GPIOs, multiplexed device functions are configured within the
> +GPIO port configuration registers and it is typical to refer to pins using the
> +naming scheme "PxN" where x is a character identifying the GPIO port with
> +which the pin is associated and N is an integer from 0 to 31 identifying the
> +pin within that GPIO port. For example PA0 is the first pin in GPIO port A, and
> +PB31 is the last pin in GPIO port B. The jz4740 contains 4 GPIO ports, PA to
> +PD, for a total of 128 pins. The jz4780 contains 6 GPIO ports, PA to PF, for a
> +total of 192 pins.

From the overlapping register addresses in the examples and this 
description, it looks like the pinctrlr and gpio controller are 1 block. 
If so, then there should only be 1 node.

Rob

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v3 01/14] Documentation: dt/bindings: Document pinctrl-ingenic
  2017-01-30 20:36         ` Rob Herring
@ 2017-01-30 20:36           ` Rob Herring
  2017-01-31 10:31           ` Paul Cercueil
  1 sibling, 0 replies; 162+ messages in thread
From: Rob Herring @ 2017-01-30 20:36 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Linus Walleij, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan

On Wed, Jan 25, 2017 at 07:51:54PM +0100, Paul Cercueil wrote:
> This commit adds documentation for the devicetree bidings of the
> pinctrl-ingenic driver, which handles pin configuration and pin
> muxing of the Ingenic SoCs currently supported by the Linux kernel.
> 
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
> ---
>  .../bindings/pinctrl/ingenic,pinctrl.txt           | 77 ++++++++++++++++++++++
>  1 file changed, 77 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
> 
> v2: Rewrote the documentation for the new pinctrl-ingenic driver
> v3: No changes
> 
> diff --git a/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
> new file mode 100644
> index 000000000000..ead5b01ad471
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
> @@ -0,0 +1,77 @@
> +Ingenic jz47xx pin controller
> +
> +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".
> +
> +For the jz47xx SoCs, pin control is tightly bound with GPIO ports. All pins may
> +be used as GPIOs, multiplexed device functions are configured within the
> +GPIO port configuration registers and it is typical to refer to pins using the
> +naming scheme "PxN" where x is a character identifying the GPIO port with
> +which the pin is associated and N is an integer from 0 to 31 identifying the
> +pin within that GPIO port. For example PA0 is the first pin in GPIO port A, and
> +PB31 is the last pin in GPIO port B. The jz4740 contains 4 GPIO ports, PA to
> +PD, for a total of 128 pins. The jz4780 contains 6 GPIO ports, PA to PF, for a
> +total of 192 pins.

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v3 01/14] Documentation: dt/bindings: Document  pinctrl-ingenic
  2017-01-30 20:36         ` Rob Herring
  2017-01-30 20:36           ` Rob Herring
@ 2017-01-31 10:31           ` Paul Cercueil
  2017-01-31 13:09             ` Linus Walleij
  1 sibling, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-01-31 10:31 UTC (permalink / raw)
  To: Rob Herring
  Cc: Linus Walleij, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, james.hogan

Hi,

> From the overlapping register addresses in the examples and this
> description, it looks like the pinctrlr and gpio controller are 1 
> block.
> If so, then there should only be 1 node.

Well, that's what I had until Linus W. just told me to do the opposite:

> Just pull all these down two levels and make them one device
> each instead of having them inside the pin controller node
> like this.

-Paul

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v2 01/14] Documentation: dt/bindings: Document pinctrl-ingenic
  2017-01-27 15:27           ` Paul Cercueil
@ 2017-01-31 12:59             ` Linus Walleij
  0 siblings, 0 replies; 162+ messages in thread
From: Linus Walleij @ 2017-01-31 12:59 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

On Fri, Jan 27, 2017 at 4:27 PM, Paul Cercueil <paul@crapouillou.net> wrote:
> [Me]:
>> In the former case, if this pertains to the *inside* of the SoC:
>> is it just different between jz4740 and jz4780?
>> In that case, just code this into the driver as .data to the .compatible
>> in the DT match. No special DT properties needed.
>
> Well, I've been taught that devicetree is for describing the hardware, and
> the driver code is for functionality. So that's why I put it in devicetree.

This is a gray area.

But as GPIO maintainer I'm not happy about encoding information
about the hardware, that can be deducted from the compatible-string,
into the devicetree.

I prefer to encode per-compatible hardware information tables into
the driver, as structs, and pick the right table based on the compatible
string as .data in the of match entry.

It's simple to retrieve into the driver using of_device_get_match_data()
these days.

> That's also the reason why I put the list of functions and groups in
> devicetree and not in the driver code.

I'm not super-happy about that either, and it's not the way I would
have done it but the argument has been made
that it is a lot of opaque data and people prefer to maintain it
in the device tree.

I accept it for functions and groups, but I don't like it.

I will not fold to any consistency arguments of the type "now
you allowed this one thing, so you must allow this other thing
so you are consistent", just no. I didn't like it the first time, so I'm
not liking it anymore the second time.

I guess if the DT people tell me it has to be done this way I would
accept it. After a lot of discussion. But noone has.

Please make it a table and put it in the driver instead.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v3 01/14] Documentation: dt/bindings: Document pinctrl-ingenic
  2017-01-31 10:31           ` Paul Cercueil
@ 2017-01-31 13:09             ` Linus Walleij
  2017-02-09 17:28               ` Paul Cercueil
  0 siblings, 1 reply; 162+ messages in thread
From: Linus Walleij @ 2017-01-31 13:09 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

On Tue, Jan 31, 2017 at 11:31 AM, Paul Cercueil <paul@crapouillou.net> wrote:
> [Rob]:
>> From the overlapping register addresses in the examples and this
>> description, it looks like the pinctrlr and gpio controller are 1 block.
>> If so, then there should only be 1 node.
>
> Well, that's what I had until Linus W. just told me to do the opposite:
>
>> Just pull all these down two levels and make them one device
>> each instead of having them inside the pin controller node
>> like this.

I guess the argument is that they are in the same coherent memory
range so they should be one device node. That is how we handle
e.g. system controllers so it makes some sense.

So can the two GPIO controllers be modeled as two subnodes of
the pin controller then?

Subnodes are certainly OK, we have that for many other devices
such as interrupt controllers on PCI bridges and what not.

So when the probing of the pin controller is ready it can just
walk down and populate the GPIO subdevices with
of_platform_default_populate() or simply by registering the
device directly with platform_device_add_data() just like an
MFD device does?

This is nice because we want to use the standard gpio ranges
to map pins to GPIO lines.

I'm sorry about the unclarities here, but it's essentially an intrinsic
problem with GPIO that has been with us for years: do we model
each "bank" as a device or do we just register each bank as a
gpiochip, or do we even make one gpiochip to cover all the banks.
All solutions can be found in the kernel... also the different DT bindings:
one node for a whole slew of GPIO controllers, or seveal nodes
and I bet also several nodes for memory ranges in close proximity.

I don't know for sure what is the most elegant solution, we might
need to build some consensus here for the future so it doesn't
get to heterogeneous.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v3 03/14] pinctrl-ingenic: add a pinctrl driver for the Ingenic jz47xx SoCs
  2017-01-25 18:51       ` [PATCH v3 03/14] pinctrl-ingenic: add a pinctrl driver for the Ingenic jz47xx SoCs Paul Cercueil
@ 2017-01-31 14:05         ` Linus Walleij
  2017-01-31 14:12           ` Paul Cercueil
  0 siblings, 1 reply; 162+ messages in thread
From: Linus Walleij @ 2017-01-31 14:05 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

On Wed, Jan 25, 2017 at 7:51 PM, Paul Cercueil <paul@crapouillou.net> wrote:

> This driver handles pin configuration and pin muxing for the
> JZ4740 and JZ4780 SoCs from Ingenic.
>
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>

This is starting to look very nice.

> +#include <linux/compiler.h>
> +#include <linux/gpio.h>

Use <linux/gpio/driver.h> if it is a GPIO driver. I should
be enough ... I think.

> +static int ingenic_pinctrl_parse_dt_func(struct ingenic_pinctrl *jzpc,
> +               struct device_node *np)
> +{
> +       unsigned int num_groups;
> +       struct device_node *group_node;
> +       unsigned int i, j;
> +       int err, npins, *pins, *confs;
> +       const char **groups;
> +
> +       num_groups = of_get_child_count(np);
> +       groups = devm_kzalloc(jzpc->dev,
> +                       sizeof(*groups) * num_groups, GFP_KERNEL);
> +       if (!groups)
> +               return -ENOMEM;
> +
> +       i = 0;
> +       for_each_child_of_node(np, group_node) {
> +               groups[i++] = group_node->name;
> +
> +               npins = of_property_count_elems_of_size(group_node,
> +                               "ingenic,pins", 8);
> +               if (npins < 0)
> +                       return npins;
> +
> +               pins = devm_kzalloc(jzpc->dev,
> +                               sizeof(*pins) * npins, GFP_KERNEL);
> +               confs = devm_kzalloc(jzpc->dev,
> +                               sizeof(*confs) * npins, GFP_KERNEL);
> +               if (!pins || !confs)
> +                       return -ENOMEM;
> +
> +               for (j = 0; j < npins; j++) {
> +                       of_property_read_u32_index(group_node,
> +                                       "ingenic,pins", j * 2, &pins[j]);
> +
> +                       of_property_read_u32_index(group_node,
> +                                       "ingenic,pins", j * 2 + 1, &confs[j]);

If I didn't mention before this could pperhaps just use "pins"?

Or does these DT entries not match the generic bindings?

> +               }
> +
> +               err = pinctrl_generic_add_group(jzpc->pctl, group_node->name,
> +                               pins, npins, confs);
> +               if (err)
> +                       return err;
> +       }
> +
> +       return pinmux_generic_add_function(jzpc->pctl, np->name,
> +                       groups, num_groups, NULL);
> +}

If you just use "pins" can this even be parsed by a generic parser function
pinconf_generic_dt_subnode_to_map()?

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v3 03/14] pinctrl-ingenic: add a pinctrl driver for the  Ingenic jz47xx SoCs
  2017-01-31 14:05         ` Linus Walleij
@ 2017-01-31 14:12           ` Paul Cercueil
  0 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-01-31 14:12 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

Le 2017-01-31 15:05, Linus Walleij a écrit :

> If I didn't mention before this could pperhaps just use "pins"?

You commented this on v2 after I sent the v3 :)
I will fix it for v4.

> If you just use "pins" can this even be parsed by a generic parser 
> function
> pinconf_generic_dt_subnode_to_map()?

I'll take a look. Thanks.

Regards,
-Paul

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v3 04/14] GPIO: Add gpio-ingenic driver
  2017-01-25 18:51       ` [PATCH v3 04/14] GPIO: Add gpio-ingenic driver Paul Cercueil
@ 2017-01-31 14:13         ` Linus Walleij
  2017-02-09 17:14           ` Paul Cercueil
  2017-01-31 14:20         ` Linus Walleij
  1 sibling, 1 reply; 162+ messages in thread
From: Linus Walleij @ 2017-01-31 14:13 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

On Wed, Jan 25, 2017 at 7:51 PM, Paul Cercueil <paul@crapouillou.net> wrote:

> This driver handles the GPIOs of all the Ingenic JZ47xx SoCs
> currently supported by the upsteam Linux kernel.
>
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>

Looking nice.

> +#define JZ4740_GPIO_DATA       0x10
> +#define JZ4740_GPIO_SELECT     0x50
> +#define JZ4740_GPIO_DIR                0x60
> +#define JZ4740_GPIO_TRIG       0x70
> +#define JZ4740_GPIO_FLAG       0x80
> +
> +#define JZ4780_GPIO_INT                0x10
> +#define JZ4780_GPIO_PAT1       0x30
> +#define JZ4780_GPIO_PAT0       0x40
> +#define JZ4780_GPIO_FLAG       0x50
> +
> +#define REG_SET(x) ((x) + 0x4)
> +#define REG_CLEAR(x) ((x) + 0x8)
(...)
> +enum jz_version {
> +       ID_JZ4740,
> +       ID_JZ4780,
> +};
(...)
> +static inline bool gpio_get_value(struct ingenic_gpio_chip *jzgc, u8 offset)
> +{
> +       if (jzgc->version >= ID_JZ4780)
> +               return readl(jzgc->base + GPIO_PIN) & BIT(offset);
> +       else
> +               return readl(jzgc->base + JZ4740_GPIO_DATA) & BIT(offset);
> +}

This works for me, for sure.

What some people do, is to put the right virtual address in to the state
container.

So it would be just:

return !!readl(jzgc->datareg) & BIT(offset));

Notice also the double-bang that clamps the value to a bool. I know
the core does it too but I like to see it in drivers just to be sure.

> +static void gpio_set_value(struct ingenic_gpio_chip *jzgc, u8 offset, int value)
> +{
> +       u8 reg;
> +
> +       if (jzgc->version >= ID_JZ4780)
> +               reg = JZ4780_GPIO_PAT0;
> +       else
> +               reg = JZ4740_GPIO_DATA;
> +
> +       if (value)
> +               writel(BIT(offset), jzgc->base + REG_SET(reg));
> +       else
> +               writel(BIT(offset), jzgc->base + REG_CLEAR(reg));
> +}

Same comment.

What some drivers do when they just get/set a bit in a register
to get/set or set the direction of a GPIO, is to select GPIO_GENERIC
and just bgpio_init() with the right iomem pointers, then the core
will register handlers for get, set, set_direcition callback and
get_direction and your driver can just focus on the remainders.

> +static void ingenic_gpio_set(struct gpio_chip *gc,
> +               unsigned int offset, int value)
> +{
> +       struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
> +
> +       gpio_set_value(jzgc, offset, value);
> +}
> +
> +static int ingenic_gpio_get(struct gpio_chip *gc, unsigned int offset)
> +{
> +       struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
> +
> +       return (int) gpio_get_value(jzgc, offset);
> +}
> +
> +static int ingenic_gpio_direction_input(struct gpio_chip *gc,
> +               unsigned int offset)
> +{
> +       return pinctrl_gpio_direction_input(gc->base + offset);
> +}
> +
> +static int ingenic_gpio_direction_output(struct gpio_chip *gc,
> +               unsigned int offset, int value)
> +{
> +       ingenic_gpio_set(gc, offset, value);
> +       return pinctrl_gpio_direction_output(gc->base + offset);
> +}

If you're not just replacing these with GPIO_GENERIC, please also
include a .get_direction() callback.

It's especially nice as it reads out the state at probe and "lsgpio"
lists if pins are inputs or outputs.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v3 06/14] MIPS: jz4740: DTS: Add nodes for ingenic pinctrl and gpio drivers
  2017-01-25 18:51       ` [PATCH v3 06/14] MIPS: jz4740: DTS: Add nodes for ingenic pinctrl and gpio drivers Paul Cercueil
@ 2017-01-31 14:16         ` Linus Walleij
  0 siblings, 0 replies; 162+ messages in thread
From: Linus Walleij @ 2017-01-31 14:16 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

On Wed, Jan 25, 2017 at 7:51 PM, Paul Cercueil <paul@crapouillou.net> wrote:

> For a description of the pinctrl devicetree node, please read
> Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
>
> For a description of the gpio devicetree nodes, please read
> Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
>
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
> ---
>  arch/mips/boot/dts/ingenic/jz4740.dtsi | 194 +++++++++++++++++++++++++++++++++
>  1 file changed, 194 insertions(+)
>
> v2: Changed the devicetree bindings to match the new driver
> v3: No changes

This looks good to me, except the use of ingenic,pins instead
of just pins and the GPIO base property
which needs to be removed from the DT bindings and
the driver alike.

But now we're discussing where to put these GPIO controllers
in the device tree in another thread. Maybe as subnodes of the
pin controller...

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v3 04/14] GPIO: Add gpio-ingenic driver
  2017-01-25 18:51       ` [PATCH v3 04/14] GPIO: Add gpio-ingenic driver Paul Cercueil
  2017-01-31 14:13         ` Linus Walleij
@ 2017-01-31 14:20         ` Linus Walleij
  2017-01-31 15:29           ` Paul Cercueil
  1 sibling, 1 reply; 162+ messages in thread
From: Linus Walleij @ 2017-01-31 14:20 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

Forgot to mention this:

On Wed, Jan 25, 2017 at 7:51 PM, Paul Cercueil <paul@crapouillou.net> wrote:
> This driver handles the GPIOs of all the Ingenic JZ47xx SoCs
> currently supported by the upsteam Linux kernel.
>
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
(...)
> +       jzgc->gc.base = -1;

Nice

> +       of_property_read_u32(dev->of_node, "base", &jzgc->gc.base);

Remove this. Dynamic allocation should be fine, if you're using the
new userspace ABI like tools/gpio/* or libgpiod and only that and in-kernel
consumers, dynamic numbers are just fine.

If you have old sysfs userspace that you need to support using the
global GPIO numberspace, please look into ways to phase that out.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v3 04/14] GPIO: Add gpio-ingenic driver
  2017-01-31 14:20         ` Linus Walleij
@ 2017-01-31 15:29           ` Paul Cercueil
  2017-02-03 13:58             ` Linus Walleij
  0 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-01-31 15:29 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

Le 2017-01-31 15:20, Linus Walleij a écrit :

>> + of_property_read_u32(dev->of_node, "base", &jzgc->gc.base);
> 
> Remove this. Dynamic allocation should be fine, if you're using the
> new userspace ABI like tools/gpio/* or libgpiod and only that and 
> in-kernel
> consumers, dynamic numbers are just fine.

The problem is that the QI_LB60 board code still have a lot of 
references
to global GPIO numbers. Just grep for JZ_GPIO_PORT in
arch/mips/jz4740/board-qi_lb60.c to see what I mean...

-Paul

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v3 04/14] GPIO: Add gpio-ingenic driver
  2017-01-31 15:29           ` Paul Cercueil
@ 2017-02-03 13:58             ` Linus Walleij
  0 siblings, 0 replies; 162+ messages in thread
From: Linus Walleij @ 2017-02-03 13:58 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

On Tue, Jan 31, 2017 at 4:29 PM, Paul Cercueil <paul@crapouillou.net> wrote:
> Le 2017-01-31 15:20, Linus Walleij a écrit :
>
>>> + of_property_read_u32(dev->of_node, "base", &jzgc->gc.base);
>>
>>
>> Remove this. Dynamic allocation should be fine, if you're using the
>> new userspace ABI like tools/gpio/* or libgpiod and only that and
>> in-kernel
>> consumers, dynamic numbers are just fine.
>
>
> The problem is that the QI_LB60 board code still have a lot of references
> to global GPIO numbers. Just grep for JZ_GPIO_PORT in
> arch/mips/jz4740/board-qi_lb60.c to see what I mean...

OK I understand we might need a compromise here to get the code moving.

But we need to keep it out of the device tree.

I think it's better to put a base table relative to the memory base in
the driver in that case:

unsigned int gpio_global_base;

switch (memory_base_address) {
case 0x41000000:
    gpio_global_base = 0x00;
    break;
case 0x42000000:
    gpio_global_base = 0x20;

(...)

etc. (Those are not your base addresses but you get the idea).

Include a few comments like:

/*
 * DO NOT EXPAND THIS: FOR BACKWARD GPIO NUMBERSPACE
 * COMPATIBIBILITY ONLY: WORK TO TRANSITION CONSUMERS TO
 * USE THE GPIO DESCRIPTOR API IN <linux/gpio/consumer.h> INSTEAD.
 */

Then I'll be happy :)

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v3 04/14] GPIO: Add gpio-ingenic driver
  2017-01-31 14:13         ` Linus Walleij
@ 2017-02-09 17:14           ` Paul Cercueil
  2017-02-12 20:48             ` Linus Walleij
  0 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-02-09 17:14 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

Hi,

> What some drivers do when they just get/set a bit in a register
> to get/set or set the direction of a GPIO, is to select GPIO_GENERIC
> and just bgpio_init() with the right iomem pointers, then the core
> will register handlers for get, set, set_direcition callback and
> get_direction and your driver can just focus on the remainders.

GPIO_GENERIC and bgpio_init() would work for my .set() / .get() 
callbacks,
not for my .direction_input() / .direction_output() callbacks which need
to set more than one register.

> If you're not just replacing these with GPIO_GENERIC, please also
> include a .get_direction() callback.

My .direction_input() and .direction_output() callbacks just call into
the pinctrl driver, using pinctrl_gpio_direction_[in,out]put().
I didn't find a way to get the direction info from the pinctrl driver,
is that something that the core should provide?

Thanks,
-Paul

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v3 01/14] Documentation: dt/bindings: Document  pinctrl-ingenic
  2017-01-31 13:09             ` Linus Walleij
@ 2017-02-09 17:28               ` Paul Cercueil
  2017-02-20 13:56                 ` Linus Walleij
  0 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-02-09 17:28 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

Le 2017-01-31 14:09, Linus Walleij a écrit :
> On Tue, Jan 31, 2017 at 11:31 AM, Paul Cercueil <paul@crapouillou.net> 
> wrote:
>> [Rob]:
>>> From the overlapping register addresses in the examples and this
>>> description, it looks like the pinctrlr and gpio controller are 1 
>>> block.
>>> If so, then there should only be 1 node.
>> 
>> Well, that's what I had until Linus W. just told me to do the 
>> opposite:
>> 
>>> Just pull all these down two levels and make them one device
>>> each instead of having them inside the pin controller node
>>> like this.
> 
> I guess the argument is that they are in the same coherent memory
> range so they should be one device node. That is how we handle
> e.g. system controllers so it makes some sense.
> 
> So can the two GPIO controllers be modeled as two subnodes of
> the pin controller then?
> 
> Subnodes are certainly OK, we have that for many other devices
> such as interrupt controllers on PCI bridges and what not.
> 
> So when the probing of the pin controller is ready it can just
> walk down and populate the GPIO subdevices with
> of_platform_default_populate() or simply by registering the
> device directly with platform_device_add_data() just like an
> MFD device does?
> 
> This is nice because we want to use the standard gpio ranges
> to map pins to GPIO lines.
> 
> I'm sorry about the unclarities here, but it's essentially an intrinsic
> problem with GPIO that has been with us for years: do we model
> each "bank" as a device or do we just register each bank as a
> gpiochip, or do we even make one gpiochip to cover all the banks.
> All solutions can be found in the kernel... also the different DT 
> bindings:
> one node for a whole slew of GPIO controllers, or seveal nodes
> and I bet also several nodes for memory ranges in close proximity.
> 
> I don't know for sure what is the most elegant solution, we might
> need to build some consensus here for the future so it doesn't
> get to heterogeneous.
> 
> Yours,
> Linus Walleij

I was thinking that instead of having one pinctrl-ingenic instance 
covering
0x600 of register space, and 6 instances of gpio-ingenic having 0x100 
each,
I could just have 6 instances of pinctrl-ingenic, each one with an 
instance
of gpio-ingenic declared as a sub-node, each handling just 0x100 of 
memory space.

Then I can make pinctrl-ingenic and gpio-ingenic share a regmap (through 
syscon),
which would be a good idea anyway since the two drivers poke to the very 
same
registers (in theory not at the same time, but it's never safe to assume 
things
like this).

Problem is, that in that case the pin functions/groups (and 
ingenic,pull-ups)
would have to be in DTS because we would have 6 instances with different 
pin
groups, and I know you hate that.

Thoughts?

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v3 04/14] GPIO: Add gpio-ingenic driver
  2017-02-09 17:14           ` Paul Cercueil
@ 2017-02-12 20:48             ` Linus Walleij
  0 siblings, 0 replies; 162+ messages in thread
From: Linus Walleij @ 2017-02-12 20:48 UTC (permalink / raw)
  To: Paul Cercueil, Mika Westerberg
  Cc: Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

On Thu, Feb 9, 2017 at 6:14 PM, Paul Cercueil <paul@crapouillou.net> wrote:

>> If you're not just replacing these with GPIO_GENERIC, please also
>> include a .get_direction() callback.
>
> My .direction_input() and .direction_output() callbacks just call into
> the pinctrl driver, using pinctrl_gpio_direction_[in,out]put().
> I didn't find a way to get the direction info from the pinctrl driver,
> is that something that the core should provide?

Hm OK you have a clear point there, there is no such callback.

OK I do not require you to fix that at this time.

I am hesitant about providing ever more callbacks from GPIO
to pin control, I might need some help for consolidation here.

With Mika's patches we have a .set_config() call to
pinctrl_gpio_set_config() so essentially
we *could* actually refactor all pin control drivers providing
a GPIO back-end to use:

pinctrl_gpio_set_config(gpio, PIN_CONF_PACKED(PIN_CONFIG_INPUT_ENABLE, 0));
pinctrl_gpio_set_config(gpio, PIN_CONF_PACKED(PIN_CONFIG_OUTPUT, val));

And replace the calls to pinctrl_gpio_direction_input()
and pinctrl_gpio_direction_output() with this throughout.

It makes things a bit simpler. If we need to figure things
out the reverse direction then pinctrl_gpio_get_config()
should be implemented and used as back-end for
figuring out direction.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v3 01/14] Documentation: dt/bindings: Document pinctrl-ingenic
  2017-02-09 17:28               ` Paul Cercueil
@ 2017-02-20 13:56                 ` Linus Walleij
  2017-02-21 11:20                   ` Paul Cercueil
  0 siblings, 1 reply; 162+ messages in thread
From: Linus Walleij @ 2017-02-20 13:56 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

On Thu, Feb 9, 2017 at 6:28 PM, Paul Cercueil <paul@crapouillou.net> wrote:

> I was thinking that instead of having one pinctrl-ingenic instance covering
> 0x600 of register space, and 6 instances of gpio-ingenic having 0x100 each,
> I could just have 6 instances of pinctrl-ingenic, each one with an instance
> of gpio-ingenic declared as a sub-node, each handling just 0x100 of memory
> space.

My head is spinning,  but I think I get it. What is wrong with the solution
I proposed with one pin control instance covering the whole 0x600 and with 6
subnodes of GPIO?

The GPIO nodes do not even have to have an address range associated with
them you know, that can be distributed out with regmap code accessing
the parent regmap.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v3 01/14] Documentation: dt/bindings: Document pinctrl-ingenic
  2017-02-20 13:56                 ` Linus Walleij
@ 2017-02-21 11:20                   ` Paul Cercueil
  2017-02-23  9:59                     ` Linus Walleij
  0 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-02-21 11:20 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

Le 2017-02-20 14:56, Linus Walleij a écrit :
> On Thu, Feb 9, 2017 at 6:28 PM, Paul Cercueil <paul@crapouillou.net> 
> wrote:
> 
>> I was thinking that instead of having one pinctrl-ingenic instance 
>> covering
>> 0x600 of register space, and 6 instances of gpio-ingenic having 0x100 
>> each,
>> I could just have 6 instances of pinctrl-ingenic, each one with an 
>> instance
>> of gpio-ingenic declared as a sub-node, each handling just 0x100 of 
>> memory
>> space.
> 
> My head is spinning,  but I think I get it. What is wrong with the 
> solution
> I proposed with one pin control instance covering the whole 0x600 and 
> with 6
> subnodes of GPIO?
> 
> The GPIO nodes do not even have to have an address range associated 
> with
> them you know, that can be distributed out with regmap code accessing
> the parent regmap.

OK, but then each GPIO chip 'X' still need to know its offset in the 
register
area, which is (pinctrl_base + X * 0x100).
What's the best way to pass that info to the driver? (I assume it's not 
with
a custom DT binding...).

Regards,
-Paul

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v3 01/14] Documentation: dt/bindings: Document pinctrl-ingenic
  2017-02-21 11:20                   ` Paul Cercueil
@ 2017-02-23  9:59                     ` Linus Walleij
  0 siblings, 0 replies; 162+ messages in thread
From: Linus Walleij @ 2017-02-23  9:59 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Rob Herring, Mark Rutland, Ralf Baechle, Ulf Hansson,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, James Hogan

On Tue, Feb 21, 2017 at 12:20 PM, Paul Cercueil <paul@crapouillou.net> wrote:
> Le 2017-02-20 14:56, Linus Walleij a écrit :
>>
>> On Thu, Feb 9, 2017 at 6:28 PM, Paul Cercueil <paul@crapouillou.net>
>> wrote:
>>
>>> I was thinking that instead of having one pinctrl-ingenic instance
>>> covering
>>> 0x600 of register space, and 6 instances of gpio-ingenic having 0x100
>>> each,
>>> I could just have 6 instances of pinctrl-ingenic, each one with an
>>> instance
>>> of gpio-ingenic declared as a sub-node, each handling just 0x100 of
>>> memory
>>> space.
>>
>>
>> My head is spinning,  but I think I get it. What is wrong with the
>> solution
>> I proposed with one pin control instance covering the whole 0x600 and with
>> 6
>> subnodes of GPIO?
>>
>> The GPIO nodes do not even have to have an address range associated with
>> them you know, that can be distributed out with regmap code accessing
>> the parent regmap.
>
>
> OK, but then each GPIO chip 'X' still need to know its offset in the
> register
> area, which is (pinctrl_base + X * 0x100).
> What's the best way to pass that info to the driver? (I assume it's not with
> a custom DT binding...).

I do not really understand what driver you are referring to.

If the pin controller node is overarching and spawning children for
the gpiochips, you use the design pattern from MFD to pass data
from parents to children, e.g.:

#include <linux/regmap.h>

pinctrl driver:
     struct regmap_config mapconf = {
                .reg_bits = 32,
                .val_bits = 32,
                .reg_stride = 4,
     };
    struct regmap *map;

    map = regmap_init_mmio(dev, base, &mapconf);
    if (IS_ERR(map))
          ....
    dev_set_drvdata(dev, map);
    of_populate_children(dev,)..
    (can also use platform_device_add_data() or "simple-bus" etc)

gpio subdrivers:
     struct regmap *map;

     map = dev_get_drvdata(dev->parent);

There are examples of drivers passing more complex things to
their children than a regmap, just put some struct in a <linux/*/*.h>
file and pass it with drvdata as per above.

PS i2c_set_drvdata(), platform_set_drvdata() are just aliases
for dev_set_drvdata().

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver
  2017-01-25 18:51       ` [PATCH v3 01/14] Documentation: dt/bindings: Document pinctrl-ingenic Paul Cercueil
  2017-01-30 20:36         ` Rob Herring
@ 2017-04-02 20:42         ` Paul Cercueil
  2017-04-02 20:42           ` [PATCH v4 01/14] dt/bindings: Document pinctrl-ingenic Paul Cercueil
                             ` (13 more replies)
  1 sibling, 14 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-04-02 20:42 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev

This is the v4 of my patchset that introduces the pinctrl-ingenic and
gpio-ingenic drivers. The drivers were rewritten based on the feedback
received on the v3 version.

The pinctrl-ingenic driver now contains the pinmux/pinconf information of
each compatible SoC, so the devicetree bindings have been simplified greatly.

The driver now uses regmap for accessing the registers. This regmap is shared
to optional instances of the gpio-ingenic driver, that are instanciated as
MFD cells of the pinctrl-ingenic driver.

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v4 01/14] dt/bindings: Document pinctrl-ingenic
  2017-04-02 20:42         ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
@ 2017-04-02 20:42           ` Paul Cercueil
  2017-04-04 14:48             ` Rob Herring
  2017-04-28 20:08             ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
  2017-04-02 20:42           ` [PATCH v4 02/14] dt/bindings: Document gpio-ingenic Paul Cercueil
                             ` (12 subsequent siblings)
  13 siblings, 2 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-04-02 20:42 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

This commit adds documentation for the devicetree bindings of the
pinctrl-ingenic driver, which handles pin configuration and pin
muxing of the Ingenic SoCs currently supported by the Linux kernel.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 .../bindings/pinctrl/ingenic,pinctrl.txt           | 41 ++++++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt

 v2: Rewrote the documentation for the new pinctrl-ingenic driver
 v3: No changes
 v4: Update for the v4 version of the pinctrl-ingenic driver

diff --git a/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
new file mode 100644
index 000000000000..0e43b527b681
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
@@ -0,0 +1,41 @@
+Ingenic jz47xx pin controller
+
+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".
+
+For the jz47xx SoCs, pin control is tightly bound with GPIO ports. All pins may
+be used as GPIOs, multiplexed device functions are configured within the
+GPIO port configuration registers and it is typical to refer to pins using the
+naming scheme "PxN" where x is a character identifying the GPIO port with
+which the pin is associated and N is an integer from 0 to 31 identifying the
+pin within that GPIO port. For example PA0 is the first pin in GPIO port A, and
+PB31 is the last pin in GPIO port B. The jz4740 contains 4 GPIO ports, PA to
+PD, for a total of 128 pins. The jz4780 contains 6 GPIO ports, PA to PF, for a
+total of 192 pins.
+
+
+Required properties:
+--------------------
+
+ - compatible: One of:
+    - "ingenic,jz4740-pinctrl"
+    - "ingenic,jz4770-pinctrl"
+    - "ingenic,jz4780-pinctrl"
+ - reg: Address range of the pinctrl registers.
+
+
+GPIO sub-nodes
+--------------
+
+The pinctrl node can have optional sub-nodes for the Ingenic GPIO driver;
+please refer to ../gpio/ingenic,gpio.txt.
+
+
+Example:
+--------
+
+pinctrl: ingenic-pinctrl@10010000 {
+	compatible = "ingenic,jz4740-pinctrl";
+	reg = <0x10010000 0x400>;
+};
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v4 02/14] dt/bindings: Document gpio-ingenic
  2017-04-02 20:42         ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
  2017-04-02 20:42           ` [PATCH v4 01/14] dt/bindings: Document pinctrl-ingenic Paul Cercueil
@ 2017-04-02 20:42           ` Paul Cercueil
  2017-04-04 14:52             ` Rob Herring
  2017-04-02 20:42           ` [PATCH v4 03/14] pinctrl-ingenic: add a pinctrl driver for the Ingenic jz47xx SoCs Paul Cercueil
                             ` (11 subsequent siblings)
  13 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-04-02 20:42 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

This commit adds documentation for the devicetree bindings of the
gpio-ingenic driver, which handles GPIOs of the Ingenic SoCs
currently supported by the Linux kernel.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 .../devicetree/bindings/gpio/ingenic,gpio.txt      | 48 ++++++++++++++++++++++
 1 file changed, 48 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/gpio/ingenic,gpio.txt

 v2: New patch
 v3: No changes
 v4: Update for the v4 version of the gpio-ingenic driver

diff --git a/Documentation/devicetree/bindings/gpio/ingenic,gpio.txt b/Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
new file mode 100644
index 000000000000..f54af444f7c3
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
@@ -0,0 +1,48 @@
+Ingenic jz47xx GPIO controller
+
+That the Ingenic GPIO driver node must be a sub-node of the Ingenic pinctrl
+driver node.
+
+Required properties:
+--------------------
+
+ - compatible: Must contain one of:
+    - "ingenic,jz4740-gpio"
+    - "ingenic,jz4770-gpio"
+    - "ingenic,jz4780-gpio"
+	And one of:
+	- "ingenic,gpio-bank-a"
+	- "ingenic,gpio-bank-b"
+	- "ingenic,gpio-bank-c"
+	- "ingenic,gpio-bank-d"
+	- "ingenic,gpio-bank-e" (for SoC version > jz4740)
+	- "ingenic,gpio-bank-f" (for SoC version > jz4740)
+ - interrupt-controller: Marks the device node as an interrupt controller.
+ - interrupts: Interrupt specifier for the controllers interrupt.
+ - #interrupt-cells: Should be 2. Refer to
+   ../interrupt-controller/interrupts.txt for more details.
+ - gpio-controller: Marks the device node as a GPIO controller.
+ - #gpio-cells: Should be 2. The first cell is the GPIO number and the second
+    cell specifies GPIO flags, as defined in <dt-bindings/gpio/gpio.h>. Only the
+    GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported.
+ - gpio-ranges: Range of pins managed by the GPIO controller. Refer to
+   'gpio.txt' in this directory for more details.
+
+Example:
+--------
+
+&pinctrl {
+	gpa: gpio-controller@0 {
+		compatible = "ingenic,gpio-bank-a", "ingenic,jz4740-gpio";
+
+		gpio-controller;
+		gpio-ranges = <&pinctrl 0 0 32>;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <28>;
+	};
+};
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v4 03/14] pinctrl-ingenic: add a pinctrl driver for the Ingenic jz47xx SoCs
  2017-04-02 20:42         ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
  2017-04-02 20:42           ` [PATCH v4 01/14] dt/bindings: Document pinctrl-ingenic Paul Cercueil
  2017-04-02 20:42           ` [PATCH v4 02/14] dt/bindings: Document gpio-ingenic Paul Cercueil
@ 2017-04-02 20:42           ` Paul Cercueil
  2017-04-07  9:41             ` Linus Walleij
  2017-04-02 20:42           ` [PATCH v4 04/14] GPIO: Add gpio-ingenic driver Paul Cercueil
                             ` (10 subsequent siblings)
  13 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-04-02 20:42 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

This driver handles pin configuration and pin muxing for the
JZ4740 and JZ4780 SoCs from Ingenic.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/pinctrl/Kconfig           |  10 +
 drivers/pinctrl/Makefile          |   1 +
 drivers/pinctrl/pinctrl-ingenic.c | 884 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 895 insertions(+)
 create mode 100644 drivers/pinctrl/pinctrl-ingenic.c

 v2: Consider it's a new patch. Completely rewritten from v1.
 v3: 'unsigned' -> 'unsigned int'
 v4: Completely rewritten from v3.

diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 8f8c2af45781..82ce72fcb8e0 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -285,6 +285,16 @@ config PINCTRL_ZYNQ
 	help
 	  This selects the pinctrl driver for Xilinx Zynq.
 
+config PINCTRL_INGENIC
+	bool "Pinctrl driver for the Ingenic JZ47xx SoCs"
+	default y
+	depends on MACH_INGENIC || COMPILE_TEST
+	select GENERIC_PINCONF
+	select GENERIC_PINCTRL_GROUPS
+	select GENERIC_PINMUX_FUNCTIONS
+	select REGMAP_MMIO
+	select MFD_CORE
+
 source "drivers/pinctrl/aspeed/Kconfig"
 source "drivers/pinctrl/bcm/Kconfig"
 source "drivers/pinctrl/berlin/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index a251f439626f..80f327239d4b 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_PINCTRL_LPC18XX)	+= pinctrl-lpc18xx.o
 obj-$(CONFIG_PINCTRL_TB10X)	+= pinctrl-tb10x.o
 obj-$(CONFIG_PINCTRL_ST) 	+= pinctrl-st.o
 obj-$(CONFIG_PINCTRL_ZYNQ)	+= pinctrl-zynq.o
+obj-$(CONFIG_PINCTRL_INGENIC)	+= pinctrl-ingenic.o
 
 obj-$(CONFIG_ARCH_ASPEED)	+= aspeed/
 obj-y				+= bcm/
diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-ingenic.c
new file mode 100644
index 000000000000..3eeee46d7432
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-ingenic.c
@@ -0,0 +1,884 @@
+/*
+ * Ingenic SoCs pinctrl driver
+ *
+ * Copyright (c) 2017 Paul Cercueil <paul@crapouillou.net>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/compiler.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mfd/core.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include "core.h"
+#include "pinconf.h"
+#include "pinmux.h"
+
+#define JZ4740_GPIO_DATA	0x10
+#define JZ4740_GPIO_PULL_DIS	0x30
+#define JZ4740_GPIO_FUNC	0x40
+#define JZ4740_GPIO_SELECT	0x50
+#define JZ4740_GPIO_DIR		0x60
+#define JZ4740_GPIO_TRIG	0x70
+#define JZ4740_GPIO_FLAG	0x80
+
+#define JZ4770_GPIO_INT		0x10
+#define JZ4770_GPIO_MSK		0x20
+#define JZ4770_GPIO_PAT1	0x30
+#define JZ4770_GPIO_PAT0	0x40
+#define JZ4770_GPIO_FLAG	0x50
+#define JZ4770_GPIO_PEN		0x70
+
+#define REG_SET(x) ((x) + 0x4)
+#define REG_CLEAR(x) ((x) + 0x8)
+
+#define PINS_PER_GPIO_CHIP 32
+
+enum jz_version {
+	ID_JZ4740,
+	ID_JZ4770,
+	ID_JZ4780,
+};
+
+struct ingenic_chip_info {
+	unsigned int num_chips;
+
+	const struct group_desc *groups;
+	unsigned int num_groups;
+
+	const struct function_desc *functions;
+	unsigned int num_functions;
+
+	const u32 *pull_ups, *pull_downs;
+};
+
+struct ingenic_pinctrl {
+	struct device *dev;
+	struct regmap *map;
+	struct pinctrl_dev *pctl;
+	struct pinctrl_pin_desc *pdesc;
+	enum jz_version version;
+
+	const struct ingenic_chip_info *info;
+};
+
+static const u32 jz4740_pull_ups[4] = {
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+};
+
+static const u32 jz4740_pull_downs[4] = {
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static int jz4740_mmc_1bit_pins[] = { 0x69, 0x68, 0x6a, };
+static int jz4740_mmc_4bit_pins[] = { 0x6b, 0x6c, 0x6d, };
+static int jz4740_uart0_data_pins[] = { 0x7a, 0x79, };
+static int jz4740_uart0_hwflow_pins[] = { 0x7e, 0x7f, };
+static int jz4740_uart1_data_pins[] = { 0x7e, 0x7f, };
+static int jz4740_lcd_8bit_pins[] = {
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x52, 0x53, 0x54,
+};
+static int jz4740_lcd_16bit_pins[] = {
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x55,
+};
+static int jz4740_lcd_18bit_pins[] = { 0x50, 0x51, };
+static int jz4740_lcd_18bit_tft_pins[] = { 0x56, 0x57, 0x31, 0x32, };
+static int jz4740_nand_cs1_pins[] = { 0x39, };
+static int jz4740_nand_cs2_pins[] = { 0x3a, };
+static int jz4740_nand_cs3_pins[] = { 0x3b, };
+static int jz4740_nand_cs4_pins[] = { 0x3c, };
+static int jz4740_pwm_pwm0_pins[] = { 0x77, };
+static int jz4740_pwm_pwm1_pins[] = { 0x78, };
+static int jz4740_pwm_pwm2_pins[] = { 0x79, };
+static int jz4740_pwm_pwm3_pins[] = { 0x7a, };
+static int jz4740_pwm_pwm4_pins[] = { 0x7b, };
+static int jz4740_pwm_pwm5_pins[] = { 0x7c, };
+static int jz4740_pwm_pwm6_pins[] = { 0x7e, };
+static int jz4740_pwm_pwm7_pins[] = { 0x7f, };
+
+static int jz4740_mmc_1bit_funcs[] = { 0, 0, 0, };
+static int jz4740_mmc_4bit_funcs[] = { 0, 0, 0, };
+static int jz4740_uart0_data_funcs[] = { 1, 1, };
+static int jz4740_uart0_hwflow_funcs[] = { 1, 1, };
+static int jz4740_uart1_data_funcs[] = { 2, 2, };
+static int jz4740_lcd_8bit_funcs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
+static int jz4740_lcd_16bit_funcs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, };
+static int jz4740_lcd_18bit_funcs[] = { 0, 0, };
+static int jz4740_lcd_18bit_tft_funcs[] = { 0, 0, 0, 0, };
+static int jz4740_nand_cs1_funcs[] = { 0, };
+static int jz4740_nand_cs2_funcs[] = { 0, };
+static int jz4740_nand_cs3_funcs[] = { 0, };
+static int jz4740_nand_cs4_funcs[] = { 0, };
+static int jz4740_pwm_pwm0_funcs[] = { 0, };
+static int jz4740_pwm_pwm1_funcs[] = { 0, };
+static int jz4740_pwm_pwm2_funcs[] = { 0, };
+static int jz4740_pwm_pwm3_funcs[] = { 0, };
+static int jz4740_pwm_pwm4_funcs[] = { 0, };
+static int jz4740_pwm_pwm5_funcs[] = { 0, };
+static int jz4740_pwm_pwm6_funcs[] = { 0, };
+static int jz4740_pwm_pwm7_funcs[] = { 0, };
+
+#define INGENIC_PIN_GROUP(name, id)			\
+	{						\
+		name,					\
+		id##_pins,				\
+		ARRAY_SIZE(id##_pins),			\
+		id##_funcs,				\
+	}
+
+static const struct group_desc jz4740_groups[] = {
+	INGENIC_PIN_GROUP("mmc-1bit", jz4740_mmc_1bit),
+	INGENIC_PIN_GROUP("mmc-4bit", jz4740_mmc_4bit),
+	INGENIC_PIN_GROUP("uart0-data", jz4740_uart0_data),
+	INGENIC_PIN_GROUP("uart0-hwflow", jz4740_uart0_hwflow),
+	INGENIC_PIN_GROUP("uart1-data", jz4740_uart1_data),
+	INGENIC_PIN_GROUP("lcd-8bit", jz4740_lcd_8bit),
+	INGENIC_PIN_GROUP("lcd-16bit", jz4740_lcd_16bit),
+	INGENIC_PIN_GROUP("lcd-18bit", jz4740_lcd_18bit),
+	INGENIC_PIN_GROUP("lcd-18bit-tft", jz4740_lcd_18bit_tft),
+	{ "lcd-no-pins", },
+	INGENIC_PIN_GROUP("nand-cs1", jz4740_nand_cs1),
+	INGENIC_PIN_GROUP("nand-cs2", jz4740_nand_cs2),
+	INGENIC_PIN_GROUP("nand-cs3", jz4740_nand_cs3),
+	INGENIC_PIN_GROUP("nand-cs4", jz4740_nand_cs4),
+	INGENIC_PIN_GROUP("pwm0", jz4740_pwm_pwm0),
+	INGENIC_PIN_GROUP("pwm1", jz4740_pwm_pwm1),
+	INGENIC_PIN_GROUP("pwm2", jz4740_pwm_pwm2),
+	INGENIC_PIN_GROUP("pwm3", jz4740_pwm_pwm3),
+	INGENIC_PIN_GROUP("pwm4", jz4740_pwm_pwm4),
+	INGENIC_PIN_GROUP("pwm5", jz4740_pwm_pwm5),
+	INGENIC_PIN_GROUP("pwm6", jz4740_pwm_pwm6),
+	INGENIC_PIN_GROUP("pwm7", jz4740_pwm_pwm7),
+};
+
+static const char *jz4740_mmc_groups[] = { "mmc-1bit", "mmc-4bit", };
+static const char *jz4740_uart0_groups[] = { "uart0-data", "uart0-hwflow", };
+static const char *jz4740_uart1_groups[] = { "uart1-data", };
+static const char *jz4740_lcd_groups[] = {
+	"lcd-8bit", "lcd-16bit", "lcd-18bit", "lcd-18bit-tft", "lcd-no-pins",
+};
+static const char *jz4740_nand_groups[] = {
+	"nand-cs1", "nand-cs2", "nand-cs3", "nand-cs4",
+};
+static const char *jz4740_pwm0_groups[] = { "pwm0", };
+static const char *jz4740_pwm1_groups[] = { "pwm1", };
+static const char *jz4740_pwm2_groups[] = { "pwm2", };
+static const char *jz4740_pwm3_groups[] = { "pwm3", };
+static const char *jz4740_pwm4_groups[] = { "pwm4", };
+static const char *jz4740_pwm5_groups[] = { "pwm5", };
+static const char *jz4740_pwm6_groups[] = { "pwm6", };
+static const char *jz4740_pwm7_groups[] = { "pwm7", };
+
+static const struct function_desc jz4740_functions[] = {
+	{ "mmc", jz4740_mmc_groups, ARRAY_SIZE(jz4740_mmc_groups), },
+	{ "uart0", jz4740_uart0_groups, ARRAY_SIZE(jz4740_uart0_groups), },
+	{ "uart1", jz4740_uart1_groups, ARRAY_SIZE(jz4740_uart1_groups), },
+	{ "lcd", jz4740_lcd_groups, ARRAY_SIZE(jz4740_lcd_groups), },
+	{ "nand", jz4740_nand_groups, ARRAY_SIZE(jz4740_nand_groups), },
+	{ "pwm0", jz4740_pwm0_groups, ARRAY_SIZE(jz4740_pwm0_groups), },
+	{ "pwm1", jz4740_pwm1_groups, ARRAY_SIZE(jz4740_pwm1_groups), },
+	{ "pwm2", jz4740_pwm2_groups, ARRAY_SIZE(jz4740_pwm2_groups), },
+	{ "pwm3", jz4740_pwm3_groups, ARRAY_SIZE(jz4740_pwm3_groups), },
+	{ "pwm4", jz4740_pwm4_groups, ARRAY_SIZE(jz4740_pwm4_groups), },
+	{ "pwm5", jz4740_pwm5_groups, ARRAY_SIZE(jz4740_pwm5_groups), },
+	{ "pwm6", jz4740_pwm6_groups, ARRAY_SIZE(jz4740_pwm6_groups), },
+	{ "pwm7", jz4740_pwm7_groups, ARRAY_SIZE(jz4740_pwm7_groups), },
+};
+
+static const struct ingenic_chip_info jz4740_chip_info = {
+	.num_chips = 4,
+	.groups = jz4740_groups,
+	.num_groups = ARRAY_SIZE(jz4740_groups),
+	.functions = jz4740_functions,
+	.num_functions = ARRAY_SIZE(jz4740_functions),
+	.pull_ups = jz4740_pull_ups,
+	.pull_downs = jz4740_pull_downs,
+};
+
+static const u32 jz4770_pull_ups[6] = {
+	0x3fffffff, 0xfff0030c, 0xffffffff, 0xffff4fff, 0xfffffb7c, 0xffa7f00f,
+};
+
+static const u32 jz4770_pull_downs[6] = {
+	0x00000000, 0x000f0c03, 0x00000000, 0x0000b000, 0x00000483, 0x00580ff0,
+};
+
+static int jz4770_uart0_data_pins[] = { 0xa0, 0xa3, };
+static int jz4770_uart0_hwflow_pins[] = { 0xa1, 0xa2, };
+static int jz4770_uart1_data_pins[] = { 0x7a, 0x7c, };
+static int jz4770_uart1_hwflow_pins[] = { 0x7b, 0x7d, };
+static int jz4770_uart2_data_pins[] = { 0x66, 0x67, };
+static int jz4770_uart2_hwflow_pins[] = { 0x65, 0x64, };
+static int jz4770_uart3_data_pins[] = { 0x6c, 0x85, };
+static int jz4770_uart3_hwflow_pins[] = { 0x88, 0x89, };
+static int jz4770_uart4_data_pins[] = { 0x54, 0x4a, };
+static int jz4770_mmc0_8bit_a_pins[] = { 0x04, 0x05, 0x06, 0x07, 0x18, };
+static int jz4770_mmc0_4bit_a_pins[] = { 0x15, 0x16, 0x17, };
+static int jz4770_mmc0_1bit_a_pins[] = { 0x12, 0x13, 0x14, };
+static int jz4770_mmc0_4bit_e_pins[] = { 0x95, 0x96, 0x97, };
+static int jz4770_mmc0_1bit_e_pins[] = { 0x9c, 0x9d, 0x94, };
+static int jz4770_mmc1_4bit_d_pins[] = { 0x75, 0x76, 0x77, };
+static int jz4770_mmc1_1bit_d_pins[] = { 0x78, 0x79, 0x74, };
+static int jz4770_mmc1_4bit_e_pins[] = { 0x95, 0x96, 0x97, };
+static int jz4770_mmc1_1bit_e_pins[] = { 0x9c, 0x9d, 0x94, };
+static int jz4770_nemc_data_pins[] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+};
+static int jz4770_nemc_cle_ale_pins[] = { 0x20, 0x21, };
+static int jz4770_nemc_addr_pins[] = { 0x22, 0x23, 0x24, 0x25, };
+static int jz4770_nemc_rd_we_pins[] = { 0x10, 0x11, };
+static int jz4770_nemc_frd_fwe_pins[] = { 0x12, 0x13, };
+static int jz4770_nemc_cs1_pins[] = { 0x15, };
+static int jz4770_nemc_cs2_pins[] = { 0x16, };
+static int jz4770_nemc_cs3_pins[] = { 0x17, };
+static int jz4770_nemc_cs4_pins[] = { 0x18, };
+static int jz4770_nemc_cs5_pins[] = { 0x19, };
+static int jz4770_nemc_cs6_pins[] = { 0x1a, };
+static int jz4770_i2c0_pins[] = { 0x6e, 0x6f, };
+static int jz4770_i2c1_pins[] = { 0x8e, 0x8f, };
+static int jz4770_i2c2_pins[] = { 0xb0, 0xb1, };
+static int jz4770_i2c3_pins[] = { 0x6a, 0x6b, };
+static int jz4770_i2c4_e_pins[] = { 0x8c, 0x8d, };
+static int jz4770_i2c4_f_pins[] = { 0xb9, 0xb8, };
+static int jz4770_cim_pins[] = {
+	0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31,
+};
+static int jz4770_lcd_32bit_pins[] = {
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+	0x58, 0x59, 0x51,
+};
+static int jz4770_pwm_pwm0_pins[] = { 0x80, };
+static int jz4770_pwm_pwm1_pins[] = { 0x81, };
+static int jz4770_pwm_pwm2_pins[] = { 0x82, };
+static int jz4770_pwm_pwm3_pins[] = { 0x83, };
+static int jz4770_pwm_pwm4_pins[] = { 0x84, };
+static int jz4770_pwm_pwm5_pins[] = { 0x85, };
+static int jz4770_pwm_pwm6_pins[] = { 0x6a, };
+static int jz4770_pwm_pwm7_pins[] = { 0x6b, };
+
+static int jz4770_uart0_data_funcs[] = { 0, 0, };
+static int jz4770_uart0_hwflow_funcs[] = { 0, 0, };
+static int jz4770_uart1_data_funcs[] = { 0, 0, };
+static int jz4770_uart1_hwflow_funcs[] = { 0, 0, };
+static int jz4770_uart2_data_funcs[] = { 1, 1, };
+static int jz4770_uart2_hwflow_funcs[] = { 1, 1, };
+static int jz4770_uart3_data_funcs[] = { 0, 1, };
+static int jz4770_uart3_hwflow_funcs[] = { 0, 0, };
+static int jz4770_uart4_data_funcs[] = { 2, 2, };
+static int jz4770_mmc0_8bit_a_funcs[] = { 1, 1, 1, 1, 1, };
+static int jz4770_mmc0_4bit_a_funcs[] = { 1, 1, 1, };
+static int jz4770_mmc0_1bit_a_funcs[] = { 1, 1, 0, };
+static int jz4770_mmc0_4bit_e_funcs[] = { 0, 0, 0, };
+static int jz4770_mmc0_1bit_e_funcs[] = { 0, 0, 0, };
+static int jz4770_mmc1_4bit_d_funcs[] = { 0, 0, 0, };
+static int jz4770_mmc1_1bit_d_funcs[] = { 0, 0, 0, };
+static int jz4770_mmc1_4bit_e_funcs[] = { 1, 1, 1, };
+static int jz4770_mmc1_1bit_e_funcs[] = { 1, 1, 1, };
+static int jz4770_nemc_data_funcs[] = { 0, 0, 0, 0, 0, 0, 0, 0, };
+static int jz4770_nemc_cle_ale_funcs[] = { 0, 0, };
+static int jz4770_nemc_addr_funcs[] = { 0, 0, 0, 0, };
+static int jz4770_nemc_rd_we_funcs[] = { 0, 0, };
+static int jz4770_nemc_frd_fwe_funcs[] = { 0, 0, };
+static int jz4770_nemc_cs1_funcs[] = { 0, };
+static int jz4770_nemc_cs2_funcs[] = { 0, };
+static int jz4770_nemc_cs3_funcs[] = { 0, };
+static int jz4770_nemc_cs4_funcs[] = { 0, };
+static int jz4770_nemc_cs5_funcs[] = { 0, };
+static int jz4770_nemc_cs6_funcs[] = { 0, };
+static int jz4770_i2c0_funcs[] = { 0, 0, };
+static int jz4770_i2c1_funcs[] = { 0, 0, };
+static int jz4770_i2c2_funcs[] = { 2, 2, };
+static int jz4770_i2c3_funcs[] = { 1, 1, };
+static int jz4770_i2c4_e_funcs[] = { 1, 1, };
+static int jz4770_i2c4_f_funcs[] = { 1, 1, };
+static int jz4770_cim_funcs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
+static int jz4770_lcd_32bit_funcs[] = {
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0,
+};
+static int jz4770_pwm_pwm0_funcs[] = { 0, };
+static int jz4770_pwm_pwm1_funcs[] = { 0, };
+static int jz4770_pwm_pwm2_funcs[] = { 0, };
+static int jz4770_pwm_pwm3_funcs[] = { 0, };
+static int jz4770_pwm_pwm4_funcs[] = { 0, };
+static int jz4770_pwm_pwm5_funcs[] = { 0, };
+static int jz4770_pwm_pwm6_funcs[] = { 0, };
+static int jz4770_pwm_pwm7_funcs[] = { 0, };
+
+static const struct group_desc jz4770_groups[] = {
+	INGENIC_PIN_GROUP("uart0-data", jz4770_uart0_data),
+	INGENIC_PIN_GROUP("uart0-hwflow", jz4770_uart0_hwflow),
+	INGENIC_PIN_GROUP("uart1-data", jz4770_uart1_data),
+	INGENIC_PIN_GROUP("uart1-hwflow", jz4770_uart1_hwflow),
+	INGENIC_PIN_GROUP("uart2-data", jz4770_uart2_data),
+	INGENIC_PIN_GROUP("uart2-hwflow", jz4770_uart2_hwflow),
+	INGENIC_PIN_GROUP("uart3-data", jz4770_uart3_data),
+	INGENIC_PIN_GROUP("uart3-hwflow", jz4770_uart3_hwflow),
+	INGENIC_PIN_GROUP("uart4-data", jz4770_uart4_data),
+	INGENIC_PIN_GROUP("mmc0-8bit-a", jz4770_mmc0_8bit_a),
+	INGENIC_PIN_GROUP("mmc0-4bit-a", jz4770_mmc0_4bit_a),
+	INGENIC_PIN_GROUP("mmc0-1bit-a", jz4770_mmc0_1bit_a),
+	INGENIC_PIN_GROUP("mmc0-4bit-e", jz4770_mmc0_4bit_e),
+	INGENIC_PIN_GROUP("mmc0-1bit-e", jz4770_mmc0_1bit_e),
+	INGENIC_PIN_GROUP("mmc1-4bit-d", jz4770_mmc1_4bit_d),
+	INGENIC_PIN_GROUP("mmc1-1bit-d", jz4770_mmc1_1bit_d),
+	INGENIC_PIN_GROUP("mmc1-4bit-e", jz4770_mmc1_4bit_e),
+	INGENIC_PIN_GROUP("mmc1-1bit-e", jz4770_mmc1_1bit_e),
+	INGENIC_PIN_GROUP("nemc-data", jz4770_nemc_data),
+	INGENIC_PIN_GROUP("nemc-cle-ale", jz4770_nemc_cle_ale),
+	INGENIC_PIN_GROUP("nemc-addr", jz4770_nemc_addr),
+	INGENIC_PIN_GROUP("nemc-rd-we", jz4770_nemc_rd_we),
+	INGENIC_PIN_GROUP("nemc-frd-fwe", jz4770_nemc_frd_fwe),
+	INGENIC_PIN_GROUP("nemc-cs1", jz4770_nemc_cs1),
+	INGENIC_PIN_GROUP("nemc-cs2", jz4770_nemc_cs2),
+	INGENIC_PIN_GROUP("nemc-cs3", jz4770_nemc_cs3),
+	INGENIC_PIN_GROUP("nemc-cs4", jz4770_nemc_cs4),
+	INGENIC_PIN_GROUP("nemc-cs5", jz4770_nemc_cs5),
+	INGENIC_PIN_GROUP("nemc-cs6", jz4770_nemc_cs6),
+	INGENIC_PIN_GROUP("i2c0-data", jz4770_i2c0),
+	INGENIC_PIN_GROUP("i2c1-data", jz4770_i2c1),
+	INGENIC_PIN_GROUP("i2c2-data", jz4770_i2c2),
+	INGENIC_PIN_GROUP("i2c3-data", jz4770_i2c3),
+	INGENIC_PIN_GROUP("i2c4-data-e", jz4770_i2c4_e),
+	INGENIC_PIN_GROUP("i2c4-data-f", jz4770_i2c4_f),
+	INGENIC_PIN_GROUP("cim-data", jz4770_cim),
+	INGENIC_PIN_GROUP("lcd-32bit", jz4770_lcd_32bit),
+	{ "lcd-no-pins", },
+	INGENIC_PIN_GROUP("pwm0", jz4770_pwm_pwm0),
+	INGENIC_PIN_GROUP("pwm1", jz4770_pwm_pwm1),
+	INGENIC_PIN_GROUP("pwm2", jz4770_pwm_pwm2),
+	INGENIC_PIN_GROUP("pwm3", jz4770_pwm_pwm3),
+	INGENIC_PIN_GROUP("pwm4", jz4770_pwm_pwm4),
+	INGENIC_PIN_GROUP("pwm5", jz4770_pwm_pwm5),
+	INGENIC_PIN_GROUP("pwm6", jz4770_pwm_pwm6),
+	INGENIC_PIN_GROUP("pwm7", jz4770_pwm_pwm7),
+};
+
+static const char *jz4770_uart0_groups[] = { "uart0-data", "uart0-hwflow", };
+static const char *jz4770_uart1_groups[] = { "uart1-data", "uart1-hwflow", };
+static const char *jz4770_uart2_groups[] = { "uart2-data", "uart2-hwflow", };
+static const char *jz4770_uart3_groups[] = { "uart3-data", "uart3-hwflow", };
+static const char *jz4770_uart4_groups[] = { "uart4-data", };
+static const char *jz4770_mmc0_groups[] = {
+	"mmc0-8bit-a", "mmc0-4bit-a", "mmc0-1bit-a",
+	"mmc0-1bit-e", "mmc0-4bit-e",
+};
+static const char *jz4770_mmc1_groups[] = {
+	"mmc1-1bit-d", "mmc1-4bit-d", "mmc1-1bit-e", "mmc1-4bit-e",
+};
+static const char *jz4770_nemc_groups[] = {
+	"nemc-data", "nemc-cle-ale", "nemc-addr", "nemc-rd-we", "nemc-frd-fwe",
+};
+static const char *jz4770_cs1_groups[] = { "nemc-cs1", };
+static const char *jz4770_cs6_groups[] = { "nemc-cs6", };
+static const char *jz4770_i2c0_groups[] = { "i2c0-data", };
+static const char *jz4770_i2c1_groups[] = { "i2c1-data", };
+static const char *jz4770_i2c2_groups[] = { "i2c2-data", };
+static const char *jz4770_i2c3_groups[] = { "i2c3-data", };
+static const char *jz4770_i2c4_groups[] = { "i2c4-data-e", "i2c4-data-f", };
+static const char *jz4770_cim_groups[] = { "cim-data", };
+static const char *jz4770_lcd_groups[] = { "lcd-32bit", "lcd-no-pins", };
+static const char *jz4770_pwm0_groups[] = { "pwm0", };
+static const char *jz4770_pwm1_groups[] = { "pwm1", };
+static const char *jz4770_pwm2_groups[] = { "pwm2", };
+static const char *jz4770_pwm3_groups[] = { "pwm3", };
+static const char *jz4770_pwm4_groups[] = { "pwm4", };
+static const char *jz4770_pwm5_groups[] = { "pwm5", };
+static const char *jz4770_pwm6_groups[] = { "pwm6", };
+static const char *jz4770_pwm7_groups[] = { "pwm7", };
+
+static const struct function_desc jz4770_functions[] = {
+	{ "uart0", jz4770_uart0_groups, ARRAY_SIZE(jz4770_uart0_groups), },
+	{ "uart1", jz4770_uart1_groups, ARRAY_SIZE(jz4770_uart1_groups), },
+	{ "uart2", jz4770_uart2_groups, ARRAY_SIZE(jz4770_uart2_groups), },
+	{ "uart3", jz4770_uart3_groups, ARRAY_SIZE(jz4770_uart3_groups), },
+	{ "uart4", jz4770_uart4_groups, ARRAY_SIZE(jz4770_uart4_groups), },
+	{ "mmc0", jz4770_mmc0_groups, ARRAY_SIZE(jz4770_mmc0_groups), },
+	{ "mmc1", jz4770_mmc1_groups, ARRAY_SIZE(jz4770_mmc1_groups), },
+	{ "nemc", jz4770_nemc_groups, ARRAY_SIZE(jz4770_nemc_groups), },
+	{ "nemc-cs1", jz4770_cs1_groups, ARRAY_SIZE(jz4770_cs1_groups), },
+	{ "nemc-cs6", jz4770_cs6_groups, ARRAY_SIZE(jz4770_cs6_groups), },
+	{ "i2c0", jz4770_i2c0_groups, ARRAY_SIZE(jz4770_i2c0_groups), },
+	{ "i2c1", jz4770_i2c1_groups, ARRAY_SIZE(jz4770_i2c1_groups), },
+	{ "i2c2", jz4770_i2c2_groups, ARRAY_SIZE(jz4770_i2c2_groups), },
+	{ "i2c3", jz4770_i2c3_groups, ARRAY_SIZE(jz4770_i2c3_groups), },
+	{ "i2c4", jz4770_i2c4_groups, ARRAY_SIZE(jz4770_i2c4_groups), },
+	{ "cim", jz4770_cim_groups, ARRAY_SIZE(jz4770_cim_groups), },
+	{ "lcd", jz4770_lcd_groups, ARRAY_SIZE(jz4770_lcd_groups), },
+	{ "pwm0", jz4770_pwm0_groups, ARRAY_SIZE(jz4770_pwm0_groups), },
+	{ "pwm1", jz4770_pwm1_groups, ARRAY_SIZE(jz4770_pwm1_groups), },
+	{ "pwm2", jz4770_pwm2_groups, ARRAY_SIZE(jz4770_pwm2_groups), },
+	{ "pwm3", jz4770_pwm3_groups, ARRAY_SIZE(jz4770_pwm3_groups), },
+	{ "pwm4", jz4770_pwm4_groups, ARRAY_SIZE(jz4770_pwm4_groups), },
+	{ "pwm5", jz4770_pwm5_groups, ARRAY_SIZE(jz4770_pwm5_groups), },
+	{ "pwm6", jz4770_pwm6_groups, ARRAY_SIZE(jz4770_pwm6_groups), },
+	{ "pwm7", jz4770_pwm7_groups, ARRAY_SIZE(jz4770_pwm7_groups), },
+};
+
+static const struct ingenic_chip_info jz4770_chip_info = {
+	.num_chips = 6,
+	.groups = jz4770_groups,
+	.num_groups = ARRAY_SIZE(jz4770_groups),
+	.functions = jz4770_functions,
+	.num_functions = ARRAY_SIZE(jz4770_functions),
+	.pull_ups = jz4770_pull_ups,
+	.pull_downs = jz4770_pull_downs,
+};
+
+static inline void ingenic_config_pin(struct ingenic_pinctrl *jzpc,
+		unsigned int pin, u8 reg, bool set)
+{
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+
+	regmap_write(jzpc->map, offt * 0x100 +
+			(set ? REG_SET(reg) : REG_CLEAR(reg)), BIT(idx));
+}
+
+static inline bool ingenic_get_pin_config(struct ingenic_pinctrl *jzpc,
+		unsigned int pin, u8 reg)
+{
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+	unsigned int val;
+
+	regmap_read(jzpc->map, offt * 0x100 + reg, &val);
+
+	return val & BIT(idx);
+}
+
+static struct pinctrl_ops ingenic_pctlops = {
+	.get_groups_count = pinctrl_generic_get_group_count,
+	.get_group_name = pinctrl_generic_get_group_name,
+	.get_group_pins = pinctrl_generic_get_group_pins,
+	.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
+	.dt_free_map = pinconf_generic_dt_free_map,
+};
+
+static int ingenic_pinmux_set_pin_fn(struct ingenic_pinctrl *jzpc,
+		int pin, int func)
+{
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+
+	dev_dbg(jzpc->dev, "set pin P%c%u to function %u\n",
+			'A' + offt, idx, func);
+
+	if (jzpc->version >= ID_JZ4770) {
+		ingenic_config_pin(jzpc, pin, JZ4770_GPIO_INT, false);
+		ingenic_config_pin(jzpc, pin, JZ4770_GPIO_MSK, false);
+		ingenic_config_pin(jzpc, pin, JZ4770_GPIO_PAT1, func & 0x2);
+		ingenic_config_pin(jzpc, pin, JZ4770_GPIO_PAT0, func & 0x1);
+	} else {
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_FUNC, true);
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_TRIG, func & 0x2);
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_SELECT, func > 0);
+	}
+
+	return 0;
+}
+
+static int ingenic_pinmux_set_mux(struct pinctrl_dev *pctldev,
+		unsigned int selector, unsigned int group)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	struct function_desc *func;
+	struct group_desc *grp;
+	unsigned int i;
+
+	func = pinmux_generic_get_function(pctldev, selector);
+	if (!func)
+		return -EINVAL;
+
+	grp = pinctrl_generic_get_group(pctldev, group);
+	if (!grp)
+		return -EINVAL;
+
+	dev_dbg(pctldev->dev, "enable function %s group %s\n",
+		func->name, grp->name);
+
+	for (i = 0; i < grp->num_pins; i++) {
+		int *pin_modes = grp->data;
+
+		ingenic_pinmux_set_pin_fn(jzpc, grp->pins[i], pin_modes[i]);
+	}
+
+	return 0;
+}
+
+static int ingenic_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
+		struct pinctrl_gpio_range *range,
+		unsigned int pin, bool input)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+
+	dev_dbg(pctldev->dev, "set pin P%c%u to %sput\n",
+			'A' + offt, idx, input ? "in" : "out");
+
+	if (jzpc->version >= ID_JZ4770) {
+		ingenic_config_pin(jzpc, pin, JZ4770_GPIO_INT, false);
+		ingenic_config_pin(jzpc, pin, JZ4770_GPIO_MSK, true);
+		ingenic_config_pin(jzpc, pin, JZ4770_GPIO_PAT1, input);
+	} else {
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_SELECT, false);
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_DIR, input);
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_FUNC, false);
+	}
+
+	return 0;
+}
+
+static struct pinmux_ops ingenic_pmxops = {
+	.get_functions_count = pinmux_generic_get_function_count,
+	.get_function_name = pinmux_generic_get_function_name,
+	.get_function_groups = pinmux_generic_get_function_groups,
+	.set_mux = ingenic_pinmux_set_mux,
+	.gpio_set_direction = ingenic_pinmux_gpio_set_direction,
+};
+
+static int ingenic_pinconf_get(struct pinctrl_dev *pctldev,
+		unsigned int pin, unsigned long *config)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	enum pin_config_param param = pinconf_to_config_param(*config);
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+	bool pull;
+
+	if (jzpc->version >= ID_JZ4770)
+		pull = !ingenic_get_pin_config(jzpc, pin, JZ4770_GPIO_PEN);
+	else
+		pull = !ingenic_get_pin_config(jzpc, pin, JZ4740_GPIO_PULL_DIS);
+
+	switch (param) {
+	case PIN_CONFIG_BIAS_DISABLE:
+		if (pull)
+			return -EINVAL;
+		break;
+
+	case PIN_CONFIG_BIAS_PULL_UP:
+		if (!pull || !(jzpc->info->pull_ups[offt] & BIT(idx)))
+			return -EINVAL;
+		break;
+
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		if (!pull || !(jzpc->info->pull_downs[offt] & BIT(idx)))
+			return -EINVAL;
+		break;
+
+	default:
+		return -ENOTSUPP;
+	}
+
+	*config = pinconf_to_config_packed(param, 1);
+	return 0;
+}
+
+static void ingenic_set_bias(struct ingenic_pinctrl *jzpc,
+		unsigned int pin, bool enabled)
+{
+	if (jzpc->version >= ID_JZ4770)
+		ingenic_config_pin(jzpc, pin, JZ4770_GPIO_PEN, !enabled);
+	else
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_PULL_DIS, !enabled);
+}
+
+static int ingenic_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
+		unsigned long *configs, unsigned int num_configs)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+	unsigned int cfg;
+
+	for (cfg = 0; cfg < num_configs; cfg++) {
+		switch (pinconf_to_config_param(configs[cfg])) {
+		case PIN_CONFIG_BIAS_DISABLE:
+		case PIN_CONFIG_BIAS_PULL_UP:
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			continue;
+		default:
+			return -ENOTSUPP;
+		}
+	}
+
+	for (cfg = 0; cfg < num_configs; cfg++) {
+		switch (pinconf_to_config_param(configs[cfg])) {
+		case PIN_CONFIG_BIAS_DISABLE:
+			dev_dbg(jzpc->dev, "disable pull-over for pin P%c%u\n",
+					'A' + offt, idx);
+			ingenic_set_bias(jzpc, pin, false);
+			break;
+
+		case PIN_CONFIG_BIAS_PULL_UP:
+			if (!(jzpc->info->pull_ups[offt] & BIT(idx)))
+				return -EINVAL;
+			dev_dbg(jzpc->dev, "set pull-up for pin P%c%u\n",
+					'A' + offt, idx);
+			ingenic_set_bias(jzpc, pin, true);
+			break;
+
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			if (!(jzpc->info->pull_downs[offt] & BIT(idx)))
+				return -EINVAL;
+			dev_dbg(jzpc->dev, "set pull-down for pin P%c%u\n",
+					'A' + offt, idx);
+			ingenic_set_bias(jzpc, pin, true);
+			break;
+
+		default:
+			unreachable();
+		}
+	}
+
+	return 0;
+}
+
+static int ingenic_pinconf_group_get(struct pinctrl_dev *pctldev,
+		unsigned int group, unsigned long *config)
+{
+	const unsigned *pins;
+	unsigned int i, npins, old = 0;
+	int ret;
+
+	ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < npins; i++) {
+		if (ingenic_pinconf_get(pctldev, pins[i], config))
+			return -ENOTSUPP;
+
+		/* configs do not match between two pins */
+		if (i && (old != *config))
+			return -ENOTSUPP;
+
+		old = *config;
+	}
+
+	return 0;
+}
+
+static int ingenic_pinconf_group_set(struct pinctrl_dev *pctldev,
+		unsigned int group, unsigned long *configs,
+		unsigned int num_configs)
+{
+	const unsigned *pins;
+	unsigned int i, npins;
+	int ret;
+
+	ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < npins; i++) {
+		ret = ingenic_pinconf_set(pctldev,
+				pins[i], configs, num_configs);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static struct pinconf_ops ingenic_confops = {
+	.is_generic = true,
+	.pin_config_get = ingenic_pinconf_get,
+	.pin_config_set = ingenic_pinconf_set,
+	.pin_config_group_get = ingenic_pinconf_group_get,
+	.pin_config_group_set = ingenic_pinconf_group_set,
+};
+
+static struct mfd_cell ingenic_pinctrl_mfd_cells[] = {
+	{
+		.id = 0,
+		.name = "GPIOA",
+		.of_compatible = "ingenic,gpio-bank-a",
+	},
+	{
+		.id = 1,
+		.name = "GPIOB",
+		.of_compatible = "ingenic,gpio-bank-b",
+	},
+	{
+		.id = 2,
+		.name = "GPIOC",
+		.of_compatible = "ingenic,gpio-bank-c",
+	},
+	{
+		.id = 3,
+		.name = "GPIOD",
+		.of_compatible = "ingenic,gpio-bank-d",
+	},
+	{
+		.id = 4,
+		.name = "GPIOE",
+		.of_compatible = "ingenic,gpio-bank-e",
+	},
+	{
+		.id = 5,
+		.name = "GPIOF",
+		.of_compatible = "ingenic,gpio-bank-f",
+	},
+};
+
+static const struct regmap_config ingenic_pinctrl_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+};
+
+static const struct of_device_id ingenic_pinctrl_of_match[] = {
+	{ .compatible = "ingenic,jz4740-pinctrl", .data = (void *) ID_JZ4740 },
+	{ .compatible = "ingenic,jz4770-pinctrl", .data = (void *) ID_JZ4770 },
+	{ .compatible = "ingenic,jz4780-pinctrl", .data = (void *) ID_JZ4780 },
+	{},
+};
+
+int ingenic_pinctrl_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct ingenic_pinctrl *jzpc;
+	struct pinctrl_desc *pctl_desc;
+	void __iomem *base;
+	const struct platform_device_id *id = platform_get_device_id(pdev);
+	const struct of_device_id *of_id = of_match_device(
+			ingenic_pinctrl_of_match, dev);
+	const struct ingenic_chip_info *chip_info;
+	unsigned int i;
+	int err;
+
+	jzpc = devm_kzalloc(dev, sizeof(*jzpc), GFP_KERNEL);
+	if (!jzpc)
+		return -ENOMEM;
+
+	base = devm_ioremap_resource(dev,
+			platform_get_resource(pdev, IORESOURCE_MEM, 0));
+	if (IS_ERR(base)) {
+		dev_err(dev, "Failed to ioremap registers\n");
+		return PTR_ERR(base);
+	}
+
+	jzpc->map = devm_regmap_init_mmio(dev, base,
+			&ingenic_pinctrl_regmap_config);
+	if (IS_ERR(jzpc->map)) {
+		dev_err(dev, "Failed to create regmap\n");
+		return PTR_ERR(jzpc->map);
+	}
+
+	jzpc->dev = dev;
+
+	if (of_id)
+		jzpc->version = (enum jz_version)of_id->data;
+	else
+		jzpc->version = (enum jz_version)id->driver_data;
+
+	if (jzpc->version >= ID_JZ4770)
+		chip_info = &jz4770_chip_info;
+	else
+		chip_info = &jz4740_chip_info;
+	jzpc->info = chip_info;
+
+	pctl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctl_desc), GFP_KERNEL);
+	if (!pctl_desc)
+		return -ENOMEM;
+
+	/* fill in pinctrl_desc structure */
+	pctl_desc->name = dev_name(dev);
+	pctl_desc->owner = THIS_MODULE;
+	pctl_desc->pctlops = &ingenic_pctlops;
+	pctl_desc->pmxops = &ingenic_pmxops;
+	pctl_desc->confops = &ingenic_confops;
+	pctl_desc->npins = chip_info->num_chips * PINS_PER_GPIO_CHIP;
+	pctl_desc->pins = jzpc->pdesc = devm_kzalloc(&pdev->dev,
+			sizeof(*jzpc->pdesc) * pctl_desc->npins, GFP_KERNEL);
+	if (!jzpc->pdesc)
+		return -ENOMEM;
+
+	for (i = 0; i < pctl_desc->npins; i++) {
+		jzpc->pdesc[i].number = i;
+		jzpc->pdesc[i].name = kasprintf(GFP_KERNEL, "P%c%d",
+						'A' + (i / PINS_PER_GPIO_CHIP),
+						i % PINS_PER_GPIO_CHIP);
+	}
+
+	jzpc->pctl = devm_pinctrl_register(dev, pctl_desc, jzpc);
+	if (!jzpc->pctl) {
+		dev_err(dev, "Failed to register pinctrl\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < chip_info->num_groups; i++) {
+		const struct group_desc *group = &chip_info->groups[i];
+
+		err = pinctrl_generic_add_group(jzpc->pctl, group->name,
+				group->pins, group->num_pins, group->data);
+		if (err) {
+			dev_err(dev, "Failed to register group %s\n",
+					group->name);
+			return err;
+		}
+	}
+
+	for (i = 0; i < chip_info->num_functions; i++) {
+		const struct function_desc *func = &chip_info->functions[i];
+
+		err = pinmux_generic_add_function(jzpc->pctl, func->name,
+				func->group_names, func->num_group_names,
+				func->data);
+		if (err) {
+			dev_err(dev, "Failed to register function %s\n",
+					func->name);
+			return err;
+		}
+	}
+
+	dev_set_drvdata(dev, jzpc->map);
+
+	err = devm_mfd_add_devices(dev, 0, ingenic_pinctrl_mfd_cells,
+			ARRAY_SIZE(ingenic_pinctrl_mfd_cells), NULL, 0, NULL);
+	if (err) {
+		dev_err(dev, "Failed to add MFD devices\n");
+		return err;
+	}
+
+	return 0;
+}
+
+static const struct platform_device_id ingenic_pinctrl_ids[] = {
+	{ "jz4740-pinctrl", ID_JZ4740 },
+	{ "jz4770-pinctrl", ID_JZ4770 },
+	{ "jz4780-pinctrl", ID_JZ4780 },
+	{},
+};
+
+static struct platform_driver ingenic_pinctrl_driver = {
+	.driver = {
+		.name = "pinctrl-ingenic",
+		.of_match_table = of_match_ptr(ingenic_pinctrl_of_match),
+		.suppress_bind_attrs = true,
+	},
+	.probe = ingenic_pinctrl_probe,
+	.id_table = ingenic_pinctrl_ids,
+};
+
+static int __init ingenic_pinctrl_drv_register(void)
+{
+	return platform_driver_register(&ingenic_pinctrl_driver);
+}
+postcore_initcall(ingenic_pinctrl_drv_register);
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v4 04/14] GPIO: Add gpio-ingenic driver
  2017-04-02 20:42         ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                             ` (2 preceding siblings ...)
  2017-04-02 20:42           ` [PATCH v4 03/14] pinctrl-ingenic: add a pinctrl driver for the Ingenic jz47xx SoCs Paul Cercueil
@ 2017-04-02 20:42           ` Paul Cercueil
  2017-04-03 14:15             ` kbuild test robot
  2017-04-07  9:34             ` Linus Walleij
  2017-04-02 20:42           ` [PATCH v4 05/14] MIPS: ingenic: Enable pinctrl for all ingenic SoCs Paul Cercueil
                             ` (9 subsequent siblings)
  13 siblings, 2 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-04-02 20:42 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

This driver handles the GPIOs of all the Ingenic JZ47xx SoCs
currently supported by the upsteam Linux kernel.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/gpio/Kconfig        |  11 ++
 drivers/gpio/Makefile       |   1 +
 drivers/gpio/gpio-ingenic.c | 397 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 409 insertions(+)
 create mode 100644 drivers/gpio/gpio-ingenic.c

 v2: Consider it's a new patch. Completely rewritten from v1.
 v3: Add missing include <linux/pinctrl/consumer.h> and drop semicolon after }
 v4: Completely rewritten from v3.

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 05043071fc98..4f59128527dd 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -241,6 +241,17 @@ config GPIO_ICH
 
 	  If unsure, say N.
 
+config GPIO_INGENIC
+	tristate "Ingenic JZ47xx SoCs GPIO support"
+	depends on MACH_INGENIC || COMPILE_TEST
+	select PINCTRL_INGENIC
+	select GPIOLIB_IRQCHIP
+	help
+	  Say yes here to support the GPIO functionality present on the
+	  JZ4740 and JZ4780 SoCs from Ingenic.
+
+	  If unsure, say N.
+
 config GPIO_IOP
 	tristate "Intel IOP GPIO"
 	depends on ARCH_IOP32X || ARCH_IOP33X || COMPILE_TEST
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index becb96c724fe..3fceb4ab3ca7 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_GPIO_GPIO_MM)	+= gpio-gpio-mm.o
 obj-$(CONFIG_GPIO_GRGPIO)	+= gpio-grgpio.o
 obj-$(CONFIG_HTC_EGPIO)		+= gpio-htc-egpio.o
 obj-$(CONFIG_GPIO_ICH)		+= gpio-ich.o
+obj-$(CONFIG_GPIO_INGENIC)	+= gpio-ingenic.o
 obj-$(CONFIG_GPIO_IOP)		+= gpio-iop.o
 obj-$(CONFIG_GPIO_IT87)		+= gpio-it87.o
 obj-$(CONFIG_GPIO_JANZ_TTL)	+= gpio-janz-ttl.o
diff --git a/drivers/gpio/gpio-ingenic.c b/drivers/gpio/gpio-ingenic.c
new file mode 100644
index 000000000000..8a57e6c35733
--- /dev/null
+++ b/drivers/gpio/gpio-ingenic.c
@@ -0,0 +1,397 @@
+/*
+ * Ingenic JZ47xx GPIO driver
+ *
+ * Copyright (c) 2017 Paul Cercueil <paul@crapouillou.net>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regmap.h>
+
+#define GPIO_PIN	0x00
+#define GPIO_MSK	0x20
+
+#define JZ4740_GPIO_DATA	0x10
+#define JZ4740_GPIO_SELECT	0x50
+#define JZ4740_GPIO_DIR		0x60
+#define JZ4740_GPIO_TRIG	0x70
+#define JZ4740_GPIO_FLAG	0x80
+
+#define JZ4770_GPIO_INT		0x10
+#define JZ4770_GPIO_PAT1	0x30
+#define JZ4770_GPIO_PAT0	0x40
+#define JZ4770_GPIO_FLAG	0x50
+
+#define REG_SET(x) ((x) + 0x4)
+#define REG_CLEAR(x) ((x) + 0x8)
+
+enum jz_version {
+	ID_JZ4740,
+	ID_JZ4770,
+	ID_JZ4780,
+};
+
+struct ingenic_gpio_chip {
+	struct regmap *map;
+	struct gpio_chip gc;
+	struct irq_chip irq_chip;
+	unsigned int irq, reg_base;
+	enum jz_version version;
+};
+
+static u32 gpio_ingenic_read_reg(struct ingenic_gpio_chip *jzgc, u8 reg)
+{
+	unsigned int val;
+
+	regmap_read(jzgc->map, jzgc->reg_base + reg, &val);
+
+	return (u32) val;
+}
+
+static void gpio_ingenic_set_bit(struct ingenic_gpio_chip *jzgc,
+		u8 reg, u8 offset, bool set)
+{
+	if (set)
+		reg = REG_SET(reg);
+	else
+		reg = REG_CLEAR(reg);
+
+	regmap_write(jzgc->map, jzgc->reg_base + reg, BIT(offset));
+}
+
+static inline bool gpio_get_value(struct ingenic_gpio_chip *jzgc, u8 offset)
+{
+	unsigned int val;
+
+	if (jzgc->version >= ID_JZ4770)
+		val = gpio_ingenic_read_reg(jzgc, GPIO_PIN);
+	else
+		val = gpio_ingenic_read_reg(jzgc, JZ4740_GPIO_DATA);
+
+	return !!(val & BIT(offset));
+}
+
+static void gpio_set_value(struct ingenic_gpio_chip *jzgc, u8 offset, int value)
+{
+	if (jzgc->version >= ID_JZ4770)
+		gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_PAT0, offset, !!value);
+	else
+		gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_DATA, offset, !!value);
+}
+
+static void irq_set_type(struct ingenic_gpio_chip *jzgc,
+		u8 offset, unsigned int type)
+{
+	u8 reg1, reg2;
+
+	if (jzgc->version >= ID_JZ4770) {
+		reg1 = JZ4770_GPIO_PAT1;
+		reg2 = JZ4770_GPIO_PAT0;
+	} else {
+		reg1 = JZ4740_GPIO_TRIG;
+		reg2 = JZ4740_GPIO_DIR;
+	}
+
+	switch (type) {
+	case IRQ_TYPE_EDGE_RISING:
+		gpio_ingenic_set_bit(jzgc, reg2, offset, true);
+		gpio_ingenic_set_bit(jzgc, reg1, offset, true);
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		gpio_ingenic_set_bit(jzgc, reg2, offset, false);
+		gpio_ingenic_set_bit(jzgc, reg1, offset, true);
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		gpio_ingenic_set_bit(jzgc, reg2, offset, true);
+		gpio_ingenic_set_bit(jzgc, reg1, offset, false);
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+	default:
+		gpio_ingenic_set_bit(jzgc, reg2, offset, false);
+		gpio_ingenic_set_bit(jzgc, reg1, offset, false);
+		break;
+	}
+}
+
+static void ingenic_gpio_irq_mask(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	gpio_ingenic_set_bit(jzgc, GPIO_MSK, irqd->hwirq, true);
+}
+
+static void ingenic_gpio_irq_unmask(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	gpio_ingenic_set_bit(jzgc, GPIO_MSK, irqd->hwirq, false);
+}
+
+static void ingenic_gpio_irq_enable(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+	int irq = irqd->hwirq;
+
+	if (jzgc->version >= ID_JZ4770)
+		gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_INT, irq, true);
+	else
+		gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_SELECT, irq, true);
+
+	ingenic_gpio_irq_unmask(irqd);
+}
+
+static void ingenic_gpio_irq_disable(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+	int irq = irqd->hwirq;
+
+	ingenic_gpio_irq_mask(irqd);
+
+	if (jzgc->version >= ID_JZ4770)
+		gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_INT, irq, false);
+	else
+		gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_SELECT, irq, false);
+}
+
+static void ingenic_gpio_irq_ack(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+	int irq = irqd->hwirq;
+	bool high;
+
+	if (irqd_get_trigger_type(irqd) == IRQ_TYPE_EDGE_BOTH) {
+		/*
+		 * Switch to an interrupt for the opposite edge to the one that
+		 * triggered the interrupt being ACKed.
+		 */
+		high = gpio_get_value(jzgc, irq);
+		if (high)
+			irq_set_type(jzgc, irq, IRQ_TYPE_EDGE_FALLING);
+		else
+			irq_set_type(jzgc, irq, IRQ_TYPE_EDGE_RISING);
+	}
+
+	if (jzgc->version >= ID_JZ4770)
+		gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_FLAG, irq, false);
+	else
+		gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_DATA, irq, true);
+}
+
+static int ingenic_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	switch (type) {
+	case IRQ_TYPE_EDGE_BOTH:
+	case IRQ_TYPE_EDGE_RISING:
+	case IRQ_TYPE_EDGE_FALLING:
+		irq_set_handler_locked(irqd, handle_edge_irq);
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+	case IRQ_TYPE_LEVEL_LOW:
+		irq_set_handler_locked(irqd, handle_level_irq);
+		break;
+	default:
+		irq_set_handler_locked(irqd, handle_bad_irq);
+	}
+
+	if (type == IRQ_TYPE_EDGE_BOTH) {
+		/*
+		 * The hardware does not support interrupts on both edges. The
+		 * best we can do is to set up a single-edge interrupt and then
+		 * switch to the opposing edge when ACKing the interrupt.
+		 */
+		bool high = gpio_get_value(jzgc, irqd->hwirq);
+
+		type = high ? IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING;
+	}
+
+	irq_set_type(jzgc, irqd->hwirq, type);
+	return 0;
+}
+
+static int ingenic_gpio_irq_set_wake(struct irq_data *irqd, unsigned int on)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	return irq_set_irq_wake(jzgc->irq, on);
+}
+
+static void ingenic_gpio_irq_handler(struct irq_desc *desc)
+{
+	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+	struct irq_chip *irq_chip = irq_data_get_irq_chip(&desc->irq_data);
+	unsigned long flag, i;
+
+	chained_irq_enter(irq_chip, desc);
+
+	if (jzgc->version >= ID_JZ4770)
+		flag = gpio_ingenic_read_reg(jzgc, JZ4770_GPIO_FLAG);
+	else
+		flag = gpio_ingenic_read_reg(jzgc, JZ4740_GPIO_FLAG);
+
+	for_each_set_bit(i, &flag, 32)
+		generic_handle_irq(irq_linear_revmap(gc->irqdomain, i));
+	chained_irq_exit(irq_chip, desc);
+}
+
+static void ingenic_gpio_set(struct gpio_chip *gc,
+		unsigned int offset, int value)
+{
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	gpio_set_value(jzgc, offset, value);
+}
+
+static int ingenic_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	return (int) gpio_get_value(jzgc, offset);
+}
+
+static int ingenic_gpio_direction_input(struct gpio_chip *gc,
+		unsigned int offset)
+{
+	return pinctrl_gpio_direction_input(gc->base + offset);
+}
+
+static int ingenic_gpio_direction_output(struct gpio_chip *gc,
+		unsigned int offset, int value)
+{
+	ingenic_gpio_set(gc, offset, value);
+	return pinctrl_gpio_direction_output(gc->base + offset);
+}
+
+static const struct of_device_id ingenic_gpio_of_match[] = {
+	{ .compatible = "ingenic,jz4740-gpio", .data = (void *)ID_JZ4740 },
+	{ .compatible = "ingenic,jz4770-gpio", .data = (void *)ID_JZ4770 },
+	{ .compatible = "ingenic,jz4780-gpio", .data = (void *)ID_JZ4780 },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ingenic_gpio_of_match);
+
+static int ingenic_gpio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	const struct of_device_id *of_id = of_match_device(
+			ingenic_gpio_of_match, dev);
+	struct ingenic_gpio_chip *jzgc;
+	const struct mfd_cell *cell;
+	int err;
+
+	jzgc = devm_kzalloc(dev, sizeof(*jzgc), GFP_KERNEL);
+	if (!jzgc)
+		return -ENOMEM;
+
+	jzgc->map = dev_get_drvdata(dev->parent);
+	if (!jzgc->map) {
+		dev_err(dev, "Cannot get parent regmap\n");
+		return -ENXIO;
+	}
+
+	cell = mfd_get_cell(pdev);
+	if (!cell) {
+		dev_err(dev, "Cannot get mfd cell\n");
+		return -ENXIO;
+	}
+
+	jzgc->reg_base = cell->id * 0x100;
+
+	/* DO NOT EXPAND THIS: FOR BACKWARD GPIO NUMBERSPACE COMPATIBIBILITY
+	 * ONLY: WORK TO TRANSITION CONSUMERS TO USE THE GPIO DESCRIPTOR API IN
+	 * <linux/gpio/consumer.h> INSTEAD.
+	 */
+	jzgc->gc.base = cell->id * 32;
+
+	jzgc->gc.ngpio = 32;
+	jzgc->gc.parent = dev;
+	jzgc->gc.of_node = dev->of_node;
+	jzgc->gc.label = cell->name;
+	jzgc->gc.owner = THIS_MODULE;
+	jzgc->version = (enum jz_version)of_id->data;
+
+	jzgc->gc.set = ingenic_gpio_set;
+	jzgc->gc.get = ingenic_gpio_get;
+	jzgc->gc.direction_input = ingenic_gpio_direction_input;
+	jzgc->gc.direction_output = ingenic_gpio_direction_output;
+
+	if (of_property_read_bool(dev->of_node, "gpio-ranges")) {
+		jzgc->gc.request = gpiochip_generic_request;
+		jzgc->gc.free = gpiochip_generic_free;
+	}
+
+	err = devm_gpiochip_add_data(dev, &jzgc->gc, jzgc);
+	if (err)
+		return err;
+
+	jzgc->irq = irq_of_parse_and_map(dev->of_node, 0);
+	if (!jzgc->irq)
+		return -EINVAL;
+
+	jzgc->irq_chip.name = cell->name;
+	jzgc->irq_chip.irq_enable = ingenic_gpio_irq_enable;
+	jzgc->irq_chip.irq_disable = ingenic_gpio_irq_disable;
+	jzgc->irq_chip.irq_unmask = ingenic_gpio_irq_unmask;
+	jzgc->irq_chip.irq_mask = ingenic_gpio_irq_mask;
+	jzgc->irq_chip.irq_ack = ingenic_gpio_irq_ack;
+	jzgc->irq_chip.irq_set_type = ingenic_gpio_irq_set_type;
+	jzgc->irq_chip.irq_set_wake = ingenic_gpio_irq_set_wake;
+	jzgc->irq_chip.flags = IRQCHIP_MASK_ON_SUSPEND;
+
+	err = gpiochip_irqchip_add(&jzgc->gc, &jzgc->irq_chip, 0,
+			handle_level_irq, IRQ_TYPE_NONE);
+	if (err)
+		return err;
+
+	gpiochip_set_chained_irqchip(&jzgc->gc, &jzgc->irq_chip,
+			jzgc->irq, ingenic_gpio_irq_handler);
+	return 0;
+}
+
+static int ingenic_gpio_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver ingenic_gpio_driver = {
+	.driver = {
+		.name = "gpio-ingenic",
+		.of_match_table = of_match_ptr(ingenic_gpio_of_match),
+	},
+	.probe = ingenic_gpio_probe,
+	.remove = ingenic_gpio_remove,
+};
+
+static int __init ingenic_gpio_drv_register(void)
+{
+	return platform_driver_register(&ingenic_gpio_driver);
+}
+subsys_initcall(ingenic_gpio_drv_register);
+
+static void __exit ingenic_gpio_drv_unregister(void)
+{
+	platform_driver_unregister(&ingenic_gpio_driver);
+}
+module_exit(ingenic_gpio_drv_unregister);
+
+MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
+MODULE_DESCRIPTION("Ingenic JZ47xx GPIO driver");
+MODULE_LICENSE("GPL");
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v4 05/14] MIPS: ingenic: Enable pinctrl for all ingenic SoCs
  2017-04-02 20:42         ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                             ` (3 preceding siblings ...)
  2017-04-02 20:42           ` [PATCH v4 04/14] GPIO: Add gpio-ingenic driver Paul Cercueil
@ 2017-04-02 20:42           ` Paul Cercueil
  2017-04-02 20:42           ` [PATCH v4 06/14] MIPS: jz4740: DTS: Add nodes for ingenic pinctrl and gpio drivers Paul Cercueil
                             ` (8 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-04-02 20:42 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

There is a pinctrl driver for each of the Ingenic SoCs supported by the
upstream Linux kernel. In order to switch away from the old GPIO
platform code, we now enable the pinctrl drivers by default for the
Ingenic SoCs.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/Kconfig | 1 +
 1 file changed, 1 insertion(+)

 v2: No changes
 v3: No changes
 v4: No changes

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index a008a9f03072..b88cf931b829 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -363,6 +363,7 @@ config MACH_INGENIC
 	select SYS_SUPPORTS_ZBOOT_UART16550
 	select DMA_NONCOHERENT
 	select IRQ_MIPS_CPU
+	select PINCTRL
 	select GPIOLIB
 	select COMMON_CLK
 	select GENERIC_IRQ_CHIP
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v4 06/14] MIPS: jz4740: DTS: Add nodes for ingenic pinctrl and gpio drivers
  2017-04-02 20:42         ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                             ` (4 preceding siblings ...)
  2017-04-02 20:42           ` [PATCH v4 05/14] MIPS: ingenic: Enable pinctrl for all ingenic SoCs Paul Cercueil
@ 2017-04-02 20:42           ` Paul Cercueil
  2017-04-03  9:57             ` Sergei Shtylyov
  2017-04-07  9:44             ` Linus Walleij
  2017-04-02 20:42           ` [PATCH v4 07/14] MIPS: jz4780: " Paul Cercueil
                             ` (7 subsequent siblings)
  13 siblings, 2 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-04-02 20:42 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

For a description of the pinctrl devicetree node, please read
Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt

For a description of the gpio devicetree nodes, please read
Documentation/devicetree/bindings/gpio/ingenic,gpio.txt

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/boot/dts/ingenic/jz4740.dtsi | 61 ++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)

 v2: Changed the devicetree bindings to match the new driver
 v3: No changes
 v4: Update the bindings for the v4 version of the drivers

diff --git a/arch/mips/boot/dts/ingenic/jz4740.dtsi b/arch/mips/boot/dts/ingenic/jz4740.dtsi
index 3e1587f1f77a..9c23c877fc34 100644
--- a/arch/mips/boot/dts/ingenic/jz4740.dtsi
+++ b/arch/mips/boot/dts/ingenic/jz4740.dtsi
@@ -55,6 +55,67 @@
 		clock-names = "rtc";
 	};
 
+	pinctrl: ingenic-pinctrl@10010000 {
+		compatible = "ingenic,jz4740-pinctrl";
+		reg = <0x10010000 0x400>;
+
+		gpa: gpio-controller@0 {
+			compatible = "ingenic,gpio-bank-a", "ingenic,jz4740-gpio";
+
+			gpio-controller;
+			gpio-ranges = <&pinctrl 0 0 32>;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+
+			interrupt-parent = <&intc>;
+			interrupts = <28>;
+		};
+
+		gpb: gpio-controller@1 {
+			compatible = "ingenic,gpio-bank-b", "ingenic,jz4740-gpio";
+
+			gpio-controller;
+			gpio-ranges = <&pinctrl 0 32 32>;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+
+			interrupt-parent = <&intc>;
+			interrupts = <27>;
+		};
+
+		gpc: gpio-controller@2 {
+			compatible = "ingenic,gpio-bank-c", "ingenic,jz4740-gpio";
+
+			gpio-controller;
+			gpio-ranges = <&pinctrl 0 64 32>;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+
+			interrupt-parent = <&intc>;
+			interrupts = <26>;
+		};
+
+		gpd: gpio-controller@3 {
+			compatible = "ingenic,gpio-bank-d", "ingenic,jz4740-gpio";
+
+			gpio-controller;
+			gpio-ranges = <&pinctrl 0 96 32>;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+
+			interrupt-parent = <&intc>;
+			interrupts = <25>;
+		};
+	};
+
 	uart0: serial@10030000 {
 		compatible = "ingenic,jz4740-uart";
 		reg = <0x10030000 0x100>;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v4 07/14] MIPS: jz4780: DTS: Add nodes for ingenic pinctrl and gpio drivers
  2017-04-02 20:42         ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                             ` (5 preceding siblings ...)
  2017-04-02 20:42           ` [PATCH v4 06/14] MIPS: jz4740: DTS: Add nodes for ingenic pinctrl and gpio drivers Paul Cercueil
@ 2017-04-02 20:42           ` Paul Cercueil
  2017-04-02 20:42           ` [PATCH v4 08/14] MIPS: JZ4740: Qi LB60: Add pinctrl configuration for several drivers Paul Cercueil
                             ` (6 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-04-02 20:42 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

For a description of the devicetree node, please read
Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt

For a description of the gpio devicetree nodes, please read
Documentation/devicetree/bindings/gpio/ingenic,gpio.txt

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/boot/dts/ingenic/jz4780.dtsi | 89 ++++++++++++++++++++++++++++++++++
 1 file changed, 89 insertions(+)

 v2: Changed the devicetree bindings to match the new driver
 v3: No changes
 v4: Update the bindings for the v4 version of the drivers

diff --git a/arch/mips/boot/dts/ingenic/jz4780.dtsi b/arch/mips/boot/dts/ingenic/jz4780.dtsi
index b868b429add2..f90199a7925d 100644
--- a/arch/mips/boot/dts/ingenic/jz4780.dtsi
+++ b/arch/mips/boot/dts/ingenic/jz4780.dtsi
@@ -44,6 +44,95 @@
 		#clock-cells = <1>;
 	};
 
+	pinctrl: ingenic-pinctrl@10010000 {
+		compatible = "ingenic,jz4780-pinctrl";
+		reg = <0x10010000 0x600>;
+
+		gpa: gpio-controller@0 {
+			compatible = "ingenic,gpio-bank-a", "ingenic,jz4780-gpio";
+
+			gpio-controller;
+			gpio-ranges = <&pinctrl 0 0 32>;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+
+			interrupt-parent = <&intc>;
+			interrupts = <17>;
+		};
+
+		gpb: gpio-controller@1 {
+			compatible = "ingenic,gpio-bank-b", "ingenic,jz4780-gpio";
+
+			gpio-controller;
+			gpio-ranges = <&pinctrl 0 32 32>;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+
+			interrupt-parent = <&intc>;
+			interrupts = <16>;
+		};
+
+		gpc: gpio-controller@2 {
+			compatible = "ingenic,gpio-bank-c", "ingenic,jz4780-gpio";
+
+			gpio-controller;
+			gpio-ranges = <&pinctrl 0 64 32>;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+
+			interrupt-parent = <&intc>;
+			interrupts = <15>;
+		};
+
+		gpd: gpio-controller@3 {
+			compatible = "ingenic,gpio-bank-d", "ingenic,jz4780-gpio";
+
+			gpio-controller;
+			gpio-ranges = <&pinctrl 0 96 32>;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+
+			interrupt-parent = <&intc>;
+			interrupts = <14>;
+		};
+
+		gpe: gpio-controller@4 {
+			compatible = "ingenic,gpio-bank-e", "ingenic,jz4780-gpio";
+
+			gpio-controller;
+			gpio-ranges = <&pinctrl 0 128 32>;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+
+			interrupt-parent = <&intc>;
+			interrupts = <13>;
+		};
+
+		gpf: gpio-controller@5 {
+			compatible = "ingenic,gpio-bank-f", "ingenic,jz4780-gpio";
+
+			gpio-controller;
+			gpio-ranges = <&pinctrl 0 160 32>;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+
+			interrupt-parent = <&intc>;
+			interrupts = <12>;
+		};
+	};
+
 	uart0: serial@10030000 {
 		compatible = "ingenic,jz4780-uart";
 		reg = <0x10030000 0x100>;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v4 08/14] MIPS: JZ4740: Qi LB60: Add pinctrl configuration for several drivers
  2017-04-02 20:42         ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                             ` (6 preceding siblings ...)
  2017-04-02 20:42           ` [PATCH v4 07/14] MIPS: jz4780: " Paul Cercueil
@ 2017-04-02 20:42           ` Paul Cercueil
  2017-04-02 20:42           ` [PATCH v4 09/14] MIPS: JZ4780: CI20: " Paul Cercueil
                             ` (5 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-04-02 20:42 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

We set the pin configuration for the jz4740-nand, jz4740-mmc,
jz4740-fb, jz4740-pwm and jz4740-uart drivers.

This will permit those drivers to be cleaned out of the custom GPIO code
that they currently use.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/boot/dts/ingenic/qi_lb60.dts | 13 +++++++++++
 arch/mips/jz4740/board-qi_lb60.c       | 42 ++++++++++++++++++++++++++--------
 2 files changed, 46 insertions(+), 9 deletions(-)

 v2: Changed the devicetree bindings to match the new driver
 v3: No changes
 v4: No changes

diff --git a/arch/mips/boot/dts/ingenic/qi_lb60.dts b/arch/mips/boot/dts/ingenic/qi_lb60.dts
index be1a7d3a3e1b..b715ee2ac2ee 100644
--- a/arch/mips/boot/dts/ingenic/qi_lb60.dts
+++ b/arch/mips/boot/dts/ingenic/qi_lb60.dts
@@ -17,3 +17,16 @@
 &rtc_dev {
 	system-power-controller;
 };
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart0>;
+};
+
+&pinctrl {
+	pins_uart0: uart0 {
+		function = "uart0";
+		groups = "uart0-data";
+		bias-disable;
+	};
+};
diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c
index a5bd94b95263..bf3dcc9ee9f8 100644
--- a/arch/mips/jz4740/board-qi_lb60.c
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -22,6 +22,8 @@
 #include <linux/input/matrix_keypad.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_gpio.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf-generic.h>
 #include <linux/power_supply.h>
 #include <linux/power/jz4740-battery.h>
 #include <linux/power/gpio-charger.h>
@@ -447,13 +449,36 @@ static struct platform_device *jz_platform_devices[] __initdata = {
 	&qi_lb60_audio_device,
 };
 
-static void __init board_gpio_setup(void)
-{
-	/* We only need to enable/disable pullup here for pins used in generic
-	 * drivers. Everything else is done by the drivers themselves. */
-	jz_gpio_disable_pullup(QI_LB60_GPIO_SD_VCC_EN_N);
-	jz_gpio_disable_pullup(QI_LB60_GPIO_SD_CD);
-}
+static unsigned long pin_cfg_bias_disable[] = {
+	    PIN_CONFIG_BIAS_DISABLE,
+};
+
+static struct pinctrl_map pin_map[] __initdata = {
+	/* NAND pin configuration */
+	PIN_MAP_MUX_GROUP_DEFAULT("jz4740-nand",
+			"10010000.jz4740-pinctrl", "nand", "nand"),
+
+	/* fbdev pin configuration */
+	PIN_MAP_MUX_GROUP("jz4740-fb", PINCTRL_STATE_DEFAULT,
+			"10010000.jz4740-pinctrl", "lcd", "lcd-8bit"),
+	PIN_MAP_MUX_GROUP("jz4740-fb", PINCTRL_STATE_SLEEP,
+			"10010000.jz4740-pinctrl", "lcd", "lcd-no-pins"),
+
+	/* MMC pin configuration */
+	PIN_MAP_MUX_GROUP_DEFAULT("jz4740-mmc.0",
+			"10010000.jz4740-pinctrl", "mmc", "mmc-1bit"),
+	PIN_MAP_MUX_GROUP_DEFAULT("jz4740-mmc.0",
+			"10010000.jz4740-pinctrl", "mmc", "mmc-4bit"),
+	PIN_MAP_CONFIGS_PIN_DEFAULT("jz4740-mmc.0",
+			"10010000.jz4740-pinctrl", "PD0", pin_cfg_bias_disable),
+	PIN_MAP_CONFIGS_PIN_DEFAULT("jz4740-mmc.0",
+			"10010000.jz4740-pinctrl", "PD2", pin_cfg_bias_disable),
+
+	/* PWM pin configuration */
+	PIN_MAP_MUX_GROUP_DEFAULT("jz4740-pwm",
+			"10010000.jz4740-pinctrl", "pwm4", "pwm4"),
+};
+
 
 static int __init qi_lb60_init_platform_devices(void)
 {
@@ -469,6 +494,7 @@ static int __init qi_lb60_init_platform_devices(void)
 				ARRAY_SIZE(qi_lb60_spi_board_info));
 
 	pwm_add_table(qi_lb60_pwm_lookup, ARRAY_SIZE(qi_lb60_pwm_lookup));
+	pinctrl_register_mappings(pin_map, ARRAY_SIZE(pin_map));
 
 	return platform_add_devices(jz_platform_devices,
 					ARRAY_SIZE(jz_platform_devices));
@@ -479,8 +505,6 @@ static int __init qi_lb60_board_setup(void)
 {
 	printk(KERN_INFO "Qi Hardware JZ4740 QI LB60 setup\n");
 
-	board_gpio_setup();
-
 	if (qi_lb60_init_platform_devices())
 		panic("Failed to initialize platform devices");
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v4 09/14] MIPS: JZ4780: CI20: Add pinctrl configuration for several drivers
  2017-04-02 20:42         ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                             ` (7 preceding siblings ...)
  2017-04-02 20:42           ` [PATCH v4 08/14] MIPS: JZ4740: Qi LB60: Add pinctrl configuration for several drivers Paul Cercueil
@ 2017-04-02 20:42           ` Paul Cercueil
  2017-04-02 20:42           ` [PATCH v4 10/14] mmc: jz4740: Let the pinctrl driver configure the pins Paul Cercueil
                             ` (4 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-04-02 20:42 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

We set the pin configuration for the jz4780-nand and jz4780-uart
drivers.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/boot/dts/ingenic/ci20.dts | 60 +++++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

 v2: Changed the devicetree bindings to match the new driver
 v3: No changes
 v4: No changes

diff --git a/arch/mips/boot/dts/ingenic/ci20.dts b/arch/mips/boot/dts/ingenic/ci20.dts
index 1652d8d60b1e..fd138d9978c1 100644
--- a/arch/mips/boot/dts/ingenic/ci20.dts
+++ b/arch/mips/boot/dts/ingenic/ci20.dts
@@ -29,18 +29,30 @@
 
 &uart0 {
 	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart0>;
 };
 
 &uart1 {
 	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart1>;
 };
 
 &uart3 {
 	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart2>;
 };
 
 &uart4 {
 	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart4>;
 };
 
 &nemc {
@@ -61,6 +73,13 @@
 		ingenic,nemc-tAW = <15>;
 		ingenic,nemc-tSTRV = <100>;
 
+		/*
+		 * Only CLE/ALE are needed for the devices that are connected, rather
+		 * than the full address line set.
+		 */
+		pinctrl-names = "default";
+		pinctrl-0 = <&pins_nemc>;
+
 		nand@1 {
 			reg = <1>;
 
@@ -69,6 +88,9 @@
 			nand-ecc-mode = "hw";
 			nand-on-flash-bbt;
 
+			pinctrl-names = "default";
+			pinctrl-0 = <&pins_nemc_cs1>;
+
 			partitions {
 				compatible = "fixed-partitions";
 				#address-cells = <2>;
@@ -106,3 +128,41 @@
 &bch {
 	status = "okay";
 };
+
+&pinctrl {
+	pins_uart0: uart0 {
+		function = "uart0";
+		groups = "uart0-data";
+		bias-disable;
+	};
+
+	pins_uart1: uart1 {
+		function = "uart1";
+		groups = "uart1-data";
+		bias-disable;
+	};
+
+	pins_uart2: uart2 {
+		function = "uart2";
+		groups = "uart2-data", "uart2-hwflow";
+		bias-disable;
+	};
+
+	pins_uart4: uart4 {
+		function = "uart4";
+		groups = "uart4-data";
+		bias-disable;
+	};
+
+	pins_nemc: nemc {
+		function = "nemc";
+		groups = "nemc-data", "nemc-cle-ale", "nemc-rd-we", "nemc-frd-fwe";
+		bias-disable;
+	};
+
+	pins_nemc_cs1: nemc-cs1 {
+		function = "nemc-cs1";
+		groups = "nemc-cs1";
+		bias-disable;
+	};
+};
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v4 10/14] mmc: jz4740: Let the pinctrl driver configure the pins
  2017-04-02 20:42         ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                             ` (8 preceding siblings ...)
  2017-04-02 20:42           ` [PATCH v4 09/14] MIPS: JZ4780: CI20: " Paul Cercueil
@ 2017-04-02 20:42           ` Paul Cercueil
  2017-04-02 20:42           ` [PATCH v4 11/14] mtd: nand: " Paul Cercueil
                             ` (3 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-04-02 20:42 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
the pins being properly configured before the driver probes.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/host/jz4740_mmc.c | 44 +++++--------------------------------------
 1 file changed, 5 insertions(+), 39 deletions(-)

 v2: Set pin sleep/default state in suspend/resume callbacks
 v3: No changes
 v4: Re-insert accidentally removed <linux/gpio.h> include

diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c
index 819ad32964fc..42b3ee566dc7 100644
--- a/drivers/mmc/host/jz4740_mmc.c
+++ b/drivers/mmc/host/jz4740_mmc.c
@@ -20,6 +20,7 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/scatterlist.h>
@@ -27,7 +28,6 @@
 
 #include <linux/bitops.h>
 #include <linux/gpio.h>
-#include <asm/mach-jz4740/gpio.h>
 #include <asm/cacheflush.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
@@ -906,15 +906,6 @@ static const struct mmc_host_ops jz4740_mmc_ops = {
 	.enable_sdio_irq = jz4740_mmc_enable_sdio_irq,
 };
 
-static const struct jz_gpio_bulk_request jz4740_mmc_pins[] = {
-	JZ_GPIO_BULK_PIN(MSC_CMD),
-	JZ_GPIO_BULK_PIN(MSC_CLK),
-	JZ_GPIO_BULK_PIN(MSC_DATA0),
-	JZ_GPIO_BULK_PIN(MSC_DATA1),
-	JZ_GPIO_BULK_PIN(MSC_DATA2),
-	JZ_GPIO_BULK_PIN(MSC_DATA3),
-};
-
 static int jz4740_mmc_request_gpio(struct device *dev, int gpio,
 	const char *name, bool output, int value)
 {
@@ -978,15 +969,6 @@ static void jz4740_mmc_free_gpios(struct platform_device *pdev)
 		gpio_free(pdata->gpio_power);
 }
 
-static inline size_t jz4740_mmc_num_pins(struct jz4740_mmc_host *host)
-{
-	size_t num_pins = ARRAY_SIZE(jz4740_mmc_pins);
-	if (host->pdata && host->pdata->data_1bit)
-		num_pins -= 3;
-
-	return num_pins;
-}
-
 static int jz4740_mmc_probe(struct platform_device* pdev)
 {
 	int ret;
@@ -1027,15 +1009,9 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
 		goto err_free_host;
 	}
 
-	ret = jz_gpio_bulk_request(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
-	if (ret) {
-		dev_err(&pdev->dev, "Failed to request mmc pins: %d\n", ret);
-		goto err_free_host;
-	}
-
 	ret = jz4740_mmc_request_gpios(mmc, pdev);
 	if (ret)
-		goto err_gpio_bulk_free;
+		goto err_release_dma;
 
 	mmc->ops = &jz4740_mmc_ops;
 	mmc->f_min = JZ_MMC_CLK_RATE / 128;
@@ -1091,10 +1067,9 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
 	free_irq(host->irq, host);
 err_free_gpios:
 	jz4740_mmc_free_gpios(pdev);
-err_gpio_bulk_free:
+err_release_dma:
 	if (host->use_dma)
 		jz4740_mmc_release_dma_channels(host);
-	jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
 err_free_host:
 	mmc_free_host(mmc);
 
@@ -1114,7 +1089,6 @@ static int jz4740_mmc_remove(struct platform_device *pdev)
 	free_irq(host->irq, host);
 
 	jz4740_mmc_free_gpios(pdev);
-	jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
 
 	if (host->use_dma)
 		jz4740_mmc_release_dma_channels(host);
@@ -1128,20 +1102,12 @@ static int jz4740_mmc_remove(struct platform_device *pdev)
 
 static int jz4740_mmc_suspend(struct device *dev)
 {
-	struct jz4740_mmc_host *host = dev_get_drvdata(dev);
-
-	jz_gpio_bulk_suspend(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
-
-	return 0;
+	return pinctrl_pm_select_sleep_state(dev);
 }
 
 static int jz4740_mmc_resume(struct device *dev)
 {
-	struct jz4740_mmc_host *host = dev_get_drvdata(dev);
-
-	jz_gpio_bulk_resume(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
-
-	return 0;
+	return pinctrl_pm_select_default_state(dev);
 }
 
 static SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend,
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v4 11/14] mtd: nand: jz4740: Let the pinctrl driver configure the pins
  2017-04-02 20:42         ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                             ` (9 preceding siblings ...)
  2017-04-02 20:42           ` [PATCH v4 10/14] mmc: jz4740: Let the pinctrl driver configure the pins Paul Cercueil
@ 2017-04-02 20:42           ` Paul Cercueil
  2017-04-02 20:42           ` [PATCH v4 12/14] fbdev: jz4740-fb: " Paul Cercueil
                             ` (2 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-04-02 20:42 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

Before, this NAND driver would set itself the configuration of the
chip-select pins for the various NAND banks.

Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
the pins being properly configured before the driver probes.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/mtd/nand/jz4740_nand.c | 23 +----------------------
 1 file changed, 1 insertion(+), 22 deletions(-)

 v2: No changes
 v3: No changes
 v4: No changes

diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
index 5551c36adbdf..0d06a1f07d82 100644
--- a/drivers/mtd/nand/jz4740_nand.c
+++ b/drivers/mtd/nand/jz4740_nand.c
@@ -25,7 +25,6 @@
 
 #include <linux/gpio.h>
 
-#include <asm/mach-jz4740/gpio.h>
 #include <asm/mach-jz4740/jz4740_nand.h>
 
 #define JZ_REG_NAND_CTRL	0x50
@@ -310,34 +309,20 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
 			       uint8_t *nand_dev_id)
 {
 	int ret;
-	int gpio;
-	char gpio_name[9];
 	char res_name[6];
 	uint32_t ctrl;
 	struct nand_chip *chip = &nand->chip;
 	struct mtd_info *mtd = nand_to_mtd(chip);
 
-	/* Request GPIO port. */
-	gpio = JZ_GPIO_MEM_CS0 + bank - 1;
-	sprintf(gpio_name, "NAND CS%d", bank);
-	ret = gpio_request(gpio, gpio_name);
-	if (ret) {
-		dev_warn(&pdev->dev,
-			"Failed to request %s gpio %d: %d\n",
-			gpio_name, gpio, ret);
-		goto notfound_gpio;
-	}
-
 	/* Request I/O resource. */
 	sprintf(res_name, "bank%d", bank);
 	ret = jz_nand_ioremap_resource(pdev, res_name,
 					&nand->bank_mem[bank - 1],
 					&nand->bank_base[bank - 1]);
 	if (ret)
-		goto notfound_resource;
+		return ret;
 
 	/* Enable chip in bank. */
-	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_MEM_CS0);
 	ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
 	ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1);
 	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
@@ -377,12 +362,8 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
 	dev_info(&pdev->dev, "No chip found on bank %i\n", bank);
 	ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1));
 	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
-	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE);
 	jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
 				 nand->bank_base[bank - 1]);
-notfound_resource:
-	gpio_free(gpio);
-notfound_gpio:
 	return ret;
 }
 
@@ -503,7 +484,6 @@ static int jz_nand_probe(struct platform_device *pdev)
 err_unclaim_banks:
 	while (chipnr--) {
 		unsigned char bank = nand->banks[chipnr];
-		gpio_free(JZ_GPIO_MEM_CS0 + bank - 1);
 		jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
 					 nand->bank_base[bank - 1]);
 	}
@@ -530,7 +510,6 @@ static int jz_nand_remove(struct platform_device *pdev)
 		if (bank != 0) {
 			jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
 						 nand->bank_base[bank - 1]);
-			gpio_free(JZ_GPIO_MEM_CS0 + bank - 1);
 		}
 	}
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v4 12/14] fbdev: jz4740-fb: Let the pinctrl driver configure the pins
  2017-04-02 20:42         ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                             ` (10 preceding siblings ...)
  2017-04-02 20:42           ` [PATCH v4 11/14] mtd: nand: " Paul Cercueil
@ 2017-04-02 20:42           ` Paul Cercueil
  2017-04-02 20:42           ` [PATCH v4 13/14] pwm: jz4740: " Paul Cercueil
  2017-04-02 20:42           ` [PATCH v4 14/14] MIPS: jz4740: Remove custom GPIO code Paul Cercueil
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-04-02 20:42 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
the pins being properly configured before the driver probes.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Acked-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
---
 drivers/video/fbdev/jz4740_fb.c | 104 ++--------------------------------------
 1 file changed, 3 insertions(+), 101 deletions(-)

 v2: No changes
 v3: No changes
 v4: No changes

diff --git a/drivers/video/fbdev/jz4740_fb.c b/drivers/video/fbdev/jz4740_fb.c
index 87790e9644d0..b57df83fdbd3 100644
--- a/drivers/video/fbdev/jz4740_fb.c
+++ b/drivers/video/fbdev/jz4740_fb.c
@@ -17,6 +17,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
 
 #include <linux/clk.h>
 #include <linux/delay.h>
@@ -27,7 +28,6 @@
 #include <linux/dma-mapping.h>
 
 #include <asm/mach-jz4740/jz4740_fb.h>
-#include <asm/mach-jz4740/gpio.h>
 
 #define JZ_REG_LCD_CFG		0x00
 #define JZ_REG_LCD_VSYNC	0x04
@@ -146,93 +146,6 @@ static const struct fb_fix_screeninfo jzfb_fix = {
 	.accel		= FB_ACCEL_NONE,
 };
 
-static const struct jz_gpio_bulk_request jz_lcd_ctrl_pins[] = {
-	JZ_GPIO_BULK_PIN(LCD_PCLK),
-	JZ_GPIO_BULK_PIN(LCD_HSYNC),
-	JZ_GPIO_BULK_PIN(LCD_VSYNC),
-	JZ_GPIO_BULK_PIN(LCD_DE),
-	JZ_GPIO_BULK_PIN(LCD_PS),
-	JZ_GPIO_BULK_PIN(LCD_REV),
-	JZ_GPIO_BULK_PIN(LCD_CLS),
-	JZ_GPIO_BULK_PIN(LCD_SPL),
-};
-
-static const struct jz_gpio_bulk_request jz_lcd_data_pins[] = {
-	JZ_GPIO_BULK_PIN(LCD_DATA0),
-	JZ_GPIO_BULK_PIN(LCD_DATA1),
-	JZ_GPIO_BULK_PIN(LCD_DATA2),
-	JZ_GPIO_BULK_PIN(LCD_DATA3),
-	JZ_GPIO_BULK_PIN(LCD_DATA4),
-	JZ_GPIO_BULK_PIN(LCD_DATA5),
-	JZ_GPIO_BULK_PIN(LCD_DATA6),
-	JZ_GPIO_BULK_PIN(LCD_DATA7),
-	JZ_GPIO_BULK_PIN(LCD_DATA8),
-	JZ_GPIO_BULK_PIN(LCD_DATA9),
-	JZ_GPIO_BULK_PIN(LCD_DATA10),
-	JZ_GPIO_BULK_PIN(LCD_DATA11),
-	JZ_GPIO_BULK_PIN(LCD_DATA12),
-	JZ_GPIO_BULK_PIN(LCD_DATA13),
-	JZ_GPIO_BULK_PIN(LCD_DATA14),
-	JZ_GPIO_BULK_PIN(LCD_DATA15),
-	JZ_GPIO_BULK_PIN(LCD_DATA16),
-	JZ_GPIO_BULK_PIN(LCD_DATA17),
-};
-
-static unsigned int jzfb_num_ctrl_pins(struct jzfb *jzfb)
-{
-	unsigned int num;
-
-	switch (jzfb->pdata->lcd_type) {
-	case JZ_LCD_TYPE_GENERIC_16_BIT:
-		num = 4;
-		break;
-	case JZ_LCD_TYPE_GENERIC_18_BIT:
-		num = 4;
-		break;
-	case JZ_LCD_TYPE_8BIT_SERIAL:
-		num = 3;
-		break;
-	case JZ_LCD_TYPE_SPECIAL_TFT_1:
-	case JZ_LCD_TYPE_SPECIAL_TFT_2:
-	case JZ_LCD_TYPE_SPECIAL_TFT_3:
-		num = 8;
-		break;
-	default:
-		num = 0;
-		break;
-	}
-	return num;
-}
-
-static unsigned int jzfb_num_data_pins(struct jzfb *jzfb)
-{
-	unsigned int num;
-
-	switch (jzfb->pdata->lcd_type) {
-	case JZ_LCD_TYPE_GENERIC_16_BIT:
-		num = 16;
-		break;
-	case JZ_LCD_TYPE_GENERIC_18_BIT:
-		num = 18;
-		break;
-	case JZ_LCD_TYPE_8BIT_SERIAL:
-		num = 8;
-		break;
-	case JZ_LCD_TYPE_SPECIAL_TFT_1:
-	case JZ_LCD_TYPE_SPECIAL_TFT_2:
-	case JZ_LCD_TYPE_SPECIAL_TFT_3:
-		if (jzfb->pdata->bpp == 18)
-			num = 18;
-		else
-			num = 16;
-		break;
-	default:
-		num = 0;
-		break;
-	}
-	return num;
-}
-
 /* Based on CNVT_TOHW macro from skeletonfb.c */
 static inline uint32_t jzfb_convert_color_to_hw(unsigned val,
 	struct fb_bitfield *bf)
@@ -487,8 +400,7 @@ static void jzfb_enable(struct jzfb *jzfb)
 
 	clk_prepare_enable(jzfb->ldclk);
 
-	jz_gpio_bulk_resume(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_resume(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
+	pinctrl_pm_select_default_state(&jzfb->pdev->dev);
 
 	writel(0, jzfb->base + JZ_REG_LCD_STATE);
 
@@ -511,8 +423,7 @@ static void jzfb_disable(struct jzfb *jzfb)
 		ctrl = readl(jzfb->base + JZ_REG_LCD_STATE);
 	} while (!(ctrl & JZ_LCD_STATE_DISABLED));
 
-	jz_gpio_bulk_suspend(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_suspend(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
+	pinctrl_pm_select_sleep_state(&jzfb->pdev->dev);
 
 	clk_disable_unprepare(jzfb->ldclk);
 }
@@ -701,9 +612,6 @@ static int jzfb_probe(struct platform_device *pdev)
 	fb->mode = NULL;
 	jzfb_set_par(fb);
 
-	jz_gpio_bulk_request(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_request(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
-
 	ret = register_framebuffer(fb);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to register framebuffer: %d\n", ret);
@@ -715,9 +623,6 @@ static int jzfb_probe(struct platform_device *pdev)
 	return 0;
 
 err_free_devmem:
-	jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
-
 	fb_dealloc_cmap(&fb->cmap);
 	jzfb_free_devmem(jzfb);
 err_framebuffer_release:
@@ -731,9 +636,6 @@ static int jzfb_remove(struct platform_device *pdev)
 
 	jzfb_blank(FB_BLANK_POWERDOWN, jzfb->fb);
 
-	jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
-
 	fb_dealloc_cmap(&jzfb->fb->cmap);
 	jzfb_free_devmem(jzfb);
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v4 13/14] pwm: jz4740: Let the pinctrl driver configure the pins
  2017-04-02 20:42         ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                             ` (11 preceding siblings ...)
  2017-04-02 20:42           ` [PATCH v4 12/14] fbdev: jz4740-fb: " Paul Cercueil
@ 2017-04-02 20:42           ` Paul Cercueil
  2017-04-06 14:40             ` Thierry Reding
  2017-04-02 20:42           ` [PATCH v4 14/14] MIPS: jz4740: Remove custom GPIO code Paul Cercueil
  13 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-04-02 20:42 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
the pins being properly configured before the driver probes.

One inherent problem of this new approach is that the pinctrl framework
does not allow us to configure each pin on demand, when the various PWM
channels are requested or released. For instance, the PWM channels can
be configured from sysfs, which would require all PWM pins to be configured
properly beforehand for the PWM function, eventually causing conflicts
with other platform or board drivers.

The proper solution here would be to modify the pwm-jz4740 driver to
handle only one PWM channel, and create an instance of this driver
for each one of the 8 PWM channels. Then, it could use the pinctrl
framework to dynamically configure the PWM pin it controls.

Until this can be done, the only jz4740 board supported upstream
(Qi lb60) can configure all of its connected PWM pins in PWM function
mode, since those are not used by other drivers nor by GPIOs on the
board.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/pwm/pwm-jz4740.c | 29 -----------------------------
 1 file changed, 29 deletions(-)

 v2: No changes
 v3: No changes
 v4: No changes

diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c
index 76d13150283f..a75ff3622450 100644
--- a/drivers/pwm/pwm-jz4740.c
+++ b/drivers/pwm/pwm-jz4740.c
@@ -21,22 +21,10 @@
 #include <linux/platform_device.h>
 #include <linux/pwm.h>
 
-#include <asm/mach-jz4740/gpio.h>
 #include <asm/mach-jz4740/timer.h>
 
 #define NUM_PWM 8
 
-static const unsigned int jz4740_pwm_gpio_list[NUM_PWM] = {
-	JZ_GPIO_PWM0,
-	JZ_GPIO_PWM1,
-	JZ_GPIO_PWM2,
-	JZ_GPIO_PWM3,
-	JZ_GPIO_PWM4,
-	JZ_GPIO_PWM5,
-	JZ_GPIO_PWM6,
-	JZ_GPIO_PWM7,
-};
-
 struct jz4740_pwm_chip {
 	struct pwm_chip chip;
 	struct clk *clk;
@@ -49,9 +37,6 @@ static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip)
 
 static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-	unsigned int gpio = jz4740_pwm_gpio_list[pwm->hwpwm];
-	int ret;
-
 	/*
 	 * Timers 0 and 1 are used for system tasks, so they are unavailable
 	 * for use as PWMs.
@@ -59,15 +44,6 @@ static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 	if (pwm->hwpwm < 2)
 		return -EBUSY;
 
-	ret = gpio_request(gpio, pwm->label);
-	if (ret) {
-		dev_err(chip->dev, "Failed to request GPIO#%u for PWM: %d\n",
-			gpio, ret);
-		return ret;
-	}
-
-	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_PWM);
-
 	jz4740_timer_start(pwm->hwpwm);
 
 	return 0;
@@ -75,13 +51,8 @@ static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 
 static void jz4740_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-	unsigned int gpio = jz4740_pwm_gpio_list[pwm->hwpwm];
-
 	jz4740_timer_set_ctrl(pwm->hwpwm, 0);
 
-	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE);
-	gpio_free(gpio);
-
 	jz4740_timer_stop(pwm->hwpwm);
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v4 14/14] MIPS: jz4740: Remove custom GPIO code
  2017-04-02 20:42         ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                             ` (12 preceding siblings ...)
  2017-04-02 20:42           ` [PATCH v4 13/14] pwm: jz4740: " Paul Cercueil
@ 2017-04-02 20:42           ` Paul Cercueil
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-04-02 20:42 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

All the drivers for the various hardware elements of the jz4740 SoC have
been modified to use the pinctrl framework for their pin configuration
needs.
As such, this platform code is now unused and can be deleted.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/include/asm/mach-jz4740/gpio.h | 371 ----------------------
 arch/mips/jz4740/Makefile                |   2 -
 arch/mips/jz4740/gpio.c                  | 519 -------------------------------
 3 files changed, 892 deletions(-)
 delete mode 100644 arch/mips/jz4740/gpio.c

 v2: No changes
 v3: No changes
 v4: No changes

diff --git a/arch/mips/include/asm/mach-jz4740/gpio.h b/arch/mips/include/asm/mach-jz4740/gpio.h
index 7c7708a23baa..fd847c984701 100644
--- a/arch/mips/include/asm/mach-jz4740/gpio.h
+++ b/arch/mips/include/asm/mach-jz4740/gpio.h
@@ -16,380 +16,9 @@
 #ifndef _JZ_GPIO_H
 #define _JZ_GPIO_H
 
-#include <linux/types.h>
-
-enum jz_gpio_function {
-    JZ_GPIO_FUNC_NONE,
-    JZ_GPIO_FUNC1,
-    JZ_GPIO_FUNC2,
-    JZ_GPIO_FUNC3,
-};
-
-/*
- Usually a driver for a SoC component has to request several gpio pins and
- configure them as function pins.
- jz_gpio_bulk_request can be used to ease this process.
- Usually one would do something like:
-
- static const struct jz_gpio_bulk_request i2c_pins[] = {
-	JZ_GPIO_BULK_PIN(I2C_SDA),
-	JZ_GPIO_BULK_PIN(I2C_SCK),
- };
-
- inside the probe function:
-
-    ret = jz_gpio_bulk_request(i2c_pins, ARRAY_SIZE(i2c_pins));
-    if (ret) {
-	...
-
- inside the remove function:
-
-    jz_gpio_bulk_free(i2c_pins, ARRAY_SIZE(i2c_pins));
-
-*/
-
-struct jz_gpio_bulk_request {
-	int gpio;
-	const char *name;
-	enum jz_gpio_function function;
-};
-
-#define JZ_GPIO_BULK_PIN(pin) { \
-    .gpio = JZ_GPIO_ ## pin, \
-    .name = #pin, \
-    .function = JZ_GPIO_FUNC_ ## pin \
-}
-
-int jz_gpio_bulk_request(const struct jz_gpio_bulk_request *request, size_t num);
-void jz_gpio_bulk_free(const struct jz_gpio_bulk_request *request, size_t num);
-void jz_gpio_bulk_suspend(const struct jz_gpio_bulk_request *request, size_t num);
-void jz_gpio_bulk_resume(const struct jz_gpio_bulk_request *request, size_t num);
-void jz_gpio_enable_pullup(unsigned gpio);
-void jz_gpio_disable_pullup(unsigned gpio);
-int jz_gpio_set_function(int gpio, enum jz_gpio_function function);
-
-int jz_gpio_port_direction_input(int port, uint32_t mask);
-int jz_gpio_port_direction_output(int port, uint32_t mask);
-void jz_gpio_port_set_value(int port, uint32_t value, uint32_t mask);
-uint32_t jz_gpio_port_get_value(int port, uint32_t mask);
-
 #define JZ_GPIO_PORTA(x) ((x) + 32 * 0)
 #define JZ_GPIO_PORTB(x) ((x) + 32 * 1)
 #define JZ_GPIO_PORTC(x) ((x) + 32 * 2)
 #define JZ_GPIO_PORTD(x) ((x) + 32 * 3)
 
-/* Port A function pins */
-#define JZ_GPIO_MEM_DATA0		JZ_GPIO_PORTA(0)
-#define JZ_GPIO_MEM_DATA1		JZ_GPIO_PORTA(1)
-#define JZ_GPIO_MEM_DATA2		JZ_GPIO_PORTA(2)
-#define JZ_GPIO_MEM_DATA3		JZ_GPIO_PORTA(3)
-#define JZ_GPIO_MEM_DATA4		JZ_GPIO_PORTA(4)
-#define JZ_GPIO_MEM_DATA5		JZ_GPIO_PORTA(5)
-#define JZ_GPIO_MEM_DATA6		JZ_GPIO_PORTA(6)
-#define JZ_GPIO_MEM_DATA7		JZ_GPIO_PORTA(7)
-#define JZ_GPIO_MEM_DATA8		JZ_GPIO_PORTA(8)
-#define JZ_GPIO_MEM_DATA9		JZ_GPIO_PORTA(9)
-#define JZ_GPIO_MEM_DATA10		JZ_GPIO_PORTA(10)
-#define JZ_GPIO_MEM_DATA11		JZ_GPIO_PORTA(11)
-#define JZ_GPIO_MEM_DATA12		JZ_GPIO_PORTA(12)
-#define JZ_GPIO_MEM_DATA13		JZ_GPIO_PORTA(13)
-#define JZ_GPIO_MEM_DATA14		JZ_GPIO_PORTA(14)
-#define JZ_GPIO_MEM_DATA15		JZ_GPIO_PORTA(15)
-#define JZ_GPIO_MEM_DATA16		JZ_GPIO_PORTA(16)
-#define JZ_GPIO_MEM_DATA17		JZ_GPIO_PORTA(17)
-#define JZ_GPIO_MEM_DATA18		JZ_GPIO_PORTA(18)
-#define JZ_GPIO_MEM_DATA19		JZ_GPIO_PORTA(19)
-#define JZ_GPIO_MEM_DATA20		JZ_GPIO_PORTA(20)
-#define JZ_GPIO_MEM_DATA21		JZ_GPIO_PORTA(21)
-#define JZ_GPIO_MEM_DATA22		JZ_GPIO_PORTA(22)
-#define JZ_GPIO_MEM_DATA23		JZ_GPIO_PORTA(23)
-#define JZ_GPIO_MEM_DATA24		JZ_GPIO_PORTA(24)
-#define JZ_GPIO_MEM_DATA25		JZ_GPIO_PORTA(25)
-#define JZ_GPIO_MEM_DATA26		JZ_GPIO_PORTA(26)
-#define JZ_GPIO_MEM_DATA27		JZ_GPIO_PORTA(27)
-#define JZ_GPIO_MEM_DATA28		JZ_GPIO_PORTA(28)
-#define JZ_GPIO_MEM_DATA29		JZ_GPIO_PORTA(29)
-#define JZ_GPIO_MEM_DATA30		JZ_GPIO_PORTA(30)
-#define JZ_GPIO_MEM_DATA31		JZ_GPIO_PORTA(31)
-
-#define JZ_GPIO_FUNC_MEM_DATA0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA4		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA5		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA6		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA7		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA8		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA9		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA10		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA11		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA12		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA13		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA14		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA15		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA16		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA17		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA18		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA19		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA20		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA21		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA22		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA23		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA24		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA25		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA26		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA27		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA28		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA29		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA30		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA31		JZ_GPIO_FUNC1
-
-/* Port B function pins */
-#define JZ_GPIO_MEM_ADDR0		JZ_GPIO_PORTB(0)
-#define JZ_GPIO_MEM_ADDR1		JZ_GPIO_PORTB(1)
-#define JZ_GPIO_MEM_ADDR2		JZ_GPIO_PORTB(2)
-#define JZ_GPIO_MEM_ADDR3		JZ_GPIO_PORTB(3)
-#define JZ_GPIO_MEM_ADDR4		JZ_GPIO_PORTB(4)
-#define JZ_GPIO_MEM_ADDR5		JZ_GPIO_PORTB(5)
-#define JZ_GPIO_MEM_ADDR6		JZ_GPIO_PORTB(6)
-#define JZ_GPIO_MEM_ADDR7		JZ_GPIO_PORTB(7)
-#define JZ_GPIO_MEM_ADDR8		JZ_GPIO_PORTB(8)
-#define JZ_GPIO_MEM_ADDR9		JZ_GPIO_PORTB(9)
-#define JZ_GPIO_MEM_ADDR10		JZ_GPIO_PORTB(10)
-#define JZ_GPIO_MEM_ADDR11		JZ_GPIO_PORTB(11)
-#define JZ_GPIO_MEM_ADDR12		JZ_GPIO_PORTB(12)
-#define JZ_GPIO_MEM_ADDR13		JZ_GPIO_PORTB(13)
-#define JZ_GPIO_MEM_ADDR14		JZ_GPIO_PORTB(14)
-#define JZ_GPIO_MEM_ADDR15		JZ_GPIO_PORTB(15)
-#define JZ_GPIO_MEM_ADDR16		JZ_GPIO_PORTB(16)
-#define JZ_GPIO_LCD_CLS			JZ_GPIO_PORTB(17)
-#define JZ_GPIO_LCD_SPL			JZ_GPIO_PORTB(18)
-#define JZ_GPIO_MEM_DCS			JZ_GPIO_PORTB(19)
-#define JZ_GPIO_MEM_RAS			JZ_GPIO_PORTB(20)
-#define JZ_GPIO_MEM_CAS			JZ_GPIO_PORTB(21)
-#define JZ_GPIO_MEM_SDWE		JZ_GPIO_PORTB(22)
-#define JZ_GPIO_MEM_CKE			JZ_GPIO_PORTB(23)
-#define JZ_GPIO_MEM_CKO			JZ_GPIO_PORTB(24)
-#define JZ_GPIO_MEM_CS0			JZ_GPIO_PORTB(25)
-#define JZ_GPIO_MEM_CS1			JZ_GPIO_PORTB(26)
-#define JZ_GPIO_MEM_CS2			JZ_GPIO_PORTB(27)
-#define JZ_GPIO_MEM_CS3			JZ_GPIO_PORTB(28)
-#define JZ_GPIO_MEM_RD			JZ_GPIO_PORTB(29)
-#define JZ_GPIO_MEM_WR			JZ_GPIO_PORTB(30)
-#define JZ_GPIO_MEM_WE0			JZ_GPIO_PORTB(31)
-
-#define JZ_GPIO_FUNC_MEM_ADDR0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR4		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR5		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR6		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR7		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR8		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR9		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR10		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR11		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR12		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR13		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR14		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR15		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR16		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_CLS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_SPL		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DCS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_RAS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CAS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_SDWE		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CKE		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CKO		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CS0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CS1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CS2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CS3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_RD		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WR		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WE0		JZ_GPIO_FUNC1
-
-
-#define JZ_GPIO_MEM_ADDR21		JZ_GPIO_PORTB(17)
-#define JZ_GPIO_MEM_ADDR22		JZ_GPIO_PORTB(18)
-
-#define JZ_GPIO_FUNC_MEM_ADDR21		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_ADDR22		JZ_GPIO_FUNC2
-
-/* Port C function pins */
-#define JZ_GPIO_LCD_DATA0		JZ_GPIO_PORTC(0)
-#define JZ_GPIO_LCD_DATA1		JZ_GPIO_PORTC(1)
-#define JZ_GPIO_LCD_DATA2		JZ_GPIO_PORTC(2)
-#define JZ_GPIO_LCD_DATA3		JZ_GPIO_PORTC(3)
-#define JZ_GPIO_LCD_DATA4		JZ_GPIO_PORTC(4)
-#define JZ_GPIO_LCD_DATA5		JZ_GPIO_PORTC(5)
-#define JZ_GPIO_LCD_DATA6		JZ_GPIO_PORTC(6)
-#define JZ_GPIO_LCD_DATA7		JZ_GPIO_PORTC(7)
-#define JZ_GPIO_LCD_DATA8		JZ_GPIO_PORTC(8)
-#define JZ_GPIO_LCD_DATA9		JZ_GPIO_PORTC(9)
-#define JZ_GPIO_LCD_DATA10		JZ_GPIO_PORTC(10)
-#define JZ_GPIO_LCD_DATA11		JZ_GPIO_PORTC(11)
-#define JZ_GPIO_LCD_DATA12		JZ_GPIO_PORTC(12)
-#define JZ_GPIO_LCD_DATA13		JZ_GPIO_PORTC(13)
-#define JZ_GPIO_LCD_DATA14		JZ_GPIO_PORTC(14)
-#define JZ_GPIO_LCD_DATA15		JZ_GPIO_PORTC(15)
-#define JZ_GPIO_LCD_DATA16		JZ_GPIO_PORTC(16)
-#define JZ_GPIO_LCD_DATA17		JZ_GPIO_PORTC(17)
-#define JZ_GPIO_LCD_PCLK		JZ_GPIO_PORTC(18)
-#define JZ_GPIO_LCD_HSYNC		JZ_GPIO_PORTC(19)
-#define JZ_GPIO_LCD_VSYNC		JZ_GPIO_PORTC(20)
-#define JZ_GPIO_LCD_DE			JZ_GPIO_PORTC(21)
-#define JZ_GPIO_LCD_PS			JZ_GPIO_PORTC(22)
-#define JZ_GPIO_LCD_REV			JZ_GPIO_PORTC(23)
-#define JZ_GPIO_MEM_WE1			JZ_GPIO_PORTC(24)
-#define JZ_GPIO_MEM_WE2			JZ_GPIO_PORTC(25)
-#define JZ_GPIO_MEM_WE3			JZ_GPIO_PORTC(26)
-#define JZ_GPIO_MEM_WAIT		JZ_GPIO_PORTC(27)
-#define JZ_GPIO_MEM_FRE			JZ_GPIO_PORTC(28)
-#define JZ_GPIO_MEM_FWE			JZ_GPIO_PORTC(29)
-
-#define JZ_GPIO_FUNC_LCD_DATA0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA4		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA5		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA6		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA7		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA8		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA9		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA10		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA11		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA12		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA13		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA14		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA15		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA16		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA17		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_PCLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_VSYNC		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_HSYNC		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DE		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_PS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_REV		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WE1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WE2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WE3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WAIT		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_FRE		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_FWE		JZ_GPIO_FUNC1
-
-
-#define JZ_GPIO_MEM_ADDR19		JZ_GPIO_PORTB(22)
-#define JZ_GPIO_MEM_ADDR20		JZ_GPIO_PORTB(23)
-
-#define JZ_GPIO_FUNC_MEM_ADDR19		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_ADDR20		JZ_GPIO_FUNC2
-
-/* Port D function pins */
-#define JZ_GPIO_CIM_DATA0		JZ_GPIO_PORTD(0)
-#define JZ_GPIO_CIM_DATA1		JZ_GPIO_PORTD(1)
-#define JZ_GPIO_CIM_DATA2		JZ_GPIO_PORTD(2)
-#define JZ_GPIO_CIM_DATA3		JZ_GPIO_PORTD(3)
-#define JZ_GPIO_CIM_DATA4		JZ_GPIO_PORTD(4)
-#define JZ_GPIO_CIM_DATA5		JZ_GPIO_PORTD(5)
-#define JZ_GPIO_CIM_DATA6		JZ_GPIO_PORTD(6)
-#define JZ_GPIO_CIM_DATA7		JZ_GPIO_PORTD(7)
-#define JZ_GPIO_MSC_CMD			JZ_GPIO_PORTD(8)
-#define JZ_GPIO_MSC_CLK			JZ_GPIO_PORTD(9)
-#define JZ_GPIO_MSC_DATA0		JZ_GPIO_PORTD(10)
-#define JZ_GPIO_MSC_DATA1		JZ_GPIO_PORTD(11)
-#define JZ_GPIO_MSC_DATA2		JZ_GPIO_PORTD(12)
-#define JZ_GPIO_MSC_DATA3		JZ_GPIO_PORTD(13)
-#define JZ_GPIO_CIM_MCLK		JZ_GPIO_PORTD(14)
-#define JZ_GPIO_CIM_PCLK		JZ_GPIO_PORTD(15)
-#define JZ_GPIO_CIM_VSYNC		JZ_GPIO_PORTD(16)
-#define JZ_GPIO_CIM_HSYNC		JZ_GPIO_PORTD(17)
-#define JZ_GPIO_SPI_CLK			JZ_GPIO_PORTD(18)
-#define JZ_GPIO_SPI_CE0			JZ_GPIO_PORTD(19)
-#define JZ_GPIO_SPI_DT			JZ_GPIO_PORTD(20)
-#define JZ_GPIO_SPI_DR			JZ_GPIO_PORTD(21)
-#define JZ_GPIO_SPI_CE1			JZ_GPIO_PORTD(22)
-#define JZ_GPIO_PWM0			JZ_GPIO_PORTD(23)
-#define JZ_GPIO_PWM1			JZ_GPIO_PORTD(24)
-#define JZ_GPIO_PWM2			JZ_GPIO_PORTD(25)
-#define JZ_GPIO_PWM3			JZ_GPIO_PORTD(26)
-#define JZ_GPIO_PWM4			JZ_GPIO_PORTD(27)
-#define JZ_GPIO_PWM5			JZ_GPIO_PORTD(28)
-#define JZ_GPIO_PWM6			JZ_GPIO_PORTD(30)
-#define JZ_GPIO_PWM7			JZ_GPIO_PORTD(31)
-
-#define JZ_GPIO_FUNC_CIM_DATA		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_CIM_DATA0		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA1		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA2		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA3		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA4		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA5		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA6		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA7		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_MSC_CMD		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MSC_CLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MSC_DATA		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MSC_DATA0		JZ_GPIO_FUNC_MSC_DATA
-#define JZ_GPIO_FUNC_MSC_DATA1		JZ_GPIO_FUNC_MSC_DATA
-#define JZ_GPIO_FUNC_MSC_DATA2		JZ_GPIO_FUNC_MSC_DATA
-#define JZ_GPIO_FUNC_MSC_DATA3		JZ_GPIO_FUNC_MSC_DATA
-#define JZ_GPIO_FUNC_CIM_MCLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_CIM_PCLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_CIM_VSYNC		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_CIM_HSYNC		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_CLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_CE0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_DT		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_DR		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_CE1		JZ_GPIO_FUNC1
-
-#define JZ_GPIO_FUNC_PWM		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_PWM0		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM1		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM2		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM3		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM4		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM5		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM6		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM7		JZ_GPIO_FUNC_PWM
-
-#define JZ_GPIO_MEM_SCLK_RSTN		JZ_GPIO_PORTD(18)
-#define JZ_GPIO_MEM_BCLK		JZ_GPIO_PORTD(19)
-#define JZ_GPIO_MEM_SDATO		JZ_GPIO_PORTD(20)
-#define JZ_GPIO_MEM_SDATI		JZ_GPIO_PORTD(21)
-#define JZ_GPIO_MEM_SYNC		JZ_GPIO_PORTD(22)
-#define JZ_GPIO_I2C_SDA			JZ_GPIO_PORTD(23)
-#define JZ_GPIO_I2C_SCK			JZ_GPIO_PORTD(24)
-#define JZ_GPIO_UART0_TXD		JZ_GPIO_PORTD(25)
-#define JZ_GPIO_UART0_RXD		JZ_GPIO_PORTD(26)
-#define JZ_GPIO_MEM_ADDR17		JZ_GPIO_PORTD(27)
-#define JZ_GPIO_MEM_ADDR18		JZ_GPIO_PORTD(28)
-#define JZ_GPIO_UART0_CTS		JZ_GPIO_PORTD(30)
-#define JZ_GPIO_UART0_RTS		JZ_GPIO_PORTD(31)
-
-#define JZ_GPIO_FUNC_MEM_SCLK_RSTN	JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_BCLK		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_SDATO		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_SDATI		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_SYNC		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_I2C_SDA		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_I2C_SCK		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_UART0_TXD		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_UART0_RXD		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_ADDR17		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_ADDR18		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_UART0_CTS		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_UART0_RTS		JZ_GPIO_FUNC2
-
-#define JZ_GPIO_UART1_RXD		JZ_GPIO_PORTD(30)
-#define JZ_GPIO_UART1_TXD		JZ_GPIO_PORTD(31)
-
-#define JZ_GPIO_FUNC_UART1_RXD		JZ_GPIO_FUNC3
-#define JZ_GPIO_FUNC_UART1_TXD		JZ_GPIO_FUNC3
-
 #endif
diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
index 39d70bde8cfe..6b9c1f7c31c9 100644
--- a/arch/mips/jz4740/Makefile
+++ b/arch/mips/jz4740/Makefile
@@ -7,8 +7,6 @@
 obj-y += prom.o time.o reset.o setup.o \
 	platform.o timer.o
 
-obj-$(CONFIG_MACH_JZ4740) += gpio.o
-
 CFLAGS_setup.o = -I$(src)/../../../scripts/dtc/libfdt
 
 # board specific support
diff --git a/arch/mips/jz4740/gpio.c b/arch/mips/jz4740/gpio.c
deleted file mode 100644
index cac1ccde2214..000000000000
--- a/arch/mips/jz4740/gpio.c
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- *  Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
- *  JZ4740 platform GPIO support
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/init.h>
-
-#include <linux/io.h>
-#include <linux/gpio/driver.h>
-/* FIXME: needed for gpio_request(), try to remove consumer API from driver */
-#include <linux/gpio.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/irqchip/ingenic.h>
-#include <linux/bitops.h>
-
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-
-#include <asm/mach-jz4740/base.h>
-#include <asm/mach-jz4740/gpio.h>
-
-#define JZ4740_GPIO_BASE_A (32*0)
-#define JZ4740_GPIO_BASE_B (32*1)
-#define JZ4740_GPIO_BASE_C (32*2)
-#define JZ4740_GPIO_BASE_D (32*3)
-
-#define JZ4740_GPIO_NUM_A 32
-#define JZ4740_GPIO_NUM_B 32
-#define JZ4740_GPIO_NUM_C 31
-#define JZ4740_GPIO_NUM_D 32
-
-#define JZ4740_IRQ_GPIO_BASE_A (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_A)
-#define JZ4740_IRQ_GPIO_BASE_B (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_B)
-#define JZ4740_IRQ_GPIO_BASE_C (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_C)
-#define JZ4740_IRQ_GPIO_BASE_D (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_D)
-
-#define JZ_REG_GPIO_PIN			0x00
-#define JZ_REG_GPIO_DATA		0x10
-#define JZ_REG_GPIO_DATA_SET		0x14
-#define JZ_REG_GPIO_DATA_CLEAR		0x18
-#define JZ_REG_GPIO_MASK		0x20
-#define JZ_REG_GPIO_MASK_SET		0x24
-#define JZ_REG_GPIO_MASK_CLEAR		0x28
-#define JZ_REG_GPIO_PULL		0x30
-#define JZ_REG_GPIO_PULL_SET		0x34
-#define JZ_REG_GPIO_PULL_CLEAR		0x38
-#define JZ_REG_GPIO_FUNC		0x40
-#define JZ_REG_GPIO_FUNC_SET		0x44
-#define JZ_REG_GPIO_FUNC_CLEAR		0x48
-#define JZ_REG_GPIO_SELECT		0x50
-#define JZ_REG_GPIO_SELECT_SET		0x54
-#define JZ_REG_GPIO_SELECT_CLEAR	0x58
-#define JZ_REG_GPIO_DIRECTION		0x60
-#define JZ_REG_GPIO_DIRECTION_SET	0x64
-#define JZ_REG_GPIO_DIRECTION_CLEAR	0x68
-#define JZ_REG_GPIO_TRIGGER		0x70
-#define JZ_REG_GPIO_TRIGGER_SET		0x74
-#define JZ_REG_GPIO_TRIGGER_CLEAR	0x78
-#define JZ_REG_GPIO_FLAG		0x80
-#define JZ_REG_GPIO_FLAG_CLEAR		0x14
-
-#define GPIO_TO_BIT(gpio) BIT(gpio & 0x1f)
-#define GPIO_TO_REG(gpio, reg) (gpio_to_jz_gpio_chip(gpio)->base + (reg))
-#define CHIP_TO_REG(chip, reg) (gpio_chip_to_jz_gpio_chip(chip)->base + (reg))
-
-struct jz_gpio_chip {
-	unsigned int irq;
-	unsigned int irq_base;
-	uint32_t edge_trigger_both;
-
-	void __iomem *base;
-
-	struct gpio_chip gpio_chip;
-};
-
-static struct jz_gpio_chip jz4740_gpio_chips[];
-
-static inline struct jz_gpio_chip *gpio_to_jz_gpio_chip(unsigned int gpio)
-{
-	return &jz4740_gpio_chips[gpio >> 5];
-}
-
-static inline struct jz_gpio_chip *gpio_chip_to_jz_gpio_chip(struct gpio_chip *gc)
-{
-	return gpiochip_get_data(gc);
-}
-
-static inline struct jz_gpio_chip *irq_to_jz_gpio_chip(struct irq_data *data)
-{
-	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
-	return gc->private;
-}
-
-static inline void jz_gpio_write_bit(unsigned int gpio, unsigned int reg)
-{
-	writel(GPIO_TO_BIT(gpio), GPIO_TO_REG(gpio, reg));
-}
-
-int jz_gpio_set_function(int gpio, enum jz_gpio_function function)
-{
-	if (function == JZ_GPIO_FUNC_NONE) {
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_FUNC_CLEAR);
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_CLEAR);
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_CLEAR);
-	} else {
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_FUNC_SET);
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_CLEAR);
-		switch (function) {
-		case JZ_GPIO_FUNC1:
-			jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_CLEAR);
-			break;
-		case JZ_GPIO_FUNC3:
-			jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_SET);
-		case JZ_GPIO_FUNC2: /* Falltrough */
-			jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_SET);
-			break;
-		default:
-			BUG();
-			break;
-		}
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(jz_gpio_set_function);
-
-int jz_gpio_bulk_request(const struct jz_gpio_bulk_request *request, size_t num)
-{
-	size_t i;
-	int ret;
-
-	for (i = 0; i < num; ++i, ++request) {
-		ret = gpio_request(request->gpio, request->name);
-		if (ret)
-			goto err;
-		jz_gpio_set_function(request->gpio, request->function);
-	}
-
-	return 0;
-
-err:
-	for (--request; i > 0; --i, --request) {
-		gpio_free(request->gpio);
-		jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
-	}
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(jz_gpio_bulk_request);
-
-void jz_gpio_bulk_free(const struct jz_gpio_bulk_request *request, size_t num)
-{
-	size_t i;
-
-	for (i = 0; i < num; ++i, ++request) {
-		gpio_free(request->gpio);
-		jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
-	}
-
-}
-EXPORT_SYMBOL_GPL(jz_gpio_bulk_free);
-
-void jz_gpio_bulk_suspend(const struct jz_gpio_bulk_request *request, size_t num)
-{
-	size_t i;
-
-	for (i = 0; i < num; ++i, ++request) {
-		jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
-		jz_gpio_write_bit(request->gpio, JZ_REG_GPIO_DIRECTION_CLEAR);
-		jz_gpio_write_bit(request->gpio, JZ_REG_GPIO_PULL_SET);
-	}
-}
-EXPORT_SYMBOL_GPL(jz_gpio_bulk_suspend);
-
-void jz_gpio_bulk_resume(const struct jz_gpio_bulk_request *request, size_t num)
-{
-	size_t i;
-
-	for (i = 0; i < num; ++i, ++request)
-		jz_gpio_set_function(request->gpio, request->function);
-}
-EXPORT_SYMBOL_GPL(jz_gpio_bulk_resume);
-
-void jz_gpio_enable_pullup(unsigned gpio)
-{
-	jz_gpio_write_bit(gpio, JZ_REG_GPIO_PULL_CLEAR);
-}
-EXPORT_SYMBOL_GPL(jz_gpio_enable_pullup);
-
-void jz_gpio_disable_pullup(unsigned gpio)
-{
-	jz_gpio_write_bit(gpio, JZ_REG_GPIO_PULL_SET);
-}
-EXPORT_SYMBOL_GPL(jz_gpio_disable_pullup);
-
-static int jz_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
-{
-	return !!(readl(CHIP_TO_REG(chip, JZ_REG_GPIO_PIN)) & BIT(gpio));
-}
-
-static void jz_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
-{
-	uint32_t __iomem *reg = CHIP_TO_REG(chip, JZ_REG_GPIO_DATA_SET);
-	reg += !value;
-	writel(BIT(gpio), reg);
-}
-
-static int jz_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
-	int value)
-{
-	writel(BIT(gpio), CHIP_TO_REG(chip, JZ_REG_GPIO_DIRECTION_SET));
-	jz_gpio_set_value(chip, gpio, value);
-
-	return 0;
-}
-
-static int jz_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
-{
-	writel(BIT(gpio), CHIP_TO_REG(chip, JZ_REG_GPIO_DIRECTION_CLEAR));
-
-	return 0;
-}
-
-static int jz_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
-{
-	struct jz_gpio_chip *jz_gpio = gpiochip_get_data(chip);
-
-	return jz_gpio->irq_base + gpio;
-}
-
-int jz_gpio_port_direction_input(int port, uint32_t mask)
-{
-	writel(mask, GPIO_TO_REG(port, JZ_REG_GPIO_DIRECTION_CLEAR));
-
-	return 0;
-}
-EXPORT_SYMBOL(jz_gpio_port_direction_input);
-
-int jz_gpio_port_direction_output(int port, uint32_t mask)
-{
-	writel(mask, GPIO_TO_REG(port, JZ_REG_GPIO_DIRECTION_SET));
-
-	return 0;
-}
-EXPORT_SYMBOL(jz_gpio_port_direction_output);
-
-void jz_gpio_port_set_value(int port, uint32_t value, uint32_t mask)
-{
-	writel(~value & mask, GPIO_TO_REG(port, JZ_REG_GPIO_DATA_CLEAR));
-	writel(value & mask, GPIO_TO_REG(port, JZ_REG_GPIO_DATA_SET));
-}
-EXPORT_SYMBOL(jz_gpio_port_set_value);
-
-uint32_t jz_gpio_port_get_value(int port, uint32_t mask)
-{
-	uint32_t value = readl(GPIO_TO_REG(port, JZ_REG_GPIO_PIN));
-
-	return value & mask;
-}
-EXPORT_SYMBOL(jz_gpio_port_get_value);
-
-#define IRQ_TO_BIT(irq) BIT((irq - JZ4740_IRQ_GPIO(0)) & 0x1f)
-
-static void jz_gpio_check_trigger_both(struct jz_gpio_chip *chip, unsigned int irq)
-{
-	uint32_t value;
-	void __iomem *reg;
-	uint32_t mask = IRQ_TO_BIT(irq);
-
-	if (!(chip->edge_trigger_both & mask))
-		return;
-
-	reg = chip->base;
-
-	value = readl(chip->base + JZ_REG_GPIO_PIN);
-	if (value & mask)
-		reg += JZ_REG_GPIO_DIRECTION_CLEAR;
-	else
-		reg += JZ_REG_GPIO_DIRECTION_SET;
-
-	writel(mask, reg);
-}
-
-static void jz_gpio_irq_demux_handler(struct irq_desc *desc)
-{
-	uint32_t flag;
-	unsigned int gpio_irq;
-	struct jz_gpio_chip *chip = irq_desc_get_handler_data(desc);
-
-	flag = readl(chip->base + JZ_REG_GPIO_FLAG);
-	if (!flag)
-		return;
-
-	gpio_irq = chip->irq_base + __fls(flag);
-
-	jz_gpio_check_trigger_both(chip, gpio_irq);
-
-	generic_handle_irq(gpio_irq);
-};
-
-static inline void jz_gpio_set_irq_bit(struct irq_data *data, unsigned int reg)
-{
-	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
-	writel(IRQ_TO_BIT(data->irq), chip->base + reg);
-}
-
-static void jz_gpio_irq_unmask(struct irq_data *data)
-{
-	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
-
-	jz_gpio_check_trigger_both(chip, data->irq);
-	irq_gc_unmask_enable_reg(data);
-};
-
-/* TODO: Check if function is gpio */
-static unsigned int jz_gpio_irq_startup(struct irq_data *data)
-{
-	jz_gpio_set_irq_bit(data, JZ_REG_GPIO_SELECT_SET);
-	jz_gpio_irq_unmask(data);
-	return 0;
-}
-
-static void jz_gpio_irq_shutdown(struct irq_data *data)
-{
-	irq_gc_mask_disable_reg(data);
-
-	/* Set direction to input */
-	jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR);
-	jz_gpio_set_irq_bit(data, JZ_REG_GPIO_SELECT_CLEAR);
-}
-
-static int jz_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type)
-{
-	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
-	unsigned int irq = data->irq;
-
-	if (flow_type == IRQ_TYPE_EDGE_BOTH) {
-		uint32_t value = readl(chip->base + JZ_REG_GPIO_PIN);
-		if (value & IRQ_TO_BIT(irq))
-			flow_type = IRQ_TYPE_EDGE_FALLING;
-		else
-			flow_type = IRQ_TYPE_EDGE_RISING;
-		chip->edge_trigger_both |= IRQ_TO_BIT(irq);
-	} else {
-		chip->edge_trigger_both &= ~IRQ_TO_BIT(irq);
-	}
-
-	switch (flow_type) {
-	case IRQ_TYPE_EDGE_RISING:
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_SET);
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_SET);
-		break;
-	case IRQ_TYPE_EDGE_FALLING:
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR);
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_SET);
-		break;
-	case IRQ_TYPE_LEVEL_HIGH:
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_SET);
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_CLEAR);
-		break;
-	case IRQ_TYPE_LEVEL_LOW:
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR);
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_CLEAR);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int jz_gpio_irq_set_wake(struct irq_data *data, unsigned int on)
-{
-	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
-
-	irq_gc_set_wake(data, on);
-	irq_set_irq_wake(chip->irq, on);
-
-	return 0;
-}
-
-#define JZ4740_GPIO_CHIP(_bank) { \
-	.irq_base = JZ4740_IRQ_GPIO_BASE_ ## _bank, \
-	.gpio_chip = { \
-		.label = "Bank " # _bank, \
-		.owner = THIS_MODULE, \
-		.set = jz_gpio_set_value, \
-		.get = jz_gpio_get_value, \
-		.direction_output = jz_gpio_direction_output, \
-		.direction_input = jz_gpio_direction_input, \
-		.to_irq = jz_gpio_to_irq, \
-		.base = JZ4740_GPIO_BASE_ ## _bank, \
-		.ngpio = JZ4740_GPIO_NUM_ ## _bank, \
-	}, \
-}
-
-static struct jz_gpio_chip jz4740_gpio_chips[] = {
-	JZ4740_GPIO_CHIP(A),
-	JZ4740_GPIO_CHIP(B),
-	JZ4740_GPIO_CHIP(C),
-	JZ4740_GPIO_CHIP(D),
-};
-
-static void jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id)
-{
-	struct irq_chip_generic *gc;
-	struct irq_chip_type *ct;
-
-	chip->base = ioremap(JZ4740_GPIO_BASE_ADDR + (id * 0x100), 0x100);
-
-	chip->irq = JZ4740_IRQ_INTC_GPIO(id);
-	irq_set_chained_handler_and_data(chip->irq,
-					 jz_gpio_irq_demux_handler, chip);
-
-	gc = irq_alloc_generic_chip(chip->gpio_chip.label, 1, chip->irq_base,
-		chip->base, handle_level_irq);
-
-	gc->wake_enabled = IRQ_MSK(chip->gpio_chip.ngpio);
-	gc->private = chip;
-
-	ct = gc->chip_types;
-	ct->regs.enable = JZ_REG_GPIO_MASK_CLEAR;
-	ct->regs.disable = JZ_REG_GPIO_MASK_SET;
-	ct->regs.ack = JZ_REG_GPIO_FLAG_CLEAR;
-
-	ct->chip.name = "GPIO";
-	ct->chip.irq_mask = irq_gc_mask_disable_reg;
-	ct->chip.irq_unmask = jz_gpio_irq_unmask;
-	ct->chip.irq_ack = irq_gc_ack_set_bit;
-	ct->chip.irq_suspend = ingenic_intc_irq_suspend;
-	ct->chip.irq_resume = ingenic_intc_irq_resume;
-	ct->chip.irq_startup = jz_gpio_irq_startup;
-	ct->chip.irq_shutdown = jz_gpio_irq_shutdown;
-	ct->chip.irq_set_type = jz_gpio_irq_set_type;
-	ct->chip.irq_set_wake = jz_gpio_irq_set_wake;
-	ct->chip.flags = IRQCHIP_SET_TYPE_MASKED;
-
-	irq_setup_generic_chip(gc, IRQ_MSK(chip->gpio_chip.ngpio),
-		IRQ_GC_INIT_NESTED_LOCK, 0, IRQ_NOPROBE | IRQ_LEVEL);
-
-	gpiochip_add_data(&chip->gpio_chip, chip);
-}
-
-static int __init jz4740_gpio_init(void)
-{
-	unsigned int i;
-
-	for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i)
-		jz4740_gpio_chip_init(&jz4740_gpio_chips[i], i);
-
-	printk(KERN_INFO "JZ4740 GPIO initialized\n");
-
-	return 0;
-}
-arch_initcall(jz4740_gpio_init);
-
-#ifdef CONFIG_DEBUG_FS
-
-static inline void gpio_seq_reg(struct seq_file *s, struct jz_gpio_chip *chip,
-	const char *name, unsigned int reg)
-{
-	seq_printf(s, "\t%s: %08x\n", name, readl(chip->base + reg));
-}
-
-static int gpio_regs_show(struct seq_file *s, void *unused)
-{
-	struct jz_gpio_chip *chip = jz4740_gpio_chips;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i, ++chip) {
-		seq_printf(s, "==GPIO %d==\n", i);
-		gpio_seq_reg(s, chip, "Pin", JZ_REG_GPIO_PIN);
-		gpio_seq_reg(s, chip, "Data", JZ_REG_GPIO_DATA);
-		gpio_seq_reg(s, chip, "Mask", JZ_REG_GPIO_MASK);
-		gpio_seq_reg(s, chip, "Pull", JZ_REG_GPIO_PULL);
-		gpio_seq_reg(s, chip, "Func", JZ_REG_GPIO_FUNC);
-		gpio_seq_reg(s, chip, "Select", JZ_REG_GPIO_SELECT);
-		gpio_seq_reg(s, chip, "Direction", JZ_REG_GPIO_DIRECTION);
-		gpio_seq_reg(s, chip, "Trigger", JZ_REG_GPIO_TRIGGER);
-		gpio_seq_reg(s, chip, "Flag", JZ_REG_GPIO_FLAG);
-	}
-
-	return 0;
-}
-
-static int gpio_regs_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, gpio_regs_show, NULL);
-}
-
-static const struct file_operations gpio_regs_operations = {
-	.open		= gpio_regs_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static int __init gpio_debugfs_init(void)
-{
-	(void) debugfs_create_file("jz_regs_gpio", S_IFREG | S_IRUGO,
-				NULL, NULL, &gpio_regs_operations);
-	return 0;
-}
-subsys_initcall(gpio_debugfs_init);
-
-#endif
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v4 06/14] MIPS: jz4740: DTS: Add nodes for ingenic pinctrl and gpio drivers
  2017-04-02 20:42           ` [PATCH v4 06/14] MIPS: jz4740: DTS: Add nodes for ingenic pinctrl and gpio drivers Paul Cercueil
@ 2017-04-03  9:57             ` Sergei Shtylyov
  2017-04-03 10:20               ` Paul Cercueil
  2017-04-07  9:44             ` Linus Walleij
  1 sibling, 1 reply; 162+ messages in thread
From: Sergei Shtylyov @ 2017-04-03  9:57 UTC (permalink / raw)
  To: Paul Cercueil, Linus Walleij, Alexandre Courbot, Rob Herring,
	Mark Rutland, Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev

Hello!

On 4/2/2017 11:42 PM, Paul Cercueil wrote:

> For a description of the pinctrl devicetree node, please read
> Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
>
> For a description of the gpio devicetree nodes, please read
> Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
>
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
[...]

> diff --git a/arch/mips/boot/dts/ingenic/jz4740.dtsi b/arch/mips/boot/dts/ingenic/jz4740.dtsi
> index 3e1587f1f77a..9c23c877fc34 100644
> --- a/arch/mips/boot/dts/ingenic/jz4740.dtsi
> +++ b/arch/mips/boot/dts/ingenic/jz4740.dtsi
> @@ -55,6 +55,67 @@
>  		clock-names = "rtc";
>  	};
>
> +	pinctrl: ingenic-pinctrl@10010000 {

    The node name should be generic, so please rename it to something like 
"pin-controller@..."

> +		compatible = "ingenic,jz4740-pinctrl";
> +		reg = <0x10010000 0x400>;
> +
> +		gpa: gpio-controller@0 {

    The name should be just "gpio@0", according to ePAPR and its successor 
spec. Although, using the <unit-address> without the "reg" prop isn't allowed 
either...

[...]

MBR, Sergei

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v4 06/14] MIPS: jz4740: DTS: Add nodes for ingenic pinctrl and gpio drivers
  2017-04-03  9:57             ` Sergei Shtylyov
@ 2017-04-03 10:20               ` Paul Cercueil
  2017-04-03 10:32                 ` Sergei Shtylyov
  0 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-04-03 10:20 UTC (permalink / raw)
  To: Sergei Shtylyov
  Cc: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton, james.hogan, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev

Hi,

Le 2017-04-03 11:57, Sergei Shtylyov a écrit :
> Hello!
> 
> On 4/2/2017 11:42 PM, Paul Cercueil wrote:
> 
>> For a description of the pinctrl devicetree node, please read
>> Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
>> 
>> For a description of the gpio devicetree nodes, please read
>> Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
>> 
>> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
> [...]
> 
>> diff --git a/arch/mips/boot/dts/ingenic/jz4740.dtsi 
>> b/arch/mips/boot/dts/ingenic/jz4740.dtsi
>> index 3e1587f1f77a..9c23c877fc34 100644
>> --- a/arch/mips/boot/dts/ingenic/jz4740.dtsi
>> +++ b/arch/mips/boot/dts/ingenic/jz4740.dtsi
>> @@ -55,6 +55,67 @@
>>  		clock-names = "rtc";
>>  	};
>> 
>> +	pinctrl: ingenic-pinctrl@10010000 {
> 
>    The node name should be generic, so please rename it to something
> like "pin-controller@..."

OK.

>> +		compatible = "ingenic,jz4740-pinctrl";
>> +		reg = <0x10010000 0x400>;
>> +
>> +		gpa: gpio-controller@0 {
> 
>    The name should be just "gpio@0", according to ePAPR and its
> successor spec. Although, using the <unit-address> without the "reg"
> prop isn't allowed either...

ePAPR says: "If the node has no reg property, the unit-address may be
omitted if the node name alone differentiates the node from other nodes 
at
the same level in the tree."

I could use 'gpio@bank-a', it is allowed by the spec. Or do you prefer 
'gpio@0'?

> MBR, Sergei

I'll wait from some feedback on the other patches then send a v5.

Thanks,
-Paul

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v4 06/14] MIPS: jz4740: DTS: Add nodes for ingenic pinctrl and gpio drivers
  2017-04-03 10:20               ` Paul Cercueil
@ 2017-04-03 10:32                 ` Sergei Shtylyov
  0 siblings, 0 replies; 162+ messages in thread
From: Sergei Shtylyov @ 2017-04-03 10:32 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton, james.hogan, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev

On 4/3/2017 1:20 PM, Paul Cercueil wrote:

>>> For a description of the pinctrl devicetree node, please read
>>> Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
>>>
>>> For a description of the gpio devicetree nodes, please read
>>> Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
>>>
>>> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
>> [...]
>>
>>> diff --git a/arch/mips/boot/dts/ingenic/jz4740.dtsi
>>> b/arch/mips/boot/dts/ingenic/jz4740.dtsi
>>> index 3e1587f1f77a..9c23c877fc34 100644
>>> --- a/arch/mips/boot/dts/ingenic/jz4740.dtsi
>>> +++ b/arch/mips/boot/dts/ingenic/jz4740.dtsi
>>> @@ -55,6 +55,67 @@
>>>          clock-names = "rtc";
>>>      };
>>>
>>> +    pinctrl: ingenic-pinctrl@10010000 {
>>
>>    The node name should be generic, so please rename it to something
>> like "pin-controller@..."
>
> OK.
>
>>> +        compatible = "ingenic,jz4740-pinctrl";
>>> +        reg = <0x10010000 0x400>;
>>> +
>>> +        gpa: gpio-controller@0 {
>>
>>    The name should be just "gpio@0", according to ePAPR and its
>> successor spec. Although, using the <unit-address> without the "reg"
>> prop isn't allowed either...
>
> ePAPR says: "If the node has no reg property, the unit-address may be

    My copy of ePAPR 1.1 says "must be omitted". :-)

> omitted if the node name alone differentiates the node from other nodes at
> the same level in the tree."

> I could use 'gpio@bank-a', it is allowed by the spec. Or do you prefer 'gpio@0'?

    Hm... maybe you should just use the "reg" prop.

> I'll wait from some feedback on the other patches then send a v5.
>
> Thanks,
> -Paul

MBR, Sergei

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v4 04/14] GPIO: Add gpio-ingenic driver
  2017-04-02 20:42           ` [PATCH v4 04/14] GPIO: Add gpio-ingenic driver Paul Cercueil
@ 2017-04-03 14:15             ` kbuild test robot
  2017-04-03 14:15               ` kbuild test robot
  2017-04-07  9:34             ` Linus Walleij
  1 sibling, 1 reply; 162+ messages in thread
From: kbuild test robot @ 2017-04-03 14:15 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: kbuild-all, Linus Walleij, Alexandre Courbot, Rob Herring,
	Mark Rutland, Ralf Baechle, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton, james.hogan, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev, Paul Cercueil

[-- Attachment #1: Type: text/plain, Size: 980 bytes --]

Hi Paul,

[auto build test WARNING on linus/master]
[also build test WARNING on v4.11-rc5 next-20170403]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Paul-Cercueil/Ingenic-JZ4740-JZ4780-pinctrl-driver/20170403-184309
config: xtensa-allmodconfig (attached as .config)
compiler: xtensa-linux-gcc (GCC) 4.9.0
reproduce:
        wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=xtensa 

All warnings (new ones prefixed by >>):

warning: (GPIO_INGENIC) selects PINCTRL_INGENIC which has unmet direct dependencies (PINCTRL && (MACH_INGENIC || COMPILE_TEST))

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 49094 bytes --]

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v4 04/14] GPIO: Add gpio-ingenic driver
  2017-04-03 14:15             ` kbuild test robot
@ 2017-04-03 14:15               ` kbuild test robot
  0 siblings, 0 replies; 162+ messages in thread
From: kbuild test robot @ 2017-04-03 14:15 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: kbuild-all, Linus Walleij, Alexandre Courbot, Rob Herring,
	Mark Rutland, Ralf Baechle, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton, james.hogan, linux-gpio,
	devicetree, linux-kernel, linux-mips, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev

[-- Attachment #1: Type: text/plain, Size: 980 bytes --]

Hi Paul,

[auto build test WARNING on linus/master]
[also build test WARNING on v4.11-rc5 next-20170403]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Paul-Cercueil/Ingenic-JZ4740-JZ4780-pinctrl-driver/20170403-184309
config: xtensa-allmodconfig (attached as .config)
compiler: xtensa-linux-gcc (GCC) 4.9.0
reproduce:
        wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=xtensa 

All warnings (new ones prefixed by >>):

warning: (GPIO_INGENIC) selects PINCTRL_INGENIC which has unmet direct dependencies (PINCTRL && (MACH_INGENIC || COMPILE_TEST))

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 49094 bytes --]

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v4 01/14] dt/bindings: Document pinctrl-ingenic
  2017-04-02 20:42           ` [PATCH v4 01/14] dt/bindings: Document pinctrl-ingenic Paul Cercueil
@ 2017-04-04 14:48             ` Rob Herring
  2017-04-28 20:08             ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
  1 sibling, 0 replies; 162+ messages in thread
From: Rob Herring @ 2017-04-04 14:48 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Linus Walleij, Alexandre Courbot, Mark Rutland, Ralf Baechle,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev

On Sun, Apr 02, 2017 at 10:42:31PM +0200, Paul Cercueil wrote:
> This commit adds documentation for the devicetree bindings of the
> pinctrl-ingenic driver, which handles pin configuration and pin
> muxing of the Ingenic SoCs currently supported by the Linux kernel.
> 
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
> ---
>  .../bindings/pinctrl/ingenic,pinctrl.txt           | 41 ++++++++++++++++++++++
>  1 file changed, 41 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt

Acked-by: Rob Herring <robh@kernel.org>

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v4 02/14] dt/bindings: Document gpio-ingenic
  2017-04-02 20:42           ` [PATCH v4 02/14] dt/bindings: Document gpio-ingenic Paul Cercueil
@ 2017-04-04 14:52             ` Rob Herring
  0 siblings, 0 replies; 162+ messages in thread
From: Rob Herring @ 2017-04-04 14:52 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Linus Walleij, Alexandre Courbot, Mark Rutland, Ralf Baechle,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev

On Sun, Apr 02, 2017 at 10:42:32PM +0200, Paul Cercueil wrote:
> This commit adds documentation for the devicetree bindings of the
> gpio-ingenic driver, which handles GPIOs of the Ingenic SoCs
> currently supported by the Linux kernel.
> 
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
> ---
>  .../devicetree/bindings/gpio/ingenic,gpio.txt      | 48 ++++++++++++++++++++++
>  1 file changed, 48 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
> 
>  v2: New patch
>  v3: No changes
>  v4: Update for the v4 version of the gpio-ingenic driver
> 
> diff --git a/Documentation/devicetree/bindings/gpio/ingenic,gpio.txt b/Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
> new file mode 100644
> index 000000000000..f54af444f7c3
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
> @@ -0,0 +1,48 @@
> +Ingenic jz47xx GPIO controller
> +
> +That the Ingenic GPIO driver node must be a sub-node of the Ingenic pinctrl
> +driver node.
> +
> +Required properties:
> +--------------------
> +
> + - compatible: Must contain one of:
> +    - "ingenic,jz4740-gpio"
> +    - "ingenic,jz4770-gpio"
> +    - "ingenic,jz4780-gpio"
> +	And one of:
> +	- "ingenic,gpio-bank-a"
> +	- "ingenic,gpio-bank-b"
> +	- "ingenic,gpio-bank-c"
> +	- "ingenic,gpio-bank-d"
> +	- "ingenic,gpio-bank-e" (for SoC version > jz4740)
> +	- "ingenic,gpio-bank-f" (for SoC version > jz4740)

This is quite strange. Why do you need the bank? Doesn't gpio-ranges 
give you that info? Maybe use reg property here instead.

> + - interrupt-controller: Marks the device node as an interrupt controller.
> + - interrupts: Interrupt specifier for the controllers interrupt.
> + - #interrupt-cells: Should be 2. Refer to
> +   ../interrupt-controller/interrupts.txt for more details.
> + - gpio-controller: Marks the device node as a GPIO controller.
> + - #gpio-cells: Should be 2. The first cell is the GPIO number and the second
> +    cell specifies GPIO flags, as defined in <dt-bindings/gpio/gpio.h>. Only the
> +    GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported.
> + - gpio-ranges: Range of pins managed by the GPIO controller. Refer to
> +   'gpio.txt' in this directory for more details.
> +
> +Example:
> +--------
> +
> +&pinctrl {
> +	gpa: gpio-controller@0 {

gpio@...

> +		compatible = "ingenic,gpio-bank-a", "ingenic,jz4740-gpio";
> +
> +		gpio-controller;
> +		gpio-ranges = <&pinctrl 0 0 32>;
> +		#gpio-cells = <2>;
> +
> +		interrupt-controller;
> +		#interrupt-cells = <2>;
> +
> +		interrupt-parent = <&intc>;
> +		interrupts = <28>;
> +	};
> +};
> -- 
> 2.11.0
> 

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v4 13/14] pwm: jz4740: Let the pinctrl driver configure the pins
  2017-04-02 20:42           ` [PATCH v4 13/14] pwm: jz4740: " Paul Cercueil
@ 2017-04-06 14:40             ` Thierry Reding
  0 siblings, 0 replies; 162+ messages in thread
From: Thierry Reding @ 2017-04-06 14:40 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle, Boris Brezillon, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev

[-- Attachment #1: Type: text/plain, Size: 1455 bytes --]

On Sun, Apr 02, 2017 at 10:42:43PM +0200, Paul Cercueil wrote:
> Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
> the pins being properly configured before the driver probes.
> 
> One inherent problem of this new approach is that the pinctrl framework
> does not allow us to configure each pin on demand, when the various PWM
> channels are requested or released. For instance, the PWM channels can
> be configured from sysfs, which would require all PWM pins to be configured
> properly beforehand for the PWM function, eventually causing conflicts
> with other platform or board drivers.
> 
> The proper solution here would be to modify the pwm-jz4740 driver to
> handle only one PWM channel, and create an instance of this driver
> for each one of the 8 PWM channels. Then, it could use the pinctrl
> framework to dynamically configure the PWM pin it controls.
> 
> Until this can be done, the only jz4740 board supported upstream
> (Qi lb60) can configure all of its connected PWM pins in PWM function
> mode, since those are not used by other drivers nor by GPIOs on the
> board.
> 
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
> ---
>  drivers/pwm/pwm-jz4740.c | 29 -----------------------------
>  1 file changed, 29 deletions(-)

Assuming that you want to take this through the pinctrl tree along with
the remainder of the series:

Acked-by: Thierry Reding <thierry.reding@gmail.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v4 04/14] GPIO: Add gpio-ingenic driver
  2017-04-02 20:42           ` [PATCH v4 04/14] GPIO: Add gpio-ingenic driver Paul Cercueil
  2017-04-03 14:15             ` kbuild test robot
@ 2017-04-07  9:34             ` Linus Walleij
  1 sibling, 0 replies; 162+ messages in thread
From: Linus Walleij @ 2017-04-07  9:34 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Alexandre Courbot, Rob Herring, Mark Rutland, Ralf Baechle,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, James Hogan,
	linux-gpio, devicetree, linux-kernel, Linux MIPS, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev

On Sun, Apr 2, 2017 at 10:42 PM, Paul Cercueil <paul@crapouillou.net> wrote:

> This driver handles the GPIOs of all the Ingenic JZ47xx SoCs
> currently supported by the upsteam Linux kernel.
>
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>

I guess you saw the Kconfig complaint from the build robot, please fix that
so we get silent builds.

>  v2: Consider it's a new patch. Completely rewritten from v1.
>  v3: Add missing include <linux/pinctrl/consumer.h> and drop semicolon after }
>  v4: Completely rewritten from v3.

I really like v4 :)

> +static inline bool gpio_get_value(struct ingenic_gpio_chip *jzgc, u8 offset)

Actually the return value should be an int.

I know, it is a historical artifact, if we change it we need to change
it everywhere.

> +       /* DO NOT EXPAND THIS: FOR BACKWARD GPIO NUMBERSPACE COMPATIBIBILITY
> +        * ONLY: WORK TO TRANSITION CONSUMERS TO USE THE GPIO DESCRIPTOR API IN
> +        * <linux/gpio/consumer.h> INSTEAD.
> +        */
> +       jzgc->gc.base = cell->id * 32;

OK then :)

This is merge material.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v4 03/14] pinctrl-ingenic: add a pinctrl driver for the Ingenic jz47xx SoCs
  2017-04-02 20:42           ` [PATCH v4 03/14] pinctrl-ingenic: add a pinctrl driver for the Ingenic jz47xx SoCs Paul Cercueil
@ 2017-04-07  9:41             ` Linus Walleij
  2017-04-07 10:56               ` Lee Jones
  0 siblings, 1 reply; 162+ messages in thread
From: Linus Walleij @ 2017-04-07  9:41 UTC (permalink / raw)
  To: Paul Cercueil, Lee Jones
  Cc: Alexandre Courbot, Rob Herring, Mark Rutland, Ralf Baechle,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, James Hogan,
	linux-gpio, devicetree, linux-kernel, Linux MIPS, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev

On Sun, Apr 2, 2017 at 10:42 PM, Paul Cercueil <paul@crapouillou.net> wrote:

> This driver handles pin configuration and pin muxing for the
> JZ4740 and JZ4780 SoCs from Ingenic.
>
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
(...)
> +       select MFD_CORE
(...)
> +#include <linux/mfd/core.h>

That's unorthodox. Still quite pretty!
I would nee Lee Jones to say something about this, as it is
essentially hijacking MFD into the pinctrl subsystem.

> +static struct mfd_cell ingenic_pinctrl_mfd_cells[] = {
> +       {
> +               .id = 0,
> +               .name = "GPIOA",
> +               .of_compatible = "ingenic,gpio-bank-a",
> +       },
> +       {
> +               .id = 1,
> +               .name = "GPIOB",
> +               .of_compatible = "ingenic,gpio-bank-b",
> +       },
> +       {
> +               .id = 2,
> +               .name = "GPIOC",
> +               .of_compatible = "ingenic,gpio-bank-c",
> +       },
> +       {
> +               .id = 3,
> +               .name = "GPIOD",
> +               .of_compatible = "ingenic,gpio-bank-d",
> +       },
> +       {
> +               .id = 4,
> +               .name = "GPIOE",
> +               .of_compatible = "ingenic,gpio-bank-e",
> +       },
> +       {
> +               .id = 5,
> +               .name = "GPIOF",
> +               .of_compatible = "ingenic,gpio-bank-f",
> +       },
> +};
(...)
> +       err = devm_mfd_add_devices(dev, 0, ingenic_pinctrl_mfd_cells,
> +                       ARRAY_SIZE(ingenic_pinctrl_mfd_cells), NULL, 0, NULL);
> +       if (err) {
> +               dev_err(dev, "Failed to add MFD devices\n");
> +               return err;
> +       }

I guess the alternative would be to reimplement the MFD structure.

Did you check the approach to use "simple-mfd" and just let the subnodes
spawn as devices that way? I guess you did and this adds something
necessary.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v4 06/14] MIPS: jz4740: DTS: Add nodes for ingenic pinctrl and gpio drivers
  2017-04-02 20:42           ` [PATCH v4 06/14] MIPS: jz4740: DTS: Add nodes for ingenic pinctrl and gpio drivers Paul Cercueil
  2017-04-03  9:57             ` Sergei Shtylyov
@ 2017-04-07  9:44             ` Linus Walleij
  2017-04-07 13:57               ` Paul Cercueil
  1 sibling, 1 reply; 162+ messages in thread
From: Linus Walleij @ 2017-04-07  9:44 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Alexandre Courbot, Rob Herring, Mark Rutland, Ralf Baechle,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, James Hogan,
	linux-gpio, devicetree, linux-kernel, Linux MIPS, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev

On Sun, Apr 2, 2017 at 10:42 PM, Paul Cercueil <paul@crapouillou.net> wrote:

> For a description of the pinctrl devicetree node, please read
> Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
>
> For a description of the gpio devicetree nodes, please read
> Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
>
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
> ---
>  arch/mips/boot/dts/ingenic/jz4740.dtsi | 61 ++++++++++++++++++++++++++++++++++
>  1 file changed, 61 insertions(+)
>
>  v2: Changed the devicetree bindings to match the new driver
>  v3: No changes
>  v4: Update the bindings for the v4 version of the drivers
(...)

> +       pinctrl: ingenic-pinctrl@10010000 {
> +               compatible = "ingenic,jz4740-pinctrl";
> +               reg = <0x10010000 0x400>;
> +
> +               gpa: gpio-controller@0 {
> +                       compatible = "ingenic,gpio-bank-a", "ingenic,jz4740-gpio";

As Sergei and Rob notes, the bank compatible properties look
a bit strange. Especially if they are all the same essentially.

I like Sergei's idea to simply use the reg property if what you want
is really a unique ID number. What do you think about this?

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v4 03/14] pinctrl-ingenic: add a pinctrl driver for the Ingenic jz47xx SoCs
  2017-04-07  9:41             ` Linus Walleij
@ 2017-04-07 10:56               ` Lee Jones
  0 siblings, 0 replies; 162+ messages in thread
From: Lee Jones @ 2017-04-07 10:56 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Paul Cercueil, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle, Boris Brezillon, Thierry Reding,
	Bartlomiej Zolnierkiewicz, Maarten ter Huurne,
	Lars-Peter Clausen, Paul Burton, James Hogan, linux-gpio,
	devicetree, linux-kernel, Linux MIPS, linux-mmc, linux-mtd,
	linux-pwm, linux-fbdev

On Fri, 07 Apr 2017, Linus Walleij wrote:

> On Sun, Apr 2, 2017 at 10:42 PM, Paul Cercueil <paul@crapouillou.net> wrote:
> 
> > This driver handles pin configuration and pin muxing for the
> > JZ4740 and JZ4780 SoCs from Ingenic.
> >
> > Signed-off-by: Paul Cercueil <paul@crapouillou.net>
> (...)
> > +       select MFD_CORE
> (...)
> > +#include <linux/mfd/core.h>
> 
> That's unorthodox. Still quite pretty!
> I would nee Lee Jones to say something about this, as it is
> essentially hijacking MFD into the pinctrl subsystem.
> 
> > +static struct mfd_cell ingenic_pinctrl_mfd_cells[] = {
> > +       {
> > +               .id = 0,
> > +               .name = "GPIOA",
> > +               .of_compatible = "ingenic,gpio-bank-a",
> > +       },
> > +       {
> > +               .id = 1,
> > +               .name = "GPIOB",
> > +               .of_compatible = "ingenic,gpio-bank-b",
> > +       },
> > +       {
> > +               .id = 2,
> > +               .name = "GPIOC",
> > +               .of_compatible = "ingenic,gpio-bank-c",
> > +       },
> > +       {
> > +               .id = 3,
> > +               .name = "GPIOD",
> > +               .of_compatible = "ingenic,gpio-bank-d",
> > +       },
> > +       {
> > +               .id = 4,
> > +               .name = "GPIOE",
> > +               .of_compatible = "ingenic,gpio-bank-e",
> > +       },
> > +       {
> > +               .id = 5,
> > +               .name = "GPIOF",
> > +               .of_compatible = "ingenic,gpio-bank-f",
> > +       },
> > +};
> (...)
> > +       err = devm_mfd_add_devices(dev, 0, ingenic_pinctrl_mfd_cells,
> > +                       ARRAY_SIZE(ingenic_pinctrl_mfd_cells), NULL, 0, NULL);
> > +       if (err) {
> > +               dev_err(dev, "Failed to add MFD devices\n");
> > +               return err;
> > +       }
> 
> I guess the alternative would be to reimplement the MFD structure.
> 
> Did you check the approach to use "simple-mfd" and just let the subnodes
> spawn as devices that way? I guess you did and this adds something
> necessary.

I'd like to hear what the OP has to say about why this is necessary.
However, as a first glimpse, I'm dead against exporting MFD
functionality to outside of the subsystem.

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v4 06/14] MIPS: jz4740: DTS: Add nodes for ingenic pinctrl and gpio drivers
  2017-04-07  9:44             ` Linus Walleij
@ 2017-04-07 13:57               ` Paul Cercueil
  2017-04-24 12:58                 ` Linus Walleij
  0 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-04-07 13:57 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Alexandre Courbot, Rob Herring, Mark Rutland, Ralf Baechle,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, James Hogan,
	linux-gpio, devicetree, linux-kernel, Linux MIPS, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev

Le 2017-04-07 11:44, Linus Walleij a écrit :
> On Sun, Apr 2, 2017 at 10:42 PM, Paul Cercueil <paul@crapouillou.net> 
> wrote:
> 
>> For a description of the pinctrl devicetree node, please read
>> Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
>> 
>> For a description of the gpio devicetree nodes, please read
>> Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
>> 
>> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
>> ---
>>  arch/mips/boot/dts/ingenic/jz4740.dtsi | 61 
>> ++++++++++++++++++++++++++++++++++
>>  1 file changed, 61 insertions(+)
>> 
>>  v2: Changed the devicetree bindings to match the new driver
>>  v3: No changes
>>  v4: Update the bindings for the v4 version of the drivers
> (...)
> 
>> +       pinctrl: ingenic-pinctrl@10010000 {
>> +               compatible = "ingenic,jz4740-pinctrl";
>> +               reg = <0x10010000 0x400>;
>> +
>> +               gpa: gpio-controller@0 {
>> +                       compatible = "ingenic,gpio-bank-a", 
>> "ingenic,jz4740-gpio";
> 
> As Sergei and Rob notes, the bank compatible properties look
> a bit strange. Especially if they are all the same essentially.
> 
> I like Sergei's idea to simply use the reg property if what you want
> is really a unique ID number. What do you think about this?
> 
> Yours,
> Linus Walleij

I think the 'reg' property makes more sense, yes. I'll fix this in the 
v5, this
week-end. Do you think it can go in 4.12?

Thanks,
-Paul

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v4 06/14] MIPS: jz4740: DTS: Add nodes for ingenic pinctrl and gpio drivers
  2017-04-07 13:57               ` Paul Cercueil
@ 2017-04-24 12:58                 ` Linus Walleij
  0 siblings, 0 replies; 162+ messages in thread
From: Linus Walleij @ 2017-04-24 12:58 UTC (permalink / raw)
  To: Paul Cercueil
  Cc: Alexandre Courbot, Rob Herring, Mark Rutland, Ralf Baechle,
	Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, James Hogan,
	linux-gpio, devicetree, linux-kernel, Linux MIPS, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev

On Fri, Apr 7, 2017 at 3:57 PM, Paul Cercueil <paul@crapouillou.net> wrote:

> I think the 'reg' property makes more sense, yes. I'll fix this in the v5,
> this
> week-end. Do you think it can go in 4.12?

Surely, Torvalds just cut an -rc8 giving me more time to queue more
material, and I really like this series.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver
  2017-04-02 20:42           ` [PATCH v4 01/14] dt/bindings: Document pinctrl-ingenic Paul Cercueil
  2017-04-04 14:48             ` Rob Herring
@ 2017-04-28 20:08             ` Paul Cercueil
  2017-04-28 20:08               ` [PATCH v5 01/14] dt/bindings: Document pinctrl-ingenic Paul Cercueil
                                 ` (13 more replies)
  1 sibling, 14 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-04-28 20:08 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev

Hi,

This is the v5 of my Ingenic pinctrl / GPIO patch set.

The pinctrl driver now probes its children devices without using the MFD
subsystem; the GPIO driver now uses the 'reg' property to know the bank
number.

Best regards,
- Paul

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v5 01/14] dt/bindings: Document pinctrl-ingenic
  2017-04-28 20:08             ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
@ 2017-04-28 20:08               ` Paul Cercueil
  2017-05-12 16:52                 ` [PATCH v6 " Paul Cercueil
  2017-04-28 20:08               ` [PATCH v5 02/14] dt/bindings: Document gpio-ingenic Paul Cercueil
                                 ` (12 subsequent siblings)
  13 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-04-28 20:08 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

This commit adds documentation for the devicetree bindings of the
pinctrl-ingenic driver, which handles pin configuration and pin
muxing of the Ingenic SoCs currently supported by the Linux kernel.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Acked-by: Rob Herring <robh@kernel.org>
---
 .../bindings/pinctrl/ingenic,pinctrl.txt           | 41 ++++++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt

 v2: Rewrote the documentation for the new pinctrl-ingenic driver
 v3: No changes
 v4: Update for the v4 version of the pinctrl-ingenic driver
 v5: Rename 'ingenic-pinctrl@...' to 'pin-controller@...' in example

diff --git a/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
new file mode 100644
index 000000000000..ca313a7aeaff
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt
@@ -0,0 +1,41 @@
+Ingenic jz47xx pin controller
+
+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".
+
+For the jz47xx SoCs, pin control is tightly bound with GPIO ports. All pins may
+be used as GPIOs, multiplexed device functions are configured within the
+GPIO port configuration registers and it is typical to refer to pins using the
+naming scheme "PxN" where x is a character identifying the GPIO port with
+which the pin is associated and N is an integer from 0 to 31 identifying the
+pin within that GPIO port. For example PA0 is the first pin in GPIO port A, and
+PB31 is the last pin in GPIO port B. The jz4740 contains 4 GPIO ports, PA to
+PD, for a total of 128 pins. The jz4780 contains 6 GPIO ports, PA to PF, for a
+total of 192 pins.
+
+
+Required properties:
+--------------------
+
+ - compatible: One of:
+    - "ingenic,jz4740-pinctrl"
+    - "ingenic,jz4770-pinctrl"
+    - "ingenic,jz4780-pinctrl"
+ - reg: Address range of the pinctrl registers.
+
+
+GPIO sub-nodes
+--------------
+
+The pinctrl node can have optional sub-nodes for the Ingenic GPIO driver;
+please refer to ../gpio/ingenic,gpio.txt.
+
+
+Example:
+--------
+
+pinctrl: pin-controller@10010000 {
+	compatible = "ingenic,jz4740-pinctrl";
+	reg = <0x10010000 0x400>;
+};
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v5 02/14] dt/bindings: Document gpio-ingenic
  2017-04-28 20:08             ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
  2017-04-28 20:08               ` [PATCH v5 01/14] dt/bindings: Document pinctrl-ingenic Paul Cercueil
@ 2017-04-28 20:08               ` Paul Cercueil
  2017-05-05 19:57                 ` Rob Herring
  2017-04-28 20:08               ` [PATCH v5 03/14] pinctrl: add a pinctrl driver for the Ingenic jz47xx SoCs Paul Cercueil
                                 ` (11 subsequent siblings)
  13 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-04-28 20:08 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

This commit adds documentation for the devicetree bindings of the
gpio-ingenic driver, which handles GPIOs of the Ingenic SoCs
currently supported by the Linux kernel.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 .../devicetree/bindings/gpio/ingenic,gpio.txt      | 46 ++++++++++++++++++++++
 1 file changed, 46 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/gpio/ingenic,gpio.txt

 v2: New patch
 v3: No changes
 v4: Update for the v4 version of the gpio-ingenic driver
 v5: Remove gpio-bank-... compatible strings, and add 'reg' property

diff --git a/Documentation/devicetree/bindings/gpio/ingenic,gpio.txt b/Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
new file mode 100644
index 000000000000..7988aeb725f4
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/ingenic,gpio.txt
@@ -0,0 +1,46 @@
+Ingenic jz47xx GPIO controller
+
+That the Ingenic GPIO driver node must be a sub-node of the Ingenic pinctrl
+driver node.
+
+Required properties:
+--------------------
+
+ - compatible: Must contain one of:
+    - "ingenic,jz4740-gpio"
+    - "ingenic,jz4770-gpio"
+    - "ingenic,jz4780-gpio"
+ - reg: The GPIO bank number.
+ - interrupt-controller: Marks the device node as an interrupt controller.
+ - interrupts: Interrupt specifier for the controllers interrupt.
+ - #interrupt-cells: Should be 2. Refer to
+   ../interrupt-controller/interrupts.txt for more details.
+ - gpio-controller: Marks the device node as a GPIO controller.
+ - #gpio-cells: Should be 2. The first cell is the GPIO number and the second
+    cell specifies GPIO flags, as defined in <dt-bindings/gpio/gpio.h>. Only the
+    GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported.
+ - gpio-ranges: Range of pins managed by the GPIO controller. Refer to
+   'gpio.txt' in this directory for more details.
+
+Example:
+--------
+
+&pinctrl {
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	gpa: gpio@0 {
+		compatible = "ingenic,jz4740-gpio";
+		reg = <0>;
+
+		gpio-controller;
+		gpio-ranges = <&pinctrl 0 0 32>;
+		#gpio-cells = <2>;
+
+		interrupt-controller;
+		#interrupt-cells = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <28>;
+	};
+};
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v5 03/14] pinctrl: add a pinctrl driver for the Ingenic jz47xx SoCs
  2017-04-28 20:08             ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
  2017-04-28 20:08               ` [PATCH v5 01/14] dt/bindings: Document pinctrl-ingenic Paul Cercueil
  2017-04-28 20:08               ` [PATCH v5 02/14] dt/bindings: Document gpio-ingenic Paul Cercueil
@ 2017-04-28 20:08               ` Paul Cercueil
  2017-05-03  9:12                 ` Paul Cercueil
  2017-04-28 20:08               ` [PATCH v5 04/14] GPIO: Add gpio-ingenic driver Paul Cercueil
                                 ` (10 subsequent siblings)
  13 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-04-28 20:08 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

This driver handles pin configuration and pin muxing for the
JZ4740 and JZ4780 SoCs from Ingenic.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/pinctrl/Kconfig           |  10 +
 drivers/pinctrl/Makefile          |   1 +
 drivers/pinctrl/pinctrl-ingenic.c | 852 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 863 insertions(+)
 create mode 100644 drivers/pinctrl/pinctrl-ingenic.c

 v2: Consider it's a new patch. Completely rewritten from v1.
 v3: 'unsigned' -> 'unsigned int'
 v4: Completely rewritten from v3.
 v5: Probe child devices directly instead of using MFD framework

diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 8f8c2af45781..82ce72fcb8e0 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -285,6 +285,16 @@ config PINCTRL_ZYNQ
 	help
 	  This selects the pinctrl driver for Xilinx Zynq.
 
+config PINCTRL_INGENIC
+	bool "Pinctrl driver for the Ingenic JZ47xx SoCs"
+	default y
+	depends on MACH_INGENIC || COMPILE_TEST
+	select GENERIC_PINCONF
+	select GENERIC_PINCTRL_GROUPS
+	select GENERIC_PINMUX_FUNCTIONS
+	select REGMAP_MMIO
+	select MFD_CORE
+
 source "drivers/pinctrl/aspeed/Kconfig"
 source "drivers/pinctrl/bcm/Kconfig"
 source "drivers/pinctrl/berlin/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index a251f439626f..80f327239d4b 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_PINCTRL_LPC18XX)	+= pinctrl-lpc18xx.o
 obj-$(CONFIG_PINCTRL_TB10X)	+= pinctrl-tb10x.o
 obj-$(CONFIG_PINCTRL_ST) 	+= pinctrl-st.o
 obj-$(CONFIG_PINCTRL_ZYNQ)	+= pinctrl-zynq.o
+obj-$(CONFIG_PINCTRL_INGENIC)	+= pinctrl-ingenic.o
 
 obj-$(CONFIG_ARCH_ASPEED)	+= aspeed/
 obj-y				+= bcm/
diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-ingenic.c
new file mode 100644
index 000000000000..d8473d929cb1
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-ingenic.c
@@ -0,0 +1,852 @@
+/*
+ * Ingenic SoCs pinctrl driver
+ *
+ * Copyright (c) 2017 Paul Cercueil <paul@crapouillou.net>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/compiler.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include "core.h"
+#include "pinconf.h"
+#include "pinmux.h"
+
+#define JZ4740_GPIO_DATA	0x10
+#define JZ4740_GPIO_PULL_DIS	0x30
+#define JZ4740_GPIO_FUNC	0x40
+#define JZ4740_GPIO_SELECT	0x50
+#define JZ4740_GPIO_DIR		0x60
+#define JZ4740_GPIO_TRIG	0x70
+#define JZ4740_GPIO_FLAG	0x80
+
+#define JZ4770_GPIO_INT		0x10
+#define JZ4770_GPIO_MSK		0x20
+#define JZ4770_GPIO_PAT1	0x30
+#define JZ4770_GPIO_PAT0	0x40
+#define JZ4770_GPIO_FLAG	0x50
+#define JZ4770_GPIO_PEN		0x70
+
+#define REG_SET(x) ((x) + 0x4)
+#define REG_CLEAR(x) ((x) + 0x8)
+
+#define PINS_PER_GPIO_CHIP 32
+
+enum jz_version {
+	ID_JZ4740,
+	ID_JZ4770,
+	ID_JZ4780,
+};
+
+struct ingenic_chip_info {
+	unsigned int num_chips;
+
+	const struct group_desc *groups;
+	unsigned int num_groups;
+
+	const struct function_desc *functions;
+	unsigned int num_functions;
+
+	const u32 *pull_ups, *pull_downs;
+};
+
+struct ingenic_pinctrl {
+	struct device *dev;
+	struct regmap *map;
+	struct pinctrl_dev *pctl;
+	struct pinctrl_pin_desc *pdesc;
+	enum jz_version version;
+
+	const struct ingenic_chip_info *info;
+};
+
+static const u32 jz4740_pull_ups[4] = {
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+};
+
+static const u32 jz4740_pull_downs[4] = {
+	0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+static int jz4740_mmc_1bit_pins[] = { 0x69, 0x68, 0x6a, };
+static int jz4740_mmc_4bit_pins[] = { 0x6b, 0x6c, 0x6d, };
+static int jz4740_uart0_data_pins[] = { 0x7a, 0x79, };
+static int jz4740_uart0_hwflow_pins[] = { 0x7e, 0x7f, };
+static int jz4740_uart1_data_pins[] = { 0x7e, 0x7f, };
+static int jz4740_lcd_8bit_pins[] = {
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x52, 0x53, 0x54,
+};
+static int jz4740_lcd_16bit_pins[] = {
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x55,
+};
+static int jz4740_lcd_18bit_pins[] = { 0x50, 0x51, };
+static int jz4740_lcd_18bit_tft_pins[] = { 0x56, 0x57, 0x31, 0x32, };
+static int jz4740_nand_cs1_pins[] = { 0x39, };
+static int jz4740_nand_cs2_pins[] = { 0x3a, };
+static int jz4740_nand_cs3_pins[] = { 0x3b, };
+static int jz4740_nand_cs4_pins[] = { 0x3c, };
+static int jz4740_pwm_pwm0_pins[] = { 0x77, };
+static int jz4740_pwm_pwm1_pins[] = { 0x78, };
+static int jz4740_pwm_pwm2_pins[] = { 0x79, };
+static int jz4740_pwm_pwm3_pins[] = { 0x7a, };
+static int jz4740_pwm_pwm4_pins[] = { 0x7b, };
+static int jz4740_pwm_pwm5_pins[] = { 0x7c, };
+static int jz4740_pwm_pwm6_pins[] = { 0x7e, };
+static int jz4740_pwm_pwm7_pins[] = { 0x7f, };
+
+static int jz4740_mmc_1bit_funcs[] = { 0, 0, 0, };
+static int jz4740_mmc_4bit_funcs[] = { 0, 0, 0, };
+static int jz4740_uart0_data_funcs[] = { 1, 1, };
+static int jz4740_uart0_hwflow_funcs[] = { 1, 1, };
+static int jz4740_uart1_data_funcs[] = { 2, 2, };
+static int jz4740_lcd_8bit_funcs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
+static int jz4740_lcd_16bit_funcs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, };
+static int jz4740_lcd_18bit_funcs[] = { 0, 0, };
+static int jz4740_lcd_18bit_tft_funcs[] = { 0, 0, 0, 0, };
+static int jz4740_nand_cs1_funcs[] = { 0, };
+static int jz4740_nand_cs2_funcs[] = { 0, };
+static int jz4740_nand_cs3_funcs[] = { 0, };
+static int jz4740_nand_cs4_funcs[] = { 0, };
+static int jz4740_pwm_pwm0_funcs[] = { 0, };
+static int jz4740_pwm_pwm1_funcs[] = { 0, };
+static int jz4740_pwm_pwm2_funcs[] = { 0, };
+static int jz4740_pwm_pwm3_funcs[] = { 0, };
+static int jz4740_pwm_pwm4_funcs[] = { 0, };
+static int jz4740_pwm_pwm5_funcs[] = { 0, };
+static int jz4740_pwm_pwm6_funcs[] = { 0, };
+static int jz4740_pwm_pwm7_funcs[] = { 0, };
+
+#define INGENIC_PIN_GROUP(name, id)			\
+	{						\
+		name,					\
+		id##_pins,				\
+		ARRAY_SIZE(id##_pins),			\
+		id##_funcs,				\
+	}
+
+static const struct group_desc jz4740_groups[] = {
+	INGENIC_PIN_GROUP("mmc-1bit", jz4740_mmc_1bit),
+	INGENIC_PIN_GROUP("mmc-4bit", jz4740_mmc_4bit),
+	INGENIC_PIN_GROUP("uart0-data", jz4740_uart0_data),
+	INGENIC_PIN_GROUP("uart0-hwflow", jz4740_uart0_hwflow),
+	INGENIC_PIN_GROUP("uart1-data", jz4740_uart1_data),
+	INGENIC_PIN_GROUP("lcd-8bit", jz4740_lcd_8bit),
+	INGENIC_PIN_GROUP("lcd-16bit", jz4740_lcd_16bit),
+	INGENIC_PIN_GROUP("lcd-18bit", jz4740_lcd_18bit),
+	INGENIC_PIN_GROUP("lcd-18bit-tft", jz4740_lcd_18bit_tft),
+	{ "lcd-no-pins", },
+	INGENIC_PIN_GROUP("nand-cs1", jz4740_nand_cs1),
+	INGENIC_PIN_GROUP("nand-cs2", jz4740_nand_cs2),
+	INGENIC_PIN_GROUP("nand-cs3", jz4740_nand_cs3),
+	INGENIC_PIN_GROUP("nand-cs4", jz4740_nand_cs4),
+	INGENIC_PIN_GROUP("pwm0", jz4740_pwm_pwm0),
+	INGENIC_PIN_GROUP("pwm1", jz4740_pwm_pwm1),
+	INGENIC_PIN_GROUP("pwm2", jz4740_pwm_pwm2),
+	INGENIC_PIN_GROUP("pwm3", jz4740_pwm_pwm3),
+	INGENIC_PIN_GROUP("pwm4", jz4740_pwm_pwm4),
+	INGENIC_PIN_GROUP("pwm5", jz4740_pwm_pwm5),
+	INGENIC_PIN_GROUP("pwm6", jz4740_pwm_pwm6),
+	INGENIC_PIN_GROUP("pwm7", jz4740_pwm_pwm7),
+};
+
+static const char *jz4740_mmc_groups[] = { "mmc-1bit", "mmc-4bit", };
+static const char *jz4740_uart0_groups[] = { "uart0-data", "uart0-hwflow", };
+static const char *jz4740_uart1_groups[] = { "uart1-data", };
+static const char *jz4740_lcd_groups[] = {
+	"lcd-8bit", "lcd-16bit", "lcd-18bit", "lcd-18bit-tft", "lcd-no-pins",
+};
+static const char *jz4740_nand_groups[] = {
+	"nand-cs1", "nand-cs2", "nand-cs3", "nand-cs4",
+};
+static const char *jz4740_pwm0_groups[] = { "pwm0", };
+static const char *jz4740_pwm1_groups[] = { "pwm1", };
+static const char *jz4740_pwm2_groups[] = { "pwm2", };
+static const char *jz4740_pwm3_groups[] = { "pwm3", };
+static const char *jz4740_pwm4_groups[] = { "pwm4", };
+static const char *jz4740_pwm5_groups[] = { "pwm5", };
+static const char *jz4740_pwm6_groups[] = { "pwm6", };
+static const char *jz4740_pwm7_groups[] = { "pwm7", };
+
+static const struct function_desc jz4740_functions[] = {
+	{ "mmc", jz4740_mmc_groups, ARRAY_SIZE(jz4740_mmc_groups), },
+	{ "uart0", jz4740_uart0_groups, ARRAY_SIZE(jz4740_uart0_groups), },
+	{ "uart1", jz4740_uart1_groups, ARRAY_SIZE(jz4740_uart1_groups), },
+	{ "lcd", jz4740_lcd_groups, ARRAY_SIZE(jz4740_lcd_groups), },
+	{ "nand", jz4740_nand_groups, ARRAY_SIZE(jz4740_nand_groups), },
+	{ "pwm0", jz4740_pwm0_groups, ARRAY_SIZE(jz4740_pwm0_groups), },
+	{ "pwm1", jz4740_pwm1_groups, ARRAY_SIZE(jz4740_pwm1_groups), },
+	{ "pwm2", jz4740_pwm2_groups, ARRAY_SIZE(jz4740_pwm2_groups), },
+	{ "pwm3", jz4740_pwm3_groups, ARRAY_SIZE(jz4740_pwm3_groups), },
+	{ "pwm4", jz4740_pwm4_groups, ARRAY_SIZE(jz4740_pwm4_groups), },
+	{ "pwm5", jz4740_pwm5_groups, ARRAY_SIZE(jz4740_pwm5_groups), },
+	{ "pwm6", jz4740_pwm6_groups, ARRAY_SIZE(jz4740_pwm6_groups), },
+	{ "pwm7", jz4740_pwm7_groups, ARRAY_SIZE(jz4740_pwm7_groups), },
+};
+
+static const struct ingenic_chip_info jz4740_chip_info = {
+	.num_chips = 4,
+	.groups = jz4740_groups,
+	.num_groups = ARRAY_SIZE(jz4740_groups),
+	.functions = jz4740_functions,
+	.num_functions = ARRAY_SIZE(jz4740_functions),
+	.pull_ups = jz4740_pull_ups,
+	.pull_downs = jz4740_pull_downs,
+};
+
+static const u32 jz4770_pull_ups[6] = {
+	0x3fffffff, 0xfff0030c, 0xffffffff, 0xffff4fff, 0xfffffb7c, 0xffa7f00f,
+};
+
+static const u32 jz4770_pull_downs[6] = {
+	0x00000000, 0x000f0c03, 0x00000000, 0x0000b000, 0x00000483, 0x00580ff0,
+};
+
+static int jz4770_uart0_data_pins[] = { 0xa0, 0xa3, };
+static int jz4770_uart0_hwflow_pins[] = { 0xa1, 0xa2, };
+static int jz4770_uart1_data_pins[] = { 0x7a, 0x7c, };
+static int jz4770_uart1_hwflow_pins[] = { 0x7b, 0x7d, };
+static int jz4770_uart2_data_pins[] = { 0x66, 0x67, };
+static int jz4770_uart2_hwflow_pins[] = { 0x65, 0x64, };
+static int jz4770_uart3_data_pins[] = { 0x6c, 0x85, };
+static int jz4770_uart3_hwflow_pins[] = { 0x88, 0x89, };
+static int jz4770_uart4_data_pins[] = { 0x54, 0x4a, };
+static int jz4770_mmc0_8bit_a_pins[] = { 0x04, 0x05, 0x06, 0x07, 0x18, };
+static int jz4770_mmc0_4bit_a_pins[] = { 0x15, 0x16, 0x17, };
+static int jz4770_mmc0_1bit_a_pins[] = { 0x12, 0x13, 0x14, };
+static int jz4770_mmc0_4bit_e_pins[] = { 0x95, 0x96, 0x97, };
+static int jz4770_mmc0_1bit_e_pins[] = { 0x9c, 0x9d, 0x94, };
+static int jz4770_mmc1_4bit_d_pins[] = { 0x75, 0x76, 0x77, };
+static int jz4770_mmc1_1bit_d_pins[] = { 0x78, 0x79, 0x74, };
+static int jz4770_mmc1_4bit_e_pins[] = { 0x95, 0x96, 0x97, };
+static int jz4770_mmc1_1bit_e_pins[] = { 0x9c, 0x9d, 0x94, };
+static int jz4770_nemc_data_pins[] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+};
+static int jz4770_nemc_cle_ale_pins[] = { 0x20, 0x21, };
+static int jz4770_nemc_addr_pins[] = { 0x22, 0x23, 0x24, 0x25, };
+static int jz4770_nemc_rd_we_pins[] = { 0x10, 0x11, };
+static int jz4770_nemc_frd_fwe_pins[] = { 0x12, 0x13, };
+static int jz4770_nemc_cs1_pins[] = { 0x15, };
+static int jz4770_nemc_cs2_pins[] = { 0x16, };
+static int jz4770_nemc_cs3_pins[] = { 0x17, };
+static int jz4770_nemc_cs4_pins[] = { 0x18, };
+static int jz4770_nemc_cs5_pins[] = { 0x19, };
+static int jz4770_nemc_cs6_pins[] = { 0x1a, };
+static int jz4770_i2c0_pins[] = { 0x6e, 0x6f, };
+static int jz4770_i2c1_pins[] = { 0x8e, 0x8f, };
+static int jz4770_i2c2_pins[] = { 0xb0, 0xb1, };
+static int jz4770_i2c3_pins[] = { 0x6a, 0x6b, };
+static int jz4770_i2c4_e_pins[] = { 0x8c, 0x8d, };
+static int jz4770_i2c4_f_pins[] = { 0xb9, 0xb8, };
+static int jz4770_cim_pins[] = {
+	0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31,
+};
+static int jz4770_lcd_32bit_pins[] = {
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+	0x58, 0x59, 0x51,
+};
+static int jz4770_pwm_pwm0_pins[] = { 0x80, };
+static int jz4770_pwm_pwm1_pins[] = { 0x81, };
+static int jz4770_pwm_pwm2_pins[] = { 0x82, };
+static int jz4770_pwm_pwm3_pins[] = { 0x83, };
+static int jz4770_pwm_pwm4_pins[] = { 0x84, };
+static int jz4770_pwm_pwm5_pins[] = { 0x85, };
+static int jz4770_pwm_pwm6_pins[] = { 0x6a, };
+static int jz4770_pwm_pwm7_pins[] = { 0x6b, };
+
+static int jz4770_uart0_data_funcs[] = { 0, 0, };
+static int jz4770_uart0_hwflow_funcs[] = { 0, 0, };
+static int jz4770_uart1_data_funcs[] = { 0, 0, };
+static int jz4770_uart1_hwflow_funcs[] = { 0, 0, };
+static int jz4770_uart2_data_funcs[] = { 1, 1, };
+static int jz4770_uart2_hwflow_funcs[] = { 1, 1, };
+static int jz4770_uart3_data_funcs[] = { 0, 1, };
+static int jz4770_uart3_hwflow_funcs[] = { 0, 0, };
+static int jz4770_uart4_data_funcs[] = { 2, 2, };
+static int jz4770_mmc0_8bit_a_funcs[] = { 1, 1, 1, 1, 1, };
+static int jz4770_mmc0_4bit_a_funcs[] = { 1, 1, 1, };
+static int jz4770_mmc0_1bit_a_funcs[] = { 1, 1, 0, };
+static int jz4770_mmc0_4bit_e_funcs[] = { 0, 0, 0, };
+static int jz4770_mmc0_1bit_e_funcs[] = { 0, 0, 0, };
+static int jz4770_mmc1_4bit_d_funcs[] = { 0, 0, 0, };
+static int jz4770_mmc1_1bit_d_funcs[] = { 0, 0, 0, };
+static int jz4770_mmc1_4bit_e_funcs[] = { 1, 1, 1, };
+static int jz4770_mmc1_1bit_e_funcs[] = { 1, 1, 1, };
+static int jz4770_nemc_data_funcs[] = { 0, 0, 0, 0, 0, 0, 0, 0, };
+static int jz4770_nemc_cle_ale_funcs[] = { 0, 0, };
+static int jz4770_nemc_addr_funcs[] = { 0, 0, 0, 0, };
+static int jz4770_nemc_rd_we_funcs[] = { 0, 0, };
+static int jz4770_nemc_frd_fwe_funcs[] = { 0, 0, };
+static int jz4770_nemc_cs1_funcs[] = { 0, };
+static int jz4770_nemc_cs2_funcs[] = { 0, };
+static int jz4770_nemc_cs3_funcs[] = { 0, };
+static int jz4770_nemc_cs4_funcs[] = { 0, };
+static int jz4770_nemc_cs5_funcs[] = { 0, };
+static int jz4770_nemc_cs6_funcs[] = { 0, };
+static int jz4770_i2c0_funcs[] = { 0, 0, };
+static int jz4770_i2c1_funcs[] = { 0, 0, };
+static int jz4770_i2c2_funcs[] = { 2, 2, };
+static int jz4770_i2c3_funcs[] = { 1, 1, };
+static int jz4770_i2c4_e_funcs[] = { 1, 1, };
+static int jz4770_i2c4_f_funcs[] = { 1, 1, };
+static int jz4770_cim_funcs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
+static int jz4770_lcd_32bit_funcs[] = {
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0,
+};
+static int jz4770_pwm_pwm0_funcs[] = { 0, };
+static int jz4770_pwm_pwm1_funcs[] = { 0, };
+static int jz4770_pwm_pwm2_funcs[] = { 0, };
+static int jz4770_pwm_pwm3_funcs[] = { 0, };
+static int jz4770_pwm_pwm4_funcs[] = { 0, };
+static int jz4770_pwm_pwm5_funcs[] = { 0, };
+static int jz4770_pwm_pwm6_funcs[] = { 0, };
+static int jz4770_pwm_pwm7_funcs[] = { 0, };
+
+static const struct group_desc jz4770_groups[] = {
+	INGENIC_PIN_GROUP("uart0-data", jz4770_uart0_data),
+	INGENIC_PIN_GROUP("uart0-hwflow", jz4770_uart0_hwflow),
+	INGENIC_PIN_GROUP("uart1-data", jz4770_uart1_data),
+	INGENIC_PIN_GROUP("uart1-hwflow", jz4770_uart1_hwflow),
+	INGENIC_PIN_GROUP("uart2-data", jz4770_uart2_data),
+	INGENIC_PIN_GROUP("uart2-hwflow", jz4770_uart2_hwflow),
+	INGENIC_PIN_GROUP("uart3-data", jz4770_uart3_data),
+	INGENIC_PIN_GROUP("uart3-hwflow", jz4770_uart3_hwflow),
+	INGENIC_PIN_GROUP("uart4-data", jz4770_uart4_data),
+	INGENIC_PIN_GROUP("mmc0-8bit-a", jz4770_mmc0_8bit_a),
+	INGENIC_PIN_GROUP("mmc0-4bit-a", jz4770_mmc0_4bit_a),
+	INGENIC_PIN_GROUP("mmc0-1bit-a", jz4770_mmc0_1bit_a),
+	INGENIC_PIN_GROUP("mmc0-4bit-e", jz4770_mmc0_4bit_e),
+	INGENIC_PIN_GROUP("mmc0-1bit-e", jz4770_mmc0_1bit_e),
+	INGENIC_PIN_GROUP("mmc1-4bit-d", jz4770_mmc1_4bit_d),
+	INGENIC_PIN_GROUP("mmc1-1bit-d", jz4770_mmc1_1bit_d),
+	INGENIC_PIN_GROUP("mmc1-4bit-e", jz4770_mmc1_4bit_e),
+	INGENIC_PIN_GROUP("mmc1-1bit-e", jz4770_mmc1_1bit_e),
+	INGENIC_PIN_GROUP("nemc-data", jz4770_nemc_data),
+	INGENIC_PIN_GROUP("nemc-cle-ale", jz4770_nemc_cle_ale),
+	INGENIC_PIN_GROUP("nemc-addr", jz4770_nemc_addr),
+	INGENIC_PIN_GROUP("nemc-rd-we", jz4770_nemc_rd_we),
+	INGENIC_PIN_GROUP("nemc-frd-fwe", jz4770_nemc_frd_fwe),
+	INGENIC_PIN_GROUP("nemc-cs1", jz4770_nemc_cs1),
+	INGENIC_PIN_GROUP("nemc-cs2", jz4770_nemc_cs2),
+	INGENIC_PIN_GROUP("nemc-cs3", jz4770_nemc_cs3),
+	INGENIC_PIN_GROUP("nemc-cs4", jz4770_nemc_cs4),
+	INGENIC_PIN_GROUP("nemc-cs5", jz4770_nemc_cs5),
+	INGENIC_PIN_GROUP("nemc-cs6", jz4770_nemc_cs6),
+	INGENIC_PIN_GROUP("i2c0-data", jz4770_i2c0),
+	INGENIC_PIN_GROUP("i2c1-data", jz4770_i2c1),
+	INGENIC_PIN_GROUP("i2c2-data", jz4770_i2c2),
+	INGENIC_PIN_GROUP("i2c3-data", jz4770_i2c3),
+	INGENIC_PIN_GROUP("i2c4-data-e", jz4770_i2c4_e),
+	INGENIC_PIN_GROUP("i2c4-data-f", jz4770_i2c4_f),
+	INGENIC_PIN_GROUP("cim-data", jz4770_cim),
+	INGENIC_PIN_GROUP("lcd-32bit", jz4770_lcd_32bit),
+	{ "lcd-no-pins", },
+	INGENIC_PIN_GROUP("pwm0", jz4770_pwm_pwm0),
+	INGENIC_PIN_GROUP("pwm1", jz4770_pwm_pwm1),
+	INGENIC_PIN_GROUP("pwm2", jz4770_pwm_pwm2),
+	INGENIC_PIN_GROUP("pwm3", jz4770_pwm_pwm3),
+	INGENIC_PIN_GROUP("pwm4", jz4770_pwm_pwm4),
+	INGENIC_PIN_GROUP("pwm5", jz4770_pwm_pwm5),
+	INGENIC_PIN_GROUP("pwm6", jz4770_pwm_pwm6),
+	INGENIC_PIN_GROUP("pwm7", jz4770_pwm_pwm7),
+};
+
+static const char *jz4770_uart0_groups[] = { "uart0-data", "uart0-hwflow", };
+static const char *jz4770_uart1_groups[] = { "uart1-data", "uart1-hwflow", };
+static const char *jz4770_uart2_groups[] = { "uart2-data", "uart2-hwflow", };
+static const char *jz4770_uart3_groups[] = { "uart3-data", "uart3-hwflow", };
+static const char *jz4770_uart4_groups[] = { "uart4-data", };
+static const char *jz4770_mmc0_groups[] = {
+	"mmc0-8bit-a", "mmc0-4bit-a", "mmc0-1bit-a",
+	"mmc0-1bit-e", "mmc0-4bit-e",
+};
+static const char *jz4770_mmc1_groups[] = {
+	"mmc1-1bit-d", "mmc1-4bit-d", "mmc1-1bit-e", "mmc1-4bit-e",
+};
+static const char *jz4770_nemc_groups[] = {
+	"nemc-data", "nemc-cle-ale", "nemc-addr", "nemc-rd-we", "nemc-frd-fwe",
+};
+static const char *jz4770_cs1_groups[] = { "nemc-cs1", };
+static const char *jz4770_cs6_groups[] = { "nemc-cs6", };
+static const char *jz4770_i2c0_groups[] = { "i2c0-data", };
+static const char *jz4770_i2c1_groups[] = { "i2c1-data", };
+static const char *jz4770_i2c2_groups[] = { "i2c2-data", };
+static const char *jz4770_i2c3_groups[] = { "i2c3-data", };
+static const char *jz4770_i2c4_groups[] = { "i2c4-data-e", "i2c4-data-f", };
+static const char *jz4770_cim_groups[] = { "cim-data", };
+static const char *jz4770_lcd_groups[] = { "lcd-32bit", "lcd-no-pins", };
+static const char *jz4770_pwm0_groups[] = { "pwm0", };
+static const char *jz4770_pwm1_groups[] = { "pwm1", };
+static const char *jz4770_pwm2_groups[] = { "pwm2", };
+static const char *jz4770_pwm3_groups[] = { "pwm3", };
+static const char *jz4770_pwm4_groups[] = { "pwm4", };
+static const char *jz4770_pwm5_groups[] = { "pwm5", };
+static const char *jz4770_pwm6_groups[] = { "pwm6", };
+static const char *jz4770_pwm7_groups[] = { "pwm7", };
+
+static const struct function_desc jz4770_functions[] = {
+	{ "uart0", jz4770_uart0_groups, ARRAY_SIZE(jz4770_uart0_groups), },
+	{ "uart1", jz4770_uart1_groups, ARRAY_SIZE(jz4770_uart1_groups), },
+	{ "uart2", jz4770_uart2_groups, ARRAY_SIZE(jz4770_uart2_groups), },
+	{ "uart3", jz4770_uart3_groups, ARRAY_SIZE(jz4770_uart3_groups), },
+	{ "uart4", jz4770_uart4_groups, ARRAY_SIZE(jz4770_uart4_groups), },
+	{ "mmc0", jz4770_mmc0_groups, ARRAY_SIZE(jz4770_mmc0_groups), },
+	{ "mmc1", jz4770_mmc1_groups, ARRAY_SIZE(jz4770_mmc1_groups), },
+	{ "nemc", jz4770_nemc_groups, ARRAY_SIZE(jz4770_nemc_groups), },
+	{ "nemc-cs1", jz4770_cs1_groups, ARRAY_SIZE(jz4770_cs1_groups), },
+	{ "nemc-cs6", jz4770_cs6_groups, ARRAY_SIZE(jz4770_cs6_groups), },
+	{ "i2c0", jz4770_i2c0_groups, ARRAY_SIZE(jz4770_i2c0_groups), },
+	{ "i2c1", jz4770_i2c1_groups, ARRAY_SIZE(jz4770_i2c1_groups), },
+	{ "i2c2", jz4770_i2c2_groups, ARRAY_SIZE(jz4770_i2c2_groups), },
+	{ "i2c3", jz4770_i2c3_groups, ARRAY_SIZE(jz4770_i2c3_groups), },
+	{ "i2c4", jz4770_i2c4_groups, ARRAY_SIZE(jz4770_i2c4_groups), },
+	{ "cim", jz4770_cim_groups, ARRAY_SIZE(jz4770_cim_groups), },
+	{ "lcd", jz4770_lcd_groups, ARRAY_SIZE(jz4770_lcd_groups), },
+	{ "pwm0", jz4770_pwm0_groups, ARRAY_SIZE(jz4770_pwm0_groups), },
+	{ "pwm1", jz4770_pwm1_groups, ARRAY_SIZE(jz4770_pwm1_groups), },
+	{ "pwm2", jz4770_pwm2_groups, ARRAY_SIZE(jz4770_pwm2_groups), },
+	{ "pwm3", jz4770_pwm3_groups, ARRAY_SIZE(jz4770_pwm3_groups), },
+	{ "pwm4", jz4770_pwm4_groups, ARRAY_SIZE(jz4770_pwm4_groups), },
+	{ "pwm5", jz4770_pwm5_groups, ARRAY_SIZE(jz4770_pwm5_groups), },
+	{ "pwm6", jz4770_pwm6_groups, ARRAY_SIZE(jz4770_pwm6_groups), },
+	{ "pwm7", jz4770_pwm7_groups, ARRAY_SIZE(jz4770_pwm7_groups), },
+};
+
+static const struct ingenic_chip_info jz4770_chip_info = {
+	.num_chips = 6,
+	.groups = jz4770_groups,
+	.num_groups = ARRAY_SIZE(jz4770_groups),
+	.functions = jz4770_functions,
+	.num_functions = ARRAY_SIZE(jz4770_functions),
+	.pull_ups = jz4770_pull_ups,
+	.pull_downs = jz4770_pull_downs,
+};
+
+static inline void ingenic_config_pin(struct ingenic_pinctrl *jzpc,
+		unsigned int pin, u8 reg, bool set)
+{
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+
+	regmap_write(jzpc->map, offt * 0x100 +
+			(set ? REG_SET(reg) : REG_CLEAR(reg)), BIT(idx));
+}
+
+static inline bool ingenic_get_pin_config(struct ingenic_pinctrl *jzpc,
+		unsigned int pin, u8 reg)
+{
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+	unsigned int val;
+
+	regmap_read(jzpc->map, offt * 0x100 + reg, &val);
+
+	return val & BIT(idx);
+}
+
+static struct pinctrl_ops ingenic_pctlops = {
+	.get_groups_count = pinctrl_generic_get_group_count,
+	.get_group_name = pinctrl_generic_get_group_name,
+	.get_group_pins = pinctrl_generic_get_group_pins,
+	.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
+	.dt_free_map = pinconf_generic_dt_free_map,
+};
+
+static int ingenic_pinmux_set_pin_fn(struct ingenic_pinctrl *jzpc,
+		int pin, int func)
+{
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+
+	dev_dbg(jzpc->dev, "set pin P%c%u to function %u\n",
+			'A' + offt, idx, func);
+
+	if (jzpc->version >= ID_JZ4770) {
+		ingenic_config_pin(jzpc, pin, JZ4770_GPIO_INT, false);
+		ingenic_config_pin(jzpc, pin, JZ4770_GPIO_MSK, false);
+		ingenic_config_pin(jzpc, pin, JZ4770_GPIO_PAT1, func & 0x2);
+		ingenic_config_pin(jzpc, pin, JZ4770_GPIO_PAT0, func & 0x1);
+	} else {
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_FUNC, true);
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_TRIG, func & 0x2);
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_SELECT, func > 0);
+	}
+
+	return 0;
+}
+
+static int ingenic_pinmux_set_mux(struct pinctrl_dev *pctldev,
+		unsigned int selector, unsigned int group)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	struct function_desc *func;
+	struct group_desc *grp;
+	unsigned int i;
+
+	func = pinmux_generic_get_function(pctldev, selector);
+	if (!func)
+		return -EINVAL;
+
+	grp = pinctrl_generic_get_group(pctldev, group);
+	if (!grp)
+		return -EINVAL;
+
+	dev_dbg(pctldev->dev, "enable function %s group %s\n",
+		func->name, grp->name);
+
+	for (i = 0; i < grp->num_pins; i++) {
+		int *pin_modes = grp->data;
+
+		ingenic_pinmux_set_pin_fn(jzpc, grp->pins[i], pin_modes[i]);
+	}
+
+	return 0;
+}
+
+static int ingenic_pinmux_gpio_set_direction(struct pinctrl_dev *pctldev,
+		struct pinctrl_gpio_range *range,
+		unsigned int pin, bool input)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+
+	dev_dbg(pctldev->dev, "set pin P%c%u to %sput\n",
+			'A' + offt, idx, input ? "in" : "out");
+
+	if (jzpc->version >= ID_JZ4770) {
+		ingenic_config_pin(jzpc, pin, JZ4770_GPIO_INT, false);
+		ingenic_config_pin(jzpc, pin, JZ4770_GPIO_MSK, true);
+		ingenic_config_pin(jzpc, pin, JZ4770_GPIO_PAT1, input);
+	} else {
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_SELECT, false);
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_DIR, input);
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_FUNC, false);
+	}
+
+	return 0;
+}
+
+static struct pinmux_ops ingenic_pmxops = {
+	.get_functions_count = pinmux_generic_get_function_count,
+	.get_function_name = pinmux_generic_get_function_name,
+	.get_function_groups = pinmux_generic_get_function_groups,
+	.set_mux = ingenic_pinmux_set_mux,
+	.gpio_set_direction = ingenic_pinmux_gpio_set_direction,
+};
+
+static int ingenic_pinconf_get(struct pinctrl_dev *pctldev,
+		unsigned int pin, unsigned long *config)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	enum pin_config_param param = pinconf_to_config_param(*config);
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+	bool pull;
+
+	if (jzpc->version >= ID_JZ4770)
+		pull = !ingenic_get_pin_config(jzpc, pin, JZ4770_GPIO_PEN);
+	else
+		pull = !ingenic_get_pin_config(jzpc, pin, JZ4740_GPIO_PULL_DIS);
+
+	switch (param) {
+	case PIN_CONFIG_BIAS_DISABLE:
+		if (pull)
+			return -EINVAL;
+		break;
+
+	case PIN_CONFIG_BIAS_PULL_UP:
+		if (!pull || !(jzpc->info->pull_ups[offt] & BIT(idx)))
+			return -EINVAL;
+		break;
+
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		if (!pull || !(jzpc->info->pull_downs[offt] & BIT(idx)))
+			return -EINVAL;
+		break;
+
+	default:
+		return -ENOTSUPP;
+	}
+
+	*config = pinconf_to_config_packed(param, 1);
+	return 0;
+}
+
+static void ingenic_set_bias(struct ingenic_pinctrl *jzpc,
+		unsigned int pin, bool enabled)
+{
+	if (jzpc->version >= ID_JZ4770)
+		ingenic_config_pin(jzpc, pin, JZ4770_GPIO_PEN, !enabled);
+	else
+		ingenic_config_pin(jzpc, pin, JZ4740_GPIO_PULL_DIS, !enabled);
+}
+
+static int ingenic_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
+		unsigned long *configs, unsigned int num_configs)
+{
+	struct ingenic_pinctrl *jzpc = pinctrl_dev_get_drvdata(pctldev);
+	unsigned int idx = pin % PINS_PER_GPIO_CHIP;
+	unsigned int offt = pin / PINS_PER_GPIO_CHIP;
+	unsigned int cfg;
+
+	for (cfg = 0; cfg < num_configs; cfg++) {
+		switch (pinconf_to_config_param(configs[cfg])) {
+		case PIN_CONFIG_BIAS_DISABLE:
+		case PIN_CONFIG_BIAS_PULL_UP:
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			continue;
+		default:
+			return -ENOTSUPP;
+		}
+	}
+
+	for (cfg = 0; cfg < num_configs; cfg++) {
+		switch (pinconf_to_config_param(configs[cfg])) {
+		case PIN_CONFIG_BIAS_DISABLE:
+			dev_dbg(jzpc->dev, "disable pull-over for pin P%c%u\n",
+					'A' + offt, idx);
+			ingenic_set_bias(jzpc, pin, false);
+			break;
+
+		case PIN_CONFIG_BIAS_PULL_UP:
+			if (!(jzpc->info->pull_ups[offt] & BIT(idx)))
+				return -EINVAL;
+			dev_dbg(jzpc->dev, "set pull-up for pin P%c%u\n",
+					'A' + offt, idx);
+			ingenic_set_bias(jzpc, pin, true);
+			break;
+
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			if (!(jzpc->info->pull_downs[offt] & BIT(idx)))
+				return -EINVAL;
+			dev_dbg(jzpc->dev, "set pull-down for pin P%c%u\n",
+					'A' + offt, idx);
+			ingenic_set_bias(jzpc, pin, true);
+			break;
+
+		default:
+			unreachable();
+		}
+	}
+
+	return 0;
+}
+
+static int ingenic_pinconf_group_get(struct pinctrl_dev *pctldev,
+		unsigned int group, unsigned long *config)
+{
+	const unsigned int *pins;
+	unsigned int i, npins, old = 0;
+	int ret;
+
+	ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < npins; i++) {
+		if (ingenic_pinconf_get(pctldev, pins[i], config))
+			return -ENOTSUPP;
+
+		/* configs do not match between two pins */
+		if (i && (old != *config))
+			return -ENOTSUPP;
+
+		old = *config;
+	}
+
+	return 0;
+}
+
+static int ingenic_pinconf_group_set(struct pinctrl_dev *pctldev,
+		unsigned int group, unsigned long *configs,
+		unsigned int num_configs)
+{
+	const unsigned int *pins;
+	unsigned int i, npins;
+	int ret;
+
+	ret = pinctrl_generic_get_group_pins(pctldev, group, &pins, &npins);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < npins; i++) {
+		ret = ingenic_pinconf_set(pctldev,
+				pins[i], configs, num_configs);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static struct pinconf_ops ingenic_confops = {
+	.is_generic = true,
+	.pin_config_get = ingenic_pinconf_get,
+	.pin_config_set = ingenic_pinconf_set,
+	.pin_config_group_get = ingenic_pinconf_group_get,
+	.pin_config_group_set = ingenic_pinconf_group_set,
+};
+
+static const struct regmap_config ingenic_pinctrl_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+};
+
+static const struct of_device_id ingenic_pinctrl_of_match[] = {
+	{ .compatible = "ingenic,jz4740-pinctrl", .data = (void *) ID_JZ4740 },
+	{ .compatible = "ingenic,jz4770-pinctrl", .data = (void *) ID_JZ4770 },
+	{ .compatible = "ingenic,jz4780-pinctrl", .data = (void *) ID_JZ4780 },
+	{},
+};
+
+int ingenic_pinctrl_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct ingenic_pinctrl *jzpc;
+	struct pinctrl_desc *pctl_desc;
+	void __iomem *base;
+	const struct platform_device_id *id = platform_get_device_id(pdev);
+	const struct of_device_id *of_id = of_match_device(
+			ingenic_pinctrl_of_match, dev);
+	const struct ingenic_chip_info *chip_info;
+	unsigned int i;
+	int err;
+
+	jzpc = devm_kzalloc(dev, sizeof(*jzpc), GFP_KERNEL);
+	if (!jzpc)
+		return -ENOMEM;
+
+	base = devm_ioremap_resource(dev,
+			platform_get_resource(pdev, IORESOURCE_MEM, 0));
+	if (IS_ERR(base)) {
+		dev_err(dev, "Failed to ioremap registers\n");
+		return PTR_ERR(base);
+	}
+
+	jzpc->map = devm_regmap_init_mmio(dev, base,
+			&ingenic_pinctrl_regmap_config);
+	if (IS_ERR(jzpc->map)) {
+		dev_err(dev, "Failed to create regmap\n");
+		return PTR_ERR(jzpc->map);
+	}
+
+	jzpc->dev = dev;
+
+	if (of_id)
+		jzpc->version = (enum jz_version)of_id->data;
+	else
+		jzpc->version = (enum jz_version)id->driver_data;
+
+	if (jzpc->version >= ID_JZ4770)
+		chip_info = &jz4770_chip_info;
+	else
+		chip_info = &jz4740_chip_info;
+	jzpc->info = chip_info;
+
+	pctl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctl_desc), GFP_KERNEL);
+	if (!pctl_desc)
+		return -ENOMEM;
+
+	/* fill in pinctrl_desc structure */
+	pctl_desc->name = dev_name(dev);
+	pctl_desc->owner = THIS_MODULE;
+	pctl_desc->pctlops = &ingenic_pctlops;
+	pctl_desc->pmxops = &ingenic_pmxops;
+	pctl_desc->confops = &ingenic_confops;
+	pctl_desc->npins = chip_info->num_chips * PINS_PER_GPIO_CHIP;
+	pctl_desc->pins = jzpc->pdesc = devm_kzalloc(&pdev->dev,
+			sizeof(*jzpc->pdesc) * pctl_desc->npins, GFP_KERNEL);
+	if (!jzpc->pdesc)
+		return -ENOMEM;
+
+	for (i = 0; i < pctl_desc->npins; i++) {
+		jzpc->pdesc[i].number = i;
+		jzpc->pdesc[i].name = kasprintf(GFP_KERNEL, "P%c%d",
+						'A' + (i / PINS_PER_GPIO_CHIP),
+						i % PINS_PER_GPIO_CHIP);
+	}
+
+	jzpc->pctl = devm_pinctrl_register(dev, pctl_desc, jzpc);
+	if (!jzpc->pctl) {
+		dev_err(dev, "Failed to register pinctrl\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < chip_info->num_groups; i++) {
+		const struct group_desc *group = &chip_info->groups[i];
+
+		err = pinctrl_generic_add_group(jzpc->pctl, group->name,
+				group->pins, group->num_pins, group->data);
+		if (err) {
+			dev_err(dev, "Failed to register group %s\n",
+					group->name);
+			return err;
+		}
+	}
+
+	for (i = 0; i < chip_info->num_functions; i++) {
+		const struct function_desc *func = &chip_info->functions[i];
+
+		err = pinmux_generic_add_function(jzpc->pctl, func->name,
+				func->group_names, func->num_group_names,
+				func->data);
+		if (err) {
+			dev_err(dev, "Failed to register function %s\n",
+					func->name);
+			return err;
+		}
+	}
+
+	dev_set_drvdata(dev, jzpc->map);
+
+	if (dev->of_node) {
+		err = of_platform_populate(dev->of_node, NULL, NULL, dev);
+		if (err) {
+			dev_err(dev, "Failed to probe GPIO devices\n");
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static const struct platform_device_id ingenic_pinctrl_ids[] = {
+	{ "jz4740-pinctrl", ID_JZ4740 },
+	{ "jz4770-pinctrl", ID_JZ4770 },
+	{ "jz4780-pinctrl", ID_JZ4780 },
+	{},
+};
+
+static struct platform_driver ingenic_pinctrl_driver = {
+	.driver = {
+		.name = "pinctrl-ingenic",
+		.of_match_table = of_match_ptr(ingenic_pinctrl_of_match),
+		.suppress_bind_attrs = true,
+	},
+	.probe = ingenic_pinctrl_probe,
+	.id_table = ingenic_pinctrl_ids,
+};
+
+static int __init ingenic_pinctrl_drv_register(void)
+{
+	return platform_driver_register(&ingenic_pinctrl_driver);
+}
+postcore_initcall(ingenic_pinctrl_drv_register);
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v5 04/14] GPIO: Add gpio-ingenic driver
  2017-04-28 20:08             ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                                 ` (2 preceding siblings ...)
  2017-04-28 20:08               ` [PATCH v5 03/14] pinctrl: add a pinctrl driver for the Ingenic jz47xx SoCs Paul Cercueil
@ 2017-04-28 20:08               ` Paul Cercueil
  2017-05-07 22:05                 ` Paul Cercueil
  2017-04-28 20:08               ` [PATCH v5 05/14] MIPS: ingenic: Enable pinctrl for all ingenic SoCs Paul Cercueil
                                 ` (9 subsequent siblings)
  13 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-04-28 20:08 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

This driver handles the GPIOs of all the Ingenic JZ47xx SoCs
currently supported by the upsteam Linux kernel.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/gpio/Kconfig        |  10 ++
 drivers/gpio/Makefile       |   1 +
 drivers/gpio/gpio-ingenic.c | 399 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 410 insertions(+)
 create mode 100644 drivers/gpio/gpio-ingenic.c

 v2: Consider it's a new patch. Completely rewritten from v1.
 v3: Add missing include <linux/pinctrl/consumer.h> and drop semicolon after }
 v4: Completely rewritten from v3.
 v5: Get bank number from 'reg' property; drop dependency on PINCTRL_INGENIC
     (note: selecting PINCTRL would cause cyclic Kconfig dependencies, that's
      why I just dropped the dependency on PINCTRL_INGENIC)

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 05043071fc98..7a5f9cf123c1 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -241,6 +241,16 @@ config GPIO_ICH
 
 	  If unsure, say N.
 
+config GPIO_INGENIC
+	tristate "Ingenic JZ47xx SoCs GPIO support"
+	depends on MACH_INGENIC || COMPILE_TEST
+	select GPIOLIB_IRQCHIP
+	help
+	  Say yes here to support the GPIO functionality present on the
+	  JZ4740 and JZ4780 SoCs from Ingenic.
+
+	  If unsure, say N.
+
 config GPIO_IOP
 	tristate "Intel IOP GPIO"
 	depends on ARCH_IOP32X || ARCH_IOP33X || COMPILE_TEST
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index becb96c724fe..3fceb4ab3ca7 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_GPIO_GPIO_MM)	+= gpio-gpio-mm.o
 obj-$(CONFIG_GPIO_GRGPIO)	+= gpio-grgpio.o
 obj-$(CONFIG_HTC_EGPIO)		+= gpio-htc-egpio.o
 obj-$(CONFIG_GPIO_ICH)		+= gpio-ich.o
+obj-$(CONFIG_GPIO_INGENIC)	+= gpio-ingenic.o
 obj-$(CONFIG_GPIO_IOP)		+= gpio-iop.o
 obj-$(CONFIG_GPIO_IT87)		+= gpio-it87.o
 obj-$(CONFIG_GPIO_JANZ_TTL)	+= gpio-janz-ttl.o
diff --git a/drivers/gpio/gpio-ingenic.c b/drivers/gpio/gpio-ingenic.c
new file mode 100644
index 000000000000..34e9339bd815
--- /dev/null
+++ b/drivers/gpio/gpio-ingenic.c
@@ -0,0 +1,399 @@
+/*
+ * Ingenic JZ47xx GPIO driver
+ *
+ * Copyright (c) 2017 Paul Cercueil <paul@crapouillou.net>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/regmap.h>
+
+#define GPIO_PIN	0x00
+#define GPIO_MSK	0x20
+
+#define JZ4740_GPIO_DATA	0x10
+#define JZ4740_GPIO_SELECT	0x50
+#define JZ4740_GPIO_DIR		0x60
+#define JZ4740_GPIO_TRIG	0x70
+#define JZ4740_GPIO_FLAG	0x80
+
+#define JZ4770_GPIO_INT		0x10
+#define JZ4770_GPIO_PAT1	0x30
+#define JZ4770_GPIO_PAT0	0x40
+#define JZ4770_GPIO_FLAG	0x50
+
+#define REG_SET(x) ((x) + 0x4)
+#define REG_CLEAR(x) ((x) + 0x8)
+
+enum jz_version {
+	ID_JZ4740,
+	ID_JZ4770,
+	ID_JZ4780,
+};
+
+struct ingenic_gpio_chip {
+	struct regmap *map;
+	struct gpio_chip gc;
+	struct irq_chip irq_chip;
+	unsigned int irq, reg_base;
+	enum jz_version version;
+};
+
+static u32 gpio_ingenic_read_reg(struct ingenic_gpio_chip *jzgc, u8 reg)
+{
+	unsigned int val;
+
+	regmap_read(jzgc->map, jzgc->reg_base + reg, &val);
+
+	return (u32) val;
+}
+
+static void gpio_ingenic_set_bit(struct ingenic_gpio_chip *jzgc,
+		u8 reg, u8 offset, bool set)
+{
+	if (set)
+		reg = REG_SET(reg);
+	else
+		reg = REG_CLEAR(reg);
+
+	regmap_write(jzgc->map, jzgc->reg_base + reg, BIT(offset));
+}
+
+static inline bool gpio_get_value(struct ingenic_gpio_chip *jzgc, u8 offset)
+{
+	unsigned int val;
+
+	if (jzgc->version >= ID_JZ4770)
+		val = gpio_ingenic_read_reg(jzgc, GPIO_PIN);
+	else
+		val = gpio_ingenic_read_reg(jzgc, JZ4740_GPIO_DATA);
+
+	return !!(val & BIT(offset));
+}
+
+static void gpio_set_value(struct ingenic_gpio_chip *jzgc, u8 offset, int value)
+{
+	if (jzgc->version >= ID_JZ4770)
+		gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_PAT0, offset, !!value);
+	else
+		gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_DATA, offset, !!value);
+}
+
+static void irq_set_type(struct ingenic_gpio_chip *jzgc,
+		u8 offset, unsigned int type)
+{
+	u8 reg1, reg2;
+
+	if (jzgc->version >= ID_JZ4770) {
+		reg1 = JZ4770_GPIO_PAT1;
+		reg2 = JZ4770_GPIO_PAT0;
+	} else {
+		reg1 = JZ4740_GPIO_TRIG;
+		reg2 = JZ4740_GPIO_DIR;
+	}
+
+	switch (type) {
+	case IRQ_TYPE_EDGE_RISING:
+		gpio_ingenic_set_bit(jzgc, reg2, offset, true);
+		gpio_ingenic_set_bit(jzgc, reg1, offset, true);
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		gpio_ingenic_set_bit(jzgc, reg2, offset, false);
+		gpio_ingenic_set_bit(jzgc, reg1, offset, true);
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		gpio_ingenic_set_bit(jzgc, reg2, offset, true);
+		gpio_ingenic_set_bit(jzgc, reg1, offset, false);
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+	default:
+		gpio_ingenic_set_bit(jzgc, reg2, offset, false);
+		gpio_ingenic_set_bit(jzgc, reg1, offset, false);
+		break;
+	}
+}
+
+static void ingenic_gpio_irq_mask(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	gpio_ingenic_set_bit(jzgc, GPIO_MSK, irqd->hwirq, true);
+}
+
+static void ingenic_gpio_irq_unmask(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	gpio_ingenic_set_bit(jzgc, GPIO_MSK, irqd->hwirq, false);
+}
+
+static void ingenic_gpio_irq_enable(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+	int irq = irqd->hwirq;
+
+	if (jzgc->version >= ID_JZ4770)
+		gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_INT, irq, true);
+	else
+		gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_SELECT, irq, true);
+
+	ingenic_gpio_irq_unmask(irqd);
+}
+
+static void ingenic_gpio_irq_disable(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+	int irq = irqd->hwirq;
+
+	ingenic_gpio_irq_mask(irqd);
+
+	if (jzgc->version >= ID_JZ4770)
+		gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_INT, irq, false);
+	else
+		gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_SELECT, irq, false);
+}
+
+static void ingenic_gpio_irq_ack(struct irq_data *irqd)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+	int irq = irqd->hwirq;
+	bool high;
+
+	if (irqd_get_trigger_type(irqd) == IRQ_TYPE_EDGE_BOTH) {
+		/*
+		 * Switch to an interrupt for the opposite edge to the one that
+		 * triggered the interrupt being ACKed.
+		 */
+		high = gpio_get_value(jzgc, irq);
+		if (high)
+			irq_set_type(jzgc, irq, IRQ_TYPE_EDGE_FALLING);
+		else
+			irq_set_type(jzgc, irq, IRQ_TYPE_EDGE_RISING);
+	}
+
+	if (jzgc->version >= ID_JZ4770)
+		gpio_ingenic_set_bit(jzgc, JZ4770_GPIO_FLAG, irq, false);
+	else
+		gpio_ingenic_set_bit(jzgc, JZ4740_GPIO_DATA, irq, true);
+}
+
+static int ingenic_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	switch (type) {
+	case IRQ_TYPE_EDGE_BOTH:
+	case IRQ_TYPE_EDGE_RISING:
+	case IRQ_TYPE_EDGE_FALLING:
+		irq_set_handler_locked(irqd, handle_edge_irq);
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+	case IRQ_TYPE_LEVEL_LOW:
+		irq_set_handler_locked(irqd, handle_level_irq);
+		break;
+	default:
+		irq_set_handler_locked(irqd, handle_bad_irq);
+	}
+
+	if (type == IRQ_TYPE_EDGE_BOTH) {
+		/*
+		 * The hardware does not support interrupts on both edges. The
+		 * best we can do is to set up a single-edge interrupt and then
+		 * switch to the opposing edge when ACKing the interrupt.
+		 */
+		bool high = gpio_get_value(jzgc, irqd->hwirq);
+
+		type = high ? IRQ_TYPE_EDGE_FALLING : IRQ_TYPE_EDGE_RISING;
+	}
+
+	irq_set_type(jzgc, irqd->hwirq, type);
+	return 0;
+}
+
+static int ingenic_gpio_irq_set_wake(struct irq_data *irqd, unsigned int on)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	return irq_set_irq_wake(jzgc->irq, on);
+}
+
+static void ingenic_gpio_irq_handler(struct irq_desc *desc)
+{
+	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+	struct irq_chip *irq_chip = irq_data_get_irq_chip(&desc->irq_data);
+	unsigned long flag, i;
+
+	chained_irq_enter(irq_chip, desc);
+
+	if (jzgc->version >= ID_JZ4770)
+		flag = gpio_ingenic_read_reg(jzgc, JZ4770_GPIO_FLAG);
+	else
+		flag = gpio_ingenic_read_reg(jzgc, JZ4740_GPIO_FLAG);
+
+	for_each_set_bit(i, &flag, 32)
+		generic_handle_irq(irq_linear_revmap(gc->irqdomain, i));
+	chained_irq_exit(irq_chip, desc);
+}
+
+static void ingenic_gpio_set(struct gpio_chip *gc,
+		unsigned int offset, int value)
+{
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	gpio_set_value(jzgc, offset, value);
+}
+
+static int ingenic_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+	struct ingenic_gpio_chip *jzgc = gpiochip_get_data(gc);
+
+	return (int) gpio_get_value(jzgc, offset);
+}
+
+static int ingenic_gpio_direction_input(struct gpio_chip *gc,
+		unsigned int offset)
+{
+	return pinctrl_gpio_direction_input(gc->base + offset);
+}
+
+static int ingenic_gpio_direction_output(struct gpio_chip *gc,
+		unsigned int offset, int value)
+{
+	ingenic_gpio_set(gc, offset, value);
+	return pinctrl_gpio_direction_output(gc->base + offset);
+}
+
+static const struct of_device_id ingenic_gpio_of_match[] = {
+	{ .compatible = "ingenic,jz4740-gpio", .data = (void *)ID_JZ4740 },
+	{ .compatible = "ingenic,jz4770-gpio", .data = (void *)ID_JZ4770 },
+	{ .compatible = "ingenic,jz4780-gpio", .data = (void *)ID_JZ4780 },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ingenic_gpio_of_match);
+
+static int ingenic_gpio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	const struct of_device_id *of_id = of_match_device(
+			ingenic_gpio_of_match, dev);
+	struct ingenic_gpio_chip *jzgc;
+	u32 bank;
+	int err;
+
+	jzgc = devm_kzalloc(dev, sizeof(*jzgc), GFP_KERNEL);
+	if (!jzgc)
+		return -ENOMEM;
+
+	jzgc->map = dev_get_drvdata(dev->parent);
+	if (!jzgc->map) {
+		dev_err(dev, "Cannot get parent regmap\n");
+		return -ENXIO;
+	}
+
+	err = of_property_read_u32(dev->of_node, "reg", &bank);
+	if (err) {
+		dev_err(dev, "Cannot read \"reg\" property: %i\n", err);
+		return err;
+	}
+
+	jzgc->reg_base = bank * 0x100;
+
+	jzgc->gc.label = devm_kasprintf(dev, GFP_KERNEL, "GPIO%c", 'A' + bank);
+	if (!jzgc->gc.label)
+		return -ENOMEM;
+
+	/* DO NOT EXPAND THIS: FOR BACKWARD GPIO NUMBERSPACE COMPATIBIBILITY
+	 * ONLY: WORK TO TRANSITION CONSUMERS TO USE THE GPIO DESCRIPTOR API IN
+	 * <linux/gpio/consumer.h> INSTEAD.
+	 */
+	jzgc->gc.base = bank * 32;
+
+	jzgc->gc.ngpio = 32;
+	jzgc->gc.parent = dev;
+	jzgc->gc.of_node = dev->of_node;
+	jzgc->gc.owner = THIS_MODULE;
+	jzgc->version = (enum jz_version)of_id->data;
+
+	jzgc->gc.set = ingenic_gpio_set;
+	jzgc->gc.get = ingenic_gpio_get;
+	jzgc->gc.direction_input = ingenic_gpio_direction_input;
+	jzgc->gc.direction_output = ingenic_gpio_direction_output;
+
+	if (of_property_read_bool(dev->of_node, "gpio-ranges")) {
+		jzgc->gc.request = gpiochip_generic_request;
+		jzgc->gc.free = gpiochip_generic_free;
+	}
+
+	err = devm_gpiochip_add_data(dev, &jzgc->gc, jzgc);
+	if (err)
+		return err;
+
+	jzgc->irq = irq_of_parse_and_map(dev->of_node, 0);
+	if (!jzgc->irq)
+		return -EINVAL;
+
+	jzgc->irq_chip.name = jzgc->gc.label;
+	jzgc->irq_chip.irq_enable = ingenic_gpio_irq_enable;
+	jzgc->irq_chip.irq_disable = ingenic_gpio_irq_disable;
+	jzgc->irq_chip.irq_unmask = ingenic_gpio_irq_unmask;
+	jzgc->irq_chip.irq_mask = ingenic_gpio_irq_mask;
+	jzgc->irq_chip.irq_ack = ingenic_gpio_irq_ack;
+	jzgc->irq_chip.irq_set_type = ingenic_gpio_irq_set_type;
+	jzgc->irq_chip.irq_set_wake = ingenic_gpio_irq_set_wake;
+	jzgc->irq_chip.flags = IRQCHIP_MASK_ON_SUSPEND;
+
+	err = gpiochip_irqchip_add(&jzgc->gc, &jzgc->irq_chip, 0,
+			handle_level_irq, IRQ_TYPE_NONE);
+	if (err)
+		return err;
+
+	gpiochip_set_chained_irqchip(&jzgc->gc, &jzgc->irq_chip,
+			jzgc->irq, ingenic_gpio_irq_handler);
+	return 0;
+}
+
+static int ingenic_gpio_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver ingenic_gpio_driver = {
+	.driver = {
+		.name = "gpio-ingenic",
+		.of_match_table = of_match_ptr(ingenic_gpio_of_match),
+	},
+	.probe = ingenic_gpio_probe,
+	.remove = ingenic_gpio_remove,
+};
+
+static int __init ingenic_gpio_drv_register(void)
+{
+	return platform_driver_register(&ingenic_gpio_driver);
+}
+subsys_initcall(ingenic_gpio_drv_register);
+
+static void __exit ingenic_gpio_drv_unregister(void)
+{
+	platform_driver_unregister(&ingenic_gpio_driver);
+}
+module_exit(ingenic_gpio_drv_unregister);
+
+MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
+MODULE_DESCRIPTION("Ingenic JZ47xx GPIO driver");
+MODULE_LICENSE("GPL");
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v5 05/14] MIPS: ingenic: Enable pinctrl for all ingenic SoCs
  2017-04-28 20:08             ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                                 ` (3 preceding siblings ...)
  2017-04-28 20:08               ` [PATCH v5 04/14] GPIO: Add gpio-ingenic driver Paul Cercueil
@ 2017-04-28 20:08               ` Paul Cercueil
  2017-05-11 11:08                 ` Linus Walleij
  2017-05-22 15:31                 ` Linus Walleij
  2017-04-28 20:08               ` [PATCH v5 06/14] MIPS: jz4740: DTS: Add nodes for ingenic pinctrl and gpio drivers Paul Cercueil
                                 ` (8 subsequent siblings)
  13 siblings, 2 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-04-28 20:08 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

There is a pinctrl driver for each of the Ingenic SoCs supported by the
upstream Linux kernel. In order to switch away from the old GPIO
platform code, we now enable the pinctrl drivers by default for the
Ingenic SoCs.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/Kconfig | 1 +
 1 file changed, 1 insertion(+)

 v2: No changes
 v3: No changes
 v4: No changes
 v5: No changes

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index e0bb576410bb..771995b75e0d 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -363,6 +363,7 @@ config MACH_INGENIC
 	select SYS_SUPPORTS_ZBOOT_UART16550
 	select DMA_NONCOHERENT
 	select IRQ_MIPS_CPU
+	select PINCTRL
 	select GPIOLIB
 	select COMMON_CLK
 	select GENERIC_IRQ_CHIP
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v5 06/14] MIPS: jz4740: DTS: Add nodes for ingenic pinctrl and gpio drivers
  2017-04-28 20:08             ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                                 ` (4 preceding siblings ...)
  2017-04-28 20:08               ` [PATCH v5 05/14] MIPS: ingenic: Enable pinctrl for all ingenic SoCs Paul Cercueil
@ 2017-04-28 20:08               ` Paul Cercueil
  2017-04-28 20:08               ` [PATCH v5 07/14] MIPS: jz4780: " Paul Cercueil
                                 ` (7 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-04-28 20:08 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

For a description of the pinctrl devicetree node, please read
Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt

For a description of the gpio devicetree nodes, please read
Documentation/devicetree/bindings/gpio/ingenic,gpio.txt

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/boot/dts/ingenic/jz4740.dtsi | 68 ++++++++++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)

 v2: Changed the devicetree bindings to match the new driver
 v3: No changes
 v4: Update the bindings for the v4 version of the drivers
 v5: Add 'reg' properties and rename pinctrl/gpio nodes

diff --git a/arch/mips/boot/dts/ingenic/jz4740.dtsi b/arch/mips/boot/dts/ingenic/jz4740.dtsi
index 3e1587f1f77a..2ca7ce7481f1 100644
--- a/arch/mips/boot/dts/ingenic/jz4740.dtsi
+++ b/arch/mips/boot/dts/ingenic/jz4740.dtsi
@@ -55,6 +55,74 @@
 		clock-names = "rtc";
 	};
 
+	pinctrl: pin-controller@10010000 {
+		compatible = "ingenic,jz4740-pinctrl";
+		reg = <0x10010000 0x400>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		gpa: gpio@0 {
+			compatible = "ingenic,jz4740-gpio";
+			reg = <0>;
+
+			gpio-controller;
+			gpio-ranges = <&pinctrl 0 0 32>;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+
+			interrupt-parent = <&intc>;
+			interrupts = <28>;
+		};
+
+		gpb: gpio@1 {
+			compatible = "ingenic,jz4740-gpio";
+			reg = <1>;
+
+			gpio-controller;
+			gpio-ranges = <&pinctrl 0 32 32>;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+
+			interrupt-parent = <&intc>;
+			interrupts = <27>;
+		};
+
+		gpc: gpio@2 {
+			compatible = "ingenic,jz4740-gpio";
+			reg = <2>;
+
+			gpio-controller;
+			gpio-ranges = <&pinctrl 0 64 32>;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+
+			interrupt-parent = <&intc>;
+			interrupts = <26>;
+		};
+
+		gpd: gpio@3 {
+			compatible = "ingenic,jz4740-gpio";
+			reg = <3>;
+
+			gpio-controller;
+			gpio-ranges = <&pinctrl 0 96 32>;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+
+			interrupt-parent = <&intc>;
+			interrupts = <25>;
+		};
+	};
+
 	uart0: serial@10030000 {
 		compatible = "ingenic,jz4740-uart";
 		reg = <0x10030000 0x100>;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v5 07/14] MIPS: jz4780: DTS: Add nodes for ingenic pinctrl and gpio drivers
  2017-04-28 20:08             ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                                 ` (5 preceding siblings ...)
  2017-04-28 20:08               ` [PATCH v5 06/14] MIPS: jz4740: DTS: Add nodes for ingenic pinctrl and gpio drivers Paul Cercueil
@ 2017-04-28 20:08               ` Paul Cercueil
  2017-04-28 20:08               ` [PATCH v5 08/14] MIPS: JZ4740: Qi LB60: Add pinctrl configuration for several drivers Paul Cercueil
                                 ` (6 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-04-28 20:08 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

For a description of the devicetree node, please read
Documentation/devicetree/bindings/pinctrl/ingenic,pinctrl.txt

For a description of the gpio devicetree nodes, please read
Documentation/devicetree/bindings/gpio/ingenic,gpio.txt

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/boot/dts/ingenic/jz4780.dtsi | 98 ++++++++++++++++++++++++++++++++++
 1 file changed, 98 insertions(+)

 v2: Changed the devicetree bindings to match the new driver
 v3: No changes
 v4: Update the bindings for the v4 version of the drivers
 v5: Add 'reg' properties and rename pinctrl/gpio nodes

diff --git a/arch/mips/boot/dts/ingenic/jz4780.dtsi b/arch/mips/boot/dts/ingenic/jz4780.dtsi
index b868b429add2..4853ef67b3ab 100644
--- a/arch/mips/boot/dts/ingenic/jz4780.dtsi
+++ b/arch/mips/boot/dts/ingenic/jz4780.dtsi
@@ -44,6 +44,104 @@
 		#clock-cells = <1>;
 	};
 
+	pinctrl: pin-controller@10010000 {
+		compatible = "ingenic,jz4780-pinctrl";
+		reg = <0x10010000 0x600>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		gpa: gpio@0 {
+			compatible = "ingenic,jz4780-gpio";
+			reg = <0>;
+
+			gpio-controller;
+			gpio-ranges = <&pinctrl 0 0 32>;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+
+			interrupt-parent = <&intc>;
+			interrupts = <17>;
+		};
+
+		gpb: gpio@1 {
+			compatible = "ingenic,jz4780-gpio";
+			reg = <1>;
+
+			gpio-controller;
+			gpio-ranges = <&pinctrl 0 32 32>;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+
+			interrupt-parent = <&intc>;
+			interrupts = <16>;
+		};
+
+		gpc: gpio@2 {
+			compatible = "ingenic,jz4780-gpio";
+			reg = <2>;
+
+			gpio-controller;
+			gpio-ranges = <&pinctrl 0 64 32>;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+
+			interrupt-parent = <&intc>;
+			interrupts = <15>;
+		};
+
+		gpd: gpio@3 {
+			compatible = "ingenic,jz4780-gpio";
+			reg = <3>;
+
+			gpio-controller;
+			gpio-ranges = <&pinctrl 0 96 32>;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+
+			interrupt-parent = <&intc>;
+			interrupts = <14>;
+		};
+
+		gpe: gpio@4 {
+			compatible = "ingenic,jz4780-gpio";
+			reg = <4>;
+
+			gpio-controller;
+			gpio-ranges = <&pinctrl 0 128 32>;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+
+			interrupt-parent = <&intc>;
+			interrupts = <13>;
+		};
+
+		gpf: gpio@5 {
+			compatible = "ingenic,jz4780-gpio";
+			reg = <5>;
+
+			gpio-controller;
+			gpio-ranges = <&pinctrl 0 160 32>;
+			#gpio-cells = <2>;
+
+			interrupt-controller;
+			#interrupt-cells = <2>;
+
+			interrupt-parent = <&intc>;
+			interrupts = <12>;
+		};
+	};
+
 	uart0: serial@10030000 {
 		compatible = "ingenic,jz4780-uart";
 		reg = <0x10030000 0x100>;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v5 08/14] MIPS: JZ4740: Qi LB60: Add pinctrl configuration for several drivers
  2017-04-28 20:08             ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                                 ` (6 preceding siblings ...)
  2017-04-28 20:08               ` [PATCH v5 07/14] MIPS: jz4780: " Paul Cercueil
@ 2017-04-28 20:08               ` Paul Cercueil
  2017-04-28 20:08               ` [PATCH v5 09/14] MIPS: JZ4780: CI20: " Paul Cercueil
                                 ` (5 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-04-28 20:08 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

We set the pin configuration for the jz4740-nand, jz4740-mmc,
jz4740-fb, jz4740-pwm and jz4740-uart drivers.

This will permit those drivers to be cleaned out of the custom GPIO code
that they currently use.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/boot/dts/ingenic/qi_lb60.dts | 13 +++++++++++
 arch/mips/jz4740/board-qi_lb60.c       | 42 ++++++++++++++++++++++++++--------
 2 files changed, 46 insertions(+), 9 deletions(-)

 v2: Changed the devicetree bindings to match the new driver
 v3: No changes
 v4: No changes
 v5: No changes

diff --git a/arch/mips/boot/dts/ingenic/qi_lb60.dts b/arch/mips/boot/dts/ingenic/qi_lb60.dts
index be1a7d3a3e1b..b715ee2ac2ee 100644
--- a/arch/mips/boot/dts/ingenic/qi_lb60.dts
+++ b/arch/mips/boot/dts/ingenic/qi_lb60.dts
@@ -17,3 +17,16 @@
 &rtc_dev {
 	system-power-controller;
 };
+
+&uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart0>;
+};
+
+&pinctrl {
+	pins_uart0: uart0 {
+		function = "uart0";
+		groups = "uart0-data";
+		bias-disable;
+	};
+};
diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c
index a5bd94b95263..bf3dcc9ee9f8 100644
--- a/arch/mips/jz4740/board-qi_lb60.c
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -22,6 +22,8 @@
 #include <linux/input/matrix_keypad.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_gpio.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf-generic.h>
 #include <linux/power_supply.h>
 #include <linux/power/jz4740-battery.h>
 #include <linux/power/gpio-charger.h>
@@ -447,13 +449,36 @@ static struct platform_device *jz_platform_devices[] __initdata = {
 	&qi_lb60_audio_device,
 };
 
-static void __init board_gpio_setup(void)
-{
-	/* We only need to enable/disable pullup here for pins used in generic
-	 * drivers. Everything else is done by the drivers themselves. */
-	jz_gpio_disable_pullup(QI_LB60_GPIO_SD_VCC_EN_N);
-	jz_gpio_disable_pullup(QI_LB60_GPIO_SD_CD);
-}
+static unsigned long pin_cfg_bias_disable[] = {
+	    PIN_CONFIG_BIAS_DISABLE,
+};
+
+static struct pinctrl_map pin_map[] __initdata = {
+	/* NAND pin configuration */
+	PIN_MAP_MUX_GROUP_DEFAULT("jz4740-nand",
+			"10010000.jz4740-pinctrl", "nand", "nand"),
+
+	/* fbdev pin configuration */
+	PIN_MAP_MUX_GROUP("jz4740-fb", PINCTRL_STATE_DEFAULT,
+			"10010000.jz4740-pinctrl", "lcd", "lcd-8bit"),
+	PIN_MAP_MUX_GROUP("jz4740-fb", PINCTRL_STATE_SLEEP,
+			"10010000.jz4740-pinctrl", "lcd", "lcd-no-pins"),
+
+	/* MMC pin configuration */
+	PIN_MAP_MUX_GROUP_DEFAULT("jz4740-mmc.0",
+			"10010000.jz4740-pinctrl", "mmc", "mmc-1bit"),
+	PIN_MAP_MUX_GROUP_DEFAULT("jz4740-mmc.0",
+			"10010000.jz4740-pinctrl", "mmc", "mmc-4bit"),
+	PIN_MAP_CONFIGS_PIN_DEFAULT("jz4740-mmc.0",
+			"10010000.jz4740-pinctrl", "PD0", pin_cfg_bias_disable),
+	PIN_MAP_CONFIGS_PIN_DEFAULT("jz4740-mmc.0",
+			"10010000.jz4740-pinctrl", "PD2", pin_cfg_bias_disable),
+
+	/* PWM pin configuration */
+	PIN_MAP_MUX_GROUP_DEFAULT("jz4740-pwm",
+			"10010000.jz4740-pinctrl", "pwm4", "pwm4"),
+};
+
 
 static int __init qi_lb60_init_platform_devices(void)
 {
@@ -469,6 +494,7 @@ static int __init qi_lb60_init_platform_devices(void)
 				ARRAY_SIZE(qi_lb60_spi_board_info));
 
 	pwm_add_table(qi_lb60_pwm_lookup, ARRAY_SIZE(qi_lb60_pwm_lookup));
+	pinctrl_register_mappings(pin_map, ARRAY_SIZE(pin_map));
 
 	return platform_add_devices(jz_platform_devices,
 					ARRAY_SIZE(jz_platform_devices));
@@ -479,8 +505,6 @@ static int __init qi_lb60_board_setup(void)
 {
 	printk(KERN_INFO "Qi Hardware JZ4740 QI LB60 setup\n");
 
-	board_gpio_setup();
-
 	if (qi_lb60_init_platform_devices())
 		panic("Failed to initialize platform devices");
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v5 09/14] MIPS: JZ4780: CI20: Add pinctrl configuration for several drivers
  2017-04-28 20:08             ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                                 ` (7 preceding siblings ...)
  2017-04-28 20:08               ` [PATCH v5 08/14] MIPS: JZ4740: Qi LB60: Add pinctrl configuration for several drivers Paul Cercueil
@ 2017-04-28 20:08               ` Paul Cercueil
  2017-04-28 20:08               ` [PATCH v5 10/14] mmc: jz4740: Let the pinctrl driver configure the pins Paul Cercueil
                                 ` (4 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-04-28 20:08 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

We set the pin configuration for the jz4780-nand and jz4780-uart
drivers.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/boot/dts/ingenic/ci20.dts | 60 +++++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

 v2: Changed the devicetree bindings to match the new driver
 v3: No changes
 v4: No changes
 v5: No changes

diff --git a/arch/mips/boot/dts/ingenic/ci20.dts b/arch/mips/boot/dts/ingenic/ci20.dts
index 1652d8d60b1e..fd138d9978c1 100644
--- a/arch/mips/boot/dts/ingenic/ci20.dts
+++ b/arch/mips/boot/dts/ingenic/ci20.dts
@@ -29,18 +29,30 @@
 
 &uart0 {
 	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart0>;
 };
 
 &uart1 {
 	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart1>;
 };
 
 &uart3 {
 	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart2>;
 };
 
 &uart4 {
 	status = "okay";
+
+	pinctrl-names = "default";
+	pinctrl-0 = <&pins_uart4>;
 };
 
 &nemc {
@@ -61,6 +73,13 @@
 		ingenic,nemc-tAW = <15>;
 		ingenic,nemc-tSTRV = <100>;
 
+		/*
+		 * Only CLE/ALE are needed for the devices that are connected, rather
+		 * than the full address line set.
+		 */
+		pinctrl-names = "default";
+		pinctrl-0 = <&pins_nemc>;
+
 		nand@1 {
 			reg = <1>;
 
@@ -69,6 +88,9 @@
 			nand-ecc-mode = "hw";
 			nand-on-flash-bbt;
 
+			pinctrl-names = "default";
+			pinctrl-0 = <&pins_nemc_cs1>;
+
 			partitions {
 				compatible = "fixed-partitions";
 				#address-cells = <2>;
@@ -106,3 +128,41 @@
 &bch {
 	status = "okay";
 };
+
+&pinctrl {
+	pins_uart0: uart0 {
+		function = "uart0";
+		groups = "uart0-data";
+		bias-disable;
+	};
+
+	pins_uart1: uart1 {
+		function = "uart1";
+		groups = "uart1-data";
+		bias-disable;
+	};
+
+	pins_uart2: uart2 {
+		function = "uart2";
+		groups = "uart2-data", "uart2-hwflow";
+		bias-disable;
+	};
+
+	pins_uart4: uart4 {
+		function = "uart4";
+		groups = "uart4-data";
+		bias-disable;
+	};
+
+	pins_nemc: nemc {
+		function = "nemc";
+		groups = "nemc-data", "nemc-cle-ale", "nemc-rd-we", "nemc-frd-fwe";
+		bias-disable;
+	};
+
+	pins_nemc_cs1: nemc-cs1 {
+		function = "nemc-cs1";
+		groups = "nemc-cs1";
+		bias-disable;
+	};
+};
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v5 10/14] mmc: jz4740: Let the pinctrl driver configure the pins
  2017-04-28 20:08             ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                                 ` (8 preceding siblings ...)
  2017-04-28 20:08               ` [PATCH v5 09/14] MIPS: JZ4780: CI20: " Paul Cercueil
@ 2017-04-28 20:08               ` Paul Cercueil
  2017-04-28 20:08               ` [PATCH v5 11/14] mtd: nand: " Paul Cercueil
                                 ` (3 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-04-28 20:08 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
the pins being properly configured before the driver probes.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
---
 drivers/mmc/host/jz4740_mmc.c | 44 +++++--------------------------------------
 1 file changed, 5 insertions(+), 39 deletions(-)

 v2: Set pin sleep/default state in suspend/resume callbacks
 v3: No changes
 v4: Re-insert accidentally removed <linux/gpio.h> include
 v5: No changes

diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c
index 819ad32964fc..42b3ee566dc7 100644
--- a/drivers/mmc/host/jz4740_mmc.c
+++ b/drivers/mmc/host/jz4740_mmc.c
@@ -20,6 +20,7 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/scatterlist.h>
@@ -27,7 +28,6 @@
 
 #include <linux/bitops.h>
 #include <linux/gpio.h>
-#include <asm/mach-jz4740/gpio.h>
 #include <asm/cacheflush.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
@@ -906,15 +906,6 @@ static const struct mmc_host_ops jz4740_mmc_ops = {
 	.enable_sdio_irq = jz4740_mmc_enable_sdio_irq,
 };
 
-static const struct jz_gpio_bulk_request jz4740_mmc_pins[] = {
-	JZ_GPIO_BULK_PIN(MSC_CMD),
-	JZ_GPIO_BULK_PIN(MSC_CLK),
-	JZ_GPIO_BULK_PIN(MSC_DATA0),
-	JZ_GPIO_BULK_PIN(MSC_DATA1),
-	JZ_GPIO_BULK_PIN(MSC_DATA2),
-	JZ_GPIO_BULK_PIN(MSC_DATA3),
-};
-
 static int jz4740_mmc_request_gpio(struct device *dev, int gpio,
 	const char *name, bool output, int value)
 {
@@ -978,15 +969,6 @@ static void jz4740_mmc_free_gpios(struct platform_device *pdev)
 		gpio_free(pdata->gpio_power);
 }
 
-static inline size_t jz4740_mmc_num_pins(struct jz4740_mmc_host *host)
-{
-	size_t num_pins = ARRAY_SIZE(jz4740_mmc_pins);
-	if (host->pdata && host->pdata->data_1bit)
-		num_pins -= 3;
-
-	return num_pins;
-}
-
 static int jz4740_mmc_probe(struct platform_device* pdev)
 {
 	int ret;
@@ -1027,15 +1009,9 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
 		goto err_free_host;
 	}
 
-	ret = jz_gpio_bulk_request(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
-	if (ret) {
-		dev_err(&pdev->dev, "Failed to request mmc pins: %d\n", ret);
-		goto err_free_host;
-	}
-
 	ret = jz4740_mmc_request_gpios(mmc, pdev);
 	if (ret)
-		goto err_gpio_bulk_free;
+		goto err_release_dma;
 
 	mmc->ops = &jz4740_mmc_ops;
 	mmc->f_min = JZ_MMC_CLK_RATE / 128;
@@ -1091,10 +1067,9 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
 	free_irq(host->irq, host);
 err_free_gpios:
 	jz4740_mmc_free_gpios(pdev);
-err_gpio_bulk_free:
+err_release_dma:
 	if (host->use_dma)
 		jz4740_mmc_release_dma_channels(host);
-	jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
 err_free_host:
 	mmc_free_host(mmc);
 
@@ -1114,7 +1089,6 @@ static int jz4740_mmc_remove(struct platform_device *pdev)
 	free_irq(host->irq, host);
 
 	jz4740_mmc_free_gpios(pdev);
-	jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
 
 	if (host->use_dma)
 		jz4740_mmc_release_dma_channels(host);
@@ -1128,20 +1102,12 @@ static int jz4740_mmc_remove(struct platform_device *pdev)
 
 static int jz4740_mmc_suspend(struct device *dev)
 {
-	struct jz4740_mmc_host *host = dev_get_drvdata(dev);
-
-	jz_gpio_bulk_suspend(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
-
-	return 0;
+	return pinctrl_pm_select_sleep_state(dev);
 }
 
 static int jz4740_mmc_resume(struct device *dev)
 {
-	struct jz4740_mmc_host *host = dev_get_drvdata(dev);
-
-	jz_gpio_bulk_resume(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
-
-	return 0;
+	return pinctrl_pm_select_default_state(dev);
 }
 
 static SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend,
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v5 11/14] mtd: nand: jz4740: Let the pinctrl driver configure the pins
  2017-04-28 20:08             ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                                 ` (9 preceding siblings ...)
  2017-04-28 20:08               ` [PATCH v5 10/14] mmc: jz4740: Let the pinctrl driver configure the pins Paul Cercueil
@ 2017-04-28 20:08               ` Paul Cercueil
  2017-04-28 20:08               ` [PATCH v5 12/14] fbdev: jz4740-fb: " Paul Cercueil
                                 ` (2 subsequent siblings)
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-04-28 20:08 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

Before, this NAND driver would set itself the configuration of the
chip-select pins for the various NAND banks.

Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
the pins being properly configured before the driver probes.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/mtd/nand/jz4740_nand.c | 23 +----------------------
 1 file changed, 1 insertion(+), 22 deletions(-)

 v2: No changes
 v3: No changes
 v4: No changes
 v5: No changes

diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
index 5551c36adbdf..0d06a1f07d82 100644
--- a/drivers/mtd/nand/jz4740_nand.c
+++ b/drivers/mtd/nand/jz4740_nand.c
@@ -25,7 +25,6 @@
 
 #include <linux/gpio.h>
 
-#include <asm/mach-jz4740/gpio.h>
 #include <asm/mach-jz4740/jz4740_nand.h>
 
 #define JZ_REG_NAND_CTRL	0x50
@@ -310,34 +309,20 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
 			       uint8_t *nand_dev_id)
 {
 	int ret;
-	int gpio;
-	char gpio_name[9];
 	char res_name[6];
 	uint32_t ctrl;
 	struct nand_chip *chip = &nand->chip;
 	struct mtd_info *mtd = nand_to_mtd(chip);
 
-	/* Request GPIO port. */
-	gpio = JZ_GPIO_MEM_CS0 + bank - 1;
-	sprintf(gpio_name, "NAND CS%d", bank);
-	ret = gpio_request(gpio, gpio_name);
-	if (ret) {
-		dev_warn(&pdev->dev,
-			"Failed to request %s gpio %d: %d\n",
-			gpio_name, gpio, ret);
-		goto notfound_gpio;
-	}
-
 	/* Request I/O resource. */
 	sprintf(res_name, "bank%d", bank);
 	ret = jz_nand_ioremap_resource(pdev, res_name,
 					&nand->bank_mem[bank - 1],
 					&nand->bank_base[bank - 1]);
 	if (ret)
-		goto notfound_resource;
+		return ret;
 
 	/* Enable chip in bank. */
-	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_MEM_CS0);
 	ctrl = readl(nand->base + JZ_REG_NAND_CTRL);
 	ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1);
 	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
@@ -377,12 +362,8 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
 	dev_info(&pdev->dev, "No chip found on bank %i\n", bank);
 	ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1));
 	writel(ctrl, nand->base + JZ_REG_NAND_CTRL);
-	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE);
 	jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
 				 nand->bank_base[bank - 1]);
-notfound_resource:
-	gpio_free(gpio);
-notfound_gpio:
 	return ret;
 }
 
@@ -503,7 +484,6 @@ static int jz_nand_probe(struct platform_device *pdev)
 err_unclaim_banks:
 	while (chipnr--) {
 		unsigned char bank = nand->banks[chipnr];
-		gpio_free(JZ_GPIO_MEM_CS0 + bank - 1);
 		jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
 					 nand->bank_base[bank - 1]);
 	}
@@ -530,7 +510,6 @@ static int jz_nand_remove(struct platform_device *pdev)
 		if (bank != 0) {
 			jz_nand_iounmap_resource(nand->bank_mem[bank - 1],
 						 nand->bank_base[bank - 1]);
-			gpio_free(JZ_GPIO_MEM_CS0 + bank - 1);
 		}
 	}
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v5 12/14] fbdev: jz4740-fb: Let the pinctrl driver configure the pins
  2017-04-28 20:08             ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                                 ` (10 preceding siblings ...)
  2017-04-28 20:08               ` [PATCH v5 11/14] mtd: nand: " Paul Cercueil
@ 2017-04-28 20:08               ` Paul Cercueil
  2017-04-28 20:08               ` [PATCH v5 13/14] pwm: jz4740: " Paul Cercueil
  2017-04-28 20:08               ` [PATCH v5 14/14] MIPS: jz4740: Remove custom GPIO code Paul Cercueil
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-04-28 20:08 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
the pins being properly configured before the driver probes.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Acked-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
---
 drivers/video/fbdev/jz4740_fb.c | 104 ++--------------------------------------
 1 file changed, 3 insertions(+), 101 deletions(-)

 v2: No changes
 v3: No changes
 v4: No changes
 v5: No changes

diff --git a/drivers/video/fbdev/jz4740_fb.c b/drivers/video/fbdev/jz4740_fb.c
index 87790e9644d0..b57df83fdbd3 100644
--- a/drivers/video/fbdev/jz4740_fb.c
+++ b/drivers/video/fbdev/jz4740_fb.c
@@ -17,6 +17,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
 
 #include <linux/clk.h>
 #include <linux/delay.h>
@@ -27,7 +28,6 @@
 #include <linux/dma-mapping.h>
 
 #include <asm/mach-jz4740/jz4740_fb.h>
-#include <asm/mach-jz4740/gpio.h>
 
 #define JZ_REG_LCD_CFG		0x00
 #define JZ_REG_LCD_VSYNC	0x04
@@ -146,93 +146,6 @@ static const struct fb_fix_screeninfo jzfb_fix = {
 	.accel		= FB_ACCEL_NONE,
 };
 
-static const struct jz_gpio_bulk_request jz_lcd_ctrl_pins[] = {
-	JZ_GPIO_BULK_PIN(LCD_PCLK),
-	JZ_GPIO_BULK_PIN(LCD_HSYNC),
-	JZ_GPIO_BULK_PIN(LCD_VSYNC),
-	JZ_GPIO_BULK_PIN(LCD_DE),
-	JZ_GPIO_BULK_PIN(LCD_PS),
-	JZ_GPIO_BULK_PIN(LCD_REV),
-	JZ_GPIO_BULK_PIN(LCD_CLS),
-	JZ_GPIO_BULK_PIN(LCD_SPL),
-};
-
-static const struct jz_gpio_bulk_request jz_lcd_data_pins[] = {
-	JZ_GPIO_BULK_PIN(LCD_DATA0),
-	JZ_GPIO_BULK_PIN(LCD_DATA1),
-	JZ_GPIO_BULK_PIN(LCD_DATA2),
-	JZ_GPIO_BULK_PIN(LCD_DATA3),
-	JZ_GPIO_BULK_PIN(LCD_DATA4),
-	JZ_GPIO_BULK_PIN(LCD_DATA5),
-	JZ_GPIO_BULK_PIN(LCD_DATA6),
-	JZ_GPIO_BULK_PIN(LCD_DATA7),
-	JZ_GPIO_BULK_PIN(LCD_DATA8),
-	JZ_GPIO_BULK_PIN(LCD_DATA9),
-	JZ_GPIO_BULK_PIN(LCD_DATA10),
-	JZ_GPIO_BULK_PIN(LCD_DATA11),
-	JZ_GPIO_BULK_PIN(LCD_DATA12),
-	JZ_GPIO_BULK_PIN(LCD_DATA13),
-	JZ_GPIO_BULK_PIN(LCD_DATA14),
-	JZ_GPIO_BULK_PIN(LCD_DATA15),
-	JZ_GPIO_BULK_PIN(LCD_DATA16),
-	JZ_GPIO_BULK_PIN(LCD_DATA17),
-};
-
-static unsigned int jzfb_num_ctrl_pins(struct jzfb *jzfb)
-{
-	unsigned int num;
-
-	switch (jzfb->pdata->lcd_type) {
-	case JZ_LCD_TYPE_GENERIC_16_BIT:
-		num = 4;
-		break;
-	case JZ_LCD_TYPE_GENERIC_18_BIT:
-		num = 4;
-		break;
-	case JZ_LCD_TYPE_8BIT_SERIAL:
-		num = 3;
-		break;
-	case JZ_LCD_TYPE_SPECIAL_TFT_1:
-	case JZ_LCD_TYPE_SPECIAL_TFT_2:
-	case JZ_LCD_TYPE_SPECIAL_TFT_3:
-		num = 8;
-		break;
-	default:
-		num = 0;
-		break;
-	}
-	return num;
-}
-
-static unsigned int jzfb_num_data_pins(struct jzfb *jzfb)
-{
-	unsigned int num;
-
-	switch (jzfb->pdata->lcd_type) {
-	case JZ_LCD_TYPE_GENERIC_16_BIT:
-		num = 16;
-		break;
-	case JZ_LCD_TYPE_GENERIC_18_BIT:
-		num = 18;
-		break;
-	case JZ_LCD_TYPE_8BIT_SERIAL:
-		num = 8;
-		break;
-	case JZ_LCD_TYPE_SPECIAL_TFT_1:
-	case JZ_LCD_TYPE_SPECIAL_TFT_2:
-	case JZ_LCD_TYPE_SPECIAL_TFT_3:
-		if (jzfb->pdata->bpp == 18)
-			num = 18;
-		else
-			num = 16;
-		break;
-	default:
-		num = 0;
-		break;
-	}
-	return num;
-}
-
 /* Based on CNVT_TOHW macro from skeletonfb.c */
 static inline uint32_t jzfb_convert_color_to_hw(unsigned val,
 	struct fb_bitfield *bf)
@@ -487,8 +400,7 @@ static void jzfb_enable(struct jzfb *jzfb)
 
 	clk_prepare_enable(jzfb->ldclk);
 
-	jz_gpio_bulk_resume(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_resume(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
+	pinctrl_pm_select_default_state(&jzfb->pdev->dev);
 
 	writel(0, jzfb->base + JZ_REG_LCD_STATE);
 
@@ -511,8 +423,7 @@ static void jzfb_disable(struct jzfb *jzfb)
 		ctrl = readl(jzfb->base + JZ_REG_LCD_STATE);
 	} while (!(ctrl & JZ_LCD_STATE_DISABLED));
 
-	jz_gpio_bulk_suspend(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_suspend(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
+	pinctrl_pm_select_sleep_state(&jzfb->pdev->dev);
 
 	clk_disable_unprepare(jzfb->ldclk);
 }
@@ -701,9 +612,6 @@ static int jzfb_probe(struct platform_device *pdev)
 	fb->mode = NULL;
 	jzfb_set_par(fb);
 
-	jz_gpio_bulk_request(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_request(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
-
 	ret = register_framebuffer(fb);
 	if (ret) {
 		dev_err(&pdev->dev, "Failed to register framebuffer: %d\n", ret);
@@ -715,9 +623,6 @@ static int jzfb_probe(struct platform_device *pdev)
 	return 0;
 
 err_free_devmem:
-	jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
-
 	fb_dealloc_cmap(&fb->cmap);
 	jzfb_free_devmem(jzfb);
 err_framebuffer_release:
@@ -731,9 +636,6 @@ static int jzfb_remove(struct platform_device *pdev)
 
 	jzfb_blank(FB_BLANK_POWERDOWN, jzfb->fb);
 
-	jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
-	jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
-
 	fb_dealloc_cmap(&jzfb->fb->cmap);
 	jzfb_free_devmem(jzfb);
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v5 13/14] pwm: jz4740: Let the pinctrl driver configure the pins
  2017-04-28 20:08             ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                                 ` (11 preceding siblings ...)
  2017-04-28 20:08               ` [PATCH v5 12/14] fbdev: jz4740-fb: " Paul Cercueil
@ 2017-04-28 20:08               ` Paul Cercueil
  2017-04-28 20:08               ` [PATCH v5 14/14] MIPS: jz4740: Remove custom GPIO code Paul Cercueil
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-04-28 20:08 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

Now that the JZ4740 and similar SoCs have a pinctrl driver, we rely on
the pins being properly configured before the driver probes.

One inherent problem of this new approach is that the pinctrl framework
does not allow us to configure each pin on demand, when the various PWM
channels are requested or released. For instance, the PWM channels can
be configured from sysfs, which would require all PWM pins to be configured
properly beforehand for the PWM function, eventually causing conflicts
with other platform or board drivers.

The proper solution here would be to modify the pwm-jz4740 driver to
handle only one PWM channel, and create an instance of this driver
for each one of the 8 PWM channels. Then, it could use the pinctrl
framework to dynamically configure the PWM pin it controls.

Until this can be done, the only jz4740 board supported upstream
(Qi lb60) can configure all of its connected PWM pins in PWM function
mode, since those are not used by other drivers nor by GPIOs on the
board.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Acked-by: Thierry Reding <thierry.reding@gmail.com>
---
 drivers/pwm/pwm-jz4740.c | 29 -----------------------------
 1 file changed, 29 deletions(-)

 v2: No changes
 v3: No changes
 v4: No changes
 v5: No changes

diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c
index 76d13150283f..a75ff3622450 100644
--- a/drivers/pwm/pwm-jz4740.c
+++ b/drivers/pwm/pwm-jz4740.c
@@ -21,22 +21,10 @@
 #include <linux/platform_device.h>
 #include <linux/pwm.h>
 
-#include <asm/mach-jz4740/gpio.h>
 #include <asm/mach-jz4740/timer.h>
 
 #define NUM_PWM 8
 
-static const unsigned int jz4740_pwm_gpio_list[NUM_PWM] = {
-	JZ_GPIO_PWM0,
-	JZ_GPIO_PWM1,
-	JZ_GPIO_PWM2,
-	JZ_GPIO_PWM3,
-	JZ_GPIO_PWM4,
-	JZ_GPIO_PWM5,
-	JZ_GPIO_PWM6,
-	JZ_GPIO_PWM7,
-};
-
 struct jz4740_pwm_chip {
 	struct pwm_chip chip;
 	struct clk *clk;
@@ -49,9 +37,6 @@ static inline struct jz4740_pwm_chip *to_jz4740(struct pwm_chip *chip)
 
 static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-	unsigned int gpio = jz4740_pwm_gpio_list[pwm->hwpwm];
-	int ret;
-
 	/*
 	 * Timers 0 and 1 are used for system tasks, so they are unavailable
 	 * for use as PWMs.
@@ -59,15 +44,6 @@ static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 	if (pwm->hwpwm < 2)
 		return -EBUSY;
 
-	ret = gpio_request(gpio, pwm->label);
-	if (ret) {
-		dev_err(chip->dev, "Failed to request GPIO#%u for PWM: %d\n",
-			gpio, ret);
-		return ret;
-	}
-
-	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_PWM);
-
 	jz4740_timer_start(pwm->hwpwm);
 
 	return 0;
@@ -75,13 +51,8 @@ static int jz4740_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
 
 static void jz4740_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 {
-	unsigned int gpio = jz4740_pwm_gpio_list[pwm->hwpwm];
-
 	jz4740_timer_set_ctrl(pwm->hwpwm, 0);
 
-	jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE);
-	gpio_free(gpio);
-
 	jz4740_timer_stop(pwm->hwpwm);
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* [PATCH v5 14/14] MIPS: jz4740: Remove custom GPIO code
  2017-04-28 20:08             ` [PATCH v4 00/14] Ingenic JZ4740 / JZ4780 pinctrl driver Paul Cercueil
                                 ` (12 preceding siblings ...)
  2017-04-28 20:08               ` [PATCH v5 13/14] pwm: jz4740: " Paul Cercueil
@ 2017-04-28 20:08               ` Paul Cercueil
  13 siblings, 0 replies; 162+ messages in thread
From: Paul Cercueil @ 2017-04-28 20:08 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev, Paul Cercueil

All the drivers for the various hardware elements of the jz4740 SoC have
been modified to use the pinctrl framework for their pin configuration
needs.
As such, this platform code is now unused and can be deleted.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 arch/mips/include/asm/mach-jz4740/gpio.h | 371 ----------------------
 arch/mips/jz4740/Makefile                |   2 -
 arch/mips/jz4740/gpio.c                  | 519 -------------------------------
 3 files changed, 892 deletions(-)
 delete mode 100644 arch/mips/jz4740/gpio.c

 v2: No changes
 v3: No changes
 v4: No changes
 v5: No changes

diff --git a/arch/mips/include/asm/mach-jz4740/gpio.h b/arch/mips/include/asm/mach-jz4740/gpio.h
index 7c7708a23baa..fd847c984701 100644
--- a/arch/mips/include/asm/mach-jz4740/gpio.h
+++ b/arch/mips/include/asm/mach-jz4740/gpio.h
@@ -16,380 +16,9 @@
 #ifndef _JZ_GPIO_H
 #define _JZ_GPIO_H
 
-#include <linux/types.h>
-
-enum jz_gpio_function {
-    JZ_GPIO_FUNC_NONE,
-    JZ_GPIO_FUNC1,
-    JZ_GPIO_FUNC2,
-    JZ_GPIO_FUNC3,
-};
-
-/*
- Usually a driver for a SoC component has to request several gpio pins and
- configure them as function pins.
- jz_gpio_bulk_request can be used to ease this process.
- Usually one would do something like:
-
- static const struct jz_gpio_bulk_request i2c_pins[] = {
-	JZ_GPIO_BULK_PIN(I2C_SDA),
-	JZ_GPIO_BULK_PIN(I2C_SCK),
- };
-
- inside the probe function:
-
-    ret = jz_gpio_bulk_request(i2c_pins, ARRAY_SIZE(i2c_pins));
-    if (ret) {
-	...
-
- inside the remove function:
-
-    jz_gpio_bulk_free(i2c_pins, ARRAY_SIZE(i2c_pins));
-
-*/
-
-struct jz_gpio_bulk_request {
-	int gpio;
-	const char *name;
-	enum jz_gpio_function function;
-};
-
-#define JZ_GPIO_BULK_PIN(pin) { \
-    .gpio = JZ_GPIO_ ## pin, \
-    .name = #pin, \
-    .function = JZ_GPIO_FUNC_ ## pin \
-}
-
-int jz_gpio_bulk_request(const struct jz_gpio_bulk_request *request, size_t num);
-void jz_gpio_bulk_free(const struct jz_gpio_bulk_request *request, size_t num);
-void jz_gpio_bulk_suspend(const struct jz_gpio_bulk_request *request, size_t num);
-void jz_gpio_bulk_resume(const struct jz_gpio_bulk_request *request, size_t num);
-void jz_gpio_enable_pullup(unsigned gpio);
-void jz_gpio_disable_pullup(unsigned gpio);
-int jz_gpio_set_function(int gpio, enum jz_gpio_function function);
-
-int jz_gpio_port_direction_input(int port, uint32_t mask);
-int jz_gpio_port_direction_output(int port, uint32_t mask);
-void jz_gpio_port_set_value(int port, uint32_t value, uint32_t mask);
-uint32_t jz_gpio_port_get_value(int port, uint32_t mask);
-
 #define JZ_GPIO_PORTA(x) ((x) + 32 * 0)
 #define JZ_GPIO_PORTB(x) ((x) + 32 * 1)
 #define JZ_GPIO_PORTC(x) ((x) + 32 * 2)
 #define JZ_GPIO_PORTD(x) ((x) + 32 * 3)
 
-/* Port A function pins */
-#define JZ_GPIO_MEM_DATA0		JZ_GPIO_PORTA(0)
-#define JZ_GPIO_MEM_DATA1		JZ_GPIO_PORTA(1)
-#define JZ_GPIO_MEM_DATA2		JZ_GPIO_PORTA(2)
-#define JZ_GPIO_MEM_DATA3		JZ_GPIO_PORTA(3)
-#define JZ_GPIO_MEM_DATA4		JZ_GPIO_PORTA(4)
-#define JZ_GPIO_MEM_DATA5		JZ_GPIO_PORTA(5)
-#define JZ_GPIO_MEM_DATA6		JZ_GPIO_PORTA(6)
-#define JZ_GPIO_MEM_DATA7		JZ_GPIO_PORTA(7)
-#define JZ_GPIO_MEM_DATA8		JZ_GPIO_PORTA(8)
-#define JZ_GPIO_MEM_DATA9		JZ_GPIO_PORTA(9)
-#define JZ_GPIO_MEM_DATA10		JZ_GPIO_PORTA(10)
-#define JZ_GPIO_MEM_DATA11		JZ_GPIO_PORTA(11)
-#define JZ_GPIO_MEM_DATA12		JZ_GPIO_PORTA(12)
-#define JZ_GPIO_MEM_DATA13		JZ_GPIO_PORTA(13)
-#define JZ_GPIO_MEM_DATA14		JZ_GPIO_PORTA(14)
-#define JZ_GPIO_MEM_DATA15		JZ_GPIO_PORTA(15)
-#define JZ_GPIO_MEM_DATA16		JZ_GPIO_PORTA(16)
-#define JZ_GPIO_MEM_DATA17		JZ_GPIO_PORTA(17)
-#define JZ_GPIO_MEM_DATA18		JZ_GPIO_PORTA(18)
-#define JZ_GPIO_MEM_DATA19		JZ_GPIO_PORTA(19)
-#define JZ_GPIO_MEM_DATA20		JZ_GPIO_PORTA(20)
-#define JZ_GPIO_MEM_DATA21		JZ_GPIO_PORTA(21)
-#define JZ_GPIO_MEM_DATA22		JZ_GPIO_PORTA(22)
-#define JZ_GPIO_MEM_DATA23		JZ_GPIO_PORTA(23)
-#define JZ_GPIO_MEM_DATA24		JZ_GPIO_PORTA(24)
-#define JZ_GPIO_MEM_DATA25		JZ_GPIO_PORTA(25)
-#define JZ_GPIO_MEM_DATA26		JZ_GPIO_PORTA(26)
-#define JZ_GPIO_MEM_DATA27		JZ_GPIO_PORTA(27)
-#define JZ_GPIO_MEM_DATA28		JZ_GPIO_PORTA(28)
-#define JZ_GPIO_MEM_DATA29		JZ_GPIO_PORTA(29)
-#define JZ_GPIO_MEM_DATA30		JZ_GPIO_PORTA(30)
-#define JZ_GPIO_MEM_DATA31		JZ_GPIO_PORTA(31)
-
-#define JZ_GPIO_FUNC_MEM_DATA0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA4		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA5		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA6		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA7		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA8		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA9		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA10		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA11		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA12		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA13		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA14		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA15		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA16		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA17		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA18		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA19		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA20		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA21		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA22		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA23		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA24		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA25		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA26		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA27		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA28		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA29		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA30		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DATA31		JZ_GPIO_FUNC1
-
-/* Port B function pins */
-#define JZ_GPIO_MEM_ADDR0		JZ_GPIO_PORTB(0)
-#define JZ_GPIO_MEM_ADDR1		JZ_GPIO_PORTB(1)
-#define JZ_GPIO_MEM_ADDR2		JZ_GPIO_PORTB(2)
-#define JZ_GPIO_MEM_ADDR3		JZ_GPIO_PORTB(3)
-#define JZ_GPIO_MEM_ADDR4		JZ_GPIO_PORTB(4)
-#define JZ_GPIO_MEM_ADDR5		JZ_GPIO_PORTB(5)
-#define JZ_GPIO_MEM_ADDR6		JZ_GPIO_PORTB(6)
-#define JZ_GPIO_MEM_ADDR7		JZ_GPIO_PORTB(7)
-#define JZ_GPIO_MEM_ADDR8		JZ_GPIO_PORTB(8)
-#define JZ_GPIO_MEM_ADDR9		JZ_GPIO_PORTB(9)
-#define JZ_GPIO_MEM_ADDR10		JZ_GPIO_PORTB(10)
-#define JZ_GPIO_MEM_ADDR11		JZ_GPIO_PORTB(11)
-#define JZ_GPIO_MEM_ADDR12		JZ_GPIO_PORTB(12)
-#define JZ_GPIO_MEM_ADDR13		JZ_GPIO_PORTB(13)
-#define JZ_GPIO_MEM_ADDR14		JZ_GPIO_PORTB(14)
-#define JZ_GPIO_MEM_ADDR15		JZ_GPIO_PORTB(15)
-#define JZ_GPIO_MEM_ADDR16		JZ_GPIO_PORTB(16)
-#define JZ_GPIO_LCD_CLS			JZ_GPIO_PORTB(17)
-#define JZ_GPIO_LCD_SPL			JZ_GPIO_PORTB(18)
-#define JZ_GPIO_MEM_DCS			JZ_GPIO_PORTB(19)
-#define JZ_GPIO_MEM_RAS			JZ_GPIO_PORTB(20)
-#define JZ_GPIO_MEM_CAS			JZ_GPIO_PORTB(21)
-#define JZ_GPIO_MEM_SDWE		JZ_GPIO_PORTB(22)
-#define JZ_GPIO_MEM_CKE			JZ_GPIO_PORTB(23)
-#define JZ_GPIO_MEM_CKO			JZ_GPIO_PORTB(24)
-#define JZ_GPIO_MEM_CS0			JZ_GPIO_PORTB(25)
-#define JZ_GPIO_MEM_CS1			JZ_GPIO_PORTB(26)
-#define JZ_GPIO_MEM_CS2			JZ_GPIO_PORTB(27)
-#define JZ_GPIO_MEM_CS3			JZ_GPIO_PORTB(28)
-#define JZ_GPIO_MEM_RD			JZ_GPIO_PORTB(29)
-#define JZ_GPIO_MEM_WR			JZ_GPIO_PORTB(30)
-#define JZ_GPIO_MEM_WE0			JZ_GPIO_PORTB(31)
-
-#define JZ_GPIO_FUNC_MEM_ADDR0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR4		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR5		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR6		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR7		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR8		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR9		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR10		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR11		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR12		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR13		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR14		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR15		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_ADDR16		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_CLS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_SPL		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_DCS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_RAS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CAS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_SDWE		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CKE		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CKO		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CS0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CS1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CS2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_CS3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_RD		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WR		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WE0		JZ_GPIO_FUNC1
-
-
-#define JZ_GPIO_MEM_ADDR21		JZ_GPIO_PORTB(17)
-#define JZ_GPIO_MEM_ADDR22		JZ_GPIO_PORTB(18)
-
-#define JZ_GPIO_FUNC_MEM_ADDR21		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_ADDR22		JZ_GPIO_FUNC2
-
-/* Port C function pins */
-#define JZ_GPIO_LCD_DATA0		JZ_GPIO_PORTC(0)
-#define JZ_GPIO_LCD_DATA1		JZ_GPIO_PORTC(1)
-#define JZ_GPIO_LCD_DATA2		JZ_GPIO_PORTC(2)
-#define JZ_GPIO_LCD_DATA3		JZ_GPIO_PORTC(3)
-#define JZ_GPIO_LCD_DATA4		JZ_GPIO_PORTC(4)
-#define JZ_GPIO_LCD_DATA5		JZ_GPIO_PORTC(5)
-#define JZ_GPIO_LCD_DATA6		JZ_GPIO_PORTC(6)
-#define JZ_GPIO_LCD_DATA7		JZ_GPIO_PORTC(7)
-#define JZ_GPIO_LCD_DATA8		JZ_GPIO_PORTC(8)
-#define JZ_GPIO_LCD_DATA9		JZ_GPIO_PORTC(9)
-#define JZ_GPIO_LCD_DATA10		JZ_GPIO_PORTC(10)
-#define JZ_GPIO_LCD_DATA11		JZ_GPIO_PORTC(11)
-#define JZ_GPIO_LCD_DATA12		JZ_GPIO_PORTC(12)
-#define JZ_GPIO_LCD_DATA13		JZ_GPIO_PORTC(13)
-#define JZ_GPIO_LCD_DATA14		JZ_GPIO_PORTC(14)
-#define JZ_GPIO_LCD_DATA15		JZ_GPIO_PORTC(15)
-#define JZ_GPIO_LCD_DATA16		JZ_GPIO_PORTC(16)
-#define JZ_GPIO_LCD_DATA17		JZ_GPIO_PORTC(17)
-#define JZ_GPIO_LCD_PCLK		JZ_GPIO_PORTC(18)
-#define JZ_GPIO_LCD_HSYNC		JZ_GPIO_PORTC(19)
-#define JZ_GPIO_LCD_VSYNC		JZ_GPIO_PORTC(20)
-#define JZ_GPIO_LCD_DE			JZ_GPIO_PORTC(21)
-#define JZ_GPIO_LCD_PS			JZ_GPIO_PORTC(22)
-#define JZ_GPIO_LCD_REV			JZ_GPIO_PORTC(23)
-#define JZ_GPIO_MEM_WE1			JZ_GPIO_PORTC(24)
-#define JZ_GPIO_MEM_WE2			JZ_GPIO_PORTC(25)
-#define JZ_GPIO_MEM_WE3			JZ_GPIO_PORTC(26)
-#define JZ_GPIO_MEM_WAIT		JZ_GPIO_PORTC(27)
-#define JZ_GPIO_MEM_FRE			JZ_GPIO_PORTC(28)
-#define JZ_GPIO_MEM_FWE			JZ_GPIO_PORTC(29)
-
-#define JZ_GPIO_FUNC_LCD_DATA0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA4		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA5		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA6		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA7		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA8		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA9		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA10		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA11		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA12		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA13		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA14		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA15		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA16		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DATA17		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_PCLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_VSYNC		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_HSYNC		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_DE		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_PS		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_LCD_REV		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WE1		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WE2		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WE3		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_WAIT		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_FRE		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MEM_FWE		JZ_GPIO_FUNC1
-
-
-#define JZ_GPIO_MEM_ADDR19		JZ_GPIO_PORTB(22)
-#define JZ_GPIO_MEM_ADDR20		JZ_GPIO_PORTB(23)
-
-#define JZ_GPIO_FUNC_MEM_ADDR19		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_ADDR20		JZ_GPIO_FUNC2
-
-/* Port D function pins */
-#define JZ_GPIO_CIM_DATA0		JZ_GPIO_PORTD(0)
-#define JZ_GPIO_CIM_DATA1		JZ_GPIO_PORTD(1)
-#define JZ_GPIO_CIM_DATA2		JZ_GPIO_PORTD(2)
-#define JZ_GPIO_CIM_DATA3		JZ_GPIO_PORTD(3)
-#define JZ_GPIO_CIM_DATA4		JZ_GPIO_PORTD(4)
-#define JZ_GPIO_CIM_DATA5		JZ_GPIO_PORTD(5)
-#define JZ_GPIO_CIM_DATA6		JZ_GPIO_PORTD(6)
-#define JZ_GPIO_CIM_DATA7		JZ_GPIO_PORTD(7)
-#define JZ_GPIO_MSC_CMD			JZ_GPIO_PORTD(8)
-#define JZ_GPIO_MSC_CLK			JZ_GPIO_PORTD(9)
-#define JZ_GPIO_MSC_DATA0		JZ_GPIO_PORTD(10)
-#define JZ_GPIO_MSC_DATA1		JZ_GPIO_PORTD(11)
-#define JZ_GPIO_MSC_DATA2		JZ_GPIO_PORTD(12)
-#define JZ_GPIO_MSC_DATA3		JZ_GPIO_PORTD(13)
-#define JZ_GPIO_CIM_MCLK		JZ_GPIO_PORTD(14)
-#define JZ_GPIO_CIM_PCLK		JZ_GPIO_PORTD(15)
-#define JZ_GPIO_CIM_VSYNC		JZ_GPIO_PORTD(16)
-#define JZ_GPIO_CIM_HSYNC		JZ_GPIO_PORTD(17)
-#define JZ_GPIO_SPI_CLK			JZ_GPIO_PORTD(18)
-#define JZ_GPIO_SPI_CE0			JZ_GPIO_PORTD(19)
-#define JZ_GPIO_SPI_DT			JZ_GPIO_PORTD(20)
-#define JZ_GPIO_SPI_DR			JZ_GPIO_PORTD(21)
-#define JZ_GPIO_SPI_CE1			JZ_GPIO_PORTD(22)
-#define JZ_GPIO_PWM0			JZ_GPIO_PORTD(23)
-#define JZ_GPIO_PWM1			JZ_GPIO_PORTD(24)
-#define JZ_GPIO_PWM2			JZ_GPIO_PORTD(25)
-#define JZ_GPIO_PWM3			JZ_GPIO_PORTD(26)
-#define JZ_GPIO_PWM4			JZ_GPIO_PORTD(27)
-#define JZ_GPIO_PWM5			JZ_GPIO_PORTD(28)
-#define JZ_GPIO_PWM6			JZ_GPIO_PORTD(30)
-#define JZ_GPIO_PWM7			JZ_GPIO_PORTD(31)
-
-#define JZ_GPIO_FUNC_CIM_DATA		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_CIM_DATA0		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA1		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA2		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA3		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA4		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA5		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA6		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_CIM_DATA7		JZ_GPIO_FUNC_CIM_DATA
-#define JZ_GPIO_FUNC_MSC_CMD		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MSC_CLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MSC_DATA		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_MSC_DATA0		JZ_GPIO_FUNC_MSC_DATA
-#define JZ_GPIO_FUNC_MSC_DATA1		JZ_GPIO_FUNC_MSC_DATA
-#define JZ_GPIO_FUNC_MSC_DATA2		JZ_GPIO_FUNC_MSC_DATA
-#define JZ_GPIO_FUNC_MSC_DATA3		JZ_GPIO_FUNC_MSC_DATA
-#define JZ_GPIO_FUNC_CIM_MCLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_CIM_PCLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_CIM_VSYNC		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_CIM_HSYNC		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_CLK		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_CE0		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_DT		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_DR		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_SPI_CE1		JZ_GPIO_FUNC1
-
-#define JZ_GPIO_FUNC_PWM		JZ_GPIO_FUNC1
-#define JZ_GPIO_FUNC_PWM0		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM1		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM2		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM3		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM4		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM5		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM6		JZ_GPIO_FUNC_PWM
-#define JZ_GPIO_FUNC_PWM7		JZ_GPIO_FUNC_PWM
-
-#define JZ_GPIO_MEM_SCLK_RSTN		JZ_GPIO_PORTD(18)
-#define JZ_GPIO_MEM_BCLK		JZ_GPIO_PORTD(19)
-#define JZ_GPIO_MEM_SDATO		JZ_GPIO_PORTD(20)
-#define JZ_GPIO_MEM_SDATI		JZ_GPIO_PORTD(21)
-#define JZ_GPIO_MEM_SYNC		JZ_GPIO_PORTD(22)
-#define JZ_GPIO_I2C_SDA			JZ_GPIO_PORTD(23)
-#define JZ_GPIO_I2C_SCK			JZ_GPIO_PORTD(24)
-#define JZ_GPIO_UART0_TXD		JZ_GPIO_PORTD(25)
-#define JZ_GPIO_UART0_RXD		JZ_GPIO_PORTD(26)
-#define JZ_GPIO_MEM_ADDR17		JZ_GPIO_PORTD(27)
-#define JZ_GPIO_MEM_ADDR18		JZ_GPIO_PORTD(28)
-#define JZ_GPIO_UART0_CTS		JZ_GPIO_PORTD(30)
-#define JZ_GPIO_UART0_RTS		JZ_GPIO_PORTD(31)
-
-#define JZ_GPIO_FUNC_MEM_SCLK_RSTN	JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_BCLK		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_SDATO		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_SDATI		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_SYNC		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_I2C_SDA		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_I2C_SCK		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_UART0_TXD		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_UART0_RXD		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_ADDR17		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_MEM_ADDR18		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_UART0_CTS		JZ_GPIO_FUNC2
-#define JZ_GPIO_FUNC_UART0_RTS		JZ_GPIO_FUNC2
-
-#define JZ_GPIO_UART1_RXD		JZ_GPIO_PORTD(30)
-#define JZ_GPIO_UART1_TXD		JZ_GPIO_PORTD(31)
-
-#define JZ_GPIO_FUNC_UART1_RXD		JZ_GPIO_FUNC3
-#define JZ_GPIO_FUNC_UART1_TXD		JZ_GPIO_FUNC3
-
 #endif
diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
index 39d70bde8cfe..6b9c1f7c31c9 100644
--- a/arch/mips/jz4740/Makefile
+++ b/arch/mips/jz4740/Makefile
@@ -7,8 +7,6 @@
 obj-y += prom.o time.o reset.o setup.o \
 	platform.o timer.o
 
-obj-$(CONFIG_MACH_JZ4740) += gpio.o
-
 CFLAGS_setup.o = -I$(src)/../../../scripts/dtc/libfdt
 
 # board specific support
diff --git a/arch/mips/jz4740/gpio.c b/arch/mips/jz4740/gpio.c
deleted file mode 100644
index cac1ccde2214..000000000000
--- a/arch/mips/jz4740/gpio.c
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- *  Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
- *  JZ4740 platform GPIO support
- *
- *  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.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/init.h>
-
-#include <linux/io.h>
-#include <linux/gpio/driver.h>
-/* FIXME: needed for gpio_request(), try to remove consumer API from driver */
-#include <linux/gpio.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/irqchip/ingenic.h>
-#include <linux/bitops.h>
-
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-
-#include <asm/mach-jz4740/base.h>
-#include <asm/mach-jz4740/gpio.h>
-
-#define JZ4740_GPIO_BASE_A (32*0)
-#define JZ4740_GPIO_BASE_B (32*1)
-#define JZ4740_GPIO_BASE_C (32*2)
-#define JZ4740_GPIO_BASE_D (32*3)
-
-#define JZ4740_GPIO_NUM_A 32
-#define JZ4740_GPIO_NUM_B 32
-#define JZ4740_GPIO_NUM_C 31
-#define JZ4740_GPIO_NUM_D 32
-
-#define JZ4740_IRQ_GPIO_BASE_A (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_A)
-#define JZ4740_IRQ_GPIO_BASE_B (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_B)
-#define JZ4740_IRQ_GPIO_BASE_C (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_C)
-#define JZ4740_IRQ_GPIO_BASE_D (JZ4740_IRQ_GPIO(0) + JZ4740_GPIO_BASE_D)
-
-#define JZ_REG_GPIO_PIN			0x00
-#define JZ_REG_GPIO_DATA		0x10
-#define JZ_REG_GPIO_DATA_SET		0x14
-#define JZ_REG_GPIO_DATA_CLEAR		0x18
-#define JZ_REG_GPIO_MASK		0x20
-#define JZ_REG_GPIO_MASK_SET		0x24
-#define JZ_REG_GPIO_MASK_CLEAR		0x28
-#define JZ_REG_GPIO_PULL		0x30
-#define JZ_REG_GPIO_PULL_SET		0x34
-#define JZ_REG_GPIO_PULL_CLEAR		0x38
-#define JZ_REG_GPIO_FUNC		0x40
-#define JZ_REG_GPIO_FUNC_SET		0x44
-#define JZ_REG_GPIO_FUNC_CLEAR		0x48
-#define JZ_REG_GPIO_SELECT		0x50
-#define JZ_REG_GPIO_SELECT_SET		0x54
-#define JZ_REG_GPIO_SELECT_CLEAR	0x58
-#define JZ_REG_GPIO_DIRECTION		0x60
-#define JZ_REG_GPIO_DIRECTION_SET	0x64
-#define JZ_REG_GPIO_DIRECTION_CLEAR	0x68
-#define JZ_REG_GPIO_TRIGGER		0x70
-#define JZ_REG_GPIO_TRIGGER_SET		0x74
-#define JZ_REG_GPIO_TRIGGER_CLEAR	0x78
-#define JZ_REG_GPIO_FLAG		0x80
-#define JZ_REG_GPIO_FLAG_CLEAR		0x14
-
-#define GPIO_TO_BIT(gpio) BIT(gpio & 0x1f)
-#define GPIO_TO_REG(gpio, reg) (gpio_to_jz_gpio_chip(gpio)->base + (reg))
-#define CHIP_TO_REG(chip, reg) (gpio_chip_to_jz_gpio_chip(chip)->base + (reg))
-
-struct jz_gpio_chip {
-	unsigned int irq;
-	unsigned int irq_base;
-	uint32_t edge_trigger_both;
-
-	void __iomem *base;
-
-	struct gpio_chip gpio_chip;
-};
-
-static struct jz_gpio_chip jz4740_gpio_chips[];
-
-static inline struct jz_gpio_chip *gpio_to_jz_gpio_chip(unsigned int gpio)
-{
-	return &jz4740_gpio_chips[gpio >> 5];
-}
-
-static inline struct jz_gpio_chip *gpio_chip_to_jz_gpio_chip(struct gpio_chip *gc)
-{
-	return gpiochip_get_data(gc);
-}
-
-static inline struct jz_gpio_chip *irq_to_jz_gpio_chip(struct irq_data *data)
-{
-	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
-	return gc->private;
-}
-
-static inline void jz_gpio_write_bit(unsigned int gpio, unsigned int reg)
-{
-	writel(GPIO_TO_BIT(gpio), GPIO_TO_REG(gpio, reg));
-}
-
-int jz_gpio_set_function(int gpio, enum jz_gpio_function function)
-{
-	if (function == JZ_GPIO_FUNC_NONE) {
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_FUNC_CLEAR);
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_CLEAR);
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_CLEAR);
-	} else {
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_FUNC_SET);
-		jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_CLEAR);
-		switch (function) {
-		case JZ_GPIO_FUNC1:
-			jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_CLEAR);
-			break;
-		case JZ_GPIO_FUNC3:
-			jz_gpio_write_bit(gpio, JZ_REG_GPIO_TRIGGER_SET);
-		case JZ_GPIO_FUNC2: /* Falltrough */
-			jz_gpio_write_bit(gpio, JZ_REG_GPIO_SELECT_SET);
-			break;
-		default:
-			BUG();
-			break;
-		}
-	}
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(jz_gpio_set_function);
-
-int jz_gpio_bulk_request(const struct jz_gpio_bulk_request *request, size_t num)
-{
-	size_t i;
-	int ret;
-
-	for (i = 0; i < num; ++i, ++request) {
-		ret = gpio_request(request->gpio, request->name);
-		if (ret)
-			goto err;
-		jz_gpio_set_function(request->gpio, request->function);
-	}
-
-	return 0;
-
-err:
-	for (--request; i > 0; --i, --request) {
-		gpio_free(request->gpio);
-		jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
-	}
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(jz_gpio_bulk_request);
-
-void jz_gpio_bulk_free(const struct jz_gpio_bulk_request *request, size_t num)
-{
-	size_t i;
-
-	for (i = 0; i < num; ++i, ++request) {
-		gpio_free(request->gpio);
-		jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
-	}
-
-}
-EXPORT_SYMBOL_GPL(jz_gpio_bulk_free);
-
-void jz_gpio_bulk_suspend(const struct jz_gpio_bulk_request *request, size_t num)
-{
-	size_t i;
-
-	for (i = 0; i < num; ++i, ++request) {
-		jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE);
-		jz_gpio_write_bit(request->gpio, JZ_REG_GPIO_DIRECTION_CLEAR);
-		jz_gpio_write_bit(request->gpio, JZ_REG_GPIO_PULL_SET);
-	}
-}
-EXPORT_SYMBOL_GPL(jz_gpio_bulk_suspend);
-
-void jz_gpio_bulk_resume(const struct jz_gpio_bulk_request *request, size_t num)
-{
-	size_t i;
-
-	for (i = 0; i < num; ++i, ++request)
-		jz_gpio_set_function(request->gpio, request->function);
-}
-EXPORT_SYMBOL_GPL(jz_gpio_bulk_resume);
-
-void jz_gpio_enable_pullup(unsigned gpio)
-{
-	jz_gpio_write_bit(gpio, JZ_REG_GPIO_PULL_CLEAR);
-}
-EXPORT_SYMBOL_GPL(jz_gpio_enable_pullup);
-
-void jz_gpio_disable_pullup(unsigned gpio)
-{
-	jz_gpio_write_bit(gpio, JZ_REG_GPIO_PULL_SET);
-}
-EXPORT_SYMBOL_GPL(jz_gpio_disable_pullup);
-
-static int jz_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
-{
-	return !!(readl(CHIP_TO_REG(chip, JZ_REG_GPIO_PIN)) & BIT(gpio));
-}
-
-static void jz_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
-{
-	uint32_t __iomem *reg = CHIP_TO_REG(chip, JZ_REG_GPIO_DATA_SET);
-	reg += !value;
-	writel(BIT(gpio), reg);
-}
-
-static int jz_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
-	int value)
-{
-	writel(BIT(gpio), CHIP_TO_REG(chip, JZ_REG_GPIO_DIRECTION_SET));
-	jz_gpio_set_value(chip, gpio, value);
-
-	return 0;
-}
-
-static int jz_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
-{
-	writel(BIT(gpio), CHIP_TO_REG(chip, JZ_REG_GPIO_DIRECTION_CLEAR));
-
-	return 0;
-}
-
-static int jz_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
-{
-	struct jz_gpio_chip *jz_gpio = gpiochip_get_data(chip);
-
-	return jz_gpio->irq_base + gpio;
-}
-
-int jz_gpio_port_direction_input(int port, uint32_t mask)
-{
-	writel(mask, GPIO_TO_REG(port, JZ_REG_GPIO_DIRECTION_CLEAR));
-
-	return 0;
-}
-EXPORT_SYMBOL(jz_gpio_port_direction_input);
-
-int jz_gpio_port_direction_output(int port, uint32_t mask)
-{
-	writel(mask, GPIO_TO_REG(port, JZ_REG_GPIO_DIRECTION_SET));
-
-	return 0;
-}
-EXPORT_SYMBOL(jz_gpio_port_direction_output);
-
-void jz_gpio_port_set_value(int port, uint32_t value, uint32_t mask)
-{
-	writel(~value & mask, GPIO_TO_REG(port, JZ_REG_GPIO_DATA_CLEAR));
-	writel(value & mask, GPIO_TO_REG(port, JZ_REG_GPIO_DATA_SET));
-}
-EXPORT_SYMBOL(jz_gpio_port_set_value);
-
-uint32_t jz_gpio_port_get_value(int port, uint32_t mask)
-{
-	uint32_t value = readl(GPIO_TO_REG(port, JZ_REG_GPIO_PIN));
-
-	return value & mask;
-}
-EXPORT_SYMBOL(jz_gpio_port_get_value);
-
-#define IRQ_TO_BIT(irq) BIT((irq - JZ4740_IRQ_GPIO(0)) & 0x1f)
-
-static void jz_gpio_check_trigger_both(struct jz_gpio_chip *chip, unsigned int irq)
-{
-	uint32_t value;
-	void __iomem *reg;
-	uint32_t mask = IRQ_TO_BIT(irq);
-
-	if (!(chip->edge_trigger_both & mask))
-		return;
-
-	reg = chip->base;
-
-	value = readl(chip->base + JZ_REG_GPIO_PIN);
-	if (value & mask)
-		reg += JZ_REG_GPIO_DIRECTION_CLEAR;
-	else
-		reg += JZ_REG_GPIO_DIRECTION_SET;
-
-	writel(mask, reg);
-}
-
-static void jz_gpio_irq_demux_handler(struct irq_desc *desc)
-{
-	uint32_t flag;
-	unsigned int gpio_irq;
-	struct jz_gpio_chip *chip = irq_desc_get_handler_data(desc);
-
-	flag = readl(chip->base + JZ_REG_GPIO_FLAG);
-	if (!flag)
-		return;
-
-	gpio_irq = chip->irq_base + __fls(flag);
-
-	jz_gpio_check_trigger_both(chip, gpio_irq);
-
-	generic_handle_irq(gpio_irq);
-};
-
-static inline void jz_gpio_set_irq_bit(struct irq_data *data, unsigned int reg)
-{
-	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
-	writel(IRQ_TO_BIT(data->irq), chip->base + reg);
-}
-
-static void jz_gpio_irq_unmask(struct irq_data *data)
-{
-	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
-
-	jz_gpio_check_trigger_both(chip, data->irq);
-	irq_gc_unmask_enable_reg(data);
-};
-
-/* TODO: Check if function is gpio */
-static unsigned int jz_gpio_irq_startup(struct irq_data *data)
-{
-	jz_gpio_set_irq_bit(data, JZ_REG_GPIO_SELECT_SET);
-	jz_gpio_irq_unmask(data);
-	return 0;
-}
-
-static void jz_gpio_irq_shutdown(struct irq_data *data)
-{
-	irq_gc_mask_disable_reg(data);
-
-	/* Set direction to input */
-	jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR);
-	jz_gpio_set_irq_bit(data, JZ_REG_GPIO_SELECT_CLEAR);
-}
-
-static int jz_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type)
-{
-	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
-	unsigned int irq = data->irq;
-
-	if (flow_type == IRQ_TYPE_EDGE_BOTH) {
-		uint32_t value = readl(chip->base + JZ_REG_GPIO_PIN);
-		if (value & IRQ_TO_BIT(irq))
-			flow_type = IRQ_TYPE_EDGE_FALLING;
-		else
-			flow_type = IRQ_TYPE_EDGE_RISING;
-		chip->edge_trigger_both |= IRQ_TO_BIT(irq);
-	} else {
-		chip->edge_trigger_both &= ~IRQ_TO_BIT(irq);
-	}
-
-	switch (flow_type) {
-	case IRQ_TYPE_EDGE_RISING:
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_SET);
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_SET);
-		break;
-	case IRQ_TYPE_EDGE_FALLING:
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR);
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_SET);
-		break;
-	case IRQ_TYPE_LEVEL_HIGH:
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_SET);
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_CLEAR);
-		break;
-	case IRQ_TYPE_LEVEL_LOW:
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_DIRECTION_CLEAR);
-		jz_gpio_set_irq_bit(data, JZ_REG_GPIO_TRIGGER_CLEAR);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int jz_gpio_irq_set_wake(struct irq_data *data, unsigned int on)
-{
-	struct jz_gpio_chip *chip = irq_to_jz_gpio_chip(data);
-
-	irq_gc_set_wake(data, on);
-	irq_set_irq_wake(chip->irq, on);
-
-	return 0;
-}
-
-#define JZ4740_GPIO_CHIP(_bank) { \
-	.irq_base = JZ4740_IRQ_GPIO_BASE_ ## _bank, \
-	.gpio_chip = { \
-		.label = "Bank " # _bank, \
-		.owner = THIS_MODULE, \
-		.set = jz_gpio_set_value, \
-		.get = jz_gpio_get_value, \
-		.direction_output = jz_gpio_direction_output, \
-		.direction_input = jz_gpio_direction_input, \
-		.to_irq = jz_gpio_to_irq, \
-		.base = JZ4740_GPIO_BASE_ ## _bank, \
-		.ngpio = JZ4740_GPIO_NUM_ ## _bank, \
-	}, \
-}
-
-static struct jz_gpio_chip jz4740_gpio_chips[] = {
-	JZ4740_GPIO_CHIP(A),
-	JZ4740_GPIO_CHIP(B),
-	JZ4740_GPIO_CHIP(C),
-	JZ4740_GPIO_CHIP(D),
-};
-
-static void jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id)
-{
-	struct irq_chip_generic *gc;
-	struct irq_chip_type *ct;
-
-	chip->base = ioremap(JZ4740_GPIO_BASE_ADDR + (id * 0x100), 0x100);
-
-	chip->irq = JZ4740_IRQ_INTC_GPIO(id);
-	irq_set_chained_handler_and_data(chip->irq,
-					 jz_gpio_irq_demux_handler, chip);
-
-	gc = irq_alloc_generic_chip(chip->gpio_chip.label, 1, chip->irq_base,
-		chip->base, handle_level_irq);
-
-	gc->wake_enabled = IRQ_MSK(chip->gpio_chip.ngpio);
-	gc->private = chip;
-
-	ct = gc->chip_types;
-	ct->regs.enable = JZ_REG_GPIO_MASK_CLEAR;
-	ct->regs.disable = JZ_REG_GPIO_MASK_SET;
-	ct->regs.ack = JZ_REG_GPIO_FLAG_CLEAR;
-
-	ct->chip.name = "GPIO";
-	ct->chip.irq_mask = irq_gc_mask_disable_reg;
-	ct->chip.irq_unmask = jz_gpio_irq_unmask;
-	ct->chip.irq_ack = irq_gc_ack_set_bit;
-	ct->chip.irq_suspend = ingenic_intc_irq_suspend;
-	ct->chip.irq_resume = ingenic_intc_irq_resume;
-	ct->chip.irq_startup = jz_gpio_irq_startup;
-	ct->chip.irq_shutdown = jz_gpio_irq_shutdown;
-	ct->chip.irq_set_type = jz_gpio_irq_set_type;
-	ct->chip.irq_set_wake = jz_gpio_irq_set_wake;
-	ct->chip.flags = IRQCHIP_SET_TYPE_MASKED;
-
-	irq_setup_generic_chip(gc, IRQ_MSK(chip->gpio_chip.ngpio),
-		IRQ_GC_INIT_NESTED_LOCK, 0, IRQ_NOPROBE | IRQ_LEVEL);
-
-	gpiochip_add_data(&chip->gpio_chip, chip);
-}
-
-static int __init jz4740_gpio_init(void)
-{
-	unsigned int i;
-
-	for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i)
-		jz4740_gpio_chip_init(&jz4740_gpio_chips[i], i);
-
-	printk(KERN_INFO "JZ4740 GPIO initialized\n");
-
-	return 0;
-}
-arch_initcall(jz4740_gpio_init);
-
-#ifdef CONFIG_DEBUG_FS
-
-static inline void gpio_seq_reg(struct seq_file *s, struct jz_gpio_chip *chip,
-	const char *name, unsigned int reg)
-{
-	seq_printf(s, "\t%s: %08x\n", name, readl(chip->base + reg));
-}
-
-static int gpio_regs_show(struct seq_file *s, void *unused)
-{
-	struct jz_gpio_chip *chip = jz4740_gpio_chips;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i, ++chip) {
-		seq_printf(s, "==GPIO %d==\n", i);
-		gpio_seq_reg(s, chip, "Pin", JZ_REG_GPIO_PIN);
-		gpio_seq_reg(s, chip, "Data", JZ_REG_GPIO_DATA);
-		gpio_seq_reg(s, chip, "Mask", JZ_REG_GPIO_MASK);
-		gpio_seq_reg(s, chip, "Pull", JZ_REG_GPIO_PULL);
-		gpio_seq_reg(s, chip, "Func", JZ_REG_GPIO_FUNC);
-		gpio_seq_reg(s, chip, "Select", JZ_REG_GPIO_SELECT);
-		gpio_seq_reg(s, chip, "Direction", JZ_REG_GPIO_DIRECTION);
-		gpio_seq_reg(s, chip, "Trigger", JZ_REG_GPIO_TRIGGER);
-		gpio_seq_reg(s, chip, "Flag", JZ_REG_GPIO_FLAG);
-	}
-
-	return 0;
-}
-
-static int gpio_regs_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, gpio_regs_show, NULL);
-}
-
-static const struct file_operations gpio_regs_operations = {
-	.open		= gpio_regs_open,
-	.read		= seq_read,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static int __init gpio_debugfs_init(void)
-{
-	(void) debugfs_create_file("jz_regs_gpio", S_IFREG | S_IRUGO,
-				NULL, NULL, &gpio_regs_operations);
-	return 0;
-}
-subsys_initcall(gpio_debugfs_init);
-
-#endif
-- 
2.11.0

^ permalink raw reply	[flat|nested] 162+ messages in thread

* Re: [PATCH v5 03/14] pinctrl: add a pinctrl driver for the Ingenic jz47xx SoCs
  2017-04-28 20:08               ` [PATCH v5 03/14] pinctrl: add a pinctrl driver for the Ingenic jz47xx SoCs Paul Cercueil
@ 2017-05-03  9:12                 ` Paul Cercueil
  2017-05-11 11:01                   ` Linus Walleij
  0 siblings, 1 reply; 162+ messages in thread
From: Paul Cercueil @ 2017-05-03  9:12 UTC (permalink / raw)
  To: Linus Walleij, Alexandre Courbot, Rob Herring, Mark Rutland,
	Ralf Baechle
  Cc: Boris Brezillon, Thierry Reding, Bartlomiej Zolnierkiewicz,
	Maarten ter Huurne, Lars-Peter Clausen, Paul Burton, james.hogan,
	linux-gpio, devicetree, linux-kernel, linux-mips, linux-mmc,
	linux-mtd, linux-pwm, linux-fbdev

The dependency on MFD is gone but now I notice I forgot to remove the 
'select MFD_CORE'
in the Kconfig. It'd be great if you can make a quick edit when merging 
this,
otherwise I'll send a v6.

- Paul

Le 2017-04-28 22:08, Paul Cercueil a écrit :
> This driver handles pin configuration and pin muxing for the
> JZ4740 and JZ4780 SoCs from Ingenic.
> 
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
> ---
>  drivers/pinctrl/Kconfig           |  10 +
>  drivers/pinctrl/Makefile          |   1 +
>  drivers/pinctrl/pinctrl-ingenic.c | 852 
> ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 863 insertions(+)
>  create mode 100644 drivers/pinctrl/pinctrl-ingenic.c
> 
>  v2: Consider it's a new patch. Completely rewritten from v1.
>  v3: 'unsigned' -> 'unsigned int'
>  v4: Completely rewritten from v3.
>  v5: Probe child devices directly instead of using MFD framework
> 
> diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
> index 8f8c2af45781..82ce72fcb8e0 100644
> --- a/drivers/pinctrl/Kconfig
> +++ b/drivers/pinctrl/Kconfig
> @@ -285,6 +285,16 @@ config PINCTRL_ZYNQ
>  	help
>  	  This selects the pinctrl driver for Xilinx Zynq.
> 
> +config PINCTRL_INGENIC
> +	bool "Pinctrl driver for the Ingenic JZ47xx SoCs"
> +	default y
> +	depends on MACH_INGENIC || COMPILE_TEST
> +	select GENERIC_PINCONF
> +	select GENERIC_PINCTRL_GROUPS
> +	select GENERIC_PINMUX_FUNCTIONS
> +	select REGMAP_MMIO
> +	select MFD_CORE
> +
>  source "drivers/pinctrl/aspeed/Kconfig"
>  source "drivers/pinctrl/bcm/Kconfig"
>  source "drivers/pinctrl/berlin/Kconfig"
> diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
> index a251f439626f..80f327239d4b 100644
> --- a/drivers/pinctrl/Makefile
> +++ b/drivers/pinctrl/Makefile
> @@ -38,6 +38,7 @@ obj-$(CONFIG_PINCTRL_LPC18XX)	+= pinctrl-lpc18xx.o
>  obj-$(CONFIG_PINCTRL_TB10X)	+= pinctrl-tb10x.o
>  obj-$(CONFIG_PINCTRL_ST) 	+= pinctrl-st.o
>  obj-$(CONFIG_PINCTRL_ZYNQ)	+= pinctrl-zynq.o
> +obj-$(CONFIG_PINCTRL_INGENIC)	+= pinctrl-ingenic.o
> 
>  obj-$(CONFIG_ARCH_ASPEED)	+= aspeed/
>  obj-y				+= bcm/
> diff --git a/drivers/pinctrl/pinctrl-ingenic.c
> b/drivers/pinctrl/pinctrl-ingenic.c
> new file mode 100644
> index 000000000000..d8473d929cb1
> --- /dev/null
> +++ b/drivers/pinctrl/pinctrl-ingenic.c
> @@ -0,0 +1,852 @@
> +/*
> + * Ingenic SoCs pinctrl driver
> + *
> + * Copyright (c) 2017 Paul Cercueil <paul@crapouillou.net>
> + *
> + * License terms: GNU General Public License (GPL) version 2
> + */
> +
> +#include <linux/compiler.h>
> +#include <linux/gpio.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/of_device.h>
> +#include <linux/of_platform.h>
> +#include <linux/pinctrl/pinctrl.h>
> +#include <linux/pinctrl/pinmux.h>
> +#include <linux/pinctrl/pinconf.h>
> +#include <linux/pinctrl/pinconf-generic.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +
> +#include "core.h"
> +#include "pinconf.h"
> +#include "pinmux.h"
> +
> +#define JZ4740_GPIO_DATA	0x10
> +#define JZ4740_GPIO_PULL_DIS	0x30
> +#define JZ4740_GPIO_FUNC	0x40
> +#define JZ4740_GPIO_SELECT	0x50
> +#define JZ4740_GPIO_DIR		0x60
> +#define JZ4740_GPIO_TRIG	0x70
> +#define JZ4740_GPIO_FLAG	0x80
> +
> +#define JZ4770_GPIO_INT		0x10
> +#define JZ4770_GPIO_MSK		0x20
> +#define JZ4770_GPIO_PAT1	0x30
> +#define JZ4770_GPIO_PAT0	0x40
> +#define JZ4770_GPIO_FLAG	0x50
> +#define JZ4770_GPIO_PEN		0x70
> +
> +#define REG_SET(x) ((x) + 0x4)
> +#define REG_CLEAR(x) ((x) + 0x8)
> +
> +#define PINS_PER_GPIO_CHIP 32
> +
> +enum jz_version {
> +	ID_JZ4740,
> +	ID_JZ4770,
> +	ID_JZ4780,
> +};
> +
> +struct ingenic_chip_info {
> +	unsigned int num_chips;
> +
> +	const struct group_desc *groups;
> +	unsigned int num_groups;
> +
> +	const struct function_desc *functions;
> +	unsigned int num_functions;
> +
> +	const u32 *pull_ups, *pull_downs;
> +};
> +
> +struct ingenic_pinctrl {
> +	struct device *dev;
> +	struct regmap *map;
> +	struct pinctrl_dev *pctl;
> +	struct pinctrl_pin_desc *pdesc;
> +	enum jz_version version;
> +
> +	const struct ingenic_chip_info *info;
> +};
> +
> +static const u32 jz4740_pull_ups[4] = {
> +	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
> +};
> +
> +static const u32 jz4740_pull_downs[4] = {
> +	0x00000000, 0x00000000, 0x00000000, 0x00000000,
> +};
> +
> +static int jz4740_mmc_1bit_pins[] = { 0x69, 0x68, 0x6a, };
> +static int jz4740_mmc_4bit_pins[] = { 0x6b, 0x6c, 0x6d, };
> +static int jz4740_uart0_data_pins[] = { 0x7a, 0x79, };
> +static int jz4740_uart0_hwflow_pins[] = { 0x7e, 0x7f, };
> +static int jz4740_uart1_data_pins[] = { 0x7e, 0x7f, };
> +static int jz4740_lcd_8bit_pins[] = {
> +	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x52, 0x53, 0x54,
> +};
> +static int jz4740_lcd_16bit_pins[] = {
> +	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x55,
> +};
> +static int jz4740_lcd_18bit_pins[] = { 0x50, 0x51, };
> +static int jz4740_lcd_18bit_tft_pins[] = { 0x56, 0x57, 0x31, 0x32, };
> +static int jz4740_nand_cs1_pins[] = { 0x39, };
> +static int jz4740_nand_cs2_pins[] = { 0x3a, };
> +static int jz4740_nand_cs3_pins[] = { 0x3b, };
> +static int jz4740_nand_cs4_pins[] = { 0x3c, };
> +static int jz4740_pwm_pwm0_pins[] = { 0x77, };
> +static int jz4740_pwm_pwm1_pins[] = { 0x78, };
> +static int jz4740_pwm_pwm2_pins[] = { 0x79, };
> +static int jz4740_pwm_pwm3_pins[] = { 0x7a, };
> +static int jz4740_pwm_pwm4_pins[] = { 0x7b, };
> +static int jz4740_pwm_pwm5_pins[] = { 0x7c, };
> +static int jz4740_pwm_pwm6_pins[] = { 0x7e, };
> +static int jz4740_pwm_pwm7_pins[] = { 0x7f, };
> +
> +static int jz4740_mmc_1bit_funcs[] = { 0, 0, 0, };
> +static int jz4740_mmc_4bit_funcs[] = { 0, 0, 0, };
> +static int jz4740_uart0_data_funcs[] = { 1, 1, };
> +static int jz4740_uart0_hwflow_funcs[] = { 1, 1, };
> +static int jz4740_uart1_data_funcs[] = { 2, 2, };
> +static int jz4740_lcd_8bit_funcs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
> 0, };
> +static int jz4740_lcd_16bit_funcs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, };
> +static int jz4740_lcd_18bit_funcs[] = { 0, 0, };
> +static int jz4740_lcd_18bit_tft_funcs[] = { 0, 0, 0, 0, };
> +static int jz4740_nand_cs1_funcs[] = { 0, };
> +static int jz4740_nand_cs2_funcs[] = { 0, };
> +static int jz4740_nand_cs3_funcs[] = { 0, };
> +static int jz4740_nand_cs4_funcs[] = { 0, };
> +static int jz4740_pwm_pwm0_funcs[] = { 0, };
> +static int jz4740_pwm_pwm1_funcs[] = { 0, };
> +static int jz4740_pwm_pwm2_funcs[] = { 0, };
> +static int jz4740_pwm_pwm3_funcs[] = { 0, };
> +static int jz4740_pwm_pwm4_funcs[] = { 0, };
> +static int jz4740_pwm_pwm5_funcs[] = { 0, };
> +static int jz4740_pwm_pwm6_funcs[] = { 0, };
> +static int jz4740_pwm_pwm7_funcs[] = { 0, };
> +
> +#define INGENIC_PIN_GROUP(name, id)			\
> +	{						\
> +		name,					\
> +		id##_pins,				\
> +		ARRAY_SIZE(id##_pins),			\
> +		id##_funcs,				\
> +	}
> +
> +static const struct group_desc jz4740_groups[] = {
> +	INGENIC_PIN_GROUP("mmc-1bit", jz4740_mmc_1bit),
> +	INGENIC_PIN_GROUP("mmc-4bit", jz4740_mmc_4bit),
> +	INGENIC_PIN_GROUP("uart0-data", jz4740_uart0_data),
> +	INGENIC_PIN_GROUP("uart0-hwflow", jz4740_uart0_hwflow),
> +	INGENIC_PIN_GROUP("uart1-data", jz4740_uart1_data),
> +	INGENIC_PIN_GROUP("lcd-8bit", jz4740_lcd_8bit),
> +	INGENIC_PIN_GROUP("lcd-16bit", jz4740_lcd_16bit),
> +	INGENIC_PIN_GROUP("lcd-18bit", jz4740_lcd_18bit),
> +	INGENIC_PIN_GROUP("lcd-18bit-tft", jz4740_lcd_18bit_tft),
> +	{ "lcd-no-pins", },
> +	INGENIC_PIN_GROUP("nand-cs1", jz4740_nand_cs1),
> +	INGENIC_PIN_GROUP("nand-cs2", jz4740_nand_cs2),
> +	INGENIC_PIN_GROUP("nand-cs3", jz4740_nand_cs3),
> +	INGENIC_PIN_GROUP("nand-cs4", jz4740_nand_cs4),
> +	INGENIC_PIN_GROUP("pwm0", jz4740_pwm_pwm0),
> +	INGENIC_PIN_GROUP("pwm1", jz4740_pwm_pwm1),
> +	INGENIC_PIN_GROUP("pwm2", jz4740_pwm_pwm2),
> +	INGENIC_PIN_GROUP("pwm3", jz4740_pwm_pwm3),
> +	INGENIC_PIN_GROUP("pwm4", jz4740_pwm_pwm4),
> +	INGENIC_PIN_GROUP("pwm5", jz4740_pwm_pwm5),
> +	INGENIC_PIN_GROUP("pwm6", jz4740_pwm_pwm6),
> +	INGENIC_PIN_GROUP("pwm7", jz4740_pwm_pwm7),
> +};
> +
> +static const char *jz4740_mmc_groups[] = { "mmc-1bit", "mmc-4bit", };
> +static const char *jz4740_uart0_groups[] = { "uart0-data", 
> "uart0-hwflow", };
> +static const char *jz4740_uart1_groups[] = { "uart1-data", };
> +static const char *jz4740_lcd_groups[] = {
> +	"lcd-8bit", "lcd-16bit", "lcd-18bit", "lcd-18bit-tft", "lcd-no-pins",
> +};
> +static const char *jz4740_nand_groups[] = {
> +	"nand-cs1", "nand-cs2", "nand-cs3", "nand-cs4",
> +};
> +static const char *jz4740_pwm0_groups[] = { "pwm0", };
> +static const char *jz4740_pwm1_groups[] = { "pwm1", };
> +static const char *jz4740_pwm2_groups[] = { "pwm2", };
> +static const char *jz4740_pwm3_groups[] = { "pwm3", };
> +static const char *jz4740_pwm4_groups[] = { "pwm4", };
> +static const char *jz4740_pwm5_groups[] = { "pwm5", };
> +static const char *jz4740_pwm6_groups[] = { "pwm6", };
> +static const char *jz4740_pwm7_groups[] = { "pwm7", };
> +
> +static const struct function_desc jz4740_functions[] = {
> +	{ "mmc", jz4740_mmc_groups, ARRAY_SIZE(jz4740_mmc_groups), },
> +	{ "uart0", jz4740_uart0_groups, ARRAY_SIZE(jz4740_uart0_groups), },
> +	{ "uart1", jz4740_uart1_groups, ARRAY_SIZE(jz4740_uart1_groups), },
> +	{ "lcd", jz4740_lcd_groups, ARRAY_SIZE(jz4740_lcd_groups), },
> +	{ "nand", jz4740_nand_groups, ARRAY_SIZE(jz4740_nand_groups), },
> +	{ "pwm0", jz4740_pwm0_groups, ARRAY_SIZE(jz4740_pwm0_groups), },
> +	{ "pwm1", jz4740_pwm1_groups, ARRAY_SIZE(jz4740_pwm1_groups), },
> +	{ "pwm2", jz4740_pwm2_groups, ARRAY_SIZE(jz4740_pwm2_groups), },
> +	{ "pwm3", jz4740_pwm3_groups, ARRAY_SIZE(jz4740_pwm3_groups), },
> +	{ "pwm4", jz4740_pwm4_groups, ARRAY_SIZE(jz4740_pwm4_groups), },
> +	{ "pwm5", jz4740_pwm5_groups, ARRAY_SIZE(jz4740_pwm5_groups), },
> +	{ "pwm6", jz4740_pwm6_groups, ARRAY_SIZE(jz4740_pwm6_groups), },
> +	{ "pwm7", jz4740_pwm7_groups, ARRAY_SIZE(jz4740_pwm7_groups), },
> +};
> +
> +static const struct ingenic_chip_info jz4740_chip_info = {
> +	.num_chips = 4,
> +	.groups = jz4740_groups,
> +	.num_groups = ARRAY_SIZE(jz4740_groups),
> +	.functions = jz4740_functions,
> +	.num_functions = ARRAY_SIZE(jz4740_functions),
> +	.pull_ups = jz4740_pull_ups,
> +	.pull_downs = jz4740_pull_downs,
> +};
> +
> +static const u32 jz4770_pull_ups[6] = {
> +	0x3fffffff, 0xfff0030c, 0xffffffff, 0xffff4fff, 0xfffffb7c, 
> 0xffa7f00f,
> +};
> +
> +static const u32 jz4770_pull_downs[6] = {
> +	0x00000000, 0x000f0c03, 0x00000000, 0x0000b000, 0x00000483, 
> 0x00580ff0,
> +};
> +
> +static int jz4770_uart0_data_pins[] = { 0xa0, 0xa3, };
> +static int jz4770_uart0_hwflow_pins[] = { 0xa1, 0xa2, };
> +static int jz4770_uart1_data_pins[] = { 0x7a, 0x7c, };
> +static int jz4770_uart1_hwflow_pins[] = { 0x7b, 0x7d, };
> +static int jz4770_uart2_data_pins[] = { 0x66, 0x67, };
> +static int jz4770_uart2_hwflow_pins[] = { 0x65, 0x64, };
> +static int jz4770_uart3_data_pins[] = { 0x6c, 0x85, };
> +static int jz4770_uart3_hwflow_pins[] = { 0x88, 0x89, };
> +static int jz4770_uart4_data_pins[] = { 0x54, 0x4a, };
> +static int jz4770_mmc0_8bit_a_pins[] = { 0x04, 0x05, 0x06, 0x07, 0x18, 
> };
> +static int jz4770_mmc0_4bit_a_pins[] = { 0x15, 0x16, 0x17, };
> +static int jz4770_mmc0_1bit_a_pins[] = { 0x12, 0x13, 0x14, };
> +static int jz4770_mmc0_4bit_e_pins[] = { 0x95, 0x96, 0x97, };
> +static int jz4770_mmc0_1bit_e_pins[] = { 0x9c, 0x9d, 0x94, };
> +static int jz4770_mmc1_4bit_d_pins[] = { 0x75, 0x76, 0x77, };
> +static int jz4770_mmc1_1bit_d_pins[] = { 0x78, 0x79, 0x74, };
> +static int jz4770_mmc1_4bit_e_pins[] = { 0x95, 0x96, 0x97, };
> +static int jz4770_mmc1_1bit_e_pins[] = { 0x9c, 0x9d, 0x94, };
> +static int jz4770_nemc_data_pins[] = {
> +	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
> +};
> +static int jz4770_nemc_cle_ale_pins[] = { 0x20, 0x21, };
> +static int jz4770_nemc_addr_pins[] = { 0x22, 0x23, 0x24, 0x25, };
> +static int jz4770_nemc_rd_we_pins[] = { 0x10, 0x11, };
> +static int jz4770_nemc_frd_fwe_pins[] = { 0x12, 0x13, };
> +static int jz4770_nemc_cs1_pins[] = { 0x15, };
> +static int jz4770_nemc_cs2_pins[] = { 0x16, };
> +static int jz4770_nemc_cs3_pins[] = { 0x17, };
> +static int jz4770_nemc_cs4_pins[] = { 0x18, };
> +static int jz4770_nemc_cs5_pins[] = { 0x19, };
> +static int jz4770_nemc_cs6_pins[] = { 0x1a, };
> +static int jz4770_i2c0_pins[] = { 0x6e, 0x6f, };
> +static int jz4770_i2c1_pins[] = { 0x8e, 0x8f, };
> +static int jz4770_i2c2_pins[] = { 0xb0, 0xb1, };
> +static int jz4770_i2c3_pins[] = { 0x6a, 0x6b, };
> +static int jz4770_i2c4_e_pins[] = { 0x8c, 0x8d, };
> +static int jz4770_i2c4_f_pins[] = { 0xb9, 0xb8, };
> +static int jz4770_cim_pins[] = {
> +	0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 
> 0x31,
> +};
> +static int jz4770_lcd_32bit_pins[] = {
> +	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
> +	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
> +	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
> +	0x58, 0x59, 0x51,
> +};
> +static int jz4770_pwm_pwm0_pins[] = { 0x80, };
> +static int jz4770_pwm_pwm1_pins[] = { 0x81, };
> +static int jz4770_pwm_pwm2_pins[] = { 0x82, };
> +static int jz4770_pwm_pwm3_pins[] = { 0x83, };
> +static int jz4770_pwm_pwm4_pins[] = { 0x84, };
> +static int jz4770_pwm_pwm5_pins[] = { 0x85, };
> +static int jz4770_pwm_pwm6_pins[] = { 0x6a, };
> +static int jz4770_pwm_pwm7_pins[] = { 0x6b, };
> +
> +static int jz4770_uart0_data_funcs[] = { 0, 0, };
> +static int jz4770_uart0_hwflow_funcs[] = { 0, 0, };
> +static int jz4770_uart1_data_funcs[] = { 0, 0, };
> +static int jz4770_uart1_hwflow_funcs[] = { 0, 0, };
> +static int jz4770_uart2_data_funcs[] = { 1, 1, };
> +static int jz4770_uart2_hwflow_funcs[] = { 1, 1, };
> +static int jz4770_uart3_data_funcs[] = { 0, 1, };
> +static int jz4770_uart3_hwflow_funcs[] = { 0, 0, };
> +static int jz4770_uart4_data_funcs[] = { 2, 2, };
> +static int jz4770_mmc0_8bit_a_funcs[] = { 1, 1, 1, 1, 1, };
> +static int jz4770_mmc0_4bit_a_funcs[] = { 1, 1, 1, };
> +static int jz4770_mmc0_1bit_a_funcs[] = { 1, 1, 0, };
> +static int jz4770_mmc0_4bit_e_funcs[] = { 0, 0, 0, };
> +static int jz4770_mmc0_1bit_e_funcs[] = { 0, 0, 0, };
> +static int jz4770_mmc1_4bit_d_funcs[] = { 0, 0, 0, };
> +static int jz4770_mmc1_1bit_d_funcs[] = { 0, 0, 0, };
> +static int jz4770_mmc1_4bit_e_funcs[] = { 1, 1, 1, };
> +static int jz4770_mmc1_1bit_e_funcs[] = { 1, 1, 1, };
> +static int jz4770_nemc_data_funcs[] = { 0, 0, 0, 0, 0, 0, 0, 0, };
> +static int jz4770_nemc_cle_ale_funcs[] = { 0, 0, };
> +static int jz4770_nemc_addr_funcs[] = { 0, 0, 0, 0, };
> +static int jz4770_nemc_rd_we_funcs[] = { 0, 0, };
> +static int jz4770_nemc_frd_fwe_funcs[] = { 0, 0, };
> +static int jz4770_nemc_cs1_funcs[] = { 0, };
> +static int jz4770_nemc_cs2_funcs[] = { 0, };
> +static int jz4770_nemc_cs3_funcs[] = { 0, };
> +static int jz4770_nemc_cs4_funcs[] = { 0, };
> +static int jz4770_nemc_cs5_funcs[] = { 0, };
> +static int jz4770_nemc_cs6_funcs[] = { 0, };
> +static int jz4770_i2c0_funcs[] = { 0, 0, };
> +static int jz4770_i2c1_funcs[] = { 0, 0, };
> +static int jz4770_i2c2_funcs[] = { 2, 2, };
> +static int jz4770_i2c3_funcs[] = { 1, 1, };
> +static int jz4770_i2c4_e_funcs[] = { 1, 1, };
> +static int jz4770_i2c4_f_funcs[] = { 1, 1, };
> +static int jz4770_cim_funcs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
> };
> +static int jz4770_lcd_32bit_funcs[] = {
> +	0, 0, 0, 0, 0, 0, 0, 0,
> +	0, 0, 0, 0, 0, 0, 0, 0,
> +	0, 0, 0,
> +};
> +static int jz4770_pwm_pwm0_funcs[] = { 0, };
> +static int jz4770_pwm_pwm1_funcs[] = { 0, };
> +static int jz4770_pwm_pwm2_funcs[] = { 0, };
> +static int jz4770_pwm_pwm3_funcs[] = { 0, };
> +static int jz4770_pwm_pwm4_funcs[] = { 0, };
> +static int jz4770_pwm_pwm5_funcs[] = { 0, };
> +static int jz4770_pwm_pwm6_funcs[] = { 0, };
> +static int jz4770_pwm_pwm7_funcs[] = { 0, };
> +
> +static const struct group_desc jz4770_groups[] = {
> +	INGENIC_PIN_GROUP("uart0-data", jz4770_uart0_data),
> +	INGENIC_PIN_GROUP("uart0-hwflow", jz4770_uart0_hwflow),
> +	INGENIC_PIN_GROUP("uart1-data", jz4770_uart1_data),
> +	INGENIC_PIN_GROUP("uart1-hwflow", jz4770_uart1_hwflow),
> +	INGENIC_PIN_GROUP("uart2-data", jz4770_uart2_data),
> +	INGENIC_PIN_GROUP("uart2-hwflow", jz4770_uart2_hwflow),
> +	INGENIC_PIN_GROUP("uart3-data", jz4770_uart3_data),
> +	INGENIC_PIN_GROUP("uart3-hwflow", jz4770_uart3_hwflow),
> +	INGENIC_PIN_GROUP("uart4-data", jz4770_uart4_data),
> +	INGENIC_PIN_GROUP("mmc0-8bit-a", jz4770_mmc0_8bit_a),
> +	INGENIC_PIN_GROUP("mmc0-4bit-a", jz4770_mmc0_4bit_a),
> +	INGENIC_PIN_GROUP("mmc0-1bit-a", jz4770_mmc0_1bit_a),
> +	INGENIC_PIN_GROUP("mmc0-4bit-e", jz4770_mmc0_4bit_e),
> +	INGENIC_PIN_GROUP("mmc0-1bit-e", jz4770_mmc0_1bit_e),
> +	INGENIC_PIN_GROUP("mmc1-4bit-d", jz4770_mmc1_4bit_d),
> +	INGENIC_PIN_GROUP("mmc1-1bit-d", jz4770_mmc1_1bit_d),
> +	INGENIC_PIN_GROUP("mmc1-4bit-e", jz4770_mmc1_4bit_e),
> +	INGENIC_PIN_GROUP("mmc1-1bit-e", jz4770_mmc1_1bit_e),
> +	INGENIC_PIN_GROUP("nemc-data", jz4770_nemc_data),
> +	INGENIC_PIN_GROUP("nemc-cle-ale", jz4770_nemc_cle_ale),
> +	INGENIC_PIN_GROUP("nemc-addr", jz4770_nemc_addr),
> +	INGENIC_PIN_GROUP("nemc-rd-we", jz4770_nemc_rd_we),
> +	INGENIC_PIN_GROUP("nemc-frd-fwe", jz4770_nemc_frd_fwe),
> +	INGENIC_PIN_GROUP("nemc-cs1", jz4770_nemc_cs1),
> +	INGENIC_PIN_GROUP("nemc-cs2", jz4770_nemc_cs2),
> +	INGENIC_PIN_GROUP("nemc-cs3", jz4770_nemc_cs3),
> +	INGENIC_PIN_GROUP("nemc-cs4", jz4770_nemc_cs4),
> +	INGENIC_PIN_GROUP("nemc-cs5", jz4770_nemc_cs5),
> +	INGENIC_PIN_GROUP("nemc-cs6", jz4770_nemc_cs6),
> +	INGENIC_PIN_GROUP("i2c0-data", jz4770_i2c0),
> +	INGENIC_PIN_GROUP("i2c1-data", jz4770_i2c1),
> +	INGENIC_PIN_GROUP("i2c2-data", jz4770_i2c2),
> +	INGENIC_PIN_GROUP("i2c3-data", jz4770_i2c3),
> +	INGENIC_PIN_GROUP("i2c4-data-e", jz4770_i2c4_e),
> +	INGENIC_PIN_GROUP("i2c4-data-f", jz4770_i2c4_f),
> +	INGENIC_PIN_GROUP("cim-data", jz4770_cim),
> +	INGENIC_PIN_GROUP("lcd-32bit", jz4770_lcd_32bit),
> +	{ "lcd-no-pins", },
> +	INGENIC_PIN_GROUP("pwm0", jz4770_pwm_pwm0),
> +	INGENIC_PIN_GROUP("pwm1", jz4770_pwm_pwm1),
> +	INGENIC_PIN_GROUP("pwm2", jz4770_pwm_pwm2),
> +	INGENIC_PIN_GROUP("pwm3", jz4770_pwm_pwm3),
> +	INGENIC_PIN_GROUP("pwm4", jz4770_pwm_pwm4),
> +	INGENIC_PIN_GROUP("pwm5", jz4770_pwm_pwm5),
> +	INGENIC_PIN_GROUP("pwm6", jz4770_pwm_pwm6),
> +	INGENIC_PIN_GROUP("pwm7", jz4770_pwm_pwm7),
> +};
> +
> +stati