根据设备树节点创建平台设备

 文件路径:kernel\arch\arm\mach-tcc803x\board-tcc803x.c 

struct of_dev_auxdata {
	char *compatible;
	resource_size_t phys_addr;
	char *name;
	void *platform_data;
};
#define OF_DEV_AUXDATA(_compat,_phys,_name,_pdata) \
	{ .compatible = _compat, .phys_addr = _phys, .name = _name, \
	  .platform_data = _pdata }
static struct of_dev_auxdata tcc803x_auxdata_lookup[] __initdata = {
	OF_DEV_AUXDATA("telechips,vioc-fb", TCC803X_PA_VIOC, "tccfb", NULL),
	OF_DEV_AUXDATA("telechips,nand-v8", TCC803X_PA_NFC,"tcc_nand", NULL),
	OF_DEV_AUXDATA("telechips,tcc-ehci", TCC_PA_EHCI0, "tcc-ehci.0", NULL),
	OF_DEV_AUXDATA("telechips,tcc-ehci", TCC_PA_EHCI1, "tcc-ehci.1", NULL),
	OF_DEV_AUXDATA("telechips,tcc-ohci", TCC_PA_OHCI0, "tcc-ohci.0", NULL),
	OF_DEV_AUXDATA("telechips,tcc-ohci", TCC_PA_OHCI1, "tcc-ohci.1", NULL),
	OF_DEV_AUXDATA("telechips,dwc_otg", TCC_PA_DWC_OTG,"dwc_otg", NULL),
	OF_DEV_AUXDATA("telechips,i2c", TCC803X_PA_I2C0, "i2c.0", NULL),
	OF_DEV_AUXDATA("telechips,i2c", TCC803X_PA_I2C1, "i2c.1", NULL),
	OF_DEV_AUXDATA("telechips,i2c", TCC803X_PA_I2C2, "i2c.2", NULL),
	OF_DEV_AUXDATA("telechips,i2c", TCC803X_PA_I2C3, "i2c.3", NULL),
	OF_DEV_AUXDATA("telechips,tcc-sdhc", TCC803X_PA_SDHC0, "tcc-sdhc.0", NULL),
	OF_DEV_AUXDATA("telechips,tcc-sdhc", TCC803X_PA_SDHC1, "tcc-sdhc.1", NULL),
	OF_DEV_AUXDATA("telechips,tcc-sdhc", TCC803X_PA_SDHC2, "tcc-sdhc.2", NULL),
	OF_DEV_AUXDATA("telechips,wmixer_drv", 0, "wmixer0", NULL),
	OF_DEV_AUXDATA("telechips,wmixer_drv", 1, "wmixer1", NULL),
	OF_DEV_AUXDATA("telechips,scaler_drv", 1, "scaler1", NULL),
	OF_DEV_AUXDATA("telechips,scaler_drv", 3, "scaler3", NULL),
	#ifdef CONFIG_TCC_ATTACH
	OF_DEV_AUXDATA("telechips,attach_drv", 0, "attach0", NULL),
	OF_DEV_AUXDATA("telechips,attach_drv", 1, "attach1", NULL),
	#endif
	OF_DEV_AUXDATA("telechips,tcc_wdma", 0, "wdma", NULL),
	OF_DEV_AUXDATA("telechips,tcc_overlay", 0, "overlay", NULL),
	{},
};
const struct of_device_id of_default_bus_match_table[] = {
	{ .compatible = "simple-bus", },
	{ .compatible = "simple-mfd", },
	{ .compatible = "isa", },
#ifdef CONFIG_ARM_AMBA
	{ .compatible = "arm,amba-bus", },
#endif /* CONFIG_ARM_AMBA */
	{} /* Empty terminated list */
};
static void __init tcc803x_dt_init(void)
{
	of_platform_populate(NULL, of_default_bus_match_table,
			     tcc803x_auxdata_lookup, NULL);
}

of_platform_populate函数从设备树的根节点开始,为每个子节点是平台设备的节点创建平台设备。populate:填充,即根据设备树的设备节点参数填充平台设备。

int of_platform_populate(struct device_node *root,
			const struct of_device_id *matches,
			const struct of_dev_auxdata *lookup,
			struct device *parent)
{
	struct device_node *child;
	int rc = 0;

    //root为null,所以root= of_find_node_by_path("/")
	root = root ? of_node_get(root) : of_find_node_by_path("/");
    //遍历设备树的"/"节点的所有子节点
	for_each_child_of_node(root, child) {
		rc = of_platform_bus_create(child, matches, lookup, parent, true);
		if (rc) {
			of_node_put(child);
			break;
		}
	}
	of_node_set_flag(root, OF_POPULATED_BUS);

	return rc;
}

of_platform_bus_create函数:创建根节点下的某个子节点以及该子节点下的所有子节点对应的平台设备。

static int of_platform_bus_create(struct device_node *bus,
				  const struct of_device_id *matches,
				  const struct of_dev_auxdata *lookup,
				  struct device *parent, bool strict)
{
	const struct of_dev_auxdata *auxdata;
	struct device_node *child;
	struct platform_device *dev;
	const char *bus_id = NULL;
	void *platform_data = NULL;
	int rc = 0;

	/* Make sure it has a compatible property */
	if (strict && (!of_get_property(bus, "compatible", NULL))) {
		return 0;
	}
    //确保该设备节点之前没有被填充过
	if (of_node_check_flag(bus, OF_POPULATED_BUS)) {
		return 0;
	}

    //查看lookup数组里有没有数组元素与该设备节点的compatile和内存空间首地址匹配,
    //如果有匹配,返回该数组元素
	auxdata = of_dev_lookup(lookup, bus);
	if (auxdata) {
		bus_id = auxdata->name;
        //如果设备节点是在lookup数组里,是带有平台数据的,
        //否则没有平台数据
		platform_data = auxdata->platform_data;
	}

	dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);

    //递归创建bus节点的子节点对应的平台设备
	for_each_child_of_node(bus, child) {
		rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict);
		if (rc) {
			of_node_put(child);
			break;
		}
	}

    //设置标志,表示该节点填充完
	of_node_set_flag(bus, OF_POPULATED_BUS);
	return rc;
}

of_dev_lookup函数: 

static const struct of_dev_auxdata *of_dev_lookup(const struct of_dev_auxdata *lookup,
				 struct device_node *np)
{
	const struct of_dev_auxdata *auxdata;
	struct resource res;
	int compatible = 0;

	if (!lookup)
		return NULL;

	auxdata = lookup;

    //查看lookup数组里有没有数组元素与该设备节点的compatile和内存空间首地址匹配,
    //如果有匹配,返回该数组元素
	for (; auxdata->compatible; auxdata++) {
        
        //of_device_is_compatible函数返回0,表示没有匹配上,
        //返回正整数,表示匹配上。
		if (!of_device_is_compatible(np, auxdata->compatible))
			continue;
		compatible++;
		if (!of_address_to_resource(np, 0, &res))
			if (res.start != auxdata->phys_addr)
				continue;
		return auxdata;
	}

	if (!compatible)
		return NULL;

	/* Try compatible match if no phys_addr and name are specified */
	auxdata = lookup;
	for (; auxdata->compatible; auxdata++) {
		if (!of_device_is_compatible(np, auxdata->compatible))
			continue;
		if (!auxdata->phys_addr && !auxdata->name) {
			pr_debug("%pOF: compatible match\n", np);
			return auxdata;
		}
	}

	return NULL;
}

of_device_is_compatible函数:

int of_device_is_compatible(const struct device_node *device,
		const char *compat)
{
	unsigned long flags;
	int res;

	raw_spin_lock_irqsave(&devtree_lock, flags);
	res = __of_device_is_compatible(device, compat, NULL, NULL);
	raw_spin_unlock_irqrestore(&devtree_lock, flags);
	return res;
}

__of_device_is_compatible函数:

static int __of_device_is_compatible(const struct device_node *device,
				     const char *compat, const char *type, const char *name)
{
	struct property *prop;
	const char *cp;
	int index = 0, score = 0;

    //compatible属性匹配优先级最高,所以对应的score分数最大,其次是type,再其次是name。
	if (compat && compat[0]) {
		prop = __of_find_property(device, "compatible", NULL);
        //获取"compatible"节点属性的字符串值,一般只有一个字符串
		for (cp = of_prop_next_string(prop, NULL); cp;
             cp = of_prop_next_string(prop, cp), index++) {
			if (of_compat_cmp(cp, compat, strlen(compat)) == 0) {
                //score:匹配度的相对分数,正整数,分数越高,越匹配
                //如果是0,表示没有匹配上
				score = INT_MAX/2 - (index << 2);
				break;
			}
		}
		if (!score)
			return 0;
	}

	//一般type设置为NULL,就是不进行type匹配
	if (type && type[0]) {
		if (!device->type || of_node_cmp(type, device->type))
			return 0;
		score += 2;
	}

	//一般name设置为NULL,就是不进行name匹配
	if (name && name[0]) {
		if (!device->name || of_node_cmp(name, device->name))
			return 0;
		score++;
	}

	return score;
}

of_platform_device_create_pdata函数:

static struct platform_device *of_platform_device_create_pdata(
					struct device_node *np,
					const char *bus_id,
					void *platform_data,
					struct device *parent)
{
	struct platform_device *dev;

    //设备节点的status属性有,且不是"okay"或者"ok"状态,那么返回,不会创建平台设备。
	if (!of_device_is_available(np) || of_node_test_and_set_flag(np, OF_POPULATED))
		return NULL;

    //平台设备对应的结构体的内存分配
	dev = of_device_alloc(np, bus_id, parent);
	
    //总线类型为平台总线类型
	dev->dev.bus = &platform_bus_type;
	dev->dev.platform_data = platform_data;

    //添加设备
	if (of_device_add(dev) != 0) {
	    ......
	}

	return dev;

}

of_device_is_available函数:

bool of_device_is_available(const struct device_node *device)
{
	unsigned long flags;
	bool res;

	raw_spin_lock_irqsave(&devtree_lock, flags);
	res = __of_device_is_available(device);
	raw_spin_unlock_irqrestore(&devtree_lock, flags);
	return res;

}

__of_device_is_available函数:

static bool __of_device_is_available(const struct device_node *device)
{
	const char *status;
	int statlen;

	if (!device)
		return false;

    //如果没有status属性,没问题
	status = __of_get_property(device, "status", &statlen);
	if (status == NULL)
		return true;

    //如果有status属性,且设置成"okay"或者"ok",没问题
	if (statlen > 0) {
		if (!strcmp(status, "okay") || !strcmp(status, "ok"))
			return true;
	}
    //否则有问题
	return false;
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值