1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Copyright (c) 2016 Maxime Ripard. All rights reserved.
4  */
5 
6 #ifndef _CCU_MP_H_
7 #define _CCU_MP_H_
8 
9 #include <linux/bitops.h>
10 #include <linux/clk-provider.h>
11 
12 #include "ccu_common.h"
13 #include "ccu_div.h"
14 #include "ccu_mult.h"
15 #include "ccu_mux.h"
16 
17 /*
18  * struct ccu_mp - Definition of an M-P clock
19  *
20  * Clocks based on the formula parent >> P / M
21  */
22 struct ccu_mp {
23 	u32			enable;
24 
25 	struct ccu_div_internal		m;
26 	struct ccu_div_internal		p;
27 	struct ccu_mux_internal	mux;
28 
29 	unsigned int		fixed_post_div;
30 
31 	struct ccu_common	common;
32 };
33 
34 #define SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(_struct, _name, _parents, _reg, \
35 					   _mshift, _mwidth,		\
36 					   _pshift, _pwidth,		\
37 					   _muxshift, _muxwidth,	\
38 					   _gate, _postdiv, _flags)	\
39 	struct ccu_mp _struct = {					\
40 		.enable	= _gate,					\
41 		.m	= _SUNXI_CCU_DIV(_mshift, _mwidth),		\
42 		.p	= _SUNXI_CCU_DIV(_pshift, _pwidth),		\
43 		.mux	= _SUNXI_CCU_MUX(_muxshift, _muxwidth),		\
44 		.fixed_post_div	= _postdiv,				\
45 		.common	= {						\
46 			.reg		= _reg,				\
47 			.features	= CCU_FEATURE_FIXED_POSTDIV,	\
48 			.hw.init	= CLK_HW_INIT_PARENTS(_name,	\
49 							      _parents, \
50 							      &ccu_mp_ops, \
51 							      _flags),	\
52 		}							\
53 	}
54 
55 #define SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
56 				   _mshift, _mwidth,			\
57 				   _pshift, _pwidth,			\
58 				   _muxshift, _muxwidth,		\
59 				   _gate, _flags)			\
60 	struct ccu_mp _struct = {					\
61 		.enable	= _gate,					\
62 		.m	= _SUNXI_CCU_DIV(_mshift, _mwidth),		\
63 		.p	= _SUNXI_CCU_DIV(_pshift, _pwidth),		\
64 		.mux	= _SUNXI_CCU_MUX(_muxshift, _muxwidth),		\
65 		.common	= {						\
66 			.reg		= _reg,				\
67 			.hw.init	= CLK_HW_INIT_PARENTS(_name,	\
68 							      _parents, \
69 							      &ccu_mp_ops, \
70 							      _flags),	\
71 		}							\
72 	}
73 
74 #define SUNXI_CCU_MP_WITH_MUX(_struct, _name, _parents, _reg,		\
75 			      _mshift, _mwidth,				\
76 			      _pshift, _pwidth,				\
77 			      _muxshift, _muxwidth,			\
78 			      _flags)					\
79 	SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
80 				   _mshift, _mwidth,			\
81 				   _pshift, _pwidth,			\
82 				   _muxshift, _muxwidth,		\
83 				   0, _flags)
84 
hw_to_ccu_mp(struct clk_hw * hw)85 static inline struct ccu_mp *hw_to_ccu_mp(struct clk_hw *hw)
86 {
87 	struct ccu_common *common = hw_to_ccu_common(hw);
88 
89 	return container_of(common, struct ccu_mp, common);
90 }
91 
92 extern const struct clk_ops ccu_mp_ops;
93 
94 /*
95  * Special class of M-P clock that supports MMC timing modes
96  *
97  * Since the MMC clock registers all follow the same layout, we can
98  * simplify the macro for this particular case. In addition, as
99  * switching modes also affects the output clock rate, we need to
100  * have CLK_GET_RATE_NOCACHE for all these types of clocks.
101  */
102 
103 #define SUNXI_CCU_MP_MMC_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
104 				       _flags)				\
105 	struct ccu_mp _struct = {					\
106 		.enable	= BIT(31),					\
107 		.m	= _SUNXI_CCU_DIV(0, 4),				\
108 		.p	= _SUNXI_CCU_DIV(16, 2),			\
109 		.mux	= _SUNXI_CCU_MUX(24, 2),			\
110 		.common	= {						\
111 			.reg		= _reg,				\
112 			.features	= CCU_FEATURE_MMC_TIMING_SWITCH, \
113 			.hw.init	= CLK_HW_INIT_PARENTS(_name,	\
114 							      _parents, \
115 							      &ccu_mp_mmc_ops, \
116 							      CLK_GET_RATE_NOCACHE | \
117 							      _flags),	\
118 		}							\
119 	}
120 
121 extern const struct clk_ops ccu_mp_mmc_ops;
122 
123 #endif /* _CCU_MP_H_ */
124