2019-05-20 09:19:02 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2009-06-15 18:39:46 +02:00
/* tmp401.c
*
* Copyright ( C ) 2007 , 2008 Hans de Goede < hdegoede @ redhat . com >
2009-06-15 18:39:47 +02:00
* Preliminary tmp411 support by :
* Gabriel Konat , Sander Leget , Wouter Willems
* Copyright ( C ) 2009 Andre Prendel < andre . prendel @ gmx . de >
2009-06-15 18:39:46 +02:00
*
2013-03-28 01:36:44 -07:00
* Cleanup and support for TMP431 and TMP432 by Guenter Roeck
* Copyright ( c ) 2013 Guenter Roeck < linux @ roeck - us . net >
2009-06-15 18:39:46 +02:00
*/
/*
* Driver for the Texas Instruments TMP401 SMBUS temperature sensor IC .
*
* Note this IC is in some aspect similar to the LM90 , but it has quite a
* few differences too , for example the local temp has a higher resolution
* and thus has 16 bits registers for its value and limit instead of 8 bits .
*/
2013-03-27 08:48:03 -07:00
# include <linux/bitops.h>
2021-10-16 10:51:27 -07:00
# include <linux/err.h>
2009-06-15 18:39:46 +02:00
# include <linux/i2c.h>
# include <linux/hwmon.h>
2021-10-16 10:51:27 -07:00
# include <linux/init.h>
# include <linux/module.h>
2009-06-15 18:39:46 +02:00
# include <linux/mutex.h>
2021-10-16 14:56:29 -07:00
# include <linux/regmap.h>
2021-10-16 10:51:27 -07:00
# include <linux/slab.h>
2009-06-15 18:39:46 +02:00
/* Addresses to scan */
2015-05-27 16:11:48 -07:00
static const unsigned short normal_i2c [ ] = { 0x48 , 0x49 , 0x4a , 0x4c , 0x4d ,
2014-12-05 10:15:03 -08:00
0x4e , 0x4f , I2C_CLIENT_END } ;
2009-06-15 18:39:46 +02:00
2021-10-15 17:34:25 -07:00
enum chips { tmp401 , tmp411 , tmp431 , tmp432 , tmp435 } ;
2009-06-15 18:39:46 +02:00
/*
* The TMP401 registers , note some registers have different addresses for
* reading and writing
*/
# define TMP401_STATUS 0x02
2021-11-09 13:18:26 -08:00
# define TMP401_CONFIG 0x03
# define TMP401_CONVERSION_RATE 0x04
2022-04-14 09:58:23 +02:00
# define TMP4XX_N_FACTOR_REG 0x18
# define TMP43X_BETA_RANGE 0x25
2009-06-15 18:39:46 +02:00
# define TMP401_TEMP_CRIT_HYST 0x21
# define TMP401_MANUFACTURER_ID_REG 0xFE
# define TMP401_DEVICE_ID_REG 0xFF
2021-11-09 13:18:26 -08:00
static const u8 TMP401_TEMP_MSB [ 7 ] [ 3 ] = {
2013-03-28 01:36:44 -07:00
{ 0x00 , 0x01 , 0x23 } , /* temp */
{ 0x06 , 0x08 , 0x16 } , /* low limit */
{ 0x05 , 0x07 , 0x15 } , /* high limit */
2021-10-17 07:47:43 -07:00
{ 0x20 , 0x19 , 0x1a } , /* therm (crit) limit */
{ 0x30 , 0x34 , 0x00 } , /* lowest */
2021-10-16 10:51:27 -07:00
{ 0x32 , 0xf6 , 0x00 } , /* highest */
2013-03-28 01:36:44 -07:00
} ;
/* [0] = fault, [1] = low, [2] = high, [3] = therm/crit */
static const u8 TMP432_STATUS_REG [ ] = {
0x1b , 0x36 , 0x35 , 0x37 } ;
2009-06-15 18:39:46 +02:00
/* Flags */
2013-03-27 08:48:03 -07:00
# define TMP401_CONFIG_RANGE BIT(2)
# define TMP401_CONFIG_SHUTDOWN BIT(6)
# define TMP401_STATUS_LOCAL_CRIT BIT(0)
# define TMP401_STATUS_REMOTE_CRIT BIT(1)
# define TMP401_STATUS_REMOTE_OPEN BIT(2)
# define TMP401_STATUS_REMOTE_LOW BIT(3)
# define TMP401_STATUS_REMOTE_HIGH BIT(4)
# define TMP401_STATUS_LOCAL_LOW BIT(5)
# define TMP401_STATUS_LOCAL_HIGH BIT(6)
2009-06-15 18:39:46 +02:00
2013-03-28 01:36:44 -07:00
/* On TMP432, each status has its own register */
# define TMP432_STATUS_LOCAL BIT(0)
# define TMP432_STATUS_REMOTE1 BIT(1)
# define TMP432_STATUS_REMOTE2 BIT(2)
2009-06-15 18:39:46 +02:00
/* Manufacturer / Device ID's */
# define TMP401_MANUFACTURER_ID 0x55
# define TMP401_DEVICE_ID 0x11
2013-03-29 17:56:07 -07:00
# define TMP411A_DEVICE_ID 0x12
# define TMP411B_DEVICE_ID 0x13
# define TMP411C_DEVICE_ID 0x10
2013-03-15 12:55:08 -07:00
# define TMP431_DEVICE_ID 0x31
2013-03-28 01:36:44 -07:00
# define TMP432_DEVICE_ID 0x32
2014-12-04 17:45:51 +01:00
# define TMP435_DEVICE_ID 0x35
2009-06-15 18:39:46 +02:00
/*
* Driver data ( common to all clients )
*/
static const struct i2c_device_id tmp401_id [ ] = {
{ " tmp401 " , tmp401 } ,
2009-06-15 18:39:47 +02:00
{ " tmp411 " , tmp411 } ,
2013-03-15 12:55:08 -07:00
{ " tmp431 " , tmp431 } ,
2013-03-28 01:36:44 -07:00
{ " tmp432 " , tmp432 } ,
2014-12-04 17:45:51 +01:00
{ " tmp435 " , tmp435 } ,
2009-06-15 18:39:46 +02:00
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , tmp401_id ) ;
/*
* Client data ( each client gets its own )
*/
struct tmp401_data {
2013-09-04 16:24:09 -07:00
struct i2c_client * client ;
2021-10-16 14:56:29 -07:00
struct regmap * regmap ;
2009-06-15 18:39:46 +02:00
struct mutex update_lock ;
2010-03-05 22:17:26 +01:00
enum chips kind ;
2009-06-15 18:39:46 +02:00
2021-10-16 10:51:27 -07:00
bool extended_range ;
2013-03-28 02:03:10 -07:00
2021-10-16 10:51:27 -07:00
/* hwmon API configuration data */
u32 chip_channel_config [ 4 ] ;
struct hwmon_channel_info chip_info ;
u32 temp_channel_config [ 4 ] ;
struct hwmon_channel_info temp_info ;
const struct hwmon_channel_info * info [ 3 ] ;
struct hwmon_chip_info chip ;
2009-06-15 18:39:46 +02:00
} ;
2021-10-16 14:56:29 -07:00
/* regmap */
2009-06-15 18:39:46 +02:00
2021-10-16 14:56:29 -07:00
static bool tmp401_regmap_is_volatile ( struct device * dev , unsigned int reg )
2009-06-15 18:39:46 +02:00
{
2021-10-16 14:56:29 -07:00
switch ( reg ) {
case 0 : /* local temp msb */
case 1 : /* remote temp msb */
case 2 : /* status */
case 0x10 : /* remote temp lsb */
case 0x15 : /* local temp lsb */
case 0x1b : /* status (tmp432) */
case 0x23 . . . 0x24 : /* remote temp 2 msb / lsb */
case 0x30 . . . 0x37 : /* lowest/highest temp; status (tmp432) */
return true ;
default :
return false ;
2021-10-16 10:51:27 -07:00
}
2009-06-15 18:39:46 +02:00
}
2021-10-16 14:56:29 -07:00
static int tmp401_reg_read ( void * context , unsigned int reg , unsigned int * val )
2010-05-27 19:58:49 +02:00
{
2021-10-16 14:56:29 -07:00
struct tmp401_data * data = context ;
2013-09-04 16:24:09 -07:00
struct i2c_client * client = data - > client ;
2021-10-16 14:56:29 -07:00
int regval ;
2010-05-27 19:58:49 +02:00
2021-10-16 10:51:27 -07:00
switch ( reg ) {
case 0 : /* local temp msb */
case 1 : /* remote temp msb */
case 5 : /* local temp high limit msb */
case 6 : /* local temp low limit msb */
case 7 : /* remote temp ligh limit msb */
case 8 : /* remote temp low limit msb */
case 0x15 : /* remote temp 2 high limit msb */
case 0x16 : /* remote temp 2 low limit msb */
case 0x23 : /* remote temp 2 msb */
case 0x30 : /* local temp minimum, tmp411 */
case 0x32 : /* local temp maximum, tmp411 */
case 0x34 : /* remote temp minimum, tmp411 */
case 0xf6 : /* remote temp maximum, tmp411 (really 0x36) */
/* work around register overlap between TMP411 and TMP432 */
if ( reg = = 0xf6 )
reg = 0x36 ;
2021-10-16 14:56:29 -07:00
regval = i2c_smbus_read_word_swapped ( client , reg ) ;
if ( regval < 0 )
return regval ;
* val = regval ;
break ;
2021-10-16 10:51:27 -07:00
case 0x19 : /* critical limits, 8-bit registers */
case 0x1a :
case 0x20 :
regval = i2c_smbus_read_byte_data ( client , reg ) ;
if ( regval < 0 )
return regval ;
2021-10-16 14:56:29 -07:00
* val = regval < < 8 ;
break ;
2021-10-16 10:51:27 -07:00
case 0x1b :
case 0x35 . . . 0x37 :
2021-10-16 14:56:29 -07:00
if ( data - > kind = = tmp432 ) {
regval = i2c_smbus_read_byte_data ( client , reg ) ;
if ( regval < 0 )
return regval ;
* val = regval ;
break ;
}
2021-10-16 10:51:27 -07:00
/* simulate TMP432 status registers */
regval = i2c_smbus_read_byte_data ( client , TMP401_STATUS ) ;
if ( regval < 0 )
return regval ;
2021-10-16 14:56:29 -07:00
* val = 0 ;
2021-10-16 10:51:27 -07:00
switch ( reg ) {
case 0x1b : /* open / fault */
if ( regval & TMP401_STATUS_REMOTE_OPEN )
2021-10-16 14:56:29 -07:00
* val | = BIT ( 1 ) ;
2021-10-16 10:51:27 -07:00
break ;
case 0x35 : /* high limit */
if ( regval & TMP401_STATUS_LOCAL_HIGH )
2021-10-16 14:56:29 -07:00
* val | = BIT ( 0 ) ;
2021-10-16 10:51:27 -07:00
if ( regval & TMP401_STATUS_REMOTE_HIGH )
2021-10-16 14:56:29 -07:00
* val | = BIT ( 1 ) ;
2021-10-16 10:51:27 -07:00
break ;
case 0x36 : /* low limit */
if ( regval & TMP401_STATUS_LOCAL_LOW )
2021-10-16 14:56:29 -07:00
* val | = BIT ( 0 ) ;
2021-10-16 10:51:27 -07:00
if ( regval & TMP401_STATUS_REMOTE_LOW )
2021-10-16 14:56:29 -07:00
* val | = BIT ( 1 ) ;
2021-10-16 10:51:27 -07:00
break ;
case 0x37 : /* therm / crit limit */
if ( regval & TMP401_STATUS_LOCAL_CRIT )
2021-10-16 14:56:29 -07:00
* val | = BIT ( 0 ) ;
2021-10-16 10:51:27 -07:00
if ( regval & TMP401_STATUS_REMOTE_CRIT )
2021-10-16 14:56:29 -07:00
* val | = BIT ( 1 ) ;
2021-10-16 10:51:27 -07:00
break ;
2013-03-27 21:23:10 -07:00
}
2021-10-16 14:56:29 -07:00
break ;
2021-10-16 10:51:27 -07:00
default :
2021-10-16 14:56:29 -07:00
regval = i2c_smbus_read_byte_data ( client , reg ) ;
if ( regval < 0 )
return regval ;
* val = regval ;
break ;
2010-05-27 19:58:49 +02:00
}
2021-10-16 14:56:29 -07:00
return 0 ;
2009-06-15 18:39:46 +02:00
}
2021-10-16 14:56:29 -07:00
static int tmp401_reg_write ( void * context , unsigned int reg , unsigned int val )
2009-06-15 18:39:46 +02:00
{
2021-10-16 14:56:29 -07:00
struct tmp401_data * data = context ;
2021-10-16 10:51:27 -07:00
struct i2c_client * client = data - > client ;
2009-06-15 18:39:46 +02:00
2021-10-16 10:51:27 -07:00
switch ( reg ) {
2021-11-09 13:18:26 -08:00
case 0x05 : /* local temp high limit msb */
case 0x06 : /* local temp low limit msb */
case 0x07 : /* remote temp ligh limit msb */
case 0x08 : /* remote temp low limit msb */
reg + = 6 ; /* adjust for register write address */
fallthrough ;
2021-10-16 10:51:27 -07:00
case 0x15 : /* remote temp 2 high limit msb */
case 0x16 : /* remote temp 2 low limit msb */
return i2c_smbus_write_word_swapped ( client , reg , val ) ;
case 0x19 : /* critical limits, 8-bit registers */
case 0x1a :
case 0x20 :
return i2c_smbus_write_byte_data ( client , reg , val > > 8 ) ;
2021-11-09 13:18:26 -08:00
case TMP401_CONVERSION_RATE :
case TMP401_CONFIG :
reg + = 6 ; /* adjust for register write address */
fallthrough ;
2021-10-16 10:51:27 -07:00
default :
return i2c_smbus_write_byte_data ( client , reg , val ) ;
}
2009-06-15 18:39:46 +02:00
}
2021-10-16 14:56:29 -07:00
static const struct regmap_config tmp401_regmap_config = {
. reg_bits = 8 ,
. val_bits = 16 ,
. cache_type = REGCACHE_RBTREE ,
. volatile_reg = tmp401_regmap_is_volatile ,
. reg_read = tmp401_reg_read ,
. reg_write = tmp401_reg_write ,
} ;
/* temperature conversion */
static int tmp401_register_to_temp ( u16 reg , bool extended )
{
int temp = reg ;
if ( extended )
temp - = 64 * 256 ;
return DIV_ROUND_CLOSEST ( temp * 125 , 32 ) ;
}
static u16 tmp401_temp_to_register ( long temp , bool extended , int zbits )
{
if ( extended ) {
temp = clamp_val ( temp , - 64000 , 191000 ) ;
temp + = 64000 ;
} else {
temp = clamp_val ( temp , 0 , 127000 ) ;
}
return DIV_ROUND_CLOSEST ( temp * ( 1 < < ( 8 - zbits ) ) , 1000 ) < < zbits ;
}
/* hwmon API functions */
2021-10-16 10:51:27 -07:00
static const u8 tmp401_temp_reg_index [ ] = {
[ hwmon_temp_input ] = 0 ,
[ hwmon_temp_min ] = 1 ,
[ hwmon_temp_max ] = 2 ,
[ hwmon_temp_crit ] = 3 ,
[ hwmon_temp_lowest ] = 4 ,
[ hwmon_temp_highest ] = 5 ,
} ;
2009-06-15 18:39:46 +02:00
2021-10-16 10:51:27 -07:00
static const u8 tmp401_status_reg_index [ ] = {
[ hwmon_temp_fault ] = 0 ,
[ hwmon_temp_min_alarm ] = 1 ,
[ hwmon_temp_max_alarm ] = 2 ,
[ hwmon_temp_crit_alarm ] = 3 ,
} ;
2009-06-15 18:39:46 +02:00
2021-10-16 10:51:27 -07:00
static int tmp401_temp_read ( struct device * dev , u32 attr , int channel , long * val )
2009-06-15 18:39:46 +02:00
{
2013-09-04 16:24:09 -07:00
struct tmp401_data * data = dev_get_drvdata ( dev ) ;
2021-10-16 14:56:29 -07:00
struct regmap * regmap = data - > regmap ;
unsigned int regval ;
int reg , ret ;
2021-10-16 10:51:27 -07:00
switch ( attr ) {
case hwmon_temp_input :
case hwmon_temp_min :
case hwmon_temp_max :
case hwmon_temp_crit :
case hwmon_temp_lowest :
case hwmon_temp_highest :
2021-11-09 13:18:26 -08:00
reg = TMP401_TEMP_MSB [ tmp401_temp_reg_index [ attr ] ] [ channel ] ;
2021-10-16 14:56:29 -07:00
ret = regmap_read ( regmap , reg , & regval ) ;
if ( ret < 0 )
return ret ;
2021-10-16 10:51:27 -07:00
* val = tmp401_register_to_temp ( regval , data - > extended_range ) ;
break ;
case hwmon_temp_crit_hyst :
mutex_lock ( & data - > update_lock ) ;
2021-11-09 13:18:26 -08:00
reg = TMP401_TEMP_MSB [ 3 ] [ channel ] ;
2021-10-16 14:56:29 -07:00
ret = regmap_read ( regmap , reg , & regval ) ;
if ( ret < 0 )
2021-10-16 10:51:27 -07:00
goto unlock ;
* val = tmp401_register_to_temp ( regval , data - > extended_range ) ;
2021-10-16 14:56:29 -07:00
ret = regmap_read ( regmap , TMP401_TEMP_CRIT_HYST , & regval ) ;
if ( ret < 0 )
2021-10-16 10:51:27 -07:00
goto unlock ;
* val - = regval * 1000 ;
unlock :
mutex_unlock ( & data - > update_lock ) ;
2021-10-16 14:56:29 -07:00
if ( ret < 0 )
return ret ;
2021-10-16 10:51:27 -07:00
break ;
case hwmon_temp_fault :
case hwmon_temp_min_alarm :
case hwmon_temp_max_alarm :
case hwmon_temp_crit_alarm :
reg = TMP432_STATUS_REG [ tmp401_status_reg_index [ attr ] ] ;
2021-10-16 14:56:29 -07:00
ret = regmap_read ( regmap , reg , & regval ) ;
if ( ret < 0 )
return ret ;
2021-10-16 10:51:27 -07:00
* val = ! ! ( regval & BIT ( channel ) ) ;
break ;
default :
return - EOPNOTSUPP ;
2013-03-27 21:23:10 -07:00
}
2021-10-16 10:51:27 -07:00
return 0 ;
2009-06-15 18:39:46 +02:00
}
2021-10-16 10:51:27 -07:00
static int tmp401_temp_write ( struct device * dev , u32 attr , int channel ,
long val )
2009-06-15 18:39:47 +02:00
{
2013-09-04 16:24:09 -07:00
struct tmp401_data * data = dev_get_drvdata ( dev ) ;
2021-10-16 14:56:29 -07:00
struct regmap * regmap = data - > regmap ;
unsigned int regval ;
int reg , ret , temp ;
2009-06-15 18:39:47 +02:00
2013-04-14 04:39:46 -07:00
mutex_lock ( & data - > update_lock ) ;
2021-10-16 10:51:27 -07:00
switch ( attr ) {
case hwmon_temp_min :
case hwmon_temp_max :
case hwmon_temp_crit :
2021-11-09 13:18:26 -08:00
reg = TMP401_TEMP_MSB [ tmp401_temp_reg_index [ attr ] ] [ channel ] ;
2021-10-16 10:51:27 -07:00
regval = tmp401_temp_to_register ( val , data - > extended_range ,
attr = = hwmon_temp_crit ? 8 : 4 ) ;
2021-10-16 14:56:29 -07:00
ret = regmap_write ( regmap , reg , regval ) ;
2021-10-16 10:51:27 -07:00
break ;
case hwmon_temp_crit_hyst :
if ( data - > extended_range )
val = clamp_val ( val , - 64000 , 191000 ) ;
else
val = clamp_val ( val , 0 , 127000 ) ;
2021-11-09 13:18:26 -08:00
reg = TMP401_TEMP_MSB [ 3 ] [ channel ] ;
2021-10-16 14:56:29 -07:00
ret = regmap_read ( regmap , reg , & regval ) ;
2021-10-16 10:51:27 -07:00
if ( ret < 0 )
break ;
2021-10-16 14:56:29 -07:00
temp = tmp401_register_to_temp ( regval , data - > extended_range ) ;
2021-10-16 10:51:27 -07:00
val = clamp_val ( val , temp - 255000 , temp ) ;
regval = ( ( temp - val ) + 500 ) / 1000 ;
2021-10-16 14:56:29 -07:00
ret = regmap_write ( regmap , TMP401_TEMP_CRIT_HYST , regval ) ;
2021-10-16 10:51:27 -07:00
break ;
default :
ret = - EOPNOTSUPP ;
break ;
}
2013-04-14 04:39:46 -07:00
mutex_unlock ( & data - > update_lock ) ;
2021-10-16 10:51:27 -07:00
return ret ;
2009-06-15 18:39:47 +02:00
}
2021-10-16 10:51:27 -07:00
static int tmp401_chip_read ( struct device * dev , u32 attr , int channel , long * val )
2013-03-28 02:03:10 -07:00
{
2013-09-04 16:24:09 -07:00
struct tmp401_data * data = dev_get_drvdata ( dev ) ;
2021-10-16 14:56:29 -07:00
u32 regval ;
int ret ;
2021-10-16 10:51:27 -07:00
switch ( attr ) {
case hwmon_chip_update_interval :
2021-11-09 13:18:26 -08:00
ret = regmap_read ( data - > regmap , TMP401_CONVERSION_RATE , & regval ) ;
2021-10-16 14:56:29 -07:00
if ( ret < 0 )
return ret ;
2021-10-16 10:51:27 -07:00
* val = ( 1 < < ( 7 - regval ) ) * 125 ;
break ;
case hwmon_chip_temp_reset_history :
* val = 0 ;
break ;
default :
return - EOPNOTSUPP ;
}
2013-03-28 02:03:10 -07:00
2021-10-16 10:51:27 -07:00
return 0 ;
2013-03-28 02:03:10 -07:00
}
2021-10-16 14:56:29 -07:00
static int tmp401_set_convrate ( struct regmap * regmap , long val )
2013-03-28 02:03:10 -07:00
{
2021-11-09 13:18:26 -08:00
int rate ;
2013-03-28 02:03:10 -07:00
/*
* For valid rates , interval can be calculated as
* interval = ( 1 < < ( 7 - rate ) ) * 125 ;
* Rounded rate is therefore
* rate = 7 - __fls ( interval * 4 / ( 125 * 3 ) ) ;
* Use clamp_val ( ) to avoid overflows , and to ensure valid input
* for __fls .
*/
val = clamp_val ( val , 125 , 16000 ) ;
rate = 7 - __fls ( val * 4 / ( 125 * 3 ) ) ;
2021-11-09 13:18:26 -08:00
return regmap_write ( regmap , TMP401_CONVERSION_RATE , rate ) ;
2021-10-16 10:51:27 -07:00
}
static int tmp401_chip_write ( struct device * dev , u32 attr , int channel , long val )
{
struct tmp401_data * data = dev_get_drvdata ( dev ) ;
2021-10-16 14:56:29 -07:00
struct regmap * regmap = data - > regmap ;
2021-10-16 10:51:27 -07:00
int err ;
2013-03-28 02:03:10 -07:00
mutex_lock ( & data - > update_lock ) ;
2021-10-16 10:51:27 -07:00
switch ( attr ) {
case hwmon_chip_update_interval :
2021-10-16 14:56:29 -07:00
err = tmp401_set_convrate ( regmap , val ) ;
2021-10-16 10:51:27 -07:00
break ;
case hwmon_chip_temp_reset_history :
if ( val ! = 1 ) {
err = - EINVAL ;
break ;
}
/*
* Reset history by writing any value to any of the
* minimum / maximum registers ( 0x30 - 0x37 ) .
*/
2021-10-16 14:56:29 -07:00
err = regmap_write ( regmap , 0x30 , 0 ) ;
2021-10-16 10:51:27 -07:00
break ;
default :
err = - EOPNOTSUPP ;
break ;
}
2013-03-28 02:03:10 -07:00
mutex_unlock ( & data - > update_lock ) ;
2021-10-16 10:51:27 -07:00
return err ;
2013-03-28 02:03:10 -07:00
}
2021-10-16 10:51:27 -07:00
static int tmp401_read ( struct device * dev , enum hwmon_sensor_types type ,
u32 attr , int channel , long * val )
{
switch ( type ) {
case hwmon_chip :
return tmp401_chip_read ( dev , attr , channel , val ) ;
case hwmon_temp :
return tmp401_temp_read ( dev , attr , channel , val ) ;
default :
return - EOPNOTSUPP ;
}
}
2013-03-27 08:58:46 -07:00
2021-10-16 10:51:27 -07:00
static int tmp401_write ( struct device * dev , enum hwmon_sensor_types type ,
u32 attr , int channel , long val )
{
switch ( type ) {
case hwmon_chip :
return tmp401_chip_write ( dev , attr , channel , val ) ;
case hwmon_temp :
return tmp401_temp_write ( dev , attr , channel , val ) ;
default :
return - EOPNOTSUPP ;
}
}
2009-06-15 18:39:47 +02:00
2021-10-16 10:51:27 -07:00
static umode_t tmp401_is_visible ( const void * data , enum hwmon_sensor_types type ,
u32 attr , int channel )
{
switch ( type ) {
case hwmon_chip :
switch ( attr ) {
case hwmon_chip_update_interval :
case hwmon_chip_temp_reset_history :
return 0644 ;
default :
break ;
}
break ;
case hwmon_temp :
switch ( attr ) {
case hwmon_temp_input :
case hwmon_temp_min_alarm :
case hwmon_temp_max_alarm :
case hwmon_temp_crit_alarm :
case hwmon_temp_fault :
case hwmon_temp_lowest :
case hwmon_temp_highest :
return 0444 ;
case hwmon_temp_min :
case hwmon_temp_max :
case hwmon_temp_crit :
case hwmon_temp_crit_hyst :
return 0644 ;
default :
break ;
}
break ;
default :
break ;
}
return 0 ;
}
2013-03-28 01:36:44 -07:00
2021-10-16 10:51:27 -07:00
static const struct hwmon_ops tmp401_ops = {
. is_visible = tmp401_is_visible ,
. read = tmp401_read ,
. write = tmp401_write ,
2013-03-28 01:36:44 -07:00
} ;
2021-10-16 14:56:29 -07:00
/* chip initialization, detect, probe */
static int tmp401_init_client ( struct tmp401_data * data )
2009-06-15 18:39:46 +02:00
{
2021-10-16 14:56:29 -07:00
struct regmap * regmap = data - > regmap ;
u32 config , config_orig ;
int ret ;
2022-04-14 09:58:23 +02:00
u32 val = 0 ;
s32 nfactor = 0 ;
2009-06-15 18:39:46 +02:00
2021-10-16 14:56:29 -07:00
/* Set conversion rate to 2 Hz */
2021-11-09 13:18:26 -08:00
ret = regmap_write ( regmap , TMP401_CONVERSION_RATE , 5 ) ;
2021-10-16 14:56:29 -07:00
if ( ret < 0 )
return ret ;
2009-06-15 18:39:46 +02:00
/* Start conversions (disable shutdown if necessary) */
2021-11-09 13:18:26 -08:00
ret = regmap_read ( regmap , TMP401_CONFIG , & config ) ;
2021-10-16 14:56:29 -07:00
if ( ret < 0 )
return ret ;
2009-06-15 18:39:46 +02:00
config_orig = config ;
config & = ~ TMP401_CONFIG_SHUTDOWN ;
2022-04-14 09:58:23 +02:00
if ( of_property_read_bool ( data - > client - > dev . of_node , " ti,extended-range-enable " ) ) {
/* Enable measurement over extended temperature range */
config | = TMP401_CONFIG_RANGE ;
}
2021-10-16 10:51:27 -07:00
data - > extended_range = ! ! ( config & TMP401_CONFIG_RANGE ) ;
2022-04-14 09:58:23 +02:00
if ( config ! = config_orig ) {
2021-11-09 13:18:26 -08:00
ret = regmap_write ( regmap , TMP401_CONFIG , config ) ;
2022-04-14 09:58:23 +02:00
if ( ret < 0 )
return ret ;
}
ret = of_property_read_u32 ( data - > client - > dev . of_node , " ti,n-factor " , & nfactor ) ;
if ( ! ret ) {
if ( data - > kind = = tmp401 ) {
dev_err ( & data - > client - > dev , " ti,tmp401 does not support n-factor correction \n " ) ;
return - EINVAL ;
}
if ( nfactor < - 128 | | nfactor > 127 ) {
dev_err ( & data - > client - > dev , " n-factor is invalid (%d) \n " , nfactor ) ;
return - EINVAL ;
}
ret = regmap_write ( regmap , TMP4XX_N_FACTOR_REG , ( unsigned int ) nfactor ) ;
if ( ret < 0 )
return ret ;
}
ret = of_property_read_u32 ( data - > client - > dev . of_node , " ti,beta-compensation " , & val ) ;
if ( ! ret ) {
if ( data - > kind = = tmp401 | | data - > kind = = tmp411 ) {
dev_err ( & data - > client - > dev , " ti,tmp401 or ti,tmp411 does not support beta compensation \n " ) ;
return - EINVAL ;
}
if ( val > 15 ) {
dev_err ( & data - > client - > dev , " beta-compensation is invalid (%u) \n " , val ) ;
return - EINVAL ;
}
ret = regmap_write ( regmap , TMP43X_BETA_RANGE , val ) ;
if ( ret < 0 )
return ret ;
}
2014-12-04 17:45:53 +01:00
2022-04-25 12:00:19 +02:00
return 0 ;
2009-06-15 18:39:46 +02:00
}
2009-12-14 21:17:23 +01:00
static int tmp401_detect ( struct i2c_client * client ,
2009-06-15 18:39:46 +02:00
struct i2c_board_info * info )
{
2009-12-09 20:35:54 +01:00
enum chips kind ;
2009-06-15 18:39:46 +02:00
struct i2c_adapter * adapter = client - > adapter ;
2009-12-09 20:35:54 +01:00
u8 reg ;
2009-06-15 18:39:46 +02:00
if ( ! i2c_check_functionality ( adapter , I2C_FUNC_SMBUS_BYTE_DATA ) )
return - ENODEV ;
/* Detect and identify the chip */
2009-12-09 20:35:54 +01:00
reg = i2c_smbus_read_byte_data ( client , TMP401_MANUFACTURER_ID_REG ) ;
if ( reg ! = TMP401_MANUFACTURER_ID )
return - ENODEV ;
2009-06-15 18:39:46 +02:00
2009-12-09 20:35:54 +01:00
reg = i2c_smbus_read_byte_data ( client , TMP401_DEVICE_ID_REG ) ;
2009-06-15 18:39:46 +02:00
2009-12-09 20:35:54 +01:00
switch ( reg ) {
case TMP401_DEVICE_ID :
2013-03-15 12:55:08 -07:00
if ( client - > addr ! = 0x4c )
return - ENODEV ;
2009-12-09 20:35:54 +01:00
kind = tmp401 ;
break ;
2013-03-29 17:56:07 -07:00
case TMP411A_DEVICE_ID :
if ( client - > addr ! = 0x4c )
return - ENODEV ;
kind = tmp411 ;
break ;
case TMP411B_DEVICE_ID :
if ( client - > addr ! = 0x4d )
return - ENODEV ;
kind = tmp411 ;
break ;
case TMP411C_DEVICE_ID :
if ( client - > addr ! = 0x4e )
return - ENODEV ;
2009-12-09 20:35:54 +01:00
kind = tmp411 ;
break ;
2013-03-15 12:55:08 -07:00
case TMP431_DEVICE_ID :
2014-12-05 10:15:03 -08:00
if ( client - > addr ! = 0x4c & & client - > addr ! = 0x4d )
2013-03-15 12:55:08 -07:00
return - ENODEV ;
kind = tmp431 ;
break ;
2013-03-28 01:36:44 -07:00
case TMP432_DEVICE_ID :
2014-12-05 10:15:03 -08:00
if ( client - > addr ! = 0x4c & & client - > addr ! = 0x4d )
2013-03-28 01:36:44 -07:00
return - ENODEV ;
kind = tmp432 ;
break ;
2014-12-04 17:45:51 +01:00
case TMP435_DEVICE_ID :
kind = tmp435 ;
break ;
2009-12-09 20:35:54 +01:00
default :
return - ENODEV ;
2009-06-15 18:39:46 +02:00
}
2009-12-09 20:35:54 +01:00
2021-11-09 13:18:26 -08:00
reg = i2c_smbus_read_byte_data ( client , TMP401_CONFIG ) ;
2009-12-09 20:35:54 +01:00
if ( reg & 0x1b )
return - ENODEV ;
2021-11-09 13:18:26 -08:00
reg = i2c_smbus_read_byte_data ( client , TMP401_CONVERSION_RATE ) ;
2009-12-09 20:35:54 +01:00
/* Datasheet says: 0x1-0x6 */
if ( reg > 15 )
return - ENODEV ;
2022-08-18 23:00:11 +02:00
strscpy ( info - > type , tmp401_id [ kind ] . name , I2C_NAME_SIZE ) ;
2009-06-15 18:39:46 +02:00
return 0 ;
}
2020-08-13 18:02:22 +02:00
static int tmp401_probe ( struct i2c_client * client )
2009-06-15 18:39:46 +02:00
{
2014-12-04 17:45:51 +01:00
static const char * const names [ ] = {
2021-10-15 17:34:25 -07:00
" TMP401 " , " TMP411 " , " TMP431 " , " TMP432 " , " TMP435 "
2014-12-04 17:45:51 +01:00
} ;
2013-03-27 08:58:46 -07:00
struct device * dev = & client - > dev ;
2021-10-16 10:51:27 -07:00
struct hwmon_channel_info * info ;
2013-09-04 16:24:09 -07:00
struct device * hwmon_dev ;
2009-06-15 18:39:46 +02:00
struct tmp401_data * data ;
2021-10-16 10:51:27 -07:00
int status ;
2009-06-15 18:39:46 +02:00
2013-03-27 08:58:46 -07:00
data = devm_kzalloc ( dev , sizeof ( struct tmp401_data ) , GFP_KERNEL ) ;
2009-06-15 18:39:46 +02:00
if ( ! data )
return - ENOMEM ;
2013-09-04 16:24:09 -07:00
data - > client = client ;
2009-06-15 18:39:46 +02:00
mutex_init ( & data - > update_lock ) ;
2020-08-13 18:02:22 +02:00
data - > kind = i2c_match_id ( tmp401_id , client ) - > driver_data ;
2009-06-15 18:39:46 +02:00
2021-10-16 14:56:29 -07:00
data - > regmap = devm_regmap_init ( dev , NULL , data , & tmp401_regmap_config ) ;
if ( IS_ERR ( data - > regmap ) )
return PTR_ERR ( data - > regmap ) ;
2021-10-16 10:51:27 -07:00
/* initialize configuration data */
data - > chip . ops = & tmp401_ops ;
data - > chip . info = data - > info ;
data - > info [ 0 ] = & data - > chip_info ;
data - > info [ 1 ] = & data - > temp_info ;
info = & data - > chip_info ;
info - > type = hwmon_chip ;
info - > config = data - > chip_channel_config ;
data - > chip_channel_config [ 0 ] = HWMON_C_UPDATE_INTERVAL ;
info = & data - > temp_info ;
info - > type = hwmon_temp ;
info - > config = data - > temp_channel_config ;
data - > temp_channel_config [ 0 ] = HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM ;
data - > temp_channel_config [ 1 ] = HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_FAULT ;
if ( data - > kind = = tmp411 ) {
data - > temp_channel_config [ 0 ] | = HWMON_T_HIGHEST | HWMON_T_LOWEST ;
data - > temp_channel_config [ 1 ] | = HWMON_T_HIGHEST | HWMON_T_LOWEST ;
data - > chip_channel_config [ 0 ] | = HWMON_C_TEMP_RESET_HISTORY ;
}
if ( data - > kind = = tmp432 ) {
data - > temp_channel_config [ 2 ] = HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM | HWMON_T_FAULT ;
}
2009-06-15 18:39:46 +02:00
/* Initialize the TMP401 chip */
2021-10-16 14:56:29 -07:00
status = tmp401_init_client ( data ) ;
2014-12-04 17:45:53 +01:00
if ( status < 0 )
return status ;
2009-06-15 18:39:46 +02:00
2021-10-16 10:51:27 -07:00
hwmon_dev = devm_hwmon_device_register_with_info ( dev , client - > name , data ,
& data - > chip , NULL ) ;
2013-09-04 16:24:09 -07:00
if ( IS_ERR ( hwmon_dev ) )
return PTR_ERR ( hwmon_dev ) ;
2009-06-15 18:39:46 +02:00
2013-03-27 08:58:46 -07:00
dev_info ( dev , " Detected TI %s chip \n " , names [ data - > kind ] ) ;
2009-06-15 18:39:46 +02:00
return 0 ;
}
hwmon: (tmp401) Add OF device ID table
This driver doesn't have of_match_table. This makes the kernel module
tmp401.ko lack alias patterns (e.g: of:N*T*Cti,tmp411) to match DT node
of the supported devices hence this kernel module will not be
automatically loaded.
After adding of_match_table to this driver, the folllowing alias will be
added into tmp401.ko.
$ modinfo drivers/hwmon/tmp401.ko
filename: drivers/hwmon/tmp401.ko
......
author: Hans de Goede <hdegoede@redhat.com>
alias: of:N*T*Cti,tmp435C*
alias: of:N*T*Cti,tmp435
alias: of:N*T*Cti,tmp432C*
alias: of:N*T*Cti,tmp432
alias: of:N*T*Cti,tmp431C*
alias: of:N*T*Cti,tmp431
alias: of:N*T*Cti,tmp411C*
alias: of:N*T*Cti,tmp411
alias: of:N*T*Cti,tmp401C*
alias: of:N*T*Cti,tmp401
......
Fixes: af503716ac14 ("i2c: core: report OF style module alias for devices registered via OF")
Signed-off-by: Camel Guo <camel.guo@axis.com>
Link: https://lore.kernel.org/r/20220503114333.456476-1-camel.guo@axis.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2022-05-03 13:43:33 +02:00
static const struct of_device_id __maybe_unused tmp4xx_of_match [ ] = {
{ . compatible = " ti,tmp401 " , } ,
{ . compatible = " ti,tmp411 " , } ,
{ . compatible = " ti,tmp431 " , } ,
{ . compatible = " ti,tmp432 " , } ,
{ . compatible = " ti,tmp435 " , } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , tmp4xx_of_match ) ;
2010-05-27 19:58:49 +02:00
static struct i2c_driver tmp401_driver = {
. class = I2C_CLASS_HWMON ,
. driver = {
. name = " tmp401 " ,
hwmon: (tmp401) Add OF device ID table
This driver doesn't have of_match_table. This makes the kernel module
tmp401.ko lack alias patterns (e.g: of:N*T*Cti,tmp411) to match DT node
of the supported devices hence this kernel module will not be
automatically loaded.
After adding of_match_table to this driver, the folllowing alias will be
added into tmp401.ko.
$ modinfo drivers/hwmon/tmp401.ko
filename: drivers/hwmon/tmp401.ko
......
author: Hans de Goede <hdegoede@redhat.com>
alias: of:N*T*Cti,tmp435C*
alias: of:N*T*Cti,tmp435
alias: of:N*T*Cti,tmp432C*
alias: of:N*T*Cti,tmp432
alias: of:N*T*Cti,tmp431C*
alias: of:N*T*Cti,tmp431
alias: of:N*T*Cti,tmp411C*
alias: of:N*T*Cti,tmp411
alias: of:N*T*Cti,tmp401C*
alias: of:N*T*Cti,tmp401
......
Fixes: af503716ac14 ("i2c: core: report OF style module alias for devices registered via OF")
Signed-off-by: Camel Guo <camel.guo@axis.com>
Link: https://lore.kernel.org/r/20220503114333.456476-1-camel.guo@axis.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
2022-05-03 13:43:33 +02:00
. of_match_table = of_match_ptr ( tmp4xx_of_match ) ,
2010-05-27 19:58:49 +02:00
} ,
2023-05-05 15:17:18 +02:00
. probe = tmp401_probe ,
2010-05-27 19:58:49 +02:00
. id_table = tmp401_id ,
. detect = tmp401_detect ,
. address_list = normal_i2c ,
} ;
2009-06-15 18:39:46 +02:00
2012-01-20 15:38:18 +08:00
module_i2c_driver ( tmp401_driver ) ;
2009-06-15 18:39:46 +02:00
MODULE_AUTHOR ( " Hans de Goede <hdegoede@redhat.com> " ) ;
MODULE_DESCRIPTION ( " Texas Instruments TMP401 temperature sensor driver " ) ;
MODULE_LICENSE ( " GPL " ) ;