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 */ 20 struct ccu_gate_config { 21 u32 mask; 22 }; 23 24 struct ccu_factor_config { 25 u32 div; 26 u32 mul; 27 }; 28 29 struct ccu_mux_config { 30 u8 shift; 31 u8 width; 32 }; 33 34 struct ccu_div_config { 35 u8 shift; 36 u8 width; 37 }; 38 39 struct ccu_mix { 40 struct ccu_factor_config factor; 41 struct ccu_gate_config gate; 42 struct ccu_div_config div; 43 struct ccu_mux_config mux; 44 struct ccu_common common; 45 }; 46 47 #define CCU_GATE_INIT(_mask) { .mask = _mask } 48 #define CCU_FACTOR_INIT(_div, _mul) { .div = _div, .mul = _mul } 49 #define CCU_MUX_INIT(_shift, _width) { .shift = _shift, .width = _width } 50 #define CCU_DIV_INIT(_shift, _width) { .shift = _shift, .width = _width } 51 52 #define CCU_PARENT_HW(_parent) { .hw = &_parent.common.hw } 53 #define CCU_PARENT_NAME(_name) { .fw_name = #_name } 54 55 #define CCU_MIX_INITHW(_name, _parent, _ops, _flags) \ 56 .hw.init = &(struct clk_init_data) { \ 57 .flags = _flags, \ 58 .name = #_name, \ 59 .parent_data = (const struct clk_parent_data[]) \ 60 { _parent }, \ 61 .num_parents = 1, \ 62 .ops = &_ops, \ 63 } 64 65 #define CCU_MIX_INITHW_PARENTS(_name, _parents, _ops, _flags) \ 66 .hw.init = CLK_HW_INIT_PARENTS_DATA(#_name, _parents, &_ops, _flags) 67 68 #define CCU_GATE_DEFINE(_name, _parent, _reg_ctrl, _mask_gate, _flags) \ 69 static struct ccu_mix _name = { \ 70 .gate = CCU_GATE_INIT(_mask_gate), \ 71 .common = { \ 72 .reg_ctrl = _reg_ctrl, \ 73 CCU_MIX_INITHW(_name, _parent, spacemit_ccu_gate_ops, _flags), \ 74 } \ 75 } 76 77 #define CCU_FACTOR_DEFINE(_name, _parent, _div, _mul) \ 78 static struct ccu_mix _name = { \ 79 .factor = CCU_FACTOR_INIT(_div, _mul), \ 80 .common = { \ 81 CCU_MIX_INITHW(_name, _parent, spacemit_ccu_factor_ops, 0), \ 82 } \ 83 } 84 85 #define CCU_MUX_DEFINE(_name, _parents, _reg_ctrl, _shift, _width, _flags) \ 86 static struct ccu_mix _name = { \ 87 .mux = CCU_MUX_INIT(_shift, _width), \ 88 .common = { \ 89 .reg_ctrl = _reg_ctrl, \ 90 CCU_MIX_INITHW_PARENTS(_name, _parents, spacemit_ccu_mux_ops, \ 91 _flags), \ 92 } \ 93 } 94 95 #define CCU_DIV_DEFINE(_name, _parent, _reg_ctrl, _shift, _width, _flags) \ 96 static struct ccu_mix _name = { \ 97 .div = CCU_DIV_INIT(_shift, _width), \ 98 .common = { \ 99 .reg_ctrl = _reg_ctrl, \ 100 CCU_MIX_INITHW(_name, _parent, spacemit_ccu_div_ops, _flags) \ 101 } \ 102 } 103 104 #define CCU_FACTOR_GATE_DEFINE(_name, _parent, _reg_ctrl, _mask_gate, _div, \ 105 _mul) \ 106 static struct ccu_mix _name = { \ 107 .gate = CCU_GATE_INIT(_mask_gate), \ 108 .factor = CCU_FACTOR_INIT(_div, _mul), \ 109 .common = { \ 110 .reg_ctrl = _reg_ctrl, \ 111 CCU_MIX_INITHW(_name, _parent, spacemit_ccu_factor_gate_ops, 0) \ 112 } \ 113 } 114 115 #define CCU_MUX_GATE_DEFINE(_name, _parents, _reg_ctrl, _shift, _width, \ 116 _mask_gate, _flags) \ 117 static struct ccu_mix _name = { \ 118 .gate = CCU_GATE_INIT(_mask_gate), \ 119 .mux = CCU_MUX_INIT(_shift, _width), \ 120 .common = { \ 121 .reg_ctrl = _reg_ctrl, \ 122 CCU_MIX_INITHW_PARENTS(_name, _parents, \ 123 spacemit_ccu_mux_gate_ops, _flags), \ 124 } \ 125 } 126 127 #define CCU_DIV_GATE_DEFINE(_name, _parent, _reg_ctrl, _shift, _width, \ 128 _mask_gate, _flags) \ 129 static struct ccu_mix _name = { \ 130 .gate = CCU_GATE_INIT(_mask_gate), \ 131 .div = CCU_DIV_INIT(_shift, _width), \ 132 .common = { \ 133 .reg_ctrl = _reg_ctrl, \ 134 CCU_MIX_INITHW(_name, _parent, spacemit_ccu_div_gate_ops, \ 135 _flags), \ 136 } \ 137 } 138 139 #define CCU_MUX_DIV_GATE_DEFINE(_name, _parents, _reg_ctrl, _mshift, _mwidth, \ 140 _muxshift, _muxwidth, _mask_gate, _flags) \ 141 static struct ccu_mix _name = { \ 142 .gate = CCU_GATE_INIT(_mask_gate), \ 143 .div = CCU_DIV_INIT(_mshift, _mwidth), \ 144 .mux = CCU_MUX_INIT(_muxshift, _muxwidth), \ 145 .common = { \ 146 .reg_ctrl = _reg_ctrl, \ 147 CCU_MIX_INITHW_PARENTS(_name, _parents, \ 148 spacemit_ccu_mux_div_gate_ops, _flags), \ 149 }, \ 150 } 151 152 #define CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(_name, _parents, _reg_ctrl, _reg_fc, \ 153 _mshift, _mwidth, _mask_fc, _muxshift, \ 154 _muxwidth, _mask_gate, _flags) \ 155 static struct ccu_mix _name = { \ 156 .gate = CCU_GATE_INIT(_mask_gate), \ 157 .div = CCU_DIV_INIT(_mshift, _mwidth), \ 158 .mux = CCU_MUX_INIT(_muxshift, _muxwidth), \ 159 .common = { \ 160 .reg_ctrl = _reg_ctrl, \ 161 .reg_fc = _reg_fc, \ 162 .mask_fc = _mask_fc, \ 163 CCU_MIX_INITHW_PARENTS(_name, _parents, \ 164 spacemit_ccu_mux_div_gate_ops, _flags), \ 165 }, \ 166 } 167 168 #define CCU_MUX_DIV_GATE_FC_DEFINE(_name, _parents, _reg_ctrl, _mshift, _mwidth,\ 169 _mask_fc, _muxshift, _muxwidth, _mask_gate, \ 170 _flags) \ 171 CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(_name, _parents, _reg_ctrl, _reg_ctrl, _mshift,\ 172 _mwidth, _mask_fc, _muxshift, _muxwidth, \ 173 _mask_gate, _flags) 174 175 #define CCU_MUX_DIV_FC_DEFINE(_name, _parents, _reg_ctrl, _mshift, _mwidth, \ 176 _mask_fc, _muxshift, _muxwidth, _flags) \ 177 static struct ccu_mix _name = { \ 178 .div = CCU_DIV_INIT(_mshift, _mwidth), \ 179 .mux = CCU_MUX_INIT(_muxshift, _muxwidth), \ 180 .common = { \ 181 .reg_ctrl = _reg_ctrl, \ 182 .reg_fc = _reg_ctrl, \ 183 .mask_fc = _mask_fc, \ 184 CCU_MIX_INITHW_PARENTS(_name, _parents, \ 185 spacemit_ccu_mux_div_ops, _flags), \ 186 }, \ 187 } 188 189 #define CCU_MUX_FC_DEFINE(_name, _parents, _reg_ctrl, _mask_fc, _muxshift, \ 190 _muxwidth, _flags) \ 191 static struct ccu_mix _name = { \ 192 .mux = CCU_MUX_INIT(_muxshift, _muxwidth), \ 193 .common = { \ 194 .reg_ctrl = _reg_ctrl, \ 195 .reg_fc = _reg_ctrl, \ 196 .mask_fc = _mask_fc, \ 197 CCU_MIX_INITHW_PARENTS(_name, _parents, spacemit_ccu_mux_ops, \ 198 _flags) \ 199 }, \ 200 } 201 202 static inline struct ccu_mix *hw_to_ccu_mix(struct clk_hw *hw) 203 { 204 struct ccu_common *common = hw_to_ccu_common(hw); 205 206 return container_of(common, struct ccu_mix, common); 207 } 208 209 extern const struct clk_ops spacemit_ccu_gate_ops; 210 extern const struct clk_ops spacemit_ccu_factor_ops; 211 extern const struct clk_ops spacemit_ccu_mux_ops; 212 extern const struct clk_ops spacemit_ccu_div_ops; 213 extern const struct clk_ops spacemit_ccu_factor_gate_ops; 214 extern const struct clk_ops spacemit_ccu_div_gate_ops; 215 extern const struct clk_ops spacemit_ccu_mux_gate_ops; 216 extern const struct clk_ops spacemit_ccu_mux_div_ops; 217 extern const struct clk_ops spacemit_ccu_mux_div_gate_ops; 218 #endif /* _CCU_DIV_H_ */ 219