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(*mux), GFP_KERNEL); 138 if (!mux) 139 return ERR_PTR(-ENOMEM); 140 141 init.name = name; 142 if (clk_mux_flags & CLK_MUX_READ_ONLY) 143 init.ops = &clk_mux_ro_ops; 144 else 145 init.ops = &clk_mux_ops; 146 init.flags = flags | CLK_IS_BASIC; 147 init.parent_names = parent_names; 148 init.num_parents = num_parents; 149 150 /* struct clk_mux assignments */ 151 mux->reg = reg; 152 mux->shift = shift; 153 mux->mask = mask; 154 mux->flags = clk_mux_flags; 155 mux->lock = lock; 156 mux->table = table; 157 mux->hw.init = &init; 158 159 hw = &mux->hw; 160 ret = clk_hw_register(dev, hw); 161 if (ret) { 162 kfree(mux); 163 hw = ERR_PTR(ret); 164 } 165 166 return hw; 167 } 168 EXPORT_SYMBOL_GPL(clk_hw_register_mux_table); 169 170 struct clk *clk_register_mux_table(struct device *dev, const char *name, 171 const char * const *parent_names, u8 num_parents, 172 unsigned long flags, 173 void __iomem *reg, u8 shift, u32 mask, 174 u8 clk_mux_flags, u32 *table, spinlock_t *lock) 175 { 176 struct clk_hw *hw; 177 178 hw = clk_hw_register_mux_table(dev, name, parent_names, num_parents, 179 flags, reg, shift, mask, clk_mux_flags, 180 table, lock); 181 if (IS_ERR(hw)) 182 return ERR_CAST(hw); 183 return hw->clk; 184 } 185 EXPORT_SYMBOL_GPL(clk_register_mux_table); 186 187 struct clk *clk_register_mux(struct device *dev, const char *name, 188 const char * const *parent_names, u8 num_parents, 189 unsigned long flags, 190 void __iomem *reg, u8 shift, u8 width, 191 u8 clk_mux_flags, spinlock_t *lock) 192 { 193 u32 mask = BIT(width) - 1; 194 195 return clk_register_mux_table(dev, name, parent_names, num_parents, 196 flags, reg, shift, mask, clk_mux_flags, 197 NULL, lock); 198 } 199 EXPORT_SYMBOL_GPL(clk_register_mux); 200 201 struct clk_hw *clk_hw_register_mux(struct device *dev, const char *name, 202 const char * const *parent_names, u8 num_parents, 203 unsigned long flags, 204 void __iomem *reg, u8 shift, u8 width, 205 u8 clk_mux_flags, spinlock_t *lock) 206 { 207 u32 mask = BIT(width) - 1; 208 209 return clk_hw_register_mux_table(dev, name, parent_names, num_parents, 210 flags, reg, shift, mask, clk_mux_flags, 211 NULL, lock); 212 } 213 EXPORT_SYMBOL_GPL(clk_hw_register_mux); 214 215 void clk_unregister_mux(struct clk *clk) 216 { 217 struct clk_mux *mux; 218 struct clk_hw *hw; 219 220 hw = __clk_get_hw(clk); 221 if (!hw) 222 return; 223 224 mux = to_clk_mux(hw); 225 226 clk_unregister(clk); 227 kfree(mux); 228 } 229 EXPORT_SYMBOL_GPL(clk_unregister_mux); 230 231 void clk_hw_unregister_mux(struct clk_hw *hw) 232 { 233 struct clk_mux *mux; 234 235 mux = to_clk_mux(hw); 236 237 clk_hw_unregister(hw); 238 kfree(mux); 239 } 240 EXPORT_SYMBOL_GPL(clk_hw_unregister_mux); 241