drv_clock.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. /**
  2. * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. ******************************************************************************
  6. * @file drv_clock.c
  7. * @version V0.1
  8. * @brief cru clock interface
  9. *
  10. * Change Logs:
  11. * Date Author Notes
  12. * 2019-07-11 Elaine.Zhang first implementation
  13. *
  14. ******************************************************************************
  15. */
  16. /** @addtogroup RKBSP_Driver_Reference
  17. * @{
  18. */
  19. /** @addtogroup Clock
  20. * @{
  21. */
  22. /** @defgroup Clock_How_To_Use How To Use
  23. * @{
  24. The Clock driver use to configure clock frequency, enable/disable clock output, clock reset, power on/off power domain,
  25. it can be used in the following three scenarios:
  26. - **Configure clock frequency**:
  27. - The device set clock rate by clk_set_rate(eCLOCK_Name clk_id, uint32_t rate);
  28. - The device get clock rate by clk_get_rate(eCLOCK_Name clk_id);
  29. - **Enable/disable clock output**:
  30. - The device get clock by get_clk_gate_from_id(int clk_id);
  31. - The device set clock enable/disable by clk_enable(struct clk_gate *gate) or clk_disable(struct clk_gate *gate);
  32. - **Power on/off power domain**:
  33. - The device get pd by get_pd_from_id(int pd_id);
  34. - The device power on/off pd by pd_power(struct pd *power, int on);
  35. @} */
  36. #include <rtdevice.h>
  37. #include <rtthread.h>
  38. #if defined(RT_USING_CRU)
  39. #include "hal_base.h"
  40. #include "drv_clock.h"
  41. static const struct clk_init *g_clk_init = RT_NULL;
  42. static rt_slist_t clk_gate_list;
  43. static struct rt_mutex clk_lock;
  44. static struct rt_mutex gate_lock;
  45. #if defined(RT_USING_PMU)
  46. static struct rt_mutex pd_lock;
  47. static rt_slist_t pd_list;
  48. #endif
  49. /********************* Public Function Definition ****************************/
  50. /** @defgroup CLOCK_Public_Functions Public Functions
  51. * @{
  52. */
  53. /**
  54. * @brief clk set enable.
  55. * @param gate: get_clk_gate_from_id.
  56. * @retval -RT_EINVAL: struct gate is invalid argument
  57. * @retval -RT_ERROR: clk enable failed.
  58. */
  59. rt_err_t clk_enable(struct clk_gate *gate)
  60. {
  61. rt_err_t error = RT_EOK;
  62. HAL_Status ret;
  63. if (!gate)
  64. {
  65. return -RT_EINVAL;
  66. }
  67. rt_mutex_take(&gate_lock, RT_WAITING_FOREVER);
  68. if (gate->enable_count == 0)
  69. {
  70. ret = HAL_CRU_ClkEnable(gate->gate_id);
  71. if (ret != HAL_OK)
  72. error = -RT_ERROR;
  73. }
  74. gate->enable_count++;
  75. rt_mutex_release(&gate_lock);
  76. return error;
  77. }
  78. /**
  79. * @brief clk set disable.
  80. * @param gate: get_clk_gate_from_id.
  81. * @retval -RT_EINVAL: struct gate is invalid argument
  82. * @retval -RT_ERROR: clk disable failed.
  83. */
  84. rt_err_t clk_disable(struct clk_gate *gate)
  85. {
  86. rt_err_t error = RT_EOK;
  87. HAL_Status ret;
  88. if (!gate)
  89. {
  90. return -RT_EINVAL;
  91. }
  92. rt_mutex_take(&gate_lock, RT_WAITING_FOREVER);
  93. if (gate->enable_count == 0)
  94. {
  95. rt_kprintf("It may be wrong to used, make enable first.(gate_id = %d)\n", __func__, gate->gate_id);
  96. goto out;
  97. }
  98. if (--gate->enable_count > 0)
  99. {
  100. goto out;
  101. }
  102. ret = HAL_CRU_ClkDisable(gate->gate_id);
  103. if (ret != HAL_OK)
  104. error = -RT_ERROR;
  105. out:
  106. rt_mutex_release(&gate_lock);
  107. return error;
  108. }
  109. /**
  110. * @brief clk is enabled.
  111. * @param gate: get_clk_gate_from_id.
  112. * @retval 0: clk is disabled
  113. * @retval 1: clk is enabled
  114. */
  115. int clk_is_enabled(struct clk_gate *gate)
  116. {
  117. if (!gate)
  118. {
  119. return 0;
  120. }
  121. return HAL_CRU_ClkIsEnabled(gate->gate_id);
  122. }
  123. /**
  124. * @brief get clk gate by id.
  125. * @param gate_id: clk gate id.
  126. * @return struct of type clk_gate
  127. */
  128. struct clk_gate *get_clk_gate_from_id(int gate_id)
  129. {
  130. struct clk_gate *clk_gate;
  131. rt_mutex_take(&gate_lock, RT_WAITING_FOREVER);
  132. rt_slist_for_each_entry(clk_gate, &clk_gate_list, node)
  133. {
  134. if (clk_gate->gate_id == gate_id)
  135. {
  136. goto out;
  137. }
  138. }
  139. clk_gate = rt_calloc(1, sizeof(struct clk_gate));
  140. clk_gate->gate_id = gate_id;
  141. clk_gate->enable_count = 0;
  142. rt_slist_insert(&clk_gate_list, &clk_gate->node);
  143. out:
  144. clk_gate->ref_count++;
  145. rt_mutex_release(&gate_lock);
  146. return clk_gate;
  147. }
  148. /**
  149. * @brief put clk gate.
  150. * @param gate: get_clk_gate_from_id.
  151. */
  152. void put_clk_gate(struct clk_gate *gate)
  153. {
  154. if (!gate)
  155. return;
  156. rt_mutex_take(&gate_lock, RT_WAITING_FOREVER);
  157. if (--gate->ref_count > 0)
  158. {
  159. goto out;
  160. }
  161. rt_slist_remove(&clk_gate_list, &gate->node);
  162. rt_free(gate);
  163. out:
  164. rt_mutex_release(&gate_lock);
  165. }
  166. /**
  167. * @brief clk get rate.
  168. * @param clk_id: clk id.
  169. * @return the return value of HAL_CRU_ClkGetFreq, which returns the frequency value in unit hz.
  170. */
  171. uint32_t clk_get_rate(eCLOCK_Name clk_id)
  172. {
  173. uint32_t rate;
  174. rt_mutex_take(&clk_lock, RT_WAITING_FOREVER);
  175. rate = HAL_CRU_ClkGetFreq(clk_id);
  176. rt_mutex_release(&clk_lock);
  177. return rate;
  178. }
  179. /**
  180. * @brief clk set rate.
  181. * @param clk_id: clk id.
  182. * @param rate: frequency value hz.
  183. * @retval RT_EOK: clk set successful
  184. * @retval HAL_OK: HAL_CRU_ClkSetFreq set frequency successfully
  185. * @retval HAL_ERROR: HAL_CRU_ClkSetFreq set frequency failed
  186. * @retval HAL_INVAL: HAL_CRU_ClkSetFreq set frequency unsupported
  187. */
  188. rt_err_t clk_set_rate(eCLOCK_Name clk_id, uint32_t rate)
  189. {
  190. rt_err_t error = RT_EOK;
  191. if (rate == clk_get_rate(clk_id))
  192. return error;
  193. rt_mutex_take(&clk_lock, RT_WAITING_FOREVER);
  194. error = HAL_CRU_ClkSetFreq(clk_id, rate);
  195. rt_mutex_release(&clk_lock);
  196. return error;
  197. }
  198. #if defined(RT_USING_PMU)
  199. /**
  200. * @brief pd power on.
  201. * @param power: get_pd_from_id.
  202. * @retval -RT_EINVAL: struct pd is invalid argument
  203. * @retval -RT_ERROR: pd power on failed.
  204. * @retval RT_EOK: pd power on success.
  205. */
  206. rt_err_t pd_on(struct pd *power)
  207. {
  208. rt_err_t error = RT_EOK;
  209. HAL_Status ret;
  210. if (!power)
  211. {
  212. return -RT_EINVAL;
  213. }
  214. rt_mutex_take(&pd_lock, RT_WAITING_FOREVER);
  215. if (power->enable_count == 0)
  216. {
  217. ret = HAL_PD_On(power->pd_id);
  218. if (ret != HAL_OK)
  219. error = -RT_ERROR;
  220. }
  221. power->enable_count++;
  222. rt_mutex_release(&pd_lock);
  223. return error;
  224. }
  225. /**
  226. * @brief pd power off.
  227. * @param power: get_pd_from_id.
  228. * @retval -RT_EINVAL: struct pd is invalid argument
  229. * @retval -RT_ERROR: pd power off failed.
  230. * @retval RT_EOK: pd power off success.
  231. */
  232. rt_err_t pd_off(struct pd *power)
  233. {
  234. rt_err_t error = RT_EOK;
  235. HAL_Status ret;
  236. if (!power)
  237. {
  238. return -RT_EINVAL;
  239. }
  240. rt_mutex_take(&pd_lock, RT_WAITING_FOREVER);
  241. if (--power->enable_count > 0)
  242. {
  243. goto out;
  244. }
  245. ret = HAL_PD_Off(power->pd_id);
  246. if (ret != HAL_OK)
  247. error = -RT_ERROR;
  248. out:
  249. rt_mutex_release(&pd_lock);
  250. return error;
  251. }
  252. /**
  253. * @brief get pd by id.
  254. * @param pd_id: pd id.
  255. * @return struct of type pd
  256. */
  257. struct pd *get_pd_from_id(ePD_Id pd_id)
  258. {
  259. struct pd *pd;
  260. if (!pd_id)
  261. return NULL;
  262. rt_mutex_take(&pd_lock, RT_WAITING_FOREVER);
  263. rt_slist_for_each_entry(pd, &pd_list, node)
  264. {
  265. if (pd->pd_id == pd_id)
  266. {
  267. goto out;
  268. }
  269. }
  270. pd = rt_calloc(1, sizeof(struct pd));
  271. pd->pd_id = pd_id;
  272. pd->enable_count = 0;
  273. rt_slist_insert(&pd_list, &pd->node);
  274. out:
  275. pd->ref_count++;
  276. rt_mutex_release(&pd_lock);
  277. return pd;
  278. }
  279. /**
  280. * @brief put pd.
  281. * @param power: get_pd_from_id.
  282. */
  283. void put_pd(struct pd *power)
  284. {
  285. if (!power)
  286. return;
  287. rt_mutex_take(&pd_lock, RT_WAITING_FOREVER);
  288. if (--power->ref_count > 0)
  289. {
  290. goto out;
  291. }
  292. rt_slist_remove(&pd_list, &power->node);
  293. rt_free(power);
  294. out:
  295. rt_mutex_release(&pd_lock);
  296. }
  297. #endif
  298. /**
  299. * @brief clock dev init.
  300. * @return RT_EOK
  301. */
  302. int clock_dev_init(void)
  303. {
  304. if (rt_mutex_init(&(clk_lock), "clkLock", RT_IPC_FLAG_FIFO) != RT_EOK)
  305. {
  306. RT_ASSERT(0);
  307. }
  308. if (rt_mutex_init(&(gate_lock), "gateLock", RT_IPC_FLAG_FIFO) != RT_EOK)
  309. {
  310. RT_ASSERT(0);
  311. }
  312. rt_slist_init(&clk_gate_list);
  313. #if defined(RT_USING_PMU)
  314. if (rt_mutex_init(&(pd_lock), "pdLock", RT_IPC_FLAG_FIFO) != RT_EOK)
  315. {
  316. RT_ASSERT(0);
  317. }
  318. rt_slist_init(&pd_list);
  319. #endif
  320. return RT_EOK;
  321. }
  322. INIT_BOARD_EXPORT(clock_dev_init);
  323. /**
  324. * @brief clock init frequency.
  325. * @param clk_inits: some need init clks.
  326. * @param clk_dump: if need printf clk get freq after setting.
  327. */
  328. void clk_init(const struct clk_init *clk_inits, bool clk_dump)
  329. {
  330. const struct clk_init *clks = clk_inits;
  331. while (clks->name)
  332. {
  333. if (clks->init_rate)
  334. {
  335. HAL_CRU_ClkSetFreq(clks->clk_id, clks->init_rate);
  336. }
  337. if (clk_dump)
  338. rt_kprintf("%s: %s = %d\n", __func__, clks->name, HAL_CRU_ClkGetFreq(clks->clk_id));
  339. clks++;
  340. }
  341. g_clk_init = clk_inits;
  342. }
  343. /**
  344. * @brief clock disable unused.
  345. * @param clks_unused: disable some not needed clks.
  346. */
  347. void clk_disable_unused(const struct clk_unused *clks_unused)
  348. {
  349. const struct clk_unused *clks = clks_unused;
  350. while (clks->gate_val)
  351. {
  352. if (clks->is_pmucru)
  353. {
  354. #if defined(CRU_PMU_CLKGATE_CON0_OFFSET)
  355. CRU->PMU_CLKGATE_CON[clks->gate_con] = clks->gate_val;
  356. #endif
  357. }
  358. else
  359. {
  360. CRU->CRU_CLKGATE_CON[clks->gate_con] = clks->gate_val;
  361. }
  362. clks++;
  363. }
  364. }
  365. #if defined(RT_USING_CRU_DUMP)
  366. /**
  367. * @brief clock dump frequency, dump cru registers, used for debug.
  368. */
  369. static void clk_dump(void)
  370. {
  371. const struct clk_init *clks = g_clk_init;
  372. int i;
  373. if (clks)
  374. {
  375. while (clks->name)
  376. {
  377. rt_kprintf("%s: %s[%x] = %d\n", __func__, clks->name, clks->clk_id,
  378. HAL_CRU_ClkGetFreq(clks->clk_id));
  379. clks++;
  380. }
  381. }
  382. for (i = 0; i < HAL_ARRAY_SIZE(CRU->CRU_CLKSEL_CON); i++)
  383. {
  384. rt_kprintf("%s: cru_sel_con[%d] = %lx\n", __func__, i, CRU->CRU_CLKSEL_CON[i]);
  385. }
  386. for (i = 0; i < HAL_ARRAY_SIZE(CRU->CRU_CLKGATE_CON); i++)
  387. {
  388. rt_kprintf("%s: cru_gate_con[%d] = %lx\n", __func__, i, CRU->CRU_CLKGATE_CON[i]);
  389. }
  390. for (i = 0; i < HAL_ARRAY_SIZE(CRU->CRU_SOFTRST_CON); i++)
  391. {
  392. rt_kprintf("%s: cru_softreset_con[%d] = %lx\n", __func__, i, CRU->CRU_SOFTRST_CON[i]);
  393. }
  394. }
  395. #ifdef RT_USING_FINSH
  396. #include <finsh.h>
  397. MSH_CMD_EXPORT(clk_dump, cru drive test. e.g: clk_dump);
  398. #endif
  399. #endif
  400. /** @} */
  401. #endif
  402. /** @} */
  403. /** @} */