superio.c revision 16541c8745e28f62b3dcb6cb354b73c9c01ea178
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*      National Semiconductor NS87560UBD Super I/O controller used in
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      HP [BCJ]x000 workstations.
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      This chip is a horrid piece of engineering, and National
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      denies any knowledge of its existence. Thus no datasheet is
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      available off www.national.com.
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	(C) Copyright 2000 Linuxcare, Inc.
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 	(C) Copyright 2000 Linuxcare Canada, Inc.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	(C) Copyright 2000 Martin K. Petersen <mkp@linuxcare.com>
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 	(C) Copyright 2000 Alex deVries <alex@onefishtwo.ca>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      (C) Copyright 2001 John Marvin <jsm fc hp com>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      (C) Copyright 2003 Grant Grundler <grundler parisc-linux org>
147efe1611b2db9025ffc52a686897ab91820caeb4Kyle McMartin *	(C) Copyright 2005 Kyle McMartin <kyle@parisc-linux.org>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	This program is free software; you can redistribute it and/or
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	modify it under the terms of the GNU General Public License as
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	published by the Free Software Foundation; either version 2 of
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	the License, or (at your option) any later version.
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	The initial version of this is by Martin Peterson.  Alex deVries
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	has spent a bit of time trying to coax it into working.
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Major changes to get basic interrupt infrastructure working to
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      hopefully be able to support all SuperIO devices. Currently
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      works with serial. -- John Marvin <jsm@fc.hp.com>
27a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin *
28a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin *	Converted superio_init() to be a PCI_FIXUP_FINAL callee.
29a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin *         -- Kyle McMartin <kyle@parisc-linux.org>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* NOTES:
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function 0 is an IDE controller. It is identical to a PC87415 IDE
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * controller (and identifies itself as such).
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function 1 is a "Legacy I/O" controller. Under this function is a
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * whole mess of legacy I/O peripherals. Of course, HP hasn't enabled
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * all the functionality in hardware, but the following is available:
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Two 16550A compatible serial controllers
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      An IEEE 1284 compatible parallel port
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      A floppy disk controller
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function 2 is a USB controller.
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We must be incredibly careful during initialization.  Since all
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupts are routed through function 1 (which is not allowed by
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the PCI spec), we need to program the PICs on the legacy I/O port
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * *before* we attempt to set up IDE and USB.  @#$!&
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * According to HP, devices are only enabled by firmware if they have
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a physical device connected.
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Configuration register bits:
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     0x5A: FDC, SP1, IDE1, SP2, IDE2, PAR, Reserved, P92
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     0x5B: RTC, 8259, 8254, DMA1, DMA2, KBC, P61, APM
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h>
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/parport.h>
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/parport_pc.h>
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/termios.h>
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h>
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial_core.h>
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/hardware.h>
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/superio.h>
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct superio_device sio_dev;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef DEBUG_SUPERIO_INIT
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_SUPERIO_INIT
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG_INIT(x...)  printk(x)
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG_INIT(x...)
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9216541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin#define SUPERIO	"SuperIO"
9316541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin#define PFX	SUPERIO ": "
9416541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic irqreturn_t
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssuperio_interrupt(int parent_irq, void *devp, struct pt_regs *regs)
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 results;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 local_irq;
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Poll the 8259 to see if there's an interrupt. */
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (OCW3_POLL,IC_PIC1+0);
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	results = inb(IC_PIC1+0);
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Bit    7:	1 = active Interrupt; 0 = no Interrupt pending
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Bits 6-3:	zero
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Bits 2-0:	highest priority, active requesting interrupt ID (0-7)
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((results & 0x80) == 0) {
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* I suspect "spurious" interrupts are from unmasking an IRQ.
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * We don't know if an interrupt was/is pending and thus
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * just call the handler for that IRQ as if it were pending.
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return IRQ_NONE;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check to see which device is interrupting */
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq = results & 0x0f;
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (local_irq == 2 || local_irq > 7) {
12316541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin		printk(KERN_ERR PFX "slave interrupted!\n");
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return IRQ_HANDLED;
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (local_irq == 7) {
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Could be spurious. Check in service bits */
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(OCW3_ISR,IC_PIC1+0);
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		results = inb(IC_PIC1+0);
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((results & 0x80) == 0) { /* if ISR7 not set: spurious */
13416541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin			printk(KERN_WARNING PFX "spurious interrupt!\n");
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return IRQ_HANDLED;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Call the appropriate device's interrupt */
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__do_IRQ(local_irq, regs);
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set EOI - forces a new interrupt if a lower priority device
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * still needs service.
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb((OCW2_SEOI|local_irq),IC_PIC1 + 0);
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_HANDLED;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Initialize Super I/O device */
150a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartinstatic void
151a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartinsuperio_init(struct pci_dev *pcidev)
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
153a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin	struct superio_device *sio = &sio_dev;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_dev *pdev = sio->lio_pdev;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 word;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if (sio->suckyio_irq_enabled)
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!pdev) BUG();
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!sio->usb_pdev) BUG();
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* use the IRQ iosapic found for USB INT D... */
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pdev->irq = sio->usb_pdev->irq;
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* ...then properly fixup the USB to point at suckyio PIC */
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sio->usb_pdev->irq = superio_fixup_irq(sio->usb_pdev);
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16916541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin	printk(KERN_INFO PFX "Found NS87560 Legacy I/O device at %s (IRQ %i) \n",
170a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin	       pci_name(pdev), pdev->irq);
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_read_config_dword (pdev, SIO_SP1BAR, &sio->sp1_base);
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sio->sp1_base &= ~1;
17416541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin	printk(KERN_INFO PFX "Serial port 1 at 0x%x\n", sio->sp1_base);
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_read_config_dword (pdev, SIO_SP2BAR, &sio->sp2_base);
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sio->sp2_base &= ~1;
17816541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin	printk(KERN_INFO PFX "Serial port 2 at 0x%x\n", sio->sp2_base);
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_read_config_dword (pdev, SIO_PPBAR, &sio->pp_base);
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sio->pp_base &= ~1;
18216541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin	printk(KERN_INFO PFX "Parallel port at 0x%x\n", sio->pp_base);
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_read_config_dword (pdev, SIO_FDCBAR, &sio->fdc_base);
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sio->fdc_base &= ~1;
18616541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin	printk(KERN_INFO PFX "Floppy controller at 0x%x\n", sio->fdc_base);
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_read_config_dword (pdev, SIO_ACPIBAR, &sio->acpi_base);
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sio->acpi_base &= ~1;
18916541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin	printk(KERN_INFO PFX "ACPI at 0x%x\n", sio->acpi_base);
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	request_region (IC_PIC1, 0x1f, "pic1");
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	request_region (IC_PIC2, 0x1f, "pic2");
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	request_region (sio->acpi_base, 0x1f, "acpi");
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Enable the legacy I/O function */
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        pci_read_config_word (pdev, PCI_COMMAND, &word);
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO;
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_write_config_word (pdev, PCI_COMMAND, word);
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_set_master (pdev);
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_enable_device(pdev);
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Next project is programming the onboard interrupt controllers.
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * PDC hasn't done this for us, since it's using polled I/O.
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * XXX Use dword writes to avoid bugs in Elroy or Suckyio Config
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *     space access.  PCI is by nature a 32-bit bus and config
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *     space can be sensitive to that.
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* 0x64 - 0x67 :
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DMA Rtg 2
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DMA Rtg 3
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DMA Chan Ctl
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		TRIGGER_1    == 0x82   USB & IDE level triggered, rest to edge
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*/
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_write_config_dword (pdev, 0x64,         0x82000000U);
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* 0x68 - 0x6b :
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		TRIGGER_2    == 0x00   all edge triggered (not used)
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CFG_IR_SER   == 0x43   SerPort1 = IRQ3, SerPort2 = IRQ4
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CFG_IR_PF    == 0x65   ParPort  = IRQ5, FloppyCtlr = IRQ6
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CFG_IR_IDE   == 0x07   IDE1 = IRQ7, reserved
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*/
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_write_config_dword (pdev, TRIGGER_2,    0x07654300U);
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* 0x6c - 0x6f :
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CFG_IR_INTAB == 0x00
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CFG_IR_INTCD == 0x10   USB = IRQ1
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CFG_IR_PS2   == 0x00
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CFG_IR_FXBUS == 0x00
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*/
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_write_config_dword (pdev, CFG_IR_INTAB, 0x00001000U);
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* 0x70 - 0x73 :
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CFG_IR_USB   == 0x00  not used. USB is connected to INTD.
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CFG_IR_ACPI  == 0x00  not used.
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DMA Priority == 0x4c88  Power on default value. NFC.
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*/
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_write_config_dword (pdev, CFG_IR_USB, 0x4c880000U);
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* PIC1 Initialization Command Word register programming */
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0x11,IC_PIC1+0);	/* ICW1: ICW4 write req | ICW1 */
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0x00,IC_PIC1+1);	/* ICW2: interrupt vector table - not used */
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0x04,IC_PIC1+1);	/* ICW3: Cascade */
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0x01,IC_PIC1+1);	/* ICW4: x86 mode */
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* PIC1 Program Operational Control Words */
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0xff,IC_PIC1+1);	/* OCW1: Mask all interrupts */
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0xc2,IC_PIC1+0);  /* OCW2: priority (3-7,0-2) */
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* PIC2 Initialization Command Word register programming */
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0x11,IC_PIC2+0);	/* ICW1: ICW4 write req | ICW1 */
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0x00,IC_PIC2+1);	/* ICW2: N/A */
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0x02,IC_PIC2+1);	/* ICW3: Slave ID code */
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0x01,IC_PIC2+1);	/* ICW4: x86 mode */
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Program Operational Control Words */
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0xff,IC_PIC1+1);	/* OCW1: Mask all interrupts */
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0x68,IC_PIC1+0);	/* OCW3: OCW3 select | ESMM | SMM */
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Write master mask reg */
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0xff,IC_PIC1+1);
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Setup USB power regulation */
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(1, sio->acpi_base + USB_REG_CR);
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (inb(sio->acpi_base + USB_REG_CR) & 1)
26916541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin		printk(KERN_INFO PFX "USB regulator enabled\n");
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
27116541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin		printk(KERN_ERR PFX "USB regulator not initialized!\n");
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (request_irq(pdev->irq, superio_interrupt, SA_INTERRUPT,
27416541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin			SUPERIO, (void *)sio)) {
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27616541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin		printk(KERN_ERR PFX "could not get irq\n");
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG();
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sio->suckyio_irq_enabled = 1;
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
283a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartinDECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87560_LIO, superio_init);
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void superio_disable_irq(unsigned int irq)
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 r8;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((irq < 1) || (irq == 2) || (irq > 7)) {
29016541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin		printk(KERN_ERR PFX "Illegal irq number.\n");
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG();
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Mask interrupt */
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r8 = inb(IC_PIC1+1);
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r8 |= (1 << irq);
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (r8,IC_PIC1+1);
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void superio_enable_irq(unsigned int irq)
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 r8;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((irq < 1) || (irq == 2) || (irq > 7)) {
30716541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin		printk(KERN_ERR PFX "Illegal irq number (%d).\n", irq);
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG();
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Unmask interrupt */
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r8 = inb(IC_PIC1+1);
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r8 &= ~(1 << irq);
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (r8,IC_PIC1+1);
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int superio_startup_irq(unsigned int irq)
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	superio_enable_irq(irq);
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct hw_interrupt_type superio_interrupt_type = {
32516541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin	.typename =	SUPERIO,
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.startup =	superio_startup_irq,
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.shutdown =	superio_disable_irq,
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.enable =	superio_enable_irq,
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.disable =	superio_disable_irq,
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.ack =		no_ack_irq,
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.end =		no_end_irq,
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_SUPERIO_INIT
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned short expected_device[3] = {
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PCI_DEVICE_ID_NS_87415,
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PCI_DEVICE_ID_NS_87560_LIO,
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PCI_DEVICE_ID_NS_87560_USB
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint superio_fixup_irq(struct pci_dev *pcidev)
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int local_irq, i;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_SUPERIO_INIT
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int fn;
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fn = PCI_FUNC(pcidev->devfn);
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Verify the function number matches the expected device id. */
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (expected_device[fn] != pcidev->device) {
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG();
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("superio_fixup_irq(%s) ven 0x%x dev 0x%x from %p\n",
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_name(pcidev),
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pcidev->vendor, pcidev->device,
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__builtin_return_address(0));
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 16; i++) {
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq_desc[i].handler = &superio_interrupt_type;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We don't allocate a SuperIO irq for the legacy IO function,
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * since it is a "bridge". Instead, we will allocate irq's for
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * each legacy device as they are initialized.
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch(pcidev->device) {
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PCI_DEVICE_ID_NS_87415:		/* Function 0 */
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		local_irq = IDE_IRQ;
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PCI_DEVICE_ID_NS_87560_LIO:	/* Function 1 */
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sio_dev.lio_pdev = pcidev;	/* save for superio_init() */
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PCI_DEVICE_ID_NS_87560_USB:	/* Function 2 */
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sio_dev.usb_pdev = pcidev;	/* save for superio_init() */
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		local_irq = USB_IRQ;
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		local_irq = -1;
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG();
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return local_irq;
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct uart_port serial[] = {
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.iotype		= UPIO_PORT,
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.line		= 0,
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.type		= PORT_16550A,
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.uartclk	= 115200*16,
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.fifosize	= 16,
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.iotype		= UPIO_PORT,
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.line		= 1,
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.type		= PORT_16550A,
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.uartclk	= 115200*16,
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.fifosize	= 16,
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __devinit superio_serial_init(void)
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SERIAL_8250
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial[0].iobase = sio_dev.sp1_base;
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial[0].irq = SP1_IRQ;
4157efe1611b2db9025ffc52a686897ab91820caeb4Kyle McMartin	spin_lock_init(&serial[0].lock);
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = early_serial_setup(&serial[0]);
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
41916541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin		printk(KERN_WARNING PFX "Register Serial #0 failed.\n");
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial[1].iobase = sio_dev.sp2_base;
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial[1].irq = SP2_IRQ;
4257efe1611b2db9025ffc52a686897ab91820caeb4Kyle McMartin	spin_lock_init(&serial[1].lock);
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = early_serial_setup(&serial[1]);
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0)
42916541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin		printk(KERN_WARNING PFX "Register Serial #1 failed.\n");
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_SERIAL_8250 */
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __devinit superio_parport_init(void)
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PARPORT_PC
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!parport_pc_probe_port(sio_dev.pp_base,
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			0 /*base_hi*/,
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			PAR_IRQ,
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			PARPORT_DMA_NONE /* dma */,
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			NULL /*struct pci_dev* */) )
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44316541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin		printk(KERN_WARNING PFX "Probing parallel port failed.\n");
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif	/* CONFIG_PARPORT_PC */
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void superio_fixup_pci(struct pci_dev *pdev)
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 prog;
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pdev->class |= 0x5;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_write_config_byte(pdev, PCI_CLASS_PROG, pdev->class);
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog);
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("PCI: Enabled native mode for NS87415 (pif=0x%x)\n", prog);
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsDECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415, superio_fixup_pci);
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartinstatic int __devinit
462a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartinsuperio_probe(struct pci_dev *dev, const struct pci_device_id *id)
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
464a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin	struct superio_device *sio = &sio_dev;
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	** superio_probe(00:0e.0) ven 0x100b dev 0x2 sv 0x0 sd 0x0 class 0x1018a
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	** superio_probe(00:0e.1) ven 0x100b dev 0xe sv 0x0 sd 0x0 class 0x68000
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	** superio_probe(00:0e.2) ven 0x100b dev 0x12 sv 0x0 sd 0x0 class 0xc0310
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*/
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBG_INIT("superio_probe(%s) ven 0x%x dev 0x%x sv 0x%x sd 0x%x class 0x%x\n",
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_name(dev),
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->vendor, dev->device,
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->subsystem_vendor, dev->subsystem_device,
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->class);
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
477a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin	if (!sio->suckyio_irq_enabled)
478a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin		BUG(); /* Enabled by PCI_FIXUP_FINAL */
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->device == PCI_DEVICE_ID_NS_87560_LIO) {	/* Function 1 */
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		superio_parport_init();
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		superio_serial_init();
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* REVISIT XXX : superio_fdc_init() ? */
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (dev->device == PCI_DEVICE_ID_NS_87415) {	/* Function 0 */
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DBG_INIT("superio_probe: ignoring IDE 87415\n");
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (dev->device == PCI_DEVICE_ID_NS_87560_USB) {	/* Function 2 */
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DBG_INIT("superio_probe: ignoring USB OHCI controller\n");
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DBG_INIT("superio_probe: WTF? Fire Extinguisher?\n");
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
493a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin	/* Let appropriate other driver claim this device. */
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENODEV;
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_device_id superio_tbl[] = {
498a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87560_LIO) },
499a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87560_USB) },
500a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415) },
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0, }
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_driver superio_driver = {
50516541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin	.name =         SUPERIO,
506a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin	.id_table =     superio_tbl,
507a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin	.probe =        superio_probe,
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init superio_modinit(void)
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return pci_register_driver(&superio_driver);
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit superio_exit(void)
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_unregister_driver(&superio_driver);
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(superio_modinit);
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(superio_exit);
522