linux/drivers/clk/mediatek/clk-mux.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2018 MediaTek Inc.
   4 * Author: Owen Chen <owen.chen@mediatek.com>
   5 */
   6
   7#include <linux/of.h>
   8#include <linux/of_address.h>
   9#include <linux/slab.h>
  10#include <linux/mfd/syscon.h>
  11
  12#include "clk-mtk.h"
  13#include "clk-mux.h"
  14
  15static inline struct mtk_clk_mux *to_mtk_clk_mux(struct clk_hw *hw)
  16{
  17        return container_of(hw, struct mtk_clk_mux, hw);
  18}
  19
  20static int mtk_clk_mux_enable(struct clk_hw *hw)
  21{
  22        struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
  23        u32 mask = BIT(mux->data->gate_shift);
  24
  25        return regmap_update_bits(mux->regmap, mux->data->mux_ofs,
  26                        mask, ~mask);
  27}
  28
  29static void mtk_clk_mux_disable(struct clk_hw *hw)
  30{
  31        struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
  32        u32 mask = BIT(mux->data->gate_shift);
  33
  34        regmap_update_bits(mux->regmap, mux->data->mux_ofs, mask, mask);
  35}
  36
  37static int mtk_clk_mux_enable_setclr(struct clk_hw *hw)
  38{
  39        struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
  40
  41        return regmap_write(mux->regmap, mux->data->clr_ofs,
  42                        BIT(mux->data->gate_shift));
  43}
  44
  45static void mtk_clk_mux_disable_setclr(struct clk_hw *hw)
  46{
  47        struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
  48
  49        regmap_write(mux->regmap, mux->data->set_ofs,
  50                        BIT(mux->data->gate_shift));
  51}
  52
  53static int mtk_clk_mux_is_enabled(struct clk_hw *hw)
  54{
  55        struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
  56        u32 val;
  57
  58        regmap_read(mux->regmap, mux->data->mux_ofs, &val);
  59
  60        return (val & BIT(mux->data->gate_shift)) == 0;
  61}
  62
  63static u8 mtk_clk_mux_get_parent(struct clk_hw *hw)
  64{
  65        struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
  66        u32 mask = GENMASK(mux->data->mux_width - 1, 0);
  67        u32 val;
  68
  69        regmap_read(mux->regmap, mux->data->mux_ofs, &val);
  70        val = (val >> mux->data->mux_shift) & mask;
  71
  72        return val;
  73}
  74
  75static int mtk_clk_mux_set_parent_lock(struct clk_hw *hw, u8 index)
  76{
  77        struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
  78        u32 mask = GENMASK(mux->data->mux_width - 1, 0);
  79        unsigned long flags = 0;
  80
  81        if (mux->lock)
  82                spin_lock_irqsave(mux->lock, flags);
  83        else
  84                __acquire(mux->lock);
  85
  86        regmap_update_bits(mux->regmap, mux->data->mux_ofs, mask,
  87                index << mux->data->mux_shift);
  88
  89        if (mux->lock)
  90                spin_unlock_irqrestore(mux->lock, flags);
  91        else
  92                __release(mux->lock);
  93
  94        return 0;
  95}
  96
  97static int mtk_clk_mux_set_parent_setclr_lock(struct clk_hw *hw, u8 index)
  98{
  99        struct mtk_clk_mux *mux = to_mtk_clk_mux(hw);
 100        u32 mask = GENMASK(mux->data->mux_width - 1, 0);
 101        u32 val, orig;
 102        unsigned long flags = 0;
 103
 104        if (mux->lock)
 105                spin_lock_irqsave(mux->lock, flags);
 106        else
 107                __acquire(mux->lock);
 108
 109        regmap_read(mux->regmap, mux->data->mux_ofs, &orig);
 110        val = (orig & ~(mask << mux->data->mux_shift))
 111                        | (index << mux->data->mux_shift);
 112
 113        if (val != orig) {
 114                regmap_write(mux->regmap, mux->data->clr_ofs,
 115                                mask << mux->data->mux_shift);
 116                regmap_write(mux->regmap, mux->data->set_ofs,
 117                                index << mux->data->mux_shift);
 118
 119                if (mux->data->upd_shift >= 0)
 120                        regmap_write(mux->regmap, mux->data->upd_ofs,
 121                                        BIT(mux->data->upd_shift));
 122        }
 123
 124        if (mux->lock)
 125                spin_unlock_irqrestore(mux->lock, flags);
 126        else
 127                __release(mux->lock);
 128
 129        return 0;
 130}
 131
 132const struct clk_ops mtk_mux_ops = {
 133        .get_parent = mtk_clk_mux_get_parent,
 134        .set_parent = mtk_clk_mux_set_parent_lock,
 135};
 136
 137const struct clk_ops mtk_mux_clr_set_upd_ops = {
 138        .get_parent = mtk_clk_mux_get_parent,
 139        .set_parent = mtk_clk_mux_set_parent_setclr_lock,
 140};
 141
 142const struct clk_ops mtk_mux_gate_ops = {
 143        .enable = mtk_clk_mux_enable,
 144        .disable = mtk_clk_mux_disable,
 145        .is_enabled = mtk_clk_mux_is_enabled,
 146        .get_parent = mtk_clk_mux_get_parent,
 147        .set_parent = mtk_clk_mux_set_parent_lock,
 148};
 149
 150const struct clk_ops mtk_mux_gate_clr_set_upd_ops = {
 151        .enable = mtk_clk_mux_enable_setclr,
 152        .disable = mtk_clk_mux_disable_setclr,
 153        .is_enabled = mtk_clk_mux_is_enabled,
 154        .get_parent = mtk_clk_mux_get_parent,
 155        .set_parent = mtk_clk_mux_set_parent_setclr_lock,
 156};
 157
 158struct clk *mtk_clk_register_mux(const struct mtk_mux *mux,
 159                                 struct regmap *regmap,
 160                                 spinlock_t *lock)
 161{
 162        struct mtk_clk_mux *clk_mux;
 163        struct clk_init_data init;
 164        struct clk *clk;
 165
 166        clk_mux = kzalloc(sizeof(*clk_mux), GFP_KERNEL);
 167        if (!clk_mux)
 168                return ERR_PTR(-ENOMEM);
 169
 170        init.name = mux->name;
 171        init.flags = mux->flags | CLK_SET_RATE_PARENT;
 172        init.parent_names = mux->parent_names;
 173        init.num_parents = mux->num_parents;
 174        init.ops = mux->ops;
 175
 176        clk_mux->regmap = regmap;
 177        clk_mux->data = mux;
 178        clk_mux->lock = lock;
 179        clk_mux->hw.init = &init;
 180
 181        clk = clk_register(NULL, &clk_mux->hw);
 182        if (IS_ERR(clk)) {
 183                kfree(clk_mux);
 184                return clk;
 185        }
 186
 187        return clk;
 188}
 189
 190int mtk_clk_register_muxes(const struct mtk_mux *muxes,
 191                           int num, struct device_node *node,
 192                           spinlock_t *lock,
 193                           struct clk_onecell_data *clk_data)
 194{
 195        struct regmap *regmap;
 196        struct clk *clk;
 197        int i;
 198
 199        regmap = syscon_node_to_regmap(node);
 200        if (IS_ERR(regmap)) {
 201                pr_err("Cannot find regmap for %pOF: %ld\n", node,
 202                       PTR_ERR(regmap));
 203                return PTR_ERR(regmap);
 204        }
 205
 206        for (i = 0; i < num; i++) {
 207                const struct mtk_mux *mux = &muxes[i];
 208
 209                if (IS_ERR_OR_NULL(clk_data->clks[mux->id])) {
 210                        clk = mtk_clk_register_mux(mux, regmap, lock);
 211
 212                        if (IS_ERR(clk)) {
 213                                pr_err("Failed to register clk %s: %ld\n",
 214                                       mux->name, PTR_ERR(clk));
 215                                continue;
 216                        }
 217
 218                        clk_data->clks[mux->id] = clk;
 219                }
 220        }
 221
 222        return 0;
 223}
 224