Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2015 Jens Kuske <jenskuske@gmail.com>
0004  *
0005  * Based on clk-simple-gates.c, which is:
0006  * Copyright 2015 Maxime Ripard
0007  *
0008  * Maxime Ripard <maxime.ripard@free-electrons.com>
0009  */
0010 
0011 #include <linux/clk-provider.h>
0012 #include <linux/io.h>
0013 #include <linux/of.h>
0014 #include <linux/of_address.h>
0015 #include <linux/slab.h>
0016 #include <linux/spinlock.h>
0017 
0018 static DEFINE_SPINLOCK(gates_lock);
0019 
0020 static void __init sun8i_h3_bus_gates_init(struct device_node *node)
0021 {
0022     static const char * const names[] = { "ahb1", "ahb2", "apb1", "apb2" };
0023     enum { AHB1, AHB2, APB1, APB2, PARENT_MAX } clk_parent;
0024     const char *parents[PARENT_MAX];
0025     struct clk_onecell_data *clk_data;
0026     const char *clk_name;
0027     struct property *prop;
0028     struct resource res;
0029     void __iomem *clk_reg;
0030     void __iomem *reg;
0031     const __be32 *p;
0032     int number, i;
0033     u8 clk_bit;
0034     int index;
0035 
0036     reg = of_io_request_and_map(node, 0, of_node_full_name(node));
0037     if (IS_ERR(reg))
0038         return;
0039 
0040     for (i = 0; i < ARRAY_SIZE(names); i++) {
0041         int idx = of_property_match_string(node, "clock-names",
0042                            names[i]);
0043         if (idx < 0)
0044             return;
0045 
0046         parents[i] = of_clk_get_parent_name(node, idx);
0047     }
0048 
0049     clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
0050     if (!clk_data)
0051         goto err_unmap;
0052 
0053     number = of_property_count_u32_elems(node, "clock-indices");
0054     of_property_read_u32_index(node, "clock-indices", number - 1, &number);
0055 
0056     clk_data->clks = kcalloc(number + 1, sizeof(struct clk *), GFP_KERNEL);
0057     if (!clk_data->clks)
0058         goto err_free_data;
0059 
0060     i = 0;
0061     of_property_for_each_u32(node, "clock-indices", prop, p, index) {
0062         of_property_read_string_index(node, "clock-output-names",
0063                           i, &clk_name);
0064 
0065         if (index == 17 || (index >= 29 && index <= 31))
0066             clk_parent = AHB2;
0067         else if (index <= 63 || index >= 128)
0068             clk_parent = AHB1;
0069         else if (index >= 64 && index <= 95)
0070             clk_parent = APB1;
0071         else if (index >= 96 && index <= 127)
0072             clk_parent = APB2;
0073         else {
0074             WARN_ON(true);
0075             continue;
0076         }
0077 
0078         clk_reg = reg + 4 * (index / 32);
0079         clk_bit = index % 32;
0080 
0081         clk_data->clks[index] = clk_register_gate(NULL, clk_name,
0082                               parents[clk_parent],
0083                               0, clk_reg, clk_bit,
0084                               0, &gates_lock);
0085         i++;
0086 
0087         if (IS_ERR(clk_data->clks[index])) {
0088             WARN_ON(true);
0089             continue;
0090         }
0091     }
0092 
0093     clk_data->clk_num = number + 1;
0094     of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
0095 
0096     return;
0097 
0098 err_free_data:
0099     kfree(clk_data);
0100 err_unmap:
0101     iounmap(reg);
0102     of_address_to_resource(node, 0, &res);
0103     release_mem_region(res.start, resource_size(&res));
0104 }
0105 
0106 CLK_OF_DECLARE(sun8i_h3_bus_gates, "allwinner,sun8i-h3-bus-gates-clk",
0107            sun8i_h3_bus_gates_init);
0108 CLK_OF_DECLARE(sun8i_a83t_bus_gates, "allwinner,sun8i-a83t-bus-gates-clk",
0109            sun8i_h3_bus_gates_init);