clockdomain.c 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  1. /*
  2. * OMAP2/3/4 clockdomain framework functions
  3. *
  4. * Copyright (C) 2008-2011 Texas Instruments, Inc.
  5. * Copyright (C) 2008-2011 Nokia Corporation
  6. *
  7. * Written by Paul Walmsley and Jouni Högander
  8. * Added OMAP4 specific support by Abhijit Pagare <abhijitpagare@ti.com>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License version 2 as
  12. * published by the Free Software Foundation.
  13. */
  14. #undef DEBUG
  15. #include <linux/kernel.h>
  16. #include <linux/device.h>
  17. #include <linux/list.h>
  18. #include <linux/errno.h>
  19. #include <linux/string.h>
  20. #include <linux/delay.h>
  21. #include <linux/clk.h>
  22. #include <linux/limits.h>
  23. #include <linux/err.h>
  24. #include <linux/io.h>
  25. #include <linux/bitops.h>
  26. #include <plat/clock.h>
  27. #include "clockdomain.h"
  28. /* clkdm_list contains all registered struct clockdomains */
  29. static LIST_HEAD(clkdm_list);
  30. /* array of clockdomain deps to be added/removed when clkdm in hwsup mode */
  31. static struct clkdm_autodep *autodeps;
  32. static struct clkdm_ops *arch_clkdm;
  33. /* Private functions */
  34. static struct clockdomain *_clkdm_lookup(const char *name)
  35. {
  36. struct clockdomain *clkdm, *temp_clkdm;
  37. if (!name)
  38. return NULL;
  39. clkdm = NULL;
  40. list_for_each_entry(temp_clkdm, &clkdm_list, node) {
  41. if (!strcmp(name, temp_clkdm->name)) {
  42. clkdm = temp_clkdm;
  43. break;
  44. }
  45. }
  46. return clkdm;
  47. }
  48. /**
  49. * _clkdm_register - register a clockdomain
  50. * @clkdm: struct clockdomain * to register
  51. *
  52. * Adds a clockdomain to the internal clockdomain list.
  53. * Returns -EINVAL if given a null pointer, -EEXIST if a clockdomain is
  54. * already registered by the provided name, or 0 upon success.
  55. */
  56. static int _clkdm_register(struct clockdomain *clkdm)
  57. {
  58. struct powerdomain *pwrdm;
  59. if (!clkdm || !clkdm->name)
  60. return -EINVAL;
  61. if (!omap_chip_is(clkdm->omap_chip))
  62. return -EINVAL;
  63. pwrdm = pwrdm_lookup(clkdm->pwrdm.name);
  64. if (!pwrdm) {
  65. pr_err("clockdomain: %s: powerdomain %s does not exist\n",
  66. clkdm->name, clkdm->pwrdm.name);
  67. return -EINVAL;
  68. }
  69. clkdm->pwrdm.ptr = pwrdm;
  70. /* Verify that the clockdomain is not already registered */
  71. if (_clkdm_lookup(clkdm->name))
  72. return -EEXIST;
  73. list_add(&clkdm->node, &clkdm_list);
  74. pwrdm_add_clkdm(pwrdm, clkdm);
  75. spin_lock_init(&clkdm->lock);
  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 || !omap_chip_is(clkdm->omap_chip))
  85. return ERR_PTR(-EINVAL);
  86. for (cd = deps; cd->clkdm_name; cd++) {
  87. if (!omap_chip_is(cd->omap_chip))
  88. continue;
  89. if (!cd->clkdm && cd->clkdm_name)
  90. cd->clkdm = _clkdm_lookup(cd->clkdm_name);
  91. if (cd->clkdm == clkdm)
  92. break;
  93. }
  94. if (!cd->clkdm_name)
  95. return ERR_PTR(-ENOENT);
  96. return cd;
  97. }
  98. /*
  99. * _autodep_lookup - resolve autodep clkdm names to clkdm pointers; store
  100. * @autodep: struct clkdm_autodep * to resolve
  101. *
  102. * Resolve autodep clockdomain names to clockdomain pointers via
  103. * clkdm_lookup() and store the pointers in the autodep structure. An
  104. * "autodep" is a clockdomain sleep/wakeup dependency that is
  105. * automatically added and removed whenever clocks in the associated
  106. * clockdomain are enabled or disabled (respectively) when the
  107. * clockdomain is in hardware-supervised mode. Meant to be called
  108. * once at clockdomain layer initialization, since these should remain
  109. * fixed for a particular architecture. No return value.
  110. *
  111. * XXX autodeps are deprecated and should be removed at the earliest
  112. * opportunity
  113. */
  114. static void _autodep_lookup(struct clkdm_autodep *autodep)
  115. {
  116. struct clockdomain *clkdm;
  117. if (!autodep)
  118. return;
  119. if (!omap_chip_is(autodep->omap_chip))
  120. return;
  121. clkdm = clkdm_lookup(autodep->clkdm.name);
  122. if (!clkdm) {
  123. pr_err("clockdomain: autodeps: clockdomain %s does not exist\n",
  124. autodep->clkdm.name);
  125. clkdm = ERR_PTR(-ENOENT);
  126. }
  127. autodep->clkdm.ptr = clkdm;
  128. }
  129. /*
  130. * _clkdm_add_autodeps - add auto sleepdeps/wkdeps to clkdm upon clock enable
  131. * @clkdm: struct clockdomain *
  132. *
  133. * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm'
  134. * in hardware-supervised mode. Meant to be called from clock framework
  135. * when a clock inside clockdomain 'clkdm' is enabled. No return value.
  136. *
  137. * XXX autodeps are deprecated and should be removed at the earliest
  138. * opportunity
  139. */
  140. void _clkdm_add_autodeps(struct clockdomain *clkdm)
  141. {
  142. struct clkdm_autodep *autodep;
  143. if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS)
  144. return;
  145. for (autodep = autodeps; autodep->clkdm.ptr; autodep++) {
  146. if (IS_ERR(autodep->clkdm.ptr))
  147. continue;
  148. if (!omap_chip_is(autodep->omap_chip))
  149. continue;
  150. pr_debug("clockdomain: adding %s sleepdep/wkdep for "
  151. "clkdm %s\n", autodep->clkdm.ptr->name,
  152. clkdm->name);
  153. clkdm_add_sleepdep(clkdm, autodep->clkdm.ptr);
  154. clkdm_add_wkdep(clkdm, autodep->clkdm.ptr);
  155. }
  156. }
  157. /*
  158. * _clkdm_add_autodeps - remove auto sleepdeps/wkdeps from clkdm
  159. * @clkdm: struct clockdomain *
  160. *
  161. * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm'
  162. * in hardware-supervised mode. Meant to be called from clock framework
  163. * when a clock inside clockdomain 'clkdm' is disabled. No return value.
  164. *
  165. * XXX autodeps are deprecated and should be removed at the earliest
  166. * opportunity
  167. */
  168. void _clkdm_del_autodeps(struct clockdomain *clkdm)
  169. {
  170. struct clkdm_autodep *autodep;
  171. if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS)
  172. return;
  173. for (autodep = autodeps; autodep->clkdm.ptr; autodep++) {
  174. if (IS_ERR(autodep->clkdm.ptr))
  175. continue;
  176. if (!omap_chip_is(autodep->omap_chip))
  177. continue;
  178. pr_debug("clockdomain: removing %s sleepdep/wkdep for "
  179. "clkdm %s\n", autodep->clkdm.ptr->name,
  180. clkdm->name);
  181. clkdm_del_sleepdep(clkdm, autodep->clkdm.ptr);
  182. clkdm_del_wkdep(clkdm, autodep->clkdm.ptr);
  183. }
  184. }
  185. /**
  186. * _resolve_clkdm_deps() - resolve clkdm_names in @clkdm_deps to clkdms
  187. * @clkdm: clockdomain that we are resolving dependencies for
  188. * @clkdm_deps: ptr to array of struct clkdm_deps to resolve
  189. *
  190. * Iterates through @clkdm_deps, looking up the struct clockdomain named by
  191. * clkdm_name and storing the clockdomain pointer in the struct clkdm_dep.
  192. * No return value.
  193. */
  194. static void _resolve_clkdm_deps(struct clockdomain *clkdm,
  195. struct clkdm_dep *clkdm_deps)
  196. {
  197. struct clkdm_dep *cd;
  198. for (cd = clkdm_deps; cd && cd->clkdm_name; cd++) {
  199. if (!omap_chip_is(cd->omap_chip))
  200. continue;
  201. if (cd->clkdm)
  202. continue;
  203. cd->clkdm = _clkdm_lookup(cd->clkdm_name);
  204. WARN(!cd->clkdm, "clockdomain: %s: could not find clkdm %s while resolving dependencies - should never happen",
  205. clkdm->name, cd->clkdm_name);
  206. }
  207. }
  208. /* Public functions */
  209. /**
  210. * clkdm_init - set up the clockdomain layer
  211. * @clkdms: optional pointer to an array of clockdomains to register
  212. * @init_autodeps: optional pointer to an array of autodeps to register
  213. * @custom_funcs: func pointers for arch specific implementations
  214. *
  215. * Set up internal state. If a pointer to an array of clockdomains
  216. * @clkdms was supplied, loop through the list of clockdomains,
  217. * register all that are available on the current platform. Similarly,
  218. * if a pointer to an array of clockdomain autodependencies
  219. * @init_autodeps was provided, register those. No return value.
  220. */
  221. void clkdm_init(struct clockdomain **clkdms,
  222. struct clkdm_autodep *init_autodeps,
  223. struct clkdm_ops *custom_funcs)
  224. {
  225. struct clockdomain **c = NULL;
  226. struct clockdomain *clkdm;
  227. struct clkdm_autodep *autodep = NULL;
  228. if (!custom_funcs)
  229. WARN(1, "No custom clkdm functions registered\n");
  230. else
  231. arch_clkdm = custom_funcs;
  232. if (clkdms)
  233. for (c = clkdms; *c; c++)
  234. _clkdm_register(*c);
  235. autodeps = init_autodeps;
  236. if (autodeps)
  237. for (autodep = autodeps; autodep->clkdm.ptr; autodep++)
  238. _autodep_lookup(autodep);
  239. /*
  240. * Put all clockdomains into software-supervised mode; PM code
  241. * should later enable hardware-supervised mode as appropriate
  242. */
  243. list_for_each_entry(clkdm, &clkdm_list, node) {
  244. if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
  245. clkdm_wakeup(clkdm);
  246. else if (clkdm->flags & CLKDM_CAN_DISABLE_AUTO)
  247. clkdm_deny_idle(clkdm);
  248. _resolve_clkdm_deps(clkdm, clkdm->wkdep_srcs);
  249. clkdm_clear_all_wkdeps(clkdm);
  250. _resolve_clkdm_deps(clkdm, clkdm->sleepdep_srcs);
  251. clkdm_clear_all_sleepdeps(clkdm);
  252. }
  253. }
  254. /**
  255. * clkdm_lookup - look up a clockdomain by name, return a pointer
  256. * @name: name of clockdomain
  257. *
  258. * Find a registered clockdomain by its name @name. Returns a pointer
  259. * to the struct clockdomain if found, or NULL otherwise.
  260. */
  261. struct clockdomain *clkdm_lookup(const char *name)
  262. {
  263. struct clockdomain *clkdm, *temp_clkdm;
  264. if (!name)
  265. return NULL;
  266. clkdm = NULL;
  267. list_for_each_entry(temp_clkdm, &clkdm_list, node) {
  268. if (!strcmp(name, temp_clkdm->name)) {
  269. clkdm = temp_clkdm;
  270. break;
  271. }
  272. }
  273. return clkdm;
  274. }
  275. /**
  276. * clkdm_for_each - call function on each registered clockdomain
  277. * @fn: callback function *
  278. *
  279. * Call the supplied function @fn for each registered clockdomain.
  280. * The callback function @fn can return anything but 0 to bail
  281. * out early from the iterator. The callback function is called with
  282. * the clkdm_mutex held, so no clockdomain structure manipulation
  283. * functions should be called from the callback, although hardware
  284. * clockdomain control functions are fine. Returns the last return
  285. * value of the callback function, which should be 0 for success or
  286. * anything else to indicate failure; or -EINVAL if the function pointer
  287. * is null.
  288. */
  289. int clkdm_for_each(int (*fn)(struct clockdomain *clkdm, void *user),
  290. void *user)
  291. {
  292. struct clockdomain *clkdm;
  293. int ret = 0;
  294. if (!fn)
  295. return -EINVAL;
  296. list_for_each_entry(clkdm, &clkdm_list, node) {
  297. ret = (*fn)(clkdm, user);
  298. if (ret)
  299. break;
  300. }
  301. return ret;
  302. }
  303. /**
  304. * clkdm_get_pwrdm - return a ptr to the pwrdm that this clkdm resides in
  305. * @clkdm: struct clockdomain *
  306. *
  307. * Return a pointer to the struct powerdomain that the specified clockdomain
  308. * @clkdm exists in, or returns NULL if @clkdm is NULL.
  309. */
  310. struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm)
  311. {
  312. if (!clkdm)
  313. return NULL;
  314. return clkdm->pwrdm.ptr;
  315. }
  316. /* Hardware clockdomain control */
  317. /**
  318. * clkdm_add_wkdep - add a wakeup dependency from clkdm2 to clkdm1
  319. * @clkdm1: wake this struct clockdomain * up (dependent)
  320. * @clkdm2: when this struct clockdomain * wakes up (source)
  321. *
  322. * When the clockdomain represented by @clkdm2 wakes up, wake up
  323. * @clkdm1. Implemented in hardware on the OMAP, this feature is
  324. * designed to reduce wakeup latency of the dependent clockdomain @clkdm1.
  325. * Returns -EINVAL if presented with invalid clockdomain pointers,
  326. * -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or 0 upon
  327. * success.
  328. */
  329. int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
  330. {
  331. struct clkdm_dep *cd;
  332. int ret = 0;
  333. if (!clkdm1 || !clkdm2)
  334. return -EINVAL;
  335. cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
  336. if (IS_ERR(cd))
  337. ret = PTR_ERR(cd);
  338. if (!arch_clkdm || !arch_clkdm->clkdm_add_wkdep)
  339. ret = -EINVAL;
  340. if (ret) {
  341. pr_debug("clockdomain: hardware cannot set/clear wake up of "
  342. "%s when %s wakes up\n", clkdm1->name, clkdm2->name);
  343. return ret;
  344. }
  345. if (atomic_inc_return(&cd->wkdep_usecount) == 1) {
  346. pr_debug("clockdomain: hardware will wake up %s when %s wakes "
  347. "up\n", clkdm1->name, clkdm2->name);
  348. ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2);
  349. }
  350. return ret;
  351. }
  352. /**
  353. * clkdm_del_wkdep - remove a wakeup dependency from clkdm2 to clkdm1
  354. * @clkdm1: wake this struct clockdomain * up (dependent)
  355. * @clkdm2: when this struct clockdomain * wakes up (source)
  356. *
  357. * Remove a wakeup dependency causing @clkdm1 to wake up when @clkdm2
  358. * wakes up. Returns -EINVAL if presented with invalid clockdomain
  359. * pointers, -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or
  360. * 0 upon success.
  361. */
  362. int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
  363. {
  364. struct clkdm_dep *cd;
  365. int ret = 0;
  366. if (!clkdm1 || !clkdm2)
  367. return -EINVAL;
  368. cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
  369. if (IS_ERR(cd))
  370. ret = PTR_ERR(cd);
  371. if (!arch_clkdm || !arch_clkdm->clkdm_del_wkdep)
  372. ret = -EINVAL;
  373. if (ret) {
  374. pr_debug("clockdomain: hardware cannot set/clear wake up of "
  375. "%s when %s wakes up\n", clkdm1->name, clkdm2->name);
  376. return ret;
  377. }
  378. if (atomic_dec_return(&cd->wkdep_usecount) == 0) {
  379. pr_debug("clockdomain: hardware will no longer wake up %s "
  380. "after %s wakes up\n", clkdm1->name, clkdm2->name);
  381. ret = arch_clkdm->clkdm_del_wkdep(clkdm1, clkdm2);
  382. }
  383. return ret;
  384. }
  385. /**
  386. * clkdm_read_wkdep - read wakeup dependency state from clkdm2 to clkdm1
  387. * @clkdm1: wake this struct clockdomain * up (dependent)
  388. * @clkdm2: when this struct clockdomain * wakes up (source)
  389. *
  390. * Return 1 if a hardware wakeup dependency exists wherein @clkdm1 will be
  391. * awoken when @clkdm2 wakes up; 0 if dependency is not set; -EINVAL
  392. * if either clockdomain pointer is invalid; or -ENOENT if the hardware
  393. * is incapable.
  394. *
  395. * REVISIT: Currently this function only represents software-controllable
  396. * wakeup dependencies. Wakeup dependencies fixed in hardware are not
  397. * yet handled here.
  398. */
  399. int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
  400. {
  401. struct clkdm_dep *cd;
  402. int ret = 0;
  403. if (!clkdm1 || !clkdm2)
  404. return -EINVAL;
  405. cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
  406. if (IS_ERR(cd))
  407. ret = PTR_ERR(cd);
  408. if (!arch_clkdm || !arch_clkdm->clkdm_read_wkdep)
  409. ret = -EINVAL;
  410. if (ret) {
  411. pr_debug("clockdomain: hardware cannot set/clear wake up of "
  412. "%s when %s wakes up\n", clkdm1->name, clkdm2->name);
  413. return ret;
  414. }
  415. /* XXX It's faster to return the atomic wkdep_usecount */
  416. return arch_clkdm->clkdm_read_wkdep(clkdm1, clkdm2);
  417. }
  418. /**
  419. * clkdm_clear_all_wkdeps - remove all wakeup dependencies from target clkdm
  420. * @clkdm: struct clockdomain * to remove all wakeup dependencies from
  421. *
  422. * Remove all inter-clockdomain wakeup dependencies that could cause
  423. * @clkdm to wake. Intended to be used during boot to initialize the
  424. * PRCM to a known state, after all clockdomains are put into swsup idle
  425. * and woken up. Returns -EINVAL if @clkdm pointer is invalid, or
  426. * 0 upon success.
  427. */
  428. int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
  429. {
  430. if (!clkdm)
  431. return -EINVAL;
  432. if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_wkdeps)
  433. return -EINVAL;
  434. return arch_clkdm->clkdm_clear_all_wkdeps(clkdm);
  435. }
  436. /**
  437. * clkdm_add_sleepdep - add a sleep dependency from clkdm2 to clkdm1
  438. * @clkdm1: prevent this struct clockdomain * from sleeping (dependent)
  439. * @clkdm2: when this struct clockdomain * is active (source)
  440. *
  441. * Prevent @clkdm1 from automatically going inactive (and then to
  442. * retention or off) if @clkdm2 is active. Returns -EINVAL if
  443. * presented with invalid clockdomain pointers or called on a machine
  444. * that does not support software-configurable hardware sleep
  445. * dependencies, -ENOENT if the specified dependency cannot be set in
  446. * hardware, or 0 upon success.
  447. */
  448. int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
  449. {
  450. struct clkdm_dep *cd;
  451. int ret = 0;
  452. if (!clkdm1 || !clkdm2)
  453. return -EINVAL;
  454. cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
  455. if (IS_ERR(cd))
  456. ret = PTR_ERR(cd);
  457. if (!arch_clkdm || !arch_clkdm->clkdm_add_sleepdep)
  458. ret = -EINVAL;
  459. if (ret) {
  460. pr_debug("clockdomain: hardware cannot set/clear sleep "
  461. "dependency affecting %s from %s\n", clkdm1->name,
  462. clkdm2->name);
  463. return ret;
  464. }
  465. if (atomic_inc_return(&cd->sleepdep_usecount) == 1) {
  466. pr_debug("clockdomain: will prevent %s from sleeping if %s "
  467. "is active\n", clkdm1->name, clkdm2->name);
  468. ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2);
  469. }
  470. return ret;
  471. }
  472. /**
  473. * clkdm_del_sleepdep - remove a sleep dependency from clkdm2 to clkdm1
  474. * @clkdm1: prevent this struct clockdomain * from sleeping (dependent)
  475. * @clkdm2: when this struct clockdomain * is active (source)
  476. *
  477. * Allow @clkdm1 to automatically go inactive (and then to retention or
  478. * off), independent of the activity state of @clkdm2. Returns -EINVAL
  479. * if presented with invalid clockdomain pointers or called on a machine
  480. * that does not support software-configurable hardware sleep dependencies,
  481. * -ENOENT if the specified dependency cannot be cleared in hardware, or
  482. * 0 upon success.
  483. */
  484. int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
  485. {
  486. struct clkdm_dep *cd;
  487. int ret = 0;
  488. if (!clkdm1 || !clkdm2)
  489. return -EINVAL;
  490. cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
  491. if (IS_ERR(cd))
  492. ret = PTR_ERR(cd);
  493. if (!arch_clkdm || !arch_clkdm->clkdm_del_sleepdep)
  494. ret = -EINVAL;
  495. if (ret) {
  496. pr_debug("clockdomain: hardware cannot set/clear sleep "
  497. "dependency affecting %s from %s\n", clkdm1->name,
  498. clkdm2->name);
  499. return ret;
  500. }
  501. if (atomic_dec_return(&cd->sleepdep_usecount) == 0) {
  502. pr_debug("clockdomain: will no longer prevent %s from "
  503. "sleeping if %s is active\n", clkdm1->name,
  504. clkdm2->name);
  505. ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2);
  506. }
  507. return ret;
  508. }
  509. /**
  510. * clkdm_read_sleepdep - read sleep dependency state from clkdm2 to clkdm1
  511. * @clkdm1: prevent this struct clockdomain * from sleeping (dependent)
  512. * @clkdm2: when this struct clockdomain * is active (source)
  513. *
  514. * Return 1 if a hardware sleep dependency exists wherein @clkdm1 will
  515. * not be allowed to automatically go inactive if @clkdm2 is active;
  516. * 0 if @clkdm1's automatic power state inactivity transition is independent
  517. * of @clkdm2's; -EINVAL if either clockdomain pointer is invalid or called
  518. * on a machine that does not support software-configurable hardware sleep
  519. * dependencies; or -ENOENT if the hardware is incapable.
  520. *
  521. * REVISIT: Currently this function only represents software-controllable
  522. * sleep dependencies. Sleep dependencies fixed in hardware are not
  523. * yet handled here.
  524. */
  525. int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
  526. {
  527. struct clkdm_dep *cd;
  528. int ret = 0;
  529. if (!clkdm1 || !clkdm2)
  530. return -EINVAL;
  531. cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
  532. if (IS_ERR(cd))
  533. ret = PTR_ERR(cd);
  534. if (!arch_clkdm || !arch_clkdm->clkdm_read_sleepdep)
  535. ret = -EINVAL;
  536. if (ret) {
  537. pr_debug("clockdomain: hardware cannot set/clear sleep "
  538. "dependency affecting %s from %s\n", clkdm1->name,
  539. clkdm2->name);
  540. return ret;
  541. }
  542. /* XXX It's faster to return the atomic sleepdep_usecount */
  543. return arch_clkdm->clkdm_read_sleepdep(clkdm1, clkdm2);
  544. }
  545. /**
  546. * clkdm_clear_all_sleepdeps - remove all sleep dependencies from target clkdm
  547. * @clkdm: struct clockdomain * to remove all sleep dependencies from
  548. *
  549. * Remove all inter-clockdomain sleep dependencies that could prevent
  550. * @clkdm from idling. Intended to be used during boot to initialize the
  551. * PRCM to a known state, after all clockdomains are put into swsup idle
  552. * and woken up. Returns -EINVAL if @clkdm pointer is invalid, or
  553. * 0 upon success.
  554. */
  555. int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
  556. {
  557. if (!clkdm)
  558. return -EINVAL;
  559. if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_sleepdeps)
  560. return -EINVAL;
  561. return arch_clkdm->clkdm_clear_all_sleepdeps(clkdm);
  562. }
  563. /**
  564. * clkdm_sleep - force clockdomain sleep transition
  565. * @clkdm: struct clockdomain *
  566. *
  567. * Instruct the CM to force a sleep transition on the specified
  568. * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if
  569. * clockdomain does not support software-initiated sleep; 0 upon
  570. * success.
  571. */
  572. int clkdm_sleep(struct clockdomain *clkdm)
  573. {
  574. int ret;
  575. unsigned long flags;
  576. if (!clkdm)
  577. return -EINVAL;
  578. if (!(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
  579. pr_debug("clockdomain: %s does not support forcing "
  580. "sleep via software\n", clkdm->name);
  581. return -EINVAL;
  582. }
  583. if (!arch_clkdm || !arch_clkdm->clkdm_sleep)
  584. return -EINVAL;
  585. pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name);
  586. spin_lock_irqsave(&clkdm->lock, flags);
  587. clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
  588. ret = arch_clkdm->clkdm_sleep(clkdm);
  589. spin_unlock_irqrestore(&clkdm->lock, flags);
  590. return ret;
  591. }
  592. /**
  593. * clkdm_wakeup - force clockdomain wakeup transition
  594. * @clkdm: struct clockdomain *
  595. *
  596. * Instruct the CM to force a wakeup transition on the specified
  597. * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if the
  598. * clockdomain does not support software-controlled wakeup; 0 upon
  599. * success.
  600. */
  601. int clkdm_wakeup(struct clockdomain *clkdm)
  602. {
  603. int ret;
  604. unsigned long flags;
  605. if (!clkdm)
  606. return -EINVAL;
  607. if (!(clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) {
  608. pr_debug("clockdomain: %s does not support forcing "
  609. "wakeup via software\n", clkdm->name);
  610. return -EINVAL;
  611. }
  612. if (!arch_clkdm || !arch_clkdm->clkdm_wakeup)
  613. return -EINVAL;
  614. pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name);
  615. spin_lock_irqsave(&clkdm->lock, flags);
  616. clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
  617. ret = arch_clkdm->clkdm_wakeup(clkdm);
  618. ret |= pwrdm_state_switch(clkdm->pwrdm.ptr);
  619. spin_unlock_irqrestore(&clkdm->lock, flags);
  620. return ret;
  621. }
  622. /**
  623. * clkdm_allow_idle - enable hwsup idle transitions for clkdm
  624. * @clkdm: struct clockdomain *
  625. *
  626. * Allow the hardware to automatically switch the clockdomain @clkdm into
  627. * active or idle states, as needed by downstream clocks. If the
  628. * clockdomain has any downstream clocks enabled in the clock
  629. * framework, wkdep/sleepdep autodependencies are added; this is so
  630. * device drivers can read and write to the device. No return value.
  631. */
  632. void clkdm_allow_idle(struct clockdomain *clkdm)
  633. {
  634. unsigned long flags;
  635. if (!clkdm)
  636. return;
  637. if (!(clkdm->flags & CLKDM_CAN_ENABLE_AUTO)) {
  638. pr_debug("clock: automatic idle transitions cannot be enabled "
  639. "on clockdomain %s\n", clkdm->name);
  640. return;
  641. }
  642. if (!arch_clkdm || !arch_clkdm->clkdm_allow_idle)
  643. return;
  644. pr_debug("clockdomain: enabling automatic idle transitions for %s\n",
  645. clkdm->name);
  646. spin_lock_irqsave(&clkdm->lock, flags);
  647. clkdm->_flags |= _CLKDM_FLAG_HWSUP_ENABLED;
  648. arch_clkdm->clkdm_allow_idle(clkdm);
  649. pwrdm_clkdm_state_switch(clkdm);
  650. spin_unlock_irqrestore(&clkdm->lock, flags);
  651. }
  652. /**
  653. * clkdm_deny_idle - disable hwsup idle transitions for clkdm
  654. * @clkdm: struct clockdomain *
  655. *
  656. * Prevent the hardware from automatically switching the clockdomain
  657. * @clkdm into inactive or idle states. If the clockdomain has
  658. * downstream clocks enabled in the clock framework, wkdep/sleepdep
  659. * autodependencies are removed. No return value.
  660. */
  661. void clkdm_deny_idle(struct clockdomain *clkdm)
  662. {
  663. unsigned long flags;
  664. if (!clkdm)
  665. return;
  666. if (!(clkdm->flags & CLKDM_CAN_DISABLE_AUTO)) {
  667. pr_debug("clockdomain: automatic idle transitions cannot be "
  668. "disabled on %s\n", clkdm->name);
  669. return;
  670. }
  671. if (!arch_clkdm || !arch_clkdm->clkdm_deny_idle)
  672. return;
  673. pr_debug("clockdomain: disabling automatic idle transitions for %s\n",
  674. clkdm->name);
  675. spin_lock_irqsave(&clkdm->lock, flags);
  676. clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
  677. arch_clkdm->clkdm_deny_idle(clkdm);
  678. pwrdm_state_switch(clkdm->pwrdm.ptr);
  679. spin_unlock_irqrestore(&clkdm->lock, flags);
  680. }
  681. /**
  682. * clkdm_in_hwsup - is clockdomain @clkdm have hardware-supervised idle enabled?
  683. * @clkdm: struct clockdomain *
  684. *
  685. * Returns true if clockdomain @clkdm currently has
  686. * hardware-supervised idle enabled, or false if it does not or if
  687. * @clkdm is NULL. It is only valid to call this function after
  688. * clkdm_init() has been called. This function does not actually read
  689. * bits from the hardware; it instead tests an in-memory flag that is
  690. * changed whenever the clockdomain code changes the auto-idle mode.
  691. */
  692. bool clkdm_in_hwsup(struct clockdomain *clkdm)
  693. {
  694. bool ret;
  695. unsigned long flags;
  696. if (!clkdm)
  697. return false;
  698. spin_lock_irqsave(&clkdm->lock, flags);
  699. ret = (clkdm->_flags & _CLKDM_FLAG_HWSUP_ENABLED) ? true : false;
  700. spin_unlock_irqrestore(&clkdm->lock, flags);
  701. return ret;
  702. }
  703. /* Clockdomain-to-clock/hwmod framework interface code */
  704. static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm)
  705. {
  706. unsigned long flags;
  707. if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable)
  708. return -EINVAL;
  709. /*
  710. * For arch's with no autodeps, clkcm_clk_enable
  711. * should be called for every clock instance or hwmod that is
  712. * enabled, so the clkdm can be force woken up.
  713. */
  714. if ((atomic_inc_return(&clkdm->usecount) > 1) && autodeps)
  715. return 0;
  716. spin_lock_irqsave(&clkdm->lock, flags);
  717. arch_clkdm->clkdm_clk_enable(clkdm);
  718. pwrdm_wait_transition(clkdm->pwrdm.ptr);
  719. pwrdm_clkdm_state_switch(clkdm);
  720. spin_unlock_irqrestore(&clkdm->lock, flags);
  721. pr_debug("clockdomain: clkdm %s: enabled\n", clkdm->name);
  722. return 0;
  723. }
  724. static int _clkdm_clk_hwmod_disable(struct clockdomain *clkdm)
  725. {
  726. unsigned long flags;
  727. if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_disable)
  728. return -EINVAL;
  729. if (atomic_read(&clkdm->usecount) == 0) {
  730. WARN_ON(1); /* underflow */
  731. return -ERANGE;
  732. }
  733. if (atomic_dec_return(&clkdm->usecount) > 0)
  734. return 0;
  735. spin_lock_irqsave(&clkdm->lock, flags);
  736. arch_clkdm->clkdm_clk_disable(clkdm);
  737. pwrdm_clkdm_state_switch(clkdm);
  738. spin_unlock_irqrestore(&clkdm->lock, flags);
  739. pr_debug("clockdomain: clkdm %s: disabled\n", clkdm->name);
  740. return 0;
  741. }
  742. /**
  743. * clkdm_clk_enable - add an enabled downstream clock to this clkdm
  744. * @clkdm: struct clockdomain *
  745. * @clk: struct clk * of the enabled downstream clock
  746. *
  747. * Increment the usecount of the clockdomain @clkdm and ensure that it
  748. * is awake before @clk is enabled. Intended to be called by
  749. * clk_enable() code. If the clockdomain is in software-supervised
  750. * idle mode, force the clockdomain to wake. If the clockdomain is in
  751. * hardware-supervised idle mode, add clkdm-pwrdm autodependencies, to
  752. * ensure that devices in the clockdomain can be read from/written to
  753. * by on-chip processors. Returns -EINVAL if passed null pointers;
  754. * returns 0 upon success or if the clockdomain is in hwsup idle mode.
  755. */
  756. int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
  757. {
  758. /*
  759. * XXX Rewrite this code to maintain a list of enabled
  760. * downstream clocks for debugging purposes?
  761. */
  762. if (!clk)
  763. return -EINVAL;
  764. return _clkdm_clk_hwmod_enable(clkdm);
  765. }
  766. /**
  767. * clkdm_clk_disable - remove an enabled downstream clock from this clkdm
  768. * @clkdm: struct clockdomain *
  769. * @clk: struct clk * of the disabled downstream clock
  770. *
  771. * Decrement the usecount of this clockdomain @clkdm when @clk is
  772. * disabled. Intended to be called by clk_disable() code. If the
  773. * clockdomain usecount goes to 0, put the clockdomain to sleep
  774. * (software-supervised mode) or remove the clkdm autodependencies
  775. * (hardware-supervised mode). Returns -EINVAL if passed null
  776. * pointers; -ERANGE if the @clkdm usecount underflows; or returns 0
  777. * upon success or if the clockdomain is in hwsup idle mode.
  778. */
  779. int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
  780. {
  781. /*
  782. * XXX Rewrite this code to maintain a list of enabled
  783. * downstream clocks for debugging purposes?
  784. */
  785. if (!clk)
  786. return -EINVAL;
  787. return _clkdm_clk_hwmod_disable(clkdm);
  788. }
  789. /**
  790. * clkdm_hwmod_enable - add an enabled downstream hwmod to this clkdm
  791. * @clkdm: struct clockdomain *
  792. * @oh: struct omap_hwmod * of the enabled downstream hwmod
  793. *
  794. * Increment the usecount of the clockdomain @clkdm and ensure that it
  795. * is awake before @oh is enabled. Intended to be called by
  796. * module_enable() code.
  797. * If the clockdomain is in software-supervised idle mode, force the
  798. * clockdomain to wake. If the clockdomain is in hardware-supervised idle
  799. * mode, add clkdm-pwrdm autodependencies, to ensure that devices in the
  800. * clockdomain can be read from/written to by on-chip processors.
  801. * Returns -EINVAL if passed null pointers;
  802. * returns 0 upon success or if the clockdomain is in hwsup idle mode.
  803. */
  804. int clkdm_hwmod_enable(struct clockdomain *clkdm, struct omap_hwmod *oh)
  805. {
  806. /* The clkdm attribute does not exist yet prior OMAP4 */
  807. if (cpu_is_omap24xx() || cpu_is_omap34xx())
  808. return 0;
  809. /*
  810. * XXX Rewrite this code to maintain a list of enabled
  811. * downstream hwmods for debugging purposes?
  812. */
  813. if (!oh)
  814. return -EINVAL;
  815. return _clkdm_clk_hwmod_enable(clkdm);
  816. }
  817. /**
  818. * clkdm_hwmod_disable - remove an enabled downstream hwmod from this clkdm
  819. * @clkdm: struct clockdomain *
  820. * @oh: struct omap_hwmod * of the disabled downstream hwmod
  821. *
  822. * Decrement the usecount of this clockdomain @clkdm when @oh is
  823. * disabled. Intended to be called by module_disable() code.
  824. * If the clockdomain usecount goes to 0, put the clockdomain to sleep
  825. * (software-supervised mode) or remove the clkdm autodependencies
  826. * (hardware-supervised mode).
  827. * Returns -EINVAL if passed null pointers; -ERANGE if the @clkdm usecount
  828. * underflows; or returns 0 upon success or if the clockdomain is in hwsup
  829. * idle mode.
  830. */
  831. int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh)
  832. {
  833. /* The clkdm attribute does not exist yet prior OMAP4 */
  834. if (cpu_is_omap24xx() || cpu_is_omap34xx())
  835. return 0;
  836. /*
  837. * XXX Rewrite this code to maintain a list of enabled
  838. * downstream hwmods for debugging purposes?
  839. */
  840. if (!oh)
  841. return -EINVAL;
  842. return _clkdm_clk_hwmod_disable(clkdm);
  843. }