aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk/sunxi
diff options
context:
space:
mode:
authorChen-Yu Tsai <wens@csie.org>2014-07-09 03:54:34 -0400
committerMaxime Ripard <maxime.ripard@free-electrons.com>2014-07-15 02:52:11 -0400
commitb72efd0f651271ee05835ab848eee7c4e6851c99 (patch)
treeb2a88aefb3d90eba77cd965be90730eeeeb9d299 /drivers/clk/sunxi
parentcd6eb534fbb8c9c52e6900f6b086d8c95f966449 (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.c75
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
20struct gates_data {
21 DECLARE_BITMAP(mask, SUN6I_APB0_GATES_MAX_SIZE);
22};
23
24static const struct gates_data sun6i_a31_apb0_gates __initconst = {
25 .mask = {0x7F},
26};
27
28const 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
18static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev) 33static 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
86const struct of_device_id sun6i_a31_apb0_gates_clk_dt_ids[] = {
87 { .compatible = "allwinner,sun6i-a31-apb0-gates-clk" },
88 { /* sentinel */ }
89};
90
91static struct platform_driver sun6i_a31_apb0_gates_clk_driver = { 94static 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",