Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 49a09c9a authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge branch 'pm-domains'

* pm-domains: (32 commits)
  PM / Domains: Rename cpu_data to cpuidle_data
  PM / Domains: Move dev_pm_domain_attach|detach() to pm_domain.h
  PM / Domains: Remove legacy API for adding devices through DT
  PM / Domains: Add genpd attach/detach callbacks
  PM / Domains: add debugfs listing of struct generic_pm_domain-s
  ACPI / PM: Convert acpi_dev_pm_detach() into a static function
  ARM: exynos: Move to generic PM domain DT bindings
  amba: Add support for attach/detach of PM domains
  spi: core: Convert to dev_pm_domain_attach|detach()
  mmc: sdio: Convert to dev_pm_domain_attach|detach()
  i2c: core: Convert to dev_pm_domain_attach|detach()
  drivercore / platform: Convert to dev_pm_domain_attach|detach()
  PM / Domains: Add APIs to attach/detach a PM domain for a device
  PM / Domains: Add generic OF-based PM domain look-up
  ACPI / PM: Assign the ->detach() callback when attaching the PM domain
  PM / Domains: Add a detach callback to the struct dev_pm_domain
  PM / domains: Spelling s/domian/domain/
  PM / domains: Keep declaration of dev_power_governors together
  PM / domains: Remove default_stop_ok() API
  drivers: sh: Leave disabling of unused PM domains to genpd
  ...
parents 28c399e2 f39cb179
Loading
Loading
Loading
Loading
+6 −7
Original line number Diff line number Diff line
@@ -8,6 +8,8 @@ Required Properties:
    * samsung,exynos4210-pd - for exynos4210 type power domain.
- reg: physical base address of the controller and length of memory mapped
    region.
- #power-domain-cells: number of cells in power domain specifier;
    must be 0.

Optional Properties:
- clocks: List of clock handles. The parent clocks of the input clocks to the
@@ -29,6 +31,7 @@ Example:
	lcd0: power-domain-lcd0 {
		compatible = "samsung,exynos4210-pd";
		reg = <0x10023C00 0x10>;
		#power-domain-cells = <0>;
	};

	mfc_pd: power-domain@10044060 {
@@ -37,12 +40,8 @@ Example:
		clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MOUT_SW_ACLK333>,
			<&clock CLK_MOUT_USER_ACLK333>;
		clock-names = "oscclk", "pclk0", "clk0";
		#power-domain-cells = <0>;
	};

Example of the node using power domain:

	node {
		/* ... */
		samsung,power-domain = <&lcd0>;
		/* ... */
	};
See Documentation/devicetree/bindings/power/power_domain.txt for description
of consumer-side bindings.
+49 −0
Original line number Diff line number Diff line
* Generic PM domains

System on chip designs are often divided into multiple PM domains that can be
used for power gating of selected IP blocks for power saving by reduced leakage
current.

This device tree binding can be used to bind PM domain consumer devices with
their PM domains provided by PM domain providers. A PM domain provider can be
represented by any node in the device tree and can provide one or more PM
domains. A consumer node can refer to the provider by a phandle and a set of
phandle arguments (so called PM domain specifiers) of length specified by the
#power-domain-cells property in the PM domain provider node.

==PM domain providers==

Required properties:
 - #power-domain-cells : Number of cells in a PM domain specifier;
   Typically 0 for nodes representing a single PM domain and 1 for nodes
   providing multiple PM domains (e.g. power controllers), but can be any value
   as specified by device tree binding documentation of particular provider.

Example:

	power: power-controller@12340000 {
		compatible = "foo,power-controller";
		reg = <0x12340000 0x1000>;
		#power-domain-cells = <1>;
	};

The node above defines a power controller that is a PM domain provider and
expects one cell as its phandle argument.

==PM domain consumers==

Required properties:
 - power-domains : A phandle and PM domain specifier as defined by bindings of
                   the power controller specified by phandle.

Example:

	leaky-device@12350000 {
		compatible = "foo,i-leak-current";
		reg = <0x12350000 0x1000>;
		power-domains = <&power 0>;
	};

The node above defines a typical PM domain consumer device, which is located
inside a PM domain with index 0 of a power controller represented by a node
with the label "power".
+0 −1
Original line number Diff line number Diff line
@@ -193,7 +193,6 @@ static void __init exynos_init_late(void)
		/* to be supported later */
		return;

	pm_genpd_poweroff_unused();
	exynos_pm_init();
}

+1 −77
Original line number Diff line number Diff line
@@ -105,78 +105,6 @@ static int exynos_pd_power_off(struct generic_pm_domain *domain)
	return exynos_pd_power(domain, false);
}

static void exynos_add_device_to_domain(struct exynos_pm_domain *pd,
					 struct device *dev)
{
	int ret;

	dev_dbg(dev, "adding to power domain %s\n", pd->pd.name);

	while (1) {
		ret = pm_genpd_add_device(&pd->pd, dev);
		if (ret != -EAGAIN)
			break;
		cond_resched();
	}

	pm_genpd_dev_need_restore(dev, true);
}

static void exynos_remove_device_from_domain(struct device *dev)
{
	struct generic_pm_domain *genpd = dev_to_genpd(dev);
	int ret;

	dev_dbg(dev, "removing from power domain %s\n", genpd->name);

	while (1) {
		ret = pm_genpd_remove_device(genpd, dev);
		if (ret != -EAGAIN)
			break;
		cond_resched();
	}
}

static void exynos_read_domain_from_dt(struct device *dev)
{
	struct platform_device *pd_pdev;
	struct exynos_pm_domain *pd;
	struct device_node *node;

	node = of_parse_phandle(dev->of_node, "samsung,power-domain", 0);
	if (!node)
		return;
	pd_pdev = of_find_device_by_node(node);
	if (!pd_pdev)
		return;
	pd = platform_get_drvdata(pd_pdev);
	exynos_add_device_to_domain(pd, dev);
}

static int exynos_pm_notifier_call(struct notifier_block *nb,
				    unsigned long event, void *data)
{
	struct device *dev = data;

	switch (event) {
	case BUS_NOTIFY_BIND_DRIVER:
		if (dev->of_node)
			exynos_read_domain_from_dt(dev);

		break;

	case BUS_NOTIFY_UNBOUND_DRIVER:
		exynos_remove_device_from_domain(dev);

		break;
	}
	return NOTIFY_DONE;
}

static struct notifier_block platform_nb = {
	.notifier_call = exynos_pm_notifier_call,
};

static __init int exynos4_pm_init_power_domain(void)
{
	struct platform_device *pdev;
@@ -202,7 +130,6 @@ static __init int exynos4_pm_init_power_domain(void)
		pd->base = of_iomap(np, 0);
		pd->pd.power_off = exynos_pd_power_off;
		pd->pd.power_on = exynos_pd_power_on;
		pd->pd.of_node = np;

		pd->oscclk = clk_get(dev, "oscclk");
		if (IS_ERR(pd->oscclk))
@@ -228,15 +155,12 @@ static __init int exynos4_pm_init_power_domain(void)
			clk_put(pd->oscclk);

no_clk:
		platform_set_drvdata(pdev, pd);

		on = __raw_readl(pd->base + 0x4) & INT_LOCAL_PWR_EN;

		pm_genpd_init(&pd->pd, NULL, !on);
		of_genpd_add_provider_simple(np, &pd->pd);
	}

	bus_register_notifier(&platform_bus_type, &platform_nb);

	return 0;
}
arch_initcall(exynos4_pm_init_power_domain);
+0 −5
Original line number Diff line number Diff line
@@ -440,8 +440,3 @@ void s3c64xx_restart(enum reboot_mode mode, const char *cmd)
	/* if all else fails, or mode was for soft, jump to 0 */
	soft_restart(0);
}

void __init s3c64xx_init_late(void)
{
	s3c64xx_pm_late_initcall();
}
Loading