linux/drivers/clk/rockchip/clk-muxgrf.c
<<
>>
Prefs
   1/*
   2 *
   3 * This software is licensed under the terms of the GNU General Public
   4 * License version 2, as published by the Free Software Foundation, and
   5 * may be copied, distributed, and modified under those terms.
   6 *
   7 * This program is distributed in the hope that it will be useful,
   8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
   9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10 * GNU General Public License for more details.
  11 */
  12
  13#include <linux/slab.h>
  14#include <linux/bitops.h>
  15#include <linux/regmap.h>
  16#include <linux/clk.h>
  17#include <linux/clk-provider.h>
  18#include "clk.h"
  19
  20struct rockchip_muxgrf_clock {
  21        struct clk_hw           hw;
  22        struct regmap           *regmap;
  23        u32                     reg;
  24        u32                     shift;
  25        u32                     width;
  26        int                     flags;
  27};
  28
  29#define to_muxgrf_clock(_hw) container_of(_hw, struct rockchip_muxgrf_clock, hw)
  30
  31static u8 rockchip_muxgrf_get_parent(struct clk_hw *hw)
  32{
  33        struct rockchip_muxgrf_clock *mux = to_muxgrf_clock(hw);
  34        unsigned int mask = GENMASK(mux->width - 1, 0);
  35        unsigned int val;
  36
  37        regmap_read(mux->regmap, mux->reg, &val);
  38
  39        val >>= mux->shift;
  40        val &= mask;
  41
  42        return val;
  43}
  44
  45static int rockchip_muxgrf_set_parent(struct clk_hw *hw, u8 index)
  46{
  47        struct rockchip_muxgrf_clock *mux = to_muxgrf_clock(hw);
  48        unsigned int mask = GENMASK(mux->width + mux->shift - 1, mux->shift);
  49        unsigned int val;
  50
  51        val = index;
  52        val <<= mux->shift;
  53
  54        if (mux->flags & CLK_MUX_HIWORD_MASK)
  55                return regmap_write(mux->regmap, mux->reg, val | (mask << 16));
  56        else
  57                return regmap_update_bits(mux->regmap, mux->reg, mask, val);
  58}
  59
  60static const struct clk_ops rockchip_muxgrf_clk_ops = {
  61        .get_parent = rockchip_muxgrf_get_parent,
  62        .set_parent = rockchip_muxgrf_set_parent,
  63        .determine_rate = __clk_mux_determine_rate,
  64};
  65
  66struct clk *rockchip_clk_register_muxgrf(const char *name,
  67                                const char *const *parent_names, u8 num_parents,
  68                                int flags, struct regmap *regmap, int reg,
  69                                int shift, int width, int mux_flags)
  70{
  71        struct rockchip_muxgrf_clock *muxgrf_clock;
  72        struct clk_init_data init;
  73        struct clk *clk;
  74
  75        if (IS_ERR(regmap)) {
  76                pr_err("%s: regmap not available\n", __func__);
  77                return ERR_PTR(-ENOTSUPP);
  78        }
  79
  80        muxgrf_clock = kmalloc(sizeof(*muxgrf_clock), GFP_KERNEL);
  81        if (!muxgrf_clock)
  82                return ERR_PTR(-ENOMEM);
  83
  84        init.name = name;
  85        init.flags = flags;
  86        init.num_parents = num_parents;
  87        init.parent_names = parent_names;
  88        init.ops = &rockchip_muxgrf_clk_ops;
  89
  90        muxgrf_clock->hw.init = &init;
  91        muxgrf_clock->regmap = regmap;
  92        muxgrf_clock->reg = reg;
  93        muxgrf_clock->shift = shift;
  94        muxgrf_clock->width = width;
  95        muxgrf_clock->flags = mux_flags;
  96
  97        clk = clk_register(NULL, &muxgrf_clock->hw);
  98        if (IS_ERR(clk))
  99                kfree(muxgrf_clock);
 100
 101        return clk;
 102}
 103