1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2016 Maxime Ripard
4 * Maxime Ripard <maxime.ripard@free-electrons.com>
5 */
6 #include "ccu.h"
7 #include "ccu_frac.h"
8 #include <hal_log.h>
9
ccu_frac_helper_is_enabled(struct ccu_common * common,struct ccu_frac_internal * cf)10 bool ccu_frac_helper_is_enabled(struct ccu_common *common,
11 struct ccu_frac_internal *cf)
12 {
13 if (!(common->features & CCU_FEATURE_FRACTIONAL))
14 {
15 return false;
16 }
17
18 return !(readl(common->base + common->reg) & cf->enable);
19 }
20
ccu_frac_helper_enable(struct ccu_common * common,struct ccu_frac_internal * cf)21 void ccu_frac_helper_enable(struct ccu_common *common,
22 struct ccu_frac_internal *cf)
23 {
24 u32 reg;
25 u32 __cspr;
26
27 if (!(common->features & CCU_FEATURE_FRACTIONAL))
28 {
29 return;
30 }
31
32 __cspr = hal_spin_lock_irqsave(&common->lock);
33 reg = readl(common->base + common->reg);
34 writel(reg & ~cf->enable, common->base + common->reg);
35 hal_spin_unlock_irqrestore(&common->lock, __cspr);
36 }
37
ccu_frac_helper_disable(struct ccu_common * common,struct ccu_frac_internal * cf)38 void ccu_frac_helper_disable(struct ccu_common *common,
39 struct ccu_frac_internal *cf)
40 {
41 u32 reg;
42 u32 __cspr;
43
44 if (!(common->features & CCU_FEATURE_FRACTIONAL))
45 {
46 return;
47 }
48
49 __cspr = hal_spin_lock_irqsave(&common->lock);
50 reg = readl(common->base + common->reg);
51 writel(reg | cf->enable, common->base + common->reg);
52 hal_spin_unlock_irqrestore(&common->lock, __cspr);
53 }
54
ccu_frac_helper_has_rate(struct ccu_common * common,struct ccu_frac_internal * cf,unsigned long rate)55 bool ccu_frac_helper_has_rate(struct ccu_common *common,
56 struct ccu_frac_internal *cf,
57 unsigned long rate)
58 {
59 if (!(common->features & CCU_FEATURE_FRACTIONAL))
60 {
61 return false;
62 }
63
64 return (cf->rates[0] == rate) || (cf->rates[1] == rate);
65 }
66
ccu_frac_helper_read_rate(struct ccu_common * common,struct ccu_frac_internal * cf)67 unsigned long ccu_frac_helper_read_rate(struct ccu_common *common,
68 struct ccu_frac_internal *cf)
69 {
70 u32 reg;
71
72 hal_log_debug("%s: Read fractional\n", clk_hw_get_name(&common->hw));
73
74 if (!(common->features & CCU_FEATURE_FRACTIONAL))
75 {
76 return 0;
77 }
78
79 hal_log_debug("%s: clock is fractional (rates %lu and %lu)\n",
80 clk_hw_get_name(&common->hw), cf->rates[0], cf->rates[1]);
81
82 reg = readl(common->base + common->reg);
83
84 hal_log_debug("%s: clock reg is 0x%x (select is 0x%x)\n",
85 clk_hw_get_name(&common->hw), reg, cf->select);
86
87 return (reg & cf->select) ? cf->rates[1] : cf->rates[0];
88 }
89
ccu_frac_helper_set_rate(struct ccu_common * common,struct ccu_frac_internal * cf,unsigned long rate,u32 lock)90 int ccu_frac_helper_set_rate(struct ccu_common *common,
91 struct ccu_frac_internal *cf,
92 unsigned long rate, u32 lock)
93 {
94 u32 reg, sel;
95 u32 __cspr;
96
97 if (!(common->features & CCU_FEATURE_FRACTIONAL))
98 {
99 return -1;
100 }
101
102 if (cf->rates[0] == rate)
103 {
104 sel = 0;
105 }
106 else if (cf->rates[1] == rate)
107 {
108 sel = cf->select;
109 }
110 else
111 {
112 return -1;
113 }
114
115 __cspr = hal_spin_lock_irqsave(&common->lock);
116 reg = readl(common->base + common->reg);
117 reg &= ~cf->select;
118 writel(reg | sel, common->base + common->reg);
119 hal_spin_unlock_irqrestore(&common->lock, __cspr);
120
121 ccu_helper_wait_for_lock(common, lock);
122 return 0;
123 }
124