1514b044cSAnnaliese McDermond /* SPDX-License-Identifier: GPL-2.0
2514b044cSAnnaliese McDermond *
3514b044cSAnnaliese McDermond * Clock Tree for the Texas Instruments TLV320AIC32x4
4514b044cSAnnaliese McDermond *
5514b044cSAnnaliese McDermond * Copyright 2019 Annaliese McDermond
6514b044cSAnnaliese McDermond *
7514b044cSAnnaliese McDermond * Author: Annaliese McDermond <nh6z@nh6z.net>
8514b044cSAnnaliese McDermond */
9514b044cSAnnaliese McDermond
10514b044cSAnnaliese McDermond #include <linux/clk-provider.h>
11514b044cSAnnaliese McDermond #include <linux/clkdev.h>
12514b044cSAnnaliese McDermond #include <linux/regmap.h>
13514b044cSAnnaliese McDermond #include <linux/device.h>
14514b044cSAnnaliese McDermond
15514b044cSAnnaliese McDermond #include "tlv320aic32x4.h"
16514b044cSAnnaliese McDermond
17514b044cSAnnaliese McDermond #define to_clk_aic32x4(_hw) container_of(_hw, struct clk_aic32x4, hw)
18514b044cSAnnaliese McDermond struct clk_aic32x4 {
19514b044cSAnnaliese McDermond struct clk_hw hw;
20514b044cSAnnaliese McDermond struct device *dev;
21514b044cSAnnaliese McDermond struct regmap *regmap;
22514b044cSAnnaliese McDermond unsigned int reg;
23514b044cSAnnaliese McDermond };
24514b044cSAnnaliese McDermond
25514b044cSAnnaliese McDermond /*
26514b044cSAnnaliese McDermond * struct clk_aic32x4_pll_muldiv - Multiplier/divider settings
27514b044cSAnnaliese McDermond * @p: Divider
28514b044cSAnnaliese McDermond * @r: first multiplier
29514b044cSAnnaliese McDermond * @j: integer part of second multiplier
30514b044cSAnnaliese McDermond * @d: decimal part of second multiplier
31514b044cSAnnaliese McDermond */
32514b044cSAnnaliese McDermond struct clk_aic32x4_pll_muldiv {
33514b044cSAnnaliese McDermond u8 p;
34514b044cSAnnaliese McDermond u16 r;
35514b044cSAnnaliese McDermond u8 j;
36514b044cSAnnaliese McDermond u16 d;
37514b044cSAnnaliese McDermond };
38514b044cSAnnaliese McDermond
39514b044cSAnnaliese McDermond struct aic32x4_clkdesc {
40514b044cSAnnaliese McDermond const char *name;
41514b044cSAnnaliese McDermond const char * const *parent_names;
42514b044cSAnnaliese McDermond unsigned int num_parents;
43514b044cSAnnaliese McDermond const struct clk_ops *ops;
44514b044cSAnnaliese McDermond unsigned int reg;
45514b044cSAnnaliese McDermond };
46514b044cSAnnaliese McDermond
clk_aic32x4_pll_prepare(struct clk_hw * hw)47514b044cSAnnaliese McDermond static int clk_aic32x4_pll_prepare(struct clk_hw *hw)
48514b044cSAnnaliese McDermond {
49514b044cSAnnaliese McDermond struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
50514b044cSAnnaliese McDermond
51514b044cSAnnaliese McDermond return regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
52514b044cSAnnaliese McDermond AIC32X4_PLLEN, AIC32X4_PLLEN);
53514b044cSAnnaliese McDermond }
54514b044cSAnnaliese McDermond
clk_aic32x4_pll_unprepare(struct clk_hw * hw)55514b044cSAnnaliese McDermond static void clk_aic32x4_pll_unprepare(struct clk_hw *hw)
56514b044cSAnnaliese McDermond {
57514b044cSAnnaliese McDermond struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
58514b044cSAnnaliese McDermond
59514b044cSAnnaliese McDermond regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
60514b044cSAnnaliese McDermond AIC32X4_PLLEN, 0);
61514b044cSAnnaliese McDermond }
62514b044cSAnnaliese McDermond
clk_aic32x4_pll_is_prepared(struct clk_hw * hw)63514b044cSAnnaliese McDermond static int clk_aic32x4_pll_is_prepared(struct clk_hw *hw)
64514b044cSAnnaliese McDermond {
65514b044cSAnnaliese McDermond struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
66514b044cSAnnaliese McDermond
67514b044cSAnnaliese McDermond unsigned int val;
68514b044cSAnnaliese McDermond int ret;
69514b044cSAnnaliese McDermond
70514b044cSAnnaliese McDermond ret = regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
71514b044cSAnnaliese McDermond if (ret < 0)
72514b044cSAnnaliese McDermond return ret;
73514b044cSAnnaliese McDermond
74514b044cSAnnaliese McDermond return !!(val & AIC32X4_PLLEN);
75514b044cSAnnaliese McDermond }
76514b044cSAnnaliese McDermond
clk_aic32x4_pll_get_muldiv(struct clk_aic32x4 * pll,struct clk_aic32x4_pll_muldiv * settings)77514b044cSAnnaliese McDermond static int clk_aic32x4_pll_get_muldiv(struct clk_aic32x4 *pll,
78514b044cSAnnaliese McDermond struct clk_aic32x4_pll_muldiv *settings)
79514b044cSAnnaliese McDermond {
80514b044cSAnnaliese McDermond /* Change to use regmap_bulk_read? */
81514b044cSAnnaliese McDermond unsigned int val;
82514b044cSAnnaliese McDermond int ret;
83514b044cSAnnaliese McDermond
84514b044cSAnnaliese McDermond ret = regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
85a23e34c0SAnnaliese McDermond if (ret < 0)
86514b044cSAnnaliese McDermond return ret;
87514b044cSAnnaliese McDermond settings->r = val & AIC32X4_PLL_R_MASK;
88514b044cSAnnaliese McDermond settings->p = (val & AIC32X4_PLL_P_MASK) >> AIC32X4_PLL_P_SHIFT;
89514b044cSAnnaliese McDermond
90514b044cSAnnaliese McDermond ret = regmap_read(pll->regmap, AIC32X4_PLLJ, &val);
91514b044cSAnnaliese McDermond if (ret < 0)
92514b044cSAnnaliese McDermond return ret;
93514b044cSAnnaliese McDermond settings->j = val;
94514b044cSAnnaliese McDermond
95514b044cSAnnaliese McDermond ret = regmap_read(pll->regmap, AIC32X4_PLLDMSB, &val);
96514b044cSAnnaliese McDermond if (ret < 0)
97514b044cSAnnaliese McDermond return ret;
98514b044cSAnnaliese McDermond settings->d = val << 8;
99514b044cSAnnaliese McDermond
100514b044cSAnnaliese McDermond ret = regmap_read(pll->regmap, AIC32X4_PLLDLSB, &val);
101514b044cSAnnaliese McDermond if (ret < 0)
102514b044cSAnnaliese McDermond return ret;
103514b044cSAnnaliese McDermond settings->d |= val;
104514b044cSAnnaliese McDermond
105514b044cSAnnaliese McDermond return 0;
106514b044cSAnnaliese McDermond }
107514b044cSAnnaliese McDermond
clk_aic32x4_pll_set_muldiv(struct clk_aic32x4 * pll,struct clk_aic32x4_pll_muldiv * settings)108514b044cSAnnaliese McDermond static int clk_aic32x4_pll_set_muldiv(struct clk_aic32x4 *pll,
109514b044cSAnnaliese McDermond struct clk_aic32x4_pll_muldiv *settings)
110514b044cSAnnaliese McDermond {
111514b044cSAnnaliese McDermond int ret;
112514b044cSAnnaliese McDermond /* Change to use regmap_bulk_write for some if not all? */
113514b044cSAnnaliese McDermond
114514b044cSAnnaliese McDermond ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
115514b044cSAnnaliese McDermond AIC32X4_PLL_R_MASK, settings->r);
116514b044cSAnnaliese McDermond if (ret < 0)
117514b044cSAnnaliese McDermond return ret;
118514b044cSAnnaliese McDermond
119514b044cSAnnaliese McDermond ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
120514b044cSAnnaliese McDermond AIC32X4_PLL_P_MASK,
121514b044cSAnnaliese McDermond settings->p << AIC32X4_PLL_P_SHIFT);
122514b044cSAnnaliese McDermond if (ret < 0)
123514b044cSAnnaliese McDermond return ret;
124514b044cSAnnaliese McDermond
125514b044cSAnnaliese McDermond ret = regmap_write(pll->regmap, AIC32X4_PLLJ, settings->j);
126514b044cSAnnaliese McDermond if (ret < 0)
127514b044cSAnnaliese McDermond return ret;
128514b044cSAnnaliese McDermond
129514b044cSAnnaliese McDermond ret = regmap_write(pll->regmap, AIC32X4_PLLDMSB, (settings->d >> 8));
130514b044cSAnnaliese McDermond if (ret < 0)
131514b044cSAnnaliese McDermond return ret;
132514b044cSAnnaliese McDermond ret = regmap_write(pll->regmap, AIC32X4_PLLDLSB, (settings->d & 0xff));
133514b044cSAnnaliese McDermond if (ret < 0)
134514b044cSAnnaliese McDermond return ret;
135514b044cSAnnaliese McDermond
136514b044cSAnnaliese McDermond return 0;
137514b044cSAnnaliese McDermond }
138514b044cSAnnaliese McDermond
clk_aic32x4_pll_calc_rate(struct clk_aic32x4_pll_muldiv * settings,unsigned long parent_rate)139514b044cSAnnaliese McDermond static unsigned long clk_aic32x4_pll_calc_rate(
140514b044cSAnnaliese McDermond struct clk_aic32x4_pll_muldiv *settings,
141514b044cSAnnaliese McDermond unsigned long parent_rate)
142514b044cSAnnaliese McDermond {
143514b044cSAnnaliese McDermond u64 rate;
144514b044cSAnnaliese McDermond /*
145514b044cSAnnaliese McDermond * We scale j by 10000 to account for the decimal part of P and divide
146514b044cSAnnaliese McDermond * it back out later.
147514b044cSAnnaliese McDermond */
148514b044cSAnnaliese McDermond rate = (u64) parent_rate * settings->r *
149514b044cSAnnaliese McDermond ((settings->j * 10000) + settings->d);
150514b044cSAnnaliese McDermond
151514b044cSAnnaliese McDermond return (unsigned long) DIV_ROUND_UP_ULL(rate, settings->p * 10000);
152514b044cSAnnaliese McDermond }
153514b044cSAnnaliese McDermond
clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv * settings,unsigned long rate,unsigned long parent_rate)154514b044cSAnnaliese McDermond static int clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv *settings,
155514b044cSAnnaliese McDermond unsigned long rate, unsigned long parent_rate)
156514b044cSAnnaliese McDermond {
157514b044cSAnnaliese McDermond u64 multiplier;
158514b044cSAnnaliese McDermond
159514b044cSAnnaliese McDermond settings->p = parent_rate / AIC32X4_MAX_PLL_CLKIN + 1;
160514b044cSAnnaliese McDermond if (settings->p > 8)
161514b044cSAnnaliese McDermond return -1;
162514b044cSAnnaliese McDermond
163514b044cSAnnaliese McDermond /*
164514b044cSAnnaliese McDermond * We scale this figure by 10000 so that we can get the decimal part
165514b044cSAnnaliese McDermond * of the multiplier. This is because we can't do floating point
166514b044cSAnnaliese McDermond * math in the kernel.
167514b044cSAnnaliese McDermond */
168514b044cSAnnaliese McDermond multiplier = (u64) rate * settings->p * 10000;
169514b044cSAnnaliese McDermond do_div(multiplier, parent_rate);
170514b044cSAnnaliese McDermond
171514b044cSAnnaliese McDermond /*
172514b044cSAnnaliese McDermond * J can't be over 64, so R can scale this.
173514b044cSAnnaliese McDermond * R can't be greater than 4.
174514b044cSAnnaliese McDermond */
175514b044cSAnnaliese McDermond settings->r = ((u32) multiplier / 640000) + 1;
176514b044cSAnnaliese McDermond if (settings->r > 4)
177514b044cSAnnaliese McDermond return -1;
178514b044cSAnnaliese McDermond do_div(multiplier, settings->r);
179514b044cSAnnaliese McDermond
180514b044cSAnnaliese McDermond /*
181514b044cSAnnaliese McDermond * J can't be < 1.
182514b044cSAnnaliese McDermond */
183514b044cSAnnaliese McDermond if (multiplier < 10000)
184514b044cSAnnaliese McDermond return -1;
185514b044cSAnnaliese McDermond
186514b044cSAnnaliese McDermond /* Figure out the integer part, J, and the fractional part, D. */
187514b044cSAnnaliese McDermond settings->j = (u32) multiplier / 10000;
188514b044cSAnnaliese McDermond settings->d = (u32) multiplier % 10000;
189514b044cSAnnaliese McDermond
190514b044cSAnnaliese McDermond return 0;
191514b044cSAnnaliese McDermond }
192514b044cSAnnaliese McDermond
clk_aic32x4_pll_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)193514b044cSAnnaliese McDermond static unsigned long clk_aic32x4_pll_recalc_rate(struct clk_hw *hw,
194514b044cSAnnaliese McDermond unsigned long parent_rate)
195514b044cSAnnaliese McDermond {
196514b044cSAnnaliese McDermond struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
197514b044cSAnnaliese McDermond struct clk_aic32x4_pll_muldiv settings;
198514b044cSAnnaliese McDermond int ret;
199514b044cSAnnaliese McDermond
200514b044cSAnnaliese McDermond ret = clk_aic32x4_pll_get_muldiv(pll, &settings);
201514b044cSAnnaliese McDermond if (ret < 0)
202514b044cSAnnaliese McDermond return 0;
203514b044cSAnnaliese McDermond
204514b044cSAnnaliese McDermond return clk_aic32x4_pll_calc_rate(&settings, parent_rate);
205514b044cSAnnaliese McDermond }
206514b044cSAnnaliese McDermond
clk_aic32x4_pll_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)20725d43ec3SMaxime Ripard static int clk_aic32x4_pll_determine_rate(struct clk_hw *hw,
20825d43ec3SMaxime Ripard struct clk_rate_request *req)
209514b044cSAnnaliese McDermond {
210514b044cSAnnaliese McDermond struct clk_aic32x4_pll_muldiv settings;
211514b044cSAnnaliese McDermond int ret;
212514b044cSAnnaliese McDermond
21325d43ec3SMaxime Ripard ret = clk_aic32x4_pll_calc_muldiv(&settings, req->rate, req->best_parent_rate);
214514b044cSAnnaliese McDermond if (ret < 0)
21525d43ec3SMaxime Ripard return -EINVAL;
216514b044cSAnnaliese McDermond
2173e253b21SStephen Boyd req->rate = clk_aic32x4_pll_calc_rate(&settings, req->best_parent_rate);
21825d43ec3SMaxime Ripard
21925d43ec3SMaxime Ripard return 0;
220514b044cSAnnaliese McDermond }
221514b044cSAnnaliese McDermond
clk_aic32x4_pll_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)222514b044cSAnnaliese McDermond static int clk_aic32x4_pll_set_rate(struct clk_hw *hw,
223514b044cSAnnaliese McDermond unsigned long rate,
224514b044cSAnnaliese McDermond unsigned long parent_rate)
225514b044cSAnnaliese McDermond {
226514b044cSAnnaliese McDermond struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
227514b044cSAnnaliese McDermond struct clk_aic32x4_pll_muldiv settings;
228514b044cSAnnaliese McDermond int ret;
229514b044cSAnnaliese McDermond
230514b044cSAnnaliese McDermond ret = clk_aic32x4_pll_calc_muldiv(&settings, rate, parent_rate);
231514b044cSAnnaliese McDermond if (ret < 0)
232514b044cSAnnaliese McDermond return -EINVAL;
233514b044cSAnnaliese McDermond
2345b4458ebSMiquel Raynal ret = clk_aic32x4_pll_set_muldiv(pll, &settings);
2355b4458ebSMiquel Raynal if (ret)
2365b4458ebSMiquel Raynal return ret;
2375b4458ebSMiquel Raynal
2385b4458ebSMiquel Raynal /* 10ms is the delay to wait before the clocks are stable */
2395b4458ebSMiquel Raynal msleep(10);
2405b4458ebSMiquel Raynal
2415b4458ebSMiquel Raynal return 0;
242514b044cSAnnaliese McDermond }
243514b044cSAnnaliese McDermond
clk_aic32x4_pll_set_parent(struct clk_hw * hw,u8 index)244514b044cSAnnaliese McDermond static int clk_aic32x4_pll_set_parent(struct clk_hw *hw, u8 index)
245514b044cSAnnaliese McDermond {
246514b044cSAnnaliese McDermond struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
247514b044cSAnnaliese McDermond
248514b044cSAnnaliese McDermond return regmap_update_bits(pll->regmap,
249514b044cSAnnaliese McDermond AIC32X4_CLKMUX,
250514b044cSAnnaliese McDermond AIC32X4_PLL_CLKIN_MASK,
251514b044cSAnnaliese McDermond index << AIC32X4_PLL_CLKIN_SHIFT);
252514b044cSAnnaliese McDermond }
253514b044cSAnnaliese McDermond
clk_aic32x4_pll_get_parent(struct clk_hw * hw)254514b044cSAnnaliese McDermond static u8 clk_aic32x4_pll_get_parent(struct clk_hw *hw)
255514b044cSAnnaliese McDermond {
256514b044cSAnnaliese McDermond struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
257514b044cSAnnaliese McDermond unsigned int val;
258514b044cSAnnaliese McDermond
259514b044cSAnnaliese McDermond regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
260514b044cSAnnaliese McDermond
261514b044cSAnnaliese McDermond return (val & AIC32X4_PLL_CLKIN_MASK) >> AIC32X4_PLL_CLKIN_SHIFT;
262514b044cSAnnaliese McDermond }
263514b044cSAnnaliese McDermond
264514b044cSAnnaliese McDermond
265514b044cSAnnaliese McDermond static const struct clk_ops aic32x4_pll_ops = {
266514b044cSAnnaliese McDermond .prepare = clk_aic32x4_pll_prepare,
267514b044cSAnnaliese McDermond .unprepare = clk_aic32x4_pll_unprepare,
268514b044cSAnnaliese McDermond .is_prepared = clk_aic32x4_pll_is_prepared,
269514b044cSAnnaliese McDermond .recalc_rate = clk_aic32x4_pll_recalc_rate,
27025d43ec3SMaxime Ripard .determine_rate = clk_aic32x4_pll_determine_rate,
271514b044cSAnnaliese McDermond .set_rate = clk_aic32x4_pll_set_rate,
272514b044cSAnnaliese McDermond .set_parent = clk_aic32x4_pll_set_parent,
273514b044cSAnnaliese McDermond .get_parent = clk_aic32x4_pll_get_parent,
274514b044cSAnnaliese McDermond };
275514b044cSAnnaliese McDermond
clk_aic32x4_codec_clkin_set_parent(struct clk_hw * hw,u8 index)276fd2df3aeSAnnaliese McDermond static int clk_aic32x4_codec_clkin_set_parent(struct clk_hw *hw, u8 index)
277fd2df3aeSAnnaliese McDermond {
278fd2df3aeSAnnaliese McDermond struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
279fd2df3aeSAnnaliese McDermond
280fd2df3aeSAnnaliese McDermond return regmap_update_bits(mux->regmap,
281fd2df3aeSAnnaliese McDermond AIC32X4_CLKMUX,
282fd2df3aeSAnnaliese McDermond AIC32X4_CODEC_CLKIN_MASK, index << AIC32X4_CODEC_CLKIN_SHIFT);
283fd2df3aeSAnnaliese McDermond }
284fd2df3aeSAnnaliese McDermond
clk_aic32x4_codec_clkin_get_parent(struct clk_hw * hw)285fd2df3aeSAnnaliese McDermond static u8 clk_aic32x4_codec_clkin_get_parent(struct clk_hw *hw)
286fd2df3aeSAnnaliese McDermond {
287fd2df3aeSAnnaliese McDermond struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
288fd2df3aeSAnnaliese McDermond unsigned int val;
289fd2df3aeSAnnaliese McDermond
290fd2df3aeSAnnaliese McDermond regmap_read(mux->regmap, AIC32X4_CLKMUX, &val);
291fd2df3aeSAnnaliese McDermond
292fd2df3aeSAnnaliese McDermond return (val & AIC32X4_CODEC_CLKIN_MASK) >> AIC32X4_CODEC_CLKIN_SHIFT;
293fd2df3aeSAnnaliese McDermond }
294fd2df3aeSAnnaliese McDermond
295fd2df3aeSAnnaliese McDermond static const struct clk_ops aic32x4_codec_clkin_ops = {
296218b95baSMaxime Ripard .determine_rate = clk_hw_determine_rate_no_reparent,
297fd2df3aeSAnnaliese McDermond .set_parent = clk_aic32x4_codec_clkin_set_parent,
298fd2df3aeSAnnaliese McDermond .get_parent = clk_aic32x4_codec_clkin_get_parent,
299fd2df3aeSAnnaliese McDermond };
300fd2df3aeSAnnaliese McDermond
clk_aic32x4_div_prepare(struct clk_hw * hw)301a51b5006SAnnaliese McDermond static int clk_aic32x4_div_prepare(struct clk_hw *hw)
302a51b5006SAnnaliese McDermond {
303a51b5006SAnnaliese McDermond struct clk_aic32x4 *div = to_clk_aic32x4(hw);
304a51b5006SAnnaliese McDermond
305a51b5006SAnnaliese McDermond return regmap_update_bits(div->regmap, div->reg,
306a51b5006SAnnaliese McDermond AIC32X4_DIVEN, AIC32X4_DIVEN);
307a51b5006SAnnaliese McDermond }
308a51b5006SAnnaliese McDermond
clk_aic32x4_div_unprepare(struct clk_hw * hw)309a51b5006SAnnaliese McDermond static void clk_aic32x4_div_unprepare(struct clk_hw *hw)
310a51b5006SAnnaliese McDermond {
311a51b5006SAnnaliese McDermond struct clk_aic32x4 *div = to_clk_aic32x4(hw);
312a51b5006SAnnaliese McDermond
313a51b5006SAnnaliese McDermond regmap_update_bits(div->regmap, div->reg,
314a51b5006SAnnaliese McDermond AIC32X4_DIVEN, 0);
315a51b5006SAnnaliese McDermond }
316a51b5006SAnnaliese McDermond
clk_aic32x4_div_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)317a51b5006SAnnaliese McDermond static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate,
318a51b5006SAnnaliese McDermond unsigned long parent_rate)
319a51b5006SAnnaliese McDermond {
320a51b5006SAnnaliese McDermond struct clk_aic32x4 *div = to_clk_aic32x4(hw);
321a51b5006SAnnaliese McDermond u8 divisor;
322a51b5006SAnnaliese McDermond
323a51b5006SAnnaliese McDermond divisor = DIV_ROUND_UP(parent_rate, rate);
324*11e756ccSGuiting Shen if (divisor > AIC32X4_DIV_MAX)
325a51b5006SAnnaliese McDermond return -EINVAL;
326a51b5006SAnnaliese McDermond
327a51b5006SAnnaliese McDermond return regmap_update_bits(div->regmap, div->reg,
328a51b5006SAnnaliese McDermond AIC32X4_DIV_MASK, divisor);
329a51b5006SAnnaliese McDermond }
330a51b5006SAnnaliese McDermond
clk_aic32x4_div_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)3312b6c9b0eSMaxime Ripard static int clk_aic32x4_div_determine_rate(struct clk_hw *hw,
3322b6c9b0eSMaxime Ripard struct clk_rate_request *req)
333a51b5006SAnnaliese McDermond {
334a51b5006SAnnaliese McDermond unsigned long divisor;
335a51b5006SAnnaliese McDermond
3362b6c9b0eSMaxime Ripard divisor = DIV_ROUND_UP(req->best_parent_rate, req->rate);
337*11e756ccSGuiting Shen if (divisor > AIC32X4_DIV_MAX)
338a51b5006SAnnaliese McDermond return -EINVAL;
339a51b5006SAnnaliese McDermond
3402b6c9b0eSMaxime Ripard req->rate = DIV_ROUND_UP(req->best_parent_rate, divisor);
3412b6c9b0eSMaxime Ripard return 0;
342a51b5006SAnnaliese McDermond }
343a51b5006SAnnaliese McDermond
clk_aic32x4_div_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)344a51b5006SAnnaliese McDermond static unsigned long clk_aic32x4_div_recalc_rate(struct clk_hw *hw,
345a51b5006SAnnaliese McDermond unsigned long parent_rate)
346a51b5006SAnnaliese McDermond {
347a51b5006SAnnaliese McDermond struct clk_aic32x4 *div = to_clk_aic32x4(hw);
348a51b5006SAnnaliese McDermond unsigned int val;
349*11e756ccSGuiting Shen int err;
350a51b5006SAnnaliese McDermond
351*11e756ccSGuiting Shen err = regmap_read(div->regmap, div->reg, &val);
352*11e756ccSGuiting Shen if (err)
353*11e756ccSGuiting Shen return 0;
354a51b5006SAnnaliese McDermond
355*11e756ccSGuiting Shen val &= AIC32X4_DIV_MASK;
356*11e756ccSGuiting Shen if (!val)
357*11e756ccSGuiting Shen val = AIC32X4_DIV_MAX;
358*11e756ccSGuiting Shen
359*11e756ccSGuiting Shen return DIV_ROUND_UP(parent_rate, val);
360a51b5006SAnnaliese McDermond }
361a51b5006SAnnaliese McDermond
362a51b5006SAnnaliese McDermond static const struct clk_ops aic32x4_div_ops = {
363a51b5006SAnnaliese McDermond .prepare = clk_aic32x4_div_prepare,
364a51b5006SAnnaliese McDermond .unprepare = clk_aic32x4_div_unprepare,
365a51b5006SAnnaliese McDermond .set_rate = clk_aic32x4_div_set_rate,
3662b6c9b0eSMaxime Ripard .determine_rate = clk_aic32x4_div_determine_rate,
367a51b5006SAnnaliese McDermond .recalc_rate = clk_aic32x4_div_recalc_rate,
368a51b5006SAnnaliese McDermond };
369a51b5006SAnnaliese McDermond
clk_aic32x4_bdiv_set_parent(struct clk_hw * hw,u8 index)3709b484124SAnnaliese McDermond static int clk_aic32x4_bdiv_set_parent(struct clk_hw *hw, u8 index)
3719b484124SAnnaliese McDermond {
3729b484124SAnnaliese McDermond struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
3739b484124SAnnaliese McDermond
3749b484124SAnnaliese McDermond return regmap_update_bits(mux->regmap, AIC32X4_IFACE3,
3759b484124SAnnaliese McDermond AIC32X4_BDIVCLK_MASK, index);
3769b484124SAnnaliese McDermond }
3779b484124SAnnaliese McDermond
clk_aic32x4_bdiv_get_parent(struct clk_hw * hw)3789b484124SAnnaliese McDermond static u8 clk_aic32x4_bdiv_get_parent(struct clk_hw *hw)
3799b484124SAnnaliese McDermond {
3809b484124SAnnaliese McDermond struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
3819b484124SAnnaliese McDermond unsigned int val;
3829b484124SAnnaliese McDermond
3839b484124SAnnaliese McDermond regmap_read(mux->regmap, AIC32X4_IFACE3, &val);
3849b484124SAnnaliese McDermond
3859b484124SAnnaliese McDermond return val & AIC32X4_BDIVCLK_MASK;
3869b484124SAnnaliese McDermond }
3879b484124SAnnaliese McDermond
3889b484124SAnnaliese McDermond static const struct clk_ops aic32x4_bdiv_ops = {
3899b484124SAnnaliese McDermond .prepare = clk_aic32x4_div_prepare,
3909b484124SAnnaliese McDermond .unprepare = clk_aic32x4_div_unprepare,
3919b484124SAnnaliese McDermond .set_parent = clk_aic32x4_bdiv_set_parent,
3929b484124SAnnaliese McDermond .get_parent = clk_aic32x4_bdiv_get_parent,
3939b484124SAnnaliese McDermond .set_rate = clk_aic32x4_div_set_rate,
3942b6c9b0eSMaxime Ripard .determine_rate = clk_aic32x4_div_determine_rate,
3959b484124SAnnaliese McDermond .recalc_rate = clk_aic32x4_div_recalc_rate,
3969b484124SAnnaliese McDermond };
3979b484124SAnnaliese McDermond
398514b044cSAnnaliese McDermond static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
399514b044cSAnnaliese McDermond {
400514b044cSAnnaliese McDermond .name = "pll",
401514b044cSAnnaliese McDermond .parent_names =
402514b044cSAnnaliese McDermond (const char* []) { "mclk", "bclk", "gpio", "din" },
403514b044cSAnnaliese McDermond .num_parents = 4,
404514b044cSAnnaliese McDermond .ops = &aic32x4_pll_ops,
405514b044cSAnnaliese McDermond .reg = 0,
406514b044cSAnnaliese McDermond },
407fd2df3aeSAnnaliese McDermond {
408fd2df3aeSAnnaliese McDermond .name = "codec_clkin",
409fd2df3aeSAnnaliese McDermond .parent_names =
410fd2df3aeSAnnaliese McDermond (const char *[]) { "mclk", "bclk", "gpio", "pll" },
411fd2df3aeSAnnaliese McDermond .num_parents = 4,
412fd2df3aeSAnnaliese McDermond .ops = &aic32x4_codec_clkin_ops,
413fd2df3aeSAnnaliese McDermond .reg = 0,
414fd2df3aeSAnnaliese McDermond },
415a51b5006SAnnaliese McDermond {
416a51b5006SAnnaliese McDermond .name = "ndac",
417a51b5006SAnnaliese McDermond .parent_names = (const char * []) { "codec_clkin" },
418a51b5006SAnnaliese McDermond .num_parents = 1,
419a51b5006SAnnaliese McDermond .ops = &aic32x4_div_ops,
420a51b5006SAnnaliese McDermond .reg = AIC32X4_NDAC,
421a51b5006SAnnaliese McDermond },
422a51b5006SAnnaliese McDermond {
423a51b5006SAnnaliese McDermond .name = "mdac",
424a51b5006SAnnaliese McDermond .parent_names = (const char * []) { "ndac" },
425a51b5006SAnnaliese McDermond .num_parents = 1,
426a51b5006SAnnaliese McDermond .ops = &aic32x4_div_ops,
427a51b5006SAnnaliese McDermond .reg = AIC32X4_MDAC,
428a51b5006SAnnaliese McDermond },
429a51b5006SAnnaliese McDermond {
430a51b5006SAnnaliese McDermond .name = "nadc",
431a51b5006SAnnaliese McDermond .parent_names = (const char * []) { "codec_clkin" },
432a51b5006SAnnaliese McDermond .num_parents = 1,
433a51b5006SAnnaliese McDermond .ops = &aic32x4_div_ops,
434a51b5006SAnnaliese McDermond .reg = AIC32X4_NADC,
435a51b5006SAnnaliese McDermond },
436a51b5006SAnnaliese McDermond {
437a51b5006SAnnaliese McDermond .name = "madc",
438a51b5006SAnnaliese McDermond .parent_names = (const char * []) { "nadc" },
439a51b5006SAnnaliese McDermond .num_parents = 1,
440a51b5006SAnnaliese McDermond .ops = &aic32x4_div_ops,
441a51b5006SAnnaliese McDermond .reg = AIC32X4_MADC,
442a51b5006SAnnaliese McDermond },
4439b484124SAnnaliese McDermond {
4449b484124SAnnaliese McDermond .name = "bdiv",
4459b484124SAnnaliese McDermond .parent_names =
4469b484124SAnnaliese McDermond (const char *[]) { "ndac", "mdac", "nadc", "madc" },
4479b484124SAnnaliese McDermond .num_parents = 4,
4489b484124SAnnaliese McDermond .ops = &aic32x4_bdiv_ops,
4499b484124SAnnaliese McDermond .reg = AIC32X4_BCLKN,
4509b484124SAnnaliese McDermond },
451514b044cSAnnaliese McDermond };
452514b044cSAnnaliese McDermond
aic32x4_register_clk(struct device * dev,struct aic32x4_clkdesc * desc)453514b044cSAnnaliese McDermond static struct clk *aic32x4_register_clk(struct device *dev,
454514b044cSAnnaliese McDermond struct aic32x4_clkdesc *desc)
455514b044cSAnnaliese McDermond {
456514b044cSAnnaliese McDermond struct clk_init_data init;
457514b044cSAnnaliese McDermond struct clk_aic32x4 *priv;
458514b044cSAnnaliese McDermond const char *devname = dev_name(dev);
459514b044cSAnnaliese McDermond
460514b044cSAnnaliese McDermond init.ops = desc->ops;
461514b044cSAnnaliese McDermond init.name = desc->name;
462514b044cSAnnaliese McDermond init.parent_names = desc->parent_names;
463514b044cSAnnaliese McDermond init.num_parents = desc->num_parents;
464514b044cSAnnaliese McDermond init.flags = 0;
465514b044cSAnnaliese McDermond
466514b044cSAnnaliese McDermond priv = devm_kzalloc(dev, sizeof(struct clk_aic32x4), GFP_KERNEL);
467514b044cSAnnaliese McDermond if (priv == NULL)
468514b044cSAnnaliese McDermond return (struct clk *) -ENOMEM;
469514b044cSAnnaliese McDermond
470514b044cSAnnaliese McDermond priv->dev = dev;
471514b044cSAnnaliese McDermond priv->hw.init = &init;
472514b044cSAnnaliese McDermond priv->regmap = dev_get_regmap(dev, NULL);
473514b044cSAnnaliese McDermond priv->reg = desc->reg;
474514b044cSAnnaliese McDermond
475514b044cSAnnaliese McDermond clk_hw_register_clkdev(&priv->hw, desc->name, devname);
476514b044cSAnnaliese McDermond return devm_clk_register(dev, &priv->hw);
477514b044cSAnnaliese McDermond }
478514b044cSAnnaliese McDermond
aic32x4_register_clocks(struct device * dev,const char * mclk_name)479514b044cSAnnaliese McDermond int aic32x4_register_clocks(struct device *dev, const char *mclk_name)
480514b044cSAnnaliese McDermond {
481514b044cSAnnaliese McDermond int i;
482514b044cSAnnaliese McDermond
483514b044cSAnnaliese McDermond /*
484514b044cSAnnaliese McDermond * These lines are here to preserve the current functionality of
485514b044cSAnnaliese McDermond * the driver with regard to the DT. These should eventually be set
486514b044cSAnnaliese McDermond * by DT nodes so that the connections can be set up in configuration
487514b044cSAnnaliese McDermond * rather than code.
488514b044cSAnnaliese McDermond */
489514b044cSAnnaliese McDermond aic32x4_clkdesc_array[0].parent_names =
490514b044cSAnnaliese McDermond (const char* []) { mclk_name, "bclk", "gpio", "din" };
491fd2df3aeSAnnaliese McDermond aic32x4_clkdesc_array[1].parent_names =
492fd2df3aeSAnnaliese McDermond (const char *[]) { mclk_name, "bclk", "gpio", "pll" };
493514b044cSAnnaliese McDermond
494514b044cSAnnaliese McDermond for (i = 0; i < ARRAY_SIZE(aic32x4_clkdesc_array); ++i)
495514b044cSAnnaliese McDermond aic32x4_register_clk(dev, &aic32x4_clkdesc_array[i]);
496514b044cSAnnaliese McDermond
497514b044cSAnnaliese McDermond return 0;
498514b044cSAnnaliese McDermond }
499514b044cSAnnaliese McDermond EXPORT_SYMBOL_GPL(aic32x4_register_clocks);
500