162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#include <linux/slab.h> 462306a36Sopenharmony_ci#include <linux/bitops.h> 562306a36Sopenharmony_ci#include <linux/regmap.h> 662306a36Sopenharmony_ci#include <linux/clk.h> 762306a36Sopenharmony_ci#include <linux/clk-provider.h> 862306a36Sopenharmony_ci#include "clk.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_cistruct rockchip_muxgrf_clock { 1162306a36Sopenharmony_ci struct clk_hw hw; 1262306a36Sopenharmony_ci struct regmap *regmap; 1362306a36Sopenharmony_ci u32 reg; 1462306a36Sopenharmony_ci u32 shift; 1562306a36Sopenharmony_ci u32 width; 1662306a36Sopenharmony_ci int flags; 1762306a36Sopenharmony_ci}; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define to_muxgrf_clock(_hw) container_of(_hw, struct rockchip_muxgrf_clock, hw) 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic u8 rockchip_muxgrf_get_parent(struct clk_hw *hw) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci struct rockchip_muxgrf_clock *mux = to_muxgrf_clock(hw); 2462306a36Sopenharmony_ci unsigned int mask = GENMASK(mux->width - 1, 0); 2562306a36Sopenharmony_ci unsigned int val; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci regmap_read(mux->regmap, mux->reg, &val); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci val >>= mux->shift; 3062306a36Sopenharmony_ci val &= mask; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci return val; 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic int rockchip_muxgrf_set_parent(struct clk_hw *hw, u8 index) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci struct rockchip_muxgrf_clock *mux = to_muxgrf_clock(hw); 3862306a36Sopenharmony_ci unsigned int mask = GENMASK(mux->width + mux->shift - 1, mux->shift); 3962306a36Sopenharmony_ci unsigned int val; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci val = index; 4262306a36Sopenharmony_ci val <<= mux->shift; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci if (mux->flags & CLK_MUX_HIWORD_MASK) 4562306a36Sopenharmony_ci return regmap_write(mux->regmap, mux->reg, val | (mask << 16)); 4662306a36Sopenharmony_ci else 4762306a36Sopenharmony_ci return regmap_update_bits(mux->regmap, mux->reg, mask, val); 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic const struct clk_ops rockchip_muxgrf_clk_ops = { 5162306a36Sopenharmony_ci .get_parent = rockchip_muxgrf_get_parent, 5262306a36Sopenharmony_ci .set_parent = rockchip_muxgrf_set_parent, 5362306a36Sopenharmony_ci .determine_rate = __clk_mux_determine_rate, 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistruct clk *rockchip_clk_register_muxgrf(const char *name, 5762306a36Sopenharmony_ci const char *const *parent_names, u8 num_parents, 5862306a36Sopenharmony_ci int flags, struct regmap *regmap, int reg, 5962306a36Sopenharmony_ci int shift, int width, int mux_flags) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct rockchip_muxgrf_clock *muxgrf_clock; 6262306a36Sopenharmony_ci struct clk_init_data init; 6362306a36Sopenharmony_ci struct clk *clk; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (IS_ERR(regmap)) { 6662306a36Sopenharmony_ci pr_err("%s: regmap not available\n", __func__); 6762306a36Sopenharmony_ci return ERR_PTR(-ENOTSUPP); 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci muxgrf_clock = kmalloc(sizeof(*muxgrf_clock), GFP_KERNEL); 7162306a36Sopenharmony_ci if (!muxgrf_clock) 7262306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci init.name = name; 7562306a36Sopenharmony_ci init.flags = flags; 7662306a36Sopenharmony_ci init.num_parents = num_parents; 7762306a36Sopenharmony_ci init.parent_names = parent_names; 7862306a36Sopenharmony_ci init.ops = &rockchip_muxgrf_clk_ops; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci muxgrf_clock->hw.init = &init; 8162306a36Sopenharmony_ci muxgrf_clock->regmap = regmap; 8262306a36Sopenharmony_ci muxgrf_clock->reg = reg; 8362306a36Sopenharmony_ci muxgrf_clock->shift = shift; 8462306a36Sopenharmony_ci muxgrf_clock->width = width; 8562306a36Sopenharmony_ci muxgrf_clock->flags = mux_flags; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci clk = clk_register(NULL, &muxgrf_clock->hw); 8862306a36Sopenharmony_ci if (IS_ERR(clk)) 8962306a36Sopenharmony_ci kfree(muxgrf_clock); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci return clk; 9262306a36Sopenharmony_ci} 93