^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2014 Free Electrons
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Allwinner A31 APB0 clock gates driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/clk-provider.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define SUN6I_APB0_GATES_MAX_SIZE 32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) struct gates_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) DECLARE_BITMAP(mask, SUN6I_APB0_GATES_MAX_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static const struct gates_data sun6i_a31_apb0_gates __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) .mask = {0x7F},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) static const struct gates_data sun8i_a23_apb0_gates __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) .mask = {0x5D},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) static const struct of_device_id sun6i_a31_apb0_gates_clk_dt_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) { .compatible = "allwinner,sun6i-a31-apb0-gates-clk", .data = &sun6i_a31_apb0_gates },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) { .compatible = "allwinner,sun8i-a23-apb0-gates-clk", .data = &sun8i_a23_apb0_gates },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) { /* sentinel */ }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct device_node *np = pdev->dev.of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) struct clk_onecell_data *clk_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) const struct gates_data *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) const char *clk_parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) const char *clk_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) struct resource *r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) void __iomem *reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) int ngates;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) int j = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) if (!np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) data = of_device_get_match_data(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) if (!data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) reg = devm_ioremap_resource(&pdev->dev, r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) if (IS_ERR(reg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) return PTR_ERR(reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) clk_parent = of_clk_get_parent_name(np, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if (!clk_parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (!clk_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) /* Worst-case size approximation and memory allocation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) ngates = find_last_bit(data->mask, SUN6I_APB0_GATES_MAX_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) clk_data->clks = devm_kcalloc(&pdev->dev, (ngates + 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) sizeof(struct clk *), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (!clk_data->clks)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) for_each_set_bit(i, data->mask, SUN6I_APB0_GATES_MAX_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) of_property_read_string_index(np, "clock-output-names",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) j, &clk_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) clk_data->clks[i] = clk_register_gate(&pdev->dev, clk_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) clk_parent, 0, reg, i,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) 0, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) WARN_ON(IS_ERR(clk_data->clks[i]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) j++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) clk_data->clk_num = ngates + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) static struct platform_driver sun6i_a31_apb0_gates_clk_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) .name = "sun6i-a31-apb0-gates-clk",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) .of_match_table = sun6i_a31_apb0_gates_clk_dt_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) .probe = sun6i_a31_apb0_gates_clk_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) builtin_platform_driver(sun6i_a31_apb0_gates_clk_driver);