2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2009-01-16 00:27:47 +03:00
/*
* adt7475 - Thermal sensor driver for the ADT7475 chip and derivatives
* Copyright ( C ) 2007 - 2008 , Advanced Micro Devices , Inc .
* Copyright ( C ) 2008 Jordan Crouse < jordan @ cosmicpenguin . net >
* Copyright ( C ) 2008 Hans de Goede < hdegoede @ redhat . com >
2014-01-29 23:40:08 +04:00
* Copyright ( C ) 2009 Jean Delvare < jdelvare @ suse . de >
2009-12-09 22:36:05 +03:00
*
2009-01-16 00:27:47 +03:00
* Derived from the lm83 driver by Jean Delvare
*/
# include <linux/module.h>
2017-02-24 16:12:58 +03:00
# include <linux/of_device.h>
2009-01-16 00:27:47 +03:00
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/i2c.h>
# include <linux/hwmon.h>
# include <linux/hwmon-sysfs.h>
2009-12-09 22:36:08 +03:00
# include <linux/hwmon-vid.h>
2009-01-16 00:27:47 +03:00
# include <linux/err.h>
2012-10-10 17:25:56 +04:00
# include <linux/jiffies.h>
2020-02-27 11:46:41 +03:00
# include <linux/of.h>
2017-05-11 06:45:21 +03:00
# include <linux/util_macros.h>
2009-01-16 00:27:47 +03:00
/* Indexes for the sysfs hooks */
# define INPUT 0
# define MIN 1
# define MAX 2
# define CONTROL 3
# define OFFSET 3
# define AUTOMIN 4
# define THERM 5
# define HYSTERSIS 6
2012-01-19 23:02:15 +04:00
/*
* These are unique identifiers for the sysfs functions - unlike the
* numbers above , these are not also indexes into an array
*/
2009-01-16 00:27:47 +03:00
# define ALARM 9
# define FAULT 10
/* 7475 Common Registers */
2009-12-09 22:36:07 +03:00
# define REG_DEVREV2 0x12 /* ADT7490 only */
2009-12-09 22:36:05 +03:00
# define REG_VTT 0x1E /* ADT7490 only */
# define REG_EXTEND3 0x1F /* ADT7490 only */
2009-12-09 22:36:03 +03:00
# define REG_VOLTAGE_BASE 0x20
2009-01-16 00:27:47 +03:00
# define REG_TEMP_BASE 0x25
# define REG_TACH_BASE 0x28
# define REG_PWM_BASE 0x30
# define REG_PWM_MAX_BASE 0x38
# define REG_DEVID 0x3D
# define REG_VENDID 0x3E
2009-12-09 22:36:04 +03:00
# define REG_DEVID2 0x3F
2009-01-16 00:27:47 +03:00
2017-04-21 22:08:09 +03:00
# define REG_CONFIG1 0x40
2009-01-16 00:27:47 +03:00
# define REG_STATUS1 0x41
# define REG_STATUS2 0x42
2009-12-09 22:36:08 +03:00
# define REG_VID 0x43 /* ADT7476 only */
2009-12-09 22:36:03 +03:00
# define REG_VOLTAGE_MIN_BASE 0x44
# define REG_VOLTAGE_MAX_BASE 0x45
2009-01-16 00:27:47 +03:00
# define REG_TEMP_MIN_BASE 0x4E
# define REG_TEMP_MAX_BASE 0x4F
# define REG_TACH_MIN_BASE 0x54
# define REG_PWM_CONFIG_BASE 0x5C
# define REG_TEMP_TRANGE_BASE 0x5F
2017-05-15 04:30:27 +03:00
# define REG_ENHANCE_ACOUSTICS1 0x62
# define REG_ENHANCE_ACOUSTICS2 0x63
2009-01-16 00:27:47 +03:00
# define REG_PWM_MIN_BASE 0x64
# define REG_TEMP_TMIN_BASE 0x67
# define REG_TEMP_THERM_BASE 0x6A
# define REG_REMOTE1_HYSTERSIS 0x6D
# define REG_REMOTE2_HYSTERSIS 0x6E
# define REG_TEMP_OFFSET_BASE 0x70
2009-12-09 22:36:07 +03:00
# define REG_CONFIG2 0x73
2009-01-16 00:27:47 +03:00
# define REG_EXTEND1 0x76
# define REG_EXTEND2 0x77
2009-12-09 22:36:06 +03:00
# define REG_CONFIG3 0x78
2009-01-16 00:27:47 +03:00
# define REG_CONFIG5 0x7C
2009-12-09 22:36:03 +03:00
# define REG_CONFIG4 0x7D
2009-12-09 22:36:05 +03:00
# define REG_STATUS4 0x81 /* ADT7490 only */
# define REG_VTT_MIN 0x84 /* ADT7490 only */
# define REG_VTT_MAX 0x86 /* ADT7490 only */
2009-12-09 22:36:08 +03:00
# define VID_VIDSEL 0x80 /* ADT7476 only */
2009-12-09 22:36:07 +03:00
# define CONFIG2_ATTN 0x20
2009-12-09 22:36:06 +03:00
# define CONFIG3_SMBALERT 0x01
# define CONFIG3_THERM 0x02
# define CONFIG4_PINFUNC 0x03
2009-12-09 22:36:03 +03:00
# define CONFIG4_MAXDUTY 0x08
2009-12-09 22:36:07 +03:00
# define CONFIG4_ATTN_IN10 0x30
# define CONFIG4_ATTN_IN43 0xC0
2009-01-16 00:27:47 +03:00
# define CONFIG5_TWOSCOMP 0x01
# define CONFIG5_TEMPOFFSET 0x02
2009-12-09 22:36:08 +03:00
# define CONFIG5_VIDGPIO 0x10 /* ADT7476 only */
2009-01-16 00:27:47 +03:00
/* ADT7475 Settings */
2009-12-09 22:36:03 +03:00
# define ADT7475_VOLTAGE_COUNT 5 /* Not counting Vtt */
2009-01-16 00:27:47 +03:00
# define ADT7475_TEMP_COUNT 3
# define ADT7475_TACH_COUNT 4
# define ADT7475_PWM_COUNT 3
/* Macro to read the registers */
# define adt7475_read(reg) i2c_smbus_read_byte_data(client, (reg))
/* Macros to easily index the registers */
# define TACH_REG(idx) (REG_TACH_BASE + ((idx) * 2))
# define TACH_MIN_REG(idx) (REG_TACH_MIN_BASE + ((idx) * 2))
# define PWM_REG(idx) (REG_PWM_BASE + (idx))
# define PWM_MAX_REG(idx) (REG_PWM_MAX_BASE + (idx))
# define PWM_MIN_REG(idx) (REG_PWM_MIN_BASE + (idx))
# define PWM_CONFIG_REG(idx) (REG_PWM_CONFIG_BASE + (idx))
# define VOLTAGE_REG(idx) (REG_VOLTAGE_BASE + (idx))
# define VOLTAGE_MIN_REG(idx) (REG_VOLTAGE_MIN_BASE + ((idx) * 2))
# define VOLTAGE_MAX_REG(idx) (REG_VOLTAGE_MAX_BASE + ((idx) * 2))
# define TEMP_REG(idx) (REG_TEMP_BASE + (idx))
# define TEMP_MIN_REG(idx) (REG_TEMP_MIN_BASE + ((idx) * 2))
# define TEMP_MAX_REG(idx) (REG_TEMP_MAX_BASE + ((idx) * 2))
# define TEMP_TMIN_REG(idx) (REG_TEMP_TMIN_BASE + (idx))
# define TEMP_THERM_REG(idx) (REG_TEMP_THERM_BASE + (idx))
# define TEMP_OFFSET_REG(idx) (REG_TEMP_OFFSET_BASE + (idx))
# define TEMP_TRANGE_REG(idx) (REG_TEMP_TRANGE_BASE + (idx))
2010-10-28 22:31:50 +04:00
static const unsigned short normal_i2c [ ] = { 0x2c , 0x2d , 0x2e , I2C_CLIENT_END } ;
2009-01-16 00:27:47 +03:00
2009-12-14 23:17:27 +03:00
enum chips { adt7473 , adt7475 , adt7476 , adt7490 } ;
2009-01-16 00:27:47 +03:00
static const struct i2c_device_id adt7475_id [ ] = {
2009-12-09 22:36:02 +03:00
{ " adt7473 " , adt7473 } ,
2009-01-16 00:27:47 +03:00
{ " adt7475 " , adt7475 } ,
2009-12-09 22:36:08 +03:00
{ " adt7476 " , adt7476 } ,
2009-12-09 22:36:05 +03:00
{ " adt7490 " , adt7490 } ,
2009-01-16 00:27:47 +03:00
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , adt7475_id ) ;
2019-04-04 16:33:42 +03:00
static const struct of_device_id __maybe_unused adt7475_of_match [ ] = {
2017-02-24 16:12:58 +03:00
{
. compatible = " adi,adt7473 " ,
. data = ( void * ) adt7473
} ,
{
. compatible = " adi,adt7475 " ,
. data = ( void * ) adt7475
} ,
{
. compatible = " adi,adt7476 " ,
. data = ( void * ) adt7476
} ,
{
. compatible = " adi,adt7490 " ,
. data = ( void * ) adt7490
} ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , adt7475_of_match ) ;
2009-01-16 00:27:47 +03:00
struct adt7475_data {
2019-07-22 01:55:30 +03:00
struct i2c_client * client ;
2009-01-16 00:27:47 +03:00
struct mutex lock ;
unsigned long measure_updated ;
2018-08-08 04:32:17 +03:00
bool valid ;
2009-01-16 00:27:47 +03:00
2020-02-27 11:46:41 +03:00
u8 config2 ;
2009-12-09 22:36:03 +03:00
u8 config4 ;
2009-01-16 00:27:47 +03:00
u8 config5 ;
2009-12-09 22:36:03 +03:00
u8 has_voltage ;
2009-12-09 22:36:07 +03:00
u8 bypass_attn ; /* Bypass voltage attenuator */
2009-12-09 22:36:06 +03:00
u8 has_pwm2 : 1 ;
u8 has_fan4 : 1 ;
2009-12-09 22:36:08 +03:00
u8 has_vid : 1 ;
2009-12-09 22:36:05 +03:00
u32 alarms ;
2009-12-09 22:36:03 +03:00
u16 voltage [ 3 ] [ 6 ] ;
2009-01-16 00:27:47 +03:00
u16 temp [ 7 ] [ 3 ] ;
u16 tach [ 2 ] [ 4 ] ;
u8 pwm [ 4 ] [ 3 ] ;
u8 range [ 3 ] ;
u8 pwmctl [ 3 ] ;
u8 pwmchan [ 3 ] ;
2017-05-15 04:30:27 +03:00
u8 enh_acoustics [ 2 ] ;
2009-12-09 22:36:08 +03:00
u8 vid ;
u8 vrm ;
2019-07-22 01:55:30 +03:00
const struct attribute_group * groups [ 9 ] ;
2009-01-16 00:27:47 +03:00
} ;
static struct i2c_driver adt7475_driver ;
static struct adt7475_data * adt7475_update_device ( struct device * dev ) ;
static void adt7475_read_hystersis ( struct i2c_client * client ) ;
static void adt7475_read_pwm ( struct i2c_client * client , int index ) ;
/* Given a temp value, convert it to register value */
static inline u16 temp2reg ( struct adt7475_data * data , long val )
{
u16 ret ;
if ( ! ( data - > config5 & CONFIG5_TWOSCOMP ) ) {
2013-01-09 20:09:34 +04:00
val = clamp_val ( val , - 64000 , 191000 ) ;
2009-01-16 00:27:47 +03:00
ret = ( val + 64500 ) / 1000 ;
} else {
2013-01-09 20:09:34 +04:00
val = clamp_val ( val , - 128000 , 127000 ) ;
2009-01-16 00:27:47 +03:00
if ( val < - 500 )
ret = ( 256500 + val ) / 1000 ;
else
ret = ( val + 500 ) / 1000 ;
}
return ret < < 2 ;
}
/* Given a register value, convert it to a real temp value */
static inline int reg2temp ( struct adt7475_data * data , u16 reg )
{
if ( data - > config5 & CONFIG5_TWOSCOMP ) {
if ( reg > = 512 )
return ( reg - 1024 ) * 250 ;
else
return reg * 250 ;
} else
return ( reg - 256 ) * 250 ;
}
static inline int tach2rpm ( u16 tach )
{
if ( tach = = 0 | | tach = = 0xFFFF )
return 0 ;
return ( 90000 * 60 ) / tach ;
}
static inline u16 rpm2tach ( unsigned long rpm )
{
if ( rpm = = 0 )
return 0 ;
2013-01-09 20:09:34 +04:00
return clamp_val ( ( 90000 * 60 ) / rpm , 1 , 0xFFFF ) ;
2009-01-16 00:27:47 +03:00
}
2009-12-09 22:36:03 +03:00
/* Scaling factors for voltage inputs, taken from the ADT7490 datasheet */
static const int adt7473_in_scaling [ ADT7475_VOLTAGE_COUNT + 1 ] [ 2 ] = {
{ 45 , 94 } , /* +2.5V */
{ 175 , 525 } , /* Vccp */
{ 68 , 71 } , /* Vcc */
{ 93 , 47 } , /* +5V */
{ 120 , 20 } , /* +12V */
{ 45 , 45 } , /* Vtt */
} ;
2009-01-16 00:27:47 +03:00
2009-12-09 22:36:07 +03:00
static inline int reg2volt ( int channel , u16 reg , u8 bypass_attn )
2009-01-16 00:27:47 +03:00
{
2009-12-09 22:36:03 +03:00
const int * r = adt7473_in_scaling [ channel ] ;
2009-01-16 00:27:47 +03:00
2009-12-09 22:36:07 +03:00
if ( bypass_attn & ( 1 < < channel ) )
return DIV_ROUND_CLOSEST ( reg * 2250 , 1024 ) ;
2009-12-09 22:36:03 +03:00
return DIV_ROUND_CLOSEST ( reg * ( r [ 0 ] + r [ 1 ] ) * 2250 , r [ 1 ] * 1024 ) ;
2009-01-16 00:27:47 +03:00
}
2009-12-09 22:36:07 +03:00
static inline u16 volt2reg ( int channel , long volt , u8 bypass_attn )
2009-01-16 00:27:47 +03:00
{
2009-12-09 22:36:03 +03:00
const int * r = adt7473_in_scaling [ channel ] ;
long reg ;
2009-12-09 22:36:07 +03:00
if ( bypass_attn & ( 1 < < channel ) )
2019-12-06 02:16:59 +03:00
reg = DIV_ROUND_CLOSEST ( volt * 1024 , 2250 ) ;
2009-12-09 22:36:07 +03:00
else
2019-12-06 02:16:59 +03:00
reg = DIV_ROUND_CLOSEST ( volt * r [ 1 ] * 1024 ,
( r [ 0 ] + r [ 1 ] ) * 2250 ) ;
2013-01-09 20:09:34 +04:00
return clamp_val ( reg , 0 , 1023 ) & ( 0xff < < 2 ) ;
2009-01-16 00:27:47 +03:00
}
2018-08-14 13:07:47 +03:00
static int adt7475_read_word ( struct i2c_client * client , int reg )
2009-01-16 00:27:47 +03:00
{
2018-08-14 13:07:47 +03:00
int val1 , val2 ;
2009-01-16 00:27:47 +03:00
2018-08-14 13:07:47 +03:00
val1 = i2c_smbus_read_byte_data ( client , reg ) ;
if ( val1 < 0 )
return val1 ;
val2 = i2c_smbus_read_byte_data ( client , reg + 1 ) ;
if ( val2 < 0 )
return val2 ;
2009-01-16 00:27:47 +03:00
2018-08-14 13:07:47 +03:00
return val1 | ( val2 < < 8 ) ;
2009-01-16 00:27:47 +03:00
}
static void adt7475_write_word ( struct i2c_client * client , int reg , u16 val )
{
i2c_smbus_write_byte_data ( client , reg + 1 , val > > 8 ) ;
i2c_smbus_write_byte_data ( client , reg , val & 0xFF ) ;
}
2018-12-11 01:02:02 +03:00
static ssize_t voltage_show ( struct device * dev , struct device_attribute * attr ,
2009-01-16 00:27:47 +03:00
char * buf )
{
struct adt7475_data * data = adt7475_update_device ( dev ) ;
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
unsigned short val ;
2018-08-08 04:32:19 +03:00
if ( IS_ERR ( data ) )
return PTR_ERR ( data ) ;
2009-01-16 00:27:47 +03:00
switch ( sattr - > nr ) {
case ALARM :
return sprintf ( buf , " %d \n " ,
2009-12-09 22:36:03 +03:00
( data - > alarms > > sattr - > index ) & 1 ) ;
2009-01-16 00:27:47 +03:00
default :
val = data - > voltage [ sattr - > nr ] [ sattr - > index ] ;
2009-12-09 22:36:07 +03:00
return sprintf ( buf , " %d \n " ,
reg2volt ( sattr - > index , val , data - > bypass_attn ) ) ;
2009-01-16 00:27:47 +03:00
}
}
2018-12-11 01:02:02 +03:00
static ssize_t voltage_store ( struct device * dev ,
struct device_attribute * attr , const char * buf ,
size_t count )
2009-01-16 00:27:47 +03:00
{
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
2019-07-22 01:55:30 +03:00
struct adt7475_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2009-01-16 00:27:47 +03:00
unsigned char reg ;
long val ;
2012-01-04 23:58:52 +04:00
if ( kstrtol ( buf , 10 , & val ) )
2009-01-16 00:27:47 +03:00
return - EINVAL ;
mutex_lock ( & data - > lock ) ;
2009-12-09 22:36:07 +03:00
data - > voltage [ sattr - > nr ] [ sattr - > index ] =
volt2reg ( sattr - > index , val , data - > bypass_attn ) ;
2009-01-16 00:27:47 +03:00
2009-12-09 22:36:05 +03:00
if ( sattr - > index < ADT7475_VOLTAGE_COUNT ) {
if ( sattr - > nr = = MIN )
reg = VOLTAGE_MIN_REG ( sattr - > index ) ;
else
reg = VOLTAGE_MAX_REG ( sattr - > index ) ;
} else {
if ( sattr - > nr = = MIN )
reg = REG_VTT_MIN ;
else
reg = REG_VTT_MAX ;
}
2009-01-16 00:27:47 +03:00
i2c_smbus_write_byte_data ( client , reg ,
data - > voltage [ sattr - > nr ] [ sattr - > index ] > > 2 ) ;
mutex_unlock ( & data - > lock ) ;
return count ;
}
2018-12-11 01:02:02 +03:00
static ssize_t temp_show ( struct device * dev , struct device_attribute * attr ,
2009-01-16 00:27:47 +03:00
char * buf )
{
struct adt7475_data * data = adt7475_update_device ( dev ) ;
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
int out ;
2018-08-08 04:32:19 +03:00
if ( IS_ERR ( data ) )
return PTR_ERR ( data ) ;
2009-01-16 00:27:47 +03:00
switch ( sattr - > nr ) {
case HYSTERSIS :
mutex_lock ( & data - > lock ) ;
out = data - > temp [ sattr - > nr ] [ sattr - > index ] ;
if ( sattr - > index ! = 1 )
out = ( out > > 4 ) & 0xF ;
else
out = ( out & 0xF ) ;
2012-01-19 23:02:15 +04:00
/*
* Show the value as an absolute number tied to
* THERM
*/
2009-01-16 00:27:47 +03:00
out = reg2temp ( data , data - > temp [ THERM ] [ sattr - > index ] ) -
out * 1000 ;
mutex_unlock ( & data - > lock ) ;
break ;
case OFFSET :
2012-01-19 23:02:15 +04:00
/*
* Offset is always 2 ' s complement , regardless of the
* setting in CONFIG5
*/
2009-01-16 00:27:47 +03:00
mutex_lock ( & data - > lock ) ;
out = ( s8 ) data - > temp [ sattr - > nr ] [ sattr - > index ] ;
if ( data - > config5 & CONFIG5_TEMPOFFSET )
out * = 1000 ;
else
out * = 500 ;
mutex_unlock ( & data - > lock ) ;
break ;
case ALARM :
out = ( data - > alarms > > ( sattr - > index + 4 ) ) & 1 ;
break ;
case FAULT :
/* Note - only for remote1 and remote2 */
2009-11-16 14:45:39 +03:00
out = ! ! ( data - > alarms & ( sattr - > index ? 0x8000 : 0x4000 ) ) ;
2009-01-16 00:27:47 +03:00
break ;
default :
/* All other temp values are in the configured format */
out = reg2temp ( data , data - > temp [ sattr - > nr ] [ sattr - > index ] ) ;
}
return sprintf ( buf , " %d \n " , out ) ;
}
2018-12-11 01:02:02 +03:00
static ssize_t temp_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2009-01-16 00:27:47 +03:00
{
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
2019-07-22 01:55:30 +03:00
struct adt7475_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2009-01-16 00:27:47 +03:00
unsigned char reg = 0 ;
u8 out ;
int temp ;
long val ;
2012-01-04 23:58:52 +04:00
if ( kstrtol ( buf , 10 , & val ) )
2009-01-16 00:27:47 +03:00
return - EINVAL ;
mutex_lock ( & data - > lock ) ;
/* We need the config register in all cases for temp <-> reg conv. */
data - > config5 = adt7475_read ( REG_CONFIG5 ) ;
switch ( sattr - > nr ) {
case OFFSET :
if ( data - > config5 & CONFIG5_TEMPOFFSET ) {
2013-01-09 20:09:34 +04:00
val = clamp_val ( val , - 63000 , 127000 ) ;
2009-01-16 00:27:47 +03:00
out = data - > temp [ OFFSET ] [ sattr - > index ] = val / 1000 ;
} else {
2013-01-09 20:09:34 +04:00
val = clamp_val ( val , - 63000 , 64000 ) ;
2009-01-16 00:27:47 +03:00
out = data - > temp [ OFFSET ] [ sattr - > index ] = val / 500 ;
}
break ;
case HYSTERSIS :
2012-01-19 23:02:15 +04:00
/*
* The value will be given as an absolute value , turn it
* into an offset based on THERM
*/
2009-01-16 00:27:47 +03:00
/* Read fresh THERM and HYSTERSIS values from the chip */
data - > temp [ THERM ] [ sattr - > index ] =
adt7475_read ( TEMP_THERM_REG ( sattr - > index ) ) < < 2 ;
adt7475_read_hystersis ( client ) ;
temp = reg2temp ( data , data - > temp [ THERM ] [ sattr - > index ] ) ;
2013-01-09 20:09:34 +04:00
val = clamp_val ( val , temp - 15000 , temp ) ;
2009-01-16 00:27:47 +03:00
val = ( temp - val ) / 1000 ;
if ( sattr - > index ! = 1 ) {
data - > temp [ HYSTERSIS ] [ sattr - > index ] & = 0xF0 ;
data - > temp [ HYSTERSIS ] [ sattr - > index ] | = ( val & 0xF ) < < 4 ;
} else {
data - > temp [ HYSTERSIS ] [ sattr - > index ] & = 0x0F ;
data - > temp [ HYSTERSIS ] [ sattr - > index ] | = ( val & 0xF ) ;
}
out = data - > temp [ HYSTERSIS ] [ sattr - > index ] ;
break ;
default :
data - > temp [ sattr - > nr ] [ sattr - > index ] = temp2reg ( data , val ) ;
2012-01-19 23:02:15 +04:00
/*
* We maintain an extra 2 digits of precision for simplicity
* - shift those back off before writing the value
*/
2009-01-16 00:27:47 +03:00
out = ( u8 ) ( data - > temp [ sattr - > nr ] [ sattr - > index ] > > 2 ) ;
}
switch ( sattr - > nr ) {
case MIN :
reg = TEMP_MIN_REG ( sattr - > index ) ;
break ;
case MAX :
reg = TEMP_MAX_REG ( sattr - > index ) ;
break ;
case OFFSET :
reg = TEMP_OFFSET_REG ( sattr - > index ) ;
break ;
case AUTOMIN :
reg = TEMP_TMIN_REG ( sattr - > index ) ;
break ;
case THERM :
reg = TEMP_THERM_REG ( sattr - > index ) ;
break ;
case HYSTERSIS :
if ( sattr - > index ! = 2 )
reg = REG_REMOTE1_HYSTERSIS ;
else
reg = REG_REMOTE2_HYSTERSIS ;
break ;
}
i2c_smbus_write_byte_data ( client , reg , out ) ;
mutex_unlock ( & data - > lock ) ;
return count ;
}
2017-05-15 04:30:28 +03:00
/* Assuming CONFIG6[SLOW] is 0 */
static const int ad7475_st_map [ ] = {
37500 , 18800 , 12500 , 7500 , 4700 , 3100 , 1600 , 800 ,
} ;
2018-12-11 01:02:02 +03:00
static ssize_t temp_st_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
2017-05-15 04:30:28 +03:00
{
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
2019-07-22 01:55:30 +03:00
struct adt7475_data * data = dev_get_drvdata ( dev ) ;
2017-05-15 04:30:28 +03:00
long val ;
switch ( sattr - > index ) {
case 0 :
val = data - > enh_acoustics [ 0 ] & 0xf ;
break ;
case 1 :
val = ( data - > enh_acoustics [ 1 ] > > 4 ) & 0xf ;
break ;
case 2 :
default :
val = data - > enh_acoustics [ 1 ] & 0xf ;
break ;
}
if ( val & 0x8 )
return sprintf ( buf , " %d \n " , ad7475_st_map [ val & 0x7 ] ) ;
else
return sprintf ( buf , " 0 \n " ) ;
}
2018-12-11 01:02:02 +03:00
static ssize_t temp_st_store ( struct device * dev ,
struct device_attribute * attr , const char * buf ,
size_t count )
2017-05-15 04:30:28 +03:00
{
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
2019-07-22 01:55:30 +03:00
struct adt7475_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2017-05-15 04:30:28 +03:00
unsigned char reg ;
int shift , idx ;
ulong val ;
if ( kstrtoul ( buf , 10 , & val ) )
return - EINVAL ;
switch ( sattr - > index ) {
case 0 :
reg = REG_ENHANCE_ACOUSTICS1 ;
shift = 0 ;
idx = 0 ;
break ;
case 1 :
reg = REG_ENHANCE_ACOUSTICS2 ;
shift = 0 ;
idx = 1 ;
break ;
case 2 :
default :
reg = REG_ENHANCE_ACOUSTICS2 ;
shift = 4 ;
idx = 1 ;
break ;
}
if ( val > 0 ) {
val = find_closest_descending ( val , ad7475_st_map ,
ARRAY_SIZE ( ad7475_st_map ) ) ;
val | = 0x8 ;
}
mutex_lock ( & data - > lock ) ;
data - > enh_acoustics [ idx ] & = ~ ( 0xf < < shift ) ;
data - > enh_acoustics [ idx ] | = ( val < < shift ) ;
i2c_smbus_write_byte_data ( client , reg , data - > enh_acoustics [ idx ] ) ;
mutex_unlock ( & data - > lock ) ;
return count ;
}
2012-01-19 23:02:15 +04:00
/*
* Table of autorange values - the user will write the value in millidegrees ,
* and we ' ll convert it
*/
2009-01-16 00:27:47 +03:00
static const int autorange_table [ ] = {
2000 , 2500 , 3330 , 4000 , 5000 , 6670 , 8000 ,
10000 , 13330 , 16000 , 20000 , 26670 , 32000 , 40000 ,
53330 , 80000
} ;
2018-12-11 01:02:02 +03:00
static ssize_t point2_show ( struct device * dev , struct device_attribute * attr ,
2009-01-16 00:27:47 +03:00
char * buf )
{
struct adt7475_data * data = adt7475_update_device ( dev ) ;
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
int out , val ;
2018-08-08 04:32:19 +03:00
if ( IS_ERR ( data ) )
return PTR_ERR ( data ) ;
2009-01-16 00:27:47 +03:00
mutex_lock ( & data - > lock ) ;
out = ( data - > range [ sattr - > index ] > > 4 ) & 0x0F ;
val = reg2temp ( data , data - > temp [ AUTOMIN ] [ sattr - > index ] ) ;
mutex_unlock ( & data - > lock ) ;
return sprintf ( buf , " %d \n " , val + autorange_table [ out ] ) ;
}
2018-12-11 01:02:02 +03:00
static ssize_t point2_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2009-01-16 00:27:47 +03:00
{
2019-07-22 01:55:30 +03:00
struct adt7475_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2009-01-16 00:27:47 +03:00
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
int temp ;
long val ;
2012-01-04 23:58:52 +04:00
if ( kstrtol ( buf , 10 , & val ) )
2009-01-16 00:27:47 +03:00
return - EINVAL ;
mutex_lock ( & data - > lock ) ;
/* Get a fresh copy of the needed registers */
data - > config5 = adt7475_read ( REG_CONFIG5 ) ;
data - > temp [ AUTOMIN ] [ sattr - > index ] =
adt7475_read ( TEMP_TMIN_REG ( sattr - > index ) ) < < 2 ;
data - > range [ sattr - > index ] =
adt7475_read ( TEMP_TRANGE_REG ( sattr - > index ) ) ;
2012-01-19 23:02:15 +04:00
/*
* The user will write an absolute value , so subtract the start point
* to figure the range
*/
2009-01-16 00:27:47 +03:00
temp = reg2temp ( data , data - > temp [ AUTOMIN ] [ sattr - > index ] ) ;
2013-01-09 20:09:34 +04:00
val = clamp_val ( val , temp + autorange_table [ 0 ] ,
2009-01-16 00:27:47 +03:00
temp + autorange_table [ ARRAY_SIZE ( autorange_table ) - 1 ] ) ;
val - = temp ;
/* Find the nearest table entry to what the user wrote */
2017-05-11 06:45:21 +03:00
val = find_closest ( val , autorange_table , ARRAY_SIZE ( autorange_table ) ) ;
2009-01-16 00:27:47 +03:00
data - > range [ sattr - > index ] & = ~ 0xF0 ;
data - > range [ sattr - > index ] | = val < < 4 ;
i2c_smbus_write_byte_data ( client , TEMP_TRANGE_REG ( sattr - > index ) ,
data - > range [ sattr - > index ] ) ;
mutex_unlock ( & data - > lock ) ;
return count ;
}
2018-12-11 01:02:02 +03:00
static ssize_t tach_show ( struct device * dev , struct device_attribute * attr ,
2009-01-16 00:27:47 +03:00
char * buf )
{
struct adt7475_data * data = adt7475_update_device ( dev ) ;
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
int out ;
2018-08-08 04:32:19 +03:00
if ( IS_ERR ( data ) )
return PTR_ERR ( data ) ;
2009-01-16 00:27:47 +03:00
if ( sattr - > nr = = ALARM )
out = ( data - > alarms > > ( sattr - > index + 10 ) ) & 1 ;
else
out = tach2rpm ( data - > tach [ sattr - > nr ] [ sattr - > index ] ) ;
return sprintf ( buf , " %d \n " , out ) ;
}
2018-12-11 01:02:02 +03:00
static ssize_t tach_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2009-01-16 00:27:47 +03:00
{
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
2019-07-22 01:55:30 +03:00
struct adt7475_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2009-01-16 00:27:47 +03:00
unsigned long val ;
2012-01-04 23:58:52 +04:00
if ( kstrtoul ( buf , 10 , & val ) )
2009-01-16 00:27:47 +03:00
return - EINVAL ;
mutex_lock ( & data - > lock ) ;
data - > tach [ MIN ] [ sattr - > index ] = rpm2tach ( val ) ;
adt7475_write_word ( client , TACH_MIN_REG ( sattr - > index ) ,
data - > tach [ MIN ] [ sattr - > index ] ) ;
mutex_unlock ( & data - > lock ) ;
return count ;
}
2018-12-11 01:02:02 +03:00
static ssize_t pwm_show ( struct device * dev , struct device_attribute * attr ,
2009-01-16 00:27:47 +03:00
char * buf )
{
struct adt7475_data * data = adt7475_update_device ( dev ) ;
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
2018-08-08 04:32:19 +03:00
if ( IS_ERR ( data ) )
return PTR_ERR ( data ) ;
2009-01-16 00:27:47 +03:00
return sprintf ( buf , " %d \n " , data - > pwm [ sattr - > nr ] [ sattr - > index ] ) ;
}
2018-12-11 01:02:02 +03:00
static ssize_t pwmchan_show ( struct device * dev , struct device_attribute * attr ,
2009-01-16 00:27:47 +03:00
char * buf )
{
struct adt7475_data * data = adt7475_update_device ( dev ) ;
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
2018-08-08 04:32:19 +03:00
if ( IS_ERR ( data ) )
return PTR_ERR ( data ) ;
2009-01-16 00:27:47 +03:00
return sprintf ( buf , " %d \n " , data - > pwmchan [ sattr - > index ] ) ;
}
2018-12-11 01:02:02 +03:00
static ssize_t pwmctrl_show ( struct device * dev , struct device_attribute * attr ,
2009-01-16 00:27:47 +03:00
char * buf )
{
struct adt7475_data * data = adt7475_update_device ( dev ) ;
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
2018-08-08 04:32:19 +03:00
if ( IS_ERR ( data ) )
return PTR_ERR ( data ) ;
2009-01-16 00:27:47 +03:00
return sprintf ( buf , " %d \n " , data - > pwmctl [ sattr - > index ] ) ;
}
2018-12-11 01:02:02 +03:00
static ssize_t pwm_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2009-01-16 00:27:47 +03:00
{
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
2019-07-22 01:55:30 +03:00
struct adt7475_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2009-01-16 00:27:47 +03:00
unsigned char reg = 0 ;
long val ;
2012-01-04 23:58:52 +04:00
if ( kstrtol ( buf , 10 , & val ) )
2009-01-16 00:27:47 +03:00
return - EINVAL ;
mutex_lock ( & data - > lock ) ;
switch ( sattr - > nr ) {
case INPUT :
/* Get a fresh value for CONTROL */
data - > pwm [ CONTROL ] [ sattr - > index ] =
adt7475_read ( PWM_CONFIG_REG ( sattr - > index ) ) ;
2012-01-19 23:02:15 +04:00
/*
* If we are not in manual mode , then we shouldn ' t allow
* the user to set the pwm speed
*/
2009-01-16 00:27:47 +03:00
if ( ( ( data - > pwm [ CONTROL ] [ sattr - > index ] > > 5 ) & 7 ) ! = 7 ) {
mutex_unlock ( & data - > lock ) ;
return count ;
}
reg = PWM_REG ( sattr - > index ) ;
break ;
case MIN :
reg = PWM_MIN_REG ( sattr - > index ) ;
break ;
case MAX :
reg = PWM_MAX_REG ( sattr - > index ) ;
break ;
}
2013-01-09 20:09:34 +04:00
data - > pwm [ sattr - > nr ] [ sattr - > index ] = clamp_val ( val , 0 , 0xFF ) ;
2009-01-16 00:27:47 +03:00
i2c_smbus_write_byte_data ( client , reg ,
data - > pwm [ sattr - > nr ] [ sattr - > index ] ) ;
2017-05-15 04:30:27 +03:00
mutex_unlock ( & data - > lock ) ;
return count ;
}
2018-12-11 01:02:02 +03:00
static ssize_t stall_disable_show ( struct device * dev ,
2017-05-15 04:30:27 +03:00
struct device_attribute * attr , char * buf )
{
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
2019-07-22 01:55:30 +03:00
struct adt7475_data * data = dev_get_drvdata ( dev ) ;
2017-05-15 04:30:27 +03:00
u8 mask = BIT ( 5 + sattr - > index ) ;
return sprintf ( buf , " %d \n " , ! ! ( data - > enh_acoustics [ 0 ] & mask ) ) ;
}
2018-12-11 01:02:02 +03:00
static ssize_t stall_disable_store ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
2017-05-15 04:30:27 +03:00
{
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
2019-07-22 01:55:30 +03:00
struct adt7475_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2017-05-15 04:30:27 +03:00
long val ;
u8 mask = BIT ( 5 + sattr - > index ) ;
if ( kstrtol ( buf , 10 , & val ) )
return - EINVAL ;
mutex_lock ( & data - > lock ) ;
data - > enh_acoustics [ 0 ] & = ~ mask ;
if ( val )
data - > enh_acoustics [ 0 ] | = mask ;
i2c_smbus_write_byte_data ( client , REG_ENHANCE_ACOUSTICS1 ,
data - > enh_acoustics [ 0 ] ) ;
2009-01-16 00:27:47 +03:00
mutex_unlock ( & data - > lock ) ;
return count ;
}
/* Called by set_pwmctrl and set_pwmchan */
static int hw_set_pwm ( struct i2c_client * client , int index ,
unsigned int pwmctl , unsigned int pwmchan )
{
struct adt7475_data * data = i2c_get_clientdata ( client ) ;
long val = 0 ;
switch ( pwmctl ) {
case 0 :
val = 0x03 ; /* Run at full speed */
break ;
case 1 :
val = 0x07 ; /* Manual mode */
break ;
case 2 :
switch ( pwmchan ) {
case 1 :
/* Remote1 controls PWM */
val = 0x00 ;
break ;
case 2 :
/* local controls PWM */
val = 0x01 ;
break ;
case 4 :
/* remote2 controls PWM */
val = 0x02 ;
break ;
case 6 :
/* local/remote2 control PWM */
val = 0x05 ;
break ;
case 7 :
/* All three control PWM */
val = 0x06 ;
break ;
default :
return - EINVAL ;
}
break ;
default :
return - EINVAL ;
}
data - > pwmctl [ index ] = pwmctl ;
data - > pwmchan [ index ] = pwmchan ;
data - > pwm [ CONTROL ] [ index ] & = ~ 0xE0 ;
data - > pwm [ CONTROL ] [ index ] | = ( val & 7 ) < < 5 ;
i2c_smbus_write_byte_data ( client , PWM_CONFIG_REG ( index ) ,
data - > pwm [ CONTROL ] [ index ] ) ;
return 0 ;
}
2018-12-11 01:02:02 +03:00
static ssize_t pwmchan_store ( struct device * dev ,
struct device_attribute * attr , const char * buf ,
size_t count )
2009-01-16 00:27:47 +03:00
{
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
2019-07-22 01:55:30 +03:00
struct adt7475_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2009-01-16 00:27:47 +03:00
int r ;
long val ;
2012-01-04 23:58:52 +04:00
if ( kstrtol ( buf , 10 , & val ) )
2009-01-16 00:27:47 +03:00
return - EINVAL ;
mutex_lock ( & data - > lock ) ;
/* Read Modify Write PWM values */
adt7475_read_pwm ( client , sattr - > index ) ;
r = hw_set_pwm ( client , sattr - > index , data - > pwmctl [ sattr - > index ] , val ) ;
if ( r )
count = r ;
mutex_unlock ( & data - > lock ) ;
return count ;
}
2018-12-11 01:02:02 +03:00
static ssize_t pwmctrl_store ( struct device * dev ,
struct device_attribute * attr , const char * buf ,
size_t count )
2009-01-16 00:27:47 +03:00
{
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
2019-07-22 01:55:30 +03:00
struct adt7475_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2009-01-16 00:27:47 +03:00
int r ;
long val ;
2012-01-04 23:58:52 +04:00
if ( kstrtol ( buf , 10 , & val ) )
2009-01-16 00:27:47 +03:00
return - EINVAL ;
mutex_lock ( & data - > lock ) ;
/* Read Modify Write PWM values */
adt7475_read_pwm ( client , sattr - > index ) ;
r = hw_set_pwm ( client , sattr - > index , val , data - > pwmchan [ sattr - > index ] ) ;
if ( r )
count = r ;
mutex_unlock ( & data - > lock ) ;
return count ;
}
/* List of frequencies for the PWM */
static const int pwmfreq_table [ ] = {
2017-05-15 04:30:29 +03:00
11 , 14 , 22 , 29 , 35 , 44 , 58 , 88 , 22500
2009-01-16 00:27:47 +03:00
} ;
2018-12-11 01:02:02 +03:00
static ssize_t pwmfreq_show ( struct device * dev , struct device_attribute * attr ,
2009-01-16 00:27:47 +03:00
char * buf )
{
struct adt7475_data * data = adt7475_update_device ( dev ) ;
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
2018-08-14 12:12:36 +03:00
int idx ;
2009-01-16 00:27:47 +03:00
2018-08-08 04:32:19 +03:00
if ( IS_ERR ( data ) )
return PTR_ERR ( data ) ;
2018-08-14 12:12:36 +03:00
idx = clamp_val ( data - > range [ sattr - > index ] & 0xf , 0 ,
ARRAY_SIZE ( pwmfreq_table ) - 1 ) ;
2018-08-08 04:32:19 +03:00
2018-08-14 12:12:36 +03:00
return sprintf ( buf , " %d \n " , pwmfreq_table [ idx ] ) ;
2009-01-16 00:27:47 +03:00
}
2018-12-11 01:02:02 +03:00
static ssize_t pwmfreq_store ( struct device * dev ,
struct device_attribute * attr , const char * buf ,
size_t count )
2009-01-16 00:27:47 +03:00
{
struct sensor_device_attribute_2 * sattr = to_sensor_dev_attr_2 ( attr ) ;
2019-07-22 01:55:30 +03:00
struct adt7475_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2009-01-16 00:27:47 +03:00
int out ;
long val ;
2012-01-04 23:58:52 +04:00
if ( kstrtol ( buf , 10 , & val ) )
2009-01-16 00:27:47 +03:00
return - EINVAL ;
2017-05-11 06:45:21 +03:00
out = find_closest ( val , pwmfreq_table , ARRAY_SIZE ( pwmfreq_table ) ) ;
2009-01-16 00:27:47 +03:00
mutex_lock ( & data - > lock ) ;
data - > range [ sattr - > index ] =
adt7475_read ( TEMP_TRANGE_REG ( sattr - > index ) ) ;
2017-05-15 04:30:29 +03:00
data - > range [ sattr - > index ] & = ~ 0xf ;
2009-01-16 00:27:47 +03:00
data - > range [ sattr - > index ] | = out ;
i2c_smbus_write_byte_data ( client , TEMP_TRANGE_REG ( sattr - > index ) ,
data - > range [ sattr - > index ] ) ;
mutex_unlock ( & data - > lock ) ;
return count ;
}
2016-12-22 15:05:33 +03:00
static ssize_t pwm_use_point2_pwm_at_crit_show ( struct device * dev ,
struct device_attribute * devattr ,
char * buf )
2009-12-09 22:36:03 +03:00
{
struct adt7475_data * data = adt7475_update_device ( dev ) ;
2018-08-14 12:12:36 +03:00
if ( IS_ERR ( data ) )
return PTR_ERR ( data ) ;
2009-12-09 22:36:03 +03:00
return sprintf ( buf , " %d \n " , ! ! ( data - > config4 & CONFIG4_MAXDUTY ) ) ;
}
2016-12-22 15:05:33 +03:00
static ssize_t pwm_use_point2_pwm_at_crit_store ( struct device * dev ,
struct device_attribute * devattr ,
const char * buf , size_t count )
2009-12-09 22:36:03 +03:00
{
2019-07-22 01:55:30 +03:00
struct adt7475_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2009-12-09 22:36:03 +03:00
long val ;
2012-01-04 23:58:52 +04:00
if ( kstrtol ( buf , 10 , & val ) )
2009-12-09 22:36:03 +03:00
return - EINVAL ;
if ( val ! = 0 & & val ! = 1 )
return - EINVAL ;
mutex_lock ( & data - > lock ) ;
data - > config4 = i2c_smbus_read_byte_data ( client , REG_CONFIG4 ) ;
if ( val )
data - > config4 | = CONFIG4_MAXDUTY ;
else
data - > config4 & = ~ CONFIG4_MAXDUTY ;
i2c_smbus_write_byte_data ( client , REG_CONFIG4 , data - > config4 ) ;
mutex_unlock ( & data - > lock ) ;
return count ;
}
2016-12-22 15:05:33 +03:00
static ssize_t vrm_show ( struct device * dev , struct device_attribute * devattr ,
2009-12-09 22:36:08 +03:00
char * buf )
{
struct adt7475_data * data = dev_get_drvdata ( dev ) ;
return sprintf ( buf , " %d \n " , ( int ) data - > vrm ) ;
}
2016-12-22 15:05:33 +03:00
static ssize_t vrm_store ( struct device * dev , struct device_attribute * devattr ,
const char * buf , size_t count )
2009-12-09 22:36:08 +03:00
{
struct adt7475_data * data = dev_get_drvdata ( dev ) ;
long val ;
2012-01-04 23:58:52 +04:00
if ( kstrtol ( buf , 10 , & val ) )
2009-12-09 22:36:08 +03:00
return - EINVAL ;
if ( val < 0 | | val > 255 )
return - EINVAL ;
data - > vrm = val ;
return count ;
}
2016-12-22 15:05:33 +03:00
static ssize_t cpu0_vid_show ( struct device * dev ,
struct device_attribute * devattr , char * buf )
2009-12-09 22:36:08 +03:00
{
struct adt7475_data * data = adt7475_update_device ( dev ) ;
2018-08-08 04:32:19 +03:00
if ( IS_ERR ( data ) )
return PTR_ERR ( data ) ;
2009-12-09 22:36:08 +03:00
return sprintf ( buf , " %d \n " , vid_from_reg ( data - > vid , data - > vrm ) ) ;
}
2018-12-11 01:02:02 +03:00
static SENSOR_DEVICE_ATTR_2_RO ( in0_input , voltage , INPUT , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in0_max , voltage , MAX , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in0_min , voltage , MIN , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in0_alarm , voltage , ALARM , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in1_input , voltage , INPUT , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in1_max , voltage , MAX , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in1_min , voltage , MIN , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in1_alarm , voltage , ALARM , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in2_input , voltage , INPUT , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in2_max , voltage , MAX , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in2_min , voltage , MIN , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in2_alarm , voltage , ALARM , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in3_input , voltage , INPUT , 3 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in3_max , voltage , MAX , 3 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in3_min , voltage , MIN , 3 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in3_alarm , voltage , ALARM , 3 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in4_input , voltage , INPUT , 4 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in4_max , voltage , MAX , 4 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in4_min , voltage , MIN , 4 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in4_alarm , voltage , ALARM , 8 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in5_input , voltage , INPUT , 5 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in5_max , voltage , MAX , 5 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in5_min , voltage , MIN , 5 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in5_alarm , voltage , ALARM , 31 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( temp1_input , temp , INPUT , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( temp1_alarm , temp , ALARM , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( temp1_fault , temp , FAULT , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp1_max , temp , MAX , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp1_min , temp , MIN , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp1_offset , temp , OFFSET , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp1_auto_point1_temp , temp , AUTOMIN , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp1_auto_point2_temp , point2 , 0 , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp1_crit , temp , THERM , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp1_crit_hyst , temp , HYSTERSIS , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp1_smoothing , temp_st , 0 , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( temp2_input , temp , INPUT , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( temp2_alarm , temp , ALARM , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp2_max , temp , MAX , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp2_min , temp , MIN , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp2_offset , temp , OFFSET , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp2_auto_point1_temp , temp , AUTOMIN , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp2_auto_point2_temp , point2 , 0 , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp2_crit , temp , THERM , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp2_crit_hyst , temp , HYSTERSIS , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp2_smoothing , temp_st , 0 , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( temp3_input , temp , INPUT , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( temp3_alarm , temp , ALARM , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( temp3_fault , temp , FAULT , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp3_max , temp , MAX , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp3_min , temp , MIN , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp3_offset , temp , OFFSET , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp3_auto_point1_temp , temp , AUTOMIN , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp3_auto_point2_temp , point2 , 0 , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp3_crit , temp , THERM , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp3_crit_hyst , temp , HYSTERSIS , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( temp3_smoothing , temp_st , 0 , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( fan1_input , tach , INPUT , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( fan1_min , tach , MIN , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( fan1_alarm , tach , ALARM , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( fan2_input , tach , INPUT , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( fan2_min , tach , MIN , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( fan2_alarm , tach , ALARM , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( fan3_input , tach , INPUT , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( fan3_min , tach , MIN , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( fan3_alarm , tach , ALARM , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( fan4_input , tach , INPUT , 3 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( fan4_min , tach , MIN , 3 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( fan4_alarm , tach , ALARM , 3 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( pwm1 , pwm , INPUT , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( pwm1_freq , pwmfreq , INPUT , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( pwm1_enable , pwmctrl , INPUT , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( pwm1_auto_channels_temp , pwmchan , INPUT , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( pwm1_auto_point1_pwm , pwm , MIN , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( pwm1_auto_point2_pwm , pwm , MAX , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( pwm1_stall_disable , stall_disable , 0 , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( pwm2 , pwm , INPUT , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( pwm2_freq , pwmfreq , INPUT , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( pwm2_enable , pwmctrl , INPUT , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( pwm2_auto_channels_temp , pwmchan , INPUT , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( pwm2_auto_point1_pwm , pwm , MIN , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( pwm2_auto_point2_pwm , pwm , MAX , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( pwm2_stall_disable , stall_disable , 0 , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( pwm3 , pwm , INPUT , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( pwm3_freq , pwmfreq , INPUT , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( pwm3_enable , pwmctrl , INPUT , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( pwm3_auto_channels_temp , pwmchan , INPUT , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( pwm3_auto_point1_pwm , pwm , MIN , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( pwm3_auto_point2_pwm , pwm , MAX , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( pwm3_stall_disable , stall_disable , 0 , 2 ) ;
2009-01-16 00:27:47 +03:00
2009-12-09 22:36:03 +03:00
/* Non-standard name, might need revisiting */
2016-12-22 15:05:33 +03:00
static DEVICE_ATTR_RW ( pwm_use_point2_pwm_at_crit ) ;
2009-12-09 22:36:03 +03:00
2016-12-22 15:05:33 +03:00
static DEVICE_ATTR_RW ( vrm ) ;
static DEVICE_ATTR_RO ( cpu0_vid ) ;
2009-12-09 22:36:08 +03:00
2009-01-16 00:27:47 +03:00
static struct attribute * adt7475_attrs [ ] = {
& sensor_dev_attr_in1_input . dev_attr . attr ,
& sensor_dev_attr_in1_max . dev_attr . attr ,
& sensor_dev_attr_in1_min . dev_attr . attr ,
& sensor_dev_attr_in1_alarm . dev_attr . attr ,
& sensor_dev_attr_in2_input . dev_attr . attr ,
& sensor_dev_attr_in2_max . dev_attr . attr ,
& sensor_dev_attr_in2_min . dev_attr . attr ,
& sensor_dev_attr_in2_alarm . dev_attr . attr ,
& sensor_dev_attr_temp1_input . dev_attr . attr ,
& sensor_dev_attr_temp1_alarm . dev_attr . attr ,
& sensor_dev_attr_temp1_fault . dev_attr . attr ,
& sensor_dev_attr_temp1_max . dev_attr . attr ,
& sensor_dev_attr_temp1_min . dev_attr . attr ,
& sensor_dev_attr_temp1_offset . dev_attr . attr ,
& sensor_dev_attr_temp1_auto_point1_temp . dev_attr . attr ,
& sensor_dev_attr_temp1_auto_point2_temp . dev_attr . attr ,
& sensor_dev_attr_temp1_crit . dev_attr . attr ,
& sensor_dev_attr_temp1_crit_hyst . dev_attr . attr ,
2017-05-15 04:30:28 +03:00
& sensor_dev_attr_temp1_smoothing . dev_attr . attr ,
2009-01-16 00:27:47 +03:00
& sensor_dev_attr_temp2_input . dev_attr . attr ,
& sensor_dev_attr_temp2_alarm . dev_attr . attr ,
& sensor_dev_attr_temp2_max . dev_attr . attr ,
& sensor_dev_attr_temp2_min . dev_attr . attr ,
& sensor_dev_attr_temp2_offset . dev_attr . attr ,
& sensor_dev_attr_temp2_auto_point1_temp . dev_attr . attr ,
& sensor_dev_attr_temp2_auto_point2_temp . dev_attr . attr ,
& sensor_dev_attr_temp2_crit . dev_attr . attr ,
& sensor_dev_attr_temp2_crit_hyst . dev_attr . attr ,
2017-05-15 04:30:28 +03:00
& sensor_dev_attr_temp2_smoothing . dev_attr . attr ,
2009-01-16 00:27:47 +03:00
& sensor_dev_attr_temp3_input . dev_attr . attr ,
& sensor_dev_attr_temp3_fault . dev_attr . attr ,
& sensor_dev_attr_temp3_alarm . dev_attr . attr ,
& sensor_dev_attr_temp3_max . dev_attr . attr ,
& sensor_dev_attr_temp3_min . dev_attr . attr ,
& sensor_dev_attr_temp3_offset . dev_attr . attr ,
& sensor_dev_attr_temp3_auto_point1_temp . dev_attr . attr ,
& sensor_dev_attr_temp3_auto_point2_temp . dev_attr . attr ,
& sensor_dev_attr_temp3_crit . dev_attr . attr ,
& sensor_dev_attr_temp3_crit_hyst . dev_attr . attr ,
2017-05-15 04:30:28 +03:00
& sensor_dev_attr_temp3_smoothing . dev_attr . attr ,
2009-01-16 00:27:47 +03:00
& sensor_dev_attr_fan1_input . dev_attr . attr ,
& sensor_dev_attr_fan1_min . dev_attr . attr ,
& sensor_dev_attr_fan1_alarm . dev_attr . attr ,
& sensor_dev_attr_fan2_input . dev_attr . attr ,
& sensor_dev_attr_fan2_min . dev_attr . attr ,
& sensor_dev_attr_fan2_alarm . dev_attr . attr ,
& sensor_dev_attr_fan3_input . dev_attr . attr ,
& sensor_dev_attr_fan3_min . dev_attr . attr ,
& sensor_dev_attr_fan3_alarm . dev_attr . attr ,
& sensor_dev_attr_pwm1 . dev_attr . attr ,
& sensor_dev_attr_pwm1_freq . dev_attr . attr ,
& sensor_dev_attr_pwm1_enable . dev_attr . attr ,
2009-11-16 14:45:40 +03:00
& sensor_dev_attr_pwm1_auto_channels_temp . dev_attr . attr ,
2009-01-16 00:27:47 +03:00
& sensor_dev_attr_pwm1_auto_point1_pwm . dev_attr . attr ,
& sensor_dev_attr_pwm1_auto_point2_pwm . dev_attr . attr ,
2017-05-15 04:30:27 +03:00
& sensor_dev_attr_pwm1_stall_disable . dev_attr . attr ,
2009-01-16 00:27:47 +03:00
& sensor_dev_attr_pwm3 . dev_attr . attr ,
& sensor_dev_attr_pwm3_freq . dev_attr . attr ,
& sensor_dev_attr_pwm3_enable . dev_attr . attr ,
2009-11-16 14:45:40 +03:00
& sensor_dev_attr_pwm3_auto_channels_temp . dev_attr . attr ,
2009-01-16 00:27:47 +03:00
& sensor_dev_attr_pwm3_auto_point1_pwm . dev_attr . attr ,
& sensor_dev_attr_pwm3_auto_point2_pwm . dev_attr . attr ,
2017-05-15 04:30:27 +03:00
& sensor_dev_attr_pwm3_stall_disable . dev_attr . attr ,
2009-12-09 22:36:03 +03:00
& dev_attr_pwm_use_point2_pwm_at_crit . attr ,
2009-01-16 00:27:47 +03:00
NULL ,
} ;
2009-12-09 22:36:06 +03:00
static struct attribute * fan4_attrs [ ] = {
& sensor_dev_attr_fan4_input . dev_attr . attr ,
& sensor_dev_attr_fan4_min . dev_attr . attr ,
& sensor_dev_attr_fan4_alarm . dev_attr . attr ,
NULL
} ;
static struct attribute * pwm2_attrs [ ] = {
& sensor_dev_attr_pwm2 . dev_attr . attr ,
& sensor_dev_attr_pwm2_freq . dev_attr . attr ,
& sensor_dev_attr_pwm2_enable . dev_attr . attr ,
& sensor_dev_attr_pwm2_auto_channels_temp . dev_attr . attr ,
& sensor_dev_attr_pwm2_auto_point1_pwm . dev_attr . attr ,
& sensor_dev_attr_pwm2_auto_point2_pwm . dev_attr . attr ,
2017-05-15 04:30:27 +03:00
& sensor_dev_attr_pwm2_stall_disable . dev_attr . attr ,
2009-12-09 22:36:06 +03:00
NULL
} ;
static struct attribute * in0_attrs [ ] = {
2009-12-09 22:36:05 +03:00
& sensor_dev_attr_in0_input . dev_attr . attr ,
& sensor_dev_attr_in0_max . dev_attr . attr ,
& sensor_dev_attr_in0_min . dev_attr . attr ,
& sensor_dev_attr_in0_alarm . dev_attr . attr ,
2009-12-09 22:36:06 +03:00
NULL
} ;
2009-12-09 22:36:08 +03:00
static struct attribute * in3_attrs [ ] = {
2009-12-09 22:36:05 +03:00
& sensor_dev_attr_in3_input . dev_attr . attr ,
& sensor_dev_attr_in3_max . dev_attr . attr ,
& sensor_dev_attr_in3_min . dev_attr . attr ,
& sensor_dev_attr_in3_alarm . dev_attr . attr ,
2009-12-09 22:36:08 +03:00
NULL
} ;
static struct attribute * in4_attrs [ ] = {
2009-12-09 22:36:05 +03:00
& sensor_dev_attr_in4_input . dev_attr . attr ,
& sensor_dev_attr_in4_max . dev_attr . attr ,
& sensor_dev_attr_in4_min . dev_attr . attr ,
& sensor_dev_attr_in4_alarm . dev_attr . attr ,
2009-12-09 22:36:08 +03:00
NULL
} ;
static struct attribute * in5_attrs [ ] = {
2009-12-09 22:36:05 +03:00
& sensor_dev_attr_in5_input . dev_attr . attr ,
& sensor_dev_attr_in5_max . dev_attr . attr ,
& sensor_dev_attr_in5_min . dev_attr . attr ,
& sensor_dev_attr_in5_alarm . dev_attr . attr ,
NULL
} ;
2009-12-09 22:36:08 +03:00
static struct attribute * vid_attrs [ ] = {
& dev_attr_cpu0_vid . attr ,
& dev_attr_vrm . attr ,
NULL
} ;
2017-07-05 08:34:04 +03:00
static const struct attribute_group adt7475_attr_group = { . attrs = adt7475_attrs } ;
static const struct attribute_group fan4_attr_group = { . attrs = fan4_attrs } ;
static const struct attribute_group pwm2_attr_group = { . attrs = pwm2_attrs } ;
static const struct attribute_group in0_attr_group = { . attrs = in0_attrs } ;
static const struct attribute_group in3_attr_group = { . attrs = in3_attrs } ;
static const struct attribute_group in4_attr_group = { . attrs = in4_attrs } ;
static const struct attribute_group in5_attr_group = { . attrs = in5_attrs } ;
static const struct attribute_group vid_attr_group = { . attrs = vid_attrs } ;
2009-01-16 00:27:47 +03:00
2009-12-14 23:17:23 +03:00
static int adt7475_detect ( struct i2c_client * client ,
2009-01-16 00:27:47 +03:00
struct i2c_board_info * info )
{
struct i2c_adapter * adapter = client - > adapter ;
2009-12-09 22:36:04 +03:00
int vendid , devid , devid2 ;
2009-12-09 22:36:02 +03:00
const char * name ;
2009-01-16 00:27:47 +03:00
if ( ! i2c_check_functionality ( adapter , I2C_FUNC_SMBUS_BYTE_DATA ) )
return - ENODEV ;
2009-12-09 22:36:02 +03:00
vendid = adt7475_read ( REG_VENDID ) ;
2009-12-09 22:36:04 +03:00
devid2 = adt7475_read ( REG_DEVID2 ) ;
if ( vendid ! = 0x41 | | /* Analog Devices */
( devid2 & 0xf8 ) ! = 0x68 )
return - ENODEV ;
2009-12-09 22:36:02 +03:00
2009-12-09 22:36:04 +03:00
devid = adt7475_read ( REG_DEVID ) ;
if ( devid = = 0x73 )
2009-12-09 22:36:02 +03:00
name = " adt7473 " ;
2009-12-09 22:36:04 +03:00
else if ( devid = = 0x75 & & client - > addr = = 0x2e )
2009-12-09 22:36:02 +03:00
name = " adt7475 " ;
2009-12-09 22:36:08 +03:00
else if ( devid = = 0x76 )
name = " adt7476 " ;
2009-12-09 22:36:05 +03:00
else if ( ( devid2 & 0xfc ) = = 0x6c )
name = " adt7490 " ;
2009-12-09 22:36:02 +03:00
else {
dev_dbg ( & adapter - > dev ,
2009-12-09 22:36:08 +03:00
" Couldn't detect an ADT7473/75/76/90 part at "
2009-12-09 22:36:02 +03:00
" 0x%02x \n " , ( unsigned int ) client - > addr ) ;
2009-12-09 22:35:57 +03:00
return - ENODEV ;
2009-01-16 00:27:47 +03:00
}
2009-12-09 22:36:02 +03:00
strlcpy ( info - > type , name , I2C_NAME_SIZE ) ;
2009-01-16 00:27:47 +03:00
return 0 ;
}
2018-08-08 04:32:18 +03:00
static int adt7475_update_limits ( struct i2c_client * client )
2018-08-08 04:32:16 +03:00
{
struct adt7475_data * data = i2c_get_clientdata ( client ) ;
int i ;
2018-08-08 04:32:18 +03:00
int ret ;
2018-08-08 04:32:16 +03:00
2018-08-08 04:32:18 +03:00
ret = adt7475_read ( REG_CONFIG4 ) ;
if ( ret < 0 )
return ret ;
data - > config4 = ret ;
ret = adt7475_read ( REG_CONFIG5 ) ;
if ( ret < 0 )
return ret ;
data - > config5 = ret ;
2018-08-08 04:32:16 +03:00
for ( i = 0 ; i < ADT7475_VOLTAGE_COUNT ; i + + ) {
if ( ! ( data - > has_voltage & ( 1 < < i ) ) )
continue ;
/* Adjust values so they match the input precision */
2018-08-08 04:32:18 +03:00
ret = adt7475_read ( VOLTAGE_MIN_REG ( i ) ) ;
if ( ret < 0 )
return ret ;
data - > voltage [ MIN ] [ i ] = ret < < 2 ;
ret = adt7475_read ( VOLTAGE_MAX_REG ( i ) ) ;
if ( ret < 0 )
return ret ;
data - > voltage [ MAX ] [ i ] = ret < < 2 ;
2018-08-08 04:32:16 +03:00
}
if ( data - > has_voltage & ( 1 < < 5 ) ) {
2018-08-08 04:32:18 +03:00
ret = adt7475_read ( REG_VTT_MIN ) ;
if ( ret < 0 )
return ret ;
data - > voltage [ MIN ] [ 5 ] = ret < < 2 ;
ret = adt7475_read ( REG_VTT_MAX ) ;
if ( ret < 0 )
return ret ;
data - > voltage [ MAX ] [ 5 ] = ret < < 2 ;
2018-08-08 04:32:16 +03:00
}
for ( i = 0 ; i < ADT7475_TEMP_COUNT ; i + + ) {
/* Adjust values so they match the input precision */
2018-08-08 04:32:18 +03:00
ret = adt7475_read ( TEMP_MIN_REG ( i ) ) ;
if ( ret < 0 )
return ret ;
data - > temp [ MIN ] [ i ] = ret < < 2 ;
ret = adt7475_read ( TEMP_MAX_REG ( i ) ) ;
if ( ret < 0 )
return ret ;
data - > temp [ MAX ] [ i ] = ret < < 2 ;
ret = adt7475_read ( TEMP_TMIN_REG ( i ) ) ;
if ( ret < 0 )
return ret ;
data - > temp [ AUTOMIN ] [ i ] = ret < < 2 ;
ret = adt7475_read ( TEMP_THERM_REG ( i ) ) ;
if ( ret < 0 )
return ret ;
data - > temp [ THERM ] [ i ] = ret < < 2 ;
ret = adt7475_read ( TEMP_OFFSET_REG ( i ) ) ;
if ( ret < 0 )
return ret ;
data - > temp [ OFFSET ] [ i ] = ret ;
2018-08-08 04:32:16 +03:00
}
adt7475_read_hystersis ( client ) ;
for ( i = 0 ; i < ADT7475_TACH_COUNT ; i + + ) {
if ( i = = 3 & & ! data - > has_fan4 )
continue ;
2018-08-08 04:32:18 +03:00
ret = adt7475_read_word ( client , TACH_MIN_REG ( i ) ) ;
if ( ret < 0 )
return ret ;
data - > tach [ MIN ] [ i ] = ret ;
2018-08-08 04:32:16 +03:00
}
for ( i = 0 ; i < ADT7475_PWM_COUNT ; i + + ) {
if ( i = = 1 & & ! data - > has_pwm2 )
continue ;
2018-08-08 04:32:18 +03:00
ret = adt7475_read ( PWM_MAX_REG ( i ) ) ;
if ( ret < 0 )
return ret ;
data - > pwm [ MAX ] [ i ] = ret ;
ret = adt7475_read ( PWM_MIN_REG ( i ) ) ;
if ( ret < 0 )
return ret ;
data - > pwm [ MIN ] [ i ] = ret ;
2018-08-08 04:32:16 +03:00
/* Set the channel and control information */
adt7475_read_pwm ( client , i ) ;
}
2018-08-08 04:32:18 +03:00
ret = adt7475_read ( TEMP_TRANGE_REG ( 0 ) ) ;
if ( ret < 0 )
return ret ;
data - > range [ 0 ] = ret ;
ret = adt7475_read ( TEMP_TRANGE_REG ( 1 ) ) ;
if ( ret < 0 )
return ret ;
data - > range [ 1 ] = ret ;
ret = adt7475_read ( TEMP_TRANGE_REG ( 2 ) ) ;
if ( ret < 0 )
return ret ;
data - > range [ 2 ] = ret ;
return 0 ;
2018-08-08 04:32:16 +03:00
}
2020-02-27 11:46:41 +03:00
static int set_property_bit ( const struct i2c_client * client , char * property ,
u8 * config , u8 bit_index )
{
u32 prop_value = 0 ;
int ret = of_property_read_u32 ( client - > dev . of_node , property ,
& prop_value ) ;
if ( ! ret ) {
if ( prop_value )
* config | = ( 1 < < bit_index ) ;
else
* config & = ~ ( 1 < < bit_index ) ;
}
return ret ;
}
static int load_attenuators ( const struct i2c_client * client , int chip ,
struct adt7475_data * data )
{
int ret ;
if ( chip = = adt7476 | | chip = = adt7490 ) {
set_property_bit ( client , " adi,bypass-attenuator-in0 " ,
& data - > config4 , 4 ) ;
set_property_bit ( client , " adi,bypass-attenuator-in1 " ,
& data - > config4 , 5 ) ;
set_property_bit ( client , " adi,bypass-attenuator-in3 " ,
& data - > config4 , 6 ) ;
set_property_bit ( client , " adi,bypass-attenuator-in4 " ,
& data - > config4 , 7 ) ;
ret = i2c_smbus_write_byte_data ( client , REG_CONFIG4 ,
data - > config4 ) ;
if ( ret < 0 )
return ret ;
} else if ( chip = = adt7473 | | chip = = adt7475 ) {
set_property_bit ( client , " adi,bypass-attenuator-in1 " ,
& data - > config2 , 5 ) ;
ret = i2c_smbus_write_byte_data ( client , REG_CONFIG2 ,
data - > config2 ) ;
if ( ret < 0 )
return ret ;
}
return 0 ;
}
2020-02-27 11:46:42 +03:00
static int adt7475_set_pwm_polarity ( struct i2c_client * client )
{
u32 states [ ADT7475_PWM_COUNT ] ;
int ret , i ;
u8 val ;
ret = of_property_read_u32_array ( client - > dev . of_node ,
" adi,pwm-active-state " , states ,
ARRAY_SIZE ( states ) ) ;
if ( ret )
return ret ;
for ( i = 0 ; i < ADT7475_PWM_COUNT ; i + + ) {
ret = adt7475_read ( PWM_CONFIG_REG ( i ) ) ;
if ( ret < 0 )
return ret ;
val = ret ;
if ( states [ i ] )
val & = ~ BIT ( 4 ) ;
else
val | = BIT ( 4 ) ;
ret = i2c_smbus_write_byte_data ( client , PWM_CONFIG_REG ( i ) , val ) ;
if ( ret )
return ret ;
}
return 0 ;
}
2020-08-13 19:02:22 +03:00
static int adt7475_probe ( struct i2c_client * client )
2009-01-16 00:27:47 +03:00
{
2017-02-24 16:12:58 +03:00
enum chips chip ;
2012-01-08 22:34:08 +04:00
static const char * const names [ ] = {
2009-12-09 22:36:07 +03:00
[ adt7473 ] = " ADT7473 " ,
[ adt7475 ] = " ADT7475 " ,
2009-12-09 22:36:08 +03:00
[ adt7476 ] = " ADT7476 " ,
2009-12-09 22:36:07 +03:00
[ adt7490 ] = " ADT7490 " ,
} ;
2009-01-16 00:27:47 +03:00
struct adt7475_data * data ;
2019-07-22 01:55:30 +03:00
struct device * hwmon_dev ;
int i , ret = 0 , revision , group_num = 0 ;
2020-02-27 11:46:41 +03:00
u8 config3 ;
2020-08-13 19:02:22 +03:00
const struct i2c_device_id * id = i2c_match_id ( adt7475_id , client ) ;
2009-01-16 00:27:47 +03:00
2012-06-02 20:58:01 +04:00
data = devm_kzalloc ( & client - > dev , sizeof ( * data ) , GFP_KERNEL ) ;
2009-01-16 00:27:47 +03:00
if ( data = = NULL )
return - ENOMEM ;
mutex_init ( & data - > lock ) ;
2019-07-22 01:55:30 +03:00
data - > client = client ;
2009-01-16 00:27:47 +03:00
i2c_set_clientdata ( client , data ) ;
2017-02-24 16:12:58 +03:00
if ( client - > dev . of_node )
chip = ( enum chips ) of_device_get_match_data ( & client - > dev ) ;
else
chip = id - > driver_data ;
2009-12-09 22:36:03 +03:00
/* Initialize device-specific values */
2017-02-24 16:12:58 +03:00
switch ( chip ) {
2009-12-09 22:36:08 +03:00
case adt7476 :
data - > has_voltage = 0x0e ; /* in1 to in3 */
revision = adt7475_read ( REG_DEVID2 ) & 0x07 ;
break ;
2009-12-09 22:36:05 +03:00
case adt7490 :
2009-12-09 22:36:06 +03:00
data - > has_voltage = 0x3e ; /* in1 to in5 */
revision = adt7475_read ( REG_DEVID2 ) & 0x03 ;
2009-12-09 22:36:07 +03:00
if ( revision = = 0x03 )
revision + = adt7475_read ( REG_DEVREV2 ) ;
2009-12-09 22:36:05 +03:00
break ;
2009-12-09 22:36:03 +03:00
default :
data - > has_voltage = 0x06 ; /* in1, in2 */
2009-12-09 22:36:06 +03:00
revision = adt7475_read ( REG_DEVID2 ) & 0x07 ;
}
config3 = adt7475_read ( REG_CONFIG3 ) ;
/* Pin PWM2 may alternatively be used for ALERT output */
if ( ! ( config3 & CONFIG3_SMBALERT ) )
data - > has_pwm2 = 1 ;
/* Meaning of this bit is inverted for the ADT7473-1 */
if ( id - > driver_data = = adt7473 & & revision > = 1 )
data - > has_pwm2 = ! data - > has_pwm2 ;
data - > config4 = adt7475_read ( REG_CONFIG4 ) ;
/* Pin TACH4 may alternatively be used for THERM */
if ( ( data - > config4 & CONFIG4_PINFUNC ) = = 0x0 )
data - > has_fan4 = 1 ;
2012-01-19 23:02:15 +04:00
/*
* THERM configuration is more complex on the ADT7476 and ADT7490 ,
* because 2 different pins ( TACH4 and + 2.5 Vin ) can be used for
* this function
*/
2009-12-09 22:36:06 +03:00
if ( id - > driver_data = = adt7490 ) {
if ( ( data - > config4 & CONFIG4_PINFUNC ) = = 0x1 & &
! ( config3 & CONFIG3_THERM ) )
data - > has_fan4 = 1 ;
2009-12-09 22:36:08 +03:00
}
if ( id - > driver_data = = adt7476 | | id - > driver_data = = adt7490 ) {
2009-12-09 22:36:06 +03:00
if ( ! ( config3 & CONFIG3_THERM ) | |
( data - > config4 & CONFIG4_PINFUNC ) = = 0x1 )
data - > has_voltage | = ( 1 < < 0 ) ; /* in0 */
2009-12-09 22:36:03 +03:00
}
2012-01-19 23:02:15 +04:00
/*
* On the ADT7476 , the + 12 V input pin may instead be used as VID5 ,
* and VID pins may alternatively be used as GPIO
*/
2009-12-09 22:36:08 +03:00
if ( id - > driver_data = = adt7476 ) {
u8 vid = adt7475_read ( REG_VID ) ;
if ( ! ( vid & VID_VIDSEL ) )
data - > has_voltage | = ( 1 < < 4 ) ; /* in4 */
2009-12-09 22:36:08 +03:00
data - > has_vid = ! ( adt7475_read ( REG_CONFIG5 ) & CONFIG5_VIDGPIO ) ;
2009-12-09 22:36:08 +03:00
}
2009-12-09 22:36:07 +03:00
/* Voltage attenuators can be bypassed, globally or individually */
2020-02-27 11:46:41 +03:00
data - > config2 = adt7475_read ( REG_CONFIG2 ) ;
ret = load_attenuators ( client , chip , data ) ;
if ( ret )
dev_warn ( & client - > dev , " Error configuring attenuator bypass \n " ) ;
if ( data - > config2 & CONFIG2_ATTN ) {
2009-12-09 22:36:07 +03:00
data - > bypass_attn = ( 0x3 < < 3 ) | 0x3 ;
} else {
data - > bypass_attn = ( ( data - > config4 & CONFIG4_ATTN_IN10 ) > > 4 ) |
( ( data - > config4 & CONFIG4_ATTN_IN43 ) > > 3 ) ;
}
data - > bypass_attn & = data - > has_voltage ;
2012-01-19 23:02:15 +04:00
/*
* Call adt7475_read_pwm for all pwm ' s as this will reprogram any
* pwm ' s which are disabled to manual mode with 0 % duty cycle
*/
2009-01-16 00:27:47 +03:00
for ( i = 0 ; i < ADT7475_PWM_COUNT ; i + + )
adt7475_read_pwm ( client , i ) ;
2020-02-27 11:46:42 +03:00
ret = adt7475_set_pwm_polarity ( client ) ;
if ( ret & & ret ! = - EINVAL )
dev_warn ( & client - > dev , " Error configuring pwm polarity \n " ) ;
2017-04-21 22:08:09 +03:00
/* Start monitoring */
switch ( chip ) {
case adt7475 :
case adt7476 :
i2c_smbus_write_byte_data ( client , REG_CONFIG1 ,
adt7475_read ( REG_CONFIG1 ) | 0x01 ) ;
break ;
default :
break ;
}
2019-07-22 01:55:30 +03:00
data - > groups [ group_num + + ] = & adt7475_attr_group ;
2009-01-16 00:27:47 +03:00
2009-12-09 22:36:06 +03:00
/* Features that can be disabled individually */
if ( data - > has_fan4 ) {
2019-07-22 01:55:30 +03:00
data - > groups [ group_num + + ] = & fan4_attr_group ;
2009-12-09 22:36:06 +03:00
}
if ( data - > has_pwm2 ) {
2019-07-22 01:55:30 +03:00
data - > groups [ group_num + + ] = & pwm2_attr_group ;
2009-12-09 22:36:06 +03:00
}
if ( data - > has_voltage & ( 1 < < 0 ) ) {
2019-07-22 01:55:30 +03:00
data - > groups [ group_num + + ] = & in0_attr_group ;
2009-12-09 22:36:06 +03:00
}
2009-12-09 22:36:08 +03:00
if ( data - > has_voltage & ( 1 < < 3 ) ) {
2019-07-22 01:55:30 +03:00
data - > groups [ group_num + + ] = & in3_attr_group ;
2009-12-09 22:36:08 +03:00
}
if ( data - > has_voltage & ( 1 < < 4 ) ) {
2019-07-22 01:55:30 +03:00
data - > groups [ group_num + + ] = & in4_attr_group ;
2009-12-09 22:36:08 +03:00
}
if ( data - > has_voltage & ( 1 < < 5 ) ) {
2019-07-22 01:55:30 +03:00
data - > groups [ group_num + + ] = & in5_attr_group ;
2009-12-09 22:36:08 +03:00
}
2009-12-09 22:36:08 +03:00
if ( data - > has_vid ) {
data - > vrm = vid_which_vrm ( ) ;
2019-07-22 01:55:30 +03:00
data - > groups [ group_num ] = & vid_attr_group ;
2009-12-09 22:36:08 +03:00
}
2009-12-09 22:36:06 +03:00
2019-07-22 01:55:30 +03:00
/* register device with all the acquired attributes */
hwmon_dev = devm_hwmon_device_register_with_groups ( & client - > dev ,
client - > name , data ,
data - > groups ) ;
if ( IS_ERR ( hwmon_dev ) ) {
ret = PTR_ERR ( hwmon_dev ) ;
return ret ;
2009-01-16 00:27:47 +03:00
}
2009-12-09 22:36:07 +03:00
dev_info ( & client - > dev , " %s device, revision %d \n " ,
names [ id - > driver_data ] , revision ) ;
2009-12-09 22:36:08 +03:00
if ( ( data - > has_voltage & 0x11 ) | | data - > has_fan4 | | data - > has_pwm2 )
2009-12-09 22:36:08 +03:00
dev_info ( & client - > dev , " Optional features:%s%s%s%s%s \n " ,
2009-12-09 22:36:07 +03:00
( data - > has_voltage & ( 1 < < 0 ) ) ? " in0 " : " " ,
2009-12-09 22:36:08 +03:00
( data - > has_voltage & ( 1 < < 4 ) ) ? " in4 " : " " ,
2009-12-09 22:36:07 +03:00
data - > has_fan4 ? " fan4 " : " " ,
2009-12-09 22:36:08 +03:00
data - > has_pwm2 ? " pwm2 " : " " ,
data - > has_vid ? " vid " : " " ) ;
2009-12-09 22:36:07 +03:00
if ( data - > bypass_attn )
dev_info ( & client - > dev , " Bypassing attenuators on:%s%s%s%s \n " ,
( data - > bypass_attn & ( 1 < < 0 ) ) ? " in0 " : " " ,
( data - > bypass_attn & ( 1 < < 1 ) ) ? " in1 " : " " ,
( data - > bypass_attn & ( 1 < < 3 ) ) ? " in3 " : " " ,
( data - > bypass_attn & ( 1 < < 4 ) ) ? " in4 " : " " ) ;
2009-12-09 22:36:07 +03:00
2018-08-08 04:32:16 +03:00
/* Limits and settings, should never change update more than once */
2018-08-08 04:32:19 +03:00
ret = adt7475_update_limits ( client ) ;
if ( ret )
2019-07-22 01:55:30 +03:00
return ret ;
2009-01-16 00:27:47 +03:00
return 0 ;
}
static struct i2c_driver adt7475_driver = {
. class = I2C_CLASS_HWMON ,
. driver = {
. name = " adt7475 " ,
2017-02-24 16:12:58 +03:00
. of_match_table = of_match_ptr ( adt7475_of_match ) ,
2009-01-16 00:27:47 +03:00
} ,
2020-08-13 19:02:22 +03:00
. probe_new = adt7475_probe ,
2009-01-16 00:27:47 +03:00
. id_table = adt7475_id ,
. detect = adt7475_detect ,
2009-12-14 23:17:25 +03:00
. address_list = normal_i2c ,
2009-01-16 00:27:47 +03:00
} ;
static void adt7475_read_hystersis ( struct i2c_client * client )
{
struct adt7475_data * data = i2c_get_clientdata ( client ) ;
data - > temp [ HYSTERSIS ] [ 0 ] = ( u16 ) adt7475_read ( REG_REMOTE1_HYSTERSIS ) ;
data - > temp [ HYSTERSIS ] [ 1 ] = data - > temp [ HYSTERSIS ] [ 0 ] ;
data - > temp [ HYSTERSIS ] [ 2 ] = ( u16 ) adt7475_read ( REG_REMOTE2_HYSTERSIS ) ;
}
static void adt7475_read_pwm ( struct i2c_client * client , int index )
{
struct adt7475_data * data = i2c_get_clientdata ( client ) ;
unsigned int v ;
data - > pwm [ CONTROL ] [ index ] = adt7475_read ( PWM_CONFIG_REG ( index ) ) ;
2012-01-19 23:02:15 +04:00
/*
* Figure out the internal value for pwmctrl and pwmchan
* based on the current settings
*/
2009-01-16 00:27:47 +03:00
v = ( data - > pwm [ CONTROL ] [ index ] > > 5 ) & 7 ;
if ( v = = 3 )
data - > pwmctl [ index ] = 0 ;
else if ( v = = 7 )
data - > pwmctl [ index ] = 1 ;
else if ( v = = 4 ) {
2012-01-19 23:02:15 +04:00
/*
* The fan is disabled - we don ' t want to
* support that , so change to manual mode and
* set the duty cycle to 0 instead
*/
2009-01-16 00:27:47 +03:00
data - > pwm [ INPUT ] [ index ] = 0 ;
data - > pwm [ CONTROL ] [ index ] & = ~ 0xE0 ;
data - > pwm [ CONTROL ] [ index ] | = ( 7 < < 5 ) ;
i2c_smbus_write_byte_data ( client , PWM_CONFIG_REG ( index ) ,
data - > pwm [ INPUT ] [ index ] ) ;
i2c_smbus_write_byte_data ( client , PWM_CONFIG_REG ( index ) ,
data - > pwm [ CONTROL ] [ index ] ) ;
data - > pwmctl [ index ] = 1 ;
} else {
data - > pwmctl [ index ] = 2 ;
switch ( v ) {
case 0 :
data - > pwmchan [ index ] = 1 ;
break ;
case 1 :
data - > pwmchan [ index ] = 2 ;
break ;
case 2 :
data - > pwmchan [ index ] = 4 ;
break ;
case 5 :
data - > pwmchan [ index ] = 6 ;
break ;
case 6 :
data - > pwmchan [ index ] = 7 ;
break ;
}
}
}
2018-08-08 04:32:18 +03:00
static int adt7475_update_measure ( struct device * dev )
2009-01-16 00:27:47 +03:00
{
2019-07-22 01:55:30 +03:00
struct adt7475_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2009-12-09 22:36:05 +03:00
u16 ext ;
2009-01-16 00:27:47 +03:00
int i ;
2018-08-08 04:32:18 +03:00
int ret ;
ret = adt7475_read ( REG_STATUS2 ) ;
if ( ret < 0 )
return ret ;
data - > alarms = ret < < 8 ;
2009-01-16 00:27:47 +03:00
2018-08-08 04:32:18 +03:00
ret = adt7475_read ( REG_STATUS1 ) ;
if ( ret < 0 )
return ret ;
data - > alarms | = ret ;
ret = adt7475_read ( REG_EXTEND2 ) ;
if ( ret < 0 )
return ret ;
ext = ( ret < < 8 ) ;
ret = adt7475_read ( REG_EXTEND1 ) ;
if ( ret < 0 )
return ret ;
ext | = ret ;
2018-08-08 04:32:16 +03:00
for ( i = 0 ; i < ADT7475_VOLTAGE_COUNT ; i + + ) {
if ( ! ( data - > has_voltage & ( 1 < < i ) ) )
continue ;
2018-08-08 04:32:18 +03:00
ret = adt7475_read ( VOLTAGE_REG ( i ) ) ;
if ( ret < 0 )
return ret ;
2018-08-08 04:32:16 +03:00
data - > voltage [ INPUT ] [ i ] =
2018-08-08 04:32:18 +03:00
( ret < < 2 ) |
2018-08-08 04:32:16 +03:00
( ( ext > > ( i * 2 ) ) & 3 ) ;
}
2009-01-16 00:27:47 +03:00
2018-08-08 04:32:18 +03:00
for ( i = 0 ; i < ADT7475_TEMP_COUNT ; i + + ) {
ret = adt7475_read ( TEMP_REG ( i ) ) ;
if ( ret < 0 )
return ret ;
2018-08-08 04:32:16 +03:00
data - > temp [ INPUT ] [ i ] =
2018-08-08 04:32:18 +03:00
( ret < < 2 ) |
2018-08-08 04:32:16 +03:00
( ( ext > > ( ( i + 5 ) * 2 ) ) & 3 ) ;
2018-08-08 04:32:18 +03:00
}
2009-12-09 22:36:08 +03:00
2018-08-08 04:32:16 +03:00
if ( data - > has_voltage & ( 1 < < 5 ) ) {
2018-08-08 04:32:18 +03:00
ret = adt7475_read ( REG_STATUS4 ) ;
if ( ret < 0 )
return ret ;
data - > alarms | = ret < < 24 ;
ret = adt7475_read ( REG_EXTEND3 ) ;
if ( ret < 0 )
return ret ;
ext = ret ;
ret = adt7475_read ( REG_VTT ) ;
if ( ret < 0 )
return ret ;
data - > voltage [ INPUT ] [ 5 ] = ret < < 2 |
2018-08-08 04:32:16 +03:00
( ( ext > > 4 ) & 3 ) ;
2009-01-16 00:27:47 +03:00
}
2018-08-08 04:32:16 +03:00
for ( i = 0 ; i < ADT7475_TACH_COUNT ; i + + ) {
if ( i = = 3 & & ! data - > has_fan4 )
continue ;
2018-08-08 04:32:18 +03:00
ret = adt7475_read_word ( client , TACH_REG ( i ) ) ;
if ( ret < 0 )
return ret ;
data - > tach [ INPUT ] [ i ] = ret ;
2018-08-08 04:32:16 +03:00
}
2009-12-09 22:36:05 +03:00
2018-08-08 04:32:16 +03:00
/* Updated by hw when in auto mode */
for ( i = 0 ; i < ADT7475_PWM_COUNT ; i + + ) {
if ( i = = 1 & & ! data - > has_pwm2 )
continue ;
2018-08-08 04:32:18 +03:00
ret = adt7475_read ( PWM_REG ( i ) ) ;
if ( ret < 0 )
return ret ;
data - > pwm [ INPUT ] [ i ] = ret ;
2018-08-08 04:32:16 +03:00
}
2009-01-16 00:27:47 +03:00
2018-08-08 04:32:18 +03:00
if ( data - > has_vid ) {
ret = adt7475_read ( REG_VID ) ;
if ( ret < 0 )
return ret ;
data - > vid = ret & 0x3f ;
}
return 0 ;
2018-08-08 04:32:16 +03:00
}
2009-01-16 00:27:47 +03:00
2018-08-08 04:32:16 +03:00
static struct adt7475_data * adt7475_update_device ( struct device * dev )
{
2019-07-22 01:55:30 +03:00
struct adt7475_data * data = dev_get_drvdata ( dev ) ;
2018-08-08 04:32:19 +03:00
int ret ;
2009-01-16 00:27:47 +03:00
2018-08-08 04:32:16 +03:00
mutex_lock ( & data - > lock ) ;
2009-01-16 00:27:47 +03:00
2018-08-08 04:32:16 +03:00
/* Measurement values update every 2 seconds */
if ( time_after ( jiffies , data - > measure_updated + HZ * 2 ) | |
! data - > valid ) {
2018-08-08 04:32:19 +03:00
ret = adt7475_update_measure ( dev ) ;
if ( ret ) {
data - > valid = false ;
mutex_unlock ( & data - > lock ) ;
return ERR_PTR ( ret ) ;
}
2018-08-08 04:32:16 +03:00
data - > measure_updated = jiffies ;
2018-08-08 04:32:17 +03:00
data - > valid = true ;
2009-01-16 00:27:47 +03:00
}
mutex_unlock ( & data - > lock ) ;
return data ;
}
2012-01-20 11:38:18 +04:00
module_i2c_driver ( adt7475_driver ) ;
2009-01-16 00:27:47 +03:00
MODULE_AUTHOR ( " Advanced Micro Devices, Inc " ) ;
MODULE_DESCRIPTION ( " adt7475 driver " ) ;
MODULE_LICENSE ( " GPL " ) ;