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
9struct ccu_mux_fixed_prediv {
10	u8	index;
11	u16	div;
12};
13
14struct ccu_mux_var_prediv {
15	u8	index;
16	u8	shift;
17	u8	width;
18};
19
20struct 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
42struct ccu_mux {
43	u16			reg;
44	u32			enable;
45
46	struct ccu_mux_internal	mux;
47	struct ccu_common	common;
48};
49
50#define SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, _table,	\
51				     _reg, _shift, _width, _gate,	\
52				     _flags)				\
53	struct ccu_mux _struct = {					\
54		.enable	= _gate,					\
55		.mux	= _SUNXI_CCU_MUX_TABLE(_shift, _width, _table),	\
56		.common	= {						\
57			.reg		= _reg,				\
58			.hw.init	= CLK_HW_INIT_PARENTS(_name,	\
59							      _parents, \
60							      &ccu_mux_ops, \
61							      _flags),	\
62		}							\
63	}
64
65#define SUNXI_CCU_MUX_WITH_GATE(_struct, _name, _parents, _reg,		\
66				_shift, _width, _gate, _flags)		\
67	SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, NULL,	\
68				      _reg, _shift, _width, _gate,	\
69				      _flags)
70
71#define SUNXI_CCU_MUX(_struct, _name, _parents, _reg, _shift, _width,	\
72		      _flags)						\
73	SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, NULL,	\
74				      _reg, _shift, _width, 0, _flags)
75
76static inline struct ccu_mux *hw_to_ccu_mux(struct clk_hw *hw)
77{
78	struct ccu_common *common = hw_to_ccu_common(hw);
79
80	return container_of(common, struct ccu_mux, common);
81}
82
83extern const struct clk_ops ccu_mux_ops;
84
85unsigned long ccu_mux_helper_apply_prediv(struct ccu_common *common,
86					  struct ccu_mux_internal *cm,
87					  int parent_index,
88					  unsigned long parent_rate);
89int ccu_mux_helper_determine_rate(struct ccu_common *common,
90				  struct ccu_mux_internal *cm,
91				  struct clk_rate_request *req,
92				  unsigned long (*round)(struct ccu_mux_internal *,
93							 struct clk_hw *,
94							 unsigned long *,
95							 unsigned long,
96							 void *),
97				  void *data);
98u8 ccu_mux_helper_get_parent(struct ccu_common *common,
99			     struct ccu_mux_internal *cm);
100int ccu_mux_helper_set_parent(struct ccu_common *common,
101			      struct ccu_mux_internal *cm,
102			      u8 index);
103
104struct ccu_mux_nb {
105	struct notifier_block	clk_nb;
106	struct ccu_common	*common;
107	struct ccu_mux_internal	*cm;
108
109	u32	delay_us;	/* How many us to wait after reparenting */
110	u8	bypass_index;	/* Which parent to temporarily use */
111	u8	original_index;	/* This is set by the notifier callback */
112};
113
114#define to_ccu_mux_nb(_nb) container_of(_nb, struct ccu_mux_nb, clk_nb)
115
116int ccu_mux_notifier_register(struct clk *clk, struct ccu_mux_nb *mux_nb);
117
118#endif /* _CCU_MUX_H_ */
119