Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.2-rc1 258 lines 7.2 kB view raw
1/* 2 * Copyright 2013-2015 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.h> 18#include <linux/clk-provider.h> 19#include <linux/io.h> 20#include <linux/of.h> 21#include <linux/of_address.h> 22#include <linux/reset-controller.h> 23#include <linux/slab.h> 24#include <linux/spinlock.h> 25 26 27/** 28 * sunxi_usb_reset... - reset bits in usb clk registers handling 29 */ 30 31struct usb_reset_data { 32 void __iomem *reg; 33 spinlock_t *lock; 34 struct clk *clk; 35 struct reset_controller_dev rcdev; 36}; 37 38static int sunxi_usb_reset_assert(struct reset_controller_dev *rcdev, 39 unsigned long id) 40{ 41 struct usb_reset_data *data = container_of(rcdev, 42 struct usb_reset_data, 43 rcdev); 44 unsigned long flags; 45 u32 reg; 46 47 clk_prepare_enable(data->clk); 48 spin_lock_irqsave(data->lock, flags); 49 50 reg = readl(data->reg); 51 writel(reg & ~BIT(id), data->reg); 52 53 spin_unlock_irqrestore(data->lock, flags); 54 clk_disable_unprepare(data->clk); 55 56 return 0; 57} 58 59static int sunxi_usb_reset_deassert(struct reset_controller_dev *rcdev, 60 unsigned long id) 61{ 62 struct usb_reset_data *data = container_of(rcdev, 63 struct usb_reset_data, 64 rcdev); 65 unsigned long flags; 66 u32 reg; 67 68 clk_prepare_enable(data->clk); 69 spin_lock_irqsave(data->lock, flags); 70 71 reg = readl(data->reg); 72 writel(reg | BIT(id), data->reg); 73 74 spin_unlock_irqrestore(data->lock, flags); 75 clk_disable_unprepare(data->clk); 76 77 return 0; 78} 79 80static const struct reset_control_ops sunxi_usb_reset_ops = { 81 .assert = sunxi_usb_reset_assert, 82 .deassert = sunxi_usb_reset_deassert, 83}; 84 85/** 86 * sunxi_usb_clk_setup() - Setup function for usb gate clocks 87 */ 88 89#define SUNXI_USB_MAX_SIZE 32 90 91struct usb_clk_data { 92 u32 clk_mask; 93 u32 reset_mask; 94 bool reset_needs_clk; 95}; 96 97static void __init sunxi_usb_clk_setup(struct device_node *node, 98 const struct usb_clk_data *data, 99 spinlock_t *lock) 100{ 101 struct clk_onecell_data *clk_data; 102 struct usb_reset_data *reset_data; 103 const char *clk_parent; 104 const char *clk_name; 105 void __iomem *reg; 106 int qty; 107 int i = 0; 108 int j = 0; 109 110 reg = of_io_request_and_map(node, 0, of_node_full_name(node)); 111 if (IS_ERR(reg)) 112 return; 113 114 clk_parent = of_clk_get_parent_name(node, 0); 115 if (!clk_parent) 116 return; 117 118 /* Worst-case size approximation and memory allocation */ 119 qty = find_last_bit((unsigned long *)&data->clk_mask, 120 SUNXI_USB_MAX_SIZE); 121 122 clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL); 123 if (!clk_data) 124 return; 125 126 clk_data->clks = kcalloc(qty + 1, sizeof(struct clk *), GFP_KERNEL); 127 if (!clk_data->clks) { 128 kfree(clk_data); 129 return; 130 } 131 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", 135 j, &clk_name); 136 clk_data->clks[i] = clk_register_gate(NULL, clk_name, 137 clk_parent, 0, 138 reg, i, 0, lock); 139 WARN_ON(IS_ERR(clk_data->clks[i])); 140 141 j++; 142 } 143 144 /* Adjust to the real max */ 145 clk_data->clk_num = i; 146 147 of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); 148 149 /* Register a reset controller for usb with reset bits */ 150 if (data->reset_mask == 0) 151 return; 152 153 reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL); 154 if (!reset_data) 155 return; 156 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"); 161 kfree(reset_data); 162 return; 163 } 164 } 165 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); 172} 173 174static 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), 177}; 178 179static DEFINE_SPINLOCK(sun4i_a10_usb_lock); 180 181static void __init sun4i_a10_usb_setup(struct device_node *node) 182{ 183 sunxi_usb_clk_setup(node, &sun4i_a10_usb_clk_data, &sun4i_a10_usb_lock); 184} 185CLK_OF_DECLARE(sun4i_a10_usb, "allwinner,sun4i-a10-usb-clk", sun4i_a10_usb_setup); 186 187static 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), 190}; 191 192static void __init sun5i_a13_usb_setup(struct device_node *node) 193{ 194 sunxi_usb_clk_setup(node, &sun5i_a13_usb_clk_data, &sun4i_a10_usb_lock); 195} 196CLK_OF_DECLARE(sun5i_a13_usb, "allwinner,sun5i-a13-usb-clk", sun5i_a13_usb_setup); 197 198static 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), 201}; 202 203static void __init sun6i_a31_usb_setup(struct device_node *node) 204{ 205 sunxi_usb_clk_setup(node, &sun6i_a31_usb_clk_data, &sun4i_a10_usb_lock); 206} 207CLK_OF_DECLARE(sun6i_a31_usb, "allwinner,sun6i-a31-usb-clk", sun6i_a31_usb_setup); 208 209static 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), 212}; 213 214static void __init sun8i_a23_usb_setup(struct device_node *node) 215{ 216 sunxi_usb_clk_setup(node, &sun8i_a23_usb_clk_data, &sun4i_a10_usb_lock); 217} 218CLK_OF_DECLARE(sun8i_a23_usb, "allwinner,sun8i-a23-usb-clk", sun8i_a23_usb_setup); 219 220static 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), 224}; 225 226static void __init sun8i_h3_usb_setup(struct device_node *node) 227{ 228 sunxi_usb_clk_setup(node, &sun8i_h3_usb_clk_data, &sun4i_a10_usb_lock); 229} 230CLK_OF_DECLARE(sun8i_h3_usb, "allwinner,sun8i-h3-usb-clk", sun8i_h3_usb_setup); 231 232static 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, 236}; 237 238static DEFINE_SPINLOCK(a80_usb_mod_lock); 239 240static void __init sun9i_a80_usb_mod_setup(struct device_node *node) 241{ 242 sunxi_usb_clk_setup(node, &sun9i_a80_usb_mod_data, &a80_usb_mod_lock); 243} 244CLK_OF_DECLARE(sun9i_a80_usb_mod, "allwinner,sun9i-a80-usb-mod-clk", sun9i_a80_usb_mod_setup); 245 246static 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, 250}; 251 252static DEFINE_SPINLOCK(a80_usb_phy_lock); 253 254static void __init sun9i_a80_usb_phy_setup(struct device_node *node) 255{ 256 sunxi_usb_clk_setup(node, &sun9i_a80_usb_phy_data, &a80_usb_phy_lock); 257} 258CLK_OF_DECLARE(sun9i_a80_usb_phy, "allwinner,sun9i-a80-usb-phy-clk", sun9i_a80_usb_phy_setup);