clk-usb.c (6779B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright 2013-2015 Emilio López 4 * 5 * Emilio López <emilio@elopez.com.ar> 6 */ 7 8#include <linux/clk.h> 9#include <linux/clk-provider.h> 10#include <linux/io.h> 11#include <linux/of.h> 12#include <linux/of_address.h> 13#include <linux/reset-controller.h> 14#include <linux/slab.h> 15#include <linux/spinlock.h> 16 17 18/* 19 * sunxi_usb_reset... - reset bits in usb clk registers handling 20 */ 21 22struct usb_reset_data { 23 void __iomem *reg; 24 spinlock_t *lock; 25 struct clk *clk; 26 struct reset_controller_dev rcdev; 27}; 28 29static int sunxi_usb_reset_assert(struct reset_controller_dev *rcdev, 30 unsigned long id) 31{ 32 struct usb_reset_data *data = container_of(rcdev, 33 struct usb_reset_data, 34 rcdev); 35 unsigned long flags; 36 u32 reg; 37 38 clk_prepare_enable(data->clk); 39 spin_lock_irqsave(data->lock, flags); 40 41 reg = readl(data->reg); 42 writel(reg & ~BIT(id), data->reg); 43 44 spin_unlock_irqrestore(data->lock, flags); 45 clk_disable_unprepare(data->clk); 46 47 return 0; 48} 49 50static int sunxi_usb_reset_deassert(struct reset_controller_dev *rcdev, 51 unsigned long id) 52{ 53 struct usb_reset_data *data = container_of(rcdev, 54 struct usb_reset_data, 55 rcdev); 56 unsigned long flags; 57 u32 reg; 58 59 clk_prepare_enable(data->clk); 60 spin_lock_irqsave(data->lock, flags); 61 62 reg = readl(data->reg); 63 writel(reg | BIT(id), data->reg); 64 65 spin_unlock_irqrestore(data->lock, flags); 66 clk_disable_unprepare(data->clk); 67 68 return 0; 69} 70 71static const struct reset_control_ops sunxi_usb_reset_ops = { 72 .assert = sunxi_usb_reset_assert, 73 .deassert = sunxi_usb_reset_deassert, 74}; 75 76/** 77 * sunxi_usb_clk_setup() - Setup function for usb gate clocks 78 */ 79 80#define SUNXI_USB_MAX_SIZE 32 81 82struct usb_clk_data { 83 u32 clk_mask; 84 u32 reset_mask; 85 bool reset_needs_clk; 86}; 87 88static void __init sunxi_usb_clk_setup(struct device_node *node, 89 const struct usb_clk_data *data, 90 spinlock_t *lock) 91{ 92 struct clk_onecell_data *clk_data; 93 struct usb_reset_data *reset_data; 94 const char *clk_parent; 95 const char *clk_name; 96 void __iomem *reg; 97 int qty; 98 int i = 0; 99 int j = 0; 100 101 reg = of_io_request_and_map(node, 0, of_node_full_name(node)); 102 if (IS_ERR(reg)) 103 return; 104 105 clk_parent = of_clk_get_parent_name(node, 0); 106 if (!clk_parent) 107 return; 108 109 /* Worst-case size approximation and memory allocation */ 110 qty = find_last_bit((unsigned long *)&data->clk_mask, 111 SUNXI_USB_MAX_SIZE); 112 113 clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL); 114 if (!clk_data) 115 return; 116 117 clk_data->clks = kcalloc(qty + 1, sizeof(struct clk *), GFP_KERNEL); 118 if (!clk_data->clks) { 119 kfree(clk_data); 120 return; 121 } 122 123 for_each_set_bit(i, (unsigned long *)&data->clk_mask, 124 SUNXI_USB_MAX_SIZE) { 125 of_property_read_string_index(node, "clock-output-names", 126 j, &clk_name); 127 clk_data->clks[i] = clk_register_gate(NULL, clk_name, 128 clk_parent, 0, 129 reg, i, 0, lock); 130 WARN_ON(IS_ERR(clk_data->clks[i])); 131 132 j++; 133 } 134 135 /* Adjust to the real max */ 136 clk_data->clk_num = i; 137 138 of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); 139 140 /* Register a reset controller for usb with reset bits */ 141 if (data->reset_mask == 0) 142 return; 143 144 reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL); 145 if (!reset_data) 146 return; 147 148 if (data->reset_needs_clk) { 149 reset_data->clk = of_clk_get(node, 0); 150 if (IS_ERR(reset_data->clk)) { 151 pr_err("Could not get clock for reset controls\n"); 152 kfree(reset_data); 153 return; 154 } 155 } 156 157 reset_data->reg = reg; 158 reset_data->lock = lock; 159 reset_data->rcdev.nr_resets = __fls(data->reset_mask) + 1; 160 reset_data->rcdev.ops = &sunxi_usb_reset_ops; 161 reset_data->rcdev.of_node = node; 162 reset_controller_register(&reset_data->rcdev); 163} 164 165static const struct usb_clk_data sun4i_a10_usb_clk_data __initconst = { 166 .clk_mask = BIT(8) | BIT(7) | BIT(6), 167 .reset_mask = BIT(2) | BIT(1) | BIT(0), 168}; 169 170static DEFINE_SPINLOCK(sun4i_a10_usb_lock); 171 172static void __init sun4i_a10_usb_setup(struct device_node *node) 173{ 174 sunxi_usb_clk_setup(node, &sun4i_a10_usb_clk_data, &sun4i_a10_usb_lock); 175} 176CLK_OF_DECLARE(sun4i_a10_usb, "allwinner,sun4i-a10-usb-clk", sun4i_a10_usb_setup); 177 178static const struct usb_clk_data sun5i_a13_usb_clk_data __initconst = { 179 .clk_mask = BIT(8) | BIT(6), 180 .reset_mask = BIT(1) | BIT(0), 181}; 182 183static void __init sun5i_a13_usb_setup(struct device_node *node) 184{ 185 sunxi_usb_clk_setup(node, &sun5i_a13_usb_clk_data, &sun4i_a10_usb_lock); 186} 187CLK_OF_DECLARE(sun5i_a13_usb, "allwinner,sun5i-a13-usb-clk", sun5i_a13_usb_setup); 188 189static const struct usb_clk_data sun6i_a31_usb_clk_data __initconst = { 190 .clk_mask = BIT(18) | BIT(17) | BIT(16) | BIT(10) | BIT(9) | BIT(8), 191 .reset_mask = BIT(2) | BIT(1) | BIT(0), 192}; 193 194static void __init sun6i_a31_usb_setup(struct device_node *node) 195{ 196 sunxi_usb_clk_setup(node, &sun6i_a31_usb_clk_data, &sun4i_a10_usb_lock); 197} 198CLK_OF_DECLARE(sun6i_a31_usb, "allwinner,sun6i-a31-usb-clk", sun6i_a31_usb_setup); 199 200static const struct usb_clk_data sun8i_a23_usb_clk_data __initconst = { 201 .clk_mask = BIT(16) | BIT(11) | BIT(10) | BIT(9) | BIT(8), 202 .reset_mask = BIT(2) | BIT(1) | BIT(0), 203}; 204 205static void __init sun8i_a23_usb_setup(struct device_node *node) 206{ 207 sunxi_usb_clk_setup(node, &sun8i_a23_usb_clk_data, &sun4i_a10_usb_lock); 208} 209CLK_OF_DECLARE(sun8i_a23_usb, "allwinner,sun8i-a23-usb-clk", sun8i_a23_usb_setup); 210 211static const struct usb_clk_data sun8i_h3_usb_clk_data __initconst = { 212 .clk_mask = BIT(19) | BIT(18) | BIT(17) | BIT(16) | 213 BIT(11) | BIT(10) | BIT(9) | BIT(8), 214 .reset_mask = BIT(3) | BIT(2) | BIT(1) | BIT(0), 215}; 216 217static void __init sun8i_h3_usb_setup(struct device_node *node) 218{ 219 sunxi_usb_clk_setup(node, &sun8i_h3_usb_clk_data, &sun4i_a10_usb_lock); 220} 221CLK_OF_DECLARE(sun8i_h3_usb, "allwinner,sun8i-h3-usb-clk", sun8i_h3_usb_setup); 222 223static const struct usb_clk_data sun9i_a80_usb_mod_data __initconst = { 224 .clk_mask = BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1), 225 .reset_mask = BIT(19) | BIT(18) | BIT(17), 226 .reset_needs_clk = 1, 227}; 228 229static DEFINE_SPINLOCK(a80_usb_mod_lock); 230 231static void __init sun9i_a80_usb_mod_setup(struct device_node *node) 232{ 233 sunxi_usb_clk_setup(node, &sun9i_a80_usb_mod_data, &a80_usb_mod_lock); 234} 235CLK_OF_DECLARE(sun9i_a80_usb_mod, "allwinner,sun9i-a80-usb-mod-clk", sun9i_a80_usb_mod_setup); 236 237static const struct usb_clk_data sun9i_a80_usb_phy_data __initconst = { 238 .clk_mask = BIT(10) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1), 239 .reset_mask = BIT(21) | BIT(20) | BIT(19) | BIT(18) | BIT(17), 240 .reset_needs_clk = 1, 241}; 242 243static DEFINE_SPINLOCK(a80_usb_phy_lock); 244 245static void __init sun9i_a80_usb_phy_setup(struct device_node *node) 246{ 247 sunxi_usb_clk_setup(node, &sun9i_a80_usb_phy_data, &a80_usb_phy_lock); 248} 249CLK_OF_DECLARE(sun9i_a80_usb_phy, "allwinner,sun9i-a80-usb-phy-clk", sun9i_a80_usb_phy_setup);