1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Driver for the Cirrus PD6729 PCI-PCMCIA bridge.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Based on the i82092.c driver.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * This software may be used and distributed according to the terms of
7*4882a593Smuzhiyun * the GNU General Public License, incorporated herein by reference.
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/kernel.h>
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <linux/slab.h>
13*4882a593Smuzhiyun #include <linux/pci.h>
14*4882a593Smuzhiyun #include <linux/init.h>
15*4882a593Smuzhiyun #include <linux/workqueue.h>
16*4882a593Smuzhiyun #include <linux/interrupt.h>
17*4882a593Smuzhiyun #include <linux/device.h>
18*4882a593Smuzhiyun #include <linux/io.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include <pcmcia/ss.h>
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #include "pd6729.h"
24*4882a593Smuzhiyun #include "i82365.h"
25*4882a593Smuzhiyun #include "cirrus.h"
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun MODULE_LICENSE("GPL");
28*4882a593Smuzhiyun MODULE_DESCRIPTION("Driver for the Cirrus PD6729 PCI-PCMCIA bridge");
29*4882a593Smuzhiyun MODULE_AUTHOR("Jun Komuro <komurojun-mbn@nifty.com>");
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #define MAX_SOCKETS 2
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun /*
34*4882a593Smuzhiyun * simple helper functions
35*4882a593Smuzhiyun * External clock time, in nanoseconds. 120 ns = 8.33 MHz
36*4882a593Smuzhiyun */
37*4882a593Smuzhiyun #define to_cycles(ns) ((ns)/120)
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun #ifndef NO_IRQ
40*4882a593Smuzhiyun #define NO_IRQ ((unsigned int)(0))
41*4882a593Smuzhiyun #endif
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun /*
44*4882a593Smuzhiyun * PARAMETERS
45*4882a593Smuzhiyun * irq_mode=n
46*4882a593Smuzhiyun * Specifies the interrupt delivery mode. The default (1) is to use PCI
47*4882a593Smuzhiyun * interrupts; a value of 0 selects ISA interrupts. This must be set for
48*4882a593Smuzhiyun * correct operation of PCI card readers.
49*4882a593Smuzhiyun */
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun static int irq_mode = 1; /* 0 = ISA interrupt, 1 = PCI interrupt */
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun module_param(irq_mode, int, 0444);
54*4882a593Smuzhiyun MODULE_PARM_DESC(irq_mode,
55*4882a593Smuzhiyun "interrupt delivery mode. 0 = ISA, 1 = PCI. default is 1");
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun static DEFINE_SPINLOCK(port_lock);
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun /* basic value read/write functions */
60*4882a593Smuzhiyun
indirect_read(struct pd6729_socket * socket,unsigned short reg)61*4882a593Smuzhiyun static unsigned char indirect_read(struct pd6729_socket *socket,
62*4882a593Smuzhiyun unsigned short reg)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun unsigned long port;
65*4882a593Smuzhiyun unsigned char val;
66*4882a593Smuzhiyun unsigned long flags;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun spin_lock_irqsave(&port_lock, flags);
69*4882a593Smuzhiyun reg += socket->number * 0x40;
70*4882a593Smuzhiyun port = socket->io_base;
71*4882a593Smuzhiyun outb(reg, port);
72*4882a593Smuzhiyun val = inb(port + 1);
73*4882a593Smuzhiyun spin_unlock_irqrestore(&port_lock, flags);
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun return val;
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun
indirect_read16(struct pd6729_socket * socket,unsigned short reg)78*4882a593Smuzhiyun static unsigned short indirect_read16(struct pd6729_socket *socket,
79*4882a593Smuzhiyun unsigned short reg)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun unsigned long port;
82*4882a593Smuzhiyun unsigned short tmp;
83*4882a593Smuzhiyun unsigned long flags;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun spin_lock_irqsave(&port_lock, flags);
86*4882a593Smuzhiyun reg = reg + socket->number * 0x40;
87*4882a593Smuzhiyun port = socket->io_base;
88*4882a593Smuzhiyun outb(reg, port);
89*4882a593Smuzhiyun tmp = inb(port + 1);
90*4882a593Smuzhiyun reg++;
91*4882a593Smuzhiyun outb(reg, port);
92*4882a593Smuzhiyun tmp = tmp | (inb(port + 1) << 8);
93*4882a593Smuzhiyun spin_unlock_irqrestore(&port_lock, flags);
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun return tmp;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
indirect_write(struct pd6729_socket * socket,unsigned short reg,unsigned char value)98*4882a593Smuzhiyun static void indirect_write(struct pd6729_socket *socket, unsigned short reg,
99*4882a593Smuzhiyun unsigned char value)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun unsigned long port;
102*4882a593Smuzhiyun unsigned long flags;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun spin_lock_irqsave(&port_lock, flags);
105*4882a593Smuzhiyun reg = reg + socket->number * 0x40;
106*4882a593Smuzhiyun port = socket->io_base;
107*4882a593Smuzhiyun outb(reg, port);
108*4882a593Smuzhiyun outb(value, port + 1);
109*4882a593Smuzhiyun spin_unlock_irqrestore(&port_lock, flags);
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun
indirect_setbit(struct pd6729_socket * socket,unsigned short reg,unsigned char mask)112*4882a593Smuzhiyun static void indirect_setbit(struct pd6729_socket *socket, unsigned short reg,
113*4882a593Smuzhiyun unsigned char mask)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun unsigned long port;
116*4882a593Smuzhiyun unsigned char val;
117*4882a593Smuzhiyun unsigned long flags;
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun spin_lock_irqsave(&port_lock, flags);
120*4882a593Smuzhiyun reg = reg + socket->number * 0x40;
121*4882a593Smuzhiyun port = socket->io_base;
122*4882a593Smuzhiyun outb(reg, port);
123*4882a593Smuzhiyun val = inb(port + 1);
124*4882a593Smuzhiyun val |= mask;
125*4882a593Smuzhiyun outb(reg, port);
126*4882a593Smuzhiyun outb(val, port + 1);
127*4882a593Smuzhiyun spin_unlock_irqrestore(&port_lock, flags);
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
indirect_resetbit(struct pd6729_socket * socket,unsigned short reg,unsigned char mask)130*4882a593Smuzhiyun static void indirect_resetbit(struct pd6729_socket *socket, unsigned short reg,
131*4882a593Smuzhiyun unsigned char mask)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun unsigned long port;
134*4882a593Smuzhiyun unsigned char val;
135*4882a593Smuzhiyun unsigned long flags;
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun spin_lock_irqsave(&port_lock, flags);
138*4882a593Smuzhiyun reg = reg + socket->number * 0x40;
139*4882a593Smuzhiyun port = socket->io_base;
140*4882a593Smuzhiyun outb(reg, port);
141*4882a593Smuzhiyun val = inb(port + 1);
142*4882a593Smuzhiyun val &= ~mask;
143*4882a593Smuzhiyun outb(reg, port);
144*4882a593Smuzhiyun outb(val, port + 1);
145*4882a593Smuzhiyun spin_unlock_irqrestore(&port_lock, flags);
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
indirect_write16(struct pd6729_socket * socket,unsigned short reg,unsigned short value)148*4882a593Smuzhiyun static void indirect_write16(struct pd6729_socket *socket, unsigned short reg,
149*4882a593Smuzhiyun unsigned short value)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun unsigned long port;
152*4882a593Smuzhiyun unsigned char val;
153*4882a593Smuzhiyun unsigned long flags;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun spin_lock_irqsave(&port_lock, flags);
156*4882a593Smuzhiyun reg = reg + socket->number * 0x40;
157*4882a593Smuzhiyun port = socket->io_base;
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun outb(reg, port);
160*4882a593Smuzhiyun val = value & 255;
161*4882a593Smuzhiyun outb(val, port + 1);
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun reg++;
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun outb(reg, port);
166*4882a593Smuzhiyun val = value >> 8;
167*4882a593Smuzhiyun outb(val, port + 1);
168*4882a593Smuzhiyun spin_unlock_irqrestore(&port_lock, flags);
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun /* Interrupt handler functionality */
172*4882a593Smuzhiyun
pd6729_interrupt(int irq,void * dev)173*4882a593Smuzhiyun static irqreturn_t pd6729_interrupt(int irq, void *dev)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun struct pd6729_socket *socket = (struct pd6729_socket *)dev;
176*4882a593Smuzhiyun int i;
177*4882a593Smuzhiyun int loopcount = 0;
178*4882a593Smuzhiyun int handled = 0;
179*4882a593Smuzhiyun unsigned int events, active = 0;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun while (1) {
182*4882a593Smuzhiyun loopcount++;
183*4882a593Smuzhiyun if (loopcount > 20) {
184*4882a593Smuzhiyun printk(KERN_ERR "pd6729: infinite eventloop "
185*4882a593Smuzhiyun "in interrupt\n");
186*4882a593Smuzhiyun break;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun active = 0;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun for (i = 0; i < MAX_SOCKETS; i++) {
192*4882a593Smuzhiyun unsigned int csc;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun /* card status change register */
195*4882a593Smuzhiyun csc = indirect_read(&socket[i], I365_CSC);
196*4882a593Smuzhiyun if (csc == 0) /* no events on this socket */
197*4882a593Smuzhiyun continue;
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun handled = 1;
200*4882a593Smuzhiyun events = 0;
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun if (csc & I365_CSC_DETECT) {
203*4882a593Smuzhiyun events |= SS_DETECT;
204*4882a593Smuzhiyun dev_vdbg(&socket[i].socket.dev,
205*4882a593Smuzhiyun "Card detected in socket %i!\n", i);
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun if (indirect_read(&socket[i], I365_INTCTL)
209*4882a593Smuzhiyun & I365_PC_IOCARD) {
210*4882a593Smuzhiyun /* For IO/CARDS, bit 0 means "read the card" */
211*4882a593Smuzhiyun events |= (csc & I365_CSC_STSCHG)
212*4882a593Smuzhiyun ? SS_STSCHG : 0;
213*4882a593Smuzhiyun } else {
214*4882a593Smuzhiyun /* Check for battery/ready events */
215*4882a593Smuzhiyun events |= (csc & I365_CSC_BVD1)
216*4882a593Smuzhiyun ? SS_BATDEAD : 0;
217*4882a593Smuzhiyun events |= (csc & I365_CSC_BVD2)
218*4882a593Smuzhiyun ? SS_BATWARN : 0;
219*4882a593Smuzhiyun events |= (csc & I365_CSC_READY)
220*4882a593Smuzhiyun ? SS_READY : 0;
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun if (events)
224*4882a593Smuzhiyun pcmcia_parse_events(&socket[i].socket, events);
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun active |= events;
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun if (active == 0) /* no more events to handle */
230*4882a593Smuzhiyun break;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun return IRQ_RETVAL(handled);
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun /* socket functions */
236*4882a593Smuzhiyun
pd6729_interrupt_wrapper(struct timer_list * t)237*4882a593Smuzhiyun static void pd6729_interrupt_wrapper(struct timer_list *t)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun struct pd6729_socket *socket = from_timer(socket, t, poll_timer);
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun pd6729_interrupt(0, (void *)socket);
242*4882a593Smuzhiyun mod_timer(&socket->poll_timer, jiffies + HZ);
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun
pd6729_get_status(struct pcmcia_socket * sock,u_int * value)245*4882a593Smuzhiyun static int pd6729_get_status(struct pcmcia_socket *sock, u_int *value)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun struct pd6729_socket *socket
248*4882a593Smuzhiyun = container_of(sock, struct pd6729_socket, socket);
249*4882a593Smuzhiyun unsigned int status;
250*4882a593Smuzhiyun unsigned int data;
251*4882a593Smuzhiyun struct pd6729_socket *t;
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun /* Interface Status Register */
254*4882a593Smuzhiyun status = indirect_read(socket, I365_STATUS);
255*4882a593Smuzhiyun *value = 0;
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun if ((status & I365_CS_DETECT) == I365_CS_DETECT)
258*4882a593Smuzhiyun *value |= SS_DETECT;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun /*
261*4882a593Smuzhiyun * IO cards have a different meaning of bits 0,1
262*4882a593Smuzhiyun * Also notice the inverse-logic on the bits
263*4882a593Smuzhiyun */
264*4882a593Smuzhiyun if (indirect_read(socket, I365_INTCTL) & I365_PC_IOCARD) {
265*4882a593Smuzhiyun /* IO card */
266*4882a593Smuzhiyun if (!(status & I365_CS_STSCHG))
267*4882a593Smuzhiyun *value |= SS_STSCHG;
268*4882a593Smuzhiyun } else {
269*4882a593Smuzhiyun /* non I/O card */
270*4882a593Smuzhiyun if (!(status & I365_CS_BVD1))
271*4882a593Smuzhiyun *value |= SS_BATDEAD;
272*4882a593Smuzhiyun if (!(status & I365_CS_BVD2))
273*4882a593Smuzhiyun *value |= SS_BATWARN;
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun if (status & I365_CS_WRPROT)
277*4882a593Smuzhiyun *value |= SS_WRPROT; /* card is write protected */
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun if (status & I365_CS_READY)
280*4882a593Smuzhiyun *value |= SS_READY; /* card is not busy */
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun if (status & I365_CS_POWERON)
283*4882a593Smuzhiyun *value |= SS_POWERON; /* power is applied to the card */
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun t = (socket->number) ? socket : socket + 1;
286*4882a593Smuzhiyun indirect_write(t, PD67_EXT_INDEX, PD67_EXTERN_DATA);
287*4882a593Smuzhiyun data = indirect_read16(t, PD67_EXT_DATA);
288*4882a593Smuzhiyun *value |= (data & PD67_EXD_VS1(socket->number)) ? 0 : SS_3VCARD;
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun return 0;
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun
pd6729_set_socket(struct pcmcia_socket * sock,socket_state_t * state)294*4882a593Smuzhiyun static int pd6729_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun struct pd6729_socket *socket
297*4882a593Smuzhiyun = container_of(sock, struct pd6729_socket, socket);
298*4882a593Smuzhiyun unsigned char reg, data;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun /* First, set the global controller options */
301*4882a593Smuzhiyun indirect_write(socket, I365_GBLCTL, 0x00);
302*4882a593Smuzhiyun indirect_write(socket, I365_GENCTL, 0x00);
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun /* Values for the IGENC register */
305*4882a593Smuzhiyun socket->card_irq = state->io_irq;
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun reg = 0;
308*4882a593Smuzhiyun /* The reset bit has "inverse" logic */
309*4882a593Smuzhiyun if (!(state->flags & SS_RESET))
310*4882a593Smuzhiyun reg |= I365_PC_RESET;
311*4882a593Smuzhiyun if (state->flags & SS_IOCARD)
312*4882a593Smuzhiyun reg |= I365_PC_IOCARD;
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun /* IGENC, Interrupt and General Control Register */
315*4882a593Smuzhiyun indirect_write(socket, I365_INTCTL, reg);
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun /* Power registers */
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun reg = I365_PWR_NORESET; /* default: disable resetdrv on resume */
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun if (state->flags & SS_PWR_AUTO) {
322*4882a593Smuzhiyun dev_dbg(&sock->dev, "Auto power\n");
323*4882a593Smuzhiyun reg |= I365_PWR_AUTO; /* automatic power mngmnt */
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun if (state->flags & SS_OUTPUT_ENA) {
326*4882a593Smuzhiyun dev_dbg(&sock->dev, "Power Enabled\n");
327*4882a593Smuzhiyun reg |= I365_PWR_OUT; /* enable power */
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun switch (state->Vcc) {
331*4882a593Smuzhiyun case 0:
332*4882a593Smuzhiyun break;
333*4882a593Smuzhiyun case 33:
334*4882a593Smuzhiyun dev_dbg(&sock->dev,
335*4882a593Smuzhiyun "setting voltage to Vcc to 3.3V on socket %i\n",
336*4882a593Smuzhiyun socket->number);
337*4882a593Smuzhiyun reg |= I365_VCC_5V;
338*4882a593Smuzhiyun indirect_setbit(socket, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
339*4882a593Smuzhiyun break;
340*4882a593Smuzhiyun case 50:
341*4882a593Smuzhiyun dev_dbg(&sock->dev,
342*4882a593Smuzhiyun "setting voltage to Vcc to 5V on socket %i\n",
343*4882a593Smuzhiyun socket->number);
344*4882a593Smuzhiyun reg |= I365_VCC_5V;
345*4882a593Smuzhiyun indirect_resetbit(socket, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
346*4882a593Smuzhiyun break;
347*4882a593Smuzhiyun default:
348*4882a593Smuzhiyun dev_dbg(&sock->dev,
349*4882a593Smuzhiyun "pd6729_set_socket called with invalid VCC power "
350*4882a593Smuzhiyun "value: %i\n", state->Vcc);
351*4882a593Smuzhiyun return -EINVAL;
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun switch (state->Vpp) {
355*4882a593Smuzhiyun case 0:
356*4882a593Smuzhiyun dev_dbg(&sock->dev, "not setting Vpp on socket %i\n",
357*4882a593Smuzhiyun socket->number);
358*4882a593Smuzhiyun break;
359*4882a593Smuzhiyun case 33:
360*4882a593Smuzhiyun case 50:
361*4882a593Smuzhiyun dev_dbg(&sock->dev, "setting Vpp to Vcc for socket %i\n",
362*4882a593Smuzhiyun socket->number);
363*4882a593Smuzhiyun reg |= I365_VPP1_5V;
364*4882a593Smuzhiyun break;
365*4882a593Smuzhiyun case 120:
366*4882a593Smuzhiyun dev_dbg(&sock->dev, "setting Vpp to 12.0\n");
367*4882a593Smuzhiyun reg |= I365_VPP1_12V;
368*4882a593Smuzhiyun break;
369*4882a593Smuzhiyun default:
370*4882a593Smuzhiyun dev_dbg(&sock->dev, "pd6729: pd6729_set_socket called with "
371*4882a593Smuzhiyun "invalid VPP power value: %i\n", state->Vpp);
372*4882a593Smuzhiyun return -EINVAL;
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun /* only write if changed */
376*4882a593Smuzhiyun if (reg != indirect_read(socket, I365_POWER))
377*4882a593Smuzhiyun indirect_write(socket, I365_POWER, reg);
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun if (irq_mode == 1) {
380*4882a593Smuzhiyun /* all interrupts are to be done as PCI interrupts */
381*4882a593Smuzhiyun data = PD67_EC1_INV_MGMT_IRQ | PD67_EC1_INV_CARD_IRQ;
382*4882a593Smuzhiyun } else
383*4882a593Smuzhiyun data = 0;
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun indirect_write(socket, PD67_EXT_INDEX, PD67_EXT_CTL_1);
386*4882a593Smuzhiyun indirect_write(socket, PD67_EXT_DATA, data);
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun /* Enable specific interrupt events */
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun reg = 0x00;
391*4882a593Smuzhiyun if (state->csc_mask & SS_DETECT)
392*4882a593Smuzhiyun reg |= I365_CSC_DETECT;
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun if (state->flags & SS_IOCARD) {
395*4882a593Smuzhiyun if (state->csc_mask & SS_STSCHG)
396*4882a593Smuzhiyun reg |= I365_CSC_STSCHG;
397*4882a593Smuzhiyun } else {
398*4882a593Smuzhiyun if (state->csc_mask & SS_BATDEAD)
399*4882a593Smuzhiyun reg |= I365_CSC_BVD1;
400*4882a593Smuzhiyun if (state->csc_mask & SS_BATWARN)
401*4882a593Smuzhiyun reg |= I365_CSC_BVD2;
402*4882a593Smuzhiyun if (state->csc_mask & SS_READY)
403*4882a593Smuzhiyun reg |= I365_CSC_READY;
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun if (irq_mode == 1)
406*4882a593Smuzhiyun reg |= 0x30; /* management IRQ: PCI INTA# = "irq 3" */
407*4882a593Smuzhiyun indirect_write(socket, I365_CSCINT, reg);
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun reg = indirect_read(socket, I365_INTCTL);
410*4882a593Smuzhiyun if (irq_mode == 1)
411*4882a593Smuzhiyun reg |= 0x03; /* card IRQ: PCI INTA# = "irq 3" */
412*4882a593Smuzhiyun else
413*4882a593Smuzhiyun reg |= socket->card_irq;
414*4882a593Smuzhiyun indirect_write(socket, I365_INTCTL, reg);
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun /* now clear the (probably bogus) pending stuff by doing a dummy read */
417*4882a593Smuzhiyun (void)indirect_read(socket, I365_CSC);
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun return 0;
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun
pd6729_set_io_map(struct pcmcia_socket * sock,struct pccard_io_map * io)422*4882a593Smuzhiyun static int pd6729_set_io_map(struct pcmcia_socket *sock,
423*4882a593Smuzhiyun struct pccard_io_map *io)
424*4882a593Smuzhiyun {
425*4882a593Smuzhiyun struct pd6729_socket *socket
426*4882a593Smuzhiyun = container_of(sock, struct pd6729_socket, socket);
427*4882a593Smuzhiyun unsigned char map, ioctl;
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun map = io->map;
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun /* Check error conditions */
432*4882a593Smuzhiyun if (map > 1) {
433*4882a593Smuzhiyun dev_dbg(&sock->dev, "pd6729_set_io_map with invalid map\n");
434*4882a593Smuzhiyun return -EINVAL;
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun /* Turn off the window before changing anything */
438*4882a593Smuzhiyun if (indirect_read(socket, I365_ADDRWIN) & I365_ENA_IO(map))
439*4882a593Smuzhiyun indirect_resetbit(socket, I365_ADDRWIN, I365_ENA_IO(map));
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun /* dev_dbg(&sock->dev, "set_io_map: Setting range to %x - %x\n",
442*4882a593Smuzhiyun io->start, io->stop);*/
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun /* write the new values */
445*4882a593Smuzhiyun indirect_write16(socket, I365_IO(map)+I365_W_START, io->start);
446*4882a593Smuzhiyun indirect_write16(socket, I365_IO(map)+I365_W_STOP, io->stop);
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun ioctl = indirect_read(socket, I365_IOCTL) & ~I365_IOCTL_MASK(map);
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun if (io->flags & MAP_0WS)
451*4882a593Smuzhiyun ioctl |= I365_IOCTL_0WS(map);
452*4882a593Smuzhiyun if (io->flags & MAP_16BIT)
453*4882a593Smuzhiyun ioctl |= I365_IOCTL_16BIT(map);
454*4882a593Smuzhiyun if (io->flags & MAP_AUTOSZ)
455*4882a593Smuzhiyun ioctl |= I365_IOCTL_IOCS16(map);
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun indirect_write(socket, I365_IOCTL, ioctl);
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun /* Turn the window back on if needed */
460*4882a593Smuzhiyun if (io->flags & MAP_ACTIVE)
461*4882a593Smuzhiyun indirect_setbit(socket, I365_ADDRWIN, I365_ENA_IO(map));
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun return 0;
464*4882a593Smuzhiyun }
465*4882a593Smuzhiyun
pd6729_set_mem_map(struct pcmcia_socket * sock,struct pccard_mem_map * mem)466*4882a593Smuzhiyun static int pd6729_set_mem_map(struct pcmcia_socket *sock,
467*4882a593Smuzhiyun struct pccard_mem_map *mem)
468*4882a593Smuzhiyun {
469*4882a593Smuzhiyun struct pd6729_socket *socket
470*4882a593Smuzhiyun = container_of(sock, struct pd6729_socket, socket);
471*4882a593Smuzhiyun unsigned short base, i;
472*4882a593Smuzhiyun unsigned char map;
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun map = mem->map;
475*4882a593Smuzhiyun if (map > 4) {
476*4882a593Smuzhiyun dev_warn(&sock->dev, "invalid map requested\n");
477*4882a593Smuzhiyun return -EINVAL;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun if ((mem->res->start > mem->res->end) || (mem->speed > 1000)) {
481*4882a593Smuzhiyun dev_warn(&sock->dev, "invalid invalid address / speed\n");
482*4882a593Smuzhiyun return -EINVAL;
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun /* Turn off the window before changing anything */
486*4882a593Smuzhiyun if (indirect_read(socket, I365_ADDRWIN) & I365_ENA_MEM(map))
487*4882a593Smuzhiyun indirect_resetbit(socket, I365_ADDRWIN, I365_ENA_MEM(map));
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun /* write the start address */
490*4882a593Smuzhiyun base = I365_MEM(map);
491*4882a593Smuzhiyun i = (mem->res->start >> 12) & 0x0fff;
492*4882a593Smuzhiyun if (mem->flags & MAP_16BIT)
493*4882a593Smuzhiyun i |= I365_MEM_16BIT;
494*4882a593Smuzhiyun if (mem->flags & MAP_0WS)
495*4882a593Smuzhiyun i |= I365_MEM_0WS;
496*4882a593Smuzhiyun indirect_write16(socket, base + I365_W_START, i);
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun /* write the stop address */
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun i = (mem->res->end >> 12) & 0x0fff;
501*4882a593Smuzhiyun switch (to_cycles(mem->speed)) {
502*4882a593Smuzhiyun case 0:
503*4882a593Smuzhiyun break;
504*4882a593Smuzhiyun case 1:
505*4882a593Smuzhiyun i |= I365_MEM_WS0;
506*4882a593Smuzhiyun break;
507*4882a593Smuzhiyun case 2:
508*4882a593Smuzhiyun i |= I365_MEM_WS1;
509*4882a593Smuzhiyun break;
510*4882a593Smuzhiyun default:
511*4882a593Smuzhiyun i |= I365_MEM_WS1 | I365_MEM_WS0;
512*4882a593Smuzhiyun break;
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun indirect_write16(socket, base + I365_W_STOP, i);
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun /* Take care of high byte */
518*4882a593Smuzhiyun indirect_write(socket, PD67_EXT_INDEX, PD67_MEM_PAGE(map));
519*4882a593Smuzhiyun indirect_write(socket, PD67_EXT_DATA, mem->res->start >> 24);
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun /* card start */
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun i = ((mem->card_start - mem->res->start) >> 12) & 0x3fff;
524*4882a593Smuzhiyun if (mem->flags & MAP_WRPROT)
525*4882a593Smuzhiyun i |= I365_MEM_WRPROT;
526*4882a593Smuzhiyun if (mem->flags & MAP_ATTRIB) {
527*4882a593Smuzhiyun /* dev_dbg(&sock->dev, "requesting attribute memory for "
528*4882a593Smuzhiyun "socket %i\n", socket->number);*/
529*4882a593Smuzhiyun i |= I365_MEM_REG;
530*4882a593Smuzhiyun } else {
531*4882a593Smuzhiyun /* dev_dbg(&sock->dev, "requesting normal memory for "
532*4882a593Smuzhiyun "socket %i\n", socket->number);*/
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun indirect_write16(socket, base + I365_W_OFF, i);
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun /* Enable the window if necessary */
537*4882a593Smuzhiyun if (mem->flags & MAP_ACTIVE)
538*4882a593Smuzhiyun indirect_setbit(socket, I365_ADDRWIN, I365_ENA_MEM(map));
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun return 0;
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun
pd6729_init(struct pcmcia_socket * sock)543*4882a593Smuzhiyun static int pd6729_init(struct pcmcia_socket *sock)
544*4882a593Smuzhiyun {
545*4882a593Smuzhiyun int i;
546*4882a593Smuzhiyun struct resource res = { .end = 0x0fff };
547*4882a593Smuzhiyun pccard_io_map io = { 0, 0, 0, 0, 1 };
548*4882a593Smuzhiyun pccard_mem_map mem = { .res = &res, };
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun pd6729_set_socket(sock, &dead_socket);
551*4882a593Smuzhiyun for (i = 0; i < 2; i++) {
552*4882a593Smuzhiyun io.map = i;
553*4882a593Smuzhiyun pd6729_set_io_map(sock, &io);
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun for (i = 0; i < 5; i++) {
556*4882a593Smuzhiyun mem.map = i;
557*4882a593Smuzhiyun pd6729_set_mem_map(sock, &mem);
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun return 0;
561*4882a593Smuzhiyun }
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun /* the pccard structure and its functions */
565*4882a593Smuzhiyun static struct pccard_operations pd6729_operations = {
566*4882a593Smuzhiyun .init = pd6729_init,
567*4882a593Smuzhiyun .get_status = pd6729_get_status,
568*4882a593Smuzhiyun .set_socket = pd6729_set_socket,
569*4882a593Smuzhiyun .set_io_map = pd6729_set_io_map,
570*4882a593Smuzhiyun .set_mem_map = pd6729_set_mem_map,
571*4882a593Smuzhiyun };
572*4882a593Smuzhiyun
pd6729_test(int irq,void * dev)573*4882a593Smuzhiyun static irqreturn_t pd6729_test(int irq, void *dev)
574*4882a593Smuzhiyun {
575*4882a593Smuzhiyun pr_devel("-> hit on irq %d\n", irq);
576*4882a593Smuzhiyun return IRQ_HANDLED;
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun
pd6729_check_irq(int irq)579*4882a593Smuzhiyun static int pd6729_check_irq(int irq)
580*4882a593Smuzhiyun {
581*4882a593Smuzhiyun int ret;
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun ret = request_irq(irq, pd6729_test, IRQF_PROBE_SHARED, "x",
584*4882a593Smuzhiyun pd6729_test);
585*4882a593Smuzhiyun if (ret)
586*4882a593Smuzhiyun return -1;
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun free_irq(irq, pd6729_test);
589*4882a593Smuzhiyun return 0;
590*4882a593Smuzhiyun }
591*4882a593Smuzhiyun
pd6729_isa_scan(void)592*4882a593Smuzhiyun static u_int pd6729_isa_scan(void)
593*4882a593Smuzhiyun {
594*4882a593Smuzhiyun u_int mask0, mask = 0;
595*4882a593Smuzhiyun int i;
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun if (irq_mode == 1) {
598*4882a593Smuzhiyun printk(KERN_INFO "pd6729: PCI card interrupts, "
599*4882a593Smuzhiyun "PCI status changes\n");
600*4882a593Smuzhiyun return 0;
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun mask0 = PD67_MASK;
604*4882a593Smuzhiyun
605*4882a593Smuzhiyun /* just find interrupts that aren't in use */
606*4882a593Smuzhiyun for (i = 0; i < 16; i++)
607*4882a593Smuzhiyun if ((mask0 & (1 << i)) && (pd6729_check_irq(i) == 0))
608*4882a593Smuzhiyun mask |= (1 << i);
609*4882a593Smuzhiyun
610*4882a593Smuzhiyun printk(KERN_INFO "pd6729: ISA irqs = ");
611*4882a593Smuzhiyun for (i = 0; i < 16; i++)
612*4882a593Smuzhiyun if (mask & (1<<i))
613*4882a593Smuzhiyun printk("%s%d", ((mask & ((1<<i)-1)) ? "," : ""), i);
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun if (mask == 0)
616*4882a593Smuzhiyun printk("none!");
617*4882a593Smuzhiyun else
618*4882a593Smuzhiyun printk(" polling status changes.\n");
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun return mask;
621*4882a593Smuzhiyun }
622*4882a593Smuzhiyun
pd6729_pci_probe(struct pci_dev * dev,const struct pci_device_id * id)623*4882a593Smuzhiyun static int pd6729_pci_probe(struct pci_dev *dev,
624*4882a593Smuzhiyun const struct pci_device_id *id)
625*4882a593Smuzhiyun {
626*4882a593Smuzhiyun int i, j, ret;
627*4882a593Smuzhiyun u_int mask;
628*4882a593Smuzhiyun char configbyte;
629*4882a593Smuzhiyun struct pd6729_socket *socket;
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun socket = kcalloc(MAX_SOCKETS, sizeof(struct pd6729_socket),
632*4882a593Smuzhiyun GFP_KERNEL);
633*4882a593Smuzhiyun if (!socket) {
634*4882a593Smuzhiyun dev_warn(&dev->dev, "failed to kzalloc socket.\n");
635*4882a593Smuzhiyun return -ENOMEM;
636*4882a593Smuzhiyun }
637*4882a593Smuzhiyun
638*4882a593Smuzhiyun ret = pci_enable_device(dev);
639*4882a593Smuzhiyun if (ret) {
640*4882a593Smuzhiyun dev_warn(&dev->dev, "failed to enable pci_device.\n");
641*4882a593Smuzhiyun goto err_out_free_mem;
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun if (!pci_resource_start(dev, 0)) {
645*4882a593Smuzhiyun dev_warn(&dev->dev, "refusing to load the driver as the "
646*4882a593Smuzhiyun "io_base is NULL.\n");
647*4882a593Smuzhiyun ret = -ENOMEM;
648*4882a593Smuzhiyun goto err_out_disable;
649*4882a593Smuzhiyun }
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun dev_info(&dev->dev, "Cirrus PD6729 PCI to PCMCIA Bridge at 0x%llx "
652*4882a593Smuzhiyun "on irq %d\n",
653*4882a593Smuzhiyun (unsigned long long)pci_resource_start(dev, 0), dev->irq);
654*4882a593Smuzhiyun /*
655*4882a593Smuzhiyun * Since we have no memory BARs some firmware may not
656*4882a593Smuzhiyun * have had PCI_COMMAND_MEMORY enabled, yet the device needs it.
657*4882a593Smuzhiyun */
658*4882a593Smuzhiyun pci_read_config_byte(dev, PCI_COMMAND, &configbyte);
659*4882a593Smuzhiyun if (!(configbyte & PCI_COMMAND_MEMORY)) {
660*4882a593Smuzhiyun dev_dbg(&dev->dev, "pd6729: Enabling PCI_COMMAND_MEMORY.\n");
661*4882a593Smuzhiyun configbyte |= PCI_COMMAND_MEMORY;
662*4882a593Smuzhiyun pci_write_config_byte(dev, PCI_COMMAND, configbyte);
663*4882a593Smuzhiyun }
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun ret = pci_request_regions(dev, "pd6729");
666*4882a593Smuzhiyun if (ret) {
667*4882a593Smuzhiyun dev_warn(&dev->dev, "pci request region failed.\n");
668*4882a593Smuzhiyun goto err_out_disable;
669*4882a593Smuzhiyun }
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun if (dev->irq == NO_IRQ)
672*4882a593Smuzhiyun irq_mode = 0; /* fall back to ISA interrupt mode */
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun mask = pd6729_isa_scan();
675*4882a593Smuzhiyun if (irq_mode == 0 && mask == 0) {
676*4882a593Smuzhiyun dev_warn(&dev->dev, "no ISA interrupt is available.\n");
677*4882a593Smuzhiyun ret = -ENODEV;
678*4882a593Smuzhiyun goto err_out_free_res;
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun for (i = 0; i < MAX_SOCKETS; i++) {
682*4882a593Smuzhiyun socket[i].io_base = pci_resource_start(dev, 0);
683*4882a593Smuzhiyun socket[i].socket.features |= SS_CAP_PAGE_REGS | SS_CAP_PCCARD;
684*4882a593Smuzhiyun socket[i].socket.map_size = 0x1000;
685*4882a593Smuzhiyun socket[i].socket.irq_mask = mask;
686*4882a593Smuzhiyun socket[i].socket.pci_irq = dev->irq;
687*4882a593Smuzhiyun socket[i].socket.cb_dev = dev;
688*4882a593Smuzhiyun socket[i].socket.owner = THIS_MODULE;
689*4882a593Smuzhiyun
690*4882a593Smuzhiyun socket[i].number = i;
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun socket[i].socket.ops = &pd6729_operations;
693*4882a593Smuzhiyun socket[i].socket.resource_ops = &pccard_nonstatic_ops;
694*4882a593Smuzhiyun socket[i].socket.dev.parent = &dev->dev;
695*4882a593Smuzhiyun socket[i].socket.driver_data = &socket[i];
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun pci_set_drvdata(dev, socket);
699*4882a593Smuzhiyun if (irq_mode == 1) {
700*4882a593Smuzhiyun /* Register the interrupt handler */
701*4882a593Smuzhiyun ret = request_irq(dev->irq, pd6729_interrupt, IRQF_SHARED,
702*4882a593Smuzhiyun "pd6729", socket);
703*4882a593Smuzhiyun if (ret) {
704*4882a593Smuzhiyun dev_err(&dev->dev, "Failed to register irq %d\n",
705*4882a593Smuzhiyun dev->irq);
706*4882a593Smuzhiyun goto err_out_free_res;
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun } else {
709*4882a593Smuzhiyun /* poll Card status change */
710*4882a593Smuzhiyun timer_setup(&socket->poll_timer, pd6729_interrupt_wrapper, 0);
711*4882a593Smuzhiyun mod_timer(&socket->poll_timer, jiffies + HZ);
712*4882a593Smuzhiyun }
713*4882a593Smuzhiyun
714*4882a593Smuzhiyun for (i = 0; i < MAX_SOCKETS; i++) {
715*4882a593Smuzhiyun ret = pcmcia_register_socket(&socket[i].socket);
716*4882a593Smuzhiyun if (ret) {
717*4882a593Smuzhiyun dev_warn(&dev->dev, "pcmcia_register_socket failed.\n");
718*4882a593Smuzhiyun for (j = 0; j < i ; j++)
719*4882a593Smuzhiyun pcmcia_unregister_socket(&socket[j].socket);
720*4882a593Smuzhiyun goto err_out_free_res2;
721*4882a593Smuzhiyun }
722*4882a593Smuzhiyun }
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun return 0;
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun err_out_free_res2:
727*4882a593Smuzhiyun if (irq_mode == 1)
728*4882a593Smuzhiyun free_irq(dev->irq, socket);
729*4882a593Smuzhiyun else
730*4882a593Smuzhiyun del_timer_sync(&socket->poll_timer);
731*4882a593Smuzhiyun err_out_free_res:
732*4882a593Smuzhiyun pci_release_regions(dev);
733*4882a593Smuzhiyun err_out_disable:
734*4882a593Smuzhiyun pci_disable_device(dev);
735*4882a593Smuzhiyun
736*4882a593Smuzhiyun err_out_free_mem:
737*4882a593Smuzhiyun kfree(socket);
738*4882a593Smuzhiyun return ret;
739*4882a593Smuzhiyun }
740*4882a593Smuzhiyun
pd6729_pci_remove(struct pci_dev * dev)741*4882a593Smuzhiyun static void pd6729_pci_remove(struct pci_dev *dev)
742*4882a593Smuzhiyun {
743*4882a593Smuzhiyun int i;
744*4882a593Smuzhiyun struct pd6729_socket *socket = pci_get_drvdata(dev);
745*4882a593Smuzhiyun
746*4882a593Smuzhiyun for (i = 0; i < MAX_SOCKETS; i++) {
747*4882a593Smuzhiyun /* Turn off all interrupt sources */
748*4882a593Smuzhiyun indirect_write(&socket[i], I365_CSCINT, 0);
749*4882a593Smuzhiyun indirect_write(&socket[i], I365_INTCTL, 0);
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun pcmcia_unregister_socket(&socket[i].socket);
752*4882a593Smuzhiyun }
753*4882a593Smuzhiyun
754*4882a593Smuzhiyun if (irq_mode == 1)
755*4882a593Smuzhiyun free_irq(dev->irq, socket);
756*4882a593Smuzhiyun else
757*4882a593Smuzhiyun del_timer_sync(&socket->poll_timer);
758*4882a593Smuzhiyun pci_release_regions(dev);
759*4882a593Smuzhiyun pci_disable_device(dev);
760*4882a593Smuzhiyun
761*4882a593Smuzhiyun kfree(socket);
762*4882a593Smuzhiyun }
763*4882a593Smuzhiyun
764*4882a593Smuzhiyun static const struct pci_device_id pd6729_pci_ids[] = {
765*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6729) },
766*4882a593Smuzhiyun { }
767*4882a593Smuzhiyun };
768*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pci, pd6729_pci_ids);
769*4882a593Smuzhiyun
770*4882a593Smuzhiyun static struct pci_driver pd6729_pci_driver = {
771*4882a593Smuzhiyun .name = "pd6729",
772*4882a593Smuzhiyun .id_table = pd6729_pci_ids,
773*4882a593Smuzhiyun .probe = pd6729_pci_probe,
774*4882a593Smuzhiyun .remove = pd6729_pci_remove,
775*4882a593Smuzhiyun };
776*4882a593Smuzhiyun
777*4882a593Smuzhiyun module_pci_driver(pd6729_pci_driver);
778