日期:2014-05-16 浏览次数:20669 次
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