1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com> 4 * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org> 5 * 6 * Gated clock implementation 7 */ 8 9 #include <linux/clk-provider.h> 10 #include <linux/export.h> 11 #include <linux/module.h> 12 #include <linux/slab.h> 13 #include <linux/io.h> 14 #include <linux/err.h> 15 #include <linux/string.h> 16 #include "clk.h" 17 18 /** 19 * DOC: basic gateable clock which can gate and ungate its output 20 * 21 * Traits of this clock: 22 * prepare - clk_(un)prepare only ensures parent is (un)prepared 23 * enable - clk_enable and clk_disable are functional & control gating 24 * rate - inherits rate from parent. No clk_set_rate support 25 * parent - fixed parent. No clk_set_parent support 26 */ 27 28 struct clk_gate2 { 29 struct clk_hw hw; 30 void __iomem *reg; 31 u8 bit_idx; 32 u8 cgr_val; 33 u8 flags; 34 spinlock_t *lock; 35 unsigned int *share_count; 36 }; 37 38 #define to_clk_gate2(_hw) container_of(_hw, struct clk_gate2, hw) 39 40 static int clk_gate2_enable(struct clk_hw *hw) 41 { 42 struct clk_gate2 *gate = to_clk_gate2(hw); 43 u32 reg; 44 unsigned long flags; 45 int ret = 0; 46 47 spin_lock_irqsave(gate->lock, flags); 48 49 if (gate->share_count && (*gate->share_count)++ > 0) 50 goto out; 51 52 if (gate->flags & IMX_CLK_GATE2_SINGLE_BIT) { 53 ret = clk_gate_ops.enable(hw); 54 } else { 55 reg = readl(gate->reg); 56 reg &= ~(3 << gate->bit_idx); 57 reg |= gate->cgr_val << gate->bit_idx; 58 writel(reg, gate->reg); 59 } 60 61 out: 62 spin_unlock_irqrestore(gate->lock, flags); 63 64 return ret; 65 } 66 67 static void clk_gate2_disable(struct clk_hw *hw) 68 { 69 struct clk_gate2 *gate = to_clk_gate2(hw); 70 u32 reg; 71 unsigned long flags; 72 73 spin_lock_irqsave(gate->lock, flags); 74 75 if (gate->share_count) { 76 if (WARN_ON(*gate->share_count == 0)) 77 goto out; 78 else if (--(*gate->share_count) > 0) 79 goto out; 80 } 81 82 if (gate->flags & IMX_CLK_GATE2_SINGLE_BIT) { 83 clk_gate_ops.disable(hw); 84 } else { 85 reg = readl(gate->reg); 86 reg &= ~(3 << gate->bit_idx); 87 writel(reg, gate->reg); 88 } 89 90 out: 91 spin_unlock_irqrestore(gate->lock, flags); 92 } 93 94 static int clk_gate2_reg_is_enabled(void __iomem *reg, u8 bit_idx) 95 { 96 u32 val = readl(reg); 97 98 if (((val >> bit_idx) & 1) == 1) 99 return 1; 100 101 return 0; 102 } 103 104 static int clk_gate2_is_enabled(struct clk_hw *hw) 105 { 106 struct clk_gate2 *gate = to_clk_gate2(hw); 107 108 if (gate->flags & IMX_CLK_GATE2_SINGLE_BIT) 109 return clk_gate_ops.is_enabled(hw); 110 111 return clk_gate2_reg_is_enabled(gate->reg, gate->bit_idx); 112 } 113 114 static void clk_gate2_disable_unused(struct clk_hw *hw) 115 { 116 struct clk_gate2 *gate = to_clk_gate2(hw); 117 unsigned long flags; 118 u32 reg; 119 120 if (gate->flags & IMX_CLK_GATE2_SINGLE_BIT) 121 return; 122 123 spin_lock_irqsave(gate->lock, flags); 124 125 if (!gate->share_count || *gate->share_count == 0) { 126 reg = readl(gate->reg); 127 reg &= ~(3 << gate->bit_idx); 128 writel(reg, gate->reg); 129 } 130 131 spin_unlock_irqrestore(gate->lock, flags); 132 } 133 134 static const struct clk_ops clk_gate2_ops = { 135 .enable = clk_gate2_enable, 136 .disable = clk_gate2_disable, 137 .disable_unused = clk_gate2_disable_unused, 138 .is_enabled = clk_gate2_is_enabled, 139 }; 140 141 struct clk_hw *clk_hw_register_gate2(struct device *dev, const char *name, 142 const char *parent_name, unsigned long flags, 143 void __iomem *reg, u8 bit_idx, u8 cgr_val, 144 u8 clk_gate2_flags, spinlock_t *lock, 145 unsigned int *share_count) 146 { 147 struct clk_gate2 *gate; 148 struct clk_hw *hw; 149 struct clk_init_data init; 150 int ret; 151 152 gate = kzalloc(sizeof(struct clk_gate2), GFP_KERNEL); 153 if (!gate) 154 return ERR_PTR(-ENOMEM); 155 156 /* struct clk_gate2 assignments */ 157 gate->reg = reg; 158 gate->bit_idx = bit_idx; 159 gate->cgr_val = cgr_val; 160 gate->flags = clk_gate2_flags; 161 gate->lock = lock; 162 gate->share_count = share_count; 163 164 init.name = name; 165 init.ops = &clk_gate2_ops; 166 init.flags = flags; 167 init.parent_names = parent_name ? &parent_name : NULL; 168 init.num_parents = parent_name ? 1 : 0; 169 170 gate->hw.init = &init; 171 hw = &gate->hw; 172 173 ret = clk_hw_register(dev, hw); 174 if (ret) { 175 kfree(gate); 176 return ERR_PTR(ret); 177 } 178 179 return hw; 180 } 181 EXPORT_SYMBOL_GPL(clk_hw_register_gate2); 182