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 )
@@ -147,16 +165,23 @@ static int clk_programmable_set_rate(struct clk_hw *hw, unsigned long rate,
147165 if (!div )
148166 return - EINVAL ;
149167
150- shift = fls (div ) - 1 ;
168+ if (layout -> is_pres_direct ) {
169+ shift = div - 1 ;
151170
152- if (div != (1 << shift ))
153- return - EINVAL ;
171+ if (shift > layout -> pres_mask )
172+ return - EINVAL ;
173+ } else {
174+ shift = fls (div ) - 1 ;
154175
155- if (shift >= PROG_PRES_MASK )
156- return - EINVAL ;
176+ if (div != (1 << shift ))
177+ return - EINVAL ;
178+
179+ if (shift >= layout -> pres_mask )
180+ return - EINVAL ;
181+ }
157182
158183 regmap_update_bits (prog -> regmap , AT91_PMC_PCKR (prog -> id ),
159- PROG_PRES_MASK << layout -> pres_shift ,
184+ layout -> pres_mask << layout -> pres_shift ,
160185 shift << layout -> pres_shift );
161186
162187 return 0 ;
@@ -210,21 +235,35 @@ at91_clk_register_programmable(struct regmap *regmap,
210235}
211236
212237static const struct clk_programmable_layout at91rm9200_programmable_layout = {
238+ .pres_mask = 0x7 ,
213239 .pres_shift = 2 ,
214240 .css_mask = 0x3 ,
215241 .have_slck_mck = 0 ,
242+ .is_pres_direct = 0 ,
216243};
217244
218245static const struct clk_programmable_layout at91sam9g45_programmable_layout = {
246+ .pres_mask = 0x7 ,
219247 .pres_shift = 2 ,
220248 .css_mask = 0x3 ,
221249 .have_slck_mck = 1 ,
250+ .is_pres_direct = 0 ,
222251};
223252
224253static const struct clk_programmable_layout at91sam9x5_programmable_layout = {
254+ .pres_mask = 0x7 ,
225255 .pres_shift = 4 ,
226256 .css_mask = 0x7 ,
227257 .have_slck_mck = 0 ,
258+ .is_pres_direct = 0 ,
259+ };
260+
261+ static const struct clk_programmable_layout sama5d2_programmable_layout = {
262+ .pres_mask = 0xff ,
263+ .pres_shift = 4 ,
264+ .css_mask = 0x7 ,
265+ .have_slck_mck = 0 ,
266+ .is_pres_direct = 1 ,
228267};
229268
230269static void __init
@@ -292,3 +331,10 @@ static void __init of_at91sam9x5_clk_prog_setup(struct device_node *np)
292331}
293332CLK_OF_DECLARE (at91sam9x5_clk_prog , "atmel,at91sam9x5-clk-programmable" ,
294333 of_at91sam9x5_clk_prog_setup );
334+
335+ static void __init of_sama5d2_clk_prog_setup (struct device_node * np )
336+ {
337+ of_at91_clk_prog_setup (np , & sama5d2_programmable_layout );
338+ }
339+ CLK_OF_DECLARE (sama5d2_clk_prog , "atmel,sama5d2-clk-programmable" ,
340+ of_sama5d2_clk_prog_setup );
0 commit comments