Linux内核4.14版本——I2C子系统(4)_I2C示例(i2c-designware-platdrv.c和at24.c)

目录

1. DTS

2. I2C control实例化分析

3. adapter如何注册slave device

3.1 i2c_register_adapter

3.2 of_i2c_register_device

3.2.1 of_modalias_node

3.2.2 i2c_new_device

4. i2c consumer driver注册


源码:

drivers\i2c\busses\i2c-designware-platdrv.c
drivers\i2c\busses\i2c-designware-master.c
drivers\i2c\busses\i2c-designware-slave.c

drivers\misc\eeprom\at24.c

1. DTS

i2c2: i2c@f0d80000 {
    compatible = "snps,designware-i2c";
    status = "disabled";
    interrupt-parent = <&gic>;
    interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
    reg = <0x0 0xf0d80000 0x0 0x1000>;
    clock-frequency = <400000>;
    #address-cells = <1>;
    #size-cells = <0>;
};

&i2c2 {
    status = "okay";
    eeprom: eeprom@50 {
        compatible = "atmel,24c32";
        reg = <0x50>;
        pagesize = <32>;
    };
};

     可以看出,i2c下面挂了一个eeprom设备。

2. I2C control实例化分析

static const struct of_device_id dw_i2c_of_match[] = {
    { .compatible = "snps,designware-i2c", },
    {},
};

最终dw_i2c_plat_probe(drivers\i2c\busses\i2c-designware-platdrv.c)函数会调用。

static int dw_i2c_plat_probe(struct platform_device *pdev)
{
    ......
	ret = i2c_dw_probe_lock_support(dev);
	if (ret)
		goto exit_reset;

	if (i2c_detect_slave_mode(&pdev->dev))
		i2c_dw_configure_slave(dev);
	else
		i2c_dw_configure_master(dev);

	......
	
	if (dev->mode == DW_IC_SLAVE)
		ret = i2c_dw_probe_slave(dev);
	else
		ret = i2c_dw_probe(dev);

    ......
}

    根据该i2c控制器是主机还是从机,进行控制器配置并且调用响应的probe函数,这里我们分析主机模式,调用i2c_dw_probe函数。

static const struct i2c_algorithm i2c_dw_algo = {
	.master_xfer = i2c_dw_xfer,
	.functionality = i2c_dw_func,
};

int i2c_dw_probe(struct dw_i2c_dev *dev)
{
	struct i2c_adapter *adap = &dev->adapter;
	unsigned long irq_flags;
	int ret;
	.......
	ret = dev->init(dev);
	if (ret)
		return ret;

	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);

	if (dev->pm_disabled) {
		dev_pm_syscore_device(dev->dev, true);
		irq_flags = IRQF_NO_SUSPEND;
	} else {
		irq_flags = IRQF_SHARED | IRQF_COND_SUSPEND;
	}
	.....
	i2c_dw_disable_int(dev);
	ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, irq_flags,
			       dev_name(dev->dev), dev);
	......
	ret = i2c_add_numbered_adapter(adap);
}

   这个很简单,设置struct i2c_adapter结构体,主要是adap->algo = &i2c_dw_algo,注册中断,最终调用i2c_add_numbered_adapter注册adapter,这个前文已经写过。

3. adapter如何注册slave device

3.1 i2c_register_adapter

      i2c_add_numbered_adapter->__i2c_add_numbered_adapter->i2c_register_adapter,我们查看i2c_register_adapter函数。

static int i2c_register_adapter(struct i2c_adapter *adap)
{
    .......

	dev_set_name(&adap->dev, "i2c-%d", adap->nr);
	adap->dev.bus = &i2c_bus_type;
	adap->dev.type = &i2c_adapter_type;
	res = device_register(&adap->dev);
	.......
	i2c_init_recovery(adap);

	/* create pre-declared device nodes */
	of_i2c_register_devices(adap);
	i2c_acpi_install_space_handler(adap);
	i2c_acpi_register_devices(adap);
    ......
}

      i2c_register_adapter->of_i2c_register_devices->of_i2c_register_device,我们看of_i2c_register_device函数。

3.2 of_i2c_register_device

static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
						 struct device_node *node)
{
    ........

	if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
		dev_err(&adap->dev, "of_i2c: modalias failure on %pOF\n",
			node);
		return ERR_PTR(-EINVAL);
	}

    .......

	result = i2c_new_device(adap, &info);
    ......
}

     我们先看of_modalias_node函数。

3.2.1 of_modalias_node

int of_modalias_node(struct device_node *node, char *modalias, int len)
{
	const char *compatible, *p;
	int cplen;

	compatible = of_get_property(node, "compatible", &cplen);
	if (!compatible || strlen(compatible) > cplen)
		return -ENODEV;
	p = strchr(compatible, ',');
	strlcpy(modalias, p ? p + 1 : compatible, len);
	return 0;
}

    注意,找到i2c控制器的子节点的compatible字段,取后面的字段,根据前面的DTS介绍,最终把“at24”返回,赋值在info.type变量中。

3.2.2 i2c_new_device

/**
 * i2c_new_device - instantiate an i2c device
 * @adap: the adapter managing the device
 * @info: describes one I2C device; bus_num is ignored
 * Context: can sleep
*/
struct i2c_client *
i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
{
......

	strlcpy(client->name, info->type, sizeof(client->name));

	.......

	i2c_dev_set_name(adap, client);

	if (info->properties) {
		status = device_add_properties(&client->dev, info->properties);
		if (status) {
			dev_err(&adap->dev,
				"Failed to add properties to client %s: %d\n",
				client->name, status);
			goto out_err;
		}
	}

	status = device_register(&client->dev);
	......
}

4. i2c consumer driver注册

drivers\misc\eeprom\at24.c

static struct i2c_driver at24_driver = {
	.driver = {
		.name = "at24",
		.acpi_match_table = ACPI_PTR(at24_acpi_ids),
	},
	.probe = at24_probe,
	.remove = at24_remove,
	.id_table = at24_ids,
};

前面已经写过,at24 device已经注册了,这里是at24 driver,最终调用at24_probe。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值