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 u32 mtk_get_clockgating(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 return val & BIT(cg->bit); 27 } 28 29 static int mtk_cg_bit_is_cleared(struct clk_hw *hw) 30 { 31 return mtk_get_clockgating(hw) == 0; 32 } 33 34 static int mtk_cg_bit_is_set(struct clk_hw *hw) 35 { 36 return mtk_get_clockgating(hw) != 0; 37 } 38 39 static void mtk_cg_set_bit(struct clk_hw *hw) 40 { 41 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); 42 43 regmap_write(cg->regmap, cg->set_ofs, BIT(cg->bit)); 44 } 45 46 static void mtk_cg_clr_bit(struct clk_hw *hw) 47 { 48 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); 49 50 regmap_write(cg->regmap, cg->clr_ofs, BIT(cg->bit)); 51 } 52 53 static void mtk_cg_set_bit_no_setclr(struct clk_hw *hw) 54 { 55 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); 56 57 regmap_set_bits(cg->regmap, cg->sta_ofs, BIT(cg->bit)); 58 } 59 60 static void mtk_cg_clr_bit_no_setclr(struct clk_hw *hw) 61 { 62 struct mtk_clk_gate *cg = to_mtk_clk_gate(hw); 63 64 regmap_clear_bits(cg->regmap, cg->sta_ofs, BIT(cg->bit)); 65 } 66 67 static int mtk_cg_enable(struct clk_hw *hw) 68 { 69 mtk_cg_clr_bit(hw); 70 71 return 0; 72 } 73 74 static void mtk_cg_disable(struct clk_hw *hw) 75 { 76 mtk_cg_set_bit(hw); 77 } 78 79 static int mtk_cg_enable_inv(struct clk_hw *hw) 80 { 81 mtk_cg_set_bit(hw); 82 83 return 0; 84 } 85 86 static void mtk_cg_disable_inv(struct clk_hw *hw) 87 { 88 mtk_cg_clr_bit(hw); 89 } 90 91 static int mtk_cg_enable_no_setclr(struct clk_hw *hw) 92 { 93 mtk_cg_clr_bit_no_setclr(hw); 94 95 return 0; 96 } 97 98 static void mtk_cg_disable_no_setclr(struct clk_hw *hw) 99 { 100 mtk_cg_set_bit_no_setclr(hw); 101 } 102 103 static int mtk_cg_enable_inv_no_setclr(struct clk_hw *hw) 104 { 105 mtk_cg_set_bit_no_setclr(hw); 106 107 return 0; 108 } 109 110 static void mtk_cg_disable_inv_no_setclr(struct clk_hw *hw) 111 { 112 mtk_cg_clr_bit_no_setclr(hw); 113 } 114 115 const struct clk_ops mtk_clk_gate_ops_setclr = { 116 .is_enabled = mtk_cg_bit_is_cleared, 117 .enable = mtk_cg_enable, 118 .disable = mtk_cg_disable, 119 }; 120 EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_setclr); 121 122 const struct clk_ops mtk_clk_gate_ops_setclr_inv = { 123 .is_enabled = mtk_cg_bit_is_set, 124 .enable = mtk_cg_enable_inv, 125 .disable = mtk_cg_disable_inv, 126 }; 127 EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_setclr_inv); 128 129 const struct clk_ops mtk_clk_gate_ops_no_setclr = { 130 .is_enabled = mtk_cg_bit_is_cleared, 131 .enable = mtk_cg_enable_no_setclr, 132 .disable = mtk_cg_disable_no_setclr, 133 }; 134 EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_no_setclr); 135 136 const struct clk_ops mtk_clk_gate_ops_no_setclr_inv = { 137 .is_enabled = mtk_cg_bit_is_set, 138 .enable = mtk_cg_enable_inv_no_setclr, 139 .disable = mtk_cg_disable_inv_no_setclr, 140 }; 141 EXPORT_SYMBOL_GPL(mtk_clk_gate_ops_no_setclr_inv); 142 143 struct clk *mtk_clk_register_gate( 144 const char *name, 145 const char *parent_name, 146 struct regmap *regmap, 147 int set_ofs, 148 int clr_ofs, 149 int sta_ofs, 150 u8 bit, 151 const struct clk_ops *ops, 152 unsigned long flags, 153 struct device *dev) 154 { 155 struct mtk_clk_gate *cg; 156 struct clk *clk; 157 struct clk_init_data init = {}; 158 159 cg = kzalloc(sizeof(*cg), GFP_KERNEL); 160 if (!cg) 161 return ERR_PTR(-ENOMEM); 162 163 init.name = name; 164 init.flags = flags | CLK_SET_RATE_PARENT; 165 init.parent_names = parent_name ? &parent_name : NULL; 166 init.num_parents = parent_name ? 1 : 0; 167 init.ops = ops; 168 169 cg->regmap = regmap; 170 cg->set_ofs = set_ofs; 171 cg->clr_ofs = clr_ofs; 172 cg->sta_ofs = sta_ofs; 173 cg->bit = bit; 174 175 cg->hw.init = &init; 176 177 clk = clk_register(dev, &cg->hw); 178 if (IS_ERR(clk)) 179 kfree(cg); 180 181 return clk; 182 } 183 EXPORT_SYMBOL_GPL(mtk_clk_register_gate); 184 185 MODULE_LICENSE("GPL"); 186