1b3ee3effSStephen Boyd /*
2b3ee3effSStephen Boyd  * Copyright (c) 2014, The Linux Foundation. All rights reserved.
3b3ee3effSStephen Boyd  *
4b3ee3effSStephen Boyd  * This software is licensed under the terms of the GNU General Public
5b3ee3effSStephen Boyd  * License version 2, as published by the Free Software Foundation, and
6b3ee3effSStephen Boyd  * may be copied, distributed, and modified under those terms.
7b3ee3effSStephen Boyd  *
8b3ee3effSStephen Boyd  * This program is distributed in the hope that it will be useful,
9b3ee3effSStephen Boyd  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10b3ee3effSStephen Boyd  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11b3ee3effSStephen Boyd  * GNU General Public License for more details.
12b3ee3effSStephen Boyd  */
13b3ee3effSStephen Boyd 
14b3ee3effSStephen Boyd #include <linux/kernel.h>
15b3ee3effSStephen Boyd #include <linux/bitops.h>
16b3ee3effSStephen Boyd #include <linux/regmap.h>
17b3ee3effSStephen Boyd #include <linux/export.h>
18b3ee3effSStephen Boyd 
19b3ee3effSStephen Boyd #include "clk-regmap-mux.h"
20b3ee3effSStephen Boyd 
21b3ee3effSStephen Boyd static inline struct clk_regmap_mux *to_clk_regmap_mux(struct clk_hw *hw)
22b3ee3effSStephen Boyd {
23b3ee3effSStephen Boyd 	return container_of(to_clk_regmap(hw), struct clk_regmap_mux, clkr);
24b3ee3effSStephen Boyd }
25b3ee3effSStephen Boyd 
26b3ee3effSStephen Boyd static u8 mux_get_parent(struct clk_hw *hw)
27b3ee3effSStephen Boyd {
28b3ee3effSStephen Boyd 	struct clk_regmap_mux *mux = to_clk_regmap_mux(hw);
29b3ee3effSStephen Boyd 	struct clk_regmap *clkr = to_clk_regmap(hw);
30b3ee3effSStephen Boyd 	unsigned int mask = GENMASK(mux->width - 1, 0);
31b3ee3effSStephen Boyd 	unsigned int val;
32b3ee3effSStephen Boyd 
33b3ee3effSStephen Boyd 	regmap_read(clkr->regmap, mux->reg, &val);
34b3ee3effSStephen Boyd 
35b3ee3effSStephen Boyd 	val >>= mux->shift;
36b3ee3effSStephen Boyd 	val &= mask;
37b3ee3effSStephen Boyd 
38df964016SAbhishek Sahu 	if (mux->parent_map)
39df964016SAbhishek Sahu 		return qcom_find_src_index(hw, mux->parent_map, val);
40df964016SAbhishek Sahu 
41b3ee3effSStephen Boyd 	return val;
42b3ee3effSStephen Boyd }
43b3ee3effSStephen Boyd 
44b3ee3effSStephen Boyd static int mux_set_parent(struct clk_hw *hw, u8 index)
45b3ee3effSStephen Boyd {
46b3ee3effSStephen Boyd 	struct clk_regmap_mux *mux = to_clk_regmap_mux(hw);
47b3ee3effSStephen Boyd 	struct clk_regmap *clkr = to_clk_regmap(hw);
48b3ee3effSStephen Boyd 	unsigned int mask = GENMASK(mux->width + mux->shift - 1, mux->shift);
49b3ee3effSStephen Boyd 	unsigned int val;
50b3ee3effSStephen Boyd 
51df964016SAbhishek Sahu 	if (mux->parent_map)
52df964016SAbhishek Sahu 		index = mux->parent_map[index].cfg;
53df964016SAbhishek Sahu 
54b3ee3effSStephen Boyd 	val = index;
55b3ee3effSStephen Boyd 	val <<= mux->shift;
56b3ee3effSStephen Boyd 
57b3ee3effSStephen Boyd 	return regmap_update_bits(clkr->regmap, mux->reg, mask, val);
58b3ee3effSStephen Boyd }
59b3ee3effSStephen Boyd 
60b3ee3effSStephen Boyd const struct clk_ops clk_regmap_mux_closest_ops = {
61b3ee3effSStephen Boyd 	.get_parent = mux_get_parent,
62b3ee3effSStephen Boyd 	.set_parent = mux_set_parent,
63b3ee3effSStephen Boyd 	.determine_rate = __clk_mux_determine_rate_closest,
64b3ee3effSStephen Boyd };
65b3ee3effSStephen Boyd EXPORT_SYMBOL_GPL(clk_regmap_mux_closest_ops);
66