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 #ifndef __DRV_CLK_MTK_MUX_H 8 #define __DRV_CLK_MTK_MUX_H 9 10 #include <linux/notifier.h> 11 #include <linux/spinlock.h> 12 #include <linux/types.h> 13 14 struct clk; 15 struct clk_hw_onecell_data; 16 struct clk_ops; 17 struct device; 18 struct device_node; 19 20 struct mtk_mux { 21 int id; 22 const char *name; 23 const char * const *parent_names; 24 const u8 *parent_index; 25 unsigned int flags; 26 27 u32 mux_ofs; 28 u32 set_ofs; 29 u32 clr_ofs; 30 u32 upd_ofs; 31 32 u32 hwv_set_ofs; 33 u32 hwv_clr_ofs; 34 u32 hwv_sta_ofs; 35 u32 fenc_sta_mon_ofs; 36 37 u8 mux_shift; 38 u8 mux_width; 39 u8 gate_shift; 40 s8 upd_shift; 41 u8 fenc_shift; 42 43 const struct clk_ops *ops; 44 signed char num_parents; 45 }; 46 47 #define __GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, _paridx, \ 48 _num_parents, _mux_ofs, _mux_set_ofs, \ 49 _mux_clr_ofs, _shift, _width, _gate, _upd_ofs, \ 50 _upd, _flags, _ops) { \ 51 .id = _id, \ 52 .name = _name, \ 53 .mux_ofs = _mux_ofs, \ 54 .set_ofs = _mux_set_ofs, \ 55 .clr_ofs = _mux_clr_ofs, \ 56 .upd_ofs = _upd_ofs, \ 57 .mux_shift = _shift, \ 58 .mux_width = _width, \ 59 .gate_shift = _gate, \ 60 .upd_shift = _upd, \ 61 .parent_names = _parents, \ 62 .parent_index = _paridx, \ 63 .num_parents = _num_parents, \ 64 .flags = _flags, \ 65 .ops = &_ops, \ 66 } 67 68 #define GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, _mux_ofs, \ 69 _mux_set_ofs, _mux_clr_ofs, _shift, _width, \ 70 _gate, _upd_ofs, _upd, _flags, _ops) \ 71 __GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, \ 72 NULL, ARRAY_SIZE(_parents), _mux_ofs, \ 73 _mux_set_ofs, _mux_clr_ofs, _shift, _width, \ 74 _gate, _upd_ofs, _upd, _flags, _ops) \ 75 76 #define GATE_CLR_SET_UPD_FLAGS_INDEXED(_id, _name, _parents, _paridx, \ 77 _mux_ofs, _mux_set_ofs, _mux_clr_ofs, _shift, \ 78 _width, _gate, _upd_ofs, _upd, _flags, _ops) \ 79 __GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, \ 80 _paridx, ARRAY_SIZE(_paridx), _mux_ofs, \ 81 _mux_set_ofs, _mux_clr_ofs, _shift, _width, \ 82 _gate, _upd_ofs, _upd, _flags, _ops) \ 83 84 extern const struct clk_ops mtk_mux_clr_set_upd_ops; 85 extern const struct clk_ops mtk_mux_gate_clr_set_upd_ops; 86 extern const struct clk_ops mtk_mux_gate_fenc_clr_set_upd_ops; 87 extern const struct clk_ops mtk_mux_gate_hwv_fenc_clr_set_upd_ops; 88 89 #define MUX_GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, _mux_ofs, \ 90 _mux_set_ofs, _mux_clr_ofs, _shift, _width, \ 91 _gate, _upd_ofs, _upd, _flags) \ 92 GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, _mux_ofs, \ 93 _mux_set_ofs, _mux_clr_ofs, _shift, _width, \ 94 _gate, _upd_ofs, _upd, _flags, \ 95 mtk_mux_gate_clr_set_upd_ops) 96 97 #define MUX_GATE_CLR_SET_UPD_FLAGS_INDEXED(_id, _name, _parents, \ 98 _paridx, _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \ 99 _shift, _width, _gate, _upd_ofs, _upd, _flags) \ 100 GATE_CLR_SET_UPD_FLAGS_INDEXED(_id, _name, _parents, \ 101 _paridx, _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \ 102 _shift, _width, _gate, _upd_ofs, _upd, _flags, \ 103 mtk_mux_gate_clr_set_upd_ops) 104 105 #define MUX_GATE_CLR_SET_UPD(_id, _name, _parents, _mux_ofs, \ 106 _mux_set_ofs, _mux_clr_ofs, _shift, _width, \ 107 _gate, _upd_ofs, _upd) \ 108 MUX_GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, \ 109 _mux_ofs, _mux_set_ofs, _mux_clr_ofs, _shift, \ 110 _width, _gate, _upd_ofs, _upd, \ 111 CLK_SET_RATE_PARENT) 112 113 #define MUX_GATE_CLR_SET_UPD_INDEXED(_id, _name, _parents, _paridx, \ 114 _mux_ofs, _mux_set_ofs, _mux_clr_ofs, _shift, \ 115 _width, _gate, _upd_ofs, _upd) \ 116 MUX_GATE_CLR_SET_UPD_FLAGS_INDEXED(_id, _name, \ 117 _parents, _paridx, _mux_ofs, _mux_set_ofs, \ 118 _mux_clr_ofs, _shift, _width, _gate, _upd_ofs, \ 119 _upd, CLK_SET_RATE_PARENT) 120 121 #define MUX_CLR_SET_UPD(_id, _name, _parents, _mux_ofs, \ 122 _mux_set_ofs, _mux_clr_ofs, _shift, _width, \ 123 _upd_ofs, _upd) \ 124 GATE_CLR_SET_UPD_FLAGS(_id, _name, _parents, _mux_ofs, \ 125 _mux_set_ofs, _mux_clr_ofs, _shift, _width, \ 126 0, _upd_ofs, _upd, CLK_SET_RATE_PARENT, \ 127 mtk_mux_clr_set_upd_ops) 128 129 #define MUX_CLR_SET(_id, _name, _parents, _mux_ofs, \ 130 _mux_set_ofs, _mux_clr_ofs, _shift, _width) \ 131 MUX_CLR_SET_UPD(_id, _name, _parents, _mux_ofs, \ 132 _mux_set_ofs, _mux_clr_ofs, _shift, _width, 0, -1) 133 134 #define MUX_GATE_HWV_FENC_CLR_SET_UPD_FLAGS(_id, _name, _parents, \ 135 _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \ 136 _hwv_sta_ofs, _hwv_set_ofs, _hwv_clr_ofs, \ 137 _shift, _width, _gate, _upd_ofs, _upd, \ 138 _fenc_sta_mon_ofs, _fenc, _flags) { \ 139 .id = _id, \ 140 .name = _name, \ 141 .mux_ofs = _mux_ofs, \ 142 .set_ofs = _mux_set_ofs, \ 143 .clr_ofs = _mux_clr_ofs, \ 144 .hwv_sta_ofs = _hwv_sta_ofs, \ 145 .hwv_set_ofs = _hwv_set_ofs, \ 146 .hwv_clr_ofs = _hwv_clr_ofs, \ 147 .upd_ofs = _upd_ofs, \ 148 .fenc_sta_mon_ofs = _fenc_sta_mon_ofs, \ 149 .mux_shift = _shift, \ 150 .mux_width = _width, \ 151 .gate_shift = _gate, \ 152 .upd_shift = _upd, \ 153 .fenc_shift = _fenc, \ 154 .parent_names = _parents, \ 155 .num_parents = ARRAY_SIZE(_parents), \ 156 .flags = _flags, \ 157 .ops = &mtk_mux_gate_hwv_fenc_clr_set_upd_ops, \ 158 } 159 160 #define MUX_GATE_HWV_FENC_CLR_SET_UPD(_id, _name, _parents, \ 161 _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \ 162 _hwv_sta_ofs, _hwv_set_ofs, _hwv_clr_ofs, \ 163 _shift, _width, _gate, _upd_ofs, _upd, \ 164 _fenc_sta_mon_ofs, _fenc) \ 165 MUX_GATE_HWV_FENC_CLR_SET_UPD_FLAGS(_id, _name, _parents, \ 166 _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \ 167 _hwv_sta_ofs, _hwv_set_ofs, _hwv_clr_ofs, \ 168 _shift, _width, _gate, _upd_ofs, _upd, \ 169 _fenc_sta_mon_ofs, _fenc, 0) 170 171 #define MUX_GATE_FENC_CLR_SET_UPD_FLAGS(_id, _name, _parents, _paridx, \ 172 _num_parents, _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \ 173 _shift, _width, _gate, _upd_ofs, _upd, \ 174 _fenc_sta_mon_ofs, _fenc, _flags) { \ 175 .id = _id, \ 176 .name = _name, \ 177 .mux_ofs = _mux_ofs, \ 178 .set_ofs = _mux_set_ofs, \ 179 .clr_ofs = _mux_clr_ofs, \ 180 .upd_ofs = _upd_ofs, \ 181 .fenc_sta_mon_ofs = _fenc_sta_mon_ofs, \ 182 .mux_shift = _shift, \ 183 .mux_width = _width, \ 184 .gate_shift = _gate, \ 185 .upd_shift = _upd, \ 186 .fenc_shift = _fenc, \ 187 .parent_names = _parents, \ 188 .parent_index = _paridx, \ 189 .num_parents = _num_parents, \ 190 .flags = _flags, \ 191 .ops = &mtk_mux_gate_fenc_clr_set_upd_ops, \ 192 } 193 194 #define MUX_GATE_FENC_CLR_SET_UPD(_id, _name, _parents, \ 195 _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \ 196 _shift, _width, _gate, _upd_ofs, _upd, \ 197 _fenc_sta_mon_ofs, _fenc) \ 198 MUX_GATE_FENC_CLR_SET_UPD_FLAGS(_id, _name, _parents, \ 199 NULL, ARRAY_SIZE(_parents), _mux_ofs, \ 200 _mux_set_ofs, _mux_clr_ofs, _shift, \ 201 _width, _gate, _upd_ofs, _upd, \ 202 _fenc_sta_mon_ofs, _fenc, 0) 203 204 #define MUX_GATE_FENC_CLR_SET_UPD_INDEXED(_id, _name, _parents, _paridx, \ 205 _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \ 206 _shift, _width, _gate, _upd_ofs, _upd, \ 207 _fenc_sta_mon_ofs, _fenc) \ 208 MUX_GATE_FENC_CLR_SET_UPD_FLAGS(_id, _name, _parents, _paridx, \ 209 ARRAY_SIZE(_paridx), _mux_ofs, _mux_set_ofs, \ 210 _mux_clr_ofs, _shift, _width, _gate, _upd_ofs, _upd, \ 211 _fenc_sta_mon_ofs, _fenc, 0) 212 213 int mtk_clk_register_muxes(struct device *dev, 214 const struct mtk_mux *muxes, 215 int num, struct device_node *node, 216 spinlock_t *lock, 217 struct clk_hw_onecell_data *clk_data); 218 219 void mtk_clk_unregister_muxes(const struct mtk_mux *muxes, int num, 220 struct clk_hw_onecell_data *clk_data); 221 222 struct mtk_mux_nb { 223 struct notifier_block nb; 224 const struct clk_ops *ops; 225 226 u8 bypass_index; /* Which parent to temporarily use */ 227 u8 original_index; /* Set by notifier callback */ 228 }; 229 230 #define to_mtk_mux_nb(_nb) container_of(_nb, struct mtk_mux_nb, nb) 231 232 int devm_mtk_clk_mux_notifier_register(struct device *dev, struct clk *clk, 233 struct mtk_mux_nb *mux_nb); 234 235 #endif /* __DRV_CLK_MTK_MUX_H */ 236