All of lore.kernel.org
 help / color / mirror / Atom feed
* Renesas RZ/A1 pin and gpio controller
@ 2017-02-20 17:13 Jacopo Mondi
       [not found] ` <1487610788-6939-1-git-send-email-jacopo+renesas-AW8dsiIh9cEdnm+yROfE0A@public.gmane.org>
                   ` (2 more replies)
  0 siblings, 3 replies; 29+ messages in thread
From: Jacopo Mondi @ 2017-02-20 17:13 UTC (permalink / raw)
  To: geert+renesas, laurent.pinchart, linus.walleij, robh+dt,
	mark.rutland, linux
  Cc: linux-renesas-soc, linux-gpio, devicetree

Hello,
   this is the first submission of combined GPIO and pin controller driver
for Renesas RZ/A1 SoC.

Compared to my RFC series on the same subject, this new implementation
supports a single SoC. If more devices with a similar pin controller will
arrive later, we will consider supporting them through this driver.

The series adds the driver itself and register the pincontroller in dtsi.
The pin controller hardware supports 12 ports, each of them is also a gpio
controller.

The series makes use of pinctrl and pinmux generic function currently
available in Linus Walleij's linux-pinctrl.git tree.

Testing done veryfing functionalities of hardware modules enabled in device
tree (SCIF2 for serial output, RIIC for accessing an internal eeprom chip and
user visible leds).
Gpio have been also verified using a i2c-gpio device in place of the native
RIIC one to access the same eeprom device.

Thanks
   j

Jacopo Mondi (7):
  pinctrl: Renesas RZ/A1 pin and gpio controller
  Documentation: devicetree: bindings: Add RZ/A1 pinctrl binding
    documentation
  arm: dts: dt-bindings: Add Renesas RZ pinctrl header
  arm: dts: r7s72100: Add pin controller node
  arm: dts: genmai: Add SCIF2 pin group
  arm: dts: genmai: Add RIIC2 pin group
  arm: dts: genmai: Add user led device nodes

 .../bindings/pinctrl/renesas,rza1-pinctrl.txt      |  114 +++
 arch/arm/boot/dts/r7s72100-genmai.dts              |   35 +
 arch/arm/boot/dts/r7s72100.dtsi                    |   81 ++
 drivers/pinctrl/Kconfig                            |   10 +
 drivers/pinctrl/Makefile                           |    1 +
 drivers/pinctrl/pinctrl-rza1.c                     | 1026 ++++++++++++++++++++
 include/dt-bindings/pinctrl/r7s72100-pinctrl.h     |   30 +
 7 files changed, 1297 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/renesas,rza1-pinctrl.txt
 create mode 100644 drivers/pinctrl/pinctrl-rza1.c
 create mode 100644 include/dt-bindings/pinctrl/r7s72100-pinctrl.h

-- 
2.7.4


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

* [PATCH 1/7] pinctrl: Renesas RZ/A1 pin and gpio controller
  2017-02-20 17:13 Renesas RZ/A1 pin and gpio controller Jacopo Mondi
@ 2017-02-20 17:13     ` Jacopo Mondi
  2017-02-20 17:13 ` [PATCH 5/7] arm: dts: genmai: Add SCIF2 pin group Jacopo Mondi
  2017-03-02 20:16 ` Renesas RZ/A1 pin and gpio controller Chris Brandt
  2 siblings, 0 replies; 29+ messages in thread
From: Jacopo Mondi @ 2017-02-20 17:13 UTC (permalink / raw)
  To: geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw,
	linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	linux-I+IVW8TIWO2tmTQ+vhA3Yw
  Cc: linux-renesas-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Add combined gpio and pin controller driver for Renesas RZ/A1
r7s72100 SoC.

Signed-off-by: Jacopo Mondi <jacopo+renesas-AW8dsiIh9cEdnm+yROfE0A@public.gmane.org>
---
 drivers/pinctrl/Kconfig        |   10 +
 drivers/pinctrl/Makefile       |    1 +
 drivers/pinctrl/pinctrl-rza1.c | 1026 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1037 insertions(+)
 create mode 100644 drivers/pinctrl/pinctrl-rza1.c

diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 8f8c2af..61310ac 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -163,6 +163,16 @@ config PINCTRL_ROCKCHIP
 	select GENERIC_IRQ_CHIP
 	select MFD_SYSCON
 
+config PINCTRL_RZA1
+	bool "Renesas r7s72100 RZ/A1 gpio and pinctrl driver"
+	depends on OF
+	depends on ARCH_R7S72100 || COMPILE_TEST
+	select GENERIC_PINCTRL_GROUPS
+	select GENERIC_PINMUX_FUNCTIONS
+	select GENERIC_PINCONF
+	help
+	  This selects pinctrl driver for Renesas RZ/A1 r7s72100 platforms.
+
 config PINCTRL_SINGLE
 	tristate "One-register-per-pin type device tree based pinctrl driver"
 	depends on OF
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index a251f43..0c2328d2 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_PINCTRL_PALMAS)	+= pinctrl-palmas.o
 obj-$(CONFIG_PINCTRL_PIC32)	+= pinctrl-pic32.o
 obj-$(CONFIG_PINCTRL_PISTACHIO)	+= pinctrl-pistachio.o
 obj-$(CONFIG_PINCTRL_ROCKCHIP)	+= pinctrl-rockchip.o
+obj-$(CONFIG_PINCTRL_RZA1)	+= pinctrl-rza1.o
 obj-$(CONFIG_PINCTRL_SINGLE)	+= pinctrl-single.o
 obj-$(CONFIG_PINCTRL_SIRF)	+= sirf/
 obj-$(CONFIG_PINCTRL_SX150X)	+= pinctrl-sx150x.o
diff --git a/drivers/pinctrl/pinctrl-rza1.c b/drivers/pinctrl/pinctrl-rza1.c
new file mode 100644
index 0000000..348faee
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-rza1.c
@@ -0,0 +1,1026 @@
+/*
+ * Combined GPIO and pin controller support for Renesas RZ/A1 (r7s72100) SoC
+ *
+ * Copyright (C) 2017 Jacopo Mondi
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/*
+ * This pincontroller/gpio combined driver support Renesas devices of RZ/A1
+ * family.
+ * This includes SoCs which are sub- or super- sets of this particular line,
+ * as RZ/A1H (r7s721000), RZ/A1M (r7s721001) and RZ/A1L (r7s721002) are.
+ *
+ * To avoid compatibility issues, make the driver compatible with
+ * "renesas,r7s72100-ports".
+ * The device tree description of gpio-controllers shall provide the exact
+ * number of available pins in each port to differentiate between different
+ * SoCs of this specific family.
+ */
+
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/gpio/driver.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/slab.h>
+
+#include "core.h"
+#include "devicetree.h"
+#include "pinmux.h"
+
+#define DRIVER_NAME			"pinctrl-rza1"
+
+#define RZA1_PINMUX_OF_ARGS		2
+
+#define P_REG				0x0000
+#define PPR_REG				0x0200
+#define PM_REG				0x0300
+#define PMC_REG				0x0400
+#define PFC_REG				0x0500
+#define PFCE_REG			0x0600
+#define PFCEA_REG			0x0a00
+#define PIBC_REG			0x4000
+#define PBDC_REG			0x4100
+#define PIPC_REG			0x4200
+#define RZA1_ADDR(mem, reg, port)	((mem) + (reg) + ((port) * 4))
+
+/*
+ * Each port supports up to 16 pins.
+ * Even if not all ports have 16 active pins, we enumerate them all anyway
+ * to be able to retrieve pin position (port number and pin offset) from the
+ * pin identifier.
+ */
+#define RZA1_NPORTS			12
+#define RZA1_PINS_PER_PORT		16
+#define RZA1_NPINS			(RZA1_PINS_PER_PORT * RZA1_NPORTS)
+#define RZA1_PIN_TO_PORT(pin)		((pin) / RZA1_PINS_PER_PORT)
+#define RZA1_PIN_TO_OFFSET(pin)		((pin) % RZA1_PINS_PER_PORT)
+
+/*
+ * RZ/A1 provides up to 8 different selectable alternate functions.
+ * Be careful here: the pin configuration subnodes in device tree enumerates
+ * alternate functions from 1 to 8; subtract 1 before using macros so to match
+ * registers configuration which expects numbers from 0 to 7 instead.
+ */
+#define MUX_FUNC_OFFS			3
+#define MUX_FUNC_MASK			(BIT(MUX_FUNC_OFFS) - 1)
+#define MUX_FUNC_PFC_MASK		BIT(0)
+#define MUX_FUNC_PFCE_MASK		BIT(1)
+#define MUX_FUNC_PFCEA_MASK		BIT(2)
+#define MUX_CONF_INPUT_ENABLE		0x01
+#define MUX_CONF_SWIO			0x02
+
+/**
+ * rza1_pin_conf - describes a pin position, id, mux config and output value
+ *
+ * Use uint32_t to match types used in of_device nodes argument lists.
+ *
+ * @id: the pin identifier from 0 to RZA1_NPINS
+ * @port: the port where pin sits on
+ * @offset: pin offset in the port
+ * @mux: alternate function configuration settings
+ * @value: output value to set the pin to
+ */
+struct rza1_pin_conf {
+	uint32_t id;
+	uint32_t port;
+	uint32_t offset;
+	uint32_t mux_conf;
+	uint32_t value;
+};
+
+/**
+ * rza1_port - describes a pin port
+ *
+ * This is mostly useful to lock register writes per-bank and not globally.
+ *
+ * @lock: protect access to HW registers
+ * @id: port number
+ * @base: logical address base
+ * @pins: pins sitting on this port
+ */
+struct rza1_port {
+	spinlock_t lock;
+	unsigned int id;
+	void __iomem *base;
+	struct pinctrl_pin_desc *pins;
+};
+
+/**
+ * rza1_pinctrl - RZ pincontroller device
+ *
+ * @dev: parent device structure
+ * @mutex: protect [pinctrl|pinmux]_generic functions
+ * @base: logical address base
+ * @nports: number of pin controller ports
+ * @ports: pin controller banks
+ * @ngpiochips: number of gpio chips
+ * @gpio_ranges: gpio ranges for pinctrl core
+ * @pins: pin array for pinctrl core
+ * @desc: pincontroller desc for pinctrl core
+ * @pctl: pinctrl device
+ */
+struct rza1_pinctrl {
+	struct device *dev;
+
+	struct mutex mutex;
+
+	void __iomem *base;
+
+	unsigned int nport;
+	struct rza1_port *ports;
+
+	unsigned int ngpiochips;
+
+	struct pinctrl_gpio_range *gpio_ranges;
+	struct pinctrl_pin_desc *pins;
+	struct pinctrl_desc desc;
+	struct pinctrl_dev *pctl;
+};
+
+/* ----------------------------------------------------------------------------
+ * RZ/A1 SoC operations
+ */
+
+/**
+ * rza1_set_bit() - un-locked set/clear a single bit in pin configuration
+ *		    registers
+ *
+ * @port: port where pin sits on
+ * @reg: register offset
+ * @port: port number where pin sits
+ * @offset: pin offset in port register
+ * @set: set/clear flag
+ */
+static inline void rza1_set_bit(const struct rza1_port *port,
+				unsigned int reg, unsigned int offset,
+				bool set)
+{
+	void __iomem *mem = RZA1_ADDR(port->base, reg, port->id);
+	u16 val = ioread16(mem);
+
+	if (set)
+		val |= BIT(offset);
+	else
+		val &= ~BIT(offset);
+
+	iowrite16(val, mem);
+}
+
+/**
+ * rza1_get_bit() - get a bit value in a pin configuration register
+ *
+ * @port: port where pin sits on
+ * @reg: register offset
+ * @offset: pin offset in port register
+ */
+static inline int rza1_get_bit(struct rza1_port *port,
+			       unsigned int reg, unsigned int offset)
+{
+	void __iomem *mem = RZA1_ADDR(port->base, reg, port->id);
+
+	return ioread16(mem) & BIT(offset);
+}
+
+/**
+ * rza1_pin_reset() - reset a pin to default initial state
+ *
+ * Reset pin state disabling input buffer and bi-directional control,
+ * and configure it as input port.
+ * Note that pin is now configured with direction as input but with input
+ * buffer disabled. This implies the pin value cannot be read in this state.
+ *
+ * @port: port where pin sits on
+ * @offset: pin offset
+ */
+static void rza1_pin_reset(struct rza1_port *port,
+			   unsigned int offset)
+{
+	spin_lock(&port->lock);
+	rza1_set_bit(port, PIBC_REG, offset, 0);
+	rza1_set_bit(port, PBDC_REG, offset, 0);
+
+	rza1_set_bit(port, PM_REG, offset, 1);
+	rza1_set_bit(port, PMC_REG, offset, 0);
+	rza1_set_bit(port, PIPC_REG, offset, 0);
+	spin_unlock(&port->lock);
+}
+
+/**
+ * rza1_pin_get_direction() - get I/O direction on a pin in port mode
+ *
+ * @port: port where pin sits on
+ * @offset: pin offset
+ */
+static inline int rza1_pin_get_direction(struct rza1_port *port,
+					 int offset)
+{
+	int input;
+
+	spin_lock(&port->lock);
+	input = rza1_get_bit(port, PM_REG, offset);
+	spin_unlock(&port->lock);
+
+	return input;
+}
+
+/**
+ * rza1_pin_set_direction() - set I/O direction on a pin in port mode
+ *
+ * When running in output port mode keep PBDC enabled to allow reading the
+ * pin value from PPR.
+ * When in alternate mode disable that (if not explicitly required) not to
+ * interfere with the alternate function mode.
+ *
+ * @port: port where pin sits on
+ * @offset: pin offset
+ * @input: input enable/disable flag
+ */
+static inline void rza1_pin_set_direction(struct rza1_port *port,
+					  unsigned int offset,
+					  bool input)
+{
+	spin_lock(&port->lock);
+	if (input)
+		rza1_set_bit(port, PIBC_REG, offset, 1);
+	else {
+		rza1_set_bit(port, PM_REG, offset, 0);
+		rza1_set_bit(port, PBDC_REG, offset, 1);
+	}
+	spin_unlock(&port->lock);
+}
+
+/**
+ * rza1_pin_set() - set output value on a pin in port mode
+ *
+ * @port: port where pin sits on
+ * @offset: pin offset
+ * @value: pin output value
+ */
+static inline void rza1_pin_set(struct rza1_port *port,
+				unsigned int offset, unsigned int value)
+{
+	spin_lock(&port->lock);
+	rza1_set_bit(port, P_REG, offset, !!value);
+	spin_unlock(&port->lock);
+}
+
+/**
+ * rza1_pin_get() - get input value on a pin in port mode
+ *
+ * @port: port where pin sits on
+ * @offset: pin offset
+ */
+static inline int rza1_pin_get(struct rza1_port *port, unsigned int offset)
+{
+	int val;
+
+	spin_lock(&port->lock);
+	val = rza1_get_bit(port, PPR_REG, offset);
+	spin_unlock(&port->lock);
+
+	return val;
+}
+
+/**
+ * rza1_alternate_function_conf() - configure pin in alternate function mode
+ *
+ * @pinctrl: RZ/A1 pin controller device
+ * @pin_conf: single pin configuration descriptor
+ */
+static int rza1_alternate_function_conf(struct rza1_pinctrl *rza1_pctl,
+					struct rza1_pin_conf *pin_conf)
+{
+	unsigned int offset = pin_conf->offset;
+	struct rza1_port *port = &rza1_pctl->ports[pin_conf->port];
+	u8 mux_mode = (pin_conf->mux_conf - 1) & MUX_FUNC_MASK;
+	u8 mux_conf = pin_conf->mux_conf >> MUX_FUNC_OFFS;
+	bool swio_en = !!(mux_conf & MUX_CONF_SWIO);
+	bool input_en = !!(mux_conf & MUX_CONF_INPUT_ENABLE);
+
+	rza1_pin_reset(port, offset);
+
+	/*
+	 * When configuring pin with Software Controlled IO mode in alternate
+	 * mode, do not enable bi-directional control to avoid driving Pn
+	 * value to the pin input.
+	 * When working in direct IO mode (aka alternate function drives the
+	 * pin direction), enable bi-directional control for input pins in
+	 * order to enable the pin's input buffer as a consequence.
+	 */
+	if ((!swio_en && input_en) || (swio_en && !input_en))
+		rza1_set_bit(port, PBDC_REG, offset, 1);
+
+	/*
+	 * Enable alternate function mode and select it.
+	 *
+	 * ----------------------------------------------------
+	 * Alternate mode selection table:
+	 *
+	 * PMC	PFC	PFCE	PFCAE	mux_mode
+	 * 1	0	0	0	0
+	 * 1	1	0	0	1
+	 * 1	0	1	0	2
+	 * 1	1	1	0	3
+	 * 1	0	0	1	4
+	 * 1	1	0	1	5
+	 * 1	0	1	1	6
+	 * 1	1	1	1	7
+	 * ----------------------------------------------------
+	 */
+	rza1_set_bit(port, PFC_REG, offset, mux_mode & MUX_FUNC_PFC_MASK);
+	rza1_set_bit(port, PFCE_REG, offset, mux_mode & MUX_FUNC_PFCE_MASK);
+	rza1_set_bit(port, PFCEA_REG, offset, mux_mode & MUX_FUNC_PFCEA_MASK);
+
+	/*
+	 * All alternate functions except a few (4) need PIPCn = 1.
+	 * If PIPCn has to stay disabled (SW IO mode), configure PMn according
+	 * to I/O direction specified by pin configuration -after- PMC has been
+	 * set to one.
+	 */
+	if (!swio_en)
+		rza1_set_bit(port, PIPC_REG, offset, 1);
+
+	rza1_set_bit(port, PMC_REG, offset, 1);
+
+	if (swio_en)
+		rza1_set_bit(port, PM_REG, offset, input_en);
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------------
+ * pinctrl operations
+ */
+
+/**
+ * rza1_dt_node_to_map() - map a node to a function/group map
+ *
+ * Functions and groups are collected and registered to pinctrl_generic
+ * during DT parsing routine.
+ *
+ * @pctldev: pin controller device
+ * @np: device tree node to parse
+ * @map: pointer to pin map (output)
+ * @num_maps: number of collected maps (output)
+ */
+static int rza1_dt_node_to_map(struct pinctrl_dev *pctldev,
+			       struct device_node *np,
+			       struct pinctrl_map **map,
+			       unsigned int *num_maps)
+{
+	struct rza1_pinctrl *rza1_pctl = pinctrl_dev_get_drvdata(pctldev);
+	struct group_desc *grp;
+	unsigned int grp_sel;
+
+	/*
+	 * Find the group of this node and check if we need create
+	 * config maps for pins.
+	 */
+	grp_sel = pinctrl_get_group_selector(pctldev, np->name);
+	if (grp_sel < 0) {
+		dev_err(rza1_pctl->dev, "unable to find group for node %s\n",
+			np->name);
+		return -EINVAL;
+	}
+
+	grp = pinctrl_generic_get_group(pctldev, grp_sel);
+	if (!grp) {
+		dev_err(rza1_pctl->dev, "unable to find group for node %s\n",
+			np->name);
+		return -EINVAL;
+	}
+
+	*num_maps = 0;
+	*map = kzalloc(sizeof(**map), GFP_KERNEL);
+	if (!*map)
+		return -ENOMEM;
+
+	(*map)->type	= PIN_MAP_TYPE_MUX_GROUP;
+	(*map)->data.mux.group	= np->name;
+	(*map)->data.mux.function = np->name;
+	*num_maps = 1;
+
+	return 0;
+}
+
+static void rza1_dt_free_map(struct pinctrl_dev *pctldev,
+			     struct pinctrl_map *map, unsigned int num_maps)
+{
+	kfree(map);
+}
+
+static const struct pinctrl_ops rza1_pinctrl_ops = {
+	.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		= rza1_dt_node_to_map,
+	.dt_free_map		= rza1_dt_free_map,
+};
+
+/* ----------------------------------------------------------------------------
+ * gpio operations
+ */
+
+/**
+ * rza1_gpio_request() - configure pin in port mode
+ *
+ * Configure a pin as gpio (port mode).
+ * After reset, the pin is in input mode with input buffer disabled.
+ * To use the pin as input or output, set_direction shall be called first
+ *
+ * @chip: gpio chip where the gpio sits on
+ * @gpio: gpio offset
+ */
+static int rza1_gpio_request(struct gpio_chip *chip, unsigned int gpio)
+{
+	struct rza1_port *port = gpiochip_get_data(chip);
+
+	rza1_pin_reset(port, gpio);
+
+	return 0;
+}
+
+/**
+ * rza1_gpio_disable_free() - reset a pin
+ *
+ * Surprisingly, disable_free a gpio, is equivalent to request it.
+ * Reset pin to port mode, with input buffer disabled. This overwrites all
+ * port direction settings applied with set_direction
+ *
+ * @chip: gpio chip where the gpio sits on
+ * @gpio: gpio offset
+ */
+static void rza1_gpio_free(struct gpio_chip *chip, unsigned int gpio)
+{
+	struct rza1_port *port = gpiochip_get_data(chip);
+
+	rza1_pin_reset(port, gpio);
+}
+
+/**
+ * rza1_gpio_get_direction() - get a gpio pin I/O direction
+ *
+ * @chip: gpio chip where the gpio sits on
+ * @gpio: gpio offset
+ */
+static int rza1_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
+{
+	struct rza1_port *port = gpiochip_get_data(chip);
+
+	return rza1_pin_get_direction(port, offset);
+}
+
+/**
+ * rza1_gpio_direction_input() - set input direction on a gpio
+ *
+ * Enable input buffer to make the pin value accessible
+ *
+ * @chip: gpio chip where the gpio sits on
+ * @gpio: gpio offset
+ */
+static int rza1_gpio_direction_input(struct gpio_chip *chip,
+				     unsigned int offset)
+{
+	struct rza1_port *port = gpiochip_get_data(chip);
+
+	rza1_pin_set_direction(port, offset, true);
+
+	return 0;
+}
+
+/**
+ * rza1_gpio_direction_output() - set value and direction on a gpio
+ *
+ * Set value before driving pin direction
+ *
+ * @chip: gpio chip where the gpio sits on
+ * @gpio: gpio offset
+ */
+static int rza1_gpio_direction_output(struct gpio_chip *chip,
+				      unsigned int offset,
+				      int value)
+{
+	struct rza1_port *port = gpiochip_get_data(chip);
+
+	rza1_pin_set(port, offset, value);
+	rza1_pin_set_direction(port, offset, false);
+
+	return 0;
+}
+
+/**
+ * rza1_gpio_get() - read a gpio pin value
+ *
+ * Read gpio pin value through PPR register.
+ * Requires bi-directional mode to work when reading value of a pin
+ * in output mode
+ *
+ * @chip: gpio chip where the gpio sits on
+ * @gpio: gpio offset
+ */
+static int rza1_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+	struct rza1_port *port = gpiochip_get_data(chip);
+
+	return rza1_pin_get(port, offset);
+}
+
+/**
+ * rza1_gpio_set() - set a gpio pin value
+ *
+ * @chip: gpio chip where the gpio sits on
+ * @gpio: gpio offset
+ */
+static void rza1_gpio_set(struct gpio_chip *chip, unsigned int offset,
+			  int value)
+{
+	struct rza1_port *port = gpiochip_get_data(chip);
+
+	rza1_pin_set(port, offset, value);
+}
+
+struct gpio_chip rza1_gpiochip_template = {
+	.request		= rza1_gpio_request,
+	.free			= rza1_gpio_free,
+	.get_direction		= rza1_gpio_get_direction,
+	.direction_input	= rza1_gpio_direction_input,
+	.direction_output	= rza1_gpio_direction_output,
+	.get			= rza1_gpio_get,
+	.set			= rza1_gpio_set,
+};
+
+/* ----------------------------------------------------------------------------
+ * pinmux operations
+ */
+
+/**
+ * rza1_pinmux_set() - retrieve pins from a group and apply them mux settings
+ *
+ * @pctldev: pin controller device
+ * @selector: function selector
+ * @group: group selector
+ */
+static int rza1_pinmux_set(struct pinctrl_dev *pctldev, unsigned int selector,
+			   unsigned int group)
+{
+	int i;
+	struct group_desc *grp;
+	struct function_desc *func;
+	struct rza1_pin_conf *pin_confs;
+	struct rza1_pinctrl *rza1_pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	grp = pinctrl_generic_get_group(pctldev, group);
+	if (!grp)
+		return -EINVAL;
+
+	func = pinmux_generic_get_function(pctldev, selector);
+	if (!func)
+		return -EINVAL;
+
+	pin_confs = (struct rza1_pin_conf *)func->data;
+	for (i = 0; i < grp->num_pins; ++i) {
+		int ret;
+
+		ret = rza1_alternate_function_conf(rza1_pctl, &pin_confs[i]);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+struct pinmux_ops rza1_pinmux_ops = {
+	.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		= rza1_pinmux_set,
+	.strict			= true,
+};
+
+/* ----------------------------------------------------------------------------
+ * RZ/A1 pin controller driver operations
+ */
+
+static unsigned int rza1_count_gpio_chips(struct device_node *np)
+{
+	unsigned int count = 0;
+	struct device_node *child;
+
+	for_each_child_of_node(np, child) {
+		if (!of_property_read_bool(child, "gpio-controller"))
+			continue;
+
+		count++;
+	}
+
+	return count;
+}
+
+/**
+ * rza1_parse_pmx_function() - parse and register a pin mux function
+ *
+ * Pins for RZ SoC pin controller described by "renesas-pins" property.
+ *
+ * First argument in the list identifies the pin, while the second one
+ * describes the requested alternate function number and additional
+ * configuration parameter to be applied to the selected function.
+ *
+ * @rza1_pctl: RZ/A1 pin controller device
+ * @np: of pmx sub-node
+ */
+static int rza1_parse_pmx_function(struct rza1_pinctrl *rza1_pctl,
+				   struct device_node *np)
+{
+	int ret;
+	int of_pins;
+	unsigned int i;
+	unsigned int *grpins;
+	const char *grpname;
+	const char **fngrps;
+	struct rza1_pin_conf *pin_confs;
+	struct pinctrl_dev *pctldev = rza1_pctl->pctl;
+	char const *prop_name = "renesas,pins";
+
+	of_pins = pinctrl_count_index_with_args(np, prop_name);
+	if (of_pins <= 0) {
+		dev_err(rza1_pctl->dev, "Missing %s property\n", prop_name);
+		return -ENOENT;
+	}
+
+	/*
+	 * Functions are made of 1 group only;
+	 * in facts, functions and groups are identical for this pin controller
+	 * except that functions carry an array of per-pin configurations
+	 * settings.
+	 */
+	pin_confs = devm_kcalloc(rza1_pctl->dev, of_pins, sizeof(*pin_confs),
+				 GFP_KERNEL);
+	grpins = devm_kcalloc(rza1_pctl->dev, of_pins, sizeof(*grpins),
+			      GFP_KERNEL);
+	fngrps = devm_kzalloc(rza1_pctl->dev, sizeof(*fngrps), GFP_KERNEL);
+
+	if (!pin_confs || !grpins || !fngrps)
+		return -ENOMEM;
+
+	/* Collect pin positions and mux settings to store them in function */
+	for (i = 0; i < of_pins; ++i) {
+		struct rza1_pin_conf *pin_conf = &pin_confs[i];
+		struct of_phandle_args of_pins_args;
+
+		ret = pinctrl_parse_index_with_args(np, prop_name, i,
+						    &of_pins_args);
+		if (ret)
+			return ret;
+
+		if (of_pins_args.args_count < RZA1_PINMUX_OF_ARGS) {
+			dev_err(rza1_pctl->dev,
+				"Wrong arguments number for %s property\n",
+				prop_name);
+			return -EINVAL;
+		}
+
+		/*
+		 * This new pins configuration will be associated with a new
+		 * function, and later used to set-up pin muxing
+		 */
+		pin_conf->id = of_pins_args.args[0];
+		pin_conf->port = RZA1_PIN_TO_PORT(pin_conf->id);
+		pin_conf->offset = RZA1_PIN_TO_OFFSET(pin_conf->id);
+		pin_conf->mux_conf = of_pins_args.args[1];
+
+		if (pin_conf->port >= RZA1_NPORTS ||
+		    pin_conf->offset >= RZA1_PINS_PER_PORT) {
+			dev_err(rza1_pctl->dev,
+				"Wrong port %u pin %u for %s property\n",
+				pin_conf->port, pin_conf->offset, prop_name);
+			return -EINVAL;
+		}
+
+		grpins[i] = pin_conf->id;
+	}
+
+	grpname	= np->name;
+	fngrps[0] = grpname;
+
+	mutex_lock(&rza1_pctl->mutex);
+	ret = pinctrl_generic_add_group(pctldev, grpname, grpins, of_pins,
+					NULL);
+	if (ret) {
+		mutex_unlock(&rza1_pctl->mutex);
+		return ret;
+	}
+
+	ret = pinmux_generic_add_function(pctldev, grpname, fngrps, 1,
+					  pin_confs);
+	if (ret)
+		goto remove_group;
+	mutex_unlock(&rza1_pctl->mutex);
+
+	dev_info(rza1_pctl->dev, "Parsed function and group %s with %d pins\n",
+				 grpname, of_pins);
+
+	return 0;
+
+remove_group:
+	dev_info(rza1_pctl->dev, "Unable to parse function and group %s\n",
+				 grpname);
+	pinctrl_generic_remove_last_group(pctldev);
+	mutex_unlock(&rza1_pctl->mutex);
+
+	return ret;
+}
+
+/**
+ * rza1_remove_pmx_functions() - un-register pmx functions and groups
+ *
+ * @rza1_pctl: RZ/A1 pin controller device
+ */
+static void rza1_remove_pmx_functions(struct rza1_pinctrl *rza1_pctl)
+{
+	struct pinctrl_dev *pctldev = rza1_pctl->pctl;
+
+	mutex_lock(&rza1_pctl->mutex);
+	pinmux_generic_free_functions(pctldev);
+	mutex_unlock(&rza1_pctl->mutex);
+}
+
+/**
+ * rza1_parse_gpiochip() - parse and register a gpio chip and pin range
+ *
+ * The gpio controller subnode shall provide a "gpio-ranges" list property as
+ * defined by gpio device tree binding documentation.
+ * Gpio chips and pin ranges are here collected, but ranges are registered
+ * later, after pin controller has been registered too. Only gpiochips are
+ * registered here.
+ *
+ * @rza1_pctl: RZ/A1 pin controller device
+ * @np: of gpio-controller node
+ * @chip: gpio chip to register to gpiolib
+ * @range: pin range to register to pinctrl core
+ */
+static int rza1_parse_gpiochip(struct rza1_pinctrl *rza1_pctl,
+			       struct device_node *np,
+			       struct gpio_chip *chip,
+			       struct pinctrl_gpio_range *range)
+{
+	int ret;
+	u32 pinctrl_base;
+	unsigned int gpioport;
+	struct of_phandle_args of_args;
+	const char *list_name = "gpio-ranges";
+
+	of_parse_phandle_with_fixed_args(np, list_name, 3, 0, &of_args);
+
+	/*
+	 * Find out on which port this gpio-chip maps to inspecting the second
+	 * argument of "gpio-ranges" property.
+	 */
+	pinctrl_base = of_args.args[1];
+	gpioport = RZA1_PIN_TO_PORT(pinctrl_base);
+	if (gpioport > RZA1_NPORTS) {
+		dev_err(rza1_pctl->dev,
+			"Invalid values in property %s\n", list_name);
+		return -EINVAL;
+	}
+
+	*chip		= rza1_gpiochip_template;
+	chip->base	= -1;
+	chip->label	= kasprintf(GFP_KERNEL, "%s-%d", np->name, gpioport);
+	chip->ngpio	= of_args.args[2];
+	chip->of_node	= np;
+
+	range->id	= gpioport;
+	range->name	= kasprintf(GFP_KERNEL, "%s-%d", np->name, gpioport);
+	range->pin_base	= range->base = pinctrl_base;
+	range->npins	= of_args.args[2];
+	range->gc	= chip;
+
+	ret = devm_gpiochip_add_data(rza1_pctl->dev, chip,
+				     &rza1_pctl->ports[gpioport]);
+	if (ret)
+		return ret;
+
+	dev_info(rza1_pctl->dev, "Parsed gpiochip %s with %d pins\n",
+		 chip->label, chip->ngpio);
+
+	return 0;
+}
+
+/**
+ * rza1_parse_dt() - parse DT to collect gpiochips and pmx functions
+ *
+ * @rza1_pctl: RZ/A1 pin controller device
+ */
+static int rza1_parse_dt(struct rza1_pinctrl *rza1_pctl)
+{
+	int ret;
+	unsigned int npmxfuncs;
+	unsigned int ngpiochips;
+	unsigned int i;
+	struct gpio_chip *gpio_chips;
+	struct pinctrl_gpio_range *gpio_ranges;
+	struct device_node *np = rza1_pctl->dev->of_node;
+	struct device_node *child;
+
+	ngpiochips = rza1_count_gpio_chips(np);
+	if (ngpiochips) {
+		dev_info(rza1_pctl->dev, "Registering %u gpio chips\n",
+					 ngpiochips);
+
+		gpio_chips = devm_kcalloc(rza1_pctl->dev, ngpiochips,
+					  sizeof(*gpio_chips), GFP_KERNEL);
+		gpio_ranges = devm_kcalloc(rza1_pctl->dev, ngpiochips,
+					   sizeof(*gpio_ranges), GFP_KERNEL);
+		if (!gpio_chips || !gpio_ranges)
+			return -ENOMEM;
+	} else {
+		dev_dbg(rza1_pctl->dev, "No gpiochip registered\n");
+		gpio_ranges = NULL;
+	}
+
+	rza1_pctl->gpio_ranges	= gpio_ranges;
+
+	i = 0;
+	npmxfuncs = 0;
+	for_each_child_of_node(np, child) {
+		if (of_property_read_bool(child, "gpio-controller")) {
+			/* Never get here if ngpiochips == 0 */
+			ret = rza1_parse_gpiochip(rza1_pctl, child,
+						  &gpio_chips[i],
+						  &gpio_ranges[i]);
+			if (ret)
+				goto gpio_pmx_unregister;
+
+			++i;
+		} else {
+			ret = rza1_parse_pmx_function(rza1_pctl, child);
+			if (ret)
+				goto gpio_pmx_unregister;
+
+			++npmxfuncs;
+		}
+	}
+
+	rza1_pctl->ngpiochips = i;
+
+	dev_info(rza1_pctl->dev,
+		 "Registered %u gpio controllers and %u pin mux functions\n",
+		 rza1_pctl->ngpiochips, npmxfuncs);
+
+	return 0;
+
+gpio_pmx_unregister:
+	/*
+	 * If a pmx function creation fails or a gpiochip cannot be registered,
+	 * clean up everything we have registered to gpio or pmx core so far.
+	 */
+	for (; i > 0; i--)
+		devm_gpiochip_remove(rza1_pctl->dev, &gpio_chips[i - 1]);
+
+	rza1_remove_pmx_functions(rza1_pctl);
+
+	return ret;
+}
+
+/**
+ * rza1_pinctrl_register() - Enumerate pins, ports, gpiochips and functions and
+ *			     register to pinctrl and gpio cores
+ *
+ * @rza1_pctl: RZ/A1 pin controller device
+ */
+static int rza1_pinctrl_register(struct rza1_pinctrl *rza1_pctl)
+{
+	int ret;
+	unsigned int i;
+	struct rza1_port *ports;
+	struct pinctrl_pin_desc *pins;
+
+	pins = devm_kcalloc(rza1_pctl->dev, RZA1_NPINS, sizeof(*pins),
+			    GFP_KERNEL);
+	ports = devm_kcalloc(rza1_pctl->dev, RZA1_NPORTS, sizeof(*ports),
+			     GFP_KERNEL);
+	if (!pins || !ports)
+		return -ENOMEM;
+
+	rza1_pctl->pins		= pins;
+	rza1_pctl->desc.pins	= pins;
+	rza1_pctl->desc.npins	= RZA1_NPINS;
+	rza1_pctl->ports	= ports;
+
+	for (i = 0; i < RZA1_NPINS; ++i) {
+		unsigned int port = RZA1_PIN_TO_PORT(i);
+		unsigned int offset = RZA1_PIN_TO_OFFSET(i);
+
+		pins[i].number = i;
+		pins[i].name = kasprintf(GFP_KERNEL, "P%u-%u", port, offset);
+
+		if (i % RZA1_PINS_PER_PORT == 0) {
+			/*
+			 * Setup ports;
+			 * they provide per-port lock and logical base address.
+			 */
+			unsigned int port_id = RZA1_PIN_TO_PORT(i);
+
+			ports[port_id].id = port_id;
+			ports[port_id].base = rza1_pctl->base;
+			ports[port_id].pins = &pins[i];
+			spin_lock_init(&ports[port_id].lock);
+		}
+	}
+
+	ret = devm_pinctrl_register_and_init(rza1_pctl->dev, &rza1_pctl->desc,
+					     rza1_pctl, &rza1_pctl->pctl);
+	if (ret) {
+		dev_err(rza1_pctl->dev,
+			"RZ/A1 pin controller registration failed\n");
+		return ret;
+	}
+
+	ret = rza1_parse_dt(rza1_pctl);
+	if (ret) {
+		dev_err(rza1_pctl->dev, "RZ/A1 DT parsing failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int rza1_pinctrl_probe(struct platform_device *pdev)
+{
+	int ret;
+	unsigned int i;
+	struct resource *res;
+	struct rza1_pinctrl *rza1_pctl;
+
+	rza1_pctl = devm_kzalloc(&pdev->dev, sizeof(*rza1_pctl), GFP_KERNEL);
+	if (!rza1_pctl)
+		return -ENOMEM;
+
+	rza1_pctl->dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (ret)
+		return -ENODEV;
+
+	rza1_pctl->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(rza1_pctl->base))
+		return PTR_ERR(rza1_pctl->base);
+
+	mutex_init(&rza1_pctl->mutex);
+
+	platform_set_drvdata(pdev, rza1_pctl);
+
+	rza1_pctl->desc.name	= DRIVER_NAME;
+	rza1_pctl->desc.pctlops	= &rza1_pinctrl_ops;
+	rza1_pctl->desc.pmxops	= &rza1_pinmux_ops;
+	rza1_pctl->desc.owner	= THIS_MODULE;
+
+	ret = rza1_pinctrl_register(rza1_pctl);
+	if (ret)
+		return ret;
+
+	/* register pin control ranges collected while parsing device tree */
+	for (i = 0; i < rza1_pctl->ngpiochips; i++)
+		pinctrl_add_gpio_range(rza1_pctl->pctl,
+				       &rza1_pctl->gpio_ranges[i]);
+
+	dev_info(&pdev->dev,
+		 "RZ/A1 pin controller and gpio successfully registered\n");
+
+	return 0;
+}
+
+static const struct of_device_id rza1_pinctrl_of_match[] = {
+	{ .compatible = "renesas,r7s72100-ports", },
+	{ }
+};
+
+static struct platform_driver rza1_pinctrl_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+		.of_match_table = rza1_pinctrl_of_match,
+	},
+	.probe = rza1_pinctrl_probe,
+};
+
+static int __init rza1_pinctrl_init(void)
+{
+	return platform_driver_register(&rza1_pinctrl_driver);
+}
+core_initcall(rza1_pinctrl_init);
+
+MODULE_AUTHOR("Jacopo Mondi <jacopo+renesas-AW8dsiIh9cEdnm+yROfE0A@public.gmane.org");
+MODULE_DESCRIPTION("Pin and gpio controller driver for Reneas RZ/A1 SoC");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH 1/7] pinctrl: Renesas RZ/A1 pin and gpio controller
@ 2017-02-20 17:13     ` Jacopo Mondi
  0 siblings, 0 replies; 29+ messages in thread
From: Jacopo Mondi @ 2017-02-20 17:13 UTC (permalink / raw)
  To: geert+renesas, laurent.pinchart, linus.walleij, robh+dt,
	mark.rutland, linux
  Cc: linux-renesas-soc, linux-gpio, devicetree

Add combined gpio and pin controller driver for Renesas RZ/A1
r7s72100 SoC.

Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
---
 drivers/pinctrl/Kconfig        |   10 +
 drivers/pinctrl/Makefile       |    1 +
 drivers/pinctrl/pinctrl-rza1.c | 1026 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1037 insertions(+)
 create mode 100644 drivers/pinctrl/pinctrl-rza1.c

diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 8f8c2af..61310ac 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -163,6 +163,16 @@ config PINCTRL_ROCKCHIP
 	select GENERIC_IRQ_CHIP
 	select MFD_SYSCON
 
+config PINCTRL_RZA1
+	bool "Renesas r7s72100 RZ/A1 gpio and pinctrl driver"
+	depends on OF
+	depends on ARCH_R7S72100 || COMPILE_TEST
+	select GENERIC_PINCTRL_GROUPS
+	select GENERIC_PINMUX_FUNCTIONS
+	select GENERIC_PINCONF
+	help
+	  This selects pinctrl driver for Renesas RZ/A1 r7s72100 platforms.
+
 config PINCTRL_SINGLE
 	tristate "One-register-per-pin type device tree based pinctrl driver"
 	depends on OF
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index a251f43..0c2328d2 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_PINCTRL_PALMAS)	+= pinctrl-palmas.o
 obj-$(CONFIG_PINCTRL_PIC32)	+= pinctrl-pic32.o
 obj-$(CONFIG_PINCTRL_PISTACHIO)	+= pinctrl-pistachio.o
 obj-$(CONFIG_PINCTRL_ROCKCHIP)	+= pinctrl-rockchip.o
+obj-$(CONFIG_PINCTRL_RZA1)	+= pinctrl-rza1.o
 obj-$(CONFIG_PINCTRL_SINGLE)	+= pinctrl-single.o
 obj-$(CONFIG_PINCTRL_SIRF)	+= sirf/
 obj-$(CONFIG_PINCTRL_SX150X)	+= pinctrl-sx150x.o
diff --git a/drivers/pinctrl/pinctrl-rza1.c b/drivers/pinctrl/pinctrl-rza1.c
new file mode 100644
index 0000000..348faee
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-rza1.c
@@ -0,0 +1,1026 @@
+/*
+ * Combined GPIO and pin controller support for Renesas RZ/A1 (r7s72100) SoC
+ *
+ * Copyright (C) 2017 Jacopo Mondi
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/*
+ * This pincontroller/gpio combined driver support Renesas devices of RZ/A1
+ * family.
+ * This includes SoCs which are sub- or super- sets of this particular line,
+ * as RZ/A1H (r7s721000), RZ/A1M (r7s721001) and RZ/A1L (r7s721002) are.
+ *
+ * To avoid compatibility issues, make the driver compatible with
+ * "renesas,r7s72100-ports".
+ * The device tree description of gpio-controllers shall provide the exact
+ * number of available pins in each port to differentiate between different
+ * SoCs of this specific family.
+ */
+
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/gpio/driver.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/slab.h>
+
+#include "core.h"
+#include "devicetree.h"
+#include "pinmux.h"
+
+#define DRIVER_NAME			"pinctrl-rza1"
+
+#define RZA1_PINMUX_OF_ARGS		2
+
+#define P_REG				0x0000
+#define PPR_REG				0x0200
+#define PM_REG				0x0300
+#define PMC_REG				0x0400
+#define PFC_REG				0x0500
+#define PFCE_REG			0x0600
+#define PFCEA_REG			0x0a00
+#define PIBC_REG			0x4000
+#define PBDC_REG			0x4100
+#define PIPC_REG			0x4200
+#define RZA1_ADDR(mem, reg, port)	((mem) + (reg) + ((port) * 4))
+
+/*
+ * Each port supports up to 16 pins.
+ * Even if not all ports have 16 active pins, we enumerate them all anyway
+ * to be able to retrieve pin position (port number and pin offset) from the
+ * pin identifier.
+ */
+#define RZA1_NPORTS			12
+#define RZA1_PINS_PER_PORT		16
+#define RZA1_NPINS			(RZA1_PINS_PER_PORT * RZA1_NPORTS)
+#define RZA1_PIN_TO_PORT(pin)		((pin) / RZA1_PINS_PER_PORT)
+#define RZA1_PIN_TO_OFFSET(pin)		((pin) % RZA1_PINS_PER_PORT)
+
+/*
+ * RZ/A1 provides up to 8 different selectable alternate functions.
+ * Be careful here: the pin configuration subnodes in device tree enumerates
+ * alternate functions from 1 to 8; subtract 1 before using macros so to match
+ * registers configuration which expects numbers from 0 to 7 instead.
+ */
+#define MUX_FUNC_OFFS			3
+#define MUX_FUNC_MASK			(BIT(MUX_FUNC_OFFS) - 1)
+#define MUX_FUNC_PFC_MASK		BIT(0)
+#define MUX_FUNC_PFCE_MASK		BIT(1)
+#define MUX_FUNC_PFCEA_MASK		BIT(2)
+#define MUX_CONF_INPUT_ENABLE		0x01
+#define MUX_CONF_SWIO			0x02
+
+/**
+ * rza1_pin_conf - describes a pin position, id, mux config and output value
+ *
+ * Use uint32_t to match types used in of_device nodes argument lists.
+ *
+ * @id: the pin identifier from 0 to RZA1_NPINS
+ * @port: the port where pin sits on
+ * @offset: pin offset in the port
+ * @mux: alternate function configuration settings
+ * @value: output value to set the pin to
+ */
+struct rza1_pin_conf {
+	uint32_t id;
+	uint32_t port;
+	uint32_t offset;
+	uint32_t mux_conf;
+	uint32_t value;
+};
+
+/**
+ * rza1_port - describes a pin port
+ *
+ * This is mostly useful to lock register writes per-bank and not globally.
+ *
+ * @lock: protect access to HW registers
+ * @id: port number
+ * @base: logical address base
+ * @pins: pins sitting on this port
+ */
+struct rza1_port {
+	spinlock_t lock;
+	unsigned int id;
+	void __iomem *base;
+	struct pinctrl_pin_desc *pins;
+};
+
+/**
+ * rza1_pinctrl - RZ pincontroller device
+ *
+ * @dev: parent device structure
+ * @mutex: protect [pinctrl|pinmux]_generic functions
+ * @base: logical address base
+ * @nports: number of pin controller ports
+ * @ports: pin controller banks
+ * @ngpiochips: number of gpio chips
+ * @gpio_ranges: gpio ranges for pinctrl core
+ * @pins: pin array for pinctrl core
+ * @desc: pincontroller desc for pinctrl core
+ * @pctl: pinctrl device
+ */
+struct rza1_pinctrl {
+	struct device *dev;
+
+	struct mutex mutex;
+
+	void __iomem *base;
+
+	unsigned int nport;
+	struct rza1_port *ports;
+
+	unsigned int ngpiochips;
+
+	struct pinctrl_gpio_range *gpio_ranges;
+	struct pinctrl_pin_desc *pins;
+	struct pinctrl_desc desc;
+	struct pinctrl_dev *pctl;
+};
+
+/* ----------------------------------------------------------------------------
+ * RZ/A1 SoC operations
+ */
+
+/**
+ * rza1_set_bit() - un-locked set/clear a single bit in pin configuration
+ *		    registers
+ *
+ * @port: port where pin sits on
+ * @reg: register offset
+ * @port: port number where pin sits
+ * @offset: pin offset in port register
+ * @set: set/clear flag
+ */
+static inline void rza1_set_bit(const struct rza1_port *port,
+				unsigned int reg, unsigned int offset,
+				bool set)
+{
+	void __iomem *mem = RZA1_ADDR(port->base, reg, port->id);
+	u16 val = ioread16(mem);
+
+	if (set)
+		val |= BIT(offset);
+	else
+		val &= ~BIT(offset);
+
+	iowrite16(val, mem);
+}
+
+/**
+ * rza1_get_bit() - get a bit value in a pin configuration register
+ *
+ * @port: port where pin sits on
+ * @reg: register offset
+ * @offset: pin offset in port register
+ */
+static inline int rza1_get_bit(struct rza1_port *port,
+			       unsigned int reg, unsigned int offset)
+{
+	void __iomem *mem = RZA1_ADDR(port->base, reg, port->id);
+
+	return ioread16(mem) & BIT(offset);
+}
+
+/**
+ * rza1_pin_reset() - reset a pin to default initial state
+ *
+ * Reset pin state disabling input buffer and bi-directional control,
+ * and configure it as input port.
+ * Note that pin is now configured with direction as input but with input
+ * buffer disabled. This implies the pin value cannot be read in this state.
+ *
+ * @port: port where pin sits on
+ * @offset: pin offset
+ */
+static void rza1_pin_reset(struct rza1_port *port,
+			   unsigned int offset)
+{
+	spin_lock(&port->lock);
+	rza1_set_bit(port, PIBC_REG, offset, 0);
+	rza1_set_bit(port, PBDC_REG, offset, 0);
+
+	rza1_set_bit(port, PM_REG, offset, 1);
+	rza1_set_bit(port, PMC_REG, offset, 0);
+	rza1_set_bit(port, PIPC_REG, offset, 0);
+	spin_unlock(&port->lock);
+}
+
+/**
+ * rza1_pin_get_direction() - get I/O direction on a pin in port mode
+ *
+ * @port: port where pin sits on
+ * @offset: pin offset
+ */
+static inline int rza1_pin_get_direction(struct rza1_port *port,
+					 int offset)
+{
+	int input;
+
+	spin_lock(&port->lock);
+	input = rza1_get_bit(port, PM_REG, offset);
+	spin_unlock(&port->lock);
+
+	return input;
+}
+
+/**
+ * rza1_pin_set_direction() - set I/O direction on a pin in port mode
+ *
+ * When running in output port mode keep PBDC enabled to allow reading the
+ * pin value from PPR.
+ * When in alternate mode disable that (if not explicitly required) not to
+ * interfere with the alternate function mode.
+ *
+ * @port: port where pin sits on
+ * @offset: pin offset
+ * @input: input enable/disable flag
+ */
+static inline void rza1_pin_set_direction(struct rza1_port *port,
+					  unsigned int offset,
+					  bool input)
+{
+	spin_lock(&port->lock);
+	if (input)
+		rza1_set_bit(port, PIBC_REG, offset, 1);
+	else {
+		rza1_set_bit(port, PM_REG, offset, 0);
+		rza1_set_bit(port, PBDC_REG, offset, 1);
+	}
+	spin_unlock(&port->lock);
+}
+
+/**
+ * rza1_pin_set() - set output value on a pin in port mode
+ *
+ * @port: port where pin sits on
+ * @offset: pin offset
+ * @value: pin output value
+ */
+static inline void rza1_pin_set(struct rza1_port *port,
+				unsigned int offset, unsigned int value)
+{
+	spin_lock(&port->lock);
+	rza1_set_bit(port, P_REG, offset, !!value);
+	spin_unlock(&port->lock);
+}
+
+/**
+ * rza1_pin_get() - get input value on a pin in port mode
+ *
+ * @port: port where pin sits on
+ * @offset: pin offset
+ */
+static inline int rza1_pin_get(struct rza1_port *port, unsigned int offset)
+{
+	int val;
+
+	spin_lock(&port->lock);
+	val = rza1_get_bit(port, PPR_REG, offset);
+	spin_unlock(&port->lock);
+
+	return val;
+}
+
+/**
+ * rza1_alternate_function_conf() - configure pin in alternate function mode
+ *
+ * @pinctrl: RZ/A1 pin controller device
+ * @pin_conf: single pin configuration descriptor
+ */
+static int rza1_alternate_function_conf(struct rza1_pinctrl *rza1_pctl,
+					struct rza1_pin_conf *pin_conf)
+{
+	unsigned int offset = pin_conf->offset;
+	struct rza1_port *port = &rza1_pctl->ports[pin_conf->port];
+	u8 mux_mode = (pin_conf->mux_conf - 1) & MUX_FUNC_MASK;
+	u8 mux_conf = pin_conf->mux_conf >> MUX_FUNC_OFFS;
+	bool swio_en = !!(mux_conf & MUX_CONF_SWIO);
+	bool input_en = !!(mux_conf & MUX_CONF_INPUT_ENABLE);
+
+	rza1_pin_reset(port, offset);
+
+	/*
+	 * When configuring pin with Software Controlled IO mode in alternate
+	 * mode, do not enable bi-directional control to avoid driving Pn
+	 * value to the pin input.
+	 * When working in direct IO mode (aka alternate function drives the
+	 * pin direction), enable bi-directional control for input pins in
+	 * order to enable the pin's input buffer as a consequence.
+	 */
+	if ((!swio_en && input_en) || (swio_en && !input_en))
+		rza1_set_bit(port, PBDC_REG, offset, 1);
+
+	/*
+	 * Enable alternate function mode and select it.
+	 *
+	 * ----------------------------------------------------
+	 * Alternate mode selection table:
+	 *
+	 * PMC	PFC	PFCE	PFCAE	mux_mode
+	 * 1	0	0	0	0
+	 * 1	1	0	0	1
+	 * 1	0	1	0	2
+	 * 1	1	1	0	3
+	 * 1	0	0	1	4
+	 * 1	1	0	1	5
+	 * 1	0	1	1	6
+	 * 1	1	1	1	7
+	 * ----------------------------------------------------
+	 */
+	rza1_set_bit(port, PFC_REG, offset, mux_mode & MUX_FUNC_PFC_MASK);
+	rza1_set_bit(port, PFCE_REG, offset, mux_mode & MUX_FUNC_PFCE_MASK);
+	rza1_set_bit(port, PFCEA_REG, offset, mux_mode & MUX_FUNC_PFCEA_MASK);
+
+	/*
+	 * All alternate functions except a few (4) need PIPCn = 1.
+	 * If PIPCn has to stay disabled (SW IO mode), configure PMn according
+	 * to I/O direction specified by pin configuration -after- PMC has been
+	 * set to one.
+	 */
+	if (!swio_en)
+		rza1_set_bit(port, PIPC_REG, offset, 1);
+
+	rza1_set_bit(port, PMC_REG, offset, 1);
+
+	if (swio_en)
+		rza1_set_bit(port, PM_REG, offset, input_en);
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------------
+ * pinctrl operations
+ */
+
+/**
+ * rza1_dt_node_to_map() - map a node to a function/group map
+ *
+ * Functions and groups are collected and registered to pinctrl_generic
+ * during DT parsing routine.
+ *
+ * @pctldev: pin controller device
+ * @np: device tree node to parse
+ * @map: pointer to pin map (output)
+ * @num_maps: number of collected maps (output)
+ */
+static int rza1_dt_node_to_map(struct pinctrl_dev *pctldev,
+			       struct device_node *np,
+			       struct pinctrl_map **map,
+			       unsigned int *num_maps)
+{
+	struct rza1_pinctrl *rza1_pctl = pinctrl_dev_get_drvdata(pctldev);
+	struct group_desc *grp;
+	unsigned int grp_sel;
+
+	/*
+	 * Find the group of this node and check if we need create
+	 * config maps for pins.
+	 */
+	grp_sel = pinctrl_get_group_selector(pctldev, np->name);
+	if (grp_sel < 0) {
+		dev_err(rza1_pctl->dev, "unable to find group for node %s\n",
+			np->name);
+		return -EINVAL;
+	}
+
+	grp = pinctrl_generic_get_group(pctldev, grp_sel);
+	if (!grp) {
+		dev_err(rza1_pctl->dev, "unable to find group for node %s\n",
+			np->name);
+		return -EINVAL;
+	}
+
+	*num_maps = 0;
+	*map = kzalloc(sizeof(**map), GFP_KERNEL);
+	if (!*map)
+		return -ENOMEM;
+
+	(*map)->type	= PIN_MAP_TYPE_MUX_GROUP;
+	(*map)->data.mux.group	= np->name;
+	(*map)->data.mux.function = np->name;
+	*num_maps = 1;
+
+	return 0;
+}
+
+static void rza1_dt_free_map(struct pinctrl_dev *pctldev,
+			     struct pinctrl_map *map, unsigned int num_maps)
+{
+	kfree(map);
+}
+
+static const struct pinctrl_ops rza1_pinctrl_ops = {
+	.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		= rza1_dt_node_to_map,
+	.dt_free_map		= rza1_dt_free_map,
+};
+
+/* ----------------------------------------------------------------------------
+ * gpio operations
+ */
+
+/**
+ * rza1_gpio_request() - configure pin in port mode
+ *
+ * Configure a pin as gpio (port mode).
+ * After reset, the pin is in input mode with input buffer disabled.
+ * To use the pin as input or output, set_direction shall be called first
+ *
+ * @chip: gpio chip where the gpio sits on
+ * @gpio: gpio offset
+ */
+static int rza1_gpio_request(struct gpio_chip *chip, unsigned int gpio)
+{
+	struct rza1_port *port = gpiochip_get_data(chip);
+
+	rza1_pin_reset(port, gpio);
+
+	return 0;
+}
+
+/**
+ * rza1_gpio_disable_free() - reset a pin
+ *
+ * Surprisingly, disable_free a gpio, is equivalent to request it.
+ * Reset pin to port mode, with input buffer disabled. This overwrites all
+ * port direction settings applied with set_direction
+ *
+ * @chip: gpio chip where the gpio sits on
+ * @gpio: gpio offset
+ */
+static void rza1_gpio_free(struct gpio_chip *chip, unsigned int gpio)
+{
+	struct rza1_port *port = gpiochip_get_data(chip);
+
+	rza1_pin_reset(port, gpio);
+}
+
+/**
+ * rza1_gpio_get_direction() - get a gpio pin I/O direction
+ *
+ * @chip: gpio chip where the gpio sits on
+ * @gpio: gpio offset
+ */
+static int rza1_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
+{
+	struct rza1_port *port = gpiochip_get_data(chip);
+
+	return rza1_pin_get_direction(port, offset);
+}
+
+/**
+ * rza1_gpio_direction_input() - set input direction on a gpio
+ *
+ * Enable input buffer to make the pin value accessible
+ *
+ * @chip: gpio chip where the gpio sits on
+ * @gpio: gpio offset
+ */
+static int rza1_gpio_direction_input(struct gpio_chip *chip,
+				     unsigned int offset)
+{
+	struct rza1_port *port = gpiochip_get_data(chip);
+
+	rza1_pin_set_direction(port, offset, true);
+
+	return 0;
+}
+
+/**
+ * rza1_gpio_direction_output() - set value and direction on a gpio
+ *
+ * Set value before driving pin direction
+ *
+ * @chip: gpio chip where the gpio sits on
+ * @gpio: gpio offset
+ */
+static int rza1_gpio_direction_output(struct gpio_chip *chip,
+				      unsigned int offset,
+				      int value)
+{
+	struct rza1_port *port = gpiochip_get_data(chip);
+
+	rza1_pin_set(port, offset, value);
+	rza1_pin_set_direction(port, offset, false);
+
+	return 0;
+}
+
+/**
+ * rza1_gpio_get() - read a gpio pin value
+ *
+ * Read gpio pin value through PPR register.
+ * Requires bi-directional mode to work when reading value of a pin
+ * in output mode
+ *
+ * @chip: gpio chip where the gpio sits on
+ * @gpio: gpio offset
+ */
+static int rza1_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+	struct rza1_port *port = gpiochip_get_data(chip);
+
+	return rza1_pin_get(port, offset);
+}
+
+/**
+ * rza1_gpio_set() - set a gpio pin value
+ *
+ * @chip: gpio chip where the gpio sits on
+ * @gpio: gpio offset
+ */
+static void rza1_gpio_set(struct gpio_chip *chip, unsigned int offset,
+			  int value)
+{
+	struct rza1_port *port = gpiochip_get_data(chip);
+
+	rza1_pin_set(port, offset, value);
+}
+
+struct gpio_chip rza1_gpiochip_template = {
+	.request		= rza1_gpio_request,
+	.free			= rza1_gpio_free,
+	.get_direction		= rza1_gpio_get_direction,
+	.direction_input	= rza1_gpio_direction_input,
+	.direction_output	= rza1_gpio_direction_output,
+	.get			= rza1_gpio_get,
+	.set			= rza1_gpio_set,
+};
+
+/* ----------------------------------------------------------------------------
+ * pinmux operations
+ */
+
+/**
+ * rza1_pinmux_set() - retrieve pins from a group and apply them mux settings
+ *
+ * @pctldev: pin controller device
+ * @selector: function selector
+ * @group: group selector
+ */
+static int rza1_pinmux_set(struct pinctrl_dev *pctldev, unsigned int selector,
+			   unsigned int group)
+{
+	int i;
+	struct group_desc *grp;
+	struct function_desc *func;
+	struct rza1_pin_conf *pin_confs;
+	struct rza1_pinctrl *rza1_pctl = pinctrl_dev_get_drvdata(pctldev);
+
+	grp = pinctrl_generic_get_group(pctldev, group);
+	if (!grp)
+		return -EINVAL;
+
+	func = pinmux_generic_get_function(pctldev, selector);
+	if (!func)
+		return -EINVAL;
+
+	pin_confs = (struct rza1_pin_conf *)func->data;
+	for (i = 0; i < grp->num_pins; ++i) {
+		int ret;
+
+		ret = rza1_alternate_function_conf(rza1_pctl, &pin_confs[i]);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+struct pinmux_ops rza1_pinmux_ops = {
+	.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		= rza1_pinmux_set,
+	.strict			= true,
+};
+
+/* ----------------------------------------------------------------------------
+ * RZ/A1 pin controller driver operations
+ */
+
+static unsigned int rza1_count_gpio_chips(struct device_node *np)
+{
+	unsigned int count = 0;
+	struct device_node *child;
+
+	for_each_child_of_node(np, child) {
+		if (!of_property_read_bool(child, "gpio-controller"))
+			continue;
+
+		count++;
+	}
+
+	return count;
+}
+
+/**
+ * rza1_parse_pmx_function() - parse and register a pin mux function
+ *
+ * Pins for RZ SoC pin controller described by "renesas-pins" property.
+ *
+ * First argument in the list identifies the pin, while the second one
+ * describes the requested alternate function number and additional
+ * configuration parameter to be applied to the selected function.
+ *
+ * @rza1_pctl: RZ/A1 pin controller device
+ * @np: of pmx sub-node
+ */
+static int rza1_parse_pmx_function(struct rza1_pinctrl *rza1_pctl,
+				   struct device_node *np)
+{
+	int ret;
+	int of_pins;
+	unsigned int i;
+	unsigned int *grpins;
+	const char *grpname;
+	const char **fngrps;
+	struct rza1_pin_conf *pin_confs;
+	struct pinctrl_dev *pctldev = rza1_pctl->pctl;
+	char const *prop_name = "renesas,pins";
+
+	of_pins = pinctrl_count_index_with_args(np, prop_name);
+	if (of_pins <= 0) {
+		dev_err(rza1_pctl->dev, "Missing %s property\n", prop_name);
+		return -ENOENT;
+	}
+
+	/*
+	 * Functions are made of 1 group only;
+	 * in facts, functions and groups are identical for this pin controller
+	 * except that functions carry an array of per-pin configurations
+	 * settings.
+	 */
+	pin_confs = devm_kcalloc(rza1_pctl->dev, of_pins, sizeof(*pin_confs),
+				 GFP_KERNEL);
+	grpins = devm_kcalloc(rza1_pctl->dev, of_pins, sizeof(*grpins),
+			      GFP_KERNEL);
+	fngrps = devm_kzalloc(rza1_pctl->dev, sizeof(*fngrps), GFP_KERNEL);
+
+	if (!pin_confs || !grpins || !fngrps)
+		return -ENOMEM;
+
+	/* Collect pin positions and mux settings to store them in function */
+	for (i = 0; i < of_pins; ++i) {
+		struct rza1_pin_conf *pin_conf = &pin_confs[i];
+		struct of_phandle_args of_pins_args;
+
+		ret = pinctrl_parse_index_with_args(np, prop_name, i,
+						    &of_pins_args);
+		if (ret)
+			return ret;
+
+		if (of_pins_args.args_count < RZA1_PINMUX_OF_ARGS) {
+			dev_err(rza1_pctl->dev,
+				"Wrong arguments number for %s property\n",
+				prop_name);
+			return -EINVAL;
+		}
+
+		/*
+		 * This new pins configuration will be associated with a new
+		 * function, and later used to set-up pin muxing
+		 */
+		pin_conf->id = of_pins_args.args[0];
+		pin_conf->port = RZA1_PIN_TO_PORT(pin_conf->id);
+		pin_conf->offset = RZA1_PIN_TO_OFFSET(pin_conf->id);
+		pin_conf->mux_conf = of_pins_args.args[1];
+
+		if (pin_conf->port >= RZA1_NPORTS ||
+		    pin_conf->offset >= RZA1_PINS_PER_PORT) {
+			dev_err(rza1_pctl->dev,
+				"Wrong port %u pin %u for %s property\n",
+				pin_conf->port, pin_conf->offset, prop_name);
+			return -EINVAL;
+		}
+
+		grpins[i] = pin_conf->id;
+	}
+
+	grpname	= np->name;
+	fngrps[0] = grpname;
+
+	mutex_lock(&rza1_pctl->mutex);
+	ret = pinctrl_generic_add_group(pctldev, grpname, grpins, of_pins,
+					NULL);
+	if (ret) {
+		mutex_unlock(&rza1_pctl->mutex);
+		return ret;
+	}
+
+	ret = pinmux_generic_add_function(pctldev, grpname, fngrps, 1,
+					  pin_confs);
+	if (ret)
+		goto remove_group;
+	mutex_unlock(&rza1_pctl->mutex);
+
+	dev_info(rza1_pctl->dev, "Parsed function and group %s with %d pins\n",
+				 grpname, of_pins);
+
+	return 0;
+
+remove_group:
+	dev_info(rza1_pctl->dev, "Unable to parse function and group %s\n",
+				 grpname);
+	pinctrl_generic_remove_last_group(pctldev);
+	mutex_unlock(&rza1_pctl->mutex);
+
+	return ret;
+}
+
+/**
+ * rza1_remove_pmx_functions() - un-register pmx functions and groups
+ *
+ * @rza1_pctl: RZ/A1 pin controller device
+ */
+static void rza1_remove_pmx_functions(struct rza1_pinctrl *rza1_pctl)
+{
+	struct pinctrl_dev *pctldev = rza1_pctl->pctl;
+
+	mutex_lock(&rza1_pctl->mutex);
+	pinmux_generic_free_functions(pctldev);
+	mutex_unlock(&rza1_pctl->mutex);
+}
+
+/**
+ * rza1_parse_gpiochip() - parse and register a gpio chip and pin range
+ *
+ * The gpio controller subnode shall provide a "gpio-ranges" list property as
+ * defined by gpio device tree binding documentation.
+ * Gpio chips and pin ranges are here collected, but ranges are registered
+ * later, after pin controller has been registered too. Only gpiochips are
+ * registered here.
+ *
+ * @rza1_pctl: RZ/A1 pin controller device
+ * @np: of gpio-controller node
+ * @chip: gpio chip to register to gpiolib
+ * @range: pin range to register to pinctrl core
+ */
+static int rza1_parse_gpiochip(struct rza1_pinctrl *rza1_pctl,
+			       struct device_node *np,
+			       struct gpio_chip *chip,
+			       struct pinctrl_gpio_range *range)
+{
+	int ret;
+	u32 pinctrl_base;
+	unsigned int gpioport;
+	struct of_phandle_args of_args;
+	const char *list_name = "gpio-ranges";
+
+	of_parse_phandle_with_fixed_args(np, list_name, 3, 0, &of_args);
+
+	/*
+	 * Find out on which port this gpio-chip maps to inspecting the second
+	 * argument of "gpio-ranges" property.
+	 */
+	pinctrl_base = of_args.args[1];
+	gpioport = RZA1_PIN_TO_PORT(pinctrl_base);
+	if (gpioport > RZA1_NPORTS) {
+		dev_err(rza1_pctl->dev,
+			"Invalid values in property %s\n", list_name);
+		return -EINVAL;
+	}
+
+	*chip		= rza1_gpiochip_template;
+	chip->base	= -1;
+	chip->label	= kasprintf(GFP_KERNEL, "%s-%d", np->name, gpioport);
+	chip->ngpio	= of_args.args[2];
+	chip->of_node	= np;
+
+	range->id	= gpioport;
+	range->name	= kasprintf(GFP_KERNEL, "%s-%d", np->name, gpioport);
+	range->pin_base	= range->base = pinctrl_base;
+	range->npins	= of_args.args[2];
+	range->gc	= chip;
+
+	ret = devm_gpiochip_add_data(rza1_pctl->dev, chip,
+				     &rza1_pctl->ports[gpioport]);
+	if (ret)
+		return ret;
+
+	dev_info(rza1_pctl->dev, "Parsed gpiochip %s with %d pins\n",
+		 chip->label, chip->ngpio);
+
+	return 0;
+}
+
+/**
+ * rza1_parse_dt() - parse DT to collect gpiochips and pmx functions
+ *
+ * @rza1_pctl: RZ/A1 pin controller device
+ */
+static int rza1_parse_dt(struct rza1_pinctrl *rza1_pctl)
+{
+	int ret;
+	unsigned int npmxfuncs;
+	unsigned int ngpiochips;
+	unsigned int i;
+	struct gpio_chip *gpio_chips;
+	struct pinctrl_gpio_range *gpio_ranges;
+	struct device_node *np = rza1_pctl->dev->of_node;
+	struct device_node *child;
+
+	ngpiochips = rza1_count_gpio_chips(np);
+	if (ngpiochips) {
+		dev_info(rza1_pctl->dev, "Registering %u gpio chips\n",
+					 ngpiochips);
+
+		gpio_chips = devm_kcalloc(rza1_pctl->dev, ngpiochips,
+					  sizeof(*gpio_chips), GFP_KERNEL);
+		gpio_ranges = devm_kcalloc(rza1_pctl->dev, ngpiochips,
+					   sizeof(*gpio_ranges), GFP_KERNEL);
+		if (!gpio_chips || !gpio_ranges)
+			return -ENOMEM;
+	} else {
+		dev_dbg(rza1_pctl->dev, "No gpiochip registered\n");
+		gpio_ranges = NULL;
+	}
+
+	rza1_pctl->gpio_ranges	= gpio_ranges;
+
+	i = 0;
+	npmxfuncs = 0;
+	for_each_child_of_node(np, child) {
+		if (of_property_read_bool(child, "gpio-controller")) {
+			/* Never get here if ngpiochips == 0 */
+			ret = rza1_parse_gpiochip(rza1_pctl, child,
+						  &gpio_chips[i],
+						  &gpio_ranges[i]);
+			if (ret)
+				goto gpio_pmx_unregister;
+
+			++i;
+		} else {
+			ret = rza1_parse_pmx_function(rza1_pctl, child);
+			if (ret)
+				goto gpio_pmx_unregister;
+
+			++npmxfuncs;
+		}
+	}
+
+	rza1_pctl->ngpiochips = i;
+
+	dev_info(rza1_pctl->dev,
+		 "Registered %u gpio controllers and %u pin mux functions\n",
+		 rza1_pctl->ngpiochips, npmxfuncs);
+
+	return 0;
+
+gpio_pmx_unregister:
+	/*
+	 * If a pmx function creation fails or a gpiochip cannot be registered,
+	 * clean up everything we have registered to gpio or pmx core so far.
+	 */
+	for (; i > 0; i--)
+		devm_gpiochip_remove(rza1_pctl->dev, &gpio_chips[i - 1]);
+
+	rza1_remove_pmx_functions(rza1_pctl);
+
+	return ret;
+}
+
+/**
+ * rza1_pinctrl_register() - Enumerate pins, ports, gpiochips and functions and
+ *			     register to pinctrl and gpio cores
+ *
+ * @rza1_pctl: RZ/A1 pin controller device
+ */
+static int rza1_pinctrl_register(struct rza1_pinctrl *rza1_pctl)
+{
+	int ret;
+	unsigned int i;
+	struct rza1_port *ports;
+	struct pinctrl_pin_desc *pins;
+
+	pins = devm_kcalloc(rza1_pctl->dev, RZA1_NPINS, sizeof(*pins),
+			    GFP_KERNEL);
+	ports = devm_kcalloc(rza1_pctl->dev, RZA1_NPORTS, sizeof(*ports),
+			     GFP_KERNEL);
+	if (!pins || !ports)
+		return -ENOMEM;
+
+	rza1_pctl->pins		= pins;
+	rza1_pctl->desc.pins	= pins;
+	rza1_pctl->desc.npins	= RZA1_NPINS;
+	rza1_pctl->ports	= ports;
+
+	for (i = 0; i < RZA1_NPINS; ++i) {
+		unsigned int port = RZA1_PIN_TO_PORT(i);
+		unsigned int offset = RZA1_PIN_TO_OFFSET(i);
+
+		pins[i].number = i;
+		pins[i].name = kasprintf(GFP_KERNEL, "P%u-%u", port, offset);
+
+		if (i % RZA1_PINS_PER_PORT == 0) {
+			/*
+			 * Setup ports;
+			 * they provide per-port lock and logical base address.
+			 */
+			unsigned int port_id = RZA1_PIN_TO_PORT(i);
+
+			ports[port_id].id = port_id;
+			ports[port_id].base = rza1_pctl->base;
+			ports[port_id].pins = &pins[i];
+			spin_lock_init(&ports[port_id].lock);
+		}
+	}
+
+	ret = devm_pinctrl_register_and_init(rza1_pctl->dev, &rza1_pctl->desc,
+					     rza1_pctl, &rza1_pctl->pctl);
+	if (ret) {
+		dev_err(rza1_pctl->dev,
+			"RZ/A1 pin controller registration failed\n");
+		return ret;
+	}
+
+	ret = rza1_parse_dt(rza1_pctl);
+	if (ret) {
+		dev_err(rza1_pctl->dev, "RZ/A1 DT parsing failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int rza1_pinctrl_probe(struct platform_device *pdev)
+{
+	int ret;
+	unsigned int i;
+	struct resource *res;
+	struct rza1_pinctrl *rza1_pctl;
+
+	rza1_pctl = devm_kzalloc(&pdev->dev, sizeof(*rza1_pctl), GFP_KERNEL);
+	if (!rza1_pctl)
+		return -ENOMEM;
+
+	rza1_pctl->dev = &pdev->dev;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (ret)
+		return -ENODEV;
+
+	rza1_pctl->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(rza1_pctl->base))
+		return PTR_ERR(rza1_pctl->base);
+
+	mutex_init(&rza1_pctl->mutex);
+
+	platform_set_drvdata(pdev, rza1_pctl);
+
+	rza1_pctl->desc.name	= DRIVER_NAME;
+	rza1_pctl->desc.pctlops	= &rza1_pinctrl_ops;
+	rza1_pctl->desc.pmxops	= &rza1_pinmux_ops;
+	rza1_pctl->desc.owner	= THIS_MODULE;
+
+	ret = rza1_pinctrl_register(rza1_pctl);
+	if (ret)
+		return ret;
+
+	/* register pin control ranges collected while parsing device tree */
+	for (i = 0; i < rza1_pctl->ngpiochips; i++)
+		pinctrl_add_gpio_range(rza1_pctl->pctl,
+				       &rza1_pctl->gpio_ranges[i]);
+
+	dev_info(&pdev->dev,
+		 "RZ/A1 pin controller and gpio successfully registered\n");
+
+	return 0;
+}
+
+static const struct of_device_id rza1_pinctrl_of_match[] = {
+	{ .compatible = "renesas,r7s72100-ports", },
+	{ }
+};
+
+static struct platform_driver rza1_pinctrl_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+		.of_match_table = rza1_pinctrl_of_match,
+	},
+	.probe = rza1_pinctrl_probe,
+};
+
+static int __init rza1_pinctrl_init(void)
+{
+	return platform_driver_register(&rza1_pinctrl_driver);
+}
+core_initcall(rza1_pinctrl_init);
+
+MODULE_AUTHOR("Jacopo Mondi <jacopo+renesas@jmondi.org");
+MODULE_DESCRIPTION("Pin and gpio controller driver for Reneas RZ/A1 SoC");
+MODULE_LICENSE("GPL v2");
-- 
2.7.4

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

* [PATCH 2/7] Documentation: devicetree: bindings: Add RZ/A1 pinctrl binding documentation
  2017-02-20 17:13 Renesas RZ/A1 pin and gpio controller Jacopo Mondi
@ 2017-02-20 17:13     ` Jacopo Mondi
  2017-02-20 17:13 ` [PATCH 5/7] arm: dts: genmai: Add SCIF2 pin group Jacopo Mondi
  2017-03-02 20:16 ` Renesas RZ/A1 pin and gpio controller Chris Brandt
  2 siblings, 0 replies; 29+ messages in thread
From: Jacopo Mondi @ 2017-02-20 17:13 UTC (permalink / raw)
  To: geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw,
	linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	linux-I+IVW8TIWO2tmTQ+vhA3Yw
  Cc: linux-renesas-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Add device tree bindings documentation for Renesas RZ/A1 gpio and pin
controller.

Signed-off-by: Jacopo Mondi <jacopo+renesas-AW8dsiIh9cEdnm+yROfE0A@public.gmane.org>
---
 .../bindings/pinctrl/renesas,rza1-pinctrl.txt      | 114 +++++++++++++++++++++
 1 file changed, 114 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/renesas,rza1-pinctrl.txt

diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,rza1-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/renesas,rza1-pinctrl.txt
new file mode 100644
index 0000000..1136146
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/renesas,rza1-pinctrl.txt
@@ -0,0 +1,114 @@
+Renesas RZ/A1 combined Pin and GPIO controller
+
+Renesas SoCs of RZ/A1 family feature a combined Pin and GPIO controller
+hardware controller, named "Ports" in the hardware reference manual.
+Pin multiplexing and GPIO configuration is performed on a per-pin base
+writing configuration values to per-port register sets.
+Each "port" features up to 16 pins, each of them configurable for GPIO
+function (port mode) or in alternate function mode.
+Up to 8 different alternate function modes exist for each single pin.
+
+Pin controller node
+-------------------
+
+Required properties:
+  - compatible
+    this shall be "renesas,r7s72100-ports".
+
+  - #pinctrl-cells
+    as defined by pinctrl-bindings.txt, this is the number
+    of cells (in addition to pin index) required to configure a single pin.
+    Shall be set to 1.
+
+  - reg
+    address base and length of the memory area where pin controller
+    hardware is mapped to.
+
+Example:
+Pin controller node for RZ/A1H SoC (r7s72100)
+
+pinctrl: pinctrl@fcfe3000 {
+	compatible = "renesas,r7s72100-ports";
+
+	#pinctrl-cells = <1>;
+
+	reg = <0xfcfe3000 0x4248>;
+};
+
+Sub-nodes
+---------
+
+The child nodes of the pin controller node describe a pin multiplexing
+function or a gpio controller alternatively.
+
+- Pin multiplexing sub-nodes:
+  A pin multiplexing sub-node describes how to configure a set of
+  (or a single) pin in some desired alternate function mode.
+  A single sub-node may define several pin configurations groups.
+
+  Required properties:
+    - renesas,pins
+      describes an array of pin multiplexing configurations.
+      When a pin has to be configured in alternate function mode, use this
+      property to identify the pin by its global index, and provide its
+      alternate function configuration description along with it.
+      When multiple pins are required to be configured as part of the same
+      alternate function (odds are single-pin alternate functions exist) they
+      shall be specified as members of the same argument list of a single
+      "renesas-pins" property.
+      Helper macros to ease calculating the pin index from its position
+      (port where it sits on and pin offset), and alternate function
+      configuration options are provided in pin controller header file at:
+      include/dt-bindings/pinctrl/r7s72100-pinctrl.h
+
+  Example:
+  A serial communication interface with a TX output pin and a RX input pin.
+  The RX pin requires input capabilities.
+
+  &pinctrl {
+	scif2_pins: serial2 {
+		renesas,pins = <PIN(3, 0) 6>,
+			       <PIN(3, 2) (4 | INPUT_EN)>;
+	};
+  }
+
+  Pin #0 on port #3 is configured in alternate function #6.
+  Pin #2 on port #3 is configured in alternate function #4 with input enabled.
+
+- GPIO controller sub-nodes:
+  Each port of r7s72100 pin controller hardware is itself a gpio controller.
+  Different SoCs have different number of available pins per port, but
+  generally speaking, each of them can be configured in GPIO ("port") mode
+  on this hardware.
+  Describe gpio-controllers using sub-nodes with the following properties.
+
+  Required properties:
+    - gpio-controller
+      empty property as defined by gpio bindings documentation.
+    - #gpio-cells
+      number of cells required to identify and configure a GPIO.
+      Shall be 2.
+    - gpio-ranges
+      Describes a gpio controller specifying its specific pin base, the pin
+      base in the global pin numbering space, and the number of controlled
+      pins, as defined by gpio bindings documentation. Refer to this file
+      for a more detailed description.
+
+  Example:
+  A gpio controller node, controlling 16 pins indexed starting from 0.
+  The gpio controller base in the global pin indexing space is pin 48, thus
+  pins [0 - 15] on this controller map to pins [48 - 63] in the global pin
+  indexing space.
+
+  port3: gpio@3 {
+	gpio-controller;
+	#gpio-cells = <2>;
+	gpio-ranges = <&pinctrl 0 48 16>;
+  };
+
+  A device node willing to use pins controlled by this gpio controller, shall
+  refer to it as follows:
+
+  led1 {
+	gpios = <&port3 10 GPIO_ACTIVE_LOW>;
+  };
-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH 2/7] Documentation: devicetree: bindings: Add RZ/A1 pinctrl binding documentation
@ 2017-02-20 17:13     ` Jacopo Mondi
  0 siblings, 0 replies; 29+ messages in thread
From: Jacopo Mondi @ 2017-02-20 17:13 UTC (permalink / raw)
  To: geert+renesas, laurent.pinchart, linus.walleij, robh+dt,
	mark.rutland, linux
  Cc: linux-renesas-soc, linux-gpio, devicetree

Add device tree bindings documentation for Renesas RZ/A1 gpio and pin
controller.

Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
---
 .../bindings/pinctrl/renesas,rza1-pinctrl.txt      | 114 +++++++++++++++++++++
 1 file changed, 114 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/renesas,rza1-pinctrl.txt

diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,rza1-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/renesas,rza1-pinctrl.txt
new file mode 100644
index 0000000..1136146
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/renesas,rza1-pinctrl.txt
@@ -0,0 +1,114 @@
+Renesas RZ/A1 combined Pin and GPIO controller
+
+Renesas SoCs of RZ/A1 family feature a combined Pin and GPIO controller
+hardware controller, named "Ports" in the hardware reference manual.
+Pin multiplexing and GPIO configuration is performed on a per-pin base
+writing configuration values to per-port register sets.
+Each "port" features up to 16 pins, each of them configurable for GPIO
+function (port mode) or in alternate function mode.
+Up to 8 different alternate function modes exist for each single pin.
+
+Pin controller node
+-------------------
+
+Required properties:
+  - compatible
+    this shall be "renesas,r7s72100-ports".
+
+  - #pinctrl-cells
+    as defined by pinctrl-bindings.txt, this is the number
+    of cells (in addition to pin index) required to configure a single pin.
+    Shall be set to 1.
+
+  - reg
+    address base and length of the memory area where pin controller
+    hardware is mapped to.
+
+Example:
+Pin controller node for RZ/A1H SoC (r7s72100)
+
+pinctrl: pinctrl@fcfe3000 {
+	compatible = "renesas,r7s72100-ports";
+
+	#pinctrl-cells = <1>;
+
+	reg = <0xfcfe3000 0x4248>;
+};
+
+Sub-nodes
+---------
+
+The child nodes of the pin controller node describe a pin multiplexing
+function or a gpio controller alternatively.
+
+- Pin multiplexing sub-nodes:
+  A pin multiplexing sub-node describes how to configure a set of
+  (or a single) pin in some desired alternate function mode.
+  A single sub-node may define several pin configurations groups.
+
+  Required properties:
+    - renesas,pins
+      describes an array of pin multiplexing configurations.
+      When a pin has to be configured in alternate function mode, use this
+      property to identify the pin by its global index, and provide its
+      alternate function configuration description along with it.
+      When multiple pins are required to be configured as part of the same
+      alternate function (odds are single-pin alternate functions exist) they
+      shall be specified as members of the same argument list of a single
+      "renesas-pins" property.
+      Helper macros to ease calculating the pin index from its position
+      (port where it sits on and pin offset), and alternate function
+      configuration options are provided in pin controller header file at:
+      include/dt-bindings/pinctrl/r7s72100-pinctrl.h
+
+  Example:
+  A serial communication interface with a TX output pin and a RX input pin.
+  The RX pin requires input capabilities.
+
+  &pinctrl {
+	scif2_pins: serial2 {
+		renesas,pins = <PIN(3, 0) 6>,
+			       <PIN(3, 2) (4 | INPUT_EN)>;
+	};
+  }
+
+  Pin #0 on port #3 is configured in alternate function #6.
+  Pin #2 on port #3 is configured in alternate function #4 with input enabled.
+
+- GPIO controller sub-nodes:
+  Each port of r7s72100 pin controller hardware is itself a gpio controller.
+  Different SoCs have different number of available pins per port, but
+  generally speaking, each of them can be configured in GPIO ("port") mode
+  on this hardware.
+  Describe gpio-controllers using sub-nodes with the following properties.
+
+  Required properties:
+    - gpio-controller
+      empty property as defined by gpio bindings documentation.
+    - #gpio-cells
+      number of cells required to identify and configure a GPIO.
+      Shall be 2.
+    - gpio-ranges
+      Describes a gpio controller specifying its specific pin base, the pin
+      base in the global pin numbering space, and the number of controlled
+      pins, as defined by gpio bindings documentation. Refer to this file
+      for a more detailed description.
+
+  Example:
+  A gpio controller node, controlling 16 pins indexed starting from 0.
+  The gpio controller base in the global pin indexing space is pin 48, thus
+  pins [0 - 15] on this controller map to pins [48 - 63] in the global pin
+  indexing space.
+
+  port3: gpio@3 {
+	gpio-controller;
+	#gpio-cells = <2>;
+	gpio-ranges = <&pinctrl 0 48 16>;
+  };
+
+  A device node willing to use pins controlled by this gpio controller, shall
+  refer to it as follows:
+
+  led1 {
+	gpios = <&port3 10 GPIO_ACTIVE_LOW>;
+  };
-- 
2.7.4

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

* [PATCH 3/7] arm: dts: dt-bindings: Add Renesas RZ pinctrl header
  2017-02-20 17:13 Renesas RZ/A1 pin and gpio controller Jacopo Mondi
@ 2017-02-20 17:13     ` Jacopo Mondi
  2017-02-20 17:13 ` [PATCH 5/7] arm: dts: genmai: Add SCIF2 pin group Jacopo Mondi
  2017-03-02 20:16 ` Renesas RZ/A1 pin and gpio controller Chris Brandt
  2 siblings, 0 replies; 29+ messages in thread
From: Jacopo Mondi @ 2017-02-20 17:13 UTC (permalink / raw)
  To: geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw,
	linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	linux-I+IVW8TIWO2tmTQ+vhA3Yw
  Cc: linux-renesas-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Add dt-bindings for Renesas r7s72100 pin controller header file.

Signed-off-by: Jacopo Mondi <jacopo+renesas-AW8dsiIh9cEdnm+yROfE0A@public.gmane.org>
---
 include/dt-bindings/pinctrl/r7s72100-pinctrl.h | 30 ++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)
 create mode 100644 include/dt-bindings/pinctrl/r7s72100-pinctrl.h

diff --git a/include/dt-bindings/pinctrl/r7s72100-pinctrl.h b/include/dt-bindings/pinctrl/r7s72100-pinctrl.h
new file mode 100644
index 0000000..24759bf
--- /dev/null
+++ b/include/dt-bindings/pinctrl/r7s72100-pinctrl.h
@@ -0,0 +1,30 @@
+/*
+ * Defines macros and constants for Renesas RZ/A1 pin controller pin
+ * muxing functions.
+ */
+#ifndef __DT_BINDINGS_PINCTRL_RENESAS_RZA1_H
+#define __DT_BINDINGS_PINCTRL_RENESAS_RZA1_H
+
+#define RZA1_PINS_PER_PORT	16
+
+/* Create the pin index from it's bank and position numbers */
+#define PIN(b, p)		((b) * RZA1_PINS_PER_PORT + (p))
+
+/* Flags to apply to alternate function configuration */
+/*
+ * Pin needs input buffer enabled.
+ * This applies to pin which alternate function requires input capabilities.
+ * Eg: RX pin on a serial interface needs this flag to be set.
+ */
+#define INPUT_EN		(1 << 3)
+
+/*
+ * Let software drive the pin I/O direction overriding the alternate function
+ * configuration.
+ * Some alternate function requires software to force I/O direction of a pin,
+ * ovverriding the designated one.
+ * Reference to the HW manual to know when this flag shall be used.
+ */
+#define SWIO			(1 << 4)
+
+#endif
-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH 3/7] arm: dts: dt-bindings: Add Renesas RZ pinctrl header
@ 2017-02-20 17:13     ` Jacopo Mondi
  0 siblings, 0 replies; 29+ messages in thread
From: Jacopo Mondi @ 2017-02-20 17:13 UTC (permalink / raw)
  To: geert+renesas, laurent.pinchart, linus.walleij, robh+dt,
	mark.rutland, linux
  Cc: linux-renesas-soc, linux-gpio, devicetree

Add dt-bindings for Renesas r7s72100 pin controller header file.

Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
---
 include/dt-bindings/pinctrl/r7s72100-pinctrl.h | 30 ++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)
 create mode 100644 include/dt-bindings/pinctrl/r7s72100-pinctrl.h

diff --git a/include/dt-bindings/pinctrl/r7s72100-pinctrl.h b/include/dt-bindings/pinctrl/r7s72100-pinctrl.h
new file mode 100644
index 0000000..24759bf
--- /dev/null
+++ b/include/dt-bindings/pinctrl/r7s72100-pinctrl.h
@@ -0,0 +1,30 @@
+/*
+ * Defines macros and constants for Renesas RZ/A1 pin controller pin
+ * muxing functions.
+ */
+#ifndef __DT_BINDINGS_PINCTRL_RENESAS_RZA1_H
+#define __DT_BINDINGS_PINCTRL_RENESAS_RZA1_H
+
+#define RZA1_PINS_PER_PORT	16
+
+/* Create the pin index from it's bank and position numbers */
+#define PIN(b, p)		((b) * RZA1_PINS_PER_PORT + (p))
+
+/* Flags to apply to alternate function configuration */
+/*
+ * Pin needs input buffer enabled.
+ * This applies to pin which alternate function requires input capabilities.
+ * Eg: RX pin on a serial interface needs this flag to be set.
+ */
+#define INPUT_EN		(1 << 3)
+
+/*
+ * Let software drive the pin I/O direction overriding the alternate function
+ * configuration.
+ * Some alternate function requires software to force I/O direction of a pin,
+ * ovverriding the designated one.
+ * Reference to the HW manual to know when this flag shall be used.
+ */
+#define SWIO			(1 << 4)
+
+#endif
-- 
2.7.4

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

* [PATCH 4/7] arm: dts: r7s72100: Add pin controller node
  2017-02-20 17:13 Renesas RZ/A1 pin and gpio controller Jacopo Mondi
@ 2017-02-20 17:13     ` Jacopo Mondi
  2017-02-20 17:13 ` [PATCH 5/7] arm: dts: genmai: Add SCIF2 pin group Jacopo Mondi
  2017-03-02 20:16 ` Renesas RZ/A1 pin and gpio controller Chris Brandt
  2 siblings, 0 replies; 29+ messages in thread
From: Jacopo Mondi @ 2017-02-20 17:13 UTC (permalink / raw)
  To: geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw,
	linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	linux-I+IVW8TIWO2tmTQ+vhA3Yw
  Cc: linux-renesas-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Add pin controller node with 12 gpio controller sub-nodes to
r7s72100 dtsi.

Signed-off-by: Jacopo Mondi <jacopo+renesas-AW8dsiIh9cEdnm+yROfE0A@public.gmane.org>
---
 arch/arm/boot/dts/r7s72100.dtsi | 81 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)

diff --git a/arch/arm/boot/dts/r7s72100.dtsi b/arch/arm/boot/dts/r7s72100.dtsi
index 3dd427d..a77a431b 100644
--- a/arch/arm/boot/dts/r7s72100.dtsi
+++ b/arch/arm/boot/dts/r7s72100.dtsi
@@ -12,6 +12,7 @@
 #include <dt-bindings/clock/r7s72100-clock.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/r7s72100-pinctrl.h>
 
 / {
 	compatible = "renesas,r7s72100";
@@ -171,6 +172,86 @@
 		};
 	};
 
+	pinctrl: pinctrl@fcfe3000 {
+		compatible = "renesas,r7s72100-ports";
+
+		#pinctrl-cells = <1>;
+
+		reg = <0xfcfe3000 0x4248>;
+
+		port0: gpio@0 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 0 16>;
+		};
+
+		port1: gpio@1 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 16 16>;
+		};
+
+		port2: gpio@2 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 32 16>;
+		};
+
+		port3: gpio@3 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 48 16>;
+		};
+
+		port4: gpio@4 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 64 16>;
+		};
+
+		port5: gpio@5 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 80 16>;
+		};
+
+		port6: gpio@6 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 96 16>;
+		};
+
+		port7: gpio@7 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 112 16>;
+		};
+
+		port8: gpio@8 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 128 16>;
+		};
+
+		port9: gpio@9 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 144 16>;
+		};
+
+		port10: gpio@10 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 160 16>;
+		};
+
+		port11: gpio@11 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 176 16>;
+		};
+	};
+
 	scif0: serial@e8007000 {
 		compatible = "renesas,scif-r7s72100", "renesas,scif";
 		reg = <0xe8007000 64>;
-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH 4/7] arm: dts: r7s72100: Add pin controller node
@ 2017-02-20 17:13     ` Jacopo Mondi
  0 siblings, 0 replies; 29+ messages in thread
From: Jacopo Mondi @ 2017-02-20 17:13 UTC (permalink / raw)
  To: geert+renesas, laurent.pinchart, linus.walleij, robh+dt,
	mark.rutland, linux
  Cc: linux-renesas-soc, linux-gpio, devicetree

Add pin controller node with 12 gpio controller sub-nodes to
r7s72100 dtsi.

Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
---
 arch/arm/boot/dts/r7s72100.dtsi | 81 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)

diff --git a/arch/arm/boot/dts/r7s72100.dtsi b/arch/arm/boot/dts/r7s72100.dtsi
index 3dd427d..a77a431b 100644
--- a/arch/arm/boot/dts/r7s72100.dtsi
+++ b/arch/arm/boot/dts/r7s72100.dtsi
@@ -12,6 +12,7 @@
 #include <dt-bindings/clock/r7s72100-clock.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/r7s72100-pinctrl.h>
 
 / {
 	compatible = "renesas,r7s72100";
@@ -171,6 +172,86 @@
 		};
 	};
 
+	pinctrl: pinctrl@fcfe3000 {
+		compatible = "renesas,r7s72100-ports";
+
+		#pinctrl-cells = <1>;
+
+		reg = <0xfcfe3000 0x4248>;
+
+		port0: gpio@0 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 0 16>;
+		};
+
+		port1: gpio@1 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 16 16>;
+		};
+
+		port2: gpio@2 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 32 16>;
+		};
+
+		port3: gpio@3 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 48 16>;
+		};
+
+		port4: gpio@4 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 64 16>;
+		};
+
+		port5: gpio@5 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 80 16>;
+		};
+
+		port6: gpio@6 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 96 16>;
+		};
+
+		port7: gpio@7 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 112 16>;
+		};
+
+		port8: gpio@8 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 128 16>;
+		};
+
+		port9: gpio@9 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 144 16>;
+		};
+
+		port10: gpio@10 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 160 16>;
+		};
+
+		port11: gpio@11 {
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&pinctrl 0 176 16>;
+		};
+	};
+
 	scif0: serial@e8007000 {
 		compatible = "renesas,scif-r7s72100", "renesas,scif";
 		reg = <0xe8007000 64>;
-- 
2.7.4

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

* [PATCH 5/7] arm: dts: genmai: Add SCIF2 pin group
  2017-02-20 17:13 Renesas RZ/A1 pin and gpio controller Jacopo Mondi
       [not found] ` <1487610788-6939-1-git-send-email-jacopo+renesas-AW8dsiIh9cEdnm+yROfE0A@public.gmane.org>
@ 2017-02-20 17:13 ` Jacopo Mondi
  2017-03-02 20:16 ` Renesas RZ/A1 pin and gpio controller Chris Brandt
  2 siblings, 0 replies; 29+ messages in thread
From: Jacopo Mondi @ 2017-02-20 17:13 UTC (permalink / raw)
  To: geert+renesas, laurent.pinchart, linus.walleij, robh+dt,
	mark.rutland, linux
  Cc: linux-renesas-soc, linux-gpio, devicetree

Add pin configuration subnode for SCIF2 serial debug interface.

Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
---
 arch/arm/boot/dts/r7s72100-genmai.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm/boot/dts/r7s72100-genmai.dts b/arch/arm/boot/dts/r7s72100-genmai.dts
index 118a8e2..f7be440 100644
--- a/arch/arm/boot/dts/r7s72100-genmai.dts
+++ b/arch/arm/boot/dts/r7s72100-genmai.dts
@@ -36,6 +36,15 @@
 	};
 };
 
+&pinctrl {
+
+	scif2_pins: serial2 {
+		/* P3_0 as TxD2; P3_2 as RxD2 */
+		renesas,pins = <PIN(3, 0) 6>,
+			       <PIN(3, 2) (4 | INPUT_EN)>;
+	};
+};
+
 &extal_clk {
 	clock-frequency = <13330000>;
 };
@@ -60,6 +69,9 @@
 };
 
 &scif2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&scif2_pins>;
+
 	status = "okay";
 };
 
-- 
2.7.4

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

* [PATCH 6/7] arm: dts: genmai: Add RIIC2 pin group
  2017-02-20 17:13 Renesas RZ/A1 pin and gpio controller Jacopo Mondi
@ 2017-02-20 17:13     ` Jacopo Mondi
  2017-02-20 17:13 ` [PATCH 5/7] arm: dts: genmai: Add SCIF2 pin group Jacopo Mondi
  2017-03-02 20:16 ` Renesas RZ/A1 pin and gpio controller Chris Brandt
  2 siblings, 0 replies; 29+ messages in thread
From: Jacopo Mondi @ 2017-02-20 17:13 UTC (permalink / raw)
  To: geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw,
	linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	linux-I+IVW8TIWO2tmTQ+vhA3Yw
  Cc: linux-renesas-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Add pin configuration subnode for RIIC2 interface.

Signed-off-by: Jacopo Mondi <jacopo+renesas-AW8dsiIh9cEdnm+yROfE0A@public.gmane.org>
---
 arch/arm/boot/dts/r7s72100-genmai.dts | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/boot/dts/r7s72100-genmai.dts b/arch/arm/boot/dts/r7s72100-genmai.dts
index f7be440..467a8a1 100644
--- a/arch/arm/boot/dts/r7s72100-genmai.dts
+++ b/arch/arm/boot/dts/r7s72100-genmai.dts
@@ -43,6 +43,12 @@
 		renesas,pins = <PIN(3, 0) 6>,
 			       <PIN(3, 2) (4 | INPUT_EN)>;
 	};
+
+	i2c2_pins: i2c2 {
+		/* RIIC2: P1_4 as SCL, P1_5 as SDA */
+		renesas,pins = <PIN(1, 4) (1 | INPUT_EN)>,
+			       <PIN(1, 5) (1 | INPUT_EN)>;
+	};
 };
 
 &extal_clk {
@@ -61,6 +67,9 @@
 	status = "okay";
 	clock-frequency = <400000>;
 
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins>;
+
 	eeprom@50 {
 		compatible = "renesas,24c128";
 		reg = <0x50>;
-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH 6/7] arm: dts: genmai: Add RIIC2 pin group
@ 2017-02-20 17:13     ` Jacopo Mondi
  0 siblings, 0 replies; 29+ messages in thread
From: Jacopo Mondi @ 2017-02-20 17:13 UTC (permalink / raw)
  To: geert+renesas, laurent.pinchart, linus.walleij, robh+dt,
	mark.rutland, linux
  Cc: linux-renesas-soc, linux-gpio, devicetree

Add pin configuration subnode for RIIC2 interface.

Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
---
 arch/arm/boot/dts/r7s72100-genmai.dts | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/boot/dts/r7s72100-genmai.dts b/arch/arm/boot/dts/r7s72100-genmai.dts
index f7be440..467a8a1 100644
--- a/arch/arm/boot/dts/r7s72100-genmai.dts
+++ b/arch/arm/boot/dts/r7s72100-genmai.dts
@@ -43,6 +43,12 @@
 		renesas,pins = <PIN(3, 0) 6>,
 			       <PIN(3, 2) (4 | INPUT_EN)>;
 	};
+
+	i2c2_pins: i2c2 {
+		/* RIIC2: P1_4 as SCL, P1_5 as SDA */
+		renesas,pins = <PIN(1, 4) (1 | INPUT_EN)>,
+			       <PIN(1, 5) (1 | INPUT_EN)>;
+	};
 };
 
 &extal_clk {
@@ -61,6 +67,9 @@
 	status = "okay";
 	clock-frequency = <400000>;
 
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c2_pins>;
+
 	eeprom@50 {
 		compatible = "renesas,24c128";
 		reg = <0x50>;
-- 
2.7.4

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

* [PATCH 7/7] arm: dts: genmai: Add user led device nodes
  2017-02-20 17:13 Renesas RZ/A1 pin and gpio controller Jacopo Mondi
@ 2017-02-20 17:13     ` Jacopo Mondi
  2017-02-20 17:13 ` [PATCH 5/7] arm: dts: genmai: Add SCIF2 pin group Jacopo Mondi
  2017-03-02 20:16 ` Renesas RZ/A1 pin and gpio controller Chris Brandt
  2 siblings, 0 replies; 29+ messages in thread
From: Jacopo Mondi @ 2017-02-20 17:13 UTC (permalink / raw)
  To: geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw,
	linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	linux-I+IVW8TIWO2tmTQ+vhA3Yw
  Cc: linux-renesas-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Add device nodes for user leds on Genmai board.

Signed-off-by: Jacopo Mondi <jacopo+renesas-AW8dsiIh9cEdnm+yROfE0A@public.gmane.org>
---
 arch/arm/boot/dts/r7s72100-genmai.dts | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/arch/arm/boot/dts/r7s72100-genmai.dts b/arch/arm/boot/dts/r7s72100-genmai.dts
index 467a8a1..162e63d 100644
--- a/arch/arm/boot/dts/r7s72100-genmai.dts
+++ b/arch/arm/boot/dts/r7s72100-genmai.dts
@@ -11,6 +11,7 @@
 
 /dts-v1/;
 #include "r7s72100.dtsi"
+#include <dt-bindings/gpio/gpio.h>
 
 / {
 	model = "Genmai";
@@ -34,6 +35,19 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 	};
+
+	leds {
+		status = "okay";
+		compatible = "gpio-leds";
+
+		led1 {
+			gpios = <&port4 10 GPIO_ACTIVE_LOW>;
+		};
+
+		led2 {
+			gpios = <&port4 11 GPIO_ACTIVE_LOW>;
+		};
+	};
 };
 
 &pinctrl {
-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH 7/7] arm: dts: genmai: Add user led device nodes
@ 2017-02-20 17:13     ` Jacopo Mondi
  0 siblings, 0 replies; 29+ messages in thread
From: Jacopo Mondi @ 2017-02-20 17:13 UTC (permalink / raw)
  To: geert+renesas, laurent.pinchart, linus.walleij, robh+dt,
	mark.rutland, linux
  Cc: linux-renesas-soc, linux-gpio, devicetree

Add device nodes for user leds on Genmai board.

Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
---
 arch/arm/boot/dts/r7s72100-genmai.dts | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/arch/arm/boot/dts/r7s72100-genmai.dts b/arch/arm/boot/dts/r7s72100-genmai.dts
index 467a8a1..162e63d 100644
--- a/arch/arm/boot/dts/r7s72100-genmai.dts
+++ b/arch/arm/boot/dts/r7s72100-genmai.dts
@@ -11,6 +11,7 @@
 
 /dts-v1/;
 #include "r7s72100.dtsi"
+#include <dt-bindings/gpio/gpio.h>
 
 / {
 	model = "Genmai";
@@ -34,6 +35,19 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 	};
+
+	leds {
+		status = "okay";
+		compatible = "gpio-leds";
+
+		led1 {
+			gpios = <&port4 10 GPIO_ACTIVE_LOW>;
+		};
+
+		led2 {
+			gpios = <&port4 11 GPIO_ACTIVE_LOW>;
+		};
+	};
 };
 
 &pinctrl {
-- 
2.7.4

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

* Re: [PATCH 4/7] arm: dts: r7s72100: Add pin controller node
  2017-02-20 17:13     ` Jacopo Mondi
  (?)
@ 2017-02-21 10:46     ` jacopo mondi
  2017-03-02 20:17       ` Chris Brandt
  -1 siblings, 1 reply; 29+ messages in thread
From: jacopo mondi @ 2017-02-21 10:46 UTC (permalink / raw)
  To: Jacopo Mondi, geert+renesas, laurent.pinchart, linus.walleij,
	robh+dt, mark.rutland, linux
  Cc: linux-renesas-soc, linux-gpio, devicetree

Hello,
     self-review to save you all some time

On 20/02/2017 18:13, Jacopo Mondi wrote:
> Add pin controller node with 12 gpio controller sub-nodes to
> r7s72100 dtsi.
>
> Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
> ---
>  arch/arm/boot/dts/r7s72100.dtsi | 81 +++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 81 insertions(+)
>
> diff --git a/arch/arm/boot/dts/r7s72100.dtsi b/arch/arm/boot/dts/r7s72100.dtsi
> index 3dd427d..a77a431b 100644
> --- a/arch/arm/boot/dts/r7s72100.dtsi
> +++ b/arch/arm/boot/dts/r7s72100.dtsi
> @@ -12,6 +12,7 @@
>  #include <dt-bindings/clock/r7s72100-clock.h>
>  #include <dt-bindings/interrupt-controller/arm-gic.h>
>  #include <dt-bindings/interrupt-controller/irq.h>
> +#include <dt-bindings/pinctrl/r7s72100-pinctrl.h>

I should move this to the board specific .dts file.
It's not needed here.

>
>  / {
>  	compatible = "renesas,r7s72100";
> @@ -171,6 +172,86 @@
>  		};
>  	};
>
> +	pinctrl: pinctrl@fcfe3000 {
> +		compatible = "renesas,r7s72100-ports";
> +
> +		#pinctrl-cells = <1>;
> +
> +		reg = <0xfcfe3000 0x4248>;
> +
> +		port0: gpio@0 {

Geert pointed out offline the if the node has a unit address, it needs a 
"reg" property.
I'll change all of these to portX: gpio-X {

> +			gpio-controller;
> +			#gpio-cells = <2>;
> +			gpio-ranges = <&pinctrl 0 0 16>;

Not all ports have 16 pins available.
This is one of the differences between different RZ/A1 SoC versions 
(RZ/A1H, RZ/A1L etc)

I'll change the number of pins to the actual available ones on each port 
for r7s72100 (RZ/A1H)

Thanks
    j


> +		};
> +
> +		port1: gpio@1 {
> +			gpio-controller;
> +			#gpio-cells = <2>;
> +			gpio-ranges = <&pinctrl 0 16 16>;
> +		};
> +
> +		port2: gpio@2 {
> +			gpio-controller;
> +			#gpio-cells = <2>;
> +			gpio-ranges = <&pinctrl 0 32 16>;
> +		};
> +
> +		port3: gpio@3 {
> +			gpio-controller;
> +			#gpio-cells = <2>;
> +			gpio-ranges = <&pinctrl 0 48 16>;
> +		};
> +
> +		port4: gpio@4 {
> +			gpio-controller;
> +			#gpio-cells = <2>;
> +			gpio-ranges = <&pinctrl 0 64 16>;
> +		};
> +
> +		port5: gpio@5 {
> +			gpio-controller;
> +			#gpio-cells = <2>;
> +			gpio-ranges = <&pinctrl 0 80 16>;
> +		};
> +
> +		port6: gpio@6 {
> +			gpio-controller;
> +			#gpio-cells = <2>;
> +			gpio-ranges = <&pinctrl 0 96 16>;
> +		};
> +
> +		port7: gpio@7 {
> +			gpio-controller;
> +			#gpio-cells = <2>;
> +			gpio-ranges = <&pinctrl 0 112 16>;
> +		};
> +
> +		port8: gpio@8 {
> +			gpio-controller;
> +			#gpio-cells = <2>;
> +			gpio-ranges = <&pinctrl 0 128 16>;
> +		};
> +
> +		port9: gpio@9 {
> +			gpio-controller;
> +			#gpio-cells = <2>;
> +			gpio-ranges = <&pinctrl 0 144 16>;
> +		};
> +
> +		port10: gpio@10 {
> +			gpio-controller;
> +			#gpio-cells = <2>;
> +			gpio-ranges = <&pinctrl 0 160 16>;
> +		};
> +
> +		port11: gpio@11 {
> +			gpio-controller;
> +			#gpio-cells = <2>;
> +			gpio-ranges = <&pinctrl 0 176 16>;
> +		};
> +	};
> +
>  	scif0: serial@e8007000 {
>  		compatible = "renesas,scif-r7s72100", "renesas,scif";
>  		reg = <0xe8007000 64>;
>

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

* Re: [PATCH 1/7] pinctrl: Renesas RZ/A1 pin and gpio controller
  2017-02-20 17:13     ` Jacopo Mondi
  (?)
@ 2017-02-21 10:49     ` jacopo mondi
  -1 siblings, 0 replies; 29+ messages in thread
From: jacopo mondi @ 2017-02-21 10:49 UTC (permalink / raw)
  To: Jacopo Mondi, geert+renesas, laurent.pinchart, linus.walleij,
	robh+dt, mark.rutland, linux
  Cc: linux-renesas-soc, linux-gpio, devicetree

Hello,
     small self-review

On 20/02/2017 18:13, Jacopo Mondi wrote:

[snip]

> +/**
> + * rza1_pinctrl_register() - Enumerate pins, ports, gpiochips and functions and
> + *			     register to pinctrl and gpio cores
> + *
> + * @rza1_pctl: RZ/A1 pin controller device
> + */
> +static int rza1_pinctrl_register(struct rza1_pinctrl *rza1_pctl)
> +{
> +	int ret;
> +	unsigned int i;
> +	struct rza1_port *ports;
> +	struct pinctrl_pin_desc *pins;
> +
> +	pins = devm_kcalloc(rza1_pctl->dev, RZA1_NPINS, sizeof(*pins),
> +			    GFP_KERNEL);
> +	ports = devm_kcalloc(rza1_pctl->dev, RZA1_NPORTS, sizeof(*ports),
> +			     GFP_KERNEL);
> +	if (!pins || !ports)
> +		return -ENOMEM;
> +
> +	rza1_pctl->pins		= pins;
> +	rza1_pctl->desc.pins	= pins;
> +	rza1_pctl->desc.npins	= RZA1_NPINS;
> +	rza1_pctl->ports	= ports;
> +
> +	for (i = 0; i < RZA1_NPINS; ++i) {
> +		unsigned int port = RZA1_PIN_TO_PORT(i);
> +		unsigned int offset = RZA1_PIN_TO_OFFSET(i);
> +
> +		pins[i].number = i;
> +		pins[i].name = kasprintf(GFP_KERNEL, "P%u-%u", port, offset);
> +
> +		if (i % RZA1_PINS_PER_PORT == 0) {
> +			/*
> +			 * Setup ports;
> +			 * they provide per-port lock and logical base address.
> +			 */
> +			unsigned int port_id = RZA1_PIN_TO_PORT(i);
> +
> +			ports[port_id].id = port_id;
> +			ports[port_id].base = rza1_pctl->base;
> +			ports[port_id].pins = &pins[i];
> +			spin_lock_init(&ports[port_id].lock);
> +		}
> +	}
> +
> +	ret = devm_pinctrl_register_and_init(rza1_pctl->dev, &rza1_pctl->desc,
> +					     rza1_pctl, &rza1_pctl->pctl);
> +	if (ret) {
> +		dev_err(rza1_pctl->dev,
> +			"RZ/A1 pin controller registration failed\n");
> +		return ret;
> +	}
> +
> +	ret = rza1_parse_dt(rza1_pctl);
> +	if (ret) {
> +		dev_err(rza1_pctl->dev, "RZ/A1 DT parsing failed\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int rza1_pinctrl_probe(struct platform_device *pdev)
> +{
> +	int ret;
> +	unsigned int i;
> +	struct resource *res;
> +	struct rza1_pinctrl *rza1_pctl;
> +
> +	rza1_pctl = devm_kzalloc(&pdev->dev, sizeof(*rza1_pctl), GFP_KERNEL);
> +	if (!rza1_pctl)
> +		return -ENOMEM;
> +
> +	rza1_pctl->dev = &pdev->dev;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (ret)
> +		return -ENODEV;
> +
> +	rza1_pctl->base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(rza1_pctl->base))
> +		return PTR_ERR(rza1_pctl->base);
> +
> +	mutex_init(&rza1_pctl->mutex);
> +
> +	platform_set_drvdata(pdev, rza1_pctl);
> +
> +	rza1_pctl->desc.name	= DRIVER_NAME;
> +	rza1_pctl->desc.pctlops	= &rza1_pinctrl_ops;
> +	rza1_pctl->desc.pmxops	= &rza1_pinmux_ops;
> +	rza1_pctl->desc.owner	= THIS_MODULE;
> +
> +	ret = rza1_pinctrl_register(rza1_pctl);
> +	if (ret)
> +		return ret;
> +
> +	/* register pin control ranges collected while parsing device tree */
> +	for (i = 0; i < rza1_pctl->ngpiochips; i++)
> +		pinctrl_add_gpio_range(rza1_pctl->pctl,
> +				       &rza1_pctl->gpio_ranges[i]);

On a second thought, since I do have a "register" function, I should 
move this loop there.

Thanks
    j

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

* Re: [PATCH 2/7] Documentation: devicetree: bindings: Add RZ/A1 pinctrl binding documentation
  2017-02-20 17:13     ` Jacopo Mondi
  (?)
@ 2017-02-27 19:47     ` Rob Herring
  -1 siblings, 0 replies; 29+ messages in thread
From: Rob Herring @ 2017-02-27 19:47 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: geert+renesas, laurent.pinchart, linus.walleij, mark.rutland,
	linux, linux-renesas-soc, linux-gpio, devicetree

On Mon, Feb 20, 2017 at 06:13:03PM +0100, Jacopo Mondi wrote:
> Add device tree bindings documentation for Renesas RZ/A1 gpio and pin
> controller.

Make the subject prefix: dt-bindings: pinctrl: ...

> 
> Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
> ---
>  .../bindings/pinctrl/renesas,rza1-pinctrl.txt      | 114 +++++++++++++++++++++
>  1 file changed, 114 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pinctrl/renesas,rza1-pinctrl.txt
> 
> diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,rza1-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/renesas,rza1-pinctrl.txt
> new file mode 100644
> index 0000000..1136146
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pinctrl/renesas,rza1-pinctrl.txt
> @@ -0,0 +1,114 @@
> +Renesas RZ/A1 combined Pin and GPIO controller
> +
> +Renesas SoCs of RZ/A1 family feature a combined Pin and GPIO controller
> +hardware controller, named "Ports" in the hardware reference manual.
> +Pin multiplexing and GPIO configuration is performed on a per-pin base

s/base/basis/

> +writing configuration values to per-port register sets.
> +Each "port" features up to 16 pins, each of them configurable for GPIO
> +function (port mode) or in alternate function mode.
> +Up to 8 different alternate function modes exist for each single pin.
> +
> +Pin controller node
> +-------------------
> +
> +Required properties:
> +  - compatible
> +    this shall be "renesas,r7s72100-ports".
> +
> +  - #pinctrl-cells
> +    as defined by pinctrl-bindings.txt, this is the number
> +    of cells (in addition to pin index) required to configure a single pin.
> +    Shall be set to 1.
> +
> +  - reg
> +    address base and length of the memory area where pin controller
> +    hardware is mapped to.
> +
> +Example:
> +Pin controller node for RZ/A1H SoC (r7s72100)
> +
> +pinctrl: pinctrl@fcfe3000 {
> +	compatible = "renesas,r7s72100-ports";
> +
> +	#pinctrl-cells = <1>;
> +
> +	reg = <0xfcfe3000 0x4248>;
> +};
> +
> +Sub-nodes
> +---------
> +
> +The child nodes of the pin controller node describe a pin multiplexing
> +function or a gpio controller alternatively.
> +
> +- Pin multiplexing sub-nodes:
> +  A pin multiplexing sub-node describes how to configure a set of
> +  (or a single) pin in some desired alternate function mode.
> +  A single sub-node may define several pin configurations groups.
> +
> +  Required properties:
> +    - renesas,pins
> +      describes an array of pin multiplexing configurations.
> +      When a pin has to be configured in alternate function mode, use this
> +      property to identify the pin by its global index, and provide its
> +      alternate function configuration description along with it.
> +      When multiple pins are required to be configured as part of the same
> +      alternate function (odds are single-pin alternate functions exist) they
> +      shall be specified as members of the same argument list of a single
> +      "renesas-pins" property.
> +      Helper macros to ease calculating the pin index from its position
> +      (port where it sits on and pin offset), and alternate function
> +      configuration options are provided in pin controller header file at:
> +      include/dt-bindings/pinctrl/r7s72100-pinctrl.h
> +
> +  Example:
> +  A serial communication interface with a TX output pin and a RX input pin.
> +  The RX pin requires input capabilities.
> +
> +  &pinctrl {
> +	scif2_pins: serial2 {
> +		renesas,pins = <PIN(3, 0) 6>,
> +			       <PIN(3, 2) (4 | INPUT_EN)>;
> +	};
> +  }
> +
> +  Pin #0 on port #3 is configured in alternate function #6.
> +  Pin #2 on port #3 is configured in alternate function #4 with input enabled.
> +
> +- GPIO controller sub-nodes:
> +  Each port of r7s72100 pin controller hardware is itself a gpio controller.
> +  Different SoCs have different number of available pins per port, but
> +  generally speaking, each of them can be configured in GPIO ("port") mode
> +  on this hardware.
> +  Describe gpio-controllers using sub-nodes with the following properties.
> +
> +  Required properties:
> +    - gpio-controller
> +      empty property as defined by gpio bindings documentation.
> +    - #gpio-cells
> +      number of cells required to identify and configure a GPIO.
> +      Shall be 2.
> +    - gpio-ranges
> +      Describes a gpio controller specifying its specific pin base, the pin
> +      base in the global pin numbering space, and the number of controlled
> +      pins, as defined by gpio bindings documentation. Refer to this file
> +      for a more detailed description.
> +
> +  Example:
> +  A gpio controller node, controlling 16 pins indexed starting from 0.
> +  The gpio controller base in the global pin indexing space is pin 48, thus
> +  pins [0 - 15] on this controller map to pins [48 - 63] in the global pin
> +  indexing space.
> +
> +  port3: gpio@3 {

Why can't this just be in the parent node?

3 is not valid without a reg prop.

> +	gpio-controller;
> +	#gpio-cells = <2>;
> +	gpio-ranges = <&pinctrl 0 48 16>;
> +  };
> +
> +  A device node willing to use pins controlled by this gpio controller, shall
> +  refer to it as follows:
> +
> +  led1 {
> +	gpios = <&port3 10 GPIO_ACTIVE_LOW>;
> +  };
> -- 
> 2.7.4
> 

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

* RE: Renesas RZ/A1 pin and gpio controller
  2017-02-20 17:13 Renesas RZ/A1 pin and gpio controller Jacopo Mondi
       [not found] ` <1487610788-6939-1-git-send-email-jacopo+renesas-AW8dsiIh9cEdnm+yROfE0A@public.gmane.org>
  2017-02-20 17:13 ` [PATCH 5/7] arm: dts: genmai: Add SCIF2 pin group Jacopo Mondi
@ 2017-03-02 20:16 ` Chris Brandt
  2 siblings, 0 replies; 29+ messages in thread
From: Chris Brandt @ 2017-03-02 20:16 UTC (permalink / raw)
  To: Jacopo Mondi, geert+renesas, laurent.pinchart, linus.walleij,
	robh+dt, mark.rutland, linux
  Cc: linux-renesas-soc, linux-gpio, devicetree

Hi Jacopo,

On Monday, February 20, 2017, Jacopo Mondi wrote:
> Hello,
>    this is the first submission of combined GPIO and pin controller driver
> for Renesas RZ/A1 SoC.
> 
> Compared to my RFC series on the same subject, this new implementation
> supports a single SoC. If more devices with a similar pin controller will
> arrive later, we will consider supporting them through this driver.
> 
> The series adds the driver itself and register the pincontroller in dtsi.
> The pin controller hardware supports 12 ports, each of them is also a gpio
> controller.
> 
> The series makes use of pinctrl and pinmux generic function currently
> available in Linus Walleij's linux-pinctrl.git tree.
> 
> Testing done veryfing functionalities of hardware modules enabled in
> device tree (SCIF2 for serial output, RIIC for accessing an internal
> eeprom chip and user visible leds).
> Gpio have been also verified using a i2c-gpio device in place of the
> native RIIC one to access the same eeprom device.


Functionally, I tested these patches on an RZ/A1H RSK board (after modifying the DT for the RSK vs the GENMAI board).

The following worked fine:
 * SCIF
 * I2C
 * SDHI
 * Ethernet

  (The trick is you have to know what pins need to be set as bi-directional)


I will look over the code and provide feedback separately.

Cheers

Chris

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

* RE: [PATCH 4/7] arm: dts: r7s72100: Add pin controller node
  2017-02-21 10:46     ` jacopo mondi
@ 2017-03-02 20:17       ` Chris Brandt
  2017-03-03 10:08         ` Geert Uytterhoeven
  0 siblings, 1 reply; 29+ messages in thread
From: Chris Brandt @ 2017-03-02 20:17 UTC (permalink / raw)
  To: jacopo mondi, Jacopo Mondi, geert+renesas, laurent.pinchart,
	linus.walleij, robh+dt, mark.rutland, linux
  Cc: linux-renesas-soc, linux-gpio, devicetree

Hi Jacopo,

On Tuesday, February 21, 2017, jacopo mondi wrote:
> > +			gpio-controller;
> > +			#gpio-cells = <2>;
> > +			gpio-ranges = <&pinctrl 0 0 16>;
> 
> Not all ports have 16 pins available.
> This is one of the differences between different RZ/A1 SoC versions
> (RZ/A1H, RZ/A1L etc)
> 
> I'll change the number of pins to the actual available ones on each port
> for r7s72100 (RZ/A1H)

But wait, what if someone wants to use a RZ/A1L???

I don't want to make a separate dtsi file for RZ/A1L.

Is it possible to change the number of port pins in the board dts file?
For example:
  RZ/A1H: P5_0 - P5_10
  RZ/A1L: P5_0 - P5_16

So, in a rza1l-board.dts file I would put:

&port5 {
	gpio-ranges = <&pinctrl 0 80 16>;
}

Will this work?


Chris


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

* Re: [PATCH 4/7] arm: dts: r7s72100: Add pin controller node
  2017-03-02 20:17       ` Chris Brandt
@ 2017-03-03 10:08         ` Geert Uytterhoeven
  2017-03-03 13:24           ` Chris Brandt
  0 siblings, 1 reply; 29+ messages in thread
From: Geert Uytterhoeven @ 2017-03-03 10:08 UTC (permalink / raw)
  To: Chris Brandt
  Cc: jacopo mondi, Jacopo Mondi, geert+renesas, laurent.pinchart,
	linus.walleij, robh+dt, mark.rutland, linux, linux-renesas-soc,
	linux-gpio, devicetree

Hi Chris,

On Thu, Mar 2, 2017 at 9:17 PM, Chris Brandt <Chris.Brandt@renesas.com> wrote:
> On Tuesday, February 21, 2017, jacopo mondi wrote:
>> > +                   gpio-controller;
>> > +                   #gpio-cells = <2>;
>> > +                   gpio-ranges = <&pinctrl 0 0 16>;
>>
>> Not all ports have 16 pins available.
>> This is one of the differences between different RZ/A1 SoC versions
>> (RZ/A1H, RZ/A1L etc)
>>
>> I'll change the number of pins to the actual available ones on each port
>> for r7s72100 (RZ/A1H)
>
> But wait, what if someone wants to use a RZ/A1L???
>
> I don't want to make a separate dtsi file for RZ/A1L.
>
> Is it possible to change the number of port pins in the board dts file?
> For example:
>   RZ/A1H: P5_0 - P5_10
>   RZ/A1L: P5_0 - P5_16

That's 17 pins, not 16?

>
> So, in a rza1l-board.dts file I would put:
>
> &port5 {
>         gpio-ranges = <&pinctrl 0 80 16>;
> }
>
> Will this work?

Yes, overriding should work. But the number of pins is an SoC-property, not
a board-property?

Are the differences between RZ/A1H and RZ/A1L just the number of pins?
If yes, you could use a hierarchical DTS structure:

rza1h-<board>.dts:

    #include "rza1h.dtsi"

    // board specifics here

rza1l-<board>.dts:

    #include "rza1l.dtsi"

    // board specifics here

rza1h.dtsi:

    #include "rza.dtsi"  // r7s72100.dtsi?

    // base SoC overrides
    &port5 {
        gpio-ranges = <&pinctrl 0 80 11>;
    }

rza1l.dtsi:

    #include "rza.dtsi"  // r7s72100.dtsi?

    // base SoC overrides
    &port5 {
        gpio-ranges = <&pinctrl 0 80 16>;
    }

Actual naming of DTS files TBD.
We could also decide to not have rza1h.dtsi, and assume the base dtsi is for
RZ/A1H.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

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

* RE: [PATCH 4/7] arm: dts: r7s72100: Add pin controller node
  2017-03-03 10:08         ` Geert Uytterhoeven
@ 2017-03-03 13:24           ` Chris Brandt
  2017-03-20 13:47             ` jacopo
  0 siblings, 1 reply; 29+ messages in thread
From: Chris Brandt @ 2017-03-03 13:24 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: jacopo mondi, Jacopo Mondi, geert+renesas, laurent.pinchart,
	linus.walleij, robh+dt, mark.rutland, linux, linux-renesas-soc,
	linux-gpio, devicetree

Hi Geert,

On Friday, March 03, 2017, Geert Uytterhoeven wrote:
> > Is it possible to change the number of port pins in the board dts file?
> > For example:
> >   RZ/A1H: P5_0 - P5_10
> >   RZ/A1L: P5_0 - P5_16
> 
> That's 17 pins, not 16?

Oops, I meant P5_15

Looking at the parts, here are the differences:

RZ/A1H    RZ/A1L
------------------
P2_0:15   P2_0:9
P4_0:15   P4_0:7
P5_0:10   P5_0:15
P7_0:15   P7_0:11
P9_0:7    P9_0:5
P10_0:15  none
P11_0:15  none

> > So, in a rza1l-board.dts file I would put:
> >
> > &port5 {
> >         gpio-ranges = <&pinctrl 0 80 16>;
> > }
> >
> > Will this work?
> 
> Yes, overriding should work. But the number of pins is an SoC-property,
> not
> a board-property?

True, but I am trying to figure out how to solve this locally and not make
it an upstream problem.


> Are the differences between RZ/A1H and RZ/A1L just the number of pins?

Yes/No.

Internally, the IP blocks are the same, and located at the same register
addresses, but come out to different port pins due to the RZ/A1L having smaller
packages.

Also, the L has less channels than the H.
For example:
 QSPI: H=2, L=1
  LCD: H=2, L=1
 SCIF: H=8, L=5
  CAN: H=5, L=2

Of course there is some IP that only comes in the H.

This is why I didn't want to associate "names" with the pins in a pfc driver.
I just wanted the board DT to assign a pin to a 'function number'.



> If yes, you could use a hierarchical DTS structure:
> 
> rza1h-<board>.dts:
> 
>     #include "rza1h.dtsi"
> 
>     // board specifics here
> 
> rza1l-<board>.dts:
> 
>     #include "rza1l.dtsi"
> 
>     // board specifics here
> 
> rza1h.dtsi:
> 
>     #include "rza.dtsi"  // r7s72100.dtsi?
> 
>     // base SoC overrides
>     &port5 {
>         gpio-ranges = <&pinctrl 0 80 11>;
>     }
> 
> rza1l.dtsi:
> 
>     #include "rza.dtsi"  // r7s72100.dtsi?
> 
>     // base SoC overrides
>     &port5 {
>         gpio-ranges = <&pinctrl 0 80 16>;
>     }
> 
> Actual naming of DTS files TBD.

OK, so just put the pin differences in the two files. That's a good idea. But,
then that's 2 more files to add upstream.
As the RZ/A series continues, they might keep doing this kind of thing, so I
don't want to get into the habit of adding more and more DT files.

# I wish there was some type of if-else syntax in Device Tree so in the
board file I could just say:

/ {
	model = "RSKRZA1";
	compatible = "renesas,rskrza1", "renesas,r7s72100";

	variant = "rza1l";


> We could also decide to not have rza1h.dtsi, and assume the base dtsi is
> for
> RZ/A1H.

Honestly, I'm fine with RZ/A1H being the flagship upstream SoC since it is a
superset of all the peripherals in RZ/A1M,/A1L,/A1LU,/A1LC. Meaning, this small
difference can be handled in a simple board file addition.

I was thinking I was going to post some DT examples on eLinux.org anyway, so one of
them would just be this RZ/A1L fix.

Cheers

Chris


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

* RE: [PATCH 3/7] arm: dts: dt-bindings: Add Renesas RZ pinctrl header
  2017-02-20 17:13     ` Jacopo Mondi
  (?)
@ 2017-03-09 14:54     ` Chris Brandt
  2017-03-16 14:14       ` jacopo mondi
  -1 siblings, 1 reply; 29+ messages in thread
From: Chris Brandt @ 2017-03-09 14:54 UTC (permalink / raw)
  To: Jacopo Mondi, geert+renesas, laurent.pinchart, linus.walleij,
	robh+dt, mark.rutland, linux
  Cc: linux-renesas-soc, linux-gpio, devicetree

Hi Jacopo,

On Monday, February 20, 2017, Jacopo Mondi wrote:
> 
> Add dt-bindings for Renesas r7s72100 pin controller header file.
> 
> Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
> ---
>  include/dt-bindings/pinctrl/r7s72100-pinctrl.h | 30
> ++++++++++++++++++++++++++
>  1 file changed, 30 insertions(+)
>  create mode 100644 include/dt-bindings/pinctrl/r7s72100-pinctrl.h
> 
> diff --git a/include/dt-bindings/pinctrl/r7s72100-pinctrl.h b/include/dt-
> bindings/pinctrl/r7s72100-pinctrl.h
> new file mode 100644
> index 0000000..24759bf
> --- /dev/null
> +++ b/include/dt-bindings/pinctrl/r7s72100-pinctrl.h
> @@ -0,0 +1,30 @@
> +/*
> + * Defines macros and constants for Renesas RZ/A1 pin controller pin
> + * muxing functions.
> + */
> +#ifndef __DT_BINDINGS_PINCTRL_RENESAS_RZA1_H
> +#define __DT_BINDINGS_PINCTRL_RENESAS_RZA1_H
> +
> +#define RZA1_PINS_PER_PORT	16
> +
> +/* Create the pin index from it's bank and position numbers */
> +#define PIN(b, p)		((b) * RZA1_PINS_PER_PORT + (p))
> +
> +/* Flags to apply to alternate function configuration */
> +/*
> + * Pin needs input buffer enabled.
> + * This applies to pin which alternate function requires input
> capabilities.
> + * Eg: RX pin on a serial interface needs this flag to be set.
> + */
> +#define INPUT_EN		(1 << 3)

This is basically talking about the "Port Input Buffer Control Register"
(PIBCn) which is actually not that important. But, you are also using it
for the special cases where you have to manually define the pin to be either
input or output....but I would just remove INPUT_EN.

For the PIBCn register, just set it automatically if you are going to
use the pin as a GPIO (in or out). I have not really found a case yet where
I had to set this bit for another other than GPIO-input.

I would prefer to see a different define that talks about the pin being bi-directional
which is required for things like I2C, SDHI, etc... and would be directly related
to the "Port Bidirection Control Register" (PBDCn) for each pin.

#define BI_DIR		(1 << 3)


Additionally, according to the RZ/A1 hardware manual:
 "When the output buffer is enabled and the PBDCn.PBDCnm bit is 1, the
  input buffer is enabled regardless of this register setting."

> +
> +/*
> + * Let software drive the pin I/O direction overriding the alternate
> function
> + * configuration.
> + * Some alternate function requires software to force I/O direction of a
> pin,
> + * ovverriding the designated one.
> + * Reference to the HW manual to know when this flag shall be used.
> + */
> +#define SWIO			(1 << 4)

For "software I/O" settings, you were using INPUT_EN to determine input or output.

To make things simple, I would just define:
#define SWIO_IN			(1 << 4)
#define SWIO_OUT			(1 << 5)


So in summary, this is how I think things should look in the DT:

Example of a 'normal' pin (most of the pins).
		/* P3_0 as TxD2; P3_2 as RxD2 */
		renesas,pins = <PIN(3, 0) 6>,
			       <PIN(3, 2) 4>;

Example of pins that need bi-directional specified:
		/* RIIC2: P1_4 as SCL, P1_5 as SDA */
		renesas,pins = <PIN(1, 4) (1 | BI_DIR)>,
			       <PIN(1, 5) (1 | BI_DIR)>;


Example of pins that need software I/O manually specified (because they are
whacky pins) as defined by Table 54.7:

		/* MTU2 TIOC0A as input capture */
		renesas,pins = <PIN(4, 0) (2 | SWIO_IN)>;

		/* MTU2 TIOC0A as output compare */
		renesas,pins = <PIN(4, 0) (2 | SWIO_OUT)>;

		/* LVDS */
		renesas,pins = <PIN(5, 0) (1 | SWIO_IN)>; /* the spec says to put these as inputs */

		/* SSI Audio */
		renesas,pins = <PIN(2, 11) (4 | SWIO_OUT)>;

		/* Watchdog Overflow */
		renesas,pins = <PIN(3, 7) (8 | SWIO_OUT)>;



Chris


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

* RE: [PATCH 1/7] pinctrl: Renesas RZ/A1 pin and gpio controller
  2017-02-20 17:13     ` Jacopo Mondi
  (?)
  (?)
@ 2017-03-09 14:55     ` Chris Brandt
  2017-03-16 14:04       ` jacopo mondi
  -1 siblings, 1 reply; 29+ messages in thread
From: Chris Brandt @ 2017-03-09 14:55 UTC (permalink / raw)
  To: Jacopo Mondi, geert+renesas, laurent.pinchart, linus.walleij,
	robh+dt, mark.rutland, linux
  Cc: linux-renesas-soc, linux-gpio, devicetree

Hi Jacopo,

On Monday, February 20, 2017, Jacopo Mondi wrote:
> 
> Add combined gpio and pin controller driver for Renesas RZ/A1
> r7s72100 SoC.
> 
> Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
> ---
>  drivers/pinctrl/Kconfig        |   10 +
>  drivers/pinctrl/Makefile       |    1 +
>  drivers/pinctrl/pinctrl-rza1.c | 1026
> ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 1037 insertions(+)
>  create mode 100644 drivers/pinctrl/pinctrl-rza1.c
> 
> diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
> index 8f8c2af..61310ac 100644
> --- a/drivers/pinctrl/Kconfig
> +++ b/drivers/pinctrl/Kconfig
> @@ -163,6 +163,16 @@ config PINCTRL_ROCKCHIP
>  	select GENERIC_IRQ_CHIP
>  	select MFD_SYSCON
> 
> +config PINCTRL_RZA1
> +	bool "Renesas r7s72100 RZ/A1 gpio and pinctrl driver"

You can drop the "r7s72100" and just say RZ/A1.



> +/**
> + * rza1_pin_set_direction() - set I/O direction on a pin in port mode
> + *
> + * When running in output port mode keep PBDC enabled to allow reading
> the
> + * pin value from PPR.
> + * When in alternate mode disable that (if not explicitly required) not
> to
> + * interfere with the alternate function mode.
> + *
> + * @port: port where pin sits on
> + * @offset: pin offset
> + * @input: input enable/disable flag
> + */
> +static inline void rza1_pin_set_direction(struct rza1_port *port,
> +					  unsigned int offset,
> +					  bool input)
> +{
> +	spin_lock(&port->lock);
> +	if (input)
> +		rza1_set_bit(port, PIBC_REG, offset, 1);
> +	else {
> +		rza1_set_bit(port, PM_REG, offset, 0);
> +		rza1_set_bit(port, PBDC_REG, offset, 1);
> +	}
> +	spin_unlock(&port->lock);

When input==true, you only set PIBC_REG. Otherwise you only set PM_REG and PBDC_REG. This would imply that this function will only ever get called once for a pin and never get called a second time with a different direction...meaning it would not really change a pin from output to input. I would assume that you would need to change this function to set those 3 registers either one way or the other.

I would suggest:
   PIBC_REG = 1 /* always gets set for GPIO mode */
 input:
   PM_REG = 1
   PBDC_REG = 0
output:
   PM_REG = 0
   PBDC_REG = 1



> +/**
> + * rza1_alternate_function_conf() - configure pin in alternate function
> mode
> + *
> + * @pinctrl: RZ/A1 pin controller device
> + * @pin_conf: single pin configuration descriptor
> + */
> +static int rza1_alternate_function_conf(struct rza1_pinctrl *rza1_pctl,
> +					struct rza1_pin_conf *pin_conf)
> +{
> +	unsigned int offset = pin_conf->offset;
> +	struct rza1_port *port = &rza1_pctl->ports[pin_conf->port];
> +	u8 mux_mode = (pin_conf->mux_conf - 1) & MUX_FUNC_MASK;
> +	u8 mux_conf = pin_conf->mux_conf >> MUX_FUNC_OFFS;
> +	bool swio_en = !!(mux_conf & MUX_CONF_SWIO);
> +	bool input_en = !!(mux_conf & MUX_CONF_INPUT_ENABLE);
> +
> +	rza1_pin_reset(port, offset);
> +
> +	/*
> +	 * When configuring pin with Software Controlled IO mode in
> alternate
> +	 * mode, do not enable bi-directional control to avoid driving Pn
> +	 * value to the pin input.
> +	 * When working in direct IO mode (aka alternate function drives the
> +	 * pin direction), enable bi-directional control for input pins in
> +	 * order to enable the pin's input buffer as a consequence.
> +	 */
> +	if ((!swio_en && input_en) || (swio_en && !input_en))
> +		rza1_set_bit(port, PBDC_REG, offset, 1);


Maybe just set PBDC_REG at the end of the function with everything else.
See below...



> +
> +	/*
> +	 * Enable alternate function mode and select it.
> +	 *
> +	 * ----------------------------------------------------
> +	 * Alternate mode selection table:
> +	 *
> +	 * PMC	PFC	PFCE	PFCAE	mux_mode
> +	 * 1	0	0	0	0
> +	 * 1	1	0	0	1
> +	 * 1	0	1	0	2
> +	 * 1	1	1	0	3
> +	 * 1	0	0	1	4
> +	 * 1	1	0	1	5
> +	 * 1	0	1	1	6
> +	 * 1	1	1	1	7
> +	 * ----------------------------------------------------
> +	 */
> +	rza1_set_bit(port, PFC_REG, offset, mux_mode & MUX_FUNC_PFC_MASK);
> +	rza1_set_bit(port, PFCE_REG, offset, mux_mode & MUX_FUNC_PFCE_MASK);
> +	rza1_set_bit(port, PFCEA_REG, offset, mux_mode &
> MUX_FUNC_PFCEA_MASK);
> +
> +	/*
> +	 * All alternate functions except a few (4) need PIPCn = 1.
> +	 * If PIPCn has to stay disabled (SW IO mode), configure PMn
> according
> +	 * to I/O direction specified by pin configuration -after- PMC has
> been
> +	 * set to one.
> +	 */
> +	if (!swio_en)
> +		rza1_set_bit(port, PIPC_REG, offset, 1);
> +
> +	rza1_set_bit(port, PMC_REG, offset, 1);
> +
> +	if (swio_en)
> +		rza1_set_bit(port, PM_REG, offset, input_en);


I would suggest something like this:

	if (bidir)
		rza1_set_bit(port, PBDC_REG, offset, 1);
	else {
		rza1_set_bit(port, PBDC_REG, offset, 0);
		rza1_set_bit(port, PM_REG, offset, swio_in);
	}

	rza1_set_bit(port, PMC_REG, offset, 1);


> +
> +	return 0;
> +}




Chris

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

* Re: [PATCH 1/7] pinctrl: Renesas RZ/A1 pin and gpio controller
  2017-03-09 14:55     ` Chris Brandt
@ 2017-03-16 14:04       ` jacopo mondi
  2017-03-16 14:43         ` Chris Brandt
  0 siblings, 1 reply; 29+ messages in thread
From: jacopo mondi @ 2017-03-16 14:04 UTC (permalink / raw)
  To: Chris Brandt, Jacopo Mondi, geert+renesas, laurent.pinchart,
	linus.walleij, robh+dt, mark.rutland, linux
  Cc: linux-renesas-soc, linux-gpio, devicetree

Hi Chris,
    thanks for looking into this...

On 09/03/2017 15:55, Chris Brandt wrote:
> Hi Jacopo,
>
> On Monday, February 20, 2017, Jacopo Mondi wrote:
>>
>> Add combined gpio and pin controller driver for Renesas RZ/A1
>> r7s72100 SoC.
>>
>> Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
>> ---
>>  drivers/pinctrl/Kconfig        |   10 +
>>  drivers/pinctrl/Makefile       |    1 +
>>  drivers/pinctrl/pinctrl-rza1.c | 1026
>> ++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 1037 insertions(+)
>>  create mode 100644 drivers/pinctrl/pinctrl-rza1.c
>>
>> diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
>> index 8f8c2af..61310ac 100644
>> --- a/drivers/pinctrl/Kconfig
>> +++ b/drivers/pinctrl/Kconfig
>> @@ -163,6 +163,16 @@ config PINCTRL_ROCKCHIP
>>  	select GENERIC_IRQ_CHIP
>>  	select MFD_SYSCON
>>
>> +config PINCTRL_RZA1
>> +	bool "Renesas r7s72100 RZ/A1 gpio and pinctrl driver"
>
> You can drop the "r7s72100" and just say RZ/A1.
>
>
>
>> +/**
>> + * rza1_pin_set_direction() - set I/O direction on a pin in port mode
>> + *
>> + * When running in output port mode keep PBDC enabled to allow reading
>> the
>> + * pin value from PPR.
>> + * When in alternate mode disable that (if not explicitly required) not
>> to
>> + * interfere with the alternate function mode.
>> + *
>> + * @port: port where pin sits on
>> + * @offset: pin offset
>> + * @input: input enable/disable flag
>> + */
>> +static inline void rza1_pin_set_direction(struct rza1_port *port,
>> +					  unsigned int offset,
>> +					  bool input)
>> +{
>> +	spin_lock(&port->lock);
>> +	if (input)
>> +		rza1_set_bit(port, PIBC_REG, offset, 1);
>> +	else {
>> +		rza1_set_bit(port, PM_REG, offset, 0);
>> +		rza1_set_bit(port, PBDC_REG, offset, 1);
>> +	}
>> +	spin_unlock(&port->lock);
>
> When input==true, you only set PIBC_REG. Otherwise you only set PM_REG and PBDC_REG. This would imply that this function will only ever get called once for a pin and never get called a second time with a different direction...meaning it would not really change a pin from output to input. I would assume that you would need to change this function to set those 3 registers either one way or the other.
>
> I would suggest:
>    PIBC_REG = 1 /* always gets set for GPIO mode */
>  input:
>    PM_REG = 1
>    PBDC_REG = 0
> output:
>    PM_REG = 0
>    PBDC_REG = 1
>

I assumed "set_direction()" to always be called after a "request()", so 
that the pin is always in reset state.
This is obviously not true, so I'm going to fix this as you suggested.
I'm just wondering why we should keep input buffer enabled even if we're 
running in output mode. This seems to be "safe" according to TRM but I'm 
a bit afraid of unexpected consequences (am I too paranoid?)

>
>
>> +/**
>> + * rza1_alternate_function_conf() - configure pin in alternate function
>> mode
>> + *
>> + * @pinctrl: RZ/A1 pin controller device
>> + * @pin_conf: single pin configuration descriptor
>> + */
>> +static int rza1_alternate_function_conf(struct rza1_pinctrl *rza1_pctl,
>> +					struct rza1_pin_conf *pin_conf)
>> +{
>> +	unsigned int offset = pin_conf->offset;
>> +	struct rza1_port *port = &rza1_pctl->ports[pin_conf->port];
>> +	u8 mux_mode = (pin_conf->mux_conf - 1) & MUX_FUNC_MASK;
>> +	u8 mux_conf = pin_conf->mux_conf >> MUX_FUNC_OFFS;
>> +	bool swio_en = !!(mux_conf & MUX_CONF_SWIO);
>> +	bool input_en = !!(mux_conf & MUX_CONF_INPUT_ENABLE);
>> +
>> +	rza1_pin_reset(port, offset);
>> +
>> +	/*
>> +	 * When configuring pin with Software Controlled IO mode in
>> alternate
>> +	 * mode, do not enable bi-directional control to avoid driving Pn
>> +	 * value to the pin input.
>> +	 * When working in direct IO mode (aka alternate function drives the
>> +	 * pin direction), enable bi-directional control for input pins in
>> +	 * order to enable the pin's input buffer as a consequence.
>> +	 */
>> +	if ((!swio_en && input_en) || (swio_en && !input_en))
>> +		rza1_set_bit(port, PBDC_REG, offset, 1);
>
>
> Maybe just set PBDC_REG at the end of the function with everything else.
> See below...
>

Let me reply below to both these comments...

>
>
>> +
>> +	/*
>> +	 * Enable alternate function mode and select it.
>> +	 *
>> +	 * ----------------------------------------------------
>> +	 * Alternate mode selection table:
>> +	 *
>> +	 * PMC	PFC	PFCE	PFCAE	mux_mode
>> +	 * 1	0	0	0	0
>> +	 * 1	1	0	0	1
>> +	 * 1	0	1	0	2
>> +	 * 1	1	1	0	3
>> +	 * 1	0	0	1	4
>> +	 * 1	1	0	1	5
>> +	 * 1	0	1	1	6
>> +	 * 1	1	1	1	7
>> +	 * ----------------------------------------------------
>> +	 */
>> +	rza1_set_bit(port, PFC_REG, offset, mux_mode & MUX_FUNC_PFC_MASK);
>> +	rza1_set_bit(port, PFCE_REG, offset, mux_mode & MUX_FUNC_PFCE_MASK);
>> +	rza1_set_bit(port, PFCEA_REG, offset, mux_mode &
>> MUX_FUNC_PFCEA_MASK);
>> +
>> +	/*
>> +	 * All alternate functions except a few (4) need PIPCn = 1.
>> +	 * If PIPCn has to stay disabled (SW IO mode), configure PMn
>> according
>> +	 * to I/O direction specified by pin configuration -after- PMC has
>> been
>> +	 * set to one.
>> +	 */
>> +	if (!swio_en)
>> +		rza1_set_bit(port, PIPC_REG, offset, 1);
>> +
>> +	rza1_set_bit(port, PMC_REG, offset, 1);
>> +
>> +	if (swio_en)
>> +		rza1_set_bit(port, PM_REG, offset, input_en);
>
>
> I would suggest something like this:
>
> 	if (bidir)
> 		rza1_set_bit(port, PBDC_REG, offset, 1);
> 	else {
> 		rza1_set_bit(port, PBDC_REG, offset, 0);
> 		rza1_set_bit(port, PM_REG, offset, swio_in);
> 	}
>
> 	rza1_set_bit(port, PMC_REG, offset, 1);
>
>

This looks nicer, for sure, but from my testing I found out that the 
sequence reported in section 54.19-c of TRM has to be carefully 
respected, particularly setting PM after PMC (and iirc setting PBDC 
before PFC*)
Am I wrong? I will give your suggestion spin anyway...

This apart, you suggestion is tied to your comment on [2/7] on replacing 
INPUT_EN with BIDIR and introduce SWIO_IN and SWIO_OUT, which I mostly 
agree on (I'll comment on that as well).

A sort of middle-ground to get rid of horrible conditions like
"if ((!swio_en && input_en) || (swio_en && !input_en))"
which requires a 7 lines comments to be explained and I still found 
obscure after a month I was not looking at it, would be making BIDIR and 
SWIO_[IN|OUT] exclusive, as if a pin is set to be SWIO it already has 
direction specified, and if it is said to be BIDIR, it means its 
direction is decided by the alternate function, not by software.
Does this fly for you? Do you see cases where those flags may have to be 
specified together?
If not, it would simplify this routine for sure...

Thanks
    j


>> +
>> +	return 0;
>> +}
>
>
>
>
> Chris
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>


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

* Re: [PATCH 3/7] arm: dts: dt-bindings: Add Renesas RZ pinctrl header
  2017-03-09 14:54     ` Chris Brandt
@ 2017-03-16 14:14       ` jacopo mondi
  2017-03-16 15:03         ` Chris Brandt
  0 siblings, 1 reply; 29+ messages in thread
From: jacopo mondi @ 2017-03-16 14:14 UTC (permalink / raw)
  To: Chris Brandt, Jacopo Mondi, geert+renesas, laurent.pinchart,
	linus.walleij, robh+dt, mark.rutland, linux
  Cc: linux-renesas-soc, linux-gpio, devicetree

Hi Chris,

On 09/03/2017 15:54, Chris Brandt wrote:
> Hi Jacopo,
>
> On Monday, February 20, 2017, Jacopo Mondi wrote:
>>
>> Add dt-bindings for Renesas r7s72100 pin controller header file.
>>
>> Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
>> ---
>>  include/dt-bindings/pinctrl/r7s72100-pinctrl.h | 30
>> ++++++++++++++++++++++++++
>>  1 file changed, 30 insertions(+)
>>  create mode 100644 include/dt-bindings/pinctrl/r7s72100-pinctrl.h
>>
>> diff --git a/include/dt-bindings/pinctrl/r7s72100-pinctrl.h b/include/dt-
>> bindings/pinctrl/r7s72100-pinctrl.h
>> new file mode 100644
>> index 0000000..24759bf
>> --- /dev/null
>> +++ b/include/dt-bindings/pinctrl/r7s72100-pinctrl.h
>> @@ -0,0 +1,30 @@
>> +/*
>> + * Defines macros and constants for Renesas RZ/A1 pin controller pin
>> + * muxing functions.
>> + */
>> +#ifndef __DT_BINDINGS_PINCTRL_RENESAS_RZA1_H
>> +#define __DT_BINDINGS_PINCTRL_RENESAS_RZA1_H
>> +
>> +#define RZA1_PINS_PER_PORT	16
>> +
>> +/* Create the pin index from it's bank and position numbers */
>> +#define PIN(b, p)		((b) * RZA1_PINS_PER_PORT + (p))
>> +
>> +/* Flags to apply to alternate function configuration */
>> +/*
>> + * Pin needs input buffer enabled.
>> + * This applies to pin which alternate function requires input
>> capabilities.
>> + * Eg: RX pin on a serial interface needs this flag to be set.
>> + */
>> +#define INPUT_EN		(1 << 3)
>
> This is basically talking about the "Port Input Buffer Control Register"
> (PIBCn) which is actually not that important. But, you are also using it
> for the special cases where you have to manually define the pin to be either
> input or output....but I would just remove INPUT_EN.
>
> For the PIBCn register, just set it automatically if you are going to
> use the pin as a GPIO (in or out). I have not really found a case yet where
> I had to set this bit for another other than GPIO-input.
>
> I would prefer to see a different define that talks about the pin being bi-directional
> which is required for things like I2C, SDHI, etc... and would be directly related
> to the "Port Bidirection Control Register" (PBDCn) for each pin.
>
> #define BI_DIR		(1 << 3)
>
>
> Additionally, according to the RZ/A1 hardware manual:
>  "When the output buffer is enabled and the PBDCn.PBDCnm bit is 1, the
>   input buffer is enabled regardless of this register setting."
>

Yes, I used INPUT_EN to drive PBDC..
My assumption was that "users" would have had to decide when a pin was 
acting as input, when describing it in dts, rather than having to deal 
with the TRM and learn what bidirectional control is and is consequences 
(particularly, that it enables the input buffer).

But since I guess this whole driver assumes more detailed knowledge on 
the hardware compared to group-based ones, I think using BI_DIR is fine here

>> +
>> +/*
>> + * Let software drive the pin I/O direction overriding the alternate
>> function
>> + * configuration.
>> + * Some alternate function requires software to force I/O direction of a
>> pin,
>> + * ovverriding the designated one.
>> + * Reference to the HW manual to know when this flag shall be used.
>> + */
>> +#define SWIO			(1 << 4)
>
> For "software I/O" settings, you were using INPUT_EN to determine input or output.
>
> To make things simple, I would just define:
> #define SWIO_IN			(1 << 4)
> #define SWIO_OUT			(1 << 5)
>
>
> So in summary, this is how I think things should look in the DT:
>
> Example of a 'normal' pin (most of the pins).
> 		/* P3_0 as TxD2; P3_2 as RxD2 */
> 		renesas,pins = <PIN(3, 0) 6>,
> 			       <PIN(3, 2) 4>;

Just to make sure I'm following you: why RxD2 (P3_2) is not marked as 
BI_DIR? I would have expected to have the flag specified here, as it 
requires PIBC enabled (and as you said, BI_DIR drives PBDC that enables 
PIBC consequentially)

>
> Example of pins that need bi-directional specified:
> 		/* RIIC2: P1_4 as SCL, P1_5 as SDA */
> 		renesas,pins = <PIN(1, 4) (1 | BI_DIR)>,
> 			       <PIN(1, 5) (1 | BI_DIR)>;
>

nice

>
> Example of pins that need software I/O manually specified (because they are
> whacky pins) as defined by Table 54.7:
>
> 		/* MTU2 TIOC0A as input capture */
> 		renesas,pins = <PIN(4, 0) (2 | SWIO_IN)>;
>
> 		/* MTU2 TIOC0A as output compare */
> 		renesas,pins = <PIN(4, 0) (2 | SWIO_OUT)>;
>
> 		/* LVDS */
> 		renesas,pins = <PIN(5, 0) (1 | SWIO_IN)>; /* the spec says to put these as inputs */
>
> 		/* SSI Audio */
> 		renesas,pins = <PIN(2, 11) (4 | SWIO_OUT)>;
>
> 		/* Watchdog Overflow */
> 		renesas,pins = <PIN(3, 7) (8 | SWIO_OUT)>;
>
>

Makes total sense, and will got for it.

Thanks
    j


>
> Chris
>

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

* RE: [PATCH 1/7] pinctrl: Renesas RZ/A1 pin and gpio controller
  2017-03-16 14:04       ` jacopo mondi
@ 2017-03-16 14:43         ` Chris Brandt
  0 siblings, 0 replies; 29+ messages in thread
From: Chris Brandt @ 2017-03-16 14:43 UTC (permalink / raw)
  To: jacopo mondi, Jacopo Mondi, geert+renesas, laurent.pinchart,
	linus.walleij, robh+dt, mark.rutland, linux
  Cc: linux-renesas-soc, linux-gpio, devicetree

Hi Jacopo,

> > I would suggest:
> >    PIBC_REG = 1 /* always gets set for GPIO mode */
> >  input:
> >    PM_REG = 1
> >    PBDC_REG = 0
> > output:
> >    PM_REG = 0
> >    PBDC_REG = 1
> >
> 
> I assumed "set_direction()" to always be called after a "request()", so
> that the pin is always in reset state.
> This is obviously not true, so I'm going to fix this as you suggested.
> I'm just wondering why we should keep input buffer enabled even if we're
> running in output mode. This seems to be "safe" according to TRM but I'm a
> bit afraid of unexpected consequences (am I too paranoid?)

In the hardware manual, look at "Table 54.4 PPRnm Read Values"

When PM_REG is '0', the input buffer value (PIBC_REG) is don't care (X)



> > I would suggest something like this:
> >
> > 	if (bidir)
> > 		rza1_set_bit(port, PBDC_REG, offset, 1);
> > 	else {
> > 		rza1_set_bit(port, PBDC_REG, offset, 0);
> > 		rza1_set_bit(port, PM_REG, offset, swio_in);
> > 	}
> >
> > 	rza1_set_bit(port, PMC_REG, offset, 1);
> >
> >
> 
> This looks nicer, for sure, but from my testing I found out that the
> sequence reported in section 54.19-c of TRM has to be carefully respected,
> particularly setting PM after PMC (and iirc setting PBDC before PFC*) Am I
> wrong? I will give your suggestion spin anyway...

I admit, I didn't really look at the suggested flow that the manual said.
I just want off the fact that PMC_REG was the last thing being set, so all
the other registers were irrelevant until that point.

However, you can change the order if you like, as longs as the register
settings still end up the same way as I outlined.


> This apart, you suggestion is tied to your comment on [2/7] on replacing
> INPUT_EN with BIDIR and introduce SWIO_IN and SWIO_OUT, which I mostly
> agree on (I'll comment on that as well).
> 
> A sort of middle-ground to get rid of horrible conditions like "if
> ((!swio_en && input_en) || (swio_en && !input_en))"
> which requires a 7 lines comments to be explained and I still found
> obscure after a month I was not looking at it, would be making BIDIR and
> SWIO_[IN|OUT] exclusive, as if a pin is set to be SWIO it already has
> direction specified, and if it is said to be BIDIR, it means its direction
> is decided by the alternate function, not by software.
> Does this fly for you?

Yes, my suggestion is to make BIDIR and SWIO_[IN|OUT] exclusive in the DT. You
only choose one (or nothing). You can specify that in the DT bindings document.

> Do you see cases where those flags may have to be
> specified together?

There should not be case. Actually...when I went through this, I think the HW manual
prohibits this anyway...or rather one cancels the other....but I can't remember which.
But, I did spend a good amount of time re-reading the chapter when I was reviewing
your code.


Thank you,
Chris


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

* RE: [PATCH 3/7] arm: dts: dt-bindings: Add Renesas RZ pinctrl header
  2017-03-16 14:14       ` jacopo mondi
@ 2017-03-16 15:03         ` Chris Brandt
  0 siblings, 0 replies; 29+ messages in thread
From: Chris Brandt @ 2017-03-16 15:03 UTC (permalink / raw)
  To: jacopo mondi, Jacopo Mondi, geert+renesas, laurent.pinchart,
	linus.walleij, robh+dt, mark.rutland, linux
  Cc: linux-renesas-soc, linux-gpio, devicetree

Hi Jacopo,

> > Additionally, according to the RZ/A1 hardware manual:
> >  "When the output buffer is enabled and the PBDCn.PBDCnm bit is 1, the
> >   input buffer is enabled regardless of this register setting."
> >
> 
> Yes, I used INPUT_EN to drive PBDC..
> My assumption was that "users" would have had to decide when a pin was
> acting as input, when describing it in dts, rather than having to deal
> with the TRM and learn what bidirectional control is and is consequences
> (particularly, that it enables the input buffer).
> 
> But since I guess this whole driver assumes more detailed knowledge on the
> hardware compared to group-based ones, I think using BI_DIR is fine here

The reality is, I will be providing DT examples and people will just follow
them like they copy/paste the code from my rskrza1-board.c file today.
Of course they still have to look up the 'alternative function' number in the
Hardware manual, but that's in an easy to read table.



> > So in summary, this is how I think things should look in the DT:
> >
> > Example of a 'normal' pin (most of the pins).
> > 		/* P3_0 as TxD2; P3_2 as RxD2 */
> > 		renesas,pins = <PIN(3, 0) 6>,
> > 			       <PIN(3, 2) 4>;
> 
> Just to make sure I'm following you: why RxD2 (P3_2) is not marked as
> BI_DIR?

Because it doesn't have to be. The pin controller itself knows how to set it up
itself as soon as you set the PIPC.

> I would have expected to have the flag specified here, as it
> requires PIBC enabled (and as you said, BI_DIR drives PBDC that enables
> PIBC consequentially)

PIBC (Port Input Buffer Control) is only valid when you are in GPIO input port
mode (PMCn.PMCnm = 0 and PMn.PMnm = 1).


The reality is, it would be nice if the controller could magically know how to
set all the pins direction, buffers and such depending on their function, but
there were some that needed an extra signals to be manually set (whether it makes
sense or not). I guess that's the consequence of mixing-and-matching IP from
different product lines. Oh well, we just fix it all in software, right?  ;)

I'd rather this than the PFC that's in the R-Car....which I think is the result
of trying to make it smarter and just ended up making it more complicated.


Cheers


Chris

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

* Re: [PATCH 4/7] arm: dts: r7s72100: Add pin controller node
  2017-03-03 13:24           ` Chris Brandt
@ 2017-03-20 13:47             ` jacopo
  2017-03-20 15:17               ` Chris Brandt
  0 siblings, 1 reply; 29+ messages in thread
From: jacopo @ 2017-03-20 13:47 UTC (permalink / raw)
  To: Chris Brandt
  Cc: Geert Uytterhoeven, Jacopo Mondi, geert+renesas,
	laurent.pinchart, linus.walleij, robh+dt, mark.rutland, linux,
	linux-renesas-soc, linux-gpio, devicetree

Hi Chris, Geert,

On Fri, Mar 03, 2017 at 01:24:51PM +0000, Chris Brandt wrote:
> Hi Geert,
> 
> On Friday, March 03, 2017, Geert Uytterhoeven wrote:
> > > Is it possible to change the number of port pins in the board dts file?
> > > For example:
> > >   RZ/A1H: P5_0 - P5_10
> > >   RZ/A1L: P5_0 - P5_16
> > 
> > That's 17 pins, not 16?
> 
> Oops, I meant P5_15
> 
> Looking at the parts, here are the differences:
> 
> RZ/A1H    RZ/A1L
> ------------------
> P2_0:15   P2_0:9
> P4_0:15   P4_0:7
> P5_0:10   P5_0:15
> P7_0:15   P7_0:11
> P9_0:7    P9_0:5
> P10_0:15  none
> P11_0:15  none
> 
> > > So, in a rza1l-board.dts file I would put:
> > >
> > > &port5 {
> > >         gpio-ranges = <&pinctrl 0 80 16>;
> > > }
> > >
> > > Will this work?
> > 
> > Yes, overriding should work. But the number of pins is an SoC-property,
> > not
> > a board-property?
> 
> True, but I am trying to figure out how to solve this locally and not make
> it an upstream problem.
> 
> 
> > Are the differences between RZ/A1H and RZ/A1L just the number of pins?
> 
> Yes/No.
> 
> Internally, the IP blocks are the same, and located at the same register
> addresses, but come out to different port pins due to the RZ/A1L having smaller
> packages.
> 
> Also, the L has less channels than the H.
> For example:
>  QSPI: H=2, L=1
>   LCD: H=2, L=1
>  SCIF: H=8, L=5
>   CAN: H=5, L=2
> 
> Of course there is some IP that only comes in the H.
> 
> This is why I didn't want to associate "names" with the pins in a pfc driver.
> I just wanted the board DT to assign a pin to a 'function number'.
> 
> 
> 
> > If yes, you could use a hierarchical DTS structure:
> > 
> > rza1h-<board>.dts:
> > 
> >     #include "rza1h.dtsi"
> > 
> >     // board specifics here
> > 
> > rza1l-<board>.dts:
> > 
> >     #include "rza1l.dtsi"
> > 
> >     // board specifics here
> > 
> > rza1h.dtsi:
> > 
> >     #include "rza.dtsi"  // r7s72100.dtsi?
> > 
> >     // base SoC overrides
> >     &port5 {
> >         gpio-ranges = <&pinctrl 0 80 11>;
> >     }
> > 
> > rza1l.dtsi:
> > 
> >     #include "rza.dtsi"  // r7s72100.dtsi?
> > 
> >     // base SoC overrides
> >     &port5 {
> >         gpio-ranges = <&pinctrl 0 80 16>;
> >     }
> > 
> > Actual naming of DTS files TBD.
> 
> OK, so just put the pin differences in the two files. That's a good idea. But,
> then that's 2 more files to add upstream.
> As the RZ/A series continues, they might keep doing this kind of thing, so I
> don't want to get into the habit of adding more and more DT files.
> 
> # I wish there was some type of if-else syntax in Device Tree so in the
> board file I could just say:
> 
> / {
> 	model = "RSKRZA1";
> 	compatible = "renesas,rskrza1", "renesas,r7s72100";
> 
> 	variant = "rza1l";
> 
> 
> > We could also decide to not have rza1h.dtsi, and assume the base dtsi is
> > for
> > RZ/A1H.
> 
> Honestly, I'm fine with RZ/A1H being the flagship upstream SoC since it is a
> superset of all the peripherals in RZ/A1M,/A1L,/A1LU,/A1LC. Meaning, this small
> difference can be handled in a simple board file addition.
> 
> I was thinking I was going to post some DT examples on eLinux.org anyway, so one of
> them would just be this RZ/A1L fix.
> 

If we do all agree on having RZ/A1H upstream and let differences
between SoCs to be handled in the BSP/downstream board files, I'll send
v2 targeting that specific SoC only

Thanks
   j

> Cheers
> 
> Chris
> 

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

* RE: [PATCH 4/7] arm: dts: r7s72100: Add pin controller node
  2017-03-20 13:47             ` jacopo
@ 2017-03-20 15:17               ` Chris Brandt
  0 siblings, 0 replies; 29+ messages in thread
From: Chris Brandt @ 2017-03-20 15:17 UTC (permalink / raw)
  To: jacopo
  Cc: Geert Uytterhoeven, Jacopo Mondi, geert+renesas,
	laurent.pinchart, linus.walleij, robh+dt, mark.rutland, linux,
	linux-renesas-soc, linux-gpio, devicetree

Hi Jacopo,

Monday, March 20, 2017, jacopo wrote:
> > I was thinking I was going to post some DT examples on eLinux.org
> > anyway, so one of them would just be this RZ/A1L fix.
> >
> 
> If we do all agree on having RZ/A1H upstream and let differences between
> SoCs to be handled in the BSP/downstream board files, I'll send
> v2 targeting that specific SoC only


I'm fine with that.

      ...of course since it was my suggestion ;)


Chris


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

end of thread, other threads:[~2017-03-20 15:17 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-02-20 17:13 Renesas RZ/A1 pin and gpio controller Jacopo Mondi
     [not found] ` <1487610788-6939-1-git-send-email-jacopo+renesas-AW8dsiIh9cEdnm+yROfE0A@public.gmane.org>
2017-02-20 17:13   ` [PATCH 1/7] pinctrl: " Jacopo Mondi
2017-02-20 17:13     ` Jacopo Mondi
2017-02-21 10:49     ` jacopo mondi
2017-03-09 14:55     ` Chris Brandt
2017-03-16 14:04       ` jacopo mondi
2017-03-16 14:43         ` Chris Brandt
2017-02-20 17:13   ` [PATCH 2/7] Documentation: devicetree: bindings: Add RZ/A1 pinctrl binding documentation Jacopo Mondi
2017-02-20 17:13     ` Jacopo Mondi
2017-02-27 19:47     ` Rob Herring
2017-02-20 17:13   ` [PATCH 3/7] arm: dts: dt-bindings: Add Renesas RZ pinctrl header Jacopo Mondi
2017-02-20 17:13     ` Jacopo Mondi
2017-03-09 14:54     ` Chris Brandt
2017-03-16 14:14       ` jacopo mondi
2017-03-16 15:03         ` Chris Brandt
2017-02-20 17:13   ` [PATCH 4/7] arm: dts: r7s72100: Add pin controller node Jacopo Mondi
2017-02-20 17:13     ` Jacopo Mondi
2017-02-21 10:46     ` jacopo mondi
2017-03-02 20:17       ` Chris Brandt
2017-03-03 10:08         ` Geert Uytterhoeven
2017-03-03 13:24           ` Chris Brandt
2017-03-20 13:47             ` jacopo
2017-03-20 15:17               ` Chris Brandt
2017-02-20 17:13   ` [PATCH 6/7] arm: dts: genmai: Add RIIC2 pin group Jacopo Mondi
2017-02-20 17:13     ` Jacopo Mondi
2017-02-20 17:13   ` [PATCH 7/7] arm: dts: genmai: Add user led device nodes Jacopo Mondi
2017-02-20 17:13     ` Jacopo Mondi
2017-02-20 17:13 ` [PATCH 5/7] arm: dts: genmai: Add SCIF2 pin group Jacopo Mondi
2017-03-02 20:16 ` Renesas RZ/A1 pin and gpio controller Chris Brandt

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.