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_