2019-06-01 10:08:37 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2016-07-25 18:21:18 +03:00
/*
* IIO driver for Domintech DMARD06 accelerometer
*
* Copyright ( C ) 2016 Aleksei Mamlin < mamlinav @ gmail . com >
*/
# include <linux/module.h>
2020-04-25 04:14:37 +05:30
# include <linux/mod_devicetable.h>
2016-07-25 18:21:18 +03:00
# include <linux/i2c.h>
# include <linux/iio/iio.h>
# define DMARD06_DRV_NAME "dmard06"
/* Device data registers */
# define DMARD06_CHIP_ID_REG 0x0f
# define DMARD06_TOUT_REG 0x40
# define DMARD06_XOUT_REG 0x41
# define DMARD06_YOUT_REG 0x42
# define DMARD06_ZOUT_REG 0x43
# define DMARD06_CTRL1_REG 0x44
/* Device ID value */
# define DMARD05_CHIP_ID 0x05
# define DMARD06_CHIP_ID 0x06
# define DMARD07_CHIP_ID 0x07
/* Device values */
# define DMARD05_AXIS_SCALE_VAL 15625
# define DMARD06_AXIS_SCALE_VAL 31250
# define DMARD06_TEMP_CENTER_VAL 25
# define DMARD06_SIGN_BIT 7
/* Device power modes */
# define DMARD06_MODE_NORMAL 0x27
# define DMARD06_MODE_POWERDOWN 0x00
/* Device channels */
# define DMARD06_ACCEL_CHANNEL(_axis, _reg) { \
. type = IIO_ACCEL , \
. address = _reg , \
. channel2 = IIO_MOD_ # # _axis , \
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) , \
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SCALE ) , \
. modified = 1 , \
}
# define DMARD06_TEMP_CHANNEL(_reg) { \
. type = IIO_TEMP , \
. address = _reg , \
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) | \
BIT ( IIO_CHAN_INFO_OFFSET ) , \
}
struct dmard06_data {
struct i2c_client * client ;
u8 chip_id ;
} ;
static const struct iio_chan_spec dmard06_channels [ ] = {
DMARD06_ACCEL_CHANNEL ( X , DMARD06_XOUT_REG ) ,
DMARD06_ACCEL_CHANNEL ( Y , DMARD06_YOUT_REG ) ,
DMARD06_ACCEL_CHANNEL ( Z , DMARD06_ZOUT_REG ) ,
DMARD06_TEMP_CHANNEL ( DMARD06_TOUT_REG ) ,
} ;
static int dmard06_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val , int * val2 , long mask )
{
struct dmard06_data * dmard06 = iio_priv ( indio_dev ) ;
int ret ;
switch ( mask ) {
case IIO_CHAN_INFO_RAW :
ret = i2c_smbus_read_byte_data ( dmard06 - > client ,
chan - > address ) ;
if ( ret < 0 ) {
dev_err ( & dmard06 - > client - > dev ,
" Error reading data: %d \n " , ret ) ;
return ret ;
}
* val = sign_extend32 ( ret , DMARD06_SIGN_BIT ) ;
if ( dmard06 - > chip_id = = DMARD06_CHIP_ID )
* val = * val > > 1 ;
switch ( chan - > type ) {
case IIO_ACCEL :
return IIO_VAL_INT ;
case IIO_TEMP :
if ( dmard06 - > chip_id ! = DMARD06_CHIP_ID )
* val = * val / 2 ;
return IIO_VAL_INT ;
default :
return - EINVAL ;
}
case IIO_CHAN_INFO_OFFSET :
switch ( chan - > type ) {
case IIO_TEMP :
* val = DMARD06_TEMP_CENTER_VAL ;
return IIO_VAL_INT ;
default :
return - EINVAL ;
}
case IIO_CHAN_INFO_SCALE :
switch ( chan - > type ) {
case IIO_ACCEL :
* val = 0 ;
if ( dmard06 - > chip_id = = DMARD06_CHIP_ID )
* val2 = DMARD06_AXIS_SCALE_VAL ;
else
* val2 = DMARD05_AXIS_SCALE_VAL ;
return IIO_VAL_INT_PLUS_MICRO ;
default :
return - EINVAL ;
}
default :
return - EINVAL ;
}
}
static const struct iio_info dmard06_info = {
. read_raw = dmard06_read_raw ,
} ;
static int dmard06_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
int ret ;
struct iio_dev * indio_dev ;
struct dmard06_data * dmard06 ;
if ( ! i2c_check_functionality ( client - > adapter , I2C_FUNC_I2C ) ) {
dev_err ( & client - > dev , " I2C check functionality failed \n " ) ;
return - ENXIO ;
}
indio_dev = devm_iio_device_alloc ( & client - > dev , sizeof ( * dmard06 ) ) ;
if ( ! indio_dev ) {
dev_err ( & client - > dev , " Failed to allocate iio device \n " ) ;
return - ENOMEM ;
}
dmard06 = iio_priv ( indio_dev ) ;
dmard06 - > client = client ;
ret = i2c_smbus_read_byte_data ( dmard06 - > client , DMARD06_CHIP_ID_REG ) ;
if ( ret < 0 ) {
dev_err ( & client - > dev , " Error reading chip id: %d \n " , ret ) ;
return ret ;
}
if ( ret ! = DMARD05_CHIP_ID & & ret ! = DMARD06_CHIP_ID & &
ret ! = DMARD07_CHIP_ID ) {
dev_err ( & client - > dev , " Invalid chip id: %02d \n " , ret ) ;
return - ENODEV ;
}
dmard06 - > chip_id = ret ;
i2c_set_clientdata ( client , indio_dev ) ;
indio_dev - > name = DMARD06_DRV_NAME ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
indio_dev - > channels = dmard06_channels ;
indio_dev - > num_channels = ARRAY_SIZE ( dmard06_channels ) ;
indio_dev - > info = & dmard06_info ;
return devm_iio_device_register ( & client - > dev , indio_dev ) ;
}
# ifdef CONFIG_PM_SLEEP
static int dmard06_suspend ( struct device * dev )
{
struct iio_dev * indio_dev = i2c_get_clientdata ( to_i2c_client ( dev ) ) ;
struct dmard06_data * dmard06 = iio_priv ( indio_dev ) ;
int ret ;
ret = i2c_smbus_write_byte_data ( dmard06 - > client , DMARD06_CTRL1_REG ,
DMARD06_MODE_POWERDOWN ) ;
if ( ret < 0 )
return ret ;
return 0 ;
}
static int dmard06_resume ( struct device * dev )
{
struct iio_dev * indio_dev = i2c_get_clientdata ( to_i2c_client ( dev ) ) ;
struct dmard06_data * dmard06 = iio_priv ( indio_dev ) ;
int ret ;
ret = i2c_smbus_write_byte_data ( dmard06 - > client , DMARD06_CTRL1_REG ,
DMARD06_MODE_NORMAL ) ;
if ( ret < 0 )
return ret ;
return 0 ;
}
static SIMPLE_DEV_PM_OPS ( dmard06_pm_ops , dmard06_suspend , dmard06_resume ) ;
# define DMARD06_PM_OPS (&dmard06_pm_ops)
# else
# define DMARD06_PM_OPS NULL
# endif
static const struct i2c_device_id dmard06_id [ ] = {
{ " dmard05 " , 0 } ,
{ " dmard06 " , 0 } ,
{ " dmard07 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , dmard06_id ) ;
static const struct of_device_id dmard06_of_match [ ] = {
{ . compatible = " domintech,dmard05 " } ,
{ . compatible = " domintech,dmard06 " } ,
{ . compatible = " domintech,dmard07 " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , dmard06_of_match ) ;
static struct i2c_driver dmard06_driver = {
. probe = dmard06_probe ,
. id_table = dmard06_id ,
. driver = {
. name = DMARD06_DRV_NAME ,
2020-04-25 04:14:37 +05:30
. of_match_table = dmard06_of_match ,
2016-07-25 18:21:18 +03:00
. pm = DMARD06_PM_OPS ,
} ,
} ;
module_i2c_driver ( dmard06_driver ) ;
MODULE_AUTHOR ( " Aleksei Mamlin <mamlinav@gmail.com> " ) ;
MODULE_DESCRIPTION ( " Domintech DMARD06 accelerometer driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;