2005-11-26 22:20:05 +03:00
/*
2012-01-19 23:02:27 +04:00
* vt8231 . c - Part of lm_sensors , Linux kernel modules
* for hardware monitoring
*
* Copyright ( c ) 2005 Roger Lucas < vt8231 @ hiddenengine . co . uk >
* Copyright ( c ) 2002 Mark D . Studebaker < mdsxyz123 @ yahoo . com >
* Aaron M . Marsh < amarsh @ sdf . lonestar . 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 .
*/
2005-11-26 22:20:05 +03:00
2012-01-19 23:02:27 +04:00
/*
* Supports VIA VT8231 South Bridge embedded sensors
*/
2005-11-26 22:20:05 +03:00
2010-10-20 10:51:53 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2005-11-26 22:20:05 +03:00
# include <linux/module.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/pci.h>
# include <linux/jiffies.h>
2007-06-12 23:04:08 +04:00
# include <linux/platform_device.h>
2005-11-26 22:20:05 +03:00
# include <linux/hwmon.h>
# include <linux/hwmon-sysfs.h>
# include <linux/hwmon-vid.h>
# include <linux/err.h>
2006-01-19 01:19:26 +03:00
# include <linux/mutex.h>
2009-01-07 18:37:35 +03:00
# include <linux/acpi.h>
2009-09-15 19:18:13 +04:00
# include <linux/io.h>
2005-11-26 22:20:05 +03:00
static int force_addr ;
module_param ( force_addr , int , 0 ) ;
MODULE_PARM_DESC ( force_addr , " Initialize the base address of the sensors " ) ;
2007-06-12 23:04:08 +04:00
static struct platform_device * pdev ;
2005-11-26 22:20:05 +03:00
# define VT8231_EXTENT 0x80
# define VT8231_BASE_REG 0x70
# define VT8231_ENABLE_REG 0x74
2012-01-19 23:02:27 +04:00
/*
* The VT8231 registers
*
* The reset value for the input channel configuration is used ( Reg 0x4A = 0x07 )
* which sets the selected inputs marked with ' * ' below if multiple options are
* possible :
*
* Voltage Mode Temperature Mode
* Sensor Linux Id Linux Id VIA Id
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* CPU Diode N / A temp1 0
* UIC1 in0 temp2 * 1
* UIC2 in1 * temp3 2
* UIC3 in2 * temp4 3
* UIC4 in3 * temp5 4
* UIC5 in4 * temp6 5
* 3.3 V in5 N / A
*
* Note that the BIOS may set the configuration register to a different value
* to match the motherboard configuration .
*/
2005-11-26 22:20:05 +03:00
/* fans numbered 0-1 */
# define VT8231_REG_FAN_MIN(nr) (0x3b + (nr))
# define VT8231_REG_FAN(nr) (0x29 + (nr))
/* Voltage inputs numbered 0-5 */
static const u8 regvolt [ ] = { 0x21 , 0x22 , 0x23 , 0x24 , 0x25 , 0x26 } ;
static const u8 regvoltmax [ ] = { 0x3d , 0x2b , 0x2d , 0x2f , 0x31 , 0x33 } ;
static const u8 regvoltmin [ ] = { 0x3e , 0x2c , 0x2e , 0x30 , 0x32 , 0x34 } ;
2012-01-19 23:02:27 +04:00
/*
* Temperatures are numbered 1 - 6 according to the Linux kernel specification .
*
* In the VIA datasheet , however , the temperatures are numbered from zero .
* Since it is important that this driver can easily be compared to the VIA
* datasheet , we will use the VIA numbering within this driver and map the
* kernel sysfs device name to the VIA number in the sysfs callback .
*/
2005-11-26 22:20:05 +03:00
# define VT8231_REG_TEMP_LOW01 0x49
# define VT8231_REG_TEMP_LOW25 0x4d
static const u8 regtemp [ ] = { 0x1f , 0x21 , 0x22 , 0x23 , 0x24 , 0x25 } ;
static const u8 regtempmax [ ] = { 0x39 , 0x3d , 0x2b , 0x2d , 0x2f , 0x31 } ;
static const u8 regtempmin [ ] = { 0x3a , 0x3e , 0x2c , 0x2e , 0x30 , 0x32 } ;
# define TEMP_FROM_REG(reg) (((253 * 4 - (reg)) * 550 + 105) / 210)
# define TEMP_MAXMIN_FROM_REG(reg) (((253 - (reg)) * 2200 + 105) / 210)
# define TEMP_MAXMIN_TO_REG(val) (253 - ((val) * 210 + 1100) / 2200)
# define VT8231_REG_CONFIG 0x40
# define VT8231_REG_ALARM1 0x41
# define VT8231_REG_ALARM2 0x42
# define VT8231_REG_FANDIV 0x47
# define VT8231_REG_UCH_CONFIG 0x4a
# define VT8231_REG_TEMP1_CONFIG 0x4b
# define VT8231_REG_TEMP2_CONFIG 0x4c
2012-01-19 23:02:27 +04:00
/*
* temps 0 - 5 as numbered in VIA datasheet - see later for mapping to Linux
* numbering
*/
2005-11-26 22:20:05 +03:00
# define ISTEMP(i, ch_config) ((i) == 0 ? 1 : \
( ( ch_config ) > > ( ( i ) + 1 ) ) & 0x01 )
/* voltages 0-5 */
# define ISVOLT(i, ch_config) ((i) == 5 ? 1 : \
! ( ( ( ch_config ) > > ( ( i ) + 2 ) ) & 0x01 ) )
# define DIV_FROM_REG(val) (1 << (val))
2012-01-19 23:02:27 +04:00
/*
* NB The values returned here are NOT temperatures . The calibration curves
* for the thermistor curves are board - specific and must go in the
* sensors . conf file . Temperature sensors are actually ten bits , but the
* VIA datasheet only considers the 8 MSBs obtained from the regtemp [ ]
* register . The temperature value returned should have a magnitude of 3 ,
* so we use the VIA scaling as the " true " scaling and use the remaining 2
* LSBs as fractional precision .
*
* All the on - chip hardware temperature comparisons for the alarms are only
* 8 - bits wide , and compare against the 8 MSBs of the temperature . The bits
* in the registers VT8231_REG_TEMP_LOW01 and VT8231_REG_TEMP_LOW25 are
* ignored .
*/
/*
* * * * * * FAN RPM CONVERSIONS * * * * * * * *
* This chip saturates back at 0 , not at 255 like many the other chips .
* So , 0 means 0 RPM
*/
2005-11-26 22:20:05 +03:00
static inline u8 FAN_TO_REG ( long rpm , int div )
{
2013-12-12 11:05:33 +04:00
if ( rpm < = 0 | | rpm > 1310720 )
2005-11-26 22:20:05 +03:00
return 0 ;
2013-01-09 20:09:34 +04:00
return clamp_val ( 1310720 / ( rpm * div ) , 1 , 255 ) ;
2005-11-26 22:20:05 +03:00
}
# define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : 1310720 / ((val) * (div)))
struct vt8231_data {
2007-06-12 23:04:08 +04:00
unsigned short addr ;
const char * name ;
2006-01-19 01:19:26 +03:00
struct mutex update_lock ;
2007-08-21 00:46:20 +04:00
struct device * hwmon_dev ;
2005-11-26 22:20:05 +03:00
char valid ; /* !=0 if following fields are valid */
unsigned long last_updated ; /* In jiffies */
u8 in [ 6 ] ; /* Register value */
u8 in_max [ 6 ] ; /* Register value */
u8 in_min [ 6 ] ; /* Register value */
u16 temp [ 6 ] ; /* Register value 10 bit, right aligned */
u8 temp_max [ 6 ] ; /* Register value */
u8 temp_min [ 6 ] ; /* Register value */
u8 fan [ 2 ] ; /* Register value */
u8 fan_min [ 2 ] ; /* Register value */
u8 fan_div [ 2 ] ; /* Register encoding, shifted right */
u16 alarms ; /* Register encoding */
u8 uch_config ;
} ;
static struct pci_dev * s_bridge ;
2007-06-12 23:04:08 +04:00
static int vt8231_probe ( struct platform_device * pdev ) ;
2012-11-19 22:25:51 +04:00
static int vt8231_remove ( struct platform_device * pdev ) ;
2005-11-26 22:20:05 +03:00
static struct vt8231_data * vt8231_update_device ( struct device * dev ) ;
2007-06-12 23:04:08 +04:00
static void vt8231_init_device ( struct vt8231_data * data ) ;
2005-11-26 22:20:05 +03:00
2007-06-12 23:04:08 +04:00
static inline int vt8231_read_value ( struct vt8231_data * data , u8 reg )
2005-11-26 22:20:05 +03:00
{
2007-06-12 23:04:08 +04:00
return inb_p ( data - > addr + reg ) ;
2005-11-26 22:20:05 +03:00
}
2007-06-12 23:04:08 +04:00
static inline void vt8231_write_value ( struct vt8231_data * data , u8 reg ,
2005-11-26 22:20:05 +03:00
u8 value )
{
2007-06-12 23:04:08 +04:00
outb_p ( value , data - > addr + reg ) ;
2005-11-26 22:20:05 +03:00
}
/* following are the sysfs callback functions */
static ssize_t show_in ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct sensor_device_attribute * sensor_attr = to_sensor_dev_attr ( attr ) ;
int nr = sensor_attr - > index ;
struct vt8231_data * data = vt8231_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , ( ( data - > in [ nr ] - 3 ) * 10000 ) / 958 ) ;
}
static ssize_t show_in_min ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct sensor_device_attribute * sensor_attr = to_sensor_dev_attr ( attr ) ;
int nr = sensor_attr - > index ;
struct vt8231_data * data = vt8231_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , ( ( data - > in_min [ nr ] - 3 ) * 10000 ) / 958 ) ;
}
static ssize_t show_in_max ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct sensor_device_attribute * sensor_attr = to_sensor_dev_attr ( attr ) ;
int nr = sensor_attr - > index ;
struct vt8231_data * data = vt8231_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , ( ( ( data - > in_max [ nr ] - 3 ) * 10000 ) / 958 ) ) ;
}
static ssize_t set_in_min ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct sensor_device_attribute * sensor_attr = to_sensor_dev_attr ( attr ) ;
int nr = sensor_attr - > index ;
2007-06-12 23:04:08 +04:00
struct vt8231_data * data = dev_get_drvdata ( dev ) ;
2012-01-15 19:03:38 +04:00
unsigned long val ;
int err ;
err = kstrtoul ( buf , 10 , & val ) ;
if ( err )
return err ;
2005-11-26 22:20:05 +03:00
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2013-01-09 20:09:34 +04:00
data - > in_min [ nr ] = clamp_val ( ( ( val * 958 ) / 10000 ) + 3 , 0 , 255 ) ;
2007-06-12 23:04:08 +04:00
vt8231_write_value ( data , regvoltmin [ nr ] , data - > in_min [ nr ] ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-11-26 22:20:05 +03:00
return count ;
}
static ssize_t set_in_max ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct sensor_device_attribute * sensor_attr = to_sensor_dev_attr ( attr ) ;
int nr = sensor_attr - > index ;
2007-06-12 23:04:08 +04:00
struct vt8231_data * data = dev_get_drvdata ( dev ) ;
2012-01-15 19:03:38 +04:00
unsigned long val ;
int err ;
err = kstrtoul ( buf , 10 , & val ) ;
if ( err )
return err ;
2005-11-26 22:20:05 +03:00
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2013-01-09 20:09:34 +04:00
data - > in_max [ nr ] = clamp_val ( ( ( val * 958 ) / 10000 ) + 3 , 0 , 255 ) ;
2007-06-12 23:04:08 +04:00
vt8231_write_value ( data , regvoltmax [ nr ] , data - > in_max [ nr ] ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-11-26 22:20:05 +03:00
return count ;
}
/* Special case for input 5 as this has 3.3V scaling built into the chip */
2016-12-22 15:05:18 +03:00
static ssize_t in5_input_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-11-26 22:20:05 +03:00
{
struct vt8231_data * data = vt8231_update_device ( dev ) ;
return sprintf ( buf , " %d \n " ,
( ( ( data - > in [ 5 ] - 3 ) * 10000 * 54 ) / ( 958 * 34 ) ) ) ;
}
2016-12-22 15:05:18 +03:00
static ssize_t in5_min_show ( struct device * dev , struct device_attribute * attr ,
2005-11-26 22:20:05 +03:00
char * buf )
{
struct vt8231_data * data = vt8231_update_device ( dev ) ;
return sprintf ( buf , " %d \n " ,
( ( ( data - > in_min [ 5 ] - 3 ) * 10000 * 54 ) / ( 958 * 34 ) ) ) ;
}
2016-12-22 15:05:18 +03:00
static ssize_t in5_max_show ( struct device * dev , struct device_attribute * attr ,
2005-11-26 22:20:05 +03:00
char * buf )
{
struct vt8231_data * data = vt8231_update_device ( dev ) ;
return sprintf ( buf , " %d \n " ,
( ( ( data - > in_max [ 5 ] - 3 ) * 10000 * 54 ) / ( 958 * 34 ) ) ) ;
}
2016-12-22 15:05:18 +03:00
static ssize_t in5_min_store ( struct device * dev ,
struct device_attribute * attr , const char * buf ,
size_t count )
2005-11-26 22:20:05 +03:00
{
2007-06-12 23:04:08 +04:00
struct vt8231_data * data = dev_get_drvdata ( dev ) ;
2012-01-15 19:03:38 +04:00
unsigned long val ;
int err ;
err = kstrtoul ( buf , 10 , & val ) ;
if ( err )
return err ;
2005-11-26 22:20:05 +03:00
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2013-01-09 20:09:34 +04:00
data - > in_min [ 5 ] = clamp_val ( ( ( val * 958 * 34 ) / ( 10000 * 54 ) ) + 3 ,
0 , 255 ) ;
2007-06-12 23:04:08 +04:00
vt8231_write_value ( data , regvoltmin [ 5 ] , data - > in_min [ 5 ] ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-11-26 22:20:05 +03:00
return count ;
}
2016-12-22 15:05:18 +03:00
static ssize_t in5_max_store ( struct device * dev ,
struct device_attribute * attr , const char * buf ,
size_t count )
2005-11-26 22:20:05 +03:00
{
2007-06-12 23:04:08 +04:00
struct vt8231_data * data = dev_get_drvdata ( dev ) ;
2012-01-15 19:03:38 +04:00
unsigned long val ;
int err ;
err = kstrtoul ( buf , 10 , & val ) ;
if ( err )
return err ;
2005-11-26 22:20:05 +03:00
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2013-01-09 20:09:34 +04:00
data - > in_max [ 5 ] = clamp_val ( ( ( val * 958 * 34 ) / ( 10000 * 54 ) ) + 3 ,
0 , 255 ) ;
2007-06-12 23:04:08 +04:00
vt8231_write_value ( data , regvoltmax [ 5 ] , data - > in_max [ 5 ] ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-11-26 22:20:05 +03:00
return count ;
}
# define define_voltage_sysfs(offset) \
static SENSOR_DEVICE_ATTR ( in # # offset # # _input , S_IRUGO , \
show_in , NULL , offset ) ; \
static SENSOR_DEVICE_ATTR ( in # # offset # # _min , S_IRUGO | S_IWUSR , \
show_in_min , set_in_min , offset ) ; \
static SENSOR_DEVICE_ATTR ( in # # offset # # _max , S_IRUGO | S_IWUSR , \
show_in_max , set_in_max , offset )
define_voltage_sysfs ( 0 ) ;
define_voltage_sysfs ( 1 ) ;
define_voltage_sysfs ( 2 ) ;
define_voltage_sysfs ( 3 ) ;
define_voltage_sysfs ( 4 ) ;
2016-12-22 15:05:18 +03:00
static DEVICE_ATTR_RO ( in5_input ) ;
static DEVICE_ATTR_RW ( in5_min ) ;
static DEVICE_ATTR_RW ( in5_max ) ;
2005-11-26 22:20:05 +03:00
/* Temperatures */
2016-12-22 15:05:18 +03:00
static ssize_t temp1_input_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-11-26 22:20:05 +03:00
{
struct vt8231_data * data = vt8231_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , data - > temp [ 0 ] * 250 ) ;
}
2016-12-22 15:05:18 +03:00
static ssize_t temp1_max_show ( struct device * dev , struct device_attribute * attr ,
2005-11-26 22:20:05 +03:00
char * buf )
{
struct vt8231_data * data = vt8231_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , data - > temp_max [ 0 ] * 1000 ) ;
}
2016-12-22 15:05:18 +03:00
static ssize_t temp1_max_hyst_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-11-26 22:20:05 +03:00
{
struct vt8231_data * data = vt8231_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , data - > temp_min [ 0 ] * 1000 ) ;
}
2016-12-22 15:05:18 +03:00
static ssize_t temp1_max_store ( struct device * dev ,
struct device_attribute * attr , const char * buf ,
size_t count )
2005-11-26 22:20:05 +03:00
{
2007-06-12 23:04:08 +04:00
struct vt8231_data * data = dev_get_drvdata ( dev ) ;
2012-01-15 19:03:38 +04:00
long val ;
int err ;
err = kstrtol ( buf , 10 , & val ) ;
if ( err )
return err ;
2005-11-26 22:20:05 +03:00
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2013-01-09 20:09:34 +04:00
data - > temp_max [ 0 ] = clamp_val ( ( val + 500 ) / 1000 , 0 , 255 ) ;
2007-06-12 23:04:08 +04:00
vt8231_write_value ( data , regtempmax [ 0 ] , data - > temp_max [ 0 ] ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-11-26 22:20:05 +03:00
return count ;
}
2016-12-22 15:05:18 +03:00
static ssize_t temp1_max_hyst_store ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
2005-11-26 22:20:05 +03:00
{
2007-06-12 23:04:08 +04:00
struct vt8231_data * data = dev_get_drvdata ( dev ) ;
2012-01-15 19:03:38 +04:00
long val ;
int err ;
err = kstrtol ( buf , 10 , & val ) ;
if ( err )
return err ;
2005-11-26 22:20:05 +03:00
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2013-01-09 20:09:34 +04:00
data - > temp_min [ 0 ] = clamp_val ( ( val + 500 ) / 1000 , 0 , 255 ) ;
2007-06-12 23:04:08 +04:00
vt8231_write_value ( data , regtempmin [ 0 ] , data - > temp_min [ 0 ] ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-11-26 22:20:05 +03:00
return count ;
}
static ssize_t show_temp ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct sensor_device_attribute * sensor_attr = to_sensor_dev_attr ( attr ) ;
int nr = sensor_attr - > index ;
struct vt8231_data * data = vt8231_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , TEMP_FROM_REG ( data - > temp [ nr ] ) ) ;
}
static ssize_t show_temp_max ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct sensor_device_attribute * sensor_attr = to_sensor_dev_attr ( attr ) ;
int nr = sensor_attr - > index ;
struct vt8231_data * data = vt8231_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , TEMP_MAXMIN_FROM_REG ( data - > temp_max [ nr ] ) ) ;
}
static ssize_t show_temp_min ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct sensor_device_attribute * sensor_attr = to_sensor_dev_attr ( attr ) ;
int nr = sensor_attr - > index ;
struct vt8231_data * data = vt8231_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , TEMP_MAXMIN_FROM_REG ( data - > temp_min [ nr ] ) ) ;
}
static ssize_t set_temp_max ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct sensor_device_attribute * sensor_attr = to_sensor_dev_attr ( attr ) ;
int nr = sensor_attr - > index ;
2007-06-12 23:04:08 +04:00
struct vt8231_data * data = dev_get_drvdata ( dev ) ;
2012-01-15 19:03:38 +04:00
long val ;
int err ;
err = kstrtol ( buf , 10 , & val ) ;
if ( err )
return err ;
2005-11-26 22:20:05 +03:00
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2013-01-09 20:09:34 +04:00
data - > temp_max [ nr ] = clamp_val ( TEMP_MAXMIN_TO_REG ( val ) , 0 , 255 ) ;
2007-06-12 23:04:08 +04:00
vt8231_write_value ( data , regtempmax [ nr ] , data - > temp_max [ nr ] ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-11-26 22:20:05 +03:00
return count ;
}
static ssize_t set_temp_min ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct sensor_device_attribute * sensor_attr = to_sensor_dev_attr ( attr ) ;
int nr = sensor_attr - > index ;
2007-06-12 23:04:08 +04:00
struct vt8231_data * data = dev_get_drvdata ( dev ) ;
2012-01-15 19:03:38 +04:00
long val ;
int err ;
err = kstrtol ( buf , 10 , & val ) ;
if ( err )
return err ;
2005-11-26 22:20:05 +03:00
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2013-01-09 20:09:34 +04:00
data - > temp_min [ nr ] = clamp_val ( TEMP_MAXMIN_TO_REG ( val ) , 0 , 255 ) ;
2007-06-12 23:04:08 +04:00
vt8231_write_value ( data , regtempmin [ nr ] , data - > temp_min [ nr ] ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-11-26 22:20:05 +03:00
return count ;
}
2012-01-19 23:02:27 +04:00
/*
* Note that these map the Linux temperature sensor numbering ( 1 - 6 ) to the VIA
* temperature sensor numbering ( 0 - 5 )
*/
2005-11-26 22:20:05 +03:00
# define define_temperature_sysfs(offset) \
static SENSOR_DEVICE_ATTR ( temp # # offset # # _input , S_IRUGO , \
show_temp , NULL , offset - 1 ) ; \
static SENSOR_DEVICE_ATTR ( temp # # offset # # _max , S_IRUGO | S_IWUSR , \
show_temp_max , set_temp_max , offset - 1 ) ; \
2006-02-06 01:11:16 +03:00
static SENSOR_DEVICE_ATTR ( temp # # offset # # _max_hyst , S_IRUGO | S_IWUSR , \
2005-11-26 22:20:05 +03:00
show_temp_min , set_temp_min , offset - 1 )
2016-12-22 15:05:18 +03:00
static DEVICE_ATTR_RO ( temp1_input ) ;
static DEVICE_ATTR_RW ( temp1_max ) ;
static DEVICE_ATTR_RW ( temp1_max_hyst ) ;
2005-11-26 22:20:05 +03:00
define_temperature_sysfs ( 2 ) ;
define_temperature_sysfs ( 3 ) ;
define_temperature_sysfs ( 4 ) ;
define_temperature_sysfs ( 5 ) ;
define_temperature_sysfs ( 6 ) ;
/* Fans */
static ssize_t show_fan ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct sensor_device_attribute * sensor_attr = to_sensor_dev_attr ( attr ) ;
int nr = sensor_attr - > index ;
struct vt8231_data * data = vt8231_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , FAN_FROM_REG ( data - > fan [ nr ] ,
DIV_FROM_REG ( data - > fan_div [ nr ] ) ) ) ;
}
static ssize_t show_fan_min ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct sensor_device_attribute * sensor_attr = to_sensor_dev_attr ( attr ) ;
int nr = sensor_attr - > index ;
struct vt8231_data * data = vt8231_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , FAN_FROM_REG ( data - > fan_min [ nr ] ,
DIV_FROM_REG ( data - > fan_div [ nr ] ) ) ) ;
}
static ssize_t show_fan_div ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct sensor_device_attribute * sensor_attr = to_sensor_dev_attr ( attr ) ;
int nr = sensor_attr - > index ;
struct vt8231_data * data = vt8231_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , DIV_FROM_REG ( data - > fan_div [ nr ] ) ) ;
}
static ssize_t set_fan_min ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
{
struct sensor_device_attribute * sensor_attr = to_sensor_dev_attr ( attr ) ;
int nr = sensor_attr - > index ;
2007-06-12 23:04:08 +04:00
struct vt8231_data * data = dev_get_drvdata ( dev ) ;
2012-01-15 19:03:38 +04:00
unsigned long val ;
int err ;
err = kstrtoul ( buf , 10 , & val ) ;
if ( err )
return err ;
2005-11-26 22:20:05 +03:00
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2005-11-26 22:20:05 +03:00
data - > fan_min [ nr ] = FAN_TO_REG ( val , DIV_FROM_REG ( data - > fan_div [ nr ] ) ) ;
2007-06-12 23:04:08 +04:00
vt8231_write_value ( data , VT8231_REG_FAN_MIN ( nr ) , data - > fan_min [ nr ] ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-11-26 22:20:05 +03:00
return count ;
}
static ssize_t set_fan_div ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
{
2007-06-12 23:04:08 +04:00
struct vt8231_data * data = dev_get_drvdata ( dev ) ;
2005-11-26 22:20:05 +03:00
struct sensor_device_attribute * sensor_attr = to_sensor_dev_attr ( attr ) ;
2012-01-15 19:03:38 +04:00
unsigned long val ;
2005-11-26 22:20:05 +03:00
int nr = sensor_attr - > index ;
2007-06-12 23:04:08 +04:00
int old = vt8231_read_value ( data , VT8231_REG_FANDIV ) ;
2005-11-26 22:20:05 +03:00
long min = FAN_FROM_REG ( data - > fan_min [ nr ] ,
DIV_FROM_REG ( data - > fan_div [ nr ] ) ) ;
2012-01-15 19:03:38 +04:00
int err ;
err = kstrtoul ( buf , 10 , & val ) ;
if ( err )
return err ;
2005-11-26 22:20:05 +03:00
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2005-11-26 22:20:05 +03:00
switch ( val ) {
2012-01-15 19:03:38 +04:00
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 ;
2005-11-26 22:20:05 +03:00
default :
2013-01-10 22:01:24 +04:00
dev_err ( dev ,
" fan_div value %ld not supported. Choose one of 1, 2, 4 or 8! \n " ,
val ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-11-26 22:20:05 +03:00
return - EINVAL ;
}
/* Correct the fan minimum speed */
data - > fan_min [ nr ] = FAN_TO_REG ( min , DIV_FROM_REG ( data - > fan_div [ nr ] ) ) ;
2007-06-12 23:04:08 +04:00
vt8231_write_value ( data , VT8231_REG_FAN_MIN ( nr ) , data - > fan_min [ nr ] ) ;
2005-11-26 22:20:05 +03:00
old = ( old & 0x0f ) | ( data - > fan_div [ 1 ] < < 6 ) | ( data - > fan_div [ 0 ] < < 4 ) ;
2007-06-12 23:04:08 +04:00
vt8231_write_value ( data , VT8231_REG_FANDIV , old ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-11-26 22:20:05 +03:00
return count ;
}
# define define_fan_sysfs(offset) \
static SENSOR_DEVICE_ATTR ( fan # # offset # # _input , S_IRUGO , \
show_fan , NULL , offset - 1 ) ; \
static SENSOR_DEVICE_ATTR ( fan # # offset # # _div , S_IRUGO | S_IWUSR , \
show_fan_div , set_fan_div , offset - 1 ) ; \
static SENSOR_DEVICE_ATTR ( fan # # offset # # _min , S_IRUGO | S_IWUSR , \
show_fan_min , set_fan_min , offset - 1 )
define_fan_sysfs ( 1 ) ;
define_fan_sysfs ( 2 ) ;
/* Alarms */
2016-12-22 15:05:18 +03:00
static ssize_t alarms_show ( struct device * dev , struct device_attribute * attr ,
2005-11-26 22:20:05 +03:00
char * buf )
{
struct vt8231_data * data = vt8231_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , data - > alarms ) ;
}
2016-12-22 15:05:18 +03:00
static DEVICE_ATTR_RO ( alarms ) ;
2005-11-26 22:20:05 +03:00
2008-01-06 17:46:02 +03:00
static ssize_t show_alarm ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
int bitnr = to_sensor_dev_attr ( attr ) - > index ;
struct vt8231_data * data = vt8231_update_device ( dev ) ;
return sprintf ( buf , " %u \n " , ( data - > alarms > > bitnr ) & 1 ) ;
}
static SENSOR_DEVICE_ATTR ( temp1_alarm , S_IRUGO , show_alarm , NULL , 4 ) ;
static SENSOR_DEVICE_ATTR ( temp2_alarm , S_IRUGO , show_alarm , NULL , 11 ) ;
static SENSOR_DEVICE_ATTR ( temp3_alarm , S_IRUGO , show_alarm , NULL , 0 ) ;
static SENSOR_DEVICE_ATTR ( temp4_alarm , S_IRUGO , show_alarm , NULL , 1 ) ;
static SENSOR_DEVICE_ATTR ( temp5_alarm , S_IRUGO , show_alarm , NULL , 3 ) ;
static SENSOR_DEVICE_ATTR ( temp6_alarm , S_IRUGO , show_alarm , NULL , 8 ) ;
static SENSOR_DEVICE_ATTR ( in0_alarm , S_IRUGO , show_alarm , NULL , 11 ) ;
static SENSOR_DEVICE_ATTR ( in1_alarm , S_IRUGO , show_alarm , NULL , 0 ) ;
static SENSOR_DEVICE_ATTR ( in2_alarm , S_IRUGO , show_alarm , NULL , 1 ) ;
static SENSOR_DEVICE_ATTR ( in3_alarm , S_IRUGO , show_alarm , NULL , 3 ) ;
static SENSOR_DEVICE_ATTR ( in4_alarm , S_IRUGO , show_alarm , NULL , 8 ) ;
static SENSOR_DEVICE_ATTR ( in5_alarm , S_IRUGO , show_alarm , NULL , 2 ) ;
static SENSOR_DEVICE_ATTR ( fan1_alarm , S_IRUGO , show_alarm , NULL , 6 ) ;
static SENSOR_DEVICE_ATTR ( fan2_alarm , S_IRUGO , show_alarm , NULL , 7 ) ;
2016-12-22 15:05:18 +03:00
static ssize_t name_show ( struct device * dev , struct device_attribute
2007-06-12 23:04:08 +04:00
* devattr , char * buf )
{
struct vt8231_data * data = dev_get_drvdata ( dev ) ;
return sprintf ( buf , " %s \n " , data - > name ) ;
}
2016-12-22 15:05:18 +03:00
static DEVICE_ATTR_RO ( name ) ;
2007-06-12 23:04:08 +04:00
2008-01-06 17:46:02 +03:00
static struct attribute * vt8231_attributes_temps [ 6 ] [ 5 ] = {
2006-09-24 23:21:46 +04:00
{
& dev_attr_temp1_input . attr ,
& dev_attr_temp1_max_hyst . attr ,
& dev_attr_temp1_max . attr ,
2008-01-06 17:46:02 +03:00
& sensor_dev_attr_temp1_alarm . dev_attr . attr ,
2006-09-24 23:21:46 +04:00
NULL
} , {
& sensor_dev_attr_temp2_input . dev_attr . attr ,
& sensor_dev_attr_temp2_max_hyst . dev_attr . attr ,
& sensor_dev_attr_temp2_max . dev_attr . attr ,
2008-01-06 17:46:02 +03:00
& sensor_dev_attr_temp2_alarm . dev_attr . attr ,
2006-09-24 23:21:46 +04:00
NULL
} , {
& sensor_dev_attr_temp3_input . dev_attr . attr ,
& sensor_dev_attr_temp3_max_hyst . dev_attr . attr ,
& sensor_dev_attr_temp3_max . dev_attr . attr ,
2008-01-06 17:46:02 +03:00
& sensor_dev_attr_temp3_alarm . dev_attr . attr ,
2006-09-24 23:21:46 +04:00
NULL
} , {
& sensor_dev_attr_temp4_input . dev_attr . attr ,
& sensor_dev_attr_temp4_max_hyst . dev_attr . attr ,
& sensor_dev_attr_temp4_max . dev_attr . attr ,
2008-01-06 17:46:02 +03:00
& sensor_dev_attr_temp4_alarm . dev_attr . attr ,
2006-09-24 23:21:46 +04:00
NULL
} , {
& sensor_dev_attr_temp5_input . dev_attr . attr ,
& sensor_dev_attr_temp5_max_hyst . dev_attr . attr ,
& sensor_dev_attr_temp5_max . dev_attr . attr ,
2008-01-06 17:46:02 +03:00
& sensor_dev_attr_temp5_alarm . dev_attr . attr ,
2006-09-24 23:21:46 +04:00
NULL
} , {
& sensor_dev_attr_temp6_input . dev_attr . attr ,
& sensor_dev_attr_temp6_max_hyst . dev_attr . attr ,
& sensor_dev_attr_temp6_max . dev_attr . attr ,
2008-01-06 17:46:02 +03:00
& sensor_dev_attr_temp6_alarm . dev_attr . attr ,
2006-09-24 23:21:46 +04:00
NULL
}
} ;
static const struct attribute_group vt8231_group_temps [ 6 ] = {
{ . attrs = vt8231_attributes_temps [ 0 ] } ,
{ . attrs = vt8231_attributes_temps [ 1 ] } ,
{ . attrs = vt8231_attributes_temps [ 2 ] } ,
{ . attrs = vt8231_attributes_temps [ 3 ] } ,
{ . attrs = vt8231_attributes_temps [ 4 ] } ,
{ . attrs = vt8231_attributes_temps [ 5 ] } ,
} ;
2008-01-06 17:46:02 +03:00
static struct attribute * vt8231_attributes_volts [ 6 ] [ 5 ] = {
2006-09-24 23:21:46 +04:00
{
& sensor_dev_attr_in0_input . dev_attr . attr ,
& sensor_dev_attr_in0_min . dev_attr . attr ,
& sensor_dev_attr_in0_max . dev_attr . attr ,
2008-01-06 17:46:02 +03:00
& sensor_dev_attr_in0_alarm . dev_attr . attr ,
2006-09-24 23:21:46 +04:00
NULL
} , {
& sensor_dev_attr_in1_input . dev_attr . attr ,
& sensor_dev_attr_in1_min . dev_attr . attr ,
& sensor_dev_attr_in1_max . dev_attr . attr ,
2008-01-06 17:46:02 +03:00
& sensor_dev_attr_in1_alarm . dev_attr . attr ,
2006-09-24 23:21:46 +04:00
NULL
} , {
& sensor_dev_attr_in2_input . dev_attr . attr ,
& sensor_dev_attr_in2_min . dev_attr . attr ,
& sensor_dev_attr_in2_max . dev_attr . attr ,
2008-01-06 17:46:02 +03:00
& sensor_dev_attr_in2_alarm . dev_attr . attr ,
2006-09-24 23:21:46 +04:00
NULL
} , {
& sensor_dev_attr_in3_input . dev_attr . attr ,
& sensor_dev_attr_in3_min . dev_attr . attr ,
& sensor_dev_attr_in3_max . dev_attr . attr ,
2008-01-06 17:46:02 +03:00
& sensor_dev_attr_in3_alarm . dev_attr . attr ,
2006-09-24 23:21:46 +04:00
NULL
} , {
& sensor_dev_attr_in4_input . dev_attr . attr ,
& sensor_dev_attr_in4_min . dev_attr . attr ,
& sensor_dev_attr_in4_max . dev_attr . attr ,
2008-01-06 17:46:02 +03:00
& sensor_dev_attr_in4_alarm . dev_attr . attr ,
2006-09-24 23:21:46 +04:00
NULL
} , {
& dev_attr_in5_input . attr ,
& dev_attr_in5_min . attr ,
& dev_attr_in5_max . attr ,
2008-01-06 17:46:02 +03:00
& sensor_dev_attr_in5_alarm . dev_attr . attr ,
2006-09-24 23:21:46 +04:00
NULL
}
} ;
static const struct attribute_group vt8231_group_volts [ 6 ] = {
{ . attrs = vt8231_attributes_volts [ 0 ] } ,
{ . attrs = vt8231_attributes_volts [ 1 ] } ,
{ . attrs = vt8231_attributes_volts [ 2 ] } ,
{ . attrs = vt8231_attributes_volts [ 3 ] } ,
{ . attrs = vt8231_attributes_volts [ 4 ] } ,
{ . attrs = vt8231_attributes_volts [ 5 ] } ,
} ;
static struct attribute * vt8231_attributes [ ] = {
& sensor_dev_attr_fan1_input . dev_attr . attr ,
& sensor_dev_attr_fan2_input . dev_attr . attr ,
& sensor_dev_attr_fan1_min . dev_attr . attr ,
& sensor_dev_attr_fan2_min . dev_attr . attr ,
& sensor_dev_attr_fan1_div . dev_attr . attr ,
& sensor_dev_attr_fan2_div . dev_attr . attr ,
2008-01-06 17:46:02 +03:00
& sensor_dev_attr_fan1_alarm . dev_attr . attr ,
& sensor_dev_attr_fan2_alarm . dev_attr . attr ,
2006-09-24 23:21:46 +04:00
& dev_attr_alarms . attr ,
2007-06-12 23:04:08 +04:00
& dev_attr_name . attr ,
2006-09-24 23:21:46 +04:00
NULL
} ;
static const struct attribute_group vt8231_group = {
. attrs = vt8231_attributes ,
} ;
2007-06-12 23:04:08 +04:00
static struct platform_driver vt8231_driver = {
2005-11-26 22:37:41 +03:00
. driver = {
. name = " vt8231 " ,
} ,
2007-06-12 23:04:08 +04:00
. probe = vt8231_probe ,
2012-11-19 22:21:20 +04:00
. remove = vt8231_remove ,
2005-11-26 22:20:05 +03:00
} ;
2013-12-03 11:10:29 +04:00
static const struct pci_device_id vt8231_pci_ids [ ] = {
2005-11-26 22:20:05 +03:00
{ PCI_DEVICE ( PCI_VENDOR_ID_VIA , PCI_DEVICE_ID_VIA_8231_4 ) } ,
{ 0 , }
} ;
MODULE_DEVICE_TABLE ( pci , vt8231_pci_ids ) ;
2012-11-19 22:22:35 +04:00
static int vt8231_pci_probe ( struct pci_dev * dev ,
2012-01-15 19:03:38 +04:00
const struct pci_device_id * id ) ;
2005-11-26 22:20:05 +03:00
static struct pci_driver vt8231_pci_driver = {
. name = " vt8231 " ,
. id_table = vt8231_pci_ids ,
. probe = vt8231_pci_probe ,
} ;
2007-10-14 23:00:24 +04:00
static int vt8231_probe ( struct platform_device * pdev )
2005-11-26 22:20:05 +03:00
{
2007-06-12 23:04:08 +04:00
struct resource * res ;
2005-11-26 22:20:05 +03:00
struct vt8231_data * data ;
int err = 0 , i ;
/* Reserve the ISA region */
2007-06-12 23:04:08 +04:00
res = platform_get_resource ( pdev , IORESOURCE_IO , 0 ) ;
2012-06-02 22:35:55 +04:00
if ( ! devm_request_region ( & pdev - > dev , res - > start , VT8231_EXTENT ,
vt8231_driver . driver . name ) ) {
2007-06-12 23:04:08 +04:00
dev_err ( & pdev - > dev , " Region 0x%lx-0x%lx already in use! \n " ,
( unsigned long ) res - > start , ( unsigned long ) res - > end ) ;
2005-11-26 22:20:05 +03:00
return - ENODEV ;
}
2012-06-02 22:35:55 +04:00
data = devm_kzalloc ( & pdev - > dev , sizeof ( struct vt8231_data ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
2005-11-26 22:20:05 +03:00
2007-06-12 23:04:08 +04:00
platform_set_drvdata ( pdev , data ) ;
data - > addr = res - > start ;
data - > name = " vt8231 " ;
2005-11-26 22:20:05 +03:00
2006-01-19 01:19:26 +03:00
mutex_init ( & data - > update_lock ) ;
2007-06-12 23:04:08 +04:00
vt8231_init_device ( data ) ;
2005-11-26 22:20:05 +03:00
/* Register sysfs hooks */
2012-01-15 19:03:38 +04:00
err = sysfs_create_group ( & pdev - > dev . kobj , & vt8231_group ) ;
if ( err )
2012-06-02 22:35:55 +04:00
return err ;
2005-11-26 22:20:05 +03:00
/* Must update device information to find out the config field */
2007-06-12 23:04:08 +04:00
data - > uch_config = vt8231_read_value ( data , VT8231_REG_UCH_CONFIG ) ;
2005-11-26 22:20:05 +03:00
2006-09-24 23:21:46 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( vt8231_group_temps ) ; i + + ) {
2005-11-26 22:20:05 +03:00
if ( ISTEMP ( i , data - > uch_config ) ) {
2012-01-15 19:03:38 +04:00
err = sysfs_create_group ( & pdev - > dev . kobj ,
& vt8231_group_temps [ i ] ) ;
if ( err )
2006-09-24 23:21:46 +04:00
goto exit_remove_files ;
2005-11-26 22:20:05 +03:00
}
}
2006-09-24 23:21:46 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( vt8231_group_volts ) ; i + + ) {
2005-11-26 22:20:05 +03:00
if ( ISVOLT ( i , data - > uch_config ) ) {
2012-01-15 19:03:38 +04:00
err = sysfs_create_group ( & pdev - > dev . kobj ,
& vt8231_group_volts [ i ] ) ;
if ( err )
2006-09-24 23:21:46 +04:00
goto exit_remove_files ;
2005-11-26 22:20:05 +03:00
}
}
2007-08-21 00:46:20 +04:00
data - > hwmon_dev = hwmon_device_register ( & pdev - > dev ) ;
if ( IS_ERR ( data - > hwmon_dev ) ) {
err = PTR_ERR ( data - > hwmon_dev ) ;
2006-09-24 23:21:46 +04:00
goto exit_remove_files ;
}
2005-11-26 22:20:05 +03:00
return 0 ;
2006-09-24 23:21:46 +04:00
exit_remove_files :
for ( i = 0 ; i < ARRAY_SIZE ( vt8231_group_volts ) ; i + + )
2007-06-12 23:04:08 +04:00
sysfs_remove_group ( & pdev - > dev . kobj , & vt8231_group_volts [ i ] ) ;
2006-09-24 23:21:46 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( vt8231_group_temps ) ; i + + )
2007-06-12 23:04:08 +04:00
sysfs_remove_group ( & pdev - > dev . kobj , & vt8231_group_temps [ i ] ) ;
sysfs_remove_group ( & pdev - > dev . kobj , & vt8231_group ) ;
2005-11-26 22:20:05 +03:00
return err ;
}
2012-11-19 22:25:51 +04:00
static int vt8231_remove ( struct platform_device * pdev )
2005-11-26 22:20:05 +03:00
{
2007-06-12 23:04:08 +04:00
struct vt8231_data * data = platform_get_drvdata ( pdev ) ;
int i ;
2005-11-26 22:20:05 +03:00
2007-08-21 00:46:20 +04:00
hwmon_device_unregister ( data - > hwmon_dev ) ;
2005-11-26 22:20:05 +03:00
2006-09-24 23:21:46 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( vt8231_group_volts ) ; i + + )
2007-06-12 23:04:08 +04:00
sysfs_remove_group ( & pdev - > dev . kobj , & vt8231_group_volts [ i ] ) ;
2006-09-24 23:21:46 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( vt8231_group_temps ) ; i + + )
2007-06-12 23:04:08 +04:00
sysfs_remove_group ( & pdev - > dev . kobj , & vt8231_group_temps [ i ] ) ;
2006-09-24 23:21:46 +04:00
2007-06-12 23:04:08 +04:00
sysfs_remove_group ( & pdev - > dev . kobj , & vt8231_group ) ;
2006-09-24 23:21:46 +04:00
2005-11-26 22:20:05 +03:00
return 0 ;
}
2007-06-12 23:04:08 +04:00
static void vt8231_init_device ( struct vt8231_data * data )
2005-11-26 22:20:05 +03:00
{
2007-06-12 23:04:08 +04:00
vt8231_write_value ( data , VT8231_REG_TEMP1_CONFIG , 0 ) ;
vt8231_write_value ( data , VT8231_REG_TEMP2_CONFIG , 0 ) ;
2005-11-26 22:20:05 +03:00
}
static struct vt8231_data * vt8231_update_device ( struct device * dev )
{
2007-06-12 23:04:08 +04:00
struct vt8231_data * data = dev_get_drvdata ( dev ) ;
2005-11-26 22:20:05 +03:00
int i ;
u16 low ;
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2005-11-26 22:20:05 +03:00
if ( time_after ( jiffies , data - > last_updated + HZ + HZ / 2 )
| | ! data - > valid ) {
for ( i = 0 ; i < 6 ; i + + ) {
if ( ISVOLT ( i , data - > uch_config ) ) {
2007-06-12 23:04:08 +04:00
data - > in [ i ] = vt8231_read_value ( data ,
2005-11-26 22:20:05 +03:00
regvolt [ i ] ) ;
2007-06-12 23:04:08 +04:00
data - > in_min [ i ] = vt8231_read_value ( data ,
2005-11-26 22:20:05 +03:00
regvoltmin [ i ] ) ;
2007-06-12 23:04:08 +04:00
data - > in_max [ i ] = vt8231_read_value ( data ,
2005-11-26 22:20:05 +03:00
regvoltmax [ i ] ) ;
}
}
for ( i = 0 ; i < 2 ; i + + ) {
2007-06-12 23:04:08 +04:00
data - > fan [ i ] = vt8231_read_value ( data ,
2005-11-26 22:20:05 +03:00
VT8231_REG_FAN ( i ) ) ;
2007-06-12 23:04:08 +04:00
data - > fan_min [ i ] = vt8231_read_value ( data ,
2005-11-26 22:20:05 +03:00
VT8231_REG_FAN_MIN ( i ) ) ;
}
2007-06-12 23:04:08 +04:00
low = vt8231_read_value ( data , VT8231_REG_TEMP_LOW01 ) ;
2005-11-26 22:20:05 +03:00
low = ( low > > 6 ) | ( ( low & 0x30 ) > > 2 )
2007-06-12 23:04:08 +04:00
| ( vt8231_read_value ( data , VT8231_REG_TEMP_LOW25 ) < < 4 ) ;
2005-11-26 22:20:05 +03:00
for ( i = 0 ; i < 6 ; i + + ) {
if ( ISTEMP ( i , data - > uch_config ) ) {
2007-06-12 23:04:08 +04:00
data - > temp [ i ] = ( vt8231_read_value ( data ,
2005-11-26 22:20:05 +03:00
regtemp [ i ] ) < < 2 )
| ( ( low > > ( 2 * i ) ) & 0x03 ) ;
2007-06-12 23:04:08 +04:00
data - > temp_max [ i ] = vt8231_read_value ( data ,
2005-11-26 22:20:05 +03:00
regtempmax [ i ] ) ;
2007-06-12 23:04:08 +04:00
data - > temp_min [ i ] = vt8231_read_value ( data ,
2005-11-26 22:20:05 +03:00
regtempmin [ i ] ) ;
}
}
2007-06-12 23:04:08 +04:00
i = vt8231_read_value ( data , VT8231_REG_FANDIV ) ;
2005-11-26 22:20:05 +03:00
data - > fan_div [ 0 ] = ( i > > 4 ) & 0x03 ;
data - > fan_div [ 1 ] = i > > 6 ;
2007-06-12 23:04:08 +04:00
data - > alarms = vt8231_read_value ( data , VT8231_REG_ALARM1 ) |
( vt8231_read_value ( data , VT8231_REG_ALARM2 ) < < 8 ) ;
2005-11-26 22:20:05 +03:00
/* Set alarm flags correctly */
2012-01-15 19:03:38 +04:00
if ( ! data - > fan [ 0 ] & & data - > fan_min [ 0 ] )
2005-11-26 22:20:05 +03:00
data - > alarms | = 0x40 ;
2012-01-15 19:03:38 +04:00
else if ( data - > fan [ 0 ] & & ! data - > fan_min [ 0 ] )
2005-11-26 22:20:05 +03:00
data - > alarms & = ~ 0x40 ;
2012-01-15 19:03:38 +04:00
if ( ! data - > fan [ 1 ] & & data - > fan_min [ 1 ] )
2005-11-26 22:20:05 +03:00
data - > alarms | = 0x80 ;
2012-01-15 19:03:38 +04:00
else if ( data - > fan [ 1 ] & & ! data - > fan_min [ 1 ] )
2005-11-26 22:20:05 +03:00
data - > alarms & = ~ 0x80 ;
data - > last_updated = jiffies ;
data - > valid = 1 ;
}
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-11-26 22:20:05 +03:00
return data ;
}
2012-11-19 22:22:35 +04:00
static int vt8231_device_add ( unsigned short address )
2007-06-12 23:04:08 +04:00
{
struct resource res = {
. start = address ,
. end = address + VT8231_EXTENT - 1 ,
. name = " vt8231 " ,
. flags = IORESOURCE_IO ,
} ;
int err ;
2009-01-07 18:37:35 +03:00
err = acpi_check_resource_conflict ( & res ) ;
if ( err )
goto exit ;
2007-06-12 23:04:08 +04:00
pdev = platform_device_alloc ( " vt8231 " , address ) ;
if ( ! pdev ) {
err = - ENOMEM ;
2010-10-20 10:51:53 +04:00
pr_err ( " Device allocation failed \n " ) ;
2007-06-12 23:04:08 +04:00
goto exit ;
}
err = platform_device_add_resources ( pdev , & res , 1 ) ;
if ( err ) {
2010-10-20 10:51:53 +04:00
pr_err ( " Device resource addition failed (%d) \n " , err ) ;
2007-06-12 23:04:08 +04:00
goto exit_device_put ;
}
err = platform_device_add ( pdev ) ;
if ( err ) {
2010-10-20 10:51:53 +04:00
pr_err ( " Device addition failed (%d) \n " , err ) ;
2007-06-12 23:04:08 +04:00
goto exit_device_put ;
}
return 0 ;
exit_device_put :
platform_device_put ( pdev ) ;
exit :
return err ;
}
2012-11-19 22:22:35 +04:00
static int vt8231_pci_probe ( struct pci_dev * dev ,
2005-11-26 22:20:05 +03:00
const struct pci_device_id * id )
{
2007-06-12 23:04:08 +04:00
u16 address , val ;
if ( force_addr ) {
address = force_addr & 0xff00 ;
dev_warn ( & dev - > dev , " Forcing ISA address 0x%x \n " ,
address ) ;
if ( PCIBIOS_SUCCESSFUL ! =
pci_write_config_word ( dev , VT8231_BASE_REG , address | 1 ) )
return - ENODEV ;
}
2005-11-26 22:20:05 +03:00
if ( PCIBIOS_SUCCESSFUL ! = pci_read_config_word ( dev , VT8231_BASE_REG ,
& val ) )
return - ENODEV ;
2007-06-12 23:04:08 +04:00
address = val & ~ ( VT8231_EXTENT - 1 ) ;
if ( address = = 0 ) {
2010-03-06 00:43:56 +03:00
dev_err ( & dev - > dev , " base address not set - upgrade BIOS or use force_addr=0xaddr \n " ) ;
2005-11-26 22:20:05 +03:00
return - ENODEV ;
}
2007-06-12 23:04:08 +04:00
if ( PCIBIOS_SUCCESSFUL ! = pci_read_config_word ( dev , VT8231_ENABLE_REG ,
& val ) )
return - ENODEV ;
2005-11-26 22:20:05 +03:00
2007-06-12 23:04:08 +04:00
if ( ! ( val & 0x0001 ) ) {
dev_warn ( & dev - > dev , " enabling sensors \n " ) ;
if ( PCIBIOS_SUCCESSFUL ! =
pci_write_config_word ( dev , VT8231_ENABLE_REG ,
val | 0x0001 ) )
return - ENODEV ;
2005-11-26 22:20:05 +03:00
}
2007-06-12 23:04:08 +04:00
if ( platform_driver_register ( & vt8231_driver ) )
goto exit ;
/* Sets global pdev as a side effect */
if ( vt8231_device_add ( address ) )
goto exit_unregister ;
2012-01-19 23:02:27 +04:00
/*
* Always return failure here . This is to allow other drivers to bind
2005-11-26 22:20:05 +03:00
* 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 .
*/
2007-06-12 23:04:08 +04:00
2012-01-19 23:02:27 +04:00
/*
* We do , however , mark ourselves as using the PCI device to stop it
* getting unloaded .
*/
2007-06-12 23:04:08 +04:00
s_bridge = pci_dev_get ( dev ) ;
return - ENODEV ;
exit_unregister :
platform_driver_unregister ( & vt8231_driver ) ;
exit :
2005-11-26 22:20:05 +03:00
return - ENODEV ;
}
static int __init sm_vt8231_init ( void )
{
2005-11-30 03:00:35 +03:00
return pci_register_driver ( & vt8231_pci_driver ) ;
2005-11-26 22:20:05 +03:00
}
static void __exit sm_vt8231_exit ( void )
{
pci_unregister_driver ( & vt8231_pci_driver ) ;
if ( s_bridge ! = NULL ) {
2007-06-12 23:04:08 +04:00
platform_device_unregister ( pdev ) ;
platform_driver_unregister ( & vt8231_driver ) ;
2005-11-26 22:20:05 +03:00
pci_dev_put ( s_bridge ) ;
s_bridge = NULL ;
}
}
2008-02-13 15:52:06 +03:00
MODULE_AUTHOR ( " Roger Lucas <vt8231@hiddenengine.co.uk> " ) ;
2005-11-26 22:20:05 +03:00
MODULE_DESCRIPTION ( " VT8231 sensors " ) ;
MODULE_LICENSE ( " GPL " ) ;
module_init ( sm_vt8231_init ) ;
module_exit ( sm_vt8231_exit ) ;