1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Copyright (c) 2023 Linaro Ltd.
4  * Sam Protsenko <semen.protsenko@linaro.org>
5  *
6  * Common Clock Framework support for all Samsung platforms.
7  */
8 
9 #ifndef __EXYNOS_CLK_H
10 #define __EXYNOS_CLK_H
11 
12 #include <errno.h>
13 #include <linux/clk-provider.h>
14 #include "clk-pll.h"
15 
16 #define _SAMSUNG_CLK_OPS(_name, _cmu)					\
17 static int _name##_of_xlate(struct clk *clk,				\
18 			    struct ofnode_phandle_args *args)		\
19 {									\
20 	if (args->args_count > 1) {					\
21 		debug("Invalid args_count: %d\n", args->args_count);	\
22 		return -EINVAL;						\
23 	}								\
24 									\
25 	if (args->args_count)						\
26 		clk->id = SAMSUNG_TO_CLK_ID(_cmu, args->args[0]);	\
27 	else								\
28 		clk->id = 0;						\
29 									\
30 	return 0;							\
31 }									\
32 									\
33 static const struct clk_ops _name##_clk_ops = {				\
34 	.set_rate = ccf_clk_set_rate,					\
35 	.get_rate = ccf_clk_get_rate,					\
36 	.set_parent = ccf_clk_set_parent,				\
37 	.enable = ccf_clk_enable,					\
38 	.disable = ccf_clk_disable,					\
39 	.of_xlate = _name##_of_xlate,					\
40 }
41 
42 /**
43  * SAMSUNG_CLK_OPS - Define clock operations structure for specified CMU.
44  * @name: name of generated structure
45  * @cmu: CMU index
46  *
47  * Like ccf_clk_ops, but with custom .of_xlate callback.
48  */
49 #define SAMSUNG_CLK_OPS(name, cmu) _SAMSUNG_CLK_OPS(name, cmu)
50 
51 /**
52  * SAMSUNG_TO_CLK_ID - Calculate a global clock index.
53  * @_cmu: CMU index
54  * @_id: local clock index (unique across @_cmu)
55  *
56  * Return: A global clock index unique across all CMUs.
57  * Keeps a range of 256 available clocks for every CMU.
58  */
59 #define SAMSUNG_TO_CLK_ID(_cmu, _id)	(((_cmu) << 8) | ((_id) & 0xff))
60 
61 /**
62  * struct samsung_mux_clock - information about mux clock
63  * @id: platform specific id of the clock
64  * @name: name of this mux clock
65  * @parent_names: array of pointer to parent clock names
66  * @num_parents: number of parents listed in @parent_names
67  * @flags: optional flags for basic clock
68  * @offset: offset of the register for configuring the mux
69  * @shift: starting bit location of the mux control bit-field in @reg
70  * @width: width of the mux control bit-field in @reg
71  * @mux_flags: flags for mux-type clock
72  */
73 struct samsung_mux_clock {
74 	unsigned int		id;
75 	const char		*name;
76 	const char		* const *parent_names;
77 	u8			num_parents;
78 	unsigned long		flags;
79 	unsigned long		offset;
80 	u8			shift;
81 	u8			width;
82 	u8			mux_flags;
83 };
84 
85 #define PNAME(x) static const char * const x[]
86 
87 #define __MUX(_id, cname, pnames, o, s, w, f, mf)			\
88 	{								\
89 		.id		= _id,					\
90 		.name		= cname,				\
91 		.parent_names	= pnames,				\
92 		.num_parents	= ARRAY_SIZE(pnames),			\
93 		.flags		= (f) | CLK_SET_RATE_NO_REPARENT,	\
94 		.offset		= o,					\
95 		.shift		= s,					\
96 		.width		= w,					\
97 		.mux_flags	= mf,					\
98 	}
99 
100 #define MUX(_id, cname, pnames, o, s, w)				\
101 	__MUX(_id, cname, pnames, o, s, w, 0, 0)
102 
103 #define MUX_F(_id, cname, pnames, o, s, w, f, mf)			\
104 	__MUX(_id, cname, pnames, o, s, w, f, mf)
105 
106 /**
107  * struct samsung_div_clock - information about div clock
108  * @id: platform specific id of the clock
109  * @name: name of this div clock
110  * @parent_name: name of the parent clock
111  * @flags: optional flags for basic clock
112  * @offset: offset of the register for configuring the div
113  * @shift: starting bit location of the div control bit-field in @reg
114  * @width: width of the bitfield
115  * @div_flags: flags for div-type clock
116  */
117 struct samsung_div_clock {
118 	unsigned int		id;
119 	const char		*name;
120 	const char		*parent_name;
121 	unsigned long		flags;
122 	unsigned long		offset;
123 	u8			shift;
124 	u8			width;
125 	u8			div_flags;
126 };
127 
128 #define __DIV(_id, cname, pname, o, s, w, f, df)	\
129 	{						\
130 		.id		= _id,			\
131 		.name		= cname,		\
132 		.parent_name	= pname,		\
133 		.flags		= f,			\
134 		.offset		= o,			\
135 		.shift		= s,			\
136 		.width		= w,			\
137 		.div_flags	= df,			\
138 	}
139 
140 #define DIV(_id, cname, pname, o, s, w)			\
141 	__DIV(_id, cname, pname, o, s, w, 0, 0)
142 
143 #define DIV_F(_id, cname, pname, o, s, w, f, df)	\
144 	__DIV(_id, cname, pname, o, s, w, f, df)
145 
146 /**
147  * struct samsung_gate_clock - information about gate clock
148  * @id: platform specific id of the clock
149  * @name: name of this gate clock
150  * @parent_name: name of the parent clock
151  * @flags: optional flags for basic clock
152  * @offset: offset of the register for configuring the gate
153  * @bit_idx: bit index of the gate control bit-field in @reg
154  * @gate_flags: flags for gate-type clock
155  */
156 struct samsung_gate_clock {
157 	unsigned int		id;
158 	const char		*name;
159 	const char		*parent_name;
160 	unsigned long		flags;
161 	unsigned long		offset;
162 	u8			bit_idx;
163 	u8			gate_flags;
164 };
165 
166 #define __GATE(_id, cname, pname, o, b, f, gf)			\
167 	{							\
168 		.id		= _id,				\
169 		.name		= cname,			\
170 		.parent_name	= pname,			\
171 		.flags		= f,				\
172 		.offset		= o,				\
173 		.bit_idx	= b,				\
174 		.gate_flags	= gf,				\
175 	}
176 
177 #define GATE(_id, cname, pname, o, b, f, gf)			\
178 	__GATE(_id, cname, pname, o, b, f, gf)
179 
180 /**
181  * struct samsung_pll_clock - information about pll clock
182  * @id: platform specific id of the clock
183  * @name: name of this pll clock
184  * @parent_name: name of the parent clock
185  * @flags: optional flags for basic clock
186  * @con_offset: offset of the register for configuring the PLL
187  * @type: type of PLL to be registered
188  */
189 struct samsung_pll_clock {
190 	unsigned int		id;
191 	const char		*name;
192 	const char		*parent_name;
193 	unsigned long		flags;
194 	int			con_offset;
195 	enum samsung_pll_type	type;
196 };
197 
198 #define PLL(_typ, _id, _name, _pname, _con)		\
199 	{						\
200 		.id		= _id,			\
201 		.name		= _name,		\
202 		.parent_name	= _pname,		\
203 		.flags		= CLK_GET_RATE_NOCACHE,	\
204 		.con_offset	= _con,			\
205 		.type		= _typ,			\
206 	}
207 
208 enum samsung_clock_type {
209 	S_CLK_MUX,
210 	S_CLK_DIV,
211 	S_CLK_GATE,
212 	S_CLK_PLL,
213 };
214 
215 /**
216  * struct samsung_clock_group - contains a list of clocks of one type
217  * @type: type of clocks this structure contains
218  * @clk_list: list of clocks
219  * @nr_clk: count of clocks in @clk_list
220  */
221 struct samsung_clk_group {
222 	enum samsung_clock_type type;
223 	const void *clk_list;
224 	unsigned int nr_clk;
225 };
226 
227 int samsung_cmu_register_one(struct udevice *dev, unsigned int cmu_id,
228 			     const struct samsung_clk_group *clk_groups,
229 			     unsigned int nr_groups);
230 
231 /**
232  * samsung_register_cmu - Register CMU clocks ensuring parent CMU is present
233  * @dev: CMU device
234  * @cmu_id: CMU index number
235  * @clk_groups: list of CMU clock groups
236  * @parent_drv: name of parent CMU driver
237  *
238  * Register provided CMU clocks, but make sure CMU_TOP driver is instantiated
239  * first.
240  *
241  * Return: 0 on success or negative value on error.
242  */
243 #define samsung_register_cmu(dev, cmu_id, clk_groups, parent_drv)	\
244 ({									\
245 	struct udevice *__parent;					\
246 	int __ret;							\
247 									\
248 	__ret = uclass_get_device_by_driver(UCLASS_CLK,			\
249 		DM_DRIVER_GET(parent_drv), &__parent);			\
250 	if (__ret || !__parent)						\
251 		__ret = -ENOENT;					\
252 	else								\
253 		__ret = samsung_cmu_register_one(dev, cmu_id,		\
254 			clk_groups, ARRAY_SIZE(clk_groups));		\
255 	__ret;								\
256 })
257 
258 #endif /* __EXYNOS_CLK_H */
259