2019-05-27 09:55:15 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2010-08-10 04:21:05 +04:00
/*
* hmc6352 . c - Honeywell Compass Driver
*
* Copyright ( C ) 2009 Intel Corp
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/i2c.h>
# include <linux/err.h>
# include <linux/delay.h>
# include <linux/sysfs.h>
2018-08-15 18:50:41 +03:00
# include <linux/nospec.h>
2010-08-10 04:21:05 +04:00
static DEFINE_MUTEX ( compass_mutex ) ;
static int compass_command ( struct i2c_client * c , u8 cmd )
{
int ret = i2c_master_send ( c , & cmd , 1 ) ;
if ( ret < 0 )
dev_warn ( & c - > dev , " command '%c' failed. \n " , cmd ) ;
return ret ;
}
static int compass_store ( struct device * dev , const char * buf , size_t count ,
const char * map )
{
struct i2c_client * c = to_i2c_client ( dev ) ;
int ret ;
unsigned long val ;
2013-06-04 08:15:16 +04:00
ret = kstrtoul ( buf , 10 , & val ) ;
if ( ret )
return ret ;
2010-08-10 04:21:05 +04:00
if ( val > = strlen ( map ) )
return - EINVAL ;
2018-08-15 18:50:41 +03:00
val = array_index_nospec ( val , strlen ( map ) ) ;
2010-08-10 04:21:05 +04:00
mutex_lock ( & compass_mutex ) ;
ret = compass_command ( c , map [ val ] ) ;
mutex_unlock ( & compass_mutex ) ;
if ( ret < 0 )
return ret ;
return count ;
}
static ssize_t compass_calibration_store ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t count )
{
return compass_store ( dev , buf , count , " EC " ) ;
}
static ssize_t compass_power_mode_store ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t count )
{
return compass_store ( dev , buf , count , " SW " ) ;
}
static ssize_t compass_heading_data_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct i2c_client * client = to_i2c_client ( dev ) ;
unsigned char i2c_data [ 2 ] ;
2011-03-23 02:34:00 +03:00
int ret ;
2010-08-10 04:21:05 +04:00
mutex_lock ( & compass_mutex ) ;
ret = compass_command ( client , ' A ' ) ;
if ( ret ! = 1 ) {
mutex_unlock ( & compass_mutex ) ;
return ret ;
}
msleep ( 10 ) ; /* sending 'A' cmd we need to wait for 7-10 millisecs */
ret = i2c_master_recv ( client , i2c_data , 2 ) ;
mutex_unlock ( & compass_mutex ) ;
2011-03-23 02:34:00 +03:00
if ( ret < 0 ) {
2010-08-10 04:21:05 +04:00
dev_warn ( dev , " i2c read data cmd failed \n " ) ;
return ret ;
}
ret = ( i2c_data [ 0 ] < < 8 ) | i2c_data [ 1 ] ;
return sprintf ( buf , " %d.%d \n " , ret / 10 , ret % 10 ) ;
}
static DEVICE_ATTR ( heading0_input , S_IRUGO , compass_heading_data_show , NULL ) ;
static DEVICE_ATTR ( calibration , S_IWUSR , NULL , compass_calibration_store ) ;
static DEVICE_ATTR ( power_state , S_IWUSR , NULL , compass_power_mode_store ) ;
static struct attribute * mid_att_compass [ ] = {
& dev_attr_heading0_input . attr ,
& dev_attr_calibration . attr ,
& dev_attr_power_state . attr ,
NULL
} ;
static const struct attribute_group m_compass_gr = {
. name = " hmc6352 " ,
. attrs = mid_att_compass
} ;
static int hmc6352_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
int res ;
res = sysfs_create_group ( & client - > dev . kobj , & m_compass_gr ) ;
if ( res ) {
dev_err ( & client - > dev , " device_create_file failed \n " ) ;
return res ;
}
dev_info ( & client - > dev , " %s HMC6352 compass chip found \n " ,
client - > name ) ;
return 0 ;
}
static int hmc6352_remove ( struct i2c_client * client )
{
sysfs_remove_group ( & client - > dev . kobj , & m_compass_gr ) ;
return 0 ;
}
2017-08-21 19:43:26 +03:00
static const struct i2c_device_id hmc6352_id [ ] = {
2010-08-10 04:21:05 +04:00
{ " hmc6352 " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , hmc6352_id ) ;
static struct i2c_driver hmc6352_driver = {
. driver = {
. name = " hmc6352 " ,
} ,
. probe = hmc6352_probe ,
. remove = hmc6352_remove ,
. id_table = hmc6352_id ,
} ;
2012-01-22 11:36:45 +04:00
module_i2c_driver ( hmc6352_driver ) ;
2010-08-10 04:21:05 +04:00
MODULE_AUTHOR ( " Kalhan Trisal <kalhan.trisal@intel.com " ) ;
MODULE_DESCRIPTION ( " hmc6352 Compass Driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;