From: Ulf Hansson Date: Tue, 4 Jul 2023 22:06:27 +0000 (+0200) Subject: soc: apple: Move power-domain driver to the genpd dir X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=869b9dd3339a719d41c10870f9aaec39953edd86;p=linux.git soc: apple: Move power-domain driver to the genpd dir To simplify with maintenance let's move the apple power-domain driver to the new genpd directory. Going forward, patches are intended to be managed through a separate git tree, according to MAINTAINERS. Cc: Hector Martin Cc: Sven Peter Cc: Alyssa Rosenzweig Cc: Signed-off-by: Ulf Hansson --- diff --git a/MAINTAINERS b/MAINTAINERS index ab583b8c5b97f..caa221fd0c11f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1904,6 +1904,7 @@ F: drivers/bluetooth/hci_bcm4377.c F: drivers/clk/clk-apple-nco.c F: drivers/cpufreq/apple-soc-cpufreq.c F: drivers/dma/apple-admac.c +F: drivers/genpd/apple/ F: drivers/i2c/busses/i2c-pasemi-core.c F: drivers/i2c/busses/i2c-pasemi-platform.c F: drivers/iommu/apple-dart.c diff --git a/drivers/genpd/Makefile b/drivers/genpd/Makefile index cdba3b9f0c753..91d4a3808981d 100644 --- a/drivers/genpd/Makefile +++ b/drivers/genpd/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only obj-y += actions/ obj-y += amlogic/ +obj-y += apple/ diff --git a/drivers/genpd/apple/Makefile b/drivers/genpd/apple/Makefile new file mode 100644 index 0000000000000..53665af630be2 --- /dev/null +++ b/drivers/genpd/apple/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_APPLE_PMGR_PWRSTATE) += pmgr-pwrstate.o diff --git a/drivers/genpd/apple/pmgr-pwrstate.c b/drivers/genpd/apple/pmgr-pwrstate.c new file mode 100644 index 0000000000000..d62a776c89a12 --- /dev/null +++ b/drivers/genpd/apple/pmgr-pwrstate.c @@ -0,0 +1,326 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Apple SoC PMGR device power state driver + * + * Copyright The Asahi Linux Contributors + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define APPLE_PMGR_RESET BIT(31) +#define APPLE_PMGR_AUTO_ENABLE BIT(28) +#define APPLE_PMGR_PS_AUTO GENMASK(27, 24) +#define APPLE_PMGR_PS_MIN GENMASK(19, 16) +#define APPLE_PMGR_PARENT_OFF BIT(11) +#define APPLE_PMGR_DEV_DISABLE BIT(10) +#define APPLE_PMGR_WAS_CLKGATED BIT(9) +#define APPLE_PMGR_WAS_PWRGATED BIT(8) +#define APPLE_PMGR_PS_ACTUAL GENMASK(7, 4) +#define APPLE_PMGR_PS_TARGET GENMASK(3, 0) + +#define APPLE_PMGR_FLAGS (APPLE_PMGR_WAS_CLKGATED | APPLE_PMGR_WAS_PWRGATED) + +#define APPLE_PMGR_PS_ACTIVE 0xf +#define APPLE_PMGR_PS_CLKGATE 0x4 +#define APPLE_PMGR_PS_PWRGATE 0x0 + +#define APPLE_PMGR_PS_SET_TIMEOUT 100 +#define APPLE_PMGR_RESET_TIME 1 + +struct apple_pmgr_ps { + struct device *dev; + struct generic_pm_domain genpd; + struct reset_controller_dev rcdev; + struct regmap *regmap; + u32 offset; + u32 min_state; +}; + +#define genpd_to_apple_pmgr_ps(_genpd) container_of(_genpd, struct apple_pmgr_ps, genpd) +#define rcdev_to_apple_pmgr_ps(_rcdev) container_of(_rcdev, struct apple_pmgr_ps, rcdev) + +static int apple_pmgr_ps_set(struct generic_pm_domain *genpd, u32 pstate, bool auto_enable) +{ + int ret; + struct apple_pmgr_ps *ps = genpd_to_apple_pmgr_ps(genpd); + u32 reg; + + ret = regmap_read(ps->regmap, ps->offset, ®); + if (ret < 0) + return ret; + + /* Resets are synchronous, and only work if the device is powered and clocked. */ + if (reg & APPLE_PMGR_RESET && pstate != APPLE_PMGR_PS_ACTIVE) + dev_err(ps->dev, "PS %s: powering off with RESET active\n", + genpd->name); + + reg &= ~(APPLE_PMGR_AUTO_ENABLE | APPLE_PMGR_FLAGS | APPLE_PMGR_PS_TARGET); + reg |= FIELD_PREP(APPLE_PMGR_PS_TARGET, pstate); + + dev_dbg(ps->dev, "PS %s: pwrstate = 0x%x: 0x%x\n", genpd->name, pstate, reg); + + regmap_write(ps->regmap, ps->offset, reg); + + ret = regmap_read_poll_timeout_atomic( + ps->regmap, ps->offset, reg, + (FIELD_GET(APPLE_PMGR_PS_ACTUAL, reg) == pstate), 1, + APPLE_PMGR_PS_SET_TIMEOUT); + if (ret < 0) + dev_err(ps->dev, "PS %s: Failed to reach power state 0x%x (now: 0x%x)\n", + genpd->name, pstate, reg); + + if (auto_enable) { + /* Not all devices implement this; this is a no-op where not implemented. */ + reg &= ~APPLE_PMGR_FLAGS; + reg |= APPLE_PMGR_AUTO_ENABLE; + regmap_write(ps->regmap, ps->offset, reg); + } + + return ret; +} + +static bool apple_pmgr_ps_is_active(struct apple_pmgr_ps *ps) +{ + u32 reg = 0; + + regmap_read(ps->regmap, ps->offset, ®); + /* + * We consider domains as active if they are actually on, or if they have auto-PM + * enabled and the intended target is on. + */ + return (FIELD_GET(APPLE_PMGR_PS_ACTUAL, reg) == APPLE_PMGR_PS_ACTIVE || + (FIELD_GET(APPLE_PMGR_PS_TARGET, reg) == APPLE_PMGR_PS_ACTIVE && + reg & APPLE_PMGR_AUTO_ENABLE)); +} + +static int apple_pmgr_ps_power_on(struct generic_pm_domain *genpd) +{ + return apple_pmgr_ps_set(genpd, APPLE_PMGR_PS_ACTIVE, true); +} + +static int apple_pmgr_ps_power_off(struct generic_pm_domain *genpd) +{ + return apple_pmgr_ps_set(genpd, APPLE_PMGR_PS_PWRGATE, false); +} + +static int apple_pmgr_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev); + unsigned long flags; + + spin_lock_irqsave(&ps->genpd.slock, flags); + + if (ps->genpd.status == GENPD_STATE_OFF) + dev_err(ps->dev, "PS 0x%x: asserting RESET while powered down\n", ps->offset); + + dev_dbg(ps->dev, "PS 0x%x: assert reset\n", ps->offset); + /* Quiesce device before asserting reset */ + regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_DEV_DISABLE, + APPLE_PMGR_DEV_DISABLE); + regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_RESET, + APPLE_PMGR_RESET); + + spin_unlock_irqrestore(&ps->genpd.slock, flags); + + return 0; +} + +static int apple_pmgr_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev); + unsigned long flags; + + spin_lock_irqsave(&ps->genpd.slock, flags); + + dev_dbg(ps->dev, "PS 0x%x: deassert reset\n", ps->offset); + regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_RESET, 0); + regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_DEV_DISABLE, 0); + + if (ps->genpd.status == GENPD_STATE_OFF) + dev_err(ps->dev, "PS 0x%x: RESET was deasserted while powered down\n", ps->offset); + + spin_unlock_irqrestore(&ps->genpd.slock, flags); + + return 0; +} + +static int apple_pmgr_reset_reset(struct reset_controller_dev *rcdev, unsigned long id) +{ + int ret; + + ret = apple_pmgr_reset_assert(rcdev, id); + if (ret) + return ret; + + usleep_range(APPLE_PMGR_RESET_TIME, 2 * APPLE_PMGR_RESET_TIME); + + return apple_pmgr_reset_deassert(rcdev, id); +} + +static int apple_pmgr_reset_status(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev); + u32 reg = 0; + + regmap_read(ps->regmap, ps->offset, ®); + + return !!(reg & APPLE_PMGR_RESET); +} + +const struct reset_control_ops apple_pmgr_reset_ops = { + .assert = apple_pmgr_reset_assert, + .deassert = apple_pmgr_reset_deassert, + .reset = apple_pmgr_reset_reset, + .status = apple_pmgr_reset_status, +}; + +static int apple_pmgr_reset_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *reset_spec) +{ + return 0; +} + +static int apple_pmgr_ps_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct apple_pmgr_ps *ps; + struct regmap *regmap; + struct of_phandle_iterator it; + int ret; + const char *name; + bool active; + + regmap = syscon_node_to_regmap(node->parent); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + ps = devm_kzalloc(dev, sizeof(*ps), GFP_KERNEL); + if (!ps) + return -ENOMEM; + + ps->dev = dev; + ps->regmap = regmap; + + ret = of_property_read_string(node, "label", &name); + if (ret < 0) { + dev_err(dev, "missing label property\n"); + return ret; + } + + ret = of_property_read_u32(node, "reg", &ps->offset); + if (ret < 0) { + dev_err(dev, "missing reg property\n"); + return ret; + } + + ps->genpd.flags |= GENPD_FLAG_IRQ_SAFE; + ps->genpd.name = name; + ps->genpd.power_on = apple_pmgr_ps_power_on; + ps->genpd.power_off = apple_pmgr_ps_power_off; + + ret = of_property_read_u32(node, "apple,min-state", &ps->min_state); + if (ret == 0 && ps->min_state <= APPLE_PMGR_PS_ACTIVE) + regmap_update_bits(regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_PS_MIN, + FIELD_PREP(APPLE_PMGR_PS_MIN, ps->min_state)); + + active = apple_pmgr_ps_is_active(ps); + if (of_property_read_bool(node, "apple,always-on")) { + ps->genpd.flags |= GENPD_FLAG_ALWAYS_ON; + if (!active) { + dev_warn(dev, "always-on domain %s is not on at boot\n", name); + /* Turn it on so pm_genpd_init does not fail */ + active = apple_pmgr_ps_power_on(&ps->genpd) == 0; + } + } + + /* Turn on auto-PM if the domain is already on */ + if (active) + regmap_update_bits(regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_AUTO_ENABLE, + APPLE_PMGR_AUTO_ENABLE); + + ret = pm_genpd_init(&ps->genpd, NULL, !active); + if (ret < 0) { + dev_err(dev, "pm_genpd_init failed\n"); + return ret; + } + + ret = of_genpd_add_provider_simple(node, &ps->genpd); + if (ret < 0) { + dev_err(dev, "of_genpd_add_provider_simple failed\n"); + return ret; + } + + of_for_each_phandle(&it, ret, node, "power-domains", "#power-domain-cells", -1) { + struct of_phandle_args parent, child; + + parent.np = it.node; + parent.args_count = of_phandle_iterator_args(&it, parent.args, MAX_PHANDLE_ARGS); + child.np = node; + child.args_count = 0; + ret = of_genpd_add_subdomain(&parent, &child); + + if (ret == -EPROBE_DEFER) { + of_node_put(parent.np); + goto err_remove; + } else if (ret < 0) { + dev_err(dev, "failed to add to parent domain: %d (%s -> %s)\n", + ret, it.node->name, node->name); + of_node_put(parent.np); + goto err_remove; + } + } + + /* + * Do not participate in regular PM; parent power domains are handled via the + * genpd hierarchy. + */ + pm_genpd_remove_device(dev); + + ps->rcdev.owner = THIS_MODULE; + ps->rcdev.nr_resets = 1; + ps->rcdev.ops = &apple_pmgr_reset_ops; + ps->rcdev.of_node = dev->of_node; + ps->rcdev.of_reset_n_cells = 0; + ps->rcdev.of_xlate = apple_pmgr_reset_xlate; + + ret = devm_reset_controller_register(dev, &ps->rcdev); + if (ret < 0) + goto err_remove; + + return 0; +err_remove: + of_genpd_del_provider(node); + pm_genpd_remove(&ps->genpd); + return ret; +} + +static const struct of_device_id apple_pmgr_ps_of_match[] = { + { .compatible = "apple,pmgr-pwrstate" }, + {} +}; + +MODULE_DEVICE_TABLE(of, apple_pmgr_ps_of_match); + +static struct platform_driver apple_pmgr_ps_driver = { + .probe = apple_pmgr_ps_probe, + .driver = { + .name = "apple-pmgr-pwrstate", + .of_match_table = apple_pmgr_ps_of_match, + }, +}; + +MODULE_AUTHOR("Hector Martin "); +MODULE_DESCRIPTION("PMGR power state driver for Apple SoCs"); + +module_platform_driver(apple_pmgr_ps_driver); diff --git a/drivers/soc/apple/Makefile b/drivers/soc/apple/Makefile index e293770cf66d7..b241e6a65e5b3 100644 --- a/drivers/soc/apple/Makefile +++ b/drivers/soc/apple/Makefile @@ -1,6 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_APPLE_PMGR_PWRSTATE) += apple-pmgr-pwrstate.o - obj-$(CONFIG_APPLE_RTKIT) += apple-rtkit.o apple-rtkit-y = rtkit.o rtkit-crashlog.o diff --git a/drivers/soc/apple/apple-pmgr-pwrstate.c b/drivers/soc/apple/apple-pmgr-pwrstate.c deleted file mode 100644 index d62a776c89a12..0000000000000 --- a/drivers/soc/apple/apple-pmgr-pwrstate.c +++ /dev/null @@ -1,326 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only OR MIT -/* - * Apple SoC PMGR device power state driver - * - * Copyright The Asahi Linux Contributors - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define APPLE_PMGR_RESET BIT(31) -#define APPLE_PMGR_AUTO_ENABLE BIT(28) -#define APPLE_PMGR_PS_AUTO GENMASK(27, 24) -#define APPLE_PMGR_PS_MIN GENMASK(19, 16) -#define APPLE_PMGR_PARENT_OFF BIT(11) -#define APPLE_PMGR_DEV_DISABLE BIT(10) -#define APPLE_PMGR_WAS_CLKGATED BIT(9) -#define APPLE_PMGR_WAS_PWRGATED BIT(8) -#define APPLE_PMGR_PS_ACTUAL GENMASK(7, 4) -#define APPLE_PMGR_PS_TARGET GENMASK(3, 0) - -#define APPLE_PMGR_FLAGS (APPLE_PMGR_WAS_CLKGATED | APPLE_PMGR_WAS_PWRGATED) - -#define APPLE_PMGR_PS_ACTIVE 0xf -#define APPLE_PMGR_PS_CLKGATE 0x4 -#define APPLE_PMGR_PS_PWRGATE 0x0 - -#define APPLE_PMGR_PS_SET_TIMEOUT 100 -#define APPLE_PMGR_RESET_TIME 1 - -struct apple_pmgr_ps { - struct device *dev; - struct generic_pm_domain genpd; - struct reset_controller_dev rcdev; - struct regmap *regmap; - u32 offset; - u32 min_state; -}; - -#define genpd_to_apple_pmgr_ps(_genpd) container_of(_genpd, struct apple_pmgr_ps, genpd) -#define rcdev_to_apple_pmgr_ps(_rcdev) container_of(_rcdev, struct apple_pmgr_ps, rcdev) - -static int apple_pmgr_ps_set(struct generic_pm_domain *genpd, u32 pstate, bool auto_enable) -{ - int ret; - struct apple_pmgr_ps *ps = genpd_to_apple_pmgr_ps(genpd); - u32 reg; - - ret = regmap_read(ps->regmap, ps->offset, ®); - if (ret < 0) - return ret; - - /* Resets are synchronous, and only work if the device is powered and clocked. */ - if (reg & APPLE_PMGR_RESET && pstate != APPLE_PMGR_PS_ACTIVE) - dev_err(ps->dev, "PS %s: powering off with RESET active\n", - genpd->name); - - reg &= ~(APPLE_PMGR_AUTO_ENABLE | APPLE_PMGR_FLAGS | APPLE_PMGR_PS_TARGET); - reg |= FIELD_PREP(APPLE_PMGR_PS_TARGET, pstate); - - dev_dbg(ps->dev, "PS %s: pwrstate = 0x%x: 0x%x\n", genpd->name, pstate, reg); - - regmap_write(ps->regmap, ps->offset, reg); - - ret = regmap_read_poll_timeout_atomic( - ps->regmap, ps->offset, reg, - (FIELD_GET(APPLE_PMGR_PS_ACTUAL, reg) == pstate), 1, - APPLE_PMGR_PS_SET_TIMEOUT); - if (ret < 0) - dev_err(ps->dev, "PS %s: Failed to reach power state 0x%x (now: 0x%x)\n", - genpd->name, pstate, reg); - - if (auto_enable) { - /* Not all devices implement this; this is a no-op where not implemented. */ - reg &= ~APPLE_PMGR_FLAGS; - reg |= APPLE_PMGR_AUTO_ENABLE; - regmap_write(ps->regmap, ps->offset, reg); - } - - return ret; -} - -static bool apple_pmgr_ps_is_active(struct apple_pmgr_ps *ps) -{ - u32 reg = 0; - - regmap_read(ps->regmap, ps->offset, ®); - /* - * We consider domains as active if they are actually on, or if they have auto-PM - * enabled and the intended target is on. - */ - return (FIELD_GET(APPLE_PMGR_PS_ACTUAL, reg) == APPLE_PMGR_PS_ACTIVE || - (FIELD_GET(APPLE_PMGR_PS_TARGET, reg) == APPLE_PMGR_PS_ACTIVE && - reg & APPLE_PMGR_AUTO_ENABLE)); -} - -static int apple_pmgr_ps_power_on(struct generic_pm_domain *genpd) -{ - return apple_pmgr_ps_set(genpd, APPLE_PMGR_PS_ACTIVE, true); -} - -static int apple_pmgr_ps_power_off(struct generic_pm_domain *genpd) -{ - return apple_pmgr_ps_set(genpd, APPLE_PMGR_PS_PWRGATE, false); -} - -static int apple_pmgr_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) -{ - struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev); - unsigned long flags; - - spin_lock_irqsave(&ps->genpd.slock, flags); - - if (ps->genpd.status == GENPD_STATE_OFF) - dev_err(ps->dev, "PS 0x%x: asserting RESET while powered down\n", ps->offset); - - dev_dbg(ps->dev, "PS 0x%x: assert reset\n", ps->offset); - /* Quiesce device before asserting reset */ - regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_DEV_DISABLE, - APPLE_PMGR_DEV_DISABLE); - regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_RESET, - APPLE_PMGR_RESET); - - spin_unlock_irqrestore(&ps->genpd.slock, flags); - - return 0; -} - -static int apple_pmgr_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) -{ - struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev); - unsigned long flags; - - spin_lock_irqsave(&ps->genpd.slock, flags); - - dev_dbg(ps->dev, "PS 0x%x: deassert reset\n", ps->offset); - regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_RESET, 0); - regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_DEV_DISABLE, 0); - - if (ps->genpd.status == GENPD_STATE_OFF) - dev_err(ps->dev, "PS 0x%x: RESET was deasserted while powered down\n", ps->offset); - - spin_unlock_irqrestore(&ps->genpd.slock, flags); - - return 0; -} - -static int apple_pmgr_reset_reset(struct reset_controller_dev *rcdev, unsigned long id) -{ - int ret; - - ret = apple_pmgr_reset_assert(rcdev, id); - if (ret) - return ret; - - usleep_range(APPLE_PMGR_RESET_TIME, 2 * APPLE_PMGR_RESET_TIME); - - return apple_pmgr_reset_deassert(rcdev, id); -} - -static int apple_pmgr_reset_status(struct reset_controller_dev *rcdev, unsigned long id) -{ - struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev); - u32 reg = 0; - - regmap_read(ps->regmap, ps->offset, ®); - - return !!(reg & APPLE_PMGR_RESET); -} - -const struct reset_control_ops apple_pmgr_reset_ops = { - .assert = apple_pmgr_reset_assert, - .deassert = apple_pmgr_reset_deassert, - .reset = apple_pmgr_reset_reset, - .status = apple_pmgr_reset_status, -}; - -static int apple_pmgr_reset_xlate(struct reset_controller_dev *rcdev, - const struct of_phandle_args *reset_spec) -{ - return 0; -} - -static int apple_pmgr_ps_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *node = dev->of_node; - struct apple_pmgr_ps *ps; - struct regmap *regmap; - struct of_phandle_iterator it; - int ret; - const char *name; - bool active; - - regmap = syscon_node_to_regmap(node->parent); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); - - ps = devm_kzalloc(dev, sizeof(*ps), GFP_KERNEL); - if (!ps) - return -ENOMEM; - - ps->dev = dev; - ps->regmap = regmap; - - ret = of_property_read_string(node, "label", &name); - if (ret < 0) { - dev_err(dev, "missing label property\n"); - return ret; - } - - ret = of_property_read_u32(node, "reg", &ps->offset); - if (ret < 0) { - dev_err(dev, "missing reg property\n"); - return ret; - } - - ps->genpd.flags |= GENPD_FLAG_IRQ_SAFE; - ps->genpd.name = name; - ps->genpd.power_on = apple_pmgr_ps_power_on; - ps->genpd.power_off = apple_pmgr_ps_power_off; - - ret = of_property_read_u32(node, "apple,min-state", &ps->min_state); - if (ret == 0 && ps->min_state <= APPLE_PMGR_PS_ACTIVE) - regmap_update_bits(regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_PS_MIN, - FIELD_PREP(APPLE_PMGR_PS_MIN, ps->min_state)); - - active = apple_pmgr_ps_is_active(ps); - if (of_property_read_bool(node, "apple,always-on")) { - ps->genpd.flags |= GENPD_FLAG_ALWAYS_ON; - if (!active) { - dev_warn(dev, "always-on domain %s is not on at boot\n", name); - /* Turn it on so pm_genpd_init does not fail */ - active = apple_pmgr_ps_power_on(&ps->genpd) == 0; - } - } - - /* Turn on auto-PM if the domain is already on */ - if (active) - regmap_update_bits(regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_AUTO_ENABLE, - APPLE_PMGR_AUTO_ENABLE); - - ret = pm_genpd_init(&ps->genpd, NULL, !active); - if (ret < 0) { - dev_err(dev, "pm_genpd_init failed\n"); - return ret; - } - - ret = of_genpd_add_provider_simple(node, &ps->genpd); - if (ret < 0) { - dev_err(dev, "of_genpd_add_provider_simple failed\n"); - return ret; - } - - of_for_each_phandle(&it, ret, node, "power-domains", "#power-domain-cells", -1) { - struct of_phandle_args parent, child; - - parent.np = it.node; - parent.args_count = of_phandle_iterator_args(&it, parent.args, MAX_PHANDLE_ARGS); - child.np = node; - child.args_count = 0; - ret = of_genpd_add_subdomain(&parent, &child); - - if (ret == -EPROBE_DEFER) { - of_node_put(parent.np); - goto err_remove; - } else if (ret < 0) { - dev_err(dev, "failed to add to parent domain: %d (%s -> %s)\n", - ret, it.node->name, node->name); - of_node_put(parent.np); - goto err_remove; - } - } - - /* - * Do not participate in regular PM; parent power domains are handled via the - * genpd hierarchy. - */ - pm_genpd_remove_device(dev); - - ps->rcdev.owner = THIS_MODULE; - ps->rcdev.nr_resets = 1; - ps->rcdev.ops = &apple_pmgr_reset_ops; - ps->rcdev.of_node = dev->of_node; - ps->rcdev.of_reset_n_cells = 0; - ps->rcdev.of_xlate = apple_pmgr_reset_xlate; - - ret = devm_reset_controller_register(dev, &ps->rcdev); - if (ret < 0) - goto err_remove; - - return 0; -err_remove: - of_genpd_del_provider(node); - pm_genpd_remove(&ps->genpd); - return ret; -} - -static const struct of_device_id apple_pmgr_ps_of_match[] = { - { .compatible = "apple,pmgr-pwrstate" }, - {} -}; - -MODULE_DEVICE_TABLE(of, apple_pmgr_ps_of_match); - -static struct platform_driver apple_pmgr_ps_driver = { - .probe = apple_pmgr_ps_probe, - .driver = { - .name = "apple-pmgr-pwrstate", - .of_match_table = apple_pmgr_ps_of_match, - }, -}; - -MODULE_AUTHOR("Hector Martin "); -MODULE_DESCRIPTION("PMGR power state driver for Apple SoCs"); - -module_platform_driver(apple_pmgr_ps_driver);