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
36 struct clk_factors_config
*config
;
37 void (*get_factors
) (u32
*rate
, u32 parent
, u8
*n
, u8
*k
, u8
*m
, u8
*p
);
41 #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw)
43 #define SETMASK(len, pos) (((-1U) >> (31-len)) << (pos))
44 #define CLRMASK(len, pos) (~(SETMASK(len, pos)))
45 #define FACTOR_GET(bit, len, reg) (((reg) & SETMASK(len, bit)) >> (bit))
47 #define FACTOR_SET(bit, len, reg, val) \
48 (((reg) & CLRMASK(len, bit)) | (val << (bit)))
50 static unsigned long clk_factors_recalc_rate(struct clk_hw
*hw
,
51 unsigned long parent_rate
)
53 u8 n
= 1, k
= 0, p
= 0, m
= 0;
56 struct clk_factors
*factors
= to_clk_factors(hw
);
57 struct clk_factors_config
*config
= factors
->config
;
59 /* Fetch the register value */
60 reg
= readl(factors
->reg
);
62 /* Get each individual factor if applicable */
63 if (config
->nwidth
!= SUNXI_FACTORS_NOT_APPLICABLE
)
64 n
= FACTOR_GET(config
->nshift
, config
->nwidth
, reg
);
65 if (config
->kwidth
!= SUNXI_FACTORS_NOT_APPLICABLE
)
66 k
= FACTOR_GET(config
->kshift
, config
->kwidth
, reg
);
67 if (config
->mwidth
!= SUNXI_FACTORS_NOT_APPLICABLE
)
68 m
= FACTOR_GET(config
->mshift
, config
->mwidth
, reg
);
69 if (config
->pwidth
!= SUNXI_FACTORS_NOT_APPLICABLE
)
70 p
= FACTOR_GET(config
->pshift
, config
->pwidth
, reg
);
72 /* Calculate the rate */
73 rate
= (parent_rate
* n
* (k
+ 1) >> p
) / (m
+ 1);
78 static long clk_factors_round_rate(struct clk_hw
*hw
, unsigned long rate
,
79 unsigned long *parent_rate
)
81 struct clk_factors
*factors
= to_clk_factors(hw
);
82 factors
->get_factors((u32
*)&rate
, (u32
)*parent_rate
,
83 NULL
, NULL
, NULL
, NULL
);
88 static int clk_factors_set_rate(struct clk_hw
*hw
, unsigned long rate
,
89 unsigned long parent_rate
)
93 struct clk_factors
*factors
= to_clk_factors(hw
);
94 struct clk_factors_config
*config
= factors
->config
;
95 unsigned long flags
= 0;
97 factors
->get_factors((u32
*)&rate
, (u32
)parent_rate
, &n
, &k
, &m
, &p
);
100 spin_lock_irqsave(factors
->lock
, flags
);
102 /* Fetch the register value */
103 reg
= readl(factors
->reg
);
105 /* Set up the new factors - macros do not do anything if width is 0 */
106 reg
= FACTOR_SET(config
->nshift
, config
->nwidth
, reg
, n
);
107 reg
= FACTOR_SET(config
->kshift
, config
->kwidth
, reg
, k
);
108 reg
= FACTOR_SET(config
->mshift
, config
->mwidth
, reg
, m
);
109 reg
= FACTOR_SET(config
->pshift
, config
->pwidth
, reg
, p
);
112 writel(reg
, factors
->reg
);
114 /* delay 500us so pll stabilizes */
115 __delay((rate
>> 20) * 500 / 2);
118 spin_unlock_irqrestore(factors
->lock
, flags
);
123 static const struct clk_ops clk_factors_ops
= {
124 .recalc_rate
= clk_factors_recalc_rate
,
125 .round_rate
= clk_factors_round_rate
,
126 .set_rate
= clk_factors_set_rate
,
130 * clk_register_factors - register a factors clock with
131 * the clock framework
132 * @dev: device registering this clock
133 * @name: name of this clock
134 * @parent_name: name of clock's parent
135 * @flags: framework-specific flags
136 * @reg: register address to adjust factors
137 * @config: shift and width of factors n, k, m and p
138 * @get_factors: function to calculate the factors for a given frequency
139 * @lock: shared register lock for this clock
141 struct clk
*clk_register_factors(struct device
*dev
, const char *name
,
142 const char *parent_name
,
143 unsigned long flags
, void __iomem
*reg
,
144 struct clk_factors_config
*config
,
145 void (*get_factors
)(u32
*rate
, u32 parent
,
146 u8
*n
, u8
*k
, u8
*m
, u8
*p
),
149 struct clk_factors
*factors
;
151 struct clk_init_data init
;
153 /* allocate the factors */
154 factors
= kzalloc(sizeof(struct clk_factors
), GFP_KERNEL
);
156 pr_err("%s: could not allocate factors clk\n", __func__
);
157 return ERR_PTR(-ENOMEM
);
161 init
.ops
= &clk_factors_ops
;
163 init
.parent_names
= (parent_name
? &parent_name
: NULL
);
164 init
.num_parents
= (parent_name
? 1 : 0);
166 /* struct clk_factors assignments */
168 factors
->config
= config
;
169 factors
->lock
= lock
;
170 factors
->hw
.init
= &init
;
171 factors
->get_factors
= get_factors
;
173 /* register the clock */
174 clk
= clk_register(dev
, &factors
->hw
);