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

本文详细介绍了在MT6753平台上,针对MSENSOR:AKM09911磁力计的驱动实现。驱动代码包括了I2C通信接口、电源管理、数据读取等功能,通过这些接口与硬件设备交互,获取传感器数据。驱动还包含了设备节点创建、ioctl接口以及错误处理等细节。
摘要由CSDN通过智能技术生成

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_

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值