1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Copyright (c) 2024 SpacemiT Technology Co. Ltd 4 * Copyright (c) 2024-2025 Haylen Chu <heylenay@4d2.org> 5 */ 6 7 #ifndef _CCU_MIX_H_ 8 #define _CCU_MIX_H_ 9 10 #include <linux/clk-provider.h> 11 12 #include "ccu_common.h" 13 14 /** 15 * struct ccu_gate_config - Gate configuration 16 * 17 * @mask: Mask to enable the gate. Some clocks may have more than one bit 18 * set in this field. 19 * @inverted: Enable bit is inverted, 1 - disable clock, 0 - enable clock 20 */ 21 struct ccu_gate_config { 22 u32 mask; 23 bool inverted; 24 }; 25 26 struct ccu_factor_config { 27 u32 div; 28 u32 mul; 29 }; 30 31 struct ccu_mux_config { 32 u8 shift; 33 u8 width; 34 }; 35 36 struct ccu_div_config { 37 u8 shift; 38 u8 width; 39 }; 40 41 struct ccu_mix { 42 struct ccu_factor_config factor; 43 struct ccu_gate_config gate; 44 struct ccu_div_config div; 45 struct ccu_mux_config mux; 46 struct ccu_common common; 47 }; 48 49 #define CCU_GATE_INIT(_mask) { .mask = _mask } 50 #define CCU_FACTOR_INIT(_div, _mul) { .div = _div, .mul = _mul } 51 #define CCU_MUX_INIT(_shift, _width) { .shift = _shift, .width = _width } 52 #define CCU_DIV_INIT(_shift, _width) { .shift = _shift, .width = _width } 53 #define CCU_GATE_FLAGS_INIT(_mask, _inverted) { .mask = _mask, .inverted = _inverted } 54 55 #define CCU_PARENT_HW(_parent) { .hw = &_parent.common.hw } 56 #define CCU_PARENT_NAME(_name) { .fw_name = #_name } 57 58 #define CCU_MIX_INITHW(_name, _parent, _ops, _flags) \ 59 .hw.init = &(struct clk_init_data) { \ 60 .flags = _flags, \ 61 .name = #_name, \ 62 .parent_data = (const struct clk_parent_data[]) \ 63 { _parent }, \ 64 .num_parents = 1, \ 65 .ops = &_ops, \ 66 } 67 68 #define CCU_MIX_INITHW_PARENTS(_name, _parents, _ops, _flags) \ 69 .hw.init = CLK_HW_INIT_PARENTS_DATA(#_name, _parents, &_ops, _flags) 70 71 #define CCU_GATE_DEFINE(_name, _parent, _reg_ctrl, _mask_gate, _flags) \ 72 static struct ccu_mix _name = { \ 73 .gate = CCU_GATE_INIT(_mask_gate), \ 74 .common = { \ 75 .reg_ctrl = _reg_ctrl, \ 76 CCU_MIX_INITHW(_name, _parent, spacemit_ccu_gate_ops, _flags), \ 77 } \ 78 } 79 80 #define CCU_FACTOR_DEFINE(_name, _parent, _div, _mul) \ 81 static struct ccu_mix _name = { \ 82 .factor = CCU_FACTOR_INIT(_div, _mul), \ 83 .common = { \ 84 CCU_MIX_INITHW(_name, _parent, spacemit_ccu_factor_ops, 0), \ 85 } \ 86 } 87 88 #define CCU_MUX_DEFINE(_name, _parents, _reg_ctrl, _shift, _width, _flags) \ 89 static struct ccu_mix _name = { \ 90 .mux = CCU_MUX_INIT(_shift, _width), \ 91 .common = { \ 92 .reg_ctrl = _reg_ctrl, \ 93 CCU_MIX_INITHW_PARENTS(_name, _parents, spacemit_ccu_mux_ops, \ 94 _flags), \ 95 } \ 96 } 97 98 #define CCU_DIV_DEFINE(_name, _parent, _reg_ctrl, _shift, _width, _flags) \ 99 static struct ccu_mix _name = { \ 100 .div = CCU_DIV_INIT(_shift, _width), \ 101 .common = { \ 102 .reg_ctrl = _reg_ctrl, \ 103 CCU_MIX_INITHW(_name, _parent, spacemit_ccu_div_ops, _flags) \ 104 } \ 105 } 106 107 #define CCU_GATE_FLAGS_DEFINE(_name, _parent, _reg_ctrl, _mask_gate, _inverted, _flags) \ 108 static struct ccu_mix _name = { \ 109 .gate = CCU_GATE_FLAGS_INIT(_mask_gate, _inverted), \ 110 .common = { \ 111 .reg_ctrl = _reg_ctrl, \ 112 CCU_MIX_INITHW(_name, _parent, spacemit_ccu_gate_ops, _flags), \ 113 } \ 114 } 115 116 #define CCU_FACTOR_GATE_FLAGS_DEFINE(_name, _parent, _reg_ctrl, _mask_gate, _div, \ 117 _mul, _flags) \ 118 static struct ccu_mix _name = { \ 119 .gate = CCU_GATE_INIT(_mask_gate), \ 120 .factor = CCU_FACTOR_INIT(_div, _mul), \ 121 .common = { \ 122 .reg_ctrl = _reg_ctrl, \ 123 CCU_MIX_INITHW(_name, _parent, spacemit_ccu_factor_gate_ops, _flags) \ 124 } \ 125 } 126 127 #define CCU_FACTOR_GATE_DEFINE(_name, _parent, _reg_ctrl, _mask_gate, _div, \ 128 _mul) \ 129 CCU_FACTOR_GATE_FLAGS_DEFINE(_name, _parent, _reg_ctrl, _mask_gate, _div, \ 130 _mul, 0) 131 132 #define CCU_MUX_GATE_DEFINE(_name, _parents, _reg_ctrl, _shift, _width, \ 133 _mask_gate, _flags) \ 134 static struct ccu_mix _name = { \ 135 .gate = CCU_GATE_INIT(_mask_gate), \ 136 .mux = CCU_MUX_INIT(_shift, _width), \ 137 .common = { \ 138 .reg_ctrl = _reg_ctrl, \ 139 CCU_MIX_INITHW_PARENTS(_name, _parents, \ 140 spacemit_ccu_mux_gate_ops, _flags), \ 141 } \ 142 } 143 144 #define CCU_DIV_GATE_DEFINE(_name, _parent, _reg_ctrl, _shift, _width, \ 145 _mask_gate, _flags) \ 146 static struct ccu_mix _name = { \ 147 .gate = CCU_GATE_INIT(_mask_gate), \ 148 .div = CCU_DIV_INIT(_shift, _width), \ 149 .common = { \ 150 .reg_ctrl = _reg_ctrl, \ 151 CCU_MIX_INITHW(_name, _parent, spacemit_ccu_div_gate_ops, \ 152 _flags), \ 153 } \ 154 } 155 156 #define CCU_MUX_DIV_GATE_DEFINE(_name, _parents, _reg_ctrl, _mshift, _mwidth, \ 157 _muxshift, _muxwidth, _mask_gate, _flags) \ 158 static struct ccu_mix _name = { \ 159 .gate = CCU_GATE_INIT(_mask_gate), \ 160 .div = CCU_DIV_INIT(_mshift, _mwidth), \ 161 .mux = CCU_MUX_INIT(_muxshift, _muxwidth), \ 162 .common = { \ 163 .reg_ctrl = _reg_ctrl, \ 164 CCU_MIX_INITHW_PARENTS(_name, _parents, \ 165 spacemit_ccu_mux_div_gate_ops, _flags), \ 166 }, \ 167 } 168 169 #define CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(_name, _parents, _reg_ctrl, _reg_fc, \ 170 _mshift, _mwidth, _mask_fc, _muxshift, \ 171 _muxwidth, _mask_gate, _flags) \ 172 static struct ccu_mix _name = { \ 173 .gate = CCU_GATE_INIT(_mask_gate), \ 174 .div = CCU_DIV_INIT(_mshift, _mwidth), \ 175 .mux = CCU_MUX_INIT(_muxshift, _muxwidth), \ 176 .common = { \ 177 .reg_ctrl = _reg_ctrl, \ 178 .reg_fc = _reg_fc, \ 179 .mask_fc = _mask_fc, \ 180 CCU_MIX_INITHW_PARENTS(_name, _parents, \ 181 spacemit_ccu_mux_div_gate_ops, _flags), \ 182 }, \ 183 } 184 185 #define CCU_MUX_DIV_GATE_FC_DEFINE(_name, _parents, _reg_ctrl, _mshift, _mwidth,\ 186 _mask_fc, _muxshift, _muxwidth, _mask_gate, \ 187 _flags) \ 188 CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(_name, _parents, _reg_ctrl, _reg_ctrl, _mshift,\ 189 _mwidth, _mask_fc, _muxshift, _muxwidth, \ 190 _mask_gate, _flags) 191 192 #define CCU_MUX_DIV_FC_DEFINE(_name, _parents, _reg_ctrl, _mshift, _mwidth, \ 193 _mask_fc, _muxshift, _muxwidth, _flags) \ 194 static struct ccu_mix _name = { \ 195 .div = CCU_DIV_INIT(_mshift, _mwidth), \ 196 .mux = CCU_MUX_INIT(_muxshift, _muxwidth), \ 197 .common = { \ 198 .reg_ctrl = _reg_ctrl, \ 199 .reg_fc = _reg_ctrl, \ 200 .mask_fc = _mask_fc, \ 201 CCU_MIX_INITHW_PARENTS(_name, _parents, \ 202 spacemit_ccu_mux_div_ops, _flags), \ 203 }, \ 204 } 205 206 #define CCU_MUX_FC_DEFINE(_name, _parents, _reg_ctrl, _mask_fc, _muxshift, \ 207 _muxwidth, _flags) \ 208 static struct ccu_mix _name = { \ 209 .mux = CCU_MUX_INIT(_muxshift, _muxwidth), \ 210 .common = { \ 211 .reg_ctrl = _reg_ctrl, \ 212 .reg_fc = _reg_ctrl, \ 213 .mask_fc = _mask_fc, \ 214 CCU_MIX_INITHW_PARENTS(_name, _parents, spacemit_ccu_mux_ops, \ 215 _flags) \ 216 }, \ 217 } 218 219 static inline struct ccu_mix *hw_to_ccu_mix(struct clk_hw *hw) 220 { 221 struct ccu_common *common = hw_to_ccu_common(hw); 222 223 return container_of(common, struct ccu_mix, common); 224 } 225 226 extern const struct clk_ops spacemit_ccu_gate_ops; 227 extern const struct clk_ops spacemit_ccu_factor_ops; 228 extern const struct clk_ops spacemit_ccu_mux_ops; 229 extern const struct clk_ops spacemit_ccu_div_ops; 230 extern const struct clk_ops spacemit_ccu_factor_gate_ops; 231 extern const struct clk_ops spacemit_ccu_div_gate_ops; 232 extern const struct clk_ops spacemit_ccu_mux_gate_ops; 233 extern const struct clk_ops spacemit_ccu_mux_div_ops; 234 extern const struct clk_ops spacemit_ccu_mux_div_gate_ops; 235 #endif /* _CCU_MIX_H_ */ 236