2 * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
11 #include <linux/clk-provider.h>
12 #include <linux/clkdev.h>
13 #include <linux/clk/at91_pmc.h>
15 #include <linux/of_address.h>
20 #define SYSTEM_MAX_ID 31
22 #define SYSTEM_MAX_NAME_SZ 32
24 #define to_clk_system(hw) container_of(hw, struct clk_system, hw)
31 static int clk_system_enable(struct clk_hw
*hw
)
33 struct clk_system
*sys
= to_clk_system(hw
);
34 struct at91_pmc
*pmc
= sys
->pmc
;
36 pmc_write(pmc
, AT91_PMC_SCER
, 1 << sys
->id
);
40 static void clk_system_disable(struct clk_hw
*hw
)
42 struct clk_system
*sys
= to_clk_system(hw
);
43 struct at91_pmc
*pmc
= sys
->pmc
;
45 pmc_write(pmc
, AT91_PMC_SCDR
, 1 << sys
->id
);
48 static int clk_system_is_enabled(struct clk_hw
*hw
)
50 struct clk_system
*sys
= to_clk_system(hw
);
51 struct at91_pmc
*pmc
= sys
->pmc
;
53 return !!(pmc_read(pmc
, AT91_PMC_SCSR
) & (1 << sys
->id
));
56 static const struct clk_ops system_ops
= {
57 .enable
= clk_system_enable
,
58 .disable
= clk_system_disable
,
59 .is_enabled
= clk_system_is_enabled
,
62 static struct clk
* __init
63 at91_clk_register_system(struct at91_pmc
*pmc
, const char *name
,
64 const char *parent_name
, u8 id
)
66 struct clk_system
*sys
;
67 struct clk
*clk
= NULL
;
68 struct clk_init_data init
;
70 if (!parent_name
|| id
> SYSTEM_MAX_ID
)
71 return ERR_PTR(-EINVAL
);
73 sys
= kzalloc(sizeof(*sys
), GFP_KERNEL
);
75 return ERR_PTR(-ENOMEM
);
78 init
.ops
= &system_ops
;
79 init
.parent_names
= &parent_name
;
82 * CLK_IGNORE_UNUSED is used to avoid ddrck switch off.
83 * TODO : we should implement a driver supporting at91 ddr controller
84 * (see drivers/memory) which would request and enable the ddrck clock.
85 * When this is done we will be able to remove CLK_IGNORE_UNUSED flag.
87 init
.flags
= CLK_IGNORE_UNUSED
;
93 clk
= clk_register(NULL
, &sys
->hw
);
101 of_at91_clk_sys_setup(struct device_node
*np
, struct at91_pmc
*pmc
)
107 struct device_node
*sysclknp
;
108 const char *parent_name
;
110 num
= of_get_child_count(np
);
111 if (num
> (SYSTEM_MAX_ID
+ 1))
114 for_each_child_of_node(np
, sysclknp
) {
115 if (of_property_read_u32(sysclknp
, "reg", &id
))
118 if (of_property_read_string(np
, "clock-output-names", &name
))
119 name
= sysclknp
->name
;
121 parent_name
= of_clk_get_parent_name(sysclknp
, 0);
123 clk
= at91_clk_register_system(pmc
, name
, parent_name
, id
);
127 of_clk_add_provider(sysclknp
, of_clk_src_simple_get
, clk
);
131 void __init
of_at91rm9200_clk_sys_setup(struct device_node
*np
,
132 struct at91_pmc
*pmc
)
134 of_at91_clk_sys_setup(np
, pmc
);