[size=0.32]static int s3c24xx_i2c_probe(struct platform_device *pdev) [size=0.32]{ [size=0.32] struct s3c24xx_i2c *i2c;//最重要的结构体 [size=0.32] //保存设备树信息 [size=0.32] struct s3c2410_platform_i2c *pdata = NULL; [size=0.32] struct resource *res; [size=0.32] int ret;
[size=0.32] if (!pdev->dev.of_node) { [size=0.32] pdata = dev_get_platdata(&pdev->dev); [size=0.32] if (!pdata) { [size=0.32] dev_err(&pdev->dev, "no platform data\n"); [size=0.32] return -EINVAL; [size=0.32] } [size=0.32] } [size=0.32] /*为结构体变量i2c分配内存*/ [size=0.32] i2c = devm_kzalloc(&pdev->dev, sizeof(struct s3c24xx_i2c), GFP_KERNEL); [size=0.32] if (!i2c) { [size=0.32] dev_err(&pdev->dev, "no memory for state\n"); [size=0.32] return -ENOMEM; [size=0.32] }
[size=0.32] i2c->pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); [size=0.32] if (!i2c->pdata) { [size=0.32] dev_err(&pdev->dev, "no memory for platform data\n"); [size=0.32] return -ENOMEM; [size=0.32] } [size=0.32] /*i2c控制器的一些特殊行为 [size=0.32] #define QUIRK_S3C2440 (1 << 0) [size=0.32] #define QUIRK_HDMIPHY (1 << 1) [size=0.32] #define QUIRK_NO_GPIO (1 << 2) [size=0.32] #define QUIRK_POLL (1 << 3) [size=0.32] 其中bite:3如果采用轮训方式与底层硬件通信值为1,中断方式值为0*/ [size=0.32] i2c->quirks = s3c24xx_get_device_quirks(pdev); [size=0.32] if (pdata) [size=0.32] memcpy(i2c->pdata, pdata, sizeof(*pdata)); [size=0.32] else [size=0.32] s3c24xx_i2c_parse_dt(pdev->dev.of_node, i2c);
[size=0.32] strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name)); [size=0.32] i2c->adap.owner = THIS_MODULE; [size=0.32] /*为i2c_msg传输方法赋值,*/ [size=0.32] i2c->adap.algo = &s3c24xx_i2c_algorithm; [size=0.32] i2c->adap.retries = 2; [size=0.32] i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; [size=0.32] i2c->tx_setup = 50; [size=0.32] //初始化等待队列,该等待队列用于唤醒读写数据的进程 [size=0.32] init_waitqueue_head(&i2c->wait);
[size=0.32] /* find the clock and enable it */
[size=0.32] i2c->dev = &pdev->dev; [size=0.32] //获取时钟 [size=0.32] i2c->clk = devm_clk_get(&pdev->dev, "i2c"); [size=0.32] if (IS_ERR(i2c->clk)) { [size=0.32] dev_err(&pdev->dev, "cannot get clock\n"); [size=0.32] return -ENOENT; [size=0.32] } [size=0.32] dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk); [size=0.32] /* map the registers */ [size=0.32] //通过pdev得到i2c控制器的寄存器地址资源 [size=0.32] res = platform_get_resource(pdev, IORESOURCE_MEM, 0); [size=0.32] //映射i2c控制器的物理基地址为虚拟基地址 [size=0.32] i2c->regs = devm_ioremap_resource(&pdev->dev, res);
[size=0.32] if (IS_ERR(i2c->regs)) [size=0.32] return PTR_ERR(i2c->regs);
[size=0.32] dev_dbg(&pdev->dev, "registers %p (%p)\n", [size=0.32] i2c->regs, res);
[size=0.32] /* setup info block for the i2c core */ [size=0.32] /*将结构体变量i2c保存到i2c_adapter的私有变量指针algo_data, [size=0.32] 编写i2c设备驱动可以通过adapter指针找到结构体i2c*/ [size=0.32] i2c->adap.algo_data = i2c; [size=0.32] i2c->adap.dev.parent = &pdev->dev;
[size=0.32] i2c->pctrl = devm_pinctrl_get_select_default(i2c->dev);
[size=0.32] /* inititalise the i2c gpio lines */ [size=0.32] //得到i2c复用的gpio引脚并初始化 [size=0.32] if (i2c->pdata->cfg_gpio) { [size=0.32] i2c->pdata->cfg_gpio(to_platform_device(i2c->dev)); [size=0.32] } else if (IS_ERR(i2c->pctrl) && s3c24xx_i2c_parse_dt_gpio(i2c)) { [size=0.32] return -EINVAL; [size=0.32] }
[size=0.32] /* initialise the i2c controller */
[size=0.32] clk_prepare_enable(i2c->clk); [size=0.32] /*将从设备地址写入寄存器S3C2410_IICADD,同时初始化时钟频率*/ [size=0.32] ret = s3c24xx_i2c_init(i2c); [size=0.32] clk_disable_unprepare(i2c->clk); [size=0.32] if (ret != 0) { [size=0.32] dev_err(&pdev->dev, "I2C controller init failed\n"); [size=0.32] return ret; [size=0.32] } [size=0.32] /* find the IRQ for this unit (note, this relies on the init call to [size=0.32] * ensure no current IRQs pending [size=0.32] */
[size=0.32] if (!(i2c->quirks & QUIRK_POLL)) { [size=0.32] /*获得中断号*/ [size=0.32] i2c->irq = ret = platform_get_irq(pdev, 0); [size=0.32] if (ret <= 0) { [size=0.32] dev_err(&pdev->dev, "cannot find IRQ\n"); [size=0.32] return ret; [size=0.32] } [size=0.32] /*注册中断处理函数s3c24xx_i2c_irq()*/ [size=0.32] ret = devm_request_irq(&pdev->dev, i2c->irq, s3c24xx_i2c_irq, 0, [size=0.32] dev_name(&pdev->dev), i2c);
[size=0.32] if (ret != 0) { [size=0.32] dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq); [size=0.32] return ret; [size=0.32] } [size=0.32] }
[size=0.32] ret = s3c24xx_i2c_register_cpufreq(i2c); [size=0.32] if (ret < 0) { [size=0.32] dev_err(&pdev->dev, "failed to register cpufreq notifier\n"); [size=0.32] return ret; [size=0.32] }
[size=0.32] /* Note, previous versions of the driver used i2c_add_adapter() [size=0.32] * to add the bus at any number. We now pass the bus number via [size=0.32] * the platform data, so if unset it will now default to always [size=0.32] * being bus 0. [size=0.32] */ [size=0.32] /*保存i2c控制器的通道号,本例是bus 5*/ [size=0.32] i2c->adap.nr = i2c->pdata->bus_num; [size=0.32] i2c->adap.dev.of_node = pdev->dev.of_node; [size=0.32] //注册adapter [size=0.32] ret = i2c_add_numbered_adapter(&i2c->adap); [size=0.32] if (ret < 0) { [size=0.32] dev_err(&pdev->dev, "failed to add bus to i2c core\n"); [size=0.32] s3c24xx_i2c_deregister_cpufreq(i2c); [size=0.32] return ret; [size=0.32] } [size=0.32] /*保存私有变量i2c到pdev->dev->p->driver_data*/ [size=0.32] platform_set_drvdata(pdev, i2c);
[size=0.32] pm_runtime_enable(&pdev->dev); [size=0.32] pm_runtime_enable(&i2c->adap.dev);
[size=0.32] dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev)); [size=0.32] return 0; [size=0.32]} |