18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2020-2022 MaxLinear, Inc.
48c2ecf20Sopenharmony_ci * Copyright (C) 2020 Intel Corporation.
58c2ecf20Sopenharmony_ci * Zhu Yixin <yzhu@maxlinear.com>
68c2ecf20Sopenharmony_ci * Rahul Tanwar <rtanwar@maxlinear.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#ifndef __CLK_CGU_H
108c2ecf20Sopenharmony_ci#define __CLK_CGU_H
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/regmap.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_cistruct lgm_clk_mux {
158c2ecf20Sopenharmony_ci	struct clk_hw hw;
168c2ecf20Sopenharmony_ci	struct regmap *membase;
178c2ecf20Sopenharmony_ci	unsigned int reg;
188c2ecf20Sopenharmony_ci	u8 shift;
198c2ecf20Sopenharmony_ci	u8 width;
208c2ecf20Sopenharmony_ci	unsigned long flags;
218c2ecf20Sopenharmony_ci};
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistruct lgm_clk_divider {
248c2ecf20Sopenharmony_ci	struct clk_hw hw;
258c2ecf20Sopenharmony_ci	struct regmap *membase;
268c2ecf20Sopenharmony_ci	unsigned int reg;
278c2ecf20Sopenharmony_ci	u8 shift;
288c2ecf20Sopenharmony_ci	u8 width;
298c2ecf20Sopenharmony_ci	u8 shift_gate;
308c2ecf20Sopenharmony_ci	u8 width_gate;
318c2ecf20Sopenharmony_ci	unsigned long flags;
328c2ecf20Sopenharmony_ci	const struct clk_div_table *table;
338c2ecf20Sopenharmony_ci};
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistruct lgm_clk_ddiv {
368c2ecf20Sopenharmony_ci	struct clk_hw hw;
378c2ecf20Sopenharmony_ci	struct regmap *membase;
388c2ecf20Sopenharmony_ci	unsigned int reg;
398c2ecf20Sopenharmony_ci	u8 shift0;
408c2ecf20Sopenharmony_ci	u8 width0;
418c2ecf20Sopenharmony_ci	u8 shift1;
428c2ecf20Sopenharmony_ci	u8 width1;
438c2ecf20Sopenharmony_ci	u8 shift2;
448c2ecf20Sopenharmony_ci	u8 width2;
458c2ecf20Sopenharmony_ci	u8 shift_gate;
468c2ecf20Sopenharmony_ci	u8 width_gate;
478c2ecf20Sopenharmony_ci	unsigned int mult;
488c2ecf20Sopenharmony_ci	unsigned int div;
498c2ecf20Sopenharmony_ci	unsigned long flags;
508c2ecf20Sopenharmony_ci};
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistruct lgm_clk_gate {
538c2ecf20Sopenharmony_ci	struct clk_hw hw;
548c2ecf20Sopenharmony_ci	struct regmap *membase;
558c2ecf20Sopenharmony_ci	unsigned int reg;
568c2ecf20Sopenharmony_ci	u8 shift;
578c2ecf20Sopenharmony_ci	unsigned long flags;
588c2ecf20Sopenharmony_ci};
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_cienum lgm_clk_type {
618c2ecf20Sopenharmony_ci	CLK_TYPE_FIXED,
628c2ecf20Sopenharmony_ci	CLK_TYPE_MUX,
638c2ecf20Sopenharmony_ci	CLK_TYPE_DIVIDER,
648c2ecf20Sopenharmony_ci	CLK_TYPE_FIXED_FACTOR,
658c2ecf20Sopenharmony_ci	CLK_TYPE_GATE,
668c2ecf20Sopenharmony_ci	CLK_TYPE_NONE,
678c2ecf20Sopenharmony_ci};
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci/**
708c2ecf20Sopenharmony_ci * struct lgm_clk_provider
718c2ecf20Sopenharmony_ci * @membase: IO mem base address for CGU.
728c2ecf20Sopenharmony_ci * @np: device node
738c2ecf20Sopenharmony_ci * @dev: device
748c2ecf20Sopenharmony_ci * @clk_data: array of hw clocks and clk number.
758c2ecf20Sopenharmony_ci */
768c2ecf20Sopenharmony_cistruct lgm_clk_provider {
778c2ecf20Sopenharmony_ci	struct regmap *membase;
788c2ecf20Sopenharmony_ci	struct device_node *np;
798c2ecf20Sopenharmony_ci	struct device *dev;
808c2ecf20Sopenharmony_ci	struct clk_hw_onecell_data clk_data;
818c2ecf20Sopenharmony_ci};
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cienum pll_type {
848c2ecf20Sopenharmony_ci	TYPE_ROPLL,
858c2ecf20Sopenharmony_ci	TYPE_LJPLL,
868c2ecf20Sopenharmony_ci	TYPE_NONE,
878c2ecf20Sopenharmony_ci};
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistruct lgm_clk_pll {
908c2ecf20Sopenharmony_ci	struct clk_hw hw;
918c2ecf20Sopenharmony_ci	struct regmap *membase;
928c2ecf20Sopenharmony_ci	unsigned int reg;
938c2ecf20Sopenharmony_ci	unsigned long flags;
948c2ecf20Sopenharmony_ci	enum pll_type type;
958c2ecf20Sopenharmony_ci};
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/**
988c2ecf20Sopenharmony_ci * struct lgm_pll_clk_data
998c2ecf20Sopenharmony_ci * @id: platform specific id of the clock.
1008c2ecf20Sopenharmony_ci * @name: name of this pll clock.
1018c2ecf20Sopenharmony_ci * @parent_data: parent clock data.
1028c2ecf20Sopenharmony_ci * @num_parents: number of parents.
1038c2ecf20Sopenharmony_ci * @flags: optional flags for basic clock.
1048c2ecf20Sopenharmony_ci * @type: platform type of pll.
1058c2ecf20Sopenharmony_ci * @reg: offset of the register.
1068c2ecf20Sopenharmony_ci */
1078c2ecf20Sopenharmony_cistruct lgm_pll_clk_data {
1088c2ecf20Sopenharmony_ci	unsigned int id;
1098c2ecf20Sopenharmony_ci	const char *name;
1108c2ecf20Sopenharmony_ci	const struct clk_parent_data *parent_data;
1118c2ecf20Sopenharmony_ci	u8 num_parents;
1128c2ecf20Sopenharmony_ci	unsigned long flags;
1138c2ecf20Sopenharmony_ci	enum pll_type type;
1148c2ecf20Sopenharmony_ci	int reg;
1158c2ecf20Sopenharmony_ci};
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci#define LGM_PLL(_id, _name, _pdata, _flags,		\
1188c2ecf20Sopenharmony_ci		_reg, _type)				\
1198c2ecf20Sopenharmony_ci	{						\
1208c2ecf20Sopenharmony_ci		.id = _id,				\
1218c2ecf20Sopenharmony_ci		.name = _name,				\
1228c2ecf20Sopenharmony_ci		.parent_data = _pdata,			\
1238c2ecf20Sopenharmony_ci		.num_parents = ARRAY_SIZE(_pdata),	\
1248c2ecf20Sopenharmony_ci		.flags = _flags,			\
1258c2ecf20Sopenharmony_ci		.reg = _reg,				\
1268c2ecf20Sopenharmony_ci		.type = _type,				\
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistruct lgm_clk_ddiv_data {
1308c2ecf20Sopenharmony_ci	unsigned int id;
1318c2ecf20Sopenharmony_ci	const char *name;
1328c2ecf20Sopenharmony_ci	const struct clk_parent_data *parent_data;
1338c2ecf20Sopenharmony_ci	u8 flags;
1348c2ecf20Sopenharmony_ci	unsigned long div_flags;
1358c2ecf20Sopenharmony_ci	unsigned int reg;
1368c2ecf20Sopenharmony_ci	u8 shift0;
1378c2ecf20Sopenharmony_ci	u8 width0;
1388c2ecf20Sopenharmony_ci	u8 shift1;
1398c2ecf20Sopenharmony_ci	u8 width1;
1408c2ecf20Sopenharmony_ci	u8 shift_gate;
1418c2ecf20Sopenharmony_ci	u8 width_gate;
1428c2ecf20Sopenharmony_ci	u8 ex_shift;
1438c2ecf20Sopenharmony_ci	u8 ex_width;
1448c2ecf20Sopenharmony_ci};
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci#define LGM_DDIV(_id, _name, _pname, _flags, _reg,		\
1478c2ecf20Sopenharmony_ci		 _shft0, _wdth0, _shft1, _wdth1,		\
1488c2ecf20Sopenharmony_ci		 _shft_gate, _wdth_gate, _xshft, _df)		\
1498c2ecf20Sopenharmony_ci	{							\
1508c2ecf20Sopenharmony_ci		.id = _id,					\
1518c2ecf20Sopenharmony_ci		.name = _name,					\
1528c2ecf20Sopenharmony_ci		.parent_data = &(const struct clk_parent_data){	\
1538c2ecf20Sopenharmony_ci			.fw_name = _pname,			\
1548c2ecf20Sopenharmony_ci			.name = _pname,				\
1558c2ecf20Sopenharmony_ci		},						\
1568c2ecf20Sopenharmony_ci		.flags = _flags,				\
1578c2ecf20Sopenharmony_ci		.reg = _reg,					\
1588c2ecf20Sopenharmony_ci		.shift0 = _shft0,				\
1598c2ecf20Sopenharmony_ci		.width0 = _wdth0,				\
1608c2ecf20Sopenharmony_ci		.shift1 = _shft1,				\
1618c2ecf20Sopenharmony_ci		.width1 = _wdth1,				\
1628c2ecf20Sopenharmony_ci		.shift_gate = _shft_gate,			\
1638c2ecf20Sopenharmony_ci		.width_gate = _wdth_gate,			\
1648c2ecf20Sopenharmony_ci		.ex_shift = _xshft,				\
1658c2ecf20Sopenharmony_ci		.ex_width = 1,					\
1668c2ecf20Sopenharmony_ci		.div_flags = _df,				\
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistruct lgm_clk_branch {
1708c2ecf20Sopenharmony_ci	unsigned int id;
1718c2ecf20Sopenharmony_ci	enum lgm_clk_type type;
1728c2ecf20Sopenharmony_ci	const char *name;
1738c2ecf20Sopenharmony_ci	const struct clk_parent_data *parent_data;
1748c2ecf20Sopenharmony_ci	u8 num_parents;
1758c2ecf20Sopenharmony_ci	unsigned long flags;
1768c2ecf20Sopenharmony_ci	unsigned int mux_off;
1778c2ecf20Sopenharmony_ci	u8 mux_shift;
1788c2ecf20Sopenharmony_ci	u8 mux_width;
1798c2ecf20Sopenharmony_ci	unsigned long mux_flags;
1808c2ecf20Sopenharmony_ci	unsigned int mux_val;
1818c2ecf20Sopenharmony_ci	unsigned int div_off;
1828c2ecf20Sopenharmony_ci	u8 div_shift;
1838c2ecf20Sopenharmony_ci	u8 div_width;
1848c2ecf20Sopenharmony_ci	u8 div_shift_gate;
1858c2ecf20Sopenharmony_ci	u8 div_width_gate;
1868c2ecf20Sopenharmony_ci	unsigned long div_flags;
1878c2ecf20Sopenharmony_ci	unsigned int div_val;
1888c2ecf20Sopenharmony_ci	const struct clk_div_table *div_table;
1898c2ecf20Sopenharmony_ci	unsigned int gate_off;
1908c2ecf20Sopenharmony_ci	u8 gate_shift;
1918c2ecf20Sopenharmony_ci	unsigned long gate_flags;
1928c2ecf20Sopenharmony_ci	unsigned int gate_val;
1938c2ecf20Sopenharmony_ci	unsigned int mult;
1948c2ecf20Sopenharmony_ci	unsigned int div;
1958c2ecf20Sopenharmony_ci};
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci/* clock flags definition */
1988c2ecf20Sopenharmony_ci#define CLOCK_FLAG_VAL_INIT	BIT(16)
1998c2ecf20Sopenharmony_ci#define MUX_CLK_SW		BIT(17)
2008c2ecf20Sopenharmony_ci#define GATE_CLK_HW		BIT(18)
2018c2ecf20Sopenharmony_ci#define DIV_CLK_NO_MASK		BIT(19)
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci#define LGM_MUX(_id, _name, _pdata, _f, _reg,		\
2048c2ecf20Sopenharmony_ci		_shift, _width, _cf, _v)		\
2058c2ecf20Sopenharmony_ci	{						\
2068c2ecf20Sopenharmony_ci		.id = _id,				\
2078c2ecf20Sopenharmony_ci		.type = CLK_TYPE_MUX,			\
2088c2ecf20Sopenharmony_ci		.name = _name,				\
2098c2ecf20Sopenharmony_ci		.parent_data = _pdata,			\
2108c2ecf20Sopenharmony_ci		.num_parents = ARRAY_SIZE(_pdata),	\
2118c2ecf20Sopenharmony_ci		.flags = _f,				\
2128c2ecf20Sopenharmony_ci		.mux_off = _reg,			\
2138c2ecf20Sopenharmony_ci		.mux_shift = _shift,			\
2148c2ecf20Sopenharmony_ci		.mux_width = _width,			\
2158c2ecf20Sopenharmony_ci		.mux_flags = _cf,			\
2168c2ecf20Sopenharmony_ci		.mux_val = _v,				\
2178c2ecf20Sopenharmony_ci	}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci#define LGM_DIV(_id, _name, _pname, _f, _reg, _shift, _width,	\
2208c2ecf20Sopenharmony_ci		_shift_gate, _width_gate, _cf, _v, _dtable)	\
2218c2ecf20Sopenharmony_ci	{							\
2228c2ecf20Sopenharmony_ci		.id = _id,					\
2238c2ecf20Sopenharmony_ci		.type = CLK_TYPE_DIVIDER,			\
2248c2ecf20Sopenharmony_ci		.name = _name,					\
2258c2ecf20Sopenharmony_ci		.parent_data = &(const struct clk_parent_data){	\
2268c2ecf20Sopenharmony_ci			.fw_name = _pname,			\
2278c2ecf20Sopenharmony_ci			.name = _pname,				\
2288c2ecf20Sopenharmony_ci		},						\
2298c2ecf20Sopenharmony_ci		.num_parents = 1,				\
2308c2ecf20Sopenharmony_ci		.flags = _f,					\
2318c2ecf20Sopenharmony_ci		.div_off = _reg,				\
2328c2ecf20Sopenharmony_ci		.div_shift = _shift,				\
2338c2ecf20Sopenharmony_ci		.div_width = _width,				\
2348c2ecf20Sopenharmony_ci		.div_shift_gate = _shift_gate,			\
2358c2ecf20Sopenharmony_ci		.div_width_gate = _width_gate,			\
2368c2ecf20Sopenharmony_ci		.div_flags = _cf,				\
2378c2ecf20Sopenharmony_ci		.div_val = _v,					\
2388c2ecf20Sopenharmony_ci		.div_table = _dtable,				\
2398c2ecf20Sopenharmony_ci	}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci#define LGM_GATE(_id, _name, _pname, _f, _reg,			\
2428c2ecf20Sopenharmony_ci		 _shift, _cf, _v)				\
2438c2ecf20Sopenharmony_ci	{							\
2448c2ecf20Sopenharmony_ci		.id = _id,					\
2458c2ecf20Sopenharmony_ci		.type = CLK_TYPE_GATE,				\
2468c2ecf20Sopenharmony_ci		.name = _name,					\
2478c2ecf20Sopenharmony_ci		.parent_data = &(const struct clk_parent_data){	\
2488c2ecf20Sopenharmony_ci			.fw_name = _pname,			\
2498c2ecf20Sopenharmony_ci			.name = _pname,				\
2508c2ecf20Sopenharmony_ci		},						\
2518c2ecf20Sopenharmony_ci		.num_parents = !_pname ? 0 : 1,			\
2528c2ecf20Sopenharmony_ci		.flags = _f,					\
2538c2ecf20Sopenharmony_ci		.gate_off = _reg,				\
2548c2ecf20Sopenharmony_ci		.gate_shift = _shift,				\
2558c2ecf20Sopenharmony_ci		.gate_flags = _cf,				\
2568c2ecf20Sopenharmony_ci		.gate_val = _v,					\
2578c2ecf20Sopenharmony_ci	}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci#define LGM_FIXED(_id, _name, _pname, _f, _reg,			\
2608c2ecf20Sopenharmony_ci		  _shift, _width, _cf, _freq, _v)		\
2618c2ecf20Sopenharmony_ci	{							\
2628c2ecf20Sopenharmony_ci		.id = _id,					\
2638c2ecf20Sopenharmony_ci		.type = CLK_TYPE_FIXED,				\
2648c2ecf20Sopenharmony_ci		.name = _name,					\
2658c2ecf20Sopenharmony_ci		.parent_data = &(const struct clk_parent_data){	\
2668c2ecf20Sopenharmony_ci			.fw_name = _pname,			\
2678c2ecf20Sopenharmony_ci			.name = _pname,				\
2688c2ecf20Sopenharmony_ci		},						\
2698c2ecf20Sopenharmony_ci		.num_parents = !_pname ? 0 : 1,			\
2708c2ecf20Sopenharmony_ci		.flags = _f,					\
2718c2ecf20Sopenharmony_ci		.div_off = _reg,				\
2728c2ecf20Sopenharmony_ci		.div_shift = _shift,				\
2738c2ecf20Sopenharmony_ci		.div_width = _width,				\
2748c2ecf20Sopenharmony_ci		.div_flags = _cf,				\
2758c2ecf20Sopenharmony_ci		.div_val = _v,					\
2768c2ecf20Sopenharmony_ci		.mux_flags = _freq,				\
2778c2ecf20Sopenharmony_ci	}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci#define LGM_FIXED_FACTOR(_id, _name, _pname, _f, _reg,		\
2808c2ecf20Sopenharmony_ci			 _shift, _width, _cf, _v, _m, _d)	\
2818c2ecf20Sopenharmony_ci	{							\
2828c2ecf20Sopenharmony_ci		.id = _id,					\
2838c2ecf20Sopenharmony_ci		.type = CLK_TYPE_FIXED_FACTOR,			\
2848c2ecf20Sopenharmony_ci		.name = _name,					\
2858c2ecf20Sopenharmony_ci		.parent_data = &(const struct clk_parent_data){	\
2868c2ecf20Sopenharmony_ci			.fw_name = _pname,			\
2878c2ecf20Sopenharmony_ci			.name = _pname,				\
2888c2ecf20Sopenharmony_ci		},						\
2898c2ecf20Sopenharmony_ci		.num_parents = 1,				\
2908c2ecf20Sopenharmony_ci		.flags = _f,					\
2918c2ecf20Sopenharmony_ci		.div_off = _reg,				\
2928c2ecf20Sopenharmony_ci		.div_shift = _shift,				\
2938c2ecf20Sopenharmony_ci		.div_width = _width,				\
2948c2ecf20Sopenharmony_ci		.div_flags = _cf,				\
2958c2ecf20Sopenharmony_ci		.div_val = _v,					\
2968c2ecf20Sopenharmony_ci		.mult = _m,					\
2978c2ecf20Sopenharmony_ci		.div = _d,					\
2988c2ecf20Sopenharmony_ci	}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_cistatic inline void lgm_set_clk_val(struct regmap *membase, u32 reg,
3018c2ecf20Sopenharmony_ci				   u8 shift, u8 width, u32 set_val)
3028c2ecf20Sopenharmony_ci{
3038c2ecf20Sopenharmony_ci	u32 mask = (GENMASK(width - 1, 0) << shift);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	regmap_update_bits(membase, reg, mask, set_val << shift);
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistatic inline u32 lgm_get_clk_val(struct regmap *membase, u32 reg,
3098c2ecf20Sopenharmony_ci				  u8 shift, u8 width)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	u32 mask = (GENMASK(width - 1, 0) << shift);
3128c2ecf20Sopenharmony_ci	u32 val;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	if (regmap_read(membase, reg, &val)) {
3158c2ecf20Sopenharmony_ci		WARN_ONCE(1, "Failed to read clk reg: 0x%x\n", reg);
3168c2ecf20Sopenharmony_ci		return 0;
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	val = (val & mask) >> shift;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	return val;
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ciint lgm_clk_register_branches(struct lgm_clk_provider *ctx,
3278c2ecf20Sopenharmony_ci			      const struct lgm_clk_branch *list,
3288c2ecf20Sopenharmony_ci			      unsigned int nr_clk);
3298c2ecf20Sopenharmony_ciint lgm_clk_register_plls(struct lgm_clk_provider *ctx,
3308c2ecf20Sopenharmony_ci			  const struct lgm_pll_clk_data *list,
3318c2ecf20Sopenharmony_ci			  unsigned int nr_clk);
3328c2ecf20Sopenharmony_ciint lgm_clk_register_ddiv(struct lgm_clk_provider *ctx,
3338c2ecf20Sopenharmony_ci			  const struct lgm_clk_ddiv_data *list,
3348c2ecf20Sopenharmony_ci			  unsigned int nr_clk);
3358c2ecf20Sopenharmony_ci#endif	/* __CLK_CGU_H */
336