1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2008, 2009 Provigent Ltd. |
4 | * |
5 | * Author: Baruch Siach <baruch@tkos.co.il> |
6 | * |
7 | * Driver for the ARM PrimeCell(tm) General Purpose Input/Output (PL061) |
8 | * |
9 | * Data sheet: ARM DDI 0190B, September 2000 |
10 | */ |
11 | #include <linux/amba/bus.h> |
12 | #include <linux/bitops.h> |
13 | #include <linux/device.h> |
14 | #include <linux/errno.h> |
15 | #include <linux/gpio/driver.h> |
16 | #include <linux/init.h> |
17 | #include <linux/interrupt.h> |
18 | #include <linux/io.h> |
19 | #include <linux/ioport.h> |
20 | #include <linux/irq.h> |
21 | #include <linux/irqchip/chained_irq.h> |
22 | #include <linux/module.h> |
23 | #include <linux/pinctrl/consumer.h> |
24 | #include <linux/pm.h> |
25 | #include <linux/seq_file.h> |
26 | #include <linux/slab.h> |
27 | #include <linux/spinlock.h> |
28 | |
29 | #define GPIODIR 0x400 |
30 | #define GPIOIS 0x404 |
31 | #define GPIOIBE 0x408 |
32 | #define GPIOIEV 0x40C |
33 | #define GPIOIE 0x410 |
34 | #define GPIORIS 0x414 |
35 | #define GPIOMIS 0x418 |
36 | #define GPIOIC 0x41C |
37 | |
38 | #define PL061_GPIO_NR 8 |
39 | |
40 | #ifdef CONFIG_PM |
41 | struct pl061_context_save_regs { |
42 | u8 gpio_data; |
43 | u8 gpio_dir; |
44 | u8 gpio_is; |
45 | u8 gpio_ibe; |
46 | u8 gpio_iev; |
47 | u8 gpio_ie; |
48 | }; |
49 | #endif |
50 | |
51 | struct pl061 { |
52 | raw_spinlock_t lock; |
53 | |
54 | void __iomem *base; |
55 | struct gpio_chip gc; |
56 | int parent_irq; |
57 | |
58 | #ifdef CONFIG_PM |
59 | struct pl061_context_save_regs csave_regs; |
60 | #endif |
61 | }; |
62 | |
63 | static int pl061_get_direction(struct gpio_chip *gc, unsigned offset) |
64 | { |
65 | struct pl061 *pl061 = gpiochip_get_data(gc); |
66 | |
67 | if (readb(addr: pl061->base + GPIODIR) & BIT(offset)) |
68 | return GPIO_LINE_DIRECTION_OUT; |
69 | |
70 | return GPIO_LINE_DIRECTION_IN; |
71 | } |
72 | |
73 | static int pl061_direction_input(struct gpio_chip *gc, unsigned offset) |
74 | { |
75 | struct pl061 *pl061 = gpiochip_get_data(gc); |
76 | unsigned long flags; |
77 | unsigned char gpiodir; |
78 | |
79 | raw_spin_lock_irqsave(&pl061->lock, flags); |
80 | gpiodir = readb(addr: pl061->base + GPIODIR); |
81 | gpiodir &= ~(BIT(offset)); |
82 | writeb(val: gpiodir, addr: pl061->base + GPIODIR); |
83 | raw_spin_unlock_irqrestore(&pl061->lock, flags); |
84 | |
85 | return 0; |
86 | } |
87 | |
88 | static int pl061_direction_output(struct gpio_chip *gc, unsigned offset, |
89 | int value) |
90 | { |
91 | struct pl061 *pl061 = gpiochip_get_data(gc); |
92 | unsigned long flags; |
93 | unsigned char gpiodir; |
94 | |
95 | raw_spin_lock_irqsave(&pl061->lock, flags); |
96 | writeb(val: !!value << offset, addr: pl061->base + (BIT(offset + 2))); |
97 | gpiodir = readb(addr: pl061->base + GPIODIR); |
98 | gpiodir |= BIT(offset); |
99 | writeb(val: gpiodir, addr: pl061->base + GPIODIR); |
100 | |
101 | /* |
102 | * gpio value is set again, because pl061 doesn't allow to set value of |
103 | * a gpio pin before configuring it in OUT mode. |
104 | */ |
105 | writeb(val: !!value << offset, addr: pl061->base + (BIT(offset + 2))); |
106 | raw_spin_unlock_irqrestore(&pl061->lock, flags); |
107 | |
108 | return 0; |
109 | } |
110 | |
111 | static int pl061_get_value(struct gpio_chip *gc, unsigned offset) |
112 | { |
113 | struct pl061 *pl061 = gpiochip_get_data(gc); |
114 | |
115 | return !!readb(addr: pl061->base + (BIT(offset + 2))); |
116 | } |
117 | |
118 | static void pl061_set_value(struct gpio_chip *gc, unsigned offset, int value) |
119 | { |
120 | struct pl061 *pl061 = gpiochip_get_data(gc); |
121 | |
122 | writeb(val: !!value << offset, addr: pl061->base + (BIT(offset + 2))); |
123 | } |
124 | |
125 | static int pl061_irq_type(struct irq_data *d, unsigned trigger) |
126 | { |
127 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
128 | struct pl061 *pl061 = gpiochip_get_data(gc); |
129 | int offset = irqd_to_hwirq(d); |
130 | unsigned long flags; |
131 | u8 gpiois, gpioibe, gpioiev; |
132 | u8 bit = BIT(offset); |
133 | |
134 | if (offset < 0 || offset >= PL061_GPIO_NR) |
135 | return -EINVAL; |
136 | |
137 | if ((trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) && |
138 | (trigger & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))) |
139 | { |
140 | dev_err(gc->parent, |
141 | "trying to configure line %d for both level and edge " |
142 | "detection, choose one!\n" , |
143 | offset); |
144 | return -EINVAL; |
145 | } |
146 | |
147 | |
148 | raw_spin_lock_irqsave(&pl061->lock, flags); |
149 | |
150 | gpioiev = readb(addr: pl061->base + GPIOIEV); |
151 | gpiois = readb(addr: pl061->base + GPIOIS); |
152 | gpioibe = readb(addr: pl061->base + GPIOIBE); |
153 | |
154 | if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { |
155 | bool polarity = trigger & IRQ_TYPE_LEVEL_HIGH; |
156 | |
157 | /* Disable edge detection */ |
158 | gpioibe &= ~bit; |
159 | /* Enable level detection */ |
160 | gpiois |= bit; |
161 | /* Select polarity */ |
162 | if (polarity) |
163 | gpioiev |= bit; |
164 | else |
165 | gpioiev &= ~bit; |
166 | irq_set_handler_locked(data: d, handler: handle_level_irq); |
167 | dev_dbg(gc->parent, "line %d: IRQ on %s level\n" , |
168 | offset, |
169 | polarity ? "HIGH" : "LOW" ); |
170 | } else if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) { |
171 | /* Disable level detection */ |
172 | gpiois &= ~bit; |
173 | /* Select both edges, setting this makes GPIOEV be ignored */ |
174 | gpioibe |= bit; |
175 | irq_set_handler_locked(data: d, handler: handle_edge_irq); |
176 | dev_dbg(gc->parent, "line %d: IRQ on both edges\n" , offset); |
177 | } else if ((trigger & IRQ_TYPE_EDGE_RISING) || |
178 | (trigger & IRQ_TYPE_EDGE_FALLING)) { |
179 | bool rising = trigger & IRQ_TYPE_EDGE_RISING; |
180 | |
181 | /* Disable level detection */ |
182 | gpiois &= ~bit; |
183 | /* Clear detection on both edges */ |
184 | gpioibe &= ~bit; |
185 | /* Select edge */ |
186 | if (rising) |
187 | gpioiev |= bit; |
188 | else |
189 | gpioiev &= ~bit; |
190 | irq_set_handler_locked(data: d, handler: handle_edge_irq); |
191 | dev_dbg(gc->parent, "line %d: IRQ on %s edge\n" , |
192 | offset, |
193 | rising ? "RISING" : "FALLING" ); |
194 | } else { |
195 | /* No trigger: disable everything */ |
196 | gpiois &= ~bit; |
197 | gpioibe &= ~bit; |
198 | gpioiev &= ~bit; |
199 | irq_set_handler_locked(data: d, handler: handle_bad_irq); |
200 | dev_warn(gc->parent, "no trigger selected for line %d\n" , |
201 | offset); |
202 | } |
203 | |
204 | writeb(val: gpiois, addr: pl061->base + GPIOIS); |
205 | writeb(val: gpioibe, addr: pl061->base + GPIOIBE); |
206 | writeb(val: gpioiev, addr: pl061->base + GPIOIEV); |
207 | |
208 | raw_spin_unlock_irqrestore(&pl061->lock, flags); |
209 | |
210 | return 0; |
211 | } |
212 | |
213 | static void pl061_irq_handler(struct irq_desc *desc) |
214 | { |
215 | unsigned long pending; |
216 | int offset; |
217 | struct gpio_chip *gc = irq_desc_get_handler_data(desc); |
218 | struct pl061 *pl061 = gpiochip_get_data(gc); |
219 | struct irq_chip *irqchip = irq_desc_get_chip(desc); |
220 | |
221 | chained_irq_enter(chip: irqchip, desc); |
222 | |
223 | pending = readb(addr: pl061->base + GPIOMIS); |
224 | if (pending) { |
225 | for_each_set_bit(offset, &pending, PL061_GPIO_NR) |
226 | generic_handle_domain_irq(domain: gc->irq.domain, |
227 | hwirq: offset); |
228 | } |
229 | |
230 | chained_irq_exit(chip: irqchip, desc); |
231 | } |
232 | |
233 | static void pl061_irq_mask(struct irq_data *d) |
234 | { |
235 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
236 | struct pl061 *pl061 = gpiochip_get_data(gc); |
237 | u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); |
238 | u8 gpioie; |
239 | |
240 | raw_spin_lock(&pl061->lock); |
241 | gpioie = readb(addr: pl061->base + GPIOIE) & ~mask; |
242 | writeb(val: gpioie, addr: pl061->base + GPIOIE); |
243 | raw_spin_unlock(&pl061->lock); |
244 | |
245 | gpiochip_disable_irq(gc, offset: d->hwirq); |
246 | } |
247 | |
248 | static void pl061_irq_unmask(struct irq_data *d) |
249 | { |
250 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
251 | struct pl061 *pl061 = gpiochip_get_data(gc); |
252 | u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); |
253 | u8 gpioie; |
254 | |
255 | gpiochip_enable_irq(gc, offset: d->hwirq); |
256 | |
257 | raw_spin_lock(&pl061->lock); |
258 | gpioie = readb(addr: pl061->base + GPIOIE) | mask; |
259 | writeb(val: gpioie, addr: pl061->base + GPIOIE); |
260 | raw_spin_unlock(&pl061->lock); |
261 | } |
262 | |
263 | /** |
264 | * pl061_irq_ack() - ACK an edge IRQ |
265 | * @d: IRQ data for this IRQ |
266 | * |
267 | * This gets called from the edge IRQ handler to ACK the edge IRQ |
268 | * in the GPIOIC (interrupt-clear) register. For level IRQs this is |
269 | * not needed: these go away when the level signal goes away. |
270 | */ |
271 | static void pl061_irq_ack(struct irq_data *d) |
272 | { |
273 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
274 | struct pl061 *pl061 = gpiochip_get_data(gc); |
275 | u8 mask = BIT(irqd_to_hwirq(d) % PL061_GPIO_NR); |
276 | |
277 | raw_spin_lock(&pl061->lock); |
278 | writeb(val: mask, addr: pl061->base + GPIOIC); |
279 | raw_spin_unlock(&pl061->lock); |
280 | } |
281 | |
282 | static int pl061_irq_set_wake(struct irq_data *d, unsigned int state) |
283 | { |
284 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); |
285 | struct pl061 *pl061 = gpiochip_get_data(gc); |
286 | |
287 | return irq_set_irq_wake(irq: pl061->parent_irq, on: state); |
288 | } |
289 | |
290 | static void pl061_irq_print_chip(struct irq_data *data, struct seq_file *p) |
291 | { |
292 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d: data); |
293 | |
294 | seq_printf(m: p, fmt: dev_name(dev: gc->parent)); |
295 | } |
296 | |
297 | static const struct irq_chip pl061_irq_chip = { |
298 | .irq_ack = pl061_irq_ack, |
299 | .irq_mask = pl061_irq_mask, |
300 | .irq_unmask = pl061_irq_unmask, |
301 | .irq_set_type = pl061_irq_type, |
302 | .irq_set_wake = pl061_irq_set_wake, |
303 | .irq_print_chip = pl061_irq_print_chip, |
304 | .flags = IRQCHIP_IMMUTABLE, |
305 | GPIOCHIP_IRQ_RESOURCE_HELPERS, |
306 | }; |
307 | |
308 | static int pl061_probe(struct amba_device *adev, const struct amba_id *id) |
309 | { |
310 | struct device *dev = &adev->dev; |
311 | struct pl061 *pl061; |
312 | struct gpio_irq_chip *girq; |
313 | int ret, irq; |
314 | |
315 | pl061 = devm_kzalloc(dev, size: sizeof(*pl061), GFP_KERNEL); |
316 | if (pl061 == NULL) |
317 | return -ENOMEM; |
318 | |
319 | pl061->base = devm_ioremap_resource(dev, res: &adev->res); |
320 | if (IS_ERR(ptr: pl061->base)) |
321 | return PTR_ERR(ptr: pl061->base); |
322 | |
323 | raw_spin_lock_init(&pl061->lock); |
324 | pl061->gc.request = gpiochip_generic_request; |
325 | pl061->gc.free = gpiochip_generic_free; |
326 | pl061->gc.base = -1; |
327 | pl061->gc.get_direction = pl061_get_direction; |
328 | pl061->gc.direction_input = pl061_direction_input; |
329 | pl061->gc.direction_output = pl061_direction_output; |
330 | pl061->gc.get = pl061_get_value; |
331 | pl061->gc.set = pl061_set_value; |
332 | pl061->gc.ngpio = PL061_GPIO_NR; |
333 | pl061->gc.label = dev_name(dev); |
334 | pl061->gc.parent = dev; |
335 | pl061->gc.owner = THIS_MODULE; |
336 | |
337 | /* |
338 | * irq_chip support |
339 | */ |
340 | writeb(val: 0, addr: pl061->base + GPIOIE); /* disable irqs */ |
341 | irq = adev->irq[0]; |
342 | if (!irq) |
343 | dev_warn(&adev->dev, "IRQ support disabled\n" ); |
344 | pl061->parent_irq = irq; |
345 | |
346 | girq = &pl061->gc.irq; |
347 | gpio_irq_chip_set_chip(girq, chip: &pl061_irq_chip); |
348 | girq->parent_handler = pl061_irq_handler; |
349 | girq->num_parents = 1; |
350 | girq->parents = devm_kcalloc(dev, n: 1, size: sizeof(*girq->parents), |
351 | GFP_KERNEL); |
352 | if (!girq->parents) |
353 | return -ENOMEM; |
354 | girq->parents[0] = irq; |
355 | girq->default_type = IRQ_TYPE_NONE; |
356 | girq->handler = handle_bad_irq; |
357 | |
358 | ret = devm_gpiochip_add_data(dev, &pl061->gc, pl061); |
359 | if (ret) |
360 | return ret; |
361 | |
362 | amba_set_drvdata(adev, pl061); |
363 | dev_info(dev, "PL061 GPIO chip registered\n" ); |
364 | |
365 | return 0; |
366 | } |
367 | |
368 | #ifdef CONFIG_PM |
369 | static int pl061_suspend(struct device *dev) |
370 | { |
371 | struct pl061 *pl061 = dev_get_drvdata(dev); |
372 | int offset; |
373 | |
374 | pl061->csave_regs.gpio_data = 0; |
375 | pl061->csave_regs.gpio_dir = readb(addr: pl061->base + GPIODIR); |
376 | pl061->csave_regs.gpio_is = readb(addr: pl061->base + GPIOIS); |
377 | pl061->csave_regs.gpio_ibe = readb(addr: pl061->base + GPIOIBE); |
378 | pl061->csave_regs.gpio_iev = readb(addr: pl061->base + GPIOIEV); |
379 | pl061->csave_regs.gpio_ie = readb(addr: pl061->base + GPIOIE); |
380 | |
381 | for (offset = 0; offset < PL061_GPIO_NR; offset++) { |
382 | if (pl061->csave_regs.gpio_dir & (BIT(offset))) |
383 | pl061->csave_regs.gpio_data |= |
384 | pl061_get_value(gc: &pl061->gc, offset) << offset; |
385 | } |
386 | |
387 | return 0; |
388 | } |
389 | |
390 | static int pl061_resume(struct device *dev) |
391 | { |
392 | struct pl061 *pl061 = dev_get_drvdata(dev); |
393 | int offset; |
394 | |
395 | for (offset = 0; offset < PL061_GPIO_NR; offset++) { |
396 | if (pl061->csave_regs.gpio_dir & (BIT(offset))) |
397 | pl061_direction_output(gc: &pl061->gc, offset, |
398 | value: pl061->csave_regs.gpio_data & |
399 | (BIT(offset))); |
400 | else |
401 | pl061_direction_input(gc: &pl061->gc, offset); |
402 | } |
403 | |
404 | writeb(val: pl061->csave_regs.gpio_is, addr: pl061->base + GPIOIS); |
405 | writeb(val: pl061->csave_regs.gpio_ibe, addr: pl061->base + GPIOIBE); |
406 | writeb(val: pl061->csave_regs.gpio_iev, addr: pl061->base + GPIOIEV); |
407 | writeb(val: pl061->csave_regs.gpio_ie, addr: pl061->base + GPIOIE); |
408 | |
409 | return 0; |
410 | } |
411 | |
412 | static const struct dev_pm_ops pl061_dev_pm_ops = { |
413 | .suspend = pl061_suspend, |
414 | .resume = pl061_resume, |
415 | .freeze = pl061_suspend, |
416 | .restore = pl061_resume, |
417 | }; |
418 | #endif |
419 | |
420 | static const struct amba_id pl061_ids[] = { |
421 | { |
422 | .id = 0x00041061, |
423 | .mask = 0x000fffff, |
424 | }, |
425 | { 0, 0 }, |
426 | }; |
427 | MODULE_DEVICE_TABLE(amba, pl061_ids); |
428 | |
429 | static struct amba_driver pl061_gpio_driver = { |
430 | .drv = { |
431 | .name = "pl061_gpio" , |
432 | #ifdef CONFIG_PM |
433 | .pm = &pl061_dev_pm_ops, |
434 | #endif |
435 | }, |
436 | .id_table = pl061_ids, |
437 | .probe = pl061_probe, |
438 | }; |
439 | module_amba_driver(pl061_gpio_driver); |
440 | |
441 | MODULE_LICENSE("GPL v2" ); |
442 | |