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>
155076c15862644edb91d2e3436b2fa3e07b28385dHelge Deller *	(C) Copyright 2006 Helge Deller <deller@gmx.de>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	This program is free software; you can redistribute it and/or
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	modify it under the terms of the GNU General Public License as
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	published by the Free Software Foundation; either version 2 of
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	the License, or (at your option) any later version.
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	The initial version of this is by Martin Peterson.  Alex deVries
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	has spent a bit of time trying to coax it into working.
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Major changes to get basic interrupt infrastructure working to
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      hopefully be able to support all SuperIO devices. Currently
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      works with serial. -- John Marvin <jsm@fc.hp.com>
28a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin *
29a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin *	Converted superio_init() to be a PCI_FIXUP_FINAL callee.
30a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin *         -- Kyle McMartin <kyle@parisc-linux.org>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* NOTES:
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function 0 is an IDE controller. It is identical to a PC87415 IDE
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * controller (and identifies itself as such).
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function 1 is a "Legacy I/O" controller. Under this function is a
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * whole mess of legacy I/O peripherals. Of course, HP hasn't enabled
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * all the functionality in hardware, but the following is available:
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Two 16550A compatible serial controllers
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      An IEEE 1284 compatible parallel port
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      A floppy disk controller
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Function 2 is a USB controller.
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We must be incredibly careful during initialization.  Since all
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupts are routed through function 1 (which is not allowed by
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the PCI spec), we need to program the PICs on the legacy I/O port
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * *before* we attempt to set up IDE and USB.  @#$!&
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * According to HP, devices are only enabled by firmware if they have
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a physical device connected.
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Configuration register bits:
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     0x5A: FDC, SP1, IDE1, SP2, IDE2, PAR, Reserved, P92
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *     0x5B: RTC, 8259, 8254, DMA1, DMA2, KBC, P61, APM
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial.h>
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/parport.h>
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/parport_pc.h>
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/termios.h>
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h>
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial_core.h>
76b187f180cc942e50007aa039f8e3a620ee5f3171Yinghai Lu#include <linux/serial_8250.h>
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/hardware.h>
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/superio.h>
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct superio_device sio_dev;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#undef DEBUG_SUPERIO_INIT
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_SUPERIO_INIT
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG_INIT(x...)  printk(x)
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DBG_INIT(x...)
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9416541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin#define SUPERIO	"SuperIO"
9516541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin#define PFX	SUPERIO ": "
9616541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic irqreturn_t
987d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellssuperio_interrupt(int parent_irq, void *devp)
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 results;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 local_irq;
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Poll the 8259 to see if there's an interrupt. */
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (OCW3_POLL,IC_PIC1+0);
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	results = inb(IC_PIC1+0);
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Bit    7:	1 = active Interrupt; 0 = no Interrupt pending
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Bits 6-3:	zero
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Bits 2-0:	highest priority, active requesting interrupt ID (0-7)
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((results & 0x80) == 0) {
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* I suspect "spurious" interrupts are from unmasking an IRQ.
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * We don't know if an interrupt was/is pending and thus
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * just call the handler for that IRQ as if it were pending.
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return IRQ_NONE;
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check to see which device is interrupting */
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	local_irq = results & 0x0f;
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (local_irq == 2 || local_irq > 7) {
12516541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin		printk(KERN_ERR PFX "slave interrupted!\n");
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return IRQ_HANDLED;
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (local_irq == 7) {
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Could be spurious. Check in service bits */
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb(OCW3_ISR,IC_PIC1+0);
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		results = inb(IC_PIC1+0);
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((results & 0x80) == 0) { /* if ISR7 not set: spurious */
13616541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin			printk(KERN_WARNING PFX "spurious interrupt!\n");
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return IRQ_HANDLED;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Call the appropriate device's interrupt */
142ba20085c20f1c9e8af546dea6ad0efa421bdef32Kyle McMartin	generic_handle_irq(local_irq);
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set EOI - forces a new interrupt if a lower priority device
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * still needs service.
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb((OCW2_SEOI|local_irq),IC_PIC1 + 0);
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_HANDLED;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Initialize Super I/O device */
152a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartinstatic void
153a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartinsuperio_init(struct pci_dev *pcidev)
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
155a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin	struct superio_device *sio = &sio_dev;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pci_dev *pdev = sio->lio_pdev;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 word;
15819c4d5664aaf9419dfe6b24990a93305fded6403Kyle McMartin	int ret;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16067a5a59d3301949f51f2d617d689f005c6d21470Helge Deller	if (sio->suckyio_irq_enabled)
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
163b74945547f0679003ede4d1afcd0aa169059a436Eric Sesterhenn	BUG_ON(!pdev);
164b74945547f0679003ede4d1afcd0aa169059a436Eric Sesterhenn	BUG_ON(!sio->usb_pdev);
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* use the IRQ iosapic found for USB INT D... */
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pdev->irq = sio->usb_pdev->irq;
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* ...then properly fixup the USB to point at suckyio PIC */
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sio->usb_pdev->irq = superio_fixup_irq(sio->usb_pdev);
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
172a3bee03e718c9251456676b71a723a34c999e891Frans Pop	printk(KERN_INFO PFX "Found NS87560 Legacy I/O device at %s (IRQ %i)\n",
173a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin	       pci_name(pdev), pdev->irq);
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_read_config_dword (pdev, SIO_SP1BAR, &sio->sp1_base);
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sio->sp1_base &= ~1;
17716541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin	printk(KERN_INFO PFX "Serial port 1 at 0x%x\n", sio->sp1_base);
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_read_config_dword (pdev, SIO_SP2BAR, &sio->sp2_base);
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sio->sp2_base &= ~1;
18116541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin	printk(KERN_INFO PFX "Serial port 2 at 0x%x\n", sio->sp2_base);
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_read_config_dword (pdev, SIO_PPBAR, &sio->pp_base);
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sio->pp_base &= ~1;
18516541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin	printk(KERN_INFO PFX "Parallel port at 0x%x\n", sio->pp_base);
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_read_config_dword (pdev, SIO_FDCBAR, &sio->fdc_base);
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sio->fdc_base &= ~1;
18916541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin	printk(KERN_INFO PFX "Floppy controller at 0x%x\n", sio->fdc_base);
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_read_config_dword (pdev, SIO_ACPIBAR, &sio->acpi_base);
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sio->acpi_base &= ~1;
19216541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin	printk(KERN_INFO PFX "ACPI at 0x%x\n", sio->acpi_base);
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	request_region (IC_PIC1, 0x1f, "pic1");
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	request_region (IC_PIC2, 0x1f, "pic2");
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	request_region (sio->acpi_base, 0x1f, "acpi");
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Enable the legacy I/O function */
19967a5a59d3301949f51f2d617d689f005c6d21470Helge Deller	pci_read_config_word (pdev, PCI_COMMAND, &word);
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_write_config_word (pdev, PCI_COMMAND, word);
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_set_master (pdev);
20419c4d5664aaf9419dfe6b24990a93305fded6403Kyle McMartin	ret = pci_enable_device(pdev);
20519c4d5664aaf9419dfe6b24990a93305fded6403Kyle McMartin	BUG_ON(ret < 0);	/* not too much we can do about this... */
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Next project is programming the onboard interrupt controllers.
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * PDC hasn't done this for us, since it's using polled I/O.
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * XXX Use dword writes to avoid bugs in Elroy or Suckyio Config
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *     space access.  PCI is by nature a 32-bit bus and config
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *     space can be sensitive to that.
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* 0x64 - 0x67 :
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DMA Rtg 2
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DMA Rtg 3
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DMA Chan Ctl
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		TRIGGER_1    == 0x82   USB & IDE level triggered, rest to edge
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*/
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_write_config_dword (pdev, 0x64,         0x82000000U);
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* 0x68 - 0x6b :
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		TRIGGER_2    == 0x00   all edge triggered (not used)
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CFG_IR_SER   == 0x43   SerPort1 = IRQ3, SerPort2 = IRQ4
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CFG_IR_PF    == 0x65   ParPort  = IRQ5, FloppyCtlr = IRQ6
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CFG_IR_IDE   == 0x07   IDE1 = IRQ7, reserved
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*/
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_write_config_dword (pdev, TRIGGER_2,    0x07654300U);
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* 0x6c - 0x6f :
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CFG_IR_INTAB == 0x00
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CFG_IR_INTCD == 0x10   USB = IRQ1
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CFG_IR_PS2   == 0x00
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CFG_IR_FXBUS == 0x00
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*/
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_write_config_dword (pdev, CFG_IR_INTAB, 0x00001000U);
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* 0x70 - 0x73 :
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CFG_IR_USB   == 0x00  not used. USB is connected to INTD.
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CFG_IR_ACPI  == 0x00  not used.
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DMA Priority == 0x4c88  Power on default value. NFC.
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*/
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_write_config_dword (pdev, CFG_IR_USB, 0x4c880000U);
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* PIC1 Initialization Command Word register programming */
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0x11,IC_PIC1+0);	/* ICW1: ICW4 write req | ICW1 */
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0x00,IC_PIC1+1);	/* ICW2: interrupt vector table - not used */
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0x04,IC_PIC1+1);	/* ICW3: Cascade */
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0x01,IC_PIC1+1);	/* ICW4: x86 mode */
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* PIC1 Program Operational Control Words */
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0xff,IC_PIC1+1);	/* OCW1: Mask all interrupts */
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0xc2,IC_PIC1+0);  /* OCW2: priority (3-7,0-2) */
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* PIC2 Initialization Command Word register programming */
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0x11,IC_PIC2+0);	/* ICW1: ICW4 write req | ICW1 */
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0x00,IC_PIC2+1);	/* ICW2: N/A */
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0x02,IC_PIC2+1);	/* ICW3: Slave ID code */
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0x01,IC_PIC2+1);	/* ICW4: x86 mode */
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Program Operational Control Words */
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0xff,IC_PIC1+1);	/* OCW1: Mask all interrupts */
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0x68,IC_PIC1+0);	/* OCW3: OCW3 select | ESMM | SMM */
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Write master mask reg */
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (0xff,IC_PIC1+1);
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Setup USB power regulation */
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb(1, sio->acpi_base + USB_REG_CR);
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (inb(sio->acpi_base + USB_REG_CR) & 1)
27316541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin		printk(KERN_INFO PFX "USB regulator enabled\n");
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
27516541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin		printk(KERN_ERR PFX "USB regulator not initialized!\n");
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2778c56e7214effd2fa50359e58832ad9c3eb51a3deThomas Gleixner	if (request_irq(pdev->irq, superio_interrupt, IRQF_DISABLED,
27816541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin			SUPERIO, (void *)sio)) {
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
28016541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin		printk(KERN_ERR PFX "could not get irq\n");
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG();
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sio->suckyio_irq_enabled = 1;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
287a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartinDECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87560_LIO, superio_init);
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2894c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixnerstatic void superio_mask_irq(struct irq_data *d)
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2914c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixner	unsigned int irq = d->irq;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 r8;
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((irq < 1) || (irq == 2) || (irq > 7)) {
29516541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin		printk(KERN_ERR PFX "Illegal irq number.\n");
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG();
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Mask interrupt */
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r8 = inb(IC_PIC1+1);
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r8 |= (1 << irq);
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (r8,IC_PIC1+1);
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3074c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixnerstatic void superio_unmask_irq(struct irq_data *d)
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3094c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixner	unsigned int irq = d->irq;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 r8;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((irq < 1) || (irq == 2) || (irq > 7)) {
31316541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin		printk(KERN_ERR PFX "Illegal irq number (%d).\n", irq);
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG();
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Unmask interrupt */
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r8 = inb(IC_PIC1+1);
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	r8 &= ~(1 << irq);
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb (r8,IC_PIC1+1);
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
324dfe07565021959f0f646e9e775810c1bfbe0f6d6Thomas Gleixnerstatic struct irq_chip superio_interrupt_type = {
3254c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixner	.name		=	SUPERIO,
3264c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixner	.irq_unmask	=	superio_unmask_irq,
3274c4231ea2f794d73bbb50b8d84e00c66a012a607Thomas Gleixner	.irq_mask	=	superio_mask_irq,
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_SUPERIO_INIT
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned short expected_device[3] = {
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PCI_DEVICE_ID_NS_87415,
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PCI_DEVICE_ID_NS_87560_LIO,
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	PCI_DEVICE_ID_NS_87560_USB
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint superio_fixup_irq(struct pci_dev *pcidev)
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int local_irq, i;
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_SUPERIO_INIT
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int fn;
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	fn = PCI_FUNC(pcidev->devfn);
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Verify the function number matches the expected device id. */
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (expected_device[fn] != pcidev->device) {
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG();
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("superio_fixup_irq(%s) ven 0x%x dev 0x%x from %p\n",
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_name(pcidev),
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pcidev->vendor, pcidev->device,
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		__builtin_return_address(0));
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < 16; i++) {
358e2f571d294cc5f944539088bed46abae375b75f6Thomas Gleixner		irq_set_chip_and_handler(i, &superio_interrupt_type,
359e2f571d294cc5f944539088bed46abae375b75f6Thomas Gleixner					 handle_simple_irq);
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * We don't allocate a SuperIO irq for the legacy IO function,
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * since it is a "bridge". Instead, we will allocate irq's for
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * each legacy device as they are initialized.
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch(pcidev->device) {
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PCI_DEVICE_ID_NS_87415:		/* Function 0 */
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		local_irq = IDE_IRQ;
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PCI_DEVICE_ID_NS_87560_LIO:	/* Function 1 */
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sio_dev.lio_pdev = pcidev;	/* save for superio_init() */
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case PCI_DEVICE_ID_NS_87560_USB:	/* Function 2 */
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sio_dev.usb_pdev = pcidev;	/* save for superio_init() */
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		local_irq = USB_IRQ;
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		local_irq = -1;
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG();
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return local_irq;
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3888c678b101a08a6543e62ab60aace93042456aa9dHelge Dellerstatic void __init superio_serial_init(void)
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SERIAL_8250
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
3925076c15862644edb91d2e3436b2fa3e07b28385dHelge Deller	struct uart_port serial_port;
3935076c15862644edb91d2e3436b2fa3e07b28385dHelge Deller
3945076c15862644edb91d2e3436b2fa3e07b28385dHelge Deller	memset(&serial_port, 0, sizeof(serial_port));
3955076c15862644edb91d2e3436b2fa3e07b28385dHelge Deller	serial_port.iotype	= UPIO_PORT;
3965076c15862644edb91d2e3436b2fa3e07b28385dHelge Deller	serial_port.type	= PORT_16550A;
3975076c15862644edb91d2e3436b2fa3e07b28385dHelge Deller	serial_port.uartclk	= 115200*16;
3985076c15862644edb91d2e3436b2fa3e07b28385dHelge Deller	serial_port.fifosize	= 16;
3995076c15862644edb91d2e3436b2fa3e07b28385dHelge Deller
4005076c15862644edb91d2e3436b2fa3e07b28385dHelge Deller	/* serial port #1 */
4015076c15862644edb91d2e3436b2fa3e07b28385dHelge Deller	serial_port.iobase	= sio_dev.sp1_base;
4025076c15862644edb91d2e3436b2fa3e07b28385dHelge Deller	serial_port.irq		= SP1_IRQ;
4035076c15862644edb91d2e3436b2fa3e07b28385dHelge Deller	serial_port.line	= 0;
4045076c15862644edb91d2e3436b2fa3e07b28385dHelge Deller	retval = early_serial_setup(&serial_port);
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0) {
40616541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin		printk(KERN_WARNING PFX "Register Serial #0 failed.\n");
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4105076c15862644edb91d2e3436b2fa3e07b28385dHelge Deller	/* serial port #2 */
4115076c15862644edb91d2e3436b2fa3e07b28385dHelge Deller	serial_port.iobase	= sio_dev.sp2_base;
4125076c15862644edb91d2e3436b2fa3e07b28385dHelge Deller	serial_port.irq		= SP2_IRQ;
4135076c15862644edb91d2e3436b2fa3e07b28385dHelge Deller	serial_port.line	= 1;
4145076c15862644edb91d2e3436b2fa3e07b28385dHelge Deller	retval = early_serial_setup(&serial_port);
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval < 0)
41616541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin		printk(KERN_WARNING PFX "Register Serial #1 failed.\n");
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* CONFIG_SERIAL_8250 */
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4218c678b101a08a6543e62ab60aace93042456aa9dHelge Dellerstatic void __init superio_parport_init(void)
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PARPORT_PC
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!parport_pc_probe_port(sio_dev.pp_base,
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			0 /*base_hi*/,
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			PAR_IRQ,
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			PARPORT_DMA_NONE /* dma */,
4280c5cb79198d80eaea273f3e91cb418d559f13462Alexander Beregalov			NULL /*struct pci_dev* */,
4290c5cb79198d80eaea273f3e91cb418d559f13462Alexander Beregalov			0 /* shared irq flags */))
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
43116541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin		printk(KERN_WARNING PFX "Probing parallel port failed.\n");
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif	/* CONFIG_PARPORT_PC */
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void superio_fixup_pci(struct pci_dev *pdev)
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 prog;
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pdev->class |= 0x5;
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_write_config_byte(pdev, PCI_CLASS_PROG, pdev->class);
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog);
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("PCI: Enabled native mode for NS87415 (pif=0x%x)\n", prog);
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsDECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415, superio_fixup_pci);
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4498c678b101a08a6543e62ab60aace93042456aa9dHelge Dellerstatic int __init
450a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartinsuperio_probe(struct pci_dev *dev, const struct pci_device_id *id)
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
452a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin	struct superio_device *sio = &sio_dev;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	** superio_probe(00:0e.0) ven 0x100b dev 0x2 sv 0x0 sd 0x0 class 0x1018a
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	** superio_probe(00:0e.1) ven 0x100b dev 0xe sv 0x0 sd 0x0 class 0x68000
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	** superio_probe(00:0e.2) ven 0x100b dev 0x12 sv 0x0 sd 0x0 class 0xc0310
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*/
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DBG_INIT("superio_probe(%s) ven 0x%x dev 0x%x sv 0x%x sd 0x%x class 0x%x\n",
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_name(dev),
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->vendor, dev->device,
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->subsystem_vendor, dev->subsystem_device,
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->class);
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
465b74945547f0679003ede4d1afcd0aa169059a436Eric Sesterhenn	BUG_ON(!sio->suckyio_irq_enabled);	/* Enabled by PCI_FIXUP_FINAL */
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->device == PCI_DEVICE_ID_NS_87560_LIO) {	/* Function 1 */
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		superio_parport_init();
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		superio_serial_init();
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* REVISIT XXX : superio_fdc_init() ? */
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (dev->device == PCI_DEVICE_ID_NS_87415) {	/* Function 0 */
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DBG_INIT("superio_probe: ignoring IDE 87415\n");
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (dev->device == PCI_DEVICE_ID_NS_87560_USB) {	/* Function 2 */
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DBG_INIT("superio_probe: ignoring USB OHCI controller\n");
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		DBG_INIT("superio_probe: WTF? Fire Extinguisher?\n");
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
480a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin	/* Let appropriate other driver claim this device. */
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENODEV;
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4848c678b101a08a6543e62ab60aace93042456aa9dHelge Dellerstatic const struct pci_device_id superio_tbl[] = {
485a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87560_LIO) },
486a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87560_USB) },
487a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415) },
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0, }
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_driver superio_driver = {
49216541c8745e28f62b3dcb6cb354b73c9c01ea178Kyle McMartin	.name =         SUPERIO,
493a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin	.id_table =     superio_tbl,
494a39cf72ceb406e152c4682c0b635a96f1439c5edKyle McMartin	.probe =        superio_probe,
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init superio_modinit(void)
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return pci_register_driver(&superio_driver);
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit superio_exit(void)
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_unregister_driver(&superio_driver);
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(superio_modinit);
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(superio_exit);
509