2017-02-02 10:44:03 +03:00
/*
* STTS751 sensor driver
*
* Copyright ( C ) 2016 - 2017 Istituto Italiano di Tecnologia - RBCS - EDL
* Robotics , Brain and Cognitive Sciences department
* Electronic Design Laboratory
*
* Written by Andrea Merello < andrea . merello @ gmail . com >
*
* Based on LM95241 driver and LM90 driver
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# include <linux/bitops.h>
# include <linux/err.h>
# include <linux/hwmon.h>
# include <linux/hwmon-sysfs.h>
# include <linux/i2c.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/jiffies.h>
# include <linux/module.h>
# include <linux/mutex.h>
# include <linux/property.h>
# include <linux/slab.h>
# include <linux/sysfs.h>
# include <linux/util_macros.h>
# define DEVNAME "stts751"
static const unsigned short normal_i2c [ ] = {
0x48 , 0x49 , 0x38 , 0x39 , /* STTS751-0 */
0x4A , 0x4B , 0x3A , 0x3B , /* STTS751-1 */
I2C_CLIENT_END } ;
# define STTS751_REG_TEMP_H 0x00
# define STTS751_REG_STATUS 0x01
# define STTS751_STATUS_TRIPT BIT(0)
# define STTS751_STATUS_TRIPL BIT(5)
# define STTS751_STATUS_TRIPH BIT(6)
# define STTS751_REG_TEMP_L 0x02
# define STTS751_REG_CONF 0x03
# define STTS751_CONF_RES_MASK 0x0C
# define STTS751_CONF_RES_SHIFT 2
# define STTS751_CONF_EVENT_DIS BIT(7)
# define STTS751_CONF_STOP BIT(6)
# define STTS751_REG_RATE 0x04
# define STTS751_REG_HLIM_H 0x05
# define STTS751_REG_HLIM_L 0x06
# define STTS751_REG_LLIM_H 0x07
# define STTS751_REG_LLIM_L 0x08
# define STTS751_REG_TLIM 0x20
# define STTS751_REG_HYST 0x21
# define STTS751_REG_SMBUS_TO 0x22
# define STTS751_REG_PROD_ID 0xFD
# define STTS751_REG_MAN_ID 0xFE
# define STTS751_REG_REV_ID 0xFF
# define STTS751_0_PROD_ID 0x00
# define STTS751_1_PROD_ID 0x01
# define ST_MAN_ID 0x53
/*
* Possible update intervals are ( in mS ) :
* 16000 , 8000 , 4000 , 2000 , 1000 , 500 , 250 , 125 , 62.5 , 31.25
* However we are not going to complicate things too much and we stick to the
* approx value in mS .
*/
static const int stts751_intervals [ ] = {
16000 , 8000 , 4000 , 2000 , 1000 , 500 , 250 , 125 , 63 , 31
} ;
static const struct i2c_device_id stts751_id [ ] = {
{ " stts751 " , 0 } ,
{ }
} ;
2017-02-24 16:13:09 +03:00
static const struct of_device_id stts751_of_match [ ] = {
{ . compatible = " stts751 " } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , stts751_of_match ) ;
2017-02-02 10:44:03 +03:00
struct stts751_priv {
struct device * dev ;
struct i2c_client * client ;
struct mutex access_lock ;
u8 interval ;
int res ;
int event_max , event_min ;
int therm ;
int hyst ;
bool smbus_timeout ;
int temp ;
unsigned long last_update , last_alert_update ;
u8 config ;
bool min_alert , max_alert , therm_trip ;
bool data_valid , alert_valid ;
bool notify_max , notify_min ;
} ;
/*
* These functions converts temperature from HW format to integer format and
* vice - vers . They are ( mostly ) taken from lm90 driver . Unit is in mC .
*/
static int stts751_to_deg ( s16 hw_val )
{
return hw_val * 125 / 32 ;
}
static s32 stts751_to_hw ( int val )
{
return DIV_ROUND_CLOSEST ( val , 125 ) * 32 ;
}
static int stts751_adjust_resolution ( struct stts751_priv * priv )
{
u8 res ;
switch ( priv - > interval ) {
case 9 :
/* 10 bits */
res = 0 ;
break ;
case 8 :
/* 11 bits */
res = 1 ;
break ;
default :
/* 12 bits */
res = 3 ;
break ;
}
if ( priv - > res = = res )
return 0 ;
priv - > config & = ~ STTS751_CONF_RES_MASK ;
priv - > config | = res < < STTS751_CONF_RES_SHIFT ;
dev_dbg ( & priv - > client - > dev , " setting res %d. config %x " ,
res , priv - > config ) ;
priv - > res = res ;
return i2c_smbus_write_byte_data ( priv - > client ,
STTS751_REG_CONF , priv - > config ) ;
}
static int stts751_update_temp ( struct stts751_priv * priv )
{
s32 integer1 , integer2 , frac ;
/*
* There is a trick here , like in the lm90 driver . We have to read two
* registers to get the sensor temperature , but we have to beware a
* conversion could occur between the readings . We could use the
* one - shot conversion register , but we don ' t want to do this ( disables
* hardware monitoring ) . So the solution used here is to read the high
* byte once , then the low byte , then the high byte again . If the new
* high byte matches the old one , then we have a valid reading . Else we
* have to read the low byte again , and now we believe we have a correct
* reading .
*/
integer1 = i2c_smbus_read_byte_data ( priv - > client , STTS751_REG_TEMP_H ) ;
if ( integer1 < 0 ) {
dev_dbg ( & priv - > client - > dev ,
" I2C read failed (temp H). ret: %x \n " , integer1 ) ;
return integer1 ;
}
frac = i2c_smbus_read_byte_data ( priv - > client , STTS751_REG_TEMP_L ) ;
if ( frac < 0 ) {
dev_dbg ( & priv - > client - > dev ,
" I2C read failed (temp L). ret: %x \n " , frac ) ;
return frac ;
}
integer2 = i2c_smbus_read_byte_data ( priv - > client , STTS751_REG_TEMP_H ) ;
if ( integer2 < 0 ) {
dev_dbg ( & priv - > client - > dev ,
" I2C 2nd read failed (temp H). ret: %x \n " , integer2 ) ;
return integer2 ;
}
if ( integer1 ! = integer2 ) {
frac = i2c_smbus_read_byte_data ( priv - > client ,
STTS751_REG_TEMP_L ) ;
if ( frac < 0 ) {
dev_dbg ( & priv - > client - > dev ,
" I2C 2nd read failed (temp L). ret: %x \n " ,
frac ) ;
return frac ;
}
}
priv - > temp = stts751_to_deg ( ( integer1 < < 8 ) | frac ) ;
return 0 ;
}
static int stts751_set_temp_reg16 ( struct stts751_priv * priv , int temp ,
u8 hreg , u8 lreg )
{
s32 hwval ;
int ret ;
hwval = stts751_to_hw ( temp ) ;
ret = i2c_smbus_write_byte_data ( priv - > client , hreg , hwval > > 8 ) ;
if ( ret )
return ret ;
return i2c_smbus_write_byte_data ( priv - > client , lreg , hwval & 0xff ) ;
}
static int stts751_set_temp_reg8 ( struct stts751_priv * priv , int temp , u8 reg )
{
s32 hwval ;
hwval = stts751_to_hw ( temp ) ;
return i2c_smbus_write_byte_data ( priv - > client , reg , hwval > > 8 ) ;
}
static int stts751_read_reg16 ( struct stts751_priv * priv , int * temp ,
u8 hreg , u8 lreg )
{
int integer , frac ;
integer = i2c_smbus_read_byte_data ( priv - > client , hreg ) ;
if ( integer < 0 )
return integer ;
frac = i2c_smbus_read_byte_data ( priv - > client , lreg ) ;
if ( frac < 0 )
return frac ;
* temp = stts751_to_deg ( ( integer < < 8 ) | frac ) ;
return 0 ;
}
static int stts751_read_reg8 ( struct stts751_priv * priv , int * temp , u8 reg )
{
int integer ;
integer = i2c_smbus_read_byte_data ( priv - > client , reg ) ;
if ( integer < 0 )
return integer ;
* temp = stts751_to_deg ( integer < < 8 ) ;
return 0 ;
}
/*
* Update alert flags without waiting for cache to expire . We detects alerts
* immediately for the sake of the alert handler ; we still need to deal with
* caching to workaround the fact that alarm flags int the status register ,
* despite what the datasheet claims , gets always cleared on read .
*/
static int stts751_update_alert ( struct stts751_priv * priv )
{
int ret ;
bool conv_done ;
int cache_time = msecs_to_jiffies ( stts751_intervals [ priv - > interval ] ) ;
/*
* Add another 10 % because if we run faster than the HW conversion
* rate we will end up in reporting incorrectly alarms .
*/
cache_time + = cache_time / 10 ;
ret = i2c_smbus_read_byte_data ( priv - > client , STTS751_REG_STATUS ) ;
if ( ret < 0 )
return ret ;
dev_dbg ( & priv - > client - > dev , " status reg %x \n " , ret ) ;
conv_done = ret & ( STTS751_STATUS_TRIPH | STTS751_STATUS_TRIPL ) ;
/*
* Reset the cache if the cache time expired , or if we are sure
* we have valid data from a device conversion , or if we know
* our cache has been never written .
*
* Note that when the cache has been never written the point is
* to correctly initialize the timestamp , rather than clearing
* the cache values .
*
* Note that updating the cache timestamp when we get an alarm flag
* is required , otherwise we could incorrectly report alarms to be zero .
*/
if ( time_after ( jiffies , priv - > last_alert_update + cache_time ) | |
conv_done | | ! priv - > alert_valid ) {
priv - > max_alert = false ;
priv - > min_alert = false ;
priv - > alert_valid = true ;
priv - > last_alert_update = jiffies ;
dev_dbg ( & priv - > client - > dev , " invalidating alert cache \n " ) ;
}
priv - > max_alert | = ! ! ( ret & STTS751_STATUS_TRIPH ) ;
priv - > min_alert | = ! ! ( ret & STTS751_STATUS_TRIPL ) ;
priv - > therm_trip = ! ! ( ret & STTS751_STATUS_TRIPT ) ;
dev_dbg ( & priv - > client - > dev , " max_alert: %d, min_alert: %d, therm_trip: %d \n " ,
priv - > max_alert , priv - > min_alert , priv - > therm_trip ) ;
return 0 ;
}
static void stts751_alert ( struct i2c_client * client ,
enum i2c_alert_protocol type , unsigned int data )
{
int ret ;
struct stts751_priv * priv = i2c_get_clientdata ( client ) ;
if ( type ! = I2C_PROTOCOL_SMBUS_ALERT )
return ;
dev_dbg ( & client - > dev , " alert! " ) ;
mutex_lock ( & priv - > access_lock ) ;
ret = stts751_update_alert ( priv ) ;
if ( ret < 0 ) {
/* default to worst case */
priv - > max_alert = true ;
priv - > min_alert = true ;
dev_warn ( priv - > dev ,
" Alert received, but can't communicate to the device. Triggering all alarms! " ) ;
}
if ( priv - > max_alert ) {
if ( priv - > notify_max )
dev_notice ( priv - > dev , " got alert for HIGH temperature " ) ;
priv - > notify_max = false ;
/* unblock alert poll */
sysfs_notify ( & priv - > dev - > kobj , NULL , " temp1_max_alarm " ) ;
}
if ( priv - > min_alert ) {
if ( priv - > notify_min )
dev_notice ( priv - > dev , " got alert for LOW temperature " ) ;
priv - > notify_min = false ;
/* unblock alert poll */
sysfs_notify ( & priv - > dev - > kobj , NULL , " temp1_min_alarm " ) ;
}
if ( priv - > min_alert | | priv - > max_alert )
kobject_uevent ( & priv - > dev - > kobj , KOBJ_CHANGE ) ;
mutex_unlock ( & priv - > access_lock ) ;
}
static int stts751_update ( struct stts751_priv * priv )
{
int ret ;
int cache_time = msecs_to_jiffies ( stts751_intervals [ priv - > interval ] ) ;
if ( time_after ( jiffies , priv - > last_update + cache_time ) | |
! priv - > data_valid ) {
ret = stts751_update_temp ( priv ) ;
if ( ret )
return ret ;
ret = stts751_update_alert ( priv ) ;
if ( ret )
return ret ;
priv - > data_valid = true ;
priv - > last_update = jiffies ;
}
return 0 ;
}
2018-12-11 01:02:21 +03:00
static ssize_t max_alarm_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
2017-02-02 10:44:03 +03:00
{
int ret ;
struct stts751_priv * priv = dev_get_drvdata ( dev ) ;
mutex_lock ( & priv - > access_lock ) ;
ret = stts751_update ( priv ) ;
if ( ! ret )
priv - > notify_max = true ;
mutex_unlock ( & priv - > access_lock ) ;
if ( ret < 0 )
return ret ;
2017-09-19 15:59:34 +03:00
return snprintf ( buf , PAGE_SIZE , " %d \n " , priv - > max_alert ) ;
2017-02-02 10:44:03 +03:00
}
2018-12-11 01:02:21 +03:00
static ssize_t min_alarm_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
2017-02-02 10:44:03 +03:00
{
int ret ;
struct stts751_priv * priv = dev_get_drvdata ( dev ) ;
mutex_lock ( & priv - > access_lock ) ;
ret = stts751_update ( priv ) ;
if ( ! ret )
priv - > notify_min = true ;
mutex_unlock ( & priv - > access_lock ) ;
if ( ret < 0 )
return ret ;
2017-09-19 15:59:34 +03:00
return snprintf ( buf , PAGE_SIZE , " %d \n " , priv - > min_alert ) ;
2017-02-02 10:44:03 +03:00
}
2018-12-11 01:02:21 +03:00
static ssize_t input_show ( struct device * dev , struct device_attribute * attr ,
2017-02-02 10:44:03 +03:00
char * buf )
{
int ret ;
struct stts751_priv * priv = dev_get_drvdata ( dev ) ;
mutex_lock ( & priv - > access_lock ) ;
ret = stts751_update ( priv ) ;
mutex_unlock ( & priv - > access_lock ) ;
if ( ret < 0 )
return ret ;
2017-09-19 15:59:34 +03:00
return snprintf ( buf , PAGE_SIZE , " %d \n " , priv - > temp ) ;
2017-02-02 10:44:03 +03:00
}
2018-12-11 01:02:21 +03:00
static ssize_t therm_show ( struct device * dev , struct device_attribute * attr ,
2017-02-02 10:44:03 +03:00
char * buf )
{
struct stts751_priv * priv = dev_get_drvdata ( dev ) ;
2017-09-19 15:59:34 +03:00
return snprintf ( buf , PAGE_SIZE , " %d \n " , priv - > therm ) ;
2017-02-02 10:44:03 +03:00
}
2018-12-11 01:02:21 +03:00
static ssize_t therm_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2017-02-02 10:44:03 +03:00
{
int ret ;
long temp ;
struct stts751_priv * priv = dev_get_drvdata ( dev ) ;
if ( kstrtol ( buf , 10 , & temp ) < 0 )
return - EINVAL ;
/* HW works in range -64C to +127.937C */
temp = clamp_val ( temp , - 64000 , 127937 ) ;
mutex_lock ( & priv - > access_lock ) ;
ret = stts751_set_temp_reg8 ( priv , temp , STTS751_REG_TLIM ) ;
if ( ret )
goto exit ;
dev_dbg ( & priv - > client - > dev , " setting therm %ld " , temp ) ;
/*
* hysteresis reg is relative to therm , so the HW does not need to be
* adjusted , we need to update our local copy only .
*/
priv - > hyst = temp - ( priv - > therm - priv - > hyst ) ;
priv - > therm = temp ;
exit :
mutex_unlock ( & priv - > access_lock ) ;
if ( ret )
return ret ;
return count ;
}
2018-12-11 01:02:21 +03:00
static ssize_t hyst_show ( struct device * dev , struct device_attribute * attr ,
2017-02-02 10:44:03 +03:00
char * buf )
{
struct stts751_priv * priv = dev_get_drvdata ( dev ) ;
2017-09-19 15:59:34 +03:00
return snprintf ( buf , PAGE_SIZE , " %d \n " , priv - > hyst ) ;
2017-02-02 10:44:03 +03:00
}
2018-12-11 01:02:21 +03:00
static ssize_t hyst_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2017-02-02 10:44:03 +03:00
{
int ret ;
long temp ;
struct stts751_priv * priv = dev_get_drvdata ( dev ) ;
if ( kstrtol ( buf , 10 , & temp ) < 0 )
return - EINVAL ;
mutex_lock ( & priv - > access_lock ) ;
/* HW works in range -64C to +127.937C */
temp = clamp_val ( temp , - 64000 , priv - > therm ) ;
priv - > hyst = temp ;
dev_dbg ( & priv - > client - > dev , " setting hyst %ld " , temp ) ;
temp = priv - > therm - temp ;
ret = stts751_set_temp_reg8 ( priv , temp , STTS751_REG_HYST ) ;
mutex_unlock ( & priv - > access_lock ) ;
if ( ret )
return ret ;
return count ;
}
2018-12-11 01:02:21 +03:00
static ssize_t therm_trip_show ( struct device * dev ,
2017-02-02 10:44:03 +03:00
struct device_attribute * attr , char * buf )
{
int ret ;
struct stts751_priv * priv = dev_get_drvdata ( dev ) ;
mutex_lock ( & priv - > access_lock ) ;
ret = stts751_update ( priv ) ;
mutex_unlock ( & priv - > access_lock ) ;
if ( ret < 0 )
return ret ;
2017-09-19 15:59:34 +03:00
return snprintf ( buf , PAGE_SIZE , " %d \n " , priv - > therm_trip ) ;
2017-02-02 10:44:03 +03:00
}
2018-12-11 01:02:21 +03:00
static ssize_t max_show ( struct device * dev , struct device_attribute * attr ,
2017-02-02 10:44:03 +03:00
char * buf )
{
struct stts751_priv * priv = dev_get_drvdata ( dev ) ;
2017-09-19 15:59:34 +03:00
return snprintf ( buf , PAGE_SIZE , " %d \n " , priv - > event_max ) ;
2017-02-02 10:44:03 +03:00
}
2018-12-11 01:02:21 +03:00
static ssize_t max_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2017-02-02 10:44:03 +03:00
{
int ret ;
long temp ;
struct stts751_priv * priv = dev_get_drvdata ( dev ) ;
if ( kstrtol ( buf , 10 , & temp ) < 0 )
return - EINVAL ;
mutex_lock ( & priv - > access_lock ) ;
/* HW works in range -64C to +127.937C */
temp = clamp_val ( temp , priv - > event_min , 127937 ) ;
ret = stts751_set_temp_reg16 ( priv , temp ,
STTS751_REG_HLIM_H , STTS751_REG_HLIM_L ) ;
if ( ret )
goto exit ;
dev_dbg ( & priv - > client - > dev , " setting event max %ld " , temp ) ;
priv - > event_max = temp ;
ret = count ;
exit :
mutex_unlock ( & priv - > access_lock ) ;
return ret ;
}
2018-12-11 01:02:21 +03:00
static ssize_t min_show ( struct device * dev , struct device_attribute * attr ,
2017-02-02 10:44:03 +03:00
char * buf )
{
struct stts751_priv * priv = dev_get_drvdata ( dev ) ;
2017-09-19 15:59:34 +03:00
return snprintf ( buf , PAGE_SIZE , " %d \n " , priv - > event_min ) ;
2017-02-02 10:44:03 +03:00
}
2018-12-11 01:02:21 +03:00
static ssize_t min_store ( struct device * dev , struct device_attribute * attr ,
const char * buf , size_t count )
2017-02-02 10:44:03 +03:00
{
int ret ;
long temp ;
struct stts751_priv * priv = dev_get_drvdata ( dev ) ;
if ( kstrtol ( buf , 10 , & temp ) < 0 )
return - EINVAL ;
mutex_lock ( & priv - > access_lock ) ;
/* HW works in range -64C to +127.937C */
temp = clamp_val ( temp , - 64000 , priv - > event_max ) ;
ret = stts751_set_temp_reg16 ( priv , temp ,
STTS751_REG_LLIM_H , STTS751_REG_LLIM_L ) ;
if ( ret )
goto exit ;
dev_dbg ( & priv - > client - > dev , " setting event min %ld " , temp ) ;
priv - > event_min = temp ;
ret = count ;
exit :
mutex_unlock ( & priv - > access_lock ) ;
return ret ;
}
2018-12-11 01:02:21 +03:00
static ssize_t interval_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
2017-02-02 10:44:03 +03:00
{
struct stts751_priv * priv = dev_get_drvdata ( dev ) ;
2017-09-19 15:59:34 +03:00
return snprintf ( buf , PAGE_SIZE , " %d \n " ,
2017-02-02 10:44:03 +03:00
stts751_intervals [ priv - > interval ] ) ;
}
2018-12-11 01:02:21 +03:00
static ssize_t interval_store ( struct device * dev ,
struct device_attribute * attr , const char * buf ,
size_t count )
2017-02-02 10:44:03 +03:00
{
unsigned long val ;
int idx ;
int ret = count ;
struct stts751_priv * priv = dev_get_drvdata ( dev ) ;
if ( kstrtoul ( buf , 10 , & val ) < 0 )
return - EINVAL ;
idx = find_closest_descending ( val , stts751_intervals ,
ARRAY_SIZE ( stts751_intervals ) ) ;
dev_dbg ( & priv - > client - > dev , " setting interval. req:%lu, idx: %d, val: %d " ,
val , idx , stts751_intervals [ idx ] ) ;
mutex_lock ( & priv - > access_lock ) ;
if ( priv - > interval = = idx )
goto exit ;
/*
* In early development stages I ' ve become suspicious about the chip
* starting to misbehave if I ever set , even briefly , an invalid
* configuration . While I ' m not sure this is really needed , be
* conservative and set rate / resolution in such an order that avoids
* passing through an invalid configuration .
*/
/* speed up: lower the resolution, then modify convrate */
if ( priv - > interval < idx ) {
dev_dbg ( & priv - > client - > dev , " lower resolution, then modify convrate " ) ;
priv - > interval = idx ;
ret = stts751_adjust_resolution ( priv ) ;
if ( ret )
goto exit ;
}
ret = i2c_smbus_write_byte_data ( priv - > client , STTS751_REG_RATE , idx ) ;
if ( ret )
goto exit ;
/* slow down: modify convrate, then raise resolution */
if ( priv - > interval ! = idx ) {
dev_dbg ( & priv - > client - > dev , " modify convrate, then raise resolution " ) ;
priv - > interval = idx ;
ret = stts751_adjust_resolution ( priv ) ;
if ( ret )
goto exit ;
}
ret = count ;
exit :
mutex_unlock ( & priv - > access_lock ) ;
return ret ;
}
static int stts751_detect ( struct i2c_client * new_client ,
struct i2c_board_info * info )
{
struct i2c_adapter * adapter = new_client - > adapter ;
const char * name ;
int tmp ;
if ( ! i2c_check_functionality ( adapter , I2C_FUNC_SMBUS_BYTE_DATA ) )
return - ENODEV ;
tmp = i2c_smbus_read_byte_data ( new_client , STTS751_REG_MAN_ID ) ;
if ( tmp ! = ST_MAN_ID )
return - ENODEV ;
/* lower temperaure registers always have bits 0-3 set to zero */
tmp = i2c_smbus_read_byte_data ( new_client , STTS751_REG_TEMP_L ) ;
if ( tmp & 0xf )
return - ENODEV ;
tmp = i2c_smbus_read_byte_data ( new_client , STTS751_REG_HLIM_L ) ;
if ( tmp & 0xf )
return - ENODEV ;
tmp = i2c_smbus_read_byte_data ( new_client , STTS751_REG_LLIM_L ) ;
if ( tmp & 0xf )
return - ENODEV ;
/* smbus timeout register always have bits 0-7 set to zero */
tmp = i2c_smbus_read_byte_data ( new_client , STTS751_REG_SMBUS_TO ) ;
if ( tmp & 0x7f )
return - ENODEV ;
tmp = i2c_smbus_read_byte_data ( new_client , STTS751_REG_PROD_ID ) ;
switch ( tmp ) {
case STTS751_0_PROD_ID :
name = " STTS751-0 " ;
break ;
case STTS751_1_PROD_ID :
name = " STTS751-1 " ;
break ;
default :
return - ENODEV ;
}
dev_dbg ( & new_client - > dev , " Chip %s detected " , name ) ;
strlcpy ( info - > type , stts751_id [ 0 ] . name , I2C_NAME_SIZE ) ;
return 0 ;
}
static int stts751_read_chip_config ( struct stts751_priv * priv )
{
int ret ;
int tmp ;
ret = i2c_smbus_read_byte_data ( priv - > client , STTS751_REG_CONF ) ;
if ( ret < 0 )
return ret ;
priv - > config = ret ;
priv - > res = ( ret & STTS751_CONF_RES_MASK ) > > STTS751_CONF_RES_SHIFT ;
ret = i2c_smbus_read_byte_data ( priv - > client , STTS751_REG_RATE ) ;
if ( ret < 0 )
return ret ;
2017-08-10 19:46:32 +03:00
if ( ret > = ARRAY_SIZE ( stts751_intervals ) ) {
dev_err ( priv - > dev , " Unrecognized conversion rate 0x%x \n " , ret ) ;
return - ENODEV ;
}
2017-02-02 10:44:03 +03:00
priv - > interval = ret ;
ret = stts751_read_reg16 ( priv , & priv - > event_max ,
STTS751_REG_HLIM_H , STTS751_REG_HLIM_L ) ;
if ( ret )
return ret ;
ret = stts751_read_reg16 ( priv , & priv - > event_min ,
STTS751_REG_LLIM_H , STTS751_REG_LLIM_L ) ;
if ( ret )
return ret ;
ret = stts751_read_reg8 ( priv , & priv - > therm , STTS751_REG_TLIM ) ;
if ( ret )
return ret ;
ret = stts751_read_reg8 ( priv , & tmp , STTS751_REG_HYST ) ;
if ( ret )
return ret ;
priv - > hyst = priv - > therm - tmp ;
return 0 ;
}
2018-12-11 01:02:21 +03:00
static SENSOR_DEVICE_ATTR_RO ( temp1_input , input , 0 ) ;
static SENSOR_DEVICE_ATTR_RW ( temp1_min , min , 0 ) ;
static SENSOR_DEVICE_ATTR_RW ( temp1_max , max , 0 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp1_min_alarm , min_alarm , 0 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp1_max_alarm , max_alarm , 0 ) ;
static SENSOR_DEVICE_ATTR_RW ( temp1_crit , therm , 0 ) ;
static SENSOR_DEVICE_ATTR_RW ( temp1_crit_hyst , hyst , 0 ) ;
static SENSOR_DEVICE_ATTR_RO ( temp1_crit_alarm , therm_trip , 0 ) ;
static SENSOR_DEVICE_ATTR_RW ( update_interval , interval , 0 ) ;
2017-02-02 10:44:03 +03:00
static struct attribute * stts751_attrs [ ] = {
& sensor_dev_attr_temp1_input . dev_attr . attr ,
& sensor_dev_attr_temp1_min . dev_attr . attr ,
& sensor_dev_attr_temp1_max . dev_attr . attr ,
& sensor_dev_attr_temp1_min_alarm . dev_attr . attr ,
& sensor_dev_attr_temp1_max_alarm . dev_attr . attr ,
& sensor_dev_attr_temp1_crit . dev_attr . attr ,
& sensor_dev_attr_temp1_crit_hyst . dev_attr . attr ,
& sensor_dev_attr_temp1_crit_alarm . dev_attr . attr ,
& sensor_dev_attr_update_interval . dev_attr . attr ,
NULL
} ;
ATTRIBUTE_GROUPS ( stts751 ) ;
static int stts751_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
struct stts751_priv * priv ;
int ret ;
bool smbus_nto ;
int rev_id ;
priv = devm_kzalloc ( & client - > dev , sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
priv - > client = client ;
priv - > notify_max = true ;
priv - > notify_min = true ;
i2c_set_clientdata ( client , priv ) ;
mutex_init ( & priv - > access_lock ) ;
if ( device_property_present ( & client - > dev ,
" smbus-timeout-disable " ) ) {
smbus_nto = device_property_read_bool ( & client - > dev ,
" smbus-timeout-disable " ) ;
ret = i2c_smbus_write_byte_data ( client , STTS751_REG_SMBUS_TO ,
smbus_nto ? 0 : 0x80 ) ;
if ( ret )
return ret ;
}
rev_id = i2c_smbus_read_byte_data ( client , STTS751_REG_REV_ID ) ;
if ( rev_id < 0 )
return - ENODEV ;
if ( rev_id ! = 0x1 ) {
dev_dbg ( & client - > dev , " Chip revision 0x%x is untested \n " ,
rev_id ) ;
}
ret = stts751_read_chip_config ( priv ) ;
if ( ret )
return ret ;
priv - > config & = ~ ( STTS751_CONF_STOP | STTS751_CONF_EVENT_DIS ) ;
ret = i2c_smbus_write_byte_data ( client , STTS751_REG_CONF , priv - > config ) ;
if ( ret )
return ret ;
priv - > dev = devm_hwmon_device_register_with_groups ( & client - > dev ,
client - > name , priv ,
stts751_groups ) ;
return PTR_ERR_OR_ZERO ( priv - > dev ) ;
}
MODULE_DEVICE_TABLE ( i2c , stts751_id ) ;
static struct i2c_driver stts751_driver = {
. class = I2C_CLASS_HWMON ,
. driver = {
. name = DEVNAME ,
2017-02-24 16:13:09 +03:00
. of_match_table = of_match_ptr ( stts751_of_match ) ,
2017-02-02 10:44:03 +03:00
} ,
. probe = stts751_probe ,
. id_table = stts751_id ,
. detect = stts751_detect ,
. alert = stts751_alert ,
. address_list = normal_i2c ,
} ;
module_i2c_driver ( stts751_driver ) ;
MODULE_AUTHOR ( " Andrea Merello <andrea.merello@gmail.com> " ) ;
MODULE_DESCRIPTION ( " STTS751 sensor driver " ) ;
MODULE_LICENSE ( " GPL " ) ;