Skip to content

Commit 15ed8ce

Browse files
shenkibebarino
authored andcommitted
clk: aspeed: Register gated clocks
The majority of the clocks in the system are gates paired with a reset controller that holds the IP in reset. This borrows from clk_hw_register_gate, but registers two 'gates', one to control the clock enable register and the other to control the reset IP. This allows us to enforce the ordering: 1. Place IP in reset 2. Enable clock 3. Delay 4. Release reset There are some gates that do not have an associated reset; these are handled by using -1 as the index for the reset. Reviewed-by: Andrew Jeffery <[email protected]> Signed-off-by: Joel Stanley <[email protected]> Reviewed-by: Benjamin Herrenschmidt <[email protected]> Signed-off-by: Stephen Boyd <[email protected]>
1 parent 98f3118 commit 15ed8ce

File tree

1 file changed

+130
-0
lines changed

1 file changed

+130
-0
lines changed

drivers/clk/clk-aspeed.c

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,13 +204,114 @@ static const struct aspeed_clk_soc_data ast2400_data = {
204204
.calc_pll = aspeed_ast2400_calc_pll,
205205
};
206206

207+
static int aspeed_clk_enable(struct clk_hw *hw)
208+
{
209+
struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw);
210+
unsigned long flags;
211+
u32 clk = BIT(gate->clock_idx);
212+
u32 rst = BIT(gate->reset_idx);
213+
214+
spin_lock_irqsave(gate->lock, flags);
215+
216+
if (gate->reset_idx >= 0) {
217+
/* Put IP in reset */
218+
regmap_update_bits(gate->map, ASPEED_RESET_CTRL, rst, rst);
219+
220+
/* Delay 100us */
221+
udelay(100);
222+
}
223+
224+
/* Enable clock */
225+
regmap_update_bits(gate->map, ASPEED_CLK_STOP_CTRL, clk, 0);
226+
227+
if (gate->reset_idx >= 0) {
228+
/* A delay of 10ms is specified by the ASPEED docs */
229+
mdelay(10);
230+
231+
/* Take IP out of reset */
232+
regmap_update_bits(gate->map, ASPEED_RESET_CTRL, rst, 0);
233+
}
234+
235+
spin_unlock_irqrestore(gate->lock, flags);
236+
237+
return 0;
238+
}
239+
240+
static void aspeed_clk_disable(struct clk_hw *hw)
241+
{
242+
struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw);
243+
unsigned long flags;
244+
u32 clk = BIT(gate->clock_idx);
245+
246+
spin_lock_irqsave(gate->lock, flags);
247+
248+
regmap_update_bits(gate->map, ASPEED_CLK_STOP_CTRL, clk, clk);
249+
250+
spin_unlock_irqrestore(gate->lock, flags);
251+
}
252+
253+
static int aspeed_clk_is_enabled(struct clk_hw *hw)
254+
{
255+
struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw);
256+
u32 clk = BIT(gate->clock_idx);
257+
u32 reg;
258+
259+
regmap_read(gate->map, ASPEED_CLK_STOP_CTRL, &reg);
260+
261+
return (reg & clk) ? 0 : 1;
262+
}
263+
264+
static const struct clk_ops aspeed_clk_gate_ops = {
265+
.enable = aspeed_clk_enable,
266+
.disable = aspeed_clk_disable,
267+
.is_enabled = aspeed_clk_is_enabled,
268+
};
269+
270+
static struct clk_hw *aspeed_clk_hw_register_gate(struct device *dev,
271+
const char *name, const char *parent_name, unsigned long flags,
272+
struct regmap *map, u8 clock_idx, u8 reset_idx,
273+
u8 clk_gate_flags, spinlock_t *lock)
274+
{
275+
struct aspeed_clk_gate *gate;
276+
struct clk_init_data init;
277+
struct clk_hw *hw;
278+
int ret;
279+
280+
gate = kzalloc(sizeof(*gate), GFP_KERNEL);
281+
if (!gate)
282+
return ERR_PTR(-ENOMEM);
283+
284+
init.name = name;
285+
init.ops = &aspeed_clk_gate_ops;
286+
init.flags = flags;
287+
init.parent_names = parent_name ? &parent_name : NULL;
288+
init.num_parents = parent_name ? 1 : 0;
289+
290+
gate->map = map;
291+
gate->clock_idx = clock_idx;
292+
gate->reset_idx = reset_idx;
293+
gate->flags = clk_gate_flags;
294+
gate->lock = lock;
295+
gate->hw.init = &init;
296+
297+
hw = &gate->hw;
298+
ret = clk_hw_register(dev, hw);
299+
if (ret) {
300+
kfree(gate);
301+
hw = ERR_PTR(ret);
302+
}
303+
304+
return hw;
305+
}
306+
207307
static int aspeed_clk_probe(struct platform_device *pdev)
208308
{
209309
const struct aspeed_clk_soc_data *soc_data;
210310
struct device *dev = &pdev->dev;
211311
struct regmap *map;
212312
struct clk_hw *hw;
213313
u32 val, rate;
314+
int i;
214315

215316
map = syscon_node_to_regmap(dev->of_node);
216317
if (IS_ERR(map)) {
@@ -283,6 +384,35 @@ static int aspeed_clk_probe(struct platform_device *pdev)
283384
return PTR_ERR(hw);
284385
aspeed_clk_data->hws[ASPEED_CLK_BCLK] = hw;
285386

387+
/*
388+
* TODO: There are a number of clocks that not included in this driver
389+
* as more information is required:
390+
* D2-PLL
391+
* D-PLL
392+
* YCLK
393+
* RGMII
394+
* RMII
395+
* UART[1..5] clock source mux
396+
* Video Engine (ECLK) mux and clock divider
397+
*/
398+
399+
for (i = 0; i < ARRAY_SIZE(aspeed_gates); i++) {
400+
const struct aspeed_gate_data *gd = &aspeed_gates[i];
401+
402+
hw = aspeed_clk_hw_register_gate(dev,
403+
gd->name,
404+
gd->parent_name,
405+
gd->flags,
406+
map,
407+
gd->clock_idx,
408+
gd->reset_idx,
409+
CLK_GATE_SET_TO_DISABLE,
410+
&aspeed_clk_lock);
411+
if (IS_ERR(hw))
412+
return PTR_ERR(hw);
413+
aspeed_clk_data->hws[i] = hw;
414+
}
415+
286416
return 0;
287417
};
288418

0 commit comments

Comments
 (0)