Linux IIC框架(下)

Linux IIC框架(下)

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 datan");
return -EINVAL;
}

/*创建一个struct s3c24xx_i2c*/
i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);
if (!i2c) {
dev_err(&pdev->dev, "no memory for staten");
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 clockn");
ret = -ENOENT;
goto err_noclk;
}

dev_dbg(&pdev->dev, "clock source %pn", 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 resourcen");
ret = -ENOENT

Linux IIC框架(下)

相关文章:

你感兴趣的文章:

标签云: