18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2014, The Linux Foundation. All rights reserved.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/kernel.h>
78c2ecf20Sopenharmony_ci#include <linux/bitops.h>
88c2ecf20Sopenharmony_ci#include <linux/regmap.h>
98c2ecf20Sopenharmony_ci#include <linux/export.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include "clk-regmap-mux.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistatic inline struct clk_regmap_mux *to_clk_regmap_mux(struct clk_hw *hw)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	return container_of(to_clk_regmap(hw), struct clk_regmap_mux, clkr);
168c2ecf20Sopenharmony_ci}
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic u8 mux_get_parent(struct clk_hw *hw)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	struct clk_regmap_mux *mux = to_clk_regmap_mux(hw);
218c2ecf20Sopenharmony_ci	struct clk_regmap *clkr = to_clk_regmap(hw);
228c2ecf20Sopenharmony_ci	unsigned int mask = GENMASK(mux->width - 1, 0);
238c2ecf20Sopenharmony_ci	unsigned int val;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	regmap_read(clkr->regmap, mux->reg, &val);
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci	val >>= mux->shift;
288c2ecf20Sopenharmony_ci	val &= mask;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	if (mux->parent_map)
318c2ecf20Sopenharmony_ci		return qcom_find_cfg_index(hw, mux->parent_map, val);
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	return val;
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic int mux_set_parent(struct clk_hw *hw, u8 index)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	struct clk_regmap_mux *mux = to_clk_regmap_mux(hw);
398c2ecf20Sopenharmony_ci	struct clk_regmap *clkr = to_clk_regmap(hw);
408c2ecf20Sopenharmony_ci	unsigned int mask = GENMASK(mux->width + mux->shift - 1, mux->shift);
418c2ecf20Sopenharmony_ci	unsigned int val;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	if (mux->parent_map)
448c2ecf20Sopenharmony_ci		index = mux->parent_map[index].cfg;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	val = index;
478c2ecf20Sopenharmony_ci	val <<= mux->shift;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	return regmap_update_bits(clkr->regmap, mux->reg, mask, val);
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ciconst struct clk_ops clk_regmap_mux_closest_ops = {
538c2ecf20Sopenharmony_ci	.get_parent = mux_get_parent,
548c2ecf20Sopenharmony_ci	.set_parent = mux_set_parent,
558c2ecf20Sopenharmony_ci	.determine_rate = __clk_mux_determine_rate_closest,
568c2ecf20Sopenharmony_ci};
578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_regmap_mux_closest_ops);
58