linux-I2C驱动
来源:互联网 发布:flash游戏数据抓取 编辑:程序博客网 时间:2024/06/14 20:14
I2C体系结构
linux的I2C体系结构分为3个组成部分:
(1) I2C核心。提供I2C总线驱动和设备驱动的注册和注销方法。
(2) I2C总线驱动。对适配器端的实现。
(3) I2C设备驱动。设备端的实现。
整个体系架构如图:
I2C设备在sysfs文件系统中显示在sys/bus/i2c目录,例如:
理解i2c体系结构,首先要理解i2c_driver、i2c_client、i2c_adapter和i2c_algorithm这四个数据结构。这四个数据结构均在i2c.h在定义:
struct i2c_driver {unsigned int class;/* Notifies the driver that a new bus has appeared. You should avoid * using this, it will be removed in a near future. */int (*attach_adapter)(struct i2c_adapter *) __deprecated;/* Standard driver model interfaces */int (*probe)(struct i2c_client *, const struct i2c_device_id *);int (*remove)(struct i2c_client *);/* driver model interfaces that don't relate to enumeration */void (*shutdown)(struct i2c_client *);int (*suspend)(struct i2c_client *, pm_message_t mesg);int (*resume)(struct i2c_client *);/* Alert callback, for example for the SMBus alert protocol. * The format and meaning of the data value depends on the protocol. * For the SMBus alert protocol, there is a single bit of data passed * as the alert response's low bit ("event flag"). */void (*alert)(struct i2c_client *, unsigned int data);/* a ioctl like command that can be used to perform specific functions * with the device. */int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);struct device_driver driver;const struct i2c_device_id *id_table;/* Device detection callback for automatic device creation */int (*detect)(struct i2c_client *, struct i2c_board_info *);const unsigned short *address_list;struct list_head clients;};
struct i2c_client {unsigned short flags;/* div., see below*/unsigned short addr;/* chip address - NOTE: 7bit*//* addresses are stored in the*//* _LOWER_ 7 bits*/char name[I2C_NAME_SIZE];struct i2c_adapter *adapter;/* the adapter we sit on*/struct device dev;/* the device structure*/int irq;/* irq issued by device*/struct list_head detected;};
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;struct i2c_bus_recovery_info *bus_recovery_info;};
struct i2c_algorithm {/* If an adapter algorithm can't do I2C-level access, set master_xfer to NULL. If an adapter algorithm can do SMBus access, set smbus_xfer. If set to NULL, the SMBus protocol is simulated using common I2C messages *//* master_xfer should return the number of messages successfully processed, or a negative value on error */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);/* To determine what the adapter supports */u32 (*functionality) (struct i2c_adapter *);};
看代码,稍作分析:
1. i2c_adapter对应物理上一个适配器,而i2c_algorithm对应一套通信方法。一个i2c适配器需要i2c_algorithm中提供的通信函数来控制适配器上产生特定的访问周期。i2c_algorithm中关键函数master_xfer用于产生i2c访问周期需要的信号,以i2c_msg为单位。
2. i2c_driver对应一套驱动方法,辅助作用的数据结构,不对应任何物理实体。i2c_client对应于真实的物理设备,每个i2c设备都需要一个i2c_client来描述。i2c_driver的attach_adapter函数运行时将i2c_driver和i2c_client关联起来。
3. i2c_adapter和i2c_client的关系与i2c硬件体系中适配器和设备的关系一致,即i2c_client依附于i2c_adapter。
I2C核心
i2c核心中提供了一组不依赖于硬件平台的接口函数,具体可以查看dirvers/i2c/i2c-core.c文件。主要是增加删除i2c_driver和增加删除i2c_adapter,i2c传输发送接收等。主要功能函数必须看代码理解,不太需要我们自己去改。
I2C总线驱动
适配器的加载主要是初始化i2c适配器所使用的硬件资源,如申请I/O地址、中断后等,通过i2c_add_adapter添加i2c_adapter数据结构。卸载工作则与之相反。
i2c适配器通信方法,我们需要根据特定的适配器实现i2c_algorithm中的master_xfer方法,master_xfer方法用于传输i2c消息,内核源码中有很多可以参考的实例,这里摘取一个:
static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num){struct saa7164_i2c *bus = i2c_adap->algo_data;struct saa7164_dev *dev = bus->dev;int i, retval = 0;dprintk(DBGLVL_I2C, "%s(num = %d)\n", __func__, num);for (i = 0 ; i < num; i++) {dprintk(DBGLVL_I2C, "%s(num = %d) addr = 0x%02x len = 0x%x\n",__func__, num, msgs[i].addr, msgs[i].len);if (msgs[i].flags & I2C_M_RD) {/* Unsupported - Yet*/printk(KERN_ERR "%s() Unsupported - Yet\n", __func__);continue;} else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) && msgs[i].addr == msgs[i + 1].addr) {/* write then read from same address */retval = saa7164_api_i2c_read(bus, msgs[i].addr,msgs[i].len, msgs[i].buf,msgs[i+1].len, msgs[i+1].buf);i++;if (retval < 0)goto err;} else {/* write */retval = saa7164_api_i2c_write(bus, msgs[i].addr,msgs[i].len, msgs[i].buf);}if (retval < 0)goto err;}return num;err:return retval;}
I2C设备驱动
i2c设备驱动需要使用i2c_driver和i2c_client数据结构并填充其中的成员函数。
i2c驱动的注册加载,仍然从源码中摘取一段,看看:
static struct i2c_driver adnp_i2c_driver = {.driver = {.name = "gpio-adnp",.owner = THIS_MODULE,.of_match_table = adnp_of_match,},.probe = adnp_i2c_probe,.remove = adnp_i2c_remove,.id_table = adnp_i2c_id,};
i2c设备的注册,直接看代码:
int saa7164_i2c_register(struct saa7164_i2c *bus){struct saa7164_dev *dev = bus->dev;dprintk(DBGLVL_I2C, "%s(bus = %d)\n", __func__, bus->nr);bus->i2c_adap = saa7164_i2c_adap_template;bus->i2c_client = saa7164_i2c_client_template;bus->i2c_adap.dev.parent = &dev->pci->dev;strlcpy(bus->i2c_adap.name, bus->dev->name,sizeof(bus->i2c_adap.name));bus->i2c_adap.algo_data = bus;i2c_set_adapdata(&bus->i2c_adap, bus);i2c_add_adapter(&bus->i2c_adap);bus->i2c_client.adapter = &bus->i2c_adap;if (0 != bus->i2c_rc)printk(KERN_ERR "%s: i2c bus %d register FAILED\n",dev->name, bus->nr);return bus->i2c_rc;}
剩下的就是提供文件接口了。
总得说来,我们需要完成i2c适配器的硬件驱动、探测等,根据特定的传输规则实现algorithm中的master_xfer方法,实现设备与驱动的接口,attach_adapter。最后实现i2c设备驱动的文件操作接口。
这些理论还是通过实例会理解的更深刻一些。i2c的实例很普遍,还是通过实例学习好一些。改日通过一个显示屏的驱动实例再来过一遍吧。。
- LINUX:i2c 驱动架构
- linux i2c驱动笔记
- linux I2C驱动分析
- linux I2C驱动分析
- linux i2c驱动总结
- Linux I2C 驱动分析
- linux下I2C驱动
- linux i2c驱动笔记
- Linux驱动I2C分析
- linux i2c 驱动分析
- linux i2c驱动笔记
- Linux--I2C驱动分析
- linux i2c设备驱动
- Linux I2C 总线驱动
- Linux I2C 设备驱动
- Linux I2C驱动:i2c_device_id
- linux i2c驱动分析
- linux i2c驱动
- 我的学习之路——Oracle数据库之单行函数
- 排除“计算机-默认 权限设置未将 COM 服务器应用程序”的错误
- 汤姆·霍尔的快速成为游戏开发者的秘诀 顶级游戏设计大师谈如何成为一名游戏设计师!
- 采用软件nginx实现web服务器集群
- php ReflectionClass
- linux-I2C驱动
- hdu 1165 Eddy's research II(数学题,递推)
- 思考使人睿智,思考使人前行
- Apache Avro 与 Thrift 比较
- 信息系统项目管理师总结2
- C++中函数指针的使用
- Android context(Application/Activity)与内存泄露
- 今天的收获,关于hellolua~
- 信息系统项目管理师总结3