162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2014 MediaTek Inc.
462306a36Sopenharmony_ci * Author: James Liao <jamesjj.liao@mediatek.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#ifndef __DRV_CLK_MTK_H
862306a36Sopenharmony_ci#define __DRV_CLK_MTK_H
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/clk-provider.h>
1162306a36Sopenharmony_ci#include <linux/io.h>
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/spinlock.h>
1462306a36Sopenharmony_ci#include <linux/types.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "reset.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define MAX_MUX_GATE_BIT	31
1962306a36Sopenharmony_ci#define INVALID_MUX_GATE_BIT	(MAX_MUX_GATE_BIT + 1)
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define MHZ (1000 * 1000)
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistruct platform_device;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/*
2662306a36Sopenharmony_ci * We need the clock IDs to start from zero but to maintain devicetree
2762306a36Sopenharmony_ci * backwards compatibility we can't change bindings to start from zero.
2862306a36Sopenharmony_ci * Only a few platforms are affected, so we solve issues given by the
2962306a36Sopenharmony_ci * commonized MTK clocks probe function(s) by adding a dummy clock at
3062306a36Sopenharmony_ci * the beginning where needed.
3162306a36Sopenharmony_ci */
3262306a36Sopenharmony_ci#define CLK_DUMMY		0
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ciextern const struct clk_ops mtk_clk_dummy_ops;
3562306a36Sopenharmony_ciextern const struct mtk_gate_regs cg_regs_dummy;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#define GATE_DUMMY(_id, _name) {				\
3862306a36Sopenharmony_ci		.id = _id,					\
3962306a36Sopenharmony_ci		.name = _name,					\
4062306a36Sopenharmony_ci		.regs = &cg_regs_dummy,				\
4162306a36Sopenharmony_ci		.ops = &mtk_clk_dummy_ops,			\
4262306a36Sopenharmony_ci	}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistruct mtk_fixed_clk {
4562306a36Sopenharmony_ci	int id;
4662306a36Sopenharmony_ci	const char *name;
4762306a36Sopenharmony_ci	const char *parent;
4862306a36Sopenharmony_ci	unsigned long rate;
4962306a36Sopenharmony_ci};
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define FIXED_CLK(_id, _name, _parent, _rate) {		\
5262306a36Sopenharmony_ci		.id = _id,				\
5362306a36Sopenharmony_ci		.name = _name,				\
5462306a36Sopenharmony_ci		.parent = _parent,			\
5562306a36Sopenharmony_ci		.rate = _rate,				\
5662306a36Sopenharmony_ci	}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ciint mtk_clk_register_fixed_clks(const struct mtk_fixed_clk *clks, int num,
5962306a36Sopenharmony_ci				struct clk_hw_onecell_data *clk_data);
6062306a36Sopenharmony_civoid mtk_clk_unregister_fixed_clks(const struct mtk_fixed_clk *clks, int num,
6162306a36Sopenharmony_ci				   struct clk_hw_onecell_data *clk_data);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistruct mtk_fixed_factor {
6462306a36Sopenharmony_ci	int id;
6562306a36Sopenharmony_ci	const char *name;
6662306a36Sopenharmony_ci	const char *parent_name;
6762306a36Sopenharmony_ci	int mult;
6862306a36Sopenharmony_ci	int div;
6962306a36Sopenharmony_ci	unsigned long flags;
7062306a36Sopenharmony_ci};
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#define FACTOR_FLAGS(_id, _name, _parent, _mult, _div, _fl) {	\
7362306a36Sopenharmony_ci		.id = _id,				\
7462306a36Sopenharmony_ci		.name = _name,				\
7562306a36Sopenharmony_ci		.parent_name = _parent,			\
7662306a36Sopenharmony_ci		.mult = _mult,				\
7762306a36Sopenharmony_ci		.div = _div,				\
7862306a36Sopenharmony_ci		.flags = _fl,				\
7962306a36Sopenharmony_ci	}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#define FACTOR(_id, _name, _parent, _mult, _div)	\
8262306a36Sopenharmony_ci	FACTOR_FLAGS(_id, _name, _parent, _mult, _div, CLK_SET_RATE_PARENT)
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ciint mtk_clk_register_factors(const struct mtk_fixed_factor *clks, int num,
8562306a36Sopenharmony_ci			     struct clk_hw_onecell_data *clk_data);
8662306a36Sopenharmony_civoid mtk_clk_unregister_factors(const struct mtk_fixed_factor *clks, int num,
8762306a36Sopenharmony_ci				struct clk_hw_onecell_data *clk_data);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistruct mtk_composite {
9062306a36Sopenharmony_ci	int id;
9162306a36Sopenharmony_ci	const char *name;
9262306a36Sopenharmony_ci	const char * const *parent_names;
9362306a36Sopenharmony_ci	const char *parent;
9462306a36Sopenharmony_ci	unsigned flags;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	uint32_t mux_reg;
9762306a36Sopenharmony_ci	uint32_t divider_reg;
9862306a36Sopenharmony_ci	uint32_t gate_reg;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	signed char mux_shift;
10162306a36Sopenharmony_ci	signed char mux_width;
10262306a36Sopenharmony_ci	signed char gate_shift;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	signed char divider_shift;
10562306a36Sopenharmony_ci	signed char divider_width;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	u8 mux_flags;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	signed char num_parents;
11062306a36Sopenharmony_ci};
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci#define MUX_GATE_FLAGS_2(_id, _name, _parents, _reg, _shift,		\
11362306a36Sopenharmony_ci				_width, _gate, _flags, _muxflags) {	\
11462306a36Sopenharmony_ci		.id = _id,						\
11562306a36Sopenharmony_ci		.name = _name,						\
11662306a36Sopenharmony_ci		.mux_reg = _reg,					\
11762306a36Sopenharmony_ci		.mux_shift = _shift,					\
11862306a36Sopenharmony_ci		.mux_width = _width,					\
11962306a36Sopenharmony_ci		.gate_reg = _reg,					\
12062306a36Sopenharmony_ci		.gate_shift = _gate,					\
12162306a36Sopenharmony_ci		.divider_shift = -1,					\
12262306a36Sopenharmony_ci		.parent_names = _parents,				\
12362306a36Sopenharmony_ci		.num_parents = ARRAY_SIZE(_parents),			\
12462306a36Sopenharmony_ci		.flags = _flags,					\
12562306a36Sopenharmony_ci		.mux_flags = _muxflags,					\
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci/*
12962306a36Sopenharmony_ci * In case the rate change propagation to parent clocks is undesirable,
13062306a36Sopenharmony_ci * this macro allows to specify the clock flags manually.
13162306a36Sopenharmony_ci */
13262306a36Sopenharmony_ci#define MUX_GATE_FLAGS(_id, _name, _parents, _reg, _shift, _width,	\
13362306a36Sopenharmony_ci			_gate, _flags)					\
13462306a36Sopenharmony_ci		MUX_GATE_FLAGS_2(_id, _name, _parents, _reg,		\
13562306a36Sopenharmony_ci					_shift, _width, _gate, _flags, 0)
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci/*
13862306a36Sopenharmony_ci * Unless necessary, all MUX_GATE clocks propagate rate changes to their
13962306a36Sopenharmony_ci * parent clock by default.
14062306a36Sopenharmony_ci */
14162306a36Sopenharmony_ci#define MUX_GATE(_id, _name, _parents, _reg, _shift, _width, _gate)	\
14262306a36Sopenharmony_ci	MUX_GATE_FLAGS(_id, _name, _parents, _reg, _shift, _width,	\
14362306a36Sopenharmony_ci		_gate, CLK_SET_RATE_PARENT)
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci#define MUX(_id, _name, _parents, _reg, _shift, _width)			\
14662306a36Sopenharmony_ci	MUX_FLAGS(_id, _name, _parents, _reg,				\
14762306a36Sopenharmony_ci		  _shift, _width, CLK_SET_RATE_PARENT)
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci#define MUX_FLAGS(_id, _name, _parents, _reg, _shift, _width, _flags) {	\
15062306a36Sopenharmony_ci		.id = _id,						\
15162306a36Sopenharmony_ci		.name = _name,						\
15262306a36Sopenharmony_ci		.mux_reg = _reg,					\
15362306a36Sopenharmony_ci		.mux_shift = _shift,					\
15462306a36Sopenharmony_ci		.mux_width = _width,					\
15562306a36Sopenharmony_ci		.gate_shift = -1,					\
15662306a36Sopenharmony_ci		.divider_shift = -1,					\
15762306a36Sopenharmony_ci		.parent_names = _parents,				\
15862306a36Sopenharmony_ci		.num_parents = ARRAY_SIZE(_parents),			\
15962306a36Sopenharmony_ci		.flags = _flags,				\
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci#define DIV_GATE(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg,	\
16362306a36Sopenharmony_ci					_div_width, _div_shift) {	\
16462306a36Sopenharmony_ci		.id = _id,						\
16562306a36Sopenharmony_ci		.parent = _parent,					\
16662306a36Sopenharmony_ci		.name = _name,						\
16762306a36Sopenharmony_ci		.divider_reg = _div_reg,				\
16862306a36Sopenharmony_ci		.divider_shift = _div_shift,				\
16962306a36Sopenharmony_ci		.divider_width = _div_width,				\
17062306a36Sopenharmony_ci		.gate_reg = _gate_reg,					\
17162306a36Sopenharmony_ci		.gate_shift = _gate_shift,				\
17262306a36Sopenharmony_ci		.mux_shift = -1,					\
17362306a36Sopenharmony_ci		.flags = 0,						\
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ciint mtk_clk_register_composites(struct device *dev,
17762306a36Sopenharmony_ci				const struct mtk_composite *mcs, int num,
17862306a36Sopenharmony_ci				void __iomem *base, spinlock_t *lock,
17962306a36Sopenharmony_ci				struct clk_hw_onecell_data *clk_data);
18062306a36Sopenharmony_civoid mtk_clk_unregister_composites(const struct mtk_composite *mcs, int num,
18162306a36Sopenharmony_ci				   struct clk_hw_onecell_data *clk_data);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistruct mtk_clk_divider {
18462306a36Sopenharmony_ci	int id;
18562306a36Sopenharmony_ci	const char *name;
18662306a36Sopenharmony_ci	const char *parent_name;
18762306a36Sopenharmony_ci	unsigned long flags;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	u32 div_reg;
19062306a36Sopenharmony_ci	unsigned char div_shift;
19162306a36Sopenharmony_ci	unsigned char div_width;
19262306a36Sopenharmony_ci	unsigned char clk_divider_flags;
19362306a36Sopenharmony_ci	const struct clk_div_table *clk_div_table;
19462306a36Sopenharmony_ci};
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci#define DIV_ADJ(_id, _name, _parent, _reg, _shift, _width) {	\
19762306a36Sopenharmony_ci		.id = _id,					\
19862306a36Sopenharmony_ci		.name = _name,					\
19962306a36Sopenharmony_ci		.parent_name = _parent,				\
20062306a36Sopenharmony_ci		.div_reg = _reg,				\
20162306a36Sopenharmony_ci		.div_shift = _shift,				\
20262306a36Sopenharmony_ci		.div_width = _width,				\
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ciint mtk_clk_register_dividers(struct device *dev,
20662306a36Sopenharmony_ci			      const struct mtk_clk_divider *mcds, int num,
20762306a36Sopenharmony_ci			      void __iomem *base, spinlock_t *lock,
20862306a36Sopenharmony_ci			      struct clk_hw_onecell_data *clk_data);
20962306a36Sopenharmony_civoid mtk_clk_unregister_dividers(const struct mtk_clk_divider *mcds, int num,
21062306a36Sopenharmony_ci				 struct clk_hw_onecell_data *clk_data);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistruct clk_hw_onecell_data *mtk_alloc_clk_data(unsigned int clk_num);
21362306a36Sopenharmony_cistruct clk_hw_onecell_data *mtk_devm_alloc_clk_data(struct device *dev,
21462306a36Sopenharmony_ci						    unsigned int clk_num);
21562306a36Sopenharmony_civoid mtk_free_clk_data(struct clk_hw_onecell_data *clk_data);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistruct clk_hw *mtk_clk_register_ref2usb_tx(const char *name,
21862306a36Sopenharmony_ci			const char *parent_name, void __iomem *reg);
21962306a36Sopenharmony_civoid mtk_clk_unregister_ref2usb_tx(struct clk_hw *hw);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistruct mtk_clk_desc {
22262306a36Sopenharmony_ci	const struct mtk_gate *clks;
22362306a36Sopenharmony_ci	size_t num_clks;
22462306a36Sopenharmony_ci	const struct mtk_composite *composite_clks;
22562306a36Sopenharmony_ci	size_t num_composite_clks;
22662306a36Sopenharmony_ci	const struct mtk_clk_divider *divider_clks;
22762306a36Sopenharmony_ci	size_t num_divider_clks;
22862306a36Sopenharmony_ci	const struct mtk_fixed_clk *fixed_clks;
22962306a36Sopenharmony_ci	size_t num_fixed_clks;
23062306a36Sopenharmony_ci	const struct mtk_fixed_factor *factor_clks;
23162306a36Sopenharmony_ci	size_t num_factor_clks;
23262306a36Sopenharmony_ci	const struct mtk_mux *mux_clks;
23362306a36Sopenharmony_ci	size_t num_mux_clks;
23462306a36Sopenharmony_ci	const struct mtk_clk_rst_desc *rst_desc;
23562306a36Sopenharmony_ci	spinlock_t *clk_lock;
23662306a36Sopenharmony_ci	bool shared_io;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	int (*clk_notifier_func)(struct device *dev, struct clk *clk);
23962306a36Sopenharmony_ci	unsigned int mfg_clk_idx;
24062306a36Sopenharmony_ci};
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ciint mtk_clk_pdev_probe(struct platform_device *pdev);
24362306a36Sopenharmony_civoid mtk_clk_pdev_remove(struct platform_device *pdev);
24462306a36Sopenharmony_ciint mtk_clk_simple_probe(struct platform_device *pdev);
24562306a36Sopenharmony_civoid mtk_clk_simple_remove(struct platform_device *pdev);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci#endif /* __DRV_CLK_MTK_H */
248