linux/drivers/clk/mediatek/clk-mtk.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2014 MediaTek Inc.
   4 * Author: James Liao <jamesjj.liao@mediatek.com>
   5 */
   6
   7#include <linux/of.h>
   8#include <linux/of_address.h>
   9#include <linux/err.h>
  10#include <linux/io.h>
  11#include <linux/slab.h>
  12#include <linux/delay.h>
  13#include <linux/clkdev.h>
  14#include <linux/mfd/syscon.h>
  15#include <linux/device.h>
  16#include <linux/of_device.h>
  17
  18#include "clk-mtk.h"
  19#include "clk-gate.h"
  20
  21struct clk_onecell_data *mtk_alloc_clk_data(unsigned int clk_num)
  22{
  23        int i;
  24        struct clk_onecell_data *clk_data;
  25
  26        clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
  27        if (!clk_data)
  28                return NULL;
  29
  30        clk_data->clks = kcalloc(clk_num, sizeof(*clk_data->clks), GFP_KERNEL);
  31        if (!clk_data->clks)
  32                goto err_out;
  33
  34        clk_data->clk_num = clk_num;
  35
  36        for (i = 0; i < clk_num; i++)
  37                clk_data->clks[i] = ERR_PTR(-ENOENT);
  38
  39        return clk_data;
  40err_out:
  41        kfree(clk_data);
  42
  43        return NULL;
  44}
  45
  46void mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks,
  47                int num, struct clk_onecell_data *clk_data)
  48{
  49        int i;
  50        struct clk *clk;
  51
  52        for (i = 0; i < num; i++) {
  53                const struct mtk_fixed_clk *rc = &clks[i];
  54
  55                if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[rc->id]))
  56                        continue;
  57
  58                clk = clk_register_fixed_rate(NULL, rc->name, rc->parent, 0,
  59                                              rc->rate);
  60
  61                if (IS_ERR(clk)) {
  62                        pr_err("Failed to register clk %s: %ld\n",
  63                                        rc->name, PTR_ERR(clk));
  64                        continue;
  65                }
  66
  67                if (clk_data)
  68                        clk_data->clks[rc->id] = clk;
  69        }
  70}
  71
  72void mtk_clk_register_factors(const struct mtk_fixed_factor *clks,
  73                int num, struct clk_onecell_data *clk_data)
  74{
  75        int i;
  76        struct clk *clk;
  77
  78        for (i = 0; i < num; i++) {
  79                const struct mtk_fixed_factor *ff = &clks[i];
  80
  81                if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[ff->id]))
  82                        continue;
  83
  84                clk = clk_register_fixed_factor(NULL, ff->name, ff->parent_name,
  85                                CLK_SET_RATE_PARENT, ff->mult, ff->div);
  86
  87                if (IS_ERR(clk)) {
  88                        pr_err("Failed to register clk %s: %ld\n",
  89                                        ff->name, PTR_ERR(clk));
  90                        continue;
  91                }
  92
  93                if (clk_data)
  94                        clk_data->clks[ff->id] = clk;
  95        }
  96}
  97
  98int mtk_clk_register_gates_with_dev(struct device_node *node,
  99                const struct mtk_gate *clks,
 100                int num, struct clk_onecell_data *clk_data,
 101                struct device *dev)
 102{
 103        int i;
 104        struct clk *clk;
 105        struct regmap *regmap;
 106
 107        if (!clk_data)
 108                return -ENOMEM;
 109
 110        regmap = device_node_to_regmap(node);
 111        if (IS_ERR(regmap)) {
 112                pr_err("Cannot find regmap for %pOF: %ld\n", node,
 113                                PTR_ERR(regmap));
 114                return PTR_ERR(regmap);
 115        }
 116
 117        for (i = 0; i < num; i++) {
 118                const struct mtk_gate *gate = &clks[i];
 119
 120                if (!IS_ERR_OR_NULL(clk_data->clks[gate->id]))
 121                        continue;
 122
 123                clk = mtk_clk_register_gate(gate->name, gate->parent_name,
 124                                regmap,
 125                                gate->regs->set_ofs,
 126                                gate->regs->clr_ofs,
 127                                gate->regs->sta_ofs,
 128                                gate->shift, gate->ops, gate->flags, dev);
 129
 130                if (IS_ERR(clk)) {
 131                        pr_err("Failed to register clk %s: %ld\n",
 132                                        gate->name, PTR_ERR(clk));
 133                        continue;
 134                }
 135
 136                clk_data->clks[gate->id] = clk;
 137        }
 138
 139        return 0;
 140}
 141
 142int mtk_clk_register_gates(struct device_node *node,
 143                const struct mtk_gate *clks,
 144                int num, struct clk_onecell_data *clk_data)
 145{
 146        return mtk_clk_register_gates_with_dev(node,
 147                clks, num, clk_data, NULL);
 148}
 149
 150struct clk *mtk_clk_register_composite(const struct mtk_composite *mc,
 151                void __iomem *base, spinlock_t *lock)
 152{
 153        struct clk *clk;
 154        struct clk_mux *mux = NULL;
 155        struct clk_gate *gate = NULL;
 156        struct clk_divider *div = NULL;
 157        struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *div_hw = NULL;
 158        const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *div_ops = NULL;
 159        const char * const *parent_names;
 160        const char *parent;
 161        int num_parents;
 162        int ret;
 163
 164        if (mc->mux_shift >= 0) {
 165                mux = kzalloc(sizeof(*mux), GFP_KERNEL);
 166                if (!mux)
 167                        return ERR_PTR(-ENOMEM);
 168
 169                mux->reg = base + mc->mux_reg;
 170                mux->mask = BIT(mc->mux_width) - 1;
 171                mux->shift = mc->mux_shift;
 172                mux->lock = lock;
 173                mux->flags = mc->mux_flags;
 174                mux_hw = &mux->hw;
 175                mux_ops = &clk_mux_ops;
 176
 177                parent_names = mc->parent_names;
 178                num_parents = mc->num_parents;
 179        } else {
 180                parent = mc->parent;
 181                parent_names = &parent;
 182                num_parents = 1;
 183        }
 184
 185        if (mc->gate_shift >= 0) {
 186                gate = kzalloc(sizeof(*gate), GFP_KERNEL);
 187                if (!gate) {
 188                        ret = -ENOMEM;
 189                        goto err_out;
 190                }
 191
 192                gate->reg = base + mc->gate_reg;
 193                gate->bit_idx = mc->gate_shift;
 194                gate->flags = CLK_GATE_SET_TO_DISABLE;
 195                gate->lock = lock;
 196
 197                gate_hw = &gate->hw;
 198                gate_ops = &clk_gate_ops;
 199        }
 200
 201        if (mc->divider_shift >= 0) {
 202                div = kzalloc(sizeof(*div), GFP_KERNEL);
 203                if (!div) {
 204                        ret = -ENOMEM;
 205                        goto err_out;
 206                }
 207
 208                div->reg = base + mc->divider_reg;
 209                div->shift = mc->divider_shift;
 210                div->width = mc->divider_width;
 211                div->lock = lock;
 212
 213                div_hw = &div->hw;
 214                div_ops = &clk_divider_ops;
 215        }
 216
 217        clk = clk_register_composite(NULL, mc->name, parent_names, num_parents,
 218                mux_hw, mux_ops,
 219                div_hw, div_ops,
 220                gate_hw, gate_ops,
 221                mc->flags);
 222
 223        if (IS_ERR(clk)) {
 224                ret = PTR_ERR(clk);
 225                goto err_out;
 226        }
 227
 228        return clk;
 229err_out:
 230        kfree(div);
 231        kfree(gate);
 232        kfree(mux);
 233
 234        return ERR_PTR(ret);
 235}
 236
 237void mtk_clk_register_composites(const struct mtk_composite *mcs,
 238                int num, void __iomem *base, spinlock_t *lock,
 239                struct clk_onecell_data *clk_data)
 240{
 241        struct clk *clk;
 242        int i;
 243
 244        for (i = 0; i < num; i++) {
 245                const struct mtk_composite *mc = &mcs[i];
 246
 247                if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[mc->id]))
 248                        continue;
 249
 250                clk = mtk_clk_register_composite(mc, base, lock);
 251
 252                if (IS_ERR(clk)) {
 253                        pr_err("Failed to register clk %s: %ld\n",
 254                                        mc->name, PTR_ERR(clk));
 255                        continue;
 256                }
 257
 258                if (clk_data)
 259                        clk_data->clks[mc->id] = clk;
 260        }
 261}
 262
 263void mtk_clk_register_dividers(const struct mtk_clk_divider *mcds,
 264                        int num, void __iomem *base, spinlock_t *lock,
 265                                struct clk_onecell_data *clk_data)
 266{
 267        struct clk *clk;
 268        int i;
 269
 270        for (i = 0; i <  num; i++) {
 271                const struct mtk_clk_divider *mcd = &mcds[i];
 272
 273                if (clk_data && !IS_ERR_OR_NULL(clk_data->clks[mcd->id]))
 274                        continue;
 275
 276                clk = clk_register_divider(NULL, mcd->name, mcd->parent_name,
 277                        mcd->flags, base +  mcd->div_reg, mcd->div_shift,
 278                        mcd->div_width, mcd->clk_divider_flags, lock);
 279
 280                if (IS_ERR(clk)) {
 281                        pr_err("Failed to register clk %s: %ld\n",
 282                                mcd->name, PTR_ERR(clk));
 283                        continue;
 284                }
 285
 286                if (clk_data)
 287                        clk_data->clks[mcd->id] = clk;
 288        }
 289}
 290
 291int mtk_clk_simple_probe(struct platform_device *pdev)
 292{
 293        const struct mtk_clk_desc *mcd;
 294        struct clk_onecell_data *clk_data;
 295        struct device_node *node = pdev->dev.of_node;
 296        int r;
 297
 298        mcd = of_device_get_match_data(&pdev->dev);
 299        if (!mcd)
 300                return -EINVAL;
 301
 302        clk_data = mtk_alloc_clk_data(mcd->num_clks);
 303        if (!clk_data)
 304                return -ENOMEM;
 305
 306        r = mtk_clk_register_gates(node, mcd->clks, mcd->num_clks, clk_data);
 307        if (r)
 308                return r;
 309
 310        return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
 311}
 312