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_M_WITH_MUX_TABLE_GATE(_struct, _name, \ 112 _parents, _table, \ 113 _reg, \ 114 _mshift, _mwidth, \ 115 _muxshift, _muxwidth, \ 116 _gate, _flags) \ 117 struct ccu_div _struct = { \ 118 .enable = _gate, \ 119 .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \ 120 .mux = _SUNXI_CCU_MUX_TABLE(_muxshift, _muxwidth, _table), \ 121 .common = { \ 122 .reg = _reg, \ 123 .hw.init = CLK_HW_INIT_PARENTS(_name, \ 124 _parents, \ 125 &ccu_div_ops, \ 126 _flags), \ 127 }, \ 128 } 129 130 #define SUNXI_CCU_M_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ 131 _mshift, _mwidth, _muxshift, _muxwidth, \ 132 _gate, _flags) \ 133 SUNXI_CCU_M_WITH_MUX_TABLE_GATE(_struct, _name, \ 134 _parents, NULL, \ 135 _reg, _mshift, _mwidth, \ 136 _muxshift, _muxwidth, \ 137 _gate, _flags) 138 139 #define SUNXI_CCU_M_WITH_MUX(_struct, _name, _parents, _reg, \ 140 _mshift, _mwidth, _muxshift, _muxwidth, \ 141 _flags) \ 142 SUNXI_CCU_M_WITH_MUX_TABLE_GATE(_struct, _name, \ 143 _parents, NULL, \ 144 _reg, _mshift, _mwidth, \ 145 _muxshift, _muxwidth, \ 146 0, _flags) 147 148 149 #define SUNXI_CCU_M_WITH_GATE(_struct, _name, _parent, _reg, \ 150 _mshift, _mwidth, _gate, \ 151 _flags) \ 152 struct ccu_div _struct = { \ 153 .enable = _gate, \ 154 .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \ 155 .common = { \ 156 .reg = _reg, \ 157 .hw.init = CLK_HW_INIT(_name, \ 158 _parent, \ 159 &ccu_div_ops, \ 160 _flags), \ 161 }, \ 162 } 163 164 #define SUNXI_CCU_M(_struct, _name, _parent, _reg, _mshift, _mwidth, \ 165 _flags) \ 166 SUNXI_CCU_M_WITH_GATE(_struct, _name, _parent, _reg, \ 167 _mshift, _mwidth, 0, _flags) 168 169 static inline struct ccu_div *hw_to_ccu_div(struct clk_hw *hw) 170 { 171 struct ccu_common *common = hw_to_ccu_common(hw); 172 173 return container_of(common, struct ccu_div, common); 174 } 175 176 extern const struct clk_ops ccu_div_ops; 177 178 #endif /* _CCU_DIV_H_ */ 179