/* * OMAP2/3/4 clockdomain framework functions * * Copyright (C) 2008-2011 Texas Instruments, Inc. * Copyright (C) 2008-2011 Nokia Corporation * * Written by Paul Walmsley and Jouni Högander * Added OMAP4 specific support by Abhijit Pagare * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #undef DEBUG #include #include #include #include #include #include #include #include #include #include #include #include #include "soc.h" #include "clock.h" #include "clockdomain.h" /* clkdm_list contains all registered struct clockdomains */ static LIST_HEAD(clkdm_list); /* array of clockdomain deps to be added/removed when clkdm in hwsup mode */ static struct clkdm_autodep *autodeps; static struct clkdm_ops *arch_clkdm; /* Private functions */ static struct clockdomain *_clkdm_lookup(const char *name) { struct clockdomain *clkdm, *temp_clkdm; if (!name) return NULL; clkdm = NULL; list_for_each_entry(temp_clkdm, &clkdm_list, node) { if (!strcmp(name, temp_clkdm->name)) { clkdm = temp_clkdm; break; } } return clkdm; } /** * _clkdm_register - register a clockdomain * @clkdm: struct clockdomain * to register * * Adds a clockdomain to the internal clockdomain list. * Returns -EINVAL if given a null pointer, -EEXIST if a clockdomain is * already registered by the provided name, or 0 upon success. */ static int _clkdm_register(struct clockdomain *clkdm) { struct powerdomain *pwrdm; if (!clkdm || !clkdm->name) return -EINVAL; pwrdm = pwrdm_lookup(clkdm->pwrdm.name); if (!pwrdm) { pr_err("clockdomain: %s: powerdomain %s does not exist\n", clkdm->name, clkdm->pwrdm.name); return -EINVAL; } clkdm->pwrdm.ptr = pwrdm; /* Verify that the clockdomain is not already registered */ if (_clkdm_lookup(clkdm->name)) return -EEXIST; list_add(&clkdm->node, &clkdm_list); pwrdm_add_clkdm(pwrdm, clkdm); spin_lock_init(&clkdm->lock); pr_debug("clockdomain: registered %s\n", clkdm->name); return 0; } /* _clkdm_deps_lookup - look up the specified clockdomain in a clkdm list */ static struct clkdm_dep *_clkdm_deps_lookup(struct clockdomain *clkdm, struct clkdm_dep *deps) { struct clkdm_dep *cd; if (!clkdm || !deps) return ERR_PTR(-EINVAL); for (cd = deps; cd->clkdm_name; cd++) { if (!cd->clkdm && cd->clkdm_name) cd->clkdm = _clkdm_lookup(cd->clkdm_name); if (cd->clkdm == clkdm) break; } if (!cd->clkdm_name) return ERR_PTR(-ENOENT); return cd; } /* * _autodep_lookup - resolve autodep clkdm names to clkdm pointers; store * @autodep: struct clkdm_autodep * to resolve * * Resolve autodep clockdomain names to clockdomain pointers via * clkdm_lookup() and store the pointers in the autodep structure. An * "autodep" is a clockdomain sleep/wakeup dependency that is * automatically added and removed whenever clocks in the associated * clockdomain are enabled or disabled (respectively) when the * clockdomain is in hardware-supervised mode. Meant to be called * once at clockdomain layer initialization, since these should remain * fixed for a particular architecture. No return value. * * XXX autodeps are deprecated and should be removed at the earliest * opportunity */ static void _autodep_lookup(struct clkdm_autodep *autodep) { struct clockdomain *clkdm; if (!autodep) return; clkdm = clkdm_lookup(autodep->clkdm.name); if (!clkdm) { pr_err("clockdomain: autodeps: clockdomain %s does not exist\n", autodep->clkdm.name); clkdm = ERR_PTR(-ENOENT);