diff options
author | Chen-Yu Tsai <wens@csie.org> | 2014-07-09 03:54:34 -0400 |
---|---|---|
committer | Maxime Ripard <maxime.ripard@free-electrons.com> | 2014-07-15 02:52:11 -0400 |
commit | b72efd0f651271ee05835ab848eee7c4e6851c99 (patch) | |
tree | b2a88aefb3d90eba77cd965be90730eeeeb9d299 /drivers/clk/sunxi | |
parent | cd6eb534fbb8c9c52e6900f6b086d8c95f966449 (diff) |
clk: sunxi: sun6i-apb0-gates: use bitmaps for valid gate indices
sun6i-apb0-gates uses the "clock-indices" DT property to indicate
valid gate bits or holes in between. However, the rest of sunxi
clock drivers use bitmaps for this purpose.
This patch modifies sun6i-apb0-gates to use bitmaps as well, to be
consistent with the sunxi platform. Also add the missing call to
clk_register_clkdev, so system clock lookups will work.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Diffstat (limited to 'drivers/clk/sunxi')
-rw-r--r-- | drivers/clk/sunxi/clk-sun6i-apb0-gates.c | 75 |
1 files changed, 39 insertions, 36 deletions
diff --git a/drivers/clk/sunxi/clk-sun6i-apb0-gates.c b/drivers/clk/sunxi/clk-sun6i-apb0-gates.c index b342f2a2d4a7..3bd8357f912e 100644 --- a/drivers/clk/sunxi/clk-sun6i-apb0-gates.c +++ b/drivers/clk/sunxi/clk-sun6i-apb0-gates.c | |||
@@ -9,24 +9,48 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/clk-provider.h> | 11 | #include <linux/clk-provider.h> |
12 | #include <linux/clkdev.h> | ||
12 | #include <linux/module.h> | 13 | #include <linux/module.h> |
13 | #include <linux/of.h> | 14 | #include <linux/of.h> |
15 | #include <linux/of_device.h> | ||
14 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
15 | 17 | ||
16 | #define SUN6I_APB0_GATES_MAX_SIZE 32 | 18 | #define SUN6I_APB0_GATES_MAX_SIZE 32 |
17 | 19 | ||
20 | struct gates_data { | ||
21 | DECLARE_BITMAP(mask, SUN6I_APB0_GATES_MAX_SIZE); | ||
22 | }; | ||
23 | |||
24 | static const struct gates_data sun6i_a31_apb0_gates __initconst = { | ||
25 | .mask = {0x7F}, | ||
26 | }; | ||
27 | |||
28 | const struct of_device_id sun6i_a31_apb0_gates_clk_dt_ids[] = { | ||
29 | { .compatible = "allwinner,sun6i-a31-apb0-gates-clk", .data = &sun6i_a31_apb0_gates }, | ||
30 | { /* sentinel */ } | ||
31 | }; | ||
32 | |||
18 | static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev) | 33 | static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev) |
19 | { | 34 | { |
20 | struct device_node *np = pdev->dev.of_node; | 35 | struct device_node *np = pdev->dev.of_node; |
21 | struct clk_onecell_data *clk_data; | 36 | struct clk_onecell_data *clk_data; |
37 | const struct of_device_id *device; | ||
38 | const struct gates_data *data; | ||
22 | const char *clk_parent; | 39 | const char *clk_parent; |
23 | const char *clk_name; | 40 | const char *clk_name; |
24 | struct resource *r; | 41 | struct resource *r; |
25 | void __iomem *reg; | 42 | void __iomem *reg; |
26 | int gate_id; | ||
27 | int ngates; | 43 | int ngates; |
28 | int gate_max = 0; | ||
29 | int i; | 44 | int i; |
45 | int j = 0; | ||
46 | |||
47 | if (!np) | ||
48 | return -ENODEV; | ||
49 | |||
50 | device = of_match_device(sun6i_a31_apb0_gates_clk_dt_ids, &pdev->dev); | ||
51 | if (!device) | ||
52 | return -ENODEV; | ||
53 | data = device->data; | ||
30 | 54 | ||
31 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 55 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
32 | reg = devm_ioremap_resource(&pdev->dev, r); | 56 | reg = devm_ioremap_resource(&pdev->dev, r); |
@@ -37,57 +61,36 @@ static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev) | |||
37 | if (!clk_parent) | 61 | if (!clk_parent) |
38 | return -EINVAL; | 62 | return -EINVAL; |
39 | 63 | ||
40 | ngates = of_property_count_strings(np, "clock-output-names"); | ||
41 | if (ngates < 0) | ||
42 | return ngates; | ||
43 | |||
44 | if (!ngates || ngates > SUN6I_APB0_GATES_MAX_SIZE) | ||
45 | return -EINVAL; | ||
46 | |||
47 | clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data), | 64 | clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data), |
48 | GFP_KERNEL); | 65 | GFP_KERNEL); |
49 | if (!clk_data) | 66 | if (!clk_data) |
50 | return -ENOMEM; | 67 | return -ENOMEM; |
51 | 68 | ||
52 | clk_data->clks = devm_kzalloc(&pdev->dev, | 69 | /* Worst-case size approximation and memory allocation */ |
53 | SUN6I_APB0_GATES_MAX_SIZE * | 70 | ngates = find_last_bit(data->mask, SUN6I_APB0_GATES_MAX_SIZE); |
54 | sizeof(struct clk *), | 71 | clk_data->clks = devm_kcalloc(&pdev->dev, (ngates + 1), |
55 | GFP_KERNEL); | 72 | sizeof(struct clk *), GFP_KERNEL); |
56 | if (!clk_data->clks) | 73 | if (!clk_data->clks) |
57 | return -ENOMEM; | 74 | return -ENOMEM; |
58 | 75 | ||
59 | for (i = 0; i < ngates; i++) { | 76 | for_each_set_bit(i, data->mask, SUN6I_APB0_GATES_MAX_SIZE) { |
60 | of_property_read_string_index(np, "clock-output-names", | 77 | of_property_read_string_index(np, "clock-output-names", |
61 | i, &clk_name); | 78 | j, &clk_name); |
62 | |||
63 | gate_id = i; | ||
64 | of_property_read_u32_index(np, "clock-indices", i, &gate_id); | ||
65 | |||
66 | WARN_ON(gate_id >= SUN6I_APB0_GATES_MAX_SIZE); | ||
67 | if (gate_id >= SUN6I_APB0_GATES_MAX_SIZE) | ||
68 | continue; | ||
69 | 79 | ||
70 | clk_data->clks[gate_id] = clk_register_gate(&pdev->dev, | 80 | clk_data->clks[i] = clk_register_gate(&pdev->dev, clk_name, |
71 | clk_name, | 81 | clk_parent, 0, reg, i, |
72 | clk_parent, 0, | 82 | 0, NULL); |
73 | reg, gate_id, | 83 | WARN_ON(IS_ERR(clk_data->clks[i])); |
74 | 0, NULL); | 84 | clk_register_clkdev(clk_data->clks[i], clk_name, NULL); |
75 | WARN_ON(IS_ERR(clk_data->clks[gate_id])); | ||
76 | 85 | ||
77 | if (gate_id > gate_max) | 86 | j++; |
78 | gate_max = gate_id; | ||
79 | } | 87 | } |
80 | 88 | ||
81 | clk_data->clk_num = gate_max + 1; | 89 | clk_data->clk_num = ngates + 1; |
82 | 90 | ||
83 | return of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); | 91 | return of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); |
84 | } | 92 | } |
85 | 93 | ||
86 | const struct of_device_id sun6i_a31_apb0_gates_clk_dt_ids[] = { | ||
87 | { .compatible = "allwinner,sun6i-a31-apb0-gates-clk" }, | ||
88 | { /* sentinel */ } | ||
89 | }; | ||
90 | |||
91 | static struct platform_driver sun6i_a31_apb0_gates_clk_driver = { | 94 | static struct platform_driver sun6i_a31_apb0_gates_clk_driver = { |
92 | .driver = { | 95 | .driver = { |
93 | .name = "sun6i-a31-apb0-gates-clk", | 96 | .name = "sun6i-a31-apb0-gates-clk", |