aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk/qcom/clk-rpm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/qcom/clk-rpm.c')
-rw-r--r--drivers/clk/qcom/clk-rpm.c79
1 files changed, 78 insertions, 1 deletions
diff --git a/drivers/clk/qcom/clk-rpm.c b/drivers/clk/qcom/clk-rpm.c
index c60f61b10c7f..b94981447664 100644
--- a/drivers/clk/qcom/clk-rpm.c
+++ b/drivers/clk/qcom/clk-rpm.c
@@ -29,6 +29,7 @@
29 29
30#define QCOM_RPM_MISC_CLK_TYPE 0x306b6c63 30#define QCOM_RPM_MISC_CLK_TYPE 0x306b6c63
31#define QCOM_RPM_SCALING_ENABLE_ID 0x2 31#define QCOM_RPM_SCALING_ENABLE_ID 0x2
32#define QCOM_RPM_XO_MODE_ON 0x2
32 33
33#define DEFINE_CLK_RPM(_platform, _name, _active, r_id) \ 34#define DEFINE_CLK_RPM(_platform, _name, _active, r_id) \
34 static struct clk_rpm _platform##_##_active; \ 35 static struct clk_rpm _platform##_##_active; \
@@ -56,6 +57,18 @@
56 }, \ 57 }, \
57 } 58 }
58 59
60#define DEFINE_CLK_RPM_XO_BUFFER(_platform, _name, _active, offset) \
61 static struct clk_rpm _platform##_##_name = { \
62 .rpm_clk_id = QCOM_RPM_CXO_BUFFERS, \
63 .xo_offset = (offset), \
64 .hw.init = &(struct clk_init_data){ \
65 .ops = &clk_rpm_xo_ops, \
66 .name = #_name, \
67 .parent_names = (const char *[]){ "cxo_board" }, \
68 .num_parents = 1, \
69 }, \
70 }
71
59#define DEFINE_CLK_RPM_FIXED(_platform, _name, _active, r_id, r) \ 72#define DEFINE_CLK_RPM_FIXED(_platform, _name, _active, r_id, r) \
60 static struct clk_rpm _platform##_##_name = { \ 73 static struct clk_rpm _platform##_##_name = { \
61 .rpm_clk_id = (r_id), \ 74 .rpm_clk_id = (r_id), \
@@ -126,8 +139,11 @@
126 139
127#define to_clk_rpm(_hw) container_of(_hw, struct clk_rpm, hw) 140#define to_clk_rpm(_hw) container_of(_hw, struct clk_rpm, hw)
128 141
142struct rpm_cc;
143
129struct clk_rpm { 144struct clk_rpm {
130 const int rpm_clk_id; 145 const int rpm_clk_id;
146 const int xo_offset;
131 const bool active_only; 147 const bool active_only;
132 unsigned long rate; 148 unsigned long rate;
133 bool enabled; 149 bool enabled;
@@ -135,12 +151,15 @@ struct clk_rpm {
135 struct clk_rpm *peer; 151 struct clk_rpm *peer;
136 struct clk_hw hw; 152 struct clk_hw hw;
137 struct qcom_rpm *rpm; 153 struct qcom_rpm *rpm;
154 struct rpm_cc *rpm_cc;
138}; 155};
139 156
140struct rpm_cc { 157struct rpm_cc {
141 struct qcom_rpm *rpm; 158 struct qcom_rpm *rpm;
142 struct clk_rpm **clks; 159 struct clk_rpm **clks;
143 size_t num_clks; 160 size_t num_clks;
161 u32 xo_buffer_value;
162 struct mutex xo_lock;
144}; 163};
145 164
146struct rpm_clk_desc { 165struct rpm_clk_desc {
@@ -159,7 +178,8 @@ static int clk_rpm_handoff(struct clk_rpm *r)
159 * The vendor tree simply reads the status for this 178 * The vendor tree simply reads the status for this
160 * RPM clock. 179 * RPM clock.
161 */ 180 */
162 if (r->rpm_clk_id == QCOM_RPM_PLL_4) 181 if (r->rpm_clk_id == QCOM_RPM_PLL_4 ||
182 r->rpm_clk_id == QCOM_RPM_CXO_BUFFERS)
163 return 0; 183 return 0;
164 184
165 ret = qcom_rpm_write(r->rpm, QCOM_RPM_ACTIVE_STATE, 185 ret = qcom_rpm_write(r->rpm, QCOM_RPM_ACTIVE_STATE,
@@ -288,6 +308,46 @@ out:
288 mutex_unlock(&rpm_clk_lock); 308 mutex_unlock(&rpm_clk_lock);
289} 309}
290 310
311static int clk_rpm_xo_prepare(struct clk_hw *hw)
312{
313 struct clk_rpm *r = to_clk_rpm(hw);
314 struct rpm_cc *rcc = r->rpm_cc;
315 int ret, clk_id = r->rpm_clk_id;
316 u32 value;
317
318 mutex_lock(&rcc->xo_lock);
319
320 value = rcc->xo_buffer_value | (QCOM_RPM_XO_MODE_ON << r->xo_offset);
321 ret = qcom_rpm_write(r->rpm, QCOM_RPM_ACTIVE_STATE, clk_id, &value, 1);
322 if (!ret) {
323 r->enabled = true;
324 rcc->xo_buffer_value = value;
325 }
326
327 mutex_unlock(&rcc->xo_lock);
328
329 return ret;
330}
331
332static void clk_rpm_xo_unprepare(struct clk_hw *hw)
333{
334 struct clk_rpm *r = to_clk_rpm(hw);
335 struct rpm_cc *rcc = r->rpm_cc;
336 int ret, clk_id = r->rpm_clk_id;
337 u32 value;
338
339 mutex_lock(&rcc->xo_lock);
340
341 value = rcc->xo_buffer_value & ~(QCOM_RPM_XO_MODE_ON << r->xo_offset);
342 ret = qcom_rpm_write(r->rpm, QCOM_RPM_ACTIVE_STATE, clk_id, &value, 1);
343 if (!ret) {
344 r->enabled = false;
345 rcc->xo_buffer_value = value;
346 }
347
348 mutex_unlock(&rcc->xo_lock);
349}
350
291static int clk_rpm_fixed_prepare(struct clk_hw *hw) 351static int clk_rpm_fixed_prepare(struct clk_hw *hw)
292{ 352{
293 struct clk_rpm *r = to_clk_rpm(hw); 353 struct clk_rpm *r = to_clk_rpm(hw);
@@ -378,6 +438,11 @@ static unsigned long clk_rpm_recalc_rate(struct clk_hw *hw,
378 return r->rate; 438 return r->rate;
379} 439}
380 440
441static const struct clk_ops clk_rpm_xo_ops = {
442 .prepare = clk_rpm_xo_prepare,
443 .unprepare = clk_rpm_xo_unprepare,
444};
445
381static const struct clk_ops clk_rpm_fixed_ops = { 446static const struct clk_ops clk_rpm_fixed_ops = {
382 .prepare = clk_rpm_fixed_prepare, 447 .prepare = clk_rpm_fixed_prepare,
383 .unprepare = clk_rpm_fixed_unprepare, 448 .unprepare = clk_rpm_fixed_unprepare,
@@ -449,6 +514,11 @@ DEFINE_CLK_RPM(apq8064, mmfpb_clk, mmfpb_a_clk, QCOM_RPM_MMFPB_CLK);
449DEFINE_CLK_RPM(apq8064, sfab_clk, sfab_a_clk, QCOM_RPM_SYS_FABRIC_CLK); 514DEFINE_CLK_RPM(apq8064, sfab_clk, sfab_a_clk, QCOM_RPM_SYS_FABRIC_CLK);
450DEFINE_CLK_RPM(apq8064, sfpb_clk, sfpb_a_clk, QCOM_RPM_SFPB_CLK); 515DEFINE_CLK_RPM(apq8064, sfpb_clk, sfpb_a_clk, QCOM_RPM_SFPB_CLK);
451DEFINE_CLK_RPM(apq8064, qdss_clk, qdss_a_clk, QCOM_RPM_QDSS_CLK); 516DEFINE_CLK_RPM(apq8064, qdss_clk, qdss_a_clk, QCOM_RPM_QDSS_CLK);
517DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_d0_clk, xo_d0_a_clk, 0);
518DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_d1_clk, xo_d1_a_clk, 8);
519DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_a0_clk, xo_a0_a_clk, 16);
520DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_a1_clk, xo_a1_a_clk, 24);
521DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_a2_clk, xo_a2_a_clk, 28);
452 522
453static struct clk_rpm *apq8064_clks[] = { 523static struct clk_rpm *apq8064_clks[] = {
454 [RPM_APPS_FABRIC_CLK] = &apq8064_afab_clk, 524 [RPM_APPS_FABRIC_CLK] = &apq8064_afab_clk,
@@ -469,6 +539,11 @@ static struct clk_rpm *apq8064_clks[] = {
469 [RPM_SFPB_A_CLK] = &apq8064_sfpb_a_clk, 539 [RPM_SFPB_A_CLK] = &apq8064_sfpb_a_clk,
470 [RPM_QDSS_CLK] = &apq8064_qdss_clk, 540 [RPM_QDSS_CLK] = &apq8064_qdss_clk,
471 [RPM_QDSS_A_CLK] = &apq8064_qdss_a_clk, 541 [RPM_QDSS_A_CLK] = &apq8064_qdss_a_clk,
542 [RPM_XO_D0] = &apq8064_xo_d0_clk,
543 [RPM_XO_D1] = &apq8064_xo_d1_clk,
544 [RPM_XO_A0] = &apq8064_xo_a0_clk,
545 [RPM_XO_A1] = &apq8064_xo_a1_clk,
546 [RPM_XO_A2] = &apq8064_xo_a2_clk,
472}; 547};
473 548
474static const struct rpm_clk_desc rpm_clk_apq8064 = { 549static const struct rpm_clk_desc rpm_clk_apq8064 = {
@@ -526,12 +601,14 @@ static int rpm_clk_probe(struct platform_device *pdev)
526 601
527 rcc->clks = rpm_clks; 602 rcc->clks = rpm_clks;
528 rcc->num_clks = num_clks; 603 rcc->num_clks = num_clks;
604 mutex_init(&rcc->xo_lock);
529 605
530 for (i = 0; i < num_clks; i++) { 606 for (i = 0; i < num_clks; i++) {
531 if (!rpm_clks[i]) 607 if (!rpm_clks[i])
532 continue; 608 continue;
533 609
534 rpm_clks[i]->rpm = rpm; 610 rpm_clks[i]->rpm = rpm;
611 rpm_clks[i]->rpm_cc = rcc;
535 612
536 ret = clk_rpm_handoff(rpm_clks[i]); 613 ret = clk_rpm_handoff(rpm_clks[i]);
537 if (ret) 614 if (ret)