287 lines · c
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 description16 * @shift: Bit offset of the divider in its register17 * @width: Width of the divider field in its register18 * @max: Maximum value allowed for that divider. This is the19 * arithmetic value, not the maximum value to be set in the20 * register.21 * @flags: clk_divider flags to apply on this divider22 * @table: Divider table pointer (if applicable)23 *24 * That structure represents a single divider, and is meant to be25 * embedded in other structures representing the various clock26 * classes.27 *28 * It is basically a wrapper around the clk_divider functions29 * arguments.30 */31struct 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 78struct 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 277static 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 284extern const struct clk_ops ccu_div_ops;285 286#endif /* _CCU_DIV_H_ */287