@ -1,54 +1,54 @@
/*
sis5595 . c - Part of lm_sensors , Linux kernel modules
for hardware monitoring
Copyright ( C ) 1998 - 2001 Frodo Looijaard < frodol @ dds . nl > ,
Kyösti Mälkki < kmalkki @ cc . hut . fi > , and
Mark D . Studebaker < mdsxyz123 @ yahoo . com >
Ported to Linux 2.6 by Aurelien Jarno < aurelien @ aurel32 . net > with
the help of 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
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 .
*/
* sis5595 . c - Part of lm_sensors , Linux kernel modules
* for hardware monitoring
*
* Copyright ( C ) 1998 - 2001 Frodo Looijaard < frodol @ dds . nl > ,
* Kyösti Mälkki < kmalkki @ cc . hut . fi > , and
* Mark D . Studebaker < mdsxyz123 @ yahoo . com >
* Ported to Linux 2.6 by Aurelien Jarno < aurelien @ aurel32 . net > with
* the help of 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
* 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 .
*/
/*
SiS southbridge has a LM78 - like chip integrated on the same IC .
This driver is a customized copy of lm78 . c
Supports following revisions :
Version PCI ID PCI Revision
1 1039 / 000 8 AF or less
2 1039 / 000 8 B0 or greater
Note : these chips contain a 000 8 device which is incompatible with the
5595. We recognize these by the presence of the listed
" blacklist " PCI ID and refuse to load .
NOT SUPPORTED PCI ID BLACKLIST PCI ID
540 000 8 0540
550 000 8 0550
5513 000 8 5511
5581 000 8 5597
5582 000 8 5597
5597 000 8 5597
5598 000 8 5597 / 5598
630 000 8 0630
645 000 8 0645
730 000 8 0730
735 000 8 0735
*/
* SiS southbridge has a LM78 - like chip integrated on the same IC .
* This driver is a customized copy of lm78 . c
*
* Supports following revisions :
* Version PCI ID PCI Revision
* 1 1039 / 000 8 AF or less
* 2 1039 / 000 8 B0 or greater
*
* Note : these chips contain a 000 8 device which is incompatible with the
* 5595. We recognize these by the presence of the listed
* " blacklist " PCI ID and refuse to load .
*
* NOT SUPPORTED PCI ID BLACKLIST PCI ID
* 540 000 8 0540
* 550 000 8 0550
* 5513 000 8 5511
* 5581 000 8 5597
* 5582 000 8 5597
* 5597 000 8 5597
* 5598 000 8 5597 / 5598
* 630 000 8 0630
* 645 000 8 0645
* 730 000 8 0730
* 735 000 8 0735
*/
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@ -68,8 +68,10 @@
# include <linux/io.h>
/* If force_addr is set to anything different from 0, we forcibly enable
the device at the given address . */
/*
* If force_addr is set to anything different from 0 , we forcibly enable
* the device at the given address .
*/
static u16 force_addr ;
module_param ( force_addr , ushort , 0 ) ;
MODULE_PARM_DESC ( force_addr ,
@ -98,30 +100,36 @@ static struct platform_device *pdev;
# define SIS5595_REG_FAN_MIN(nr) (0x3b + (nr))
# define SIS5595_REG_FAN(nr) (0x28 + (nr))
/* On the first version of the chip, the temp registers are separate.
On the second version ,
TEMP pin is shared with IN4 , configured in PCI register 0x7A .
The registers are the same as well .
OVER and HYST are really MAX and MIN . */
/*
* On the first version of the chip , the temp registers are separate .
* On the second version ,
* TEMP pin is shared with IN4 , configured in PCI register 0x7A .
* The registers are the same as well .
* OVER and HYST are really MAX and MIN .
*/
# define REV2MIN 0xb0
# define SIS5595_REG_TEMP (( data->revision) >= REV2MIN) ? \
SIS5595_REG_IN ( 4 ) : 0x27
# define SIS5595_REG_TEMP_OVER (( data->revision) >= REV2MIN) ? \
SIS5595_REG_IN_MAX ( 4 ) : 0x39
# define SIS5595_REG_TEMP_HYST (( data->revision) >= REV2MIN) ? \
SIS5595_REG_IN_MIN ( 4 ) : 0x3a
# define SIS5595_REG_TEMP ((( data->revision) >= REV2MIN) ? \
SIS5595_REG_IN ( 4 ) : 0x27 )
# define SIS5595_REG_TEMP_OVER ((( data->revision) >= REV2MIN) ? \
SIS5595_REG_IN_MAX ( 4 ) : 0x39 )
# define SIS5595_REG_TEMP_HYST ((( data->revision) >= REV2MIN) ? \
SIS5595_REG_IN_MIN ( 4 ) : 0x3a )
# define SIS5595_REG_CONFIG 0x40
# define SIS5595_REG_ALARM1 0x41
# define SIS5595_REG_ALARM2 0x42
# define SIS5595_REG_FANDIV 0x47
/* Conversions. Limit checking is only done on the TO_REG
variants . */
/*
* Conversions . Limit checking is only done on the TO_REG
* variants .
*/
/* IN: mV, (0V to 4.08V)
REG : 16 mV / bit */
/*
* IN : mV , ( 0 V to 4.08 V )
* REG : 16 mV / bit
*/
static inline u8 IN_TO_REG ( unsigned long val )
{
unsigned long nval = SENSORS_LIMIT ( val , 0 , 4080 ) ;
@ -138,11 +146,13 @@ static inline u8 FAN_TO_REG(long rpm, int div)
static inline int FAN_FROM_REG ( u8 val , int div )
{
return val = = 0 ? - 1 : val = = 255 ? 0 : 1350000 / ( val * div ) ;
return val = = 0 ? - 1 : val = = 255 ? 0 : 1350000 / ( val * div ) ;
}
/* TEMP: mC (-54.12C to +157.53C)
REG : 0.83 C / bit + 52.12 , two ' s complement */
/*
* TEMP : mC ( - 54.12 C to + 157.53 C )
* REG : 0.83 C / bit + 52.12 , two ' s complement
*/
static inline int TEMP_FROM_REG ( s8 val )
{
return val * 830 + 52120 ;
@ -150,19 +160,23 @@ static inline int TEMP_FROM_REG(s8 val)
static inline s8 TEMP_TO_REG ( int val )
{
int nval = SENSORS_LIMIT ( val , - 54120 , 157530 ) ;
return nval < 0 ? ( nval - 5212 - 415 ) / 830 : ( nval - 5212 + 415 ) / 830 ;
return nval < 0 ? ( nval - 5212 - 415 ) / 830 : ( nval - 5212 + 415 ) / 830 ;
}
/* FAN DIV: 1, 2, 4, or 8 (defaults to 2)
REG : 0 , 1 , 2 , or 3 ( respectively ) ( defaults to 1 ) */
/*
* FAN DIV : 1 , 2 , 4 , or 8 ( defaults to 2 )
* REG : 0 , 1 , 2 , or 3 ( respectively ) ( defaults to 1 )
*/
static inline u8 DIV_TO_REG ( int val )
{
return val = = 8 ? 3 : val = = 4 ? 2 : val = = 1 ? 0 : 1 ;
return val = = 8 ? 3 : val = = 4 ? 2 : val = = 1 ? 0 : 1 ;
}
# define DIV_FROM_REG(val) (1 << (val))
/* For each registered chip, we need to keep some data in memory.
The structure is dynamically allocated . */
/*
* For each registered chip , we need to keep some data in memory .
* The structure is dynamically allocated .
*/
struct sis5595_data {
unsigned short addr ;
const char * name ;
@ -240,7 +254,12 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *da,
struct sis5595_data * data = dev_get_drvdata ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ;
int nr = attr - > index ;
unsigned long val = simple_strtoul ( buf , NULL , 10 ) ;
unsigned long val ;
int err ;
err = kstrtoul ( buf , 10 , & val ) ;
if ( err )
return err ;
mutex_lock ( & data - > update_lock ) ;
data - > in_min [ nr ] = IN_TO_REG ( val ) ;
@ -255,7 +274,12 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *da,
struct sis5595_data * data = dev_get_drvdata ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ;
int nr = attr - > index ;
unsigned long val = simple_strtoul ( buf , NULL , 10 ) ;
unsigned long val ;
int err ;
err = kstrtoul ( buf , 10 , & val ) ;
if ( err )
return err ;
mutex_lock ( & data - > update_lock ) ;
data - > in_max [ nr ] = IN_TO_REG ( val ) ;
@ -279,22 +303,30 @@ show_in_offset(3);
show_in_offset ( 4 ) ;
/* Temperature */
static ssize_t show_temp ( struct device * dev , struct device_attribute * attr , char * buf )
static ssize_t show_temp ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct sis5595_data * data = sis5595_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , TEMP_FROM_REG ( data - > temp ) ) ;
}
static ssize_t show_temp_over ( struct device * dev , struct device_attribute * attr , char * buf )
static ssize_t show_temp_over ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct sis5595_data * data = sis5595_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , TEMP_FROM_REG ( data - > temp_over ) ) ;
}
static ssize_t set_temp_over ( struct device * dev , struct device_attribute * attr , const char * buf , size_t count )
static ssize_t set_temp_over ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct sis5595_data * data = dev_get_drvdata ( dev ) ;
long val = simple_strtol ( buf , NULL , 10 ) ;
long val ;
int err ;
err = kstrtol ( buf , 10 , & val ) ;
if ( err )
return err ;
mutex_lock ( & data - > update_lock ) ;
data - > temp_over = TEMP_TO_REG ( val ) ;
@ -303,16 +335,23 @@ static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr,
return count ;
}
static ssize_t show_temp_hyst ( struct device * dev , struct device_attribute * attr , char * buf )
static ssize_t show_temp_hyst ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct sis5595_data * data = sis5595_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , TEMP_FROM_REG ( data - > temp_hyst ) ) ;
}
static ssize_t set_temp_hyst ( struct device * dev , struct device_attribute * attr , const char * buf , size_t count )
static ssize_t set_temp_hyst ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct sis5595_data * data = dev_get_drvdata ( dev ) ;
long val = simple_strtol ( buf , NULL , 10 ) ;
long val ;
int err ;
err = kstrtol ( buf , 10 , & val ) ;
if ( err )
return err ;
mutex_lock ( & data - > update_lock ) ;
data - > temp_hyst = TEMP_TO_REG ( val ) ;
@ -335,7 +374,7 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *da,
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ;
int nr = attr - > index ;
return sprintf ( buf , " %d \n " , FAN_FROM_REG ( data - > fan [ nr ] ,
DIV_FROM_REG ( data - > fan_div [ nr ] ) ) ) ;
DIV_FROM_REG ( data - > fan_div [ nr ] ) ) ) ;
}
static ssize_t show_fan_min ( struct device * dev , struct device_attribute * da ,
@ -344,8 +383,8 @@ static ssize_t show_fan_min(struct device *dev, struct device_attribute *da,
struct sis5595_data * data = sis5595_update_device ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ;
int nr = attr - > index ;
return sprintf ( buf , " %d \n " , FAN_FROM_REG ( data - > fan_min [ nr ] ,
DIV_FROM_REG ( data - > fan_div [ nr ] ) ) ) ;
return sprintf ( buf , " %d \n " , FAN_FROM_REG ( data - > fan_min [ nr ] ,
DIV_FROM_REG ( data - > fan_div [ nr ] ) ) ) ;
}
static ssize_t set_fan_min ( struct device * dev , struct device_attribute * da ,
@ -354,7 +393,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
struct sis5595_data * data = dev_get_drvdata ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ;
int nr = attr - > index ;
unsigned long val = simple_strtoul ( buf , NULL , 10 ) ;
unsigned long val ;
int err ;
err = kstrtoul ( buf , 10 , & val ) ;
if ( err )
return err ;
mutex_lock ( & data - > update_lock ) ;
data - > fan_min [ nr ] = FAN_TO_REG ( val , DIV_FROM_REG ( data - > fan_div [ nr ] ) ) ;
@ -369,13 +413,15 @@ static ssize_t show_fan_div(struct device *dev, struct device_attribute *da,
struct sis5595_data * data = sis5595_update_device ( dev ) ;
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ;
int nr = attr - > index ;
return sprintf ( buf , " %d \n " , DIV_FROM_REG ( data - > fan_div [ nr ] ) ) ;
return sprintf ( buf , " %d \n " , DIV_FROM_REG ( data - > fan_div [ nr ] ) ) ;
}
/* Note: we save and restore the fan minimum here, because its value is
determined in part by the fan divisor . This follows the principle of
least surprise ; the user doesn ' t expect the fan minimum to change just
because the divisor changed . */
/*
* Note : we save and restore the fan minimum here , because its value is
* determined in part by the fan divisor . This follows the principle of
* least surprise ; the user doesn ' t expect the fan minimum to change just
* because the divisor changed .
*/
static ssize_t set_fan_div ( struct device * dev , struct device_attribute * da ,
const char * buf , size_t count )
{
@ -383,8 +429,13 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ;
int nr = attr - > index ;
unsigned long min ;
unsigned long val = simple_strtoul ( buf , NULL , 10 ) ;
int reg ;
unsigned long val ;
int err ;
err = kstrtoul ( buf , 10 , & val ) ;
if ( err )
return err ;
mutex_lock ( & data - > update_lock ) ;
min = FAN_FROM_REG ( data - > fan_min [ nr ] ,
@ -392,17 +443,25 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
reg = sis5595_read_value ( data , SIS5595_REG_FANDIV ) ;
switch ( val ) {
case 1 : data - > fan_div [ nr ] = 0 ; break ;
case 2 : data - > fan_div [ nr ] = 1 ; break ;
case 4 : data - > fan_div [ nr ] = 2 ; break ;
case 8 : data - > fan_div [ nr ] = 3 ; break ;
case 1 :
data - > fan_div [ nr ] = 0 ;
break ;
case 2 :
data - > fan_div [ nr ] = 1 ;
break ;
case 4 :
data - > fan_div [ nr ] = 2 ;
break ;
case 8 :
data - > fan_div [ nr ] = 3 ;
break ;
default :
dev_err ( dev , " fan_div value %ld not "
" supported. Choose one of 1, 2, 4 or 8! \n " , val ) ;
mutex_unlock ( & data - > update_lock ) ;
return - EINVAL ;
}
switch ( nr ) {
case 0 :
reg = ( reg & 0xcf ) | ( data - > fan_div [ nr ] < < 4 ) ;
@ -431,7 +490,8 @@ show_fan_offset(1);
show_fan_offset ( 2 ) ;
/* Alarms */
static ssize_t show_alarms ( struct device * dev , struct device_attribute * attr , char * buf )
static ssize_t show_alarms ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct sis5595_data * data = sis5595_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , data - > alarms ) ;
@ -521,7 +581,7 @@ static struct attribute *sis5595_attributes_temp1[] = {
static const struct attribute_group sis5595_group_temp1 = {
. attrs = sis5595_attributes_temp1 ,
} ;
/* This is called when the module is loaded */
static int __devinit sis5595_probe ( struct platform_device * pdev )
{
@ -539,7 +599,8 @@ static int __devinit sis5595_probe(struct platform_device *pdev)
goto exit ;
}
if ( ! ( data = kzalloc ( sizeof ( struct sis5595_data ) , GFP_KERNEL ) ) ) {
data = kzalloc ( sizeof ( struct sis5595_data ) , GFP_KERNEL ) ;
if ( ! data ) {
err = - ENOMEM ;
goto exit_release ;
}
@ -550,7 +611,9 @@ static int __devinit sis5595_probe(struct platform_device *pdev)
data - > name = " sis5595 " ;
platform_set_drvdata ( pdev , data ) ;
/* Check revision and pin registers to determine whether 4 or 5 voltages */
/*
* Check revision and pin registers to determine whether 4 or 5 voltages
*/
data - > revision = s_bridge - > revision ;
/* 4 voltages, 1 temp */
data - > maxins = 3 ;
@ -560,7 +623,7 @@ static int __devinit sis5595_probe(struct platform_device *pdev)
/* 5 voltages, no temps */
data - > maxins = 4 ;
}
/* Initialize the SIS5595 chip */
sis5595_init_device ( data ) ;
@ -571,15 +634,16 @@ static int __devinit sis5595_probe(struct platform_device *pdev)
}
/* Register sysfs hooks */
if ( ( err = sysfs_create_group ( & pdev - > dev . kobj , & sis5595_group ) ) )
err = sysfs_create_group ( & pdev - > dev . kobj , & sis5595_group ) ;
if ( err )
goto exit_free ;
if ( data - > maxins = = 4 ) {
if ( ( err = sysfs_create_group ( & pdev - > dev . kobj ,
& sis5595_group_in4 ) ) )
err = sysfs_create_group ( & pdev - > dev . kobj , & sis5595_group_in4 ) ;
if ( err )
goto exit_remove_files ;
} else {
if ( ( err = sysfs_create_group ( & pdev - > dev . kobj ,
& sis5595_group_temp1 ) ) )
err = sysfs_create_group ( & pdev - > dev . kobj , & sis5595_group_temp1 ) ;
if ( err )
goto exit_remove_files ;
}
@ -713,9 +777,11 @@ static int blacklist[] __devinitdata = {
PCI_DEVICE_ID_SI_645 ,
PCI_DEVICE_ID_SI_730 ,
PCI_DEVICE_ID_SI_735 ,
PCI_DEVICE_ID_SI_5511 , /* 5513 chip has the 0008 device but
that ID shows up in other chips so we
use the 5511 ID for recognition */
PCI_DEVICE_ID_SI_5511 , /*
* 5513 chip has the 000 8 device but
* that ID shows up in other chips so we
* use the 5511 ID for recognition
*/
PCI_DEVICE_ID_SI_5597 ,
PCI_DEVICE_ID_SI_5598 ,
0 } ;
@ -770,13 +836,16 @@ static int __devinit sis5595_pci_probe(struct pci_dev *dev,
for ( i = blacklist ; * i ! = 0 ; i + + ) {
struct pci_dev * d ;
if ( ( d = pci_get_device ( PCI_VENDOR_ID_SI , * i , NULL ) ) ) {
dev_err ( & d - > dev , " Looked for SIS5595 but found unsupported device %.4x \n " , * i ) ;
d = pci_get_device ( PCI_VENDOR_ID_SI , * i , NULL ) ;
if ( d ) {
dev_err ( & d - > dev ,
" Looked for SIS5595 but found unsupported device %.4x \n " ,
* i ) ;
pci_dev_put ( d ) ;
return - ENODEV ;
}
}
force_addr & = ~ ( SIS5595_EXTENT - 1 ) ;
if ( force_addr ) {
dev_warn ( & dev - > dev , " Forcing ISA address 0x%x \n " , force_addr ) ;
@ -788,10 +857,11 @@ static int __devinit sis5595_pci_probe(struct pci_dev *dev,
dev_err ( & dev - > dev , " Failed to read ISA address \n " ) ;
return - ENODEV ;
}
address & = ~ ( SIS5595_EXTENT - 1 ) ;
if ( ! address ) {
dev_err ( & dev - > dev , " Base address not set - upgrade BIOS or use force_addr=0xaddr \n " ) ;
dev_err ( & dev - > dev ,
" Base address not set - upgrade BIOS or use force_addr=0xaddr \n " ) ;
return - ENODEV ;
}
if ( force_addr & & address ! = force_addr ) {
@ -828,7 +898,8 @@ static int __devinit sis5595_pci_probe(struct pci_dev *dev,
if ( sis5595_device_add ( address ) )
goto exit_unregister ;
/* Always return failure here. This is to allow other drivers to bind
/*
* 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 .
*/