PageRenderTime 165ms CodeModel.GetById 38ms RepoModel.GetById 0ms app.codeStats 0ms

/drivers/dsp/bridge/services/clk.c

https://github.com/galaxyishere/samsung-kernel-latona
C | 320 lines | 201 code | 44 blank | 75 comment | 28 complexity | 646bb835c437943f7a46d4b4ca8664db MD5 | raw file
  1. /*
  2. * clk.c
  3. *
  4. * DSP-BIOS Bridge driver support functions for TI OMAP processors.
  5. *
  6. * Clock and Timer services.
  7. *
  8. * Copyright (C) 2005-2006 Texas Instruments, Inc.
  9. *
  10. * This package 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. * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  15. * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  16. * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  17. */
  18. /* ----------------------------------- Host OS */
  19. #include <dspbridge/host_os.h>
  20. /* ----------------------------------- DSP/BIOS Bridge */
  21. #include <dspbridge/std.h>
  22. #include <dspbridge/dbdefs.h>
  23. /* ----------------------------------- Trace & Debug */
  24. #include <dspbridge/dbc.h>
  25. /* ----------------------------------- This */
  26. #include <dspbridge/clk.h>
  27. /* ----------------------------------- Defines, Data Structures, Typedefs */
  28. typedef volatile unsigned long reg_uword32;
  29. #define OMAP_SSI_OFFSET 0x58000
  30. #define OMAP_SSI_SIZE 0x1000
  31. #define OMAP_SSI_SYSCONFIG_OFFSET 0x10
  32. #define SSI_AUTOIDLE (1 << 0)
  33. #define SSI_SIDLE_SMARTIDLE (2 << 3)
  34. #define SSI_MIDLE_NOIDLE (1 << 12)
  35. struct services_clk_t {
  36. struct clk *clk_handle;
  37. const char *clk_name;
  38. const char *dev;
  39. };
  40. /* The row order of the below array needs to match with the clock enumerations
  41. * 'services_clk_id' provided in the header file.. any changes in the
  42. * enumerations needs to be fixed in the array as well */
  43. static struct services_clk_t services_clks[] = {
  44. {NULL, "iva2_ck", NULL},
  45. {NULL, "fck", "omap_timer.5"},
  46. {NULL, "gpt5_ick", NULL},
  47. {NULL, "fck", "omap_timer.6"},
  48. {NULL, "gpt6_ick", NULL},
  49. {NULL, "fck", "omap_timer.7"},
  50. {NULL, "gpt7_ick", NULL},
  51. {NULL, "fck", "omap_timer.8"},
  52. {NULL, "gpt8_ick", NULL},
  53. {NULL, "wdt3_fck", NULL},
  54. {NULL, "wdt3_ick", NULL},
  55. {NULL, "fck", "omap-mcbsp.1"},
  56. {NULL, "ick", "omap-mcbsp.1"},
  57. {NULL, "fck", "omap-mcbsp.2"},
  58. {NULL, "ick", "omap-mcbsp.2"},
  59. {NULL, "fck", "omap-mcbsp.3"},
  60. {NULL, "ick", "omap-mcbsp.3"},
  61. {NULL, "fck", "omap-mcbsp.4"},
  62. {NULL, "ick", "omap-mcbsp.4"},
  63. {NULL, "fck", "omap-mcbsp.5"},
  64. {NULL, "ick", "omap-mcbsp.5"},
  65. {NULL, "ssi_ssr_sst_fck", NULL},
  66. {NULL, "ssi_ick", NULL},
  67. {NULL, "omap_32k_fck", NULL},
  68. {NULL, "sys_ck", NULL},
  69. {NULL, ""}
  70. };
  71. /* Generic TIMER object: */
  72. struct timer_object {
  73. struct timer_list timer;
  74. };
  75. /*
  76. * ======== clk_exit ========
  77. * Purpose:
  78. * Cleanup CLK module.
  79. */
  80. void clk_exit(void)
  81. {
  82. int i = 0;
  83. /* Relinquish the clock handles */
  84. while (i < SERVICESCLK_NOT_DEFINED) {
  85. if (services_clks[i].clk_handle)
  86. clk_put(services_clks[i].clk_handle);
  87. services_clks[i].clk_handle = NULL;
  88. i++;
  89. }
  90. }
  91. /*
  92. * ======== services_clk_init ========
  93. * Purpose:
  94. * Initialize CLK module.
  95. */
  96. bool services_clk_init(void)
  97. {
  98. static struct platform_device dspbridge_device;
  99. struct clk *clk_handle;
  100. int i = 0;
  101. dspbridge_device.dev.bus = &platform_bus_type;
  102. /* Get the clock handles from base port and store locally */
  103. while (i < SERVICESCLK_NOT_DEFINED) {
  104. /* get the handle from BP */
  105. clk_handle = clk_get_sys(services_clks[i].dev,
  106. services_clks[i].clk_name);
  107. if (!clk_handle) {
  108. pr_err("%s: failed to get clk handle %s, dev id = %s\n",
  109. __func__, services_clks[i].clk_name,
  110. services_clks[i].dev);
  111. /* should we fail here?? */
  112. }
  113. services_clks[i].clk_handle = clk_handle;
  114. i++;
  115. }
  116. return true;
  117. }
  118. /*
  119. * ======== services_clk_enable ========
  120. * Purpose:
  121. * Enable Clock .
  122. *
  123. */
  124. int services_clk_enable(IN enum services_clk_id clk_id)
  125. {
  126. int status = 0;
  127. struct clk *clk_handle;
  128. DBC_REQUIRE(clk_id < SERVICESCLK_NOT_DEFINED);
  129. clk_handle = services_clks[clk_id].clk_handle;
  130. if (clk_handle) {
  131. if (clk_enable(clk_handle)) {
  132. pr_err("services_clk_enable: failed to Enable CLK %s, "
  133. "CLK dev id = %s\n",
  134. services_clks[clk_id].clk_name,
  135. services_clks[clk_id].dev);
  136. status = -EPERM;
  137. }
  138. } else {
  139. pr_err("%s: failed to get CLK %s, CLK dev id = %s\n", __func__,
  140. services_clks[clk_id].clk_name, services_clks[clk_id].dev);
  141. status = -EPERM;
  142. }
  143. /* The SSI module need to configured not to have the Forced idle for
  144. * master interface. If it is set to forced idle, the SSI module is
  145. * transitioning to standby thereby causing the client in the DSP hang
  146. * waiting for the SSI module to be active after enabling the clocks
  147. */
  148. if (clk_id == SERVICESCLK_SSI_FCK)
  149. ssi_clk_prepare(true);
  150. return status;
  151. }
  152. /*
  153. * ======== clk_set32k_hz ========
  154. * Purpose:
  155. * To Set parent of a clock to 32KHz.
  156. */
  157. int clk_set32k_hz(IN enum services_clk_id clk_id)
  158. {
  159. int status = 0;
  160. struct clk *clk_handle;
  161. struct clk *clk_parent;
  162. clk_parent = services_clks[SERVICESCLK_SYS32K_CK].clk_handle;
  163. DBC_REQUIRE(clk_id < SERVICESCLK_NOT_DEFINED);
  164. clk_handle = services_clks[clk_id].clk_handle;
  165. if (clk_handle) {
  166. if (!(clk_set_parent(clk_handle, clk_parent) == 0x0)) {
  167. pr_err("%s: failed for %s, dev id = %s\n", __func__,
  168. services_clks[clk_id].clk_name,
  169. services_clks[clk_id].dev);
  170. status = -EPERM;
  171. }
  172. }
  173. return status;
  174. }
  175. /*
  176. * ======== services_clk_disable ========
  177. * Purpose:
  178. * Disable the clock.
  179. *
  180. */
  181. int services_clk_disable(IN enum services_clk_id clk_id)
  182. {
  183. int status = 0;
  184. struct clk *clk_handle;
  185. s32 clk_use_cnt;
  186. DBC_REQUIRE(clk_id < SERVICESCLK_NOT_DEFINED);
  187. clk_handle = services_clks[clk_id].clk_handle;
  188. clk_use_cnt = clk_get_use_cnt(clk_id);
  189. if (clk_use_cnt == -1) {
  190. pr_err("%s: failed to get CLK Use count for CLK %s, CLK dev id"
  191. " = %s\n", __func__, services_clks[clk_id].clk_name,
  192. services_clks[clk_id].dev);
  193. } else if (clk_use_cnt == 0) {
  194. return status;
  195. }
  196. if (clk_id == SERVICESCLK_SSI_ICK)
  197. ssi_clk_prepare(false);
  198. if (clk_handle) {
  199. clk_disable(clk_handle);
  200. } else {
  201. pr_err("services_clk_disable: failed to get CLK %s,"
  202. "CLK dev id = %s\n",
  203. services_clks[clk_id].clk_name,
  204. services_clks[clk_id].dev);
  205. status = -EPERM;
  206. }
  207. return status;
  208. }
  209. /*
  210. * ======== services_clk_get_rate ========
  211. * Purpose:
  212. * GetClock Speed.
  213. *
  214. */
  215. int services_clk_get_rate(IN enum services_clk_id clk_id, u32 *speedKhz)
  216. {
  217. int status = 0;
  218. struct clk *clk_handle;
  219. u32 clk_speed_hz;
  220. DBC_REQUIRE(clk_id < SERVICESCLK_NOT_DEFINED);
  221. *speedKhz = 0x0;
  222. clk_handle = services_clks[clk_id].clk_handle;
  223. if (clk_handle) {
  224. clk_speed_hz = clk_get_rate(clk_handle);
  225. *speedKhz = clk_speed_hz / 1000;
  226. dev_dbg(bridge, "%s: clk_speed_hz = %d, speedinKhz = %d\n",
  227. __func__, clk_speed_hz, *speedKhz);
  228. } else {
  229. pr_err("%s: failed to get %s, dev Id = %s\n", __func__,
  230. services_clks[clk_id].clk_name,
  231. services_clks[clk_id].dev);
  232. status = -EPERM;
  233. }
  234. return status;
  235. }
  236. s32 clk_get_use_cnt(IN enum services_clk_id clk_id)
  237. {
  238. int status = 0;
  239. struct clk *clk_handle;
  240. s32 use_count = -1;
  241. DBC_REQUIRE(clk_id < SERVICESCLK_NOT_DEFINED);
  242. clk_handle = services_clks[clk_id].clk_handle;
  243. if (clk_handle) {
  244. /* FIXME: usecount shouldn't be used */
  245. use_count = clk_handle->usecount;
  246. } else {
  247. pr_err("%s: failed to get %s, dev Id = %s\n", __func__,
  248. services_clks[clk_id].clk_name,
  249. services_clks[clk_id].dev);
  250. status = -EPERM;
  251. }
  252. return use_count;
  253. }
  254. void ssi_clk_prepare(bool FLAG)
  255. {
  256. void __iomem *ssi_base;
  257. unsigned int value;
  258. ssi_base = ioremap(L4_34XX_BASE + OMAP_SSI_OFFSET, OMAP_SSI_SIZE);
  259. if (!ssi_base) {
  260. pr_err("%s: error, SSI not configured\n", __func__);
  261. return;
  262. }
  263. if (FLAG) {
  264. /* Set Autoidle, SIDLEMode to smart idle, and MIDLEmode to
  265. * no idle
  266. */
  267. value = SSI_AUTOIDLE | SSI_SIDLE_SMARTIDLE | SSI_MIDLE_NOIDLE;
  268. } else {
  269. /* Set Autoidle, SIDLEMode to forced idle, and MIDLEmode to
  270. * forced idle
  271. */
  272. value = SSI_AUTOIDLE;
  273. }
  274. __raw_writel(value, ssi_base + OMAP_SSI_SYSCONFIG_OFFSET);
  275. iounmap(ssi_base);
  276. }