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