blob: 9a8c603625a3a99f0103447178f598742c8470f2 [file] [log] [blame]
Gregory Fong3b0213d2015-05-28 19:14:05 -07001/*
Doug Berger0752df62017-10-24 12:54:46 -07002 * Copyright (C) 2015-2017 Broadcom
Gregory Fong3b0213d2015-05-28 19:14:05 -07003 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation version 2.
7 *
8 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
9 * kind, whether express or implied; without even the implied warranty
10 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/bitops.h>
15#include <linux/gpio/driver.h>
16#include <linux/of_device.h>
17#include <linux/of_irq.h>
18#include <linux/module.h>
Gregory Fong19a7b692015-07-31 18:17:43 -070019#include <linux/irqdomain.h>
20#include <linux/irqchip/chained_irq.h>
21#include <linux/interrupt.h>
Gregory Fong3afa1292015-07-31 18:17:44 -070022#include <linux/reboot.h>
Linus Walleijd7442362017-10-20 15:45:34 +020023#include <linux/bitops.h>
Gregory Fong3b0213d2015-05-28 19:14:05 -070024
25#define GIO_BANK_SIZE 0x20
26#define GIO_ODEN(bank) (((bank) * GIO_BANK_SIZE) + 0x00)
27#define GIO_DATA(bank) (((bank) * GIO_BANK_SIZE) + 0x04)
28#define GIO_IODIR(bank) (((bank) * GIO_BANK_SIZE) + 0x08)
29#define GIO_EC(bank) (((bank) * GIO_BANK_SIZE) + 0x0c)
30#define GIO_EI(bank) (((bank) * GIO_BANK_SIZE) + 0x10)
31#define GIO_MASK(bank) (((bank) * GIO_BANK_SIZE) + 0x14)
32#define GIO_LEVEL(bank) (((bank) * GIO_BANK_SIZE) + 0x18)
33#define GIO_STAT(bank) (((bank) * GIO_BANK_SIZE) + 0x1c)
34
35struct brcmstb_gpio_bank {
36 struct list_head node;
37 int id;
Linus Walleij0f4630f2015-12-04 14:02:58 +010038 struct gpio_chip gc;
Gregory Fong3b0213d2015-05-28 19:14:05 -070039 struct brcmstb_gpio_priv *parent_priv;
40 u32 width;
41};
42
43struct brcmstb_gpio_priv {
44 struct list_head bank_list;
45 void __iomem *reg_base;
Gregory Fong3b0213d2015-05-28 19:14:05 -070046 struct platform_device *pdev;
Doug Berger0ba31dc2017-10-24 12:54:50 -070047 struct irq_domain *irq_domain;
48 struct irq_chip irq_chip;
Gregory Fong19a7b692015-07-31 18:17:43 -070049 int parent_irq;
Gregory Fong3b0213d2015-05-28 19:14:05 -070050 int gpio_base;
Doug Berger0ba31dc2017-10-24 12:54:50 -070051 int num_gpios;
Gregory Fong19a7b692015-07-31 18:17:43 -070052 int parent_wake_irq;
Gregory Fong3afa1292015-07-31 18:17:44 -070053 struct notifier_block reboot_notifier;
Gregory Fong3b0213d2015-05-28 19:14:05 -070054};
55
Doug Berger0ba31dc2017-10-24 12:54:50 -070056#define MAX_GPIO_PER_BANK 32
Gregory Fong3b0213d2015-05-28 19:14:05 -070057#define GPIO_BANK(gpio) ((gpio) >> 5)
58/* assumes MAX_GPIO_PER_BANK is a multiple of 2 */
59#define GPIO_BIT(gpio) ((gpio) & (MAX_GPIO_PER_BANK - 1))
60
Gregory Fong3b0213d2015-05-28 19:14:05 -070061static inline struct brcmstb_gpio_priv *
62brcmstb_gpio_gc_to_priv(struct gpio_chip *gc)
63{
Linus Walleij0f4630f2015-12-04 14:02:58 +010064 struct brcmstb_gpio_bank *bank = gpiochip_get_data(gc);
Gregory Fong3b0213d2015-05-28 19:14:05 -070065 return bank->parent_priv;
66}
67
Doug Berger142c1682017-10-24 12:54:47 -070068static unsigned long
69brcmstb_gpio_get_active_irqs(struct brcmstb_gpio_bank *bank)
70{
71 void __iomem *reg_base = bank->parent_priv->reg_base;
72 unsigned long status;
73 unsigned long flags;
74
75 spin_lock_irqsave(&bank->gc.bgpio_lock, flags);
76 status = bank->gc.read_reg(reg_base + GIO_STAT(bank->id)) &
77 bank->gc.read_reg(reg_base + GIO_MASK(bank->id));
78 spin_unlock_irqrestore(&bank->gc.bgpio_lock, flags);
79
80 return status;
81}
82
Doug Berger0ba31dc2017-10-24 12:54:50 -070083static int brcmstb_gpio_hwirq_to_offset(irq_hw_number_t hwirq,
84 struct brcmstb_gpio_bank *bank)
85{
86 return hwirq - (bank->gc.base - bank->parent_priv->gpio_base);
87}
88
Gregory Fong19a7b692015-07-31 18:17:43 -070089static void brcmstb_gpio_set_imask(struct brcmstb_gpio_bank *bank,
Doug Berger0ba31dc2017-10-24 12:54:50 -070090 unsigned int hwirq, bool enable)
Gregory Fong19a7b692015-07-31 18:17:43 -070091{
Linus Walleij0f4630f2015-12-04 14:02:58 +010092 struct gpio_chip *gc = &bank->gc;
Gregory Fong19a7b692015-07-31 18:17:43 -070093 struct brcmstb_gpio_priv *priv = bank->parent_priv;
Doug Berger0ba31dc2017-10-24 12:54:50 -070094 u32 mask = BIT(brcmstb_gpio_hwirq_to_offset(hwirq, bank));
Gregory Fong19a7b692015-07-31 18:17:43 -070095 u32 imask;
96 unsigned long flags;
97
Linus Walleij0f4630f2015-12-04 14:02:58 +010098 spin_lock_irqsave(&gc->bgpio_lock, flags);
99 imask = gc->read_reg(priv->reg_base + GIO_MASK(bank->id));
Gregory Fong19a7b692015-07-31 18:17:43 -0700100 if (enable)
Doug Berger0ba31dc2017-10-24 12:54:50 -0700101 imask |= mask;
Gregory Fong19a7b692015-07-31 18:17:43 -0700102 else
Doug Berger0ba31dc2017-10-24 12:54:50 -0700103 imask &= ~mask;
Linus Walleij0f4630f2015-12-04 14:02:58 +0100104 gc->write_reg(priv->reg_base + GIO_MASK(bank->id), imask);
105 spin_unlock_irqrestore(&gc->bgpio_lock, flags);
Gregory Fong19a7b692015-07-31 18:17:43 -0700106}
107
Doug Berger0ba31dc2017-10-24 12:54:50 -0700108static int brcmstb_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
109{
110 struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc);
111 /* gc_offset is relative to this gpio_chip; want real offset */
112 int hwirq = offset + (gc->base - priv->gpio_base);
113
114 if (hwirq >= priv->num_gpios)
115 return -ENXIO;
116 return irq_create_mapping(priv->irq_domain, hwirq);
117}
118
Gregory Fong19a7b692015-07-31 18:17:43 -0700119/* -------------------- IRQ chip functions -------------------- */
120
121static void brcmstb_gpio_irq_mask(struct irq_data *d)
122{
123 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
Linus Walleij0f4630f2015-12-04 14:02:58 +0100124 struct brcmstb_gpio_bank *bank = gpiochip_get_data(gc);
Gregory Fong19a7b692015-07-31 18:17:43 -0700125
126 brcmstb_gpio_set_imask(bank, d->hwirq, false);
127}
128
129static void brcmstb_gpio_irq_unmask(struct irq_data *d)
130{
131 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
Linus Walleij0f4630f2015-12-04 14:02:58 +0100132 struct brcmstb_gpio_bank *bank = gpiochip_get_data(gc);
Gregory Fong19a7b692015-07-31 18:17:43 -0700133
134 brcmstb_gpio_set_imask(bank, d->hwirq, true);
135}
136
Doug Berger2c218b92017-10-24 12:54:48 -0700137static void brcmstb_gpio_irq_ack(struct irq_data *d)
138{
139 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
140 struct brcmstb_gpio_bank *bank = gpiochip_get_data(gc);
141 struct brcmstb_gpio_priv *priv = bank->parent_priv;
Doug Berger0ba31dc2017-10-24 12:54:50 -0700142 u32 mask = BIT(brcmstb_gpio_hwirq_to_offset(d->hwirq, bank));
Doug Berger2c218b92017-10-24 12:54:48 -0700143
144 gc->write_reg(priv->reg_base + GIO_STAT(bank->id), mask);
145}
146
Gregory Fong19a7b692015-07-31 18:17:43 -0700147static int brcmstb_gpio_irq_set_type(struct irq_data *d, unsigned int type)
148{
149 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
Linus Walleij0f4630f2015-12-04 14:02:58 +0100150 struct brcmstb_gpio_bank *bank = gpiochip_get_data(gc);
Gregory Fong19a7b692015-07-31 18:17:43 -0700151 struct brcmstb_gpio_priv *priv = bank->parent_priv;
Doug Berger0ba31dc2017-10-24 12:54:50 -0700152 u32 mask = BIT(brcmstb_gpio_hwirq_to_offset(d->hwirq, bank));
Gregory Fong19a7b692015-07-31 18:17:43 -0700153 u32 edge_insensitive, iedge_insensitive;
154 u32 edge_config, iedge_config;
155 u32 level, ilevel;
156 unsigned long flags;
157
158 switch (type) {
159 case IRQ_TYPE_LEVEL_LOW:
Doug Berger633007a2017-10-24 12:54:49 -0700160 level = mask;
Gregory Fong19a7b692015-07-31 18:17:43 -0700161 edge_config = 0;
162 edge_insensitive = 0;
163 break;
164 case IRQ_TYPE_LEVEL_HIGH:
165 level = mask;
Doug Berger633007a2017-10-24 12:54:49 -0700166 edge_config = mask;
Gregory Fong19a7b692015-07-31 18:17:43 -0700167 edge_insensitive = 0;
168 break;
169 case IRQ_TYPE_EDGE_FALLING:
170 level = 0;
171 edge_config = 0;
172 edge_insensitive = 0;
173 break;
174 case IRQ_TYPE_EDGE_RISING:
175 level = 0;
176 edge_config = mask;
177 edge_insensitive = 0;
178 break;
179 case IRQ_TYPE_EDGE_BOTH:
180 level = 0;
181 edge_config = 0; /* don't care, but want known value */
182 edge_insensitive = mask;
183 break;
184 default:
185 return -EINVAL;
186 }
187
Linus Walleij0f4630f2015-12-04 14:02:58 +0100188 spin_lock_irqsave(&bank->gc.bgpio_lock, flags);
Gregory Fong19a7b692015-07-31 18:17:43 -0700189
Linus Walleij0f4630f2015-12-04 14:02:58 +0100190 iedge_config = bank->gc.read_reg(priv->reg_base +
Gregory Fong19a7b692015-07-31 18:17:43 -0700191 GIO_EC(bank->id)) & ~mask;
Linus Walleij0f4630f2015-12-04 14:02:58 +0100192 iedge_insensitive = bank->gc.read_reg(priv->reg_base +
Gregory Fong19a7b692015-07-31 18:17:43 -0700193 GIO_EI(bank->id)) & ~mask;
Linus Walleij0f4630f2015-12-04 14:02:58 +0100194 ilevel = bank->gc.read_reg(priv->reg_base +
Gregory Fong19a7b692015-07-31 18:17:43 -0700195 GIO_LEVEL(bank->id)) & ~mask;
196
Linus Walleij0f4630f2015-12-04 14:02:58 +0100197 bank->gc.write_reg(priv->reg_base + GIO_EC(bank->id),
Gregory Fong19a7b692015-07-31 18:17:43 -0700198 iedge_config | edge_config);
Linus Walleij0f4630f2015-12-04 14:02:58 +0100199 bank->gc.write_reg(priv->reg_base + GIO_EI(bank->id),
Gregory Fong19a7b692015-07-31 18:17:43 -0700200 iedge_insensitive | edge_insensitive);
Linus Walleij0f4630f2015-12-04 14:02:58 +0100201 bank->gc.write_reg(priv->reg_base + GIO_LEVEL(bank->id),
Gregory Fong19a7b692015-07-31 18:17:43 -0700202 ilevel | level);
203
Linus Walleij0f4630f2015-12-04 14:02:58 +0100204 spin_unlock_irqrestore(&bank->gc.bgpio_lock, flags);
Gregory Fong19a7b692015-07-31 18:17:43 -0700205 return 0;
206}
207
Gregory Fong3afa1292015-07-31 18:17:44 -0700208static int brcmstb_gpio_priv_set_wake(struct brcmstb_gpio_priv *priv,
209 unsigned int enable)
Gregory Fong19a7b692015-07-31 18:17:43 -0700210{
Gregory Fong19a7b692015-07-31 18:17:43 -0700211 int ret = 0;
212
213 /*
214 * Only enable wake IRQ once for however many hwirqs can wake
215 * since they all use the same wake IRQ. Mask will be set
216 * up appropriately thanks to IRQCHIP_MASK_ON_SUSPEND flag.
217 */
218 if (enable)
219 ret = enable_irq_wake(priv->parent_wake_irq);
220 else
221 ret = disable_irq_wake(priv->parent_wake_irq);
222 if (ret)
223 dev_err(&priv->pdev->dev, "failed to %s wake-up interrupt\n",
224 enable ? "enable" : "disable");
225 return ret;
226}
227
Gregory Fong3afa1292015-07-31 18:17:44 -0700228static int brcmstb_gpio_irq_set_wake(struct irq_data *d, unsigned int enable)
229{
230 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
231 struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc);
232
233 return brcmstb_gpio_priv_set_wake(priv, enable);
234}
235
Gregory Fong19a7b692015-07-31 18:17:43 -0700236static irqreturn_t brcmstb_gpio_wake_irq_handler(int irq, void *data)
237{
238 struct brcmstb_gpio_priv *priv = data;
239
240 if (!priv || irq != priv->parent_wake_irq)
241 return IRQ_NONE;
242 pm_wakeup_event(&priv->pdev->dev, 0);
243 return IRQ_HANDLED;
244}
245
246static void brcmstb_gpio_irq_bank_handler(struct brcmstb_gpio_bank *bank)
247{
248 struct brcmstb_gpio_priv *priv = bank->parent_priv;
Doug Berger0ba31dc2017-10-24 12:54:50 -0700249 struct irq_domain *domain = priv->irq_domain;
250 int hwbase = bank->gc.base - priv->gpio_base;
Gregory Fong19a7b692015-07-31 18:17:43 -0700251 unsigned long status;
Gregory Fong19a7b692015-07-31 18:17:43 -0700252
Doug Berger142c1682017-10-24 12:54:47 -0700253 while ((status = brcmstb_gpio_get_active_irqs(bank))) {
Doug Berger0ba31dc2017-10-24 12:54:50 -0700254 unsigned int irq, offset;
Gregory Fong19a7b692015-07-31 18:17:43 -0700255
Doug Berger0ba31dc2017-10-24 12:54:50 -0700256 for_each_set_bit(offset, &status, 32) {
257 if (offset >= bank->width)
Gregory Fong19a7b692015-07-31 18:17:43 -0700258 dev_warn(&priv->pdev->dev,
259 "IRQ for invalid GPIO (bank=%d, offset=%d)\n",
Doug Berger0ba31dc2017-10-24 12:54:50 -0700260 bank->id, offset);
261 irq = irq_linear_revmap(domain, hwbase + offset);
262 generic_handle_irq(irq);
Gregory Fong19a7b692015-07-31 18:17:43 -0700263 }
264 }
Gregory Fong19a7b692015-07-31 18:17:43 -0700265}
266
267/* Each UPG GIO block has one IRQ for all banks */
Thomas Gleixnerbd0b9ac2015-09-14 10:42:37 +0200268static void brcmstb_gpio_irq_handler(struct irq_desc *desc)
Gregory Fong19a7b692015-07-31 18:17:43 -0700269{
Doug Berger0ba31dc2017-10-24 12:54:50 -0700270 struct brcmstb_gpio_priv *priv = irq_desc_get_handler_data(desc);
Gregory Fong19a7b692015-07-31 18:17:43 -0700271 struct irq_chip *chip = irq_desc_get_chip(desc);
Axel Linb178e7e2016-02-20 09:50:37 +0800272 struct brcmstb_gpio_bank *bank;
Gregory Fong19a7b692015-07-31 18:17:43 -0700273
274 /* Interrupts weren't properly cleared during probe */
275 BUG_ON(!priv || !chip);
276
277 chained_irq_enter(chip, desc);
Axel Linb178e7e2016-02-20 09:50:37 +0800278 list_for_each_entry(bank, &priv->bank_list, node)
Gregory Fong19a7b692015-07-31 18:17:43 -0700279 brcmstb_gpio_irq_bank_handler(bank);
Gregory Fong19a7b692015-07-31 18:17:43 -0700280 chained_irq_exit(chip, desc);
281}
282
Gregory Fong3afa1292015-07-31 18:17:44 -0700283static int brcmstb_gpio_reboot(struct notifier_block *nb,
284 unsigned long action, void *data)
285{
286 struct brcmstb_gpio_priv *priv =
287 container_of(nb, struct brcmstb_gpio_priv, reboot_notifier);
288
289 /* Enable GPIO for S5 cold boot */
290 if (action == SYS_POWER_OFF)
291 brcmstb_gpio_priv_set_wake(priv, 1);
292
293 return NOTIFY_DONE;
294}
295
Doug Berger0ba31dc2017-10-24 12:54:50 -0700296static struct brcmstb_gpio_bank *brcmstb_gpio_hwirq_to_bank(
297 struct brcmstb_gpio_priv *priv, irq_hw_number_t hwirq)
298{
299 struct brcmstb_gpio_bank *bank;
300 int i = 0;
301
302 /* banks are in descending order */
303 list_for_each_entry_reverse(bank, &priv->bank_list, node) {
304 i += bank->gc.ngpio;
305 if (hwirq < i)
306 return bank;
307 }
308 return NULL;
309}
310
311/*
312 * This lock class tells lockdep that GPIO irqs are in a different
313 * category than their parents, so it won't report false recursion.
314 */
315static struct lock_class_key brcmstb_gpio_irq_lock_class;
316
317
318static int brcmstb_gpio_irq_map(struct irq_domain *d, unsigned int irq,
319 irq_hw_number_t hwirq)
320{
321 struct brcmstb_gpio_priv *priv = d->host_data;
322 struct brcmstb_gpio_bank *bank =
323 brcmstb_gpio_hwirq_to_bank(priv, hwirq);
324 struct platform_device *pdev = priv->pdev;
325 int ret;
326
327 if (!bank)
328 return -EINVAL;
329
330 dev_dbg(&pdev->dev, "Mapping irq %d for gpio line %d (bank %d)\n",
331 irq, (int)hwirq, bank->id);
332 ret = irq_set_chip_data(irq, &bank->gc);
333 if (ret < 0)
334 return ret;
335 irq_set_lockdep_class(irq, &brcmstb_gpio_irq_lock_class);
336 irq_set_chip_and_handler(irq, &priv->irq_chip, handle_level_irq);
337 irq_set_noprobe(irq);
338 return 0;
339}
340
341static void brcmstb_gpio_irq_unmap(struct irq_domain *d, unsigned int irq)
342{
343 irq_set_chip_and_handler(irq, NULL, NULL);
344 irq_set_chip_data(irq, NULL);
345}
346
347static const struct irq_domain_ops brcmstb_gpio_irq_domain_ops = {
348 .map = brcmstb_gpio_irq_map,
349 .unmap = brcmstb_gpio_irq_unmap,
350 .xlate = irq_domain_xlate_twocell,
351};
352
Gregory Fong3b0213d2015-05-28 19:14:05 -0700353/* Make sure that the number of banks matches up between properties */
354static int brcmstb_gpio_sanity_check_banks(struct device *dev,
355 struct device_node *np, struct resource *res)
356{
357 int res_num_banks = resource_size(res) / GIO_BANK_SIZE;
358 int num_banks =
359 of_property_count_u32_elems(np, "brcm,gpio-bank-widths");
360
361 if (res_num_banks != num_banks) {
362 dev_err(dev, "Mismatch in banks: res had %d, bank-widths had %d\n",
363 res_num_banks, num_banks);
364 return -EINVAL;
365 } else {
366 return 0;
367 }
368}
369
370static int brcmstb_gpio_remove(struct platform_device *pdev)
371{
372 struct brcmstb_gpio_priv *priv = platform_get_drvdata(pdev);
Gregory Fong3b0213d2015-05-28 19:14:05 -0700373 struct brcmstb_gpio_bank *bank;
Doug Berger0ba31dc2017-10-24 12:54:50 -0700374 int offset, ret = 0, virq;
Gregory Fong3b0213d2015-05-28 19:14:05 -0700375
Gregory Fong22526072015-06-17 18:00:40 -0700376 if (!priv) {
377 dev_err(&pdev->dev, "called %s without drvdata!\n", __func__);
378 return -EFAULT;
379 }
380
Doug Berger0ba31dc2017-10-24 12:54:50 -0700381 if (priv->parent_irq > 0)
382 irq_set_chained_handler_and_data(priv->parent_irq, NULL, NULL);
383
384 /* Remove all IRQ mappings and delete the domain */
385 if (priv->irq_domain) {
386 for (offset = 0; offset < priv->num_gpios; offset++) {
387 virq = irq_find_mapping(priv->irq_domain, offset);
388 irq_dispose_mapping(virq);
389 }
390 irq_domain_remove(priv->irq_domain);
391 }
392
Gregory Fong22526072015-06-17 18:00:40 -0700393 /*
394 * You can lose return values below, but we report all errors, and it's
395 * more important to actually perform all of the steps.
396 */
Axel Linb178e7e2016-02-20 09:50:37 +0800397 list_for_each_entry(bank, &priv->bank_list, node)
Linus Walleij0f4630f2015-12-04 14:02:58 +0100398 gpiochip_remove(&bank->gc);
Axel Linb178e7e2016-02-20 09:50:37 +0800399
Gregory Fong3afa1292015-07-31 18:17:44 -0700400 if (priv->reboot_notifier.notifier_call) {
401 ret = unregister_reboot_notifier(&priv->reboot_notifier);
402 if (ret)
403 dev_err(&pdev->dev,
404 "failed to unregister reboot notifier\n");
405 }
Gregory Fong3b0213d2015-05-28 19:14:05 -0700406 return ret;
407}
408
409static int brcmstb_gpio_of_xlate(struct gpio_chip *gc,
410 const struct of_phandle_args *gpiospec, u32 *flags)
411{
412 struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc);
Linus Walleij0f4630f2015-12-04 14:02:58 +0100413 struct brcmstb_gpio_bank *bank = gpiochip_get_data(gc);
Gregory Fong3b0213d2015-05-28 19:14:05 -0700414 int offset;
415
416 if (gc->of_gpio_n_cells != 2) {
417 WARN_ON(1);
418 return -EINVAL;
419 }
420
421 if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
422 return -EINVAL;
423
424 offset = gpiospec->args[0] - (gc->base - priv->gpio_base);
Gregory Fong19a7b692015-07-31 18:17:43 -0700425 if (offset >= gc->ngpio || offset < 0)
Gregory Fong3b0213d2015-05-28 19:14:05 -0700426 return -EINVAL;
427
428 if (unlikely(offset >= bank->width)) {
429 dev_warn_ratelimited(&priv->pdev->dev,
430 "Received request for invalid GPIO offset %d\n",
431 gpiospec->args[0]);
432 }
433
434 if (flags)
435 *flags = gpiospec->args[1];
436
437 return offset;
438}
439
Doug Berger0ba31dc2017-10-24 12:54:50 -0700440/* priv->parent_irq and priv->num_gpios must be set before calling */
Gregory Fong19a7b692015-07-31 18:17:43 -0700441static int brcmstb_gpio_irq_setup(struct platform_device *pdev,
Doug Berger0ba31dc2017-10-24 12:54:50 -0700442 struct brcmstb_gpio_priv *priv)
Gregory Fong19a7b692015-07-31 18:17:43 -0700443{
Gregory Fong19a7b692015-07-31 18:17:43 -0700444 struct device *dev = &pdev->dev;
445 struct device_node *np = dev->of_node;
Masahiro Yamadaf89c6ea2017-08-10 07:51:27 +0900446 int err;
Gregory Fong19a7b692015-07-31 18:17:43 -0700447
Doug Berger0ba31dc2017-10-24 12:54:50 -0700448 priv->irq_domain =
449 irq_domain_add_linear(np, priv->num_gpios,
450 &brcmstb_gpio_irq_domain_ops,
451 priv);
452 if (!priv->irq_domain) {
453 dev_err(dev, "Couldn't allocate IRQ domain\n");
454 return -ENXIO;
455 }
Gregory Fong19a7b692015-07-31 18:17:43 -0700456
Doug Berger0ba31dc2017-10-24 12:54:50 -0700457 if (of_property_read_bool(np, "wakeup-source")) {
Gregory Fong19a7b692015-07-31 18:17:43 -0700458 priv->parent_wake_irq = platform_get_irq(pdev, 1);
459 if (priv->parent_wake_irq < 0) {
Doug Berger0752df62017-10-24 12:54:46 -0700460 priv->parent_wake_irq = 0;
Gregory Fong19a7b692015-07-31 18:17:43 -0700461 dev_warn(dev,
462 "Couldn't get wake IRQ - GPIOs will not be able to wake from sleep");
463 } else {
Gregory Fong3afa1292015-07-31 18:17:44 -0700464 /*
465 * Set wakeup capability before requesting wakeup
466 * interrupt, so we can process boot-time "wakeups"
467 * (e.g., from S5 cold boot)
468 */
469 device_set_wakeup_capable(dev, true);
470 device_wakeup_enable(dev);
471 err = devm_request_irq(dev, priv->parent_wake_irq,
Doug Berger0752df62017-10-24 12:54:46 -0700472 brcmstb_gpio_wake_irq_handler,
473 IRQF_SHARED,
474 "brcmstb-gpio-wake", priv);
Gregory Fong19a7b692015-07-31 18:17:43 -0700475
476 if (err < 0) {
477 dev_err(dev, "Couldn't request wake IRQ");
Doug Berger0ba31dc2017-10-24 12:54:50 -0700478 goto out_free_domain;
Gregory Fong19a7b692015-07-31 18:17:43 -0700479 }
480
Gregory Fong3afa1292015-07-31 18:17:44 -0700481 priv->reboot_notifier.notifier_call =
482 brcmstb_gpio_reboot;
483 register_reboot_notifier(&priv->reboot_notifier);
Gregory Fong19a7b692015-07-31 18:17:43 -0700484 }
485 }
486
Doug Berger0ba31dc2017-10-24 12:54:50 -0700487 priv->irq_chip.name = dev_name(dev);
488 priv->irq_chip.irq_disable = brcmstb_gpio_irq_mask;
489 priv->irq_chip.irq_mask = brcmstb_gpio_irq_mask;
490 priv->irq_chip.irq_unmask = brcmstb_gpio_irq_unmask;
491 priv->irq_chip.irq_ack = brcmstb_gpio_irq_ack;
492 priv->irq_chip.irq_set_type = brcmstb_gpio_irq_set_type;
Gregory Fong19a7b692015-07-31 18:17:43 -0700493
Doug Berger0ba31dc2017-10-24 12:54:50 -0700494 /* Ensures that all non-wakeup IRQs are disabled at suspend */
495 priv->irq_chip.flags = IRQCHIP_MASK_ON_SUSPEND;
496
497 if (priv->parent_wake_irq)
498 priv->irq_chip.irq_set_wake = brcmstb_gpio_irq_set_wake;
499
500 irq_set_chained_handler_and_data(priv->parent_irq,
501 brcmstb_gpio_irq_handler, priv);
Gregory Fong19a7b692015-07-31 18:17:43 -0700502
503 return 0;
Doug Berger0ba31dc2017-10-24 12:54:50 -0700504
505out_free_domain:
506 irq_domain_remove(priv->irq_domain);
507
508 return err;
Gregory Fong19a7b692015-07-31 18:17:43 -0700509}
510
Gregory Fong3b0213d2015-05-28 19:14:05 -0700511static int brcmstb_gpio_probe(struct platform_device *pdev)
512{
513 struct device *dev = &pdev->dev;
514 struct device_node *np = dev->of_node;
515 void __iomem *reg_base;
516 struct brcmstb_gpio_priv *priv;
517 struct resource *res;
518 struct property *prop;
519 const __be32 *p;
520 u32 bank_width;
Gregory Fong19a7b692015-07-31 18:17:43 -0700521 int num_banks = 0;
Gregory Fong3b0213d2015-05-28 19:14:05 -0700522 int err;
523 static int gpio_base;
Florian Fainellice5a7e82016-01-06 10:55:22 -0800524 unsigned long flags = 0;
Gregory Fong3b0213d2015-05-28 19:14:05 -0700525
526 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
527 if (!priv)
528 return -ENOMEM;
Gregory Fong22526072015-06-17 18:00:40 -0700529 platform_set_drvdata(pdev, priv);
530 INIT_LIST_HEAD(&priv->bank_list);
Gregory Fong3b0213d2015-05-28 19:14:05 -0700531
532 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
533 reg_base = devm_ioremap_resource(dev, res);
534 if (IS_ERR(reg_base))
535 return PTR_ERR(reg_base);
536
537 priv->gpio_base = gpio_base;
538 priv->reg_base = reg_base;
539 priv->pdev = pdev;
540
Gregory Fong19a7b692015-07-31 18:17:43 -0700541 if (of_property_read_bool(np, "interrupt-controller")) {
542 priv->parent_irq = platform_get_irq(pdev, 0);
543 if (priv->parent_irq <= 0) {
544 dev_err(dev, "Couldn't get IRQ");
545 return -ENOENT;
546 }
547 } else {
548 priv->parent_irq = -ENOENT;
549 }
550
Gregory Fong3b0213d2015-05-28 19:14:05 -0700551 if (brcmstb_gpio_sanity_check_banks(dev, np, res))
552 return -EINVAL;
553
Florian Fainellice5a7e82016-01-06 10:55:22 -0800554 /*
555 * MIPS endianness is configured by boot strap, which also reverses all
556 * bus endianness (i.e., big-endian CPU + big endian bus ==> native
557 * endian I/O).
558 *
559 * Other architectures (e.g., ARM) either do not support big endian, or
560 * else leave I/O in little endian mode.
561 */
562#if defined(CONFIG_MIPS) && defined(__BIG_ENDIAN)
563 flags = BGPIOF_BIG_ENDIAN_BYTE_ORDER;
564#endif
565
Gregory Fong3b0213d2015-05-28 19:14:05 -0700566 of_property_for_each_u32(np, "brcm,gpio-bank-widths", prop, p,
567 bank_width) {
568 struct brcmstb_gpio_bank *bank;
Gregory Fong3b0213d2015-05-28 19:14:05 -0700569 struct gpio_chip *gc;
570
571 bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL);
572 if (!bank) {
573 err = -ENOMEM;
574 goto fail;
575 }
576
577 bank->parent_priv = priv;
Gregory Fong19a7b692015-07-31 18:17:43 -0700578 bank->id = num_banks;
Gregory Fong3b0213d2015-05-28 19:14:05 -0700579 if (bank_width <= 0 || bank_width > MAX_GPIO_PER_BANK) {
580 dev_err(dev, "Invalid bank width %d\n", bank_width);
Axel Lin35b3fc882016-04-10 18:15:15 +0800581 err = -EINVAL;
Gregory Fong3b0213d2015-05-28 19:14:05 -0700582 goto fail;
583 } else {
584 bank->width = bank_width;
585 }
586
587 /*
588 * Regs are 4 bytes wide, have data reg, no set/clear regs,
589 * and direction bits have 0 = output and 1 = input
590 */
Linus Walleij0f4630f2015-12-04 14:02:58 +0100591 gc = &bank->gc;
592 err = bgpio_init(gc, dev, 4,
Gregory Fong3b0213d2015-05-28 19:14:05 -0700593 reg_base + GIO_DATA(bank->id),
594 NULL, NULL, NULL,
Florian Fainellice5a7e82016-01-06 10:55:22 -0800595 reg_base + GIO_IODIR(bank->id), flags);
Gregory Fong3b0213d2015-05-28 19:14:05 -0700596 if (err) {
597 dev_err(dev, "bgpio_init() failed\n");
598 goto fail;
599 }
600
Gregory Fong3b0213d2015-05-28 19:14:05 -0700601 gc->of_node = np;
602 gc->owner = THIS_MODULE;
Rob Herring7eb6ce22017-07-18 16:43:03 -0500603 gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", dev->of_node);
Arvind Yadavba3e2172017-09-21 10:44:13 +0530604 if (!gc->label) {
605 err = -ENOMEM;
606 goto fail;
607 }
Gregory Fong3b0213d2015-05-28 19:14:05 -0700608 gc->base = gpio_base;
609 gc->of_gpio_n_cells = 2;
610 gc->of_xlate = brcmstb_gpio_of_xlate;
611 /* not all ngpio lines are valid, will use bank width later */
612 gc->ngpio = MAX_GPIO_PER_BANK;
Doug Berger0ba31dc2017-10-24 12:54:50 -0700613 if (priv->parent_irq > 0)
614 gc->to_irq = brcmstb_gpio_to_irq;
Gregory Fong3b0213d2015-05-28 19:14:05 -0700615
Gregory Fong3afa1292015-07-31 18:17:44 -0700616 /*
617 * Mask all interrupts by default, since wakeup interrupts may
618 * be retained from S5 cold boot
619 */
Linus Walleij0f4630f2015-12-04 14:02:58 +0100620 gc->write_reg(reg_base + GIO_MASK(bank->id), 0);
Gregory Fong3afa1292015-07-31 18:17:44 -0700621
Linus Walleij0f4630f2015-12-04 14:02:58 +0100622 err = gpiochip_add_data(gc, bank);
Gregory Fong3b0213d2015-05-28 19:14:05 -0700623 if (err) {
624 dev_err(dev, "Could not add gpiochip for bank %d\n",
625 bank->id);
626 goto fail;
627 }
628 gpio_base += gc->ngpio;
Gregory Fong19a7b692015-07-31 18:17:43 -0700629
Gregory Fong3b0213d2015-05-28 19:14:05 -0700630 dev_dbg(dev, "bank=%d, base=%d, ngpio=%d, width=%d\n", bank->id,
631 gc->base, gc->ngpio, bank->width);
632
633 /* Everything looks good, so add bank to list */
634 list_add(&bank->node, &priv->bank_list);
635
Gregory Fong19a7b692015-07-31 18:17:43 -0700636 num_banks++;
Gregory Fong3b0213d2015-05-28 19:14:05 -0700637 }
638
Doug Berger0ba31dc2017-10-24 12:54:50 -0700639 priv->num_gpios = gpio_base - priv->gpio_base;
640 if (priv->parent_irq > 0) {
641 err = brcmstb_gpio_irq_setup(pdev, priv);
642 if (err)
643 goto fail;
644 }
645
Gregory Fong3b0213d2015-05-28 19:14:05 -0700646 dev_info(dev, "Registered %d banks (GPIO(s): %d-%d)\n",
Gregory Fong19a7b692015-07-31 18:17:43 -0700647 num_banks, priv->gpio_base, gpio_base - 1);
Gregory Fong3b0213d2015-05-28 19:14:05 -0700648
Gregory Fong3b0213d2015-05-28 19:14:05 -0700649 return 0;
650
651fail:
652 (void) brcmstb_gpio_remove(pdev);
653 return err;
654}
655
656static const struct of_device_id brcmstb_gpio_of_match[] = {
657 { .compatible = "brcm,brcmstb-gpio" },
658 {},
659};
660
661MODULE_DEVICE_TABLE(of, brcmstb_gpio_of_match);
662
663static struct platform_driver brcmstb_gpio_driver = {
664 .driver = {
665 .name = "brcmstb-gpio",
666 .of_match_table = brcmstb_gpio_of_match,
667 },
668 .probe = brcmstb_gpio_probe,
669 .remove = brcmstb_gpio_remove,
670};
671module_platform_driver(brcmstb_gpio_driver);
672
673MODULE_AUTHOR("Gregory Fong");
674MODULE_DESCRIPTION("Driver for Broadcom BRCMSTB SoC UPG GPIO");
675MODULE_LICENSE("GPL v2");