@@ -22,35 +22,45 @@ static int sun8i_phy_clk_determine_rate(struct clk_hw *hw,
22
22
{
23
23
unsigned long rate = req -> rate ;
24
24
unsigned long best_rate = 0 ;
25
+ struct clk_hw * best_parent = NULL ;
25
26
struct clk_hw * parent ;
26
27
int best_div = 1 ;
27
- int i ;
28
+ int i , p ;
28
29
29
- parent = clk_hw_get_parent (hw );
30
-
31
- for (i = 1 ; i <= 16 ; i ++ ) {
32
- unsigned long ideal = rate * i ;
33
- unsigned long rounded ;
34
-
35
- rounded = clk_hw_round_rate (parent , ideal );
30
+ for (p = 0 ; p < clk_hw_get_num_parents (hw ); p ++ ) {
31
+ parent = clk_hw_get_parent_by_index (hw , p );
32
+ if (!parent )
33
+ continue ;
36
34
37
- if (rounded == ideal ) {
38
- best_rate = rounded ;
39
- best_div = i ;
40
- break ;
35
+ for (i = 1 ; i <= 16 ; i ++ ) {
36
+ unsigned long ideal = rate * i ;
37
+ unsigned long rounded ;
38
+
39
+ rounded = clk_hw_round_rate (parent , ideal );
40
+
41
+ if (rounded == ideal ) {
42
+ best_rate = rounded ;
43
+ best_div = i ;
44
+ best_parent = parent ;
45
+ break ;
46
+ }
47
+
48
+ if (!best_rate ||
49
+ abs (rate - rounded / i ) <
50
+ abs (rate - best_rate / best_div )) {
51
+ best_rate = rounded ;
52
+ best_div = i ;
53
+ best_parent = parent ;
54
+ }
41
55
}
42
56
43
- if (!best_rate ||
44
- abs (rate - rounded / i ) <
45
- abs (rate - best_rate / best_div )) {
46
- best_rate = rounded ;
47
- best_div = i ;
48
- }
57
+ if (best_rate / best_div == rate )
58
+ break ;
49
59
}
50
60
51
61
req -> rate = best_rate / best_div ;
52
62
req -> best_parent_rate = best_rate ;
53
- req -> best_parent_hw = parent ;
63
+ req -> best_parent_hw = best_parent ;
54
64
55
65
return 0 ;
56
66
}
@@ -95,30 +105,66 @@ static int sun8i_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate,
95
105
return 0 ;
96
106
}
97
107
108
+ static u8 sun8i_phy_clk_get_parent (struct clk_hw * hw )
109
+ {
110
+ struct sun8i_phy_clk * priv = hw_to_phy_clk (hw );
111
+ u32 reg ;
112
+
113
+ regmap_read (priv -> phy -> regs , SUN8I_HDMI_PHY_PLL_CFG1_REG , & reg );
114
+ reg = (reg & SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK ) >>
115
+ SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_SHIFT ;
116
+
117
+ return reg ;
118
+ }
119
+
120
+ static int sun8i_phy_clk_set_parent (struct clk_hw * hw , u8 index )
121
+ {
122
+ struct sun8i_phy_clk * priv = hw_to_phy_clk (hw );
123
+
124
+ if (index > 1 )
125
+ return - EINVAL ;
126
+
127
+ regmap_update_bits (priv -> phy -> regs , SUN8I_HDMI_PHY_PLL_CFG1_REG ,
128
+ SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_MSK ,
129
+ index << SUN8I_HDMI_PHY_PLL_CFG1_CKIN_SEL_SHIFT );
130
+
131
+ return 0 ;
132
+ }
133
+
98
134
static const struct clk_ops sun8i_phy_clk_ops = {
99
135
.determine_rate = sun8i_phy_clk_determine_rate ,
100
136
.recalc_rate = sun8i_phy_clk_recalc_rate ,
101
137
.set_rate = sun8i_phy_clk_set_rate ,
138
+
139
+ .get_parent = sun8i_phy_clk_get_parent ,
140
+ .set_parent = sun8i_phy_clk_set_parent ,
102
141
};
103
142
104
- int sun8i_phy_clk_create (struct sun8i_hdmi_phy * phy , struct device * dev )
143
+ int sun8i_phy_clk_create (struct sun8i_hdmi_phy * phy , struct device * dev ,
144
+ bool second_parent )
105
145
{
106
146
struct clk_init_data init ;
107
147
struct sun8i_phy_clk * priv ;
108
- const char * parents [1 ];
148
+ const char * parents [2 ];
109
149
110
150
parents [0 ] = __clk_get_name (phy -> clk_pll0 );
111
151
if (!parents [0 ])
112
152
return - ENODEV ;
113
153
154
+ if (second_parent ) {
155
+ parents [1 ] = __clk_get_name (phy -> clk_pll1 );
156
+ if (!parents [1 ])
157
+ return - ENODEV ;
158
+ }
159
+
114
160
priv = devm_kzalloc (dev , sizeof (* priv ), GFP_KERNEL );
115
161
if (!priv )
116
162
return - ENOMEM ;
117
163
118
164
init .name = "hdmi-phy-clk" ;
119
165
init .ops = & sun8i_phy_clk_ops ;
120
166
init .parent_names = parents ;
121
- init .num_parents = 1 ;
167
+ init .num_parents = second_parent ? 2 : 1 ;
122
168
init .flags = CLK_SET_RATE_PARENT ;
123
169
124
170
priv -> phy = phy ;
0 commit comments