Commit | Line | Data |
---|---|---|
0d82fb11 SV |
1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | ||
3 | #include <linux/gpio/driver.h> | |
95fa6dbe | 4 | #include <linux/cpumask.h> |
0d82fb11 SV |
5 | #include <linux/irq.h> |
6 | #include <linux/minmax.h> | |
7 | #include <linux/mod_devicetable.h> | |
8 | #include <linux/module.h> | |
9 | #include <linux/platform_device.h> | |
10 | #include <linux/property.h> | |
11 | ||
12 | /* | |
13 | * Total register block size is 0x1C for one bank of four ports (A, B, C, D). | |
14 | * An optional second bank, with ports E, F, G, and H, may be present, starting | |
15 | * at register offset 0x1C. | |
16 | */ | |
17 | ||
18 | /* | |
19 | * Pin select: (0) "normal", (1) "dedicate peripheral" | |
20 | * Not used on RTL8380/RTL8390, peripheral selection is managed by control bits | |
21 | * in the peripheral registers. | |
22 | */ | |
23 | #define REALTEK_GPIO_REG_CNR 0x00 | |
24 | /* Clear bit (0) for input, set bit (1) for output */ | |
25 | #define REALTEK_GPIO_REG_DIR 0x08 | |
26 | #define REALTEK_GPIO_REG_DATA 0x0C | |
27 | /* Read bit for IRQ status, write 1 to clear IRQ */ | |
28 | #define REALTEK_GPIO_REG_ISR 0x10 | |
29 | /* Two bits per GPIO in IMR registers */ | |
30 | #define REALTEK_GPIO_REG_IMR 0x14 | |
31 | #define REALTEK_GPIO_REG_IMR_AB 0x14 | |
32 | #define REALTEK_GPIO_REG_IMR_CD 0x18 | |
33 | #define REALTEK_GPIO_IMR_LINE_MASK GENMASK(1, 0) | |
34 | #define REALTEK_GPIO_IRQ_EDGE_FALLING 1 | |
35 | #define REALTEK_GPIO_IRQ_EDGE_RISING 2 | |
36 | #define REALTEK_GPIO_IRQ_EDGE_BOTH 3 | |
37 | ||
38 | #define REALTEK_GPIO_MAX 32 | |
39 | #define REALTEK_GPIO_PORTS_PER_BANK 4 | |
40 | ||
41 | /** | |
42 | * realtek_gpio_ctrl - Realtek Otto GPIO driver data | |
43 | * | |
44 | * @gc: Associated gpio_chip instance | |
45 | * @base: Base address of the register block for a GPIO bank | |
46 | * @lock: Lock for accessing the IRQ registers and values | |
47 | * @intr_mask: Mask for interrupts lines | |
48 | * @intr_type: Interrupt type selection | |
ee0175b3 SV |
49 | * @bank_read: Read a bank setting as a single 32-bit value |
50 | * @bank_write: Write a bank setting as a single 32-bit value | |
51 | * @imr_line_pos: Bit shift of an IRQ line's IMR value. | |
52 | * | |
53 | * The DIR, DATA, and ISR registers consist of four 8-bit port values, packed | |
54 | * into a single 32-bit register. Use @bank_read (@bank_write) to get (assign) | |
55 | * a value from (to) these registers. The IMR register consists of four 16-bit | |
56 | * port values, packed into two 32-bit registers. Use @imr_line_pos to get the | |
57 | * bit shift of the 2-bit field for a line's IMR settings. Shifts larger than | |
58 | * 32 overflow into the second register. | |
0d82fb11 SV |
59 | * |
60 | * Because the interrupt mask register (IMR) combines the function of IRQ type | |
61 | * selection and masking, two extra values are stored. @intr_mask is used to | |
ee0175b3 | 62 | * mask/unmask the interrupts for a GPIO line, and @intr_type is used to store |
0d82fb11 SV |
63 | * the selected interrupt types. The logical AND of these values is written to |
64 | * IMR on changes. | |
65 | */ | |
66 | struct realtek_gpio_ctrl { | |
67 | struct gpio_chip gc; | |
68 | void __iomem *base; | |
95fa6dbe SV |
69 | void __iomem *cpumask_base; |
70 | struct cpumask cpu_irq_maskable; | |
0d82fb11 | 71 | raw_spinlock_t lock; |
ee0175b3 SV |
72 | u8 intr_mask[REALTEK_GPIO_MAX]; |
73 | u8 intr_type[REALTEK_GPIO_MAX]; | |
74 | u32 (*bank_read)(void __iomem *reg); | |
75 | void (*bank_write)(void __iomem *reg, u32 value); | |
76 | unsigned int (*line_imr_pos)(unsigned int line); | |
0d82fb11 SV |
77 | }; |
78 | ||
79 | /* Expand with more flags as devices with other quirks are added */ | |
80 | enum realtek_gpio_flags { | |
81 | /* | |
82 | * Allow disabling interrupts, for cases where the port order is | |
83 | * unknown. This may result in a port mismatch between ISR and IMR. | |
84 | * An interrupt would appear to come from a different line than the | |
85 | * line the IRQ handler was assigned to, causing uncaught interrupts. | |
86 | */ | |
87 | GPIO_INTERRUPTS_DISABLED = BIT(0), | |
512c5be3 SV |
88 | /* |
89 | * Port order is reversed, meaning DCBA register layout for 1-bit | |
90 | * fields, and [BA, DC] for 2-bit fields. | |
91 | */ | |
92 | GPIO_PORTS_REVERSED = BIT(1), | |
95fa6dbe SV |
93 | /* |
94 | * Interrupts can be enabled per cpu. This requires a secondary IO | |
95 | * range, where the per-cpu enable masks are located. | |
96 | */ | |
97 | GPIO_INTERRUPTS_PER_CPU = BIT(2), | |
0d82fb11 SV |
98 | }; |
99 | ||
100 | static struct realtek_gpio_ctrl *irq_data_to_ctrl(struct irq_data *data) | |
101 | { | |
102 | struct gpio_chip *gc = irq_data_get_irq_chip_data(data); | |
103 | ||
104 | return container_of(gc, struct realtek_gpio_ctrl, gc); | |
105 | } | |
106 | ||
107 | /* | |
108 | * Normal port order register access | |
109 | * | |
110 | * Port information is stored with the first port at offset 0, followed by the | |
111 | * second, etc. Most registers store one bit per GPIO and use a u8 value per | |
112 | * port. The two interrupt mask registers store two bits per GPIO, so use u16 | |
113 | * values. | |
114 | */ | |
ee0175b3 | 115 | static u32 realtek_gpio_bank_read_swapped(void __iomem *reg) |
512c5be3 | 116 | { |
ee0175b3 | 117 | return ioread32be(reg); |
512c5be3 SV |
118 | } |
119 | ||
ee0175b3 | 120 | static void realtek_gpio_bank_write_swapped(void __iomem *reg, u32 value) |
512c5be3 | 121 | { |
ee0175b3 SV |
122 | iowrite32be(value, reg); |
123 | } | |
124 | ||
125 | static unsigned int realtek_gpio_line_imr_pos_swapped(unsigned int line) | |
126 | { | |
127 | unsigned int port_pin = line % 8; | |
128 | unsigned int port = line / 8; | |
129 | ||
130 | return 2 * (8 * (port ^ 1) + port_pin); | |
512c5be3 SV |
131 | } |
132 | ||
133 | /* | |
134 | * Reversed port order register access | |
135 | * | |
136 | * For registers with one bit per GPIO, all ports are stored as u8-s in one | |
137 | * register in reversed order. The two interrupt mask registers store two bits | |
138 | * per GPIO, so use u16 values. The first register contains ports 1 and 0, the | |
139 | * second ports 3 and 2. | |
140 | */ | |
ee0175b3 | 141 | static u32 realtek_gpio_bank_read(void __iomem *reg) |
512c5be3 | 142 | { |
ee0175b3 | 143 | return ioread32(reg); |
512c5be3 SV |
144 | } |
145 | ||
ee0175b3 | 146 | static void realtek_gpio_bank_write(void __iomem *reg, u32 value) |
512c5be3 | 147 | { |
ee0175b3 | 148 | iowrite32(value, reg); |
512c5be3 SV |
149 | } |
150 | ||
ee0175b3 | 151 | static unsigned int realtek_gpio_line_imr_pos(unsigned int line) |
0d82fb11 | 152 | { |
ee0175b3 | 153 | return 2 * line; |
0d82fb11 SV |
154 | } |
155 | ||
ee0175b3 | 156 | static void realtek_gpio_clear_isr(struct realtek_gpio_ctrl *ctrl, u32 mask) |
0d82fb11 | 157 | { |
ee0175b3 | 158 | ctrl->bank_write(ctrl->base + REALTEK_GPIO_REG_ISR, mask); |
0d82fb11 SV |
159 | } |
160 | ||
ee0175b3 | 161 | static u32 realtek_gpio_read_isr(struct realtek_gpio_ctrl *ctrl) |
0d82fb11 | 162 | { |
ee0175b3 | 163 | return ctrl->bank_read(ctrl->base + REALTEK_GPIO_REG_ISR); |
0d82fb11 SV |
164 | } |
165 | ||
ee0175b3 SV |
166 | /* Set the rising and falling edge mask bits for a GPIO pin */ |
167 | static void realtek_gpio_update_line_imr(struct realtek_gpio_ctrl *ctrl, unsigned int line) | |
0d82fb11 | 168 | { |
ee0175b3 SV |
169 | void __iomem *reg = ctrl->base + REALTEK_GPIO_REG_IMR; |
170 | unsigned int line_shift = ctrl->line_imr_pos(line); | |
171 | unsigned int shift = line_shift % 32; | |
172 | u32 irq_type = ctrl->intr_type[line]; | |
173 | u32 irq_mask = ctrl->intr_mask[line]; | |
174 | u32 reg_val; | |
175 | ||
176 | reg += 4 * (line_shift / 32); | |
177 | reg_val = ioread32(reg); | |
178 | reg_val &= ~(REALTEK_GPIO_IMR_LINE_MASK << shift); | |
179 | reg_val |= (irq_type & irq_mask & REALTEK_GPIO_IMR_LINE_MASK) << shift; | |
180 | iowrite32(reg_val, reg); | |
0d82fb11 SV |
181 | } |
182 | ||
183 | static void realtek_gpio_irq_ack(struct irq_data *data) | |
184 | { | |
185 | struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data); | |
186 | irq_hw_number_t line = irqd_to_hwirq(data); | |
0d82fb11 | 187 | |
ee0175b3 | 188 | realtek_gpio_clear_isr(ctrl, BIT(line)); |
0d82fb11 SV |
189 | } |
190 | ||
191 | static void realtek_gpio_irq_unmask(struct irq_data *data) | |
192 | { | |
193 | struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data); | |
194 | unsigned int line = irqd_to_hwirq(data); | |
0d82fb11 | 195 | unsigned long flags; |
0d82fb11 | 196 | |
a01a40e3 SV |
197 | gpiochip_enable_irq(&ctrl->gc, line); |
198 | ||
0d82fb11 | 199 | raw_spin_lock_irqsave(&ctrl->lock, flags); |
ee0175b3 SV |
200 | ctrl->intr_mask[line] = REALTEK_GPIO_IMR_LINE_MASK; |
201 | realtek_gpio_update_line_imr(ctrl, line); | |
0d82fb11 SV |
202 | raw_spin_unlock_irqrestore(&ctrl->lock, flags); |
203 | } | |
204 | ||
205 | static void realtek_gpio_irq_mask(struct irq_data *data) | |
206 | { | |
207 | struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data); | |
208 | unsigned int line = irqd_to_hwirq(data); | |
0d82fb11 | 209 | unsigned long flags; |
0d82fb11 SV |
210 | |
211 | raw_spin_lock_irqsave(&ctrl->lock, flags); | |
ee0175b3 SV |
212 | ctrl->intr_mask[line] = 0; |
213 | realtek_gpio_update_line_imr(ctrl, line); | |
0d82fb11 | 214 | raw_spin_unlock_irqrestore(&ctrl->lock, flags); |
a01a40e3 SV |
215 | |
216 | gpiochip_disable_irq(&ctrl->gc, line); | |
0d82fb11 SV |
217 | } |
218 | ||
219 | static int realtek_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type) | |
220 | { | |
221 | struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data); | |
222 | unsigned int line = irqd_to_hwirq(data); | |
0d82fb11 | 223 | unsigned long flags; |
ee0175b3 | 224 | u8 type; |
0d82fb11 SV |
225 | |
226 | switch (flow_type & IRQ_TYPE_SENSE_MASK) { | |
227 | case IRQ_TYPE_EDGE_FALLING: | |
228 | type = REALTEK_GPIO_IRQ_EDGE_FALLING; | |
229 | break; | |
230 | case IRQ_TYPE_EDGE_RISING: | |
231 | type = REALTEK_GPIO_IRQ_EDGE_RISING; | |
232 | break; | |
233 | case IRQ_TYPE_EDGE_BOTH: | |
234 | type = REALTEK_GPIO_IRQ_EDGE_BOTH; | |
235 | break; | |
236 | default: | |
237 | return -EINVAL; | |
238 | } | |
239 | ||
240 | irq_set_handler_locked(data, handle_edge_irq); | |
241 | ||
242 | raw_spin_lock_irqsave(&ctrl->lock, flags); | |
ee0175b3 SV |
243 | ctrl->intr_type[line] = type; |
244 | realtek_gpio_update_line_imr(ctrl, line); | |
0d82fb11 SV |
245 | raw_spin_unlock_irqrestore(&ctrl->lock, flags); |
246 | ||
247 | return 0; | |
248 | } | |
249 | ||
250 | static void realtek_gpio_irq_handler(struct irq_desc *desc) | |
251 | { | |
252 | struct gpio_chip *gc = irq_desc_get_handler_data(desc); | |
253 | struct realtek_gpio_ctrl *ctrl = gpiochip_get_data(gc); | |
254 | struct irq_chip *irq_chip = irq_desc_get_chip(desc); | |
0d82fb11 SV |
255 | unsigned long status; |
256 | int offset; | |
257 | ||
258 | chained_irq_enter(irq_chip, desc); | |
259 | ||
ee0175b3 SV |
260 | status = realtek_gpio_read_isr(ctrl); |
261 | for_each_set_bit(offset, &status, gc->ngpio) | |
262 | generic_handle_domain_irq(gc->irq.domain, offset); | |
0d82fb11 SV |
263 | |
264 | chained_irq_exit(irq_chip, desc); | |
265 | } | |
266 | ||
ee0175b3 | 267 | static inline void __iomem *realtek_gpio_irq_cpu_mask(struct realtek_gpio_ctrl *ctrl, int cpu) |
95fa6dbe | 268 | { |
ee0175b3 | 269 | return ctrl->cpumask_base + REALTEK_GPIO_PORTS_PER_BANK * cpu; |
95fa6dbe SV |
270 | } |
271 | ||
272 | static int realtek_gpio_irq_set_affinity(struct irq_data *data, | |
273 | const struct cpumask *dest, bool force) | |
274 | { | |
275 | struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data); | |
276 | unsigned int line = irqd_to_hwirq(data); | |
95fa6dbe SV |
277 | void __iomem *irq_cpu_mask; |
278 | unsigned long flags; | |
279 | int cpu; | |
ee0175b3 | 280 | u32 v; |
95fa6dbe SV |
281 | |
282 | if (!ctrl->cpumask_base) | |
283 | return -ENXIO; | |
284 | ||
285 | raw_spin_lock_irqsave(&ctrl->lock, flags); | |
286 | ||
287 | for_each_cpu(cpu, &ctrl->cpu_irq_maskable) { | |
ee0175b3 SV |
288 | irq_cpu_mask = realtek_gpio_irq_cpu_mask(ctrl, cpu); |
289 | v = ctrl->bank_read(irq_cpu_mask); | |
95fa6dbe SV |
290 | |
291 | if (cpumask_test_cpu(cpu, dest)) | |
ee0175b3 | 292 | v |= BIT(line); |
95fa6dbe | 293 | else |
ee0175b3 | 294 | v &= ~BIT(line); |
95fa6dbe | 295 | |
ee0175b3 | 296 | ctrl->bank_write(irq_cpu_mask, v); |
95fa6dbe SV |
297 | } |
298 | ||
299 | raw_spin_unlock_irqrestore(&ctrl->lock, flags); | |
300 | ||
301 | irq_data_update_effective_affinity(data, dest); | |
302 | ||
303 | return 0; | |
304 | } | |
305 | ||
0d82fb11 SV |
306 | static int realtek_gpio_irq_init(struct gpio_chip *gc) |
307 | { | |
308 | struct realtek_gpio_ctrl *ctrl = gpiochip_get_data(gc); | |
ee0175b3 SV |
309 | u32 mask_all = GENMASK(gc->ngpio - 1, 0); |
310 | unsigned int line; | |
95fa6dbe | 311 | int cpu; |
0d82fb11 | 312 | |
ee0175b3 SV |
313 | for (line = 0; line < gc->ngpio; line++) |
314 | realtek_gpio_update_line_imr(ctrl, line); | |
95fa6dbe | 315 | |
ee0175b3 SV |
316 | realtek_gpio_clear_isr(ctrl, mask_all); |
317 | ||
318 | for_each_cpu(cpu, &ctrl->cpu_irq_maskable) | |
319 | ctrl->bank_write(realtek_gpio_irq_cpu_mask(ctrl, cpu), mask_all); | |
0d82fb11 SV |
320 | |
321 | return 0; | |
322 | } | |
323 | ||
a01a40e3 | 324 | static const struct irq_chip realtek_gpio_irq_chip = { |
0d82fb11 SV |
325 | .name = "realtek-otto-gpio", |
326 | .irq_ack = realtek_gpio_irq_ack, | |
327 | .irq_mask = realtek_gpio_irq_mask, | |
328 | .irq_unmask = realtek_gpio_irq_unmask, | |
329 | .irq_set_type = realtek_gpio_irq_set_type, | |
95fa6dbe | 330 | .irq_set_affinity = realtek_gpio_irq_set_affinity, |
a01a40e3 SV |
331 | .flags = IRQCHIP_IMMUTABLE, |
332 | GPIOCHIP_IRQ_RESOURCE_HELPERS, | |
0d82fb11 SV |
333 | }; |
334 | ||
335 | static const struct of_device_id realtek_gpio_of_match[] = { | |
336 | { | |
337 | .compatible = "realtek,otto-gpio", | |
338 | .data = (void *)GPIO_INTERRUPTS_DISABLED, | |
339 | }, | |
340 | { | |
341 | .compatible = "realtek,rtl8380-gpio", | |
342 | }, | |
343 | { | |
344 | .compatible = "realtek,rtl8390-gpio", | |
345 | }, | |
deaf1cec SV |
346 | { |
347 | .compatible = "realtek,rtl9300-gpio", | |
348 | .data = (void *)(GPIO_PORTS_REVERSED | GPIO_INTERRUPTS_PER_CPU) | |
349 | }, | |
d3bf3dc4 SV |
350 | { |
351 | .compatible = "realtek,rtl9310-gpio", | |
352 | }, | |
0d82fb11 SV |
353 | {} |
354 | }; | |
355 | MODULE_DEVICE_TABLE(of, realtek_gpio_of_match); | |
356 | ||
357 | static int realtek_gpio_probe(struct platform_device *pdev) | |
358 | { | |
359 | struct device *dev = &pdev->dev; | |
512c5be3 | 360 | unsigned long bgpio_flags; |
0d82fb11 SV |
361 | unsigned int dev_flags; |
362 | struct gpio_irq_chip *girq; | |
363 | struct realtek_gpio_ctrl *ctrl; | |
95fa6dbe | 364 | struct resource *res; |
0d82fb11 | 365 | u32 ngpios; |
95fa6dbe SV |
366 | unsigned int nr_cpus; |
367 | int cpu, err, irq; | |
0d82fb11 SV |
368 | |
369 | ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL); | |
370 | if (!ctrl) | |
371 | return -ENOMEM; | |
372 | ||
373 | dev_flags = (unsigned int) device_get_match_data(dev); | |
374 | ||
375 | ngpios = REALTEK_GPIO_MAX; | |
376 | device_property_read_u32(dev, "ngpios", &ngpios); | |
377 | ||
378 | if (ngpios > REALTEK_GPIO_MAX) { | |
379 | dev_err(&pdev->dev, "invalid ngpios (max. %d)\n", | |
380 | REALTEK_GPIO_MAX); | |
381 | return -EINVAL; | |
382 | } | |
383 | ||
384 | ctrl->base = devm_platform_ioremap_resource(pdev, 0); | |
385 | if (IS_ERR(ctrl->base)) | |
386 | return PTR_ERR(ctrl->base); | |
387 | ||
388 | raw_spin_lock_init(&ctrl->lock); | |
389 | ||
512c5be3 SV |
390 | if (dev_flags & GPIO_PORTS_REVERSED) { |
391 | bgpio_flags = 0; | |
ee0175b3 SV |
392 | ctrl->bank_read = realtek_gpio_bank_read; |
393 | ctrl->bank_write = realtek_gpio_bank_write; | |
394 | ctrl->line_imr_pos = realtek_gpio_line_imr_pos; | |
512c5be3 SV |
395 | } else { |
396 | bgpio_flags = BGPIOF_BIG_ENDIAN_BYTE_ORDER; | |
ee0175b3 SV |
397 | ctrl->bank_read = realtek_gpio_bank_read_swapped; |
398 | ctrl->bank_write = realtek_gpio_bank_write_swapped; | |
399 | ctrl->line_imr_pos = realtek_gpio_line_imr_pos_swapped; | |
512c5be3 SV |
400 | } |
401 | ||
0d82fb11 SV |
402 | err = bgpio_init(&ctrl->gc, dev, 4, |
403 | ctrl->base + REALTEK_GPIO_REG_DATA, NULL, NULL, | |
404 | ctrl->base + REALTEK_GPIO_REG_DIR, NULL, | |
512c5be3 | 405 | bgpio_flags); |
0d82fb11 SV |
406 | if (err) { |
407 | dev_err(dev, "unable to init generic GPIO"); | |
408 | return err; | |
409 | } | |
410 | ||
411 | ctrl->gc.ngpio = ngpios; | |
412 | ctrl->gc.owner = THIS_MODULE; | |
413 | ||
414 | irq = platform_get_irq_optional(pdev, 0); | |
415 | if (!(dev_flags & GPIO_INTERRUPTS_DISABLED) && irq > 0) { | |
416 | girq = &ctrl->gc.irq; | |
a01a40e3 | 417 | gpio_irq_chip_set_chip(girq, &realtek_gpio_irq_chip); |
0d82fb11 SV |
418 | girq->default_type = IRQ_TYPE_NONE; |
419 | girq->handler = handle_bad_irq; | |
420 | girq->parent_handler = realtek_gpio_irq_handler; | |
421 | girq->num_parents = 1; | |
422 | girq->parents = devm_kcalloc(dev, girq->num_parents, | |
423 | sizeof(*girq->parents), GFP_KERNEL); | |
424 | if (!girq->parents) | |
425 | return -ENOMEM; | |
426 | girq->parents[0] = irq; | |
427 | girq->init_hw = realtek_gpio_irq_init; | |
428 | } | |
429 | ||
95fa6dbe SV |
430 | cpumask_clear(&ctrl->cpu_irq_maskable); |
431 | ||
432 | if ((dev_flags & GPIO_INTERRUPTS_PER_CPU) && irq > 0) { | |
433 | ctrl->cpumask_base = devm_platform_get_and_ioremap_resource(pdev, 1, &res); | |
434 | if (IS_ERR(ctrl->cpumask_base)) | |
435 | return dev_err_probe(dev, PTR_ERR(ctrl->cpumask_base), | |
436 | "missing CPU IRQ mask registers"); | |
437 | ||
438 | nr_cpus = resource_size(res) / REALTEK_GPIO_PORTS_PER_BANK; | |
439 | nr_cpus = min(nr_cpus, num_present_cpus()); | |
440 | ||
441 | for (cpu = 0; cpu < nr_cpus; cpu++) | |
442 | cpumask_set_cpu(cpu, &ctrl->cpu_irq_maskable); | |
443 | } | |
444 | ||
0d82fb11 SV |
445 | return devm_gpiochip_add_data(dev, &ctrl->gc, ctrl); |
446 | } | |
447 | ||
448 | static struct platform_driver realtek_gpio_driver = { | |
449 | .driver = { | |
450 | .name = "realtek-otto-gpio", | |
451 | .of_match_table = realtek_gpio_of_match, | |
452 | }, | |
453 | .probe = realtek_gpio_probe, | |
454 | }; | |
455 | module_platform_driver(realtek_gpio_driver); | |
456 | ||
457 | MODULE_DESCRIPTION("Realtek Otto GPIO support"); | |
458 | MODULE_AUTHOR("Sander Vanheule <sander@svanheule.net>"); | |
459 | MODULE_LICENSE("GPL v2"); |