162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _CCU_MUX_H_
362306a36Sopenharmony_ci#define _CCU_MUX_H_
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/clk-provider.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include "ccu_common.h"
862306a36Sopenharmony_ci
962306a36Sopenharmony_cistruct ccu_mux_fixed_prediv {
1062306a36Sopenharmony_ci	u8	index;
1162306a36Sopenharmony_ci	u16	div;
1262306a36Sopenharmony_ci};
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistruct ccu_mux_var_prediv {
1562306a36Sopenharmony_ci	u8	index;
1662306a36Sopenharmony_ci	u8	shift;
1762306a36Sopenharmony_ci	u8	width;
1862306a36Sopenharmony_ci};
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistruct ccu_mux_internal {
2162306a36Sopenharmony_ci	u8		shift;
2262306a36Sopenharmony_ci	u8		width;
2362306a36Sopenharmony_ci	const u8	*table;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	const struct ccu_mux_fixed_prediv	*fixed_predivs;
2662306a36Sopenharmony_ci	u8		n_predivs;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	const struct ccu_mux_var_prediv		*var_predivs;
2962306a36Sopenharmony_ci	u8		n_var_predivs;
3062306a36Sopenharmony_ci};
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define _SUNXI_CCU_MUX_TABLE(_shift, _width, _table)	\
3362306a36Sopenharmony_ci	{						\
3462306a36Sopenharmony_ci		.shift	= _shift,			\
3562306a36Sopenharmony_ci		.width	= _width,			\
3662306a36Sopenharmony_ci		.table	= _table,			\
3762306a36Sopenharmony_ci	}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#define _SUNXI_CCU_MUX(_shift, _width) \
4062306a36Sopenharmony_ci	_SUNXI_CCU_MUX_TABLE(_shift, _width, NULL)
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistruct ccu_mux {
4362306a36Sopenharmony_ci	u32			enable;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	struct ccu_mux_internal	mux;
4662306a36Sopenharmony_ci	struct ccu_common	common;
4762306a36Sopenharmony_ci};
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents, _table,	\
5062306a36Sopenharmony_ci				     _reg, _shift, _width, _gate,		\
5162306a36Sopenharmony_ci				     _flags, _features)				\
5262306a36Sopenharmony_ci	struct ccu_mux _struct = {						\
5362306a36Sopenharmony_ci		.enable	= _gate,						\
5462306a36Sopenharmony_ci		.mux	= _SUNXI_CCU_MUX_TABLE(_shift, _width, _table),		\
5562306a36Sopenharmony_ci		.common	= {							\
5662306a36Sopenharmony_ci			.reg		= _reg,					\
5762306a36Sopenharmony_ci			.hw.init	= CLK_HW_INIT_PARENTS(_name,		\
5862306a36Sopenharmony_ci							      _parents,		\
5962306a36Sopenharmony_ci							      &ccu_mux_ops,	\
6062306a36Sopenharmony_ci							      _flags),		\
6162306a36Sopenharmony_ci			.features	= _features,				\
6262306a36Sopenharmony_ci		}								\
6362306a36Sopenharmony_ci	}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#define SUNXI_CCU_MUX_TABLE_WITH_GATE_CLOSEST(_struct, _name, _parents,	\
6662306a36Sopenharmony_ci					      _table, _reg, _shift,	\
6762306a36Sopenharmony_ci					      _width, _gate, _flags)	\
6862306a36Sopenharmony_ci	SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents,	\
6962306a36Sopenharmony_ci					   _table, _reg, _shift,	\
7062306a36Sopenharmony_ci					   _width, _gate, _flags,	\
7162306a36Sopenharmony_ci					   CCU_FEATURE_CLOSEST_RATE)
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci#define SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, _table,	\
7462306a36Sopenharmony_ci				     _reg, _shift, _width, _gate,	\
7562306a36Sopenharmony_ci				     _flags)				\
7662306a36Sopenharmony_ci	SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents,	\
7762306a36Sopenharmony_ci					   _table, _reg, _shift,	\
7862306a36Sopenharmony_ci					   _width, _gate, _flags, 0)
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci#define SUNXI_CCU_MUX_WITH_GATE(_struct, _name, _parents, _reg,		\
8162306a36Sopenharmony_ci				_shift, _width, _gate, _flags)		\
8262306a36Sopenharmony_ci	SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, NULL,	\
8362306a36Sopenharmony_ci				      _reg, _shift, _width, _gate,	\
8462306a36Sopenharmony_ci				      _flags)
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci#define SUNXI_CCU_MUX(_struct, _name, _parents, _reg, _shift, _width,	\
8762306a36Sopenharmony_ci		      _flags)						\
8862306a36Sopenharmony_ci	SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, NULL,	\
8962306a36Sopenharmony_ci				      _reg, _shift, _width, 0, _flags)
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#define SUNXI_CCU_MUX_DATA_WITH_GATE(_struct, _name, _parents, _reg,	\
9262306a36Sopenharmony_ci				     _shift, _width, _gate, _flags)	\
9362306a36Sopenharmony_ci	struct ccu_mux _struct = {					\
9462306a36Sopenharmony_ci		.enable	= _gate,					\
9562306a36Sopenharmony_ci		.mux	= _SUNXI_CCU_MUX(_shift, _width),		\
9662306a36Sopenharmony_ci		.common	= {						\
9762306a36Sopenharmony_ci			.reg		= _reg,				\
9862306a36Sopenharmony_ci			.hw.init	= CLK_HW_INIT_PARENTS_DATA(_name, \
9962306a36Sopenharmony_ci								   _parents, \
10062306a36Sopenharmony_ci								   &ccu_mux_ops, \
10162306a36Sopenharmony_ci								   _flags), \
10262306a36Sopenharmony_ci		}							\
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci#define SUNXI_CCU_MUX_DATA(_struct, _name, _parents, _reg,		\
10662306a36Sopenharmony_ci		      _shift, _width, _flags)				\
10762306a36Sopenharmony_ci	SUNXI_CCU_MUX_DATA_WITH_GATE(_struct, _name, _parents, _reg,	\
10862306a36Sopenharmony_ci				     _shift, _width, 0, _flags)
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci#define SUNXI_CCU_MUX_HW_WITH_GATE(_struct, _name, _parents, _reg,	\
11162306a36Sopenharmony_ci				   _shift, _width, _gate, _flags)	\
11262306a36Sopenharmony_ci	struct ccu_mux _struct = {					\
11362306a36Sopenharmony_ci		.enable	= _gate,					\
11462306a36Sopenharmony_ci		.mux	= _SUNXI_CCU_MUX(_shift, _width),		\
11562306a36Sopenharmony_ci		.common	= {						\
11662306a36Sopenharmony_ci			.reg		= _reg,				\
11762306a36Sopenharmony_ci			.hw.init	= CLK_HW_INIT_PARENTS_HW(_name, \
11862306a36Sopenharmony_ci								 _parents, \
11962306a36Sopenharmony_ci								 &ccu_mux_ops, \
12062306a36Sopenharmony_ci								 _flags), \
12162306a36Sopenharmony_ci		}							\
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic inline struct ccu_mux *hw_to_ccu_mux(struct clk_hw *hw)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	struct ccu_common *common = hw_to_ccu_common(hw);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	return container_of(common, struct ccu_mux, common);
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ciextern const struct clk_ops ccu_mux_ops;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ciunsigned long ccu_mux_helper_apply_prediv(struct ccu_common *common,
13462306a36Sopenharmony_ci					  struct ccu_mux_internal *cm,
13562306a36Sopenharmony_ci					  int parent_index,
13662306a36Sopenharmony_ci					  unsigned long parent_rate);
13762306a36Sopenharmony_ciint ccu_mux_helper_determine_rate(struct ccu_common *common,
13862306a36Sopenharmony_ci				  struct ccu_mux_internal *cm,
13962306a36Sopenharmony_ci				  struct clk_rate_request *req,
14062306a36Sopenharmony_ci				  unsigned long (*round)(struct ccu_mux_internal *,
14162306a36Sopenharmony_ci							 struct clk_hw *,
14262306a36Sopenharmony_ci							 unsigned long *,
14362306a36Sopenharmony_ci							 unsigned long,
14462306a36Sopenharmony_ci							 void *),
14562306a36Sopenharmony_ci				  void *data);
14662306a36Sopenharmony_ciu8 ccu_mux_helper_get_parent(struct ccu_common *common,
14762306a36Sopenharmony_ci			     struct ccu_mux_internal *cm);
14862306a36Sopenharmony_ciint ccu_mux_helper_set_parent(struct ccu_common *common,
14962306a36Sopenharmony_ci			      struct ccu_mux_internal *cm,
15062306a36Sopenharmony_ci			      u8 index);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistruct ccu_mux_nb {
15362306a36Sopenharmony_ci	struct notifier_block	clk_nb;
15462306a36Sopenharmony_ci	struct ccu_common	*common;
15562306a36Sopenharmony_ci	struct ccu_mux_internal	*cm;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	u32	delay_us;	/* How many us to wait after reparenting */
15862306a36Sopenharmony_ci	u8	bypass_index;	/* Which parent to temporarily use */
15962306a36Sopenharmony_ci	u8	original_index;	/* This is set by the notifier callback */
16062306a36Sopenharmony_ci};
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci#define to_ccu_mux_nb(_nb) container_of(_nb, struct ccu_mux_nb, clk_nb)
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ciint ccu_mux_notifier_register(struct clk *clk, struct ccu_mux_nb *mux_nb);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci#endif /* _CCU_MUX_H_ */
167