IIC设备驱动实例
来源:互联网 发布:html5影视cms系统 编辑:程序博客网 时间:2024/06/05 09:49
前面转载了很多关于i2c的文章,做完一个项目了,也该自己写点i2c心得了,我这个可是纯应用角度的,想看原理的,去看转载的文章,人家写的好多了! 对于一个i2c设备来说,其设备文件是最简单也是最复杂的,说它简单是因为很设备厂商会提供linux下的代码,这样就简单了;但是也有很多厂商它不提供或不完整提供linux下的代码,这样的话当然就复杂了。那么这个我现在这里就不说了,下面说说做了几个I2C设备(以ISA1200为例)后发现,不管设备文件如何总是要自己来做的一些事情,这大概就是所谓的移植吧。 当然这个工作都是在板文件中进行的。以mach-s5pv210.c为例来说一下: 先说下用板子自己带的I2C实现驱动加载:首先在板文件中建立ISA1200的信息:static int isa1200_power(int on){ if(on){ gpio_direction_output(S5PV210_GPJ3(1), 1); gpio_direction_output(S5PV210_GPJ3(0), 1); }else{ gpio_direction_output(S5PV210_GPJ3(1), 0); gpio_direction_output(S5PV210_GPJ3(0), 0); } return 0;}static struct isa1200_platform_data isa1200_1_pdata = { .name = "isa1200", .power_on = isa1200_power, .pwm_ch_id = 1, .hap_en_gpio = S5PV210_GPH3(1), .max_timeout = 60000,};static void isa1200_init(void){ gpio_direction_output(S5PV210_GPJ3(7), 1); gpio_direction_output(S5PV210_GPJ3(1), 1); gpio_direction_output(S5PV210_GPJ3(0), 1); /*i2c_register_board_info(3, isa1200_board_info, ARRAY_SIZE(isa1200_board_info));*/ return;}以及i2c_board_info结构体: { I2C_BOARD_INFO("isa1200_1", 0x90>>1),/*这个是I2C设备的从机地址*/ .platform_data = &isa1200_1_pdata, },然后在以下三个I2C总线中找到一条如i2c_devs1[]/* I2C0 */static struct i2c_board_info i2c_devs0[] __initdata = { { I2C_BOARD_INFO("act8937", 0x5B), .platform_data = &act8937_platform_data, }, { I2C_BOARD_INFO("wm8580", 0x1b), },};/* I2C1 */static struct i2c_board_info i2c_devs1[] __initdata = {#ifdef CONFIG_VIDEO_TV20 { I2C_BOARD_INFO("s5p_ddc", (0x74>>1)), },#endif};/* I2C2 */static struct i2c_board_info i2c_devs2[] __initdata = {#ifdef CONFIG_REGULATOR_MAX8698 { /* The address is 0xCC used since SRAD = 0 */ I2C_BOARD_INFO("max8698", (0xCC >> 1)), .platform_data = &max8698_platform_data, },#endif将i2c_board_info往里一填/* I2C1 */static struct i2c_board_info i2c_devs1[] __initdata = {#ifdef CONFIG_VIDEO_TV20 { I2C_BOARD_INFO("s5p_ddc", (0x74>>1)), }, { I2C_BOARD_INFO("isa1200_1", 0x90>>1),/*这个是I2C设备的从机地址*/ .platform_data = &isa1200_1_pdata, },#endif};这就算是把ISA1200挂接到了 I2C1上了,自己所做的事情也就完成了。接下来就是总线自己的事了:首先它会把自己再加入到platform_device中,也就是注册到platform_device 总线上:static struct platform_device *smdkv210_devices[] __initdata = {…… &s3c_device_i2c1,……}再在设备初始化中加入I2C1总线 的i2c_register_board_info让它把总线I2C1上的设备(也就是注册到i2c_board_info i2c_devs1[] 上的所有设备)加入I2C1列表。static void __init smdkv210_machine_init(void){…… i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));……}下面再说说GPIO模拟I2C实现驱动加载:这里最重要的当然是成功的注册一个i2c_gpio_w380:首先是找到CLK和SDA对应GPIO口:CLK:GPA1[3]SDA:GPA1[2]然后建立i2c-gpio的platform_device结构体:static struct i2c_gpio_platform_data i2c_gpio_w380_data = { .scl_pin = S5PV210_GPA1(3), .sda_pin = S5PV210_GPA1(2),};static struct platform_device i2c_gpio_w380= { .name = "i2c-gpio",/*这个名字要和I2c-gpio.c里platform_driver里的名字要一致,换句话说这个gpio的i2c要用的driver是I2c-gpio中实现的定义的*/ .id = 3,/*这个编号要顺系统原有的0,1,2写下来,再有一个要用4,依此递推*/ .dev = { .platform_data = &i2c_gpio_w380_data, },};完成了这些也就是完成了将两个GPIO口注册为一个I2C总线的工作。接下来就和板子自己带的I2C实现驱动加载的方法一样了:首先也是在板文件中建立ISA1200的信息:static int isa1200_power(int on){ if(on){ gpio_direction_output(S5PV210_GPJ3(1), 1); gpio_direction_output(S5PV210_GPJ3(0), 1); }else{ gpio_direction_output(S5PV210_GPJ3(1), 0); gpio_direction_output(S5PV210_GPJ3(0), 0); } return 0;}static struct isa1200_platform_data isa1200_1_pdata = { .name = "isa1200", .power_on = isa1200_power, .pwm_ch_id = 1, .hap_en_gpio = S5PV210_GPH3(1), .max_timeout = 60000,};static void isa1200_init(void){ gpio_direction_output(S5PV210_GPJ3(1), 1); gpio_direction_output(S5PV210_GPJ3(0), 1); /*i2c_register_board_info(3, isa1200_board_info, ARRAY_SIZE(isa1200_board_info));*/ return;}以及i2c_board_info结构体: { I2C_BOARD_INFO("isa1200_1", 0x90>>1),/*这个是I2C设备的从机地址*/ .platform_data = &isa1200_1_pdata, },然后在i2c_gpio_w380总线中加入一条isa1200的i2c_board_info[]/* I2C-GPIO*/static struct i2c_board_info i2c_devs3[] __initdata= { { I2C_BOARD_INFO("isa1200_1", 0x90>>1), .platform_data = &isa1200_1_pdata, },};这就算是把ISA1200挂接到了i2c_gpio_w380上了,自己所做的事情也就完成了。接下来就是总线自己的事了:首先它会把自己i2c_gpio_w380再加入到platform_device中,也就是注册到platform_device 总线上:static struct platform_device *smdkv210_devices[] __initdata = {…… &i2c_gpio_w380,……}再在设备初始化中加入i2c_gpio_w380总线的i2c_register_board_info让它把总线i2c_gpio_w380上的设备(也就是注册到i2c_board_info i2c_devs3[] 上的所有设备)加入i2c_gpio_w380的列表。static void __init smdkv210_machine_init(void){…… i2c_register_board_info(3, i2c_devs3, ARRAY_SIZE(i2c_devs3));……}以上也就是完了把一个设备ISA1200挂接在GPIO模拟的I2C总线i2c_gpio_w380上了。到这里设备ISA1200的设备文件isa1200.c里就可以通过调用i2c的i2c_smbus_write_byte_data,i2c_smbus_read_byte_data等函数了。如又要把两个GPIO口再做成I2C总线注册成一个i2c_gpio_w380_1:首先是找到CLK和SDA对应GPIO口:CLK:GPC0[1]SDA:GPC0[2],可以这样做:static struct i2c_gpio_platform_data i2c_gpio_w380_1_data= { .sda_pin = S5PV210_GPC0(2), .scl_pin = S5PV210_GPC0(1),};static struct platform_device i2c_gpio_w380_1= { .name = "i2c-gpio",/*还是用了i2c-gpio的驱动*/ .id = 4, /* 上面注册了3,顺延到了4*/ .dev = { .platform_data = &i2c_gpio_w380_1_data, }}; static struct i2c_board_info i2c_devs4[] __initdata= { { I2C_BOARD_INFO("al3000", ADDRESS), },};static struct platform_device *smdkv210_devices[] __initdata = {…… &i2c_gpio_w380_1,……}static void __init smdkv210_machine_init(void){…… i2c_register_board_info(4, i2c_devs4, ARRAY_SIZE(i2c_devs4));……}另还有一种是用gpio来模拟i2c时序,它就是单独在设备文件中完成的!如:/*****stop previous seccession and generate START seccession *********************/void I2C_start(void) { set_I2C_SCL_high(); set_I2C_SDA_low(); set_I2C_SDA_output(); // SDA = 0; set_I2C_SDA_high(); // SDA = 1, Stop previous I2C r/w action set_I2C_SDA_low(); // I2C Start Condition}/***************** generate I2C Repeat Start **************/void RepeatStart(void){ set_I2C_SCL_low(); set_I2C_SDA_high(); set_I2C_SDA_output(); set_I2C_SCL_high(); set_I2C_SDA_low(); }/********************* generate I2C STOP ******************/void I2C_stop(void) { set_I2C_SCL_low(); set_I2C_SDA_low(); set_I2C_SDA_output(); set_I2C_SCL_high(); set_I2C_SDA_high();} /*************** Test Slave Device Acknowledge status ********************/unsigned char slave_ack(void){ set_I2C_SDA_input(); // SDA Input set_I2C_SCL_high(); // Test Acknowledge if (I2C_SDA_PIN) return(FALSE); // return error if no acknowledge from slave device else return(TRUE); // return ok if got acknowledge from slave device}/*************** send Ack to Slave Device ********************/void master_ack(void) { set_I2C_SDA_high(); set_I2C_SDA_output(); set_I2C_SCL_high();}直接用GPIO口模拟I2C时序和利用内核模块i2c-gpio虚拟i2c总线的区别:1. 用GPIO口模拟I2C时序不需要在系统启动时注册I2C总线,只需要在I2C设备驱动中单独实现。用i2c-gpio模块虚拟i2c总线需要在系统启动时注册新的I2C总线,并将i2c设备挂载到新的i2c总线,涉及的范围较广。2. 用GPIO口模拟I2C时序,代码操作较繁琐,且不方便挂载多个i2c设备。用i2c-gpio模块可以完全模拟i2c总线,可以挂载多个设备。3. 在i2c读写操作时,用GPIO口模拟I2C时序需要每次根据读/写操作发送器件地址<<1+1/0,然后再发送寄存器地址。用i2c-gpio模块相当于直接在i2c总线上操作,在系统启动挂载i2c设备时已经告诉了i2c总线它的地址,在该设备自己的驱动中,只需要通过i2c_add_driver操作即可以得到其地址等诸多信息,读写操作只需要发送寄存器地址即可。
0 0
- IIC设备驱动实例
- Linux设备驱动 IIC驱动
- Linux IIC驱动实例
- IIC设备驱动程序(十)————IIC总线驱动实现实例
- linux中的IIC设备驱动
- linux中的IIC设备驱动
- Linux IIC设备驱动剖析
- 简单的IIC驱动实例
- Linux IIC驱动学习实例
- 简单的IIC驱动实例(脱离IIC驱动架构)
- Linux-IIC驱动(4)-自编IIC设备驱动程序
- 基于字符设备的IIC驱动源代码
- Linux中IIC设备驱动再细读
- RT-thread 设备驱动组件之IIC总线设备
- 完整的IIC总线驱动和设备驱动装载过程
- 设备驱动实例
- 字符设备驱动实例
- Linux设备驱动实例
- Android之WebView仿微信中图片操作(含二维码识别)
- smb协议读写远程文件
- LeetCode:Maximum Product of Word Lengths
- 简易自定义seg与tableview联动布局
- CakePHP控制器向视图传值总结
- IIC设备驱动实例
- Cannot assign to 'self' outside of a method in the init family
- SourceTree 使用教程
- 做北京linux培训哪家好?
- Android:进度条
- 常用网址
- c#值类型,引用类型
- JAVA设计模式之:观察者模式
- 第一个MapReduce案例集群模式&本地模式