root/drivers/clk/mediatek/clk-mtk.c

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

DEFINITIONS

This source file includes following definitions.
  1. mtk_alloc_clk_data
  2. mtk_clk_register_fixed_clks
  3. mtk_clk_register_factors
  4. mtk_clk_register_gates_with_dev
  5. mtk_clk_register_gates
  6. mtk_clk_register_composite
  7. mtk_clk_register_composites
  8. mtk_clk_register_dividers

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (c) 2014 MediaTek Inc.
   4  * Author: James Liao <jamesjj.liao@mediatek.com>
   5  */
   6 
   7 #include <linux/of.h>
   8 #include <linux/of_address.h>
   9 #include <linux/err.h>
  10 #include <linux/io.h>
  11 #include <linux/slab.h>
  12 #include <linux/delay.h>
  13 #include <linux/clkdev.h>
  14 #include <linux/mfd/syscon.h>
  15 #include <linux/device.h>
  16 
  17 #include "clk-mtk.h"
  18 #include "clk-gate.h"
  19 
  20 struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num)
  21 {
  22         int i;
  23         struct clk_onecell_data *clk_data;
  24 
  25         clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
  26         if (!clk_data)
  27                 return NULL;
  28 
  29         clk_data->clks = kcalloc(clk_num, sizeof(*clk_data->clks), GFP_KERNEL);
  30         if (!clk_data->clks)
  31                 goto err_out;
  32 
  33         clk_data->clk_num = clk_num;
  34 
  35         for (i = 0; i < clk_num; i++)
  36                 clk_data->clks[i] = ERR_PTR(-ENOENT);
  37 
  38         return clk_data;
  39 err_out:
  40         kfree(clk_data);
  41 
  42         return NULL;
  43 }
  44 
  45 void mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks,
  46                 int num, struct clk_onecell_data *clk_data)
  47 {
  48         int i;
  49         struct clk *clk;
  50 
  51         for (i = 0; i < num; i++) {
  52                 const struct mtk_fixed_clk *rc = &clks[i];
  53 
  54                 if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[rc->id]))
  55                         continue;
  56 
  57                 clk = clk_register_fixed_rate(NULL, rc->name, rc->parent, 0,
  58                                               rc->rate);
  59 
  60                 if (IS_ERR(clk)) {
  61                         pr_err("Failed to register clk %s: %ld\n",
  62                                         rc->name, PTR_ERR(clk));
  63                         continue;
  64                 }
  65 
  66                 if (clk_data)
  67                         clk_data->clks[rc->id] = clk;
  68         }
  69 }
  70 
  71 void mtk_clk_register_factors(const struct mtk_fixed_factor *clks,
  72                 int num, struct clk_onecell_data *clk_data)
  73 {
  74         int i;
  75         struct clk *clk;
  76 
  77         for (i = 0; i < num; i++) {
  78                 const struct mtk_fixed_factor *ff = &clks[i];
  79 
  80                 if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[ff->id]))
  81                         continue;
  82 
  83                 clk = clk_register_fixed_factor(NULL, ff->name, ff->parent_name,
  84                                 CLK_SET_RATE_PARENT, ff->mult, ff->div);
  85 
  86                 if (IS_ERR(clk)) {
  87                         pr_err("Failed to register clk %s: %ld\n",
  88                                         ff->name, PTR_ERR(clk));
  89                         continue;
  90                 }
  91 
  92                 if (clk_data)
  93                         clk_data->clks[ff->id] = clk;
  94         }
  95 }
  96 
  97 int mtk_clk_register_gates_with_dev(struct device_node *node,
  98                 const struct mtk_gate *clks,
  99                 int num, struct clk_onecell_data *clk_data,
 100                 struct device *dev)
 101 {
 102         int i;
 103         struct clk *clk;
 104         struct regmap *regmap;
 105 
 106         if (!clk_data)
 107                 return -ENOMEM;
 108 
 109         regmap = syscon_node_to_regmap(node);
 110         if (IS_ERR(regmap)) {
 111                 pr_err("Cannot find regmap for %pOF: %ld\n", node,
 112                                 PTR_ERR(regmap));
 113                 return PTR_ERR(regmap);
 114         }
 115 
 116         for (i = 0; i < num; i++) {
 117                 const struct mtk_gate *gate = &clks[i];
 118 
 119                 if (!IS_ERR_OR_NULL(clk_data->clks[gate->id]))
 120                         continue;
 121 
 122                 clk = mtk_clk_register_gate(gate->name, gate->parent_name,
 123                                 regmap,
 124                                 gate->regs->set_ofs,
 125                                 gate->regs->clr_ofs,
 126                                 gate->regs->sta_ofs,
 127                                 gate->shift, gate->ops, gate->flags, dev);
 128 
 129                 if (IS_ERR(clk)) {
 130                         pr_err("Failed to register clk %s: %ld\n",
 131                                         gate->name, PTR_ERR(clk));
 132                         continue;
 133                 }
 134 
 135                 clk_data->clks[gate->id] = clk;
 136         }
 137 
 138         return 0;
 139 }
 140 
 141 int mtk_clk_register_gates(struct device_node *node,
 142                 const struct mtk_gate *clks,
 143                 int num, struct clk_onecell_data *clk_data)
 144 {
 145         return mtk_clk_register_gates_with_dev(node,
 146                 clks, num, clk_data, NULL);
 147 }
 148 
 149 struct clk *mtk_clk_register_composite(const struct mtk_composite *mc,
 150                 void __iomem *base, spinlock_t *lock)
 151 {
 152         struct clk *clk;
 153         struct clk_mux *mux = NULL;
 154         struct clk_gate *gate = NULL;
 155         struct clk_divider *div = NULL;
 156         struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *div_hw = NULL;
 157         const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *div_ops = NULL;
 158         const char * const *parent_names;
 159         const char *parent;
 160         int num_parents;
 161         int ret;
 162 
 163         if (mc->mux_shift >= 0) {
 164                 mux = kzalloc(sizeof(*mux), GFP_KERNEL);
 165                 if (!mux)
 166                         return ERR_PTR(-ENOMEM);
 167 
 168                 mux->reg = base + mc->mux_reg;
 169                 mux->mask = BIT(mc->mux_width) - 1;
 170                 mux->shift = mc->mux_shift;
 171                 mux->lock = lock;
 172                 mux->flags = mc->mux_flags;
 173                 mux_hw = &mux->hw;
 174                 mux_ops = &clk_mux_ops;
 175 
 176                 parent_names = mc->parent_names;
 177                 num_parents = mc->num_parents;
 178         } else {
 179                 parent = mc->parent;
 180                 parent_names = &parent;
 181                 num_parents = 1;
 182         }
 183 
 184         if (mc->gate_shift >= 0) {
 185                 gate = kzalloc(sizeof(*gate), GFP_KERNEL);
 186                 if (!gate) {
 187                         ret = -ENOMEM;
 188                         goto err_out;
 189                 }
 190 
 191                 gate->reg = base + mc->gate_reg;
 192                 gate->bit_idx = mc->gate_shift;
 193                 gate->flags = CLK_GATE_SET_TO_DISABLE;
 194                 gate->lock = lock;
 195 
 196                 gate_hw = &gate->hw;
 197                 gate_ops = &clk_gate_ops;
 198         }
 199 
 200         if (mc->divider_shift >= 0) {
 201                 div = kzalloc(sizeof(*div), GFP_KERNEL);
 202                 if (!div) {
 203                         ret = -ENOMEM;
 204                         goto err_out;
 205                 }
 206 
 207                 div->reg = base + mc->divider_reg;
 208                 div->shift = mc->divider_shift;
 209                 div->width = mc->divider_width;
 210                 div->lock = lock;
 211 
 212                 div_hw = &div->hw;
 213                 div_ops = &clk_divider_ops;
 214         }
 215 
 216         clk = clk_register_composite(NULL, mc->name, parent_names, num_parents,
 217                 mux_hw, mux_ops,
 218                 div_hw, div_ops,
 219                 gate_hw, gate_ops,
 220                 mc->flags);
 221 
 222         if (IS_ERR(clk)) {
 223                 ret = PTR_ERR(clk);
 224                 goto err_out;
 225         }
 226 
 227         return clk;
 228 err_out:
 229         kfree(div);
 230         kfree(gate);
 231         kfree(mux);
 232 
 233         return ERR_PTR(ret);
 234 }
 235 
 236 void mtk_clk_register_composites(const struct mtk_composite *mcs,
 237                 int num, void __iomem *base, spinlock_t *lock,
 238                 struct clk_onecell_data *clk_data)
 239 {
 240         struct clk *clk;
 241         int i;
 242 
 243         for (i = 0; i < num; i++) {
 244                 const struct mtk_composite *mc = &mcs[i];
 245 
 246                 if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[mc->id]))
 247                         continue;
 248 
 249                 clk = mtk_clk_register_composite(mc, base, lock);
 250 
 251                 if (IS_ERR(clk)) {
 252                         pr_err("Failed to register clk %s: %ld\n",
 253                                         mc->name, PTR_ERR(clk));
 254                         continue;
 255                 }
 256 
 257                 if (clk_data)
 258                         clk_data->clks[mc->id] = clk;
 259         }
 260 }
 261 
 262 void mtk_clk_register_dividers(const struct mtk_clk_divider *mcds,
 263                         int num, void __iomem *base, spinlock_t *lock,
 264                                 struct clk_onecell_data *clk_data)
 265 {
 266         struct clk *clk;
 267         int i;
 268 
 269         for (i = 0; i <  num; i++) {
 270                 const struct mtk_clk_divider *mcd = &mcds[i];
 271 
 272                 if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[mcd->id]))
 273                         continue;
 274 
 275                 clk = clk_register_divider(NULL, mcd->name, mcd->parent_name,
 276                         mcd->flags, base +  mcd->div_reg, mcd->div_shift,
 277                         mcd->div_width, mcd->clk_divider_flags, lock);
 278 
 279                 if (IS_ERR(clk)) {
 280                         pr_err("Failed to register clk %s: %ld\n",
 281                                 mcd->name, PTR_ERR(clk));
 282                         continue;
 283                 }
 284 
 285                 if (clk_data)
 286                         clk_data->clks[mcd->id] = clk;
 287         }
 288 }

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