1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * SGI IOC3 multifunction device driver |
4 | * |
5 | * Copyright (C) 2018, 2019 Thomas Bogendoerfer <tbogendoerfer@suse.de> |
6 | * |
7 | * Based on work by: |
8 | * Stanislaw Skowronek <skylark@unaligned.org> |
9 | * Joshua Kinard <kumba@gentoo.org> |
10 | * Brent Casavant <bcasavan@sgi.com> - IOC4 master driver |
11 | * Pat Gefre <pfg@sgi.com> - IOC3 serial port IRQ demuxer |
12 | */ |
13 | |
14 | #include <linux/delay.h> |
15 | #include <linux/errno.h> |
16 | #include <linux/interrupt.h> |
17 | #include <linux/irqdomain.h> |
18 | #include <linux/mfd/core.h> |
19 | #include <linux/module.h> |
20 | #include <linux/pci.h> |
21 | #include <linux/platform_device.h> |
22 | #include <linux/platform_data/sgi-w1.h> |
23 | #include <linux/rtc/ds1685.h> |
24 | |
25 | #include <asm/pci/bridge.h> |
26 | #include <asm/sn/ioc3.h> |
27 | |
28 | #define IOC3_IRQ_SERIAL_A 6 |
29 | #define IOC3_IRQ_SERIAL_B 15 |
30 | #define IOC3_IRQ_KBD 22 |
31 | |
32 | /* Bitmask for selecting which IRQs are level triggered */ |
33 | #define IOC3_LVL_MASK (BIT(IOC3_IRQ_SERIAL_A) | BIT(IOC3_IRQ_SERIAL_B)) |
34 | |
35 | #define M48T35_REG_SIZE 32768 /* size of m48t35 registers */ |
36 | |
37 | /* 1.2 us latency timer (40 cycles at 33 MHz) */ |
38 | #define IOC3_LATENCY 40 |
39 | |
40 | struct ioc3_priv_data { |
41 | struct irq_domain *domain; |
42 | struct ioc3 __iomem *regs; |
43 | struct pci_dev *pdev; |
44 | int domain_irq; |
45 | }; |
46 | |
47 | static void ioc3_irq_ack(struct irq_data *d) |
48 | { |
49 | struct ioc3_priv_data *ipd = irq_data_get_irq_chip_data(d); |
50 | unsigned int hwirq = irqd_to_hwirq(d); |
51 | |
52 | writel(BIT(hwirq), addr: &ipd->regs->sio_ir); |
53 | } |
54 | |
55 | static void ioc3_irq_mask(struct irq_data *d) |
56 | { |
57 | struct ioc3_priv_data *ipd = irq_data_get_irq_chip_data(d); |
58 | unsigned int hwirq = irqd_to_hwirq(d); |
59 | |
60 | writel(BIT(hwirq), addr: &ipd->regs->sio_iec); |
61 | } |
62 | |
63 | static void ioc3_irq_unmask(struct irq_data *d) |
64 | { |
65 | struct ioc3_priv_data *ipd = irq_data_get_irq_chip_data(d); |
66 | unsigned int hwirq = irqd_to_hwirq(d); |
67 | |
68 | writel(BIT(hwirq), addr: &ipd->regs->sio_ies); |
69 | } |
70 | |
71 | static struct irq_chip ioc3_irq_chip = { |
72 | .name = "IOC3" , |
73 | .irq_ack = ioc3_irq_ack, |
74 | .irq_mask = ioc3_irq_mask, |
75 | .irq_unmask = ioc3_irq_unmask, |
76 | }; |
77 | |
78 | static int ioc3_irq_domain_map(struct irq_domain *d, unsigned int irq, |
79 | irq_hw_number_t hwirq) |
80 | { |
81 | /* Set level IRQs for every interrupt contained in IOC3_LVL_MASK */ |
82 | if (BIT(hwirq) & IOC3_LVL_MASK) |
83 | irq_set_chip_and_handler(irq, &ioc3_irq_chip, handle_level_irq); |
84 | else |
85 | irq_set_chip_and_handler(irq, &ioc3_irq_chip, handle_edge_irq); |
86 | |
87 | irq_set_chip_data(irq, d->host_data); |
88 | return 0; |
89 | } |
90 | |
91 | static void ioc3_irq_domain_unmap(struct irq_domain *d, unsigned int irq) |
92 | { |
93 | irq_set_chip_and_handler(irq, NULL, NULL); |
94 | irq_set_chip_data(irq, NULL); |
95 | } |
96 | |
97 | static const struct irq_domain_ops ioc3_irq_domain_ops = { |
98 | .map = ioc3_irq_domain_map, |
99 | .unmap = ioc3_irq_domain_unmap, |
100 | }; |
101 | |
102 | static void ioc3_irq_handler(struct irq_desc *desc) |
103 | { |
104 | struct irq_domain *domain = irq_desc_get_handler_data(desc); |
105 | struct ioc3_priv_data *ipd = domain->host_data; |
106 | struct ioc3 __iomem *regs = ipd->regs; |
107 | u32 pending, mask; |
108 | |
109 | pending = readl(addr: ®s->sio_ir); |
110 | mask = readl(addr: ®s->sio_ies); |
111 | pending &= mask; /* Mask off not enabled interrupts */ |
112 | |
113 | if (pending) |
114 | generic_handle_domain_irq(domain, __ffs(pending)); |
115 | else |
116 | spurious_interrupt(); |
117 | } |
118 | |
119 | /* |
120 | * System boards/BaseIOs use more interrupt pins of the bridge ASIC |
121 | * to which the IOC3 is connected. Since the IOC3 MFD driver |
122 | * knows wiring of these extra pins, we use the map_irq function |
123 | * to get interrupts activated |
124 | */ |
125 | static int ioc3_map_irq(struct pci_dev *pdev, int slot, int pin) |
126 | { |
127 | struct pci_host_bridge *hbrg = pci_find_host_bridge(bus: pdev->bus); |
128 | |
129 | return hbrg->map_irq(pdev, slot, pin); |
130 | } |
131 | |
132 | static int ioc3_irq_domain_setup(struct ioc3_priv_data *ipd, int irq) |
133 | { |
134 | struct irq_domain *domain; |
135 | struct fwnode_handle *fn; |
136 | |
137 | fn = irq_domain_alloc_named_fwnode(name: "IOC3" ); |
138 | if (!fn) |
139 | goto err; |
140 | |
141 | domain = irq_domain_create_linear(fwnode: fn, size: 24, ops: &ioc3_irq_domain_ops, host_data: ipd); |
142 | if (!domain) { |
143 | irq_domain_free_fwnode(fwnode: fn); |
144 | goto err; |
145 | } |
146 | |
147 | ipd->domain = domain; |
148 | |
149 | irq_set_chained_handler_and_data(irq, ioc3_irq_handler, domain); |
150 | ipd->domain_irq = irq; |
151 | return 0; |
152 | |
153 | err: |
154 | dev_err(&ipd->pdev->dev, "irq domain setup failed\n" ); |
155 | return -ENOMEM; |
156 | } |
157 | |
158 | static const struct resource ioc3_uarta_resources[] = { |
159 | DEFINE_RES_MEM(offsetof(struct ioc3, sregs.uarta), |
160 | sizeof_field(struct ioc3, sregs.uarta)), |
161 | DEFINE_RES_IRQ(IOC3_IRQ_SERIAL_A) |
162 | }; |
163 | |
164 | static const struct resource ioc3_uartb_resources[] = { |
165 | DEFINE_RES_MEM(offsetof(struct ioc3, sregs.uartb), |
166 | sizeof_field(struct ioc3, sregs.uartb)), |
167 | DEFINE_RES_IRQ(IOC3_IRQ_SERIAL_B) |
168 | }; |
169 | |
170 | static struct mfd_cell ioc3_serial_cells[] = { |
171 | { |
172 | .name = "ioc3-serial8250" , |
173 | .resources = ioc3_uarta_resources, |
174 | .num_resources = ARRAY_SIZE(ioc3_uarta_resources), |
175 | }, |
176 | { |
177 | .name = "ioc3-serial8250" , |
178 | .resources = ioc3_uartb_resources, |
179 | .num_resources = ARRAY_SIZE(ioc3_uartb_resources), |
180 | } |
181 | }; |
182 | |
183 | static int ioc3_serial_setup(struct ioc3_priv_data *ipd) |
184 | { |
185 | int ret; |
186 | |
187 | /* Set gpio pins for RS232/RS422 mode selection */ |
188 | writel(val: GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL, |
189 | addr: &ipd->regs->gpcr_s); |
190 | /* Select RS232 mode for uart a */ |
191 | writel(val: 0, addr: &ipd->regs->gppr[6]); |
192 | /* Select RS232 mode for uart b */ |
193 | writel(val: 0, addr: &ipd->regs->gppr[7]); |
194 | |
195 | /* Switch both ports to 16650 mode */ |
196 | writel(readl(addr: &ipd->regs->port_a.sscr) & ~SSCR_DMA_EN, |
197 | addr: &ipd->regs->port_a.sscr); |
198 | writel(readl(addr: &ipd->regs->port_b.sscr) & ~SSCR_DMA_EN, |
199 | addr: &ipd->regs->port_b.sscr); |
200 | udelay(1000); /* Wait until mode switch is done */ |
201 | |
202 | ret = mfd_add_devices(&ipd->pdev->dev, PLATFORM_DEVID_AUTO, |
203 | ioc3_serial_cells, ARRAY_SIZE(ioc3_serial_cells), |
204 | &ipd->pdev->resource[0], 0, ipd->domain); |
205 | if (ret) { |
206 | dev_err(&ipd->pdev->dev, "Failed to add 16550 subdevs\n" ); |
207 | return ret; |
208 | } |
209 | |
210 | return 0; |
211 | } |
212 | |
213 | static const struct resource ioc3_kbd_resources[] = { |
214 | DEFINE_RES_MEM(offsetof(struct ioc3, serio), |
215 | sizeof_field(struct ioc3, serio)), |
216 | DEFINE_RES_IRQ(IOC3_IRQ_KBD) |
217 | }; |
218 | |
219 | static struct mfd_cell ioc3_kbd_cells[] = { |
220 | { |
221 | .name = "ioc3-kbd" , |
222 | .resources = ioc3_kbd_resources, |
223 | .num_resources = ARRAY_SIZE(ioc3_kbd_resources), |
224 | } |
225 | }; |
226 | |
227 | static int ioc3_kbd_setup(struct ioc3_priv_data *ipd) |
228 | { |
229 | int ret; |
230 | |
231 | ret = mfd_add_devices(&ipd->pdev->dev, PLATFORM_DEVID_AUTO, |
232 | ioc3_kbd_cells, ARRAY_SIZE(ioc3_kbd_cells), |
233 | &ipd->pdev->resource[0], 0, ipd->domain); |
234 | if (ret) { |
235 | dev_err(&ipd->pdev->dev, "Failed to add 16550 subdevs\n" ); |
236 | return ret; |
237 | } |
238 | |
239 | return 0; |
240 | } |
241 | |
242 | static const struct resource ioc3_eth_resources[] = { |
243 | DEFINE_RES_MEM(offsetof(struct ioc3, eth), |
244 | sizeof_field(struct ioc3, eth)), |
245 | DEFINE_RES_MEM(offsetof(struct ioc3, ssram), |
246 | sizeof_field(struct ioc3, ssram)), |
247 | DEFINE_RES_IRQ(0) |
248 | }; |
249 | |
250 | static const struct resource ioc3_w1_resources[] = { |
251 | DEFINE_RES_MEM(offsetof(struct ioc3, mcr), |
252 | sizeof_field(struct ioc3, mcr)), |
253 | }; |
254 | static struct sgi_w1_platform_data ioc3_w1_platform_data; |
255 | |
256 | static struct mfd_cell ioc3_eth_cells[] = { |
257 | { |
258 | .name = "ioc3-eth" , |
259 | .resources = ioc3_eth_resources, |
260 | .num_resources = ARRAY_SIZE(ioc3_eth_resources), |
261 | }, |
262 | { |
263 | .name = "sgi_w1" , |
264 | .resources = ioc3_w1_resources, |
265 | .num_resources = ARRAY_SIZE(ioc3_w1_resources), |
266 | .platform_data = &ioc3_w1_platform_data, |
267 | .pdata_size = sizeof(ioc3_w1_platform_data), |
268 | } |
269 | }; |
270 | |
271 | static int ioc3_eth_setup(struct ioc3_priv_data *ipd) |
272 | { |
273 | int ret; |
274 | |
275 | /* Enable One-Wire bus */ |
276 | writel(val: GPCR_MLAN_EN, addr: &ipd->regs->gpcr_s); |
277 | |
278 | /* Generate unique identifier */ |
279 | snprintf(buf: ioc3_w1_platform_data.dev_id, |
280 | size: sizeof(ioc3_w1_platform_data.dev_id), fmt: "ioc3-%012llx" , |
281 | ipd->pdev->resource->start); |
282 | |
283 | ret = mfd_add_devices(&ipd->pdev->dev, PLATFORM_DEVID_AUTO, |
284 | ioc3_eth_cells, ARRAY_SIZE(ioc3_eth_cells), |
285 | &ipd->pdev->resource[0], ipd->pdev->irq, NULL); |
286 | if (ret) { |
287 | dev_err(&ipd->pdev->dev, "Failed to add ETH/W1 subdev\n" ); |
288 | return ret; |
289 | } |
290 | |
291 | return 0; |
292 | } |
293 | |
294 | static const struct resource ioc3_m48t35_resources[] = { |
295 | DEFINE_RES_MEM(IOC3_BYTEBUS_DEV0, M48T35_REG_SIZE) |
296 | }; |
297 | |
298 | static struct mfd_cell ioc3_m48t35_cells[] = { |
299 | { |
300 | .name = "rtc-m48t35" , |
301 | .resources = ioc3_m48t35_resources, |
302 | .num_resources = ARRAY_SIZE(ioc3_m48t35_resources), |
303 | } |
304 | }; |
305 | |
306 | static int ioc3_m48t35_setup(struct ioc3_priv_data *ipd) |
307 | { |
308 | int ret; |
309 | |
310 | ret = mfd_add_devices(&ipd->pdev->dev, PLATFORM_DEVID_AUTO, |
311 | ioc3_m48t35_cells, ARRAY_SIZE(ioc3_m48t35_cells), |
312 | &ipd->pdev->resource[0], 0, ipd->domain); |
313 | if (ret) |
314 | dev_err(&ipd->pdev->dev, "Failed to add M48T35 subdev\n" ); |
315 | |
316 | return ret; |
317 | } |
318 | |
319 | static struct ds1685_rtc_platform_data ip30_rtc_platform_data = { |
320 | .bcd_mode = false, |
321 | .no_irq = false, |
322 | .uie_unsupported = true, |
323 | .access_type = ds1685_reg_indirect, |
324 | }; |
325 | |
326 | static const struct resource ioc3_rtc_ds1685_resources[] = { |
327 | DEFINE_RES_MEM(IOC3_BYTEBUS_DEV1, 1), |
328 | DEFINE_RES_MEM(IOC3_BYTEBUS_DEV2, 1), |
329 | DEFINE_RES_IRQ(0) |
330 | }; |
331 | |
332 | static struct mfd_cell ioc3_ds1685_cells[] = { |
333 | { |
334 | .name = "rtc-ds1685" , |
335 | .resources = ioc3_rtc_ds1685_resources, |
336 | .num_resources = ARRAY_SIZE(ioc3_rtc_ds1685_resources), |
337 | .platform_data = &ip30_rtc_platform_data, |
338 | .pdata_size = sizeof(ip30_rtc_platform_data), |
339 | .id = PLATFORM_DEVID_NONE, |
340 | } |
341 | }; |
342 | |
343 | static int ioc3_ds1685_setup(struct ioc3_priv_data *ipd) |
344 | { |
345 | int ret, irq; |
346 | |
347 | irq = ioc3_map_irq(pdev: ipd->pdev, slot: 6, pin: 0); |
348 | |
349 | ret = mfd_add_devices(&ipd->pdev->dev, 0, ioc3_ds1685_cells, |
350 | ARRAY_SIZE(ioc3_ds1685_cells), |
351 | &ipd->pdev->resource[0], irq, NULL); |
352 | if (ret) |
353 | dev_err(&ipd->pdev->dev, "Failed to add DS1685 subdev\n" ); |
354 | |
355 | return ret; |
356 | }; |
357 | |
358 | |
359 | static const struct resource ioc3_leds_resources[] = { |
360 | DEFINE_RES_MEM(offsetof(struct ioc3, gppr[0]), |
361 | sizeof_field(struct ioc3, gppr[0])), |
362 | DEFINE_RES_MEM(offsetof(struct ioc3, gppr[1]), |
363 | sizeof_field(struct ioc3, gppr[1])), |
364 | }; |
365 | |
366 | static struct mfd_cell ioc3_led_cells[] = { |
367 | { |
368 | .name = "ip30-leds" , |
369 | .resources = ioc3_leds_resources, |
370 | .num_resources = ARRAY_SIZE(ioc3_leds_resources), |
371 | .id = PLATFORM_DEVID_NONE, |
372 | } |
373 | }; |
374 | |
375 | static int ioc3_led_setup(struct ioc3_priv_data *ipd) |
376 | { |
377 | int ret; |
378 | |
379 | ret = mfd_add_devices(&ipd->pdev->dev, 0, ioc3_led_cells, |
380 | ARRAY_SIZE(ioc3_led_cells), |
381 | &ipd->pdev->resource[0], 0, ipd->domain); |
382 | if (ret) |
383 | dev_err(&ipd->pdev->dev, "Failed to add LED subdev\n" ); |
384 | |
385 | return ret; |
386 | } |
387 | |
388 | static int ip27_baseio_setup(struct ioc3_priv_data *ipd) |
389 | { |
390 | int ret, io_irq; |
391 | |
392 | io_irq = ioc3_map_irq(pdev: ipd->pdev, PCI_SLOT(ipd->pdev->devfn), |
393 | pin: PCI_INTERRUPT_INTB); |
394 | ret = ioc3_irq_domain_setup(ipd, irq: io_irq); |
395 | if (ret) |
396 | return ret; |
397 | |
398 | ret = ioc3_eth_setup(ipd); |
399 | if (ret) |
400 | return ret; |
401 | |
402 | ret = ioc3_serial_setup(ipd); |
403 | if (ret) |
404 | return ret; |
405 | |
406 | return ioc3_m48t35_setup(ipd); |
407 | } |
408 | |
409 | static int ip27_baseio6g_setup(struct ioc3_priv_data *ipd) |
410 | { |
411 | int ret, io_irq; |
412 | |
413 | io_irq = ioc3_map_irq(pdev: ipd->pdev, PCI_SLOT(ipd->pdev->devfn), |
414 | pin: PCI_INTERRUPT_INTB); |
415 | ret = ioc3_irq_domain_setup(ipd, irq: io_irq); |
416 | if (ret) |
417 | return ret; |
418 | |
419 | ret = ioc3_eth_setup(ipd); |
420 | if (ret) |
421 | return ret; |
422 | |
423 | ret = ioc3_serial_setup(ipd); |
424 | if (ret) |
425 | return ret; |
426 | |
427 | ret = ioc3_m48t35_setup(ipd); |
428 | if (ret) |
429 | return ret; |
430 | |
431 | return ioc3_kbd_setup(ipd); |
432 | } |
433 | |
434 | static int ip27_mio_setup(struct ioc3_priv_data *ipd) |
435 | { |
436 | int ret; |
437 | |
438 | ret = ioc3_irq_domain_setup(ipd, irq: ipd->pdev->irq); |
439 | if (ret) |
440 | return ret; |
441 | |
442 | ret = ioc3_serial_setup(ipd); |
443 | if (ret) |
444 | return ret; |
445 | |
446 | return ioc3_kbd_setup(ipd); |
447 | } |
448 | |
449 | static int ip30_sysboard_setup(struct ioc3_priv_data *ipd) |
450 | { |
451 | int ret, io_irq; |
452 | |
453 | io_irq = ioc3_map_irq(pdev: ipd->pdev, PCI_SLOT(ipd->pdev->devfn), |
454 | pin: PCI_INTERRUPT_INTB); |
455 | ret = ioc3_irq_domain_setup(ipd, irq: io_irq); |
456 | if (ret) |
457 | return ret; |
458 | |
459 | ret = ioc3_eth_setup(ipd); |
460 | if (ret) |
461 | return ret; |
462 | |
463 | ret = ioc3_serial_setup(ipd); |
464 | if (ret) |
465 | return ret; |
466 | |
467 | ret = ioc3_kbd_setup(ipd); |
468 | if (ret) |
469 | return ret; |
470 | |
471 | ret = ioc3_ds1685_setup(ipd); |
472 | if (ret) |
473 | return ret; |
474 | |
475 | return ioc3_led_setup(ipd); |
476 | } |
477 | |
478 | static int ioc3_menet_setup(struct ioc3_priv_data *ipd) |
479 | { |
480 | int ret, io_irq; |
481 | |
482 | io_irq = ioc3_map_irq(pdev: ipd->pdev, PCI_SLOT(ipd->pdev->devfn), |
483 | pin: PCI_INTERRUPT_INTB); |
484 | ret = ioc3_irq_domain_setup(ipd, irq: io_irq); |
485 | if (ret) |
486 | return ret; |
487 | |
488 | ret = ioc3_eth_setup(ipd); |
489 | if (ret) |
490 | return ret; |
491 | |
492 | return ioc3_serial_setup(ipd); |
493 | } |
494 | |
495 | static int ioc3_menet4_setup(struct ioc3_priv_data *ipd) |
496 | { |
497 | return ioc3_eth_setup(ipd); |
498 | } |
499 | |
500 | static int ioc3_cad_duo_setup(struct ioc3_priv_data *ipd) |
501 | { |
502 | int ret, io_irq; |
503 | |
504 | io_irq = ioc3_map_irq(pdev: ipd->pdev, PCI_SLOT(ipd->pdev->devfn), |
505 | pin: PCI_INTERRUPT_INTB); |
506 | ret = ioc3_irq_domain_setup(ipd, irq: io_irq); |
507 | if (ret) |
508 | return ret; |
509 | |
510 | ret = ioc3_eth_setup(ipd); |
511 | if (ret) |
512 | return ret; |
513 | |
514 | return ioc3_kbd_setup(ipd); |
515 | } |
516 | |
517 | /* Helper macro for filling ioc3_info array */ |
518 | #define IOC3_SID(_name, _sid, _setup) \ |
519 | { \ |
520 | .name = _name, \ |
521 | .sid = PCI_VENDOR_ID_SGI | (IOC3_SUBSYS_ ## _sid << 16), \ |
522 | .setup = _setup, \ |
523 | } |
524 | |
525 | static struct { |
526 | const char *name; |
527 | u32 sid; |
528 | int (*setup)(struct ioc3_priv_data *ipd); |
529 | } ioc3_infos[] = { |
530 | IOC3_SID("IP27 BaseIO6G" , IP27_BASEIO6G, &ip27_baseio6g_setup), |
531 | IOC3_SID("IP27 MIO" , IP27_MIO, &ip27_mio_setup), |
532 | IOC3_SID("IP27 BaseIO" , IP27_BASEIO, &ip27_baseio_setup), |
533 | IOC3_SID("IP29 System Board" , IP29_SYSBOARD, &ip27_baseio6g_setup), |
534 | IOC3_SID("IP30 System Board" , IP30_SYSBOARD, &ip30_sysboard_setup), |
535 | IOC3_SID("MENET" , MENET, &ioc3_menet_setup), |
536 | IOC3_SID("MENET4" , MENET4, &ioc3_menet4_setup) |
537 | }; |
538 | #undef IOC3_SID |
539 | |
540 | static int ioc3_setup(struct ioc3_priv_data *ipd) |
541 | { |
542 | u32 sid; |
543 | int i; |
544 | |
545 | /* Clear IRQs */ |
546 | writel(val: ~0, addr: &ipd->regs->sio_iec); |
547 | writel(val: ~0, addr: &ipd->regs->sio_ir); |
548 | writel(val: 0, addr: &ipd->regs->eth.eier); |
549 | writel(val: ~0, addr: &ipd->regs->eth.eisr); |
550 | |
551 | /* Read subsystem vendor id and subsystem id */ |
552 | pci_read_config_dword(dev: ipd->pdev, PCI_SUBSYSTEM_VENDOR_ID, val: &sid); |
553 | |
554 | for (i = 0; i < ARRAY_SIZE(ioc3_infos); i++) |
555 | if (sid == ioc3_infos[i].sid) { |
556 | pr_info("ioc3: %s\n" , ioc3_infos[i].name); |
557 | return ioc3_infos[i].setup(ipd); |
558 | } |
559 | |
560 | /* Treat everything not identified by PCI subid as CAD DUO */ |
561 | pr_info("ioc3: CAD DUO\n" ); |
562 | return ioc3_cad_duo_setup(ipd); |
563 | } |
564 | |
565 | static int ioc3_mfd_probe(struct pci_dev *pdev, |
566 | const struct pci_device_id *pci_id) |
567 | { |
568 | struct ioc3_priv_data *ipd; |
569 | struct ioc3 __iomem *regs; |
570 | int ret; |
571 | |
572 | ret = pci_enable_device(dev: pdev); |
573 | if (ret) |
574 | return ret; |
575 | |
576 | pci_write_config_byte(dev: pdev, PCI_LATENCY_TIMER, IOC3_LATENCY); |
577 | pci_set_master(dev: pdev); |
578 | |
579 | ret = dma_set_mask_and_coherent(dev: &pdev->dev, DMA_BIT_MASK(64)); |
580 | if (ret) { |
581 | pr_err("%s: No usable DMA configuration, aborting.\n" , |
582 | pci_name(pdev)); |
583 | goto out_disable_device; |
584 | } |
585 | |
586 | /* Set up per-IOC3 data */ |
587 | ipd = devm_kzalloc(dev: &pdev->dev, size: sizeof(struct ioc3_priv_data), |
588 | GFP_KERNEL); |
589 | if (!ipd) { |
590 | ret = -ENOMEM; |
591 | goto out_disable_device; |
592 | } |
593 | ipd->pdev = pdev; |
594 | |
595 | /* |
596 | * Map all IOC3 registers. These are shared between subdevices |
597 | * so the main IOC3 module manages them. |
598 | */ |
599 | regs = pci_ioremap_bar(pdev, bar: 0); |
600 | if (!regs) { |
601 | dev_warn(&pdev->dev, "ioc3: Unable to remap PCI BAR for %s.\n" , |
602 | pci_name(pdev)); |
603 | ret = -ENOMEM; |
604 | goto out_disable_device; |
605 | } |
606 | ipd->regs = regs; |
607 | |
608 | /* Track PCI-device specific data */ |
609 | pci_set_drvdata(pdev, data: ipd); |
610 | |
611 | ret = ioc3_setup(ipd); |
612 | if (ret) { |
613 | /* Remove all already added MFD devices */ |
614 | mfd_remove_devices(parent: &ipd->pdev->dev); |
615 | if (ipd->domain) { |
616 | struct fwnode_handle *fn = ipd->domain->fwnode; |
617 | |
618 | irq_domain_remove(host: ipd->domain); |
619 | irq_domain_free_fwnode(fwnode: fn); |
620 | free_irq(ipd->domain_irq, (void *)ipd); |
621 | } |
622 | pci_iounmap(dev: pdev, regs); |
623 | goto out_disable_device; |
624 | } |
625 | |
626 | return 0; |
627 | |
628 | out_disable_device: |
629 | pci_disable_device(dev: pdev); |
630 | return ret; |
631 | } |
632 | |
633 | static void ioc3_mfd_remove(struct pci_dev *pdev) |
634 | { |
635 | struct ioc3_priv_data *ipd; |
636 | |
637 | ipd = pci_get_drvdata(pdev); |
638 | |
639 | /* Clear and disable all IRQs */ |
640 | writel(val: ~0, addr: &ipd->regs->sio_iec); |
641 | writel(val: ~0, addr: &ipd->regs->sio_ir); |
642 | |
643 | /* Release resources */ |
644 | mfd_remove_devices(parent: &ipd->pdev->dev); |
645 | if (ipd->domain) { |
646 | struct fwnode_handle *fn = ipd->domain->fwnode; |
647 | |
648 | irq_domain_remove(host: ipd->domain); |
649 | irq_domain_free_fwnode(fwnode: fn); |
650 | free_irq(ipd->domain_irq, (void *)ipd); |
651 | } |
652 | pci_iounmap(dev: pdev, ipd->regs); |
653 | pci_disable_device(dev: pdev); |
654 | } |
655 | |
656 | static struct pci_device_id ioc3_mfd_id_table[] = { |
657 | { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, PCI_ANY_ID, PCI_ANY_ID }, |
658 | { 0, }, |
659 | }; |
660 | MODULE_DEVICE_TABLE(pci, ioc3_mfd_id_table); |
661 | |
662 | static struct pci_driver ioc3_mfd_driver = { |
663 | .name = "IOC3" , |
664 | .id_table = ioc3_mfd_id_table, |
665 | .probe = ioc3_mfd_probe, |
666 | .remove = ioc3_mfd_remove, |
667 | }; |
668 | |
669 | module_pci_driver(ioc3_mfd_driver); |
670 | |
671 | MODULE_AUTHOR("Thomas Bogendoerfer <tbogendoerfer@suse.de>" ); |
672 | MODULE_DESCRIPTION("SGI IOC3 MFD driver" ); |
673 | MODULE_LICENSE("GPL v2" ); |
674 | |