linux/drivers/clk/sunxi/clk-usb.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright 2013-2015 Emilio L\xC3\xB3pez
   4 *
   5 * Emilio L\xC3\xB3pez <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);
 250