diff options
Diffstat (limited to 'drivers/clk/qcom/clk-rpm.c')
-rw-r--r-- | drivers/clk/qcom/clk-rpm.c | 79 |
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 | ||
142 | struct rpm_cc; | ||
143 | |||
129 | struct clk_rpm { | 144 | struct 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 | ||
140 | struct rpm_cc { | 157 | struct 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 | ||
146 | struct rpm_clk_desc { | 165 | struct 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 | ||
311 | static 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 | |||
332 | static 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 | |||
291 | static int clk_rpm_fixed_prepare(struct clk_hw *hw) | 351 | static 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 | ||
441 | static const struct clk_ops clk_rpm_xo_ops = { | ||
442 | .prepare = clk_rpm_xo_prepare, | ||
443 | .unprepare = clk_rpm_xo_unprepare, | ||
444 | }; | ||
445 | |||
381 | static const struct clk_ops clk_rpm_fixed_ops = { | 446 | static 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); | |||
449 | DEFINE_CLK_RPM(apq8064, sfab_clk, sfab_a_clk, QCOM_RPM_SYS_FABRIC_CLK); | 514 | DEFINE_CLK_RPM(apq8064, sfab_clk, sfab_a_clk, QCOM_RPM_SYS_FABRIC_CLK); |
450 | DEFINE_CLK_RPM(apq8064, sfpb_clk, sfpb_a_clk, QCOM_RPM_SFPB_CLK); | 515 | DEFINE_CLK_RPM(apq8064, sfpb_clk, sfpb_a_clk, QCOM_RPM_SFPB_CLK); |
451 | DEFINE_CLK_RPM(apq8064, qdss_clk, qdss_a_clk, QCOM_RPM_QDSS_CLK); | 516 | DEFINE_CLK_RPM(apq8064, qdss_clk, qdss_a_clk, QCOM_RPM_QDSS_CLK); |
517 | DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_d0_clk, xo_d0_a_clk, 0); | ||
518 | DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_d1_clk, xo_d1_a_clk, 8); | ||
519 | DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_a0_clk, xo_a0_a_clk, 16); | ||
520 | DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_a1_clk, xo_a1_a_clk, 24); | ||
521 | DEFINE_CLK_RPM_XO_BUFFER(apq8064, xo_a2_clk, xo_a2_a_clk, 28); | ||
452 | 522 | ||
453 | static struct clk_rpm *apq8064_clks[] = { | 523 | static 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 | ||
474 | static const struct rpm_clk_desc rpm_clk_apq8064 = { | 549 | static 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) |