13fde0e16SJolly Shah // SPDX-License-Identifier: GPL-2.0
23fde0e16SJolly Shah /*
33fde0e16SJolly Shah * Zynq UltraScale+ MPSoC mux
43fde0e16SJolly Shah *
53fde0e16SJolly Shah * Copyright (C) 2016-2018 Xilinx
63fde0e16SJolly Shah */
73fde0e16SJolly Shah
83fde0e16SJolly Shah #include <linux/clk-provider.h>
93fde0e16SJolly Shah #include <linux/slab.h>
103fde0e16SJolly Shah #include "clk-zynqmp.h"
113fde0e16SJolly Shah
123fde0e16SJolly Shah /*
133fde0e16SJolly Shah * DOC: basic adjustable multiplexer clock that cannot gate
143fde0e16SJolly Shah *
153fde0e16SJolly Shah * Traits of this clock:
163fde0e16SJolly Shah * prepare - clk_prepare only ensures that parents are prepared
173fde0e16SJolly Shah * enable - clk_enable only ensures that parents are enabled
183fde0e16SJolly Shah * rate - rate is only affected by parent switching. No clk_set_rate support
193fde0e16SJolly Shah * parent - parent is adjustable through clk_set_parent
203fde0e16SJolly Shah */
213fde0e16SJolly Shah
223fde0e16SJolly Shah /**
233fde0e16SJolly Shah * struct zynqmp_clk_mux - multiplexer clock
243fde0e16SJolly Shah *
253fde0e16SJolly Shah * @hw: handle between common and hardware-specific interfaces
263fde0e16SJolly Shah * @flags: hardware-specific flags
273fde0e16SJolly Shah * @clk_id: Id of clock
283fde0e16SJolly Shah */
293fde0e16SJolly Shah struct zynqmp_clk_mux {
303fde0e16SJolly Shah struct clk_hw hw;
313fde0e16SJolly Shah u8 flags;
323fde0e16SJolly Shah u32 clk_id;
333fde0e16SJolly Shah };
343fde0e16SJolly Shah
353fde0e16SJolly Shah #define to_zynqmp_clk_mux(_hw) container_of(_hw, struct zynqmp_clk_mux, hw)
363fde0e16SJolly Shah
373fde0e16SJolly Shah /**
383fde0e16SJolly Shah * zynqmp_clk_mux_get_parent() - Get parent of clock
393fde0e16SJolly Shah * @hw: handle between common and hardware-specific interfaces
403fde0e16SJolly Shah *
416c9feabcSMichal Simek * Return: Parent index on success or number of parents in case of error
423fde0e16SJolly Shah */
zynqmp_clk_mux_get_parent(struct clk_hw * hw)433fde0e16SJolly Shah static u8 zynqmp_clk_mux_get_parent(struct clk_hw *hw)
443fde0e16SJolly Shah {
453fde0e16SJolly Shah struct zynqmp_clk_mux *mux = to_zynqmp_clk_mux(hw);
463fde0e16SJolly Shah const char *clk_name = clk_hw_get_name(hw);
473fde0e16SJolly Shah u32 clk_id = mux->clk_id;
483fde0e16SJolly Shah u32 val;
493fde0e16SJolly Shah int ret;
503fde0e16SJolly Shah
5170c0d364SRajan Vaja ret = zynqmp_pm_clock_getparent(clk_id, &val);
523fde0e16SJolly Shah
536c9feabcSMichal Simek if (ret) {
544917394eSMichael Tretter pr_debug("%s() getparent failed for clock: %s, ret = %d\n",
553fde0e16SJolly Shah __func__, clk_name, ret);
566c9feabcSMichal Simek /*
576c9feabcSMichal Simek * clk_core_get_parent_by_index() takes num_parents as incorrect
586c9feabcSMichal Simek * index which is exactly what I want to return here
596c9feabcSMichal Simek */
606c9feabcSMichal Simek return clk_hw_get_num_parents(hw);
616c9feabcSMichal Simek }
623fde0e16SJolly Shah
633fde0e16SJolly Shah return val;
643fde0e16SJolly Shah }
653fde0e16SJolly Shah
663fde0e16SJolly Shah /**
673fde0e16SJolly Shah * zynqmp_clk_mux_set_parent() - Set parent of clock
683fde0e16SJolly Shah * @hw: handle between common and hardware-specific interfaces
693fde0e16SJolly Shah * @index: Parent index
703fde0e16SJolly Shah *
713fde0e16SJolly Shah * Return: 0 on success else error+reason
723fde0e16SJolly Shah */
zynqmp_clk_mux_set_parent(struct clk_hw * hw,u8 index)733fde0e16SJolly Shah static int zynqmp_clk_mux_set_parent(struct clk_hw *hw, u8 index)
743fde0e16SJolly Shah {
753fde0e16SJolly Shah struct zynqmp_clk_mux *mux = to_zynqmp_clk_mux(hw);
763fde0e16SJolly Shah const char *clk_name = clk_hw_get_name(hw);
773fde0e16SJolly Shah u32 clk_id = mux->clk_id;
783fde0e16SJolly Shah int ret;
793fde0e16SJolly Shah
8070c0d364SRajan Vaja ret = zynqmp_pm_clock_setparent(clk_id, index);
813fde0e16SJolly Shah
823fde0e16SJolly Shah if (ret)
834917394eSMichael Tretter pr_debug("%s() set parent failed for clock: %s, ret = %d\n",
843fde0e16SJolly Shah __func__, clk_name, ret);
853fde0e16SJolly Shah
863fde0e16SJolly Shah return ret;
873fde0e16SJolly Shah }
883fde0e16SJolly Shah
893fde0e16SJolly Shah static const struct clk_ops zynqmp_clk_mux_ops = {
903fde0e16SJolly Shah .get_parent = zynqmp_clk_mux_get_parent,
913fde0e16SJolly Shah .set_parent = zynqmp_clk_mux_set_parent,
92*9b2dcd1bSJay Buddhabhatti .determine_rate = __clk_mux_determine_rate_closest,
933fde0e16SJolly Shah };
943fde0e16SJolly Shah
953fde0e16SJolly Shah static const struct clk_ops zynqmp_clk_mux_ro_ops = {
963fde0e16SJolly Shah .get_parent = zynqmp_clk_mux_get_parent,
973fde0e16SJolly Shah };
983fde0e16SJolly Shah
zynqmp_clk_map_mux_ccf_flags(const u32 zynqmp_type_flag)9954530ed1SRajan Vaja static inline unsigned long zynqmp_clk_map_mux_ccf_flags(
10054530ed1SRajan Vaja const u32 zynqmp_type_flag)
10154530ed1SRajan Vaja {
10254530ed1SRajan Vaja unsigned long ccf_flag = 0;
10354530ed1SRajan Vaja
10454530ed1SRajan Vaja if (zynqmp_type_flag & ZYNQMP_CLK_MUX_INDEX_ONE)
10554530ed1SRajan Vaja ccf_flag |= CLK_MUX_INDEX_ONE;
10654530ed1SRajan Vaja if (zynqmp_type_flag & ZYNQMP_CLK_MUX_INDEX_BIT)
10754530ed1SRajan Vaja ccf_flag |= CLK_MUX_INDEX_BIT;
10854530ed1SRajan Vaja if (zynqmp_type_flag & ZYNQMP_CLK_MUX_HIWORD_MASK)
10954530ed1SRajan Vaja ccf_flag |= CLK_MUX_HIWORD_MASK;
11054530ed1SRajan Vaja if (zynqmp_type_flag & ZYNQMP_CLK_MUX_READ_ONLY)
11154530ed1SRajan Vaja ccf_flag |= CLK_MUX_READ_ONLY;
11254530ed1SRajan Vaja if (zynqmp_type_flag & ZYNQMP_CLK_MUX_ROUND_CLOSEST)
11354530ed1SRajan Vaja ccf_flag |= CLK_MUX_ROUND_CLOSEST;
11454530ed1SRajan Vaja if (zynqmp_type_flag & ZYNQMP_CLK_MUX_BIG_ENDIAN)
11554530ed1SRajan Vaja ccf_flag |= CLK_MUX_BIG_ENDIAN;
11654530ed1SRajan Vaja
11754530ed1SRajan Vaja return ccf_flag;
11854530ed1SRajan Vaja }
11954530ed1SRajan Vaja
1203fde0e16SJolly Shah /**
1213fde0e16SJolly Shah * zynqmp_clk_register_mux() - Register a mux table with the clock
1223fde0e16SJolly Shah * framework
1233fde0e16SJolly Shah * @name: Name of this clock
1243fde0e16SJolly Shah * @clk_id: Id of this clock
1253fde0e16SJolly Shah * @parents: Name of this clock's parents
1263fde0e16SJolly Shah * @num_parents: Number of parents
1273fde0e16SJolly Shah * @nodes: Clock topology node
1283fde0e16SJolly Shah *
1293fde0e16SJolly Shah * Return: clock hardware of the registered clock mux
1303fde0e16SJolly Shah */
zynqmp_clk_register_mux(const char * name,u32 clk_id,const char * const * parents,u8 num_parents,const struct clock_topology * nodes)1313fde0e16SJolly Shah struct clk_hw *zynqmp_clk_register_mux(const char *name, u32 clk_id,
1323fde0e16SJolly Shah const char * const *parents,
1333fde0e16SJolly Shah u8 num_parents,
1343fde0e16SJolly Shah const struct clock_topology *nodes)
1353fde0e16SJolly Shah {
1363fde0e16SJolly Shah struct zynqmp_clk_mux *mux;
1373fde0e16SJolly Shah struct clk_hw *hw;
1383fde0e16SJolly Shah struct clk_init_data init;
1393fde0e16SJolly Shah int ret;
1403fde0e16SJolly Shah
1413fde0e16SJolly Shah mux = kzalloc(sizeof(*mux), GFP_KERNEL);
1423fde0e16SJolly Shah if (!mux)
1433fde0e16SJolly Shah return ERR_PTR(-ENOMEM);
1443fde0e16SJolly Shah
1453fde0e16SJolly Shah init.name = name;
1463fde0e16SJolly Shah if (nodes->type_flag & CLK_MUX_READ_ONLY)
1473fde0e16SJolly Shah init.ops = &zynqmp_clk_mux_ro_ops;
1483fde0e16SJolly Shah else
1493fde0e16SJolly Shah init.ops = &zynqmp_clk_mux_ops;
150610a5d83SRajan Vaja
151610a5d83SRajan Vaja init.flags = zynqmp_clk_map_common_ccf_flags(nodes->flag);
152610a5d83SRajan Vaja
1533fde0e16SJolly Shah init.parent_names = parents;
1543fde0e16SJolly Shah init.num_parents = num_parents;
15554530ed1SRajan Vaja mux->flags = zynqmp_clk_map_mux_ccf_flags(nodes->type_flag);
1563fde0e16SJolly Shah mux->hw.init = &init;
1573fde0e16SJolly Shah mux->clk_id = clk_id;
1583fde0e16SJolly Shah
1593fde0e16SJolly Shah hw = &mux->hw;
1603fde0e16SJolly Shah ret = clk_hw_register(NULL, hw);
1613fde0e16SJolly Shah if (ret) {
162e7296d16SShubhrajyoti Datta kfree(mux);
1633fde0e16SJolly Shah hw = ERR_PTR(ret);
1643fde0e16SJolly Shah }
1653fde0e16SJolly Shah
1663fde0e16SJolly Shah return hw;
1673fde0e16SJolly Shah }
168