aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Turquette <mturquette@linaro.org>2014-06-11 10:11:59 -0400
committerMike Turquette <mturquette@linaro.org>2014-06-11 10:11:59 -0400
commitb640a6037c9ecd1f0ad23a8e9b4ca5f5b4112508 (patch)
tree29d2f18d98f7daef1fd8033e95583d83f2096bc2
parent3f6eec9969d24f91a3909d51e86e007ca5efd4c4 (diff)
parent5c89a8b65760a60eea38e0b172d04152ec03a067 (diff)
Merge tag 'sunxi-clk-for-3.16-2' of https://github.com/mripard/linux into clk-next
Rebase of Emilio's clk-sunxi-for-3.16 on top of clk-next Fixed a few compilation warnings exposed by a patch introduced during the 3.16 merge window. Original tag message: Allwinner sunXi SoCs clock changes This pull contains some new code to add support for A31 clocks by Maxime and Boris. It also reworks the driver a bit to avoid having a huge single file when we have a full folder for ourselves, and separating different functional units makes sense.
-rw-r--r--Documentation/devicetree/bindings/clock/sunxi.txt4
-rw-r--r--drivers/clk/sunxi/Makefile4
-rw-r--r--drivers/clk/sunxi/clk-a10-hosc.c73
-rw-r--r--drivers/clk/sunxi/clk-a20-gmac.c119
-rw-r--r--drivers/clk/sunxi/clk-sun6i-apb0-gates.c99
-rw-r--r--drivers/clk/sunxi/clk-sun6i-apb0.c77
-rw-r--r--drivers/clk/sunxi/clk-sun6i-ar100.c233
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c239
8 files changed, 661 insertions, 187 deletions
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index a5160d8cbb5f..b9ec668bfe62 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -20,12 +20,15 @@ Required properties:
20 "allwinner,sun5i-a13-ahb-gates-clk" - for the AHB gates on A13 20 "allwinner,sun5i-a13-ahb-gates-clk" - for the AHB gates on A13
21 "allwinner,sun5i-a10s-ahb-gates-clk" - for the AHB gates on A10s 21 "allwinner,sun5i-a10s-ahb-gates-clk" - for the AHB gates on A10s
22 "allwinner,sun7i-a20-ahb-gates-clk" - for the AHB gates on A20 22 "allwinner,sun7i-a20-ahb-gates-clk" - for the AHB gates on A20
23 "allwinner,sun6i-a31-ar100-clk" - for the AR100 on A31
23 "allwinner,sun6i-a31-ahb1-mux-clk" - for the AHB1 multiplexer on A31 24 "allwinner,sun6i-a31-ahb1-mux-clk" - for the AHB1 multiplexer on A31
24 "allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31 25 "allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31
25 "allwinner,sun4i-a10-apb0-clk" - for the APB0 clock 26 "allwinner,sun4i-a10-apb0-clk" - for the APB0 clock
27 "allwinner,sun6i-a31-apb0-clk" - for the APB0 clock on A31
26 "allwinner,sun4i-a10-apb0-gates-clk" - for the APB0 gates on A10 28 "allwinner,sun4i-a10-apb0-gates-clk" - for the APB0 gates on A10
27 "allwinner,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13 29 "allwinner,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13
28 "allwinner,sun5i-a10s-apb0-gates-clk" - for the APB0 gates on A10s 30 "allwinner,sun5i-a10s-apb0-gates-clk" - for the APB0 gates on A10s
31 "allwinner,sun6i-a31-apb0-gates-clk" - for the APB0 gates on A31
29 "allwinner,sun7i-a20-apb0-gates-clk" - for the APB0 gates on A20 32 "allwinner,sun7i-a20-apb0-gates-clk" - for the APB0 gates on A20
30 "allwinner,sun4i-a10-apb1-clk" - for the APB1 clock 33 "allwinner,sun4i-a10-apb1-clk" - for the APB1 clock
31 "allwinner,sun4i-a10-apb1-mux-clk" - for the APB1 clock muxing 34 "allwinner,sun4i-a10-apb1-mux-clk" - for the APB1 clock muxing
@@ -41,6 +44,7 @@ Required properties:
41 "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31 44 "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
42 "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20 45 "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
43 "allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13 46 "allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
47 "allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31
44 48
45Required properties for all clocks: 49Required properties for all clocks:
46- reg : shall be the control register address for the clock. 50- reg : shall be the control register address for the clock.
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index b5bac917612c..762fd64dbd1f 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -3,3 +3,7 @@
3# 3#
4 4
5obj-y += clk-sunxi.o clk-factors.o 5obj-y += clk-sunxi.o clk-factors.o
6obj-y += clk-a10-hosc.o
7obj-y += clk-a20-gmac.o
8
9obj-$(CONFIG_MFD_SUN6I_PRCM) += clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o
diff --git a/drivers/clk/sunxi/clk-a10-hosc.c b/drivers/clk/sunxi/clk-a10-hosc.c
new file mode 100644
index 000000000000..0481d5d673d6
--- /dev/null
+++ b/drivers/clk/sunxi/clk-a10-hosc.c
@@ -0,0 +1,73 @@
1/*
2 * Copyright 2013 Emilio López
3 *
4 * Emilio López <emilio@elopez.com.ar>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <linux/clk-provider.h>
18#include <linux/clkdev.h>
19#include <linux/of.h>
20#include <linux/of_address.h>
21
22#define SUNXI_OSC24M_GATE 0
23
24static DEFINE_SPINLOCK(hosc_lock);
25
26static void __init sun4i_osc_clk_setup(struct device_node *node)
27{
28 struct clk *clk;
29 struct clk_fixed_rate *fixed;
30 struct clk_gate *gate;
31 const char *clk_name = node->name;
32 u32 rate;
33
34 if (of_property_read_u32(node, "clock-frequency", &rate))
35 return;
36
37 /* allocate fixed-rate and gate clock structs */
38 fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL);
39 if (!fixed)
40 return;
41 gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
42 if (!gate)
43 goto err_free_fixed;
44
45 of_property_read_string(node, "clock-output-names", &clk_name);
46
47 /* set up gate and fixed rate properties */
48 gate->reg = of_iomap(node, 0);
49 gate->bit_idx = SUNXI_OSC24M_GATE;
50 gate->lock = &hosc_lock;
51 fixed->fixed_rate = rate;
52
53 clk = clk_register_composite(NULL, clk_name,
54 NULL, 0,
55 NULL, NULL,
56 &fixed->hw, &clk_fixed_rate_ops,
57 &gate->hw, &clk_gate_ops,
58 CLK_IS_ROOT);
59
60 if (IS_ERR(clk))
61 goto err_free_gate;
62
63 of_clk_add_provider(node, of_clk_src_simple_get, clk);
64 clk_register_clkdev(clk, clk_name, NULL);
65
66 return;
67
68err_free_gate:
69 kfree(gate);
70err_free_fixed:
71 kfree(fixed);
72}
73CLK_OF_DECLARE(sun4i_osc, "allwinner,sun4i-a10-osc-clk", sun4i_osc_clk_setup);
diff --git a/drivers/clk/sunxi/clk-a20-gmac.c b/drivers/clk/sunxi/clk-a20-gmac.c
new file mode 100644
index 000000000000..633ddc4389ef
--- /dev/null
+++ b/drivers/clk/sunxi/clk-a20-gmac.c
@@ -0,0 +1,119 @@
1/*
2 * Copyright 2013 Emilio López
3 * Emilio López <emilio@elopez.com.ar>
4 *
5 * Copyright 2013 Chen-Yu Tsai
6 * Chen-Yu Tsai <wens@csie.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19#include <linux/clk-provider.h>
20#include <linux/clkdev.h>
21#include <linux/of.h>
22#include <linux/of_address.h>
23#include <linux/slab.h>
24
25static DEFINE_SPINLOCK(gmac_lock);
26
27/**
28 * sun7i_a20_gmac_clk_setup - Setup function for A20/A31 GMAC clock module
29 *
30 * This clock looks something like this
31 * ________________________
32 * MII TX clock from PHY >-----|___________ _________|----> to GMAC core
33 * GMAC Int. RGMII TX clk >----|___________\__/__gate---|----> to PHY
34 * Ext. 125MHz RGMII TX clk >--|__divider__/ |
35 * |________________________|
36 *
37 * The external 125 MHz reference is optional, i.e. GMAC can use its
38 * internal TX clock just fine. The A31 GMAC clock module does not have
39 * the divider controls for the external reference.
40 *
41 * To keep it simple, let the GMAC use either the MII TX clock for MII mode,
42 * and its internal TX clock for GMII and RGMII modes. The GMAC driver should
43 * select the appropriate source and gate/ungate the output to the PHY.
44 *
45 * Only the GMAC should use this clock. Altering the clock so that it doesn't
46 * match the GMAC's operation parameters will result in the GMAC not being
47 * able to send traffic out. The GMAC driver should set the clock rate and
48 * enable/disable this clock to configure the required state. The clock
49 * driver then responds by auto-reparenting the clock.
50 */
51
52#define SUN7I_A20_GMAC_GPIT 2
53#define SUN7I_A20_GMAC_MASK 0x3
54#define SUN7I_A20_GMAC_PARENTS 2
55
56static void __init sun7i_a20_gmac_clk_setup(struct device_node *node)
57{
58 struct clk *clk;
59 struct clk_mux *mux;
60 struct clk_gate *gate;
61 const char *clk_name = node->name;
62 const char *parents[SUN7I_A20_GMAC_PARENTS];
63 void *reg;
64
65 if (of_property_read_string(node, "clock-output-names", &clk_name))
66 return;
67
68 /* allocate mux and gate clock structs */
69 mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
70 if (!mux)
71 return;
72
73 gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
74 if (!gate)
75 goto free_mux;
76
77 /* gmac clock requires exactly 2 parents */
78 parents[0] = of_clk_get_parent_name(node, 0);
79 parents[1] = of_clk_get_parent_name(node, 1);
80 if (!parents[0] || !parents[1])
81 goto free_gate;
82
83 reg = of_iomap(node, 0);
84 if (!reg)
85 goto free_gate;
86
87 /* set up gate and fixed rate properties */
88 gate->reg = reg;
89 gate->bit_idx = SUN7I_A20_GMAC_GPIT;
90 gate->lock = &gmac_lock;
91 mux->reg = reg;
92 mux->mask = SUN7I_A20_GMAC_MASK;
93 mux->flags = CLK_MUX_INDEX_BIT;
94 mux->lock = &gmac_lock;
95
96 clk = clk_register_composite(NULL, clk_name,
97 parents, SUN7I_A20_GMAC_PARENTS,
98 &mux->hw, &clk_mux_ops,
99 NULL, NULL,
100 &gate->hw, &clk_gate_ops,
101 0);
102
103 if (IS_ERR(clk))
104 goto iounmap_reg;
105
106 of_clk_add_provider(node, of_clk_src_simple_get, clk);
107 clk_register_clkdev(clk, clk_name, NULL);
108
109 return;
110
111iounmap_reg:
112 iounmap(reg);
113free_gate:
114 kfree(gate);
115free_mux:
116 kfree(mux);
117}
118CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk",
119 sun7i_a20_gmac_clk_setup);
diff --git a/drivers/clk/sunxi/clk-sun6i-apb0-gates.c b/drivers/clk/sunxi/clk-sun6i-apb0-gates.c
new file mode 100644
index 000000000000..44cd27c5c401
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun6i-apb0-gates.c
@@ -0,0 +1,99 @@
1/*
2 * Copyright (C) 2014 Free Electrons
3 *
4 * License Terms: GNU General Public License v2
5 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
6 *
7 * Allwinner A31 APB0 clock gates driver
8 *
9 */
10
11#include <linux/clk-provider.h>
12#include <linux/module.h>
13#include <linux/of.h>
14#include <linux/platform_device.h>
15
16#define SUN6I_APB0_GATES_MAX_SIZE 32
17
18static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev)
19{
20 struct device_node *np = pdev->dev.of_node;
21 struct clk_onecell_data *clk_data;
22 const char *clk_parent;
23 const char *clk_name;
24 struct resource *r;
25 void __iomem *reg;
26 int gate_id;
27 int ngates;
28 int i;
29
30 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
31 reg = devm_ioremap_resource(&pdev->dev, r);
32 if (!reg)
33 return PTR_ERR(reg);
34
35 clk_parent = of_clk_get_parent_name(np, 0);
36 if (!clk_parent)
37 return -EINVAL;
38
39 ngates = of_property_count_strings(np, "clock-output-names");
40 if (ngates < 0)
41 return ngates;
42
43 if (!ngates || ngates > SUN6I_APB0_GATES_MAX_SIZE)
44 return -EINVAL;
45
46 clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data),
47 GFP_KERNEL);
48 if (!clk_data)
49 return -ENOMEM;
50
51 clk_data->clks = devm_kzalloc(&pdev->dev,
52 SUN6I_APB0_GATES_MAX_SIZE *
53 sizeof(struct clk *),
54 GFP_KERNEL);
55 if (!clk_data->clks)
56 return -ENOMEM;
57
58 for (i = 0; i < ngates; i++) {
59 of_property_read_string_index(np, "clock-output-names",
60 i, &clk_name);
61
62 gate_id = i;
63 of_property_read_u32_index(np, "clock-indices", i, &gate_id);
64
65 WARN_ON(gate_id >= SUN6I_APB0_GATES_MAX_SIZE);
66 if (gate_id >= SUN6I_APB0_GATES_MAX_SIZE)
67 continue;
68
69 clk_data->clks[gate_id] = clk_register_gate(&pdev->dev,
70 clk_name,
71 clk_parent, 0,
72 reg, gate_id,
73 0, NULL);
74 WARN_ON(IS_ERR(clk_data->clks[gate_id]));
75 }
76
77 clk_data->clk_num = ngates;
78
79 return of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
80}
81
82const struct of_device_id sun6i_a31_apb0_gates_clk_dt_ids[] = {
83 { .compatible = "allwinner,sun6i-a31-apb0-gates-clk" },
84 { /* sentinel */ }
85};
86
87static struct platform_driver sun6i_a31_apb0_gates_clk_driver = {
88 .driver = {
89 .name = "sun6i-a31-apb0-gates-clk",
90 .owner = THIS_MODULE,
91 .of_match_table = sun6i_a31_apb0_gates_clk_dt_ids,
92 },
93 .probe = sun6i_a31_apb0_gates_clk_probe,
94};
95module_platform_driver(sun6i_a31_apb0_gates_clk_driver);
96
97MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>");
98MODULE_DESCRIPTION("Allwinner A31 APB0 gate clocks driver");
99MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/sunxi/clk-sun6i-apb0.c b/drivers/clk/sunxi/clk-sun6i-apb0.c
new file mode 100644
index 000000000000..11f17c34c2ae
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun6i-apb0.c
@@ -0,0 +1,77 @@
1/*
2 * Copyright (C) 2014 Free Electrons
3 *
4 * License Terms: GNU General Public License v2
5 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
6 *
7 * Allwinner A31 APB0 clock driver
8 *
9 */
10
11#include <linux/clk-provider.h>
12#include <linux/module.h>
13#include <linux/of.h>
14#include <linux/platform_device.h>
15
16/*
17 * The APB0 clk has a configurable divisor.
18 *
19 * We must use a clk_div_table and not a regular power of 2
20 * divisor here, because the first 2 values divide the clock
21 * by 2.
22 */
23static const struct clk_div_table sun6i_a31_apb0_divs[] = {
24 { .val = 0, .div = 2, },
25 { .val = 1, .div = 2, },
26 { .val = 2, .div = 4, },
27 { .val = 3, .div = 8, },
28 { /* sentinel */ },
29};
30
31static int sun6i_a31_apb0_clk_probe(struct platform_device *pdev)
32{
33 struct device_node *np = pdev->dev.of_node;
34 const char *clk_name = np->name;
35 const char *clk_parent;
36 struct resource *r;
37 void __iomem *reg;
38 struct clk *clk;
39
40 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
41 reg = devm_ioremap_resource(&pdev->dev, r);
42 if (IS_ERR(reg))
43 return PTR_ERR(reg);
44
45 clk_parent = of_clk_get_parent_name(np, 0);
46 if (!clk_parent)
47 return -EINVAL;
48
49 of_property_read_string(np, "clock-output-names", &clk_name);
50
51 clk = clk_register_divider_table(&pdev->dev, clk_name, clk_parent,
52 0, reg, 0, 2, 0, sun6i_a31_apb0_divs,
53 NULL);
54 if (IS_ERR(clk))
55 return PTR_ERR(clk);
56
57 return of_clk_add_provider(np, of_clk_src_simple_get, clk);
58}
59
60const struct of_device_id sun6i_a31_apb0_clk_dt_ids[] = {
61 { .compatible = "allwinner,sun6i-a31-apb0-clk" },
62 { /* sentinel */ }
63};
64
65static struct platform_driver sun6i_a31_apb0_clk_driver = {
66 .driver = {
67 .name = "sun6i-a31-apb0-clk",
68 .owner = THIS_MODULE,
69 .of_match_table = sun6i_a31_apb0_clk_dt_ids,
70 },
71 .probe = sun6i_a31_apb0_clk_probe,
72};
73module_platform_driver(sun6i_a31_apb0_clk_driver);
74
75MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>");
76MODULE_DESCRIPTION("Allwinner A31 APB0 clock Driver");
77MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/sunxi/clk-sun6i-ar100.c b/drivers/clk/sunxi/clk-sun6i-ar100.c
new file mode 100644
index 000000000000..f73cc051f0dd
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun6i-ar100.c
@@ -0,0 +1,233 @@
1/*
2 * Copyright (C) 2014 Free Electrons
3 *
4 * License Terms: GNU General Public License v2
5 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
6 *
7 * Allwinner A31 AR100 clock driver
8 *
9 */
10
11#include <linux/clk-provider.h>
12#include <linux/module.h>
13#include <linux/of.h>
14#include <linux/platform_device.h>
15
16#define SUN6I_AR100_MAX_PARENTS 4
17#define SUN6I_AR100_SHIFT_MASK 0x3
18#define SUN6I_AR100_SHIFT_MAX SUN6I_AR100_SHIFT_MASK
19#define SUN6I_AR100_SHIFT_SHIFT 4
20#define SUN6I_AR100_DIV_MASK 0x1f
21#define SUN6I_AR100_DIV_MAX (SUN6I_AR100_DIV_MASK + 1)
22#define SUN6I_AR100_DIV_SHIFT 8
23#define SUN6I_AR100_MUX_MASK 0x3
24#define SUN6I_AR100_MUX_SHIFT 16
25
26struct ar100_clk {
27 struct clk_hw hw;
28 void __iomem *reg;
29};
30
31static inline struct ar100_clk *to_ar100_clk(struct clk_hw *hw)
32{
33 return container_of(hw, struct ar100_clk, hw);
34}
35
36static unsigned long ar100_recalc_rate(struct clk_hw *hw,
37 unsigned long parent_rate)
38{
39 struct ar100_clk *clk = to_ar100_clk(hw);
40 u32 val = readl(clk->reg);
41 int shift = (val >> SUN6I_AR100_SHIFT_SHIFT) & SUN6I_AR100_SHIFT_MASK;
42 int div = (val >> SUN6I_AR100_DIV_SHIFT) & SUN6I_AR100_DIV_MASK;
43
44 return (parent_rate >> shift) / (div + 1);
45}
46
47static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate,
48 unsigned long *best_parent_rate,
49 struct clk **best_parent_clk)
50{
51 int nparents = __clk_get_num_parents(hw->clk);
52 long best_rate = -EINVAL;
53 int i;
54
55 *best_parent_clk = NULL;
56
57 for (i = 0; i < nparents; i++) {
58 unsigned long parent_rate;
59 unsigned long tmp_rate;
60 struct clk *parent;
61 unsigned long div;
62 int shift;
63
64 parent = clk_get_parent_by_index(hw->clk, i);
65 parent_rate = __clk_get_rate(parent);
66 div = DIV_ROUND_UP(parent_rate, rate);
67
68 /*
69 * The AR100 clk contains 2 divisors:
70 * - one power of 2 divisor
71 * - one regular divisor
72 *
73 * First check if we can safely shift (or divide by a power
74 * of 2) without losing precision on the requested rate.
75 */
76 shift = ffs(div) - 1;
77 if (shift > SUN6I_AR100_SHIFT_MAX)
78 shift = SUN6I_AR100_SHIFT_MAX;
79
80 div >>= shift;
81
82 /*
83 * Then if the divisor is still bigger than what the HW
84 * actually supports, use a bigger shift (or power of 2
85 * divider) value and accept to lose some precision.
86 */
87 while (div > SUN6I_AR100_DIV_MAX) {
88 shift++;
89 div >>= 1;
90 if (shift > SUN6I_AR100_SHIFT_MAX)
91 break;
92 }
93
94 /*
95 * If the shift value (or power of 2 divider) is bigger
96 * than what the HW actually support, skip this parent.
97 */
98 if (shift > SUN6I_AR100_SHIFT_MAX)
99 continue;
100
101 tmp_rate = (parent_rate >> shift) / div;
102 if (!*best_parent_clk || tmp_rate > best_rate) {
103 *best_parent_clk = parent;
104 *best_parent_rate = parent_rate;
105 best_rate = tmp_rate;
106 }
107 }
108
109 return best_rate;
110}
111
112static int ar100_set_parent(struct clk_hw *hw, u8 index)
113{
114 struct ar100_clk *clk = to_ar100_clk(hw);
115 u32 val = readl(clk->reg);
116
117 if (index >= SUN6I_AR100_MAX_PARENTS)
118 return -EINVAL;
119
120 val &= ~(SUN6I_AR100_MUX_MASK << SUN6I_AR100_MUX_SHIFT);
121 val |= (index << SUN6I_AR100_MUX_SHIFT);
122 writel(val, clk->reg);
123
124 return 0;
125}
126
127static u8 ar100_get_parent(struct clk_hw *hw)
128{
129 struct ar100_clk *clk = to_ar100_clk(hw);
130 return (readl(clk->reg) >> SUN6I_AR100_MUX_SHIFT) &
131 SUN6I_AR100_MUX_MASK;
132}
133
134static int ar100_set_rate(struct clk_hw *hw, unsigned long rate,
135 unsigned long parent_rate)
136{
137 unsigned long div = parent_rate / rate;
138 struct ar100_clk *clk = to_ar100_clk(hw);
139 u32 val = readl(clk->reg);
140 int shift;
141
142 if (parent_rate % rate)
143 return -EINVAL;
144
145 shift = ffs(div) - 1;
146 if (shift > SUN6I_AR100_SHIFT_MAX)
147 shift = SUN6I_AR100_SHIFT_MAX;
148
149 div >>= shift;
150
151 if (div > SUN6I_AR100_DIV_MAX)
152 return -EINVAL;
153
154 val &= ~((SUN6I_AR100_SHIFT_MASK << SUN6I_AR100_SHIFT_SHIFT) |
155 (SUN6I_AR100_DIV_MASK << SUN6I_AR100_DIV_SHIFT));
156 val |= (shift << SUN6I_AR100_SHIFT_SHIFT) |
157 (div << SUN6I_AR100_DIV_SHIFT);
158 writel(val, clk->reg);
159
160 return 0;
161}
162
163struct clk_ops ar100_ops = {
164 .recalc_rate = ar100_recalc_rate,
165 .determine_rate = ar100_determine_rate,
166 .set_parent = ar100_set_parent,
167 .get_parent = ar100_get_parent,
168 .set_rate = ar100_set_rate,
169};
170
171static int sun6i_a31_ar100_clk_probe(struct platform_device *pdev)
172{
173 const char *parents[SUN6I_AR100_MAX_PARENTS];
174 struct device_node *np = pdev->dev.of_node;
175 const char *clk_name = np->name;
176 struct clk_init_data init;
177 struct ar100_clk *ar100;
178 struct resource *r;
179 struct clk *clk;
180 int nparents;
181 int i;
182
183 ar100 = devm_kzalloc(&pdev->dev, sizeof(*ar100), GFP_KERNEL);
184 if (!ar100)
185 return -ENOMEM;
186
187 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
188 ar100->reg = devm_ioremap_resource(&pdev->dev, r);
189 if (IS_ERR(ar100->reg))
190 return PTR_ERR(ar100->reg);
191
192 nparents = of_clk_get_parent_count(np);
193 if (nparents > SUN6I_AR100_MAX_PARENTS)
194 nparents = SUN6I_AR100_MAX_PARENTS;
195
196 for (i = 0; i < nparents; i++)
197 parents[i] = of_clk_get_parent_name(np, i);
198
199 of_property_read_string(np, "clock-output-names", &clk_name);
200
201 init.name = clk_name;
202 init.ops = &ar100_ops;
203 init.parent_names = parents;
204 init.num_parents = nparents;
205 init.flags = 0;
206
207 ar100->hw.init = &init;
208
209 clk = clk_register(&pdev->dev, &ar100->hw);
210 if (IS_ERR(clk))
211 return PTR_ERR(clk);
212
213 return of_clk_add_provider(np, of_clk_src_simple_get, clk);
214}
215
216const struct of_device_id sun6i_a31_ar100_clk_dt_ids[] = {
217 { .compatible = "allwinner,sun6i-a31-ar100-clk" },
218 { /* sentinel */ }
219};
220
221static struct platform_driver sun6i_a31_ar100_clk_driver = {
222 .driver = {
223 .name = "sun6i-a31-ar100-clk",
224 .owner = THIS_MODULE,
225 .of_match_table = sun6i_a31_ar100_clk_dt_ids,
226 },
227 .probe = sun6i_a31_ar100_clk_probe,
228};
229module_platform_driver(sun6i_a31_ar100_clk_driver);
230
231MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>");
232MODULE_DESCRIPTION("Allwinner A31 AR100 clock Driver");
233MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 426483422d3d..fb2ce8440f0e 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -28,63 +28,6 @@ static DEFINE_SPINLOCK(clk_lock);
28#define SUNXI_MAX_PARENTS 5 28#define SUNXI_MAX_PARENTS 5
29 29
30/** 30/**
31 * sun4i_osc_clk_setup() - Setup function for gatable oscillator
32 */
33
34#define SUNXI_OSC24M_GATE 0
35
36static void __init sun4i_osc_clk_setup(struct device_node *node)
37{
38 struct clk *clk;
39 struct clk_fixed_rate *fixed;
40 struct clk_gate *gate;
41 const char *clk_name = node->name;
42 u32 rate;
43
44 if (of_property_read_u32(node, "clock-frequency", &rate))
45 return;
46
47 /* allocate fixed-rate and gate clock structs */
48 fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL);
49 if (!fixed)
50 return;
51 gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
52 if (!gate)
53 goto err_free_fixed;
54
55 of_property_read_string(node, "clock-output-names", &clk_name);
56
57 /* set up gate and fixed rate properties */
58 gate->reg = of_iomap(node, 0);
59 gate->bit_idx = SUNXI_OSC24M_GATE;
60 gate->lock = &clk_lock;
61 fixed->fixed_rate = rate;
62
63 clk = clk_register_composite(NULL, clk_name,
64 NULL, 0,
65 NULL, NULL,
66 &fixed->hw, &clk_fixed_rate_ops,
67 &gate->hw, &clk_gate_ops,
68 CLK_IS_ROOT);
69
70 if (IS_ERR(clk))
71 goto err_free_gate;
72
73 of_clk_add_provider(node, of_clk_src_simple_get, clk);
74 clk_register_clkdev(clk, clk_name, NULL);
75
76 return;
77
78err_free_gate:
79 kfree(gate);
80err_free_fixed:
81 kfree(fixed);
82}
83CLK_OF_DECLARE(sun4i_osc, "allwinner,sun4i-a10-osc-clk", sun4i_osc_clk_setup);
84
85
86
87/**
88 * sun4i_get_pll1_factors() - calculates n, k, m, p factors for PLL1 31 * sun4i_get_pll1_factors() - calculates n, k, m, p factors for PLL1
89 * PLL1 rate is calculated as follows 32 * PLL1 rate is calculated as follows
90 * rate = (parent_rate * n * (k + 1) >> p) / (m + 1); 33 * rate = (parent_rate * n * (k + 1) >> p) / (m + 1);
@@ -408,104 +351,6 @@ static void sun7i_a20_get_out_factors(u32 *freq, u32 parent_rate,
408 *p = calcp; 351 *p = calcp;
409} 352}
410 353
411
412
413/**
414 * sun7i_a20_gmac_clk_setup - Setup function for A20/A31 GMAC clock module
415 *
416 * This clock looks something like this
417 * ________________________
418 * MII TX clock from PHY >-----|___________ _________|----> to GMAC core
419 * GMAC Int. RGMII TX clk >----|___________\__/__gate---|----> to PHY
420 * Ext. 125MHz RGMII TX clk >--|__divider__/ |
421 * |________________________|
422 *
423 * The external 125 MHz reference is optional, i.e. GMAC can use its
424 * internal TX clock just fine. The A31 GMAC clock module does not have
425 * the divider controls for the external reference.
426 *
427 * To keep it simple, let the GMAC use either the MII TX clock for MII mode,
428 * and its internal TX clock for GMII and RGMII modes. The GMAC driver should
429 * select the appropriate source and gate/ungate the output to the PHY.
430 *
431 * Only the GMAC should use this clock. Altering the clock so that it doesn't
432 * match the GMAC's operation parameters will result in the GMAC not being
433 * able to send traffic out. The GMAC driver should set the clock rate and
434 * enable/disable this clock to configure the required state. The clock
435 * driver then responds by auto-reparenting the clock.
436 */
437
438#define SUN7I_A20_GMAC_GPIT 2
439#define SUN7I_A20_GMAC_MASK 0x3
440#define SUN7I_A20_GMAC_PARENTS 2
441
442static void __init sun7i_a20_gmac_clk_setup(struct device_node *node)
443{
444 struct clk *clk;
445 struct clk_mux *mux;
446 struct clk_gate *gate;
447 const char *clk_name = node->name;
448 const char *parents[SUN7I_A20_GMAC_PARENTS];
449 void *reg;
450
451 if (of_property_read_string(node, "clock-output-names", &clk_name))
452 return;
453
454 /* allocate mux and gate clock structs */
455 mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
456 if (!mux)
457 return;
458
459 gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
460 if (!gate)
461 goto free_mux;
462
463 /* gmac clock requires exactly 2 parents */
464 parents[0] = of_clk_get_parent_name(node, 0);
465 parents[1] = of_clk_get_parent_name(node, 1);
466 if (!parents[0] || !parents[1])
467 goto free_gate;
468
469 reg = of_iomap(node, 0);
470 if (!reg)
471 goto free_gate;
472
473 /* set up gate and fixed rate properties */
474 gate->reg = reg;
475 gate->bit_idx = SUN7I_A20_GMAC_GPIT;
476 gate->lock = &clk_lock;
477 mux->reg = reg;
478 mux->mask = SUN7I_A20_GMAC_MASK;
479 mux->flags = CLK_MUX_INDEX_BIT;
480 mux->lock = &clk_lock;
481
482 clk = clk_register_composite(NULL, clk_name,
483 parents, SUN7I_A20_GMAC_PARENTS,
484 &mux->hw, &clk_mux_ops,
485 NULL, NULL,
486 &gate->hw, &clk_gate_ops,
487 0);
488
489 if (IS_ERR(clk))
490 goto iounmap_reg;
491
492 of_clk_add_provider(node, of_clk_src_simple_get, clk);
493 clk_register_clkdev(clk, clk_name, NULL);
494
495 return;
496
497iounmap_reg:
498 iounmap(reg);
499free_gate:
500 kfree(gate);
501free_mux:
502 kfree(mux);
503}
504CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk",
505 sun7i_a20_gmac_clk_setup);
506
507
508
509/** 354/**
510 * clk_sunxi_mmc_phase_control() - configures MMC clock phase control 355 * clk_sunxi_mmc_phase_control() - configures MMC clock phase control
511 */ 356 */
@@ -1009,6 +854,11 @@ static const struct gates_data sun5i_a13_usb_gates_data __initconst = {
1009 .reset_mask = 0x03, 854 .reset_mask = 0x03,
1010}; 855};
1011 856
857static const struct gates_data sun6i_a31_usb_gates_data __initconst = {
858 .mask = { BIT(18) | BIT(17) | BIT(16) | BIT(10) | BIT(9) | BIT(8) },
859 .reset_mask = BIT(2) | BIT(1) | BIT(0),
860};
861
1012static void __init sunxi_gates_clk_setup(struct device_node *node, 862static void __init sunxi_gates_clk_setup(struct device_node *node,
1013 struct gates_data *data) 863 struct gates_data *data)
1014{ 864{
@@ -1304,6 +1154,7 @@ static const struct of_device_id clk_gates_match[] __initconst = {
1304 {.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,}, 1154 {.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,},
1305 {.compatible = "allwinner,sun4i-a10-usb-clk", .data = &sun4i_a10_usb_gates_data,}, 1155 {.compatible = "allwinner,sun4i-a10-usb-clk", .data = &sun4i_a10_usb_gates_data,},
1306 {.compatible = "allwinner,sun5i-a13-usb-clk", .data = &sun5i_a13_usb_gates_data,}, 1156 {.compatible = "allwinner,sun5i-a13-usb-clk", .data = &sun5i_a13_usb_gates_data,},
1157 {.compatible = "allwinner,sun6i-a31-usb-clk", .data = &sun6i_a31_usb_gates_data,},
1307 {} 1158 {}
1308}; 1159};
1309 1160
@@ -1321,33 +1172,10 @@ static void __init of_sunxi_table_clock_setup(const struct of_device_id *clk_mat
1321 } 1172 }
1322} 1173}
1323 1174
1324/** 1175static void __init sunxi_init_clocks(const char *clocks[], int nclocks)
1325 * System clock protection
1326 *
1327 * By enabling these critical clocks, we prevent their accidental gating
1328 * by the framework
1329 */
1330static void __init sunxi_clock_protect(void)
1331{ 1176{
1332 struct clk *clk; 1177 unsigned int i;
1333
1334 /* memory bus clock - sun5i+ */
1335 clk = clk_get(NULL, "mbus");
1336 if (!IS_ERR(clk)) {
1337 clk_prepare_enable(clk);
1338 clk_put(clk);
1339 }
1340
1341 /* DDR clock - sun4i+ */
1342 clk = clk_get(NULL, "pll5_ddr");
1343 if (!IS_ERR(clk)) {
1344 clk_prepare_enable(clk);
1345 clk_put(clk);
1346 }
1347}
1348 1178
1349static void __init sunxi_init_clocks(struct device_node *np)
1350{
1351 /* Register factor clocks */ 1179 /* Register factor clocks */
1352 of_sunxi_table_clock_setup(clk_factors_match, sunxi_factors_clk_setup); 1180 of_sunxi_table_clock_setup(clk_factors_match, sunxi_factors_clk_setup);
1353 1181
@@ -1363,11 +1191,48 @@ static void __init sunxi_init_clocks(struct device_node *np)
1363 /* Register gate clocks */ 1191 /* Register gate clocks */
1364 of_sunxi_table_clock_setup(clk_gates_match, sunxi_gates_clk_setup); 1192 of_sunxi_table_clock_setup(clk_gates_match, sunxi_gates_clk_setup);
1365 1193
1366 /* Enable core system clocks */ 1194 /* Protect the clocks that needs to stay on */
1367 sunxi_clock_protect(); 1195 for (i = 0; i < nclocks; i++) {
1196 struct clk *clk = clk_get(NULL, clocks[i]);
1197
1198 if (!IS_ERR(clk))
1199 clk_prepare_enable(clk);
1200 }
1201}
1202
1203static const char *sun4i_a10_critical_clocks[] __initdata = {
1204 "pll5_ddr",
1205};
1206
1207static void __init sun4i_a10_init_clocks(struct device_node *node)
1208{
1209 sunxi_init_clocks(sun4i_a10_critical_clocks,
1210 ARRAY_SIZE(sun4i_a10_critical_clocks));
1211}
1212CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sun4i_a10_init_clocks);
1213
1214static const char *sun5i_critical_clocks[] __initdata = {
1215 "mbus",
1216 "pll5_ddr",
1217};
1218
1219static void __init sun5i_init_clocks(struct device_node *node)
1220{
1221 sunxi_init_clocks(sun5i_critical_clocks,
1222 ARRAY_SIZE(sun5i_critical_clocks));
1223}
1224CLK_OF_DECLARE(sun5i_a10s_clk_init, "allwinner,sun5i-a10s", sun5i_init_clocks);
1225CLK_OF_DECLARE(sun5i_a13_clk_init, "allwinner,sun5i-a13", sun5i_init_clocks);
1226CLK_OF_DECLARE(sun7i_a20_clk_init, "allwinner,sun7i-a20", sun5i_init_clocks);
1227
1228static const char *sun6i_critical_clocks[] __initdata = {
1229 "cpu",
1230 "ahb1_sdram",
1231};
1232
1233static void __init sun6i_init_clocks(struct device_node *node)
1234{
1235 sunxi_init_clocks(sun6i_critical_clocks,
1236 ARRAY_SIZE(sun6i_critical_clocks));
1368} 1237}
1369CLK_OF_DECLARE(sun4i_a10_clk_init, "allwinner,sun4i-a10", sunxi_init_clocks); 1238CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sun6i_init_clocks);
1370CLK_OF_DECLARE(sun5i_a10s_clk_init, "allwinner,sun5i-a10s", sunxi_init_clocks);
1371CLK_OF_DECLARE(sun5i_a13_clk_init, "allwinner,sun5i-a13", sunxi_init_clocks);
1372CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sunxi_init_clocks);
1373CLK_OF_DECLARE(sun7i_a20_clk_init, "allwinner,sun7i-a20", sunxi_init_clocks);