1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2c103de24SGrant Likely /*
3c103de24SGrant Likely * Copyright (C) 2008, 2009 Provigent Ltd.
4c103de24SGrant Likely *
5ef3e7100SPaul Gortmaker * Author: Baruch Siach <baruch@tkos.co.il>
6ef3e7100SPaul Gortmaker *
7c103de24SGrant Likely * Driver for the ARM PrimeCell(tm) General Purpose Input/Output (PL061)
8c103de24SGrant Likely *
9c103de24SGrant Likely * Data sheet: ARM DDI 0190B, September 2000
10c103de24SGrant Likely */
11*5b937a83SAndy Shevchenko #include <linux/amba/bus.h>
12*5b937a83SAndy Shevchenko #include <linux/bitops.h>
13*5b937a83SAndy Shevchenko #include <linux/device.h>
14c103de24SGrant Likely #include <linux/errno.h>
15*5b937a83SAndy Shevchenko #include <linux/gpio/driver.h>
16ef3e7100SPaul Gortmaker #include <linux/init.h>
17*5b937a83SAndy Shevchenko #include <linux/interrupt.h>
18c103de24SGrant Likely #include <linux/io.h>
19c103de24SGrant Likely #include <linux/ioport.h>
20c103de24SGrant Likely #include <linux/irq.h>
21de88cbb7SCatalin Marinas #include <linux/irqchip/chained_irq.h>
2261684440SRob Herring #include <linux/module.h>
2339b70ee0SHaojian Zhuang #include <linux/pinctrl/consumer.h>
24e198a8deSDeepak Sikri #include <linux/pm.h>
25*5b937a83SAndy Shevchenko #include <linux/seq_file.h>
26*5b937a83SAndy Shevchenko #include <linux/slab.h>
27*5b937a83SAndy Shevchenko #include <linux/spinlock.h>
28c103de24SGrant Likely
29c103de24SGrant Likely #define GPIODIR 0x400
30c103de24SGrant Likely #define GPIOIS 0x404
31c103de24SGrant Likely #define GPIOIBE 0x408
32c103de24SGrant Likely #define GPIOIEV 0x40C
33c103de24SGrant Likely #define GPIOIE 0x410
34c103de24SGrant Likely #define GPIORIS 0x414
35c103de24SGrant Likely #define GPIOMIS 0x418
36c103de24SGrant Likely #define GPIOIC 0x41C
37c103de24SGrant Likely
38c103de24SGrant Likely #define PL061_GPIO_NR 8
39c103de24SGrant Likely
40e198a8deSDeepak Sikri #ifdef CONFIG_PM
41e198a8deSDeepak Sikri struct pl061_context_save_regs {
42e198a8deSDeepak Sikri u8 gpio_data;
43e198a8deSDeepak Sikri u8 gpio_dir;
44e198a8deSDeepak Sikri u8 gpio_is;
45e198a8deSDeepak Sikri u8 gpio_ibe;
46e198a8deSDeepak Sikri u8 gpio_iev;
47e198a8deSDeepak Sikri u8 gpio_ie;
48e198a8deSDeepak Sikri };
49e198a8deSDeepak Sikri #endif
50c103de24SGrant Likely
51538f76c5SLinus Walleij struct pl061 {
5299b9b45dSJulia Cartwright raw_spinlock_t lock;
53c103de24SGrant Likely
54c103de24SGrant Likely void __iomem *base;
55c103de24SGrant Likely struct gpio_chip gc;
569c18be8eSLinus Walleij int parent_irq;
57e198a8deSDeepak Sikri
58e198a8deSDeepak Sikri #ifdef CONFIG_PM
59e198a8deSDeepak Sikri struct pl061_context_save_regs csave_regs;
60e198a8deSDeepak Sikri #endif
61c103de24SGrant Likely };
62c103de24SGrant Likely
pl061_get_direction(struct gpio_chip * gc,unsigned offset)633484f1beSLinus Walleij static int pl061_get_direction(struct gpio_chip *gc, unsigned offset)
643484f1beSLinus Walleij {
652796325fSLinus Walleij struct pl061 *pl061 = gpiochip_get_data(gc);
663484f1beSLinus Walleij
67e42615ecSMatti Vaittinen if (readb(pl061->base + GPIODIR) & BIT(offset))
68e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_OUT;
69e42615ecSMatti Vaittinen
70e42615ecSMatti Vaittinen return GPIO_LINE_DIRECTION_IN;
713484f1beSLinus Walleij }
723484f1beSLinus Walleij
pl061_direction_input(struct gpio_chip * gc,unsigned offset)73c103de24SGrant Likely static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
74c103de24SGrant Likely {
752796325fSLinus Walleij struct pl061 *pl061 = gpiochip_get_data(gc);
76c103de24SGrant Likely unsigned long flags;
77c103de24SGrant Likely unsigned char gpiodir;
78c103de24SGrant Likely
7999b9b45dSJulia Cartwright raw_spin_lock_irqsave(&pl061->lock, flags);
802796325fSLinus Walleij gpiodir = readb(pl061->base + GPIODIR);
81bea41504SJavier Martinez Canillas gpiodir &= ~(BIT(offset));
822796325fSLinus Walleij writeb(gpiodir, pl061->base + GPIODIR);
8399b9b45dSJulia Cartwright raw_spin_unlock_irqrestore(&pl061->lock, flags);
84c103de24SGrant Likely
85c103de24SGrant Likely return 0;
86c103de24SGrant Likely }
87c103de24SGrant Likely
pl061_direction_output(struct gpio_chip * gc,unsigned offset,int value)88c103de24SGrant Likely static int pl061_direction_output(struct gpio_chip *gc, unsigned offset,
89c103de24SGrant Likely int value)
90c103de24SGrant Likely {
912796325fSLinus Walleij struct pl061 *pl061 = gpiochip_get_data(gc);
92c103de24SGrant Likely unsigned long flags;
93c103de24SGrant Likely unsigned char gpiodir;
94c103de24SGrant Likely
9599b9b45dSJulia Cartwright raw_spin_lock_irqsave(&pl061->lock, flags);
962796325fSLinus Walleij writeb(!!value << offset, pl061->base + (BIT(offset + 2)));
972796325fSLinus Walleij gpiodir = readb(pl061->base + GPIODIR);
98bea41504SJavier Martinez Canillas gpiodir |= BIT(offset);
992796325fSLinus Walleij writeb(gpiodir, pl061->base + GPIODIR);
100c103de24SGrant Likely
101c103de24SGrant Likely /*
102c103de24SGrant Likely * gpio value is set again, because pl061 doesn't allow to set value of
103c103de24SGrant Likely * a gpio pin before configuring it in OUT mode.
104c103de24SGrant Likely */
1052796325fSLinus Walleij writeb(!!value << offset, pl061->base + (BIT(offset + 2)));
10699b9b45dSJulia Cartwright raw_spin_unlock_irqrestore(&pl061->lock, flags);
107c103de24SGrant Likely
108c103de24SGrant Likely return 0;
109c103de24SGrant Likely }
110c103de24SGrant Likely
pl061_get_value(struct gpio_chip * gc,unsigned offset)111c103de24SGrant Likely static int pl061_get_value(struct gpio_chip *gc, unsigned offset)
112c103de24SGrant Likely {
1132796325fSLinus Walleij struct pl061 *pl061 = gpiochip_get_data(gc);
114c103de24SGrant Likely
1152796325fSLinus Walleij return !!readb(pl061->base + (BIT(offset + 2)));
116c103de24SGrant Likely }
117c103de24SGrant Likely
pl061_set_value(struct gpio_chip * gc,unsigned offset,int value)118c103de24SGrant Likely static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value)
119c103de24SGrant Likely {
1202796325fSLinus Walleij struct pl061 *pl061 = gpiochip_get_data(gc);
121c103de24SGrant Likely
1222796325fSLinus Walleij writeb(!!value << offset, pl061->base + (BIT(offset + 2)));
123c103de24SGrant Likely }
124c103de24SGrant Likely
pl061_irq_type(struct irq_data * d,unsigned trigger)125c103de24SGrant Likely static int pl061_irq_type(struct irq_data *d, unsigned trigger)
126c103de24SGrant Likely {
1278d5b24bdSLinus Walleij struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
1282796325fSLinus Walleij struct pl061 *pl061 = gpiochip_get_data(gc);
129f1f70479SHaojian Zhuang int offset = irqd_to_hwirq(d);
130c103de24SGrant Likely unsigned long flags;
131c103de24SGrant Likely u8 gpiois, gpioibe, gpioiev;
132438a2c9aSLinus Walleij u8 bit = BIT(offset);
133c103de24SGrant Likely
134c103de24SGrant Likely if (offset < 0 || offset >= PL061_GPIO_NR)
135c103de24SGrant Likely return -EINVAL;
136c103de24SGrant Likely
1371dbf7f29SLinus Walleij if ((trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) &&
1381dbf7f29SLinus Walleij (trigger & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)))
1391dbf7f29SLinus Walleij {
14058383c78SLinus Walleij dev_err(gc->parent,
1411dbf7f29SLinus Walleij "trying to configure line %d for both level and edge "
1421dbf7f29SLinus Walleij "detection, choose one!\n",
1431dbf7f29SLinus Walleij offset);
1441dbf7f29SLinus Walleij return -EINVAL;
1451dbf7f29SLinus Walleij }
1461dbf7f29SLinus Walleij
14721d4de14SDan Carpenter
14899b9b45dSJulia Cartwright raw_spin_lock_irqsave(&pl061->lock, flags);
14921d4de14SDan Carpenter
1502796325fSLinus Walleij gpioiev = readb(pl061->base + GPIOIEV);
1512796325fSLinus Walleij gpiois = readb(pl061->base + GPIOIS);
1522796325fSLinus Walleij gpioibe = readb(pl061->base + GPIOIBE);
15321d4de14SDan Carpenter
154438a2c9aSLinus Walleij if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
1551dbf7f29SLinus Walleij bool polarity = trigger & IRQ_TYPE_LEVEL_HIGH;
1561dbf7f29SLinus Walleij
1571dbf7f29SLinus Walleij /* Disable edge detection */
1581dbf7f29SLinus Walleij gpioibe &= ~bit;
1591dbf7f29SLinus Walleij /* Enable level detection */
160438a2c9aSLinus Walleij gpiois |= bit;
1611dbf7f29SLinus Walleij /* Select polarity */
1621dbf7f29SLinus Walleij if (polarity)
163438a2c9aSLinus Walleij gpioiev |= bit;
164438a2c9aSLinus Walleij else
165438a2c9aSLinus Walleij gpioiev &= ~bit;
16626ba9cd4SLinus Walleij irq_set_handler_locked(d, handle_level_irq);
16758383c78SLinus Walleij dev_dbg(gc->parent, "line %d: IRQ on %s level\n",
1681dbf7f29SLinus Walleij offset,
1691dbf7f29SLinus Walleij polarity ? "HIGH" : "LOW");
1701dbf7f29SLinus Walleij } else if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
1711dbf7f29SLinus Walleij /* Disable level detection */
1721dbf7f29SLinus Walleij gpiois &= ~bit;
1731dbf7f29SLinus Walleij /* Select both edges, setting this makes GPIOEV be ignored */
174438a2c9aSLinus Walleij gpioibe |= bit;
17526ba9cd4SLinus Walleij irq_set_handler_locked(d, handle_edge_irq);
17658383c78SLinus Walleij dev_dbg(gc->parent, "line %d: IRQ on both edges\n", offset);
1771dbf7f29SLinus Walleij } else if ((trigger & IRQ_TYPE_EDGE_RISING) ||
1781dbf7f29SLinus Walleij (trigger & IRQ_TYPE_EDGE_FALLING)) {
1791dbf7f29SLinus Walleij bool rising = trigger & IRQ_TYPE_EDGE_RISING;
1801dbf7f29SLinus Walleij
1811dbf7f29SLinus Walleij /* Disable level detection */
1821dbf7f29SLinus Walleij gpiois &= ~bit;
1831dbf7f29SLinus Walleij /* Clear detection on both edges */
184438a2c9aSLinus Walleij gpioibe &= ~bit;
1851dbf7f29SLinus Walleij /* Select edge */
1861dbf7f29SLinus Walleij if (rising)
187438a2c9aSLinus Walleij gpioiev |= bit;
1881dbf7f29SLinus Walleij else
189438a2c9aSLinus Walleij gpioiev &= ~bit;
19026ba9cd4SLinus Walleij irq_set_handler_locked(d, handle_edge_irq);
19158383c78SLinus Walleij dev_dbg(gc->parent, "line %d: IRQ on %s edge\n",
1921dbf7f29SLinus Walleij offset,
1931dbf7f29SLinus Walleij rising ? "RISING" : "FALLING");
1941dbf7f29SLinus Walleij } else {
1951dbf7f29SLinus Walleij /* No trigger: disable everything */
1961dbf7f29SLinus Walleij gpiois &= ~bit;
1971dbf7f29SLinus Walleij gpioibe &= ~bit;
1981dbf7f29SLinus Walleij gpioiev &= ~bit;
19926ba9cd4SLinus Walleij irq_set_handler_locked(d, handle_bad_irq);
20058383c78SLinus Walleij dev_warn(gc->parent, "no trigger selected for line %d\n",
2011dbf7f29SLinus Walleij offset);
202438a2c9aSLinus Walleij }
203438a2c9aSLinus Walleij
2042796325fSLinus Walleij writeb(gpiois, pl061->base + GPIOIS);
2052796325fSLinus Walleij writeb(gpioibe, pl061->base + GPIOIBE);
2062796325fSLinus Walleij writeb(gpioiev, pl061->base + GPIOIEV);
207c103de24SGrant Likely
20899b9b45dSJulia Cartwright raw_spin_unlock_irqrestore(&pl061->lock, flags);
209c103de24SGrant Likely
210c103de24SGrant Likely return 0;
211c103de24SGrant Likely }
212c103de24SGrant Likely
pl061_irq_handler(struct irq_desc * desc)213bd0b9ac4SThomas Gleixner static void pl061_irq_handler(struct irq_desc *desc)
214c103de24SGrant Likely {
215c103de24SGrant Likely unsigned long pending;
216c103de24SGrant Likely int offset;
2178d5b24bdSLinus Walleij struct gpio_chip *gc = irq_desc_get_handler_data(desc);
2182796325fSLinus Walleij struct pl061 *pl061 = gpiochip_get_data(gc);
219dece904dSRob Herring struct irq_chip *irqchip = irq_desc_get_chip(desc);
220c103de24SGrant Likely
221dece904dSRob Herring chained_irq_enter(irqchip, desc);
222c103de24SGrant Likely
2232796325fSLinus Walleij pending = readb(pl061->base + GPIOMIS);
2242de0dbc5SRob Herring if (pending) {
225c103de24SGrant Likely for_each_set_bit(offset, &pending, PL061_GPIO_NR)
226dbd1c54fSMarc Zyngier generic_handle_domain_irq(gc->irq.domain,
227dbd1c54fSMarc Zyngier offset);
228c103de24SGrant Likely }
2292de0dbc5SRob Herring
230dece904dSRob Herring chained_irq_exit(irqchip, desc);
231c103de24SGrant Likely }
232c103de24SGrant Likely
pl061_irq_mask(struct irq_data * d)233f1f70479SHaojian Zhuang static void pl061_irq_mask(struct irq_data *d)
2343ab52475SRob Herring {
2358d5b24bdSLinus Walleij struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
2362796325fSLinus Walleij struct pl061 *pl061 = gpiochip_get_data(gc);
237bea41504SJavier Martinez Canillas u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
238f1f70479SHaojian Zhuang u8 gpioie;
2393ab52475SRob Herring
24099b9b45dSJulia Cartwright raw_spin_lock(&pl061->lock);
2412796325fSLinus Walleij gpioie = readb(pl061->base + GPIOIE) & ~mask;
2422796325fSLinus Walleij writeb(gpioie, pl061->base + GPIOIE);
24399b9b45dSJulia Cartwright raw_spin_unlock(&pl061->lock);
24415d8c14aSMarc Zyngier
24515d8c14aSMarc Zyngier gpiochip_disable_irq(gc, d->hwirq);
246c103de24SGrant Likely }
247c103de24SGrant Likely
pl061_irq_unmask(struct irq_data * d)248f1f70479SHaojian Zhuang static void pl061_irq_unmask(struct irq_data *d)
249f1f70479SHaojian Zhuang {
2508d5b24bdSLinus Walleij struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
2512796325fSLinus Walleij struct pl061 *pl061 = gpiochip_get_data(gc);
252bea41504SJavier Martinez Canillas u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
253f1f70479SHaojian Zhuang u8 gpioie;
254f1f70479SHaojian Zhuang
25515d8c14aSMarc Zyngier gpiochip_enable_irq(gc, d->hwirq);
25615d8c14aSMarc Zyngier
25799b9b45dSJulia Cartwright raw_spin_lock(&pl061->lock);
2582796325fSLinus Walleij gpioie = readb(pl061->base + GPIOIE) | mask;
2592796325fSLinus Walleij writeb(gpioie, pl061->base + GPIOIE);
26099b9b45dSJulia Cartwright raw_spin_unlock(&pl061->lock);
261f1f70479SHaojian Zhuang }
262f1f70479SHaojian Zhuang
26326ba9cd4SLinus Walleij /**
26426ba9cd4SLinus Walleij * pl061_irq_ack() - ACK an edge IRQ
26526ba9cd4SLinus Walleij * @d: IRQ data for this IRQ
26626ba9cd4SLinus Walleij *
26726ba9cd4SLinus Walleij * This gets called from the edge IRQ handler to ACK the edge IRQ
26826ba9cd4SLinus Walleij * in the GPIOIC (interrupt-clear) register. For level IRQs this is
26926ba9cd4SLinus Walleij * not needed: these go away when the level signal goes away.
27026ba9cd4SLinus Walleij */
pl061_irq_ack(struct irq_data * d)27126ba9cd4SLinus Walleij static void pl061_irq_ack(struct irq_data *d)
27226ba9cd4SLinus Walleij {
27326ba9cd4SLinus Walleij struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
2742796325fSLinus Walleij struct pl061 *pl061 = gpiochip_get_data(gc);
27526ba9cd4SLinus Walleij u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR);
27626ba9cd4SLinus Walleij
27799b9b45dSJulia Cartwright raw_spin_lock(&pl061->lock);
2782796325fSLinus Walleij writeb(mask, pl061->base + GPIOIC);
27999b9b45dSJulia Cartwright raw_spin_unlock(&pl061->lock);
28026ba9cd4SLinus Walleij }
28126ba9cd4SLinus Walleij
pl061_irq_set_wake(struct irq_data * d,unsigned int state)2822f46205bSSudeep Holla static int pl061_irq_set_wake(struct irq_data *d, unsigned int state)
2832f46205bSSudeep Holla {
2842f46205bSSudeep Holla struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
2852796325fSLinus Walleij struct pl061 *pl061 = gpiochip_get_data(gc);
2862f46205bSSudeep Holla
2872796325fSLinus Walleij return irq_set_irq_wake(pl061->parent_irq, state);
2882f46205bSSudeep Holla }
2892f46205bSSudeep Holla
pl061_irq_print_chip(struct irq_data * data,struct seq_file * p)29015d8c14aSMarc Zyngier static void pl061_irq_print_chip(struct irq_data *data, struct seq_file *p)
29115d8c14aSMarc Zyngier {
29215d8c14aSMarc Zyngier struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
29315d8c14aSMarc Zyngier
29415d8c14aSMarc Zyngier seq_printf(p, dev_name(gc->parent));
29515d8c14aSMarc Zyngier }
29615d8c14aSMarc Zyngier
29715d8c14aSMarc Zyngier static const struct irq_chip pl061_irq_chip = {
29815d8c14aSMarc Zyngier .irq_ack = pl061_irq_ack,
29915d8c14aSMarc Zyngier .irq_mask = pl061_irq_mask,
30015d8c14aSMarc Zyngier .irq_unmask = pl061_irq_unmask,
30115d8c14aSMarc Zyngier .irq_set_type = pl061_irq_type,
30215d8c14aSMarc Zyngier .irq_set_wake = pl061_irq_set_wake,
30315d8c14aSMarc Zyngier .irq_print_chip = pl061_irq_print_chip,
30415d8c14aSMarc Zyngier .flags = IRQCHIP_IMMUTABLE,
30515d8c14aSMarc Zyngier GPIOCHIP_IRQ_RESOURCE_HELPERS,
30615d8c14aSMarc Zyngier };
30715d8c14aSMarc Zyngier
pl061_probe(struct amba_device * adev,const struct amba_id * id)3088944df72STobias Klauser static int pl061_probe(struct amba_device *adev, const struct amba_id *id)
309c103de24SGrant Likely {
3108944df72STobias Klauser struct device *dev = &adev->dev;
3112796325fSLinus Walleij struct pl061 *pl061;
31204ce935cSLinus Walleij struct gpio_irq_chip *girq;
3136da7b0ddSLinus Walleij int ret, irq;
314c103de24SGrant Likely
3152796325fSLinus Walleij pl061 = devm_kzalloc(dev, sizeof(*pl061), GFP_KERNEL);
3162796325fSLinus Walleij if (pl061 == NULL)
317c103de24SGrant Likely return -ENOMEM;
318c103de24SGrant Likely
3192796325fSLinus Walleij pl061->base = devm_ioremap_resource(dev, &adev->res);
3202796325fSLinus Walleij if (IS_ERR(pl061->base))
3212796325fSLinus Walleij return PTR_ERR(pl061->base);
322c103de24SGrant Likely
32399b9b45dSJulia Cartwright raw_spin_lock_init(&pl061->lock);
3242796325fSLinus Walleij pl061->gc.request = gpiochip_generic_request;
3252796325fSLinus Walleij pl061->gc.free = gpiochip_generic_free;
3266da7b0ddSLinus Walleij pl061->gc.base = -1;
3272796325fSLinus Walleij pl061->gc.get_direction = pl061_get_direction;
3282796325fSLinus Walleij pl061->gc.direction_input = pl061_direction_input;
3292796325fSLinus Walleij pl061->gc.direction_output = pl061_direction_output;
3302796325fSLinus Walleij pl061->gc.get = pl061_get_value;
3312796325fSLinus Walleij pl061->gc.set = pl061_set_value;
3322796325fSLinus Walleij pl061->gc.ngpio = PL061_GPIO_NR;
3332796325fSLinus Walleij pl061->gc.label = dev_name(dev);
3342796325fSLinus Walleij pl061->gc.parent = dev;
3352796325fSLinus Walleij pl061->gc.owner = THIS_MODULE;
336c103de24SGrant Likely
337c103de24SGrant Likely /*
338c103de24SGrant Likely * irq_chip support
339c103de24SGrant Likely */
3402796325fSLinus Walleij writeb(0, pl061->base + GPIOIE); /* disable irqs */
3418944df72STobias Klauser irq = adev->irq[0];
3421a555713SAlexander Sverdlin if (!irq)
3431a555713SAlexander Sverdlin dev_warn(&adev->dev, "IRQ support disabled\n");
3442796325fSLinus Walleij pl061->parent_irq = irq;
3458944df72STobias Klauser
34604ce935cSLinus Walleij girq = &pl061->gc.irq;
34715d8c14aSMarc Zyngier gpio_irq_chip_set_chip(girq, &pl061_irq_chip);
34804ce935cSLinus Walleij girq->parent_handler = pl061_irq_handler;
34904ce935cSLinus Walleij girq->num_parents = 1;
35004ce935cSLinus Walleij girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
35104ce935cSLinus Walleij GFP_KERNEL);
35204ce935cSLinus Walleij if (!girq->parents)
35304ce935cSLinus Walleij return -ENOMEM;
35404ce935cSLinus Walleij girq->parents[0] = irq;
35504ce935cSLinus Walleij girq->default_type = IRQ_TYPE_NONE;
35604ce935cSLinus Walleij girq->handler = handle_bad_irq;
35704ce935cSLinus Walleij
35804ce935cSLinus Walleij ret = devm_gpiochip_add_data(dev, &pl061->gc, pl061);
35904ce935cSLinus Walleij if (ret)
3608d5b24bdSLinus Walleij return ret;
3612ba3154dSLinus Walleij
3622796325fSLinus Walleij amba_set_drvdata(adev, pl061);
3634d19adddSEnrico Weigelt dev_info(dev, "PL061 GPIO chip registered\n");
364e198a8deSDeepak Sikri
365c103de24SGrant Likely return 0;
366c103de24SGrant Likely }
367c103de24SGrant Likely
368e198a8deSDeepak Sikri #ifdef CONFIG_PM
pl061_suspend(struct device * dev)369e198a8deSDeepak Sikri static int pl061_suspend(struct device *dev)
370e198a8deSDeepak Sikri {
3712796325fSLinus Walleij struct pl061 *pl061 = dev_get_drvdata(dev);
372e198a8deSDeepak Sikri int offset;
373e198a8deSDeepak Sikri
3742796325fSLinus Walleij pl061->csave_regs.gpio_data = 0;
3752796325fSLinus Walleij pl061->csave_regs.gpio_dir = readb(pl061->base + GPIODIR);
3762796325fSLinus Walleij pl061->csave_regs.gpio_is = readb(pl061->base + GPIOIS);
3772796325fSLinus Walleij pl061->csave_regs.gpio_ibe = readb(pl061->base + GPIOIBE);
3782796325fSLinus Walleij pl061->csave_regs.gpio_iev = readb(pl061->base + GPIOIEV);
3792796325fSLinus Walleij pl061->csave_regs.gpio_ie = readb(pl061->base + GPIOIE);
380e198a8deSDeepak Sikri
381e198a8deSDeepak Sikri for (offset = 0; offset < PL061_GPIO_NR; offset++) {
3822796325fSLinus Walleij if (pl061->csave_regs.gpio_dir & (BIT(offset)))
3832796325fSLinus Walleij pl061->csave_regs.gpio_data |=
3842796325fSLinus Walleij pl061_get_value(&pl061->gc, offset) << offset;
385e198a8deSDeepak Sikri }
386e198a8deSDeepak Sikri
387e198a8deSDeepak Sikri return 0;
388e198a8deSDeepak Sikri }
389e198a8deSDeepak Sikri
pl061_resume(struct device * dev)390e198a8deSDeepak Sikri static int pl061_resume(struct device *dev)
391e198a8deSDeepak Sikri {
3922796325fSLinus Walleij struct pl061 *pl061 = dev_get_drvdata(dev);
393e198a8deSDeepak Sikri int offset;
394e198a8deSDeepak Sikri
395e198a8deSDeepak Sikri for (offset = 0; offset < PL061_GPIO_NR; offset++) {
3962796325fSLinus Walleij if (pl061->csave_regs.gpio_dir & (BIT(offset)))
3972796325fSLinus Walleij pl061_direction_output(&pl061->gc, offset,
3982796325fSLinus Walleij pl061->csave_regs.gpio_data &
399bea41504SJavier Martinez Canillas (BIT(offset)));
400e198a8deSDeepak Sikri else
4012796325fSLinus Walleij pl061_direction_input(&pl061->gc, offset);
402e198a8deSDeepak Sikri }
403e198a8deSDeepak Sikri
4042796325fSLinus Walleij writeb(pl061->csave_regs.gpio_is, pl061->base + GPIOIS);
4052796325fSLinus Walleij writeb(pl061->csave_regs.gpio_ibe, pl061->base + GPIOIBE);
4062796325fSLinus Walleij writeb(pl061->csave_regs.gpio_iev, pl061->base + GPIOIEV);
4072796325fSLinus Walleij writeb(pl061->csave_regs.gpio_ie, pl061->base + GPIOIE);
408e198a8deSDeepak Sikri
409e198a8deSDeepak Sikri return 0;
410e198a8deSDeepak Sikri }
411e198a8deSDeepak Sikri
4126e33acedSViresh Kumar static const struct dev_pm_ops pl061_dev_pm_ops = {
4136e33acedSViresh Kumar .suspend = pl061_suspend,
4146e33acedSViresh Kumar .resume = pl061_resume,
4156e33acedSViresh Kumar .freeze = pl061_suspend,
4166e33acedSViresh Kumar .restore = pl061_resume,
4176e33acedSViresh Kumar };
418e198a8deSDeepak Sikri #endif
419e198a8deSDeepak Sikri
42072c7c78eSArvind Yadav static const struct amba_id pl061_ids[] = {
421c103de24SGrant Likely {
422c103de24SGrant Likely .id = 0x00041061,
423c103de24SGrant Likely .mask = 0x000fffff,
424c103de24SGrant Likely },
425c103de24SGrant Likely { 0, 0 },
426c103de24SGrant Likely };
42761684440SRob Herring MODULE_DEVICE_TABLE(amba, pl061_ids);
428c103de24SGrant Likely
429c103de24SGrant Likely static struct amba_driver pl061_gpio_driver = {
430c103de24SGrant Likely .drv = {
431c103de24SGrant Likely .name = "pl061_gpio",
432e198a8deSDeepak Sikri #ifdef CONFIG_PM
433e198a8deSDeepak Sikri .pm = &pl061_dev_pm_ops,
434e198a8deSDeepak Sikri #endif
435c103de24SGrant Likely },
436c103de24SGrant Likely .id_table = pl061_ids,
437c103de24SGrant Likely .probe = pl061_probe,
438c103de24SGrant Likely };
43961684440SRob Herring module_amba_driver(pl061_gpio_driver);
440c103de24SGrant Likely
44161684440SRob Herring MODULE_LICENSE("GPL v2");
442