1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> 4 * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org> 5 * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org> 6 * 7 * Simple multiplexer clock implementation 8 */ 9 10 #include <linux/clk-provider.h> 11 #include <linux/module.h> 12 #include <linux/slab.h> 13 #include <linux/io.h> 14 #include <linux/err.h> 15 16 /* 17 * DOC: basic adjustable multiplexer clock that cannot gate 18 * 19 * Traits of this clock: 20 * prepare - clk_prepare only ensures that parents are prepared 21 * enable - clk_enable only ensures that parents are enabled 22 * rate - rate is only affected by parent switching. No clk_set_rate support 23 * parent - parent is adjustable through clk_set_parent 24 */ 25 26 int clk_mux_val_to_index(struct clk_hw *hw, u32 *table, unsigned int flags, 27 unsigned int val) 28 { 29 int num_parents = clk_hw_get_num_parents(hw); 30 31 if (table) { 32 int i; 33 34 for (i = 0; i < num_parents; i++) 35 if (table[i] == val) 36 return i; 37 return -EINVAL; 38 } 39 40 if (val && (flags & CLK_MUX_INDEX_BIT)) 41 val = ffs(val) - 1; 42 43 if (val && (flags & CLK_MUX_INDEX_ONE)) 44 val--; 45 46 if (val >= num_parents) 47 return -EINVAL; 48 49 return val; 50 } 51 EXPORT_SYMBOL_GPL(clk_mux_val_to_index); 52 53 unsigned int clk_mux_index_to_val(u32 *table, unsigned int flags, u8 index) 54 { 55 unsigned int val = index; 56 57 if (table) { 58 val = table[index]; 59 } else { 60 if (flags & CLK_MUX_INDEX_BIT) 61 val = 1 << index; 62 63 if (flags & CLK_MUX_INDEX_ONE) 64 val++; 65 } 66 67 return val; 68 } 69 EXPORT_SYMBOL_GPL(clk_mux_index_to_val); 70 71 static u8 clk_mux_get_parent(struct clk_hw *hw) 72 { 73 struct clk_mux *mux = to_clk_mux(hw); 74 u32 val; 75 76 val = clk_readl(mux->reg) >> mux->shift; 77 val &= mux->mask; 78 79 return clk_mux_val_to_index(hw, mux->table, mux->flags, val); 80 } 81 82 static int clk_mux_set_parent(struct clk_hw *hw, u8 index) 83 { 84 struct clk_mux *mux = to_clk_mux(hw); 85 u32 val = clk_mux_index_to_val(mux->table, mux->flags, index); 86 unsigned long flags = 0; 87 u32 reg; 88 89 if (mux->lock) 90 spin_lock_irqsave(mux->lock, flags); 91 else 92 __acquire(mux->lock); 93 94 if (mux->flags & CLK_MUX_HIWORD_MASK) { 95 reg = mux->mask << (mux->shift + 16); 96 } else { 97 reg = clk_readl(mux->reg); 98 reg &= ~(mux->mask << mux->shift); 99 } 100 val = val << mux->shift; 101 reg |= val; 102 clk_writel(reg, mux->reg); 103 104 if (mux->lock) 105 spin_unlock_irqrestore(mux->lock, flags); 106 else 107 __release(mux->lock); 108 109 return 0; 110 } 111 112 static int clk_mux_determine_rate(struct clk_hw *hw, 113 struct clk_rate_request *req) 114 { 115 struct clk_mux *mux = to_clk_mux(hw); 116 117 return clk_mux_determine_rate_flags(hw, req, mux->flags); 118 } 119 120 const struct clk_ops clk_mux_ops = { 121 .get_parent = clk_mux_get_parent, 122 .set_parent = clk_mux_set_parent, 123 .determine_rate = clk_mux_determine_rate, 124 }; 125 EXPORT_SYMBOL_GPL(clk_mux_ops); 126 127 const struct clk_ops clk_mux_ro_ops = { 128 .get_parent = clk_mux_get_parent, 129 }; 130 EXPORT_SYMBOL_GPL(clk_mux_ro_ops); 131 132 struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name, 133 const char * const *parent_names, u8 num_parents, 134 unsigned long flags, 135 void __iomem *reg, u8 shift, u32 mask, 136 u8 clk_mux_flags, u32 *table, spinlock_t *lock) 137 { 138 struct clk_mux *mux; 139 struct clk_hw *hw; 140 struct clk_init_data init; 141 u8 width = 0; 142 int ret; 143 144 if (clk_mux_flags & CLK_MUX_HIWORD_MASK) { 145 width = fls(mask) - ffs(mask) + 1; 146 if (width + shift > 16) { 147 pr_err("mux value exceeds LOWORD field\n"); 148 return ERR_PTR(-EINVAL); 149 } 150 } 151 152 /* allocate the mux */ 153 mux = kzalloc(sizeof(*mux), GFP_KERNEL); 154 if (!mux) 155 return ERR_PTR(-ENOMEM); 156 157 init.name = name; 158 if (clk_mux_flags & CLK_MUX_READ_ONLY) 159 init.ops = &clk_mux_ro_ops; 160 else 161 init.ops = &clk_mux_ops; 162 init.flags = flags | CLK_IS_BASIC; 163 init.parent_names = parent_names; 164 init.num_parents = num_parents; 165 166 /* struct clk_mux assignments */ 167 mux->reg = reg; 168 mux->shift = shift; 169 mux->mask = mask; 170 mux->flags = clk_mux_flags; 171 mux->lock = lock; 172 mux->table = table; 173 mux->hw.init = &init; 174 175 hw = &mux->hw; 176 ret = clk_hw_register(dev, hw); 177 if (ret) { 178 kfree(mux); 179 hw = ERR_PTR(ret); 180 } 181 182 return hw; 183 } 184 EXPORT_SYMBOL_GPL(clk_hw_register_mux_table); 185 186 struct clk *clk_register_mux_table(struct device *dev, const char *name, 187 const char * const *parent_names, u8 num_parents, 188 unsigned long flags, 189 void __iomem *reg, u8 shift, u32 mask, 190 u8 clk_mux_flags, u32 *table, spinlock_t *lock) 191 { 192 struct clk_hw *hw; 193 194 hw = clk_hw_register_mux_table(dev, name, parent_names, num_parents, 195 flags, reg, shift, mask, clk_mux_flags, 196 table, lock); 197 if (IS_ERR(hw)) 198 return ERR_CAST(hw); 199 return hw->clk; 200 } 201 EXPORT_SYMBOL_GPL(clk_register_mux_table); 202 203 struct clk *clk_register_mux(struct device *dev, const char *name, 204 const char * const *parent_names, u8 num_parents, 205 unsigned long flags, 206 void __iomem *reg, u8 shift, u8 width, 207 u8 clk_mux_flags, spinlock_t *lock) 208 { 209 u32 mask = BIT(width) - 1; 210 211 return clk_register_mux_table(dev, name, parent_names, num_parents, 212 flags, reg, shift, mask, clk_mux_flags, 213 NULL, lock); 214 } 215 EXPORT_SYMBOL_GPL(clk_register_mux); 216 217 struct clk_hw *clk_hw_register_mux(struct device *dev, const char *name, 218 const char * const *parent_names, u8 num_parents, 219 unsigned long flags, 220 void __iomem *reg, u8 shift, u8 width, 221 u8 clk_mux_flags, spinlock_t *lock) 222 { 223 u32 mask = BIT(width) - 1; 224 225 return clk_hw_register_mux_table(dev, name, parent_names, num_parents, 226 flags, reg, shift, mask, clk_mux_flags, 227 NULL, lock); 228 } 229 EXPORT_SYMBOL_GPL(clk_hw_register_mux); 230 231 void clk_unregister_mux(struct clk *clk) 232 { 233 struct clk_mux *mux; 234 struct clk_hw *hw; 235 236 hw = __clk_get_hw(clk); 237 if (!hw) 238 return; 239 240 mux = to_clk_mux(hw); 241 242 clk_unregister(clk); 243 kfree(mux); 244 } 245 EXPORT_SYMBOL_GPL(clk_unregister_mux); 246 247 void clk_hw_unregister_mux(struct clk_hw *hw) 248 { 249 struct clk_mux *mux; 250 251 mux = to_clk_mux(hw); 252 253 clk_hw_unregister(hw); 254 kfree(mux); 255 } 256 EXPORT_SYMBOL_GPL(clk_hw_unregister_mux); 257