1  /* SPDX-License-Identifier: GPL-2.0 */
2  #ifndef _CCU_MUX_H_
3  #define _CCU_MUX_H_
4  
5  #include <linux/clk-provider.h>
6  
7  #include "ccu_common.h"
8  
9  struct ccu_mux_fixed_prediv {
10  	u8	index;
11  	u16	div;
12  };
13  
14  struct ccu_mux_var_prediv {
15  	u8	index;
16  	u8	shift;
17  	u8	width;
18  };
19  
20  struct ccu_mux_internal {
21  	u8		shift;
22  	u8		width;
23  	const u8	*table;
24  
25  	const struct ccu_mux_fixed_prediv	*fixed_predivs;
26  	u8		n_predivs;
27  
28  	const struct ccu_mux_var_prediv		*var_predivs;
29  	u8		n_var_predivs;
30  };
31  
32  #define _SUNXI_CCU_MUX_TABLE(_shift, _width, _table)	\
33  	{						\
34  		.shift	= _shift,			\
35  		.width	= _width,			\
36  		.table	= _table,			\
37  	}
38  
39  #define _SUNXI_CCU_MUX(_shift, _width) \
40  	_SUNXI_CCU_MUX_TABLE(_shift, _width, NULL)
41  
42  struct ccu_mux {
43  	u32			enable;
44  
45  	struct ccu_mux_internal	mux;
46  	struct ccu_common	common;
47  };
48  
49  #define SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents, _table,	\
50  				     _reg, _shift, _width, _gate,		\
51  				     _flags, _features)				\
52  	struct ccu_mux _struct = {						\
53  		.enable	= _gate,						\
54  		.mux	= _SUNXI_CCU_MUX_TABLE(_shift, _width, _table),		\
55  		.common	= {							\
56  			.reg		= _reg,					\
57  			.hw.init	= CLK_HW_INIT_PARENTS(_name,		\
58  							      _parents,		\
59  							      &ccu_mux_ops,	\
60  							      _flags),		\
61  			.features	= _features,				\
62  		}								\
63  	}
64  
65  #define SUNXI_CCU_MUX_TABLE_WITH_GATE_CLOSEST(_struct, _name, _parents,	\
66  					      _table, _reg, _shift,	\
67  					      _width, _gate, _flags)	\
68  	SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents,	\
69  					   _table, _reg, _shift,	\
70  					   _width, _gate, _flags,	\
71  					   CCU_FEATURE_CLOSEST_RATE)
72  
73  #define SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, _table,	\
74  				     _reg, _shift, _width, _gate,	\
75  				     _flags)				\
76  	SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents,	\
77  					   _table, _reg, _shift,	\
78  					   _width, _gate, _flags, 0)
79  
80  #define SUNXI_CCU_MUX_WITH_GATE(_struct, _name, _parents, _reg,		\
81  				_shift, _width, _gate, _flags)		\
82  	SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, NULL,	\
83  				      _reg, _shift, _width, _gate,	\
84  				      _flags)
85  
86  #define SUNXI_CCU_MUX(_struct, _name, _parents, _reg, _shift, _width,	\
87  		      _flags)						\
88  	SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, NULL,	\
89  				      _reg, _shift, _width, 0, _flags)
90  
91  #define SUNXI_CCU_MUX_DATA_WITH_GATE(_struct, _name, _parents, _reg,	\
92  				     _shift, _width, _gate, _flags)	\
93  	struct ccu_mux _struct = {					\
94  		.enable	= _gate,					\
95  		.mux	= _SUNXI_CCU_MUX(_shift, _width),		\
96  		.common	= {						\
97  			.reg		= _reg,				\
98  			.hw.init	= CLK_HW_INIT_PARENTS_DATA(_name, \
99  								   _parents, \
100  								   &ccu_mux_ops, \
101  								   _flags), \
102  		}							\
103  	}
104  
105  #define SUNXI_CCU_MUX_DATA(_struct, _name, _parents, _reg,		\
106  		      _shift, _width, _flags)				\
107  	SUNXI_CCU_MUX_DATA_WITH_GATE(_struct, _name, _parents, _reg,	\
108  				     _shift, _width, 0, _flags)
109  
110  #define SUNXI_CCU_MUX_HW_WITH_GATE(_struct, _name, _parents, _reg,	\
111  				   _shift, _width, _gate, _flags)	\
112  	struct ccu_mux _struct = {					\
113  		.enable	= _gate,					\
114  		.mux	= _SUNXI_CCU_MUX(_shift, _width),		\
115  		.common	= {						\
116  			.reg		= _reg,				\
117  			.hw.init	= CLK_HW_INIT_PARENTS_HW(_name, \
118  								 _parents, \
119  								 &ccu_mux_ops, \
120  								 _flags), \
121  		}							\
122  	}
123  
hw_to_ccu_mux(struct clk_hw * hw)124  static inline struct ccu_mux *hw_to_ccu_mux(struct clk_hw *hw)
125  {
126  	struct ccu_common *common = hw_to_ccu_common(hw);
127  
128  	return container_of(common, struct ccu_mux, common);
129  }
130  
131  extern const struct clk_ops ccu_mux_ops;
132  
133  unsigned long ccu_mux_helper_apply_prediv(struct ccu_common *common,
134  					  struct ccu_mux_internal *cm,
135  					  int parent_index,
136  					  unsigned long parent_rate);
137  int ccu_mux_helper_determine_rate(struct ccu_common *common,
138  				  struct ccu_mux_internal *cm,
139  				  struct clk_rate_request *req,
140  				  unsigned long (*round)(struct ccu_mux_internal *,
141  							 struct clk_hw *,
142  							 unsigned long *,
143  							 unsigned long,
144  							 void *),
145  				  void *data);
146  u8 ccu_mux_helper_get_parent(struct ccu_common *common,
147  			     struct ccu_mux_internal *cm);
148  int ccu_mux_helper_set_parent(struct ccu_common *common,
149  			      struct ccu_mux_internal *cm,
150  			      u8 index);
151  
152  struct ccu_mux_nb {
153  	struct notifier_block	clk_nb;
154  	struct ccu_common	*common;
155  	struct ccu_mux_internal	*cm;
156  
157  	u32	delay_us;	/* How many us to wait after reparenting */
158  	u8	bypass_index;	/* Which parent to temporarily use */
159  	u8	original_index;	/* This is set by the notifier callback */
160  };
161  
162  #define to_ccu_mux_nb(_nb) container_of(_nb, struct ccu_mux_nb, clk_nb)
163  
164  int ccu_mux_notifier_register(struct clk *clk, struct ccu_mux_nb *mux_nb);
165  
166  #endif /* _CCU_MUX_H_ */
167