2005-04-17 02:20:36 +04:00
/*
2012-01-19 23:02:14 +04:00
* adm1031 . c - Part of lm_sensors , Linux kernel modules for hardware
* monitoring
* Based on lm75 . c and lm85 . c
* Supports adm1030 / adm1031
* Copyright ( C ) 2004 Alexandre d ' Alton < alex @ alexdalton . org >
2014-01-29 23:40:08 +04:00
* Reworked by Jean Delvare < jdelvare @ suse . de >
2012-01-19 23:02:14 +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 .
*
* 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-12-03 01:39:38 +03: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
/* Following macros takes channel parameter starting from 0 to 2 */
# define ADM1031_REG_FAN_SPEED(nr) (0x08 + (nr))
2007-12-03 01:33:57 +03:00
# define ADM1031_REG_FAN_DIV(nr) (0x20 + (nr))
2005-04-17 02:20:36 +04:00
# define ADM1031_REG_PWM (0x22)
# define ADM1031_REG_FAN_MIN(nr) (0x10 + (nr))
2010-05-27 21:58:46 +04:00
# define ADM1031_REG_FAN_FILTER (0x23)
2005-04-17 02:20:36 +04:00
2009-09-24 00:59:41 +04:00
# define ADM1031_REG_TEMP_OFFSET(nr) (0x0d + (nr))
2007-12-03 01:33:57 +03:00
# define ADM1031_REG_TEMP_MAX(nr) (0x14 + 4 * (nr))
# define ADM1031_REG_TEMP_MIN(nr) (0x15 + 4 * (nr))
# define ADM1031_REG_TEMP_CRIT(nr) (0x16 + 4 * (nr))
2005-04-17 02:20:36 +04:00
2007-12-03 01:33:57 +03:00
# define ADM1031_REG_TEMP(nr) (0x0a + (nr))
2005-04-17 02:20:36 +04:00
# define ADM1031_REG_AUTO_TEMP(nr) (0x24 + (nr))
# define ADM1031_REG_STATUS(nr) (0x2 + (nr))
2007-12-03 01:33:57 +03:00
# define ADM1031_REG_CONF1 0x00
# define ADM1031_REG_CONF2 0x01
# define ADM1031_REG_EXT_TEMP 0x06
2005-04-17 02:20:36 +04:00
# define ADM1031_CONF1_MONITOR_ENABLE 0x01 /* Monitoring enable */
# define ADM1031_CONF1_PWM_INVERT 0x08 /* PWM Invert */
# define ADM1031_CONF1_AUTO_MODE 0x80 /* Auto FAN */
# define ADM1031_CONF2_PWM1_ENABLE 0x01
# define ADM1031_CONF2_PWM2_ENABLE 0x02
# define ADM1031_CONF2_TACH1_ENABLE 0x04
# define ADM1031_CONF2_TACH2_ENABLE 0x08
# define ADM1031_CONF2_TEMP_ENABLE(chan) (0x10 << (chan))
2010-05-27 21:58:46 +04:00
# define ADM1031_UPDATE_RATE_MASK 0x1c
# define ADM1031_UPDATE_RATE_SHIFT 2
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 [ ] = { 0x2c , 0x2d , 0x2e , I2C_CLIENT_END } ;
2005-04-17 02:20:36 +04:00
2009-12-14 23:17:27 +03:00
enum chips { adm1030 , adm1031 } ;
2005-04-17 02:20:36 +04:00
typedef u8 auto_chan_table_t [ 8 ] [ 2 ] ;
/* Each client has this additional data */
struct adm1031_data {
2014-07-03 17:57:44 +04:00
struct i2c_client * client ;
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
int chip_type ;
char valid ; /* !=0 if following fields are valid */
unsigned long last_updated ; /* In jiffies */
2010-09-17 19:24:14 +04:00
unsigned int update_interval ; /* In milliseconds */
2012-01-19 23:02:14 +04:00
/*
* The chan_select_table contains the possible configurations for
2005-04-17 02:20:36 +04:00
* auto fan control .
*/
2007-12-03 01:33:57 +03:00
const auto_chan_table_t * chan_select_table ;
2005-04-17 02:20:36 +04:00
u16 alarm ;
u8 conf1 ;
u8 conf2 ;
u8 fan [ 2 ] ;
u8 fan_div [ 2 ] ;
u8 fan_min [ 2 ] ;
u8 pwm [ 2 ] ;
u8 old_pwm [ 2 ] ;
s8 temp [ 3 ] ;
u8 ext_temp [ 3 ] ;
u8 auto_temp [ 3 ] ;
u8 auto_temp_min [ 3 ] ;
u8 auto_temp_off [ 3 ] ;
u8 auto_temp_max [ 3 ] ;
2009-09-24 00:59:41 +04:00
s8 temp_offset [ 3 ] ;
2005-04-17 02:20:36 +04:00
s8 temp_min [ 3 ] ;
s8 temp_max [ 3 ] ;
s8 temp_crit [ 3 ] ;
} ;
static inline u8 adm1031_read_value ( struct i2c_client * client , u8 reg )
{
return i2c_smbus_read_byte_data ( client , reg ) ;
}
static inline int
adm1031_write_value ( struct i2c_client * client , u8 reg , unsigned int value )
{
return i2c_smbus_write_byte_data ( client , reg , value ) ;
}
2014-07-03 17:56:33 +04:00
static struct adm1031_data * adm1031_update_device ( struct device * dev )
{
2014-07-03 17:57:44 +04:00
struct adm1031_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2014-07-03 17:56:33 +04:00
unsigned long next_update ;
int chan ;
mutex_lock ( & data - > update_lock ) ;
next_update = data - > last_updated
+ msecs_to_jiffies ( data - > update_interval ) ;
if ( time_after ( jiffies , next_update ) | | ! data - > valid ) {
dev_dbg ( & client - > dev , " Starting adm1031 update \n " ) ;
for ( chan = 0 ;
chan < ( ( data - > chip_type = = adm1031 ) ? 3 : 2 ) ; chan + + ) {
u8 oldh , newh ;
oldh =
adm1031_read_value ( client , ADM1031_REG_TEMP ( chan ) ) ;
data - > ext_temp [ chan ] =
adm1031_read_value ( client , ADM1031_REG_EXT_TEMP ) ;
newh =
adm1031_read_value ( client , ADM1031_REG_TEMP ( chan ) ) ;
if ( newh ! = oldh ) {
data - > ext_temp [ chan ] =
adm1031_read_value ( client ,
ADM1031_REG_EXT_TEMP ) ;
# ifdef DEBUG
oldh =
adm1031_read_value ( client ,
ADM1031_REG_TEMP ( chan ) ) ;
/* oldh is actually newer */
if ( newh ! = oldh )
dev_warn ( & client - > dev ,
" Remote temperature may be wrong. \n " ) ;
# endif
}
data - > temp [ chan ] = newh ;
data - > temp_offset [ chan ] =
adm1031_read_value ( client ,
ADM1031_REG_TEMP_OFFSET ( chan ) ) ;
data - > temp_min [ chan ] =
adm1031_read_value ( client ,
ADM1031_REG_TEMP_MIN ( chan ) ) ;
data - > temp_max [ chan ] =
adm1031_read_value ( client ,
ADM1031_REG_TEMP_MAX ( chan ) ) ;
data - > temp_crit [ chan ] =
adm1031_read_value ( client ,
ADM1031_REG_TEMP_CRIT ( chan ) ) ;
data - > auto_temp [ chan ] =
adm1031_read_value ( client ,
ADM1031_REG_AUTO_TEMP ( chan ) ) ;
}
data - > conf1 = adm1031_read_value ( client , ADM1031_REG_CONF1 ) ;
data - > conf2 = adm1031_read_value ( client , ADM1031_REG_CONF2 ) ;
data - > alarm = adm1031_read_value ( client , ADM1031_REG_STATUS ( 0 ) )
| ( adm1031_read_value ( client , ADM1031_REG_STATUS ( 1 ) ) < < 8 ) ;
if ( data - > chip_type = = adm1030 )
data - > alarm & = 0xc0ff ;
for ( chan = 0 ; chan < ( data - > chip_type = = adm1030 ? 1 : 2 ) ;
chan + + ) {
data - > fan_div [ chan ] =
adm1031_read_value ( client ,
ADM1031_REG_FAN_DIV ( chan ) ) ;
data - > fan_min [ chan ] =
adm1031_read_value ( client ,
ADM1031_REG_FAN_MIN ( chan ) ) ;
data - > fan [ chan ] =
adm1031_read_value ( client ,
ADM1031_REG_FAN_SPEED ( chan ) ) ;
data - > pwm [ chan ] =
( adm1031_read_value ( client ,
ADM1031_REG_PWM ) > > ( 4 * chan ) ) & 0x0f ;
}
data - > last_updated = jiffies ;
data - > valid = 1 ;
}
mutex_unlock ( & data - > update_lock ) ;
return data ;
}
2005-04-17 02:20:36 +04:00
# define TEMP_TO_REG(val) (((val) < 0 ? ((val - 500) / 1000) : \
( ( val + 500 ) / 1000 ) ) )
# define TEMP_FROM_REG(val) ((val) * 1000)
# define TEMP_FROM_REG_EXT(val, ext) (TEMP_FROM_REG(val) + (ext) * 125)
2009-09-24 00:59:41 +04:00
# define TEMP_OFFSET_TO_REG(val) (TEMP_TO_REG(val) & 0x8f)
# define TEMP_OFFSET_FROM_REG(val) TEMP_FROM_REG((val) < 0 ? \
( val ) | 0x70 : ( val ) )
2012-01-17 01:51:48 +04:00
# define FAN_FROM_REG(reg, div) ((reg) ? \
( 11250 * 60 ) / ( ( reg ) * ( div ) ) : 0 )
2005-04-17 02:20:36 +04:00
static int FAN_TO_REG ( int reg , int div )
{
int tmp ;
2013-01-09 20:09:34 +04:00
tmp = FAN_FROM_REG ( clamp_val ( reg , 0 , 65535 ) , div ) ;
2005-04-17 02:20:36 +04:00
return tmp > 255 ? 255 : tmp ;
}
# define FAN_DIV_FROM_REG(reg) (1<<(((reg)&0xc0)>>6))
2013-01-09 20:09:34 +04:00
# define PWM_TO_REG(val) (clamp_val((val), 0, 255) >> 4)
2005-04-17 02:20:36 +04:00
# define PWM_FROM_REG(val) ((val) << 4)
# define FAN_CHAN_FROM_REG(reg) (((reg) >> 5) & 7)
# define FAN_CHAN_TO_REG(val, reg) \
( ( ( reg ) & 0x1F ) | ( ( ( val ) < < 5 ) & 0xe0 ) )
# define AUTO_TEMP_MIN_TO_REG(val, reg) \
2012-01-17 01:51:48 +04:00
( ( ( ( val ) / 500 ) & 0xf8 ) | ( ( reg ) & 0x7 ) )
# define AUTO_TEMP_RANGE_FROM_REG(reg) (5000 * (1 << ((reg) & 0x7)))
2005-04-17 02:20:36 +04:00
# define AUTO_TEMP_MIN_FROM_REG(reg) (1000 * ((((reg) >> 3) & 0x1f) << 2))
# define AUTO_TEMP_MIN_FROM_REG_DEG(reg) ((((reg) >> 3) & 0x1f) << 2)
# define AUTO_TEMP_OFF_FROM_REG(reg) \
( AUTO_TEMP_MIN_FROM_REG ( reg ) - 5000 )
# define AUTO_TEMP_MAX_FROM_REG(reg) \
( AUTO_TEMP_RANGE_FROM_REG ( reg ) + \
AUTO_TEMP_MIN_FROM_REG ( reg ) )
static int AUTO_TEMP_MAX_TO_REG ( int val , int reg , int pwm )
{
int ret ;
int range = val - AUTO_TEMP_MIN_FROM_REG ( reg ) ;
range = ( ( val - AUTO_TEMP_MIN_FROM_REG ( reg ) ) * 10 ) / ( 16 - pwm ) ;
ret = ( ( reg & 0xf8 ) |
( range < 10000 ? 0 :
range < 20000 ? 1 :
range < 40000 ? 2 : range < 80000 ? 3 : 4 ) ) ;
return ret ;
}
/* FAN auto control */
# define GET_FAN_AUTO_BITFIELD(data, idx) \
2012-01-17 01:51:48 +04:00
( * ( data ) - > chan_select_table ) [ FAN_CHAN_FROM_REG ( ( data ) - > conf1 ) ] [ idx % 2 ]
2005-04-17 02:20:36 +04:00
2012-01-19 23:02:14 +04:00
/*
* The tables below contains the possible values for the auto fan
2005-04-17 02:20:36 +04:00
* control bitfields . the index in the table is the register value .
* MSb is the auto fan control enable bit , so the four first entries
* in the table disables auto fan control when both bitfields are zero .
*/
2007-12-03 01:33:57 +03:00
static const auto_chan_table_t auto_channel_select_table_adm1031 = {
{ 0 , 0 } , { 0 , 0 } , { 0 , 0 } , { 0 , 0 } ,
{ 2 /* 0b010 */ , 4 /* 0b100 */ } ,
{ 2 /* 0b010 */ , 2 /* 0b010 */ } ,
{ 4 /* 0b100 */ , 4 /* 0b100 */ } ,
{ 7 /* 0b111 */ , 7 /* 0b111 */ } ,
2005-04-17 02:20:36 +04:00
} ;
2007-12-03 01:33:57 +03:00
static const auto_chan_table_t auto_channel_select_table_adm1030 = {
{ 0 , 0 } , { 0 , 0 } , { 0 , 0 } , { 0 , 0 } ,
{ 2 /* 0b10 */ , 0 } ,
{ 0xff /* invalid */ , 0 } ,
{ 0xff /* invalid */ , 0 } ,
{ 3 /* 0b11 */ , 0 } ,
2005-04-17 02:20:36 +04:00
} ;
2012-01-19 23:02:14 +04:00
/*
* That function checks if a bitfield is valid and returns the other bitfield
2005-04-17 02:20:36 +04:00
* nearest match if no exact match where found .
*/
static int
2012-03-24 19:51:05 +04:00
get_fan_auto_nearest ( struct adm1031_data * data , int chan , u8 val , u8 reg )
2005-04-17 02:20:36 +04:00
{
int i ;
int first_match = - 1 , exact_match = - 1 ;
u8 other_reg_val =
( * data - > chan_select_table ) [ FAN_CHAN_FROM_REG ( reg ) ] [ chan ? 0 : 1 ] ;
2012-03-24 19:51:05 +04:00
if ( val = = 0 )
2005-04-17 02:20:36 +04:00
return 0 ;
for ( i = 0 ; i < 8 ; i + + ) {
if ( ( val = = ( * data - > chan_select_table ) [ i ] [ chan ] ) & &
( ( * data - > chan_select_table ) [ i ] [ chan ? 0 : 1 ] = =
other_reg_val ) ) {
/* We found an exact match */
exact_match = i ;
break ;
} else if ( val = = ( * data - > chan_select_table ) [ i ] [ chan ] & &
first_match = = - 1 ) {
2012-01-19 23:02:14 +04:00
/*
* Save the first match in case of an exact match has
2007-12-03 01:33:57 +03:00
* not been found
2005-04-17 02:20:36 +04:00
*/
first_match = i ;
}
}
2012-01-17 01:51:48 +04:00
if ( exact_match > = 0 )
2012-03-24 19:51:05 +04:00
return exact_match ;
2012-01-17 01:51:48 +04:00
else if ( first_match > = 0 )
2012-03-24 19:51:05 +04:00
return first_match ;
2012-01-17 01:51:48 +04:00
2012-03-24 19:51:05 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
2007-12-03 01:39:38 +03:00
static ssize_t show_fan_auto_channel ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-12-03 01:39:38 +03:00
int nr = to_sensor_dev_attr ( attr ) - > index ;
2005-04-17 02:20:36 +04:00
struct adm1031_data * data = adm1031_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , GET_FAN_AUTO_BITFIELD ( data , nr ) ) ;
}
static ssize_t
2007-12-03 01:39:38 +03:00
set_fan_auto_channel ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2014-07-03 17:57:44 +04:00
struct adm1031_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2007-12-03 01:39:38 +03:00
int nr = to_sensor_dev_attr ( attr ) - > index ;
2012-01-17 01:51:48 +04:00
long val ;
2005-04-17 02:20:36 +04:00
u8 reg ;
int ret ;
u8 old_fan_mode ;
2012-01-17 01:51:48 +04:00
ret = kstrtol ( buf , 10 , & val ) ;
if ( ret )
return ret ;
2005-04-17 02:20:36 +04:00
old_fan_mode = data - > conf1 ;
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2007-12-03 01:33:57 +03:00
2012-03-24 19:51:05 +04:00
ret = get_fan_auto_nearest ( data , nr , val , data - > conf1 ) ;
if ( ret < 0 ) {
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
2012-03-24 19:51:05 +04:00
reg = ret ;
2007-12-03 01:33:57 +03:00
data - > conf1 = FAN_CHAN_TO_REG ( reg , data - > conf1 ) ;
if ( ( data - > conf1 & ADM1031_CONF1_AUTO_MODE ) ^
2005-04-17 02:20:36 +04:00
( old_fan_mode & ADM1031_CONF1_AUTO_MODE ) ) {
2012-01-17 01:51:48 +04:00
if ( data - > conf1 & ADM1031_CONF1_AUTO_MODE ) {
2012-01-19 23:02:14 +04:00
/*
* Switch to Auto Fan Mode
2007-12-03 01:33:57 +03:00
* Save PWM registers
2012-01-19 23:02:14 +04:00
* Set PWM registers to 33 % Both
*/
2005-04-17 02:20:36 +04:00
data - > old_pwm [ 0 ] = data - > pwm [ 0 ] ;
data - > old_pwm [ 1 ] = data - > pwm [ 1 ] ;
adm1031_write_value ( client , ADM1031_REG_PWM , 0x55 ) ;
} else {
/* Switch to Manual Mode */
data - > pwm [ 0 ] = data - > old_pwm [ 0 ] ;
data - > pwm [ 1 ] = data - > old_pwm [ 1 ] ;
/* Restore PWM registers */
2007-12-03 01:33:57 +03:00
adm1031_write_value ( client , ADM1031_REG_PWM ,
2005-04-17 02:20:36 +04:00
data - > pwm [ 0 ] | ( data - > pwm [ 1 ] < < 4 ) ) ;
}
}
data - > conf1 = FAN_CHAN_TO_REG ( reg , data - > conf1 ) ;
adm1031_write_value ( client , ADM1031_REG_CONF1 , data - > conf1 ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
2007-12-03 01:39:38 +03:00
static SENSOR_DEVICE_ATTR ( auto_fan1_channel , S_IRUGO | S_IWUSR ,
show_fan_auto_channel , set_fan_auto_channel , 0 ) ;
static SENSOR_DEVICE_ATTR ( auto_fan2_channel , S_IRUGO | S_IWUSR ,
show_fan_auto_channel , set_fan_auto_channel , 1 ) ;
2005-04-17 02:20:36 +04:00
/* Auto Temps */
2007-12-03 01:39:38 +03:00
static ssize_t show_auto_temp_off ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-12-03 01:39:38 +03:00
int nr = to_sensor_dev_attr ( attr ) - > index ;
2005-04-17 02:20:36 +04:00
struct adm1031_data * data = adm1031_update_device ( dev ) ;
2007-12-03 01:33:57 +03:00
return sprintf ( buf , " %d \n " ,
2005-04-17 02:20:36 +04:00
AUTO_TEMP_OFF_FROM_REG ( data - > auto_temp [ nr ] ) ) ;
}
2007-12-03 01:39:38 +03:00
static ssize_t show_auto_temp_min ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-12-03 01:39:38 +03:00
int nr = to_sensor_dev_attr ( attr ) - > index ;
2005-04-17 02:20:36 +04:00
struct adm1031_data * data = adm1031_update_device ( dev ) ;
return sprintf ( buf , " %d \n " ,
AUTO_TEMP_MIN_FROM_REG ( data - > auto_temp [ nr ] ) ) ;
}
static ssize_t
2007-12-03 01:39:38 +03:00
set_auto_temp_min ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2014-07-03 17:57:44 +04:00
struct adm1031_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2007-12-03 01:39:38 +03:00
int nr = to_sensor_dev_attr ( attr ) - > index ;
2012-01-17 01:51:48 +04:00
long val ;
int ret ;
ret = kstrtol ( buf , 10 , & val ) ;
if ( ret )
return ret ;
2005-04-17 02:20:36 +04:00
2014-07-04 00:44:23 +04:00
val = clamp_val ( val , 0 , 127000 ) ;
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
data - > auto_temp [ nr ] = AUTO_TEMP_MIN_TO_REG ( val , data - > auto_temp [ nr ] ) ;
adm1031_write_value ( client , ADM1031_REG_AUTO_TEMP ( nr ) ,
data - > auto_temp [ nr ] ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
2007-12-03 01:39:38 +03:00
static ssize_t show_auto_temp_max ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-12-03 01:39:38 +03:00
int nr = to_sensor_dev_attr ( attr ) - > index ;
2005-04-17 02:20:36 +04:00
struct adm1031_data * data = adm1031_update_device ( dev ) ;
return sprintf ( buf , " %d \n " ,
AUTO_TEMP_MAX_FROM_REG ( data - > auto_temp [ nr ] ) ) ;
}
static ssize_t
2007-12-03 01:39:38 +03:00
set_auto_temp_max ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2014-07-03 17:57:44 +04:00
struct adm1031_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2007-12-03 01:39:38 +03:00
int nr = to_sensor_dev_attr ( attr ) - > index ;
2012-01-17 01:51:48 +04:00
long val ;
int ret ;
ret = kstrtol ( buf , 10 , & val ) ;
if ( ret )
return ret ;
2005-04-17 02:20:36 +04:00
2014-07-04 00:44:23 +04:00
val = clamp_val ( val , 0 , 127000 ) ;
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2012-01-17 01:51:48 +04:00
data - > temp_max [ nr ] = AUTO_TEMP_MAX_TO_REG ( val , data - > auto_temp [ nr ] ,
data - > pwm [ nr ] ) ;
2005-04-17 02:20:36 +04:00
adm1031_write_value ( client , ADM1031_REG_AUTO_TEMP ( nr ) ,
data - > temp_max [ nr ] ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
2007-12-03 01:39:38 +03:00
# define auto_temp_reg(offset) \
static SENSOR_DEVICE_ATTR ( auto_temp # # offset # # _off , S_IRUGO , \
show_auto_temp_off , NULL , offset - 1 ) ; \
static SENSOR_DEVICE_ATTR ( auto_temp # # offset # # _min , S_IRUGO | S_IWUSR , \
show_auto_temp_min , set_auto_temp_min , offset - 1 ) ; \
static SENSOR_DEVICE_ATTR ( auto_temp # # offset # # _max , S_IRUGO | S_IWUSR , \
show_auto_temp_max , set_auto_temp_max , offset - 1 )
2005-04-17 02:20:36 +04:00
auto_temp_reg ( 1 ) ;
auto_temp_reg ( 2 ) ;
auto_temp_reg ( 3 ) ;
/* pwm */
2007-12-03 01:39:38 +03:00
static ssize_t show_pwm ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-12-03 01:39:38 +03:00
int nr = to_sensor_dev_attr ( attr ) - > index ;
2005-04-17 02:20:36 +04:00
struct adm1031_data * data = adm1031_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , PWM_FROM_REG ( data - > pwm [ nr ] ) ) ;
}
2007-12-03 01:39:38 +03:00
static ssize_t set_pwm ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2014-07-03 17:57:44 +04:00
struct adm1031_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2007-12-03 01:39:38 +03:00
int nr = to_sensor_dev_attr ( attr ) - > index ;
2012-01-17 01:51:48 +04:00
long val ;
int ret , reg ;
ret = kstrtol ( buf , 10 , & val ) ;
if ( ret )
return ret ;
2005-04-17 02:20:36 +04:00
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2007-12-03 01:33:57 +03:00
if ( ( data - > conf1 & ADM1031_CONF1_AUTO_MODE ) & &
2005-04-17 02:20:36 +04:00
( ( ( val > > 4 ) & 0xf ) ! = 5 ) ) {
/* In automatic mode, the only PWM accepted is 33% */
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
data - > pwm [ nr ] = PWM_TO_REG ( val ) ;
reg = adm1031_read_value ( client , ADM1031_REG_PWM ) ;
adm1031_write_value ( client , ADM1031_REG_PWM ,
nr ? ( ( data - > pwm [ nr ] < < 4 ) & 0xf0 ) | ( reg & 0xf )
: ( data - > pwm [ nr ] & 0xf ) | ( reg & 0xf0 ) ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
2007-12-03 01:39:38 +03:00
static SENSOR_DEVICE_ATTR ( pwm1 , S_IRUGO | S_IWUSR , show_pwm , set_pwm , 0 ) ;
static SENSOR_DEVICE_ATTR ( pwm2 , S_IRUGO | S_IWUSR , show_pwm , set_pwm , 1 ) ;
static SENSOR_DEVICE_ATTR ( auto_fan1_min_pwm , S_IRUGO | S_IWUSR ,
show_pwm , set_pwm , 0 ) ;
static SENSOR_DEVICE_ATTR ( auto_fan2_min_pwm , S_IRUGO | S_IWUSR ,
show_pwm , set_pwm , 1 ) ;
2005-04-17 02:20:36 +04:00
/* Fans */
/*
* That function checks the cases where the fan reading is not
2005-05-04 04:21:25 +04:00
* relevant . It is used to provide 0 as fan reading when the fan is
2005-04-17 02:20:36 +04:00
* not supposed to run
*/
static int trust_fan_readings ( struct adm1031_data * data , int chan )
{
int res = 0 ;
if ( data - > conf1 & ADM1031_CONF1_AUTO_MODE ) {
switch ( data - > conf1 & 0x60 ) {
2012-01-17 01:51:48 +04:00
case 0x00 :
/*
* remote temp1 controls fan1 ,
* remote temp2 controls fan2
*/
2005-04-17 02:20:36 +04:00
res = data - > temp [ chan + 1 ] > =
2012-01-17 01:51:48 +04:00
AUTO_TEMP_MIN_FROM_REG_DEG ( data - > auto_temp [ chan + 1 ] ) ;
2005-04-17 02:20:36 +04:00
break ;
case 0x20 : /* remote temp1 controls both fans */
res =
data - > temp [ 1 ] > =
AUTO_TEMP_MIN_FROM_REG_DEG ( data - > auto_temp [ 1 ] ) ;
break ;
case 0x40 : /* remote temp2 controls both fans */
res =
data - > temp [ 2 ] > =
AUTO_TEMP_MIN_FROM_REG_DEG ( data - > auto_temp [ 2 ] ) ;
break ;
case 0x60 : /* max controls both fans */
res =
data - > temp [ 0 ] > =
AUTO_TEMP_MIN_FROM_REG_DEG ( data - > auto_temp [ 0 ] )
| | data - > temp [ 1 ] > =
AUTO_TEMP_MIN_FROM_REG_DEG ( data - > auto_temp [ 1 ] )
2007-12-03 01:33:57 +03:00
| | ( data - > chip_type = = adm1031
2005-04-17 02:20:36 +04:00
& & data - > temp [ 2 ] > =
AUTO_TEMP_MIN_FROM_REG_DEG ( data - > auto_temp [ 2 ] ) ) ;
break ;
}
} else {
res = data - > pwm [ chan ] > 0 ;
}
return res ;
}
2007-12-03 01:39:38 +03:00
static ssize_t show_fan ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-12-03 01:39:38 +03:00
int nr = to_sensor_dev_attr ( attr ) - > index ;
2005-04-17 02:20:36 +04:00
struct adm1031_data * data = adm1031_update_device ( dev ) ;
int value ;
value = trust_fan_readings ( data , nr ) ? FAN_FROM_REG ( data - > fan [ nr ] ,
FAN_DIV_FROM_REG ( data - > fan_div [ nr ] ) ) : 0 ;
return sprintf ( buf , " %d \n " , value ) ;
}
2007-12-03 01:39:38 +03:00
static ssize_t show_fan_div ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-12-03 01:39:38 +03:00
int nr = to_sensor_dev_attr ( attr ) - > index ;
2005-04-17 02:20:36 +04:00
struct adm1031_data * data = adm1031_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , FAN_DIV_FROM_REG ( data - > fan_div [ nr ] ) ) ;
}
2007-12-03 01:39:38 +03:00
static ssize_t show_fan_min ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-12-03 01:39:38 +03:00
int nr = to_sensor_dev_attr ( attr ) - > index ;
2005-04-17 02:20:36 +04:00
struct adm1031_data * data = adm1031_update_device ( dev ) ;
return sprintf ( buf , " %d \n " ,
FAN_FROM_REG ( data - > fan_min [ nr ] ,
FAN_DIV_FROM_REG ( data - > fan_div [ nr ] ) ) ) ;
}
2007-12-03 01:39:38 +03:00
static ssize_t set_fan_min ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2014-07-03 17:57:44 +04:00
struct adm1031_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2007-12-03 01:39:38 +03:00
int nr = to_sensor_dev_attr ( attr ) - > index ;
2012-01-17 01:51:48 +04:00
long val ;
int ret ;
ret = kstrtol ( buf , 10 , & val ) ;
if ( ret )
return ret ;
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 ( val ) {
2007-12-03 01:33:57 +03:00
data - > fan_min [ nr ] =
2005-04-17 02:20:36 +04:00
FAN_TO_REG ( val , FAN_DIV_FROM_REG ( data - > fan_div [ nr ] ) ) ;
} else {
data - > fan_min [ nr ] = 0xff ;
}
adm1031_write_value ( client , ADM1031_REG_FAN_MIN ( nr ) , data - > fan_min [ nr ] ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
2007-12-03 01:39:38 +03:00
static ssize_t set_fan_div ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2014-07-03 17:57:44 +04:00
struct adm1031_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2007-12-03 01:39:38 +03:00
int nr = to_sensor_dev_attr ( attr ) - > index ;
2012-01-17 01:51:48 +04:00
long val ;
2005-04-17 02:20:36 +04:00
u8 tmp ;
int old_div ;
int new_min ;
2012-01-17 01:51:48 +04:00
int ret ;
ret = kstrtol ( buf , 10 , & val ) ;
if ( ret )
return ret ;
2005-04-17 02:20:36 +04:00
tmp = val = = 8 ? 0xc0 :
val = = 4 ? 0x80 :
2007-12-03 01:33:57 +03:00
val = = 2 ? 0x40 :
val = = 1 ? 0x00 :
2005-04-17 02:20:36 +04:00
0xff ;
if ( tmp = = 0xff )
return - EINVAL ;
2007-12-03 01:33:57 +03:00
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2007-12-03 01:32:42 +03:00
/* Get fresh readings */
data - > fan_div [ nr ] = adm1031_read_value ( client ,
ADM1031_REG_FAN_DIV ( nr ) ) ;
data - > fan_min [ nr ] = adm1031_read_value ( client ,
ADM1031_REG_FAN_MIN ( nr ) ) ;
/* Write the new clock divider and fan min */
2005-04-17 02:20:36 +04:00
old_div = FAN_DIV_FROM_REG ( data - > fan_div [ nr ] ) ;
2007-12-03 01:33:57 +03:00
data - > fan_div [ nr ] = tmp | ( 0x3f & data - > fan_div [ nr ] ) ;
new_min = data - > fan_min [ nr ] * old_div / val ;
2005-04-17 02:20:36 +04:00
data - > fan_min [ nr ] = new_min > 0xff ? 0xff : new_min ;
2007-12-03 01:33:57 +03:00
adm1031_write_value ( client , ADM1031_REG_FAN_DIV ( nr ) ,
2005-04-17 02:20:36 +04:00
data - > fan_div [ nr ] ) ;
2007-12-03 01:33:57 +03:00
adm1031_write_value ( client , ADM1031_REG_FAN_MIN ( nr ) ,
2005-04-17 02:20:36 +04:00
data - > fan_min [ nr ] ) ;
2007-12-03 01:32:42 +03:00
/* Invalidate the cache: fan speed is no longer valid */
data - > valid = 0 ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
# define fan_offset(offset) \
2007-12-03 01:39:38 +03:00
static SENSOR_DEVICE_ATTR ( fan # # offset # # _input , S_IRUGO , \
show_fan , NULL , offset - 1 ) ; \
static SENSOR_DEVICE_ATTR ( fan # # offset # # _min , S_IRUGO | S_IWUSR , \
show_fan_min , set_fan_min , offset - 1 ) ; \
static SENSOR_DEVICE_ATTR ( fan # # offset # # _div , S_IRUGO | S_IWUSR , \
show_fan_div , set_fan_div , offset - 1 )
2005-04-17 02:20:36 +04:00
fan_offset ( 1 ) ;
fan_offset ( 2 ) ;
/* Temps */
2007-12-03 01:39:38 +03:00
static ssize_t show_temp ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-12-03 01:39:38 +03:00
int nr = to_sensor_dev_attr ( attr ) - > index ;
2005-04-17 02:20:36 +04:00
struct adm1031_data * data = adm1031_update_device ( dev ) ;
int ext ;
ext = nr = = 0 ?
( ( data - > ext_temp [ nr ] > > 6 ) & 0x3 ) * 2 :
( ( ( data - > ext_temp [ nr ] > > ( ( nr - 1 ) * 3 ) ) & 7 ) ) ;
return sprintf ( buf , " %d \n " , TEMP_FROM_REG_EXT ( data - > temp [ nr ] , ext ) ) ;
}
2009-09-24 00:59:41 +04:00
static ssize_t show_temp_offset ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
int nr = to_sensor_dev_attr ( attr ) - > index ;
struct adm1031_data * data = adm1031_update_device ( dev ) ;
return sprintf ( buf , " %d \n " ,
TEMP_OFFSET_FROM_REG ( data - > temp_offset [ nr ] ) ) ;
}
2007-12-03 01:39:38 +03:00
static ssize_t show_temp_min ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-12-03 01:39:38 +03:00
int nr = to_sensor_dev_attr ( attr ) - > index ;
2005-04-17 02:20:36 +04:00
struct adm1031_data * data = adm1031_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , TEMP_FROM_REG ( data - > temp_min [ nr ] ) ) ;
}
2007-12-03 01:39:38 +03:00
static ssize_t show_temp_max ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-12-03 01:39:38 +03:00
int nr = to_sensor_dev_attr ( attr ) - > index ;
2005-04-17 02:20:36 +04:00
struct adm1031_data * data = adm1031_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , TEMP_FROM_REG ( data - > temp_max [ nr ] ) ) ;
}
2007-12-03 01:39:38 +03:00
static ssize_t show_temp_crit ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-12-03 01:39:38 +03:00
int nr = to_sensor_dev_attr ( attr ) - > index ;
2005-04-17 02:20:36 +04:00
struct adm1031_data * data = adm1031_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , TEMP_FROM_REG ( data - > temp_crit [ nr ] ) ) ;
}
2009-09-24 00:59:41 +04:00
static ssize_t set_temp_offset ( struct device * dev ,
struct device_attribute * attr , const char * buf ,
size_t count )
{
2014-07-03 17:57:44 +04:00
struct adm1031_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2009-09-24 00:59:41 +04:00
int nr = to_sensor_dev_attr ( attr ) - > index ;
2012-01-17 01:51:48 +04:00
long val ;
int ret ;
ret = kstrtol ( buf , 10 , & val ) ;
if ( ret )
return ret ;
2009-09-24 00:59:41 +04:00
2013-01-09 20:09:34 +04:00
val = clamp_val ( val , - 15000 , 15000 ) ;
2009-09-24 00:59:41 +04:00
mutex_lock ( & data - > update_lock ) ;
data - > temp_offset [ nr ] = TEMP_OFFSET_TO_REG ( val ) ;
adm1031_write_value ( client , ADM1031_REG_TEMP_OFFSET ( nr ) ,
data - > temp_offset [ nr ] ) ;
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
2007-12-03 01:39:38 +03:00
static ssize_t set_temp_min ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2014-07-03 17:57:44 +04:00
struct adm1031_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2007-12-03 01:39:38 +03:00
int nr = to_sensor_dev_attr ( attr ) - > index ;
2012-01-17 01:51:48 +04:00
long val ;
int ret ;
ret = kstrtol ( buf , 10 , & val ) ;
if ( ret )
return ret ;
2005-04-17 02:20:36 +04:00
2014-07-04 00:44:23 +04:00
val = clamp_val ( val , - 55000 , 127000 ) ;
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
data - > temp_min [ nr ] = TEMP_TO_REG ( val ) ;
adm1031_write_value ( client , ADM1031_REG_TEMP_MIN ( nr ) ,
data - > temp_min [ nr ] ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
2007-12-03 01:39:38 +03:00
static ssize_t set_temp_max ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2014-07-03 17:57:44 +04:00
struct adm1031_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2007-12-03 01:39:38 +03:00
int nr = to_sensor_dev_attr ( attr ) - > index ;
2012-01-17 01:51:48 +04:00
long val ;
int ret ;
ret = kstrtol ( buf , 10 , & val ) ;
if ( ret )
return ret ;
2005-04-17 02:20:36 +04:00
2014-07-04 00:44:23 +04:00
val = clamp_val ( val , - 55000 , 127000 ) ;
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
data - > temp_max [ nr ] = TEMP_TO_REG ( val ) ;
adm1031_write_value ( client , ADM1031_REG_TEMP_MAX ( nr ) ,
data - > temp_max [ nr ] ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
2007-12-03 01:39:38 +03:00
static ssize_t set_temp_crit ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2014-07-03 17:57:44 +04:00
struct adm1031_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2007-12-03 01:39:38 +03:00
int nr = to_sensor_dev_attr ( attr ) - > index ;
2012-01-17 01:51:48 +04:00
long val ;
int ret ;
ret = kstrtol ( buf , 10 , & val ) ;
if ( ret )
return ret ;
2005-04-17 02:20:36 +04:00
2014-07-04 00:44:23 +04:00
val = clamp_val ( val , - 55000 , 127000 ) ;
2006-01-19 01:19:26 +03:00
mutex_lock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
data - > temp_crit [ nr ] = TEMP_TO_REG ( val ) ;
adm1031_write_value ( client , ADM1031_REG_TEMP_CRIT ( nr ) ,
data - > temp_crit [ nr ] ) ;
2006-01-19 01:19:26 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
return count ;
}
2007-12-03 01:39:38 +03:00
# define temp_reg(offset) \
static SENSOR_DEVICE_ATTR ( temp # # offset # # _input , S_IRUGO , \
show_temp , NULL , offset - 1 ) ; \
2009-09-24 00:59:41 +04:00
static SENSOR_DEVICE_ATTR ( temp # # offset # # _offset , S_IRUGO | S_IWUSR , \
show_temp_offset , set_temp_offset , offset - 1 ) ; \
2007-12-03 01:39:38 +03:00
static SENSOR_DEVICE_ATTR ( temp # # offset # # _min , S_IRUGO | S_IWUSR , \
show_temp_min , set_temp_min , offset - 1 ) ; \
static SENSOR_DEVICE_ATTR ( temp # # offset # # _max , S_IRUGO | S_IWUSR , \
show_temp_max , set_temp_max , offset - 1 ) ; \
static SENSOR_DEVICE_ATTR ( temp # # offset # # _crit , S_IRUGO | S_IWUSR , \
show_temp_crit , set_temp_crit , offset - 1 )
2005-04-17 02:20:36 +04:00
temp_reg ( 1 ) ;
temp_reg ( 2 ) ;
temp_reg ( 3 ) ;
/* Alarms */
2012-01-17 01:51:48 +04:00
static ssize_t show_alarms ( struct device * dev , struct device_attribute * attr ,
char * buf )
2005-04-17 02:20:36 +04:00
{
struct adm1031_data * data = adm1031_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , data - > alarm ) ;
}
static DEVICE_ATTR ( alarms , S_IRUGO , show_alarms , NULL ) ;
2007-12-03 01:42:24 +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 adm1031_data * data = adm1031_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , ( data - > alarm > > bitnr ) & 1 ) ;
}
static SENSOR_DEVICE_ATTR ( fan1_alarm , S_IRUGO , show_alarm , NULL , 0 ) ;
static SENSOR_DEVICE_ATTR ( fan1_fault , S_IRUGO , show_alarm , NULL , 1 ) ;
static SENSOR_DEVICE_ATTR ( temp2_max_alarm , S_IRUGO , show_alarm , NULL , 2 ) ;
static SENSOR_DEVICE_ATTR ( temp2_min_alarm , S_IRUGO , show_alarm , NULL , 3 ) ;
static SENSOR_DEVICE_ATTR ( temp2_crit_alarm , S_IRUGO , show_alarm , NULL , 4 ) ;
static SENSOR_DEVICE_ATTR ( temp2_fault , S_IRUGO , show_alarm , NULL , 5 ) ;
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 , 7 ) ;
static SENSOR_DEVICE_ATTR ( fan2_alarm , S_IRUGO , show_alarm , NULL , 8 ) ;
static SENSOR_DEVICE_ATTR ( fan2_fault , S_IRUGO , show_alarm , NULL , 9 ) ;
static SENSOR_DEVICE_ATTR ( temp3_max_alarm , S_IRUGO , show_alarm , NULL , 10 ) ;
static SENSOR_DEVICE_ATTR ( temp3_min_alarm , S_IRUGO , show_alarm , NULL , 11 ) ;
static SENSOR_DEVICE_ATTR ( temp3_crit_alarm , S_IRUGO , show_alarm , NULL , 12 ) ;
static SENSOR_DEVICE_ATTR ( temp3_fault , S_IRUGO , show_alarm , NULL , 13 ) ;
static SENSOR_DEVICE_ATTR ( temp1_crit_alarm , S_IRUGO , show_alarm , NULL , 14 ) ;
2005-04-17 02:20:36 +04:00
2010-09-17 19:24:14 +04:00
/* Update Interval */
static const unsigned int update_intervals [ ] = {
2010-05-27 21:58:46 +04:00
16000 , 8000 , 4000 , 2000 , 1000 , 500 , 250 , 125 ,
} ;
2010-09-17 19:24:14 +04:00
static ssize_t show_update_interval ( struct device * dev ,
struct device_attribute * attr , char * buf )
2010-05-27 21:58:46 +04:00
{
2014-07-03 17:57:44 +04:00
struct adm1031_data * data = dev_get_drvdata ( dev ) ;
2010-05-27 21:58:46 +04:00
2010-09-17 19:24:14 +04:00
return sprintf ( buf , " %u \n " , data - > update_interval ) ;
2010-05-27 21:58:46 +04:00
}
2010-09-17 19:24:14 +04:00
static ssize_t set_update_interval ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
2010-05-27 21:58:46 +04:00
{
2014-07-03 17:57:44 +04:00
struct adm1031_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2010-05-27 21:58:46 +04:00
unsigned long val ;
int i , err ;
u8 reg ;
2012-01-04 23:58:52 +04:00
err = kstrtoul ( buf , 10 , & val ) ;
2010-05-27 21:58:46 +04:00
if ( err )
return err ;
2010-09-17 19:24:14 +04:00
/*
* Find the nearest update interval from the table .
* Use it to determine the matching update rate .
*/
for ( i = 0 ; i < ARRAY_SIZE ( update_intervals ) - 1 ; i + + ) {
if ( val > = update_intervals [ i ] )
2010-05-27 21:58:46 +04:00
break ;
}
2010-09-17 19:24:14 +04:00
/* if not found, we point to the last entry (lowest update interval) */
2010-05-27 21:58:46 +04:00
/* set the new update rate while preserving other settings */
reg = adm1031_read_value ( client , ADM1031_REG_FAN_FILTER ) ;
reg & = ~ ADM1031_UPDATE_RATE_MASK ;
reg | = i < < ADM1031_UPDATE_RATE_SHIFT ;
adm1031_write_value ( client , ADM1031_REG_FAN_FILTER , reg ) ;
mutex_lock ( & data - > update_lock ) ;
2010-09-17 19:24:14 +04:00
data - > update_interval = update_intervals [ i ] ;
2010-05-27 21:58:46 +04:00
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
2010-09-17 19:24:14 +04:00
static DEVICE_ATTR ( update_interval , S_IRUGO | S_IWUSR , show_update_interval ,
set_update_interval ) ;
2010-05-27 21:58:46 +04:00
2006-09-24 23:15:35 +04:00
static struct attribute * adm1031_attributes [ ] = {
2007-12-03 01:39:38 +03:00
& sensor_dev_attr_fan1_input . dev_attr . attr ,
& sensor_dev_attr_fan1_div . dev_attr . attr ,
& sensor_dev_attr_fan1_min . dev_attr . attr ,
2007-12-03 01:42:24 +03:00
& sensor_dev_attr_fan1_alarm . dev_attr . attr ,
& sensor_dev_attr_fan1_fault . dev_attr . attr ,
2007-12-03 01:39:38 +03:00
& sensor_dev_attr_pwm1 . dev_attr . attr ,
& sensor_dev_attr_auto_fan1_channel . dev_attr . attr ,
& sensor_dev_attr_temp1_input . dev_attr . attr ,
2009-09-24 00:59:41 +04:00
& sensor_dev_attr_temp1_offset . dev_attr . attr ,
2007-12-03 01:39:38 +03:00
& sensor_dev_attr_temp1_min . dev_attr . attr ,
2007-12-03 01:42:24 +03:00
& sensor_dev_attr_temp1_min_alarm . dev_attr . attr ,
2007-12-03 01:39:38 +03:00
& sensor_dev_attr_temp1_max . dev_attr . attr ,
2007-12-03 01:42:24 +03:00
& sensor_dev_attr_temp1_max_alarm . dev_attr . attr ,
2007-12-03 01:39:38 +03:00
& sensor_dev_attr_temp1_crit . dev_attr . attr ,
2007-12-03 01:42:24 +03:00
& sensor_dev_attr_temp1_crit_alarm . dev_attr . attr ,
2007-12-03 01:39:38 +03:00
& sensor_dev_attr_temp2_input . dev_attr . attr ,
2009-09-24 00:59:41 +04:00
& sensor_dev_attr_temp2_offset . dev_attr . attr ,
2007-12-03 01:39:38 +03:00
& sensor_dev_attr_temp2_min . dev_attr . attr ,
2007-12-03 01:42:24 +03:00
& sensor_dev_attr_temp2_min_alarm . dev_attr . attr ,
2007-12-03 01:39:38 +03:00
& sensor_dev_attr_temp2_max . dev_attr . attr ,
2007-12-03 01:42:24 +03:00
& sensor_dev_attr_temp2_max_alarm . dev_attr . attr ,
2007-12-03 01:39:38 +03:00
& sensor_dev_attr_temp2_crit . dev_attr . attr ,
2007-12-03 01:42:24 +03:00
& sensor_dev_attr_temp2_crit_alarm . dev_attr . attr ,
& sensor_dev_attr_temp2_fault . dev_attr . attr ,
2007-12-03 01:39:38 +03:00
& sensor_dev_attr_auto_temp1_off . dev_attr . attr ,
& sensor_dev_attr_auto_temp1_min . dev_attr . attr ,
& sensor_dev_attr_auto_temp1_max . dev_attr . attr ,
& sensor_dev_attr_auto_temp2_off . dev_attr . attr ,
& sensor_dev_attr_auto_temp2_min . dev_attr . attr ,
& sensor_dev_attr_auto_temp2_max . dev_attr . attr ,
& sensor_dev_attr_auto_fan1_min_pwm . dev_attr . attr ,
2006-09-24 23:15:35 +04:00
2010-09-17 19:24:14 +04:00
& dev_attr_update_interval . attr ,
2006-09-24 23:15:35 +04:00
& dev_attr_alarms . attr ,
NULL
} ;
static const struct attribute_group adm1031_group = {
. attrs = adm1031_attributes ,
} ;
static struct attribute * adm1031_attributes_opt [ ] = {
2007-12-03 01:39:38 +03:00
& sensor_dev_attr_fan2_input . dev_attr . attr ,
& sensor_dev_attr_fan2_div . dev_attr . attr ,
& sensor_dev_attr_fan2_min . dev_attr . attr ,
2007-12-03 01:42:24 +03:00
& sensor_dev_attr_fan2_alarm . dev_attr . attr ,
& sensor_dev_attr_fan2_fault . dev_attr . attr ,
2007-12-03 01:39:38 +03:00
& sensor_dev_attr_pwm2 . dev_attr . attr ,
& sensor_dev_attr_auto_fan2_channel . dev_attr . attr ,
& sensor_dev_attr_temp3_input . dev_attr . attr ,
2009-09-24 00:59:41 +04:00
& sensor_dev_attr_temp3_offset . dev_attr . attr ,
2007-12-03 01:39:38 +03:00
& sensor_dev_attr_temp3_min . dev_attr . attr ,
2007-12-03 01:42:24 +03:00
& sensor_dev_attr_temp3_min_alarm . dev_attr . attr ,
2007-12-03 01:39:38 +03:00
& sensor_dev_attr_temp3_max . dev_attr . attr ,
2007-12-03 01:42:24 +03:00
& sensor_dev_attr_temp3_max_alarm . dev_attr . attr ,
2007-12-03 01:39:38 +03:00
& sensor_dev_attr_temp3_crit . dev_attr . attr ,
2007-12-03 01:42:24 +03:00
& sensor_dev_attr_temp3_crit_alarm . dev_attr . attr ,
& sensor_dev_attr_temp3_fault . dev_attr . attr ,
2007-12-03 01:39:38 +03:00
& sensor_dev_attr_auto_temp3_off . dev_attr . attr ,
& sensor_dev_attr_auto_temp3_min . dev_attr . attr ,
& sensor_dev_attr_auto_temp3_max . dev_attr . attr ,
& sensor_dev_attr_auto_fan2_min_pwm . dev_attr . attr ,
2006-09-24 23:15:35 +04:00
NULL
} ;
static const struct attribute_group adm1031_group_opt = {
. attrs = adm1031_attributes_opt ,
} ;
2008-07-16 21:30:09 +04:00
/* Return 0 if detection is successful, -ENODEV otherwise */
2009-12-14 23:17:23 +03:00
static int adm1031_detect ( struct i2c_client * client ,
2008-07-16 21:30:09 +04:00
struct i2c_board_info * info )
2005-04-17 02:20:36 +04:00
{
2008-07-16 21:30:09 +04:00
struct i2c_adapter * adapter = client - > adapter ;
2009-12-09 22:35:57 +03:00
const char * name ;
int id , co ;
2005-04-17 02:20:36 +04:00
if ( ! i2c_check_functionality ( adapter , I2C_FUNC_SMBUS_BYTE_DATA ) )
2008-07-16 21:30:09 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
2009-12-09 22:35:57 +03:00
id = i2c_smbus_read_byte_data ( client , 0x3d ) ;
co = i2c_smbus_read_byte_data ( client , 0x3e ) ;
2005-04-17 02:20:36 +04:00
2009-12-09 22:35:57 +03:00
if ( ! ( ( id = = 0x31 | | id = = 0x30 ) & & co = = 0x41 ) )
return - ENODEV ;
name = ( id = = 0x30 ) ? " adm1030 " : " adm1031 " ;
2005-04-17 02:20:36 +04:00
2008-07-16 21:30:09 +04:00
strlcpy ( info - > type , name , I2C_NAME_SIZE ) ;
2005-04-17 02:20:36 +04:00
2008-07-16 21:30:09 +04:00
return 0 ;
}
2014-07-03 17:56:33 +04:00
static void adm1031_init_client ( struct i2c_client * client )
{
unsigned int read_val ;
unsigned int mask ;
int i ;
struct adm1031_data * data = i2c_get_clientdata ( client ) ;
mask = ( ADM1031_CONF2_PWM1_ENABLE | ADM1031_CONF2_TACH1_ENABLE ) ;
if ( data - > chip_type = = adm1031 ) {
mask | = ( ADM1031_CONF2_PWM2_ENABLE |
ADM1031_CONF2_TACH2_ENABLE ) ;
}
/* Initialize the ADM1031 chip (enables fan speed reading ) */
read_val = adm1031_read_value ( client , ADM1031_REG_CONF2 ) ;
if ( ( read_val | mask ) ! = read_val )
adm1031_write_value ( client , ADM1031_REG_CONF2 , read_val | mask ) ;
read_val = adm1031_read_value ( client , ADM1031_REG_CONF1 ) ;
if ( ( read_val | ADM1031_CONF1_MONITOR_ENABLE ) ! = read_val ) {
adm1031_write_value ( client , ADM1031_REG_CONF1 ,
read_val | ADM1031_CONF1_MONITOR_ENABLE ) ;
}
/* Read the chip's update rate */
mask = ADM1031_UPDATE_RATE_MASK ;
read_val = adm1031_read_value ( client , ADM1031_REG_FAN_FILTER ) ;
i = ( read_val & mask ) > > ADM1031_UPDATE_RATE_SHIFT ;
/* Save it as update interval */
data - > update_interval = update_intervals [ i ] ;
}
2008-07-16 21:30:09 +04:00
static int adm1031_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
2014-07-03 17:57:44 +04:00
struct device * dev = & client - > dev ;
struct device * hwmon_dev ;
2008-07-16 21:30:09 +04:00
struct adm1031_data * data ;
2014-07-03 17:57:44 +04:00
data = devm_kzalloc ( dev , sizeof ( struct adm1031_data ) , GFP_KERNEL ) ;
2012-06-02 20:57:59 +04:00
if ( ! data )
return - ENOMEM ;
2008-07-16 21:30:09 +04:00
i2c_set_clientdata ( client , data ) ;
2014-07-03 17:57:44 +04:00
data - > client = client ;
2008-07-16 21:30:09 +04:00
data - > chip_type = id - > driver_data ;
2006-01-19 01:19:26 +03:00
mutex_init ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
2008-07-16 21:30:09 +04:00
if ( data - > chip_type = = adm1030 )
data - > chan_select_table = & auto_channel_select_table_adm1030 ;
else
data - > chan_select_table = & auto_channel_select_table_adm1031 ;
2005-04-17 02:20:36 +04:00
/* Initialize the ADM1031 chip */
2007-12-03 01:33:57 +03:00
adm1031_init_client ( client ) ;
2005-04-17 02:20:36 +04:00
2014-07-03 17:57:44 +04:00
/* sysfs hooks */
data - > groups [ 0 ] = & adm1031_group ;
if ( data - > chip_type = = adm1031 )
data - > groups [ 1 ] = & adm1031_group_opt ;
2005-04-17 02:20:36 +04:00
2014-07-03 17:57:44 +04:00
hwmon_dev = devm_hwmon_device_register_with_groups ( dev , client - > name ,
data , data - > groups ) ;
return PTR_ERR_OR_ZERO ( hwmon_dev ) ;
2005-04-17 02:20:36 +04:00
}
2014-07-03 17:56:33 +04:00
static const struct i2c_device_id adm1031_id [ ] = {
{ " adm1030 " , adm1030 } ,
{ " adm1031 " , adm1031 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , adm1031_id ) ;
2005-04-17 02:20:36 +04:00
2014-07-03 17:56:33 +04:00
static struct i2c_driver adm1031_driver = {
. class = I2C_CLASS_HWMON ,
. driver = {
. name = " adm1031 " ,
} ,
. probe = adm1031_probe ,
. id_table = adm1031_id ,
. detect = adm1031_detect ,
. address_list = normal_i2c ,
} ;
2005-04-17 02:20:36 +04:00
2012-01-20 11:38:18 +04:00
module_i2c_driver ( adm1031_driver ) ;
2005-04-17 02:20:36 +04:00
MODULE_AUTHOR ( " Alexandre d'Alton <alex@alexdalton.org> " ) ;
MODULE_DESCRIPTION ( " ADM1031/ADM1030 driver " ) ;
MODULE_LICENSE ( " GPL " ) ;