linux系统核心层的东西基本都是xx-core。
一 主要数据结构
- 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_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */
- #define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */
- #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 */
- };
- 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 *);
- };
i2c的通信方法。
- 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;
- };
i2c_adapter对应一个物理的i2c总线,它需要一个通信方法i2c_algorithm。
- 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 i2c_driver *driver; /* and our access routines */
- struct device dev; /* the device structure */
- int irq; /* irq issued by device */
- struct list_head detected;
- };
第一条:注册i2c_driver的时候
i2c_register_driver()->driver_register()->bus_add_driver()->driver_attach()->__driver_attach()->driver_probe_device()->really_probe()->i2c_device_probe()->client->driver = driver;
第二条:添加slave device的时候
i2c_new_device()->device_register()->device_add()->bus_probe_device()->device_attach()->__device_attach()->driver_probe_device()->really_probe()->i2c_device_probe()->client->driver = driver;
- struct i2c_driver {
- unsigned int class;
- /* Notifies the driver that a new bus has appeared or is about to be
- * removed. You should avoid using this, it will be removed in a
- * near future.
- */
- int (*attach_adapter)(struct i2c_adapter *) __deprecated;
- int (*detach_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;
- };
driver都是为device服务的,一般一个driver可以为很多device服务,通过driver_bound()->klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);把device bound到driver的list上,driver卸载的时候,要把挂在上边的device release。
- union i2c_smbus_data {
- __u8 byte;
- __u16 word;
- __u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */
- /* and one more for user-space compatibility */
- };
smbus的通信数据,是个联合体。
- struct i2c_board_info {
- char type[I2C_NAME_SIZE];
- unsigned short flags;
- unsigned short addr;
- void *platform_data;
- struct dev_archdata *archdata;
- struct device_node *of_node;
- struct acpi_dev_node acpi_node;
- int irq;
- };
二 主要函数接口
static int i2c_device_match(struct device *dev, struct device_driver *drv)‘
struct i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info);
创建一个i2c device,实际就是创建一个i2c_client结构,并初始化。void i2c_unregister_device(struct i2c_client *);
注销一个一个i2c device,实际是device_unregister(&client->dev);;是针对i2c_new_device()->device_register(&client->dev)做一些注销工作。int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned n);
该函数中新出现的结构是全局的一个读写信号量、一个devinfo、一个全局的list。extern struct rw_semaphore __i2c_board_lock;
struct i2c_devinfo *devinfo;
extern struct list_head __i2c_board_list;
- struct i2c_devinfo {
- struct list_head list;
- int busnum;
- struct i2c_board_info board_info;
- };
- #define I2C_BOARD_INFO(dev_type, dev_addr) \
- .type = dev_type, .addr = (dev_addr)
static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
扫描__i2c_board_list,if (devinfo->busnum == adapter->nr)根据bus号进行匹配,则i2c_new_device(adapter, &devinfo->board_info)。int i2c_add_adapter(struct i2c_adapter *adapter)
该函数先获得一个id,作为adapter的id,然后调用i2c_register_adapter(adapter)。获得id,用到了IDR机制,这个机制后续再说。
static int i2c_register_adapter(struct i2c_adapter *adap)
adapter也是一种device,但凡device注册都会调用device_register()。if (adap->nr < __i2c_first_dynamic_bus_num)
i2c_scan_static_board_info(adap);
如果条件成立,说明之前用i2c_register_board_info()注册过i2c_devinfo,不然__i2c_first_dynamic_bus_num怎么会大于0?既然注册过__i2c_board_list上就挂了i2c_devinfo信息,这些都是i2c client的信息,是等待new device的信息。所以这里通过i2c_scan_static_board_info()扫描了整个info list创建i2c client。因为__i2c_first_dynamic_bus_num是静态注册的下一个,如果adap->nr > __i2c_first_dynamic_bus_num,说明nr这个bus上还没有静态注册info 信息,所以是不需要扫描的。
函数最后的bus_for_each_drv(&i2c_bus_type, NULL, adap, __process_new_adapter);
- int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
- void *data, int (*fn)(struct device_driver *, void *))
- {
- struct klist_iter i;
- struct device_driver *drv;
- int error = 0;
- if (!bus)
- return -EINVAL;
- klist_iter_init_node(&bus->p->klist_drivers, &i,
- start ? &start->p->knode_bus : NULL);
- while ((drv = next_driver(&i)) && !error)
- error = fn(drv, data);
- klist_iter_exit(&i);
- return error;
- }
- void klist_iter_init_node(struct klist *k, struct klist_iter *i,
- struct klist_node *n)
- {
- i->i_klist = k;
- i->i_cur = n;
- if (n)
- kref_get(&n->n_ref);
- }
- static int __process_new_adapter(struct device_driver *d, void *data)
- {
- return i2c_do_add_adapter(to_i2c_driver(d), data);
- }
这是个双向的过程,drvier注册的时候也会执行。
- i2c_register_driver()->i2c_for_each_dev(driver, __process_new_driver);
- int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *))
- {
- int res;
- mutex_lock(&core_lock);
- res = bus_for_each_dev(&i2c_bus_type, NULL, data, fn);
- mutex_unlock(&core_lock);
- return res;
- }
- int bus_for_each_dev(struct bus_type *bus, struct device *start,
- void *data, int (*fn)(struct device *, void *))
- {
- struct klist_iter i;
- struct device *dev;
- int error = 0;
- if (!bus)
- return -EINVAL;
- klist_iter_init_node(&bus->p->klist_devices, &i,
- (start ? &start->p->knode_bus : NULL));
- while ((dev = next_device(&i)) && !error)
- error = fn(dev, data);
- klist_iter_exit(&i);
- return error;
- }
- static int __process_new_driver(struct device *dev, void *data)
- {
- if (dev->type != &i2c_adapter_type)
- return 0;
- return i2c_do_add_adapter(data, to_i2c_adapter(dev));
- }
接下来的动作同上。
register adapter时bus_for_each_drv
1__process_new_adapter(struct device_driver *d, void *data)参数是device_driver、i2c_adapter。
register driver时bus_for_each_dev
2__process_new_driver(struct device *dev, void *data)参数是device和i2c_driver。
i2c_do_add_adapter(struct i2c_driver *driver, struct i2c_adapter *adap)参数是i2c_driver和i2c_adapter。
1需要to_i2c_driver(device_driver)找到i2c_driver。
2需要to_i2c_adapter(dev)找到i2c_adapter。
int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
这个留给用户的通信接口了,信息格式i2c_msg,信息长度num。i2c_transfer()保证顺利执行,就必须实现它的通信方法adap->algo->master_xfer;
ret = __i2c_transfer(adap, msgs, num);
ret = adap->algo->master_xfer(adap, msgs, num);
三 i2c总线注册
retval = bus_register(&i2c_bus_type);
int __bus_register(struct bus_type *bus, struct lock_class_key *key)
注册一个子系统,主要是填充subsys_private这样一个结构。
初始化注册kobj、kset设备模型的一些东西,这个后续再说。
四 i2c驱动程序开发
1 注册i2c adapter,与硬件bus对应。
2 实现adapter的通信方法i2c_algorithm,主要是master_xfer。
master_xfer需要实现read、write函数。
五 软件模拟i2c
static inline void sdalo(struct i2c_algo_bit_data *adap)//数据线拉低
static inline void sdahi(struct i2c_algo_bit_data *adap)//数据线拉高
static inline void scllo(struct i2c_algo_bit_data *adap)//时钟线拉低
static int sclhi(struct i2c_algo_bit_data *adap)//时钟线拉高,需要通过getscl的值,确保已经拉高
static void i2c_start(struct i2c_algo_bit_data *adap)//start信号,要求数据和时钟都先是高;数据线先拉低,延时,时钟线拉低
static void i2c_repstart(struct i2c_algo_bit_data *adap)//要求时钟低;先拉高数据线,再拉高时钟线,然后是一个start信号
如果发送了start信号,而没有发送stop信号,就会用到repstart。
static void i2c_stop(struct i2c_algo_bit_data *adap)//要求时钟低;数据线拉低,时钟线拉高,数据线拉高,延时
static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)//要求时钟低;发送一个byte,先输出高位;时钟高的时候,要求数据稳定,不能变化;所以时钟低的时候改变;最后拉高sda,拉高scl,等ack(ack是一个低信号);拉低scl。有ack返回1,否则0。
static int i2c_inb(struct i2c_adapter *i2c_adap)//要求scl低,接收一个byt;也是先接收高位;但是indata << 2,用的是indata *= 2;。
static int test_bus(struct i2c_adapter *i2c_adap)//test bus是否idle;1 如果sda和scl不是都为高,就busy;2 只拉低sda;3 只拉高sda;4 只拉低scl;5 只拉高scl;分别读一下2、3、4、5的sda和scl是否正确。
static int try_address(struct i2c_adapter *i2c_adap, unsigned char addr, int retries)//测试i2c addr从机有没有应答,有则返回1。
static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)//发送一个msg,调用i2c_outb()实现。
static int acknak(struct i2c_adapter *i2c_adap, int is_ack)//要求sda高,发送一个ack。
static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)//接收一个msg,调用i2c_inb()和acknak()。
static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)//发送地址;1 10bit地址,把addr拆分成2bit+8bit;i2c时序要求先发送11110 AA r/w(AA就是2bit的填充位置),然后发送8bit;还是i2c时序要求,在重复开始条件(Sr)之后,被匹配的从机会保持被寻址上的状态,此时从机会检查Sr之后的第一byte的高7bit是否正确,符合11110 AA,再测试bit0是否是1(读状态);所以if (flags & I2C_M_RD)成立,还需要repstart后,发送一个这样的addr。2 正常的7bit地址,只需左移到高7bit,bit0根据读写标志填充,但是如果if (flags & I2C_M_REV_DIR_ADDR)成立,需要把读写标志翻转。
static u32 bit_func(struct i2c_adapter *adap)//确定一个adapter支持的功能
static int __i2c_bit_add_bus(struct i2c_adapter *adap, int (*add_adapter)(struct i2c_adapter *))//添加一个adapter,要求它的通信方法adap->algo = &i2c_bit_algo;
const struct i2c_algorithm i2c_bit_algo = {
.master_xfer = bit_xfer,
.functionality = bit_func,
};
int i2c_bit_add_bus(struct i2c_adapter *adap)
{
return __i2c_bit_add_bus(adap, i2c_add_adapter);
}
int i2c_bit_add_numbered_bus(struct i2c_adapter *adap)
{
return __i2c_bit_add_bus(adap, i2c_add_numbered_adapter);
}
前者是用动态的bus num,后者是动态的bus num。
对于模拟i2c驱动程序的开发,仍然是要注册一个adapter,调用i2c_bit_add_bus()或者i2c_bit_add_numbered_bus();至于通信方法已经指定了。写模拟驱动主要是填充i2c_algo_bit_data这个结构;__i2c_bit_add_bus()中有i2c_algo_bit_data *bit_adap = adap->algo_data;那么对应的在驱动中填充好这个结构也赋给adap->algo_data就好了。