diff options
Diffstat (limited to 'drivers/net/irda/smsc-ircc2.c')
-rw-r--r-- | drivers/net/irda/smsc-ircc2.c | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index ec94ecdb103d..bbcfc8ec35a1 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c | |||
@@ -11,6 +11,7 @@ | |||
11 | * Copyright (c) 2002 Daniele Peri | 11 | * Copyright (c) 2002 Daniele Peri |
12 | * All Rights Reserved. | 12 | * All Rights Reserved. |
13 | * Copyright (c) 2002 Jean Tourrilhes | 13 | * Copyright (c) 2002 Jean Tourrilhes |
14 | * Copyright (c) 2006 Linus Walleij | ||
14 | * | 15 | * |
15 | * | 16 | * |
16 | * Based on smc-ircc.c: | 17 | * Based on smc-ircc.c: |
@@ -61,6 +62,9 @@ | |||
61 | 62 | ||
62 | #include <linux/spinlock.h> | 63 | #include <linux/spinlock.h> |
63 | #include <linux/pm.h> | 64 | #include <linux/pm.h> |
65 | #ifdef CONFIG_PCI | ||
66 | #include <linux/pci.h> | ||
67 | #endif | ||
64 | 68 | ||
65 | #include <net/irda/wrapper.h> | 69 | #include <net/irda/wrapper.h> |
66 | #include <net/irda/irda.h> | 70 | #include <net/irda/irda.h> |
@@ -100,6 +104,22 @@ MODULE_PARM_DESC(ircc_transceiver, "Transceiver type"); | |||
100 | 104 | ||
101 | /* Types */ | 105 | /* Types */ |
102 | 106 | ||
107 | #ifdef CONFIG_PCI | ||
108 | struct smsc_ircc_subsystem_configuration { | ||
109 | unsigned short vendor; /* PCI vendor ID */ | ||
110 | unsigned short device; /* PCI vendor ID */ | ||
111 | unsigned short subvendor; /* PCI subsystem vendor ID */ | ||
112 | unsigned short subdevice; /* PCI sybsystem device ID */ | ||
113 | unsigned short sir_io; /* I/O port for SIR */ | ||
114 | unsigned short fir_io; /* I/O port for FIR */ | ||
115 | unsigned char fir_irq; /* FIR IRQ */ | ||
116 | unsigned char fir_dma; /* FIR DMA */ | ||
117 | unsigned short cfg_base; /* I/O port for chip configuration */ | ||
118 | int (*preconfigure)(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); /* Preconfig function */ | ||
119 | const char *name; /* name shown as info */ | ||
120 | }; | ||
121 | #endif | ||
122 | |||
103 | struct smsc_transceiver { | 123 | struct smsc_transceiver { |
104 | char *name; | 124 | char *name; |
105 | void (*set_for_speed)(int fir_base, u32 speed); | 125 | void (*set_for_speed)(int fir_base, u32 speed); |
@@ -202,6 +222,16 @@ static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned shor | |||
202 | static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type); | 222 | static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type); |
203 | static int __init smsc_superio_fdc(unsigned short cfg_base); | 223 | static int __init smsc_superio_fdc(unsigned short cfg_base); |
204 | static int __init smsc_superio_lpc(unsigned short cfg_base); | 224 | static int __init smsc_superio_lpc(unsigned short cfg_base); |
225 | #ifdef CONFIG_PCI | ||
226 | static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf); | ||
227 | static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); | ||
228 | static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); | ||
229 | static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, | ||
230 | unsigned short ircc_fir, | ||
231 | unsigned short ircc_sir, | ||
232 | unsigned char ircc_dma, | ||
233 | unsigned char ircc_irq); | ||
234 | #endif | ||
205 | 235 | ||
206 | /* Transceivers specific functions */ | 236 | /* Transceivers specific functions */ |
207 | 237 | ||
@@ -353,6 +383,13 @@ static int __init smsc_ircc_init(void) | |||
353 | return ret; | 383 | return ret; |
354 | } | 384 | } |
355 | 385 | ||
386 | #ifdef CONFIG_PCI | ||
387 | if (smsc_ircc_preconfigure_subsystems(ircc_cfg, ircc_fir, ircc_sir, ircc_dma, ircc_irq) < 0) { | ||
388 | /* Ignore errors from preconfiguration */ | ||
389 | IRDA_ERROR("%s, Preconfiguration failed !\n", driver_name); | ||
390 | } | ||
391 | #endif | ||
392 | |||
356 | dev_count = 0; | 393 | dev_count = 0; |
357 | 394 | ||
358 | if (ircc_fir > 0 && ircc_sir > 0) { | 395 | if (ircc_fir > 0 && ircc_sir > 0) { |
@@ -2285,6 +2322,280 @@ static int __init smsc_superio_lpc(unsigned short cfg_base) | |||
2285 | return ret; | 2322 | return ret; |
2286 | } | 2323 | } |
2287 | 2324 | ||
2325 | /* | ||
2326 | * Look for some specific subsystem setups that need | ||
2327 | * pre-configuration not properly done by the BIOS (especially laptops) | ||
2328 | * This code is based in part on smcinit.c, tosh1800-smcinit.c | ||
2329 | * and tosh2450-smcinit.c. The table lists the device entries | ||
2330 | * for ISA bridges with an LPC (Local Peripheral Configurator) | ||
2331 | * that are in turn used to configure the SMSC device with default | ||
2332 | * SIR and FIR I/O ports, DMA and IRQ. | ||
2333 | */ | ||
2334 | #ifdef CONFIG_PCI | ||
2335 | #define PCIID_VENDOR_INTEL 0x8086 | ||
2336 | #define PCIID_VENDOR_ALI 0x10b9 | ||
2337 | static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __devinitdata = { | ||
2338 | { | ||
2339 | .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */ | ||
2340 | .device = 0x24cc, | ||
2341 | .subvendor = 0x103c, | ||
2342 | .subdevice = 0x088c, | ||
2343 | .sir_io = 0x02f8, /* Quite certain these are the same for nc8000 as for nc6000 */ | ||
2344 | .fir_io = 0x0130, | ||
2345 | .fir_irq = 0x09, | ||
2346 | .fir_dma = 0x03, | ||
2347 | .cfg_base = 0x004e, | ||
2348 | .preconfigure = preconfigure_through_82801, | ||
2349 | .name = "HP nc8000", | ||
2350 | }, | ||
2351 | { | ||
2352 | .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */ | ||
2353 | .device = 0x24cc, | ||
2354 | .subvendor = 0x103c, | ||
2355 | .subdevice = 0x0890, | ||
2356 | .sir_io = 0x02f8, | ||
2357 | .fir_io = 0x0130, | ||
2358 | .fir_irq = 0x09, | ||
2359 | .fir_dma = 0x03, | ||
2360 | .cfg_base = 0x004e, | ||
2361 | .preconfigure = preconfigure_through_82801, | ||
2362 | .name = "HP nc6000", | ||
2363 | }, | ||
2364 | { | ||
2365 | .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */ | ||
2366 | .device = 0x24c0, | ||
2367 | .subvendor = 0x1179, | ||
2368 | .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ | ||
2369 | .sir_io = 0x03f8, | ||
2370 | .fir_io = 0x0130, | ||
2371 | .fir_irq = 0x07, | ||
2372 | .fir_dma = 0x01, | ||
2373 | .cfg_base = 0x002e, | ||
2374 | .preconfigure = preconfigure_through_82801, | ||
2375 | .name = "Toshiba Satellite 2450", | ||
2376 | }, | ||
2377 | { | ||
2378 | .vendor = PCIID_VENDOR_INTEL, /* Intel 82801CAM ISA bridge */ | ||
2379 | .device = 0x248c, /* Some use 24cc? */ | ||
2380 | .subvendor = 0x1179, | ||
2381 | .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ | ||
2382 | .sir_io = 0x03f8, | ||
2383 | .fir_io = 0x0130, | ||
2384 | .fir_irq = 0x03, | ||
2385 | .fir_dma = 0x03, | ||
2386 | .cfg_base = 0x002e, | ||
2387 | .preconfigure = preconfigure_through_82801, | ||
2388 | .name = "Toshiba Satellite 5100/5200, Tecra 9100", | ||
2389 | }, | ||
2390 | { | ||
2391 | .vendor = PCIID_VENDOR_ALI, /* ALi M1533/M1535 PCI to ISA Bridge [Aladdin IV/V/V+] */ | ||
2392 | .device = 0x1533, | ||
2393 | .subvendor = 0x1179, | ||
2394 | .subdevice = 0xffff, /* 0xffff is "any", Not sure, 0x0001 or 0x0002 */ | ||
2395 | .sir_io = 0x02e8, | ||
2396 | .fir_io = 0x02f8, | ||
2397 | .fir_irq = 0x07, | ||
2398 | .fir_dma = 0x03, | ||
2399 | .cfg_base = 0x002e, | ||
2400 | .preconfigure = preconfigure_through_ali, | ||
2401 | .name = "Toshiba Satellite 1800", | ||
2402 | }, | ||
2403 | { } // Terminator | ||
2404 | }; | ||
2405 | |||
2406 | |||
2407 | /* | ||
2408 | * This sets up the basic SMSC parameters (FIR port, SIR port, FIR DMA, FIR IRQ) | ||
2409 | * through the chip configuration port. | ||
2410 | */ | ||
2411 | static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf) | ||
2412 | { | ||
2413 | unsigned short iobase = conf->cfg_base; | ||
2414 | unsigned char tmpbyte; | ||
2415 | |||
2416 | outb(LPC47N227_CFGACCESSKEY, iobase); // enter configuration state | ||
2417 | outb(SMSCSIOFLAT_DEVICEID_REG, iobase); // set for device ID | ||
2418 | tmpbyte = inb(iobase +1); // Read device ID | ||
2419 | IRDA_DEBUG(0, "Detected Chip id: 0x%02x, setting up registers...\n",tmpbyte); | ||
2420 | |||
2421 | /* Disable UART1 and set up SIR I/O port */ | ||
2422 | outb(0x24, iobase); // select CR24 - UART1 base addr | ||
2423 | outb(0x00, iobase + 1); // disable UART1 | ||
2424 | outb(SMSCSIOFLAT_UART2BASEADDR_REG, iobase); // select CR25 - UART2 base addr | ||
2425 | outb( (conf->sir_io >> 2), iobase + 1); // bits 2-9 of 0x3f8 | ||
2426 | tmpbyte = inb(iobase + 1); | ||
2427 | if (tmpbyte != (conf->sir_io >> 2) ) { | ||
2428 | IRDA_WARNING("ERROR: could not configure SIR ioport.\n"); | ||
2429 | return -ENXIO; | ||
2430 | } | ||
2431 | |||
2432 | /* Set up FIR IRQ channel for UART2 */ | ||
2433 | outb(SMSCSIOFLAT_UARTIRQSELECT_REG, iobase); // select CR28 - UART1,2 IRQ select | ||
2434 | tmpbyte = inb(iobase + 1); | ||
2435 | tmpbyte &= SMSCSIOFLAT_UART1IRQSELECT_MASK; // Do not touch the UART1 portion | ||
2436 | tmpbyte |= (conf->fir_irq & SMSCSIOFLAT_UART2IRQSELECT_MASK); | ||
2437 | outb(tmpbyte, iobase + 1); | ||
2438 | tmpbyte = inb(iobase + 1) & SMSCSIOFLAT_UART2IRQSELECT_MASK; | ||
2439 | if (tmpbyte != conf->fir_irq) { | ||
2440 | IRDA_WARNING("ERROR: could not configure FIR IRQ channel.\n"); | ||
2441 | return -ENXIO; | ||
2442 | } | ||
2443 | |||
2444 | /* Set up FIR I/O port */ | ||
2445 | outb(SMSCSIOFLAT_FIRBASEADDR_REG, iobase); // CR2B - SCE (FIR) base addr | ||
2446 | outb((conf->fir_io >> 3), iobase + 1); | ||
2447 | tmpbyte = inb(iobase + 1); | ||
2448 | if (tmpbyte != (conf->fir_io >> 3) ) { | ||
2449 | IRDA_WARNING("ERROR: could not configure FIR I/O port.\n"); | ||
2450 | return -ENXIO; | ||
2451 | } | ||
2452 | |||
2453 | /* Set up FIR DMA channel */ | ||
2454 | outb(SMSCSIOFLAT_FIRDMASELECT_REG, iobase); // CR2C - SCE (FIR) DMA select | ||
2455 | outb((conf->fir_dma & LPC47N227_FIRDMASELECT_MASK), iobase + 1); // DMA | ||
2456 | tmpbyte = inb(iobase + 1) & LPC47N227_FIRDMASELECT_MASK; | ||
2457 | if (tmpbyte != (conf->fir_dma & LPC47N227_FIRDMASELECT_MASK)) { | ||
2458 | IRDA_WARNING("ERROR: could not configure FIR DMA channel.\n"); | ||
2459 | return -ENXIO; | ||
2460 | } | ||
2461 | |||
2462 | outb(SMSCSIOFLAT_UARTMODE0C_REG, iobase); // CR0C - UART mode | ||
2463 | tmpbyte = inb(iobase + 1); | ||
2464 | tmpbyte &= ~SMSCSIOFLAT_UART2MODE_MASK | SMSCSIOFLAT_UART2MODE_VAL_IRDA; | ||
2465 | outb(tmpbyte, iobase + 1); // enable IrDA (HPSIR) mode, high speed | ||
2466 | |||
2467 | outb(LPC47N227_APMBOOTDRIVE_REG, iobase); // CR07 - Auto Pwr Mgt/boot drive sel | ||
2468 | tmpbyte = inb(iobase + 1); | ||
2469 | outb(tmpbyte | LPC47N227_UART2AUTOPWRDOWN_MASK, iobase + 1); // enable UART2 autopower down | ||
2470 | |||
2471 | /* This one was not part of tosh1800 */ | ||
2472 | outb(0x0a, iobase); // CR0a - ecp fifo / ir mux | ||
2473 | tmpbyte = inb(iobase + 1); | ||
2474 | outb(tmpbyte | 0x40, iobase + 1); // send active device to ir port | ||
2475 | |||
2476 | outb(LPC47N227_UART12POWER_REG, iobase); // CR02 - UART 1,2 power | ||
2477 | tmpbyte = inb(iobase + 1); | ||
2478 | outb(tmpbyte | LPC47N227_UART2POWERDOWN_MASK, iobase + 1); // UART2 power up mode, UART1 power down | ||
2479 | |||
2480 | outb(LPC47N227_FDCPOWERVALIDCONF_REG, iobase); // CR00 - FDC Power/valid config cycle | ||
2481 | tmpbyte = inb(iobase + 1); | ||
2482 | outb(tmpbyte | LPC47N227_VALID_MASK, iobase + 1); // valid config cycle done | ||
2483 | |||
2484 | outb(LPC47N227_CFGEXITKEY, iobase); // Exit configuration | ||
2485 | |||
2486 | return 0; | ||
2487 | } | ||
2488 | |||
2489 | /* 82801CAM registers */ | ||
2490 | #define VID 0x00 | ||
2491 | #define DID 0x02 | ||
2492 | #define PIRQA_ROUT 0x60 | ||
2493 | #define PCI_DMA_C 0x90 | ||
2494 | #define COM_DEC 0xe0 | ||
2495 | #define LPC_EN 0xe6 | ||
2496 | #define GEN2_DEC 0xec | ||
2497 | /* | ||
2498 | * Sets up the I/O range using the 82801CAM ISA bridge, 82801DBM LPC bridge or | ||
2499 | * Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge. They all work the same way! | ||
2500 | */ | ||
2501 | static int __init preconfigure_through_82801(struct pci_dev *dev, | ||
2502 | struct smsc_ircc_subsystem_configuration *conf) | ||
2503 | { | ||
2504 | unsigned short tmpword; | ||
2505 | int ret; | ||
2506 | |||
2507 | IRDA_MESSAGE("Setting up the SMSC device via the 82801 controller.\n"); | ||
2508 | pci_write_config_byte(dev, COM_DEC, 0x10); | ||
2509 | |||
2510 | /* Enable LPC */ | ||
2511 | pci_read_config_word(dev, LPC_EN, &tmpword); /* LPC_EN register */ | ||
2512 | tmpword &= 0xfffd; /* mask bit 1 */ | ||
2513 | tmpword |= 0x0001; /* set bit 0 : COMA addr range enable */ | ||
2514 | pci_write_config_word(dev, LPC_EN, tmpword); | ||
2515 | |||
2516 | /* Setup DMA */ | ||
2517 | pci_write_config_word(dev, PCI_DMA_C, 0xc0c0); /* LPC I/F DMA on, channel 3 -- rtm (?? PCI DMA ?) */ | ||
2518 | pci_write_config_word(dev, GEN2_DEC, 0x131); /* LPC I/F 2nd decode range */ | ||
2519 | |||
2520 | /* Pre-configure chip */ | ||
2521 | ret = preconfigure_smsc_chip(conf); | ||
2522 | |||
2523 | /* Disable LPC */ | ||
2524 | pci_read_config_word(dev, LPC_EN, &tmpword); /* LPC_EN register */ | ||
2525 | tmpword &= 0xfffc; /* mask bit 1 and bit 0, COMA addr range disable */ | ||
2526 | pci_write_config_word(dev, LPC_EN, tmpword); | ||
2527 | return ret; | ||
2528 | } | ||
2529 | |||
2530 | static int __init preconfigure_through_ali(struct pci_dev *dev, | ||
2531 | struct smsc_ircc_subsystem_configuration *conf) | ||
2532 | { | ||
2533 | /* TODO: put in ALi 1533 configuration here. */ | ||
2534 | IRDA_MESSAGE("SORRY: %s has an unsupported bridge controller (ALi): not pre-configured.\n", conf->name); | ||
2535 | return -ENODEV; | ||
2536 | } | ||
2537 | |||
2538 | static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, | ||
2539 | unsigned short ircc_fir, | ||
2540 | unsigned short ircc_sir, | ||
2541 | unsigned char ircc_dma, | ||
2542 | unsigned char ircc_irq) | ||
2543 | { | ||
2544 | struct pci_dev *dev = NULL; | ||
2545 | unsigned short ss_vendor = 0x0000; | ||
2546 | unsigned short ss_device = 0x0000; | ||
2547 | int ret = 0; | ||
2548 | |||
2549 | dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); | ||
2550 | |||
2551 | while (dev != NULL) { | ||
2552 | struct smsc_ircc_subsystem_configuration *conf; | ||
2553 | |||
2554 | /* | ||
2555 | * Cache the subsystem vendor/device: some manufacturers fail to set | ||
2556 | * this for all components, so we save it in case there is just | ||
2557 | * 0x0000 0x0000 on the device we want to check. | ||
2558 | */ | ||
2559 | if (dev->subsystem_vendor != 0x0000U) { | ||
2560 | ss_vendor = dev->subsystem_vendor; | ||
2561 | ss_device = dev->subsystem_device; | ||
2562 | } | ||
2563 | conf = subsystem_configurations; | ||
2564 | for( ; conf->subvendor; conf++) { | ||
2565 | if(conf->vendor == dev->vendor && | ||
2566 | conf->device == dev->device && | ||
2567 | conf->subvendor == ss_vendor && /* Sometimes these are cached values */ | ||
2568 | (conf->subdevice == ss_device || conf->subdevice == 0xffff)) { | ||
2569 | struct smsc_ircc_subsystem_configuration tmpconf; | ||
2570 | |||
2571 | memcpy(&tmpconf, conf, sizeof(struct smsc_ircc_subsystem_configuration)); | ||
2572 | |||
2573 | /* Override the default values with anything passed in as parameter */ | ||
2574 | if (ircc_cfg != 0) | ||
2575 | tmpconf.cfg_base = ircc_cfg; | ||
2576 | if (ircc_fir != 0) | ||
2577 | tmpconf.fir_io = ircc_fir; | ||
2578 | if (ircc_sir != 0) | ||
2579 | tmpconf.sir_io = ircc_sir; | ||
2580 | if (ircc_dma != 0xff) | ||
2581 | tmpconf.fir_dma = ircc_dma; | ||
2582 | if (ircc_irq != 0xff) | ||
2583 | tmpconf.fir_irq = ircc_irq; | ||
2584 | |||
2585 | IRDA_MESSAGE("Detected unconfigured %s SMSC IrDA chip, pre-configuring device.\n", conf->name); | ||
2586 | if (conf->preconfigure) | ||
2587 | ret = conf->preconfigure(dev, &tmpconf); | ||
2588 | else | ||
2589 | ret = -ENODEV; | ||
2590 | } | ||
2591 | } | ||
2592 | dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); | ||
2593 | } | ||
2594 | |||
2595 | return ret; | ||
2596 | } | ||
2597 | #endif // CONFIG_PCI | ||
2598 | |||
2288 | /************************************************ | 2599 | /************************************************ |
2289 | * | 2600 | * |
2290 | * Transceivers specific functions | 2601 | * Transceivers specific functions |