linux/drivers/clk/sunxi/clk-simple-gates.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright 2015 Maxime Ripard
   4 *
   5 * Maxime Ripard <maxime.ripard@free-electrons.com>
   6 */
   7
   8#include <linux/clk.h>
   9#include <linux/clk-provider.h>
  10#include <linux/io.h>
  11#include <linux/of.h>
  12#include <linux/of_address.h>
  13#include <linux/slab.h>
  14#include <linux/spinlock.h>
  15
  16static DEFINE_SPINLOCK(gates_lock);
  17
  18static void __init sunxi_simple_gates_setup(struct device_node *node,
  19                                            const int protected[],
  20                                            int nprotected)
  21{
  22        struct clk_onecell_data *clk_data;
  23        const char *clk_parent, *clk_name;
  24        struct property *prop;
  25        struct resource res;
  26        void __iomem *clk_reg;
  27        void __iomem *reg;
  28        const __be32 *p;
  29        int number, i = 0, j;
  30        u8 clk_bit;
  31        u32 index;
  32
  33        reg = of_io_request_and_map(node, 0, of_node_full_name(node));
  34        if (IS_ERR(reg))
  35                return;
  36
  37        clk_parent = of_clk_get_parent_name(node, 0);
  38
  39        clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
  40        if (!clk_data)
  41                goto err_unmap;
  42
  43        number = of_property_count_u32_elems(node, "clock-indices");
  44        of_property_read_u32_index(node, "clock-indices", number - 1, &number);
  45
  46        clk_data->clks = kcalloc(number + 1, sizeof(struct clk *), GFP_KERNEL);
  47        if (!clk_data->clks)
  48                goto err_free_data;
  49
  50        of_property_for_each_u32(node, "clock-indices", prop, p, index) {
  51                of_property_read_string_index(node, "clock-output-names",
  52                                              i, &clk_name);
  53
  54                clk_reg = reg + 4 * (index / 32);
  55                clk_bit = index % 32;
  56
  57                clk_data->clks[index] = clk_register_gate(NULL, clk_name,
  58                                                          clk_parent, 0,
  59                                                          clk_reg,
  60                                                          clk_bit,
  61                                                          0, &gates_lock);
  62                i++;
  63
  64                if (IS_ERR(clk_data->clks[index])) {
  65                        WARN_ON(true);
  66                        continue;
  67                }
  68
  69                for (j = 0; j < nprotected; j++)
  70                        if (protected[j] == index)
  71                                clk_prepare_enable(clk_data->clks[index]);
  72
  73        }
  74
  75        clk_data->clk_num = number + 1;
  76        of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
  77
  78        return;
  79
  80err_free_data:
  81        kfree(clk_data);
  82err_unmap:
  83        iounmap(reg);
  84        of_address_to_resource(node, 0, &res);
  85        release_mem_region(res.start, resource_size(&res));
  86}
  87
  88static void __init sunxi_simple_gates_init(struct device_node *node)
  89{
  90        sunxi_simple_gates_setup(node, NULL, 0);
  91}
  92
  93CLK_OF_DECLARE(sun4i_a10_gates, "allwinner,sun4i-a10-gates-clk",
  94               sunxi_simple_gates_init);
  95CLK_OF_DECLARE(sun4i_a10_apb0, "allwinner,sun4i-a10-apb0-gates-clk",
  96               sunxi_simple_gates_init);
  97CLK_OF_DECLARE(sun4i_a10_apb1, "allwinner,sun4i-a10-apb1-gates-clk",
  98               sunxi_simple_gates_init);
  99CLK_OF_DECLARE(sun4i_a10_axi, "allwinner,sun4i-a10-axi-gates-clk",
 100               sunxi_simple_gates_init);
 101CLK_OF_DECLARE(sun5i_a10s_apb0, "allwinner,sun5i-a10s-apb0-gates-clk",
 102               sunxi_simple_gates_init);
 103CLK_OF_DECLARE(sun5i_a10s_apb1, "allwinner,sun5i-a10s-apb1-gates-clk",
 104               sunxi_simple_gates_init);
 105CLK_OF_DECLARE(sun5i_a13_apb0, "allwinner,sun5i-a13-apb0-gates-clk",
 106               sunxi_simple_gates_init);
 107CLK_OF_DECLARE(sun5i_a13_apb1, "allwinner,sun5i-a13-apb1-gates-clk",
 108               sunxi_simple_gates_init);
 109CLK_OF_DECLARE(sun6i_a31_ahb1, "allwinner,sun6i-a31-ahb1-gates-clk",
 110               sunxi_simple_gates_init);
 111CLK_OF_DECLARE(sun6i_a31_apb1, "allwinner,sun6i-a31-apb1-gates-clk",
 112               sunxi_simple_gates_init);
 113CLK_OF_DECLARE(sun6i_a31_apb2, "allwinner,sun6i-a31-apb2-gates-clk",
 114               sunxi_simple_gates_init);
 115CLK_OF_DECLARE(sun7i_a20_apb0, "allwinner,sun7i-a20-apb0-gates-clk",
 116               sunxi_simple_gates_init);
 117CLK_OF_DECLARE(sun7i_a20_apb1, "allwinner,sun7i-a20-apb1-gates-clk",
 118               sunxi_simple_gates_init);
 119CLK_OF_DECLARE(sun8i_a23_ahb1, "allwinner,sun8i-a23-ahb1-gates-clk",
 120               sunxi_simple_gates_init);
 121CLK_OF_DECLARE(sun8i_a23_apb1, "allwinner,sun8i-a23-apb1-gates-clk",
 122               sunxi_simple_gates_init);
 123CLK_OF_DECLARE(sun8i_a23_apb2, "allwinner,sun8i-a23-apb2-gates-clk",
 124               sunxi_simple_gates_init);
 125CLK_OF_DECLARE(sun8i_a33_ahb1, "allwinner,sun8i-a33-ahb1-gates-clk",
 126               sunxi_simple_gates_init);
 127CLK_OF_DECLARE(sun8i_a83t_apb0, "allwinner,sun8i-a83t-apb0-gates-clk",
 128               sunxi_simple_gates_init);
 129CLK_OF_DECLARE(sun9i_a80_ahb0, "allwinner,sun9i-a80-ahb0-gates-clk",
 130               sunxi_simple_gates_init);
 131CLK_OF_DECLARE(sun9i_a80_ahb1, "allwinner,sun9i-a80-ahb1-gates-clk",
 132               sunxi_simple_gates_init);
 133CLK_OF_DECLARE(sun9i_a80_ahb2, "allwinner,sun9i-a80-ahb2-gates-clk",
 134               sunxi_simple_gates_init);
 135CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-gates-clk",
 136               sunxi_simple_gates_init);
 137CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-gates-clk",
 138               sunxi_simple_gates_init);
 139CLK_OF_DECLARE(sun9i_a80_apbs, "allwinner,sun9i-a80-apbs-gates-clk",
 140               sunxi_simple_gates_init);
 141
 142static const int sun4i_a10_ahb_critical_clocks[] __initconst = {
 143        14,     /* ahb_sdram */
 144};
 145
 146static void __init sun4i_a10_ahb_init(struct device_node *node)
 147{
 148        sunxi_simple_gates_setup(node, sun4i_a10_ahb_critical_clocks,
 149                                 ARRAY_SIZE(sun4i_a10_ahb_critical_clocks));
 150}
 151CLK_OF_DECLARE(sun4i_a10_ahb, "allwinner,sun4i-a10-ahb-gates-clk",
 152               sun4i_a10_ahb_init);
 153CLK_OF_DECLARE(sun5i_a10s_ahb, "allwinner,sun5i-a10s-ahb-gates-clk",
 154               sun4i_a10_ahb_init);
 155CLK_OF_DECLARE(sun5i_a13_ahb, "allwinner,sun5i-a13-ahb-gates-clk",
 156               sun4i_a10_ahb_init);
 157CLK_OF_DECLARE(sun7i_a20_ahb, "allwinner,sun7i-a20-ahb-gates-clk",
 158               sun4i_a10_ahb_init);
 159
 160static const int sun4i_a10_dram_critical_clocks[] __initconst = {
 161        15,     /* dram_output */
 162};
 163
 164static void __init sun4i_a10_dram_init(struct device_node *node)
 165{
 166        sunxi_simple_gates_setup(node, sun4i_a10_dram_critical_clocks,
 167                                 ARRAY_SIZE(sun4i_a10_dram_critical_clocks));
 168}
 169CLK_OF_DECLARE(sun4i_a10_dram, "allwinner,sun4i-a10-dram-gates-clk",
 170               sun4i_a10_dram_init);
 171