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<
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< 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< 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.供上层调用。