1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2018 MediaTek Inc. 4 * Author: Owen Chen <owen.chen@mediatek.com> 5 */ 6 7 #include <linux/of.h> 8 #include <linux/of_address.h> 9 #include <linux/slab.h> 10 #include <linux/mfd/syscon.h> 11 12 #include "clk-mtk.h" 13 #include "clk-mux.h" 14 15 static inline struct mtk_clk_mux *to_mtk_clk_mux(struct clk_hw *hw) 16 { 17 return container_of(hw, struct mtk_clk_mux, hw); 18 } 19 20 static int mtk_clk_mux_enable(struct clk_hw *hw) 21 { 22 struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); 23 u32 mask = BIT(mux->data->gate_shift); 24 25 return regmap_update_bits(mux->regmap, mux->data->mux_ofs, 26 mask, ~mask); 27 } 28 29 static void mtk_clk_mux_disable(struct clk_hw *hw) 30 { 31 struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); 32 u32 mask = BIT(mux->data->gate_shift); 33 34 regmap_update_bits(mux->regmap, mux->data->mux_ofs, mask, mask); 35 } 36 37 static int mtk_clk_mux_enable_setclr(struct clk_hw *hw) 38 { 39 struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); 40 41 return regmap_write(mux->regmap, mux->data->clr_ofs, 42 BIT(mux->data->gate_shift)); 43 } 44 45 static void mtk_clk_mux_disable_setclr(struct clk_hw *hw) 46 { 47 struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); 48 49 regmap_write(mux->regmap, mux->data->set_ofs, 50 BIT(mux->data->gate_shift)); 51 } 52 53 static int mtk_clk_mux_is_enabled(struct clk_hw *hw) 54 { 55 struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); 56 u32 val; 57 58 regmap_read(mux->regmap, mux->data->mux_ofs, &val); 59 60 return (val & BIT(mux->data->gate_shift)) == 0; 61 } 62 63 static u8 mtk_clk_mux_get_parent(struct clk_hw *hw) 64 { 65 struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); 66 u32 mask = GENMASK(mux->data->mux_width - 1, 0); 67 u32 val; 68 69 regmap_read(mux->regmap, mux->data->mux_ofs, &val); 70 val = (val >> mux->data->mux_shift) & mask; 71 72 return val; 73 } 74 75 static int mtk_clk_mux_set_parent_lock(struct clk_hw *hw, u8 index) 76 { 77 struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); 78 u32 mask = GENMASK(mux->data->mux_width - 1, 0); 79 unsigned long flags = 0; 80 81 if (mux->lock) 82 spin_lock_irqsave(mux->lock, flags); 83 else 84 __acquire(mux->lock); 85 86 regmap_update_bits(mux->regmap, mux->data->mux_ofs, mask, 87 index << mux->data->mux_shift); 88 89 if (mux->lock) 90 spin_unlock_irqrestore(mux->lock, flags); 91 else 92 __release(mux->lock); 93 94 return 0; 95 } 96 97 static int mtk_clk_mux_set_parent_setclr_lock(struct clk_hw *hw, u8 index) 98 { 99 struct mtk_clk_mux *mux = to_mtk_clk_mux(hw); 100 u32 mask = GENMASK(mux->data->mux_width - 1, 0); 101 u32 val, orig; 102 unsigned long flags = 0; 103 104 if (mux->lock) 105 spin_lock_irqsave(mux->lock, flags); 106 else 107 __acquire(mux->lock); 108 109 regmap_read(mux->regmap, mux->data->mux_ofs, &orig); 110 val = (orig & ~(mask << mux->data->mux_shift)) 111 | (index << mux->data->mux_shift); 112 113 if (val != orig) { 114 regmap_write(mux->regmap, mux->data->clr_ofs, 115 mask << mux->data->mux_shift); 116 regmap_write(mux->regmap, mux->data->set_ofs, 117 index << mux->data->mux_shift); 118 119 if (mux->data->upd_shift >= 0) 120 regmap_write(mux->regmap, mux->data->upd_ofs, 121 BIT(mux->data->upd_shift)); 122 } 123 124 if (mux->lock) 125 spin_unlock_irqrestore(mux->lock, flags); 126 else 127 __release(mux->lock); 128 129 return 0; 130 } 131 132 const struct clk_ops mtk_mux_ops = { 133 .get_parent = mtk_clk_mux_get_parent, 134 .set_parent = mtk_clk_mux_set_parent_lock, 135 }; 136 137 const struct clk_ops mtk_mux_clr_set_upd_ops = { 138 .get_parent = mtk_clk_mux_get_parent, 139 .set_parent = mtk_clk_mux_set_parent_setclr_lock, 140 }; 141 142 const struct clk_ops mtk_mux_gate_ops = { 143 .enable = mtk_clk_mux_enable, 144 .disable = mtk_clk_mux_disable, 145 .is_enabled = mtk_clk_mux_is_enabled, 146 .get_parent = mtk_clk_mux_get_parent, 147 .set_parent = mtk_clk_mux_set_parent_lock, 148 }; 149 150 const struct clk_ops mtk_mux_gate_clr_set_upd_ops = { 151 .enable = mtk_clk_mux_enable_setclr, 152 .disable = mtk_clk_mux_disable_setclr, 153 .is_enabled = mtk_clk_mux_is_enabled, 154 .get_parent = mtk_clk_mux_get_parent, 155 .set_parent = mtk_clk_mux_set_parent_setclr_lock, 156 }; 157 158 struct clk *mtk_clk_register_mux(const struct mtk_mux *mux, 159 struct regmap *regmap, 160 spinlock_t *lock) 161 { 162 struct mtk_clk_mux *clk_mux; 163 struct clk_init_data init = {}; 164 struct clk *clk; 165 166 clk_mux = kzalloc(sizeof(*clk_mux), GFP_KERNEL); 167 if (!clk_mux) 168 return ERR_PTR(-ENOMEM); 169 170 init.name = mux->name; 171 init.flags = mux->flags | CLK_SET_RATE_PARENT; 172 init.parent_names = mux->parent_names; 173 init.num_parents = mux->num_parents; 174 init.ops = mux->ops; 175 176 clk_mux->regmap = regmap; 177 clk_mux->data = mux; 178 clk_mux->lock = lock; 179 clk_mux->hw.init = &init; 180 181 clk = clk_register(NULL, &clk_mux->hw); 182 if (IS_ERR(clk)) { 183 kfree(clk_mux); 184 return clk; 185 } 186 187 return clk; 188 } 189 190 int mtk_clk_register_muxes(const struct mtk_mux *muxes, 191 int num, struct device_node *node, 192 spinlock_t *lock, 193 struct clk_onecell_data *clk_data) 194 { 195 struct regmap *regmap; 196 struct clk *clk; 197 int i; 198 199 regmap = syscon_node_to_regmap(node); 200 if (IS_ERR(regmap)) { 201 pr_err("Cannot find regmap for %pOF: %ld\n", node, 202 PTR_ERR(regmap)); 203 return PTR_ERR(regmap); 204 } 205 206 for (i = 0; i < num; i++) { 207 const struct mtk_mux *mux = &muxes[i]; 208 209 if (IS_ERR_OR_NULL(clk_data->clks[mux->id])) { 210 clk = mtk_clk_register_mux(mux, regmap, lock); 211 212 if (IS_ERR(clk)) { 213 pr_err("Failed to register clk %s: %ld\n", 214 mux->name, PTR_ERR(clk)); 215 continue; 216 } 217 218 clk_data->clks[mux->id] = clk; 219 } 220 } 221 222 return 0; 223 } 224