xref: /linux/sound/soc/codecs/tlv320aic32x4-clk.c (revision a1c613ae4c322ddd58d5a8539dbfba2a0380a8c0)
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