From 027b6934aaa3a7eff90598980aca992b5f1f1e2e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 14 Mar 2016 16:29:02 +0100 Subject: PM / devfreq: Spelling s/frequnecy/frequency/ Signed-off-by: Geert Uytterhoeven Reviewed-by: Chanwoo Choi Signed-off-by: Rafael J. Wysocki --- drivers/devfreq/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index 64281bb2f650..4de78c552251 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -61,7 +61,7 @@ config DEVFREQ_GOV_USERSPACE Sets the frequency at the user specified one. This governor returns the user configured frequency if there has been an input to /sys/devices/.../power/devfreq_set_freq. - Otherwise, the governor does not change the frequnecy + Otherwise, the governor does not change the frequency given at the initialization. comment "DEVFREQ Drivers" -- cgit From 02113ba93ea414b7113d64e42b87dc0720e3e578 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 15 Mar 2016 11:33:40 +0000 Subject: PM / clk: Add support for obtaining clocks from device-tree The PM clocks framework requires clients to pass either a con-id or a valid clk pointer in order to add a clock to a device. Add a new function of_pm_clk_add_clks() to allows device clocks to be retrieved from device-tree and populated for a given device. Note that it is not necessary to make the compilation of this new function dependent upon CONFIG_OF because there are stubs functions for the device-tree APIs used. In order to handle errors encountered when adding clocks from device-tree, add a function pm_clk_remove_clk() to remove any clocks (using a pointer to the clk structure) that have been added successfully before the error occurred. Signed-off-by: Jon Hunter Acked-by: Geert Uytterhoeven Signed-off-by: Rafael J. Wysocki --- drivers/base/power/clock_ops.c | 89 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) (limited to 'drivers') diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index 272a52ebafc0..0e64a1b5e62a 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c @@ -137,6 +137,62 @@ int pm_clk_add_clk(struct device *dev, struct clk *clk) return __pm_clk_add(dev, NULL, clk); } + +/** + * of_pm_clk_add_clks - Start using device clock(s) for power management. + * @dev: Device whose clock(s) is going to be used for power management. + * + * Add a series of clocks described in the 'clocks' device-tree node for + * a device to the list of clocks used for the power management of @dev. + * On success, returns the number of clocks added. Returns a negative + * error code if there are no clocks in the device node for the device + * or if adding a clock fails. + */ +int of_pm_clk_add_clks(struct device *dev) +{ + struct clk **clks; + unsigned int i, count; + int ret; + + if (!dev || !dev->of_node) + return -EINVAL; + + count = of_count_phandle_with_args(dev->of_node, "clocks", + "#clock-cells"); + if (count == 0) + return -ENODEV; + + clks = kcalloc(count, sizeof(*clks), GFP_KERNEL); + if (!clks) + return -ENOMEM; + + for (i = 0; i < count; i++) { + clks[i] = of_clk_get(dev->of_node, i); + if (IS_ERR(clks[i])) { + ret = PTR_ERR(clks[i]); + goto error; + } + + ret = pm_clk_add_clk(dev, clks[i]); + if (ret) { + clk_put(clks[i]); + goto error; + } + } + + kfree(clks); + + return i; + +error: + while (i--) + pm_clk_remove_clk(dev, clks[i]); + + kfree(clks); + + return ret; +} + /** * __pm_clk_remove - Destroy PM clock entry. * @ce: PM clock entry to destroy. @@ -197,6 +253,39 @@ void pm_clk_remove(struct device *dev, const char *con_id) __pm_clk_remove(ce); } +/** + * pm_clk_remove_clk - Stop using a device clock for power management. + * @dev: Device whose clock should not be used for PM any more. + * @clk: Clock pointer + * + * Remove the clock pointed to by @clk from the list of clocks used for + * the power management of @dev. + */ +void pm_clk_remove_clk(struct device *dev, struct clk *clk) +{ + struct pm_subsys_data *psd = dev_to_psd(dev); + struct pm_clock_entry *ce; + + if (!psd || !clk) + return; + + spin_lock_irq(&psd->lock); + + list_for_each_entry(ce, &psd->clock_list, node) { + if (clk == ce->clk) + goto remove; + } + + spin_unlock_irq(&psd->lock); + return; + + remove: + list_del(&ce->node); + spin_unlock_irq(&psd->lock); + + __pm_clk_remove(ce); +} + /** * pm_clk_init - Initialize a device's list of power management clocks. * @dev: Device to initialize the list of PM clocks for. -- cgit From fbda4b38fa3995aa0777fe9cbbdcb223c6292083 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 23 Mar 2016 00:11:20 +0100 Subject: ACPI / PM: Runtime resume devices when waking from hibernate Commit 58a1fbbb2ee8 ("PM / PCI / ACPI: Kick devices that might have been reset by firmware") added a runtime resume for devices that were runtime suspended when the system entered suspend-to-RAM. Briefly, the motivation was to ensure that devices did not remain in a reset-power-on state after resume, potentially preventing deep SoC-wide low-power states from being entered on idle. Currently we're not doing the same when leaving suspend-to-disk and this asymmetry is a problem if drivers rely on the automatic resume triggered by pm_complete_with_resume_check(). Fix it. Fixes: 58a1fbbb2ee8 (PM / PCI / ACPI: Kick devices that might have been reset by firmware) Signed-off-by: Lukas Wunner Cc: 4.4+ # 4.4+ Signed-off-by: Rafael J. Wysocki --- drivers/acpi/sleep.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 9cb975200cac..f054cadf30d8 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -714,6 +714,7 @@ static int acpi_hibernation_enter(void) static void acpi_hibernation_leave(void) { + pm_set_resume_via_firmware(); /* * If ACPI is not enabled by the BIOS and the boot kernel, we need to * enable it here. -- cgit From f447671b9e4fa4b0c9faf39455269d62d94218ae Mon Sep 17 00:00:00 2001 From: David Wu Date: Wed, 16 Mar 2016 02:45:26 +0800 Subject: PM / AVS: rockchip-io: add io selectors and supplies for rk3399 This adds the necessary data for handling io voltage domains on the rk3399. As interesting tidbit, the rk3399 contains two separate iodomain areas. One in the regular General Register Files (GRF) and one in PMUGRF in the pmu power domain. Signed-off-by: David Wu Reviewed-by: Heiko Stuebner Acked-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- drivers/power/avs/rockchip-io-domain.c | 58 ++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) mode change 100644 => 100755 drivers/power/avs/rockchip-io-domain.c (limited to 'drivers') diff --git a/drivers/power/avs/rockchip-io-domain.c b/drivers/power/avs/rockchip-io-domain.c old mode 100644 new mode 100755 index 80994566a1c8..8986382718dd --- a/drivers/power/avs/rockchip-io-domain.c +++ b/drivers/power/avs/rockchip-io-domain.c @@ -47,6 +47,10 @@ #define RK3368_SOC_CON15_FLASH0 BIT(14) #define RK3368_SOC_FLASH_SUPPLY_NUM 2 +#define RK3399_PMUGRF_CON0 0x180 +#define RK3399_PMUGRF_CON0_VSEL BIT(8) +#define RK3399_PMUGRF_VSEL_SUPPLY_NUM 9 + struct rockchip_iodomain; /** @@ -181,6 +185,25 @@ static void rk3368_iodomain_init(struct rockchip_iodomain *iod) dev_warn(iod->dev, "couldn't update flash0 ctrl\n"); } +static void rk3399_pmu_iodomain_init(struct rockchip_iodomain *iod) +{ + int ret; + u32 val; + + /* if no pmu io supply we should leave things alone */ + if (!iod->supplies[RK3399_PMUGRF_VSEL_SUPPLY_NUM].reg) + return; + + /* + * set pmu io iodomain to also use this framework + * instead of a special gpio. + */ + val = RK3399_PMUGRF_CON0_VSEL | (RK3399_PMUGRF_CON0_VSEL << 16); + ret = regmap_write(iod->grf, RK3399_PMUGRF_CON0, val); + if (ret < 0) + dev_warn(iod->dev, "couldn't update pmu io iodomain ctrl\n"); +} + /* * On the rk3188 the io-domains are handled by a shared register with the * lower 8 bits being still being continuing drive-strength settings. @@ -252,6 +275,33 @@ static const struct rockchip_iodomain_soc_data soc_data_rk3368_pmu = { }, }; +static const struct rockchip_iodomain_soc_data soc_data_rk3399 = { + .grf_offset = 0xe640, + .supply_names = { + "bt656", /* APIO2_VDD */ + "audio", /* APIO5_VDD */ + "sdmmc", /* SDMMC0_VDD */ + "gpio1830", /* APIO4_VDD */ + }, +}; + +static const struct rockchip_iodomain_soc_data soc_data_rk3399_pmu = { + .grf_offset = 0x180, + .supply_names = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "pmu1830", /* PMUIO2_VDD */ + }, + .init = rk3399_pmu_iodomain_init, +}; + static const struct of_device_id rockchip_iodomain_match[] = { { .compatible = "rockchip,rk3188-io-voltage-domain", @@ -269,6 +319,14 @@ static const struct of_device_id rockchip_iodomain_match[] = { .compatible = "rockchip,rk3368-pmu-io-voltage-domain", .data = (void *)&soc_data_rk3368_pmu }, + { + .compatible = "rockchip,rk3399-io-voltage-domain", + .data = (void *)&soc_data_rk3399 + }, + { + .compatible = "rockchip,rk3399-pmu-io-voltage-domain", + .data = (void *)&soc_data_rk3399_pmu + }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, rockchip_iodomain_match); -- cgit