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