144 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Zynq UltraScale+ MPSoC clock controller4 *5 * Copyright (C) 2016-2018 Xilinx6 *7 * Gated clock implementation8 */9 10#include <linux/clk-provider.h>11#include <linux/slab.h>12#include "clk-zynqmp.h"13 14/**15 * struct zynqmp_clk_gate - gating clock16 * @hw: handle between common and hardware-specific interfaces17 * @flags: hardware-specific flags18 * @clk_id: Id of clock19 */20struct zynqmp_clk_gate {21 struct clk_hw hw;22 u8 flags;23 u32 clk_id;24};25 26#define to_zynqmp_clk_gate(_hw) container_of(_hw, struct zynqmp_clk_gate, hw)27 28/**29 * zynqmp_clk_gate_enable() - Enable clock30 * @hw: handle between common and hardware-specific interfaces31 *32 * Return: 0 on success else error code33 */34static int zynqmp_clk_gate_enable(struct clk_hw *hw)35{36 struct zynqmp_clk_gate *gate = to_zynqmp_clk_gate(hw);37 const char *clk_name = clk_hw_get_name(hw);38 u32 clk_id = gate->clk_id;39 int ret;40 41 ret = zynqmp_pm_clock_enable(clk_id);42 43 if (ret)44 pr_debug("%s() clock enable failed for %s (id %d), ret = %d\n",45 __func__, clk_name, clk_id, ret);46 47 return ret;48}49 50/*51 * zynqmp_clk_gate_disable() - Disable clock52 * @hw: handle between common and hardware-specific interfaces53 */54static void zynqmp_clk_gate_disable(struct clk_hw *hw)55{56 struct zynqmp_clk_gate *gate = to_zynqmp_clk_gate(hw);57 const char *clk_name = clk_hw_get_name(hw);58 u32 clk_id = gate->clk_id;59 int ret;60 61 ret = zynqmp_pm_clock_disable(clk_id);62 63 if (ret)64 pr_debug("%s() clock disable failed for %s (id %d), ret = %d\n",65 __func__, clk_name, clk_id, ret);66}67 68/**69 * zynqmp_clk_gate_is_enabled() - Check clock state70 * @hw: handle between common and hardware-specific interfaces71 *72 * Return: 1 if enabled, 0 if disabled else error code73 */74static int zynqmp_clk_gate_is_enabled(struct clk_hw *hw)75{76 struct zynqmp_clk_gate *gate = to_zynqmp_clk_gate(hw);77 const char *clk_name = clk_hw_get_name(hw);78 u32 clk_id = gate->clk_id;79 int state, ret;80 81 ret = zynqmp_pm_clock_getstate(clk_id, &state);82 if (ret) {83 pr_debug("%s() clock get state failed for %s, ret = %d\n",84 __func__, clk_name, ret);85 return -EIO;86 }87 88 return state ? 1 : 0;89}90 91static const struct clk_ops zynqmp_clk_gate_ops = {92 .enable = zynqmp_clk_gate_enable,93 .disable = zynqmp_clk_gate_disable,94 .is_enabled = zynqmp_clk_gate_is_enabled,95};96 97/**98 * zynqmp_clk_register_gate() - Register a gate clock with the clock framework99 * @name: Name of this clock100 * @clk_id: Id of this clock101 * @parents: Name of this clock's parents102 * @num_parents: Number of parents103 * @nodes: Clock topology node104 *105 * Return: clock hardware of the registered clock gate106 */107struct clk_hw *zynqmp_clk_register_gate(const char *name, u32 clk_id,108 const char * const *parents,109 u8 num_parents,110 const struct clock_topology *nodes)111{112 struct zynqmp_clk_gate *gate;113 struct clk_hw *hw;114 int ret;115 struct clk_init_data init;116 117 /* allocate the gate */118 gate = kzalloc(sizeof(*gate), GFP_KERNEL);119 if (!gate)120 return ERR_PTR(-ENOMEM);121 122 init.name = name;123 init.ops = &zynqmp_clk_gate_ops;124 125 init.flags = zynqmp_clk_map_common_ccf_flags(nodes->flag);126 127 init.parent_names = parents;128 init.num_parents = 1;129 130 /* struct clk_gate assignments */131 gate->flags = nodes->type_flag;132 gate->hw.init = &init;133 gate->clk_id = clk_id;134 135 hw = &gate->hw;136 ret = clk_hw_register(NULL, hw);137 if (ret) {138 kfree(gate);139 hw = ERR_PTR(ret);140 }141 142 return hw;143}144