xref: /OK3568_Linux_fs/kernel/drivers/clk/zynqmp/clk-mux-zynqmp.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Zynq UltraScale+ MPSoC mux
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  Copyright (C) 2016-2018 Xilinx
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/clk-provider.h>
9*4882a593Smuzhiyun #include <linux/slab.h>
10*4882a593Smuzhiyun #include "clk-zynqmp.h"
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun /*
13*4882a593Smuzhiyun  * DOC: basic adjustable multiplexer clock that cannot gate
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  * Traits of this clock:
16*4882a593Smuzhiyun  * prepare - clk_prepare only ensures that parents are prepared
17*4882a593Smuzhiyun  * enable - clk_enable only ensures that parents are enabled
18*4882a593Smuzhiyun  * rate - rate is only affected by parent switching.  No clk_set_rate support
19*4882a593Smuzhiyun  * parent - parent is adjustable through clk_set_parent
20*4882a593Smuzhiyun  */
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun /**
23*4882a593Smuzhiyun  * struct zynqmp_clk_mux - multiplexer clock
24*4882a593Smuzhiyun  *
25*4882a593Smuzhiyun  * @hw:		handle between common and hardware-specific interfaces
26*4882a593Smuzhiyun  * @flags:	hardware-specific flags
27*4882a593Smuzhiyun  * @clk_id:	Id of clock
28*4882a593Smuzhiyun  */
29*4882a593Smuzhiyun struct zynqmp_clk_mux {
30*4882a593Smuzhiyun 	struct clk_hw hw;
31*4882a593Smuzhiyun 	u8 flags;
32*4882a593Smuzhiyun 	u32 clk_id;
33*4882a593Smuzhiyun };
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun #define to_zynqmp_clk_mux(_hw) container_of(_hw, struct zynqmp_clk_mux, hw)
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun /**
38*4882a593Smuzhiyun  * zynqmp_clk_mux_get_parent() - Get parent of clock
39*4882a593Smuzhiyun  * @hw:		handle between common and hardware-specific interfaces
40*4882a593Smuzhiyun  *
41*4882a593Smuzhiyun  * Return: Parent index
42*4882a593Smuzhiyun  */
zynqmp_clk_mux_get_parent(struct clk_hw * hw)43*4882a593Smuzhiyun static u8 zynqmp_clk_mux_get_parent(struct clk_hw *hw)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun 	struct zynqmp_clk_mux *mux = to_zynqmp_clk_mux(hw);
46*4882a593Smuzhiyun 	const char *clk_name = clk_hw_get_name(hw);
47*4882a593Smuzhiyun 	u32 clk_id = mux->clk_id;
48*4882a593Smuzhiyun 	u32 val;
49*4882a593Smuzhiyun 	int ret;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	ret = zynqmp_pm_clock_getparent(clk_id, &val);
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	if (ret)
54*4882a593Smuzhiyun 		pr_warn_once("%s() getparent failed for clock: %s, ret = %d\n",
55*4882a593Smuzhiyun 			     __func__, clk_name, ret);
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	return val;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun /**
61*4882a593Smuzhiyun  * zynqmp_clk_mux_set_parent() - Set parent of clock
62*4882a593Smuzhiyun  * @hw:		handle between common and hardware-specific interfaces
63*4882a593Smuzhiyun  * @index:	Parent index
64*4882a593Smuzhiyun  *
65*4882a593Smuzhiyun  * Return: 0 on success else error+reason
66*4882a593Smuzhiyun  */
zynqmp_clk_mux_set_parent(struct clk_hw * hw,u8 index)67*4882a593Smuzhiyun static int zynqmp_clk_mux_set_parent(struct clk_hw *hw, u8 index)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun 	struct zynqmp_clk_mux *mux = to_zynqmp_clk_mux(hw);
70*4882a593Smuzhiyun 	const char *clk_name = clk_hw_get_name(hw);
71*4882a593Smuzhiyun 	u32 clk_id = mux->clk_id;
72*4882a593Smuzhiyun 	int ret;
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	ret = zynqmp_pm_clock_setparent(clk_id, index);
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	if (ret)
77*4882a593Smuzhiyun 		pr_warn_once("%s() set parent failed for clock: %s, ret = %d\n",
78*4882a593Smuzhiyun 			     __func__, clk_name, ret);
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	return ret;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun static const struct clk_ops zynqmp_clk_mux_ops = {
84*4882a593Smuzhiyun 	.get_parent = zynqmp_clk_mux_get_parent,
85*4882a593Smuzhiyun 	.set_parent = zynqmp_clk_mux_set_parent,
86*4882a593Smuzhiyun 	.determine_rate = __clk_mux_determine_rate,
87*4882a593Smuzhiyun };
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun static const struct clk_ops zynqmp_clk_mux_ro_ops = {
90*4882a593Smuzhiyun 	.get_parent = zynqmp_clk_mux_get_parent,
91*4882a593Smuzhiyun };
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun /**
94*4882a593Smuzhiyun  * zynqmp_clk_register_mux() - Register a mux table with the clock
95*4882a593Smuzhiyun  *			       framework
96*4882a593Smuzhiyun  * @name:		Name of this clock
97*4882a593Smuzhiyun  * @clk_id:		Id of this clock
98*4882a593Smuzhiyun  * @parents:		Name of this clock's parents
99*4882a593Smuzhiyun  * @num_parents:	Number of parents
100*4882a593Smuzhiyun  * @nodes:		Clock topology node
101*4882a593Smuzhiyun  *
102*4882a593Smuzhiyun  * Return: clock hardware of the registered clock mux
103*4882a593Smuzhiyun  */
zynqmp_clk_register_mux(const char * name,u32 clk_id,const char * const * parents,u8 num_parents,const struct clock_topology * nodes)104*4882a593Smuzhiyun struct clk_hw *zynqmp_clk_register_mux(const char *name, u32 clk_id,
105*4882a593Smuzhiyun 				       const char * const *parents,
106*4882a593Smuzhiyun 				       u8 num_parents,
107*4882a593Smuzhiyun 				       const struct clock_topology *nodes)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun 	struct zynqmp_clk_mux *mux;
110*4882a593Smuzhiyun 	struct clk_hw *hw;
111*4882a593Smuzhiyun 	struct clk_init_data init;
112*4882a593Smuzhiyun 	int ret;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
115*4882a593Smuzhiyun 	if (!mux)
116*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	init.name = name;
119*4882a593Smuzhiyun 	if (nodes->type_flag & CLK_MUX_READ_ONLY)
120*4882a593Smuzhiyun 		init.ops = &zynqmp_clk_mux_ro_ops;
121*4882a593Smuzhiyun 	else
122*4882a593Smuzhiyun 		init.ops = &zynqmp_clk_mux_ops;
123*4882a593Smuzhiyun 	init.flags = nodes->flag;
124*4882a593Smuzhiyun 	init.parent_names = parents;
125*4882a593Smuzhiyun 	init.num_parents = num_parents;
126*4882a593Smuzhiyun 	mux->flags = nodes->type_flag;
127*4882a593Smuzhiyun 	mux->hw.init = &init;
128*4882a593Smuzhiyun 	mux->clk_id = clk_id;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	hw = &mux->hw;
131*4882a593Smuzhiyun 	ret = clk_hw_register(NULL, hw);
132*4882a593Smuzhiyun 	if (ret) {
133*4882a593Smuzhiyun 		kfree(hw);
134*4882a593Smuzhiyun 		hw = ERR_PTR(ret);
135*4882a593Smuzhiyun 	}
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	return hw;
138*4882a593Smuzhiyun }
139