^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright 2014 Chen-Yu Tsai
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Chen-Yu Tsai <wens@csie.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/clk-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #define SUN8I_MBUS_ENABLE 31
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define SUN8I_MBUS_MUX_SHIFT 24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define SUN8I_MBUS_MUX_MASK 0x3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define SUN8I_MBUS_DIV_SHIFT 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define SUN8I_MBUS_DIV_WIDTH 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define SUN8I_MBUS_MAX_PARENTS 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static DEFINE_SPINLOCK(sun8i_a23_mbus_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) static void __init sun8i_a23_mbus_setup(struct device_node *node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) int num_parents = of_clk_get_parent_count(node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) const char **parents;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) const char *clk_name = node->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct resource res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct clk_divider *div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct clk_gate *gate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct clk_mux *mux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) void __iomem *reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) parents = kcalloc(num_parents, sizeof(*parents), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) if (!parents)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) reg = of_io_request_and_map(node, 0, of_node_full_name(node));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (IS_ERR(reg)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) pr_err("Could not get registers for sun8i-mbus-clk\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) goto err_free_parents;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) div = kzalloc(sizeof(*div), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) if (!div)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) goto err_unmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) mux = kzalloc(sizeof(*mux), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (!mux)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) goto err_free_div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) gate = kzalloc(sizeof(*gate), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) if (!gate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) goto err_free_mux;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) of_property_read_string(node, "clock-output-names", &clk_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) of_clk_parent_fill(node, parents, num_parents);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) gate->reg = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) gate->bit_idx = SUN8I_MBUS_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) gate->lock = &sun8i_a23_mbus_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) div->reg = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) div->shift = SUN8I_MBUS_DIV_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) div->width = SUN8I_MBUS_DIV_WIDTH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) div->lock = &sun8i_a23_mbus_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) mux->reg = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) mux->shift = SUN8I_MBUS_MUX_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) mux->mask = SUN8I_MBUS_MUX_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) mux->lock = &sun8i_a23_mbus_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) /* The MBUS clocks needs to be always enabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) clk = clk_register_composite(NULL, clk_name, parents, num_parents,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) &mux->hw, &clk_mux_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) &div->hw, &clk_divider_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) &gate->hw, &clk_gate_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) CLK_IS_CRITICAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if (IS_ERR(clk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) goto err_free_gate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) err = of_clk_add_provider(node, of_clk_src_simple_get, clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) goto err_unregister_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) kfree(parents); /* parents is deep copied */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) err_unregister_clk:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) /* TODO: The composite clock stuff will leak a bit here. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) clk_unregister(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) err_free_gate:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) kfree(gate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) err_free_mux:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) kfree(mux);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) err_free_div:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) kfree(div);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) err_unmap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) iounmap(reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) of_address_to_resource(node, 0, &res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) release_mem_region(res.start, resource_size(&res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) err_free_parents:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) kfree(parents);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) CLK_OF_DECLARE(sun8i_a23_mbus, "allwinner,sun8i-a23-mbus-clk", sun8i_a23_mbus_setup);