1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2014 MediaTek Inc. 4 * Author: James Liao <jamesjj.liao@mediatek.com> 5 */ 6 7 #include <linux/of.h> 8 #include <linux/of_address.h> 9 10 #include <linux/io.h> 11 #include <linux/slab.h> 12 #include <linux/delay.h> 13 #include <linux/clkdev.h> 14 #include <linux/module.h> 15 16 #include "clk-mtk.h" 17 #include "clk-gate.h" 18 19 static int mtk_cg_bit_is_cleared(struct clk_hw *hw) 20 { 21 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); 22 u32 val; 23 24 regmap_read(cg->regmap, cg->sta_ofs, &val); 25 26 val &= BIT(cg->bit); 27 28 return val == 0; 29 } 30 31 static int mtk_cg_bit_is_set(struct clk_hw *hw) 32 { 33 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); 34 u32 val; 35 36 regmap_read(cg->regmap, cg->sta_ofs, &val); 37 38 val &= BIT(cg->bit); 39 40 return val != 0; 41 } 42 43 static void mtk_cg_set_bit(struct clk_hw *hw) 44 { 45 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); 46 47 regmap_write(cg->regmap, cg->set_ofs, BIT(cg->bit)); 48 } 49 50 static void mtk_cg_clr_bit(struct clk_hw *hw) 51 { 52 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); 53 54 regmap_write(cg->regmap, cg->clr_ofs, BIT(cg->bit)); 55 } 56 57 static void mtk_cg_set_bit_no_setclr(struct clk_hw *hw) 58 { 59 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); 60 u32 cgbit = BIT(cg->bit); 61 62 regmap_update_bits(cg->regmap, cg->sta_ofs, cgbit, cgbit); 63 } 64 65 static void mtk_cg_clr_bit_no_setclr(struct clk_hw *hw) 66 { 67 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); 68 u32 cgbit = BIT(cg->bit); 69 70 regmap_update_bits(cg->regmap, cg->sta_ofs, cgbit, 0); 71 } 72 73 static int mtk_cg_enable(struct clk_hw *hw) 74 { 75 mtk_cg_clr_bit(hw); 76 77 return 0; 78 } 79 80 static void mtk_cg_disable(struct clk_hw *hw) 81 { 82 mtk_cg_set_bit(hw); 83 } 84 85 static int mtk_cg_enable_inv(struct clk_hw *hw) 86 { 87 mtk_cg_set_bit(hw); 88 89 return 0; 90 } 91 92 static void mtk_cg_disable_inv(struct clk_hw *hw) 93 { 94 mtk_cg_clr_bit(hw); 95 } 96 97 static int mtk_cg_enable_no_setclr(struct clk_hw *hw) 98 { 99 mtk_cg_clr_bit_no_setclr(hw); 100 101 return 0; 102 } 103 104 static void mtk_cg_disable_no_setclr(struct clk_hw *hw) 105 { 106 mtk_cg_set_bit_no_setclr(hw); 107 } 108 109 static int mtk_cg_enable_inv_no_setclr(struct clk_hw *hw) 110 { 111 mtk_cg_set_bit_no_setclr(hw); 112 113 return 0; 114 } 115 116 static void mtk_cg_disable_inv_no_setclr(struct clk_hw *hw) 117 { 118 mtk_cg_clr_bit_no_setclr(hw); 119 } 120 121 const struct clk_ops mtk_clk_gate_ops_setclr = { 122 .is_enabled = mtk_cg_bit_is_cleared, 123 .enable = mtk_cg_enable, 124 .disable = mtk_cg_disable, 125 }; 126 EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_setclr); 127 128 const struct clk_ops mtk_clk_gate_ops_setclr_inv = { 129 .is_enabled = mtk_cg_bit_is_set, 130 .enable = mtk_cg_enable_inv, 131 .disable = mtk_cg_disable_inv, 132 }; 133 EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_setclr_inv); 134 135 const struct clk_ops mtk_clk_gate_ops_no_setclr = { 136 .is_enabled = mtk_cg_bit_is_cleared, 137 .enable = mtk_cg_enable_no_setclr, 138 .disable = mtk_cg_disable_no_setclr, 139 }; 140 EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_no_setclr); 141 142 const struct clk_ops mtk_clk_gate_ops_no_setclr_inv = { 143 .is_enabled = mtk_cg_bit_is_set, 144 .enable = mtk_cg_enable_inv_no_setclr, 145 .disable = mtk_cg_disable_inv_no_setclr, 146 }; 147 EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_no_setclr_inv); 148 149 struct clk *mtk_clk_register_gate( 150 const char *name, 151 const char *parent_name, 152 struct regmap *regmap, 153 int set_ofs, 154 int clr_ofs, 155 int sta_ofs, 156 u8 bit, 157 const struct clk_ops *ops, 158 unsigned long flags, 159 struct device *dev) 160 { 161 struct mtk_clk_gate *cg; 162 struct clk *clk; 163 struct clk_init_data init = {}; 164 165 cg = kzalloc(sizeof(*cg), GFP_KERNEL); 166 if (!cg) 167 return ERR_PTR(-ENOMEM); 168 169 init.name = name; 170 init.flags = flags | CLK_SET_RATE_PARENT; 171 init.parent_names = parent_name ? &parent_name : NULL; 172 init.num_parents = parent_name ? 1 : 0; 173 init.ops = ops; 174 175 cg->regmap = regmap; 176 cg->set_ofs = set_ofs; 177 cg->clr_ofs = clr_ofs; 178 cg->sta_ofs = sta_ofs; 179 cg->bit = bit; 180 181 cg->hw.init = &init; 182 183 clk = clk_register(dev, &cg->hw); 184 if (IS_ERR(clk)) 185 kfree(cg); 186 187 return clk; 188 } 189 EXPORT_SYMBOL_GPL(mtk_clk_register_gate); 190 191 MODULE_LICENSE("GPL"); 192