diff options
author | Chen-Yu Tsai <wens@csie.org> | 2015-12-03 02:05:30 -0500 |
---|---|---|
committer | Maxime Ripard <maxime.ripard@free-electrons.com> | 2015-12-09 04:17:22 -0500 |
commit | fd9ffd8be01ad1e1204ed4aa2c43ef0a02e3dddc (patch) | |
tree | 8811342571da6f529025e1b64e1d5a865ac83871 | |
parent | 3cdd9f5c4953465abb87ec757159cc0576ae6b0a (diff) |
clk: sunxi: Add CLK_OF_DECLARE support for sun8i-a23-apb0-clk driver
The APBS clock on sun9i is the same as the APB0 clock on sun8i. With
sun9i we are supporting the PRCM clocks by using CLK_OF_DECLARE,
instead of through a PRCM mfd device and subdevices for each clock
and reset control. As such we need a CLK_OF_DECLARE version of
the sun8i-a23-apb0-clk driver.
Also, build it for sun9i/A80, and not just for configurations with
MFD_SUN6I_PRCM enabled.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
-rw-r--r-- | drivers/clk/sunxi/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-sun8i-apb0.c | 80 |
2 files changed, 69 insertions, 12 deletions
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile index 1a909f9024eb..3fd7901d48e4 100644 --- a/drivers/clk/sunxi/Makefile +++ b/drivers/clk/sunxi/Makefile | |||
@@ -17,6 +17,7 @@ obj-y += clk-sun9i-core.o | |||
17 | obj-y += clk-sun9i-mmc.o | 17 | obj-y += clk-sun9i-mmc.o |
18 | obj-y += clk-usb.o | 18 | obj-y += clk-usb.o |
19 | 19 | ||
20 | obj-$(CONFIG_MACH_SUN9I) += clk-sun8i-apb0.o | ||
20 | obj-$(CONFIG_MACH_SUN9I) += clk-sun9i-cpus.o | 21 | obj-$(CONFIG_MACH_SUN9I) += clk-sun9i-cpus.o |
21 | 22 | ||
22 | obj-$(CONFIG_MFD_SUN6I_PRCM) += \ | 23 | obj-$(CONFIG_MFD_SUN6I_PRCM) += \ |
diff --git a/drivers/clk/sunxi/clk-sun8i-apb0.c b/drivers/clk/sunxi/clk-sun8i-apb0.c index 7ae5d2c2cde1..7ba61103a6f5 100644 --- a/drivers/clk/sunxi/clk-sun8i-apb0.c +++ b/drivers/clk/sunxi/clk-sun8i-apb0.c | |||
@@ -17,13 +17,77 @@ | |||
17 | #include <linux/clk-provider.h> | 17 | #include <linux/clk-provider.h> |
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/of.h> | 19 | #include <linux/of.h> |
20 | #include <linux/of_address.h> | ||
20 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
21 | 22 | ||
23 | static struct clk *sun8i_a23_apb0_register(struct device_node *node, | ||
24 | void __iomem *reg) | ||
25 | { | ||
26 | const char *clk_name = node->name; | ||
27 | const char *clk_parent; | ||
28 | struct clk *clk; | ||
29 | int ret; | ||
30 | |||
31 | clk_parent = of_clk_get_parent_name(node, 0); | ||
32 | if (!clk_parent) | ||
33 | return ERR_PTR(-EINVAL); | ||
34 | |||
35 | of_property_read_string(node, "clock-output-names", &clk_name); | ||
36 | |||
37 | /* The A23 APB0 clock is a standard 2 bit wide divider clock */ | ||
38 | clk = clk_register_divider(NULL, clk_name, clk_parent, 0, reg, | ||
39 | 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL); | ||
40 | if (IS_ERR(clk)) | ||
41 | return clk; | ||
42 | |||
43 | ret = of_clk_add_provider(node, of_clk_src_simple_get, clk); | ||
44 | if (ret) | ||
45 | goto err_unregister; | ||
46 | |||
47 | return clk; | ||
48 | |||
49 | err_unregister: | ||
50 | clk_unregister_divider(clk); | ||
51 | |||
52 | return ERR_PTR(ret); | ||
53 | } | ||
54 | |||
55 | static void sun8i_a23_apb0_setup(struct device_node *node) | ||
56 | { | ||
57 | void __iomem *reg; | ||
58 | struct resource res; | ||
59 | struct clk *clk; | ||
60 | |||
61 | reg = of_io_request_and_map(node, 0, of_node_full_name(node)); | ||
62 | if (IS_ERR(reg)) { | ||
63 | /* | ||
64 | * This happens with clk nodes instantiated through mfd, | ||
65 | * as those do not have their resources assigned in the | ||
66 | * device tree. Do not print an error in this case. | ||
67 | */ | ||
68 | if (PTR_ERR(reg) != -EINVAL) | ||
69 | pr_err("Could not get registers for a23-apb0-clk\n"); | ||
70 | |||
71 | return; | ||
72 | } | ||
73 | |||
74 | clk = sun8i_a23_apb0_register(node, reg); | ||
75 | if (IS_ERR(clk)) | ||
76 | goto err_unmap; | ||
77 | |||
78 | return; | ||
79 | |||
80 | err_unmap: | ||
81 | iounmap(reg); | ||
82 | of_address_to_resource(node, 0, &res); | ||
83 | release_mem_region(res.start, resource_size(&res)); | ||
84 | } | ||
85 | CLK_OF_DECLARE(sun8i_a23_apb0, "allwinner,sun8i-a23-apb0-clk", | ||
86 | sun8i_a23_apb0_setup); | ||
87 | |||
22 | static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev) | 88 | static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev) |
23 | { | 89 | { |
24 | struct device_node *np = pdev->dev.of_node; | 90 | struct device_node *np = pdev->dev.of_node; |
25 | const char *clk_name = np->name; | ||
26 | const char *clk_parent; | ||
27 | struct resource *r; | 91 | struct resource *r; |
28 | void __iomem *reg; | 92 | void __iomem *reg; |
29 | struct clk *clk; | 93 | struct clk *clk; |
@@ -33,19 +97,11 @@ static int sun8i_a23_apb0_clk_probe(struct platform_device *pdev) | |||
33 | if (IS_ERR(reg)) | 97 | if (IS_ERR(reg)) |
34 | return PTR_ERR(reg); | 98 | return PTR_ERR(reg); |
35 | 99 | ||
36 | clk_parent = of_clk_get_parent_name(np, 0); | 100 | clk = sun8i_a23_apb0_register(np, reg); |
37 | if (!clk_parent) | ||
38 | return -EINVAL; | ||
39 | |||
40 | of_property_read_string(np, "clock-output-names", &clk_name); | ||
41 | |||
42 | /* The A23 APB0 clock is a standard 2 bit wide divider clock */ | ||
43 | clk = clk_register_divider(&pdev->dev, clk_name, clk_parent, 0, reg, | ||
44 | 0, 2, CLK_DIVIDER_POWER_OF_TWO, NULL); | ||
45 | if (IS_ERR(clk)) | 101 | if (IS_ERR(clk)) |
46 | return PTR_ERR(clk); | 102 | return PTR_ERR(clk); |
47 | 103 | ||
48 | return of_clk_add_provider(np, of_clk_src_simple_get, clk); | 104 | return 0; |
49 | } | 105 | } |
50 | 106 | ||
51 | static const struct of_device_id sun8i_a23_apb0_clk_dt_ids[] = { | 107 | static const struct of_device_id sun8i_a23_apb0_clk_dt_ids[] = { |