2019-05-30 02:57:44 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2014-02-05 20:58:00 +04:00
/*
2016-01-15 19:00:03 +03:00
* mpl115 . c - Support for Freescale MPL115A pressure / temperature sensor
2014-02-05 20:58:00 +04:00
*
* Copyright ( c ) 2014 Peter Meerwald < pmeerw @ pmeerw . net >
*
2022-10-10 20:37:20 +03:00
* TODO : synchronization with system suspend
2014-02-05 20:58:00 +04:00
*/
# include <linux/module.h>
# include <linux/iio/iio.h>
# include <linux/delay.h>
2022-10-10 20:37:20 +03:00
# include <linux/gpio/consumer.h>
2014-02-05 20:58:00 +04:00
2016-01-15 19:00:03 +03:00
# include "mpl115.h"
2014-02-05 20:58:00 +04:00
# define MPL115_PADC 0x00 /* pressure ADC output value, MSB first, 10 bit */
# define MPL115_TADC 0x02 /* temperature ADC output value, MSB first, 10 bit */
# define MPL115_A0 0x04 /* 12 bit integer, 3 bit fraction */
# define MPL115_B1 0x06 /* 2 bit integer, 13 bit fraction */
# define MPL115_B2 0x08 /* 1 bit integer, 14 bit fraction */
# define MPL115_C12 0x0a /* 0 bit integer, 13 bit fraction */
# define MPL115_CONVERT 0x12 /* convert temperature and pressure */
struct mpl115_data {
2016-01-15 19:00:03 +03:00
struct device * dev ;
2014-02-05 20:58:00 +04:00
struct mutex lock ;
s16 a0 ;
s16 b1 , b2 ;
s16 c12 ;
2022-10-10 20:37:20 +03:00
struct gpio_desc * shutdown ;
2016-01-15 19:00:03 +03:00
const struct mpl115_ops * ops ;
2014-02-05 20:58:00 +04:00
} ;
static int mpl115_request ( struct mpl115_data * data )
{
2016-01-15 19:00:03 +03:00
int ret = data - > ops - > write ( data - > dev , MPL115_CONVERT , 0 ) ;
2014-02-05 20:58:00 +04:00
if ( ret < 0 )
return ret ;
usleep_range ( 3000 , 4000 ) ;
return 0 ;
}
static int mpl115_comp_pressure ( struct mpl115_data * data , int * val , int * val2 )
{
int ret ;
u16 padc , tadc ;
int a1 , y1 , pcomp ;
unsigned kpa ;
mutex_lock ( & data - > lock ) ;
ret = mpl115_request ( data ) ;
if ( ret < 0 )
goto done ;
2016-01-15 19:00:03 +03:00
ret = data - > ops - > read ( data - > dev , MPL115_PADC ) ;
2014-02-05 20:58:00 +04:00
if ( ret < 0 )
goto done ;
padc = ret > > 6 ;
2016-01-15 19:00:03 +03:00
ret = data - > ops - > read ( data - > dev , MPL115_TADC ) ;
2014-02-05 20:58:00 +04:00
if ( ret < 0 )
goto done ;
tadc = ret > > 6 ;
/* see Freescale AN3785 */
a1 = data - > b1 + ( ( data - > c12 * tadc ) > > 11 ) ;
y1 = ( data - > a0 < < 10 ) + a1 * padc ;
/* compensated pressure with 4 fractional bits */
pcomp = ( y1 + ( ( data - > b2 * ( int ) tadc ) > > 1 ) ) > > 9 ;
kpa = pcomp * ( 115 - 50 ) / 1023 + ( 50 < < 4 ) ;
* val = kpa > > 4 ;
* val2 = ( kpa & 15 ) * ( 1000000 > > 4 ) ;
done :
mutex_unlock ( & data - > lock ) ;
return ret ;
}
static int mpl115_read_temp ( struct mpl115_data * data )
{
int ret ;
mutex_lock ( & data - > lock ) ;
ret = mpl115_request ( data ) ;
if ( ret < 0 )
goto done ;
2016-01-15 19:00:03 +03:00
ret = data - > ops - > read ( data - > dev , MPL115_TADC ) ;
2014-02-05 20:58:00 +04:00
done :
mutex_unlock ( & data - > lock ) ;
return ret ;
}
static int mpl115_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int * val , int * val2 , long mask )
{
struct mpl115_data * data = iio_priv ( indio_dev ) ;
int ret ;
switch ( mask ) {
case IIO_CHAN_INFO_PROCESSED :
2022-10-10 20:37:20 +03:00
pm_runtime_get_sync ( data - > dev ) ;
2014-02-05 20:58:00 +04:00
ret = mpl115_comp_pressure ( data , val , val2 ) ;
if ( ret < 0 )
return ret ;
2022-10-10 20:37:20 +03:00
pm_runtime_mark_last_busy ( data - > dev ) ;
pm_runtime_put_autosuspend ( data - > dev ) ;
2014-02-05 20:58:00 +04:00
return IIO_VAL_INT_PLUS_MICRO ;
case IIO_CHAN_INFO_RAW :
2022-10-10 20:37:20 +03:00
pm_runtime_get_sync ( data - > dev ) ;
2014-02-05 20:58:00 +04:00
/* temperature -5.35 C / LSB, 472 LSB is 25 C */
ret = mpl115_read_temp ( data ) ;
if ( ret < 0 )
return ret ;
2022-10-10 20:37:20 +03:00
pm_runtime_mark_last_busy ( data - > dev ) ;
pm_runtime_put_autosuspend ( data - > dev ) ;
2014-02-05 20:58:00 +04:00
* val = ret > > 6 ;
2022-10-10 20:37:20 +03:00
2014-02-05 20:58:00 +04:00
return IIO_VAL_INT ;
case IIO_CHAN_INFO_OFFSET :
2016-01-20 19:07:31 +03:00
* val = - 605 ;
2014-02-05 20:58:00 +04:00
* val2 = 750000 ;
return IIO_VAL_INT_PLUS_MICRO ;
case IIO_CHAN_INFO_SCALE :
* val = - 186 ;
* val2 = 915888 ;
return IIO_VAL_INT_PLUS_MICRO ;
}
return - EINVAL ;
}
static const struct iio_chan_spec mpl115_channels [ ] = {
{
. type = IIO_PRESSURE ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_PROCESSED ) ,
} ,
{
. type = IIO_TEMP ,
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) ,
2017-02-01 23:40:57 +03:00
. info_mask_shared_by_type =
2014-02-05 20:58:00 +04:00
BIT ( IIO_CHAN_INFO_OFFSET ) | BIT ( IIO_CHAN_INFO_SCALE ) ,
} ,
} ;
static const struct iio_info mpl115_info = {
. read_raw = & mpl115_read_raw ,
} ;
2016-01-15 19:00:03 +03:00
int mpl115_probe ( struct device * dev , const char * name ,
const struct mpl115_ops * ops )
2014-02-05 20:58:00 +04:00
{
struct mpl115_data * data ;
struct iio_dev * indio_dev ;
int ret ;
2016-01-15 19:00:03 +03:00
indio_dev = devm_iio_device_alloc ( dev , sizeof ( * data ) ) ;
2014-02-05 20:58:00 +04:00
if ( ! indio_dev )
return - ENOMEM ;
data = iio_priv ( indio_dev ) ;
2016-01-15 19:00:03 +03:00
data - > dev = dev ;
data - > ops = ops ;
2014-02-05 20:58:00 +04:00
mutex_init ( & data - > lock ) ;
indio_dev - > info = & mpl115_info ;
2016-01-15 19:00:03 +03:00
indio_dev - > name = name ;
2014-02-05 20:58:00 +04:00
indio_dev - > modes = INDIO_DIRECT_MODE ;
indio_dev - > channels = mpl115_channels ;
indio_dev - > num_channels = ARRAY_SIZE ( mpl115_channels ) ;
2016-01-15 19:00:03 +03:00
ret = data - > ops - > init ( data - > dev ) ;
if ( ret )
return ret ;
2022-10-10 20:37:20 +03:00
dev_set_drvdata ( dev , indio_dev ) ;
2016-01-15 19:00:03 +03:00
ret = data - > ops - > read ( data - > dev , MPL115_A0 ) ;
2014-02-05 20:58:00 +04:00
if ( ret < 0 )
return ret ;
data - > a0 = ret ;
2016-01-15 19:00:03 +03:00
ret = data - > ops - > read ( data - > dev , MPL115_B1 ) ;
2014-02-05 20:58:00 +04:00
if ( ret < 0 )
return ret ;
data - > b1 = ret ;
2016-01-15 19:00:03 +03:00
ret = data - > ops - > read ( data - > dev , MPL115_B2 ) ;
2014-02-05 20:58:00 +04:00
if ( ret < 0 )
return ret ;
data - > b2 = ret ;
2016-01-15 19:00:03 +03:00
ret = data - > ops - > read ( data - > dev , MPL115_C12 ) ;
2014-02-05 20:58:00 +04:00
if ( ret < 0 )
return ret ;
data - > c12 = ret ;
2022-10-10 20:37:20 +03:00
data - > shutdown = devm_gpiod_get_optional ( dev , " shutdown " ,
GPIOD_OUT_LOW ) ;
if ( IS_ERR ( data - > shutdown ) )
return dev_err_probe ( dev , PTR_ERR ( data - > shutdown ) ,
" cannot get shutdown gpio \n " ) ;
if ( data - > shutdown ) {
/* Enable runtime PM */
pm_runtime_get_noresume ( dev ) ;
pm_runtime_set_active ( dev ) ;
pm_runtime_enable ( dev ) ;
/*
* As the device takes 3 ms to come up with a fresh
* reading after power - on and 5 ms to actually power - on ,
* do not shut it down unnecessarily . Set autosuspend to
* 2000 ms .
*/
pm_runtime_set_autosuspend_delay ( dev , 2000 ) ;
pm_runtime_use_autosuspend ( dev ) ;
pm_runtime_put ( dev ) ;
dev_dbg ( dev , " low-power mode enabled " ) ;
} else
dev_dbg ( dev , " low-power mode disabled " ) ;
2016-01-15 19:00:03 +03:00
return devm_iio_device_register ( dev , indio_dev ) ;
2014-02-05 20:58:00 +04:00
}
2022-01-30 23:56:56 +03:00
EXPORT_SYMBOL_NS_GPL ( mpl115_probe , IIO_MPL115 ) ;
2014-02-05 20:58:00 +04:00
2022-10-10 20:37:20 +03:00
static int mpl115_runtime_suspend ( struct device * dev )
{
struct mpl115_data * data = iio_priv ( dev_get_drvdata ( dev ) ) ;
gpiod_set_value ( data - > shutdown , 1 ) ;
return 0 ;
}
static int mpl115_runtime_resume ( struct device * dev )
{
struct mpl115_data * data = iio_priv ( dev_get_drvdata ( dev ) ) ;
gpiod_set_value ( data - > shutdown , 0 ) ;
usleep_range ( 5000 , 6000 ) ;
return 0 ;
}
EXPORT_NS_RUNTIME_DEV_PM_OPS ( mpl115_dev_pm_ops , mpl115_runtime_suspend ,
mpl115_runtime_resume , NULL , IIO_MPL115 ) ;
2014-02-05 20:58:00 +04:00
MODULE_AUTHOR ( " Peter Meerwald <pmeerw@pmeerw.net> " ) ;
MODULE_DESCRIPTION ( " Freescale MPL115 pressure/temperature driver " ) ;
MODULE_LICENSE ( " GPL " ) ;