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);
34057ef04288abd27a717287a652d324f95cb77c3c6Linus Walleij		/* FIXME: negative return code will be ignored */
341e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -ENODEV;
342e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
343e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
344010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	regs = port->pint->regs;
345010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang
346e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_irqsave(&port->lock, flags);
347010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	spin_lock(&port->pint->lock);
348e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
349e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port_setup(port, d->hwirq, true);
350e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	writew(BIT(d->hwirq), &port->regs->dir_clear);
351e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	writew(readw(&port->regs->inen) | BIT(d->hwirq), &port->regs->inen);
352e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
353e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_set);
354e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
355010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	spin_unlock(&port->pint->lock);
356e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_unlock_irqrestore(&port->lock, flags);
357e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
358e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
359e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
360e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
361e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_gpio_irq_shutdown(struct irq_data *d)
362e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
363e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned long flags;
364e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port = irq_data_get_irq_chip_data(d);
365e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint_regs *regs = port->pint->regs;
366e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
367e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_irqsave(&port->lock, flags);
368010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	spin_lock(&port->pint->lock);
369e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
370e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	writel(hwirq_to_pintbit(port, d->hwirq), &regs->mask_clear);
371e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
372010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	spin_unlock(&port->pint->lock);
373e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_unlock_irqrestore(&port->lock, flags);
374e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
375e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
376e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_irq_type(struct irq_data *d, unsigned int type)
377e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
378e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned long flags;
379e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port = irq_data_get_irq_chip_data(d);
380010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	struct gpio_pint_regs *pint_regs;
381e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned pintmask;
382e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned int irq = d->irq;
383e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	int ret = 0;
384e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	char buf[16];
385e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
386e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!port) {
387010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang		pr_err("GPIO IRQ %d :Not exist\n", d->irq);
388e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -ENODEV;
389e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
390e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
391010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	pint_regs = port->pint->regs;
392010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang
393e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pintmask = hwirq_to_pintbit(port, d->hwirq);
394e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
395e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_irqsave(&port->lock, flags);
396010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	spin_lock(&port->pint->lock);
397e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
398e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	/* In case of interrupt autodetect, set irq type to edge sensitive. */
399e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (type == IRQ_TYPE_PROBE)
400e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
401e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
402e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
403e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		    IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
404719e231bed5b1c638c7f48a657547562fc2064a3Rickard Strandqvist		snprintf(buf, 16, "gpio-irq%u", irq);
405e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port_setup(port, d->hwirq, true);
406e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	} else
407e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		goto out;
408e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
409e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	/* The GPIO interrupt is triggered only when its input value
410e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 * transfer from 0 to 1. So, invert the input value if the
411e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 * irq type is low or falling
412e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 */
413e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
414e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writel(pintmask, &pint_regs->invert_set);
415e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	else
416e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writel(pintmask, &pint_regs->invert_clear);
417e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
418e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	/* In edge sensitive case, if the input value of the requested irq
419e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 * is already 1, invert it.
420e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 */
421e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
422e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		if (gpio_get_value(port->chip.base + d->hwirq))
423e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			writel(pintmask, &pint_regs->invert_set);
424e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		else
425e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			writel(pintmask, &pint_regs->invert_clear);
426e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
427e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
428e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
429e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writel(pintmask, &pint_regs->edge_set);
430e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		__irq_set_handler_locked(irq, handle_edge_irq);
431e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	} else {
432e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writel(pintmask, &pint_regs->edge_clear);
433e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		__irq_set_handler_locked(irq, handle_level_irq);
434e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
435e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
436e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangout:
437010c51e189c6a37da2908d27c93e73584f6e8fa8Sonic Zhang	spin_unlock(&port->pint->lock);
438e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_unlock_irqrestore(&port->lock, flags);
439e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
440e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return ret;
441e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
442e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
443e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#ifdef CONFIG_PM
444e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_set_wake(struct irq_data *d, unsigned int state)
445e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
446e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port = irq_data_get_irq_chip_data(d);
447e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
448e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!port || !port->pint || port->pint->irq != d->irq)
449e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -EINVAL;
450e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
451e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#ifndef SEC_GCTL
452e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	adi_internal_set_wake(port->pint->irq, state);
453e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#endif
454e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
455e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
456e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
457e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
458e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_pint_suspend(void)
459e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
460e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint *pint;
461e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
462e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	list_for_each_entry(pint, &adi_pint_list, node) {
463e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writel(0xffffffff, &pint->regs->mask_clear);
464e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		pint->saved_data.assign = readl(&pint->regs->assign);
465e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		pint->saved_data.edge_set = readl(&pint->regs->edge_set);
466e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		pint->saved_data.invert_set = readl(&pint->regs->invert_set);
467e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
468e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
469e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
470e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
471e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
472e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_pint_resume(void)
473e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
474e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint *pint;
475e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
476e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	list_for_each_entry(pint, &adi_pint_list, node) {
477e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writel(pint->saved_data.assign, &pint->regs->assign);
478e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writel(pint->saved_data.edge_set, &pint->regs->edge_set);
479e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writel(pint->saved_data.invert_set, &pint->regs->invert_set);
480e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
481e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
482e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
483e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_suspend(void)
484e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
485e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port;
486e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
487e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	list_for_each_entry(port, &adi_gpio_port_list, node) {
488e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port->saved_data.fer = readw(&port->regs->port_fer);
489e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port->saved_data.mux = readl(&port->regs->port_mux);
490e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port->saved_data.data = readw(&port->regs->data);
491e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port->saved_data.inen = readw(&port->regs->inen);
492e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port->saved_data.dir = readw(&port->regs->dir_set);
493e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
494e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
495e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return adi_pint_suspend();
496e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
497e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
498e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_gpio_resume(void)
499e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
500e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port;
501e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
502e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	adi_pint_resume();
503e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
504e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	list_for_each_entry(port, &adi_gpio_port_list, node) {
505e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writel(port->saved_data.mux, &port->regs->port_mux);
506e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writew(port->saved_data.fer, &port->regs->port_fer);
507e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writew(port->saved_data.inen, &port->regs->inen);
508e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writew(port->saved_data.data & port->saved_data.dir,
509e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang					&port->regs->data_set);
510e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writew(port->saved_data.dir, &port->regs->dir_set);
511e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
512e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
513e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
514e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
515e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct syscore_ops gpio_pm_syscore_ops = {
516e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.suspend = adi_gpio_suspend,
517e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.resume = adi_gpio_resume,
518e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang};
519e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#else /* CONFIG_PM */
520e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#define adi_gpio_set_wake NULL
521e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#endif /* CONFIG_PM */
522e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
523e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#ifdef CONFIG_IRQ_PREFLOW_FASTEOI
524e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic inline void preflow_handler(struct irq_desc *desc)
525e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
526e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (desc->preflow_handler)
527e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		desc->preflow_handler(&desc->irq_data);
528e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
529e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#else
530e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic inline void preflow_handler(struct irq_desc *desc) { }
531e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#endif
532e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
533e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_gpio_handle_pint_irq(unsigned int inta_irq,
534e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			struct irq_desc *desc)
535e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
536e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	u32 request;
537e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	u32 level_mask, hwirq;
538e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	bool umask = false;
539e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint *pint = irq_desc_get_handler_data(desc);
540e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct irq_chip *chip = irq_desc_get_chip(desc);
541e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint_regs *regs = pint->regs;
542e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct irq_domain *domain;
543e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
544e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	preflow_handler(desc);
545e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	chained_irq_enter(chip, desc);
546e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
547e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	request = readl(&regs->request);
548e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	level_mask = readl(&regs->edge_set) & request;
549e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
550e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	hwirq = 0;
551e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	domain = pint->domain[0];
552e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	while (request) {
553e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		/* domain pointer need to be changed only once at IRQ 16 when
554e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		 * we go through IRQ requests from bit 0 to bit 31.
555e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		 */
556e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		if (hwirq == PINT_HI_OFFSET)
557e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			domain = pint->domain[1];
558e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
559e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		if (request & 1) {
560e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			if (level_mask & BIT(hwirq)) {
561e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang				umask = true;
562e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang				chained_irq_exit(chip, desc);
563e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			}
564e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			generic_handle_irq(irq_find_mapping(domain,
565e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang					hwirq % PINT_HI_OFFSET));
566e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		}
567e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
568e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		hwirq++;
569e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		request >>= 1;
570e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
571e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
572e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!umask)
573e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		chained_irq_exit(chip, desc);
574e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
575e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
576e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct irq_chip adi_gpio_irqchip = {
577e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.name = "GPIO",
578e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.irq_ack = adi_gpio_ack_irq,
579e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.irq_mask = adi_gpio_mask_irq,
580e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.irq_mask_ack = adi_gpio_mask_ack_irq,
581e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.irq_unmask = adi_gpio_unmask_irq,
582e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.irq_disable = adi_gpio_mask_irq,
583e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.irq_enable = adi_gpio_unmask_irq,
584e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.irq_set_type = adi_gpio_irq_type,
585e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.irq_startup = adi_gpio_irq_startup,
586e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.irq_shutdown = adi_gpio_irq_shutdown,
587e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.irq_set_wake = adi_gpio_set_wake,
588e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang};
589e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
590e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_get_groups_count(struct pinctrl_dev *pctldev)
591e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
592e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
593e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
594e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return pinctrl->soc->ngroups;
595e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
596e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
597e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic const char *adi_get_group_name(struct pinctrl_dev *pctldev,
598e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang				       unsigned selector)
599e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
600e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
601e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
602e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return pinctrl->soc->groups[selector].name;
603e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
604e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
605e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
606e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			       const unsigned **pins,
607e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			       unsigned *num_pins)
608e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
609e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
610e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
611e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	*pins = pinctrl->soc->groups[selector].pins;
612e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	*num_pins = pinctrl->soc->groups[selector].num;
613e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
614e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
615e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
616e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct pinctrl_ops adi_pctrl_ops = {
617e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.get_groups_count = adi_get_groups_count,
618e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.get_group_name = adi_get_group_name,
619e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.get_group_pins = adi_get_group_pins,
620e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang};
621e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
62203e9f0cac5da6af85758276cb4624caf5911f2b9Linus Walleijstatic int adi_pinmux_set(struct pinctrl_dev *pctldev, unsigned func_id,
62303e9f0cac5da6af85758276cb4624caf5911f2b9Linus Walleij			  unsigned group_id)
624e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
625e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
626e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port;
627e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct pinctrl_gpio_range *range;
628e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned long flags;
629e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned short *mux, pin;
630e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
631e3653749aaee8dc8c819b9e4137f07e0383afb7eSonic Zhang	mux = (unsigned short *)pinctrl->soc->groups[group_id].mux;
632e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
633e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	while (*mux) {
634e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		pin = P_IDENT(*mux);
635e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
636e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		range = pinctrl_find_gpio_range_from_pin(pctldev, pin);
637e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		if (range == NULL) /* should not happen */
638e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			return -ENODEV;
639e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
640e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port = container_of(range->gc, struct gpio_port, chip);
641e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
642e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		spin_lock_irqsave(&port->lock, flags);
643e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
644e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		portmux_setup(port, pin_to_offset(range, pin),
645b81e57e6ac35242ba59206b303ba6c7585764ee1Sonic Zhang				P_FUNCT2MUX(*mux));
646e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port_setup(port, pin_to_offset(range, pin), false);
647e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		mux++;
648e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
649e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		spin_unlock_irqrestore(&port->lock, flags);
650e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
651e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
652e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
653e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
654e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
655e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_pinmux_get_funcs_count(struct pinctrl_dev *pctldev)
656e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
657e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
658e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
659e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return pinctrl->soc->nfunctions;
660e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
661e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
662e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic const char *adi_pinmux_get_func_name(struct pinctrl_dev *pctldev,
663e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang					  unsigned selector)
664e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
665e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
666e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
667e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return pinctrl->soc->functions[selector].name;
668e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
669e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
670e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
671e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			       const char * const **groups,
672e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			       unsigned * const num_groups)
673e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
674e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct adi_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
675e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
676e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	*groups = pinctrl->soc->functions[selector].groups;
677e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	*num_groups = pinctrl->soc->functions[selector].num_groups;
678e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
679e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
680e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
681e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_pinmux_request_gpio(struct pinctrl_dev *pctldev,
682e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct pinctrl_gpio_range *range, unsigned pin)
683e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
684e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port;
685e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned long flags;
686e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	u8 offset;
687e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
688e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port = container_of(range->gc, struct gpio_port, chip);
689e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	offset = pin_to_offset(range, pin);
690e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
691e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_irqsave(&port->lock, flags);
692e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
693e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port_setup(port, offset, true);
694e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
695e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_unlock_irqrestore(&port->lock, flags);
696e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
697e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
698e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
699e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
700e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct pinmux_ops adi_pinmux_ops = {
70103e9f0cac5da6af85758276cb4624caf5911f2b9Linus Walleij	.set_mux = adi_pinmux_set,
702e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.get_functions_count = adi_pinmux_get_funcs_count,
703e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.get_function_name = adi_pinmux_get_func_name,
704e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.get_function_groups = adi_pinmux_get_groups,
705e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.gpio_request_enable = adi_pinmux_request_gpio,
706e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang};
707e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
708e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
709e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct pinctrl_desc adi_pinmux_desc = {
710e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.name = DRIVER_NAME,
711e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.pctlops = &adi_pctrl_ops,
712e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.pmxops = &adi_pinmux_ops,
713e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.owner = THIS_MODULE,
714e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang};
715e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
716e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_request(struct gpio_chip *chip, unsigned offset)
717e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
718e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return pinctrl_request_gpio(chip->base + offset);
719e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
720e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
721e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_gpio_free(struct gpio_chip *chip, unsigned offset)
722e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
723e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pinctrl_free_gpio(chip->base + offset);
724e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
725e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
726e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
727e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
728e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port;
729e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned long flags;
730e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
731e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port = container_of(chip, struct gpio_port, chip);
732e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
733e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_irqsave(&port->lock, flags);
734e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
735e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	writew(BIT(offset), &port->regs->dir_clear);
736e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	writew(readw(&port->regs->inen) | BIT(offset), &port->regs->inen);
737e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
738e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_unlock_irqrestore(&port->lock, flags);
739e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
740e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
741e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
742e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
743e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic void adi_gpio_set_value(struct gpio_chip *chip, unsigned offset,
744e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	int value)
745e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
746e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port = container_of(chip, struct gpio_port, chip);
747e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port_t *regs = port->regs;
748e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned long flags;
749e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
750e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_irqsave(&port->lock, flags);
751e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
752e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (value)
753d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang		writew(BIT(offset), &regs->data_set);
754e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	else
755d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang		writew(BIT(offset), &regs->data_clear);
756e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
757e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_unlock_irqrestore(&port->lock, flags);
758e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
759e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
760e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
761e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	int value)
762e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
763e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port = container_of(chip, struct gpio_port, chip);
764e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port_t *regs = port->regs;
765e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned long flags;
766e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
767e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_irqsave(&port->lock, flags);
768e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
769d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang	writew(readw(&regs->inen) & ~BIT(offset), &regs->inen);
770d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang	if (value)
771d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang		writew(BIT(offset), &regs->data_set);
772d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang	else
773d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang		writew(BIT(offset), &regs->data_clear);
774d3224ed140dc440c43e1da607b7685635e8064a6Sonic Zhang	writew(BIT(offset), &regs->dir_set);
775e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
776e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_unlock_irqrestore(&port->lock, flags);
777e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
778e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
779e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
780e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
781e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_get_value(struct gpio_chip *chip, unsigned offset)
782e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
783e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port = container_of(chip, struct gpio_port, chip);
784e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port_t *regs = port->regs;
785e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	unsigned long flags;
786e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	int ret;
787e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
788e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_irqsave(&port->lock, flags);
789e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
790e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	ret = !!(readw(&regs->data) & BIT(offset));
791e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
792e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_unlock_irqrestore(&port->lock, flags);
793e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
794e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return ret;
795e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
796e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
797e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
798e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
799e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port = container_of(chip, struct gpio_port, chip);
800e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
801e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (port->irq_base >= 0)
802e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return irq_find_mapping(port->domain, offset);
803e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	else
804e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return irq_create_mapping(port->domain, offset);
805e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
806e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
807e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_pint_map_port(struct gpio_pint *pint, bool assign, u8 map,
808e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct irq_domain *domain)
809e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
810e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint_regs *regs = pint->regs;
811e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	u32 map_mask;
812e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
813e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (pint->map_count > 1)
814e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -EINVAL;
815e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
816e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pint->map_count++;
817e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
818e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	/* The map_mask of each gpio port is a 16-bit duplicate
819e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 * of the 8-bit map. It can be set to either high 16 bits or low
820e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 * 16 bits of the pint assignment register.
821e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 */
822e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	map_mask = (map << 8) | map;
823e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (assign) {
824e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		map_mask <<= PINT_HI_OFFSET;
825e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writel((readl(&regs->assign) & 0xFFFF) | map_mask,
826e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			&regs->assign);
827e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	} else
828e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		writel((readl(&regs->assign) & 0xFFFF0000) | map_mask,
829e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			&regs->assign);
830e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
831e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pint->domain[assign] = domain;
832e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
833e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
834e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
835e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
836e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_pint_probe(struct platform_device *pdev)
837e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
838e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct device *dev = &pdev->dev;
839e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct resource *res;
840e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint *pint;
841e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
842e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pint = devm_kzalloc(dev, sizeof(struct gpio_pint), GFP_KERNEL);
843e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!pint) {
844e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		dev_err(dev, "Memory alloc failed\n");
845e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -ENOMEM;
846e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
847e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
848e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
849c8690d6d2957ed060c1cba4cde3ec41e3829651bAxel Lin	pint->base = devm_ioremap_resource(dev, res);
850c8690d6d2957ed060c1cba4cde3ec41e3829651bAxel Lin	if (IS_ERR(pint->base))
851c8690d6d2957ed060c1cba4cde3ec41e3829651bAxel Lin		return PTR_ERR(pint->base);
852e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
853e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pint->regs = (struct gpio_pint_regs *)pint->base;
854e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
855e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
856e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!res) {
857e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		dev_err(dev, "Invalid IRQ resource\n");
858e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -ENODEV;
859e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
860e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
861e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_init(&pint->lock);
862e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
863e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pint->irq = res->start;
864e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pint->pint_map_port = adi_pint_map_port;
865e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	platform_set_drvdata(pdev, pint);
866e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
867e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	irq_set_chained_handler(pint->irq, adi_gpio_handle_pint_irq);
868e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	irq_set_handler_data(pint->irq, pint);
869e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
870e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	list_add_tail(&pint->node, &adi_pint_list);
871e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
872e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
873e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
874e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
875e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_pint_remove(struct platform_device *pdev)
876e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
877e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint *pint = platform_get_drvdata(pdev);
878e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
879e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	list_del(&pint->node);
880e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	irq_set_handler(pint->irq, handle_simple_irq);
881e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
882e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
883e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
884e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
885e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_irq_map(struct irq_domain *d, unsigned int irq,
886e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang				irq_hw_number_t hwirq)
887e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
888e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port = d->host_data;
889e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
890e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!port)
891e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -EINVAL;
892e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
893e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	irq_set_chip_data(irq, port);
894e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	irq_set_chip_and_handler(irq, &adi_gpio_irqchip,
895e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang				handle_level_irq);
896e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
897e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
898e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
899e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
900f77329d1edba3ce8ebfaaa8045b4b99145477141Axel Linstatic const struct irq_domain_ops adi_gpio_irq_domain_ops = {
901e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.map = adi_gpio_irq_map,
902e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.xlate = irq_domain_xlate_onecell,
903e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang};
904e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
905e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_init_int(struct gpio_port *port)
906e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
907e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct device_node *node = port->dev->of_node;
908e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_pint *pint = port->pint;
909e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	int ret;
910e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
911e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->domain = irq_domain_add_linear(node, port->width,
912e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang				&adi_gpio_irq_domain_ops, port);
913e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!port->domain) {
914e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		dev_err(port->dev, "Failed to create irqdomain\n");
915e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -ENOSYS;
916e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
917e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
918e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	/* According to BF54x and BF60x HRM, pin interrupt devices are not
919e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 * part of the GPIO port device. in GPIO interrupt mode, the GPIO
920e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 * pins of multiple port devices can be routed into one pin interrupt
921e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 * device. The mapping can be configured by setting pint assignment
922e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 * register with the mapping value of different GPIO port. This is
923e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 * done via function pint_map_port().
924e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	 */
925e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	ret = pint->pint_map_port(port->pint, port->pint_assign,
926e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			port->pint_map,	port->domain);
927e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (ret)
928e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return ret;
929e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
930e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (port->irq_base >= 0) {
931e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		ret = irq_create_strict_mappings(port->domain, port->irq_base,
932e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang					0, port->width);
933e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		if (ret) {
934e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			dev_err(port->dev, "Couldn't associate to domain\n");
935e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			return ret;
936e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		}
937e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
938e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
939e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
940e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
941e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
942e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#define DEVNAME_SIZE 16
943e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
944e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_probe(struct platform_device *pdev)
945e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
946e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct device *dev = &pdev->dev;
947e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	const struct adi_pinctrl_gpio_platform_data *pdata;
948e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct resource *res;
949e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port;
950e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	char pinctrl_devname[DEVNAME_SIZE];
951e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	static int gpio;
952b4e7c55dabf611cf5cccd1554fec06f72e1c9fafabdoulaye berthe	int ret = 0;
953e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
954e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pdata = dev->platform_data;
955e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!pdata)
956e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -EINVAL;
957e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
958e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port = devm_kzalloc(dev, sizeof(struct gpio_port), GFP_KERNEL);
959e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!port) {
960e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		dev_err(dev, "Memory alloc failed\n");
961e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -ENOMEM;
962e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
963e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
964e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
965c8690d6d2957ed060c1cba4cde3ec41e3829651bAxel Lin	port->base = devm_ioremap_resource(dev, res);
966c8690d6d2957ed060c1cba4cde3ec41e3829651bAxel Lin	if (IS_ERR(port->base))
967c8690d6d2957ed060c1cba4cde3ec41e3829651bAxel Lin		return PTR_ERR(port->base);
968e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
969e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
970e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!res)
971e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port->irq_base = -1;
972e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	else
973e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port->irq_base = res->start;
974e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
975e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->width = pdata->port_width;
976e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->dev = dev;
977e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->regs = (struct gpio_port_t *)port->base;
978e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->pint_assign = pdata->pint_assign;
979e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->pint_map = pdata->pint_map;
980e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
981e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->pint = find_gpio_pint(pdata->pint_id);
982e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (port->pint) {
983e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		ret = adi_gpio_init_int(port);
984e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		if (ret)
985e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			return ret;
986e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
987e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
988e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	spin_lock_init(&port->lock);
989e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
990e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	platform_set_drvdata(pdev, port);
991e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
992e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->chip.label		= "adi-gpio";
993e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->chip.direction_input	= adi_gpio_direction_input;
994e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->chip.get			= adi_gpio_get_value;
995e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->chip.direction_output	= adi_gpio_direction_output;
996e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->chip.set			= adi_gpio_set_value;
997e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->chip.request		= adi_gpio_request;
998e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->chip.free			= adi_gpio_free;
999e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->chip.to_irq		= adi_gpio_to_irq;
1000e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (pdata->port_gpio_base > 0)
1001e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port->chip.base		= pdata->port_gpio_base;
1002e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	else
1003e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		port->chip.base		= gpio;
1004e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	port->chip.ngpio		= port->width;
1005e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	gpio = port->chip.base + port->width;
1006e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1007e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	ret = gpiochip_add(&port->chip);
1008e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (ret) {
1009e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		dev_err(&pdev->dev, "Fail to add GPIO chip.\n");
1010e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		goto out_remove_domain;
1011e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
1012e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1013e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	/* Add gpio pin range */
1014e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	snprintf(pinctrl_devname, DEVNAME_SIZE, "pinctrl-adi2.%d",
1015e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		pdata->pinctrl_id);
1016e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pinctrl_devname[DEVNAME_SIZE - 1] = 0;
1017e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	ret = gpiochip_add_pin_range(&port->chip, pinctrl_devname,
1018e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		0, pdata->port_pin_base, port->width);
1019e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (ret) {
1020e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		dev_err(&pdev->dev, "Fail to add pin range to %s.\n",
1021e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang				pinctrl_devname);
1022e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		goto out_remove_gpiochip;
1023e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
1024e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1025e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	list_add_tail(&port->node, &adi_gpio_port_list);
1026e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1027e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
1028e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1029e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangout_remove_gpiochip:
1030b4e7c55dabf611cf5cccd1554fec06f72e1c9fafabdoulaye berthe	gpiochip_remove(&port->chip);
1031e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangout_remove_domain:
1032e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (port->pint)
1033e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		irq_domain_remove(port->domain);
1034e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1035e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return ret;
1036e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
1037e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1038e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_gpio_remove(struct platform_device *pdev)
1039e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
1040e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct gpio_port *port = platform_get_drvdata(pdev);
1041e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	u8 offset;
1042e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1043e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	list_del(&port->node);
1044b4e7c55dabf611cf5cccd1554fec06f72e1c9fafabdoulaye berthe	gpiochip_remove(&port->chip);
1045e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (port->pint) {
1046e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		for (offset = 0; offset < port->width; offset++)
1047e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang			irq_dispose_mapping(irq_find_mapping(port->domain,
1048e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang				offset));
1049e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		irq_domain_remove(port->domain);
1050e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
1051e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1052b4e7c55dabf611cf5cccd1554fec06f72e1c9fafabdoulaye berthe	return 0;
1053e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
1054e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1055e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_pinctrl_probe(struct platform_device *pdev)
1056e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
1057e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct adi_pinctrl *pinctrl;
1058e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1059e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pinctrl = devm_kzalloc(&pdev->dev, sizeof(*pinctrl), GFP_KERNEL);
1060e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!pinctrl)
1061e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -ENOMEM;
1062e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1063e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pinctrl->dev = &pdev->dev;
1064e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1065e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	adi_pinctrl_soc_init(&pinctrl->soc);
1066e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1067e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	adi_pinmux_desc.pins = pinctrl->soc->pins;
1068e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	adi_pinmux_desc.npins = pinctrl->soc->npins;
1069e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1070e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	/* Now register the pin controller and all pins it handles */
1071e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pinctrl->pctl = pinctrl_register(&adi_pinmux_desc, &pdev->dev, pinctrl);
1072e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (!pinctrl->pctl) {
1073e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		dev_err(&pdev->dev, "could not register pinctrl ADI2 driver\n");
1074e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return -EINVAL;
1075e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	}
1076e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1077e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	platform_set_drvdata(pdev, pinctrl);
1078e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1079e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
1080e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
1081e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1082e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int adi_pinctrl_remove(struct platform_device *pdev)
1083e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
1084e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	struct adi_pinctrl *pinctrl = platform_get_drvdata(pdev);
1085e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1086e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	pinctrl_unregister(pinctrl->pctl);
1087e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1088e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return 0;
1089e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
1090e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1091e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct platform_driver adi_pinctrl_driver = {
1092e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.probe		= adi_pinctrl_probe,
1093e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.remove		= adi_pinctrl_remove,
1094e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.driver		= {
1095e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		.name	= DRIVER_NAME,
1096e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	},
1097e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang};
1098e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1099e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct platform_driver adi_gpio_pint_driver = {
1100e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.probe		= adi_gpio_pint_probe,
1101e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.remove		= adi_gpio_pint_remove,
1102e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.driver		= {
1103e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		.name	= "adi-gpio-pint",
1104e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	},
1105e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang};
1106e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1107e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic struct platform_driver adi_gpio_driver = {
1108e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.probe		= adi_gpio_probe,
1109e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.remove		= adi_gpio_remove,
1110e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	.driver		= {
1111e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		.name	= "adi-gpio",
1112e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	},
1113e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang};
1114e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1115e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangstatic int __init adi_pinctrl_setup(void)
1116e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang{
1117e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	int ret;
1118e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1119e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	ret = platform_driver_register(&adi_pinctrl_driver);
1120e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (ret)
1121e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		return ret;
1122e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1123e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	ret = platform_driver_register(&adi_gpio_pint_driver);
1124e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (ret)
1125e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		goto pint_error;
1126e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1127e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	ret = platform_driver_register(&adi_gpio_driver);
1128e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	if (ret)
1129e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang		goto gpio_error;
1130e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1131e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#ifdef CONFIG_PM
1132e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	register_syscore_ops(&gpio_pm_syscore_ops);
1133e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang#endif
1134e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return ret;
1135e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhanggpio_error:
1136e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	platform_driver_unregister(&adi_gpio_pint_driver);
1137e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangpint_error:
1138e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	platform_driver_unregister(&adi_pinctrl_driver);
1139e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1140e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang	return ret;
1141e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang}
1142e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhangarch_initcall(adi_pinctrl_setup);
1143e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic Zhang
1144e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangMODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
1145e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangMODULE_DESCRIPTION("ADI gpio2 pin control driver");
1146e9a03add0c6ed5341fc59ff9c76843c2888a33faSonic ZhangMODULE_LICENSE("GPL");
1147