1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright 2013-2015 Emilio López
5 * Emilio López <emilio@elopez.com.ar>
9 #include <linux/clk-provider.h>
12 #include <linux/of_address.h>
13 #include <linux/reset-controller.h>
14 #include <linux/slab.h>
15 #include <linux/spinlock.h>
19 * sunxi_usb_reset... - reset bits in usb clk registers handling
22 struct usb_reset_data
{
26 struct reset_controller_dev rcdev
;
29 static int sunxi_usb_reset_assert(struct reset_controller_dev
*rcdev
,
32 struct usb_reset_data
*data
= container_of(rcdev
,
33 struct usb_reset_data
,
38 clk_prepare_enable(data
->clk
);
39 spin_lock_irqsave(data
->lock
, flags
);
41 reg
= readl(data
->reg
);
42 writel(reg
& ~BIT(id
), data
->reg
);
44 spin_unlock_irqrestore(data
->lock
, flags
);
45 clk_disable_unprepare(data
->clk
);
50 static int sunxi_usb_reset_deassert(struct reset_controller_dev
*rcdev
,
53 struct usb_reset_data
*data
= container_of(rcdev
,
54 struct usb_reset_data
,
59 clk_prepare_enable(data
->clk
);
60 spin_lock_irqsave(data
->lock
, flags
);
62 reg
= readl(data
->reg
);
63 writel(reg
| BIT(id
), data
->reg
);
65 spin_unlock_irqrestore(data
->lock
, flags
);
66 clk_disable_unprepare(data
->clk
);
71 static const struct reset_control_ops sunxi_usb_reset_ops
= {
72 .assert = sunxi_usb_reset_assert
,
73 .deassert
= sunxi_usb_reset_deassert
,
77 #define SUNXI_USB_MAX_SIZE 32
86 * sunxi_usb_clk_setup() - Setup function for usb gate clocks
87 * @node: &struct device_node for the clock
88 * @data: &struct usb_clk_data for the clock
89 * @lock: spinlock for the clock
91 static void __init
sunxi_usb_clk_setup(struct device_node
*node
,
92 const struct usb_clk_data
*data
,
95 struct clk_onecell_data
*clk_data
;
96 struct usb_reset_data
*reset_data
;
97 const char *clk_parent
;
104 reg
= of_io_request_and_map(node
, 0, of_node_full_name(node
));
108 clk_parent
= of_clk_get_parent_name(node
, 0);
112 /* Worst-case size approximation and memory allocation */
113 qty
= find_last_bit((unsigned long *)&data
->clk_mask
,
116 clk_data
= kmalloc(sizeof(struct clk_onecell_data
), GFP_KERNEL
);
120 clk_data
->clks
= kcalloc(qty
+ 1, sizeof(struct clk
*), GFP_KERNEL
);
121 if (!clk_data
->clks
) {
126 for_each_set_bit(i
, (unsigned long *)&data
->clk_mask
,
127 SUNXI_USB_MAX_SIZE
) {
128 of_property_read_string_index(node
, "clock-output-names",
130 clk_data
->clks
[i
] = clk_register_gate(NULL
, clk_name
,
133 WARN_ON(IS_ERR(clk_data
->clks
[i
]));
138 /* Adjust to the real max */
139 clk_data
->clk_num
= i
;
141 of_clk_add_provider(node
, of_clk_src_onecell_get
, clk_data
);
143 /* Register a reset controller for usb with reset bits */
144 if (data
->reset_mask
== 0)
147 reset_data
= kzalloc(sizeof(*reset_data
), GFP_KERNEL
);
151 if (data
->reset_needs_clk
) {
152 reset_data
->clk
= of_clk_get(node
, 0);
153 if (IS_ERR(reset_data
->clk
)) {
154 pr_err("Could not get clock for reset controls\n");
160 reset_data
->reg
= reg
;
161 reset_data
->lock
= lock
;
162 reset_data
->rcdev
.nr_resets
= __fls(data
->reset_mask
) + 1;
163 reset_data
->rcdev
.ops
= &sunxi_usb_reset_ops
;
164 reset_data
->rcdev
.of_node
= node
;
165 reset_controller_register(&reset_data
->rcdev
);
168 static const struct usb_clk_data sun4i_a10_usb_clk_data __initconst
= {
169 .clk_mask
= BIT(8) | BIT(7) | BIT(6),
170 .reset_mask
= BIT(2) | BIT(1) | BIT(0),
173 static DEFINE_SPINLOCK(sun4i_a10_usb_lock
);
175 static void __init
sun4i_a10_usb_setup(struct device_node
*node
)
177 sunxi_usb_clk_setup(node
, &sun4i_a10_usb_clk_data
, &sun4i_a10_usb_lock
);
179 CLK_OF_DECLARE(sun4i_a10_usb
, "allwinner,sun4i-a10-usb-clk", sun4i_a10_usb_setup
);
181 static const struct usb_clk_data sun5i_a13_usb_clk_data __initconst
= {
182 .clk_mask
= BIT(8) | BIT(6),
183 .reset_mask
= BIT(1) | BIT(0),
186 static void __init
sun5i_a13_usb_setup(struct device_node
*node
)
188 sunxi_usb_clk_setup(node
, &sun5i_a13_usb_clk_data
, &sun4i_a10_usb_lock
);
190 CLK_OF_DECLARE(sun5i_a13_usb
, "allwinner,sun5i-a13-usb-clk", sun5i_a13_usb_setup
);
192 static const struct usb_clk_data sun6i_a31_usb_clk_data __initconst
= {
193 .clk_mask
= BIT(18) | BIT(17) | BIT(16) | BIT(10) | BIT(9) | BIT(8),
194 .reset_mask
= BIT(2) | BIT(1) | BIT(0),
197 static void __init
sun6i_a31_usb_setup(struct device_node
*node
)
199 sunxi_usb_clk_setup(node
, &sun6i_a31_usb_clk_data
, &sun4i_a10_usb_lock
);
201 CLK_OF_DECLARE(sun6i_a31_usb
, "allwinner,sun6i-a31-usb-clk", sun6i_a31_usb_setup
);
203 static const struct usb_clk_data sun8i_a23_usb_clk_data __initconst
= {
204 .clk_mask
= BIT(16) | BIT(11) | BIT(10) | BIT(9) | BIT(8),
205 .reset_mask
= BIT(2) | BIT(1) | BIT(0),
208 static void __init
sun8i_a23_usb_setup(struct device_node
*node
)
210 sunxi_usb_clk_setup(node
, &sun8i_a23_usb_clk_data
, &sun4i_a10_usb_lock
);
212 CLK_OF_DECLARE(sun8i_a23_usb
, "allwinner,sun8i-a23-usb-clk", sun8i_a23_usb_setup
);
214 static const struct usb_clk_data sun8i_h3_usb_clk_data __initconst
= {
215 .clk_mask
= BIT(19) | BIT(18) | BIT(17) | BIT(16) |
216 BIT(11) | BIT(10) | BIT(9) | BIT(8),
217 .reset_mask
= BIT(3) | BIT(2) | BIT(1) | BIT(0),
220 static void __init
sun8i_h3_usb_setup(struct device_node
*node
)
222 sunxi_usb_clk_setup(node
, &sun8i_h3_usb_clk_data
, &sun4i_a10_usb_lock
);
224 CLK_OF_DECLARE(sun8i_h3_usb
, "allwinner,sun8i-h3-usb-clk", sun8i_h3_usb_setup
);
226 static const struct usb_clk_data sun9i_a80_usb_mod_data __initconst
= {
227 .clk_mask
= BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1),
228 .reset_mask
= BIT(19) | BIT(18) | BIT(17),
229 .reset_needs_clk
= 1,
232 static DEFINE_SPINLOCK(a80_usb_mod_lock
);
234 static void __init
sun9i_a80_usb_mod_setup(struct device_node
*node
)
236 sunxi_usb_clk_setup(node
, &sun9i_a80_usb_mod_data
, &a80_usb_mod_lock
);
238 CLK_OF_DECLARE(sun9i_a80_usb_mod
, "allwinner,sun9i-a80-usb-mod-clk", sun9i_a80_usb_mod_setup
);
240 static const struct usb_clk_data sun9i_a80_usb_phy_data __initconst
= {
241 .clk_mask
= BIT(10) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1),
242 .reset_mask
= BIT(21) | BIT(20) | BIT(19) | BIT(18) | BIT(17),
243 .reset_needs_clk
= 1,
246 static DEFINE_SPINLOCK(a80_usb_phy_lock
);
248 static void __init
sun9i_a80_usb_phy_setup(struct device_node
*node
)
250 sunxi_usb_clk_setup(node
, &sun9i_a80_usb_phy_data
, &a80_usb_phy_lock
);
252 CLK_OF_DECLARE(sun9i_a80_usb_phy
, "allwinner,sun9i-a80-usb-phy-clk", sun9i_a80_usb_phy_setup
);