summaryrefslogtreecommitdiff
path: root/drivers/power/domain/power-domain-uclass.c
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2016-07-13 13:45:31 -0600
committerSimon Glass <sjg@chromium.org>2016-07-27 16:29:56 -0600
commit61f5ddcb7a997f7b7bca3680cd6f67e60e616841 (patch)
treeca5dcfb1d2335fa819cc7e36ea6295a6d12a4898 /drivers/power/domain/power-domain-uclass.c
parent1e2b3ef8653417f296ee23f32c28abfc086529dd (diff)
Add a power domain framework/uclass
Many SoCs allow power to be applied to or removed from portions of the SoC (power domains). This may be used to save power. This API provides the means to control such power management hardware. Signed-off-by: Stephen Warren <swarren@nvidia.com> Acked-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'drivers/power/domain/power-domain-uclass.c')
-rw-r--r--drivers/power/domain/power-domain-uclass.c112
1 files changed, 112 insertions, 0 deletions
diff --git a/drivers/power/domain/power-domain-uclass.c b/drivers/power/domain/power-domain-uclass.c
new file mode 100644
index 0000000000..1bb6262fa1
--- /dev/null
+++ b/drivers/power/domain/power-domain-uclass.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <power-domain.h>
+#include <power-domain-uclass.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static inline struct power_domain_ops *power_domain_dev_ops(struct udevice *dev)
+{
+ return (struct power_domain_ops *)dev->driver->ops;
+}
+
+static int power_domain_of_xlate_default(struct power_domain *power_domain,
+ struct fdtdec_phandle_args *args)
+{
+ debug("%s(power_domain=%p)\n", __func__, power_domain);
+
+ if (args->args_count != 1) {
+ debug("Invalid args_count: %d\n", args->args_count);
+ return -EINVAL;
+ }
+
+ power_domain->id = args->args[0];
+
+ return 0;
+}
+
+int power_domain_get(struct udevice *dev, struct power_domain *power_domain)
+{
+ struct fdtdec_phandle_args args;
+ int ret;
+ struct udevice *dev_power_domain;
+ struct power_domain_ops *ops;
+
+ debug("%s(dev=%p, power_domain=%p)\n", __func__, dev, power_domain);
+
+ ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset,
+ "power-domains",
+ "#power-domain-cells", 0, 0,
+ &args);
+ if (ret) {
+ debug("%s: fdtdec_parse_phandle_with_args failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = uclass_get_device_by_of_offset(UCLASS_POWER_DOMAIN, args.node,
+ &dev_power_domain);
+ if (ret) {
+ debug("%s: uclass_get_device_by_of_offset failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+ ops = power_domain_dev_ops(dev_power_domain);
+
+ power_domain->dev = dev_power_domain;
+ if (ops->of_xlate)
+ ret = ops->of_xlate(power_domain, &args);
+ else
+ ret = power_domain_of_xlate_default(power_domain, &args);
+ if (ret) {
+ debug("of_xlate() failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = ops->request(power_domain);
+ if (ret) {
+ debug("ops->request() failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int power_domain_free(struct power_domain *power_domain)
+{
+ struct power_domain_ops *ops = power_domain_dev_ops(power_domain->dev);
+
+ debug("%s(power_domain=%p)\n", __func__, power_domain);
+
+ return ops->free(power_domain);
+}
+
+int power_domain_on(struct power_domain *power_domain)
+{
+ struct power_domain_ops *ops = power_domain_dev_ops(power_domain->dev);
+
+ debug("%s(power_domain=%p)\n", __func__, power_domain);
+
+ return ops->on(power_domain);
+}
+
+int power_domain_off(struct power_domain *power_domain)
+{
+ struct power_domain_ops *ops = power_domain_dev_ops(power_domain->dev);
+
+ debug("%s(power_domain=%p)\n", __func__, power_domain);
+
+ return ops->off(power_domain);
+}
+
+UCLASS_DRIVER(power_domain) = {
+ .id = UCLASS_POWER_DOMAIN,
+ .name = "power_domain",
+};