http://blog.csdn.net/suwenqiang_2011/article/details/8620430
G-sensor驱动和TP驱动基本是一样的,因为他们都是通过i2c来传输命令和数据,另外都将数据解析后,上报到输入子系统中。整个驱动的流程和TP驱动是一样的,我还是讲整个驱动流程分析一下。
驱动入口函数:late_initcall(BMA250_init);
进入BMA250_init()函数,开头非常明显定义了三个重要变量
struct i2c_board_info info;
struct i2c_adapter *adapter;
struct i2c_client *client;
紧接着就是info和adapter收集资源,注册i2c_clint,函数为client = i2c_new_device(adapter, &info);接下来是注册i2c_driver,函数为i2c_add_driver(&bma250_driver);根据匹配过程,probe函数被调用,进入到bma250_probe()函数。
bma250_probe()函数开头定义了一个重要的指针,struct bma250_data *data;看到这个,我们会觉得和TP的驱动如此相似,有一点不一样的话,bma250_data结构体中有一个regulator指针,应该可以通过编程控制电源供应。有关regulator的详细资料,可以参考:
http://lhsblog01.blog.163.com/blog/static/1020045192010221104120218/
regulator =regulator_get(&client->dev, buf);
err = regulator_set_voltage(regulator,2800000, 2800000);
err = regulator_enable(regulator);
设置电源管理
接着会检查adapter,分配structbma250_data的空间:
i2c_check_functionality(client->adapter, I2C_FUNC_I2C)
data = kzalloc(sizeof(struct bma250_data), GFP_KERNEL);
然后读取芯片id同时检查i2c能否正常通信
tempvalue= i2c_smbus_read_byte_data(client, BMA250_CHIP_ID_REG);
对structbma250_data结构体进行设置和初始化工作
i2c_set_clientdata(client,data);
data->bma250_client = client;
mutex_init(&data->value_mutex);
mutex_init(&data->mode_mutex);
mutex_init(&data->enable_mutex);
bma250_set_bandwidth(client,BMA250_BW_SET);
bma250_set_range(client,BMA250_RANGE_SET);
INIT_WORK(&data->irq_work,bma250_irq_work_func);
data->IRQ = client->irq;
然后会去注册中断
err= request_irq(data->IRQ, bma250_irq_handler, IRQF_TRIGGER_RISING,
"bma250",data);
接下来我们会发现一个很有趣的代码:
INIT_DELAYED_WORK(&data->work,bma250_work_func);
atomic_set(&data->delay,BMA250_MAX_DELAY);
atomic_set(&data->enable, 0);
这里会去初始化一个延时任务,设置延时时间。
原来在structbma250_data结构体中,有一个work_struct,就是中断处理下半部的任务,同时有一个delayed_work是用来定时上报G-sensor的xyz坐标的,我去查看了bma150中的代码,发现bma150中并没有采用中断的方式,而是直接采用延时任务,应该是bma250添加了中断处理。
还剩下的事情就是输入子系统的申请,绑定和注册了
dev= input_allocate_device();
input_set_drvdata(dev,data);
data->input= dev;
err= input_register_device(dev);
除了在内核中注册中断子系统以外,还要将它映射到用户空间,供用户空间使用,下面这个函数会实现:
err =sysfs_create_group(&data->input->dev.kobj,&bma250_attribute_group);
有关sysfs的更多知识可以参考:
http://blog.csdn.net/suwenqiang2011/article/details/8613818
关于G-sensor的处理流程,我们到中断处理函数bma250_irq_handler()以及延时任务函数bma250_work_func()中去看看就知道了
bma250_irq_handler()的内容仅仅有一个函数
schedule_work(&data->irq_work);
为什么这里和TP驱动中的中断处理函数内容:queue_work(ts->elan_wq,&ts->work);有所不一样呢,原来在TP驱动中,申请了一个工作队列,而G-sensor驱动使用的是默认工作队列,在每个cpu核上,都有一个默认的工作队列。
进入中断下半部,bma250_irq_work_func()主要就是接受数据,解析,然后上报,和TP的流程是一样的。
另外延时任务函数bma250_work_func()的内容也很简单,时间到了就读取G-sensor的当前值,然后上报:
bma250_read_accel_xyz(bma250->bma250_client,&acc);
input_report_abs(bma250->input,ABS_X, acc.x);
input_report_abs(bma250->input,ABS_Y, acc.y);
input_report_abs(bma250->input,ABS_Z, acc.z);
input_sync(bma250->input);
重新调度延时任务:
schedule_delayed_work(&bma250->work,delay);
整个G-sensor驱动的分析就完成了,主要使用到了i2c设备驱动,中断下半部-工作队列,延时任务,中断,输入子系统等知识。