1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Copyright (c) 2016 Maxime Ripard. All rights reserved. 4 */ 5 6 #ifndef _CCU_DIV_H_ 7 #define _CCU_DIV_H_ 8 9 #include <linux/clk-provider.h> 10 11 #include "ccu_common.h" 12 #include "ccu_mux.h" 13 14 /** 15 * struct ccu_div_internal - Internal divider description 16 * @shift: Bit offset of the divider in its register 17 * @width: Width of the divider field in its register 18 * @max: Maximum value allowed for that divider. This is the 19 * arithmetic value, not the maximum value to be set in the 20 * register. 21 * @flags: clk_divider flags to apply on this divider 22 * @table: Divider table pointer (if applicable) 23 * 24 * That structure represents a single divider, and is meant to be 25 * embedded in other structures representing the various clock 26 * classes. 27 * 28 * It is basically a wrapper around the clk_divider functions 29 * arguments. 30 */ 31 struct ccu_div_internal { 32 u8 shift; 33 u8 width; 34 35 u32 max; 36 u32 offset; 37 38 u32 flags; 39 40 struct clk_div_table *table; 41 }; 42 43 #define _SUNXI_CCU_DIV_TABLE_FLAGS(_shift, _width, _table, _flags) \ 44 { \ 45 .shift = _shift, \ 46 .width = _width, \ 47 .flags = _flags, \ 48 .table = _table, \ 49 } 50 51 #define _SUNXI_CCU_DIV_TABLE(_shift, _width, _table) \ 52 _SUNXI_CCU_DIV_TABLE_FLAGS(_shift, _width, _table, 0) 53 54 #define _SUNXI_CCU_DIV_OFFSET_MAX_FLAGS(_shift, _width, _off, _max, _flags) \ 55 { \ 56 .shift = _shift, \ 57 .width = _width, \ 58 .flags = _flags, \ 59 .max = _max, \ 60 .offset = _off, \ 61 } 62 63 #define _SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, _max, _flags) \ 64 _SUNXI_CCU_DIV_OFFSET_MAX_FLAGS(_shift, _width, 1, _max, _flags) 65 66 #define _SUNXI_CCU_DIV_FLAGS(_shift, _width, _flags) \ 67 _SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, 0, _flags) 68 69 #define _SUNXI_CCU_DIV_MAX(_shift, _width, _max) \ 70 _SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, _max, 0) 71 72 #define _SUNXI_CCU_DIV_OFFSET(_shift, _width, _offset) \ 73 _SUNXI_CCU_DIV_OFFSET_MAX_FLAGS(_shift, _width, _offset, 0, 0) 74 75 #define _SUNXI_CCU_DIV(_shift, _width) \ 76 _SUNXI_CCU_DIV_FLAGS(_shift, _width, 0) 77 78 struct ccu_div { 79 u32 enable; 80 81 struct ccu_div_internal div; 82 struct ccu_mux_internal mux; 83 struct ccu_common common; 84 unsigned int fixed_post_div; 85 }; 86 87 #define SUNXI_CCU_DIV_TABLE_WITH_GATE(_struct, _name, _parent, _reg, \ 88 _shift, _width, \ 89 _table, _gate, _flags) \ 90 struct ccu_div _struct = { \ 91 .div = _SUNXI_CCU_DIV_TABLE(_shift, _width, \ 92 _table), \ 93 .enable = _gate, \ 94 .common = { \ 95 .reg = _reg, \ 96 .hw.init = CLK_HW_INIT(_name, \ 97 _parent, \ 98 &ccu_div_ops, \ 99 _flags), \ 100 } \ 101 } 102 103 104 #define SUNXI_CCU_DIV_TABLE(_struct, _name, _parent, _reg, \ 105 _shift, _width, \ 106 _table, _flags) \ 107 SUNXI_CCU_DIV_TABLE_WITH_GATE(_struct, _name, _parent, _reg, \ 108 _shift, _width, _table, 0, \ 109 _flags) 110 111 #define SUNXI_CCU_DIV_TABLE_HW(_struct, _name, _parent, _reg, \ 112 _shift, _width, \ 113 _table, _flags) \ 114 struct ccu_div _struct = { \ 115 .div = _SUNXI_CCU_DIV_TABLE(_shift, _width, \ 116 _table), \ 117 .common = { \ 118 .reg = _reg, \ 119 .hw.init = CLK_HW_INIT_HW(_name, \ 120 _parent, \ 121 &ccu_div_ops, \ 122 _flags), \ 123 } \ 124 } 125 126 127 #define SUNXI_CCU_M_WITH_MUX_TABLE_GATE(_struct, _name, \ 128 _parents, _table, \ 129 _reg, \ 130 _mshift, _mwidth, \ 131 _muxshift, _muxwidth, \ 132 _gate, _flags) \ 133 struct ccu_div _struct = { \ 134 .enable = _gate, \ 135 .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \ 136 .mux = _SUNXI_CCU_MUX_TABLE(_muxshift, _muxwidth, _table), \ 137 .common = { \ 138 .reg = _reg, \ 139 .hw.init = CLK_HW_INIT_PARENTS(_name, \ 140 _parents, \ 141 &ccu_div_ops, \ 142 _flags), \ 143 }, \ 144 } 145 146 #define SUNXI_CCU_M_WITH_MUX_TABLE_GATE_CLOSEST(_struct, _name, \ 147 _parents, _table, \ 148 _reg, \ 149 _mshift, _mwidth, \ 150 _muxshift, _muxwidth, \ 151 _gate, _flags) \ 152 struct ccu_div _struct = { \ 153 .enable = _gate, \ 154 .div = _SUNXI_CCU_DIV_FLAGS(_mshift, _mwidth, CLK_DIVIDER_ROUND_CLOSEST), \ 155 .mux = _SUNXI_CCU_MUX_TABLE(_muxshift, _muxwidth, _table), \ 156 .common = { \ 157 .reg = _reg, \ 158 .hw.init = CLK_HW_INIT_PARENTS(_name, \ 159 _parents, \ 160 &ccu_div_ops, \ 161 _flags), \ 162 .features = CCU_FEATURE_CLOSEST_RATE, \ 163 }, \ 164 } 165 166 #define SUNXI_CCU_M_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ 167 _mshift, _mwidth, _muxshift, _muxwidth, \ 168 _gate, _flags) \ 169 SUNXI_CCU_M_WITH_MUX_TABLE_GATE(_struct, _name, \ 170 _parents, NULL, \ 171 _reg, _mshift, _mwidth, \ 172 _muxshift, _muxwidth, \ 173 _gate, _flags) 174 175 #define SUNXI_CCU_M_WITH_MUX_GATE_CLOSEST(_struct, _name, _parents, \ 176 _reg, _mshift, _mwidth, \ 177 _muxshift, _muxwidth, \ 178 _gate, _flags) \ 179 SUNXI_CCU_M_WITH_MUX_TABLE_GATE_CLOSEST(_struct, _name, \ 180 _parents, NULL, \ 181 _reg, _mshift, _mwidth, \ 182 _muxshift, _muxwidth, \ 183 _gate, _flags) 184 185 #define SUNXI_CCU_M_WITH_MUX(_struct, _name, _parents, _reg, \ 186 _mshift, _mwidth, _muxshift, _muxwidth, \ 187 _flags) \ 188 SUNXI_CCU_M_WITH_MUX_TABLE_GATE(_struct, _name, \ 189 _parents, NULL, \ 190 _reg, _mshift, _mwidth, \ 191 _muxshift, _muxwidth, \ 192 0, _flags) 193 194 195 #define SUNXI_CCU_M_WITH_GATE(_struct, _name, _parent, _reg, \ 196 _mshift, _mwidth, _gate, \ 197 _flags) \ 198 struct ccu_div _struct = { \ 199 .enable = _gate, \ 200 .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \ 201 .common = { \ 202 .reg = _reg, \ 203 .hw.init = CLK_HW_INIT(_name, \ 204 _parent, \ 205 &ccu_div_ops, \ 206 _flags), \ 207 }, \ 208 } 209 210 #define SUNXI_CCU_M(_struct, _name, _parent, _reg, _mshift, _mwidth, \ 211 _flags) \ 212 SUNXI_CCU_M_WITH_GATE(_struct, _name, _parent, _reg, \ 213 _mshift, _mwidth, 0, _flags) 214 215 #define SUNXI_CCU_M_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ 216 _mshift, _mwidth, \ 217 _muxshift, _muxwidth, \ 218 _gate, _flags) \ 219 struct ccu_div _struct = { \ 220 .enable = _gate, \ 221 .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \ 222 .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \ 223 .common = { \ 224 .reg = _reg, \ 225 .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, \ 226 _parents, \ 227 &ccu_div_ops, \ 228 _flags), \ 229 }, \ 230 } 231 232 #define SUNXI_CCU_M_DATA_WITH_MUX(_struct, _name, _parents, _reg, \ 233 _mshift, _mwidth, \ 234 _muxshift, _muxwidth, \ 235 _flags) \ 236 SUNXI_CCU_M_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ 237 _mshift, _mwidth, \ 238 _muxshift, _muxwidth, \ 239 0, _flags) 240 241 #define SUNXI_CCU_M_HW_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ 242 _mshift, _mwidth, _muxshift, _muxwidth, \ 243 _gate, _flags) \ 244 struct ccu_div _struct = { \ 245 .enable = _gate, \ 246 .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \ 247 .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \ 248 .common = { \ 249 .reg = _reg, \ 250 .hw.init = CLK_HW_INIT_PARENTS_HW(_name, \ 251 _parents, \ 252 &ccu_div_ops, \ 253 _flags), \ 254 }, \ 255 } 256 257 #define SUNXI_CCU_M_HWS_WITH_GATE(_struct, _name, _parent, _reg, \ 258 _mshift, _mwidth, _gate, \ 259 _flags) \ 260 struct ccu_div _struct = { \ 261 .enable = _gate, \ 262 .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \ 263 .common = { \ 264 .reg = _reg, \ 265 .hw.init = CLK_HW_INIT_HWS(_name, \ 266 _parent, \ 267 &ccu_div_ops, \ 268 _flags), \ 269 }, \ 270 } 271 272 #define SUNXI_CCU_M_HWS(_struct, _name, _parent, _reg, _mshift, \ 273 _mwidth, _flags) \ 274 SUNXI_CCU_M_HWS_WITH_GATE(_struct, _name, _parent, _reg, \ 275 _mshift, _mwidth, 0, _flags) 276 277 static inline struct ccu_div *hw_to_ccu_div(struct clk_hw *hw) 278 { 279 struct ccu_common *common = hw_to_ccu_common(hw); 280 281 return container_of(common, struct ccu_div, common); 282 } 283 284 extern const struct clk_ops ccu_div_ops; 285 286 #endif /* _CCU_DIV_H_ */ 287