11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Copyright (c) 1999  Frodo Looijaard <frodol@dds.nl> and
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Philip Edelbrock <phil@netroedge.com> and
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Mark D. Studebaker <mdsxyz123@yahoo.com>
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This program is free software; you can redistribute it and/or modify
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    it under the terms of the GNU General Public License as published by
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    the Free Software Foundation; either version 2 of the License, or
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    (at your option) any later version.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This program is distributed in the hope that it will be useful,
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    but WITHOUT ANY WARRANTY; without even the implied warranty of
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    GNU General Public License for more details.
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    You should have received a copy of the GNU General Public License
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    along with this program; if not, write to the Free Software
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This is the driver for the SMB Host controller on
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Acer Labs Inc. (ALI) M1541 and M1543C South Bridges.
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    The M1543C is a South bridge for desktop systems.
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    The M1533 is a South bridge for portable systems.
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    They are part of the following ALI chipsets:
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       "Aladdin Pro 2": Includes the M1621 Slot 1 North bridge
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       with AGP and 100MHz CPU Front Side bus
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       "Aladdin V": Includes the M1541 Socket 7 North bridge
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       with AGP and 100MHz CPU Front Side bus
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       "Aladdin IV": Includes the M1541 Socket 7 North bridge
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds       with host bus up to 83.3 MHz.
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    For an overview of these chips see http://www.acerlabs.com
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    The M1533/M1543C devices appear as FOUR separate devices
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    on the PCI bus. An output of lspci will show something similar
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    to the following:
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	00:02.0 USB Controller: Acer Laboratories Inc. M5237
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	00:03.0 Bridge: Acer Laboratories Inc. M7101
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	00:07.0 ISA bridge: Acer Laboratories Inc. M1533
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	00:0f.0 IDE interface: Acer Laboratories Inc. M5229
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    The SMB controller is part of the 7101 device, which is an
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    ACPI-compliant Power Management Unit (PMU).
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    The whole 7101 device has to be enabled for the SMB to work.
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    You can't just enable the SMB alone.
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    The SMB and the ACPI have separate I/O spaces.
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    We make sure that the SMB is enabled. We leave the ACPI alone.
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This driver controls the SMB Host only.
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    The SMB Slave controller on the M15X3 is not enabled.
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This driver does not use interrupts.
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Note: we assume there can only be one ALI15X3, with one SMBus interface */
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/stddef.h>
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/i2c.h>
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
6954fb4a05af0a4b814e6716cfdf3fa97fc6be7a32Jean Delvare#include <linux/acpi.h>
702178218027e4da0608219fae1d02e5c88f4e560dH Hartley Sweeten#include <linux/io.h>
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ALI15X3 SMBus address offsets */
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBHSTSTS	(0 + ali15x3_smba)
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBHSTCNT	(1 + ali15x3_smba)
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBHSTSTART	(2 + ali15x3_smba)
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBHSTCMD	(7 + ali15x3_smba)
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBHSTADD	(3 + ali15x3_smba)
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBHSTDAT0	(4 + ali15x3_smba)
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBHSTDAT1	(5 + ali15x3_smba)
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBBLKDAT	(6 + ali15x3_smba)
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* PCI Address Constants */
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBCOM		0x004
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBBA		0x014
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBATPC		0x05B	/* used to unlock xxxBA registers */
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBHSTCFG	0x0E0
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBSLVC		0x0E1
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBCLK		0x0E2
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBREV		0x008
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Other settings */
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_TIMEOUT		200	/* times 1/100 sec */
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_SMB_IOSIZE	32
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* this is what the Award 1004 BIOS sets them to on a ASUS P5A MB.
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   We don't use these here. If the bases aren't set to some value we
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   tell user to upgrade BIOS and we fail.
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_SMB_DEFAULTBASE	0xE800
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ALI15X3 address lock bits */
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_LOCK		0x06
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ALI15X3 command constants */
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_ABORT		0x02
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_T_OUT		0x04
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_QUICK		0x00
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_BYTE		0x10
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_BYTE_DATA	0x20
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_WORD_DATA	0x30
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_BLOCK_DATA	0x40
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_BLOCK_CLR	0x80
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ALI15X3 status register bits */
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_STS_IDLE	0x04
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_STS_BUSY	0x08
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_STS_DONE	0x10
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_STS_DEV		0x20	/* device error */
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_STS_COLL	0x40	/* collision or no response */
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_STS_TERM	0x80	/* terminated by abort */
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ALI15X3_STS_ERR		0xE0	/* all the bad error bits */
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* If force_addr is set to anything different from 0, we forcibly enable
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   the device at the given address. */
126605070952f0b41caaa211c47b02eeac703529008Jean Delvarestatic u16 force_addr;
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(force_addr, ushort, 0);
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(force_addr,
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 "Initialize the base address of the i2c controller");
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
131d6072f842a77014220683ee5b781b7cee8f020d1Jean Delvarestatic struct pci_driver ali15x3_driver;
132605070952f0b41caaa211c47b02eeac703529008Jean Delvarestatic unsigned short ali15x3_smba;
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
134abe38388e50f4d89726fd0c0cceea61563c7026bJean Delvarestatic int __devinit ali15x3_setup(struct pci_dev *ALI15X3_dev)
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u16 a;
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char temp;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check the following things:
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		- SMB I/O address is initialized
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		- Device is enabled
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		- We can use the addresses
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*/
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Unlock the register.
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   The data sheet says that the address registers are read-only
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   if the lock bits are 1, but in fact the address registers
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   are zero unless you clear the lock bits.
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*/
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_read_config_byte(ALI15X3_dev, SMBATPC, &temp);
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (temp & ALI15X3_LOCK) {
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp &= ~ALI15X3_LOCK;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_write_config_byte(ALI15X3_dev, SMBATPC, temp);
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Determine the address of the SMBus area */
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_read_config_word(ALI15X3_dev, SMBBA, &ali15x3_smba);
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ali15x3_smba &= (0xffff & ~(ALI15X3_SMB_IOSIZE - 1));
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ali15x3_smba == 0 && force_addr == 0) {
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err(&ALI15X3_dev->dev, "ALI15X3_smb region uninitialized "
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"- upgrade BIOS or use force_addr=0xaddr\n");
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(force_addr)
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ali15x3_smba = force_addr & ~(ALI15X3_SMB_IOSIZE - 1);
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
16854fb4a05af0a4b814e6716cfdf3fa97fc6be7a32Jean Delvare	if (acpi_check_region(ali15x3_smba, ALI15X3_SMB_IOSIZE,
16954fb4a05af0a4b814e6716cfdf3fa97fc6be7a32Jean Delvare			      ali15x3_driver.name))
17054fb4a05af0a4b814e6716cfdf3fa97fc6be7a32Jean Delvare		return -EBUSY;
17154fb4a05af0a4b814e6716cfdf3fa97fc6be7a32Jean Delvare
172d6072f842a77014220683ee5b781b7cee8f020d1Jean Delvare	if (!request_region(ali15x3_smba, ALI15X3_SMB_IOSIZE,
173d6072f842a77014220683ee5b781b7cee8f020d1Jean Delvare			    ali15x3_driver.name)) {
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err(&ALI15X3_dev->dev,
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"ALI15X3_smb region 0x%x already in use!\n",
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ali15x3_smba);
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(force_addr) {
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_info(&ALI15X3_dev->dev, "forcing ISA address 0x%04X\n",
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ali15x3_smba);
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (PCIBIOS_SUCCESSFUL != pci_write_config_word(ALI15X3_dev,
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								SMBBA,
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								ali15x3_smba))
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto error;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (PCIBIOS_SUCCESSFUL != pci_read_config_word(ALI15X3_dev,
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds								SMBBA, &a))
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto error;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((a & ~(ALI15X3_SMB_IOSIZE - 1)) != ali15x3_smba) {
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* make sure it works */
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_err(&ALI15X3_dev->dev,
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"force address failed - not supported?\n");
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto error;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* check if whole device is enabled */
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_read_config_byte(ALI15X3_dev, SMBCOM, &temp);
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((temp & 1) == 0) {
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_info(&ALI15X3_dev->dev, "enabling SMBus device\n");
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_write_config_byte(ALI15X3_dev, SMBCOM, temp | 0x01);
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Is SMB Host controller enabled? */
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_read_config_byte(ALI15X3_dev, SMBHSTCFG, &temp);
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((temp & 1) == 0) {
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_info(&ALI15X3_dev->dev, "enabling SMBus controller\n");
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_write_config_byte(ALI15X3_dev, SMBHSTCFG, temp | 0x01);
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set SMB clock to 74KHz as recommended in data sheet */
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_write_config_byte(ALI15X3_dev, SMBCLK, 0x20);
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  The interrupt routing for SMB is set up in register 0x77 in the
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  1533 ISA Bridge device, NOT in the 7101 device.
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  Don't bother with finding the 1533 device and reading the register.
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((....... & 0x0F) == 1)
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_dbg(&ALI15X3_dev->dev, "ALI15X3 using Interrupt 9 for SMBus.\n");
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*/
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_read_config_byte(ALI15X3_dev, SMBREV, &temp);
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_dbg(&ALI15X3_dev->dev, "SMBREV = 0x%X\n", temp);
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_dbg(&ALI15X3_dev->dev, "iALI15X3_smba = 0x%X\n", ali15x3_smba);
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror:
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE);
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENODEV;
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Another internally used function */
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ali15x3_transaction(struct i2c_adapter *adap)
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int temp;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result = 0;
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int timeout = 0;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_dbg(&adap->dev, "Transaction (pre): STS=%02x, CNT=%02x, CMD=%02x, "
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS),
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* get status */
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	temp = inb_p(SMBHSTSTS);
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Make sure the SMBus host is ready to start transmitting */
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check the busy bit first */
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (temp & ALI15X3_STS_BUSY) {
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   If the host controller is still busy, it may have timed out in the
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   previous transaction, resulting in a "SMBus Timeout" Dev.
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   I've tried the following to reset a stuck busy bit.
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		1. Reset the controller with an ABORT command.
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   (this doesn't seem to clear the controller if an external
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   device is hung)
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		2. Reset the controller and the other SMBus devices with a
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   T_OUT command.  (this clears the host busy bit if an
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   external device is hung, but it comes back upon a new access
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   to a device)
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		3. Disable and reenable the controller in SMBHSTCFG
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   Worst case, nothing seems to work except power reset.
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*/
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Abort - reset the host controller */
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   Try resetting entire SMB bus, including other devices -
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   This may not work either - it clears the BUSY bit but
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   then the BUSY bit may come back on when you try and use the chip again.
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   If that's the case you are stuck.
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*/
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_info(&adap->dev, "Resetting entire SMB Bus to "
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"clear busy condition (%02x)\n", temp);
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(ALI15X3_T_OUT, SMBHSTCNT);
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp = inb_p(SMBHSTSTS);
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* now check the error bits and the busy bit */
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (temp & (ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) {
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* do a clear-on-write */
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(0xFF, SMBHSTSTS);
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((temp = inb_p(SMBHSTSTS)) &
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    (ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) {
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* this is probably going to be correctable only by a power reset
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   as one of the bits now appears to be stuck */
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* This may be a bus or device with electrical problems. */
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_err(&adap->dev, "SMBus reset failed! (0x%02x) - "
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"controller or device on bus is probably hung\n",
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				temp);
28897140342e69d479a3ad82bfd4c154c0b08fe3eeaDavid Brownell			return -EBUSY;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* check and clear done bit */
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (temp & ALI15X3_STS_DONE) {
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb_p(temp, SMBHSTSTS);
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* start the transaction by writing anything to the start register */
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb_p(0xFF, SMBHSTSTART);
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We will always wait for a fraction of a second! */
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timeout = 0;
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		msleep(1);
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp = inb_p(SMBHSTSTS);
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while ((!(temp & (ALI15X3_STS_ERR | ALI15X3_STS_DONE)))
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 && (timeout++ < MAX_TIMEOUT));
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* If the SMBus is still busy, we give up */
3094ccc28f725bc2b7b0a3bc27e9c15f4eaf63fb812Roel Kluin	if (timeout > MAX_TIMEOUT) {
31097140342e69d479a3ad82bfd4c154c0b08fe3eeaDavid Brownell		result = -ETIMEDOUT;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err(&adap->dev, "SMBus Timeout!\n");
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (temp & ALI15X3_STS_TERM) {
31597140342e69d479a3ad82bfd4c154c0b08fe3eeaDavid Brownell		result = -EIO;
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  Unfortunately the ALI SMB controller maps "no response" and "bus
32125985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	  collision" into a single bit. No response is the usual case so don't
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  do a printk.
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  This means that bus collisions go unreported.
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*/
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (temp & ALI15X3_STS_COLL) {
32697140342e69d479a3ad82bfd4c154c0b08fe3eeaDavid Brownell		result = -ENXIO;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_dbg(&adap->dev,
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"Error: no response or bus collision ADD=%02x\n",
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			inb_p(SMBHSTADD));
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* haven't ever seen this */
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (temp & ALI15X3_STS_DEV) {
33497140342e69d479a3ad82bfd4c154c0b08fe3eeaDavid Brownell		result = -EIO;
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err(&adap->dev, "Error: device error\n");
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_dbg(&adap->dev, "Transaction (post): STS=%02x, CNT=%02x, CMD=%02x, "
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS),
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
34497140342e69d479a3ad82bfd4c154c0b08fe3eeaDavid Brownell/* Return negative errno on error. */
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic s32 ali15x3_access(struct i2c_adapter * adap, u16 addr,
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   unsigned short flags, char read_write, u8 command,
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   int size, union i2c_smbus_data * data)
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, len;
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int temp;
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int timeout;
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* clear all the bits (clear-on-write) */
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb_p(0xFF, SMBHSTSTS);
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* make sure SMBus is idle */
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	temp = inb_p(SMBHSTSTS);
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (timeout = 0;
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     (timeout < MAX_TIMEOUT) && !(temp & ALI15X3_STS_IDLE);
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	     timeout++) {
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		msleep(1);
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp = inb_p(SMBHSTSTS);
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (timeout >= MAX_TIMEOUT) {
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err(&adap->dev, "Idle wait Timeout! STS=0x%02x\n", temp);
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (size) {
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case I2C_SMBUS_QUICK:
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       SMBHSTADD);
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size = ALI15X3_QUICK;
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case I2C_SMBUS_BYTE:
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       SMBHSTADD);
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (read_write == I2C_SMBUS_WRITE)
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb_p(command, SMBHSTCMD);
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size = ALI15X3_BYTE;
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case I2C_SMBUS_BYTE_DATA:
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       SMBHSTADD);
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(command, SMBHSTCMD);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (read_write == I2C_SMBUS_WRITE)
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb_p(data->byte, SMBHSTDAT0);
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size = ALI15X3_BYTE_DATA;
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case I2C_SMBUS_WORD_DATA:
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       SMBHSTADD);
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(command, SMBHSTCMD);
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (read_write == I2C_SMBUS_WRITE) {
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb_p(data->word & 0xff, SMBHSTDAT0);
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size = ALI15X3_WORD_DATA;
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case I2C_SMBUS_BLOCK_DATA:
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       SMBHSTADD);
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(command, SMBHSTCMD);
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (read_write == I2C_SMBUS_WRITE) {
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = data->block[0];
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (len < 0) {
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len = 0;
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data->block[0] = len;
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (len > 32) {
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len = 32;
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				data->block[0] = len;
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb_p(len, SMBHSTDAT0);
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* Reset SMBBLKDAT */
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT);
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i = 1; i <= len; i++)
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				outb_p(data->block[i], SMBBLKDAT);
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size = ALI15X3_BLOCK_DATA;
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
420ac7fc4fb2b6a126af8d07f46500440c9641976cfJean Delvare	default:
421ac7fc4fb2b6a126af8d07f46500440c9641976cfJean Delvare		dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
422ac7fc4fb2b6a126af8d07f46500440c9641976cfJean Delvare		return -EOPNOTSUPP;
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb_p(size, SMBHSTCNT);	/* output command */
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42797140342e69d479a3ad82bfd4c154c0b08fe3eeaDavid Brownell	temp = ali15x3_transaction(adap);
42897140342e69d479a3ad82bfd4c154c0b08fe3eeaDavid Brownell	if (temp)
42997140342e69d479a3ad82bfd4c154c0b08fe3eeaDavid Brownell		return temp;
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((read_write == I2C_SMBUS_WRITE) || (size == ALI15X3_QUICK))
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (size) {
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ALI15X3_BYTE:	/* Result put in SMBHSTDAT0 */
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->byte = inb_p(SMBHSTDAT0);
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ALI15X3_BYTE_DATA:
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->byte = inb_p(SMBHSTDAT0);
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ALI15X3_WORD_DATA:
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case ALI15X3_BLOCK_DATA:
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		len = inb_p(SMBHSTDAT0);
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (len > 32)
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			len = 32;
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->block[0] = len;
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Reset SMBBLKDAT */
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT);
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 1; i <= data->block[0]; i++) {
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->block[i] = inb_p(SMBBLKDAT);
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_dbg(&adap->dev, "Blk: len=%d, i=%d, data=%02x\n",
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len, i, data->block[i]);
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 ali15x3_func(struct i2c_adapter *adapter)
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    I2C_FUNC_SMBUS_BLOCK_DATA;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4698f9082c5ce0e2c2f7ad0211b0c089f680d2efc11Jean Delvarestatic const struct i2c_algorithm smbus_algorithm = {
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.smbus_xfer	= ali15x3_access,
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.functionality	= ali15x3_func,
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct i2c_adapter ali15x3_adapter = {
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner		= THIS_MODULE,
4763401b2fff38fbb8b73ea6bcc69a8370ae5d2a7a0Jean Delvare	.class          = I2C_CLASS_HWMON | I2C_CLASS_SPD,
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.algo		= &smbus_algorithm,
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4803527bd5045aacb4e4072f9cacb8eb9a433fbad39Axel Linstatic DEFINE_PCI_DEVICE_TABLE(ali15x3_ids) = {
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0, }
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE (pci, ali15x3_ids);
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit ali15x3_probe(struct pci_dev *dev, const struct pci_device_id *id)
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ali15x3_setup(dev)) {
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err(&dev->dev,
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"ALI15X3 not detected, module not inserted.\n");
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
495405ae7d381302468ecc803f2148a2ae40a04c999Robert P. J. Day	/* set up the sysfs linkage to our parent device */
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ali15x3_adapter.dev.parent = &dev->dev;
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4982096b956d24c4b5950b808fc23b218425d79ebb1David Brownell	snprintf(ali15x3_adapter.name, sizeof(ali15x3_adapter.name),
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"SMBus ALI15X3 adapter at %04x", ali15x3_smba);
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return i2c_add_adapter(&ali15x3_adapter);
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __devexit ali15x3_remove(struct pci_dev *dev)
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i2c_del_adapter(&ali15x3_adapter);
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE);
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_driver ali15x3_driver = {
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name		= "ali15x3_smbus",
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id_table	= ali15x3_ids,
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe		= ali15x3_probe,
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.remove		= __devexit_p(ali15x3_remove),
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init i2c_ali15x3_init(void)
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return pci_register_driver(&ali15x3_driver);
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit i2c_ali15x3_exit(void)
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_unregister_driver(&ali15x3_driver);
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"Philip Edelbrock <phil@netroedge.com>, "
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"and Mark D. Studebaker <mdsxyz123@yahoo.com>");
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("ALI15X3 SMBus driver");
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(i2c_ali15x3_init);
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(i2c_ali15x3_exit);
534