root/drivers/clk/hisilicon/clk.c

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

DEFINITIONS

This source file includes following definitions.
  1. hisi_clk_alloc
  2. hisi_clk_init
  3. hisi_clk_register_fixed_rate
  4. hisi_clk_register_fixed_factor
  5. hisi_clk_register_mux
  6. hisi_clk_register_phase
  7. hisi_clk_register_divider
  8. hisi_clk_register_gate
  9. hisi_clk_register_gate_sep
  10. hi6220_clk_register_divider

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Hisilicon clock driver
   4  *
   5  * Copyright (c) 2012-2013 Hisilicon Limited.
   6  * Copyright (c) 2012-2013 Linaro Limited.
   7  *
   8  * Author: Haojian Zhuang <haojian.zhuang@linaro.org>
   9  *         Xin Li <li.xin@linaro.org>
  10  */
  11 
  12 #include <linux/kernel.h>
  13 #include <linux/clkdev.h>
  14 #include <linux/clk-provider.h>
  15 #include <linux/delay.h>
  16 #include <linux/io.h>
  17 #include <linux/of.h>
  18 #include <linux/of_address.h>
  19 #include <linux/of_device.h>
  20 #include <linux/slab.h>
  21 
  22 #include "clk.h"
  23 
  24 static DEFINE_SPINLOCK(hisi_clk_lock);
  25 
  26 struct hisi_clock_data *hisi_clk_alloc(struct platform_device *pdev,
  27                                                 int nr_clks)
  28 {
  29         struct hisi_clock_data *clk_data;
  30         struct resource *res;
  31         struct clk **clk_table;
  32 
  33         clk_data = devm_kmalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL);
  34         if (!clk_data)
  35                 return NULL;
  36 
  37         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  38         if (!res)
  39                 return NULL;
  40         clk_data->base = devm_ioremap(&pdev->dev,
  41                                 res->start, resource_size(res));
  42         if (!clk_data->base)
  43                 return NULL;
  44 
  45         clk_table = devm_kmalloc_array(&pdev->dev, nr_clks,
  46                                        sizeof(*clk_table),
  47                                        GFP_KERNEL);
  48         if (!clk_table)
  49                 return NULL;
  50 
  51         clk_data->clk_data.clks = clk_table;
  52         clk_data->clk_data.clk_num = nr_clks;
  53 
  54         return clk_data;
  55 }
  56 EXPORT_SYMBOL_GPL(hisi_clk_alloc);
  57 
  58 struct hisi_clock_data *hisi_clk_init(struct device_node *np,
  59                                              int nr_clks)
  60 {
  61         struct hisi_clock_data *clk_data;
  62         struct clk **clk_table;
  63         void __iomem *base;
  64 
  65         base = of_iomap(np, 0);
  66         if (!base) {
  67                 pr_err("%s: failed to map clock registers\n", __func__);
  68                 goto err;
  69         }
  70 
  71         clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
  72         if (!clk_data)
  73                 goto err;
  74 
  75         clk_data->base = base;
  76         clk_table = kcalloc(nr_clks, sizeof(*clk_table), GFP_KERNEL);
  77         if (!clk_table)
  78                 goto err_data;
  79 
  80         clk_data->clk_data.clks = clk_table;
  81         clk_data->clk_data.clk_num = nr_clks;
  82         of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data->clk_data);
  83         return clk_data;
  84 err_data:
  85         kfree(clk_data);
  86 err:
  87         return NULL;
  88 }
  89 EXPORT_SYMBOL_GPL(hisi_clk_init);
  90 
  91 int hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *clks,
  92                                          int nums, struct hisi_clock_data *data)
  93 {
  94         struct clk *clk;
  95         int i;
  96 
  97         for (i = 0; i < nums; i++) {
  98                 clk = clk_register_fixed_rate(NULL, clks[i].name,
  99                                               clks[i].parent_name,
 100                                               clks[i].flags,
 101                                               clks[i].fixed_rate);
 102                 if (IS_ERR(clk)) {
 103                         pr_err("%s: failed to register clock %s\n",
 104                                __func__, clks[i].name);
 105                         goto err;
 106                 }
 107                 data->clk_data.clks[clks[i].id] = clk;
 108         }
 109 
 110         return 0;
 111 
 112 err:
 113         while (i--)
 114                 clk_unregister_fixed_rate(data->clk_data.clks[clks[i].id]);
 115 
 116         return PTR_ERR(clk);
 117 }
 118 EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_rate);
 119 
 120 int hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *clks,
 121                                            int nums,
 122                                            struct hisi_clock_data *data)
 123 {
 124         struct clk *clk;
 125         int i;
 126 
 127         for (i = 0; i < nums; i++) {
 128                 clk = clk_register_fixed_factor(NULL, clks[i].name,
 129                                                 clks[i].parent_name,
 130                                                 clks[i].flags, clks[i].mult,
 131                                                 clks[i].div);
 132                 if (IS_ERR(clk)) {
 133                         pr_err("%s: failed to register clock %s\n",
 134                                __func__, clks[i].name);
 135                         goto err;
 136                 }
 137                 data->clk_data.clks[clks[i].id] = clk;
 138         }
 139 
 140         return 0;
 141 
 142 err:
 143         while (i--)
 144                 clk_unregister_fixed_factor(data->clk_data.clks[clks[i].id]);
 145 
 146         return PTR_ERR(clk);
 147 }
 148 EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_factor);
 149 
 150 int hisi_clk_register_mux(const struct hisi_mux_clock *clks,
 151                                   int nums, struct hisi_clock_data *data)
 152 {
 153         struct clk *clk;
 154         void __iomem *base = data->base;
 155         int i;
 156 
 157         for (i = 0; i < nums; i++) {
 158                 u32 mask = BIT(clks[i].width) - 1;
 159 
 160                 clk = clk_register_mux_table(NULL, clks[i].name,
 161                                         clks[i].parent_names,
 162                                         clks[i].num_parents, clks[i].flags,
 163                                         base + clks[i].offset, clks[i].shift,
 164                                         mask, clks[i].mux_flags,
 165                                         clks[i].table, &hisi_clk_lock);
 166                 if (IS_ERR(clk)) {
 167                         pr_err("%s: failed to register clock %s\n",
 168                                __func__, clks[i].name);
 169                         goto err;
 170                 }
 171 
 172                 if (clks[i].alias)
 173                         clk_register_clkdev(clk, clks[i].alias, NULL);
 174 
 175                 data->clk_data.clks[clks[i].id] = clk;
 176         }
 177 
 178         return 0;
 179 
 180 err:
 181         while (i--)
 182                 clk_unregister_mux(data->clk_data.clks[clks[i].id]);
 183 
 184         return PTR_ERR(clk);
 185 }
 186 EXPORT_SYMBOL_GPL(hisi_clk_register_mux);
 187 
 188 int hisi_clk_register_phase(struct device *dev,
 189                             const struct hisi_phase_clock *clks,
 190                             int nums, struct hisi_clock_data *data)
 191 {
 192         void __iomem *base = data->base;
 193         struct clk *clk;
 194         int i;
 195 
 196         for (i = 0; i < nums; i++) {
 197                 clk = clk_register_hisi_phase(dev, &clks[i], base,
 198                                               &hisi_clk_lock);
 199                 if (IS_ERR(clk)) {
 200                         pr_err("%s: failed to register clock %s\n", __func__,
 201                                clks[i].name);
 202                         return PTR_ERR(clk);
 203                 }
 204 
 205                 data->clk_data.clks[clks[i].id] = clk;
 206         }
 207 
 208         return 0;
 209 }
 210 EXPORT_SYMBOL_GPL(hisi_clk_register_phase);
 211 
 212 int hisi_clk_register_divider(const struct hisi_divider_clock *clks,
 213                                       int nums, struct hisi_clock_data *data)
 214 {
 215         struct clk *clk;
 216         void __iomem *base = data->base;
 217         int i;
 218 
 219         for (i = 0; i < nums; i++) {
 220                 clk = clk_register_divider_table(NULL, clks[i].name,
 221                                                  clks[i].parent_name,
 222                                                  clks[i].flags,
 223                                                  base + clks[i].offset,
 224                                                  clks[i].shift, clks[i].width,
 225                                                  clks[i].div_flags,
 226                                                  clks[i].table,
 227                                                  &hisi_clk_lock);
 228                 if (IS_ERR(clk)) {
 229                         pr_err("%s: failed to register clock %s\n",
 230                                __func__, clks[i].name);
 231                         goto err;
 232                 }
 233 
 234                 if (clks[i].alias)
 235                         clk_register_clkdev(clk, clks[i].alias, NULL);
 236 
 237                 data->clk_data.clks[clks[i].id] = clk;
 238         }
 239 
 240         return 0;
 241 
 242 err:
 243         while (i--)
 244                 clk_unregister_divider(data->clk_data.clks[clks[i].id]);
 245 
 246         return PTR_ERR(clk);
 247 }
 248 EXPORT_SYMBOL_GPL(hisi_clk_register_divider);
 249 
 250 int hisi_clk_register_gate(const struct hisi_gate_clock *clks,
 251                                        int nums, struct hisi_clock_data *data)
 252 {
 253         struct clk *clk;
 254         void __iomem *base = data->base;
 255         int i;
 256 
 257         for (i = 0; i < nums; i++) {
 258                 clk = clk_register_gate(NULL, clks[i].name,
 259                                                 clks[i].parent_name,
 260                                                 clks[i].flags,
 261                                                 base + clks[i].offset,
 262                                                 clks[i].bit_idx,
 263                                                 clks[i].gate_flags,
 264                                                 &hisi_clk_lock);
 265                 if (IS_ERR(clk)) {
 266                         pr_err("%s: failed to register clock %s\n",
 267                                __func__, clks[i].name);
 268                         goto err;
 269                 }
 270 
 271                 if (clks[i].alias)
 272                         clk_register_clkdev(clk, clks[i].alias, NULL);
 273 
 274                 data->clk_data.clks[clks[i].id] = clk;
 275         }
 276 
 277         return 0;
 278 
 279 err:
 280         while (i--)
 281                 clk_unregister_gate(data->clk_data.clks[clks[i].id]);
 282 
 283         return PTR_ERR(clk);
 284 }
 285 EXPORT_SYMBOL_GPL(hisi_clk_register_gate);
 286 
 287 void hisi_clk_register_gate_sep(const struct hisi_gate_clock *clks,
 288                                        int nums, struct hisi_clock_data *data)
 289 {
 290         struct clk *clk;
 291         void __iomem *base = data->base;
 292         int i;
 293 
 294         for (i = 0; i < nums; i++) {
 295                 clk = hisi_register_clkgate_sep(NULL, clks[i].name,
 296                                                 clks[i].parent_name,
 297                                                 clks[i].flags,
 298                                                 base + clks[i].offset,
 299                                                 clks[i].bit_idx,
 300                                                 clks[i].gate_flags,
 301                                                 &hisi_clk_lock);
 302                 if (IS_ERR(clk)) {
 303                         pr_err("%s: failed to register clock %s\n",
 304                                __func__, clks[i].name);
 305                         continue;
 306                 }
 307 
 308                 if (clks[i].alias)
 309                         clk_register_clkdev(clk, clks[i].alias, NULL);
 310 
 311                 data->clk_data.clks[clks[i].id] = clk;
 312         }
 313 }
 314 EXPORT_SYMBOL_GPL(hisi_clk_register_gate_sep);
 315 
 316 void __init hi6220_clk_register_divider(const struct hi6220_divider_clock *clks,
 317                                         int nums, struct hisi_clock_data *data)
 318 {
 319         struct clk *clk;
 320         void __iomem *base = data->base;
 321         int i;
 322 
 323         for (i = 0; i < nums; i++) {
 324                 clk = hi6220_register_clkdiv(NULL, clks[i].name,
 325                                                 clks[i].parent_name,
 326                                                 clks[i].flags,
 327                                                 base + clks[i].offset,
 328                                                 clks[i].shift,
 329                                                 clks[i].width,
 330                                                 clks[i].mask_bit,
 331                                                 &hisi_clk_lock);
 332                 if (IS_ERR(clk)) {
 333                         pr_err("%s: failed to register clock %s\n",
 334                                __func__, clks[i].name);
 335                         continue;
 336                 }
 337 
 338                 if (clks[i].alias)
 339                         clk_register_clkdev(clk, clks[i].alias, NULL);
 340 
 341                 data->clk_data.clks[clks[i].id] = clk;
 342         }
 343 }

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