2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-24 21:24:00 +08:00
linux-next/drivers/clk/sunxi-ng/ccu_mp.h
Chen-Yu Tsai dc8797e39f clk: sunxi-ng: Add MP_MMC clocks that support MMC timing modes switching
All of our MMC clocks are of the MP clock type. A few MMC clocks on some
SoCs, such as MMC2 on the A83T, support new/old timing mode switching.

>From a clock rate point of view, when the new timing mode is active. the
output clock rate is halved.

This patch adds a special wrapper class of clocks, MP_MMC, around the
generic MP type clocks. The rate related callbacks in ccu_mp_mmc_ops
for this class look at the timing mode bit and apply the /2 post-divider
when needed, before passing it through to the generic class ops,
ccu_mp_ops.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
2017-08-30 14:01:47 +02:00

108 lines
3.0 KiB
C

/*
* Copyright (c) 2016 Maxime Ripard. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _CCU_MP_H_
#define _CCU_MP_H_
#include <linux/bitops.h>
#include <linux/clk-provider.h>
#include "ccu_common.h"
#include "ccu_div.h"
#include "ccu_mult.h"
#include "ccu_mux.h"
/*
* struct ccu_mp - Definition of an M-P clock
*
* Clocks based on the formula parent >> P / M
*/
struct ccu_mp {
u32 enable;
struct ccu_div_internal m;
struct ccu_div_internal p;
struct ccu_mux_internal mux;
struct ccu_common common;
};
#define SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
_mshift, _mwidth, \
_pshift, _pwidth, \
_muxshift, _muxwidth, \
_gate, _flags) \
struct ccu_mp _struct = { \
.enable = _gate, \
.m = _SUNXI_CCU_DIV(_mshift, _mwidth), \
.p = _SUNXI_CCU_DIV(_pshift, _pwidth), \
.mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \
.common = { \
.reg = _reg, \
.hw.init = CLK_HW_INIT_PARENTS(_name, \
_parents, \
&ccu_mp_ops, \
_flags), \
} \
}
#define SUNXI_CCU_MP_WITH_MUX(_struct, _name, _parents, _reg, \
_mshift, _mwidth, \
_pshift, _pwidth, \
_muxshift, _muxwidth, \
_flags) \
SUNXI_CCU_MP_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
_mshift, _mwidth, \
_pshift, _pwidth, \
_muxshift, _muxwidth, \
0, _flags)
static inline struct ccu_mp *hw_to_ccu_mp(struct clk_hw *hw)
{
struct ccu_common *common = hw_to_ccu_common(hw);
return container_of(common, struct ccu_mp, common);
}
extern const struct clk_ops ccu_mp_ops;
/*
* Special class of M-P clock that supports MMC timing modes
*
* Since the MMC clock registers all follow the same layout, we can
* simplify the macro for this particular case. In addition, as
* switching modes also affects the output clock rate, we need to
* have CLK_GET_RATE_NOCACHE for all these types of clocks.
*/
#define SUNXI_CCU_MP_MMC_WITH_MUX_GATE(_struct, _name, _parents, _reg, \
_flags) \
struct ccu_mp _struct = { \
.enable = BIT(31), \
.m = _SUNXI_CCU_DIV(0, 4), \
.p = _SUNXI_CCU_DIV(16, 2), \
.mux = _SUNXI_CCU_MUX(24, 2), \
.common = { \
.reg = _reg, \
.features = CCU_FEATURE_MMC_TIMING_SWITCH, \
.hw.init = CLK_HW_INIT_PARENTS(_name, \
_parents, \
&ccu_mp_mmc_ops, \
CLK_GET_RATE_NOCACHE | \
_flags), \
} \
}
extern const struct clk_ops ccu_mp_mmc_ops;
#endif /* _CCU_MP_H_ */