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 "ccu.h"
10 #include "ccu_common.h"
11 #include "ccu_mux.h"
12 
13 /**
14  * struct ccu_div_internal - Internal divider description
15  * @shift: Bit offset of the divider in its register
16  * @width: Width of the divider field in its register
17  * @max: Maximum value allowed for that divider. This is the
18  *       arithmetic value, not the maximum value to be set in the
19  *       register.
20  * @flags: clk_divider flags to apply on this divider
21  * @table: Divider table pointer (if applicable)
22  *
23  * That structure represents a single divider, and is meant to be
24  * embedded in other structures representing the various clock
25  * classes.
26  *
27  * It is basically a wrapper around the clk_divider functions
28  * arguments.
29  */
30 struct ccu_div_internal
31 {
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 {
80     u32         enable;
81 
82     struct ccu_div_internal div;
83     struct ccu_mux_internal mux;
84     struct ccu_common   common;
85     unsigned int        fixed_post_div;
86 };
87 
88 #define SUNXI_CCU_DIV_TABLE_WITH_GATE(_struct, _name, _parent, _reg,    \
89                                       _shift, _width,           \
90                                       _table, _gate, _flags)        \
91 struct ccu_div _struct = {                  \
92     .div        = _SUNXI_CCU_DIV_TABLE(_shift, _width,  \
93                                        _table),     \
94                   .enable     = _gate,                \
95                                 .common = {                     \
96                                                                 .reg        = _reg,             \
97                                                                 .hw.init    = CLK_HW_INIT(_name,        \
98                                                                         _parent,      \
99                                                                         &ccu_div_ops, \
100                                                                         _flags),      \
101                                           }                           \
102 }
103 
104 
105 #define SUNXI_CCU_DIV_TABLE(_struct, _name, _parent, _reg,      \
106                             _shift, _width,             \
107                             _table, _flags)             \
108 SUNXI_CCU_DIV_TABLE_WITH_GATE(_struct, _name, _parent, _reg,    \
109                               _shift, _width, _table, 0,    \
110                               _flags)
111 
112 #define SUNXI_CCU_M_WITH_MUX_TABLE_GATE(_struct, _name,         \
113                                         _parents, _table,       \
114                                         _reg,               \
115                                         _mshift, _mwidth,       \
116                                         _muxshift, _muxwidth,       \
117                                         _gate, _flags)          \
118 struct ccu_div _struct = {                  \
119     .enable = _gate,                    \
120               .div    = _SUNXI_CCU_DIV(_mshift, _mwidth),     \
121                         .mux    = _SUNXI_CCU_MUX_TABLE(_muxshift, _muxwidth, _table), \
122                                   .common = {                     \
123                                                                   .reg        = _reg,             \
124                                                                   .hw.init    = CLK_HW_INIT_PARENTS(_name,    \
125                                                                           _parents, \
126                                                                           &ccu_div_ops, \
127                                                                           _flags),  \
128                                             },                          \
129 }
130 
131 #define SUNXI_CCU_M_WITH_MUX_GATE(_struct, _name, _parents, _reg,   \
132                                   _mshift, _mwidth, _muxshift, _muxwidth, \
133                                   _gate, _flags)            \
134 SUNXI_CCU_M_WITH_MUX_TABLE_GATE(_struct, _name,         \
135                                 _parents, NULL,         \
136                                 _reg, _mshift, _mwidth,     \
137                                 _muxshift, _muxwidth,       \
138                                 _gate, _flags)
139 
140 #define SUNXI_CCU_M_WITH_MUX(_struct, _name, _parents, _reg,        \
141                              _mshift, _mwidth, _muxshift, _muxwidth,    \
142                              _flags)                    \
143 SUNXI_CCU_M_WITH_MUX_TABLE_GATE(_struct, _name,         \
144                                 _parents, NULL,         \
145                                 _reg, _mshift, _mwidth,     \
146                                 _muxshift, _muxwidth,       \
147                                 0, _flags)
148 
149 
150 #define SUNXI_CCU_M_WITH_GATE(_struct, _name, _parent, _reg,        \
151                               _mshift, _mwidth, _gate,          \
152                               _flags)                   \
153 struct ccu_div _struct = {                  \
154     .enable = _gate,                    \
155               .div    = _SUNXI_CCU_DIV(_mshift, _mwidth),     \
156                         .common = {                     \
157                                                         .reg        = _reg,             \
158                                                         .hw.init    = CLK_HW_INIT(_name,        \
159                                                                 _parent,      \
160                                                                 &ccu_div_ops, \
161                                                                 _flags),      \
162                                   },                          \
163 }
164 
165 #define SUNXI_CCU_M(_struct, _name, _parent, _reg, _mshift, _mwidth,    \
166                     _flags)                     \
167 SUNXI_CCU_M_WITH_GATE(_struct, _name, _parent, _reg,        \
168                       _mshift, _mwidth, 0, _flags)
169 
hw_to_ccu_div(struct clk_hw * hw)170 static inline struct ccu_div *hw_to_ccu_div(struct clk_hw *hw)
171 {
172     struct ccu_common *common = hw_to_ccu_common(hw);
173 
174     return container_of(common, struct ccu_div, common);
175 }
176 
177 extern const struct clk_ops ccu_div_ops;
178 
179 #endif /* _CCU_DIV_H_ */
180