All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/3] pinctrl: ADI PIN control driver for the GPIO controller on bf54x and bf60x.
@ 2013-07-16 10:55 Sonic Zhang
  2013-07-16 10:55 ` [PATCH 2/3] blackfin: gpio: Remove none gpio lib code Sonic Zhang
                   ` (4 more replies)
  0 siblings, 5 replies; 17+ messages in thread
From: Sonic Zhang @ 2013-07-16 10:55 UTC (permalink / raw)
  To: Linus Walleij, Grant Likely, Steven Miao
  Cc: LKML, buildroot-devel, adi-buildroot-devel, Sonic Zhang

From: Sonic Zhang <sonic.zhang@analog.com>

The new ADI GPIO2 controller was introduced since the BF548 and BF60x
processors. It differs a lot from the old one on BF5xx processors. So,
create a pinctrl driver under pinctrl framework.

- Define gpio ports and gpio interrupt controllers as individual platform
devices.
- Register a pinctrl driver for the whole GPIO ports and GPIO interrupt
devices.
- Probe pint devices before port devices. Put device instances into
respective gpio and pint lists.
- Define peripheral, irq and gpio reservation bit masks for each gpio
port as runtime resources.
- Save and restore gpio port and pint status MMRs in syscore PM functions.
- Add peripheral device groups and function data into machine portmux.h.
- Handle peripheral and gpio requests in pinctrl operation functions.
- Demux gpio IRQs via the irq_domain created by each GPIO port.

Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
---
 drivers/pinctrl/Makefile                   |    1 +
 drivers/pinctrl/pinctrl-adi2.c             | 1545 ++++++++++++++++++++++++++++
 include/linux/platform_data/pinctrl-adi2.h |   38 +
 3 files changed, 1584 insertions(+)
 create mode 100644 drivers/pinctrl/pinctrl-adi2.c
 create mode 100644 include/linux/platform_data/pinctrl-adi2.h

diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index d64563bf..c685958 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_PINCTRL_AB8500)	+= pinctrl-ab8500.o
 obj-$(CONFIG_PINCTRL_AB8540)	+= pinctrl-ab8540.o
 obj-$(CONFIG_PINCTRL_AB9540)	+= pinctrl-ab9540.o
 obj-$(CONFIG_PINCTRL_AB8505)	+= pinctrl-ab8505.o
+obj-$(CONFIG_PINCTRL_ADI2)	+= pinctrl-adi2.o
 obj-$(CONFIG_PINCTRL_AT91)	+= pinctrl-at91.o
 obj-$(CONFIG_PINCTRL_BCM2835)	+= pinctrl-bcm2835.o
 obj-$(CONFIG_PINCTRL_BAYTRAIL)	+= pinctrl-baytrail.o
diff --git a/drivers/pinctrl/pinctrl-adi2.c b/drivers/pinctrl/pinctrl-adi2.c
new file mode 100644
index 0000000..222a74c
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-adi2.c
@@ -0,0 +1,1545 @@
+/*
+ * Pinctrl Driver for ADI GPIO2 controller
+ *
+ * Copyright 2007-2013 Analog Devices Inc.
+ *
+ * Licensed under the GPLv2 or later
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/irq.h>
+#include <linux/platform_data/pinctrl-adi2.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/syscore_ops.h>
+#include <linux/gpio.h>
+#include <asm/portmux.h>
+#include "core.h"
+
+static LIST_HEAD(adi_pint_list);
+static LIST_HEAD(adi_pinctrl_list);
+
+#define PERIPHERAL_USAGE 1
+#define GPIO_USAGE 0
+
+#define DRIVER_NAME "pinctrl-adi2"
+
+#define RESOURCE_LABEL_SIZE	16
+#define PINT_HI_OFFSET		16
+
+#define RSV_NONE	0
+#define RSV_GPIO	1
+#define RSV_INT		2
+#define RSV_PERI	3
+
+/**
+ * struct gpio_reserve_map - a GPIO map structure containing the
+ * reservation status of each PIN.
+ *
+ * @owner: who request the reservation
+ * @rsv_gpio: if this pin is reserved as GPIO
+ * @rsv_int: if this pin is reserved as interrupt
+ * @rsv_peri: if this pin is reserved as part of a peripheral device
+ */
+struct gpio_reserve_map {
+	unsigned char owner[RESOURCE_LABEL_SIZE];
+	bool rsv_gpio;
+	bool rsv_int;
+	bool rsv_peri;
+};
+
+/**
+ * struct gpio_port_saved - GPIO port registers that should be saved between
+ * power suspend and resume operations.
+ *
+ * @fer: PORTx_FER register
+ * @data: PORTx_DATA register
+ * @dir: PORTx_DIR register
+ * @inen: PORTx_INEN register
+ * @mux: PORTx_MUX register
+ */
+struct gpio_port_saved {
+	u16 fer;
+	u16 data;
+	u16 dir;
+	u16 inen;
+	u32 mux;
+};
+
+/**
+ * struct gpio_pint - GPIO interrupt controller device. Multiple ADI GPIO
+ * banks can be mapped into one GPIO interrupt controller.
+ *
+ * @node: All gpio_pint instances are added to a global list.
+ * @base: GPIO PINT device register base address
+ * @irq: IRQ of the GPIO PINT device, it is the parent IRQ of all
+ *       GPIO IRQs mapping to this device.
+ * @domain: [0] irq domain of the gpio port, whose hardware interrupts are
+ *		mapping to the low 16-bit of the pint registers.
+ *          [1] irq domain of the gpio port, whose hardware interrupts are
+ *		mapping to the high 16-bit of the pint registers.
+ * @regs: address pointer to the GPIO PINT device
+ * @map_count: No more than 2 GPIO banks can be mapped to this PINT device.
+ * @lock: This lock make sure the irq_chip operations to one GPIO PINT device
+ *        for different GPIO interrrupts are atomic.
+ * @pint_map_port: Set up the mapping between one GPIO PINT device and
+ *                 multiple GPIO banks.
+ */
+struct gpio_pint {
+	struct list_head node;
+	void __iomem *base;
+	int irq;
+	struct irq_domain *domain[2];
+	struct gpio_pint_regs *regs;
+	struct adi_pm_pint_save saved_data;
+	int map_count;
+	spinlock_t lock;
+
+	int (*pint_map_port)(struct gpio_pint *pint, u8 assign,
+				u8 map, struct irq_domain *domain);
+};
+
+/**
+ * ADI pin controller
+ *
+ * @node: All adi_pmx instances are added to a global list.
+ * @dev: a pointer back to containing device
+ * @pctl: the pinctrl device
+ * @gpio_list: the list of gpio banks owned by this pin controller.
+ * @gpio_base: the base gpio number of this pin controller.
+ */
+struct adi_pmx {
+	struct list_head node;
+	struct device *dev;
+	struct pinctrl_dev *pctl;
+	struct list_head gpio_list;
+	unsigned long gpio_base;
+};
+
+/**
+ * struct gpio_pint - GPIO bank device. Multiple ADI GPIO banks can be mapped
+ * into one GPIO interrupt controller.
+ *
+ * @node: All gpio_pint instances are added to a list.
+ * @base: GPIO bank device register base address
+ * @pin_base: base global GPIO pin index of the GPIO bank device
+ * @irq_base: base IRQ of the GPIO bank device
+ * @width: PIN number of the GPIO bank device
+ * @range: The range space of the GPIO bank handled by the pin controller.
+ * @regs: address pointer to the GPIO bank device
+ * @saved_data: registers that should be saved between PM operations.
+ * @dev: device structure of this GPIO bank
+ * @pmx: the pinctrl device
+ * @pint: GPIO PINT device that this GPIO bank mapped to
+ * @pint_map: GIOP bank mapping code in PINT device
+ * @pint_assign: The 32-bit GPIO PINT registers can be divided into 2 parts. A
+ *               GPIO bank can be mapped into either low 16 bits[0] or high 16
+ *               bits[1] of each PINT register.
+ * @lock: This lock make sure the irq_chip operations to one GPIO PINT device
+ *        for different GPIO interrrupts are atomic.
+ * @chip: abstract a GPIO controller
+ * @domain: The irq domain owned by the GPIO port.
+ * @rsvmap: Reservation map array for each pin in the GPIO bank
+ */
+struct gpio_port {
+	struct list_head node;
+	void __iomem *base;
+	unsigned int pin_base;
+	unsigned int irq_base;
+	unsigned int width;
+	struct pinctrl_gpio_range range;
+	struct gpio_port_t *regs;
+	struct gpio_port_saved saved_data;
+	struct device *dev;
+	struct adi_pmx *pmx;
+
+	struct gpio_pint *pint;
+	u8 pint_map;
+	u8 pint_assign;
+
+	spinlock_t lock;
+	struct gpio_chip chip;
+	struct irq_domain *domain;
+
+	struct gpio_reserve_map rsvmap[];
+};
+
+static inline u8 pin_to_offset(struct pinctrl_gpio_range *range, unsigned pin)
+{
+	return pin - range->pin_base;
+}
+
+static inline unsigned offset_to_gpio(struct gpio_port *port, u8 offset)
+{
+	return offset + port->chip.base;
+}
+
+static inline u8 gpio_to_offset(struct gpio_port *port, unsigned gpio)
+{
+	return gpio - port->chip.base;
+}
+
+static inline unsigned hwirq_to_pintbit(struct gpio_port *port, int hwirq)
+{
+	return (1 << hwirq) << (port->pint_assign * PINT_HI_OFFSET);
+}
+
+static void set_label(struct gpio_port *port, unsigned offset,
+	const char *label)
+{
+	char *pch = port->rsvmap[offset].owner;
+
+	if (label) {
+		strncpy(pch, label, RESOURCE_LABEL_SIZE);
+		pch[RESOURCE_LABEL_SIZE - 1] = 0;
+	}
+}
+
+static char *get_label(struct gpio_port *port, unsigned offset)
+{
+	char *pch = port->rsvmap[offset].owner;
+
+	return *pch ? pch : "UNKNOWN";
+}
+
+static inline unsigned int is_reserved(struct gpio_port *port, char type,
+	unsigned offset)
+{
+	switch (type) {
+	case RSV_GPIO:
+		return port->rsvmap[offset].rsv_gpio == true;
+	case RSV_INT:
+		return port->rsvmap[offset].rsv_int == true;
+	case RSV_PERI:
+		return port->rsvmap[offset].rsv_peri == true;
+	}
+
+	return 0;
+}
+
+static inline void reserve(struct gpio_port *port, char type, unsigned offset)
+{
+	switch (type) {
+	case RSV_GPIO:
+		port->rsvmap[offset].rsv_gpio = true;
+		break;
+	case RSV_INT:
+		port->rsvmap[offset].rsv_int = true;
+		break;
+	case RSV_PERI:
+		port->rsvmap[offset].rsv_peri = true;
+		break;
+	}
+}
+
+static inline void unreserve(struct gpio_port *port, char type, unsigned offset)
+{
+	switch (type) {
+	case RSV_GPIO:
+		port->rsvmap[offset].rsv_gpio = false;
+		break;
+	case RSV_INT:
+		port->rsvmap[offset].rsv_int = false;
+		break;
+	case RSV_PERI:
+		port->rsvmap[offset].rsv_peri = false;
+		break;
+	}
+}
+
+static struct gpio_pint *find_gpio_pint(unsigned id)
+{
+	struct gpio_pint *pint;
+	int i = 0;
+
+	list_for_each_entry(pint, &adi_pint_list, node) {
+		if (id == i)
+			break;
+		i++;
+	}
+
+	if (&pint->node != &adi_pint_list)
+		return pint;
+	else
+		return NULL;
+}
+
+static struct adi_pmx *find_pinctrl(unsigned id)
+{
+	struct adi_pmx *pmx;
+	int i = 0;
+
+	list_for_each_entry(pmx, &adi_pinctrl_list, node) {
+		if (id == i)
+			break;
+		i++;
+	}
+
+	if (&pmx->node != &adi_pinctrl_list)
+		return pmx;
+	else
+		return NULL;
+}
+
+static struct gpio_port *find_gpio_port(unsigned pin,
+	struct list_head *gpio_list)
+{
+	struct gpio_port *port;
+
+	list_for_each_entry(port, gpio_list, node)
+		if (pin >= port->range.pin_base &&
+			pin < port->range.pin_base + port->range.npins)
+			break;
+
+	if (&port->node != gpio_list)
+		return port;
+	else
+		return NULL;
+}
+
+static inline void port_setup(struct gpio_port *port, unsigned offset,
+	unsigned short usage)
+{
+	struct gpio_port_t *regs = port->regs;
+
+	if (usage == GPIO_USAGE)
+		writew(readw(&regs->port_fer) & ~(1 << offset),
+			&regs->port_fer);
+	else
+		writew(readw(&regs->port_fer) | (1 << offset), &regs->port_fer);
+}
+
+static inline void portmux_setup(struct gpio_port *port, unsigned offset,
+	unsigned short function)
+{
+	struct gpio_port_t *regs = port->regs;
+	u32 pmux;
+
+	pmux = readl(&regs->port_mux);
+
+	pmux &= ~(0x3 << (2 * offset));
+	pmux |= (function & 0x3) << (2 * offset);
+
+	writel(pmux, &regs->port_mux);
+}
+
+static inline u16 get_portmux(struct gpio_port *port, unsigned offset)
+{
+	struct gpio_port_t *regs = port->regs;
+	u32 pmux = readl(&regs->port_mux);
+
+	return pmux >> (2 * offset) & 0x3;
+}
+
+
+static void __adi_gpio_irq_prepare(struct gpio_port *port, unsigned offset)
+{
+	struct gpio_port_t *regs = port->regs;
+
+	port_setup(port, offset, GPIO_USAGE);
+
+	writew(1 << offset, &regs->dir_clear);
+	writew(readw(&regs->inen) | (1 << offset), &regs->inen);
+}
+
+static int __adi_gpio_irq_request(struct gpio_port *port, unsigned offset,
+	const char *label)
+{
+	if (unlikely(is_reserved(port, RSV_PERI, offset))) {
+		if (system_state == SYSTEM_BOOTING)
+			dump_stack();
+
+		dev_err(port->dev,
+		       "GPIO %d is already reserved as Peripheral by %s !\n",
+			offset_to_gpio(port, offset), get_label(port, offset));
+		return -EBUSY;
+	}
+	if (unlikely(is_reserved(port, RSV_GPIO, offset)))
+		dev_err(port->dev,
+			"GPIO %d is already reserved by %s!\n",
+			offset_to_gpio(port, offset), get_label(port, offset));
+
+	reserve(port, RSV_INT, offset);
+	set_label(port, offset, label);
+	port_setup(port, offset, GPIO_USAGE);
+
+	return 0;
+}
+
+static void __adi_gpio_irq_free(struct gpio_port *port, unsigned offset)
+{
+	if (unlikely(!is_reserved(port, RSV_INT, offset))) {
+		if (system_state == SYSTEM_BOOTING)
+			dump_stack();
+
+		dev_err(port->dev, "GPIO %d wasn't requested!\n",
+			offset_to_gpio(port, offset));
+		return;
+	}
+
+	unreserve(port, RSV_INT, offset);
+	set_label(port, offset, "free");
+}
+
+static void adi_gpio_ack_irq(struct irq_data *d)
+{
+	unsigned long flags;
+	struct gpio_port *port = irq_data_get_irq_chip_data(d);
+	struct gpio_pint_regs *regs = port->pint->regs;
+	unsigned pintbit = hwirq_to_pintbit(port, d->hwirq);
+
+	spin_lock_irqsave(&port->lock, flags);
+	spin_lock_irqsave(&port->pint->lock, flags);
+
+	if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) {
+		if (readl(&regs->invert_set) & pintbit)
+			writel(pintbit, &regs->invert_clear);
+		else
+			writel(pintbit, &regs->invert_set);
+	}
+
+	writel(pintbit, &regs->request);
+
+	spin_unlock_irqrestore(&port->pint->lock, flags);
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void adi_gpio_mask_ack_irq(struct irq_data *d)
+{
+	unsigned long flags;
+	struct gpio_port *port = irq_data_get_irq_chip_data(d);
+	struct gpio_pint_regs *regs = port->pint->regs;
+	unsigned pintbit = hwirq_to_pintbit(port, d->hwirq);
+
+	spin_lock_irqsave(&port->lock, flags);
+	spin_lock_irqsave(&port->pint->lock, flags);
+
+	if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) {
+		if (readl(&regs->invert_set) & pintbit)
+			writel(pintbit, &regs->invert_clear);
+		else
+			writel(pintbit, &regs->invert_set);
+	}
+
+	writel(pintbit, &regs->request);
+	writel(pintbit, &regs->mask_clear);
+
+	spin_unlock_irqrestore(&port->pint->lock, flags);
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void adi_gpio_mask_irq(struct irq_data *d)
+{
+	unsigned long flags;
+	struct gpio_port *port = irq_data_get_irq_chip_data(d);
+	struct gpio_pint_regs *regs = port->pint->regs;
+
+	spin_lock_irqsave(&port->lock, flags);
+	spin_lock_irqsave(&port->pint->lock, flags);
+
+	writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_clear);
+
+	spin_unlock_irqrestore(&port->pint->lock, flags);
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void adi_gpio_unmask_irq(struct irq_data *d)
+{
+	unsigned long flags;
+	struct gpio_port *port = irq_data_get_irq_chip_data(d);
+	struct gpio_pint_regs *regs = port->pint->regs;
+
+	spin_lock_irqsave(&port->lock, flags);
+	spin_lock_irqsave(&port->pint->lock, flags);
+
+	writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_set);
+
+	spin_unlock_irqrestore(&port->pint->lock, flags);
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static unsigned int adi_gpio_irq_startup(struct irq_data *d)
+{
+	unsigned long flags;
+	struct gpio_port *port = irq_data_get_irq_chip_data(d);
+	struct gpio_pint_regs *regs = port->pint->regs;
+
+	if (!port) {
+		dev_err(port->dev, "GPIO IRQ %d :Not exist\n", d->irq);
+		return -ENODEV;
+	}
+
+	spin_lock_irqsave(&port->lock, flags);
+	spin_lock_irqsave(&port->pint->lock, flags);
+
+	__adi_gpio_irq_prepare(port, d->hwirq);
+	writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_set);
+
+	spin_unlock_irqrestore(&port->pint->lock, flags);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return 0;
+}
+
+static void adi_gpio_irq_shutdown(struct irq_data *d)
+{
+	unsigned long flags;
+	struct gpio_port *port = irq_data_get_irq_chip_data(d);
+	struct gpio_pint_regs *regs = port->pint->regs;
+
+	spin_lock_irqsave(&port->lock, flags);
+	spin_lock_irqsave(&port->pint->lock, flags);
+
+	writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_clear);
+	__adi_gpio_irq_free(port, d->hwirq);
+
+	spin_unlock_irqrestore(&port->pint->lock, flags);
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int adi_gpio_irq_type(struct irq_data *d, unsigned int type)
+{
+	unsigned long flags;
+	struct gpio_port *port = irq_data_get_irq_chip_data(d);
+	struct gpio_pint_regs *pint_regs = port->pint->regs;
+	unsigned pintmask;
+	unsigned int irq = d->irq;
+	int ret = 0;
+	char buf[16];
+
+	if (!port) {
+		dev_err(port->dev, "GPIO IRQ %d :Not exist\n", irq);
+		return -ENODEV;
+	}
+
+	pintmask = hwirq_to_pintbit(port, d->hwirq);
+
+	spin_lock_irqsave(&port->lock, flags);
+	spin_lock_irqsave(&port->pint->lock, flags);
+
+	if (type == IRQ_TYPE_PROBE)
+		type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
+
+	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
+		    IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
+		snprintf(buf, 16, "gpio-irq%d", irq);
+		ret = __adi_gpio_irq_request(port, d->hwirq, buf);
+		if (ret)
+			goto out;
+	} else
+		goto out;
+
+	if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
+		/* low or falling edge denoted by one */
+		writel(pintmask, &pint_regs->invert_set);
+	else
+		/* high or rising edge denoted by zero */
+		writel(pintmask, &pint_regs->invert_clear);
+
+	if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
+		if (gpio_get_value(offset_to_gpio(port, d->hwirq)))
+			writel(pintmask, &pint_regs->invert_set);
+		else
+			writel(pintmask, &pint_regs->invert_clear);
+	}
+
+	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
+		writel(pintmask, &pint_regs->edge_set);
+		__irq_set_handler_locked(irq, handle_edge_irq);
+	} else {
+		writel(pintmask, &pint_regs->edge_clear);
+		__irq_set_handler_locked(irq, handle_level_irq);
+	}
+
+out:
+	spin_unlock_irqrestore(&port->pint->lock, flags);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return ret;
+}
+
+#ifdef CONFIG_PM
+static int adi_gpio_set_wake(struct irq_data *d, unsigned int state)
+{
+	struct gpio_port *port = irq_data_get_irq_chip_data(d);
+
+	if (!port && !port->pint && port->pint->irq != d->irq)
+		return -EINVAL;
+
+#ifndef SEC_GCTL
+	adi_internal_set_wake(port->pint->irq, state);
+#endif
+
+	return 0;
+}
+
+static int adi_pint_suspend(void)
+{
+	struct gpio_pint *pint;
+
+	list_for_each_entry(pint, &adi_pint_list, node) {
+		writel(0xffffffff, &pint->regs->mask_clear);
+		pint->saved_data.assign = readl(&pint->regs->assign);
+		pint->saved_data.edge_set = readl(&pint->regs->edge_set);
+		pint->saved_data.invert_set = readl(&pint->regs->invert_set);
+	}
+
+	return 0;
+}
+
+static void adi_pint_resume(void)
+{
+	struct gpio_pint *pint;
+
+	list_for_each_entry(pint, &adi_pint_list, node) {
+		writel(pint->saved_data.assign, &pint->regs->assign);
+		writel(pint->saved_data.edge_set, &pint->regs->edge_set);
+		writel(pint->saved_data.invert_set, &pint->regs->invert_set);
+	}
+}
+
+static int adi_gpio_suspend(void)
+{
+	struct adi_pmx *pmx;
+	struct gpio_port *port;
+
+	list_for_each_entry(pmx, &adi_pinctrl_list, node)
+		list_for_each_entry(port, &pmx->gpio_list, node) {
+			port->saved_data.fer = readw(&port->regs->port_fer);
+			port->saved_data.mux = readl(&port->regs->port_mux);
+			port->saved_data.data = readw(&port->regs->data);
+			port->saved_data.inen = readw(&port->regs->inen);
+			port->saved_data.dir = readw(&port->regs->dir_set);
+		}
+
+	return adi_pint_suspend();
+}
+
+static void adi_gpio_resume(void)
+{
+	struct adi_pmx *pmx;
+	struct gpio_port *port;
+
+	adi_pint_resume();
+
+	list_for_each_entry(pmx, &adi_pinctrl_list, node)
+		list_for_each_entry(port, &pmx->gpio_list, node) {
+			writel(port->saved_data.mux, &port->regs->port_mux);
+			writew(port->saved_data.fer, &port->regs->port_fer);
+			writew(port->saved_data.inen, &port->regs->inen);
+			writew(port->saved_data.data & port->saved_data.dir,
+						&port->regs->data_set);
+			writew(port->saved_data.dir, &port->regs->dir_set);
+		}
+
+}
+
+static struct syscore_ops gpio_pm_syscore_ops = {
+	.suspend = adi_gpio_suspend,
+	.resume = adi_gpio_resume,
+};
+#else /* CONFIG_PM */
+#define adi_gpio_set_wake NULL
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_IRQ_PREFLOW_FASTEOI
+static inline void preflow_handler(struct irq_desc *desc)
+{
+	if (desc->preflow_handler)
+		desc->preflow_handler(&desc->irq_data);
+}
+#else
+static inline void preflow_handler(struct irq_desc *desc) { }
+#endif
+
+static void adi_gpio_handle_pint_irq(unsigned int inta_irq,
+			struct irq_desc *desc)
+{
+	u32 request;
+	u32 level_mask, hwirq;
+	int umask = 0;
+	struct gpio_pint *pint = irq_desc_get_handler_data(desc);
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	struct gpio_pint_regs *regs = pint->regs;
+	struct irq_domain *domain;
+
+	preflow_handler(desc);
+	chained_irq_enter(chip, desc);
+
+	request = readl(&regs->request);
+	level_mask = readl(&regs->edge_set) & request;
+
+	hwirq = 0;
+	domain = pint->domain[0];
+	while (request) {
+		if (hwirq == PINT_HI_OFFSET)
+			domain = pint->domain[1];
+
+		if (request & 1) {
+			if (level_mask & (1 << hwirq)) {
+				umask = 1;
+				chained_irq_exit(chip, desc);
+			}
+			generic_handle_irq(irq_find_mapping(domain,
+					hwirq % PINT_HI_OFFSET));
+		}
+
+		hwirq++;
+		request >>= 1;
+	}
+
+	if (!umask)
+		chained_irq_exit(chip, desc);
+}
+
+static struct irq_chip adi_gpio_irqchip = {
+	.name = "GPIO",
+	.irq_ack = adi_gpio_ack_irq,
+	.irq_mask = adi_gpio_mask_irq,
+	.irq_mask_ack = adi_gpio_mask_ack_irq,
+	.irq_unmask = adi_gpio_unmask_irq,
+	.irq_disable = adi_gpio_mask_irq,
+	.irq_enable = adi_gpio_unmask_irq,
+	.irq_set_type = adi_gpio_irq_type,
+	.irq_startup = adi_gpio_irq_startup,
+	.irq_shutdown = adi_gpio_irq_shutdown,
+	.irq_set_wake = adi_gpio_set_wake,
+};
+
+
+static int adi_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	return ARRAY_SIZE(adi_pin_groups);
+}
+
+static const char *adi_get_group_name(struct pinctrl_dev *pctldev,
+				       unsigned selector)
+{
+	return adi_pin_groups[selector].name;
+}
+
+static int adi_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
+			       const unsigned **pins,
+			       unsigned *num_pins)
+{
+	*pins = adi_pin_groups[selector].pins;
+	*num_pins = adi_pin_groups[selector].num;
+	return 0;
+}
+
+static void adi_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+		   unsigned offset)
+{
+	seq_puts(s, DRIVER_NAME);
+}
+
+static struct pinctrl_ops adi_pctrl_ops = {
+	.get_groups_count = adi_get_groups_count,
+	.get_group_name = adi_get_group_name,
+	.get_group_pins = adi_get_group_pins,
+	.pin_dbg_show = adi_pin_dbg_show,
+};
+
+static int adi_pinmux_request(struct pinctrl_dev *pctldev, unsigned pin)
+{
+	struct adi_pmx *pmx;
+	struct gpio_port *port;
+	unsigned long flags;
+	struct pin_desc *desc;
+	u8 offset;
+
+	pmx = pinctrl_dev_get_drvdata(pctldev);
+
+	port = find_gpio_port(pin, &pmx->gpio_list);
+	if (port == NULL) {
+		dev_err(pctldev->dev,
+		       "%s: Peripheral PIN %d doesn't exist!\n",
+		       __func__, pin);
+		return -ENODEV;
+	}
+
+	offset = pin_to_offset(&port->range, pin);
+	desc = radix_tree_lookup(&pctldev->pin_desc_tree, pin);
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	/* If a pin can be muxed as either GPIO or peripheral, make
+	 * sure it is not already a GPIO pin when we request it.
+	 */
+	if (unlikely(is_reserved(port, RSV_GPIO, offset))) {
+		if (system_state == SYSTEM_BOOTING)
+			dump_stack();
+		dev_err(pctldev->dev,
+		       "%s: Peripheral PIN %d is already reserved as GPIO by %s!\n",
+		       __func__, pin, get_label(port, offset));
+		spin_unlock_irqrestore(&port->lock, flags);
+		return -EBUSY;
+	}
+
+	if (unlikely(is_reserved(port, RSV_PERI, offset))) {
+		if (system_state == SYSTEM_BOOTING)
+			dump_stack();
+		dev_err(pctldev->dev,
+			"%s: Peripheral PIN %d is already reserved by %s!\n",
+			__func__, pin, get_label(port, offset));
+		spin_unlock_irqrestore(&port->lock, flags);
+		return -EBUSY;
+	}
+
+	reserve(port, RSV_PERI, offset);
+	set_label(port, offset, desc->mux_owner);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return 0;
+}
+
+static int adi_pinmux_free(struct pinctrl_dev *pctldev, unsigned pin)
+{
+	struct adi_pmx *pmx;
+	struct gpio_port *port;
+	unsigned long flags;
+	u8 offset;
+
+	pmx = pinctrl_dev_get_drvdata(pctldev);
+	port = find_gpio_port(pin, &pmx->gpio_list);
+	if (port == NULL)
+		return 0;
+
+	offset = pin_to_offset(&port->range, pin);
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	if (unlikely(!is_reserved(port, RSV_PERI, offset))) {
+		spin_unlock_irqrestore(&port->lock, flags);
+		return 0;
+	}
+
+	unreserve(port, RSV_PERI, offset);
+	set_label(port, offset, "free");
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return 0;
+}
+
+static int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector,
+	unsigned group)
+{
+	struct adi_pmx *pmx;
+	struct gpio_port *port;
+	unsigned long flags;
+	unsigned short *mux = (unsigned short *)adi_pmx_functions[selector].mux;
+	unsigned short gpio;
+
+	pmx = pinctrl_dev_get_drvdata(pctldev);
+
+	while (*mux) {
+		gpio = P_IDENT(*mux);
+
+		port = find_gpio_port(gpio - pmx->gpio_base, &pmx->gpio_list);
+		if (port == NULL) /* should not happen */
+			continue;
+
+		spin_lock_irqsave(&port->lock, flags);
+
+		portmux_setup(port, gpio_to_offset(port, gpio),
+				 P_FUNCT2MUX(*mux));
+		port_setup(port, gpio_to_offset(port, gpio), PERIPHERAL_USAGE);
+		mux++;
+
+		spin_unlock_irqrestore(&port->lock, flags);
+	}
+
+	return 0;
+}
+
+static void adi_pinmux_disable(struct pinctrl_dev *pctldev, unsigned selector,
+	unsigned group)
+{
+	struct adi_pmx *pmx;
+	struct gpio_port *port;
+	unsigned long flags;
+	unsigned short *mux = (unsigned short *)adi_pmx_functions[selector].mux;
+	unsigned short gpio;
+
+	pmx = pinctrl_dev_get_drvdata(pctldev);
+
+	while (*mux) {
+		gpio = P_IDENT(*mux);
+
+		port = find_gpio_port(gpio - pmx->gpio_base, &pmx->gpio_list);
+		if (port == NULL) /* should not happen */
+			continue;
+
+		spin_lock_irqsave(&port->lock, flags);
+
+		port_setup(port, gpio_to_offset(port, gpio), GPIO_USAGE);
+		mux++;
+
+		spin_unlock_irqrestore(&port->lock, flags);
+	}
+}
+
+static int adi_pinmux_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+	return ARRAY_SIZE(adi_pmx_functions);
+}
+
+static const char *adi_pinmux_get_func_name(struct pinctrl_dev *pctldev,
+					  unsigned selector)
+{
+	return adi_pmx_functions[selector].name;
+}
+
+static int adi_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
+			       const char * const **groups,
+			       unsigned * const num_groups)
+{
+	*groups = adi_pmx_functions[selector].groups;
+	*num_groups = adi_pmx_functions[selector].num_groups;
+	return 0;
+}
+
+static int adi_pinmux_request_gpio(struct pinctrl_dev *pctldev,
+	struct pinctrl_gpio_range *range, unsigned pin)
+{
+	struct adi_pmx *pmx;
+	struct gpio_port *port;
+	unsigned long flags;
+	u8 offset;
+
+	pmx = pinctrl_dev_get_drvdata(pctldev);
+	port = find_gpio_port(pin, &pmx->gpio_list);
+	if (port == NULL) {
+		dev_err(pctldev->dev,
+		       "%s: GPIO PIN %d doesn't exist!\n",
+		       __func__, pin);
+		return -ENODEV;
+	}
+
+	offset = pin_to_offset(&port->range, pin);
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	if (unlikely(is_reserved(port, RSV_GPIO, offset))) {
+		if (system_state == SYSTEM_BOOTING)
+			dump_stack();
+		dev_err(pctldev->dev,
+			"GPIO %d is already reserved by %s !\n",
+			offset_to_gpio(port, offset), get_label(port, offset));
+		spin_unlock_irqrestore(&port->lock, flags);
+		return -EBUSY;
+	}
+	if (unlikely(is_reserved(port, RSV_PERI, offset))) {
+		if (system_state == SYSTEM_BOOTING)
+			dump_stack();
+		dev_err(pctldev->dev,
+			"GPIO %d is already reserved as peripheral by %s !\n",
+			offset_to_gpio(port, offset), get_label(port, offset));
+		spin_unlock_irqrestore(&port->lock, flags);
+		return -EBUSY;
+	}
+	if (unlikely(is_reserved(port, RSV_INT, offset))) {
+		dev_err(pctldev->dev,
+			"GPIO %d is already reserved as gpio-irq!\n",
+			offset_to_gpio(port, offset));
+	}
+
+	reserve(port, RSV_GPIO, offset);
+	set_label(port, offset, port->chip.label);
+	port_setup(port, offset, GPIO_USAGE);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return 0;
+}
+
+static void adi_pinmux_free_gpio(struct pinctrl_dev *pctldev,
+	struct pinctrl_gpio_range *range, unsigned pin)
+{
+	struct adi_pmx *pmx;
+	struct gpio_port *port;
+	unsigned long flags;
+	u8 offset;
+
+	pmx = pinctrl_dev_get_drvdata(pctldev);
+	port = find_gpio_port(pin, &pmx->gpio_list);
+	if (port == NULL)
+		return;
+
+	offset = pin_to_offset(&port->range, pin);
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	if (unlikely(!is_reserved(port, RSV_GPIO, offset))) {
+		if (system_state == SYSTEM_BOOTING)
+			dump_stack();
+
+		dev_err(pctldev->dev,
+			"GPIO %d wasn't requested!\n",
+			offset_to_gpio(port, offset));
+		spin_unlock_irqrestore(&port->lock, flags);
+		return;
+	}
+
+	unreserve(port, RSV_GPIO, offset);
+	set_label(port, offset, "free");
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return;
+}
+
+static struct pinmux_ops adi_pinmux_ops = {
+	.request = adi_pinmux_request,
+	.free = adi_pinmux_free,
+	.enable = adi_pinmux_enable,
+	.disable = adi_pinmux_disable,
+	.get_functions_count = adi_pinmux_get_funcs_count,
+	.get_function_name = adi_pinmux_get_func_name,
+	.get_function_groups = adi_pinmux_get_groups,
+	.gpio_request_enable = adi_pinmux_request_gpio,
+	.gpio_disable_free = adi_pinmux_free_gpio,
+};
+
+
+static struct pinctrl_desc adi_pinmux_desc = {
+	.name = DRIVER_NAME,
+	.pins = adi_pads,
+	.npins = ARRAY_SIZE(adi_pads),
+	.pctlops = &adi_pctrl_ops,
+	.pmxops = &adi_pinmux_ops,
+	.owner = THIS_MODULE,
+};
+
+static int adi_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	struct gpio_port *port;
+
+	port = container_of(chip, struct gpio_port, chip);
+
+	return pinctrl_request_gpio(offset_to_gpio(port, offset));
+}
+
+static void adi_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+	struct gpio_port *port;
+
+	port = container_of(chip, struct gpio_port, chip);
+
+	pinctrl_free_gpio(offset_to_gpio(port, offset));
+}
+
+static int adi_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	struct gpio_port *port;
+	unsigned long flags;
+
+	port = container_of(chip, struct gpio_port, chip);
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	if (unlikely(!is_reserved(port, RSV_GPIO, offset))) {
+		dev_err(port->dev, "GPIO %d wasn't requested!\n",
+			offset_to_gpio(port, offset));
+		spin_unlock_irqrestore(&port->lock, flags);
+		return -EINVAL;
+	}
+
+	writew(1 << offset, &port->regs->dir_clear);
+	writew(readw(&port->regs->inen) | (1 << offset), &port->regs->inen);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return 0;
+}
+
+static void adi_gpio_set_value(struct gpio_chip *chip, unsigned offset,
+	int value)
+{
+	struct gpio_port *port = container_of(chip, struct gpio_port, chip);
+	struct gpio_port_t *regs = port->regs;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	if (value)
+		writew(1 << offset, &regs->data_set);
+	else
+		writew(1 << offset, &regs->data_clear);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int adi_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+	int value)
+{
+	struct gpio_port *port = container_of(chip, struct gpio_port, chip);
+	struct gpio_port_t *regs = port->regs;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	if (unlikely(!is_reserved(port, RSV_GPIO, offset))) {
+		dev_err(port->dev, "GPIO %d wasn't requested!\n",
+			offset_to_gpio(port, offset));
+		spin_unlock_irqrestore(&port->lock, flags);
+		return -EINVAL;
+	}
+
+	writew(readw(&regs->inen) & ~(1 << offset), &regs->inen);
+	adi_gpio_set_value(chip, offset, value);
+	writew(1 << offset, &regs->dir_set);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return 0;
+}
+
+static int adi_gpio_get_value(struct gpio_chip *chip, unsigned offset)
+{
+	struct gpio_port *port = container_of(chip, struct gpio_port, chip);
+	struct gpio_port_t *regs = port->regs;
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	ret = 1 & (readw(&regs->data) >> offset);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return ret;
+}
+
+static int adi_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	struct gpio_port *port = container_of(chip, struct gpio_port, chip);
+
+	if (port->irq_base >= 0)
+		return irq_find_mapping(port->domain, offset);
+	else
+		return irq_create_mapping(port->domain, offset);
+}
+
+#if defined(CONFIG_PROC_FS)
+static inline unsigned short get_gpio_dir(struct gpio_port *port,
+	unsigned offset)
+{
+	struct gpio_port_t *regs = port->regs;
+
+	return 1 & (readw(&regs->dir_clear) >> offset);
+}
+
+static int gpio_proc_show(struct seq_file *m, void *v)
+{
+	int offset, irq, gpio;
+	struct adi_pmx *pmx;
+	struct gpio_port *port;
+
+	list_for_each_entry(pmx, &adi_pinctrl_list, node)
+	list_for_each_entry(port, &pmx->gpio_list, node)
+		for (offset = 0; offset < port->width; offset++) {
+			irq = is_reserved(port, RSV_INT, offset);
+			gpio = is_reserved(port, RSV_GPIO, offset);
+			if (gpio || irq)
+				seq_printf(m, "GPIO_%d: \t%s%s \t\tGPIO %s\n",
+					offset_to_gpio(port, offset),
+					get_label(port, offset),
+					(gpio && irq) ? " *" : "",
+					get_gpio_dir(port, offset) ?
+					"OUTPUT" : "INPUT");
+			else if (is_reserved(port, RSV_PERI, offset))
+				seq_printf(m, "GPIO_%d: \t%s \t\tPeripheral\n",
+					offset_to_gpio(port, offset),
+					get_label(port, offset));
+			else
+				continue;
+		}
+
+	return 0;
+}
+
+static int gpio_proc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, gpio_proc_show, NULL);
+}
+
+static const struct file_operations gpio_proc_ops = {
+	.open		= gpio_proc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static __init int gpio_register_proc(void)
+{
+	struct proc_dir_entry *proc_gpio;
+
+	proc_gpio = proc_create("gpio", 0, NULL, &gpio_proc_ops);
+	return proc_gpio == NULL;
+}
+device_initcall(gpio_register_proc);
+#endif
+
+static int adi_pint_map_port(struct gpio_pint *pint, u8 assign, u8 map,
+	struct irq_domain *domain)
+{
+	struct gpio_pint_regs *regs = pint->regs;
+
+	if (pint->map_count > 1)
+		return -EINVAL;
+
+	if (assign > 1)
+		return -EINVAL;
+
+	pint->map_count++;
+
+	writel((readl(&regs->assign) & (0xFFFF << !assign * PINT_HI_OFFSET)) |
+		(((map << 8) | map) << assign * PINT_HI_OFFSET), &regs->assign);
+
+	pint->domain[assign] = domain;
+
+	return 0;
+}
+
+static int adi_gpio_pint_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	struct gpio_pint *pint;
+
+	pint = devm_kzalloc(dev, sizeof(struct gpio_pint), GFP_KERNEL);
+	if (!pint) {
+		dev_err(dev, "Memory alloc failed\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (unlikely(!res)) {
+		dev_err(dev, "Invalid mem resource\n");
+		return -ENODEV;
+	}
+
+	if (!devm_request_mem_region(dev, res->start, resource_size(res),
+				     pdev->name)) {
+		dev_err(dev, "Region already claimed\n");
+		return -EBUSY;
+	}
+
+	pint->base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!pint->base) {
+		dev_err(dev, "Could not ioremap\n");
+		return -ENOMEM;
+	}
+
+	pint->regs = (struct gpio_pint_regs *)pint->base;
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (unlikely(!res)) {
+		dev_err(dev, "Invalid IRQ resource\n");
+		return -ENODEV;
+	}
+
+	spin_lock_init(&pint->lock);
+
+	pint->irq = res->start;
+	pint->pint_map_port = adi_pint_map_port;
+	platform_set_drvdata(pdev, pint);
+
+	irq_set_chained_handler(pint->irq, adi_gpio_handle_pint_irq);
+	irq_set_handler_data(pint->irq, pint);
+
+	list_add_tail(&pint->node, &adi_pint_list);
+
+	return 0;
+}
+
+static int adi_gpio_pint_remove(struct platform_device *pdev)
+{
+	struct gpio_pint *pint = platform_get_drvdata(pdev);
+
+	list_del(&pint->node);
+	irq_set_handler(pint->irq, handle_simple_irq);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static int adi_gpio_irq_map(struct irq_domain *d, unsigned int irq,
+				irq_hw_number_t hwirq)
+{
+	struct gpio_port *port = d->host_data;
+
+	if (!port)
+		return -EINVAL;
+
+	irq_set_chip_data(irq, port);
+	irq_set_chip_and_handler(irq, &adi_gpio_irqchip,
+				handle_level_irq);
+
+	return 0;
+}
+
+const struct irq_domain_ops adi_gpio_irq_domain_ops = {
+	.map = adi_gpio_irq_map,
+	.xlate = irq_domain_xlate_onecell,
+};
+
+static int adi_gpio_init_int(struct gpio_port *port)
+{
+	struct device_node *node = port->dev->of_node;
+	struct gpio_pint *pint = port->pint;
+	int ret;
+
+	port->domain = irq_domain_add_linear(node, port->width,
+				&adi_gpio_irq_domain_ops, port);
+	if (!port->domain) {
+		dev_err(port->dev, "Failed to create irqdomain\n");
+		return -ENOSYS;
+	}
+
+	ret = pint->pint_map_port(port->pint, port->pint_assign,
+			port->pint_map,	port->domain);
+	if (ret)
+		return ret;
+
+	if (port->irq_base >= 0) {
+		ret = irq_create_strict_mappings(port->domain, port->irq_base,
+					0, port->width);
+		if (ret) {
+			dev_err(port->dev, "Couldn't associate to domain\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int adi_gpio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	const struct adi_pinctrl_gpio_platform_data *pdata;
+	struct resource *res;
+	struct gpio_port *port;
+	static int gpio;
+	int ret = 0;
+
+	pdata = dev->platform_data;
+	if (!pdata)
+		return -EINVAL;
+
+	port = devm_kzalloc(dev, sizeof(struct gpio_port) +
+		sizeof(struct gpio_reserve_map) * pdata->port_width,
+		GFP_KERNEL);
+	if (!port) {
+		dev_err(dev, "Memory alloc failed\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (unlikely(!res)) {
+		dev_err(dev, "Invalid mem resource\n");
+		return -ENODEV;
+	}
+
+	if (!devm_request_mem_region(dev, res->start, resource_size(res),
+				     pdev->name)) {
+		dev_err(dev, "Region already claimed\n");
+		return -EBUSY;
+	}
+
+	port->base = devm_ioremap(dev, res->start, resource_size(res));
+	if (!port->base) {
+		dev_err(dev, "Could not ioremap\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (unlikely(!res))
+		port->irq_base = -1;
+	else
+		port->irq_base = res->start;
+
+	port->width = pdata->port_width;
+	port->dev = dev;
+	port->regs = (struct gpio_port_t *)port->base;
+	port->pint_assign = !!pdata->pint_assign;
+	port->pint_map = pdata->pint_map;
+
+	port->pint = find_gpio_pint(pdata->pint_id);
+	if (port->pint) {
+		ret = adi_gpio_init_int(port);
+		if (ret)
+			return ret;
+	}
+
+	port->pmx = find_pinctrl(pdata->pinctrl_id);
+	if (port->pmx == NULL) {
+		dev_err(dev, "Could not find pinctrl device\n");
+		return -ENODEV;
+	}
+	if (gpio == 0)
+		gpio = port->pmx->gpio_base;
+
+	spin_lock_init(&port->lock);
+
+	platform_set_drvdata(pdev, port);
+
+	port->chip.label		= "adi-gpio";
+	port->chip.direction_input	= adi_gpio_direction_input;
+	port->chip.get			= adi_gpio_get_value;
+	port->chip.direction_output	= adi_gpio_direction_output;
+	port->chip.set			= adi_gpio_set_value;
+	port->chip.request		= adi_gpio_request;
+	port->chip.free			= adi_gpio_free;
+	port->chip.to_irq		= adi_gpio_to_irq;
+	if (pdata->port_pin_base > 0)
+		port->chip.base		= pdata->port_pin_base +
+						port->pmx->gpio_base;
+	else
+		port->chip.base		= gpio;
+	port->chip.ngpio		= port->width;
+	gpio = port->chip.base + port->width;
+
+	ret = gpiochip_add(&port->chip);
+	if (ret)
+		return ret;
+
+	/* Set gpio range to pinctrl driver */
+	port->range.name = port->chip.label;
+	port->range.id = pdev->id;
+	port->range.base = port->chip.base;
+	port->range.pin_base = port->chip.base - port->pmx->gpio_base;
+	port->range.npins = port->width;
+	port->range.gc = &port->chip;
+	pinctrl_add_gpio_range(port->pmx->pctl, &port->range);
+
+	list_add_tail(&port->node, &port->pmx->gpio_list);
+
+	return 0;
+}
+
+static int adi_gpio_remove(struct platform_device *pdev)
+{
+	struct gpio_port *port = platform_get_drvdata(pdev);
+	int ret;
+	u8 offset;
+
+	for (offset = 0; offset < port->width; offset++)
+		irq_dispose_mapping(irq_find_mapping(port->domain, offset));
+
+	irq_domain_remove(port->domain);
+	pinctrl_remove_gpio_range(port->pmx->pctl, &port->range);
+	list_del(&port->node);
+	ret = gpiochip_remove(&port->chip);
+	platform_set_drvdata(pdev, NULL);
+
+	return ret;
+}
+
+static int adi_pinctrl_probe(struct platform_device *pdev)
+{
+	struct adi_pmx *pmx;
+	struct resource *res;
+
+	pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
+	if (!pmx)
+		return -ENOMEM;
+
+	pmx->dev = &pdev->dev;
+
+	/* Now register the pin controller and all pins it handles */
+	pmx->pctl = pinctrl_register(&adi_pinmux_desc, &pdev->dev, pmx);
+	if (!pmx->pctl) {
+		dev_err(&pdev->dev, "could not register pinctrl ADI2 driver\n");
+		return -EINVAL;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (res)
+		pmx->gpio_base = res->start;
+
+	INIT_LIST_HEAD(&pmx->gpio_list);
+
+	list_add_tail(&pmx->node, &adi_pinctrl_list);
+
+	return 0;
+}
+
+static int adi_pinctrl_remove(struct platform_device *pdev)
+{
+	struct adi_pmx *pmx = platform_get_drvdata(pdev);
+
+	list_del(&pmx->node);
+	pinctrl_unregister(pmx->pctl);
+	platform_set_drvdata(pdev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver adi_pinctrl_driver = {
+	.probe		= adi_pinctrl_probe,
+	.remove		= adi_pinctrl_remove,
+	.driver		= {
+		.name	= DRIVER_NAME,
+	},
+};
+
+static struct platform_driver adi_gpio_pint_driver = {
+	.probe		= adi_gpio_pint_probe,
+	.remove		= adi_gpio_pint_remove,
+	.driver		= {
+		.name	= "adi-gpio-pint",
+	},
+};
+
+static struct platform_driver adi_gpio_driver = {
+	.probe		= adi_gpio_probe,
+	.remove		= adi_gpio_remove,
+	.driver		= {
+		.name	= "adi-gpio",
+	},
+};
+
+static int __init adi_pinctrl_setup(void)
+{
+	int ret;
+
+	ret = platform_driver_register(&adi_pinctrl_driver);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&adi_gpio_pint_driver);
+	if (ret)
+		goto pint_error;
+
+	ret = platform_driver_register(&adi_gpio_driver);
+	if (ret)
+		goto gpio_error;
+
+#ifdef CONFIG_PM
+	register_syscore_ops(&gpio_pm_syscore_ops);
+#endif
+	return ret;
+gpio_error:
+	platform_driver_unregister(&adi_gpio_pint_driver);
+pint_error:
+	platform_driver_unregister(&adi_pinctrl_driver);
+
+	return ret;
+}
+postcore_initcall(adi_pinctrl_setup);
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("ADI gpio2 pin control driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/platform_data/pinctrl-adi2.h b/include/linux/platform_data/pinctrl-adi2.h
new file mode 100644
index 0000000..465578e
--- /dev/null
+++ b/include/linux/platform_data/pinctrl-adi2.h
@@ -0,0 +1,38 @@
+/*
+ * Pinctrl Driver for ADI GPIO2 controller
+ *
+ * Copyright 2007-2013 Analog Devices Inc.
+ *
+ * Licensed under the GPLv2 or later
+ */
+
+
+#ifndef PINCTRL_ADI2_H
+#define PINCTRL_ADI2_H
+
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+/**
+ * struct adi_pinctrl_gpio_platform_data - Pinctrl gpio platform data
+ * for ADI GPIO2 device.
+ *
+ * @port_pin_base: Optional global GPIO index of the GPIO bank.
+ *                 0 means driver decides.
+ * @port_width: PIN number of the GPIO bank device
+ * @pint_id: GPIO PINT device id that this GPIO bank should map to.
+ * @pint_assign: The 32-bit GPIO PINT registers can be divided into 2 parts. A
+ *               GPIO bank can be mapped into either low 16 bits[0] or high 16
+ *               bits[1] of each PINT register.
+ * @pint_map: GIOP bank mapping code in PINT device
+ */
+struct adi_pinctrl_gpio_platform_data {
+	unsigned int port_pin_base;
+	unsigned int port_width;
+	u8 pinctrl_id;
+	u8 pint_id;
+	u8 pint_assign;
+	u8 pint_map;
+};
+
+#endif
-- 
1.8.2.3



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

* [PATCH 2/3] blackfin: gpio: Remove none gpio lib code.
  2013-07-16 10:55 [PATCH 1/3] pinctrl: ADI PIN control driver for the GPIO controller on bf54x and bf60x Sonic Zhang
@ 2013-07-16 10:55 ` Sonic Zhang
  2013-07-23  7:33   ` Sonic Zhang
                     ` (2 more replies)
  2013-07-16 10:55 ` [PATCH 3/3] blackfin: pinctrl-adi2: Add pin control device groups and function data Sonic Zhang
                   ` (3 subsequent siblings)
  4 siblings, 3 replies; 17+ messages in thread
From: Sonic Zhang @ 2013-07-16 10:55 UTC (permalink / raw)
  To: Linus Walleij, Grant Likely, Steven Miao
  Cc: LKML, buildroot-devel, adi-buildroot-devel, Sonic Zhang

From: Sonic Zhang <sonic.zhang@analog.com>

- Remove non gpio lib code from blackfin architecture.
- Limit the lagecy blackfin gpio driver to bf5xx processors only.
- Remove unused definition of the pint power functions.

Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
---
 arch/blackfin/Kconfig            |   7 ++
 arch/blackfin/include/asm/gpio.h | 157 +++++----------------------------------
 2 files changed, 27 insertions(+), 137 deletions(-)

diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index 3b6abc5..9307e7a 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -53,6 +53,9 @@ config GENERIC_BUG
 config ZONE_DMA
 	def_bool y
 
+config GENERIC_GPIO
+	def_bool y
+
 config FORCE_MAX_ZONEORDER
 	int
 	default "14"
@@ -318,6 +321,10 @@ config BF53x
 	depends on (BF531 || BF532 || BF533 || BF534 || BF536 || BF537)
 	default y
 
+config GPIO_ADI
+	def_bool y
+	depends on (BF51x || BF52x || BF53x || BF538 || BF539 || BF561)
+
 config MEM_MT48LC64M4A2FB_7E
 	bool
 	depends on (BFIN533_STAMP)
diff --git a/arch/blackfin/include/asm/gpio.h b/arch/blackfin/include/asm/gpio.h
index 98d0133..99d338c 100644
--- a/arch/blackfin/include/asm/gpio.h
+++ b/arch/blackfin/include/asm/gpio.h
@@ -25,8 +25,12 @@
 
 #ifndef __ASSEMBLY__
 
+#ifndef CONFIG_PINCTRL
+
 #include <linux/compiler.h>
-#include <linux/gpio.h>
+#include <asm/blackfin.h>
+#include <asm/portmux.h>
+#include <asm/irq_handler.h>
 
 /***********************************************************
 *
@@ -45,7 +49,6 @@
 * MODIFICATION HISTORY :
 **************************************************************/
 
-#if !BFIN_GPIO_PINT
 void set_gpio_dir(unsigned, unsigned short);
 void set_gpio_inen(unsigned, unsigned short);
 void set_gpio_polar(unsigned, unsigned short);
@@ -115,7 +118,6 @@ struct gpio_port_t {
 	unsigned short dummy16;
 	unsigned short inen;
 };
-#endif
 
 #ifdef BFIN_SPECIAL_GPIO_BANKS
 void bfin_special_gpio_free(unsigned gpio);
@@ -127,25 +129,21 @@ void bfin_special_gpio_pm_hibernate_suspend(void);
 #endif
 
 #ifdef CONFIG_PM
-int bfin_pm_standby_ctrl(unsigned ctrl);
+void bfin_gpio_pm_hibernate_restore(void);
+void bfin_gpio_pm_hibernate_suspend(void);
+int bfin_gpio_pm_wakeup_ctrl(unsigned gpio, unsigned ctrl);
+int bfin_gpio_pm_standby_ctrl(unsigned ctrl);
 
 static inline int bfin_pm_standby_setup(void)
 {
-	return bfin_pm_standby_ctrl(1);
+	return bfin_gpio_pm_standby_ctrl(1);
 }
 
 static inline void bfin_pm_standby_restore(void)
 {
-	bfin_pm_standby_ctrl(0);
+	bfin_gpio_pm_standby_ctrl(0);
 }
 
-void bfin_gpio_pm_hibernate_restore(void);
-void bfin_gpio_pm_hibernate_suspend(void);
-void bfin_pint_suspend(void);
-void bfin_pint_resume(void);
-
-# if !BFIN_GPIO_PINT
-int gpio_pm_wakeup_ctrl(unsigned gpio, unsigned ctrl);
 
 struct gpio_port_s {
 	unsigned short data;
@@ -161,7 +159,6 @@ struct gpio_port_s {
 	unsigned short reserved;
 	unsigned short mux;
 };
-# endif
 #endif /*CONFIG_PM*/
 
 /***********************************************************
@@ -178,36 +175,29 @@ struct gpio_port_s {
 *************************************************************
 * MODIFICATION HISTORY :
 **************************************************************/
-
-int bfin_gpio_request(unsigned gpio, const char *label);
-void bfin_gpio_free(unsigned gpio);
 int bfin_gpio_irq_request(unsigned gpio, const char *label);
 void bfin_gpio_irq_free(unsigned gpio);
-int bfin_gpio_direction_input(unsigned gpio);
-int bfin_gpio_direction_output(unsigned gpio, int value);
-int bfin_gpio_get_value(unsigned gpio);
-void bfin_gpio_set_value(unsigned gpio, int value);
+void bfin_gpio_irq_prepare(unsigned gpio);
+
+static inline int irq_to_gpio(unsigned irq)
+{
+	return irq - GPIO_IRQ_BASE;
+}
+#endif /* CONFIG_PINCTRL */
 
 #include <asm/irq.h>
 #include <asm/errno.h>
 
-#ifdef CONFIG_GPIOLIB
 #include <asm-generic/gpio.h>		/* cansleep wrappers */
 
 static inline int gpio_get_value(unsigned int gpio)
 {
-	if (gpio < MAX_BLACKFIN_GPIOS)
-		return bfin_gpio_get_value(gpio);
-	else
-		return __gpio_get_value(gpio);
+	return __gpio_get_value(gpio);
 }
 
 static inline void gpio_set_value(unsigned int gpio, int value)
 {
-	if (gpio < MAX_BLACKFIN_GPIOS)
-		bfin_gpio_set_value(gpio, value);
-	else
-		__gpio_set_value(gpio, value);
+	__gpio_set_value(gpio, value);
 }
 
 static inline int gpio_cansleep(unsigned int gpio)
@@ -219,113 +209,6 @@ static inline int gpio_to_irq(unsigned gpio)
 {
 	return __gpio_to_irq(gpio);
 }
-
-#else /* !CONFIG_GPIOLIB */
-
-static inline int gpio_request(unsigned gpio, const char *label)
-{
-	return bfin_gpio_request(gpio, label);
-}
-
-static inline void gpio_free(unsigned gpio)
-{
-	return bfin_gpio_free(gpio);
-}
-
-static inline int gpio_direction_input(unsigned gpio)
-{
-	return bfin_gpio_direction_input(gpio);
-}
-
-static inline int gpio_direction_output(unsigned gpio, int value)
-{
-	return bfin_gpio_direction_output(gpio, value);
-}
-
-static inline int gpio_set_debounce(unsigned gpio, unsigned debounce)
-{
-	return -EINVAL;
-}
-
-static inline int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
-{
-	int err;
-
-	err = bfin_gpio_request(gpio, label);
-	if (err)
-		return err;
-
-	if (flags & GPIOF_DIR_IN)
-		err = bfin_gpio_direction_input(gpio);
-	else
-		err = bfin_gpio_direction_output(gpio,
-			(flags & GPIOF_INIT_HIGH) ? 1 : 0);
-
-	if (err)
-		bfin_gpio_free(gpio);
-
-	return err;
-}
-
-static inline int gpio_request_array(const struct gpio *array, size_t num)
-{
-	int i, err;
-
-	for (i = 0; i < num; i++, array++) {
-		err = gpio_request_one(array->gpio, array->flags, array->label);
-		if (err)
-			goto err_free;
-	}
-	return 0;
-
-err_free:
-	while (i--)
-		bfin_gpio_free((--array)->gpio);
-	return err;
-}
-
-static inline void gpio_free_array(const struct gpio *array, size_t num)
-{
-	while (num--)
-		bfin_gpio_free((array++)->gpio);
-}
-
-static inline int __gpio_get_value(unsigned gpio)
-{
-	return bfin_gpio_get_value(gpio);
-}
-
-static inline void __gpio_set_value(unsigned gpio, int value)
-{
-	return bfin_gpio_set_value(gpio, value);
-}
-
-static inline int gpio_get_value(unsigned gpio)
-{
-	return __gpio_get_value(gpio);
-}
-
-static inline void gpio_set_value(unsigned gpio, int value)
-{
-	return __gpio_set_value(gpio, value);
-}
-
-static inline int gpio_to_irq(unsigned gpio)
-{
-	if (likely(gpio < MAX_BLACKFIN_GPIOS))
-		return gpio + GPIO_IRQ_BASE;
-
-	return -EINVAL;
-}
-
-#include <asm-generic/gpio.h>		/* cansleep wrappers */
-#endif	/* !CONFIG_GPIOLIB */
-
-static inline int irq_to_gpio(unsigned irq)
-{
-	return (irq - GPIO_IRQ_BASE);
-}
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* __ARCH_BLACKFIN_GPIO_H__ */
-- 
1.8.2.3



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

* [PATCH 3/3] blackfin: pinctrl-adi2: Add pin control device groups and function data.
  2013-07-16 10:55 [PATCH 1/3] pinctrl: ADI PIN control driver for the GPIO controller on bf54x and bf60x Sonic Zhang
  2013-07-16 10:55 ` [PATCH 2/3] blackfin: gpio: Remove none gpio lib code Sonic Zhang
@ 2013-07-16 10:55 ` Sonic Zhang
  2013-07-23  7:33   ` Sonic Zhang
                     ` (2 more replies)
  2013-07-23  7:32 ` [PATCH 1/3] pinctrl: ADI PIN control driver for the GPIO controller on bf54x and bf60x Sonic Zhang
                   ` (2 subsequent siblings)
  4 siblings, 3 replies; 17+ messages in thread
From: Sonic Zhang @ 2013-07-16 10:55 UTC (permalink / raw)
  To: Linus Walleij, Grant Likely, Steven Miao
  Cc: LKML, buildroot-devel, adi-buildroot-devel, Sonic Zhang

From: Sonic Zhang <sonic.zhang@analog.com>

Select PINCTRL_ADI2 for bf54x and bf60x by default.

Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
---
 arch/blackfin/Kconfig                           |   7 +
 arch/blackfin/include/asm/portmux.h             |  14 +-
 arch/blackfin/mach-bf548/include/mach/portmux.h | 595 +++++++++++++++++++++++-
 arch/blackfin/mach-bf609/include/mach/portmux.h | 477 ++++++++++++++++++-
 4 files changed, 1087 insertions(+), 6 deletions(-)

diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index 9307e7a..6a3c490 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -325,6 +325,13 @@ config GPIO_ADI
 	def_bool y
 	depends on (BF51x || BF52x || BF53x || BF538 || BF539 || BF561)
 
+config PINCTRL_ADI2
+	def_bool y
+	depends on (BF54x || BF60x)
+	select PINCTRL
+	select PINMUX
+	select IRQ_DOMAIN
+
 config MEM_MT48LC64M4A2FB_7E
 	bool
 	depends on (BFIN533_STAMP)
diff --git a/arch/blackfin/include/asm/portmux.h b/arch/blackfin/include/asm/portmux.h
index 9b1e2c3..6b3e71c 100644
--- a/arch/blackfin/include/asm/portmux.h
+++ b/arch/blackfin/include/asm/portmux.h
@@ -17,14 +17,24 @@
 #define P_MAYSHARE	0x2000
 #define P_DONTCARE	0x1000
 
-
+#ifdef CONFIG_PINCTRL
+#define peripheral_request(per, label) 0
+#define peripheral_free(per)
+#define peripheral_request_list(per, label) \
+	(pdev ? (IS_ERR(devm_pinctrl_get_select_default(&pdev->dev)) \
+	? -EINVAL : 0) : 0);
+#define peripheral_free_list(per)
+#else
 int peripheral_request(unsigned short per, const char *label);
 void peripheral_free(unsigned short per);
 int peripheral_request_list(const unsigned short per[], const char *label);
 void peripheral_free_list(const unsigned short per[]);
+#endif
 
-#include <asm/gpio.h>
+#include <linux/err.h>
+#include <linux/pinctrl/pinctrl.h>
 #include <mach/portmux.h>
+#include <linux/gpio.h>
 
 #ifndef P_SPORT2_TFS
 #define P_SPORT2_TFS P_UNDEF
diff --git a/arch/blackfin/mach-bf548/include/mach/portmux.h b/arch/blackfin/mach-bf548/include/mach/portmux.h
index e222462..9fab923 100644
--- a/arch/blackfin/mach-bf548/include/mach/portmux.h
+++ b/arch/blackfin/mach-bf548/include/mach/portmux.h
@@ -7,8 +7,6 @@
 #ifndef _MACH_PORTMUX_H_
 #define _MACH_PORTMUX_H_
 
-#define MAX_RESOURCES	MAX_BLACKFIN_GPIOS
-
 #define P_SPORT2_TFS	(P_DEFINED | P_IDENT(GPIO_PA0) | P_FUNCT(0))
 #define P_SPORT2_DTSEC	(P_DEFINED | P_IDENT(GPIO_PA1) | P_FUNCT(0))
 #define P_SPORT2_DTPRI	(P_DEFINED | P_IDENT(GPIO_PA2) | P_FUNCT(0))
@@ -317,4 +315,597 @@
 #define P_NAND_CLE	(P_DONTCARE)
 #define P_NAND_ALE	(P_DONTCARE)
 
+#ifdef CONFIG_PINCTRL
+
+#include <mach/gpio.h>
+#include <asm/blackfin.h>
+#include <asm/irq_handler.h>
+
+#define gpio_pint_regs bfin_pint_regs
+#define adi_internal_set_wake bfin_internal_set_wake
+
+static const struct pinctrl_pin_desc adi_pads[] = {
+	PINCTRL_PIN(0, "PA0"),
+	PINCTRL_PIN(1, "PA1"),
+	PINCTRL_PIN(2, "PA2"),
+	PINCTRL_PIN(3, "PG3"),
+	PINCTRL_PIN(4, "PA4"),
+	PINCTRL_PIN(5, "PA5"),
+	PINCTRL_PIN(6, "PA6"),
+	PINCTRL_PIN(7, "PA7"),
+	PINCTRL_PIN(8, "PA8"),
+	PINCTRL_PIN(9, "PA9"),
+	PINCTRL_PIN(10, "PA10"),
+	PINCTRL_PIN(11, "PA11"),
+	PINCTRL_PIN(12, "PA12"),
+	PINCTRL_PIN(13, "PA13"),
+	PINCTRL_PIN(14, "PA14"),
+	PINCTRL_PIN(15, "PA15"),
+	PINCTRL_PIN(16, "PB0"),
+	PINCTRL_PIN(17, "PB1"),
+	PINCTRL_PIN(18, "PB2"),
+	PINCTRL_PIN(19, "PB3"),
+	PINCTRL_PIN(20, "PB4"),
+	PINCTRL_PIN(21, "PB5"),
+	PINCTRL_PIN(22, "PB6"),
+	PINCTRL_PIN(23, "PB7"),
+	PINCTRL_PIN(24, "PB8"),
+	PINCTRL_PIN(25, "PB9"),
+	PINCTRL_PIN(26, "PB10"),
+	PINCTRL_PIN(27, "PB11"),
+	PINCTRL_PIN(28, "PB12"),
+	PINCTRL_PIN(29, "PB13"),
+	PINCTRL_PIN(30, "PB14"),
+	PINCTRL_PIN(32, "PC0"),
+	PINCTRL_PIN(33, "PC1"),
+	PINCTRL_PIN(34, "PC2"),
+	PINCTRL_PIN(35, "PC3"),
+	PINCTRL_PIN(36, "PC4"),
+	PINCTRL_PIN(37, "PC5"),
+	PINCTRL_PIN(38, "PC6"),
+	PINCTRL_PIN(39, "PC7"),
+	PINCTRL_PIN(40, "PC8"),
+	PINCTRL_PIN(41, "PC9"),
+	PINCTRL_PIN(42, "PC10"),
+	PINCTRL_PIN(43, "PC11"),
+	PINCTRL_PIN(44, "PC12"),
+	PINCTRL_PIN(45, "PC13"),
+	PINCTRL_PIN(48, "PD0"),
+	PINCTRL_PIN(49, "PD1"),
+	PINCTRL_PIN(50, "PD2"),
+	PINCTRL_PIN(51, "PD3"),
+	PINCTRL_PIN(52, "PD4"),
+	PINCTRL_PIN(53, "PD5"),
+	PINCTRL_PIN(54, "PD6"),
+	PINCTRL_PIN(55, "PD7"),
+	PINCTRL_PIN(56, "PD8"),
+	PINCTRL_PIN(57, "PD9"),
+	PINCTRL_PIN(58, "PD10"),
+	PINCTRL_PIN(59, "PD11"),
+	PINCTRL_PIN(60, "PD12"),
+	PINCTRL_PIN(61, "PD13"),
+	PINCTRL_PIN(62, "PD14"),
+	PINCTRL_PIN(63, "PD15"),
+	PINCTRL_PIN(64, "PE0"),
+	PINCTRL_PIN(65, "PE1"),
+	PINCTRL_PIN(66, "PE2"),
+	PINCTRL_PIN(67, "PE3"),
+	PINCTRL_PIN(68, "PE4"),
+	PINCTRL_PIN(69, "PE5"),
+	PINCTRL_PIN(70, "PE6"),
+	PINCTRL_PIN(71, "PE7"),
+	PINCTRL_PIN(72, "PE8"),
+	PINCTRL_PIN(73, "PE9"),
+	PINCTRL_PIN(74, "PE10"),
+	PINCTRL_PIN(75, "PE11"),
+	PINCTRL_PIN(76, "PE12"),
+	PINCTRL_PIN(77, "PE13"),
+	PINCTRL_PIN(78, "PE14"),
+	PINCTRL_PIN(79, "PE15"),
+	PINCTRL_PIN(80, "PF0"),
+	PINCTRL_PIN(81, "PF1"),
+	PINCTRL_PIN(82, "PF2"),
+	PINCTRL_PIN(83, "PF3"),
+	PINCTRL_PIN(84, "PF4"),
+	PINCTRL_PIN(85, "PF5"),
+	PINCTRL_PIN(86, "PF6"),
+	PINCTRL_PIN(87, "PF7"),
+	PINCTRL_PIN(88, "PF8"),
+	PINCTRL_PIN(89, "PF9"),
+	PINCTRL_PIN(90, "PF10"),
+	PINCTRL_PIN(91, "PF11"),
+	PINCTRL_PIN(92, "PF12"),
+	PINCTRL_PIN(93, "PF13"),
+	PINCTRL_PIN(94, "PF14"),
+	PINCTRL_PIN(95, "PF15"),
+	PINCTRL_PIN(96, "PG0"),
+	PINCTRL_PIN(97, "PG1"),
+	PINCTRL_PIN(98, "PG2"),
+	PINCTRL_PIN(99, "PG3"),
+	PINCTRL_PIN(100, "PG4"),
+	PINCTRL_PIN(101, "PG5"),
+	PINCTRL_PIN(102, "PG6"),
+	PINCTRL_PIN(103, "PG7"),
+	PINCTRL_PIN(104, "PG8"),
+	PINCTRL_PIN(105, "PG9"),
+	PINCTRL_PIN(106, "PG10"),
+	PINCTRL_PIN(107, "PG11"),
+	PINCTRL_PIN(108, "PG12"),
+	PINCTRL_PIN(109, "PG13"),
+	PINCTRL_PIN(110, "PG14"),
+	PINCTRL_PIN(111, "PG15"),
+	PINCTRL_PIN(112, "PH0"),
+	PINCTRL_PIN(113, "PH1"),
+	PINCTRL_PIN(114, "PH2"),
+	PINCTRL_PIN(115, "PH3"),
+	PINCTRL_PIN(116, "PH4"),
+	PINCTRL_PIN(117, "PH5"),
+	PINCTRL_PIN(118, "PH6"),
+	PINCTRL_PIN(119, "PH7"),
+	PINCTRL_PIN(120, "PH8"),
+	PINCTRL_PIN(121, "PH9"),
+	PINCTRL_PIN(122, "PH10"),
+	PINCTRL_PIN(123, "PH11"),
+	PINCTRL_PIN(124, "PH12"),
+	PINCTRL_PIN(125, "PH13"),
+	PINCTRL_PIN(128, "PI0"),
+	PINCTRL_PIN(129, "PI1"),
+	PINCTRL_PIN(130, "PI2"),
+	PINCTRL_PIN(131, "PI3"),
+	PINCTRL_PIN(132, "PI4"),
+	PINCTRL_PIN(133, "PI5"),
+	PINCTRL_PIN(134, "PI6"),
+	PINCTRL_PIN(135, "PI7"),
+	PINCTRL_PIN(136, "PI8"),
+	PINCTRL_PIN(137, "PI9"),
+	PINCTRL_PIN(138, "PI10"),
+	PINCTRL_PIN(139, "PI11"),
+	PINCTRL_PIN(140, "PI12"),
+	PINCTRL_PIN(141, "PI13"),
+	PINCTRL_PIN(142, "PI14"),
+	PINCTRL_PIN(143, "PI15"),
+	PINCTRL_PIN(144, "PJ0"),
+	PINCTRL_PIN(145, "PJ1"),
+	PINCTRL_PIN(146, "PJ2"),
+	PINCTRL_PIN(147, "PJ3"),
+	PINCTRL_PIN(148, "PJ4"),
+	PINCTRL_PIN(149, "PJ5"),
+	PINCTRL_PIN(150, "PJ6"),
+	PINCTRL_PIN(151, "PJ7"),
+	PINCTRL_PIN(152, "PJ8"),
+	PINCTRL_PIN(153, "PJ9"),
+	PINCTRL_PIN(154, "PJ10"),
+	PINCTRL_PIN(155, "PJ11"),
+	PINCTRL_PIN(156, "PJ12"),
+	PINCTRL_PIN(157, "PJ13"),
+};
+
+static const unsigned uart0_pins[] = {
+	GPIO_PE7, GPIO_PE8,
+};
+
+static const unsigned uart1_pins[] = {
+	GPIO_PH0, GPIO_PH1,
+#ifdef CONFIG_BFIN_UART1_CTSRTS
+	GPIO_PE9, GPIO_PE10,
+#endif
+};
+
+static const unsigned uart2_pins[] = {
+	GPIO_PB4, GPIO_PB5,
+};
+
+static const unsigned uart3_pins[] = {
+	GPIO_PB6, GPIO_PB7,
+#ifdef CONFIG_BFIN_UART3_CTSRTS
+	GPIO_PB2, GPIO_PB3,
+#endif
+};
+
+static const unsigned rsi0_pins[] = {
+	GPIO_PC8, GPIO_PC9, GPIO_PC10, GPIO_PC11, GPIO_PC12, GPIO_PC13,
+};
+
+static const unsigned spi0_pins[] = {
+	GPIO_PE0, GPIO_PE1, GPIO_PE2,
+};
+
+static const unsigned spi1_pins[] = {
+	GPIO_PG8, GPIO_PG9, GPIO_PG10,
+};
+
+static const unsigned twi0_pins[] = {
+	GPIO_PE14, GPIO_PE15,
+};
+
+static const unsigned twi1_pins[] = {
+	GPIO_PB0, GPIO_PB1,
+};
+
+static const unsigned rotary_pins[] = {
+	GPIO_PH4, GPIO_PH3, GPIO_PH5,
+};
+
+static const unsigned can0_pins[] = {
+	GPIO_PG13, GPIO_PG12,
+};
+
+static const unsigned can1_pins[] = {
+	GPIO_PG14, GPIO_PG15,
+};
+
+static const unsigned smc0_pins[] = {
+	GPIO_PH8, GPIO_PH9, GPIO_PH10, GPIO_PH11, GPIO_PH12, GPIO_PH13,
+	GPIO_PI0, GPIO_PI1, GPIO_PI2, GPIO_PI3, GPIO_PI4, GPIO_PI5, GPIO_PI6,
+	GPIO_PI7, GPIO_PI8, GPIO_PI9, GPIO_PI10, GPIO_PI11,
+	GPIO_PI12, GPIO_PI13, GPIO_PI14, GPIO_PI15,
+};
+
+static const unsigned sport0_pins[] = {
+	GPIO_PC0, GPIO_PC2, GPIO_PC3, GPIO_PC4, GPIO_PC6, GPIO_PC7,
+};
+
+static const unsigned sport1_pins[] = {
+	GPIO_PD0, GPIO_PD2, GPIO_PD3, GPIO_PD4, GPIO_PD6, GPIO_PD7,
+};
+
+static const unsigned sport2_pins[] = {
+	GPIO_PA0, GPIO_PA2, GPIO_PA3, GPIO_PA4, GPIO_PA6, GPIO_PA7,
+};
+
+static const unsigned sport3_pins[] = {
+	GPIO_PA8, GPIO_PA10, GPIO_PA11, GPIO_PA12, GPIO_PA14, GPIO_PA15,
+};
+
+static const unsigned ppi0_8b_pins[] = {
+	GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6,
+	GPIO_PF7, GPIO_PF13, GPIO_PG0, GPIO_PG1, GPIO_PG2,
+};
+
+static const unsigned ppi0_16b_pins[] = {
+	GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6,
+	GPIO_PF7, GPIO_PF9, GPIO_PF10, GPIO_PF11, GPIO_PF12,
+	GPIO_PF13, GPIO_PF14, GPIO_PF15,
+	GPIO_PG0, GPIO_PG1, GPIO_PG2,
+};
+
+static const unsigned ppi0_24b_pins[] = {
+	GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6,
+	GPIO_PF7, GPIO_PF8, GPIO_PF9, GPIO_PF10, GPIO_PF11, GPIO_PF12,
+	GPIO_PF13, GPIO_PF14, GPIO_PF15, GPIO_PD0, GPIO_PD1, GPIO_PD2,
+	GPIO_PD3, GPIO_PD4, GPIO_PD5, GPIO_PG3, GPIO_PG4,
+	GPIO_PG0, GPIO_PG1, GPIO_PG2,
+};
+
+static const unsigned ppi1_8b_pins[] = {
+	GPIO_PD0, GPIO_PD1, GPIO_PD2, GPIO_PD3, GPIO_PD4, GPIO_PD5, GPIO_PD6,
+	GPIO_PD7, GPIO_PE11, GPIO_PE12, GPIO_PE13,
+};
+
+static const unsigned ppi1_16b_pins[] = {
+	GPIO_PD0, GPIO_PD1, GPIO_PD2, GPIO_PD3, GPIO_PD4, GPIO_PD5, GPIO_PD6,
+	GPIO_PD7, GPIO_PD8, GPIO_PD9, GPIO_PD10, GPIO_PD11, GPIO_PD12,
+	GPIO_PD13, GPIO_PD14, GPIO_PD15,
+	GPIO_PE11, GPIO_PE12, GPIO_PE13,
+};
+
+static const unsigned ppi2_8b_pins[] = {
+	GPIO_PD8, GPIO_PD9, GPIO_PD10, GPIO_PD11, GPIO_PD12,
+	GPIO_PD13, GPIO_PD14, GPIO_PD15,
+	GPIO_PA7, GPIO_PB0, GPIO_PB1, GPIO_PB2, GPIO_PB3,
+};
+
+static const unsigned atapi_pins[] = {
+	GPIO_PH2, GPIO_PJ3, GPIO_PJ4, GPIO_PJ5, GPIO_PJ6,
+	GPIO_PJ7, GPIO_PJ8, GPIO_PJ9, GPIO_PJ10,
+	GPIO_PG5, GPIO_PG6, GPIO_PG7,
+#ifdef CONFIG_BF548_ATAPI_ALTERNATIVE_PORT
+	GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6,
+	GPIO_PF7, GPIO_PF8, GPIO_PF9, GPIO_PF10, GPIO_PF11, GPIO_PF12,
+	GPIO_PF13, GPIO_PF14, GPIO_PF15, GPIO_PG2, GPIO_PG3, GPIO_PG4,
+#endif
+};
+
+static const unsigned nfc0_pins[] = {
+	GPIO_PJ1, GPIO_PJ2,
+};
+
+static const unsigned keys_4x4_pins[] = {
+	GPIO_PD8, GPIO_PD9, GPIO_PD10, GPIO_PD11,
+	GPIO_PD12, GPIO_PD13, GPIO_PD14, GPIO_PD15,
+};
+
+static const unsigned keys_8x8_pins[] = {
+	GPIO_PD8, GPIO_PD9, GPIO_PD10, GPIO_PD11,
+	GPIO_PD12, GPIO_PD13, GPIO_PD14, GPIO_PD15,
+	GPIO_PE0, GPIO_PE1, GPIO_PE2, GPIO_PE3,
+	GPIO_PE4, GPIO_PE5, GPIO_PE6, GPIO_PE7,
+};
+
+ /**
+ * struct adi_pin_group - describes a pin group
+ * @name: the name of this pin group
+ * @pins: an array of pins
+ * @num: the number of pins in this array
+ */
+struct adi_pin_group {
+	const char *name;
+	const unsigned *pins;
+	const unsigned num;
+};
+
+#define ADI_PIN_GROUP(n, p)  \
+	{			\
+		.name = n,	\
+		.pins = p,	\
+		.num = ARRAY_SIZE(p),	\
+	}
+
+static const struct adi_pin_group adi_pin_groups[] = {
+	ADI_PIN_GROUP("uart0grp", uart0_pins),
+	ADI_PIN_GROUP("uart1grp", uart1_pins),
+	ADI_PIN_GROUP("rsi0grp", rsi0_pins),
+	ADI_PIN_GROUP("spi0grp", spi0_pins),
+	ADI_PIN_GROUP("spi1grp", spi1_pins),
+	ADI_PIN_GROUP("twi0grp", twi0_pins),
+	ADI_PIN_GROUP("twi1grp", twi1_pins),
+	ADI_PIN_GROUP("rotarygrp", rotary_pins),
+	ADI_PIN_GROUP("can0grp", can0_pins),
+	ADI_PIN_GROUP("can1grp", can1_pins),
+	ADI_PIN_GROUP("smc0grp", smc0_pins),
+	ADI_PIN_GROUP("sport0grp", sport0_pins),
+	ADI_PIN_GROUP("sport1grp", sport1_pins),
+	ADI_PIN_GROUP("sport2grp", sport2_pins),
+	ADI_PIN_GROUP("sport3grp", sport3_pins),
+	ADI_PIN_GROUP("ppi0_8bgrp", ppi0_8b_pins),
+	ADI_PIN_GROUP("ppi0_16bgrp", ppi0_16b_pins),
+	ADI_PIN_GROUP("ppi0_24bgrp", ppi0_24b_pins),
+	ADI_PIN_GROUP("ppi1_8bgrp", ppi1_8b_pins),
+	ADI_PIN_GROUP("ppi1_16bgrp", ppi1_16b_pins),
+	ADI_PIN_GROUP("ppi2_8bgrp", ppi2_8b_pins),
+	ADI_PIN_GROUP("atapigrp", atapi_pins),
+	ADI_PIN_GROUP("nfc0grp", nfc0_pins),
+	ADI_PIN_GROUP("keys_4x4grp", keys_4x4_pins),
+	ADI_PIN_GROUP("keys_8x8grp", keys_8x8_pins),
+};
+
+static const unsigned short uart0_mux[] = {
+	P_UART0_TX, P_UART0_RX,
+	0
+};
+
+static const unsigned short uart1_mux[] = {
+	P_UART1_TX, P_UART1_RX,
+#ifdef CONFIG_BFIN_UART1_CTSRTS
+	P_UART1_RTS, P_UART1_CTS,
+#endif
+	0
+};
+
+static const unsigned short uart2_mux[] = {
+	P_UART2_TX, P_UART2_RX,
+	0
+};
+
+static const unsigned short uart3_mux[] = {
+	P_UART3_TX, P_UART3_RX,
+#ifdef CONFIG_BFIN_UART3_CTSRTS
+	P_UART3_RTS, P_UART3_CTS,
+#endif
+	0
+};
+
+static const unsigned short rsi0_mux[] = {
+	P_SD_D0, P_SD_D1, P_SD_D2, P_SD_D3, P_SD_CLK, P_SD_CMD,
+	0
+};
+
+static const unsigned short spi0_mux[] = {
+	P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0
+};
+
+static const unsigned short spi1_mux[] = {
+	P_SPI1_SCK, P_SPI1_MISO, P_SPI1_MOSI, 0
+};
+
+static const unsigned short twi0_mux[] = {
+	P_TWI0_SCL, P_TWI0_SDA, 0
+};
+
+static const unsigned short twi1_mux[] = {
+	P_TWI1_SCL, P_TWI1_SDA, 0
+};
+
+static const unsigned short rotary_mux[] = {
+	P_CNT_CUD, P_CNT_CDG, P_CNT_CZM, 0
+};
+
+static const unsigned short sport0_mux[] = {
+	P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+	P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0
+};
+
+static const unsigned short sport1_mux[] = {
+	P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+	P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0
+};
+
+static const unsigned short sport2_mux[] = {
+	P_SPORT2_TFS, P_SPORT2_DTPRI, P_SPORT2_TSCLK, P_SPORT2_RFS,
+	P_SPORT2_DRPRI, P_SPORT2_RSCLK, 0
+};
+
+static const unsigned short sport3_mux[] = {
+	P_SPORT3_TFS, P_SPORT3_DTPRI, P_SPORT3_TSCLK, P_SPORT3_RFS,
+	P_SPORT3_DRPRI, P_SPORT3_RSCLK, 0
+};
+
+static const unsigned short can0_mux[] = {
+	P_CAN0_RX, P_CAN0_TX, 0
+};
+
+static const unsigned short can1_mux[] = {
+	P_CAN1_RX, P_CAN1_TX, 0
+};
+
+static const unsigned short smc0_mux[] = {
+	P_A4, P_A5, P_A6, P_A7, P_A8, P_A9, P_A10, P_A11, P_A12,
+	P_A13, P_A14, P_A15, P_A16, P_A17, P_A18, P_A19, P_A20, P_A21,
+	P_A22, P_A23, P_A24, P_A25, P_NOR_CLK, 0,
+};
+
+static const unsigned short ppi0_8b_mux[] = {
+	P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3,
+	P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7,
+	P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
+	0,
+};
+
+static const unsigned short ppi0_16b_mux[] = {
+	P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3,
+	P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7,
+	P_PPI0_D8, P_PPI0_D9, P_PPI0_D10, P_PPI0_D11,
+	P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15,
+	P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
+	0,
+};
+
+static const unsigned short ppi0_24b_mux[] = {
+	P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3,
+	P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7,
+	P_PPI0_D8, P_PPI0_D9, P_PPI0_D10, P_PPI0_D11,
+	P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15,
+	P_PPI0_D16, P_PPI0_D17, P_PPI0_D18, P_PPI0_D19,
+	P_PPI0_D20, P_PPI0_D21, P_PPI0_D22, P_PPI0_D23,
+	P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
+	0,
+};
+
+static const unsigned short ppi1_8b_mux[] = {
+	P_PPI1_D0, P_PPI1_D1, P_PPI1_D2, P_PPI1_D3,
+	P_PPI1_D4, P_PPI1_D5, P_PPI1_D6, P_PPI1_D7,
+	P_PPI1_CLK, P_PPI1_FS1, P_PPI1_FS2,
+	0,
+};
+
+static const unsigned short ppi1_16b_mux[] = {
+	P_PPI1_D0, P_PPI1_D1, P_PPI1_D2, P_PPI1_D3,
+	P_PPI1_D4, P_PPI1_D5, P_PPI1_D6, P_PPI1_D7,
+	P_PPI1_D8, P_PPI1_D9, P_PPI1_D10, P_PPI1_D11,
+	P_PPI1_D12, P_PPI1_D13, P_PPI1_D14, P_PPI1_D15,
+	P_PPI1_CLK, P_PPI1_FS1, P_PPI1_FS2,
+	0,
+};
+
+static const unsigned short ppi2_8b_mux[] = {
+	P_PPI2_D0, P_PPI2_D1, P_PPI2_D2, P_PPI2_D3,
+	P_PPI2_D4, P_PPI2_D5, P_PPI2_D6, P_PPI2_D7,
+	P_PPI2_CLK, P_PPI2_FS1, P_PPI2_FS2,
+	0,
+};
+
+static const unsigned short atapi_mux[] = {
+	P_ATAPI_RESET, P_ATAPI_DIOR, P_ATAPI_DIOW, P_ATAPI_CS0, P_ATAPI_CS1,
+	P_ATAPI_DMACK, P_ATAPI_DMARQ, P_ATAPI_INTRQ, P_ATAPI_IORDY,
+	P_ATAPI_D0A, P_ATAPI_D1A, P_ATAPI_D2A, P_ATAPI_D3A, P_ATAPI_D4A,
+	P_ATAPI_D5A, P_ATAPI_D6A, P_ATAPI_D7A, P_ATAPI_D8A, P_ATAPI_D9A,
+	P_ATAPI_D10A, P_ATAPI_D11A, P_ATAPI_D12A, P_ATAPI_D13A, P_ATAPI_D14A,
+	P_ATAPI_D15A, P_ATAPI_A0A, P_ATAPI_A1A, P_ATAPI_A2A,
+	0
+};
+
+static const unsigned short nfc0_mux[] = {
+	P_NAND_CE, P_NAND_RB,
+	0
+};
+
+static const unsigned short keys_4x4_mux[] = {
+	P_KEY_ROW3, P_KEY_ROW2, P_KEY_ROW1, P_KEY_ROW0,
+	P_KEY_COL3, P_KEY_COL2, P_KEY_COL1, P_KEY_COL0,
+	0
+};
+
+static const unsigned short keys_8x8_mux[] = {
+	P_KEY_ROW7, P_KEY_ROW6, P_KEY_ROW5, P_KEY_ROW4,
+	P_KEY_ROW3, P_KEY_ROW2, P_KEY_ROW1, P_KEY_ROW0,
+	P_KEY_COL7, P_KEY_COL6, P_KEY_COL5, P_KEY_COL4,
+	P_KEY_COL3, P_KEY_COL2, P_KEY_COL1, P_KEY_COL0,
+	0
+};
+
+struct adi_pmx_func {
+	const char *name;
+	const char * const *groups;
+	const unsigned num_groups;
+	const unsigned short *mux;
+};
+
+static const char * const uart0grp[] = { "uart0grp" };
+static const char * const uart1grp[] = { "uart1grp" };
+static const char * const uart2grp[] = { "uart2grp" };
+static const char * const uart3grp[] = { "uart3grp" };
+static const char * const rsi0grp[] = { "rsi0grp" };
+static const char * const spi0grp[] = { "spi0grp" };
+static const char * const spi1grp[] = { "spi1grp" };
+static const char * const twi0grp[] = { "twi0grp" };
+static const char * const twi1grp[] = { "twi1grp" };
+static const char * const rotarygrp[] = { "rotarygrp" };
+static const char * const can0grp[] = { "can0grp" };
+static const char * const can1grp[] = { "can1grp" };
+static const char * const smc0grp[] = { "smc0grp" };
+static const char * const sport0grp[] = { "sport0grp" };
+static const char * const sport1grp[] = { "sport1grp" };
+static const char * const sport2grp[] = { "sport2grp" };
+static const char * const sport3grp[] = { "sport3grp" };
+static const char * const ppi0_8bgrp[] = { "ppi0_8bgrp" };
+static const char * const ppi0_16bgrp[] = { "ppi0_16bgrp" };
+static const char * const ppi0_24bgrp[] = { "ppi0_24bgrp" };
+static const char * const ppi1_8bgrp[] = { "ppi1_8bgrp" };
+static const char * const ppi1_16bgrp[] = { "ppi1_16bgrp" };
+static const char * const ppi2_8bgrp[] = { "ppi2_8bgrp" };
+static const char * const atapigrp[] = { "atapigrp" };
+static const char * const nfc0grp[] = { "nfc0grp" };
+static const char * const keys_4x4grp[] = { "keys_4x4grp" };
+static const char * const keys_8x8grp[] = { "keys_8x8grp" };
+
+#define ADI_PMX_FUNCTION(n, g, m)		\
+	{					\
+		.name = n,			\
+		.groups = g,			\
+		.num_groups = ARRAY_SIZE(g),	\
+		.mux = m,			\
+	}
+
+static const struct adi_pmx_func adi_pmx_functions[] = {
+	ADI_PMX_FUNCTION("uart0", uart0grp, uart0_mux),
+	ADI_PMX_FUNCTION("uart1", uart1grp, uart1_mux),
+	ADI_PMX_FUNCTION("uart2", uart0grp, uart2_mux),
+	ADI_PMX_FUNCTION("uart3", uart1grp, uart3_mux),
+	ADI_PMX_FUNCTION("rsi0", rsi0grp, rsi0_mux),
+	ADI_PMX_FUNCTION("spi0", spi0grp, spi0_mux),
+	ADI_PMX_FUNCTION("spi1", spi1grp, spi1_mux),
+	ADI_PMX_FUNCTION("twi0", twi0grp, twi0_mux),
+	ADI_PMX_FUNCTION("twi1", twi1grp, twi1_mux),
+	ADI_PMX_FUNCTION("rotary", rotarygrp, rotary_mux),
+	ADI_PMX_FUNCTION("can0", can0grp, can0_mux),
+	ADI_PMX_FUNCTION("can1", can1grp, can1_mux),
+	ADI_PMX_FUNCTION("smc0", smc0grp, smc0_mux),
+	ADI_PMX_FUNCTION("sport0", sport0grp, sport0_mux),
+	ADI_PMX_FUNCTION("sport1", sport1grp, sport1_mux),
+	ADI_PMX_FUNCTION("sport2", sport2grp, sport2_mux),
+	ADI_PMX_FUNCTION("sport3", sport3grp, sport3_mux),
+	ADI_PMX_FUNCTION("ppi0_8b", ppi0_8bgrp, ppi0_8b_mux),
+	ADI_PMX_FUNCTION("ppi0_16b", ppi0_16bgrp, ppi0_16b_mux),
+	ADI_PMX_FUNCTION("ppi0_24b", ppi0_24bgrp, ppi0_24b_mux),
+	ADI_PMX_FUNCTION("ppi1_8b", ppi1_8bgrp, ppi1_8b_mux),
+	ADI_PMX_FUNCTION("ppi1_16b", ppi1_16bgrp, ppi1_16b_mux),
+	ADI_PMX_FUNCTION("ppi2_8b", ppi2_8bgrp, ppi2_8b_mux),
+	ADI_PMX_FUNCTION("atapi", atapigrp, atapi_mux),
+	ADI_PMX_FUNCTION("nfc0", nfc0grp, nfc0_mux),
+	ADI_PMX_FUNCTION("keys_4x4", keys_4x4grp, keys_4x4_mux),
+	ADI_PMX_FUNCTION("keys_8x8", keys_8x8grp, keys_8x8_mux),
+};
+
+#endif	/* CONFIG_PINCTRL */
+
 #endif /* _MACH_PORTMUX_H_ */
diff --git a/arch/blackfin/mach-bf609/include/mach/portmux.h b/arch/blackfin/mach-bf609/include/mach/portmux.h
index 2e1a51c..5f1b1a6 100644
--- a/arch/blackfin/mach-bf609/include/mach/portmux.h
+++ b/arch/blackfin/mach-bf609/include/mach/portmux.h
@@ -7,8 +7,6 @@
 #ifndef _MACH_PORTMUX_H_
 #define _MACH_PORTMUX_H_
 
-#define MAX_RESOURCES	MAX_BLACKFIN_GPIOS
-
 /* EMAC RMII Port Mux */
 #define P_MII0_MDC	(P_DEFINED | P_IDENT(GPIO_PC6) | P_FUNCT(0))
 #define P_MII0_MDIO	(P_DEFINED | P_IDENT(GPIO_PC7) | P_FUNCT(0))
@@ -344,4 +342,479 @@
 #define P_CNT_CUD	(P_DEFINED | P_IDENT(GPIO_PG11) | P_FUNCT(3))
 #define P_CNT_CDG	(P_DEFINED | P_IDENT(GPIO_PG12) | P_FUNCT(3))
 
+#ifdef CONFIG_PINCTRL
+
+#include <mach/gpio.h>
+#include <asm/blackfin.h>
+#include <asm/irq_handler.h>
+
+#define gpio_pint_regs bfin_pint_regs
+#define adi_internal_set_wake bfin_internal_set_wake
+
+static const struct pinctrl_pin_desc adi_pads[] = {
+	PINCTRL_PIN(0, "PA0"),
+	PINCTRL_PIN(1, "PA1"),
+	PINCTRL_PIN(2, "PA2"),
+	PINCTRL_PIN(3, "PG3"),
+	PINCTRL_PIN(4, "PA4"),
+	PINCTRL_PIN(5, "PA5"),
+	PINCTRL_PIN(6, "PA6"),
+	PINCTRL_PIN(7, "PA7"),
+	PINCTRL_PIN(8, "PA8"),
+	PINCTRL_PIN(9, "PA9"),
+	PINCTRL_PIN(10, "PA10"),
+	PINCTRL_PIN(11, "PA11"),
+	PINCTRL_PIN(12, "PA12"),
+	PINCTRL_PIN(13, "PA13"),
+	PINCTRL_PIN(14, "PA14"),
+	PINCTRL_PIN(15, "PA15"),
+	PINCTRL_PIN(16, "PB0"),
+	PINCTRL_PIN(17, "PB1"),
+	PINCTRL_PIN(18, "PB2"),
+	PINCTRL_PIN(19, "PB3"),
+	PINCTRL_PIN(20, "PB4"),
+	PINCTRL_PIN(21, "PB5"),
+	PINCTRL_PIN(22, "PB6"),
+	PINCTRL_PIN(23, "PB7"),
+	PINCTRL_PIN(24, "PB8"),
+	PINCTRL_PIN(25, "PB9"),
+	PINCTRL_PIN(26, "PB10"),
+	PINCTRL_PIN(27, "PB11"),
+	PINCTRL_PIN(28, "PB12"),
+	PINCTRL_PIN(29, "PB13"),
+	PINCTRL_PIN(30, "PB14"),
+	PINCTRL_PIN(31, "PB15"),
+	PINCTRL_PIN(32, "PC0"),
+	PINCTRL_PIN(33, "PC1"),
+	PINCTRL_PIN(34, "PC2"),
+	PINCTRL_PIN(35, "PC3"),
+	PINCTRL_PIN(36, "PC4"),
+	PINCTRL_PIN(37, "PC5"),
+	PINCTRL_PIN(38, "PC6"),
+	PINCTRL_PIN(39, "PC7"),
+	PINCTRL_PIN(40, "PC8"),
+	PINCTRL_PIN(41, "PC9"),
+	PINCTRL_PIN(42, "PC10"),
+	PINCTRL_PIN(43, "PC11"),
+	PINCTRL_PIN(44, "PC12"),
+	PINCTRL_PIN(45, "PC13"),
+	PINCTRL_PIN(46, "PC14"),
+	PINCTRL_PIN(47, "PC15"),
+	PINCTRL_PIN(48, "PD0"),
+	PINCTRL_PIN(49, "PD1"),
+	PINCTRL_PIN(50, "PD2"),
+	PINCTRL_PIN(51, "PD3"),
+	PINCTRL_PIN(52, "PD4"),
+	PINCTRL_PIN(53, "PD5"),
+	PINCTRL_PIN(54, "PD6"),
+	PINCTRL_PIN(55, "PD7"),
+	PINCTRL_PIN(56, "PD8"),
+	PINCTRL_PIN(57, "PD9"),
+	PINCTRL_PIN(58, "PD10"),
+	PINCTRL_PIN(59, "PD11"),
+	PINCTRL_PIN(60, "PD12"),
+	PINCTRL_PIN(61, "PD13"),
+	PINCTRL_PIN(62, "PD14"),
+	PINCTRL_PIN(63, "PD15"),
+	PINCTRL_PIN(64, "PE0"),
+	PINCTRL_PIN(65, "PE1"),
+	PINCTRL_PIN(66, "PE2"),
+	PINCTRL_PIN(67, "PE3"),
+	PINCTRL_PIN(68, "PE4"),
+	PINCTRL_PIN(69, "PE5"),
+	PINCTRL_PIN(70, "PE6"),
+	PINCTRL_PIN(71, "PE7"),
+	PINCTRL_PIN(72, "PE8"),
+	PINCTRL_PIN(73, "PE9"),
+	PINCTRL_PIN(74, "PE10"),
+	PINCTRL_PIN(75, "PE11"),
+	PINCTRL_PIN(76, "PE12"),
+	PINCTRL_PIN(77, "PE13"),
+	PINCTRL_PIN(78, "PE14"),
+	PINCTRL_PIN(79, "PE15"),
+	PINCTRL_PIN(80, "PF0"),
+	PINCTRL_PIN(81, "PF1"),
+	PINCTRL_PIN(82, "PF2"),
+	PINCTRL_PIN(83, "PF3"),
+	PINCTRL_PIN(84, "PF4"),
+	PINCTRL_PIN(85, "PF5"),
+	PINCTRL_PIN(86, "PF6"),
+	PINCTRL_PIN(87, "PF7"),
+	PINCTRL_PIN(88, "PF8"),
+	PINCTRL_PIN(89, "PF9"),
+	PINCTRL_PIN(90, "PF10"),
+	PINCTRL_PIN(91, "PF11"),
+	PINCTRL_PIN(92, "PF12"),
+	PINCTRL_PIN(93, "PF13"),
+	PINCTRL_PIN(94, "PF14"),
+	PINCTRL_PIN(95, "PF15"),
+	PINCTRL_PIN(96, "PG0"),
+	PINCTRL_PIN(97, "PG1"),
+	PINCTRL_PIN(98, "PG2"),
+	PINCTRL_PIN(99, "PG3"),
+	PINCTRL_PIN(100, "PG4"),
+	PINCTRL_PIN(101, "PG5"),
+	PINCTRL_PIN(102, "PG6"),
+	PINCTRL_PIN(103, "PG7"),
+	PINCTRL_PIN(104, "PG8"),
+	PINCTRL_PIN(105, "PG9"),
+	PINCTRL_PIN(106, "PG10"),
+	PINCTRL_PIN(107, "PG11"),
+	PINCTRL_PIN(108, "PG12"),
+	PINCTRL_PIN(109, "PG13"),
+	PINCTRL_PIN(110, "PG14"),
+	PINCTRL_PIN(111, "PG15"),
+};
+
+static const unsigned uart0_pins[] = {
+	GPIO_PD7, GPIO_PD8,
+#ifdef CONFIG_BFIN_UART0_CTSRTS
+	GPIO_PD9, GPIO_PD10,
+#endif
+};
+
+static const unsigned uart1_pins[] = {
+	GPIO_PG15, GPIO_PG14,
+#ifdef CONFIG_BFIN_UART1_CTSRTS
+	GPIO_PG10, GPIO_PG13,
+#endif
+};
+
+static const unsigned rsi0_pins[] = {
+	GPIO_PG3, GPIO_PG2, GPIO_PG0, GPIO_PE15, GPIO_PG5, GPIO_PG6,
+};
+
+static const unsigned eth0_pins[] = {
+	GPIO_PC6, GPIO_PC7, GPIO_PC2, GPIO_PC0, GPIO_PC3, GPIO_PC1,
+	GPIO_PB13, GPIO_PD6, GPIO_PC5, GPIO_PC4, GPIO_PB14,
+};
+
+static const unsigned eth1_pins[] = {
+	GPIO_PE10, GPIO_PE11, GPIO_PG3, GPIO_PG0, GPIO_PG2, GPIO_PE15,
+	GPIO_PG5, GPIO_PE12, GPIO_PE13, GPIO_PE14, GPIO_PG6,
+};
+
+static const unsigned spi0_pins[] = {
+	GPIO_PD4, GPIO_PD2, GPIO_PD3,
+};
+
+static const unsigned spi1_pins[] = {
+	GPIO_PD5, GPIO_PD14, GPIO_PD13,
+};
+
+static const unsigned twi0_pins[] = {
+};
+
+static const unsigned twi1_pins[] = {
+};
+
+static const unsigned rotary_pins[] = {
+	GPIO_PG7, GPIO_PG11, GPIO_PG12,
+};
+
+static const unsigned can0_pins[] = {
+	GPIO_PG1, GPIO_PG4,
+};
+
+static const unsigned smc0_pins[] = {
+	GPIO_PA0, GPIO_PA1, GPIO_PA2, GPIO_PA3, GPIO_PA4, GPIO_PA5, GPIO_PA6,
+	GPIO_PA7, GPIO_PA8, GPIO_PA9, GPIO_PB2, GPIO_PA10, GPIO_PA11,
+	GPIO_PB3, GPIO_PA12, GPIO_PA13, GPIO_PA14, GPIO_PA15, GPIO_PB6,
+	GPIO_PB7, GPIO_PB8, GPIO_PB10, GPIO_PB11, GPIO_PB0,
+};
+
+static const unsigned sport0_pins[] = {
+	GPIO_PB5, GPIO_PB4, GPIO_PB9, GPIO_PB8, GPIO_PB7, GPIO_PB11,
+};
+
+static const unsigned sport1_pins[] = {
+	GPIO_PE2, GPIO_PE5, GPIO_PD15, GPIO_PE4, GPIO_PE3, GPIO_PE1,
+};
+
+static const unsigned sport2_pins[] = {
+	GPIO_PG4, GPIO_PG1, GPIO_PG9, GPIO_PG10, GPIO_PG7, GPIO_PB12,
+};
+
+static const unsigned ppi0_8b_pins[] = {
+	GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6,
+	GPIO_PF7, GPIO_PF13, GPIO_PF14, GPIO_PF15,
+	GPIO_PE6, GPIO_PE7, GPIO_PE8, GPIO_PE9,
+};
+
+static const unsigned ppi0_16b_pins[] = {
+	GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6,
+	GPIO_PF7, GPIO_PF9, GPIO_PF10, GPIO_PF11, GPIO_PF12,
+	GPIO_PF13, GPIO_PF14, GPIO_PF15,
+	GPIO_PE6, GPIO_PE7, GPIO_PE8, GPIO_PE9,
+};
+
+static const unsigned ppi0_24b_pins[] = {
+	GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6,
+	GPIO_PF7, GPIO_PF8, GPIO_PF9, GPIO_PF10, GPIO_PF11, GPIO_PF12,
+	GPIO_PF13, GPIO_PF14, GPIO_PF15, GPIO_PE0, GPIO_PE1, GPIO_PE2,
+	GPIO_PE3, GPIO_PE4, GPIO_PE5, GPIO_PE6, GPIO_PE7, GPIO_PE8,
+	GPIO_PE9, GPIO_PD12, GPIO_PD15,
+};
+
+static const unsigned ppi1_8b_pins[] = {
+	GPIO_PC0, GPIO_PC1, GPIO_PC2, GPIO_PC3, GPIO_PC4, GPIO_PC5, GPIO_PC6,
+	GPIO_PC7, GPIO_PC8, GPIO_PB13, GPIO_PB14, GPIO_PB15, GPIO_PD6,
+};
+
+static const unsigned ppi1_16b_pins[] = {
+	GPIO_PC0, GPIO_PC1, GPIO_PC2, GPIO_PC3, GPIO_PC4, GPIO_PC5, GPIO_PC6,
+	GPIO_PC7, GPIO_PC9, GPIO_PC10, GPIO_PC11, GPIO_PC12,
+	GPIO_PC13, GPIO_PC14, GPIO_PC15,
+	GPIO_PB13, GPIO_PB14, GPIO_PB15, GPIO_PD6,
+};
+
+static const unsigned ppi2_8b_pins[] = {
+	GPIO_PA0, GPIO_PA1, GPIO_PA2, GPIO_PA3, GPIO_PA4, GPIO_PA5, GPIO_PA6,
+	GPIO_PA7, GPIO_PB0, GPIO_PB1, GPIO_PB2, GPIO_PB3,
+};
+
+static const unsigned ppi2_16b_pins[] = {
+	GPIO_PA0, GPIO_PA1, GPIO_PA2, GPIO_PA3, GPIO_PA4, GPIO_PA5, GPIO_PA6,
+	GPIO_PA7, GPIO_PA8, GPIO_PA9, GPIO_PA10, GPIO_PA11, GPIO_PA12,
+	GPIO_PA13, GPIO_PA14, GPIO_PA15,
+	GPIO_PA7, GPIO_PB0, GPIO_PB1, GPIO_PB2, GPIO_PB3,
+};
+
+ /**
+ * struct adi_pin_group - describes a pin group
+ * @name: the name of this pin group
+ * @pins: an array of pins
+ * @num: the number of pins in this array
+ */
+struct adi_pin_group {
+	const char *name;
+	const unsigned *pins;
+	const unsigned num;
+};
+
+#define ADI_PIN_GROUP(n, p)  \
+	{			\
+		.name = n,	\
+		.pins = p,	\
+		.num = ARRAY_SIZE(p),	\
+	}
+
+static const struct adi_pin_group adi_pin_groups[] = {
+	ADI_PIN_GROUP("uart0grp", uart0_pins),
+	ADI_PIN_GROUP("uart1grp", uart1_pins),
+	ADI_PIN_GROUP("rsi0grp", rsi0_pins),
+	ADI_PIN_GROUP("eth0grp", eth0_pins),
+	ADI_PIN_GROUP("eth1grp", eth1_pins),
+	ADI_PIN_GROUP("spi0grp", spi0_pins),
+	ADI_PIN_GROUP("spi1grp", spi1_pins),
+	ADI_PIN_GROUP("twi0grp", twi0_pins),
+	ADI_PIN_GROUP("twi1grp", twi1_pins),
+	ADI_PIN_GROUP("rotarygrp", rotary_pins),
+	ADI_PIN_GROUP("can0grp", can0_pins),
+	ADI_PIN_GROUP("smc0grp", smc0_pins),
+	ADI_PIN_GROUP("sport0grp", sport0_pins),
+	ADI_PIN_GROUP("sport1grp", sport1_pins),
+	ADI_PIN_GROUP("sport2grp", sport2_pins),
+	ADI_PIN_GROUP("ppi0_8bgrp", ppi0_8b_pins),
+	ADI_PIN_GROUP("ppi0_16bgrp", ppi0_16b_pins),
+	ADI_PIN_GROUP("ppi0_24bgrp", ppi0_24b_pins),
+	ADI_PIN_GROUP("ppi1_8bgrp", ppi1_8b_pins),
+	ADI_PIN_GROUP("ppi1_16bgrp", ppi1_16b_pins),
+	ADI_PIN_GROUP("ppi2_8bgrp", ppi2_8b_pins),
+	ADI_PIN_GROUP("ppi2_16bgrp", ppi2_16b_pins),
+};
+
+static const unsigned short uart0_mux[] = {
+	P_UART0_TX, P_UART0_RX,
+#ifdef CONFIG_BFIN_UART0_CTSRTS
+	P_UART0_RTS, P_UART0_CTS,
+#endif
+	0
+};
+
+static const unsigned short uart1_mux[] = {
+	P_UART1_TX, P_UART1_RX,
+#ifdef CONFIG_BFIN_UART1_CTSRTS
+	P_UART1_RTS, P_UART1_CTS,
+#endif
+	0
+};
+
+static const unsigned short rsi0_mux[] = {
+	P_RSI_DATA0, P_RSI_DATA1, P_RSI_DATA2, P_RSI_DATA3,
+	P_RSI_CMD, P_RSI_CLK, 0
+};
+
+static const unsigned short eth0_mux[] = P_RMII0;
+static const unsigned short eth1_mux[] = P_RMII1;
+
+static const unsigned short spi0_mux[] = {
+	P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0
+};
+
+static const unsigned short spi1_mux[] = {
+	P_SPI1_SCK, P_SPI1_MISO, P_SPI1_MOSI, 0
+};
+
+static const unsigned short twi0_mux[] = {
+	P_TWI0_SCL, P_TWI0_SDA, 0
+};
+
+static const unsigned short twi1_mux[] = {
+	P_TWI1_SCL, P_TWI1_SDA, 0
+};
+
+static const unsigned short rotary_mux[] = {
+	P_CNT_CUD, P_CNT_CDG, P_CNT_CZM, 0
+};
+
+static const unsigned short sport0_mux[] = {
+	P_SPORT0_ACLK, P_SPORT0_AFS, P_SPORT0_AD0, P_SPORT0_BCLK,
+	P_SPORT0_BFS, P_SPORT0_BD0, 0,
+};
+
+static const unsigned short sport1_mux[] = {
+	P_SPORT1_ACLK, P_SPORT1_AFS, P_SPORT1_AD0, P_SPORT1_BCLK,
+	P_SPORT1_BFS, P_SPORT1_BD0, 0,
+};
+
+static const unsigned short sport2_mux[] = {
+	P_SPORT2_ACLK, P_SPORT2_AFS, P_SPORT2_AD0, P_SPORT2_BCLK,
+	P_SPORT2_BFS, P_SPORT2_BD0, 0,
+};
+
+static const unsigned short can0_mux[] = {
+	P_CAN0_RX, P_CAN0_TX, 0
+};
+
+static const unsigned short smc0_mux[] = {
+	P_A3, P_A4, P_A5, P_A6, P_A7, P_A8, P_A9, P_A10, P_A11, P_A12,
+	P_A13, P_A14, P_A15, P_A16, P_A17, P_A18, P_A19, P_A20, P_A21,
+	P_A22, P_A23, P_A24, P_A25, P_NORCK, 0,
+};
+
+static const unsigned short ppi0_8b_mux[] = {
+	P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3,
+	P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7,
+	P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
+	0,
+};
+
+static const unsigned short ppi0_16b_mux[] = {
+	P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3,
+	P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7,
+	P_PPI0_D8, P_PPI0_D9, P_PPI0_D10, P_PPI0_D11,
+	P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15,
+	P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
+	0,
+};
+
+static const unsigned short ppi0_24b_mux[] = {
+	P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3,
+	P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7,
+	P_PPI0_D8, P_PPI0_D9, P_PPI0_D10, P_PPI0_D11,
+	P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15,
+	P_PPI0_D16, P_PPI0_D17, P_PPI0_D18, P_PPI0_D19,
+	P_PPI0_D20, P_PPI0_D21, P_PPI0_D22, P_PPI0_D23,
+	P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
+	0,
+};
+
+static const unsigned short ppi1_8b_mux[] = {
+	P_PPI1_D0, P_PPI1_D1, P_PPI1_D2, P_PPI1_D3,
+	P_PPI1_D4, P_PPI1_D5, P_PPI1_D6, P_PPI1_D7,
+	P_PPI1_CLK, P_PPI1_FS1, P_PPI1_FS2,
+	0,
+};
+
+static const unsigned short ppi1_16b_mux[] = {
+	P_PPI1_D0, P_PPI1_D1, P_PPI1_D2, P_PPI1_D3,
+	P_PPI1_D4, P_PPI1_D5, P_PPI1_D6, P_PPI1_D7,
+	P_PPI1_D8, P_PPI1_D9, P_PPI1_D10, P_PPI1_D11,
+	P_PPI1_D12, P_PPI1_D13, P_PPI1_D14, P_PPI1_D15,
+	P_PPI1_CLK, P_PPI1_FS1, P_PPI1_FS2,
+	0,
+};
+
+static const unsigned short ppi2_8b_mux[] = {
+	P_PPI2_D0, P_PPI2_D1, P_PPI2_D2, P_PPI2_D3,
+	P_PPI2_D4, P_PPI2_D5, P_PPI2_D6, P_PPI2_D7,
+	P_PPI2_CLK, P_PPI2_FS1, P_PPI2_FS2,
+	0,
+};
+
+static const unsigned short ppi2_16b_mux[] = {
+	P_PPI2_D0, P_PPI2_D1, P_PPI2_D2, P_PPI2_D3,
+	P_PPI2_D4, P_PPI2_D5, P_PPI2_D6, P_PPI2_D7,
+	P_PPI2_D8, P_PPI2_D9, P_PPI2_D10, P_PPI2_D11,
+	P_PPI2_D12, P_PPI2_D13, P_PPI2_D14, P_PPI2_D15,
+	P_PPI2_CLK, P_PPI2_FS1, P_PPI2_FS2,
+	0,
+};
+
+struct adi_pmx_func {
+	const char *name;
+	const char * const *groups;
+	const unsigned num_groups;
+	const unsigned short *mux;
+};
+
+static const char * const uart0grp[] = { "uart0grp" };
+static const char * const uart1grp[] = { "uart1grp" };
+static const char * const rsi0grp[] = { "rsi0grp" };
+static const char * const eth0grp[] = { "eth0grp" };
+static const char * const eth1grp[] = { "eth1grp" };
+static const char * const spi0grp[] = { "spi0grp" };
+static const char * const spi1grp[] = { "spi1grp" };
+static const char * const twi0grp[] = { "twi0grp" };
+static const char * const twi1grp[] = { "twi1grp" };
+static const char * const rotarygrp[] = { "rotarygrp" };
+static const char * const can0grp[] = { "can0grp" };
+static const char * const smc0grp[] = { "smc0grp" };
+static const char * const sport0grp[] = { "sport0grp" };
+static const char * const sport1grp[] = { "sport1grp" };
+static const char * const sport2grp[] = { "sport2grp" };
+static const char * const ppi0_8bgrp[] = { "ppi0_8bgrp" };
+static const char * const ppi0_16bgrp[] = { "ppi0_16bgrp" };
+static const char * const ppi0_24bgrp[] = { "ppi0_24bgrp" };
+static const char * const ppi1_8bgrp[] = { "ppi1_8bgrp" };
+static const char * const ppi1_16bgrp[] = { "ppi1_16bgrp" };
+static const char * const ppi2_8bgrp[] = { "ppi2_8bgrp" };
+static const char * const ppi2_16bgrp[] = { "ppi2_16bgrp" };
+
+#define ADI_PMX_FUNCTION(n, g, m)		\
+	{					\
+		.name = n,			\
+		.groups = g,			\
+		.num_groups = ARRAY_SIZE(g),	\
+		.mux = m,			\
+	}
+
+static const struct adi_pmx_func adi_pmx_functions[] = {
+	ADI_PMX_FUNCTION("uart0", uart0grp, uart0_mux),
+	ADI_PMX_FUNCTION("uart1", uart1grp, uart1_mux),
+	ADI_PMX_FUNCTION("rsi0", rsi0grp, rsi0_mux),
+	ADI_PMX_FUNCTION("eth0", eth0grp, eth0_mux),
+	ADI_PMX_FUNCTION("eth1", eth1grp, eth1_mux),
+	ADI_PMX_FUNCTION("spi0", spi0grp, spi0_mux),
+	ADI_PMX_FUNCTION("spi1", spi1grp, spi1_mux),
+	ADI_PMX_FUNCTION("twi0", twi0grp, twi0_mux),
+	ADI_PMX_FUNCTION("twi1", twi1grp, twi1_mux),
+	ADI_PMX_FUNCTION("rotary", rotarygrp, rotary_mux),
+	ADI_PMX_FUNCTION("can0", can0grp, can0_mux),
+	ADI_PMX_FUNCTION("smc0", smc0grp, smc0_mux),
+	ADI_PMX_FUNCTION("sport0", sport0grp, sport0_mux),
+	ADI_PMX_FUNCTION("sport1", sport1grp, sport1_mux),
+	ADI_PMX_FUNCTION("sport2", sport2grp, sport2_mux),
+	ADI_PMX_FUNCTION("ppi0_8b", ppi0_8bgrp, ppi0_8b_mux),
+	ADI_PMX_FUNCTION("ppi0_16b", ppi0_16bgrp, ppi0_16b_mux),
+	ADI_PMX_FUNCTION("ppi0_24b", ppi0_24bgrp, ppi0_24b_mux),
+	ADI_PMX_FUNCTION("ppi1_8b", ppi1_8bgrp, ppi1_8b_mux),
+	ADI_PMX_FUNCTION("ppi1_16b", ppi1_16bgrp, ppi1_16b_mux),
+	ADI_PMX_FUNCTION("ppi2_8b", ppi2_8bgrp, ppi2_8b_mux),
+	ADI_PMX_FUNCTION("ppi2_16b", ppi2_16bgrp, ppi2_16b_mux),
+};
+
+#endif	/* CONFIG_PINCTRL */
+
 #endif				/* _MACH_PORTMUX_H_ */
-- 
1.8.2.3



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

* Re: [PATCH 1/3] pinctrl: ADI PIN control driver for the GPIO controller on bf54x and bf60x.
  2013-07-16 10:55 [PATCH 1/3] pinctrl: ADI PIN control driver for the GPIO controller on bf54x and bf60x Sonic Zhang
  2013-07-16 10:55 ` [PATCH 2/3] blackfin: gpio: Remove none gpio lib code Sonic Zhang
  2013-07-16 10:55 ` [PATCH 3/3] blackfin: pinctrl-adi2: Add pin control device groups and function data Sonic Zhang
@ 2013-07-23  7:32 ` Sonic Zhang
  2013-07-26  4:57 ` Sonic Zhang
  2013-08-14 13:47 ` Linus Walleij
  4 siblings, 0 replies; 17+ messages in thread
From: Sonic Zhang @ 2013-07-23  7:32 UTC (permalink / raw)
  To: Linus Walleij, Grant Likely, Steven Miao
  Cc: LKML, buildroot-devel, adi-buildroot-devel, Sonic Zhang

Ping

On Tue, Jul 16, 2013 at 6:55 PM, Sonic Zhang <sonic.adi@gmail.com> wrote:
> From: Sonic Zhang <sonic.zhang@analog.com>
>
> The new ADI GPIO2 controller was introduced since the BF548 and BF60x
> processors. It differs a lot from the old one on BF5xx processors. So,
> create a pinctrl driver under pinctrl framework.
>
> - Define gpio ports and gpio interrupt controllers as individual platform
> devices.
> - Register a pinctrl driver for the whole GPIO ports and GPIO interrupt
> devices.
> - Probe pint devices before port devices. Put device instances into
> respective gpio and pint lists.
> - Define peripheral, irq and gpio reservation bit masks for each gpio
> port as runtime resources.
> - Save and restore gpio port and pint status MMRs in syscore PM functions.
> - Add peripheral device groups and function data into machine portmux.h.
> - Handle peripheral and gpio requests in pinctrl operation functions.
> - Demux gpio IRQs via the irq_domain created by each GPIO port.
>
> Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
> ---
>  drivers/pinctrl/Makefile                   |    1 +
>  drivers/pinctrl/pinctrl-adi2.c             | 1545 ++++++++++++++++++++++++++++
>  include/linux/platform_data/pinctrl-adi2.h |   38 +
>  3 files changed, 1584 insertions(+)
>  create mode 100644 drivers/pinctrl/pinctrl-adi2.c
>  create mode 100644 include/linux/platform_data/pinctrl-adi2.h
>
> diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
> index d64563bf..c685958 100644
> --- a/drivers/pinctrl/Makefile
> +++ b/drivers/pinctrl/Makefile
> @@ -14,6 +14,7 @@ obj-$(CONFIG_PINCTRL_AB8500)  += pinctrl-ab8500.o
>  obj-$(CONFIG_PINCTRL_AB8540)   += pinctrl-ab8540.o
>  obj-$(CONFIG_PINCTRL_AB9540)   += pinctrl-ab9540.o
>  obj-$(CONFIG_PINCTRL_AB8505)   += pinctrl-ab8505.o
> +obj-$(CONFIG_PINCTRL_ADI2)     += pinctrl-adi2.o
>  obj-$(CONFIG_PINCTRL_AT91)     += pinctrl-at91.o
>  obj-$(CONFIG_PINCTRL_BCM2835)  += pinctrl-bcm2835.o
>  obj-$(CONFIG_PINCTRL_BAYTRAIL) += pinctrl-baytrail.o
> diff --git a/drivers/pinctrl/pinctrl-adi2.c b/drivers/pinctrl/pinctrl-adi2.c
> new file mode 100644
> index 0000000..222a74c
> --- /dev/null
> +++ b/drivers/pinctrl/pinctrl-adi2.c
> @@ -0,0 +1,1545 @@
> +/*
> + * Pinctrl Driver for ADI GPIO2 controller
> + *
> + * Copyright 2007-2013 Analog Devices Inc.
> + *
> + * Licensed under the GPLv2 or later
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/module.h>
> +#include <linux/err.h>
> +#include <linux/proc_fs.h>
> +#include <linux/seq_file.h>
> +#include <linux/irq.h>
> +#include <linux/platform_data/pinctrl-adi2.h>
> +#include <linux/irqdomain.h>
> +#include <linux/irqchip/chained_irq.h>
> +#include <linux/pinctrl/pinctrl.h>
> +#include <linux/pinctrl/pinmux.h>
> +#include <linux/pinctrl/consumer.h>
> +#include <linux/pinctrl/machine.h>
> +#include <linux/syscore_ops.h>
> +#include <linux/gpio.h>
> +#include <asm/portmux.h>
> +#include "core.h"
> +
> +static LIST_HEAD(adi_pint_list);
> +static LIST_HEAD(adi_pinctrl_list);
> +
> +#define PERIPHERAL_USAGE 1
> +#define GPIO_USAGE 0
> +
> +#define DRIVER_NAME "pinctrl-adi2"
> +
> +#define RESOURCE_LABEL_SIZE    16
> +#define PINT_HI_OFFSET         16
> +
> +#define RSV_NONE       0
> +#define RSV_GPIO       1
> +#define RSV_INT                2
> +#define RSV_PERI       3
> +
> +/**
> + * struct gpio_reserve_map - a GPIO map structure containing the
> + * reservation status of each PIN.
> + *
> + * @owner: who request the reservation
> + * @rsv_gpio: if this pin is reserved as GPIO
> + * @rsv_int: if this pin is reserved as interrupt
> + * @rsv_peri: if this pin is reserved as part of a peripheral device
> + */
> +struct gpio_reserve_map {
> +       unsigned char owner[RESOURCE_LABEL_SIZE];
> +       bool rsv_gpio;
> +       bool rsv_int;
> +       bool rsv_peri;
> +};
> +
> +/**
> + * struct gpio_port_saved - GPIO port registers that should be saved between
> + * power suspend and resume operations.
> + *
> + * @fer: PORTx_FER register
> + * @data: PORTx_DATA register
> + * @dir: PORTx_DIR register
> + * @inen: PORTx_INEN register
> + * @mux: PORTx_MUX register
> + */
> +struct gpio_port_saved {
> +       u16 fer;
> +       u16 data;
> +       u16 dir;
> +       u16 inen;
> +       u32 mux;
> +};
> +
> +/**
> + * struct gpio_pint - GPIO interrupt controller device. Multiple ADI GPIO
> + * banks can be mapped into one GPIO interrupt controller.
> + *
> + * @node: All gpio_pint instances are added to a global list.
> + * @base: GPIO PINT device register base address
> + * @irq: IRQ of the GPIO PINT device, it is the parent IRQ of all
> + *       GPIO IRQs mapping to this device.
> + * @domain: [0] irq domain of the gpio port, whose hardware interrupts are
> + *             mapping to the low 16-bit of the pint registers.
> + *          [1] irq domain of the gpio port, whose hardware interrupts are
> + *             mapping to the high 16-bit of the pint registers.
> + * @regs: address pointer to the GPIO PINT device
> + * @map_count: No more than 2 GPIO banks can be mapped to this PINT device.
> + * @lock: This lock make sure the irq_chip operations to one GPIO PINT device
> + *        for different GPIO interrrupts are atomic.
> + * @pint_map_port: Set up the mapping between one GPIO PINT device and
> + *                 multiple GPIO banks.
> + */
> +struct gpio_pint {
> +       struct list_head node;
> +       void __iomem *base;
> +       int irq;
> +       struct irq_domain *domain[2];
> +       struct gpio_pint_regs *regs;
> +       struct adi_pm_pint_save saved_data;
> +       int map_count;
> +       spinlock_t lock;
> +
> +       int (*pint_map_port)(struct gpio_pint *pint, u8 assign,
> +                               u8 map, struct irq_domain *domain);
> +};
> +
> +/**
> + * ADI pin controller
> + *
> + * @node: All adi_pmx instances are added to a global list.
> + * @dev: a pointer back to containing device
> + * @pctl: the pinctrl device
> + * @gpio_list: the list of gpio banks owned by this pin controller.
> + * @gpio_base: the base gpio number of this pin controller.
> + */
> +struct adi_pmx {
> +       struct list_head node;
> +       struct device *dev;
> +       struct pinctrl_dev *pctl;
> +       struct list_head gpio_list;
> +       unsigned long gpio_base;
> +};
> +
> +/**
> + * struct gpio_pint - GPIO bank device. Multiple ADI GPIO banks can be mapped
> + * into one GPIO interrupt controller.
> + *
> + * @node: All gpio_pint instances are added to a list.
> + * @base: GPIO bank device register base address
> + * @pin_base: base global GPIO pin index of the GPIO bank device
> + * @irq_base: base IRQ of the GPIO bank device
> + * @width: PIN number of the GPIO bank device
> + * @range: The range space of the GPIO bank handled by the pin controller.
> + * @regs: address pointer to the GPIO bank device
> + * @saved_data: registers that should be saved between PM operations.
> + * @dev: device structure of this GPIO bank
> + * @pmx: the pinctrl device
> + * @pint: GPIO PINT device that this GPIO bank mapped to
> + * @pint_map: GIOP bank mapping code in PINT device
> + * @pint_assign: The 32-bit GPIO PINT registers can be divided into 2 parts. A
> + *               GPIO bank can be mapped into either low 16 bits[0] or high 16
> + *               bits[1] of each PINT register.
> + * @lock: This lock make sure the irq_chip operations to one GPIO PINT device
> + *        for different GPIO interrrupts are atomic.
> + * @chip: abstract a GPIO controller
> + * @domain: The irq domain owned by the GPIO port.
> + * @rsvmap: Reservation map array for each pin in the GPIO bank
> + */
> +struct gpio_port {
> +       struct list_head node;
> +       void __iomem *base;
> +       unsigned int pin_base;
> +       unsigned int irq_base;
> +       unsigned int width;
> +       struct pinctrl_gpio_range range;
> +       struct gpio_port_t *regs;
> +       struct gpio_port_saved saved_data;
> +       struct device *dev;
> +       struct adi_pmx *pmx;
> +
> +       struct gpio_pint *pint;
> +       u8 pint_map;
> +       u8 pint_assign;
> +
> +       spinlock_t lock;
> +       struct gpio_chip chip;
> +       struct irq_domain *domain;
> +
> +       struct gpio_reserve_map rsvmap[];
> +};
> +
> +static inline u8 pin_to_offset(struct pinctrl_gpio_range *range, unsigned pin)
> +{
> +       return pin - range->pin_base;
> +}
> +
> +static inline unsigned offset_to_gpio(struct gpio_port *port, u8 offset)
> +{
> +       return offset + port->chip.base;
> +}
> +
> +static inline u8 gpio_to_offset(struct gpio_port *port, unsigned gpio)
> +{
> +       return gpio - port->chip.base;
> +}
> +
> +static inline unsigned hwirq_to_pintbit(struct gpio_port *port, int hwirq)
> +{
> +       return (1 << hwirq) << (port->pint_assign * PINT_HI_OFFSET);
> +}
> +
> +static void set_label(struct gpio_port *port, unsigned offset,
> +       const char *label)
> +{
> +       char *pch = port->rsvmap[offset].owner;
> +
> +       if (label) {
> +               strncpy(pch, label, RESOURCE_LABEL_SIZE);
> +               pch[RESOURCE_LABEL_SIZE - 1] = 0;
> +       }
> +}
> +
> +static char *get_label(struct gpio_port *port, unsigned offset)
> +{
> +       char *pch = port->rsvmap[offset].owner;
> +
> +       return *pch ? pch : "UNKNOWN";
> +}
> +
> +static inline unsigned int is_reserved(struct gpio_port *port, char type,
> +       unsigned offset)
> +{
> +       switch (type) {
> +       case RSV_GPIO:
> +               return port->rsvmap[offset].rsv_gpio == true;
> +       case RSV_INT:
> +               return port->rsvmap[offset].rsv_int == true;
> +       case RSV_PERI:
> +               return port->rsvmap[offset].rsv_peri == true;
> +       }
> +
> +       return 0;
> +}
> +
> +static inline void reserve(struct gpio_port *port, char type, unsigned offset)
> +{
> +       switch (type) {
> +       case RSV_GPIO:
> +               port->rsvmap[offset].rsv_gpio = true;
> +               break;
> +       case RSV_INT:
> +               port->rsvmap[offset].rsv_int = true;
> +               break;
> +       case RSV_PERI:
> +               port->rsvmap[offset].rsv_peri = true;
> +               break;
> +       }
> +}
> +
> +static inline void unreserve(struct gpio_port *port, char type, unsigned offset)
> +{
> +       switch (type) {
> +       case RSV_GPIO:
> +               port->rsvmap[offset].rsv_gpio = false;
> +               break;
> +       case RSV_INT:
> +               port->rsvmap[offset].rsv_int = false;
> +               break;
> +       case RSV_PERI:
> +               port->rsvmap[offset].rsv_peri = false;
> +               break;
> +       }
> +}
> +
> +static struct gpio_pint *find_gpio_pint(unsigned id)
> +{
> +       struct gpio_pint *pint;
> +       int i = 0;
> +
> +       list_for_each_entry(pint, &adi_pint_list, node) {
> +               if (id == i)
> +                       break;
> +               i++;
> +       }
> +
> +       if (&pint->node != &adi_pint_list)
> +               return pint;
> +       else
> +               return NULL;
> +}
> +
> +static struct adi_pmx *find_pinctrl(unsigned id)
> +{
> +       struct adi_pmx *pmx;
> +       int i = 0;
> +
> +       list_for_each_entry(pmx, &adi_pinctrl_list, node) {
> +               if (id == i)
> +                       break;
> +               i++;
> +       }
> +
> +       if (&pmx->node != &adi_pinctrl_list)
> +               return pmx;
> +       else
> +               return NULL;
> +}
> +
> +static struct gpio_port *find_gpio_port(unsigned pin,
> +       struct list_head *gpio_list)
> +{
> +       struct gpio_port *port;
> +
> +       list_for_each_entry(port, gpio_list, node)
> +               if (pin >= port->range.pin_base &&
> +                       pin < port->range.pin_base + port->range.npins)
> +                       break;
> +
> +       if (&port->node != gpio_list)
> +               return port;
> +       else
> +               return NULL;
> +}
> +
> +static inline void port_setup(struct gpio_port *port, unsigned offset,
> +       unsigned short usage)
> +{
> +       struct gpio_port_t *regs = port->regs;
> +
> +       if (usage == GPIO_USAGE)
> +               writew(readw(&regs->port_fer) & ~(1 << offset),
> +                       &regs->port_fer);
> +       else
> +               writew(readw(&regs->port_fer) | (1 << offset), &regs->port_fer);
> +}
> +
> +static inline void portmux_setup(struct gpio_port *port, unsigned offset,
> +       unsigned short function)
> +{
> +       struct gpio_port_t *regs = port->regs;
> +       u32 pmux;
> +
> +       pmux = readl(&regs->port_mux);
> +
> +       pmux &= ~(0x3 << (2 * offset));
> +       pmux |= (function & 0x3) << (2 * offset);
> +
> +       writel(pmux, &regs->port_mux);
> +}
> +
> +static inline u16 get_portmux(struct gpio_port *port, unsigned offset)
> +{
> +       struct gpio_port_t *regs = port->regs;
> +       u32 pmux = readl(&regs->port_mux);
> +
> +       return pmux >> (2 * offset) & 0x3;
> +}
> +
> +
> +static void __adi_gpio_irq_prepare(struct gpio_port *port, unsigned offset)
> +{
> +       struct gpio_port_t *regs = port->regs;
> +
> +       port_setup(port, offset, GPIO_USAGE);
> +
> +       writew(1 << offset, &regs->dir_clear);
> +       writew(readw(&regs->inen) | (1 << offset), &regs->inen);
> +}
> +
> +static int __adi_gpio_irq_request(struct gpio_port *port, unsigned offset,
> +       const char *label)
> +{
> +       if (unlikely(is_reserved(port, RSV_PERI, offset))) {
> +               if (system_state == SYSTEM_BOOTING)
> +                       dump_stack();
> +
> +               dev_err(port->dev,
> +                      "GPIO %d is already reserved as Peripheral by %s !\n",
> +                       offset_to_gpio(port, offset), get_label(port, offset));
> +               return -EBUSY;
> +       }
> +       if (unlikely(is_reserved(port, RSV_GPIO, offset)))
> +               dev_err(port->dev,
> +                       "GPIO %d is already reserved by %s!\n",
> +                       offset_to_gpio(port, offset), get_label(port, offset));
> +
> +       reserve(port, RSV_INT, offset);
> +       set_label(port, offset, label);
> +       port_setup(port, offset, GPIO_USAGE);
> +
> +       return 0;
> +}
> +
> +static void __adi_gpio_irq_free(struct gpio_port *port, unsigned offset)
> +{
> +       if (unlikely(!is_reserved(port, RSV_INT, offset))) {
> +               if (system_state == SYSTEM_BOOTING)
> +                       dump_stack();
> +
> +               dev_err(port->dev, "GPIO %d wasn't requested!\n",
> +                       offset_to_gpio(port, offset));
> +               return;
> +       }
> +
> +       unreserve(port, RSV_INT, offset);
> +       set_label(port, offset, "free");
> +}
> +
> +static void adi_gpio_ack_irq(struct irq_data *d)
> +{
> +       unsigned long flags;
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +       struct gpio_pint_regs *regs = port->pint->regs;
> +       unsigned pintbit = hwirq_to_pintbit(port, d->hwirq);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +       spin_lock_irqsave(&port->pint->lock, flags);
> +
> +       if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) {
> +               if (readl(&regs->invert_set) & pintbit)
> +                       writel(pintbit, &regs->invert_clear);
> +               else
> +                       writel(pintbit, &regs->invert_set);
> +       }
> +
> +       writel(pintbit, &regs->request);
> +
> +       spin_unlock_irqrestore(&port->pint->lock, flags);
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static void adi_gpio_mask_ack_irq(struct irq_data *d)
> +{
> +       unsigned long flags;
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +       struct gpio_pint_regs *regs = port->pint->regs;
> +       unsigned pintbit = hwirq_to_pintbit(port, d->hwirq);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +       spin_lock_irqsave(&port->pint->lock, flags);
> +
> +       if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) {
> +               if (readl(&regs->invert_set) & pintbit)
> +                       writel(pintbit, &regs->invert_clear);
> +               else
> +                       writel(pintbit, &regs->invert_set);
> +       }
> +
> +       writel(pintbit, &regs->request);
> +       writel(pintbit, &regs->mask_clear);
> +
> +       spin_unlock_irqrestore(&port->pint->lock, flags);
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static void adi_gpio_mask_irq(struct irq_data *d)
> +{
> +       unsigned long flags;
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +       struct gpio_pint_regs *regs = port->pint->regs;
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +       spin_lock_irqsave(&port->pint->lock, flags);
> +
> +       writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_clear);
> +
> +       spin_unlock_irqrestore(&port->pint->lock, flags);
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static void adi_gpio_unmask_irq(struct irq_data *d)
> +{
> +       unsigned long flags;
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +       struct gpio_pint_regs *regs = port->pint->regs;
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +       spin_lock_irqsave(&port->pint->lock, flags);
> +
> +       writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_set);
> +
> +       spin_unlock_irqrestore(&port->pint->lock, flags);
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static unsigned int adi_gpio_irq_startup(struct irq_data *d)
> +{
> +       unsigned long flags;
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +       struct gpio_pint_regs *regs = port->pint->regs;
> +
> +       if (!port) {
> +               dev_err(port->dev, "GPIO IRQ %d :Not exist\n", d->irq);
> +               return -ENODEV;
> +       }
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +       spin_lock_irqsave(&port->pint->lock, flags);
> +
> +       __adi_gpio_irq_prepare(port, d->hwirq);
> +       writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_set);
> +
> +       spin_unlock_irqrestore(&port->pint->lock, flags);
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return 0;
> +}
> +
> +static void adi_gpio_irq_shutdown(struct irq_data *d)
> +{
> +       unsigned long flags;
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +       struct gpio_pint_regs *regs = port->pint->regs;
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +       spin_lock_irqsave(&port->pint->lock, flags);
> +
> +       writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_clear);
> +       __adi_gpio_irq_free(port, d->hwirq);
> +
> +       spin_unlock_irqrestore(&port->pint->lock, flags);
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static int adi_gpio_irq_type(struct irq_data *d, unsigned int type)
> +{
> +       unsigned long flags;
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +       struct gpio_pint_regs *pint_regs = port->pint->regs;
> +       unsigned pintmask;
> +       unsigned int irq = d->irq;
> +       int ret = 0;
> +       char buf[16];
> +
> +       if (!port) {
> +               dev_err(port->dev, "GPIO IRQ %d :Not exist\n", irq);
> +               return -ENODEV;
> +       }
> +
> +       pintmask = hwirq_to_pintbit(port, d->hwirq);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +       spin_lock_irqsave(&port->pint->lock, flags);
> +
> +       if (type == IRQ_TYPE_PROBE)
> +               type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
> +
> +       if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
> +                   IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
> +               snprintf(buf, 16, "gpio-irq%d", irq);
> +               ret = __adi_gpio_irq_request(port, d->hwirq, buf);
> +               if (ret)
> +                       goto out;
> +       } else
> +               goto out;
> +
> +       if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
> +               /* low or falling edge denoted by one */
> +               writel(pintmask, &pint_regs->invert_set);
> +       else
> +               /* high or rising edge denoted by zero */
> +               writel(pintmask, &pint_regs->invert_clear);
> +
> +       if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
> +               if (gpio_get_value(offset_to_gpio(port, d->hwirq)))
> +                       writel(pintmask, &pint_regs->invert_set);
> +               else
> +                       writel(pintmask, &pint_regs->invert_clear);
> +       }
> +
> +       if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
> +               writel(pintmask, &pint_regs->edge_set);
> +               __irq_set_handler_locked(irq, handle_edge_irq);
> +       } else {
> +               writel(pintmask, &pint_regs->edge_clear);
> +               __irq_set_handler_locked(irq, handle_level_irq);
> +       }
> +
> +out:
> +       spin_unlock_irqrestore(&port->pint->lock, flags);
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return ret;
> +}
> +
> +#ifdef CONFIG_PM
> +static int adi_gpio_set_wake(struct irq_data *d, unsigned int state)
> +{
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +
> +       if (!port && !port->pint && port->pint->irq != d->irq)
> +               return -EINVAL;
> +
> +#ifndef SEC_GCTL
> +       adi_internal_set_wake(port->pint->irq, state);
> +#endif
> +
> +       return 0;
> +}
> +
> +static int adi_pint_suspend(void)
> +{
> +       struct gpio_pint *pint;
> +
> +       list_for_each_entry(pint, &adi_pint_list, node) {
> +               writel(0xffffffff, &pint->regs->mask_clear);
> +               pint->saved_data.assign = readl(&pint->regs->assign);
> +               pint->saved_data.edge_set = readl(&pint->regs->edge_set);
> +               pint->saved_data.invert_set = readl(&pint->regs->invert_set);
> +       }
> +
> +       return 0;
> +}
> +
> +static void adi_pint_resume(void)
> +{
> +       struct gpio_pint *pint;
> +
> +       list_for_each_entry(pint, &adi_pint_list, node) {
> +               writel(pint->saved_data.assign, &pint->regs->assign);
> +               writel(pint->saved_data.edge_set, &pint->regs->edge_set);
> +               writel(pint->saved_data.invert_set, &pint->regs->invert_set);
> +       }
> +}
> +
> +static int adi_gpio_suspend(void)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +
> +       list_for_each_entry(pmx, &adi_pinctrl_list, node)
> +               list_for_each_entry(port, &pmx->gpio_list, node) {
> +                       port->saved_data.fer = readw(&port->regs->port_fer);
> +                       port->saved_data.mux = readl(&port->regs->port_mux);
> +                       port->saved_data.data = readw(&port->regs->data);
> +                       port->saved_data.inen = readw(&port->regs->inen);
> +                       port->saved_data.dir = readw(&port->regs->dir_set);
> +               }
> +
> +       return adi_pint_suspend();
> +}
> +
> +static void adi_gpio_resume(void)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +
> +       adi_pint_resume();
> +
> +       list_for_each_entry(pmx, &adi_pinctrl_list, node)
> +               list_for_each_entry(port, &pmx->gpio_list, node) {
> +                       writel(port->saved_data.mux, &port->regs->port_mux);
> +                       writew(port->saved_data.fer, &port->regs->port_fer);
> +                       writew(port->saved_data.inen, &port->regs->inen);
> +                       writew(port->saved_data.data & port->saved_data.dir,
> +                                               &port->regs->data_set);
> +                       writew(port->saved_data.dir, &port->regs->dir_set);
> +               }
> +
> +}
> +
> +static struct syscore_ops gpio_pm_syscore_ops = {
> +       .suspend = adi_gpio_suspend,
> +       .resume = adi_gpio_resume,
> +};
> +#else /* CONFIG_PM */
> +#define adi_gpio_set_wake NULL
> +#endif /* CONFIG_PM */
> +
> +#ifdef CONFIG_IRQ_PREFLOW_FASTEOI
> +static inline void preflow_handler(struct irq_desc *desc)
> +{
> +       if (desc->preflow_handler)
> +               desc->preflow_handler(&desc->irq_data);
> +}
> +#else
> +static inline void preflow_handler(struct irq_desc *desc) { }
> +#endif
> +
> +static void adi_gpio_handle_pint_irq(unsigned int inta_irq,
> +                       struct irq_desc *desc)
> +{
> +       u32 request;
> +       u32 level_mask, hwirq;
> +       int umask = 0;
> +       struct gpio_pint *pint = irq_desc_get_handler_data(desc);
> +       struct irq_chip *chip = irq_desc_get_chip(desc);
> +       struct gpio_pint_regs *regs = pint->regs;
> +       struct irq_domain *domain;
> +
> +       preflow_handler(desc);
> +       chained_irq_enter(chip, desc);
> +
> +       request = readl(&regs->request);
> +       level_mask = readl(&regs->edge_set) & request;
> +
> +       hwirq = 0;
> +       domain = pint->domain[0];
> +       while (request) {
> +               if (hwirq == PINT_HI_OFFSET)
> +                       domain = pint->domain[1];
> +
> +               if (request & 1) {
> +                       if (level_mask & (1 << hwirq)) {
> +                               umask = 1;
> +                               chained_irq_exit(chip, desc);
> +                       }
> +                       generic_handle_irq(irq_find_mapping(domain,
> +                                       hwirq % PINT_HI_OFFSET));
> +               }
> +
> +               hwirq++;
> +               request >>= 1;
> +       }
> +
> +       if (!umask)
> +               chained_irq_exit(chip, desc);
> +}
> +
> +static struct irq_chip adi_gpio_irqchip = {
> +       .name = "GPIO",
> +       .irq_ack = adi_gpio_ack_irq,
> +       .irq_mask = adi_gpio_mask_irq,
> +       .irq_mask_ack = adi_gpio_mask_ack_irq,
> +       .irq_unmask = adi_gpio_unmask_irq,
> +       .irq_disable = adi_gpio_mask_irq,
> +       .irq_enable = adi_gpio_unmask_irq,
> +       .irq_set_type = adi_gpio_irq_type,
> +       .irq_startup = adi_gpio_irq_startup,
> +       .irq_shutdown = adi_gpio_irq_shutdown,
> +       .irq_set_wake = adi_gpio_set_wake,
> +};
> +
> +
> +static int adi_get_groups_count(struct pinctrl_dev *pctldev)
> +{
> +       return ARRAY_SIZE(adi_pin_groups);
> +}
> +
> +static const char *adi_get_group_name(struct pinctrl_dev *pctldev,
> +                                      unsigned selector)
> +{
> +       return adi_pin_groups[selector].name;
> +}
> +
> +static int adi_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
> +                              const unsigned **pins,
> +                              unsigned *num_pins)
> +{
> +       *pins = adi_pin_groups[selector].pins;
> +       *num_pins = adi_pin_groups[selector].num;
> +       return 0;
> +}
> +
> +static void adi_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
> +                  unsigned offset)
> +{
> +       seq_puts(s, DRIVER_NAME);
> +}
> +
> +static struct pinctrl_ops adi_pctrl_ops = {
> +       .get_groups_count = adi_get_groups_count,
> +       .get_group_name = adi_get_group_name,
> +       .get_group_pins = adi_get_group_pins,
> +       .pin_dbg_show = adi_pin_dbg_show,
> +};
> +
> +static int adi_pinmux_request(struct pinctrl_dev *pctldev, unsigned pin)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +       unsigned long flags;
> +       struct pin_desc *desc;
> +       u8 offset;
> +
> +       pmx = pinctrl_dev_get_drvdata(pctldev);
> +
> +       port = find_gpio_port(pin, &pmx->gpio_list);
> +       if (port == NULL) {
> +               dev_err(pctldev->dev,
> +                      "%s: Peripheral PIN %d doesn't exist!\n",
> +                      __func__, pin);
> +               return -ENODEV;
> +       }
> +
> +       offset = pin_to_offset(&port->range, pin);
> +       desc = radix_tree_lookup(&pctldev->pin_desc_tree, pin);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       /* If a pin can be muxed as either GPIO or peripheral, make
> +        * sure it is not already a GPIO pin when we request it.
> +        */
> +       if (unlikely(is_reserved(port, RSV_GPIO, offset))) {
> +               if (system_state == SYSTEM_BOOTING)
> +                       dump_stack();
> +               dev_err(pctldev->dev,
> +                      "%s: Peripheral PIN %d is already reserved as GPIO by %s!\n",
> +                      __func__, pin, get_label(port, offset));
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return -EBUSY;
> +       }
> +
> +       if (unlikely(is_reserved(port, RSV_PERI, offset))) {
> +               if (system_state == SYSTEM_BOOTING)
> +                       dump_stack();
> +               dev_err(pctldev->dev,
> +                       "%s: Peripheral PIN %d is already reserved by %s!\n",
> +                       __func__, pin, get_label(port, offset));
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return -EBUSY;
> +       }
> +
> +       reserve(port, RSV_PERI, offset);
> +       set_label(port, offset, desc->mux_owner);
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return 0;
> +}
> +
> +static int adi_pinmux_free(struct pinctrl_dev *pctldev, unsigned pin)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +       unsigned long flags;
> +       u8 offset;
> +
> +       pmx = pinctrl_dev_get_drvdata(pctldev);
> +       port = find_gpio_port(pin, &pmx->gpio_list);
> +       if (port == NULL)
> +               return 0;
> +
> +       offset = pin_to_offset(&port->range, pin);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       if (unlikely(!is_reserved(port, RSV_PERI, offset))) {
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return 0;
> +       }
> +
> +       unreserve(port, RSV_PERI, offset);
> +       set_label(port, offset, "free");
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return 0;
> +}
> +
> +static int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector,
> +       unsigned group)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +       unsigned long flags;
> +       unsigned short *mux = (unsigned short *)adi_pmx_functions[selector].mux;
> +       unsigned short gpio;
> +
> +       pmx = pinctrl_dev_get_drvdata(pctldev);
> +
> +       while (*mux) {
> +               gpio = P_IDENT(*mux);
> +
> +               port = find_gpio_port(gpio - pmx->gpio_base, &pmx->gpio_list);
> +               if (port == NULL) /* should not happen */
> +                       continue;
> +
> +               spin_lock_irqsave(&port->lock, flags);
> +
> +               portmux_setup(port, gpio_to_offset(port, gpio),
> +                                P_FUNCT2MUX(*mux));
> +               port_setup(port, gpio_to_offset(port, gpio), PERIPHERAL_USAGE);
> +               mux++;
> +
> +               spin_unlock_irqrestore(&port->lock, flags);
> +       }
> +
> +       return 0;
> +}
> +
> +static void adi_pinmux_disable(struct pinctrl_dev *pctldev, unsigned selector,
> +       unsigned group)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +       unsigned long flags;
> +       unsigned short *mux = (unsigned short *)adi_pmx_functions[selector].mux;
> +       unsigned short gpio;
> +
> +       pmx = pinctrl_dev_get_drvdata(pctldev);
> +
> +       while (*mux) {
> +               gpio = P_IDENT(*mux);
> +
> +               port = find_gpio_port(gpio - pmx->gpio_base, &pmx->gpio_list);
> +               if (port == NULL) /* should not happen */
> +                       continue;
> +
> +               spin_lock_irqsave(&port->lock, flags);
> +
> +               port_setup(port, gpio_to_offset(port, gpio), GPIO_USAGE);
> +               mux++;
> +
> +               spin_unlock_irqrestore(&port->lock, flags);
> +       }
> +}
> +
> +static int adi_pinmux_get_funcs_count(struct pinctrl_dev *pctldev)
> +{
> +       return ARRAY_SIZE(adi_pmx_functions);
> +}
> +
> +static const char *adi_pinmux_get_func_name(struct pinctrl_dev *pctldev,
> +                                         unsigned selector)
> +{
> +       return adi_pmx_functions[selector].name;
> +}
> +
> +static int adi_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
> +                              const char * const **groups,
> +                              unsigned * const num_groups)
> +{
> +       *groups = adi_pmx_functions[selector].groups;
> +       *num_groups = adi_pmx_functions[selector].num_groups;
> +       return 0;
> +}
> +
> +static int adi_pinmux_request_gpio(struct pinctrl_dev *pctldev,
> +       struct pinctrl_gpio_range *range, unsigned pin)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +       unsigned long flags;
> +       u8 offset;
> +
> +       pmx = pinctrl_dev_get_drvdata(pctldev);
> +       port = find_gpio_port(pin, &pmx->gpio_list);
> +       if (port == NULL) {
> +               dev_err(pctldev->dev,
> +                      "%s: GPIO PIN %d doesn't exist!\n",
> +                      __func__, pin);
> +               return -ENODEV;
> +       }
> +
> +       offset = pin_to_offset(&port->range, pin);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       if (unlikely(is_reserved(port, RSV_GPIO, offset))) {
> +               if (system_state == SYSTEM_BOOTING)
> +                       dump_stack();
> +               dev_err(pctldev->dev,
> +                       "GPIO %d is already reserved by %s !\n",
> +                       offset_to_gpio(port, offset), get_label(port, offset));
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return -EBUSY;
> +       }
> +       if (unlikely(is_reserved(port, RSV_PERI, offset))) {
> +               if (system_state == SYSTEM_BOOTING)
> +                       dump_stack();
> +               dev_err(pctldev->dev,
> +                       "GPIO %d is already reserved as peripheral by %s !\n",
> +                       offset_to_gpio(port, offset), get_label(port, offset));
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return -EBUSY;
> +       }
> +       if (unlikely(is_reserved(port, RSV_INT, offset))) {
> +               dev_err(pctldev->dev,
> +                       "GPIO %d is already reserved as gpio-irq!\n",
> +                       offset_to_gpio(port, offset));
> +       }
> +
> +       reserve(port, RSV_GPIO, offset);
> +       set_label(port, offset, port->chip.label);
> +       port_setup(port, offset, GPIO_USAGE);
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return 0;
> +}
> +
> +static void adi_pinmux_free_gpio(struct pinctrl_dev *pctldev,
> +       struct pinctrl_gpio_range *range, unsigned pin)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +       unsigned long flags;
> +       u8 offset;
> +
> +       pmx = pinctrl_dev_get_drvdata(pctldev);
> +       port = find_gpio_port(pin, &pmx->gpio_list);
> +       if (port == NULL)
> +               return;
> +
> +       offset = pin_to_offset(&port->range, pin);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       if (unlikely(!is_reserved(port, RSV_GPIO, offset))) {
> +               if (system_state == SYSTEM_BOOTING)
> +                       dump_stack();
> +
> +               dev_err(pctldev->dev,
> +                       "GPIO %d wasn't requested!\n",
> +                       offset_to_gpio(port, offset));
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return;
> +       }
> +
> +       unreserve(port, RSV_GPIO, offset);
> +       set_label(port, offset, "free");
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return;
> +}
> +
> +static struct pinmux_ops adi_pinmux_ops = {
> +       .request = adi_pinmux_request,
> +       .free = adi_pinmux_free,
> +       .enable = adi_pinmux_enable,
> +       .disable = adi_pinmux_disable,
> +       .get_functions_count = adi_pinmux_get_funcs_count,
> +       .get_function_name = adi_pinmux_get_func_name,
> +       .get_function_groups = adi_pinmux_get_groups,
> +       .gpio_request_enable = adi_pinmux_request_gpio,
> +       .gpio_disable_free = adi_pinmux_free_gpio,
> +};
> +
> +
> +static struct pinctrl_desc adi_pinmux_desc = {
> +       .name = DRIVER_NAME,
> +       .pins = adi_pads,
> +       .npins = ARRAY_SIZE(adi_pads),
> +       .pctlops = &adi_pctrl_ops,
> +       .pmxops = &adi_pinmux_ops,
> +       .owner = THIS_MODULE,
> +};
> +
> +static int adi_gpio_request(struct gpio_chip *chip, unsigned offset)
> +{
> +       struct gpio_port *port;
> +
> +       port = container_of(chip, struct gpio_port, chip);
> +
> +       return pinctrl_request_gpio(offset_to_gpio(port, offset));
> +}
> +
> +static void adi_gpio_free(struct gpio_chip *chip, unsigned offset)
> +{
> +       struct gpio_port *port;
> +
> +       port = container_of(chip, struct gpio_port, chip);
> +
> +       pinctrl_free_gpio(offset_to_gpio(port, offset));
> +}
> +
> +static int adi_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
> +{
> +       struct gpio_port *port;
> +       unsigned long flags;
> +
> +       port = container_of(chip, struct gpio_port, chip);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       if (unlikely(!is_reserved(port, RSV_GPIO, offset))) {
> +               dev_err(port->dev, "GPIO %d wasn't requested!\n",
> +                       offset_to_gpio(port, offset));
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return -EINVAL;
> +       }
> +
> +       writew(1 << offset, &port->regs->dir_clear);
> +       writew(readw(&port->regs->inen) | (1 << offset), &port->regs->inen);
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return 0;
> +}
> +
> +static void adi_gpio_set_value(struct gpio_chip *chip, unsigned offset,
> +       int value)
> +{
> +       struct gpio_port *port = container_of(chip, struct gpio_port, chip);
> +       struct gpio_port_t *regs = port->regs;
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       if (value)
> +               writew(1 << offset, &regs->data_set);
> +       else
> +               writew(1 << offset, &regs->data_clear);
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static int adi_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
> +       int value)
> +{
> +       struct gpio_port *port = container_of(chip, struct gpio_port, chip);
> +       struct gpio_port_t *regs = port->regs;
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       if (unlikely(!is_reserved(port, RSV_GPIO, offset))) {
> +               dev_err(port->dev, "GPIO %d wasn't requested!\n",
> +                       offset_to_gpio(port, offset));
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return -EINVAL;
> +       }
> +
> +       writew(readw(&regs->inen) & ~(1 << offset), &regs->inen);
> +       adi_gpio_set_value(chip, offset, value);
> +       writew(1 << offset, &regs->dir_set);
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return 0;
> +}
> +
> +static int adi_gpio_get_value(struct gpio_chip *chip, unsigned offset)
> +{
> +       struct gpio_port *port = container_of(chip, struct gpio_port, chip);
> +       struct gpio_port_t *regs = port->regs;
> +       unsigned long flags;
> +       int ret;
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       ret = 1 & (readw(&regs->data) >> offset);
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return ret;
> +}
> +
> +static int adi_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
> +{
> +       struct gpio_port *port = container_of(chip, struct gpio_port, chip);
> +
> +       if (port->irq_base >= 0)
> +               return irq_find_mapping(port->domain, offset);
> +       else
> +               return irq_create_mapping(port->domain, offset);
> +}
> +
> +#if defined(CONFIG_PROC_FS)
> +static inline unsigned short get_gpio_dir(struct gpio_port *port,
> +       unsigned offset)
> +{
> +       struct gpio_port_t *regs = port->regs;
> +
> +       return 1 & (readw(&regs->dir_clear) >> offset);
> +}
> +
> +static int gpio_proc_show(struct seq_file *m, void *v)
> +{
> +       int offset, irq, gpio;
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +
> +       list_for_each_entry(pmx, &adi_pinctrl_list, node)
> +       list_for_each_entry(port, &pmx->gpio_list, node)
> +               for (offset = 0; offset < port->width; offset++) {
> +                       irq = is_reserved(port, RSV_INT, offset);
> +                       gpio = is_reserved(port, RSV_GPIO, offset);
> +                       if (gpio || irq)
> +                               seq_printf(m, "GPIO_%d: \t%s%s \t\tGPIO %s\n",
> +                                       offset_to_gpio(port, offset),
> +                                       get_label(port, offset),
> +                                       (gpio && irq) ? " *" : "",
> +                                       get_gpio_dir(port, offset) ?
> +                                       "OUTPUT" : "INPUT");
> +                       else if (is_reserved(port, RSV_PERI, offset))
> +                               seq_printf(m, "GPIO_%d: \t%s \t\tPeripheral\n",
> +                                       offset_to_gpio(port, offset),
> +                                       get_label(port, offset));
> +                       else
> +                               continue;
> +               }
> +
> +       return 0;
> +}
> +
> +static int gpio_proc_open(struct inode *inode, struct file *file)
> +{
> +       return single_open(file, gpio_proc_show, NULL);
> +}
> +
> +static const struct file_operations gpio_proc_ops = {
> +       .open           = gpio_proc_open,
> +       .read           = seq_read,
> +       .llseek         = seq_lseek,
> +       .release        = single_release,
> +};
> +
> +static __init int gpio_register_proc(void)
> +{
> +       struct proc_dir_entry *proc_gpio;
> +
> +       proc_gpio = proc_create("gpio", 0, NULL, &gpio_proc_ops);
> +       return proc_gpio == NULL;
> +}
> +device_initcall(gpio_register_proc);
> +#endif
> +
> +static int adi_pint_map_port(struct gpio_pint *pint, u8 assign, u8 map,
> +       struct irq_domain *domain)
> +{
> +       struct gpio_pint_regs *regs = pint->regs;
> +
> +       if (pint->map_count > 1)
> +               return -EINVAL;
> +
> +       if (assign > 1)
> +               return -EINVAL;
> +
> +       pint->map_count++;
> +
> +       writel((readl(&regs->assign) & (0xFFFF << !assign * PINT_HI_OFFSET)) |
> +               (((map << 8) | map) << assign * PINT_HI_OFFSET), &regs->assign);
> +
> +       pint->domain[assign] = domain;
> +
> +       return 0;
> +}
> +
> +static int adi_gpio_pint_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct resource *res;
> +       struct gpio_pint *pint;
> +
> +       pint = devm_kzalloc(dev, sizeof(struct gpio_pint), GFP_KERNEL);
> +       if (!pint) {
> +               dev_err(dev, "Memory alloc failed\n");
> +               return -ENOMEM;
> +       }
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       if (unlikely(!res)) {
> +               dev_err(dev, "Invalid mem resource\n");
> +               return -ENODEV;
> +       }
> +
> +       if (!devm_request_mem_region(dev, res->start, resource_size(res),
> +                                    pdev->name)) {
> +               dev_err(dev, "Region already claimed\n");
> +               return -EBUSY;
> +       }
> +
> +       pint->base = devm_ioremap(dev, res->start, resource_size(res));
> +       if (!pint->base) {
> +               dev_err(dev, "Could not ioremap\n");
> +               return -ENOMEM;
> +       }
> +
> +       pint->regs = (struct gpio_pint_regs *)pint->base;
> +
> +       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> +       if (unlikely(!res)) {
> +               dev_err(dev, "Invalid IRQ resource\n");
> +               return -ENODEV;
> +       }
> +
> +       spin_lock_init(&pint->lock);
> +
> +       pint->irq = res->start;
> +       pint->pint_map_port = adi_pint_map_port;
> +       platform_set_drvdata(pdev, pint);
> +
> +       irq_set_chained_handler(pint->irq, adi_gpio_handle_pint_irq);
> +       irq_set_handler_data(pint->irq, pint);
> +
> +       list_add_tail(&pint->node, &adi_pint_list);
> +
> +       return 0;
> +}
> +
> +static int adi_gpio_pint_remove(struct platform_device *pdev)
> +{
> +       struct gpio_pint *pint = platform_get_drvdata(pdev);
> +
> +       list_del(&pint->node);
> +       irq_set_handler(pint->irq, handle_simple_irq);
> +       platform_set_drvdata(pdev, NULL);
> +
> +       return 0;
> +}
> +
> +static int adi_gpio_irq_map(struct irq_domain *d, unsigned int irq,
> +                               irq_hw_number_t hwirq)
> +{
> +       struct gpio_port *port = d->host_data;
> +
> +       if (!port)
> +               return -EINVAL;
> +
> +       irq_set_chip_data(irq, port);
> +       irq_set_chip_and_handler(irq, &adi_gpio_irqchip,
> +                               handle_level_irq);
> +
> +       return 0;
> +}
> +
> +const struct irq_domain_ops adi_gpio_irq_domain_ops = {
> +       .map = adi_gpio_irq_map,
> +       .xlate = irq_domain_xlate_onecell,
> +};
> +
> +static int adi_gpio_init_int(struct gpio_port *port)
> +{
> +       struct device_node *node = port->dev->of_node;
> +       struct gpio_pint *pint = port->pint;
> +       int ret;
> +
> +       port->domain = irq_domain_add_linear(node, port->width,
> +                               &adi_gpio_irq_domain_ops, port);
> +       if (!port->domain) {
> +               dev_err(port->dev, "Failed to create irqdomain\n");
> +               return -ENOSYS;
> +       }
> +
> +       ret = pint->pint_map_port(port->pint, port->pint_assign,
> +                       port->pint_map, port->domain);
> +       if (ret)
> +               return ret;
> +
> +       if (port->irq_base >= 0) {
> +               ret = irq_create_strict_mappings(port->domain, port->irq_base,
> +                                       0, port->width);
> +               if (ret) {
> +                       dev_err(port->dev, "Couldn't associate to domain\n");
> +                       return ret;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +static int adi_gpio_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       const struct adi_pinctrl_gpio_platform_data *pdata;
> +       struct resource *res;
> +       struct gpio_port *port;
> +       static int gpio;
> +       int ret = 0;
> +
> +       pdata = dev->platform_data;
> +       if (!pdata)
> +               return -EINVAL;
> +
> +       port = devm_kzalloc(dev, sizeof(struct gpio_port) +
> +               sizeof(struct gpio_reserve_map) * pdata->port_width,
> +               GFP_KERNEL);
> +       if (!port) {
> +               dev_err(dev, "Memory alloc failed\n");
> +               return -ENOMEM;
> +       }
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       if (unlikely(!res)) {
> +               dev_err(dev, "Invalid mem resource\n");
> +               return -ENODEV;
> +       }
> +
> +       if (!devm_request_mem_region(dev, res->start, resource_size(res),
> +                                    pdev->name)) {
> +               dev_err(dev, "Region already claimed\n");
> +               return -EBUSY;
> +       }
> +
> +       port->base = devm_ioremap(dev, res->start, resource_size(res));
> +       if (!port->base) {
> +               dev_err(dev, "Could not ioremap\n");
> +               return -ENOMEM;
> +       }
> +
> +       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> +       if (unlikely(!res))
> +               port->irq_base = -1;
> +       else
> +               port->irq_base = res->start;
> +
> +       port->width = pdata->port_width;
> +       port->dev = dev;
> +       port->regs = (struct gpio_port_t *)port->base;
> +       port->pint_assign = !!pdata->pint_assign;
> +       port->pint_map = pdata->pint_map;
> +
> +       port->pint = find_gpio_pint(pdata->pint_id);
> +       if (port->pint) {
> +               ret = adi_gpio_init_int(port);
> +               if (ret)
> +                       return ret;
> +       }
> +
> +       port->pmx = find_pinctrl(pdata->pinctrl_id);
> +       if (port->pmx == NULL) {
> +               dev_err(dev, "Could not find pinctrl device\n");
> +               return -ENODEV;
> +       }
> +       if (gpio == 0)
> +               gpio = port->pmx->gpio_base;
> +
> +       spin_lock_init(&port->lock);
> +
> +       platform_set_drvdata(pdev, port);
> +
> +       port->chip.label                = "adi-gpio";
> +       port->chip.direction_input      = adi_gpio_direction_input;
> +       port->chip.get                  = adi_gpio_get_value;
> +       port->chip.direction_output     = adi_gpio_direction_output;
> +       port->chip.set                  = adi_gpio_set_value;
> +       port->chip.request              = adi_gpio_request;
> +       port->chip.free                 = adi_gpio_free;
> +       port->chip.to_irq               = adi_gpio_to_irq;
> +       if (pdata->port_pin_base > 0)
> +               port->chip.base         = pdata->port_pin_base +
> +                                               port->pmx->gpio_base;
> +       else
> +               port->chip.base         = gpio;
> +       port->chip.ngpio                = port->width;
> +       gpio = port->chip.base + port->width;
> +
> +       ret = gpiochip_add(&port->chip);
> +       if (ret)
> +               return ret;
> +
> +       /* Set gpio range to pinctrl driver */
> +       port->range.name = port->chip.label;
> +       port->range.id = pdev->id;
> +       port->range.base = port->chip.base;
> +       port->range.pin_base = port->chip.base - port->pmx->gpio_base;
> +       port->range.npins = port->width;
> +       port->range.gc = &port->chip;
> +       pinctrl_add_gpio_range(port->pmx->pctl, &port->range);
> +
> +       list_add_tail(&port->node, &port->pmx->gpio_list);
> +
> +       return 0;
> +}
> +
> +static int adi_gpio_remove(struct platform_device *pdev)
> +{
> +       struct gpio_port *port = platform_get_drvdata(pdev);
> +       int ret;
> +       u8 offset;
> +
> +       for (offset = 0; offset < port->width; offset++)
> +               irq_dispose_mapping(irq_find_mapping(port->domain, offset));
> +
> +       irq_domain_remove(port->domain);
> +       pinctrl_remove_gpio_range(port->pmx->pctl, &port->range);
> +       list_del(&port->node);
> +       ret = gpiochip_remove(&port->chip);
> +       platform_set_drvdata(pdev, NULL);
> +
> +       return ret;
> +}
> +
> +static int adi_pinctrl_probe(struct platform_device *pdev)
> +{
> +       struct adi_pmx *pmx;
> +       struct resource *res;
> +
> +       pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
> +       if (!pmx)
> +               return -ENOMEM;
> +
> +       pmx->dev = &pdev->dev;
> +
> +       /* Now register the pin controller and all pins it handles */
> +       pmx->pctl = pinctrl_register(&adi_pinmux_desc, &pdev->dev, pmx);
> +       if (!pmx->pctl) {
> +               dev_err(&pdev->dev, "could not register pinctrl ADI2 driver\n");
> +               return -EINVAL;
> +       }
> +
> +       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
> +       if (res)
> +               pmx->gpio_base = res->start;
> +
> +       INIT_LIST_HEAD(&pmx->gpio_list);
> +
> +       list_add_tail(&pmx->node, &adi_pinctrl_list);
> +
> +       return 0;
> +}
> +
> +static int adi_pinctrl_remove(struct platform_device *pdev)
> +{
> +       struct adi_pmx *pmx = platform_get_drvdata(pdev);
> +
> +       list_del(&pmx->node);
> +       pinctrl_unregister(pmx->pctl);
> +       platform_set_drvdata(pdev, NULL);
> +
> +       return 0;
> +}
> +
> +static struct platform_driver adi_pinctrl_driver = {
> +       .probe          = adi_pinctrl_probe,
> +       .remove         = adi_pinctrl_remove,
> +       .driver         = {
> +               .name   = DRIVER_NAME,
> +       },
> +};
> +
> +static struct platform_driver adi_gpio_pint_driver = {
> +       .probe          = adi_gpio_pint_probe,
> +       .remove         = adi_gpio_pint_remove,
> +       .driver         = {
> +               .name   = "adi-gpio-pint",
> +       },
> +};
> +
> +static struct platform_driver adi_gpio_driver = {
> +       .probe          = adi_gpio_probe,
> +       .remove         = adi_gpio_remove,
> +       .driver         = {
> +               .name   = "adi-gpio",
> +       },
> +};
> +
> +static int __init adi_pinctrl_setup(void)
> +{
> +       int ret;
> +
> +       ret = platform_driver_register(&adi_pinctrl_driver);
> +       if (ret)
> +               return ret;
> +
> +       ret = platform_driver_register(&adi_gpio_pint_driver);
> +       if (ret)
> +               goto pint_error;
> +
> +       ret = platform_driver_register(&adi_gpio_driver);
> +       if (ret)
> +               goto gpio_error;
> +
> +#ifdef CONFIG_PM
> +       register_syscore_ops(&gpio_pm_syscore_ops);
> +#endif
> +       return ret;
> +gpio_error:
> +       platform_driver_unregister(&adi_gpio_pint_driver);
> +pint_error:
> +       platform_driver_unregister(&adi_pinctrl_driver);
> +
> +       return ret;
> +}
> +postcore_initcall(adi_pinctrl_setup);
> +
> +MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
> +MODULE_DESCRIPTION("ADI gpio2 pin control driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/platform_data/pinctrl-adi2.h b/include/linux/platform_data/pinctrl-adi2.h
> new file mode 100644
> index 0000000..465578e
> --- /dev/null
> +++ b/include/linux/platform_data/pinctrl-adi2.h
> @@ -0,0 +1,38 @@
> +/*
> + * Pinctrl Driver for ADI GPIO2 controller
> + *
> + * Copyright 2007-2013 Analog Devices Inc.
> + *
> + * Licensed under the GPLv2 or later
> + */
> +
> +
> +#ifndef PINCTRL_ADI2_H
> +#define PINCTRL_ADI2_H
> +
> +#include <linux/io.h>
> +#include <linux/platform_device.h>
> +
> +/**
> + * struct adi_pinctrl_gpio_platform_data - Pinctrl gpio platform data
> + * for ADI GPIO2 device.
> + *
> + * @port_pin_base: Optional global GPIO index of the GPIO bank.
> + *                 0 means driver decides.
> + * @port_width: PIN number of the GPIO bank device
> + * @pint_id: GPIO PINT device id that this GPIO bank should map to.
> + * @pint_assign: The 32-bit GPIO PINT registers can be divided into 2 parts. A
> + *               GPIO bank can be mapped into either low 16 bits[0] or high 16
> + *               bits[1] of each PINT register.
> + * @pint_map: GIOP bank mapping code in PINT device
> + */
> +struct adi_pinctrl_gpio_platform_data {
> +       unsigned int port_pin_base;
> +       unsigned int port_width;
> +       u8 pinctrl_id;
> +       u8 pint_id;
> +       u8 pint_assign;
> +       u8 pint_map;
> +};
> +
> +#endif
> --
> 1.8.2.3
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

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

* Re: [PATCH 2/3] blackfin: gpio: Remove none gpio lib code.
  2013-07-16 10:55 ` [PATCH 2/3] blackfin: gpio: Remove none gpio lib code Sonic Zhang
@ 2013-07-23  7:33   ` Sonic Zhang
  2013-07-26  4:57   ` Sonic Zhang
  2013-08-14 15:34   ` Linus Walleij
  2 siblings, 0 replies; 17+ messages in thread
From: Sonic Zhang @ 2013-07-23  7:33 UTC (permalink / raw)
  To: Linus Walleij, Grant Likely, Steven Miao
  Cc: LKML, buildroot-devel, adi-buildroot-devel, Sonic Zhang

Ping

On Tue, Jul 16, 2013 at 6:55 PM, Sonic Zhang <sonic.adi@gmail.com> wrote:
> From: Sonic Zhang <sonic.zhang@analog.com>
>
> - Remove non gpio lib code from blackfin architecture.
> - Limit the lagecy blackfin gpio driver to bf5xx processors only.
> - Remove unused definition of the pint power functions.
>
> Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
> ---
>  arch/blackfin/Kconfig            |   7 ++
>  arch/blackfin/include/asm/gpio.h | 157 +++++----------------------------------
>  2 files changed, 27 insertions(+), 137 deletions(-)
>
> diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
> index 3b6abc5..9307e7a 100644
> --- a/arch/blackfin/Kconfig
> +++ b/arch/blackfin/Kconfig
> @@ -53,6 +53,9 @@ config GENERIC_BUG
>  config ZONE_DMA
>         def_bool y
>
> +config GENERIC_GPIO
> +       def_bool y
> +
>  config FORCE_MAX_ZONEORDER
>         int
>         default "14"
> @@ -318,6 +321,10 @@ config BF53x
>         depends on (BF531 || BF532 || BF533 || BF534 || BF536 || BF537)
>         default y
>
> +config GPIO_ADI
> +       def_bool y
> +       depends on (BF51x || BF52x || BF53x || BF538 || BF539 || BF561)
> +
>  config MEM_MT48LC64M4A2FB_7E
>         bool
>         depends on (BFIN533_STAMP)
> diff --git a/arch/blackfin/include/asm/gpio.h b/arch/blackfin/include/asm/gpio.h
> index 98d0133..99d338c 100644
> --- a/arch/blackfin/include/asm/gpio.h
> +++ b/arch/blackfin/include/asm/gpio.h
> @@ -25,8 +25,12 @@
>
>  #ifndef __ASSEMBLY__
>
> +#ifndef CONFIG_PINCTRL
> +
>  #include <linux/compiler.h>
> -#include <linux/gpio.h>
> +#include <asm/blackfin.h>
> +#include <asm/portmux.h>
> +#include <asm/irq_handler.h>
>
>  /***********************************************************
>  *
> @@ -45,7 +49,6 @@
>  * MODIFICATION HISTORY :
>  **************************************************************/
>
> -#if !BFIN_GPIO_PINT
>  void set_gpio_dir(unsigned, unsigned short);
>  void set_gpio_inen(unsigned, unsigned short);
>  void set_gpio_polar(unsigned, unsigned short);
> @@ -115,7 +118,6 @@ struct gpio_port_t {
>         unsigned short dummy16;
>         unsigned short inen;
>  };
> -#endif
>
>  #ifdef BFIN_SPECIAL_GPIO_BANKS
>  void bfin_special_gpio_free(unsigned gpio);
> @@ -127,25 +129,21 @@ void bfin_special_gpio_pm_hibernate_suspend(void);
>  #endif
>
>  #ifdef CONFIG_PM
> -int bfin_pm_standby_ctrl(unsigned ctrl);
> +void bfin_gpio_pm_hibernate_restore(void);
> +void bfin_gpio_pm_hibernate_suspend(void);
> +int bfin_gpio_pm_wakeup_ctrl(unsigned gpio, unsigned ctrl);
> +int bfin_gpio_pm_standby_ctrl(unsigned ctrl);
>
>  static inline int bfin_pm_standby_setup(void)
>  {
> -       return bfin_pm_standby_ctrl(1);
> +       return bfin_gpio_pm_standby_ctrl(1);
>  }
>
>  static inline void bfin_pm_standby_restore(void)
>  {
> -       bfin_pm_standby_ctrl(0);
> +       bfin_gpio_pm_standby_ctrl(0);
>  }
>
> -void bfin_gpio_pm_hibernate_restore(void);
> -void bfin_gpio_pm_hibernate_suspend(void);
> -void bfin_pint_suspend(void);
> -void bfin_pint_resume(void);
> -
> -# if !BFIN_GPIO_PINT
> -int gpio_pm_wakeup_ctrl(unsigned gpio, unsigned ctrl);
>
>  struct gpio_port_s {
>         unsigned short data;
> @@ -161,7 +159,6 @@ struct gpio_port_s {
>         unsigned short reserved;
>         unsigned short mux;
>  };
> -# endif
>  #endif /*CONFIG_PM*/
>
>  /***********************************************************
> @@ -178,36 +175,29 @@ struct gpio_port_s {
>  *************************************************************
>  * MODIFICATION HISTORY :
>  **************************************************************/
> -
> -int bfin_gpio_request(unsigned gpio, const char *label);
> -void bfin_gpio_free(unsigned gpio);
>  int bfin_gpio_irq_request(unsigned gpio, const char *label);
>  void bfin_gpio_irq_free(unsigned gpio);
> -int bfin_gpio_direction_input(unsigned gpio);
> -int bfin_gpio_direction_output(unsigned gpio, int value);
> -int bfin_gpio_get_value(unsigned gpio);
> -void bfin_gpio_set_value(unsigned gpio, int value);
> +void bfin_gpio_irq_prepare(unsigned gpio);
> +
> +static inline int irq_to_gpio(unsigned irq)
> +{
> +       return irq - GPIO_IRQ_BASE;
> +}
> +#endif /* CONFIG_PINCTRL */
>
>  #include <asm/irq.h>
>  #include <asm/errno.h>
>
> -#ifdef CONFIG_GPIOLIB
>  #include <asm-generic/gpio.h>          /* cansleep wrappers */
>
>  static inline int gpio_get_value(unsigned int gpio)
>  {
> -       if (gpio < MAX_BLACKFIN_GPIOS)
> -               return bfin_gpio_get_value(gpio);
> -       else
> -               return __gpio_get_value(gpio);
> +       return __gpio_get_value(gpio);
>  }
>
>  static inline void gpio_set_value(unsigned int gpio, int value)
>  {
> -       if (gpio < MAX_BLACKFIN_GPIOS)
> -               bfin_gpio_set_value(gpio, value);
> -       else
> -               __gpio_set_value(gpio, value);
> +       __gpio_set_value(gpio, value);
>  }
>
>  static inline int gpio_cansleep(unsigned int gpio)
> @@ -219,113 +209,6 @@ static inline int gpio_to_irq(unsigned gpio)
>  {
>         return __gpio_to_irq(gpio);
>  }
> -
> -#else /* !CONFIG_GPIOLIB */
> -
> -static inline int gpio_request(unsigned gpio, const char *label)
> -{
> -       return bfin_gpio_request(gpio, label);
> -}
> -
> -static inline void gpio_free(unsigned gpio)
> -{
> -       return bfin_gpio_free(gpio);
> -}
> -
> -static inline int gpio_direction_input(unsigned gpio)
> -{
> -       return bfin_gpio_direction_input(gpio);
> -}
> -
> -static inline int gpio_direction_output(unsigned gpio, int value)
> -{
> -       return bfin_gpio_direction_output(gpio, value);
> -}
> -
> -static inline int gpio_set_debounce(unsigned gpio, unsigned debounce)
> -{
> -       return -EINVAL;
> -}
> -
> -static inline int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
> -{
> -       int err;
> -
> -       err = bfin_gpio_request(gpio, label);
> -       if (err)
> -               return err;
> -
> -       if (flags & GPIOF_DIR_IN)
> -               err = bfin_gpio_direction_input(gpio);
> -       else
> -               err = bfin_gpio_direction_output(gpio,
> -                       (flags & GPIOF_INIT_HIGH) ? 1 : 0);
> -
> -       if (err)
> -               bfin_gpio_free(gpio);
> -
> -       return err;
> -}
> -
> -static inline int gpio_request_array(const struct gpio *array, size_t num)
> -{
> -       int i, err;
> -
> -       for (i = 0; i < num; i++, array++) {
> -               err = gpio_request_one(array->gpio, array->flags, array->label);
> -               if (err)
> -                       goto err_free;
> -       }
> -       return 0;
> -
> -err_free:
> -       while (i--)
> -               bfin_gpio_free((--array)->gpio);
> -       return err;
> -}
> -
> -static inline void gpio_free_array(const struct gpio *array, size_t num)
> -{
> -       while (num--)
> -               bfin_gpio_free((array++)->gpio);
> -}
> -
> -static inline int __gpio_get_value(unsigned gpio)
> -{
> -       return bfin_gpio_get_value(gpio);
> -}
> -
> -static inline void __gpio_set_value(unsigned gpio, int value)
> -{
> -       return bfin_gpio_set_value(gpio, value);
> -}
> -
> -static inline int gpio_get_value(unsigned gpio)
> -{
> -       return __gpio_get_value(gpio);
> -}
> -
> -static inline void gpio_set_value(unsigned gpio, int value)
> -{
> -       return __gpio_set_value(gpio, value);
> -}
> -
> -static inline int gpio_to_irq(unsigned gpio)
> -{
> -       if (likely(gpio < MAX_BLACKFIN_GPIOS))
> -               return gpio + GPIO_IRQ_BASE;
> -
> -       return -EINVAL;
> -}
> -
> -#include <asm-generic/gpio.h>          /* cansleep wrappers */
> -#endif /* !CONFIG_GPIOLIB */
> -
> -static inline int irq_to_gpio(unsigned irq)
> -{
> -       return (irq - GPIO_IRQ_BASE);
> -}
> -
>  #endif /* __ASSEMBLY__ */
>
>  #endif /* __ARCH_BLACKFIN_GPIO_H__ */
> --
> 1.8.2.3
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

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

* Re: [PATCH 3/3] blackfin: pinctrl-adi2: Add pin control device groups and function data.
  2013-07-16 10:55 ` [PATCH 3/3] blackfin: pinctrl-adi2: Add pin control device groups and function data Sonic Zhang
@ 2013-07-23  7:33   ` Sonic Zhang
  2013-07-26  4:58   ` Sonic Zhang
  2013-08-14 15:39   ` Linus Walleij
  2 siblings, 0 replies; 17+ messages in thread
From: Sonic Zhang @ 2013-07-23  7:33 UTC (permalink / raw)
  To: Linus Walleij, Grant Likely, Steven Miao
  Cc: LKML, buildroot-devel, adi-buildroot-devel, Sonic Zhang

Ping

On Tue, Jul 16, 2013 at 6:55 PM, Sonic Zhang <sonic.adi@gmail.com> wrote:
> From: Sonic Zhang <sonic.zhang@analog.com>
>
> Select PINCTRL_ADI2 for bf54x and bf60x by default.
>
> Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
> ---
>  arch/blackfin/Kconfig                           |   7 +
>  arch/blackfin/include/asm/portmux.h             |  14 +-
>  arch/blackfin/mach-bf548/include/mach/portmux.h | 595 +++++++++++++++++++++++-
>  arch/blackfin/mach-bf609/include/mach/portmux.h | 477 ++++++++++++++++++-
>  4 files changed, 1087 insertions(+), 6 deletions(-)
>
> diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
> index 9307e7a..6a3c490 100644
> --- a/arch/blackfin/Kconfig
> +++ b/arch/blackfin/Kconfig
> @@ -325,6 +325,13 @@ config GPIO_ADI
>         def_bool y
>         depends on (BF51x || BF52x || BF53x || BF538 || BF539 || BF561)
>
> +config PINCTRL_ADI2
> +       def_bool y
> +       depends on (BF54x || BF60x)
> +       select PINCTRL
> +       select PINMUX
> +       select IRQ_DOMAIN
> +
>  config MEM_MT48LC64M4A2FB_7E
>         bool
>         depends on (BFIN533_STAMP)
> diff --git a/arch/blackfin/include/asm/portmux.h b/arch/blackfin/include/asm/portmux.h
> index 9b1e2c3..6b3e71c 100644
> --- a/arch/blackfin/include/asm/portmux.h
> +++ b/arch/blackfin/include/asm/portmux.h
> @@ -17,14 +17,24 @@
>  #define P_MAYSHARE     0x2000
>  #define P_DONTCARE     0x1000
>
> -
> +#ifdef CONFIG_PINCTRL
> +#define peripheral_request(per, label) 0
> +#define peripheral_free(per)
> +#define peripheral_request_list(per, label) \
> +       (pdev ? (IS_ERR(devm_pinctrl_get_select_default(&pdev->dev)) \
> +       ? -EINVAL : 0) : 0);
> +#define peripheral_free_list(per)
> +#else
>  int peripheral_request(unsigned short per, const char *label);
>  void peripheral_free(unsigned short per);
>  int peripheral_request_list(const unsigned short per[], const char *label);
>  void peripheral_free_list(const unsigned short per[]);
> +#endif
>
> -#include <asm/gpio.h>
> +#include <linux/err.h>
> +#include <linux/pinctrl/pinctrl.h>
>  #include <mach/portmux.h>
> +#include <linux/gpio.h>
>
>  #ifndef P_SPORT2_TFS
>  #define P_SPORT2_TFS P_UNDEF
> diff --git a/arch/blackfin/mach-bf548/include/mach/portmux.h b/arch/blackfin/mach-bf548/include/mach/portmux.h
> index e222462..9fab923 100644
> --- a/arch/blackfin/mach-bf548/include/mach/portmux.h
> +++ b/arch/blackfin/mach-bf548/include/mach/portmux.h
> @@ -7,8 +7,6 @@
>  #ifndef _MACH_PORTMUX_H_
>  #define _MACH_PORTMUX_H_
>
> -#define MAX_RESOURCES  MAX_BLACKFIN_GPIOS
> -
>  #define P_SPORT2_TFS   (P_DEFINED | P_IDENT(GPIO_PA0) | P_FUNCT(0))
>  #define P_SPORT2_DTSEC (P_DEFINED | P_IDENT(GPIO_PA1) | P_FUNCT(0))
>  #define P_SPORT2_DTPRI (P_DEFINED | P_IDENT(GPIO_PA2) | P_FUNCT(0))
> @@ -317,4 +315,597 @@
>  #define P_NAND_CLE     (P_DONTCARE)
>  #define P_NAND_ALE     (P_DONTCARE)
>
> +#ifdef CONFIG_PINCTRL
> +
> +#include <mach/gpio.h>
> +#include <asm/blackfin.h>
> +#include <asm/irq_handler.h>
> +
> +#define gpio_pint_regs bfin_pint_regs
> +#define adi_internal_set_wake bfin_internal_set_wake
> +
> +static const struct pinctrl_pin_desc adi_pads[] = {
> +       PINCTRL_PIN(0, "PA0"),
> +       PINCTRL_PIN(1, "PA1"),
> +       PINCTRL_PIN(2, "PA2"),
> +       PINCTRL_PIN(3, "PG3"),
> +       PINCTRL_PIN(4, "PA4"),
> +       PINCTRL_PIN(5, "PA5"),
> +       PINCTRL_PIN(6, "PA6"),
> +       PINCTRL_PIN(7, "PA7"),
> +       PINCTRL_PIN(8, "PA8"),
> +       PINCTRL_PIN(9, "PA9"),
> +       PINCTRL_PIN(10, "PA10"),
> +       PINCTRL_PIN(11, "PA11"),
> +       PINCTRL_PIN(12, "PA12"),
> +       PINCTRL_PIN(13, "PA13"),
> +       PINCTRL_PIN(14, "PA14"),
> +       PINCTRL_PIN(15, "PA15"),
> +       PINCTRL_PIN(16, "PB0"),
> +       PINCTRL_PIN(17, "PB1"),
> +       PINCTRL_PIN(18, "PB2"),
> +       PINCTRL_PIN(19, "PB3"),
> +       PINCTRL_PIN(20, "PB4"),
> +       PINCTRL_PIN(21, "PB5"),
> +       PINCTRL_PIN(22, "PB6"),
> +       PINCTRL_PIN(23, "PB7"),
> +       PINCTRL_PIN(24, "PB8"),
> +       PINCTRL_PIN(25, "PB9"),
> +       PINCTRL_PIN(26, "PB10"),
> +       PINCTRL_PIN(27, "PB11"),
> +       PINCTRL_PIN(28, "PB12"),
> +       PINCTRL_PIN(29, "PB13"),
> +       PINCTRL_PIN(30, "PB14"),
> +       PINCTRL_PIN(32, "PC0"),
> +       PINCTRL_PIN(33, "PC1"),
> +       PINCTRL_PIN(34, "PC2"),
> +       PINCTRL_PIN(35, "PC3"),
> +       PINCTRL_PIN(36, "PC4"),
> +       PINCTRL_PIN(37, "PC5"),
> +       PINCTRL_PIN(38, "PC6"),
> +       PINCTRL_PIN(39, "PC7"),
> +       PINCTRL_PIN(40, "PC8"),
> +       PINCTRL_PIN(41, "PC9"),
> +       PINCTRL_PIN(42, "PC10"),
> +       PINCTRL_PIN(43, "PC11"),
> +       PINCTRL_PIN(44, "PC12"),
> +       PINCTRL_PIN(45, "PC13"),
> +       PINCTRL_PIN(48, "PD0"),
> +       PINCTRL_PIN(49, "PD1"),
> +       PINCTRL_PIN(50, "PD2"),
> +       PINCTRL_PIN(51, "PD3"),
> +       PINCTRL_PIN(52, "PD4"),
> +       PINCTRL_PIN(53, "PD5"),
> +       PINCTRL_PIN(54, "PD6"),
> +       PINCTRL_PIN(55, "PD7"),
> +       PINCTRL_PIN(56, "PD8"),
> +       PINCTRL_PIN(57, "PD9"),
> +       PINCTRL_PIN(58, "PD10"),
> +       PINCTRL_PIN(59, "PD11"),
> +       PINCTRL_PIN(60, "PD12"),
> +       PINCTRL_PIN(61, "PD13"),
> +       PINCTRL_PIN(62, "PD14"),
> +       PINCTRL_PIN(63, "PD15"),
> +       PINCTRL_PIN(64, "PE0"),
> +       PINCTRL_PIN(65, "PE1"),
> +       PINCTRL_PIN(66, "PE2"),
> +       PINCTRL_PIN(67, "PE3"),
> +       PINCTRL_PIN(68, "PE4"),
> +       PINCTRL_PIN(69, "PE5"),
> +       PINCTRL_PIN(70, "PE6"),
> +       PINCTRL_PIN(71, "PE7"),
> +       PINCTRL_PIN(72, "PE8"),
> +       PINCTRL_PIN(73, "PE9"),
> +       PINCTRL_PIN(74, "PE10"),
> +       PINCTRL_PIN(75, "PE11"),
> +       PINCTRL_PIN(76, "PE12"),
> +       PINCTRL_PIN(77, "PE13"),
> +       PINCTRL_PIN(78, "PE14"),
> +       PINCTRL_PIN(79, "PE15"),
> +       PINCTRL_PIN(80, "PF0"),
> +       PINCTRL_PIN(81, "PF1"),
> +       PINCTRL_PIN(82, "PF2"),
> +       PINCTRL_PIN(83, "PF3"),
> +       PINCTRL_PIN(84, "PF4"),
> +       PINCTRL_PIN(85, "PF5"),
> +       PINCTRL_PIN(86, "PF6"),
> +       PINCTRL_PIN(87, "PF7"),
> +       PINCTRL_PIN(88, "PF8"),
> +       PINCTRL_PIN(89, "PF9"),
> +       PINCTRL_PIN(90, "PF10"),
> +       PINCTRL_PIN(91, "PF11"),
> +       PINCTRL_PIN(92, "PF12"),
> +       PINCTRL_PIN(93, "PF13"),
> +       PINCTRL_PIN(94, "PF14"),
> +       PINCTRL_PIN(95, "PF15"),
> +       PINCTRL_PIN(96, "PG0"),
> +       PINCTRL_PIN(97, "PG1"),
> +       PINCTRL_PIN(98, "PG2"),
> +       PINCTRL_PIN(99, "PG3"),
> +       PINCTRL_PIN(100, "PG4"),
> +       PINCTRL_PIN(101, "PG5"),
> +       PINCTRL_PIN(102, "PG6"),
> +       PINCTRL_PIN(103, "PG7"),
> +       PINCTRL_PIN(104, "PG8"),
> +       PINCTRL_PIN(105, "PG9"),
> +       PINCTRL_PIN(106, "PG10"),
> +       PINCTRL_PIN(107, "PG11"),
> +       PINCTRL_PIN(108, "PG12"),
> +       PINCTRL_PIN(109, "PG13"),
> +       PINCTRL_PIN(110, "PG14"),
> +       PINCTRL_PIN(111, "PG15"),
> +       PINCTRL_PIN(112, "PH0"),
> +       PINCTRL_PIN(113, "PH1"),
> +       PINCTRL_PIN(114, "PH2"),
> +       PINCTRL_PIN(115, "PH3"),
> +       PINCTRL_PIN(116, "PH4"),
> +       PINCTRL_PIN(117, "PH5"),
> +       PINCTRL_PIN(118, "PH6"),
> +       PINCTRL_PIN(119, "PH7"),
> +       PINCTRL_PIN(120, "PH8"),
> +       PINCTRL_PIN(121, "PH9"),
> +       PINCTRL_PIN(122, "PH10"),
> +       PINCTRL_PIN(123, "PH11"),
> +       PINCTRL_PIN(124, "PH12"),
> +       PINCTRL_PIN(125, "PH13"),
> +       PINCTRL_PIN(128, "PI0"),
> +       PINCTRL_PIN(129, "PI1"),
> +       PINCTRL_PIN(130, "PI2"),
> +       PINCTRL_PIN(131, "PI3"),
> +       PINCTRL_PIN(132, "PI4"),
> +       PINCTRL_PIN(133, "PI5"),
> +       PINCTRL_PIN(134, "PI6"),
> +       PINCTRL_PIN(135, "PI7"),
> +       PINCTRL_PIN(136, "PI8"),
> +       PINCTRL_PIN(137, "PI9"),
> +       PINCTRL_PIN(138, "PI10"),
> +       PINCTRL_PIN(139, "PI11"),
> +       PINCTRL_PIN(140, "PI12"),
> +       PINCTRL_PIN(141, "PI13"),
> +       PINCTRL_PIN(142, "PI14"),
> +       PINCTRL_PIN(143, "PI15"),
> +       PINCTRL_PIN(144, "PJ0"),
> +       PINCTRL_PIN(145, "PJ1"),
> +       PINCTRL_PIN(146, "PJ2"),
> +       PINCTRL_PIN(147, "PJ3"),
> +       PINCTRL_PIN(148, "PJ4"),
> +       PINCTRL_PIN(149, "PJ5"),
> +       PINCTRL_PIN(150, "PJ6"),
> +       PINCTRL_PIN(151, "PJ7"),
> +       PINCTRL_PIN(152, "PJ8"),
> +       PINCTRL_PIN(153, "PJ9"),
> +       PINCTRL_PIN(154, "PJ10"),
> +       PINCTRL_PIN(155, "PJ11"),
> +       PINCTRL_PIN(156, "PJ12"),
> +       PINCTRL_PIN(157, "PJ13"),
> +};
> +
> +static const unsigned uart0_pins[] = {
> +       GPIO_PE7, GPIO_PE8,
> +};
> +
> +static const unsigned uart1_pins[] = {
> +       GPIO_PH0, GPIO_PH1,
> +#ifdef CONFIG_BFIN_UART1_CTSRTS
> +       GPIO_PE9, GPIO_PE10,
> +#endif
> +};
> +
> +static const unsigned uart2_pins[] = {
> +       GPIO_PB4, GPIO_PB5,
> +};
> +
> +static const unsigned uart3_pins[] = {
> +       GPIO_PB6, GPIO_PB7,
> +#ifdef CONFIG_BFIN_UART3_CTSRTS
> +       GPIO_PB2, GPIO_PB3,
> +#endif
> +};
> +
> +static const unsigned rsi0_pins[] = {
> +       GPIO_PC8, GPIO_PC9, GPIO_PC10, GPIO_PC11, GPIO_PC12, GPIO_PC13,
> +};
> +
> +static const unsigned spi0_pins[] = {
> +       GPIO_PE0, GPIO_PE1, GPIO_PE2,
> +};
> +
> +static const unsigned spi1_pins[] = {
> +       GPIO_PG8, GPIO_PG9, GPIO_PG10,
> +};
> +
> +static const unsigned twi0_pins[] = {
> +       GPIO_PE14, GPIO_PE15,
> +};
> +
> +static const unsigned twi1_pins[] = {
> +       GPIO_PB0, GPIO_PB1,
> +};
> +
> +static const unsigned rotary_pins[] = {
> +       GPIO_PH4, GPIO_PH3, GPIO_PH5,
> +};
> +
> +static const unsigned can0_pins[] = {
> +       GPIO_PG13, GPIO_PG12,
> +};
> +
> +static const unsigned can1_pins[] = {
> +       GPIO_PG14, GPIO_PG15,
> +};
> +
> +static const unsigned smc0_pins[] = {
> +       GPIO_PH8, GPIO_PH9, GPIO_PH10, GPIO_PH11, GPIO_PH12, GPIO_PH13,
> +       GPIO_PI0, GPIO_PI1, GPIO_PI2, GPIO_PI3, GPIO_PI4, GPIO_PI5, GPIO_PI6,
> +       GPIO_PI7, GPIO_PI8, GPIO_PI9, GPIO_PI10, GPIO_PI11,
> +       GPIO_PI12, GPIO_PI13, GPIO_PI14, GPIO_PI15,
> +};
> +
> +static const unsigned sport0_pins[] = {
> +       GPIO_PC0, GPIO_PC2, GPIO_PC3, GPIO_PC4, GPIO_PC6, GPIO_PC7,
> +};
> +
> +static const unsigned sport1_pins[] = {
> +       GPIO_PD0, GPIO_PD2, GPIO_PD3, GPIO_PD4, GPIO_PD6, GPIO_PD7,
> +};
> +
> +static const unsigned sport2_pins[] = {
> +       GPIO_PA0, GPIO_PA2, GPIO_PA3, GPIO_PA4, GPIO_PA6, GPIO_PA7,
> +};
> +
> +static const unsigned sport3_pins[] = {
> +       GPIO_PA8, GPIO_PA10, GPIO_PA11, GPIO_PA12, GPIO_PA14, GPIO_PA15,
> +};
> +
> +static const unsigned ppi0_8b_pins[] = {
> +       GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6,
> +       GPIO_PF7, GPIO_PF13, GPIO_PG0, GPIO_PG1, GPIO_PG2,
> +};
> +
> +static const unsigned ppi0_16b_pins[] = {
> +       GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6,
> +       GPIO_PF7, GPIO_PF9, GPIO_PF10, GPIO_PF11, GPIO_PF12,
> +       GPIO_PF13, GPIO_PF14, GPIO_PF15,
> +       GPIO_PG0, GPIO_PG1, GPIO_PG2,
> +};
> +
> +static const unsigned ppi0_24b_pins[] = {
> +       GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6,
> +       GPIO_PF7, GPIO_PF8, GPIO_PF9, GPIO_PF10, GPIO_PF11, GPIO_PF12,
> +       GPIO_PF13, GPIO_PF14, GPIO_PF15, GPIO_PD0, GPIO_PD1, GPIO_PD2,
> +       GPIO_PD3, GPIO_PD4, GPIO_PD5, GPIO_PG3, GPIO_PG4,
> +       GPIO_PG0, GPIO_PG1, GPIO_PG2,
> +};
> +
> +static const unsigned ppi1_8b_pins[] = {
> +       GPIO_PD0, GPIO_PD1, GPIO_PD2, GPIO_PD3, GPIO_PD4, GPIO_PD5, GPIO_PD6,
> +       GPIO_PD7, GPIO_PE11, GPIO_PE12, GPIO_PE13,
> +};
> +
> +static const unsigned ppi1_16b_pins[] = {
> +       GPIO_PD0, GPIO_PD1, GPIO_PD2, GPIO_PD3, GPIO_PD4, GPIO_PD5, GPIO_PD6,
> +       GPIO_PD7, GPIO_PD8, GPIO_PD9, GPIO_PD10, GPIO_PD11, GPIO_PD12,
> +       GPIO_PD13, GPIO_PD14, GPIO_PD15,
> +       GPIO_PE11, GPIO_PE12, GPIO_PE13,
> +};
> +
> +static const unsigned ppi2_8b_pins[] = {
> +       GPIO_PD8, GPIO_PD9, GPIO_PD10, GPIO_PD11, GPIO_PD12,
> +       GPIO_PD13, GPIO_PD14, GPIO_PD15,
> +       GPIO_PA7, GPIO_PB0, GPIO_PB1, GPIO_PB2, GPIO_PB3,
> +};
> +
> +static const unsigned atapi_pins[] = {
> +       GPIO_PH2, GPIO_PJ3, GPIO_PJ4, GPIO_PJ5, GPIO_PJ6,
> +       GPIO_PJ7, GPIO_PJ8, GPIO_PJ9, GPIO_PJ10,
> +       GPIO_PG5, GPIO_PG6, GPIO_PG7,
> +#ifdef CONFIG_BF548_ATAPI_ALTERNATIVE_PORT
> +       GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6,
> +       GPIO_PF7, GPIO_PF8, GPIO_PF9, GPIO_PF10, GPIO_PF11, GPIO_PF12,
> +       GPIO_PF13, GPIO_PF14, GPIO_PF15, GPIO_PG2, GPIO_PG3, GPIO_PG4,
> +#endif
> +};
> +
> +static const unsigned nfc0_pins[] = {
> +       GPIO_PJ1, GPIO_PJ2,
> +};
> +
> +static const unsigned keys_4x4_pins[] = {
> +       GPIO_PD8, GPIO_PD9, GPIO_PD10, GPIO_PD11,
> +       GPIO_PD12, GPIO_PD13, GPIO_PD14, GPIO_PD15,
> +};
> +
> +static const unsigned keys_8x8_pins[] = {
> +       GPIO_PD8, GPIO_PD9, GPIO_PD10, GPIO_PD11,
> +       GPIO_PD12, GPIO_PD13, GPIO_PD14, GPIO_PD15,
> +       GPIO_PE0, GPIO_PE1, GPIO_PE2, GPIO_PE3,
> +       GPIO_PE4, GPIO_PE5, GPIO_PE6, GPIO_PE7,
> +};
> +
> + /**
> + * struct adi_pin_group - describes a pin group
> + * @name: the name of this pin group
> + * @pins: an array of pins
> + * @num: the number of pins in this array
> + */
> +struct adi_pin_group {
> +       const char *name;
> +       const unsigned *pins;
> +       const unsigned num;
> +};
> +
> +#define ADI_PIN_GROUP(n, p)  \
> +       {                       \
> +               .name = n,      \
> +               .pins = p,      \
> +               .num = ARRAY_SIZE(p),   \
> +       }
> +
> +static const struct adi_pin_group adi_pin_groups[] = {
> +       ADI_PIN_GROUP("uart0grp", uart0_pins),
> +       ADI_PIN_GROUP("uart1grp", uart1_pins),
> +       ADI_PIN_GROUP("rsi0grp", rsi0_pins),
> +       ADI_PIN_GROUP("spi0grp", spi0_pins),
> +       ADI_PIN_GROUP("spi1grp", spi1_pins),
> +       ADI_PIN_GROUP("twi0grp", twi0_pins),
> +       ADI_PIN_GROUP("twi1grp", twi1_pins),
> +       ADI_PIN_GROUP("rotarygrp", rotary_pins),
> +       ADI_PIN_GROUP("can0grp", can0_pins),
> +       ADI_PIN_GROUP("can1grp", can1_pins),
> +       ADI_PIN_GROUP("smc0grp", smc0_pins),
> +       ADI_PIN_GROUP("sport0grp", sport0_pins),
> +       ADI_PIN_GROUP("sport1grp", sport1_pins),
> +       ADI_PIN_GROUP("sport2grp", sport2_pins),
> +       ADI_PIN_GROUP("sport3grp", sport3_pins),
> +       ADI_PIN_GROUP("ppi0_8bgrp", ppi0_8b_pins),
> +       ADI_PIN_GROUP("ppi0_16bgrp", ppi0_16b_pins),
> +       ADI_PIN_GROUP("ppi0_24bgrp", ppi0_24b_pins),
> +       ADI_PIN_GROUP("ppi1_8bgrp", ppi1_8b_pins),
> +       ADI_PIN_GROUP("ppi1_16bgrp", ppi1_16b_pins),
> +       ADI_PIN_GROUP("ppi2_8bgrp", ppi2_8b_pins),
> +       ADI_PIN_GROUP("atapigrp", atapi_pins),
> +       ADI_PIN_GROUP("nfc0grp", nfc0_pins),
> +       ADI_PIN_GROUP("keys_4x4grp", keys_4x4_pins),
> +       ADI_PIN_GROUP("keys_8x8grp", keys_8x8_pins),
> +};
> +
> +static const unsigned short uart0_mux[] = {
> +       P_UART0_TX, P_UART0_RX,
> +       0
> +};
> +
> +static const unsigned short uart1_mux[] = {
> +       P_UART1_TX, P_UART1_RX,
> +#ifdef CONFIG_BFIN_UART1_CTSRTS
> +       P_UART1_RTS, P_UART1_CTS,
> +#endif
> +       0
> +};
> +
> +static const unsigned short uart2_mux[] = {
> +       P_UART2_TX, P_UART2_RX,
> +       0
> +};
> +
> +static const unsigned short uart3_mux[] = {
> +       P_UART3_TX, P_UART3_RX,
> +#ifdef CONFIG_BFIN_UART3_CTSRTS
> +       P_UART3_RTS, P_UART3_CTS,
> +#endif
> +       0
> +};
> +
> +static const unsigned short rsi0_mux[] = {
> +       P_SD_D0, P_SD_D1, P_SD_D2, P_SD_D3, P_SD_CLK, P_SD_CMD,
> +       0
> +};
> +
> +static const unsigned short spi0_mux[] = {
> +       P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0
> +};
> +
> +static const unsigned short spi1_mux[] = {
> +       P_SPI1_SCK, P_SPI1_MISO, P_SPI1_MOSI, 0
> +};
> +
> +static const unsigned short twi0_mux[] = {
> +       P_TWI0_SCL, P_TWI0_SDA, 0
> +};
> +
> +static const unsigned short twi1_mux[] = {
> +       P_TWI1_SCL, P_TWI1_SDA, 0
> +};
> +
> +static const unsigned short rotary_mux[] = {
> +       P_CNT_CUD, P_CNT_CDG, P_CNT_CZM, 0
> +};
> +
> +static const unsigned short sport0_mux[] = {
> +       P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
> +       P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0
> +};
> +
> +static const unsigned short sport1_mux[] = {
> +       P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
> +       P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0
> +};
> +
> +static const unsigned short sport2_mux[] = {
> +       P_SPORT2_TFS, P_SPORT2_DTPRI, P_SPORT2_TSCLK, P_SPORT2_RFS,
> +       P_SPORT2_DRPRI, P_SPORT2_RSCLK, 0
> +};
> +
> +static const unsigned short sport3_mux[] = {
> +       P_SPORT3_TFS, P_SPORT3_DTPRI, P_SPORT3_TSCLK, P_SPORT3_RFS,
> +       P_SPORT3_DRPRI, P_SPORT3_RSCLK, 0
> +};
> +
> +static const unsigned short can0_mux[] = {
> +       P_CAN0_RX, P_CAN0_TX, 0
> +};
> +
> +static const unsigned short can1_mux[] = {
> +       P_CAN1_RX, P_CAN1_TX, 0
> +};
> +
> +static const unsigned short smc0_mux[] = {
> +       P_A4, P_A5, P_A6, P_A7, P_A8, P_A9, P_A10, P_A11, P_A12,
> +       P_A13, P_A14, P_A15, P_A16, P_A17, P_A18, P_A19, P_A20, P_A21,
> +       P_A22, P_A23, P_A24, P_A25, P_NOR_CLK, 0,
> +};
> +
> +static const unsigned short ppi0_8b_mux[] = {
> +       P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3,
> +       P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7,
> +       P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
> +       0,
> +};
> +
> +static const unsigned short ppi0_16b_mux[] = {
> +       P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3,
> +       P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7,
> +       P_PPI0_D8, P_PPI0_D9, P_PPI0_D10, P_PPI0_D11,
> +       P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15,
> +       P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
> +       0,
> +};
> +
> +static const unsigned short ppi0_24b_mux[] = {
> +       P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3,
> +       P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7,
> +       P_PPI0_D8, P_PPI0_D9, P_PPI0_D10, P_PPI0_D11,
> +       P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15,
> +       P_PPI0_D16, P_PPI0_D17, P_PPI0_D18, P_PPI0_D19,
> +       P_PPI0_D20, P_PPI0_D21, P_PPI0_D22, P_PPI0_D23,
> +       P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
> +       0,
> +};
> +
> +static const unsigned short ppi1_8b_mux[] = {
> +       P_PPI1_D0, P_PPI1_D1, P_PPI1_D2, P_PPI1_D3,
> +       P_PPI1_D4, P_PPI1_D5, P_PPI1_D6, P_PPI1_D7,
> +       P_PPI1_CLK, P_PPI1_FS1, P_PPI1_FS2,
> +       0,
> +};
> +
> +static const unsigned short ppi1_16b_mux[] = {
> +       P_PPI1_D0, P_PPI1_D1, P_PPI1_D2, P_PPI1_D3,
> +       P_PPI1_D4, P_PPI1_D5, P_PPI1_D6, P_PPI1_D7,
> +       P_PPI1_D8, P_PPI1_D9, P_PPI1_D10, P_PPI1_D11,
> +       P_PPI1_D12, P_PPI1_D13, P_PPI1_D14, P_PPI1_D15,
> +       P_PPI1_CLK, P_PPI1_FS1, P_PPI1_FS2,
> +       0,
> +};
> +
> +static const unsigned short ppi2_8b_mux[] = {
> +       P_PPI2_D0, P_PPI2_D1, P_PPI2_D2, P_PPI2_D3,
> +       P_PPI2_D4, P_PPI2_D5, P_PPI2_D6, P_PPI2_D7,
> +       P_PPI2_CLK, P_PPI2_FS1, P_PPI2_FS2,
> +       0,
> +};
> +
> +static const unsigned short atapi_mux[] = {
> +       P_ATAPI_RESET, P_ATAPI_DIOR, P_ATAPI_DIOW, P_ATAPI_CS0, P_ATAPI_CS1,
> +       P_ATAPI_DMACK, P_ATAPI_DMARQ, P_ATAPI_INTRQ, P_ATAPI_IORDY,
> +       P_ATAPI_D0A, P_ATAPI_D1A, P_ATAPI_D2A, P_ATAPI_D3A, P_ATAPI_D4A,
> +       P_ATAPI_D5A, P_ATAPI_D6A, P_ATAPI_D7A, P_ATAPI_D8A, P_ATAPI_D9A,
> +       P_ATAPI_D10A, P_ATAPI_D11A, P_ATAPI_D12A, P_ATAPI_D13A, P_ATAPI_D14A,
> +       P_ATAPI_D15A, P_ATAPI_A0A, P_ATAPI_A1A, P_ATAPI_A2A,
> +       0
> +};
> +
> +static const unsigned short nfc0_mux[] = {
> +       P_NAND_CE, P_NAND_RB,
> +       0
> +};
> +
> +static const unsigned short keys_4x4_mux[] = {
> +       P_KEY_ROW3, P_KEY_ROW2, P_KEY_ROW1, P_KEY_ROW0,
> +       P_KEY_COL3, P_KEY_COL2, P_KEY_COL1, P_KEY_COL0,
> +       0
> +};
> +
> +static const unsigned short keys_8x8_mux[] = {
> +       P_KEY_ROW7, P_KEY_ROW6, P_KEY_ROW5, P_KEY_ROW4,
> +       P_KEY_ROW3, P_KEY_ROW2, P_KEY_ROW1, P_KEY_ROW0,
> +       P_KEY_COL7, P_KEY_COL6, P_KEY_COL5, P_KEY_COL4,
> +       P_KEY_COL3, P_KEY_COL2, P_KEY_COL1, P_KEY_COL0,
> +       0
> +};
> +
> +struct adi_pmx_func {
> +       const char *name;
> +       const char * const *groups;
> +       const unsigned num_groups;
> +       const unsigned short *mux;
> +};
> +
> +static const char * const uart0grp[] = { "uart0grp" };
> +static const char * const uart1grp[] = { "uart1grp" };
> +static const char * const uart2grp[] = { "uart2grp" };
> +static const char * const uart3grp[] = { "uart3grp" };
> +static const char * const rsi0grp[] = { "rsi0grp" };
> +static const char * const spi0grp[] = { "spi0grp" };
> +static const char * const spi1grp[] = { "spi1grp" };
> +static const char * const twi0grp[] = { "twi0grp" };
> +static const char * const twi1grp[] = { "twi1grp" };
> +static const char * const rotarygrp[] = { "rotarygrp" };
> +static const char * const can0grp[] = { "can0grp" };
> +static const char * const can1grp[] = { "can1grp" };
> +static const char * const smc0grp[] = { "smc0grp" };
> +static const char * const sport0grp[] = { "sport0grp" };
> +static const char * const sport1grp[] = { "sport1grp" };
> +static const char * const sport2grp[] = { "sport2grp" };
> +static const char * const sport3grp[] = { "sport3grp" };
> +static const char * const ppi0_8bgrp[] = { "ppi0_8bgrp" };
> +static const char * const ppi0_16bgrp[] = { "ppi0_16bgrp" };
> +static const char * const ppi0_24bgrp[] = { "ppi0_24bgrp" };
> +static const char * const ppi1_8bgrp[] = { "ppi1_8bgrp" };
> +static const char * const ppi1_16bgrp[] = { "ppi1_16bgrp" };
> +static const char * const ppi2_8bgrp[] = { "ppi2_8bgrp" };
> +static const char * const atapigrp[] = { "atapigrp" };
> +static const char * const nfc0grp[] = { "nfc0grp" };
> +static const char * const keys_4x4grp[] = { "keys_4x4grp" };
> +static const char * const keys_8x8grp[] = { "keys_8x8grp" };
> +
> +#define ADI_PMX_FUNCTION(n, g, m)              \
> +       {                                       \
> +               .name = n,                      \
> +               .groups = g,                    \
> +               .num_groups = ARRAY_SIZE(g),    \
> +               .mux = m,                       \
> +       }
> +
> +static const struct adi_pmx_func adi_pmx_functions[] = {
> +       ADI_PMX_FUNCTION("uart0", uart0grp, uart0_mux),
> +       ADI_PMX_FUNCTION("uart1", uart1grp, uart1_mux),
> +       ADI_PMX_FUNCTION("uart2", uart0grp, uart2_mux),
> +       ADI_PMX_FUNCTION("uart3", uart1grp, uart3_mux),
> +       ADI_PMX_FUNCTION("rsi0", rsi0grp, rsi0_mux),
> +       ADI_PMX_FUNCTION("spi0", spi0grp, spi0_mux),
> +       ADI_PMX_FUNCTION("spi1", spi1grp, spi1_mux),
> +       ADI_PMX_FUNCTION("twi0", twi0grp, twi0_mux),
> +       ADI_PMX_FUNCTION("twi1", twi1grp, twi1_mux),
> +       ADI_PMX_FUNCTION("rotary", rotarygrp, rotary_mux),
> +       ADI_PMX_FUNCTION("can0", can0grp, can0_mux),
> +       ADI_PMX_FUNCTION("can1", can1grp, can1_mux),
> +       ADI_PMX_FUNCTION("smc0", smc0grp, smc0_mux),
> +       ADI_PMX_FUNCTION("sport0", sport0grp, sport0_mux),
> +       ADI_PMX_FUNCTION("sport1", sport1grp, sport1_mux),
> +       ADI_PMX_FUNCTION("sport2", sport2grp, sport2_mux),
> +       ADI_PMX_FUNCTION("sport3", sport3grp, sport3_mux),
> +       ADI_PMX_FUNCTION("ppi0_8b", ppi0_8bgrp, ppi0_8b_mux),
> +       ADI_PMX_FUNCTION("ppi0_16b", ppi0_16bgrp, ppi0_16b_mux),
> +       ADI_PMX_FUNCTION("ppi0_24b", ppi0_24bgrp, ppi0_24b_mux),
> +       ADI_PMX_FUNCTION("ppi1_8b", ppi1_8bgrp, ppi1_8b_mux),
> +       ADI_PMX_FUNCTION("ppi1_16b", ppi1_16bgrp, ppi1_16b_mux),
> +       ADI_PMX_FUNCTION("ppi2_8b", ppi2_8bgrp, ppi2_8b_mux),
> +       ADI_PMX_FUNCTION("atapi", atapigrp, atapi_mux),
> +       ADI_PMX_FUNCTION("nfc0", nfc0grp, nfc0_mux),
> +       ADI_PMX_FUNCTION("keys_4x4", keys_4x4grp, keys_4x4_mux),
> +       ADI_PMX_FUNCTION("keys_8x8", keys_8x8grp, keys_8x8_mux),
> +};
> +
> +#endif /* CONFIG_PINCTRL */
> +
>  #endif /* _MACH_PORTMUX_H_ */
> diff --git a/arch/blackfin/mach-bf609/include/mach/portmux.h b/arch/blackfin/mach-bf609/include/mach/portmux.h
> index 2e1a51c..5f1b1a6 100644
> --- a/arch/blackfin/mach-bf609/include/mach/portmux.h
> +++ b/arch/blackfin/mach-bf609/include/mach/portmux.h
> @@ -7,8 +7,6 @@
>  #ifndef _MACH_PORTMUX_H_
>  #define _MACH_PORTMUX_H_
>
> -#define MAX_RESOURCES  MAX_BLACKFIN_GPIOS
> -
>  /* EMAC RMII Port Mux */
>  #define P_MII0_MDC     (P_DEFINED | P_IDENT(GPIO_PC6) | P_FUNCT(0))
>  #define P_MII0_MDIO    (P_DEFINED | P_IDENT(GPIO_PC7) | P_FUNCT(0))
> @@ -344,4 +342,479 @@
>  #define P_CNT_CUD      (P_DEFINED | P_IDENT(GPIO_PG11) | P_FUNCT(3))
>  #define P_CNT_CDG      (P_DEFINED | P_IDENT(GPIO_PG12) | P_FUNCT(3))
>
> +#ifdef CONFIG_PINCTRL
> +
> +#include <mach/gpio.h>
> +#include <asm/blackfin.h>
> +#include <asm/irq_handler.h>
> +
> +#define gpio_pint_regs bfin_pint_regs
> +#define adi_internal_set_wake bfin_internal_set_wake
> +
> +static const struct pinctrl_pin_desc adi_pads[] = {
> +       PINCTRL_PIN(0, "PA0"),
> +       PINCTRL_PIN(1, "PA1"),
> +       PINCTRL_PIN(2, "PA2"),
> +       PINCTRL_PIN(3, "PG3"),
> +       PINCTRL_PIN(4, "PA4"),
> +       PINCTRL_PIN(5, "PA5"),
> +       PINCTRL_PIN(6, "PA6"),
> +       PINCTRL_PIN(7, "PA7"),
> +       PINCTRL_PIN(8, "PA8"),
> +       PINCTRL_PIN(9, "PA9"),
> +       PINCTRL_PIN(10, "PA10"),
> +       PINCTRL_PIN(11, "PA11"),
> +       PINCTRL_PIN(12, "PA12"),
> +       PINCTRL_PIN(13, "PA13"),
> +       PINCTRL_PIN(14, "PA14"),
> +       PINCTRL_PIN(15, "PA15"),
> +       PINCTRL_PIN(16, "PB0"),
> +       PINCTRL_PIN(17, "PB1"),
> +       PINCTRL_PIN(18, "PB2"),
> +       PINCTRL_PIN(19, "PB3"),
> +       PINCTRL_PIN(20, "PB4"),
> +       PINCTRL_PIN(21, "PB5"),
> +       PINCTRL_PIN(22, "PB6"),
> +       PINCTRL_PIN(23, "PB7"),
> +       PINCTRL_PIN(24, "PB8"),
> +       PINCTRL_PIN(25, "PB9"),
> +       PINCTRL_PIN(26, "PB10"),
> +       PINCTRL_PIN(27, "PB11"),
> +       PINCTRL_PIN(28, "PB12"),
> +       PINCTRL_PIN(29, "PB13"),
> +       PINCTRL_PIN(30, "PB14"),
> +       PINCTRL_PIN(31, "PB15"),
> +       PINCTRL_PIN(32, "PC0"),
> +       PINCTRL_PIN(33, "PC1"),
> +       PINCTRL_PIN(34, "PC2"),
> +       PINCTRL_PIN(35, "PC3"),
> +       PINCTRL_PIN(36, "PC4"),
> +       PINCTRL_PIN(37, "PC5"),
> +       PINCTRL_PIN(38, "PC6"),
> +       PINCTRL_PIN(39, "PC7"),
> +       PINCTRL_PIN(40, "PC8"),
> +       PINCTRL_PIN(41, "PC9"),
> +       PINCTRL_PIN(42, "PC10"),
> +       PINCTRL_PIN(43, "PC11"),
> +       PINCTRL_PIN(44, "PC12"),
> +       PINCTRL_PIN(45, "PC13"),
> +       PINCTRL_PIN(46, "PC14"),
> +       PINCTRL_PIN(47, "PC15"),
> +       PINCTRL_PIN(48, "PD0"),
> +       PINCTRL_PIN(49, "PD1"),
> +       PINCTRL_PIN(50, "PD2"),
> +       PINCTRL_PIN(51, "PD3"),
> +       PINCTRL_PIN(52, "PD4"),
> +       PINCTRL_PIN(53, "PD5"),
> +       PINCTRL_PIN(54, "PD6"),
> +       PINCTRL_PIN(55, "PD7"),
> +       PINCTRL_PIN(56, "PD8"),
> +       PINCTRL_PIN(57, "PD9"),
> +       PINCTRL_PIN(58, "PD10"),
> +       PINCTRL_PIN(59, "PD11"),
> +       PINCTRL_PIN(60, "PD12"),
> +       PINCTRL_PIN(61, "PD13"),
> +       PINCTRL_PIN(62, "PD14"),
> +       PINCTRL_PIN(63, "PD15"),
> +       PINCTRL_PIN(64, "PE0"),
> +       PINCTRL_PIN(65, "PE1"),
> +       PINCTRL_PIN(66, "PE2"),
> +       PINCTRL_PIN(67, "PE3"),
> +       PINCTRL_PIN(68, "PE4"),
> +       PINCTRL_PIN(69, "PE5"),
> +       PINCTRL_PIN(70, "PE6"),
> +       PINCTRL_PIN(71, "PE7"),
> +       PINCTRL_PIN(72, "PE8"),
> +       PINCTRL_PIN(73, "PE9"),
> +       PINCTRL_PIN(74, "PE10"),
> +       PINCTRL_PIN(75, "PE11"),
> +       PINCTRL_PIN(76, "PE12"),
> +       PINCTRL_PIN(77, "PE13"),
> +       PINCTRL_PIN(78, "PE14"),
> +       PINCTRL_PIN(79, "PE15"),
> +       PINCTRL_PIN(80, "PF0"),
> +       PINCTRL_PIN(81, "PF1"),
> +       PINCTRL_PIN(82, "PF2"),
> +       PINCTRL_PIN(83, "PF3"),
> +       PINCTRL_PIN(84, "PF4"),
> +       PINCTRL_PIN(85, "PF5"),
> +       PINCTRL_PIN(86, "PF6"),
> +       PINCTRL_PIN(87, "PF7"),
> +       PINCTRL_PIN(88, "PF8"),
> +       PINCTRL_PIN(89, "PF9"),
> +       PINCTRL_PIN(90, "PF10"),
> +       PINCTRL_PIN(91, "PF11"),
> +       PINCTRL_PIN(92, "PF12"),
> +       PINCTRL_PIN(93, "PF13"),
> +       PINCTRL_PIN(94, "PF14"),
> +       PINCTRL_PIN(95, "PF15"),
> +       PINCTRL_PIN(96, "PG0"),
> +       PINCTRL_PIN(97, "PG1"),
> +       PINCTRL_PIN(98, "PG2"),
> +       PINCTRL_PIN(99, "PG3"),
> +       PINCTRL_PIN(100, "PG4"),
> +       PINCTRL_PIN(101, "PG5"),
> +       PINCTRL_PIN(102, "PG6"),
> +       PINCTRL_PIN(103, "PG7"),
> +       PINCTRL_PIN(104, "PG8"),
> +       PINCTRL_PIN(105, "PG9"),
> +       PINCTRL_PIN(106, "PG10"),
> +       PINCTRL_PIN(107, "PG11"),
> +       PINCTRL_PIN(108, "PG12"),
> +       PINCTRL_PIN(109, "PG13"),
> +       PINCTRL_PIN(110, "PG14"),
> +       PINCTRL_PIN(111, "PG15"),
> +};
> +
> +static const unsigned uart0_pins[] = {
> +       GPIO_PD7, GPIO_PD8,
> +#ifdef CONFIG_BFIN_UART0_CTSRTS
> +       GPIO_PD9, GPIO_PD10,
> +#endif
> +};
> +
> +static const unsigned uart1_pins[] = {
> +       GPIO_PG15, GPIO_PG14,
> +#ifdef CONFIG_BFIN_UART1_CTSRTS
> +       GPIO_PG10, GPIO_PG13,
> +#endif
> +};
> +
> +static const unsigned rsi0_pins[] = {
> +       GPIO_PG3, GPIO_PG2, GPIO_PG0, GPIO_PE15, GPIO_PG5, GPIO_PG6,
> +};
> +
> +static const unsigned eth0_pins[] = {
> +       GPIO_PC6, GPIO_PC7, GPIO_PC2, GPIO_PC0, GPIO_PC3, GPIO_PC1,
> +       GPIO_PB13, GPIO_PD6, GPIO_PC5, GPIO_PC4, GPIO_PB14,
> +};
> +
> +static const unsigned eth1_pins[] = {
> +       GPIO_PE10, GPIO_PE11, GPIO_PG3, GPIO_PG0, GPIO_PG2, GPIO_PE15,
> +       GPIO_PG5, GPIO_PE12, GPIO_PE13, GPIO_PE14, GPIO_PG6,
> +};
> +
> +static const unsigned spi0_pins[] = {
> +       GPIO_PD4, GPIO_PD2, GPIO_PD3,
> +};
> +
> +static const unsigned spi1_pins[] = {
> +       GPIO_PD5, GPIO_PD14, GPIO_PD13,
> +};
> +
> +static const unsigned twi0_pins[] = {
> +};
> +
> +static const unsigned twi1_pins[] = {
> +};
> +
> +static const unsigned rotary_pins[] = {
> +       GPIO_PG7, GPIO_PG11, GPIO_PG12,
> +};
> +
> +static const unsigned can0_pins[] = {
> +       GPIO_PG1, GPIO_PG4,
> +};
> +
> +static const unsigned smc0_pins[] = {
> +       GPIO_PA0, GPIO_PA1, GPIO_PA2, GPIO_PA3, GPIO_PA4, GPIO_PA5, GPIO_PA6,
> +       GPIO_PA7, GPIO_PA8, GPIO_PA9, GPIO_PB2, GPIO_PA10, GPIO_PA11,
> +       GPIO_PB3, GPIO_PA12, GPIO_PA13, GPIO_PA14, GPIO_PA15, GPIO_PB6,
> +       GPIO_PB7, GPIO_PB8, GPIO_PB10, GPIO_PB11, GPIO_PB0,
> +};
> +
> +static const unsigned sport0_pins[] = {
> +       GPIO_PB5, GPIO_PB4, GPIO_PB9, GPIO_PB8, GPIO_PB7, GPIO_PB11,
> +};
> +
> +static const unsigned sport1_pins[] = {
> +       GPIO_PE2, GPIO_PE5, GPIO_PD15, GPIO_PE4, GPIO_PE3, GPIO_PE1,
> +};
> +
> +static const unsigned sport2_pins[] = {
> +       GPIO_PG4, GPIO_PG1, GPIO_PG9, GPIO_PG10, GPIO_PG7, GPIO_PB12,
> +};
> +
> +static const unsigned ppi0_8b_pins[] = {
> +       GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6,
> +       GPIO_PF7, GPIO_PF13, GPIO_PF14, GPIO_PF15,
> +       GPIO_PE6, GPIO_PE7, GPIO_PE8, GPIO_PE9,
> +};
> +
> +static const unsigned ppi0_16b_pins[] = {
> +       GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6,
> +       GPIO_PF7, GPIO_PF9, GPIO_PF10, GPIO_PF11, GPIO_PF12,
> +       GPIO_PF13, GPIO_PF14, GPIO_PF15,
> +       GPIO_PE6, GPIO_PE7, GPIO_PE8, GPIO_PE9,
> +};
> +
> +static const unsigned ppi0_24b_pins[] = {
> +       GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6,
> +       GPIO_PF7, GPIO_PF8, GPIO_PF9, GPIO_PF10, GPIO_PF11, GPIO_PF12,
> +       GPIO_PF13, GPIO_PF14, GPIO_PF15, GPIO_PE0, GPIO_PE1, GPIO_PE2,
> +       GPIO_PE3, GPIO_PE4, GPIO_PE5, GPIO_PE6, GPIO_PE7, GPIO_PE8,
> +       GPIO_PE9, GPIO_PD12, GPIO_PD15,
> +};
> +
> +static const unsigned ppi1_8b_pins[] = {
> +       GPIO_PC0, GPIO_PC1, GPIO_PC2, GPIO_PC3, GPIO_PC4, GPIO_PC5, GPIO_PC6,
> +       GPIO_PC7, GPIO_PC8, GPIO_PB13, GPIO_PB14, GPIO_PB15, GPIO_PD6,
> +};
> +
> +static const unsigned ppi1_16b_pins[] = {
> +       GPIO_PC0, GPIO_PC1, GPIO_PC2, GPIO_PC3, GPIO_PC4, GPIO_PC5, GPIO_PC6,
> +       GPIO_PC7, GPIO_PC9, GPIO_PC10, GPIO_PC11, GPIO_PC12,
> +       GPIO_PC13, GPIO_PC14, GPIO_PC15,
> +       GPIO_PB13, GPIO_PB14, GPIO_PB15, GPIO_PD6,
> +};
> +
> +static const unsigned ppi2_8b_pins[] = {
> +       GPIO_PA0, GPIO_PA1, GPIO_PA2, GPIO_PA3, GPIO_PA4, GPIO_PA5, GPIO_PA6,
> +       GPIO_PA7, GPIO_PB0, GPIO_PB1, GPIO_PB2, GPIO_PB3,
> +};
> +
> +static const unsigned ppi2_16b_pins[] = {
> +       GPIO_PA0, GPIO_PA1, GPIO_PA2, GPIO_PA3, GPIO_PA4, GPIO_PA5, GPIO_PA6,
> +       GPIO_PA7, GPIO_PA8, GPIO_PA9, GPIO_PA10, GPIO_PA11, GPIO_PA12,
> +       GPIO_PA13, GPIO_PA14, GPIO_PA15,
> +       GPIO_PA7, GPIO_PB0, GPIO_PB1, GPIO_PB2, GPIO_PB3,
> +};
> +
> + /**
> + * struct adi_pin_group - describes a pin group
> + * @name: the name of this pin group
> + * @pins: an array of pins
> + * @num: the number of pins in this array
> + */
> +struct adi_pin_group {
> +       const char *name;
> +       const unsigned *pins;
> +       const unsigned num;
> +};
> +
> +#define ADI_PIN_GROUP(n, p)  \
> +       {                       \
> +               .name = n,      \
> +               .pins = p,      \
> +               .num = ARRAY_SIZE(p),   \
> +       }
> +
> +static const struct adi_pin_group adi_pin_groups[] = {
> +       ADI_PIN_GROUP("uart0grp", uart0_pins),
> +       ADI_PIN_GROUP("uart1grp", uart1_pins),
> +       ADI_PIN_GROUP("rsi0grp", rsi0_pins),
> +       ADI_PIN_GROUP("eth0grp", eth0_pins),
> +       ADI_PIN_GROUP("eth1grp", eth1_pins),
> +       ADI_PIN_GROUP("spi0grp", spi0_pins),
> +       ADI_PIN_GROUP("spi1grp", spi1_pins),
> +       ADI_PIN_GROUP("twi0grp", twi0_pins),
> +       ADI_PIN_GROUP("twi1grp", twi1_pins),
> +       ADI_PIN_GROUP("rotarygrp", rotary_pins),
> +       ADI_PIN_GROUP("can0grp", can0_pins),
> +       ADI_PIN_GROUP("smc0grp", smc0_pins),
> +       ADI_PIN_GROUP("sport0grp", sport0_pins),
> +       ADI_PIN_GROUP("sport1grp", sport1_pins),
> +       ADI_PIN_GROUP("sport2grp", sport2_pins),
> +       ADI_PIN_GROUP("ppi0_8bgrp", ppi0_8b_pins),
> +       ADI_PIN_GROUP("ppi0_16bgrp", ppi0_16b_pins),
> +       ADI_PIN_GROUP("ppi0_24bgrp", ppi0_24b_pins),
> +       ADI_PIN_GROUP("ppi1_8bgrp", ppi1_8b_pins),
> +       ADI_PIN_GROUP("ppi1_16bgrp", ppi1_16b_pins),
> +       ADI_PIN_GROUP("ppi2_8bgrp", ppi2_8b_pins),
> +       ADI_PIN_GROUP("ppi2_16bgrp", ppi2_16b_pins),
> +};
> +
> +static const unsigned short uart0_mux[] = {
> +       P_UART0_TX, P_UART0_RX,
> +#ifdef CONFIG_BFIN_UART0_CTSRTS
> +       P_UART0_RTS, P_UART0_CTS,
> +#endif
> +       0
> +};
> +
> +static const unsigned short uart1_mux[] = {
> +       P_UART1_TX, P_UART1_RX,
> +#ifdef CONFIG_BFIN_UART1_CTSRTS
> +       P_UART1_RTS, P_UART1_CTS,
> +#endif
> +       0
> +};
> +
> +static const unsigned short rsi0_mux[] = {
> +       P_RSI_DATA0, P_RSI_DATA1, P_RSI_DATA2, P_RSI_DATA3,
> +       P_RSI_CMD, P_RSI_CLK, 0
> +};
> +
> +static const unsigned short eth0_mux[] = P_RMII0;
> +static const unsigned short eth1_mux[] = P_RMII1;
> +
> +static const unsigned short spi0_mux[] = {
> +       P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0
> +};
> +
> +static const unsigned short spi1_mux[] = {
> +       P_SPI1_SCK, P_SPI1_MISO, P_SPI1_MOSI, 0
> +};
> +
> +static const unsigned short twi0_mux[] = {
> +       P_TWI0_SCL, P_TWI0_SDA, 0
> +};
> +
> +static const unsigned short twi1_mux[] = {
> +       P_TWI1_SCL, P_TWI1_SDA, 0
> +};
> +
> +static const unsigned short rotary_mux[] = {
> +       P_CNT_CUD, P_CNT_CDG, P_CNT_CZM, 0
> +};
> +
> +static const unsigned short sport0_mux[] = {
> +       P_SPORT0_ACLK, P_SPORT0_AFS, P_SPORT0_AD0, P_SPORT0_BCLK,
> +       P_SPORT0_BFS, P_SPORT0_BD0, 0,
> +};
> +
> +static const unsigned short sport1_mux[] = {
> +       P_SPORT1_ACLK, P_SPORT1_AFS, P_SPORT1_AD0, P_SPORT1_BCLK,
> +       P_SPORT1_BFS, P_SPORT1_BD0, 0,
> +};
> +
> +static const unsigned short sport2_mux[] = {
> +       P_SPORT2_ACLK, P_SPORT2_AFS, P_SPORT2_AD0, P_SPORT2_BCLK,
> +       P_SPORT2_BFS, P_SPORT2_BD0, 0,
> +};
> +
> +static const unsigned short can0_mux[] = {
> +       P_CAN0_RX, P_CAN0_TX, 0
> +};
> +
> +static const unsigned short smc0_mux[] = {
> +       P_A3, P_A4, P_A5, P_A6, P_A7, P_A8, P_A9, P_A10, P_A11, P_A12,
> +       P_A13, P_A14, P_A15, P_A16, P_A17, P_A18, P_A19, P_A20, P_A21,
> +       P_A22, P_A23, P_A24, P_A25, P_NORCK, 0,
> +};
> +
> +static const unsigned short ppi0_8b_mux[] = {
> +       P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3,
> +       P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7,
> +       P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
> +       0,
> +};
> +
> +static const unsigned short ppi0_16b_mux[] = {
> +       P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3,
> +       P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7,
> +       P_PPI0_D8, P_PPI0_D9, P_PPI0_D10, P_PPI0_D11,
> +       P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15,
> +       P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
> +       0,
> +};
> +
> +static const unsigned short ppi0_24b_mux[] = {
> +       P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3,
> +       P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7,
> +       P_PPI0_D8, P_PPI0_D9, P_PPI0_D10, P_PPI0_D11,
> +       P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15,
> +       P_PPI0_D16, P_PPI0_D17, P_PPI0_D18, P_PPI0_D19,
> +       P_PPI0_D20, P_PPI0_D21, P_PPI0_D22, P_PPI0_D23,
> +       P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
> +       0,
> +};
> +
> +static const unsigned short ppi1_8b_mux[] = {
> +       P_PPI1_D0, P_PPI1_D1, P_PPI1_D2, P_PPI1_D3,
> +       P_PPI1_D4, P_PPI1_D5, P_PPI1_D6, P_PPI1_D7,
> +       P_PPI1_CLK, P_PPI1_FS1, P_PPI1_FS2,
> +       0,
> +};
> +
> +static const unsigned short ppi1_16b_mux[] = {
> +       P_PPI1_D0, P_PPI1_D1, P_PPI1_D2, P_PPI1_D3,
> +       P_PPI1_D4, P_PPI1_D5, P_PPI1_D6, P_PPI1_D7,
> +       P_PPI1_D8, P_PPI1_D9, P_PPI1_D10, P_PPI1_D11,
> +       P_PPI1_D12, P_PPI1_D13, P_PPI1_D14, P_PPI1_D15,
> +       P_PPI1_CLK, P_PPI1_FS1, P_PPI1_FS2,
> +       0,
> +};
> +
> +static const unsigned short ppi2_8b_mux[] = {
> +       P_PPI2_D0, P_PPI2_D1, P_PPI2_D2, P_PPI2_D3,
> +       P_PPI2_D4, P_PPI2_D5, P_PPI2_D6, P_PPI2_D7,
> +       P_PPI2_CLK, P_PPI2_FS1, P_PPI2_FS2,
> +       0,
> +};
> +
> +static const unsigned short ppi2_16b_mux[] = {
> +       P_PPI2_D0, P_PPI2_D1, P_PPI2_D2, P_PPI2_D3,
> +       P_PPI2_D4, P_PPI2_D5, P_PPI2_D6, P_PPI2_D7,
> +       P_PPI2_D8, P_PPI2_D9, P_PPI2_D10, P_PPI2_D11,
> +       P_PPI2_D12, P_PPI2_D13, P_PPI2_D14, P_PPI2_D15,
> +       P_PPI2_CLK, P_PPI2_FS1, P_PPI2_FS2,
> +       0,
> +};
> +
> +struct adi_pmx_func {
> +       const char *name;
> +       const char * const *groups;
> +       const unsigned num_groups;
> +       const unsigned short *mux;
> +};
> +
> +static const char * const uart0grp[] = { "uart0grp" };
> +static const char * const uart1grp[] = { "uart1grp" };
> +static const char * const rsi0grp[] = { "rsi0grp" };
> +static const char * const eth0grp[] = { "eth0grp" };
> +static const char * const eth1grp[] = { "eth1grp" };
> +static const char * const spi0grp[] = { "spi0grp" };
> +static const char * const spi1grp[] = { "spi1grp" };
> +static const char * const twi0grp[] = { "twi0grp" };
> +static const char * const twi1grp[] = { "twi1grp" };
> +static const char * const rotarygrp[] = { "rotarygrp" };
> +static const char * const can0grp[] = { "can0grp" };
> +static const char * const smc0grp[] = { "smc0grp" };
> +static const char * const sport0grp[] = { "sport0grp" };
> +static const char * const sport1grp[] = { "sport1grp" };
> +static const char * const sport2grp[] = { "sport2grp" };
> +static const char * const ppi0_8bgrp[] = { "ppi0_8bgrp" };
> +static const char * const ppi0_16bgrp[] = { "ppi0_16bgrp" };
> +static const char * const ppi0_24bgrp[] = { "ppi0_24bgrp" };
> +static const char * const ppi1_8bgrp[] = { "ppi1_8bgrp" };
> +static const char * const ppi1_16bgrp[] = { "ppi1_16bgrp" };
> +static const char * const ppi2_8bgrp[] = { "ppi2_8bgrp" };
> +static const char * const ppi2_16bgrp[] = { "ppi2_16bgrp" };
> +
> +#define ADI_PMX_FUNCTION(n, g, m)              \
> +       {                                       \
> +               .name = n,                      \
> +               .groups = g,                    \
> +               .num_groups = ARRAY_SIZE(g),    \
> +               .mux = m,                       \
> +       }
> +
> +static const struct adi_pmx_func adi_pmx_functions[] = {
> +       ADI_PMX_FUNCTION("uart0", uart0grp, uart0_mux),
> +       ADI_PMX_FUNCTION("uart1", uart1grp, uart1_mux),
> +       ADI_PMX_FUNCTION("rsi0", rsi0grp, rsi0_mux),
> +       ADI_PMX_FUNCTION("eth0", eth0grp, eth0_mux),
> +       ADI_PMX_FUNCTION("eth1", eth1grp, eth1_mux),
> +       ADI_PMX_FUNCTION("spi0", spi0grp, spi0_mux),
> +       ADI_PMX_FUNCTION("spi1", spi1grp, spi1_mux),
> +       ADI_PMX_FUNCTION("twi0", twi0grp, twi0_mux),
> +       ADI_PMX_FUNCTION("twi1", twi1grp, twi1_mux),
> +       ADI_PMX_FUNCTION("rotary", rotarygrp, rotary_mux),
> +       ADI_PMX_FUNCTION("can0", can0grp, can0_mux),
> +       ADI_PMX_FUNCTION("smc0", smc0grp, smc0_mux),
> +       ADI_PMX_FUNCTION("sport0", sport0grp, sport0_mux),
> +       ADI_PMX_FUNCTION("sport1", sport1grp, sport1_mux),
> +       ADI_PMX_FUNCTION("sport2", sport2grp, sport2_mux),
> +       ADI_PMX_FUNCTION("ppi0_8b", ppi0_8bgrp, ppi0_8b_mux),
> +       ADI_PMX_FUNCTION("ppi0_16b", ppi0_16bgrp, ppi0_16b_mux),
> +       ADI_PMX_FUNCTION("ppi0_24b", ppi0_24bgrp, ppi0_24b_mux),
> +       ADI_PMX_FUNCTION("ppi1_8b", ppi1_8bgrp, ppi1_8b_mux),
> +       ADI_PMX_FUNCTION("ppi1_16b", ppi1_16bgrp, ppi1_16b_mux),
> +       ADI_PMX_FUNCTION("ppi2_8b", ppi2_8bgrp, ppi2_8b_mux),
> +       ADI_PMX_FUNCTION("ppi2_16b", ppi2_16bgrp, ppi2_16b_mux),
> +};
> +
> +#endif /* CONFIG_PINCTRL */
> +
>  #endif                         /* _MACH_PORTMUX_H_ */
> --
> 1.8.2.3
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

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

* Re: [PATCH 1/3] pinctrl: ADI PIN control driver for the GPIO controller on bf54x and bf60x.
  2013-07-16 10:55 [PATCH 1/3] pinctrl: ADI PIN control driver for the GPIO controller on bf54x and bf60x Sonic Zhang
                   ` (2 preceding siblings ...)
  2013-07-23  7:32 ` [PATCH 1/3] pinctrl: ADI PIN control driver for the GPIO controller on bf54x and bf60x Sonic Zhang
@ 2013-07-26  4:57 ` Sonic Zhang
  2013-07-29 16:47   ` Linus Walleij
  2013-08-14 13:47 ` Linus Walleij
  4 siblings, 1 reply; 17+ messages in thread
From: Sonic Zhang @ 2013-07-26  4:57 UTC (permalink / raw)
  To: Linus Walleij, Grant Likely, Steven Miao
  Cc: LKML, adi-buildroot-devel, Sonic Zhang

Hi Linus,



On Tue, Jul 16, 2013 at 6:55 PM, Sonic Zhang <sonic.adi@gmail.com> wrote:
> From: Sonic Zhang <sonic.zhang@analog.com>
>
> The new ADI GPIO2 controller was introduced since the BF548 and BF60x
> processors. It differs a lot from the old one on BF5xx processors. So,
> create a pinctrl driver under pinctrl framework.
>
> - Define gpio ports and gpio interrupt controllers as individual platform
> devices.
> - Register a pinctrl driver for the whole GPIO ports and GPIO interrupt
> devices.
> - Probe pint devices before port devices. Put device instances into
> respective gpio and pint lists.
> - Define peripheral, irq and gpio reservation bit masks for each gpio
> port as runtime resources.
> - Save and restore gpio port and pint status MMRs in syscore PM functions.
> - Add peripheral device groups and function data into machine portmux.h.
> - Handle peripheral and gpio requests in pinctrl operation functions.
> - Demux gpio IRQs via the irq_domain created by each GPIO port.
>
> Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
> ---
>  drivers/pinctrl/Makefile                   |    1 +
>  drivers/pinctrl/pinctrl-adi2.c             | 1545 ++++++++++++++++++++++++++++
>  include/linux/platform_data/pinctrl-adi2.h |   38 +
>  3 files changed, 1584 insertions(+)
>  create mode 100644 drivers/pinctrl/pinctrl-adi2.c
>  create mode 100644 include/linux/platform_data/pinctrl-adi2.h
>
> diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
> index d64563bf..c685958 100644
> --- a/drivers/pinctrl/Makefile
> +++ b/drivers/pinctrl/Makefile
> @@ -14,6 +14,7 @@ obj-$(CONFIG_PINCTRL_AB8500)  += pinctrl-ab8500.o
>  obj-$(CONFIG_PINCTRL_AB8540)   += pinctrl-ab8540.o
>  obj-$(CONFIG_PINCTRL_AB9540)   += pinctrl-ab9540.o
>  obj-$(CONFIG_PINCTRL_AB8505)   += pinctrl-ab8505.o
> +obj-$(CONFIG_PINCTRL_ADI2)     += pinctrl-adi2.o
>  obj-$(CONFIG_PINCTRL_AT91)     += pinctrl-at91.o
>  obj-$(CONFIG_PINCTRL_BCM2835)  += pinctrl-bcm2835.o
>  obj-$(CONFIG_PINCTRL_BAYTRAIL) += pinctrl-baytrail.o
> diff --git a/drivers/pinctrl/pinctrl-adi2.c b/drivers/pinctrl/pinctrl-adi2.c
> new file mode 100644
> index 0000000..222a74c
> --- /dev/null
> +++ b/drivers/pinctrl/pinctrl-adi2.c
> @@ -0,0 +1,1545 @@
> +/*
> + * Pinctrl Driver for ADI GPIO2 controller
> + *
> + * Copyright 2007-2013 Analog Devices Inc.
> + *
> + * Licensed under the GPLv2 or later
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/module.h>
> +#include <linux/err.h>
> +#include <linux/proc_fs.h>
> +#include <linux/seq_file.h>
> +#include <linux/irq.h>
> +#include <linux/platform_data/pinctrl-adi2.h>
> +#include <linux/irqdomain.h>
> +#include <linux/irqchip/chained_irq.h>
> +#include <linux/pinctrl/pinctrl.h>
> +#include <linux/pinctrl/pinmux.h>
> +#include <linux/pinctrl/consumer.h>
> +#include <linux/pinctrl/machine.h>
> +#include <linux/syscore_ops.h>
> +#include <linux/gpio.h>
> +#include <asm/portmux.h>
> +#include "core.h"
> +
> +static LIST_HEAD(adi_pint_list);
> +static LIST_HEAD(adi_pinctrl_list);
> +
> +#define PERIPHERAL_USAGE 1
> +#define GPIO_USAGE 0
> +
> +#define DRIVER_NAME "pinctrl-adi2"
> +
> +#define RESOURCE_LABEL_SIZE    16
> +#define PINT_HI_OFFSET         16
> +
> +#define RSV_NONE       0
> +#define RSV_GPIO       1
> +#define RSV_INT                2
> +#define RSV_PERI       3
> +
> +/**
> + * struct gpio_reserve_map - a GPIO map structure containing the
> + * reservation status of each PIN.
> + *
> + * @owner: who request the reservation
> + * @rsv_gpio: if this pin is reserved as GPIO
> + * @rsv_int: if this pin is reserved as interrupt
> + * @rsv_peri: if this pin is reserved as part of a peripheral device
> + */
> +struct gpio_reserve_map {
> +       unsigned char owner[RESOURCE_LABEL_SIZE];
> +       bool rsv_gpio;
> +       bool rsv_int;
> +       bool rsv_peri;
> +};
> +
> +/**
> + * struct gpio_port_saved - GPIO port registers that should be saved between
> + * power suspend and resume operations.
> + *
> + * @fer: PORTx_FER register
> + * @data: PORTx_DATA register
> + * @dir: PORTx_DIR register
> + * @inen: PORTx_INEN register
> + * @mux: PORTx_MUX register
> + */
> +struct gpio_port_saved {
> +       u16 fer;
> +       u16 data;
> +       u16 dir;
> +       u16 inen;
> +       u32 mux;
> +};
> +
> +/**
> + * struct gpio_pint - GPIO interrupt controller device. Multiple ADI GPIO
> + * banks can be mapped into one GPIO interrupt controller.
> + *
> + * @node: All gpio_pint instances are added to a global list.
> + * @base: GPIO PINT device register base address
> + * @irq: IRQ of the GPIO PINT device, it is the parent IRQ of all
> + *       GPIO IRQs mapping to this device.
> + * @domain: [0] irq domain of the gpio port, whose hardware interrupts are
> + *             mapping to the low 16-bit of the pint registers.
> + *          [1] irq domain of the gpio port, whose hardware interrupts are
> + *             mapping to the high 16-bit of the pint registers.
> + * @regs: address pointer to the GPIO PINT device
> + * @map_count: No more than 2 GPIO banks can be mapped to this PINT device.
> + * @lock: This lock make sure the irq_chip operations to one GPIO PINT device
> + *        for different GPIO interrrupts are atomic.
> + * @pint_map_port: Set up the mapping between one GPIO PINT device and
> + *                 multiple GPIO banks.
> + */
> +struct gpio_pint {
> +       struct list_head node;
> +       void __iomem *base;
> +       int irq;
> +       struct irq_domain *domain[2];
> +       struct gpio_pint_regs *regs;
> +       struct adi_pm_pint_save saved_data;
> +       int map_count;
> +       spinlock_t lock;
> +
> +       int (*pint_map_port)(struct gpio_pint *pint, u8 assign,
> +                               u8 map, struct irq_domain *domain);
> +};
> +
> +/**
> + * ADI pin controller
> + *
> + * @node: All adi_pmx instances are added to a global list.
> + * @dev: a pointer back to containing device
> + * @pctl: the pinctrl device
> + * @gpio_list: the list of gpio banks owned by this pin controller.
> + * @gpio_base: the base gpio number of this pin controller.
> + */
> +struct adi_pmx {
> +       struct list_head node;
> +       struct device *dev;
> +       struct pinctrl_dev *pctl;
> +       struct list_head gpio_list;
> +       unsigned long gpio_base;
> +};
> +
> +/**
> + * struct gpio_pint - GPIO bank device. Multiple ADI GPIO banks can be mapped
> + * into one GPIO interrupt controller.
> + *
> + * @node: All gpio_pint instances are added to a list.
> + * @base: GPIO bank device register base address
> + * @pin_base: base global GPIO pin index of the GPIO bank device
> + * @irq_base: base IRQ of the GPIO bank device
> + * @width: PIN number of the GPIO bank device
> + * @range: The range space of the GPIO bank handled by the pin controller.
> + * @regs: address pointer to the GPIO bank device
> + * @saved_data: registers that should be saved between PM operations.
> + * @dev: device structure of this GPIO bank
> + * @pmx: the pinctrl device
> + * @pint: GPIO PINT device that this GPIO bank mapped to
> + * @pint_map: GIOP bank mapping code in PINT device
> + * @pint_assign: The 32-bit GPIO PINT registers can be divided into 2 parts. A
> + *               GPIO bank can be mapped into either low 16 bits[0] or high 16
> + *               bits[1] of each PINT register.
> + * @lock: This lock make sure the irq_chip operations to one GPIO PINT device
> + *        for different GPIO interrrupts are atomic.
> + * @chip: abstract a GPIO controller
> + * @domain: The irq domain owned by the GPIO port.
> + * @rsvmap: Reservation map array for each pin in the GPIO bank
> + */
> +struct gpio_port {
> +       struct list_head node;
> +       void __iomem *base;
> +       unsigned int pin_base;
> +       unsigned int irq_base;
> +       unsigned int width;
> +       struct pinctrl_gpio_range range;
> +       struct gpio_port_t *regs;
> +       struct gpio_port_saved saved_data;
> +       struct device *dev;
> +       struct adi_pmx *pmx;
> +
> +       struct gpio_pint *pint;
> +       u8 pint_map;
> +       u8 pint_assign;
> +
> +       spinlock_t lock;
> +       struct gpio_chip chip;
> +       struct irq_domain *domain;
> +
> +       struct gpio_reserve_map rsvmap[];
> +};
> +
> +static inline u8 pin_to_offset(struct pinctrl_gpio_range *range, unsigned pin)
> +{
> +       return pin - range->pin_base;
> +}
> +
> +static inline unsigned offset_to_gpio(struct gpio_port *port, u8 offset)
> +{
> +       return offset + port->chip.base;
> +}
> +
> +static inline u8 gpio_to_offset(struct gpio_port *port, unsigned gpio)
> +{
> +       return gpio - port->chip.base;
> +}
> +
> +static inline unsigned hwirq_to_pintbit(struct gpio_port *port, int hwirq)
> +{
> +       return (1 << hwirq) << (port->pint_assign * PINT_HI_OFFSET);
> +}
> +
> +static void set_label(struct gpio_port *port, unsigned offset,
> +       const char *label)
> +{
> +       char *pch = port->rsvmap[offset].owner;
> +
> +       if (label) {
> +               strncpy(pch, label, RESOURCE_LABEL_SIZE);
> +               pch[RESOURCE_LABEL_SIZE - 1] = 0;
> +       }
> +}
> +
> +static char *get_label(struct gpio_port *port, unsigned offset)
> +{
> +       char *pch = port->rsvmap[offset].owner;
> +
> +       return *pch ? pch : "UNKNOWN";
> +}
> +
> +static inline unsigned int is_reserved(struct gpio_port *port, char type,
> +       unsigned offset)
> +{
> +       switch (type) {
> +       case RSV_GPIO:
> +               return port->rsvmap[offset].rsv_gpio == true;
> +       case RSV_INT:
> +               return port->rsvmap[offset].rsv_int == true;
> +       case RSV_PERI:
> +               return port->rsvmap[offset].rsv_peri == true;
> +       }
> +
> +       return 0;
> +}
> +
> +static inline void reserve(struct gpio_port *port, char type, unsigned offset)
> +{
> +       switch (type) {
> +       case RSV_GPIO:
> +               port->rsvmap[offset].rsv_gpio = true;
> +               break;
> +       case RSV_INT:
> +               port->rsvmap[offset].rsv_int = true;
> +               break;
> +       case RSV_PERI:
> +               port->rsvmap[offset].rsv_peri = true;
> +               break;
> +       }
> +}
> +
> +static inline void unreserve(struct gpio_port *port, char type, unsigned offset)
> +{
> +       switch (type) {
> +       case RSV_GPIO:
> +               port->rsvmap[offset].rsv_gpio = false;
> +               break;
> +       case RSV_INT:
> +               port->rsvmap[offset].rsv_int = false;
> +               break;
> +       case RSV_PERI:
> +               port->rsvmap[offset].rsv_peri = false;
> +               break;
> +       }
> +}
> +
> +static struct gpio_pint *find_gpio_pint(unsigned id)
> +{
> +       struct gpio_pint *pint;
> +       int i = 0;
> +
> +       list_for_each_entry(pint, &adi_pint_list, node) {
> +               if (id == i)
> +                       break;
> +               i++;
> +       }
> +
> +       if (&pint->node != &adi_pint_list)
> +               return pint;
> +       else
> +               return NULL;
> +}
> +
> +static struct adi_pmx *find_pinctrl(unsigned id)
> +{
> +       struct adi_pmx *pmx;
> +       int i = 0;
> +
> +       list_for_each_entry(pmx, &adi_pinctrl_list, node) {
> +               if (id == i)
> +                       break;
> +               i++;
> +       }
> +
> +       if (&pmx->node != &adi_pinctrl_list)
> +               return pmx;
> +       else
> +               return NULL;
> +}
> +
> +static struct gpio_port *find_gpio_port(unsigned pin,
> +       struct list_head *gpio_list)
> +{
> +       struct gpio_port *port;
> +
> +       list_for_each_entry(port, gpio_list, node)
> +               if (pin >= port->range.pin_base &&
> +                       pin < port->range.pin_base + port->range.npins)
> +                       break;
> +
> +       if (&port->node != gpio_list)
> +               return port;
> +       else
> +               return NULL;
> +}
> +
> +static inline void port_setup(struct gpio_port *port, unsigned offset,
> +       unsigned short usage)
> +{
> +       struct gpio_port_t *regs = port->regs;
> +
> +       if (usage == GPIO_USAGE)
> +               writew(readw(&regs->port_fer) & ~(1 << offset),
> +                       &regs->port_fer);
> +       else
> +               writew(readw(&regs->port_fer) | (1 << offset), &regs->port_fer);
> +}
> +
> +static inline void portmux_setup(struct gpio_port *port, unsigned offset,
> +       unsigned short function)
> +{
> +       struct gpio_port_t *regs = port->regs;
> +       u32 pmux;
> +
> +       pmux = readl(&regs->port_mux);
> +
> +       pmux &= ~(0x3 << (2 * offset));
> +       pmux |= (function & 0x3) << (2 * offset);
> +
> +       writel(pmux, &regs->port_mux);
> +}
> +
> +static inline u16 get_portmux(struct gpio_port *port, unsigned offset)
> +{
> +       struct gpio_port_t *regs = port->regs;
> +       u32 pmux = readl(&regs->port_mux);
> +
> +       return pmux >> (2 * offset) & 0x3;
> +}
> +
> +
> +static void __adi_gpio_irq_prepare(struct gpio_port *port, unsigned offset)
> +{
> +       struct gpio_port_t *regs = port->regs;
> +
> +       port_setup(port, offset, GPIO_USAGE);
> +
> +       writew(1 << offset, &regs->dir_clear);
> +       writew(readw(&regs->inen) | (1 << offset), &regs->inen);
> +}
> +
> +static int __adi_gpio_irq_request(struct gpio_port *port, unsigned offset,
> +       const char *label)
> +{
> +       if (unlikely(is_reserved(port, RSV_PERI, offset))) {
> +               if (system_state == SYSTEM_BOOTING)
> +                       dump_stack();
> +
> +               dev_err(port->dev,
> +                      "GPIO %d is already reserved as Peripheral by %s !\n",
> +                       offset_to_gpio(port, offset), get_label(port, offset));
> +               return -EBUSY;
> +       }
> +       if (unlikely(is_reserved(port, RSV_GPIO, offset)))
> +               dev_err(port->dev,
> +                       "GPIO %d is already reserved by %s!\n",
> +                       offset_to_gpio(port, offset), get_label(port, offset));
> +
> +       reserve(port, RSV_INT, offset);
> +       set_label(port, offset, label);
> +       port_setup(port, offset, GPIO_USAGE);
> +
> +       return 0;
> +}
> +
> +static void __adi_gpio_irq_free(struct gpio_port *port, unsigned offset)
> +{
> +       if (unlikely(!is_reserved(port, RSV_INT, offset))) {
> +               if (system_state == SYSTEM_BOOTING)
> +                       dump_stack();
> +
> +               dev_err(port->dev, "GPIO %d wasn't requested!\n",
> +                       offset_to_gpio(port, offset));
> +               return;
> +       }
> +
> +       unreserve(port, RSV_INT, offset);
> +       set_label(port, offset, "free");
> +}
> +
> +static void adi_gpio_ack_irq(struct irq_data *d)
> +{
> +       unsigned long flags;
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +       struct gpio_pint_regs *regs = port->pint->regs;
> +       unsigned pintbit = hwirq_to_pintbit(port, d->hwirq);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +       spin_lock_irqsave(&port->pint->lock, flags);
> +
> +       if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) {
> +               if (readl(&regs->invert_set) & pintbit)
> +                       writel(pintbit, &regs->invert_clear);
> +               else
> +                       writel(pintbit, &regs->invert_set);
> +       }
> +
> +       writel(pintbit, &regs->request);
> +
> +       spin_unlock_irqrestore(&port->pint->lock, flags);
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static void adi_gpio_mask_ack_irq(struct irq_data *d)
> +{
> +       unsigned long flags;
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +       struct gpio_pint_regs *regs = port->pint->regs;
> +       unsigned pintbit = hwirq_to_pintbit(port, d->hwirq);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +       spin_lock_irqsave(&port->pint->lock, flags);
> +
> +       if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) {
> +               if (readl(&regs->invert_set) & pintbit)
> +                       writel(pintbit, &regs->invert_clear);
> +               else
> +                       writel(pintbit, &regs->invert_set);
> +       }
> +
> +       writel(pintbit, &regs->request);
> +       writel(pintbit, &regs->mask_clear);
> +
> +       spin_unlock_irqrestore(&port->pint->lock, flags);
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static void adi_gpio_mask_irq(struct irq_data *d)
> +{
> +       unsigned long flags;
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +       struct gpio_pint_regs *regs = port->pint->regs;
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +       spin_lock_irqsave(&port->pint->lock, flags);
> +
> +       writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_clear);
> +
> +       spin_unlock_irqrestore(&port->pint->lock, flags);
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static void adi_gpio_unmask_irq(struct irq_data *d)
> +{
> +       unsigned long flags;
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +       struct gpio_pint_regs *regs = port->pint->regs;
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +       spin_lock_irqsave(&port->pint->lock, flags);
> +
> +       writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_set);
> +
> +       spin_unlock_irqrestore(&port->pint->lock, flags);
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static unsigned int adi_gpio_irq_startup(struct irq_data *d)
> +{
> +       unsigned long flags;
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +       struct gpio_pint_regs *regs = port->pint->regs;
> +
> +       if (!port) {
> +               dev_err(port->dev, "GPIO IRQ %d :Not exist\n", d->irq);
> +               return -ENODEV;
> +       }
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +       spin_lock_irqsave(&port->pint->lock, flags);
> +
> +       __adi_gpio_irq_prepare(port, d->hwirq);
> +       writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_set);
> +
> +       spin_unlock_irqrestore(&port->pint->lock, flags);
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return 0;
> +}
> +
> +static void adi_gpio_irq_shutdown(struct irq_data *d)
> +{
> +       unsigned long flags;
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +       struct gpio_pint_regs *regs = port->pint->regs;
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +       spin_lock_irqsave(&port->pint->lock, flags);
> +
> +       writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_clear);
> +       __adi_gpio_irq_free(port, d->hwirq);
> +
> +       spin_unlock_irqrestore(&port->pint->lock, flags);
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static int adi_gpio_irq_type(struct irq_data *d, unsigned int type)
> +{
> +       unsigned long flags;
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +       struct gpio_pint_regs *pint_regs = port->pint->regs;
> +       unsigned pintmask;
> +       unsigned int irq = d->irq;
> +       int ret = 0;
> +       char buf[16];
> +
> +       if (!port) {
> +               dev_err(port->dev, "GPIO IRQ %d :Not exist\n", irq);
> +               return -ENODEV;
> +       }
> +
> +       pintmask = hwirq_to_pintbit(port, d->hwirq);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +       spin_lock_irqsave(&port->pint->lock, flags);
> +
> +       if (type == IRQ_TYPE_PROBE)
> +               type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
> +
> +       if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
> +                   IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
> +               snprintf(buf, 16, "gpio-irq%d", irq);
> +               ret = __adi_gpio_irq_request(port, d->hwirq, buf);
> +               if (ret)
> +                       goto out;
> +       } else
> +               goto out;
> +
> +       if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
> +               /* low or falling edge denoted by one */
> +               writel(pintmask, &pint_regs->invert_set);
> +       else
> +               /* high or rising edge denoted by zero */
> +               writel(pintmask, &pint_regs->invert_clear);
> +
> +       if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
> +               if (gpio_get_value(offset_to_gpio(port, d->hwirq)))
> +                       writel(pintmask, &pint_regs->invert_set);
> +               else
> +                       writel(pintmask, &pint_regs->invert_clear);
> +       }
> +
> +       if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
> +               writel(pintmask, &pint_regs->edge_set);
> +               __irq_set_handler_locked(irq, handle_edge_irq);
> +       } else {
> +               writel(pintmask, &pint_regs->edge_clear);
> +               __irq_set_handler_locked(irq, handle_level_irq);
> +       }
> +
> +out:
> +       spin_unlock_irqrestore(&port->pint->lock, flags);
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return ret;
> +}
> +
> +#ifdef CONFIG_PM
> +static int adi_gpio_set_wake(struct irq_data *d, unsigned int state)
> +{
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +
> +       if (!port && !port->pint && port->pint->irq != d->irq)
> +               return -EINVAL;
> +
> +#ifndef SEC_GCTL
> +       adi_internal_set_wake(port->pint->irq, state);
> +#endif
> +
> +       return 0;
> +}
> +
> +static int adi_pint_suspend(void)
> +{
> +       struct gpio_pint *pint;
> +
> +       list_for_each_entry(pint, &adi_pint_list, node) {
> +               writel(0xffffffff, &pint->regs->mask_clear);
> +               pint->saved_data.assign = readl(&pint->regs->assign);
> +               pint->saved_data.edge_set = readl(&pint->regs->edge_set);
> +               pint->saved_data.invert_set = readl(&pint->regs->invert_set);
> +       }
> +
> +       return 0;
> +}
> +
> +static void adi_pint_resume(void)
> +{
> +       struct gpio_pint *pint;
> +
> +       list_for_each_entry(pint, &adi_pint_list, node) {
> +               writel(pint->saved_data.assign, &pint->regs->assign);
> +               writel(pint->saved_data.edge_set, &pint->regs->edge_set);
> +               writel(pint->saved_data.invert_set, &pint->regs->invert_set);
> +       }
> +}
> +
> +static int adi_gpio_suspend(void)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +
> +       list_for_each_entry(pmx, &adi_pinctrl_list, node)
> +               list_for_each_entry(port, &pmx->gpio_list, node) {
> +                       port->saved_data.fer = readw(&port->regs->port_fer);
> +                       port->saved_data.mux = readl(&port->regs->port_mux);
> +                       port->saved_data.data = readw(&port->regs->data);
> +                       port->saved_data.inen = readw(&port->regs->inen);
> +                       port->saved_data.dir = readw(&port->regs->dir_set);
> +               }
> +
> +       return adi_pint_suspend();
> +}
> +
> +static void adi_gpio_resume(void)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +
> +       adi_pint_resume();
> +
> +       list_for_each_entry(pmx, &adi_pinctrl_list, node)
> +               list_for_each_entry(port, &pmx->gpio_list, node) {
> +                       writel(port->saved_data.mux, &port->regs->port_mux);
> +                       writew(port->saved_data.fer, &port->regs->port_fer);
> +                       writew(port->saved_data.inen, &port->regs->inen);
> +                       writew(port->saved_data.data & port->saved_data.dir,
> +                                               &port->regs->data_set);
> +                       writew(port->saved_data.dir, &port->regs->dir_set);
> +               }
> +
> +}
> +
> +static struct syscore_ops gpio_pm_syscore_ops = {
> +       .suspend = adi_gpio_suspend,
> +       .resume = adi_gpio_resume,
> +};
> +#else /* CONFIG_PM */
> +#define adi_gpio_set_wake NULL
> +#endif /* CONFIG_PM */
> +
> +#ifdef CONFIG_IRQ_PREFLOW_FASTEOI
> +static inline void preflow_handler(struct irq_desc *desc)
> +{
> +       if (desc->preflow_handler)
> +               desc->preflow_handler(&desc->irq_data);
> +}
> +#else
> +static inline void preflow_handler(struct irq_desc *desc) { }
> +#endif
> +
> +static void adi_gpio_handle_pint_irq(unsigned int inta_irq,
> +                       struct irq_desc *desc)
> +{
> +       u32 request;
> +       u32 level_mask, hwirq;
> +       int umask = 0;
> +       struct gpio_pint *pint = irq_desc_get_handler_data(desc);
> +       struct irq_chip *chip = irq_desc_get_chip(desc);
> +       struct gpio_pint_regs *regs = pint->regs;
> +       struct irq_domain *domain;
> +
> +       preflow_handler(desc);
> +       chained_irq_enter(chip, desc);
> +
> +       request = readl(&regs->request);
> +       level_mask = readl(&regs->edge_set) & request;
> +
> +       hwirq = 0;
> +       domain = pint->domain[0];
> +       while (request) {
> +               if (hwirq == PINT_HI_OFFSET)
> +                       domain = pint->domain[1];
> +
> +               if (request & 1) {
> +                       if (level_mask & (1 << hwirq)) {
> +                               umask = 1;
> +                               chained_irq_exit(chip, desc);
> +                       }
> +                       generic_handle_irq(irq_find_mapping(domain,
> +                                       hwirq % PINT_HI_OFFSET));
> +               }
> +
> +               hwirq++;
> +               request >>= 1;
> +       }
> +
> +       if (!umask)
> +               chained_irq_exit(chip, desc);
> +}
> +
> +static struct irq_chip adi_gpio_irqchip = {
> +       .name = "GPIO",
> +       .irq_ack = adi_gpio_ack_irq,
> +       .irq_mask = adi_gpio_mask_irq,
> +       .irq_mask_ack = adi_gpio_mask_ack_irq,
> +       .irq_unmask = adi_gpio_unmask_irq,
> +       .irq_disable = adi_gpio_mask_irq,
> +       .irq_enable = adi_gpio_unmask_irq,
> +       .irq_set_type = adi_gpio_irq_type,
> +       .irq_startup = adi_gpio_irq_startup,
> +       .irq_shutdown = adi_gpio_irq_shutdown,
> +       .irq_set_wake = adi_gpio_set_wake,
> +};
> +
> +
> +static int adi_get_groups_count(struct pinctrl_dev *pctldev)
> +{
> +       return ARRAY_SIZE(adi_pin_groups);
> +}
> +
> +static const char *adi_get_group_name(struct pinctrl_dev *pctldev,
> +                                      unsigned selector)
> +{
> +       return adi_pin_groups[selector].name;
> +}
> +
> +static int adi_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
> +                              const unsigned **pins,
> +                              unsigned *num_pins)
> +{
> +       *pins = adi_pin_groups[selector].pins;
> +       *num_pins = adi_pin_groups[selector].num;
> +       return 0;
> +}
> +
> +static void adi_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
> +                  unsigned offset)
> +{
> +       seq_puts(s, DRIVER_NAME);
> +}
> +
> +static struct pinctrl_ops adi_pctrl_ops = {
> +       .get_groups_count = adi_get_groups_count,
> +       .get_group_name = adi_get_group_name,
> +       .get_group_pins = adi_get_group_pins,
> +       .pin_dbg_show = adi_pin_dbg_show,
> +};
> +
> +static int adi_pinmux_request(struct pinctrl_dev *pctldev, unsigned pin)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +       unsigned long flags;
> +       struct pin_desc *desc;
> +       u8 offset;
> +
> +       pmx = pinctrl_dev_get_drvdata(pctldev);
> +
> +       port = find_gpio_port(pin, &pmx->gpio_list);
> +       if (port == NULL) {
> +               dev_err(pctldev->dev,
> +                      "%s: Peripheral PIN %d doesn't exist!\n",
> +                      __func__, pin);
> +               return -ENODEV;
> +       }
> +
> +       offset = pin_to_offset(&port->range, pin);
> +       desc = radix_tree_lookup(&pctldev->pin_desc_tree, pin);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       /* If a pin can be muxed as either GPIO or peripheral, make
> +        * sure it is not already a GPIO pin when we request it.
> +        */
> +       if (unlikely(is_reserved(port, RSV_GPIO, offset))) {
> +               if (system_state == SYSTEM_BOOTING)
> +                       dump_stack();
> +               dev_err(pctldev->dev,
> +                      "%s: Peripheral PIN %d is already reserved as GPIO by %s!\n",
> +                      __func__, pin, get_label(port, offset));
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return -EBUSY;
> +       }
> +
> +       if (unlikely(is_reserved(port, RSV_PERI, offset))) {
> +               if (system_state == SYSTEM_BOOTING)
> +                       dump_stack();
> +               dev_err(pctldev->dev,
> +                       "%s: Peripheral PIN %d is already reserved by %s!\n",
> +                       __func__, pin, get_label(port, offset));
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return -EBUSY;
> +       }
> +
> +       reserve(port, RSV_PERI, offset);
> +       set_label(port, offset, desc->mux_owner);
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return 0;
> +}
> +
> +static int adi_pinmux_free(struct pinctrl_dev *pctldev, unsigned pin)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +       unsigned long flags;
> +       u8 offset;
> +
> +       pmx = pinctrl_dev_get_drvdata(pctldev);
> +       port = find_gpio_port(pin, &pmx->gpio_list);
> +       if (port == NULL)
> +               return 0;
> +
> +       offset = pin_to_offset(&port->range, pin);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       if (unlikely(!is_reserved(port, RSV_PERI, offset))) {
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return 0;
> +       }
> +
> +       unreserve(port, RSV_PERI, offset);
> +       set_label(port, offset, "free");
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return 0;
> +}
> +
> +static int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector,
> +       unsigned group)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +       unsigned long flags;
> +       unsigned short *mux = (unsigned short *)adi_pmx_functions[selector].mux;
> +       unsigned short gpio;
> +
> +       pmx = pinctrl_dev_get_drvdata(pctldev);
> +
> +       while (*mux) {
> +               gpio = P_IDENT(*mux);
> +
> +               port = find_gpio_port(gpio - pmx->gpio_base, &pmx->gpio_list);
> +               if (port == NULL) /* should not happen */
> +                       continue;
> +
> +               spin_lock_irqsave(&port->lock, flags);
> +
> +               portmux_setup(port, gpio_to_offset(port, gpio),
> +                                P_FUNCT2MUX(*mux));
> +               port_setup(port, gpio_to_offset(port, gpio), PERIPHERAL_USAGE);
> +               mux++;
> +
> +               spin_unlock_irqrestore(&port->lock, flags);
> +       }
> +
> +       return 0;
> +}
> +
> +static void adi_pinmux_disable(struct pinctrl_dev *pctldev, unsigned selector,
> +       unsigned group)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +       unsigned long flags;
> +       unsigned short *mux = (unsigned short *)adi_pmx_functions[selector].mux;
> +       unsigned short gpio;
> +
> +       pmx = pinctrl_dev_get_drvdata(pctldev);
> +
> +       while (*mux) {
> +               gpio = P_IDENT(*mux);
> +
> +               port = find_gpio_port(gpio - pmx->gpio_base, &pmx->gpio_list);
> +               if (port == NULL) /* should not happen */
> +                       continue;
> +
> +               spin_lock_irqsave(&port->lock, flags);
> +
> +               port_setup(port, gpio_to_offset(port, gpio), GPIO_USAGE);
> +               mux++;
> +
> +               spin_unlock_irqrestore(&port->lock, flags);
> +       }
> +}
> +
> +static int adi_pinmux_get_funcs_count(struct pinctrl_dev *pctldev)
> +{
> +       return ARRAY_SIZE(adi_pmx_functions);
> +}
> +
> +static const char *adi_pinmux_get_func_name(struct pinctrl_dev *pctldev,
> +                                         unsigned selector)
> +{
> +       return adi_pmx_functions[selector].name;
> +}
> +
> +static int adi_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
> +                              const char * const **groups,
> +                              unsigned * const num_groups)
> +{
> +       *groups = adi_pmx_functions[selector].groups;
> +       *num_groups = adi_pmx_functions[selector].num_groups;
> +       return 0;
> +}
> +
> +static int adi_pinmux_request_gpio(struct pinctrl_dev *pctldev,
> +       struct pinctrl_gpio_range *range, unsigned pin)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +       unsigned long flags;
> +       u8 offset;
> +
> +       pmx = pinctrl_dev_get_drvdata(pctldev);
> +       port = find_gpio_port(pin, &pmx->gpio_list);
> +       if (port == NULL) {
> +               dev_err(pctldev->dev,
> +                      "%s: GPIO PIN %d doesn't exist!\n",
> +                      __func__, pin);
> +               return -ENODEV;
> +       }
> +
> +       offset = pin_to_offset(&port->range, pin);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       if (unlikely(is_reserved(port, RSV_GPIO, offset))) {
> +               if (system_state == SYSTEM_BOOTING)
> +                       dump_stack();
> +               dev_err(pctldev->dev,
> +                       "GPIO %d is already reserved by %s !\n",
> +                       offset_to_gpio(port, offset), get_label(port, offset));
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return -EBUSY;
> +       }
> +       if (unlikely(is_reserved(port, RSV_PERI, offset))) {
> +               if (system_state == SYSTEM_BOOTING)
> +                       dump_stack();
> +               dev_err(pctldev->dev,
> +                       "GPIO %d is already reserved as peripheral by %s !\n",
> +                       offset_to_gpio(port, offset), get_label(port, offset));
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return -EBUSY;
> +       }
> +       if (unlikely(is_reserved(port, RSV_INT, offset))) {
> +               dev_err(pctldev->dev,
> +                       "GPIO %d is already reserved as gpio-irq!\n",
> +                       offset_to_gpio(port, offset));
> +       }
> +
> +       reserve(port, RSV_GPIO, offset);
> +       set_label(port, offset, port->chip.label);
> +       port_setup(port, offset, GPIO_USAGE);
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return 0;
> +}
> +
> +static void adi_pinmux_free_gpio(struct pinctrl_dev *pctldev,
> +       struct pinctrl_gpio_range *range, unsigned pin)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +       unsigned long flags;
> +       u8 offset;
> +
> +       pmx = pinctrl_dev_get_drvdata(pctldev);
> +       port = find_gpio_port(pin, &pmx->gpio_list);
> +       if (port == NULL)
> +               return;
> +
> +       offset = pin_to_offset(&port->range, pin);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       if (unlikely(!is_reserved(port, RSV_GPIO, offset))) {
> +               if (system_state == SYSTEM_BOOTING)
> +                       dump_stack();
> +
> +               dev_err(pctldev->dev,
> +                       "GPIO %d wasn't requested!\n",
> +                       offset_to_gpio(port, offset));
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return;
> +       }
> +
> +       unreserve(port, RSV_GPIO, offset);
> +       set_label(port, offset, "free");
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return;
> +}
> +
> +static struct pinmux_ops adi_pinmux_ops = {
> +       .request = adi_pinmux_request,
> +       .free = adi_pinmux_free,
> +       .enable = adi_pinmux_enable,
> +       .disable = adi_pinmux_disable,
> +       .get_functions_count = adi_pinmux_get_funcs_count,
> +       .get_function_name = adi_pinmux_get_func_name,
> +       .get_function_groups = adi_pinmux_get_groups,
> +       .gpio_request_enable = adi_pinmux_request_gpio,
> +       .gpio_disable_free = adi_pinmux_free_gpio,
> +};
> +
> +
> +static struct pinctrl_desc adi_pinmux_desc = {
> +       .name = DRIVER_NAME,
> +       .pins = adi_pads,
> +       .npins = ARRAY_SIZE(adi_pads),
> +       .pctlops = &adi_pctrl_ops,
> +       .pmxops = &adi_pinmux_ops,
> +       .owner = THIS_MODULE,
> +};
> +
> +static int adi_gpio_request(struct gpio_chip *chip, unsigned offset)
> +{
> +       struct gpio_port *port;
> +
> +       port = container_of(chip, struct gpio_port, chip);
> +
> +       return pinctrl_request_gpio(offset_to_gpio(port, offset));
> +}
> +
> +static void adi_gpio_free(struct gpio_chip *chip, unsigned offset)
> +{
> +       struct gpio_port *port;
> +
> +       port = container_of(chip, struct gpio_port, chip);
> +
> +       pinctrl_free_gpio(offset_to_gpio(port, offset));
> +}
> +
> +static int adi_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
> +{
> +       struct gpio_port *port;
> +       unsigned long flags;
> +
> +       port = container_of(chip, struct gpio_port, chip);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       if (unlikely(!is_reserved(port, RSV_GPIO, offset))) {
> +               dev_err(port->dev, "GPIO %d wasn't requested!\n",
> +                       offset_to_gpio(port, offset));
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return -EINVAL;
> +       }
> +
> +       writew(1 << offset, &port->regs->dir_clear);
> +       writew(readw(&port->regs->inen) | (1 << offset), &port->regs->inen);
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return 0;
> +}
> +
> +static void adi_gpio_set_value(struct gpio_chip *chip, unsigned offset,
> +       int value)
> +{
> +       struct gpio_port *port = container_of(chip, struct gpio_port, chip);
> +       struct gpio_port_t *regs = port->regs;
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       if (value)
> +               writew(1 << offset, &regs->data_set);
> +       else
> +               writew(1 << offset, &regs->data_clear);
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static int adi_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
> +       int value)
> +{
> +       struct gpio_port *port = container_of(chip, struct gpio_port, chip);
> +       struct gpio_port_t *regs = port->regs;
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       if (unlikely(!is_reserved(port, RSV_GPIO, offset))) {
> +               dev_err(port->dev, "GPIO %d wasn't requested!\n",
> +                       offset_to_gpio(port, offset));
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return -EINVAL;
> +       }
> +
> +       writew(readw(&regs->inen) & ~(1 << offset), &regs->inen);
> +       adi_gpio_set_value(chip, offset, value);
> +       writew(1 << offset, &regs->dir_set);
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return 0;
> +}
> +
> +static int adi_gpio_get_value(struct gpio_chip *chip, unsigned offset)
> +{
> +       struct gpio_port *port = container_of(chip, struct gpio_port, chip);
> +       struct gpio_port_t *regs = port->regs;
> +       unsigned long flags;
> +       int ret;
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       ret = 1 & (readw(&regs->data) >> offset);
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return ret;
> +}
> +
> +static int adi_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
> +{
> +       struct gpio_port *port = container_of(chip, struct gpio_port, chip);
> +
> +       if (port->irq_base >= 0)
> +               return irq_find_mapping(port->domain, offset);
> +       else
> +               return irq_create_mapping(port->domain, offset);
> +}
> +
> +#if defined(CONFIG_PROC_FS)
> +static inline unsigned short get_gpio_dir(struct gpio_port *port,
> +       unsigned offset)
> +{
> +       struct gpio_port_t *regs = port->regs;
> +
> +       return 1 & (readw(&regs->dir_clear) >> offset);
> +}
> +
> +static int gpio_proc_show(struct seq_file *m, void *v)
> +{
> +       int offset, irq, gpio;
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +
> +       list_for_each_entry(pmx, &adi_pinctrl_list, node)
> +       list_for_each_entry(port, &pmx->gpio_list, node)
> +               for (offset = 0; offset < port->width; offset++) {
> +                       irq = is_reserved(port, RSV_INT, offset);
> +                       gpio = is_reserved(port, RSV_GPIO, offset);
> +                       if (gpio || irq)
> +                               seq_printf(m, "GPIO_%d: \t%s%s \t\tGPIO %s\n",
> +                                       offset_to_gpio(port, offset),
> +                                       get_label(port, offset),
> +                                       (gpio && irq) ? " *" : "",
> +                                       get_gpio_dir(port, offset) ?
> +                                       "OUTPUT" : "INPUT");
> +                       else if (is_reserved(port, RSV_PERI, offset))
> +                               seq_printf(m, "GPIO_%d: \t%s \t\tPeripheral\n",
> +                                       offset_to_gpio(port, offset),
> +                                       get_label(port, offset));
> +                       else
> +                               continue;
> +               }
> +
> +       return 0;
> +}
> +
> +static int gpio_proc_open(struct inode *inode, struct file *file)
> +{
> +       return single_open(file, gpio_proc_show, NULL);
> +}
> +
> +static const struct file_operations gpio_proc_ops = {
> +       .open           = gpio_proc_open,
> +       .read           = seq_read,
> +       .llseek         = seq_lseek,
> +       .release        = single_release,
> +};
> +
> +static __init int gpio_register_proc(void)
> +{
> +       struct proc_dir_entry *proc_gpio;
> +
> +       proc_gpio = proc_create("gpio", 0, NULL, &gpio_proc_ops);
> +       return proc_gpio == NULL;
> +}
> +device_initcall(gpio_register_proc);
> +#endif
> +
> +static int adi_pint_map_port(struct gpio_pint *pint, u8 assign, u8 map,
> +       struct irq_domain *domain)
> +{
> +       struct gpio_pint_regs *regs = pint->regs;
> +
> +       if (pint->map_count > 1)
> +               return -EINVAL;
> +
> +       if (assign > 1)
> +               return -EINVAL;
> +
> +       pint->map_count++;
> +
> +       writel((readl(&regs->assign) & (0xFFFF << !assign * PINT_HI_OFFSET)) |
> +               (((map << 8) | map) << assign * PINT_HI_OFFSET), &regs->assign);
> +
> +       pint->domain[assign] = domain;
> +
> +       return 0;
> +}
> +
> +static int adi_gpio_pint_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct resource *res;
> +       struct gpio_pint *pint;
> +
> +       pint = devm_kzalloc(dev, sizeof(struct gpio_pint), GFP_KERNEL);
> +       if (!pint) {
> +               dev_err(dev, "Memory alloc failed\n");
> +               return -ENOMEM;
> +       }
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       if (unlikely(!res)) {
> +               dev_err(dev, "Invalid mem resource\n");
> +               return -ENODEV;
> +       }
> +
> +       if (!devm_request_mem_region(dev, res->start, resource_size(res),
> +                                    pdev->name)) {
> +               dev_err(dev, "Region already claimed\n");
> +               return -EBUSY;
> +       }
> +
> +       pint->base = devm_ioremap(dev, res->start, resource_size(res));
> +       if (!pint->base) {
> +               dev_err(dev, "Could not ioremap\n");
> +               return -ENOMEM;
> +       }
> +
> +       pint->regs = (struct gpio_pint_regs *)pint->base;
> +
> +       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> +       if (unlikely(!res)) {
> +               dev_err(dev, "Invalid IRQ resource\n");
> +               return -ENODEV;
> +       }
> +
> +       spin_lock_init(&pint->lock);
> +
> +       pint->irq = res->start;
> +       pint->pint_map_port = adi_pint_map_port;
> +       platform_set_drvdata(pdev, pint);
> +
> +       irq_set_chained_handler(pint->irq, adi_gpio_handle_pint_irq);
> +       irq_set_handler_data(pint->irq, pint);
> +
> +       list_add_tail(&pint->node, &adi_pint_list);
> +
> +       return 0;
> +}
> +
> +static int adi_gpio_pint_remove(struct platform_device *pdev)
> +{
> +       struct gpio_pint *pint = platform_get_drvdata(pdev);
> +
> +       list_del(&pint->node);
> +       irq_set_handler(pint->irq, handle_simple_irq);
> +       platform_set_drvdata(pdev, NULL);
> +
> +       return 0;
> +}
> +
> +static int adi_gpio_irq_map(struct irq_domain *d, unsigned int irq,
> +                               irq_hw_number_t hwirq)
> +{
> +       struct gpio_port *port = d->host_data;
> +
> +       if (!port)
> +               return -EINVAL;
> +
> +       irq_set_chip_data(irq, port);
> +       irq_set_chip_and_handler(irq, &adi_gpio_irqchip,
> +                               handle_level_irq);
> +
> +       return 0;
> +}
> +
> +const struct irq_domain_ops adi_gpio_irq_domain_ops = {
> +       .map = adi_gpio_irq_map,
> +       .xlate = irq_domain_xlate_onecell,
> +};
> +
> +static int adi_gpio_init_int(struct gpio_port *port)
> +{
> +       struct device_node *node = port->dev->of_node;
> +       struct gpio_pint *pint = port->pint;
> +       int ret;
> +
> +       port->domain = irq_domain_add_linear(node, port->width,
> +                               &adi_gpio_irq_domain_ops, port);
> +       if (!port->domain) {
> +               dev_err(port->dev, "Failed to create irqdomain\n");
> +               return -ENOSYS;
> +       }
> +
> +       ret = pint->pint_map_port(port->pint, port->pint_assign,
> +                       port->pint_map, port->domain);
> +       if (ret)
> +               return ret;
> +
> +       if (port->irq_base >= 0) {
> +               ret = irq_create_strict_mappings(port->domain, port->irq_base,
> +                                       0, port->width);
> +               if (ret) {
> +                       dev_err(port->dev, "Couldn't associate to domain\n");
> +                       return ret;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +static int adi_gpio_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       const struct adi_pinctrl_gpio_platform_data *pdata;
> +       struct resource *res;
> +       struct gpio_port *port;
> +       static int gpio;
> +       int ret = 0;
> +
> +       pdata = dev->platform_data;
> +       if (!pdata)
> +               return -EINVAL;
> +
> +       port = devm_kzalloc(dev, sizeof(struct gpio_port) +
> +               sizeof(struct gpio_reserve_map) * pdata->port_width,
> +               GFP_KERNEL);
> +       if (!port) {
> +               dev_err(dev, "Memory alloc failed\n");
> +               return -ENOMEM;
> +       }
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       if (unlikely(!res)) {
> +               dev_err(dev, "Invalid mem resource\n");
> +               return -ENODEV;
> +       }
> +
> +       if (!devm_request_mem_region(dev, res->start, resource_size(res),
> +                                    pdev->name)) {
> +               dev_err(dev, "Region already claimed\n");
> +               return -EBUSY;
> +       }
> +
> +       port->base = devm_ioremap(dev, res->start, resource_size(res));
> +       if (!port->base) {
> +               dev_err(dev, "Could not ioremap\n");
> +               return -ENOMEM;
> +       }
> +
> +       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> +       if (unlikely(!res))
> +               port->irq_base = -1;
> +       else
> +               port->irq_base = res->start;
> +
> +       port->width = pdata->port_width;
> +       port->dev = dev;
> +       port->regs = (struct gpio_port_t *)port->base;
> +       port->pint_assign = !!pdata->pint_assign;
> +       port->pint_map = pdata->pint_map;
> +
> +       port->pint = find_gpio_pint(pdata->pint_id);
> +       if (port->pint) {
> +               ret = adi_gpio_init_int(port);
> +               if (ret)
> +                       return ret;
> +       }
> +
> +       port->pmx = find_pinctrl(pdata->pinctrl_id);
> +       if (port->pmx == NULL) {
> +               dev_err(dev, "Could not find pinctrl device\n");
> +               return -ENODEV;
> +       }
> +       if (gpio == 0)
> +               gpio = port->pmx->gpio_base;
> +
> +       spin_lock_init(&port->lock);
> +
> +       platform_set_drvdata(pdev, port);
> +
> +       port->chip.label                = "adi-gpio";
> +       port->chip.direction_input      = adi_gpio_direction_input;
> +       port->chip.get                  = adi_gpio_get_value;
> +       port->chip.direction_output     = adi_gpio_direction_output;
> +       port->chip.set                  = adi_gpio_set_value;
> +       port->chip.request              = adi_gpio_request;
> +       port->chip.free                 = adi_gpio_free;
> +       port->chip.to_irq               = adi_gpio_to_irq;
> +       if (pdata->port_pin_base > 0)
> +               port->chip.base         = pdata->port_pin_base +
> +                                               port->pmx->gpio_base;
> +       else
> +               port->chip.base         = gpio;
> +       port->chip.ngpio                = port->width;
> +       gpio = port->chip.base + port->width;
> +
> +       ret = gpiochip_add(&port->chip);
> +       if (ret)
> +               return ret;
> +
> +       /* Set gpio range to pinctrl driver */
> +       port->range.name = port->chip.label;
> +       port->range.id = pdev->id;
> +       port->range.base = port->chip.base;
> +       port->range.pin_base = port->chip.base - port->pmx->gpio_base;
> +       port->range.npins = port->width;
> +       port->range.gc = &port->chip;
> +       pinctrl_add_gpio_range(port->pmx->pctl, &port->range);
> +
> +       list_add_tail(&port->node, &port->pmx->gpio_list);
> +
> +       return 0;
> +}
> +
> +static int adi_gpio_remove(struct platform_device *pdev)
> +{
> +       struct gpio_port *port = platform_get_drvdata(pdev);
> +       int ret;
> +       u8 offset;
> +
> +       for (offset = 0; offset < port->width; offset++)
> +               irq_dispose_mapping(irq_find_mapping(port->domain, offset));
> +
> +       irq_domain_remove(port->domain);
> +       pinctrl_remove_gpio_range(port->pmx->pctl, &port->range);
> +       list_del(&port->node);
> +       ret = gpiochip_remove(&port->chip);
> +       platform_set_drvdata(pdev, NULL);
> +
> +       return ret;
> +}
> +
> +static int adi_pinctrl_probe(struct platform_device *pdev)
> +{
> +       struct adi_pmx *pmx;
> +       struct resource *res;
> +
> +       pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
> +       if (!pmx)
> +               return -ENOMEM;
> +
> +       pmx->dev = &pdev->dev;
> +
> +       /* Now register the pin controller and all pins it handles */
> +       pmx->pctl = pinctrl_register(&adi_pinmux_desc, &pdev->dev, pmx);
> +       if (!pmx->pctl) {
> +               dev_err(&pdev->dev, "could not register pinctrl ADI2 driver\n");
> +               return -EINVAL;
> +       }
> +
> +       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
> +       if (res)
> +               pmx->gpio_base = res->start;
> +
> +       INIT_LIST_HEAD(&pmx->gpio_list);
> +
> +       list_add_tail(&pmx->node, &adi_pinctrl_list);
> +
> +       return 0;
> +}
> +
> +static int adi_pinctrl_remove(struct platform_device *pdev)
> +{
> +       struct adi_pmx *pmx = platform_get_drvdata(pdev);
> +
> +       list_del(&pmx->node);
> +       pinctrl_unregister(pmx->pctl);
> +       platform_set_drvdata(pdev, NULL);
> +
> +       return 0;
> +}
> +
> +static struct platform_driver adi_pinctrl_driver = {
> +       .probe          = adi_pinctrl_probe,
> +       .remove         = adi_pinctrl_remove,
> +       .driver         = {
> +               .name   = DRIVER_NAME,
> +       },
> +};
> +
> +static struct platform_driver adi_gpio_pint_driver = {
> +       .probe          = adi_gpio_pint_probe,
> +       .remove         = adi_gpio_pint_remove,
> +       .driver         = {
> +               .name   = "adi-gpio-pint",
> +       },
> +};
> +
> +static struct platform_driver adi_gpio_driver = {
> +       .probe          = adi_gpio_probe,
> +       .remove         = adi_gpio_remove,
> +       .driver         = {
> +               .name   = "adi-gpio",
> +       },
> +};
> +
> +static int __init adi_pinctrl_setup(void)
> +{
> +       int ret;
> +
> +       ret = platform_driver_register(&adi_pinctrl_driver);
> +       if (ret)
> +               return ret;
> +
> +       ret = platform_driver_register(&adi_gpio_pint_driver);
> +       if (ret)
> +               goto pint_error;
> +
> +       ret = platform_driver_register(&adi_gpio_driver);
> +       if (ret)
> +               goto gpio_error;
> +
> +#ifdef CONFIG_PM
> +       register_syscore_ops(&gpio_pm_syscore_ops);
> +#endif
> +       return ret;
> +gpio_error:
> +       platform_driver_unregister(&adi_gpio_pint_driver);
> +pint_error:
> +       platform_driver_unregister(&adi_pinctrl_driver);
> +
> +       return ret;
> +}
> +postcore_initcall(adi_pinctrl_setup);
> +
> +MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
> +MODULE_DESCRIPTION("ADI gpio2 pin control driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/platform_data/pinctrl-adi2.h b/include/linux/platform_data/pinctrl-adi2.h
> new file mode 100644
> index 0000000..465578e
> --- /dev/null
> +++ b/include/linux/platform_data/pinctrl-adi2.h
> @@ -0,0 +1,38 @@
> +/*
> + * Pinctrl Driver for ADI GPIO2 controller
> + *
> + * Copyright 2007-2013 Analog Devices Inc.
> + *
> + * Licensed under the GPLv2 or later
> + */
> +
> +
> +#ifndef PINCTRL_ADI2_H
> +#define PINCTRL_ADI2_H
> +
> +#include <linux/io.h>
> +#include <linux/platform_device.h>
> +
> +/**
> + * struct adi_pinctrl_gpio_platform_data - Pinctrl gpio platform data
> + * for ADI GPIO2 device.
> + *
> + * @port_pin_base: Optional global GPIO index of the GPIO bank.
> + *                 0 means driver decides.
> + * @port_width: PIN number of the GPIO bank device
> + * @pint_id: GPIO PINT device id that this GPIO bank should map to.
> + * @pint_assign: The 32-bit GPIO PINT registers can be divided into 2 parts. A
> + *               GPIO bank can be mapped into either low 16 bits[0] or high 16
> + *               bits[1] of each PINT register.
> + * @pint_map: GIOP bank mapping code in PINT device
> + */
> +struct adi_pinctrl_gpio_platform_data {
> +       unsigned int port_pin_base;
> +       unsigned int port_width;
> +       u8 pinctrl_id;
> +       u8 pint_id;
> +       u8 pint_assign;
> +       u8 pint_map;
> +};
> +
> +#endif
> --
> 1.8.2.3
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

Could you please comment on this patch set? It is based on your former comments.

Thanks,

Sonic Zhang

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

* Re: [PATCH 2/3] blackfin: gpio: Remove none gpio lib code.
  2013-07-16 10:55 ` [PATCH 2/3] blackfin: gpio: Remove none gpio lib code Sonic Zhang
  2013-07-23  7:33   ` Sonic Zhang
@ 2013-07-26  4:57   ` Sonic Zhang
  2013-08-14 15:34   ` Linus Walleij
  2 siblings, 0 replies; 17+ messages in thread
From: Sonic Zhang @ 2013-07-26  4:57 UTC (permalink / raw)
  To: Linus Walleij, Grant Likely, Steven Miao
  Cc: LKML, adi-buildroot-devel, Sonic Zhang

Hi Linus,

On Tue, Jul 16, 2013 at 6:55 PM, Sonic Zhang <sonic.adi@gmail.com> wrote:
> From: Sonic Zhang <sonic.zhang@analog.com>
>
> - Remove non gpio lib code from blackfin architecture.
> - Limit the lagecy blackfin gpio driver to bf5xx processors only.
> - Remove unused definition of the pint power functions.
>
> Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
> ---
>  arch/blackfin/Kconfig            |   7 ++
>  arch/blackfin/include/asm/gpio.h | 157 +++++----------------------------------
>  2 files changed, 27 insertions(+), 137 deletions(-)
>
> diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
> index 3b6abc5..9307e7a 100644
> --- a/arch/blackfin/Kconfig
> +++ b/arch/blackfin/Kconfig
> @@ -53,6 +53,9 @@ config GENERIC_BUG
>  config ZONE_DMA
>         def_bool y
>
> +config GENERIC_GPIO
> +       def_bool y
> +
>  config FORCE_MAX_ZONEORDER
>         int
>         default "14"
> @@ -318,6 +321,10 @@ config BF53x
>         depends on (BF531 || BF532 || BF533 || BF534 || BF536 || BF537)
>         default y
>
> +config GPIO_ADI
> +       def_bool y
> +       depends on (BF51x || BF52x || BF53x || BF538 || BF539 || BF561)
> +
>  config MEM_MT48LC64M4A2FB_7E
>         bool
>         depends on (BFIN533_STAMP)
> diff --git a/arch/blackfin/include/asm/gpio.h b/arch/blackfin/include/asm/gpio.h
> index 98d0133..99d338c 100644
> --- a/arch/blackfin/include/asm/gpio.h
> +++ b/arch/blackfin/include/asm/gpio.h
> @@ -25,8 +25,12 @@
>
>  #ifndef __ASSEMBLY__
>
> +#ifndef CONFIG_PINCTRL
> +
>  #include <linux/compiler.h>
> -#include <linux/gpio.h>
> +#include <asm/blackfin.h>
> +#include <asm/portmux.h>
> +#include <asm/irq_handler.h>
>
>  /***********************************************************
>  *
> @@ -45,7 +49,6 @@
>  * MODIFICATION HISTORY :
>  **************************************************************/
>
> -#if !BFIN_GPIO_PINT
>  void set_gpio_dir(unsigned, unsigned short);
>  void set_gpio_inen(unsigned, unsigned short);
>  void set_gpio_polar(unsigned, unsigned short);
> @@ -115,7 +118,6 @@ struct gpio_port_t {
>         unsigned short dummy16;
>         unsigned short inen;
>  };
> -#endif
>
>  #ifdef BFIN_SPECIAL_GPIO_BANKS
>  void bfin_special_gpio_free(unsigned gpio);
> @@ -127,25 +129,21 @@ void bfin_special_gpio_pm_hibernate_suspend(void);
>  #endif
>
>  #ifdef CONFIG_PM
> -int bfin_pm_standby_ctrl(unsigned ctrl);
> +void bfin_gpio_pm_hibernate_restore(void);
> +void bfin_gpio_pm_hibernate_suspend(void);
> +int bfin_gpio_pm_wakeup_ctrl(unsigned gpio, unsigned ctrl);
> +int bfin_gpio_pm_standby_ctrl(unsigned ctrl);
>
>  static inline int bfin_pm_standby_setup(void)
>  {
> -       return bfin_pm_standby_ctrl(1);
> +       return bfin_gpio_pm_standby_ctrl(1);
>  }
>
>  static inline void bfin_pm_standby_restore(void)
>  {
> -       bfin_pm_standby_ctrl(0);
> +       bfin_gpio_pm_standby_ctrl(0);
>  }
>
> -void bfin_gpio_pm_hibernate_restore(void);
> -void bfin_gpio_pm_hibernate_suspend(void);
> -void bfin_pint_suspend(void);
> -void bfin_pint_resume(void);
> -
> -# if !BFIN_GPIO_PINT
> -int gpio_pm_wakeup_ctrl(unsigned gpio, unsigned ctrl);
>
>  struct gpio_port_s {
>         unsigned short data;
> @@ -161,7 +159,6 @@ struct gpio_port_s {
>         unsigned short reserved;
>         unsigned short mux;
>  };
> -# endif
>  #endif /*CONFIG_PM*/
>
>  /***********************************************************
> @@ -178,36 +175,29 @@ struct gpio_port_s {
>  *************************************************************
>  * MODIFICATION HISTORY :
>  **************************************************************/
> -
> -int bfin_gpio_request(unsigned gpio, const char *label);
> -void bfin_gpio_free(unsigned gpio);
>  int bfin_gpio_irq_request(unsigned gpio, const char *label);
>  void bfin_gpio_irq_free(unsigned gpio);
> -int bfin_gpio_direction_input(unsigned gpio);
> -int bfin_gpio_direction_output(unsigned gpio, int value);
> -int bfin_gpio_get_value(unsigned gpio);
> -void bfin_gpio_set_value(unsigned gpio, int value);
> +void bfin_gpio_irq_prepare(unsigned gpio);
> +
> +static inline int irq_to_gpio(unsigned irq)
> +{
> +       return irq - GPIO_IRQ_BASE;
> +}
> +#endif /* CONFIG_PINCTRL */
>
>  #include <asm/irq.h>
>  #include <asm/errno.h>
>
> -#ifdef CONFIG_GPIOLIB
>  #include <asm-generic/gpio.h>          /* cansleep wrappers */
>
>  static inline int gpio_get_value(unsigned int gpio)
>  {
> -       if (gpio < MAX_BLACKFIN_GPIOS)
> -               return bfin_gpio_get_value(gpio);
> -       else
> -               return __gpio_get_value(gpio);
> +       return __gpio_get_value(gpio);
>  }
>
>  static inline void gpio_set_value(unsigned int gpio, int value)
>  {
> -       if (gpio < MAX_BLACKFIN_GPIOS)
> -               bfin_gpio_set_value(gpio, value);
> -       else
> -               __gpio_set_value(gpio, value);
> +       __gpio_set_value(gpio, value);
>  }
>
>  static inline int gpio_cansleep(unsigned int gpio)
> @@ -219,113 +209,6 @@ static inline int gpio_to_irq(unsigned gpio)
>  {
>         return __gpio_to_irq(gpio);
>  }
> -
> -#else /* !CONFIG_GPIOLIB */
> -
> -static inline int gpio_request(unsigned gpio, const char *label)
> -{
> -       return bfin_gpio_request(gpio, label);
> -}
> -
> -static inline void gpio_free(unsigned gpio)
> -{
> -       return bfin_gpio_free(gpio);
> -}
> -
> -static inline int gpio_direction_input(unsigned gpio)
> -{
> -       return bfin_gpio_direction_input(gpio);
> -}
> -
> -static inline int gpio_direction_output(unsigned gpio, int value)
> -{
> -       return bfin_gpio_direction_output(gpio, value);
> -}
> -
> -static inline int gpio_set_debounce(unsigned gpio, unsigned debounce)
> -{
> -       return -EINVAL;
> -}
> -
> -static inline int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
> -{
> -       int err;
> -
> -       err = bfin_gpio_request(gpio, label);
> -       if (err)
> -               return err;
> -
> -       if (flags & GPIOF_DIR_IN)
> -               err = bfin_gpio_direction_input(gpio);
> -       else
> -               err = bfin_gpio_direction_output(gpio,
> -                       (flags & GPIOF_INIT_HIGH) ? 1 : 0);
> -
> -       if (err)
> -               bfin_gpio_free(gpio);
> -
> -       return err;
> -}
> -
> -static inline int gpio_request_array(const struct gpio *array, size_t num)
> -{
> -       int i, err;
> -
> -       for (i = 0; i < num; i++, array++) {
> -               err = gpio_request_one(array->gpio, array->flags, array->label);
> -               if (err)
> -                       goto err_free;
> -       }
> -       return 0;
> -
> -err_free:
> -       while (i--)
> -               bfin_gpio_free((--array)->gpio);
> -       return err;
> -}
> -
> -static inline void gpio_free_array(const struct gpio *array, size_t num)
> -{
> -       while (num--)
> -               bfin_gpio_free((array++)->gpio);
> -}
> -
> -static inline int __gpio_get_value(unsigned gpio)
> -{
> -       return bfin_gpio_get_value(gpio);
> -}
> -
> -static inline void __gpio_set_value(unsigned gpio, int value)
> -{
> -       return bfin_gpio_set_value(gpio, value);
> -}
> -
> -static inline int gpio_get_value(unsigned gpio)
> -{
> -       return __gpio_get_value(gpio);
> -}
> -
> -static inline void gpio_set_value(unsigned gpio, int value)
> -{
> -       return __gpio_set_value(gpio, value);
> -}
> -
> -static inline int gpio_to_irq(unsigned gpio)
> -{
> -       if (likely(gpio < MAX_BLACKFIN_GPIOS))
> -               return gpio + GPIO_IRQ_BASE;
> -
> -       return -EINVAL;
> -}
> -
> -#include <asm-generic/gpio.h>          /* cansleep wrappers */
> -#endif /* !CONFIG_GPIOLIB */
> -
> -static inline int irq_to_gpio(unsigned irq)
> -{
> -       return (irq - GPIO_IRQ_BASE);
> -}
> -
>  #endif /* __ASSEMBLY__ */
>
>  #endif /* __ARCH_BLACKFIN_GPIO_H__ */
> --
> 1.8.2.3
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/


Could you please comment on this patch set? It is based on your former comments.

Thanks,

Sonic Zhang

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

* Re: [PATCH 3/3] blackfin: pinctrl-adi2: Add pin control device groups and function data.
  2013-07-16 10:55 ` [PATCH 3/3] blackfin: pinctrl-adi2: Add pin control device groups and function data Sonic Zhang
  2013-07-23  7:33   ` Sonic Zhang
@ 2013-07-26  4:58   ` Sonic Zhang
  2013-08-14 15:39   ` Linus Walleij
  2 siblings, 0 replies; 17+ messages in thread
From: Sonic Zhang @ 2013-07-26  4:58 UTC (permalink / raw)
  To: Linus Walleij, Grant Likely, Steven Miao
  Cc: LKML, adi-buildroot-devel, Sonic Zhang

Hi Linus,

On Tue, Jul 16, 2013 at 6:55 PM, Sonic Zhang <sonic.adi@gmail.com> wrote:
> From: Sonic Zhang <sonic.zhang@analog.com>
>
> Select PINCTRL_ADI2 for bf54x and bf60x by default.
>
> Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
> ---
>  arch/blackfin/Kconfig                           |   7 +
>  arch/blackfin/include/asm/portmux.h             |  14 +-
>  arch/blackfin/mach-bf548/include/mach/portmux.h | 595 +++++++++++++++++++++++-
>  arch/blackfin/mach-bf609/include/mach/portmux.h | 477 ++++++++++++++++++-
>  4 files changed, 1087 insertions(+), 6 deletions(-)
>
> diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
> index 9307e7a..6a3c490 100644
> --- a/arch/blackfin/Kconfig
> +++ b/arch/blackfin/Kconfig
> @@ -325,6 +325,13 @@ config GPIO_ADI
>         def_bool y
>         depends on (BF51x || BF52x || BF53x || BF538 || BF539 || BF561)
>
> +config PINCTRL_ADI2
> +       def_bool y
> +       depends on (BF54x || BF60x)
> +       select PINCTRL
> +       select PINMUX
> +       select IRQ_DOMAIN
> +
>  config MEM_MT48LC64M4A2FB_7E
>         bool
>         depends on (BFIN533_STAMP)
> diff --git a/arch/blackfin/include/asm/portmux.h b/arch/blackfin/include/asm/portmux.h
> index 9b1e2c3..6b3e71c 100644
> --- a/arch/blackfin/include/asm/portmux.h
> +++ b/arch/blackfin/include/asm/portmux.h
> @@ -17,14 +17,24 @@
>  #define P_MAYSHARE     0x2000
>  #define P_DONTCARE     0x1000
>
> -
> +#ifdef CONFIG_PINCTRL
> +#define peripheral_request(per, label) 0
> +#define peripheral_free(per)
> +#define peripheral_request_list(per, label) \
> +       (pdev ? (IS_ERR(devm_pinctrl_get_select_default(&pdev->dev)) \
> +       ? -EINVAL : 0) : 0);
> +#define peripheral_free_list(per)
> +#else
>  int peripheral_request(unsigned short per, const char *label);
>  void peripheral_free(unsigned short per);
>  int peripheral_request_list(const unsigned short per[], const char *label);
>  void peripheral_free_list(const unsigned short per[]);
> +#endif
>
> -#include <asm/gpio.h>
> +#include <linux/err.h>
> +#include <linux/pinctrl/pinctrl.h>
>  #include <mach/portmux.h>
> +#include <linux/gpio.h>
>
>  #ifndef P_SPORT2_TFS
>  #define P_SPORT2_TFS P_UNDEF
> diff --git a/arch/blackfin/mach-bf548/include/mach/portmux.h b/arch/blackfin/mach-bf548/include/mach/portmux.h
> index e222462..9fab923 100644
> --- a/arch/blackfin/mach-bf548/include/mach/portmux.h
> +++ b/arch/blackfin/mach-bf548/include/mach/portmux.h
> @@ -7,8 +7,6 @@
>  #ifndef _MACH_PORTMUX_H_
>  #define _MACH_PORTMUX_H_
>
> -#define MAX_RESOURCES  MAX_BLACKFIN_GPIOS
> -
>  #define P_SPORT2_TFS   (P_DEFINED | P_IDENT(GPIO_PA0) | P_FUNCT(0))
>  #define P_SPORT2_DTSEC (P_DEFINED | P_IDENT(GPIO_PA1) | P_FUNCT(0))
>  #define P_SPORT2_DTPRI (P_DEFINED | P_IDENT(GPIO_PA2) | P_FUNCT(0))
> @@ -317,4 +315,597 @@
>  #define P_NAND_CLE     (P_DONTCARE)
>  #define P_NAND_ALE     (P_DONTCARE)
>
> +#ifdef CONFIG_PINCTRL
> +
> +#include <mach/gpio.h>
> +#include <asm/blackfin.h>
> +#include <asm/irq_handler.h>
> +
> +#define gpio_pint_regs bfin_pint_regs
> +#define adi_internal_set_wake bfin_internal_set_wake
> +
> +static const struct pinctrl_pin_desc adi_pads[] = {
> +       PINCTRL_PIN(0, "PA0"),
> +       PINCTRL_PIN(1, "PA1"),
> +       PINCTRL_PIN(2, "PA2"),
> +       PINCTRL_PIN(3, "PG3"),
> +       PINCTRL_PIN(4, "PA4"),
> +       PINCTRL_PIN(5, "PA5"),
> +       PINCTRL_PIN(6, "PA6"),
> +       PINCTRL_PIN(7, "PA7"),
> +       PINCTRL_PIN(8, "PA8"),
> +       PINCTRL_PIN(9, "PA9"),
> +       PINCTRL_PIN(10, "PA10"),
> +       PINCTRL_PIN(11, "PA11"),
> +       PINCTRL_PIN(12, "PA12"),
> +       PINCTRL_PIN(13, "PA13"),
> +       PINCTRL_PIN(14, "PA14"),
> +       PINCTRL_PIN(15, "PA15"),
> +       PINCTRL_PIN(16, "PB0"),
> +       PINCTRL_PIN(17, "PB1"),
> +       PINCTRL_PIN(18, "PB2"),
> +       PINCTRL_PIN(19, "PB3"),
> +       PINCTRL_PIN(20, "PB4"),
> +       PINCTRL_PIN(21, "PB5"),
> +       PINCTRL_PIN(22, "PB6"),
> +       PINCTRL_PIN(23, "PB7"),
> +       PINCTRL_PIN(24, "PB8"),
> +       PINCTRL_PIN(25, "PB9"),
> +       PINCTRL_PIN(26, "PB10"),
> +       PINCTRL_PIN(27, "PB11"),
> +       PINCTRL_PIN(28, "PB12"),
> +       PINCTRL_PIN(29, "PB13"),
> +       PINCTRL_PIN(30, "PB14"),
> +       PINCTRL_PIN(32, "PC0"),
> +       PINCTRL_PIN(33, "PC1"),
> +       PINCTRL_PIN(34, "PC2"),
> +       PINCTRL_PIN(35, "PC3"),
> +       PINCTRL_PIN(36, "PC4"),
> +       PINCTRL_PIN(37, "PC5"),
> +       PINCTRL_PIN(38, "PC6"),
> +       PINCTRL_PIN(39, "PC7"),
> +       PINCTRL_PIN(40, "PC8"),
> +       PINCTRL_PIN(41, "PC9"),
> +       PINCTRL_PIN(42, "PC10"),
> +       PINCTRL_PIN(43, "PC11"),
> +       PINCTRL_PIN(44, "PC12"),
> +       PINCTRL_PIN(45, "PC13"),
> +       PINCTRL_PIN(48, "PD0"),
> +       PINCTRL_PIN(49, "PD1"),
> +       PINCTRL_PIN(50, "PD2"),
> +       PINCTRL_PIN(51, "PD3"),
> +       PINCTRL_PIN(52, "PD4"),
> +       PINCTRL_PIN(53, "PD5"),
> +       PINCTRL_PIN(54, "PD6"),
> +       PINCTRL_PIN(55, "PD7"),
> +       PINCTRL_PIN(56, "PD8"),
> +       PINCTRL_PIN(57, "PD9"),
> +       PINCTRL_PIN(58, "PD10"),
> +       PINCTRL_PIN(59, "PD11"),
> +       PINCTRL_PIN(60, "PD12"),
> +       PINCTRL_PIN(61, "PD13"),
> +       PINCTRL_PIN(62, "PD14"),
> +       PINCTRL_PIN(63, "PD15"),
> +       PINCTRL_PIN(64, "PE0"),
> +       PINCTRL_PIN(65, "PE1"),
> +       PINCTRL_PIN(66, "PE2"),
> +       PINCTRL_PIN(67, "PE3"),
> +       PINCTRL_PIN(68, "PE4"),
> +       PINCTRL_PIN(69, "PE5"),
> +       PINCTRL_PIN(70, "PE6"),
> +       PINCTRL_PIN(71, "PE7"),
> +       PINCTRL_PIN(72, "PE8"),
> +       PINCTRL_PIN(73, "PE9"),
> +       PINCTRL_PIN(74, "PE10"),
> +       PINCTRL_PIN(75, "PE11"),
> +       PINCTRL_PIN(76, "PE12"),
> +       PINCTRL_PIN(77, "PE13"),
> +       PINCTRL_PIN(78, "PE14"),
> +       PINCTRL_PIN(79, "PE15"),
> +       PINCTRL_PIN(80, "PF0"),
> +       PINCTRL_PIN(81, "PF1"),
> +       PINCTRL_PIN(82, "PF2"),
> +       PINCTRL_PIN(83, "PF3"),
> +       PINCTRL_PIN(84, "PF4"),
> +       PINCTRL_PIN(85, "PF5"),
> +       PINCTRL_PIN(86, "PF6"),
> +       PINCTRL_PIN(87, "PF7"),
> +       PINCTRL_PIN(88, "PF8"),
> +       PINCTRL_PIN(89, "PF9"),
> +       PINCTRL_PIN(90, "PF10"),
> +       PINCTRL_PIN(91, "PF11"),
> +       PINCTRL_PIN(92, "PF12"),
> +       PINCTRL_PIN(93, "PF13"),
> +       PINCTRL_PIN(94, "PF14"),
> +       PINCTRL_PIN(95, "PF15"),
> +       PINCTRL_PIN(96, "PG0"),
> +       PINCTRL_PIN(97, "PG1"),
> +       PINCTRL_PIN(98, "PG2"),
> +       PINCTRL_PIN(99, "PG3"),
> +       PINCTRL_PIN(100, "PG4"),
> +       PINCTRL_PIN(101, "PG5"),
> +       PINCTRL_PIN(102, "PG6"),
> +       PINCTRL_PIN(103, "PG7"),
> +       PINCTRL_PIN(104, "PG8"),
> +       PINCTRL_PIN(105, "PG9"),
> +       PINCTRL_PIN(106, "PG10"),
> +       PINCTRL_PIN(107, "PG11"),
> +       PINCTRL_PIN(108, "PG12"),
> +       PINCTRL_PIN(109, "PG13"),
> +       PINCTRL_PIN(110, "PG14"),
> +       PINCTRL_PIN(111, "PG15"),
> +       PINCTRL_PIN(112, "PH0"),
> +       PINCTRL_PIN(113, "PH1"),
> +       PINCTRL_PIN(114, "PH2"),
> +       PINCTRL_PIN(115, "PH3"),
> +       PINCTRL_PIN(116, "PH4"),
> +       PINCTRL_PIN(117, "PH5"),
> +       PINCTRL_PIN(118, "PH6"),
> +       PINCTRL_PIN(119, "PH7"),
> +       PINCTRL_PIN(120, "PH8"),
> +       PINCTRL_PIN(121, "PH9"),
> +       PINCTRL_PIN(122, "PH10"),
> +       PINCTRL_PIN(123, "PH11"),
> +       PINCTRL_PIN(124, "PH12"),
> +       PINCTRL_PIN(125, "PH13"),
> +       PINCTRL_PIN(128, "PI0"),
> +       PINCTRL_PIN(129, "PI1"),
> +       PINCTRL_PIN(130, "PI2"),
> +       PINCTRL_PIN(131, "PI3"),
> +       PINCTRL_PIN(132, "PI4"),
> +       PINCTRL_PIN(133, "PI5"),
> +       PINCTRL_PIN(134, "PI6"),
> +       PINCTRL_PIN(135, "PI7"),
> +       PINCTRL_PIN(136, "PI8"),
> +       PINCTRL_PIN(137, "PI9"),
> +       PINCTRL_PIN(138, "PI10"),
> +       PINCTRL_PIN(139, "PI11"),
> +       PINCTRL_PIN(140, "PI12"),
> +       PINCTRL_PIN(141, "PI13"),
> +       PINCTRL_PIN(142, "PI14"),
> +       PINCTRL_PIN(143, "PI15"),
> +       PINCTRL_PIN(144, "PJ0"),
> +       PINCTRL_PIN(145, "PJ1"),
> +       PINCTRL_PIN(146, "PJ2"),
> +       PINCTRL_PIN(147, "PJ3"),
> +       PINCTRL_PIN(148, "PJ4"),
> +       PINCTRL_PIN(149, "PJ5"),
> +       PINCTRL_PIN(150, "PJ6"),
> +       PINCTRL_PIN(151, "PJ7"),
> +       PINCTRL_PIN(152, "PJ8"),
> +       PINCTRL_PIN(153, "PJ9"),
> +       PINCTRL_PIN(154, "PJ10"),
> +       PINCTRL_PIN(155, "PJ11"),
> +       PINCTRL_PIN(156, "PJ12"),
> +       PINCTRL_PIN(157, "PJ13"),
> +};
> +
> +static const unsigned uart0_pins[] = {
> +       GPIO_PE7, GPIO_PE8,
> +};
> +
> +static const unsigned uart1_pins[] = {
> +       GPIO_PH0, GPIO_PH1,
> +#ifdef CONFIG_BFIN_UART1_CTSRTS
> +       GPIO_PE9, GPIO_PE10,
> +#endif
> +};
> +
> +static const unsigned uart2_pins[] = {
> +       GPIO_PB4, GPIO_PB5,
> +};
> +
> +static const unsigned uart3_pins[] = {
> +       GPIO_PB6, GPIO_PB7,
> +#ifdef CONFIG_BFIN_UART3_CTSRTS
> +       GPIO_PB2, GPIO_PB3,
> +#endif
> +};
> +
> +static const unsigned rsi0_pins[] = {
> +       GPIO_PC8, GPIO_PC9, GPIO_PC10, GPIO_PC11, GPIO_PC12, GPIO_PC13,
> +};
> +
> +static const unsigned spi0_pins[] = {
> +       GPIO_PE0, GPIO_PE1, GPIO_PE2,
> +};
> +
> +static const unsigned spi1_pins[] = {
> +       GPIO_PG8, GPIO_PG9, GPIO_PG10,
> +};
> +
> +static const unsigned twi0_pins[] = {
> +       GPIO_PE14, GPIO_PE15,
> +};
> +
> +static const unsigned twi1_pins[] = {
> +       GPIO_PB0, GPIO_PB1,
> +};
> +
> +static const unsigned rotary_pins[] = {
> +       GPIO_PH4, GPIO_PH3, GPIO_PH5,
> +};
> +
> +static const unsigned can0_pins[] = {
> +       GPIO_PG13, GPIO_PG12,
> +};
> +
> +static const unsigned can1_pins[] = {
> +       GPIO_PG14, GPIO_PG15,
> +};
> +
> +static const unsigned smc0_pins[] = {
> +       GPIO_PH8, GPIO_PH9, GPIO_PH10, GPIO_PH11, GPIO_PH12, GPIO_PH13,
> +       GPIO_PI0, GPIO_PI1, GPIO_PI2, GPIO_PI3, GPIO_PI4, GPIO_PI5, GPIO_PI6,
> +       GPIO_PI7, GPIO_PI8, GPIO_PI9, GPIO_PI10, GPIO_PI11,
> +       GPIO_PI12, GPIO_PI13, GPIO_PI14, GPIO_PI15,
> +};
> +
> +static const unsigned sport0_pins[] = {
> +       GPIO_PC0, GPIO_PC2, GPIO_PC3, GPIO_PC4, GPIO_PC6, GPIO_PC7,
> +};
> +
> +static const unsigned sport1_pins[] = {
> +       GPIO_PD0, GPIO_PD2, GPIO_PD3, GPIO_PD4, GPIO_PD6, GPIO_PD7,
> +};
> +
> +static const unsigned sport2_pins[] = {
> +       GPIO_PA0, GPIO_PA2, GPIO_PA3, GPIO_PA4, GPIO_PA6, GPIO_PA7,
> +};
> +
> +static const unsigned sport3_pins[] = {
> +       GPIO_PA8, GPIO_PA10, GPIO_PA11, GPIO_PA12, GPIO_PA14, GPIO_PA15,
> +};
> +
> +static const unsigned ppi0_8b_pins[] = {
> +       GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6,
> +       GPIO_PF7, GPIO_PF13, GPIO_PG0, GPIO_PG1, GPIO_PG2,
> +};
> +
> +static const unsigned ppi0_16b_pins[] = {
> +       GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6,
> +       GPIO_PF7, GPIO_PF9, GPIO_PF10, GPIO_PF11, GPIO_PF12,
> +       GPIO_PF13, GPIO_PF14, GPIO_PF15,
> +       GPIO_PG0, GPIO_PG1, GPIO_PG2,
> +};
> +
> +static const unsigned ppi0_24b_pins[] = {
> +       GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6,
> +       GPIO_PF7, GPIO_PF8, GPIO_PF9, GPIO_PF10, GPIO_PF11, GPIO_PF12,
> +       GPIO_PF13, GPIO_PF14, GPIO_PF15, GPIO_PD0, GPIO_PD1, GPIO_PD2,
> +       GPIO_PD3, GPIO_PD4, GPIO_PD5, GPIO_PG3, GPIO_PG4,
> +       GPIO_PG0, GPIO_PG1, GPIO_PG2,
> +};
> +
> +static const unsigned ppi1_8b_pins[] = {
> +       GPIO_PD0, GPIO_PD1, GPIO_PD2, GPIO_PD3, GPIO_PD4, GPIO_PD5, GPIO_PD6,
> +       GPIO_PD7, GPIO_PE11, GPIO_PE12, GPIO_PE13,
> +};
> +
> +static const unsigned ppi1_16b_pins[] = {
> +       GPIO_PD0, GPIO_PD1, GPIO_PD2, GPIO_PD3, GPIO_PD4, GPIO_PD5, GPIO_PD6,
> +       GPIO_PD7, GPIO_PD8, GPIO_PD9, GPIO_PD10, GPIO_PD11, GPIO_PD12,
> +       GPIO_PD13, GPIO_PD14, GPIO_PD15,
> +       GPIO_PE11, GPIO_PE12, GPIO_PE13,
> +};
> +
> +static const unsigned ppi2_8b_pins[] = {
> +       GPIO_PD8, GPIO_PD9, GPIO_PD10, GPIO_PD11, GPIO_PD12,
> +       GPIO_PD13, GPIO_PD14, GPIO_PD15,
> +       GPIO_PA7, GPIO_PB0, GPIO_PB1, GPIO_PB2, GPIO_PB3,
> +};
> +
> +static const unsigned atapi_pins[] = {
> +       GPIO_PH2, GPIO_PJ3, GPIO_PJ4, GPIO_PJ5, GPIO_PJ6,
> +       GPIO_PJ7, GPIO_PJ8, GPIO_PJ9, GPIO_PJ10,
> +       GPIO_PG5, GPIO_PG6, GPIO_PG7,
> +#ifdef CONFIG_BF548_ATAPI_ALTERNATIVE_PORT
> +       GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6,
> +       GPIO_PF7, GPIO_PF8, GPIO_PF9, GPIO_PF10, GPIO_PF11, GPIO_PF12,
> +       GPIO_PF13, GPIO_PF14, GPIO_PF15, GPIO_PG2, GPIO_PG3, GPIO_PG4,
> +#endif
> +};
> +
> +static const unsigned nfc0_pins[] = {
> +       GPIO_PJ1, GPIO_PJ2,
> +};
> +
> +static const unsigned keys_4x4_pins[] = {
> +       GPIO_PD8, GPIO_PD9, GPIO_PD10, GPIO_PD11,
> +       GPIO_PD12, GPIO_PD13, GPIO_PD14, GPIO_PD15,
> +};
> +
> +static const unsigned keys_8x8_pins[] = {
> +       GPIO_PD8, GPIO_PD9, GPIO_PD10, GPIO_PD11,
> +       GPIO_PD12, GPIO_PD13, GPIO_PD14, GPIO_PD15,
> +       GPIO_PE0, GPIO_PE1, GPIO_PE2, GPIO_PE3,
> +       GPIO_PE4, GPIO_PE5, GPIO_PE6, GPIO_PE7,
> +};
> +
> + /**
> + * struct adi_pin_group - describes a pin group
> + * @name: the name of this pin group
> + * @pins: an array of pins
> + * @num: the number of pins in this array
> + */
> +struct adi_pin_group {
> +       const char *name;
> +       const unsigned *pins;
> +       const unsigned num;
> +};
> +
> +#define ADI_PIN_GROUP(n, p)  \
> +       {                       \
> +               .name = n,      \
> +               .pins = p,      \
> +               .num = ARRAY_SIZE(p),   \
> +       }
> +
> +static const struct adi_pin_group adi_pin_groups[] = {
> +       ADI_PIN_GROUP("uart0grp", uart0_pins),
> +       ADI_PIN_GROUP("uart1grp", uart1_pins),
> +       ADI_PIN_GROUP("rsi0grp", rsi0_pins),
> +       ADI_PIN_GROUP("spi0grp", spi0_pins),
> +       ADI_PIN_GROUP("spi1grp", spi1_pins),
> +       ADI_PIN_GROUP("twi0grp", twi0_pins),
> +       ADI_PIN_GROUP("twi1grp", twi1_pins),
> +       ADI_PIN_GROUP("rotarygrp", rotary_pins),
> +       ADI_PIN_GROUP("can0grp", can0_pins),
> +       ADI_PIN_GROUP("can1grp", can1_pins),
> +       ADI_PIN_GROUP("smc0grp", smc0_pins),
> +       ADI_PIN_GROUP("sport0grp", sport0_pins),
> +       ADI_PIN_GROUP("sport1grp", sport1_pins),
> +       ADI_PIN_GROUP("sport2grp", sport2_pins),
> +       ADI_PIN_GROUP("sport3grp", sport3_pins),
> +       ADI_PIN_GROUP("ppi0_8bgrp", ppi0_8b_pins),
> +       ADI_PIN_GROUP("ppi0_16bgrp", ppi0_16b_pins),
> +       ADI_PIN_GROUP("ppi0_24bgrp", ppi0_24b_pins),
> +       ADI_PIN_GROUP("ppi1_8bgrp", ppi1_8b_pins),
> +       ADI_PIN_GROUP("ppi1_16bgrp", ppi1_16b_pins),
> +       ADI_PIN_GROUP("ppi2_8bgrp", ppi2_8b_pins),
> +       ADI_PIN_GROUP("atapigrp", atapi_pins),
> +       ADI_PIN_GROUP("nfc0grp", nfc0_pins),
> +       ADI_PIN_GROUP("keys_4x4grp", keys_4x4_pins),
> +       ADI_PIN_GROUP("keys_8x8grp", keys_8x8_pins),
> +};
> +
> +static const unsigned short uart0_mux[] = {
> +       P_UART0_TX, P_UART0_RX,
> +       0
> +};
> +
> +static const unsigned short uart1_mux[] = {
> +       P_UART1_TX, P_UART1_RX,
> +#ifdef CONFIG_BFIN_UART1_CTSRTS
> +       P_UART1_RTS, P_UART1_CTS,
> +#endif
> +       0
> +};
> +
> +static const unsigned short uart2_mux[] = {
> +       P_UART2_TX, P_UART2_RX,
> +       0
> +};
> +
> +static const unsigned short uart3_mux[] = {
> +       P_UART3_TX, P_UART3_RX,
> +#ifdef CONFIG_BFIN_UART3_CTSRTS
> +       P_UART3_RTS, P_UART3_CTS,
> +#endif
> +       0
> +};
> +
> +static const unsigned short rsi0_mux[] = {
> +       P_SD_D0, P_SD_D1, P_SD_D2, P_SD_D3, P_SD_CLK, P_SD_CMD,
> +       0
> +};
> +
> +static const unsigned short spi0_mux[] = {
> +       P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0
> +};
> +
> +static const unsigned short spi1_mux[] = {
> +       P_SPI1_SCK, P_SPI1_MISO, P_SPI1_MOSI, 0
> +};
> +
> +static const unsigned short twi0_mux[] = {
> +       P_TWI0_SCL, P_TWI0_SDA, 0
> +};
> +
> +static const unsigned short twi1_mux[] = {
> +       P_TWI1_SCL, P_TWI1_SDA, 0
> +};
> +
> +static const unsigned short rotary_mux[] = {
> +       P_CNT_CUD, P_CNT_CDG, P_CNT_CZM, 0
> +};
> +
> +static const unsigned short sport0_mux[] = {
> +       P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
> +       P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0
> +};
> +
> +static const unsigned short sport1_mux[] = {
> +       P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
> +       P_SPORT1_DRPRI, P_SPORT1_RSCLK, 0
> +};
> +
> +static const unsigned short sport2_mux[] = {
> +       P_SPORT2_TFS, P_SPORT2_DTPRI, P_SPORT2_TSCLK, P_SPORT2_RFS,
> +       P_SPORT2_DRPRI, P_SPORT2_RSCLK, 0
> +};
> +
> +static const unsigned short sport3_mux[] = {
> +       P_SPORT3_TFS, P_SPORT3_DTPRI, P_SPORT3_TSCLK, P_SPORT3_RFS,
> +       P_SPORT3_DRPRI, P_SPORT3_RSCLK, 0
> +};
> +
> +static const unsigned short can0_mux[] = {
> +       P_CAN0_RX, P_CAN0_TX, 0
> +};
> +
> +static const unsigned short can1_mux[] = {
> +       P_CAN1_RX, P_CAN1_TX, 0
> +};
> +
> +static const unsigned short smc0_mux[] = {
> +       P_A4, P_A5, P_A6, P_A7, P_A8, P_A9, P_A10, P_A11, P_A12,
> +       P_A13, P_A14, P_A15, P_A16, P_A17, P_A18, P_A19, P_A20, P_A21,
> +       P_A22, P_A23, P_A24, P_A25, P_NOR_CLK, 0,
> +};
> +
> +static const unsigned short ppi0_8b_mux[] = {
> +       P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3,
> +       P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7,
> +       P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
> +       0,
> +};
> +
> +static const unsigned short ppi0_16b_mux[] = {
> +       P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3,
> +       P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7,
> +       P_PPI0_D8, P_PPI0_D9, P_PPI0_D10, P_PPI0_D11,
> +       P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15,
> +       P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
> +       0,
> +};
> +
> +static const unsigned short ppi0_24b_mux[] = {
> +       P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3,
> +       P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7,
> +       P_PPI0_D8, P_PPI0_D9, P_PPI0_D10, P_PPI0_D11,
> +       P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15,
> +       P_PPI0_D16, P_PPI0_D17, P_PPI0_D18, P_PPI0_D19,
> +       P_PPI0_D20, P_PPI0_D21, P_PPI0_D22, P_PPI0_D23,
> +       P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
> +       0,
> +};
> +
> +static const unsigned short ppi1_8b_mux[] = {
> +       P_PPI1_D0, P_PPI1_D1, P_PPI1_D2, P_PPI1_D3,
> +       P_PPI1_D4, P_PPI1_D5, P_PPI1_D6, P_PPI1_D7,
> +       P_PPI1_CLK, P_PPI1_FS1, P_PPI1_FS2,
> +       0,
> +};
> +
> +static const unsigned short ppi1_16b_mux[] = {
> +       P_PPI1_D0, P_PPI1_D1, P_PPI1_D2, P_PPI1_D3,
> +       P_PPI1_D4, P_PPI1_D5, P_PPI1_D6, P_PPI1_D7,
> +       P_PPI1_D8, P_PPI1_D9, P_PPI1_D10, P_PPI1_D11,
> +       P_PPI1_D12, P_PPI1_D13, P_PPI1_D14, P_PPI1_D15,
> +       P_PPI1_CLK, P_PPI1_FS1, P_PPI1_FS2,
> +       0,
> +};
> +
> +static const unsigned short ppi2_8b_mux[] = {
> +       P_PPI2_D0, P_PPI2_D1, P_PPI2_D2, P_PPI2_D3,
> +       P_PPI2_D4, P_PPI2_D5, P_PPI2_D6, P_PPI2_D7,
> +       P_PPI2_CLK, P_PPI2_FS1, P_PPI2_FS2,
> +       0,
> +};
> +
> +static const unsigned short atapi_mux[] = {
> +       P_ATAPI_RESET, P_ATAPI_DIOR, P_ATAPI_DIOW, P_ATAPI_CS0, P_ATAPI_CS1,
> +       P_ATAPI_DMACK, P_ATAPI_DMARQ, P_ATAPI_INTRQ, P_ATAPI_IORDY,
> +       P_ATAPI_D0A, P_ATAPI_D1A, P_ATAPI_D2A, P_ATAPI_D3A, P_ATAPI_D4A,
> +       P_ATAPI_D5A, P_ATAPI_D6A, P_ATAPI_D7A, P_ATAPI_D8A, P_ATAPI_D9A,
> +       P_ATAPI_D10A, P_ATAPI_D11A, P_ATAPI_D12A, P_ATAPI_D13A, P_ATAPI_D14A,
> +       P_ATAPI_D15A, P_ATAPI_A0A, P_ATAPI_A1A, P_ATAPI_A2A,
> +       0
> +};
> +
> +static const unsigned short nfc0_mux[] = {
> +       P_NAND_CE, P_NAND_RB,
> +       0
> +};
> +
> +static const unsigned short keys_4x4_mux[] = {
> +       P_KEY_ROW3, P_KEY_ROW2, P_KEY_ROW1, P_KEY_ROW0,
> +       P_KEY_COL3, P_KEY_COL2, P_KEY_COL1, P_KEY_COL0,
> +       0
> +};
> +
> +static const unsigned short keys_8x8_mux[] = {
> +       P_KEY_ROW7, P_KEY_ROW6, P_KEY_ROW5, P_KEY_ROW4,
> +       P_KEY_ROW3, P_KEY_ROW2, P_KEY_ROW1, P_KEY_ROW0,
> +       P_KEY_COL7, P_KEY_COL6, P_KEY_COL5, P_KEY_COL4,
> +       P_KEY_COL3, P_KEY_COL2, P_KEY_COL1, P_KEY_COL0,
> +       0
> +};
> +
> +struct adi_pmx_func {
> +       const char *name;
> +       const char * const *groups;
> +       const unsigned num_groups;
> +       const unsigned short *mux;
> +};
> +
> +static const char * const uart0grp[] = { "uart0grp" };
> +static const char * const uart1grp[] = { "uart1grp" };
> +static const char * const uart2grp[] = { "uart2grp" };
> +static const char * const uart3grp[] = { "uart3grp" };
> +static const char * const rsi0grp[] = { "rsi0grp" };
> +static const char * const spi0grp[] = { "spi0grp" };
> +static const char * const spi1grp[] = { "spi1grp" };
> +static const char * const twi0grp[] = { "twi0grp" };
> +static const char * const twi1grp[] = { "twi1grp" };
> +static const char * const rotarygrp[] = { "rotarygrp" };
> +static const char * const can0grp[] = { "can0grp" };
> +static const char * const can1grp[] = { "can1grp" };
> +static const char * const smc0grp[] = { "smc0grp" };
> +static const char * const sport0grp[] = { "sport0grp" };
> +static const char * const sport1grp[] = { "sport1grp" };
> +static const char * const sport2grp[] = { "sport2grp" };
> +static const char * const sport3grp[] = { "sport3grp" };
> +static const char * const ppi0_8bgrp[] = { "ppi0_8bgrp" };
> +static const char * const ppi0_16bgrp[] = { "ppi0_16bgrp" };
> +static const char * const ppi0_24bgrp[] = { "ppi0_24bgrp" };
> +static const char * const ppi1_8bgrp[] = { "ppi1_8bgrp" };
> +static const char * const ppi1_16bgrp[] = { "ppi1_16bgrp" };
> +static const char * const ppi2_8bgrp[] = { "ppi2_8bgrp" };
> +static const char * const atapigrp[] = { "atapigrp" };
> +static const char * const nfc0grp[] = { "nfc0grp" };
> +static const char * const keys_4x4grp[] = { "keys_4x4grp" };
> +static const char * const keys_8x8grp[] = { "keys_8x8grp" };
> +
> +#define ADI_PMX_FUNCTION(n, g, m)              \
> +       {                                       \
> +               .name = n,                      \
> +               .groups = g,                    \
> +               .num_groups = ARRAY_SIZE(g),    \
> +               .mux = m,                       \
> +       }
> +
> +static const struct adi_pmx_func adi_pmx_functions[] = {
> +       ADI_PMX_FUNCTION("uart0", uart0grp, uart0_mux),
> +       ADI_PMX_FUNCTION("uart1", uart1grp, uart1_mux),
> +       ADI_PMX_FUNCTION("uart2", uart0grp, uart2_mux),
> +       ADI_PMX_FUNCTION("uart3", uart1grp, uart3_mux),
> +       ADI_PMX_FUNCTION("rsi0", rsi0grp, rsi0_mux),
> +       ADI_PMX_FUNCTION("spi0", spi0grp, spi0_mux),
> +       ADI_PMX_FUNCTION("spi1", spi1grp, spi1_mux),
> +       ADI_PMX_FUNCTION("twi0", twi0grp, twi0_mux),
> +       ADI_PMX_FUNCTION("twi1", twi1grp, twi1_mux),
> +       ADI_PMX_FUNCTION("rotary", rotarygrp, rotary_mux),
> +       ADI_PMX_FUNCTION("can0", can0grp, can0_mux),
> +       ADI_PMX_FUNCTION("can1", can1grp, can1_mux),
> +       ADI_PMX_FUNCTION("smc0", smc0grp, smc0_mux),
> +       ADI_PMX_FUNCTION("sport0", sport0grp, sport0_mux),
> +       ADI_PMX_FUNCTION("sport1", sport1grp, sport1_mux),
> +       ADI_PMX_FUNCTION("sport2", sport2grp, sport2_mux),
> +       ADI_PMX_FUNCTION("sport3", sport3grp, sport3_mux),
> +       ADI_PMX_FUNCTION("ppi0_8b", ppi0_8bgrp, ppi0_8b_mux),
> +       ADI_PMX_FUNCTION("ppi0_16b", ppi0_16bgrp, ppi0_16b_mux),
> +       ADI_PMX_FUNCTION("ppi0_24b", ppi0_24bgrp, ppi0_24b_mux),
> +       ADI_PMX_FUNCTION("ppi1_8b", ppi1_8bgrp, ppi1_8b_mux),
> +       ADI_PMX_FUNCTION("ppi1_16b", ppi1_16bgrp, ppi1_16b_mux),
> +       ADI_PMX_FUNCTION("ppi2_8b", ppi2_8bgrp, ppi2_8b_mux),
> +       ADI_PMX_FUNCTION("atapi", atapigrp, atapi_mux),
> +       ADI_PMX_FUNCTION("nfc0", nfc0grp, nfc0_mux),
> +       ADI_PMX_FUNCTION("keys_4x4", keys_4x4grp, keys_4x4_mux),
> +       ADI_PMX_FUNCTION("keys_8x8", keys_8x8grp, keys_8x8_mux),
> +};
> +
> +#endif /* CONFIG_PINCTRL */
> +
>  #endif /* _MACH_PORTMUX_H_ */
> diff --git a/arch/blackfin/mach-bf609/include/mach/portmux.h b/arch/blackfin/mach-bf609/include/mach/portmux.h
> index 2e1a51c..5f1b1a6 100644
> --- a/arch/blackfin/mach-bf609/include/mach/portmux.h
> +++ b/arch/blackfin/mach-bf609/include/mach/portmux.h
> @@ -7,8 +7,6 @@
>  #ifndef _MACH_PORTMUX_H_
>  #define _MACH_PORTMUX_H_
>
> -#define MAX_RESOURCES  MAX_BLACKFIN_GPIOS
> -
>  /* EMAC RMII Port Mux */
>  #define P_MII0_MDC     (P_DEFINED | P_IDENT(GPIO_PC6) | P_FUNCT(0))
>  #define P_MII0_MDIO    (P_DEFINED | P_IDENT(GPIO_PC7) | P_FUNCT(0))
> @@ -344,4 +342,479 @@
>  #define P_CNT_CUD      (P_DEFINED | P_IDENT(GPIO_PG11) | P_FUNCT(3))
>  #define P_CNT_CDG      (P_DEFINED | P_IDENT(GPIO_PG12) | P_FUNCT(3))
>
> +#ifdef CONFIG_PINCTRL
> +
> +#include <mach/gpio.h>
> +#include <asm/blackfin.h>
> +#include <asm/irq_handler.h>
> +
> +#define gpio_pint_regs bfin_pint_regs
> +#define adi_internal_set_wake bfin_internal_set_wake
> +
> +static const struct pinctrl_pin_desc adi_pads[] = {
> +       PINCTRL_PIN(0, "PA0"),
> +       PINCTRL_PIN(1, "PA1"),
> +       PINCTRL_PIN(2, "PA2"),
> +       PINCTRL_PIN(3, "PG3"),
> +       PINCTRL_PIN(4, "PA4"),
> +       PINCTRL_PIN(5, "PA5"),
> +       PINCTRL_PIN(6, "PA6"),
> +       PINCTRL_PIN(7, "PA7"),
> +       PINCTRL_PIN(8, "PA8"),
> +       PINCTRL_PIN(9, "PA9"),
> +       PINCTRL_PIN(10, "PA10"),
> +       PINCTRL_PIN(11, "PA11"),
> +       PINCTRL_PIN(12, "PA12"),
> +       PINCTRL_PIN(13, "PA13"),
> +       PINCTRL_PIN(14, "PA14"),
> +       PINCTRL_PIN(15, "PA15"),
> +       PINCTRL_PIN(16, "PB0"),
> +       PINCTRL_PIN(17, "PB1"),
> +       PINCTRL_PIN(18, "PB2"),
> +       PINCTRL_PIN(19, "PB3"),
> +       PINCTRL_PIN(20, "PB4"),
> +       PINCTRL_PIN(21, "PB5"),
> +       PINCTRL_PIN(22, "PB6"),
> +       PINCTRL_PIN(23, "PB7"),
> +       PINCTRL_PIN(24, "PB8"),
> +       PINCTRL_PIN(25, "PB9"),
> +       PINCTRL_PIN(26, "PB10"),
> +       PINCTRL_PIN(27, "PB11"),
> +       PINCTRL_PIN(28, "PB12"),
> +       PINCTRL_PIN(29, "PB13"),
> +       PINCTRL_PIN(30, "PB14"),
> +       PINCTRL_PIN(31, "PB15"),
> +       PINCTRL_PIN(32, "PC0"),
> +       PINCTRL_PIN(33, "PC1"),
> +       PINCTRL_PIN(34, "PC2"),
> +       PINCTRL_PIN(35, "PC3"),
> +       PINCTRL_PIN(36, "PC4"),
> +       PINCTRL_PIN(37, "PC5"),
> +       PINCTRL_PIN(38, "PC6"),
> +       PINCTRL_PIN(39, "PC7"),
> +       PINCTRL_PIN(40, "PC8"),
> +       PINCTRL_PIN(41, "PC9"),
> +       PINCTRL_PIN(42, "PC10"),
> +       PINCTRL_PIN(43, "PC11"),
> +       PINCTRL_PIN(44, "PC12"),
> +       PINCTRL_PIN(45, "PC13"),
> +       PINCTRL_PIN(46, "PC14"),
> +       PINCTRL_PIN(47, "PC15"),
> +       PINCTRL_PIN(48, "PD0"),
> +       PINCTRL_PIN(49, "PD1"),
> +       PINCTRL_PIN(50, "PD2"),
> +       PINCTRL_PIN(51, "PD3"),
> +       PINCTRL_PIN(52, "PD4"),
> +       PINCTRL_PIN(53, "PD5"),
> +       PINCTRL_PIN(54, "PD6"),
> +       PINCTRL_PIN(55, "PD7"),
> +       PINCTRL_PIN(56, "PD8"),
> +       PINCTRL_PIN(57, "PD9"),
> +       PINCTRL_PIN(58, "PD10"),
> +       PINCTRL_PIN(59, "PD11"),
> +       PINCTRL_PIN(60, "PD12"),
> +       PINCTRL_PIN(61, "PD13"),
> +       PINCTRL_PIN(62, "PD14"),
> +       PINCTRL_PIN(63, "PD15"),
> +       PINCTRL_PIN(64, "PE0"),
> +       PINCTRL_PIN(65, "PE1"),
> +       PINCTRL_PIN(66, "PE2"),
> +       PINCTRL_PIN(67, "PE3"),
> +       PINCTRL_PIN(68, "PE4"),
> +       PINCTRL_PIN(69, "PE5"),
> +       PINCTRL_PIN(70, "PE6"),
> +       PINCTRL_PIN(71, "PE7"),
> +       PINCTRL_PIN(72, "PE8"),
> +       PINCTRL_PIN(73, "PE9"),
> +       PINCTRL_PIN(74, "PE10"),
> +       PINCTRL_PIN(75, "PE11"),
> +       PINCTRL_PIN(76, "PE12"),
> +       PINCTRL_PIN(77, "PE13"),
> +       PINCTRL_PIN(78, "PE14"),
> +       PINCTRL_PIN(79, "PE15"),
> +       PINCTRL_PIN(80, "PF0"),
> +       PINCTRL_PIN(81, "PF1"),
> +       PINCTRL_PIN(82, "PF2"),
> +       PINCTRL_PIN(83, "PF3"),
> +       PINCTRL_PIN(84, "PF4"),
> +       PINCTRL_PIN(85, "PF5"),
> +       PINCTRL_PIN(86, "PF6"),
> +       PINCTRL_PIN(87, "PF7"),
> +       PINCTRL_PIN(88, "PF8"),
> +       PINCTRL_PIN(89, "PF9"),
> +       PINCTRL_PIN(90, "PF10"),
> +       PINCTRL_PIN(91, "PF11"),
> +       PINCTRL_PIN(92, "PF12"),
> +       PINCTRL_PIN(93, "PF13"),
> +       PINCTRL_PIN(94, "PF14"),
> +       PINCTRL_PIN(95, "PF15"),
> +       PINCTRL_PIN(96, "PG0"),
> +       PINCTRL_PIN(97, "PG1"),
> +       PINCTRL_PIN(98, "PG2"),
> +       PINCTRL_PIN(99, "PG3"),
> +       PINCTRL_PIN(100, "PG4"),
> +       PINCTRL_PIN(101, "PG5"),
> +       PINCTRL_PIN(102, "PG6"),
> +       PINCTRL_PIN(103, "PG7"),
> +       PINCTRL_PIN(104, "PG8"),
> +       PINCTRL_PIN(105, "PG9"),
> +       PINCTRL_PIN(106, "PG10"),
> +       PINCTRL_PIN(107, "PG11"),
> +       PINCTRL_PIN(108, "PG12"),
> +       PINCTRL_PIN(109, "PG13"),
> +       PINCTRL_PIN(110, "PG14"),
> +       PINCTRL_PIN(111, "PG15"),
> +};
> +
> +static const unsigned uart0_pins[] = {
> +       GPIO_PD7, GPIO_PD8,
> +#ifdef CONFIG_BFIN_UART0_CTSRTS
> +       GPIO_PD9, GPIO_PD10,
> +#endif
> +};
> +
> +static const unsigned uart1_pins[] = {
> +       GPIO_PG15, GPIO_PG14,
> +#ifdef CONFIG_BFIN_UART1_CTSRTS
> +       GPIO_PG10, GPIO_PG13,
> +#endif
> +};
> +
> +static const unsigned rsi0_pins[] = {
> +       GPIO_PG3, GPIO_PG2, GPIO_PG0, GPIO_PE15, GPIO_PG5, GPIO_PG6,
> +};
> +
> +static const unsigned eth0_pins[] = {
> +       GPIO_PC6, GPIO_PC7, GPIO_PC2, GPIO_PC0, GPIO_PC3, GPIO_PC1,
> +       GPIO_PB13, GPIO_PD6, GPIO_PC5, GPIO_PC4, GPIO_PB14,
> +};
> +
> +static const unsigned eth1_pins[] = {
> +       GPIO_PE10, GPIO_PE11, GPIO_PG3, GPIO_PG0, GPIO_PG2, GPIO_PE15,
> +       GPIO_PG5, GPIO_PE12, GPIO_PE13, GPIO_PE14, GPIO_PG6,
> +};
> +
> +static const unsigned spi0_pins[] = {
> +       GPIO_PD4, GPIO_PD2, GPIO_PD3,
> +};
> +
> +static const unsigned spi1_pins[] = {
> +       GPIO_PD5, GPIO_PD14, GPIO_PD13,
> +};
> +
> +static const unsigned twi0_pins[] = {
> +};
> +
> +static const unsigned twi1_pins[] = {
> +};
> +
> +static const unsigned rotary_pins[] = {
> +       GPIO_PG7, GPIO_PG11, GPIO_PG12,
> +};
> +
> +static const unsigned can0_pins[] = {
> +       GPIO_PG1, GPIO_PG4,
> +};
> +
> +static const unsigned smc0_pins[] = {
> +       GPIO_PA0, GPIO_PA1, GPIO_PA2, GPIO_PA3, GPIO_PA4, GPIO_PA5, GPIO_PA6,
> +       GPIO_PA7, GPIO_PA8, GPIO_PA9, GPIO_PB2, GPIO_PA10, GPIO_PA11,
> +       GPIO_PB3, GPIO_PA12, GPIO_PA13, GPIO_PA14, GPIO_PA15, GPIO_PB6,
> +       GPIO_PB7, GPIO_PB8, GPIO_PB10, GPIO_PB11, GPIO_PB0,
> +};
> +
> +static const unsigned sport0_pins[] = {
> +       GPIO_PB5, GPIO_PB4, GPIO_PB9, GPIO_PB8, GPIO_PB7, GPIO_PB11,
> +};
> +
> +static const unsigned sport1_pins[] = {
> +       GPIO_PE2, GPIO_PE5, GPIO_PD15, GPIO_PE4, GPIO_PE3, GPIO_PE1,
> +};
> +
> +static const unsigned sport2_pins[] = {
> +       GPIO_PG4, GPIO_PG1, GPIO_PG9, GPIO_PG10, GPIO_PG7, GPIO_PB12,
> +};
> +
> +static const unsigned ppi0_8b_pins[] = {
> +       GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6,
> +       GPIO_PF7, GPIO_PF13, GPIO_PF14, GPIO_PF15,
> +       GPIO_PE6, GPIO_PE7, GPIO_PE8, GPIO_PE9,
> +};
> +
> +static const unsigned ppi0_16b_pins[] = {
> +       GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6,
> +       GPIO_PF7, GPIO_PF9, GPIO_PF10, GPIO_PF11, GPIO_PF12,
> +       GPIO_PF13, GPIO_PF14, GPIO_PF15,
> +       GPIO_PE6, GPIO_PE7, GPIO_PE8, GPIO_PE9,
> +};
> +
> +static const unsigned ppi0_24b_pins[] = {
> +       GPIO_PF0, GPIO_PF1, GPIO_PF2, GPIO_PF3, GPIO_PF4, GPIO_PF5, GPIO_PF6,
> +       GPIO_PF7, GPIO_PF8, GPIO_PF9, GPIO_PF10, GPIO_PF11, GPIO_PF12,
> +       GPIO_PF13, GPIO_PF14, GPIO_PF15, GPIO_PE0, GPIO_PE1, GPIO_PE2,
> +       GPIO_PE3, GPIO_PE4, GPIO_PE5, GPIO_PE6, GPIO_PE7, GPIO_PE8,
> +       GPIO_PE9, GPIO_PD12, GPIO_PD15,
> +};
> +
> +static const unsigned ppi1_8b_pins[] = {
> +       GPIO_PC0, GPIO_PC1, GPIO_PC2, GPIO_PC3, GPIO_PC4, GPIO_PC5, GPIO_PC6,
> +       GPIO_PC7, GPIO_PC8, GPIO_PB13, GPIO_PB14, GPIO_PB15, GPIO_PD6,
> +};
> +
> +static const unsigned ppi1_16b_pins[] = {
> +       GPIO_PC0, GPIO_PC1, GPIO_PC2, GPIO_PC3, GPIO_PC4, GPIO_PC5, GPIO_PC6,
> +       GPIO_PC7, GPIO_PC9, GPIO_PC10, GPIO_PC11, GPIO_PC12,
> +       GPIO_PC13, GPIO_PC14, GPIO_PC15,
> +       GPIO_PB13, GPIO_PB14, GPIO_PB15, GPIO_PD6,
> +};
> +
> +static const unsigned ppi2_8b_pins[] = {
> +       GPIO_PA0, GPIO_PA1, GPIO_PA2, GPIO_PA3, GPIO_PA4, GPIO_PA5, GPIO_PA6,
> +       GPIO_PA7, GPIO_PB0, GPIO_PB1, GPIO_PB2, GPIO_PB3,
> +};
> +
> +static const unsigned ppi2_16b_pins[] = {
> +       GPIO_PA0, GPIO_PA1, GPIO_PA2, GPIO_PA3, GPIO_PA4, GPIO_PA5, GPIO_PA6,
> +       GPIO_PA7, GPIO_PA8, GPIO_PA9, GPIO_PA10, GPIO_PA11, GPIO_PA12,
> +       GPIO_PA13, GPIO_PA14, GPIO_PA15,
> +       GPIO_PA7, GPIO_PB0, GPIO_PB1, GPIO_PB2, GPIO_PB3,
> +};
> +
> + /**
> + * struct adi_pin_group - describes a pin group
> + * @name: the name of this pin group
> + * @pins: an array of pins
> + * @num: the number of pins in this array
> + */
> +struct adi_pin_group {
> +       const char *name;
> +       const unsigned *pins;
> +       const unsigned num;
> +};
> +
> +#define ADI_PIN_GROUP(n, p)  \
> +       {                       \
> +               .name = n,      \
> +               .pins = p,      \
> +               .num = ARRAY_SIZE(p),   \
> +       }
> +
> +static const struct adi_pin_group adi_pin_groups[] = {
> +       ADI_PIN_GROUP("uart0grp", uart0_pins),
> +       ADI_PIN_GROUP("uart1grp", uart1_pins),
> +       ADI_PIN_GROUP("rsi0grp", rsi0_pins),
> +       ADI_PIN_GROUP("eth0grp", eth0_pins),
> +       ADI_PIN_GROUP("eth1grp", eth1_pins),
> +       ADI_PIN_GROUP("spi0grp", spi0_pins),
> +       ADI_PIN_GROUP("spi1grp", spi1_pins),
> +       ADI_PIN_GROUP("twi0grp", twi0_pins),
> +       ADI_PIN_GROUP("twi1grp", twi1_pins),
> +       ADI_PIN_GROUP("rotarygrp", rotary_pins),
> +       ADI_PIN_GROUP("can0grp", can0_pins),
> +       ADI_PIN_GROUP("smc0grp", smc0_pins),
> +       ADI_PIN_GROUP("sport0grp", sport0_pins),
> +       ADI_PIN_GROUP("sport1grp", sport1_pins),
> +       ADI_PIN_GROUP("sport2grp", sport2_pins),
> +       ADI_PIN_GROUP("ppi0_8bgrp", ppi0_8b_pins),
> +       ADI_PIN_GROUP("ppi0_16bgrp", ppi0_16b_pins),
> +       ADI_PIN_GROUP("ppi0_24bgrp", ppi0_24b_pins),
> +       ADI_PIN_GROUP("ppi1_8bgrp", ppi1_8b_pins),
> +       ADI_PIN_GROUP("ppi1_16bgrp", ppi1_16b_pins),
> +       ADI_PIN_GROUP("ppi2_8bgrp", ppi2_8b_pins),
> +       ADI_PIN_GROUP("ppi2_16bgrp", ppi2_16b_pins),
> +};
> +
> +static const unsigned short uart0_mux[] = {
> +       P_UART0_TX, P_UART0_RX,
> +#ifdef CONFIG_BFIN_UART0_CTSRTS
> +       P_UART0_RTS, P_UART0_CTS,
> +#endif
> +       0
> +};
> +
> +static const unsigned short uart1_mux[] = {
> +       P_UART1_TX, P_UART1_RX,
> +#ifdef CONFIG_BFIN_UART1_CTSRTS
> +       P_UART1_RTS, P_UART1_CTS,
> +#endif
> +       0
> +};
> +
> +static const unsigned short rsi0_mux[] = {
> +       P_RSI_DATA0, P_RSI_DATA1, P_RSI_DATA2, P_RSI_DATA3,
> +       P_RSI_CMD, P_RSI_CLK, 0
> +};
> +
> +static const unsigned short eth0_mux[] = P_RMII0;
> +static const unsigned short eth1_mux[] = P_RMII1;
> +
> +static const unsigned short spi0_mux[] = {
> +       P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0
> +};
> +
> +static const unsigned short spi1_mux[] = {
> +       P_SPI1_SCK, P_SPI1_MISO, P_SPI1_MOSI, 0
> +};
> +
> +static const unsigned short twi0_mux[] = {
> +       P_TWI0_SCL, P_TWI0_SDA, 0
> +};
> +
> +static const unsigned short twi1_mux[] = {
> +       P_TWI1_SCL, P_TWI1_SDA, 0
> +};
> +
> +static const unsigned short rotary_mux[] = {
> +       P_CNT_CUD, P_CNT_CDG, P_CNT_CZM, 0
> +};
> +
> +static const unsigned short sport0_mux[] = {
> +       P_SPORT0_ACLK, P_SPORT0_AFS, P_SPORT0_AD0, P_SPORT0_BCLK,
> +       P_SPORT0_BFS, P_SPORT0_BD0, 0,
> +};
> +
> +static const unsigned short sport1_mux[] = {
> +       P_SPORT1_ACLK, P_SPORT1_AFS, P_SPORT1_AD0, P_SPORT1_BCLK,
> +       P_SPORT1_BFS, P_SPORT1_BD0, 0,
> +};
> +
> +static const unsigned short sport2_mux[] = {
> +       P_SPORT2_ACLK, P_SPORT2_AFS, P_SPORT2_AD0, P_SPORT2_BCLK,
> +       P_SPORT2_BFS, P_SPORT2_BD0, 0,
> +};
> +
> +static const unsigned short can0_mux[] = {
> +       P_CAN0_RX, P_CAN0_TX, 0
> +};
> +
> +static const unsigned short smc0_mux[] = {
> +       P_A3, P_A4, P_A5, P_A6, P_A7, P_A8, P_A9, P_A10, P_A11, P_A12,
> +       P_A13, P_A14, P_A15, P_A16, P_A17, P_A18, P_A19, P_A20, P_A21,
> +       P_A22, P_A23, P_A24, P_A25, P_NORCK, 0,
> +};
> +
> +static const unsigned short ppi0_8b_mux[] = {
> +       P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3,
> +       P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7,
> +       P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
> +       0,
> +};
> +
> +static const unsigned short ppi0_16b_mux[] = {
> +       P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3,
> +       P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7,
> +       P_PPI0_D8, P_PPI0_D9, P_PPI0_D10, P_PPI0_D11,
> +       P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15,
> +       P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
> +       0,
> +};
> +
> +static const unsigned short ppi0_24b_mux[] = {
> +       P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3,
> +       P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7,
> +       P_PPI0_D8, P_PPI0_D9, P_PPI0_D10, P_PPI0_D11,
> +       P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15,
> +       P_PPI0_D16, P_PPI0_D17, P_PPI0_D18, P_PPI0_D19,
> +       P_PPI0_D20, P_PPI0_D21, P_PPI0_D22, P_PPI0_D23,
> +       P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
> +       0,
> +};
> +
> +static const unsigned short ppi1_8b_mux[] = {
> +       P_PPI1_D0, P_PPI1_D1, P_PPI1_D2, P_PPI1_D3,
> +       P_PPI1_D4, P_PPI1_D5, P_PPI1_D6, P_PPI1_D7,
> +       P_PPI1_CLK, P_PPI1_FS1, P_PPI1_FS2,
> +       0,
> +};
> +
> +static const unsigned short ppi1_16b_mux[] = {
> +       P_PPI1_D0, P_PPI1_D1, P_PPI1_D2, P_PPI1_D3,
> +       P_PPI1_D4, P_PPI1_D5, P_PPI1_D6, P_PPI1_D7,
> +       P_PPI1_D8, P_PPI1_D9, P_PPI1_D10, P_PPI1_D11,
> +       P_PPI1_D12, P_PPI1_D13, P_PPI1_D14, P_PPI1_D15,
> +       P_PPI1_CLK, P_PPI1_FS1, P_PPI1_FS2,
> +       0,
> +};
> +
> +static const unsigned short ppi2_8b_mux[] = {
> +       P_PPI2_D0, P_PPI2_D1, P_PPI2_D2, P_PPI2_D3,
> +       P_PPI2_D4, P_PPI2_D5, P_PPI2_D6, P_PPI2_D7,
> +       P_PPI2_CLK, P_PPI2_FS1, P_PPI2_FS2,
> +       0,
> +};
> +
> +static const unsigned short ppi2_16b_mux[] = {
> +       P_PPI2_D0, P_PPI2_D1, P_PPI2_D2, P_PPI2_D3,
> +       P_PPI2_D4, P_PPI2_D5, P_PPI2_D6, P_PPI2_D7,
> +       P_PPI2_D8, P_PPI2_D9, P_PPI2_D10, P_PPI2_D11,
> +       P_PPI2_D12, P_PPI2_D13, P_PPI2_D14, P_PPI2_D15,
> +       P_PPI2_CLK, P_PPI2_FS1, P_PPI2_FS2,
> +       0,
> +};
> +
> +struct adi_pmx_func {
> +       const char *name;
> +       const char * const *groups;
> +       const unsigned num_groups;
> +       const unsigned short *mux;
> +};
> +
> +static const char * const uart0grp[] = { "uart0grp" };
> +static const char * const uart1grp[] = { "uart1grp" };
> +static const char * const rsi0grp[] = { "rsi0grp" };
> +static const char * const eth0grp[] = { "eth0grp" };
> +static const char * const eth1grp[] = { "eth1grp" };
> +static const char * const spi0grp[] = { "spi0grp" };
> +static const char * const spi1grp[] = { "spi1grp" };
> +static const char * const twi0grp[] = { "twi0grp" };
> +static const char * const twi1grp[] = { "twi1grp" };
> +static const char * const rotarygrp[] = { "rotarygrp" };
> +static const char * const can0grp[] = { "can0grp" };
> +static const char * const smc0grp[] = { "smc0grp" };
> +static const char * const sport0grp[] = { "sport0grp" };
> +static const char * const sport1grp[] = { "sport1grp" };
> +static const char * const sport2grp[] = { "sport2grp" };
> +static const char * const ppi0_8bgrp[] = { "ppi0_8bgrp" };
> +static const char * const ppi0_16bgrp[] = { "ppi0_16bgrp" };
> +static const char * const ppi0_24bgrp[] = { "ppi0_24bgrp" };
> +static const char * const ppi1_8bgrp[] = { "ppi1_8bgrp" };
> +static const char * const ppi1_16bgrp[] = { "ppi1_16bgrp" };
> +static const char * const ppi2_8bgrp[] = { "ppi2_8bgrp" };
> +static const char * const ppi2_16bgrp[] = { "ppi2_16bgrp" };
> +
> +#define ADI_PMX_FUNCTION(n, g, m)              \
> +       {                                       \
> +               .name = n,                      \
> +               .groups = g,                    \
> +               .num_groups = ARRAY_SIZE(g),    \
> +               .mux = m,                       \
> +       }
> +
> +static const struct adi_pmx_func adi_pmx_functions[] = {
> +       ADI_PMX_FUNCTION("uart0", uart0grp, uart0_mux),
> +       ADI_PMX_FUNCTION("uart1", uart1grp, uart1_mux),
> +       ADI_PMX_FUNCTION("rsi0", rsi0grp, rsi0_mux),
> +       ADI_PMX_FUNCTION("eth0", eth0grp, eth0_mux),
> +       ADI_PMX_FUNCTION("eth1", eth1grp, eth1_mux),
> +       ADI_PMX_FUNCTION("spi0", spi0grp, spi0_mux),
> +       ADI_PMX_FUNCTION("spi1", spi1grp, spi1_mux),
> +       ADI_PMX_FUNCTION("twi0", twi0grp, twi0_mux),
> +       ADI_PMX_FUNCTION("twi1", twi1grp, twi1_mux),
> +       ADI_PMX_FUNCTION("rotary", rotarygrp, rotary_mux),
> +       ADI_PMX_FUNCTION("can0", can0grp, can0_mux),
> +       ADI_PMX_FUNCTION("smc0", smc0grp, smc0_mux),
> +       ADI_PMX_FUNCTION("sport0", sport0grp, sport0_mux),
> +       ADI_PMX_FUNCTION("sport1", sport1grp, sport1_mux),
> +       ADI_PMX_FUNCTION("sport2", sport2grp, sport2_mux),
> +       ADI_PMX_FUNCTION("ppi0_8b", ppi0_8bgrp, ppi0_8b_mux),
> +       ADI_PMX_FUNCTION("ppi0_16b", ppi0_16bgrp, ppi0_16b_mux),
> +       ADI_PMX_FUNCTION("ppi0_24b", ppi0_24bgrp, ppi0_24b_mux),
> +       ADI_PMX_FUNCTION("ppi1_8b", ppi1_8bgrp, ppi1_8b_mux),
> +       ADI_PMX_FUNCTION("ppi1_16b", ppi1_16bgrp, ppi1_16b_mux),
> +       ADI_PMX_FUNCTION("ppi2_8b", ppi2_8bgrp, ppi2_8b_mux),
> +       ADI_PMX_FUNCTION("ppi2_16b", ppi2_16bgrp, ppi2_16b_mux),
> +};
> +
> +#endif /* CONFIG_PINCTRL */
> +
>  #endif                         /* _MACH_PORTMUX_H_ */
> --
> 1.8.2.3
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/


Could you please comment on this patch set? It is based on your former comments.

Thanks,

Sonic Zhang

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

* Re: [PATCH 1/3] pinctrl: ADI PIN control driver for the GPIO controller on bf54x and bf60x.
  2013-07-26  4:57 ` Sonic Zhang
@ 2013-07-29 16:47   ` Linus Walleij
  2013-08-01  7:31     ` Sonic Zhang
  0 siblings, 1 reply; 17+ messages in thread
From: Linus Walleij @ 2013-07-29 16:47 UTC (permalink / raw)
  To: Sonic Zhang
  Cc: Grant Likely, Steven Miao, LKML, adi-buildroot-devel, Sonic Zhang

On Fri, Jul 26, 2013 at 6:57 AM, Sonic Zhang <sonic.adi@gmail.com> wrote:

> Could you please comment on this patch set? It is based on your former comments.

I'll get to it. I'm pretty choked right now and actually trying to have
some vacation at the same time.

In the meantime, after glancing over and noting prolific use of the
unlikely() macro, please read the following articles:
http://lwn.net/Articles/70473/
http://lwn.net/Articles/420019/

Yours,
Linus Walleij

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

* Re: [PATCH 1/3] pinctrl: ADI PIN control driver for the GPIO controller on bf54x and bf60x.
  2013-07-29 16:47   ` Linus Walleij
@ 2013-08-01  7:31     ` Sonic Zhang
  2013-08-07 18:56       ` Linus Walleij
  0 siblings, 1 reply; 17+ messages in thread
From: Sonic Zhang @ 2013-08-01  7:31 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Grant Likely, Steven Miao, LKML, adi-buildroot-devel, Sonic Zhang

Hi Linus,

On Tue, Jul 30, 2013 at 12:47 AM, Linus Walleij
<linus.walleij@linaro.org> wrote:
> On Fri, Jul 26, 2013 at 6:57 AM, Sonic Zhang <sonic.adi@gmail.com> wrote:
>
>> Could you please comment on this patch set? It is based on your former comments.
>
> I'll get to it. I'm pretty choked right now and actually trying to have
> some vacation at the same time.
>
> In the meantime, after glancing over and noting prolific use of the
> unlikely() macro, please read the following articles:
> http://lwn.net/Articles/70473/
> http://lwn.net/Articles/420019/
>

These articles say the directives should be rarely used. Do you
suggest to remove them from the patch?

Regards,

Sonic

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

* Re: [PATCH 1/3] pinctrl: ADI PIN control driver for the GPIO controller on bf54x and bf60x.
  2013-08-01  7:31     ` Sonic Zhang
@ 2013-08-07 18:56       ` Linus Walleij
  2013-08-08  3:07         ` Sonic Zhang
  0 siblings, 1 reply; 17+ messages in thread
From: Linus Walleij @ 2013-08-07 18:56 UTC (permalink / raw)
  To: Sonic Zhang
  Cc: Grant Likely, Steven Miao, LKML, adi-buildroot-devel, Sonic Zhang

On Thu, Aug 1, 2013 at 9:31 AM, Sonic Zhang <sonic.adi@gmail.com> wrote:
> On Tue, Jul 30, 2013 at 12:47 AM, Linus Walleij
> <linus.walleij@linaro.org> wrote:
>> On Fri, Jul 26, 2013 at 6:57 AM, Sonic Zhang <sonic.adi@gmail.com> wrote:
>>
>>> Could you please comment on this patch set? It is based on your former comments.
>>
>> I'll get to it. I'm pretty choked right now and actually trying to have
>> some vacation at the same time.
>>
>> In the meantime, after glancing over and noting prolific use of the
>> unlikely() macro, please read the following articles:
>> http://lwn.net/Articles/70473/
>> http://lwn.net/Articles/420019/
>>
>
> These articles say the directives should be rarely used. Do you
> suggest to remove them from the patch?

I think so? Or can you make a case for them being in
a critical path, like have you run a profiler (such as perf)
on the code and come to the conclusion that it's really
needed for performance? In that case, spell it out in the
patch description.

Yours,
Linus Walleij

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

* Re: [PATCH 1/3] pinctrl: ADI PIN control driver for the GPIO controller on bf54x and bf60x.
  2013-08-07 18:56       ` Linus Walleij
@ 2013-08-08  3:07         ` Sonic Zhang
  0 siblings, 0 replies; 17+ messages in thread
From: Sonic Zhang @ 2013-08-08  3:07 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Grant Likely, Steven Miao, LKML, adi-buildroot-devel, Sonic Zhang

Hi Linus,

On Thu, Aug 8, 2013 at 2:56 AM, Linus Walleij <linus.walleij@linaro.org> wrote:
> On Thu, Aug 1, 2013 at 9:31 AM, Sonic Zhang <sonic.adi@gmail.com> wrote:
>> On Tue, Jul 30, 2013 at 12:47 AM, Linus Walleij
>> <linus.walleij@linaro.org> wrote:
>>> On Fri, Jul 26, 2013 at 6:57 AM, Sonic Zhang <sonic.adi@gmail.com> wrote:
>>>
>>>> Could you please comment on this patch set? It is based on your former comments.
>>>
>>> I'll get to it. I'm pretty choked right now and actually trying to have
>>> some vacation at the same time.
>>>
>>> In the meantime, after glancing over and noting prolific use of the
>>> unlikely() macro, please read the following articles:
>>> http://lwn.net/Articles/70473/
>>> http://lwn.net/Articles/420019/
>>>
>>
>> These articles say the directives should be rarely used. Do you
>> suggest to remove them from the patch?
>
> I think so? Or can you make a case for them being in
> a critical path, like have you run a profiler (such as perf)
> on the code and come to the conclusion that it's really
> needed for performance? In that case, spell it out in the
> patch description.
>

I don't have a profiler data. These directives are from the legacy
blackfin gpio driver based on developer's estimation. Removing it in
next patch set is fine to me.

In addition, do you have time to review the whole patch now?


Thanks

Sonic

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

* Re: [PATCH 1/3] pinctrl: ADI PIN control driver for the GPIO controller on bf54x and bf60x.
  2013-07-16 10:55 [PATCH 1/3] pinctrl: ADI PIN control driver for the GPIO controller on bf54x and bf60x Sonic Zhang
                   ` (3 preceding siblings ...)
  2013-07-26  4:57 ` Sonic Zhang
@ 2013-08-14 13:47 ` Linus Walleij
  2013-08-16  6:23   ` Sonic Zhang
  4 siblings, 1 reply; 17+ messages in thread
From: Linus Walleij @ 2013-08-14 13:47 UTC (permalink / raw)
  To: Sonic Zhang, Greg KH
  Cc: Grant Likely, Steven Miao, LKML, buildroot-devel,
	adi-buildroot-devel, Sonic Zhang

i Sonic,

sorry for taking so long before reviewing this, I was on vacation and
had various urgent things to take care of.

On Tue, Jul 16, 2013 at 12:55 PM, Sonic Zhang <sonic.adi@gmail.com> wrote:

> From: Sonic Zhang <sonic.zhang@analog.com>
>
> The new ADI GPIO2 controller was introduced since the BF548 and BF60x
> processors. It differs a lot from the old one on BF5xx processors. So,
> create a pinctrl driver under pinctrl framework.
>
> - Define gpio ports and gpio interrupt controllers as individual platform
> devices.
> - Register a pinctrl driver for the whole GPIO ports and GPIO interrupt
> devices.
> - Probe pint devices before port devices. Put device instances into
> respective gpio and pint lists.
> - Define peripheral, irq and gpio reservation bit masks for each gpio
> port as runtime resources.
> - Save and restore gpio port and pint status MMRs in syscore PM functions.
> - Add peripheral device groups and function data into machine portmux.h.
> - Handle peripheral and gpio requests in pinctrl operation functions.
> - Demux gpio IRQs via the irq_domain created by each GPIO port.
>
> Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>

OK...

> +++ b/drivers/pinctrl/pinctrl-adi2.c
> @@ -0,0 +1,1545 @@
> +/*
> + * Pinctrl Driver for ADI GPIO2 controller
> + *
> + * Copyright 2007-2013 Analog Devices Inc.
> + *
> + * Licensed under the GPLv2 or later
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/module.h>
> +#include <linux/err.h>
> +#include <linux/proc_fs.h>
> +#include <linux/seq_file.h>
> +#include <linux/irq.h>
> +#include <linux/platform_data/pinctrl-adi2.h>
> +#include <linux/irqdomain.h>
> +#include <linux/irqchip/chained_irq.h>
> +#include <linux/pinctrl/pinctrl.h>
> +#include <linux/pinctrl/pinmux.h>
> +#include <linux/pinctrl/consumer.h>
> +#include <linux/pinctrl/machine.h>
> +#include <linux/syscore_ops.h>
> +#include <linux/gpio.h>
> +#include <asm/portmux.h>
> +#include "core.h"
> +
> +static LIST_HEAD(adi_pint_list);
> +static LIST_HEAD(adi_pinctrl_list);

No locks? It seems you getting this all wrong, defining
locks inside the per-instance structs for these lists. That is
not going to protect anything from concurrent use.

Use static local locks right here for the lists instead.

> +
> +#define PERIPHERAL_USAGE 1
> +#define GPIO_USAGE 0
> +
> +#define DRIVER_NAME "pinctrl-adi2"
> +
> +#define RESOURCE_LABEL_SIZE    16
> +#define PINT_HI_OFFSET         16
> +
> +#define RSV_NONE       0
> +#define RSV_GPIO       1
> +#define RSV_INT                2
> +#define RSV_PERI       3
> +
> +/**
> + * struct gpio_reserve_map - a GPIO map structure containing the
> + * reservation status of each PIN.
> + *
> + * @owner: who request the reservation
> + * @rsv_gpio: if this pin is reserved as GPIO
> + * @rsv_int: if this pin is reserved as interrupt
> + * @rsv_peri: if this pin is reserved as part of a peripheral device
> + */
> +struct gpio_reserve_map {
> +       unsigned char owner[RESOURCE_LABEL_SIZE];
> +       bool rsv_gpio;
> +       bool rsv_int;
> +       bool rsv_peri;
> +};

Hm if a pin is us used for interrupts is it not also used
for GPIO at the same time?

I don't understand why you want to keep track of this stuff,
basically the kernel frameworks are already abstracting
this but I guess there is some good reason for this.

> +/**
> + * struct gpio_port_saved - GPIO port registers that should be saved between
> + * power suspend and resume operations.
> + *
> + * @fer: PORTx_FER register
> + * @data: PORTx_DATA register
> + * @dir: PORTx_DIR register
> + * @inen: PORTx_INEN register
> + * @mux: PORTx_MUX register
> + */
> +struct gpio_port_saved {
> +       u16 fer;
> +       u16 data;
> +       u16 dir;
> +       u16 inen;
> +       u32 mux;
> +};

Seem straight-forward.

> +/**
> + * struct gpio_pint - GPIO interrupt controller device. Multiple ADI GPIO
> + * banks can be mapped into one GPIO interrupt controller.
> + *
> + * @node: All gpio_pint instances are added to a global list.

Why? Usually we make drivers self-contained per instance, no need
for one driver instance to know about all the others.

> + * @base: GPIO PINT device register base address
> + * @irq: IRQ of the GPIO PINT device, it is the parent IRQ of all
> + *       GPIO IRQs mapping to this device.
> + * @domain: [0] irq domain of the gpio port, whose hardware interrupts are
> + *             mapping to the low 16-bit of the pint registers.
> + *          [1] irq domain of the gpio port, whose hardware interrupts are
> + *             mapping to the high 16-bit of the pint registers.
> + * @regs: address pointer to the GPIO PINT device> +


What is this struct gpio_pint_regs? I tried to grep the kernel for it:
zero hits. Is this some way to pass the physical address or something?
Anyway you need to merge the code introducing this struct *first*
since it is not before this patch I guess this patch set is not based
on the mainline Linux kernel...

What is a "pint"? It doesn't seem to be a "port interrupt" or anything
like that....

This is what it means to most:
http://en.wikipedia.org/wiki/Pint

> + * @map_count: No more than 2 GPIO banks can be mapped to this PINT device.

Why? Explain here what it means to "map a GPIO bank to a  PINT device".

> + * @lock: This lock make sure the irq_chip operations to one GPIO PINT device
> + *        for different GPIO interrrupts are atomic.
> + * @pint_map_port: Set up the mapping between one GPIO PINT device and
> + *                 multiple GPIO banks.

I don't realize why you need a function pointer for this, and why it needs to be
in this local state container, but I'll read on...

> + */
> +struct gpio_pint {
> +       struct list_head node;
> +       void __iomem *base;
> +       int irq;
> +       struct irq_domain *domain[2];
> +       struct gpio_pint_regs *regs;
> +       struct adi_pm_pint_save saved_data;
> +       int map_count;
> +       spinlock_t lock;
> +
> +       int (*pint_map_port)(struct gpio_pint *pint, u8 assign,
> +                               u8 map, struct irq_domain *domain);
> +};
> +
> +/**
> + * ADI pin controller


> + *
> + * @node: All adi_pmx instances are added to a global list.
> + * @dev: a pointer back to containing device
> + * @pctl: the pinctrl device
> + * @gpio_list: the list of gpio banks owned by this pin controller.
> + * @gpio_base: the base gpio number of this pin controller.

This looks like you are re-implementing the GPIO ranges that we
already have in the pinctrl subsystem. Please look at the other
drivers and try to use the same style and common infrastructure.
The GPIO ranges are also well documented in Documentation/pinctrl.txt

> + */
> +struct adi_pmx {

If it is a pin controller... then rename it adi_pinctrl.

> +       struct list_head node;
> +       struct device *dev;
> +       struct pinctrl_dev *pctl;
> +       struct list_head gpio_list;
> +       unsigned long gpio_base;
> +};
> +
> +/**
> + * struct gpio_pint - GPIO bank device. Multiple ADI GPIO banks can be mapped

pint? Port? The struct is named port...

Please check this in the entire file.

> + * into one GPIO interrupt controller.
> + *
> + * @node: All gpio_pint instances are added to a list.
> + * @base: GPIO bank device register base address
> + * @pin_base: base global GPIO pin index of the GPIO bank device

I think this is another aspect of reimplementing GPIO ranges.

> + * @irq_base: base IRQ of the GPIO bank device
> + * @width: PIN number of the GPIO bank device
> + * @range: The range space of the GPIO bank handled by the pin controller.
> + * @regs: address pointer to the GPIO bank device
> + * @saved_data: registers that should be saved between PM operations.
> + * @dev: device structure of this GPIO bank
> + * @pmx: the pinctrl device
> + * @pint: GPIO PINT device that this GPIO bank mapped to
> + * @pint_map: GIOP bank mapping code in PINT device
> + * @pint_assign: The 32-bit GPIO PINT registers can be divided into 2 parts. A
> + *               GPIO bank can be mapped into either low 16 bits[0] or high 16
> + *               bits[1] of each PINT register.

Is this always 0 or 1? Then you should instead have a bool
named bool is_high; or something.

> + * @lock: This lock make sure the irq_chip operations to one GPIO PINT device
> + *        for different GPIO interrrupts are atomic.
> + * @chip: abstract a GPIO controller
> + * @domain: The irq domain owned by the GPIO port.

Here seems to be many IRQ domains, this this really necessary?

Two in "struct gpio_pint" and one more here? Why?

This seems very complex.

I think you basically need to structure the code and add comments to
the driver header so that it is chrystal clear why we have two abstractions
named "pint" and "port" and how they relate to each other.

> + * @rsvmap: Reservation map array for each pin in the GPIO bank
> + */
> +struct gpio_port {
> +       struct list_head node;
> +       void __iomem *base;
> +       unsigned int pin_base;
> +       unsigned int irq_base;
> +       unsigned int width;
> +       struct pinctrl_gpio_range range;

Here you're finally using the GPIO ranges.

> +       struct gpio_port_t *regs;

Suffuxing things with _t, like it's a type, is hungarian notation
and is not encouraged in the kernel... anyway I see this is
already in the kernel so not your fault I guess.

> +       struct gpio_port_saved saved_data;
> +       struct device *dev;
> +       struct adi_pmx *pmx;

Can't you just make the members of this struct (adi_pmx)
member of this struct and cut down on unnecessary structs?

> +
> +       struct gpio_pint *pint;
> +       u8 pint_map;
> +       u8 pint_assign;
> +
> +       spinlock_t lock;
> +       struct gpio_chip chip;
> +       struct irq_domain *domain;
> +
> +       struct gpio_reserve_map rsvmap[];

And this reserve map.

> +};

What I do not understand is why you need gpio_pint?

Usually this struct is all you need.

> +static inline u8 pin_to_offset(struct pinctrl_gpio_range *range, unsigned pin)
> +{
> +       return pin - range->pin_base;
> +}
> +
> +static inline unsigned offset_to_gpio(struct gpio_port *port, u8 offset)
> +{
> +       return offset + port->chip.base;
> +}
> +
> +static inline u8 gpio_to_offset(struct gpio_port *port, unsigned gpio)
> +{
> +       return gpio - port->chip.base;
> +}

Hmmmm we need this kind of stuff to be done in the pinctrl core. Usually
this should not be needed. Why do you need to do this?

> +static inline unsigned hwirq_to_pintbit(struct gpio_port *port, int hwirq)

Why is this unsigned? Isn't it really u32 or u16?

> +{
> +       return (1 << hwirq) << (port->pint_assign * PINT_HI_OFFSET);

Atleast do this:

#include <linux/bitops.h>

return BIT(hwirq) << (port->pint_assign * PINT_HI_OFFSET);

If pin_assign is only 0 or 1 as I suspect, this is  very unelegant
construction. Then I would prefer:

return port->pint_assign ? BIT(offset) << PINT_HI_OFFSET : BIT(offset);

or something like that where you can see what is going on.

> +static void set_label(struct gpio_port *port, unsigned offset,
> +       const char *label)
> +{
> +       char *pch = port->rsvmap[offset].owner;
> +
> +       if (label) {
> +               strncpy(pch, label, RESOURCE_LABEL_SIZE);
> +               pch[RESOURCE_LABEL_SIZE - 1] = 0;
> +       }
> +}
> +
> +static char *get_label(struct gpio_port *port, unsigned offset)
> +{
> +       char *pch = port->rsvmap[offset].owner;
> +
> +       return *pch ? pch : "UNKNOWN";
> +}

Hm, OK ...

> +static inline unsigned int is_reserved(struct gpio_port *port, char type,
> +       unsigned offset)

The return type should be bool should it not?

> +{
> +       switch (type) {
> +       case RSV_GPIO:
> +               return port->rsvmap[offset].rsv_gpio == true;
> +       case RSV_INT:
> +               return port->rsvmap[offset].rsv_int == true;
> +       case RSV_PERI:
> +               return port->rsvmap[offset].rsv_peri == true;
> +       }

For each of these just e.g.:
return port->rsvmap[offset].rsv_gpio

You're making this simple thing look very complicated.

> +
> +       return 0;
> +}
> +
> +static inline void reserve(struct gpio_port *port, char type, unsigned offset)
> +{
> +       switch (type) {
> +       case RSV_GPIO:
> +               port->rsvmap[offset].rsv_gpio = true;
> +               break;
> +       case RSV_INT:
> +               port->rsvmap[offset].rsv_int = true;
> +               break;
> +       case RSV_PERI:
> +               port->rsvmap[offset].rsv_peri = true;
> +               break;
> +       }
> +}
> +
> +static inline void unreserve(struct gpio_port *port, char type, unsigned offset)
> +{
> +       switch (type) {
> +       case RSV_GPIO:
> +               port->rsvmap[offset].rsv_gpio = false;
> +               break;
> +       case RSV_INT:
> +               port->rsvmap[offset].rsv_int = false;
> +               break;
> +       case RSV_PERI:
> +               port->rsvmap[offset].rsv_peri = false;
> +               break;
> +       }
> +}

Having helper functions for these things seem a bit overdesigned
actually. Do you really need them?

> +static struct gpio_pint *find_gpio_pint(unsigned id)
> +{
> +       struct gpio_pint *pint;
> +       int i = 0;
> +
> +       list_for_each_entry(pint, &adi_pint_list, node) {
> +               if (id == i)
> +                       break;

Just return pint; here

> +               i++;
> +       }
> +
> +       if (&pint->node != &adi_pint_list)
> +               return pint;

And skip this super-confusing thing.

> +       else
> +               return NULL;
> +}

And just return NULL;

> +
> +static struct adi_pmx *find_pinctrl(unsigned id)
> +{
> +       struct adi_pmx *pmx;
> +       int i = 0;
> +
> +       list_for_each_entry(pmx, &adi_pinctrl_list, node) {
> +               if (id == i)
> +                       break;
> +               i++;
> +       }
> +
> +       if (&pmx->node != &adi_pinctrl_list)
> +               return pmx;
> +       else
> +               return NULL;
> +}

Same comments.

If you merge the pmx and gpio_port structs into one you
will at least just need one of these functions.

But I am suspecting that all this is unnecessary and you
should be using something like container_of() instead.

Do you know and understand the kernel container_of()
abstraction pattern? Else please look at examples of how
we use this.

> +static struct gpio_port *find_gpio_port(unsigned pin,
> +       struct list_head *gpio_list)
> +{
> +       struct gpio_port *port;
> +
> +       list_for_each_entry(port, gpio_list, node)
> +               if (pin >= port->range.pin_base &&
> +                       pin < port->range.pin_base + port->range.npins)
> +                       break;
> +
> +       if (&port->node != gpio_list)
> +               return port;
> +       else
> +               return NULL;
> +}

Same comments.

> +static inline void port_setup(struct gpio_port *port, unsigned offset,
> +       unsigned short usage)

Either usage should be an enum or you can replace it with a bool
like bool use_for_gpio.

> +{
> +       struct gpio_port_t *regs = port->regs;
> +
> +       if (usage == GPIO_USAGE)
> +               writew(readw(&regs->port_fer) & ~(1 << offset),
> +                       &regs->port_fer);

Use BIT(offset)

This &regs->ports_fer is really awkward but I guess all
blackfin stuff is written that way?

> +       else
> +               writew(readw(&regs->port_fer) | (1 << offset), &regs->port_fer);

Use BIT(offset)

> +}
> +
> +static inline void portmux_setup(struct gpio_port *port, unsigned offset,
> +       unsigned short function)
> +{
> +       struct gpio_port_t *regs = port->regs;
> +       u32 pmux;
> +
> +       pmux = readl(&regs->port_mux);
> +
> +       pmux &= ~(0x3 << (2 * offset));
> +       pmux |= (function & 0x3) << (2 * offset);

0x3? why? 2*offset?

Care to put in a comment on what is happening here?
Like that we use 2 consecutive bits for setting function?

> +
> +       writel(pmux, &regs->port_mux);
> +}
> +
> +static inline u16 get_portmux(struct gpio_port *port, unsigned offset)
> +{
> +       struct gpio_port_t *regs = port->regs;
> +       u32 pmux = readl(&regs->port_mux);
> +
> +       return pmux >> (2 * offset) & 0x3;

Dito...

> +}
> +
> +
> +static void __adi_gpio_irq_prepare(struct gpio_port *port, unsigned offset)
> +{
> +       struct gpio_port_t *regs = port->regs;
> +
> +       port_setup(port, offset, GPIO_USAGE);
> +
> +       writew(1 << offset, &regs->dir_clear);

BIT(offset)

> +       writew(readw(&regs->inen) | (1 << offset), &regs->inen);

etc.

> +}
> +
> +static int __adi_gpio_irq_request(struct gpio_port *port, unsigned offset,
> +       const char *label)
> +{
> +       if (unlikely(is_reserved(port, RSV_PERI, offset))) {
> +               if (system_state == SYSTEM_BOOTING)
> +                       dump_stack();
> +
> +               dev_err(port->dev,
> +                      "GPIO %d is already reserved as Peripheral by %s !\n",
> +                       offset_to_gpio(port, offset), get_label(port, offset));
> +               return -EBUSY;
> +       }
> +       if (unlikely(is_reserved(port, RSV_GPIO, offset)))
> +               dev_err(port->dev,
> +                       "GPIO %d is already reserved by %s!\n",
> +                       offset_to_gpio(port, offset), get_label(port, offset));

As mentioned get rid of unlikely() macros.

> +
> +       reserve(port, RSV_INT, offset);
> +       set_label(port, offset, label);
> +       port_setup(port, offset, GPIO_USAGE);
> +
> +       return 0;
> +}
> +
> +static void __adi_gpio_irq_free(struct gpio_port *port, unsigned offset)
> +{
> +       if (unlikely(!is_reserved(port, RSV_INT, offset))) {
> +               if (system_state == SYSTEM_BOOTING)
> +                       dump_stack();
> +
> +               dev_err(port->dev, "GPIO %d wasn't requested!\n",
> +                       offset_to_gpio(port, offset));
> +               return;
> +       }
> +
> +       unreserve(port, RSV_INT, offset);
> +       set_label(port, offset, "free");
> +}
> +
> +static void adi_gpio_ack_irq(struct irq_data *d)
> +{
> +       unsigned long flags;
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +       struct gpio_pint_regs *regs = port->pint->regs;
> +       unsigned pintbit = hwirq_to_pintbit(port, d->hwirq);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +       spin_lock_irqsave(&port->pint->lock, flags);

Taking two locks to ACK an IRQ is really inconvenient is it not?

It also impacts performance.

This is one reason you should try to get rid of excess
structs in this driver.

If any or both locks are really locks for the lists, then make
the static locals in the driver instead of part of the struct.

> +
> +       if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) {
> +               if (readl(&regs->invert_set) & pintbit)
> +                       writel(pintbit, &regs->invert_clear);
> +               else
> +                       writel(pintbit, &regs->invert_set);
> +       }
> +
> +       writel(pintbit, &regs->request);
> +
> +       spin_unlock_irqrestore(&port->pint->lock, flags);
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static void adi_gpio_mask_ack_irq(struct irq_data *d)
> +{
> +       unsigned long flags;
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +       struct gpio_pint_regs *regs = port->pint->regs;
> +       unsigned pintbit = hwirq_to_pintbit(port, d->hwirq);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +       spin_lock_irqsave(&port->pint->lock, flags);
> +
> +       if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) {
> +               if (readl(&regs->invert_set) & pintbit)
> +                       writel(pintbit, &regs->invert_clear);
> +               else
> +                       writel(pintbit, &regs->invert_set);
> +       }
> +
> +       writel(pintbit, &regs->request);
> +       writel(pintbit, &regs->mask_clear);
> +
> +       spin_unlock_irqrestore(&port->pint->lock, flags);
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static void adi_gpio_mask_irq(struct irq_data *d)
> +{
> +       unsigned long flags;
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +       struct gpio_pint_regs *regs = port->pint->regs;
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +       spin_lock_irqsave(&port->pint->lock, flags);
> +
> +       writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_clear);
> +
> +       spin_unlock_irqrestore(&port->pint->lock, flags);
> +       spin_unlock_irqrestore(&port->lock, flags);

So like in a case like this taking two locks to write a single
bit in a single register is starting to look a bit silly.

> +}
> +
> +static void adi_gpio_unmask_irq(struct irq_data *d)
> +{
> +       unsigned long flags;
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +       struct gpio_pint_regs *regs = port->pint->regs;
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +       spin_lock_irqsave(&port->pint->lock, flags);
> +
> +       writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_set);
> +
> +       spin_unlock_irqrestore(&port->pint->lock, flags);
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}

Dito.

> +static unsigned int adi_gpio_irq_startup(struct irq_data *d)
> +{
> +       unsigned long flags;
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +       struct gpio_pint_regs *regs = port->pint->regs;
> +
> +       if (!port) {
> +               dev_err(port->dev, "GPIO IRQ %d :Not exist\n", d->irq);
> +               return -ENODEV;
> +       }
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +       spin_lock_irqsave(&port->pint->lock, flags);
> +
> +       __adi_gpio_irq_prepare(port, d->hwirq);
> +       writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_set);
> +
> +       spin_unlock_irqrestore(&port->pint->lock, flags);
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return 0;
> +}

Dito.

> +static void adi_gpio_irq_shutdown(struct irq_data *d)
> +{
> +       unsigned long flags;
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +       struct gpio_pint_regs *regs = port->pint->regs;
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +       spin_lock_irqsave(&port->pint->lock, flags);
> +
> +       writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_clear);
> +       __adi_gpio_irq_free(port, d->hwirq);
> +
> +       spin_unlock_irqrestore(&port->pint->lock, flags);
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}

Dito.

> +static int adi_gpio_irq_type(struct irq_data *d, unsigned int type)
> +{
> +       unsigned long flags;
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +       struct gpio_pint_regs *pint_regs = port->pint->regs;
> +       unsigned pintmask;
> +       unsigned int irq = d->irq;
> +       int ret = 0;
> +       char buf[16];
> +
> +       if (!port) {
> +               dev_err(port->dev, "GPIO IRQ %d :Not exist\n", irq);
> +               return -ENODEV;
> +       }
> +
> +       pintmask = hwirq_to_pintbit(port, d->hwirq);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +       spin_lock_irqsave(&port->pint->lock, flags);
> +
> +       if (type == IRQ_TYPE_PROBE)
> +               type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;

What does this mean in practice? Add a comment explaining
why you do this.

> +
> +       if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
> +                   IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
> +               snprintf(buf, 16, "gpio-irq%d", irq);
> +               ret = __adi_gpio_irq_request(port, d->hwirq, buf);
> +               if (ret)
> +                       goto out;
> +       } else
> +               goto out;
> +
> +       if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
> +               /* low or falling edge denoted by one */
> +               writel(pintmask, &pint_regs->invert_set);
> +       else
> +               /* high or rising edge denoted by zero */
> +               writel(pintmask, &pint_regs->invert_clear);

So one register to set and one to clear the flags, clever...

> +       if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
> +               if (gpio_get_value(offset_to_gpio(port, d->hwirq)))
> +                       writel(pintmask, &pint_regs->invert_set);
> +               else
> +                       writel(pintmask, &pint_regs->invert_clear);
> +       }

Care to explain what's happening here? Some comment in the
code?

> +       if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
> +               writel(pintmask, &pint_regs->edge_set);
> +               __irq_set_handler_locked(irq, handle_edge_irq);
> +       } else {
> +               writel(pintmask, &pint_regs->edge_clear);
> +               __irq_set_handler_locked(irq, handle_level_irq);
> +       }

I think I understand this part.

> +
> +out:
> +       spin_unlock_irqrestore(&port->pint->lock, flags);
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return ret;
> +}
> +
> +#ifdef CONFIG_PM
> +static int adi_gpio_set_wake(struct irq_data *d, unsigned int state)
> +{
> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
> +
> +       if (!port && !port->pint && port->pint->irq != d->irq)
> +               return -EINVAL;

Why are you using the && operator here?

If port is NULL it will go on an dereference port->pint and have
a NULL reference.

Probably you meant to use ||.

> +#ifndef SEC_GCTL
> +       adi_internal_set_wake(port->pint->irq, state);
> +#endif
> +
> +       return 0;
> +}
> +
> +static int adi_pint_suspend(void)
> +{
> +       struct gpio_pint *pint;
> +
> +       list_for_each_entry(pint, &adi_pint_list, node) {
> +               writel(0xffffffff, &pint->regs->mask_clear);
> +               pint->saved_data.assign = readl(&pint->regs->assign);
> +               pint->saved_data.edge_set = readl(&pint->regs->edge_set);
> +               pint->saved_data.invert_set = readl(&pint->regs->invert_set);
> +       }

Will the wakeups really work if you clear all regs like this?

> +
> +       return 0;
> +}
> +
> +static void adi_pint_resume(void)
> +{
> +       struct gpio_pint *pint;
> +
> +       list_for_each_entry(pint, &adi_pint_list, node) {
> +               writel(pint->saved_data.assign, &pint->regs->assign);
> +               writel(pint->saved_data.edge_set, &pint->regs->edge_set);
> +               writel(pint->saved_data.invert_set, &pint->regs->invert_set);
> +       }
> +}
> +
> +static int adi_gpio_suspend(void)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +
> +       list_for_each_entry(pmx, &adi_pinctrl_list, node)
> +               list_for_each_entry(port, &pmx->gpio_list, node) {
> +                       port->saved_data.fer = readw(&port->regs->port_fer);
> +                       port->saved_data.mux = readl(&port->regs->port_mux);
> +                       port->saved_data.data = readw(&port->regs->data);
> +                       port->saved_data.inen = readw(&port->regs->inen);
> +                       port->saved_data.dir = readw(&port->regs->dir_set);
> +               }
> +
> +       return adi_pint_suspend();
> +}
> +
> +static void adi_gpio_resume(void)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +
> +       adi_pint_resume();
> +
> +       list_for_each_entry(pmx, &adi_pinctrl_list, node)
> +               list_for_each_entry(port, &pmx->gpio_list, node) {
> +                       writel(port->saved_data.mux, &port->regs->port_mux);
> +                       writew(port->saved_data.fer, &port->regs->port_fer);
> +                       writew(port->saved_data.inen, &port->regs->inen);
> +                       writew(port->saved_data.data & port->saved_data.dir,
> +                                               &port->regs->data_set);
> +                       writew(port->saved_data.dir, &port->regs->dir_set);
> +               }
> +
> +}

The four functions are doing much the same thing, can't you just
merge the pint and port structs as mentioned elsewhere and make
things a lot simpler that way?

> +static struct syscore_ops gpio_pm_syscore_ops = {
> +       .suspend = adi_gpio_suspend,
> +       .resume = adi_gpio_resume,
> +};
> +#else /* CONFIG_PM */
> +#define adi_gpio_set_wake NULL
> +#endif /* CONFIG_PM */
> +
> +#ifdef CONFIG_IRQ_PREFLOW_FASTEOI
> +static inline void preflow_handler(struct irq_desc *desc)
> +{
> +       if (desc->preflow_handler)
> +               desc->preflow_handler(&desc->irq_data);
> +}
> +#else
> +static inline void preflow_handler(struct irq_desc *desc) { }
> +#endif
> +
> +static void adi_gpio_handle_pint_irq(unsigned int inta_irq,
> +                       struct irq_desc *desc)
> +{
> +       u32 request;
> +       u32 level_mask, hwirq;
> +       int umask = 0;

bool umask = false;

> +       struct gpio_pint *pint = irq_desc_get_handler_data(desc);
> +       struct irq_chip *chip = irq_desc_get_chip(desc);
> +       struct gpio_pint_regs *regs = pint->regs;
> +       struct irq_domain *domain;
> +
> +       preflow_handler(desc);
> +       chained_irq_enter(chip, desc);
> +
> +       request = readl(&regs->request);
> +       level_mask = readl(&regs->edge_set) & request;
> +
> +       hwirq = 0;
> +       domain = pint->domain[0];
> +       while (request) {

You probably want to re-read request in each iteration.
What will happen if new bits are lit up as you process
the IRQs otherwise?

> +               if (hwirq == PINT_HI_OFFSET)
> +                       domain = pint->domain[1];

Why is that not hwirq >= PINT_HI_OFFSET?
This will *only* be true for IRQ 16.

> +
> +               if (request & 1) {
> +                       if (level_mask & (1 << hwirq)) {

BIT(hwirq)

> +                               umask = 1;

umask = true;

> +                               chained_irq_exit(chip, desc);
> +                       }
> +                       generic_handle_irq(irq_find_mapping(domain,
> +                                       hwirq % PINT_HI_OFFSET));

This was elegant, and not complicated as in other places.

> +               }
> +
> +               hwirq++;
> +               request >>= 1;
> +       }
> +
> +       if (!umask)
> +               chained_irq_exit(chip, desc);
> +}
> +
> +static struct irq_chip adi_gpio_irqchip = {
> +       .name = "GPIO",
> +       .irq_ack = adi_gpio_ack_irq,
> +       .irq_mask = adi_gpio_mask_irq,
> +       .irq_mask_ack = adi_gpio_mask_ack_irq,
> +       .irq_unmask = adi_gpio_unmask_irq,
> +       .irq_disable = adi_gpio_mask_irq,
> +       .irq_enable = adi_gpio_unmask_irq,
> +       .irq_set_type = adi_gpio_irq_type,
> +       .irq_startup = adi_gpio_irq_startup,
> +       .irq_shutdown = adi_gpio_irq_shutdown,
> +       .irq_set_wake = adi_gpio_set_wake,
> +};
> +
> +
> +static int adi_get_groups_count(struct pinctrl_dev *pctldev)
> +{
> +       return ARRAY_SIZE(adi_pin_groups);
> +}
> +
> +static const char *adi_get_group_name(struct pinctrl_dev *pctldev,
> +                                      unsigned selector)
> +{
> +       return adi_pin_groups[selector].name;
> +}
> +
> +static int adi_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
> +                              const unsigned **pins,
> +                              unsigned *num_pins)
> +{
> +       *pins = adi_pin_groups[selector].pins;
> +       *num_pins = adi_pin_groups[selector].num;
> +       return 0;
> +}
> +
> +static void adi_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
> +                  unsigned offset)
> +{
> +       seq_puts(s, DRIVER_NAME);

Can't you output some useful data here instead of just the driver name?
You know the pin offset and everything, why not print the status of triggers,
whether it is in GPIO mode, if it is flagged to be used as IRQ etc?

> +}
> +
> +static struct pinctrl_ops adi_pctrl_ops = {
> +       .get_groups_count = adi_get_groups_count,
> +       .get_group_name = adi_get_group_name,
> +       .get_group_pins = adi_get_group_pins,
> +       .pin_dbg_show = adi_pin_dbg_show,
> +};
> +
> +static int adi_pinmux_request(struct pinctrl_dev *pctldev, unsigned pin)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +       unsigned long flags;
> +       struct pin_desc *desc;
> +       u8 offset;
> +
> +       pmx = pinctrl_dev_get_drvdata(pctldev);
> +
> +       port = find_gpio_port(pin, &pmx->gpio_list);
> +       if (port == NULL) {
> +               dev_err(pctldev->dev,
> +                      "%s: Peripheral PIN %d doesn't exist!\n",
> +                      __func__, pin);
> +               return -ENODEV;
> +       }
> +
> +       offset = pin_to_offset(&port->range, pin);
> +       desc = radix_tree_lookup(&pctldev->pin_desc_tree, pin);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       /* If a pin can be muxed as either GPIO or peripheral, make
> +        * sure it is not already a GPIO pin when we request it.
> +        */
> +       if (unlikely(is_reserved(port, RSV_GPIO, offset))) {
> +               if (system_state == SYSTEM_BOOTING)
> +                       dump_stack();
> +               dev_err(pctldev->dev,
> +                      "%s: Peripheral PIN %d is already reserved as GPIO by %s!\n",
> +                      __func__, pin, get_label(port, offset));
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return -EBUSY;
> +       }
> +
> +       if (unlikely(is_reserved(port, RSV_PERI, offset))) {
> +               if (system_state == SYSTEM_BOOTING)
> +                       dump_stack();
> +               dev_err(pctldev->dev,
> +                       "%s: Peripheral PIN %d is already reserved by %s!\n",
> +                       __func__, pin, get_label(port, offset));
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return -EBUSY;
> +       }

Get rid of unlikely().

> +
> +       reserve(port, RSV_PERI, offset);
> +       set_label(port, offset, desc->mux_owner);
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return 0;
> +}
> +
> +static int adi_pinmux_free(struct pinctrl_dev *pctldev, unsigned pin)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +       unsigned long flags;
> +       u8 offset;
> +
> +       pmx = pinctrl_dev_get_drvdata(pctldev);
> +       port = find_gpio_port(pin, &pmx->gpio_list);
> +       if (port == NULL)
> +               return 0;
> +
> +       offset = pin_to_offset(&port->range, pin);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       if (unlikely(!is_reserved(port, RSV_PERI, offset))) {
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return 0;
> +       }

get rid of unlikely().

> +
> +       unreserve(port, RSV_PERI, offset);
> +       set_label(port, offset, "free");
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return 0;
> +}
> +
> +static int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector,
> +       unsigned group)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +       unsigned long flags;
> +       unsigned short *mux = (unsigned short *)adi_pmx_functions[selector].mux;
> +       unsigned short gpio;
> +
> +       pmx = pinctrl_dev_get_drvdata(pctldev);
> +
> +       while (*mux) {
> +               gpio = P_IDENT(*mux);
> +
> +               port = find_gpio_port(gpio - pmx->gpio_base, &pmx->gpio_list);
> +               if (port == NULL) /* should not happen */
> +                       continue;
> +
> +               spin_lock_irqsave(&port->lock, flags);
> +
> +               portmux_setup(port, gpio_to_offset(port, gpio),
> +                                P_FUNCT2MUX(*mux));
> +               port_setup(port, gpio_to_offset(port, gpio), PERIPHERAL_USAGE);
> +               mux++;
> +
> +               spin_unlock_irqrestore(&port->lock, flags);
> +       }
> +
> +       return 0;
> +}
> +
> +static void adi_pinmux_disable(struct pinctrl_dev *pctldev, unsigned selector,
> +       unsigned group)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +       unsigned long flags;
> +       unsigned short *mux = (unsigned short *)adi_pmx_functions[selector].mux;
> +       unsigned short gpio;
> +
> +       pmx = pinctrl_dev_get_drvdata(pctldev);
> +
> +       while (*mux) {
> +               gpio = P_IDENT(*mux);
> +
> +               port = find_gpio_port(gpio - pmx->gpio_base, &pmx->gpio_list);
> +               if (port == NULL) /* should not happen */
> +                       continue;
> +
> +               spin_lock_irqsave(&port->lock, flags);
> +
> +               port_setup(port, gpio_to_offset(port, gpio), GPIO_USAGE);
> +               mux++;
> +
> +               spin_unlock_irqrestore(&port->lock, flags);
> +       }
> +}
> +
> +static int adi_pinmux_get_funcs_count(struct pinctrl_dev *pctldev)
> +{
> +       return ARRAY_SIZE(adi_pmx_functions);
> +}
> +
> +static const char *adi_pinmux_get_func_name(struct pinctrl_dev *pctldev,
> +                                         unsigned selector)
> +{
> +       return adi_pmx_functions[selector].name;
> +}
> +
> +static int adi_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
> +                              const char * const **groups,
> +                              unsigned * const num_groups)
> +{
> +       *groups = adi_pmx_functions[selector].groups;
> +       *num_groups = adi_pmx_functions[selector].num_groups;
> +       return 0;
> +}
> +
> +static int adi_pinmux_request_gpio(struct pinctrl_dev *pctldev,
> +       struct pinctrl_gpio_range *range, unsigned pin)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +       unsigned long flags;
> +       u8 offset;
> +
> +       pmx = pinctrl_dev_get_drvdata(pctldev);
> +       port = find_gpio_port(pin, &pmx->gpio_list);
> +       if (port == NULL) {
> +               dev_err(pctldev->dev,
> +                      "%s: GPIO PIN %d doesn't exist!\n",
> +                      __func__, pin);
> +               return -ENODEV;
> +       }
> +
> +       offset = pin_to_offset(&port->range, pin);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       if (unlikely(is_reserved(port, RSV_GPIO, offset))) {
> +               if (system_state == SYSTEM_BOOTING)
> +                       dump_stack();
> +               dev_err(pctldev->dev,
> +                       "GPIO %d is already reserved by %s !\n",
> +                       offset_to_gpio(port, offset), get_label(port, offset));
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return -EBUSY;
> +       }
> +       if (unlikely(is_reserved(port, RSV_PERI, offset))) {
> +               if (system_state == SYSTEM_BOOTING)
> +                       dump_stack();
> +               dev_err(pctldev->dev,
> +                       "GPIO %d is already reserved as peripheral by %s !\n",
> +                       offset_to_gpio(port, offset), get_label(port, offset));
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return -EBUSY;
> +       }
> +       if (unlikely(is_reserved(port, RSV_INT, offset))) {
> +               dev_err(pctldev->dev,
> +                       "GPIO %d is already reserved as gpio-irq!\n",
> +                       offset_to_gpio(port, offset));
> +       }

Get rid of all unlikely().

> +       reserve(port, RSV_GPIO, offset);
> +       set_label(port, offset, port->chip.label);
> +       port_setup(port, offset, GPIO_USAGE);
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return 0;
> +}
> +
> +static void adi_pinmux_free_gpio(struct pinctrl_dev *pctldev,
> +       struct pinctrl_gpio_range *range, unsigned pin)
> +{
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +       unsigned long flags;
> +       u8 offset;
> +
> +       pmx = pinctrl_dev_get_drvdata(pctldev);
> +       port = find_gpio_port(pin, &pmx->gpio_list);
> +       if (port == NULL)
> +               return;
> +
> +       offset = pin_to_offset(&port->range, pin);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       if (unlikely(!is_reserved(port, RSV_GPIO, offset))) {
> +               if (system_state == SYSTEM_BOOTING)
> +                       dump_stack();
> +
> +               dev_err(pctldev->dev,
> +                       "GPIO %d wasn't requested!\n",
> +                       offset_to_gpio(port, offset));
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return;
> +       }

Dito.

> +       unreserve(port, RSV_GPIO, offset);
> +       set_label(port, offset, "free");
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return;
> +}
> +
> +static struct pinmux_ops adi_pinmux_ops = {
> +       .request = adi_pinmux_request,
> +       .free = adi_pinmux_free,
> +       .enable = adi_pinmux_enable,
> +       .disable = adi_pinmux_disable,
> +       .get_functions_count = adi_pinmux_get_funcs_count,
> +       .get_function_name = adi_pinmux_get_func_name,
> +       .get_function_groups = adi_pinmux_get_groups,
> +       .gpio_request_enable = adi_pinmux_request_gpio,
> +       .gpio_disable_free = adi_pinmux_free_gpio,
> +};
> +
> +
> +static struct pinctrl_desc adi_pinmux_desc = {
> +       .name = DRIVER_NAME,
> +       .pins = adi_pads,
> +       .npins = ARRAY_SIZE(adi_pads),
> +       .pctlops = &adi_pctrl_ops,
> +       .pmxops = &adi_pinmux_ops,
> +       .owner = THIS_MODULE,
> +};
> +
> +static int adi_gpio_request(struct gpio_chip *chip, unsigned offset)
> +{
> +       struct gpio_port *port;
> +
> +       port = container_of(chip, struct gpio_port, chip);
> +
> +       return pinctrl_request_gpio(offset_to_gpio(port, offset));
> +}
> +
> +static void adi_gpio_free(struct gpio_chip *chip, unsigned offset)
> +{
> +       struct gpio_port *port;
> +
> +       port = container_of(chip, struct gpio_port, chip);
> +
> +       pinctrl_free_gpio(offset_to_gpio(port, offset));
> +}
> +
> +static int adi_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
> +{
> +       struct gpio_port *port;
> +       unsigned long flags;
> +
> +       port = container_of(chip, struct gpio_port, chip);
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       if (unlikely(!is_reserved(port, RSV_GPIO, offset))) {
> +               dev_err(port->dev, "GPIO %d wasn't requested!\n",
> +                       offset_to_gpio(port, offset));
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return -EINVAL;
> +       }
> +
> +       writew(1 << offset, &port->regs->dir_clear);
> +       writew(readw(&port->regs->inen) | (1 << offset), &port->regs->inen);

BIT(offset) etc.

> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return 0;
> +}
> +
> +static void adi_gpio_set_value(struct gpio_chip *chip, unsigned offset,
> +       int value)
> +{
> +       struct gpio_port *port = container_of(chip, struct gpio_port, chip);
> +       struct gpio_port_t *regs = port->regs;
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       if (value)
> +               writew(1 << offset, &regs->data_set);
> +       else
> +               writew(1 << offset, &regs->data_clear);
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static int adi_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
> +       int value)
> +{
> +       struct gpio_port *port = container_of(chip, struct gpio_port, chip);
> +       struct gpio_port_t *regs = port->regs;
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       if (unlikely(!is_reserved(port, RSV_GPIO, offset))) {
> +               dev_err(port->dev, "GPIO %d wasn't requested!\n",
> +                       offset_to_gpio(port, offset));
> +               spin_unlock_irqrestore(&port->lock, flags);
> +               return -EINVAL;
> +       }
> +
> +       writew(readw(&regs->inen) & ~(1 << offset), &regs->inen);
> +       adi_gpio_set_value(chip, offset, value);
> +       writew(1 << offset, &regs->dir_set);
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return 0;
> +}
> +
> +static int adi_gpio_get_value(struct gpio_chip *chip, unsigned offset)
> +{
> +       struct gpio_port *port = container_of(chip, struct gpio_port, chip);
> +       struct gpio_port_t *regs = port->regs;
> +       unsigned long flags;
> +       int ret;
> +
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       ret = 1 & (readw(&regs->data) >> offset);

Use this construct:

ret = !!(readw(&regs->data) & BIT(offset));

> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +
> +       return ret;
> +}
> +
> +static int adi_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
> +{
> +       struct gpio_port *port = container_of(chip, struct gpio_port, chip);
> +
> +       if (port->irq_base >= 0)
> +               return irq_find_mapping(port->domain, offset);

Why? Normally you want to create a mapping for everything
here, and it doesn't hurt if you do it twice. Just use

return irq_create_mapping(...);

> +       else
> +               return irq_create_mapping(port->domain, offset);
> +}
> +
> +#if defined(CONFIG_PROC_FS)
> +static inline unsigned short get_gpio_dir(struct gpio_port *port,
> +       unsigned offset)
> +{
> +       struct gpio_port_t *regs = port->regs;
> +
> +       return 1 & (readw(&regs->dir_clear) >> offset);

Use:
return !!(readw(&regs->dir_clear) & BIT(offset));

> +static int gpio_proc_show(struct seq_file *m, void *v)
> +{
> +       int offset, irq, gpio;
> +       struct adi_pmx *pmx;
> +       struct gpio_port *port;
> +
> +       list_for_each_entry(pmx, &adi_pinctrl_list, node)
> +       list_for_each_entry(port, &pmx->gpio_list, node)
> +               for (offset = 0; offset < port->width; offset++) {
> +                       irq = is_reserved(port, RSV_INT, offset);
> +                       gpio = is_reserved(port, RSV_GPIO, offset);
> +                       if (gpio || irq)
> +                               seq_printf(m, "GPIO_%d: \t%s%s \t\tGPIO %s\n",
> +                                       offset_to_gpio(port, offset),
> +                                       get_label(port, offset),
> +                                       (gpio && irq) ? " *" : "",
> +                                       get_gpio_dir(port, offset) ?
> +                                       "OUTPUT" : "INPUT");
> +                       else if (is_reserved(port, RSV_PERI, offset))
> +                               seq_printf(m, "GPIO_%d: \t%s \t\tPeripheral\n",
> +                                       offset_to_gpio(port, offset),
> +                                       get_label(port, offset));
> +                       else
> +                               continue;
> +               }

This double-list traversal is really awkward.
Can't you just merge pint & port?

> +
> +       return 0;
> +}
> +
> +static int gpio_proc_open(struct inode *inode, struct file *file)
> +{
> +       return single_open(file, gpio_proc_show, NULL);
> +}
> +
> +static const struct file_operations gpio_proc_ops = {
> +       .open           = gpio_proc_open,
> +       .read           = seq_read,
> +       .llseek         = seq_lseek,
> +       .release        = single_release,
> +};
> +
> +static __init int gpio_register_proc(void)
> +{
> +       struct proc_dir_entry *proc_gpio;
> +
> +       proc_gpio = proc_create("gpio", 0, NULL, &gpio_proc_ops);

No way are you going to create a procfs file for this.
Greg would get me for this. Use debugfs for this and make the
code dependent on #ifdef CONFIG_DEBUG_FS.

> +       return proc_gpio == NULL;
> +}
> +device_initcall(gpio_register_proc);
> +#endif
> +
> +static int adi_pint_map_port(struct gpio_pint *pint, u8 assign, u8 map,
> +       struct irq_domain *domain)
> +{
> +       struct gpio_pint_regs *regs = pint->regs;
> +
> +       if (pint->map_count > 1)
> +               return -EINVAL;
> +
> +       if (assign > 1)
> +               return -EINVAL;
> +
> +       pint->map_count++;
> +
> +       writel((readl(&regs->assign) & (0xFFFF << !assign * PINT_HI_OFFSET)) |
> +               (((map << 8) | map) << assign * PINT_HI_OFFSET), &regs->assign);

Do you understand what is happening here? I don't.

Care to break it down and explain it?

> +       pint->domain[assign] = domain;
> +
> +       return 0;
> +}
> +
> +static int adi_gpio_pint_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct resource *res;
> +       struct gpio_pint *pint;
> +
> +       pint = devm_kzalloc(dev, sizeof(struct gpio_pint), GFP_KERNEL);
> +       if (!pint) {
> +               dev_err(dev, "Memory alloc failed\n");
> +               return -ENOMEM;
> +       }
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       if (unlikely(!res)) {

Get rid of all these unlikely() macros in probe().

> +               dev_err(dev, "Invalid mem resource\n");
> +               return -ENODEV;
> +       }
> +
> +       if (!devm_request_mem_region(dev, res->start, resource_size(res),
> +                                    pdev->name)) {
> +               dev_err(dev, "Region already claimed\n");
> +               return -EBUSY;
> +       }
> +
> +       pint->base = devm_ioremap(dev, res->start, resource_size(res));
> +       if (!pint->base) {
> +               dev_err(dev, "Could not ioremap\n");
> +               return -ENOMEM;
> +       }
> +
> +       pint->regs = (struct gpio_pint_regs *)pint->base;
> +
> +       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> +       if (unlikely(!res)) {
> +               dev_err(dev, "Invalid IRQ resource\n");
> +               return -ENODEV;
> +       }
> +
> +       spin_lock_init(&pint->lock);
> +
> +       pint->irq = res->start;
> +       pint->pint_map_port = adi_pint_map_port;
> +       platform_set_drvdata(pdev, pint);
> +
> +       irq_set_chained_handler(pint->irq, adi_gpio_handle_pint_irq);
> +       irq_set_handler_data(pint->irq, pint);
> +
> +       list_add_tail(&pint->node, &adi_pint_list);
> +
> +       return 0;
> +}
> +
> +static int adi_gpio_pint_remove(struct platform_device *pdev)
> +{
> +       struct gpio_pint *pint = platform_get_drvdata(pdev);
> +
> +       list_del(&pint->node);
> +       irq_set_handler(pint->irq, handle_simple_irq);
> +       platform_set_drvdata(pdev, NULL);

There is no need to set drvdata to NULL. This is done by the
device core, so get rid of this line.

> +
> +       return 0;
> +}
> +
> +static int adi_gpio_irq_map(struct irq_domain *d, unsigned int irq,
> +                               irq_hw_number_t hwirq)
> +{
> +       struct gpio_port *port = d->host_data;
> +
> +       if (!port)
> +               return -EINVAL;
> +
> +       irq_set_chip_data(irq, port);
> +       irq_set_chip_and_handler(irq, &adi_gpio_irqchip,
> +                               handle_level_irq);
> +
> +       return 0;
> +}
> +
> +const struct irq_domain_ops adi_gpio_irq_domain_ops = {
> +       .map = adi_gpio_irq_map,
> +       .xlate = irq_domain_xlate_onecell,
> +};
> +
> +static int adi_gpio_init_int(struct gpio_port *port)
> +{
> +       struct device_node *node = port->dev->of_node;
> +       struct gpio_pint *pint = port->pint;
> +       int ret;
> +
> +       port->domain = irq_domain_add_linear(node, port->width,
> +                               &adi_gpio_irq_domain_ops, port);
> +       if (!port->domain) {
> +               dev_err(port->dev, "Failed to create irqdomain\n");
> +               return -ENOSYS;
> +       }
> +
> +       ret = pint->pint_map_port(port->pint, port->pint_assign,
> +                       port->pint_map, port->domain);
> +       if (ret)
> +               return ret;

Explain what is happening here and how pints and ports relate.

> +       if (port->irq_base >= 0) {
> +               ret = irq_create_strict_mappings(port->domain, port->irq_base,
> +                                       0, port->width);
> +               if (ret) {
> +                       dev_err(port->dev, "Couldn't associate to domain\n");
> +                       return ret;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +static int adi_gpio_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       const struct adi_pinctrl_gpio_platform_data *pdata;
> +       struct resource *res;
> +       struct gpio_port *port;
> +       static int gpio;
> +       int ret = 0;
> +
> +       pdata = dev->platform_data;
> +       if (!pdata)
> +               return -EINVAL;
> +
> +       port = devm_kzalloc(dev, sizeof(struct gpio_port) +
> +               sizeof(struct gpio_reserve_map) * pdata->port_width,
> +               GFP_KERNEL);
> +       if (!port) {
> +               dev_err(dev, "Memory alloc failed\n");
> +               return -ENOMEM;
> +       }
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       if (unlikely(!res)) {

Get rid of all unlikely() in probe().

> +               dev_err(dev, "Invalid mem resource\n");
> +               return -ENODEV;
> +       }
> +
> +       if (!devm_request_mem_region(dev, res->start, resource_size(res),
> +                                    pdev->name)) {
> +               dev_err(dev, "Region already claimed\n");
> +               return -EBUSY;
> +       }
> +
> +       port->base = devm_ioremap(dev, res->start, resource_size(res));
> +       if (!port->base) {
> +               dev_err(dev, "Could not ioremap\n");
> +               return -ENOMEM;
> +       }
> +
> +       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> +       if (unlikely(!res))
> +               port->irq_base = -1;
> +       else
> +               port->irq_base = res->start;
> +
> +       port->width = pdata->port_width;
> +       port->dev = dev;
> +       port->regs = (struct gpio_port_t *)port->base;
> +       port->pint_assign = !!pdata->pint_assign;
> +       port->pint_map = pdata->pint_map;
> +
> +       port->pint = find_gpio_pint(pdata->pint_id);
> +       if (port->pint) {
> +               ret = adi_gpio_init_int(port);
> +               if (ret)
> +                       return ret;
> +       }
> +
> +       port->pmx = find_pinctrl(pdata->pinctrl_id);

OK I see what you're trying to do.

Do you *really* need to tie the pinctrl and GPIO parts of the
driver together this hard? Why can't the GPIO part and the pinctrl
part probe by itself and then you can cross-reference using only
the GPIO ranges?

For example check the pinctrl-u300.c and pinctrl-coh901.c drivers.
They probe for the GPIO and pinctrl side independently.

To cross-reference from the pin controller to the GPIO controller
it uses pinctrl_find_gpio_range_from_pin() and then the
gpiochip there to call into the GPIO driver. Nice and clean.

Can you try this approach? Then you can even split the driver
in two parts (two files) if you like, but that's no requirement.

Another option is to create a single state struct for both GPIO
and pin control such as is done in the pinctrl-abx500.c driver.

> +       if (port->pmx == NULL) {
> +               dev_err(dev, "Could not find pinctrl device\n");
> +               return -ENODEV;
> +       }
> +       if (gpio == 0)
> +               gpio = port->pmx->gpio_base;
> +
> +       spin_lock_init(&port->lock);
> +
> +       platform_set_drvdata(pdev, port);
> +
> +       port->chip.label                = "adi-gpio";
> +       port->chip.direction_input      = adi_gpio_direction_input;
> +       port->chip.get                  = adi_gpio_get_value;
> +       port->chip.direction_output     = adi_gpio_direction_output;
> +       port->chip.set                  = adi_gpio_set_value;
> +       port->chip.request              = adi_gpio_request;
> +       port->chip.free                 = adi_gpio_free;
> +       port->chip.to_irq               = adi_gpio_to_irq;
> +       if (pdata->port_pin_base > 0)
> +               port->chip.base         = pdata->port_pin_base +
> +                                               port->pmx->gpio_base;
> +       else
> +               port->chip.base         = gpio;
> +       port->chip.ngpio                = port->width;
> +       gpio = port->chip.base + port->width;
> +
> +       ret = gpiochip_add(&port->chip);
> +       if (ret)
> +               return ret;
> +
> +       /* Set gpio range to pinctrl driver */
> +       port->range.name = port->chip.label;
> +       port->range.id = pdev->id;
> +       port->range.base = port->chip.base;
> +       port->range.pin_base = port->chip.base - port->pmx->gpio_base;
> +       port->range.npins = port->width;
> +       port->range.gc = &port->chip;
> +       pinctrl_add_gpio_range(port->pmx->pctl, &port->range);

No, don't do this from the pinctrl interface.

Use
gpiochip_add_pin_range() from the <linux/gpio.h> interface
instead. That will make everything simpler and cleaner,
and will illustrate why you want to get rid of the cross-dependence
between the pinctrl and GPIO portions of the driver.

> +       list_add_tail(&port->node, &port->pmx->gpio_list);
> +
> +       return 0;
> +}
> +
> +static int adi_gpio_remove(struct platform_device *pdev)
> +{
> +       struct gpio_port *port = platform_get_drvdata(pdev);
> +       int ret;
> +       u8 offset;
> +
> +       for (offset = 0; offset < port->width; offset++)
> +               irq_dispose_mapping(irq_find_mapping(port->domain, offset));
> +
> +       irq_domain_remove(port->domain);
> +       pinctrl_remove_gpio_range(port->pmx->pctl, &port->range);

No, just use:
gpiochip_remove_pin_ranges()

on the chip.

> +       list_del(&port->node);
> +       ret = gpiochip_remove(&port->chip);
> +       platform_set_drvdata(pdev, NULL);
> +
> +       return ret;
> +}
> +
> +static int adi_pinctrl_probe(struct platform_device *pdev)
> +{
> +       struct adi_pmx *pmx;
> +       struct resource *res;
> +
> +       pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
> +       if (!pmx)
> +               return -ENOMEM;
> +
> +       pmx->dev = &pdev->dev;
> +
> +       /* Now register the pin controller and all pins it handles */
> +       pmx->pctl = pinctrl_register(&adi_pinmux_desc, &pdev->dev, pmx);
> +       if (!pmx->pctl) {
> +               dev_err(&pdev->dev, "could not register pinctrl ADI2 driver\n");
> +               return -EINVAL;
> +       }
> +
> +       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
> +       if (res)
> +               pmx->gpio_base = res->start;
> +
> +       INIT_LIST_HEAD(&pmx->gpio_list);

And here is where you'r initialized the static local lock for this list.

> +
> +       list_add_tail(&pmx->node, &adi_pinctrl_list);
> +
> +       return 0;
> +}
> +
> +static int adi_pinctrl_remove(struct platform_device *pdev)
> +{
> +       struct adi_pmx *pmx = platform_get_drvdata(pdev);
> +
> +       list_del(&pmx->node);
> +       pinctrl_unregister(pmx->pctl);
> +       platform_set_drvdata(pdev, NULL);

As mentioned, this setting NULL is superfluous.

> +
> +       return 0;
> +}
> +
> +static struct platform_driver adi_pinctrl_driver = {
> +       .probe          = adi_pinctrl_probe,
> +       .remove         = adi_pinctrl_remove,
> +       .driver         = {
> +               .name   = DRIVER_NAME,
> +       },
> +};
> +
> +static struct platform_driver adi_gpio_pint_driver = {
> +       .probe          = adi_gpio_pint_probe,
> +       .remove         = adi_gpio_pint_remove,
> +       .driver         = {
> +               .name   = "adi-gpio-pint",
> +       },
> +};
> +
> +static struct platform_driver adi_gpio_driver = {
> +       .probe          = adi_gpio_probe,
> +       .remove         = adi_gpio_remove,
> +       .driver         = {
> +               .name   = "adi-gpio",
> +       },
> +};
> +
> +static int __init adi_pinctrl_setup(void)
> +{
> +       int ret;
> +
> +       ret = platform_driver_register(&adi_pinctrl_driver);
> +       if (ret)
> +               return ret;
> +
> +       ret = platform_driver_register(&adi_gpio_pint_driver);
> +       if (ret)
> +               goto pint_error;
> +
> +       ret = platform_driver_register(&adi_gpio_driver);
> +       if (ret)
> +               goto gpio_error;
> +
> +#ifdef CONFIG_PM
> +       register_syscore_ops(&gpio_pm_syscore_ops);
> +#endif
> +       return ret;
> +gpio_error:
> +       platform_driver_unregister(&adi_gpio_pint_driver);
> +pint_error:
> +       platform_driver_unregister(&adi_pinctrl_driver);
> +
> +       return ret;
> +}
> +postcore_initcall(adi_pinctrl_setup);

Why does this need to be postcore?

> +++ b/include/linux/platform_data/pinctrl-adi2.h
> @@ -0,0 +1,38 @@
> +/*
> + * Pinctrl Driver for ADI GPIO2 controller
> + *
> + * Copyright 2007-2013 Analog Devices Inc.
> + *
> + * Licensed under the GPLv2 or later
> + */
> +
> +
> +#ifndef PINCTRL_ADI2_H
> +#define PINCTRL_ADI2_H
> +
> +#include <linux/io.h>
> +#include <linux/platform_device.h>
> +
> +/**
> + * struct adi_pinctrl_gpio_platform_data - Pinctrl gpio platform data
> + * for ADI GPIO2 device.
> + *
> + * @port_pin_base: Optional global GPIO index of the GPIO bank.
> + *                 0 means driver decides.
> + * @port_width: PIN number of the GPIO bank device
> + * @pint_id: GPIO PINT device id that this GPIO bank should map to.
> + * @pint_assign: The 32-bit GPIO PINT registers can be divided into 2 parts. A
> + *               GPIO bank can be mapped into either low 16 bits[0] or high 16
> + *               bits[1] of each PINT register.
> + * @pint_map: GIOP bank mapping code in PINT device
> + */
> +struct adi_pinctrl_gpio_platform_data {
> +       unsigned int port_pin_base;
> +       unsigned int port_width;
> +       u8 pinctrl_id;
> +       u8 pint_id;
> +       u8 pint_assign;

Is this always 0 or 1? Then you should instead have a bool
named bool is_high; or something.

> +       u8 pint_map;
> +};

I'm sorry that there are many issues with this driver and it takes me time
to review because it is not very much like other drivers, especially I think
you need to understand how other drivers cross-reference using ranges
and how to get rid of the two lists and the strange locking.

Yours,
Linus Walleij

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

* Re: [PATCH 2/3] blackfin: gpio: Remove none gpio lib code.
  2013-07-16 10:55 ` [PATCH 2/3] blackfin: gpio: Remove none gpio lib code Sonic Zhang
  2013-07-23  7:33   ` Sonic Zhang
  2013-07-26  4:57   ` Sonic Zhang
@ 2013-08-14 15:34   ` Linus Walleij
  2 siblings, 0 replies; 17+ messages in thread
From: Linus Walleij @ 2013-08-14 15:34 UTC (permalink / raw)
  To: Sonic Zhang
  Cc: Grant Likely, Steven Miao, LKML, buildroot-devel,
	adi-buildroot-devel, Sonic Zhang

On Tue, Jul 16, 2013 at 12:55 PM, Sonic Zhang <sonic.adi@gmail.com> wrote:

> From: Sonic Zhang <sonic.zhang@analog.com>
>
> - Remove non gpio lib code from blackfin architecture.
> - Limit the lagecy blackfin gpio driver to bf5xx processors only.
> - Remove unused definition of the pint power functions.
>
> Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>

This seems fine.
Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

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

* Re: [PATCH 3/3] blackfin: pinctrl-adi2: Add pin control device groups and function data.
  2013-07-16 10:55 ` [PATCH 3/3] blackfin: pinctrl-adi2: Add pin control device groups and function data Sonic Zhang
  2013-07-23  7:33   ` Sonic Zhang
  2013-07-26  4:58   ` Sonic Zhang
@ 2013-08-14 15:39   ` Linus Walleij
  2 siblings, 0 replies; 17+ messages in thread
From: Linus Walleij @ 2013-08-14 15:39 UTC (permalink / raw)
  To: Sonic Zhang
  Cc: Grant Likely, Steven Miao, LKML, buildroot-devel,
	adi-buildroot-devel, Sonic Zhang

On Tue, Jul 16, 2013 at 12:55 PM, Sonic Zhang <sonic.adi@gmail.com> wrote:

> From: Sonic Zhang <sonic.zhang@analog.com>
>
> Select PINCTRL_ADI2 for bf54x and bf60x by default.
>
> Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>

(...)
> +++ b/arch/blackfin/mach-bf548/include/mach/portmux.h
(...)
> +static const struct pinctrl_pin_desc adi_pads[] = {
> +       PINCTRL_PIN(0, "PA0"),
> +       PINCTRL_PIN(1, "PA1"),
> +       PINCTRL_PIN(2, "PA2"),
> +       PINCTRL_PIN(3, "PG3"),

The pattern we follow is not to pass the information about pins in a certain
SoC or package as platform data.

Instead we rely on plug-in subdrivers down in the pinctrl subsystem under
drivers/pinctrl/*.

Nominally you should write a central blackfind pinctrl driver such
as drivers/pinctrl/pinctrl-blackfin.c then have a local header such
as drivers/pinctrl/pinctrl-blackfin.h that enable SoC sub-drivers
such as drivers/pinctrl/pinctrl-blackfin-bf54x.c, pinctrl-blackfin-bf60f.c
to register to that.

Please read the current drivers such as pinctrl-nomadik.c
and pinctrl-nomadik-db8500.c for an idea of how this
plugin concept works.

In short: move all this data down into pinctrl.

Yours,
Linus Walleij

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

* Re: [PATCH 1/3] pinctrl: ADI PIN control driver for the GPIO controller on bf54x and bf60x.
  2013-08-14 13:47 ` Linus Walleij
@ 2013-08-16  6:23   ` Sonic Zhang
  0 siblings, 0 replies; 17+ messages in thread
From: Sonic Zhang @ 2013-08-16  6:23 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Greg KH, Grant Likely, Steven Miao, LKML, buildroot-devel,
	adi-buildroot-devel, Sonic Zhang

()Hi Linus,



On Wed, Aug 14, 2013 at 9:47 PM, Linus Walleij <linus.walleij@linaro.org> wrote:
> i Sonic,
>
> sorry for taking so long before reviewing this, I was on vacation and
> had various urgent things to take care of.

Thank you for your time.

>
> On Tue, Jul 16, 2013 at 12:55 PM, Sonic Zhang <sonic.adi@gmail.com> wrote:
>
>> From: Sonic Zhang <sonic.zhang@analog.com>
>>
>> The new ADI GPIO2 controller was introduced since the BF548 and BF60x
>> processors. It differs a lot from the old one on BF5xx processors. So,
>> create a pinctrl driver under pinctrl framework.
>>
>> - Define gpio ports and gpio interrupt controllers as individual platform
>> devices.
>> - Register a pinctrl driver for the whole GPIO ports and GPIO interrupt
>> devices.
>> - Probe pint devices before port devices. Put device instances into
>> respective gpio and pint lists.
>> - Define peripheral, irq and gpio reservation bit masks for each gpio
>> port as runtime resources.
>> - Save and restore gpio port and pint status MMRs in syscore PM functions.
>> - Add peripheral device groups and function data into machine portmux.h.
>> - Handle peripheral and gpio requests in pinctrl operation functions.
>> - Demux gpio IRQs via the irq_domain created by each GPIO port.
>>
>> Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
>
> OK...
>
>> +++ b/drivers/pinctrl/pinctrl-adi2.c
>> @@ -0,0 +1,1545 @@
>> +/*
>> + * Pinctrl Driver for ADI GPIO2 controller
>> + *
>> + * Copyright 2007-2013 Analog Devices Inc.
>> + *
>> + * Licensed under the GPLv2 or later
>> + */
>> +
>> +#include <linux/delay.h>
>> +#include <linux/module.h>
>> +#include <linux/err.h>
>> +#include <linux/proc_fs.h>
>> +#include <linux/seq_file.h>
>> +#include <linux/irq.h>
>> +#include <linux/platform_data/pinctrl-adi2.h>
>> +#include <linux/irqdomain.h>
>> +#include <linux/irqchip/chained_irq.h>
>> +#include <linux/pinctrl/pinctrl.h>
>> +#include <linux/pinctrl/pinmux.h>
>> +#include <linux/pinctrl/consumer.h>
>> +#include <linux/pinctrl/machine.h>
>> +#include <linux/syscore_ops.h>
>> +#include <linux/gpio.h>
>> +#include <asm/portmux.h>
>> +#include "core.h"
>> +
>> +static LIST_HEAD(adi_pint_list);
>> +static LIST_HEAD(adi_pinctrl_list);
>
> No locks? It seems you getting this all wrong, defining
> locks inside the per-instance structs for these lists. That is
> not going to protect anything from concurrent use.
>
> Use static local locks right here for the lists instead.

These 2 lists are only increased in the device probe stage. There is
no concurrent use issue in this stage. And because they are not
changed any more after the probe stage, it is not necessary to lock
the list finding operation as well.


>
>> +
>> +#define PERIPHERAL_USAGE 1
>> +#define GPIO_USAGE 0
>> +
>> +#define DRIVER_NAME "pinctrl-adi2"
>> +
>> +#define RESOURCE_LABEL_SIZE    16
>> +#define PINT_HI_OFFSET         16
>> +
>> +#define RSV_NONE       0
>> +#define RSV_GPIO       1
>> +#define RSV_INT                2
>> +#define RSV_PERI       3
>> +
>> +/**
>> + * struct gpio_reserve_map - a GPIO map structure containing the
>> + * reservation status of each PIN.
>> + *
>> + * @owner: who request the reservation
>> + * @rsv_gpio: if this pin is reserved as GPIO
>> + * @rsv_int: if this pin is reserved as interrupt
>> + * @rsv_peri: if this pin is reserved as part of a peripheral device
>> + */
>> +struct gpio_reserve_map {
>> +       unsigned char owner[RESOURCE_LABEL_SIZE];
>> +       bool rsv_gpio;
>> +       bool rsv_int;
>> +       bool rsv_peri;
>> +};
>
> Hm if a pin is us used for interrupts is it not also used
> for GPIO at the same time?
>

The interrupt pin is requested and reserved in irq_chip operation
irq_set_type() other than gpio_request(). In Blackfin, one gpio pin is
allowed to be set up as both gpio interrupt and gpio input. So, we
need bits to differentiate them.

> I don't understand why you want to keep track of this stuff,
> basically the kernel frameworks are already abstracting
> this but I guess there is some good reason for this.
>
>> +/**
>> + * struct gpio_port_saved - GPIO port registers that should be saved between
>> + * power suspend and resume operations.
>> + *
>> + * @fer: PORTx_FER register
>> + * @data: PORTx_DATA register
>> + * @dir: PORTx_DIR register
>> + * @inen: PORTx_INEN register
>> + * @mux: PORTx_MUX register
>> + */
>> +struct gpio_port_saved {
>> +       u16 fer;
>> +       u16 data;
>> +       u16 dir;
>> +       u16 inen;
>> +       u32 mux;
>> +};
>
> Seem straight-forward.
>
>> +/**
>> + * struct gpio_pint - GPIO interrupt controller device. Multiple ADI GPIO
>> + * banks can be mapped into one GPIO interrupt controller.
>> + *
>> + * @node: All gpio_pint instances are added to a global list.
>
> Why? Usually we make drivers self-contained per instance, no need
> for one driver instance to know about all the others.

Because the pint device is independent from the GPIO port device. The
GPIO port device finds out which pint device it should route to in its
probe stage. So, the pint devices should be probed and added to the
pint list before the GPIO port devices are probed. Yes, after the
probe stage, GPIO port device knows nothing of the other pint device.

>
>> + * @base: GPIO PINT device register base address
>> + * @irq: IRQ of the GPIO PINT device, it is the parent IRQ of all
>> + *       GPIO IRQs mapping to this device.
>> + * @domain: [0] irq domain of the gpio port, whose hardware interrupts are
>> + *             mapping to the low 16-bit of the pint registers.
>> + *          [1] irq domain of the gpio port, whose hardware interrupts are
>> + *             mapping to the high 16-bit of the pint registers.
>> + * @regs: address pointer to the GPIO PINT device> +
>
>
> What is this struct gpio_pint_regs? I tried to grep the kernel for it:
> zero hits. Is this some way to pass the physical address or something?
> Anyway you need to merge the code introducing this struct *first*
> since it is not before this patch I guess this patch set is not based
> on the mainline Linux kernel...

struct gpio_pint_regs can be found in [patch 3/3] blackfin:
pinctrl-adi2: Add pin control device groups and function data.

>
> What is a "pint"? It doesn't seem to be a "port interrupt" or anything
> like that....
>
> This is what it means to most:
> http://en.wikipedia.org/wiki/Pint

According to the BF54x HRM, pint means "pin interrupt".
http://www.analog.com/static/imported-files/processor_manuals/ADSP-BF54x_hwr_rev1.2.pdf

ADSP-BF54x processor Blackfin processors have four SIC interrupt chan-
nels dedicated to pin interrupt purposes. These channels are managed by
four hardware blocks, called PINT0, PINT1, PINT2, and PINT3. Every PINTx
block can sense to up to 32 pins. While PINT0 and PINT1 can sense the
pins of port A and port B, PINT2 and PINT3 manage all the pins from port
C to port J as shown in Figure 9-2.



>
>> + * @map_count: No more than 2 GPIO banks can be mapped to this PINT device.
>
> Why? Explain here what it means to "map a GPIO bank to a  PINT device".

In BF54x HRM:
The ten GPIO ports are subdivided into 8-bit half ports, resulting in lower and
upper half 8-bit units. The PINTx_ASSIGN registers control the 8-bit multi-
plexers shown in Figure 9-3. Lower half units of eight pins can be
forwarded to either byte 0 or byte 2 of either associated PINTx block.
Upper half units can be forwarded to either byte 1 or byte 3 of the pin
interrupt blocks, without further restrictions.

All MMR registers in the pin interrupt module are 32 bits wide. To
simply the mapping logic, this driver only maps a 16-bit gpio port to
the upper or lower 16 bits of a PINTx block. You can find the Figure
9-3 on page 583.


>
>> + * @lock: This lock make sure the irq_chip operations to one GPIO PINT device
>> + *        for different GPIO interrrupts are atomic.
>> + * @pint_map_port: Set up the mapping between one GPIO PINT device and
>> + *                 multiple GPIO banks.
>
> I don't realize why you need a function pointer for this, and why it needs to be
> in this local state container, but I'll read on...
>
>> + */
>> +struct gpio_pint {
>> +       struct list_head node;
>> +       void __iomem *base;
>> +       int irq;
>> +       struct irq_domain *domain[2];
>> +       struct gpio_pint_regs *regs;
>> +       struct adi_pm_pint_save saved_data;
>> +       int map_count;
>> +       spinlock_t lock;
>> +
>> +       int (*pint_map_port)(struct gpio_pint *pint, u8 assign,
>> +                               u8 map, struct irq_domain *domain);
>> +};
>> +
>> +/**
>> + * ADI pin controller
>
>
>> + *
>> + * @node: All adi_pmx instances are added to a global list.
>> + * @dev: a pointer back to containing device
>> + * @pctl: the pinctrl device
>> + * @gpio_list: the list of gpio banks owned by this pin controller.
>> + * @gpio_base: the base gpio number of this pin controller.
>
> This looks like you are re-implementing the GPIO ranges that we
> already have in the pinctrl subsystem. Please look at the other
> drivers and try to use the same style and common infrastructure.
> The GPIO ranges are also well documented in Documentation/pinctrl.txt
>

In order to keep GPIO number consistent with BF5xx driver, the
gpio_base is used to initialize the GPIO ranges according to the
predefined GPIO numbers in platform data struct. This is for backward
compatibility in Blackfin architecture.

>> + */
>> +struct adi_pmx {
>
> If it is a pin controller... then rename it adi_pinctrl.

OK

>
>> +       struct list_head node;
>> +       struct device *dev;
>> +       struct pinctrl_dev *pctl;
>> +       struct list_head gpio_list;
>> +       unsigned long gpio_base;
>> +};
>> +
>> +/**
>> + * struct gpio_pint - GPIO bank device. Multiple ADI GPIO banks can be mapped
>
> pint? Port? The struct is named port...
>
> Please check this in the entire file.
>

OK

>> + * into one GPIO interrupt controller.
>> + *
>> + * @node: All gpio_pint instances are added to a list.
>> + * @base: GPIO bank device register base address
>> + * @pin_base: base global GPIO pin index of the GPIO bank device
>
> I think this is another aspect of reimplementing GPIO ranges.

No, this pin_base variable is not used after move to GPIO ranges. I
will remove it.

>
>> + * @irq_base: base IRQ of the GPIO bank device
>> + * @width: PIN number of the GPIO bank device
>> + * @range: The range space of the GPIO bank handled by the pin controller.
>> + * @regs: address pointer to the GPIO bank device
>> + * @saved_data: registers that should be saved between PM operations.
>> + * @dev: device structure of this GPIO bank
>> + * @pmx: the pinctrl device
>> + * @pint: GPIO PINT device that this GPIO bank mapped to
>> + * @pint_map: GIOP bank mapping code in PINT device
>> + * @pint_assign: The 32-bit GPIO PINT registers can be divided into 2 parts. A
>> + *               GPIO bank can be mapped into either low 16 bits[0] or high 16
>> + *               bits[1] of each PINT register.
>
> Is this always 0 or 1? Then you should instead have a bool
> named bool is_high; or something.

OK

>
>> + * @lock: This lock make sure the irq_chip operations to one GPIO PINT device
>> + *        for different GPIO interrrupts are atomic.
>> + * @chip: abstract a GPIO controller
>> + * @domain: The irq domain owned by the GPIO port.
>
> Here seems to be many IRQ domains, this this really necessary?
>
> Two in "struct gpio_pint" and one more here? Why?

Each IRQ domain is binding to a GPIO bank device. 2 GPIO bank devices
can map to one PINT device. Two in "struct gpio_pint" are used to ease
the PINT interrupt handler.

The GPIO bank mapping to the lower 16 bits of the PINT device set its
IRQ domain pointer in domain[0]. The IRQ domain pointer of the other
bank is set to domain[1]. PINT interrupt handler
adi_gpio_handle_pint_irq() finds out the current domain pointer
according to whether the interrupt request mask is in lower 16 bits
(domain[0]) or upper 16bits (domain[1]).

>
> This seems very complex.
>
> I think you basically need to structure the code and add comments to
> the driver header so that it is chrystal clear why we have two abstractions
> named "pint" and "port" and how they relate to each other.

OK.

>
>> + * @rsvmap: Reservation map array for each pin in the GPIO bank
>> + */
>> +struct gpio_port {
>> +       struct list_head node;
>> +       void __iomem *base;
>> +       unsigned int pin_base;
>> +       unsigned int irq_base;
>> +       unsigned int width;
>> +       struct pinctrl_gpio_range range;
>
> Here you're finally using the GPIO ranges.
>
>> +       struct gpio_port_t *regs;
>
> Suffuxing things with _t, like it's a type, is hungarian notation
> and is not encouraged in the kernel... anyway I see this is
> already in the kernel so not your fault I guess.
>
>> +       struct gpio_port_saved saved_data;
>> +       struct device *dev;
>> +       struct adi_pmx *pmx;
>
> Can't you just make the members of this struct (adi_pmx)
> member of this struct and cut down on unnecessary structs?
>
>> +
>> +       struct gpio_pint *pint;
>> +       u8 pint_map;
>> +       u8 pint_assign;
>> +
>> +       spinlock_t lock;
>> +       struct gpio_chip chip;
>> +       struct irq_domain *domain;
>> +
>> +       struct gpio_reserve_map rsvmap[];
>
> And this reserve map.
>
>> +};
>
> What I do not understand is why you need gpio_pint?
>
> Usually this struct is all you need.

As I explained above, A PINT device is not part of a GPIO port device
in Blackfin. Multiple GPIO port devices can be mapped to the same PINT
device.

>
>> +static inline u8 pin_to_offset(struct pinctrl_gpio_range *range, unsigned pin)
>> +{
>> +       return pin - range->pin_base;
>> +}
>> +
>> +static inline unsigned offset_to_gpio(struct gpio_port *port, u8 offset)
>> +{
>> +       return offset + port->chip.base;
>> +}
>> +
>> +static inline u8 gpio_to_offset(struct gpio_port *port, unsigned gpio)
>> +{
>> +       return gpio - port->chip.base;
>> +}
>
> Hmmmm we need this kind of stuff to be done in the pinctrl core. Usually
> this should not be needed. Why do you need to do this?
>
>> +static inline unsigned hwirq_to_pintbit(struct gpio_port *port, int hwirq)
>
> Why is this unsigned? Isn't it really u32 or u16?

Should be u32.

>
>> +{
>> +       return (1 << hwirq) << (port->pint_assign * PINT_HI_OFFSET);
>
> Atleast do this:
>
> #include <linux/bitops.h>
>
> return BIT(hwirq) << (port->pint_assign * PINT_HI_OFFSET);
>
> If pin_assign is only 0 or 1 as I suspect, this is  very unelegant
> construction. Then I would prefer:
>
> return port->pint_assign ? BIT(offset) << PINT_HI_OFFSET : BIT(offset);
>
> or something like that where you can see what is going on.

OK

>
>> +static void set_label(struct gpio_port *port, unsigned offset,
>> +       const char *label)
>> +{
>> +       char *pch = port->rsvmap[offset].owner;
>> +
>> +       if (label) {
>> +               strncpy(pch, label, RESOURCE_LABEL_SIZE);
>> +               pch[RESOURCE_LABEL_SIZE - 1] = 0;
>> +       }
>> +}
>> +
>> +static char *get_label(struct gpio_port *port, unsigned offset)
>> +{
>> +       char *pch = port->rsvmap[offset].owner;
>> +
>> +       return *pch ? pch : "UNKNOWN";
>> +}
>
> Hm, OK ...
>
>> +static inline unsigned int is_reserved(struct gpio_port *port, char type,
>> +       unsigned offset)
>
> The return type should be bool should it not?
>
>> +{
>> +       switch (type) {
>> +       case RSV_GPIO:
>> +               return port->rsvmap[offset].rsv_gpio == true;
>> +       case RSV_INT:
>> +               return port->rsvmap[offset].rsv_int == true;
>> +       case RSV_PERI:
>> +               return port->rsvmap[offset].rsv_peri == true;
>> +       }
>
> For each of these just e.g.:
> return port->rsvmap[offset].rsv_gpio
>
> You're making this simple thing look very complicated.

OK

>
>> +
>> +       return 0;
>> +}
>> +
>> +static inline void reserve(struct gpio_port *port, char type, unsigned offset)
>> +{
>> +       switch (type) {
>> +       case RSV_GPIO:
>> +               port->rsvmap[offset].rsv_gpio = true;
>> +               break;
>> +       case RSV_INT:
>> +               port->rsvmap[offset].rsv_int = true;
>> +               break;
>> +       case RSV_PERI:
>> +               port->rsvmap[offset].rsv_peri = true;
>> +               break;
>> +       }
>> +}
>> +
>> +static inline void unreserve(struct gpio_port *port, char type, unsigned offset)
>> +{
>> +       switch (type) {
>> +       case RSV_GPIO:
>> +               port->rsvmap[offset].rsv_gpio = false;
>> +               break;
>> +       case RSV_INT:
>> +               port->rsvmap[offset].rsv_int = false;
>> +               break;
>> +       case RSV_PERI:
>> +               port->rsvmap[offset].rsv_peri = false;
>> +               break;
>> +       }
>> +}
>
> Having helper functions for these things seem a bit overdesigned
> actually. Do you really need them?

OK. I will remove them.

>
>> +static struct gpio_pint *find_gpio_pint(unsigned id)
>> +{
>> +       struct gpio_pint *pint;
>> +       int i = 0;
>> +
>> +       list_for_each_entry(pint, &adi_pint_list, node) {
>> +               if (id == i)
>> +                       break;
>
> Just return pint; here
>
>> +               i++;
>> +       }
>> +
>> +       if (&pint->node != &adi_pint_list)
>> +               return pint;
>
> And skip this super-confusing thing.
>
>> +       else
>> +               return NULL;
>> +}
>
> And just return NULL;

OK

>
>> +
>> +static struct adi_pmx *find_pinctrl(unsigned id)
>> +{
>> +       struct adi_pmx *pmx;
>> +       int i = 0;
>> +
>> +       list_for_each_entry(pmx, &adi_pinctrl_list, node) {
>> +               if (id == i)
>> +                       break;
>> +               i++;
>> +       }
>> +
>> +       if (&pmx->node != &adi_pinctrl_list)
>> +               return pmx;
>> +       else
>> +               return NULL;
>> +}
>
> Same comments.
>
> If you merge the pmx and gpio_port structs into one you
> will at least just need one of these functions.
>
> But I am suspecting that all this is unnecessary and you
> should be using something like container_of() instead.
>
> Do you know and understand the kernel container_of()
> abstraction pattern? Else please look at examples of how
> we use this.
>
>> +static struct gpio_port *find_gpio_port(unsigned pin,
>> +       struct list_head *gpio_list)
>> +{
>> +       struct gpio_port *port;
>> +
>> +       list_for_each_entry(port, gpio_list, node)
>> +               if (pin >= port->range.pin_base &&
>> +                       pin < port->range.pin_base + port->range.npins)
>> +                       break;
>> +
>> +       if (&port->node != gpio_list)
>> +               return port;
>> +       else
>> +               return NULL;
>> +}
>
> Same comments.

OK

>
>> +static inline void port_setup(struct gpio_port *port, unsigned offset,
>> +       unsigned short usage)
>
> Either usage should be an enum or you can replace it with a bool
> like bool use_for_gpio.

OK

>
>> +{
>> +       struct gpio_port_t *regs = port->regs;
>> +
>> +       if (usage == GPIO_USAGE)
>> +               writew(readw(&regs->port_fer) & ~(1 << offset),
>> +                       &regs->port_fer);
>
> Use BIT(offset)
>
> This &regs->ports_fer is really awkward but I guess all
> blackfin stuff is written that way?
>
>> +       else
>> +               writew(readw(&regs->port_fer) | (1 << offset), &regs->port_fer);
>
> Use BIT(offset)

OK

>
>> +}
>> +
>> +static inline void portmux_setup(struct gpio_port *port, unsigned offset,
>> +       unsigned short function)
>> +{
>> +       struct gpio_port_t *regs = port->regs;
>> +       u32 pmux;
>> +
>> +       pmux = readl(&regs->port_mux);
>> +
>> +       pmux &= ~(0x3 << (2 * offset));
>> +       pmux |= (function & 0x3) << (2 * offset);
>
> 0x3? why? 2*offset?
>
> Care to put in a comment on what is happening here?
> Like that we use 2 consecutive bits for setting function?

OK

>
>> +
>> +       writel(pmux, &regs->port_mux);
>> +}
>> +
>> +static inline u16 get_portmux(struct gpio_port *port, unsigned offset)
>> +{
>> +       struct gpio_port_t *regs = port->regs;
>> +       u32 pmux = readl(&regs->port_mux);
>> +
>> +       return pmux >> (2 * offset) & 0x3;
>
> Dito...
>
>> +}
>> +
>> +
>> +static void __adi_gpio_irq_prepare(struct gpio_port *port, unsigned offset)
>> +{
>> +       struct gpio_port_t *regs = port->regs;
>> +
>> +       port_setup(port, offset, GPIO_USAGE);
>> +
>> +       writew(1 << offset, &regs->dir_clear);
>
> BIT(offset)
>
>> +       writew(readw(&regs->inen) | (1 << offset), &regs->inen);
>
> etc.

OK

>
>> +}
>> +
>> +static int __adi_gpio_irq_request(struct gpio_port *port, unsigned offset,
>> +       const char *label)
>> +{
>> +       if (unlikely(is_reserved(port, RSV_PERI, offset))) {
>> +               if (system_state == SYSTEM_BOOTING)
>> +                       dump_stack();
>> +
>> +               dev_err(port->dev,
>> +                      "GPIO %d is already reserved as Peripheral by %s !\n",
>> +                       offset_to_gpio(port, offset), get_label(port, offset));
>> +               return -EBUSY;
>> +       }
>> +       if (unlikely(is_reserved(port, RSV_GPIO, offset)))
>> +               dev_err(port->dev,
>> +                       "GPIO %d is already reserved by %s!\n",
>> +                       offset_to_gpio(port, offset), get_label(port, offset));
>
> As mentioned get rid of unlikely() macros.
>
>> +
>> +       reserve(port, RSV_INT, offset);
>> +       set_label(port, offset, label);
>> +       port_setup(port, offset, GPIO_USAGE);
>> +
>> +       return 0;
>> +}
>> +
>> +static void __adi_gpio_irq_free(struct gpio_port *port, unsigned offset)
>> +{
>> +       if (unlikely(!is_reserved(port, RSV_INT, offset))) {
>> +               if (system_state == SYSTEM_BOOTING)
>> +                       dump_stack();
>> +
>> +               dev_err(port->dev, "GPIO %d wasn't requested!\n",
>> +                       offset_to_gpio(port, offset));
>> +               return;
>> +       }
>> +
>> +       unreserve(port, RSV_INT, offset);
>> +       set_label(port, offset, "free");
>> +}
>> +
>> +static void adi_gpio_ack_irq(struct irq_data *d)
>> +{
>> +       unsigned long flags;
>> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
>> +       struct gpio_pint_regs *regs = port->pint->regs;
>> +       unsigned pintbit = hwirq_to_pintbit(port, d->hwirq);
>> +
>> +       spin_lock_irqsave(&port->lock, flags);
>> +       spin_lock_irqsave(&port->pint->lock, flags);
>
> Taking two locks to ACK an IRQ is really inconvenient is it not?
>
> It also impacts performance.
>
> This is one reason you should try to get rid of excess
> structs in this driver.

As I explained above, these PINT and GPIO port structs can't be
merged. They are not one by one. And double locks are only required in
irq_chip operations. Portmux and GPIO operations only lock once in
GPIO port.

>
> If any or both locks are really locks for the lists, then make
> the static locals in the driver instead of part of the struct.

NO, these locks are not for the lists.

>
>> +
>> +       if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) {
>> +               if (readl(&regs->invert_set) & pintbit)
>> +                       writel(pintbit, &regs->invert_clear);
>> +               else
>> +                       writel(pintbit, &regs->invert_set);
>> +       }
>> +
>> +       writel(pintbit, &regs->request);
>> +
>> +       spin_unlock_irqrestore(&port->pint->lock, flags);
>> +       spin_unlock_irqrestore(&port->lock, flags);
>> +}
>> +
>> +static void adi_gpio_mask_ack_irq(struct irq_data *d)
>> +{
>> +       unsigned long flags;
>> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
>> +       struct gpio_pint_regs *regs = port->pint->regs;
>> +       unsigned pintbit = hwirq_to_pintbit(port, d->hwirq);
>> +
>> +       spin_lock_irqsave(&port->lock, flags);
>> +       spin_lock_irqsave(&port->pint->lock, flags);
>> +
>> +       if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) {
>> +               if (readl(&regs->invert_set) & pintbit)
>> +                       writel(pintbit, &regs->invert_clear);
>> +               else
>> +                       writel(pintbit, &regs->invert_set);
>> +       }
>> +
>> +       writel(pintbit, &regs->request);
>> +       writel(pintbit, &regs->mask_clear);
>> +
>> +       spin_unlock_irqrestore(&port->pint->lock, flags);
>> +       spin_unlock_irqrestore(&port->lock, flags);
>> +}
>> +
>> +static void adi_gpio_mask_irq(struct irq_data *d)
>> +{
>> +       unsigned long flags;
>> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
>> +       struct gpio_pint_regs *regs = port->pint->regs;
>> +
>> +       spin_lock_irqsave(&port->lock, flags);
>> +       spin_lock_irqsave(&port->pint->lock, flags);
>> +
>> +       writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_clear);
>> +
>> +       spin_unlock_irqrestore(&port->pint->lock, flags);
>> +       spin_unlock_irqrestore(&port->lock, flags);
>
> So like in a case like this taking two locks to write a single
> bit in a single register is starting to look a bit silly.
>
>> +}
>> +
>> +static void adi_gpio_unmask_irq(struct irq_data *d)
>> +{
>> +       unsigned long flags;
>> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
>> +       struct gpio_pint_regs *regs = port->pint->regs;
>> +
>> +       spin_lock_irqsave(&port->lock, flags);
>> +       spin_lock_irqsave(&port->pint->lock, flags);
>> +
>> +       writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_set);
>> +
>> +       spin_unlock_irqrestore(&port->pint->lock, flags);
>> +       spin_unlock_irqrestore(&port->lock, flags);
>> +}
>
> Dito.
>
>> +static unsigned int adi_gpio_irq_startup(struct irq_data *d)
>> +{
>> +       unsigned long flags;
>> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
>> +       struct gpio_pint_regs *regs = port->pint->regs;
>> +
>> +       if (!port) {
>> +               dev_err(port->dev, "GPIO IRQ %d :Not exist\n", d->irq);
>> +               return -ENODEV;
>> +       }
>> +
>> +       spin_lock_irqsave(&port->lock, flags);
>> +       spin_lock_irqsave(&port->pint->lock, flags);
>> +
>> +       __adi_gpio_irq_prepare(port, d->hwirq);
>> +       writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_set);
>> +
>> +       spin_unlock_irqrestore(&port->pint->lock, flags);
>> +       spin_unlock_irqrestore(&port->lock, flags);
>> +
>> +       return 0;
>> +}
>
> Dito.
>
>> +static void adi_gpio_irq_shutdown(struct irq_data *d)
>> +{
>> +       unsigned long flags;
>> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
>> +       struct gpio_pint_regs *regs = port->pint->regs;
>> +
>> +       spin_lock_irqsave(&port->lock, flags);
>> +       spin_lock_irqsave(&port->pint->lock, flags);
>> +
>> +       writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_clear);
>> +       __adi_gpio_irq_free(port, d->hwirq);
>> +
>> +       spin_unlock_irqrestore(&port->pint->lock, flags);
>> +       spin_unlock_irqrestore(&port->lock, flags);
>> +}
>
> Dito.
>
>> +static int adi_gpio_irq_type(struct irq_data *d, unsigned int type)
>> +{
>> +       unsigned long flags;
>> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
>> +       struct gpio_pint_regs *pint_regs = port->pint->regs;
>> +       unsigned pintmask;
>> +       unsigned int irq = d->irq;
>> +       int ret = 0;
>> +       char buf[16];
>> +
>> +       if (!port) {
>> +               dev_err(port->dev, "GPIO IRQ %d :Not exist\n", irq);
>> +               return -ENODEV;
>> +       }
>> +
>> +       pintmask = hwirq_to_pintbit(port, d->hwirq);
>> +
>> +       spin_lock_irqsave(&port->lock, flags);
>> +       spin_lock_irqsave(&port->pint->lock, flags);
>> +
>> +       if (type == IRQ_TYPE_PROBE)
>> +               type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
>
> What does this mean in practice? Add a comment explaining
> why you do this.

These are from bf5xx legacy gpio driver, I need checking with the
former developer.

>
>> +
>> +       if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
>> +                   IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
>> +               snprintf(buf, 16, "gpio-irq%d", irq);
>> +               ret = __adi_gpio_irq_request(port, d->hwirq, buf);
>> +               if (ret)
>> +                       goto out;
>> +       } else
>> +               goto out;
>> +
>> +       if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
>> +               /* low or falling edge denoted by one */
>> +               writel(pintmask, &pint_regs->invert_set);
>> +       else
>> +               /* high or rising edge denoted by zero */
>> +               writel(pintmask, &pint_regs->invert_clear);
>
> So one register to set and one to clear the flags, clever...
>
>> +       if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
>> +               if (gpio_get_value(offset_to_gpio(port, d->hwirq)))
>> +                       writel(pintmask, &pint_regs->invert_set);
>> +               else
>> +                       writel(pintmask, &pint_regs->invert_clear);
>> +       }
>
> Care to explain what's happening here? Some comment in the
> code?

These are from bf5xx legacy gpio driver, I need checking with the
former developer.


>
>> +       if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
>> +               writel(pintmask, &pint_regs->edge_set);
>> +               __irq_set_handler_locked(irq, handle_edge_irq);
>> +       } else {
>> +               writel(pintmask, &pint_regs->edge_clear);
>> +               __irq_set_handler_locked(irq, handle_level_irq);
>> +       }
>
> I think I understand this part.
>
>> +
>> +out:
>> +       spin_unlock_irqrestore(&port->pint->lock, flags);
>> +       spin_unlock_irqrestore(&port->lock, flags);
>> +
>> +       return ret;
>> +}
>> +
>> +#ifdef CONFIG_PM
>> +static int adi_gpio_set_wake(struct irq_data *d, unsigned int state)
>> +{
>> +       struct gpio_port *port = irq_data_get_irq_chip_data(d);
>> +
>> +       if (!port && !port->pint && port->pint->irq != d->irq)
>> +               return -EINVAL;
>
> Why are you using the && operator here?
>
> If port is NULL it will go on an dereference port->pint and have
> a NULL reference.
>
> Probably you meant to use ||.

Yes, typo.

>
>> +#ifndef SEC_GCTL
>> +       adi_internal_set_wake(port->pint->irq, state);
>> +#endif
>> +
>> +       return 0;
>> +}
>> +
>> +static int adi_pint_suspend(void)
>> +{
>> +       struct gpio_pint *pint;
>> +
>> +       list_for_each_entry(pint, &adi_pint_list, node) {
>> +               writel(0xffffffff, &pint->regs->mask_clear);
>> +               pint->saved_data.assign = readl(&pint->regs->assign);
>> +               pint->saved_data.edge_set = readl(&pint->regs->edge_set);
>> +               pint->saved_data.invert_set = readl(&pint->regs->invert_set);
>> +       }
>
> Will the wakeups really work if you clear all regs like this?

Yes, it works well on Blackfin.

>
>> +
>> +       return 0;
>> +}
>> +
>> +static void adi_pint_resume(void)
>> +{
>> +       struct gpio_pint *pint;
>> +
>> +       list_for_each_entry(pint, &adi_pint_list, node) {
>> +               writel(pint->saved_data.assign, &pint->regs->assign);
>> +               writel(pint->saved_data.edge_set, &pint->regs->edge_set);
>> +               writel(pint->saved_data.invert_set, &pint->regs->invert_set);
>> +       }
>> +}
>> +
>> +static int adi_gpio_suspend(void)
>> +{
>> +       struct adi_pmx *pmx;
>> +       struct gpio_port *port;
>> +
>> +       list_for_each_entry(pmx, &adi_pinctrl_list, node)
>> +               list_for_each_entry(port, &pmx->gpio_list, node) {
>> +                       port->saved_data.fer = readw(&port->regs->port_fer);
>> +                       port->saved_data.mux = readl(&port->regs->port_mux);
>> +                       port->saved_data.data = readw(&port->regs->data);
>> +                       port->saved_data.inen = readw(&port->regs->inen);
>> +                       port->saved_data.dir = readw(&port->regs->dir_set);
>> +               }
>> +
>> +       return adi_pint_suspend();
>> +}
>> +
>> +static void adi_gpio_resume(void)
>> +{
>> +       struct adi_pmx *pmx;
>> +       struct gpio_port *port;
>> +
>> +       adi_pint_resume();
>> +
>> +       list_for_each_entry(pmx, &adi_pinctrl_list, node)
>> +               list_for_each_entry(port, &pmx->gpio_list, node) {
>> +                       writel(port->saved_data.mux, &port->regs->port_mux);
>> +                       writew(port->saved_data.fer, &port->regs->port_fer);
>> +                       writew(port->saved_data.inen, &port->regs->inen);
>> +                       writew(port->saved_data.data & port->saved_data.dir,
>> +                                               &port->regs->data_set);
>> +                       writew(port->saved_data.dir, &port->regs->dir_set);
>> +               }
>> +
>> +}
>
> The four functions are doing much the same thing, can't you just
> merge the pint and port structs as mentioned elsewhere and make
> things a lot simpler that way?
>
>> +static struct syscore_ops gpio_pm_syscore_ops = {
>> +       .suspend = adi_gpio_suspend,
>> +       .resume = adi_gpio_resume,
>> +};
>> +#else /* CONFIG_PM */
>> +#define adi_gpio_set_wake NULL
>> +#endif /* CONFIG_PM */
>> +
>> +#ifdef CONFIG_IRQ_PREFLOW_FASTEOI
>> +static inline void preflow_handler(struct irq_desc *desc)
>> +{
>> +       if (desc->preflow_handler)
>> +               desc->preflow_handler(&desc->irq_data);
>> +}
>> +#else
>> +static inline void preflow_handler(struct irq_desc *desc) { }
>> +#endif
>> +
>> +static void adi_gpio_handle_pint_irq(unsigned int inta_irq,
>> +                       struct irq_desc *desc)
>> +{
>> +       u32 request;
>> +       u32 level_mask, hwirq;
>> +       int umask = 0;
>
> bool umask = false;

OK

>
>> +       struct gpio_pint *pint = irq_desc_get_handler_data(desc);
>> +       struct irq_chip *chip = irq_desc_get_chip(desc);
>> +       struct gpio_pint_regs *regs = pint->regs;
>> +       struct irq_domain *domain;
>> +
>> +       preflow_handler(desc);
>> +       chained_irq_enter(chip, desc);
>> +
>> +       request = readl(&regs->request);
>> +       level_mask = readl(&regs->edge_set) & request;
>> +
>> +       hwirq = 0;
>> +       domain = pint->domain[0];
>> +       while (request) {
>
> You probably want to re-read request in each iteration.
> What will happen if new bits are lit up as you process
> the IRQs otherwise?

The PINT interrupt PIN is masked when requested gpio interrupts are
under dispatch. New bits lit up will be handled in next PINT
interrupt.

>
>> +               if (hwirq == PINT_HI_OFFSET)
>> +                       domain = pint->domain[1];
>
> Why is that not hwirq >= PINT_HI_OFFSET?
> This will *only* be true for IRQ 16.

Yes, domain pointer needs to be changed only once at IRQ 16 when we go
through IRQ requests from bit 0 to bit 31.

>
>> +
>> +               if (request & 1) {
>> +                       if (level_mask & (1 << hwirq)) {
>
> BIT(hwirq)
>
>> +                               umask = 1;
>
> umask = true;

OK

>
>> +                               chained_irq_exit(chip, desc);
>> +                       }
>> +                       generic_handle_irq(irq_find_mapping(domain,
>> +                                       hwirq % PINT_HI_OFFSET));
>
> This was elegant, and not complicated as in other places.
>
>> +               }
>> +
>> +               hwirq++;
>> +               request >>= 1;
>> +       }
>> +
>> +       if (!umask)
>> +               chained_irq_exit(chip, desc);
>> +}
>> +
>> +static struct irq_chip adi_gpio_irqchip = {
>> +       .name = "GPIO",
>> +       .irq_ack = adi_gpio_ack_irq,
>> +       .irq_mask = adi_gpio_mask_irq,
>> +       .irq_mask_ack = adi_gpio_mask_ack_irq,
>> +       .irq_unmask = adi_gpio_unmask_irq,
>> +       .irq_disable = adi_gpio_mask_irq,
>> +       .irq_enable = adi_gpio_unmask_irq,
>> +       .irq_set_type = adi_gpio_irq_type,
>> +       .irq_startup = adi_gpio_irq_startup,
>> +       .irq_shutdown = adi_gpio_irq_shutdown,
>> +       .irq_set_wake = adi_gpio_set_wake,
>> +};
>> +
>> +
>> +static int adi_get_groups_count(struct pinctrl_dev *pctldev)
>> +{
>> +       return ARRAY_SIZE(adi_pin_groups);
>> +}
>> +
>> +static const char *adi_get_group_name(struct pinctrl_dev *pctldev,
>> +                                      unsigned selector)
>> +{
>> +       return adi_pin_groups[selector].name;
>> +}
>> +
>> +static int adi_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
>> +                              const unsigned **pins,
>> +                              unsigned *num_pins)
>> +{
>> +       *pins = adi_pin_groups[selector].pins;
>> +       *num_pins = adi_pin_groups[selector].num;
>> +       return 0;
>> +}
>> +
>> +static void adi_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
>> +                  unsigned offset)
>> +{
>> +       seq_puts(s, DRIVER_NAME);
>
> Can't you output some useful data here instead of just the driver name?
> You know the pin offset and everything, why not print the status of triggers,
> whether it is in GPIO mode, if it is flagged to be used as IRQ etc?

OK

>
>> +}
>> +
>> +static struct pinctrl_ops adi_pctrl_ops = {
>> +       .get_groups_count = adi_get_groups_count,
>> +       .get_group_name = adi_get_group_name,
>> +       .get_group_pins = adi_get_group_pins,
>> +       .pin_dbg_show = adi_pin_dbg_show,
>> +};
>> +
>> +static int adi_pinmux_request(struct pinctrl_dev *pctldev, unsigned pin)
>> +{
>> +       struct adi_pmx *pmx;
>> +       struct gpio_port *port;
>> +       unsigned long flags;
>> +       struct pin_desc *desc;
>> +       u8 offset;
>> +
>> +       pmx = pinctrl_dev_get_drvdata(pctldev);
>> +
>> +       port = find_gpio_port(pin, &pmx->gpio_list);
>> +       if (port == NULL) {
>> +               dev_err(pctldev->dev,
>> +                      "%s: Peripheral PIN %d doesn't exist!\n",
>> +                      __func__, pin);
>> +               return -ENODEV;
>> +       }
>> +
>> +       offset = pin_to_offset(&port->range, pin);
>> +       desc = radix_tree_lookup(&pctldev->pin_desc_tree, pin);
>> +
>> +       spin_lock_irqsave(&port->lock, flags);
>> +
>> +       /* If a pin can be muxed as either GPIO or peripheral, make
>> +        * sure it is not already a GPIO pin when we request it.
>> +        */
>> +       if (unlikely(is_reserved(port, RSV_GPIO, offset))) {
>> +               if (system_state == SYSTEM_BOOTING)
>> +                       dump_stack();
>> +               dev_err(pctldev->dev,
>> +                      "%s: Peripheral PIN %d is already reserved as GPIO by %s!\n",
>> +                      __func__, pin, get_label(port, offset));
>> +               spin_unlock_irqrestore(&port->lock, flags);
>> +               return -EBUSY;
>> +       }
>> +
>> +       if (unlikely(is_reserved(port, RSV_PERI, offset))) {
>> +               if (system_state == SYSTEM_BOOTING)
>> +                       dump_stack();
>> +               dev_err(pctldev->dev,
>> +                       "%s: Peripheral PIN %d is already reserved by %s!\n",
>> +                       __func__, pin, get_label(port, offset));
>> +               spin_unlock_irqrestore(&port->lock, flags);
>> +               return -EBUSY;
>> +       }
>
> Get rid of unlikely().
>
>> +
>> +       reserve(port, RSV_PERI, offset);
>> +       set_label(port, offset, desc->mux_owner);
>> +
>> +       spin_unlock_irqrestore(&port->lock, flags);
>> +
>> +       return 0;
>> +}
>> +
>> +static int adi_pinmux_free(struct pinctrl_dev *pctldev, unsigned pin)
>> +{
>> +       struct adi_pmx *pmx;
>> +       struct gpio_port *port;
>> +       unsigned long flags;
>> +       u8 offset;
>> +
>> +       pmx = pinctrl_dev_get_drvdata(pctldev);
>> +       port = find_gpio_port(pin, &pmx->gpio_list);
>> +       if (port == NULL)
>> +               return 0;
>> +
>> +       offset = pin_to_offset(&port->range, pin);
>> +
>> +       spin_lock_irqsave(&port->lock, flags);
>> +
>> +       if (unlikely(!is_reserved(port, RSV_PERI, offset))) {
>> +               spin_unlock_irqrestore(&port->lock, flags);
>> +               return 0;
>> +       }
>
> get rid of unlikely().
>
>> +
>> +       unreserve(port, RSV_PERI, offset);
>> +       set_label(port, offset, "free");
>> +
>> +       spin_unlock_irqrestore(&port->lock, flags);
>> +
>> +       return 0;
>> +}
>> +
>> +static int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector,
>> +       unsigned group)
>> +{
>> +       struct adi_pmx *pmx;
>> +       struct gpio_port *port;
>> +       unsigned long flags;
>> +       unsigned short *mux = (unsigned short *)adi_pmx_functions[selector].mux;
>> +       unsigned short gpio;
>> +
>> +       pmx = pinctrl_dev_get_drvdata(pctldev);
>> +
>> +       while (*mux) {
>> +               gpio = P_IDENT(*mux);
>> +
>> +               port = find_gpio_port(gpio - pmx->gpio_base, &pmx->gpio_list);
>> +               if (port == NULL) /* should not happen */
>> +                       continue;
>> +
>> +               spin_lock_irqsave(&port->lock, flags);
>> +
>> +               portmux_setup(port, gpio_to_offset(port, gpio),
>> +                                P_FUNCT2MUX(*mux));
>> +               port_setup(port, gpio_to_offset(port, gpio), PERIPHERAL_USAGE);
>> +               mux++;
>> +
>> +               spin_unlock_irqrestore(&port->lock, flags);
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static void adi_pinmux_disable(struct pinctrl_dev *pctldev, unsigned selector,
>> +       unsigned group)
>> +{
>> +       struct adi_pmx *pmx;
>> +       struct gpio_port *port;
>> +       unsigned long flags;
>> +       unsigned short *mux = (unsigned short *)adi_pmx_functions[selector].mux;
>> +       unsigned short gpio;
>> +
>> +       pmx = pinctrl_dev_get_drvdata(pctldev);
>> +
>> +       while (*mux) {
>> +               gpio = P_IDENT(*mux);
>> +
>> +               port = find_gpio_port(gpio - pmx->gpio_base, &pmx->gpio_list);
>> +               if (port == NULL) /* should not happen */
>> +                       continue;
>> +
>> +               spin_lock_irqsave(&port->lock, flags);
>> +
>> +               port_setup(port, gpio_to_offset(port, gpio), GPIO_USAGE);
>> +               mux++;
>> +
>> +               spin_unlock_irqrestore(&port->lock, flags);
>> +       }
>> +}
>> +
>> +static int adi_pinmux_get_funcs_count(struct pinctrl_dev *pctldev)
>> +{
>> +       return ARRAY_SIZE(adi_pmx_functions);
>> +}
>> +
>> +static const char *adi_pinmux_get_func_name(struct pinctrl_dev *pctldev,
>> +                                         unsigned selector)
>> +{
>> +       return adi_pmx_functions[selector].name;
>> +}
>> +
>> +static int adi_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
>> +                              const char * const **groups,
>> +                              unsigned * const num_groups)
>> +{
>> +       *groups = adi_pmx_functions[selector].groups;
>> +       *num_groups = adi_pmx_functions[selector].num_groups;
>> +       return 0;
>> +}
>> +
>> +static int adi_pinmux_request_gpio(struct pinctrl_dev *pctldev,
>> +       struct pinctrl_gpio_range *range, unsigned pin)
>> +{
>> +       struct adi_pmx *pmx;
>> +       struct gpio_port *port;
>> +       unsigned long flags;
>> +       u8 offset;
>> +
>> +       pmx = pinctrl_dev_get_drvdata(pctldev);
>> +       port = find_gpio_port(pin, &pmx->gpio_list);
>> +       if (port == NULL) {
>> +               dev_err(pctldev->dev,
>> +                      "%s: GPIO PIN %d doesn't exist!\n",
>> +                      __func__, pin);
>> +               return -ENODEV;
>> +       }
>> +
>> +       offset = pin_to_offset(&port->range, pin);
>> +
>> +       spin_lock_irqsave(&port->lock, flags);
>> +
>> +       if (unlikely(is_reserved(port, RSV_GPIO, offset))) {
>> +               if (system_state == SYSTEM_BOOTING)
>> +                       dump_stack();
>> +               dev_err(pctldev->dev,
>> +                       "GPIO %d is already reserved by %s !\n",
>> +                       offset_to_gpio(port, offset), get_label(port, offset));
>> +               spin_unlock_irqrestore(&port->lock, flags);
>> +               return -EBUSY;
>> +       }
>> +       if (unlikely(is_reserved(port, RSV_PERI, offset))) {
>> +               if (system_state == SYSTEM_BOOTING)
>> +                       dump_stack();
>> +               dev_err(pctldev->dev,
>> +                       "GPIO %d is already reserved as peripheral by %s !\n",
>> +                       offset_to_gpio(port, offset), get_label(port, offset));
>> +               spin_unlock_irqrestore(&port->lock, flags);
>> +               return -EBUSY;
>> +       }
>> +       if (unlikely(is_reserved(port, RSV_INT, offset))) {
>> +               dev_err(pctldev->dev,
>> +                       "GPIO %d is already reserved as gpio-irq!\n",
>> +                       offset_to_gpio(port, offset));
>> +       }
>
> Get rid of all unlikely().
>
>> +       reserve(port, RSV_GPIO, offset);
>> +       set_label(port, offset, port->chip.label);
>> +       port_setup(port, offset, GPIO_USAGE);
>> +
>> +       spin_unlock_irqrestore(&port->lock, flags);
>> +
>> +       return 0;
>> +}
>> +
>> +static void adi_pinmux_free_gpio(struct pinctrl_dev *pctldev,
>> +       struct pinctrl_gpio_range *range, unsigned pin)
>> +{
>> +       struct adi_pmx *pmx;
>> +       struct gpio_port *port;
>> +       unsigned long flags;
>> +       u8 offset;
>> +
>> +       pmx = pinctrl_dev_get_drvdata(pctldev);
>> +       port = find_gpio_port(pin, &pmx->gpio_list);
>> +       if (port == NULL)
>> +               return;
>> +
>> +       offset = pin_to_offset(&port->range, pin);
>> +
>> +       spin_lock_irqsave(&port->lock, flags);
>> +
>> +       if (unlikely(!is_reserved(port, RSV_GPIO, offset))) {
>> +               if (system_state == SYSTEM_BOOTING)
>> +                       dump_stack();
>> +
>> +               dev_err(pctldev->dev,
>> +                       "GPIO %d wasn't requested!\n",
>> +                       offset_to_gpio(port, offset));
>> +               spin_unlock_irqrestore(&port->lock, flags);
>> +               return;
>> +       }
>
> Dito.
>
>> +       unreserve(port, RSV_GPIO, offset);
>> +       set_label(port, offset, "free");
>> +
>> +       spin_unlock_irqrestore(&port->lock, flags);
>> +
>> +       return;
>> +}
>> +
>> +static struct pinmux_ops adi_pinmux_ops = {
>> +       .request = adi_pinmux_request,
>> +       .free = adi_pinmux_free,
>> +       .enable = adi_pinmux_enable,
>> +       .disable = adi_pinmux_disable,
>> +       .get_functions_count = adi_pinmux_get_funcs_count,
>> +       .get_function_name = adi_pinmux_get_func_name,
>> +       .get_function_groups = adi_pinmux_get_groups,
>> +       .gpio_request_enable = adi_pinmux_request_gpio,
>> +       .gpio_disable_free = adi_pinmux_free_gpio,
>> +};
>> +
>> +
>> +static struct pinctrl_desc adi_pinmux_desc = {
>> +       .name = DRIVER_NAME,
>> +       .pins = adi_pads,
>> +       .npins = ARRAY_SIZE(adi_pads),
>> +       .pctlops = &adi_pctrl_ops,
>> +       .pmxops = &adi_pinmux_ops,
>> +       .owner = THIS_MODULE,
>> +};
>> +
>> +static int adi_gpio_request(struct gpio_chip *chip, unsigned offset)
>> +{
>> +       struct gpio_port *port;
>> +
>> +       port = container_of(chip, struct gpio_port, chip);
>> +
>> +       return pinctrl_request_gpio(offset_to_gpio(port, offset));
>> +}
>> +
>> +static void adi_gpio_free(struct gpio_chip *chip, unsigned offset)
>> +{
>> +       struct gpio_port *port;
>> +
>> +       port = container_of(chip, struct gpio_port, chip);
>> +
>> +       pinctrl_free_gpio(offset_to_gpio(port, offset));
>> +}
>> +
>> +static int adi_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
>> +{
>> +       struct gpio_port *port;
>> +       unsigned long flags;
>> +
>> +       port = container_of(chip, struct gpio_port, chip);
>> +
>> +       spin_lock_irqsave(&port->lock, flags);
>> +
>> +       if (unlikely(!is_reserved(port, RSV_GPIO, offset))) {
>> +               dev_err(port->dev, "GPIO %d wasn't requested!\n",
>> +                       offset_to_gpio(port, offset));
>> +               spin_unlock_irqrestore(&port->lock, flags);
>> +               return -EINVAL;
>> +       }
>> +
>> +       writew(1 << offset, &port->regs->dir_clear);
>> +       writew(readw(&port->regs->inen) | (1 << offset), &port->regs->inen);
>
> BIT(offset) etc.

OK

>
>> +
>> +       spin_unlock_irqrestore(&port->lock, flags);
>> +
>> +       return 0;
>> +}
>> +
>> +static void adi_gpio_set_value(struct gpio_chip *chip, unsigned offset,
>> +       int value)
>> +{
>> +       struct gpio_port *port = container_of(chip, struct gpio_port, chip);
>> +       struct gpio_port_t *regs = port->regs;
>> +       unsigned long flags;
>> +
>> +       spin_lock_irqsave(&port->lock, flags);
>> +
>> +       if (value)
>> +               writew(1 << offset, &regs->data_set);
>> +       else
>> +               writew(1 << offset, &regs->data_clear);
>> +
>> +       spin_unlock_irqrestore(&port->lock, flags);
>> +}
>> +
>> +static int adi_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
>> +       int value)
>> +{
>> +       struct gpio_port *port = container_of(chip, struct gpio_port, chip);
>> +       struct gpio_port_t *regs = port->regs;
>> +       unsigned long flags;
>> +
>> +       spin_lock_irqsave(&port->lock, flags);
>> +
>> +       if (unlikely(!is_reserved(port, RSV_GPIO, offset))) {
>> +               dev_err(port->dev, "GPIO %d wasn't requested!\n",
>> +                       offset_to_gpio(port, offset));
>> +               spin_unlock_irqrestore(&port->lock, flags);
>> +               return -EINVAL;
>> +       }
>> +
>> +       writew(readw(&regs->inen) & ~(1 << offset), &regs->inen);
>> +       adi_gpio_set_value(chip, offset, value);
>> +       writew(1 << offset, &regs->dir_set);
>> +
>> +       spin_unlock_irqrestore(&port->lock, flags);
>> +
>> +       return 0;
>> +}
>> +
>> +static int adi_gpio_get_value(struct gpio_chip *chip, unsigned offset)
>> +{
>> +       struct gpio_port *port = container_of(chip, struct gpio_port, chip);
>> +       struct gpio_port_t *regs = port->regs;
>> +       unsigned long flags;
>> +       int ret;
>> +
>> +       spin_lock_irqsave(&port->lock, flags);
>> +
>> +       ret = 1 & (readw(&regs->data) >> offset);
>
> Use this construct:
>
> ret = !!(readw(&regs->data) & BIT(offset));

OK

>
>> +
>> +       spin_unlock_irqrestore(&port->lock, flags);
>> +
>> +       return ret;
>> +}
>> +
>> +static int adi_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
>> +{
>> +       struct gpio_port *port = container_of(chip, struct gpio_port, chip);
>> +
>> +       if (port->irq_base >= 0)
>> +               return irq_find_mapping(port->domain, offset);
>
> Why? Normally you want to create a mapping for everything
> here, and it doesn't hurt if you do it twice. Just use
>
> return irq_create_mapping(...);

In order to keep bf54x and bf60x gpio to irq mapping consistent with
the bf5xx driver, gpio pins should be mapped to the predefined IRQ in
function adi_gpio_init_int(). The irq_base is defined in platform data
struct.

    if (port->irq_base >= 0) {
        ret = irq_create_strict_mappings(port->domain, port->irq_base,
                    0, port->width);
        if (ret) {
            dev_err(port->dev, "Couldn't associate to domain\n");
            return ret;
        }
    }


>
>> +       else
>> +               return irq_create_mapping(port->domain, offset);
>> +}
>> +
>> +#if defined(CONFIG_PROC_FS)
>> +static inline unsigned short get_gpio_dir(struct gpio_port *port,
>> +       unsigned offset)
>> +{
>> +       struct gpio_port_t *regs = port->regs;
>> +
>> +       return 1 & (readw(&regs->dir_clear) >> offset);
>
> Use:
> return !!(readw(&regs->dir_clear) & BIT(offset));
>

OK

>> +static int gpio_proc_show(struct seq_file *m, void *v)
>> +{
>> +       int offset, irq, gpio;
>> +       struct adi_pmx *pmx;
>> +       struct gpio_port *port;
>> +
>> +       list_for_each_entry(pmx, &adi_pinctrl_list, node)
>> +       list_for_each_entry(port, &pmx->gpio_list, node)
>> +               for (offset = 0; offset < port->width; offset++) {
>> +                       irq = is_reserved(port, RSV_INT, offset);
>> +                       gpio = is_reserved(port, RSV_GPIO, offset);
>> +                       if (gpio || irq)
>> +                               seq_printf(m, "GPIO_%d: \t%s%s \t\tGPIO %s\n",
>> +                                       offset_to_gpio(port, offset),
>> +                                       get_label(port, offset),
>> +                                       (gpio && irq) ? " *" : "",
>> +                                       get_gpio_dir(port, offset) ?
>> +                                       "OUTPUT" : "INPUT");
>> +                       else if (is_reserved(port, RSV_PERI, offset))
>> +                               seq_printf(m, "GPIO_%d: \t%s \t\tPeripheral\n",
>> +                                       offset_to_gpio(port, offset),
>> +                                       get_label(port, offset));
>> +                       else
>> +                               continue;
>> +               }
>
> This double-list traversal is really awkward.
> Can't you just merge pint & port?
>
>> +
>> +       return 0;
>> +}
>> +
>> +static int gpio_proc_open(struct inode *inode, struct file *file)
>> +{
>> +       return single_open(file, gpio_proc_show, NULL);
>> +}
>> +
>> +static const struct file_operations gpio_proc_ops = {
>> +       .open           = gpio_proc_open,
>> +       .read           = seq_read,
>> +       .llseek         = seq_lseek,
>> +       .release        = single_release,
>> +};
>> +
>> +static __init int gpio_register_proc(void)
>> +{
>> +       struct proc_dir_entry *proc_gpio;
>> +
>> +       proc_gpio = proc_create("gpio", 0, NULL, &gpio_proc_ops);
>
> No way are you going to create a procfs file for this.
> Greg would get me for this. Use debugfs for this and make the
> code dependent on #ifdef CONFIG_DEBUG_FS.

OK

>
>> +       return proc_gpio == NULL;
>> +}
>> +device_initcall(gpio_register_proc);
>> +#endif
>> +
>> +static int adi_pint_map_port(struct gpio_pint *pint, u8 assign, u8 map,
>> +       struct irq_domain *domain)
>> +{
>> +       struct gpio_pint_regs *regs = pint->regs;
>> +
>> +       if (pint->map_count > 1)
>> +               return -EINVAL;
>> +
>> +       if (assign > 1)
>> +               return -EINVAL;
>> +
>> +       pint->map_count++;
>> +
>> +       writel((readl(&regs->assign) & (0xFFFF << !assign * PINT_HI_OFFSET)) |
>> +               (((map << 8) | map) << assign * PINT_HI_OFFSET), &regs->assign);
>
> Do you understand what is happening here? I don't.
>
> Care to break it down and explain it?

OK
    /* The map_mask of each gpio port is a 16-bit duplicate
     * of the 8-bit map. It can be set to either high 16 bits or low
     * 16 bits of the pint assignment register.
     */
    map_mask = (map << 8) | map;
    if (assign) {
        map_mask <<= PINT_HI_OFFSET;
        writel((readl(&regs->assign) & 0xFFFF) | map_mask,
            &regs->assign);
    } else
        writel((readl(&regs->assign) & 0xFFFF0000) | map_mask,
            &regs->assign);

>
>> +       pint->domain[assign] = domain;
>> +
>> +       return 0;
>> +}
>> +
>> +static int adi_gpio_pint_probe(struct platform_device *pdev)
>> +{
>> +       struct device *dev = &pdev->dev;
>> +       struct resource *res;
>> +       struct gpio_pint *pint;
>> +
>> +       pint = devm_kzalloc(dev, sizeof(struct gpio_pint), GFP_KERNEL);
>> +       if (!pint) {
>> +               dev_err(dev, "Memory alloc failed\n");
>> +               return -ENOMEM;
>> +       }
>> +
>> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +       if (unlikely(!res)) {
>
> Get rid of all these unlikely() macros in probe().
>
>> +               dev_err(dev, "Invalid mem resource\n");
>> +               return -ENODEV;
>> +       }
>> +
>> +       if (!devm_request_mem_region(dev, res->start, resource_size(res),
>> +                                    pdev->name)) {
>> +               dev_err(dev, "Region already claimed\n");
>> +               return -EBUSY;
>> +       }
>> +
>> +       pint->base = devm_ioremap(dev, res->start, resource_size(res));
>> +       if (!pint->base) {
>> +               dev_err(dev, "Could not ioremap\n");
>> +               return -ENOMEM;
>> +       }
>> +
>> +       pint->regs = (struct gpio_pint_regs *)pint->base;
>> +
>> +       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
>> +       if (unlikely(!res)) {
>> +               dev_err(dev, "Invalid IRQ resource\n");
>> +               return -ENODEV;
>> +       }
>> +
>> +       spin_lock_init(&pint->lock);
>> +
>> +       pint->irq = res->start;
>> +       pint->pint_map_port = adi_pint_map_port;
>> +       platform_set_drvdata(pdev, pint);
>> +
>> +       irq_set_chained_handler(pint->irq, adi_gpio_handle_pint_irq);
>> +       irq_set_handler_data(pint->irq, pint);
>> +
>> +       list_add_tail(&pint->node, &adi_pint_list);
>> +
>> +       return 0;
>> +}
>> +
>> +static int adi_gpio_pint_remove(struct platform_device *pdev)
>> +{
>> +       struct gpio_pint *pint = platform_get_drvdata(pdev);
>> +
>> +       list_del(&pint->node);
>> +       irq_set_handler(pint->irq, handle_simple_irq);
>> +       platform_set_drvdata(pdev, NULL);
>
> There is no need to set drvdata to NULL. This is done by the
> device core, so get rid of this line.

OK

>
>> +
>> +       return 0;
>> +}
>> +
>> +static int adi_gpio_irq_map(struct irq_domain *d, unsigned int irq,
>> +                               irq_hw_number_t hwirq)
>> +{
>> +       struct gpio_port *port = d->host_data;
>> +
>> +       if (!port)
>> +               return -EINVAL;
>> +
>> +       irq_set_chip_data(irq, port);
>> +       irq_set_chip_and_handler(irq, &adi_gpio_irqchip,
>> +                               handle_level_irq);
>> +
>> +       return 0;
>> +}
>> +
>> +const struct irq_domain_ops adi_gpio_irq_domain_ops = {
>> +       .map = adi_gpio_irq_map,
>> +       .xlate = irq_domain_xlate_onecell,
>> +};
>> +
>> +static int adi_gpio_init_int(struct gpio_port *port)
>> +{
>> +       struct device_node *node = port->dev->of_node;
>> +       struct gpio_pint *pint = port->pint;
>> +       int ret;
>> +
>> +       port->domain = irq_domain_add_linear(node, port->width,
>> +                               &adi_gpio_irq_domain_ops, port);
>> +       if (!port->domain) {
>> +               dev_err(port->dev, "Failed to create irqdomain\n");
>> +               return -ENOSYS;
>> +       }
>> +
>> +       ret = pint->pint_map_port(port->pint, port->pint_assign,
>> +                       port->pint_map, port->domain);
>> +       if (ret)
>> +               return ret;
>
> Explain what is happening here and how pints and ports relate.

OK

    /* According to BF54x and BF60x HRM, pin interrupt devices are not
     * part of the GPIO port device. in GPIO interrupt mode, the GPIO
     * pins of multiple port devices can be routed into one pin interrupt
     * devices. The mapping can be configured by setting pint assignment
     * register with the mapping value of different GPIO port. This is
     * done via function pint_map_port().
     */


>
>> +       if (port->irq_base >= 0) {
>> +               ret = irq_create_strict_mappings(port->domain, port->irq_base,
>> +                                       0, port->width);
>> +               if (ret) {
>> +                       dev_err(port->dev, "Couldn't associate to domain\n");
>> +                       return ret;
>> +               }
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int adi_gpio_probe(struct platform_device *pdev)
>> +{
>> +       struct device *dev = &pdev->dev;
>> +       const struct adi_pinctrl_gpio_platform_data *pdata;
>> +       struct resource *res;
>> +       struct gpio_port *port;
>> +       static int gpio;
>> +       int ret = 0;
>> +
>> +       pdata = dev->platform_data;
>> +       if (!pdata)
>> +               return -EINVAL;
>> +
>> +       port = devm_kzalloc(dev, sizeof(struct gpio_port) +
>> +               sizeof(struct gpio_reserve_map) * pdata->port_width,
>> +               GFP_KERNEL);
>> +       if (!port) {
>> +               dev_err(dev, "Memory alloc failed\n");
>> +               return -ENOMEM;
>> +       }
>> +
>> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +       if (unlikely(!res)) {
>
> Get rid of all unlikely() in probe().
>
>> +               dev_err(dev, "Invalid mem resource\n");
>> +               return -ENODEV;
>> +       }
>> +
>> +       if (!devm_request_mem_region(dev, res->start, resource_size(res),
>> +                                    pdev->name)) {
>> +               dev_err(dev, "Region already claimed\n");
>> +               return -EBUSY;
>> +       }
>> +
>> +       port->base = devm_ioremap(dev, res->start, resource_size(res));
>> +       if (!port->base) {
>> +               dev_err(dev, "Could not ioremap\n");
>> +               return -ENOMEM;
>> +       }
>> +
>> +       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
>> +       if (unlikely(!res))
>> +               port->irq_base = -1;
>> +       else
>> +               port->irq_base = res->start;
>> +
>> +       port->width = pdata->port_width;
>> +       port->dev = dev;
>> +       port->regs = (struct gpio_port_t *)port->base;
>> +       port->pint_assign = !!pdata->pint_assign;
>> +       port->pint_map = pdata->pint_map;
>> +
>> +       port->pint = find_gpio_pint(pdata->pint_id);
>> +       if (port->pint) {
>> +               ret = adi_gpio_init_int(port);
>> +               if (ret)
>> +                       return ret;
>> +       }
>> +
>> +       port->pmx = find_pinctrl(pdata->pinctrl_id);
>
> OK I see what you're trying to do.
>
> Do you *really* need to tie the pinctrl and GPIO parts of the
> driver together this hard? Why can't the GPIO part and the pinctrl
> part probe by itself and then you can cross-reference using only
> the GPIO ranges?
>
> For example check the pinctrl-u300.c and pinctrl-coh901.c drivers.
> They probe for the GPIO and pinctrl side independently.
>
> To cross-reference from the pin controller to the GPIO controller
> it uses pinctrl_find_gpio_range_from_pin() and then the
> gpiochip there to call into the GPIO driver. Nice and clean.
>
> Can you try this approach? Then you can even split the driver
> in two parts (two files) if you like, but that's no requirement.
>
> Another option is to create a single state struct for both GPIO
> and pin control such as is done in the pinctrl-abx500.c driver.

I will try the cross-reference via range APIs.

>
>> +       if (port->pmx == NULL) {
>> +               dev_err(dev, "Could not find pinctrl device\n");
>> +               return -ENODEV;
>> +       }
>> +       if (gpio == 0)
>> +               gpio = port->pmx->gpio_base;
>> +
>> +       spin_lock_init(&port->lock);
>> +
>> +       platform_set_drvdata(pdev, port);
>> +
>> +       port->chip.label                = "adi-gpio";
>> +       port->chip.direction_input      = adi_gpio_direction_input;
>> +       port->chip.get                  = adi_gpio_get_value;
>> +       port->chip.direction_output     = adi_gpio_direction_output;
>> +       port->chip.set                  = adi_gpio_set_value;
>> +       port->chip.request              = adi_gpio_request;
>> +       port->chip.free                 = adi_gpio_free;
>> +       port->chip.to_irq               = adi_gpio_to_irq;
>> +       if (pdata->port_pin_base > 0)
>> +               port->chip.base         = pdata->port_pin_base +
>> +                                               port->pmx->gpio_base;
>> +       else
>> +               port->chip.base         = gpio;
>> +       port->chip.ngpio                = port->width;
>> +       gpio = port->chip.base + port->width;
>> +
>> +       ret = gpiochip_add(&port->chip);
>> +       if (ret)
>> +               return ret;
>> +
>> +       /* Set gpio range to pinctrl driver */
>> +       port->range.name = port->chip.label;
>> +       port->range.id = pdev->id;
>> +       port->range.base = port->chip.base;
>> +       port->range.pin_base = port->chip.base - port->pmx->gpio_base;
>> +       port->range.npins = port->width;
>> +       port->range.gc = &port->chip;
>> +       pinctrl_add_gpio_range(port->pmx->pctl, &port->range);
>
> No, don't do this from the pinctrl interface.
>
> Use
> gpiochip_add_pin_range() from the <linux/gpio.h> interface
> instead. That will make everything simpler and cleaner,
> and will illustrate why you want to get rid of the cross-dependence
> between the pinctrl and GPIO portions of the driver.

OK

>
>> +       list_add_tail(&port->node, &port->pmx->gpio_list);
>> +
>> +       return 0;
>> +}
>> +
>> +static int adi_gpio_remove(struct platform_device *pdev)
>> +{
>> +       struct gpio_port *port = platform_get_drvdata(pdev);
>> +       int ret;
>> +       u8 offset;
>> +
>> +       for (offset = 0; offset < port->width; offset++)
>> +               irq_dispose_mapping(irq_find_mapping(port->domain, offset));
>> +
>> +       irq_domain_remove(port->domain);
>> +       pinctrl_remove_gpio_range(port->pmx->pctl, &port->range);
>
> No, just use:
> gpiochip_remove_pin_ranges()
>
> on the chip.

OK

>
>> +       list_del(&port->node);
>> +       ret = gpiochip_remove(&port->chip);
>> +       platform_set_drvdata(pdev, NULL);
>> +
>> +       return ret;
>> +}
>> +
>> +static int adi_pinctrl_probe(struct platform_device *pdev)
>> +{
>> +       struct adi_pmx *pmx;
>> +       struct resource *res;
>> +
>> +       pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
>> +       if (!pmx)
>> +               return -ENOMEM;
>> +
>> +       pmx->dev = &pdev->dev;
>> +
>> +       /* Now register the pin controller and all pins it handles */
>> +       pmx->pctl = pinctrl_register(&adi_pinmux_desc, &pdev->dev, pmx);
>> +       if (!pmx->pctl) {
>> +               dev_err(&pdev->dev, "could not register pinctrl ADI2 driver\n");
>> +               return -EINVAL;
>> +       }
>> +
>> +       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
>> +       if (res)
>> +               pmx->gpio_base = res->start;
>> +
>> +       INIT_LIST_HEAD(&pmx->gpio_list);
>
> And here is where you'r initialized the static local lock for this list.
>
>> +
>> +       list_add_tail(&pmx->node, &adi_pinctrl_list);
>> +
>> +       return 0;
>> +}
>> +
>> +static int adi_pinctrl_remove(struct platform_device *pdev)
>> +{
>> +       struct adi_pmx *pmx = platform_get_drvdata(pdev);
>> +
>> +       list_del(&pmx->node);
>> +       pinctrl_unregister(pmx->pctl);
>> +       platform_set_drvdata(pdev, NULL);
>
> As mentioned, this setting NULL is superfluous.

OK

>
>> +
>> +       return 0;
>> +}
>> +
>> +static struct platform_driver adi_pinctrl_driver = {
>> +       .probe          = adi_pinctrl_probe,
>> +       .remove         = adi_pinctrl_remove,
>> +       .driver         = {
>> +               .name   = DRIVER_NAME,
>> +       },
>> +};
>> +
>> +static struct platform_driver adi_gpio_pint_driver = {
>> +       .probe          = adi_gpio_pint_probe,
>> +       .remove         = adi_gpio_pint_remove,
>> +       .driver         = {
>> +               .name   = "adi-gpio-pint",
>> +       },
>> +};
>> +
>> +static struct platform_driver adi_gpio_driver = {
>> +       .probe          = adi_gpio_probe,
>> +       .remove         = adi_gpio_remove,
>> +       .driver         = {
>> +               .name   = "adi-gpio",
>> +       },
>> +};
>> +
>> +static int __init adi_pinctrl_setup(void)
>> +{
>> +       int ret;
>> +
>> +       ret = platform_driver_register(&adi_pinctrl_driver);
>> +       if (ret)
>> +               return ret;
>> +
>> +       ret = platform_driver_register(&adi_gpio_pint_driver);
>> +       if (ret)
>> +               goto pint_error;
>> +
>> +       ret = platform_driver_register(&adi_gpio_driver);
>> +       if (ret)
>> +               goto gpio_error;
>> +
>> +#ifdef CONFIG_PM
>> +       register_syscore_ops(&gpio_pm_syscore_ops);
>> +#endif
>> +       return ret;
>> +gpio_error:
>> +       platform_driver_unregister(&adi_gpio_pint_driver);
>> +pint_error:
>> +       platform_driver_unregister(&adi_pinctrl_driver);
>> +
>> +       return ret;
>> +}
>> +postcore_initcall(adi_pinctrl_setup);
>
> Why does this need to be postcore?

OK. I will change to arch_initcall().

>
>> +++ b/include/linux/platform_data/pinctrl-adi2.h
>> @@ -0,0 +1,38 @@
>> +/*
>> + * Pinctrl Driver for ADI GPIO2 controller
>> + *
>> + * Copyright 2007-2013 Analog Devices Inc.
>> + *
>> + * Licensed under the GPLv2 or later
>> + */
>> +
>> +
>> +#ifndef PINCTRL_ADI2_H
>> +#define PINCTRL_ADI2_H
>> +
>> +#include <linux/io.h>
>> +#include <linux/platform_device.h>
>> +
>> +/**
>> + * struct adi_pinctrl_gpio_platform_data - Pinctrl gpio platform data
>> + * for ADI GPIO2 device.
>> + *
>> + * @port_pin_base: Optional global GPIO index of the GPIO bank.
>> + *                 0 means driver decides.
>> + * @port_width: PIN number of the GPIO bank device
>> + * @pint_id: GPIO PINT device id that this GPIO bank should map to.
>> + * @pint_assign: The 32-bit GPIO PINT registers can be divided into 2 parts. A
>> + *               GPIO bank can be mapped into either low 16 bits[0] or high 16
>> + *               bits[1] of each PINT register.
>> + * @pint_map: GIOP bank mapping code in PINT device
>> + */
>> +struct adi_pinctrl_gpio_platform_data {
>> +       unsigned int port_pin_base;
>> +       unsigned int port_width;
>> +       u8 pinctrl_id;
>> +       u8 pint_id;
>> +       u8 pint_assign;
>
> Is this always 0 or 1? Then you should instead have a bool
> named bool is_high; or something.

OK

>
>> +       u8 pint_map;
>> +};
>
> I'm sorry that there are many issues with this driver and it takes me time
> to review because it is not very much like other drivers, especially I think
> you need to understand how other drivers cross-reference using ranges
> and how to get rid of the two lists and the strange locking.

I will try to do cross-reference by ranges between pinctrl and gpio
port. But, I am afraid these 2 lists can't be dropped, because the
GPIO power suspend and resume functions have to walk through the
lists. The GPIO PM functions should be called before any other device
drivers on Blackfin. This is ensured by registering to the syscore
operations. Any other options?

In addition, 2 type of locks are owned by 2 different devices. It is
strange to merge into one lock.

Thank you again for your great suggestion.


Sonic Zhang

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

end of thread, other threads:[~2013-08-16  6:23 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-07-16 10:55 [PATCH 1/3] pinctrl: ADI PIN control driver for the GPIO controller on bf54x and bf60x Sonic Zhang
2013-07-16 10:55 ` [PATCH 2/3] blackfin: gpio: Remove none gpio lib code Sonic Zhang
2013-07-23  7:33   ` Sonic Zhang
2013-07-26  4:57   ` Sonic Zhang
2013-08-14 15:34   ` Linus Walleij
2013-07-16 10:55 ` [PATCH 3/3] blackfin: pinctrl-adi2: Add pin control device groups and function data Sonic Zhang
2013-07-23  7:33   ` Sonic Zhang
2013-07-26  4:58   ` Sonic Zhang
2013-08-14 15:39   ` Linus Walleij
2013-07-23  7:32 ` [PATCH 1/3] pinctrl: ADI PIN control driver for the GPIO controller on bf54x and bf60x Sonic Zhang
2013-07-26  4:57 ` Sonic Zhang
2013-07-29 16:47   ` Linus Walleij
2013-08-01  7:31     ` Sonic Zhang
2013-08-07 18:56       ` Linus Walleij
2013-08-08  3:07         ` Sonic Zhang
2013-08-14 13:47 ` Linus Walleij
2013-08-16  6:23   ` Sonic Zhang

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.