2019-05-27 09:55:06 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2005-04-17 02:20:36 +04:00
/*
2005-09-22 23:50:47 +04:00
Copyright ( c ) 1998 - 2002 Frodo Looijaard < frodol @ dds . nl > ,
2007-10-20 01:21:04 +04:00
Philip Edelbrock < phil @ netroedge . com > , Kyösti Mälkki < kmalkki @ cc . hut . fi > ,
2005-04-17 02:20:36 +04:00
Mark D . Studebaker < mdsxyz123 @ yahoo . com >
2014-01-29 23:40:08 +04:00
Copyright ( C ) 2005 - 2008 Jean Delvare < jdelvare @ suse . de >
2005-04-17 02:20:36 +04:00
*/
/*
2005-09-23 00:09:07 +04:00
Supports the following VIA south bridges :
Chip name PCI ID REV I2C block
VT82C596A 0x3050 no
VT82C596B 0x3051 no
VT82C686A 0x3057 0x30 no
VT82C686B 0x3057 0x40 yes
VT8231 0x8235 no ?
VT8233 0x3074 yes
VT8233A 0x3147 yes ?
VT8235 0x3177 yes
VT8237R 0x3227 yes
2006-09-04 00:35:21 +04:00
VT8237A 0x3337 yes
2008-01-27 20:14:51 +03:00
VT8237S 0x3372 yes
2006-09-04 00:35:21 +04:00
VT8251 0x3287 yes
2007-02-14 00:09:02 +03:00
CX700 0x8324 yes
2008-10-14 19:30:03 +04:00
VX800 / VX820 0x8353 yes
2009-06-15 20:01:49 +04:00
VX855 / VX875 0x8409 yes
2005-09-23 00:09:07 +04:00
2005-04-17 02:20:36 +04:00
Note : we assume there can only be one device , with one SMBus interface .
*/
# include <linux/module.h>
# include <linux/delay.h>
# include <linux/pci.h>
# include <linux/kernel.h>
# include <linux/stddef.h>
# include <linux/ioport.h>
# include <linux/i2c.h>
# include <linux/init.h>
2008-07-15 00:38:33 +04:00
# include <linux/acpi.h>
2010-05-21 20:41:01 +04:00
# include <linux/io.h>
2005-04-17 02:20:36 +04:00
static struct pci_dev * vt596_pdev ;
2005-09-22 23:50:47 +04:00
# define SMBBA1 0x90
# define SMBBA2 0x80
# define SMBBA3 0xD0
2005-04-17 02:20:36 +04:00
/* SMBus address offsets */
static unsigned short vt596_smba ;
# define SMBHSTSTS (vt596_smba + 0)
# define SMBHSTCNT (vt596_smba + 2)
# define SMBHSTCMD (vt596_smba + 3)
# define SMBHSTADD (vt596_smba + 4)
# define SMBHSTDAT0 (vt596_smba + 5)
# define SMBHSTDAT1 (vt596_smba + 6)
# define SMBBLKDAT (vt596_smba + 7)
/* PCI Address Constants */
/* SMBus data in configuration space can be found in two places,
2005-09-22 23:50:47 +04:00
We try to select the better one */
2005-04-17 02:20:36 +04:00
2005-09-23 00:01:07 +04:00
static unsigned short SMBHSTCFG = 0xD2 ;
2005-04-17 02:20:36 +04:00
/* Other settings */
# define MAX_TIMEOUT 500
/* VT82C596 constants */
2005-09-22 23:50:47 +04:00
# define VT596_QUICK 0x00
# define VT596_BYTE 0x04
# define VT596_BYTE_DATA 0x08
# define VT596_WORD_DATA 0x0C
2008-10-14 19:30:06 +04:00
# define VT596_PROC_CALL 0x10
2005-09-22 23:50:47 +04:00
# define VT596_BLOCK_DATA 0x14
2005-09-22 23:58:41 +04:00
# define VT596_I2C_BLOCK_DATA 0x34
2005-04-17 02:20:36 +04:00
/* If force is set to anything different from 0, we forcibly enable the
VT596 . DANGEROUS ! */
2012-01-13 03:02:20 +04:00
static bool force ;
2005-04-17 02:20:36 +04:00
module_param ( force , bool , 0 ) ;
MODULE_PARM_DESC ( force , " Forcibly enable the SMBus. DANGEROUS! " ) ;
/* If force_addr is set to anything different from 0, we forcibly enable
the VT596 at the given address . VERY DANGEROUS ! */
static u16 force_addr ;
2017-04-04 18:54:23 +03:00
module_param_hw ( force_addr , ushort , ioport , 0 ) ;
2005-04-17 02:20:36 +04:00
MODULE_PARM_DESC ( force_addr ,
" Forcibly enable the SMBus at the given address. "
" EXTREMELY DANGEROUS! " ) ;
2005-09-23 00:01:07 +04:00
static struct pci_driver vt596_driver ;
2005-04-17 02:20:36 +04:00
static struct i2c_adapter vt596_adapter ;
2005-09-22 23:58:41 +04:00
# define FEATURE_I2CBLOCK (1<<0)
static unsigned int vt596_features ;
2005-09-23 00:23:32 +04:00
# ifdef DEBUG
static void vt596_dump_regs ( const char * msg , u8 size )
{
dev_dbg ( & vt596_adapter . dev , " %s: STS=%02x CNT=%02x CMD=%02x ADD=%02x "
" DAT=%02x,%02x \n " , msg , inb_p ( SMBHSTSTS ) , inb_p ( SMBHSTCNT ) ,
inb_p ( SMBHSTCMD ) , inb_p ( SMBHSTADD ) , inb_p ( SMBHSTDAT0 ) ,
inb_p ( SMBHSTDAT1 ) ) ;
if ( size = = VT596_BLOCK_DATA
| | size = = VT596_I2C_BLOCK_DATA ) {
int i ;
dev_dbg ( & vt596_adapter . dev , " BLK= " ) ;
for ( i = 0 ; i < I2C_SMBUS_BLOCK_MAX / 2 ; i + + )
printk ( " %02x, " , inb_p ( SMBBLKDAT ) ) ;
printk ( " \n " ) ;
dev_dbg ( & vt596_adapter . dev , " " ) ;
for ( ; i < I2C_SMBUS_BLOCK_MAX - 1 ; i + + )
printk ( " %02x, " , inb_p ( SMBBLKDAT ) ) ;
printk ( " %02x \n " , inb_p ( SMBBLKDAT ) ) ;
}
}
2005-09-23 00:23:32 +04:00
# else
static inline void vt596_dump_regs ( const char * msg , u8 size ) { }
2005-09-23 00:23:32 +04:00
# endif
2005-09-23 00:01:07 +04:00
/* Return -1 on error, 0 on success */
2005-09-23 00:15:53 +04:00
static int vt596_transaction ( u8 size )
2005-04-17 02:20:36 +04:00
{
int temp ;
int result = 0 ;
int timeout = 0 ;
2005-09-23 00:23:32 +04:00
vt596_dump_regs ( " Transaction (pre) " , size ) ;
2005-04-17 02:20:36 +04:00
/* Make sure the SMBus host is ready to start transmitting */
if ( ( temp = inb_p ( SMBHSTSTS ) ) & 0x1F ) {
dev_dbg ( & vt596_adapter . dev , " SMBus busy (0x%02x). "
2005-10-31 20:51:21 +03:00
" Resetting... \n " , temp ) ;
2005-09-22 23:50:47 +04:00
2005-04-17 02:20:36 +04:00
outb_p ( temp , SMBHSTSTS ) ;
if ( ( temp = inb_p ( SMBHSTSTS ) ) & 0x1F ) {
2005-10-31 20:51:21 +03:00
dev_err ( & vt596_adapter . dev , " SMBus reset failed! "
" (0x%02x) \n " , temp ) ;
2008-07-15 00:38:25 +04:00
return - EBUSY ;
2005-04-17 02:20:36 +04:00
}
}
2005-09-23 00:01:07 +04:00
/* Start the transaction by setting bit 6 */
2005-10-31 20:51:21 +03:00
outb_p ( 0x40 | size , SMBHSTCNT ) ;
2005-04-17 02:20:36 +04:00
2005-09-23 00:01:07 +04:00
/* We will always wait for a fraction of a second */
2005-04-17 02:20:36 +04:00
do {
msleep ( 1 ) ;
temp = inb_p ( SMBHSTSTS ) ;
2010-01-16 22:43:12 +03:00
} while ( ( temp & 0x01 ) & & ( + + timeout < MAX_TIMEOUT ) ) ;
2005-04-17 02:20:36 +04:00
/* If the SMBus is still busy, we give up */
2010-01-16 22:43:12 +03:00
if ( timeout = = MAX_TIMEOUT ) {
2008-07-15 00:38:25 +04:00
result = - ETIMEDOUT ;
2005-09-23 00:01:07 +04:00
dev_err ( & vt596_adapter . dev , " SMBus timeout! \n " ) ;
2005-04-17 02:20:36 +04:00
}
if ( temp & 0x10 ) {
2008-07-15 00:38:25 +04:00
result = - EIO ;
2005-09-23 00:01:07 +04:00
dev_err ( & vt596_adapter . dev , " Transaction failed (0x%02x) \n " ,
2005-10-31 20:51:21 +03:00
size ) ;
2005-04-17 02:20:36 +04:00
}
if ( temp & 0x08 ) {
2008-07-15 00:38:25 +04:00
result = - EIO ;
2005-09-23 00:01:07 +04:00
dev_err ( & vt596_adapter . dev , " SMBus collision! \n " ) ;
2005-04-17 02:20:36 +04:00
}
if ( temp & 0x04 ) {
2008-07-15 00:38:25 +04:00
result = - ENXIO ;
2010-10-24 20:16:59 +04:00
dev_dbg ( & vt596_adapter . dev , " No response \n " ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-23 00:01:07 +04:00
/* Resetting status register */
if ( temp & 0x1F )
2005-04-17 02:20:36 +04:00
outb_p ( temp , SMBHSTSTS ) ;
2005-09-23 00:23:32 +04:00
vt596_dump_regs ( " Transaction (post) " , size ) ;
2005-09-22 23:50:47 +04:00
2005-04-17 02:20:36 +04:00
return result ;
}
2008-07-15 00:38:25 +04:00
/* Return negative errno on error, 0 on success */
2005-04-17 02:20:36 +04:00
static s32 vt596_access ( struct i2c_adapter * adap , u16 addr ,
2005-09-22 23:50:47 +04:00
unsigned short flags , char read_write , u8 command ,
int size , union i2c_smbus_data * data )
2005-04-17 02:20:36 +04:00
{
2005-09-23 00:01:07 +04:00
int i ;
2008-07-15 00:38:25 +04:00
int status ;
2005-04-17 02:20:36 +04:00
switch ( size ) {
case I2C_SMBUS_QUICK :
size = VT596_QUICK ;
break ;
case I2C_SMBUS_BYTE :
if ( read_write = = I2C_SMBUS_WRITE )
outb_p ( command , SMBHSTCMD ) ;
size = VT596_BYTE ;
break ;
case I2C_SMBUS_BYTE_DATA :
outb_p ( command , SMBHSTCMD ) ;
if ( read_write = = I2C_SMBUS_WRITE )
outb_p ( data - > byte , SMBHSTDAT0 ) ;
size = VT596_BYTE_DATA ;
break ;
case I2C_SMBUS_WORD_DATA :
outb_p ( command , SMBHSTCMD ) ;
if ( read_write = = I2C_SMBUS_WRITE ) {
outb_p ( data - > word & 0xff , SMBHSTDAT0 ) ;
outb_p ( ( data - > word & 0xff00 ) > > 8 , SMBHSTDAT1 ) ;
}
size = VT596_WORD_DATA ;
break ;
2008-10-14 19:30:06 +04:00
case I2C_SMBUS_PROC_CALL :
outb_p ( command , SMBHSTCMD ) ;
outb_p ( data - > word & 0xff , SMBHSTDAT0 ) ;
outb_p ( ( data - > word & 0xff00 ) > > 8 , SMBHSTDAT1 ) ;
size = VT596_PROC_CALL ;
break ;
2005-09-22 23:58:41 +04:00
case I2C_SMBUS_I2C_BLOCK_DATA :
if ( ! ( vt596_features & FEATURE_I2CBLOCK ) )
2005-09-23 00:01:07 +04:00
goto exit_unsupported ;
2005-09-22 23:58:41 +04:00
if ( read_write = = I2C_SMBUS_READ )
i2c: Fix the i2c_smbus_read_i2c_block_data() prototype
Let the drivers specify how many bytes they want to read with
i2c_smbus_read_i2c_block_data(). So far, the block count was
hard-coded to I2C_SMBUS_BLOCK_MAX (32), which did not make much sense.
Many driver authors complained about this before, and I believe it's
about time to fix it. Right now, authors have to do technically stupid
things, such as individual byte reads or full-fledged I2C messaging,
to work around the problem. We do not want to encourage that.
I even found that some bus drivers (e.g. i2c-amd8111) already
implemented I2C block read the "right" way, that is, they didn't
follow the old, broken standard. The fact that it was never noticed
before just shows how little i2c_smbus_read_i2c_block_data() was used,
which isn't that surprising given how broken its prototype was so far.
There are some obvious compatiblity considerations:
* This changes the i2c_smbus_read_i2c_block_data() prototype. Users
outside the kernel tree will notice at compilation time, and will
have to update their code.
* User-space has access to i2c_smbus_xfer() directly using i2c-dev, so
the changed expectations would affect tools such as i2cdump. In order
to preserve binary compatibility, we give I2C_SMBUS_I2C_BLOCK_DATA
a new numeric value, and define I2C_SMBUS_I2C_BLOCK_BROKEN with the
old numeric value. When i2c-dev receives a transaction with the
old value, it can convert it to the new format on the fly.
Signed-off-by: Jean Delvare <khali@linux-fr.org>
2007-07-12 16:12:29 +04:00
outb_p ( data - > block [ 0 ] , SMBHSTDAT0 ) ;
2005-09-22 23:58:41 +04:00
/* Fall through */
2005-04-17 02:20:36 +04:00
case I2C_SMBUS_BLOCK_DATA :
outb_p ( command , SMBHSTCMD ) ;
if ( read_write = = I2C_SMBUS_WRITE ) {
2005-09-23 00:01:07 +04:00
u8 len = data - > block [ 0 ] ;
2005-04-17 02:20:36 +04:00
if ( len > I2C_SMBUS_BLOCK_MAX )
len = I2C_SMBUS_BLOCK_MAX ;
outb_p ( len , SMBHSTDAT0 ) ;
2005-09-23 00:01:07 +04:00
inb_p ( SMBHSTCNT ) ; /* Reset SMBBLKDAT */
2005-04-17 02:20:36 +04:00
for ( i = 1 ; i < = len ; i + + )
outb_p ( data - > block [ i ] , SMBBLKDAT ) ;
}
2005-09-22 23:58:41 +04:00
size = ( size = = I2C_SMBUS_I2C_BLOCK_DATA ) ?
VT596_I2C_BLOCK_DATA : VT596_BLOCK_DATA ;
2005-04-17 02:20:36 +04:00
break ;
2005-09-23 00:01:07 +04:00
default :
goto exit_unsupported ;
2005-04-17 02:20:36 +04:00
}
2005-09-23 00:01:07 +04:00
outb_p ( ( ( addr & 0x7f ) < < 1 ) | read_write , SMBHSTADD ) ;
2005-04-17 02:20:36 +04:00
2008-07-15 00:38:25 +04:00
status = vt596_transaction ( size ) ;
if ( status )
return status ;
2005-04-17 02:20:36 +04:00
2008-10-14 19:30:06 +04:00
if ( size = = VT596_PROC_CALL )
read_write = I2C_SMBUS_READ ;
2005-04-17 02:20:36 +04:00
if ( ( read_write = = I2C_SMBUS_WRITE ) | | ( size = = VT596_QUICK ) )
return 0 ;
switch ( size ) {
case VT596_BYTE :
case VT596_BYTE_DATA :
data - > byte = inb_p ( SMBHSTDAT0 ) ;
break ;
case VT596_WORD_DATA :
2008-10-14 19:30:06 +04:00
case VT596_PROC_CALL :
2005-04-17 02:20:36 +04:00
data - > word = inb_p ( SMBHSTDAT0 ) + ( inb_p ( SMBHSTDAT1 ) < < 8 ) ;
break ;
2005-09-22 23:58:41 +04:00
case VT596_I2C_BLOCK_DATA :
2005-04-17 02:20:36 +04:00
case VT596_BLOCK_DATA :
data - > block [ 0 ] = inb_p ( SMBHSTDAT0 ) ;
if ( data - > block [ 0 ] > I2C_SMBUS_BLOCK_MAX )
data - > block [ 0 ] = I2C_SMBUS_BLOCK_MAX ;
2005-09-23 00:01:07 +04:00
inb_p ( SMBHSTCNT ) ; /* Reset SMBBLKDAT */
2005-04-17 02:20:36 +04:00
for ( i = 1 ; i < = data - > block [ 0 ] ; i + + )
data - > block [ i ] = inb_p ( SMBBLKDAT ) ;
break ;
}
return 0 ;
2005-09-23 00:01:07 +04:00
exit_unsupported :
2008-07-15 00:38:25 +04:00
dev_warn ( & vt596_adapter . dev , " Unsupported transaction %d \n " ,
2005-09-23 00:01:07 +04:00
size ) ;
2008-07-15 00:38:25 +04:00
return - EOPNOTSUPP ;
2005-04-17 02:20:36 +04:00
}
static u32 vt596_func ( struct i2c_adapter * adapter )
{
2005-09-22 23:58:41 +04:00
u32 func = I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
2005-04-17 02:20:36 +04:00
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
2008-10-14 19:30:06 +04:00
I2C_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_DATA ;
2005-09-22 23:58:41 +04:00
if ( vt596_features & FEATURE_I2CBLOCK )
func | = I2C_FUNC_SMBUS_I2C_BLOCK ;
return func ;
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 = vt596_access ,
. functionality = vt596_func ,
} ;
static struct i2c_adapter vt596_adapter = {
. owner = THIS_MODULE ,
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 ,
} ;
2012-11-28 00:59:38 +04:00
static int vt596_probe ( struct pci_dev * pdev ,
const struct pci_device_id * id )
2005-04-17 02:20:36 +04:00
{
unsigned char temp ;
2012-01-12 23:32:03 +04:00
int error ;
2005-09-22 23:50:47 +04:00
2005-04-17 02:20:36 +04:00
/* Determine the address of the SMBus areas */
if ( force_addr ) {
vt596_smba = force_addr & 0xfff0 ;
force = 0 ;
goto found ;
}
if ( ( pci_read_config_word ( pdev , id - > driver_data , & vt596_smba ) ) | |
2005-09-23 00:01:07 +04:00
! ( vt596_smba & 0x0001 ) ) {
2005-04-17 02:20:36 +04:00
/* try 2nd address and config reg. for 596 */
if ( id - > device = = PCI_DEVICE_ID_VIA_82C596_3 & &
! pci_read_config_word ( pdev , SMBBA2 , & vt596_smba ) & &
2005-09-23 00:01:07 +04:00
( vt596_smba & 0x0001 ) ) {
SMBHSTCFG = 0x84 ;
2005-04-17 02:20:36 +04:00
} else {
/* no matches at all */
dev_err ( & pdev - > dev , " Cannot configure "
" SMBus I/O Base address \n " ) ;
return - ENODEV ;
}
}
vt596_smba & = 0xfff0 ;
if ( vt596_smba = = 0 ) {
dev_err ( & pdev - > dev , " SMBus base address "
" uninitialized - upgrade BIOS or use "
" force_addr=0xaddr \n " ) ;
return - ENODEV ;
}
2005-09-22 23:50:47 +04:00
found :
2008-07-15 00:38:33 +04:00
error = acpi_check_region ( vt596_smba , 8 , vt596_driver . name ) ;
if ( error )
2009-10-05 00:53:45 +04:00
return - ENODEV ;
2008-07-15 00:38:33 +04:00
2005-09-23 00:01:07 +04:00
if ( ! request_region ( vt596_smba , 8 , vt596_driver . name ) ) {
2005-04-17 02:20:36 +04:00
dev_err ( & pdev - > dev , " SMBus region 0x%x already in use! \n " ,
2005-09-22 23:50:47 +04:00
vt596_smba ) ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
}
pci_read_config_byte ( pdev , SMBHSTCFG , & temp ) ;
/* If force_addr is set, we program the new address here. Just to make
sure , we disable the VT596 first . */
if ( force_addr ) {
pci_write_config_byte ( pdev , SMBHSTCFG , temp & 0xfe ) ;
pci_write_config_word ( pdev , id - > driver_data , vt596_smba ) ;
pci_write_config_byte ( pdev , SMBHSTCFG , temp | 0x01 ) ;
dev_warn ( & pdev - > dev , " WARNING: SMBus interface set to new "
2005-09-22 23:50:47 +04:00
" address 0x%04x! \n " , vt596_smba ) ;
2005-09-23 00:01:07 +04:00
} else if ( ! ( temp & 0x01 ) ) {
2005-04-17 02:20:36 +04:00
if ( force ) {
2005-09-22 23:50:47 +04:00
/* NOTE: This assumes I/O space and other allocations
* WERE done by the Bios ! Don ' t complain if your
* hardware does weird things after enabling this .
* : ' ) Check for Bios updates before resorting to
2005-04-17 02:20:36 +04:00
* this .
*/
2005-09-23 00:01:07 +04:00
pci_write_config_byte ( pdev , SMBHSTCFG , temp | 0x01 ) ;
2005-04-17 02:20:36 +04:00
dev_info ( & pdev - > dev , " Enabling SMBus device \n " ) ;
} else {
dev_err ( & pdev - > dev , " SMBUS: Error: Host SMBus "
" controller not enabled! - upgrade BIOS or "
" use force=1 \n " ) ;
2012-01-12 23:32:03 +04:00
error = - ENODEV ;
2005-04-17 02:20:36 +04:00
goto release_region ;
}
}
dev_dbg ( & pdev - > dev , " VT596_smba = 0x%X \n " , vt596_smba ) ;
2005-09-22 23:58:41 +04:00
switch ( pdev - > device ) {
2007-02-14 00:09:02 +03:00
case PCI_DEVICE_ID_VIA_CX700 :
2008-10-14 19:30:03 +04:00
case PCI_DEVICE_ID_VIA_VX800 :
2009-06-15 20:01:49 +04:00
case PCI_DEVICE_ID_VIA_VX855 :
2012-10-06 00:23:53 +04:00
case PCI_DEVICE_ID_VIA_VX900 :
2006-09-04 00:35:21 +04:00
case PCI_DEVICE_ID_VIA_8251 :
2005-09-22 23:58:41 +04:00
case PCI_DEVICE_ID_VIA_8237 :
2006-09-04 00:35:21 +04:00
case PCI_DEVICE_ID_VIA_8237A :
2008-01-27 20:14:51 +03:00
case PCI_DEVICE_ID_VIA_8237S :
2005-09-22 23:58:41 +04:00
case PCI_DEVICE_ID_VIA_8235 :
case PCI_DEVICE_ID_VIA_8233A :
case PCI_DEVICE_ID_VIA_8233_0 :
vt596_features | = FEATURE_I2CBLOCK ;
break ;
case PCI_DEVICE_ID_VIA_82C686_4 :
/* The VT82C686B (rev 0x40) does support I2C block
transactions , but the VT82C686A ( rev 0x30 ) doesn ' t */
2007-06-09 02:46:36 +04:00
if ( pdev - > revision > = 0x40 )
2005-09-22 23:58:41 +04:00
vt596_features | = FEATURE_I2CBLOCK ;
break ;
}
2005-04-17 02:20:36 +04:00
vt596_adapter . dev . parent = & pdev - > dev ;
2007-05-02 01:26:28 +04:00
snprintf ( vt596_adapter . name , sizeof ( vt596_adapter . name ) ,
2005-09-22 23:50:47 +04:00
" SMBus Via Pro adapter at %04x " , vt596_smba ) ;
2005-04-17 02:20:36 +04:00
vt596_pdev = pci_dev_get ( pdev ) ;
2012-01-12 23:32:03 +04:00
error = i2c_add_adapter ( & vt596_adapter ) ;
if ( error ) {
2005-04-17 02:20:36 +04:00
pci_dev_put ( vt596_pdev ) ;
vt596_pdev = NULL ;
2012-01-12 23:32:03 +04:00
goto release_region ;
2005-04-17 02:20:36 +04:00
}
/* Always return failure here. This is to allow other drivers to bind
* to this pci device . We don ' t really want to have control over the
* pci device , we only wanted to read as few register values from it .
*/
return - ENODEV ;
2005-09-22 23:50:47 +04:00
release_region :
2005-04-17 02:20:36 +04:00
release_region ( vt596_smba , 8 ) ;
return error ;
}
2013-12-03 03:11:20 +04:00
static const struct pci_device_id vt596_ids [ ] = {
2005-04-17 02:20:36 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_VIA , PCI_DEVICE_ID_VIA_82C596_3 ) ,
. driver_data = SMBBA1 } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_VIA , PCI_DEVICE_ID_VIA_82C596B_3 ) ,
. driver_data = SMBBA1 } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_VIA , PCI_DEVICE_ID_VIA_82C686_4 ) ,
. driver_data = SMBBA1 } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_VIA , PCI_DEVICE_ID_VIA_8233_0 ) ,
. driver_data = SMBBA3 } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_VIA , PCI_DEVICE_ID_VIA_8233A ) ,
. driver_data = SMBBA3 } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_VIA , PCI_DEVICE_ID_VIA_8235 ) ,
. driver_data = SMBBA3 } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_VIA , PCI_DEVICE_ID_VIA_8237 ) ,
. driver_data = SMBBA3 } ,
2006-09-04 00:35:21 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_VIA , PCI_DEVICE_ID_VIA_8237A ) ,
. driver_data = SMBBA3 } ,
2008-01-27 20:14:51 +03:00
{ PCI_DEVICE ( PCI_VENDOR_ID_VIA , PCI_DEVICE_ID_VIA_8237S ) ,
. driver_data = SMBBA3 } ,
2005-04-17 02:20:36 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_VIA , PCI_DEVICE_ID_VIA_8231_4 ) ,
. driver_data = SMBBA1 } ,
2006-09-04 00:35:21 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_VIA , PCI_DEVICE_ID_VIA_8251 ) ,
. driver_data = SMBBA3 } ,
2007-02-14 00:09:02 +03:00
{ PCI_DEVICE ( PCI_VENDOR_ID_VIA , PCI_DEVICE_ID_VIA_CX700 ) ,
. driver_data = SMBBA3 } ,
2008-10-14 19:30:03 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_VIA , PCI_DEVICE_ID_VIA_VX800 ) ,
. driver_data = SMBBA3 } ,
2009-06-15 20:01:49 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_VIA , PCI_DEVICE_ID_VIA_VX855 ) ,
. driver_data = SMBBA3 } ,
2012-10-06 00:23:53 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_VIA , PCI_DEVICE_ID_VIA_VX900 ) ,
. driver_data = SMBBA3 } ,
2005-04-17 02:20:36 +04:00
{ 0 , }
} ;
2005-09-22 23:50:47 +04:00
MODULE_DEVICE_TABLE ( pci , vt596_ids ) ;
2005-04-17 02:20:36 +04:00
static struct pci_driver vt596_driver = {
. name = " vt596_smbus " ,
. id_table = vt596_ids ,
. probe = vt596_probe ,
} ;
static int __init i2c_vt596_init ( void )
{
return pci_register_driver ( & vt596_driver ) ;
}
static void __exit i2c_vt596_exit ( void )
{
pci_unregister_driver ( & vt596_driver ) ;
if ( vt596_pdev ! = NULL ) {
i2c_del_adapter ( & vt596_adapter ) ;
release_region ( vt596_smba , 8 ) ;
pci_dev_put ( vt596_pdev ) ;
vt596_pdev = NULL ;
}
}
2020-06-11 14:05:34 +03:00
MODULE_AUTHOR ( " Kyosti Malkki <kmalkki@cc.hut.fi> " ) ;
MODULE_AUTHOR ( " Mark D. Studebaker <mdsxyz123@yahoo.com> " ) ;
MODULE_AUTHOR ( " Jean Delvare <jdelvare@suse.de> " ) ;
2005-04-17 02:20:36 +04:00
MODULE_DESCRIPTION ( " vt82c596 SMBus driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
module_init ( i2c_vt596_init ) ;
module_exit ( i2c_vt596_exit ) ;