Commit | Line | Data |
---|---|---|
93374b76 | 1 | // SPDX-License-Identifier: GPL-2.0 |
ccf6fd6d AS |
2 | /* |
3 | * Intel Merrifield SoC GPIO driver | |
4 | * | |
5 | * Copyright (c) 2016 Intel Corporation. | |
6 | * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> | |
ccf6fd6d AS |
7 | */ |
8 | ||
dd1dbf94 | 9 | #include <linux/acpi.h> |
ccf6fd6d AS |
10 | #include <linux/bitops.h> |
11 | #include <linux/gpio/driver.h> | |
ccf6fd6d AS |
12 | #include <linux/interrupt.h> |
13 | #include <linux/io.h> | |
14 | #include <linux/module.h> | |
15 | #include <linux/pci.h> | |
16 | #include <linux/pinctrl/consumer.h> | |
17 | ||
18 | #define GCCR 0x000 /* controller configuration */ | |
19 | #define GPLR 0x004 /* pin level r/o */ | |
20 | #define GPDR 0x01c /* pin direction */ | |
21 | #define GPSR 0x034 /* pin set w/o */ | |
22 | #define GPCR 0x04c /* pin clear w/o */ | |
23 | #define GRER 0x064 /* rising edge detect */ | |
24 | #define GFER 0x07c /* falling edge detect */ | |
25 | #define GFBR 0x094 /* glitch filter bypass */ | |
26 | #define GIMR 0x0ac /* interrupt mask */ | |
27 | #define GISR 0x0c4 /* interrupt source */ | |
28 | #define GITR 0x300 /* input type */ | |
29 | #define GLPR 0x318 /* level input polarity */ | |
30 | #define GWMR 0x400 /* wake mask */ | |
31 | #define GWSR 0x418 /* wake source */ | |
32 | #define GSIR 0xc00 /* secure input */ | |
33 | ||
34 | /* Intel Merrifield has 192 GPIO pins */ | |
35 | #define MRFLD_NGPIO 192 | |
36 | ||
37 | struct mrfld_gpio_pinrange { | |
38 | unsigned int gpio_base; | |
39 | unsigned int pin_base; | |
40 | unsigned int npins; | |
41 | }; | |
42 | ||
43 | #define GPIO_PINRANGE(gstart, gend, pstart) \ | |
44 | { \ | |
45 | .gpio_base = (gstart), \ | |
46 | .pin_base = (pstart), \ | |
47 | .npins = (gend) - (gstart) + 1, \ | |
48 | } | |
49 | ||
50 | struct mrfld_gpio { | |
51 | struct gpio_chip chip; | |
52 | void __iomem *reg_base; | |
53 | raw_spinlock_t lock; | |
54 | struct device *dev; | |
55 | }; | |
56 | ||
57 | static const struct mrfld_gpio_pinrange mrfld_gpio_ranges[] = { | |
58 | GPIO_PINRANGE(0, 11, 146), | |
59 | GPIO_PINRANGE(12, 13, 144), | |
60 | GPIO_PINRANGE(14, 15, 35), | |
61 | GPIO_PINRANGE(16, 16, 164), | |
62 | GPIO_PINRANGE(17, 18, 105), | |
63 | GPIO_PINRANGE(19, 22, 101), | |
64 | GPIO_PINRANGE(23, 30, 107), | |
65 | GPIO_PINRANGE(32, 43, 67), | |
66 | GPIO_PINRANGE(44, 63, 195), | |
67 | GPIO_PINRANGE(64, 67, 140), | |
68 | GPIO_PINRANGE(68, 69, 165), | |
69 | GPIO_PINRANGE(70, 71, 65), | |
70 | GPIO_PINRANGE(72, 76, 228), | |
71 | GPIO_PINRANGE(77, 86, 37), | |
72 | GPIO_PINRANGE(87, 87, 48), | |
73 | GPIO_PINRANGE(88, 88, 47), | |
74 | GPIO_PINRANGE(89, 96, 49), | |
75 | GPIO_PINRANGE(97, 97, 34), | |
76 | GPIO_PINRANGE(102, 119, 83), | |
77 | GPIO_PINRANGE(120, 123, 79), | |
78 | GPIO_PINRANGE(124, 135, 115), | |
79 | GPIO_PINRANGE(137, 142, 158), | |
80 | GPIO_PINRANGE(154, 163, 24), | |
81 | GPIO_PINRANGE(164, 176, 215), | |
82 | GPIO_PINRANGE(177, 189, 127), | |
83 | GPIO_PINRANGE(190, 191, 178), | |
84 | }; | |
85 | ||
86 | static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned int offset, | |
87 | unsigned int reg_type_offset) | |
88 | { | |
89 | struct mrfld_gpio *priv = gpiochip_get_data(chip); | |
90 | u8 reg = offset / 32; | |
91 | ||
92 | return priv->reg_base + reg_type_offset + reg * 4; | |
93 | } | |
94 | ||
95 | static int mrfld_gpio_get(struct gpio_chip *chip, unsigned int offset) | |
96 | { | |
97 | void __iomem *gplr = gpio_reg(chip, offset, GPLR); | |
98 | ||
99 | return !!(readl(gplr) & BIT(offset % 32)); | |
100 | } | |
101 | ||
102 | static void mrfld_gpio_set(struct gpio_chip *chip, unsigned int offset, | |
103 | int value) | |
104 | { | |
fcce9f14 | 105 | struct mrfld_gpio *priv = gpiochip_get_data(chip); |
ccf6fd6d | 106 | void __iomem *gpsr, *gpcr; |
fcce9f14 AS |
107 | unsigned long flags; |
108 | ||
109 | raw_spin_lock_irqsave(&priv->lock, flags); | |
ccf6fd6d AS |
110 | |
111 | if (value) { | |
112 | gpsr = gpio_reg(chip, offset, GPSR); | |
113 | writel(BIT(offset % 32), gpsr); | |
114 | } else { | |
115 | gpcr = gpio_reg(chip, offset, GPCR); | |
116 | writel(BIT(offset % 32), gpcr); | |
117 | } | |
fcce9f14 AS |
118 | |
119 | raw_spin_unlock_irqrestore(&priv->lock, flags); | |
ccf6fd6d AS |
120 | } |
121 | ||
122 | static int mrfld_gpio_direction_input(struct gpio_chip *chip, | |
123 | unsigned int offset) | |
124 | { | |
125 | struct mrfld_gpio *priv = gpiochip_get_data(chip); | |
126 | void __iomem *gpdr = gpio_reg(chip, offset, GPDR); | |
127 | unsigned long flags; | |
128 | u32 value; | |
129 | ||
130 | raw_spin_lock_irqsave(&priv->lock, flags); | |
131 | ||
132 | value = readl(gpdr); | |
133 | value &= ~BIT(offset % 32); | |
134 | writel(value, gpdr); | |
135 | ||
136 | raw_spin_unlock_irqrestore(&priv->lock, flags); | |
137 | ||
138 | return 0; | |
139 | } | |
140 | ||
141 | static int mrfld_gpio_direction_output(struct gpio_chip *chip, | |
142 | unsigned int offset, int value) | |
143 | { | |
144 | struct mrfld_gpio *priv = gpiochip_get_data(chip); | |
145 | void __iomem *gpdr = gpio_reg(chip, offset, GPDR); | |
146 | unsigned long flags; | |
147 | ||
148 | mrfld_gpio_set(chip, offset, value); | |
149 | ||
150 | raw_spin_lock_irqsave(&priv->lock, flags); | |
151 | ||
152 | value = readl(gpdr); | |
153 | value |= BIT(offset % 32); | |
154 | writel(value, gpdr); | |
155 | ||
156 | raw_spin_unlock_irqrestore(&priv->lock, flags); | |
157 | ||
158 | return 0; | |
159 | } | |
160 | ||
46a5c112 AS |
161 | static int mrfld_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) |
162 | { | |
163 | void __iomem *gpdr = gpio_reg(chip, offset, GPDR); | |
164 | ||
7477e137 | 165 | return !(readl(gpdr) & BIT(offset % 32)); |
46a5c112 AS |
166 | } |
167 | ||
e7a718f9 AS |
168 | static int mrfld_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset, |
169 | unsigned int debounce) | |
170 | { | |
171 | struct mrfld_gpio *priv = gpiochip_get_data(chip); | |
172 | void __iomem *gfbr = gpio_reg(chip, offset, GFBR); | |
173 | unsigned long flags; | |
174 | u32 value; | |
175 | ||
176 | raw_spin_lock_irqsave(&priv->lock, flags); | |
177 | ||
178 | if (debounce) | |
179 | value = readl(gfbr) & ~BIT(offset % 32); | |
180 | else | |
181 | value = readl(gfbr) | BIT(offset % 32); | |
182 | writel(value, gfbr); | |
183 | ||
184 | raw_spin_unlock_irqrestore(&priv->lock, flags); | |
185 | ||
186 | return 0; | |
187 | } | |
188 | ||
2956b5d9 MW |
189 | static int mrfld_gpio_set_config(struct gpio_chip *chip, unsigned int offset, |
190 | unsigned long config) | |
191 | { | |
192 | u32 debounce; | |
193 | ||
194 | if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE) | |
195 | return -ENOTSUPP; | |
196 | ||
197 | debounce = pinconf_to_config_argument(config); | |
198 | return mrfld_gpio_set_debounce(chip, offset, debounce); | |
199 | } | |
200 | ||
ccf6fd6d AS |
201 | static void mrfld_irq_ack(struct irq_data *d) |
202 | { | |
203 | struct mrfld_gpio *priv = irq_data_get_irq_chip_data(d); | |
204 | u32 gpio = irqd_to_hwirq(d); | |
205 | void __iomem *gisr = gpio_reg(&priv->chip, gpio, GISR); | |
fcce9f14 AS |
206 | unsigned long flags; |
207 | ||
208 | raw_spin_lock_irqsave(&priv->lock, flags); | |
ccf6fd6d AS |
209 | |
210 | writel(BIT(gpio % 32), gisr); | |
fcce9f14 AS |
211 | |
212 | raw_spin_unlock_irqrestore(&priv->lock, flags); | |
ccf6fd6d AS |
213 | } |
214 | ||
215 | static void mrfld_irq_unmask_mask(struct irq_data *d, bool unmask) | |
216 | { | |
217 | struct mrfld_gpio *priv = irq_data_get_irq_chip_data(d); | |
218 | u32 gpio = irqd_to_hwirq(d); | |
219 | void __iomem *gimr = gpio_reg(&priv->chip, gpio, GIMR); | |
220 | unsigned long flags; | |
221 | u32 value; | |
222 | ||
223 | raw_spin_lock_irqsave(&priv->lock, flags); | |
224 | ||
225 | if (unmask) | |
226 | value = readl(gimr) | BIT(gpio % 32); | |
227 | else | |
228 | value = readl(gimr) & ~BIT(gpio % 32); | |
229 | writel(value, gimr); | |
230 | ||
231 | raw_spin_unlock_irqrestore(&priv->lock, flags); | |
232 | } | |
233 | ||
234 | static void mrfld_irq_mask(struct irq_data *d) | |
235 | { | |
236 | mrfld_irq_unmask_mask(d, false); | |
237 | } | |
238 | ||
239 | static void mrfld_irq_unmask(struct irq_data *d) | |
240 | { | |
241 | mrfld_irq_unmask_mask(d, true); | |
242 | } | |
243 | ||
244 | static int mrfld_irq_set_type(struct irq_data *d, unsigned int type) | |
245 | { | |
246 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | |
247 | struct mrfld_gpio *priv = gpiochip_get_data(gc); | |
248 | u32 gpio = irqd_to_hwirq(d); | |
249 | void __iomem *grer = gpio_reg(&priv->chip, gpio, GRER); | |
250 | void __iomem *gfer = gpio_reg(&priv->chip, gpio, GFER); | |
251 | void __iomem *gitr = gpio_reg(&priv->chip, gpio, GITR); | |
252 | void __iomem *glpr = gpio_reg(&priv->chip, gpio, GLPR); | |
253 | unsigned long flags; | |
254 | u32 value; | |
255 | ||
256 | raw_spin_lock_irqsave(&priv->lock, flags); | |
257 | ||
258 | if (type & IRQ_TYPE_EDGE_RISING) | |
259 | value = readl(grer) | BIT(gpio % 32); | |
260 | else | |
261 | value = readl(grer) & ~BIT(gpio % 32); | |
262 | writel(value, grer); | |
263 | ||
264 | if (type & IRQ_TYPE_EDGE_FALLING) | |
265 | value = readl(gfer) | BIT(gpio % 32); | |
266 | else | |
267 | value = readl(gfer) & ~BIT(gpio % 32); | |
268 | writel(value, gfer); | |
269 | ||
270 | /* | |
271 | * To prevent glitches from triggering an unintended level interrupt, | |
272 | * configure GLPR register first and then configure GITR. | |
273 | */ | |
274 | if (type & IRQ_TYPE_LEVEL_LOW) | |
275 | value = readl(glpr) | BIT(gpio % 32); | |
276 | else | |
277 | value = readl(glpr) & ~BIT(gpio % 32); | |
278 | writel(value, glpr); | |
279 | ||
280 | if (type & IRQ_TYPE_LEVEL_MASK) { | |
281 | value = readl(gitr) | BIT(gpio % 32); | |
282 | writel(value, gitr); | |
283 | ||
284 | irq_set_handler_locked(d, handle_level_irq); | |
285 | } else if (type & IRQ_TYPE_EDGE_BOTH) { | |
286 | value = readl(gitr) & ~BIT(gpio % 32); | |
287 | writel(value, gitr); | |
288 | ||
289 | irq_set_handler_locked(d, handle_edge_irq); | |
290 | } | |
291 | ||
292 | raw_spin_unlock_irqrestore(&priv->lock, flags); | |
293 | ||
294 | return 0; | |
295 | } | |
296 | ||
297 | static int mrfld_irq_set_wake(struct irq_data *d, unsigned int on) | |
298 | { | |
299 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | |
300 | struct mrfld_gpio *priv = gpiochip_get_data(gc); | |
301 | u32 gpio = irqd_to_hwirq(d); | |
302 | void __iomem *gwmr = gpio_reg(&priv->chip, gpio, GWMR); | |
303 | void __iomem *gwsr = gpio_reg(&priv->chip, gpio, GWSR); | |
304 | unsigned long flags; | |
305 | u32 value; | |
306 | ||
307 | raw_spin_lock_irqsave(&priv->lock, flags); | |
308 | ||
309 | /* Clear the existing wake status */ | |
310 | writel(BIT(gpio % 32), gwsr); | |
311 | ||
312 | if (on) | |
313 | value = readl(gwmr) | BIT(gpio % 32); | |
314 | else | |
315 | value = readl(gwmr) & ~BIT(gpio % 32); | |
316 | writel(value, gwmr); | |
317 | ||
318 | raw_spin_unlock_irqrestore(&priv->lock, flags); | |
319 | ||
320 | dev_dbg(priv->dev, "%sable wake for gpio %u\n", on ? "en" : "dis", gpio); | |
321 | return 0; | |
322 | } | |
323 | ||
324 | static struct irq_chip mrfld_irqchip = { | |
325 | .name = "gpio-merrifield", | |
326 | .irq_ack = mrfld_irq_ack, | |
327 | .irq_mask = mrfld_irq_mask, | |
328 | .irq_unmask = mrfld_irq_unmask, | |
329 | .irq_set_type = mrfld_irq_set_type, | |
330 | .irq_set_wake = mrfld_irq_set_wake, | |
331 | }; | |
332 | ||
333 | static void mrfld_irq_handler(struct irq_desc *desc) | |
334 | { | |
335 | struct gpio_chip *gc = irq_desc_get_handler_data(desc); | |
336 | struct mrfld_gpio *priv = gpiochip_get_data(gc); | |
337 | struct irq_chip *irqchip = irq_desc_get_chip(desc); | |
338 | unsigned long base, gpio; | |
339 | ||
340 | chained_irq_enter(irqchip, desc); | |
341 | ||
342 | /* Check GPIO controller to check which pin triggered the interrupt */ | |
343 | for (base = 0; base < priv->chip.ngpio; base += 32) { | |
344 | void __iomem *gisr = gpio_reg(&priv->chip, base, GISR); | |
345 | void __iomem *gimr = gpio_reg(&priv->chip, base, GIMR); | |
346 | unsigned long pending, enabled; | |
347 | ||
348 | pending = readl(gisr); | |
349 | enabled = readl(gimr); | |
350 | ||
351 | /* Only interrupts that are enabled */ | |
352 | pending &= enabled; | |
353 | ||
354 | for_each_set_bit(gpio, &pending, 32) { | |
355 | unsigned int irq; | |
356 | ||
f0fbe7bc | 357 | irq = irq_find_mapping(gc->irq.domain, base + gpio); |
ccf6fd6d AS |
358 | generic_handle_irq(irq); |
359 | } | |
360 | } | |
361 | ||
362 | chained_irq_exit(irqchip, desc); | |
363 | } | |
364 | ||
4c875409 | 365 | static int mrfld_irq_init_hw(struct gpio_chip *chip) |
ccf6fd6d | 366 | { |
4c875409 | 367 | struct mrfld_gpio *priv = gpiochip_get_data(chip); |
ccf6fd6d AS |
368 | void __iomem *reg; |
369 | unsigned int base; | |
370 | ||
371 | for (base = 0; base < priv->chip.ngpio; base += 32) { | |
372 | /* Clear the rising-edge detect register */ | |
373 | reg = gpio_reg(&priv->chip, base, GRER); | |
374 | writel(0, reg); | |
375 | /* Clear the falling-edge detect register */ | |
376 | reg = gpio_reg(&priv->chip, base, GFER); | |
377 | writel(0, reg); | |
378 | } | |
4c875409 AS |
379 | |
380 | return 0; | |
ccf6fd6d AS |
381 | } |
382 | ||
d00d2109 | 383 | static const char *mrfld_gpio_get_pinctrl_dev_name(struct mrfld_gpio *priv) |
dd1dbf94 | 384 | { |
d00d2109 AS |
385 | struct acpi_device *adev; |
386 | const char *name; | |
387 | ||
388 | adev = acpi_dev_get_first_match_dev("INTC1002", NULL, -1); | |
389 | if (adev) { | |
390 | name = devm_kstrdup(priv->dev, acpi_dev_name(adev), GFP_KERNEL); | |
fe066621 | 391 | acpi_dev_put(adev); |
d00d2109 AS |
392 | } else { |
393 | name = "pinctrl-merrifield"; | |
394 | } | |
395 | ||
396 | return name; | |
dd1dbf94 AS |
397 | } |
398 | ||
ccf6fd6d AS |
399 | static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
400 | { | |
401 | const struct mrfld_gpio_pinrange *range; | |
dd1dbf94 | 402 | const char *pinctrl_dev_name; |
8f86a5b4 | 403 | struct gpio_irq_chip *girq; |
ccf6fd6d AS |
404 | struct mrfld_gpio *priv; |
405 | u32 gpio_base, irq_base; | |
406 | void __iomem *base; | |
407 | unsigned int i; | |
408 | int retval; | |
409 | ||
410 | retval = pcim_enable_device(pdev); | |
411 | if (retval) | |
412 | return retval; | |
413 | ||
414 | retval = pcim_iomap_regions(pdev, BIT(1) | BIT(0), pci_name(pdev)); | |
415 | if (retval) { | |
416 | dev_err(&pdev->dev, "I/O memory mapping error\n"); | |
417 | return retval; | |
418 | } | |
419 | ||
420 | base = pcim_iomap_table(pdev)[1]; | |
421 | ||
422 | irq_base = readl(base); | |
423 | gpio_base = readl(sizeof(u32) + base); | |
424 | ||
425 | /* Release the IO mapping, since we already get the info from BAR1 */ | |
426 | pcim_iounmap_regions(pdev, BIT(1)); | |
427 | ||
428 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | |
4b7edaef | 429 | if (!priv) |
ccf6fd6d | 430 | return -ENOMEM; |
ccf6fd6d AS |
431 | |
432 | priv->dev = &pdev->dev; | |
433 | priv->reg_base = pcim_iomap_table(pdev)[0]; | |
434 | ||
435 | priv->chip.label = dev_name(&pdev->dev); | |
436 | priv->chip.parent = &pdev->dev; | |
437 | priv->chip.request = gpiochip_generic_request; | |
438 | priv->chip.free = gpiochip_generic_free; | |
439 | priv->chip.direction_input = mrfld_gpio_direction_input; | |
440 | priv->chip.direction_output = mrfld_gpio_direction_output; | |
441 | priv->chip.get = mrfld_gpio_get; | |
442 | priv->chip.set = mrfld_gpio_set; | |
46a5c112 | 443 | priv->chip.get_direction = mrfld_gpio_get_direction; |
2956b5d9 | 444 | priv->chip.set_config = mrfld_gpio_set_config; |
ccf6fd6d AS |
445 | priv->chip.base = gpio_base; |
446 | priv->chip.ngpio = MRFLD_NGPIO; | |
447 | priv->chip.can_sleep = false; | |
448 | ||
449 | raw_spin_lock_init(&priv->lock); | |
450 | ||
8f86a5b4 LW |
451 | girq = &priv->chip.irq; |
452 | girq->chip = &mrfld_irqchip; | |
4c875409 | 453 | girq->init_hw = mrfld_irq_init_hw; |
8f86a5b4 LW |
454 | girq->parent_handler = mrfld_irq_handler; |
455 | girq->num_parents = 1; | |
456 | girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents, | |
457 | sizeof(*girq->parents), | |
458 | GFP_KERNEL); | |
459 | if (!girq->parents) | |
460 | return -ENOMEM; | |
461 | girq->parents[0] = pdev->irq; | |
6658f87f | 462 | girq->first = irq_base; |
8f86a5b4 LW |
463 | girq->default_type = IRQ_TYPE_NONE; |
464 | girq->handler = handle_bad_irq; | |
465 | ||
ccf6fd6d AS |
466 | pci_set_drvdata(pdev, priv); |
467 | retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv); | |
468 | if (retval) { | |
469 | dev_err(&pdev->dev, "gpiochip_add error %d\n", retval); | |
470 | return retval; | |
471 | } | |
472 | ||
d00d2109 | 473 | pinctrl_dev_name = mrfld_gpio_get_pinctrl_dev_name(priv); |
ccf6fd6d AS |
474 | for (i = 0; i < ARRAY_SIZE(mrfld_gpio_ranges); i++) { |
475 | range = &mrfld_gpio_ranges[i]; | |
476 | retval = gpiochip_add_pin_range(&priv->chip, | |
dd1dbf94 | 477 | pinctrl_dev_name, |
ccf6fd6d AS |
478 | range->gpio_base, |
479 | range->pin_base, | |
480 | range->npins); | |
481 | if (retval) { | |
482 | dev_err(&pdev->dev, "failed to add GPIO pin range\n"); | |
483 | return retval; | |
484 | } | |
485 | } | |
486 | ||
ccf6fd6d AS |
487 | return 0; |
488 | } | |
489 | ||
490 | static const struct pci_device_id mrfld_gpio_ids[] = { | |
491 | { PCI_VDEVICE(INTEL, 0x1199) }, | |
492 | { } | |
493 | }; | |
494 | MODULE_DEVICE_TABLE(pci, mrfld_gpio_ids); | |
495 | ||
496 | static struct pci_driver mrfld_gpio_driver = { | |
497 | .name = "gpio-merrifield", | |
498 | .id_table = mrfld_gpio_ids, | |
499 | .probe = mrfld_gpio_probe, | |
500 | }; | |
501 | ||
502 | module_pci_driver(mrfld_gpio_driver); | |
503 | ||
504 | MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>"); | |
505 | MODULE_DESCRIPTION("Intel Merrifield SoC GPIO driver"); | |
506 | MODULE_LICENSE("GPL v2"); |