162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2014, The Linux Foundation. All rights reserved.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/kernel.h>
762306a36Sopenharmony_ci#include <linux/bitops.h>
862306a36Sopenharmony_ci#include <linux/regmap.h>
962306a36Sopenharmony_ci#include <linux/export.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "clk-regmap-mux.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistatic inline struct clk_regmap_mux *to_clk_regmap_mux(struct clk_hw *hw)
1462306a36Sopenharmony_ci{
1562306a36Sopenharmony_ci	return container_of(to_clk_regmap(hw), struct clk_regmap_mux, clkr);
1662306a36Sopenharmony_ci}
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistatic u8 mux_get_parent(struct clk_hw *hw)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	struct clk_regmap_mux *mux = to_clk_regmap_mux(hw);
2162306a36Sopenharmony_ci	struct clk_regmap *clkr = to_clk_regmap(hw);
2262306a36Sopenharmony_ci	unsigned int mask = GENMASK(mux->width - 1, 0);
2362306a36Sopenharmony_ci	unsigned int val;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	regmap_read(clkr->regmap, mux->reg, &val);
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	val >>= mux->shift;
2862306a36Sopenharmony_ci	val &= mask;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	if (mux->parent_map)
3162306a36Sopenharmony_ci		return qcom_find_cfg_index(hw, mux->parent_map, val);
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	return val;
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic int mux_set_parent(struct clk_hw *hw, u8 index)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	struct clk_regmap_mux *mux = to_clk_regmap_mux(hw);
3962306a36Sopenharmony_ci	struct clk_regmap *clkr = to_clk_regmap(hw);
4062306a36Sopenharmony_ci	unsigned int mask = GENMASK(mux->width + mux->shift - 1, mux->shift);
4162306a36Sopenharmony_ci	unsigned int val;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	if (mux->parent_map)
4462306a36Sopenharmony_ci		index = mux->parent_map[index].cfg;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	val = index;
4762306a36Sopenharmony_ci	val <<= mux->shift;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	return regmap_update_bits(clkr->regmap, mux->reg, mask, val);
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ciconst struct clk_ops clk_regmap_mux_closest_ops = {
5362306a36Sopenharmony_ci	.get_parent = mux_get_parent,
5462306a36Sopenharmony_ci	.set_parent = mux_set_parent,
5562306a36Sopenharmony_ci	.determine_rate = __clk_mux_determine_rate_closest,
5662306a36Sopenharmony_ci};
5762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_regmap_mux_closest_ops);
58