2 * Copyright (C) 2013 Emilio López <emilio@elopez.com.ar>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
8 * Adjustable factor-based clock implementation
11 #include <linux/clk-provider.h>
12 #include <linux/module.h>
13 #include <linux/slab.h>
15 #include <linux/err.h>
16 #include <linux/string.h>
18 #include <linux/delay.h>
20 #include "clk-factors.h"
23 * DOC: basic adjustable factor-based clock that cannot gate
25 * Traits of this clock:
26 * prepare - clk_prepare only ensures that parents are prepared
27 * enable - clk_enable only ensures that parents are enabled
28 * rate - rate is adjustable.
29 * clk->rate = (parent->rate * N * (K + 1) >> P) / (M + 1)
30 * parent - fixed parent. No clk_set_parent support
33 #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw)
35 #define SETMASK(len, pos) (((1U << (len)) - 1) << (pos))
36 #define CLRMASK(len, pos) (~(SETMASK(len, pos)))
37 #define FACTOR_GET(bit, len, reg) (((reg) & SETMASK(len, bit)) >> (bit))
39 #define FACTOR_SET(bit, len, reg, val) \
40 (((reg) & CLRMASK(len, bit)) | (val << (bit)))
42 static unsigned long clk_factors_recalc_rate(struct clk_hw
*hw
,
43 unsigned long parent_rate
)
45 u8 n
= 1, k
= 0, p
= 0, m
= 0;
48 struct clk_factors
*factors
= to_clk_factors(hw
);
49 struct clk_factors_config
*config
= factors
->config
;
51 /* Fetch the register value */
52 reg
= readl(factors
->reg
);
54 /* Get each individual factor if applicable */
55 if (config
->nwidth
!= SUNXI_FACTORS_NOT_APPLICABLE
)
56 n
= FACTOR_GET(config
->nshift
, config
->nwidth
, reg
);
57 if (config
->kwidth
!= SUNXI_FACTORS_NOT_APPLICABLE
)
58 k
= FACTOR_GET(config
->kshift
, config
->kwidth
, reg
);
59 if (config
->mwidth
!= SUNXI_FACTORS_NOT_APPLICABLE
)
60 m
= FACTOR_GET(config
->mshift
, config
->mwidth
, reg
);
61 if (config
->pwidth
!= SUNXI_FACTORS_NOT_APPLICABLE
)
62 p
= FACTOR_GET(config
->pshift
, config
->pwidth
, reg
);
64 /* Calculate the rate */
65 rate
= (parent_rate
* n
* (k
+ 1) >> p
) / (m
+ 1);
70 static long clk_factors_round_rate(struct clk_hw
*hw
, unsigned long rate
,
71 unsigned long *parent_rate
)
73 struct clk_factors
*factors
= to_clk_factors(hw
);
74 factors
->get_factors((u32
*)&rate
, (u32
)*parent_rate
,
75 NULL
, NULL
, NULL
, NULL
);
80 static int clk_factors_set_rate(struct clk_hw
*hw
, unsigned long rate
,
81 unsigned long parent_rate
)
83 u8 n
= 0, k
= 0, m
= 0, p
= 0;
85 struct clk_factors
*factors
= to_clk_factors(hw
);
86 struct clk_factors_config
*config
= factors
->config
;
87 unsigned long flags
= 0;
89 factors
->get_factors((u32
*)&rate
, (u32
)parent_rate
, &n
, &k
, &m
, &p
);
92 spin_lock_irqsave(factors
->lock
, flags
);
94 /* Fetch the register value */
95 reg
= readl(factors
->reg
);
97 /* Set up the new factors - macros do not do anything if width is 0 */
98 reg
= FACTOR_SET(config
->nshift
, config
->nwidth
, reg
, n
);
99 reg
= FACTOR_SET(config
->kshift
, config
->kwidth
, reg
, k
);
100 reg
= FACTOR_SET(config
->mshift
, config
->mwidth
, reg
, m
);
101 reg
= FACTOR_SET(config
->pshift
, config
->pwidth
, reg
, p
);
104 writel(reg
, factors
->reg
);
106 /* delay 500us so pll stabilizes */
107 __delay((rate
>> 20) * 500 / 2);
110 spin_unlock_irqrestore(factors
->lock
, flags
);
115 const struct clk_ops clk_factors_ops
= {
116 .recalc_rate
= clk_factors_recalc_rate
,
117 .round_rate
= clk_factors_round_rate
,
118 .set_rate
= clk_factors_set_rate
,