2019-05-27 09:55:06 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2014-01-11 12:17:05 +04:00
/*
* Driver for Linear Technology LTC4260 I2C Positive Voltage Hot Swap Controller
*
* Copyright ( c ) 2014 Guenter Roeck
*/
# include <linux/kernel.h>
# include <linux/module.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>
# include <linux/regmap.h>
/* chip registers */
# define LTC4260_CONTROL 0x00
# define LTC4260_ALERT 0x01
# define LTC4260_STATUS 0x02
# define LTC4260_FAULT 0x03
# define LTC4260_SENSE 0x04
# define LTC4260_SOURCE 0x05
# define LTC4260_ADIN 0x06
/*
* Fault register bits
*/
# define FAULT_OV (1 << 0)
# define FAULT_UV (1 << 1)
# define FAULT_OC (1 << 2)
# define FAULT_POWER_BAD (1 << 3)
# define FAULT_FET_SHORT (1 << 5)
/* Return the voltage from the given register in mV or mA */
static int ltc4260_get_value ( struct device * dev , u8 reg )
{
struct regmap * regmap = dev_get_drvdata ( dev ) ;
unsigned int val ;
int ret ;
ret = regmap_read ( regmap , reg , & val ) ;
if ( ret < 0 )
return ret ;
switch ( reg ) {
case LTC4260_ADIN :
/* 10 mV resolution. Convert to mV. */
val = val * 10 ;
break ;
case LTC4260_SOURCE :
/* 400 mV resolution. Convert to mV. */
val = val * 400 ;
break ;
case LTC4260_SENSE :
/*
* 300 uV resolution . Convert to current as measured with
* an 1 mOhm sense resistor , in mA . If a different sense
* resistor is installed , calculate the actual current by
* dividing the reported current by the sense resistor value
* in mOhm .
*/
val = val * 300 ;
break ;
default :
return - EINVAL ;
}
return val ;
}
2018-12-06 21:44:42 +03:00
static ssize_t ltc4260_value_show ( struct device * dev ,
2014-01-11 12:17:05 +04:00
struct device_attribute * da , char * buf )
{
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ;
int value ;
value = ltc4260_get_value ( dev , attr - > index ) ;
if ( value < 0 )
return value ;
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 " , value ) ;
2014-01-11 12:17:05 +04:00
}
2018-12-06 21:44:42 +03:00
static ssize_t ltc4260_bool_show ( struct device * dev ,
2014-01-11 12:17:05 +04:00
struct device_attribute * da , char * buf )
{
struct sensor_device_attribute * attr = to_sensor_dev_attr ( da ) ;
struct regmap * regmap = dev_get_drvdata ( dev ) ;
unsigned int fault ;
int ret ;
ret = regmap_read ( regmap , LTC4260_FAULT , & fault ) ;
if ( ret < 0 )
return ret ;
fault & = attr - > index ;
if ( fault ) /* Clear reported faults in chip register */
regmap_update_bits ( regmap , LTC4260_FAULT , attr - > index , 0 ) ;
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 " , ! ! fault ) ;
2014-01-11 12:17:05 +04:00
}
/* Voltages */
2018-12-06 21:44:42 +03:00
static SENSOR_DEVICE_ATTR_RO ( in1_input , ltc4260_value , LTC4260_SOURCE ) ;
static SENSOR_DEVICE_ATTR_RO ( in2_input , ltc4260_value , LTC4260_ADIN ) ;
2014-01-11 12:17:05 +04:00
/*
* Voltage alarms
* UV / OV faults are associated with the input voltage , and the POWER BAD and
* FET SHORT faults are associated with the output voltage .
*/
2018-12-06 21:44:42 +03:00
static SENSOR_DEVICE_ATTR_RO ( in1_min_alarm , ltc4260_bool , FAULT_UV ) ;
static SENSOR_DEVICE_ATTR_RO ( in1_max_alarm , ltc4260_bool , FAULT_OV ) ;
static SENSOR_DEVICE_ATTR_RO ( in2_alarm , ltc4260_bool ,
FAULT_POWER_BAD | FAULT_FET_SHORT ) ;
2014-01-11 12:17:05 +04:00
/* Current (via sense resistor) */
2018-12-06 21:44:42 +03:00
static SENSOR_DEVICE_ATTR_RO ( curr1_input , ltc4260_value , LTC4260_SENSE ) ;
2014-01-11 12:17:05 +04:00
/* Overcurrent alarm */
2018-12-06 21:44:42 +03:00
static SENSOR_DEVICE_ATTR_RO ( curr1_max_alarm , ltc4260_bool , FAULT_OC ) ;
2014-01-11 12:17:05 +04:00
static struct attribute * ltc4260_attrs [ ] = {
& sensor_dev_attr_in1_input . dev_attr . attr ,
& sensor_dev_attr_in1_min_alarm . dev_attr . attr ,
& sensor_dev_attr_in1_max_alarm . dev_attr . attr ,
& sensor_dev_attr_in2_input . dev_attr . attr ,
& sensor_dev_attr_in2_alarm . dev_attr . attr ,
& sensor_dev_attr_curr1_input . dev_attr . attr ,
& sensor_dev_attr_curr1_max_alarm . dev_attr . attr ,
NULL ,
} ;
ATTRIBUTE_GROUPS ( ltc4260 ) ;
2014-07-02 04:42:18 +04:00
static const struct regmap_config ltc4260_regmap_config = {
2014-01-11 12:17:05 +04:00
. reg_bits = 8 ,
. val_bits = 8 ,
. max_register = LTC4260_ADIN ,
} ;
2020-08-13 19:02:22 +03:00
static int ltc4260_probe ( struct i2c_client * client )
2014-01-11 12:17:05 +04:00
{
struct device * dev = & client - > dev ;
struct device * hwmon_dev ;
struct regmap * regmap ;
regmap = devm_regmap_init_i2c ( client , & ltc4260_regmap_config ) ;
if ( IS_ERR ( regmap ) ) {
dev_err ( dev , " failed to allocate register map \n " ) ;
return PTR_ERR ( regmap ) ;
}
/* Clear faults */
regmap_write ( regmap , LTC4260_FAULT , 0x00 ) ;
hwmon_dev = devm_hwmon_device_register_with_groups ( dev , client - > name ,
regmap ,
ltc4260_groups ) ;
return PTR_ERR_OR_ZERO ( hwmon_dev ) ;
}
static const struct i2c_device_id ltc4260_id [ ] = {
{ " ltc4260 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , ltc4260_id ) ;
static struct i2c_driver ltc4260_driver = {
. driver = {
. name = " ltc4260 " ,
} ,
2020-08-13 19:02:22 +03:00
. probe_new = ltc4260_probe ,
2014-01-11 12:17:05 +04:00
. id_table = ltc4260_id ,
} ;
module_i2c_driver ( ltc4260_driver ) ;
MODULE_AUTHOR ( " Guenter Roeck <linux@roeck-us.net> " ) ;
MODULE_DESCRIPTION ( " LTC4260 driver " ) ;
MODULE_LICENSE ( " GPL " ) ;