]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
soc/tegra: pmc: Add PMC contextual functions
authorThierry Reding <treding@nvidia.com>
Mon, 3 Feb 2025 15:22:58 +0000 (16:22 +0100)
committerThierry Reding <treding@nvidia.com>
Sun, 18 Jan 2026 07:48:30 +0000 (08:48 +0100)
Add implementations that take as argument a struct tegra_pmc * for most
public APIs, as well as a function to obtain the PMC for any given
device. This will allow transitioning away users from relying on a
global variable storing the PMC context.

Signed-off-by: Thierry Reding <treding@nvidia.com>
drivers/soc/tegra/pmc.c
include/soc/tegra/pmc.h

index 750fe29f4cf59b07270ac17db5271202e287c6c1..9cdbd8ba94be00175b0bc24991172979a5064de6 100644 (file)
@@ -957,30 +957,122 @@ static int tegra_genpd_power_off(struct generic_pm_domain *domain)
        return err;
 }
 
+static void tegra_pmc_put_device(void *data)
+{
+       struct tegra_pmc *pmc = data;
+
+       put_device(pmc->dev);
+}
+
+static const struct of_device_id tegra_pmc_match[];
+
+static struct tegra_pmc *tegra_pmc_get(struct device *dev)
+{
+       struct platform_device *pdev;
+       struct device_node *np;
+       struct tegra_pmc *pmc;
+
+       np = of_parse_phandle(dev->of_node, "nvidia,pmc", 0);
+       if (!np) {
+               struct device_node *parent = of_node_get(dev->of_node);
+
+               while ((parent = of_get_next_parent(parent)) != NULL) {
+                       np = of_find_matching_node(parent, tegra_pmc_match);
+                       if (np)
+                               break;
+               }
+
+               of_node_put(parent);
+
+               if (!np)
+                       return ERR_PTR(-ENODEV);
+       }
+
+       pdev = of_find_device_by_node(np);
+       of_node_put(np);
+
+       if (!pdev)
+               return ERR_PTR(-ENODEV);
+
+       pmc = platform_get_drvdata(pdev);
+       if (!pmc) {
+               put_device(&pdev->dev);
+               return ERR_PTR(-EPROBE_DEFER);
+       }
+
+       return pmc;
+}
+
 /**
- * tegra_powergate_power_on() - power on partition
+ * tegra_pmc_get() - find the PMC for a given device
+ * @dev: device for which to find the PMC
+ *
+ * Returns a pointer to the PMC on success or an ERR_PTR()-encoded error code
+ * otherwise.
+ */
+struct tegra_pmc *devm_tegra_pmc_get(struct device *dev)
+{
+       struct tegra_pmc *pmc;
+       int err;
+
+       pmc = tegra_pmc_get(dev);
+       if (IS_ERR(pmc))
+               return pmc;
+
+       err = devm_add_action_or_reset(dev, tegra_pmc_put_device, pmc);
+       if (err < 0)
+               return ERR_PTR(err);
+
+       return pmc;
+}
+EXPORT_SYMBOL(devm_tegra_pmc_get);
+
+/**
+ * tegra_pmc_powergate_power_on() - power on partition
+ * @pmc: power management controller
  * @id: partition ID
  */
-int tegra_powergate_power_on(unsigned int id)
+int tegra_pmc_powergate_power_on(struct tegra_pmc *pmc, unsigned int id)
 {
        if (!tegra_powergate_is_available(pmc, id))
                return -EINVAL;
 
        return tegra_powergate_set(pmc, id, true);
 }
+EXPORT_SYMBOL(tegra_pmc_powergate_power_on);
+
+/**
+ * tegra_powergate_power_on() - power on partition
+ * @id: partition ID
+ */
+int tegra_powergate_power_on(unsigned int id)
+{
+       return tegra_pmc_powergate_power_on(pmc, id);
+}
 EXPORT_SYMBOL(tegra_powergate_power_on);
 
 /**
- * tegra_powergate_power_off() - power off partition
+ * tegra_pmc_powergate_power_off() - power off partition
+ * @pmc: power management controller
  * @id: partition ID
  */
-int tegra_powergate_power_off(unsigned int id)
+int tegra_pmc_powergate_power_off(struct tegra_pmc *pmc, unsigned int id)
 {
        if (!tegra_powergate_is_available(pmc, id))
                return -EINVAL;
 
        return tegra_powergate_set(pmc, id, false);
 }
+EXPORT_SYMBOL(tegra_pmc_powergate_power_off);
+
+/**
+ * tegra_powergate_power_off() - power off partition
+ * @id: partition ID
+ */
+int tegra_powergate_power_off(unsigned int id)
+{
+       return tegra_pmc_powergate_power_off(pmc, id);
+}
 EXPORT_SYMBOL(tegra_powergate_power_off);
 
 /**
@@ -997,28 +1089,41 @@ static int tegra_powergate_is_powered(struct tegra_pmc *pmc, unsigned int id)
 }
 
 /**
- * tegra_powergate_remove_clamping() - remove power clamps for partition
+ * tegra_pmc_powergate_remove_clamping() - remove power clamps for partition
+ * @pmc: power management controller
  * @id: partition ID
  */
-int tegra_powergate_remove_clamping(unsigned int id)
+int tegra_pmc_powergate_remove_clamping(struct tegra_pmc *pmc, unsigned int id)
 {
        if (!tegra_powergate_is_available(pmc, id))
                return -EINVAL;
 
        return __tegra_powergate_remove_clamping(pmc, id);
 }
+EXPORT_SYMBOL(tegra_pmc_powergate_remove_clamping);
+
+/**
+ * tegra_powergate_remove_clamping() - remove power clamps for partition
+ * @id: partition ID
+ */
+int tegra_powergate_remove_clamping(unsigned int id)
+{
+       return tegra_pmc_powergate_remove_clamping(pmc, id);
+}
 EXPORT_SYMBOL(tegra_powergate_remove_clamping);
 
 /**
- * tegra_powergate_sequence_power_up() - power up partition
+ * tegra_pmc_powergate_sequence_power_up() - power up partition
+ * @pmc: power management controller
  * @id: partition ID
  * @clk: clock for partition
  * @rst: reset for partition
  *
  * Must be called with clk disabled, and returns with clk enabled.
  */
-int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,
-                                     struct reset_control *rst)
+int tegra_pmc_powergate_sequence_power_up(struct tegra_pmc *pmc,
+                                         unsigned int id, struct clk *clk,
+                                         struct reset_control *rst)
 {
        struct tegra_powergate *pg;
        int err;
@@ -1052,6 +1157,21 @@ int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,
 
        return err;
 }
+EXPORT_SYMBOL(tegra_pmc_powergate_sequence_power_up);
+
+/**
+ * tegra_powergate_sequence_power_up() - power up partition
+ * @id: partition ID
+ * @clk: clock for partition
+ * @rst: reset for partition
+ *
+ * Must be called with clk disabled, and returns with clk enabled.
+ */
+int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,
+                                     struct reset_control *rst)
+{
+       return tegra_pmc_powergate_sequence_power_up(pmc, id, clk, rst);
+}
 EXPORT_SYMBOL(tegra_powergate_sequence_power_up);
 
 /**
@@ -1627,11 +1747,12 @@ static void tegra_io_pad_unprepare(struct tegra_pmc *pmc)
 
 /**
  * tegra_io_pad_power_enable() - enable power to I/O pad
+ * @pmc: power management controller
  * @id: Tegra I/O pad ID for which to enable power
  *
  * Returns: 0 on success or a negative error code on failure.
  */
-int tegra_io_pad_power_enable(enum tegra_io_pad id)
+int tegra_pmc_io_pad_power_enable(struct tegra_pmc *pmc, enum tegra_io_pad id)
 {
        const struct tegra_io_pad_soc *pad;
        unsigned long request, status;
@@ -1666,15 +1787,28 @@ unlock:
        mutex_unlock(&pmc->powergates_lock);
        return err;
 }
+EXPORT_SYMBOL(tegra_pmc_io_pad_power_enable);
+
+/**
+ * tegra_io_pad_power_enable() - enable power to I/O pad
+ * @id: Tegra I/O pad ID for which to enable power
+ *
+ * Returns: 0 on success or a negative error code on failure.
+ */
+int tegra_io_pad_power_enable(enum tegra_io_pad id)
+{
+       return tegra_pmc_io_pad_power_enable(pmc, id);
+}
 EXPORT_SYMBOL(tegra_io_pad_power_enable);
 
 /**
- * tegra_io_pad_power_disable() - disable power to I/O pad
+ * tegra_pmc_io_pad_power_disable() - disable power to I/O pad
+ * @pmc: power management controller
  * @id: Tegra I/O pad ID for which to disable power
  *
  * Returns: 0 on success or a negative error code on failure.
  */
-int tegra_io_pad_power_disable(enum tegra_io_pad id)
+int tegra_pmc_io_pad_power_disable(struct tegra_pmc *pmc, enum tegra_io_pad id)
 {
        const struct tegra_io_pad_soc *pad;
        unsigned long request, status;
@@ -1709,6 +1843,18 @@ unlock:
        mutex_unlock(&pmc->powergates_lock);
        return err;
 }
+EXPORT_SYMBOL(tegra_pmc_io_pad_power_disable);
+
+/**
+ * tegra_io_pad_power_disable() - disable power to I/O pad
+ * @id: Tegra I/O pad ID for which to disable power
+ *
+ * Returns: 0 on success or a negative error code on failure.
+ */
+int tegra_io_pad_power_disable(enum tegra_io_pad id)
+{
+       return tegra_pmc_io_pad_power_disable(pmc, id);
+}
 EXPORT_SYMBOL(tegra_io_pad_power_disable);
 
 static int tegra_io_pad_is_powered(struct tegra_pmc *pmc, enum tegra_io_pad id)
@@ -2184,9 +2330,9 @@ static int tegra_io_pad_pinconf_set(struct pinctrl_dev *pctl_dev,
                switch (param) {
                case PIN_CONFIG_MODE_LOW_POWER:
                        if (arg)
-                               err = tegra_io_pad_power_disable(pad->id);
+                               err = tegra_pmc_io_pad_power_disable(pmc, pad->id);
                        else
-                               err = tegra_io_pad_power_enable(pad->id);
+                               err = tegra_pmc_io_pad_power_enable(pmc, pad->id);
                        if (err)
                                return err;
                        break;
index c545875d0ff18e6117e1ad0ffc61252240fd16a2..1fd21be025778ea82d449b266215abe33e65ea5b 100644 (file)
@@ -16,6 +16,7 @@
 
 struct clk;
 struct reset_control;
+struct tegra_pmc;
 
 bool tegra_pmc_cpu_is_powered(unsigned int cpuid);
 int tegra_pmc_cpu_power_on(unsigned int cpuid);
@@ -149,11 +150,24 @@ enum tegra_io_pad {
 };
 
 #ifdef CONFIG_SOC_TEGRA_PMC
+struct tegra_pmc *devm_tegra_pmc_get(struct device *dev);
+
+int tegra_pmc_powergate_power_on(struct tegra_pmc *pmc, unsigned int id);
+int tegra_pmc_powergate_power_off(struct tegra_pmc *pmc, unsigned int id);
+int tegra_pmc_powergate_remove_clamping(struct tegra_pmc *pmc, unsigned int id);
+
+/* Must be called with clk disabled, and returns with clk enabled */
+int tegra_pmc_powergate_sequence_power_up(struct tegra_pmc *pmc,
+                                         unsigned int id, struct clk *clk,
+                                         struct reset_control *rst);
+int tegra_pmc_io_pad_power_enable(struct tegra_pmc *pmc, enum tegra_io_pad id);
+int tegra_pmc_io_pad_power_disable(struct tegra_pmc *pmc, enum tegra_io_pad id);
+
+/* legacy */
 int tegra_powergate_power_on(unsigned int id);
 int tegra_powergate_power_off(unsigned int id);
 int tegra_powergate_remove_clamping(unsigned int id);
 
-/* Must be called with clk disabled, and returns with clk enabled */
 int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk,
                                      struct reset_control *rst);
 
@@ -166,6 +180,50 @@ void tegra_pmc_enter_suspend_mode(enum tegra_suspend_mode mode);
 bool tegra_pmc_core_domain_state_synced(void);
 
 #else
+static inline struct tegra_pmc *devm_tegra_pmc_get(struct device *dev)
+{
+       return ERR_PTR(-ENOSYS);
+}
+
+static inline int
+tegra_pmc_powergate_power_on(struct tegra_pmc *pmc, unsigned int id)
+{
+       return -ENOSYS;
+}
+
+static inline int
+tegra_pmc_powergate_power_off(struct tegra_pmc *pmc, unsigned int id)
+{
+       return -ENOSYS;
+}
+
+static inline int
+tegra_pmc_powergate_remove_clamping(struct tegra_pmc *pmc, unsigned int id)
+{
+       return -ENOSYS;
+}
+
+/* Must be called with clk disabled, and returns with clk enabled */
+static inline int
+tegra_pmc_powergate_sequence_power_up(struct tegra_pmc *pmc, unsigned int id,
+                                     struct clk *clk,
+                                     struct reset_control *rst)
+{
+       return -ENOSYS;
+}
+
+static inline int
+tegra_pmc_io_pad_power_enable(struct tegra_pmc *pmc, enum tegra_io_pad id)
+{
+       return -ENOSYS;
+}
+
+static inline int
+tegra_pmc_io_pad_power_disable(struct tegra_pmc *pmc, enum tegra_io_pad id)
+{
+       return -ENOSYS;
+}
+
 static inline int tegra_powergate_power_on(unsigned int id)
 {
        return -ENOSYS;