i2c--ioctl--主机控制器驱动(i2c_adapter)--外设驱动(i2c_driver)
updating...
i2c驱动目录
i2c-s3c2410.c里面有一个重要的全局结构体,
①i2c-s3c2410.c实现i2c总线驱动(即cpu的i2c主控制器和外接设备的i2c接口的通信),
1.需要填充i2c_adapter结构体。i2c_adapter结构体即i2c适配器即i2c主控制器,对于不同的硬件需要有不同的配置。然后向通过i2c核心添加这个适配器。
2.需要填充i2c-algorithm结构体。i2c-algorithm结构体即指定i2c通信算法,
②i2c-dev.c 实现i2c设备驱动。即实现i2c_driver结构体并向i2c核心注册,还要实现设备自身的驱动如普通字符设备(或许也可以用misc设备)的驱动,以便与用户空间交互。
如下
i2c总线驱动(对应i2c_adapter)和i2c设备驱动(对应i2c_driver)是通过i2c核心关联起来的。当有一个i2c_adapter通过i2c核心添加,i2c核心会自动匹配对应的i2c_driver,调用i2c_driver的probe函数....不过在i2c-dev.c 没有实现这个函数指针,而是实现了attach_adapter函数指针。
****************************************************************************************************************************************
在i2c-dev.h中定义了如下ioctl命令:
当在用户侧使用ioctl(fd, I2C_RDWR, (unsigned long)&e2prom_data);读取数据时,会调用驱动的ioctl设备方法
i2c-dev.c
case I2C_RDWR:
return i2cdev_ioctl_rdrw(client, arg);
先看client是什么东东,line 3有
struct i2c_client *client = (struct i2c_client *)file->private_data;
接着看一下打开设备时的动作,如下
client->driver = &i2cdev_driver;//client绑定i2c_driver
client->adapter = adap;//client绑定i2c_adapter
很明确的说明了client就是把driver(i2c-dev.c)和adapter(i2c-s3c2410.c)关联
回到i2cdev_ioctl_rdrw(client, arg);源码是
是一个要在设备驱动(i2c-dev.c)里面调用以便访问总线驱动(i2c-s3c2410.c)的接口函数。
使用i2c subsystem的这种分离设计是为了cpu平台更换时可以保持与用户的接口不变:
比如有1个i2c_driver(设备驱动,处理用户接口)和5个i2c_adapter(代表5个cpu平台的i2c主控制器驱动,处理与特定设备的寄存器配置和信息传输的具体实现)。在换平台的时候,只需要实现i2c_adapter部分,而i2c_driver不必改变,因为它最终调用i2c核心的i2c_transfer()与i2c_adapter交互。
而如果不分离。即将用户接口的实现(比如字符设备)和i2c数据传输的实现够放在一个文件里面------传统的做法,则公司在换cpu平台的时候,就需要修改整个驱动文件。
这种分离设计也可以实现cpu平台不变外设更换时,可以保持同一套用户接口。此时仍然是只需要修改i2c_adapter或者如果外设特性能完全相同则不必修改。
但对于专注于一个cpu一个外设的厂家而言这种分离设计就有点浪费了,,,
并且这种设计也遵守内核实现机制(套路)的思想。比如i2c子系统为已经定义了结构体i2c_msg,在用户空间只需填充i2c_msg然后发送。
综上可知:
即内核实现怎么发,用户决定发什么。而内核实现怎么发的同时,还考虑到用户的换平台的情况,所以采用分离设计将用户接口与具体的怎么发分离。
虽然i2c子系统是按照这个思想设计的,但和同样是这个设计思想的spi子系统对比,却没有spi的明朗。
--2011年12月4日
几个重要的结构体
i2c.h
s3c2440的i2c主控制器仅5个寄存器,在linux内核中却搞得这么繁杂,,,,,
IICCON 0x54000000 R/W IIC-Bus control register
IICSTAT 0x54000004 R/W IIC-Bus control/status register
IICADD 0x54000008 R/W IIC-Bus address register
IICDS 0x5400000C R/W IIC-Bus transmit/receive data shift register
IICLC 0x54000010 R/W IIC-Bus multi-master line control register
并且micro2440的eeprom的i2c驱动最外层是platform总线然后是i2c总线然后才是面向用户访问的字符设备。。。
目前的一点个人理解,有待更新。。。
存在的问题,在insmod时i2c核心具体怎么匹配外设驱动(设备)和总线(控制器驱动),在ioctl时i2c核心具体怎么处理(匹配)外设驱动和总线,i2c具体数据的传输。有时间再去细读。
对总线设备驱动模型认识不清,对sysfs认识不清,对mdev如何利用sysfs创建设备节点的过程不清。
refer to
http://blog.csdn.net/cjok376240497/article/details/6982883
http://blog.csdn.net/hongtao_liu/article/details/4964244
http://blog.csdn.net/hongtao_liu/article/details/5260739
i2c驱动目录
[root@localhost i2c]# pwd /opt/FriendlyArm/mini2440/linux-2.6.32.2/drivers/i2c [root@localhost i2c]# tree //.有省略 |-- Kconfig |-- Makefile |-- algos | |-- Kconfig | |-- Makefile | |-- built-in.o | |-- i2c-algo-bit.c | |-- i2c-algo-pca.c | |-- i2c-algo-pcf.c | |-- i2c-algo-pcf.h | `-- modules.order |-- built-in.o |-- busses | |-- Kconfig | |-- Makefile | |-- ... | -- i2c-s3c2410.c |-- chips | |-- Kconfig | |-- Makefile | |-- ds1682.c | `-- tsl2550.c |-- i2c-boardinfo.c |-- i2c-core.c |-- i2c-core.h |-- i2c-core.o |-- i2c-dev.c
i2c-s3c2410.c里面有一个重要的全局结构体,
struct s3c24xx_i2c { spinlock_t lock; wait_queue_head_t wait; unsigned int suspended:1; struct i2c_msg *msg; unsigned int msg_num; unsigned int msg_idx; unsigned int msg_ptr; unsigned int tx_setup; unsigned int irq; enum s3c24xx_i2c_state state; unsigned long clkrate; void __iomem *regs; struct clk *clk; struct device *dev; struct resource *ioarea; struct i2c_adapter adap; #ifdef CONFIG_CPU_FREQ struct notifier_block freq_transition; #endif };
①i2c-s3c2410.c实现i2c总线驱动(即cpu的i2c主控制器和外接设备的i2c接口的通信),
1.需要填充i2c_adapter结构体。i2c_adapter结构体即i2c适配器即i2c主控制器,对于不同的硬件需要有不同的配置。然后向通过i2c核心添加这个适配器。
strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name)); i2c->adap.owner = THIS_MODULE; i2c->adap.algo = &s3c24xx_i2c_algorithm;//指定adapter的通信算法结构体 i2c->adap.retries = 2; i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; i2c->tx_setup = 50; ... ret = i2c_add_numbered_adapter(&i2c->adap);
2.需要填充i2c-algorithm结构体。i2c-algorithm结构体即指定i2c通信算法,
static const struct i2c_algorithm s3c24xx_i2c_algorithm = { .master_xfer = s3c24xx_i2c_xfer, .functionality = s3c24xx_i2c_func, };在s3c24xx_i2c_xfer里(其调用到的函数里)用到i2c_msg结构体访问i2c.
②i2c-dev.c 实现i2c设备驱动。即实现i2c_driver结构体并向i2c核心注册,还要实现设备自身的驱动如普通字符设备(或许也可以用misc设备)的驱动,以便与用户空间交互。
如下
static int __init i2c_dev_init(void) { int res; printk(KERN_INFO "i2c /dev entries driver\n"); res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);// ......... return res; }在i2cdev_attach_adapter里面向sysfs文件系统写入信息。以便i2c_adapter”热插拔“的时候动态创建节点.
static int i2cdev_attach_adapter(struct i2c_adapter *adap) { struct i2c_dev *i2c_dev; int res; i2c_dev = get_free_i2c_dev(adap); if (IS_ERR(i2c_dev)) return PTR_ERR(i2c_dev); /* register this i2c device with the driver core */ i2c_dev->dev = device_create(i2c_dev_class, &adap->dev, MKDEV(I2C_MAJOR, adap->nr), NULL, "i2c-%d", adap->nr); ......... }
i2c总线驱动(对应i2c_adapter)和i2c设备驱动(对应i2c_driver)是通过i2c核心关联起来的。当有一个i2c_adapter通过i2c核心添加,i2c核心会自动匹配对应的i2c_driver,调用i2c_driver的probe函数....不过在i2c-dev.c 没有实现这个函数指针,而是实现了attach_adapter函数指针。
****************************************************************************************************************************************
在i2c-dev.h中定义了如下ioctl命令:
/* /dev/i2c-X ioctl commands. The ioctl's parameter is always an * unsigned long, except for: * - I2C_FUNCS, takes pointer to an unsigned long * - I2C_RDWR, takes pointer to struct i2c_rdwr_ioctl_data * - I2C_SMBUS, takes pointer to struct i2c_smbus_ioctl_data */ #define I2C_RETRIES 0x0701 /* number of times a device address should be polled when not acknowledging */ #define I2C_TIMEOUT 0x0702 /* set timeout in units of 10 ms */ /* NOTE: Slave address is 7 or 10 bits, but 10-bit addresses * are NOT supported! (due to code brokenness) */ #define I2C_SLAVE 0x0703 /* Use this slave address */ #define I2C_SLAVE_FORCE 0x0706 /* Use this slave address, even if it is already in use by a driver! */ #define I2C_TENBIT 0x0704 /* 0 for 7 bit addrs, != 0 for 10 bit */ #define I2C_FUNCS 0x0705 /* Get the adapter functionality mask */ #define I2C_RDWR 0x0707 /* Combined R/W transfer (one STOP only) */ #define I2C_PEC 0x0708 /* != 0 to use PEC with SMBus */ #define I2C_SMBUS 0x0720 /* SMBus transfer */
当在用户侧使用ioctl(fd, I2C_RDWR, (unsigned long)&e2prom_data);读取数据时,会调用驱动的ioctl设备方法
i2c-dev.c
static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct i2c_client *client = (struct i2c_client *)file->private_data; unsigned long funcs; dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n", cmd, arg); switch ( cmd ) { case I2C_SLAVE: case I2C_SLAVE_FORCE: /* NOTE: devices set up to work with "new style" drivers * can't use I2C_SLAVE, even when the device node is not * bound to a driver. Only I2C_SLAVE_FORCE will work. * * Setting the PEC flag here won't affect kernel drivers, * which will be using the i2c_client node registered with * the driver model core. Likewise, when that client has * the PEC flag already set, the i2c-dev driver won't see * (or use) this setting. */ if ((arg > 0x3ff) || (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f)) return -EINVAL; if (cmd == I2C_SLAVE && i2cdev_check_addr(client->adapter, arg)) return -EBUSY; /* REVISIT: address could become busy later */ client->addr = arg; return 0; case I2C_TENBIT: if (arg) client->flags |= I2C_M_TEN; else client->flags &= ~I2C_M_TEN; return 0; case I2C_PEC: if (arg) client->flags |= I2C_CLIENT_PEC; else client->flags &= ~I2C_CLIENT_PEC; return 0; case I2C_FUNCS: funcs = i2c_get_functionality(client->adapter); return put_user(funcs, (unsigned long __user *)arg); case I2C_RDWR: return i2cdev_ioctl_rdrw(client, arg); case I2C_SMBUS: return i2cdev_ioctl_smbus(client, arg); case I2C_RETRIES: client->adapter->retries = arg; break; case I2C_TIMEOUT: /* For historical reasons, user-space sets the timeout * value in units of 10 ms. */ client->adapter->timeout = msecs_to_jiffies(arg * 10); break; default: /* NOTE: returning a fault code here could cause trouble * in buggy userspace code. Some old kernel bugs returned * zero in this case, and userspace code might accidentally * have depended on that bug. */ return -ENOTTY; } return 0; }而
case I2C_RDWR:
return i2cdev_ioctl_rdrw(client, arg);
先看client是什么东东,line 3有
struct i2c_client *client = (struct i2c_client *)file->private_data;
接着看一下打开设备时的动作,如下
static int i2cdev_open(struct inode *inode, struct file *file) { unsigned int minor = iminor(inode); struct i2c_client *client; struct i2c_adapter *adap; struct i2c_dev *i2c_dev; int ret = 0; lock_kernel(); i2c_dev = i2c_dev_get_by_minor(minor); if (!i2c_dev) { ret = -ENODEV; goto out; } adap = i2c_get_adapter(i2c_dev->adap->nr); if (!adap) { ret = -ENODEV; goto out; } /* This creates an anonymous i2c_client, which may later be * pointed to some address using I2C_SLAVE or I2C_SLAVE_FORCE. * * This client is ** NEVER REGISTERED ** with the driver model * or I2C core code!! It just holds private copies of addressing * information and maybe a PEC flag. */ client = kzalloc(sizeof(*client), GFP_KERNEL); if (!client) { i2c_put_adapter(adap); ret = -ENOMEM; goto out; } snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr); client->driver = &i2cdev_driver;//client绑定i2c_driver client->adapter = adap;//client绑定i2c_adapter file->private_data = client;//一般都是这样搞的,文件私有数据指向client out: unlock_kernel(); return ret; }其中这2行
client->driver = &i2cdev_driver;//client绑定i2c_driver
client->adapter = adap;//client绑定i2c_adapter
回到i2cdev_ioctl_rdrw(client, arg);源码是
static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client, unsigned long arg) { struct i2c_rdwr_ioctl_data rdwr_arg; struct i2c_msg *rdwr_pa; u8 __user **data_ptrs; int i, res; if (copy_from_user(&rdwr_arg, (struct i2c_rdwr_ioctl_data __user *)arg, sizeof(rdwr_arg))) return -EFAULT; /* Put an arbitrary limit on the number of messages that can * be sent at once */ if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS) return -EINVAL; rdwr_pa = (struct i2c_msg *) kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL); if (!rdwr_pa) return -ENOMEM; if (copy_from_user(rdwr_pa, rdwr_arg.msgs, rdwr_arg.nmsgs * sizeof(struct i2c_msg))) { kfree(rdwr_pa); return -EFAULT; } data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL); if (data_ptrs == NULL) { kfree(rdwr_pa); return -ENOMEM; } res = 0; for (i = 0; i < rdwr_arg.nmsgs; i++) { /* Limit the size of the message to a sane amount; * and don't let length change either. */ if ((rdwr_pa[i].len > 8192) || (rdwr_pa[i].flags & I2C_M_RECV_LEN)) { res = -EINVAL; break; } data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf; rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL); if (rdwr_pa[i].buf == NULL) { res = -ENOMEM; break; } if (copy_from_user(rdwr_pa[i].buf, data_ptrs[i], rdwr_pa[i].len)) { ++i; /* Needs to be kfreed too */ res = -EFAULT; break; } } if (res < 0) { int j; for (j = 0; j < i; ++j) kfree(rdwr_pa[j].buf); kfree(data_ptrs); kfree(rdwr_pa); return res; } res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs);// while (i-- > 0) { if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) { if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf, rdwr_pa[i].len)) res = -EFAULT; } kfree(rdwr_pa[i].buf); } kfree(data_ptrs); kfree(rdwr_pa); return res; }line 68调用了i2c core提供的一个函数i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs);看下这个函数的注释
是一个要在设备驱动(i2c-dev.c)里面调用以便访问总线驱动(i2c-s3c2410.c)的接口函数。
/* ---------------------------------------------------- * the functional interface to the i2c busses. * ---------------------------------------------------- */ /** * i2c_transfer - execute a single or combined I2C message * @adap: Handle to I2C bus * @msgs: One or more messages to execute before STOP is issued to * terminate the operation; each message begins with a START. * @num: Number of messages to be executed. * * Returns negative errno, else the number of messages executed. * * Note that there is no requirement that each message be sent to * the same slave address, although that is the most common model. */ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)调用此函数时,会将设备驱动的i2c_msg传输给总线驱动,i2c核心自动调用总线驱动里的master_xfer函数指针指向的实际执行数据传输的函数将i2c_msg在i2c主控制器与i2c外设之间传输。
static const struct i2c_algorithm s3c24xx_i2c_algorithm = { .master_xfer = s3c24xx_i2c_xfer, .functionality = s3c24xx_i2c_func, };
使用i2c subsystem的这种分离设计是为了cpu平台更换时可以保持与用户的接口不变:
比如有1个i2c_driver(设备驱动,处理用户接口)和5个i2c_adapter(代表5个cpu平台的i2c主控制器驱动,处理与特定设备的寄存器配置和信息传输的具体实现)。在换平台的时候,只需要实现i2c_adapter部分,而i2c_driver不必改变,因为它最终调用i2c核心的i2c_transfer()与i2c_adapter交互。
而如果不分离。即将用户接口的实现(比如字符设备)和i2c数据传输的实现够放在一个文件里面------传统的做法,则公司在换cpu平台的时候,就需要修改整个驱动文件。
这种分离设计也可以实现cpu平台不变外设更换时,可以保持同一套用户接口。此时仍然是只需要修改i2c_adapter或者如果外设特性能完全相同则不必修改。
但对于专注于一个cpu一个外设的厂家而言这种分离设计就有点浪费了,,,
并且这种设计也遵守内核实现机制(套路)的思想。比如i2c子系统为已经定义了结构体i2c_msg,在用户空间只需填充i2c_msg然后发送。
综上可知:
即内核实现怎么发,用户决定发什么。而内核实现怎么发的同时,还考虑到用户的换平台的情况,所以采用分离设计将用户接口与具体的怎么发分离。
虽然i2c子系统是按照这个思想设计的,但和同样是这个设计思想的spi子系统对比,却没有spi的明朗。
--2011年12月4日
几个重要的结构体
i2c.h
/** * struct i2c_driver - represent an I2C device driver * @class: What kind of i2c device we instantiate (for detect) * @attach_adapter: Callback for bus addition (for legacy drivers) * @detach_adapter: Callback for bus removal (for legacy drivers) * @probe: Callback for device binding * @remove: Callback for device unbinding * @shutdown: Callback for device shutdown * @suspend: Callback for device suspend * @resume: Callback for device resume * @command: Callback for bus-wide signaling (optional) * @driver: Device driver model driver * @id_table: List of I2C devices supported by this driver * @detect: Callback for device detection * @address_data: The I2C addresses to probe, ignore or force (for detect) * @clients: List of detected clients we created (for i2c-core use only) * * The driver.owner field should be set to the module owner of this driver. * The driver.name field should be set to the name of this driver. * * For automatic device detection, both @detect and @address_data must * be defined. @class should also be set, otherwise only devices forced * with module parameters will be created. The detect function must * fill at least the name field of the i2c_board_info structure it is * handed upon successful detection, and possibly also the flags field. * * If @detect is missing, the driver will still work fine for enumerated * devices. Detected devices simply won't be supported. This is expected * for the many I2C/SMBus devices which can't be detected reliably, and * the ones which can always be enumerated in practice. * * The i2c_client structure which is handed to the @detect callback is * not a real i2c_client. It is initialized just enough so that you can * call i2c_smbus_read_byte_data and friends on it. Don't do anything * else with it. In particular, calling dev_dbg and friends on it is * not allowed. */ 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 if you can, it will probably * be removed in a near future. */ int (*attach_adapter)(struct i2c_adapter *); int (*detach_adapter)(struct i2c_adapter *); /* 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 *); /* 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 *, int kind, struct i2c_board_info *); const struct i2c_client_address_data *address_data; struct list_head clients; }; #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)
/** * struct i2c_client - represent an I2C slave device * @flags: I2C_CLIENT_TEN indicates the device uses a ten bit chip address; * I2C_CLIENT_PEC indicates it uses SMBus Packet Error Checking * @addr: Address used on the I2C bus connected to the parent adapter. * @name: Indicates the type of the device, usually a chip name that's * generic enough to hide second-sourcing and compatible revisions. * @adapter: manages the bus segment hosting this I2C device * @driver: device's driver, hence pointer to access routines * @dev: Driver model device node for the slave. * @irq: indicates the IRQ generated by this device (if any) * @detected: member of an i2c_driver.clients list or i2c-core's * userspace_devices list * * An i2c_client identifies a single device (i.e. chip) connected to an * i2c bus. The behaviour exposed to Linux is defined by the driver * managing the device. */ 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; }; #define to_i2c_client(d) container_of(d, struct i2c_client, dev)
/** * struct i2c_msg - an I2C transaction segment beginning with START * @addr: Slave address, either seven or ten bits. When this is a ten * bit address, I2C_M_TEN must be set in @flags and the adapter * must support I2C_FUNC_10BIT_ADDR. * @flags: I2C_M_RD is handled by all adapters. No other flags may be * provided unless the adapter exported the relevant I2C_FUNC_* * flags through i2c_check_functionality(). * @len: Number of data bytes in @buf being read from or written to the * I2C slave address. For read transactions where I2C_M_RECV_LEN * is set, the caller guarantees that this buffer can hold up to * 32 bytes in addition to the initial length byte sent by the * slave (plus, if used, the SMBus PEC); and this value will be * incremented by the number of block data bytes received. * @buf: The buffer into which data is read, or from which it's written. * * An i2c_msg is the low level representation of one segment of an I2C * transaction. It is visible to drivers in the @i2c_transfer() procedure, * to userspace from i2c-dev, and to I2C adapter drivers through the * @i2c_adapter.@master_xfer() method. * * Except when I2C "protocol mangling" is used, all I2C adapters implement * the standard rules for I2C transactions. Each transaction begins with a * START. That is followed by the slave address, and a bit encoding read * versus write. Then follow all the data bytes, possibly including a byte * with SMBus PEC. The transfer terminates with a NAK, or when all those * bytes have been transferred and ACKed. If this is the last message in a * group, it is followed by a STOP. Otherwise it is followed by the next * @i2c_msg transaction segment, beginning with a (repeated) START. * * Alternatively, when the adapter supports I2C_FUNC_PROTOCOL_MANGLING then * passing certain @flags may have changed those standard protocol behaviors. * Those flags are only for use with broken/nonconforming slaves, and with * adapters which are known to support the specific mangling options they * need (one or more of IGNORE_NAK, NO_RD_ACK, NOSTART, and REV_DIR_ADDR). */ 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 */ };
/* * i2c_adapter is the structure used to identify a physical i2c bus along * with the access algorithms necessary to access it. */ struct i2c_adapter { struct module *owner; unsigned int id; 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 */ u8 level; /* nesting level for lockdep */ struct mutex bus_lock; int timeout; /* in jiffies */ int retries; struct device dev; /* the adapter device */ int nr; char name[48]; struct completion dev_released; }; #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
/* * The following structs are for those who like to implement new bus drivers: * i2c_algorithm is the interface to a class of hardware solutions which can * be addressed using the same bus algorithms - i.e. bit-banging or the PCF8584 * to name two of the most common. */ 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 *); };
/** * struct i2c_board_info - template for device creation * @type: chip type, to initialize i2c_client.name * @flags: to initialize i2c_client.flags * @addr: stored in i2c_client.addr * @platform_data: stored in i2c_client.dev.platform_data * @archdata: copied into i2c_client.dev.archdata * @irq: stored in i2c_client.irq * * I2C doesn't actually support hardware probing, although controllers and * devices may be able to use I2C_SMBUS_QUICK to tell whether or not there's * a device at a given address. Drivers commonly need more information than * that, such as chip type, configuration, associated IRQ, and so on. * * i2c_board_info is used to build tables of information listing I2C devices * that are present. This information is used to grow the driver model tree. * For mainboards this is done statically using i2c_register_board_info(); * bus numbers identify adapters that aren't yet available. For add-on boards, * i2c_new_device() does this dynamically with the adapter already known. */ struct i2c_board_info { char type[I2C_NAME_SIZE]; unsigned short flags; unsigned short addr; void *platform_data; struct dev_archdata *archdata; int irq; };
s3c2440的i2c主控制器仅5个寄存器,在linux内核中却搞得这么繁杂,,,,,
IICCON 0x54000000 R/W IIC-Bus control register
IICSTAT 0x54000004 R/W IIC-Bus control/status register
IICADD 0x54000008 R/W IIC-Bus address register
IICDS 0x5400000C R/W IIC-Bus transmit/receive data shift register
IICLC 0x54000010 R/W IIC-Bus multi-master line control register
并且micro2440的eeprom的i2c驱动最外层是platform总线然后是i2c总线然后才是面向用户访问的字符设备。。。
目前的一点个人理解,有待更新。。。
存在的问题,在insmod时i2c核心具体怎么匹配外设驱动(设备)和总线(控制器驱动),在ioctl时i2c核心具体怎么处理(匹配)外设驱动和总线,i2c具体数据的传输。有时间再去细读。
对总线设备驱动模型认识不清,对sysfs认识不清,对mdev如何利用sysfs创建设备节点的过程不清。
refer to
http://blog.csdn.net/cjok376240497/article/details/6982883
http://blog.csdn.net/hongtao_liu/article/details/4964244
http://blog.csdn.net/hongtao_liu/article/details/5260739