2005-04-17 02:20:36 +04:00
/*
2012-01-15 00:45:47 +04:00
* adm1021 . c - Part of lm_sensors , Linux kernel modules for hardware
* monitoring
* Copyright ( c ) 1998 , 1999 Frodo Looijaard < frodol @ dds . nl > and
* Philip Edelbrock < phil @ netroedge . com >
*
* 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-04-17 02:20:36 +04:00
# include <linux/module.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/jiffies.h>
# include <linux/i2c.h>
2005-07-16 05:39:18 +04:00
# include <linux/hwmon.h>
2007-09-09 21:51:14 +04:00
# include <linux/hwmon-sysfs.h>
2005-07-16 05:39:18 +04:00
# include <linux/err.h>
2006-01-19 01:19:26 +03:00
# include <linux/mutex.h>
2005-04-17 02:20:36 +04:00
/* Addresses to scan */
2008-02-18 06:28:03 +03:00
static const unsigned short normal_i2c [ ] = {
0x18 , 0x19 , 0x1a , 0x29 , 0x2a , 0x2b , 0x4c , 0x4d , 0x4e , I2C_CLIENT_END } ;
2005-04-17 02:20:36 +04:00
2009-12-14 23:17:27 +03:00
enum chips {
adm1021 , adm1023 , max1617 , max1617a , thmc10 , lm84 , gl523sm , mc1066 } ;
2005-04-17 02:20:36 +04:00
/* adm1021 constants specified below */
/* The adm1021 registers */
/* Read-only */
2007-09-09 21:51:14 +04:00
/* For nr in 0-1 */
# define ADM1021_REG_TEMP(nr) (nr)
2005-04-17 02:20:36 +04:00
# define ADM1021_REG_STATUS 0x02
2007-07-19 10:00:17 +04:00
/* 0x41 = AD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi */
# define ADM1021_REG_MAN_ID 0xFE
/* ADM1021 = 0x0X, ADM1023 = 0x3X */
# define ADM1021_REG_DEV_ID 0xFF
2005-04-17 02:20:36 +04:00
/* These use different addresses for reading/writing */
# define ADM1021_REG_CONFIG_R 0x03
# define ADM1021_REG_CONFIG_W 0x09
# define ADM1021_REG_CONV_RATE_R 0x04
# define ADM1021_REG_CONV_RATE_W 0x0A
/* These are for the ADM1023's additional precision on the remote temp sensor */
2007-07-19 10:00:17 +04:00
# define ADM1023_REG_REM_TEMP_PREC 0x10
# define ADM1023_REG_REM_OFFSET 0x11
# define ADM1023_REG_REM_OFFSET_PREC 0x12
# define ADM1023_REG_REM_TOS_PREC 0x13
# define ADM1023_REG_REM_THYST_PREC 0x14
2005-04-17 02:20:36 +04:00
/* limits */
2007-09-09 21:51:14 +04:00
/* For nr in 0-1 */
# define ADM1021_REG_TOS_R(nr) (0x05 + 2 * (nr))
# define ADM1021_REG_TOS_W(nr) (0x0B + 2 * (nr))
# define ADM1021_REG_THYST_R(nr) (0x06 + 2 * (nr))
# define ADM1021_REG_THYST_W(nr) (0x0C + 2 * (nr))
2005-04-17 02:20:36 +04:00
/* write-only */
# define ADM1021_REG_ONESHOT 0x0F
/* Initial values */
2012-01-15 00:45:47 +04:00
/*
* Note : Even though I left the low and high limits named os and hyst ,
* they don ' t quite work like a thermostat the way the LM75 does . I . e . ,
* a lower temp than THYST actually triggers an alarm instead of
* clearing it . Weird , ey ? - - Phil
*/
2005-04-17 02:20:36 +04:00
/* Each client has this additional data */
struct adm1021_data {
2014-04-04 20:01:34 +04:00
struct i2c_client * client ;
2005-04-17 02:20:36 +04:00
enum chips type ;
2014-04-04 20:01:34 +04:00
const struct attribute_group * groups [ 3 ] ;
2006-01-19 01:19:26 +03:00
struct mutex update_lock ;
2005-04-17 02:20:36 +04:00
char valid ; /* !=0 if following fields are valid */
2009-09-22 04:04:47 +04:00
char low_power ; /* !=0 if device in low power mode */
2005-04-17 02:20:36 +04:00
unsigned long last_updated ; /* In jiffies */
2009-09-22 04:04:46 +04:00
int temp_max [ 2 ] ; /* Register values */
int temp_min [ 2 ] ;
int temp [ 2 ] ;
2007-09-09 21:51:14 +04:00
u8 alarms ;
/* Special values for ADM1023 only */
u8 remote_temp_offset ;
u8 remote_temp_offset_prec ;
2005-04-17 02:20:36 +04:00
} ;
2008-07-16 21:30:08 +04:00
static int adm1021_probe ( struct i2c_client * client ,
const struct i2c_device_id * id ) ;
2009-12-14 23:17:23 +03:00
static int adm1021_detect ( struct i2c_client * client ,
2008-07-16 21:30:08 +04:00
struct i2c_board_info * info ) ;
2005-04-17 02:20:36 +04:00
static void adm1021_init_client ( struct i2c_client * client ) ;
static struct adm1021_data * adm1021_update_device ( struct device * dev ) ;
/* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */
2012-01-13 03:02:20 +04:00
static bool read_only ;
2005-04-17 02:20:36 +04:00
2008-07-16 21:30:08 +04:00
static const struct i2c_device_id adm1021_id [ ] = {
{ " adm1021 " , adm1021 } ,
{ " adm1023 " , adm1023 } ,
{ " max1617 " , max1617 } ,
{ " max1617a " , max1617a } ,
{ " thmc10 " , thmc10 } ,
{ " lm84 " , lm84 } ,
{ " gl523sm " , gl523sm } ,
{ " mc1066 " , mc1066 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , adm1021_id ) ;
2005-04-17 02:20:36 +04:00
/* This is the driver that will be inserted */
static struct i2c_driver adm1021_driver = {
2008-07-16 21:30:08 +04:00
. class = I2C_CLASS_HWMON ,
2005-11-26 22:37:41 +03:00
. driver = {
. name = " adm1021 " ,
} ,
2008-07-16 21:30:08 +04:00
. probe = adm1021_probe ,
. id_table = adm1021_id ,
. detect = adm1021_detect ,
2009-12-14 23:17:25 +03:00
. address_list = normal_i2c ,
2005-04-17 02:20:36 +04:00
} ;
2007-09-09 21:51:14 +04:00
static ssize_t show_temp ( struct device * dev ,
struct device_attribute * devattr , char * buf )
{
int index = to_sensor_dev_attr ( devattr ) - > index ;
struct adm1021_data * data = adm1021_update_device ( dev ) ;
2009-09-22 04:04:46 +04:00
return sprintf ( buf , " %d \n " , data - > temp [ index ] ) ;
2007-09-09 21:51:14 +04:00
}
static ssize_t show_temp_max ( struct device * dev ,
struct device_attribute * devattr , char * buf )
{
int index = to_sensor_dev_attr ( devattr ) - > index ;
struct adm1021_data * data = adm1021_update_device ( dev ) ;
2009-09-22 04:04:46 +04:00
return sprintf ( buf , " %d \n " , data - > temp_max [ index ] ) ;
2007-09-09 21:51:14 +04:00
}
static ssize_t show_temp_min ( struct device * dev ,
struct device_attribute * devattr , char * buf )
{
int index = to_sensor_dev_attr ( devattr ) - > index ;
struct adm1021_data * data = adm1021_update_device ( dev ) ;
2009-09-22 04:04:46 +04:00
return sprintf ( buf , " %d \n " , data - > temp_min [ index ] ) ;
2005-04-17 02:20:36 +04:00
}
2007-09-09 21:16:03 +04:00
static ssize_t show_alarm ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
int index = to_sensor_dev_attr ( attr ) - > index ;
struct adm1021_data * data = adm1021_update_device ( dev ) ;
return sprintf ( buf , " %u \n " , ( data - > alarms > > index ) & 1 ) ;
}
2007-07-19 10:00:17 +04:00
static ssize_t show_alarms ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct adm1021_data * data = adm1021_update_device ( dev ) ;
return sprintf ( buf , " %u \n " , data - > alarms ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 10:00:17 +04:00
2007-09-09 21:51:14 +04:00
static ssize_t set_temp_max ( struct device * dev ,
struct device_attribute * devattr ,
const char * buf , size_t count )
{
int index = to_sensor_dev_attr ( devattr ) - > index ;
2014-04-04 20:01:34 +04:00
struct adm1021_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2012-01-15 00:45:47 +04:00
long temp ;
2014-07-03 18:45:45 +04:00
int reg_val , err ;
2012-01-15 00:45:47 +04:00
err = kstrtol ( buf , 10 , & temp ) ;
if ( err )
return err ;
temp / = 1000 ;
2007-09-09 21:51:14 +04:00
mutex_lock ( & data - > update_lock ) ;
2014-07-03 18:45:45 +04:00
reg_val = clamp_val ( temp , - 128 , 127 ) ;
data - > temp_max [ index ] = reg_val * 1000 ;
2007-09-09 21:51:14 +04:00
if ( ! read_only )
i2c_smbus_write_byte_data ( client , ADM1021_REG_TOS_W ( index ) ,
2014-07-03 18:45:45 +04:00
reg_val ) ;
2007-09-09 21:51:14 +04:00
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
static ssize_t set_temp_min ( struct device * dev ,
struct device_attribute * devattr ,
const char * buf , size_t count )
{
int index = to_sensor_dev_attr ( devattr ) - > index ;
2014-04-04 20:01:34 +04:00
struct adm1021_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2012-01-15 00:45:47 +04:00
long temp ;
2014-07-03 18:45:45 +04:00
int reg_val , err ;
2012-01-15 00:45:47 +04:00
err = kstrtol ( buf , 10 , & temp ) ;
if ( err )
return err ;
temp / = 1000 ;
2007-09-09 21:51:14 +04:00
mutex_lock ( & data - > update_lock ) ;
2014-07-03 18:45:45 +04:00
reg_val = clamp_val ( temp , - 128 , 127 ) ;
data - > temp_min [ index ] = reg_val * 1000 ;
2007-09-09 21:51:14 +04:00
if ( ! read_only )
i2c_smbus_write_byte_data ( client , ADM1021_REG_THYST_W ( index ) ,
2014-07-03 18:45:45 +04:00
reg_val ) ;
2007-09-09 21:51:14 +04:00
mutex_unlock ( & data - > update_lock ) ;
return count ;
2005-04-17 02:20:36 +04:00
}
2009-09-22 04:04:47 +04:00
static ssize_t show_low_power ( struct device * dev ,
struct device_attribute * devattr , char * buf )
{
struct adm1021_data * data = adm1021_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , data - > low_power ) ;
}
static ssize_t set_low_power ( struct device * dev ,
struct device_attribute * devattr ,
const char * buf , size_t count )
{
2014-04-04 20:01:34 +04:00
struct adm1021_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2012-01-15 00:45:47 +04:00
char low_power ;
unsigned long val ;
int err ;
err = kstrtoul ( buf , 10 , & val ) ;
if ( err )
return err ;
low_power = val ! = 0 ;
2009-09-22 04:04:47 +04:00
mutex_lock ( & data - > update_lock ) ;
if ( low_power ! = data - > low_power ) {
int config = i2c_smbus_read_byte_data (
client , ADM1021_REG_CONFIG_R ) ;
data - > low_power = low_power ;
i2c_smbus_write_byte_data ( client , ADM1021_REG_CONFIG_W ,
( config & 0xBF ) | ( low_power < < 6 ) ) ;
}
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
2007-09-09 21:51:14 +04:00
static SENSOR_DEVICE_ATTR ( temp1_input , S_IRUGO , show_temp , NULL , 0 ) ;
static SENSOR_DEVICE_ATTR ( temp1_max , S_IWUSR | S_IRUGO , show_temp_max ,
set_temp_max , 0 ) ;
static SENSOR_DEVICE_ATTR ( temp1_min , S_IWUSR | S_IRUGO , show_temp_min ,
set_temp_min , 0 ) ;
static SENSOR_DEVICE_ATTR ( temp2_input , S_IRUGO , show_temp , NULL , 1 ) ;
static SENSOR_DEVICE_ATTR ( temp2_max , S_IWUSR | S_IRUGO , show_temp_max ,
set_temp_max , 1 ) ;
static SENSOR_DEVICE_ATTR ( temp2_min , S_IWUSR | S_IRUGO , show_temp_min ,
set_temp_min , 1 ) ;
2007-09-09 21:16:03 +04:00
static SENSOR_DEVICE_ATTR ( temp1_max_alarm , S_IRUGO , show_alarm , NULL , 6 ) ;
static SENSOR_DEVICE_ATTR ( temp1_min_alarm , S_IRUGO , show_alarm , NULL , 5 ) ;
static SENSOR_DEVICE_ATTR ( temp2_max_alarm , S_IRUGO , show_alarm , NULL , 4 ) ;
static SENSOR_DEVICE_ATTR ( temp2_min_alarm , S_IRUGO , show_alarm , NULL , 3 ) ;
static SENSOR_DEVICE_ATTR ( temp2_fault , S_IRUGO , show_alarm , NULL , 2 ) ;
2007-09-09 21:51:14 +04:00
static DEVICE_ATTR ( alarms , S_IRUGO , show_alarms , NULL ) ;
2009-09-22 04:04:47 +04:00
static DEVICE_ATTR ( low_power , S_IWUSR | S_IRUGO , show_low_power , set_low_power ) ;
2005-04-17 02:20:36 +04:00
2006-09-24 23:15:35 +04:00
static struct attribute * adm1021_attributes [ ] = {
2007-09-09 21:51:14 +04:00
& sensor_dev_attr_temp1_max . dev_attr . attr ,
& sensor_dev_attr_temp1_input . dev_attr . attr ,
& sensor_dev_attr_temp2_max . dev_attr . attr ,
& sensor_dev_attr_temp2_input . dev_attr . attr ,
2007-09-09 21:16:03 +04:00
& sensor_dev_attr_temp1_max_alarm . dev_attr . attr ,
& sensor_dev_attr_temp2_max_alarm . dev_attr . attr ,
& sensor_dev_attr_temp2_fault . dev_attr . attr ,
2006-09-24 23:15:35 +04:00
& dev_attr_alarms . attr ,
2009-09-22 04:04:47 +04:00
& dev_attr_low_power . attr ,
2006-09-24 23:15:35 +04:00
NULL
} ;
static const struct attribute_group adm1021_group = {
. attrs = adm1021_attributes ,
} ;
2013-06-06 21:30:10 +04:00
static struct attribute * adm1021_min_attributes [ ] = {
& sensor_dev_attr_temp1_min . dev_attr . attr ,
& sensor_dev_attr_temp2_min . dev_attr . attr ,
& sensor_dev_attr_temp1_min_alarm . dev_attr . attr ,
& sensor_dev_attr_temp2_min_alarm . dev_attr . attr ,
NULL
} ;
static const struct attribute_group adm1021_min_group = {
. attrs = adm1021_min_attributes ,
} ;
2008-07-16 21:30:08 +04:00
/* Return 0 if detection is successful, -ENODEV otherwise */
2009-12-14 23:17:23 +03:00
static int adm1021_detect ( struct i2c_client * client ,
2008-07-16 21:30:08 +04:00
struct i2c_board_info * info )
2005-04-17 02:20:36 +04:00
{
2008-07-16 21:30:08 +04:00
struct i2c_adapter * adapter = client - > adapter ;
2009-12-09 22:35:51 +03:00
const char * type_name ;
int conv_rate , status , config , man_id , dev_id ;
2005-04-17 02:20:36 +04:00
2007-07-19 10:00:17 +04:00
if ( ! i2c_check_functionality ( adapter , I2C_FUNC_SMBUS_BYTE_DATA ) ) {
2013-01-10 22:01:24 +04:00
pr_debug ( " detect failed, smbus byte data not supported! \n " ) ;
2008-07-16 21:30:08 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 10:00:17 +04:00
status = i2c_smbus_read_byte_data ( client , ADM1021_REG_STATUS ) ;
conv_rate = i2c_smbus_read_byte_data ( client ,
ADM1021_REG_CONV_RATE_R ) ;
config = i2c_smbus_read_byte_data ( client , ADM1021_REG_CONFIG_R ) ;
2005-04-17 02:20:36 +04:00
2009-12-09 22:35:51 +03:00
/* Check unused bits */
if ( ( status & 0x03 ) | | ( config & 0x3F ) | | ( conv_rate & 0xF8 ) ) {
2013-01-10 22:01:24 +04:00
pr_debug ( " detect failed, chip not detected! \n " ) ;
2009-12-09 22:35:51 +03:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
/* Determine the chip type. */
2009-12-09 22:35:51 +03:00
man_id = i2c_smbus_read_byte_data ( client , ADM1021_REG_MAN_ID ) ;
dev_id = i2c_smbus_read_byte_data ( client , ADM1021_REG_DEV_ID ) ;
2005-04-17 02:20:36 +04:00
2013-06-06 01:09:30 +04:00
if ( man_id < 0 | | dev_id < 0 )
return - ENODEV ;
2009-12-09 22:35:51 +03:00
if ( man_id = = 0x4d & & dev_id = = 0x01 )
2005-04-17 02:20:36 +04:00
type_name = " max1617a " ;
2009-12-09 22:35:51 +03:00
else if ( man_id = = 0x41 ) {
if ( ( dev_id & 0xF0 ) = = 0x30 )
type_name = " adm1023 " ;
2013-06-06 01:09:30 +04:00
else if ( ( dev_id & 0xF0 ) = = 0x00 )
2009-12-09 22:35:51 +03:00
type_name = " adm1021 " ;
2013-06-06 01:09:30 +04:00
else
return - ENODEV ;
2009-12-09 22:35:51 +03:00
} else if ( man_id = = 0x49 )
2005-04-17 02:20:36 +04:00
type_name = " thmc10 " ;
2009-12-09 22:35:51 +03:00
else if ( man_id = = 0x23 )
2005-04-17 02:20:36 +04:00
type_name = " gl523sm " ;
2009-12-09 22:35:51 +03:00
else if ( man_id = = 0x54 )
2005-04-17 02:20:36 +04:00
type_name = " mc1066 " ;
2013-06-06 01:09:30 +04:00
else {
int lte , rte , lhi , rhi , llo , rlo ;
/* extra checks for LM84 and MAX1617 to avoid misdetections */
llo = i2c_smbus_read_byte_data ( client , ADM1021_REG_THYST_R ( 0 ) ) ;
rlo = i2c_smbus_read_byte_data ( client , ADM1021_REG_THYST_R ( 1 ) ) ;
/* fail if any of the additional register reads failed */
if ( llo < 0 | | rlo < 0 )
return - ENODEV ;
lte = i2c_smbus_read_byte_data ( client , ADM1021_REG_TEMP ( 0 ) ) ;
rte = i2c_smbus_read_byte_data ( client , ADM1021_REG_TEMP ( 1 ) ) ;
lhi = i2c_smbus_read_byte_data ( client , ADM1021_REG_TOS_R ( 0 ) ) ;
rhi = i2c_smbus_read_byte_data ( client , ADM1021_REG_TOS_R ( 1 ) ) ;
/*
* Fail for negative temperatures and negative high limits .
* This check also catches read errors on the tested registers .
*/
if ( ( s8 ) lte < 0 | | ( s8 ) rte < 0 | | ( s8 ) lhi < 0 | | ( s8 ) rhi < 0 )
return - ENODEV ;
/* fail if all registers hold the same value */
if ( lte = = rte & & lte = = lhi & & lte = = rhi & & lte = = llo
& & lte = = rlo )
return - ENODEV ;
/*
* LM84 Mfr ID is in a different place ,
* and it has more unused bits .
*/
if ( conv_rate = = 0x00
& & ( config & 0x7F ) = = 0x00
& & ( status & 0xAB ) = = 0x00 ) {
type_name = " lm84 " ;
} else {
/* fail if low limits are larger than high limits */
if ( ( s8 ) llo > lhi | | ( s8 ) rlo > rhi )
return - ENODEV ;
type_name = " max1617 " ;
}
}
2009-12-09 22:35:51 +03:00
2013-01-10 22:01:24 +04:00
pr_debug ( " Detected chip %s at adapter %d, address 0x%02x. \n " ,
2008-07-16 21:30:08 +04:00
type_name , i2c_adapter_id ( adapter ) , client - > addr ) ;
strlcpy ( info - > type , type_name , I2C_NAME_SIZE ) ;
2005-04-17 02:20:36 +04:00
2008-07-16 21:30:08 +04:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
2008-07-16 21:30:08 +04:00
static int adm1021_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
2014-04-04 20:01:34 +04:00
struct device * dev = & client - > dev ;
2008-07-16 21:30:08 +04:00
struct adm1021_data * data ;
2014-04-04 20:01:34 +04:00
struct device * hwmon_dev ;
2008-07-16 21:30:08 +04:00
2014-04-04 20:01:34 +04:00
data = devm_kzalloc ( dev , sizeof ( struct adm1021_data ) , GFP_KERNEL ) ;
2013-01-10 22:01:24 +04:00
if ( ! data )
2012-06-02 20:57:58 +04:00
return - ENOMEM ;
2008-07-16 21:30:08 +04:00
2014-04-04 20:01:34 +04:00
data - > client = client ;
2008-07-16 21:30:08 +04:00
data - > type = id - > driver_data ;
mutex_init ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
/* Initialize the ADM1021 chip */
2008-07-16 21:30:08 +04:00
if ( data - > type ! = lm84 & & ! read_only )
2007-07-19 10:00:17 +04:00
adm1021_init_client ( client ) ;
2005-04-17 02:20:36 +04:00
2014-04-04 20:01:34 +04:00
data - > groups [ 0 ] = & adm1021_group ;
if ( data - > type ! = lm84 )
data - > groups [ 1 ] = & adm1021_min_group ;
2013-06-06 21:30:10 +04:00
2014-04-04 20:01:34 +04:00
hwmon_dev = devm_hwmon_device_register_with_groups ( dev , client - > name ,
data , data - > groups ) ;
2005-07-16 05:39:18 +04:00
2014-04-04 20:01:34 +04:00
return PTR_ERR_OR_ZERO ( hwmon_dev ) ;
2005-04-17 02:20:36 +04:00
}
static void adm1021_init_client ( struct i2c_client * client )
{
/* Enable ADC and disable suspend mode */
2007-07-19 10:00:17 +04:00
i2c_smbus_write_byte_data ( client , ADM1021_REG_CONFIG_W ,
i2c_smbus_read_byte_data ( client , ADM1021_REG_CONFIG_R ) & 0xBF ) ;
2005-04-17 02:20:36 +04:00
/* Set Conversion rate to 1/sec (this can be tinkered with) */
2007-07-19 10:00:17 +04:00
i2c_smbus_write_byte_data ( client , ADM1021_REG_CONV_RATE_W , 0x04 ) ;
2005-04-17 02:20:36 +04:00
}
static struct adm1021_data * adm1021_update_device ( struct device * dev )
{
2014-04-04 20:01:34 +04:00
struct adm1021_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2005-04-17 02:20:36 +04:00
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
if ( time_after ( jiffies , data - > last_updated + HZ + HZ / 2 )
| | ! data - > valid ) {
2007-09-09 21:51:14 +04:00
int i ;
2014-04-04 20:01:34 +04:00
dev_dbg ( dev , " Starting adm1021 update \n " ) ;
2005-04-17 02:20:36 +04:00
2007-09-09 21:51:14 +04:00
for ( i = 0 ; i < 2 ; i + + ) {
2009-09-22 04:04:46 +04:00
data - > temp [ i ] = 1000 *
( s8 ) i2c_smbus_read_byte_data (
client , ADM1021_REG_TEMP ( i ) ) ;
data - > temp_max [ i ] = 1000 *
( s8 ) i2c_smbus_read_byte_data (
client , ADM1021_REG_TOS_R ( i ) ) ;
2013-06-06 21:30:10 +04:00
if ( data - > type ! = lm84 ) {
data - > temp_min [ i ] = 1000 *
( s8 ) i2c_smbus_read_byte_data ( client ,
ADM1021_REG_THYST_R ( i ) ) ;
}
2007-09-09 21:51:14 +04:00
}
2007-07-19 10:00:17 +04:00
data - > alarms = i2c_smbus_read_byte_data ( client ,
ADM1021_REG_STATUS ) & 0x7c ;
2005-04-17 02:20:36 +04:00
if ( data - > type = = adm1023 ) {
2012-01-15 00:45:47 +04:00
/*
* The ADM1023 provides 3 extra bits of precision for
* the remote sensor in extra registers .
*/
2009-09-22 04:04:46 +04:00
data - > temp [ 1 ] + = 125 * ( i2c_smbus_read_byte_data (
client , ADM1023_REG_REM_TEMP_PREC ) > > 5 ) ;
data - > temp_max [ 1 ] + = 125 * ( i2c_smbus_read_byte_data (
client , ADM1023_REG_REM_TOS_PREC ) > > 5 ) ;
data - > temp_min [ 1 ] + = 125 * ( i2c_smbus_read_byte_data (
client , ADM1023_REG_REM_THYST_PREC ) > > 5 ) ;
2007-07-19 10:00:17 +04:00
data - > remote_temp_offset =
i2c_smbus_read_byte_data ( client ,
ADM1023_REG_REM_OFFSET ) ;
data - > remote_temp_offset_prec =
i2c_smbus_read_byte_data ( client ,
ADM1023_REG_REM_OFFSET_PREC ) ;
2005-04-17 02:20:36 +04:00
}
data - > last_updated = jiffies ;
data - > valid = 1 ;
}
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
return data ;
}
2012-01-20 11:38:18 +04:00
module_i2c_driver ( adm1021_driver ) ;
2005-04-17 02:20:36 +04:00
2012-01-15 00:45:47 +04:00
MODULE_AUTHOR ( " Frodo Looijaard <frodol@dds.nl> and "
2005-04-17 02:20:36 +04:00
" Philip Edelbrock <phil@netroedge.com> " ) ;
MODULE_DESCRIPTION ( " adm1021 driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
module_param ( read_only , bool , 0 ) ;
MODULE_PARM_DESC ( read_only , " Don't set any values, read only mode " ) ;