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