ccu-div.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
  4. *
  5. * Authors:
  6. * Serge Semin <Sergey.Semin@baikalelectronics.ru>
  7. * Dmitry Dunaev <dmitry.dunaev@baikalelectronics.ru>
  8. *
  9. * Baikal-T1 CCU Dividers interface driver
  10. */
  11. #define pr_fmt(fmt) "bt1-ccu-div: " fmt
  12. #include <linux/kernel.h>
  13. #include <linux/printk.h>
  14. #include <linux/bits.h>
  15. #include <linux/bitfield.h>
  16. #include <linux/slab.h>
  17. #include <linux/clk-provider.h>
  18. #include <linux/of.h>
  19. #include <linux/spinlock.h>
  20. #include <linux/regmap.h>
  21. #include <linux/delay.h>
  22. #include <linux/time64.h>
  23. #include <linux/debugfs.h>
  24. #include "ccu-div.h"
  25. #define CCU_DIV_CTL 0x00
  26. #define CCU_DIV_CTL_EN BIT(0)
  27. #define CCU_DIV_CTL_RST BIT(1)
  28. #define CCU_DIV_CTL_SET_CLKDIV BIT(2)
  29. #define CCU_DIV_CTL_CLKDIV_FLD 4
  30. #define CCU_DIV_CTL_CLKDIV_MASK(_width) \
  31. GENMASK((_width) + CCU_DIV_CTL_CLKDIV_FLD - 1, CCU_DIV_CTL_CLKDIV_FLD)
  32. #define CCU_DIV_CTL_LOCK_SHIFTED BIT(27)
  33. #define CCU_DIV_CTL_GATE_REF_BUF BIT(28)
  34. #define CCU_DIV_CTL_LOCK_NORMAL BIT(31)
  35. #define CCU_DIV_LOCK_CHECK_RETRIES 50
  36. #define CCU_DIV_CLKDIV_MIN 0
  37. #define CCU_DIV_CLKDIV_MAX(_mask) \
  38. ((_mask) >> CCU_DIV_CTL_CLKDIV_FLD)
  39. /*
  40. * Use the next two methods until there are generic field setter and
  41. * getter available with non-constant mask support.
  42. */
  43. static inline u32 ccu_div_get(u32 mask, u32 val)
  44. {
  45. return (val & mask) >> CCU_DIV_CTL_CLKDIV_FLD;
  46. }
  47. static inline u32 ccu_div_prep(u32 mask, u32 val)
  48. {
  49. return (val << CCU_DIV_CTL_CLKDIV_FLD) & mask;
  50. }
  51. static inline unsigned long ccu_div_lock_delay_ns(unsigned long ref_clk,
  52. unsigned long div)
  53. {
  54. u64 ns = 4ULL * (div ?: 1) * NSEC_PER_SEC;
  55. do_div(ns, ref_clk);
  56. return ns;
  57. }
  58. static inline unsigned long ccu_div_calc_freq(unsigned long ref_clk,
  59. unsigned long div)
  60. {
  61. return ref_clk / (div ?: 1);
  62. }
  63. static int ccu_div_var_update_clkdiv(struct ccu_div *div,
  64. unsigned long parent_rate,
  65. unsigned long divider)
  66. {
  67. unsigned long nd;
  68. u32 val = 0;
  69. u32 lock;
  70. int count;
  71. nd = ccu_div_lock_delay_ns(parent_rate, divider);
  72. if (div->features & CCU_DIV_LOCK_SHIFTED)
  73. lock = CCU_DIV_CTL_LOCK_SHIFTED;
  74. else
  75. lock = CCU_DIV_CTL_LOCK_NORMAL;
  76. regmap_update_bits(div->sys_regs, div->reg_ctl,
  77. CCU_DIV_CTL_SET_CLKDIV, CCU_DIV_CTL_SET_CLKDIV);
  78. /*
  79. * Until there is nsec-version of readl_poll_timeout() is available
  80. * we have to implement the next polling loop.
  81. */
  82. count = CCU_DIV_LOCK_CHECK_RETRIES;
  83. do {
  84. ndelay(nd);
  85. regmap_read(div->sys_regs, div->reg_ctl, &val);
  86. if (val & lock)
  87. return 0;
  88. } while (--count);
  89. return -ETIMEDOUT;
  90. }
  91. static int ccu_div_var_enable(struct clk_hw *hw)
  92. {
  93. struct clk_hw *parent_hw = clk_hw_get_parent(hw);
  94. struct ccu_div *div = to_ccu_div(hw);
  95. unsigned long flags;
  96. u32 val = 0;
  97. int ret;
  98. if (!parent_hw) {
  99. pr_err("Can't enable '%s' with no parent", clk_hw_get_name(hw));
  100. return -EINVAL;
  101. }
  102. regmap_read(div->sys_regs, div->reg_ctl, &val);
  103. if (val & CCU_DIV_CTL_EN)
  104. return 0;
  105. spin_lock_irqsave(&div->lock, flags);
  106. ret = ccu_div_var_update_clkdiv(div, clk_hw_get_rate(parent_hw),
  107. ccu_div_get(div->mask, val));
  108. if (!ret)
  109. regmap_update_bits(div->sys_regs, div->reg_ctl,
  110. CCU_DIV_CTL_EN, CCU_DIV_CTL_EN);
  111. spin_unlock_irqrestore(&div->lock, flags);
  112. if (ret)
  113. pr_err("Divider '%s' lock timed out\n", clk_hw_get_name(hw));
  114. return ret;
  115. }
  116. static int ccu_div_gate_enable(struct clk_hw *hw)
  117. {
  118. struct ccu_div *div = to_ccu_div(hw);
  119. unsigned long flags;
  120. spin_lock_irqsave(&div->lock, flags);
  121. regmap_update_bits(div->sys_regs, div->reg_ctl,
  122. CCU_DIV_CTL_EN, CCU_DIV_CTL_EN);
  123. spin_unlock_irqrestore(&div->lock, flags);
  124. return 0;
  125. }
  126. static void ccu_div_gate_disable(struct clk_hw *hw)
  127. {
  128. struct ccu_div *div = to_ccu_div(hw);
  129. unsigned long flags;
  130. spin_lock_irqsave(&div->lock, flags);
  131. regmap_update_bits(div->sys_regs, div->reg_ctl, CCU_DIV_CTL_EN, 0);
  132. spin_unlock_irqrestore(&div->lock, flags);
  133. }
  134. static int ccu_div_gate_is_enabled(struct clk_hw *hw)
  135. {
  136. struct ccu_div *div = to_ccu_div(hw);
  137. u32 val = 0;
  138. regmap_read(div->sys_regs, div->reg_ctl, &val);
  139. return !!(val & CCU_DIV_CTL_EN);
  140. }
  141. static int ccu_div_buf_enable(struct clk_hw *hw)
  142. {
  143. struct ccu_div *div = to_ccu_div(hw);
  144. unsigned long flags;
  145. spin_lock_irqsave(&div->lock, flags);
  146. regmap_update_bits(div->sys_regs, div->reg_ctl,
  147. CCU_DIV_CTL_GATE_REF_BUF, 0);
  148. spin_unlock_irqrestore(&div->lock, flags);
  149. return 0;
  150. }
  151. static void ccu_div_buf_disable(struct clk_hw *hw)
  152. {
  153. struct ccu_div *div = to_ccu_div(hw);
  154. unsigned long flags;
  155. spin_lock_irqsave(&div->lock, flags);
  156. regmap_update_bits(div->sys_regs, div->reg_ctl,
  157. CCU_DIV_CTL_GATE_REF_BUF, CCU_DIV_CTL_GATE_REF_BUF);
  158. spin_unlock_irqrestore(&div->lock, flags);
  159. }
  160. static int ccu_div_buf_is_enabled(struct clk_hw *hw)
  161. {
  162. struct ccu_div *div = to_ccu_div(hw);
  163. u32 val = 0;
  164. regmap_read(div->sys_regs, div->reg_ctl, &val);
  165. return !(val & CCU_DIV_CTL_GATE_REF_BUF);
  166. }
  167. static unsigned long ccu_div_var_recalc_rate(struct clk_hw *hw,
  168. unsigned long parent_rate)
  169. {
  170. struct ccu_div *div = to_ccu_div(hw);
  171. unsigned long divider;
  172. u32 val = 0;
  173. regmap_read(div->sys_regs, div->reg_ctl, &val);
  174. divider = ccu_div_get(div->mask, val);
  175. return ccu_div_calc_freq(parent_rate, divider);
  176. }
  177. static inline unsigned long ccu_div_var_calc_divider(unsigned long rate,
  178. unsigned long parent_rate,
  179. unsigned int mask)
  180. {
  181. unsigned long divider;
  182. divider = parent_rate / rate;
  183. return clamp_t(unsigned long, divider, CCU_DIV_CLKDIV_MIN,
  184. CCU_DIV_CLKDIV_MAX(mask));
  185. }
  186. static int ccu_div_var_determine_rate(struct clk_hw *hw,
  187. struct clk_rate_request *req)
  188. {
  189. struct ccu_div *div = to_ccu_div(hw);
  190. unsigned long divider;
  191. divider = ccu_div_var_calc_divider(req->rate, req->best_parent_rate,
  192. div->mask);
  193. req->rate = ccu_div_calc_freq(req->best_parent_rate, divider);
  194. return 0;
  195. }
  196. /*
  197. * This method is used for the clock divider blocks, which support the
  198. * on-the-fly rate change. So due to lacking the EN bit functionality
  199. * they can't be gated before the rate adjustment.
  200. */
  201. static int ccu_div_var_set_rate_slow(struct clk_hw *hw, unsigned long rate,
  202. unsigned long parent_rate)
  203. {
  204. struct ccu_div *div = to_ccu_div(hw);
  205. unsigned long flags, divider;
  206. u32 val;
  207. int ret;
  208. divider = ccu_div_var_calc_divider(rate, parent_rate, div->mask);
  209. if (divider == 1 && div->features & CCU_DIV_SKIP_ONE) {
  210. divider = 0;
  211. } else if (div->features & CCU_DIV_SKIP_ONE_TO_THREE) {
  212. if (divider == 1 || divider == 2)
  213. divider = 0;
  214. else if (divider == 3)
  215. divider = 4;
  216. }
  217. val = ccu_div_prep(div->mask, divider);
  218. spin_lock_irqsave(&div->lock, flags);
  219. regmap_update_bits(div->sys_regs, div->reg_ctl, div->mask, val);
  220. ret = ccu_div_var_update_clkdiv(div, parent_rate, divider);
  221. spin_unlock_irqrestore(&div->lock, flags);
  222. if (ret)
  223. pr_err("Divider '%s' lock timed out\n", clk_hw_get_name(hw));
  224. return ret;
  225. }
  226. /*
  227. * This method is used for the clock divider blocks, which don't support
  228. * the on-the-fly rate change.
  229. */
  230. static int ccu_div_var_set_rate_fast(struct clk_hw *hw, unsigned long rate,
  231. unsigned long parent_rate)
  232. {
  233. struct ccu_div *div = to_ccu_div(hw);
  234. unsigned long flags, divider;
  235. u32 val;
  236. divider = ccu_div_var_calc_divider(rate, parent_rate, div->mask);
  237. val = ccu_div_prep(div->mask, divider);
  238. /*
  239. * Also disable the clock divider block if it was enabled by default
  240. * or by the bootloader.
  241. */
  242. spin_lock_irqsave(&div->lock, flags);
  243. regmap_update_bits(div->sys_regs, div->reg_ctl,
  244. div->mask | CCU_DIV_CTL_EN, val);
  245. spin_unlock_irqrestore(&div->lock, flags);
  246. return 0;
  247. }
  248. static unsigned long ccu_div_fixed_recalc_rate(struct clk_hw *hw,
  249. unsigned long parent_rate)
  250. {
  251. struct ccu_div *div = to_ccu_div(hw);
  252. return ccu_div_calc_freq(parent_rate, div->divider);
  253. }
  254. static int ccu_div_fixed_determine_rate(struct clk_hw *hw,
  255. struct clk_rate_request *req)
  256. {
  257. struct ccu_div *div = to_ccu_div(hw);
  258. req->rate = ccu_div_calc_freq(req->best_parent_rate, div->divider);
  259. return 0;
  260. }
  261. static int ccu_div_fixed_set_rate(struct clk_hw *hw, unsigned long rate,
  262. unsigned long parent_rate)
  263. {
  264. return 0;
  265. }
  266. #ifdef CONFIG_DEBUG_FS
  267. struct ccu_div_dbgfs_bit {
  268. struct ccu_div *div;
  269. const char *name;
  270. u32 mask;
  271. };
  272. #define CCU_DIV_DBGFS_BIT_ATTR(_name, _mask) { \
  273. .name = _name, \
  274. .mask = _mask \
  275. }
  276. static const struct ccu_div_dbgfs_bit ccu_div_bits[] = {
  277. CCU_DIV_DBGFS_BIT_ATTR("div_en", CCU_DIV_CTL_EN),
  278. CCU_DIV_DBGFS_BIT_ATTR("div_rst", CCU_DIV_CTL_RST),
  279. CCU_DIV_DBGFS_BIT_ATTR("div_bypass", CCU_DIV_CTL_SET_CLKDIV),
  280. CCU_DIV_DBGFS_BIT_ATTR("div_buf", CCU_DIV_CTL_GATE_REF_BUF),
  281. CCU_DIV_DBGFS_BIT_ATTR("div_lock", CCU_DIV_CTL_LOCK_NORMAL)
  282. };
  283. #define CCU_DIV_DBGFS_BIT_NUM ARRAY_SIZE(ccu_div_bits)
  284. /*
  285. * It can be dangerous to change the Divider settings behind clock framework
  286. * back, therefore we don't provide any kernel config based compile time option
  287. * for this feature to enable.
  288. */
  289. #undef CCU_DIV_ALLOW_WRITE_DEBUGFS
  290. #ifdef CCU_DIV_ALLOW_WRITE_DEBUGFS
  291. static int ccu_div_dbgfs_bit_set(void *priv, u64 val)
  292. {
  293. const struct ccu_div_dbgfs_bit *bit = priv;
  294. struct ccu_div *div = bit->div;
  295. unsigned long flags;
  296. spin_lock_irqsave(&div->lock, flags);
  297. regmap_update_bits(div->sys_regs, div->reg_ctl,
  298. bit->mask, val ? bit->mask : 0);
  299. spin_unlock_irqrestore(&div->lock, flags);
  300. return 0;
  301. }
  302. static int ccu_div_dbgfs_var_clkdiv_set(void *priv, u64 val)
  303. {
  304. struct ccu_div *div = priv;
  305. unsigned long flags;
  306. u32 data;
  307. val = clamp_t(u64, val, CCU_DIV_CLKDIV_MIN,
  308. CCU_DIV_CLKDIV_MAX(div->mask));
  309. data = ccu_div_prep(div->mask, val);
  310. spin_lock_irqsave(&div->lock, flags);
  311. regmap_update_bits(div->sys_regs, div->reg_ctl, div->mask, data);
  312. spin_unlock_irqrestore(&div->lock, flags);
  313. return 0;
  314. }
  315. #define ccu_div_dbgfs_mode 0644
  316. #else /* !CCU_DIV_ALLOW_WRITE_DEBUGFS */
  317. #define ccu_div_dbgfs_bit_set NULL
  318. #define ccu_div_dbgfs_var_clkdiv_set NULL
  319. #define ccu_div_dbgfs_mode 0444
  320. #endif /* !CCU_DIV_ALLOW_WRITE_DEBUGFS */
  321. static int ccu_div_dbgfs_bit_get(void *priv, u64 *val)
  322. {
  323. const struct ccu_div_dbgfs_bit *bit = priv;
  324. struct ccu_div *div = bit->div;
  325. u32 data = 0;
  326. regmap_read(div->sys_regs, div->reg_ctl, &data);
  327. *val = !!(data & bit->mask);
  328. return 0;
  329. }
  330. DEFINE_DEBUGFS_ATTRIBUTE(ccu_div_dbgfs_bit_fops,
  331. ccu_div_dbgfs_bit_get, ccu_div_dbgfs_bit_set, "%llu\n");
  332. static int ccu_div_dbgfs_var_clkdiv_get(void *priv, u64 *val)
  333. {
  334. struct ccu_div *div = priv;
  335. u32 data = 0;
  336. regmap_read(div->sys_regs, div->reg_ctl, &data);
  337. *val = ccu_div_get(div->mask, data);
  338. return 0;
  339. }
  340. DEFINE_DEBUGFS_ATTRIBUTE(ccu_div_dbgfs_var_clkdiv_fops,
  341. ccu_div_dbgfs_var_clkdiv_get, ccu_div_dbgfs_var_clkdiv_set, "%llu\n");
  342. static int ccu_div_dbgfs_fixed_clkdiv_get(void *priv, u64 *val)
  343. {
  344. struct ccu_div *div = priv;
  345. *val = div->divider;
  346. return 0;
  347. }
  348. DEFINE_DEBUGFS_ATTRIBUTE(ccu_div_dbgfs_fixed_clkdiv_fops,
  349. ccu_div_dbgfs_fixed_clkdiv_get, NULL, "%llu\n");
  350. static void ccu_div_var_debug_init(struct clk_hw *hw, struct dentry *dentry)
  351. {
  352. struct ccu_div *div = to_ccu_div(hw);
  353. struct ccu_div_dbgfs_bit *bits;
  354. int didx, bidx, num = 2;
  355. const char *name;
  356. num += !!(div->flags & CLK_SET_RATE_GATE) +
  357. !!(div->features & CCU_DIV_RESET_DOMAIN);
  358. bits = kzalloc_objs(*bits, num);
  359. if (!bits)
  360. return;
  361. for (didx = 0, bidx = 0; bidx < CCU_DIV_DBGFS_BIT_NUM; ++bidx) {
  362. name = ccu_div_bits[bidx].name;
  363. if (!(div->flags & CLK_SET_RATE_GATE) &&
  364. !strcmp("div_en", name)) {
  365. continue;
  366. }
  367. if (!(div->features & CCU_DIV_RESET_DOMAIN) &&
  368. !strcmp("div_rst", name)) {
  369. continue;
  370. }
  371. if (!strcmp("div_buf", name))
  372. continue;
  373. bits[didx] = ccu_div_bits[bidx];
  374. bits[didx].div = div;
  375. if (div->features & CCU_DIV_LOCK_SHIFTED &&
  376. !strcmp("div_lock", name)) {
  377. bits[didx].mask = CCU_DIV_CTL_LOCK_SHIFTED;
  378. }
  379. debugfs_create_file_unsafe(bits[didx].name, ccu_div_dbgfs_mode,
  380. dentry, &bits[didx],
  381. &ccu_div_dbgfs_bit_fops);
  382. ++didx;
  383. }
  384. debugfs_create_file_unsafe("div_clkdiv", ccu_div_dbgfs_mode, dentry,
  385. div, &ccu_div_dbgfs_var_clkdiv_fops);
  386. }
  387. static void ccu_div_gate_debug_init(struct clk_hw *hw, struct dentry *dentry)
  388. {
  389. struct ccu_div *div = to_ccu_div(hw);
  390. struct ccu_div_dbgfs_bit *bit;
  391. bit = kmalloc_obj(*bit);
  392. if (!bit)
  393. return;
  394. *bit = ccu_div_bits[0];
  395. bit->div = div;
  396. debugfs_create_file_unsafe(bit->name, ccu_div_dbgfs_mode, dentry, bit,
  397. &ccu_div_dbgfs_bit_fops);
  398. debugfs_create_file_unsafe("div_clkdiv", 0400, dentry, div,
  399. &ccu_div_dbgfs_fixed_clkdiv_fops);
  400. }
  401. static void ccu_div_buf_debug_init(struct clk_hw *hw, struct dentry *dentry)
  402. {
  403. struct ccu_div *div = to_ccu_div(hw);
  404. struct ccu_div_dbgfs_bit *bit;
  405. bit = kmalloc_obj(*bit);
  406. if (!bit)
  407. return;
  408. *bit = ccu_div_bits[3];
  409. bit->div = div;
  410. debugfs_create_file_unsafe(bit->name, ccu_div_dbgfs_mode, dentry, bit,
  411. &ccu_div_dbgfs_bit_fops);
  412. }
  413. static void ccu_div_fixed_debug_init(struct clk_hw *hw, struct dentry *dentry)
  414. {
  415. struct ccu_div *div = to_ccu_div(hw);
  416. debugfs_create_file_unsafe("div_clkdiv", 0400, dentry, div,
  417. &ccu_div_dbgfs_fixed_clkdiv_fops);
  418. }
  419. #else /* !CONFIG_DEBUG_FS */
  420. #define ccu_div_var_debug_init NULL
  421. #define ccu_div_gate_debug_init NULL
  422. #define ccu_div_buf_debug_init NULL
  423. #define ccu_div_fixed_debug_init NULL
  424. #endif /* !CONFIG_DEBUG_FS */
  425. static const struct clk_ops ccu_div_var_gate_to_set_ops = {
  426. .enable = ccu_div_var_enable,
  427. .disable = ccu_div_gate_disable,
  428. .is_enabled = ccu_div_gate_is_enabled,
  429. .recalc_rate = ccu_div_var_recalc_rate,
  430. .determine_rate = ccu_div_var_determine_rate,
  431. .set_rate = ccu_div_var_set_rate_fast,
  432. .debug_init = ccu_div_var_debug_init
  433. };
  434. static const struct clk_ops ccu_div_var_nogate_ops = {
  435. .recalc_rate = ccu_div_var_recalc_rate,
  436. .determine_rate = ccu_div_var_determine_rate,
  437. .set_rate = ccu_div_var_set_rate_slow,
  438. .debug_init = ccu_div_var_debug_init
  439. };
  440. static const struct clk_ops ccu_div_gate_ops = {
  441. .enable = ccu_div_gate_enable,
  442. .disable = ccu_div_gate_disable,
  443. .is_enabled = ccu_div_gate_is_enabled,
  444. .recalc_rate = ccu_div_fixed_recalc_rate,
  445. .determine_rate = ccu_div_fixed_determine_rate,
  446. .set_rate = ccu_div_fixed_set_rate,
  447. .debug_init = ccu_div_gate_debug_init
  448. };
  449. static const struct clk_ops ccu_div_buf_ops = {
  450. .enable = ccu_div_buf_enable,
  451. .disable = ccu_div_buf_disable,
  452. .is_enabled = ccu_div_buf_is_enabled,
  453. .debug_init = ccu_div_buf_debug_init
  454. };
  455. static const struct clk_ops ccu_div_fixed_ops = {
  456. .recalc_rate = ccu_div_fixed_recalc_rate,
  457. .determine_rate = ccu_div_fixed_determine_rate,
  458. .set_rate = ccu_div_fixed_set_rate,
  459. .debug_init = ccu_div_fixed_debug_init
  460. };
  461. struct ccu_div *ccu_div_hw_register(const struct ccu_div_init_data *div_init)
  462. {
  463. struct clk_parent_data parent_data = { };
  464. struct clk_init_data hw_init = { };
  465. struct ccu_div *div;
  466. int ret;
  467. if (!div_init)
  468. return ERR_PTR(-EINVAL);
  469. div = kzalloc_obj(*div);
  470. if (!div)
  471. return ERR_PTR(-ENOMEM);
  472. /*
  473. * Note since Baikal-T1 System Controller registers are MMIO-backed
  474. * we won't check the regmap IO operations return status, because it
  475. * must be zero anyway.
  476. */
  477. div->hw.init = &hw_init;
  478. div->id = div_init->id;
  479. div->reg_ctl = div_init->base + CCU_DIV_CTL;
  480. div->sys_regs = div_init->sys_regs;
  481. div->flags = div_init->flags;
  482. div->features = div_init->features;
  483. spin_lock_init(&div->lock);
  484. hw_init.name = div_init->name;
  485. hw_init.flags = div_init->flags;
  486. if (div_init->type == CCU_DIV_VAR) {
  487. if (hw_init.flags & CLK_SET_RATE_GATE)
  488. hw_init.ops = &ccu_div_var_gate_to_set_ops;
  489. else
  490. hw_init.ops = &ccu_div_var_nogate_ops;
  491. div->mask = CCU_DIV_CTL_CLKDIV_MASK(div_init->width);
  492. } else if (div_init->type == CCU_DIV_GATE) {
  493. hw_init.ops = &ccu_div_gate_ops;
  494. div->divider = div_init->divider;
  495. } else if (div_init->type == CCU_DIV_BUF) {
  496. hw_init.ops = &ccu_div_buf_ops;
  497. } else if (div_init->type == CCU_DIV_FIXED) {
  498. hw_init.ops = &ccu_div_fixed_ops;
  499. div->divider = div_init->divider;
  500. } else {
  501. ret = -EINVAL;
  502. goto err_free_div;
  503. }
  504. if (!div_init->parent_name) {
  505. ret = -EINVAL;
  506. goto err_free_div;
  507. }
  508. parent_data.fw_name = div_init->parent_name;
  509. parent_data.name = div_init->parent_name;
  510. hw_init.parent_data = &parent_data;
  511. hw_init.num_parents = 1;
  512. ret = of_clk_hw_register(div_init->np, &div->hw);
  513. if (ret)
  514. goto err_free_div;
  515. return div;
  516. err_free_div:
  517. kfree(div);
  518. return ERR_PTR(ret);
  519. }
  520. void ccu_div_hw_unregister(struct ccu_div *div)
  521. {
  522. clk_hw_unregister(&div->hw);
  523. kfree(div);
  524. }