2 * Copyright 2013-2015 Emilio López
4 * Emilio López <emilio@elopez.com.ar>
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.
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.
17 #include <linux/clk.h>
18 #include <linux/clk-provider.h>
20 #include <linux/of_address.h>
21 #include <linux/reset-controller.h>
22 #include <linux/slab.h>
23 #include <linux/spinlock.h>
27 * sunxi_usb_reset... - reset bits in usb clk registers handling
30 struct usb_reset_data
{
34 struct reset_controller_dev rcdev
;
37 static int sunxi_usb_reset_assert(struct reset_controller_dev
*rcdev
,
40 struct usb_reset_data
*data
= container_of(rcdev
,
41 struct usb_reset_data
,
46 clk_prepare_enable(data
->clk
);
47 spin_lock_irqsave(data
->lock
, flags
);
49 reg
= readl(data
->reg
);
50 writel(reg
& ~BIT(id
), data
->reg
);
52 spin_unlock_irqrestore(data
->lock
, flags
);
53 clk_disable_unprepare(data
->clk
);
58 static int sunxi_usb_reset_deassert(struct reset_controller_dev
*rcdev
,
61 struct usb_reset_data
*data
= container_of(rcdev
,
62 struct usb_reset_data
,
67 clk_prepare_enable(data
->clk
);
68 spin_lock_irqsave(data
->lock
, flags
);
70 reg
= readl(data
->reg
);
71 writel(reg
| BIT(id
), data
->reg
);
73 spin_unlock_irqrestore(data
->lock
, flags
);
74 clk_disable_unprepare(data
->clk
);
79 static const struct reset_control_ops sunxi_usb_reset_ops
= {
80 .assert = sunxi_usb_reset_assert
,
81 .deassert
= sunxi_usb_reset_deassert
,
85 * sunxi_usb_clk_setup() - Setup function for usb gate clocks
88 #define SUNXI_USB_MAX_SIZE 32
96 static void __init
sunxi_usb_clk_setup(struct device_node
*node
,
97 const struct usb_clk_data
*data
,
100 struct clk_onecell_data
*clk_data
;
101 struct usb_reset_data
*reset_data
;
102 const char *clk_parent
;
103 const char *clk_name
;
109 reg
= of_io_request_and_map(node
, 0, of_node_full_name(node
));
113 clk_parent
= of_clk_get_parent_name(node
, 0);
117 /* Worst-case size approximation and memory allocation */
118 qty
= find_last_bit((unsigned long *)&data
->clk_mask
,
121 clk_data
= kmalloc(sizeof(struct clk_onecell_data
), GFP_KERNEL
);
125 clk_data
->clks
= kcalloc(qty
+ 1, sizeof(struct clk
*), GFP_KERNEL
);
126 if (!clk_data
->clks
) {
131 for_each_set_bit(i
, (unsigned long *)&data
->clk_mask
,
132 SUNXI_USB_MAX_SIZE
) {
133 of_property_read_string_index(node
, "clock-output-names",
135 clk_data
->clks
[i
] = clk_register_gate(NULL
, clk_name
,
138 WARN_ON(IS_ERR(clk_data
->clks
[i
]));
143 /* Adjust to the real max */
144 clk_data
->clk_num
= i
;
146 of_clk_add_provider(node
, of_clk_src_onecell_get
, clk_data
);
148 /* Register a reset controller for usb with reset bits */
149 if (data
->reset_mask
== 0)
152 reset_data
= kzalloc(sizeof(*reset_data
), GFP_KERNEL
);
156 if (data
->reset_needs_clk
) {
157 reset_data
->clk
= of_clk_get(node
, 0);
158 if (IS_ERR(reset_data
->clk
)) {
159 pr_err("Could not get clock for reset controls\n");
165 reset_data
->reg
= reg
;
166 reset_data
->lock
= lock
;
167 reset_data
->rcdev
.nr_resets
= __fls(data
->reset_mask
) + 1;
168 reset_data
->rcdev
.ops
= &sunxi_usb_reset_ops
;
169 reset_data
->rcdev
.of_node
= node
;
170 reset_controller_register(&reset_data
->rcdev
);
173 static const struct usb_clk_data sun4i_a10_usb_clk_data __initconst
= {
174 .clk_mask
= BIT(8) | BIT(7) | BIT(6),
175 .reset_mask
= BIT(2) | BIT(1) | BIT(0),
178 static DEFINE_SPINLOCK(sun4i_a10_usb_lock
);
180 static void __init
sun4i_a10_usb_setup(struct device_node
*node
)
182 sunxi_usb_clk_setup(node
, &sun4i_a10_usb_clk_data
, &sun4i_a10_usb_lock
);
184 CLK_OF_DECLARE(sun4i_a10_usb
, "allwinner,sun4i-a10-usb-clk", sun4i_a10_usb_setup
);
186 static const struct usb_clk_data sun5i_a13_usb_clk_data __initconst
= {
187 .clk_mask
= BIT(8) | BIT(6),
188 .reset_mask
= BIT(1) | BIT(0),
191 static void __init
sun5i_a13_usb_setup(struct device_node
*node
)
193 sunxi_usb_clk_setup(node
, &sun5i_a13_usb_clk_data
, &sun4i_a10_usb_lock
);
195 CLK_OF_DECLARE(sun5i_a13_usb
, "allwinner,sun5i-a13-usb-clk", sun5i_a13_usb_setup
);
197 static const struct usb_clk_data sun6i_a31_usb_clk_data __initconst
= {
198 .clk_mask
= BIT(18) | BIT(17) | BIT(16) | BIT(10) | BIT(9) | BIT(8),
199 .reset_mask
= BIT(2) | BIT(1) | BIT(0),
202 static void __init
sun6i_a31_usb_setup(struct device_node
*node
)
204 sunxi_usb_clk_setup(node
, &sun6i_a31_usb_clk_data
, &sun4i_a10_usb_lock
);
206 CLK_OF_DECLARE(sun6i_a31_usb
, "allwinner,sun6i-a31-usb-clk", sun6i_a31_usb_setup
);
208 static const struct usb_clk_data sun8i_a23_usb_clk_data __initconst
= {
209 .clk_mask
= BIT(16) | BIT(11) | BIT(10) | BIT(9) | BIT(8),
210 .reset_mask
= BIT(2) | BIT(1) | BIT(0),
213 static void __init
sun8i_a23_usb_setup(struct device_node
*node
)
215 sunxi_usb_clk_setup(node
, &sun8i_a23_usb_clk_data
, &sun4i_a10_usb_lock
);
217 CLK_OF_DECLARE(sun8i_a23_usb
, "allwinner,sun8i-a23-usb-clk", sun8i_a23_usb_setup
);
219 static const struct usb_clk_data sun8i_h3_usb_clk_data __initconst
= {
220 .clk_mask
= BIT(19) | BIT(18) | BIT(17) | BIT(16) |
221 BIT(11) | BIT(10) | BIT(9) | BIT(8),
222 .reset_mask
= BIT(3) | BIT(2) | BIT(1) | BIT(0),
225 static void __init
sun8i_h3_usb_setup(struct device_node
*node
)
227 sunxi_usb_clk_setup(node
, &sun8i_h3_usb_clk_data
, &sun4i_a10_usb_lock
);
229 CLK_OF_DECLARE(sun8i_h3_usb
, "allwinner,sun8i-h3-usb-clk", sun8i_h3_usb_setup
);
231 static const struct usb_clk_data sun9i_a80_usb_mod_data __initconst
= {
232 .clk_mask
= BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1),
233 .reset_mask
= BIT(19) | BIT(18) | BIT(17),
234 .reset_needs_clk
= 1,
237 static DEFINE_SPINLOCK(a80_usb_mod_lock
);
239 static void __init
sun9i_a80_usb_mod_setup(struct device_node
*node
)
241 sunxi_usb_clk_setup(node
, &sun9i_a80_usb_mod_data
, &a80_usb_mod_lock
);
243 CLK_OF_DECLARE(sun9i_a80_usb_mod
, "allwinner,sun9i-a80-usb-mod-clk", sun9i_a80_usb_mod_setup
);
245 static const struct usb_clk_data sun9i_a80_usb_phy_data __initconst
= {
246 .clk_mask
= BIT(10) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1),
247 .reset_mask
= BIT(21) | BIT(20) | BIT(19) | BIT(18) | BIT(17),
248 .reset_needs_clk
= 1,
251 static DEFINE_SPINLOCK(a80_usb_phy_lock
);
253 static void __init
sun9i_a80_usb_phy_setup(struct device_node
*node
)
255 sunxi_usb_clk_setup(node
, &sun9i_a80_usb_phy_data
, &a80_usb_phy_lock
);
257 CLK_OF_DECLARE(sun9i_a80_usb_phy
, "allwinner,sun9i-a80-usb-phy-clk", sun9i_a80_usb_phy_setup
);