162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2016 Maxime Ripard. All rights reserved.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#ifndef _CCU_MP_H_
762306a36Sopenharmony_ci#define _CCU_MP_H_
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/bitops.h>
1062306a36Sopenharmony_ci#include <linux/clk-provider.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "ccu_common.h"
1362306a36Sopenharmony_ci#include "ccu_div.h"
1462306a36Sopenharmony_ci#include "ccu_mult.h"
1562306a36Sopenharmony_ci#include "ccu_mux.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/*
1862306a36Sopenharmony_ci * struct ccu_mp - Definition of an M-P clock
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci * Clocks based on the formula parent >> P / M
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_cistruct ccu_mp {
2362306a36Sopenharmony_ci	u32			enable;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	struct ccu_div_internal		m;
2662306a36Sopenharmony_ci	struct ccu_div_internal		p;
2762306a36Sopenharmony_ci	struct ccu_mux_internal	mux;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	unsigned int		fixed_post_div;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	struct ccu_common	common;
3262306a36Sopenharmony_ci};
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(_struct, _name, _parents, _reg, \
3562306a36Sopenharmony_ci					   _mshift, _mwidth,		\
3662306a36Sopenharmony_ci					   _pshift, _pwidth,		\
3762306a36Sopenharmony_ci					   _muxshift, _muxwidth,	\
3862306a36Sopenharmony_ci					   _gate, _postdiv, _flags)	\
3962306a36Sopenharmony_ci	struct ccu_mp _struct = {					\
4062306a36Sopenharmony_ci		.enable	= _gate,					\
4162306a36Sopenharmony_ci		.m	= _SUNXI_CCU_DIV(_mshift, _mwidth),		\
4262306a36Sopenharmony_ci		.p	= _SUNXI_CCU_DIV(_pshift, _pwidth),		\
4362306a36Sopenharmony_ci		.mux	= _SUNXI_CCU_MUX(_muxshift, _muxwidth),		\
4462306a36Sopenharmony_ci		.fixed_post_div	= _postdiv,				\
4562306a36Sopenharmony_ci		.common	= {						\
4662306a36Sopenharmony_ci			.reg		= _reg,				\
4762306a36Sopenharmony_ci			.features	= CCU_FEATURE_FIXED_POSTDIV,	\
4862306a36Sopenharmony_ci			.hw.init	= CLK_HW_INIT_PARENTS(_name,	\
4962306a36Sopenharmony_ci							      _parents, \
5062306a36Sopenharmony_ci							      &ccu_mp_ops, \
5162306a36Sopenharmony_ci							      _flags),	\
5262306a36Sopenharmony_ci		}							\
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
5662306a36Sopenharmony_ci				   _mshift, _mwidth,			\
5762306a36Sopenharmony_ci				   _pshift, _pwidth,			\
5862306a36Sopenharmony_ci				   _muxshift, _muxwidth,		\
5962306a36Sopenharmony_ci				   _gate, _flags)			\
6062306a36Sopenharmony_ci	struct ccu_mp _struct = {					\
6162306a36Sopenharmony_ci		.enable	= _gate,					\
6262306a36Sopenharmony_ci		.m	= _SUNXI_CCU_DIV(_mshift, _mwidth),		\
6362306a36Sopenharmony_ci		.p	= _SUNXI_CCU_DIV(_pshift, _pwidth),		\
6462306a36Sopenharmony_ci		.mux	= _SUNXI_CCU_MUX(_muxshift, _muxwidth),		\
6562306a36Sopenharmony_ci		.common	= {						\
6662306a36Sopenharmony_ci			.reg		= _reg,				\
6762306a36Sopenharmony_ci			.hw.init	= CLK_HW_INIT_PARENTS(_name,	\
6862306a36Sopenharmony_ci							      _parents, \
6962306a36Sopenharmony_ci							      &ccu_mp_ops, \
7062306a36Sopenharmony_ci							      _flags),	\
7162306a36Sopenharmony_ci		}							\
7262306a36Sopenharmony_ci	}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci#define SUNXI_CCU_MP_WITH_MUX(_struct, _name, _parents, _reg,		\
7562306a36Sopenharmony_ci			      _mshift, _mwidth,				\
7662306a36Sopenharmony_ci			      _pshift, _pwidth,				\
7762306a36Sopenharmony_ci			      _muxshift, _muxwidth,			\
7862306a36Sopenharmony_ci			      _flags)					\
7962306a36Sopenharmony_ci	SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
8062306a36Sopenharmony_ci				   _mshift, _mwidth,			\
8162306a36Sopenharmony_ci				   _pshift, _pwidth,			\
8262306a36Sopenharmony_ci				   _muxshift, _muxwidth,		\
8362306a36Sopenharmony_ci				   0, _flags)
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#define SUNXI_CCU_MP_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
8662306a36Sopenharmony_ci					_mshift, _mwidth,		\
8762306a36Sopenharmony_ci					_pshift, _pwidth,		\
8862306a36Sopenharmony_ci					_muxshift, _muxwidth,		\
8962306a36Sopenharmony_ci					_gate, _flags)			\
9062306a36Sopenharmony_ci	struct ccu_mp _struct = {					\
9162306a36Sopenharmony_ci		.enable	= _gate,					\
9262306a36Sopenharmony_ci		.m	= _SUNXI_CCU_DIV(_mshift, _mwidth),		\
9362306a36Sopenharmony_ci		.p	= _SUNXI_CCU_DIV(_pshift, _pwidth),		\
9462306a36Sopenharmony_ci		.mux	= _SUNXI_CCU_MUX(_muxshift, _muxwidth),		\
9562306a36Sopenharmony_ci		.common	= {						\
9662306a36Sopenharmony_ci			.reg		= _reg,				\
9762306a36Sopenharmony_ci			.hw.init	= CLK_HW_INIT_PARENTS_DATA(_name, \
9862306a36Sopenharmony_ci								   _parents, \
9962306a36Sopenharmony_ci								   &ccu_mp_ops, \
10062306a36Sopenharmony_ci								   _flags), \
10162306a36Sopenharmony_ci		}							\
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci#define SUNXI_CCU_MP_DATA_WITH_MUX(_struct, _name, _parents, _reg,	\
10562306a36Sopenharmony_ci				   _mshift, _mwidth,			\
10662306a36Sopenharmony_ci				   _pshift, _pwidth,			\
10762306a36Sopenharmony_ci				   _muxshift, _muxwidth,		\
10862306a36Sopenharmony_ci				   _flags)				\
10962306a36Sopenharmony_ci	SUNXI_CCU_MP_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
11062306a36Sopenharmony_ci					_mshift, _mwidth,		\
11162306a36Sopenharmony_ci					_pshift, _pwidth,		\
11262306a36Sopenharmony_ci					_muxshift, _muxwidth,		\
11362306a36Sopenharmony_ci					0, _flags)
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci#define SUNXI_CCU_MP_HW_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
11662306a36Sopenharmony_ci				      _mshift, _mwidth,			\
11762306a36Sopenharmony_ci				      _pshift, _pwidth,			\
11862306a36Sopenharmony_ci				      _muxshift, _muxwidth,		\
11962306a36Sopenharmony_ci				      _gate, _flags)			\
12062306a36Sopenharmony_ci	struct ccu_mp _struct = {					\
12162306a36Sopenharmony_ci		.enable	= _gate,					\
12262306a36Sopenharmony_ci		.m	= _SUNXI_CCU_DIV(_mshift, _mwidth),		\
12362306a36Sopenharmony_ci		.p	= _SUNXI_CCU_DIV(_pshift, _pwidth),		\
12462306a36Sopenharmony_ci		.mux	= _SUNXI_CCU_MUX(_muxshift, _muxwidth),		\
12562306a36Sopenharmony_ci		.common	= {						\
12662306a36Sopenharmony_ci			.reg		= _reg,				\
12762306a36Sopenharmony_ci			.hw.init	= CLK_HW_INIT_PARENTS_HW(_name, \
12862306a36Sopenharmony_ci								 _parents, \
12962306a36Sopenharmony_ci								 &ccu_mp_ops, \
13062306a36Sopenharmony_ci								 _flags), \
13162306a36Sopenharmony_ci		}							\
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic inline struct ccu_mp *hw_to_ccu_mp(struct clk_hw *hw)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	struct ccu_common *common = hw_to_ccu_common(hw);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	return container_of(common, struct ccu_mp, common);
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ciextern const struct clk_ops ccu_mp_ops;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci/*
14462306a36Sopenharmony_ci * Special class of M-P clock that supports MMC timing modes
14562306a36Sopenharmony_ci *
14662306a36Sopenharmony_ci * Since the MMC clock registers all follow the same layout, we can
14762306a36Sopenharmony_ci * simplify the macro for this particular case. In addition, as
14862306a36Sopenharmony_ci * switching modes also affects the output clock rate, we need to
14962306a36Sopenharmony_ci * have CLK_GET_RATE_NOCACHE for all these types of clocks.
15062306a36Sopenharmony_ci */
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci#define SUNXI_CCU_MP_MMC_WITH_MUX_GATE(_struct, _name, _parents, _reg,	\
15362306a36Sopenharmony_ci				       _flags)				\
15462306a36Sopenharmony_ci	struct ccu_mp _struct = {					\
15562306a36Sopenharmony_ci		.enable	= BIT(31),					\
15662306a36Sopenharmony_ci		.m	= _SUNXI_CCU_DIV(0, 4),				\
15762306a36Sopenharmony_ci		.p	= _SUNXI_CCU_DIV(16, 2),			\
15862306a36Sopenharmony_ci		.mux	= _SUNXI_CCU_MUX(24, 2),			\
15962306a36Sopenharmony_ci		.common	= {						\
16062306a36Sopenharmony_ci			.reg		= _reg,				\
16162306a36Sopenharmony_ci			.features	= CCU_FEATURE_MMC_TIMING_SWITCH, \
16262306a36Sopenharmony_ci			.hw.init	= CLK_HW_INIT_PARENTS(_name,	\
16362306a36Sopenharmony_ci							      _parents, \
16462306a36Sopenharmony_ci							      &ccu_mp_mmc_ops, \
16562306a36Sopenharmony_ci							      CLK_GET_RATE_NOCACHE | \
16662306a36Sopenharmony_ci							      _flags),	\
16762306a36Sopenharmony_ci		}							\
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ciextern const struct clk_ops ccu_mp_mmc_ops;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci#endif /* _CCU_MP_H_ */
173