All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 3 of 10] New/Updated drivers: Intel 82801 (ICH) driver backported from Linux Kernel Ver. 2.6.29.2
@ 2009-11-24 11:38 Daniel Kiper
  0 siblings, 0 replies; only message in thread
From: Daniel Kiper @ 2009-11-24 11:38 UTC (permalink / raw)
  To: xen-devel

# HG changeset patch
# User root@dte40r0-um-i386.local.net-space.pl
# Date 1259015516 -3600
# Node ID 3eaec2bd5066e416e65ec082cd5d783ef36ff6bb
# Parent  1db1bb63824b25f97d127449faeb3a56f1272c97
Intel 82801 (ICH) driver backported
from Linux Kernel Ver. 2.6.29.2
Signed-off-by: Daniel Kiper <dkiper@net-space.pl>

diff -r 1db1bb63824b -r 3eaec2bd5066 Documentation/i2c/dev-interface
--- a/Documentation/i2c/dev-interface	Mon Nov 23 07:32:47 2009 +0000
+++ b/Documentation/i2c/dev-interface	Mon Nov 23 23:31:56 2009 +0100
@@ -4,6 +4,10 @@ the /dev interface. You need to load mod
 
 Each registered i2c adapter gets a number, counting from 0. You can
 examine /sys/class/i2c-dev/ to see what number corresponds to which adapter.
+Alternatively, you can run "i2cdetect -l" to obtain a formated list of all
+i2c adapters present on your system at a given time. i2cdetect is part of
+the i2c-tools package.
+
 I2C device files are character device files with major device number 89
 and a minor device number corresponding to the number assigned as 
 explained above. They should be called "i2c-%d" (i2c-0, i2c-1, ..., 
@@ -17,30 +21,34 @@ first thing to do is "#include <linux/i2
 first thing to do is "#include <linux/i2c-dev.h>". Please note that
 there are two files named "i2c-dev.h" out there, one is distributed
 with the Linux kernel and is meant to be included from kernel
-driver code, the other one is distributed with lm_sensors and is
+driver code, the other one is distributed with i2c-tools and is
 meant to be included from user-space programs. You obviously want
 the second one here.
 
 Now, you have to decide which adapter you want to access. You should
-inspect /sys/class/i2c-dev/ to decide this. Adapter numbers are assigned
-somewhat dynamically, so you can not even assume /dev/i2c-0 is the
-first adapter.
+inspect /sys/class/i2c-dev/ or run "i2cdetect -l" to decide this.
+Adapter numbers are assigned somewhat dynamically, so you can not
+assume much about them. They can even change from one boot to the next.
 
 Next thing, open the device file, as follows:
+
   int file;
   int adapter_nr = 2; /* probably dynamically determined */
   char filename[20];
   
-  sprintf(filename,"/dev/i2c-%d",adapter_nr);
-  if ((file = open(filename,O_RDWR)) < 0) {
+  snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
+  file = open(filename, O_RDWR);
+  if (file < 0) {
     /* ERROR HANDLING; you can check errno to see what went wrong */
     exit(1);
   }
 
 When you have opened the device, you must specify with what device
 address you want to communicate:
+
   int addr = 0x40; /* The I2C address */
-  if (ioctl(file,I2C_SLAVE,addr) < 0) {
+
+  if (ioctl(file, I2C_SLAVE, addr) < 0) {
     /* ERROR HANDLING; you can check errno to see what went wrong */
     exit(1);
   }
@@ -48,31 +56,41 @@ Well, you are all set up now. You can no
 Well, you are all set up now. You can now use SMBus commands or plain
 I2C to communicate with your device. SMBus commands are preferred if
 the device supports them. Both are illustrated below.
+
   __u8 register = 0x10; /* Device register to access */
   __s32 res;
   char buf[10];
+
   /* Using SMBus commands */
-  res = i2c_smbus_read_word_data(file,register);
+  res = i2c_smbus_read_word_data(file, register);
   if (res < 0) {
     /* ERROR HANDLING: i2c transaction failed */
   } else {
     /* res contains the read word */
   }
+
   /* Using I2C Write, equivalent of 
-           i2c_smbus_write_word_data(file,register,0x6543) */
+     i2c_smbus_write_word_data(file, register, 0x6543) */
   buf[0] = register;
   buf[1] = 0x43;
   buf[2] = 0x65;
-  if ( write(file,buf,3) != 3) {
-    /* ERROR HANDLING: i2c transaction failed */
-  }
+  if (write(file, buf, 3) ! =3) {
+    /* ERROR HANDLING: i2c transaction failed */
+  }
+
   /* Using I2C Read, equivalent of i2c_smbus_read_byte(file) */
-  if (read(file,buf,1) != 1) {
+  if (read(file, buf, 1) != 1) {
     /* ERROR HANDLING: i2c transaction failed */
   } else {
     /* buf[0] contains the read byte */
   }
 
+Note that only a subset of the I2C and SMBus protocols can be achieved by
+the means of read() and write() calls. In particular, so-called combined
+transactions (mixing read and write messages in the same transaction)
+aren't supported. For this reason, this interface is almost never used by
+user-space programs.
+
 IMPORTANT: because of the use of inline functions, you *have* to use
 '-O' or some variation when you compile your program!
 
@@ -80,31 +98,34 @@ Full interface description
 Full interface description
 ==========================
 
-The following IOCTLs are defined and fully supported 
-(see also i2c-dev.h):
-
-ioctl(file,I2C_SLAVE,long addr)
+The following IOCTLs are defined:
+
+ioctl(file, I2C_SLAVE, long addr)
   Change slave address. The address is passed in the 7 lower bits of the
   argument (except for 10 bit addresses, passed in the 10 lower bits in this
   case).
 
-ioctl(file,I2C_TENBIT,long select)
+ioctl(file, I2C_TENBIT, long select)
   Selects ten bit addresses if select not equals 0, selects normal 7 bit
-  addresses if select equals 0. Default 0.
-
-ioctl(file,I2C_PEC,long select)
+  addresses if select equals 0. Default 0.  This request is only valid
+  if the adapter has I2C_FUNC_10BIT_ADDR.
+
+ioctl(file, I2C_PEC, long select)
   Selects SMBus PEC (packet error checking) generation and verification
   if select not equals 0, disables if select equals 0. Default 0.
-  Used only for SMBus transactions.
-
-ioctl(file,I2C_FUNCS,unsigned long *funcs)
+  Used only for SMBus transactions.  This request only has an effect if the
+  the adapter has I2C_FUNC_SMBUS_PEC; it is still safe if not, it just
+  doesn't have any effect.
+
+ioctl(file, I2C_FUNCS, unsigned long *funcs)
   Gets the adapter functionality and puts it in *funcs.
 
-ioctl(file,I2C_RDWR,struct i2c_rdwr_ioctl_data *msgset)
-
+ioctl(file, I2C_RDWR, struct i2c_rdwr_ioctl_data *msgset)
   Do combined read/write transaction without stop in between.
-  The argument is a pointer to a struct i2c_rdwr_ioctl_data {
-
+  Only valid if the adapter has I2C_FUNC_I2C.  The argument is
+  a pointer to a
+
+  struct i2c_rdwr_ioctl_data {
       struct i2c_msg *msgs;  /* ptr to array of simple messages */
       int nmsgs;             /* number of messages to exchange */
   }
@@ -115,10 +136,9 @@ ioctl(file,I2C_RDWR,struct i2c_rdwr_ioct
   The slave address and whether to use ten bit address mode has to be
   set in each message, overriding the values set with the above ioctl's.
 
-
-Other values are NOT supported at this moment, except for I2C_SMBUS,
-which you should never directly call; instead, use the access functions
-below.
+ioctl(file, I2C_SMBUS, struct i2c_smbus_ioctl_data *args)
+  Not meant to be called  directly; instead, use the access functions
+  below.
 
 You can do plain i2c transactions by using read(2) and write(2) calls.
 You do not need to pass the address byte; instead, set it through
@@ -143,7 +163,52 @@ returns the number of values read. The b
 returns the number of values read. The block buffers need not be longer
 than 32 bytes.
 
-The above functions are all macros, that resolve to calls to the
-i2c_smbus_access function, that on its turn calls a specific ioctl
+The above functions are all inline functions, that resolve to calls to
+the i2c_smbus_access function, that on its turn calls a specific ioctl
 with the data in a specific format. Read the source code if you
 want to know what happens behind the screens.
+
+
+Implementation details
+======================
+
+For the interested, here's the code flow which happens inside the kernel
+when you use the /dev interface to I2C:
+
+1* Your program opens /dev/i2c-N and calls ioctl() on it, as described in
+section "C example" above.
+
+2* These open() and ioctl() calls are handled by the i2c-dev kernel
+driver: see i2c-dev.c:i2cdev_open() and i2c-dev.c:i2cdev_ioctl(),
+respectively. You can think of i2c-dev as a generic I2C chip driver
+that can be programmed from user-space.
+
+3* Some ioctl() calls are for administrative tasks and are handled by
+i2c-dev directly. Examples include I2C_SLAVE (set the address of the
+device you want to access) and I2C_PEC (enable or disable SMBus error
+checking on future transactions.)
+
+4* Other ioctl() calls are converted to in-kernel function calls by
+i2c-dev. Examples include I2C_FUNCS, which queries the I2C adapter
+functionality using i2c.h:i2c_get_functionality(), and I2C_SMBUS, which
+performs an SMBus transaction using i2c-core.c:i2c_smbus_xfer().
+
+The i2c-dev driver is responsible for checking all the parameters that
+come from user-space for validity. After this point, there is no
+difference between these calls that came from user-space through i2c-dev
+and calls that would have been performed by kernel I2C chip drivers
+directly. This means that I2C bus drivers don't need to implement
+anything special to support access from user-space.
+
+5* These i2c-core.c/i2c.h functions are wrappers to the actual
+implementation of your I2C bus driver. Each adapter must declare
+callback functions implementing these standard calls.
+i2c.h:i2c_get_functionality() calls i2c_adapter.algo->functionality(),
+while i2c-core.c:i2c_smbus_xfer() calls either
+adapter.algo->smbus_xfer() if it is implemented, or if not,
+i2c-core.c:i2c_smbus_xfer_emulated() which in turn calls
+i2c_adapter.algo->master_xfer().
+
+After your I2C bus driver has processed these requests, execution runs
+up the call chain, with almost no processing done, except by i2c-dev to
+package the returned data, if any, in suitable format for the ioctl.
diff -r 1db1bb63824b -r 3eaec2bd5066 drivers/i2c/busses/Kconfig
--- a/drivers/i2c/busses/Kconfig	Mon Nov 23 07:32:47 2009 +0000
+++ b/drivers/i2c/busses/Kconfig	Mon Nov 23 23:31:56 2009 +0100
@@ -126,8 +126,9 @@ config I2C_I801
 	    ESB2
 	    ICH8
 	    ICH9
+	    Tolapai
 	    ICH10
-            PCH
+	    PCH
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-i801.
diff -r 1db1bb63824b -r 3eaec2bd5066 drivers/i2c/busses/i2c-i801.c
--- a/drivers/i2c/busses/i2c-i801.c	Mon Nov 23 07:32:47 2009 +0000
+++ b/drivers/i2c/busses/i2c-i801.c	Mon Nov 23 23:31:56 2009 +0100
@@ -1,9 +1,8 @@
 /*
-    i2c-i801.c - Part of lm_sensors, Linux kernel modules for hardware
-              monitoring
     Copyright (c) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>,
     Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
     <mdsxyz123@yahoo.com>
+    Copyright (C) 2007, 2008   Jean Delvare <khali@linux-fr.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -21,27 +20,37 @@
 */
 
 /*
-    SUPPORTED DEVICES	PCI ID
-    82801AA		2413           
-    82801AB		2423           
-    82801BA		2443           
-    82801CA/CAM		2483           
-    82801DB		24C3   (HW PEC supported, 32 byte buffer not supported)
-    82801EB		24D3   (HW PEC supported, 32 byte buffer not supported)
-    6300ESB		25A4
-    ICH6		266A
-    ICH7		27DA
-    ESB2		269B
-    ICH8		283E
-    ICH9		2930
-    ICH10		3A30
-    ICH10		3A60
-    PCH			3B30
-    This driver supports several versions of Intel's I/O Controller Hubs (ICH).
-    For SMBus support, they are similar to the PIIX4 and are part
-    of Intel's '810' and other chipsets.
-    See the file Documentation/i2c/busses/i2c-i801 for details.
-    I2C Block Read and Process Call are not supported.
+  Supports the following Intel I/O Controller Hubs (ICH):
+
+                                  I/O                     Block   I2C
+                                  region  SMBus   Block   proc.   block
+  Chip name             PCI ID    size    PEC     buffer  call    read
+  ----------------------------------------------------------------------
+  82801AA  (ICH)        0x2413     16      no      no      no      no
+  82801AB  (ICH0)       0x2423     16      no      no      no      no
+  82801BA  (ICH2)       0x2443     16      no      no      no      no
+  82801CA  (ICH3)       0x2483     32     soft     no      no      no
+  82801DB  (ICH4)       0x24c3     32     hard     yes     no      no
+  82801E   (ICH5)       0x24d3     32     hard     yes     yes     yes
+  6300ESB               0x25a4     32     hard     yes     yes     yes
+  82801F   (ICH6)       0x266a     32     hard     yes     yes     yes
+  6310ESB/6320ESB       0x269b     32     hard     yes     yes     yes
+  82801G   (ICH7)       0x27da     32     hard     yes     yes     yes
+  82801H   (ICH8)       0x283e     32     hard     yes     yes     yes
+  82801I   (ICH9)       0x2930     32     hard     yes     yes     yes
+  Tolapai               0x5032     32     hard     yes     yes     yes
+  ICH10                 0x3a30     32     hard     yes     yes     yes
+  ICH10                 0x3a60     32     hard     yes     yes     yes
+  PCH                   0x3b30     32     hard     yes     yes     yes
+
+  Features supported by this driver:
+  Software PEC                     no
+  Hardware PEC                     yes
+  Block buffer                     yes
+  Block process call transaction   no
+  I2C block read transaction       yes  (doesn't use the block buffer)
+
+  See the file Documentation/i2c/busses/i2c-i801 for details.
 */
 
 /* Note: we assume there can only be one I801, with one SMBus interface */
@@ -51,11 +60,11 @@
 #include <linux/kernel.h>
 #include <linux/stddef.h>
 #include <linux/delay.h>
-#include <linux/sched.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
-#include <asm/io.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
 
 /* I801 SMBus address offsets */
 #define SMBHSTSTS	(0 + i801_smba)
@@ -65,9 +74,9 @@
 #define SMBHSTDAT0	(5 + i801_smba)
 #define SMBHSTDAT1	(6 + i801_smba)
 #define SMBBLKDAT	(7 + i801_smba)
-#define SMBPEC		(8 + i801_smba)	/* ICH4 only */
-#define SMBAUXSTS	(12 + i801_smba)	/* ICH4 only */
-#define SMBAUXCTL	(13 + i801_smba)	/* ICH4 only */
+#define SMBPEC		(8 + i801_smba)		/* ICH3 and later */
+#define SMBAUXSTS	(12 + i801_smba)	/* ICH4 and later */
+#define SMBAUXCTL	(13 + i801_smba)	/* ICH4 and later */
 
 /* PCI Address Constants */
 #define SMBBAR		4
@@ -77,6 +86,13 @@
 #define SMBHSTCFG_HST_EN	1
 #define SMBHSTCFG_SMB_SMI_EN	2
 #define SMBHSTCFG_I2C_EN	4
+
+/* Auxillary control register bits, ICH4+ only */
+#define SMBAUXCTL_CRC		1
+#define SMBAUXCTL_E32B		2
+
+/* kill bit for SMBHSTCNT */
+#define SMBHSTCNT_KILL		2
 
 /* Other settings */
 #define MAX_TIMEOUT		100
@@ -87,104 +103,293 @@
 #define I801_BYTE		0x04
 #define I801_BYTE_DATA		0x08
 #define I801_WORD_DATA		0x0C
-#define I801_PROC_CALL		0x10	/* later chips only, unimplemented */
+#define I801_PROC_CALL		0x10	/* unimplemented */
 #define I801_BLOCK_DATA		0x14
-#define I801_I2C_BLOCK_DATA	0x18	/* unimplemented */
+#define I801_I2C_BLOCK_DATA	0x18	/* ICH5 and later */
 #define I801_BLOCK_LAST		0x34
-#define I801_I2C_BLOCK_LAST	0x38	/* unimplemented */
+#define I801_I2C_BLOCK_LAST	0x38	/* ICH5 and later */
 #define I801_START		0x40
-#define I801_PEC_EN		0x80	/* ICH4 only */
-
-
-static int i801_transaction(void);
-static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
-				  int command, int hwpec);
+#define I801_PEC_EN		0x80	/* ICH3 and later */
+
+/* I801 Hosts Status register bits */
+#define SMBHSTSTS_BYTE_DONE	0x80
+#define SMBHSTSTS_INUSE_STS	0x40
+#define SMBHSTSTS_SMBALERT_STS	0x20
+#define SMBHSTSTS_FAILED	0x10
+#define SMBHSTSTS_BUS_ERR	0x08
+#define SMBHSTSTS_DEV_ERR	0x04
+#define SMBHSTSTS_INTR		0x02
+#define SMBHSTSTS_HOST_BUSY	0x01
+
+#define STATUS_FLAGS		(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_FAILED | \
+				 SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | \
+				 SMBHSTSTS_INTR)
 
 static unsigned long i801_smba;
+static unsigned char i801_original_hstcfg;
 static struct pci_driver i801_driver;
 static struct pci_dev *I801_dev;
-static int isich4;
-
-static int i801_transaction(void)
-{
-	int temp;
+
+#define FEATURE_SMBUS_PEC	(1 << 0)
+#define FEATURE_BLOCK_BUFFER	(1 << 1)
+#define FEATURE_BLOCK_PROC	(1 << 2)
+#define FEATURE_I2C_BLOCK_READ	(1 << 3)
+static unsigned int i801_features;
+
+/* Make sure the SMBus host is ready to start transmitting.
+   Return 0 if it is, -EBUSY if it is not. */
+static int i801_check_pre(void)
+{
+	int status;
+
+	status = inb_p(SMBHSTSTS);
+	if (status & SMBHSTSTS_HOST_BUSY) {
+		dev_err(&I801_dev->dev, "SMBus is busy, can't use it!\n");
+		return -EBUSY;
+	}
+
+	status &= STATUS_FLAGS;
+	if (status) {
+		dev_dbg(&I801_dev->dev, "Clearing status flags (%02x)\n",
+			status);
+		outb_p(status, SMBHSTSTS);
+		status = inb_p(SMBHSTSTS) & STATUS_FLAGS;
+		if (status) {
+			dev_err(&I801_dev->dev,
+				"Failed clearing status flags (%02x)\n",
+				status);
+			return -EBUSY;
+		}
+	}
+
+	return 0;
+}
+
+/* Convert the status register to an error code, and clear it. */
+static int i801_check_post(int status, int timeout)
+{
 	int result = 0;
+
+	/* If the SMBus is still busy, we give up */
+	if (timeout) {
+		dev_err(&I801_dev->dev, "Transaction timeout\n");
+		/* try to stop the current command */
+		dev_dbg(&I801_dev->dev, "Terminating the current operation\n");
+		outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT);
+		msleep(1);
+		outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL), SMBHSTCNT);
+
+		/* Check if it worked */
+		status = inb_p(SMBHSTSTS);
+		if ((status & SMBHSTSTS_HOST_BUSY) ||
+		    !(status & SMBHSTSTS_FAILED))
+			dev_err(&I801_dev->dev,
+				"Failed terminating the transaction\n");
+		outb_p(STATUS_FLAGS, SMBHSTSTS);
+		return -ETIMEDOUT;
+	}
+
+	if (status & SMBHSTSTS_FAILED) {
+		result = -EIO;
+		dev_err(&I801_dev->dev, "Transaction failed\n");
+	}
+	if (status & SMBHSTSTS_DEV_ERR) {
+		result = -ENXIO;
+		dev_dbg(&I801_dev->dev, "No response\n");
+	}
+	if (status & SMBHSTSTS_BUS_ERR) {
+		result = -EAGAIN;
+		dev_dbg(&I801_dev->dev, "Lost arbitration\n");
+	}
+
+	if (result) {
+		/* Clear error flags */
+		outb_p(status & STATUS_FLAGS, SMBHSTSTS);
+		status = inb_p(SMBHSTSTS) & STATUS_FLAGS;
+		if (status) {
+			dev_warn(&I801_dev->dev, "Failed clearing status "
+				 "flags at end of transaction (%02x)\n",
+				 status);
+		}
+	}
+
+	return result;
+}
+
+static int i801_transaction(int xact)
+{
+	int status;
+	int result;
 	int timeout = 0;
 
-	dev_dbg(&I801_dev->dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
-		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
-		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
-		inb_p(SMBHSTDAT1));
-
-	/* Make sure the SMBus host is ready to start transmitting */
-	/* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
-	if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
-		dev_dbg(&I801_dev->dev, "SMBus busy (%02x). Resetting...\n",
-			temp);
-		outb_p(temp, SMBHSTSTS);
-		if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
-			dev_dbg(&I801_dev->dev, "Failed! (%02x)\n", temp);
-			return -1;
-		} else {
-			dev_dbg(&I801_dev->dev, "Successfull!\n");
-		}
-	}
-
-	outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT);
+	result = i801_check_pre();
+	if (result < 0)
+		return result;
+
+	/* the current contents of SMBHSTCNT can be overwritten, since PEC,
+	 * INTREN, SMBSCMD are passed in xact */
+	outb_p(xact | I801_START, SMBHSTCNT);
 
 	/* We will always wait for a fraction of a second! */
 	do {
 		msleep(1);
-		temp = inb_p(SMBHSTSTS);
-	} while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT));
-
-	/* If the SMBus is still busy, we give up */
+		status = inb_p(SMBHSTSTS);
+	} while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT));
+
+	result = i801_check_post(status, timeout >= MAX_TIMEOUT);
+	if (result < 0)
+		return result;
+
+	outb_p(SMBHSTSTS_INTR, SMBHSTSTS);
+	return 0;
+}
+
+/* wait for INTR bit as advised by Intel */
+static void i801_wait_hwpec(void)
+{
+	int timeout = 0;
+	int status;
+
+	do {
+		msleep(1);
+		status = inb_p(SMBHSTSTS);
+	} while ((!(status & SMBHSTSTS_INTR))
+		 && (timeout++ < MAX_TIMEOUT));
+
 	if (timeout >= MAX_TIMEOUT) {
-		dev_dbg(&I801_dev->dev, "SMBus Timeout!\n");
-		result = -1;
-	}
-
-	if (temp & 0x10) {
-		result = -1;
-		dev_dbg(&I801_dev->dev, "Error: Failed bus transaction\n");
-	}
-
-	if (temp & 0x08) {
-		result = -1;
-		dev_err(&I801_dev->dev, "Bus collision! SMBus may be locked "
-			"until next hard reset. (sorry!)\n");
-		/* Clock stops and slave is stuck in mid-transmission */
-	}
-
-	if (temp & 0x04) {
-		result = -1;
-		dev_dbg(&I801_dev->dev, "Error: no response!\n");
-	}
-
-	if ((inb_p(SMBHSTSTS) & 0x1f) != 0x00)
-		outb_p(inb(SMBHSTSTS), SMBHSTSTS);
-
-	if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
-		dev_dbg(&I801_dev->dev, "Failed reset at end of transaction "
-			"(%02x)\n", temp);
-	}
-	dev_dbg(&I801_dev->dev, "Transaction (post): CNT=%02x, CMD=%02x, "
-		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
-		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
-		inb_p(SMBHSTDAT1));
-	return result;
-}
-
-/* All-inclusive block transaction function */
+		dev_dbg(&I801_dev->dev, "PEC Timeout!\n");
+	}
+	outb_p(status, SMBHSTSTS);
+}
+
+static int i801_block_transaction_by_block(union i2c_smbus_data *data,
+					   char read_write, int hwpec)
+{
+	int i, len;
+	int status;
+
+	inb_p(SMBHSTCNT); /* reset the data buffer index */
+
+	/* Use 32-byte buffer to process this transaction */
+	if (read_write == I2C_SMBUS_WRITE) {
+		len = data->block[0];
+		outb_p(len, SMBHSTDAT0);
+		for (i = 0; i < len; i++)
+			outb_p(data->block[i+1], SMBBLKDAT);
+	}
+
+	status = i801_transaction(I801_BLOCK_DATA | ENABLE_INT9 |
+				  I801_PEC_EN * hwpec);
+	if (status)
+		return status;
+
+	if (read_write == I2C_SMBUS_READ) {
+		len = inb_p(SMBHSTDAT0);
+		if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
+			return -EPROTO;
+
+		data->block[0] = len;
+		for (i = 0; i < len; i++)
+			data->block[i + 1] = inb_p(SMBBLKDAT);
+	}
+	return 0;
+}
+
+static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
+					       char read_write, int command,
+					       int hwpec)
+{
+	int i, len;
+	int smbcmd;
+	int status;
+	int result;
+	int timeout;
+
+	result = i801_check_pre();
+	if (result < 0)
+		return result;
+
+	len = data->block[0];
+
+	if (read_write == I2C_SMBUS_WRITE) {
+		outb_p(len, SMBHSTDAT0);
+		outb_p(data->block[1], SMBBLKDAT);
+	}
+
+	for (i = 1; i <= len; i++) {
+		if (i == len && read_write == I2C_SMBUS_READ) {
+			if (command == I2C_SMBUS_I2C_BLOCK_DATA)
+				smbcmd = I801_I2C_BLOCK_LAST;
+			else
+				smbcmd = I801_BLOCK_LAST;
+		} else {
+			if (command == I2C_SMBUS_I2C_BLOCK_DATA
+			 && read_write == I2C_SMBUS_READ)
+				smbcmd = I801_I2C_BLOCK_DATA;
+			else
+				smbcmd = I801_BLOCK_DATA;
+		}
+		outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT);
+
+		if (i == 1)
+			outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT);
+
+		/* We will always wait for a fraction of a second! */
+		timeout = 0;
+		do {
+			msleep(1);
+			status = inb_p(SMBHSTSTS);
+		}
+		while ((!(status & SMBHSTSTS_BYTE_DONE))
+		       && (timeout++ < MAX_TIMEOUT));
+
+		result = i801_check_post(status, timeout >= MAX_TIMEOUT);
+		if (result < 0)
+			return result;
+
+		if (i == 1 && read_write == I2C_SMBUS_READ
+		 && command != I2C_SMBUS_I2C_BLOCK_DATA) {
+			len = inb_p(SMBHSTDAT0);
+			if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
+				dev_err(&I801_dev->dev,
+					"Illegal SMBus block read size %d\n",
+					len);
+				/* Recover */
+				while (inb_p(SMBHSTSTS) & SMBHSTSTS_HOST_BUSY)
+					outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS);
+				outb_p(SMBHSTSTS_INTR, SMBHSTSTS);
+				return -EPROTO;
+			}
+			data->block[0] = len;
+		}
+
+		/* Retrieve/store value in SMBBLKDAT */
+		if (read_write == I2C_SMBUS_READ)
+			data->block[i] = inb_p(SMBBLKDAT);
+		if (read_write == I2C_SMBUS_WRITE && i+1 <= len)
+			outb_p(data->block[i+1], SMBBLKDAT);
+
+		/* signals SMBBLKDAT ready */
+		outb_p(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR, SMBHSTSTS);
+	}
+
+	return 0;
+}
+
+static int i801_set_block_buffer_mode(void)
+{
+	outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_E32B, SMBAUXCTL);
+	if ((inb_p(SMBAUXCTL) & SMBAUXCTL_E32B) == 0)
+		return -EIO;
+	return 0;
+}
+
+/* Block transaction function */
 static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
 				  int command, int hwpec)
 {
-	int i, len;
-	int smbcmd;
-	int temp;
 	int result = 0;
-	int timeout;
-	unsigned char hostc, errmask;
+	unsigned char hostc;
 
 	if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
 		if (read_write == I2C_SMBUS_WRITE) {
@@ -192,154 +397,45 @@ static int i801_block_transaction(union 
 			pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc);
 			pci_write_config_byte(I801_dev, SMBHSTCFG,
 					      hostc | SMBHSTCFG_I2C_EN);
-		} else {
+		} else if (!(i801_features & FEATURE_I2C_BLOCK_READ)) {
 			dev_err(&I801_dev->dev,
-				"I2C_SMBUS_I2C_BLOCK_READ not DB!\n");
-			return -1;
+				"I2C block read is unsupported!\n");
+			return -EOPNOTSUPP;
 		}
 	}
 
-	if (read_write == I2C_SMBUS_WRITE) {
-		len = data->block[0];
-		if (len < 1)
-			len = 1;
-		if (len > 32)
-			len = 32;
-		outb_p(len, SMBHSTDAT0);
-		outb_p(data->block[1], SMBBLKDAT);
+	if (read_write == I2C_SMBUS_WRITE
+	 || command == I2C_SMBUS_I2C_BLOCK_DATA) {
+		if (data->block[0] < 1)
+			data->block[0] = 1;
+		if (data->block[0] > I2C_SMBUS_BLOCK_MAX)
+			data->block[0] = I2C_SMBUS_BLOCK_MAX;
 	} else {
-		len = 32;	/* max for reads */
-	}
-
-	if(isich4 && command != I2C_SMBUS_I2C_BLOCK_DATA) {
-		/* set 32 byte buffer */
-	}
-
-	for (i = 1; i <= len; i++) {
-		if (i == len && read_write == I2C_SMBUS_READ)
-			smbcmd = I801_BLOCK_LAST;
-		else
-			smbcmd = I801_BLOCK_DATA;
-		outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT);
-
-		dev_dbg(&I801_dev->dev, "Block (pre %d): CNT=%02x, CMD=%02x, "
-			"ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i,
-			inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
-			inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
-
-		/* Make sure the SMBus host is ready to start transmitting */
-		temp = inb_p(SMBHSTSTS);
-		if (i == 1) {
-			/* Erronenous conditions before transaction: 
-			 * Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
-			errmask=0x9f; 
-		} else {
-			/* Erronenous conditions during transaction: 
-			 * Failed, Bus_Err, Dev_Err, Intr */
-			errmask=0x1e; 
-		}
-		if (temp & errmask) {
-			dev_dbg(&I801_dev->dev, "SMBus busy (%02x). "
-				"Resetting...\n", temp);
-			outb_p(temp, SMBHSTSTS);
-			if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) {
-				dev_err(&I801_dev->dev,
-					"Reset failed! (%02x)\n", temp);
-				result = -1;
-                                goto END;
-			}
-			if (i != 1) {
-				/* if die in middle of block transaction, fail */
-				result = -1;
-				goto END;
-			}
-		}
-
-		if (i == 1)
-			outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT);
-
-		/* We will always wait for a fraction of a second! */
-		timeout = 0;
-		do {
-			msleep(1);
-			temp = inb_p(SMBHSTSTS);
-		}
-		    while ((!(temp & 0x80))
-			   && (timeout++ < MAX_TIMEOUT));
-
-		/* If the SMBus is still busy, we give up */
-		if (timeout >= MAX_TIMEOUT) {
-			result = -1;
-			dev_dbg(&I801_dev->dev, "SMBus Timeout!\n");
-		}
-
-		if (temp & 0x10) {
-			result = -1;
-			dev_dbg(&I801_dev->dev,
-				"Error: Failed bus transaction\n");
-		} else if (temp & 0x08) {
-			result = -1;
-			dev_err(&I801_dev->dev, "Bus collision!\n");
-		} else if (temp & 0x04) {
-			result = -1;
-			dev_dbg(&I801_dev->dev, "Error: no response!\n");
-		}
-
-		if (i == 1 && read_write == I2C_SMBUS_READ) {
-			len = inb_p(SMBHSTDAT0);
-			if (len < 1)
-				len = 1;
-			if (len > 32)
-				len = 32;
-			data->block[0] = len;
-		}
-
-		/* Retrieve/store value in SMBBLKDAT */
-		if (read_write == I2C_SMBUS_READ)
-			data->block[i] = inb_p(SMBBLKDAT);
-		if (read_write == I2C_SMBUS_WRITE && i+1 <= len)
-			outb_p(data->block[i+1], SMBBLKDAT);
-		if ((temp & 0x9e) != 0x00)
-			outb_p(temp, SMBHSTSTS);  /* signals SMBBLKDAT ready */
-
-		if ((temp = (0x1e & inb_p(SMBHSTSTS))) != 0x00) {
-			dev_dbg(&I801_dev->dev,
-				"Bad status (%02x) at end of transaction\n",
-				temp);
-		}
-		dev_dbg(&I801_dev->dev, "Block (post %d): CNT=%02x, CMD=%02x, "
-			"ADD=%02x, DAT0=%02x, BLKDAT=%02x\n", i,
-			inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
-			inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
-
-		if (result < 0)
-			goto END;
-	}
-
-	if (hwpec) {
-		/* wait for INTR bit as advised by Intel */
-		timeout = 0;
-		do {
-			msleep(1);
-			temp = inb_p(SMBHSTSTS);
-		} while ((!(temp & 0x02))
-			   && (timeout++ < MAX_TIMEOUT));
-
-		if (timeout >= MAX_TIMEOUT) {
-			dev_dbg(&I801_dev->dev, "PEC Timeout!\n");
-		}
-		outb_p(temp, SMBHSTSTS); 
-	}
-	result = 0;
-END:
-	if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
+		data->block[0] = 32;	/* max for SMBus block reads */
+	}
+
+	if ((i801_features & FEATURE_BLOCK_BUFFER)
+	 && !(command == I2C_SMBUS_I2C_BLOCK_DATA
+	      && read_write == I2C_SMBUS_READ)
+	 && i801_set_block_buffer_mode() == 0)
+		result = i801_block_transaction_by_block(data, read_write,
+							 hwpec);
+	else
+		result = i801_block_transaction_byte_by_byte(data, read_write,
+							     command, hwpec);
+
+	if (result == 0 && hwpec)
+		i801_wait_hwpec();
+
+	if (command == I2C_SMBUS_I2C_BLOCK_DATA
+	 && read_write == I2C_SMBUS_WRITE) {
 		/* restore saved configuration register value */
 		pci_write_config_byte(I801_dev, SMBHSTCFG, hostc);
 	}
 	return result;
 }
 
-/* Return -1 on error. */
+/* Return negative errno on error. */
 static s32 i801_access(struct i2c_adapter * adap, u16 addr,
 		       unsigned short flags, char read_write, u8 command,
 		       int size, union i2c_smbus_data * data)
@@ -348,7 +444,7 @@ static s32 i801_access(struct i2c_adapte
 	int block = 0;
 	int ret, xact = 0;
 
-	hwpec = isich4 && (flags & I2C_CLIENT_PEC)
+	hwpec = (i801_features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)
 		&& size != I2C_SMBUS_QUICK
 		&& size != I2C_SMBUS_I2C_BLOCK_DATA;
 
@@ -384,36 +480,49 @@ static s32 i801_access(struct i2c_adapte
 		xact = I801_WORD_DATA;
 		break;
 	case I2C_SMBUS_BLOCK_DATA:
-	case I2C_SMBUS_I2C_BLOCK_DATA:
 		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
 		       SMBHSTADD);
 		outb_p(command, SMBHSTCMD);
 		block = 1;
 		break;
-	case I2C_SMBUS_PROC_CALL:
+	case I2C_SMBUS_I2C_BLOCK_DATA:
+		/* NB: page 240 of ICH5 datasheet shows that the R/#W
+		 * bit should be cleared here, even when reading */
+		outb_p((addr & 0x7f) << 1, SMBHSTADD);
+		if (read_write == I2C_SMBUS_READ) {
+			/* NB: page 240 of ICH5 datasheet also shows
+			 * that DATA1 is the cmd field when reading */
+			outb_p(command, SMBHSTDAT1);
+		} else
+			outb_p(command, SMBHSTCMD);
+		block = 1;
+		break;
 	default:
 		dev_err(&I801_dev->dev, "Unsupported transaction %d\n", size);
-		return -1;
-	}
-
-	outb_p(hwpec, SMBAUXCTL);	/* enable/disable hardware PEC */
+		return -EOPNOTSUPP;
+	}
+
+	if (hwpec)	/* enable/disable hardware PEC */
+		outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_CRC, SMBAUXCTL);
+	else
+		outb_p(inb_p(SMBAUXCTL) & (~SMBAUXCTL_CRC), SMBAUXCTL);
 
 	if(block)
 		ret = i801_block_transaction(data, read_write, size, hwpec);
-	else {
-		outb_p(xact | ENABLE_INT9, SMBHSTCNT);
-		ret = i801_transaction();
-	}
+	else
+		ret = i801_transaction(xact | ENABLE_INT9);
 
 	/* Some BIOSes don't like it when PEC is enabled at reboot or resume
-	   time, so we forcibly disable it after every transaction. */
-	if (hwpec)
-		outb_p(0, SMBAUXCTL);
+	   time, so we forcibly disable it after every transaction. Turn off
+	   E32B for the same reason. */
+	if (hwpec || block)
+		outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B),
+		       SMBAUXCTL);
 
 	if(block)
 		return ret;
 	if(ret)
-		return -1;
+		return ret;
 	if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK))
 		return 0;
 
@@ -433,9 +542,11 @@ static u32 i801_func(struct i2c_adapter 
 static u32 i801_func(struct i2c_adapter *adapter)
 {
 	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
-	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
-	    I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK
-	     | (isich4 ? I2C_FUNC_SMBUS_HWPEC_CALC : 0);
+	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	       I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
+	       ((i801_features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) |
+	       ((i801_features & FEATURE_I2C_BLOCK_READ) ?
+		I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0);
 }
 
 static struct i2c_algorithm smbus_algorithm = {
@@ -462,6 +573,7 @@ static struct pci_device_id i801_ids[] =
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_6) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TOLAPAI_1) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_4) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_5) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PCH_SMBUS) },
@@ -470,18 +582,66 @@ static struct pci_device_id i801_ids[] =
 
 MODULE_DEVICE_TABLE (pci, i801_ids);
 
+#if defined CONFIG_INPUT_APANEL || defined CONFIG_INPUT_APANEL_MODULE
+static unsigned char apanel_addr;
+
+/* Scan the system ROM for the signature "FJKEYINF" */
+static __init const void __iomem *bios_signature(const void __iomem *bios)
+{
+	ssize_t offset;
+	const unsigned char signature[] = "FJKEYINF";
+
+	for (offset = 0; offset < 0x10000; offset += 0x10) {
+		if (check_signature(bios + offset, signature,
+				    sizeof(signature)-1))
+			return bios + offset;
+	}
+	return NULL;
+}
+
+static void __init input_apanel_init(void)
+{
+	void __iomem *bios;
+	const void __iomem *p;
+
+	bios = ioremap(0xF0000, 0x10000); /* Can't fail */
+	p = bios_signature(bios);
+	if (p) {
+		/* just use the first address */
+		apanel_addr = readb(p + 8 + 3) >> 1;
+	}
+	iounmap(bios);
+}
+#else
+static void __init input_apanel_init(void) {}
+#endif
+
 static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
 	unsigned char temp;
 	int err;
 
 	I801_dev = dev;
-	if ((dev->device == PCI_DEVICE_ID_INTEL_82801DB_3) ||
-	    (dev->device == PCI_DEVICE_ID_INTEL_82801EB_3) ||
-	    (dev->device == PCI_DEVICE_ID_INTEL_ESB_4))
-		isich4 = 1;
-	else
-		isich4 = 0;
+	i801_features = 0;
+	switch (dev->device) {
+	case PCI_DEVICE_ID_INTEL_82801EB_3:
+	case PCI_DEVICE_ID_INTEL_ESB_4:
+	case PCI_DEVICE_ID_INTEL_ICH6_16:
+	case PCI_DEVICE_ID_INTEL_ICH7_17:
+	case PCI_DEVICE_ID_INTEL_ESB2_17:
+	case PCI_DEVICE_ID_INTEL_ICH8_5:
+	case PCI_DEVICE_ID_INTEL_ICH9_6:
+	case PCI_DEVICE_ID_INTEL_TOLAPAI_1:
+	case PCI_DEVICE_ID_INTEL_ICH10_4:
+	case PCI_DEVICE_ID_INTEL_ICH10_5:
+	case PCI_DEVICE_ID_INTEL_PCH_SMBUS:
+		i801_features |= FEATURE_I2C_BLOCK_READ;
+		/* fall through */
+	case PCI_DEVICE_ID_INTEL_82801DB_3:
+		i801_features |= FEATURE_SMBUS_PEC;
+		i801_features |= FEATURE_BLOCK_BUFFER;
+		break;
+	}
 
 	err = pci_enable_device(dev);
 	if (err) {
@@ -508,6 +668,7 @@ static int __devinit i801_probe(struct p
 	}
 
 	pci_read_config_byte(I801_dev, SMBHSTCFG, &temp);
+	i801_original_hstcfg = temp;
 	temp &= ~SMBHSTCFG_I2C_EN;	/* SMBus timing */
 	if (!(temp & SMBHSTCFG_HST_EN)) {
 		dev_info(&dev->dev, "Enabling SMBus device\n");
@@ -520,16 +681,34 @@ static int __devinit i801_probe(struct p
 	else
 		dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n");
 
-	/* set up the driverfs linkage to our parent device */
+	/* Clear special mode bits */
+	if (i801_features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER))
+		outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B),
+		       SMBAUXCTL);
+
+	/* set up the sysfs linkage to our parent device */
 	i801_adapter.dev.parent = &dev->dev;
 
-	snprintf(i801_adapter.name, I2C_NAME_SIZE,
+	snprintf(i801_adapter.name, sizeof(i801_adapter.name),
 		"SMBus I801 adapter at %04lx", i801_smba);
 	err = i2c_add_adapter(&i801_adapter);
 	if (err) {
 		dev_err(&dev->dev, "Failed to add SMBus adapter\n");
 		goto exit_release;
 	}
+
+	/* Register optional slaves */
+#if defined CONFIG_INPUT_APANEL || defined CONFIG_INPUT_APANEL_MODULE
+	if (apanel_addr) {
+		struct i2c_board_info info;
+
+		memset(&info, 0, sizeof(struct i2c_board_info));
+		info.addr = apanel_addr;
+		strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE);
+		i2c_new_device(&i801_adapter, &info);
+	}
+#endif
+
 	return 0;
 
 exit_release:
@@ -541,6 +720,7 @@ static void __devexit i801_remove(struct
 static void __devexit i801_remove(struct pci_dev *dev)
 {
 	i2c_del_adapter(&i801_adapter);
+	pci_write_config_byte(I801_dev, SMBHSTCFG, i801_original_hstcfg);
 	pci_release_region(dev, SMBBAR);
 	/*
 	 * do not call pci_disable_device(dev) since it can cause hard hangs on
@@ -548,15 +728,38 @@ static void __devexit i801_remove(struct
 	 */
 }
 
+#ifdef CONFIG_PM
+static int i801_suspend(struct pci_dev *dev, pm_message_t mesg)
+{
+	pci_save_state(dev);
+	pci_write_config_byte(dev, SMBHSTCFG, i801_original_hstcfg);
+	pci_set_power_state(dev, pci_choose_state(dev, mesg));
+	return 0;
+}
+
+static int i801_resume(struct pci_dev *dev)
+{
+	pci_set_power_state(dev, PCI_D0);
+	pci_restore_state(dev);
+	return pci_enable_device(dev);
+}
+#else
+#define i801_suspend NULL
+#define i801_resume NULL
+#endif
+
 static struct pci_driver i801_driver = {
 	.name		= "i801_smbus",
 	.id_table	= i801_ids,
 	.probe		= i801_probe,
 	.remove		= __devexit_p(i801_remove),
+	.suspend	= i801_suspend,
+	.resume		= i801_resume,
 };
 
 static int __init i2c_i801_init(void)
 {
+	input_apanel_init();
 	return pci_register_driver(&i801_driver);
 }
 
@@ -565,9 +768,8 @@ static void __exit i2c_i801_exit(void)
 	pci_unregister_driver(&i801_driver);
 }
 
-MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
-		"Philip Edelbrock <phil@netroedge.com>, "
-		"and Mark D. Studebaker <mdsxyz123@yahoo.com>");
+MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>, "
+	      "Jean Delvare <khali@linux-fr.org>");
 MODULE_DESCRIPTION("I801 SMBus driver");
 MODULE_LICENSE("GPL");
 
diff -r 1db1bb63824b -r 3eaec2bd5066 include/linux/i2c.h
--- a/include/linux/i2c.h	Mon Nov 23 07:32:47 2009 +0000
+++ b/include/linux/i2c.h	Mon Nov 23 23:31:56 2009 +0100
@@ -380,6 +380,7 @@ struct i2c_msg {
 #define I2C_FUNC_I2C			0x00000001
 #define I2C_FUNC_10BIT_ADDR		0x00000002
 #define I2C_FUNC_PROTOCOL_MANGLING	0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */
+#define I2C_FUNC_SMBUS_PEC		0x00000008
 #define I2C_FUNC_SMBUS_HWPEC_CALC	0x00000008 /* SMBus 2.0 */
 #define I2C_FUNC_SMBUS_BLOCK_PROC_CALL	0x00008000 /* SMBus 2.0 */
 #define I2C_FUNC_SMBUS_QUICK		0x00010000 
@@ -416,7 +417,8 @@ struct i2c_msg {
                              I2C_FUNC_SMBUS_WORD_DATA | \
                              I2C_FUNC_SMBUS_PROC_CALL | \
                              I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | \
-                             I2C_FUNC_SMBUS_I2C_BLOCK)
+                             I2C_FUNC_SMBUS_I2C_BLOCK | \
+                             I2C_FUNC_SMBUS_PEC)
 
 /* 
  * Data for SMBus Messages 
diff -r 1db1bb63824b -r 3eaec2bd5066 include/linux/pci_ids.h
--- a/include/linux/pci_ids.h	Mon Nov 23 07:32:47 2009 +0000
+++ b/include/linux/pci_ids.h	Mon Nov 23 23:31:56 2009 +0100
@@ -2222,6 +2222,7 @@
 #define PCI_DEVICE_ID_INTEL_PCH_LPC_MIN	0x3b00
 #define PCI_DEVICE_ID_INTEL_PCH_LPC_MAX	0x3b1f
 #define PCI_DEVICE_ID_INTEL_PCH_SMBUS	0x3b30
+#define PCI_DEVICE_ID_INTEL_TOLAPAI_1	0x5032
 #define PCI_DEVICE_ID_INTEL_82371SB_0	0x7000
 #define PCI_DEVICE_ID_INTEL_82371SB_1	0x7010
 #define PCI_DEVICE_ID_INTEL_82371SB_2	0x7020

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2009-11-24 11:38 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-11-24 11:38 [PATCH 3 of 10] New/Updated drivers: Intel 82801 (ICH) driver backported from Linux Kernel Ver. 2.6.29.2 Daniel Kiper

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.