日期:2014-05-16  浏览次数:20629 次

Linux IIC框架(上)

        IIC的框架结构和SPI是类似的,它们都拥有总线驱动层(IIC主控制器驱动层),核心层和从设备驱动层。本节主要介绍IIC主控制器的注册以及从设备的注册过程。首先要介绍描述IIC主控制器的结构struct i2c_adapter和描述IIC从设备的结构struct i2c_client

struct i2c_adapter的定义如下:

struct i2c_adapter {
	struct module *owner;  /*所属模块*/
	unsigned int id;        /*algorithm的类型*/
	unsigned int class;	    /* classes to allow probing for */
	const struct i2c_algorithm *algo; /*总线通信方法*/
	void *algo_data;       /*algorithm的数据*/

	/* --- administration stuff. */
	/*从设备注册时调用*/
	int (*client_register)(struct i2c_client *) __deprecated;
	/*从设备注销时调用*/
	int (*client_unregister)(struct i2c_client *) __deprecated;

	/* data fields that are valid for all devices	*/
	u8 level; 			/* nesting level for lockdep */
	struct mutex bus_lock;
	struct mutex clist_lock;

	int timeout;			/* in jiffies */
	int retries;           /*重试次数*/
	struct device dev;		

	int nr;                     /*主控制器的编号*/
	struct list_head clients;	/*用于链接从设备的链表头*/
	char name[48];              /*控制器名*/
	struct completion dev_released;/*用于同步的完成量*/
};

algo中定义了主控制器的的数据传输方式,client是一个链表头,由于可能有多个从设备挂接在该总线上,因此client用于链接该控制器下的从设备

 

和SPI控制器一样,IIC控制器也是平台资源,因此以platform的方式注册进内核

static int __init i2c_adap_s3c_init(void)
{
	int ret;

	ret = platform_driver_register(&s3c2410_i2c_driver);
	if (ret == 0) {
		ret = platform_driver_register(&s3c2440_i2c_driver);
		if (ret)
			platform_driver_unregister(&s3c2410_i2c_driver);
	}

	return ret;
}


s3c2410_i2c_driver和s3c2440_i2c_driver的定义除了name字段不一样外,其他部分都一样

static struct platform_driver s3c2410_i2c_driver = {
	.probe		= s3c24xx_i2c_probe,
	.remove		= s3c24xx_i2c_remove,
	.suspend_late	= s3c24xx_i2c_suspend_late,
	.resume		= s3c24xx_i2c_resume,
	.driver		= {
		.owner	= THIS_MODULE,
		.name	= "s3c2410-i2c",
	},
};

static struct platform_driver s3c2440_i2c_driver = {
	.probe		= s3c24xx_i2c_probe,
	.remove		= s3c24xx_i2c_remove,
	.suspend_late	= s3c24xx_i2c_suspend_late,
	.resume		= s3c24xx_i2c_resume,
	.driver		= {
		.owner	= THIS_MODULE,
		.name	= "s3c2440-i2c",
	},
};


当和platform_device匹配成功后,便调用s3c24xx_i2c_probe()函数

static int s3c24xx_i2c_probe(struct platform_device *pdev)
{
	struct s3c24xx_i2c *i2c;
	struct s3c2410_platform_i2c *pdata;
	struct resource *res;
	int ret;

	pdata = pdev->dev.platform_data;//获取平台IIC数据
	if (!pdata) {
		dev_err(&pdev->dev, "no platform data\n");
		return -EINVAL;
	}

	/*创建一个struct s3c24xx_i2c*/
	i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);
	if (!i2c) {
		dev_err(&pdev->dev, "no memory for state\n");
		return -ENOMEM;
	}

	/*设置IIC总线的相关项*/
	strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));
	i2c->adap.owner   = THIS_MODULE;
	i2c->adap.algo    = &s3c24xx_i2c_algorithm;
	i2c->adap.retries = 2;
	i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;
	i2c->tx_setup     = 50;

	spin_lock_init(&i2c->lock);
	init_waitqueue_head(&i2c->wait);//初始化等待队列

	/* find the clock and enable it */

	i2c->dev = &pdev->dev;
	i2c->clk = clk_get(&pdev->dev, "i2c");
	if (IS_ERR(i2c->clk)) {
		dev_err(&pdev->dev, "cannot get clock\n");
		ret = -ENOENT;
		goto err_noclk;
	}

	dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);

	clk_enable(i2c->clk);

	/* map the registers */

	/*获取IIC的资源*/
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (res == NULL) {
		dev_err(&pdev->dev, "cannot find IO resource\n");
		ret = -ENOENT