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