diff options
| author | Rafael J. Wysocki <rjw@sisk.pl> | 2012-02-01 22:18:43 +0100 | 
|---|---|---|
| committer | Rafael J. Wysocki <rjw@sisk.pl> | 2012-02-01 22:18:43 +0100 | 
| commit | dcaad77a8074b6de58e745546bc543d5538404f2 (patch) | |
| tree | 5f988393b64f1a8053f2f5d0be7113e991d40886 | |
| parent | 0496c8ae366724a0a2136cec09a2e277e782c126 (diff) | |
| parent | 91cfbd4ee0875f8a826731983378670012ba6e01 (diff) | |
Merge branch 'v3.4-for-rafael' of git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung into pm-domains
* 'v3.4-for-rafael' of git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung:
  ARM: EXYNOS: Hook up power domains to generic power domain infrastructure
  PM / Domains: Add OF support
| -rw-r--r-- | Documentation/devicetree/bindings/arm/exynos/power_domain.txt | 21 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/Kconfig | 10 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/Makefile | 2 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/dev-pd.c | 139 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/mach-nuri.c | 11 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/mach-origen.c | 14 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/mach-smdkv310.c | 12 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/mach-universal_c210.c | 17 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/pm_domains.c | 195 | ||||
| -rw-r--r-- | drivers/base/power/domain.c | 32 | ||||
| -rw-r--r-- | include/linux/pm_domain.h | 12 | 
11 files changed, 262 insertions, 203 deletions
diff --git a/Documentation/devicetree/bindings/arm/exynos/power_domain.txt b/Documentation/devicetree/bindings/arm/exynos/power_domain.txt new file mode 100644 index 000000000000..6528e215c5fe --- /dev/null +++ b/Documentation/devicetree/bindings/arm/exynos/power_domain.txt @@ -0,0 +1,21 @@ +* Samsung Exynos Power Domains + +Exynos processors include support for multiple power domains which are used +to gate power to one or more peripherals on the processor. + +Required Properties: +- compatiable: should be one of the following. +    * samsung,exynos4210-pd - for exynos4210 type power domain. +- reg: physical base address of the controller and length of memory mapped +    region. + +Optional Properties: +- samsung,exynos4210-pd-off: Specifies that the power domain is in turned-off +    state during boot and remains to be turned-off until explicitly turned-on. + +Example: + +	lcd0: power-domain-lcd0 { +		compatible = "samsung,exynos4210-pd"; +		reg = <0x10023C00 0x10>; +	}; diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 5d602f68a0e8..dfad6538b273 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -34,6 +34,7 @@ config CPU_EXYNOS4210  	select ARM_CPU_SUSPEND if PM  	select S5P_PM if PM  	select S5P_SLEEP if PM +	select PM_GENERIC_DOMAINS  	help  	  Enable EXYNOS4210 CPU support @@ -74,11 +75,6 @@ config EXYNOS4_SETUP_FIMD0  	help  	  Common setup code for FIMD0. -config EXYNOS4_DEV_PD -	bool -	help -	  Compile in platform device definitions for Power Domain -  config EXYNOS4_DEV_SYSMMU  	bool  	help @@ -195,7 +191,6 @@ config MACH_SMDKV310  	select EXYNOS4_DEV_AHCI  	select SAMSUNG_DEV_KEYPAD  	select EXYNOS4_DEV_DMA -	select EXYNOS4_DEV_PD  	select SAMSUNG_DEV_PWM  	select EXYNOS4_DEV_USB_OHCI  	select EXYNOS4_DEV_SYSMMU @@ -243,7 +238,6 @@ config MACH_UNIVERSAL_C210  	select S5P_DEV_ONENAND  	select S5P_DEV_TV  	select EXYNOS4_DEV_DMA -	select EXYNOS4_DEV_PD  	select EXYNOS4_SETUP_FIMD0  	select EXYNOS4_SETUP_I2C1  	select EXYNOS4_SETUP_I2C3 @@ -277,7 +271,6 @@ config MACH_NURI  	select S5P_DEV_USB_EHCI  	select S5P_SETUP_MIPIPHY  	select EXYNOS4_DEV_DMA -	select EXYNOS4_DEV_PD  	select EXYNOS4_SETUP_FIMC  	select EXYNOS4_SETUP_FIMD0  	select EXYNOS4_SETUP_I2C1 @@ -310,7 +303,6 @@ config MACH_ORIGEN  	select SAMSUNG_DEV_BACKLIGHT  	select SAMSUNG_DEV_PWM  	select EXYNOS4_DEV_DMA -	select EXYNOS4_DEV_PD  	select EXYNOS4_DEV_USB_OHCI  	select EXYNOS4_SETUP_FIMD0  	select EXYNOS4_SETUP_SDHCI diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index 5fc202cdfdb6..d9191f9a7af8 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_CPU_EXYNOS4210)	+= clock-exynos4210.o  obj-$(CONFIG_SOC_EXYNOS4212)	+= clock-exynos4212.o  obj-$(CONFIG_PM)		+= pm.o +obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o  obj-$(CONFIG_CPU_IDLE)		+= cpuidle.o  obj-$(CONFIG_ARCH_EXYNOS4)	+= pmu.o @@ -45,7 +46,6 @@ obj-$(CONFIG_MACH_EXYNOS4_DT)		+= mach-exynos4-dt.o  obj-$(CONFIG_ARCH_EXYNOS4)		+= dev-audio.o  obj-$(CONFIG_EXYNOS4_DEV_AHCI)		+= dev-ahci.o -obj-$(CONFIG_EXYNOS4_DEV_PD)		+= dev-pd.o  obj-$(CONFIG_EXYNOS4_DEV_SYSMMU)	+= dev-sysmmu.o  obj-$(CONFIG_EXYNOS4_DEV_DWMCI)		+= dev-dwmci.o  obj-$(CONFIG_EXYNOS4_DEV_DMA)		+= dma.o diff --git a/arch/arm/mach-exynos/dev-pd.c b/arch/arm/mach-exynos/dev-pd.c deleted file mode 100644 index 3273f25d6a75..000000000000 --- a/arch/arm/mach-exynos/dev-pd.c +++ /dev/null @@ -1,139 +0,0 @@ -/* linux/arch/arm/mach-exynos4/dev-pd.c - * - * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. - *		http://www.samsung.com - * - * EXYNOS4 - Power Domain support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#include <linux/io.h> -#include <linux/kernel.h> -#include <linux/platform_device.h> -#include <linux/delay.h> - -#include <mach/regs-pmu.h> - -#include <plat/pd.h> - -static int exynos4_pd_enable(struct device *dev) -{ -	struct samsung_pd_info *pdata =  dev->platform_data; -	u32 timeout; - -	__raw_writel(S5P_INT_LOCAL_PWR_EN, pdata->base); - -	/* Wait max 1ms */ -	timeout = 10; -	while ((__raw_readl(pdata->base + 0x4) & S5P_INT_LOCAL_PWR_EN) -		!= S5P_INT_LOCAL_PWR_EN) { -		if (timeout == 0) { -			printk(KERN_ERR "Power domain %s enable failed.\n", -				dev_name(dev)); -			return -ETIMEDOUT; -		} -		timeout--; -		udelay(100); -	} - -	return 0; -} - -static int exynos4_pd_disable(struct device *dev) -{ -	struct samsung_pd_info *pdata =  dev->platform_data; -	u32 timeout; - -	__raw_writel(0, pdata->base); - -	/* Wait max 1ms */ -	timeout = 10; -	while (__raw_readl(pdata->base + 0x4) & S5P_INT_LOCAL_PWR_EN) { -		if (timeout == 0) { -			printk(KERN_ERR "Power domain %s disable failed.\n", -				dev_name(dev)); -			return -ETIMEDOUT; -		} -		timeout--; -		udelay(100); -	} - -	return 0; -} - -struct platform_device exynos4_device_pd[] = { -	{ -		.name		= "samsung-pd", -		.id		= 0, -		.dev = { -			.platform_data = &(struct samsung_pd_info) { -				.enable		= exynos4_pd_enable, -				.disable	= exynos4_pd_disable, -				.base		= S5P_PMU_MFC_CONF, -			}, -		}, -	}, { -		.name		= "samsung-pd", -		.id		= 1, -		.dev = { -			.platform_data = &(struct samsung_pd_info) { -				.enable		= exynos4_pd_enable, -				.disable	= exynos4_pd_disable, -				.base		= S5P_PMU_G3D_CONF, -			}, -		}, -	}, { -		.name		= "samsung-pd", -		.id		= 2, -		.dev = { -			.platform_data = &(struct samsung_pd_info) { -				.enable		= exynos4_pd_enable, -				.disable	= exynos4_pd_disable, -				.base		= S5P_PMU_LCD0_CONF, -			}, -		}, -	}, { -		.name		= "samsung-pd", -		.id		= 3, -		.dev = { -			.platform_data = &(struct samsung_pd_info) { -				.enable		= exynos4_pd_enable, -				.disable	= exynos4_pd_disable, -				.base		= S5P_PMU_LCD1_CONF, -			}, -		}, -	}, { -		.name		= "samsung-pd", -		.id		= 4, -		.dev = { -			.platform_data = &(struct samsung_pd_info) { -				.enable		= exynos4_pd_enable, -				.disable	= exynos4_pd_disable, -				.base		= S5P_PMU_TV_CONF, -			}, -		}, -	}, { -		.name		= "samsung-pd", -		.id		= 5, -		.dev = { -			.platform_data = &(struct samsung_pd_info) { -				.enable		= exynos4_pd_enable, -				.disable	= exynos4_pd_disable, -				.base		= S5P_PMU_CAM_CONF, -			}, -		}, -	}, { -		.name		= "samsung-pd", -		.id		= 6, -		.dev = { -			.platform_data = &(struct samsung_pd_info) { -				.enable		= exynos4_pd_enable, -				.disable	= exynos4_pd_disable, -				.base		= S5P_PMU_GPS_CONF, -			}, -		}, -	}, -}; diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c index b895ec031105..df705db08b06 100644 --- a/arch/arm/mach-exynos/mach-nuri.c +++ b/arch/arm/mach-exynos/mach-nuri.c @@ -1263,9 +1263,6 @@ static struct platform_device *nuri_devices[] __initdata = {  	&s5p_device_mfc,  	&s5p_device_mfc_l,  	&s5p_device_mfc_r, -	&exynos4_device_pd[PD_MFC], -	&exynos4_device_pd[PD_LCD0], -	&exynos4_device_pd[PD_CAM],  	&s5p_device_fimc_md,  	/* NURI Devices */ @@ -1315,14 +1312,6 @@ static void __init nuri_machine_init(void)  	/* Last */  	platform_add_devices(nuri_devices, ARRAY_SIZE(nuri_devices)); -	s5p_device_mfc.dev.parent = &exynos4_device_pd[PD_MFC].dev; -	s5p_device_fimd0.dev.parent = &exynos4_device_pd[PD_LCD0].dev; - -	s5p_device_fimc0.dev.parent = &exynos4_device_pd[PD_CAM].dev; -	s5p_device_fimc1.dev.parent = &exynos4_device_pd[PD_CAM].dev; -	s5p_device_fimc2.dev.parent = &exynos4_device_pd[PD_CAM].dev; -	s5p_device_fimc3.dev.parent = &exynos4_device_pd[PD_CAM].dev; -	s5p_device_mipi_csis0.dev.parent = &exynos4_device_pd[PD_CAM].dev;  }  MACHINE_START(NURI, "NURI") diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c index 0679b8ad2d1e..fa5c4a59b0aa 100644 --- a/arch/arm/mach-exynos/mach-origen.c +++ b/arch/arm/mach-exynos/mach-origen.c @@ -621,13 +621,6 @@ static struct platform_device *origen_devices[] __initdata = {  	&s5p_device_mfc_r,  	&s5p_device_mixer,  	&exynos4_device_ohci, -	&exynos4_device_pd[PD_LCD0], -	&exynos4_device_pd[PD_TV], -	&exynos4_device_pd[PD_G3D], -	&exynos4_device_pd[PD_LCD1], -	&exynos4_device_pd[PD_CAM], -	&exynos4_device_pd[PD_GPS], -	&exynos4_device_pd[PD_MFC],  	&origen_device_gpiokeys,  	&origen_lcd_hv070wsa,  }; @@ -695,13 +688,6 @@ static void __init origen_machine_init(void)  	platform_add_devices(origen_devices, ARRAY_SIZE(origen_devices)); -	s5p_device_fimd0.dev.parent = &exynos4_device_pd[PD_LCD0].dev; - -	s5p_device_hdmi.dev.parent = &exynos4_device_pd[PD_TV].dev; -	s5p_device_mixer.dev.parent = &exynos4_device_pd[PD_TV].dev; - -	s5p_device_mfc.dev.parent = &exynos4_device_pd[PD_MFC].dev; -  	samsung_bl_set(&origen_bl_gpio_info, &origen_bl_data);  } diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c index b2c5557f50e4..5258b8563676 100644 --- a/arch/arm/mach-exynos/mach-smdkv310.c +++ b/arch/arm/mach-exynos/mach-smdkv310.c @@ -277,13 +277,6 @@ static struct platform_device *smdkv310_devices[] __initdata = {  	&s5p_device_mfc,  	&s5p_device_mfc_l,  	&s5p_device_mfc_r, -	&exynos4_device_pd[PD_MFC], -	&exynos4_device_pd[PD_G3D], -	&exynos4_device_pd[PD_LCD0], -	&exynos4_device_pd[PD_LCD1], -	&exynos4_device_pd[PD_CAM], -	&exynos4_device_pd[PD_TV], -	&exynos4_device_pd[PD_GPS],  	&exynos4_device_spdif,  	&exynos4_device_sysmmu,  	&samsung_asoc_dma, @@ -336,10 +329,6 @@ static void s5p_tv_setup(void)  	WARN_ON(gpio_request_one(EXYNOS4_GPX3(7), GPIOF_IN, "hpd-plug"));  	s3c_gpio_cfgpin(EXYNOS4_GPX3(7), S3C_GPIO_SFN(0x3));  	s3c_gpio_setpull(EXYNOS4_GPX3(7), S3C_GPIO_PULL_NONE); - -	/* setup dependencies between TV devices */ -	s5p_device_hdmi.dev.parent = &exynos4_device_pd[PD_TV].dev; -	s5p_device_mixer.dev.parent = &exynos4_device_pd[PD_TV].dev;  }  static void __init smdkv310_map_io(void) @@ -379,7 +368,6 @@ static void __init smdkv310_machine_init(void)  	clk_xusbxti.rate = 24000000;  	platform_add_devices(smdkv310_devices, ARRAY_SIZE(smdkv310_devices)); -	s5p_device_mfc.dev.parent = &exynos4_device_pd[PD_MFC].dev;  }  MACHINE_START(SMDKV310, "SMDKV310") diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c index 37ac93e8d6d9..026241737919 100644 --- a/arch/arm/mach-exynos/mach-universal_c210.c +++ b/arch/arm/mach-exynos/mach-universal_c210.c @@ -969,7 +969,6 @@ static struct platform_device *universal_devices[] __initdata = {  	&s3c_device_i2c5,  	&s5p_device_i2c_hdmiphy,  	&hdmi_fixed_voltage, -	&exynos4_device_pd[PD_TV],  	&s5p_device_hdmi,  	&s5p_device_sdo,  	&s5p_device_mixer, @@ -982,9 +981,6 @@ static struct platform_device *universal_devices[] __initdata = {  	&s5p_device_mfc,  	&s5p_device_mfc_l,  	&s5p_device_mfc_r, -	&exynos4_device_pd[PD_MFC], -	&exynos4_device_pd[PD_LCD0], -	&exynos4_device_pd[PD_CAM],  	&cam_i_core_fixed_reg_dev,  	&cam_s_if_fixed_reg_dev,  	&s5p_device_fimc_md, @@ -1003,10 +999,6 @@ void s5p_tv_setup(void)  	gpio_request_one(EXYNOS4_GPX3(7), GPIOF_IN, "hpd-plug");  	s3c_gpio_cfgpin(EXYNOS4_GPX3(7), S3C_GPIO_SFN(0x3));  	s3c_gpio_setpull(EXYNOS4_GPX3(7), S3C_GPIO_PULL_NONE); - -	/* setup dependencies between TV devices */ -	s5p_device_hdmi.dev.parent = &exynos4_device_pd[PD_TV].dev; -	s5p_device_mixer.dev.parent = &exynos4_device_pd[PD_TV].dev;  }  static void __init universal_reserve(void) @@ -1040,15 +1032,6 @@ static void __init universal_machine_init(void)  	/* Last */  	platform_add_devices(universal_devices, ARRAY_SIZE(universal_devices)); - -	s5p_device_mfc.dev.parent = &exynos4_device_pd[PD_MFC].dev; -	s5p_device_fimd0.dev.parent = &exynos4_device_pd[PD_LCD0].dev; - -	s5p_device_fimc0.dev.parent = &exynos4_device_pd[PD_CAM].dev; -	s5p_device_fimc1.dev.parent = &exynos4_device_pd[PD_CAM].dev; -	s5p_device_fimc2.dev.parent = &exynos4_device_pd[PD_CAM].dev; -	s5p_device_fimc3.dev.parent = &exynos4_device_pd[PD_CAM].dev; -	s5p_device_mipi_csis0.dev.parent = &exynos4_device_pd[PD_CAM].dev;  }  MACHINE_START(UNIVERSAL_C210, "UNIVERSAL_C210") diff --git a/arch/arm/mach-exynos/pm_domains.c b/arch/arm/mach-exynos/pm_domains.c new file mode 100644 index 000000000000..0b04af2b13cc --- /dev/null +++ b/arch/arm/mach-exynos/pm_domains.c @@ -0,0 +1,195 @@ +/* + * Exynos Generic power domain support. + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + *		http://www.samsung.com + * + * Implementation of Exynos specific power domain control which is used in + * conjunction with runtime-pm. Support for both device-tree and non-device-tree + * based power domain support is included. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/io.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/pm_domain.h> +#include <linux/delay.h> +#include <linux/of_address.h> + +#include <mach/regs-pmu.h> +#include <plat/devs.h> + +/* + * Exynos specific wrapper around the generic power domain + */ +struct exynos_pm_domain { +	void __iomem *base; +	char const *name; +	bool is_off; +	struct generic_pm_domain pd; +}; + +static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) +{ +	struct exynos_pm_domain *pd; +	void __iomem *base; +	u32 timeout, pwr; +	char *op; + +	pd = container_of(domain, struct exynos_pm_domain, pd); +	base = pd->base; + +	pwr = power_on ? S5P_INT_LOCAL_PWR_EN : 0; +	__raw_writel(pwr, base); + +	/* Wait max 1ms */ +	timeout = 10; + +	while ((__raw_readl(base + 0x4) & S5P_INT_LOCAL_PWR_EN)	!= pwr) { +		if (!timeout) { +			op = (power_on) ? "enable" : "disable"; +			pr_err("Power domain %s %s failed\n", domain->name, op); +			return -ETIMEDOUT; +		} +		timeout--; +		cpu_relax(); +		usleep_range(80, 100); +	} +	return 0; +} + +static int exynos_pd_power_on(struct generic_pm_domain *domain) +{ +	return exynos_pd_power(domain, true); +} + +static int exynos_pd_power_off(struct generic_pm_domain *domain) +{ +	return exynos_pd_power(domain, false); +} + +#define EXYNOS_GPD(PD, BASE, NAME)			\ +static struct exynos_pm_domain PD = {			\ +	.base = (void __iomem *)BASE,			\ +	.name = NAME,					\ +	.pd = {						\ +		.power_off = exynos_pd_power_off,	\ +		.power_on = exynos_pd_power_on,	\ +	},						\ +} + +#ifdef CONFIG_OF +static __init int exynos_pm_dt_parse_domains(void) +{ +	struct device_node *np; + +	for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") { +		struct exynos_pm_domain *pd; + +		pd = kzalloc(sizeof(*pd), GFP_KERNEL); +		if (!pd) { +			pr_err("%s: failed to allocate memory for domain\n", +					__func__); +			return -ENOMEM; +		} + +		if (of_get_property(np, "samsung,exynos4210-pd-off", NULL)) +			pd->is_off = true; +		pd->name = np->name; +		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; +		pm_genpd_init(&pd->pd, NULL, false); +	} +	return 0; +} +#else +static __init int exynos_pm_dt_parse_domains(void) +{ +	return 0; +} +#endif /* CONFIG_OF */ + +static __init void exynos_pm_add_dev_to_genpd(struct platform_device *pdev, +						struct exynos_pm_domain *pd) +{ +	if (pdev->dev.bus) { +		if (pm_genpd_add_device(&pd->pd, &pdev->dev)) +			pr_info("%s: error in adding %s device to %s power" +				"domain\n", __func__, dev_name(&pdev->dev), +				pd->name); +	} +} + +EXYNOS_GPD(exynos4_pd_mfc, S5P_PMU_MFC_CONF, "pd-mfc"); +EXYNOS_GPD(exynos4_pd_g3d, S5P_PMU_G3D_CONF, "pd-g3d"); +EXYNOS_GPD(exynos4_pd_lcd0, S5P_PMU_LCD0_CONF, "pd-lcd0"); +EXYNOS_GPD(exynos4_pd_lcd1, S5P_PMU_LCD1_CONF, "pd-lcd1"); +EXYNOS_GPD(exynos4_pd_tv, S5P_PMU_TV_CONF, "pd-tv"); +EXYNOS_GPD(exynos4_pd_cam, S5P_PMU_CAM_CONF, "pd-cam"); +EXYNOS_GPD(exynos4_pd_gps, S5P_PMU_GPS_CONF, "pd-gps"); + +static struct exynos_pm_domain *exynos4_pm_domains[] = { +	&exynos4_pd_mfc, +	&exynos4_pd_g3d, +	&exynos4_pd_lcd0, +	&exynos4_pd_lcd1, +	&exynos4_pd_tv, +	&exynos4_pd_cam, +	&exynos4_pd_gps, +}; + +static __init int exynos4_pm_init_power_domain(void) +{ +	int idx; + +	if (of_have_populated_dt()) +		return exynos_pm_dt_parse_domains(); + +	for (idx = 0; idx < ARRAY_SIZE(exynos4_pm_domains); idx++) +		pm_genpd_init(&exynos4_pm_domains[idx]->pd, NULL, +				exynos4_pm_domains[idx]->is_off); + +#ifdef CONFIG_S5P_DEV_FIMD0 +	exynos_pm_add_dev_to_genpd(&s5p_device_fimd0, &exynos4_pd_lcd0); +#endif +#ifdef CONFIG_S5P_DEV_TV +	exynos_pm_add_dev_to_genpd(&s5p_device_hdmi, &exynos4_pd_tv); +	exynos_pm_add_dev_to_genpd(&s5p_device_mixer, &exynos4_pd_tv); +#endif +#ifdef CONFIG_S5P_DEV_MFC +	exynos_pm_add_dev_to_genpd(&s5p_device_mfc, &exynos4_pd_mfc); +#endif +#ifdef CONFIG_S5P_DEV_FIMC0 +	exynos_pm_add_dev_to_genpd(&s5p_device_fimc0, &exynos4_pd_cam); +#endif +#ifdef CONFIG_S5P_DEV_FIMC1 +	exynos_pm_add_dev_to_genpd(&s5p_device_fimc1, &exynos4_pd_cam); +#endif +#ifdef CONFIG_S5P_DEV_FIMC2 +	exynos_pm_add_dev_to_genpd(&s5p_device_fimc2, &exynos4_pd_cam); +#endif +#ifdef CONFIG_S5P_DEV_FIMC3 +	exynos_pm_add_dev_to_genpd(&s5p_device_fimc3, &exynos4_pd_cam); +#endif +#ifdef CONFIG_S5P_DEV_CSIS0 +	exynos_pm_add_dev_to_genpd(&s5p_device_mipi_csis0, &exynos4_pd_cam); +#endif +#ifdef CONFIG_S5P_DEV_CSIS1 +	exynos_pm_add_dev_to_genpd(&s5p_device_mipi_csis1, &exynos4_pd_cam); +#endif +	return 0; +} +arch_initcall(exynos4_pm_init_power_domain); + +static __init int exynos_pm_late_initcall(void) +{ +	pm_genpd_poweroff_unused(); +	return 0; +} +late_initcall(exynos_pm_late_initcall); diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 12a03afe5305..d2c03239abcf 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1230,6 +1230,38 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,  }  /** + * __pm_genpd_of_add_device - Add a device to an I/O PM domain. + * @genpd_node: Device tree node pointer representing a PM domain to which the + *   the device is added to. + * @dev: Device to be added. + * @td: Set of PM QoS timing parameters to attach to the device. + */ +int __pm_genpd_of_add_device(struct device_node *genpd_node, struct device *dev, +			     struct gpd_timing_data *td) +{ +	struct generic_pm_domain *genpd = NULL, *gpd; + +	dev_dbg(dev, "%s()\n", __func__); + +	if (IS_ERR_OR_NULL(genpd_node) || IS_ERR_OR_NULL(dev)) +		return -EINVAL; + +	mutex_lock(&gpd_list_lock); +	list_for_each_entry(gpd, &gpd_list, gpd_list_node) { +		if (gpd->of_node == genpd_node) { +			genpd = gpd; +			break; +		} +	} +	mutex_unlock(&gpd_list_lock); + +	if (!genpd) +		return -EINVAL; + +	return __pm_genpd_add_device(genpd, dev, td); +} + +/**   * pm_genpd_remove_device - Remove a device from an I/O PM domain.   * @genpd: PM domain to remove the device from.   * @dev: Device to be removed. diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index a03a0ad998b8..e3ff87550eeb 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -11,6 +11,7 @@  #include <linux/device.h>  #include <linux/err.h> +#include <linux/of.h>  enum gpd_status {  	GPD_STATE_ACTIVE = 0,	/* PM domain is active */ @@ -70,6 +71,7 @@ struct generic_pm_domain {  	s64 break_even_ns;	/* Power break even for the entire domain. */  	s64 max_off_time_ns;	/* Maximum allowed "suspended" time. */  	ktime_t power_off_time; +	struct device_node *of_node; /* Node in device tree */  };  static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd) @@ -117,12 +119,22 @@ extern int __pm_genpd_add_device(struct generic_pm_domain *genpd,  				 struct device *dev,  				 struct gpd_timing_data *td); +extern int __pm_genpd_of_add_device(struct device_node *genpd_node, +				    struct device *dev, +				    struct gpd_timing_data *td); +  static inline int pm_genpd_add_device(struct generic_pm_domain *genpd,  				      struct device *dev)  {  	return __pm_genpd_add_device(genpd, dev, NULL);  } +static inline int pm_genpd_of_add_device(struct device_node *genpd_node, +					 struct device *dev) +{ +	return __pm_genpd_of_add_device(genpd_node, dev, NULL); +} +  extern int pm_genpd_remove_device(struct generic_pm_domain *genpd,  				  struct device *dev);  extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,  | 
