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>
21 #include <linux/of_address.h>
22 #include <linux/reset-controller.h>
23 #include <linux/slab.h>
24 #include <linux/spinlock.h>
28 * sunxi_usb_reset... - reset bits in usb clk registers handling
31 struct usb_reset_data
{
35 struct reset_controller_dev rcdev
;
38 static int sunxi_usb_reset_assert(struct reset_controller_dev
*rcdev
,
41 struct usb_reset_data
*data
= container_of(rcdev
,
42 struct usb_reset_data
,
47 clk_prepare_enable(data
->clk
);
48 spin_lock_irqsave(data
->lock
, flags
);
50 reg
= readl(data
->reg
);
51 writel(reg
& ~BIT(id
), data
->reg
);
53 spin_unlock_irqrestore(data
->lock
, flags
);
54 clk_disable_unprepare(data
->clk
);
59 static int sunxi_usb_reset_deassert(struct reset_controller_dev
*rcdev
,
62 struct usb_reset_data
*data
= container_of(rcdev
,
63 struct usb_reset_data
,
68 clk_prepare_enable(data
->clk
);
69 spin_lock_irqsave(data
->lock
, flags
);
71 reg
= readl(data
->reg
);
72 writel(reg
| BIT(id
), data
->reg
);
74 spin_unlock_irqrestore(data
->lock
, flags
);
75 clk_disable_unprepare(data
->clk
);
80 static const struct reset_control_ops sunxi_usb_reset_ops
= {
81 .assert = sunxi_usb_reset_assert
,
82 .deassert
= sunxi_usb_reset_deassert
,
86 * sunxi_usb_clk_setup() - Setup function for usb gate clocks
89 #define SUNXI_USB_MAX_SIZE 32
97 static void __init
sunxi_usb_clk_setup(struct device_node
*node
,
98 const struct usb_clk_data
*data
,
101 struct clk_onecell_data
*clk_data
;
102 struct usb_reset_data
*reset_data
;
103 const char *clk_parent
;
104 const char *clk_name
;
110 reg
= of_io_request_and_map(node
, 0, of_node_full_name(node
));
114 clk_parent
= of_clk_get_parent_name(node
, 0);
118 /* Worst-case size approximation and memory allocation */
119 qty
= find_last_bit((unsigned long *)&data
->clk_mask
,
122 clk_data
= kmalloc(sizeof(struct clk_onecell_data
), GFP_KERNEL
);
126 clk_data
->clks
= kcalloc(qty
+ 1, sizeof(struct clk
*), GFP_KERNEL
);
127 if (!clk_data
->clks
) {
132 for_each_set_bit(i
, (unsigned long *)&data
->clk_mask
,
133 SUNXI_USB_MAX_SIZE
) {
134 of_property_read_string_index(node
, "clock-output-names",
136 clk_data
->clks
[i
] = clk_register_gate(NULL
, clk_name
,
139 WARN_ON(IS_ERR(clk_data
->clks
[i
]));
144 /* Adjust to the real max */
145 clk_data
->clk_num
= i
;
147 of_clk_add_provider(node
, of_clk_src_onecell_get
, clk_data
);
149 /* Register a reset controller for usb with reset bits */
150 if (data
->reset_mask
== 0)
153 reset_data
= kzalloc(sizeof(*reset_data
), GFP_KERNEL
);
157 if (data
->reset_needs_clk
) {
158 reset_data
->clk
= of_clk_get(node
, 0);
159 if (IS_ERR(reset_data
->clk
)) {
160 pr_err("Could not get clock for reset controls\n");
166 reset_data
->reg
= reg
;
167 reset_data
->lock
= lock
;
168 reset_data
->rcdev
.nr_resets
= __fls(data
->reset_mask
) + 1;
169 reset_data
->rcdev
.ops
= &sunxi_usb_reset_ops
;
170 reset_data
->rcdev
.of_node
= node
;
171 reset_controller_register(&reset_data
->rcdev
);
174 static const struct usb_clk_data sun4i_a10_usb_clk_data __initconst
= {
175 .clk_mask
= BIT(8) | BIT(7) | BIT(6),
176 .reset_mask
= BIT(2) | BIT(1) | BIT(0),
179 static DEFINE_SPINLOCK(sun4i_a10_usb_lock
);
181 static void __init
sun4i_a10_usb_setup(struct device_node
*node
)
183 sunxi_usb_clk_setup(node
, &sun4i_a10_usb_clk_data
, &sun4i_a10_usb_lock
);
185 CLK_OF_DECLARE(sun4i_a10_usb
, "allwinner,sun4i-a10-usb-clk", sun4i_a10_usb_setup
);
187 static const struct usb_clk_data sun5i_a13_usb_clk_data __initconst
= {
188 .clk_mask
= BIT(8) | BIT(6),
189 .reset_mask
= BIT(1) | BIT(0),
192 static void __init
sun5i_a13_usb_setup(struct device_node
*node
)
194 sunxi_usb_clk_setup(node
, &sun5i_a13_usb_clk_data
, &sun4i_a10_usb_lock
);
196 CLK_OF_DECLARE(sun5i_a13_usb
, "allwinner,sun5i-a13-usb-clk", sun5i_a13_usb_setup
);
198 static const struct usb_clk_data sun6i_a31_usb_clk_data __initconst
= {
199 .clk_mask
= BIT(18) | BIT(17) | BIT(16) | BIT(10) | BIT(9) | BIT(8),
200 .reset_mask
= BIT(2) | BIT(1) | BIT(0),
203 static void __init
sun6i_a31_usb_setup(struct device_node
*node
)
205 sunxi_usb_clk_setup(node
, &sun6i_a31_usb_clk_data
, &sun4i_a10_usb_lock
);
207 CLK_OF_DECLARE(sun6i_a31_usb
, "allwinner,sun6i-a31-usb-clk", sun6i_a31_usb_setup
);
209 static const struct usb_clk_data sun8i_a23_usb_clk_data __initconst
= {
210 .clk_mask
= BIT(16) | BIT(11) | BIT(10) | BIT(9) | BIT(8),
211 .reset_mask
= BIT(2) | BIT(1) | BIT(0),
214 static void __init
sun8i_a23_usb_setup(struct device_node
*node
)
216 sunxi_usb_clk_setup(node
, &sun8i_a23_usb_clk_data
, &sun4i_a10_usb_lock
);
218 CLK_OF_DECLARE(sun8i_a23_usb
, "allwinner,sun8i-a23-usb-clk", sun8i_a23_usb_setup
);
220 static const struct usb_clk_data sun8i_h3_usb_clk_data __initconst
= {
221 .clk_mask
= BIT(19) | BIT(18) | BIT(17) | BIT(16) |
222 BIT(11) | BIT(10) | BIT(9) | BIT(8),
223 .reset_mask
= BIT(3) | BIT(2) | BIT(1) | BIT(0),
226 static void __init
sun8i_h3_usb_setup(struct device_node
*node
)
228 sunxi_usb_clk_setup(node
, &sun8i_h3_usb_clk_data
, &sun4i_a10_usb_lock
);
230 CLK_OF_DECLARE(sun8i_h3_usb
, "allwinner,sun8i-h3-usb-clk", sun8i_h3_usb_setup
);
232 static const struct usb_clk_data sun9i_a80_usb_mod_data __initconst
= {
233 .clk_mask
= BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1),
234 .reset_mask
= BIT(19) | BIT(18) | BIT(17),
235 .reset_needs_clk
= 1,
238 static DEFINE_SPINLOCK(a80_usb_mod_lock
);
240 static void __init
sun9i_a80_usb_mod_setup(struct device_node
*node
)
242 sunxi_usb_clk_setup(node
, &sun9i_a80_usb_mod_data
, &a80_usb_mod_lock
);
244 CLK_OF_DECLARE(sun9i_a80_usb_mod
, "allwinner,sun9i-a80-usb-mod-clk", sun9i_a80_usb_mod_setup
);
246 static const struct usb_clk_data sun9i_a80_usb_phy_data __initconst
= {
247 .clk_mask
= BIT(10) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1),
248 .reset_mask
= BIT(21) | BIT(20) | BIT(19) | BIT(18) | BIT(17),
249 .reset_needs_clk
= 1,
252 static DEFINE_SPINLOCK(a80_usb_phy_lock
);
254 static void __init
sun9i_a80_usb_phy_setup(struct device_node
*node
)
256 sunxi_usb_clk_setup(node
, &sun9i_a80_usb_phy_data
, &a80_usb_phy_lock
);
258 CLK_OF_DECLARE(sun9i_a80_usb_phy
, "allwinner,sun9i-a80-usb-phy-clk", sun9i_a80_usb_phy_setup
);