2005-04-17 02:20:36 +04:00
/*
Copyright ( c ) 1998 - 2002 Frodo Looijaard < frodol @ dds . nl > ,
Philip Edelbrock < phil @ netroedge . com > , and Mark D . Studebaker
< mdsxyz123 @ yahoo . com >
2008-07-15 00:38:33 +04:00
Copyright ( C ) 2007 , 2008 Jean Delvare < khali @ linux - fr . org >
2005-04-17 02:20:36 +04:00
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
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
/*
2008-01-27 20:14:49 +03:00
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
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
82801 AA ( ICH ) 0x2413 16 no no no no
82801 AB ( ICH0 ) 0x2423 16 no no no no
82801 BA ( ICH2 ) 0x2443 16 no no no no
82801 CA ( ICH3 ) 0x2483 32 soft no no no
82801 DB ( ICH4 ) 0x24c3 32 hard yes no no
82801 E ( ICH5 ) 0x24d3 32 hard yes yes yes
6300 ESB 0x25a4 32 hard yes yes yes
82801F ( ICH6 ) 0x266a 32 hard yes yes yes
6310 ESB / 6320 ESB 0x269b 32 hard yes yes yes
82801 G ( ICH7 ) 0x27da 32 hard yes yes yes
82801 H ( ICH8 ) 0x283e 32 hard yes yes yes
82801 I ( ICH9 ) 0x2930 32 hard yes yes yes
2008-02-24 22:03:42 +03:00
Tolapai 0x5032 32 hard yes yes yes
ICH10 0x3a30 32 hard yes yes yes
ICH10 0x3a60 32 hard yes yes yes
2008-01-27 20:14:49 +03:00
Features supported by this driver :
Software PEC no
Hardware PEC yes
Block buffer yes
Block process call transaction no
2008-01-27 20:14:50 +03:00
I2C block read transaction yes ( doesn ' t use the block buffer )
2008-01-27 20:14:49 +03:00
See the file Documentation / i2c / busses / i2c - i801 for details .
2005-04-17 02:20:36 +04:00
*/
/* Note: we assume there can only be one I801, with one SMBus interface */
# include <linux/module.h>
# include <linux/pci.h>
# include <linux/kernel.h>
# include <linux/stddef.h>
# include <linux/delay.h>
# include <linux/ioport.h>
# include <linux/init.h>
# include <linux/i2c.h>
2008-07-15 00:38:33 +04:00
# include <linux/acpi.h>
2005-04-17 02:20:36 +04:00
# include <asm/io.h>
/* I801 SMBus address offsets */
# define SMBHSTSTS (0 + i801_smba)
# define SMBHSTCNT (2 + i801_smba)
# define SMBHSTCMD (3 + i801_smba)
# define SMBHSTADD (4 + i801_smba)
# define SMBHSTDAT0 (5 + i801_smba)
# define SMBHSTDAT1 (6 + i801_smba)
# define SMBBLKDAT (7 + i801_smba)
2008-01-27 20:14:49 +03:00
# define SMBPEC (8 + i801_smba) /* ICH3 and later */
# define SMBAUXSTS (12 + i801_smba) /* ICH4 and later */
# define SMBAUXCTL (13 + i801_smba) /* ICH4 and later */
2005-04-17 02:20:36 +04:00
/* PCI Address Constants */
2006-06-12 23:53:02 +04:00
# define SMBBAR 4
2005-04-17 02:20:36 +04:00
# define SMBHSTCFG 0x040
/* Host configuration bits for SMBHSTCFG */
# define SMBHSTCFG_HST_EN 1
# define SMBHSTCFG_SMB_SMI_EN 2
# define SMBHSTCFG_I2C_EN 4
2007-07-12 16:12:31 +04:00
/* Auxillary control register bits, ICH4+ only */
# define SMBAUXCTL_CRC 1
# define SMBAUXCTL_E32B 2
/* kill bit for SMBHSTCNT */
# define SMBHSTCNT_KILL 2
2005-04-17 02:20:36 +04:00
/* Other settings */
# define MAX_TIMEOUT 100
# define ENABLE_INT9 0 /* set to 0x01 to enable - untested */
/* I801 command constants */
# define I801_QUICK 0x00
# define I801_BYTE 0x04
# define I801_BYTE_DATA 0x08
# define I801_WORD_DATA 0x0C
2008-01-27 20:14:49 +03:00
# define I801_PROC_CALL 0x10 /* unimplemented */
2005-04-17 02:20:36 +04:00
# define I801_BLOCK_DATA 0x14
2008-01-27 20:14:50 +03:00
# define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */
2005-04-17 02:20:36 +04:00
# define I801_BLOCK_LAST 0x34
2008-01-27 20:14:50 +03:00
# define I801_I2C_BLOCK_LAST 0x38 /* ICH5 and later */
2005-04-17 02:20:36 +04:00
# define I801_START 0x40
2008-01-27 20:14:49 +03:00
# define I801_PEC_EN 0x80 /* ICH3 and later */
2005-04-17 02:20:36 +04:00
2007-07-12 16:12:31 +04:00
/* 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
2005-04-17 02:20:36 +04:00
2008-07-15 00:38:33 +04:00
# define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_FAILED | \
SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | \
SMBHSTSTS_INTR )
2006-06-12 23:53:02 +04:00
static unsigned long i801_smba ;
2007-03-22 21:49:01 +03:00
static unsigned char i801_original_hstcfg ;
2005-09-25 18:37:04 +04:00
static struct pci_driver i801_driver ;
2005-04-17 02:20:36 +04:00
static struct pci_dev * I801_dev ;
2008-01-27 20:14:50 +03:00
# 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 ;
2005-04-17 02:20:36 +04:00
2008-07-15 00:38:33 +04:00
/* 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 )
2005-04-17 02:20:36 +04:00
{
2008-07-15 00:38:32 +04:00
int status ;
2005-04-17 02:20:36 +04:00
2008-07-15 00:38:33 +04:00
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 " ,
2008-07-15 00:38:32 +04:00
status ) ;
outb_p ( status , SMBHSTSTS ) ;
2008-07-15 00:38:33 +04:00
status = inb_p ( SMBHSTSTS ) & STATUS_FLAGS ;
if ( status ) {
dev_err ( & I801_dev - > dev ,
" Failed clearing status flags (%02x) \n " ,
status ) ;
2008-07-15 00:38:25 +04:00
return - EBUSY ;
2005-04-17 02:20:36 +04:00
}
}
2008-07-15 00:38:33 +04:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
2008-07-15 00:38:33 +04:00
/* Convert the status register to an error code, and clear it. */
static int i801_check_post ( int status , int timeout )
{
int result = 0 ;
2005-04-17 02:20:36 +04:00
/* If the SMBus is still busy, we give up */
2008-07-15 00:38:33 +04:00
if ( timeout ) {
dev_err ( & I801_dev - > dev , " Transaction timeout \n " ) ;
2007-07-12 16:12:31 +04:00
/* 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 ) ;
2008-07-15 00:38:33 +04:00
/* 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 ;
2005-04-17 02:20:36 +04:00
}
2008-07-15 00:38:32 +04:00
if ( status & SMBHSTSTS_FAILED ) {
2008-07-15 00:38:25 +04:00
result = - EIO ;
2008-07-15 00:38:33 +04:00
dev_err ( & I801_dev - > dev , " Transaction failed \n " ) ;
}
if ( status & SMBHSTSTS_DEV_ERR ) {
result = - ENXIO ;
dev_dbg ( & I801_dev - > dev , " No response \n " ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-15 00:38:32 +04:00
if ( status & SMBHSTSTS_BUS_ERR ) {
2008-07-15 00:38:32 +04:00
result = - EAGAIN ;
dev_dbg ( & I801_dev - > dev , " Lost arbitration \n " ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-15 00:38:33 +04:00
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 ) ;
}
2005-04-17 02:20:36 +04:00
}
return result ;
}
2008-07-15 00:38:33 +04:00
static int i801_transaction ( int xact )
{
int status ;
int result ;
int timeout = 0 ;
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 ) ;
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 ;
}
2007-07-12 16:12:31 +04:00
/* wait for INTR bit as advised by Intel */
static void i801_wait_hwpec ( void )
{
int timeout = 0 ;
2008-07-15 00:38:32 +04:00
int status ;
2007-07-12 16:12:31 +04:00
do {
msleep ( 1 ) ;
2008-07-15 00:38:32 +04:00
status = inb_p ( SMBHSTSTS ) ;
} while ( ( ! ( status & SMBHSTSTS_INTR ) )
2007-07-12 16:12:31 +04:00
& & ( timeout + + < MAX_TIMEOUT ) ) ;
if ( timeout > = MAX_TIMEOUT ) {
dev_dbg ( & I801_dev - > dev , " PEC Timeout! \n " ) ;
}
2008-07-15 00:38:32 +04:00
outb_p ( status , SMBHSTSTS ) ;
2007-07-12 16:12:31 +04:00
}
2007-07-12 16:12:31 +04:00
static int i801_block_transaction_by_block ( union i2c_smbus_data * data ,
char read_write , int hwpec )
{
int i , len ;
2008-07-15 00:38:25 +04:00
int status ;
2007-07-12 16:12:31 +04:00
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 ) ;
}
2008-07-15 00:38:25 +04:00
status = i801_transaction ( I801_BLOCK_DATA | ENABLE_INT9 |
I801_PEC_EN * hwpec ) ;
if ( status )
return status ;
2007-07-12 16:12:31 +04:00
if ( read_write = = I2C_SMBUS_READ ) {
len = inb_p ( SMBHSTDAT0 ) ;
if ( len < 1 | | len > I2C_SMBUS_BLOCK_MAX )
2008-07-15 00:38:25 +04:00
return - EPROTO ;
2007-07-12 16:12:31 +04:00
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 ,
2008-01-27 20:14:50 +03:00
char read_write , int command ,
int hwpec )
2005-04-17 02:20:36 +04:00
{
int i , len ;
int smbcmd ;
2008-07-15 00:38:32 +04:00
int status ;
2008-07-15 00:38:33 +04:00
int result ;
2005-04-17 02:20:36 +04:00
int timeout ;
2008-07-15 00:38:33 +04:00
result = i801_check_pre ( ) ;
if ( result < 0 )
return result ;
2005-04-17 02:20:36 +04:00
2007-07-12 16:12:31 +04:00
len = data - > block [ 0 ] ;
2005-04-17 02:20:36 +04:00
if ( read_write = = I2C_SMBUS_WRITE ) {
outb_p ( len , SMBHSTDAT0 ) ;
outb_p ( data - > block [ 1 ] , SMBBLKDAT ) ;
}
for ( i = 1 ; i < = len ; i + + ) {
2008-01-27 20:14:50 +03:00
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 ;
}
2005-04-17 02:20:36 +04:00
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 ) ;
2008-07-15 00:38:32 +04:00
status = inb_p ( SMBHSTSTS ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-15 00:38:32 +04:00
while ( ( ! ( status & SMBHSTSTS_BYTE_DONE ) )
2007-07-12 16:12:31 +04:00
& & ( timeout + + < MAX_TIMEOUT ) ) ;
2005-04-17 02:20:36 +04:00
2008-07-15 00:38:33 +04:00
result = i801_check_post ( status , timeout > = MAX_TIMEOUT ) ;
if ( result < 0 )
return result ;
2005-04-17 02:20:36 +04:00
2008-01-27 20:14:50 +03:00
if ( i = = 1 & & read_write = = I2C_SMBUS_READ
& & command ! = I2C_SMBUS_I2C_BLOCK_DATA ) {
2005-04-17 02:20:36 +04:00
len = inb_p ( SMBHSTDAT0 ) ;
2008-07-15 00:38:33 +04:00
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 ) ;
2008-07-15 00:38:25 +04:00
return - EPROTO ;
2008-07-15 00:38:33 +04:00
}
2005-04-17 02:20:36 +04:00
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 ) ;
2008-07-15 00:38:33 +04:00
/* signals SMBBLKDAT ready */
outb_p ( SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR , SMBHSTSTS ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-15 00:38:33 +04:00
return 0 ;
2007-07-12 16:12:31 +04:00
}
2005-04-17 02:20:36 +04:00
2007-07-12 16:12:31 +04:00
static int i801_set_block_buffer_mode ( void )
{
outb_p ( inb_p ( SMBAUXCTL ) | SMBAUXCTL_E32B , SMBAUXCTL ) ;
if ( ( inb_p ( SMBAUXCTL ) & SMBAUXCTL_E32B ) = = 0 )
2008-07-15 00:38:25 +04:00
return - EIO ;
2007-07-12 16:12:31 +04:00
return 0 ;
}
/* Block transaction function */
static int i801_block_transaction ( union i2c_smbus_data * data , char read_write ,
int command , int hwpec )
{
int result = 0 ;
unsigned char hostc ;
if ( command = = I2C_SMBUS_I2C_BLOCK_DATA ) {
if ( read_write = = I2C_SMBUS_WRITE ) {
/* set I2C_EN bit in configuration register */
pci_read_config_byte ( I801_dev , SMBHSTCFG , & hostc ) ;
pci_write_config_byte ( I801_dev , SMBHSTCFG ,
hostc | SMBHSTCFG_I2C_EN ) ;
2008-01-27 20:14:50 +03:00
} else if ( ! ( i801_features & FEATURE_I2C_BLOCK_READ ) ) {
2007-07-12 16:12:31 +04:00
dev_err ( & I801_dev - > dev ,
2008-01-27 20:14:50 +03:00
" I2C block read is unsupported! \n " ) ;
2008-07-15 00:38:25 +04:00
return - EOPNOTSUPP ;
2007-07-12 16:12:31 +04:00
}
}
2008-01-27 20:14:50 +03:00
if ( read_write = = I2C_SMBUS_WRITE
| | command = = I2C_SMBUS_I2C_BLOCK_DATA ) {
2007-07-12 16:12:31 +04:00
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 {
2008-01-27 20:14:50 +03:00
data - > block [ 0 ] = 32 ; /* max for SMBus block reads */
2007-07-12 16:12:31 +04:00
}
2008-01-27 20:14:50 +03:00
if ( ( i801_features & FEATURE_BLOCK_BUFFER )
2008-01-27 20:14:50 +03:00
& & ! ( command = = I2C_SMBUS_I2C_BLOCK_DATA
& & read_write = = I2C_SMBUS_READ )
2008-01-27 20:14:50 +03:00
& & i801_set_block_buffer_mode ( ) = = 0 )
2007-07-12 16:12:31 +04:00
result = i801_block_transaction_by_block ( data , read_write ,
hwpec ) ;
else
result = i801_block_transaction_byte_by_byte ( data , read_write ,
2008-01-27 20:14:50 +03:00
command , hwpec ) ;
2007-07-12 16:12:31 +04:00
if ( result = = 0 & & hwpec )
2007-07-12 16:12:31 +04:00
i801_wait_hwpec ( ) ;
2005-04-17 02:20:36 +04:00
2008-01-27 20:14:50 +03:00
if ( command = = I2C_SMBUS_I2C_BLOCK_DATA
& & read_write = = I2C_SMBUS_WRITE ) {
2005-04-17 02:20:36 +04:00
/* restore saved configuration register value */
pci_write_config_byte ( I801_dev , SMBHSTCFG , hostc ) ;
}
return result ;
}
2008-07-15 00:38:25 +04:00
/* Return negative errno on error. */
2005-04-17 02:20:36 +04:00
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 )
{
2005-10-26 23:34:42 +04:00
int hwpec ;
2005-04-17 02:20:36 +04:00
int block = 0 ;
int ret , xact = 0 ;
2008-01-27 20:14:50 +03:00
hwpec = ( i801_features & FEATURE_SMBUS_PEC ) & & ( flags & I2C_CLIENT_PEC )
2005-10-26 23:34:42 +04:00
& & size ! = I2C_SMBUS_QUICK
& & size ! = I2C_SMBUS_I2C_BLOCK_DATA ;
2005-04-17 02:20:36 +04:00
switch ( size ) {
case I2C_SMBUS_QUICK :
outb_p ( ( ( addr & 0x7f ) < < 1 ) | ( read_write & 0x01 ) ,
SMBHSTADD ) ;
xact = I801_QUICK ;
break ;
case I2C_SMBUS_BYTE :
outb_p ( ( ( addr & 0x7f ) < < 1 ) | ( read_write & 0x01 ) ,
SMBHSTADD ) ;
if ( read_write = = I2C_SMBUS_WRITE )
outb_p ( command , SMBHSTCMD ) ;
xact = I801_BYTE ;
break ;
case I2C_SMBUS_BYTE_DATA :
outb_p ( ( ( addr & 0x7f ) < < 1 ) | ( read_write & 0x01 ) ,
SMBHSTADD ) ;
outb_p ( command , SMBHSTCMD ) ;
if ( read_write = = I2C_SMBUS_WRITE )
outb_p ( data - > byte , SMBHSTDAT0 ) ;
xact = I801_BYTE_DATA ;
break ;
case I2C_SMBUS_WORD_DATA :
outb_p ( ( ( addr & 0x7f ) < < 1 ) | ( read_write & 0x01 ) ,
SMBHSTADD ) ;
outb_p ( command , SMBHSTCMD ) ;
if ( read_write = = I2C_SMBUS_WRITE ) {
outb_p ( data - > word & 0xff , SMBHSTDAT0 ) ;
outb_p ( ( data - > word & 0xff00 ) > > 8 , SMBHSTDAT1 ) ;
}
xact = I801_WORD_DATA ;
break ;
case I2C_SMBUS_BLOCK_DATA :
outb_p ( ( ( addr & 0x7f ) < < 1 ) | ( read_write & 0x01 ) ,
SMBHSTADD ) ;
outb_p ( command , SMBHSTCMD ) ;
block = 1 ;
break ;
2008-01-27 20:14:50 +03:00
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 ;
2005-04-17 02:20:36 +04:00
default :
dev_err ( & I801_dev - > dev , " Unsupported transaction %d \n " , size ) ;
2008-07-15 00:38:25 +04:00
return - EOPNOTSUPP ;
2005-04-17 02:20:36 +04:00
}
2007-07-12 16:12:31 +04:00
if ( hwpec ) /* enable/disable hardware PEC */
outb_p ( inb_p ( SMBAUXCTL ) | SMBAUXCTL_CRC , SMBAUXCTL ) ;
else
outb_p ( inb_p ( SMBAUXCTL ) & ( ~ SMBAUXCTL_CRC ) , SMBAUXCTL ) ;
2005-10-26 23:34:42 +04:00
2005-04-17 02:20:36 +04:00
if ( block )
2005-10-26 23:31:15 +04:00
ret = i801_block_transaction ( data , read_write , size , hwpec ) ;
2007-07-12 16:12:31 +04:00
else
ret = i801_transaction ( xact | ENABLE_INT9 ) ;
2005-04-17 02:20:36 +04:00
2006-04-20 13:43:18 +04:00
/* Some BIOSes don't like it when PEC is enabled at reboot or resume
2007-07-12 16:12:31 +04:00
time , so we forcibly disable it after every transaction . Turn off
E32B for the same reason . */
2008-01-27 20:14:50 +03:00
if ( hwpec | | block )
2007-07-12 16:12:31 +04:00
outb_p ( inb_p ( SMBAUXCTL ) & ~ ( SMBAUXCTL_CRC | SMBAUXCTL_E32B ) ,
SMBAUXCTL ) ;
2006-04-20 13:43:18 +04:00
2005-04-17 02:20:36 +04:00
if ( block )
return ret ;
if ( ret )
2008-07-15 00:38:25 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
if ( ( read_write = = I2C_SMBUS_WRITE ) | | ( xact = = I801_QUICK ) )
return 0 ;
switch ( xact & 0x7f ) {
case I801_BYTE : /* Result put in SMBHSTDAT0 */
case I801_BYTE_DATA :
data - > byte = inb_p ( SMBHSTDAT0 ) ;
break ;
case I801_WORD_DATA :
data - > word = inb_p ( SMBHSTDAT0 ) + ( inb_p ( SMBHSTDAT1 ) < < 8 ) ;
break ;
}
return 0 ;
}
static u32 i801_func ( struct i2c_adapter * adapter )
{
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
2008-01-27 20:14:50 +03:00
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
2008-01-27 20:14:50 +03:00
( ( i801_features & FEATURE_SMBUS_PEC ) ? I2C_FUNC_SMBUS_PEC : 0 ) |
( ( i801_features & FEATURE_I2C_BLOCK_READ ) ?
I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0 ) ;
2005-04-17 02:20:36 +04:00
}
2006-09-04 00:39:46 +04:00
static const struct i2c_algorithm smbus_algorithm = {
2005-04-17 02:20:36 +04:00
. smbus_xfer = i801_access ,
. functionality = i801_func ,
} ;
static struct i2c_adapter i801_adapter = {
. owner = THIS_MODULE ,
2007-02-14 00:09:01 +03:00
. id = I2C_HW_SMBUS_I801 ,
2008-07-15 00:38:29 +04:00
. class = I2C_CLASS_HWMON | I2C_CLASS_SPD ,
2005-04-17 02:20:36 +04:00
. algo = & smbus_algorithm ,
} ;
static struct pci_device_id i801_ids [ ] = {
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_82801AA_3 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_82801AB_3 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_82801BA_2 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_82801CA_3 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_82801DB_3 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_82801EB_3 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_ESB_4 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_ICH6_16 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_ICH7_17 ) } ,
2005-04-17 02:24:45 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_ESB2_17 ) } ,
2006-01-09 21:58:08 +03:00
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_ICH8_5 ) } ,
2006-11-23 02:19:12 +03:00
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_ICH9_6 ) } ,
2007-10-14 01:56:31 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_TOLAPAI_1 ) } ,
2008-02-24 22:03:42 +03:00
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_ICH10_4 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_ICH10_5 ) } ,
2005-04-17 02:20:36 +04:00
{ 0 , }
} ;
MODULE_DEVICE_TABLE ( pci , i801_ids ) ;
static int __devinit i801_probe ( struct pci_dev * dev , const struct pci_device_id * id )
{
2006-06-12 23:53:41 +04:00
unsigned char temp ;
2006-06-12 23:52:02 +04:00
int err ;
2005-04-17 02:20:36 +04:00
2006-06-12 23:53:41 +04:00
I801_dev = dev ;
2008-01-27 20:14:50 +03:00
i801_features = 0 ;
2006-12-10 23:21:33 +03:00
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 :
2008-02-24 22:03:42 +03:00
case PCI_DEVICE_ID_INTEL_TOLAPAI_1 :
case PCI_DEVICE_ID_INTEL_ICH10_4 :
case PCI_DEVICE_ID_INTEL_ICH10_5 :
2008-01-27 20:14:50 +03:00
i801_features | = FEATURE_I2C_BLOCK_READ ;
/* fall through */
case PCI_DEVICE_ID_INTEL_82801DB_3 :
2008-01-27 20:14:50 +03:00
i801_features | = FEATURE_SMBUS_PEC ;
i801_features | = FEATURE_BLOCK_BUFFER ;
2006-12-10 23:21:33 +03:00
break ;
}
2006-06-12 23:53:41 +04:00
err = pci_enable_device ( dev ) ;
if ( err ) {
dev_err ( & dev - > dev , " Failed to enable SMBus PCI device (%d) \n " ,
err ) ;
goto exit ;
}
/* Determine the address of the SMBus area */
i801_smba = pci_resource_start ( dev , SMBBAR ) ;
if ( ! i801_smba ) {
dev_err ( & dev - > dev , " SMBus base address uninitialized, "
" upgrade BIOS \n " ) ;
err = - ENODEV ;
2006-06-27 20:40:54 +04:00
goto exit ;
2006-06-12 23:53:41 +04:00
}
2008-07-15 00:38:33 +04:00
err = acpi_check_resource_conflict ( & dev - > resource [ SMBBAR ] ) ;
if ( err )
goto exit ;
2006-06-12 23:53:41 +04:00
err = pci_request_region ( dev , SMBBAR , i801_driver . name ) ;
if ( err ) {
dev_err ( & dev - > dev , " Failed to request SMBus region "
2006-06-30 12:56:20 +04:00
" 0x%lx-0x%Lx \n " , i801_smba ,
( unsigned long long ) pci_resource_end ( dev , SMBBAR ) ) ;
2006-06-27 20:40:54 +04:00
goto exit ;
2006-06-12 23:53:41 +04:00
}
pci_read_config_byte ( I801_dev , SMBHSTCFG , & temp ) ;
2007-03-22 21:49:01 +03:00
i801_original_hstcfg = temp ;
2006-06-12 23:53:41 +04:00
temp & = ~ SMBHSTCFG_I2C_EN ; /* SMBus timing */
if ( ! ( temp & SMBHSTCFG_HST_EN ) ) {
dev_info ( & dev - > dev , " Enabling SMBus device \n " ) ;
temp | = SMBHSTCFG_HST_EN ;
}
pci_write_config_byte ( I801_dev , SMBHSTCFG , temp ) ;
if ( temp & SMBHSTCFG_SMB_SMI_EN )
dev_dbg ( & dev - > dev , " SMBus using interrupt SMI# \n " ) ;
else
dev_dbg ( & dev - > dev , " SMBus using PCI Interrupt \n " ) ;
2005-04-17 02:20:36 +04:00
2008-01-27 20:14:50 +03:00
/* Clear special mode bits */
if ( i801_features & ( FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER ) )
outb_p ( inb_p ( SMBAUXCTL ) & ~ ( SMBAUXCTL_CRC | SMBAUXCTL_E32B ) ,
SMBAUXCTL ) ;
2007-02-17 21:13:42 +03:00
/* set up the sysfs linkage to our parent device */
2005-04-17 02:20:36 +04:00
i801_adapter . dev . parent = & dev - > dev ;
2007-05-02 01:26:28 +04:00
snprintf ( i801_adapter . name , sizeof ( i801_adapter . name ) ,
2006-06-12 23:53:02 +04:00
" SMBus I801 adapter at %04lx " , i801_smba ) ;
2006-06-12 23:53:41 +04:00
err = i2c_add_adapter ( & i801_adapter ) ;
if ( err ) {
dev_err ( & dev - > dev , " Failed to add SMBus adapter \n " ) ;
2006-06-27 20:40:54 +04:00
goto exit_release ;
2006-06-12 23:53:41 +04:00
}
2006-06-27 20:40:54 +04:00
return 0 ;
2006-06-12 23:53:41 +04:00
2006-06-27 20:40:54 +04:00
exit_release :
pci_release_region ( dev , SMBBAR ) ;
2006-06-12 23:53:41 +04:00
exit :
return err ;
2005-04-17 02:20:36 +04:00
}
static void __devexit i801_remove ( struct pci_dev * dev )
{
i2c_del_adapter ( & i801_adapter ) ;
2007-03-22 21:49:01 +03:00
pci_write_config_byte ( I801_dev , SMBHSTCFG , i801_original_hstcfg ) ;
2006-06-12 23:53:02 +04:00
pci_release_region ( dev , SMBBAR ) ;
2006-06-27 20:40:54 +04:00
/*
* do not call pci_disable_device ( dev ) since it can cause hard hangs on
* some systems during power - off ( eg . Fujitsu - Siemens Lifebook E8010 )
*/
2005-04-17 02:20:36 +04:00
}
2007-03-22 21:49:01 +03:00
# 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
2005-04-17 02:20:36 +04:00
static struct pci_driver i801_driver = {
. name = " i801_smbus " ,
. id_table = i801_ids ,
. probe = i801_probe ,
. remove = __devexit_p ( i801_remove ) ,
2007-03-22 21:49:01 +03:00
. suspend = i801_suspend ,
. resume = i801_resume ,
2005-04-17 02:20:36 +04:00
} ;
static int __init i2c_i801_init ( void )
{
return pci_register_driver ( & i801_driver ) ;
}
static void __exit i2c_i801_exit ( void )
{
pci_unregister_driver ( & i801_driver ) ;
}
2008-01-27 20:14:50 +03:00
MODULE_AUTHOR ( " Mark D. Studebaker <mdsxyz123@yahoo.com>, "
" Jean Delvare <khali@linux-fr.org> " ) ;
2005-04-17 02:20:36 +04:00
MODULE_DESCRIPTION ( " I801 SMBus driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
module_init ( i2c_i801_init ) ;
module_exit ( i2c_i801_exit ) ;