i2c子系统

目录(?)[+]

linux系统核心层的东西基本都是xx-core。

一 主要数据结构

[cpp]  view plain copy
  1. struct i2c_msg {  
  2.     __u16 addr; /* slave address            */  
  3.     __u16 flags;  
  4. #define I2C_M_TEN       0x0010  /* this is a ten bit chip address */  
  5. #define I2C_M_RD        0x0001  /* read data, from slave to master */  
  6. #define I2C_M_STOP      0x8000  /* if I2C_FUNC_PROTOCOL_MANGLING */  
  7. #define I2C_M_NOSTART       0x4000  /* if I2C_FUNC_NOSTART */  
  8. #define I2C_M_REV_DIR_ADDR  0x2000  /* if I2C_FUNC_PROTOCOL_MANGLING */  
  9. #define I2C_M_IGNORE_NAK    0x1000  /* if I2C_FUNC_PROTOCOL_MANGLING */  
  10. #define I2C_M_NO_RD_ACK     0x0800  /* if I2C_FUNC_PROTOCOL_MANGLING */  
  11. #define I2C_M_RECV_LEN      0x0400  /* length will be first received byte */  
  12.     __u16 len;      /* msg length               */  
  13.     __u8 *buf;      /* pointer to msg data          */  
  14. };  
i2c通信的基本单位,flag为1表示读;flag为0表示写。
[cpp]  view plain copy
  1. struct i2c_algorithm {  
  2.     /* If an adapter algorithm can't do I2C-level access, set master_xfer 
  3.        to NULL. If an adapter algorithm can do SMBus access, set 
  4.        smbus_xfer. If set to NULL, the SMBus protocol is simulated 
  5.        using common I2C messages */  
  6.     /* master_xfer should return the number of messages successfully 
  7.        processed, or a negative value on error */  
  8.     int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,  
  9.                int num);  
  10.     int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,  
  11.                unsigned short flags, char read_write,  
  12.                u8 command, int size, union i2c_smbus_data *data);  
  13.   
  14.     /* To determine what the adapter supports */  
  15.     u32 (*functionality) (struct i2c_adapter *);  
  16. };  

i2c的通信方法。

[cpp]  view plain copy
  1. struct i2c_adapter {  
  2.     struct module *owner;  
  3.     unsigned int class;       /* classes to allow probing for */  
  4.     const struct i2c_algorithm *algo; /* the algorithm to access the bus */  
  5.     void *algo_data;  
  6.   
  7.     /* data fields that are valid for all devices   */  
  8.     struct rt_mutex bus_lock;  
  9.   
  10.     int timeout;            /* in jiffies */  
  11.     int retries;  
  12.     struct device dev;      /* the adapter device */  
  13.   
  14.     int nr;  
  15.     char name[48];  
  16.     struct completion dev_released;  
  17.   
  18.     struct mutex userspace_clients_lock;  
  19.     struct list_head userspace_clients;  
  20. };  

i2c_adapter对应一个物理的i2c总线,它需要一个通信方法i2c_algorithm。

[cpp]  view plain copy
  1. struct i2c_client {  
  2.     unsigned short flags;       /* div., see below      */  
  3.     unsigned short addr;        /* chip address - NOTE: 7bit    */  
  4.                     /* addresses are stored in the  */  
  5.                     /* _LOWER_ 7 bits       */  
  6.     char name[I2C_NAME_SIZE];  
  7.     struct i2c_adapter *adapter;    /* the adapter we sit on    */  
  8.     struct i2c_driver *driver;  /* and our access routines  */  
  9.     struct device dev;      /* the device structure     */  
  10.     int irq;            /* irq issued by device     */  
  11.     struct list_head detected;  
  12. };  
i2c_client代表一个i2c从设备,需要有自己的地址(地址分7bit和8bit,8bit地址需要右移变成7bit),需要挂接的总线,也就是i2c_adapter,还需要i2c_driver来实现读写操作。addr和adapter需要在i2c_new_device之前都准备好,它们都与硬件相关。addr是从设备决定的,i2c_get_adapter()可以获得一个adapter,要保证的是,这个adapter必须是连接到从设备上的。drvier和device的匹配是个双向的过程,所以driver填充的路径有两条:
第一条:注册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;
[cpp]  view plain copy
  1. struct i2c_driver {  
  2.     unsigned int class;  
  3.   
  4.     /* Notifies the driver that a new bus has appeared or is about to be 
  5.      * removed. You should avoid using this, it will be removed in a 
  6.      * near future. 
  7.      */  
  8.     int (*attach_adapter)(struct i2c_adapter *) __deprecated;  
  9.     int (*detach_adapter)(struct i2c_adapter *) __deprecated;  
  10.   
  11.     /* Standard driver model interfaces */  
  12.     int (*probe)(struct i2c_client *, const struct i2c_device_id *);  
  13.     int (*remove)(struct i2c_client *);  
  14.   
  15.     /* driver model interfaces that don't relate to enumeration  */  
  16.     void (*shutdown)(struct i2c_client *);  
  17.     int (*suspend)(struct i2c_client *, pm_message_t mesg);  
  18.     int (*resume)(struct i2c_client *);  
  19.   
  20.     /* Alert callback, for example for the SMBus alert protocol. 
  21.      * The format and meaning of the data value depends on the protocol. 
  22.      * For the SMBus alert protocol, there is a single bit of data passed 
  23.      * as the alert response's low bit ("event flag"). 
  24.      */  
  25.     void (*alert)(struct i2c_client *, unsigned int data);  
  26.   
  27.     /* a ioctl like command that can be used to perform specific functions 
  28.      * with the device. 
  29.      */  
  30.     int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);  
  31.   
  32.     struct device_driver driver;  
  33.     const struct i2c_device_id *id_table;  
  34.   
  35.     /* Device detection callback for automatic device creation */  
  36.     int (*detect)(struct i2c_client *, struct i2c_board_info *);  
  37.     const unsigned short *address_list;  
  38.     struct list_head clients;  
  39. };  

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。

[cpp]  view plain copy
  1. union i2c_smbus_data {  
  2.     __u8 byte;  
  3.     __u16 word;  
  4.     __u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */  
  5.                    /* and one more for user-space compatibility */  
  6. };  

smbus的通信数据,是个联合体。

[cpp]  view plain copy
  1. struct i2c_board_info {  
  2.     char        type[I2C_NAME_SIZE];  
  3.     unsigned short  flags;  
  4.     unsigned short  addr;  
  5.     void        *platform_data;  
  6.     struct dev_archdata *archdata;  
  7.     struct device_node *of_node;  
  8.     struct acpi_dev_node acpi_node;  
  9.     int     irq;  
  10. };  
这是一个信息结构,作为new device的参数,type最终会变成client->name。driver注册的时候会用driver->id_table->name和client->name进行match,只有这里match成功了,才会有接下来的device匹配。

二 主要函数接口

static int i2c_device_match(struct device *dev, struct device_driver *drv)‘

调用i2c_match_id(),通过strcmp(client->name, id->name)进行匹配;匹配成功返回1,否则返回0。

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;
[cpp]  view plain copy
  1. struct i2c_devinfo {  
  2.     struct list_head    list;  
  3.     int         busnum;  
  4.     struct i2c_board_info   board_info;  
  5. };  
i2c_devinfo是对 i2c_board_info的一层封装,增加了一个list,i2c_register_board_info函数正是利用这个list将devinfo挂在了全局的__i2c_board_list上。新增的busnum是对应i2c_adapter->nr的。i2c_register_board_info()还要更新__i2c_first_dynamic_bus_num,它记录的是第一个动态的bus num,被分配为最后一个静态申请的下一个,= busnum + 1。
[cpp]  view plain copy
  1. #define I2C_BOARD_INFO(dev_type, dev_addr) \  
  2.     .type = dev_type, .addr = (dev_addr)  
这个宏就是用来填充一个i2c_board_info结构的。

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);
[cpp]  view plain copy
  1. int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,  
  2.              void *data, int (*fn)(struct device_driver *, void *))  
  3. {  
  4.     struct klist_iter i;  
  5.     struct device_driver *drv;  
  6.     int error = 0;  
  7.   
  8.     if (!bus)  
  9.         return -EINVAL;  
  10.   
  11.     klist_iter_init_node(&bus->p->klist_drivers, &i,  
  12.                  start ? &start->p->knode_bus : NULL);  
  13.     while ((drv = next_driver(&i)) && !error)  
  14.         error = fn(drv, data);  
  15.     klist_iter_exit(&i);  
  16.     return error;  
  17. }  
  18. void klist_iter_init_node(struct klist *k, struct klist_iter *i,  
  19.               struct klist_node *n)  
  20. {  
  21.     i->i_klist = k;  
  22.     i->i_cur = n;  
  23.     if (n)  
  24.         kref_get(&n->n_ref);  
  25. }  
klist_iter_init_node()中初始化 klist_iter i,i->i_klist = &bus->p->klist_drivers,i->i_cur = start。klist_devices是对driver list的一个封装,上面挂的driver是driver_register()->bus_add_driver()->klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);时添加的。如果start 不是 NULL,并增加(&start ->n_ref)->->refcount引用计数。接下来next_driver()中如果start存在,就从start开始;否则从bus->p->klist_drivers开始,&bus->p->klist_drivers->next是一个*list_head,通过它找到一个*klist_node,挂的时候就是这样挂的,找的时候自然这样找,继续找到driver_private;这里就有driver了,driver_register()->bus_add_driver()->(priv->driver = drv;),注册的时候就藏到这了;经过结构的转换总能找到next driver,执行__process_new_adapter(device_driver, i2c_adapter)。
[cpp]  view plain copy
  1. static int __process_new_adapter(struct device_driver *d, void *data)  
  2. {  
  3.     return i2c_do_add_adapter(to_i2c_driver(d), data);  
  4. }  
原来只是针对dev->type == &i2c_adapter_type,才会有i2c_do_add_adapter(struct i2c_driver *driver, struct i2c_adapter *adap),包括i2c_detect()和driver->attach_adapter(adap)。只是针对挂到bus->p->klist_devices的adapter(i2c client是一种device,i2c adapter也是一直device,它们都会挂上,就是通过dev->type区分的,显然client的dev->type = &i2c_client_type;);进行driver和adapter的依附动作,一般会在attach_adapter()中执行probe动作,为i2c client找到依附的adapter,这个函数基本不用了,已经被probe()函数取代了。
这是个双向的过程,drvier注册的时候也会执行。
[cpp]  view plain copy
  1. i2c_register_driver()->i2c_for_each_dev(driver, __process_new_driver);  
  2. int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *))  
  3. {  
  4.     int res;  
  5.   
  6.     mutex_lock(&core_lock);  
  7.     res = bus_for_each_dev(&i2c_bus_type, NULL, data, fn);  
  8.     mutex_unlock(&core_lock);  
  9.   
  10.     return res;  
  11. }  
  12. int bus_for_each_dev(struct bus_type *bus, struct device *start,  
  13.              void *data, int (*fn)(struct device *, void *))  
  14. {  
  15.     struct klist_iter i;  
  16.     struct device *dev;  
  17.     int error = 0;  
  18.   
  19.     if (!bus)  
  20.         return -EINVAL;  
  21.   
  22.     klist_iter_init_node(&bus->p->klist_devices, &i,  
  23.                  (start ? &start->p->knode_bus : NULL));  
  24.     while ((dev = next_device(&i)) && !error)  
  25.         error = fn(dev, data);  
  26.     klist_iter_exit(&i);  
  27.     return error;  
  28. }  
klist_iter_init_node()中初始化 klist_iter i,i->i_klist = &bus->p->klist_devices,i->i_cur = start。klist_devices是对device list的一个封装,上面挂的device是device_register()->device_add()->bus_add_device()->klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);时添加的。如果start 不是 NULL,并增加(&start ->n_ref)->->refcount引用计数。接下来next_device()中如果start存在,就从start开始;否则从bus->p->klist_devices开始;&bus->p->klist_devices->next是一个*list_head,通过它找到一个*klist_node,继续找到device_private;这里就有device了,device_register()->device_add()->device_private_init()->(dev->p->device = dev);经过结构的转换总能找到next device,执行__process_new_driver(device, i2c_driver)。
[cpp]  view plain copy
  1. static int __process_new_driver(struct device *dev, void *data)  
  2. {  
  3.     if (dev->type != &i2c_adapter_type)  
  4.         return 0;  
  5.     return i2c_do_add_adapter(data, to_i2c_adapter(dev));  
  6. }  

接下来的动作同上。

register adapterbus_for_each_drv

1__process_new_adapter(struct device_driver *d, void *data)参数是device_driver、i2c_adapter

register driverbus_for_each_dev

2__process_new_driver(struct device *dev, void *data)参数是devicei2c_driver

i2c_do_add_adapter(struct i2c_driver *driver, struct i2c_adapter *adap)参数是i2c_driveri2c_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总线注册

i2c是总线设备,注册等级要高,postcore_initcall(i2c_init);对应__define_initcall(fn, 2)第2级。我们平常使用的module_init(x)是第6级的。
retval = bus_register(&i2c_bus_type);
int __bus_register(struct bus_type *bus, struct lock_class_key *key)
注册一个子系统,主要是填充subsys_private这样一个结构。
初始化注册kobj、kset设备模型的一些东西,这个后续再说。

四 i2c驱动程序开发

i2c子系统已经搭建好了,驱动开发就是填充子系统中的一些结构。
1 注册i2c adapter,与硬件bus对应。
2 实现adapter的通信方法i2c_algorithm,主要是master_xfer。
master_xfer需要实现read、write函数。

五 软件模拟i2c

软件模拟i2c是通过GPIO实现的,按照总线时序模拟的;通用代码位于drver/i2c/algos/i2c-algo-bit.c和include/linux/i2c-algo-bit.h。
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 int bit_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)//终于到了真正的传输函数了,先发送start信号。if (!(pmsg->flags & I2C_M_NOSTART)) 成立则发送重复开始信号和addr,然后根据msg->flags判断是read还是write。需要注意的是这个I2C_M_NOSTART标志应该什么时候设置?如果msgs[0]就定义了该标志,就会发送S和Sr两个开始信号,没必要吧;所以一般msgs[0]不会定义。最后发送stop信号。
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就好了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值