Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright (C) 2016 Socionext Inc.
0004  *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
0005  */
0006 
0007 #include <linux/clk-provider.h>
0008 #include <linux/device.h>
0009 #include <linux/regmap.h>
0010 
0011 #include "clk-uniphier.h"
0012 
0013 struct uniphier_clk_mux {
0014     struct clk_hw hw;
0015     struct regmap *regmap;
0016     unsigned int reg;
0017     const unsigned int *masks;
0018     const unsigned int *vals;
0019 };
0020 
0021 #define to_uniphier_clk_mux(_hw) container_of(_hw, struct uniphier_clk_mux, hw)
0022 
0023 static int uniphier_clk_mux_set_parent(struct clk_hw *hw, u8 index)
0024 {
0025     struct uniphier_clk_mux *mux = to_uniphier_clk_mux(hw);
0026 
0027     return regmap_write_bits(mux->regmap, mux->reg, mux->masks[index],
0028                  mux->vals[index]);
0029 }
0030 
0031 static u8 uniphier_clk_mux_get_parent(struct clk_hw *hw)
0032 {
0033     struct uniphier_clk_mux *mux = to_uniphier_clk_mux(hw);
0034     unsigned int num_parents = clk_hw_get_num_parents(hw);
0035     int ret;
0036     unsigned int val;
0037     unsigned int i;
0038 
0039     ret = regmap_read(mux->regmap, mux->reg, &val);
0040     if (ret)
0041         return ret;
0042 
0043     for (i = 0; i < num_parents; i++)
0044         if ((mux->masks[i] & val) == mux->vals[i])
0045             return i;
0046 
0047     return -EINVAL;
0048 }
0049 
0050 static const struct clk_ops uniphier_clk_mux_ops = {
0051     .determine_rate = __clk_mux_determine_rate,
0052     .set_parent = uniphier_clk_mux_set_parent,
0053     .get_parent = uniphier_clk_mux_get_parent,
0054 };
0055 
0056 struct clk_hw *uniphier_clk_register_mux(struct device *dev,
0057                      struct regmap *regmap,
0058                      const char *name,
0059                 const struct uniphier_clk_mux_data *data)
0060 {
0061     struct uniphier_clk_mux *mux;
0062     struct clk_init_data init;
0063     int ret;
0064 
0065     mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
0066     if (!mux)
0067         return ERR_PTR(-ENOMEM);
0068 
0069     init.name = name;
0070     init.ops = &uniphier_clk_mux_ops;
0071     init.flags = CLK_SET_RATE_PARENT;
0072     init.parent_names = data->parent_names;
0073     init.num_parents = data->num_parents;
0074 
0075     mux->regmap = regmap;
0076     mux->reg = data->reg;
0077     mux->masks = data->masks;
0078     mux->vals = data->vals;
0079     mux->hw.init = &init;
0080 
0081     ret = devm_clk_hw_register(dev, &mux->hw);
0082     if (ret)
0083         return ERR_PTR(ret);
0084 
0085     return &mux->hw;
0086 }