xref: /openbmc/linux/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1f876dbffSLinus Walleij // SPDX-License-Identifier: GPL-2.0-only
2616043d5SPramod Kumar /*
318f75c0aSScott Branden  * Copyright (C) 2014-2017 Broadcom
418f75c0aSScott Branden  */
518f75c0aSScott Branden 
618f75c0aSScott Branden /*
7616043d5SPramod Kumar  * This file contains the Broadcom Iproc GPIO driver that supports 3
8616043d5SPramod Kumar  * GPIO controllers on Iproc including the ASIU GPIO controller, the
9616043d5SPramod Kumar  * chipCommonG GPIO controller, and the always-on GPIO controller. Basic
10616043d5SPramod Kumar  * PINCONF such as bias pull up/down, and drive strength are also supported
11616043d5SPramod Kumar  * in this driver.
12616043d5SPramod Kumar  *
13616043d5SPramod Kumar  * It provides the functionality where pins from the GPIO can be
14616043d5SPramod Kumar  * individually muxed to GPIO function, if individual pad
15616043d5SPramod Kumar  * configuration is supported, through the interaction with respective
16616043d5SPramod Kumar  * SoCs IOMUX controller.
17616043d5SPramod Kumar  */
18616043d5SPramod Kumar 
19eebefdd0SAndy Shevchenko #include <linux/gpio/driver.h>
20616043d5SPramod Kumar #include <linux/interrupt.h>
21616043d5SPramod Kumar #include <linux/io.h>
22616043d5SPramod Kumar #include <linux/ioport.h>
23eebefdd0SAndy Shevchenko #include <linux/kernel.h>
24060f03e9SRob Herring #include <linux/of.h>
25060f03e9SRob Herring #include <linux/platform_device.h>
262cc4485eSLinus Walleij #include <linux/seq_file.h>
27eebefdd0SAndy Shevchenko #include <linux/slab.h>
28eebefdd0SAndy Shevchenko 
29eebefdd0SAndy Shevchenko #include <linux/pinctrl/consumer.h>
30616043d5SPramod Kumar #include <linux/pinctrl/pinconf-generic.h>
31eebefdd0SAndy Shevchenko #include <linux/pinctrl/pinconf.h>
32eebefdd0SAndy Shevchenko #include <linux/pinctrl/pinctrl.h>
33616043d5SPramod Kumar 
34616043d5SPramod Kumar #include "../pinctrl-utils.h"
35616043d5SPramod Kumar 
36616043d5SPramod Kumar #define IPROC_GPIO_DATA_IN_OFFSET   0x00
37616043d5SPramod Kumar #define IPROC_GPIO_DATA_OUT_OFFSET  0x04
38616043d5SPramod Kumar #define IPROC_GPIO_OUT_EN_OFFSET    0x08
39616043d5SPramod Kumar #define IPROC_GPIO_INT_TYPE_OFFSET  0x0c
40616043d5SPramod Kumar #define IPROC_GPIO_INT_DE_OFFSET    0x10
41616043d5SPramod Kumar #define IPROC_GPIO_INT_EDGE_OFFSET  0x14
42616043d5SPramod Kumar #define IPROC_GPIO_INT_MSK_OFFSET   0x18
43616043d5SPramod Kumar #define IPROC_GPIO_INT_STAT_OFFSET  0x1c
44616043d5SPramod Kumar #define IPROC_GPIO_INT_MSTAT_OFFSET 0x20
45616043d5SPramod Kumar #define IPROC_GPIO_INT_CLR_OFFSET   0x24
46616043d5SPramod Kumar #define IPROC_GPIO_PAD_RES_OFFSET   0x34
47616043d5SPramod Kumar #define IPROC_GPIO_RES_EN_OFFSET    0x38
48616043d5SPramod Kumar 
49616043d5SPramod Kumar /* drive strength control for ASIU GPIO */
50616043d5SPramod Kumar #define IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET 0x58
51616043d5SPramod Kumar 
52398a1f50SLi Jin /* pinconf for CCM GPIO */
53398a1f50SLi Jin #define IPROC_GPIO_PULL_DN_OFFSET   0x10
54398a1f50SLi Jin #define IPROC_GPIO_PULL_UP_OFFSET   0x14
55398a1f50SLi Jin 
56398a1f50SLi Jin /* pinconf for CRMU(aon) GPIO and CCM GPIO*/
57398a1f50SLi Jin #define IPROC_GPIO_DRV_CTRL_OFFSET  0x00
58616043d5SPramod Kumar 
59616043d5SPramod Kumar #define GPIO_BANK_SIZE 0x200
60616043d5SPramod Kumar #define NGPIOS_PER_BANK 32
61616043d5SPramod Kumar #define GPIO_BANK(pin) ((pin) / NGPIOS_PER_BANK)
62616043d5SPramod Kumar 
63616043d5SPramod Kumar #define IPROC_GPIO_REG(pin, reg) (GPIO_BANK(pin) * GPIO_BANK_SIZE + (reg))
64616043d5SPramod Kumar #define IPROC_GPIO_SHIFT(pin) ((pin) % NGPIOS_PER_BANK)
65616043d5SPramod Kumar 
66616043d5SPramod Kumar #define GPIO_DRV_STRENGTH_BIT_SHIFT  20
67616043d5SPramod Kumar #define GPIO_DRV_STRENGTH_BITS       3
68616043d5SPramod Kumar #define GPIO_DRV_STRENGTH_BIT_MASK   ((1 << GPIO_DRV_STRENGTH_BITS) - 1)
69616043d5SPramod Kumar 
70f58de3d9SRay Jui enum iproc_pinconf_param {
71f58de3d9SRay Jui 	IPROC_PINCONF_DRIVE_STRENGTH = 0,
72f58de3d9SRay Jui 	IPROC_PINCONF_BIAS_DISABLE,
73f58de3d9SRay Jui 	IPROC_PINCONF_BIAS_PULL_UP,
74f58de3d9SRay Jui 	IPROC_PINCONF_BIAS_PULL_DOWN,
75f58de3d9SRay Jui 	IPROC_PINCON_MAX,
76f58de3d9SRay Jui };
77f58de3d9SRay Jui 
78398a1f50SLi Jin enum iproc_pinconf_ctrl_type {
79398a1f50SLi Jin 	IOCTRL_TYPE_AON = 1,
80398a1f50SLi Jin 	IOCTRL_TYPE_CDRU,
81398a1f50SLi Jin 	IOCTRL_TYPE_INVALID,
82398a1f50SLi Jin };
83398a1f50SLi Jin 
84616043d5SPramod Kumar /*
85616043d5SPramod Kumar  * Iproc GPIO core
86616043d5SPramod Kumar  *
87616043d5SPramod Kumar  * @dev: pointer to device
88616043d5SPramod Kumar  * @base: I/O register base for Iproc GPIO controller
89616043d5SPramod Kumar  * @io_ctrl: I/O register base for certain type of Iproc GPIO controller that
90616043d5SPramod Kumar  * has the PINCONF support implemented outside of the GPIO block
91616043d5SPramod Kumar  * @lock: lock to protect access to I/O registers
92616043d5SPramod Kumar  * @gc: GPIO chip
93616043d5SPramod Kumar  * @num_banks: number of GPIO banks, each bank supports up to 32 GPIOs
94616043d5SPramod Kumar  * @pinmux_is_supported: flag to indicate this GPIO controller contains pins
95616043d5SPramod Kumar  * that can be individually muxed to GPIO
96f58de3d9SRay Jui  * @pinconf_disable: contains a list of PINCONF parameters that need to be
97f58de3d9SRay Jui  * disabled
98f58de3d9SRay Jui  * @nr_pinconf_disable: total number of PINCONF parameters that need to be
99f58de3d9SRay Jui  * disabled
100616043d5SPramod Kumar  * @pctl: pointer to pinctrl_dev
101616043d5SPramod Kumar  * @pctldesc: pinctrl descriptor
102616043d5SPramod Kumar  */
103616043d5SPramod Kumar struct iproc_gpio {
104616043d5SPramod Kumar 	struct device *dev;
105616043d5SPramod Kumar 
106616043d5SPramod Kumar 	void __iomem *base;
107616043d5SPramod Kumar 	void __iomem *io_ctrl;
108398a1f50SLi Jin 	enum iproc_pinconf_ctrl_type io_ctrl_type;
109616043d5SPramod Kumar 
110cb96a662SJulia Cartwright 	raw_spinlock_t lock;
111616043d5SPramod Kumar 
112616043d5SPramod Kumar 	struct gpio_chip gc;
113616043d5SPramod Kumar 	unsigned num_banks;
114616043d5SPramod Kumar 
115616043d5SPramod Kumar 	bool pinmux_is_supported;
116616043d5SPramod Kumar 
117f58de3d9SRay Jui 	enum pin_config_param *pinconf_disable;
118f58de3d9SRay Jui 	unsigned int nr_pinconf_disable;
119f58de3d9SRay Jui 
120616043d5SPramod Kumar 	struct pinctrl_dev *pctl;
121616043d5SPramod Kumar 	struct pinctrl_desc pctldesc;
122616043d5SPramod Kumar };
123616043d5SPramod Kumar 
124616043d5SPramod Kumar /*
125616043d5SPramod Kumar  * Mapping from PINCONF pins to GPIO pins is 1-to-1
126616043d5SPramod Kumar  */
iproc_pin_to_gpio(unsigned pin)127616043d5SPramod Kumar static inline unsigned iproc_pin_to_gpio(unsigned pin)
128616043d5SPramod Kumar {
129616043d5SPramod Kumar 	return pin;
130616043d5SPramod Kumar }
131616043d5SPramod Kumar 
132616043d5SPramod Kumar /**
133616043d5SPramod Kumar  *  iproc_set_bit - set or clear one bit (corresponding to the GPIO pin) in a
134616043d5SPramod Kumar  *  Iproc GPIO register
135616043d5SPramod Kumar  *
1362dd2dbc5SLee Jones  *  @chip: Iproc GPIO device
137616043d5SPramod Kumar  *  @reg: register offset
138616043d5SPramod Kumar  *  @gpio: GPIO pin
139616043d5SPramod Kumar  *  @set: set or clear
140616043d5SPramod Kumar  */
iproc_set_bit(struct iproc_gpio * chip,unsigned int reg,unsigned gpio,bool set)141616043d5SPramod Kumar static inline void iproc_set_bit(struct iproc_gpio *chip, unsigned int reg,
142616043d5SPramod Kumar 				  unsigned gpio, bool set)
143616043d5SPramod Kumar {
144616043d5SPramod Kumar 	unsigned int offset = IPROC_GPIO_REG(gpio, reg);
145616043d5SPramod Kumar 	unsigned int shift = IPROC_GPIO_SHIFT(gpio);
146616043d5SPramod Kumar 	u32 val;
147616043d5SPramod Kumar 
148616043d5SPramod Kumar 	val = readl(chip->base + offset);
149616043d5SPramod Kumar 	if (set)
150616043d5SPramod Kumar 		val |= BIT(shift);
151616043d5SPramod Kumar 	else
152616043d5SPramod Kumar 		val &= ~BIT(shift);
153616043d5SPramod Kumar 	writel(val, chip->base + offset);
154616043d5SPramod Kumar }
155616043d5SPramod Kumar 
iproc_get_bit(struct iproc_gpio * chip,unsigned int reg,unsigned gpio)156616043d5SPramod Kumar static inline bool iproc_get_bit(struct iproc_gpio *chip, unsigned int reg,
157616043d5SPramod Kumar 				  unsigned gpio)
158616043d5SPramod Kumar {
159616043d5SPramod Kumar 	unsigned int offset = IPROC_GPIO_REG(gpio, reg);
160616043d5SPramod Kumar 	unsigned int shift = IPROC_GPIO_SHIFT(gpio);
161616043d5SPramod Kumar 
162616043d5SPramod Kumar 	return !!(readl(chip->base + offset) & BIT(shift));
163616043d5SPramod Kumar }
164616043d5SPramod Kumar 
iproc_gpio_irq_handler(struct irq_desc * desc)165616043d5SPramod Kumar static void iproc_gpio_irq_handler(struct irq_desc *desc)
166616043d5SPramod Kumar {
167616043d5SPramod Kumar 	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
16869fd6aeaSLinus Walleij 	struct iproc_gpio *chip = gpiochip_get_data(gc);
169616043d5SPramod Kumar 	struct irq_chip *irq_chip = irq_desc_get_chip(desc);
170616043d5SPramod Kumar 	int i, bit;
171616043d5SPramod Kumar 
172616043d5SPramod Kumar 	chained_irq_enter(irq_chip, desc);
173616043d5SPramod Kumar 
174616043d5SPramod Kumar 	/* go through the entire GPIO banks and handle all interrupts */
175616043d5SPramod Kumar 	for (i = 0; i < chip->num_banks; i++) {
176616043d5SPramod Kumar 		unsigned long val = readl(chip->base + (i * GPIO_BANK_SIZE) +
177616043d5SPramod Kumar 					  IPROC_GPIO_INT_MSTAT_OFFSET);
178616043d5SPramod Kumar 
179616043d5SPramod Kumar 		for_each_set_bit(bit, &val, NGPIOS_PER_BANK) {
180616043d5SPramod Kumar 			unsigned pin = NGPIOS_PER_BANK * i + bit;
181616043d5SPramod Kumar 
182616043d5SPramod Kumar 			/*
183616043d5SPramod Kumar 			 * Clear the interrupt before invoking the
184616043d5SPramod Kumar 			 * handler, so we do not leave any window
185616043d5SPramod Kumar 			 */
186616043d5SPramod Kumar 			writel(BIT(bit), chip->base + (i * GPIO_BANK_SIZE) +
187616043d5SPramod Kumar 			       IPROC_GPIO_INT_CLR_OFFSET);
188616043d5SPramod Kumar 
189a9cb09b7SMarc Zyngier 			generic_handle_domain_irq(gc->irq.domain, pin);
190616043d5SPramod Kumar 		}
191616043d5SPramod Kumar 	}
192616043d5SPramod Kumar 
193616043d5SPramod Kumar 	chained_irq_exit(irq_chip, desc);
194616043d5SPramod Kumar }
195616043d5SPramod Kumar 
196616043d5SPramod Kumar 
iproc_gpio_irq_ack(struct irq_data * d)197616043d5SPramod Kumar static void iproc_gpio_irq_ack(struct irq_data *d)
198616043d5SPramod Kumar {
199616043d5SPramod Kumar 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
20069fd6aeaSLinus Walleij 	struct iproc_gpio *chip = gpiochip_get_data(gc);
201616043d5SPramod Kumar 	unsigned gpio = d->hwirq;
202616043d5SPramod Kumar 	unsigned int offset = IPROC_GPIO_REG(gpio,
203616043d5SPramod Kumar 			IPROC_GPIO_INT_CLR_OFFSET);
204616043d5SPramod Kumar 	unsigned int shift = IPROC_GPIO_SHIFT(gpio);
205616043d5SPramod Kumar 	u32 val = BIT(shift);
206616043d5SPramod Kumar 
207616043d5SPramod Kumar 	writel(val, chip->base + offset);
208616043d5SPramod Kumar }
209616043d5SPramod Kumar 
210616043d5SPramod Kumar /**
211616043d5SPramod Kumar  *  iproc_gpio_irq_set_mask - mask/unmask a GPIO interrupt
212616043d5SPramod Kumar  *
213616043d5SPramod Kumar  *  @d: IRQ chip data
214616043d5SPramod Kumar  *  @unmask: mask/unmask GPIO interrupt
215616043d5SPramod Kumar  */
iproc_gpio_irq_set_mask(struct irq_data * d,bool unmask)216616043d5SPramod Kumar static void iproc_gpio_irq_set_mask(struct irq_data *d, bool unmask)
217616043d5SPramod Kumar {
218616043d5SPramod Kumar 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
21969fd6aeaSLinus Walleij 	struct iproc_gpio *chip = gpiochip_get_data(gc);
2202cc4485eSLinus Walleij 	unsigned gpio = irqd_to_hwirq(d);
221616043d5SPramod Kumar 
222616043d5SPramod Kumar 	iproc_set_bit(chip, IPROC_GPIO_INT_MSK_OFFSET, gpio, unmask);
223616043d5SPramod Kumar }
224616043d5SPramod Kumar 
iproc_gpio_irq_mask(struct irq_data * d)225616043d5SPramod Kumar static void iproc_gpio_irq_mask(struct irq_data *d)
226616043d5SPramod Kumar {
227616043d5SPramod Kumar 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
22869fd6aeaSLinus Walleij 	struct iproc_gpio *chip = gpiochip_get_data(gc);
229616043d5SPramod Kumar 	unsigned long flags;
230616043d5SPramod Kumar 
231cb96a662SJulia Cartwright 	raw_spin_lock_irqsave(&chip->lock, flags);
232616043d5SPramod Kumar 	iproc_gpio_irq_set_mask(d, false);
233cb96a662SJulia Cartwright 	raw_spin_unlock_irqrestore(&chip->lock, flags);
2342cc4485eSLinus Walleij 	gpiochip_disable_irq(gc, irqd_to_hwirq(d));
235616043d5SPramod Kumar }
236616043d5SPramod Kumar 
iproc_gpio_irq_unmask(struct irq_data * d)237616043d5SPramod Kumar static void iproc_gpio_irq_unmask(struct irq_data *d)
238616043d5SPramod Kumar {
239616043d5SPramod Kumar 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
24069fd6aeaSLinus Walleij 	struct iproc_gpio *chip = gpiochip_get_data(gc);
241616043d5SPramod Kumar 	unsigned long flags;
242616043d5SPramod Kumar 
2432cc4485eSLinus Walleij 	gpiochip_enable_irq(gc, irqd_to_hwirq(d));
244cb96a662SJulia Cartwright 	raw_spin_lock_irqsave(&chip->lock, flags);
245616043d5SPramod Kumar 	iproc_gpio_irq_set_mask(d, true);
246cb96a662SJulia Cartwright 	raw_spin_unlock_irqrestore(&chip->lock, flags);
247616043d5SPramod Kumar }
248616043d5SPramod Kumar 
iproc_gpio_irq_set_type(struct irq_data * d,unsigned int type)249616043d5SPramod Kumar static int iproc_gpio_irq_set_type(struct irq_data *d, unsigned int type)
250616043d5SPramod Kumar {
251616043d5SPramod Kumar 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
25269fd6aeaSLinus Walleij 	struct iproc_gpio *chip = gpiochip_get_data(gc);
253616043d5SPramod Kumar 	unsigned gpio = d->hwirq;
254616043d5SPramod Kumar 	bool level_triggered = false;
255616043d5SPramod Kumar 	bool dual_edge = false;
256616043d5SPramod Kumar 	bool rising_or_high = false;
257616043d5SPramod Kumar 	unsigned long flags;
258616043d5SPramod Kumar 
259616043d5SPramod Kumar 	switch (type & IRQ_TYPE_SENSE_MASK) {
260616043d5SPramod Kumar 	case IRQ_TYPE_EDGE_RISING:
261616043d5SPramod Kumar 		rising_or_high = true;
262616043d5SPramod Kumar 		break;
263616043d5SPramod Kumar 
264616043d5SPramod Kumar 	case IRQ_TYPE_EDGE_FALLING:
265616043d5SPramod Kumar 		break;
266616043d5SPramod Kumar 
267616043d5SPramod Kumar 	case IRQ_TYPE_EDGE_BOTH:
268616043d5SPramod Kumar 		dual_edge = true;
269616043d5SPramod Kumar 		break;
270616043d5SPramod Kumar 
271616043d5SPramod Kumar 	case IRQ_TYPE_LEVEL_HIGH:
272616043d5SPramod Kumar 		level_triggered = true;
273616043d5SPramod Kumar 		rising_or_high = true;
274616043d5SPramod Kumar 		break;
275616043d5SPramod Kumar 
276616043d5SPramod Kumar 	case IRQ_TYPE_LEVEL_LOW:
277616043d5SPramod Kumar 		level_triggered = true;
278616043d5SPramod Kumar 		break;
279616043d5SPramod Kumar 
280616043d5SPramod Kumar 	default:
281616043d5SPramod Kumar 		dev_err(chip->dev, "invalid GPIO IRQ type 0x%x\n",
282616043d5SPramod Kumar 			type);
283616043d5SPramod Kumar 		return -EINVAL;
284616043d5SPramod Kumar 	}
285616043d5SPramod Kumar 
286cb96a662SJulia Cartwright 	raw_spin_lock_irqsave(&chip->lock, flags);
287616043d5SPramod Kumar 	iproc_set_bit(chip, IPROC_GPIO_INT_TYPE_OFFSET, gpio,
288616043d5SPramod Kumar 		       level_triggered);
289616043d5SPramod Kumar 	iproc_set_bit(chip, IPROC_GPIO_INT_DE_OFFSET, gpio, dual_edge);
290616043d5SPramod Kumar 	iproc_set_bit(chip, IPROC_GPIO_INT_EDGE_OFFSET, gpio,
291616043d5SPramod Kumar 		       rising_or_high);
292534ad357SHamish Martin 
293534ad357SHamish Martin 	if (type & IRQ_TYPE_EDGE_BOTH)
294534ad357SHamish Martin 		irq_set_handler_locked(d, handle_edge_irq);
295534ad357SHamish Martin 	else
296534ad357SHamish Martin 		irq_set_handler_locked(d, handle_level_irq);
297534ad357SHamish Martin 
298cb96a662SJulia Cartwright 	raw_spin_unlock_irqrestore(&chip->lock, flags);
299616043d5SPramod Kumar 
300616043d5SPramod Kumar 	dev_dbg(chip->dev,
301616043d5SPramod Kumar 		"gpio:%u level_triggered:%d dual_edge:%d rising_or_high:%d\n",
302616043d5SPramod Kumar 		gpio, level_triggered, dual_edge, rising_or_high);
303616043d5SPramod Kumar 
304616043d5SPramod Kumar 	return 0;
305616043d5SPramod Kumar }
306616043d5SPramod Kumar 
iproc_gpio_irq_print_chip(struct irq_data * d,struct seq_file * p)3072cc4485eSLinus Walleij static void iproc_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p)
3082cc4485eSLinus Walleij {
3092cc4485eSLinus Walleij 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
3102cc4485eSLinus Walleij 	struct iproc_gpio *chip = gpiochip_get_data(gc);
3112cc4485eSLinus Walleij 
3122cc4485eSLinus Walleij 	seq_printf(p, dev_name(chip->dev));
3132cc4485eSLinus Walleij }
3142cc4485eSLinus Walleij 
3152cc4485eSLinus Walleij static const struct irq_chip iproc_gpio_irq_chip = {
3162cc4485eSLinus Walleij 	.irq_ack = iproc_gpio_irq_ack,
3172cc4485eSLinus Walleij 	.irq_mask = iproc_gpio_irq_mask,
3182cc4485eSLinus Walleij 	.irq_unmask = iproc_gpio_irq_unmask,
3192cc4485eSLinus Walleij 	.irq_set_type = iproc_gpio_irq_set_type,
3202cc4485eSLinus Walleij 	.irq_enable = iproc_gpio_irq_unmask,
3212cc4485eSLinus Walleij 	.irq_disable = iproc_gpio_irq_mask,
3222cc4485eSLinus Walleij 	.irq_print_chip = iproc_gpio_irq_print_chip,
3232cc4485eSLinus Walleij 	.flags = IRQCHIP_IMMUTABLE,
3242cc4485eSLinus Walleij 	GPIOCHIP_IRQ_RESOURCE_HELPERS,
3252cc4485eSLinus Walleij };
3262cc4485eSLinus Walleij 
327616043d5SPramod Kumar /*
328616043d5SPramod Kumar  * Request the Iproc IOMUX pinmux controller to mux individual pins to GPIO
329616043d5SPramod Kumar  */
iproc_gpio_request(struct gpio_chip * gc,unsigned offset)330616043d5SPramod Kumar static int iproc_gpio_request(struct gpio_chip *gc, unsigned offset)
331616043d5SPramod Kumar {
33269fd6aeaSLinus Walleij 	struct iproc_gpio *chip = gpiochip_get_data(gc);
333616043d5SPramod Kumar 	unsigned gpio = gc->base + offset;
334616043d5SPramod Kumar 
335616043d5SPramod Kumar 	/* not all Iproc GPIO pins can be muxed individually */
336616043d5SPramod Kumar 	if (!chip->pinmux_is_supported)
337616043d5SPramod Kumar 		return 0;
338616043d5SPramod Kumar 
339a9a1d2a7SLinus Walleij 	return pinctrl_gpio_request(gpio);
340616043d5SPramod Kumar }
341616043d5SPramod Kumar 
iproc_gpio_free(struct gpio_chip * gc,unsigned offset)342616043d5SPramod Kumar static void iproc_gpio_free(struct gpio_chip *gc, unsigned offset)
343616043d5SPramod Kumar {
34469fd6aeaSLinus Walleij 	struct iproc_gpio *chip = gpiochip_get_data(gc);
345616043d5SPramod Kumar 	unsigned gpio = gc->base + offset;
346616043d5SPramod Kumar 
347616043d5SPramod Kumar 	if (!chip->pinmux_is_supported)
348616043d5SPramod Kumar 		return;
349616043d5SPramod Kumar 
350a9a1d2a7SLinus Walleij 	pinctrl_gpio_free(gpio);
351616043d5SPramod Kumar }
352616043d5SPramod Kumar 
iproc_gpio_direction_input(struct gpio_chip * gc,unsigned gpio)353616043d5SPramod Kumar static int iproc_gpio_direction_input(struct gpio_chip *gc, unsigned gpio)
354616043d5SPramod Kumar {
35569fd6aeaSLinus Walleij 	struct iproc_gpio *chip = gpiochip_get_data(gc);
356616043d5SPramod Kumar 	unsigned long flags;
357616043d5SPramod Kumar 
358cb96a662SJulia Cartwright 	raw_spin_lock_irqsave(&chip->lock, flags);
359616043d5SPramod Kumar 	iproc_set_bit(chip, IPROC_GPIO_OUT_EN_OFFSET, gpio, false);
360cb96a662SJulia Cartwright 	raw_spin_unlock_irqrestore(&chip->lock, flags);
361616043d5SPramod Kumar 
362616043d5SPramod Kumar 	dev_dbg(chip->dev, "gpio:%u set input\n", gpio);
363616043d5SPramod Kumar 
364616043d5SPramod Kumar 	return 0;
365616043d5SPramod Kumar }
366616043d5SPramod Kumar 
iproc_gpio_direction_output(struct gpio_chip * gc,unsigned gpio,int val)367616043d5SPramod Kumar static int iproc_gpio_direction_output(struct gpio_chip *gc, unsigned gpio,
368616043d5SPramod Kumar 					int val)
369616043d5SPramod Kumar {
37069fd6aeaSLinus Walleij 	struct iproc_gpio *chip = gpiochip_get_data(gc);
371616043d5SPramod Kumar 	unsigned long flags;
372616043d5SPramod Kumar 
373cb96a662SJulia Cartwright 	raw_spin_lock_irqsave(&chip->lock, flags);
374616043d5SPramod Kumar 	iproc_set_bit(chip, IPROC_GPIO_OUT_EN_OFFSET, gpio, true);
375616043d5SPramod Kumar 	iproc_set_bit(chip, IPROC_GPIO_DATA_OUT_OFFSET, gpio, !!(val));
376cb96a662SJulia Cartwright 	raw_spin_unlock_irqrestore(&chip->lock, flags);
377616043d5SPramod Kumar 
378616043d5SPramod Kumar 	dev_dbg(chip->dev, "gpio:%u set output, value:%d\n", gpio, val);
379616043d5SPramod Kumar 
380616043d5SPramod Kumar 	return 0;
381616043d5SPramod Kumar }
382616043d5SPramod Kumar 
iproc_gpio_get_direction(struct gpio_chip * gc,unsigned int gpio)38303518271SRayagonda Kokatanur static int iproc_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio)
38403518271SRayagonda Kokatanur {
38503518271SRayagonda Kokatanur 	struct iproc_gpio *chip = gpiochip_get_data(gc);
38603518271SRayagonda Kokatanur 	unsigned int offset = IPROC_GPIO_REG(gpio, IPROC_GPIO_OUT_EN_OFFSET);
38703518271SRayagonda Kokatanur 	unsigned int shift = IPROC_GPIO_SHIFT(gpio);
38803518271SRayagonda Kokatanur 
3893c827873SMatti Vaittinen 	if (readl(chip->base + offset) & BIT(shift))
3903c827873SMatti Vaittinen 		return GPIO_LINE_DIRECTION_OUT;
3913c827873SMatti Vaittinen 
3923c827873SMatti Vaittinen 	return GPIO_LINE_DIRECTION_IN;
39303518271SRayagonda Kokatanur }
39403518271SRayagonda Kokatanur 
iproc_gpio_set(struct gpio_chip * gc,unsigned gpio,int val)395616043d5SPramod Kumar static void iproc_gpio_set(struct gpio_chip *gc, unsigned gpio, int val)
396616043d5SPramod Kumar {
39769fd6aeaSLinus Walleij 	struct iproc_gpio *chip = gpiochip_get_data(gc);
398616043d5SPramod Kumar 	unsigned long flags;
399616043d5SPramod Kumar 
400cb96a662SJulia Cartwright 	raw_spin_lock_irqsave(&chip->lock, flags);
401616043d5SPramod Kumar 	iproc_set_bit(chip, IPROC_GPIO_DATA_OUT_OFFSET, gpio, !!(val));
402cb96a662SJulia Cartwright 	raw_spin_unlock_irqrestore(&chip->lock, flags);
403616043d5SPramod Kumar 
404616043d5SPramod Kumar 	dev_dbg(chip->dev, "gpio:%u set, value:%d\n", gpio, val);
405616043d5SPramod Kumar }
406616043d5SPramod Kumar 
iproc_gpio_get(struct gpio_chip * gc,unsigned gpio)407616043d5SPramod Kumar static int iproc_gpio_get(struct gpio_chip *gc, unsigned gpio)
408616043d5SPramod Kumar {
40969fd6aeaSLinus Walleij 	struct iproc_gpio *chip = gpiochip_get_data(gc);
410616043d5SPramod Kumar 	unsigned int offset = IPROC_GPIO_REG(gpio,
411616043d5SPramod Kumar 					      IPROC_GPIO_DATA_IN_OFFSET);
412616043d5SPramod Kumar 	unsigned int shift = IPROC_GPIO_SHIFT(gpio);
413616043d5SPramod Kumar 
414616043d5SPramod Kumar 	return !!(readl(chip->base + offset) & BIT(shift));
415616043d5SPramod Kumar }
416616043d5SPramod Kumar 
417f58de3d9SRay Jui /*
418f58de3d9SRay Jui  * Mapping of the iProc PINCONF parameters to the generic pin configuration
419f58de3d9SRay Jui  * parameters
420f58de3d9SRay Jui  */
421f58de3d9SRay Jui static const enum pin_config_param iproc_pinconf_disable_map[] = {
422f58de3d9SRay Jui 	[IPROC_PINCONF_DRIVE_STRENGTH] = PIN_CONFIG_DRIVE_STRENGTH,
423f58de3d9SRay Jui 	[IPROC_PINCONF_BIAS_DISABLE] = PIN_CONFIG_BIAS_DISABLE,
424f58de3d9SRay Jui 	[IPROC_PINCONF_BIAS_PULL_UP] = PIN_CONFIG_BIAS_PULL_UP,
425f58de3d9SRay Jui 	[IPROC_PINCONF_BIAS_PULL_DOWN] = PIN_CONFIG_BIAS_PULL_DOWN,
426f58de3d9SRay Jui };
427f58de3d9SRay Jui 
iproc_pinconf_param_is_disabled(struct iproc_gpio * chip,enum pin_config_param param)428f58de3d9SRay Jui static bool iproc_pinconf_param_is_disabled(struct iproc_gpio *chip,
429f58de3d9SRay Jui 					    enum pin_config_param param)
430f58de3d9SRay Jui {
431f58de3d9SRay Jui 	unsigned int i;
432f58de3d9SRay Jui 
433f58de3d9SRay Jui 	if (!chip->nr_pinconf_disable)
434f58de3d9SRay Jui 		return false;
435f58de3d9SRay Jui 
436f58de3d9SRay Jui 	for (i = 0; i < chip->nr_pinconf_disable; i++)
437f58de3d9SRay Jui 		if (chip->pinconf_disable[i] == param)
438f58de3d9SRay Jui 			return true;
439f58de3d9SRay Jui 
440f58de3d9SRay Jui 	return false;
441f58de3d9SRay Jui }
442f58de3d9SRay Jui 
iproc_pinconf_disable_map_create(struct iproc_gpio * chip,unsigned long disable_mask)443f58de3d9SRay Jui static int iproc_pinconf_disable_map_create(struct iproc_gpio *chip,
444f58de3d9SRay Jui 					    unsigned long disable_mask)
445f58de3d9SRay Jui {
446f58de3d9SRay Jui 	unsigned int map_size = ARRAY_SIZE(iproc_pinconf_disable_map);
447f58de3d9SRay Jui 	unsigned int bit, nbits = 0;
448f58de3d9SRay Jui 
449f58de3d9SRay Jui 	/* figure out total number of PINCONF parameters to disable */
450f58de3d9SRay Jui 	for_each_set_bit(bit, &disable_mask, map_size)
451f58de3d9SRay Jui 		nbits++;
452f58de3d9SRay Jui 
453f58de3d9SRay Jui 	if (!nbits)
454f58de3d9SRay Jui 		return 0;
455f58de3d9SRay Jui 
456f58de3d9SRay Jui 	/*
457f58de3d9SRay Jui 	 * Allocate an array to store PINCONF parameters that need to be
458f58de3d9SRay Jui 	 * disabled
459f58de3d9SRay Jui 	 */
460f58de3d9SRay Jui 	chip->pinconf_disable = devm_kcalloc(chip->dev, nbits,
461f58de3d9SRay Jui 					     sizeof(*chip->pinconf_disable),
462f58de3d9SRay Jui 					     GFP_KERNEL);
463f58de3d9SRay Jui 	if (!chip->pinconf_disable)
464f58de3d9SRay Jui 		return -ENOMEM;
465f58de3d9SRay Jui 
466f58de3d9SRay Jui 	chip->nr_pinconf_disable = nbits;
467f58de3d9SRay Jui 
468f58de3d9SRay Jui 	/* now store these parameters */
469f58de3d9SRay Jui 	nbits = 0;
470f58de3d9SRay Jui 	for_each_set_bit(bit, &disable_mask, map_size)
471f58de3d9SRay Jui 		chip->pinconf_disable[nbits++] = iproc_pinconf_disable_map[bit];
472f58de3d9SRay Jui 
473f58de3d9SRay Jui 	return 0;
474f58de3d9SRay Jui }
475f58de3d9SRay Jui 
iproc_get_groups_count(struct pinctrl_dev * pctldev)476616043d5SPramod Kumar static int iproc_get_groups_count(struct pinctrl_dev *pctldev)
477616043d5SPramod Kumar {
478616043d5SPramod Kumar 	return 1;
479616043d5SPramod Kumar }
480616043d5SPramod Kumar 
481616043d5SPramod Kumar /*
482616043d5SPramod Kumar  * Only one group: "gpio_grp", since this local pinctrl device only performs
483616043d5SPramod Kumar  * GPIO specific PINCONF configurations
484616043d5SPramod Kumar  */
iproc_get_group_name(struct pinctrl_dev * pctldev,unsigned selector)485616043d5SPramod Kumar static const char *iproc_get_group_name(struct pinctrl_dev *pctldev,
486616043d5SPramod Kumar 					 unsigned selector)
487616043d5SPramod Kumar {
488616043d5SPramod Kumar 	return "gpio_grp";
489616043d5SPramod Kumar }
490616043d5SPramod Kumar 
491616043d5SPramod Kumar static const struct pinctrl_ops iproc_pctrl_ops = {
492616043d5SPramod Kumar 	.get_groups_count = iproc_get_groups_count,
493616043d5SPramod Kumar 	.get_group_name = iproc_get_group_name,
494616043d5SPramod Kumar 	.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
495d32f7fd3SIrina Tirdea 	.dt_free_map = pinctrl_utils_free_map,
496616043d5SPramod Kumar };
497616043d5SPramod Kumar 
iproc_gpio_set_pull(struct iproc_gpio * chip,unsigned gpio,bool disable,bool pull_up)498616043d5SPramod Kumar static int iproc_gpio_set_pull(struct iproc_gpio *chip, unsigned gpio,
499616043d5SPramod Kumar 				bool disable, bool pull_up)
500616043d5SPramod Kumar {
501398a1f50SLi Jin 	void __iomem *base;
502616043d5SPramod Kumar 	unsigned long flags;
503398a1f50SLi Jin 	unsigned int shift;
504398a1f50SLi Jin 	u32 val_1, val_2;
505616043d5SPramod Kumar 
506cb96a662SJulia Cartwright 	raw_spin_lock_irqsave(&chip->lock, flags);
507398a1f50SLi Jin 	if (chip->io_ctrl_type == IOCTRL_TYPE_CDRU) {
508398a1f50SLi Jin 		base = chip->io_ctrl;
509398a1f50SLi Jin 		shift = IPROC_GPIO_SHIFT(gpio);
510616043d5SPramod Kumar 
511398a1f50SLi Jin 		val_1 = readl(base + IPROC_GPIO_PULL_UP_OFFSET);
512398a1f50SLi Jin 		val_2 = readl(base + IPROC_GPIO_PULL_DN_OFFSET);
513616043d5SPramod Kumar 		if (disable) {
514398a1f50SLi Jin 			/* no pull-up or pull-down */
515398a1f50SLi Jin 			val_1 &= ~BIT(shift);
516398a1f50SLi Jin 			val_2 &= ~BIT(shift);
517398a1f50SLi Jin 		} else if (pull_up) {
518398a1f50SLi Jin 			val_1 |= BIT(shift);
519398a1f50SLi Jin 			val_2 &= ~BIT(shift);
520398a1f50SLi Jin 		} else {
521398a1f50SLi Jin 			val_1 &= ~BIT(shift);
522398a1f50SLi Jin 			val_2 |= BIT(shift);
523398a1f50SLi Jin 		}
524398a1f50SLi Jin 		writel(val_1, base + IPROC_GPIO_PULL_UP_OFFSET);
525398a1f50SLi Jin 		writel(val_2, base + IPROC_GPIO_PULL_DN_OFFSET);
526398a1f50SLi Jin 	} else {
527398a1f50SLi Jin 		if (disable) {
528398a1f50SLi Jin 			iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio,
529398a1f50SLi Jin 				      false);
530616043d5SPramod Kumar 		} else {
531616043d5SPramod Kumar 			iproc_set_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio,
532616043d5SPramod Kumar 				      pull_up);
533398a1f50SLi Jin 			iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio,
534398a1f50SLi Jin 				      true);
535398a1f50SLi Jin 		}
536616043d5SPramod Kumar 	}
537616043d5SPramod Kumar 
538cb96a662SJulia Cartwright 	raw_spin_unlock_irqrestore(&chip->lock, flags);
539616043d5SPramod Kumar 	dev_dbg(chip->dev, "gpio:%u set pullup:%d\n", gpio, pull_up);
540616043d5SPramod Kumar 
541616043d5SPramod Kumar 	return 0;
542616043d5SPramod Kumar }
543616043d5SPramod Kumar 
iproc_gpio_get_pull(struct iproc_gpio * chip,unsigned gpio,bool * disable,bool * pull_up)544616043d5SPramod Kumar static void iproc_gpio_get_pull(struct iproc_gpio *chip, unsigned gpio,
545616043d5SPramod Kumar 				 bool *disable, bool *pull_up)
546616043d5SPramod Kumar {
547398a1f50SLi Jin 	void __iomem *base;
548616043d5SPramod Kumar 	unsigned long flags;
549398a1f50SLi Jin 	unsigned int shift;
550398a1f50SLi Jin 	u32 val_1, val_2;
551616043d5SPramod Kumar 
552cb96a662SJulia Cartwright 	raw_spin_lock_irqsave(&chip->lock, flags);
553398a1f50SLi Jin 	if (chip->io_ctrl_type == IOCTRL_TYPE_CDRU) {
554398a1f50SLi Jin 		base = chip->io_ctrl;
555398a1f50SLi Jin 		shift = IPROC_GPIO_SHIFT(gpio);
556398a1f50SLi Jin 
557398a1f50SLi Jin 		val_1 = readl(base + IPROC_GPIO_PULL_UP_OFFSET) & BIT(shift);
558398a1f50SLi Jin 		val_2 = readl(base + IPROC_GPIO_PULL_DN_OFFSET) & BIT(shift);
559398a1f50SLi Jin 
560398a1f50SLi Jin 		*pull_up = val_1 ? true : false;
561398a1f50SLi Jin 		*disable = (val_1 | val_2) ? false : true;
562398a1f50SLi Jin 
563398a1f50SLi Jin 	} else {
564616043d5SPramod Kumar 		*disable = !iproc_get_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio);
565616043d5SPramod Kumar 		*pull_up = iproc_get_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio);
566398a1f50SLi Jin 	}
567cb96a662SJulia Cartwright 	raw_spin_unlock_irqrestore(&chip->lock, flags);
568616043d5SPramod Kumar }
569616043d5SPramod Kumar 
570398a1f50SLi Jin #define DRV_STRENGTH_OFFSET(gpio, bit, type)  ((type) == IOCTRL_TYPE_AON ? \
571398a1f50SLi Jin 	((2 - (bit)) * 4 + IPROC_GPIO_DRV_CTRL_OFFSET) : \
572398a1f50SLi Jin 	((type) == IOCTRL_TYPE_CDRU) ? \
573398a1f50SLi Jin 	((bit) * 4 + IPROC_GPIO_DRV_CTRL_OFFSET) : \
574398a1f50SLi Jin 	((bit) * 4 + IPROC_GPIO_REG(gpio, IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET)))
575398a1f50SLi Jin 
iproc_gpio_set_strength(struct iproc_gpio * chip,unsigned gpio,unsigned strength)576616043d5SPramod Kumar static int iproc_gpio_set_strength(struct iproc_gpio *chip, unsigned gpio,
577616043d5SPramod Kumar 				    unsigned strength)
578616043d5SPramod Kumar {
579616043d5SPramod Kumar 	void __iomem *base;
580616043d5SPramod Kumar 	unsigned int i, offset, shift;
581616043d5SPramod Kumar 	u32 val;
582616043d5SPramod Kumar 	unsigned long flags;
583616043d5SPramod Kumar 
584616043d5SPramod Kumar 	/* make sure drive strength is supported */
585616043d5SPramod Kumar 	if (strength < 2 ||  strength > 16 || (strength % 2))
586616043d5SPramod Kumar 		return -ENOTSUPP;
587616043d5SPramod Kumar 
588616043d5SPramod Kumar 	if (chip->io_ctrl) {
589616043d5SPramod Kumar 		base = chip->io_ctrl;
590616043d5SPramod Kumar 	} else {
591616043d5SPramod Kumar 		base = chip->base;
592616043d5SPramod Kumar 	}
593616043d5SPramod Kumar 
594616043d5SPramod Kumar 	shift = IPROC_GPIO_SHIFT(gpio);
595616043d5SPramod Kumar 
596616043d5SPramod Kumar 	dev_dbg(chip->dev, "gpio:%u set drive strength:%d mA\n", gpio,
597616043d5SPramod Kumar 		strength);
598616043d5SPramod Kumar 
599cb96a662SJulia Cartwright 	raw_spin_lock_irqsave(&chip->lock, flags);
600616043d5SPramod Kumar 	strength = (strength / 2) - 1;
601616043d5SPramod Kumar 	for (i = 0; i < GPIO_DRV_STRENGTH_BITS; i++) {
602398a1f50SLi Jin 		offset = DRV_STRENGTH_OFFSET(gpio, i, chip->io_ctrl_type);
603616043d5SPramod Kumar 		val = readl(base + offset);
604616043d5SPramod Kumar 		val &= ~BIT(shift);
605616043d5SPramod Kumar 		val |= ((strength >> i) & 0x1) << shift;
606616043d5SPramod Kumar 		writel(val, base + offset);
607616043d5SPramod Kumar 	}
608cb96a662SJulia Cartwright 	raw_spin_unlock_irqrestore(&chip->lock, flags);
609616043d5SPramod Kumar 
610616043d5SPramod Kumar 	return 0;
611616043d5SPramod Kumar }
612616043d5SPramod Kumar 
iproc_gpio_get_strength(struct iproc_gpio * chip,unsigned gpio,u16 * strength)613616043d5SPramod Kumar static int iproc_gpio_get_strength(struct iproc_gpio *chip, unsigned gpio,
614616043d5SPramod Kumar 				    u16 *strength)
615616043d5SPramod Kumar {
616616043d5SPramod Kumar 	void __iomem *base;
617616043d5SPramod Kumar 	unsigned int i, offset, shift;
618616043d5SPramod Kumar 	u32 val;
619616043d5SPramod Kumar 	unsigned long flags;
620616043d5SPramod Kumar 
621616043d5SPramod Kumar 	if (chip->io_ctrl) {
622616043d5SPramod Kumar 		base = chip->io_ctrl;
623616043d5SPramod Kumar 	} else {
624616043d5SPramod Kumar 		base = chip->base;
625616043d5SPramod Kumar 	}
626616043d5SPramod Kumar 
627616043d5SPramod Kumar 	shift = IPROC_GPIO_SHIFT(gpio);
628616043d5SPramod Kumar 
629cb96a662SJulia Cartwright 	raw_spin_lock_irqsave(&chip->lock, flags);
630616043d5SPramod Kumar 	*strength = 0;
631616043d5SPramod Kumar 	for (i = 0; i < GPIO_DRV_STRENGTH_BITS; i++) {
632398a1f50SLi Jin 		offset = DRV_STRENGTH_OFFSET(gpio, i, chip->io_ctrl_type);
633616043d5SPramod Kumar 		val = readl(base + offset) & BIT(shift);
634616043d5SPramod Kumar 		val >>= shift;
635616043d5SPramod Kumar 		*strength += (val << i);
636616043d5SPramod Kumar 	}
637616043d5SPramod Kumar 
638616043d5SPramod Kumar 	/* convert to mA */
639616043d5SPramod Kumar 	*strength = (*strength + 1) * 2;
640cb96a662SJulia Cartwright 	raw_spin_unlock_irqrestore(&chip->lock, flags);
641616043d5SPramod Kumar 
642616043d5SPramod Kumar 	return 0;
643616043d5SPramod Kumar }
644616043d5SPramod Kumar 
iproc_pin_config_get(struct pinctrl_dev * pctldev,unsigned pin,unsigned long * config)645616043d5SPramod Kumar static int iproc_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
646616043d5SPramod Kumar 				 unsigned long *config)
647616043d5SPramod Kumar {
648616043d5SPramod Kumar 	struct iproc_gpio *chip = pinctrl_dev_get_drvdata(pctldev);
649616043d5SPramod Kumar 	enum pin_config_param param = pinconf_to_config_param(*config);
650616043d5SPramod Kumar 	unsigned gpio = iproc_pin_to_gpio(pin);
651616043d5SPramod Kumar 	u16 arg;
652616043d5SPramod Kumar 	bool disable, pull_up;
653616043d5SPramod Kumar 	int ret;
654616043d5SPramod Kumar 
655f58de3d9SRay Jui 	if (iproc_pinconf_param_is_disabled(chip, param))
656f58de3d9SRay Jui 		return -ENOTSUPP;
657f58de3d9SRay Jui 
658616043d5SPramod Kumar 	switch (param) {
659616043d5SPramod Kumar 	case PIN_CONFIG_BIAS_DISABLE:
660616043d5SPramod Kumar 		iproc_gpio_get_pull(chip, gpio, &disable, &pull_up);
661616043d5SPramod Kumar 		if (disable)
662616043d5SPramod Kumar 			return 0;
663616043d5SPramod Kumar 		else
664616043d5SPramod Kumar 			return -EINVAL;
665616043d5SPramod Kumar 
666616043d5SPramod Kumar 	case PIN_CONFIG_BIAS_PULL_UP:
667616043d5SPramod Kumar 		iproc_gpio_get_pull(chip, gpio, &disable, &pull_up);
668616043d5SPramod Kumar 		if (!disable && pull_up)
669616043d5SPramod Kumar 			return 0;
670616043d5SPramod Kumar 		else
671616043d5SPramod Kumar 			return -EINVAL;
672616043d5SPramod Kumar 
673616043d5SPramod Kumar 	case PIN_CONFIG_BIAS_PULL_DOWN:
674616043d5SPramod Kumar 		iproc_gpio_get_pull(chip, gpio, &disable, &pull_up);
675616043d5SPramod Kumar 		if (!disable && !pull_up)
676616043d5SPramod Kumar 			return 0;
677616043d5SPramod Kumar 		else
678616043d5SPramod Kumar 			return -EINVAL;
679616043d5SPramod Kumar 
680616043d5SPramod Kumar 	case PIN_CONFIG_DRIVE_STRENGTH:
681616043d5SPramod Kumar 		ret = iproc_gpio_get_strength(chip, gpio, &arg);
682616043d5SPramod Kumar 		if (ret)
683616043d5SPramod Kumar 			return ret;
684616043d5SPramod Kumar 		*config = pinconf_to_config_packed(param, arg);
685616043d5SPramod Kumar 
686616043d5SPramod Kumar 		return 0;
687616043d5SPramod Kumar 
688616043d5SPramod Kumar 	default:
689616043d5SPramod Kumar 		return -ENOTSUPP;
690616043d5SPramod Kumar 	}
691616043d5SPramod Kumar 
692616043d5SPramod Kumar 	return -ENOTSUPP;
693616043d5SPramod Kumar }
694616043d5SPramod Kumar 
iproc_pin_config_set(struct pinctrl_dev * pctldev,unsigned pin,unsigned long * configs,unsigned num_configs)695616043d5SPramod Kumar static int iproc_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
696616043d5SPramod Kumar 				 unsigned long *configs, unsigned num_configs)
697616043d5SPramod Kumar {
698616043d5SPramod Kumar 	struct iproc_gpio *chip = pinctrl_dev_get_drvdata(pctldev);
699616043d5SPramod Kumar 	enum pin_config_param param;
70058957d2eSMika Westerberg 	u32 arg;
701616043d5SPramod Kumar 	unsigned i, gpio = iproc_pin_to_gpio(pin);
702616043d5SPramod Kumar 	int ret = -ENOTSUPP;
703616043d5SPramod Kumar 
704616043d5SPramod Kumar 	for (i = 0; i < num_configs; i++) {
705616043d5SPramod Kumar 		param = pinconf_to_config_param(configs[i]);
706f58de3d9SRay Jui 
707f58de3d9SRay Jui 		if (iproc_pinconf_param_is_disabled(chip, param))
708f58de3d9SRay Jui 			return -ENOTSUPP;
709f58de3d9SRay Jui 
710616043d5SPramod Kumar 		arg = pinconf_to_config_argument(configs[i]);
711616043d5SPramod Kumar 
712616043d5SPramod Kumar 		switch (param) {
713616043d5SPramod Kumar 		case PIN_CONFIG_BIAS_DISABLE:
714616043d5SPramod Kumar 			ret = iproc_gpio_set_pull(chip, gpio, true, false);
715616043d5SPramod Kumar 			if (ret < 0)
716616043d5SPramod Kumar 				goto out;
717616043d5SPramod Kumar 			break;
718616043d5SPramod Kumar 
719616043d5SPramod Kumar 		case PIN_CONFIG_BIAS_PULL_UP:
720616043d5SPramod Kumar 			ret = iproc_gpio_set_pull(chip, gpio, false, true);
721616043d5SPramod Kumar 			if (ret < 0)
722616043d5SPramod Kumar 				goto out;
723616043d5SPramod Kumar 			break;
724616043d5SPramod Kumar 
725616043d5SPramod Kumar 		case PIN_CONFIG_BIAS_PULL_DOWN:
726616043d5SPramod Kumar 			ret = iproc_gpio_set_pull(chip, gpio, false, false);
727616043d5SPramod Kumar 			if (ret < 0)
728616043d5SPramod Kumar 				goto out;
729616043d5SPramod Kumar 			break;
730616043d5SPramod Kumar 
731616043d5SPramod Kumar 		case PIN_CONFIG_DRIVE_STRENGTH:
732616043d5SPramod Kumar 			ret = iproc_gpio_set_strength(chip, gpio, arg);
733616043d5SPramod Kumar 			if (ret < 0)
734616043d5SPramod Kumar 				goto out;
735616043d5SPramod Kumar 			break;
736616043d5SPramod Kumar 
737616043d5SPramod Kumar 		default:
738616043d5SPramod Kumar 			dev_err(chip->dev, "invalid configuration\n");
739616043d5SPramod Kumar 			return -ENOTSUPP;
740616043d5SPramod Kumar 		}
741616043d5SPramod Kumar 	} /* for each config */
742616043d5SPramod Kumar 
743616043d5SPramod Kumar out:
744616043d5SPramod Kumar 	return ret;
745616043d5SPramod Kumar }
746616043d5SPramod Kumar 
747616043d5SPramod Kumar static const struct pinconf_ops iproc_pconf_ops = {
748616043d5SPramod Kumar 	.is_generic = true,
749616043d5SPramod Kumar 	.pin_config_get = iproc_pin_config_get,
750616043d5SPramod Kumar 	.pin_config_set = iproc_pin_config_set,
751616043d5SPramod Kumar };
752616043d5SPramod Kumar 
753616043d5SPramod Kumar /*
754616043d5SPramod Kumar  * Iproc GPIO controller supports some PINCONF related configurations such as
755616043d5SPramod Kumar  * pull up, pull down, and drive strength, when the pin is configured to GPIO
756616043d5SPramod Kumar  *
757616043d5SPramod Kumar  * Here a local pinctrl device is created with simple 1-to-1 pin mapping to the
758616043d5SPramod Kumar  * local GPIO pins
759616043d5SPramod Kumar  */
iproc_gpio_register_pinconf(struct iproc_gpio * chip)760616043d5SPramod Kumar static int iproc_gpio_register_pinconf(struct iproc_gpio *chip)
761616043d5SPramod Kumar {
762616043d5SPramod Kumar 	struct pinctrl_desc *pctldesc = &chip->pctldesc;
763616043d5SPramod Kumar 	struct pinctrl_pin_desc *pins;
764616043d5SPramod Kumar 	struct gpio_chip *gc = &chip->gc;
765616043d5SPramod Kumar 	int i;
766616043d5SPramod Kumar 
767616043d5SPramod Kumar 	pins = devm_kcalloc(chip->dev, gc->ngpio, sizeof(*pins), GFP_KERNEL);
768616043d5SPramod Kumar 	if (!pins)
769616043d5SPramod Kumar 		return -ENOMEM;
770616043d5SPramod Kumar 
771616043d5SPramod Kumar 	for (i = 0; i < gc->ngpio; i++) {
772616043d5SPramod Kumar 		pins[i].number = i;
773616043d5SPramod Kumar 		pins[i].name = devm_kasprintf(chip->dev, GFP_KERNEL,
774616043d5SPramod Kumar 					      "gpio-%d", i);
775616043d5SPramod Kumar 		if (!pins[i].name)
776616043d5SPramod Kumar 			return -ENOMEM;
777616043d5SPramod Kumar 	}
778616043d5SPramod Kumar 
779616043d5SPramod Kumar 	pctldesc->name = dev_name(chip->dev);
780616043d5SPramod Kumar 	pctldesc->pctlops = &iproc_pctrl_ops;
781616043d5SPramod Kumar 	pctldesc->pins = pins;
782616043d5SPramod Kumar 	pctldesc->npins = gc->ngpio;
783616043d5SPramod Kumar 	pctldesc->confops = &iproc_pconf_ops;
784616043d5SPramod Kumar 
785ee17e041SLaxman Dewangan 	chip->pctl = devm_pinctrl_register(chip->dev, pctldesc, chip);
786616043d5SPramod Kumar 	if (IS_ERR(chip->pctl)) {
787616043d5SPramod Kumar 		dev_err(chip->dev, "unable to register pinctrl device\n");
788616043d5SPramod Kumar 		return PTR_ERR(chip->pctl);
789616043d5SPramod Kumar 	}
790616043d5SPramod Kumar 
791616043d5SPramod Kumar 	return 0;
792616043d5SPramod Kumar }
793616043d5SPramod Kumar 
794616043d5SPramod Kumar static const struct of_device_id iproc_gpio_of_match[] = {
795f58de3d9SRay Jui 	{ .compatible = "brcm,iproc-gpio" },
796616043d5SPramod Kumar 	{ .compatible = "brcm,cygnus-ccm-gpio" },
797616043d5SPramod Kumar 	{ .compatible = "brcm,cygnus-asiu-gpio" },
798616043d5SPramod Kumar 	{ .compatible = "brcm,cygnus-crmu-gpio" },
799f58de3d9SRay Jui 	{ .compatible = "brcm,iproc-nsp-gpio" },
800f58de3d9SRay Jui 	{ .compatible = "brcm,iproc-stingray-gpio" },
801f58de3d9SRay Jui 	{ /* sentinel */ }
802616043d5SPramod Kumar };
803616043d5SPramod Kumar 
iproc_gpio_probe(struct platform_device * pdev)804616043d5SPramod Kumar static int iproc_gpio_probe(struct platform_device *pdev)
805616043d5SPramod Kumar {
806616043d5SPramod Kumar 	struct device *dev = &pdev->dev;
807616043d5SPramod Kumar 	struct resource *res;
808616043d5SPramod Kumar 	struct iproc_gpio *chip;
809616043d5SPramod Kumar 	struct gpio_chip *gc;
810f58de3d9SRay Jui 	u32 ngpios, pinconf_disable_mask = 0;
811616043d5SPramod Kumar 	int irq, ret;
812f58de3d9SRay Jui 	bool no_pinconf = false;
813398a1f50SLi Jin 	enum iproc_pinconf_ctrl_type io_ctrl_type = IOCTRL_TYPE_INVALID;
814f58de3d9SRay Jui 
815f58de3d9SRay Jui 	/* NSP does not support drive strength config */
816f58de3d9SRay Jui 	if (of_device_is_compatible(dev->of_node, "brcm,iproc-nsp-gpio"))
817f58de3d9SRay Jui 		pinconf_disable_mask = BIT(IPROC_PINCONF_DRIVE_STRENGTH);
818f58de3d9SRay Jui 	/* Stingray does not support pinconf in this controller */
819f58de3d9SRay Jui 	else if (of_device_is_compatible(dev->of_node,
820f58de3d9SRay Jui 					 "brcm,iproc-stingray-gpio"))
821f58de3d9SRay Jui 		no_pinconf = true;
822616043d5SPramod Kumar 
823616043d5SPramod Kumar 	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
824616043d5SPramod Kumar 	if (!chip)
825616043d5SPramod Kumar 		return -ENOMEM;
826616043d5SPramod Kumar 
827616043d5SPramod Kumar 	chip->dev = dev;
828616043d5SPramod Kumar 	platform_set_drvdata(pdev, chip);
829616043d5SPramod Kumar 
8304b024225SYueHaibing 	chip->base = devm_platform_ioremap_resource(pdev, 0);
831616043d5SPramod Kumar 	if (IS_ERR(chip->base)) {
832616043d5SPramod Kumar 		dev_err(dev, "unable to map I/O memory\n");
833616043d5SPramod Kumar 		return PTR_ERR(chip->base);
834616043d5SPramod Kumar 	}
835616043d5SPramod Kumar 
836616043d5SPramod Kumar 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
837616043d5SPramod Kumar 	if (res) {
838616043d5SPramod Kumar 		chip->io_ctrl = devm_ioremap_resource(dev, res);
839ef9385fbSZhen Lei 		if (IS_ERR(chip->io_ctrl))
840616043d5SPramod Kumar 			return PTR_ERR(chip->io_ctrl);
841398a1f50SLi Jin 		if (of_device_is_compatible(dev->of_node,
842398a1f50SLi Jin 					    "brcm,cygnus-ccm-gpio"))
843398a1f50SLi Jin 			io_ctrl_type = IOCTRL_TYPE_CDRU;
844398a1f50SLi Jin 		else
845398a1f50SLi Jin 			io_ctrl_type = IOCTRL_TYPE_AON;
846616043d5SPramod Kumar 	}
847616043d5SPramod Kumar 
848398a1f50SLi Jin 	chip->io_ctrl_type = io_ctrl_type;
849398a1f50SLi Jin 
850616043d5SPramod Kumar 	if (of_property_read_u32(dev->of_node, "ngpios", &ngpios)) {
851616043d5SPramod Kumar 		dev_err(&pdev->dev, "missing ngpios DT property\n");
852616043d5SPramod Kumar 		return -ENODEV;
853616043d5SPramod Kumar 	}
854616043d5SPramod Kumar 
855cb96a662SJulia Cartwright 	raw_spin_lock_init(&chip->lock);
856616043d5SPramod Kumar 
857616043d5SPramod Kumar 	gc = &chip->gc;
858616043d5SPramod Kumar 	gc->base = -1;
859616043d5SPramod Kumar 	gc->ngpio = ngpios;
860616043d5SPramod Kumar 	chip->num_banks = (ngpios + NGPIOS_PER_BANK - 1) / NGPIOS_PER_BANK;
861616043d5SPramod Kumar 	gc->label = dev_name(dev);
86258cf279aSLinus Torvalds 	gc->parent = dev;
863616043d5SPramod Kumar 	gc->request = iproc_gpio_request;
864616043d5SPramod Kumar 	gc->free = iproc_gpio_free;
865616043d5SPramod Kumar 	gc->direction_input = iproc_gpio_direction_input;
866616043d5SPramod Kumar 	gc->direction_output = iproc_gpio_direction_output;
86703518271SRayagonda Kokatanur 	gc->get_direction = iproc_gpio_get_direction;
868616043d5SPramod Kumar 	gc->set = iproc_gpio_set;
869616043d5SPramod Kumar 	gc->get = iproc_gpio_get;
870616043d5SPramod Kumar 
871616043d5SPramod Kumar 	chip->pinmux_is_supported = of_property_read_bool(dev->of_node,
872616043d5SPramod Kumar 							"gpio-ranges");
873616043d5SPramod Kumar 
8746f265e5dSLinus Walleij 	/* optional GPIO interrupt support */
875783e9986SRayagonda Kokatanur 	irq = platform_get_irq_optional(pdev, 0);
87648659227SChris Packham 	if (irq > 0) {
8776f265e5dSLinus Walleij 		struct gpio_irq_chip *girq;
8786f265e5dSLinus Walleij 
8796f265e5dSLinus Walleij 		girq = &gc->irq;
8802cc4485eSLinus Walleij 		gpio_irq_chip_set_chip(girq, &iproc_gpio_irq_chip);
8816f265e5dSLinus Walleij 		girq->parent_handler = iproc_gpio_irq_handler;
8826f265e5dSLinus Walleij 		girq->num_parents = 1;
8836f265e5dSLinus Walleij 		girq->parents = devm_kcalloc(dev, 1,
8846f265e5dSLinus Walleij 					     sizeof(*girq->parents),
8856f265e5dSLinus Walleij 					     GFP_KERNEL);
8866f265e5dSLinus Walleij 		if (!girq->parents)
8876f265e5dSLinus Walleij 			return -ENOMEM;
8886f265e5dSLinus Walleij 		girq->parents[0] = irq;
8896f265e5dSLinus Walleij 		girq->default_type = IRQ_TYPE_NONE;
890534ad357SHamish Martin 		girq->handler = handle_bad_irq;
8916f265e5dSLinus Walleij 	}
8926f265e5dSLinus Walleij 
89369fd6aeaSLinus Walleij 	ret = gpiochip_add_data(gc, chip);
894*d2606a63SFlorian Fainelli 	if (ret < 0)
895*d2606a63SFlorian Fainelli 		return dev_err_probe(dev, ret, "unable to add GPIO chip\n");
896616043d5SPramod Kumar 
897f58de3d9SRay Jui 	if (!no_pinconf) {
898616043d5SPramod Kumar 		ret = iproc_gpio_register_pinconf(chip);
899616043d5SPramod Kumar 		if (ret) {
900616043d5SPramod Kumar 			dev_err(dev, "unable to register pinconf\n");
901616043d5SPramod Kumar 			goto err_rm_gpiochip;
902616043d5SPramod Kumar 		}
903616043d5SPramod Kumar 
904f58de3d9SRay Jui 		if (pinconf_disable_mask) {
905f58de3d9SRay Jui 			ret = iproc_pinconf_disable_map_create(chip,
906f58de3d9SRay Jui 							 pinconf_disable_mask);
907f58de3d9SRay Jui 			if (ret) {
908f58de3d9SRay Jui 				dev_err(dev,
909f58de3d9SRay Jui 					"unable to create pinconf disable map\n");
910f58de3d9SRay Jui 				goto err_rm_gpiochip;
911f58de3d9SRay Jui 			}
912f58de3d9SRay Jui 		}
913f58de3d9SRay Jui 	}
914f58de3d9SRay Jui 
915616043d5SPramod Kumar 	return 0;
916616043d5SPramod Kumar 
917616043d5SPramod Kumar err_rm_gpiochip:
918616043d5SPramod Kumar 	gpiochip_remove(gc);
919616043d5SPramod Kumar 
920616043d5SPramod Kumar 	return ret;
921616043d5SPramod Kumar }
922616043d5SPramod Kumar 
923616043d5SPramod Kumar static struct platform_driver iproc_gpio_driver = {
924616043d5SPramod Kumar 	.driver = {
925616043d5SPramod Kumar 		.name = "iproc-gpio",
926616043d5SPramod Kumar 		.of_match_table = iproc_gpio_of_match,
927616043d5SPramod Kumar 	},
928616043d5SPramod Kumar 	.probe = iproc_gpio_probe,
929616043d5SPramod Kumar };
930616043d5SPramod Kumar 
iproc_gpio_init(void)931616043d5SPramod Kumar static int __init iproc_gpio_init(void)
932616043d5SPramod Kumar {
933091c531bSRay Jui 	return platform_driver_register(&iproc_gpio_driver);
934616043d5SPramod Kumar }
935616043d5SPramod Kumar arch_initcall_sync(iproc_gpio_init);
936