2005-04-17 02:20:36 +04:00
/*
i2c Support for Via Technologies 82 C586B South Bridge
2007-10-20 01:21:04 +04:00
Copyright ( c ) 1998 , 1999 Kyösti Mälkki < kmalkki @ cc . hut . fi >
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 .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/pci.h>
# include <linux/ioport.h>
# include <linux/i2c.h>
# include <linux/i2c-algo-bit.h>
2010-05-21 20:41:01 +04:00
# include <linux/io.h>
2005-04-17 02:20:36 +04:00
/* Power management registers */
# define PM_CFG_REVID 0x08 /* silicon revision code */
# define PM_CFG_IOBASE0 0x20
# define PM_CFG_IOBASE1 0x48
# define I2C_DIR (pm_io_base+0x40)
# define I2C_OUT (pm_io_base+0x42)
# define I2C_IN (pm_io_base+0x44)
# define I2C_SCL 0x02 /* clock bit in DIR/OUT/IN register */
# define I2C_SDA 0x04
/* io-region reservation */
# define IOSPACE 0x06
2005-09-25 18:37:04 +04:00
static struct pci_driver vt586b_driver ;
2005-09-25 18:23:07 +04:00
static u16 pm_io_base ;
2005-04-17 02:20:36 +04:00
/*
It does not appear from the datasheet that the GPIO pins are
open drain . So a we set a low value by setting the direction to
output and a high value by setting the direction to input and
relying on the required I2C pullup . The data value is initialized
to 0 in via_init ( ) and never changed .
*/
static void bit_via_setscl ( void * data , int state )
{
outb ( state ? inb ( I2C_DIR ) & ~ I2C_SCL : inb ( I2C_DIR ) | I2C_SCL , I2C_DIR ) ;
}
static void bit_via_setsda ( void * data , int state )
{
outb ( state ? inb ( I2C_DIR ) & ~ I2C_SDA : inb ( I2C_DIR ) | I2C_SDA , I2C_DIR ) ;
}
static int bit_via_getscl ( void * data )
{
return ( 0 ! = ( inb ( I2C_IN ) & I2C_SCL ) ) ;
}
static int bit_via_getsda ( void * data )
{
return ( 0 ! = ( inb ( I2C_IN ) & I2C_SDA ) ) ;
}
static struct i2c_algo_bit_data bit_data = {
. setsda = bit_via_setsda ,
. setscl = bit_via_setscl ,
. getsda = bit_via_getsda ,
. getscl = bit_via_getscl ,
. udelay = 5 ,
. timeout = HZ
} ;
static struct i2c_adapter vt586b_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
. name = " VIA i2c " ,
. algo_data = & bit_data ,
} ;
2013-12-03 03:11:20 +04:00
static const struct pci_device_id vt586b_ids [ ] = {
2005-04-17 02:20:36 +04:00
{ PCI_DEVICE ( PCI_VENDOR_ID_VIA , PCI_DEVICE_ID_VIA_82C586_3 ) } ,
{ 0 , }
} ;
MODULE_DEVICE_TABLE ( pci , vt586b_ids ) ;
2012-11-28 00:59:38 +04:00
static int vt586b_probe ( struct pci_dev * dev , const struct pci_device_id * id )
2005-04-17 02:20:36 +04:00
{
u16 base ;
u8 rev ;
int res ;
if ( pm_io_base ) {
dev_err ( & dev - > dev , " i2c-via: Will only support one host \n " ) ;
return - ENODEV ;
}
pci_read_config_byte ( dev , PM_CFG_REVID , & rev ) ;
switch ( rev ) {
case 0x00 :
base = PM_CFG_IOBASE0 ;
break ;
case 0x01 :
case 0x10 :
base = PM_CFG_IOBASE1 ;
break ;
default :
base = PM_CFG_IOBASE1 ;
/* later revision */
}
pci_read_config_word ( dev , base , & pm_io_base ) ;
pm_io_base & = ( 0xff < < 8 ) ;
2005-09-25 18:37:04 +04:00
if ( ! request_region ( I2C_DIR , IOSPACE , vt586b_driver . name ) ) {
2005-04-17 02:20:36 +04:00
dev_err ( & dev - > dev , " IO 0x%x-0x%x already in use \n " , I2C_DIR , I2C_DIR + IOSPACE ) ;
return - ENODEV ;
}
outb ( inb ( I2C_DIR ) & ~ ( I2C_SDA | I2C_SCL ) , I2C_DIR ) ;
outb ( inb ( I2C_OUT ) & ~ ( I2C_SDA | I2C_SCL ) , I2C_OUT ) ;
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
vt586b_adapter . dev . parent = & dev - > dev ;
res = i2c_bit_add_bus ( & vt586b_adapter ) ;
if ( res < 0 ) {
release_region ( I2C_DIR , IOSPACE ) ;
pm_io_base = 0 ;
return res ;
}
return 0 ;
}
2012-11-28 00:59:38 +04:00
static void vt586b_remove ( struct pci_dev * dev )
2005-04-17 02:20:36 +04:00
{
2006-12-10 23:21:33 +03:00
i2c_del_adapter ( & vt586b_adapter ) ;
2005-04-17 02:20:36 +04:00
release_region ( I2C_DIR , IOSPACE ) ;
pm_io_base = 0 ;
}
static struct pci_driver vt586b_driver = {
. name = " vt586b_smbus " ,
. id_table = vt586b_ids ,
. probe = vt586b_probe ,
2012-11-28 00:59:38 +04:00
. remove = vt586b_remove ,
2005-04-17 02:20:36 +04:00
} ;
2012-07-24 16:13:56 +04:00
module_pci_driver ( vt586b_driver ) ;
2005-04-17 02:20:36 +04:00
2007-10-20 01:21:04 +04:00
MODULE_AUTHOR ( " Kyösti Mälkki <kmalkki@cc.hut.fi> " ) ;
2005-04-17 02:20:36 +04:00
MODULE_DESCRIPTION ( " i2c for Via vt82c586b southbridge " ) ;
MODULE_LICENSE ( " GPL " ) ;