pinctrl-adi2.c revision b81e57e6ac35242ba59206b303ba6c7585764ee1
1e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang/*
2e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * Pinctrl Driver for ADI GPIO2 controller
3e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang *
4e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * Copyright 2007-2013 Analog Devices Inc.
5e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang *
6e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * Licensed under the GPLv2 or later
7e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang */
8e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
9e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/bitops.h>
10e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/delay.h>
11e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/module.h>
12e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/err.h>
13e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/debugfs.h>
14e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/seq_file.h>
15e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/irq.h>
16e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/platform_data/pinctrl-adi2.h>
17e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/irqdomain.h>
18e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/irqchip/chained_irq.h>
19e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/pinctrl/pinctrl.h>
20e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/pinctrl/pinmux.h>
21e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/pinctrl/consumer.h>
22e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/pinctrl/machine.h>
23e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/syscore_ops.h>
24e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <linux/gpio.h>
25e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include <asm/portmux.h>
26e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include "pinctrl-adi2.h"
27e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#include "core.h"
28e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
29e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang/*
30e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangAccording to the BF54x HRM, pint means "pin interrupt".
31e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhanghttp://www.analog.com/static/imported-files/processor_manuals/ADSP-BF54x_hwr_rev1.2.pdf
32e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
33e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangADSP-BF54x processor Blackfin processors have four SIC interrupt chan-
34e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangnels dedicated to pin interrupt purposes. These channels are managed by
35e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangfour hardware blocks, called PINT0, PINT1, PINT2, and PINT3. Every PINTx
36e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangblock can sense to up to 32 pins. While PINT0 and PINT1 can sense the
37e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangpins of port A and port B, PINT2 and PINT3 manage all the pins from port
38e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangC to port J as shown in Figure 9-2.
39e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
40e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangn BF54x HRM:
41e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangThe ten GPIO ports are subdivided into 8-bit half ports, resulting in lower and
42e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangupper half 8-bit units. The PINTx_ASSIGN registers control the 8-bit multi-
43e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangplexers shown in Figure 9-3. Lower half units of eight pins can be
44e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangforwarded to either byte 0 or byte 2 of either associated PINTx block.
45e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangUpper half units can be forwarded to either byte 1 or byte 3 of the pin
46e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhanginterrupt blocks, without further restrictions.
47e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
48e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangAll MMR registers in the pin interrupt module are 32 bits wide. To simply the
49e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangmapping logic, this driver only maps a 16-bit gpio port to the upper or lower
50e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang16 bits of a PINTx block. You can find the Figure 9-3 on page 583.
51e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
52e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangEach IRQ domain is binding to a GPIO bank device. 2 GPIO bank devices can map
53e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangto one PINT device. Two in "struct gpio_pint" are used to ease the PINT
54e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhanginterrupt handler.
55e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
56e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangThe GPIO bank mapping to the lower 16 bits of the PINT device set its IRQ
57e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangdomain pointer in domain[0]. The IRQ domain pointer of the other bank is set
58e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangto domain[1]. PINT interrupt handler adi_gpio_handle_pint_irq() finds out
59e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangthe current domain pointer according to whether the interrupt request mask
60e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangis in lower 16 bits (domain[0]) or upper 16bits (domain[1]).
61e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
62e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangA PINT device is not part of a GPIO port device in Blackfin. Multiple GPIO
63e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangport devices can be mapped to the same PINT device.
64e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
65e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang*/
66e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
67e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic LIST_HEAD(adi_pint_list);
68e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic LIST_HEAD(adi_gpio_port_list);
69e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
70e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#define DRIVER_NAME "pinctrl-adi2"
71e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
72e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#define PINT_HI_OFFSET		16
73e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
74e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang/**
75e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * struct gpio_port_saved - GPIO port registers that should be saved between
76e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * power suspend and resume operations.
77e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang *
78e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @fer: PORTx_FER register
79e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @data: PORTx_DATA register
80e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @dir: PORTx_DIR register
81e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @inen: PORTx_INEN register
82e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @mux: PORTx_MUX register
83e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang */
84e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstruct gpio_port_saved {
85e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	u16 fer;
86e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	u16 data;
87e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	u16 dir;
88e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	u16 inen;
89e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	u32 mux;
90e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang};
91e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
921e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang/*
931e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang * struct gpio_pint_saved - PINT registers saved in PM operations
941e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang *
951e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang * @assign: ASSIGN register
961e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang * @edge_set: EDGE_SET register
971e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang * @invert_set: INVERT_SET register
981e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang */
991e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhangstruct gpio_pint_saved {
1001e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang	u32 assign;
1011e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang	u32 edge_set;
1021e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang	u32 invert_set;
1031e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang};
1041e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang
105e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang/**
106e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * struct gpio_pint - Pin interrupt controller device. Multiple ADI GPIO
107e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * banks can be mapped into one Pin interrupt controller.
108e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang *
109e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @node: All gpio_pint instances are added to a global list.
110e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @base: PINT device register base address
111e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @irq: IRQ of the PINT device, it is the parent IRQ of all
112e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang *       GPIO IRQs mapping to this device.
113e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @domain: [0] irq domain of the gpio port, whose hardware interrupts are
114e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang *		mapping to the low 16-bit of the pint registers.
115e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang *          [1] irq domain of the gpio port, whose hardware interrupts are
116e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang *		mapping to the high 16-bit of the pint registers.
117e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @regs: address pointer to the PINT device
118e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @map_count: No more than 2 GPIO banks can be mapped to this PINT device.
119e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @lock: This lock make sure the irq_chip operations to one PINT device
120e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang *        for different GPIO interrrupts are atomic.
121e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @pint_map_port: Set up the mapping between one PINT device and
122e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang *                 multiple GPIO banks.
123e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang */
124e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstruct gpio_pint {
125e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct list_head node;
126e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	void __iomem *base;
127e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	int irq;
128e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct irq_domain *domain[2];
129e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint_regs *regs;
1301e6f8e3c92fbbcd5bcca860c4db4eef2052aa79fSonic Zhang	struct gpio_pint_saved saved_data;
131e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	int map_count;
132e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spinlock_t lock;
133e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
134e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	int (*pint_map_port)(struct gpio_pint *pint, bool assign,
135e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang				u8 map, struct irq_domain *domain);
136e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang};
137e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
138e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang/**
139e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * ADI pin controller
140e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang *
141e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @dev: a pointer back to containing device
142e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @pctl: the pinctrl device
143e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @soc: SoC data for this specific chip
144e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang */
145e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstruct adi_pinctrl {
146e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct device *dev;
147e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct pinctrl_dev *pctl;
148e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	const struct adi_pinctrl_soc_data *soc;
149e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang};
150e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
151e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang/**
152e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * struct gpio_port - GPIO bank device. Multiple ADI GPIO banks can be mapped
153e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * into one pin interrupt controller.
154e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang *
155e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @node: All gpio_port instances are added to a list.
156e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @base: GPIO bank device register base address
157e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @irq_base: base IRQ of the GPIO bank device
158e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @width: PIN number of the GPIO bank device
159e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @regs: address pointer to the GPIO bank device
160e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @saved_data: registers that should be saved between PM operations.
161e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @dev: device structure of this GPIO bank
162e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @pint: GPIO PINT device that this GPIO bank mapped to
163e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @pint_map: GIOP bank mapping code in PINT device
164e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @pint_assign: The 32-bit PINT registers can be divided into 2 parts. A
165e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang *               GPIO bank can be mapped into either low 16 bits[0] or high 16
166e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang *               bits[1] of each PINT register.
167e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @lock: This lock make sure the irq_chip operations to one PINT device
168e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang *        for different GPIO interrrupts are atomic.
169e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @chip: abstract a GPIO controller
170e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @domain: The irq domain owned by the GPIO port.
171e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang * @rsvmap: Reservation map array for each pin in the GPIO bank
172e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang */
173e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstruct gpio_port {
174e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct list_head node;
175e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	void __iomem *base;
176b4eef7b22544d46d918696253e9086975dc6f8b0Sonic Zhang	int irq_base;
177e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned int width;
178e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port_t *regs;
179e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port_saved saved_data;
180e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct device *dev;
181e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
182e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint *pint;
183e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	u8 pint_map;
184e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	bool pint_assign;
185e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
186e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spinlock_t lock;
187e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_chip chip;
188e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct irq_domain *domain;
189e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang};
190e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
191e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic inline u8 pin_to_offset(struct pinctrl_gpio_range *range, unsigned pin)
192e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
193e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return pin - range->pin_base;
194e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
195e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
196e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic inline u32 hwirq_to_pintbit(struct gpio_port *port, int hwirq)
197e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
198e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return port->pint_assign ? BIT(hwirq) << PINT_HI_OFFSET : BIT(hwirq);
199e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
200e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
201e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct gpio_pint *find_gpio_pint(unsigned id)
202e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
203e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint *pint;
204e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	int i = 0;
205e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
206e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	list_for_each_entry(pint, &adi_pint_list, node) {
207e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		if (id == i)
208e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			return pint;
209e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		i++;
210e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
211e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
212e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return NULL;
213e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
214e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
215e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic inline void port_setup(struct gpio_port *port, unsigned offset,
216e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	bool use_for_gpio)
217e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
218e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port_t *regs = port->regs;
219e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
220e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (use_for_gpio)
221e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writew(readw(&regs->port_fer) & ~BIT(offset),
222e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			&regs->port_fer);
223e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	else
224e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writew(readw(&regs->port_fer) | BIT(offset), &regs->port_fer);
225e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
226e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
227e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic inline void portmux_setup(struct gpio_port *port, unsigned offset,
228e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned short function)
229e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
230e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port_t *regs = port->regs;
231e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	u32 pmux;
232e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
233e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pmux = readl(&regs->port_mux);
234e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
235e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	/* The function field of each pin has 2 consecutive bits in
236e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 * the mux register.
237e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 */
238e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pmux &= ~(0x3 << (2 * offset));
239e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pmux |= (function & 0x3) << (2 * offset);
240e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
241e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	writel(pmux, &regs->port_mux);
242e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
243e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
244e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic inline u16 get_portmux(struct gpio_port *port, unsigned offset)
245e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
246e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port_t *regs = port->regs;
247e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	u32 pmux = readl(&regs->port_mux);
248e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
249e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	/* The function field of each pin has 2 consecutive bits in
250e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 * the mux register.
251e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 */
252e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return pmux >> (2 * offset) & 0x3;
253e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
254e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
255e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_gpio_ack_irq(struct irq_data *d)
256e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
257e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned long flags;
258e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port = irq_data_get_irq_chip_data(d);
259e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint_regs *regs = port->pint->regs;
260e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned pintbit = hwirq_to_pintbit(port, d->hwirq);
261e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
262e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_irqsave(&port->lock, flags);
263010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	spin_lock(&port->pint->lock);
264e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
265e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) {
266e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		if (readl(&regs->invert_set) & pintbit)
267e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			writel(pintbit, &regs->invert_clear);
268e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		else
269e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			writel(pintbit, &regs->invert_set);
270e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
271e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
272e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	writel(pintbit, &regs->request);
273e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
274010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	spin_unlock(&port->pint->lock);
275e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_unlock_irqrestore(&port->lock, flags);
276e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
277e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
278e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_gpio_mask_ack_irq(struct irq_data *d)
279e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
280e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned long flags;
281e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port = irq_data_get_irq_chip_data(d);
282e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint_regs *regs = port->pint->regs;
283e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned pintbit = hwirq_to_pintbit(port, d->hwirq);
284e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
285e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_irqsave(&port->lock, flags);
286010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	spin_lock(&port->pint->lock);
287e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
288e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) {
289e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		if (readl(&regs->invert_set) & pintbit)
290e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			writel(pintbit, &regs->invert_clear);
291e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		else
292e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			writel(pintbit, &regs->invert_set);
293e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
294e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
295e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	writel(pintbit, &regs->request);
296e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	writel(pintbit, &regs->mask_clear);
297e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
298010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	spin_unlock(&port->pint->lock);
299e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_unlock_irqrestore(&port->lock, flags);
300e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
301e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
302e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_gpio_mask_irq(struct irq_data *d)
303e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
304e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned long flags;
305e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port = irq_data_get_irq_chip_data(d);
306e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint_regs *regs = port->pint->regs;
307e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
308e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_irqsave(&port->lock, flags);
309010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	spin_lock(&port->pint->lock);
310e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
311e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_clear);
312e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
313010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	spin_unlock(&port->pint->lock);
314e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_unlock_irqrestore(&port->lock, flags);
315e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
316e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
317e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_gpio_unmask_irq(struct irq_data *d)
318e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
319e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned long flags;
320e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port = irq_data_get_irq_chip_data(d);
321e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint_regs *regs = port->pint->regs;
322e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
323e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_irqsave(&port->lock, flags);
324010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	spin_lock(&port->pint->lock);
325e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
326e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_set);
327e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
328010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	spin_unlock(&port->pint->lock);
329e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_unlock_irqrestore(&port->lock, flags);
330e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
331e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
332e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic unsigned int adi_gpio_irq_startup(struct irq_data *d)
333e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
334e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned long flags;
335e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port = irq_data_get_irq_chip_data(d);
336010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	struct gpio_pint_regs *regs;
337e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
338e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!port) {
339010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang		pr_err("GPIO IRQ %d :Not exist\n", d->irq);
340e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -ENODEV;
341e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
342e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
343010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	regs = port->pint->regs;
344010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang
345e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_irqsave(&port->lock, flags);
346010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	spin_lock(&port->pint->lock);
347e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
348e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port_setup(port, d->hwirq, true);
349e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	writew(BIT(d->hwirq), &port->regs->dir_clear);
350e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	writew(readw(&port->regs->inen) | BIT(d->hwirq), &port->regs->inen);
351e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
352e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_set);
353e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
354010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	spin_unlock(&port->pint->lock);
355e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_unlock_irqrestore(&port->lock, flags);
356e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
357e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
358e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
359e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
360e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_gpio_irq_shutdown(struct irq_data *d)
361e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
362e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned long flags;
363e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port = irq_data_get_irq_chip_data(d);
364e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint_regs *regs = port->pint->regs;
365e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
366e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_irqsave(&port->lock, flags);
367010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	spin_lock(&port->pint->lock);
368e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
369e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_clear);
370e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
371010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	spin_unlock(&port->pint->lock);
372e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_unlock_irqrestore(&port->lock, flags);
373e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
374e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
375e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_irq_type(struct irq_data *d, unsigned int type)
376e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
377e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned long flags;
378e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port = irq_data_get_irq_chip_data(d);
379010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	struct gpio_pint_regs *pint_regs;
380e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned pintmask;
381e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned int irq = d->irq;
382e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	int ret = 0;
383e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	char buf[16];
384e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
385e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!port) {
386010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang		pr_err("GPIO IRQ %d :Not exist\n", d->irq);
387e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -ENODEV;
388e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
389e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
390010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	pint_regs = port->pint->regs;
391010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang
392e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pintmask = hwirq_to_pintbit(port, d->hwirq);
393e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
394e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_irqsave(&port->lock, flags);
395010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	spin_lock(&port->pint->lock);
396e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
397e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	/* In case of interrupt autodetect, set irq type to edge sensitive. */
398e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (type == IRQ_TYPE_PROBE)
399e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
400e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
401e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
402e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		    IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
403e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		snprintf(buf, 16, "gpio-irq%d", irq);
404e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port_setup(port, d->hwirq, true);
405e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	} else
406e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		goto out;
407e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
408e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	/* The GPIO interrupt is triggered only when its input value
409e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 * transfer from 0 to 1. So, invert the input value if the
410e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 * irq type is low or falling
411e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 */
412e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
413e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writel(pintmask, &pint_regs->invert_set);
414e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	else
415e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writel(pintmask, &pint_regs->invert_clear);
416e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
417e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	/* In edge sensitive case, if the input value of the requested irq
418e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 * is already 1, invert it.
419e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 */
420e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
421e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		if (gpio_get_value(port->chip.base + d->hwirq))
422e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			writel(pintmask, &pint_regs->invert_set);
423e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		else
424e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			writel(pintmask, &pint_regs->invert_clear);
425e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
426e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
427e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
428e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writel(pintmask, &pint_regs->edge_set);
429e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		__irq_set_handler_locked(irq, handle_edge_irq);
430e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	} else {
431e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writel(pintmask, &pint_regs->edge_clear);
432e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		__irq_set_handler_locked(irq, handle_level_irq);
433e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
434e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
435e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangout:
436010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	spin_unlock(&port->pint->lock);
437e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_unlock_irqrestore(&port->lock, flags);
438e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
439e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return ret;
440e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
441e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
442e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#ifdef CONFIG_PM
443e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_set_wake(struct irq_data *d, unsigned int state)
444e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
445e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port = irq_data_get_irq_chip_data(d);
446e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
447e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!port || !port->pint || port->pint->irq != d->irq)
448e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -EINVAL;
449e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
450e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#ifndef SEC_GCTL
451e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	adi_internal_set_wake(port->pint->irq, state);
452e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#endif
453e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
454e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
455e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
456e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
457e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_pint_suspend(void)
458e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
459e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint *pint;
460e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
461e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	list_for_each_entry(pint, &adi_pint_list, node) {
462e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writel(0xffffffff, &pint->regs->mask_clear);
463e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		pint->saved_data.assign = readl(&pint->regs->assign);
464e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		pint->saved_data.edge_set = readl(&pint->regs->edge_set);
465e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		pint->saved_data.invert_set = readl(&pint->regs->invert_set);
466e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
467e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
468e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
469e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
470e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
471e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_pint_resume(void)
472e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
473e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint *pint;
474e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
475e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	list_for_each_entry(pint, &adi_pint_list, node) {
476e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writel(pint->saved_data.assign, &pint->regs->assign);
477e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writel(pint->saved_data.edge_set, &pint->regs->edge_set);
478e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writel(pint->saved_data.invert_set, &pint->regs->invert_set);
479e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
480e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
481e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
482e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_suspend(void)
483e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
484e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port;
485e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
486e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	list_for_each_entry(port, &adi_gpio_port_list, node) {
487e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port->saved_data.fer = readw(&port->regs->port_fer);
488e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port->saved_data.mux = readl(&port->regs->port_mux);
489e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port->saved_data.data = readw(&port->regs->data);
490e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port->saved_data.inen = readw(&port->regs->inen);
491e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port->saved_data.dir = readw(&port->regs->dir_set);
492e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
493e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
494e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return adi_pint_suspend();
495e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
496e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
497e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_gpio_resume(void)
498e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
499e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port;
500e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
501e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	adi_pint_resume();
502e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
503e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	list_for_each_entry(port, &adi_gpio_port_list, node) {
504e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writel(port->saved_data.mux, &port->regs->port_mux);
505e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writew(port->saved_data.fer, &port->regs->port_fer);
506e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writew(port->saved_data.inen, &port->regs->inen);
507e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writew(port->saved_data.data & port->saved_data.dir,
508e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang					&port->regs->data_set);
509e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writew(port->saved_data.dir, &port->regs->dir_set);
510e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
511e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
512e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
513e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
514e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct syscore_ops gpio_pm_syscore_ops = {
515e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.suspend = adi_gpio_suspend,
516e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.resume = adi_gpio_resume,
517e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang};
518e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#else /* CONFIG_PM */
519e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#define adi_gpio_set_wake NULL
520e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#endif /* CONFIG_PM */
521e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
522e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#ifdef CONFIG_IRQ_PREFLOW_FASTEOI
523e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic inline void preflow_handler(struct irq_desc *desc)
524e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
525e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (desc->preflow_handler)
526e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		desc->preflow_handler(&desc->irq_data);
527e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
528e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#else
529e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic inline void preflow_handler(struct irq_desc *desc) { }
530e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#endif
531e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
532e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_gpio_handle_pint_irq(unsigned int inta_irq,
533e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			struct irq_desc *desc)
534e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
535e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	u32 request;
536e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	u32 level_mask, hwirq;
537e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	bool umask = false;
538e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint *pint = irq_desc_get_handler_data(desc);
539e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct irq_chip *chip = irq_desc_get_chip(desc);
540e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint_regs *regs = pint->regs;
541e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct irq_domain *domain;
542e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
543e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	preflow_handler(desc);
544e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	chained_irq_enter(chip, desc);
545e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
546e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	request = readl(&regs->request);
547e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	level_mask = readl(&regs->edge_set) & request;
548e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
549e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	hwirq = 0;
550e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	domain = pint->domain[0];
551e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	while (request) {
552e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		/* domain pointer need to be changed only once at IRQ 16 when
553e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		 * we go through IRQ requests from bit 0 to bit 31.
554e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		 */
555e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		if (hwirq == PINT_HI_OFFSET)
556e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			domain = pint->domain[1];
557e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
558e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		if (request & 1) {
559e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			if (level_mask & BIT(hwirq)) {
560e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang				umask = true;
561e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang				chained_irq_exit(chip, desc);
562e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			}
563e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			generic_handle_irq(irq_find_mapping(domain,
564e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang					hwirq % PINT_HI_OFFSET));
565e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		}
566e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
567e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		hwirq++;
568e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		request >>= 1;
569e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
570e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
571e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!umask)
572e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		chained_irq_exit(chip, desc);
573e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
574e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
575e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct irq_chip adi_gpio_irqchip = {
576e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.name = "GPIO",
577e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.irq_ack = adi_gpio_ack_irq,
578e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.irq_mask = adi_gpio_mask_irq,
579e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.irq_mask_ack = adi_gpio_mask_ack_irq,
580e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.irq_unmask = adi_gpio_unmask_irq,
581e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.irq_disable = adi_gpio_mask_irq,
582e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.irq_enable = adi_gpio_unmask_irq,
583e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.irq_set_type = adi_gpio_irq_type,
584e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.irq_startup = adi_gpio_irq_startup,
585e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.irq_shutdown = adi_gpio_irq_shutdown,
586e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.irq_set_wake = adi_gpio_set_wake,
587e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang};
588e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
589e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_get_groups_count(struct pinctrl_dev *pctldev)
590e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
591e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
592e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
593e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return pinctrl->soc->ngroups;
594e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
595e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
596e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic const char *adi_get_group_name(struct pinctrl_dev *pctldev,
597e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang				       unsigned selector)
598e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
599e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
600e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
601e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return pinctrl->soc->groups[selector].name;
602e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
603e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
604e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
605e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			       const unsigned **pins,
606e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			       unsigned *num_pins)
607e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
608e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
609e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
610e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	*pins = pinctrl->soc->groups[selector].pins;
611e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	*num_pins = pinctrl->soc->groups[selector].num;
612e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
613e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
614e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
615e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct pinctrl_ops adi_pctrl_ops = {
616e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.get_groups_count = adi_get_groups_count,
617e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.get_group_name = adi_get_group_name,
618e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.get_group_pins = adi_get_group_pins,
619e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang};
620e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
621e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_pinmux_enable(struct pinctrl_dev *pctldev, unsigned selector,
622e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned group)
623e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
624e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
625e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port;
626e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct pinctrl_gpio_range *range;
627e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned long flags;
628e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned short *mux, pin;
629e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
630e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	mux = (unsigned short *)pinctrl->soc->functions[selector].mux;
631e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
632e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	while (*mux) {
633e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		pin = P_IDENT(*mux);
634e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
635e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		range = pinctrl_find_gpio_range_from_pin(pctldev, pin);
636e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		if (range == NULL) /* should not happen */
637e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			return -ENODEV;
638e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
639e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port = container_of(range->gc, struct gpio_port, chip);
640e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
641e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		spin_lock_irqsave(&port->lock, flags);
642e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
643e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		portmux_setup(port, pin_to_offset(range, pin),
644b81e57e6ac35242ba59206b303ba6c7585764ee1Sonic Zhang				P_FUNCT2MUX(*mux));
645e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port_setup(port, pin_to_offset(range, pin), false);
646e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		mux++;
647e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
648e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		spin_unlock_irqrestore(&port->lock, flags);
649e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
650e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
651e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
652e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
653e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
654e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_pinmux_disable(struct pinctrl_dev *pctldev, unsigned selector,
655e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned group)
656e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
657e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
658e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port;
659e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct pinctrl_gpio_range *range;
660e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned long flags;
661e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned short *mux, pin;
662e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
663e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	mux = (unsigned short *)pinctrl->soc->functions[selector].mux;
664e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
665e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	while (*mux) {
666e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		pin = P_IDENT(*mux);
667e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
668e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		range = pinctrl_find_gpio_range_from_pin(pctldev, pin);
669e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		if (range == NULL) /* should not happen */
670e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			return;
671e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
672e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port = container_of(range->gc, struct gpio_port, chip);
673e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
674e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		spin_lock_irqsave(&port->lock, flags);
675e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
676e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port_setup(port, pin_to_offset(range, pin), true);
677e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		mux++;
678e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
679e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		spin_unlock_irqrestore(&port->lock, flags);
680e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
681e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
682e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
683e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_pinmux_get_funcs_count(struct pinctrl_dev *pctldev)
684e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
685e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
686e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
687e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return pinctrl->soc->nfunctions;
688e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
689e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
690e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic const char *adi_pinmux_get_func_name(struct pinctrl_dev *pctldev,
691e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang					  unsigned selector)
692e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
693e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
694e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
695e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return pinctrl->soc->functions[selector].name;
696e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
697e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
698e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
699e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			       const char * const **groups,
700e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			       unsigned * const num_groups)
701e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
702e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
703e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
704e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	*groups = pinctrl->soc->functions[selector].groups;
705e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	*num_groups = pinctrl->soc->functions[selector].num_groups;
706e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
707e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
708e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
709e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_pinmux_request_gpio(struct pinctrl_dev *pctldev,
710e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct pinctrl_gpio_range *range, unsigned pin)
711e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
712e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port;
713e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned long flags;
714e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	u8 offset;
715e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
716e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port = container_of(range->gc, struct gpio_port, chip);
717e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	offset = pin_to_offset(range, pin);
718e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
719e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_irqsave(&port->lock, flags);
720e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
721e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port_setup(port, offset, true);
722e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
723e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_unlock_irqrestore(&port->lock, flags);
724e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
725e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
726e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
727e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
728e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct pinmux_ops adi_pinmux_ops = {
729e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.enable = adi_pinmux_enable,
730e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.disable = adi_pinmux_disable,
731e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.get_functions_count = adi_pinmux_get_funcs_count,
732e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.get_function_name = adi_pinmux_get_func_name,
733e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.get_function_groups = adi_pinmux_get_groups,
734e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.gpio_request_enable = adi_pinmux_request_gpio,
735e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang};
736e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
737e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
738e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct pinctrl_desc adi_pinmux_desc = {
739e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.name = DRIVER_NAME,
740e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.pctlops = &adi_pctrl_ops,
741e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.pmxops = &adi_pinmux_ops,
742e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.owner = THIS_MODULE,
743e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang};
744e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
745e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_request(struct gpio_chip *chip, unsigned offset)
746e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
747e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return pinctrl_request_gpio(chip->base + offset);
748e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
749e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
750e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_gpio_free(struct gpio_chip *chip, unsigned offset)
751e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
752e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pinctrl_free_gpio(chip->base + offset);
753e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
754e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
755e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
756e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
757e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port;
758e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned long flags;
759e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
760e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port = container_of(chip, struct gpio_port, chip);
761e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
762e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_irqsave(&port->lock, flags);
763e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
764e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	writew(BIT(offset), &port->regs->dir_clear);
765e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	writew(readw(&port->regs->inen) | BIT(offset), &port->regs->inen);
766e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
767e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_unlock_irqrestore(&port->lock, flags);
768e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
769e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
770e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
771e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
772e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_gpio_set_value(struct gpio_chip *chip, unsigned offset,
773e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	int value)
774e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
775e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port = container_of(chip, struct gpio_port, chip);
776e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port_t *regs = port->regs;
777e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned long flags;
778e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
779e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_irqsave(&port->lock, flags);
780e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
781e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (value)
782d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang		writew(BIT(offset), &regs->data_set);
783e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	else
784d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang		writew(BIT(offset), &regs->data_clear);
785e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
786e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_unlock_irqrestore(&port->lock, flags);
787e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
788e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
789e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
790e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	int value)
791e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
792e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port = container_of(chip, struct gpio_port, chip);
793e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port_t *regs = port->regs;
794e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned long flags;
795e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
796e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_irqsave(&port->lock, flags);
797e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
798d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang	writew(readw(&regs->inen) & ~BIT(offset), &regs->inen);
799d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang	if (value)
800d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang		writew(BIT(offset), &regs->data_set);
801d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang	else
802d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang		writew(BIT(offset), &regs->data_clear);
803d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang	writew(BIT(offset), &regs->dir_set);
804e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
805e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_unlock_irqrestore(&port->lock, flags);
806e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
807e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
808e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
809e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
810e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_get_value(struct gpio_chip *chip, unsigned offset)
811e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
812e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port = container_of(chip, struct gpio_port, chip);
813e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port_t *regs = port->regs;
814e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned long flags;
815e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	int ret;
816e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
817e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_irqsave(&port->lock, flags);
818e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
819e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	ret = !!(readw(&regs->data) & BIT(offset));
820e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
821e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_unlock_irqrestore(&port->lock, flags);
822e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
823e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return ret;
824e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
825e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
826e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
827e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
828e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port = container_of(chip, struct gpio_port, chip);
829e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
830e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (port->irq_base >= 0)
831e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return irq_find_mapping(port->domain, offset);
832e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	else
833e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return irq_create_mapping(port->domain, offset);
834e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
835e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
836e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_pint_map_port(struct gpio_pint *pint, bool assign, u8 map,
837e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct irq_domain *domain)
838e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
839e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint_regs *regs = pint->regs;
840e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	u32 map_mask;
841e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
842e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (pint->map_count > 1)
843e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -EINVAL;
844e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
845e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pint->map_count++;
846e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
847e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	/* The map_mask of each gpio port is a 16-bit duplicate
848e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 * of the 8-bit map. It can be set to either high 16 bits or low
849e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 * 16 bits of the pint assignment register.
850e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 */
851e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	map_mask = (map << 8) | map;
852e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (assign) {
853e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		map_mask <<= PINT_HI_OFFSET;
854e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writel((readl(&regs->assign) & 0xFFFF) | map_mask,
855e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			&regs->assign);
856e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	} else
857e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writel((readl(&regs->assign) & 0xFFFF0000) | map_mask,
858e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			&regs->assign);
859e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
860e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pint->domain[assign] = domain;
861e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
862e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
863e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
864e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
865e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_pint_probe(struct platform_device *pdev)
866e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
867e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct device *dev = &pdev->dev;
868e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct resource *res;
869e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint *pint;
870e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
871e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pint = devm_kzalloc(dev, sizeof(struct gpio_pint), GFP_KERNEL);
872e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!pint) {
873e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		dev_err(dev, "Memory alloc failed\n");
874e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -ENOMEM;
875e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
876e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
877e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
878c8690d6d2957ed060c1cba4cde3ec41e3829651bAxel Lin	pint->base = devm_ioremap_resource(dev, res);
879c8690d6d2957ed060c1cba4cde3ec41e3829651bAxel Lin	if (IS_ERR(pint->base))
880c8690d6d2957ed060c1cba4cde3ec41e3829651bAxel Lin		return PTR_ERR(pint->base);
881e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
882e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pint->regs = (struct gpio_pint_regs *)pint->base;
883e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
884e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
885e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!res) {
886e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		dev_err(dev, "Invalid IRQ resource\n");
887e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -ENODEV;
888e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
889e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
890e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_init(&pint->lock);
891e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
892e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pint->irq = res->start;
893e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pint->pint_map_port = adi_pint_map_port;
894e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	platform_set_drvdata(pdev, pint);
895e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
896e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	irq_set_chained_handler(pint->irq, adi_gpio_handle_pint_irq);
897e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	irq_set_handler_data(pint->irq, pint);
898e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
899e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	list_add_tail(&pint->node, &adi_pint_list);
900e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
901e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
902e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
903e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
904e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_pint_remove(struct platform_device *pdev)
905e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
906e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint *pint = platform_get_drvdata(pdev);
907e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
908e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	list_del(&pint->node);
909e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	irq_set_handler(pint->irq, handle_simple_irq);
910e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
911e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
912e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
913e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
914e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_irq_map(struct irq_domain *d, unsigned int irq,
915e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang				irq_hw_number_t hwirq)
916e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
917e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port = d->host_data;
918e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
919e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!port)
920e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -EINVAL;
921e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
922e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	irq_set_chip_data(irq, port);
923e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	irq_set_chip_and_handler(irq, &adi_gpio_irqchip,
924e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang				handle_level_irq);
925e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
926e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
927e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
928e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
929e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangconst struct irq_domain_ops adi_gpio_irq_domain_ops = {
930e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.map = adi_gpio_irq_map,
931e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.xlate = irq_domain_xlate_onecell,
932e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang};
933e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
934e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_init_int(struct gpio_port *port)
935e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
936e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct device_node *node = port->dev->of_node;
937e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint *pint = port->pint;
938e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	int ret;
939e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
940e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->domain = irq_domain_add_linear(node, port->width,
941e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang				&adi_gpio_irq_domain_ops, port);
942e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!port->domain) {
943e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		dev_err(port->dev, "Failed to create irqdomain\n");
944e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -ENOSYS;
945e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
946e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
947e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	/* According to BF54x and BF60x HRM, pin interrupt devices are not
948e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 * part of the GPIO port device. in GPIO interrupt mode, the GPIO
949e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 * pins of multiple port devices can be routed into one pin interrupt
950e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 * device. The mapping can be configured by setting pint assignment
951e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 * register with the mapping value of different GPIO port. This is
952e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 * done via function pint_map_port().
953e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 */
954e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	ret = pint->pint_map_port(port->pint, port->pint_assign,
955e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			port->pint_map,	port->domain);
956e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (ret)
957e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return ret;
958e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
959e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (port->irq_base >= 0) {
960e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		ret = irq_create_strict_mappings(port->domain, port->irq_base,
961e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang					0, port->width);
962e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		if (ret) {
963e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			dev_err(port->dev, "Couldn't associate to domain\n");
964e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			return ret;
965e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		}
966e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
967e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
968e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
969e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
970e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
971e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#define DEVNAME_SIZE 16
972e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
973e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_probe(struct platform_device *pdev)
974e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
975e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct device *dev = &pdev->dev;
976e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	const struct adi_pinctrl_gpio_platform_data *pdata;
977e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct resource *res;
978e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port;
979e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	char pinctrl_devname[DEVNAME_SIZE];
980e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	static int gpio;
981e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	int ret = 0, ret1;
982e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
983e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pdata = dev->platform_data;
984e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!pdata)
985e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -EINVAL;
986e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
987e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port = devm_kzalloc(dev, sizeof(struct gpio_port), GFP_KERNEL);
988e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!port) {
989e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		dev_err(dev, "Memory alloc failed\n");
990e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -ENOMEM;
991e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
992e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
993e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
994c8690d6d2957ed060c1cba4cde3ec41e3829651bAxel Lin	port->base = devm_ioremap_resource(dev, res);
995c8690d6d2957ed060c1cba4cde3ec41e3829651bAxel Lin	if (IS_ERR(port->base))
996c8690d6d2957ed060c1cba4cde3ec41e3829651bAxel Lin		return PTR_ERR(port->base);
997e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
998e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
999e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!res)
1000e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port->irq_base = -1;
1001e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	else
1002e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port->irq_base = res->start;
1003e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1004e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->width = pdata->port_width;
1005e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->dev = dev;
1006e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->regs = (struct gpio_port_t *)port->base;
1007e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->pint_assign = pdata->pint_assign;
1008e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->pint_map = pdata->pint_map;
1009e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1010e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->pint = find_gpio_pint(pdata->pint_id);
1011e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (port->pint) {
1012e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		ret = adi_gpio_init_int(port);
1013e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		if (ret)
1014e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			return ret;
1015e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
1016e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1017e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_init(&port->lock);
1018e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1019e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	platform_set_drvdata(pdev, port);
1020e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1021e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->chip.label		= "adi-gpio";
1022e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->chip.direction_input	= adi_gpio_direction_input;
1023e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->chip.get			= adi_gpio_get_value;
1024e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->chip.direction_output	= adi_gpio_direction_output;
1025e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->chip.set			= adi_gpio_set_value;
1026e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->chip.request		= adi_gpio_request;
1027e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->chip.free			= adi_gpio_free;
1028e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->chip.to_irq		= adi_gpio_to_irq;
1029e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (pdata->port_gpio_base > 0)
1030e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port->chip.base		= pdata->port_gpio_base;
1031e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	else
1032e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port->chip.base		= gpio;
1033e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->chip.ngpio		= port->width;
1034e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	gpio = port->chip.base + port->width;
1035e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1036e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	ret = gpiochip_add(&port->chip);
1037e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (ret) {
1038e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		dev_err(&pdev->dev, "Fail to add GPIO chip.\n");
1039e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		goto out_remove_domain;
1040e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
1041e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1042e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	/* Add gpio pin range */
1043e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	snprintf(pinctrl_devname, DEVNAME_SIZE, "pinctrl-adi2.%d",
1044e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		pdata->pinctrl_id);
1045e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pinctrl_devname[DEVNAME_SIZE - 1] = 0;
1046e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	ret = gpiochip_add_pin_range(&port->chip, pinctrl_devname,
1047e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		0, pdata->port_pin_base, port->width);
1048e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (ret) {
1049e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		dev_err(&pdev->dev, "Fail to add pin range to %s.\n",
1050e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang				pinctrl_devname);
1051e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		goto out_remove_gpiochip;
1052e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
1053e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1054e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	list_add_tail(&port->node, &adi_gpio_port_list);
1055e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1056e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
1057e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1058e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangout_remove_gpiochip:
1059e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	ret1 = gpiochip_remove(&port->chip);
1060e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangout_remove_domain:
1061e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (port->pint)
1062e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		irq_domain_remove(port->domain);
1063e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1064e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return ret;
1065e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
1066e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1067e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_remove(struct platform_device *pdev)
1068e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
1069e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port = platform_get_drvdata(pdev);
1070e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	int ret;
1071e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	u8 offset;
1072e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1073e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	list_del(&port->node);
1074e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	gpiochip_remove_pin_ranges(&port->chip);
1075e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	ret = gpiochip_remove(&port->chip);
1076e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (port->pint) {
1077e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		for (offset = 0; offset < port->width; offset++)
1078e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			irq_dispose_mapping(irq_find_mapping(port->domain,
1079e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang				offset));
1080e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		irq_domain_remove(port->domain);
1081e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
1082e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1083e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return ret;
1084e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
1085e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1086e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_pinctrl_probe(struct platform_device *pdev)
1087e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
1088e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct adi_pinctrl *pinctrl;
1089e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1090e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pinctrl = devm_kzalloc(&pdev->dev, sizeof(*pinctrl), GFP_KERNEL);
1091e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!pinctrl)
1092e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -ENOMEM;
1093e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1094e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pinctrl->dev = &pdev->dev;
1095e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1096e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	adi_pinctrl_soc_init(&pinctrl->soc);
1097e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1098e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	adi_pinmux_desc.pins = pinctrl->soc->pins;
1099e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	adi_pinmux_desc.npins = pinctrl->soc->npins;
1100e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1101e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	/* Now register the pin controller and all pins it handles */
1102e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pinctrl->pctl = pinctrl_register(&adi_pinmux_desc, &pdev->dev, pinctrl);
1103e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!pinctrl->pctl) {
1104e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		dev_err(&pdev->dev, "could not register pinctrl ADI2 driver\n");
1105e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -EINVAL;
1106e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
1107e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1108e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	platform_set_drvdata(pdev, pinctrl);
1109e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1110e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
1111e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
1112e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1113e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_pinctrl_remove(struct platform_device *pdev)
1114e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
1115e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct adi_pinctrl *pinctrl = platform_get_drvdata(pdev);
1116e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1117e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pinctrl_unregister(pinctrl->pctl);
1118e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1119e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
1120e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
1121e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1122e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct platform_driver adi_pinctrl_driver = {
1123e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.probe		= adi_pinctrl_probe,
1124e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.remove		= adi_pinctrl_remove,
1125e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.driver		= {
1126e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		.name	= DRIVER_NAME,
1127e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	},
1128e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang};
1129e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1130e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct platform_driver adi_gpio_pint_driver = {
1131e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.probe		= adi_gpio_pint_probe,
1132e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.remove		= adi_gpio_pint_remove,
1133e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.driver		= {
1134e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		.name	= "adi-gpio-pint",
1135e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	},
1136e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang};
1137e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1138e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct platform_driver adi_gpio_driver = {
1139e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.probe		= adi_gpio_probe,
1140e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.remove		= adi_gpio_remove,
1141e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.driver		= {
1142e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		.name	= "adi-gpio",
1143e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	},
1144e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang};
1145e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1146e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int __init adi_pinctrl_setup(void)
1147e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
1148e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	int ret;
1149e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1150e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	ret = platform_driver_register(&adi_pinctrl_driver);
1151e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (ret)
1152e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return ret;
1153e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1154e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	ret = platform_driver_register(&adi_gpio_pint_driver);
1155e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (ret)
1156e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		goto pint_error;
1157e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1158e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	ret = platform_driver_register(&adi_gpio_driver);
1159e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (ret)
1160e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		goto gpio_error;
1161e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1162e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#ifdef CONFIG_PM
1163e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	register_syscore_ops(&gpio_pm_syscore_ops);
1164e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#endif
1165e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return ret;
1166e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhanggpio_error:
1167e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	platform_driver_unregister(&adi_gpio_pint_driver);
1168e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangpint_error:
1169e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	platform_driver_unregister(&adi_pinctrl_driver);
1170e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1171e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return ret;
1172e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
1173e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangarch_initcall(adi_pinctrl_setup);
1174e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1175e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangMODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
1176e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangMODULE_DESCRIPTION("ADI gpio2 pin control driver");
1177e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangMODULE_LICENSE("GPL");
1178