2019-05-20 10:19:02 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2005-04-17 02:20:36 +04:00
/*
* adm1025 . c
*
* Copyright ( C ) 2000 Chen - Yuan Wu < gwu @ esoft . com >
2014-01-29 23:40:08 +04:00
* Copyright ( C ) 2003 - 2009 Jean Delvare < jdelvare @ suse . de >
2005-04-17 02:20:36 +04:00
*
* The ADM1025 is a sensor chip made by Analog Devices . It reports up to 6
* voltages ( including its own power source ) and up to two temperatures
* ( its own plus up to one external one ) . Voltages are scaled internally
* ( which is not the common way ) with ratios such that the nominal value
* of each voltage correspond to a register value of 192 ( which means a
* resolution of about 0.5 % of the nominal value ) . Temperature values are
* reported with a 1 deg resolution and a 3 deg accuracy . Complete
* datasheet can be obtained from Analog ' s website at :
2020-07-13 17:00:28 +03:00
* https : //www.onsemi.com/PowerSolutions/product.do?id=ADM1025
2005-04-17 02:20:36 +04:00
*
* This driver also supports the ADM1025A , which differs from the ADM1025
* only in that it has " open-drain VID inputs while the ADM1025 has
* on - chip 100 k pull - ups on the VID inputs " . It doesn't make any
* difference for us .
*
* This driver also supports the NE1619 , a sensor chip made by Philips .
* That chip is similar to the ADM1025A , with a few differences . The only
* difference that matters to us is that the NE1619 has only two possible
* addresses while the ADM1025A has a third one . Complete datasheet can be
* obtained from Philips ' s website at :
* http : //www.semiconductors.philips.com/pip/NE1619DS.html
*
* Since the ADM1025 was the first chipset supported by this driver , most
* comments will refer to this chipset , but are actually general and
* concern all supported chipsets , unless mentioned otherwise .
*/
# 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-10-10 23:11:01 +04:00
# include <linux/hwmon-sysfs.h>
2005-07-31 23:52:01 +04:00
# include <linux/hwmon-vid.h>
2005-07-16 05:39:18 +04:00
# include <linux/err.h>
2006-01-19 01:19:26 +03:00
# include <linux/mutex.h>
2005-04-17 02:20:36 +04:00
/*
* Addresses to scan
* ADM1025 and ADM1025A have three possible addresses : 0x2c , 0x2d and 0x2e .
* NE1619 has two possible addresses : 0x2c and 0x2d .
*/
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 { adm1025 , ne1619 } ;
2005-04-17 02:20:36 +04:00
/*
* The ADM1025 registers
*/
# define ADM1025_REG_MAN_ID 0x3E
2007-10-10 23:14:11 +04:00
# define ADM1025_REG_CHIP_ID 0x3F
2005-04-17 02:20:36 +04:00
# define ADM1025_REG_CONFIG 0x40
# define ADM1025_REG_STATUS1 0x41
# define ADM1025_REG_STATUS2 0x42
# define ADM1025_REG_IN(nr) (0x20 + (nr))
# define ADM1025_REG_IN_MAX(nr) (0x2B + (nr) * 2)
# define ADM1025_REG_IN_MIN(nr) (0x2C + (nr) * 2)
# define ADM1025_REG_TEMP(nr) (0x26 + (nr))
# define ADM1025_REG_TEMP_HIGH(nr) (0x37 + (nr) * 2)
# define ADM1025_REG_TEMP_LOW(nr) (0x38 + (nr) * 2)
# define ADM1025_REG_VID 0x47
# define ADM1025_REG_VID4 0x49
/*
* Conversions and various macros
* The ADM1025 uses signed 8 - bit values for temperatures .
*/
2007-10-10 23:14:11 +04:00
static const int in_scale [ 6 ] = { 2500 , 2250 , 3300 , 5000 , 12000 , 3300 } ;
2005-04-17 02:20:36 +04:00
2012-01-15 00:49:22 +04:00
# define IN_FROM_REG(reg, scale) (((reg) * (scale) + 96) / 192)
# define IN_TO_REG(val, scale) ((val) <= 0 ? 0 : \
2016-12-03 22:07:14 +03:00
( val ) > = ( scale ) * 255 / 192 ? 255 : \
2012-01-15 00:49:22 +04:00
( ( val ) * 192 + ( scale ) / 2 ) / ( scale ) )
2005-04-17 02:20:36 +04:00
# define TEMP_FROM_REG(reg) ((reg) * 1000)
# define TEMP_TO_REG(val) ((val) <= -127500 ? -128 : \
( val ) > = 126500 ? 127 : \
2012-01-15 00:49:22 +04:00
( ( ( val ) < 0 ? ( val ) - 500 : \
( val ) + 500 ) / 1000 ) )
2005-04-17 02:20:36 +04:00
/*
* Client data ( each client gets its own )
*/
struct adm1025_data {
2014-07-03 17:49:27 +04:00
struct i2c_client * client ;
const struct attribute_group * groups [ 3 ] ;
2006-01-19 01:19:26 +03:00
struct mutex update_lock ;
2021-09-24 22:52:02 +03:00
bool valid ; /* false until following fields are valid */
2005-04-17 02:20:36 +04:00
unsigned long last_updated ; /* in jiffies */
u8 in [ 6 ] ; /* register value */
u8 in_max [ 6 ] ; /* register value */
u8 in_min [ 6 ] ; /* register value */
s8 temp [ 2 ] ; /* register value */
s8 temp_min [ 2 ] ; /* register value */
s8 temp_max [ 2 ] ; /* register value */
u16 alarms ; /* register values, combined */
u8 vid ; /* register values, combined */
u8 vrm ;
} ;
2014-07-03 17:48:15 +04:00
static struct adm1025_data * adm1025_update_device ( struct device * dev )
{
2014-07-03 17:49:27 +04:00
struct adm1025_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2014-07-03 17:48:15 +04:00
mutex_lock ( & data - > update_lock ) ;
if ( time_after ( jiffies , data - > last_updated + HZ * 2 ) | | ! data - > valid ) {
int i ;
dev_dbg ( & client - > dev , " Updating data. \n " ) ;
for ( i = 0 ; i < 6 ; i + + ) {
data - > in [ i ] = i2c_smbus_read_byte_data ( client ,
ADM1025_REG_IN ( i ) ) ;
data - > in_min [ i ] = i2c_smbus_read_byte_data ( client ,
ADM1025_REG_IN_MIN ( i ) ) ;
data - > in_max [ i ] = i2c_smbus_read_byte_data ( client ,
ADM1025_REG_IN_MAX ( i ) ) ;
}
for ( i = 0 ; i < 2 ; i + + ) {
data - > temp [ i ] = i2c_smbus_read_byte_data ( client ,
ADM1025_REG_TEMP ( i ) ) ;
data - > temp_min [ i ] = i2c_smbus_read_byte_data ( client ,
ADM1025_REG_TEMP_LOW ( i ) ) ;
data - > temp_max [ i ] = i2c_smbus_read_byte_data ( client ,
ADM1025_REG_TEMP_HIGH ( i ) ) ;
}
data - > alarms = i2c_smbus_read_byte_data ( client ,
ADM1025_REG_STATUS1 )
| ( i2c_smbus_read_byte_data ( client ,
ADM1025_REG_STATUS2 ) < < 8 ) ;
data - > vid = ( i2c_smbus_read_byte_data ( client ,
ADM1025_REG_VID ) & 0x0f )
| ( ( i2c_smbus_read_byte_data ( client ,
ADM1025_REG_VID4 ) & 0x01 ) < < 4 ) ;
data - > last_updated = jiffies ;
2021-09-24 22:52:02 +03:00
data - > valid = true ;
2014-07-03 17:48:15 +04:00
}
mutex_unlock ( & data - > update_lock ) ;
return data ;
}
2005-04-17 02:20:36 +04:00
/*
* Sysfs stuff
*/
2007-10-10 23:11:01 +04:00
static ssize_t
2019-01-22 05:33:47 +03:00
in_show ( struct device * dev , struct device_attribute * attr , char * buf )
2007-10-10 23:11:01 +04:00
{
int index = to_sensor_dev_attr ( attr ) - > index ;
struct adm1025_data * data = adm1025_update_device ( dev ) ;
return sprintf ( buf , " %u \n " , IN_FROM_REG ( data - > in [ index ] ,
in_scale [ index ] ) ) ;
}
static ssize_t
2019-01-22 05:33:47 +03:00
in_min_show ( struct device * dev , struct device_attribute * attr , char * buf )
2007-10-10 23:11:01 +04:00
{
int index = to_sensor_dev_attr ( attr ) - > index ;
struct adm1025_data * data = adm1025_update_device ( dev ) ;
return sprintf ( buf , " %u \n " , IN_FROM_REG ( data - > in_min [ index ] ,
in_scale [ index ] ) ) ;
}
static ssize_t
2019-01-22 05:33:47 +03:00
in_max_show ( struct device * dev , struct device_attribute * attr , char * buf )
2007-10-10 23:11:01 +04:00
{
int index = to_sensor_dev_attr ( attr ) - > index ;
struct adm1025_data * data = adm1025_update_device ( dev ) ;
return sprintf ( buf , " %u \n " , IN_FROM_REG ( data - > in_max [ index ] ,
in_scale [ index ] ) ) ;
}
static ssize_t
2019-01-22 05:33:47 +03:00
temp_show ( struct device * dev , struct device_attribute * attr , char * buf )
2007-10-10 23:11:01 +04:00
{
int index = to_sensor_dev_attr ( attr ) - > index ;
struct adm1025_data * data = adm1025_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , TEMP_FROM_REG ( data - > temp [ index ] ) ) ;
}
static ssize_t
2019-01-22 05:33:47 +03:00
temp_min_show ( struct device * dev , struct device_attribute * attr , char * buf )
2007-10-10 23:11:01 +04:00
{
int index = to_sensor_dev_attr ( attr ) - > index ;
struct adm1025_data * data = adm1025_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , TEMP_FROM_REG ( data - > temp_min [ index ] ) ) ;
}
static ssize_t
2019-01-22 05:33:47 +03:00
temp_max_show ( struct device * dev , struct device_attribute * attr , char * buf )
2007-10-10 23:11:01 +04:00
{
int index = to_sensor_dev_attr ( attr ) - > index ;
struct adm1025_data * data = adm1025_update_device ( dev ) ;
return sprintf ( buf , " %d \n " , TEMP_FROM_REG ( data - > temp_max [ index ] ) ) ;
}
2019-01-22 05:33:47 +03:00
static ssize_t in_min_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2007-10-10 23:11:01 +04:00
{
int index = to_sensor_dev_attr ( attr ) - > index ;
2014-07-03 17:49:27 +04:00
struct adm1025_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2012-01-15 00:49:22 +04:00
long val ;
int err ;
err = kstrtol ( buf , 10 , & val ) ;
if ( err )
return err ;
2007-10-10 23:11:01 +04:00
mutex_lock ( & data - > update_lock ) ;
data - > in_min [ index ] = IN_TO_REG ( val , in_scale [ index ] ) ;
i2c_smbus_write_byte_data ( client , ADM1025_REG_IN_MIN ( index ) ,
data - > in_min [ index ] ) ;
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
2019-01-22 05:33:47 +03:00
static ssize_t in_max_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2007-10-10 23:11:01 +04:00
{
int index = to_sensor_dev_attr ( attr ) - > index ;
2014-07-03 17:49:27 +04:00
struct adm1025_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2012-01-15 00:49:22 +04:00
long val ;
int err ;
err = kstrtol ( buf , 10 , & val ) ;
if ( err )
return err ;
2007-10-10 23:11:01 +04:00
mutex_lock ( & data - > update_lock ) ;
data - > in_max [ index ] = IN_TO_REG ( val , in_scale [ index ] ) ;
i2c_smbus_write_byte_data ( client , ADM1025_REG_IN_MAX ( index ) ,
data - > in_max [ index ] ) ;
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
2005-04-17 02:20:36 +04:00
2019-01-22 05:33:47 +03:00
static SENSOR_DEVICE_ATTR_RO ( in0_input , in , 0 ) ;
static SENSOR_DEVICE_ATTR_RW ( in0_min , in_min , 0 ) ;
static SENSOR_DEVICE_ATTR_RW ( in0_max , in_max , 0 ) ;
static SENSOR_DEVICE_ATTR_RO ( in1_input , in , 1 ) ;
static SENSOR_DEVICE_ATTR_RW ( in1_min , in_min , 1 ) ;
static SENSOR_DEVICE_ATTR_RW ( in1_max , in_max , 1 ) ;
static SENSOR_DEVICE_ATTR_RO ( in2_input , in , 2 ) ;
static SENSOR_DEVICE_ATTR_RW ( in2_min , in_min , 2 ) ;
static SENSOR_DEVICE_ATTR_RW ( in2_max , in_max , 2 ) ;
static SENSOR_DEVICE_ATTR_RO ( in3_input , in , 3 ) ;
static SENSOR_DEVICE_ATTR_RW ( in3_min , in_min , 3 ) ;
static SENSOR_DEVICE_ATTR_RW ( in3_max , in_max , 3 ) ;
static SENSOR_DEVICE_ATTR_RO ( in4_input , in , 4 ) ;
static SENSOR_DEVICE_ATTR_RW ( in4_min , in_min , 4 ) ;
static SENSOR_DEVICE_ATTR_RW ( in4_max , in_max , 4 ) ;
static SENSOR_DEVICE_ATTR_RO ( in5_input , in , 5 ) ;
static SENSOR_DEVICE_ATTR_RW ( in5_min , in_min , 5 ) ;
static SENSOR_DEVICE_ATTR_RW ( in5_max , in_max , 5 ) ;
static ssize_t temp_min_store ( struct device * dev ,
struct device_attribute * attr , const char * buf ,
size_t count )
2007-10-10 23:11:01 +04:00
{
int index = to_sensor_dev_attr ( attr ) - > index ;
2014-07-03 17:49:27 +04:00
struct adm1025_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2012-01-15 00:49:22 +04:00
long val ;
int err ;
err = kstrtol ( buf , 10 , & val ) ;
if ( err )
return err ;
2007-10-10 23:11:01 +04:00
mutex_lock ( & data - > update_lock ) ;
data - > temp_min [ index ] = TEMP_TO_REG ( val ) ;
i2c_smbus_write_byte_data ( client , ADM1025_REG_TEMP_LOW ( index ) ,
data - > temp_min [ index ] ) ;
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
2019-01-22 05:33:47 +03:00
static ssize_t temp_max_store ( struct device * dev ,
struct device_attribute * attr , const char * buf ,
size_t count )
2007-10-10 23:11:01 +04:00
{
int index = to_sensor_dev_attr ( attr ) - > index ;
2014-07-03 17:49:27 +04:00
struct adm1025_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2012-01-15 00:49:22 +04:00
long val ;
int err ;
err = kstrtol ( buf , 10 , & val ) ;
if ( err )
return err ;
2007-10-10 23:11:01 +04:00
mutex_lock ( & data - > update_lock ) ;
data - > temp_max [ index ] = TEMP_TO_REG ( val ) ;
i2c_smbus_write_byte_data ( client , ADM1025_REG_TEMP_HIGH ( index ) ,
data - > temp_max [ index ] ) ;
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
2019-01-22 05:33:47 +03:00
static SENSOR_DEVICE_ATTR_RO ( temp1_input , temp , 0 ) ;
static SENSOR_DEVICE_ATTR_RW ( temp1_min , temp_min , 0 ) ;
static SENSOR_DEVICE_ATTR_RW ( temp1_max , temp_max , 0 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp2_input , temp , 1 ) ;
static SENSOR_DEVICE_ATTR_RW ( temp2_min , temp_min , 1 ) ;
static SENSOR_DEVICE_ATTR_RW ( temp2_max , temp_max , 1 ) ;
2005-04-17 02:20:36 +04:00
2007-10-10 23:14:11 +04:00
static ssize_t
2016-12-22 15:05:28 +03:00
alarms_show ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct adm1025_data * data = adm1025_update_device ( dev ) ;
return sprintf ( buf , " %u \n " , data - > alarms ) ;
}
2016-12-22 15:05:28 +03:00
static DEVICE_ATTR_RO ( alarms ) ;
2005-04-17 02:20:36 +04:00
2007-10-10 23:11:52 +04:00
static ssize_t
2019-01-22 05:33:47 +03:00
alarm_show ( struct device * dev , struct device_attribute * attr , char * buf )
2007-10-10 23:11:52 +04:00
{
int bitnr = to_sensor_dev_attr ( attr ) - > index ;
struct adm1025_data * data = adm1025_update_device ( dev ) ;
return sprintf ( buf , " %u \n " , ( data - > alarms > > bitnr ) & 1 ) ;
}
2019-01-22 05:33:47 +03:00
static SENSOR_DEVICE_ATTR_RO ( in0_alarm , alarm , 0 ) ;
static SENSOR_DEVICE_ATTR_RO ( in1_alarm , alarm , 1 ) ;
static SENSOR_DEVICE_ATTR_RO ( in2_alarm , alarm , 2 ) ;
static SENSOR_DEVICE_ATTR_RO ( in3_alarm , alarm , 3 ) ;
static SENSOR_DEVICE_ATTR_RO ( in4_alarm , alarm , 8 ) ;
static SENSOR_DEVICE_ATTR_RO ( in5_alarm , alarm , 9 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp1_alarm , alarm , 5 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp2_alarm , alarm , 4 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp1_fault , alarm , 14 ) ;
2007-10-10 23:11:52 +04:00
2007-10-10 23:14:11 +04:00
static ssize_t
2016-12-22 15:05:28 +03:00
cpu0_vid_show ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
struct adm1025_data * data = adm1025_update_device ( dev ) ;
return sprintf ( buf , " %u \n " , vid_from_reg ( data - > vid , data - > vrm ) ) ;
}
2016-12-22 15:05:28 +03:00
static DEVICE_ATTR_RO ( cpu0_vid ) ;
2005-04-17 02:20:36 +04:00
2007-10-10 23:14:11 +04:00
static ssize_t
2016-12-22 15:05:28 +03:00
vrm_show ( struct device * dev , struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-10-08 20:24:35 +04:00
struct adm1025_data * data = dev_get_drvdata ( dev ) ;
2005-04-17 02:20:36 +04:00
return sprintf ( buf , " %u \n " , data - > vrm ) ;
}
2016-12-22 15:05:28 +03:00
static ssize_t vrm_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2007-12-01 13:25:33 +03:00
struct adm1025_data * data = dev_get_drvdata ( dev ) ;
2012-01-15 00:49:22 +04:00
unsigned long val ;
int err ;
err = kstrtoul ( buf , 10 , & val ) ;
if ( err )
return err ;
2014-08-06 04:19:43 +04:00
if ( val > 255 )
return - EINVAL ;
2012-01-15 00:49:22 +04:00
data - > vrm = val ;
2005-04-17 02:20:36 +04:00
return count ;
}
2016-12-22 15:05:28 +03:00
static DEVICE_ATTR_RW ( vrm ) ;
2005-04-17 02:20:36 +04:00
/*
* Real code
*/
2006-09-24 23:15:35 +04:00
static struct attribute * adm1025_attributes [ ] = {
2007-10-10 23:11:01 +04:00
& sensor_dev_attr_in0_input . dev_attr . attr ,
& sensor_dev_attr_in1_input . dev_attr . attr ,
& sensor_dev_attr_in2_input . dev_attr . attr ,
& sensor_dev_attr_in3_input . dev_attr . attr ,
& sensor_dev_attr_in5_input . dev_attr . attr ,
& sensor_dev_attr_in0_min . dev_attr . attr ,
& sensor_dev_attr_in1_min . dev_attr . attr ,
& sensor_dev_attr_in2_min . dev_attr . attr ,
& sensor_dev_attr_in3_min . dev_attr . attr ,
& sensor_dev_attr_in5_min . dev_attr . attr ,
& sensor_dev_attr_in0_max . dev_attr . attr ,
& sensor_dev_attr_in1_max . dev_attr . attr ,
& sensor_dev_attr_in2_max . dev_attr . attr ,
& sensor_dev_attr_in3_max . dev_attr . attr ,
& sensor_dev_attr_in5_max . dev_attr . attr ,
2007-10-10 23:11:52 +04:00
& sensor_dev_attr_in0_alarm . dev_attr . attr ,
& sensor_dev_attr_in1_alarm . dev_attr . attr ,
& sensor_dev_attr_in2_alarm . dev_attr . attr ,
& sensor_dev_attr_in3_alarm . dev_attr . attr ,
& sensor_dev_attr_in5_alarm . dev_attr . attr ,
2007-10-10 23:11:01 +04:00
& sensor_dev_attr_temp1_input . dev_attr . attr ,
& sensor_dev_attr_temp2_input . dev_attr . attr ,
& sensor_dev_attr_temp1_min . dev_attr . attr ,
& sensor_dev_attr_temp2_min . dev_attr . attr ,
& sensor_dev_attr_temp1_max . dev_attr . attr ,
& sensor_dev_attr_temp2_max . dev_attr . attr ,
2007-10-10 23:11:52 +04:00
& sensor_dev_attr_temp1_alarm . dev_attr . attr ,
& sensor_dev_attr_temp2_alarm . dev_attr . attr ,
& sensor_dev_attr_temp1_fault . dev_attr . attr ,
2006-09-24 23:15:35 +04:00
& dev_attr_alarms . attr ,
& dev_attr_cpu0_vid . attr ,
& dev_attr_vrm . attr ,
NULL
} ;
static const struct attribute_group adm1025_group = {
. attrs = adm1025_attributes ,
} ;
2007-10-10 23:14:11 +04:00
static struct attribute * adm1025_attributes_in4 [ ] = {
2007-10-10 23:11:01 +04:00
& sensor_dev_attr_in4_input . dev_attr . attr ,
& sensor_dev_attr_in4_min . dev_attr . attr ,
& sensor_dev_attr_in4_max . dev_attr . attr ,
2007-10-10 23:11:52 +04:00
& sensor_dev_attr_in4_alarm . dev_attr . attr ,
2006-09-24 23:15:35 +04:00
NULL
} ;
2007-10-10 23:14:11 +04:00
static const struct attribute_group adm1025_group_in4 = {
. attrs = adm1025_attributes_in4 ,
2006-09-24 23:15:35 +04:00
} ;
2008-07-16 21:30:08 +04:00
/* Return 0 if detection is successful, -ENODEV otherwise */
2009-12-14 23:17:23 +03:00
static int adm1025_detect ( struct i2c_client * client ,
2008-07-16 21:30:08 +04:00
struct i2c_board_info * info )
2005-04-17 02:20:36 +04:00
{
2008-07-16 21:30:08 +04:00
struct i2c_adapter * adapter = client - > adapter ;
2009-12-09 22:35:51 +03:00
const char * name ;
u8 man_id , chip_id ;
2005-04-17 02:20:36 +04:00
if ( ! i2c_check_functionality ( adapter , I2C_FUNC_SMBUS_BYTE_DATA ) )
2008-07-16 21:30:08 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
2009-12-09 22:35:51 +03:00
/* Check for unused bits */
if ( ( i2c_smbus_read_byte_data ( client , ADM1025_REG_CONFIG ) & 0x80 )
| | ( i2c_smbus_read_byte_data ( client , ADM1025_REG_STATUS1 ) & 0xC0 )
| | ( i2c_smbus_read_byte_data ( client , ADM1025_REG_STATUS2 ) & 0xBC ) ) {
dev_dbg ( & adapter - > dev , " ADM1025 detection failed at 0x%02x \n " ,
client - > addr ) ;
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
2009-12-09 22:35:51 +03:00
/* Identification */
chip_id = i2c_smbus_read_byte_data ( client , ADM1025_REG_CHIP_ID ) ;
if ( ( chip_id & 0xF0 ) ! = 0x20 )
return - ENODEV ;
2005-04-17 02:20:36 +04:00
2009-12-09 22:35:51 +03:00
man_id = i2c_smbus_read_byte_data ( client , ADM1025_REG_MAN_ID ) ;
if ( man_id = = 0x41 )
2005-04-17 02:20:36 +04:00
name = " adm1025 " ;
2009-12-09 22:35:51 +03:00
else if ( man_id = = 0xA1 & & client - > addr ! = 0x2E )
2005-04-17 02:20:36 +04:00
name = " ne1619 " ;
2009-12-09 22:35:51 +03:00
else
return - ENODEV ;
2008-07-16 21:30:08 +04:00
strlcpy ( info - > type , name , I2C_NAME_SIZE ) ;
2005-04-17 02:20:36 +04:00
2008-07-16 21:30:08 +04:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
2014-07-03 17:48:15 +04:00
static void adm1025_init_client ( struct i2c_client * client )
{
u8 reg ;
struct adm1025_data * data = i2c_get_clientdata ( client ) ;
int i ;
data - > vrm = vid_which_vrm ( ) ;
/*
* Set high limits
* Usually we avoid setting limits on driver init , but it happens
* that the ADM1025 comes with stupid default limits ( all registers
* set to 0 ) . In case the chip has not gone through any limit
* setting yet , we better set the high limits to the max so that
* no alarm triggers .
*/
for ( i = 0 ; i < 6 ; i + + ) {
reg = i2c_smbus_read_byte_data ( client ,
ADM1025_REG_IN_MAX ( i ) ) ;
if ( reg = = 0 )
i2c_smbus_write_byte_data ( client ,
ADM1025_REG_IN_MAX ( i ) ,
0xFF ) ;
}
for ( i = 0 ; i < 2 ; i + + ) {
reg = i2c_smbus_read_byte_data ( client ,
ADM1025_REG_TEMP_HIGH ( i ) ) ;
if ( reg = = 0 )
i2c_smbus_write_byte_data ( client ,
ADM1025_REG_TEMP_HIGH ( i ) ,
0x7F ) ;
}
/*
* Start the conversions
*/
reg = i2c_smbus_read_byte_data ( client , ADM1025_REG_CONFIG ) ;
if ( ! ( reg & 0x01 ) )
i2c_smbus_write_byte_data ( client , ADM1025_REG_CONFIG ,
( reg & 0x7E ) | 0x01 ) ;
}
2020-08-13 19:02:22 +03:00
static int adm1025_probe ( struct i2c_client * client )
2008-07-16 21:30:08 +04:00
{
2014-07-03 17:49:27 +04:00
struct device * dev = & client - > dev ;
struct device * hwmon_dev ;
2008-07-16 21:30:08 +04:00
struct adm1025_data * data ;
u8 config ;
2014-07-03 17:49:27 +04:00
data = devm_kzalloc ( dev , sizeof ( struct adm1025_data ) , GFP_KERNEL ) ;
2012-06-02 20:57:58 +04:00
if ( ! data )
return - ENOMEM ;
2008-07-16 21:30:08 +04:00
i2c_set_clientdata ( client , data ) ;
2014-07-03 17:49:27 +04:00
data - > client = client ;
2008-07-16 21:30:08 +04:00
mutex_init ( & data - > update_lock ) ;
2005-04-17 02:20:36 +04:00
/* Initialize the ADM1025 chip */
2007-10-10 23:14:11 +04:00
adm1025_init_client ( client ) ;
2005-04-17 02:20:36 +04:00
2014-07-03 17:49:27 +04:00
/* sysfs hooks */
data - > groups [ 0 ] = & adm1025_group ;
2005-04-17 02:20:36 +04:00
/* Pin 11 is either in4 (+12V) or VID4 */
2008-07-16 21:30:08 +04:00
config = i2c_smbus_read_byte_data ( client , ADM1025_REG_CONFIG ) ;
2014-07-03 17:49:27 +04:00
if ( ! ( config & 0x20 ) )
data - > groups [ 1 ] = & adm1025_group_in4 ;
2005-04-17 02:20:36 +04:00
2014-07-03 17:49:27 +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:48:15 +04:00
static const struct i2c_device_id adm1025_id [ ] = {
{ " adm1025 " , adm1025 } ,
{ " ne1619 " , ne1619 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , adm1025_id ) ;
2005-04-17 02:20:36 +04:00
2014-07-03 17:48:15 +04:00
static struct i2c_driver adm1025_driver = {
. class = I2C_CLASS_HWMON ,
. driver = {
. name = " adm1025 " ,
} ,
2020-08-13 19:02:22 +03:00
. probe_new = adm1025_probe ,
2014-07-03 17:48:15 +04:00
. id_table = adm1025_id ,
. detect = adm1025_detect ,
. address_list = normal_i2c ,
} ;
2005-04-17 02:20:36 +04:00
2012-01-20 11:38:18 +04:00
module_i2c_driver ( adm1025_driver ) ;
2005-04-17 02:20:36 +04:00
2014-01-29 23:40:08 +04:00
MODULE_AUTHOR ( " Jean Delvare <jdelvare@suse.de> " ) ;
2005-04-17 02:20:36 +04:00
MODULE_DESCRIPTION ( " ADM1025 driver " ) ;
MODULE_LICENSE ( " GPL " ) ;