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(&pdev->dev, sizeof(struct clk *) * nr_clks,
  58                                GFP_KERNEL);
  59        if (!clk_table)
  60                return NULL;
  61
  62        clk_data->clk_data.clks = clk_table;
  63        clk_data->clk_data.clk_num = nr_clks;
  64
  65        return clk_data;
  66}
  67EXPORT_SYMBOL_GPL(hisi_clk_alloc);
  68
  69struct hisi_clock_data *hisi_clk_init(struct device_node *np,
  70                                             int nr_clks)
  71{
  72        struct hisi_clock_data *clk_data;
  73        struct clk **clk_table;
  74        void __iomem *base;
  75
  76        base = of_iomap(np, 0);
  77        if (!base) {
  78                pr_err("%s: failed to map clock registers\n", __func__);
  79                goto err;
  80        }
  81
  82        clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
  83        if (!clk_data) {
  84                pr_err("%s: could not allocate clock data\n", __func__);
  85                goto err;
  86        }
  87        clk_data->base = base;
  88
  89        clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
  90        if (!clk_table) {
  91                pr_err("%s: could not allocate clock lookup table\n", __func__);
  92                goto err_data;
  93        }
  94        clk_data->clk_data.clks = clk_table;
  95        clk_data->clk_data.clk_num = nr_clks;
  96        of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data->clk_data);
  97        return clk_data;
  98err_data:
  99        kfree(clk_data);
 100err:
 101        return NULL;
 102}
 103EXPORT_SYMBOL_GPL(hisi_clk_init);
 104
 105int hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *clks,
 106                                         int nums, struct hisi_clock_data *data)
 107{
 108        struct clk *clk;
 109        int i;
 110
 111        for (i = 0; i < nums; i++) {
 112                clk = clk_register_fixed_rate(NULL, clks[i].name,
 113                                              clks[i].parent_name,
 114                                              clks[i].flags,
 115                                              clks[i].fixed_rate);
 116                if (IS_ERR(clk)) {
 117                        pr_err("%s: failed to register clock %s\n",
 118                               __func__, clks[i].name);
 119                        goto err;
 120                }
 121                data->clk_data.clks[clks[i].id] = clk;
 122        }
 123
 124        return 0;
 125
 126err:
 127        while (i--)
 128                clk_unregister_fixed_rate(data->clk_data.clks[clks[i].id]);
 129
 130        return PTR_ERR(clk);
 131}
 132EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_rate);
 133
 134int hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *clks,
 135                                           int nums,
 136                                           struct hisi_clock_data *data)
 137{
 138        struct clk *clk;
 139        int i;
 140
 141        for (i = 0; i < nums; i++) {
 142                clk = clk_register_fixed_factor(NULL, clks[i].name,
 143                                                clks[i].parent_name,
 144                                                clks[i].flags, clks[i].mult,
 145                                                clks[i].div);
 146                if (IS_ERR(clk)) {
 147                        pr_err("%s: failed to register clock %s\n",
 148                               __func__, clks[i].name);
 149                        goto err;
 150                }
 151                data->clk_data.clks[clks[i].id] = clk;
 152        }
 153
 154        return 0;
 155
 156err:
 157        while (i--)
 158                clk_unregister_fixed_factor(data->clk_data.clks[clks[i].id]);
 159
 160        return PTR_ERR(clk);
 161}
 162EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_factor);
 163
 164int hisi_clk_register_mux(const struct hisi_mux_clock *clks,
 165                                  int nums, struct hisi_clock_data *data)
 166{
 167        struct clk *clk;
 168        void __iomem *base = data->base;
 169        int i;
 170
 171        for (i = 0; i < nums; i++) {
 172                u32 mask = BIT(clks[i].width) - 1;
 173
 174                clk = clk_register_mux_table(NULL, clks[i].name,
 175                                        clks[i].parent_names,
 176                                        clks[i].num_parents, clks[i].flags,
 177                                        base + clks[i].offset, clks[i].shift,
 178                                        mask, clks[i].mux_flags,
 179                                        clks[i].table, &hisi_clk_lock);
 180                if (IS_ERR(clk)) {
 181                        pr_err("%s: failed to register clock %s\n",
 182                               __func__, clks[i].name);
 183                        goto err;
 184                }
 185
 186                if (clks[i].alias)
 187                        clk_register_clkdev(clk, clks[i].alias, NULL);
 188
 189                data->clk_data.clks[clks[i].id] = clk;
 190        }
 191
 192        return 0;
 193
 194err:
 195        while (i--)
 196                clk_unregister_mux(data->clk_data.clks[clks[i].id]);
 197
 198        return PTR_ERR(clk);
 199}
 200EXPORT_SYMBOL_GPL(hisi_clk_register_mux);
 201
 202int hisi_clk_register_divider(const struct hisi_divider_clock *clks,
 203                                      int nums, struct hisi_clock_data *data)
 204{
 205        struct clk *clk;
 206        void __iomem *base = data->base;
 207        int i;
 208
 209        for (i = 0; i < nums; i++) {
 210                clk = clk_register_divider_table(NULL, clks[i].name,
 211                                                 clks[i].parent_name,
 212                                                 clks[i].flags,
 213                                                 base + clks[i].offset,
 214                                                 clks[i].shift, clks[i].width,
 215                                                 clks[i].div_flags,
 216                                                 clks[i].table,
 217                                                 &hisi_clk_lock);
 218                if (IS_ERR(clk)) {
 219                        pr_err("%s: failed to register clock %s\n",
 220                               __func__, clks[i].name);
 221                        goto err;
 222                }
 223
 224                if (clks[i].alias)
 225                        clk_register_clkdev(clk, clks[i].alias, NULL);
 226
 227                data->clk_data.clks[clks[i].id] = clk;
 228        }
 229
 230        return 0;
 231
 232err:
 233        while (i--)
 234                clk_unregister_divider(data->clk_data.clks[clks[i].id]);
 235
 236        return PTR_ERR(clk);
 237}
 238EXPORT_SYMBOL_GPL(hisi_clk_register_divider);
 239
 240int hisi_clk_register_gate(const struct hisi_gate_clock *clks,
 241                                       int nums, struct hisi_clock_data *data)
 242{
 243        struct clk *clk;
 244        void __iomem *base = data->base;
 245        int i;
 246
 247        for (i = 0; i < nums; i++) {
 248                clk = clk_register_gate(NULL, clks[i].name,
 249                                                clks[i].parent_name,
 250                                                clks[i].flags,
 251                                                base + clks[i].offset,
 252                                                clks[i].bit_idx,
 253                                                clks[i].gate_flags,
 254                                                &hisi_clk_lock);
 255                if (IS_ERR(clk)) {
 256                        pr_err("%s: failed to register clock %s\n",
 257                               __func__, clks[i].name);
 258                        goto err;
 259                }
 260
 261                if (clks[i].alias)
 262                        clk_register_clkdev(clk, clks[i].alias, NULL);
 263
 264                data->clk_data.clks[clks[i].id] = clk;
 265        }
 266
 267        return 0;
 268
 269err:
 270        while (i--)
 271                clk_unregister_gate(data->clk_data.clks[clks[i].id]);
 272
 273        return PTR_ERR(clk);
 274}
 275EXPORT_SYMBOL_GPL(hisi_clk_register_gate);
 276
 277void hisi_clk_register_gate_sep(const struct hisi_gate_clock *clks,
 278                                       int nums, struct hisi_clock_data *data)
 279{
 280        struct clk *clk;
 281        void __iomem *base = data->base;
 282        int i;
 283
 284        for (i = 0; i < nums; i++) {
 285                clk = hisi_register_clkgate_sep(NULL, clks[i].name,
 286                                                clks[i].parent_name,
 287                                                clks[i].flags,
 288                                                base + clks[i].offset,
 289                                                clks[i].bit_idx,
 290                                                clks[i].gate_flags,
 291                                                &hisi_clk_lock);
 292                if (IS_ERR(clk)) {
 293                        pr_err("%s: failed to register clock %s\n",
 294                               __func__, clks[i].name);
 295                        continue;
 296                }
 297
 298                if (clks[i].alias)
 299                        clk_register_clkdev(clk, clks[i].alias, NULL);
 300
 301                data->clk_data.clks[clks[i].id] = clk;
 302        }
 303}
 304EXPORT_SYMBOL_GPL(hisi_clk_register_gate_sep);
 305
 306void __init hi6220_clk_register_divider(const struct hi6220_divider_clock *clks,
 307                                        int nums, struct hisi_clock_data *data)
 308{
 309        struct clk *clk;
 310        void __iomem *base = data->base;
 311        int i;
 312
 313        for (i = 0; i < nums; i++) {
 314                clk = hi6220_register_clkdiv(NULL, clks[i].name,
 315                                                clks[i].parent_name,
 316                                                clks[i].flags,
 317                                                base + clks[i].offset,
 318                                                clks[i].shift,
 319                                                clks[i].width,
 320                                                clks[i].mask_bit,
 321                                                &hisi_clk_lock);
 322                if (IS_ERR(clk)) {
 323                        pr_err("%s: failed to register clock %s\n",
 324                               __func__, clks[i].name);
 325                        continue;
 326                }
 327
 328                if (clks[i].alias)
 329                        clk_register_clkdev(clk, clks[i].alias, NULL);
 330
 331                data->clk_data.clks[clks[i].id] = clk;
 332        }
 333}
 334