blob: 91a51b877a635759e5004b0ce8eb2f3015526fca [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
16/**
17 * struct samsung_mux_clock - information about mux clock
18 * @id: platform specific id of the clock
19 * @name: name of this mux clock
20 * @parent_names: array of pointer to parent clock names
21 * @num_parents: number of parents listed in @parent_names
22 * @flags: optional flags for basic clock
23 * @offset: offset of the register for configuring the mux
24 * @shift: starting bit location of the mux control bit-field in @reg
25 * @width: width of the mux control bit-field in @reg
26 * @mux_flags: flags for mux-type clock
27 */
28struct samsung_mux_clock {
29 unsigned int id;
30 const char *name;
31 const char * const *parent_names;
32 u8 num_parents;
33 unsigned long flags;
34 unsigned long offset;
35 u8 shift;
36 u8 width;
37 u8 mux_flags;
38};
39
40#define PNAME(x) static const char * const x[]
41
42#define __MUX(_id, cname, pnames, o, s, w, f, mf) \
43 { \
44 .id = _id, \
45 .name = cname, \
46 .parent_names = pnames, \
47 .num_parents = ARRAY_SIZE(pnames), \
48 .flags = (f) | CLK_SET_RATE_NO_REPARENT, \
49 .offset = o, \
50 .shift = s, \
51 .width = w, \
52 .mux_flags = mf, \
53 }
54
55#define MUX(_id, cname, pnames, o, s, w) \
56 __MUX(_id, cname, pnames, o, s, w, 0, 0)
57
58#define MUX_F(_id, cname, pnames, o, s, w, f, mf) \
59 __MUX(_id, cname, pnames, o, s, w, f, mf)
60
61/**
62 * struct samsung_div_clock - information about div clock
63 * @id: platform specific id of the clock
64 * @name: name of this div clock
65 * @parent_name: name of the parent clock
66 * @flags: optional flags for basic clock
67 * @offset: offset of the register for configuring the div
68 * @shift: starting bit location of the div control bit-field in @reg
69 * @width: width of the bitfield
70 * @div_flags: flags for div-type clock
71 */
72struct samsung_div_clock {
73 unsigned int id;
74 const char *name;
75 const char *parent_name;
76 unsigned long flags;
77 unsigned long offset;
78 u8 shift;
79 u8 width;
80 u8 div_flags;
81};
82
83#define __DIV(_id, cname, pname, o, s, w, f, df) \
84 { \
85 .id = _id, \
86 .name = cname, \
87 .parent_name = pname, \
88 .flags = f, \
89 .offset = o, \
90 .shift = s, \
91 .width = w, \
92 .div_flags = df, \
93 }
94
95#define DIV(_id, cname, pname, o, s, w) \
96 __DIV(_id, cname, pname, o, s, w, 0, 0)
97
98#define DIV_F(_id, cname, pname, o, s, w, f, df) \
99 __DIV(_id, cname, pname, o, s, w, f, df)
100
101/**
102 * struct samsung_gate_clock - information about gate clock
103 * @id: platform specific id of the clock
104 * @name: name of this gate clock
105 * @parent_name: name of the parent clock
106 * @flags: optional flags for basic clock
107 * @offset: offset of the register for configuring the gate
108 * @bit_idx: bit index of the gate control bit-field in @reg
109 * @gate_flags: flags for gate-type clock
110 */
111struct samsung_gate_clock {
112 unsigned int id;
113 const char *name;
114 const char *parent_name;
115 unsigned long flags;
116 unsigned long offset;
117 u8 bit_idx;
118 u8 gate_flags;
119};
120
121#define __GATE(_id, cname, pname, o, b, f, gf) \
122 { \
123 .id = _id, \
124 .name = cname, \
125 .parent_name = pname, \
126 .flags = f, \
127 .offset = o, \
128 .bit_idx = b, \
129 .gate_flags = gf, \
130 }
131
132#define GATE(_id, cname, pname, o, b, f, gf) \
133 __GATE(_id, cname, pname, o, b, f, gf)
134
135/**
136 * struct samsung_pll_clock - information about pll clock
137 * @id: platform specific id of the clock
138 * @name: name of this pll clock
139 * @parent_name: name of the parent clock
140 * @flags: optional flags for basic clock
141 * @con_offset: offset of the register for configuring the PLL
142 * @type: type of PLL to be registered
143 */
144struct samsung_pll_clock {
145 unsigned int id;
146 const char *name;
147 const char *parent_name;
148 unsigned long flags;
149 int con_offset;
150 enum samsung_pll_type type;
151};
152
153#define PLL(_typ, _id, _name, _pname, _con) \
154 { \
155 .id = _id, \
156 .name = _name, \
157 .parent_name = _pname, \
158 .flags = CLK_GET_RATE_NOCACHE, \
159 .con_offset = _con, \
160 .type = _typ, \
161 }
162
163enum samsung_clock_type {
164 S_CLK_MUX,
165 S_CLK_DIV,
166 S_CLK_GATE,
167 S_CLK_PLL,
168};
169
170/**
171 * struct samsung_clock_group - contains a list of clocks of one type
172 * @type: type of clocks this structure contains
173 * @clk_list: list of clocks
174 * @nr_clk: count of clocks in @clk_list
175 */
176struct samsung_clk_group {
177 enum samsung_clock_type type;
178 const void *clk_list;
179 unsigned int nr_clk;
180};
181
182void samsung_clk_register_mux(void __iomem *base,
183 const struct samsung_mux_clock *clk_list,
184 unsigned int nr_clk);
185void samsung_clk_register_div(void __iomem *base,
186 const struct samsung_div_clock *clk_list,
187 unsigned int nr_clk);
188void samsung_clk_register_gate(void __iomem *base,
189 const struct samsung_gate_clock *clk_list,
190 unsigned int nr_clk);
191void samsung_clk_register_pll(void __iomem *base,
192 const struct samsung_pll_clock *clk_list,
193 unsigned int nr_clk);
194
195void samsung_cmu_register_clocks(void __iomem *base,
196 const struct samsung_clk_group *clk_groups,
197 unsigned int nr_groups);
198int samsung_cmu_register_one(struct udevice *dev,
199 const struct samsung_clk_group *clk_groups,
200 unsigned int nr_groups);
201
202/**
203 * samsung_register_cmu - Register CMU clocks ensuring parent CMU is present
204 * @dev: CMU device
205 * @clk_groups: list of CMU clock groups
206 * @parent_drv: name of parent CMU driver
207 *
208 * Register provided CMU clocks, but make sure CMU_TOP driver is instantiated
209 * first.
210 *
211 * Return: 0 on success or negative value on error.
212 */
213#define samsung_register_cmu(dev, clk_groups, parent_drv) \
214({ \
215 struct udevice *__parent; \
216 int __ret; \
217 \
218 __ret = uclass_get_device_by_driver(UCLASS_CLK, \
219 DM_DRIVER_GET(parent_drv), &__parent); \
220 if (__ret || !__parent) \
221 __ret = -ENOENT; \
222 else \
223 __ret = samsung_cmu_register_one(dev, clk_groups, \
224 ARRAY_SIZE(clk_groups)); \
225 __ret; \
226})
227
228#endif /* __EXYNOS_CLK_H */