i2c-core.c这个文件实现了I2C核心的功能以及/proc/bus/i2c*接口。    i2c-dev.c实现了I2C适配器设备文件的功能,每一个I2C适配器都被分配一个设备。通过适配器访设备时的主设备号都为89,次设备号为0-255。I2c-dev.c并没有针对特定的设备而设计,只是提供了通用的read(),write(),和ioctl()等接口,应用层可以借用这些接口访问挂接在适配器上的I2C设备的存储空间或寄存器,并控制I2C设备的工作方式。  busses文件夹这个文件中包含了一些I2C总线的驱动,如针对S3C2410,S3C2440,S3C6410等处理器的I2C控制器驱动为i2c-s3c2410.c.  algos文件夹实现了一些I2C总线适配器的algorithm.////////////////////////////////////////////////////////////////////////////////////描述6410芯片里I2C控制器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};///////////////////////////////////////////////////////////////////////////////////module_init(i2c_adap_s3c_init);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;}////////////////////////////////////////////////////////////////////////////////////* device driver for platform bus bits */static struct platform_driver s3c2410_i2c_driver = {//Probe的规则是:如果BUS上实现了probe就用BUS的probe;否则才会用driver的probe    .probe        = s3c24xx_i2c_probe,    .remove        = s3c24xx_i2c_remove,    .suspend_late    = s3c24xx_i2c_suspend_late,    .resume        = s3c24xx_i2c_resume,    .driver        = {        .owner    = THIS_MODULE,//platform_device s3c_device_i2c0 >相互匹配        .name    = "s3c2410-i2c",    },};BUS上实现的.match()函数,定义了Device和Driver绑定时的规则。比如Platform实现的就是先比较id_table,然后比较name的规则。如果BUS的match()函数没实现,认为BUS上的所有的Device和Driver都是match的,具体后续过程要看probe()的实现了////////////////////////////////////////////////////////////////////////////////////* s3c24xx_i2c_probe * * called by the bus driver when a suitable device is found*/与//platform_device s3c_device_i2c0 >相互匹配成功后调用s3c24xx_i2c_probestatic 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;    if (!pdata) {        dev_err(&pdev->dev, "no platform data\n");        return -EINVAL;    }    i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);    if (!i2c) {        dev_err(&pdev->dev, "no memory for state\n");        return -ENOMEM;    }    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 *///获取i2c寄存器内存地址    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);    if (res == NULL) {        dev_err(&pdev->dev, "cannot find IO resource\n");        ret = -ENOENT;        goto err_clk;    }    i2c->ioarea = request_mem_region(res->start, (res->end-res->start)+1,                     pdev->name);    if (i2c->ioarea == NULL) {        dev_err(&pdev->dev, "cannot request IO\n");        ret = -ENXIO;        goto err_clk;    }    i2c->regs = ioremap(res->start, (res->end-res->start)+1);    if (i2c->regs == NULL) {        dev_err(&pdev->dev, "cannot map IO\n");        ret = -ENXIO;        goto err_ioarea;    }    dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",        i2c->regs, i2c->ioarea, res);    /* setup info block for the i2c core */    i2c->adap.algo_data = i2c;    i2c->adap.dev.parent = &pdev->dev;    /* initialise the i2c controller */    ret = s3c24xx_i2c_init(i2c);    if (ret != 0)        goto err_iomap;    /* find the IRQ for this unit (note, this relies on the init call to     * ensure no current IRQs pending     *///获取i2c irq中断资源   在platform设备和驱动里定义的。    i2c->irq = ret = platform_get_irq(pdev, 0);    if (ret        dev_err(&pdev->dev, "cannot find IRQ\n");        goto err_iomap;    }//申请i2c  IRQ中断    ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,              dev_name(&pdev->dev), i2c);    if (ret != 0) {        dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);        goto err_iomap;    }    ret = s3c24xx_i2c_register_cpufreq(i2c);    if (ret        dev_err(&pdev->dev, "failed to register cpufreq notifier\n");        goto err_irq;    }    /* Note, previous versions of the driver used i2c_add_adapter()     * to add the bus at any number. We now pass the bus number via     * the platform data, so if unset it will now default to always     * being bus 0.     *///见//i2c_scan_static_board_info函数// if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter,&devinfo->board_info))//只有如果adapter的号码和节点中的号码相同,才会调用i2c_new_device创建i2c clien    i2c->adap.nr = pdata->bus_num;//注册了struct i2c_adapter//并且根据i2c_register_board_info()添加到链表里的板子信息注册    struct i2c_client////执行完i2c_add_numbered_adapter函数后,内核的i2c总线上已有adapter device和client device//在里    ret = i2c_add_numbered_adapter(&i2c->adap);    if (ret        dev_err(&pdev->dev, "failed to add bus to i2c core\n");        goto err_cpufreq;    }    platform_set_drvdata(pdev, i2c);    dev_info(&pdev->dev, "%s: S3C I2C adapter\n", i2c->adap.dev.bus_id);    return 0; err_cpufreq:    s3c24xx_i2c_deregister_cpufreq(i2c); err_irq:    free_irq(i2c->irq, i2c); err_iomap:    iounmap(i2c->regs); err_ioarea:    release_resource(i2c->ioarea);    kfree(i2c->ioarea); err_clk:    clk_disable(i2c->clk);    clk_put(i2c->clk); err_noclk:    kfree(i2c);    return ret;}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////* i2c bus registration info *///用于读写传输的算法结构static const struct i2c_algorithm s3c24xx_i2c_algorithm = {    .master_xfer        = s3c24xx_i2c_xfer,    .functionality        = s3c24xx_i2c_func,};////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////* s3c24xx_i2c_xfer * * first port of call from the i2c bus code when an message needs * transferring across the i2c bus.*/static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,            struct i2c_msg *msgs, int num){    struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data;    int retry;    int ret;    for (retry = 0; retry retries; retry++) {        ret = s3c24xx_i2c_doxfer(i2c, msgs, num);        if (ret != -EAGAIN)            return ret;        dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry);        udelay(100);    }    return -EREMOTEIO;}///////////////////////////////////////////////////////////////////////////////////* s3c24xx_i2c_doxfer * * this starts an i2c transfer*/static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,                  struct i2c_msg *msgs, int num){    unsigned long timeout;    int ret;    if (i2c->suspended)        return -EIO;    ret = s3c24xx_i2c_set_master(i2c);    if (ret != 0) {        dev_err(i2c->dev, "cannot get bus (error %d)\n", ret);        ret = -EAGAIN;        goto out;    }    spin_lock_irq(&i2c->lock);    i2c->msg     = msgs;    i2c->msg_num = num;    i2c->msg_ptr = 0;    i2c->msg_idx = 0;    i2c->state   = STATE_START;    s3c24xx_i2c_enable_irq(i2c);    s3c24xx_i2c_message_start(i2c, msgs);    spin_unlock_irq(&i2c->lock);    timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);    ret = i2c->msg_idx;    /* having these next two as dev_err() makes life very     * noisy when doing an i2cdetect */    if (timeout == 0)        dev_dbg(i2c->dev, "timeout\n");    else if (ret != num)        dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);    /* ensure the stop has been through the bus */    msleep(1); out:    return ret;}///////////////////////////////////////////////////////////////////////////////////* s3c24xx_i2c_message_start * * put the start of a message onto the bus*///最终的最底层的读写函数在此static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,                      struct i2c_msg *msg){    unsigned int addr = (msg->addr & 0x7f)    unsigned long stat;    unsigned long iiccon;    stat = 0;    stat |=  S3C2410_IICSTAT_TXRXEN;    if (msg->flags & I2C_M_RD) {        stat |= S3C2410_IICSTAT_MASTER_RX;        addr |= 1;    } else        stat |= S3C2410_IICSTAT_MASTER_TX;    if (msg->flags & I2C_M_REV_DIR_ADDR)        addr ^= 1;    /* todo - check for wether ack wanted or not */    s3c24xx_i2c_enable_ack(i2c);    iiccon = readl(i2c->regs + S3C2410_IICCON);    writel(stat, i2c->regs + S3C2410_IICSTAT);    dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr);    writeb(addr, i2c->regs + S3C2410_IICDS);    /* delay here to ensure the data byte has gotten onto the bus     * before the transaction is started */    ndelay(i2c->tx_setup);    dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon);    writel(iiccon, i2c->regs + S3C2410_IICCON);    stat |= S3C2410_IICSTAT_START;    writel(stat, i2c->regs + S3C2410_IICSTAT);}/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////* s3c24xx_i2c_irq * * top level IRQ servicing routine*///芯片手册s3c6410    iic一章。//在i2c时序的ACK时会产生中断,ACK是在一个字节数据发送完时出现ACK。static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id){//dev_id这个参数是s3c24xx_i2c_probe函数里的    struct s3c24xx_i2c *i2c;这个类型的成员    struct s3c24xx_i2c *i2c = dev_id;    unsigned long status;    unsigned long tmp;    status = readl(i2c->regs + S3C2410_IICSTAT);    if (status & S3C2410_IICSTAT_ARBITR) {        /* deal with arbitration loss */        dev_err(i2c->dev, "deal with arbitration loss\n");    }    if (i2c->state == STATE_IDLE) {        dev_dbg(i2c->dev, "IRQ: error i2c->state == IDLE\n");        tmp = readl(i2c->regs + S3C2410_IICCON);        tmp &= ~S3C2410_IICCON_IRQPEND;        writel(tmp, i2c->regs +  S3C2410_IICCON);        goto out;    }    /* pretty much this leaves us with the fact that we've     * transmitted or received whatever byte we last sent */    i2s_s3c_irq_nextbyte(i2c, status); out:    return IRQ_HANDLED;}
12-09 21:38
查看更多