linux之i2c子系统架构

 

总线驱动

4.1 概述

I2C总线驱动是I2C适配器的软件实现,提供I2C适配器与从设备间完成数据通信的能力,比如起始,停止,应答信号和master_xfer的实现函数。

I2C总线驱动由i2c_adapter和i2c_algorithm来描述

4.2 S3c2440I2C控制器的硬件描述

S3c2440处理器内部集成了一个I2C控制器,通过四个寄存器来进行控制:

IICCON     I2C控制寄存器

IICSTAT     I2C状态寄存器

IICDS       I2C收发数据移位寄存器

IICADD     I2C地址寄存器

通过IICCON,IICDS,IICADD寄存器操作,可在I2C总线上产生开始位、停止位、数据和地址,而传输的状态则通过IICSTAT寄存器来获取。

4.3 i2c-s3c2410总线驱动分析(platform_driver)

I2C总线驱动代码在drivers/i2c/busses/i2c-s3c2410.c,这个代码同样支持s3c2410,s3c6410,s5pc110等Samsung 系列的芯片。

初始化模块和卸载模块

[cpp] view plaincopy

  1. static int __init i2c_adap_s3c_init(void)
  2. {
  3. returnplatform_driver_register(&s3c24xx_i2c_driver);
  4. }
  5. static void __exit i2c_adap_s3c_exit(void)
  6. {
  7. platform_driver_unregister(&s3c24xx_i2c_driver);
  8. }

总线驱动是基于platform来实现的,很符合设备驱动模型的思想。

[cpp] view plaincopy

  1. static struct platform_drivers3c24xx_i2c_driver = {
  2. .probe                = s3c24xx_i2c_probe,
  3. .remove            = s3c24xx_i2c_remove,
  4. .id_table  = s3c24xx_driver_ids,
  5. .driver                = {
  6. .owner     = THIS_MODULE,
  7. .name       = "s3c-i2c",
  8. .pm  = S3C24XX_DEV_PM_OPS,
  9. .of_match_table= s3c24xx_i2c_match,
  10. },
  11. };

s3c24xx_i2c_probe函数

当调用platform_driver_register函数注册platform_driver结构体时,如果platformdevice 和 platform driver匹配成功后,会调用probe函数,来初始化适配器硬件。

[cpp] view plaincopy

  1. static int s3c24xx_i2c_probe(structplatform_device *pdev)
  2. {
  3. ……
  4. /*初始化适配器信息 */
  5. strlcpy(i2c->adap.name,"s3c2410-i2c", sizeof(i2c->adap.name));
  6. i2c->adap.owner   = THIS_MODULE;
  7. i2c->adap.algo    = &s3c24xx_i2c_algorithm;
  8. i2c->adap.retries= 2;
  9. i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;
  10. i2c->tx_setup     = 50;
  11. /*初始化自旋锁和等待队列头 */
  12. spin_lock_init(&i2c->lock);
  13. init_waitqueue_head(&i2c->wait);
  14. /*映射寄存器 */
  15. res= platform_get_resource(pdev, IORESOURCE_MEM, 0);
  16. i2c->ioarea= request_mem_region(res->start, resource_size(res),
  17. pdev->name);
  18. i2c->regs= ioremap(res->start, resource_size(res));
  19. /*设置I2C核心需要的信息 */
  20. i2c->adap.algo_data= i2c;
  21. i2c->adap.dev.parent= &pdev->dev;
  22. /*初始化I2C控制器 */
  23. ret= s3c24xx_i2c_init(i2c);
  24. /*申请中断 */
  25. i2c->irq= ret = platform_get_irq(pdev, 0);
  26. ret= request_irq(i2c->irq, s3c24xx_i2c_irq, 0,
  27. dev_name(&pdev->dev), i2c);
  28. /* 注册I2C适配器 */
  29. ret= i2c_add_numbered_adapter(&i2c->adap);
  30. ……
  31. }

Probe主要工作是时能硬件并申请I2C适配器使用的IO地址,中断号等,然后向I2C核心添加这个适配器。I2c_adapter注册过程i2c_add_numbered_adapter->i2c_register_adapter

I2C总线通信方法

[cpp] view plaincopy

  1. static const struct i2c_algorithms3c24xx_i2c_algorithm = {
  2. .master_xfer             = s3c24xx_i2c_xfer,
  3. .functionality             = s3c24xx_i2c_func,
  4. };

s3c24xx_i2c_xfer函数是总线通信方式的具体实现,依赖于s3c24xx_i2c_doxfer和s3c24xx_i2c_message_start两个函数;

[cpp] view plaincopy

  1. static int s3c24xx_i2c_doxfer(structs3c24xx_i2c *i2c,
  2. struct i2c_msg *msgs, int num)
  3. {
  4. ret =s3c24xx_i2c_set_master(i2c);
  5. i2c->msg     = msgs;
  6. i2c->msg_num= num;
  7. i2c->msg_ptr= 0;
  8. i2c->msg_idx= 0;
  9. i2c->state   = STATE_START;
  10. s3c24xx_i2c_message_start(i2c,msgs);
  11. }

首先设置s3c I2C设备器为主设备,然后调用s3c24xx_i2c_message_start函数启动I2C消息传输。

s3c24xx_i2c_func函数返回适配器所支持的通信功能。

4.4 适配器的设备资源(platform_device)

S3c2440的I2C总线驱动是基于platform来实现,前面我们分析了platformdriver部分,再来看下platform device部分。

在arch/arm/plat-samsung/dev-i2c0.c文件中定义了platform_device结构体以及I2C控制器的资源信息:

[cpp] view plaincopy

  1. static struct resource s3c_i2c_resource[] ={
  2. [0]= {
  3. .start= S3C_PA_IIC,
  4. .end   = S3C_PA_IIC + SZ_4K - 1,
  5. .flags= IORESOURCE_MEM,
  6. },
  7. [1]= {
  8. .start= IRQ_IIC,
  9. .end  = IRQ_IIC,
  10. .flags= IORESOURCE_IRQ,
  11. },
  12. };
  13. struct platform_device s3c_device_i2c0 = {
  14. .name                 = "s3c2410-i2c",   /* 设备名 */
  15. #ifdef CONFIG_S3C_DEV_I2C1
  16. .id               = 0,
  17. #else
  18. .id               = -1,
  19. #endif
  20. .num_resources         =ARRAY_SIZE(s3c_i2c_resource),
  21. .resource   =s3c_i2c_resource,
  22. };
  23. struct s3c2410_platform_i2cdefault_i2c_data __initdata = {
  24. .flags                  = 0,
  25. .slave_addr      = 0x10,  /* I2C适配器的地址 */
  26. .frequency        = 100*1000,  /* 总线频率 */
  27. .sda_delay        = 100,   /* SDA边沿延迟时间ns */
  28. };
  29. void __init s3c_i2c0_set_platdata(structs3c2410_platform_i2c *pd)
  30. {
  31. structs3c2410_platform_i2c *npd;
  32. if(!pd)
  33. pd= &default_i2c_data;
  34. npd= s3c_set_platdata(pd, sizeof(struct s3c2410_platform_i2c),
  35. &s3c_device_i2c0);
  36. if(!npd->cfg_gpio)
  37. npd->cfg_gpio= s3c_i2c0_cfg_gpio;
  38. }

在板文件中把platform_device注册进内核:

[cpp] view plaincopy

  1. static struct platform_device*mini2440_devices[] __initdata = {
  2. ……
  3. &s3c_device_i2c0,
  4. ……
  5. };

调用s3c_i2c0_set_platdata 函数把适配器具体的数据赋值给dev.platform_data:

[cpp] view plaincopy

  1. static void __init mini2440_init(void)
  2. {
  3. ……
  4. s3c_i2c0_set_platdata(NULL);
  5. }

I2C总线驱动就分析到这里。

时间: 2025-01-02 16:15:15

linux之i2c子系统架构的相关文章

linux内核I2C子系统学习(三)

写设备驱动: 四部曲: 构建i2c_driver 注册i2c_driver 构建i2c_client ( 第一种方法:注册字符设备驱动.第二种方法:通过板文件的i2c_board_info填充,然后注册) 注销i2c_driver 具体如下: ●    构建i2c_driver static struct i2c_driver pca953x_driver = {                 .driver = {                                     .n

嵌入式Linux内核I2C子系统详解

1.1 I2C总线知识 1.1.1  I2C总线物理拓扑结构     I2C总线在物理连接上非常简单,分别由SDA(串行数据线)和SCL(串行时钟线)及上拉电阻组成.通信原理是通过对SCL和SDA线高低电平时序的控制,来产生I2C总线协议所需要的信号进行数据的传递.在总线空闲状态时,这两根线一般被上面所接的上拉电阻拉高,保持着高电平. 1.1.2  I2C总线特征    I2C总线上的每一个设备都可以作为主设备或者从设备,而且每一个设备都会对应一个唯一的地址(可以从I2C器件的数据手册得知),主

Linux usb子系统(一):子系统架构

摘自:http://www.360doc.com/content/15/0519/05/22854460_471598740.shtml 摘自:https://www.cnblogs.com/cslunatic/p/3726053.html Linux usb子系统(一):子系统架构 一.USB协议基础知识   前序:USB概念概述 USB1.0版本速度1.5Mbps(低速USB) USB1.1版本速度12Mbps(全速USB)  USB2.0版本速度480Mbps(高速USB). USB 分为

linux驱动之i2c子系统device注册driver注册简单分析

Linux 驱动设计主要是根据分层分离思想,i2c子系统分为i2cocre.adapter.及device_driver层,其实adapter也是个device,只不过是我们主控芯片的I2C控制接口而已,我们的主控芯片有几个I2C接口就有几个adapter; i2ccore这一层linux已经帮我们实现,主要的工做是类似platform总线的作用,负责drvier及设备的注册,相比platform多了个adapter的注册管理工作,以及i2c的数据发送接收等等算法,说算法有点夸大,其实就是按照i

Linux的操作系统I2C驱动架构解说

Linux的操作系统I2C驱动架构解说 发布时间:2006.10.16 04:52 来源:赛迪网技术社区 作者:LoneStar 最近因为工作需要涉及到了I2C总线.虽然我过去用过I2c,但看了 Linux kernel 后才发现,一个 layer 能被做到这样完善. 1.Linux的I2C驱动架 Linux中I2C总线的驱动分为两个部分,总线驱动(BUS)和设备驱动(DEVICE).其中总线驱动的职责,是为系统中每个I2C总线增加相应的读写方法.但是总线驱动本身并不会进行任何的通讯,它只是存在

关于linux input device输入子系统架构及android中的框架

关于linux input device输入子系统架构及android中的框架 应用app和windowmanagerservice的input event通信方式 在Native层的InputChannel就是一个通道,仅仅是一个通道,仅仅具有通信功能,不包含其他的.至于从数据流动方向,与InputChannel无关.数据流向是由InputPublisher和InputConsumer在组合了InputChannel后决定的.把InputChannel由应用程序传递到WindowManageS

Linux的i2c驱动详解

目录(?)[-] 简介 架构 设备注册 I2C关键数据结构和详细注册流程 关键数据结构 详细注册流程 使用I2C子系统资源函数操作I2C设备 Gpio模拟i2c总线的通用传输算法 总结 理清i2c中的个结构体关系 i2c驱动的编写建议 1 简介 I2C 总线仅仅使用 SCL . SDA 两根信号线就实现了设备之间的数据交互,极大地简化对硬件资源和 PCB 板布线空间的占用.因此, I2C 总线被非常广泛地应用在 EEPROM .实时钟.小型 LCD 等设备与 CPU 的接口中. Linux I2

Linux kernel中断子系统之(五):驱动申请中断API

一.前言 本文主要的议题是作为一个普通的驱动工程师,在撰写自己负责的驱动的时候,如何向Linux Kernel中的中断子系统注册中断处理函数?为了理解注册中断的接口,必须了解一些中断线程化(threaded interrupt handler)的基础知识,这些在第二章描述.第三章主要描述了驱动申请 interrupt line接口API request_threaded_irq的规格.第四章是进入request_threaded_irq的实现细节,分析整个代码的执行过程. 二.和中断相关的lin

深入解析Linux内核及其相关架构的依赖关系

Linux kernel 成功的两个原因: 灵活的架构设计使得大量的志愿开发者能够很容易加入到开发过程中:每个子系统(尤其是那些需要改进的)都具备良好的可扩展性.正是这两个原因使得Linux kernel可以不断进化和改进. 一.Linux内核在整个计算机系统中的位置 分层结构的原则: the dependencies between subsystems are from the top down: layers pictured near the top depend on lower la