2021-04-07 23:51:47 +05:30
// SPDX-License-Identifier: GPL-2.0-only
/*
* Digital temperature sensor with integrated Non - volatile memory
* Copyright ( c ) 2021 Puranjay Mohan < puranjay12 @ gmail . com >
*
* Driver for the Texas Instruments TMP117 Temperature Sensor
* ( 7 - bit I2C slave address ( 0x48 - 0x4B ) , changeable via ADD pins )
*
* Note : This driver assumes that the sensor has been calibrated beforehand .
*/
# include <linux/err.h>
# include <linux/i2c.h>
# include <linux/module.h>
# include <linux/bitops.h>
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/limits.h>
2023-02-28 10:05:15 +01:00
# include <linux/property.h>
2021-04-07 23:51:47 +05:30
# include <linux/iio/iio.h>
# define TMP117_REG_TEMP 0x0
# define TMP117_REG_CFGR 0x1
# define TMP117_REG_HIGH_LIM 0x2
# define TMP117_REG_LOW_LIM 0x3
# define TMP117_REG_EEPROM_UL 0x4
# define TMP117_REG_EEPROM1 0x5
# define TMP117_REG_EEPROM2 0x6
# define TMP117_REG_TEMP_OFFSET 0x7
# define TMP117_REG_EEPROM3 0x8
# define TMP117_REG_DEVICE_ID 0xF
# define TMP117_RESOLUTION_10UC 78125
# define MICRODEGREE_PER_10MILLIDEGREE 10000
2023-02-28 10:05:17 +01:00
# define TMP116_DEVICE_ID 0x1116
# define TMP117_DEVICE_ID 0x0117
2021-04-07 23:51:47 +05:30
struct tmp117_data {
struct i2c_client * client ;
s16 calibbias ;
} ;
static int tmp117_read_raw ( struct iio_dev * indio_dev ,
2023-02-28 10:05:18 +01:00
struct iio_chan_spec const * channel , int * val ,
int * val2 , long mask )
2021-04-07 23:51:47 +05:30
{
struct tmp117_data * data = iio_priv ( indio_dev ) ;
s32 ret ;
switch ( mask ) {
case IIO_CHAN_INFO_RAW :
ret = i2c_smbus_read_word_swapped ( data - > client ,
2023-02-28 10:05:18 +01:00
TMP117_REG_TEMP ) ;
2021-04-07 23:51:47 +05:30
if ( ret < 0 )
return ret ;
* val = sign_extend32 ( ret , 15 ) ;
return IIO_VAL_INT ;
case IIO_CHAN_INFO_CALIBBIAS :
ret = i2c_smbus_read_word_swapped ( data - > client ,
2023-02-28 10:05:18 +01:00
TMP117_REG_TEMP_OFFSET ) ;
2021-04-07 23:51:47 +05:30
if ( ret < 0 )
return ret ;
* val = sign_extend32 ( ret , 15 ) ;
return IIO_VAL_INT ;
case IIO_CHAN_INFO_SCALE :
/*
* Conversion from 10 s of uC to mC
* as IIO reports temperature in mC
*/
* val = TMP117_RESOLUTION_10UC / MICRODEGREE_PER_10MILLIDEGREE ;
* val2 = ( TMP117_RESOLUTION_10UC %
MICRODEGREE_PER_10MILLIDEGREE ) * 100 ;
return IIO_VAL_INT_PLUS_MICRO ;
default :
return - EINVAL ;
}
}
2023-02-28 10:05:18 +01:00
static int tmp117_write_raw ( struct iio_dev * indio_dev , struct iio_chan_spec
const * channel , int val , int val2 , long mask )
2021-04-07 23:51:47 +05:30
{
struct tmp117_data * data = iio_priv ( indio_dev ) ;
s16 off ;
switch ( mask ) {
case IIO_CHAN_INFO_CALIBBIAS :
off = clamp_t ( int , val , S16_MIN , S16_MAX ) ;
if ( off = = data - > calibbias )
return 0 ;
data - > calibbias = off ;
return i2c_smbus_write_word_swapped ( data - > client ,
TMP117_REG_TEMP_OFFSET , off ) ;
default :
return - EINVAL ;
}
}
static const struct iio_chan_spec tmp117_channels [ ] = {
{
. type = IIO_TEMP ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
2023-02-28 10:05:18 +01:00
BIT ( IIO_CHAN_INFO_CALIBBIAS ) |
BIT ( IIO_CHAN_INFO_SCALE ) ,
2021-04-07 23:51:47 +05:30
} ,
} ;
2023-02-28 10:05:17 +01:00
static const struct iio_chan_spec tmp116_channels [ ] = {
{
. type = IIO_TEMP ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
BIT ( IIO_CHAN_INFO_SCALE ) ,
} ,
} ;
2021-04-07 23:51:47 +05:30
static const struct iio_info tmp117_info = {
. read_raw = tmp117_read_raw ,
. write_raw = tmp117_write_raw ,
} ;
static int tmp117_identify ( struct i2c_client * client )
{
2023-02-28 10:05:15 +01:00
const struct i2c_device_id * id ;
unsigned long match_data ;
2021-04-07 23:51:47 +05:30
int dev_id ;
dev_id = i2c_smbus_read_word_swapped ( client , TMP117_REG_DEVICE_ID ) ;
if ( dev_id < 0 )
return dev_id ;
2023-02-28 10:05:15 +01:00
switch ( dev_id ) {
2023-02-28 10:05:17 +01:00
case TMP116_DEVICE_ID :
2023-02-28 10:05:15 +01:00
case TMP117_DEVICE_ID :
return dev_id ;
2021-04-07 23:51:47 +05:30
}
2023-02-28 10:05:15 +01:00
dev_info ( & client - > dev , " Unknown device id (0x%x), use fallback compatible \n " ,
dev_id ) ;
match_data = ( uintptr_t ) device_get_match_data ( & client - > dev ) ;
if ( match_data )
return match_data ;
id = i2c_client_get_device_id ( client ) ;
if ( id )
return id - > driver_data ;
dev_err ( & client - > dev , " Failed to identify unsupported device \n " ) ;
return - ENODEV ;
2021-04-07 23:51:47 +05:30
}
static int tmp117_probe ( struct i2c_client * client )
{
struct tmp117_data * data ;
struct iio_dev * indio_dev ;
2023-02-28 10:05:15 +01:00
int ret , dev_id ;
2021-04-07 23:51:47 +05:30
if ( ! i2c_check_functionality ( client - > adapter , I2C_FUNC_SMBUS_WORD_DATA ) )
return - EOPNOTSUPP ;
ret = tmp117_identify ( client ) ;
if ( ret < 0 )
return ret ;
2023-02-28 10:05:15 +01:00
dev_id = ret ;
2021-04-07 23:51:47 +05:30
indio_dev = devm_iio_device_alloc ( & client - > dev , sizeof ( * data ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
data = iio_priv ( indio_dev ) ;
data - > client = client ;
data - > calibbias = 0 ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
indio_dev - > info = & tmp117_info ;
2023-02-28 10:05:15 +01:00
switch ( dev_id ) {
2023-02-28 10:05:17 +01:00
case TMP116_DEVICE_ID :
indio_dev - > channels = tmp116_channels ;
indio_dev - > num_channels = ARRAY_SIZE ( tmp116_channels ) ;
indio_dev - > name = " tmp116 " ;
break ;
2023-02-28 10:05:15 +01:00
case TMP117_DEVICE_ID :
indio_dev - > channels = tmp117_channels ;
indio_dev - > num_channels = ARRAY_SIZE ( tmp117_channels ) ;
indio_dev - > name = " tmp117 " ;
break ;
}
2021-04-07 23:51:47 +05:30
return devm_iio_device_register ( & client - > dev , indio_dev ) ;
}
static const struct of_device_id tmp117_of_match [ ] = {
2023-02-28 10:05:17 +01:00
{ . compatible = " ti,tmp116 " , . data = ( void * ) TMP116_DEVICE_ID } ,
2023-02-28 10:05:15 +01:00
{ . compatible = " ti,tmp117 " , . data = ( void * ) TMP117_DEVICE_ID } ,
2021-04-07 23:51:47 +05:30
{ }
} ;
MODULE_DEVICE_TABLE ( of , tmp117_of_match ) ;
static const struct i2c_device_id tmp117_id [ ] = {
2023-02-28 10:05:17 +01:00
{ " tmp116 " , TMP116_DEVICE_ID } ,
2023-02-28 10:05:15 +01:00
{ " tmp117 " , TMP117_DEVICE_ID } ,
2021-04-07 23:51:47 +05:30
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , tmp117_id ) ;
static struct i2c_driver tmp117_driver = {
. driver = {
. name = " tmp117 " ,
. of_match_table = tmp117_of_match ,
} ,
. probe_new = tmp117_probe ,
. id_table = tmp117_id ,
} ;
module_i2c_driver ( tmp117_driver ) ;
MODULE_AUTHOR ( " Puranjay Mohan <puranjay12@gmail.com> " ) ;
MODULE_DESCRIPTION ( " TI TMP117 Temperature sensor driver " ) ;
MODULE_LICENSE ( " GPL " ) ;