2019-06-01 11:08:55 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2011-02-02 19:49:54 +03:00
/*
* Driver for
* Maxim MAX16065 / MAX16066 12 - Channel / 8 - Channel , Flash - Configurable
* System Managers with Nonvolatile Fault Registers
* Maxim MAX16067 / MAX16068 6 - Channel , Flash - Configurable System Managers
* with Nonvolatile Fault Registers
* Maxim MAX16070 / MAX16071 12 - Channel / 8 - Channel , Flash - Configurable System
* Monitors with Nonvolatile Fault Registers
*
* Copyright ( C ) 2011 Ericsson AB .
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/err.h>
# include <linux/slab.h>
# include <linux/i2c.h>
# include <linux/hwmon.h>
# include <linux/hwmon-sysfs.h>
# include <linux/jiffies.h>
enum chips { max16065 , max16066 , max16067 , max16068 , max16070 , max16071 } ;
/*
* Registers
*/
# define MAX16065_ADC(x) ((x) * 2)
# define MAX16065_CURR_SENSE 0x18
# define MAX16065_CSP_ADC 0x19
# define MAX16065_FAULT(x) (0x1b + (x))
# define MAX16065_SCALE(x) (0x43 + (x))
# define MAX16065_CURR_CONTROL 0x47
# define MAX16065_LIMIT(l, x) (0x48 + (l) + (x) * 3) / *
* l : limit
* 0 : min / max
* 1 : crit
* 2 : lcrit
* x : ADC index
*/
# define MAX16065_SW_ENABLE 0x73
# define MAX16065_WARNING_OV (1 << 3) / * Set if secondary threshold is OV
warning */
# define MAX16065_CURR_ENABLE (1 << 0)
# define MAX16065_NUM_LIMIT 3
# define MAX16065_NUM_ADC 12 /* maximum number of ADC channels */
static const int max16065_num_adc [ ] = {
[ max16065 ] = 12 ,
[ max16066 ] = 8 ,
[ max16067 ] = 6 ,
[ max16068 ] = 6 ,
[ max16070 ] = 12 ,
[ max16071 ] = 8 ,
} ;
static const bool max16065_have_secondary [ ] = {
[ max16065 ] = true ,
[ max16066 ] = true ,
[ max16067 ] = false ,
[ max16068 ] = false ,
[ max16070 ] = true ,
[ max16071 ] = true ,
} ;
static const bool max16065_have_current [ ] = {
[ max16065 ] = true ,
[ max16066 ] = true ,
[ max16067 ] = false ,
[ max16068 ] = false ,
[ max16070 ] = true ,
[ max16071 ] = true ,
} ;
struct max16065_data {
enum chips type ;
2013-09-02 22:31:28 +04:00
struct i2c_client * client ;
const struct attribute_group * groups [ 4 ] ;
2011-02-02 19:49:54 +03:00
struct mutex update_lock ;
bool valid ;
unsigned long last_updated ; /* in jiffies */
int num_adc ;
bool have_current ;
int curr_gain ;
/* limits are in mV */
int limit [ MAX16065_NUM_LIMIT ] [ MAX16065_NUM_ADC ] ;
int range [ MAX16065_NUM_ADC + 1 ] ; /* voltage range */
int adc [ MAX16065_NUM_ADC + 1 ] ; /* adc values (raw) including csp_adc */
int curr_sense ;
int fault [ 2 ] ;
} ;
static const int max16065_adc_range [ ] = { 5560 , 2780 , 1390 , 0 } ;
static const int max16065_csp_adc_range [ ] = { 7000 , 14000 } ;
/* ADC registers have 10 bit resolution. */
static inline int ADC_TO_MV ( int adc , int range )
{
return ( adc * range ) / 1024 ;
}
/*
* Limit registers have 8 bit resolution and match upper 8 bits of ADC
* registers .
*/
static inline int LIMIT_TO_MV ( int limit , int range )
{
return limit * range / 256 ;
}
static inline int MV_TO_LIMIT ( int mv , int range )
{
2013-01-09 20:09:34 +04:00
return clamp_val ( DIV_ROUND_CLOSEST ( mv * 256 , range ) , 0 , 255 ) ;
2011-02-02 19:49:54 +03:00
}
static inline int ADC_TO_CURR ( int adc , int gain )
{
2011-08-29 00:01:49 +04:00
return adc * 1400000 / ( gain * 255 ) ;
2011-02-02 19:49:54 +03:00
}
/*
* max16065_read_adc ( )
*
* Read 16 bit value from < reg > , < reg + 1 > .
* Upper 8 bits are in < reg > , lower 2 bits are in bits 7 : 6 of < reg + 1 > .
*/
static int max16065_read_adc ( struct i2c_client * client , int reg )
{
int rv ;
2011-11-04 15:00:47 +04:00
rv = i2c_smbus_read_word_swapped ( client , reg ) ;
2011-02-02 19:49:54 +03:00
if ( unlikely ( rv < 0 ) )
return rv ;
2011-11-04 15:00:47 +04:00
return rv > > 6 ;
2011-02-02 19:49:54 +03:00
}
static struct max16065_data * max16065_update_device ( struct device * dev )
{
2013-09-02 22:31:28 +04:00
struct max16065_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
2011-02-02 19:49:54 +03:00
mutex_lock ( & data - > update_lock ) ;
if ( time_after ( jiffies , data - > last_updated + HZ ) | | ! data - > valid ) {
int i ;
for ( i = 0 ; i < data - > num_adc ; i + + )
data - > adc [ i ]
= max16065_read_adc ( client , MAX16065_ADC ( i ) ) ;
if ( data - > have_current ) {
data - > adc [ MAX16065_NUM_ADC ]
= max16065_read_adc ( client , MAX16065_CSP_ADC ) ;
data - > curr_sense
= i2c_smbus_read_byte_data ( client ,
MAX16065_CURR_SENSE ) ;
}
for ( i = 0 ; i < DIV_ROUND_UP ( data - > num_adc , 8 ) ; i + + )
data - > fault [ i ]
= i2c_smbus_read_byte_data ( client , MAX16065_FAULT ( i ) ) ;
data - > last_updated = jiffies ;
data - > valid = 1 ;
}
mutex_unlock ( & data - > update_lock ) ;
return data ;
}
2018-12-11 01:02:15 +03:00
static ssize_t max16065_alarm_show ( struct device * dev ,
2011-02-02 19:49:54 +03:00
struct device_attribute * da , char * buf )
{
struct sensor_device_attribute_2 * attr2 = to_sensor_dev_attr_2 ( da ) ;
struct max16065_data * data = max16065_update_device ( dev ) ;
int val = data - > fault [ attr2 - > nr ] ;
if ( val < 0 )
return val ;
val & = ( 1 < < attr2 - > index ) ;
if ( val )
2013-09-02 22:31:28 +04:00
i2c_smbus_write_byte_data ( data - > client ,
2011-02-02 19:49:54 +03:00
MAX16065_FAULT ( attr2 - > nr ) , val ) ;
hwmon: replace snprintf in show functions with sysfs_emit
coccicheck complains about the use of snprintf() in sysfs
show functions.
drivers/hwmon/ina3221.c:701:8-16: WARNING: use scnprintf or sprintf
This results in a large number of patch submissions. Fix it all in
one go using the following coccinelle rules. Use sysfs_emit instead
of scnprintf or sprintf since that makes more sense.
@depends on patch@
identifier show, dev, attr, buf;
@@
ssize_t show(struct device *dev, struct device_attribute *attr, char *buf)
{
<...
return
- snprintf(buf, \( PAGE_SIZE \| PAGE_SIZE - 1 \),
+ sysfs_emit(buf,
...);
...>
}
@depends on patch@
identifier show, dev, attr, buf, rc;
@@
ssize_t show(struct device *dev, struct device_attribute *attr, char *buf)
{
<...
rc =
- snprintf(buf, \( PAGE_SIZE \| PAGE_SIZE - 1 \),
+ sysfs_emit(buf,
...);
...>
}
While at it, remove unnecessary braces and as well as unnecessary
else after return statements to address checkpatch warnings in the
resulting patch.
Cc: Zihao Tang <tangzihao1@hisilicon.com>
Cc: Jay Fang <f.fangjian@huawei.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2021-03-22 06:49:10 +03:00
return sysfs_emit ( buf , " %d \n " , ! ! val ) ;
2011-02-02 19:49:54 +03:00
}
2018-12-11 01:02:15 +03:00
static ssize_t max16065_input_show ( struct device * dev ,
2011-02-02 19:49:54 +03:00
struct device_attribute * da , char * buf )
{
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ;
struct max16065_data * data = max16065_update_device ( dev ) ;
int adc = data - > adc [ attr - > index ] ;
if ( unlikely ( adc < 0 ) )
return adc ;
hwmon: replace snprintf in show functions with sysfs_emit
coccicheck complains about the use of snprintf() in sysfs
show functions.
drivers/hwmon/ina3221.c:701:8-16: WARNING: use scnprintf or sprintf
This results in a large number of patch submissions. Fix it all in
one go using the following coccinelle rules. Use sysfs_emit instead
of scnprintf or sprintf since that makes more sense.
@depends on patch@
identifier show, dev, attr, buf;
@@
ssize_t show(struct device *dev, struct device_attribute *attr, char *buf)
{
<...
return
- snprintf(buf, \( PAGE_SIZE \| PAGE_SIZE - 1 \),
+ sysfs_emit(buf,
...);
...>
}
@depends on patch@
identifier show, dev, attr, buf, rc;
@@
ssize_t show(struct device *dev, struct device_attribute *attr, char *buf)
{
<...
rc =
- snprintf(buf, \( PAGE_SIZE \| PAGE_SIZE - 1 \),
+ sysfs_emit(buf,
...);
...>
}
While at it, remove unnecessary braces and as well as unnecessary
else after return statements to address checkpatch warnings in the
resulting patch.
Cc: Zihao Tang <tangzihao1@hisilicon.com>
Cc: Jay Fang <f.fangjian@huawei.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2021-03-22 06:49:10 +03:00
return sysfs_emit ( buf , " %d \n " ,
ADC_TO_MV ( adc , data - > range [ attr - > index ] ) ) ;
2011-02-02 19:49:54 +03:00
}
2018-12-11 01:02:15 +03:00
static ssize_t max16065_current_show ( struct device * dev ,
2011-02-02 19:49:54 +03:00
struct device_attribute * da , char * buf )
{
struct max16065_data * data = max16065_update_device ( dev ) ;
if ( unlikely ( data - > curr_sense < 0 ) )
return data - > curr_sense ;
hwmon: replace snprintf in show functions with sysfs_emit
coccicheck complains about the use of snprintf() in sysfs
show functions.
drivers/hwmon/ina3221.c:701:8-16: WARNING: use scnprintf or sprintf
This results in a large number of patch submissions. Fix it all in
one go using the following coccinelle rules. Use sysfs_emit instead
of scnprintf or sprintf since that makes more sense.
@depends on patch@
identifier show, dev, attr, buf;
@@
ssize_t show(struct device *dev, struct device_attribute *attr, char *buf)
{
<...
return
- snprintf(buf, \( PAGE_SIZE \| PAGE_SIZE - 1 \),
+ sysfs_emit(buf,
...);
...>
}
@depends on patch@
identifier show, dev, attr, buf, rc;
@@
ssize_t show(struct device *dev, struct device_attribute *attr, char *buf)
{
<...
rc =
- snprintf(buf, \( PAGE_SIZE \| PAGE_SIZE - 1 \),
+ sysfs_emit(buf,
...);
...>
}
While at it, remove unnecessary braces and as well as unnecessary
else after return statements to address checkpatch warnings in the
resulting patch.
Cc: Zihao Tang <tangzihao1@hisilicon.com>
Cc: Jay Fang <f.fangjian@huawei.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2021-03-22 06:49:10 +03:00
return sysfs_emit ( buf , " %d \n " ,
ADC_TO_CURR ( data - > curr_sense , data - > curr_gain ) ) ;
2011-02-02 19:49:54 +03:00
}
2018-12-11 01:02:15 +03:00
static ssize_t max16065_limit_store ( struct device * dev ,
struct device_attribute * da ,
const char * buf , size_t count )
2011-02-02 19:49:54 +03:00
{
struct sensor_device_attribute_2 * attr2 = to_sensor_dev_attr_2 ( da ) ;
2013-09-02 22:31:28 +04:00
struct max16065_data * data = dev_get_drvdata ( dev ) ;
2011-02-02 19:49:54 +03:00
unsigned long val ;
int err ;
int limit ;
2012-01-04 23:58:52 +04:00
err = kstrtoul ( buf , 10 , & val ) ;
2011-02-02 19:49:54 +03:00
if ( unlikely ( err < 0 ) )
return err ;
limit = MV_TO_LIMIT ( val , data - > range [ attr2 - > index ] ) ;
mutex_lock ( & data - > update_lock ) ;
data - > limit [ attr2 - > nr ] [ attr2 - > index ]
= LIMIT_TO_MV ( limit , data - > range [ attr2 - > index ] ) ;
2013-09-02 22:31:28 +04:00
i2c_smbus_write_byte_data ( data - > client ,
2011-02-02 19:49:54 +03:00
MAX16065_LIMIT ( attr2 - > nr , attr2 - > index ) ,
limit ) ;
mutex_unlock ( & data - > update_lock ) ;
return count ;
}
2018-12-11 01:02:15 +03:00
static ssize_t max16065_limit_show ( struct device * dev ,
2011-02-02 19:49:54 +03:00
struct device_attribute * da , char * buf )
{
struct sensor_device_attribute_2 * attr2 = to_sensor_dev_attr_2 ( da ) ;
2013-09-02 22:31:28 +04:00
struct max16065_data * data = dev_get_drvdata ( dev ) ;
2011-02-02 19:49:54 +03:00
hwmon: replace snprintf in show functions with sysfs_emit
coccicheck complains about the use of snprintf() in sysfs
show functions.
drivers/hwmon/ina3221.c:701:8-16: WARNING: use scnprintf or sprintf
This results in a large number of patch submissions. Fix it all in
one go using the following coccinelle rules. Use sysfs_emit instead
of scnprintf or sprintf since that makes more sense.
@depends on patch@
identifier show, dev, attr, buf;
@@
ssize_t show(struct device *dev, struct device_attribute *attr, char *buf)
{
<...
return
- snprintf(buf, \( PAGE_SIZE \| PAGE_SIZE - 1 \),
+ sysfs_emit(buf,
...);
...>
}
@depends on patch@
identifier show, dev, attr, buf, rc;
@@
ssize_t show(struct device *dev, struct device_attribute *attr, char *buf)
{
<...
rc =
- snprintf(buf, \( PAGE_SIZE \| PAGE_SIZE - 1 \),
+ sysfs_emit(buf,
...);
...>
}
While at it, remove unnecessary braces and as well as unnecessary
else after return statements to address checkpatch warnings in the
resulting patch.
Cc: Zihao Tang <tangzihao1@hisilicon.com>
Cc: Jay Fang <f.fangjian@huawei.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2021-03-22 06:49:10 +03:00
return sysfs_emit ( buf , " %d \n " ,
data - > limit [ attr2 - > nr ] [ attr2 - > index ] ) ;
2011-02-02 19:49:54 +03:00
}
/* Construct a sensor_device_attribute structure for each register */
/* Input voltages */
2018-12-11 01:02:15 +03:00
static SENSOR_DEVICE_ATTR_RO ( in0_input , max16065_input , 0 ) ;
static SENSOR_DEVICE_ATTR_RO ( in1_input , max16065_input , 1 ) ;
static SENSOR_DEVICE_ATTR_RO ( in2_input , max16065_input , 2 ) ;
static SENSOR_DEVICE_ATTR_RO ( in3_input , max16065_input , 3 ) ;
static SENSOR_DEVICE_ATTR_RO ( in4_input , max16065_input , 4 ) ;
static SENSOR_DEVICE_ATTR_RO ( in5_input , max16065_input , 5 ) ;
static SENSOR_DEVICE_ATTR_RO ( in6_input , max16065_input , 6 ) ;
static SENSOR_DEVICE_ATTR_RO ( in7_input , max16065_input , 7 ) ;
static SENSOR_DEVICE_ATTR_RO ( in8_input , max16065_input , 8 ) ;
static SENSOR_DEVICE_ATTR_RO ( in9_input , max16065_input , 9 ) ;
static SENSOR_DEVICE_ATTR_RO ( in10_input , max16065_input , 10 ) ;
static SENSOR_DEVICE_ATTR_RO ( in11_input , max16065_input , 11 ) ;
static SENSOR_DEVICE_ATTR_RO ( in12_input , max16065_input , 12 ) ;
2011-02-02 19:49:54 +03:00
/* Input voltages lcrit */
2018-12-11 01:02:15 +03:00
static SENSOR_DEVICE_ATTR_2_RW ( in0_lcrit , max16065_limit , 2 , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in1_lcrit , max16065_limit , 2 , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in2_lcrit , max16065_limit , 2 , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in3_lcrit , max16065_limit , 2 , 3 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in4_lcrit , max16065_limit , 2 , 4 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in5_lcrit , max16065_limit , 2 , 5 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in6_lcrit , max16065_limit , 2 , 6 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in7_lcrit , max16065_limit , 2 , 7 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in8_lcrit , max16065_limit , 2 , 8 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in9_lcrit , max16065_limit , 2 , 9 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in10_lcrit , max16065_limit , 2 , 10 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in11_lcrit , max16065_limit , 2 , 11 ) ;
2011-02-02 19:49:54 +03:00
/* Input voltages crit */
2018-12-11 01:02:15 +03:00
static SENSOR_DEVICE_ATTR_2_RW ( in0_crit , max16065_limit , 1 , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in1_crit , max16065_limit , 1 , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in2_crit , max16065_limit , 1 , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in3_crit , max16065_limit , 1 , 3 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in4_crit , max16065_limit , 1 , 4 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in5_crit , max16065_limit , 1 , 5 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in6_crit , max16065_limit , 1 , 6 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in7_crit , max16065_limit , 1 , 7 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in8_crit , max16065_limit , 1 , 8 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in9_crit , max16065_limit , 1 , 9 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in10_crit , max16065_limit , 1 , 10 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in11_crit , max16065_limit , 1 , 11 ) ;
2011-02-02 19:49:54 +03:00
/* Input voltages min */
2018-12-11 01:02:15 +03:00
static SENSOR_DEVICE_ATTR_2_RW ( in0_min , max16065_limit , 0 , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in1_min , max16065_limit , 0 , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in2_min , max16065_limit , 0 , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in3_min , max16065_limit , 0 , 3 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in4_min , max16065_limit , 0 , 4 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in5_min , max16065_limit , 0 , 5 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in6_min , max16065_limit , 0 , 6 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in7_min , max16065_limit , 0 , 7 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in8_min , max16065_limit , 0 , 8 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in9_min , max16065_limit , 0 , 9 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in10_min , max16065_limit , 0 , 10 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in11_min , max16065_limit , 0 , 11 ) ;
2011-02-02 19:49:54 +03:00
/* Input voltages max */
2018-12-11 01:02:15 +03:00
static SENSOR_DEVICE_ATTR_2_RW ( in0_max , max16065_limit , 0 , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in1_max , max16065_limit , 0 , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in2_max , max16065_limit , 0 , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in3_max , max16065_limit , 0 , 3 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in4_max , max16065_limit , 0 , 4 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in5_max , max16065_limit , 0 , 5 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in6_max , max16065_limit , 0 , 6 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in7_max , max16065_limit , 0 , 7 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in8_max , max16065_limit , 0 , 8 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in9_max , max16065_limit , 0 , 9 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in10_max , max16065_limit , 0 , 10 ) ;
static SENSOR_DEVICE_ATTR_2_RW ( in11_max , max16065_limit , 0 , 11 ) ;
2011-02-02 19:49:54 +03:00
/* alarms */
2018-12-11 01:02:15 +03:00
static SENSOR_DEVICE_ATTR_2_RO ( in0_alarm , max16065_alarm , 0 , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in1_alarm , max16065_alarm , 0 , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in2_alarm , max16065_alarm , 0 , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in3_alarm , max16065_alarm , 0 , 3 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in4_alarm , max16065_alarm , 0 , 4 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in5_alarm , max16065_alarm , 0 , 5 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in6_alarm , max16065_alarm , 0 , 6 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in7_alarm , max16065_alarm , 0 , 7 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in8_alarm , max16065_alarm , 1 , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in9_alarm , max16065_alarm , 1 , 1 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in10_alarm , max16065_alarm , 1 , 2 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( in11_alarm , max16065_alarm , 1 , 3 ) ;
2011-02-02 19:49:54 +03:00
/* Current and alarm */
2018-12-11 01:02:15 +03:00
static SENSOR_DEVICE_ATTR_RO ( curr1_input , max16065_current , 0 ) ;
static SENSOR_DEVICE_ATTR_2_RO ( curr1_alarm , max16065_alarm , 1 , 4 ) ;
2011-02-02 19:49:54 +03:00
/*
* Finally , construct an array of pointers to members of the above objects ,
* as required for sysfs_create_group ( )
*/
static struct attribute * max16065_basic_attributes [ ] = {
& sensor_dev_attr_in0_input . dev_attr . attr ,
& sensor_dev_attr_in0_lcrit . dev_attr . attr ,
& sensor_dev_attr_in0_crit . dev_attr . attr ,
& sensor_dev_attr_in0_alarm . dev_attr . attr ,
& sensor_dev_attr_in1_input . dev_attr . attr ,
& sensor_dev_attr_in1_lcrit . dev_attr . attr ,
& sensor_dev_attr_in1_crit . dev_attr . attr ,
& sensor_dev_attr_in1_alarm . dev_attr . attr ,
& sensor_dev_attr_in2_input . dev_attr . attr ,
& sensor_dev_attr_in2_lcrit . dev_attr . attr ,
& sensor_dev_attr_in2_crit . dev_attr . attr ,
& sensor_dev_attr_in2_alarm . dev_attr . attr ,
& sensor_dev_attr_in3_input . dev_attr . attr ,
& sensor_dev_attr_in3_lcrit . dev_attr . attr ,
& sensor_dev_attr_in3_crit . dev_attr . attr ,
& sensor_dev_attr_in3_alarm . dev_attr . attr ,
& sensor_dev_attr_in4_input . dev_attr . attr ,
& sensor_dev_attr_in4_lcrit . dev_attr . attr ,
& sensor_dev_attr_in4_crit . dev_attr . attr ,
& sensor_dev_attr_in4_alarm . dev_attr . attr ,
& sensor_dev_attr_in5_input . dev_attr . attr ,
& sensor_dev_attr_in5_lcrit . dev_attr . attr ,
& sensor_dev_attr_in5_crit . dev_attr . attr ,
& sensor_dev_attr_in5_alarm . dev_attr . attr ,
& sensor_dev_attr_in6_input . dev_attr . attr ,
& sensor_dev_attr_in6_lcrit . dev_attr . attr ,
& sensor_dev_attr_in6_crit . dev_attr . attr ,
& sensor_dev_attr_in6_alarm . dev_attr . attr ,
& sensor_dev_attr_in7_input . dev_attr . attr ,
& sensor_dev_attr_in7_lcrit . dev_attr . attr ,
& sensor_dev_attr_in7_crit . dev_attr . attr ,
& sensor_dev_attr_in7_alarm . dev_attr . attr ,
& sensor_dev_attr_in8_input . dev_attr . attr ,
& sensor_dev_attr_in8_lcrit . dev_attr . attr ,
& sensor_dev_attr_in8_crit . dev_attr . attr ,
& sensor_dev_attr_in8_alarm . dev_attr . attr ,
& sensor_dev_attr_in9_input . dev_attr . attr ,
& sensor_dev_attr_in9_lcrit . dev_attr . attr ,
& sensor_dev_attr_in9_crit . dev_attr . attr ,
& sensor_dev_attr_in9_alarm . dev_attr . attr ,
& sensor_dev_attr_in10_input . dev_attr . attr ,
& sensor_dev_attr_in10_lcrit . dev_attr . attr ,
& sensor_dev_attr_in10_crit . dev_attr . attr ,
& sensor_dev_attr_in10_alarm . dev_attr . attr ,
& sensor_dev_attr_in11_input . dev_attr . attr ,
& sensor_dev_attr_in11_lcrit . dev_attr . attr ,
& sensor_dev_attr_in11_crit . dev_attr . attr ,
& sensor_dev_attr_in11_alarm . dev_attr . attr ,
NULL
} ;
static struct attribute * max16065_current_attributes [ ] = {
& sensor_dev_attr_in12_input . dev_attr . attr ,
& sensor_dev_attr_curr1_input . dev_attr . attr ,
& sensor_dev_attr_curr1_alarm . dev_attr . attr ,
NULL
} ;
static struct attribute * max16065_min_attributes [ ] = {
& 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_in4_min . dev_attr . attr ,
& sensor_dev_attr_in5_min . dev_attr . attr ,
& sensor_dev_attr_in6_min . dev_attr . attr ,
& sensor_dev_attr_in7_min . dev_attr . attr ,
& sensor_dev_attr_in8_min . dev_attr . attr ,
& sensor_dev_attr_in9_min . dev_attr . attr ,
& sensor_dev_attr_in10_min . dev_attr . attr ,
& sensor_dev_attr_in11_min . dev_attr . attr ,
NULL
} ;
static struct attribute * max16065_max_attributes [ ] = {
& 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_in4_max . dev_attr . attr ,
& sensor_dev_attr_in5_max . dev_attr . attr ,
& sensor_dev_attr_in6_max . dev_attr . attr ,
& sensor_dev_attr_in7_max . dev_attr . attr ,
& sensor_dev_attr_in8_max . dev_attr . attr ,
& sensor_dev_attr_in9_max . dev_attr . attr ,
& sensor_dev_attr_in10_max . dev_attr . attr ,
& sensor_dev_attr_in11_max . dev_attr . attr ,
NULL
} ;
2013-09-02 22:31:28 +04:00
static umode_t max16065_basic_is_visible ( struct kobject * kobj ,
struct attribute * a , int n )
{
2021-03-18 22:06:19 +03:00
struct device * dev = kobj_to_dev ( kobj ) ;
2013-09-02 22:31:28 +04:00
struct max16065_data * data = dev_get_drvdata ( dev ) ;
int index = n / 4 ;
if ( index > = data - > num_adc | | ! data - > range [ index ] )
return 0 ;
return a - > mode ;
}
static umode_t max16065_secondary_is_visible ( struct kobject * kobj ,
struct attribute * a , int index )
{
2021-03-18 22:06:19 +03:00
struct device * dev = kobj_to_dev ( kobj ) ;
2013-09-02 22:31:28 +04:00
struct max16065_data * data = dev_get_drvdata ( dev ) ;
if ( index > = data - > num_adc )
return 0 ;
return a - > mode ;
}
2011-02-02 19:49:54 +03:00
static const struct attribute_group max16065_basic_group = {
. attrs = max16065_basic_attributes ,
2013-09-02 22:31:28 +04:00
. is_visible = max16065_basic_is_visible ,
2011-02-02 19:49:54 +03:00
} ;
static const struct attribute_group max16065_current_group = {
. attrs = max16065_current_attributes ,
} ;
static const struct attribute_group max16065_min_group = {
. attrs = max16065_min_attributes ,
2013-09-02 22:31:28 +04:00
. is_visible = max16065_secondary_is_visible ,
2011-02-02 19:49:54 +03:00
} ;
static const struct attribute_group max16065_max_group = {
. attrs = max16065_max_attributes ,
2013-09-02 22:31:28 +04:00
. is_visible = max16065_secondary_is_visible ,
2011-02-02 19:49:54 +03:00
} ;
2020-08-13 19:02:22 +03:00
static const struct i2c_device_id max16065_id [ ] ;
static int max16065_probe ( struct i2c_client * client )
2011-02-02 19:49:54 +03:00
{
struct i2c_adapter * adapter = client - > adapter ;
struct max16065_data * data ;
2013-09-02 22:31:28 +04:00
struct device * dev = & client - > dev ;
struct device * hwmon_dev ;
int i , j , val ;
2011-02-02 19:49:54 +03:00
bool have_secondary ; /* true if chip has secondary limits */
bool secondary_is_max = false ; /* secondary limits reflect max */
2013-09-02 22:31:28 +04:00
int groups = 0 ;
2020-08-13 19:02:22 +03:00
const struct i2c_device_id * id = i2c_match_id ( max16065_id , client ) ;
2011-02-02 19:49:54 +03:00
if ( ! i2c_check_functionality ( adapter , I2C_FUNC_SMBUS_BYTE_DATA
| I2C_FUNC_SMBUS_READ_WORD_DATA ) )
return - ENODEV ;
2013-09-02 22:31:28 +04:00
data = devm_kzalloc ( dev , sizeof ( * data ) , GFP_KERNEL ) ;
2011-02-02 19:49:54 +03:00
if ( unlikely ( ! data ) )
return - ENOMEM ;
2013-09-02 22:31:28 +04:00
data - > client = client ;
2011-02-02 19:49:54 +03:00
mutex_init ( & data - > update_lock ) ;
data - > num_adc = max16065_num_adc [ id - > driver_data ] ;
data - > have_current = max16065_have_current [ id - > driver_data ] ;
have_secondary = max16065_have_secondary [ id - > driver_data ] ;
if ( have_secondary ) {
val = i2c_smbus_read_byte_data ( client , MAX16065_SW_ENABLE ) ;
2012-02-22 20:56:46 +04:00
if ( unlikely ( val < 0 ) )
return val ;
2011-02-02 19:49:54 +03:00
secondary_is_max = val & MAX16065_WARNING_OV ;
}
/* Read scale registers, convert to range */
for ( i = 0 ; i < DIV_ROUND_UP ( data - > num_adc , 4 ) ; i + + ) {
val = i2c_smbus_read_byte_data ( client , MAX16065_SCALE ( i ) ) ;
2012-02-22 20:56:46 +04:00
if ( unlikely ( val < 0 ) )
return val ;
2011-02-02 19:49:54 +03:00
for ( j = 0 ; j < 4 & & i * 4 + j < data - > num_adc ; j + + ) {
data - > range [ i * 4 + j ] =
max16065_adc_range [ ( val > > ( j * 2 ) ) & 0x3 ] ;
}
}
/* Read limits */
for ( i = 0 ; i < MAX16065_NUM_LIMIT ; i + + ) {
if ( i = = 0 & & ! have_secondary )
continue ;
for ( j = 0 ; j < data - > num_adc ; j + + ) {
val = i2c_smbus_read_byte_data ( client ,
MAX16065_LIMIT ( i , j ) ) ;
2012-02-22 20:56:46 +04:00
if ( unlikely ( val < 0 ) )
return val ;
2011-02-02 19:49:54 +03:00
data - > limit [ i ] [ j ] = LIMIT_TO_MV ( val , data - > range [ j ] ) ;
}
}
2013-09-02 22:31:28 +04:00
/* sysfs hooks */
data - > groups [ groups + + ] = & max16065_basic_group ;
if ( have_secondary )
data - > groups [ groups + + ] = secondary_is_max ?
& max16065_max_group : & max16065_min_group ;
2011-02-02 19:49:54 +03:00
if ( data - > have_current ) {
val = i2c_smbus_read_byte_data ( client , MAX16065_CURR_CONTROL ) ;
2013-09-02 22:31:28 +04:00
if ( unlikely ( val < 0 ) )
return val ;
2011-02-02 19:49:54 +03:00
if ( val & MAX16065_CURR_ENABLE ) {
/*
* Current gain is 6 , 12 , 24 , 48 based on values in
* bit 2 , 3.
*/
data - > curr_gain = 6 < < ( ( val > > 2 ) & 0x03 ) ;
data - > range [ MAX16065_NUM_ADC ]
= max16065_csp_adc_range [ ( val > > 1 ) & 0x01 ] ;
2013-09-02 22:31:28 +04:00
data - > groups [ groups + + ] = & max16065_current_group ;
2011-02-02 19:49:54 +03:00
} else {
data - > have_current = false ;
}
}
2013-09-02 22:31:28 +04:00
hwmon_dev = devm_hwmon_device_register_with_groups ( dev , client - > name ,
data , data - > groups ) ;
2014-07-11 12:45:37 +04:00
return PTR_ERR_OR_ZERO ( hwmon_dev ) ;
2011-02-02 19:49:54 +03:00
}
static const struct i2c_device_id max16065_id [ ] = {
{ " max16065 " , max16065 } ,
{ " max16066 " , max16066 } ,
{ " max16067 " , max16067 } ,
{ " max16068 " , max16068 } ,
{ " max16070 " , max16070 } ,
{ " max16071 " , max16071 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , max16065_id ) ;
/* This is the driver that will be inserted */
static struct i2c_driver max16065_driver = {
. driver = {
. name = " max16065 " ,
} ,
2020-08-13 19:02:22 +03:00
. probe_new = max16065_probe ,
2011-02-02 19:49:54 +03:00
. id_table = max16065_id ,
} ;
2012-01-20 11:38:18 +04:00
module_i2c_driver ( max16065_driver ) ;
2011-02-02 19:49:54 +03:00
2012-06-22 23:07:25 +04:00
MODULE_AUTHOR ( " Guenter Roeck <linux@roeck-us.net> " ) ;
2011-02-02 19:49:54 +03:00
MODULE_DESCRIPTION ( " MAX16065 driver " ) ;
MODULE_LICENSE ( " GPL " ) ;