SCP午後ドメイン

在spci_pm_domian.c中会为支持power on 和 power off的设备提供scp 的接口。
其入口函数是scpi_pm_domain_probe
static int scpi_pm_domain_probe(struct platform_device *pdev)
{
	
#每个设备可能有多个power domain
	ret = of_property_read_u32(np, "num-domains", &num_domains);
	if (ret) {
		dev_err(dev, "number of domains not found\n");
		return -EINVAL;
	}

	

	for (i = 0; i < num_domains; i++, scpi_pd++) {
		domains[i] = &scpi_pd->genpd;

		scpi_pd->domain = i;
		scpi_pd->ops = scpi_ops;
		sprintf(scpi_pd->name, "%pOFn.%d", np, i);
		scpi_pd->genpd.name = scpi_pd->name;
		scpi_pd->genpd.power_off = scpi_pd_power_off;
		scpi_pd->genpd.power_on = scpi_pd_power_on;

		/*
		 * Treat all power domains as off at boot.
		 *
		 * The SCP firmware itself may have switched on some domains,
		 * but for reference counting purpose, keep it this way.
		 */
		给domain 赋值,这样这个设备的domain 就不为空
		pm_genpd_init(&scpi_pd->genpd, NULL, true);
	}

	scpi_pd_data->domains = domains;
	scpi_pd_data->num_domains = num_domains;
#将这个设备的power domian 添加到全局链表of_genpd_providers中
	of_genpd_add_provider_onecell(np, scpi_pd_data);

	return 0;
}

#of_genpd_add_provider_onecell -genpd_add_provider
static int genpd_add_provider(struct device_node *np, genpd_xlate_t xlate,
			      void *data)
{
	struct of_genpd_provider *cp;

	cp = kzalloc(sizeof(*cp), GFP_KERNEL);
	if (!cp)
		return -ENOMEM;

	cp->node = of_node_get(np);
	cp->data = data;
	cp->xlate = xlate;

	mutex_lock(&of_genpd_mutex);
	list_add(&cp->link, &of_genpd_providers);
	mutex_unlock(&of_genpd_mutex);
	pr_debug("Added domain provider from %pOF\n", np);

	return 0;
}

这样当设备注册自己时
int __platform_driver_register(struct platform_driver *drv,
				struct module *owner)
{
	drv->driver.owner = owner;
	drv->driver.bus = &platform_bus_type;
	drv->driver.probe = platform_drv_probe;
	drv->driver.remove = platform_drv_remove;
	drv->driver.shutdown = platform_drv_shutdown;

	return driver_register(&drv->driver);
}
会调用platform_drv_probe->dev_pm_domain_attach->genpd_dev_pm_attach->__genpd_dev_pm_attach
int dev_pm_domain_attach(struct device *dev, bool power_on)
{
	int ret;
#以apci为例的话,一般在acpi)dev_pmattach调用dev_pm_domain-set来设置pm_domain为acpi_general_pm_domain。这里的意思如果已经设置过,就不用重复设置了
	if (dev->pm_domain)
		return 0;

	ret = acpi_dev_pm_attach(dev, power_on);
	if (!ret)
		ret = genpd_dev_pm_attach(dev);

	return ret < 0 ? ret : 0;
}
static int __genpd_dev_pm_attach(struct device *dev, struct device *base_dev,
				 unsigned int index, bool power_on)
{
	struct of_phandle_args pd_args;
	struct generic_pm_domain *pd;
	int ret;

	ret = of_parse_phandle_with_args(dev->of_node, "power-domains",
				"#power-domain-cells", index, &pd_args);
	if (ret < 0)
		return ret;
#从全局链表中找到of_genpd_providers 找到pm domain
	mutex_lock(&gpd_list_lock);
	pd = genpd_get_from_provider(&pd_args);
	of_node_put(pd_args.np);
	if (IS_ERR(pd)) {
		mutex_unlock(&gpd_list_lock);
		dev_dbg(dev, "%s() failed to find PM domain: %ld\n",
			__func__, PTR_ERR(pd));
		return driver_deferred_probe_check_state(base_dev);
	}

	dev_dbg(dev, "adding to PM domain %s\n", pd->name);
#调用attach_dev
	ret = genpd_add_device(pd, dev, base_dev);
	mutex_unlock(&gpd_list_lock);

#power on这个设备
	if (power_on) {
		genpd_lock(pd);
		ret = genpd_power_on(pd, 0);
		genpd_unlock(pd);
	}

	if (ret)
		genpd_remove_device(pd, dev);

	return ret ? -EPROBE_DEFER : 1;
}

 

リリース1442元の記事 ウォン称賛65 ビュー136万+

おすすめ

転載: blog.csdn.net/tiantao2012/article/details/105278683