1 /* 2 * Copyright (c) 2016 Maxime Ripard. All rights reserved. 3 * 4 * This software is licensed under the terms of the GNU General Public 5 * License version 2, as published by the Free Software Foundation, and 6 * may be copied, distributed, and modified under those terms. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 */ 13 14 #ifndef _CCU_DIV_H_ 15 #define _CCU_DIV_H_ 16 17 #include <linux/clk-provider.h> 18 19 #include "ccu_common.h" 20 #include "ccu_mux.h" 21 22 /** 23 * struct _ccu_div - Internal divider description 24 * @shift: Bit offset of the divider in its register 25 * @width: Width of the divider field in its register 26 * @max: Maximum value allowed for that divider. This is the 27 * arithmetic value, not the maximum value to be set in the 28 * register. 29 * @flags: clk_divider flags to apply on this divider 30 * @table: Divider table pointer (if applicable) 31 * 32 * That structure represents a single divider, and is meant to be 33 * embedded in other structures representing the various clock 34 * classes. 35 * 36 * It is basically a wrapper around the clk_divider functions 37 * arguments. 38 */ 39 struct _ccu_div { 40 u8 shift; 41 u8 width; 42 43 u32 max; 44 45 u32 flags; 46 47 struct clk_div_table *table; 48 }; 49 50 #define _SUNXI_CCU_DIV_TABLE_FLAGS(_shift, _width, _table, _flags) \ 51 { \ 52 .shift = _shift, \ 53 .width = _width, \ 54 .flags = _flags, \ 55 .table = _table, \ 56 } 57 58 #define _SUNXI_CCU_DIV_TABLE(_shift, _width, _table) \ 59 _SUNXI_CCU_DIV_TABLE_FLAGS(_shift, _width, _table, 0) 60 61 #define _SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, _max, _flags) \ 62 { \ 63 .shift = _shift, \ 64 .width = _width, \ 65 .flags = _flags, \ 66 .max = _max, \ 67 } 68 69 #define _SUNXI_CCU_DIV_FLAGS(_shift, _width, _flags) \ 70 _SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, 0, _flags) 71 72 #define _SUNXI_CCU_DIV_MAX(_shift, _width, _max) \ 73 _SUNXI_CCU_DIV_MAX_FLAGS(_shift, _width, _max, 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 div; 82 struct ccu_mux_internal mux; 83 struct ccu_common common; 84 }; 85 86 #define SUNXI_CCU_DIV_TABLE_WITH_GATE(_struct, _name, _parent, _reg, \ 87 _shift, _width, \ 88 _table, _gate, _flags) \ 89 struct ccu_div _struct = { \ 90 .div = _SUNXI_CCU_DIV_TABLE(_shift, _width, \ 91 _table), \ 92 .enable = _gate, \ 93 .common = { \ 94 .reg = _reg, \ 95 .hw.init = CLK_HW_INIT(_name, \ 96 _parent, \ 97 &ccu_div_ops, \ 98 _flags), \ 99 } \ 100 } 101 102 103 #define SUNXI_CCU_DIV_TABLE(_struct, _name, _parent, _reg, \ 104 _shift, _width, \ 105 _table, _flags) \ 106 SUNXI_CCU_DIV_TABLE_WITH_GATE(_struct, _name, _parent, _reg, \ 107 _shift, _width, _table, 0, \ 108 _flags) 109 110 #define SUNXI_CCU_M_WITH_MUX_TABLE_GATE(_struct, _name, \ 111 _parents, _table, \ 112 _reg, \ 113 _mshift, _mwidth, \ 114 _muxshift, _muxwidth, \ 115 _gate, _flags) \ 116 struct ccu_div _struct = { \ 117 .enable = _gate, \ 118 .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \ 119 .mux = _SUNXI_CCU_MUX_TABLE(_muxshift, _muxwidth, _table), \ 120 .common = { \ 121 .reg = _reg, \ 122 .hw.init = CLK_HW_INIT_PARENTS(_name, \ 123 _parents, \ 124 &ccu_div_ops, \ 125 _flags), \ 126 }, \ 127 } 128 129 #define SUNXI_CCU_M_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ 130 _mshift, _mwidth, _muxshift, _muxwidth, \ 131 _gate, _flags) \ 132 SUNXI_CCU_M_WITH_MUX_TABLE_GATE(_struct, _name, \ 133 _parents, NULL, \ 134 _reg, _mshift, _mwidth, \ 135 _muxshift, _muxwidth, \ 136 _gate, _flags) 137 138 #define SUNXI_CCU_M_WITH_MUX(_struct, _name, _parents, _reg, \ 139 _mshift, _mwidth, _muxshift, _muxwidth, \ 140 _flags) \ 141 SUNXI_CCU_M_WITH_MUX_TABLE_GATE(_struct, _name, \ 142 _parents, NULL, \ 143 _reg, _mshift, _mwidth, \ 144 _muxshift, _muxwidth, \ 145 0, _flags) 146 147 148 #define SUNXI_CCU_M_WITH_GATE(_struct, _name, _parent, _reg, \ 149 _mshift, _mwidth, _gate, \ 150 _flags) \ 151 struct ccu_div _struct = { \ 152 .enable = _gate, \ 153 .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \ 154 .common = { \ 155 .reg = _reg, \ 156 .hw.init = CLK_HW_INIT(_name, \ 157 _parent, \ 158 &ccu_div_ops, \ 159 _flags), \ 160 }, \ 161 } 162 163 #define SUNXI_CCU_M(_struct, _name, _parent, _reg, _mshift, _mwidth, \ 164 _flags) \ 165 SUNXI_CCU_M_WITH_GATE(_struct, _name, _parent, _reg, \ 166 _mshift, _mwidth, 0, _flags) 167 168 static inline struct ccu_div *hw_to_ccu_div(struct clk_hw *hw) 169 { 170 struct ccu_common *common = hw_to_ccu_common(hw); 171 172 return container_of(common, struct ccu_div, common); 173 } 174 175 extern const struct clk_ops ccu_div_ops; 176 177 #endif /* _CCU_DIV_H_ */ 178