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