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