1ab73cf2aSChunyan Zhang // SPDX-License-Identifier: GPL-2.0
2ab73cf2aSChunyan Zhang //
3ab73cf2aSChunyan Zhang // Spreadtrum multiplexer clock driver
4ab73cf2aSChunyan Zhang //
5ab73cf2aSChunyan Zhang // Copyright (C) 2017 Spreadtrum, Inc.
6ab73cf2aSChunyan Zhang // Author: Chunyan Zhang <chunyan.zhang@spreadtrum.com>
7ab73cf2aSChunyan Zhang
8ab73cf2aSChunyan Zhang #include <linux/clk.h>
9ab73cf2aSChunyan Zhang #include <linux/clk-provider.h>
10ab73cf2aSChunyan Zhang #include <linux/regmap.h>
11ab73cf2aSChunyan Zhang
12ab73cf2aSChunyan Zhang #include "mux.h"
13ab73cf2aSChunyan Zhang
sprd_mux_helper_get_parent(const struct sprd_clk_common * common,const struct sprd_mux_ssel * mux)14ab73cf2aSChunyan Zhang u8 sprd_mux_helper_get_parent(const struct sprd_clk_common *common,
15ab73cf2aSChunyan Zhang const struct sprd_mux_ssel *mux)
16ab73cf2aSChunyan Zhang {
17ab73cf2aSChunyan Zhang unsigned int reg;
18ab73cf2aSChunyan Zhang u8 parent;
19ab73cf2aSChunyan Zhang int num_parents;
20ab73cf2aSChunyan Zhang int i;
21ab73cf2aSChunyan Zhang
22ab73cf2aSChunyan Zhang regmap_read(common->regmap, common->reg, ®);
23ab73cf2aSChunyan Zhang parent = reg >> mux->shift;
24ab73cf2aSChunyan Zhang parent &= (1 << mux->width) - 1;
25ab73cf2aSChunyan Zhang
26ab73cf2aSChunyan Zhang if (!mux->table)
27ab73cf2aSChunyan Zhang return parent;
28ab73cf2aSChunyan Zhang
29ab73cf2aSChunyan Zhang num_parents = clk_hw_get_num_parents(&common->hw);
30ab73cf2aSChunyan Zhang
31ab73cf2aSChunyan Zhang for (i = 0; i < num_parents - 1; i++)
32ab73cf2aSChunyan Zhang if (parent >= mux->table[i] && parent < mux->table[i + 1])
33ab73cf2aSChunyan Zhang return i;
34ab73cf2aSChunyan Zhang
35ab73cf2aSChunyan Zhang return num_parents - 1;
36ab73cf2aSChunyan Zhang }
37ab73cf2aSChunyan Zhang EXPORT_SYMBOL_GPL(sprd_mux_helper_get_parent);
38ab73cf2aSChunyan Zhang
sprd_mux_get_parent(struct clk_hw * hw)39ab73cf2aSChunyan Zhang static u8 sprd_mux_get_parent(struct clk_hw *hw)
40ab73cf2aSChunyan Zhang {
41ab73cf2aSChunyan Zhang struct sprd_mux *cm = hw_to_sprd_mux(hw);
42ab73cf2aSChunyan Zhang
43ab73cf2aSChunyan Zhang return sprd_mux_helper_get_parent(&cm->common, &cm->mux);
44ab73cf2aSChunyan Zhang }
45ab73cf2aSChunyan Zhang
sprd_mux_helper_set_parent(const struct sprd_clk_common * common,const struct sprd_mux_ssel * mux,u8 index)46ab73cf2aSChunyan Zhang int sprd_mux_helper_set_parent(const struct sprd_clk_common *common,
47ab73cf2aSChunyan Zhang const struct sprd_mux_ssel *mux,
48ab73cf2aSChunyan Zhang u8 index)
49ab73cf2aSChunyan Zhang {
50ab73cf2aSChunyan Zhang unsigned int reg;
51ab73cf2aSChunyan Zhang
52ab73cf2aSChunyan Zhang if (mux->table)
53ab73cf2aSChunyan Zhang index = mux->table[index];
54ab73cf2aSChunyan Zhang
55ab73cf2aSChunyan Zhang regmap_read(common->regmap, common->reg, ®);
56ab73cf2aSChunyan Zhang reg &= ~GENMASK(mux->width + mux->shift - 1, mux->shift);
57ab73cf2aSChunyan Zhang regmap_write(common->regmap, common->reg,
58ab73cf2aSChunyan Zhang reg | (index << mux->shift));
59ab73cf2aSChunyan Zhang
60ab73cf2aSChunyan Zhang return 0;
61ab73cf2aSChunyan Zhang }
62ab73cf2aSChunyan Zhang EXPORT_SYMBOL_GPL(sprd_mux_helper_set_parent);
63ab73cf2aSChunyan Zhang
sprd_mux_set_parent(struct clk_hw * hw,u8 index)64ab73cf2aSChunyan Zhang static int sprd_mux_set_parent(struct clk_hw *hw, u8 index)
65ab73cf2aSChunyan Zhang {
66ab73cf2aSChunyan Zhang struct sprd_mux *cm = hw_to_sprd_mux(hw);
67ab73cf2aSChunyan Zhang
68ab73cf2aSChunyan Zhang return sprd_mux_helper_set_parent(&cm->common, &cm->mux, index);
69ab73cf2aSChunyan Zhang }
70ab73cf2aSChunyan Zhang
71ab73cf2aSChunyan Zhang const struct clk_ops sprd_mux_ops = {
72ab73cf2aSChunyan Zhang .get_parent = sprd_mux_get_parent,
73ab73cf2aSChunyan Zhang .set_parent = sprd_mux_set_parent,
74ab73cf2aSChunyan Zhang .determine_rate = __clk_mux_determine_rate,
75ab73cf2aSChunyan Zhang };
76ab73cf2aSChunyan Zhang EXPORT_SYMBOL_GPL(sprd_mux_ops);
77