13fde0e16SJolly Shah // SPDX-License-Identifier: GPL-2.0
23fde0e16SJolly Shah /*
33fde0e16SJolly Shah * Zynq UltraScale+ MPSoC clock controller
43fde0e16SJolly Shah *
53fde0e16SJolly Shah * Copyright (C) 2016-2018 Xilinx
63fde0e16SJolly Shah *
73fde0e16SJolly Shah * Gated clock implementation
83fde0e16SJolly Shah */
93fde0e16SJolly Shah
103fde0e16SJolly Shah #include <linux/clk-provider.h>
113fde0e16SJolly Shah #include <linux/slab.h>
123fde0e16SJolly Shah #include "clk-zynqmp.h"
133fde0e16SJolly Shah
143fde0e16SJolly Shah /**
156e1cc688SMichal Simek * struct zynqmp_clk_gate - gating clock
163fde0e16SJolly Shah * @hw: handle between common and hardware-specific interfaces
173fde0e16SJolly Shah * @flags: hardware-specific flags
183fde0e16SJolly Shah * @clk_id: Id of clock
193fde0e16SJolly Shah */
203fde0e16SJolly Shah struct zynqmp_clk_gate {
213fde0e16SJolly Shah struct clk_hw hw;
223fde0e16SJolly Shah u8 flags;
233fde0e16SJolly Shah u32 clk_id;
243fde0e16SJolly Shah };
253fde0e16SJolly Shah
263fde0e16SJolly Shah #define to_zynqmp_clk_gate(_hw) container_of(_hw, struct zynqmp_clk_gate, hw)
273fde0e16SJolly Shah
283fde0e16SJolly Shah /**
293fde0e16SJolly Shah * zynqmp_clk_gate_enable() - Enable clock
303fde0e16SJolly Shah * @hw: handle between common and hardware-specific interfaces
313fde0e16SJolly Shah *
323fde0e16SJolly Shah * Return: 0 on success else error code
333fde0e16SJolly Shah */
zynqmp_clk_gate_enable(struct clk_hw * hw)343fde0e16SJolly Shah static int zynqmp_clk_gate_enable(struct clk_hw *hw)
353fde0e16SJolly Shah {
363fde0e16SJolly Shah struct zynqmp_clk_gate *gate = to_zynqmp_clk_gate(hw);
373fde0e16SJolly Shah const char *clk_name = clk_hw_get_name(hw);
383fde0e16SJolly Shah u32 clk_id = gate->clk_id;
393fde0e16SJolly Shah int ret;
403fde0e16SJolly Shah
413637e84cSRajan Vaja ret = zynqmp_pm_clock_enable(clk_id);
423fde0e16SJolly Shah
433fde0e16SJolly Shah if (ret)
444917394eSMichael Tretter pr_debug("%s() clock enable failed for %s (id %d), ret = %d\n",
454917394eSMichael Tretter __func__, clk_name, clk_id, ret);
463fde0e16SJolly Shah
473fde0e16SJolly Shah return ret;
483fde0e16SJolly Shah }
493fde0e16SJolly Shah
503fde0e16SJolly Shah /*
513fde0e16SJolly Shah * zynqmp_clk_gate_disable() - Disable clock
523fde0e16SJolly Shah * @hw: handle between common and hardware-specific interfaces
533fde0e16SJolly Shah */
zynqmp_clk_gate_disable(struct clk_hw * hw)543fde0e16SJolly Shah static void zynqmp_clk_gate_disable(struct clk_hw *hw)
553fde0e16SJolly Shah {
563fde0e16SJolly Shah struct zynqmp_clk_gate *gate = to_zynqmp_clk_gate(hw);
573fde0e16SJolly Shah const char *clk_name = clk_hw_get_name(hw);
583fde0e16SJolly Shah u32 clk_id = gate->clk_id;
593fde0e16SJolly Shah int ret;
603fde0e16SJolly Shah
61f5ccd54bSRajan Vaja ret = zynqmp_pm_clock_disable(clk_id);
623fde0e16SJolly Shah
633fde0e16SJolly Shah if (ret)
644917394eSMichael Tretter pr_debug("%s() clock disable failed for %s (id %d), ret = %d\n",
654917394eSMichael Tretter __func__, clk_name, clk_id, ret);
663fde0e16SJolly Shah }
673fde0e16SJolly Shah
683fde0e16SJolly Shah /**
696e1cc688SMichal Simek * zynqmp_clk_gate_is_enabled() - Check clock state
703fde0e16SJolly Shah * @hw: handle between common and hardware-specific interfaces
713fde0e16SJolly Shah *
723fde0e16SJolly Shah * Return: 1 if enabled, 0 if disabled else error code
733fde0e16SJolly Shah */
zynqmp_clk_gate_is_enabled(struct clk_hw * hw)743fde0e16SJolly Shah static int zynqmp_clk_gate_is_enabled(struct clk_hw *hw)
753fde0e16SJolly Shah {
763fde0e16SJolly Shah struct zynqmp_clk_gate *gate = to_zynqmp_clk_gate(hw);
773fde0e16SJolly Shah const char *clk_name = clk_hw_get_name(hw);
783fde0e16SJolly Shah u32 clk_id = gate->clk_id;
793fde0e16SJolly Shah int state, ret;
803fde0e16SJolly Shah
815e76731dSRajan Vaja ret = zynqmp_pm_clock_getstate(clk_id, &state);
823fde0e16SJolly Shah if (ret) {
834917394eSMichael Tretter pr_debug("%s() clock get state failed for %s, ret = %d\n",
843fde0e16SJolly Shah __func__, clk_name, ret);
853fde0e16SJolly Shah return -EIO;
863fde0e16SJolly Shah }
873fde0e16SJolly Shah
883fde0e16SJolly Shah return state ? 1 : 0;
893fde0e16SJolly Shah }
903fde0e16SJolly Shah
913fde0e16SJolly Shah static const struct clk_ops zynqmp_clk_gate_ops = {
923fde0e16SJolly Shah .enable = zynqmp_clk_gate_enable,
933fde0e16SJolly Shah .disable = zynqmp_clk_gate_disable,
943fde0e16SJolly Shah .is_enabled = zynqmp_clk_gate_is_enabled,
953fde0e16SJolly Shah };
963fde0e16SJolly Shah
973fde0e16SJolly Shah /**
983fde0e16SJolly Shah * zynqmp_clk_register_gate() - Register a gate clock with the clock framework
993fde0e16SJolly Shah * @name: Name of this clock
1003fde0e16SJolly Shah * @clk_id: Id of this clock
1013fde0e16SJolly Shah * @parents: Name of this clock's parents
1023fde0e16SJolly Shah * @num_parents: Number of parents
1033fde0e16SJolly Shah * @nodes: Clock topology node
1043fde0e16SJolly Shah *
1053fde0e16SJolly Shah * Return: clock hardware of the registered clock gate
1063fde0e16SJolly Shah */
zynqmp_clk_register_gate(const char * name,u32 clk_id,const char * const * parents,u8 num_parents,const struct clock_topology * nodes)1073fde0e16SJolly Shah struct clk_hw *zynqmp_clk_register_gate(const char *name, u32 clk_id,
1083fde0e16SJolly Shah const char * const *parents,
1093fde0e16SJolly Shah u8 num_parents,
1103fde0e16SJolly Shah const struct clock_topology *nodes)
1113fde0e16SJolly Shah {
1123fde0e16SJolly Shah struct zynqmp_clk_gate *gate;
1133fde0e16SJolly Shah struct clk_hw *hw;
1143fde0e16SJolly Shah int ret;
1153fde0e16SJolly Shah struct clk_init_data init;
1163fde0e16SJolly Shah
1173fde0e16SJolly Shah /* allocate the gate */
1183fde0e16SJolly Shah gate = kzalloc(sizeof(*gate), GFP_KERNEL);
1193fde0e16SJolly Shah if (!gate)
1203fde0e16SJolly Shah return ERR_PTR(-ENOMEM);
1213fde0e16SJolly Shah
1223fde0e16SJolly Shah init.name = name;
1233fde0e16SJolly Shah init.ops = &zynqmp_clk_gate_ops;
124610a5d83SRajan Vaja
125610a5d83SRajan Vaja init.flags = zynqmp_clk_map_common_ccf_flags(nodes->flag);
126610a5d83SRajan Vaja
1273fde0e16SJolly Shah init.parent_names = parents;
1283fde0e16SJolly Shah init.num_parents = 1;
1293fde0e16SJolly Shah
1303fde0e16SJolly Shah /* struct clk_gate assignments */
1313fde0e16SJolly Shah gate->flags = nodes->type_flag;
1323fde0e16SJolly Shah gate->hw.init = &init;
1333fde0e16SJolly Shah gate->clk_id = clk_id;
1343fde0e16SJolly Shah
1353fde0e16SJolly Shah hw = &gate->hw;
1363fde0e16SJolly Shah ret = clk_hw_register(NULL, hw);
1373fde0e16SJolly Shah if (ret) {
1383fde0e16SJolly Shah kfree(gate);
1393fde0e16SJolly Shah hw = ERR_PTR(ret);
1403fde0e16SJolly Shah }
1413fde0e16SJolly Shah
1423fde0e16SJolly Shah return hw;
1433fde0e16SJolly Shah }
144