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 __init *hisi_clk_init(struct device_node *np,
  41                                             int nr_clks)
  42{
  43        struct hisi_clock_data *clk_data;
  44        struct clk **clk_table;
  45        void __iomem *base;
  46
  47        base = of_iomap(np, 0);
  48        if (!base) {
  49                pr_err("%s: failed to map clock registers\n", __func__);
  50                goto err;
  51        }
  52
  53        clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
  54        if (!clk_data) {
  55                pr_err("%s: could not allocate clock data\n", __func__);
  56                goto err;
  57        }
  58        clk_data->base = base;
  59
  60        clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
  61        if (!clk_table) {
  62                pr_err("%s: could not allocate clock lookup table\n", __func__);
  63                goto err_data;
  64        }
  65        clk_data->clk_data.clks = clk_table;
  66        clk_data->clk_data.clk_num = nr_clks;
  67        of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data->clk_data);
  68        return clk_data;
  69err_data:
  70        kfree(clk_data);
  71err:
  72        return NULL;
  73}
  74
  75void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *clks,
  76                                         int nums, struct hisi_clock_data *data)
  77{
  78        struct clk *clk;
  79        int i;
  80
  81        for (i = 0; i < nums; i++) {
  82                clk = clk_register_fixed_rate(NULL, clks[i].name,
  83                                              clks[i].parent_name,
  84                                              clks[i].flags,
  85                                              clks[i].fixed_rate);
  86                if (IS_ERR(clk)) {
  87                        pr_err("%s: failed to register clock %s\n",
  88                               __func__, clks[i].name);
  89                        continue;
  90                }
  91                data->clk_data.clks[clks[i].id] = clk;
  92        }
  93}
  94
  95void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *clks,
  96                                           int nums,
  97                                           struct hisi_clock_data *data)
  98{
  99        struct clk *clk;
 100        int i;
 101
 102        for (i = 0; i < nums; i++) {
 103                clk = clk_register_fixed_factor(NULL, clks[i].name,
 104                                                clks[i].parent_name,
 105                                                clks[i].flags, clks[i].mult,
 106                                                clks[i].div);
 107                if (IS_ERR(clk)) {
 108                        pr_err("%s: failed to register clock %s\n",
 109                               __func__, clks[i].name);
 110                        continue;
 111                }
 112                data->clk_data.clks[clks[i].id] = clk;
 113        }
 114}
 115
 116void __init hisi_clk_register_mux(struct hisi_mux_clock *clks,
 117                                  int nums, struct hisi_clock_data *data)
 118{
 119        struct clk *clk;
 120        void __iomem *base = data->base;
 121        int i;
 122
 123        for (i = 0; i < nums; i++) {
 124                u32 mask = BIT(clks[i].width) - 1;
 125
 126                clk = clk_register_mux_table(NULL, clks[i].name,
 127                                        clks[i].parent_names,
 128                                        clks[i].num_parents, clks[i].flags,
 129                                        base + clks[i].offset, clks[i].shift,
 130                                        mask, clks[i].mux_flags,
 131                                        clks[i].table, &hisi_clk_lock);
 132                if (IS_ERR(clk)) {
 133                        pr_err("%s: failed to register clock %s\n",
 134                               __func__, clks[i].name);
 135                        continue;
 136                }
 137
 138                if (clks[i].alias)
 139                        clk_register_clkdev(clk, clks[i].alias, NULL);
 140
 141                data->clk_data.clks[clks[i].id] = clk;
 142        }
 143}
 144
 145void __init hisi_clk_register_divider(struct hisi_divider_clock *clks,
 146                                      int nums, struct hisi_clock_data *data)
 147{
 148        struct clk *clk;
 149        void __iomem *base = data->base;
 150        int i;
 151
 152        for (i = 0; i < nums; i++) {
 153                clk = clk_register_divider_table(NULL, clks[i].name,
 154                                                 clks[i].parent_name,
 155                                                 clks[i].flags,
 156                                                 base + clks[i].offset,
 157                                                 clks[i].shift, clks[i].width,
 158                                                 clks[i].div_flags,
 159                                                 clks[i].table,
 160                                                 &hisi_clk_lock);
 161                if (IS_ERR(clk)) {
 162                        pr_err("%s: failed to register clock %s\n",
 163                               __func__, clks[i].name);
 164                        continue;
 165                }
 166
 167                if (clks[i].alias)
 168                        clk_register_clkdev(clk, clks[i].alias, NULL);
 169
 170                data->clk_data.clks[clks[i].id] = clk;
 171        }
 172}
 173
 174void __init hisi_clk_register_gate(struct hisi_gate_clock *clks,
 175                                       int nums, struct hisi_clock_data *data)
 176{
 177        struct clk *clk;
 178        void __iomem *base = data->base;
 179        int i;
 180
 181        for (i = 0; i < nums; i++) {
 182                clk = clk_register_gate(NULL, clks[i].name,
 183                                                clks[i].parent_name,
 184                                                clks[i].flags,
 185                                                base + clks[i].offset,
 186                                                clks[i].bit_idx,
 187                                                clks[i].gate_flags,
 188                                                &hisi_clk_lock);
 189                if (IS_ERR(clk)) {
 190                        pr_err("%s: failed to register clock %s\n",
 191                               __func__, clks[i].name);
 192                        continue;
 193                }
 194
 195                if (clks[i].alias)
 196                        clk_register_clkdev(clk, clks[i].alias, NULL);
 197
 198                data->clk_data.clks[clks[i].id] = clk;
 199        }
 200}
 201
 202void __init hisi_clk_register_gate_sep(struct hisi_gate_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 = hisi_register_clkgate_sep(NULL, clks[i].name,
 211                                                clks[i].parent_name,
 212                                                clks[i].flags,
 213                                                base + clks[i].offset,
 214                                                clks[i].bit_idx,
 215                                                clks[i].gate_flags,
 216                                                &hisi_clk_lock);
 217                if (IS_ERR(clk)) {
 218                        pr_err("%s: failed to register clock %s\n",
 219                               __func__, clks[i].name);
 220                        continue;
 221                }
 222
 223                if (clks[i].alias)
 224                        clk_register_clkdev(clk, clks[i].alias, NULL);
 225
 226                data->clk_data.clks[clks[i].id] = clk;
 227        }
 228}
 229
 230void __init hi6220_clk_register_divider(struct hi6220_divider_clock *clks,
 231                                        int nums, struct hisi_clock_data *data)
 232{
 233        struct clk *clk;
 234        void __iomem *base = data->base;
 235        int i;
 236
 237        for (i = 0; i < nums; i++) {
 238                clk = hi6220_register_clkdiv(NULL, clks[i].name,
 239                                                clks[i].parent_name,
 240                                                clks[i].flags,
 241                                                base + clks[i].offset,
 242                                                clks[i].shift,
 243                                                clks[i].width,
 244                                                clks[i].mask_bit,
 245                                                &hisi_clk_lock);
 246                if (IS_ERR(clk)) {
 247                        pr_err("%s: failed to register clock %s\n",
 248                               __func__, clks[i].name);
 249                        continue;
 250                }
 251
 252                if (clks[i].alias)
 253                        clk_register_clkdev(clk, clks[i].alias, NULL);
 254
 255                data->clk_data.clks[clks[i].id] = clk;
 256        }
 257}
 258