SENSOR------驱动简介:
2017-06-05 18:38
141 查看
SENSOR------驱动简介:
sensor在KERNEL层就是各个sensor的驱动代码的具体实现,而驱动的任务,就是通过总线与硬件设备进行通信,控制硬件进去各种工作状态,获取器件相关寄存器的值,从而得到设备的状态。下面以MT6753 6.0的MSENSOR:AKM09911具体介绍下。
alps\kernel-3.18\drivers\misc\mediatek\magnetometer\akm09911-new
......
static struct i2c_driverakm09911_i2c_driver = {
.driver= {
.name = AKM09911_DEV_NAME,
#ifdef CONFIG_OF
.of_match_table= mag_of_match,
#endif
},
.probe = akm09911_i2c_probe,
.remove = akm09911_i2c_remove,
.detect = akm09911_i2c_detect,
.suspend = akm09911_suspend,
.resume = akm09911_resume,
.id_table= akm09911_i2c_id,
};
/*----------------------------------------------------------------------------*/
static atomic_t dev_open_count;
/*----------------------------------------------------------------------------*/
/*
重力感应器的I2C通信接口。调试前,需要先确保供电正常,再就是I2C的通信正常。这个就是驱动工程师做的最多的事情,因为这个供电是开机一直供电的,所以没有供电的问题。只需要确认下就好了。重点还是看LOG,看看该设备的I2C是是否正常。如果不正常,需要检查I2C的地址,硬件的连接。或者打电话给FAE了。
*/
static DEFINE_MUTEX(akm09911_i2c_mutex);
#ifndef CONFIG_MTK_I2C_EXTENSION
static int mag_i2c_read_block(structi2c_client *client, u8 addr, u8 *data, u8 len)
{
interr = 0;
u8beg = addr;
structi2c_msg msgs[2] = { {0}, {0} };
mutex_lock(&akm09911_i2c_mutex);
msgs[0].addr= client->addr;
msgs[0].flags= 0;
msgs[0].len= 1;
msgs[0].buf= &beg;
msgs[1].addr= client->addr;
msgs[1].flags= I2C_M_RD;
msgs[1].len= len;
msgs[1].buf= data;
if(!client) {
mutex_unlock(&akm09911_i2c_mutex);
return-EINVAL;
}else if (len > C_I2C_FIFO_SIZE) {
mutex_unlock(&akm09911_i2c_mutex);
MAGN_ERR("length %d exceeds %d\n", len, C_I2C_FIFO_SIZE);
return-EINVAL;
}
err= i2c_transfer(client->adapter, msgs, sizeof(msgs) / sizeof(msgs[0]));
if(err != 2) {
MAGN_ERR("i2c_transfererror: (%d %p %d) %d\n", addr, data, len, err);
err= -EIO;
}else {
err= 0;
}
mutex_unlock(&akm09911_i2c_mutex);
returnerr;
}
static int mag_i2c_write_block(structi2c_client *client, u8 addr, u8 *data, u8 len)
{ /*becauseaddress also occupies one byte, the maximum length for write is 7 bytes */
interr = 0, idx = 0, num = 0;
charbuf[C_I2C_FIFO_SIZE];
err= 0;
mutex_lock(&akm09911_i2c_mutex);
if(!client) {
mutex_unlock(&akm09911_i2c_mutex);
return-EINVAL;
}else if (len >= C_I2C_FIFO_SIZE) {
mutex_unlock(&akm09911_i2c_mutex);
MAGN_ERR("length %d exceeds %d\n", len, C_I2C_FIFO_SIZE);
return-EINVAL;
}
num= 0;
buf[num++]= addr;
for(idx = 0; idx < len; idx++)
buf[num++]= data[idx];
err= i2c_master_send(client, buf, num);
if(err < 0) {
mutex_unlock(&akm09911_i2c_mutex);
MAGN_ERR("sendcommand error!!\n");
return-EFAULT;
}
mutex_unlock(&akm09911_i2c_mutex);
returnerr;
}
#endif
static void akm09911_power(struct mag_hw*hw, unsigned int on)
{
}
/*其他的一些驱动函数不太关心,悄悄的滤过,具体要有问题可以看看DATASHEET,一般用到比较少。厂家给过来的一般都是有验证过的。
*/
static long AKECS_SetMode_SngMeasure(void)
{
charbuffer[2];
#ifdefAKM_Device_AK8963
buffer[0]= AK8963_REG_CNTL1;
buffer[1]= AK8963_MODE_SNG_MEASURE;
#else
/*Set measure mode */
buffer[0]= AK09911_REG_CNTL2;
buffer[1]= AK09911_MODE_SNG_MEASURE;
#endif
/*Set data */
returnAKI2C_TxData(buffer, 2);
}
static long AKECS_SetMode_SelfTest(void)
{
charbuffer[2];
#ifdefAKM_Device_AK8963
buffer[0]= AK8963_REG_CNTL1;
buffer[1]= AK8963_MODE_SELF_TEST;
#else
/*Set measure mode */
buffer[0]= AK09911_REG_CNTL2;
buffer[1]= AK09911_MODE_SELF_TEST;
/*Set data */
#endif
returnAKI2C_TxData(buffer, 2);
}
/*
读取器件数据,不管上层如何转了转去,获取数据的时候,都是会调用到这个接口来获取芯片的寄存器数据。调试的时候可以把MAGN_LOG
打开调试。看看从芯片读取到的数据是否正常,芯片是否工作正常。
*/
/* M-sensor daemon application have set thesng mode */
static long AKECS_GetData(char *rbuf, intsize)
{
chartemp;
intloop_i, ret;
#if DEBUG
structi2c_client *client = this_client;
structakm09911_i2c_data *data = i2c_get_clientdata(client);
#endif
if(size < SENSOR_DATA_SIZE) {
MAG_ERR("buffsize is too small %d!\n", size);
return-1;
}
memset(rbuf,0, SENSOR_DATA_SIZE);
#ifdefAKM_Device_AK8963
rbuf[0]= AK8963_REG_ST1;
#else
rbuf[0]= AK09911_REG_ST1;
#endif
for(loop_i = 0; loop_i < AKM09911_RETRY_COUNT; loop_i++) {
ret= AKI2C_RxData(rbuf, 1);
if(ret) {
MAG_ERR("readST1 resigster failed!\n");
return-1;
}
if((rbuf[0] & 0x01) == 0x01)
break;
mdelay(2);
#ifdefAKM_Device_AK8963
rbuf[0]= AK8963_REG_ST1;
#else
rbuf[0]= AK09911_REG_ST1;
#endif
}
if(loop_i >= AKM09911_RETRY_COUNT) {
MAG_ERR("Dataread retry larger the max count!\n");
if(0 == factory_mode)
/*if return we can not get data at factory mode */
return-1;
}
temp= rbuf[0];
#ifdefAKM_Device_AK8963
rbuf[1]= AK8963_REG_HXL;
ret= AKI2C_RxData(&rbuf[1], SENSOR_DATA_SIZE - 2);
#elifdefined(AKM_Device_AK09916)
rbuf[1]=AK09911_REG_HXL;
ret= AKI2C_RxData(&rbuf[1], SENSOR_DATA_SIZE -2);
#else
rbuf[1]= AK09911_REG_HXL;
ret= AKI2C_RxData(&rbuf[1], SENSOR_DATA_SIZE - 1);
#endif
if(ret < 0) {
MAG_ERR("AKM8975akm8975_work_func: I2C failed\n");
return-1;
}
rbuf[0]= temp;
#ifdefAKM_Device_AK8963
rbuf[8]= rbuf[7];
rbuf[7]= 0;
#endif
#ifdefAKM_Device_AK09916
rbuf[9]= 1;
#endif
mutex_lock(&sense_data_mutex);
memcpy(sense_data,rbuf, sizeof(sense_data));
mutex_unlock(&sense_data_mutex);
MAGN_LOG("Getdevice data: %d, %d, %d, %d , %d, %d, %d, %d!\n",
sense_data[0],sense_data[1], sense_data[2], sense_data[3],
sense_data[4],sense_data[5], sense_data[6], sense_data[7]);
#if DEBUG
if(atomic_read(&data->trace) & AMK_DATA_DEBUG) {
MAGN_LOG("Getdevice data: %d, %d, %d, %d , %d, %d, %d, %d!\n",
sense_data[0],sense_data[1], sense_data[2], sense_data[3],
sense_data[4],sense_data[5], sense_data[6], sense_data[7]);
}
#endif
return0;
}
。。。。。。
/*
设备的节点建立在/sys/bus/platform/drivers/msensor的下面。可以直接用ADB来获取数据,方便调试。
*/
/*----------------------------------------------------------------------------*/
static struct driver_attribute*akm09911_attr_list[] = {
&driver_attr_daemon,
&driver_attr_shipmenttest,
&driver_attr_chipinfo,
&driver_attr_sensordata,
&driver_attr_posturedata,
&driver_attr_layout,
&driver_attr_status,
&driver_attr_trace,
&driver_attr_orientation,
&driver_attr_power,
&driver_attr_regmap,
};
/*----------------------------------------------------------------------------*/
static int akm09911_create_attr(structdevice_driver *driver)
{
intidx, err = 0;
intnum = (int)(sizeof(akm09911_attr_list)/sizeof(akm09911_attr_list[0]));
if(driver == NULL)
return-EINVAL;
for(idx = 0; idx < num; idx++) {
err= driver_create_file(driver, akm09911_attr_list[idx]);
if(err) {
MAG_ERR("driver_create_file(%s) = %d\n", akm09911_attr_list[idx]->attr.name, err);
break;
}
}
returnerr;
}
......
/*
IOCTL的接口,工厂模式有用到,正常模式应该是不需要的。可以绕开android
的系统SENSOR架构,直接用IOCTL来获取驱动的接口。
*/
/*----------------------------------------------------------------------------*/
/* static int akm09911_ioctl(struct inode*inode, struct file *file, unsigned int cmd,unsigned long arg) */
static long akm09911_unlocked_ioctl(structfile *file, unsigned int cmd, unsigned long arg)
{
void__user *argp = (void __user *)arg;
/*NOTE: In this function the size of "char" should be 1-byte. */
charsData[SENSOR_DATA_SIZE];/* for GETDATA */
charrwbuf[RWBUF_SIZE]; /* for READ/WRITE*/
charbuff[AKM09911_BUFSIZE]; /*for chip information */
charmode; /* forSET_MODE*/
intvalue[26]; /* for SET_YPR */
int64_tdelay[3]; /* for GET_DELAY*/
intstatus; /* forOPEN/CLOSE_STATUS */
longret = -1; /* Return value. */
intlayout;
structi2c_client *client = this_client;
structakm09911_i2c_data *data = i2c_get_clientdata(client);
structhwm_sensor_data *osensor_data;
uint32_tenable;
/*These two buffers are initialized at start up.
Afterthat, the value is not changed */
unsignedchar sense_info[AKM_SENSOR_INFO_SIZE];
unsignedchar sense_conf[AKM_SENSOR_CONF_SIZE];
/*MAG_ERR("akm09911 cmd:0x%x\n", cmd); */
switch(cmd) {
caseECS_IOCTL_WRITE:
/*AKMFUNC("ECS_IOCTL_WRITE"); */
if(argp == NULL) {
MAGN_LOG("invalidargument.");
return-EINVAL;
}
if(copy_from_user(rwbuf, argp, sizeof(rwbuf))) {
MAGN_LOG("copy_from_userfailed.");
return-EFAULT;
}
if((rwbuf[0] < 2) || (rwbuf[0] > (RWBUF_SIZE-1))) {
MAGN_LOG("invalidargument.");
return-EINVAL;
}
ret= AKI2C_TxData(&rwbuf[1], rwbuf[0]);
if(ret < 0)
returnret;
break;
caseECS_IOCTL_RESET:
ret= AKECS_Reset(0); /* sw: 0, hw: 1 */
if(ret < 0)
returnret;
break;
caseECS_IOCTL_READ:
if(argp == NULL) {
MAGN_LOG("invalidargument.");
return-EINVAL;
}
if(copy_from_user(rwbuf, argp, sizeof(rwbuf))) {
MAGN_LOG("copy_from_userfailed.");
return-EFAULT;
}
if((rwbuf[0] < 1) || (rwbuf[0] > (RWBUF_SIZE-1))) {
MAGN_LOG("invalidargument.");
return-EINVAL;
}
ret= AKI2C_RxData(&rwbuf[1], rwbuf[0]);
if(ret < 0)
returnret;
if(copy_to_user(argp, rwbuf, rwbuf[0]+1)) {
MAGN_LOG("copy_to_userfailed.");
return-EFAULT;
}
break;
caseECS_IOCTL_GET_INFO:
#ifdefAKM_Device_AK8963
sense_info[0]= AK8963_REG_WIA;
#else
sense_info[0]= AK09911_REG_WIA1;
#endif
ret= AKI2C_RxData(sense_info, AKM_SENSOR_INFO_SIZE);
if(ret < 0)
{
returnret;
}
if(copy_to_user(argp,sense_info, AKM_SENSOR_INFO_SIZE))
{
MAGN_LOG("copy_to_userfailed.");
return-EFAULT;
}
break;
caseECS_IOCTL_GET_CONF:
/*Set FUSE access mode */
#ifdefAKM_Device_AK8963
ret= AKECS_SetMode(AK8963_MODE_FUSE_ACCESS);
#else
ret= AKECS_SetMode(AK09911_MODE_FUSE_ACCESS);
#endif
if(ret < 0)
return ret;
#ifdefAKM_Device_AK8963
sense_conf[0]= AK8963_FUSE_ASAX;
#else
sense_conf[0]= AK09911_FUSE_ASAX;
#endif
#ifdefAKM_Device_AK09916
sense_conf[0]= AK09916_ASA;
sense_conf[1]= AK09916_ASA;
sense_conf[2]= AK09916_ASA;
#else
ret= AKI2C_RxData(sense_conf, AKM_SENSOR_CONF_SIZE);
#endif
if(ret < 0)
{
returnret;
}
if(copy_to_user(argp,sense_conf, AKM_SENSOR_CONF_SIZE))
{
MAGN_LOG("copy_to_userfailed.");
return-EFAULT;
}
#ifdefAKM_Device_AK8963
ret= AKECS_SetMode(AK8963_MODE_POWERDOWN);
#else
ret= AKECS_SetMode(AK09911_MODE_POWERDOWN);
#endif
if(ret < 0)
returnret;
break;
caseECS_IOCTL_SET_MODE:
/*AKMFUNC("ECS_IOCTL_SET_MODE"); */
if(argp == NULL) {
MAGN_LOG("invalidargument.");
return-EINVAL;
}
if(copy_from_user(&mode, argp, sizeof(mode))) {
MAGN_LOG("copy_from_userfailed.");
return-EFAULT;
}
ret= AKECS_SetMode(mode); /* MATCH commandfrom AKMD PART */
if(ret < 0)
returnret;
break;
caseECS_IOCTL_GETDATA:
/*AKMFUNC("ECS_IOCTL_GETDATA"); */
ret= AKECS_GetData(sData, SENSOR_DATA_SIZE);
if(ret < 0)
returnret;
if(copy_to_user(argp, sData, sizeof(sData))) {
MAGN_LOG("copy_to_userfailed.");
return-EFAULT;
}
break;
caseECS_IOCTL_SET_YPR_09911:
/*AKMFUNC("ECS_IOCTL_SET_YPR"); */
if(argp == NULL) {
MAGN_LOG("invalidargument.");
return-EINVAL;
}
if(copy_from_user(value, argp, sizeof(value))) {
MAGN_LOG("copy_from_userfailed.");
return-EFAULT;
}
AKECS_SaveData(value);
break;
caseECS_IOCTL_GET_OPEN_STATUS:
/*AKMFUNC("IOCTL_GET_OPEN_STATUS"); */
status= AKECS_GetOpenStatus();
/*MAGN_LOG("AKECS_GetOpenStatus returned (%d)", status); */
if(copy_to_user(argp, &status, sizeof(status))) {
MAGN_LOG("copy_to_userfailed.");
return-EFAULT;
}
break;
caseECS_IOCTL_GET_CLOSE_STATUS:
/*AKMFUNC("IOCTL_GET_CLOSE_STATUS"); */
status= AKECS_GetCloseStatus();
/*MAGN_LOG("AKECS_GetCloseStatus returned (%d)", status); */
if(copy_to_user(argp, &status, sizeof(status))) {
MAGN_LOG("copy_to_userfailed.");
return-EFAULT;
}
break;
caseECS_IOCTL_GET_OSENSOR_STATUS:
/*AKMFUNC("ECS_IOCTL_GET_OSENSOR_STATUS"); */
status= atomic_read(&o_flag);
if(copy_to_user(argp, &status, sizeof(status))) {
MAGN_LOG("copy_to_userfailed.");
return-EFAULT;
}
break;
caseECS_IOCTL_GET_DELAY_09911:
/*AKMFUNC("IOCTL_GET_DELAY"); */
delay[0]= (int)akmd_delay * 1000000;
delay[1]= (int)akmd_delay * 1000000;
delay[2]= (int)akmd_delay * 1000000;
if(copy_to_user(argp, delay, sizeof(delay))) {
MAGN_LOG("copy_to_userfailed.");
return-EFAULT;
}
break;
caseECS_IOCTL_GET_LAYOUT_09911:
layout= atomic_read(&data->layout);
MAG_ERR("layout=%d\r\n",layout);
if(copy_to_user(argp, &layout, sizeof(char))) {
MAGN_LOG("copy_to_userfailed.");
return-EFAULT;
}
break;
caseMSENSOR_IOCTL_READ_CHIPINFO:
if(argp == NULL) {
MAG_ERR("IOparameter pointer is NULL!\r\n");
break;
}
akm09911_ReadChipInfo(buff,AKM09911_BUFSIZE);
if(copy_to_user(argp, buff, strlen(buff)+1))
return-EFAULT;
break;
caseMSENSOR_IOCTL_READ_SENSORDATA:
if(argp == NULL) {
MAG_ERR("IOparameter pointer is NULL!\r\n");
break;
}
AKECS_GetRawData(buff,AKM09911_BUFSIZE);
if(copy_to_user(argp, buff, strlen(buff)+1))
return-EFAULT;
break;
caseMSENSOR_IOCTL_SENSOR_ENABLE:
if(argp == NULL) {
MAG_ERR("IOparameter pointer is NULL!\r\n");
break;
}
if(copy_from_user(&enable, argp, sizeof(enable))) {
MAGN_LOG("copy_from_userfailed.");
return-EFAULT;
}
MAGN_LOG("MSENSOR_IOCTL_SENSOR_ENABLEenable=%d!\r\n", enable);
factory_mode= 1;
if(1 == enable) {
atomic_set(&o_flag,1);
atomic_set(&open_flag,1);
}else {
atomic_set(&o_flag,0);
if(atomic_read(&m_flag) == 0)
atomic_set(&open_flag,0);
}
wake_up(&open_wq);
break;
caseMSENSOR_IOCTL_READ_FACTORY_SENSORDATA:
if(argp == NULL) {
MAG_ERR("IOparameter pointer is NULL!\r\n");
break;
}
/*AKECS_GetRawData(buff, AKM09911_BUFSIZE); */
osensor_data= (struct hwm_sensor_data *)buff;
mutex_lock(&sensor_data_mutex);
osensor_data->values[0]= sensor_data[13] * CONVERT_O;
osensor_data->values[1]= sensor_data[14] * CONVERT_O;
osensor_data->values[2]= sensor_data[15] * CONVERT_O;
osensor_data->status= sensor_data[8];
osensor_data->value_divide= CONVERT_O_DIV;
mutex_unlock(&sensor_data_mutex);
sprintf(buff,"%x %x %x %x %x", osensor_data->values[0],osensor_data->values[1],
osensor_data->values[2],osensor_data->status, osensor_data->value_divide);
if(copy_to_user(argp, buff, strlen(buff)+1))
return-EFAULT;
break;
default:
MAG_ERR("%snot supported = 0x%04x", __func__, cmd);
return-ENOIOCTLCMD;
}
return0;
}
/*----------------------------------------------------------------------------*/
static const struct file_operationsakm09911_fops = {
.owner= THIS_MODULE,
.open= akm09911_open,
.release= akm09911_release,
/*.unlocked_ioctl = akm09911_ioctl, */
.unlocked_ioctl= akm09911_unlocked_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl= akm09911_compat_ioctl,
#endif
};
/*----------------------------------------------------------------------------*/
static struct miscdevice akm09911_device ={
.minor= MISC_DYNAMIC_MINOR,
.name= "msensor",
.fops= &akm09911_fops,
};
/*----------------------------------------------------------------------------*/
int akm09911_operate(void *self, uint32_tcommand, void *buff_in, int size_in,
void*buff_out, int size_out, int *actualout)
{
interr = 0;
intvalue;
structhwm_sensor_data *msensor_data;
#if DEBUG
structi2c_client *client = this_client;
structakm09911_i2c_data *data = i2c_get_clientdata(client);
#endif
#if DEBUG
if(atomic_read(&data->trace) & AMK_FUN_DEBUG)
AKMFUNC("akm09911_operate");
#endif
switch(command) {
caseSENSOR_DELAY:
if((buff_in == NULL) || (size_in < sizeof(int))) {
MAG_ERR("Setdelay parameter error!\n");
err= -EINVAL;
}else {
value= *(int *)buff_in;
if(value <= 10)
value= 10;
akmd_delay= value;
}
break;
caseSENSOR_ENABLE:
if((buff_in == NULL) || (size_in < sizeof(int))) {
MAG_ERR("Enablesensor parameter error!\n");
err= -EINVAL;
}else {
value= *(int *)buff_in;
if(value == 1) {
atomic_set(&m_flag,1);
atomic_set(&open_flag,1);
}else {
atomic_set(&m_flag,0);
if((atomic_read(&o_flag) == 0))
atomic_set(&open_flag,0);
}
wake_up(&open_wq);
/*TODO: turn device into standby or normal mode */
}
break;
caseSENSOR_GET_DATA:
if((buff_out == NULL) || (size_out < sizeof(struct hwm_sensor_data))) {
MAG_ERR("getsensor data parameter error!\n");
err= -EINVAL;
}else {
msensor_data= (struct hwm_sensor_data *)buff_out;
mutex_lock(&sensor_data_mutex);
msensor_data->values[0]= sensor_data[5] * CONVERT_M;
msensor_data->values[1]= sensor_data[6] * CONVERT_M;
msensor_data->values[2]= sensor_data[7] * CONVERT_M;
msensor_data->status= sensor_data[8];
msensor_data->value_divide= CONVERT_M_DIV;
mutex_unlock(&sensor_data_mutex);
#if DEBUG
if(atomic_read(&data->trace) & AMK_HWM_DEBUG) {
MAGN_LOG("Hwmget m-sensor data: %d, %d, %d. divide %d, status %d!\n",
msensor_data->values[0],msensor_data->values[1], msensor_data->values[2],
msensor_data->value_divide,msensor_data->status);
}
#endif
}
break;
default:
MAG_ERR("msensoroperate function no this parameter %d!\n", command);
err= -1;
break;
}
returnerr;
}
/*----------------------------------------------------------------------------*/
int akm09911_orientation_operate(void*self, uint32_t command, void *buff_in, int size_in,
void*buff_out, int size_out, int *actualout)
{
interr = 0;
intvalue;
structhwm_sensor_data *osensor_data;
#if DEBUG
structi2c_client *client = this_client;
structakm09911_i2c_data *data = i2c_get_clientdata(client);
#endif
#if DEBUG
if(atomic_read(&data->trace) & AMK_FUN_DEBUG)
AKMFUNC("akm09911_orientation_operate");
#endif
switch(command) {
caseSENSOR_DELAY:
if((buff_in == NULL) || (size_in < sizeof(int))) {
MAG_ERR("Setdelay parameter error!\n");
err= -EINVAL;
}else {
value= *(int *)buff_in;
if(value <= 10)
value= 10;
akmd_delay= value;
}
break;
caseSENSOR_ENABLE:
if((buff_in == NULL) || (size_in < sizeof(int))) {
MAG_ERR("Enablesensor parameter error!\n");
err= -EINVAL;
}else {
value= *(int *)buff_in;
if(mEnabled <= 0) {
if(value == 1) {
atomic_set(&o_flag,1);
atomic_set(&open_flag,1);
}
}else if (mEnabled == 1) {
if(!value) {
atomic_set(&o_flag,0);
if(atomic_read(&m_flag) == 0)
atomic_set(&open_flag,0);
}
}
if(value) {
mEnabled++;
if(mEnabled > 32767)
mEnabled= 32767;
}else {
mEnabled--;
if(mEnabled < 0)
mEnabled= 0;
}
wake_up(&open_wq);
}
break;
caseSENSOR_GET_DATA:
if((buff_out == NULL) || (size_out < sizeof(struct hwm_sensor_data))) {
MAG_ERR("getsensor data parameter error!\n");
err= -EINVAL;
}else {
osensor_data= (struct hwm_sensor_data *)buff_out;
mutex_lock(&sensor_data_mutex);
osensor_data->values[0]= sensor_data[13] * CONVERT_O;
osensor_data->values[1]= sensor_data[14] * CONVERT_O;
osensor_data->values[2]= sensor_data[15] * CONVERT_O;
osensor_data->status= sensor_data[8];
osensor_data->value_divide= CONVERT_O_DIV;
mutex_unlock(&sensor_data_mutex);
#if DEBUG
if(atomic_read(&data->trace) & AMK_HWM_DEBUG) {
MAGN_LOG("Hwmget o-sensor data: %d, %d, %d. divide %d, status %d!\n",
osensor_data->values[0],osensor_data->values[1], osensor_data->values[2],
osensor_data->value_divide,osensor_data->status);
}
#endif
}
break;
default:
MAG_ERR("gsensoroperate function no this parameter %d!\n", command);
err= -1;
break;
}
returnerr;
}
。。。。。。
/*----------------------------------------------------------------------------*/
static int akm09911_suspend(structi2c_client *client, pm_message_t msg)
{
structakm09911_i2c_data *obj = i2c_get_clientdata(client);
if(msg.event == PM_EVENT_SUSPEND)
akm09911_power(obj->hw,0);
return0;
}
/*----------------------------------------------------------------------------*/
static int akm09911_resume(structi2c_client *client)
{
structakm09911_i2c_data *obj = i2c_get_clientdata(client);
akm09911_power(obj->hw,1);
return0;
}
/*----------------------------------------------------------------------------*/
static int akm09911_i2c_detect(structi2c_client *client, struct i2c_board_info *info)
{
strcpy(info->type,AKM09911_DEV_NAME);
return0;
}
/*
sensor的使能接口,在上层调用enable这个驱动的时候会调用到这里。
*/
static int akm09911_m_enable(int en)
{
intvalue = 0;
interr = 0;
value= en;
factory_mode= 1;
if(value == 1) {
atomic_set(&m_flag,1);
atomic_set(&open_flag,1);
err= AKECS_SetMode(AK09911_MODE_SNG_MEASURE);
if(err < 0) {
MAG_ERR("%s:AKECS_SetModeError.\n", __func__);
returnerr;
}
}else {
atomic_set(&m_flag,0);
if(atomic_read(&o_flag) == 0) {
atomic_set(&open_flag,0);
err= AKECS_SetMode(AK09911_MODE_POWERDOWN);
if(err < 0) {
MAG_ERR("%s:AKECS_SetModeError.\n", __func__);
returnerr;
}
}
}
wake_up(&open_wq);
returnerr;
}
static int akm09911_m_get_data(int *x , int*y, int *z, int *status)
{
charsensordata[SENSOR_DATA_SIZE];
s16data[3];
MAG_ERR("%s:akm09911_m_get_dataliyanfei.\n", __func__);
//AKECS_GetRawData(buff,AKM09911_BUFSIZE);
AKECS_SetMode_SngMeasure();
mdelay(10);
AKECS_GetData(sensordata,SENSOR_DATA_SIZE);
MAG_ERR("update!sensordata:%d, %d, %d, %d\n" , sensordata[5], sensordata[6], sensordata[7],sensordata[8]);
MAG_ERR("update!sensor_data: %d, %d, %d, %d\n" ,sensor_data[5], sensor_data[6], sensor_data[7], sensor_data[8]);
data[0]= (s16)(sensordata[1] | (sensordata[2] << 8));
data[1]= (s16)(sensordata[3] | (sensordata[4] << 8));
data[2]= (s16)(sensordata[5] | (sensordata[6] << 8));
MAG_ERR("akm09911_m_get_data:%x %x %x", data[0], data[1], data[2]);
// sprintf(rbuf,"%x %x %x", data[0], data[1], data[2]);
mutex_lock(&sensor_data_mutex);
*x= data[0] * CONVERT_M;
*y= data[1] * CONVERT_M;
*z= data[2]* CONVERT_M;
*status= sensordata[8];
MAG_ERR("update!valus222:%d, %d, %d, %d\n" , *x, *y, *z, *status);
mutex_unlock(&sensor_data_mutex);
return0;
}
static int akm09911_o_enable(int en)
{
intvalue = 0;
interr = 0;
value= en;
if(value == 1) {
atomic_set(&o_flag,1);
atomic_set(&open_flag,1);
err= AKECS_SetMode(AK09911_MODE_SNG_MEASURE);
if(err < 0) {
MAG_ERR("%s:AKECS_SetModeError.\n", __func__);
returnerr;
}
}else {
atomic_set(&o_flag,0);
if(atomic_read(&m_flag) == 0) {
atomic_set(&open_flag,0);
err= AKECS_SetMode(AK09911_MODE_POWERDOWN);
if(err < 0) {
MAG_ERR("%s:AKECS_SetModeError.\n", __func__);
returnerr;
}
}
}
wake_up(&open_wq);
returnerr;
}
static int akm09911_o_set_delay(u64 ns)
{
intvalue = 0;
value= (int)ns/1000/1000;
if(value <= 10)
akmd_delay= 10;
else
akmd_delay= value;
return0;
}
static int akm09911_o_open_report_data(intopen)
{
return0;
}
#if 0
static int akm09911_o_get_data(int *x , int*y, int *z, int *status)
{
mutex_lock(&sensor_data_mutex);
*x= sensor_data[13] * CONVERT_M;
*y= sensor_data[14] * CONVERT_M;
*z= sensor_data[15] * CONVERT_M;
*status= sensor_data[8];
mutex_unlock(&sensor_data_mutex);
return0;
}
#endif
static int akm09911_o_get_data(int *x , int*y, int *z, int *status)
{
charsensordata[SENSOR_DATA_SIZE];
s16data[3];
MAG_ERR("%s:akm09911_m_get_dataliyanfei.\n", __func__);
//AKECS_GetRawData(buff,AKM09911_BUFSIZE);
AKECS_SetMode_SngMeasure();
mdelay(10);
AKECS_GetData(sensordata,SENSOR_DATA_SIZE);
MAG_ERR("update!sensordata:%d, %d, %d, %d\n" , sensordata[5], sensordata[6], sensordata[7],sensordata[8]);
MAG_ERR("update!sensor_data: %d, %d, %d, %d\n" ,sensor_data[5], sensor_data[6], sensor_data[7], sensor_data[8]);
data[0]= (s16)(sensordata[1] | (sensordata[2] << 8));
data[1]= (s16)(sensordata[3] | (sensordata[4] << 8));
data[2]= (s16)(sensordata[5] | (sensordata[6] << 8));
MAG_ERR("akm09911_m_get_data:%x %x %x", data[0], data[1], data[2]);
// sprintf(rbuf,"%x %x %x", data[0], data[1], data[2]);
mutex_lock(&sensor_data_mutex);
*x= data[0] * CONVERT_M;
*y= data[1] * CONVERT_M;
*z= data[2]* CONVERT_M;
*status= sensordata[8];
MAG_ERR("update!valus222:%d, %d, %d, %d\n" , *x, *y, *z, *status);
mutex_unlock(&sensor_data_mutex);
return0;
}
/*
设备I2C的PROB,匹配上下面的信息后就会进去。msensor是在DCT里面配置的。
static const structof_device_id mag_of_match[] = {
{.compatible ="mediatek,msensor"},
{},
};
*/
/*----------------------------------------------------------------------------*/
static int akm09911_i2c_probe(structi2c_client *client, const struct i2c_device_id *id)
{
interr = 0;
structi2c_client *new_client;
structakm09911_i2c_data *data;
structmag_control_path ctl = {0};
structmag_data_path mag_data = {0};
MAGN_LOG("akm09911_i2c_probe\n");
data= kzalloc(sizeof(struct akm09911_i2c_data), GFP_KERNEL);
if(!data) {
err= -ENOMEM;
gotoexit;
}
data->hw= hw;
atomic_set(&data->layout,data->hw->direction);
atomic_set(&data->trace,0);
mutex_init(&sense_data_mutex);
mutex_init(&sensor_data_mutex);
/*init_waitqueue_head(&data_ready_wq); */
init_waitqueue_head(&open_wq);
data->client= client;
new_client= data->client;
i2c_set_clientdata(new_client,data);
this_client= new_client;
/*Check connection */
err= AKECS_CheckDevice();
if(err < 0) {
MAG_ERR("AKM09911akm09911_probe: check device connect error\n");
gotoexit_init_failed;
}
/*
注册驱动设备的相关节点,就是上面说明的一些节点信息。
*/
/*Register sysfs attribute */
err= akm09911_create_attr(&(akm09911_init_info.platform_diver_addr->driver));
if(err) {
MAG_ERR("createattribute err = %d\n", err);
gotoexit_sysfs_create_group_failed;
}
/*
注册一个MISC设备,设备位置在:/sys/class/misc/msensor。暂时不知道这个有啥用。
*/
err= misc_register(&akm09911_device);
if(err) {
MAG_ERR("akm09911_deviceregister failed\n");
gotoexit_misc_device_register_failed;
}
ctl.is_use_common_factory= false;
ctl.m_enable= akm09911_m_enable;
ctl.m_set_delay = akm09911_m_set_delay;
ctl.m_open_report_data= akm09911_m_open_report_data;
ctl.o_enable= akm09911_o_enable;
ctl.o_set_delay = akm09911_o_set_delay;
ctl.o_open_report_data= akm09911_o_open_report_data;
ctl.is_report_input_direct= false;
ctl.is_support_batch= data->hw->is_batch_supported;
/*
MTK 平台统一的接口,以方便对具体驱动的管理,这个支持多个相同的SENSOR。
*/
err = mag_register_control_path(&ctl);
if(err) {
MAG_ERR("registermag control path err\n");
gotoexit_kfree;
}
mag_data.div_m= CONVERT_M_DIV;
mag_data.div_o= CONVERT_O_DIV;
mag_data.get_data_o= akm09911_o_get_data;
mag_data.get_data_m= akm09911_m_get_data;
err = mag_register_data_path(&mag_data);
if(err) {
MAG_ERR("registerdata control path err\n");
gotoexit_kfree;
}
MAG_ERR("%s:OK\n", __func__);
akm09911_init_flag= 1;
return0;
exit_sysfs_create_group_failed:
exit_init_failed:
exit_misc_device_register_failed:
exit_kfree:
kfree(data);
exit:
MAG_ERR("%s:err = %d\n", __func__, err);
akm09911_init_flag= -1;
returnerr;
}
/*----------------------------------------------------------------------------*/
static int __init akm09911_init(void)
{
constchar *name = "mediatek,akm09911";
/*
获取akm09911的DTS相关信息。
*/
hw= get_mag_dts_func(name, hw);
if(!hw)
MAGN_ERR("getdts info fail\n");
/*
MTK的接口,在MAG.C中有用到,下面再具体说明。
*/
mag_driver_add(&akm09911_init_info);
return0;
}
module_init(akm09911_init);
module_exit(akm09911_exit);
MODULE_AUTHOR("MTK");
MODULE_DESCRIPTION("AKM09911 compassdriver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRIVER_VERSION);
上面是厂家提供的具体驱动sensor的代码,代码结构大同小异,具体的寄存器操作有差异,到时候可以具体看看DATASHEET或者直接找FAE来协助解决。
下面看看mag.c文档,MTK统一相关的接口。
alps\kernel-3.18\drivers\misc\mediatek\magnetometer\mag.c
......
static void mag_work_func(structwork_struct *work)
{
structmag_context *cxt = NULL;
structhwm_sensor_data sensor_data;
int64_tm_pre_ns, o_pre_ns, cur_ns;
int64_tdelay_ms;
structtimespec time;
interr;
inti;
intx, y, z, status;
cxt = mag_context_obj;
delay_ms= atomic_read(&cxt->delay);
memset(&sensor_data,0, sizeof(sensor_data));
time.tv_sec= time.tv_nsec = 0;
get_monotonic_boottime(&time);
cur_ns= time.tv_sec*1000000000LL+time.tv_nsec;
for(i = 0; i < MAX_M_V_SENSOR; i++) {
if(!(cxt->active_data_sensor&(0x01<<i))) {
MAG_LOG("mag_type(%d) enabled(%d)\n", i, cxt->active_data_sensor);
continue;
}
MAG_LOG("mag_type(%d)liyanfei enabled(%d)\n", i,cxt->active_data_sensor);
if(ID_M_V_MAGNETIC == i) {
/*
获取驱动的数据。
*/
err= cxt->mag_dev_data.get_data_m(&x,&y, &z, &status);
if(err) {
MAG_ERR("get%d data fails!!\n" , i);
return;
}
cxt->drv_data[i].mag_data.values[0]= x;
cxt->drv_data[i].mag_data.values[1]= y;
cxt->drv_data[i].mag_data.values[2]= z;
cxt->drv_data[i].mag_data.status= status;
m_pre_ns= cxt->drv_data[i].mag_data.time;
cxt->drv_data[i].mag_data.time= cur_ns;
if(true == cxt->is_first_data_after_enable) {
m_pre_ns= cur_ns;
cxt->is_first_data_after_enable= false;
/*filter -1 value */
if(MAG_INVALID_VALUE == cxt->drv_data[i].mag_data.values[0] ||
MAG_INVALID_VALUE== cxt->drv_data[i].mag_data.values[1] ||
MAG_INVALID_VALUE== cxt->drv_data[i].mag_data.values[2]) {
MAG_LOG("read invalid data\n");
continue;
}
}
while((cur_ns - m_pre_ns) >= delay_ms*1800000LL) {
m_pre_ns+= delay_ms*1000000LL;
mag_data_report(MAGNETIC,cxt->drv_data[i].mag_data.values[0],
cxt->drv_data[i].mag_data.values[1],
cxt->drv_data[i].mag_data.values[2],
cxt->drv_data[i].mag_data.status,m_pre_ns);
}
/*
通过input_report_XXX的相关接口INPUT接口,向对应INPUT设备中写入数据。
*/
mag_data_report(MAGNETIC,cxt->drv_data[i].mag_data.values[0],
cxt->drv_data[i].mag_data.values[1],
cxt->drv_data[i].mag_data.values[2],
cxt->drv_data[i].mag_data.status,cxt->drv_data[i].mag_data.time);
MAG_LOG("mag_type(%d)data[%d,%d,%d]\n" ,i,cxt->drv_data[i].mag_data.values[0],
cxt->drv_data[i].mag_data.values[1],cxt->drv_data[i].mag_data.values[2]);
}
......
if(true == cxt->is_polling_run)
startTimer(&cxt->hrTimer,atomic_read(&cxt->delay), false);
}
/*
驱动中启用了一个TIMER,不停的再读取数据,然后向上派发。
*/
enum hrtimer_restart mag_poll(structhrtimer *timer)
{
structmag_context *obj = (struct mag_context *)container_of(timer, structmag_context, hrTimer);
queue_work(obj->mag_workqueue,&obj->report);
returnHRTIMER_NORESTART;
}
static struct mag_context*mag_context_alloc_object(void)
{
structmag_context *obj = kzalloc(sizeof(*obj), GFP_KERNEL);
MAG_LOG("mag_context_alloc_object++++\n");
if(!obj) {
MAG_ERR("Allocmagel object error!\n");
returnNULL;
}
atomic_set(&obj->delay,200); /* set work queue delay time 200ms */
atomic_set(&obj->wake,0);
INIT_WORK(&obj->report,mag_work_func);
obj->mag_workqueue= NULL;
obj->mag_workqueue= create_workqueue("mag_polling");
if(!obj->mag_workqueue) {
kfree(obj);
returnNULL;
}
initTimer(&obj->hrTimer,mag_poll);
obj->is_first_data_after_enable= false;
obj->is_polling_run= false;
obj->active_data_sensor= 0;
obj->active_nodata_sensor= 0;
obj->is_batch_enable= false;
mutex_init(&obj->mag_op_mutex);
MAG_LOG("mag_context_alloc_object----\n");
returnobj;
}
/*
打开sensor的时候,需要使能这个设备,最后会调用到这里来。然后调用对应驱动里面具体进行使能操作。
*/
static int mag_enable_data(int handle, intenable)
{
structmag_context *cxt = NULL;
cxt= mag_context_obj;
if(NULL == cxt->drv_obj[handle]&& NULL == cxt->mag_ctl.m_enable) {
MAG_ERR("noreal mag driver\n");
return-1;
}
if(1 == enable) {
MAG_LOG("MAG(%d)enable\n", handle);
cxt->is_first_data_after_enable= true;
cxt->active_data_sensor|= 1<<handle;
if(ID_M_V_ORIENTATION == handle) {
cxt->mag_ctl.o_enable(1);
cxt->mag_ctl.o_open_report_data(1);
}
if(ID_M_V_MAGNETIC == handle) {
cxt->mag_ctl.m_enable(1);
cxt->mag_ctl.m_open_report_data(1);
}
if((0 != cxt->active_data_sensor) && (false == cxt->is_polling_run)&&
(false== cxt->is_batch_enable)) {
if(false == cxt->mag_ctl.is_report_input_direct) {
MAG_LOG("MAG(%d) mod timer\n", handle);
startTimer(&cxt->hrTimer,atomic_read(&cxt->delay), true);
cxt->is_polling_run= true;
}
}
}
if(0 == enable) {
MAG_LOG("MAG(%d)disable\n", handle);
cxt->active_data_sensor&= ~(1<<handle);
if(ID_M_V_ORIENTATION == handle) {
cxt->mag_ctl.o_enable(0);
cxt->mag_ctl.o_open_report_data(0);
}
if(ID_M_V_MAGNETIC == handle) {
cxt->mag_ctl.m_enable(0);
cxt->mag_ctl.m_open_report_data(0);
}
if(0 == cxt->active_data_sensor && true == cxt->is_polling_run) {
if(false == cxt->mag_ctl.is_report_input_direct) {
MAG_LOG("MAG(%d) del timer\n", handle);
cxt->is_polling_run= false;
smp_mb();/*fomemory barrier*/
stopTimer(&cxt->hrTimer);
smp_mb();/*formemory barrier*/
cancel_work_sync(&cxt->report);
cxt->drv_data[handle].mag_data.values[0]= MAG_INVALID_VALUE;
cxt->drv_data[handle].mag_data.values[1]= MAG_INVALID_VALUE;
cxt->drv_data[handle].mag_data.values[2]= MAG_INVALID_VALUE;
}
}
}
return0;
}
.......
int mag_attach(int sensor, structmag_drv_obj *obj)
{
interr = 0;
MAG_FUN();
mag_context_obj->drv_obj[sensor]= kzalloc(sizeof(struct mag_drv_obj), GFP_KERNEL);
if(mag_context_obj->drv_obj[sensor] == NULL) {
err= -EPERM;
MAG_ERR("mag attatch alloc fail\n");
returnerr;
}
memcpy(mag_context_obj->drv_obj[sensor],obj, sizeof(*obj));
if(NULL == mag_context_obj->drv_obj[sensor]) {
err= -1;
MAG_ERR("mag attatch fail\n");
}
returnerr;
}
/*----------------------------------------------------------------------------*/
EXPORT_SYMBOL_GPL(mag_attach);
static int msensor_remove(structplatform_device *pdev)
{
MAG_LOG("msensor_remove\n");
return0;
}
static int msensor_probe(structplatform_device *pdev)
{
MAG_LOG("msensor_probe\n");
return0;
}
#ifdef CONFIG_OF
static const struct of_device_idmsensor_of_match[] = {
{.compatible = "mediatek,msensor", },
{},
};
#endif
static struct platform_drivermsensor_driver = {
.probe =msensor_probe,
.remove = msensor_remove,
.driver= {
.name = "msensor",
#ifdefCONFIG_OF
.of_match_table= msensor_of_match,
#endif
}
};
/*
支持多个SENSOR,这里会调用各个驱动sensor的init,如上面的会调用akm09911_local_init,会进行I2C的通信,如果正常就认为该SENSOR是存在的。
*/
static int mag_real_driver_init(void)
{
inti = 0;
interr = 0;
MAG_LOG("mag_real_driver_init +\n");
for(i = 0; i < MAX_CHOOSE_G_NUM; i++) {
MAG_LOG("i=%d\n", i);
if(0 != msensor_init_list[i]) {
MAG_LOG("mag try to init driver %s\n", msensor_init_list[i]->name);
err= msensor_init_list[i]->init();
if(0 == err) {
MAG_LOG("mag real driver %s probe ok\n", msensor_init_list[i]->name);
break;
}
}
}
if(i == MAX_CHOOSE_G_NUM) {
MAG_LOG("mag_real_driver_init fail\n");
err= -1;
}
returnerr;
}
/*
给具体 sensor提供接口而已。驱动中有调用到。
*/
int mag_driver_add(struct mag_init_info*obj)
{
interr = 0;
inti = 0;
MAG_FUN();
if(!obj) {
MAG_ERR("MAGdriver add fail, mag_init_info is NULL\n");
return-1;
}
for(i = 0; i < MAX_CHOOSE_G_NUM; i++) {
if((i == 0) && (NULL == msensor_init_list[0])) {
MAG_LOG("registermensor driver for the first time\n");
if(platform_driver_register(&msensor_driver))
MAG_ERR("failedto register msensor driver already exist\n");
}
if(NULL == msensor_init_list[i]) {
obj->platform_diver_addr= &msensor_driver;
msensor_init_list[i]= obj;
break;
}
}
if(i >= MAX_CHOOSE_G_NUM) {
MAG_ERR("MAGdriver add err\n");
err= -1;
}
returnerr;
}
EXPORT_SYMBOL_GPL(mag_driver_add);
static int mag_misc_init(struct mag_context*cxt)
{
interr = 0;
cxt->mdev.minor= MISC_DYNAMIC_MINOR;
cxt->mdev.name = MAG_MISC_DEV_NAME;
/*
创建misc节点: /sys/class/misc/m_mag_misc/
相关的MAG节点都挂载在上面。使能的时候就是向下面的节点magactive写入1,然后调用mag_store_active---》mag_enable_data(ID_M_V_MAGNETIC,
1);具体使能对应MAG SENSOR.
*/
err= misc_register(&cxt->mdev);
if(err)
MAG_ERR("unableto register mag misc device!!\n");
returnerr;
}
static int mag_input_init(structmag_context *cxt)
{
structinput_dev *dev;
interr = 0;
dev= input_allocate_device();
if(NULL == dev)
return-ENOMEM;
dev->name= MAG_INPUTDEV_NAME;
input_set_capability(dev,EV_ABS, EVENT_TYPE_MAGEL_X);
input_set_capability(dev,EV_ABS, EVENT_TYPE_MAGEL_Y);
input_set_capability(dev,EV_ABS, EVENT_TYPE_MAGEL_Z);
input_set_capability(dev,EV_ABS, EVENT_TYPE_MAGEL_STATUS);
input_set_capability(dev,EV_REL, EVENT_TYPE_MAGEL_UPDATE);
input_set_capability(dev,EV_REL, EVENT_TYPE_MAG_TIMESTAMP_HI);
input_set_capability(dev,EV_REL, EVENT_TYPE_MAG_TIMESTAMP_LO);
input_set_capability(dev,EV_REL, EVENT_TYPE_ORIENT_UPDATE);
input_set_capability(dev,EV_REL, EVENT_TYPE_ORIENT_TIMESTAMP_HI);
input_set_capability(dev,EV_REL, EVENT_TYPE_ORIENT_TIMESTAMP_LO);
input_set_capability(dev,EV_ABS, EVENT_TYPE_O_X);
input_set_capability(dev,EV_ABS, EVENT_TYPE_O_Y);
input_set_capability(dev,EV_ABS, EVENT_TYPE_O_Z);
input_set_capability(dev,EV_ABS, EVENT_TYPE_O_STATUS);
input_set_capability(dev,EV_REL, EVENT_TYPE_O_UPDATE);
input_set_abs_params(dev,EVENT_TYPE_MAGEL_X, MAG_VALUE_MIN, MAG_VALUE_MAX, 0, 0);
input_set_abs_params(dev,EVENT_TYPE_MAGEL_Y, MAG_VALUE_MIN, MAG_VALUE_MAX, 0, 0);
input_set_abs_params(dev,EVENT_TYPE_MAGEL_Z, MAG_VALUE_MIN, MAG_VALUE_MAX, 0, 0);
input_set_abs_params(dev,EVENT_TYPE_MAGEL_STATUS, MAG_STATUS_MIN, MAG_STATUS_MAX, 0, 0);
input_set_abs_params(dev,EVENT_TYPE_O_X, MAG_VALUE_MIN, MAG_VALUE_MAX, 0, 0);
input_set_abs_params(dev,EVENT_TYPE_O_Y, MAG_VALUE_MIN, MAG_VALUE_MAX, 0, 0);
input_set_abs_params(dev,EVENT_TYPE_O_Z, MAG_VALUE_MIN, MAG_VALUE_MAX, 0, 0);
input_set_abs_params(dev,EVENT_TYPE_O_STATUS, MAG_STATUS_MIN, MAG_STATUS_MAX, 0, 0);
input_set_drvdata(dev,cxt);
/*
注册INPUT设备,上层从/dev/input/eventX获取到数据,也可以用
adb shellgetevnet /dev/input/eventx来看是否有数据输入到INPUT设备中来。
*/
err= input_register_device(dev);
if(err < 0) {
input_free_device(dev);
returnerr;
}
cxt->idev= dev;
return0;
}
DEVICE_ATTR(magdev, S_IWUSR | S_IRUGO, mag_show_magdev, NULL);
DEVICE_ATTR(magactive, S_IWUSR | S_IRUGO, mag_show_active,mag_store_active);
DEVICE_ATTR(magdelay, S_IWUSR | S_IRUGO, mag_show_delay, mag_store_delay);
DEVICE_ATTR(magoactive, S_IWUSR | S_IRUGO, mag_show_oactive,mag_store_oactive);
DEVICE_ATTR(magodelay, S_IWUSR | S_IRUGO, mag_show_odelay, mag_store_odelay);
DEVICE_ATTR(magbatch, S_IWUSR | S_IRUGO, mag_show_batch, mag_store_batch);
DEVICE_ATTR(magflush, S_IWUSR | S_IRUGO, mag_show_flush, mag_store_flush);
DEVICE_ATTR(magobatch, S_IWUSR | S_IRUGO, mag_show_obatch, mag_store_obatch);
DEVICE_ATTR(magoflush, S_IWUSR | S_IRUGO, mag_show_oflush, mag_store_oflush);
DEVICE_ATTR(magdevnum, S_IWUSR | S_IRUGO,mag_show_sensordevnum, NULL);
static struct attribute *mag_attributes[] ={
&dev_attr_magdev.attr,
&dev_attr_magactive.attr,
&dev_attr_magdelay.attr,
&dev_attr_magbatch.attr,
&dev_attr_magflush.attr,
&dev_attr_magoactive.attr,
&dev_attr_magodelay.attr,
&dev_attr_magobatch.attr,
&dev_attr_magoflush.attr,
&dev_attr_magdevnum.attr,
NULL
};
static struct attribute_groupmag_attribute_group = {
.attrs= mag_attributes
};
/*
接口提供
*/
int mag_register_data_path(structmag_data_path *data)
{
structmag_context *cxt = NULL;
cxt= mag_context_obj;
cxt->mag_dev_data.div_m= data->div_m;
cxt->mag_dev_data.div_o= data->div_o;
cxt->mag_dev_data.get_data_m= data->get_data_m;
cxt->mag_dev_data.get_data_o= data->get_data_o;
cxt->mag_dev_data.get_raw_data= data->get_raw_data;
MAG_LOG("magregister data path div_o: %d\n", cxt->mag_dev_data.div_o);
MAG_LOG("magregister data path div_m: %d\n", cxt->mag_dev_data.div_m);
return0;
}
/*
接口提供
*/
int mag_register_control_path(structmag_control_path *ctl)
{
structmag_context *cxt = NULL;
interr = 0;
cxt= mag_context_obj;
cxt->mag_ctl.m_set_delay= ctl->m_set_delay;
cxt->mag_ctl.m_enable= ctl->m_enable;
cxt->mag_ctl.m_open_report_data= ctl->m_open_report_data;
cxt->mag_ctl.o_set_delay= ctl->o_set_delay;
cxt->mag_ctl.o_open_report_data= ctl->o_open_report_data;
cxt->mag_ctl.o_enable= ctl->o_enable;
cxt->mag_ctl.is_report_input_direct= ctl->is_report_input_direct;
cxt->mag_ctl.is_support_batch= ctl->is_support_batch;
cxt->mag_ctl.is_use_common_factory= ctl->is_use_common_factory;
if(NULL == cxt->mag_ctl.m_set_delay || NULL == cxt->mag_ctl.m_enable
||NULL == cxt->mag_ctl.m_open_report_data
||NULL == cxt->mag_ctl.o_set_delay || NULL ==cxt->mag_ctl.o_open_report_data
||NULL == cxt->mag_ctl.o_enable) {
MAG_LOG("magregister control path fail\n");
return-1;
}
/*add misc dev for sensor hal control cmd */
err= mag_misc_init(mag_context_obj);
if(err) {
MAG_ERR("unableto register mag misc device!!\n");
return-2;
}
err= sysfs_create_group(&mag_context_obj->mdev.this_device->kobj,
&mag_attribute_group);
if(err < 0) {
MAG_ERR("unableto create mag attribute file\n");
return-3;
}
kobject_uevent(&mag_context_obj->mdev.this_device->kobj,KOBJ_ADD);
return0;
}
......
int mag_data_report(enum MAG_TYPE type, intx, int y, int z, int status, int64_t nt)
{
structmag_context *cxt = NULL;
MAG_LOG("update!valus:%d, %d, %d, %d\n" , x, y, z, status);
check_repeat_data(x,y, z);
check_abnormal_data(x,y, z, status);
cxt= mag_context_obj;
if(MAGNETIC == type) {
input_report_abs(cxt->idev,EVENT_TYPE_MAGEL_STATUS, status);
input_report_abs(cxt->idev,EVENT_TYPE_MAGEL_X, x);
input_report_abs(cxt->idev,EVENT_TYPE_MAGEL_Y, y);
input_report_abs(cxt->idev,EVENT_TYPE_MAGEL_Z, z);
input_report_rel(cxt->idev,EVENT_TYPE_MAGEL_UPDATE, 1);
input_report_rel(cxt->idev,EVENT_TYPE_MAG_TIMESTAMP_HI, nt >> 32);
input_report_rel(cxt->idev,EVENT_TYPE_MAG_TIMESTAMP_LO, nt & 0xFFFFFFFFLL);
input_sync(cxt->idev);
}
if(ORIENTATION == type) {
input_report_abs(cxt->idev,EVENT_TYPE_O_STATUS, status);
input_report_abs(cxt->idev,EVENT_TYPE_O_X, x);
input_report_abs(cxt->idev,EVENT_TYPE_O_Y, y);
input_report_abs(cxt->idev,EVENT_TYPE_O_Z, z);
input_report_rel(cxt->idev,EVENT_TYPE_O_UPDATE, 1);
input_report_rel(cxt->idev,EVENT_TYPE_ORIENT_TIMESTAMP_HI, nt >> 32);
input_report_rel(cxt->idev,EVENT_TYPE_ORIENT_TIMESTAMP_LO, nt & 0xFFFFFFFFLL);
input_sync(cxt->idev);
}
return0;
}
static int mag_probe(void)
{
interr;
MAG_LOG("+++++++++++++mag_probe!!\n");
mag_context_obj= mag_context_alloc_object();
if(!mag_context_obj) {
err= -ENOMEM;
MAG_ERR("unableto allocate devobj!\n");
gotoexit_alloc_data_failed;
}
/*init real mageleration driver */
err = mag_real_driver_init();
if(err) {
MAG_ERR("mag_real_driver_initfail\n");
gotoexit_alloc_data_failed;
}
err = mag_factory_device_init();
if(err)
MAG_ERR("mag_factory_device_initfail\n");
/*init input dev */
err = mag_input_init(mag_context_obj);
if(err) {
MAG_ERR("unableto register mag input device!\n");
gotoexit_alloc_input_dev_failed;
}
MAG_LOG("----magel_probeOK !!\n");
return0;
exit_alloc_input_dev_failed:
mag_input_destroy(mag_context_obj);
exit_alloc_data_failed:
kfree(mag_context_obj);
MAG_ERR("----magel_probefail !!!\n");
returnerr;
}
。。。。。。
static int __init mag_init(void)
{
MAG_FUN();
if(mag_probe()) {
MAG_ERR("failedto register mag driver\n");
return-ENODEV;
}
return0;
}
static void __exit mag_exit(void)
{
mag_remove();
platform_driver_unregister(&msensor_driver);
}
late_initcall(mag_init);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("MAGELEROMETERdevice driver");
MODULE_AUTHOR("Mediatek");
个人理解:
KERNEL驱动的主要功能是加载相应的驱动代码,完成对SENSOR芯片的初始化工作,当上层发送enable命令来后,芯片进入工作状态,不停通过TIMER读取芯片的数据,然后放入到INPUT系统的节点上面:/dev/input/eventX.供上层调用。
sensor在KERNEL层就是各个sensor的驱动代码的具体实现,而驱动的任务,就是通过总线与硬件设备进行通信,控制硬件进去各种工作状态,获取器件相关寄存器的值,从而得到设备的状态。下面以MT6753 6.0的MSENSOR:AKM09911具体介绍下。
alps\kernel-3.18\drivers\misc\mediatek\magnetometer\akm09911-new
......
static struct i2c_driverakm09911_i2c_driver = {
.driver= {
.name = AKM09911_DEV_NAME,
#ifdef CONFIG_OF
.of_match_table= mag_of_match,
#endif
},
.probe = akm09911_i2c_probe,
.remove = akm09911_i2c_remove,
.detect = akm09911_i2c_detect,
.suspend = akm09911_suspend,
.resume = akm09911_resume,
.id_table= akm09911_i2c_id,
};
/*----------------------------------------------------------------------------*/
static atomic_t dev_open_count;
/*----------------------------------------------------------------------------*/
/*
重力感应器的I2C通信接口。调试前,需要先确保供电正常,再就是I2C的通信正常。这个就是驱动工程师做的最多的事情,因为这个供电是开机一直供电的,所以没有供电的问题。只需要确认下就好了。重点还是看LOG,看看该设备的I2C是是否正常。如果不正常,需要检查I2C的地址,硬件的连接。或者打电话给FAE了。
*/
static DEFINE_MUTEX(akm09911_i2c_mutex);
#ifndef CONFIG_MTK_I2C_EXTENSION
static int mag_i2c_read_block(structi2c_client *client, u8 addr, u8 *data, u8 len)
{
interr = 0;
u8beg = addr;
structi2c_msg msgs[2] = { {0}, {0} };
mutex_lock(&akm09911_i2c_mutex);
msgs[0].addr= client->addr;
msgs[0].flags= 0;
msgs[0].len= 1;
msgs[0].buf= &beg;
msgs[1].addr= client->addr;
msgs[1].flags= I2C_M_RD;
msgs[1].len= len;
msgs[1].buf= data;
if(!client) {
mutex_unlock(&akm09911_i2c_mutex);
return-EINVAL;
}else if (len > C_I2C_FIFO_SIZE) {
mutex_unlock(&akm09911_i2c_mutex);
MAGN_ERR("length %d exceeds %d\n", len, C_I2C_FIFO_SIZE);
return-EINVAL;
}
err= i2c_transfer(client->adapter, msgs, sizeof(msgs) / sizeof(msgs[0]));
if(err != 2) {
MAGN_ERR("i2c_transfererror: (%d %p %d) %d\n", addr, data, len, err);
err= -EIO;
}else {
err= 0;
}
mutex_unlock(&akm09911_i2c_mutex);
returnerr;
}
static int mag_i2c_write_block(structi2c_client *client, u8 addr, u8 *data, u8 len)
{ /*becauseaddress also occupies one byte, the maximum length for write is 7 bytes */
interr = 0, idx = 0, num = 0;
charbuf[C_I2C_FIFO_SIZE];
err= 0;
mutex_lock(&akm09911_i2c_mutex);
if(!client) {
mutex_unlock(&akm09911_i2c_mutex);
return-EINVAL;
}else if (len >= C_I2C_FIFO_SIZE) {
mutex_unlock(&akm09911_i2c_mutex);
MAGN_ERR("length %d exceeds %d\n", len, C_I2C_FIFO_SIZE);
return-EINVAL;
}
num= 0;
buf[num++]= addr;
for(idx = 0; idx < len; idx++)
buf[num++]= data[idx];
err= i2c_master_send(client, buf, num);
if(err < 0) {
mutex_unlock(&akm09911_i2c_mutex);
MAGN_ERR("sendcommand error!!\n");
return-EFAULT;
}
mutex_unlock(&akm09911_i2c_mutex);
returnerr;
}
#endif
static void akm09911_power(struct mag_hw*hw, unsigned int on)
{
}
/*其他的一些驱动函数不太关心,悄悄的滤过,具体要有问题可以看看DATASHEET,一般用到比较少。厂家给过来的一般都是有验证过的。
*/
static long AKECS_SetMode_SngMeasure(void)
{
charbuffer[2];
#ifdefAKM_Device_AK8963
buffer[0]= AK8963_REG_CNTL1;
buffer[1]= AK8963_MODE_SNG_MEASURE;
#else
/*Set measure mode */
buffer[0]= AK09911_REG_CNTL2;
buffer[1]= AK09911_MODE_SNG_MEASURE;
#endif
/*Set data */
returnAKI2C_TxData(buffer, 2);
}
static long AKECS_SetMode_SelfTest(void)
{
charbuffer[2];
#ifdefAKM_Device_AK8963
buffer[0]= AK8963_REG_CNTL1;
buffer[1]= AK8963_MODE_SELF_TEST;
#else
/*Set measure mode */
buffer[0]= AK09911_REG_CNTL2;
buffer[1]= AK09911_MODE_SELF_TEST;
/*Set data */
#endif
returnAKI2C_TxData(buffer, 2);
}
/*
读取器件数据,不管上层如何转了转去,获取数据的时候,都是会调用到这个接口来获取芯片的寄存器数据。调试的时候可以把MAGN_LOG
打开调试。看看从芯片读取到的数据是否正常,芯片是否工作正常。
*/
/* M-sensor daemon application have set thesng mode */
static long AKECS_GetData(char *rbuf, intsize)
{
chartemp;
intloop_i, ret;
#if DEBUG
structi2c_client *client = this_client;
structakm09911_i2c_data *data = i2c_get_clientdata(client);
#endif
if(size < SENSOR_DATA_SIZE) {
MAG_ERR("buffsize is too small %d!\n", size);
return-1;
}
memset(rbuf,0, SENSOR_DATA_SIZE);
#ifdefAKM_Device_AK8963
rbuf[0]= AK8963_REG_ST1;
#else
rbuf[0]= AK09911_REG_ST1;
#endif
for(loop_i = 0; loop_i < AKM09911_RETRY_COUNT; loop_i++) {
ret= AKI2C_RxData(rbuf, 1);
if(ret) {
MAG_ERR("readST1 resigster failed!\n");
return-1;
}
if((rbuf[0] & 0x01) == 0x01)
break;
mdelay(2);
#ifdefAKM_Device_AK8963
rbuf[0]= AK8963_REG_ST1;
#else
rbuf[0]= AK09911_REG_ST1;
#endif
}
if(loop_i >= AKM09911_RETRY_COUNT) {
MAG_ERR("Dataread retry larger the max count!\n");
if(0 == factory_mode)
/*if return we can not get data at factory mode */
return-1;
}
temp= rbuf[0];
#ifdefAKM_Device_AK8963
rbuf[1]= AK8963_REG_HXL;
ret= AKI2C_RxData(&rbuf[1], SENSOR_DATA_SIZE - 2);
#elifdefined(AKM_Device_AK09916)
rbuf[1]=AK09911_REG_HXL;
ret= AKI2C_RxData(&rbuf[1], SENSOR_DATA_SIZE -2);
#else
rbuf[1]= AK09911_REG_HXL;
ret= AKI2C_RxData(&rbuf[1], SENSOR_DATA_SIZE - 1);
#endif
if(ret < 0) {
MAG_ERR("AKM8975akm8975_work_func: I2C failed\n");
return-1;
}
rbuf[0]= temp;
#ifdefAKM_Device_AK8963
rbuf[8]= rbuf[7];
rbuf[7]= 0;
#endif
#ifdefAKM_Device_AK09916
rbuf[9]= 1;
#endif
mutex_lock(&sense_data_mutex);
memcpy(sense_data,rbuf, sizeof(sense_data));
mutex_unlock(&sense_data_mutex);
MAGN_LOG("Getdevice data: %d, %d, %d, %d , %d, %d, %d, %d!\n",
sense_data[0],sense_data[1], sense_data[2], sense_data[3],
sense_data[4],sense_data[5], sense_data[6], sense_data[7]);
#if DEBUG
if(atomic_read(&data->trace) & AMK_DATA_DEBUG) {
MAGN_LOG("Getdevice data: %d, %d, %d, %d , %d, %d, %d, %d!\n",
sense_data[0],sense_data[1], sense_data[2], sense_data[3],
sense_data[4],sense_data[5], sense_data[6], sense_data[7]);
}
#endif
return0;
}
。。。。。。
/*
设备的节点建立在/sys/bus/platform/drivers/msensor的下面。可以直接用ADB来获取数据,方便调试。
*/
/*----------------------------------------------------------------------------*/
static struct driver_attribute*akm09911_attr_list[] = {
&driver_attr_daemon,
&driver_attr_shipmenttest,
&driver_attr_chipinfo,
&driver_attr_sensordata,
&driver_attr_posturedata,
&driver_attr_layout,
&driver_attr_status,
&driver_attr_trace,
&driver_attr_orientation,
&driver_attr_power,
&driver_attr_regmap,
};
/*----------------------------------------------------------------------------*/
static int akm09911_create_attr(structdevice_driver *driver)
{
intidx, err = 0;
intnum = (int)(sizeof(akm09911_attr_list)/sizeof(akm09911_attr_list[0]));
if(driver == NULL)
return-EINVAL;
for(idx = 0; idx < num; idx++) {
err= driver_create_file(driver, akm09911_attr_list[idx]);
if(err) {
MAG_ERR("driver_create_file(%s) = %d\n", akm09911_attr_list[idx]->attr.name, err);
break;
}
}
returnerr;
}
......
/*
IOCTL的接口,工厂模式有用到,正常模式应该是不需要的。可以绕开android
的系统SENSOR架构,直接用IOCTL来获取驱动的接口。
*/
/*----------------------------------------------------------------------------*/
/* static int akm09911_ioctl(struct inode*inode, struct file *file, unsigned int cmd,unsigned long arg) */
static long akm09911_unlocked_ioctl(structfile *file, unsigned int cmd, unsigned long arg)
{
void__user *argp = (void __user *)arg;
/*NOTE: In this function the size of "char" should be 1-byte. */
charsData[SENSOR_DATA_SIZE];/* for GETDATA */
charrwbuf[RWBUF_SIZE]; /* for READ/WRITE*/
charbuff[AKM09911_BUFSIZE]; /*for chip information */
charmode; /* forSET_MODE*/
intvalue[26]; /* for SET_YPR */
int64_tdelay[3]; /* for GET_DELAY*/
intstatus; /* forOPEN/CLOSE_STATUS */
longret = -1; /* Return value. */
intlayout;
structi2c_client *client = this_client;
structakm09911_i2c_data *data = i2c_get_clientdata(client);
structhwm_sensor_data *osensor_data;
uint32_tenable;
/*These two buffers are initialized at start up.
Afterthat, the value is not changed */
unsignedchar sense_info[AKM_SENSOR_INFO_SIZE];
unsignedchar sense_conf[AKM_SENSOR_CONF_SIZE];
/*MAG_ERR("akm09911 cmd:0x%x\n", cmd); */
switch(cmd) {
caseECS_IOCTL_WRITE:
/*AKMFUNC("ECS_IOCTL_WRITE"); */
if(argp == NULL) {
MAGN_LOG("invalidargument.");
return-EINVAL;
}
if(copy_from_user(rwbuf, argp, sizeof(rwbuf))) {
MAGN_LOG("copy_from_userfailed.");
return-EFAULT;
}
if((rwbuf[0] < 2) || (rwbuf[0] > (RWBUF_SIZE-1))) {
MAGN_LOG("invalidargument.");
return-EINVAL;
}
ret= AKI2C_TxData(&rwbuf[1], rwbuf[0]);
if(ret < 0)
returnret;
break;
caseECS_IOCTL_RESET:
ret= AKECS_Reset(0); /* sw: 0, hw: 1 */
if(ret < 0)
returnret;
break;
caseECS_IOCTL_READ:
if(argp == NULL) {
MAGN_LOG("invalidargument.");
return-EINVAL;
}
if(copy_from_user(rwbuf, argp, sizeof(rwbuf))) {
MAGN_LOG("copy_from_userfailed.");
return-EFAULT;
}
if((rwbuf[0] < 1) || (rwbuf[0] > (RWBUF_SIZE-1))) {
MAGN_LOG("invalidargument.");
return-EINVAL;
}
ret= AKI2C_RxData(&rwbuf[1], rwbuf[0]);
if(ret < 0)
returnret;
if(copy_to_user(argp, rwbuf, rwbuf[0]+1)) {
MAGN_LOG("copy_to_userfailed.");
return-EFAULT;
}
break;
caseECS_IOCTL_GET_INFO:
#ifdefAKM_Device_AK8963
sense_info[0]= AK8963_REG_WIA;
#else
sense_info[0]= AK09911_REG_WIA1;
#endif
ret= AKI2C_RxData(sense_info, AKM_SENSOR_INFO_SIZE);
if(ret < 0)
{
returnret;
}
if(copy_to_user(argp,sense_info, AKM_SENSOR_INFO_SIZE))
{
MAGN_LOG("copy_to_userfailed.");
return-EFAULT;
}
break;
caseECS_IOCTL_GET_CONF:
/*Set FUSE access mode */
#ifdefAKM_Device_AK8963
ret= AKECS_SetMode(AK8963_MODE_FUSE_ACCESS);
#else
ret= AKECS_SetMode(AK09911_MODE_FUSE_ACCESS);
#endif
if(ret < 0)
return ret;
#ifdefAKM_Device_AK8963
sense_conf[0]= AK8963_FUSE_ASAX;
#else
sense_conf[0]= AK09911_FUSE_ASAX;
#endif
#ifdefAKM_Device_AK09916
sense_conf[0]= AK09916_ASA;
sense_conf[1]= AK09916_ASA;
sense_conf[2]= AK09916_ASA;
#else
ret= AKI2C_RxData(sense_conf, AKM_SENSOR_CONF_SIZE);
#endif
if(ret < 0)
{
returnret;
}
if(copy_to_user(argp,sense_conf, AKM_SENSOR_CONF_SIZE))
{
MAGN_LOG("copy_to_userfailed.");
return-EFAULT;
}
#ifdefAKM_Device_AK8963
ret= AKECS_SetMode(AK8963_MODE_POWERDOWN);
#else
ret= AKECS_SetMode(AK09911_MODE_POWERDOWN);
#endif
if(ret < 0)
returnret;
break;
caseECS_IOCTL_SET_MODE:
/*AKMFUNC("ECS_IOCTL_SET_MODE"); */
if(argp == NULL) {
MAGN_LOG("invalidargument.");
return-EINVAL;
}
if(copy_from_user(&mode, argp, sizeof(mode))) {
MAGN_LOG("copy_from_userfailed.");
return-EFAULT;
}
ret= AKECS_SetMode(mode); /* MATCH commandfrom AKMD PART */
if(ret < 0)
returnret;
break;
caseECS_IOCTL_GETDATA:
/*AKMFUNC("ECS_IOCTL_GETDATA"); */
ret= AKECS_GetData(sData, SENSOR_DATA_SIZE);
if(ret < 0)
returnret;
if(copy_to_user(argp, sData, sizeof(sData))) {
MAGN_LOG("copy_to_userfailed.");
return-EFAULT;
}
break;
caseECS_IOCTL_SET_YPR_09911:
/*AKMFUNC("ECS_IOCTL_SET_YPR"); */
if(argp == NULL) {
MAGN_LOG("invalidargument.");
return-EINVAL;
}
if(copy_from_user(value, argp, sizeof(value))) {
MAGN_LOG("copy_from_userfailed.");
return-EFAULT;
}
AKECS_SaveData(value);
break;
caseECS_IOCTL_GET_OPEN_STATUS:
/*AKMFUNC("IOCTL_GET_OPEN_STATUS"); */
status= AKECS_GetOpenStatus();
/*MAGN_LOG("AKECS_GetOpenStatus returned (%d)", status); */
if(copy_to_user(argp, &status, sizeof(status))) {
MAGN_LOG("copy_to_userfailed.");
return-EFAULT;
}
break;
caseECS_IOCTL_GET_CLOSE_STATUS:
/*AKMFUNC("IOCTL_GET_CLOSE_STATUS"); */
status= AKECS_GetCloseStatus();
/*MAGN_LOG("AKECS_GetCloseStatus returned (%d)", status); */
if(copy_to_user(argp, &status, sizeof(status))) {
MAGN_LOG("copy_to_userfailed.");
return-EFAULT;
}
break;
caseECS_IOCTL_GET_OSENSOR_STATUS:
/*AKMFUNC("ECS_IOCTL_GET_OSENSOR_STATUS"); */
status= atomic_read(&o_flag);
if(copy_to_user(argp, &status, sizeof(status))) {
MAGN_LOG("copy_to_userfailed.");
return-EFAULT;
}
break;
caseECS_IOCTL_GET_DELAY_09911:
/*AKMFUNC("IOCTL_GET_DELAY"); */
delay[0]= (int)akmd_delay * 1000000;
delay[1]= (int)akmd_delay * 1000000;
delay[2]= (int)akmd_delay * 1000000;
if(copy_to_user(argp, delay, sizeof(delay))) {
MAGN_LOG("copy_to_userfailed.");
return-EFAULT;
}
break;
caseECS_IOCTL_GET_LAYOUT_09911:
layout= atomic_read(&data->layout);
MAG_ERR("layout=%d\r\n",layout);
if(copy_to_user(argp, &layout, sizeof(char))) {
MAGN_LOG("copy_to_userfailed.");
return-EFAULT;
}
break;
caseMSENSOR_IOCTL_READ_CHIPINFO:
if(argp == NULL) {
MAG_ERR("IOparameter pointer is NULL!\r\n");
break;
}
akm09911_ReadChipInfo(buff,AKM09911_BUFSIZE);
if(copy_to_user(argp, buff, strlen(buff)+1))
return-EFAULT;
break;
caseMSENSOR_IOCTL_READ_SENSORDATA:
if(argp == NULL) {
MAG_ERR("IOparameter pointer is NULL!\r\n");
break;
}
AKECS_GetRawData(buff,AKM09911_BUFSIZE);
if(copy_to_user(argp, buff, strlen(buff)+1))
return-EFAULT;
break;
caseMSENSOR_IOCTL_SENSOR_ENABLE:
if(argp == NULL) {
MAG_ERR("IOparameter pointer is NULL!\r\n");
break;
}
if(copy_from_user(&enable, argp, sizeof(enable))) {
MAGN_LOG("copy_from_userfailed.");
return-EFAULT;
}
MAGN_LOG("MSENSOR_IOCTL_SENSOR_ENABLEenable=%d!\r\n", enable);
factory_mode= 1;
if(1 == enable) {
atomic_set(&o_flag,1);
atomic_set(&open_flag,1);
}else {
atomic_set(&o_flag,0);
if(atomic_read(&m_flag) == 0)
atomic_set(&open_flag,0);
}
wake_up(&open_wq);
break;
caseMSENSOR_IOCTL_READ_FACTORY_SENSORDATA:
if(argp == NULL) {
MAG_ERR("IOparameter pointer is NULL!\r\n");
break;
}
/*AKECS_GetRawData(buff, AKM09911_BUFSIZE); */
osensor_data= (struct hwm_sensor_data *)buff;
mutex_lock(&sensor_data_mutex);
osensor_data->values[0]= sensor_data[13] * CONVERT_O;
osensor_data->values[1]= sensor_data[14] * CONVERT_O;
osensor_data->values[2]= sensor_data[15] * CONVERT_O;
osensor_data->status= sensor_data[8];
osensor_data->value_divide= CONVERT_O_DIV;
mutex_unlock(&sensor_data_mutex);
sprintf(buff,"%x %x %x %x %x", osensor_data->values[0],osensor_data->values[1],
osensor_data->values[2],osensor_data->status, osensor_data->value_divide);
if(copy_to_user(argp, buff, strlen(buff)+1))
return-EFAULT;
break;
default:
MAG_ERR("%snot supported = 0x%04x", __func__, cmd);
return-ENOIOCTLCMD;
}
return0;
}
/*----------------------------------------------------------------------------*/
static const struct file_operationsakm09911_fops = {
.owner= THIS_MODULE,
.open= akm09911_open,
.release= akm09911_release,
/*.unlocked_ioctl = akm09911_ioctl, */
.unlocked_ioctl= akm09911_unlocked_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl= akm09911_compat_ioctl,
#endif
};
/*----------------------------------------------------------------------------*/
static struct miscdevice akm09911_device ={
.minor= MISC_DYNAMIC_MINOR,
.name= "msensor",
.fops= &akm09911_fops,
};
/*----------------------------------------------------------------------------*/
int akm09911_operate(void *self, uint32_tcommand, void *buff_in, int size_in,
void*buff_out, int size_out, int *actualout)
{
interr = 0;
intvalue;
structhwm_sensor_data *msensor_data;
#if DEBUG
structi2c_client *client = this_client;
structakm09911_i2c_data *data = i2c_get_clientdata(client);
#endif
#if DEBUG
if(atomic_read(&data->trace) & AMK_FUN_DEBUG)
AKMFUNC("akm09911_operate");
#endif
switch(command) {
caseSENSOR_DELAY:
if((buff_in == NULL) || (size_in < sizeof(int))) {
MAG_ERR("Setdelay parameter error!\n");
err= -EINVAL;
}else {
value= *(int *)buff_in;
if(value <= 10)
value= 10;
akmd_delay= value;
}
break;
caseSENSOR_ENABLE:
if((buff_in == NULL) || (size_in < sizeof(int))) {
MAG_ERR("Enablesensor parameter error!\n");
err= -EINVAL;
}else {
value= *(int *)buff_in;
if(value == 1) {
atomic_set(&m_flag,1);
atomic_set(&open_flag,1);
}else {
atomic_set(&m_flag,0);
if((atomic_read(&o_flag) == 0))
atomic_set(&open_flag,0);
}
wake_up(&open_wq);
/*TODO: turn device into standby or normal mode */
}
break;
caseSENSOR_GET_DATA:
if((buff_out == NULL) || (size_out < sizeof(struct hwm_sensor_data))) {
MAG_ERR("getsensor data parameter error!\n");
err= -EINVAL;
}else {
msensor_data= (struct hwm_sensor_data *)buff_out;
mutex_lock(&sensor_data_mutex);
msensor_data->values[0]= sensor_data[5] * CONVERT_M;
msensor_data->values[1]= sensor_data[6] * CONVERT_M;
msensor_data->values[2]= sensor_data[7] * CONVERT_M;
msensor_data->status= sensor_data[8];
msensor_data->value_divide= CONVERT_M_DIV;
mutex_unlock(&sensor_data_mutex);
#if DEBUG
if(atomic_read(&data->trace) & AMK_HWM_DEBUG) {
MAGN_LOG("Hwmget m-sensor data: %d, %d, %d. divide %d, status %d!\n",
msensor_data->values[0],msensor_data->values[1], msensor_data->values[2],
msensor_data->value_divide,msensor_data->status);
}
#endif
}
break;
default:
MAG_ERR("msensoroperate function no this parameter %d!\n", command);
err= -1;
break;
}
returnerr;
}
/*----------------------------------------------------------------------------*/
int akm09911_orientation_operate(void*self, uint32_t command, void *buff_in, int size_in,
void*buff_out, int size_out, int *actualout)
{
interr = 0;
intvalue;
structhwm_sensor_data *osensor_data;
#if DEBUG
structi2c_client *client = this_client;
structakm09911_i2c_data *data = i2c_get_clientdata(client);
#endif
#if DEBUG
if(atomic_read(&data->trace) & AMK_FUN_DEBUG)
AKMFUNC("akm09911_orientation_operate");
#endif
switch(command) {
caseSENSOR_DELAY:
if((buff_in == NULL) || (size_in < sizeof(int))) {
MAG_ERR("Setdelay parameter error!\n");
err= -EINVAL;
}else {
value= *(int *)buff_in;
if(value <= 10)
value= 10;
akmd_delay= value;
}
break;
caseSENSOR_ENABLE:
if((buff_in == NULL) || (size_in < sizeof(int))) {
MAG_ERR("Enablesensor parameter error!\n");
err= -EINVAL;
}else {
value= *(int *)buff_in;
if(mEnabled <= 0) {
if(value == 1) {
atomic_set(&o_flag,1);
atomic_set(&open_flag,1);
}
}else if (mEnabled == 1) {
if(!value) {
atomic_set(&o_flag,0);
if(atomic_read(&m_flag) == 0)
atomic_set(&open_flag,0);
}
}
if(value) {
mEnabled++;
if(mEnabled > 32767)
mEnabled= 32767;
}else {
mEnabled--;
if(mEnabled < 0)
mEnabled= 0;
}
wake_up(&open_wq);
}
break;
caseSENSOR_GET_DATA:
if((buff_out == NULL) || (size_out < sizeof(struct hwm_sensor_data))) {
MAG_ERR("getsensor data parameter error!\n");
err= -EINVAL;
}else {
osensor_data= (struct hwm_sensor_data *)buff_out;
mutex_lock(&sensor_data_mutex);
osensor_data->values[0]= sensor_data[13] * CONVERT_O;
osensor_data->values[1]= sensor_data[14] * CONVERT_O;
osensor_data->values[2]= sensor_data[15] * CONVERT_O;
osensor_data->status= sensor_data[8];
osensor_data->value_divide= CONVERT_O_DIV;
mutex_unlock(&sensor_data_mutex);
#if DEBUG
if(atomic_read(&data->trace) & AMK_HWM_DEBUG) {
MAGN_LOG("Hwmget o-sensor data: %d, %d, %d. divide %d, status %d!\n",
osensor_data->values[0],osensor_data->values[1], osensor_data->values[2],
osensor_data->value_divide,osensor_data->status);
}
#endif
}
break;
default:
MAG_ERR("gsensoroperate function no this parameter %d!\n", command);
err= -1;
break;
}
returnerr;
}
。。。。。。
/*----------------------------------------------------------------------------*/
static int akm09911_suspend(structi2c_client *client, pm_message_t msg)
{
structakm09911_i2c_data *obj = i2c_get_clientdata(client);
if(msg.event == PM_EVENT_SUSPEND)
akm09911_power(obj->hw,0);
return0;
}
/*----------------------------------------------------------------------------*/
static int akm09911_resume(structi2c_client *client)
{
structakm09911_i2c_data *obj = i2c_get_clientdata(client);
akm09911_power(obj->hw,1);
return0;
}
/*----------------------------------------------------------------------------*/
static int akm09911_i2c_detect(structi2c_client *client, struct i2c_board_info *info)
{
strcpy(info->type,AKM09911_DEV_NAME);
return0;
}
/*
sensor的使能接口,在上层调用enable这个驱动的时候会调用到这里。
*/
static int akm09911_m_enable(int en)
{
intvalue = 0;
interr = 0;
value= en;
factory_mode= 1;
if(value == 1) {
atomic_set(&m_flag,1);
atomic_set(&open_flag,1);
err= AKECS_SetMode(AK09911_MODE_SNG_MEASURE);
if(err < 0) {
MAG_ERR("%s:AKECS_SetModeError.\n", __func__);
returnerr;
}
}else {
atomic_set(&m_flag,0);
if(atomic_read(&o_flag) == 0) {
atomic_set(&open_flag,0);
err= AKECS_SetMode(AK09911_MODE_POWERDOWN);
if(err < 0) {
MAG_ERR("%s:AKECS_SetModeError.\n", __func__);
returnerr;
}
}
}
wake_up(&open_wq);
returnerr;
}
static int akm09911_m_get_data(int *x , int*y, int *z, int *status)
{
charsensordata[SENSOR_DATA_SIZE];
s16data[3];
MAG_ERR("%s:akm09911_m_get_dataliyanfei.\n", __func__);
//AKECS_GetRawData(buff,AKM09911_BUFSIZE);
AKECS_SetMode_SngMeasure();
mdelay(10);
AKECS_GetData(sensordata,SENSOR_DATA_SIZE);
MAG_ERR("update!sensordata:%d, %d, %d, %d\n" , sensordata[5], sensordata[6], sensordata[7],sensordata[8]);
MAG_ERR("update!sensor_data: %d, %d, %d, %d\n" ,sensor_data[5], sensor_data[6], sensor_data[7], sensor_data[8]);
data[0]= (s16)(sensordata[1] | (sensordata[2] << 8));
data[1]= (s16)(sensordata[3] | (sensordata[4] << 8));
data[2]= (s16)(sensordata[5] | (sensordata[6] << 8));
MAG_ERR("akm09911_m_get_data:%x %x %x", data[0], data[1], data[2]);
// sprintf(rbuf,"%x %x %x", data[0], data[1], data[2]);
mutex_lock(&sensor_data_mutex);
*x= data[0] * CONVERT_M;
*y= data[1] * CONVERT_M;
*z= data[2]* CONVERT_M;
*status= sensordata[8];
MAG_ERR("update!valus222:%d, %d, %d, %d\n" , *x, *y, *z, *status);
mutex_unlock(&sensor_data_mutex);
return0;
}
static int akm09911_o_enable(int en)
{
intvalue = 0;
interr = 0;
value= en;
if(value == 1) {
atomic_set(&o_flag,1);
atomic_set(&open_flag,1);
err= AKECS_SetMode(AK09911_MODE_SNG_MEASURE);
if(err < 0) {
MAG_ERR("%s:AKECS_SetModeError.\n", __func__);
returnerr;
}
}else {
atomic_set(&o_flag,0);
if(atomic_read(&m_flag) == 0) {
atomic_set(&open_flag,0);
err= AKECS_SetMode(AK09911_MODE_POWERDOWN);
if(err < 0) {
MAG_ERR("%s:AKECS_SetModeError.\n", __func__);
returnerr;
}
}
}
wake_up(&open_wq);
returnerr;
}
static int akm09911_o_set_delay(u64 ns)
{
intvalue = 0;
value= (int)ns/1000/1000;
if(value <= 10)
akmd_delay= 10;
else
akmd_delay= value;
return0;
}
static int akm09911_o_open_report_data(intopen)
{
return0;
}
#if 0
static int akm09911_o_get_data(int *x , int*y, int *z, int *status)
{
mutex_lock(&sensor_data_mutex);
*x= sensor_data[13] * CONVERT_M;
*y= sensor_data[14] * CONVERT_M;
*z= sensor_data[15] * CONVERT_M;
*status= sensor_data[8];
mutex_unlock(&sensor_data_mutex);
return0;
}
#endif
static int akm09911_o_get_data(int *x , int*y, int *z, int *status)
{
charsensordata[SENSOR_DATA_SIZE];
s16data[3];
MAG_ERR("%s:akm09911_m_get_dataliyanfei.\n", __func__);
//AKECS_GetRawData(buff,AKM09911_BUFSIZE);
AKECS_SetMode_SngMeasure();
mdelay(10);
AKECS_GetData(sensordata,SENSOR_DATA_SIZE);
MAG_ERR("update!sensordata:%d, %d, %d, %d\n" , sensordata[5], sensordata[6], sensordata[7],sensordata[8]);
MAG_ERR("update!sensor_data: %d, %d, %d, %d\n" ,sensor_data[5], sensor_data[6], sensor_data[7], sensor_data[8]);
data[0]= (s16)(sensordata[1] | (sensordata[2] << 8));
data[1]= (s16)(sensordata[3] | (sensordata[4] << 8));
data[2]= (s16)(sensordata[5] | (sensordata[6] << 8));
MAG_ERR("akm09911_m_get_data:%x %x %x", data[0], data[1], data[2]);
// sprintf(rbuf,"%x %x %x", data[0], data[1], data[2]);
mutex_lock(&sensor_data_mutex);
*x= data[0] * CONVERT_M;
*y= data[1] * CONVERT_M;
*z= data[2]* CONVERT_M;
*status= sensordata[8];
MAG_ERR("update!valus222:%d, %d, %d, %d\n" , *x, *y, *z, *status);
mutex_unlock(&sensor_data_mutex);
return0;
}
/*
设备I2C的PROB,匹配上下面的信息后就会进去。msensor是在DCT里面配置的。
static const structof_device_id mag_of_match[] = {
{.compatible ="mediatek,msensor"},
{},
};
*/
/*----------------------------------------------------------------------------*/
static int akm09911_i2c_probe(structi2c_client *client, const struct i2c_device_id *id)
{
interr = 0;
structi2c_client *new_client;
structakm09911_i2c_data *data;
structmag_control_path ctl = {0};
structmag_data_path mag_data = {0};
MAGN_LOG("akm09911_i2c_probe\n");
data= kzalloc(sizeof(struct akm09911_i2c_data), GFP_KERNEL);
if(!data) {
err= -ENOMEM;
gotoexit;
}
data->hw= hw;
atomic_set(&data->layout,data->hw->direction);
atomic_set(&data->trace,0);
mutex_init(&sense_data_mutex);
mutex_init(&sensor_data_mutex);
/*init_waitqueue_head(&data_ready_wq); */
init_waitqueue_head(&open_wq);
data->client= client;
new_client= data->client;
i2c_set_clientdata(new_client,data);
this_client= new_client;
/*Check connection */
err= AKECS_CheckDevice();
if(err < 0) {
MAG_ERR("AKM09911akm09911_probe: check device connect error\n");
gotoexit_init_failed;
}
/*
注册驱动设备的相关节点,就是上面说明的一些节点信息。
*/
/*Register sysfs attribute */
err= akm09911_create_attr(&(akm09911_init_info.platform_diver_addr->driver));
if(err) {
MAG_ERR("createattribute err = %d\n", err);
gotoexit_sysfs_create_group_failed;
}
/*
注册一个MISC设备,设备位置在:/sys/class/misc/msensor。暂时不知道这个有啥用。
*/
err= misc_register(&akm09911_device);
if(err) {
MAG_ERR("akm09911_deviceregister failed\n");
gotoexit_misc_device_register_failed;
}
ctl.is_use_common_factory= false;
ctl.m_enable= akm09911_m_enable;
ctl.m_set_delay = akm09911_m_set_delay;
ctl.m_open_report_data= akm09911_m_open_report_data;
ctl.o_enable= akm09911_o_enable;
ctl.o_set_delay = akm09911_o_set_delay;
ctl.o_open_report_data= akm09911_o_open_report_data;
ctl.is_report_input_direct= false;
ctl.is_support_batch= data->hw->is_batch_supported;
/*
MTK 平台统一的接口,以方便对具体驱动的管理,这个支持多个相同的SENSOR。
*/
err = mag_register_control_path(&ctl);
if(err) {
MAG_ERR("registermag control path err\n");
gotoexit_kfree;
}
mag_data.div_m= CONVERT_M_DIV;
mag_data.div_o= CONVERT_O_DIV;
mag_data.get_data_o= akm09911_o_get_data;
mag_data.get_data_m= akm09911_m_get_data;
err = mag_register_data_path(&mag_data);
if(err) {
MAG_ERR("registerdata control path err\n");
gotoexit_kfree;
}
MAG_ERR("%s:OK\n", __func__);
akm09911_init_flag= 1;
return0;
exit_sysfs_create_group_failed:
exit_init_failed:
exit_misc_device_register_failed:
exit_kfree:
kfree(data);
exit:
MAG_ERR("%s:err = %d\n", __func__, err);
akm09911_init_flag= -1;
returnerr;
}
/*----------------------------------------------------------------------------*/
static int __init akm09911_init(void)
{
constchar *name = "mediatek,akm09911";
/*
获取akm09911的DTS相关信息。
*/
hw= get_mag_dts_func(name, hw);
if(!hw)
MAGN_ERR("getdts info fail\n");
/*
MTK的接口,在MAG.C中有用到,下面再具体说明。
*/
mag_driver_add(&akm09911_init_info);
return0;
}
module_init(akm09911_init);
module_exit(akm09911_exit);
MODULE_AUTHOR("MTK");
MODULE_DESCRIPTION("AKM09911 compassdriver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRIVER_VERSION);
上面是厂家提供的具体驱动sensor的代码,代码结构大同小异,具体的寄存器操作有差异,到时候可以具体看看DATASHEET或者直接找FAE来协助解决。
下面看看mag.c文档,MTK统一相关的接口。
alps\kernel-3.18\drivers\misc\mediatek\magnetometer\mag.c
......
static void mag_work_func(structwork_struct *work)
{
structmag_context *cxt = NULL;
structhwm_sensor_data sensor_data;
int64_tm_pre_ns, o_pre_ns, cur_ns;
int64_tdelay_ms;
structtimespec time;
interr;
inti;
intx, y, z, status;
cxt = mag_context_obj;
delay_ms= atomic_read(&cxt->delay);
memset(&sensor_data,0, sizeof(sensor_data));
time.tv_sec= time.tv_nsec = 0;
get_monotonic_boottime(&time);
cur_ns= time.tv_sec*1000000000LL+time.tv_nsec;
for(i = 0; i < MAX_M_V_SENSOR; i++) {
if(!(cxt->active_data_sensor&(0x01<<i))) {
MAG_LOG("mag_type(%d) enabled(%d)\n", i, cxt->active_data_sensor);
continue;
}
MAG_LOG("mag_type(%d)liyanfei enabled(%d)\n", i,cxt->active_data_sensor);
if(ID_M_V_MAGNETIC == i) {
/*
获取驱动的数据。
*/
err= cxt->mag_dev_data.get_data_m(&x,&y, &z, &status);
if(err) {
MAG_ERR("get%d data fails!!\n" , i);
return;
}
cxt->drv_data[i].mag_data.values[0]= x;
cxt->drv_data[i].mag_data.values[1]= y;
cxt->drv_data[i].mag_data.values[2]= z;
cxt->drv_data[i].mag_data.status= status;
m_pre_ns= cxt->drv_data[i].mag_data.time;
cxt->drv_data[i].mag_data.time= cur_ns;
if(true == cxt->is_first_data_after_enable) {
m_pre_ns= cur_ns;
cxt->is_first_data_after_enable= false;
/*filter -1 value */
if(MAG_INVALID_VALUE == cxt->drv_data[i].mag_data.values[0] ||
MAG_INVALID_VALUE== cxt->drv_data[i].mag_data.values[1] ||
MAG_INVALID_VALUE== cxt->drv_data[i].mag_data.values[2]) {
MAG_LOG("read invalid data\n");
continue;
}
}
while((cur_ns - m_pre_ns) >= delay_ms*1800000LL) {
m_pre_ns+= delay_ms*1000000LL;
mag_data_report(MAGNETIC,cxt->drv_data[i].mag_data.values[0],
cxt->drv_data[i].mag_data.values[1],
cxt->drv_data[i].mag_data.values[2],
cxt->drv_data[i].mag_data.status,m_pre_ns);
}
/*
通过input_report_XXX的相关接口INPUT接口,向对应INPUT设备中写入数据。
*/
mag_data_report(MAGNETIC,cxt->drv_data[i].mag_data.values[0],
cxt->drv_data[i].mag_data.values[1],
cxt->drv_data[i].mag_data.values[2],
cxt->drv_data[i].mag_data.status,cxt->drv_data[i].mag_data.time);
MAG_LOG("mag_type(%d)data[%d,%d,%d]\n" ,i,cxt->drv_data[i].mag_data.values[0],
cxt->drv_data[i].mag_data.values[1],cxt->drv_data[i].mag_data.values[2]);
}
......
if(true == cxt->is_polling_run)
startTimer(&cxt->hrTimer,atomic_read(&cxt->delay), false);
}
/*
驱动中启用了一个TIMER,不停的再读取数据,然后向上派发。
*/
enum hrtimer_restart mag_poll(structhrtimer *timer)
{
structmag_context *obj = (struct mag_context *)container_of(timer, structmag_context, hrTimer);
queue_work(obj->mag_workqueue,&obj->report);
returnHRTIMER_NORESTART;
}
static struct mag_context*mag_context_alloc_object(void)
{
structmag_context *obj = kzalloc(sizeof(*obj), GFP_KERNEL);
MAG_LOG("mag_context_alloc_object++++\n");
if(!obj) {
MAG_ERR("Allocmagel object error!\n");
returnNULL;
}
atomic_set(&obj->delay,200); /* set work queue delay time 200ms */
atomic_set(&obj->wake,0);
INIT_WORK(&obj->report,mag_work_func);
obj->mag_workqueue= NULL;
obj->mag_workqueue= create_workqueue("mag_polling");
if(!obj->mag_workqueue) {
kfree(obj);
returnNULL;
}
initTimer(&obj->hrTimer,mag_poll);
obj->is_first_data_after_enable= false;
obj->is_polling_run= false;
obj->active_data_sensor= 0;
obj->active_nodata_sensor= 0;
obj->is_batch_enable= false;
mutex_init(&obj->mag_op_mutex);
MAG_LOG("mag_context_alloc_object----\n");
returnobj;
}
/*
打开sensor的时候,需要使能这个设备,最后会调用到这里来。然后调用对应驱动里面具体进行使能操作。
*/
static int mag_enable_data(int handle, intenable)
{
structmag_context *cxt = NULL;
cxt= mag_context_obj;
if(NULL == cxt->drv_obj[handle]&& NULL == cxt->mag_ctl.m_enable) {
MAG_ERR("noreal mag driver\n");
return-1;
}
if(1 == enable) {
MAG_LOG("MAG(%d)enable\n", handle);
cxt->is_first_data_after_enable= true;
cxt->active_data_sensor|= 1<<handle;
if(ID_M_V_ORIENTATION == handle) {
cxt->mag_ctl.o_enable(1);
cxt->mag_ctl.o_open_report_data(1);
}
if(ID_M_V_MAGNETIC == handle) {
cxt->mag_ctl.m_enable(1);
cxt->mag_ctl.m_open_report_data(1);
}
if((0 != cxt->active_data_sensor) && (false == cxt->is_polling_run)&&
(false== cxt->is_batch_enable)) {
if(false == cxt->mag_ctl.is_report_input_direct) {
MAG_LOG("MAG(%d) mod timer\n", handle);
startTimer(&cxt->hrTimer,atomic_read(&cxt->delay), true);
cxt->is_polling_run= true;
}
}
}
if(0 == enable) {
MAG_LOG("MAG(%d)disable\n", handle);
cxt->active_data_sensor&= ~(1<<handle);
if(ID_M_V_ORIENTATION == handle) {
cxt->mag_ctl.o_enable(0);
cxt->mag_ctl.o_open_report_data(0);
}
if(ID_M_V_MAGNETIC == handle) {
cxt->mag_ctl.m_enable(0);
cxt->mag_ctl.m_open_report_data(0);
}
if(0 == cxt->active_data_sensor && true == cxt->is_polling_run) {
if(false == cxt->mag_ctl.is_report_input_direct) {
MAG_LOG("MAG(%d) del timer\n", handle);
cxt->is_polling_run= false;
smp_mb();/*fomemory barrier*/
stopTimer(&cxt->hrTimer);
smp_mb();/*formemory barrier*/
cancel_work_sync(&cxt->report);
cxt->drv_data[handle].mag_data.values[0]= MAG_INVALID_VALUE;
cxt->drv_data[handle].mag_data.values[1]= MAG_INVALID_VALUE;
cxt->drv_data[handle].mag_data.values[2]= MAG_INVALID_VALUE;
}
}
}
return0;
}
.......
int mag_attach(int sensor, structmag_drv_obj *obj)
{
interr = 0;
MAG_FUN();
mag_context_obj->drv_obj[sensor]= kzalloc(sizeof(struct mag_drv_obj), GFP_KERNEL);
if(mag_context_obj->drv_obj[sensor] == NULL) {
err= -EPERM;
MAG_ERR("mag attatch alloc fail\n");
returnerr;
}
memcpy(mag_context_obj->drv_obj[sensor],obj, sizeof(*obj));
if(NULL == mag_context_obj->drv_obj[sensor]) {
err= -1;
MAG_ERR("mag attatch fail\n");
}
returnerr;
}
/*----------------------------------------------------------------------------*/
EXPORT_SYMBOL_GPL(mag_attach);
static int msensor_remove(structplatform_device *pdev)
{
MAG_LOG("msensor_remove\n");
return0;
}
static int msensor_probe(structplatform_device *pdev)
{
MAG_LOG("msensor_probe\n");
return0;
}
#ifdef CONFIG_OF
static const struct of_device_idmsensor_of_match[] = {
{.compatible = "mediatek,msensor", },
{},
};
#endif
static struct platform_drivermsensor_driver = {
.probe =msensor_probe,
.remove = msensor_remove,
.driver= {
.name = "msensor",
#ifdefCONFIG_OF
.of_match_table= msensor_of_match,
#endif
}
};
/*
支持多个SENSOR,这里会调用各个驱动sensor的init,如上面的会调用akm09911_local_init,会进行I2C的通信,如果正常就认为该SENSOR是存在的。
*/
static int mag_real_driver_init(void)
{
inti = 0;
interr = 0;
MAG_LOG("mag_real_driver_init +\n");
for(i = 0; i < MAX_CHOOSE_G_NUM; i++) {
MAG_LOG("i=%d\n", i);
if(0 != msensor_init_list[i]) {
MAG_LOG("mag try to init driver %s\n", msensor_init_list[i]->name);
err= msensor_init_list[i]->init();
if(0 == err) {
MAG_LOG("mag real driver %s probe ok\n", msensor_init_list[i]->name);
break;
}
}
}
if(i == MAX_CHOOSE_G_NUM) {
MAG_LOG("mag_real_driver_init fail\n");
err= -1;
}
returnerr;
}
/*
给具体 sensor提供接口而已。驱动中有调用到。
*/
int mag_driver_add(struct mag_init_info*obj)
{
interr = 0;
inti = 0;
MAG_FUN();
if(!obj) {
MAG_ERR("MAGdriver add fail, mag_init_info is NULL\n");
return-1;
}
for(i = 0; i < MAX_CHOOSE_G_NUM; i++) {
if((i == 0) && (NULL == msensor_init_list[0])) {
MAG_LOG("registermensor driver for the first time\n");
if(platform_driver_register(&msensor_driver))
MAG_ERR("failedto register msensor driver already exist\n");
}
if(NULL == msensor_init_list[i]) {
obj->platform_diver_addr= &msensor_driver;
msensor_init_list[i]= obj;
break;
}
}
if(i >= MAX_CHOOSE_G_NUM) {
MAG_ERR("MAGdriver add err\n");
err= -1;
}
returnerr;
}
EXPORT_SYMBOL_GPL(mag_driver_add);
static int mag_misc_init(struct mag_context*cxt)
{
interr = 0;
cxt->mdev.minor= MISC_DYNAMIC_MINOR;
cxt->mdev.name = MAG_MISC_DEV_NAME;
/*
创建misc节点: /sys/class/misc/m_mag_misc/
相关的MAG节点都挂载在上面。使能的时候就是向下面的节点magactive写入1,然后调用mag_store_active---》mag_enable_data(ID_M_V_MAGNETIC,
1);具体使能对应MAG SENSOR.
*/
err= misc_register(&cxt->mdev);
if(err)
MAG_ERR("unableto register mag misc device!!\n");
returnerr;
}
static int mag_input_init(structmag_context *cxt)
{
structinput_dev *dev;
interr = 0;
dev= input_allocate_device();
if(NULL == dev)
return-ENOMEM;
dev->name= MAG_INPUTDEV_NAME;
input_set_capability(dev,EV_ABS, EVENT_TYPE_MAGEL_X);
input_set_capability(dev,EV_ABS, EVENT_TYPE_MAGEL_Y);
input_set_capability(dev,EV_ABS, EVENT_TYPE_MAGEL_Z);
input_set_capability(dev,EV_ABS, EVENT_TYPE_MAGEL_STATUS);
input_set_capability(dev,EV_REL, EVENT_TYPE_MAGEL_UPDATE);
input_set_capability(dev,EV_REL, EVENT_TYPE_MAG_TIMESTAMP_HI);
input_set_capability(dev,EV_REL, EVENT_TYPE_MAG_TIMESTAMP_LO);
input_set_capability(dev,EV_REL, EVENT_TYPE_ORIENT_UPDATE);
input_set_capability(dev,EV_REL, EVENT_TYPE_ORIENT_TIMESTAMP_HI);
input_set_capability(dev,EV_REL, EVENT_TYPE_ORIENT_TIMESTAMP_LO);
input_set_capability(dev,EV_ABS, EVENT_TYPE_O_X);
input_set_capability(dev,EV_ABS, EVENT_TYPE_O_Y);
input_set_capability(dev,EV_ABS, EVENT_TYPE_O_Z);
input_set_capability(dev,EV_ABS, EVENT_TYPE_O_STATUS);
input_set_capability(dev,EV_REL, EVENT_TYPE_O_UPDATE);
input_set_abs_params(dev,EVENT_TYPE_MAGEL_X, MAG_VALUE_MIN, MAG_VALUE_MAX, 0, 0);
input_set_abs_params(dev,EVENT_TYPE_MAGEL_Y, MAG_VALUE_MIN, MAG_VALUE_MAX, 0, 0);
input_set_abs_params(dev,EVENT_TYPE_MAGEL_Z, MAG_VALUE_MIN, MAG_VALUE_MAX, 0, 0);
input_set_abs_params(dev,EVENT_TYPE_MAGEL_STATUS, MAG_STATUS_MIN, MAG_STATUS_MAX, 0, 0);
input_set_abs_params(dev,EVENT_TYPE_O_X, MAG_VALUE_MIN, MAG_VALUE_MAX, 0, 0);
input_set_abs_params(dev,EVENT_TYPE_O_Y, MAG_VALUE_MIN, MAG_VALUE_MAX, 0, 0);
input_set_abs_params(dev,EVENT_TYPE_O_Z, MAG_VALUE_MIN, MAG_VALUE_MAX, 0, 0);
input_set_abs_params(dev,EVENT_TYPE_O_STATUS, MAG_STATUS_MIN, MAG_STATUS_MAX, 0, 0);
input_set_drvdata(dev,cxt);
/*
注册INPUT设备,上层从/dev/input/eventX获取到数据,也可以用
adb shellgetevnet /dev/input/eventx来看是否有数据输入到INPUT设备中来。
*/
err= input_register_device(dev);
if(err < 0) {
input_free_device(dev);
returnerr;
}
cxt->idev= dev;
return0;
}
DEVICE_ATTR(magdev, S_IWUSR | S_IRUGO, mag_show_magdev, NULL);
DEVICE_ATTR(magactive, S_IWUSR | S_IRUGO, mag_show_active,mag_store_active);
DEVICE_ATTR(magdelay, S_IWUSR | S_IRUGO, mag_show_delay, mag_store_delay);
DEVICE_ATTR(magoactive, S_IWUSR | S_IRUGO, mag_show_oactive,mag_store_oactive);
DEVICE_ATTR(magodelay, S_IWUSR | S_IRUGO, mag_show_odelay, mag_store_odelay);
DEVICE_ATTR(magbatch, S_IWUSR | S_IRUGO, mag_show_batch, mag_store_batch);
DEVICE_ATTR(magflush, S_IWUSR | S_IRUGO, mag_show_flush, mag_store_flush);
DEVICE_ATTR(magobatch, S_IWUSR | S_IRUGO, mag_show_obatch, mag_store_obatch);
DEVICE_ATTR(magoflush, S_IWUSR | S_IRUGO, mag_show_oflush, mag_store_oflush);
DEVICE_ATTR(magdevnum, S_IWUSR | S_IRUGO,mag_show_sensordevnum, NULL);
static struct attribute *mag_attributes[] ={
&dev_attr_magdev.attr,
&dev_attr_magactive.attr,
&dev_attr_magdelay.attr,
&dev_attr_magbatch.attr,
&dev_attr_magflush.attr,
&dev_attr_magoactive.attr,
&dev_attr_magodelay.attr,
&dev_attr_magobatch.attr,
&dev_attr_magoflush.attr,
&dev_attr_magdevnum.attr,
NULL
};
static struct attribute_groupmag_attribute_group = {
.attrs= mag_attributes
};
/*
接口提供
*/
int mag_register_data_path(structmag_data_path *data)
{
structmag_context *cxt = NULL;
cxt= mag_context_obj;
cxt->mag_dev_data.div_m= data->div_m;
cxt->mag_dev_data.div_o= data->div_o;
cxt->mag_dev_data.get_data_m= data->get_data_m;
cxt->mag_dev_data.get_data_o= data->get_data_o;
cxt->mag_dev_data.get_raw_data= data->get_raw_data;
MAG_LOG("magregister data path div_o: %d\n", cxt->mag_dev_data.div_o);
MAG_LOG("magregister data path div_m: %d\n", cxt->mag_dev_data.div_m);
return0;
}
/*
接口提供
*/
int mag_register_control_path(structmag_control_path *ctl)
{
structmag_context *cxt = NULL;
interr = 0;
cxt= mag_context_obj;
cxt->mag_ctl.m_set_delay= ctl->m_set_delay;
cxt->mag_ctl.m_enable= ctl->m_enable;
cxt->mag_ctl.m_open_report_data= ctl->m_open_report_data;
cxt->mag_ctl.o_set_delay= ctl->o_set_delay;
cxt->mag_ctl.o_open_report_data= ctl->o_open_report_data;
cxt->mag_ctl.o_enable= ctl->o_enable;
cxt->mag_ctl.is_report_input_direct= ctl->is_report_input_direct;
cxt->mag_ctl.is_support_batch= ctl->is_support_batch;
cxt->mag_ctl.is_use_common_factory= ctl->is_use_common_factory;
if(NULL == cxt->mag_ctl.m_set_delay || NULL == cxt->mag_ctl.m_enable
||NULL == cxt->mag_ctl.m_open_report_data
||NULL == cxt->mag_ctl.o_set_delay || NULL ==cxt->mag_ctl.o_open_report_data
||NULL == cxt->mag_ctl.o_enable) {
MAG_LOG("magregister control path fail\n");
return-1;
}
/*add misc dev for sensor hal control cmd */
err= mag_misc_init(mag_context_obj);
if(err) {
MAG_ERR("unableto register mag misc device!!\n");
return-2;
}
err= sysfs_create_group(&mag_context_obj->mdev.this_device->kobj,
&mag_attribute_group);
if(err < 0) {
MAG_ERR("unableto create mag attribute file\n");
return-3;
}
kobject_uevent(&mag_context_obj->mdev.this_device->kobj,KOBJ_ADD);
return0;
}
......
int mag_data_report(enum MAG_TYPE type, intx, int y, int z, int status, int64_t nt)
{
structmag_context *cxt = NULL;
MAG_LOG("update!valus:%d, %d, %d, %d\n" , x, y, z, status);
check_repeat_data(x,y, z);
check_abnormal_data(x,y, z, status);
cxt= mag_context_obj;
if(MAGNETIC == type) {
input_report_abs(cxt->idev,EVENT_TYPE_MAGEL_STATUS, status);
input_report_abs(cxt->idev,EVENT_TYPE_MAGEL_X, x);
input_report_abs(cxt->idev,EVENT_TYPE_MAGEL_Y, y);
input_report_abs(cxt->idev,EVENT_TYPE_MAGEL_Z, z);
input_report_rel(cxt->idev,EVENT_TYPE_MAGEL_UPDATE, 1);
input_report_rel(cxt->idev,EVENT_TYPE_MAG_TIMESTAMP_HI, nt >> 32);
input_report_rel(cxt->idev,EVENT_TYPE_MAG_TIMESTAMP_LO, nt & 0xFFFFFFFFLL);
input_sync(cxt->idev);
}
if(ORIENTATION == type) {
input_report_abs(cxt->idev,EVENT_TYPE_O_STATUS, status);
input_report_abs(cxt->idev,EVENT_TYPE_O_X, x);
input_report_abs(cxt->idev,EVENT_TYPE_O_Y, y);
input_report_abs(cxt->idev,EVENT_TYPE_O_Z, z);
input_report_rel(cxt->idev,EVENT_TYPE_O_UPDATE, 1);
input_report_rel(cxt->idev,EVENT_TYPE_ORIENT_TIMESTAMP_HI, nt >> 32);
input_report_rel(cxt->idev,EVENT_TYPE_ORIENT_TIMESTAMP_LO, nt & 0xFFFFFFFFLL);
input_sync(cxt->idev);
}
return0;
}
static int mag_probe(void)
{
interr;
MAG_LOG("+++++++++++++mag_probe!!\n");
mag_context_obj= mag_context_alloc_object();
if(!mag_context_obj) {
err= -ENOMEM;
MAG_ERR("unableto allocate devobj!\n");
gotoexit_alloc_data_failed;
}
/*init real mageleration driver */
err = mag_real_driver_init();
if(err) {
MAG_ERR("mag_real_driver_initfail\n");
gotoexit_alloc_data_failed;
}
err = mag_factory_device_init();
if(err)
MAG_ERR("mag_factory_device_initfail\n");
/*init input dev */
err = mag_input_init(mag_context_obj);
if(err) {
MAG_ERR("unableto register mag input device!\n");
gotoexit_alloc_input_dev_failed;
}
MAG_LOG("----magel_probeOK !!\n");
return0;
exit_alloc_input_dev_failed:
mag_input_destroy(mag_context_obj);
exit_alloc_data_failed:
kfree(mag_context_obj);
MAG_ERR("----magel_probefail !!!\n");
returnerr;
}
。。。。。。
static int __init mag_init(void)
{
MAG_FUN();
if(mag_probe()) {
MAG_ERR("failedto register mag driver\n");
return-ENODEV;
}
return0;
}
static void __exit mag_exit(void)
{
mag_remove();
platform_driver_unregister(&msensor_driver);
}
late_initcall(mag_init);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("MAGELEROMETERdevice driver");
MODULE_AUTHOR("Mediatek");
个人理解:
KERNEL驱动的主要功能是加载相应的驱动代码,完成对SENSOR芯片的初始化工作,当上层发送enable命令来后,芯片进入工作状态,不停通过TIMER读取芯片的数据,然后放入到INPUT系统的节点上面:/dev/input/eventX.供上层调用。
相关文章推荐
- 高通sensor架构实例分析之二(adsp驱动代码结构)
- linux platform设备驱动简介及实例
- NodeJS中MongoDB驱动mongodb使用简介
- Code maturity level options 代码成熟度选项 [*]Prompt for development and/or incomplete code/drivers 显示尚在开发中或尚未完成的代码与驱动.除非你是测试人员或者开发者,否则请勿选择 我是开发者,所以选[*] Loadable module support 可加载模块支持 [*]Enable loadable module support 内核编译配置选项简介 (2.4.20-8
- linux下测试RTC驱动相关的命令date和hwclock常见用法简介
- linux驱动学习--第五天:第四章 Linux 内核模块 之 Linux 内核模块简介
- Docker存储驱动之Device Mapper简介
- Linux内核分析(四)----进程管理|网络子系统|虚拟文件系统|驱动简介
- Linux ALSA声卡驱动之一:ALSA架构简介
- openVR驱动接口之IVRCameraComponent简介
- NDIS LWF网络过滤驱动开发(一):LWF简介及数据结构说明
- i2c 驱动一:简介
- Linux驱动调试的Debugfs的使用简介
- 第 1 章 设备驱动简介
- Active Record 驱动框架:简介
- 高通sensor架构实例分析之二(驱动代码结构)
- 【嵌入式开发】 Linux Kernel 下载 配置 编译 安装 及 驱动简介
- Linux ALSA声卡驱动之一:ALSA架构简介
- usb驱动的基本结构和函数简介
- Docker存储驱动之Btrfs简介