diff options
Diffstat (limited to 'drivers/clk/qcom')
-rw-r--r-- | drivers/clk/qcom/clk-regmap-divider.c | 20 | ||||
-rw-r--r-- | drivers/clk/qcom/clk-rpm.c | 79 | ||||
-rw-r--r-- | drivers/clk/qcom/clk-smd-rpm.c | 9 | ||||
-rw-r--r-- | drivers/clk/qcom/gcc-msm8996.c | 8 |
4 files changed, 89 insertions, 27 deletions
diff --git a/drivers/clk/qcom/clk-regmap-divider.c b/drivers/clk/qcom/clk-regmap-divider.c index 4e9b8c2c8980..1ee75a5e93f4 100644 --- a/drivers/clk/qcom/clk-regmap-divider.c +++ b/drivers/clk/qcom/clk-regmap-divider.c | |||
@@ -28,22 +28,14 @@ static long div_round_ro_rate(struct clk_hw *hw, unsigned long rate, | |||
28 | { | 28 | { |
29 | struct clk_regmap_div *divider = to_clk_regmap_div(hw); | 29 | struct clk_regmap_div *divider = to_clk_regmap_div(hw); |
30 | struct clk_regmap *clkr = ÷r->clkr; | 30 | struct clk_regmap *clkr = ÷r->clkr; |
31 | u32 div; | 31 | u32 val; |
32 | struct clk_hw *hw_parent = clk_hw_get_parent(hw); | ||
33 | |||
34 | regmap_read(clkr->regmap, divider->reg, &div); | ||
35 | div >>= divider->shift; | ||
36 | div &= BIT(divider->width) - 1; | ||
37 | div += 1; | ||
38 | |||
39 | if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) { | ||
40 | if (!hw_parent) | ||
41 | return -EINVAL; | ||
42 | 32 | ||
43 | *prate = clk_hw_round_rate(hw_parent, rate * div); | 33 | regmap_read(clkr->regmap, divider->reg, &val); |
44 | } | 34 | val >>= divider->shift; |
35 | val &= BIT(divider->width) - 1; | ||
45 | 36 | ||
46 | return DIV_ROUND_UP_ULL((u64)*prate, div); | 37 | return divider_ro_round_rate(hw, rate, prate, NULL, divider->width, |
38 | CLK_DIVIDER_ROUND_CLOSEST, val); | ||
47 | } | 39 | } |
48 | 40 | ||
49 | static long div_round_rate(struct clk_hw *hw, unsigned long rate, | 41 | static long div_round_rate(struct clk_hw *hw, unsigned long rate, |
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) |
diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c index c26d9007bfc4..850c02a52248 100644 --- a/drivers/clk/qcom/clk-smd-rpm.c +++ b/drivers/clk/qcom/clk-smd-rpm.c | |||
@@ -686,7 +686,7 @@ static int rpm_smd_clk_probe(struct platform_device *pdev) | |||
686 | goto err; | 686 | goto err; |
687 | } | 687 | } |
688 | 688 | ||
689 | ret = of_clk_add_hw_provider(pdev->dev.of_node, qcom_smdrpm_clk_hw_get, | 689 | ret = devm_of_clk_add_hw_provider(&pdev->dev, qcom_smdrpm_clk_hw_get, |
690 | rcc); | 690 | rcc); |
691 | if (ret) | 691 | if (ret) |
692 | goto err; | 692 | goto err; |
@@ -697,19 +697,12 @@ err: | |||
697 | return ret; | 697 | return ret; |
698 | } | 698 | } |
699 | 699 | ||
700 | static int rpm_smd_clk_remove(struct platform_device *pdev) | ||
701 | { | ||
702 | of_clk_del_provider(pdev->dev.of_node); | ||
703 | return 0; | ||
704 | } | ||
705 | |||
706 | static struct platform_driver rpm_smd_clk_driver = { | 700 | static struct platform_driver rpm_smd_clk_driver = { |
707 | .driver = { | 701 | .driver = { |
708 | .name = "qcom-clk-smd-rpm", | 702 | .name = "qcom-clk-smd-rpm", |
709 | .of_match_table = rpm_smd_clk_match_table, | 703 | .of_match_table = rpm_smd_clk_match_table, |
710 | }, | 704 | }, |
711 | .probe = rpm_smd_clk_probe, | 705 | .probe = rpm_smd_clk_probe, |
712 | .remove = rpm_smd_clk_remove, | ||
713 | }; | 706 | }; |
714 | 707 | ||
715 | static int __init rpm_smd_clk_init(void) | 708 | static int __init rpm_smd_clk_init(void) |
diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c index 5d7451209206..3d6452932797 100644 --- a/drivers/clk/qcom/gcc-msm8996.c +++ b/drivers/clk/qcom/gcc-msm8996.c | |||
@@ -2895,7 +2895,7 @@ static struct clk_branch gcc_aggre0_snoc_axi_clk = { | |||
2895 | .name = "gcc_aggre0_snoc_axi_clk", | 2895 | .name = "gcc_aggre0_snoc_axi_clk", |
2896 | .parent_names = (const char *[]){ "system_noc_clk_src" }, | 2896 | .parent_names = (const char *[]){ "system_noc_clk_src" }, |
2897 | .num_parents = 1, | 2897 | .num_parents = 1, |
2898 | .flags = CLK_SET_RATE_PARENT, | 2898 | .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, |
2899 | .ops = &clk_branch2_ops, | 2899 | .ops = &clk_branch2_ops, |
2900 | }, | 2900 | }, |
2901 | }, | 2901 | }, |
@@ -2910,7 +2910,7 @@ static struct clk_branch gcc_aggre0_cnoc_ahb_clk = { | |||
2910 | .name = "gcc_aggre0_cnoc_ahb_clk", | 2910 | .name = "gcc_aggre0_cnoc_ahb_clk", |
2911 | .parent_names = (const char *[]){ "config_noc_clk_src" }, | 2911 | .parent_names = (const char *[]){ "config_noc_clk_src" }, |
2912 | .num_parents = 1, | 2912 | .num_parents = 1, |
2913 | .flags = CLK_SET_RATE_PARENT, | 2913 | .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, |
2914 | .ops = &clk_branch2_ops, | 2914 | .ops = &clk_branch2_ops, |
2915 | }, | 2915 | }, |
2916 | }, | 2916 | }, |
@@ -2925,7 +2925,7 @@ static struct clk_branch gcc_smmu_aggre0_axi_clk = { | |||
2925 | .name = "gcc_smmu_aggre0_axi_clk", | 2925 | .name = "gcc_smmu_aggre0_axi_clk", |
2926 | .parent_names = (const char *[]){ "system_noc_clk_src" }, | 2926 | .parent_names = (const char *[]){ "system_noc_clk_src" }, |
2927 | .num_parents = 1, | 2927 | .num_parents = 1, |
2928 | .flags = CLK_SET_RATE_PARENT, | 2928 | .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, |
2929 | .ops = &clk_branch2_ops, | 2929 | .ops = &clk_branch2_ops, |
2930 | }, | 2930 | }, |
2931 | }, | 2931 | }, |
@@ -2940,7 +2940,7 @@ static struct clk_branch gcc_smmu_aggre0_ahb_clk = { | |||
2940 | .name = "gcc_smmu_aggre0_ahb_clk", | 2940 | .name = "gcc_smmu_aggre0_ahb_clk", |
2941 | .parent_names = (const char *[]){ "config_noc_clk_src" }, | 2941 | .parent_names = (const char *[]){ "config_noc_clk_src" }, |
2942 | .num_parents = 1, | 2942 | .num_parents = 1, |
2943 | .flags = CLK_SET_RATE_PARENT, | 2943 | .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, |
2944 | .ops = &clk_branch2_ops, | 2944 | .ops = &clk_branch2_ops, |
2945 | }, | 2945 | }, |
2946 | }, | 2946 | }, |