diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 8f8c2af..6d72e58 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -294,6 +294,7 @@ source "drivers/pinctrl/mvebu/Kconfig"
 source "drivers/pinctrl/nomadik/Kconfig"
 source "drivers/pinctrl/pxa/Kconfig"
 source "drivers/pinctrl/qcom/Kconfig"
+source "drivers/pinctrl/rz-pfc/Kconfig"
 source "drivers/pinctrl/samsung/Kconfig"
 source "drivers/pinctrl/sh-pfc/Kconfig"
 source "drivers/pinctrl/spear/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index a251f43..96e7ece 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -48,6 +48,7 @@ obj-$(CONFIG_PINCTRL_MVEBU)	+= mvebu/
 obj-y				+= nomadik/
 obj-$(CONFIG_PINCTRL_PXA)	+= pxa/
 obj-$(CONFIG_ARCH_QCOM)		+= qcom/
+obj-$(CONFIG_PINCTRL_RZ_PINCTRL)	+= rz-pfc/
 obj-$(CONFIG_PINCTRL_SAMSUNG)	+= samsung/
 obj-$(CONFIG_PINCTRL_SH_PFC)	+= sh-pfc/
 obj-$(CONFIG_PINCTRL_SPEAR)	+= spear/
diff --git a/drivers/pinctrl/rz-pfc/Kconfig b/drivers/pinctrl/rz-pfc/Kconfig
new file mode 100644
index 0000000..3714c10
--- /dev/null
+++ b/drivers/pinctrl/rz-pfc/Kconfig
@@ -0,0 +1,18 @@
+#
+# Renesas RZ pinctrl drivers
+#
+
+if ARCH_RENESAS
+
+config PINCTRL_RZ_PINCTRL
+	select PINMUX
+	select PINCONF
+	select GPIOLIB
+	select GENERIC_PINCONF
+	select GENERIC_PINMUX_FUNCTIONS
+	select GENERIC_PINCTRL_GROUPS
+	def_bool y
+	help
+	  This enables pin control drivers for Renesas RZ platforms
+
+endif
diff --git a/drivers/pinctrl/rz-pfc/Makefile b/drivers/pinctrl/rz-pfc/Makefile
new file mode 100644
index 0000000..cba8283
--- /dev/null
+++ b/drivers/pinctrl/rz-pfc/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_PINCTRL_RZ_PINCTRL)		+= pinctrl-rz.o
diff --git a/drivers/pinctrl/rz-pfc/pinctrl-rz.c b/drivers/pinctrl/rz-pfc/pinctrl-rz.c
new file mode 100644
index 0000000..3efbf03
--- /dev/null
+++ b/drivers/pinctrl/rz-pfc/pinctrl-rz.c
@@ -0,0 +1,447 @@
+/*
+ * Pinctrl support for Renesas RZ Series
+ *
+ * Copyright (C) 2017 Jacopo Mondi
+ * Copyright (C) 2017 Renesas Electronics Corporation
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/err.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 "../core.h"
+#include "../devicetree.h"
+#include "../pinmux.h"
+
+#include "pinctrl-rz.h"
+
+#define DRIVER_NAME		"rz-pinctrl"
+#define RZ_PIN_ARGS_COUNT	3
+
+/**
+ * rz_pinctrl_pos_to_index() - Retrieve the index of pin at position [bank:pin]
+ *
+ * This can be improved, as it walks all the pins reported by the SoC driver
+ *
+ * @return: pin number between [0 - npins]; -1 if not found
+ */
+static int rz_pinctrl_pos_to_index(struct rz_pinctrl_dev *rz_pinctrl,
+				   unsigned int bank, unsigned int pin)
+{
+	struct rz_pinctrl_info *info;
+	struct rz_pin_desc *rz_pin;
+	int i, npins;
+
+	info = rz_pinctrl->info;
+	npins = info->npins;
+	for (i = 0; i < npins; ++i) {
+		rz_pin = &info->pins[i];
+
+		/*
+		 * return the pin index in the array, not the pin number,
+		 * so that we can access it easily when muxing group's pins
+		 */
+		if (rz_pin->bank == bank && rz_pin->pin == pin)
+			return i;
+	}
+
+	return -1;
+}
+
+/* ----------------------------------------------------------------------------
+ * pinctrl operations
+ */
+static void rz_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+			    unsigned int pin)
+{
+	struct rz_pinctrl_dev *rz_pinctrl;
+	struct rz_pinctrl_info *info;
+
+	rz_pinctrl = pinctrl_dev_get_drvdata(pctldev);
+	info = rz_pinctrl->info;
+
+	seq_printf(s, "%s %s\n", info->pins[pin].name, DRIVER_NAME);
+}
+
+/**
+ * rz_dt_node_to_map() - Parse device tree nodes and collect pins, groups and
+ *			 functions
+ *
+ * Pins for RZ series pin controller described by "renesas-rz,pins" property
+ * are arrays of u32 values in the form:
+ *
+ * "renesas-rz,pins" = <BANK PIN MUX>, ... ;
+ *
+ * Parse the list arguments and identify pins through their position
+ * (bank and pin offset) and save the provided mux mode for later use.
+ *
+ * TODO: the array can be expended to support additional parameters for
+ *	 pin configurations values (IO direction etc)
+ *
+ * @pctldev: pin controller device
+ * @np_config: device tree node to parse
+ * @map: pointer to pin map (output)
+ * @num_maps: number of collected maps (output)
+ *
+ * @return: 0 for success; != 0 otherwise
+ */
+static int rz_dt_node_to_map(struct pinctrl_dev *pctldev,
+			     struct device_node *np_config,
+			     struct pinctrl_map **map, unsigned int *num_maps)
+{
+	struct rz_pinctrl_dev *rz_pinctrl;
+	const char *prop_name = "renesas-rz,pins",
+		   *grpname, **fngrps;
+	unsigned int *grpins,
+		     *mux_modes;
+	int i, npins, ret;
+
+	rz_pinctrl = pinctrl_dev_get_drvdata(pctldev);
+
+	npins = pinctrl_count_index_with_args(np_config, prop_name);
+	if (npins <= 0) {
+		dev_err(rz_pinctrl->dev, "Missing pins configuration prop\n");
+		return -EINVAL;
+	}
+
+	mux_modes = devm_kzalloc(rz_pinctrl->dev, sizeof(*mux_modes) * npins,
+				 GFP_KERNEL);
+	grpins = devm_kzalloc(rz_pinctrl->dev, sizeof(*grpins) * npins,
+			      GFP_KERNEL);
+	if (unlikely(!grpins || !mux_modes))
+		return -ENOMEM;
+
+	/*
+	 * functions are made of 1 group only;
+	 * in facts, functions and groups are identical for RZ pin controller,
+	 * except that functions carry an array of mux modes (aka alternate
+	 * functions IDs)
+	 */
+	fngrps = devm_kzalloc(rz_pinctrl->dev, sizeof(*fngrps), GFP_KERNEL);
+	if (unlikely(!fngrps)) {
+		ret = -ENOMEM;
+		goto free_pins;
+	}
+
+	*num_maps = 0;
+	(*map) = devm_kzalloc(rz_pinctrl->dev, sizeof(**map), GFP_KERNEL);
+	if (unlikely(!*map)) {
+		ret = -ENOMEM;
+		goto free_fngrps;
+	}
+
+	/* collect pin numbers and mux confs to create groups and functions */
+	for (i = 0; i < npins; ++i) {
+		struct of_phandle_args of_pins_args;
+		unsigned int bank, offs, mode, pin_idx;
+
+		/* DTS identifies pin by position: bank and pin offset */
+		ret = pinctrl_parse_index_with_args(np_config, prop_name, i,
+						    &of_pins_args);
+		if (ret)
+			goto free_map;
+
+		if (of_pins_args.args_count < RZ_PIN_ARGS_COUNT) {
+			dev_err(rz_pinctrl->dev,
+				"Wrong arguments number for renesas-rz,pins");
+			ret = -EINVAL;
+			goto free_map;
+		}
+
+		bank = of_pins_args.args[0];
+		offs = of_pins_args.args[1];
+		mode = of_pins_args.args[2];
+
+		/* pin_idx is the index on the static pin array */
+		pin_idx = rz_pinctrl_pos_to_index(rz_pinctrl, bank, offs);
+		if (pin_idx < 0) {
+			dev_err(rz_pinctrl->dev,
+				"Invalid pin position %d-%d\n", bank, offs);
+			ret = -EINVAL;
+			goto free_map;
+		}
+
+		grpins[i] = pin_idx;
+		mux_modes[i] = mode;
+	}
+
+	grpname = np_config->name;
+	fngrps[0] = grpname;
+
+	mutex_lock(&rz_pinctrl->mutex);
+	ret = pinctrl_generic_add_group(pctldev, grpname, grpins, npins, NULL);
+	if (ret) {
+		mutex_unlock(&rz_pinctrl->mutex);
+		goto free_map;
+	}
+
+	ret = pinmux_generic_add_function(pctldev, grpname, fngrps,
+					  1, mux_modes);
+	if (ret) {
+		mutex_unlock(&rz_pinctrl->mutex);
+		goto free_map;
+	}
+	mutex_unlock(&rz_pinctrl->mutex);
+
+	(*map)->type = PIN_MAP_TYPE_MUX_GROUP;
+	(*map)->data.mux.group = grpname;
+	(*map)->data.mux.function = grpname;
+	*num_maps = 1;
+
+	return 0;
+
+free_map:
+	devm_kfree(rz_pinctrl->dev, *map);
+free_fngrps:
+	devm_kfree(rz_pinctrl->dev, fngrps);
+free_pins:
+	devm_kfree(rz_pinctrl->dev, mux_modes);
+	devm_kfree(rz_pinctrl->dev, grpins);
+	return ret;
+}
+
+/**
+ * rz_dt_free_map()
+ */
+static void rz_dt_free_map(struct pinctrl_dev *pctldev,
+			   struct pinctrl_map *map, unsigned int num_maps)
+{
+	struct rz_pinctrl_dev *rz_pinctrl = pinctrl_dev_get_drvdata(pctldev);
+
+	devm_kfree(rz_pinctrl->dev, map);
+}
+
+static const struct pinctrl_ops rz_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,
+	.pin_dbg_show = rz_pin_dbg_show,
+	.dt_node_to_map = rz_dt_node_to_map,
+	.dt_free_map = rz_dt_free_map,
+};
+
+/* ----------------------------------------------------------------------------
+ * pinconfig operations
+ */
+
+/* TODO */
+
+/* ----------------------------------------------------------------------------
+ * pinmux operations
+ */
+
+/**
+ * rz_pinmux_set() - Retrieve pins from a group and apply mux settings
+ *
+ * @pctldev: pin controller device
+ * @selector: Function selector
+ * @group: Group selector
+ * @return: 0 for success; != otherwise
+ */
+static int rz_pinmux_set(struct pinctrl_dev *pctldev, unsigned int selector,
+			 unsigned int group)
+{
+	struct rz_pinctrl_dev *rz_pinctrl;
+	struct rz_pinctrl_info *info;
+	struct rz_pinctrl_ops *ops;
+	struct group_desc *grp;
+	struct function_desc *func;
+	unsigned int npins, *mux_modes;
+	int i;
+
+	rz_pinctrl = pinctrl_dev_get_drvdata(pctldev);
+	info = rz_pinctrl->info;
+	ops = info->ops;
+
+	grp = pinctrl_generic_get_group(pctldev, group);
+	if (!grp)
+		return -EINVAL;
+
+	func = pinmux_generic_get_function(pctldev, selector);
+	if (!func)
+		return -EINVAL;
+
+	npins = grp->num_pins;
+	mux_modes = (unsigned int *)func->data;
+
+	for (i = 0; i < npins; ++i) {
+		unsigned int pin_idx, mux_mode;
+		struct rz_pin_desc *pin;
+		int ret;
+
+		/*
+		 * use pin index to retrieve pin descriptor;
+		 * then provide it to the set_mux SoC operation
+		 */
+		pin_idx = grp->pins[i];
+		pin = &info->pins[pin_idx];
+		mux_mode = mux_modes[i];
+
+		if (!ops || !ops->set_mux) {
+			dev_err(rz_pinctrl->dev, "Pin muxing not supported\n");
+			return -EINVAL;
+		}
+
+		ret = ops->set_mux(rz_pinctrl, pin, mux_mode);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+struct pinmux_ops rz_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 = rz_pinmux_set,
+};
+
+/* ----------------------------------------------------------------------------
+ * rz pinctrl operations
+ */
+
+/**
+ * rz_add_pins() - Enumerate pins reported by SoC driver in pin desc array
+ *
+ * @rz_pinctrl: RZ pincontroller
+ *
+ * @return: 0 for success; != 0 otherwise
+ */
+static int rz_add_pins(struct rz_pinctrl_dev *rz_pinctrl)
+{
+	struct rz_pinctrl_info *info;
+	struct rz_pin_desc *pin;
+	unsigned int npins, i;
+
+	info = rz_pinctrl->info;
+	npins = info->npins;
+
+	rz_pinctrl->pins = devm_kzalloc(rz_pinctrl->dev,
+					npins * sizeof(*rz_pinctrl->pins),
+					GFP_KERNEL);
+	if (unlikely(!rz_pinctrl->pins))
+		return -ENOMEM;
+
+	rz_pinctrl->desc.pins = rz_pinctrl->pins;
+	rz_pinctrl->desc.npins = npins;
+
+	for (i = 0; i < npins; ++i) {
+		pin = &info->pins[i];
+
+		rz_pinctrl->pins[i].number = pin->number;
+		rz_pinctrl->pins[i].name = pin->name;
+	}
+
+	return 0;
+}
+
+/**
+ * rz_pinctrl_map_res() - Map memory resources for pincontroller
+ *
+ * @pdev: platform device
+ * @rz_pincrl: RZ pincontroller
+ *
+ * @return: 0 for success; != 0 otherwise
+ */
+static int rz_pinctrl_map_res(struct platform_device *pdev,
+			      struct rz_pinctrl_dev *rz_pinctrl)
+{
+	struct resource *res;
+	struct rz_pinctrl_res *rz_res;
+	unsigned int i, nres;
+
+	nres = pdev->num_resources;
+	rz_res = devm_kzalloc(&pdev->dev, nres * sizeof(*rz_res),
+			      GFP_KERNEL);
+	if (unlikely(!rz_res))
+		return -ENOMEM;
+
+	rz_pinctrl->nres = nres;
+	rz_pinctrl->res = rz_res;
+
+	for (i = 0; i < nres; i++) {
+		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+		if (!res)
+			return -ENODEV;
+
+		rz_res = &rz_pinctrl->res[i];
+
+		rz_res->start = res->start;
+		rz_res->size = resource_size(res);
+		rz_res->base = devm_ioremap_resource(&pdev->dev, res);
+		if (IS_ERR(rz_res->base))
+			return PTR_ERR(rz_res->base);
+	}
+
+	return 0;
+}
+
+/**
+ * rz_pinctrl_probe() - Register pincontroller driver operations
+ *
+ * @pdev: platform device
+ * @info: SoC device info structure
+ */
+int rz_pinctrl_probe(struct platform_device *pdev, struct rz_pinctrl_info *info)
+{
+	int ret;
+	struct rz_pinctrl_dev *rz_pinctrl;
+
+	rz_pinctrl = devm_kzalloc(&pdev->dev, sizeof(*rz_pinctrl), GFP_KERNEL);
+	if (!rz_pinctrl)
+		return -ENOMEM;
+
+	rz_pinctrl->dev = &pdev->dev;
+	rz_pinctrl->info = info;
+
+	ret = rz_pinctrl_map_res(pdev, rz_pinctrl);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, rz_pinctrl);
+
+	rz_pinctrl->desc.name = DRIVER_NAME;
+	rz_pinctrl->desc.pctlops = &rz_pinctrl_ops;
+	rz_pinctrl->desc.pmxops = &rz_pinmux_ops;
+	rz_pinctrl->desc.owner = THIS_MODULE;
+
+	ret = rz_add_pins(rz_pinctrl);
+	if (ret)
+		return ret;
+
+	mutex_init(&rz_pinctrl->mutex);
+
+	ret = pinctrl_register_and_init(&rz_pinctrl->desc, rz_pinctrl->dev,
+					rz_pinctrl, &rz_pinctrl->pctl);
+	if (ret) {
+		dev_err(&pdev->dev, "could not register rz pinctrl driver\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+void rz_pinctrl_remove(struct platform_device *pdev)
+{
+	struct rz_pinctrl_dev *rz_pinctrl = platform_get_drvdata(pdev);
+
+	pinctrl_unregister(rz_pinctrl->pctl);
+}
+
+MODULE_AUTHOR("Jacopo Mondi <jacopo+renesas@jmondi.org");
+MODULE_DESCRIPTION("Pinctrl driver for Reneas RZ series");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/rz-pfc/pinctrl-rz.h b/drivers/pinctrl/rz-pfc/pinctrl-rz.h
new file mode 100644
index 0000000..b873c89
--- /dev/null
+++ b/drivers/pinctrl/rz-pfc/pinctrl-rz.h
@@ -0,0 +1,114 @@
+/*
+ * Pinctrl support for Renesas RZ Series
+ *
+ * Copyright (C) 2017 Jacopo Mondi
+ * Copyright (C) 2017 Renesas Electronics Corporation
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#ifndef __RZ_PINCTRL_H__
+#define __RZ_PINCTRL_H__
+
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/types.h>
+
+/* ----------------------------------------------------------------------------
+ * pinctrl-rz data types
+ */
+#define RZ_PIN_NAME(bank, pin)						\
+	PIN_##bank##_##pin
+
+#define RZ_PIN_DESC(b, p)						\
+	{ .number = RZ_PIN_NAME(b, p),					\
+	  .name = __stringify(RZ_PIN_NAME(b, p)),			\
+	  .bank = b, .pin = p }
+
+/**
+ * rz_pin_desc - Single RZ pin descriptor
+ *
+ * @number: pin number as enumerated by SoC driver
+ * @name: pin name as reported by SoC driver
+ * @bank: pin bank location
+ * @pin: pin register offset
+ */
+struct rz_pin_desc {
+	unsigned int bank, pin;
+	unsigned int number;
+	const char *name;
+};
+
+/**
+ * rz_pinctrl_info - SoC info data
+ *
+ * @ops: SoC specific operations
+ * @npins: number of pins
+ * @pins: pin array
+ */
+struct rz_pinctrl_ops;
+struct rz_pinctrl_info {
+	struct rz_pinctrl_ops *ops;
+
+	unsigned int npins;
+	struct rz_pin_desc *pins;
+};
+
+/**
+ * rz_pinctrl_res - Memory resource for RZ SoC
+ *
+ * @start: physical address base
+ * @size: memory region size
+ * @base: logical address base
+ */
+struct rz_pinctrl_res {
+	resource_size_t start;
+	resource_size_t size;
+	void __iomem *base;
+};
+
+/**
+ * rz_pinctrl_dev - RZ pincontroller device
+ *
+ * @dev: device
+ * @info: SoC data
+ * @nres: number of memory regions
+ * @res: memory regions
+ * @mutex: protect pin*_generic functions
+ * @pins: pin array for pinctrl core
+ * @desc: pincontroller desc for pinctrl core
+ * @pctl: pinctrl device
+ */
+struct rz_pinctrl_dev {
+	struct device *dev;
+
+	struct rz_pinctrl_info *info;
+
+	unsigned int nres;
+	struct rz_pinctrl_res *res;
+
+	struct mutex mutex;
+
+	struct pinctrl_pin_desc *pins;
+	struct pinctrl_desc desc;
+	struct pinctrl_dev *pctl;
+};
+
+/**
+ * rz_pinctrl_ops - SoC operations
+ *
+ * @set_mux: perform pin muxing on SoC registers
+ */
+struct rz_pinctrl_ops {
+	int (*set_mux)(struct rz_pinctrl_dev *, struct rz_pin_desc *,
+		       unsigned int mux_mode);
+};
+
+/* ----------------------------------------------------------------------------
+ * pinctrl-rz prototypes
+ */
+int rz_pinctrl_probe(struct platform_device *pdev,
+		     struct rz_pinctrl_info *info);
+void rz_pinctrl_remove(struct platform_device *pdev);
+
+#endif
