root/drivers/clk/sunxi/clk-a10-ve.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sunxi_ve_reset_assert
  2. sunxi_ve_reset_deassert
  3. sunxi_ve_of_xlate
  4. sun4i_ve_clk_setup

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright 2015 Chen-Yu Tsai
   4  *
   5  * Chen-Yu Tsai <wens@csie.org>
   6  */
   7 
   8 #include <linux/clk-provider.h>
   9 #include <linux/io.h>
  10 #include <linux/of.h>
  11 #include <linux/of_address.h>
  12 #include <linux/reset-controller.h>
  13 #include <linux/slab.h>
  14 #include <linux/spinlock.h>
  15 
  16 static DEFINE_SPINLOCK(ve_lock);
  17 
  18 #define SUN4I_VE_ENABLE         31
  19 #define SUN4I_VE_DIVIDER_SHIFT  16
  20 #define SUN4I_VE_DIVIDER_WIDTH  3
  21 #define SUN4I_VE_RESET          0
  22 
  23 /**
  24  * sunxi_ve_reset... - reset bit in ve clk registers handling
  25  */
  26 
  27 struct ve_reset_data {
  28         void __iomem                    *reg;
  29         spinlock_t                      *lock;
  30         struct reset_controller_dev     rcdev;
  31 };
  32 
  33 static int sunxi_ve_reset_assert(struct reset_controller_dev *rcdev,
  34                                  unsigned long id)
  35 {
  36         struct ve_reset_data *data = container_of(rcdev,
  37                                                   struct ve_reset_data,
  38                                                   rcdev);
  39         unsigned long flags;
  40         u32 reg;
  41 
  42         spin_lock_irqsave(data->lock, flags);
  43 
  44         reg = readl(data->reg);
  45         writel(reg & ~BIT(SUN4I_VE_RESET), data->reg);
  46 
  47         spin_unlock_irqrestore(data->lock, flags);
  48 
  49         return 0;
  50 }
  51 
  52 static int sunxi_ve_reset_deassert(struct reset_controller_dev *rcdev,
  53                                    unsigned long id)
  54 {
  55         struct ve_reset_data *data = container_of(rcdev,
  56                                                   struct ve_reset_data,
  57                                                   rcdev);
  58         unsigned long flags;
  59         u32 reg;
  60 
  61         spin_lock_irqsave(data->lock, flags);
  62 
  63         reg = readl(data->reg);
  64         writel(reg | BIT(SUN4I_VE_RESET), data->reg);
  65 
  66         spin_unlock_irqrestore(data->lock, flags);
  67 
  68         return 0;
  69 }
  70 
  71 static int sunxi_ve_of_xlate(struct reset_controller_dev *rcdev,
  72                              const struct of_phandle_args *reset_spec)
  73 {
  74         if (WARN_ON(reset_spec->args_count != 0))
  75                 return -EINVAL;
  76 
  77         return 0;
  78 }
  79 
  80 static const struct reset_control_ops sunxi_ve_reset_ops = {
  81         .assert         = sunxi_ve_reset_assert,
  82         .deassert       = sunxi_ve_reset_deassert,
  83 };
  84 
  85 static void __init sun4i_ve_clk_setup(struct device_node *node)
  86 {
  87         struct clk *clk;
  88         struct clk_divider *div;
  89         struct clk_gate *gate;
  90         struct ve_reset_data *reset_data;
  91         const char *parent;
  92         const char *clk_name = node->name;
  93         void __iomem *reg;
  94         int err;
  95 
  96         reg = of_io_request_and_map(node, 0, of_node_full_name(node));
  97         if (IS_ERR(reg))
  98                 return;
  99 
 100         div = kzalloc(sizeof(*div), GFP_KERNEL);
 101         if (!div)
 102                 goto err_unmap;
 103 
 104         gate = kzalloc(sizeof(*gate), GFP_KERNEL);
 105         if (!gate)
 106                 goto err_free_div;
 107 
 108         of_property_read_string(node, "clock-output-names", &clk_name);
 109         parent = of_clk_get_parent_name(node, 0);
 110 
 111         gate->reg = reg;
 112         gate->bit_idx = SUN4I_VE_ENABLE;
 113         gate->lock = &ve_lock;
 114 
 115         div->reg = reg;
 116         div->shift = SUN4I_VE_DIVIDER_SHIFT;
 117         div->width = SUN4I_VE_DIVIDER_WIDTH;
 118         div->lock = &ve_lock;
 119 
 120         clk = clk_register_composite(NULL, clk_name, &parent, 1,
 121                                      NULL, NULL,
 122                                      &div->hw, &clk_divider_ops,
 123                                      &gate->hw, &clk_gate_ops,
 124                                      CLK_SET_RATE_PARENT);
 125         if (IS_ERR(clk))
 126                 goto err_free_gate;
 127 
 128         err = of_clk_add_provider(node, of_clk_src_simple_get, clk);
 129         if (err)
 130                 goto err_unregister_clk;
 131 
 132         reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
 133         if (!reset_data)
 134                 goto err_del_provider;
 135 
 136         reset_data->reg = reg;
 137         reset_data->lock = &ve_lock;
 138         reset_data->rcdev.nr_resets = 1;
 139         reset_data->rcdev.ops = &sunxi_ve_reset_ops;
 140         reset_data->rcdev.of_node = node;
 141         reset_data->rcdev.of_xlate = sunxi_ve_of_xlate;
 142         reset_data->rcdev.of_reset_n_cells = 0;
 143         err = reset_controller_register(&reset_data->rcdev);
 144         if (err)
 145                 goto err_free_reset;
 146 
 147         return;
 148 
 149 err_free_reset:
 150         kfree(reset_data);
 151 err_del_provider:
 152         of_clk_del_provider(node);
 153 err_unregister_clk:
 154         clk_unregister(clk);
 155 err_free_gate:
 156         kfree(gate);
 157 err_free_div:
 158         kfree(div);
 159 err_unmap:
 160         iounmap(reg);
 161 }
 162 CLK_OF_DECLARE(sun4i_ve, "allwinner,sun4i-a10-ve-clk",
 163                sun4i_ve_clk_setup);

/* [<][>][^][v][top][bottom][index][help] */