Synopsys DesignWareI2C master init

来源:互联网 发布:广电总局封网络机顶盒 编辑:程序博客网 时间:2024/05/18 11:48
Synopsys DesignWare的I2C master的code主要在drivers/i2c/busses/I2C-designware-platdrv.c中。kernel中将I2C master也叫做 I2c adapter driver
static struct platform_driver dw_i2c_driver = {
    .probe = dw_i2c_plat_probe,
    .remove = dw_i2c_plat_remove,
    .driver        = {
        .name    = "i2c_designware",
        .of_match_table = of_match_ptr(dw_i2c_of_match),
        .acpi_match_table = ACPI_PTR(dw_i2c_acpi_match),
        .pm    = DW_I2C_DEV_PMOPS,
    },
};

static int __init dw_i2c_init_driver(void)
{
    return platform_driver_register(&dw_i2c_driver);
}
subsys_initcall(dw_i2c_init_driver);
static void __exit dw_i2c_exit_driver(void)
{
    platform_driver_unregister(&dw_i2c_driver);
}
module_exit(dw_i2c_exit_driver);
还是一贯的写法,这里注意的是和module_exit 对应的不一定是module_init ,这里就是和subsys_initcall。
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:i2c_designware");

针对ACPI bus的话,hotplut可以通过
static const struct acpi_device_id dw_i2c_acpi_match[] = {
    { "INT33C2", 0 },
    { "INT33C3", 0 },
    { "INT3432", 0 },
    { "INT3433", 0 },
    { "80860F41", 0 },
    { "808622C1", 0 },
    { "AMD0010", ACCESS_INTR_MASK },
    { "AMDI0010", ACCESS_INTR_MASK },
    { "AMDI0510", 0 },
    { "APMC0D0F", 0 },
    { }
};
MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
来在module_alias中产生相关的信息 ,但是如果匹配的id不在acpi_device_id中的话,还是需要通过下面的code来
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:i2c_designware");
在module_alias中产生相关的信息 。也就是一般不同特别显示调用MODULE_ALIAS,从这里也可以知道同一个ko在module_alias 中的对应的alias不止一个.
我这里是通过bios传递APMC0D0F。因此匹配,调用dw_i2c_plat_probe
static int dw_i2c_plat_probe(struct platform_device *pdev)
{
//通过dev_get_platdata 拿到bios传递的platform_data
    struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev);
    struct dw_i2c_dev *dev;
    struct i2c_adapter *adap;
    struct resource *mem;
    int irq, r;
    u32 acpi_speed, ht = 0;
//platform_get_irq 中通过platform_get_resource得到irq 资源。
    irq = platform_get_irq(pdev, 0);
    if (irq < 0)
        return irq;
//申请dw_i2c_dev 空间
    dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL);
    if (!dev)
        return -ENOMEM;
//得到bios传递过来的mem资源,并remap成虚拟地址
    mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    dev->base = devm_ioremap_resource(&pdev->dev, mem);
    if (IS_ERR(dev->base))
        return PTR_ERR(dev->base);

    dev->dev = &pdev->dev;
    dev->irq = irq;
//将struct dw_i2c_dev *dev; 保存为drv_data。
    platform_set_drvdata(pdev, dev);

    /* fast mode by default because of legacy reasons */
    dev->clk_freq = 400000;

    if (pdata) {
        dev->clk_freq = pdata->i2c_scl_freq;
    } else {
//通过dt得到参数
        device_property_read_u32(&pdev->dev, "i2c-sda-hold-time-ns",
                     &ht);
        device_property_read_u32(&pdev->dev, "i2c-sda-falling-time-ns",
                     &dev->sda_falling_time);
        device_property_read_u32(&pdev->dev, "i2c-scl-falling-time-ns",
                     &dev->scl_falling_time);
        device_property_read_u32(&pdev->dev, "clock-frequency",
                     &dev->clk_freq);
    }
//得到传输speed,这个speed 是在bios传递给kernel的ACPI 表中已经规定好的,这里只是找到而已.
    acpi_speed = i2c_acpi_find_bus_speed(&pdev->dev);
    if (acpi_speed)
        dev->clk_freq = acpi_speed;
//看是否同ACPI 传递参数的.
    if (has_acpi_companion(&pdev->dev))
        dw_i2c_acpi_configure(pdev);

    /*
     * Only standard mode at 100kHz, fast mode at 400kHz,
     * fast mode plus at 1MHz and high speed mode at 3.4MHz are supported.
     */
    if (dev->clk_freq != 100000 && dev->clk_freq != 400000
        && dev->clk_freq != 1000000 && dev->clk_freq != 3400000) {
        dev_err(&pdev->dev,
            "Only 100kHz, 400kHz, 1MHz and 3.4MHz supported");
        return -EINVAL;
    }
//没有定义CONFIG_I2C_DESIGNWARE_BAYTRAIL的话,为空函数.
    r = i2c_dw_eval_lock_support(dev);
    if (r)
        return r;

    dev->functionality =
        I2C_FUNC_I2C |
        I2C_FUNC_10BIT_ADDR |
        I2C_FUNC_SMBUS_BYTE |
        I2C_FUNC_SMBUS_BYTE_DATA |
        I2C_FUNC_SMBUS_WORD_DATA |
        I2C_FUNC_SMBUS_I2C_BLOCK;

    dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
              DW_IC_CON_RESTART_EN;
//支持三种speed :std/fast/high
    switch (dev->clk_freq) {
    case 100000:
        dev->master_cfg |= DW_IC_CON_SPEED_STD;
        break;
    case 3400000:
        dev->master_cfg |= DW_IC_CON_SPEED_HIGH;
        break;
    default:
        dev->master_cfg |= DW_IC_CON_SPEED_FAST;
    }
//得到clk
    dev->clk = devm_clk_get(&pdev->dev, NULL);
    if (!i2c_dw_plat_prepare_clk(dev, true)) {
        dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;

        if (!dev->sda_hold_time && ht)
            dev->sda_hold_time = div_u64(
                (u64)dev->get_clk_rate_khz(dev) * ht + 500000,
                1000000);
    }
//配置发送fifo的深度
    if (!dev->tx_fifo_depth) {
        u32 param1 = i2c_dw_read_comp_param(dev);

        dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1;
        dev->rx_fifo_depth = ((param1 >> 8)  & 0xff) + 1;
        dev->adapter.nr = pdev->id;
    }

    adap = &dev->adapter;
    adap->owner = THIS_MODULE;
    adap->class = I2C_CLASS_DEPRECATED;
//通过ACPI_COMPANION(&pdev->dev)得到acpi的fwnode再赋值给adap->dev
    ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
    adap->dev.of_node = pdev->dev.of_node;
//power相关的设定
    if (dev->pm_runtime_disabled) {
        pm_runtime_forbid(&pdev->dev);
    } else {
        pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
        pm_runtime_use_autosuspend(&pdev->dev);
        pm_runtime_set_active(&pdev->dev);
        pm_runtime_enable(&pdev->dev);
    }
//继续调用i2c_dw_probe
    r = i2c_dw_probe(dev);
    if (r && !dev->pm_runtime_disabled)
        pm_runtime_disable(&pdev->dev);

    return r;
}
int i2c_dw_probe(struct dw_i2c_dev *dev)
{
    struct i2c_adapter *adap = &dev->adapter;
    int r;
//初始化完成量,完成量一般用于中断中,这里可以看出I2C  master的发送和接收肯定用的是中断
    init_completion(&dev->cmd_complete);
//硬件的初始化,主要是设定寄存器
    r = i2c_dw_init(dev);
    if (r)
        return r;
//将名字改为Synopsys DesignWare I2C adapter。
    snprintf(adap->name, sizeof(adap->name),
         "Synopsys DesignWare I2C adapter");
    adap->retries = 3;
    adap->algo = &i2c_dw_algo;
    adap->dev.parent = dev->dev;
    i2c_set_adapdata(adap, dev);

    i2c_dw_disable_int(dev);
//注册中断
    r = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr,
                 IRQF_SHARED | IRQF_COND_SUSPEND,
                 dev_name(dev->dev), dev);
    if (r) {
        dev_err(dev->dev, "failure requesting irq %i: %d\n",
            dev->irq, r);
        return r;
    }

    /*
     * Increment PM usage count during adapter registration in order to
     * avoid possible spurious runtime suspend when adapter device is
     * registered to the device core and immediate resume in case bus has
     * registered I2C slaves that do I2C transfers in their probe.
     */
    pm_runtime_get_noresume(dev->dev);
//添加这个adaper对应的device
    r = i2c_add_numbered_adapter(adap);
    if (r)
        dev_err(dev->dev, "failure adding adapter: %d\n", r);
    pm_runtime_put_noidle(dev->dev);

    return r;
}

int i2c_add_numbered_adapter(struct i2c_adapter *adap)
{
//一般都是动态分配bus id
    if (adap->nr == -1) /* -1 means dynamically assign bus id */
        return i2c_add_adapter(adap);

    return __i2c_add_numbered_adapter(adap);
}

int i2c_add_adapter(struct i2c_adapter *adapter)
{
    struct device *dev = &adapter->dev;
    int id;
//通过dt传递参数
    if (dev->of_node) {
        id = of_alias_get_id(dev->of_node, "i2c");
        if (id >= 0) {
            adapter->nr = id;
            return __i2c_add_numbered_adapter(adapter);
        }
    }
//下面通过acpi 传递参数,这里的id 从__i2c_first_dynamic_bus_num 开始,一般为0.
    mutex_lock(&core_lock);
    id = idr_alloc(&i2c_adapter_idr, adapter,
               __i2c_first_dynamic_bus_num, 0, GFP_KERNEL);
    mutex_unlock(&core_lock);
    if (WARN(id < 0, "couldn't get idr"))
        return id;
//所以这里如果是地一个adapter的话,这里id就是0
    adapter->nr = id;
//继续调用i2c_register_adapter
    return i2c_register_adapter(adapter);
}

static int i2c_register_adapter(struct i2c_adapter *adap)
{
    int res = -EINVAL;

    /* Can't register until after driver model init */
    if (WARN_ON(!is_registered)) {
        res = -EAGAIN;
        goto out_list;
    }

    /* Sanity checks */
    if (WARN(!adap->name[0], "i2c adapter has no name"))
        goto out_list;

    if (!adap->algo) {
        pr_err("adapter '%s': no algo supplied!\n", adap->name);
        goto out_list;
    }

    if (!adap->lock_ops)
        adap->lock_ops = &i2c_adapter_lock_ops;

    rt_mutex_init(&adap->bus_lock);
    rt_mutex_init(&adap->mux_lock);
    mutex_init(&adap->userspace_clients_lock);
    INIT_LIST_HEAD(&adap->userspace_clients);

    /* Set default timeout to 1 second if not already set */
    if (adap->timeout == 0)
        adap->timeout = HZ;
//这里如果是第一个adapter的name就是i2c-0
    dev_set_name(&adap->dev, "i2c-%d", adap->nr);
//这里adapter的bus type是i2c_bus_type
    adap->dev.bus = &i2c_bus_type;
    adap->dev.type = &i2c_adapter_type;
//添加这个device
    res = device_register(&adap->dev);
    if (res) {
        pr_err("adapter '%s': can't register device (%d)\n", adap->name, res);
        goto out_list;
    }

    dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);

}