linux/drivers/clk/spacemit/ccu_mix.h

224 lines
6.9 KiB
C
Raw Permalink Normal View History

/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2024 SpacemiT Technology Co. Ltd
* Copyright (c) 2024-2025 Haylen Chu <heylenay@4d2.org>
*/
#ifndef _CCU_MIX_H_
#define _CCU_MIX_H_
#include <linux/clk-provider.h>
#include "ccu_common.h"
/**
* struct ccu_gate_config - Gate configuration
*
* @mask: Mask to enable the gate. Some clocks may have more than one bit
* set in this field.
*/
struct ccu_gate_config {
u32 mask;
};
struct ccu_factor_config {
u32 div;
u32 mul;
};
struct ccu_mux_config {
u8 shift;
u8 width;
};
struct ccu_div_config {
u8 shift;
u8 width;
};
struct ccu_mix {
struct ccu_factor_config factor;
struct ccu_gate_config gate;
struct ccu_div_config div;
struct ccu_mux_config mux;
struct ccu_common common;
};
#define CCU_GATE_INIT(_mask) { .mask = _mask }
#define CCU_FACTOR_INIT(_div, _mul) { .div = _div, .mul = _mul }
#define CCU_MUX_INIT(_shift, _width) { .shift = _shift, .width = _width }
#define CCU_DIV_INIT(_shift, _width) { .shift = _shift, .width = _width }
#define CCU_PARENT_HW(_parent) { .hw = &_parent.common.hw }
#define CCU_PARENT_NAME(_name) { .fw_name = #_name }
#define CCU_MIX_INITHW(_name, _parent, _ops, _flags) \
.hw.init = &(struct clk_init_data) { \
.flags = _flags, \
.name = #_name, \
.parent_data = (const struct clk_parent_data[]) \
{ _parent }, \
.num_parents = 1, \
.ops = &_ops, \
}
#define CCU_MIX_INITHW_PARENTS(_name, _parents, _ops, _flags) \
.hw.init = CLK_HW_INIT_PARENTS_DATA(#_name, _parents, &_ops, _flags)
#define CCU_GATE_DEFINE(_name, _parent, _reg_ctrl, _mask_gate, _flags) \
static struct ccu_mix _name = { \
.gate = CCU_GATE_INIT(_mask_gate), \
.common = { \
.reg_ctrl = _reg_ctrl, \
CCU_MIX_INITHW(_name, _parent, spacemit_ccu_gate_ops, _flags), \
} \
}
#define CCU_FACTOR_DEFINE(_name, _parent, _div, _mul) \
static struct ccu_mix _name = { \
.factor = CCU_FACTOR_INIT(_div, _mul), \
.common = { \
CCU_MIX_INITHW(_name, _parent, spacemit_ccu_factor_ops, 0), \
} \
}
#define CCU_MUX_DEFINE(_name, _parents, _reg_ctrl, _shift, _width, _flags) \
static struct ccu_mix _name = { \
.mux = CCU_MUX_INIT(_shift, _width), \
.common = { \
.reg_ctrl = _reg_ctrl, \
CCU_MIX_INITHW_PARENTS(_name, _parents, spacemit_ccu_mux_ops, \
_flags), \
} \
}
#define CCU_DIV_DEFINE(_name, _parent, _reg_ctrl, _shift, _width, _flags) \
static struct ccu_mix _name = { \
.div = CCU_DIV_INIT(_shift, _width), \
.common = { \
.reg_ctrl = _reg_ctrl, \
CCU_MIX_INITHW(_name, _parent, spacemit_ccu_div_ops, _flags) \
} \
}
#define CCU_FACTOR_GATE_FLAGS_DEFINE(_name, _parent, _reg_ctrl, _mask_gate, _div, \
_mul, _flags) \
static struct ccu_mix _name = { \
.gate = CCU_GATE_INIT(_mask_gate), \
.factor = CCU_FACTOR_INIT(_div, _mul), \
.common = { \
.reg_ctrl = _reg_ctrl, \
CCU_MIX_INITHW(_name, _parent, spacemit_ccu_factor_gate_ops, _flags) \
} \
}
#define CCU_FACTOR_GATE_DEFINE(_name, _parent, _reg_ctrl, _mask_gate, _div, \
_mul) \
CCU_FACTOR_GATE_FLAGS_DEFINE(_name, _parent, _reg_ctrl, _mask_gate, _div, \
_mul, 0)
#define CCU_MUX_GATE_DEFINE(_name, _parents, _reg_ctrl, _shift, _width, \
_mask_gate, _flags) \
static struct ccu_mix _name = { \
.gate = CCU_GATE_INIT(_mask_gate), \
.mux = CCU_MUX_INIT(_shift, _width), \
.common = { \
.reg_ctrl = _reg_ctrl, \
CCU_MIX_INITHW_PARENTS(_name, _parents, \
spacemit_ccu_mux_gate_ops, _flags), \
} \
}
#define CCU_DIV_GATE_DEFINE(_name, _parent, _reg_ctrl, _shift, _width, \
_mask_gate, _flags) \
static struct ccu_mix _name = { \
.gate = CCU_GATE_INIT(_mask_gate), \
.div = CCU_DIV_INIT(_shift, _width), \
.common = { \
.reg_ctrl = _reg_ctrl, \
CCU_MIX_INITHW(_name, _parent, spacemit_ccu_div_gate_ops, \
_flags), \
} \
}
#define CCU_MUX_DIV_GATE_DEFINE(_name, _parents, _reg_ctrl, _mshift, _mwidth, \
_muxshift, _muxwidth, _mask_gate, _flags) \
static struct ccu_mix _name = { \
.gate = CCU_GATE_INIT(_mask_gate), \
.div = CCU_DIV_INIT(_mshift, _mwidth), \
.mux = CCU_MUX_INIT(_muxshift, _muxwidth), \
.common = { \
.reg_ctrl = _reg_ctrl, \
CCU_MIX_INITHW_PARENTS(_name, _parents, \
spacemit_ccu_mux_div_gate_ops, _flags), \
}, \
}
#define CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(_name, _parents, _reg_ctrl, _reg_fc, \
_mshift, _mwidth, _mask_fc, _muxshift, \
_muxwidth, _mask_gate, _flags) \
static struct ccu_mix _name = { \
.gate = CCU_GATE_INIT(_mask_gate), \
.div = CCU_DIV_INIT(_mshift, _mwidth), \
.mux = CCU_MUX_INIT(_muxshift, _muxwidth), \
.common = { \
.reg_ctrl = _reg_ctrl, \
.reg_fc = _reg_fc, \
.mask_fc = _mask_fc, \
CCU_MIX_INITHW_PARENTS(_name, _parents, \
spacemit_ccu_mux_div_gate_ops, _flags), \
}, \
}
#define CCU_MUX_DIV_GATE_FC_DEFINE(_name, _parents, _reg_ctrl, _mshift, _mwidth,\
_mask_fc, _muxshift, _muxwidth, _mask_gate, \
_flags) \
CCU_MUX_DIV_GATE_SPLIT_FC_DEFINE(_name, _parents, _reg_ctrl, _reg_ctrl, _mshift,\
_mwidth, _mask_fc, _muxshift, _muxwidth, \
_mask_gate, _flags)
#define CCU_MUX_DIV_FC_DEFINE(_name, _parents, _reg_ctrl, _mshift, _mwidth, \
_mask_fc, _muxshift, _muxwidth, _flags) \
static struct ccu_mix _name = { \
.div = CCU_DIV_INIT(_mshift, _mwidth), \
.mux = CCU_MUX_INIT(_muxshift, _muxwidth), \
.common = { \
.reg_ctrl = _reg_ctrl, \
.reg_fc = _reg_ctrl, \
.mask_fc = _mask_fc, \
CCU_MIX_INITHW_PARENTS(_name, _parents, \
spacemit_ccu_mux_div_ops, _flags), \
}, \
}
#define CCU_MUX_FC_DEFINE(_name, _parents, _reg_ctrl, _mask_fc, _muxshift, \
_muxwidth, _flags) \
static struct ccu_mix _name = { \
.mux = CCU_MUX_INIT(_muxshift, _muxwidth), \
.common = { \
.reg_ctrl = _reg_ctrl, \
.reg_fc = _reg_ctrl, \
.mask_fc = _mask_fc, \
CCU_MIX_INITHW_PARENTS(_name, _parents, spacemit_ccu_mux_ops, \
_flags) \
}, \
}
static inline struct ccu_mix *hw_to_ccu_mix(struct clk_hw *hw)
{
struct ccu_common *common = hw_to_ccu_common(hw);
return container_of(common, struct ccu_mix, common);
}
extern const struct clk_ops spacemit_ccu_gate_ops;
extern const struct clk_ops spacemit_ccu_factor_ops;
extern const struct clk_ops spacemit_ccu_mux_ops;
extern const struct clk_ops spacemit_ccu_div_ops;
extern const struct clk_ops spacemit_ccu_factor_gate_ops;
extern const struct clk_ops spacemit_ccu_div_gate_ops;
extern const struct clk_ops spacemit_ccu_mux_gate_ops;
extern const struct clk_ops spacemit_ccu_mux_div_ops;
extern const struct clk_ops spacemit_ccu_mux_div_gate_ops;
#endif /* _CCU_DIV_H_ */