forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
109 lines
2.7 KiB
109 lines
2.7 KiB
// SPDX-License-Identifier: GPL-2.0-or-later |
|
/* |
|
* Copyright (C) 2015 Jens Kuske <[email protected]> |
|
* |
|
* Based on clk-simple-gates.c, which is: |
|
* Copyright 2015 Maxime Ripard |
|
* |
|
* Maxime Ripard <[email protected]> |
|
*/ |
|
|
|
#include <linux/clk-provider.h> |
|
#include <linux/io.h> |
|
#include <linux/of.h> |
|
#include <linux/of_address.h> |
|
#include <linux/slab.h> |
|
#include <linux/spinlock.h> |
|
|
|
static DEFINE_SPINLOCK(gates_lock); |
|
|
|
static void __init sun8i_h3_bus_gates_init(struct device_node *node) |
|
{ |
|
static const char * const names[] = { "ahb1", "ahb2", "apb1", "apb2" }; |
|
enum { AHB1, AHB2, APB1, APB2, PARENT_MAX } clk_parent; |
|
const char *parents[PARENT_MAX]; |
|
struct clk_onecell_data *clk_data; |
|
const char *clk_name; |
|
struct property *prop; |
|
struct resource res; |
|
void __iomem *clk_reg; |
|
void __iomem *reg; |
|
const __be32 *p; |
|
int number, i; |
|
u8 clk_bit; |
|
int index; |
|
|
|
reg = of_io_request_and_map(node, 0, of_node_full_name(node)); |
|
if (IS_ERR(reg)) |
|
return; |
|
|
|
for (i = 0; i < ARRAY_SIZE(names); i++) { |
|
int idx = of_property_match_string(node, "clock-names", |
|
names[i]); |
|
if (idx < 0) |
|
return; |
|
|
|
parents[i] = of_clk_get_parent_name(node, idx); |
|
} |
|
|
|
clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL); |
|
if (!clk_data) |
|
goto err_unmap; |
|
|
|
number = of_property_count_u32_elems(node, "clock-indices"); |
|
of_property_read_u32_index(node, "clock-indices", number - 1, &number); |
|
|
|
clk_data->clks = kcalloc(number + 1, sizeof(struct clk *), GFP_KERNEL); |
|
if (!clk_data->clks) |
|
goto err_free_data; |
|
|
|
i = 0; |
|
of_property_for_each_u32(node, "clock-indices", prop, p, index) { |
|
of_property_read_string_index(node, "clock-output-names", |
|
i, &clk_name); |
|
|
|
if (index == 17 || (index >= 29 && index <= 31)) |
|
clk_parent = AHB2; |
|
else if (index <= 63 || index >= 128) |
|
clk_parent = AHB1; |
|
else if (index >= 64 && index <= 95) |
|
clk_parent = APB1; |
|
else if (index >= 96 && index <= 127) |
|
clk_parent = APB2; |
|
else { |
|
WARN_ON(true); |
|
continue; |
|
} |
|
|
|
clk_reg = reg + 4 * (index / 32); |
|
clk_bit = index % 32; |
|
|
|
clk_data->clks[index] = clk_register_gate(NULL, clk_name, |
|
parents[clk_parent], |
|
0, clk_reg, clk_bit, |
|
0, &gates_lock); |
|
i++; |
|
|
|
if (IS_ERR(clk_data->clks[index])) { |
|
WARN_ON(true); |
|
continue; |
|
} |
|
} |
|
|
|
clk_data->clk_num = number + 1; |
|
of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); |
|
|
|
return; |
|
|
|
err_free_data: |
|
kfree(clk_data); |
|
err_unmap: |
|
iounmap(reg); |
|
of_address_to_resource(node, 0, &res); |
|
release_mem_region(res.start, resource_size(&res)); |
|
} |
|
|
|
CLK_OF_DECLARE(sun8i_h3_bus_gates, "allwinner,sun8i-h3-bus-gates-clk", |
|
sun8i_h3_bus_gates_init); |
|
CLK_OF_DECLARE(sun8i_a83t_bus_gates, "allwinner,sun8i-a83t-bus-gates-clk", |
|
sun8i_h3_bus_gates_init);
|
|
|