xref: /openbmc/linux/drivers/clk/sprd/mux.c (revision ab73cf2a)
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, &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, &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