root/drivers/clk/sunxi/clk-sun4i-display.c

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

DEFINITIONS

This source file includes following definitions.
  1. rcdev_to_reset_data
  2. sun4i_a10_display_assert
  3. sun4i_a10_display_deassert
  4. sun4i_a10_display_status
  5. sun4i_a10_display_reset_xlate
  6. sun4i_a10_display_init
  7. sun4i_a10_tcon_ch0_setup
  8. sun4i_a10_display_setup

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright 2015 Maxime Ripard
   4  *
   5  * Maxime Ripard <maxime.ripard@free-electrons.com>
   6  */
   7 
   8 #include <linux/clk-provider.h>
   9 #include <linux/io.h>
  10 #include <linux/kernel.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 struct sun4i_a10_display_clk_data {
  17         bool    has_div;
  18         u8      num_rst;
  19         u8      parents;
  20 
  21         u8      offset_en;
  22         u8      offset_div;
  23         u8      offset_mux;
  24         u8      offset_rst;
  25 
  26         u8      width_div;
  27         u8      width_mux;
  28 
  29         u32     flags;
  30 };
  31 
  32 struct reset_data {
  33         void __iomem                    *reg;
  34         spinlock_t                      *lock;
  35         struct reset_controller_dev     rcdev;
  36         u8                              offset;
  37 };
  38 
  39 static DEFINE_SPINLOCK(sun4i_a10_display_lock);
  40 
  41 static inline struct reset_data *rcdev_to_reset_data(struct reset_controller_dev *rcdev)
  42 {
  43         return container_of(rcdev, struct reset_data, rcdev);
  44 };
  45 
  46 static int sun4i_a10_display_assert(struct reset_controller_dev *rcdev,
  47                                     unsigned long id)
  48 {
  49         struct reset_data *data = rcdev_to_reset_data(rcdev);
  50         unsigned long flags;
  51         u32 reg;
  52 
  53         spin_lock_irqsave(data->lock, flags);
  54 
  55         reg = readl(data->reg);
  56         writel(reg & ~BIT(data->offset + id), data->reg);
  57 
  58         spin_unlock_irqrestore(data->lock, flags);
  59 
  60         return 0;
  61 }
  62 
  63 static int sun4i_a10_display_deassert(struct reset_controller_dev *rcdev,
  64                                       unsigned long id)
  65 {
  66         struct reset_data *data = rcdev_to_reset_data(rcdev);
  67         unsigned long flags;
  68         u32 reg;
  69 
  70         spin_lock_irqsave(data->lock, flags);
  71 
  72         reg = readl(data->reg);
  73         writel(reg | BIT(data->offset + id), data->reg);
  74 
  75         spin_unlock_irqrestore(data->lock, flags);
  76 
  77         return 0;
  78 }
  79 
  80 static int sun4i_a10_display_status(struct reset_controller_dev *rcdev,
  81                                     unsigned long id)
  82 {
  83         struct reset_data *data = rcdev_to_reset_data(rcdev);
  84 
  85         return !(readl(data->reg) & BIT(data->offset + id));
  86 }
  87 
  88 static const struct reset_control_ops sun4i_a10_display_reset_ops = {
  89         .assert         = sun4i_a10_display_assert,
  90         .deassert       = sun4i_a10_display_deassert,
  91         .status         = sun4i_a10_display_status,
  92 };
  93 
  94 static int sun4i_a10_display_reset_xlate(struct reset_controller_dev *rcdev,
  95                                          const struct of_phandle_args *spec)
  96 {
  97         /* We only have a single reset signal */
  98         return 0;
  99 }
 100 
 101 static void __init sun4i_a10_display_init(struct device_node *node,
 102                                           const struct sun4i_a10_display_clk_data *data)
 103 {
 104         const char *parents[4];
 105         const char *clk_name = node->name;
 106         struct reset_data *reset_data;
 107         struct clk_divider *div = NULL;
 108         struct clk_gate *gate;
 109         struct resource res;
 110         struct clk_mux *mux;
 111         void __iomem *reg;
 112         struct clk *clk;
 113         int ret;
 114 
 115         of_property_read_string(node, "clock-output-names", &clk_name);
 116 
 117         reg = of_io_request_and_map(node, 0, of_node_full_name(node));
 118         if (IS_ERR(reg)) {
 119                 pr_err("%s: Could not map the clock registers\n", clk_name);
 120                 return;
 121         }
 122 
 123         ret = of_clk_parent_fill(node, parents, data->parents);
 124         if (ret != data->parents) {
 125                 pr_err("%s: Could not retrieve the parents\n", clk_name);
 126                 goto unmap;
 127         }
 128 
 129         mux = kzalloc(sizeof(*mux), GFP_KERNEL);
 130         if (!mux)
 131                 goto unmap;
 132 
 133         mux->reg = reg;
 134         mux->shift = data->offset_mux;
 135         mux->mask = (1 << data->width_mux) - 1;
 136         mux->lock = &sun4i_a10_display_lock;
 137 
 138         gate = kzalloc(sizeof(*gate), GFP_KERNEL);
 139         if (!gate)
 140                 goto free_mux;
 141 
 142         gate->reg = reg;
 143         gate->bit_idx = data->offset_en;
 144         gate->lock = &sun4i_a10_display_lock;
 145 
 146         if (data->has_div) {
 147                 div = kzalloc(sizeof(*div), GFP_KERNEL);
 148                 if (!div)
 149                         goto free_gate;
 150 
 151                 div->reg = reg;
 152                 div->shift = data->offset_div;
 153                 div->width = data->width_div;
 154                 div->lock = &sun4i_a10_display_lock;
 155         }
 156 
 157         clk = clk_register_composite(NULL, clk_name,
 158                                      parents, data->parents,
 159                                      &mux->hw, &clk_mux_ops,
 160                                      data->has_div ? &div->hw : NULL,
 161                                      data->has_div ? &clk_divider_ops : NULL,
 162                                      &gate->hw, &clk_gate_ops,
 163                                      data->flags);
 164         if (IS_ERR(clk)) {
 165                 pr_err("%s: Couldn't register the clock\n", clk_name);
 166                 goto free_div;
 167         }
 168 
 169         ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
 170         if (ret) {
 171                 pr_err("%s: Couldn't register DT provider\n", clk_name);
 172                 goto free_clk;
 173         }
 174 
 175         if (!data->num_rst)
 176                 return;
 177 
 178         reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
 179         if (!reset_data)
 180                 goto free_of_clk;
 181 
 182         reset_data->reg = reg;
 183         reset_data->offset = data->offset_rst;
 184         reset_data->lock = &sun4i_a10_display_lock;
 185         reset_data->rcdev.nr_resets = data->num_rst;
 186         reset_data->rcdev.ops = &sun4i_a10_display_reset_ops;
 187         reset_data->rcdev.of_node = node;
 188 
 189         if (data->num_rst == 1) {
 190                 reset_data->rcdev.of_reset_n_cells = 0;
 191                 reset_data->rcdev.of_xlate = &sun4i_a10_display_reset_xlate;
 192         } else {
 193                 reset_data->rcdev.of_reset_n_cells = 1;
 194         }
 195 
 196         if (reset_controller_register(&reset_data->rcdev)) {
 197                 pr_err("%s: Couldn't register the reset controller\n",
 198                        clk_name);
 199                 goto free_reset;
 200         }
 201 
 202         return;
 203 
 204 free_reset:
 205         kfree(reset_data);
 206 free_of_clk:
 207         of_clk_del_provider(node);
 208 free_clk:
 209         clk_unregister_composite(clk);
 210 free_div:
 211         kfree(div);
 212 free_gate:
 213         kfree(gate);
 214 free_mux:
 215         kfree(mux);
 216 unmap:
 217         iounmap(reg);
 218         of_address_to_resource(node, 0, &res);
 219         release_mem_region(res.start, resource_size(&res));
 220 }
 221 
 222 static const struct sun4i_a10_display_clk_data sun4i_a10_tcon_ch0_data __initconst = {
 223         .num_rst        = 2,
 224         .parents        = 4,
 225         .offset_en      = 31,
 226         .offset_rst     = 29,
 227         .offset_mux     = 24,
 228         .width_mux      = 2,
 229         .flags          = CLK_SET_RATE_PARENT,
 230 };
 231 
 232 static void __init sun4i_a10_tcon_ch0_setup(struct device_node *node)
 233 {
 234         sun4i_a10_display_init(node, &sun4i_a10_tcon_ch0_data);
 235 }
 236 CLK_OF_DECLARE(sun4i_a10_tcon_ch0, "allwinner,sun4i-a10-tcon-ch0-clk",
 237                sun4i_a10_tcon_ch0_setup);
 238 
 239 static const struct sun4i_a10_display_clk_data sun4i_a10_display_data __initconst = {
 240         .has_div        = true,
 241         .num_rst        = 1,
 242         .parents        = 3,
 243         .offset_en      = 31,
 244         .offset_rst     = 30,
 245         .offset_mux     = 24,
 246         .offset_div     = 0,
 247         .width_mux      = 2,
 248         .width_div      = 4,
 249 };
 250 
 251 static void __init sun4i_a10_display_setup(struct device_node *node)
 252 {
 253         sun4i_a10_display_init(node, &sun4i_a10_display_data);
 254 }
 255 CLK_OF_DECLARE(sun4i_a10_display, "allwinner,sun4i-a10-display-clk",
 256                sun4i_a10_display_setup);

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