Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright 2015 Maxime Ripard
0004  *
0005  * Maxime Ripard <maxime.ripard@free-electrons.com>
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, /* ahb_sdram */
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, /* dram_output */
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);