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_GATE(_struct, _name, _parents, _reg, \ 147 _mshift, _mwidth, _muxshift, _muxwidth, \ 148 _gate, _flags) \ 149 SUNXI_CCU_M_WITH_MUX_TABLE_GATE(_struct, _name, \ 150 _parents, NULL, \ 151 _reg, _mshift, _mwidth, \ 152 _muxshift, _muxwidth, \ 153 _gate, _flags) 154 155 #define SUNXI_CCU_M_WITH_MUX(_struct, _name, _parents, _reg, \ 156 _mshift, _mwidth, _muxshift, _muxwidth, \ 157 _flags) \ 158 SUNXI_CCU_M_WITH_MUX_TABLE_GATE(_struct, _name, \ 159 _parents, NULL, \ 160 _reg, _mshift, _mwidth, \ 161 _muxshift, _muxwidth, \ 162 0, _flags) 163 164 165 #define SUNXI_CCU_M_WITH_GATE(_struct, _name, _parent, _reg, \ 166 _mshift, _mwidth, _gate, \ 167 _flags) \ 168 struct ccu_div _struct = { \ 169 .enable = _gate, \ 170 .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \ 171 .common = { \ 172 .reg = _reg, \ 173 .hw.init = CLK_HW_INIT(_name, \ 174 _parent, \ 175 &ccu_div_ops, \ 176 _flags), \ 177 }, \ 178 } 179 180 #define SUNXI_CCU_M(_struct, _name, _parent, _reg, _mshift, _mwidth, \ 181 _flags) \ 182 SUNXI_CCU_M_WITH_GATE(_struct, _name, _parent, _reg, \ 183 _mshift, _mwidth, 0, _flags) 184 185 #define SUNXI_CCU_M_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ 186 _mshift, _mwidth, \ 187 _muxshift, _muxwidth, \ 188 _gate, _flags) \ 189 struct ccu_div _struct = { \ 190 .enable = _gate, \ 191 .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \ 192 .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \ 193 .common = { \ 194 .reg = _reg, \ 195 .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, \ 196 _parents, \ 197 &ccu_div_ops, \ 198 _flags), \ 199 }, \ 200 } 201 202 #define SUNXI_CCU_M_DATA_WITH_MUX(_struct, _name, _parents, _reg, \ 203 _mshift, _mwidth, \ 204 _muxshift, _muxwidth, \ 205 _flags) \ 206 SUNXI_CCU_M_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ 207 _mshift, _mwidth, \ 208 _muxshift, _muxwidth, \ 209 0, _flags) 210 211 #define SUNXI_CCU_M_HW_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ 212 _mshift, _mwidth, _muxshift, _muxwidth, \ 213 _gate, _flags) \ 214 struct ccu_div _struct = { \ 215 .enable = _gate, \ 216 .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \ 217 .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \ 218 .common = { \ 219 .reg = _reg, \ 220 .hw.init = CLK_HW_INIT_PARENTS_HW(_name, \ 221 _parents, \ 222 &ccu_div_ops, \ 223 _flags), \ 224 }, \ 225 } 226 227 #define SUNXI_CCU_M_HWS_WITH_GATE(_struct, _name, _parent, _reg, \ 228 _mshift, _mwidth, _gate, \ 229 _flags) \ 230 struct ccu_div _struct = { \ 231 .enable = _gate, \ 232 .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \ 233 .common = { \ 234 .reg = _reg, \ 235 .hw.init = CLK_HW_INIT_HWS(_name, \ 236 _parent, \ 237 &ccu_div_ops, \ 238 _flags), \ 239 }, \ 240 } 241 242 #define SUNXI_CCU_M_HWS(_struct, _name, _parent, _reg, _mshift, \ 243 _mwidth, _flags) \ 244 SUNXI_CCU_M_HWS_WITH_GATE(_struct, _name, _parent, _reg, \ 245 _mshift, _mwidth, 0, _flags) 246 247 static inline struct ccu_div *hw_to_ccu_div(struct clk_hw *hw) 248 { 249 struct ccu_common *common = hw_to_ccu_common(hw); 250 251 return container_of(common, struct ccu_div, common); 252 } 253 254 extern const struct clk_ops ccu_div_ops; 255 256 #endif /* _CCU_DIV_H_ */ 257