2015-03-22 21:43:16 +03:00
/*
* Device driver for the the HMC5843 multi - chip module designed
* for low field magnetic sensing .
*
* Copyright ( C ) 2010 Texas Instruments
*
* Author : Shubhrajyoti Datta < shubhrajyoti @ ti . com >
* Acknowledgment : Jonathan Cameron < jic23 @ kernel . org > for valuable inputs .
* Support for HMC5883 and HMC5883L by Peter Meerwald < pmeerw @ pmeerw . net > .
* Split to multiple files by Josef Gajdusek < atx @ atx . name > - 2014
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
2010-07-17 17:02:52 +04:00
# include <linux/module.h>
2014-07-22 19:00:00 +04:00
# include <linux/regmap.h>
2012-04-25 18:54:58 +04:00
# include <linux/iio/iio.h>
# include <linux/iio/sysfs.h>
2013-10-17 02:19:00 +04:00
# include <linux/iio/trigger_consumer.h>
# include <linux/iio/buffer.h>
# include <linux/iio/triggered_buffer.h>
2013-07-27 19:31:00 +04:00
# include <linux/delay.h>
2010-07-17 17:02:52 +04:00
2014-07-22 19:01:00 +04:00
# include "hmc5843.h"
2012-05-16 20:22:05 +04:00
2010-07-17 17:02:52 +04:00
/*
2012-05-16 20:22:05 +04:00
* Range gain settings in ( + - ) Ga
* Beware : HMC5843 and HMC5883 have different recommended sensor field
* ranges ; default corresponds to + - 1.0 Ga and + - 1.3 Ga , respectively
*/
# define HMC5843_RANGE_GAIN_OFFSET 0x05
# define HMC5843_RANGE_GAIN_DEFAULT 0x01
2014-07-22 19:00:00 +04:00
# define HMC5843_RANGE_GAIN_MASK 0xe0
2010-07-17 17:02:52 +04:00
2013-09-19 23:35:00 +04:00
/* Device status */
2012-05-16 20:22:05 +04:00
# define HMC5843_DATA_READY 0x01
# define HMC5843_DATA_OUTPUT_LOCK 0x02
2010-07-17 17:02:52 +04:00
2013-09-19 23:35:00 +04:00
/* Mode register configuration */
2012-05-16 20:22:05 +04:00
# define HMC5843_MODE_CONVERSION_CONTINUOUS 0x00
# define HMC5843_MODE_CONVERSION_SINGLE 0x01
# define HMC5843_MODE_IDLE 0x02
# define HMC5843_MODE_SLEEP 0x03
# define HMC5843_MODE_MASK 0x03
/*
* HMC5843 : Minimum data output rate
* HMC5883 : Typical data output rate
*/
# define HMC5843_RATE_OFFSET 0x02
2013-09-19 23:35:00 +04:00
# define HMC5843_RATE_DEFAULT 0x04
2014-07-22 19:00:00 +04:00
# define HMC5843_RATE_MASK 0x1c
2010-07-17 17:02:52 +04:00
2013-09-19 23:35:00 +04:00
/* Device measurement configuration */
2012-05-16 20:22:05 +04:00
# define HMC5843_MEAS_CONF_NORMAL 0x00
# define HMC5843_MEAS_CONF_POSITIVE_BIAS 0x01
# define HMC5843_MEAS_CONF_NEGATIVE_BIAS 0x02
# define HMC5843_MEAS_CONF_MASK 0x03
2010-07-17 17:02:52 +04:00
2016-02-15 01:37:37 +03:00
/*
* API for setting the measurement configuration to
* Normal , Positive bias and Negative bias
*
* From the datasheet :
* 0 - Normal measurement configuration ( default ) : In normal measurement
* configuration the device follows normal measurement flow . Pins BP
* and BN are left floating and high impedance .
*
* 1 - Positive bias configuration : In positive bias configuration , a
* positive current is forced across the resistive load on pins BP
* and BN .
*
* 2 - Negative bias configuration . In negative bias configuration , a
* negative current is forced across the resistive load on pins BP
* and BN .
*
* 3 - Only available on HMC5983 . Magnetic sensor is disabled .
* Temperature sensor is enabled .
*/
static const char * const hmc5843_meas_conf_modes [ ] = { " normal " , " positivebias " ,
" negativebias " } ;
static const char * const hmc5983_meas_conf_modes [ ] = { " normal " , " positivebias " ,
" negativebias " ,
" disabled " } ;
2013-09-19 23:35:00 +04:00
/* Scaling factors: 10000000/Gain */
2014-07-22 19:02:00 +04:00
static const int hmc5843_regval_to_nanoscale [ ] = {
2011-08-12 20:47:58 +04:00
6173 , 7692 , 10309 , 12821 , 18868 , 21739 , 25641 , 35714
2010-07-17 17:02:52 +04:00
} ;
2011-08-12 20:47:58 +04:00
2014-07-22 19:02:00 +04:00
static const int hmc5883_regval_to_nanoscale [ ] = {
2012-05-17 04:28:13 +04:00
7812 , 9766 , 13021 , 16287 , 24096 , 27701 , 32573 , 45662
} ;
2014-07-22 19:02:00 +04:00
static const int hmc5883l_regval_to_nanoscale [ ] = {
2012-05-17 04:28:13 +04:00
7299 , 9174 , 12195 , 15152 , 22727 , 25641 , 30303 , 43478
} ;
2012-05-17 04:28:10 +04:00
/*
* From the datasheet :
2012-05-17 04:28:13 +04:00
* Value | HMC5843 | HMC5883 / HMC5883L
* | Data output rate ( Hz ) | Data output rate ( Hz )
* 0 | 0.5 | 0.75
* 1 | 1 | 1.5
* 2 | 2 | 3
* 3 | 5 | 7.5
* 4 | 10 ( default ) | 15
* 5 | 20 | 30
* 6 | 50 | 75
* 7 | Not used | Not used
2012-05-17 04:28:10 +04:00
*/
2014-07-22 19:02:00 +04:00
static const int hmc5843_regval_to_samp_freq [ ] [ 2 ] = {
2013-09-19 23:35:00 +04:00
{ 0 , 500000 } , { 1 , 0 } , { 2 , 0 } , { 5 , 0 } , { 10 , 0 } , { 20 , 0 } , { 50 , 0 }
2012-05-17 04:28:13 +04:00
} ;
2014-07-22 19:02:00 +04:00
static const int hmc5883_regval_to_samp_freq [ ] [ 2 ] = {
2013-09-19 23:35:00 +04:00
{ 0 , 750000 } , { 1 , 500000 } , { 3 , 0 } , { 7 , 500000 } , { 15 , 0 } , { 30 , 0 } ,
{ 75 , 0 }
2010-07-17 17:02:52 +04:00
} ;
2014-07-22 19:02:00 +04:00
static const int hmc5983_regval_to_samp_freq [ ] [ 2 ] = {
{ 0 , 750000 } , { 1 , 500000 } , { 3 , 0 } , { 7 , 500000 } , { 15 , 0 } , { 30 , 0 } ,
{ 75 , 0 } , { 220 , 0 }
} ;
2012-05-17 04:28:13 +04:00
/* Describe chip variants */
struct hmc5843_chip_info {
const struct iio_chan_spec * channels ;
2013-09-19 23:35:00 +04:00
const int ( * regval_to_samp_freq ) [ 2 ] ;
2014-07-22 19:02:00 +04:00
const int n_regval_to_samp_freq ;
2012-05-17 04:28:13 +04:00
const int * regval_to_nanoscale ;
2014-07-22 19:02:00 +04:00
const int n_regval_to_nanoscale ;
2012-05-17 04:28:13 +04:00
} ;
2012-05-17 04:28:10 +04:00
/* The lower two bits contain the current conversion mode */
2013-10-17 02:19:00 +04:00
static s32 hmc5843_set_mode ( struct hmc5843_data * data , u8 operating_mode )
2010-07-17 17:02:52 +04:00
{
2013-10-17 02:19:00 +04:00
int ret ;
mutex_lock ( & data - > lock ) ;
2014-07-22 19:00:00 +04:00
ret = regmap_update_bits ( data - > regmap , HMC5843_MODE_REG ,
2015-03-19 22:06:42 +03:00
HMC5843_MODE_MASK , operating_mode ) ;
2013-10-17 02:19:00 +04:00
mutex_unlock ( & data - > lock ) ;
return ret ;
2010-07-17 17:02:52 +04:00
}
2013-10-17 02:19:00 +04:00
static int hmc5843_wait_measurement ( struct hmc5843_data * data )
2010-07-17 17:02:52 +04:00
{
2013-07-27 19:31:00 +04:00
int tries = 150 ;
2014-07-28 15:18:00 +04:00
unsigned int val ;
2014-07-22 19:00:00 +04:00
int ret ;
2010-07-17 17:02:52 +04:00
2013-07-27 19:31:00 +04:00
while ( tries - - > 0 ) {
2014-07-22 19:00:00 +04:00
ret = regmap_read ( data - > regmap , HMC5843_STATUS_REG , & val ) ;
if ( ret < 0 )
return ret ;
if ( val & HMC5843_DATA_READY )
2013-07-27 19:31:00 +04:00
break ;
msleep ( 20 ) ;
}
if ( tries < 0 ) {
2014-07-22 19:01:00 +04:00
dev_err ( data - > dev , " data not ready \n " ) ;
2013-07-27 19:31:00 +04:00
return - EIO ;
}
2010-07-17 17:02:52 +04:00
2013-10-17 02:19:00 +04:00
return 0 ;
}
/* Return the measurement value from the specified channel */
static int hmc5843_read_measurement ( struct hmc5843_data * data ,
int idx , int * val )
{
__be16 values [ 3 ] ;
2014-07-22 19:00:00 +04:00
int ret ;
2013-10-17 02:19:00 +04:00
mutex_lock ( & data - > lock ) ;
2014-07-22 19:00:00 +04:00
ret = hmc5843_wait_measurement ( data ) ;
if ( ret < 0 ) {
2013-10-17 02:19:00 +04:00
mutex_unlock ( & data - > lock ) ;
2014-07-22 19:00:00 +04:00
return ret ;
2013-10-17 02:19:00 +04:00
}
2014-07-22 19:00:00 +04:00
ret = regmap_bulk_read ( data - > regmap , HMC5843_DATA_OUT_MSB_REGS ,
2015-03-19 22:06:42 +03:00
values , sizeof ( values ) ) ;
2010-07-17 17:02:52 +04:00
mutex_unlock ( & data - > lock ) ;
2014-07-22 19:00:00 +04:00
if ( ret < 0 )
return ret ;
2010-07-17 17:02:52 +04:00
2013-10-17 02:19:00 +04:00
* val = sign_extend32 ( be16_to_cpu ( values [ idx ] ) , 15 ) ;
2011-08-12 20:47:58 +04:00
return IIO_VAL_INT ;
2010-07-17 17:02:52 +04:00
}
2011-08-12 20:47:58 +04:00
2014-07-22 19:00:00 +04:00
static int hmc5843_set_meas_conf ( struct hmc5843_data * data , u8 meas_conf )
2010-07-17 17:02:52 +04:00
{
2013-10-17 02:19:00 +04:00
int ret ;
mutex_lock ( & data - > lock ) ;
2014-07-22 19:00:00 +04:00
ret = regmap_update_bits ( data - > regmap , HMC5843_CONFIG_REG_A ,
2015-03-19 22:06:42 +03:00
HMC5843_MEAS_CONF_MASK , meas_conf ) ;
2013-10-17 02:19:00 +04:00
mutex_unlock ( & data - > lock ) ;
return ret ;
2010-07-17 17:02:52 +04:00
}
2015-03-19 22:06:42 +03:00
static
2016-02-15 01:37:37 +03:00
int hmc5843_show_measurement_configuration ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan )
2010-07-17 17:02:52 +04:00
{
2016-02-15 01:37:37 +03:00
struct hmc5843_data * data = iio_priv ( indio_dev ) ;
2014-07-28 15:18:00 +04:00
unsigned int val ;
2014-07-22 19:00:00 +04:00
int ret ;
ret = regmap_read ( data - > regmap , HMC5843_CONFIG_REG_A , & val ) ;
if ( ret )
return ret ;
2016-02-15 01:37:37 +03:00
return val & HMC5843_MEAS_CONF_MASK ;
2010-07-17 17:02:52 +04:00
}
2015-03-19 22:06:42 +03:00
static
2016-02-15 01:37:37 +03:00
int hmc5843_set_measurement_configuration ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan ,
unsigned int meas_conf )
2010-07-17 17:02:52 +04:00
{
2016-02-15 01:37:37 +03:00
struct hmc5843_data * data = iio_priv ( indio_dev ) ;
2012-05-17 04:28:09 +04:00
2016-02-15 01:37:37 +03:00
return hmc5843_set_meas_conf ( data , meas_conf ) ;
}
2012-05-17 04:28:09 +04:00
2016-02-15 01:37:37 +03:00
static const struct iio_enum hmc5843_meas_conf_enum = {
. items = hmc5843_meas_conf_modes ,
. num_items = ARRAY_SIZE ( hmc5843_meas_conf_modes ) ,
. get = hmc5843_show_measurement_configuration ,
. set = hmc5843_set_measurement_configuration ,
} ;
2010-07-17 17:02:52 +04:00
2016-02-15 01:37:37 +03:00
static const struct iio_chan_spec_ext_info hmc5843_ext_info [ ] = {
IIO_ENUM ( " meas_conf " , true , & hmc5843_meas_conf_enum ) ,
IIO_ENUM_AVAILABLE ( " meas_conf " , & hmc5843_meas_conf_enum ) ,
{ } ,
} ;
2012-05-17 04:28:10 +04:00
2016-02-15 01:37:37 +03:00
static const struct iio_enum hmc5983_meas_conf_enum = {
. items = hmc5983_meas_conf_modes ,
. num_items = ARRAY_SIZE ( hmc5983_meas_conf_modes ) ,
. get = hmc5843_show_measurement_configuration ,
. set = hmc5843_set_measurement_configuration ,
} ;
static const struct iio_chan_spec_ext_info hmc5983_ext_info [ ] = {
IIO_ENUM ( " meas_conf " , true , & hmc5983_meas_conf_enum ) ,
IIO_ENUM_AVAILABLE ( " meas_conf " , & hmc5983_meas_conf_enum ) ,
{ } ,
} ;
2010-07-17 17:02:52 +04:00
2015-03-19 22:06:42 +03:00
static
ssize_t hmc5843_show_samp_freq_avail ( struct device * dev ,
struct device_attribute * attr , char * buf )
2012-05-17 04:28:13 +04:00
{
2013-10-17 02:19:00 +04:00
struct hmc5843_data * data = iio_priv ( dev_to_iio_dev ( dev ) ) ;
2013-09-19 23:35:00 +04:00
size_t len = 0 ;
2012-05-17 04:28:13 +04:00
int i ;
2014-07-22 19:02:00 +04:00
for ( i = 0 ; i < data - > variant - > n_regval_to_samp_freq ; i + + )
2013-09-19 23:35:00 +04:00
len + = scnprintf ( buf + len , PAGE_SIZE - len ,
2013-10-17 02:19:00 +04:00
" %d.%d " , data - > variant - > regval_to_samp_freq [ i ] [ 0 ] ,
data - > variant - > regval_to_samp_freq [ i ] [ 1 ] ) ;
2013-09-19 23:35:00 +04:00
2012-05-17 04:28:13 +04:00
/* replace trailing space by newline */
2013-09-19 23:35:00 +04:00
buf [ len - 1 ] = ' \n ' ;
return len ;
}
2012-05-17 04:28:13 +04:00
2013-09-19 23:35:00 +04:00
static IIO_DEV_ATTR_SAMP_FREQ_AVAIL ( hmc5843_show_samp_freq_avail ) ;
2010-07-17 17:02:52 +04:00
2013-10-17 02:19:00 +04:00
static int hmc5843_set_samp_freq ( struct hmc5843_data * data , u8 rate )
2010-07-17 17:02:52 +04:00
{
2013-10-17 02:19:00 +04:00
int ret ;
mutex_lock ( & data - > lock ) ;
2014-07-22 19:00:00 +04:00
ret = regmap_update_bits ( data - > regmap , HMC5843_CONFIG_REG_A ,
2015-03-19 22:06:42 +03:00
HMC5843_RATE_MASK ,
rate < < HMC5843_RATE_OFFSET ) ;
2013-10-17 02:19:00 +04:00
mutex_unlock ( & data - > lock ) ;
2012-05-17 04:28:12 +04:00
2013-10-17 02:19:00 +04:00
return ret ;
2010-07-17 17:02:52 +04:00
}
2013-10-17 02:19:00 +04:00
static int hmc5843_get_samp_freq_index ( struct hmc5843_data * data ,
2015-03-19 22:06:42 +03:00
int val , int val2 )
2012-05-17 04:28:08 +04:00
{
2013-10-17 02:19:00 +04:00
int i ;
2014-07-22 19:02:00 +04:00
for ( i = 0 ; i < data - > variant - > n_regval_to_samp_freq ; i + + )
2013-10-17 02:19:00 +04:00
if ( val = = data - > variant - > regval_to_samp_freq [ i ] [ 0 ] & &
2015-03-19 22:06:42 +03:00
val2 = = data - > variant - > regval_to_samp_freq [ i ] [ 1 ] )
2013-10-17 02:19:00 +04:00
return i ;
return - EINVAL ;
2012-05-17 04:28:08 +04:00
}
2013-10-17 02:19:00 +04:00
static int hmc5843_set_range_gain ( struct hmc5843_data * data , u8 range )
{
int ret ;
mutex_lock ( & data - > lock ) ;
2014-07-22 19:00:00 +04:00
ret = regmap_update_bits ( data - > regmap , HMC5843_CONFIG_REG_B ,
2015-03-19 22:06:42 +03:00
HMC5843_RANGE_GAIN_MASK ,
range < < HMC5843_RANGE_GAIN_OFFSET ) ;
2013-10-17 02:19:00 +04:00
mutex_unlock ( & data - > lock ) ;
return ret ;
}
2013-10-17 02:19:00 +04:00
static ssize_t hmc5843_show_scale_avail ( struct device * dev ,
2015-03-19 22:06:42 +03:00
struct device_attribute * attr ,
char * buf )
2010-07-17 17:02:52 +04:00
{
2013-10-17 02:19:00 +04:00
struct hmc5843_data * data = iio_priv ( dev_to_iio_dev ( dev ) ) ;
size_t len = 0 ;
int i ;
2010-07-17 17:02:52 +04:00
2014-07-22 19:02:00 +04:00
for ( i = 0 ; i < data - > variant - > n_regval_to_nanoscale ; i + + )
2013-10-17 02:19:00 +04:00
len + = scnprintf ( buf + len , PAGE_SIZE - len ,
" 0.%09d " , data - > variant - > regval_to_nanoscale [ i ] ) ;
/* replace trailing space by newline */
buf [ len - 1 ] = ' \n ' ;
return len ;
2010-07-17 17:02:52 +04:00
}
2013-10-17 02:19:00 +04:00
static IIO_DEVICE_ATTR ( scale_available , S_IRUGO ,
hmc5843_show_scale_avail , NULL , 0 ) ;
2012-05-17 04:28:10 +04:00
2013-10-17 02:19:00 +04:00
static int hmc5843_get_scale_index ( struct hmc5843_data * data , int val , int val2 )
{
int i ;
2010-07-17 17:02:52 +04:00
2015-10-20 22:55:47 +03:00
if ( val )
2013-10-17 02:19:00 +04:00
return - EINVAL ;
2010-07-17 17:02:52 +04:00
2014-07-22 19:02:00 +04:00
for ( i = 0 ; i < data - > variant - > n_regval_to_nanoscale ; i + + )
2013-10-17 02:19:00 +04:00
if ( val2 = = data - > variant - > regval_to_nanoscale [ i ] )
return i ;
2010-07-17 17:02:52 +04:00
2013-10-17 02:19:00 +04:00
return - EINVAL ;
2010-07-17 17:02:52 +04:00
}
2012-05-17 04:28:10 +04:00
2011-08-12 20:47:58 +04:00
static int hmc5843_read_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
2013-09-19 23:35:00 +04:00
int * val , int * val2 , long mask )
2010-07-17 17:02:52 +04:00
{
2011-06-27 16:07:56 +04:00
struct hmc5843_data * data = iio_priv ( indio_dev ) ;
2014-07-28 15:18:00 +04:00
unsigned int rval ;
2014-07-22 19:00:00 +04:00
int ret ;
2011-08-12 20:47:58 +04:00
switch ( mask ) {
2012-04-15 20:41:23 +04:00
case IIO_CHAN_INFO_RAW :
2013-10-17 02:19:00 +04:00
return hmc5843_read_measurement ( data , chan - > scan_index , val ) ;
2011-10-26 20:41:36 +04:00
case IIO_CHAN_INFO_SCALE :
2014-07-22 19:00:00 +04:00
ret = regmap_read ( data - > regmap , HMC5843_CONFIG_REG_B , & rval ) ;
if ( ret < 0 )
return ret ;
rval > > = HMC5843_RANGE_GAIN_OFFSET ;
2011-08-12 20:47:58 +04:00
* val = 0 ;
2014-07-22 19:00:00 +04:00
* val2 = data - > variant - > regval_to_nanoscale [ rval ] ;
2011-08-12 20:47:58 +04:00
return IIO_VAL_INT_PLUS_NANO ;
2013-09-19 23:35:00 +04:00
case IIO_CHAN_INFO_SAMP_FREQ :
2014-07-22 19:00:00 +04:00
ret = regmap_read ( data - > regmap , HMC5843_CONFIG_REG_A , & rval ) ;
if ( ret < 0 )
return ret ;
rval > > = HMC5843_RATE_OFFSET ;
* val = data - > variant - > regval_to_samp_freq [ rval ] [ 0 ] ;
* val2 = data - > variant - > regval_to_samp_freq [ rval ] [ 1 ] ;
2013-09-19 23:35:00 +04:00
return IIO_VAL_INT_PLUS_MICRO ;
2012-09-28 13:57:00 +04:00
}
2011-08-12 20:47:58 +04:00
return - EINVAL ;
2010-07-17 17:02:52 +04:00
}
2011-08-12 20:47:58 +04:00
2013-09-19 23:35:00 +04:00
static int hmc5843_write_raw ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan ,
int val , int val2 , long mask )
{
struct hmc5843_data * data = iio_priv ( indio_dev ) ;
2013-10-17 02:19:00 +04:00
int rate , range ;
2013-09-19 23:35:00 +04:00
switch ( mask ) {
case IIO_CHAN_INFO_SAMP_FREQ :
2013-10-17 02:19:00 +04:00
rate = hmc5843_get_samp_freq_index ( data , val , val2 ) ;
2013-09-19 23:35:00 +04:00
if ( rate < 0 )
return - EINVAL ;
2013-10-17 02:19:00 +04:00
return hmc5843_set_samp_freq ( data , rate ) ;
2013-10-17 02:19:00 +04:00
case IIO_CHAN_INFO_SCALE :
range = hmc5843_get_scale_index ( data , val , val2 ) ;
if ( range < 0 )
return - EINVAL ;
2013-10-17 02:19:00 +04:00
return hmc5843_set_range_gain ( data , range ) ;
2013-10-17 02:19:00 +04:00
default :
return - EINVAL ;
}
}
static int hmc5843_write_raw_get_fmt ( struct iio_dev * indio_dev ,
2015-03-19 22:06:42 +03:00
struct iio_chan_spec const * chan ,
long mask )
2013-10-17 02:19:00 +04:00
{
switch ( mask ) {
case IIO_CHAN_INFO_SAMP_FREQ :
return IIO_VAL_INT_PLUS_MICRO ;
case IIO_CHAN_INFO_SCALE :
return IIO_VAL_INT_PLUS_NANO ;
2013-09-19 23:35:00 +04:00
default :
return - EINVAL ;
}
}
2013-10-17 02:19:00 +04:00
static irqreturn_t hmc5843_trigger_handler ( int irq , void * p )
{
struct iio_poll_func * pf = p ;
struct iio_dev * indio_dev = pf - > indio_dev ;
struct hmc5843_data * data = iio_priv ( indio_dev ) ;
int ret ;
mutex_lock ( & data - > lock ) ;
ret = hmc5843_wait_measurement ( data ) ;
if ( ret < 0 ) {
mutex_unlock ( & data - > lock ) ;
goto done ;
}
2014-07-22 19:00:00 +04:00
ret = regmap_bulk_read ( data - > regmap , HMC5843_DATA_OUT_MSB_REGS ,
2015-03-19 22:06:42 +03:00
data - > buffer , 3 * sizeof ( __be16 ) ) ;
2014-07-22 19:00:00 +04:00
2013-10-17 02:19:00 +04:00
mutex_unlock ( & data - > lock ) ;
if ( ret < 0 )
goto done ;
iio_push_to_buffers_with_timestamp ( indio_dev , data - > buffer ,
2016-03-09 21:05:49 +03:00
iio_get_time_ns ( indio_dev ) ) ;
2013-10-17 02:19:00 +04:00
done :
iio_trigger_notify_done ( indio_dev - > trig ) ;
return IRQ_HANDLED ;
}
2013-10-17 02:19:00 +04:00
# define HMC5843_CHANNEL(axis, idx) \
2011-08-12 20:47:58 +04:00
{ \
. type = IIO_MAGN , \
. modified = 1 , \
. channel2 = IIO_MOD_ # # axis , \
2013-02-27 23:40:58 +04:00
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) , \
2013-09-19 23:35:00 +04:00
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SCALE ) | \
BIT ( IIO_CHAN_INFO_SAMP_FREQ ) , \
2013-10-17 02:19:00 +04:00
. scan_index = idx , \
2013-12-11 22:45:00 +04:00
. scan_type = { \
. sign = ' s ' , \
. realbits = 16 , \
. storagebits = 16 , \
. endianness = IIO_BE , \
} , \
2016-02-15 01:37:37 +03:00
. ext_info = hmc5843_ext_info , \
}
# define HMC5983_CHANNEL(axis, idx) \
{ \
. type = IIO_MAGN , \
. modified = 1 , \
. channel2 = IIO_MOD_ # # axis , \
. info_mask_separate = BIT ( IIO_CHAN_INFO_RAW ) , \
. info_mask_shared_by_type = BIT ( IIO_CHAN_INFO_SCALE ) | \
BIT ( IIO_CHAN_INFO_SAMP_FREQ ) , \
. scan_index = idx , \
. scan_type = { \
. sign = ' s ' , \
. realbits = 16 , \
. storagebits = 16 , \
. endianness = IIO_BE , \
} , \
. ext_info = hmc5983_ext_info , \
2011-08-12 20:47:58 +04:00
}
static const struct iio_chan_spec hmc5843_channels [ ] = {
2013-10-17 02:19:00 +04:00
HMC5843_CHANNEL ( X , 0 ) ,
HMC5843_CHANNEL ( Y , 1 ) ,
HMC5843_CHANNEL ( Z , 2 ) ,
2013-10-17 02:19:00 +04:00
IIO_CHAN_SOFT_TIMESTAMP ( 3 ) ,
2011-08-12 20:47:58 +04:00
} ;
2010-07-17 17:02:52 +04:00
2014-07-22 19:02:00 +04:00
/* Beware: Y and Z are exchanged on HMC5883 and 5983 */
2012-05-17 04:28:13 +04:00
static const struct iio_chan_spec hmc5883_channels [ ] = {
2013-10-17 02:19:00 +04:00
HMC5843_CHANNEL ( X , 0 ) ,
HMC5843_CHANNEL ( Z , 1 ) ,
HMC5843_CHANNEL ( Y , 2 ) ,
2013-10-17 02:19:00 +04:00
IIO_CHAN_SOFT_TIMESTAMP ( 3 ) ,
2012-05-17 04:28:13 +04:00
} ;
2016-02-15 01:37:37 +03:00
static const struct iio_chan_spec hmc5983_channels [ ] = {
HMC5983_CHANNEL ( X , 0 ) ,
HMC5983_CHANNEL ( Z , 1 ) ,
HMC5983_CHANNEL ( Y , 2 ) ,
IIO_CHAN_SOFT_TIMESTAMP ( 3 ) ,
} ;
2010-07-17 17:02:52 +04:00
static struct attribute * hmc5843_attributes [ ] = {
2013-10-17 02:19:00 +04:00
& iio_dev_attr_scale_available . dev_attr . attr ,
2012-05-17 04:28:13 +04:00
& iio_dev_attr_sampling_frequency_available . dev_attr . attr ,
2010-07-17 17:02:52 +04:00
NULL
} ;
static const struct attribute_group hmc5843_group = {
. attrs = hmc5843_attributes ,
} ;
2012-05-17 04:28:13 +04:00
static const struct hmc5843_chip_info hmc5843_chip_info_tbl [ ] = {
[ HMC5843_ID ] = {
. channels = hmc5843_channels ,
2013-09-19 23:35:00 +04:00
. regval_to_samp_freq = hmc5843_regval_to_samp_freq ,
2014-07-22 19:02:00 +04:00
. n_regval_to_samp_freq =
ARRAY_SIZE ( hmc5843_regval_to_samp_freq ) ,
2012-05-17 04:28:13 +04:00
. regval_to_nanoscale = hmc5843_regval_to_nanoscale ,
2014-07-22 19:02:00 +04:00
. n_regval_to_nanoscale =
ARRAY_SIZE ( hmc5843_regval_to_nanoscale ) ,
2012-05-17 04:28:13 +04:00
} ,
[ HMC5883_ID ] = {
. channels = hmc5883_channels ,
2013-09-19 23:35:00 +04:00
. regval_to_samp_freq = hmc5883_regval_to_samp_freq ,
2014-07-22 19:02:00 +04:00
. n_regval_to_samp_freq =
ARRAY_SIZE ( hmc5883_regval_to_samp_freq ) ,
2012-05-17 04:28:13 +04:00
. regval_to_nanoscale = hmc5883_regval_to_nanoscale ,
2014-07-22 19:02:00 +04:00
. n_regval_to_nanoscale =
ARRAY_SIZE ( hmc5883_regval_to_nanoscale ) ,
2012-05-17 04:28:13 +04:00
} ,
[ HMC5883L_ID ] = {
. channels = hmc5883_channels ,
2013-09-19 23:35:00 +04:00
. regval_to_samp_freq = hmc5883_regval_to_samp_freq ,
2014-07-22 19:02:00 +04:00
. n_regval_to_samp_freq =
ARRAY_SIZE ( hmc5883_regval_to_samp_freq ) ,
2012-05-17 04:28:13 +04:00
. regval_to_nanoscale = hmc5883l_regval_to_nanoscale ,
2014-07-22 19:02:00 +04:00
. n_regval_to_nanoscale =
ARRAY_SIZE ( hmc5883l_regval_to_nanoscale ) ,
2012-05-17 04:28:13 +04:00
} ,
2014-07-22 19:02:00 +04:00
[ HMC5983_ID ] = {
2016-02-15 01:37:37 +03:00
. channels = hmc5983_channels ,
2014-07-22 19:02:00 +04:00
. regval_to_samp_freq = hmc5983_regval_to_samp_freq ,
. n_regval_to_samp_freq =
ARRAY_SIZE ( hmc5983_regval_to_samp_freq ) ,
. regval_to_nanoscale = hmc5883l_regval_to_nanoscale ,
. n_regval_to_nanoscale =
ARRAY_SIZE ( hmc5883l_regval_to_nanoscale ) ,
}
2012-05-17 04:28:13 +04:00
} ;
2013-10-17 02:19:00 +04:00
static int hmc5843_init ( struct hmc5843_data * data )
2010-07-17 17:02:52 +04:00
{
2013-10-17 02:19:00 +04:00
int ret ;
u8 id [ 3 ] ;
2014-07-22 19:00:00 +04:00
ret = regmap_bulk_read ( data - > regmap , HMC5843_ID_REG ,
2015-03-19 22:06:42 +03:00
id , ARRAY_SIZE ( id ) ) ;
2013-10-17 02:19:00 +04:00
if ( ret < 0 )
return ret ;
if ( id [ 0 ] ! = ' H ' | | id [ 1 ] ! = ' 4 ' | | id [ 2 ] ! = ' 3 ' ) {
2014-07-22 19:02:00 +04:00
dev_err ( data - > dev , " no HMC5843/5883/5883L/5983 sensor \n " ) ;
2013-10-17 02:19:00 +04:00
return - ENODEV ;
}
ret = hmc5843_set_meas_conf ( data , HMC5843_MEAS_CONF_NORMAL ) ;
if ( ret < 0 )
return ret ;
ret = hmc5843_set_samp_freq ( data , HMC5843_RATE_DEFAULT ) ;
if ( ret < 0 )
return ret ;
ret = hmc5843_set_range_gain ( data , HMC5843_RANGE_GAIN_DEFAULT ) ;
if ( ret < 0 )
return ret ;
return hmc5843_set_mode ( data , HMC5843_MODE_CONVERSION_CONTINUOUS ) ;
2010-07-17 17:02:52 +04:00
}
2011-05-18 17:42:37 +04:00
static const struct iio_info hmc5843_info = {
. attrs = & hmc5843_group ,
2016-02-15 01:37:39 +03:00
. read_raw = & hmc5843_read_raw ,
. write_raw = & hmc5843_write_raw ,
. write_raw_get_fmt = & hmc5843_write_raw_get_fmt ,
2011-05-18 17:42:37 +04:00
. driver_module = THIS_MODULE ,
} ;
2013-10-17 02:19:00 +04:00
static const unsigned long hmc5843_scan_masks [ ] = { 0x7 , 0 } ;
2014-07-22 19:01:00 +04:00
int hmc5843_common_suspend ( struct device * dev )
{
return hmc5843_set_mode ( iio_priv ( dev_get_drvdata ( dev ) ) ,
2016-02-08 01:21:48 +03:00
HMC5843_MODE_SLEEP ) ;
2014-07-22 19:01:00 +04:00
}
EXPORT_SYMBOL ( hmc5843_common_suspend ) ;
2014-07-22 19:00:00 +04:00
2014-07-22 19:01:00 +04:00
int hmc5843_common_resume ( struct device * dev )
{
return hmc5843_set_mode ( iio_priv ( dev_get_drvdata ( dev ) ) ,
2016-02-08 01:21:48 +03:00
HMC5843_MODE_CONVERSION_CONTINUOUS ) ;
2014-07-22 19:01:00 +04:00
}
EXPORT_SYMBOL ( hmc5843_common_resume ) ;
2014-07-22 19:00:00 +04:00
2014-07-22 19:01:00 +04:00
int hmc5843_common_probe ( struct device * dev , struct regmap * regmap ,
2015-08-12 16:25:46 +03:00
enum hmc5843_ids id , const char * name )
2010-07-17 17:02:52 +04:00
{
struct hmc5843_data * data ;
2011-06-27 16:07:56 +04:00
struct iio_dev * indio_dev ;
2013-10-17 02:19:00 +04:00
int ret ;
2010-07-17 17:02:52 +04:00
2014-07-22 19:01:00 +04:00
indio_dev = devm_iio_device_alloc ( dev , sizeof ( * data ) ) ;
2015-03-19 22:04:42 +03:00
if ( ! indio_dev )
2013-09-03 05:05:00 +04:00
return - ENOMEM ;
2010-07-17 17:02:52 +04:00
2014-07-22 19:01:00 +04:00
dev_set_drvdata ( dev , indio_dev ) ;
2012-05-16 20:22:05 +04:00
/* default settings at probe */
data = iio_priv ( indio_dev ) ;
2014-07-22 19:01:00 +04:00
data - > dev = dev ;
data - > regmap = regmap ;
data - > variant = & hmc5843_chip_info_tbl [ id ] ;
2013-09-19 23:35:00 +04:00
mutex_init ( & data - > lock ) ;
2010-07-17 17:02:52 +04:00
2014-07-22 19:01:00 +04:00
indio_dev - > dev . parent = dev ;
2015-08-12 16:25:46 +03:00
indio_dev - > name = name ;
2011-06-27 16:07:56 +04:00
indio_dev - > info = & hmc5843_info ;
indio_dev - > modes = INDIO_DIRECT_MODE ;
2013-09-19 23:35:00 +04:00
indio_dev - > channels = data - > variant - > channels ;
2013-10-17 02:19:00 +04:00
indio_dev - > num_channels = 4 ;
indio_dev - > available_scan_masks = hmc5843_scan_masks ;
2013-09-19 23:35:00 +04:00
2013-10-17 02:19:00 +04:00
ret = hmc5843_init ( data ) ;
if ( ret < 0 )
return ret ;
2012-05-17 04:28:10 +04:00
2013-10-17 02:19:00 +04:00
ret = iio_triggered_buffer_setup ( indio_dev , NULL ,
2015-03-19 22:06:42 +03:00
hmc5843_trigger_handler , NULL ) ;
2013-10-17 02:19:00 +04:00
if ( ret < 0 )
2015-03-22 21:42:42 +03:00
goto buffer_setup_err ;
2013-10-17 02:19:00 +04:00
ret = iio_device_register ( indio_dev ) ;
if ( ret < 0 )
goto buffer_cleanup ;
2012-05-17 04:28:10 +04:00
2010-07-17 17:02:52 +04:00
return 0 ;
2013-10-17 02:19:00 +04:00
buffer_cleanup :
iio_triggered_buffer_cleanup ( indio_dev ) ;
2015-03-22 21:42:42 +03:00
buffer_setup_err :
hmc5843_set_mode ( iio_priv ( indio_dev ) , HMC5843_MODE_SLEEP ) ;
2013-10-17 02:19:00 +04:00
return ret ;
2010-07-17 17:02:52 +04:00
}
2014-07-22 19:01:00 +04:00
EXPORT_SYMBOL ( hmc5843_common_probe ) ;
2010-07-17 17:02:52 +04:00
2014-07-22 19:01:00 +04:00
int hmc5843_common_remove ( struct device * dev )
2010-07-17 17:02:52 +04:00
{
2014-07-22 19:01:00 +04:00
struct iio_dev * indio_dev = dev_get_drvdata ( dev ) ;
2013-10-17 02:19:00 +04:00
iio_device_unregister ( indio_dev ) ;
iio_triggered_buffer_cleanup ( indio_dev ) ;
2013-10-17 02:19:00 +04:00
/* sleep mode to save power */
2013-10-17 02:19:00 +04:00
hmc5843_set_mode ( iio_priv ( indio_dev ) , HMC5843_MODE_SLEEP ) ;
2011-06-27 16:07:56 +04:00
2010-07-17 17:02:52 +04:00
return 0 ;
}
2014-07-22 19:01:00 +04:00
EXPORT_SYMBOL ( hmc5843_common_remove ) ;
2010-07-17 17:02:52 +04:00
2013-09-05 13:29:00 +04:00
MODULE_AUTHOR ( " Shubhrajyoti Datta <shubhrajyoti@ti.com> " ) ;
2014-07-22 19:02:00 +04:00
MODULE_DESCRIPTION ( " HMC5843/5883/5883L/5983 core driver " ) ;
2010-07-17 17:02:52 +04:00
MODULE_LICENSE ( " GPL " ) ;