|
@@ -255,3 +255,116 @@ int pwrdm_register_pwrdms(struct powerdomain **ps)
|
|
|
*
|
|
|
* Do whatever is necessary to initialize registered powerdomains and
|
|
|
* powerdomain code. Currently, this programs the next power state
|
|
|
+ * for each powerdomain to ON. This prevents powerdomains from
|
|
|
+ * unexpectedly losing context or entering high wakeup latency modes
|
|
|
+ * with non-power-management-enabled kernels. Must be called after
|
|
|
+ * pwrdm_register_pwrdms(). Returns -EACCES if called before
|
|
|
+ * pwrdm_register_pwrdms(), or 0 upon success.
|
|
|
+ */
|
|
|
+int pwrdm_complete_init(void)
|
|
|
+{
|
|
|
+ struct powerdomain *temp_p;
|
|
|
+
|
|
|
+ if (list_empty(&pwrdm_list))
|
|
|
+ return -EACCES;
|
|
|
+
|
|
|
+ list_for_each_entry(temp_p, &pwrdm_list, node)
|
|
|
+ pwrdm_set_next_pwrst(temp_p, PWRDM_POWER_ON);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * pwrdm_lookup - look up a powerdomain by name, return a pointer
|
|
|
+ * @name: name of powerdomain
|
|
|
+ *
|
|
|
+ * Find a registered powerdomain by its name @name. Returns a pointer
|
|
|
+ * to the struct powerdomain if found, or NULL otherwise.
|
|
|
+ */
|
|
|
+struct powerdomain *pwrdm_lookup(const char *name)
|
|
|
+{
|
|
|
+ struct powerdomain *pwrdm;
|
|
|
+
|
|
|
+ if (!name)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ pwrdm = _pwrdm_lookup(name);
|
|
|
+
|
|
|
+ return pwrdm;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * pwrdm_for_each - call function on each registered clockdomain
|
|
|
+ * @fn: callback function *
|
|
|
+ *
|
|
|
+ * Call the supplied function @fn for each registered powerdomain.
|
|
|
+ * The callback function @fn can return anything but 0 to bail out
|
|
|
+ * early from the iterator. Returns the last return value of the
|
|
|
+ * callback function, which should be 0 for success or anything else
|
|
|
+ * to indicate failure; or -EINVAL if the function pointer is null.
|
|
|
+ */
|
|
|
+int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user),
|
|
|
+ void *user)
|
|
|
+{
|
|
|
+ struct powerdomain *temp_pwrdm;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ if (!fn)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
|
|
|
+ ret = (*fn)(temp_pwrdm, user);
|
|
|
+ if (ret)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * pwrdm_add_clkdm - add a clockdomain to a powerdomain
|
|
|
+ * @pwrdm: struct powerdomain * to add the clockdomain to
|
|
|
+ * @clkdm: struct clockdomain * to associate with a powerdomain
|
|
|
+ *
|
|
|
+ * Associate the clockdomain @clkdm with a powerdomain @pwrdm. This
|
|
|
+ * enables the use of pwrdm_for_each_clkdm(). Returns -EINVAL if
|
|
|
+ * presented with invalid pointers; -ENOMEM if memory could not be allocated;
|
|
|
+ * or 0 upon success.
|
|
|
+ */
|
|
|
+int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ int ret = -EINVAL;
|
|
|
+
|
|
|
+ if (!pwrdm || !clkdm)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ pr_debug("powerdomain: %s: associating clockdomain %s\n",
|
|
|
+ pwrdm->name, clkdm->name);
|
|
|
+
|
|
|
+ for (i = 0; i < PWRDM_MAX_CLKDMS; i++) {
|
|
|
+ if (!pwrdm->pwrdm_clkdms[i])
|
|
|
+ break;
|
|
|
+#ifdef DEBUG
|
|
|
+ if (pwrdm->pwrdm_clkdms[i] == clkdm) {
|
|
|
+ ret = -EINVAL;
|
|
|
+ goto pac_exit;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+ if (i == PWRDM_MAX_CLKDMS) {
|
|
|
+ pr_debug("powerdomain: %s: increase PWRDM_MAX_CLKDMS for clkdm %s\n",
|
|
|
+ pwrdm->name, clkdm->name);
|
|
|
+ WARN_ON(1);
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto pac_exit;
|
|
|
+ }
|
|
|
+
|
|
|
+ pwrdm->pwrdm_clkdms[i] = clkdm;
|
|
|
+
|
|
|
+ ret = 0;
|
|
|
+
|
|
|
+pac_exit:
|
|
|
+ return ret;
|
|
|
+}
|