2019-05-30 02:57:44 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2014-10-01 15:03:00 +04:00
/*
* si7005 . c - Support for Silabs Si7005 humidity and temperature sensor
*
* Copyright ( c ) 2014 Peter Meerwald < pmeerw @ pmeerw . net >
*
* ( 7 - bit I2C slave address 0x40 )
*
* TODO : heater , fast mode , processed mode ( temp . / linearity compensation )
*/
# include <linux/err.h>
# include <linux/i2c.h>
# include <linux/delay.h>
# include <linux/module.h>
# include <linux/pm.h>
# include <linux/iio/iio.h>
# include <linux/iio/sysfs.h>
# define SI7005_STATUS 0x00
# define SI7005_DATA 0x01 /* 16-bit, MSB */
# define SI7005_CONFIG 0x03
# define SI7005_ID 0x11
# define SI7005_STATUS_NRDY BIT(0)
# define SI7005_CONFIG_TEMP BIT(4)
# define SI7005_CONFIG_START BIT(0)
# define SI7005_ID_7005 0x50
# define SI7005_ID_7015 0xf0
struct si7005_data {
struct i2c_client * client ;
struct mutex lock ;
u8 config ;
} ;
static int si7005_read_measurement ( struct si7005_data * data , bool temp )
{
int tries = 50 ;
int ret ;
mutex_lock ( & data - > lock ) ;
ret = i2c_smbus_write_byte_data ( data - > client , SI7005_CONFIG ,
data - > config | SI7005_CONFIG_START |
( temp ? SI7005_CONFIG_TEMP : 0 ) ) ;
if ( ret < 0 )
goto done ;
while ( tries - - > 0 ) {
msleep ( 20 ) ;
ret = i2c_smbus_read_byte_data ( data - > client , SI7005_STATUS ) ;
if ( ret < 0 )
goto done ;
if ( ! ( ret & SI7005_STATUS_NRDY ) )
break ;
}
if ( tries < 0 ) {
ret = - EIO ;
goto done ;
}
ret = i2c_smbus_read_word_swapped ( data - > client , SI7005_DATA ) ;
done :
mutex_unlock ( & data - > lock ) ;
return ret ;
}
static int si7005_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan , int * val ,
int * val2 , long mask )
{
struct si7005_data * data = iio_priv ( indio_dev ) ;
int ret ;
switch ( mask ) {
case IIO_CHAN_INFO_RAW :
ret = si7005_read_measurement ( data , chan - > type = = IIO_TEMP ) ;
if ( ret < 0 )
return ret ;
* val = ret ;
return IIO_VAL_INT ;
case IIO_CHAN_INFO_SCALE :
if ( chan - > type = = IIO_TEMP ) {
* val = 7 ;
* val2 = 812500 ;
} else {
* val = 3 ;
* val2 = 906250 ;
}
return IIO_VAL_INT_PLUS_MICRO ;
case IIO_CHAN_INFO_OFFSET :
if ( chan - > type = = IIO_TEMP )
* val = - 50 * 32 * 4 ;
else
* val = - 24 * 16 * 16 ;
return IIO_VAL_INT ;
default :
break ;
}
return - EINVAL ;
}
static const struct iio_chan_spec si7005_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 si7005_info = {
. read_raw = si7005_read_raw ,
} ;
2022-11-19 01:37:19 +03:00
static int si7005_probe ( struct i2c_client * client )
2014-10-01 15:03:00 +04:00
{
struct iio_dev * indio_dev ;
struct si7005_data * data ;
int ret ;
if ( ! i2c_check_functionality ( client - > adapter , I2C_FUNC_SMBUS_WORD_DATA ) )
2016-02-27 09:13:49 +03:00
return - EOPNOTSUPP ;
2014-10-01 15:03:00 +04:00
indio_dev = devm_iio_device_alloc ( & client - > dev , sizeof ( * data ) ) ;
if ( ! indio_dev )
return - ENOMEM ;
data = iio_priv ( indio_dev ) ;
i2c_set_clientdata ( client , indio_dev ) ;
data - > client = client ;
mutex_init ( & data - > lock ) ;
indio_dev - > name = dev_name ( & client - > dev ) ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
indio_dev - > info = & si7005_info ;
indio_dev - > channels = si7005_channels ;
indio_dev - > num_channels = ARRAY_SIZE ( si7005_channels ) ;
ret = i2c_smbus_read_byte_data ( client , SI7005_ID ) ;
if ( ret < 0 )
return ret ;
if ( ret ! = SI7005_ID_7005 & & ret ! = SI7005_ID_7015 )
return - ENODEV ;
ret = i2c_smbus_read_byte_data ( client , SI7005_CONFIG ) ;
if ( ret < 0 )
return ret ;
data - > config = ret ;
return devm_iio_device_register ( & client - > dev , indio_dev ) ;
}
static const struct i2c_device_id si7005_id [ ] = {
{ " si7005 " , 0 } ,
2016-01-26 23:21:07 +03:00
{ " th02 " , 0 } ,
2014-10-01 15:03:00 +04:00
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , si7005_id ) ;
static struct i2c_driver si7005_driver = {
. driver = {
. name = " si7005 " ,
} ,
2022-11-19 01:37:19 +03:00
. probe_new = si7005_probe ,
2014-10-01 15:03:00 +04:00
. id_table = si7005_id ,
} ;
module_i2c_driver ( si7005_driver ) ;
MODULE_AUTHOR ( " Peter Meerwald <pmeerw@pmeerw.net> " ) ;
MODULE_DESCRIPTION ( " Silabs Si7005 humidity and temperature sensor driver " ) ;
MODULE_LICENSE ( " GPL " ) ;