Linux I2c Driver的整体分析

一、i2c driver的组成部分

  I2C驱动由I2C核心、I2C主控制器驱动程序与I2C从设备驱动程序三部分组成。

1、i2c主控制器(adapter):

属于总线驱动程序。对于嵌入式处理器,内部都集成了一个I2C主控制器,其通过I2C与外设进行通信,在通信过程中,作为主设备。I2C主控制器驱动程序一般由CPU厂商完成。

    2、i2c 核心:

由主控制器驱动程序与从设备驱动程度可利用的函数与数据结构组成,其使得从设备驱动独立于主控制器驱动程序。I2C核心的代码由操作系统已经完成,其主要依据为I2C的通信协议。

   3、i2c slave :

挂载在CPUI2C总线的外围设备(如触摸屏,感应器等设备)的驱动程序。在I2C通信过程中,外围设备作为从设备。

除了以上三部分程序外,Linux还支持i2c-dev。它允许在用户模式下实现i2c从设备驱动程序。

二、i2c core

一般Linux驱动的核心层有两部分的工作:一是为某一类设备或者总线设备注册一个class或者bus以统一管理这类设备;另一个是给设备驱动程序或者上层提供一些统一的接口,让驱动程序通过这些接口向核心层注册一个驱动设备。

i2c core第一步就是创建一个bus的设备模型:代码路径:

driver/i2c/i2c-core.c

static int __init i2c_init(void)
{
	int retval;

	retval = bus_register(&i2c_bus_type);
	if (retval)
		return retval;
#ifdef CONFIG_I2C_COMPAT
	i2c_adapter_compat_class = class_compat_register("i2c-adapter");
	if (!i2c_adapter_compat_class) {
		retval = -ENOMEM;
		goto bus_err;
	}
#endif
	retval = i2c_add_driver(&dummy_driver);
	if (retval)
		goto class_err;
	return 0;

class_err:
#ifdef CONFIG_I2C_COMPAT
	class_compat_unregister(i2c_adapter_compat_class);
bus_err:
#endif
	bus_unregister(&i2c_bus_type);
	return retval;
}

bus_type结构的i2c_bus_type定义如下,具体各个成员函数可以查看内核源码

struct bus_type i2c_bus_type = {
	.name		= "i2c",
	.match		= i2c_device_match,
	.probe		= i2c_device_probe,
	.remove		= i2c_device_remove,
	.shutdown	= i2c_device_shutdown,
	.pm		= &i2c_device_pm_ops,
};
EXPORT_SYMBOL_GPL(i2c_bus_type);

i2c_bus_type匹配的规则是i2c slave与slave driver。match函数其匹配的依据i2c slave name与i2c slave driver name。当匹配成功后,会调用i2c_device_probe函数,该probe函数再会调用slave driver中的probe函数。

core 层的流程图如下:


三、i2c adapter

i2c adapter 的核心结构为struct i2c_adapter。其表示一个i2c control,也可以理解为一条i2c bus。

struct i2c_adapter {
	struct module *owner;
	unsigned int class;		  /* classes to allow probing for */
	const struct i2c_algorithm *algo; /*the algorithm to access the bus*/
	void *algo_data;

	/* data fields that are valid for all devices	*/
	struct rt_mutex bus_lock;

	int timeout;			/* in jiffies */
	int retries;
	struct device dev;		/* the adapter device */ 

	int nr;
	char name[48];
	struct completion dev_released;

	struct mutex userspace_clients_lock;
	struct list_head userspace_clients;
};

unsigned int class表示的是i2c adapter所支持的slave的种类,取值如下:

#defineI2C_CLASS_HWMON (1<<0)/* lm_sensors,... */

#defineI2C_CLASS_DDC (1<<3)/* DDC bus ongraphics adapters */

#defineI2C_CLASS_SPD (1<<7)/* Memory modules*/

I2C_CLASS_HWMON:一般i2c主控制器都支持该类型。lm_sensorslinux的一个监控硬件的项目,具体可查看www.lm-sensors.org

I2C_CLASS_DDC:显示器数据通道。DDC(DisplayDataChannel)是一个I2C通道,是PC主机用于访问显示器存储器以获取显示器中EEPROM中的EDID格式数据,确定显示器的显示属性(如分辨率、纵横比等)信息的数据通道。如15针的VGA接口,其12pin15pin可用作i2cSDASDL线。

I2C_CLASS_SPDSPDSerialPresenceDetect)是18针的SOIC封装(3mm*4mm)256字节的EEPROM(ElectricallyErasableProgrammableROM电可擦写可编程只读存储器)芯片。

通常该成员变量都初始化为I2C_CLASS_HWMON

const struct i2c_algorithm *algo:在i2c总线上完成主从设备之间数据通信的算法,i2c的数据传输就是通过该结构去完成的

struct i2c_algorithm {
        int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
                           int num);
        int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr, unsigned short flags, 
               char read_write,u8 command, int size, union i2c_smbus_data *data);
        u32 (*functionality) (struct i2c_adapter *);
};
master_xfer:i2c具体的传输方法,如果不支持直接赋空就行,参数struct i2c_msg表示的是一次传输,一次传输可以包含多个字节,其中包括传输的数据。

include/linux/i2c.h
struct i2c_msg {
        __u16 addr;     /* slave address                        */
        __u16 flags;
#define I2C_M_TEN               0x0010  /* this is a ten bit chip address */
#define I2C_M_RD                0x0001  /* read data, from slave to master */
#define I2C_M_NOSTART           0x4000  /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR      0x2000  /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK        0x1000  /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK         0x0800  /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN          0x0400 /*length will be first received byte*/
        __u16 len;              /* msg length                           */
        __u8 *buf;              /* pointer to msg data                  */
};
      addr:从设备的地址,可取7位或10位,如果是10位的话,flag必须设置为I2C_M_TEN,adapter也必须支持I2C_FUNC_10BIT_ADDR

flags:信息传输标志位,可取值如下:
      I2C_M_TEN:表示地址为10位。

I2C_M_RD:表示是读操作,即从从设备中读取数据到主控制器中。

I2C_M_NOSTART:设置这个标志意味当前i2c_msg不发送start信号。如果一个i2c_msg没有定义I2C_M_NOSTART而且又不是msgs序列里的第一个i2c_msg,则回发送Rs信号。用于Rs的传输方法。
1.msgs序列第一个数据必须是地址,所以必须不定义这个标志位;
2.在进行读数据,当传送数据方法发生改变时,如从写操作转变为读操作时,会发重复start信号,所以不定义这个标志位;
3.其它情况下一的i2c_msg,则应该定义这个标志。

I2C_M_REV_DIR_ADDR:表示把读写标志位反转,也就是读是把相应位置0。

I2C_M_IGNORE_NAK:正常情况下,当接收到NAK信号时,表示停止发送数据。如果设置这个标志,意味把NAK当作ACK信号,则会继续发送数据。

I2C_M_NO_RD_ACK:这个标识表示在进行读操作时,主设备忽略ACK与NAK信号。
      I2C_M_RECV_LEN:将接收数据的长度放在第一字节中。
注意,上面说的读写都是相对主控制器,也就是CPU的I2C控制器而言的。
      len:Number of data bytes in @buf being read from or written to the I2C slave address.

buf:The buffer into which data is read, or from which it's written.

master_xfer中的另一个参数num表示的是要传输的消息个数。

master_xfer实现方法:一般I2C主控制器,只有一个字节大小的寄存器来循环传输数据,通常做法是将一次传递的消息保存到内存变量中,然后初始化I2C主控制器,发送开始第一个字节数据(包括从设备地址与数据传输方向)到数据寄存器中,接着等待I2C主控制器中断的发生(表示一个字节数据传输完成),在中断中,向数据寄存器写入下一个要传输的数据或者从数据寄存器读数据。

smbus_xfer:SMBus的传输的方法,如果为空,其将采用master_xfer的传输方法。

functionality:i2c主控制器支持的功能。支持的功能可取的值有:

#define I2C_FUNC_I2C                    0x00000001
#define I2C_FUNC_10BIT_ADDR             0x00000002
#define I2C_FUNC_PROTOCOL_MANGLING      0x00000004 /* I2C_M_NOSTART etc. */
#define I2C_FUNC_SMBUS_PEC              0x00000008
#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL  0x00008000 /* SMBus 2.0 */
#define I2C_FUNC_SMBUS_QUICK            0x00010000
#define I2C_FUNC_SMBUS_READ_BYTE        0x00020000
#define I2C_FUNC_SMBUS_WRITE_BYTE       0x00040000
#define I2C_FUNC_SMBUS_READ_BYTE_DATA   0x00080000
#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA  0x00100000
#define I2C_FUNC_SMBUS_READ_WORD_DATA   0x00200000
#define I2C_FUNC_SMBUS_WRITE_WORD_DATA  0x00400000
#define I2C_FUNC_SMBUS_PROC_CALL        0x00800000
#define I2C_FUNC_SMBUS_READ_BLOCK_DATA  0x01000000
#define 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值