Linux_I2C设备驱动文件操作接口_第1页
Linux_I2C设备驱动文件操作接口_第2页
Linux_I2C设备驱动文件操作接口_第3页
Linux_I2C设备驱动文件操作接口_第4页
已阅读5页,还剩26页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、精品文档I2C 适配器驱动被作为一个单独的模块被加载进内核,在模块的加载和卸载函数中, 只需注册和注销一个platform_driver结构体,如代码清单 15.25 。代码清单 15.25 S3C2410 I2C 总线驱动模块加载与卸载1 static int _init i2c_adap_s3c_init(void)2 3 int ret;45 ret = platform_driver_register(&s3c2410_i2c_driver);6 if (ret = 0) 7 ret = platform_driver_register(&s3c2440_i2c_driver);8if

2、 (ret)9platform_driver_unregister(&s3c2410_i2c_driver);10 1112 return ret;13 1415 static void _exit i2c_adap_s3c_exit(void)16 17 platform_driver_unregister(&s3c2410_i2c_driver);18 platform_driver_unregister(&s3c2440_i2c_driver);.精品文档19 20 module_init(i2c_adap_s3c_init);21 module_exit(i2c_adap_s3c_ex

3、it);platform_driver结构体包含了具体适配器的probe() 函数、 remove()函数、 resume() 函数指针等信息,它需要被定义和赋值,如代码清单15.26 。代码清单 15.26 platform_driver结构体1 static struct platform_driver s3c2410_i2c_driver = 2.probe= s3c24xx_i2c_probe,3.remove= s3c24xx_i2c_remove,4.resume= s3c24xx_i2c_resume,5.driver= 6.owner = THIS_MODULE,7.name

4、= s3c2410-i2c,8,9;当 通过 Linux内核源代码 /drivers/base/platform.c文件中定义platform_driver_unregister()函数注 册 platform_driver结构体时,其中 probe 指针指向的 s3c24xx_i2c_probe()函数将被调用以初始化适配器硬件,如代码清单 15.27 。代码清单 15.27 S3C2410 I2C 总线驱动中的s3c24xx_i2c_probe函数1 static int s3c24xx_i2c_probe(struct platform_device *pdev).精品文档2 3 str

5、uct s3c24xx_i2c *i2c = &s3c24xx_i2c;4 struct resource *res;5 int ret;67 /*使能 I2C 的时钟 */8 i2c-dev = &pdev-dev;9 i2c-clk = clk_get(&pdev-dev, i2c);10 if (IS_ERR(i2c-clk) 11 dev_err(&pdev-dev, cannot get clockn);12 ret = -ENOENT;13 goto out;14 15 clk_enable(i2c-clk);1617 /*映射寄存器 */18 res = platform_get

6、_resource(pdev, IORESOURCE_MEM, 0);19 if (res = NULL) 20 dev_err(&pdev-dev, cannot find IO resourcen);21 ret = -ENOENT;22 goto out;23 .精品文档24 i2c-ioarea = request_mem_region(res-start, (res-end-res-start)+1,25pdev-name);26 if (i2c-ioarea = NULL) 27 dev_err(&pdev-dev, cannot request IOn);28 ret = -EN

7、XIO;29 goto out;30 3132 i2c-regs = ioremap(res-start, (res-end-res-start)+1);33 if (i2c-regs = NULL) 34 dev_err(&pdev-dev, cannot map IOn);35 ret = -ENXIO;36 goto out;37 3839 /*设置 I2C 的信息块 */40 i2c-adap.algo_data = i2c;41 i2c-adap.dev.parent = &pdev-dev;4243 /*初始化 I2C 控制器 */44 ret = s3c24xx_i2c_init

8、(i2c);.精品文档45 if (ret != 0)46 goto out;4748 /* 申请中断 */49 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);50 if (res = NULL) 51 ret = -ENOENT;52 goto out;53 54 ret= request_irq(res-start,s3c24xx_i2c_irq,SA_INTERRUPT,55pdev-name, i2c);56 if (ret != 0) 57 goto out;58 59 i2c-irq = res;6061 ret = i2

9、c_add_adapter(&i2c-adap); /*添加 i2c_adapter*/62 if (ret 0) 63goto out;64 6566 platform_set_drvdata(pdev, i2c);.精品文档6768 out:69 if (ret algo_data;5 int retry;6 int ret;78 for (retry = 0; retry retries; retry+) 9 ret = s3c24xx_i2c_doxfer(i2c, msgs, num);10 if (ret != -EAGAIN)11return ret;.精品文档12 udelay

10、(100);13 1415 return -EREMOTEIO;16 1718 staticint s3c24xx_i2c_doxfer(structs3c24xx_i2c *i2c, structi2c_msg *msgs, int num)19 20 unsigned long timeout;21 int ret;2223 ret = s3c24xx_i2c_set_master(i2c);24 if (ret != 0) 25ret = -EAGAIN;26goto out;27 2829 spin_lock_irq(&i2c-lock);30 i2c-msg= msgs;31 i2c

11、-msg_num = num;32 i2c-msg_ptr = 0;.精品文档33 i2c-msg_idx = 0;34 i2c-state= STATE_START;35 s3c24xx_i2c_enable_irq(i2c);36 s3c24xx_i2c_message_start(i2c, msgs);37 spin_unlock_irq(&i2c-lock);3839 timeout= wait_event_timeout(i2c-wait,i2c-msg_num = 0, HZ* 5);4041 ret = i2c-msg_idx;4243 if (timeout = 0)44 de

12、v_dbg(i2c-dev, timeoutn);45 else if (ret != num)46 dev_dbg(i2c-dev, incomplete xfer (%d)n, ret);4748 msleep(1);/*确保停止位已经被传递*/4950 out:51 return ret;52 53.精品文档54 staticvoid s3c24xx_i2c_message_start(structs3c24xx_i2c *i2c,55struct i2c_msg *msg)56 57 unsigned int addr = (msg-addr & 0x7f) flags & I2C_M

13、_RD) 65 stat |= S3C2410_IICSTAT_MASTER_RX;66 addr |= 1;67 else68 stat |= S3C2410_IICSTAT_MASTER_TX;69 if (msg-flags & I2C_M_REV_DIR_ADDR)70 addr = 1;7172 s3c24xx_i2c_enable_ack(i2c);/*如果要使能 ACK,则使能 */7374 iiccon = readl(i2c-regs + S3C2410_IICCON);75 writel(stat, i2c-regs + S3C2410_IICSTAT);.精品文档76 w

14、riteb(addr, i2c-regs + S3C2410_IICDS);7778 udelay(1);/*在发送新的开始位前延迟1 位*/79 writel(iiccon, i2c-regs + S3C2410_IICCON);80 stat |= S3C2410_IICSTAT_START;81 writel(stat, i2c-regs + S3C2410_IICSTAT);82 s3c24xx_i2c_xfer()函数调用 s3c24xx_i2c_doxfer()函数传输 I2C 消息,第 8 行的循环意味着最多可以重试adap-retries次。s3c24xx_i2c_doxfer

15、()首先将 S3C2410的 I2C 适配器设置为 I2C 主设备,其后初始化 s3c24xx_i2c 结构体,使能I2C 中断,并调用s3c24xx_i2c_message_start()函数启动 I2C 消息的传输。s3c24xx_i2c_message_start()函数写 S3C2410适配器对应的控制寄存器向 I2C 从设备传递开始位和从设备地址。上 述代码只是启动了I2C 消息数组的传输周期,并没有完整实现图15.3 中给出的 algorithmmaster_xfer流程。这个流程的完整实现需要借助 I2C 适配器上的中断来步步推进。代码清单15.32 给出了 S3C2410I2C

16、 适配器中断处理函数以及其依赖的i2s_s3c_irq_nextbyte()函数的源代码。代码清单 15.32 S3C2410 I2C 适配器中断处理函数1static irqreturn_ts3c24xx_i2c_irq(intirqno, void *dev_id,2struct pt_regs *regs).精品文档3 4 struct s3c24xx_i2c *i2c = dev_id;5 unsigned long status;6 unsigned long tmp;78 status = readl(i2c-regs + S3C2410_IICSTAT);9 if (status

17、 & S3C2410_IICSTAT_ARBITR) 10 .11 1213 if (i2c-state = STATE_IDLE) 14 tmp = readl(i2c-regs + S3C2410_IICCON);15 tmp &= S3C2410_IICCON_IRQPEND;16 writel(tmp, i2c-regs + S3C2410_IICCON);17 goto out;18 1920 i2s_s3c_irq_nextbyte(i2c, status);/*把传输工作进一步推进*/2122out:23 return IRQ_HANDLED;.精品文档24 2526 stati

18、c int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)27 28 unsigned long tmp;29 unsigned char byte;30 int ret = 0;3132 switch (i2c-state) 33 case STATE_IDLE:34 goto out;35 break;36 case STATE_STOP:37 s3c24xx_i2c_disable_irq(i2c);38 goto out_ack;39 case STATE_START:40 /* 我们最近做的一件

19、事是启动一个新 I2C 消息 */41 if (iicstat & S3C2410_IICSTAT_LASTBIT &42!(i2c-msg-flags & I2C_M_IGNORE_NAK) 43/* 没有收到 ACK */44s3c24xx_i2c_stop(i2c, -EREMOTEIO);.精品文档45goto out_ack;46 4748 if (i2c-msg-flags & I2C_M_RD)49i2c-state = STATE_READ;50else51i2c-state = STATE_WRITE;5253 /* 仅一条消息, 而且长度为 0(主要用于适配器探测) ,发送

20、停止位 */54 if (is_lastmsg(i2c) & i2c-msg-len = 0) 55s3c24xx_i2c_stop(i2c, 0);56goto out_ack;57 5859 if (i2c-state = STATE_READ)60goto prepare_read;61 /* 进入写状态 */62 case STATE_WRITE:63 retry_write:64 if (!is_msgend(i2c) 65byte = i2c-msg-bufi2c-msg_ptr+;.精品文档66writeb(byte, i2c-regs + S3C2410_IICDS);6768

21、 else if (!is_lastmsg(i2c) 69 /* 推进到下一条消息 */70i2c-msg_ptr = 0;71i2c-msg_idx +;72i2c-msg+;7374/*检查是否要为该消息产生开始位 */75if (i2c-msg-flags & I2C_M_NOSTART) 76if (i2c-msg-flags & I2C_M_RD) 77s3c24xx_i2c_stop(i2c, -EINVAL);7879goto retry_write;80 else 81/*发送新的开始位 */82s3c24xx_i2c_message_start(i2c, i2c-msg);8

22、3i2c-state = STATE_START;8485 else 86s3c24xx_i2c_stop(i2c, 0);/* send stop */87.精品文档88 break;89 case STATE_READ:90 /* 有一个字节可读,看是否还有消息要处理*/91 if (!(i2c-msg-flags & I2C_M_IGNORE_NAK) &92!(is_msglast(i2c) & is_lastmsg(i2c) 9394if (iicstat & S3C2410_IICSTAT_LASTBIT) 95dev_dbg(i2c-dev, READ: No Ackn);969

23、7s3c24xx_i2c_stop(i2c, -ECONNREFUSED);98goto out_ack;99100 101 byte = readb(i2c-regs + S3C2410_IICDS);102 i2c-msg-bufi2c-msg_ptr+ = byte;103104 prepare_read:105 if (is_msglast(i2c) /* last byte of buffer */106if (is_lastmsg(i2c)107s3c24xx_i2c_disable_ack(i2c);108109 else if (is_msgend(i2c) .精品文档110/

24、*还有消息要处理吗 ? */111if (is_lastmsg(i2c) 112s3c24xx_i2c_stop(i2c,0);/* last message, send stopand complete */113 else 114/*推进到下一条消息 */115i2c-msg_ptr = 0;116i2c-msg_idx+;117i2c-msg+;118119 120 break;121 122123 /* irq清除 */124 out_ack:125 tmp = readl(i2c-regs + S3C2410_IICCON);126 tmp &= S3C2410_IICCON_IRQ

25、PEND;127 writel(tmp, i2c-regs + S3C2410_IICCON);128 out:129 return ret;130 .精品文档中 断处理函数 s3c24xx_i2c_irq()主要通过调用i2s_s3c_irq_nextbyte()函数进行传输工作的进一步推进。i2s_s3c_irq_nextbyte() 函数通过 switch(i2c-state) 语句分成 i2c-state 的不同状态进行处 理,在每种状态下, 先检查 i2c-state的状态与硬件寄存器应该处于的状态是否一致,如果不一致,则证明有误,直接返回。当I2C 处于读状态 STATE_READ

26、或写状态 STATE_WRITE时,通过 is_lastmsg()函数判断是否传输的是最后一条I2C 消息,如果是,则产生停止位,否则通过 i2c-msg_idx+ 、i2c-msg+ 推进到下一条消息。15.6 实例: SAA7113H视频 AD芯片 I2C 设备驱动15.6.1 SAA7113H 视频 AD芯片硬件描述如图 15.9 ,SAA7113H是飞利浦半导体推出的9 位视频 AD芯片,它可以选择 4 路视频输入中的1 路,并采样为 9 位的数字信号。图 15.9 SAA7113H 输入、输出与 I2C 接口对 SAA7113H输入通道的选择以及采样方式的设置都需通过其I2C 接口进

27、行,以 0x4A 地址可读 SAA7113H寄存器,以 0x4B 可写 SAA7113H寄存器。SAA7113H的 I2C 接口连接在 S3C2410的 I2C 控制器上,作为 S3C2410I2C 控制器的从设备。 SAA7113H的写时序与图15.7 给出的写时序是一致的,但是读时序则需通过2 条 I2C 消息解决,在第 1 条消息中应该给SAA7113H写入寄存器子地址,如图15.10 。.精品文档图 15.10 SAA7113H 读时序15.6.2 SAA7113H 视频 AD芯片驱动模块加载与卸载由于不需要给SAA7113H实现文件操作接口,在设备驱动模块的加载和卸载函数中均不再需要

28、注册和注销字符设备的操作,代码清单 15.33 给出了 SAA7113H设备驱动模块加载和卸载的源代码。代码清单 15.33 SAA7113H设备驱动模块加载和卸载函数1 static int _init saa711x_init (void)2 3return i2c_add_driver(&i2c_driver_saa711x); /注册i2c_driver4 56 static void _exit saa711x_exit (void)7 8i2c_del_driver(&i2c_driver_saa711x); /注销 i2c_driver9 1011 module_init(saa

29、711x_init);12 module_exit(saa711x_exit);15.6.3 SAA7113H 设备驱动 i2c_driver成员函数如 代码清单 15.34 ,SAA7113H设备驱动模块加载和卸载中添加和删除的 i2c_driver_saa711x结构体的 attach_adapter指针被赋值为.精品文档saa711x_attach_adapter,detach_client指针被赋值为saa711x_detach_client,而 command指针被赋值为saa711x_command,代码清单 15.35 给出了这 3 个函数的实现。代码清单 15.34 SAA71

30、13H设备驱动 i2c_driver结构体1 static struct i2c_driver i2c_driver_saa711x = 2 .driver = 3 .name = saa711x,4 ,5 .id = I2C_DRIVERID_SAA711X,6 /* 成员函数 */7 .attach_adapter = saa711x_attach_adapter,8 .detach_client = saa711x_detach_client,9 .command = saa711x_command,10 ;代码清单 15.35 SAA7113H设备驱动 i2c_driver成员函数1

31、saa711x_attach_adapter (struct i2c_adapter *adapter)2 3 dprintk(1,KERN_INFOsaa711x.c:startingprobe foradapter %s(0x%x)n,4 I2C_NAME(adapter), adapter-id);56 returni2c_probe(adapter,&addr_data,&saa711x_detect_client);.精品文档7/saa711x_detect_client会调用 i2c_set_clientdata()、i2c_attach_client()8910 staticin

32、tsaa711x_detach_client(structi2c_client *client)11 12 struct saa711x *decoder = i2c_get_clientdata(client);13 int err;1415 err = i2c_detach_client(client);16 if (err) 17 return err;18 1920 kfree(decoder);21 kfree(client);2223 return 0;24 2526 static int saa711x_command(struct i2c_client *client, uns

33、igned int cmd, void.精品文档27 *arg)28 29 struct saa711x *decoder = i2c_get_clientdata(client);3031switch (cmd) /处理不同的命令3233case 0:34case DECODER_INIT:35.36case DECODER_DUMP:37.38case DECODER_GET_CAPABILITIES:39.40case DECODER_GET_STATUS:41.42case DECODER_SET_VBI_BYPASS:43.44case DECODER_SET_NORM:45.46case DECODER_SET_INPUT:4748int *iarg = arg;.精品文档49if (*

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论