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 15static 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 20static 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 29static 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 37static 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 45static 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 53static 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 63static 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 75static 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 97static 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 132const 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 137const 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 142const 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 150const 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 158struct 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 190int 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