I2C系统中的重要结构

I2C硬件框架

在这里插入图片描述
Linux使用i2c_adapter来表示i2c Controller

//在include/linux/i2c.h中
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 */	/* 这里有i2c的传输函数 */
    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;					/* 表示第几个i2c控制器,第几条i2c总线 */
    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;
    const struct i2c_adapter_quirks *quirks;
};

i2c_algorithm的结构

//在include/linux/i2c.h中
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);				//这里就是i2c的传输函数
    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 *);

#if IS_ENABLED(CONFIG_I2C_SLAVE)
    int (*reg_slave)(struct i2c_client *client);
    int (*unreg_slave)(struct i2c_client *client);
#endif
};
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	*/	/* 挂在哪个i2c总线上 */
	struct device dev;		/* the device structure		*/
	int irq;			/* irq issued by device		*/
	struct list_head detected;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
	i2c_slave_cb_t slave_cb;	/* callback for slave mode	*/
#endif
};
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          */
};

总结

i2c_client代表一个挂载到i2操纵线上的i2c从设备,该设备所需要的数据结构,其中包括

  • 该i2c从设备所依附的i2c主设备(struct i2c_adapter *adapter)
  • 该i2c从设备的驱动程序(struct i2c_driver *driver)
  • i2c设备所通用的属性,比如addr,name等
  • 该i2c从设备驱动所特有的数据,在dev->driver_data下

i2c_adapter代表主芯片所支持的一个i2c主设备,该设备需要的数据结构。
const struct i2c_algorithm *algo是该i2c主设备传输数据的一种算法,或者说是在i2c总线上完成主从设备间数据通信的一种能力。

i2c-dev.c源码学习

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;

    i2c_dev = i2c_dev_get_by_minor(minor);	//根据次设备号获取i2c_dev
    if (!i2c_dev)
        return -ENODEV;

    adap = i2c_get_adapter(i2c_dev->adap->nr);		//根据i2c_dev获取i2c_adapter
    if (!adap)
        return -ENODEV;

    /* 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);	//分配i2c_client表示I2C设备,但是还没有分配设备地址
    if (!client) {
        i2c_put_adapter(adap);
        return -ENOMEM;
    }
    snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);

    client->adapter = adap;		//client和adapter建立联系
    file->private_data = client;	//作为文件的私有数据暂存起来

    return 0;
}
static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    struct i2c_client *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:
        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;							//设置i2c地址
        return 0;
    case I2C_TENBIT:
        if (arg)
            client->flags |= I2C_M_TEN;
        else
            client->flags &= ~I2C_M_TEN;
        return 0;
    case I2C_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_rdwr(client, arg);

    case I2C_SMBUS:
        return i2cdev_ioctl_smbus(client, arg);
	//....	
    }
    return 0;
}

static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client,
        unsigned long arg)
{
	//...
	res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs);		//发起i2c传输
    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;
}

static noinline int i2cdev_ioctl_smbus(struct i2c_client *client,
        unsigned long arg)
{
	//...
    res = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
          data_arg.read_write, data_arg.command, data_arg.size, &temp);		//发起smbus传输
    if (!res && ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
             (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
             (data_arg.read_write == I2C_SMBUS_READ))) {
        if (copy_to_user(data_arg.data, &temp, datasize))				//如果是读数据,就返回给用户
            return -EFAULT;
    }
    return res;
}

总结

在这里插入图片描述
在用户层打开的时候,驱动会从设备次设备号中获取i2c_adpater,然后获取i2c_client保存进file的私有数据。
在app调用ioctl(I2C_RDWR)或者ioctl(I2C_SMBUS)时,驱动会去调用i2c_transfer或者i2c_smbus_xfer去读写数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

习惯就好zz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值