blob: b0f3aca61974c1d16708ebd64c43d052faaddf44 [file] [log] [blame]
Thomas Gleixnerd2912cb2019-06-04 10:11:33 +02001// SPDX-License-Identifier: GPL-2.0-only
Jamie Iles7779b3452014-02-25 17:01:01 -06002/*
3 * Copyright (c) 2011 Jamie Iles
4 *
Jamie Iles7779b3452014-02-25 17:01:01 -06005 * All enquiries to support@picochip.com
6 */
Jiang Qiue6cb3482016-04-28 17:32:03 +08007#include <linux/acpi.h>
Phil Edworthye6bf3772018-03-12 18:30:56 +00008#include <linux/clk.h>
Jamie Iles7779b3452014-02-25 17:01:01 -06009#include <linux/err.h>
Phil Edworthye6bf3772018-03-12 18:30:56 +000010#include <linux/gpio/driver.h>
Jamie Iles7779b3452014-02-25 17:01:01 -060011#include <linux/init.h>
12#include <linux/interrupt.h>
13#include <linux/io.h>
14#include <linux/ioport.h>
15#include <linux/irq.h>
Andy Shevchenko043a0c92021-06-04 21:50:13 +030016#include <linux/mod_devicetable.h>
Jamie Iles7779b3452014-02-25 17:01:01 -060017#include <linux/module.h>
Jamie Iles7779b3452014-02-25 17:01:01 -060018#include <linux/platform_device.h>
Jiang Qiu4ba8cfa2016-04-28 17:32:02 +080019#include <linux/property.h>
Alan Tull07901a92017-10-11 11:34:44 -050020#include <linux/reset.h>
Weike Chen3d2613c2014-09-17 09:18:39 -070021#include <linux/slab.h>
Andy Shevchenko043a0c92021-06-04 21:50:13 +030022#include <linux/spinlock.h>
Jamie Iles7779b3452014-02-25 17:01:01 -060023
Jiang Qiue6cb3482016-04-28 17:32:03 +080024#include "gpiolib.h"
Andy Shevchenko77cb9072019-07-30 13:43:36 +030025#include "gpiolib-acpi.h"
Jiang Qiue6cb3482016-04-28 17:32:03 +080026
Jamie Iles7779b3452014-02-25 17:01:01 -060027#define GPIO_SWPORTA_DR 0x00
28#define GPIO_SWPORTA_DDR 0x04
29#define GPIO_SWPORTB_DR 0x0c
30#define GPIO_SWPORTB_DDR 0x10
31#define GPIO_SWPORTC_DR 0x18
32#define GPIO_SWPORTC_DDR 0x1c
33#define GPIO_SWPORTD_DR 0x24
34#define GPIO_SWPORTD_DDR 0x28
35#define GPIO_INTEN 0x30
36#define GPIO_INTMASK 0x34
37#define GPIO_INTTYPE_LEVEL 0x38
38#define GPIO_INT_POLARITY 0x3c
39#define GPIO_INTSTATUS 0x40
Weike Chen5d60d9e2014-09-17 09:18:41 -070040#define GPIO_PORTA_DEBOUNCE 0x48
Jamie Iles7779b3452014-02-25 17:01:01 -060041#define GPIO_PORTA_EOI 0x4c
42#define GPIO_EXT_PORTA 0x50
43#define GPIO_EXT_PORTB 0x54
44#define GPIO_EXT_PORTC 0x58
45#define GPIO_EXT_PORTD 0x5c
46
Andy Shevchenkoc58220c2020-04-15 17:15:21 +030047#define DWAPB_DRIVER_NAME "gpio-dwapb"
Jamie Iles7779b3452014-02-25 17:01:01 -060048#define DWAPB_MAX_PORTS 4
Andy Shevchenko5111c2b2021-08-04 19:00:19 +030049#define DWAPB_MAX_GPIOS 32
Andy Shevchenkoc58220c2020-04-15 17:15:21 +030050
Linus Walleij89f99fe2018-02-08 17:03:58 +010051#define GPIO_EXT_PORT_STRIDE 0x04 /* register stride 32 bits */
52#define GPIO_SWPORT_DR_STRIDE 0x0c /* register stride 3*32 bits */
53#define GPIO_SWPORT_DDR_STRIDE 0x0c /* register stride 3*32 bits */
Jamie Iles7779b3452014-02-25 17:01:01 -060054
Andy Shevchenkoe1610432021-11-30 18:49:56 +020055#define GPIO_REG_OFFSET_V1 0
Hoan Trana72b8c42017-02-21 11:32:43 -080056#define GPIO_REG_OFFSET_V2 1
Andy Shevchenkoe1610432021-11-30 18:49:56 +020057#define GPIO_REG_OFFSET_MASK BIT(0)
Hoan Trana72b8c42017-02-21 11:32:43 -080058
59#define GPIO_INTMASK_V2 0x44
60#define GPIO_INTTYPE_LEVEL_V2 0x34
61#define GPIO_INT_POLARITY_V2 0x38
62#define GPIO_INTSTATUS_V2 0x3c
63#define GPIO_PORTA_EOI_V2 0x40
64
Serge Semin5c544c92020-03-23 22:54:00 +030065#define DWAPB_NR_CLOCKS 2
66
Jamie Iles7779b3452014-02-25 17:01:01 -060067struct dwapb_gpio;
68
Andy Shevchenko5111c2b2021-08-04 19:00:19 +030069struct dwapb_port_property {
70 struct fwnode_handle *fwnode;
71 unsigned int idx;
72 unsigned int ngpio;
73 unsigned int gpio_base;
74 int irq[DWAPB_MAX_GPIOS];
75};
76
77struct dwapb_platform_data {
78 struct dwapb_port_property *properties;
79 unsigned int nports;
80};
81
Weike Chen1e960db2014-09-17 09:18:42 -070082#ifdef CONFIG_PM_SLEEP
83/* Store GPIO context across system-wide suspend/resume transitions */
84struct dwapb_context {
85 u32 data;
86 u32 dir;
87 u32 ext;
88 u32 int_en;
89 u32 int_mask;
90 u32 int_type;
91 u32 int_pol;
92 u32 int_deb;
Hoan Tran6437c7b2017-09-08 15:41:15 -070093 u32 wake_en;
Weike Chen1e960db2014-09-17 09:18:42 -070094};
95#endif
96
Serge Semin0ea68392020-07-30 18:28:02 +030097struct dwapb_gpio_port_irqchip {
98 struct irq_chip irqchip;
99 unsigned int nr_irqs;
100 unsigned int irq[DWAPB_MAX_GPIOS];
101};
102
Jamie Iles7779b3452014-02-25 17:01:01 -0600103struct dwapb_gpio_port {
Linus Walleij0f4630f2015-12-04 14:02:58 +0100104 struct gpio_chip gc;
Serge Semin0ea68392020-07-30 18:28:02 +0300105 struct dwapb_gpio_port_irqchip *pirq;
Jamie Iles7779b3452014-02-25 17:01:01 -0600106 struct dwapb_gpio *gpio;
Weike Chen1e960db2014-09-17 09:18:42 -0700107#ifdef CONFIG_PM_SLEEP
108 struct dwapb_context *ctx;
109#endif
110 unsigned int idx;
Jamie Iles7779b3452014-02-25 17:01:01 -0600111};
Serge Semin0ea68392020-07-30 18:28:02 +0300112#define to_dwapb_gpio(_gc) \
113 (container_of(_gc, struct dwapb_gpio_port, gc)->gpio)
Jamie Iles7779b3452014-02-25 17:01:01 -0600114
115struct dwapb_gpio {
116 struct device *dev;
117 void __iomem *regs;
118 struct dwapb_gpio_port *ports;
119 unsigned int nr_ports;
Hoan Trana72b8c42017-02-21 11:32:43 -0800120 unsigned int flags;
Alan Tull07901a92017-10-11 11:34:44 -0500121 struct reset_control *rst;
Serge Semin5c544c92020-03-23 22:54:00 +0300122 struct clk_bulk_data clks[DWAPB_NR_CLOCKS];
Jamie Iles7779b3452014-02-25 17:01:01 -0600123};
124
Hoan Trana72b8c42017-02-21 11:32:43 -0800125static inline u32 gpio_reg_v2_convert(unsigned int offset)
126{
127 switch (offset) {
128 case GPIO_INTMASK:
129 return GPIO_INTMASK_V2;
130 case GPIO_INTTYPE_LEVEL:
131 return GPIO_INTTYPE_LEVEL_V2;
132 case GPIO_INT_POLARITY:
133 return GPIO_INT_POLARITY_V2;
134 case GPIO_INTSTATUS:
135 return GPIO_INTSTATUS_V2;
136 case GPIO_PORTA_EOI:
137 return GPIO_PORTA_EOI_V2;
138 }
139
140 return offset;
141}
142
143static inline u32 gpio_reg_convert(struct dwapb_gpio *gpio, unsigned int offset)
144{
Andy Shevchenkoe1610432021-11-30 18:49:56 +0200145 if ((gpio->flags & GPIO_REG_OFFSET_MASK) == GPIO_REG_OFFSET_V2)
Hoan Trana72b8c42017-02-21 11:32:43 -0800146 return gpio_reg_v2_convert(offset);
147
148 return offset;
149}
150
Weike Chen67809b92014-09-17 09:18:40 -0700151static inline u32 dwapb_read(struct dwapb_gpio *gpio, unsigned int offset)
152{
Linus Walleij0f4630f2015-12-04 14:02:58 +0100153 struct gpio_chip *gc = &gpio->ports[0].gc;
Weike Chen67809b92014-09-17 09:18:40 -0700154 void __iomem *reg_base = gpio->regs;
155
Hoan Trana72b8c42017-02-21 11:32:43 -0800156 return gc->read_reg(reg_base + gpio_reg_convert(gpio, offset));
Weike Chen67809b92014-09-17 09:18:40 -0700157}
158
159static inline void dwapb_write(struct dwapb_gpio *gpio, unsigned int offset,
160 u32 val)
161{
Linus Walleij0f4630f2015-12-04 14:02:58 +0100162 struct gpio_chip *gc = &gpio->ports[0].gc;
Weike Chen67809b92014-09-17 09:18:40 -0700163 void __iomem *reg_base = gpio->regs;
164
Hoan Trana72b8c42017-02-21 11:32:43 -0800165 gc->write_reg(reg_base + gpio_reg_convert(gpio, offset), val);
Weike Chen67809b92014-09-17 09:18:40 -0700166}
167
Linus Walleij62c16232018-02-08 18:00:05 +0100168static struct dwapb_gpio_port *dwapb_offs_to_port(struct dwapb_gpio *gpio, unsigned int offs)
169{
170 struct dwapb_gpio_port *port;
171 int i;
172
173 for (i = 0; i < gpio->nr_ports; i++) {
174 port = &gpio->ports[i];
Serge Seminf9f890b2020-07-30 18:28:01 +0300175 if (port->idx == offs / DWAPB_MAX_GPIOS)
Linus Walleij62c16232018-02-08 18:00:05 +0100176 return port;
177 }
178
179 return NULL;
180}
181
Jamie Iles7779b3452014-02-25 17:01:01 -0600182static void dwapb_toggle_trigger(struct dwapb_gpio *gpio, unsigned int offs)
183{
Linus Walleij62c16232018-02-08 18:00:05 +0100184 struct dwapb_gpio_port *port = dwapb_offs_to_port(gpio, offs);
185 struct gpio_chip *gc;
186 u32 pol;
187 int val;
Jamie Iles7779b3452014-02-25 17:01:01 -0600188
Linus Walleij62c16232018-02-08 18:00:05 +0100189 if (!port)
190 return;
191 gc = &port->gc;
192
193 pol = dwapb_read(gpio, GPIO_INT_POLARITY);
194 /* Just read the current value right out of the data register */
Serge Seminf9f890b2020-07-30 18:28:01 +0300195 val = gc->get(gc, offs % DWAPB_MAX_GPIOS);
Linus Walleij62c16232018-02-08 18:00:05 +0100196 if (val)
197 pol &= ~BIT(offs);
Jamie Iles7779b3452014-02-25 17:01:01 -0600198 else
Linus Walleij62c16232018-02-08 18:00:05 +0100199 pol |= BIT(offs);
Jamie Iles7779b3452014-02-25 17:01:01 -0600200
Linus Walleij62c16232018-02-08 18:00:05 +0100201 dwapb_write(gpio, GPIO_INT_POLARITY, pol);
Jamie Iles7779b3452014-02-25 17:01:01 -0600202}
203
Weike Chen3d2613c2014-09-17 09:18:39 -0700204static u32 dwapb_do_irq(struct dwapb_gpio *gpio)
Jamie Iles7779b3452014-02-25 17:01:01 -0600205{
Serge Semin0ea68392020-07-30 18:28:02 +0300206 struct gpio_chip *gc = &gpio->ports[0].gc;
Andy Shevchenko038aa1f2020-04-15 17:15:22 +0300207 unsigned long irq_status;
Andy Shevchenkoe092bc52020-04-15 17:15:26 +0300208 irq_hw_number_t hwirq;
Jamie Iles7779b3452014-02-25 17:01:01 -0600209
Andy Shevchenko038aa1f2020-04-15 17:15:22 +0300210 irq_status = dwapb_read(gpio, GPIO_INTSTATUS);
Serge Seminf9f890b2020-07-30 18:28:01 +0300211 for_each_set_bit(hwirq, &irq_status, DWAPB_MAX_GPIOS) {
Serge Semin0ea68392020-07-30 18:28:02 +0300212 int gpio_irq = irq_find_mapping(gc->irq.domain, hwirq);
Andy Shevchenko038aa1f2020-04-15 17:15:22 +0300213 u32 irq_type = irq_get_trigger_type(gpio_irq);
Jamie Iles7779b3452014-02-25 17:01:01 -0600214
215 generic_handle_irq(gpio_irq);
Jamie Iles7779b3452014-02-25 17:01:01 -0600216
Andy Shevchenko038aa1f2020-04-15 17:15:22 +0300217 if ((irq_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH)
Jamie Iles7779b3452014-02-25 17:01:01 -0600218 dwapb_toggle_trigger(gpio, hwirq);
219 }
220
Andy Shevchenko038aa1f2020-04-15 17:15:22 +0300221 return irq_status;
Weike Chen3d2613c2014-09-17 09:18:39 -0700222}
223
Thomas Gleixnerbd0b9ac2015-09-14 10:42:37 +0200224static void dwapb_irq_handler(struct irq_desc *desc)
Weike Chen3d2613c2014-09-17 09:18:39 -0700225{
Jiang Liu476f8b42015-06-04 12:13:15 +0800226 struct dwapb_gpio *gpio = irq_desc_get_handler_data(desc);
Weike Chen3d2613c2014-09-17 09:18:39 -0700227 struct irq_chip *chip = irq_desc_get_chip(desc);
228
Andy Shevchenko9b0aef32020-04-15 17:15:23 +0300229 chained_irq_enter(chip, desc);
Weike Chen3d2613c2014-09-17 09:18:39 -0700230 dwapb_do_irq(gpio);
Andy Shevchenko9b0aef32020-04-15 17:15:23 +0300231 chained_irq_exit(chip, desc);
Jamie Iles7779b3452014-02-25 17:01:01 -0600232}
233
Serge Semin75c12362020-07-30 18:28:00 +0300234static irqreturn_t dwapb_irq_handler_mfd(int irq, void *dev_id)
235{
236 return IRQ_RETVAL(dwapb_do_irq(dev_id));
237}
238
Serge Semin0ea68392020-07-30 18:28:02 +0300239static void dwapb_irq_ack(struct irq_data *d)
240{
241 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
242 struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
243 u32 val = BIT(irqd_to_hwirq(d));
244 unsigned long flags;
245
246 spin_lock_irqsave(&gc->bgpio_lock, flags);
247 dwapb_write(gpio, GPIO_PORTA_EOI, val);
248 spin_unlock_irqrestore(&gc->bgpio_lock, flags);
249}
250
251static void dwapb_irq_mask(struct irq_data *d)
252{
253 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
254 struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
255 unsigned long flags;
256 u32 val;
257
258 spin_lock_irqsave(&gc->bgpio_lock, flags);
259 val = dwapb_read(gpio, GPIO_INTMASK) | BIT(irqd_to_hwirq(d));
260 dwapb_write(gpio, GPIO_INTMASK, val);
261 spin_unlock_irqrestore(&gc->bgpio_lock, flags);
262}
263
264static void dwapb_irq_unmask(struct irq_data *d)
265{
266 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
267 struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
268 unsigned long flags;
269 u32 val;
270
271 spin_lock_irqsave(&gc->bgpio_lock, flags);
272 val = dwapb_read(gpio, GPIO_INTMASK) & ~BIT(irqd_to_hwirq(d));
273 dwapb_write(gpio, GPIO_INTMASK, val);
274 spin_unlock_irqrestore(&gc->bgpio_lock, flags);
275}
276
Jamie Iles7779b3452014-02-25 17:01:01 -0600277static void dwapb_irq_enable(struct irq_data *d)
278{
Serge Semin0ea68392020-07-30 18:28:02 +0300279 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
280 struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
Jamie Iles7779b3452014-02-25 17:01:01 -0600281 unsigned long flags;
282 u32 val;
283
Linus Walleij0f4630f2015-12-04 14:02:58 +0100284 spin_lock_irqsave(&gc->bgpio_lock, flags);
Weike Chen67809b92014-09-17 09:18:40 -0700285 val = dwapb_read(gpio, GPIO_INTEN);
Andy Shevchenkoe092bc52020-04-15 17:15:26 +0300286 val |= BIT(irqd_to_hwirq(d));
Weike Chen67809b92014-09-17 09:18:40 -0700287 dwapb_write(gpio, GPIO_INTEN, val);
Linus Walleij0f4630f2015-12-04 14:02:58 +0100288 spin_unlock_irqrestore(&gc->bgpio_lock, flags);
Jamie Iles7779b3452014-02-25 17:01:01 -0600289}
290
291static void dwapb_irq_disable(struct irq_data *d)
292{
Serge Semin0ea68392020-07-30 18:28:02 +0300293 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
294 struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
Jamie Iles7779b3452014-02-25 17:01:01 -0600295 unsigned long flags;
296 u32 val;
297
Linus Walleij0f4630f2015-12-04 14:02:58 +0100298 spin_lock_irqsave(&gc->bgpio_lock, flags);
Weike Chen67809b92014-09-17 09:18:40 -0700299 val = dwapb_read(gpio, GPIO_INTEN);
Andy Shevchenkoe092bc52020-04-15 17:15:26 +0300300 val &= ~BIT(irqd_to_hwirq(d));
Weike Chen67809b92014-09-17 09:18:40 -0700301 dwapb_write(gpio, GPIO_INTEN, val);
Linus Walleij0f4630f2015-12-04 14:02:58 +0100302 spin_unlock_irqrestore(&gc->bgpio_lock, flags);
Jamie Iles7779b3452014-02-25 17:01:01 -0600303}
304
Jamie Iles7779b3452014-02-25 17:01:01 -0600305static int dwapb_irq_set_type(struct irq_data *d, u32 type)
306{
Serge Semin0ea68392020-07-30 18:28:02 +0300307 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
308 struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
Andy Shevchenkoe092bc52020-04-15 17:15:26 +0300309 irq_hw_number_t bit = irqd_to_hwirq(d);
Jamie Iles7779b3452014-02-25 17:01:01 -0600310 unsigned long level, polarity, flags;
311
Linus Walleij0f4630f2015-12-04 14:02:58 +0100312 spin_lock_irqsave(&gc->bgpio_lock, flags);
Weike Chen67809b92014-09-17 09:18:40 -0700313 level = dwapb_read(gpio, GPIO_INTTYPE_LEVEL);
314 polarity = dwapb_read(gpio, GPIO_INT_POLARITY);
Jamie Iles7779b3452014-02-25 17:01:01 -0600315
316 switch (type) {
317 case IRQ_TYPE_EDGE_BOTH:
318 level |= BIT(bit);
319 dwapb_toggle_trigger(gpio, bit);
320 break;
321 case IRQ_TYPE_EDGE_RISING:
322 level |= BIT(bit);
323 polarity |= BIT(bit);
324 break;
325 case IRQ_TYPE_EDGE_FALLING:
326 level |= BIT(bit);
327 polarity &= ~BIT(bit);
328 break;
329 case IRQ_TYPE_LEVEL_HIGH:
330 level &= ~BIT(bit);
331 polarity |= BIT(bit);
332 break;
333 case IRQ_TYPE_LEVEL_LOW:
334 level &= ~BIT(bit);
335 polarity &= ~BIT(bit);
336 break;
337 }
338
Serge Semin0ea68392020-07-30 18:28:02 +0300339 if (type & IRQ_TYPE_LEVEL_MASK)
340 irq_set_handler_locked(d, handle_level_irq);
341 else if (type & IRQ_TYPE_EDGE_BOTH)
342 irq_set_handler_locked(d, handle_edge_irq);
Sebastian Andrzej Siewior6a2f4b72014-05-26 22:58:14 +0200343
Weike Chen67809b92014-09-17 09:18:40 -0700344 dwapb_write(gpio, GPIO_INTTYPE_LEVEL, level);
Xiaoguang Chenedadced2017-06-02 07:27:15 +0800345 if (type != IRQ_TYPE_EDGE_BOTH)
346 dwapb_write(gpio, GPIO_INT_POLARITY, polarity);
Linus Walleij0f4630f2015-12-04 14:02:58 +0100347 spin_unlock_irqrestore(&gc->bgpio_lock, flags);
Jamie Iles7779b3452014-02-25 17:01:01 -0600348
349 return 0;
350}
351
Hoan Tran6437c7b2017-09-08 15:41:15 -0700352#ifdef CONFIG_PM_SLEEP
353static int dwapb_irq_set_wake(struct irq_data *d, unsigned int enable)
354{
Jia He3fe37202020-10-16 23:35:44 +0800355 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
356 struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
Hoan Tran6437c7b2017-09-08 15:41:15 -0700357 struct dwapb_context *ctx = gpio->ports[0].ctx;
Andy Shevchenkoe092bc52020-04-15 17:15:26 +0300358 irq_hw_number_t bit = irqd_to_hwirq(d);
Hoan Tran6437c7b2017-09-08 15:41:15 -0700359
360 if (enable)
Andy Shevchenkoe092bc52020-04-15 17:15:26 +0300361 ctx->wake_en |= BIT(bit);
Hoan Tran6437c7b2017-09-08 15:41:15 -0700362 else
Andy Shevchenkoe092bc52020-04-15 17:15:26 +0300363 ctx->wake_en &= ~BIT(bit);
Hoan Tran6437c7b2017-09-08 15:41:15 -0700364
365 return 0;
366}
367#endif
368
Weike Chen5d60d9e2014-09-17 09:18:41 -0700369static int dwapb_gpio_set_debounce(struct gpio_chip *gc,
370 unsigned offset, unsigned debounce)
371{
Linus Walleij0f4630f2015-12-04 14:02:58 +0100372 struct dwapb_gpio_port *port = gpiochip_get_data(gc);
Weike Chen5d60d9e2014-09-17 09:18:41 -0700373 struct dwapb_gpio *gpio = port->gpio;
374 unsigned long flags, val_deb;
Linus Walleijd97a1b52017-10-20 12:26:51 +0200375 unsigned long mask = BIT(offset);
Weike Chen5d60d9e2014-09-17 09:18:41 -0700376
Linus Walleij0f4630f2015-12-04 14:02:58 +0100377 spin_lock_irqsave(&gc->bgpio_lock, flags);
Weike Chen5d60d9e2014-09-17 09:18:41 -0700378
379 val_deb = dwapb_read(gpio, GPIO_PORTA_DEBOUNCE);
380 if (debounce)
Andy Shevchenko48ce8052020-04-15 17:15:29 +0300381 val_deb |= mask;
Weike Chen5d60d9e2014-09-17 09:18:41 -0700382 else
Andy Shevchenko48ce8052020-04-15 17:15:29 +0300383 val_deb &= ~mask;
384 dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, val_deb);
Weike Chen5d60d9e2014-09-17 09:18:41 -0700385
Linus Walleij0f4630f2015-12-04 14:02:58 +0100386 spin_unlock_irqrestore(&gc->bgpio_lock, flags);
Weike Chen5d60d9e2014-09-17 09:18:41 -0700387
388 return 0;
389}
390
Mika Westerberg2956b5d2017-01-23 15:34:34 +0300391static int dwapb_gpio_set_config(struct gpio_chip *gc, unsigned offset,
392 unsigned long config)
393{
394 u32 debounce;
395
396 if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE)
397 return -ENOTSUPP;
398
399 debounce = pinconf_to_config_argument(config);
400 return dwapb_gpio_set_debounce(gc, offset, debounce);
401}
402
Serge Semin0ea68392020-07-30 18:28:02 +0300403static int dwapb_convert_irqs(struct dwapb_gpio_port_irqchip *pirq,
404 struct dwapb_port_property *pp)
405{
406 int i;
407
408 /* Group all available IRQs into an array of parental IRQs. */
409 for (i = 0; i < pp->ngpio; ++i) {
410 if (!pp->irq[i])
411 continue;
412
413 pirq->irq[pirq->nr_irqs++] = pp->irq[i];
414 }
415
416 return pirq->nr_irqs ? 0 : -ENOENT;
417}
418
Jamie Iles7779b3452014-02-25 17:01:01 -0600419static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
Weike Chen3d2613c2014-09-17 09:18:39 -0700420 struct dwapb_gpio_port *port,
421 struct dwapb_port_property *pp)
Jamie Iles7779b3452014-02-25 17:01:01 -0600422{
Serge Semin0ea68392020-07-30 18:28:02 +0300423 struct dwapb_gpio_port_irqchip *pirq;
Linus Walleij0f4630f2015-12-04 14:02:58 +0100424 struct gpio_chip *gc = &port->gc;
Serge Semin0ea68392020-07-30 18:28:02 +0300425 struct gpio_irq_chip *girq;
426 int err;
Jamie Iles7779b3452014-02-25 17:01:01 -0600427
Serge Semin0ea68392020-07-30 18:28:02 +0300428 pirq = devm_kzalloc(gpio->dev, sizeof(*pirq), GFP_KERNEL);
429 if (!pirq)
430 return;
431
432 if (dwapb_convert_irqs(pirq, pp)) {
Andy Shevchenko551cb862020-05-19 16:12:33 +0300433 dev_warn(gpio->dev, "no IRQ for port%d\n", pp->idx);
Serge Semin0ea68392020-07-30 18:28:02 +0300434 goto err_kfree_pirq;
Andy Shevchenko551cb862020-05-19 16:12:33 +0300435 }
436
Serge Semin0ea68392020-07-30 18:28:02 +0300437 girq = &gc->irq;
438 girq->handler = handle_bad_irq;
439 girq->default_type = IRQ_TYPE_NONE;
Jamie Iles7779b3452014-02-25 17:01:01 -0600440
Serge Semin0ea68392020-07-30 18:28:02 +0300441 port->pirq = pirq;
442 pirq->irqchip.name = DWAPB_DRIVER_NAME;
443 pirq->irqchip.irq_ack = dwapb_irq_ack;
444 pirq->irqchip.irq_mask = dwapb_irq_mask;
445 pirq->irqchip.irq_unmask = dwapb_irq_unmask;
446 pirq->irqchip.irq_set_type = dwapb_irq_set_type;
447 pirq->irqchip.irq_enable = dwapb_irq_enable;
448 pirq->irqchip.irq_disable = dwapb_irq_disable;
Hoan Tran6437c7b2017-09-08 15:41:15 -0700449#ifdef CONFIG_PM_SLEEP
Serge Semin0ea68392020-07-30 18:28:02 +0300450 pirq->irqchip.irq_set_wake = dwapb_irq_set_wake;
Hoan Tran6437c7b2017-09-08 15:41:15 -0700451#endif
Jamie Iles7779b3452014-02-25 17:01:01 -0600452
Andy Shevchenkoc1b291e2021-08-04 19:00:16 +0300453 /*
454 * Intel ACPI-based platforms mostly have the DesignWare APB GPIO
455 * IRQ lane shared between several devices. In that case the parental
456 * IRQ has to be handled in the shared way so to be properly delivered
457 * to all the connected devices.
458 */
459 if (has_acpi_companion(gpio->dev)) {
Serge Semin0ea68392020-07-30 18:28:02 +0300460 girq->num_parents = 0;
461 girq->parents = NULL;
462 girq->parent_handler = NULL;
463
Phil Edworthye6ca26a2018-04-26 17:19:47 +0100464 err = devm_request_irq(gpio->dev, pp->irq[0],
Weike Chen3d2613c2014-09-17 09:18:39 -0700465 dwapb_irq_handler_mfd,
Andy Shevchenkoc58220c2020-04-15 17:15:21 +0300466 IRQF_SHARED, DWAPB_DRIVER_NAME, gpio);
Weike Chen3d2613c2014-09-17 09:18:39 -0700467 if (err) {
468 dev_err(gpio->dev, "error requesting IRQ\n");
Serge Semin0ea68392020-07-30 18:28:02 +0300469 goto err_kfree_pirq;
Weike Chen3d2613c2014-09-17 09:18:39 -0700470 }
Andy Shevchenkoc1b291e2021-08-04 19:00:16 +0300471 } else {
472 girq->num_parents = pirq->nr_irqs;
473 girq->parents = pirq->irq;
474 girq->parent_handler_data = gpio;
475 girq->parent_handler = dwapb_irq_handler;
Weike Chen3d2613c2014-09-17 09:18:39 -0700476 }
Jamie Iles7779b3452014-02-25 17:01:01 -0600477
Serge Semin0ea68392020-07-30 18:28:02 +0300478 girq->chip = &pirq->irqchip;
Jamie Iles7779b3452014-02-25 17:01:01 -0600479
Serge Semin0ea68392020-07-30 18:28:02 +0300480 return;
Jamie Iles7779b3452014-02-25 17:01:01 -0600481
Serge Semin0ea68392020-07-30 18:28:02 +0300482err_kfree_pirq:
483 devm_kfree(gpio->dev, pirq);
Jamie Iles7779b3452014-02-25 17:01:01 -0600484}
485
486static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
Weike Chen3d2613c2014-09-17 09:18:39 -0700487 struct dwapb_port_property *pp,
Jamie Iles7779b3452014-02-25 17:01:01 -0600488 unsigned int offs)
489{
490 struct dwapb_gpio_port *port;
Jamie Iles7779b3452014-02-25 17:01:01 -0600491 void __iomem *dat, *set, *dirout;
492 int err;
493
Jamie Iles7779b3452014-02-25 17:01:01 -0600494 port = &gpio->ports[offs];
495 port->gpio = gpio;
Weike Chen1e960db2014-09-17 09:18:42 -0700496 port->idx = pp->idx;
497
498#ifdef CONFIG_PM_SLEEP
499 port->ctx = devm_kzalloc(gpio->dev, sizeof(*port->ctx), GFP_KERNEL);
500 if (!port->ctx)
501 return -ENOMEM;
502#endif
Jamie Iles7779b3452014-02-25 17:01:01 -0600503
Andy Shevchenko1475b622020-04-22 14:06:54 +0300504 dat = gpio->regs + GPIO_EXT_PORTA + pp->idx * GPIO_EXT_PORT_STRIDE;
505 set = gpio->regs + GPIO_SWPORTA_DR + pp->idx * GPIO_SWPORT_DR_STRIDE;
506 dirout = gpio->regs + GPIO_SWPORTA_DDR + pp->idx * GPIO_SWPORT_DDR_STRIDE;
Jamie Iles7779b3452014-02-25 17:01:01 -0600507
Linus Walleij62c16232018-02-08 18:00:05 +0100508 /* This registers 32 GPIO lines per port */
Linus Walleij0f4630f2015-12-04 14:02:58 +0100509 err = bgpio_init(&port->gc, gpio->dev, 4, dat, set, NULL, dirout,
Linus Walleijd97a1b52017-10-20 12:26:51 +0200510 NULL, 0);
Jamie Iles7779b3452014-02-25 17:01:01 -0600511 if (err) {
Jiang Qiue8159182016-04-28 17:32:01 +0800512 dev_err(gpio->dev, "failed to init gpio chip for port%d\n",
513 port->idx);
Jamie Iles7779b3452014-02-25 17:01:01 -0600514 return err;
515 }
516
Andy Shevchenko80f60eb2021-12-23 12:38:09 +0200517 port->gc.fwnode = pp->fwnode;
Linus Walleij0f4630f2015-12-04 14:02:58 +0100518 port->gc.ngpio = pp->ngpio;
519 port->gc.base = pp->gpio_base;
Jamie Iles7779b3452014-02-25 17:01:01 -0600520
Weike Chen5d60d9e2014-09-17 09:18:41 -0700521 /* Only port A support debounce */
522 if (pp->idx == 0)
Mika Westerberg2956b5d2017-01-23 15:34:34 +0300523 port->gc.set_config = dwapb_gpio_set_config;
Weike Chen5d60d9e2014-09-17 09:18:41 -0700524
Andy Shevchenko551cb862020-05-19 16:12:33 +0300525 /* Only port A can provide interrupts in all configurations of the IP */
526 if (pp->idx == 0)
Weike Chen3d2613c2014-09-17 09:18:39 -0700527 dwapb_configure_irqs(gpio, port, pp);
Jamie Iles7779b3452014-02-25 17:01:01 -0600528
Serge Seminfeeaefd2020-07-30 18:28:07 +0300529 err = devm_gpiochip_add_data(gpio->dev, &port->gc, port);
Andy Shevchenko494a94e2020-05-19 16:12:30 +0300530 if (err) {
Jiang Qiue8159182016-04-28 17:32:01 +0800531 dev_err(gpio->dev, "failed to register gpiochip for port%d\n",
532 port->idx);
Andy Shevchenko494a94e2020-05-19 16:12:30 +0300533 return err;
534 }
Jamie Iles7779b3452014-02-25 17:01:01 -0600535
Andy Shevchenko494a94e2020-05-19 16:12:30 +0300536 return 0;
Jamie Iles7779b3452014-02-25 17:01:01 -0600537}
538
Andy Shevchenko4c2b54f2020-04-15 17:15:32 +0300539static void dwapb_get_irq(struct device *dev, struct fwnode_handle *fwnode,
540 struct dwapb_port_property *pp)
541{
Andy Shevchenkobd56b052021-06-01 19:21:28 +0300542 int irq, j;
Andy Shevchenko4c2b54f2020-04-15 17:15:32 +0300543
544 for (j = 0; j < pp->ngpio; j++) {
Andy Shevchenkobd56b052021-06-01 19:21:28 +0300545 if (has_acpi_companion(dev))
Andy Shevchenkoaa909392020-05-19 16:12:32 +0300546 irq = platform_get_irq_optional(to_platform_device(dev), j);
Andy Shevchenkobd56b052021-06-01 19:21:28 +0300547 else
548 irq = fwnode_irq_get(fwnode, j);
Andy Shevchenkoaa909392020-05-19 16:12:32 +0300549 if (irq > 0)
550 pp->irq[j] = irq;
Andy Shevchenko4c2b54f2020-04-15 17:15:32 +0300551 }
Andy Shevchenko4c2b54f2020-04-15 17:15:32 +0300552}
553
554static struct dwapb_platform_data *dwapb_gpio_get_pdata(struct device *dev)
Weike Chen3d2613c2014-09-17 09:18:39 -0700555{
Jiang Qiu4ba8cfa2016-04-28 17:32:02 +0800556 struct fwnode_handle *fwnode;
Weike Chen3d2613c2014-09-17 09:18:39 -0700557 struct dwapb_platform_data *pdata;
558 struct dwapb_port_property *pp;
559 int nports;
Andy Shevchenko4c2b54f2020-04-15 17:15:32 +0300560 int i;
Weike Chen3d2613c2014-09-17 09:18:39 -0700561
Jiang Qiu4ba8cfa2016-04-28 17:32:02 +0800562 nports = device_get_child_node_count(dev);
Weike Chen3d2613c2014-09-17 09:18:39 -0700563 if (nports == 0)
564 return ERR_PTR(-ENODEV);
565
Axel Linda9df932014-12-28 15:23:14 +0800566 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
Weike Chen3d2613c2014-09-17 09:18:39 -0700567 if (!pdata)
568 return ERR_PTR(-ENOMEM);
569
Axel Linda9df932014-12-28 15:23:14 +0800570 pdata->properties = devm_kcalloc(dev, nports, sizeof(*pp), GFP_KERNEL);
571 if (!pdata->properties)
Weike Chen3d2613c2014-09-17 09:18:39 -0700572 return ERR_PTR(-ENOMEM);
Weike Chen3d2613c2014-09-17 09:18:39 -0700573
574 pdata->nports = nports;
575
576 i = 0;
Jiang Qiu4ba8cfa2016-04-28 17:32:02 +0800577 device_for_each_child_node(dev, fwnode) {
Weike Chen3d2613c2014-09-17 09:18:39 -0700578 pp = &pdata->properties[i++];
Jiang Qiu4ba8cfa2016-04-28 17:32:02 +0800579 pp->fwnode = fwnode;
Weike Chen3d2613c2014-09-17 09:18:39 -0700580
Jiang Qiu4ba8cfa2016-04-28 17:32:02 +0800581 if (fwnode_property_read_u32(fwnode, "reg", &pp->idx) ||
Weike Chen3d2613c2014-09-17 09:18:39 -0700582 pp->idx >= DWAPB_MAX_PORTS) {
Jiang Qiue8159182016-04-28 17:32:01 +0800583 dev_err(dev,
584 "missing/invalid port index for port%d\n", i);
Wei Yongjunbfab7c82016-07-10 02:17:36 +0000585 fwnode_handle_put(fwnode);
Weike Chen3d2613c2014-09-17 09:18:39 -0700586 return ERR_PTR(-EINVAL);
587 }
588
Serge Semin75694862020-07-30 18:27:59 +0300589 if (fwnode_property_read_u32(fwnode, "ngpios", &pp->ngpio) &&
590 fwnode_property_read_u32(fwnode, "snps,nr-gpios", &pp->ngpio)) {
Jiang Qiue8159182016-04-28 17:32:01 +0800591 dev_info(dev,
592 "failed to get number of gpios for port%d\n",
593 i);
Serge Seminf9f890b2020-07-30 18:28:01 +0300594 pp->ngpio = DWAPB_MAX_GPIOS;
Weike Chen3d2613c2014-09-17 09:18:39 -0700595 }
596
Phil Edworthyda069d52018-05-23 09:52:44 +0100597 pp->gpio_base = -1;
598
Andy Shevchenkof973be82021-08-04 19:00:17 +0300599 /* For internal use only, new platforms mustn't exercise this */
600 if (is_software_node(fwnode))
601 fwnode_property_read_u32(fwnode, "gpio-base", &pp->gpio_base);
602
Weike Chen3d2613c2014-09-17 09:18:39 -0700603 /*
604 * Only port A can provide interrupts in all configurations of
605 * the IP.
606 */
Andy Shevchenko4c2b54f2020-04-15 17:15:32 +0300607 if (pp->idx == 0)
608 dwapb_get_irq(dev, fwnode, pp);
Weike Chen3d2613c2014-09-17 09:18:39 -0700609 }
610
611 return pdata;
612}
613
Serge Semin4731d802020-07-30 18:28:05 +0300614static void dwapb_assert_reset(void *data)
615{
616 struct dwapb_gpio *gpio = data;
617
618 reset_control_assert(gpio->rst);
619}
620
621static int dwapb_get_reset(struct dwapb_gpio *gpio)
622{
623 int err;
624
625 gpio->rst = devm_reset_control_get_optional_shared(gpio->dev, NULL);
Damien Le Moal7d3615a2020-11-30 19:57:49 +0900626 if (IS_ERR(gpio->rst))
627 return dev_err_probe(gpio->dev, PTR_ERR(gpio->rst),
628 "Cannot get reset descriptor\n");
Serge Semin4731d802020-07-30 18:28:05 +0300629
630 err = reset_control_deassert(gpio->rst);
631 if (err) {
632 dev_err(gpio->dev, "Cannot deassert reset lane\n");
633 return err;
634 }
635
636 return devm_add_action_or_reset(gpio->dev, dwapb_assert_reset, gpio);
637}
638
Serge Semindaa3f582020-07-30 18:28:06 +0300639static void dwapb_disable_clks(void *data)
640{
641 struct dwapb_gpio *gpio = data;
642
643 clk_bulk_disable_unprepare(DWAPB_NR_CLOCKS, gpio->clks);
644}
645
646static int dwapb_get_clks(struct dwapb_gpio *gpio)
647{
648 int err;
649
650 /* Optional bus and debounce clocks */
651 gpio->clks[0].id = "bus";
652 gpio->clks[1].id = "db";
653 err = devm_clk_bulk_get_optional(gpio->dev, DWAPB_NR_CLOCKS,
654 gpio->clks);
655 if (err) {
656 dev_err(gpio->dev, "Cannot get APB/Debounce clocks\n");
657 return err;
658 }
659
660 err = clk_bulk_prepare_enable(DWAPB_NR_CLOCKS, gpio->clks);
661 if (err) {
662 dev_err(gpio->dev, "Cannot enable APB/Debounce clocks\n");
663 return err;
664 }
665
666 return devm_add_action_or_reset(gpio->dev, dwapb_disable_clks, gpio);
667}
668
Hoan Trana72b8c42017-02-21 11:32:43 -0800669static const struct of_device_id dwapb_of_match[] = {
Andy Shevchenkoe1610432021-11-30 18:49:56 +0200670 { .compatible = "snps,dw-apb-gpio", .data = (void *)GPIO_REG_OFFSET_V1},
Hoan Trana72b8c42017-02-21 11:32:43 -0800671 { .compatible = "apm,xgene-gpio-v2", .data = (void *)GPIO_REG_OFFSET_V2},
672 { /* Sentinel */ }
673};
674MODULE_DEVICE_TABLE(of, dwapb_of_match);
675
676static const struct acpi_device_id dwapb_acpi_match[] = {
Andy Shevchenkoe1610432021-11-30 18:49:56 +0200677 {"HISI0181", GPIO_REG_OFFSET_V1},
678 {"APMC0D07", GPIO_REG_OFFSET_V1},
Hoan Trana72b8c42017-02-21 11:32:43 -0800679 {"APMC0D81", GPIO_REG_OFFSET_V2},
680 { }
681};
682MODULE_DEVICE_TABLE(acpi, dwapb_acpi_match);
683
Jamie Iles7779b3452014-02-25 17:01:01 -0600684static int dwapb_gpio_probe(struct platform_device *pdev)
685{
Weike Chen3d2613c2014-09-17 09:18:39 -0700686 unsigned int i;
Jamie Iles7779b3452014-02-25 17:01:01 -0600687 struct dwapb_gpio *gpio;
Jamie Iles7779b3452014-02-25 17:01:01 -0600688 int err;
Andy Shevchenko5111c2b2021-08-04 19:00:19 +0300689 struct dwapb_platform_data *pdata;
Weike Chen3d2613c2014-09-17 09:18:39 -0700690 struct device *dev = &pdev->dev;
Jamie Iles7779b3452014-02-25 17:01:01 -0600691
Andy Shevchenko5111c2b2021-08-04 19:00:19 +0300692 pdata = dwapb_gpio_get_pdata(dev);
693 if (IS_ERR(pdata))
694 return PTR_ERR(pdata);
Weike Chen3d2613c2014-09-17 09:18:39 -0700695
696 gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
Axel Linda9df932014-12-28 15:23:14 +0800697 if (!gpio)
698 return -ENOMEM;
699
Weike Chen3d2613c2014-09-17 09:18:39 -0700700 gpio->dev = &pdev->dev;
701 gpio->nr_ports = pdata->nports;
702
Serge Semin4731d802020-07-30 18:28:05 +0300703 err = dwapb_get_reset(gpio);
704 if (err)
705 return err;
Alan Tull07901a92017-10-11 11:34:44 -0500706
Weike Chen3d2613c2014-09-17 09:18:39 -0700707 gpio->ports = devm_kcalloc(&pdev->dev, gpio->nr_ports,
Jamie Iles7779b3452014-02-25 17:01:01 -0600708 sizeof(*gpio->ports), GFP_KERNEL);
Axel Linda9df932014-12-28 15:23:14 +0800709 if (!gpio->ports)
710 return -ENOMEM;
Jamie Iles7779b3452014-02-25 17:01:01 -0600711
Enrico Weigelt, metux IT consult2a7194e2019-03-11 19:54:47 +0100712 gpio->regs = devm_platform_ioremap_resource(pdev, 0);
Axel Linda9df932014-12-28 15:23:14 +0800713 if (IS_ERR(gpio->regs))
714 return PTR_ERR(gpio->regs);
Jamie Iles7779b3452014-02-25 17:01:01 -0600715
Serge Semindaa3f582020-07-30 18:28:06 +0300716 err = dwapb_get_clks(gpio);
717 if (err)
Serge Semin5c544c92020-03-23 22:54:00 +0300718 return err;
Phil Edworthye6bf3772018-03-12 18:30:56 +0000719
Andy Shevchenko9826bbe2020-04-15 17:15:27 +0300720 gpio->flags = (uintptr_t)device_get_match_data(dev);
Hoan Trana72b8c42017-02-21 11:32:43 -0800721
Weike Chen3d2613c2014-09-17 09:18:39 -0700722 for (i = 0; i < gpio->nr_ports; i++) {
723 err = dwapb_gpio_add_port(gpio, &pdata->properties[i], i);
Jamie Iles7779b3452014-02-25 17:01:01 -0600724 if (err)
Serge Seminfeeaefd2020-07-30 18:28:07 +0300725 return err;
Jamie Iles7779b3452014-02-25 17:01:01 -0600726 }
Jamie Iles7779b3452014-02-25 17:01:01 -0600727
Luo Jiaxing60593df2020-11-27 16:50:02 +0800728 platform_set_drvdata(pdev, gpio);
729
Jamie Iles7779b3452014-02-25 17:01:01 -0600730 return 0;
731}
732
Weike Chen1e960db2014-09-17 09:18:42 -0700733#ifdef CONFIG_PM_SLEEP
734static int dwapb_gpio_suspend(struct device *dev)
735{
Wolfram Sangdeb19ac2018-10-21 21:59:56 +0200736 struct dwapb_gpio *gpio = dev_get_drvdata(dev);
Linus Walleij0f4630f2015-12-04 14:02:58 +0100737 struct gpio_chip *gc = &gpio->ports[0].gc;
Weike Chen1e960db2014-09-17 09:18:42 -0700738 unsigned long flags;
739 int i;
740
Linus Walleij0f4630f2015-12-04 14:02:58 +0100741 spin_lock_irqsave(&gc->bgpio_lock, flags);
Weike Chen1e960db2014-09-17 09:18:42 -0700742 for (i = 0; i < gpio->nr_ports; i++) {
743 unsigned int offset;
744 unsigned int idx = gpio->ports[i].idx;
745 struct dwapb_context *ctx = gpio->ports[i].ctx;
746
Linus Walleij89f99fe2018-02-08 17:03:58 +0100747 offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_STRIDE;
Weike Chen1e960db2014-09-17 09:18:42 -0700748 ctx->dir = dwapb_read(gpio, offset);
749
Linus Walleij89f99fe2018-02-08 17:03:58 +0100750 offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_STRIDE;
Weike Chen1e960db2014-09-17 09:18:42 -0700751 ctx->data = dwapb_read(gpio, offset);
752
Linus Walleij89f99fe2018-02-08 17:03:58 +0100753 offset = GPIO_EXT_PORTA + idx * GPIO_EXT_PORT_STRIDE;
Weike Chen1e960db2014-09-17 09:18:42 -0700754 ctx->ext = dwapb_read(gpio, offset);
755
756 /* Only port A can provide interrupts */
757 if (idx == 0) {
758 ctx->int_mask = dwapb_read(gpio, GPIO_INTMASK);
759 ctx->int_en = dwapb_read(gpio, GPIO_INTEN);
760 ctx->int_pol = dwapb_read(gpio, GPIO_INT_POLARITY);
761 ctx->int_type = dwapb_read(gpio, GPIO_INTTYPE_LEVEL);
762 ctx->int_deb = dwapb_read(gpio, GPIO_PORTA_DEBOUNCE);
763
764 /* Mask out interrupts */
Andy Shevchenko1afbc802020-04-22 14:06:53 +0300765 dwapb_write(gpio, GPIO_INTMASK, ~ctx->wake_en);
Weike Chen1e960db2014-09-17 09:18:42 -0700766 }
767 }
Linus Walleij0f4630f2015-12-04 14:02:58 +0100768 spin_unlock_irqrestore(&gc->bgpio_lock, flags);
Weike Chen1e960db2014-09-17 09:18:42 -0700769
Serge Semin5c544c92020-03-23 22:54:00 +0300770 clk_bulk_disable_unprepare(DWAPB_NR_CLOCKS, gpio->clks);
Phil Edworthye6bf3772018-03-12 18:30:56 +0000771
Weike Chen1e960db2014-09-17 09:18:42 -0700772 return 0;
773}
774
775static int dwapb_gpio_resume(struct device *dev)
776{
Wolfram Sangdeb19ac2018-10-21 21:59:56 +0200777 struct dwapb_gpio *gpio = dev_get_drvdata(dev);
Linus Walleij0f4630f2015-12-04 14:02:58 +0100778 struct gpio_chip *gc = &gpio->ports[0].gc;
Weike Chen1e960db2014-09-17 09:18:42 -0700779 unsigned long flags;
Serge Semin5c544c92020-03-23 22:54:00 +0300780 int i, err;
Weike Chen1e960db2014-09-17 09:18:42 -0700781
Serge Semin5c544c92020-03-23 22:54:00 +0300782 err = clk_bulk_prepare_enable(DWAPB_NR_CLOCKS, gpio->clks);
783 if (err) {
784 dev_err(gpio->dev, "Cannot reenable APB/Debounce clocks\n");
785 return err;
786 }
Phil Edworthye6bf3772018-03-12 18:30:56 +0000787
Linus Walleij0f4630f2015-12-04 14:02:58 +0100788 spin_lock_irqsave(&gc->bgpio_lock, flags);
Weike Chen1e960db2014-09-17 09:18:42 -0700789 for (i = 0; i < gpio->nr_ports; i++) {
790 unsigned int offset;
791 unsigned int idx = gpio->ports[i].idx;
792 struct dwapb_context *ctx = gpio->ports[i].ctx;
793
Linus Walleij89f99fe2018-02-08 17:03:58 +0100794 offset = GPIO_SWPORTA_DR + idx * GPIO_SWPORT_DR_STRIDE;
Weike Chen1e960db2014-09-17 09:18:42 -0700795 dwapb_write(gpio, offset, ctx->data);
796
Linus Walleij89f99fe2018-02-08 17:03:58 +0100797 offset = GPIO_SWPORTA_DDR + idx * GPIO_SWPORT_DDR_STRIDE;
Weike Chen1e960db2014-09-17 09:18:42 -0700798 dwapb_write(gpio, offset, ctx->dir);
799
Linus Walleij89f99fe2018-02-08 17:03:58 +0100800 offset = GPIO_EXT_PORTA + idx * GPIO_EXT_PORT_STRIDE;
Weike Chen1e960db2014-09-17 09:18:42 -0700801 dwapb_write(gpio, offset, ctx->ext);
802
803 /* Only port A can provide interrupts */
804 if (idx == 0) {
805 dwapb_write(gpio, GPIO_INTTYPE_LEVEL, ctx->int_type);
806 dwapb_write(gpio, GPIO_INT_POLARITY, ctx->int_pol);
807 dwapb_write(gpio, GPIO_PORTA_DEBOUNCE, ctx->int_deb);
808 dwapb_write(gpio, GPIO_INTEN, ctx->int_en);
809 dwapb_write(gpio, GPIO_INTMASK, ctx->int_mask);
810
811 /* Clear out spurious interrupts */
812 dwapb_write(gpio, GPIO_PORTA_EOI, 0xffffffff);
813 }
814 }
Linus Walleij0f4630f2015-12-04 14:02:58 +0100815 spin_unlock_irqrestore(&gc->bgpio_lock, flags);
Weike Chen1e960db2014-09-17 09:18:42 -0700816
817 return 0;
818}
819#endif
820
821static SIMPLE_DEV_PM_OPS(dwapb_gpio_pm_ops, dwapb_gpio_suspend,
822 dwapb_gpio_resume);
823
Jamie Iles7779b3452014-02-25 17:01:01 -0600824static struct platform_driver dwapb_gpio_driver = {
825 .driver = {
Andy Shevchenkoc58220c2020-04-15 17:15:21 +0300826 .name = DWAPB_DRIVER_NAME,
Weike Chen1e960db2014-09-17 09:18:42 -0700827 .pm = &dwapb_gpio_pm_ops,
Andy Shevchenkoc59042e2020-04-15 17:15:31 +0300828 .of_match_table = dwapb_of_match,
829 .acpi_match_table = dwapb_acpi_match,
Jamie Iles7779b3452014-02-25 17:01:01 -0600830 },
831 .probe = dwapb_gpio_probe,
Jamie Iles7779b3452014-02-25 17:01:01 -0600832};
833
834module_platform_driver(dwapb_gpio_driver);
835
836MODULE_LICENSE("GPL");
837MODULE_AUTHOR("Jamie Iles");
838MODULE_DESCRIPTION("Synopsys DesignWare APB GPIO driver");
Andy Shevchenkoc58220c2020-04-15 17:15:21 +0300839MODULE_ALIAS("platform:" DWAPB_DRIVER_NAME);