linux/drivers/clk/hisilicon/clk.c
<<
>>
Prefs
   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
  24static DEFINE_SPINLOCK(hisi_clk_lock);
  25
  26struct 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}
  56EXPORT_SYMBOL_GPL(hisi_clk_alloc);
  57
  58struct 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;
  84err_data:
  85        kfree(clk_data);
  86err:
  87        return NULL;
  88}
  89EXPORT_SYMBOL_GPL(hisi_clk_init);
  90
  91int 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
 112err:
 113        while (i--)
 114                clk_unregister_fixed_rate(data->clk_data.clks[clks[i].id]);
 115
 116        return PTR_ERR(clk);
 117}
 118EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_rate);
 119
 120int 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
 142err:
 143        while (i--)
 144                clk_unregister_fixed_factor(data->clk_data.clks[clks[i].id]);
 145
 146        return PTR_ERR(clk);
 147}
 148EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_factor);
 149
 150int 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                                        (u32 *)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
 180err:
 181        while (i--)
 182                clk_unregister_mux(data->clk_data.clks[clks[i].id]);
 183
 184        return PTR_ERR(clk);
 185}
 186EXPORT_SYMBOL_GPL(hisi_clk_register_mux);
 187
 188int 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}
 210EXPORT_SYMBOL_GPL(hisi_clk_register_phase);
 211
 212int 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
 242err:
 243        while (i--)
 244                clk_unregister_divider(data->clk_data.clks[clks[i].id]);
 245
 246        return PTR_ERR(clk);
 247}
 248EXPORT_SYMBOL_GPL(hisi_clk_register_divider);
 249
 250int 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
 279err:
 280        while (i--)
 281                clk_unregister_gate(data->clk_data.clks[clks[i].id]);
 282
 283        return PTR_ERR(clk);
 284}
 285EXPORT_SYMBOL_GPL(hisi_clk_register_gate);
 286
 287void 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}
 314EXPORT_SYMBOL_GPL(hisi_clk_register_gate_sep);
 315
 316void __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}
 344