0002-clk-mediatek-Add-initial-common-clock-support-for-Me.patch 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954
  1. From f851b4ea6cae9fd5875036b6d3968375882ce56b Mon Sep 17 00:00:00 2001
  2. From: James Liao <[email protected]>
  3. Date: Thu, 23 Apr 2015 10:35:39 +0200
  4. Subject: [PATCH 02/76] clk: mediatek: Add initial common clock support for
  5. Mediatek SoCs.
  6. This patch adds common clock support for Mediatek SoCs, including plls,
  7. muxes and clock gates.
  8. Signed-off-by: James Liao <[email protected]>
  9. Signed-off-by: Henry Chen <[email protected]>
  10. Signed-off-by: Sascha Hauer <[email protected]>
  11. ---
  12. drivers/clk/Makefile | 1 +
  13. drivers/clk/mediatek/Makefile | 1 +
  14. drivers/clk/mediatek/clk-gate.c | 137 ++++++++++++++++
  15. drivers/clk/mediatek/clk-gate.h | 49 ++++++
  16. drivers/clk/mediatek/clk-mtk.c | 220 ++++++++++++++++++++++++++
  17. drivers/clk/mediatek/clk-mtk.h | 159 +++++++++++++++++++
  18. drivers/clk/mediatek/clk-pll.c | 332 +++++++++++++++++++++++++++++++++++++++
  19. 7 files changed, 899 insertions(+)
  20. create mode 100644 drivers/clk/mediatek/Makefile
  21. create mode 100644 drivers/clk/mediatek/clk-gate.c
  22. create mode 100644 drivers/clk/mediatek/clk-gate.h
  23. create mode 100644 drivers/clk/mediatek/clk-mtk.c
  24. create mode 100644 drivers/clk/mediatek/clk-mtk.h
  25. create mode 100644 drivers/clk/mediatek/clk-pll.c
  26. --- a/drivers/clk/Makefile
  27. +++ b/drivers/clk/Makefile
  28. @@ -51,6 +51,7 @@ obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/
  29. obj-$(CONFIG_ARCH_HIP04) += hisilicon/
  30. obj-$(CONFIG_ARCH_HIX5HD2) += hisilicon/
  31. obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
  32. +obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
  33. ifeq ($(CONFIG_COMMON_CLK), y)
  34. obj-$(CONFIG_ARCH_MMP) += mmp/
  35. endif
  36. --- /dev/null
  37. +++ b/drivers/clk/mediatek/Makefile
  38. @@ -0,0 +1 @@
  39. +obj-y += clk-mtk.o clk-pll.o clk-gate.o
  40. --- /dev/null
  41. +++ b/drivers/clk/mediatek/clk-gate.c
  42. @@ -0,0 +1,137 @@
  43. +/*
  44. + * Copyright (c) 2014 MediaTek Inc.
  45. + * Author: James Liao <[email protected]>
  46. + *
  47. + * This program is free software; you can redistribute it and/or modify
  48. + * it under the terms of the GNU General Public License version 2 as
  49. + * published by the Free Software Foundation.
  50. + *
  51. + * This program is distributed in the hope that it will be useful,
  52. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  53. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  54. + * GNU General Public License for more details.
  55. + */
  56. +
  57. +#include <linux/of.h>
  58. +#include <linux/of_address.h>
  59. +
  60. +#include <linux/io.h>
  61. +#include <linux/slab.h>
  62. +#include <linux/delay.h>
  63. +#include <linux/clkdev.h>
  64. +
  65. +#include "clk-mtk.h"
  66. +#include "clk-gate.h"
  67. +
  68. +static int mtk_cg_bit_is_cleared(struct clk_hw *hw)
  69. +{
  70. + struct mtk_clk_gate *cg = to_clk_gate(hw);
  71. + u32 val;
  72. +
  73. + regmap_read(cg->regmap, cg->sta_ofs, &val);
  74. +
  75. + val &= BIT(cg->bit);
  76. +
  77. + return val == 0;
  78. +}
  79. +
  80. +static int mtk_cg_bit_is_set(struct clk_hw *hw)
  81. +{
  82. + struct mtk_clk_gate *cg = to_clk_gate(hw);
  83. + u32 val;
  84. +
  85. + regmap_read(cg->regmap, cg->sta_ofs, &val);
  86. +
  87. + val &= BIT(cg->bit);
  88. +
  89. + return val != 0;
  90. +}
  91. +
  92. +static void mtk_cg_set_bit(struct clk_hw *hw)
  93. +{
  94. + struct mtk_clk_gate *cg = to_clk_gate(hw);
  95. +
  96. + regmap_write(cg->regmap, cg->set_ofs, BIT(cg->bit));
  97. +}
  98. +
  99. +static void mtk_cg_clr_bit(struct clk_hw *hw)
  100. +{
  101. + struct mtk_clk_gate *cg = to_clk_gate(hw);
  102. +
  103. + regmap_write(cg->regmap, cg->clr_ofs, BIT(cg->bit));
  104. +}
  105. +
  106. +static int mtk_cg_enable(struct clk_hw *hw)
  107. +{
  108. + mtk_cg_clr_bit(hw);
  109. +
  110. + return 0;
  111. +}
  112. +
  113. +static void mtk_cg_disable(struct clk_hw *hw)
  114. +{
  115. + mtk_cg_set_bit(hw);
  116. +}
  117. +
  118. +static int mtk_cg_enable_inv(struct clk_hw *hw)
  119. +{
  120. + mtk_cg_set_bit(hw);
  121. +
  122. + return 0;
  123. +}
  124. +
  125. +static void mtk_cg_disable_inv(struct clk_hw *hw)
  126. +{
  127. + mtk_cg_clr_bit(hw);
  128. +}
  129. +
  130. +const struct clk_ops mtk_clk_gate_ops_setclr = {
  131. + .is_enabled = mtk_cg_bit_is_cleared,
  132. + .enable = mtk_cg_enable,
  133. + .disable = mtk_cg_disable,
  134. +};
  135. +
  136. +const struct clk_ops mtk_clk_gate_ops_setclr_inv = {
  137. + .is_enabled = mtk_cg_bit_is_set,
  138. + .enable = mtk_cg_enable_inv,
  139. + .disable = mtk_cg_disable_inv,
  140. +};
  141. +
  142. +struct clk *mtk_clk_register_gate(
  143. + const char *name,
  144. + const char *parent_name,
  145. + struct regmap *regmap,
  146. + int set_ofs,
  147. + int clr_ofs,
  148. + int sta_ofs,
  149. + u8 bit,
  150. + const struct clk_ops *ops)
  151. +{
  152. + struct mtk_clk_gate *cg;
  153. + struct clk *clk;
  154. + struct clk_init_data init;
  155. +
  156. + cg = kzalloc(sizeof(*cg), GFP_KERNEL);
  157. + if (!cg)
  158. + return ERR_PTR(-ENOMEM);
  159. +
  160. + init.name = name;
  161. + init.flags = CLK_SET_RATE_PARENT;
  162. + init.parent_names = parent_name ? &parent_name : NULL;
  163. + init.num_parents = parent_name ? 1 : 0;
  164. + init.ops = ops;
  165. +
  166. + cg->regmap = regmap;
  167. + cg->set_ofs = set_ofs;
  168. + cg->clr_ofs = clr_ofs;
  169. + cg->sta_ofs = sta_ofs;
  170. + cg->bit = bit;
  171. +
  172. + cg->hw.init = &init;
  173. +
  174. + clk = clk_register(NULL, &cg->hw);
  175. + if (IS_ERR(clk))
  176. + kfree(cg);
  177. +
  178. + return clk;
  179. +}
  180. --- /dev/null
  181. +++ b/drivers/clk/mediatek/clk-gate.h
  182. @@ -0,0 +1,49 @@
  183. +/*
  184. + * Copyright (c) 2014 MediaTek Inc.
  185. + * Author: James Liao <[email protected]>
  186. + *
  187. + * This program is free software; you can redistribute it and/or modify
  188. + * it under the terms of the GNU General Public License version 2 as
  189. + * published by the Free Software Foundation.
  190. + *
  191. + * This program is distributed in the hope that it will be useful,
  192. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  193. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  194. + * GNU General Public License for more details.
  195. + */
  196. +
  197. +#ifndef __DRV_CLK_GATE_H
  198. +#define __DRV_CLK_GATE_H
  199. +
  200. +#include <linux/regmap.h>
  201. +#include <linux/clk.h>
  202. +#include <linux/clk-provider.h>
  203. +
  204. +struct mtk_clk_gate {
  205. + struct clk_hw hw;
  206. + struct regmap *regmap;
  207. + int set_ofs;
  208. + int clr_ofs;
  209. + int sta_ofs;
  210. + u8 bit;
  211. +};
  212. +
  213. +static inline struct mtk_clk_gate *to_clk_gate(struct clk_hw *hw)
  214. +{
  215. + return container_of(hw, struct mtk_clk_gate, hw);
  216. +}
  217. +
  218. +extern const struct clk_ops mtk_clk_gate_ops_setclr;
  219. +extern const struct clk_ops mtk_clk_gate_ops_setclr_inv;
  220. +
  221. +struct clk *mtk_clk_register_gate(
  222. + const char *name,
  223. + const char *parent_name,
  224. + struct regmap *regmap,
  225. + int set_ofs,
  226. + int clr_ofs,
  227. + int sta_ofs,
  228. + u8 bit,
  229. + const struct clk_ops *ops);
  230. +
  231. +#endif /* __DRV_CLK_GATE_H */
  232. --- /dev/null
  233. +++ b/drivers/clk/mediatek/clk-mtk.c
  234. @@ -0,0 +1,220 @@
  235. +/*
  236. + * Copyright (c) 2014 MediaTek Inc.
  237. + * Author: James Liao <[email protected]>
  238. + *
  239. + * This program is free software; you can redistribute it and/or modify
  240. + * it under the terms of the GNU General Public License version 2 as
  241. + * published by the Free Software Foundation.
  242. + *
  243. + * This program is distributed in the hope that it will be useful,
  244. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  245. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  246. + * GNU General Public License for more details.
  247. + */
  248. +
  249. +#include <linux/of.h>
  250. +#include <linux/of_address.h>
  251. +#include <linux/err.h>
  252. +#include <linux/io.h>
  253. +#include <linux/slab.h>
  254. +#include <linux/delay.h>
  255. +#include <linux/clkdev.h>
  256. +#include <linux/mfd/syscon.h>
  257. +
  258. +#include "clk-mtk.h"
  259. +#include "clk-gate.h"
  260. +
  261. +struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num)
  262. +{
  263. + int i;
  264. + struct clk_onecell_data *clk_data;
  265. +
  266. + clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
  267. + if (!clk_data)
  268. + return NULL;
  269. +
  270. + clk_data->clks = kcalloc(clk_num, sizeof(*clk_data->clks), GFP_KERNEL);
  271. + if (!clk_data->clks)
  272. + goto err_out;
  273. +
  274. + clk_data->clk_num = clk_num;
  275. +
  276. + for (i = 0; i < clk_num; i++)
  277. + clk_data->clks[i] = ERR_PTR(-ENOENT);
  278. +
  279. + return clk_data;
  280. +err_out:
  281. + kfree(clk_data);
  282. +
  283. + return NULL;
  284. +}
  285. +
  286. +void mtk_clk_register_factors(const struct mtk_fixed_factor *clks, int num,
  287. + struct clk_onecell_data *clk_data)
  288. +{
  289. + int i;
  290. + struct clk *clk;
  291. +
  292. + for (i = 0; i < num; i++) {
  293. + const struct mtk_fixed_factor *ff = &clks[i];
  294. +
  295. + clk = clk_register_fixed_factor(NULL, ff->name, ff->parent_name,
  296. + CLK_SET_RATE_PARENT, ff->mult, ff->div);
  297. +
  298. + if (IS_ERR(clk)) {
  299. + pr_err("Failed to register clk %s: %ld\n",
  300. + ff->name, PTR_ERR(clk));
  301. + continue;
  302. + }
  303. +
  304. + if (clk_data)
  305. + clk_data->clks[ff->id] = clk;
  306. + }
  307. +}
  308. +
  309. +int mtk_clk_register_gates(struct device_node *node, const struct mtk_gate *clks,
  310. + int num, struct clk_onecell_data *clk_data)
  311. +{
  312. + int i;
  313. + struct clk *clk;
  314. + struct regmap *regmap;
  315. +
  316. + if (!clk_data)
  317. + return -ENOMEM;
  318. +
  319. + regmap = syscon_node_to_regmap(node);
  320. + if (IS_ERR(regmap)) {
  321. + pr_err("Cannot find regmap for %s: %ld\n", node->full_name,
  322. + PTR_ERR(regmap));
  323. + return PTR_ERR(regmap);
  324. + }
  325. +
  326. + for (i = 0; i < num; i++) {
  327. + const struct mtk_gate *gate = &clks[i];
  328. +
  329. + clk = mtk_clk_register_gate(gate->name, gate->parent_name,
  330. + regmap,
  331. + gate->regs->set_ofs,
  332. + gate->regs->clr_ofs,
  333. + gate->regs->sta_ofs,
  334. + gate->shift, gate->ops);
  335. +
  336. + if (IS_ERR(clk)) {
  337. + pr_err("Failed to register clk %s: %ld\n",
  338. + gate->name, PTR_ERR(clk));
  339. + continue;
  340. + }
  341. +
  342. + clk_data->clks[gate->id] = clk;
  343. + }
  344. +
  345. + return 0;
  346. +}
  347. +
  348. +struct clk *mtk_clk_register_composite(const struct mtk_composite *mc,
  349. + void __iomem *base, spinlock_t *lock)
  350. +{
  351. + struct clk *clk;
  352. + struct clk_mux *mux = NULL;
  353. + struct clk_gate *gate = NULL;
  354. + struct clk_divider *div = NULL;
  355. + struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *div_hw = NULL;
  356. + const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *div_ops = NULL;
  357. + const char * const *parent_names;
  358. + const char *parent;
  359. + int num_parents;
  360. + int ret;
  361. +
  362. + if (mc->mux_shift >= 0) {
  363. + mux = kzalloc(sizeof(*mux), GFP_KERNEL);
  364. + if (!mux)
  365. + return ERR_PTR(-ENOMEM);
  366. +
  367. + mux->reg = base + mc->mux_reg;
  368. + mux->mask = BIT(mc->mux_width) - 1;
  369. + mux->shift = mc->mux_shift;
  370. + mux->lock = lock;
  371. +
  372. + mux_hw = &mux->hw;
  373. + mux_ops = &clk_mux_ops;
  374. +
  375. + parent_names = mc->parent_names;
  376. + num_parents = mc->num_parents;
  377. + } else {
  378. + parent = mc->parent;
  379. + parent_names = &parent;
  380. + num_parents = 1;
  381. + }
  382. +
  383. + if (mc->gate_shift >= 0) {
  384. + gate = kzalloc(sizeof(*gate), GFP_KERNEL);
  385. + if (!gate) {
  386. + ret = -ENOMEM;
  387. + goto err_out;
  388. + }
  389. +
  390. + gate->reg = base + mc->gate_reg;
  391. + gate->bit_idx = mc->gate_shift;
  392. + gate->flags = CLK_GATE_SET_TO_DISABLE;
  393. + gate->lock = lock;
  394. +
  395. + gate_hw = &gate->hw;
  396. + gate_ops = &clk_gate_ops;
  397. + }
  398. +
  399. + if (mc->divider_shift >= 0) {
  400. + div = kzalloc(sizeof(*div), GFP_KERNEL);
  401. + if (!div) {
  402. + ret = -ENOMEM;
  403. + goto err_out;
  404. + }
  405. +
  406. + div->reg = base + mc->divider_reg;
  407. + div->shift = mc->divider_shift;
  408. + div->width = mc->divider_width;
  409. + div->lock = lock;
  410. +
  411. + div_hw = &div->hw;
  412. + div_ops = &clk_divider_ops;
  413. + }
  414. +
  415. + clk = clk_register_composite(NULL, mc->name, parent_names, num_parents,
  416. + mux_hw, mux_ops,
  417. + div_hw, div_ops,
  418. + gate_hw, gate_ops,
  419. + mc->flags);
  420. +
  421. + if (IS_ERR(clk)) {
  422. + kfree(gate);
  423. + kfree(mux);
  424. + }
  425. +
  426. + return clk;
  427. +err_out:
  428. + kfree(mux);
  429. +
  430. + return ERR_PTR(ret);
  431. +}
  432. +
  433. +void mtk_clk_register_composites(const struct mtk_composite *mcs,
  434. + int num, void __iomem *base, spinlock_t *lock,
  435. + struct clk_onecell_data *clk_data)
  436. +{
  437. + struct clk *clk;
  438. + int i;
  439. +
  440. + for (i = 0; i < num; i++) {
  441. + const struct mtk_composite *mc = &mcs[i];
  442. +
  443. + clk = mtk_clk_register_composite(mc, base, lock);
  444. +
  445. + if (IS_ERR(clk)) {
  446. + pr_err("Failed to register clk %s: %ld\n",
  447. + mc->name, PTR_ERR(clk));
  448. + continue;
  449. + }
  450. +
  451. + if (clk_data)
  452. + clk_data->clks[mc->id] = clk;
  453. + }
  454. +}
  455. --- /dev/null
  456. +++ b/drivers/clk/mediatek/clk-mtk.h
  457. @@ -0,0 +1,159 @@
  458. +/*
  459. + * Copyright (c) 2014 MediaTek Inc.
  460. + * Author: James Liao <[email protected]>
  461. + *
  462. + * This program is free software; you can redistribute it and/or modify
  463. + * it under the terms of the GNU General Public License version 2 as
  464. + * published by the Free Software Foundation.
  465. + *
  466. + * This program is distributed in the hope that it will be useful,
  467. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  468. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  469. + * GNU General Public License for more details.
  470. + */
  471. +
  472. +#ifndef __DRV_CLK_MTK_H
  473. +#define __DRV_CLK_MTK_H
  474. +
  475. +#include <linux/regmap.h>
  476. +#include <linux/bitops.h>
  477. +#include <linux/clk.h>
  478. +#include <linux/clk-provider.h>
  479. +
  480. +#define MAX_MUX_GATE_BIT 31
  481. +#define INVALID_MUX_GATE_BIT (MAX_MUX_GATE_BIT + 1)
  482. +
  483. +#define MHZ (1000 * 1000)
  484. +
  485. +struct mtk_fixed_factor {
  486. + int id;
  487. + const char *name;
  488. + const char *parent_name;
  489. + int mult;
  490. + int div;
  491. +};
  492. +
  493. +#define FACTOR(_id, _name, _parent, _mult, _div) { \
  494. + .id = _id, \
  495. + .name = _name, \
  496. + .parent_name = _parent, \
  497. + .mult = _mult, \
  498. + .div = _div, \
  499. + }
  500. +
  501. +extern void mtk_clk_register_factors(const struct mtk_fixed_factor *clks,
  502. + int num, struct clk_onecell_data *clk_data);
  503. +
  504. +struct mtk_composite {
  505. + int id;
  506. + const char *name;
  507. + const char * const * parent_names;
  508. + const char *parent;
  509. + unsigned flags;
  510. +
  511. + uint32_t mux_reg;
  512. + uint32_t divider_reg;
  513. + uint32_t gate_reg;
  514. +
  515. + signed char mux_shift;
  516. + signed char mux_width;
  517. + signed char gate_shift;
  518. +
  519. + signed char divider_shift;
  520. + signed char divider_width;
  521. +
  522. + signed char num_parents;
  523. +};
  524. +
  525. +#define MUX_GATE(_id, _name, _parents, _reg, _shift, _width, _gate) { \
  526. + .id = _id, \
  527. + .name = _name, \
  528. + .mux_reg = _reg, \
  529. + .mux_shift = _shift, \
  530. + .mux_width = _width, \
  531. + .gate_reg = _reg, \
  532. + .gate_shift = _gate, \
  533. + .divider_shift = -1, \
  534. + .parent_names = _parents, \
  535. + .num_parents = ARRAY_SIZE(_parents), \
  536. + .flags = CLK_SET_RATE_PARENT, \
  537. + }
  538. +
  539. +#define MUX(_id, _name, _parents, _reg, _shift, _width) { \
  540. + .id = _id, \
  541. + .name = _name, \
  542. + .mux_reg = _reg, \
  543. + .mux_shift = _shift, \
  544. + .mux_width = _width, \
  545. + .gate_shift = -1, \
  546. + .divider_shift = -1, \
  547. + .parent_names = _parents, \
  548. + .num_parents = ARRAY_SIZE(_parents), \
  549. + .flags = CLK_SET_RATE_PARENT, \
  550. + }
  551. +
  552. +#define DIV_GATE(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg, _div_width, _div_shift) { \
  553. + .id = _id, \
  554. + .parent = _parent, \
  555. + .name = _name, \
  556. + .divider_reg = _div_reg, \
  557. + .divider_shift = _div_shift, \
  558. + .divider_width = _div_width, \
  559. + .gate_reg = _gate_reg, \
  560. + .gate_shift = _gate_shift, \
  561. + .mux_shift = -1, \
  562. + .flags = 0, \
  563. + }
  564. +
  565. +struct clk *mtk_clk_register_composite(const struct mtk_composite *mc,
  566. + void __iomem *base, spinlock_t *lock);
  567. +
  568. +void mtk_clk_register_composites(const struct mtk_composite *mcs,
  569. + int num, void __iomem *base, spinlock_t *lock,
  570. + struct clk_onecell_data *clk_data);
  571. +
  572. +struct mtk_gate_regs {
  573. + u32 sta_ofs;
  574. + u32 clr_ofs;
  575. + u32 set_ofs;
  576. +};
  577. +
  578. +struct mtk_gate {
  579. + int id;
  580. + const char *name;
  581. + const char *parent_name;
  582. + const struct mtk_gate_regs *regs;
  583. + int shift;
  584. + const struct clk_ops *ops;
  585. +};
  586. +
  587. +int mtk_clk_register_gates(struct device_node *node, const struct mtk_gate *clks,
  588. + int num, struct clk_onecell_data *clk_data);
  589. +
  590. +struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num);
  591. +
  592. +#define HAVE_RST_BAR BIT(0)
  593. +
  594. +struct mtk_pll_data {
  595. + int id;
  596. + const char *name;
  597. + uint32_t reg;
  598. + uint32_t pwr_reg;
  599. + uint32_t en_mask;
  600. + uint32_t pd_reg;
  601. + uint32_t tuner_reg;
  602. + int pd_shift;
  603. + unsigned int flags;
  604. + const struct clk_ops *ops;
  605. + u32 rst_bar_mask;
  606. + unsigned long fmax;
  607. + int pcwbits;
  608. + uint32_t pcw_reg;
  609. + int pcw_shift;
  610. +};
  611. +
  612. +void __init mtk_clk_register_plls(struct device_node *node,
  613. + const struct mtk_pll_data *plls, int num_plls,
  614. + struct clk_onecell_data *clk_data);
  615. +
  616. +#endif /* __DRV_CLK_MTK_H */
  617. --- /dev/null
  618. +++ b/drivers/clk/mediatek/clk-pll.c
  619. @@ -0,0 +1,332 @@
  620. +/*
  621. + * Copyright (c) 2014 MediaTek Inc.
  622. + * Author: James Liao <[email protected]>
  623. + *
  624. + * This program is free software; you can redistribute it and/or modify
  625. + * it under the terms of the GNU General Public License version 2 as
  626. + * published by the Free Software Foundation.
  627. + *
  628. + * This program is distributed in the hope that it will be useful,
  629. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  630. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  631. + * GNU General Public License for more details.
  632. + */
  633. +
  634. +#include <linux/of.h>
  635. +#include <linux/of_address.h>
  636. +#include <linux/io.h>
  637. +#include <linux/slab.h>
  638. +#include <linux/clkdev.h>
  639. +#include <linux/delay.h>
  640. +
  641. +#include "clk-mtk.h"
  642. +
  643. +#define REG_CON0 0
  644. +#define REG_CON1 4
  645. +
  646. +#define CON0_BASE_EN BIT(0)
  647. +#define CON0_PWR_ON BIT(0)
  648. +#define CON0_ISO_EN BIT(1)
  649. +#define CON0_PCW_CHG BIT(31)
  650. +
  651. +#define AUDPLL_TUNER_EN BIT(31)
  652. +
  653. +#define POSTDIV_MASK 0x7
  654. +#define INTEGER_BITS 7
  655. +
  656. +/*
  657. + * MediaTek PLLs are configured through their pcw value. The pcw value describes
  658. + * a divider in the PLL feedback loop which consists of 7 bits for the integer
  659. + * part and the remaining bits (if present) for the fractional part. Also they
  660. + * have a 3 bit power-of-two post divider.
  661. + */
  662. +
  663. +struct mtk_clk_pll {
  664. + struct clk_hw hw;
  665. + void __iomem *base_addr;
  666. + void __iomem *pd_addr;
  667. + void __iomem *pwr_addr;
  668. + void __iomem *tuner_addr;
  669. + void __iomem *pcw_addr;
  670. + const struct mtk_pll_data *data;
  671. +};
  672. +
  673. +static inline struct mtk_clk_pll *to_mtk_clk_pll(struct clk_hw *hw)
  674. +{
  675. + return container_of(hw, struct mtk_clk_pll, hw);
  676. +}
  677. +
  678. +static int mtk_pll_is_prepared(struct clk_hw *hw)
  679. +{
  680. + struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
  681. +
  682. + return (readl(pll->base_addr + REG_CON0) & CON0_BASE_EN) != 0;
  683. +}
  684. +
  685. +static unsigned long __mtk_pll_recalc_rate(struct mtk_clk_pll *pll, u32 fin,
  686. + u32 pcw, int postdiv)
  687. +{
  688. + int pcwbits = pll->data->pcwbits;
  689. + int pcwfbits;
  690. + u64 vco;
  691. + u8 c = 0;
  692. +
  693. + /* The fractional part of the PLL divider. */
  694. + pcwfbits = pcwbits > INTEGER_BITS ? pcwbits - INTEGER_BITS : 0;
  695. +
  696. + vco = (u64)fin * pcw;
  697. +
  698. + if (pcwfbits && (vco & GENMASK(pcwfbits - 1, 0)))
  699. + c = 1;
  700. +
  701. + vco >>= pcwfbits;
  702. +
  703. + if (c)
  704. + vco++;
  705. +
  706. + return ((unsigned long)vco + postdiv - 1) / postdiv;
  707. +}
  708. +
  709. +static void mtk_pll_set_rate_regs(struct mtk_clk_pll *pll, u32 pcw,
  710. + int postdiv)
  711. +{
  712. + u32 con1, pd, val;
  713. + int pll_en;
  714. +
  715. + /* set postdiv */
  716. + pd = readl(pll->pd_addr);
  717. + pd &= ~(POSTDIV_MASK << pll->data->pd_shift);
  718. + pd |= (ffs(postdiv) - 1) << pll->data->pd_shift;
  719. + writel(pd, pll->pd_addr);
  720. +
  721. + pll_en = readl(pll->base_addr + REG_CON0) & CON0_BASE_EN;
  722. +
  723. + /* set pcw */
  724. + val = readl(pll->pcw_addr);
  725. +
  726. + val &= ~GENMASK(pll->data->pcw_shift + pll->data->pcwbits - 1,
  727. + pll->data->pcw_shift);
  728. + val |= pcw << pll->data->pcw_shift;
  729. + writel(val, pll->pcw_addr);
  730. +
  731. + con1 = readl(pll->base_addr + REG_CON1);
  732. +
  733. + if (pll_en)
  734. + con1 |= CON0_PCW_CHG;
  735. +
  736. + writel(con1, pll->base_addr + REG_CON1);
  737. + if (pll->tuner_addr)
  738. + writel(con1 + 1, pll->tuner_addr);
  739. +
  740. + if (pll_en)
  741. + udelay(20);
  742. +}
  743. +
  744. +/*
  745. + * mtk_pll_calc_values - calculate good values for a given input frequency.
  746. + * @pll: The pll
  747. + * @pcw: The pcw value (output)
  748. + * @postdiv: The post divider (output)
  749. + * @freq: The desired target frequency
  750. + * @fin: The input frequency
  751. + *
  752. + */
  753. +static void mtk_pll_calc_values(struct mtk_clk_pll *pll, u32 *pcw, u32 *postdiv,
  754. + u32 freq, u32 fin)
  755. +{
  756. + unsigned long fmin = 1000 * MHZ;
  757. + u64 _pcw;
  758. + u32 val;
  759. +
  760. + if (freq > pll->data->fmax)
  761. + freq = pll->data->fmax;
  762. +
  763. + for (val = 0; val < 4; val++) {
  764. + *postdiv = 1 << val;
  765. + if (freq * *postdiv >= fmin)
  766. + break;
  767. + }
  768. +
  769. + /* _pcw = freq * postdiv / fin * 2^pcwfbits */
  770. + _pcw = ((u64)freq << val) << (pll->data->pcwbits - INTEGER_BITS);
  771. + do_div(_pcw, fin);
  772. +
  773. + *pcw = (u32)_pcw;
  774. +}
  775. +
  776. +static int mtk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
  777. + unsigned long parent_rate)
  778. +{
  779. + struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
  780. + u32 pcw = 0;
  781. + u32 postdiv;
  782. +
  783. + mtk_pll_calc_values(pll, &pcw, &postdiv, rate, parent_rate);
  784. + mtk_pll_set_rate_regs(pll, pcw, postdiv);
  785. +
  786. + return 0;
  787. +}
  788. +
  789. +static unsigned long mtk_pll_recalc_rate(struct clk_hw *hw,
  790. + unsigned long parent_rate)
  791. +{
  792. + struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
  793. + u32 postdiv;
  794. + u32 pcw;
  795. +
  796. + postdiv = (readl(pll->pd_addr) >> pll->data->pd_shift) & POSTDIV_MASK;
  797. + postdiv = 1 << postdiv;
  798. +
  799. + pcw = readl(pll->pcw_addr) >> pll->data->pcw_shift;
  800. + pcw &= GENMASK(pll->data->pcwbits - 1, 0);
  801. +
  802. + return __mtk_pll_recalc_rate(pll, parent_rate, pcw, postdiv);
  803. +}
  804. +
  805. +static long mtk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
  806. + unsigned long *prate)
  807. +{
  808. + struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
  809. + u32 pcw = 0;
  810. + int postdiv;
  811. +
  812. + mtk_pll_calc_values(pll, &pcw, &postdiv, rate, *prate);
  813. +
  814. + return __mtk_pll_recalc_rate(pll, *prate, pcw, postdiv);
  815. +}
  816. +
  817. +static int mtk_pll_prepare(struct clk_hw *hw)
  818. +{
  819. + struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
  820. + u32 r;
  821. +
  822. + r = readl(pll->pwr_addr) | CON0_PWR_ON;
  823. + writel(r, pll->pwr_addr);
  824. + udelay(1);
  825. +
  826. + r = readl(pll->pwr_addr) & ~CON0_ISO_EN;
  827. + writel(r, pll->pwr_addr);
  828. + udelay(1);
  829. +
  830. + r = readl(pll->base_addr + REG_CON0);
  831. + r |= pll->data->en_mask;
  832. + writel(r, pll->base_addr + REG_CON0);
  833. +
  834. + if (pll->tuner_addr) {
  835. + r = readl(pll->tuner_addr) | AUDPLL_TUNER_EN;
  836. + writel(r, pll->tuner_addr);
  837. + }
  838. +
  839. + udelay(20);
  840. +
  841. + if (pll->data->flags & HAVE_RST_BAR) {
  842. + r = readl(pll->base_addr + REG_CON0);
  843. + r |= pll->data->rst_bar_mask;
  844. + writel(r, pll->base_addr + REG_CON0);
  845. + }
  846. +
  847. + return 0;
  848. +}
  849. +
  850. +static void mtk_pll_unprepare(struct clk_hw *hw)
  851. +{
  852. + struct mtk_clk_pll *pll = to_mtk_clk_pll(hw);
  853. + u32 r;
  854. +
  855. + if (pll->data->flags & HAVE_RST_BAR) {
  856. + r = readl(pll->base_addr + REG_CON0);
  857. + r &= ~pll->data->rst_bar_mask;
  858. + writel(r, pll->base_addr + REG_CON0);
  859. + }
  860. +
  861. + if (pll->tuner_addr) {
  862. + r = readl(pll->tuner_addr) & ~AUDPLL_TUNER_EN;
  863. + writel(r, pll->tuner_addr);
  864. + }
  865. +
  866. + r = readl(pll->base_addr + REG_CON0);
  867. + r &= ~CON0_BASE_EN;
  868. + writel(r, pll->base_addr + REG_CON0);
  869. +
  870. + r = readl(pll->pwr_addr) | CON0_ISO_EN;
  871. + writel(r, pll->pwr_addr);
  872. +
  873. + r = readl(pll->pwr_addr) & ~CON0_PWR_ON;
  874. + writel(r, pll->pwr_addr);
  875. +}
  876. +
  877. +static const struct clk_ops mtk_pll_ops = {
  878. + .is_prepared = mtk_pll_is_prepared,
  879. + .prepare = mtk_pll_prepare,
  880. + .unprepare = mtk_pll_unprepare,
  881. + .recalc_rate = mtk_pll_recalc_rate,
  882. + .round_rate = mtk_pll_round_rate,
  883. + .set_rate = mtk_pll_set_rate,
  884. +};
  885. +
  886. +static struct clk *mtk_clk_register_pll(const struct mtk_pll_data *data,
  887. + void __iomem *base)
  888. +{
  889. + struct mtk_clk_pll *pll;
  890. + struct clk_init_data init;
  891. + struct clk *clk;
  892. + const char *parent_name = "clk26m";
  893. +
  894. + pll = kzalloc(sizeof(*pll), GFP_KERNEL);
  895. + if (!pll)
  896. + return ERR_PTR(-ENOMEM);
  897. +
  898. + pll->base_addr = base + data->reg;
  899. + pll->pwr_addr = base + data->pwr_reg;
  900. + pll->pd_addr = base + data->pd_reg;
  901. + pll->pcw_addr = base + data->pcw_reg;
  902. + if (data->tuner_reg)
  903. + pll->tuner_addr = base + data->tuner_reg;
  904. + pll->hw.init = &init;
  905. + pll->data = data;
  906. +
  907. + init.name = data->name;
  908. + init.ops = &mtk_pll_ops;
  909. + init.parent_names = &parent_name;
  910. + init.num_parents = 1;
  911. +
  912. + clk = clk_register(NULL, &pll->hw);
  913. +
  914. + if (IS_ERR(clk))
  915. + kfree(pll);
  916. +
  917. + return clk;
  918. +}
  919. +
  920. +void __init mtk_clk_register_plls(struct device_node *node,
  921. + const struct mtk_pll_data *plls, int num_plls, struct clk_onecell_data *clk_data)
  922. +{
  923. + void __iomem *base;
  924. + int r, i;
  925. + struct clk *clk;
  926. +
  927. + base = of_iomap(node, 0);
  928. + if (!base) {
  929. + pr_err("%s(): ioremap failed\n", __func__);
  930. + return;
  931. + }
  932. +
  933. + for (i = 0; i < num_plls; i++) {
  934. + const struct mtk_pll_data *pll = &plls[i];
  935. +
  936. + clk = mtk_clk_register_pll(pll, base);
  937. +
  938. + if (IS_ERR(clk)) {
  939. + pr_err("Failed to register clk %s: %ld\n",
  940. + pll->name, PTR_ERR(clk));
  941. + continue;
  942. + }
  943. +
  944. + clk_data->clks[pll->id] = clk;
  945. + }
  946. +
  947. + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
  948. + if (r)
  949. + pr_err("%s(): could not register clock provider: %d\n",
  950. + __func__, r);
  951. +}