2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2015-06-21 16:54:44 +03:00
/*
* An hwmon driver for the Microchip TC74
*
* Copyright 2015 Maciej Szmigiero < mail @ maciej . szmigiero . name >
*
* Based on ad7414 . c :
* Copyright 2006 Stefan Roese , DENX Software Engineering
* Copyright 2008 Sean MacLennan , PIKA Technologies
* Copyright 2008 Frank Edelhaeuser , Spansion Inc .
*/
# include <linux/bitops.h>
# include <linux/err.h>
# include <linux/hwmon.h>
# include <linux/hwmon-sysfs.h>
# include <linux/i2c.h>
# include <linux/jiffies.h>
# include <linux/module.h>
# include <linux/mutex.h>
# include <linux/slab.h>
# include <linux/sysfs.h>
/* TC74 registers */
# define TC74_REG_TEMP 0x00
# define TC74_REG_CONFIG 0x01
struct tc74_data {
struct i2c_client * client ;
struct mutex lock ; /* atomic read data updates */
bool valid ; /* validity of fields below */
unsigned long next_update ; /* In jiffies */
s8 temp_input ; /* Temp value in dC */
} ;
static int tc74_update_device ( struct device * dev )
{
struct tc74_data * data = dev_get_drvdata ( dev ) ;
struct i2c_client * client = data - > client ;
int ret ;
ret = mutex_lock_interruptible ( & data - > lock ) ;
if ( ret )
return ret ;
if ( time_after ( jiffies , data - > next_update ) | | ! data - > valid ) {
s32 value ;
value = i2c_smbus_read_byte_data ( client , TC74_REG_CONFIG ) ;
if ( value < 0 ) {
dev_dbg ( & client - > dev , " TC74_REG_CONFIG read err %d \n " ,
( int ) value ) ;
ret = value ;
goto ret_unlock ;
}
if ( ! ( value & BIT ( 6 ) ) ) {
/* not ready yet */
ret = - EAGAIN ;
goto ret_unlock ;
}
value = i2c_smbus_read_byte_data ( client , TC74_REG_TEMP ) ;
if ( value < 0 ) {
dev_dbg ( & client - > dev , " TC74_REG_TEMP read err %d \n " ,
( int ) value ) ;
ret = value ;
goto ret_unlock ;
}
data - > temp_input = value ;
data - > next_update = jiffies + HZ / 4 ;
data - > valid = true ;
}
ret_unlock :
mutex_unlock ( & data - > lock ) ;
return ret ;
}
2018-12-11 01:02:22 +03:00
static ssize_t temp_input_show ( struct device * dev ,
2015-06-21 16:54:44 +03:00
struct device_attribute * attr , char * buf )
{
struct tc74_data * data = dev_get_drvdata ( dev ) ;
int ret ;
ret = tc74_update_device ( dev ) ;
if ( ret )
return ret ;
return sprintf ( buf , " %d \n " , data - > temp_input * 1000 ) ;
}
2018-12-11 01:02:22 +03:00
static SENSOR_DEVICE_ATTR_RO ( temp1_input , temp_input , 0 ) ;
2015-06-21 16:54:44 +03:00
static struct attribute * tc74_attrs [ ] = {
& sensor_dev_attr_temp1_input . dev_attr . attr ,
NULL
} ;
ATTRIBUTE_GROUPS ( tc74 ) ;
2020-08-13 19:02:22 +03:00
static int tc74_probe ( struct i2c_client * client )
2015-06-21 16:54:44 +03:00
{
struct device * dev = & client - > dev ;
struct tc74_data * data ;
struct device * hwmon_dev ;
s32 conf ;
if ( ! i2c_check_functionality ( client - > adapter , I2C_FUNC_SMBUS_BYTE_DATA ) )
return - EOPNOTSUPP ;
data = devm_kzalloc ( dev , sizeof ( struct tc74_data ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
data - > client = client ;
mutex_init ( & data - > lock ) ;
/* Make sure the chip is powered up. */
conf = i2c_smbus_read_byte_data ( client , TC74_REG_CONFIG ) ;
if ( conf < 0 ) {
dev_err ( dev , " unable to read config register \n " ) ;
return conf ;
}
if ( conf & 0x3f ) {
dev_err ( dev , " invalid config register value \n " ) ;
return - ENODEV ;
}
if ( conf & BIT ( 7 ) ) {
s32 ret ;
conf & = ~ BIT ( 7 ) ;
ret = i2c_smbus_write_byte_data ( client , TC74_REG_CONFIG , conf ) ;
if ( ret )
dev_warn ( dev , " unable to disable STANDBY \n " ) ;
}
hwmon_dev = devm_hwmon_device_register_with_groups ( dev ,
client - > name ,
data , tc74_groups ) ;
return PTR_ERR_OR_ZERO ( hwmon_dev ) ;
}
static const struct i2c_device_id tc74_id [ ] = {
{ " tc74 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , tc74_id ) ;
static struct i2c_driver tc74_driver = {
. driver = {
. name = " tc74 " ,
} ,
2020-08-13 19:02:22 +03:00
. probe_new = tc74_probe ,
2015-06-21 16:54:44 +03:00
. id_table = tc74_id ,
} ;
module_i2c_driver ( tc74_driver ) ;
MODULE_AUTHOR ( " Maciej Szmigiero <mail@maciej.szmigiero.name> " ) ;
MODULE_DESCRIPTION ( " TC74 driver " ) ;
MODULE_LICENSE ( " GPL " ) ;