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_GATE_HWV_FENC_CLR_SET_UPD_FLAGS(_id, _name, _parents, \ 130 _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \ 131 _hwv_sta_ofs, _hwv_set_ofs, _hwv_clr_ofs, \ 132 _shift, _width, _gate, _upd_ofs, _upd, \ 133 _fenc_sta_mon_ofs, _fenc, _flags) { \ 134 .id = _id, \ 135 .name = _name, \ 136 .mux_ofs = _mux_ofs, \ 137 .set_ofs = _mux_set_ofs, \ 138 .clr_ofs = _mux_clr_ofs, \ 139 .hwv_sta_ofs = _hwv_sta_ofs, \ 140 .hwv_set_ofs = _hwv_set_ofs, \ 141 .hwv_clr_ofs = _hwv_clr_ofs, \ 142 .upd_ofs = _upd_ofs, \ 143 .fenc_sta_mon_ofs = _fenc_sta_mon_ofs, \ 144 .mux_shift = _shift, \ 145 .mux_width = _width, \ 146 .gate_shift = _gate, \ 147 .upd_shift = _upd, \ 148 .fenc_shift = _fenc, \ 149 .parent_names = _parents, \ 150 .num_parents = ARRAY_SIZE(_parents), \ 151 .flags = _flags, \ 152 .ops = &mtk_mux_gate_hwv_fenc_clr_set_upd_ops, \ 153 } 154 155 #define MUX_GATE_HWV_FENC_CLR_SET_UPD(_id, _name, _parents, \ 156 _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \ 157 _hwv_sta_ofs, _hwv_set_ofs, _hwv_clr_ofs, \ 158 _shift, _width, _gate, _upd_ofs, _upd, \ 159 _fenc_sta_mon_ofs, _fenc) \ 160 MUX_GATE_HWV_FENC_CLR_SET_UPD_FLAGS(_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, 0) 165 166 #define MUX_GATE_FENC_CLR_SET_UPD_FLAGS(_id, _name, _parents, _paridx, \ 167 _num_parents, _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \ 168 _shift, _width, _gate, _upd_ofs, _upd, \ 169 _fenc_sta_mon_ofs, _fenc, _flags) { \ 170 .id = _id, \ 171 .name = _name, \ 172 .mux_ofs = _mux_ofs, \ 173 .set_ofs = _mux_set_ofs, \ 174 .clr_ofs = _mux_clr_ofs, \ 175 .upd_ofs = _upd_ofs, \ 176 .fenc_sta_mon_ofs = _fenc_sta_mon_ofs, \ 177 .mux_shift = _shift, \ 178 .mux_width = _width, \ 179 .gate_shift = _gate, \ 180 .upd_shift = _upd, \ 181 .fenc_shift = _fenc, \ 182 .parent_names = _parents, \ 183 .parent_index = _paridx, \ 184 .num_parents = _num_parents, \ 185 .flags = _flags, \ 186 .ops = &mtk_mux_gate_fenc_clr_set_upd_ops, \ 187 } 188 189 #define MUX_GATE_FENC_CLR_SET_UPD(_id, _name, _parents, \ 190 _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \ 191 _shift, _width, _gate, _upd_ofs, _upd, \ 192 _fenc_sta_mon_ofs, _fenc) \ 193 MUX_GATE_FENC_CLR_SET_UPD_FLAGS(_id, _name, _parents, \ 194 NULL, ARRAY_SIZE(_parents), _mux_ofs, \ 195 _mux_set_ofs, _mux_clr_ofs, _shift, \ 196 _width, _gate, _upd_ofs, _upd, \ 197 _fenc_sta_mon_ofs, _fenc, 0) 198 199 #define MUX_GATE_FENC_CLR_SET_UPD_INDEXED(_id, _name, _parents, _paridx, \ 200 _mux_ofs, _mux_set_ofs, _mux_clr_ofs, \ 201 _shift, _width, _gate, _upd_ofs, _upd, \ 202 _fenc_sta_mon_ofs, _fenc) \ 203 MUX_GATE_FENC_CLR_SET_UPD_FLAGS(_id, _name, _parents, _paridx, \ 204 ARRAY_SIZE(_paridx), _mux_ofs, _mux_set_ofs, \ 205 _mux_clr_ofs, _shift, _width, _gate, _upd_ofs, _upd, \ 206 _fenc_sta_mon_ofs, _fenc, 0) 207 208 int mtk_clk_register_muxes(struct device *dev, 209 const struct mtk_mux *muxes, 210 int num, struct device_node *node, 211 spinlock_t *lock, 212 struct clk_hw_onecell_data *clk_data); 213 214 void mtk_clk_unregister_muxes(const struct mtk_mux *muxes, int num, 215 struct clk_hw_onecell_data *clk_data); 216 217 struct mtk_mux_nb { 218 struct notifier_block nb; 219 const struct clk_ops *ops; 220 221 u8 bypass_index; /* Which parent to temporarily use */ 222 u8 original_index; /* Set by notifier callback */ 223 }; 224 225 #define to_mtk_mux_nb(_nb) container_of(_nb, struct mtk_mux_nb, nb) 226 227 int devm_mtk_clk_mux_notifier_register(struct device *dev, struct clk *clk, 228 struct mtk_mux_nb *mux_nb); 229 230 #endif /* __DRV_CLK_MTK_MUX_H */ 231