SENSOR------驱动简介:

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;

}

 

/*

设备I2CPROB,匹配上下面的信息后就会进去。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";

/*

获取akm09911DTS相关信息。

*/

         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,这里会调用各个驱动sensorinit,如上面的会调用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学习)