Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Zynq UltraScale+ MPSoC mux
0004  *
0005  *  Copyright (C) 2016-2018 Xilinx
0006  */
0007 
0008 #include <linux/clk-provider.h>
0009 #include <linux/slab.h>
0010 #include "clk-zynqmp.h"
0011 
0012 /*
0013  * DOC: basic adjustable multiplexer clock that cannot gate
0014  *
0015  * Traits of this clock:
0016  * prepare - clk_prepare only ensures that parents are prepared
0017  * enable - clk_enable only ensures that parents are enabled
0018  * rate - rate is only affected by parent switching.  No clk_set_rate support
0019  * parent - parent is adjustable through clk_set_parent
0020  */
0021 
0022 /**
0023  * struct zynqmp_clk_mux - multiplexer clock
0024  *
0025  * @hw:     handle between common and hardware-specific interfaces
0026  * @flags:  hardware-specific flags
0027  * @clk_id: Id of clock
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  * zynqmp_clk_mux_get_parent() - Get parent of clock
0039  * @hw:     handle between common and hardware-specific interfaces
0040  *
0041  * Return: Parent index on success or number of parents in case of error
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          * clk_core_get_parent_by_index() takes num_parents as incorrect
0058          * index which is exactly what I want to return here
0059          */
0060         return clk_hw_get_num_parents(hw);
0061     }
0062 
0063     return val;
0064 }
0065 
0066 /**
0067  * zynqmp_clk_mux_set_parent() - Set parent of clock
0068  * @hw:     handle between common and hardware-specific interfaces
0069  * @index:  Parent index
0070  *
0071  * Return: 0 on success else error+reason
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  * zynqmp_clk_register_mux() - Register a mux table with the clock
0122  *                 framework
0123  * @name:       Name of this clock
0124  * @clk_id:     Id of this clock
0125  * @parents:        Name of this clock's parents
0126  * @num_parents:    Number of parents
0127  * @nodes:      Clock topology node
0128  *
0129  * Return: clock hardware of the registered clock mux
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 }