clockdomain.c 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * OMAP2/3/4 clockdomain framework functions
  4. *
  5. * Copyright (C) 2008-2011 Texas Instruments, Inc.
  6. * Copyright (C) 2008-2011 Nokia Corporation
  7. *
  8. * Written by Paul Walmsley and Jouni Högander
  9. * Added OMAP4 specific support by Abhijit Pagare <[email protected]>
  10. */
  11. #undef DEBUG
  12. #include <linux/kernel.h>
  13. #include <linux/device.h>
  14. #include <linux/list.h>
  15. #include <linux/errno.h>
  16. #include <linux/string.h>
  17. #include <linux/delay.h>
  18. #include <linux/clk.h>
  19. #include <linux/limits.h>
  20. #include <linux/err.h>
  21. #include <linux/clk-provider.h>
  22. #include <linux/cpu_pm.h>
  23. #include <linux/io.h>
  24. #include <linux/bitops.h>
  25. #include "soc.h"
  26. #include "clock.h"
  27. #include "clockdomain.h"
  28. #include "pm.h"
  29. /* clkdm_list contains all registered struct clockdomains */
  30. static LIST_HEAD(clkdm_list);
  31. /* array of clockdomain deps to be added/removed when clkdm in hwsup mode */
  32. static struct clkdm_autodep *autodeps;
  33. static struct clkdm_ops *arch_clkdm;
  34. void clkdm_save_context(void);
  35. void clkdm_restore_context(void);
  36. /* Private functions */
  37. static struct clockdomain *_clkdm_lookup(const char *name)
  38. {
  39. struct clockdomain *clkdm, *temp_clkdm;
  40. if (!name)
  41. return NULL;
  42. clkdm = NULL;
  43. list_for_each_entry(temp_clkdm, &clkdm_list, node) {
  44. if (!strcmp(name, temp_clkdm->name)) {
  45. clkdm = temp_clkdm;
  46. break;
  47. }
  48. }
  49. return clkdm;
  50. }
  51. /**
  52. * _clkdm_register - register a clockdomain
  53. * @clkdm: struct clockdomain * to register
  54. *
  55. * Adds a clockdomain to the internal clockdomain list.
  56. * Returns -EINVAL if given a null pointer, -EEXIST if a clockdomain is
  57. * already registered by the provided name, or 0 upon success.
  58. */
  59. static int _clkdm_register(struct clockdomain *clkdm)
  60. {
  61. struct powerdomain *pwrdm;
  62. if (!clkdm || !clkdm->name)
  63. return -EINVAL;
  64. pwrdm = pwrdm_lookup(clkdm->pwrdm.name);
  65. if (!pwrdm) {
  66. pr_err("clockdomain: %s: powerdomain %s does not exist\n",
  67. clkdm->name, clkdm->pwrdm.name);
  68. return -EINVAL;
  69. }
  70. clkdm->pwrdm.ptr = pwrdm;
  71. /* Verify that the clockdomain is not already registered */
  72. if (_clkdm_lookup(clkdm->name))
  73. return -EEXIST;
  74. list_add(&clkdm->node, &clkdm_list);
  75. pwrdm_add_clkdm(pwrdm, clkdm);
  76. pr_debug("clockdomain: registered %s\n", clkdm->name);
  77. return 0;
  78. }
  79. /* _clkdm_deps_lookup - look up the specified clockdomain in a clkdm list */
  80. static struct clkdm_dep *_clkdm_deps_lookup(struct clockdomain *clkdm,
  81. struct clkdm_dep *deps)
  82. {
  83. struct clkdm_dep *cd;
  84. if (!clkdm || !deps)
  85. return ERR_PTR(-EINVAL);
  86. for (cd = deps; cd->clkdm_name; cd++) {
  87. if (!cd->clkdm && cd->clkdm_name)
  88. cd->clkdm = _clkdm_lookup(cd->clkdm_name);
  89. if (cd->clkdm == clkdm)
  90. break;
  91. }
  92. if (!cd->clkdm_name)
  93. return ERR_PTR(-ENOENT);
  94. return cd;
  95. }
  96. /**
  97. * _autodep_lookup - resolve autodep clkdm names to clkdm pointers; store
  98. * @autodep: struct clkdm_autodep * to resolve
  99. *
  100. * Resolve autodep clockdomain names to clockdomain pointers via
  101. * clkdm_lookup() and store the pointers in the autodep structure. An
  102. * "autodep" is a clockdomain sleep/wakeup dependency that is
  103. * automatically added and removed whenever clocks in the associated
  104. * clockdomain are enabled or disabled (respectively) when the
  105. * clockdomain is in hardware-supervised mode. Meant to be called
  106. * once at clockdomain layer initialization, since these should remain
  107. * fixed for a particular architecture. No return value.
  108. *
  109. * XXX autodeps are deprecated and should be removed at the earliest
  110. * opportunity
  111. */
  112. static void _autodep_lookup(struct clkdm_autodep *autodep)
  113. {
  114. struct clockdomain *clkdm;
  115. if (!autodep)
  116. return;
  117. clkdm = clkdm_lookup(autodep->clkdm.name);
  118. if (!clkdm) {
  119. pr_err("clockdomain: autodeps: clockdomain %s does not exist\n",
  120. autodep->clkdm.name);
  121. clkdm = ERR_PTR(-ENOENT);
  122. }
  123. autodep->clkdm.ptr = clkdm;
  124. }
  125. /**
  126. * _resolve_clkdm_deps() - resolve clkdm_names in @clkdm_deps to clkdms
  127. * @clkdm: clockdomain that we are resolving dependencies for
  128. * @clkdm_deps: ptr to array of struct clkdm_deps to resolve
  129. *
  130. * Iterates through @clkdm_deps, looking up the struct clockdomain named by
  131. * clkdm_name and storing the clockdomain pointer in the struct clkdm_dep.
  132. * No return value.
  133. */
  134. static void _resolve_clkdm_deps(struct clockdomain *clkdm,
  135. struct clkdm_dep *clkdm_deps)
  136. {
  137. struct clkdm_dep *cd;
  138. for (cd = clkdm_deps; cd && cd->clkdm_name; cd++) {
  139. if (cd->clkdm)
  140. continue;
  141. cd->clkdm = _clkdm_lookup(cd->clkdm_name);
  142. WARN(!cd->clkdm, "clockdomain: %s: could not find clkdm %s while resolving dependencies - should never happen",
  143. clkdm->name, cd->clkdm_name);
  144. }
  145. }
  146. /**
  147. * _clkdm_add_wkdep - add a wakeup dependency from clkdm2 to clkdm1 (lockless)
  148. * @clkdm1: wake this struct clockdomain * up (dependent)
  149. * @clkdm2: when this struct clockdomain * wakes up (source)
  150. *
  151. * When the clockdomain represented by @clkdm2 wakes up, wake up
  152. * @clkdm1. Implemented in hardware on the OMAP, this feature is
  153. * designed to reduce wakeup latency of the dependent clockdomain @clkdm1.
  154. * Returns -EINVAL if presented with invalid clockdomain pointers,
  155. * -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or 0 upon
  156. * success.
  157. */
  158. static int _clkdm_add_wkdep(struct clockdomain *clkdm1,
  159. struct clockdomain *clkdm2)
  160. {
  161. struct clkdm_dep *cd;
  162. int ret = 0;
  163. if (!clkdm1 || !clkdm2)
  164. return -EINVAL;
  165. cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
  166. if (IS_ERR(cd))
  167. ret = PTR_ERR(cd);
  168. if (!arch_clkdm || !arch_clkdm->clkdm_add_wkdep)
  169. ret = -EINVAL;
  170. if (ret) {
  171. pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n",
  172. clkdm1->name, clkdm2->name);
  173. return ret;
  174. }
  175. cd->wkdep_usecount++;
  176. if (cd->wkdep_usecount == 1) {
  177. pr_debug("clockdomain: hardware will wake up %s when %s wakes up\n",
  178. clkdm1->name, clkdm2->name);
  179. ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2);
  180. }
  181. return ret;
  182. }
  183. /**
  184. * _clkdm_del_wkdep - remove a wakeup dep from clkdm2 to clkdm1 (lockless)
  185. * @clkdm1: wake this struct clockdomain * up (dependent)
  186. * @clkdm2: when this struct clockdomain * wakes up (source)
  187. *
  188. * Remove a wakeup dependency causing @clkdm1 to wake up when @clkdm2
  189. * wakes up. Returns -EINVAL if presented with invalid clockdomain
  190. * pointers, -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or
  191. * 0 upon success.
  192. */
  193. static int _clkdm_del_wkdep(struct clockdomain *clkdm1,
  194. struct clockdomain *clkdm2)
  195. {
  196. struct clkdm_dep *cd;
  197. int ret = 0;
  198. if (!clkdm1 || !clkdm2)
  199. return -EINVAL;
  200. cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
  201. if (IS_ERR(cd))
  202. ret = PTR_ERR(cd);
  203. if (!arch_clkdm || !arch_clkdm->clkdm_del_wkdep)
  204. ret = -EINVAL;
  205. if (ret) {
  206. pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n",
  207. clkdm1->name, clkdm2->name);
  208. return ret;
  209. }
  210. cd->wkdep_usecount--;
  211. if (cd->wkdep_usecount == 0) {
  212. pr_debug("clockdomain: hardware will no longer wake up %s after %s wakes up\n",
  213. clkdm1->name, clkdm2->name);
  214. ret = arch_clkdm->clkdm_del_wkdep(clkdm1, clkdm2);
  215. }
  216. return ret;
  217. }
  218. /**
  219. * _clkdm_add_sleepdep - add a sleep dependency from clkdm2 to clkdm1 (lockless)
  220. * @clkdm1: prevent this struct clockdomain * from sleeping (dependent)
  221. * @clkdm2: when this struct clockdomain * is active (source)
  222. *
  223. * Prevent @clkdm1 from automatically going inactive (and then to
  224. * retention or off) if @clkdm2 is active. Returns -EINVAL if
  225. * presented with invalid clockdomain pointers or called on a machine
  226. * that does not support software-configurable hardware sleep
  227. * dependencies, -ENOENT if the specified dependency cannot be set in
  228. * hardware, or 0 upon success.
  229. */
  230. static int _clkdm_add_sleepdep(struct clockdomain *clkdm1,
  231. struct clockdomain *clkdm2)
  232. {
  233. struct clkdm_dep *cd;
  234. int ret = 0;
  235. if (!clkdm1 || !clkdm2)
  236. return -EINVAL;
  237. cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
  238. if (IS_ERR(cd))
  239. ret = PTR_ERR(cd);
  240. if (!arch_clkdm || !arch_clkdm->clkdm_add_sleepdep)
  241. ret = -EINVAL;
  242. if (ret) {
  243. pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n",
  244. clkdm1->name, clkdm2->name);
  245. return ret;
  246. }
  247. cd->sleepdep_usecount++;
  248. if (cd->sleepdep_usecount == 1) {
  249. pr_debug("clockdomain: will prevent %s from sleeping if %s is active\n",
  250. clkdm1->name, clkdm2->name);
  251. ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2);
  252. }
  253. return ret;
  254. }
  255. /**
  256. * _clkdm_del_sleepdep - remove a sleep dep from clkdm2 to clkdm1 (lockless)
  257. * @clkdm1: prevent this struct clockdomain * from sleeping (dependent)
  258. * @clkdm2: when this struct clockdomain * is active (source)
  259. *
  260. * Allow @clkdm1 to automatically go inactive (and then to retention or
  261. * off), independent of the activity state of @clkdm2. Returns -EINVAL
  262. * if presented with invalid clockdomain pointers or called on a machine
  263. * that does not support software-configurable hardware sleep dependencies,
  264. * -ENOENT if the specified dependency cannot be cleared in hardware, or
  265. * 0 upon success.
  266. */
  267. static int _clkdm_del_sleepdep(struct clockdomain *clkdm1,
  268. struct clockdomain *clkdm2)
  269. {
  270. struct clkdm_dep *cd;
  271. int ret = 0;
  272. if (!clkdm1 || !clkdm2)
  273. return -EINVAL;
  274. cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
  275. if (IS_ERR(cd))
  276. ret = PTR_ERR(cd);
  277. if (!arch_clkdm || !arch_clkdm->clkdm_del_sleepdep)
  278. ret = -EINVAL;
  279. if (ret) {
  280. pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n",
  281. clkdm1->name, clkdm2->name);
  282. return ret;
  283. }
  284. cd->sleepdep_usecount--;
  285. if (cd->sleepdep_usecount == 0) {
  286. pr_debug("clockdomain: will no longer prevent %s from sleeping if %s is active\n",
  287. clkdm1->name, clkdm2->name);
  288. ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2);
  289. }
  290. return ret;
  291. }
  292. /* Public functions */
  293. /**
  294. * clkdm_register_platform_funcs - register clockdomain implementation fns
  295. * @co: func pointers for arch specific implementations
  296. *
  297. * Register the list of function pointers used to implement the
  298. * clockdomain functions on different OMAP SoCs. Should be called
  299. * before any other clkdm_register*() function. Returns -EINVAL if
  300. * @co is null, -EEXIST if platform functions have already been
  301. * registered, or 0 upon success.
  302. */
  303. int clkdm_register_platform_funcs(struct clkdm_ops *co)
  304. {
  305. if (!co)
  306. return -EINVAL;
  307. if (arch_clkdm)
  308. return -EEXIST;
  309. arch_clkdm = co;
  310. return 0;
  311. };
  312. /**
  313. * clkdm_register_clkdms - register SoC clockdomains
  314. * @cs: pointer to an array of struct clockdomain to register
  315. *
  316. * Register the clockdomains available on a particular OMAP SoC. Must
  317. * be called after clkdm_register_platform_funcs(). May be called
  318. * multiple times. Returns -EACCES if called before
  319. * clkdm_register_platform_funcs(); -EINVAL if the argument @cs is
  320. * null; or 0 upon success.
  321. */
  322. int clkdm_register_clkdms(struct clockdomain **cs)
  323. {
  324. struct clockdomain **c = NULL;
  325. if (!arch_clkdm)
  326. return -EACCES;
  327. if (!cs)
  328. return -EINVAL;
  329. for (c = cs; *c; c++)
  330. _clkdm_register(*c);
  331. return 0;
  332. }
  333. /**
  334. * clkdm_register_autodeps - register autodeps (if required)
  335. * @ia: pointer to a static array of struct clkdm_autodep to register
  336. *
  337. * Register clockdomain "automatic dependencies." These are
  338. * clockdomain wakeup and sleep dependencies that are automatically
  339. * added whenever the first clock inside a clockdomain is enabled, and
  340. * removed whenever the last clock inside a clockdomain is disabled.
  341. * These are currently only used on OMAP3 devices, and are deprecated,
  342. * since they waste energy. However, until the OMAP2/3 IP block
  343. * enable/disable sequence can be converted to match the OMAP4
  344. * sequence, they are needed.
  345. *
  346. * Must be called only after all of the SoC clockdomains are
  347. * registered, since the function will resolve autodep clockdomain
  348. * names into clockdomain pointers.
  349. *
  350. * The struct clkdm_autodep @ia array must be static, as this function
  351. * does not copy the array elements.
  352. *
  353. * Returns -EACCES if called before any clockdomains have been
  354. * registered, -EINVAL if called with a null @ia argument, -EEXIST if
  355. * autodeps have already been registered, or 0 upon success.
  356. */
  357. int clkdm_register_autodeps(struct clkdm_autodep *ia)
  358. {
  359. struct clkdm_autodep *a = NULL;
  360. if (list_empty(&clkdm_list))
  361. return -EACCES;
  362. if (!ia)
  363. return -EINVAL;
  364. if (autodeps)
  365. return -EEXIST;
  366. autodeps = ia;
  367. for (a = autodeps; a->clkdm.ptr; a++)
  368. _autodep_lookup(a);
  369. return 0;
  370. }
  371. static int cpu_notifier(struct notifier_block *nb, unsigned long cmd, void *v)
  372. {
  373. switch (cmd) {
  374. case CPU_CLUSTER_PM_ENTER:
  375. if (enable_off_mode)
  376. clkdm_save_context();
  377. break;
  378. case CPU_CLUSTER_PM_EXIT:
  379. if (enable_off_mode)
  380. clkdm_restore_context();
  381. break;
  382. }
  383. return NOTIFY_OK;
  384. }
  385. /**
  386. * clkdm_complete_init - set up the clockdomain layer
  387. *
  388. * Put all clockdomains into software-supervised mode; PM code should
  389. * later enable hardware-supervised mode as appropriate. Must be
  390. * called after clkdm_register_clkdms(). Returns -EACCES if called
  391. * before clkdm_register_clkdms(), or 0 upon success.
  392. */
  393. int clkdm_complete_init(void)
  394. {
  395. struct clockdomain *clkdm;
  396. static struct notifier_block nb;
  397. if (list_empty(&clkdm_list))
  398. return -EACCES;
  399. list_for_each_entry(clkdm, &clkdm_list, node) {
  400. clkdm_deny_idle(clkdm);
  401. _resolve_clkdm_deps(clkdm, clkdm->wkdep_srcs);
  402. clkdm_clear_all_wkdeps(clkdm);
  403. _resolve_clkdm_deps(clkdm, clkdm->sleepdep_srcs);
  404. clkdm_clear_all_sleepdeps(clkdm);
  405. }
  406. /* Only AM43XX can lose clkdm context during rtc-ddr suspend */
  407. if (soc_is_am43xx()) {
  408. nb.notifier_call = cpu_notifier;
  409. cpu_pm_register_notifier(&nb);
  410. }
  411. return 0;
  412. }
  413. /**
  414. * clkdm_lookup - look up a clockdomain by name, return a pointer
  415. * @name: name of clockdomain
  416. *
  417. * Find a registered clockdomain by its name @name. Returns a pointer
  418. * to the struct clockdomain if found, or NULL otherwise.
  419. */
  420. struct clockdomain *clkdm_lookup(const char *name)
  421. {
  422. struct clockdomain *clkdm, *temp_clkdm;
  423. if (!name)
  424. return NULL;
  425. clkdm = NULL;
  426. list_for_each_entry(temp_clkdm, &clkdm_list, node) {
  427. if (!strcmp(name, temp_clkdm->name)) {
  428. clkdm = temp_clkdm;
  429. break;
  430. }
  431. }
  432. return clkdm;
  433. }
  434. /**
  435. * clkdm_for_each - call function on each registered clockdomain
  436. * @fn: callback function *
  437. *
  438. * Call the supplied function @fn for each registered clockdomain.
  439. * The callback function @fn can return anything but 0 to bail
  440. * out early from the iterator. The callback function is called with
  441. * the clkdm_mutex held, so no clockdomain structure manipulation
  442. * functions should be called from the callback, although hardware
  443. * clockdomain control functions are fine. Returns the last return
  444. * value of the callback function, which should be 0 for success or
  445. * anything else to indicate failure; or -EINVAL if the function pointer
  446. * is null.
  447. */
  448. int clkdm_for_each(int (*fn)(struct clockdomain *clkdm, void *user),
  449. void *user)
  450. {
  451. struct clockdomain *clkdm;
  452. int ret = 0;
  453. if (!fn)
  454. return -EINVAL;
  455. list_for_each_entry(clkdm, &clkdm_list, node) {
  456. ret = (*fn)(clkdm, user);
  457. if (ret)
  458. break;
  459. }
  460. return ret;
  461. }
  462. /**
  463. * clkdm_get_pwrdm - return a ptr to the pwrdm that this clkdm resides in
  464. * @clkdm: struct clockdomain *
  465. *
  466. * Return a pointer to the struct powerdomain that the specified clockdomain
  467. * @clkdm exists in, or returns NULL if @clkdm is NULL.
  468. */
  469. struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm)
  470. {
  471. if (!clkdm)
  472. return NULL;
  473. return clkdm->pwrdm.ptr;
  474. }
  475. /* Hardware clockdomain control */
  476. /**
  477. * clkdm_add_wkdep - add a wakeup dependency from clkdm2 to clkdm1
  478. * @clkdm1: wake this struct clockdomain * up (dependent)
  479. * @clkdm2: when this struct clockdomain * wakes up (source)
  480. *
  481. * When the clockdomain represented by @clkdm2 wakes up, wake up
  482. * @clkdm1. Implemented in hardware on the OMAP, this feature is
  483. * designed to reduce wakeup latency of the dependent clockdomain @clkdm1.
  484. * Returns -EINVAL if presented with invalid clockdomain pointers,
  485. * -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or 0 upon
  486. * success.
  487. */
  488. int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
  489. {
  490. struct clkdm_dep *cd;
  491. int ret;
  492. if (!clkdm1 || !clkdm2)
  493. return -EINVAL;
  494. cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
  495. if (IS_ERR(cd))
  496. return PTR_ERR(cd);
  497. pwrdm_lock(cd->clkdm->pwrdm.ptr);
  498. ret = _clkdm_add_wkdep(clkdm1, clkdm2);
  499. pwrdm_unlock(cd->clkdm->pwrdm.ptr);
  500. return ret;
  501. }
  502. /**
  503. * clkdm_del_wkdep - remove a wakeup dependency from clkdm2 to clkdm1
  504. * @clkdm1: wake this struct clockdomain * up (dependent)
  505. * @clkdm2: when this struct clockdomain * wakes up (source)
  506. *
  507. * Remove a wakeup dependency causing @clkdm1 to wake up when @clkdm2
  508. * wakes up. Returns -EINVAL if presented with invalid clockdomain
  509. * pointers, -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or
  510. * 0 upon success.
  511. */
  512. int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
  513. {
  514. struct clkdm_dep *cd;
  515. int ret;
  516. if (!clkdm1 || !clkdm2)
  517. return -EINVAL;
  518. cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
  519. if (IS_ERR(cd))
  520. return PTR_ERR(cd);
  521. pwrdm_lock(cd->clkdm->pwrdm.ptr);
  522. ret = _clkdm_del_wkdep(clkdm1, clkdm2);
  523. pwrdm_unlock(cd->clkdm->pwrdm.ptr);
  524. return ret;
  525. }
  526. /**
  527. * clkdm_read_wkdep - read wakeup dependency state from clkdm2 to clkdm1
  528. * @clkdm1: wake this struct clockdomain * up (dependent)
  529. * @clkdm2: when this struct clockdomain * wakes up (source)
  530. *
  531. * Return 1 if a hardware wakeup dependency exists wherein @clkdm1 will be
  532. * awoken when @clkdm2 wakes up; 0 if dependency is not set; -EINVAL
  533. * if either clockdomain pointer is invalid; or -ENOENT if the hardware
  534. * is incapable.
  535. *
  536. * REVISIT: Currently this function only represents software-controllable
  537. * wakeup dependencies. Wakeup dependencies fixed in hardware are not
  538. * yet handled here.
  539. */
  540. int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
  541. {
  542. struct clkdm_dep *cd;
  543. int ret = 0;
  544. if (!clkdm1 || !clkdm2)
  545. return -EINVAL;
  546. cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
  547. if (IS_ERR(cd))
  548. ret = PTR_ERR(cd);
  549. if (!arch_clkdm || !arch_clkdm->clkdm_read_wkdep)
  550. ret = -EINVAL;
  551. if (ret) {
  552. pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n",
  553. clkdm1->name, clkdm2->name);
  554. return ret;
  555. }
  556. /* XXX It's faster to return the wkdep_usecount */
  557. return arch_clkdm->clkdm_read_wkdep(clkdm1, clkdm2);
  558. }
  559. /**
  560. * clkdm_clear_all_wkdeps - remove all wakeup dependencies from target clkdm
  561. * @clkdm: struct clockdomain * to remove all wakeup dependencies from
  562. *
  563. * Remove all inter-clockdomain wakeup dependencies that could cause
  564. * @clkdm to wake. Intended to be used during boot to initialize the
  565. * PRCM to a known state, after all clockdomains are put into swsup idle
  566. * and woken up. Returns -EINVAL if @clkdm pointer is invalid, or
  567. * 0 upon success.
  568. */
  569. int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
  570. {
  571. if (!clkdm)
  572. return -EINVAL;
  573. if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_wkdeps)
  574. return -EINVAL;
  575. return arch_clkdm->clkdm_clear_all_wkdeps(clkdm);
  576. }
  577. /**
  578. * clkdm_add_sleepdep - add a sleep dependency from clkdm2 to clkdm1
  579. * @clkdm1: prevent this struct clockdomain * from sleeping (dependent)
  580. * @clkdm2: when this struct clockdomain * is active (source)
  581. *
  582. * Prevent @clkdm1 from automatically going inactive (and then to
  583. * retention or off) if @clkdm2 is active. Returns -EINVAL if
  584. * presented with invalid clockdomain pointers or called on a machine
  585. * that does not support software-configurable hardware sleep
  586. * dependencies, -ENOENT if the specified dependency cannot be set in
  587. * hardware, or 0 upon success.
  588. */
  589. int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
  590. {
  591. struct clkdm_dep *cd;
  592. int ret;
  593. if (!clkdm1 || !clkdm2)
  594. return -EINVAL;
  595. cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
  596. if (IS_ERR(cd))
  597. return PTR_ERR(cd);
  598. pwrdm_lock(cd->clkdm->pwrdm.ptr);
  599. ret = _clkdm_add_sleepdep(clkdm1, clkdm2);
  600. pwrdm_unlock(cd->clkdm->pwrdm.ptr);
  601. return ret;
  602. }
  603. /**
  604. * clkdm_del_sleepdep - remove a sleep dependency from clkdm2 to clkdm1
  605. * @clkdm1: prevent this struct clockdomain * from sleeping (dependent)
  606. * @clkdm2: when this struct clockdomain * is active (source)
  607. *
  608. * Allow @clkdm1 to automatically go inactive (and then to retention or
  609. * off), independent of the activity state of @clkdm2. Returns -EINVAL
  610. * if presented with invalid clockdomain pointers or called on a machine
  611. * that does not support software-configurable hardware sleep dependencies,
  612. * -ENOENT if the specified dependency cannot be cleared in hardware, or
  613. * 0 upon success.
  614. */
  615. int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
  616. {
  617. struct clkdm_dep *cd;
  618. int ret;
  619. if (!clkdm1 || !clkdm2)
  620. return -EINVAL;
  621. cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
  622. if (IS_ERR(cd))
  623. return PTR_ERR(cd);
  624. pwrdm_lock(cd->clkdm->pwrdm.ptr);
  625. ret = _clkdm_del_sleepdep(clkdm1, clkdm2);
  626. pwrdm_unlock(cd->clkdm->pwrdm.ptr);
  627. return ret;
  628. }
  629. /**
  630. * clkdm_read_sleepdep - read sleep dependency state from clkdm2 to clkdm1
  631. * @clkdm1: prevent this struct clockdomain * from sleeping (dependent)
  632. * @clkdm2: when this struct clockdomain * is active (source)
  633. *
  634. * Return 1 if a hardware sleep dependency exists wherein @clkdm1 will
  635. * not be allowed to automatically go inactive if @clkdm2 is active;
  636. * 0 if @clkdm1's automatic power state inactivity transition is independent
  637. * of @clkdm2's; -EINVAL if either clockdomain pointer is invalid or called
  638. * on a machine that does not support software-configurable hardware sleep
  639. * dependencies; or -ENOENT if the hardware is incapable.
  640. *
  641. * REVISIT: Currently this function only represents software-controllable
  642. * sleep dependencies. Sleep dependencies fixed in hardware are not
  643. * yet handled here.
  644. */
  645. int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
  646. {
  647. struct clkdm_dep *cd;
  648. int ret = 0;
  649. if (!clkdm1 || !clkdm2)
  650. return -EINVAL;
  651. cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
  652. if (IS_ERR(cd))
  653. ret = PTR_ERR(cd);
  654. if (!arch_clkdm || !arch_clkdm->clkdm_read_sleepdep)
  655. ret = -EINVAL;
  656. if (ret) {
  657. pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n",
  658. clkdm1->name, clkdm2->name);
  659. return ret;
  660. }
  661. /* XXX It's faster to return the sleepdep_usecount */
  662. return arch_clkdm->clkdm_read_sleepdep(clkdm1, clkdm2);
  663. }
  664. /**
  665. * clkdm_clear_all_sleepdeps - remove all sleep dependencies from target clkdm
  666. * @clkdm: struct clockdomain * to remove all sleep dependencies from
  667. *
  668. * Remove all inter-clockdomain sleep dependencies that could prevent
  669. * @clkdm from idling. Intended to be used during boot to initialize the
  670. * PRCM to a known state, after all clockdomains are put into swsup idle
  671. * and woken up. Returns -EINVAL if @clkdm pointer is invalid, or
  672. * 0 upon success.
  673. */
  674. int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
  675. {
  676. if (!clkdm)
  677. return -EINVAL;
  678. if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_sleepdeps)
  679. return -EINVAL;
  680. return arch_clkdm->clkdm_clear_all_sleepdeps(clkdm);
  681. }
  682. /**
  683. * clkdm_sleep_nolock - force clockdomain sleep transition (lockless)
  684. * @clkdm: struct clockdomain *
  685. *
  686. * Instruct the CM to force a sleep transition on the specified
  687. * clockdomain @clkdm. Only for use by the powerdomain code. Returns
  688. * -EINVAL if @clkdm is NULL or if clockdomain does not support
  689. * software-initiated sleep; 0 upon success.
  690. */
  691. int clkdm_sleep_nolock(struct clockdomain *clkdm)
  692. {
  693. int ret;
  694. if (!clkdm)
  695. return -EINVAL;
  696. if (!(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
  697. pr_debug("clockdomain: %s does not support forcing sleep via software\n",
  698. clkdm->name);
  699. return -EINVAL;
  700. }
  701. if (!arch_clkdm || !arch_clkdm->clkdm_sleep)
  702. return -EINVAL;
  703. pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name);
  704. clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
  705. ret = arch_clkdm->clkdm_sleep(clkdm);
  706. ret |= pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
  707. return ret;
  708. }
  709. /**
  710. * clkdm_sleep - force clockdomain sleep transition
  711. * @clkdm: struct clockdomain *
  712. *
  713. * Instruct the CM to force a sleep transition on the specified
  714. * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if
  715. * clockdomain does not support software-initiated sleep; 0 upon
  716. * success.
  717. */
  718. int clkdm_sleep(struct clockdomain *clkdm)
  719. {
  720. int ret;
  721. pwrdm_lock(clkdm->pwrdm.ptr);
  722. ret = clkdm_sleep_nolock(clkdm);
  723. pwrdm_unlock(clkdm->pwrdm.ptr);
  724. return ret;
  725. }
  726. /**
  727. * clkdm_wakeup_nolock - force clockdomain wakeup transition (lockless)
  728. * @clkdm: struct clockdomain *
  729. *
  730. * Instruct the CM to force a wakeup transition on the specified
  731. * clockdomain @clkdm. Only for use by the powerdomain code. Returns
  732. * -EINVAL if @clkdm is NULL or if the clockdomain does not support
  733. * software-controlled wakeup; 0 upon success.
  734. */
  735. int clkdm_wakeup_nolock(struct clockdomain *clkdm)
  736. {
  737. int ret;
  738. if (!clkdm)
  739. return -EINVAL;
  740. if (!(clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) {
  741. pr_debug("clockdomain: %s does not support forcing wakeup via software\n",
  742. clkdm->name);
  743. return -EINVAL;
  744. }
  745. if (!arch_clkdm || !arch_clkdm->clkdm_wakeup)
  746. return -EINVAL;
  747. pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name);
  748. clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
  749. ret = arch_clkdm->clkdm_wakeup(clkdm);
  750. ret |= pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
  751. return ret;
  752. }
  753. /**
  754. * clkdm_wakeup - force clockdomain wakeup transition
  755. * @clkdm: struct clockdomain *
  756. *
  757. * Instruct the CM to force a wakeup transition on the specified
  758. * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if the
  759. * clockdomain does not support software-controlled wakeup; 0 upon
  760. * success.
  761. */
  762. int clkdm_wakeup(struct clockdomain *clkdm)
  763. {
  764. int ret;
  765. pwrdm_lock(clkdm->pwrdm.ptr);
  766. ret = clkdm_wakeup_nolock(clkdm);
  767. pwrdm_unlock(clkdm->pwrdm.ptr);
  768. return ret;
  769. }
  770. /**
  771. * clkdm_allow_idle_nolock - enable hwsup idle transitions for clkdm
  772. * @clkdm: struct clockdomain *
  773. *
  774. * Allow the hardware to automatically switch the clockdomain @clkdm
  775. * into active or idle states, as needed by downstream clocks. If the
  776. * clockdomain has any downstream clocks enabled in the clock
  777. * framework, wkdep/sleepdep autodependencies are added; this is so
  778. * device drivers can read and write to the device. Only for use by
  779. * the powerdomain code. No return value.
  780. */
  781. void clkdm_allow_idle_nolock(struct clockdomain *clkdm)
  782. {
  783. if (!clkdm)
  784. return;
  785. if (!WARN_ON(!clkdm->forcewake_count))
  786. clkdm->forcewake_count--;
  787. if (clkdm->forcewake_count)
  788. return;
  789. if (!clkdm->usecount && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
  790. clkdm_sleep_nolock(clkdm);
  791. if (!(clkdm->flags & CLKDM_CAN_ENABLE_AUTO))
  792. return;
  793. if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING)
  794. return;
  795. if (!arch_clkdm || !arch_clkdm->clkdm_allow_idle)
  796. return;
  797. pr_debug("clockdomain: enabling automatic idle transitions for %s\n",
  798. clkdm->name);
  799. clkdm->_flags |= _CLKDM_FLAG_HWSUP_ENABLED;
  800. arch_clkdm->clkdm_allow_idle(clkdm);
  801. pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
  802. }
  803. /**
  804. * clkdm_allow_idle - enable hwsup idle transitions for clkdm
  805. * @clkdm: struct clockdomain *
  806. *
  807. * Allow the hardware to automatically switch the clockdomain @clkdm into
  808. * active or idle states, as needed by downstream clocks. If the
  809. * clockdomain has any downstream clocks enabled in the clock
  810. * framework, wkdep/sleepdep autodependencies are added; this is so
  811. * device drivers can read and write to the device. No return value.
  812. */
  813. void clkdm_allow_idle(struct clockdomain *clkdm)
  814. {
  815. pwrdm_lock(clkdm->pwrdm.ptr);
  816. clkdm_allow_idle_nolock(clkdm);
  817. pwrdm_unlock(clkdm->pwrdm.ptr);
  818. }
  819. /**
  820. * clkdm_deny_idle - disable hwsup idle transitions for clkdm
  821. * @clkdm: struct clockdomain *
  822. *
  823. * Prevent the hardware from automatically switching the clockdomain
  824. * @clkdm into inactive or idle states. If the clockdomain has
  825. * downstream clocks enabled in the clock framework, wkdep/sleepdep
  826. * autodependencies are removed. Only for use by the powerdomain
  827. * code. No return value.
  828. */
  829. void clkdm_deny_idle_nolock(struct clockdomain *clkdm)
  830. {
  831. if (!clkdm)
  832. return;
  833. if (clkdm->forcewake_count++)
  834. return;
  835. if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
  836. clkdm_wakeup_nolock(clkdm);
  837. if (!(clkdm->flags & CLKDM_CAN_DISABLE_AUTO))
  838. return;
  839. if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING)
  840. return;
  841. if (!arch_clkdm || !arch_clkdm->clkdm_deny_idle)
  842. return;
  843. pr_debug("clockdomain: disabling automatic idle transitions for %s\n",
  844. clkdm->name);
  845. clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
  846. arch_clkdm->clkdm_deny_idle(clkdm);
  847. pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
  848. }
  849. /**
  850. * clkdm_deny_idle - disable hwsup idle transitions for clkdm
  851. * @clkdm: struct clockdomain *
  852. *
  853. * Prevent the hardware from automatically switching the clockdomain
  854. * @clkdm into inactive or idle states. If the clockdomain has
  855. * downstream clocks enabled in the clock framework, wkdep/sleepdep
  856. * autodependencies are removed. No return value.
  857. */
  858. void clkdm_deny_idle(struct clockdomain *clkdm)
  859. {
  860. pwrdm_lock(clkdm->pwrdm.ptr);
  861. clkdm_deny_idle_nolock(clkdm);
  862. pwrdm_unlock(clkdm->pwrdm.ptr);
  863. }
  864. /**
  865. * clkdm_in_hwsup - is clockdomain @clkdm have hardware-supervised idle enabled?
  866. * @clkdm: struct clockdomain *
  867. *
  868. * Returns true if clockdomain @clkdm currently has
  869. * hardware-supervised idle enabled, or false if it does not or if
  870. * @clkdm is NULL. It is only valid to call this function after
  871. * clkdm_init() has been called. This function does not actually read
  872. * bits from the hardware; it instead tests an in-memory flag that is
  873. * changed whenever the clockdomain code changes the auto-idle mode.
  874. */
  875. bool clkdm_in_hwsup(struct clockdomain *clkdm)
  876. {
  877. bool ret;
  878. if (!clkdm)
  879. return false;
  880. ret = (clkdm->_flags & _CLKDM_FLAG_HWSUP_ENABLED) ? true : false;
  881. return ret;
  882. }
  883. /**
  884. * clkdm_missing_idle_reporting - can @clkdm enter autoidle even if in use?
  885. * @clkdm: struct clockdomain *
  886. *
  887. * Returns true if clockdomain @clkdm has the
  888. * CLKDM_MISSING_IDLE_REPORTING flag set, or false if not or @clkdm is
  889. * null. More information is available in the documentation for the
  890. * CLKDM_MISSING_IDLE_REPORTING macro.
  891. */
  892. bool clkdm_missing_idle_reporting(struct clockdomain *clkdm)
  893. {
  894. if (!clkdm)
  895. return false;
  896. return (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) ? true : false;
  897. }
  898. /* Public autodep handling functions (deprecated) */
  899. /**
  900. * clkdm_add_autodeps - add auto sleepdeps/wkdeps to clkdm upon clock enable
  901. * @clkdm: struct clockdomain *
  902. *
  903. * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm'
  904. * in hardware-supervised mode. Meant to be called from clock framework
  905. * when a clock inside clockdomain 'clkdm' is enabled. No return value.
  906. *
  907. * XXX autodeps are deprecated and should be removed at the earliest
  908. * opportunity
  909. */
  910. void clkdm_add_autodeps(struct clockdomain *clkdm)
  911. {
  912. struct clkdm_autodep *autodep;
  913. if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS)
  914. return;
  915. for (autodep = autodeps; autodep->clkdm.ptr; autodep++) {
  916. if (IS_ERR(autodep->clkdm.ptr))
  917. continue;
  918. pr_debug("clockdomain: %s: adding %s sleepdep/wkdep\n",
  919. clkdm->name, autodep->clkdm.ptr->name);
  920. _clkdm_add_sleepdep(clkdm, autodep->clkdm.ptr);
  921. _clkdm_add_wkdep(clkdm, autodep->clkdm.ptr);
  922. }
  923. }
  924. /**
  925. * clkdm_del_autodeps - remove auto sleepdeps/wkdeps from clkdm
  926. * @clkdm: struct clockdomain *
  927. *
  928. * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm'
  929. * in hardware-supervised mode. Meant to be called from clock framework
  930. * when a clock inside clockdomain 'clkdm' is disabled. No return value.
  931. *
  932. * XXX autodeps are deprecated and should be removed at the earliest
  933. * opportunity
  934. */
  935. void clkdm_del_autodeps(struct clockdomain *clkdm)
  936. {
  937. struct clkdm_autodep *autodep;
  938. if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS)
  939. return;
  940. for (autodep = autodeps; autodep->clkdm.ptr; autodep++) {
  941. if (IS_ERR(autodep->clkdm.ptr))
  942. continue;
  943. pr_debug("clockdomain: %s: removing %s sleepdep/wkdep\n",
  944. clkdm->name, autodep->clkdm.ptr->name);
  945. _clkdm_del_sleepdep(clkdm, autodep->clkdm.ptr);
  946. _clkdm_del_wkdep(clkdm, autodep->clkdm.ptr);
  947. }
  948. }
  949. /* Clockdomain-to-clock/hwmod framework interface code */
  950. /**
  951. * clkdm_clk_enable - add an enabled downstream clock to this clkdm
  952. * @clkdm: struct clockdomain *
  953. * @clk: struct clk * of the enabled downstream clock
  954. *
  955. * Increment the usecount of the clockdomain @clkdm and ensure that it
  956. * is awake before @clk is enabled. Intended to be called by
  957. * clk_enable() code. If the clockdomain is in software-supervised
  958. * idle mode, force the clockdomain to wake. If the clockdomain is in
  959. * hardware-supervised idle mode, add clkdm-pwrdm autodependencies, to
  960. * ensure that devices in the clockdomain can be read from/written to
  961. * by on-chip processors. Returns -EINVAL if passed null pointers;
  962. * returns 0 upon success or if the clockdomain is in hwsup idle mode.
  963. */
  964. int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *unused)
  965. {
  966. if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable)
  967. return -EINVAL;
  968. pwrdm_lock(clkdm->pwrdm.ptr);
  969. /*
  970. * For arch's with no autodeps, clkcm_clk_enable
  971. * should be called for every clock instance or hwmod that is
  972. * enabled, so the clkdm can be force woken up.
  973. */
  974. clkdm->usecount++;
  975. if (clkdm->usecount > 1 && autodeps) {
  976. pwrdm_unlock(clkdm->pwrdm.ptr);
  977. return 0;
  978. }
  979. arch_clkdm->clkdm_clk_enable(clkdm);
  980. pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
  981. pwrdm_unlock(clkdm->pwrdm.ptr);
  982. pr_debug("clockdomain: %s: enabled\n", clkdm->name);
  983. return 0;
  984. }
  985. /**
  986. * clkdm_clk_disable - remove an enabled downstream clock from this clkdm
  987. * @clkdm: struct clockdomain *
  988. * @clk: struct clk * of the disabled downstream clock
  989. *
  990. * Decrement the usecount of this clockdomain @clkdm when @clk is
  991. * disabled. Intended to be called by clk_disable() code. If the
  992. * clockdomain usecount goes to 0, put the clockdomain to sleep
  993. * (software-supervised mode) or remove the clkdm autodependencies
  994. * (hardware-supervised mode). Returns -EINVAL if passed null
  995. * pointers; -ERANGE if the @clkdm usecount underflows; or returns 0
  996. * upon success or if the clockdomain is in hwsup idle mode.
  997. */
  998. int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
  999. {
  1000. if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_disable)
  1001. return -EINVAL;
  1002. pwrdm_lock(clkdm->pwrdm.ptr);
  1003. /* corner case: disabling unused clocks */
  1004. if (clk && (__clk_get_enable_count(clk) == 0) && clkdm->usecount == 0)
  1005. goto ccd_exit;
  1006. if (clkdm->usecount == 0) {
  1007. pwrdm_unlock(clkdm->pwrdm.ptr);
  1008. WARN_ON(1); /* underflow */
  1009. return -ERANGE;
  1010. }
  1011. clkdm->usecount--;
  1012. if (clkdm->usecount > 0) {
  1013. pwrdm_unlock(clkdm->pwrdm.ptr);
  1014. return 0;
  1015. }
  1016. arch_clkdm->clkdm_clk_disable(clkdm);
  1017. pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
  1018. pr_debug("clockdomain: %s: disabled\n", clkdm->name);
  1019. ccd_exit:
  1020. pwrdm_unlock(clkdm->pwrdm.ptr);
  1021. return 0;
  1022. }
  1023. /**
  1024. * clkdm_hwmod_enable - add an enabled downstream hwmod to this clkdm
  1025. * @clkdm: struct clockdomain *
  1026. * @oh: struct omap_hwmod * of the enabled downstream hwmod
  1027. *
  1028. * Increment the usecount of the clockdomain @clkdm and ensure that it
  1029. * is awake before @oh is enabled. Intended to be called by
  1030. * module_enable() code.
  1031. * If the clockdomain is in software-supervised idle mode, force the
  1032. * clockdomain to wake. If the clockdomain is in hardware-supervised idle
  1033. * mode, add clkdm-pwrdm autodependencies, to ensure that devices in the
  1034. * clockdomain can be read from/written to by on-chip processors.
  1035. * Returns -EINVAL if passed null pointers;
  1036. * returns 0 upon success or if the clockdomain is in hwsup idle mode.
  1037. */
  1038. int clkdm_hwmod_enable(struct clockdomain *clkdm, struct omap_hwmod *oh)
  1039. {
  1040. /* The clkdm attribute does not exist yet prior OMAP4 */
  1041. if (cpu_is_omap24xx() || cpu_is_omap34xx())
  1042. return 0;
  1043. /*
  1044. * XXX Rewrite this code to maintain a list of enabled
  1045. * downstream hwmods for debugging purposes?
  1046. */
  1047. if (!oh)
  1048. return -EINVAL;
  1049. return clkdm_clk_enable(clkdm, NULL);
  1050. }
  1051. /**
  1052. * clkdm_hwmod_disable - remove an enabled downstream hwmod from this clkdm
  1053. * @clkdm: struct clockdomain *
  1054. * @oh: struct omap_hwmod * of the disabled downstream hwmod
  1055. *
  1056. * Decrement the usecount of this clockdomain @clkdm when @oh is
  1057. * disabled. Intended to be called by module_disable() code.
  1058. * If the clockdomain usecount goes to 0, put the clockdomain to sleep
  1059. * (software-supervised mode) or remove the clkdm autodependencies
  1060. * (hardware-supervised mode).
  1061. * Returns -EINVAL if passed null pointers; -ERANGE if the @clkdm usecount
  1062. * underflows; or returns 0 upon success or if the clockdomain is in hwsup
  1063. * idle mode.
  1064. */
  1065. int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh)
  1066. {
  1067. /* The clkdm attribute does not exist yet prior OMAP4 */
  1068. if (cpu_is_omap24xx() || cpu_is_omap34xx())
  1069. return 0;
  1070. if (!oh)
  1071. return -EINVAL;
  1072. return clkdm_clk_disable(clkdm, NULL);
  1073. }
  1074. /**
  1075. * _clkdm_save_context - save the context for the control of this clkdm
  1076. *
  1077. * Due to a suspend or hibernation operation, the state of the registers
  1078. * controlling this clkdm will be lost, save their context.
  1079. */
  1080. static int _clkdm_save_context(struct clockdomain *clkdm, void *unused)
  1081. {
  1082. if (!arch_clkdm || !arch_clkdm->clkdm_save_context)
  1083. return -EINVAL;
  1084. return arch_clkdm->clkdm_save_context(clkdm);
  1085. }
  1086. /**
  1087. * _clkdm_restore_context - restore context for control of this clkdm
  1088. *
  1089. * Restore the register values for this clockdomain.
  1090. */
  1091. static int _clkdm_restore_context(struct clockdomain *clkdm, void *unused)
  1092. {
  1093. if (!arch_clkdm || !arch_clkdm->clkdm_restore_context)
  1094. return -EINVAL;
  1095. return arch_clkdm->clkdm_restore_context(clkdm);
  1096. }
  1097. /**
  1098. * clkdm_save_context - Saves the context for each registered clkdm
  1099. *
  1100. * Save the context for each registered clockdomain.
  1101. */
  1102. void clkdm_save_context(void)
  1103. {
  1104. clkdm_for_each(_clkdm_save_context, NULL);
  1105. }
  1106. /**
  1107. * clkdm_restore_context - Restores the context for each registered clkdm
  1108. *
  1109. * Restore the context for each registered clockdomain.
  1110. */
  1111. void clkdm_restore_context(void)
  1112. {
  1113. clkdm_for_each(_clkdm_restore_context, NULL);
  1114. }