您的位置:首页 > 其它

i2c--ioctl--主机控制器驱动(i2c_adapter)--外设驱动(i2c_driver)

2011-12-02 08:07 543 查看
updating...

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

很明确的说明了client就是把driver(i2c-dev.c)和adapter(i2c-s3c2410.c)关联

回到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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: