167 lines · c
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 u32 enable;44 45 struct ccu_mux_internal mux;46 struct ccu_common common;47};48 49#define SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents, _table, \50 _reg, _shift, _width, _gate, \51 _flags, _features) \52 struct ccu_mux _struct = { \53 .enable = _gate, \54 .mux = _SUNXI_CCU_MUX_TABLE(_shift, _width, _table), \55 .common = { \56 .reg = _reg, \57 .hw.init = CLK_HW_INIT_PARENTS(_name, \58 _parents, \59 &ccu_mux_ops, \60 _flags), \61 .features = _features, \62 } \63 }64 65#define SUNXI_CCU_MUX_TABLE_WITH_GATE_CLOSEST(_struct, _name, _parents, \66 _table, _reg, _shift, \67 _width, _gate, _flags) \68 SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents, \69 _table, _reg, _shift, \70 _width, _gate, _flags, \71 CCU_FEATURE_CLOSEST_RATE)72 73#define SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, _table, \74 _reg, _shift, _width, _gate, \75 _flags) \76 SUNXI_CCU_MUX_TABLE_WITH_GATE_FEAT(_struct, _name, _parents, \77 _table, _reg, _shift, \78 _width, _gate, _flags, 0)79 80#define SUNXI_CCU_MUX_WITH_GATE(_struct, _name, _parents, _reg, \81 _shift, _width, _gate, _flags) \82 SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, NULL, \83 _reg, _shift, _width, _gate, \84 _flags)85 86#define SUNXI_CCU_MUX(_struct, _name, _parents, _reg, _shift, _width, \87 _flags) \88 SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, NULL, \89 _reg, _shift, _width, 0, _flags)90 91#define SUNXI_CCU_MUX_DATA_WITH_GATE(_struct, _name, _parents, _reg, \92 _shift, _width, _gate, _flags) \93 struct ccu_mux _struct = { \94 .enable = _gate, \95 .mux = _SUNXI_CCU_MUX(_shift, _width), \96 .common = { \97 .reg = _reg, \98 .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, \99 _parents, \100 &ccu_mux_ops, \101 _flags), \102 } \103 }104 105#define SUNXI_CCU_MUX_DATA(_struct, _name, _parents, _reg, \106 _shift, _width, _flags) \107 SUNXI_CCU_MUX_DATA_WITH_GATE(_struct, _name, _parents, _reg, \108 _shift, _width, 0, _flags)109 110#define SUNXI_CCU_MUX_HW_WITH_GATE(_struct, _name, _parents, _reg, \111 _shift, _width, _gate, _flags) \112 struct ccu_mux _struct = { \113 .enable = _gate, \114 .mux = _SUNXI_CCU_MUX(_shift, _width), \115 .common = { \116 .reg = _reg, \117 .hw.init = CLK_HW_INIT_PARENTS_HW(_name, \118 _parents, \119 &ccu_mux_ops, \120 _flags), \121 } \122 }123 124static inline struct ccu_mux *hw_to_ccu_mux(struct clk_hw *hw)125{126 struct ccu_common *common = hw_to_ccu_common(hw);127 128 return container_of(common, struct ccu_mux, common);129}130 131extern const struct clk_ops ccu_mux_ops;132 133unsigned long ccu_mux_helper_apply_prediv(struct ccu_common *common,134 struct ccu_mux_internal *cm,135 int parent_index,136 unsigned long parent_rate);137int ccu_mux_helper_determine_rate(struct ccu_common *common,138 struct ccu_mux_internal *cm,139 struct clk_rate_request *req,140 unsigned long (*round)(struct ccu_mux_internal *,141 struct clk_hw *,142 unsigned long *,143 unsigned long,144 void *),145 void *data);146u8 ccu_mux_helper_get_parent(struct ccu_common *common,147 struct ccu_mux_internal *cm);148int ccu_mux_helper_set_parent(struct ccu_common *common,149 struct ccu_mux_internal *cm,150 u8 index);151 152struct ccu_mux_nb {153 struct notifier_block clk_nb;154 struct ccu_common *common;155 struct ccu_mux_internal *cm;156 157 u32 delay_us; /* How many us to wait after reparenting */158 u8 bypass_index; /* Which parent to temporarily use */159 u8 original_index; /* This is set by the notifier callback */160};161 162#define to_ccu_mux_nb(_nb) container_of(_nb, struct ccu_mux_nb, clk_nb)163 164int ccu_mux_notifier_register(struct clk *clk, struct ccu_mux_nb *mux_nb);165 166#endif /* _CCU_MUX_H_ */167