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