1717
1818#include "pmc.h"
1919
20- #define PROG_SOURCE_MAX 5
20+ #define PROG_SOURCE_MAX 6
2121#define PROG_ID_MAX 7
2222
2323#define PROG_STATUS_MASK (id ) (1 << ((id) + 8))
24- #define PROG_PRES_MASK 0x7
25- #define PROG_PRES (layout , pckr ) ((pckr >> layout->pres_shift) & PROG_PRES_MASK)
24+ #define PROG_PRES (layout , pckr ) ((pckr >> layout->pres_shift) & layout->pres_mask)
2625#define PROG_MAX_RM9200_CSS 3
2726
2827struct clk_programmable_layout {
28+ u8 pres_mask ;
2929 u8 pres_shift ;
3030 u8 css_mask ;
3131 u8 have_slck_mck ;
32+ u8 is_pres_direct ;
3233};
3334
3435struct clk_programmable {
@@ -44,20 +45,29 @@ static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw,
4445 unsigned long parent_rate )
4546{
4647 struct clk_programmable * prog = to_clk_programmable (hw );
48+ const struct clk_programmable_layout * layout = prog -> layout ;
4749 unsigned int pckr ;
50+ unsigned long rate ;
4851
4952 regmap_read (prog -> regmap , AT91_PMC_PCKR (prog -> id ), & pckr );
5053
51- return parent_rate >> PROG_PRES (prog -> layout , pckr );
54+ if (layout -> is_pres_direct )
55+ rate = parent_rate / (PROG_PRES (layout , pckr ) + 1 );
56+ else
57+ rate = parent_rate >> PROG_PRES (layout , pckr );
58+
59+ return rate ;
5260}
5361
5462static int clk_programmable_determine_rate (struct clk_hw * hw ,
5563 struct clk_rate_request * req )
5664{
65+ struct clk_programmable * prog = to_clk_programmable (hw );
66+ const struct clk_programmable_layout * layout = prog -> layout ;
5767 struct clk_hw * parent ;
5868 long best_rate = - EINVAL ;
5969 unsigned long parent_rate ;
60- unsigned long tmp_rate ;
70+ unsigned long tmp_rate = 0 ;
6171 int shift ;
6272 int i ;
6373
@@ -67,10 +77,18 @@ static int clk_programmable_determine_rate(struct clk_hw *hw,
6777 continue ;
6878
6979 parent_rate = clk_hw_get_rate (parent );
70- for (shift = 0 ; shift < PROG_PRES_MASK ; shift ++ ) {
71- tmp_rate = parent_rate >> shift ;
72- if (tmp_rate <= req -> rate )
73- break ;
80+ if (layout -> is_pres_direct ) {
81+ for (shift = 0 ; shift <= layout -> pres_mask ; shift ++ ) {
82+ tmp_rate = parent_rate / (shift + 1 );
83+ if (tmp_rate <= req -> rate )
84+ break ;
85+ }
86+ } else {
87+ for (shift = 0 ; shift < layout -> pres_mask ; shift ++ ) {
88+ tmp_rate = parent_rate >> shift ;
89+ if (tmp_rate <= req -> rate )
90+ break ;
91+ }
7492 }
7593
7694 if (tmp_rate > req -> rate )
@@ -139,24 +157,28 @@ static int clk_programmable_set_rate(struct clk_hw *hw, unsigned long rate,
139157 struct clk_programmable * prog = to_clk_programmable (hw );
140158 const struct clk_programmable_layout * layout = prog -> layout ;
141159 unsigned long div = parent_rate / rate ;
142- unsigned int pckr ;
143160 int shift = 0 ;
144161
145- regmap_read (prog -> regmap , AT91_PMC_PCKR (prog -> id ), & pckr );
146-
147162 if (!div )
148163 return - EINVAL ;
149164
150- shift = fls (div ) - 1 ;
165+ if (layout -> is_pres_direct ) {
166+ shift = div - 1 ;
151167
152- if (div != (1 << shift ))
153- return - EINVAL ;
168+ if (shift > layout -> pres_mask )
169+ return - EINVAL ;
170+ } else {
171+ shift = fls (div ) - 1 ;
154172
155- if (shift >= PROG_PRES_MASK )
156- return - EINVAL ;
173+ if (div != (1 << shift ))
174+ return - EINVAL ;
175+
176+ if (shift >= layout -> pres_mask )
177+ return - EINVAL ;
178+ }
157179
158180 regmap_update_bits (prog -> regmap , AT91_PMC_PCKR (prog -> id ),
159- PROG_PRES_MASK << layout -> pres_shift ,
181+ layout -> pres_mask << layout -> pres_shift ,
160182 shift << layout -> pres_shift );
161183
162184 return 0 ;
@@ -212,21 +234,35 @@ at91_clk_register_programmable(struct regmap *regmap,
212234}
213235
214236static const struct clk_programmable_layout at91rm9200_programmable_layout = {
237+ .pres_mask = 0x7 ,
215238 .pres_shift = 2 ,
216239 .css_mask = 0x3 ,
217240 .have_slck_mck = 0 ,
241+ .is_pres_direct = 0 ,
218242};
219243
220244static const struct clk_programmable_layout at91sam9g45_programmable_layout = {
245+ .pres_mask = 0x7 ,
221246 .pres_shift = 2 ,
222247 .css_mask = 0x3 ,
223248 .have_slck_mck = 1 ,
249+ .is_pres_direct = 0 ,
224250};
225251
226252static const struct clk_programmable_layout at91sam9x5_programmable_layout = {
253+ .pres_mask = 0x7 ,
227254 .pres_shift = 4 ,
228255 .css_mask = 0x7 ,
229256 .have_slck_mck = 0 ,
257+ .is_pres_direct = 0 ,
258+ };
259+
260+ static const struct clk_programmable_layout sama5d2_programmable_layout = {
261+ .pres_mask = 0xff ,
262+ .pres_shift = 4 ,
263+ .css_mask = 0x7 ,
264+ .have_slck_mck = 0 ,
265+ .is_pres_direct = 1 ,
230266};
231267
232268static void __init
@@ -294,3 +330,10 @@ static void __init of_at91sam9x5_clk_prog_setup(struct device_node *np)
294330}
295331CLK_OF_DECLARE (at91sam9x5_clk_prog , "atmel,at91sam9x5-clk-programmable" ,
296332 of_at91sam9x5_clk_prog_setup );
333+
334+ static void __init of_sama5d2_clk_prog_setup (struct device_node * np )
335+ {
336+ of_at91_clk_prog_setup (np , & sama5d2_programmable_layout );
337+ }
338+ CLK_OF_DECLARE (sama5d2_clk_prog , "atmel,sama5d2-clk-programmable" ,
339+ of_sama5d2_clk_prog_setup );
0 commit comments