linux/drivers/clk/zynqmp/clk-gate-zynqmp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Zynq UltraScale+ MPSoC clock controller
   4 *
   5 *  Copyright (C) 2016-2018 Xilinx
   6 *
   7 * Gated clock implementation
   8 */
   9
  10#include <linux/clk-provider.h>
  11#include <linux/slab.h>
  12#include "clk-zynqmp.h"
  13
  14/**
  15 * struct clk_gate - gating clock
  16 * @hw:         handle between common and hardware-specific interfaces
  17 * @flags:      hardware-specific flags
  18 * @clk_id:     Id of clock
  19 */
  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 clock
  30 * @hw:         handle between common and hardware-specific interfaces
  31 *
  32 * Return: 0 on success else error code
  33 */
  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_warn_once("%s() clock enabled failed for %s, ret = %d\n",
  45                             __func__, clk_name, ret);
  46
  47        return ret;
  48}
  49
  50/*
  51 * zynqmp_clk_gate_disable() - Disable clock
  52 * @hw:         handle between common and hardware-specific interfaces
  53 */
  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_warn_once("%s() clock disable failed for %s, ret = %d\n",
  65                             __func__, clk_name, ret);
  66}
  67
  68/**
  69 * zynqmp_clk_gate_is_enable() - Check clock state
  70 * @hw:         handle between common and hardware-specific interfaces
  71 *
  72 * Return: 1 if enabled, 0 if disabled else error code
  73 */
  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_warn_once("%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 framework
  99 * @name:               Name of this clock
 100 * @clk_id:             Id of this clock
 101 * @parents:            Name of this clock's parents
 102 * @num_parents:        Number of parents
 103 * @nodes:              Clock topology node
 104 *
 105 * Return: clock hardware of the registered clock gate
 106 */
 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