blob: ed0a395f0f636eea40c63dd7bbd2dbcaf8ae2b0b [file] [log] [blame]
Sam Protsenko8a0f6342024-01-10 21:09:03 -06001/* 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
Sam Protsenko62112352024-03-07 20:18:57 -060016#define _SAMSUNG_CLK_OPS(_name, _cmu) \
17static 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 \
33static 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
Sam Protsenko8a0f6342024-01-10 21:09:03 -060061/**
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 */
73struct 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 */
117struct 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 */
156struct 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 */
189struct 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
208enum 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 */
221struct samsung_clk_group {
222 enum samsung_clock_type type;
223 const void *clk_list;
224 unsigned int nr_clk;
225};
226
Sam Protsenko62112352024-03-07 20:18:57 -0600227int samsung_cmu_register_one(struct udevice *dev, unsigned int cmu_id,
Sam Protsenko8a0f6342024-01-10 21:09:03 -0600228 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
Sam Protsenko62112352024-03-07 20:18:57 -0600234 * @cmu_id: CMU index number
Sam Protsenko8a0f6342024-01-10 21:09:03 -0600235 * @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 */
Sam Protsenko62112352024-03-07 20:18:57 -0600243#define samsung_register_cmu(dev, cmu_id, clk_groups, parent_drv) \
Sam Protsenko8a0f6342024-01-10 21:09:03 -0600244({ \
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 \
Sam Protsenko62112352024-03-07 20:18:57 -0600253 __ret = samsung_cmu_register_one(dev, cmu_id, \
254 clk_groups, ARRAY_SIZE(clk_groups)); \
Sam Protsenko8a0f6342024-01-10 21:09:03 -0600255 __ret; \
256})
257
258#endif /* __EXYNOS_CLK_H */