2019-06-04 11:11:24 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2014-09-29 22:28:55 +04:00
/*
* si7020 . c - Silicon Labs Si7013 / 20 / 21 Relative Humidity and Temp Sensors
* Copyright ( c ) 2013 , 2014 Uplogix , Inc .
* David Barksdale < dbarksdale @ uplogix . com >
*/
/*
* The Silicon Labs Si7013 / 20 / 21 Relative Humidity and Temperature Sensors
* are i2c devices which have an identical programming interface for
* measuring relative humidity and temperature . The Si7013 has an additional
* temperature input which this driver does not support .
*
* Data Sheets :
* Si7013 : http : //www.silabs.com/Support%20Documents/TechnicalDocs/Si7013.pdf
* Si7020 : http : //www.silabs.com/Support%20Documents/TechnicalDocs/Si7020.pdf
* Si7021 : http : //www.silabs.com/Support%20Documents/TechnicalDocs/Si7021.pdf
*/
# include <linux/delay.h>
# include <linux/i2c.h>
# include <linux/module.h>
2020-09-10 20:32:41 +03:00
# include <linux/mod_devicetable.h>
2014-09-29 22:28:55 +04:00
# include <linux/slab.h>
# include <linux/sysfs.h>
# include <linux/iio/iio.h>
# include <linux/iio/sysfs.h>
/* Measure Relative Humidity, Hold Master Mode */
# define SI7020CMD_RH_HOLD 0xE5
/* Measure Temperature, Hold Master Mode */
# define SI7020CMD_TEMP_HOLD 0xE3
/* Software Reset */
# define SI7020CMD_RESET 0xFE
static int si7020_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan , int * val ,
int * val2 , long mask )
{
2015-02-14 14:32:17 +03:00
struct i2c_client * * client = iio_priv ( indio_dev ) ;
2014-09-29 22:28:55 +04:00
int ret ;
switch ( mask ) {
case IIO_CHAN_INFO_RAW :
2015-11-03 00:45:03 +03:00
ret = i2c_smbus_read_word_swapped ( * client ,
chan - > type = = IIO_TEMP ?
SI7020CMD_TEMP_HOLD :
SI7020CMD_RH_HOLD ) ;
2014-09-29 22:28:55 +04:00
if ( ret < 0 )
return ret ;
2014-10-25 22:09:11 +04:00
* val = ret > > 2 ;
2015-08-24 00:06:19 +03:00
/*
* Humidity values can slightly exceed the 0 - 100 % RH
* range and should be corrected by software
*/
2014-10-25 22:09:11 +04:00
if ( chan - > type = = IIO_HUMIDITYRELATIVE )
2015-08-24 00:06:19 +03:00
* val = clamp_val ( * val , 786 , 13893 ) ;
2014-09-29 22:28:55 +04:00
return IIO_VAL_INT ;
case IIO_CHAN_INFO_SCALE :
if ( chan - > type = = IIO_TEMP )
* val = 175720 ; /* = 175.72 * 1000 */
else
* val = 125 * 1000 ;
* val2 = 65536 > > 2 ;
return IIO_VAL_FRACTIONAL ;
case IIO_CHAN_INFO_OFFSET :
/*
* Since iio_convert_raw_to_processed_unlocked assumes offset
* is an integer we have to round these values and lose
* accuracy .
* Relative humidity will be 0.0032959 % too high and
* temperature will be 0.00277344 degrees too high .
* This is no big deal because it ' s within the accuracy of the
* sensor .
*/
if ( chan - > type = = IIO_TEMP )
* val = - 4368 ; /* = -46.85 * (65536 >> 2) / 175.72 */
else
* val = - 786 ; /* = -6 * (65536 >> 2) / 125 */
return IIO_VAL_INT ;
default :
break ;
}
return - EINVAL ;
}
static const struct iio_chan_spec si7020_channels [ ] = {
{
. type = IIO_HUMIDITYRELATIVE ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
BIT ( IIO_CHAN_INFO_SCALE ) | BIT ( IIO_CHAN_INFO_OFFSET ) ,
} ,
{
. type = IIO_TEMP ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) |
BIT ( IIO_CHAN_INFO_SCALE ) | BIT ( IIO_CHAN_INFO_OFFSET ) ,
}
} ;
static const struct iio_info si7020_info = {
. read_raw = si7020_read_raw ,
} ;
2022-11-19 01:37:20 +03:00
static int si7020_probe ( struct i2c_client * client )
2014-09-29 22:28:55 +04:00
{
struct iio_dev * indio_dev ;
struct i2c_client * * data ;
int ret ;
if ( ! i2c_check_functionality ( client - > adapter ,
I2C_FUNC_SMBUS_WRITE_BYTE |
I2C_FUNC_SMBUS_READ_WORD_DATA ) )
2016-02-27 09:13:49 +03:00
return - EOPNOTSUPP ;
2014-09-29 22:28:55 +04:00
/* Reset device, loads default settings. */
ret = i2c_smbus_write_byte ( client , SI7020CMD_RESET ) ;
if ( ret < 0 )
return ret ;
/* Wait the maximum power-up time after software reset. */
msleep ( 15 ) ;
2015-02-13 10:58:41 +03:00
indio_dev = devm_iio_device_alloc ( & client - > dev , sizeof ( * data ) ) ;
2014-09-29 22:28:55 +04:00
if ( ! indio_dev )
return - ENOMEM ;
data = iio_priv ( indio_dev ) ;
* data = client ;
indio_dev - > name = dev_name ( & client - > dev ) ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
indio_dev - > info = & si7020_info ;
indio_dev - > channels = si7020_channels ;
indio_dev - > num_channels = ARRAY_SIZE ( si7020_channels ) ;
return devm_iio_device_register ( & client - > dev , indio_dev ) ;
}
static const struct i2c_device_id si7020_id [ ] = {
{ " si7020 " , 0 } ,
2016-01-26 23:17:49 +03:00
{ " th06 " , 0 } ,
2014-09-29 22:28:55 +04:00
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , si7020_id ) ;
2016-10-25 22:20:10 +03:00
static const struct of_device_id si7020_dt_ids [ ] = {
{ . compatible = " silabs,si7020 " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , si7020_dt_ids ) ;
2014-09-29 22:28:55 +04:00
static struct i2c_driver si7020_driver = {
2016-10-25 22:20:10 +03:00
. driver = {
. name = " si7020 " ,
2020-09-10 20:32:41 +03:00
. of_match_table = si7020_dt_ids ,
2016-10-25 22:20:10 +03:00
} ,
2022-11-19 01:37:20 +03:00
. probe_new = si7020_probe ,
2014-09-29 22:28:55 +04:00
. id_table = si7020_id ,
} ;
module_i2c_driver ( si7020_driver ) ;
MODULE_DESCRIPTION ( " Silicon Labs Si7013/20/21 Relative Humidity and Temperature Sensors " ) ;
MODULE_AUTHOR ( " David Barksdale <dbarksdale@uplogix.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;