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 | ||
e42615ec MV |
165 | if (readl(gpdr) & BIT(offset % 32)) |
166 | return GPIO_LINE_DIRECTION_OUT; | |
167 | ||
168 | return GPIO_LINE_DIRECTION_IN; | |
46a5c112 AS |
169 | } |
170 | ||
e7a718f9 AS |
171 | static int mrfld_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset, |
172 | unsigned int debounce) | |
173 | { | |
174 | struct mrfld_gpio *priv = gpiochip_get_data(chip); | |
175 | void __iomem *gfbr = gpio_reg(chip, offset, GFBR); | |
176 | unsigned long flags; | |
177 | u32 value; | |
178 | ||
179 | raw_spin_lock_irqsave(&priv->lock, flags); | |
180 | ||
181 | if (debounce) | |
182 | value = readl(gfbr) & ~BIT(offset % 32); | |
183 | else | |
184 | value = readl(gfbr) | BIT(offset % 32); | |
185 | writel(value, gfbr); | |
186 | ||
187 | raw_spin_unlock_irqrestore(&priv->lock, flags); | |
188 | ||
189 | return 0; | |
190 | } | |
191 | ||
2956b5d9 MW |
192 | static int mrfld_gpio_set_config(struct gpio_chip *chip, unsigned int offset, |
193 | unsigned long config) | |
194 | { | |
195 | u32 debounce; | |
196 | ||
1d10243d AS |
197 | if ((pinconf_to_config_param(config) == PIN_CONFIG_BIAS_DISABLE) || |
198 | (pinconf_to_config_param(config) == PIN_CONFIG_BIAS_PULL_UP) || | |
199 | (pinconf_to_config_param(config) == PIN_CONFIG_BIAS_PULL_DOWN)) | |
200 | return gpiochip_generic_config(chip, offset, config); | |
201 | ||
2956b5d9 MW |
202 | if (pinconf_to_config_param(config) != PIN_CONFIG_INPUT_DEBOUNCE) |
203 | return -ENOTSUPP; | |
204 | ||
205 | debounce = pinconf_to_config_argument(config); | |
206 | return mrfld_gpio_set_debounce(chip, offset, debounce); | |
207 | } | |
208 | ||
ccf6fd6d AS |
209 | static void mrfld_irq_ack(struct irq_data *d) |
210 | { | |
211 | struct mrfld_gpio *priv = irq_data_get_irq_chip_data(d); | |
212 | u32 gpio = irqd_to_hwirq(d); | |
213 | void __iomem *gisr = gpio_reg(&priv->chip, gpio, GISR); | |
fcce9f14 AS |
214 | unsigned long flags; |
215 | ||
216 | raw_spin_lock_irqsave(&priv->lock, flags); | |
ccf6fd6d AS |
217 | |
218 | writel(BIT(gpio % 32), gisr); | |
fcce9f14 AS |
219 | |
220 | raw_spin_unlock_irqrestore(&priv->lock, flags); | |
ccf6fd6d AS |
221 | } |
222 | ||
223 | static void mrfld_irq_unmask_mask(struct irq_data *d, bool unmask) | |
224 | { | |
225 | struct mrfld_gpio *priv = irq_data_get_irq_chip_data(d); | |
226 | u32 gpio = irqd_to_hwirq(d); | |
227 | void __iomem *gimr = gpio_reg(&priv->chip, gpio, GIMR); | |
228 | unsigned long flags; | |
229 | u32 value; | |
230 | ||
231 | raw_spin_lock_irqsave(&priv->lock, flags); | |
232 | ||
233 | if (unmask) | |
234 | value = readl(gimr) | BIT(gpio % 32); | |
235 | else | |
236 | value = readl(gimr) & ~BIT(gpio % 32); | |
237 | writel(value, gimr); | |
238 | ||
239 | raw_spin_unlock_irqrestore(&priv->lock, flags); | |
240 | } | |
241 | ||
242 | static void mrfld_irq_mask(struct irq_data *d) | |
243 | { | |
244 | mrfld_irq_unmask_mask(d, false); | |
245 | } | |
246 | ||
247 | static void mrfld_irq_unmask(struct irq_data *d) | |
248 | { | |
249 | mrfld_irq_unmask_mask(d, true); | |
250 | } | |
251 | ||
252 | static int mrfld_irq_set_type(struct irq_data *d, unsigned int type) | |
253 | { | |
254 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | |
255 | struct mrfld_gpio *priv = gpiochip_get_data(gc); | |
256 | u32 gpio = irqd_to_hwirq(d); | |
257 | void __iomem *grer = gpio_reg(&priv->chip, gpio, GRER); | |
258 | void __iomem *gfer = gpio_reg(&priv->chip, gpio, GFER); | |
259 | void __iomem *gitr = gpio_reg(&priv->chip, gpio, GITR); | |
260 | void __iomem *glpr = gpio_reg(&priv->chip, gpio, GLPR); | |
261 | unsigned long flags; | |
262 | u32 value; | |
263 | ||
264 | raw_spin_lock_irqsave(&priv->lock, flags); | |
265 | ||
266 | if (type & IRQ_TYPE_EDGE_RISING) | |
267 | value = readl(grer) | BIT(gpio % 32); | |
268 | else | |
269 | value = readl(grer) & ~BIT(gpio % 32); | |
270 | writel(value, grer); | |
271 | ||
272 | if (type & IRQ_TYPE_EDGE_FALLING) | |
273 | value = readl(gfer) | BIT(gpio % 32); | |
274 | else | |
275 | value = readl(gfer) & ~BIT(gpio % 32); | |
276 | writel(value, gfer); | |
277 | ||
278 | /* | |
279 | * To prevent glitches from triggering an unintended level interrupt, | |
280 | * configure GLPR register first and then configure GITR. | |
281 | */ | |
282 | if (type & IRQ_TYPE_LEVEL_LOW) | |
283 | value = readl(glpr) | BIT(gpio % 32); | |
284 | else | |
285 | value = readl(glpr) & ~BIT(gpio % 32); | |
286 | writel(value, glpr); | |
287 | ||
288 | if (type & IRQ_TYPE_LEVEL_MASK) { | |
289 | value = readl(gitr) | BIT(gpio % 32); | |
290 | writel(value, gitr); | |
291 | ||
292 | irq_set_handler_locked(d, handle_level_irq); | |
293 | } else if (type & IRQ_TYPE_EDGE_BOTH) { | |
294 | value = readl(gitr) & ~BIT(gpio % 32); | |
295 | writel(value, gitr); | |
296 | ||
297 | irq_set_handler_locked(d, handle_edge_irq); | |
298 | } | |
299 | ||
300 | raw_spin_unlock_irqrestore(&priv->lock, flags); | |
301 | ||
302 | return 0; | |
303 | } | |
304 | ||
305 | static int mrfld_irq_set_wake(struct irq_data *d, unsigned int on) | |
306 | { | |
307 | struct gpio_chip *gc = irq_data_get_irq_chip_data(d); | |
308 | struct mrfld_gpio *priv = gpiochip_get_data(gc); | |
309 | u32 gpio = irqd_to_hwirq(d); | |
310 | void __iomem *gwmr = gpio_reg(&priv->chip, gpio, GWMR); | |
311 | void __iomem *gwsr = gpio_reg(&priv->chip, gpio, GWSR); | |
312 | unsigned long flags; | |
313 | u32 value; | |
314 | ||
315 | raw_spin_lock_irqsave(&priv->lock, flags); | |
316 | ||
317 | /* Clear the existing wake status */ | |
318 | writel(BIT(gpio % 32), gwsr); | |
319 | ||
320 | if (on) | |
321 | value = readl(gwmr) | BIT(gpio % 32); | |
322 | else | |
323 | value = readl(gwmr) & ~BIT(gpio % 32); | |
324 | writel(value, gwmr); | |
325 | ||
326 | raw_spin_unlock_irqrestore(&priv->lock, flags); | |
327 | ||
328 | dev_dbg(priv->dev, "%sable wake for gpio %u\n", on ? "en" : "dis", gpio); | |
329 | return 0; | |
330 | } | |
331 | ||
332 | static struct irq_chip mrfld_irqchip = { | |
333 | .name = "gpio-merrifield", | |
334 | .irq_ack = mrfld_irq_ack, | |
335 | .irq_mask = mrfld_irq_mask, | |
336 | .irq_unmask = mrfld_irq_unmask, | |
337 | .irq_set_type = mrfld_irq_set_type, | |
338 | .irq_set_wake = mrfld_irq_set_wake, | |
339 | }; | |
340 | ||
341 | static void mrfld_irq_handler(struct irq_desc *desc) | |
342 | { | |
343 | struct gpio_chip *gc = irq_desc_get_handler_data(desc); | |
344 | struct mrfld_gpio *priv = gpiochip_get_data(gc); | |
345 | struct irq_chip *irqchip = irq_desc_get_chip(desc); | |
346 | unsigned long base, gpio; | |
347 | ||
348 | chained_irq_enter(irqchip, desc); | |
349 | ||
350 | /* Check GPIO controller to check which pin triggered the interrupt */ | |
351 | for (base = 0; base < priv->chip.ngpio; base += 32) { | |
352 | void __iomem *gisr = gpio_reg(&priv->chip, base, GISR); | |
353 | void __iomem *gimr = gpio_reg(&priv->chip, base, GIMR); | |
354 | unsigned long pending, enabled; | |
355 | ||
356 | pending = readl(gisr); | |
357 | enabled = readl(gimr); | |
358 | ||
359 | /* Only interrupts that are enabled */ | |
360 | pending &= enabled; | |
361 | ||
362 | for_each_set_bit(gpio, &pending, 32) { | |
363 | unsigned int irq; | |
364 | ||
f0fbe7bc | 365 | irq = irq_find_mapping(gc->irq.domain, base + gpio); |
ccf6fd6d AS |
366 | generic_handle_irq(irq); |
367 | } | |
368 | } | |
369 | ||
370 | chained_irq_exit(irqchip, desc); | |
371 | } | |
372 | ||
4a5e0f9e | 373 | static int mrfld_irq_init_hw(struct gpio_chip *chip) |
ccf6fd6d | 374 | { |
4a5e0f9e | 375 | struct mrfld_gpio *priv = gpiochip_get_data(chip); |
ccf6fd6d AS |
376 | void __iomem *reg; |
377 | unsigned int base; | |
378 | ||
379 | for (base = 0; base < priv->chip.ngpio; base += 32) { | |
380 | /* Clear the rising-edge detect register */ | |
381 | reg = gpio_reg(&priv->chip, base, GRER); | |
382 | writel(0, reg); | |
383 | /* Clear the falling-edge detect register */ | |
384 | reg = gpio_reg(&priv->chip, base, GFER); | |
385 | writel(0, reg); | |
386 | } | |
4a5e0f9e AS |
387 | |
388 | return 0; | |
ccf6fd6d AS |
389 | } |
390 | ||
d00d2109 | 391 | static const char *mrfld_gpio_get_pinctrl_dev_name(struct mrfld_gpio *priv) |
dd1dbf94 | 392 | { |
d00d2109 AS |
393 | struct acpi_device *adev; |
394 | const char *name; | |
395 | ||
396 | adev = acpi_dev_get_first_match_dev("INTC1002", NULL, -1); | |
397 | if (adev) { | |
398 | name = devm_kstrdup(priv->dev, acpi_dev_name(adev), GFP_KERNEL); | |
fe066621 | 399 | acpi_dev_put(adev); |
d00d2109 AS |
400 | } else { |
401 | name = "pinctrl-merrifield"; | |
402 | } | |
403 | ||
404 | return name; | |
dd1dbf94 AS |
405 | } |
406 | ||
cd242b33 | 407 | static int mrfld_gpio_add_pin_ranges(struct gpio_chip *chip) |
ccf6fd6d | 408 | { |
cd242b33 | 409 | struct mrfld_gpio *priv = gpiochip_get_data(chip); |
ccf6fd6d | 410 | const struct mrfld_gpio_pinrange *range; |
dd1dbf94 | 411 | const char *pinctrl_dev_name; |
cd242b33 AS |
412 | unsigned int i; |
413 | int retval; | |
414 | ||
415 | pinctrl_dev_name = mrfld_gpio_get_pinctrl_dev_name(priv); | |
416 | for (i = 0; i < ARRAY_SIZE(mrfld_gpio_ranges); i++) { | |
417 | range = &mrfld_gpio_ranges[i]; | |
418 | retval = gpiochip_add_pin_range(&priv->chip, pinctrl_dev_name, | |
419 | range->gpio_base, | |
420 | range->pin_base, | |
421 | range->npins); | |
422 | if (retval) { | |
423 | dev_err(priv->dev, "failed to add GPIO pin range\n"); | |
424 | return retval; | |
425 | } | |
426 | } | |
427 | ||
428 | return 0; | |
429 | } | |
430 | ||
431 | static int mrfld_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |
432 | { | |
4a5e0f9e | 433 | struct gpio_irq_chip *girq; |
ccf6fd6d AS |
434 | struct mrfld_gpio *priv; |
435 | u32 gpio_base, irq_base; | |
436 | void __iomem *base; | |
ccf6fd6d AS |
437 | int retval; |
438 | ||
439 | retval = pcim_enable_device(pdev); | |
440 | if (retval) | |
441 | return retval; | |
442 | ||
443 | retval = pcim_iomap_regions(pdev, BIT(1) | BIT(0), pci_name(pdev)); | |
444 | if (retval) { | |
445 | dev_err(&pdev->dev, "I/O memory mapping error\n"); | |
446 | return retval; | |
447 | } | |
448 | ||
449 | base = pcim_iomap_table(pdev)[1]; | |
450 | ||
7e73aa90 AS |
451 | irq_base = readl(base + 0 * sizeof(u32)); |
452 | gpio_base = readl(base + 1 * sizeof(u32)); | |
ccf6fd6d AS |
453 | |
454 | /* Release the IO mapping, since we already get the info from BAR1 */ | |
455 | pcim_iounmap_regions(pdev, BIT(1)); | |
456 | ||
457 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | |
4b7edaef | 458 | if (!priv) |
ccf6fd6d | 459 | return -ENOMEM; |
ccf6fd6d AS |
460 | |
461 | priv->dev = &pdev->dev; | |
462 | priv->reg_base = pcim_iomap_table(pdev)[0]; | |
463 | ||
464 | priv->chip.label = dev_name(&pdev->dev); | |
465 | priv->chip.parent = &pdev->dev; | |
466 | priv->chip.request = gpiochip_generic_request; | |
467 | priv->chip.free = gpiochip_generic_free; | |
468 | priv->chip.direction_input = mrfld_gpio_direction_input; | |
469 | priv->chip.direction_output = mrfld_gpio_direction_output; | |
470 | priv->chip.get = mrfld_gpio_get; | |
471 | priv->chip.set = mrfld_gpio_set; | |
46a5c112 | 472 | priv->chip.get_direction = mrfld_gpio_get_direction; |
2956b5d9 | 473 | priv->chip.set_config = mrfld_gpio_set_config; |
ccf6fd6d AS |
474 | priv->chip.base = gpio_base; |
475 | priv->chip.ngpio = MRFLD_NGPIO; | |
476 | priv->chip.can_sleep = false; | |
cd242b33 | 477 | priv->chip.add_pin_ranges = mrfld_gpio_add_pin_ranges; |
ccf6fd6d AS |
478 | |
479 | raw_spin_lock_init(&priv->lock); | |
480 | ||
6b1c7837 AS |
481 | retval = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); |
482 | if (retval < 0) | |
483 | return retval; | |
484 | ||
4a5e0f9e AS |
485 | girq = &priv->chip.irq; |
486 | girq->chip = &mrfld_irqchip; | |
487 | girq->init_hw = mrfld_irq_init_hw; | |
488 | girq->parent_handler = mrfld_irq_handler; | |
489 | girq->num_parents = 1; | |
490 | girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents, | |
491 | sizeof(*girq->parents), GFP_KERNEL); | |
492 | if (!girq->parents) | |
493 | return -ENOMEM; | |
6b1c7837 | 494 | girq->parents[0] = pci_irq_vector(pdev, 0); |
4a5e0f9e AS |
495 | girq->first = irq_base; |
496 | girq->default_type = IRQ_TYPE_NONE; | |
497 | girq->handler = handle_bad_irq; | |
498 | ||
ccf6fd6d AS |
499 | retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv); |
500 | if (retval) { | |
501 | dev_err(&pdev->dev, "gpiochip_add error %d\n", retval); | |
502 | return retval; | |
503 | } | |
504 | ||
cd242b33 | 505 | pci_set_drvdata(pdev, priv); |
ccf6fd6d AS |
506 | return 0; |
507 | } | |
508 | ||
509 | static const struct pci_device_id mrfld_gpio_ids[] = { | |
510 | { PCI_VDEVICE(INTEL, 0x1199) }, | |
511 | { } | |
512 | }; | |
513 | MODULE_DEVICE_TABLE(pci, mrfld_gpio_ids); | |
514 | ||
515 | static struct pci_driver mrfld_gpio_driver = { | |
516 | .name = "gpio-merrifield", | |
517 | .id_table = mrfld_gpio_ids, | |
518 | .probe = mrfld_gpio_probe, | |
519 | }; | |
520 | ||
521 | module_pci_driver(mrfld_gpio_driver); | |
522 | ||
523 | MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>"); | |
524 | MODULE_DESCRIPTION("Intel Merrifield SoC GPIO driver"); | |
525 | MODULE_LICENSE("GPL v2"); |