linux i2c驱动分析 s3c6410 (3)

来源:互联网 发布:万方数据库检索方法 编辑:程序博客网 时间:2024/05/17 01:39

       上一此说到了驱动和设备匹配,中间隔了几天读了下 LDD3   ch14: The Linux Device Model,受益匪浅。 

       平台驱动中添加  .id_table 成员好处是   使驱动和设备可以一对多,即一个驱动可以支持多个设备。如果我们只使用设备里的  name 和驱动里的name进行匹配匹配那么设备和驱动只能一对一了。

static struct platform_device_id s3c24xx_driver_ids[] = {{.name= "s3c2410-i2c",.driver_data= TYPE_S3C2410,}, {.name= "s3c2440-i2c",.driver_data= TYPE_S3C2440,}, { },};

       关于设备和驱动匹配后如何绑定的我们来继续分析代码

static int __driver_attach(struct device *dev, void *data){struct device_driver *drv = data;/* * Lock device and try to bind to it. We drop the error * here and always return 0, because we need to keep trying * to bind to devices and some drivers will return an error * simply if it didn't support the device. * * driver_probe_device() will spit a warning if there * is an error. */if (!driver_match_device(drv, dev))   //匹配return 0;if (dev->parent)/* Needed for USB */device_lock(dev->parent);device_lock(dev);if (!dev->driver)driver_probe_device(drv, dev);  //绑定device_unlock(dev);if (dev->parent)device_unlock(dev->parent);return 0;}
上节分析到 在
driver_match_device(drv, dev)
中完成了驱动和设备的匹配,  向下看 driver_probe_device(drv, dev) 函数  注释上写了 试图把设备和驱动绑定到一起。呵呵,像月老用红绳把痴男怨女的脚绑到一起,才突然明白为什么这么多年轻人手上面系着红绳。
/** * driver_probe_device - attempt to bind device & driver together * @drv: driver to bind a device to * @dev: device to try to bind to the driver * * This function returns -ENODEV if the device is not registered, * 1 if the device is bound successfully and 0 otherwise. * * This function must be called with @dev lock held.  When called for a * USB interface, @dev->parent lock must be held as well. */int driver_probe_device(struct device_driver *drv, struct device *dev){int ret = 0;if (!device_is_registered(dev))return -ENODEV;pr_debug("bus: '%s': %s: matched device %s with driver %s\n", drv->bus->name, __func__, dev_name(dev), drv->name);pm_runtime_get_noresume(dev);pm_runtime_barrier(dev);ret = really_probe(dev, drv);pm_runtime_put_sync(dev);return ret;}
继续分析里面有个 real_probe(dev, drv) 函数  

static int really_probe(struct device *dev, struct device_driver *drv){int ret = 0;atomic_inc(&probe_count);pr_debug("bus: '%s': %s: probing driver %s with device %s\n", drv->bus->name, __func__, drv->name, dev_name(dev));WARN_ON(!list_empty(&dev->devres_head));dev->driver = drv;   //呵呵 终于看到了if (driver_sysfs_add(dev)) {printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",__func__, dev_name(dev));goto probe_failed;}if (dev->bus->probe) {ret = dev->bus->probe(dev);if (ret)goto probe_failed;} else if (drv->probe) {ret = drv->probe(dev);if (ret)goto probe_failed;}driver_bound(dev);ret = 1;pr_debug("bus: '%s': %s: bound device %s to driver %s\n", drv->bus->name, __func__, dev_name(dev), drv->name);goto done;probe_failed:devres_release_all(dev);driver_sysfs_remove(dev);dev->driver = NULL;if (ret != -ENODEV && ret != -ENXIO) {/* driver matched but the probe failed */printk(KERN_WARNING       "%s: probe of %s failed with error %d\n",       drv->name, dev_name(dev), ret);}/* * Ignore errors returned by ->probe so that the next driver can try * its luck. */ret = 0;done:atomic_dec(&probe_count);wake_up(&probe_waitqueue);return ret;}

看到一行 dev->driver = drv, 这样应该就是把设备结构里的驱动指向了 我们注册的 driver。那下面为什么还有一行driver_bound(dev),看样还要继续分析。

static void driver_bound(struct device *dev){if (klist_node_attached(&dev->p->knode_driver)) {printk(KERN_WARNING "%s: device %s already bound\n",__func__, kobject_name(&dev->kobj));return;}pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev), __func__, dev->driver->name);klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);if (dev->bus)blocking_notifier_call_chain(&dev->bus->p->bus_notifier,     BUS_NOTIFY_BOUND_DRIVER, dev);}
此把设备加入了驱动的的设备链表。

中间还落下了一部分 就是 real_probe(dev, drv) 函数  的

if (dev->bus->probe) {ret = dev->bus->probe(dev);if (ret)goto probe_failed;} else if (drv->probe) {ret = drv->probe(dev);if (ret)goto probe_failed;}
此处就是调用了 

static struct platform_driver s3c24xx_i2c_driver = {.probe= s3c24xx_i2c_probe,.remove= s3c24xx_i2c_remove,.id_table= s3c24xx_driver_ids,.driver= {.owner= THIS_MODULE,.name= "s3c-i2c",.pm= S3C24XX_DEV_PM_OPS,},};

的  s3c_i2c_probe  函数。   此处要明确下,处传给s3c_i2c_probe 的参数是 我们注册的i2c 平台设备 s3c_device_i2c0

/* s3c24xx_i2c_probe * * called by the bus driver when a suitable device is found*/static int s3c24xx_i2c_probe(struct platform_device *pdev){struct s3c24xx_i2c *i2c;   //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);  //为i2c控制器申请空间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 */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, resource_size(res), pdev->name);if (i2c->ioarea == NULL) {dev_err(&pdev->dev, "cannot request IO\n");ret = -ENXIO;goto err_clk;}i2c->regs = ioremap(res->start, resource_size(res));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 = ret = platform_get_irq(pdev, 0);if (ret <= 0) {dev_err(&pdev->dev, "cannot find IRQ\n");goto err_iomap;}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 < 0) {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->adap.nr = pdata->bus_num;ret = i2c_add_numbered_adapter(&i2c->adap);if (ret < 0) {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", dev_name(&i2c->adap.dev));clk_disable(i2c->clk);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;}

此函数明天继续分析  再见