0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/clk-provider.h>
0009 #include <linux/slab.h>
0010 #include "clk-zynqmp.h"
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029 struct zynqmp_clk_mux {
0030 struct clk_hw hw;
0031 u8 flags;
0032 u32 clk_id;
0033 };
0034
0035 #define to_zynqmp_clk_mux(_hw) container_of(_hw, struct zynqmp_clk_mux, hw)
0036
0037
0038
0039
0040
0041
0042
0043 static u8 zynqmp_clk_mux_get_parent(struct clk_hw *hw)
0044 {
0045 struct zynqmp_clk_mux *mux = to_zynqmp_clk_mux(hw);
0046 const char *clk_name = clk_hw_get_name(hw);
0047 u32 clk_id = mux->clk_id;
0048 u32 val;
0049 int ret;
0050
0051 ret = zynqmp_pm_clock_getparent(clk_id, &val);
0052
0053 if (ret) {
0054 pr_debug("%s() getparent failed for clock: %s, ret = %d\n",
0055 __func__, clk_name, ret);
0056
0057
0058
0059
0060 return clk_hw_get_num_parents(hw);
0061 }
0062
0063 return val;
0064 }
0065
0066
0067
0068
0069
0070
0071
0072
0073 static int zynqmp_clk_mux_set_parent(struct clk_hw *hw, u8 index)
0074 {
0075 struct zynqmp_clk_mux *mux = to_zynqmp_clk_mux(hw);
0076 const char *clk_name = clk_hw_get_name(hw);
0077 u32 clk_id = mux->clk_id;
0078 int ret;
0079
0080 ret = zynqmp_pm_clock_setparent(clk_id, index);
0081
0082 if (ret)
0083 pr_debug("%s() set parent failed for clock: %s, ret = %d\n",
0084 __func__, clk_name, ret);
0085
0086 return ret;
0087 }
0088
0089 static const struct clk_ops zynqmp_clk_mux_ops = {
0090 .get_parent = zynqmp_clk_mux_get_parent,
0091 .set_parent = zynqmp_clk_mux_set_parent,
0092 .determine_rate = __clk_mux_determine_rate,
0093 };
0094
0095 static const struct clk_ops zynqmp_clk_mux_ro_ops = {
0096 .get_parent = zynqmp_clk_mux_get_parent,
0097 };
0098
0099 static inline unsigned long zynqmp_clk_map_mux_ccf_flags(
0100 const u32 zynqmp_type_flag)
0101 {
0102 unsigned long ccf_flag = 0;
0103
0104 if (zynqmp_type_flag & ZYNQMP_CLK_MUX_INDEX_ONE)
0105 ccf_flag |= CLK_MUX_INDEX_ONE;
0106 if (zynqmp_type_flag & ZYNQMP_CLK_MUX_INDEX_BIT)
0107 ccf_flag |= CLK_MUX_INDEX_BIT;
0108 if (zynqmp_type_flag & ZYNQMP_CLK_MUX_HIWORD_MASK)
0109 ccf_flag |= CLK_MUX_HIWORD_MASK;
0110 if (zynqmp_type_flag & ZYNQMP_CLK_MUX_READ_ONLY)
0111 ccf_flag |= CLK_MUX_READ_ONLY;
0112 if (zynqmp_type_flag & ZYNQMP_CLK_MUX_ROUND_CLOSEST)
0113 ccf_flag |= CLK_MUX_ROUND_CLOSEST;
0114 if (zynqmp_type_flag & ZYNQMP_CLK_MUX_BIG_ENDIAN)
0115 ccf_flag |= CLK_MUX_BIG_ENDIAN;
0116
0117 return ccf_flag;
0118 }
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131 struct clk_hw *zynqmp_clk_register_mux(const char *name, u32 clk_id,
0132 const char * const *parents,
0133 u8 num_parents,
0134 const struct clock_topology *nodes)
0135 {
0136 struct zynqmp_clk_mux *mux;
0137 struct clk_hw *hw;
0138 struct clk_init_data init;
0139 int ret;
0140
0141 mux = kzalloc(sizeof(*mux), GFP_KERNEL);
0142 if (!mux)
0143 return ERR_PTR(-ENOMEM);
0144
0145 init.name = name;
0146 if (nodes->type_flag & CLK_MUX_READ_ONLY)
0147 init.ops = &zynqmp_clk_mux_ro_ops;
0148 else
0149 init.ops = &zynqmp_clk_mux_ops;
0150
0151 init.flags = zynqmp_clk_map_common_ccf_flags(nodes->flag);
0152
0153 init.parent_names = parents;
0154 init.num_parents = num_parents;
0155 mux->flags = zynqmp_clk_map_mux_ccf_flags(nodes->type_flag);
0156 mux->hw.init = &init;
0157 mux->clk_id = clk_id;
0158
0159 hw = &mux->hw;
0160 ret = clk_hw_register(NULL, hw);
0161 if (ret) {
0162 kfree(mux);
0163 hw = ERR_PTR(ret);
0164 }
0165
0166 return hw;
0167 }