1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Driver for Intel I82092AA PCI-PCMCIA bridge.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * (C) 2001 Red Hat, Inc.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Author: Arjan Van De Ven <arjanv@redhat.com>
8*4882a593Smuzhiyun * Loosly based on i82365.c from the pcmcia-cs package
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <linux/kernel.h>
12*4882a593Smuzhiyun #include <linux/module.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
19*4882a593Smuzhiyun #include <pcmcia/ss.h>
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #include <linux/io.h>
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #include "i82092aa.h"
24*4882a593Smuzhiyun #include "i82365.h"
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun MODULE_LICENSE("GPL");
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun /* PCI core routines */
29*4882a593Smuzhiyun static const struct pci_device_id i82092aa_pci_ids[] = {
30*4882a593Smuzhiyun { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82092AA_0) },
31*4882a593Smuzhiyun { }
32*4882a593Smuzhiyun };
33*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pci, i82092aa_pci_ids);
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun static struct pci_driver i82092aa_pci_driver = {
36*4882a593Smuzhiyun .name = "i82092aa",
37*4882a593Smuzhiyun .id_table = i82092aa_pci_ids,
38*4882a593Smuzhiyun .probe = i82092aa_pci_probe,
39*4882a593Smuzhiyun .remove = i82092aa_pci_remove,
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun /* the pccard structure and its functions */
44*4882a593Smuzhiyun static struct pccard_operations i82092aa_operations = {
45*4882a593Smuzhiyun .init = i82092aa_init,
46*4882a593Smuzhiyun .get_status = i82092aa_get_status,
47*4882a593Smuzhiyun .set_socket = i82092aa_set_socket,
48*4882a593Smuzhiyun .set_io_map = i82092aa_set_io_map,
49*4882a593Smuzhiyun .set_mem_map = i82092aa_set_mem_map,
50*4882a593Smuzhiyun };
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun /* The card can do up to 4 sockets, allocate a structure for each of them */
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun struct socket_info {
55*4882a593Smuzhiyun int number;
56*4882a593Smuzhiyun int card_state;
57*4882a593Smuzhiyun /* 0 = no socket,
58*4882a593Smuzhiyun * 1 = empty socket,
59*4882a593Smuzhiyun * 2 = card but not initialized,
60*4882a593Smuzhiyun * 3 = operational card
61*4882a593Smuzhiyun */
62*4882a593Smuzhiyun unsigned int io_base; /* base io address of the socket */
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun struct pcmcia_socket socket;
65*4882a593Smuzhiyun struct pci_dev *dev; /* The PCI device for the socket */
66*4882a593Smuzhiyun };
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun #define MAX_SOCKETS 4
69*4882a593Smuzhiyun static struct socket_info sockets[MAX_SOCKETS];
70*4882a593Smuzhiyun static int socket_count; /* shortcut */
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun
i82092aa_pci_probe(struct pci_dev * dev,const struct pci_device_id * id)73*4882a593Smuzhiyun static int i82092aa_pci_probe(struct pci_dev *dev,
74*4882a593Smuzhiyun const struct pci_device_id *id)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun unsigned char configbyte;
77*4882a593Smuzhiyun int i, ret;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun ret = pci_enable_device(dev);
80*4882a593Smuzhiyun if (ret)
81*4882a593Smuzhiyun return ret;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun /* PCI Configuration Control */
84*4882a593Smuzhiyun pci_read_config_byte(dev, 0x40, &configbyte);
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun switch (configbyte&6) {
87*4882a593Smuzhiyun case 0:
88*4882a593Smuzhiyun socket_count = 2;
89*4882a593Smuzhiyun break;
90*4882a593Smuzhiyun case 2:
91*4882a593Smuzhiyun socket_count = 1;
92*4882a593Smuzhiyun break;
93*4882a593Smuzhiyun case 4:
94*4882a593Smuzhiyun case 6:
95*4882a593Smuzhiyun socket_count = 4;
96*4882a593Smuzhiyun break;
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun default:
99*4882a593Smuzhiyun dev_err(&dev->dev,
100*4882a593Smuzhiyun "Oops, you did something we didn't think of.\n");
101*4882a593Smuzhiyun ret = -EIO;
102*4882a593Smuzhiyun goto err_out_disable;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun dev_info(&dev->dev, "configured as a %d socket device.\n",
105*4882a593Smuzhiyun socket_count);
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun if (!request_region(pci_resource_start(dev, 0), 2, "i82092aa")) {
108*4882a593Smuzhiyun ret = -EBUSY;
109*4882a593Smuzhiyun goto err_out_disable;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun for (i = 0; i < socket_count; i++) {
113*4882a593Smuzhiyun sockets[i].card_state = 1; /* 1 = present but empty */
114*4882a593Smuzhiyun sockets[i].io_base = pci_resource_start(dev, 0);
115*4882a593Smuzhiyun sockets[i].dev = dev;
116*4882a593Smuzhiyun sockets[i].socket.features |= SS_CAP_PCCARD;
117*4882a593Smuzhiyun sockets[i].socket.map_size = 0x1000;
118*4882a593Smuzhiyun sockets[i].socket.irq_mask = 0;
119*4882a593Smuzhiyun sockets[i].socket.pci_irq = dev->irq;
120*4882a593Smuzhiyun sockets[i].socket.cb_dev = dev;
121*4882a593Smuzhiyun sockets[i].socket.owner = THIS_MODULE;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun sockets[i].number = i;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun if (card_present(i)) {
126*4882a593Smuzhiyun sockets[i].card_state = 3;
127*4882a593Smuzhiyun dev_dbg(&dev->dev, "slot %i is occupied\n", i);
128*4882a593Smuzhiyun } else {
129*4882a593Smuzhiyun dev_dbg(&dev->dev, "slot %i is vacant\n", i);
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun /* Now, specifiy that all interrupts are to be done as PCI interrupts
134*4882a593Smuzhiyun * bitmask, one bit per event, 1 = PCI interrupt, 0 = ISA interrupt
135*4882a593Smuzhiyun */
136*4882a593Smuzhiyun configbyte = 0xFF;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun /* PCI Interrupt Routing Register */
139*4882a593Smuzhiyun pci_write_config_byte(dev, 0x50, configbyte);
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun /* Register the interrupt handler */
142*4882a593Smuzhiyun dev_dbg(&dev->dev, "Requesting interrupt %i\n", dev->irq);
143*4882a593Smuzhiyun ret = request_irq(dev->irq, i82092aa_interrupt, IRQF_SHARED,
144*4882a593Smuzhiyun "i82092aa", i82092aa_interrupt);
145*4882a593Smuzhiyun if (ret) {
146*4882a593Smuzhiyun dev_err(&dev->dev, "Failed to register IRQ %d, aborting\n",
147*4882a593Smuzhiyun dev->irq);
148*4882a593Smuzhiyun goto err_out_free_res;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun for (i = 0; i < socket_count; i++) {
152*4882a593Smuzhiyun sockets[i].socket.dev.parent = &dev->dev;
153*4882a593Smuzhiyun sockets[i].socket.ops = &i82092aa_operations;
154*4882a593Smuzhiyun sockets[i].socket.resource_ops = &pccard_nonstatic_ops;
155*4882a593Smuzhiyun ret = pcmcia_register_socket(&sockets[i].socket);
156*4882a593Smuzhiyun if (ret)
157*4882a593Smuzhiyun goto err_out_free_sockets;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun return 0;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun err_out_free_sockets:
163*4882a593Smuzhiyun if (i) {
164*4882a593Smuzhiyun for (i--; i >= 0; i--)
165*4882a593Smuzhiyun pcmcia_unregister_socket(&sockets[i].socket);
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun free_irq(dev->irq, i82092aa_interrupt);
168*4882a593Smuzhiyun err_out_free_res:
169*4882a593Smuzhiyun release_region(pci_resource_start(dev, 0), 2);
170*4882a593Smuzhiyun err_out_disable:
171*4882a593Smuzhiyun pci_disable_device(dev);
172*4882a593Smuzhiyun return ret;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
i82092aa_pci_remove(struct pci_dev * dev)175*4882a593Smuzhiyun static void i82092aa_pci_remove(struct pci_dev *dev)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun int i;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun free_irq(dev->irq, i82092aa_interrupt);
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun for (i = 0; i < socket_count; i++)
182*4882a593Smuzhiyun pcmcia_unregister_socket(&sockets[i].socket);
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun static DEFINE_SPINLOCK(port_lock);
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun /* basic value read/write functions */
188*4882a593Smuzhiyun
indirect_read(int socket,unsigned short reg)189*4882a593Smuzhiyun static unsigned char indirect_read(int socket, unsigned short reg)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun unsigned short int port;
192*4882a593Smuzhiyun unsigned char val;
193*4882a593Smuzhiyun unsigned long flags;
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun spin_lock_irqsave(&port_lock, flags);
196*4882a593Smuzhiyun reg += socket * 0x40;
197*4882a593Smuzhiyun port = sockets[socket].io_base;
198*4882a593Smuzhiyun outb(reg, port);
199*4882a593Smuzhiyun val = inb(port+1);
200*4882a593Smuzhiyun spin_unlock_irqrestore(&port_lock, flags);
201*4882a593Smuzhiyun return val;
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun
indirect_write(int socket,unsigned short reg,unsigned char value)204*4882a593Smuzhiyun static void indirect_write(int socket, unsigned short reg, unsigned char value)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun unsigned short int port;
207*4882a593Smuzhiyun unsigned long flags;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun spin_lock_irqsave(&port_lock, flags);
210*4882a593Smuzhiyun reg = reg + socket * 0x40;
211*4882a593Smuzhiyun port = sockets[socket].io_base;
212*4882a593Smuzhiyun outb(reg, port);
213*4882a593Smuzhiyun outb(value, port+1);
214*4882a593Smuzhiyun spin_unlock_irqrestore(&port_lock, flags);
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun
indirect_setbit(int socket,unsigned short reg,unsigned char mask)217*4882a593Smuzhiyun static void indirect_setbit(int socket, unsigned short reg, unsigned char mask)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun unsigned short int port;
220*4882a593Smuzhiyun unsigned char val;
221*4882a593Smuzhiyun unsigned long flags;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun spin_lock_irqsave(&port_lock, flags);
224*4882a593Smuzhiyun reg = reg + socket * 0x40;
225*4882a593Smuzhiyun port = sockets[socket].io_base;
226*4882a593Smuzhiyun outb(reg, port);
227*4882a593Smuzhiyun val = inb(port+1);
228*4882a593Smuzhiyun val |= mask;
229*4882a593Smuzhiyun outb(reg, port);
230*4882a593Smuzhiyun outb(val, port+1);
231*4882a593Smuzhiyun spin_unlock_irqrestore(&port_lock, flags);
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun
indirect_resetbit(int socket,unsigned short reg,unsigned char mask)235*4882a593Smuzhiyun static void indirect_resetbit(int socket,
236*4882a593Smuzhiyun unsigned short reg, unsigned char mask)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun unsigned short int port;
239*4882a593Smuzhiyun unsigned char val;
240*4882a593Smuzhiyun unsigned long flags;
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun spin_lock_irqsave(&port_lock, flags);
243*4882a593Smuzhiyun reg = reg + socket * 0x40;
244*4882a593Smuzhiyun port = sockets[socket].io_base;
245*4882a593Smuzhiyun outb(reg, port);
246*4882a593Smuzhiyun val = inb(port+1);
247*4882a593Smuzhiyun val &= ~mask;
248*4882a593Smuzhiyun outb(reg, port);
249*4882a593Smuzhiyun outb(val, port+1);
250*4882a593Smuzhiyun spin_unlock_irqrestore(&port_lock, flags);
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun
indirect_write16(int socket,unsigned short reg,unsigned short value)253*4882a593Smuzhiyun static void indirect_write16(int socket,
254*4882a593Smuzhiyun unsigned short reg, unsigned short value)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun unsigned short int port;
257*4882a593Smuzhiyun unsigned char val;
258*4882a593Smuzhiyun unsigned long flags;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun spin_lock_irqsave(&port_lock, flags);
261*4882a593Smuzhiyun reg = reg + socket * 0x40;
262*4882a593Smuzhiyun port = sockets[socket].io_base;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun outb(reg, port);
265*4882a593Smuzhiyun val = value & 255;
266*4882a593Smuzhiyun outb(val, port+1);
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun reg++;
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun outb(reg, port);
271*4882a593Smuzhiyun val = value>>8;
272*4882a593Smuzhiyun outb(val, port+1);
273*4882a593Smuzhiyun spin_unlock_irqrestore(&port_lock, flags);
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun /* simple helper functions */
277*4882a593Smuzhiyun /* External clock time, in nanoseconds. 120 ns = 8.33 MHz */
278*4882a593Smuzhiyun static int cycle_time = 120;
279*4882a593Smuzhiyun
to_cycles(int ns)280*4882a593Smuzhiyun static int to_cycles(int ns)
281*4882a593Smuzhiyun {
282*4882a593Smuzhiyun if (cycle_time != 0)
283*4882a593Smuzhiyun return ns/cycle_time;
284*4882a593Smuzhiyun else
285*4882a593Smuzhiyun return 0;
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun /* Interrupt handler functionality */
290*4882a593Smuzhiyun
i82092aa_interrupt(int irq,void * dev)291*4882a593Smuzhiyun static irqreturn_t i82092aa_interrupt(int irq, void *dev)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun int i;
294*4882a593Smuzhiyun int loopcount = 0;
295*4882a593Smuzhiyun int handled = 0;
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun unsigned int events, active = 0;
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun while (1) {
300*4882a593Smuzhiyun loopcount++;
301*4882a593Smuzhiyun if (loopcount > 20) {
302*4882a593Smuzhiyun pr_err("i82092aa: infinite eventloop in interrupt\n");
303*4882a593Smuzhiyun break;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun active = 0;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun for (i = 0; i < socket_count; i++) {
309*4882a593Smuzhiyun int csc;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun /* Inactive socket, should not happen */
312*4882a593Smuzhiyun if (sockets[i].card_state == 0)
313*4882a593Smuzhiyun continue;
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun /* card status change register */
316*4882a593Smuzhiyun csc = indirect_read(i, I365_CSC);
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun if (csc == 0) /* no events on this socket */
319*4882a593Smuzhiyun continue;
320*4882a593Smuzhiyun handled = 1;
321*4882a593Smuzhiyun events = 0;
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun if (csc & I365_CSC_DETECT) {
324*4882a593Smuzhiyun events |= SS_DETECT;
325*4882a593Smuzhiyun dev_info(&sockets[i].dev->dev,
326*4882a593Smuzhiyun "Card detected in socket %i!\n", i);
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun if (indirect_read(i, I365_INTCTL) & I365_PC_IOCARD) {
330*4882a593Smuzhiyun /* For IO/CARDS, bit 0 means "read the card" */
331*4882a593Smuzhiyun if (csc & I365_CSC_STSCHG)
332*4882a593Smuzhiyun events |= SS_STSCHG;
333*4882a593Smuzhiyun } else {
334*4882a593Smuzhiyun /* Check for battery/ready events */
335*4882a593Smuzhiyun if (csc & I365_CSC_BVD1)
336*4882a593Smuzhiyun events |= SS_BATDEAD;
337*4882a593Smuzhiyun if (csc & I365_CSC_BVD2)
338*4882a593Smuzhiyun events |= SS_BATWARN;
339*4882a593Smuzhiyun if (csc & I365_CSC_READY)
340*4882a593Smuzhiyun events |= SS_READY;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun if (events)
344*4882a593Smuzhiyun pcmcia_parse_events(&sockets[i].socket, events);
345*4882a593Smuzhiyun active |= events;
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun if (active == 0) /* no more events to handle */
349*4882a593Smuzhiyun break;
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun return IRQ_RETVAL(handled);
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun /* socket functions */
357*4882a593Smuzhiyun
card_present(int socketno)358*4882a593Smuzhiyun static int card_present(int socketno)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun unsigned int val;
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun if ((socketno < 0) || (socketno >= MAX_SOCKETS))
363*4882a593Smuzhiyun return 0;
364*4882a593Smuzhiyun if (sockets[socketno].io_base == 0)
365*4882a593Smuzhiyun return 0;
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun val = indirect_read(socketno, 1); /* Interface status register */
369*4882a593Smuzhiyun if ((val&12) == 12)
370*4882a593Smuzhiyun return 1;
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun return 0;
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun
set_bridge_state(int sock)375*4882a593Smuzhiyun static void set_bridge_state(int sock)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun indirect_write(sock, I365_GBLCTL, 0x00);
378*4882a593Smuzhiyun indirect_write(sock, I365_GENCTL, 0x00);
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun indirect_setbit(sock, I365_INTCTL, 0x08);
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun
i82092aa_init(struct pcmcia_socket * sock)384*4882a593Smuzhiyun static int i82092aa_init(struct pcmcia_socket *sock)
385*4882a593Smuzhiyun {
386*4882a593Smuzhiyun int i;
387*4882a593Smuzhiyun struct resource res = { .start = 0, .end = 0x0fff };
388*4882a593Smuzhiyun pccard_io_map io = { 0, 0, 0, 0, 1 };
389*4882a593Smuzhiyun pccard_mem_map mem = { .res = &res, };
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun for (i = 0; i < 2; i++) {
392*4882a593Smuzhiyun io.map = i;
393*4882a593Smuzhiyun i82092aa_set_io_map(sock, &io);
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun for (i = 0; i < 5; i++) {
396*4882a593Smuzhiyun mem.map = i;
397*4882a593Smuzhiyun i82092aa_set_mem_map(sock, &mem);
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun return 0;
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun
i82092aa_get_status(struct pcmcia_socket * socket,u_int * value)403*4882a593Smuzhiyun static int i82092aa_get_status(struct pcmcia_socket *socket, u_int *value)
404*4882a593Smuzhiyun {
405*4882a593Smuzhiyun unsigned int sock = container_of(socket,
406*4882a593Smuzhiyun struct socket_info, socket)->number;
407*4882a593Smuzhiyun unsigned int status;
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun /* Interface Status Register */
410*4882a593Smuzhiyun status = indirect_read(sock, I365_STATUS);
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun *value = 0;
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun if ((status & I365_CS_DETECT) == I365_CS_DETECT)
415*4882a593Smuzhiyun *value |= SS_DETECT;
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun /* IO cards have a different meaning of bits 0,1 */
418*4882a593Smuzhiyun /* Also notice the inverse-logic on the bits */
419*4882a593Smuzhiyun if (indirect_read(sock, I365_INTCTL) & I365_PC_IOCARD) {
420*4882a593Smuzhiyun /* IO card */
421*4882a593Smuzhiyun if (!(status & I365_CS_STSCHG))
422*4882a593Smuzhiyun *value |= SS_STSCHG;
423*4882a593Smuzhiyun } else { /* non I/O card */
424*4882a593Smuzhiyun if (!(status & I365_CS_BVD1))
425*4882a593Smuzhiyun *value |= SS_BATDEAD;
426*4882a593Smuzhiyun if (!(status & I365_CS_BVD2))
427*4882a593Smuzhiyun *value |= SS_BATWARN;
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun if (status & I365_CS_WRPROT)
431*4882a593Smuzhiyun (*value) |= SS_WRPROT; /* card is write protected */
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun if (status & I365_CS_READY)
434*4882a593Smuzhiyun (*value) |= SS_READY; /* card is not busy */
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun if (status & I365_CS_POWERON)
437*4882a593Smuzhiyun (*value) |= SS_POWERON; /* power is applied to the card */
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun return 0;
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun
i82092aa_set_socket(struct pcmcia_socket * socket,socket_state_t * state)443*4882a593Smuzhiyun static int i82092aa_set_socket(struct pcmcia_socket *socket,
444*4882a593Smuzhiyun socket_state_t *state)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun struct socket_info *sock_info = container_of(socket, struct socket_info,
447*4882a593Smuzhiyun socket);
448*4882a593Smuzhiyun unsigned int sock = sock_info->number;
449*4882a593Smuzhiyun unsigned char reg;
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun /* First, set the global controller options */
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun set_bridge_state(sock);
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun /* Values for the IGENC register */
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun reg = 0;
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun /* The reset bit has "inverse" logic */
460*4882a593Smuzhiyun if (!(state->flags & SS_RESET))
461*4882a593Smuzhiyun reg = reg | I365_PC_RESET;
462*4882a593Smuzhiyun if (state->flags & SS_IOCARD)
463*4882a593Smuzhiyun reg = reg | I365_PC_IOCARD;
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun /* IGENC, Interrupt and General Control Register */
466*4882a593Smuzhiyun indirect_write(sock, I365_INTCTL, reg);
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun /* Power registers */
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun reg = I365_PWR_NORESET; /* default: disable resetdrv on resume */
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun if (state->flags & SS_PWR_AUTO) {
473*4882a593Smuzhiyun dev_info(&sock_info->dev->dev, "Auto power\n");
474*4882a593Smuzhiyun reg |= I365_PWR_AUTO; /* automatic power mngmnt */
475*4882a593Smuzhiyun }
476*4882a593Smuzhiyun if (state->flags & SS_OUTPUT_ENA) {
477*4882a593Smuzhiyun dev_info(&sock_info->dev->dev, "Power Enabled\n");
478*4882a593Smuzhiyun reg |= I365_PWR_OUT; /* enable power */
479*4882a593Smuzhiyun }
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun switch (state->Vcc) {
482*4882a593Smuzhiyun case 0:
483*4882a593Smuzhiyun break;
484*4882a593Smuzhiyun case 50:
485*4882a593Smuzhiyun dev_info(&sock_info->dev->dev,
486*4882a593Smuzhiyun "setting voltage to Vcc to 5V on socket %i\n",
487*4882a593Smuzhiyun sock);
488*4882a593Smuzhiyun reg |= I365_VCC_5V;
489*4882a593Smuzhiyun break;
490*4882a593Smuzhiyun default:
491*4882a593Smuzhiyun dev_err(&sock_info->dev->dev,
492*4882a593Smuzhiyun "%s called with invalid VCC power value: %i",
493*4882a593Smuzhiyun __func__, state->Vcc);
494*4882a593Smuzhiyun return -EINVAL;
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun switch (state->Vpp) {
498*4882a593Smuzhiyun case 0:
499*4882a593Smuzhiyun dev_info(&sock_info->dev->dev,
500*4882a593Smuzhiyun "not setting Vpp on socket %i\n", sock);
501*4882a593Smuzhiyun break;
502*4882a593Smuzhiyun case 50:
503*4882a593Smuzhiyun dev_info(&sock_info->dev->dev,
504*4882a593Smuzhiyun "setting Vpp to 5.0 for socket %i\n", sock);
505*4882a593Smuzhiyun reg |= I365_VPP1_5V | I365_VPP2_5V;
506*4882a593Smuzhiyun break;
507*4882a593Smuzhiyun case 120:
508*4882a593Smuzhiyun dev_info(&sock_info->dev->dev, "setting Vpp to 12.0\n");
509*4882a593Smuzhiyun reg |= I365_VPP1_12V | I365_VPP2_12V;
510*4882a593Smuzhiyun break;
511*4882a593Smuzhiyun default:
512*4882a593Smuzhiyun dev_err(&sock_info->dev->dev,
513*4882a593Smuzhiyun "%s called with invalid VPP power value: %i",
514*4882a593Smuzhiyun __func__, state->Vcc);
515*4882a593Smuzhiyun return -EINVAL;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun if (reg != indirect_read(sock, I365_POWER)) /* only write if changed */
519*4882a593Smuzhiyun indirect_write(sock, I365_POWER, reg);
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun /* Enable specific interrupt events */
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun reg = 0x00;
524*4882a593Smuzhiyun if (state->csc_mask & SS_DETECT)
525*4882a593Smuzhiyun reg |= I365_CSC_DETECT;
526*4882a593Smuzhiyun if (state->flags & SS_IOCARD) {
527*4882a593Smuzhiyun if (state->csc_mask & SS_STSCHG)
528*4882a593Smuzhiyun reg |= I365_CSC_STSCHG;
529*4882a593Smuzhiyun } else {
530*4882a593Smuzhiyun if (state->csc_mask & SS_BATDEAD)
531*4882a593Smuzhiyun reg |= I365_CSC_BVD1;
532*4882a593Smuzhiyun if (state->csc_mask & SS_BATWARN)
533*4882a593Smuzhiyun reg |= I365_CSC_BVD2;
534*4882a593Smuzhiyun if (state->csc_mask & SS_READY)
535*4882a593Smuzhiyun reg |= I365_CSC_READY;
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun /* now write the value and clear the (probably bogus) pending stuff
540*4882a593Smuzhiyun * by doing a dummy read
541*4882a593Smuzhiyun */
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun indirect_write(sock, I365_CSCINT, reg);
544*4882a593Smuzhiyun (void)indirect_read(sock, I365_CSC);
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun return 0;
547*4882a593Smuzhiyun }
548*4882a593Smuzhiyun
i82092aa_set_io_map(struct pcmcia_socket * socket,struct pccard_io_map * io)549*4882a593Smuzhiyun static int i82092aa_set_io_map(struct pcmcia_socket *socket,
550*4882a593Smuzhiyun struct pccard_io_map *io)
551*4882a593Smuzhiyun {
552*4882a593Smuzhiyun struct socket_info *sock_info = container_of(socket, struct socket_info,
553*4882a593Smuzhiyun socket);
554*4882a593Smuzhiyun unsigned int sock = sock_info->number;
555*4882a593Smuzhiyun unsigned char map, ioctl;
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun map = io->map;
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun /* Check error conditions */
560*4882a593Smuzhiyun if (map > 1)
561*4882a593Smuzhiyun return -EINVAL;
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun if ((io->start > 0xffff) || (io->stop > 0xffff)
564*4882a593Smuzhiyun || (io->stop < io->start))
565*4882a593Smuzhiyun return -EINVAL;
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun /* Turn off the window before changing anything */
568*4882a593Smuzhiyun if (indirect_read(sock, I365_ADDRWIN) & I365_ENA_IO(map))
569*4882a593Smuzhiyun indirect_resetbit(sock, I365_ADDRWIN, I365_ENA_IO(map));
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun /* write the new values */
572*4882a593Smuzhiyun indirect_write16(sock, I365_IO(map)+I365_W_START, io->start);
573*4882a593Smuzhiyun indirect_write16(sock, I365_IO(map)+I365_W_STOP, io->stop);
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun ioctl = indirect_read(sock, I365_IOCTL) & ~I365_IOCTL_MASK(map);
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun if (io->flags & (MAP_16BIT|MAP_AUTOSZ))
578*4882a593Smuzhiyun ioctl |= I365_IOCTL_16BIT(map);
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun indirect_write(sock, I365_IOCTL, ioctl);
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun /* Turn the window back on if needed */
583*4882a593Smuzhiyun if (io->flags & MAP_ACTIVE)
584*4882a593Smuzhiyun indirect_setbit(sock, I365_ADDRWIN, I365_ENA_IO(map));
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun return 0;
587*4882a593Smuzhiyun }
588*4882a593Smuzhiyun
i82092aa_set_mem_map(struct pcmcia_socket * socket,struct pccard_mem_map * mem)589*4882a593Smuzhiyun static int i82092aa_set_mem_map(struct pcmcia_socket *socket,
590*4882a593Smuzhiyun struct pccard_mem_map *mem)
591*4882a593Smuzhiyun {
592*4882a593Smuzhiyun struct socket_info *sock_info = container_of(socket, struct socket_info,
593*4882a593Smuzhiyun socket);
594*4882a593Smuzhiyun unsigned int sock = sock_info->number;
595*4882a593Smuzhiyun struct pci_bus_region region;
596*4882a593Smuzhiyun unsigned short base, i;
597*4882a593Smuzhiyun unsigned char map;
598*4882a593Smuzhiyun
599*4882a593Smuzhiyun pcibios_resource_to_bus(sock_info->dev->bus, ®ion, mem->res);
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun map = mem->map;
602*4882a593Smuzhiyun if (map > 4)
603*4882a593Smuzhiyun return -EINVAL;
604*4882a593Smuzhiyun
605*4882a593Smuzhiyun if ((mem->card_start > 0x3ffffff) || (region.start > region.end) ||
606*4882a593Smuzhiyun (mem->speed > 1000)) {
607*4882a593Smuzhiyun dev_err(&sock_info->dev->dev,
608*4882a593Smuzhiyun "invalid mem map for socket %i: %llx to %llx with a start of %x\n",
609*4882a593Smuzhiyun sock,
610*4882a593Smuzhiyun (unsigned long long)region.start,
611*4882a593Smuzhiyun (unsigned long long)region.end,
612*4882a593Smuzhiyun mem->card_start);
613*4882a593Smuzhiyun return -EINVAL;
614*4882a593Smuzhiyun }
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun /* Turn off the window before changing anything */
617*4882a593Smuzhiyun if (indirect_read(sock, I365_ADDRWIN) & I365_ENA_MEM(map))
618*4882a593Smuzhiyun indirect_resetbit(sock, I365_ADDRWIN, I365_ENA_MEM(map));
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun /* write the start address */
621*4882a593Smuzhiyun base = I365_MEM(map);
622*4882a593Smuzhiyun i = (region.start >> 12) & 0x0fff;
623*4882a593Smuzhiyun if (mem->flags & MAP_16BIT)
624*4882a593Smuzhiyun i |= I365_MEM_16BIT;
625*4882a593Smuzhiyun if (mem->flags & MAP_0WS)
626*4882a593Smuzhiyun i |= I365_MEM_0WS;
627*4882a593Smuzhiyun indirect_write16(sock, base+I365_W_START, i);
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun /* write the stop address */
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun i = (region.end >> 12) & 0x0fff;
632*4882a593Smuzhiyun switch (to_cycles(mem->speed)) {
633*4882a593Smuzhiyun case 0:
634*4882a593Smuzhiyun break;
635*4882a593Smuzhiyun case 1:
636*4882a593Smuzhiyun i |= I365_MEM_WS0;
637*4882a593Smuzhiyun break;
638*4882a593Smuzhiyun case 2:
639*4882a593Smuzhiyun i |= I365_MEM_WS1;
640*4882a593Smuzhiyun break;
641*4882a593Smuzhiyun default:
642*4882a593Smuzhiyun i |= I365_MEM_WS1 | I365_MEM_WS0;
643*4882a593Smuzhiyun break;
644*4882a593Smuzhiyun }
645*4882a593Smuzhiyun
646*4882a593Smuzhiyun indirect_write16(sock, base+I365_W_STOP, i);
647*4882a593Smuzhiyun
648*4882a593Smuzhiyun /* card start */
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun i = ((mem->card_start - region.start) >> 12) & 0x3fff;
651*4882a593Smuzhiyun if (mem->flags & MAP_WRPROT)
652*4882a593Smuzhiyun i |= I365_MEM_WRPROT;
653*4882a593Smuzhiyun if (mem->flags & MAP_ATTRIB)
654*4882a593Smuzhiyun i |= I365_MEM_REG;
655*4882a593Smuzhiyun indirect_write16(sock, base+I365_W_OFF, i);
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun /* Enable the window if necessary */
658*4882a593Smuzhiyun if (mem->flags & MAP_ACTIVE)
659*4882a593Smuzhiyun indirect_setbit(sock, I365_ADDRWIN, I365_ENA_MEM(map));
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun return 0;
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun
i82092aa_module_init(void)664*4882a593Smuzhiyun static int i82092aa_module_init(void)
665*4882a593Smuzhiyun {
666*4882a593Smuzhiyun return pci_register_driver(&i82092aa_pci_driver);
667*4882a593Smuzhiyun }
668*4882a593Smuzhiyun
i82092aa_module_exit(void)669*4882a593Smuzhiyun static void i82092aa_module_exit(void)
670*4882a593Smuzhiyun {
671*4882a593Smuzhiyun pci_unregister_driver(&i82092aa_pci_driver);
672*4882a593Smuzhiyun if (sockets[0].io_base > 0)
673*4882a593Smuzhiyun release_region(sockets[0].io_base, 2);
674*4882a593Smuzhiyun }
675*4882a593Smuzhiyun
676*4882a593Smuzhiyun module_init(i82092aa_module_init);
677*4882a593Smuzhiyun module_exit(i82092aa_module_exit);
678*4882a593Smuzhiyun
679