aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk/qcom
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/qcom')
-rw-r--r--drivers/clk/qcom/clk-regmap-divider.c20
-rw-r--r--drivers/clk/qcom/clk-rpm.c79
-rw-r--r--drivers/clk/qcom/clk-smd-rpm.c9
-rw-r--r--drivers/clk/qcom/gcc-msm8996.c8
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 = &divider->clkr; 30 struct clk_regmap *clkr = &divider->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
49static long div_round_rate(struct clk_hw *hw, unsigned long rate, 41static 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
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)
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
700static int rpm_smd_clk_remove(struct platform_device *pdev)
701{
702 of_clk_del_provider(pdev->dev.of_node);
703 return 0;
704}
705
706static struct platform_driver rpm_smd_clk_driver = { 700static 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
715static int __init rpm_smd_clk_init(void) 708static 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 },