linux IIC子系统分析(六)——I2c plaform driver 初始化
来源:互联网 发布:部落冲突亡灵升级数据 编辑:程序博客网 时间:2024/04/18 20:54
完成platform device注册之后,接下来需要初始化的是platform driver。
在driver/i2c/busees 目录下的i2c_s3c2410c 中有函数:
driver/i2c/busees/i2c_s3c2410.c
static int __init i2c_adap_s3c_init(void){return platform_driver_register(&s3c24xx_i2c_driver); (1.0)}subsys_initcall(i2c_adap_s3c_init);(1.0)完成platform driver的注册操作。
s3c24xx_i2c_driver 被定义为:
static struct platform_driver s3c24xx_i2c_driver = {.probe= s3c24xx_i2c_probe,.remove= s3c24xx_i2c_remove,.id_table= s3c24xx_driver_ids, (2.0).driver= {.owner= THIS_MODULE,.name= "s3c-i2c",.pm= S3C24XX_DEV_PM_OPS,},};(2.0)设备表赋值,其中设备表被定义为:
static struct platform_device_id s3c24xx_driver_ids[] = {{.name= "s3c2410-i2c",.driver_data= TYPE_S3C2410,}, {.name= "s3c2440-i2c",.driver_data= TYPE_S3C2440,}, { },};MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); (3.0)(3.0)使用MODULE_DEVICE_TABLE 宏声明,s3c24xx_driver_ids 是platform类型的一个设备表。
platform driver 在被注册到platform bus 上的时候,会与已经注册到platform bus 上的所有platform device 进行名字配对。但是这里platform driver 有多个名字,所以就使用id_table 来实现配对。与I2C platform device相匹配的名字是:s3c2410-i2c
回到(1.0)处,我们看platform_driver_register函数,跟踪代码发现:
platform_driver_register
driver_register
bus_add_driver
/drivers/base/Bus.c
int bus_add_driver(struct device_driver *drv){......if (drv->bus->p->drivers_autoprobe) {error = driver_attach(drv);<span style="white-space:pre"></span>(1.1)if (error)goto out_unregister;}<span style="white-space:pre"></span>......if (!drv->suppress_bind_attrs) {error = add_bind_files(drv);<span style="white-space:pre"></span>(1.2)if (error) {/* Ditto */printk(KERN_ERR "%s: add_bind_files(%s) failed\n",__func__, drv->name);}}<span style="white-space:pre"></span>......}
(1.1)进行platform device与platform driver 的配对
(1.2)进行platform device 与platform driver 的绑定
在绑定函数中:
static int __must_check add_bind_files(struct device_driver *drv){int ret;ret = driver_create_file(drv, &driver_attr_unbind);if (ret == 0) {ret = driver_create_file(drv, &driver_attr_bind); (1.3)if (ret)driver_remove_file(drv, &driver_attr_unbind);}return ret;}(1.3) 这里会调用dirver_bind函数:
static ssize_t driver_bind(struct device_driver *drv, const char *buf, size_t count){struct bus_type *bus = bus_get(drv->bus);struct device *dev;int err = -ENODEV;dev = bus_find_device_by_name(bus, NULL, buf);if (dev && dev->driver == NULL && driver_match_device(drv, dev)) {if (dev->parent)/* Needed for USB */down(&dev->parent->sem);down(&dev->sem);err = driver_probe_device(drv, dev); (1.5)up(&dev->sem);if (dev->parent)up(&dev->parent->sem);if (err > 0) {/* success */err = count;} else if (err == 0) {/* driver didn't accept device */err = -ENODEV;}}put_device(dev);bus_put(bus);return err;}static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind); (1.4)(1.4)DRIVER_ATTR 的定义为下面的这个宏,这也是为什么(1.3)处会调用到driver_bind 函数。
#define DRIVER_ATTR(_name, _mode, _show, _store) \struct driver_attribute driver_attr_##_name = \ __ATTR(_name, _mode, _show, _store)
(1.5)进一步分析probe函数:
driver_probe_device
really_probe
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) {<span style="white-space:pre"></span>(1.6)ret = dev->bus->probe(dev);if (ret)goto probe_failed;} else if (drv->probe) {ret = drv->probe(dev);<span style="white-space:pre"></span>(1.7)if (ret)goto probe_failed;}driver_bound(dev);<span style="white-space:pre"></span>......}在(1.6)我们的bus->probe 是没有提供probe 方法的,因此调用的是下面(1.7)drv->probe(dev),也就是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; (5.0)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; (6.0)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); (7.0)/* 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); (8.0)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, (9.0) 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); (1.0)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));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;}
(5.0)获取s3c24xx_i2c.platform_data 里面i2c的一些设备参数,也就是在platform device 注册到内核的那些设备信息。
(6.0)初始化algo 算法。
(7.0)初始化一个等待队列
(8.0)初始化i2c 控制器,主要是针对s3c24xx_i2c 寄存器的一些操作。
(9.0)申请中断,内核中i2c的读写通过中断来实现。
(10)向系统注册一个i2c adapter
初始化到这里,IIC总线设备已经初始化完成。也就是I2C硬件体系结构中适配器端的驱动程序已经完成。
如果需要调用I2C子系统去访问客户端设备,这里还需要添加I2C设备驱动(客户驱动)
说明:
1.分析的内核版本是linux2.6.32.2
2.开发板为友善之臂的mini2440, 用的是ARM9(S3C2440A)处理器
3.链接的IIC设备是EEPROM(AT24C02)
4.按照内核I2C子系统的注册顺序分析。
- linux IIC子系统分析(六)——I2c plaform driver 初始化
- linux IIC子系统分析(五)——I2C plaform device 初始化
- linux IIC子系统分析(四)——I2c bus初始化
- linux IIC子系统分析(三)——I2c子系统初始化顺序分析
- linux IIC子系统分析(三)——I2c子系统初始化顺序分析
- linux IIC子系统分析(七)——实例分析通过i2c-dev操作I2C设备
- linux IIC子系统分析(七)——实例分析通过i2c-dev操作I2C设备
- linux IIC子系统分析(八)——实例分析通过sysfs访问I2c设备
- linux IIC子系统分析(九)——实例分析通过设备节点访问I2c设备
- linux IIC子系统分析(二)—— linux i2c 架构概述
- linux IIC子系统分析(一)——AT24C02 芯片简介
- Linux I2C 子系统分析
- Linux I2C子系统分析
- LINUX下IIC子系统分析
- i2c子系统之i2c bus初始化——i2c_init()
- I2C子系统之I2C bus初始化——I2C_init()
- i2c子系统之 adapter driver注册——i2c_dev_init()
- I2C子系统之 adapter driver注册——I2C_dev_init()
- N-0.5倍分频(Verilog)
- 如何学习android(看stay4it的笔记)+android stdio简单实用简介
- Oracle 执行计划优化
- AngularJs+bootstrap搭载前台框架2
- ThinkPHP中的行为扩展和插件详解
- linux IIC子系统分析(六)——I2c plaform driver 初始化
- Linear Layout
- 解决AngularJS使用ng-bind-html会过滤html中style属性的问题
- Ubuntu 14.04 安装xvid编码器
- 关于arcgis 9.3 Java服务器发布服务问题
- <LeetCode OJ> 357. Count Numbers with Unique Digits
- 单链表的增、删、查、改、逆置、排序
- restoration of CBCentralManager is only allowed for applications that have specified the "bluetooth-
- 图片压缩工具Thumbnailator的使用