android 驱动 三轴加速器
时间:10-02
整理:3721RD
点击:
第一次发帖,有点小激动的说
1、本驱动采用的是Device Tree这种数据结构来描述硬件信息关于DeviceTree的说明
http://wenku.baidu.com/view/5f867ce6102de2bd960588b8.html
sensor驱动大致流程:
http://blog.csdn.net/zclongembedded/article/details/8216651
本驱动中该文件信息:
使用Device Tree后,驱动需要与.dts中描述的设备结点进行匹配,从而引发驱动的 probe()函数执行。对于platform_driver而言,需要添加一个OF匹配表:
static struct of_device_id kxtj9_match_table[] = {
{ .compatible = "kionix,kxtj9", },
{ },
};
宏:module_I2C_driver(Kxtj9_driver);
相当于:
static __init int Kxtj9_init(void)
{
return i2c_add_driver(&Kxtj9_driver);
}
static __exit void Kxtj9_exit(void)
{
i2c_del_driver(&Kxtj9_driver);
}
module_init(Kxtj9_init);
module_exit(Kxtj9_exit);
i2c_add_driver和i2c_del_driver函数都是定于在i2c-core.c中的,属于i2c核心范围。
××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
匹配成功后开始kxtj9_probe函数的执行:
1、i2c_check_functionality(CLIent->adapter,I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA))
判定适配器的能力。目前设配器主要支持两种传输方法:smbus_xfer和master_xfer。一般来说,如果设配器支持了master_xfer那么它也可以模拟支持smbus的传输。
=======================================================================================================
2、tj9 = kzalloc(sizeof(*tj9), GFP_KERNEL);
为Kxtj9_data类型的结构体分配空间
=======================================================================================================
3、if (client->dev.of_node)
kxtj9_parse_dt(&client->dev, &tj9->pdata);
该函数是从.dtsi文件中获取板级资源:
rc = of_property_read_u32(np, "kionix,axis-map-y", &temp_val);
将读取设备结点np的属性名为propname,类型为8、16、32、64位整型数组的属性。对于32位处理器来讲,最常用的是of_property_read_u32_array()。具体操作可查阅上述关于DeviceTree(设备树)的说明链接。
if (client->dev.platform_data)
tj9->pdata = *(struct kxtj9_platform_data *)client->dev.platform_data;
如果找不到设备树节点,那么将去找设备结构体信息,直接赋值
======================================================================================================
4、
tj9->client = client;
tj9->power_enabled = false;
tj9->pdata.init(); //这句不是很明白,并未找到该函数指针所指向的函数
kxtj9_power_init(tj9, true);
kxtj9_device_power_on(tj9);
kxtj9_verify(tj9); //retval = i2c_smbus_read_byte_data(tj9->client, WHO_AM_I);从设备指定偏移处(0x0F)处读取一个字节。
以上是硬件的初始化
=======================================================================================================
5、i2c_set_clientdata(client, tj9);
把tj9这个data以私有的数据存放于client中。
=======================================================================================================
6、tj9->ctrl_reg1 = tj9->pdata.res_ctl | tj9->pdata.g_range;
tj9->last_poll_interval = tj9->pdata.init_interval;
从kxtj9_parse_dt(&client->dev, &tj9->pdata)函数中得到
tj9->pdata.g-range值为 KXTJ9_G_2G(宏值为0)
tj9->pdata.res_ctl值为 RES_12BIT(宏值为1<<6)
tj9->pdata.init_interval值为200
=> tj9->ctrl_reg1 = 1<<6; tj9->last_poll_interval = 200;
=======================================================================================================
7、if (client->irq) // 如果采用中断模式,则做以下处理:
tj9->int_ctrl |= KXTJ9_IEN | KXTJ9_IEA | KXTJ9_IEL;
tj9->ctrl_reg1 |= DRDYE; // 寄存器配置,设置中断模式?数值可算出,但具体操作不清楚
kxtj9_setup_input_device(tj9); // input子系统的注册及其参数设置,具体如下方框函数实现
————————————————————————————————————————————
| input_dev = input_allocate_device(); //申请一个新的input设备,即为一个input_dev申请内存空间 |
| tj9->input_dev = input_dev; |
| input_set_drvdata(input_dev, tj9); //把data数据以私有的数据存放于input_dev中方便以后调用 |
| kxtj9_init_input_device(tj9, input_dev); //设置input设备支持的数据类型 |
| input_register_device(tj9->input_dev); //向input子系统注册 |
————————————————————————————————————————————
request_threaded_irq(client->irq, NULL, kxtj9_isr, //申请中断,中断处理函数名kxtj9_isr,上升沿触发
IRQF_TRIGGER_RISING | IRQF_ONESHOT, "kxtj9-irq", tj9);
sysfs_create_group(&client->dev.kobj, &kxtj9_attribute_group);//将设备体创建到相关guoup组主要为调试使用
中断处理函数static irqreturn_t kxtj9_isr(int irq, void *dev)操作说明
————————————————————————————————————————————————
| kxtj9_report_acceleration_data(tj9); //数据上报,里面数据如何读取和操作 |
| err = kxtj9_i2c_read(tj9, XOUT_L, (u8 *)acc_data, 6); //从寄存器XOUT_L中读取6个字节长度的数组 |
| x = le16_to_cpu(acc_data[tj9->pdata.axis_map_x]); // 端序的转换 |
| input_report_abs(tj9->input_dev, ABS_X, tj9->pdata.negate_x ? -x : x); //上报x轴的绝对数值 |
| input_sync(tj9->input_dev); //同步input子系统数据
| err = i2c_smbus_read_byte_data(tj9->client, INT_REL) //读取INT_REL数据,判断中断状态 |
————————————————————————————————————————————————
========================================================================================================
8、err = kxtj9_setup_polled_device(tj9); //如果没有中断,则执行轮询POLL 机制
poll_dev = input_allocate_polled_device(); //申请一个轮询input设备,即为一个input_dev申请内存空间
tj9->poll_dev = poll_dev;
tj9->input_dev = poll_dev->input;
poll_dev->private = tj9;
poll_dev->poll = kxtj9_poll; //轮询设备操作,实现轮询上报数据。轮询机制资料还未查到
poll_dev->open = kxtj9_polled_input_open; //配置寄存器,使能器件
poll_dev->close = kxtj9_polled_input_close; //关闭器件
kxtj9_init_input_device(tj9, poll_dev->input); //设置input设备支持的数据类型
err = input_register_polled_device(poll_dev); //轮询poll机制注册
对于没有中断功能的GPIO,可能需要一个定时器来轮询其输入状态,不过,系统还准备了另外一个结构体用于此种键盘方式:
struct input_polled_dev;
并使用input_allocate_polled_device();来初始化其指针。
其中两个比较重要的成员:
poll:查询的函数
poll_interval:查询间隔,以毫秒为单位。
最后,调用input_register_polled_device()来注册该驱动。
至此,probe函数执行完毕
========================================================================================================================
另说明:
static DEVICE_ATTR(poll_delay, S_IRUGO|S_IWUSR|S_IWGRP,
kxtj9_get_poll_delay, kxtj9_set_poll_delay);
static DEVICE_ATTR(poll_delay, S_IRUGO|S_IWUSR|S_IWGRP,
kxtj9_get_poll_delay, kxtj9_set_poll_delay);
static struct attribute *kxtj9_attributes[] = {
&dev_attr_enable.attr,
&dev_attr_poll_delay.attr,
NULL
};
error = sysfs_create_group(input- dev.kobj input_polldev attribute_group)
error = sysfs_create_group(&client->dev.kobj, &kxtj9_attribute_group);
关于sysfs接口函数的说明链接:
http://blog.csdn.net/string19820108/article/details/7283079
1、本驱动采用的是Device Tree这种数据结构来描述硬件信息关于DeviceTree的说明
http://wenku.baidu.com/view/5f867ce6102de2bd960588b8.html
sensor驱动大致流程:
http://blog.csdn.net/zclongembedded/article/details/8216651
本驱动中该文件信息:
使用Device Tree后,驱动需要与.dts中描述的设备结点进行匹配,从而引发驱动的 probe()函数执行。对于platform_driver而言,需要添加一个OF匹配表:
static struct of_device_id kxtj9_match_table[] = {
{ .compatible = "kionix,kxtj9", },
{ },
};
宏:module_I2C_driver(Kxtj9_driver);
相当于:
static __init int Kxtj9_init(void)
{
return i2c_add_driver(&Kxtj9_driver);
}
static __exit void Kxtj9_exit(void)
{
i2c_del_driver(&Kxtj9_driver);
}
module_init(Kxtj9_init);
module_exit(Kxtj9_exit);
i2c_add_driver和i2c_del_driver函数都是定于在i2c-core.c中的,属于i2c核心范围。
××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
匹配成功后开始kxtj9_probe函数的执行:
1、i2c_check_functionality(CLIent->adapter,I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA))
判定适配器的能力。目前设配器主要支持两种传输方法:smbus_xfer和master_xfer。一般来说,如果设配器支持了master_xfer那么它也可以模拟支持smbus的传输。
=======================================================================================================
2、tj9 = kzalloc(sizeof(*tj9), GFP_KERNEL);
为Kxtj9_data类型的结构体分配空间
=======================================================================================================
3、if (client->dev.of_node)
kxtj9_parse_dt(&client->dev, &tj9->pdata);
该函数是从.dtsi文件中获取板级资源:
rc = of_property_read_u32(np, "kionix,axis-map-y", &temp_val);
将读取设备结点np的属性名为propname,类型为8、16、32、64位整型数组的属性。对于32位处理器来讲,最常用的是of_property_read_u32_array()。具体操作可查阅上述关于DeviceTree(设备树)的说明链接。
if (client->dev.platform_data)
tj9->pdata = *(struct kxtj9_platform_data *)client->dev.platform_data;
如果找不到设备树节点,那么将去找设备结构体信息,直接赋值
======================================================================================================
4、
tj9->client = client;
tj9->power_enabled = false;
tj9->pdata.init(); //这句不是很明白,并未找到该函数指针所指向的函数
kxtj9_power_init(tj9, true);
kxtj9_device_power_on(tj9);
kxtj9_verify(tj9); //retval = i2c_smbus_read_byte_data(tj9->client, WHO_AM_I);从设备指定偏移处(0x0F)处读取一个字节。
以上是硬件的初始化
=======================================================================================================
5、i2c_set_clientdata(client, tj9);
把tj9这个data以私有的数据存放于client中。
=======================================================================================================
6、tj9->ctrl_reg1 = tj9->pdata.res_ctl | tj9->pdata.g_range;
tj9->last_poll_interval = tj9->pdata.init_interval;
从kxtj9_parse_dt(&client->dev, &tj9->pdata)函数中得到
tj9->pdata.g-range值为 KXTJ9_G_2G(宏值为0)
tj9->pdata.res_ctl值为 RES_12BIT(宏值为1<<6)
tj9->pdata.init_interval值为200
=> tj9->ctrl_reg1 = 1<<6; tj9->last_poll_interval = 200;
=======================================================================================================
7、if (client->irq) // 如果采用中断模式,则做以下处理:
tj9->int_ctrl |= KXTJ9_IEN | KXTJ9_IEA | KXTJ9_IEL;
tj9->ctrl_reg1 |= DRDYE; // 寄存器配置,设置中断模式?数值可算出,但具体操作不清楚
kxtj9_setup_input_device(tj9); // input子系统的注册及其参数设置,具体如下方框函数实现
————————————————————————————————————————————
| input_dev = input_allocate_device(); //申请一个新的input设备,即为一个input_dev申请内存空间 |
| tj9->input_dev = input_dev; |
| input_set_drvdata(input_dev, tj9); //把data数据以私有的数据存放于input_dev中方便以后调用 |
| kxtj9_init_input_device(tj9, input_dev); //设置input设备支持的数据类型 |
| input_register_device(tj9->input_dev); //向input子系统注册 |
————————————————————————————————————————————
request_threaded_irq(client->irq, NULL, kxtj9_isr, //申请中断,中断处理函数名kxtj9_isr,上升沿触发
IRQF_TRIGGER_RISING | IRQF_ONESHOT, "kxtj9-irq", tj9);
sysfs_create_group(&client->dev.kobj, &kxtj9_attribute_group);//将设备体创建到相关guoup组主要为调试使用
中断处理函数static irqreturn_t kxtj9_isr(int irq, void *dev)操作说明
————————————————————————————————————————————————
| kxtj9_report_acceleration_data(tj9); //数据上报,里面数据如何读取和操作 |
| err = kxtj9_i2c_read(tj9, XOUT_L, (u8 *)acc_data, 6); //从寄存器XOUT_L中读取6个字节长度的数组 |
| x = le16_to_cpu(acc_data[tj9->pdata.axis_map_x]); // 端序的转换 |
| input_report_abs(tj9->input_dev, ABS_X, tj9->pdata.negate_x ? -x : x); //上报x轴的绝对数值 |
| input_sync(tj9->input_dev); //同步input子系统数据
| err = i2c_smbus_read_byte_data(tj9->client, INT_REL) //读取INT_REL数据,判断中断状态 |
————————————————————————————————————————————————
========================================================================================================
8、err = kxtj9_setup_polled_device(tj9); //如果没有中断,则执行轮询POLL 机制
poll_dev = input_allocate_polled_device(); //申请一个轮询input设备,即为一个input_dev申请内存空间
tj9->poll_dev = poll_dev;
tj9->input_dev = poll_dev->input;
poll_dev->private = tj9;
poll_dev->poll = kxtj9_poll; //轮询设备操作,实现轮询上报数据。轮询机制资料还未查到
poll_dev->open = kxtj9_polled_input_open; //配置寄存器,使能器件
poll_dev->close = kxtj9_polled_input_close; //关闭器件
kxtj9_init_input_device(tj9, poll_dev->input); //设置input设备支持的数据类型
err = input_register_polled_device(poll_dev); //轮询poll机制注册
对于没有中断功能的GPIO,可能需要一个定时器来轮询其输入状态,不过,系统还准备了另外一个结构体用于此种键盘方式:
struct input_polled_dev;
并使用input_allocate_polled_device();来初始化其指针。
其中两个比较重要的成员:
poll:查询的函数
poll_interval:查询间隔,以毫秒为单位。
最后,调用input_register_polled_device()来注册该驱动。
至此,probe函数执行完毕
========================================================================================================================
另说明:
static DEVICE_ATTR(poll_delay, S_IRUGO|S_IWUSR|S_IWGRP,
kxtj9_get_poll_delay, kxtj9_set_poll_delay);
static DEVICE_ATTR(poll_delay, S_IRUGO|S_IWUSR|S_IWGRP,
kxtj9_get_poll_delay, kxtj9_set_poll_delay);
static struct attribute *kxtj9_attributes[] = {
&dev_attr_enable.attr,
&dev_attr_poll_delay.attr,
NULL
};
error = sysfs_create_group(input- dev.kobj input_polldev attribute_group)
error = sysfs_create_group(&client->dev.kobj, &kxtj9_attribute_group);
关于sysfs接口函数的说明链接:
http://blog.csdn.net/string19820108/article/details/7283079
关于sysfs接口函数的说明链接:
http://blog.csdn.net/string19820108/article/details/7283079
这个已经打不开了。
不错,好东西
http://www.cnblogs.com/superlcc/archive/2012/08/08/2628290.html可以网上搜的,都差不多
一直很佩服那些抢沙发的人
支持原创。