xref: /linux/drivers/ipack/carriers/tpci200.c (revision 05e5027efc9c0bb6d1d04cde279afbafca0a7929)
1*05e5027eSGreg Kroah-Hartman /**
2*05e5027eSGreg Kroah-Hartman  * tpci200.c
3*05e5027eSGreg Kroah-Hartman  *
4*05e5027eSGreg Kroah-Hartman  * driver for the TEWS TPCI-200 device
5*05e5027eSGreg Kroah-Hartman  *
6*05e5027eSGreg Kroah-Hartman  * Copyright (C) 2009-2012 CERN (www.cern.ch)
7*05e5027eSGreg Kroah-Hartman  * Author: Nicolas Serafini, EIC2 SA
8*05e5027eSGreg Kroah-Hartman  * Author: Samuel Iglesias Gonsalvez <siglesias@igalia.com>
9*05e5027eSGreg Kroah-Hartman  *
10*05e5027eSGreg Kroah-Hartman  * This program is free software; you can redistribute it and/or modify it
11*05e5027eSGreg Kroah-Hartman  * under the terms of the GNU General Public License as published by the Free
12*05e5027eSGreg Kroah-Hartman  * Software Foundation; version 2 of the License.
13*05e5027eSGreg Kroah-Hartman  */
14*05e5027eSGreg Kroah-Hartman 
15*05e5027eSGreg Kroah-Hartman #include <linux/module.h>
16*05e5027eSGreg Kroah-Hartman #include <linux/slab.h>
17*05e5027eSGreg Kroah-Hartman #include "tpci200.h"
18*05e5027eSGreg Kroah-Hartman 
19*05e5027eSGreg Kroah-Hartman static const u16 tpci200_status_timeout[] = {
20*05e5027eSGreg Kroah-Hartman 	TPCI200_A_TIMEOUT,
21*05e5027eSGreg Kroah-Hartman 	TPCI200_B_TIMEOUT,
22*05e5027eSGreg Kroah-Hartman 	TPCI200_C_TIMEOUT,
23*05e5027eSGreg Kroah-Hartman 	TPCI200_D_TIMEOUT,
24*05e5027eSGreg Kroah-Hartman };
25*05e5027eSGreg Kroah-Hartman 
26*05e5027eSGreg Kroah-Hartman static const u16 tpci200_status_error[] = {
27*05e5027eSGreg Kroah-Hartman 	TPCI200_A_ERROR,
28*05e5027eSGreg Kroah-Hartman 	TPCI200_B_ERROR,
29*05e5027eSGreg Kroah-Hartman 	TPCI200_C_ERROR,
30*05e5027eSGreg Kroah-Hartman 	TPCI200_D_ERROR,
31*05e5027eSGreg Kroah-Hartman };
32*05e5027eSGreg Kroah-Hartman 
33*05e5027eSGreg Kroah-Hartman static const size_t tpci200_space_size[IPACK_SPACE_COUNT] = {
34*05e5027eSGreg Kroah-Hartman 	[IPACK_IO_SPACE]    = TPCI200_IO_SPACE_SIZE,
35*05e5027eSGreg Kroah-Hartman 	[IPACK_ID_SPACE]    = TPCI200_ID_SPACE_SIZE,
36*05e5027eSGreg Kroah-Hartman 	[IPACK_INT_SPACE]   = TPCI200_INT_SPACE_SIZE,
37*05e5027eSGreg Kroah-Hartman 	[IPACK_MEM8_SPACE]  = TPCI200_MEM8_SPACE_SIZE,
38*05e5027eSGreg Kroah-Hartman 	[IPACK_MEM16_SPACE] = TPCI200_MEM16_SPACE_SIZE,
39*05e5027eSGreg Kroah-Hartman };
40*05e5027eSGreg Kroah-Hartman 
41*05e5027eSGreg Kroah-Hartman static const size_t tpci200_space_interval[IPACK_SPACE_COUNT] = {
42*05e5027eSGreg Kroah-Hartman 	[IPACK_IO_SPACE]    = TPCI200_IO_SPACE_INTERVAL,
43*05e5027eSGreg Kroah-Hartman 	[IPACK_ID_SPACE]    = TPCI200_ID_SPACE_INTERVAL,
44*05e5027eSGreg Kroah-Hartman 	[IPACK_INT_SPACE]   = TPCI200_INT_SPACE_INTERVAL,
45*05e5027eSGreg Kroah-Hartman 	[IPACK_MEM8_SPACE]  = TPCI200_MEM8_SPACE_INTERVAL,
46*05e5027eSGreg Kroah-Hartman 	[IPACK_MEM16_SPACE] = TPCI200_MEM16_SPACE_INTERVAL,
47*05e5027eSGreg Kroah-Hartman };
48*05e5027eSGreg Kroah-Hartman 
49*05e5027eSGreg Kroah-Hartman static struct tpci200_board *check_slot(struct ipack_device *dev)
50*05e5027eSGreg Kroah-Hartman {
51*05e5027eSGreg Kroah-Hartman 	struct tpci200_board *tpci200;
52*05e5027eSGreg Kroah-Hartman 
53*05e5027eSGreg Kroah-Hartman 	if (dev == NULL)
54*05e5027eSGreg Kroah-Hartman 		return NULL;
55*05e5027eSGreg Kroah-Hartman 
56*05e5027eSGreg Kroah-Hartman 
57*05e5027eSGreg Kroah-Hartman 	tpci200 = dev_get_drvdata(dev->bus->parent);
58*05e5027eSGreg Kroah-Hartman 
59*05e5027eSGreg Kroah-Hartman 	if (tpci200 == NULL) {
60*05e5027eSGreg Kroah-Hartman 		dev_info(&dev->dev, "carrier board not found\n");
61*05e5027eSGreg Kroah-Hartman 		return NULL;
62*05e5027eSGreg Kroah-Hartman 	}
63*05e5027eSGreg Kroah-Hartman 
64*05e5027eSGreg Kroah-Hartman 	if (dev->slot >= TPCI200_NB_SLOT) {
65*05e5027eSGreg Kroah-Hartman 		dev_info(&dev->dev,
66*05e5027eSGreg Kroah-Hartman 			 "Slot [%d:%d] doesn't exist! Last tpci200 slot is %d.\n",
67*05e5027eSGreg Kroah-Hartman 			 dev->bus->bus_nr, dev->slot, TPCI200_NB_SLOT-1);
68*05e5027eSGreg Kroah-Hartman 		return NULL;
69*05e5027eSGreg Kroah-Hartman 	}
70*05e5027eSGreg Kroah-Hartman 
71*05e5027eSGreg Kroah-Hartman 	return tpci200;
72*05e5027eSGreg Kroah-Hartman }
73*05e5027eSGreg Kroah-Hartman 
74*05e5027eSGreg Kroah-Hartman static void tpci200_clear_mask(struct tpci200_board *tpci200,
75*05e5027eSGreg Kroah-Hartman 			       __le16 __iomem *addr, u16 mask)
76*05e5027eSGreg Kroah-Hartman {
77*05e5027eSGreg Kroah-Hartman 	unsigned long flags;
78*05e5027eSGreg Kroah-Hartman 	spin_lock_irqsave(&tpci200->regs_lock, flags);
79*05e5027eSGreg Kroah-Hartman 	iowrite16(ioread16(addr) & (~mask), addr);
80*05e5027eSGreg Kroah-Hartman 	spin_unlock_irqrestore(&tpci200->regs_lock, flags);
81*05e5027eSGreg Kroah-Hartman }
82*05e5027eSGreg Kroah-Hartman 
83*05e5027eSGreg Kroah-Hartman static void tpci200_set_mask(struct tpci200_board *tpci200,
84*05e5027eSGreg Kroah-Hartman 			     __le16 __iomem *addr, u16 mask)
85*05e5027eSGreg Kroah-Hartman {
86*05e5027eSGreg Kroah-Hartman 	unsigned long flags;
87*05e5027eSGreg Kroah-Hartman 	spin_lock_irqsave(&tpci200->regs_lock, flags);
88*05e5027eSGreg Kroah-Hartman 	iowrite16(ioread16(addr) | mask, addr);
89*05e5027eSGreg Kroah-Hartman 	spin_unlock_irqrestore(&tpci200->regs_lock, flags);
90*05e5027eSGreg Kroah-Hartman }
91*05e5027eSGreg Kroah-Hartman 
92*05e5027eSGreg Kroah-Hartman static void tpci200_unregister(struct tpci200_board *tpci200)
93*05e5027eSGreg Kroah-Hartman {
94*05e5027eSGreg Kroah-Hartman 	free_irq(tpci200->info->pdev->irq, (void *) tpci200);
95*05e5027eSGreg Kroah-Hartman 
96*05e5027eSGreg Kroah-Hartman 	pci_iounmap(tpci200->info->pdev, tpci200->info->interface_regs);
97*05e5027eSGreg Kroah-Hartman 	pci_iounmap(tpci200->info->pdev, tpci200->info->cfg_regs);
98*05e5027eSGreg Kroah-Hartman 
99*05e5027eSGreg Kroah-Hartman 	pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR);
100*05e5027eSGreg Kroah-Hartman 	pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR);
101*05e5027eSGreg Kroah-Hartman 	pci_release_region(tpci200->info->pdev, TPCI200_MEM16_SPACE_BAR);
102*05e5027eSGreg Kroah-Hartman 	pci_release_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR);
103*05e5027eSGreg Kroah-Hartman 	pci_release_region(tpci200->info->pdev, TPCI200_CFG_MEM_BAR);
104*05e5027eSGreg Kroah-Hartman 
105*05e5027eSGreg Kroah-Hartman 	pci_disable_device(tpci200->info->pdev);
106*05e5027eSGreg Kroah-Hartman 	pci_dev_put(tpci200->info->pdev);
107*05e5027eSGreg Kroah-Hartman }
108*05e5027eSGreg Kroah-Hartman 
109*05e5027eSGreg Kroah-Hartman static void tpci200_enable_irq(struct tpci200_board *tpci200,
110*05e5027eSGreg Kroah-Hartman 			       int islot)
111*05e5027eSGreg Kroah-Hartman {
112*05e5027eSGreg Kroah-Hartman 	tpci200_set_mask(tpci200,
113*05e5027eSGreg Kroah-Hartman 			&tpci200->info->interface_regs->control[islot],
114*05e5027eSGreg Kroah-Hartman 			TPCI200_INT0_EN | TPCI200_INT1_EN);
115*05e5027eSGreg Kroah-Hartman }
116*05e5027eSGreg Kroah-Hartman 
117*05e5027eSGreg Kroah-Hartman static void tpci200_disable_irq(struct tpci200_board *tpci200,
118*05e5027eSGreg Kroah-Hartman 				int islot)
119*05e5027eSGreg Kroah-Hartman {
120*05e5027eSGreg Kroah-Hartman 	tpci200_clear_mask(tpci200,
121*05e5027eSGreg Kroah-Hartman 			&tpci200->info->interface_regs->control[islot],
122*05e5027eSGreg Kroah-Hartman 			TPCI200_INT0_EN | TPCI200_INT1_EN);
123*05e5027eSGreg Kroah-Hartman }
124*05e5027eSGreg Kroah-Hartman 
125*05e5027eSGreg Kroah-Hartman static irqreturn_t tpci200_slot_irq(struct slot_irq *slot_irq)
126*05e5027eSGreg Kroah-Hartman {
127*05e5027eSGreg Kroah-Hartman 	irqreturn_t ret;
128*05e5027eSGreg Kroah-Hartman 
129*05e5027eSGreg Kroah-Hartman 	if (!slot_irq)
130*05e5027eSGreg Kroah-Hartman 		return -ENODEV;
131*05e5027eSGreg Kroah-Hartman 	ret = slot_irq->handler(slot_irq->arg);
132*05e5027eSGreg Kroah-Hartman 
133*05e5027eSGreg Kroah-Hartman 	return ret;
134*05e5027eSGreg Kroah-Hartman }
135*05e5027eSGreg Kroah-Hartman 
136*05e5027eSGreg Kroah-Hartman static irqreturn_t tpci200_interrupt(int irq, void *dev_id)
137*05e5027eSGreg Kroah-Hartman {
138*05e5027eSGreg Kroah-Hartman 	struct tpci200_board *tpci200 = (struct tpci200_board *) dev_id;
139*05e5027eSGreg Kroah-Hartman 	struct slot_irq *slot_irq;
140*05e5027eSGreg Kroah-Hartman 	irqreturn_t ret;
141*05e5027eSGreg Kroah-Hartman 	u16 status_reg;
142*05e5027eSGreg Kroah-Hartman 	int i;
143*05e5027eSGreg Kroah-Hartman 
144*05e5027eSGreg Kroah-Hartman 	/* Read status register */
145*05e5027eSGreg Kroah-Hartman 	status_reg = ioread16(&tpci200->info->interface_regs->status);
146*05e5027eSGreg Kroah-Hartman 
147*05e5027eSGreg Kroah-Hartman 	/* Did we cause the interrupt? */
148*05e5027eSGreg Kroah-Hartman 	if (!(status_reg & TPCI200_SLOT_INT_MASK))
149*05e5027eSGreg Kroah-Hartman 		return IRQ_NONE;
150*05e5027eSGreg Kroah-Hartman 
151*05e5027eSGreg Kroah-Hartman 	/* callback to the IRQ handler for the corresponding slot */
152*05e5027eSGreg Kroah-Hartman 	rcu_read_lock();
153*05e5027eSGreg Kroah-Hartman 	for (i = 0; i < TPCI200_NB_SLOT; i++) {
154*05e5027eSGreg Kroah-Hartman 		if (!(status_reg & ((TPCI200_A_INT0 | TPCI200_A_INT1) << (2 * i))))
155*05e5027eSGreg Kroah-Hartman 			continue;
156*05e5027eSGreg Kroah-Hartman 		slot_irq = rcu_dereference(tpci200->slots[i].irq);
157*05e5027eSGreg Kroah-Hartman 		ret = tpci200_slot_irq(slot_irq);
158*05e5027eSGreg Kroah-Hartman 		if (ret == -ENODEV) {
159*05e5027eSGreg Kroah-Hartman 			dev_info(&tpci200->info->pdev->dev,
160*05e5027eSGreg Kroah-Hartman 				 "No registered ISR for slot [%d:%d]!. IRQ will be disabled.\n",
161*05e5027eSGreg Kroah-Hartman 				 tpci200->number, i);
162*05e5027eSGreg Kroah-Hartman 			tpci200_disable_irq(tpci200, i);
163*05e5027eSGreg Kroah-Hartman 		}
164*05e5027eSGreg Kroah-Hartman 	}
165*05e5027eSGreg Kroah-Hartman 	rcu_read_unlock();
166*05e5027eSGreg Kroah-Hartman 
167*05e5027eSGreg Kroah-Hartman 	return IRQ_HANDLED;
168*05e5027eSGreg Kroah-Hartman }
169*05e5027eSGreg Kroah-Hartman 
170*05e5027eSGreg Kroah-Hartman static int tpci200_free_irq(struct ipack_device *dev)
171*05e5027eSGreg Kroah-Hartman {
172*05e5027eSGreg Kroah-Hartman 	struct slot_irq *slot_irq;
173*05e5027eSGreg Kroah-Hartman 	struct tpci200_board *tpci200;
174*05e5027eSGreg Kroah-Hartman 
175*05e5027eSGreg Kroah-Hartman 	tpci200 = check_slot(dev);
176*05e5027eSGreg Kroah-Hartman 	if (tpci200 == NULL)
177*05e5027eSGreg Kroah-Hartman 		return -EINVAL;
178*05e5027eSGreg Kroah-Hartman 
179*05e5027eSGreg Kroah-Hartman 	if (mutex_lock_interruptible(&tpci200->mutex))
180*05e5027eSGreg Kroah-Hartman 		return -ERESTARTSYS;
181*05e5027eSGreg Kroah-Hartman 
182*05e5027eSGreg Kroah-Hartman 	if (tpci200->slots[dev->slot].irq == NULL) {
183*05e5027eSGreg Kroah-Hartman 		mutex_unlock(&tpci200->mutex);
184*05e5027eSGreg Kroah-Hartman 		return -EINVAL;
185*05e5027eSGreg Kroah-Hartman 	}
186*05e5027eSGreg Kroah-Hartman 
187*05e5027eSGreg Kroah-Hartman 	tpci200_disable_irq(tpci200, dev->slot);
188*05e5027eSGreg Kroah-Hartman 	slot_irq = tpci200->slots[dev->slot].irq;
189*05e5027eSGreg Kroah-Hartman 	/* uninstall handler */
190*05e5027eSGreg Kroah-Hartman 	RCU_INIT_POINTER(tpci200->slots[dev->slot].irq, NULL);
191*05e5027eSGreg Kroah-Hartman 	synchronize_rcu();
192*05e5027eSGreg Kroah-Hartman 	kfree(slot_irq);
193*05e5027eSGreg Kroah-Hartman 	mutex_unlock(&tpci200->mutex);
194*05e5027eSGreg Kroah-Hartman 	return 0;
195*05e5027eSGreg Kroah-Hartman }
196*05e5027eSGreg Kroah-Hartman 
197*05e5027eSGreg Kroah-Hartman static int tpci200_request_irq(struct ipack_device *dev,
198*05e5027eSGreg Kroah-Hartman 			       irqreturn_t (*handler)(void *), void *arg)
199*05e5027eSGreg Kroah-Hartman {
200*05e5027eSGreg Kroah-Hartman 	int res = 0;
201*05e5027eSGreg Kroah-Hartman 	struct slot_irq *slot_irq;
202*05e5027eSGreg Kroah-Hartman 	struct tpci200_board *tpci200;
203*05e5027eSGreg Kroah-Hartman 
204*05e5027eSGreg Kroah-Hartman 	tpci200 = check_slot(dev);
205*05e5027eSGreg Kroah-Hartman 	if (tpci200 == NULL)
206*05e5027eSGreg Kroah-Hartman 		return -EINVAL;
207*05e5027eSGreg Kroah-Hartman 
208*05e5027eSGreg Kroah-Hartman 	if (mutex_lock_interruptible(&tpci200->mutex))
209*05e5027eSGreg Kroah-Hartman 		return -ERESTARTSYS;
210*05e5027eSGreg Kroah-Hartman 
211*05e5027eSGreg Kroah-Hartman 	if (tpci200->slots[dev->slot].irq != NULL) {
212*05e5027eSGreg Kroah-Hartman 		dev_err(&dev->dev,
213*05e5027eSGreg Kroah-Hartman 			"Slot [%d:%d] IRQ already registered !\n",
214*05e5027eSGreg Kroah-Hartman 			dev->bus->bus_nr,
215*05e5027eSGreg Kroah-Hartman 			dev->slot);
216*05e5027eSGreg Kroah-Hartman 		res = -EINVAL;
217*05e5027eSGreg Kroah-Hartman 		goto out_unlock;
218*05e5027eSGreg Kroah-Hartman 	}
219*05e5027eSGreg Kroah-Hartman 
220*05e5027eSGreg Kroah-Hartman 	slot_irq = kzalloc(sizeof(struct slot_irq), GFP_KERNEL);
221*05e5027eSGreg Kroah-Hartman 	if (slot_irq == NULL) {
222*05e5027eSGreg Kroah-Hartman 		dev_err(&dev->dev,
223*05e5027eSGreg Kroah-Hartman 			"Slot [%d:%d] unable to allocate memory for IRQ !\n",
224*05e5027eSGreg Kroah-Hartman 			dev->bus->bus_nr, dev->slot);
225*05e5027eSGreg Kroah-Hartman 		res = -ENOMEM;
226*05e5027eSGreg Kroah-Hartman 		goto out_unlock;
227*05e5027eSGreg Kroah-Hartman 	}
228*05e5027eSGreg Kroah-Hartman 
229*05e5027eSGreg Kroah-Hartman 	/*
230*05e5027eSGreg Kroah-Hartman 	 * WARNING: Setup Interrupt Vector in the IndustryPack device
231*05e5027eSGreg Kroah-Hartman 	 * before an IRQ request.
232*05e5027eSGreg Kroah-Hartman 	 * Read the User Manual of your IndustryPack device to know
233*05e5027eSGreg Kroah-Hartman 	 * where to write the vector in memory.
234*05e5027eSGreg Kroah-Hartman 	 */
235*05e5027eSGreg Kroah-Hartman 	slot_irq->handler = handler;
236*05e5027eSGreg Kroah-Hartman 	slot_irq->arg = arg;
237*05e5027eSGreg Kroah-Hartman 	slot_irq->holder = dev;
238*05e5027eSGreg Kroah-Hartman 
239*05e5027eSGreg Kroah-Hartman 	rcu_assign_pointer(tpci200->slots[dev->slot].irq, slot_irq);
240*05e5027eSGreg Kroah-Hartman 	tpci200_enable_irq(tpci200, dev->slot);
241*05e5027eSGreg Kroah-Hartman 
242*05e5027eSGreg Kroah-Hartman out_unlock:
243*05e5027eSGreg Kroah-Hartman 	mutex_unlock(&tpci200->mutex);
244*05e5027eSGreg Kroah-Hartman 	return res;
245*05e5027eSGreg Kroah-Hartman }
246*05e5027eSGreg Kroah-Hartman 
247*05e5027eSGreg Kroah-Hartman static int tpci200_register(struct tpci200_board *tpci200)
248*05e5027eSGreg Kroah-Hartman {
249*05e5027eSGreg Kroah-Hartman 	int i;
250*05e5027eSGreg Kroah-Hartman 	int res;
251*05e5027eSGreg Kroah-Hartman 	phys_addr_t ioidint_base;
252*05e5027eSGreg Kroah-Hartman 	unsigned short slot_ctrl;
253*05e5027eSGreg Kroah-Hartman 
254*05e5027eSGreg Kroah-Hartman 	if (pci_enable_device(tpci200->info->pdev) < 0)
255*05e5027eSGreg Kroah-Hartman 		return -ENODEV;
256*05e5027eSGreg Kroah-Hartman 
257*05e5027eSGreg Kroah-Hartman 	/* Request IP interface register (Bar 2) */
258*05e5027eSGreg Kroah-Hartman 	res = pci_request_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR,
259*05e5027eSGreg Kroah-Hartman 				 "Carrier IP interface registers");
260*05e5027eSGreg Kroah-Hartman 	if (res) {
261*05e5027eSGreg Kroah-Hartman 		dev_err(&tpci200->info->pdev->dev,
262*05e5027eSGreg Kroah-Hartman 			"(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 2 !",
263*05e5027eSGreg Kroah-Hartman 			tpci200->info->pdev->bus->number,
264*05e5027eSGreg Kroah-Hartman 			tpci200->info->pdev->devfn);
265*05e5027eSGreg Kroah-Hartman 		goto out_disable_pci;
266*05e5027eSGreg Kroah-Hartman 	}
267*05e5027eSGreg Kroah-Hartman 
268*05e5027eSGreg Kroah-Hartman 	/* Request IO ID INT space (Bar 3) */
269*05e5027eSGreg Kroah-Hartman 	res = pci_request_region(tpci200->info->pdev,
270*05e5027eSGreg Kroah-Hartman 				 TPCI200_IO_ID_INT_SPACES_BAR,
271*05e5027eSGreg Kroah-Hartman 				 "Carrier IO ID INT space");
272*05e5027eSGreg Kroah-Hartman 	if (res) {
273*05e5027eSGreg Kroah-Hartman 		dev_err(&tpci200->info->pdev->dev,
274*05e5027eSGreg Kroah-Hartman 			"(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 3 !",
275*05e5027eSGreg Kroah-Hartman 			tpci200->info->pdev->bus->number,
276*05e5027eSGreg Kroah-Hartman 			tpci200->info->pdev->devfn);
277*05e5027eSGreg Kroah-Hartman 		goto out_release_ip_space;
278*05e5027eSGreg Kroah-Hartman 	}
279*05e5027eSGreg Kroah-Hartman 
280*05e5027eSGreg Kroah-Hartman 	/* Request MEM8 space (Bar 5) */
281*05e5027eSGreg Kroah-Hartman 	res = pci_request_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR,
282*05e5027eSGreg Kroah-Hartman 				 "Carrier MEM8 space");
283*05e5027eSGreg Kroah-Hartman 	if (res) {
284*05e5027eSGreg Kroah-Hartman 		dev_err(&tpci200->info->pdev->dev,
285*05e5027eSGreg Kroah-Hartman 			"(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 5!",
286*05e5027eSGreg Kroah-Hartman 			tpci200->info->pdev->bus->number,
287*05e5027eSGreg Kroah-Hartman 			tpci200->info->pdev->devfn);
288*05e5027eSGreg Kroah-Hartman 		goto out_release_ioid_int_space;
289*05e5027eSGreg Kroah-Hartman 	}
290*05e5027eSGreg Kroah-Hartman 
291*05e5027eSGreg Kroah-Hartman 	/* Request MEM16 space (Bar 4) */
292*05e5027eSGreg Kroah-Hartman 	res = pci_request_region(tpci200->info->pdev, TPCI200_MEM16_SPACE_BAR,
293*05e5027eSGreg Kroah-Hartman 				 "Carrier MEM16 space");
294*05e5027eSGreg Kroah-Hartman 	if (res) {
295*05e5027eSGreg Kroah-Hartman 		dev_err(&tpci200->info->pdev->dev,
296*05e5027eSGreg Kroah-Hartman 			"(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 4!",
297*05e5027eSGreg Kroah-Hartman 			tpci200->info->pdev->bus->number,
298*05e5027eSGreg Kroah-Hartman 			tpci200->info->pdev->devfn);
299*05e5027eSGreg Kroah-Hartman 		goto out_release_mem8_space;
300*05e5027eSGreg Kroah-Hartman 	}
301*05e5027eSGreg Kroah-Hartman 
302*05e5027eSGreg Kroah-Hartman 	/* Map internal tpci200 driver user space */
303*05e5027eSGreg Kroah-Hartman 	tpci200->info->interface_regs =
304*05e5027eSGreg Kroah-Hartman 		ioremap_nocache(pci_resource_start(tpci200->info->pdev,
305*05e5027eSGreg Kroah-Hartman 					   TPCI200_IP_INTERFACE_BAR),
306*05e5027eSGreg Kroah-Hartman 			TPCI200_IFACE_SIZE);
307*05e5027eSGreg Kroah-Hartman 
308*05e5027eSGreg Kroah-Hartman 	/* Initialize lock that protects interface_regs */
309*05e5027eSGreg Kroah-Hartman 	spin_lock_init(&tpci200->regs_lock);
310*05e5027eSGreg Kroah-Hartman 
311*05e5027eSGreg Kroah-Hartman 	ioidint_base = pci_resource_start(tpci200->info->pdev,
312*05e5027eSGreg Kroah-Hartman 					  TPCI200_IO_ID_INT_SPACES_BAR);
313*05e5027eSGreg Kroah-Hartman 	tpci200->mod_mem[IPACK_IO_SPACE] = ioidint_base + TPCI200_IO_SPACE_OFF;
314*05e5027eSGreg Kroah-Hartman 	tpci200->mod_mem[IPACK_ID_SPACE] = ioidint_base + TPCI200_ID_SPACE_OFF;
315*05e5027eSGreg Kroah-Hartman 	tpci200->mod_mem[IPACK_INT_SPACE] =
316*05e5027eSGreg Kroah-Hartman 		ioidint_base + TPCI200_INT_SPACE_OFF;
317*05e5027eSGreg Kroah-Hartman 	tpci200->mod_mem[IPACK_MEM8_SPACE] =
318*05e5027eSGreg Kroah-Hartman 		pci_resource_start(tpci200->info->pdev,
319*05e5027eSGreg Kroah-Hartman 				   TPCI200_MEM8_SPACE_BAR);
320*05e5027eSGreg Kroah-Hartman 	tpci200->mod_mem[IPACK_MEM16_SPACE] =
321*05e5027eSGreg Kroah-Hartman 		pci_resource_start(tpci200->info->pdev,
322*05e5027eSGreg Kroah-Hartman 				   TPCI200_MEM16_SPACE_BAR);
323*05e5027eSGreg Kroah-Hartman 
324*05e5027eSGreg Kroah-Hartman 	/* Set the default parameters of the slot
325*05e5027eSGreg Kroah-Hartman 	 * INT0 disabled, level sensitive
326*05e5027eSGreg Kroah-Hartman 	 * INT1 disabled, level sensitive
327*05e5027eSGreg Kroah-Hartman 	 * error interrupt disabled
328*05e5027eSGreg Kroah-Hartman 	 * timeout interrupt disabled
329*05e5027eSGreg Kroah-Hartman 	 * recover time disabled
330*05e5027eSGreg Kroah-Hartman 	 * clock rate 8 MHz
331*05e5027eSGreg Kroah-Hartman 	 */
332*05e5027eSGreg Kroah-Hartman 	slot_ctrl = 0;
333*05e5027eSGreg Kroah-Hartman 	for (i = 0; i < TPCI200_NB_SLOT; i++)
334*05e5027eSGreg Kroah-Hartman 		writew(slot_ctrl, &tpci200->info->interface_regs->control[i]);
335*05e5027eSGreg Kroah-Hartman 
336*05e5027eSGreg Kroah-Hartman 	res = request_irq(tpci200->info->pdev->irq,
337*05e5027eSGreg Kroah-Hartman 			  tpci200_interrupt, IRQF_SHARED,
338*05e5027eSGreg Kroah-Hartman 			  KBUILD_MODNAME, (void *) tpci200);
339*05e5027eSGreg Kroah-Hartman 	if (res) {
340*05e5027eSGreg Kroah-Hartman 		dev_err(&tpci200->info->pdev->dev,
341*05e5027eSGreg Kroah-Hartman 			"(bn 0x%X, sn 0x%X) unable to register IRQ !",
342*05e5027eSGreg Kroah-Hartman 			tpci200->info->pdev->bus->number,
343*05e5027eSGreg Kroah-Hartman 			tpci200->info->pdev->devfn);
344*05e5027eSGreg Kroah-Hartman 		goto out_release_ioid_int_space;
345*05e5027eSGreg Kroah-Hartman 	}
346*05e5027eSGreg Kroah-Hartman 
347*05e5027eSGreg Kroah-Hartman 	return 0;
348*05e5027eSGreg Kroah-Hartman 
349*05e5027eSGreg Kroah-Hartman out_release_mem8_space:
350*05e5027eSGreg Kroah-Hartman 	pci_release_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR);
351*05e5027eSGreg Kroah-Hartman out_release_ioid_int_space:
352*05e5027eSGreg Kroah-Hartman 	pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR);
353*05e5027eSGreg Kroah-Hartman out_release_ip_space:
354*05e5027eSGreg Kroah-Hartman 	pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR);
355*05e5027eSGreg Kroah-Hartman out_disable_pci:
356*05e5027eSGreg Kroah-Hartman 	pci_disable_device(tpci200->info->pdev);
357*05e5027eSGreg Kroah-Hartman 	return res;
358*05e5027eSGreg Kroah-Hartman }
359*05e5027eSGreg Kroah-Hartman 
360*05e5027eSGreg Kroah-Hartman static int tpci200_get_clockrate(struct ipack_device *dev)
361*05e5027eSGreg Kroah-Hartman {
362*05e5027eSGreg Kroah-Hartman 	struct tpci200_board *tpci200 = check_slot(dev);
363*05e5027eSGreg Kroah-Hartman 	__le16 __iomem *addr;
364*05e5027eSGreg Kroah-Hartman 
365*05e5027eSGreg Kroah-Hartman 	if (!tpci200)
366*05e5027eSGreg Kroah-Hartman 		return -ENODEV;
367*05e5027eSGreg Kroah-Hartman 
368*05e5027eSGreg Kroah-Hartman 	addr = &tpci200->info->interface_regs->control[dev->slot];
369*05e5027eSGreg Kroah-Hartman 	return (ioread16(addr) & TPCI200_CLK32) ? 32 : 8;
370*05e5027eSGreg Kroah-Hartman }
371*05e5027eSGreg Kroah-Hartman 
372*05e5027eSGreg Kroah-Hartman static int tpci200_set_clockrate(struct ipack_device *dev, int mherz)
373*05e5027eSGreg Kroah-Hartman {
374*05e5027eSGreg Kroah-Hartman 	struct tpci200_board *tpci200 = check_slot(dev);
375*05e5027eSGreg Kroah-Hartman 	__le16 __iomem *addr;
376*05e5027eSGreg Kroah-Hartman 
377*05e5027eSGreg Kroah-Hartman 	if (!tpci200)
378*05e5027eSGreg Kroah-Hartman 		return -ENODEV;
379*05e5027eSGreg Kroah-Hartman 
380*05e5027eSGreg Kroah-Hartman 	addr = &tpci200->info->interface_regs->control[dev->slot];
381*05e5027eSGreg Kroah-Hartman 
382*05e5027eSGreg Kroah-Hartman 	switch (mherz) {
383*05e5027eSGreg Kroah-Hartman 	case 8:
384*05e5027eSGreg Kroah-Hartman 		tpci200_clear_mask(tpci200, addr, TPCI200_CLK32);
385*05e5027eSGreg Kroah-Hartman 		break;
386*05e5027eSGreg Kroah-Hartman 	case 32:
387*05e5027eSGreg Kroah-Hartman 		tpci200_set_mask(tpci200, addr, TPCI200_CLK32);
388*05e5027eSGreg Kroah-Hartman 		break;
389*05e5027eSGreg Kroah-Hartman 	default:
390*05e5027eSGreg Kroah-Hartman 		return -EINVAL;
391*05e5027eSGreg Kroah-Hartman 	}
392*05e5027eSGreg Kroah-Hartman 	return 0;
393*05e5027eSGreg Kroah-Hartman }
394*05e5027eSGreg Kroah-Hartman 
395*05e5027eSGreg Kroah-Hartman static int tpci200_get_error(struct ipack_device *dev)
396*05e5027eSGreg Kroah-Hartman {
397*05e5027eSGreg Kroah-Hartman 	struct tpci200_board *tpci200 = check_slot(dev);
398*05e5027eSGreg Kroah-Hartman 	__le16 __iomem *addr;
399*05e5027eSGreg Kroah-Hartman 	u16 mask;
400*05e5027eSGreg Kroah-Hartman 
401*05e5027eSGreg Kroah-Hartman 	if (!tpci200)
402*05e5027eSGreg Kroah-Hartman 		return -ENODEV;
403*05e5027eSGreg Kroah-Hartman 
404*05e5027eSGreg Kroah-Hartman 	addr = &tpci200->info->interface_regs->status;
405*05e5027eSGreg Kroah-Hartman 	mask = tpci200_status_error[dev->slot];
406*05e5027eSGreg Kroah-Hartman 	return (ioread16(addr) & mask) ? 1 : 0;
407*05e5027eSGreg Kroah-Hartman }
408*05e5027eSGreg Kroah-Hartman 
409*05e5027eSGreg Kroah-Hartman static int tpci200_get_timeout(struct ipack_device *dev)
410*05e5027eSGreg Kroah-Hartman {
411*05e5027eSGreg Kroah-Hartman 	struct tpci200_board *tpci200 = check_slot(dev);
412*05e5027eSGreg Kroah-Hartman 	__le16 __iomem *addr;
413*05e5027eSGreg Kroah-Hartman 	u16 mask;
414*05e5027eSGreg Kroah-Hartman 
415*05e5027eSGreg Kroah-Hartman 	if (!tpci200)
416*05e5027eSGreg Kroah-Hartman 		return -ENODEV;
417*05e5027eSGreg Kroah-Hartman 
418*05e5027eSGreg Kroah-Hartman 	addr = &tpci200->info->interface_regs->status;
419*05e5027eSGreg Kroah-Hartman 	mask = tpci200_status_timeout[dev->slot];
420*05e5027eSGreg Kroah-Hartman 
421*05e5027eSGreg Kroah-Hartman 	return (ioread16(addr) & mask) ? 1 : 0;
422*05e5027eSGreg Kroah-Hartman }
423*05e5027eSGreg Kroah-Hartman 
424*05e5027eSGreg Kroah-Hartman static int tpci200_reset_timeout(struct ipack_device *dev)
425*05e5027eSGreg Kroah-Hartman {
426*05e5027eSGreg Kroah-Hartman 	struct tpci200_board *tpci200 = check_slot(dev);
427*05e5027eSGreg Kroah-Hartman 	__le16 __iomem *addr;
428*05e5027eSGreg Kroah-Hartman 	u16 mask;
429*05e5027eSGreg Kroah-Hartman 
430*05e5027eSGreg Kroah-Hartman 	if (!tpci200)
431*05e5027eSGreg Kroah-Hartman 		return -ENODEV;
432*05e5027eSGreg Kroah-Hartman 
433*05e5027eSGreg Kroah-Hartman 	addr = &tpci200->info->interface_regs->status;
434*05e5027eSGreg Kroah-Hartman 	mask = tpci200_status_timeout[dev->slot];
435*05e5027eSGreg Kroah-Hartman 
436*05e5027eSGreg Kroah-Hartman 	iowrite16(mask, addr);
437*05e5027eSGreg Kroah-Hartman 	return 0;
438*05e5027eSGreg Kroah-Hartman }
439*05e5027eSGreg Kroah-Hartman 
440*05e5027eSGreg Kroah-Hartman static void tpci200_uninstall(struct tpci200_board *tpci200)
441*05e5027eSGreg Kroah-Hartman {
442*05e5027eSGreg Kroah-Hartman 	tpci200_unregister(tpci200);
443*05e5027eSGreg Kroah-Hartman 	kfree(tpci200->slots);
444*05e5027eSGreg Kroah-Hartman }
445*05e5027eSGreg Kroah-Hartman 
446*05e5027eSGreg Kroah-Hartman static const struct ipack_bus_ops tpci200_bus_ops = {
447*05e5027eSGreg Kroah-Hartman 	.request_irq = tpci200_request_irq,
448*05e5027eSGreg Kroah-Hartman 	.free_irq = tpci200_free_irq,
449*05e5027eSGreg Kroah-Hartman 	.get_clockrate = tpci200_get_clockrate,
450*05e5027eSGreg Kroah-Hartman 	.set_clockrate = tpci200_set_clockrate,
451*05e5027eSGreg Kroah-Hartman 	.get_error     = tpci200_get_error,
452*05e5027eSGreg Kroah-Hartman 	.get_timeout   = tpci200_get_timeout,
453*05e5027eSGreg Kroah-Hartman 	.reset_timeout = tpci200_reset_timeout,
454*05e5027eSGreg Kroah-Hartman };
455*05e5027eSGreg Kroah-Hartman 
456*05e5027eSGreg Kroah-Hartman static int tpci200_install(struct tpci200_board *tpci200)
457*05e5027eSGreg Kroah-Hartman {
458*05e5027eSGreg Kroah-Hartman 	int res;
459*05e5027eSGreg Kroah-Hartman 
460*05e5027eSGreg Kroah-Hartman 	tpci200->slots = kzalloc(
461*05e5027eSGreg Kroah-Hartman 		TPCI200_NB_SLOT * sizeof(struct tpci200_slot), GFP_KERNEL);
462*05e5027eSGreg Kroah-Hartman 	if (tpci200->slots == NULL)
463*05e5027eSGreg Kroah-Hartman 		return -ENOMEM;
464*05e5027eSGreg Kroah-Hartman 
465*05e5027eSGreg Kroah-Hartman 	res = tpci200_register(tpci200);
466*05e5027eSGreg Kroah-Hartman 	if (res) {
467*05e5027eSGreg Kroah-Hartman 		kfree(tpci200->slots);
468*05e5027eSGreg Kroah-Hartman 		tpci200->slots = NULL;
469*05e5027eSGreg Kroah-Hartman 		return res;
470*05e5027eSGreg Kroah-Hartman 	}
471*05e5027eSGreg Kroah-Hartman 
472*05e5027eSGreg Kroah-Hartman 	mutex_init(&tpci200->mutex);
473*05e5027eSGreg Kroah-Hartman 	return 0;
474*05e5027eSGreg Kroah-Hartman }
475*05e5027eSGreg Kroah-Hartman 
476*05e5027eSGreg Kroah-Hartman static void tpci200_release_device(struct ipack_device *dev)
477*05e5027eSGreg Kroah-Hartman {
478*05e5027eSGreg Kroah-Hartman 	kfree(dev);
479*05e5027eSGreg Kroah-Hartman }
480*05e5027eSGreg Kroah-Hartman 
481*05e5027eSGreg Kroah-Hartman static int tpci200_create_device(struct tpci200_board *tpci200, int i)
482*05e5027eSGreg Kroah-Hartman {
483*05e5027eSGreg Kroah-Hartman 	enum ipack_space space;
484*05e5027eSGreg Kroah-Hartman 	struct ipack_device *dev =
485*05e5027eSGreg Kroah-Hartman 		kzalloc(sizeof(struct ipack_device), GFP_KERNEL);
486*05e5027eSGreg Kroah-Hartman 	if (!dev)
487*05e5027eSGreg Kroah-Hartman 		return -ENOMEM;
488*05e5027eSGreg Kroah-Hartman 	dev->slot = i;
489*05e5027eSGreg Kroah-Hartman 	dev->bus = tpci200->info->ipack_bus;
490*05e5027eSGreg Kroah-Hartman 	dev->release = tpci200_release_device;
491*05e5027eSGreg Kroah-Hartman 
492*05e5027eSGreg Kroah-Hartman 	for (space = 0; space < IPACK_SPACE_COUNT; space++) {
493*05e5027eSGreg Kroah-Hartman 		dev->region[space].start =
494*05e5027eSGreg Kroah-Hartman 			tpci200->mod_mem[space]
495*05e5027eSGreg Kroah-Hartman 			+ tpci200_space_interval[space] * i;
496*05e5027eSGreg Kroah-Hartman 		dev->region[space].size = tpci200_space_size[space];
497*05e5027eSGreg Kroah-Hartman 	}
498*05e5027eSGreg Kroah-Hartman 	return ipack_device_register(dev);
499*05e5027eSGreg Kroah-Hartman }
500*05e5027eSGreg Kroah-Hartman 
501*05e5027eSGreg Kroah-Hartman static int tpci200_pci_probe(struct pci_dev *pdev,
502*05e5027eSGreg Kroah-Hartman 			     const struct pci_device_id *id)
503*05e5027eSGreg Kroah-Hartman {
504*05e5027eSGreg Kroah-Hartman 	int ret, i;
505*05e5027eSGreg Kroah-Hartman 	struct tpci200_board *tpci200;
506*05e5027eSGreg Kroah-Hartman 	u32 reg32;
507*05e5027eSGreg Kroah-Hartman 
508*05e5027eSGreg Kroah-Hartman 	tpci200 = kzalloc(sizeof(struct tpci200_board), GFP_KERNEL);
509*05e5027eSGreg Kroah-Hartman 	if (!tpci200)
510*05e5027eSGreg Kroah-Hartman 		return -ENOMEM;
511*05e5027eSGreg Kroah-Hartman 
512*05e5027eSGreg Kroah-Hartman 	tpci200->info = kzalloc(sizeof(struct tpci200_infos), GFP_KERNEL);
513*05e5027eSGreg Kroah-Hartman 	if (!tpci200->info) {
514*05e5027eSGreg Kroah-Hartman 		ret = -ENOMEM;
515*05e5027eSGreg Kroah-Hartman 		goto out_err_info;
516*05e5027eSGreg Kroah-Hartman 	}
517*05e5027eSGreg Kroah-Hartman 
518*05e5027eSGreg Kroah-Hartman 	pci_dev_get(pdev);
519*05e5027eSGreg Kroah-Hartman 
520*05e5027eSGreg Kroah-Hartman 	/* Obtain a mapping of the carrier's PCI configuration registers */
521*05e5027eSGreg Kroah-Hartman 	ret = pci_request_region(pdev, TPCI200_CFG_MEM_BAR,
522*05e5027eSGreg Kroah-Hartman 				 KBUILD_MODNAME " Configuration Memory");
523*05e5027eSGreg Kroah-Hartman 	if (ret) {
524*05e5027eSGreg Kroah-Hartman 		dev_err(&pdev->dev, "Failed to allocate PCI Configuration Memory");
525*05e5027eSGreg Kroah-Hartman 		ret = -EBUSY;
526*05e5027eSGreg Kroah-Hartman 		goto out_err_pci_request;
527*05e5027eSGreg Kroah-Hartman 	}
528*05e5027eSGreg Kroah-Hartman 	tpci200->info->cfg_regs = ioremap_nocache(
529*05e5027eSGreg Kroah-Hartman 			pci_resource_start(pdev, TPCI200_CFG_MEM_BAR),
530*05e5027eSGreg Kroah-Hartman 			pci_resource_len(pdev, TPCI200_CFG_MEM_BAR));
531*05e5027eSGreg Kroah-Hartman 	if (!tpci200->info->cfg_regs) {
532*05e5027eSGreg Kroah-Hartman 		dev_err(&pdev->dev, "Failed to map PCI Configuration Memory");
533*05e5027eSGreg Kroah-Hartman 		ret = -EFAULT;
534*05e5027eSGreg Kroah-Hartman 		goto out_err_ioremap;
535*05e5027eSGreg Kroah-Hartman 	}
536*05e5027eSGreg Kroah-Hartman 
537*05e5027eSGreg Kroah-Hartman 	/* Disable byte swapping for 16 bit IP module access. This will ensure
538*05e5027eSGreg Kroah-Hartman 	 * that the Industrypack big endian byte order is preserved by the
539*05e5027eSGreg Kroah-Hartman 	 * carrier. */
540*05e5027eSGreg Kroah-Hartman 	reg32 = ioread32(tpci200->info->cfg_regs + LAS1_DESC);
541*05e5027eSGreg Kroah-Hartman 	reg32 |= 1 << LAS_BIT_BIGENDIAN;
542*05e5027eSGreg Kroah-Hartman 	iowrite32(reg32, tpci200->info->cfg_regs + LAS1_DESC);
543*05e5027eSGreg Kroah-Hartman 
544*05e5027eSGreg Kroah-Hartman 	reg32 = ioread32(tpci200->info->cfg_regs + LAS2_DESC);
545*05e5027eSGreg Kroah-Hartman 	reg32 |= 1 << LAS_BIT_BIGENDIAN;
546*05e5027eSGreg Kroah-Hartman 	iowrite32(reg32, tpci200->info->cfg_regs + LAS2_DESC);
547*05e5027eSGreg Kroah-Hartman 
548*05e5027eSGreg Kroah-Hartman 	/* Save struct pci_dev pointer */
549*05e5027eSGreg Kroah-Hartman 	tpci200->info->pdev = pdev;
550*05e5027eSGreg Kroah-Hartman 	tpci200->info->id_table = (struct pci_device_id *)id;
551*05e5027eSGreg Kroah-Hartman 
552*05e5027eSGreg Kroah-Hartman 	/* register the device and initialize it */
553*05e5027eSGreg Kroah-Hartman 	ret = tpci200_install(tpci200);
554*05e5027eSGreg Kroah-Hartman 	if (ret) {
555*05e5027eSGreg Kroah-Hartman 		dev_err(&pdev->dev, "error during tpci200 install\n");
556*05e5027eSGreg Kroah-Hartman 		ret = -ENODEV;
557*05e5027eSGreg Kroah-Hartman 		goto out_err_install;
558*05e5027eSGreg Kroah-Hartman 	}
559*05e5027eSGreg Kroah-Hartman 
560*05e5027eSGreg Kroah-Hartman 	/* Register the carrier in the industry pack bus driver */
561*05e5027eSGreg Kroah-Hartman 	tpci200->info->ipack_bus = ipack_bus_register(&pdev->dev,
562*05e5027eSGreg Kroah-Hartman 						      TPCI200_NB_SLOT,
563*05e5027eSGreg Kroah-Hartman 						      &tpci200_bus_ops);
564*05e5027eSGreg Kroah-Hartman 	if (!tpci200->info->ipack_bus) {
565*05e5027eSGreg Kroah-Hartman 		dev_err(&pdev->dev,
566*05e5027eSGreg Kroah-Hartman 			"error registering the carrier on ipack driver\n");
567*05e5027eSGreg Kroah-Hartman 		ret = -EFAULT;
568*05e5027eSGreg Kroah-Hartman 		goto out_err_bus_register;
569*05e5027eSGreg Kroah-Hartman 	}
570*05e5027eSGreg Kroah-Hartman 
571*05e5027eSGreg Kroah-Hartman 	/* save the bus number given by ipack to logging purpose */
572*05e5027eSGreg Kroah-Hartman 	tpci200->number = tpci200->info->ipack_bus->bus_nr;
573*05e5027eSGreg Kroah-Hartman 	dev_set_drvdata(&pdev->dev, tpci200);
574*05e5027eSGreg Kroah-Hartman 
575*05e5027eSGreg Kroah-Hartman 	for (i = 0; i < TPCI200_NB_SLOT; i++)
576*05e5027eSGreg Kroah-Hartman 		tpci200_create_device(tpci200, i);
577*05e5027eSGreg Kroah-Hartman 	return 0;
578*05e5027eSGreg Kroah-Hartman 
579*05e5027eSGreg Kroah-Hartman out_err_bus_register:
580*05e5027eSGreg Kroah-Hartman 	tpci200_uninstall(tpci200);
581*05e5027eSGreg Kroah-Hartman out_err_install:
582*05e5027eSGreg Kroah-Hartman 	iounmap(tpci200->info->cfg_regs);
583*05e5027eSGreg Kroah-Hartman out_err_ioremap:
584*05e5027eSGreg Kroah-Hartman 	pci_release_region(pdev, TPCI200_CFG_MEM_BAR);
585*05e5027eSGreg Kroah-Hartman out_err_pci_request:
586*05e5027eSGreg Kroah-Hartman 	pci_dev_put(pdev);
587*05e5027eSGreg Kroah-Hartman 	kfree(tpci200->info);
588*05e5027eSGreg Kroah-Hartman out_err_info:
589*05e5027eSGreg Kroah-Hartman 	kfree(tpci200);
590*05e5027eSGreg Kroah-Hartman 	return ret;
591*05e5027eSGreg Kroah-Hartman }
592*05e5027eSGreg Kroah-Hartman 
593*05e5027eSGreg Kroah-Hartman static void __tpci200_pci_remove(struct tpci200_board *tpci200)
594*05e5027eSGreg Kroah-Hartman {
595*05e5027eSGreg Kroah-Hartman 	ipack_bus_unregister(tpci200->info->ipack_bus);
596*05e5027eSGreg Kroah-Hartman 	tpci200_uninstall(tpci200);
597*05e5027eSGreg Kroah-Hartman 
598*05e5027eSGreg Kroah-Hartman 	kfree(tpci200->info);
599*05e5027eSGreg Kroah-Hartman 	kfree(tpci200);
600*05e5027eSGreg Kroah-Hartman }
601*05e5027eSGreg Kroah-Hartman 
602*05e5027eSGreg Kroah-Hartman static void __devexit tpci200_pci_remove(struct pci_dev *dev)
603*05e5027eSGreg Kroah-Hartman {
604*05e5027eSGreg Kroah-Hartman 	struct tpci200_board *tpci200 = pci_get_drvdata(dev);
605*05e5027eSGreg Kroah-Hartman 
606*05e5027eSGreg Kroah-Hartman 	__tpci200_pci_remove(tpci200);
607*05e5027eSGreg Kroah-Hartman }
608*05e5027eSGreg Kroah-Hartman 
609*05e5027eSGreg Kroah-Hartman static DEFINE_PCI_DEVICE_TABLE(tpci200_idtable) = {
610*05e5027eSGreg Kroah-Hartman 	{ TPCI200_VENDOR_ID, TPCI200_DEVICE_ID, TPCI200_SUBVENDOR_ID,
611*05e5027eSGreg Kroah-Hartman 	  TPCI200_SUBDEVICE_ID },
612*05e5027eSGreg Kroah-Hartman 	{ 0, },
613*05e5027eSGreg Kroah-Hartman };
614*05e5027eSGreg Kroah-Hartman 
615*05e5027eSGreg Kroah-Hartman MODULE_DEVICE_TABLE(pci, tpci200_idtable);
616*05e5027eSGreg Kroah-Hartman 
617*05e5027eSGreg Kroah-Hartman static struct pci_driver tpci200_pci_drv = {
618*05e5027eSGreg Kroah-Hartman 	.name = "tpci200",
619*05e5027eSGreg Kroah-Hartman 	.id_table = tpci200_idtable,
620*05e5027eSGreg Kroah-Hartman 	.probe = tpci200_pci_probe,
621*05e5027eSGreg Kroah-Hartman 	.remove = __devexit_p(tpci200_pci_remove),
622*05e5027eSGreg Kroah-Hartman };
623*05e5027eSGreg Kroah-Hartman 
624*05e5027eSGreg Kroah-Hartman module_pci_driver(tpci200_pci_drv);
625*05e5027eSGreg Kroah-Hartman 
626*05e5027eSGreg Kroah-Hartman MODULE_DESCRIPTION("TEWS TPCI-200 device driver");
627*05e5027eSGreg Kroah-Hartman MODULE_LICENSE("GPL");
628