0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/clk.h>
0009 #include <linux/clk-provider.h>
0010 #include <linux/io.h>
0011 #include <linux/of.h>
0012 #include <linux/of_address.h>
0013 #include <linux/slab.h>
0014 #include <linux/spinlock.h>
0015
0016 static DEFINE_SPINLOCK(gates_lock);
0017
0018 static void __init sunxi_simple_gates_setup(struct device_node *node,
0019 const int protected[],
0020 int nprotected)
0021 {
0022 struct clk_onecell_data *clk_data;
0023 const char *clk_parent, *clk_name;
0024 struct property *prop;
0025 struct resource res;
0026 void __iomem *clk_reg;
0027 void __iomem *reg;
0028 const __be32 *p;
0029 int number, i = 0, j;
0030 u8 clk_bit;
0031 u32 index;
0032
0033 reg = of_io_request_and_map(node, 0, of_node_full_name(node));
0034 if (IS_ERR(reg))
0035 return;
0036
0037 clk_parent = of_clk_get_parent_name(node, 0);
0038
0039 clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
0040 if (!clk_data)
0041 goto err_unmap;
0042
0043 number = of_property_count_u32_elems(node, "clock-indices");
0044 of_property_read_u32_index(node, "clock-indices", number - 1, &number);
0045
0046 clk_data->clks = kcalloc(number + 1, sizeof(struct clk *), GFP_KERNEL);
0047 if (!clk_data->clks)
0048 goto err_free_data;
0049
0050 of_property_for_each_u32(node, "clock-indices", prop, p, index) {
0051 of_property_read_string_index(node, "clock-output-names",
0052 i, &clk_name);
0053
0054 clk_reg = reg + 4 * (index / 32);
0055 clk_bit = index % 32;
0056
0057 clk_data->clks[index] = clk_register_gate(NULL, clk_name,
0058 clk_parent, 0,
0059 clk_reg,
0060 clk_bit,
0061 0, &gates_lock);
0062 i++;
0063
0064 if (IS_ERR(clk_data->clks[index])) {
0065 WARN_ON(true);
0066 continue;
0067 }
0068
0069 for (j = 0; j < nprotected; j++)
0070 if (protected[j] == index)
0071 clk_prepare_enable(clk_data->clks[index]);
0072
0073 }
0074
0075 clk_data->clk_num = number + 1;
0076 of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
0077
0078 return;
0079
0080 err_free_data:
0081 kfree(clk_data);
0082 err_unmap:
0083 iounmap(reg);
0084 of_address_to_resource(node, 0, &res);
0085 release_mem_region(res.start, resource_size(&res));
0086 }
0087
0088 static void __init sunxi_simple_gates_init(struct device_node *node)
0089 {
0090 sunxi_simple_gates_setup(node, NULL, 0);
0091 }
0092
0093 CLK_OF_DECLARE(sun4i_a10_gates, "allwinner,sun4i-a10-gates-clk",
0094 sunxi_simple_gates_init);
0095 CLK_OF_DECLARE(sun4i_a10_apb0, "allwinner,sun4i-a10-apb0-gates-clk",
0096 sunxi_simple_gates_init);
0097 CLK_OF_DECLARE(sun4i_a10_apb1, "allwinner,sun4i-a10-apb1-gates-clk",
0098 sunxi_simple_gates_init);
0099 CLK_OF_DECLARE(sun4i_a10_axi, "allwinner,sun4i-a10-axi-gates-clk",
0100 sunxi_simple_gates_init);
0101 CLK_OF_DECLARE(sun5i_a10s_apb0, "allwinner,sun5i-a10s-apb0-gates-clk",
0102 sunxi_simple_gates_init);
0103 CLK_OF_DECLARE(sun5i_a10s_apb1, "allwinner,sun5i-a10s-apb1-gates-clk",
0104 sunxi_simple_gates_init);
0105 CLK_OF_DECLARE(sun5i_a13_apb0, "allwinner,sun5i-a13-apb0-gates-clk",
0106 sunxi_simple_gates_init);
0107 CLK_OF_DECLARE(sun5i_a13_apb1, "allwinner,sun5i-a13-apb1-gates-clk",
0108 sunxi_simple_gates_init);
0109 CLK_OF_DECLARE(sun6i_a31_ahb1, "allwinner,sun6i-a31-ahb1-gates-clk",
0110 sunxi_simple_gates_init);
0111 CLK_OF_DECLARE(sun6i_a31_apb1, "allwinner,sun6i-a31-apb1-gates-clk",
0112 sunxi_simple_gates_init);
0113 CLK_OF_DECLARE(sun6i_a31_apb2, "allwinner,sun6i-a31-apb2-gates-clk",
0114 sunxi_simple_gates_init);
0115 CLK_OF_DECLARE(sun7i_a20_apb0, "allwinner,sun7i-a20-apb0-gates-clk",
0116 sunxi_simple_gates_init);
0117 CLK_OF_DECLARE(sun7i_a20_apb1, "allwinner,sun7i-a20-apb1-gates-clk",
0118 sunxi_simple_gates_init);
0119 CLK_OF_DECLARE(sun8i_a23_ahb1, "allwinner,sun8i-a23-ahb1-gates-clk",
0120 sunxi_simple_gates_init);
0121 CLK_OF_DECLARE(sun8i_a23_apb1, "allwinner,sun8i-a23-apb1-gates-clk",
0122 sunxi_simple_gates_init);
0123 CLK_OF_DECLARE(sun8i_a23_apb2, "allwinner,sun8i-a23-apb2-gates-clk",
0124 sunxi_simple_gates_init);
0125 CLK_OF_DECLARE(sun8i_a33_ahb1, "allwinner,sun8i-a33-ahb1-gates-clk",
0126 sunxi_simple_gates_init);
0127 CLK_OF_DECLARE(sun8i_a83t_apb0, "allwinner,sun8i-a83t-apb0-gates-clk",
0128 sunxi_simple_gates_init);
0129 CLK_OF_DECLARE(sun9i_a80_ahb0, "allwinner,sun9i-a80-ahb0-gates-clk",
0130 sunxi_simple_gates_init);
0131 CLK_OF_DECLARE(sun9i_a80_ahb1, "allwinner,sun9i-a80-ahb1-gates-clk",
0132 sunxi_simple_gates_init);
0133 CLK_OF_DECLARE(sun9i_a80_ahb2, "allwinner,sun9i-a80-ahb2-gates-clk",
0134 sunxi_simple_gates_init);
0135 CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-gates-clk",
0136 sunxi_simple_gates_init);
0137 CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-gates-clk",
0138 sunxi_simple_gates_init);
0139 CLK_OF_DECLARE(sun9i_a80_apbs, "allwinner,sun9i-a80-apbs-gates-clk",
0140 sunxi_simple_gates_init);
0141
0142 static const int sun4i_a10_ahb_critical_clocks[] __initconst = {
0143 14,
0144 };
0145
0146 static void __init sun4i_a10_ahb_init(struct device_node *node)
0147 {
0148 sunxi_simple_gates_setup(node, sun4i_a10_ahb_critical_clocks,
0149 ARRAY_SIZE(sun4i_a10_ahb_critical_clocks));
0150 }
0151 CLK_OF_DECLARE(sun4i_a10_ahb, "allwinner,sun4i-a10-ahb-gates-clk",
0152 sun4i_a10_ahb_init);
0153 CLK_OF_DECLARE(sun5i_a10s_ahb, "allwinner,sun5i-a10s-ahb-gates-clk",
0154 sun4i_a10_ahb_init);
0155 CLK_OF_DECLARE(sun5i_a13_ahb, "allwinner,sun5i-a13-ahb-gates-clk",
0156 sun4i_a10_ahb_init);
0157 CLK_OF_DECLARE(sun7i_a20_ahb, "allwinner,sun7i-a20-ahb-gates-clk",
0158 sun4i_a10_ahb_init);
0159
0160 static const int sun4i_a10_dram_critical_clocks[] __initconst = {
0161 15,
0162 };
0163
0164 static void __init sun4i_a10_dram_init(struct device_node *node)
0165 {
0166 sunxi_simple_gates_setup(node, sun4i_a10_dram_critical_clocks,
0167 ARRAY_SIZE(sun4i_a10_dram_critical_clocks));
0168 }
0169 CLK_OF_DECLARE(sun4i_a10_dram, "allwinner,sun4i-a10-dram-gates-clk",
0170 sun4i_a10_dram_init);