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 */ 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_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 169static 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 176extern const struct clk_ops ccu_div_ops; 177 178#endif /* _CCU_DIV_H_ */ 179