xref: /openbmc/u-boot/drivers/sound/wm8994.c (revision 8fc26fce41592175ae004514e431e68a9dd60671)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2a2d8e0a7SRajeshwari Shinde /*
3a2d8e0a7SRajeshwari Shinde  * Copyright (C) 2012 Samsung Electronics
4a2d8e0a7SRajeshwari Shinde  * R. Chandrasekar <rcsekar@samsung.com>
5a2d8e0a7SRajeshwari Shinde  */
6150c5afeSSimon Glass #include <common.h>
7*d6cadd59SSimon Glass #include <audio_codec.h>
8*d6cadd59SSimon Glass #include <dm.h>
9a2d8e0a7SRajeshwari Shinde #include <div64.h>
106647c7acSRajeshwari Shinde #include <fdtdec.h>
11a2d8e0a7SRajeshwari Shinde #include <i2c.h>
12a2d8e0a7SRajeshwari Shinde #include <i2s.h>
13a2d8e0a7SRajeshwari Shinde #include <sound.h>
14a1efd49eSSimon Glass #include <asm/gpio.h>
15a1efd49eSSimon Glass #include <asm/io.h>
16a1efd49eSSimon Glass #include <asm/arch/clk.h>
17a1efd49eSSimon Glass #include <asm/arch/cpu.h>
186647c7acSRajeshwari Shinde #include <asm/arch/sound.h>
19a2d8e0a7SRajeshwari Shinde #include "wm8994.h"
20a2d8e0a7SRajeshwari Shinde #include "wm8994_registers.h"
21a2d8e0a7SRajeshwari Shinde 
22a2d8e0a7SRajeshwari Shinde /* defines for wm8994 system clock selection */
23a2d8e0a7SRajeshwari Shinde #define SEL_MCLK1	0x00
24a2d8e0a7SRajeshwari Shinde #define SEL_MCLK2	0x08
25a2d8e0a7SRajeshwari Shinde #define SEL_FLL1	0x10
26a2d8e0a7SRajeshwari Shinde #define SEL_FLL2	0x18
27a2d8e0a7SRajeshwari Shinde 
28a2d8e0a7SRajeshwari Shinde /* fll config to configure fll */
29a2d8e0a7SRajeshwari Shinde struct wm8994_fll_config {
30a2d8e0a7SRajeshwari Shinde 	int src;	/* Source */
31a2d8e0a7SRajeshwari Shinde 	int in;		/* Input frequency in Hz */
32a2d8e0a7SRajeshwari Shinde 	int out;	/* output frequency in Hz */
33a2d8e0a7SRajeshwari Shinde };
34a2d8e0a7SRajeshwari Shinde 
35a2d8e0a7SRajeshwari Shinde /* codec private data */
36a2d8e0a7SRajeshwari Shinde struct wm8994_priv {
37a2d8e0a7SRajeshwari Shinde 	enum wm8994_type type;		/* codec type of wolfson */
38a2d8e0a7SRajeshwari Shinde 	int revision;			/* Revision */
39a2d8e0a7SRajeshwari Shinde 	int sysclk[WM8994_MAX_AIF];	/* System clock frequency in Hz  */
40a2d8e0a7SRajeshwari Shinde 	int mclk[WM8994_MAX_AIF];	/* master clock frequency in Hz */
41a2d8e0a7SRajeshwari Shinde 	int aifclk[WM8994_MAX_AIF];	/* audio interface clock in Hz   */
42a2d8e0a7SRajeshwari Shinde 	struct wm8994_fll_config fll[2]; /* fll config to configure fll */
43*d6cadd59SSimon Glass 	struct udevice *dev;
44a2d8e0a7SRajeshwari Shinde };
45a2d8e0a7SRajeshwari Shinde 
46a2d8e0a7SRajeshwari Shinde /* wm 8994 supported sampling rate values */
47a2d8e0a7SRajeshwari Shinde static unsigned int src_rate[] = {
48a2d8e0a7SRajeshwari Shinde 			 8000, 11025, 12000, 16000, 22050, 24000,
49a2d8e0a7SRajeshwari Shinde 			 32000, 44100, 48000, 88200, 96000
50a2d8e0a7SRajeshwari Shinde };
51a2d8e0a7SRajeshwari Shinde 
52a2d8e0a7SRajeshwari Shinde /* op clock divisions */
53a2d8e0a7SRajeshwari Shinde static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 };
54a2d8e0a7SRajeshwari Shinde 
55a2d8e0a7SRajeshwari Shinde /* lr clock frame size ratio */
56a2d8e0a7SRajeshwari Shinde static int fs_ratios[] = {
57a2d8e0a7SRajeshwari Shinde 	64, 128, 192, 256, 348, 512, 768, 1024, 1408, 1536
58a2d8e0a7SRajeshwari Shinde };
59a2d8e0a7SRajeshwari Shinde 
60a2d8e0a7SRajeshwari Shinde /* bit clock divisors */
61a2d8e0a7SRajeshwari Shinde static int bclk_divs[] = {
62a2d8e0a7SRajeshwari Shinde 	10, 15, 20, 30, 40, 50, 60, 80, 110, 120, 160, 220, 240, 320, 440, 480,
63a2d8e0a7SRajeshwari Shinde 	640, 880, 960, 1280, 1760, 1920
64a2d8e0a7SRajeshwari Shinde };
65a2d8e0a7SRajeshwari Shinde 
66a2d8e0a7SRajeshwari Shinde /*
67a2d8e0a7SRajeshwari Shinde  * Writes value to a device register through i2c
68a2d8e0a7SRajeshwari Shinde  *
69107ab83eSSimon Glass  * @param priv	Private data for driver
70a2d8e0a7SRajeshwari Shinde  * @param reg	reg number to be write
71a2d8e0a7SRajeshwari Shinde  * @param data	data to be writen to the above registor
72a2d8e0a7SRajeshwari Shinde  *
73a2d8e0a7SRajeshwari Shinde  * @return	int value 1 for change, 0 for no change or negative error code.
74a2d8e0a7SRajeshwari Shinde  */
wm8994_i2c_write(struct wm8994_priv * priv,unsigned int reg,unsigned short data)75107ab83eSSimon Glass static int wm8994_i2c_write(struct wm8994_priv *priv, unsigned int reg,
76107ab83eSSimon Glass 			    unsigned short data)
77a2d8e0a7SRajeshwari Shinde {
78a2d8e0a7SRajeshwari Shinde 	unsigned char val[2];
79a2d8e0a7SRajeshwari Shinde 
80a2d8e0a7SRajeshwari Shinde 	val[0] = (unsigned char)((data >> 8) & 0xff);
81a2d8e0a7SRajeshwari Shinde 	val[1] = (unsigned char)(data & 0xff);
82a2d8e0a7SRajeshwari Shinde 	debug("Write Addr : 0x%04X, Data :  0x%04X\n", reg, data);
83a2d8e0a7SRajeshwari Shinde 
84*d6cadd59SSimon Glass 	return dm_i2c_write(priv->dev, reg, val, 2);
85a2d8e0a7SRajeshwari Shinde }
86a2d8e0a7SRajeshwari Shinde 
87a2d8e0a7SRajeshwari Shinde /*
88a2d8e0a7SRajeshwari Shinde  * Read a value from a device register through i2c
89a2d8e0a7SRajeshwari Shinde  *
90107ab83eSSimon Glass  * @param priv	Private data for driver
91a2d8e0a7SRajeshwari Shinde  * @param reg	reg number to be read
92a2d8e0a7SRajeshwari Shinde  * @param data	address of read data to be stored
93a2d8e0a7SRajeshwari Shinde  *
94a2d8e0a7SRajeshwari Shinde  * @return	int value 0 for success, -1 in case of error.
95a2d8e0a7SRajeshwari Shinde  */
wm8994_i2c_read(struct wm8994_priv * priv,unsigned int reg,unsigned short * data)96107ab83eSSimon Glass static unsigned int wm8994_i2c_read(struct wm8994_priv *priv, unsigned int reg,
97107ab83eSSimon Glass 				    unsigned short *data)
98a2d8e0a7SRajeshwari Shinde {
99a2d8e0a7SRajeshwari Shinde 	unsigned char val[2];
100a2d8e0a7SRajeshwari Shinde 	int ret;
101a2d8e0a7SRajeshwari Shinde 
102*d6cadd59SSimon Glass 	ret = dm_i2c_read(priv->dev, reg, val, 1);
103a2d8e0a7SRajeshwari Shinde 	if (ret != 0) {
104a2d8e0a7SRajeshwari Shinde 		debug("%s: Error while reading register %#04x\n",
105a2d8e0a7SRajeshwari Shinde 		      __func__, reg);
106a2d8e0a7SRajeshwari Shinde 		return -1;
107a2d8e0a7SRajeshwari Shinde 	}
108a2d8e0a7SRajeshwari Shinde 
109a2d8e0a7SRajeshwari Shinde 	*data = val[0];
110a2d8e0a7SRajeshwari Shinde 	*data <<= 8;
111a2d8e0a7SRajeshwari Shinde 	*data |= val[1];
112a2d8e0a7SRajeshwari Shinde 
113a2d8e0a7SRajeshwari Shinde 	return 0;
114a2d8e0a7SRajeshwari Shinde }
115a2d8e0a7SRajeshwari Shinde 
116a2d8e0a7SRajeshwari Shinde /*
117a2d8e0a7SRajeshwari Shinde  * update device register bits through i2c
118a2d8e0a7SRajeshwari Shinde  *
119107ab83eSSimon Glass  * @param priv	Private data for driver
120a2d8e0a7SRajeshwari Shinde  * @param reg	codec register
121a2d8e0a7SRajeshwari Shinde  * @param mask	register mask
122a2d8e0a7SRajeshwari Shinde  * @param value	new value
123a2d8e0a7SRajeshwari Shinde  *
124a2d8e0a7SRajeshwari Shinde  * @return int value 1 if change in the register value,
125a2d8e0a7SRajeshwari Shinde  * 0 for no change or negative error code.
126a2d8e0a7SRajeshwari Shinde  */
wm8994_bic_or(struct wm8994_priv * priv,unsigned int reg,unsigned short mask,unsigned short value)127107ab83eSSimon Glass static int wm8994_bic_or(struct wm8994_priv *priv, unsigned int reg,
128107ab83eSSimon Glass 			 unsigned short mask, unsigned short value)
129a2d8e0a7SRajeshwari Shinde {
130a2d8e0a7SRajeshwari Shinde 	int change , ret = 0;
131a2d8e0a7SRajeshwari Shinde 	unsigned short old, new;
132a2d8e0a7SRajeshwari Shinde 
133107ab83eSSimon Glass 	if (wm8994_i2c_read(priv, reg, &old) != 0)
134a2d8e0a7SRajeshwari Shinde 		return -1;
135a2d8e0a7SRajeshwari Shinde 	new = (old & ~mask) | (value & mask);
136a2d8e0a7SRajeshwari Shinde 	change  = (old != new) ? 1 : 0;
137a2d8e0a7SRajeshwari Shinde 	if (change)
138107ab83eSSimon Glass 		ret = wm8994_i2c_write(priv, reg, new);
139a2d8e0a7SRajeshwari Shinde 	if (ret < 0)
140a2d8e0a7SRajeshwari Shinde 		return ret;
141a2d8e0a7SRajeshwari Shinde 
142a2d8e0a7SRajeshwari Shinde 	return change;
143a2d8e0a7SRajeshwari Shinde }
144a2d8e0a7SRajeshwari Shinde 
145a2d8e0a7SRajeshwari Shinde /*
146a2d8e0a7SRajeshwari Shinde  * Sets i2s set format
147a2d8e0a7SRajeshwari Shinde  *
148107ab83eSSimon Glass  * @param priv		wm8994 information
149a2d8e0a7SRajeshwari Shinde  * @param aif_id	Interface ID
150a2d8e0a7SRajeshwari Shinde  * @param fmt		i2S format
151a2d8e0a7SRajeshwari Shinde  *
152a2d8e0a7SRajeshwari Shinde  * @return -1 for error and 0  Success.
153a2d8e0a7SRajeshwari Shinde  */
wm8994_set_fmt(struct wm8994_priv * priv,int aif_id,uint fmt)154107ab83eSSimon Glass static int wm8994_set_fmt(struct wm8994_priv *priv, int aif_id, uint fmt)
155a2d8e0a7SRajeshwari Shinde {
156a2d8e0a7SRajeshwari Shinde 	int ms_reg;
157a2d8e0a7SRajeshwari Shinde 	int aif_reg;
158a2d8e0a7SRajeshwari Shinde 	int ms = 0;
159a2d8e0a7SRajeshwari Shinde 	int aif = 0;
160a2d8e0a7SRajeshwari Shinde 	int aif_clk = 0;
161a2d8e0a7SRajeshwari Shinde 	int error = 0;
162a2d8e0a7SRajeshwari Shinde 
163a2d8e0a7SRajeshwari Shinde 	switch (aif_id) {
164a2d8e0a7SRajeshwari Shinde 	case 1:
165a2d8e0a7SRajeshwari Shinde 		ms_reg = WM8994_AIF1_MASTER_SLAVE;
166a2d8e0a7SRajeshwari Shinde 		aif_reg = WM8994_AIF1_CONTROL_1;
167a2d8e0a7SRajeshwari Shinde 		aif_clk = WM8994_AIF1_CLOCKING_1;
168a2d8e0a7SRajeshwari Shinde 		break;
169a2d8e0a7SRajeshwari Shinde 	case 2:
170a2d8e0a7SRajeshwari Shinde 		ms_reg = WM8994_AIF2_MASTER_SLAVE;
171a2d8e0a7SRajeshwari Shinde 		aif_reg = WM8994_AIF2_CONTROL_1;
172a2d8e0a7SRajeshwari Shinde 		aif_clk = WM8994_AIF2_CLOCKING_1;
173a2d8e0a7SRajeshwari Shinde 		break;
174a2d8e0a7SRajeshwari Shinde 	default:
175a2d8e0a7SRajeshwari Shinde 		debug("%s: Invalid audio interface selection\n", __func__);
176a2d8e0a7SRajeshwari Shinde 		return -1;
177a2d8e0a7SRajeshwari Shinde 	}
178a2d8e0a7SRajeshwari Shinde 
179a2d8e0a7SRajeshwari Shinde 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
180a2d8e0a7SRajeshwari Shinde 	case SND_SOC_DAIFMT_CBS_CFS:
181a2d8e0a7SRajeshwari Shinde 		break;
182a2d8e0a7SRajeshwari Shinde 	case SND_SOC_DAIFMT_CBM_CFM:
183a2d8e0a7SRajeshwari Shinde 		ms = WM8994_AIF1_MSTR;
184a2d8e0a7SRajeshwari Shinde 		break;
185a2d8e0a7SRajeshwari Shinde 	default:
186a2d8e0a7SRajeshwari Shinde 		debug("%s: Invalid i2s master selection\n", __func__);
187a2d8e0a7SRajeshwari Shinde 		return -1;
188a2d8e0a7SRajeshwari Shinde 	}
189a2d8e0a7SRajeshwari Shinde 
190a2d8e0a7SRajeshwari Shinde 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
191a2d8e0a7SRajeshwari Shinde 	case SND_SOC_DAIFMT_DSP_B:
192a2d8e0a7SRajeshwari Shinde 		aif |= WM8994_AIF1_LRCLK_INV;
193a2d8e0a7SRajeshwari Shinde 	case SND_SOC_DAIFMT_DSP_A:
194a2d8e0a7SRajeshwari Shinde 		aif |= 0x18;
195a2d8e0a7SRajeshwari Shinde 		break;
196a2d8e0a7SRajeshwari Shinde 	case SND_SOC_DAIFMT_I2S:
197a2d8e0a7SRajeshwari Shinde 		aif |= 0x10;
198a2d8e0a7SRajeshwari Shinde 		break;
199a2d8e0a7SRajeshwari Shinde 	case SND_SOC_DAIFMT_RIGHT_J:
200a2d8e0a7SRajeshwari Shinde 		break;
201a2d8e0a7SRajeshwari Shinde 	case SND_SOC_DAIFMT_LEFT_J:
202a2d8e0a7SRajeshwari Shinde 		aif |= 0x8;
203a2d8e0a7SRajeshwari Shinde 		break;
204a2d8e0a7SRajeshwari Shinde 	default:
205a2d8e0a7SRajeshwari Shinde 		debug("%s: Invalid i2s format selection\n", __func__);
206a2d8e0a7SRajeshwari Shinde 		return -1;
207a2d8e0a7SRajeshwari Shinde 	}
208a2d8e0a7SRajeshwari Shinde 
209a2d8e0a7SRajeshwari Shinde 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
210a2d8e0a7SRajeshwari Shinde 	case SND_SOC_DAIFMT_DSP_A:
211a2d8e0a7SRajeshwari Shinde 	case SND_SOC_DAIFMT_DSP_B:
212a2d8e0a7SRajeshwari Shinde 		/* frame inversion not valid for DSP modes */
213a2d8e0a7SRajeshwari Shinde 		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
214a2d8e0a7SRajeshwari Shinde 		case SND_SOC_DAIFMT_NB_NF:
215a2d8e0a7SRajeshwari Shinde 			break;
216a2d8e0a7SRajeshwari Shinde 		case SND_SOC_DAIFMT_IB_NF:
217a2d8e0a7SRajeshwari Shinde 			aif |= WM8994_AIF1_BCLK_INV;
218a2d8e0a7SRajeshwari Shinde 			break;
219a2d8e0a7SRajeshwari Shinde 		default:
220a2d8e0a7SRajeshwari Shinde 			debug("%s: Invalid i2s frame inverse selection\n",
221a2d8e0a7SRajeshwari Shinde 			      __func__);
222a2d8e0a7SRajeshwari Shinde 			return -1;
223a2d8e0a7SRajeshwari Shinde 		}
224a2d8e0a7SRajeshwari Shinde 		break;
225a2d8e0a7SRajeshwari Shinde 
226a2d8e0a7SRajeshwari Shinde 	case SND_SOC_DAIFMT_I2S:
227a2d8e0a7SRajeshwari Shinde 	case SND_SOC_DAIFMT_RIGHT_J:
228a2d8e0a7SRajeshwari Shinde 	case SND_SOC_DAIFMT_LEFT_J:
229a2d8e0a7SRajeshwari Shinde 		switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
230a2d8e0a7SRajeshwari Shinde 		case SND_SOC_DAIFMT_NB_NF:
231a2d8e0a7SRajeshwari Shinde 			break;
232a2d8e0a7SRajeshwari Shinde 		case SND_SOC_DAIFMT_IB_IF:
233a2d8e0a7SRajeshwari Shinde 			aif |= WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV;
234a2d8e0a7SRajeshwari Shinde 			break;
235a2d8e0a7SRajeshwari Shinde 		case SND_SOC_DAIFMT_IB_NF:
236a2d8e0a7SRajeshwari Shinde 			aif |= WM8994_AIF1_BCLK_INV;
237a2d8e0a7SRajeshwari Shinde 			break;
238a2d8e0a7SRajeshwari Shinde 		case SND_SOC_DAIFMT_NB_IF:
239a2d8e0a7SRajeshwari Shinde 			aif |= WM8994_AIF1_LRCLK_INV;
240a2d8e0a7SRajeshwari Shinde 			break;
241a2d8e0a7SRajeshwari Shinde 		default:
242a2d8e0a7SRajeshwari Shinde 			debug("%s: Invalid i2s clock polarity selection\n",
243a2d8e0a7SRajeshwari Shinde 			      __func__);
244a2d8e0a7SRajeshwari Shinde 			return -1;
245a2d8e0a7SRajeshwari Shinde 		}
246a2d8e0a7SRajeshwari Shinde 		break;
247a2d8e0a7SRajeshwari Shinde 	default:
248a2d8e0a7SRajeshwari Shinde 		debug("%s: Invalid i2s format selection\n", __func__);
249a2d8e0a7SRajeshwari Shinde 		return -1;
250a2d8e0a7SRajeshwari Shinde 	}
251a2d8e0a7SRajeshwari Shinde 
252107ab83eSSimon Glass 	error = wm8994_bic_or(priv, aif_reg, WM8994_AIF1_BCLK_INV |
253107ab83eSSimon Glass 			      WM8994_AIF1_LRCLK_INV_MASK |
254107ab83eSSimon Glass 			       WM8994_AIF1_FMT_MASK, aif);
255a2d8e0a7SRajeshwari Shinde 
256107ab83eSSimon Glass 	error |= wm8994_bic_or(priv, ms_reg, WM8994_AIF1_MSTR_MASK, ms);
257107ab83eSSimon Glass 	error |= wm8994_bic_or(priv, aif_clk, WM8994_AIF1CLK_ENA_MASK,
258a2d8e0a7SRajeshwari Shinde 			       WM8994_AIF1CLK_ENA);
259a2d8e0a7SRajeshwari Shinde 	if (error < 0) {
260a2d8e0a7SRajeshwari Shinde 		debug("%s: codec register access error\n", __func__);
261a2d8e0a7SRajeshwari Shinde 		return -1;
262a2d8e0a7SRajeshwari Shinde 	}
263a2d8e0a7SRajeshwari Shinde 
264a2d8e0a7SRajeshwari Shinde 	return 0;
265a2d8e0a7SRajeshwari Shinde }
266a2d8e0a7SRajeshwari Shinde 
267a2d8e0a7SRajeshwari Shinde /*
268a2d8e0a7SRajeshwari Shinde  * Sets hw params FOR WM8994
269a2d8e0a7SRajeshwari Shinde  *
270107ab83eSSimon Glass  * @param priv			wm8994 information pointer
271a2d8e0a7SRajeshwari Shinde  * @param aif_id		Audio interface ID
272a2d8e0a7SRajeshwari Shinde  * @param sampling_rate		Sampling rate
273a2d8e0a7SRajeshwari Shinde  * @param bits_per_sample	Bits per sample
274a2d8e0a7SRajeshwari Shinde  * @param Channels		Channels in the given audio input
275a2d8e0a7SRajeshwari Shinde  *
276a2d8e0a7SRajeshwari Shinde  * @return -1 for error  and 0  Success.
277a2d8e0a7SRajeshwari Shinde  */
wm8994_hw_params(struct wm8994_priv * priv,int aif_id,uint sampling_rate,uint bits_per_sample,uint channels)278107ab83eSSimon Glass static int wm8994_hw_params(struct wm8994_priv *priv, int aif_id,
279107ab83eSSimon Glass 			    uint sampling_rate, uint bits_per_sample,
280107ab83eSSimon Glass 			    uint channels)
281a2d8e0a7SRajeshwari Shinde {
282a2d8e0a7SRajeshwari Shinde 	int aif1_reg;
283a2d8e0a7SRajeshwari Shinde 	int aif2_reg;
284a2d8e0a7SRajeshwari Shinde 	int bclk_reg;
285a2d8e0a7SRajeshwari Shinde 	int bclk = 0;
286a2d8e0a7SRajeshwari Shinde 	int rate_reg;
287a2d8e0a7SRajeshwari Shinde 	int aif1 = 0;
288a2d8e0a7SRajeshwari Shinde 	int aif2 = 0;
289a2d8e0a7SRajeshwari Shinde 	int rate_val = 0;
290a2d8e0a7SRajeshwari Shinde 	int id = aif_id - 1;
291a2d8e0a7SRajeshwari Shinde 	int i, cur_val, best_val, bclk_rate, best;
292a2d8e0a7SRajeshwari Shinde 	unsigned short reg_data;
293a2d8e0a7SRajeshwari Shinde 	int ret = 0;
294a2d8e0a7SRajeshwari Shinde 
295a2d8e0a7SRajeshwari Shinde 	switch (aif_id) {
296a2d8e0a7SRajeshwari Shinde 	case 1:
297a2d8e0a7SRajeshwari Shinde 		aif1_reg = WM8994_AIF1_CONTROL_1;
298a2d8e0a7SRajeshwari Shinde 		aif2_reg = WM8994_AIF1_CONTROL_2;
299a2d8e0a7SRajeshwari Shinde 		bclk_reg = WM8994_AIF1_BCLK;
300a2d8e0a7SRajeshwari Shinde 		rate_reg = WM8994_AIF1_RATE;
301a2d8e0a7SRajeshwari Shinde 		break;
302a2d8e0a7SRajeshwari Shinde 	case 2:
303a2d8e0a7SRajeshwari Shinde 		aif1_reg = WM8994_AIF2_CONTROL_1;
304a2d8e0a7SRajeshwari Shinde 		aif2_reg = WM8994_AIF2_CONTROL_2;
305a2d8e0a7SRajeshwari Shinde 		bclk_reg = WM8994_AIF2_BCLK;
306a2d8e0a7SRajeshwari Shinde 		rate_reg = WM8994_AIF2_RATE;
307a2d8e0a7SRajeshwari Shinde 		break;
308a2d8e0a7SRajeshwari Shinde 	default:
309a2d8e0a7SRajeshwari Shinde 		return -1;
310a2d8e0a7SRajeshwari Shinde 	}
311a2d8e0a7SRajeshwari Shinde 
312a2d8e0a7SRajeshwari Shinde 	bclk_rate = sampling_rate * 32;
313a2d8e0a7SRajeshwari Shinde 	switch (bits_per_sample) {
314a2d8e0a7SRajeshwari Shinde 	case 16:
315a2d8e0a7SRajeshwari Shinde 		bclk_rate *= 16;
316a2d8e0a7SRajeshwari Shinde 		break;
317a2d8e0a7SRajeshwari Shinde 	case 20:
318a2d8e0a7SRajeshwari Shinde 		bclk_rate *= 20;
319a2d8e0a7SRajeshwari Shinde 		aif1 |= 0x20;
320a2d8e0a7SRajeshwari Shinde 		break;
321a2d8e0a7SRajeshwari Shinde 	case 24:
322a2d8e0a7SRajeshwari Shinde 		bclk_rate *= 24;
323a2d8e0a7SRajeshwari Shinde 		aif1 |= 0x40;
324a2d8e0a7SRajeshwari Shinde 		break;
325a2d8e0a7SRajeshwari Shinde 	case 32:
326a2d8e0a7SRajeshwari Shinde 		bclk_rate *= 32;
327a2d8e0a7SRajeshwari Shinde 		aif1 |= 0x60;
328a2d8e0a7SRajeshwari Shinde 		break;
329a2d8e0a7SRajeshwari Shinde 	default:
330a2d8e0a7SRajeshwari Shinde 		return -1;
331a2d8e0a7SRajeshwari Shinde 	}
332a2d8e0a7SRajeshwari Shinde 
333a2d8e0a7SRajeshwari Shinde 	/* Try to find an appropriate sample rate; look for an exact match. */
334a2d8e0a7SRajeshwari Shinde 	for (i = 0; i < ARRAY_SIZE(src_rate); i++)
335a2d8e0a7SRajeshwari Shinde 		if (src_rate[i] == sampling_rate)
336a2d8e0a7SRajeshwari Shinde 			break;
337a2d8e0a7SRajeshwari Shinde 
338a2d8e0a7SRajeshwari Shinde 	if (i == ARRAY_SIZE(src_rate)) {
339a2d8e0a7SRajeshwari Shinde 		debug("%s: Could not get the best matching samplingrate\n",
340a2d8e0a7SRajeshwari Shinde 		      __func__);
341a2d8e0a7SRajeshwari Shinde 		return -1;
342a2d8e0a7SRajeshwari Shinde 	}
343a2d8e0a7SRajeshwari Shinde 
344a2d8e0a7SRajeshwari Shinde 	rate_val |= i << WM8994_AIF1_SR_SHIFT;
345a2d8e0a7SRajeshwari Shinde 
346a2d8e0a7SRajeshwari Shinde 	/* AIFCLK/fs ratio; look for a close match in either direction */
347a2d8e0a7SRajeshwari Shinde 	best = 0;
348107ab83eSSimon Glass 	best_val = abs((fs_ratios[0] * sampling_rate) - priv->aifclk[id]);
349a2d8e0a7SRajeshwari Shinde 
350a2d8e0a7SRajeshwari Shinde 	for (i = 1; i < ARRAY_SIZE(fs_ratios); i++) {
351107ab83eSSimon Glass 		cur_val = abs(fs_ratios[i] * sampling_rate - priv->aifclk[id]);
352a2d8e0a7SRajeshwari Shinde 		if (cur_val >= best_val)
353a2d8e0a7SRajeshwari Shinde 			continue;
354a2d8e0a7SRajeshwari Shinde 		best = i;
355a2d8e0a7SRajeshwari Shinde 		best_val = cur_val;
356a2d8e0a7SRajeshwari Shinde 	}
357a2d8e0a7SRajeshwari Shinde 
358a2d8e0a7SRajeshwari Shinde 	rate_val |= best;
359a2d8e0a7SRajeshwari Shinde 
360a2d8e0a7SRajeshwari Shinde 	/*
361a2d8e0a7SRajeshwari Shinde 	 * We may not get quite the right frequency if using
362a2d8e0a7SRajeshwari Shinde 	 * approximate clocks so look for the closest match that is
363a2d8e0a7SRajeshwari Shinde 	 * higher than the target (we need to ensure that there enough
364a2d8e0a7SRajeshwari Shinde 	 * BCLKs to clock out the samples).
365a2d8e0a7SRajeshwari Shinde 	 */
366a2d8e0a7SRajeshwari Shinde 	best = 0;
367a2d8e0a7SRajeshwari Shinde 	for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
368107ab83eSSimon Glass 		cur_val = (priv->aifclk[id] * 10 / bclk_divs[i]) - bclk_rate;
369a2d8e0a7SRajeshwari Shinde 		if (cur_val < 0) /* BCLK table is sorted */
370a2d8e0a7SRajeshwari Shinde 			break;
371a2d8e0a7SRajeshwari Shinde 		best = i;
372a2d8e0a7SRajeshwari Shinde 	}
373a2d8e0a7SRajeshwari Shinde 
374a2d8e0a7SRajeshwari Shinde 	if (i ==  ARRAY_SIZE(bclk_divs)) {
375a2d8e0a7SRajeshwari Shinde 		debug("%s: Could not get the best matching bclk division\n",
376a2d8e0a7SRajeshwari Shinde 		      __func__);
377a2d8e0a7SRajeshwari Shinde 		return -1;
378a2d8e0a7SRajeshwari Shinde 	}
379a2d8e0a7SRajeshwari Shinde 
380107ab83eSSimon Glass 	bclk_rate = priv->aifclk[id] * 10 / bclk_divs[best];
381a2d8e0a7SRajeshwari Shinde 	bclk |= best << WM8994_AIF1_BCLK_DIV_SHIFT;
382a2d8e0a7SRajeshwari Shinde 
383107ab83eSSimon Glass 	if (wm8994_i2c_read(priv, aif1_reg, &reg_data) != 0) {
384a2d8e0a7SRajeshwari Shinde 		debug("%s: AIF1 register read Failed\n", __func__);
385a2d8e0a7SRajeshwari Shinde 		return -1;
386a2d8e0a7SRajeshwari Shinde 	}
387a2d8e0a7SRajeshwari Shinde 
388a2d8e0a7SRajeshwari Shinde 	if ((channels == 1) && ((reg_data & 0x18) == 0x18))
389a2d8e0a7SRajeshwari Shinde 		aif2 |= WM8994_AIF1_MONO;
390a2d8e0a7SRajeshwari Shinde 
391107ab83eSSimon Glass 	if (priv->aifclk[id] == 0) {
392a2d8e0a7SRajeshwari Shinde 		debug("%s:Audio interface clock not set\n", __func__);
393a2d8e0a7SRajeshwari Shinde 		return -1;
394a2d8e0a7SRajeshwari Shinde 	}
395a2d8e0a7SRajeshwari Shinde 
396107ab83eSSimon Glass 	ret = wm8994_bic_or(priv, aif1_reg, WM8994_AIF1_WL_MASK, aif1);
397107ab83eSSimon Glass 	ret |= wm8994_bic_or(priv, aif2_reg, WM8994_AIF1_MONO, aif2);
398107ab83eSSimon Glass 	ret |= wm8994_bic_or(priv, bclk_reg, WM8994_AIF1_BCLK_DIV_MASK,
399107ab83eSSimon Glass 				  bclk);
400107ab83eSSimon Glass 	ret |= wm8994_bic_or(priv, rate_reg, WM8994_AIF1_SR_MASK |
401a2d8e0a7SRajeshwari Shinde 				  WM8994_AIF1CLK_RATE_MASK, rate_val);
402a2d8e0a7SRajeshwari Shinde 
403a2d8e0a7SRajeshwari Shinde 	debug("rate vale = %x , bclk val= %x\n", rate_val, bclk);
404a2d8e0a7SRajeshwari Shinde 
405a2d8e0a7SRajeshwari Shinde 	if (ret < 0) {
406a2d8e0a7SRajeshwari Shinde 		debug("%s: codec register access error\n", __func__);
407a2d8e0a7SRajeshwari Shinde 		return -1;
408a2d8e0a7SRajeshwari Shinde 	}
409a2d8e0a7SRajeshwari Shinde 
410a2d8e0a7SRajeshwari Shinde 	return 0;
411a2d8e0a7SRajeshwari Shinde }
412a2d8e0a7SRajeshwari Shinde 
413a2d8e0a7SRajeshwari Shinde /*
414a2d8e0a7SRajeshwari Shinde  * Configures Audio interface Clock
415a2d8e0a7SRajeshwari Shinde  *
416107ab83eSSimon Glass  * @param priv		wm8994 information pointer
417a2d8e0a7SRajeshwari Shinde  * @param aif		Audio Interface ID
418a2d8e0a7SRajeshwari Shinde  *
419a2d8e0a7SRajeshwari Shinde  * @return -1 for error  and 0  Success.
420a2d8e0a7SRajeshwari Shinde  */
configure_aif_clock(struct wm8994_priv * priv,int aif)421107ab83eSSimon Glass static int configure_aif_clock(struct wm8994_priv *priv, int aif)
422a2d8e0a7SRajeshwari Shinde {
423a2d8e0a7SRajeshwari Shinde 	int rate;
424a2d8e0a7SRajeshwari Shinde 	int reg1 = 0;
425a2d8e0a7SRajeshwari Shinde 	int offset;
426a2d8e0a7SRajeshwari Shinde 	int ret;
427a2d8e0a7SRajeshwari Shinde 
428a2d8e0a7SRajeshwari Shinde 	/* AIF(1/0) register adress offset calculated */
429d981d80dSDani Krishna Mohan 	if (aif-1)
430a2d8e0a7SRajeshwari Shinde 		offset = 4;
431a2d8e0a7SRajeshwari Shinde 	else
432a2d8e0a7SRajeshwari Shinde 		offset = 0;
433a2d8e0a7SRajeshwari Shinde 
434107ab83eSSimon Glass 	switch (priv->sysclk[aif - 1]) {
435a2d8e0a7SRajeshwari Shinde 	case WM8994_SYSCLK_MCLK1:
436a2d8e0a7SRajeshwari Shinde 		reg1 |= SEL_MCLK1;
437107ab83eSSimon Glass 		rate = priv->mclk[0];
438a2d8e0a7SRajeshwari Shinde 		break;
439a2d8e0a7SRajeshwari Shinde 
440a2d8e0a7SRajeshwari Shinde 	case WM8994_SYSCLK_MCLK2:
441a2d8e0a7SRajeshwari Shinde 		reg1 |= SEL_MCLK2;
442107ab83eSSimon Glass 		rate = priv->mclk[1];
443a2d8e0a7SRajeshwari Shinde 		break;
444a2d8e0a7SRajeshwari Shinde 
445a2d8e0a7SRajeshwari Shinde 	case WM8994_SYSCLK_FLL1:
446a2d8e0a7SRajeshwari Shinde 		reg1 |= SEL_FLL1;
447107ab83eSSimon Glass 		rate = priv->fll[0].out;
448a2d8e0a7SRajeshwari Shinde 		break;
449a2d8e0a7SRajeshwari Shinde 
450a2d8e0a7SRajeshwari Shinde 	case WM8994_SYSCLK_FLL2:
451a2d8e0a7SRajeshwari Shinde 		reg1 |= SEL_FLL2;
452107ab83eSSimon Glass 		rate = priv->fll[1].out;
453a2d8e0a7SRajeshwari Shinde 		break;
454a2d8e0a7SRajeshwari Shinde 
455a2d8e0a7SRajeshwari Shinde 	default:
456a2d8e0a7SRajeshwari Shinde 		debug("%s: Invalid input clock selection [%d]\n",
457107ab83eSSimon Glass 		      __func__, priv->sysclk[aif - 1]);
458a2d8e0a7SRajeshwari Shinde 		return -1;
459a2d8e0a7SRajeshwari Shinde 	}
460a2d8e0a7SRajeshwari Shinde 
461a2d8e0a7SRajeshwari Shinde 	/* if input clock frequenct is more than 135Mhz then divide */
462a2d8e0a7SRajeshwari Shinde 	if (rate >= WM8994_MAX_INPUT_CLK_FREQ) {
463a2d8e0a7SRajeshwari Shinde 		rate /= 2;
464a2d8e0a7SRajeshwari Shinde 		reg1 |= WM8994_AIF1CLK_DIV;
465a2d8e0a7SRajeshwari Shinde 	}
466a2d8e0a7SRajeshwari Shinde 
467107ab83eSSimon Glass 	priv->aifclk[aif - 1] = rate;
468a2d8e0a7SRajeshwari Shinde 
469107ab83eSSimon Glass 	ret = wm8994_bic_or(priv, WM8994_AIF1_CLOCKING_1 + offset,
470a2d8e0a7SRajeshwari Shinde 			    WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV,
471a2d8e0a7SRajeshwari Shinde 			    reg1);
472a2d8e0a7SRajeshwari Shinde 
473d981d80dSDani Krishna Mohan 	if (aif == WM8994_AIF1)
474107ab83eSSimon Glass 		ret |= wm8994_bic_or(priv, WM8994_CLOCKING_1,
475d981d80dSDani Krishna Mohan 			WM8994_AIF1DSPCLK_ENA_MASK | WM8994_SYSDSPCLK_ENA_MASK,
476d981d80dSDani Krishna Mohan 			WM8994_AIF1DSPCLK_ENA | WM8994_SYSDSPCLK_ENA);
477d981d80dSDani Krishna Mohan 	else if (aif == WM8994_AIF2)
478107ab83eSSimon Glass 		ret |= wm8994_bic_or(priv, WM8994_CLOCKING_1,
479a2d8e0a7SRajeshwari Shinde 			WM8994_SYSCLK_SRC | WM8994_AIF2DSPCLK_ENA_MASK |
480a2d8e0a7SRajeshwari Shinde 			WM8994_SYSDSPCLK_ENA_MASK, WM8994_SYSCLK_SRC |
481a2d8e0a7SRajeshwari Shinde 			WM8994_AIF2DSPCLK_ENA | WM8994_SYSDSPCLK_ENA);
482a2d8e0a7SRajeshwari Shinde 
483a2d8e0a7SRajeshwari Shinde 	if (ret < 0) {
484a2d8e0a7SRajeshwari Shinde 		debug("%s: codec register access error\n", __func__);
485a2d8e0a7SRajeshwari Shinde 		return -1;
486a2d8e0a7SRajeshwari Shinde 	}
487a2d8e0a7SRajeshwari Shinde 
488a2d8e0a7SRajeshwari Shinde 	return 0;
489a2d8e0a7SRajeshwari Shinde }
490a2d8e0a7SRajeshwari Shinde 
491a2d8e0a7SRajeshwari Shinde /*
492a2d8e0a7SRajeshwari Shinde  * Configures Audio interface  for the given frequency
493a2d8e0a7SRajeshwari Shinde  *
494107ab83eSSimon Glass  * @param priv		wm8994 information
495a2d8e0a7SRajeshwari Shinde  * @param aif_id	Audio Interface
496a2d8e0a7SRajeshwari Shinde  * @param clk_id	Input Clock ID
497a2d8e0a7SRajeshwari Shinde  * @param freq		Sampling frequency in Hz
498a2d8e0a7SRajeshwari Shinde  *
499a2d8e0a7SRajeshwari Shinde  * @return -1 for error and 0 success.
500a2d8e0a7SRajeshwari Shinde  */
wm8994_set_sysclk(struct wm8994_priv * priv,int aif_id,int clk_id,unsigned int freq)501107ab83eSSimon Glass static int wm8994_set_sysclk(struct wm8994_priv *priv, int aif_id, int clk_id,
502107ab83eSSimon Glass 			     unsigned int freq)
503a2d8e0a7SRajeshwari Shinde {
504a2d8e0a7SRajeshwari Shinde 	int i;
505a2d8e0a7SRajeshwari Shinde 	int ret = 0;
506a2d8e0a7SRajeshwari Shinde 
507107ab83eSSimon Glass 	priv->sysclk[aif_id - 1] = clk_id;
508a2d8e0a7SRajeshwari Shinde 
509a2d8e0a7SRajeshwari Shinde 	switch (clk_id) {
510a2d8e0a7SRajeshwari Shinde 	case WM8994_SYSCLK_MCLK1:
511107ab83eSSimon Glass 		priv->mclk[0] = freq;
512a2d8e0a7SRajeshwari Shinde 		if (aif_id == 2) {
513107ab83eSSimon Glass 			ret = wm8994_bic_or(priv, WM8994_AIF1_CLOCKING_2,
514a2d8e0a7SRajeshwari Shinde 					    WM8994_AIF2DAC_DIV_MASK, 0);
515a2d8e0a7SRajeshwari Shinde 		}
516a2d8e0a7SRajeshwari Shinde 		break;
517a2d8e0a7SRajeshwari Shinde 
518a2d8e0a7SRajeshwari Shinde 	case WM8994_SYSCLK_MCLK2:
519a2d8e0a7SRajeshwari Shinde 		/* TODO: Set GPIO AF */
520107ab83eSSimon Glass 		priv->mclk[1] = freq;
521a2d8e0a7SRajeshwari Shinde 		break;
522a2d8e0a7SRajeshwari Shinde 
523a2d8e0a7SRajeshwari Shinde 	case WM8994_SYSCLK_FLL1:
524a2d8e0a7SRajeshwari Shinde 	case WM8994_SYSCLK_FLL2:
525a2d8e0a7SRajeshwari Shinde 		break;
526a2d8e0a7SRajeshwari Shinde 
527a2d8e0a7SRajeshwari Shinde 	case WM8994_SYSCLK_OPCLK:
528a2d8e0a7SRajeshwari Shinde 		/*
529a2d8e0a7SRajeshwari Shinde 		 * Special case - a division (times 10) is given and
530a2d8e0a7SRajeshwari Shinde 		 * no effect on main clocking.
531a2d8e0a7SRajeshwari Shinde 		 */
532a2d8e0a7SRajeshwari Shinde 		if (freq) {
533a2d8e0a7SRajeshwari Shinde 			for (i = 0; i < ARRAY_SIZE(opclk_divs); i++)
534a2d8e0a7SRajeshwari Shinde 				if (opclk_divs[i] == freq)
535a2d8e0a7SRajeshwari Shinde 					break;
536a2d8e0a7SRajeshwari Shinde 			if (i == ARRAY_SIZE(opclk_divs)) {
537a2d8e0a7SRajeshwari Shinde 				debug("%s frequency divisor not found\n",
538a2d8e0a7SRajeshwari Shinde 				      __func__);
539a2d8e0a7SRajeshwari Shinde 				return -1;
540a2d8e0a7SRajeshwari Shinde 			}
541107ab83eSSimon Glass 			ret = wm8994_bic_or(priv, WM8994_CLOCKING_2,
542a2d8e0a7SRajeshwari Shinde 					    WM8994_OPCLK_DIV_MASK, i);
543107ab83eSSimon Glass 			ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_2,
544107ab83eSSimon Glass 					     WM8994_OPCLK_ENA,
545107ab83eSSimon Glass 					     WM8994_OPCLK_ENA);
546a2d8e0a7SRajeshwari Shinde 		} else {
547107ab83eSSimon Glass 			ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_2,
548a2d8e0a7SRajeshwari Shinde 					     WM8994_OPCLK_ENA, 0);
549a2d8e0a7SRajeshwari Shinde 		}
550a2d8e0a7SRajeshwari Shinde 
551a2d8e0a7SRajeshwari Shinde 	default:
552a2d8e0a7SRajeshwari Shinde 		debug("%s Invalid input clock selection [%d]\n",
553a2d8e0a7SRajeshwari Shinde 		      __func__, clk_id);
554a2d8e0a7SRajeshwari Shinde 		return -1;
555a2d8e0a7SRajeshwari Shinde 	}
556a2d8e0a7SRajeshwari Shinde 
557107ab83eSSimon Glass 	ret |= configure_aif_clock(priv, aif_id);
558a2d8e0a7SRajeshwari Shinde 
559a2d8e0a7SRajeshwari Shinde 	if (ret < 0) {
560a2d8e0a7SRajeshwari Shinde 		debug("%s: codec register access error\n", __func__);
561a2d8e0a7SRajeshwari Shinde 		return -1;
562a2d8e0a7SRajeshwari Shinde 	}
563a2d8e0a7SRajeshwari Shinde 
564a2d8e0a7SRajeshwari Shinde 	return 0;
565a2d8e0a7SRajeshwari Shinde }
566a2d8e0a7SRajeshwari Shinde 
567a2d8e0a7SRajeshwari Shinde /*
568a2d8e0a7SRajeshwari Shinde  * Initializes Volume for AIF2 to HP path
569a2d8e0a7SRajeshwari Shinde  *
570107ab83eSSimon Glass  * @param priv		wm8994 information
571a2d8e0a7SRajeshwari Shinde  * @returns -1 for error  and 0 Success.
572a2d8e0a7SRajeshwari Shinde  *
573a2d8e0a7SRajeshwari Shinde  */
wm8994_init_volume_aif2_dac1(struct wm8994_priv * priv)574107ab83eSSimon Glass static int wm8994_init_volume_aif2_dac1(struct wm8994_priv *priv)
575a2d8e0a7SRajeshwari Shinde {
576a2d8e0a7SRajeshwari Shinde 	int ret;
577a2d8e0a7SRajeshwari Shinde 
578a2d8e0a7SRajeshwari Shinde 	/* Unmute AIF2DAC */
579107ab83eSSimon Glass 	ret = wm8994_bic_or(priv, WM8994_AIF2_DAC_FILTERS_1,
580a2d8e0a7SRajeshwari Shinde 			    WM8994_AIF2DAC_MUTE_MASK, 0);
581a2d8e0a7SRajeshwari Shinde 
582a2d8e0a7SRajeshwari Shinde 
583107ab83eSSimon Glass 	ret |= wm8994_bic_or(priv, WM8994_AIF2_DAC_LEFT_VOLUME,
584a2d8e0a7SRajeshwari Shinde 			     WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACL_VOL_MASK,
585a2d8e0a7SRajeshwari Shinde 			     WM8994_AIF2DAC_VU | 0xff);
586a2d8e0a7SRajeshwari Shinde 
587107ab83eSSimon Glass 	ret |= wm8994_bic_or(priv, WM8994_AIF2_DAC_RIGHT_VOLUME,
588a2d8e0a7SRajeshwari Shinde 			     WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACR_VOL_MASK,
589a2d8e0a7SRajeshwari Shinde 			     WM8994_AIF2DAC_VU | 0xff);
590a2d8e0a7SRajeshwari Shinde 
591a2d8e0a7SRajeshwari Shinde 
592107ab83eSSimon Glass 	ret |= wm8994_bic_or(priv, WM8994_DAC1_LEFT_VOLUME,
593a2d8e0a7SRajeshwari Shinde 			     WM8994_DAC1_VU_MASK | WM8994_DAC1L_VOL_MASK |
594a2d8e0a7SRajeshwari Shinde 			     WM8994_DAC1L_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
595a2d8e0a7SRajeshwari Shinde 
596107ab83eSSimon Glass 	ret |= wm8994_bic_or(priv, WM8994_DAC1_RIGHT_VOLUME,
597a2d8e0a7SRajeshwari Shinde 			     WM8994_DAC1_VU_MASK | WM8994_DAC1R_VOL_MASK |
598a2d8e0a7SRajeshwari Shinde 			     WM8994_DAC1R_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
599a2d8e0a7SRajeshwari Shinde 	/* Head Phone Volume */
600107ab83eSSimon Glass 	ret |= wm8994_i2c_write(priv, WM8994_LEFT_OUTPUT_VOLUME, 0x12D);
601107ab83eSSimon Glass 	ret |= wm8994_i2c_write(priv, WM8994_RIGHT_OUTPUT_VOLUME, 0x12D);
602a2d8e0a7SRajeshwari Shinde 
603a2d8e0a7SRajeshwari Shinde 	if (ret < 0) {
604a2d8e0a7SRajeshwari Shinde 		debug("%s: codec register access error\n", __func__);
605a2d8e0a7SRajeshwari Shinde 		return -1;
606a2d8e0a7SRajeshwari Shinde 	}
607a2d8e0a7SRajeshwari Shinde 
608a2d8e0a7SRajeshwari Shinde 	return 0;
609a2d8e0a7SRajeshwari Shinde }
610a2d8e0a7SRajeshwari Shinde 
611a2d8e0a7SRajeshwari Shinde /*
612d981d80dSDani Krishna Mohan  * Initializes Volume for AIF1 to HP path
613d981d80dSDani Krishna Mohan  *
614107ab83eSSimon Glass  * @param priv		wm8994 information
615d981d80dSDani Krishna Mohan  * @returns -1 for error  and 0 Success.
616d981d80dSDani Krishna Mohan  *
617d981d80dSDani Krishna Mohan  */
wm8994_init_volume_aif1_dac1(struct wm8994_priv * priv)618107ab83eSSimon Glass static int wm8994_init_volume_aif1_dac1(struct wm8994_priv *priv)
619d981d80dSDani Krishna Mohan {
620d981d80dSDani Krishna Mohan 	int ret = 0;
621d981d80dSDani Krishna Mohan 
622d981d80dSDani Krishna Mohan 	/* Unmute AIF1DAC */
623107ab83eSSimon Glass 	ret |= wm8994_i2c_write(priv, WM8994_AIF1_DAC_FILTERS_1, 0x0000);
624d981d80dSDani Krishna Mohan 
625107ab83eSSimon Glass 	ret |= wm8994_bic_or(priv, WM8994_DAC1_LEFT_VOLUME,
626d981d80dSDani Krishna Mohan 			     WM8994_DAC1_VU_MASK | WM8994_DAC1L_VOL_MASK |
627d981d80dSDani Krishna Mohan 			     WM8994_DAC1L_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
628d981d80dSDani Krishna Mohan 
629107ab83eSSimon Glass 	ret |= wm8994_bic_or(priv, WM8994_DAC1_RIGHT_VOLUME,
630d981d80dSDani Krishna Mohan 			     WM8994_DAC1_VU_MASK | WM8994_DAC1R_VOL_MASK |
631d981d80dSDani Krishna Mohan 			     WM8994_DAC1R_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
632d981d80dSDani Krishna Mohan 	/* Head Phone Volume */
633107ab83eSSimon Glass 	ret |= wm8994_i2c_write(priv, WM8994_LEFT_OUTPUT_VOLUME, 0x12D);
634107ab83eSSimon Glass 	ret |= wm8994_i2c_write(priv, WM8994_RIGHT_OUTPUT_VOLUME, 0x12D);
635d981d80dSDani Krishna Mohan 
636d981d80dSDani Krishna Mohan 	if (ret < 0) {
637d981d80dSDani Krishna Mohan 		debug("%s: codec register access error\n", __func__);
638d981d80dSDani Krishna Mohan 		return -1;
639d981d80dSDani Krishna Mohan 	}
640d981d80dSDani Krishna Mohan 
641d981d80dSDani Krishna Mohan 	return 0;
642d981d80dSDani Krishna Mohan }
643d981d80dSDani Krishna Mohan 
644d981d80dSDani Krishna Mohan /*
645a2d8e0a7SRajeshwari Shinde  * Intialise wm8994 codec device
646a2d8e0a7SRajeshwari Shinde  *
647107ab83eSSimon Glass  * @param priv		wm8994 information
648a2d8e0a7SRajeshwari Shinde  *
649a2d8e0a7SRajeshwari Shinde  * @returns -1 for error  and 0 Success.
650a2d8e0a7SRajeshwari Shinde  */
wm8994_device_init(struct wm8994_priv * priv)651cfbe7623SSimon Glass static int wm8994_device_init(struct wm8994_priv *priv)
652a2d8e0a7SRajeshwari Shinde {
653a2d8e0a7SRajeshwari Shinde 	const char *devname;
654a2d8e0a7SRajeshwari Shinde 	unsigned short reg_data;
655a2d8e0a7SRajeshwari Shinde 	int ret;
656a2d8e0a7SRajeshwari Shinde 
657107ab83eSSimon Glass 	wm8994_i2c_write(priv, WM8994_SOFTWARE_RESET, WM8994_SW_RESET);
658a2d8e0a7SRajeshwari Shinde 
659107ab83eSSimon Glass 	ret = wm8994_i2c_read(priv, WM8994_SOFTWARE_RESET, &reg_data);
660a2d8e0a7SRajeshwari Shinde 	if (ret < 0) {
661a2d8e0a7SRajeshwari Shinde 		debug("Failed to read ID register\n");
662cfbe7623SSimon Glass 		return ret;
663a2d8e0a7SRajeshwari Shinde 	}
664a2d8e0a7SRajeshwari Shinde 
665a2d8e0a7SRajeshwari Shinde 	if (reg_data == WM8994_ID) {
666a2d8e0a7SRajeshwari Shinde 		devname = "WM8994";
667107ab83eSSimon Glass 		debug("Device registered as type %d\n", priv->type);
668107ab83eSSimon Glass 		priv->type = WM8994;
669a2d8e0a7SRajeshwari Shinde 	} else {
670a2d8e0a7SRajeshwari Shinde 		debug("Device is not a WM8994, ID is %x\n", ret);
671cfbe7623SSimon Glass 		return -ENXIO;
672a2d8e0a7SRajeshwari Shinde 	}
673a2d8e0a7SRajeshwari Shinde 
674107ab83eSSimon Glass 	ret = wm8994_i2c_read(priv, WM8994_CHIP_REVISION, &reg_data);
675a2d8e0a7SRajeshwari Shinde 	if (ret < 0) {
676a2d8e0a7SRajeshwari Shinde 		debug("Failed to read revision register: %d\n", ret);
677cfbe7623SSimon Glass 		return ret;
678a2d8e0a7SRajeshwari Shinde 	}
679107ab83eSSimon Glass 	priv->revision = reg_data;
680107ab83eSSimon Glass 	debug("%s revision %c\n", devname, 'A' + priv->revision);
681a2d8e0a7SRajeshwari Shinde 
682cfbe7623SSimon Glass 	return 0;
683cfbe7623SSimon Glass }
684cfbe7623SSimon Glass 
wm8994_setup_interface(struct wm8994_priv * priv,enum en_audio_interface aif_id)685cfbe7623SSimon Glass static int wm8994_setup_interface(struct wm8994_priv *priv,
686cfbe7623SSimon Glass 				  enum en_audio_interface aif_id)
687cfbe7623SSimon Glass {
688cfbe7623SSimon Glass 	int ret;
689cfbe7623SSimon Glass 
690a2d8e0a7SRajeshwari Shinde 	/* VMID Selection */
691cfbe7623SSimon Glass 	ret = wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_1,
692a2d8e0a7SRajeshwari Shinde 			    WM8994_VMID_SEL_MASK | WM8994_BIAS_ENA_MASK, 0x3);
693a2d8e0a7SRajeshwari Shinde 
694a2d8e0a7SRajeshwari Shinde 	/* Charge Pump Enable */
695107ab83eSSimon Glass 	ret |= wm8994_bic_or(priv, WM8994_CHARGE_PUMP_1, WM8994_CP_ENA_MASK,
696a2d8e0a7SRajeshwari Shinde 			     WM8994_CP_ENA);
697a2d8e0a7SRajeshwari Shinde 
698a2d8e0a7SRajeshwari Shinde 	/* Head Phone Power Enable */
699107ab83eSSimon Glass 	ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_1,
700a2d8e0a7SRajeshwari Shinde 			     WM8994_HPOUT1L_ENA_MASK, WM8994_HPOUT1L_ENA);
701a2d8e0a7SRajeshwari Shinde 
702107ab83eSSimon Glass 	ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_1,
703a2d8e0a7SRajeshwari Shinde 			     WM8994_HPOUT1R_ENA_MASK, WM8994_HPOUT1R_ENA);
704a2d8e0a7SRajeshwari Shinde 
705d981d80dSDani Krishna Mohan 	if (aif_id == WM8994_AIF1) {
706107ab83eSSimon Glass 		ret |= wm8994_i2c_write(priv, WM8994_POWER_MANAGEMENT_2,
707d981d80dSDani Krishna Mohan 					WM8994_TSHUT_ENA | WM8994_MIXINL_ENA |
708d981d80dSDani Krishna Mohan 					WM8994_MIXINR_ENA | WM8994_IN2L_ENA |
709d981d80dSDani Krishna Mohan 					WM8994_IN2R_ENA);
710d981d80dSDani Krishna Mohan 
711107ab83eSSimon Glass 		ret |= wm8994_i2c_write(priv, WM8994_POWER_MANAGEMENT_4,
712d981d80dSDani Krishna Mohan 					WM8994_ADCL_ENA | WM8994_ADCR_ENA |
713d981d80dSDani Krishna Mohan 					WM8994_AIF1ADC1R_ENA |
714d981d80dSDani Krishna Mohan 					WM8994_AIF1ADC1L_ENA);
715d981d80dSDani Krishna Mohan 
716d981d80dSDani Krishna Mohan 		/* Power enable for AIF1 and DAC1 */
717107ab83eSSimon Glass 		ret |= wm8994_i2c_write(priv, WM8994_POWER_MANAGEMENT_5,
718d981d80dSDani Krishna Mohan 					WM8994_AIF1DACL_ENA |
719d981d80dSDani Krishna Mohan 					WM8994_AIF1DACR_ENA |
720d981d80dSDani Krishna Mohan 					WM8994_DAC1L_ENA | WM8994_DAC1R_ENA);
721d981d80dSDani Krishna Mohan 	} else if (aif_id == WM8994_AIF2) {
722a2d8e0a7SRajeshwari Shinde 		/* Power enable for AIF2 and DAC1 */
723107ab83eSSimon Glass 		ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_5,
724a2d8e0a7SRajeshwari Shinde 			WM8994_AIF2DACL_ENA_MASK | WM8994_AIF2DACR_ENA_MASK |
725a2d8e0a7SRajeshwari Shinde 			WM8994_DAC1L_ENA_MASK | WM8994_DAC1R_ENA_MASK,
726d981d80dSDani Krishna Mohan 			WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA |
727d981d80dSDani Krishna Mohan 			WM8994_DAC1L_ENA | WM8994_DAC1R_ENA);
728d981d80dSDani Krishna Mohan 	}
729a2d8e0a7SRajeshwari Shinde 	/* Head Phone Initialisation */
730107ab83eSSimon Glass 	ret |= wm8994_bic_or(priv, WM8994_ANALOGUE_HP_1,
731a2d8e0a7SRajeshwari Shinde 		WM8994_HPOUT1L_DLY_MASK | WM8994_HPOUT1R_DLY_MASK,
732a2d8e0a7SRajeshwari Shinde 		WM8994_HPOUT1L_DLY | WM8994_HPOUT1R_DLY);
733a2d8e0a7SRajeshwari Shinde 
734107ab83eSSimon Glass 	ret |= wm8994_bic_or(priv, WM8994_DC_SERVO_1,
735a2d8e0a7SRajeshwari Shinde 			WM8994_DCS_ENA_CHAN_0_MASK |
736a2d8e0a7SRajeshwari Shinde 			WM8994_DCS_ENA_CHAN_1_MASK , WM8994_DCS_ENA_CHAN_0 |
737a2d8e0a7SRajeshwari Shinde 			WM8994_DCS_ENA_CHAN_1);
738a2d8e0a7SRajeshwari Shinde 
739107ab83eSSimon Glass 	ret |= wm8994_bic_or(priv, WM8994_ANALOGUE_HP_1,
740a2d8e0a7SRajeshwari Shinde 			WM8994_HPOUT1L_DLY_MASK |
741a2d8e0a7SRajeshwari Shinde 			WM8994_HPOUT1R_DLY_MASK | WM8994_HPOUT1L_OUTP_MASK |
742a2d8e0a7SRajeshwari Shinde 			WM8994_HPOUT1R_OUTP_MASK |
743a2d8e0a7SRajeshwari Shinde 			WM8994_HPOUT1L_RMV_SHORT_MASK |
744a2d8e0a7SRajeshwari Shinde 			WM8994_HPOUT1R_RMV_SHORT_MASK, WM8994_HPOUT1L_DLY |
745a2d8e0a7SRajeshwari Shinde 			WM8994_HPOUT1R_DLY | WM8994_HPOUT1L_OUTP |
746a2d8e0a7SRajeshwari Shinde 			WM8994_HPOUT1R_OUTP | WM8994_HPOUT1L_RMV_SHORT |
747a2d8e0a7SRajeshwari Shinde 			WM8994_HPOUT1R_RMV_SHORT);
748a2d8e0a7SRajeshwari Shinde 
749a2d8e0a7SRajeshwari Shinde 	/* MIXER Config DAC1 to HP */
750107ab83eSSimon Glass 	ret |= wm8994_bic_or(priv, WM8994_OUTPUT_MIXER_1,
751107ab83eSSimon Glass 			     WM8994_DAC1L_TO_HPOUT1L_MASK,
752107ab83eSSimon Glass 			     WM8994_DAC1L_TO_HPOUT1L);
753a2d8e0a7SRajeshwari Shinde 
754107ab83eSSimon Glass 	ret |= wm8994_bic_or(priv, WM8994_OUTPUT_MIXER_2,
755107ab83eSSimon Glass 			     WM8994_DAC1R_TO_HPOUT1R_MASK,
756107ab83eSSimon Glass 			     WM8994_DAC1R_TO_HPOUT1R);
757a2d8e0a7SRajeshwari Shinde 
758d981d80dSDani Krishna Mohan 	if (aif_id == WM8994_AIF1) {
759d981d80dSDani Krishna Mohan 		/* Routing AIF1 to DAC1 */
760107ab83eSSimon Glass 		ret |= wm8994_i2c_write(priv, WM8994_DAC1_LEFT_MIXER_ROUTING,
761d981d80dSDani Krishna Mohan 					WM8994_AIF1DAC1L_TO_DAC1L);
762d981d80dSDani Krishna Mohan 
763107ab83eSSimon Glass 		ret |= wm8994_i2c_write(priv, WM8994_DAC1_RIGHT_MIXER_ROUTING,
764d981d80dSDani Krishna Mohan 					WM8994_AIF1DAC1R_TO_DAC1R);
765d981d80dSDani Krishna Mohan 
766d981d80dSDani Krishna Mohan 		/* GPIO Settings for AIF1 */
767107ab83eSSimon Glass 		ret |=  wm8994_i2c_write(priv, WM8994_GPIO_1,
768107ab83eSSimon Glass 					 WM8994_GPIO_DIR_OUTPUT |
769107ab83eSSimon Glass 					 WM8994_GPIO_FUNCTION_I2S_CLK |
770107ab83eSSimon Glass 					 WM8994_GPIO_INPUT_DEBOUNCE);
771d981d80dSDani Krishna Mohan 
772107ab83eSSimon Glass 		ret |= wm8994_init_volume_aif1_dac1(priv);
773d981d80dSDani Krishna Mohan 	} else if (aif_id == WM8994_AIF2) {
774a2d8e0a7SRajeshwari Shinde 		/* Routing AIF2 to DAC1 */
775107ab83eSSimon Glass 		ret |= wm8994_bic_or(priv, WM8994_DAC1_LEFT_MIXER_ROUTING,
776a2d8e0a7SRajeshwari Shinde 				     WM8994_AIF2DACL_TO_DAC1L_MASK,
777a2d8e0a7SRajeshwari Shinde 				     WM8994_AIF2DACL_TO_DAC1L);
778a2d8e0a7SRajeshwari Shinde 
779107ab83eSSimon Glass 		ret |= wm8994_bic_or(priv, WM8994_DAC1_RIGHT_MIXER_ROUTING,
780a2d8e0a7SRajeshwari Shinde 				     WM8994_AIF2DACR_TO_DAC1R_MASK,
781a2d8e0a7SRajeshwari Shinde 				     WM8994_AIF2DACR_TO_DAC1R);
782a2d8e0a7SRajeshwari Shinde 
783a2d8e0a7SRajeshwari Shinde 		/* GPIO Settings for AIF2 */
784a2d8e0a7SRajeshwari Shinde 		/* B CLK */
785107ab83eSSimon Glass 		ret |= wm8994_bic_or(priv, WM8994_GPIO_3, WM8994_GPIO_DIR_MASK |
786a2d8e0a7SRajeshwari Shinde 				     WM8994_GPIO_FUNCTION_MASK,
787d981d80dSDani Krishna Mohan 				     WM8994_GPIO_DIR_OUTPUT);
788a2d8e0a7SRajeshwari Shinde 
789a2d8e0a7SRajeshwari Shinde 		/* LR CLK */
790107ab83eSSimon Glass 		ret |= wm8994_bic_or(priv, WM8994_GPIO_4, WM8994_GPIO_DIR_MASK |
791a2d8e0a7SRajeshwari Shinde 				     WM8994_GPIO_FUNCTION_MASK,
792d981d80dSDani Krishna Mohan 				     WM8994_GPIO_DIR_OUTPUT);
793a2d8e0a7SRajeshwari Shinde 
794a2d8e0a7SRajeshwari Shinde 		/* DATA */
795107ab83eSSimon Glass 		ret |= wm8994_bic_or(priv, WM8994_GPIO_5, WM8994_GPIO_DIR_MASK |
796a2d8e0a7SRajeshwari Shinde 				     WM8994_GPIO_FUNCTION_MASK,
797d981d80dSDani Krishna Mohan 				     WM8994_GPIO_DIR_OUTPUT);
798a2d8e0a7SRajeshwari Shinde 
799107ab83eSSimon Glass 		ret |= wm8994_init_volume_aif2_dac1(priv);
800d981d80dSDani Krishna Mohan 	}
801d981d80dSDani Krishna Mohan 
802a2d8e0a7SRajeshwari Shinde 	if (ret < 0)
803a2d8e0a7SRajeshwari Shinde 		goto err;
804a2d8e0a7SRajeshwari Shinde 
805cfbe7623SSimon Glass 	debug("%s: Codec chip setup ok\n", __func__);
806a2d8e0a7SRajeshwari Shinde 	return 0;
807a2d8e0a7SRajeshwari Shinde err:
808cfbe7623SSimon Glass 	debug("%s: Codec chip setup error\n", __func__);
809a2d8e0a7SRajeshwari Shinde 	return -1;
810a2d8e0a7SRajeshwari Shinde }
811a2d8e0a7SRajeshwari Shinde 
_wm8994_init(struct wm8994_priv * priv,enum en_audio_interface aif_id,int sampling_rate,int mclk_freq,int bits_per_sample,unsigned int channels)81254e67e27SSimon Glass static int _wm8994_init(struct wm8994_priv *priv,
81354e67e27SSimon Glass 			enum en_audio_interface aif_id, int sampling_rate,
81454e67e27SSimon Glass 			int mclk_freq, int bits_per_sample,
81554e67e27SSimon Glass 			unsigned int channels)
81654e67e27SSimon Glass {
81754e67e27SSimon Glass 	int ret;
81854e67e27SSimon Glass 
819cfbe7623SSimon Glass 	ret = wm8994_setup_interface(priv, aif_id);
82054e67e27SSimon Glass 	if (ret < 0) {
82154e67e27SSimon Glass 		debug("%s: wm8994 codec chip init failed\n", __func__);
82254e67e27SSimon Glass 		return ret;
82354e67e27SSimon Glass 	}
82454e67e27SSimon Glass 
82554e67e27SSimon Glass 	ret = wm8994_set_sysclk(priv, aif_id, WM8994_SYSCLK_MCLK1, mclk_freq);
82654e67e27SSimon Glass 	if (ret < 0) {
82754e67e27SSimon Glass 		debug("%s: wm8994 codec set sys clock failed\n", __func__);
82854e67e27SSimon Glass 		return ret;
82954e67e27SSimon Glass 	}
83054e67e27SSimon Glass 
83154e67e27SSimon Glass 	ret = wm8994_hw_params(priv, aif_id, sampling_rate, bits_per_sample,
83254e67e27SSimon Glass 			       channels);
83354e67e27SSimon Glass 
83454e67e27SSimon Glass 	if (ret == 0) {
83554e67e27SSimon Glass 		ret = wm8994_set_fmt(priv, aif_id, SND_SOC_DAIFMT_I2S |
83654e67e27SSimon Glass 				     SND_SOC_DAIFMT_NB_NF |
83754e67e27SSimon Glass 				     SND_SOC_DAIFMT_CBS_CFS);
83854e67e27SSimon Glass 	}
83954e67e27SSimon Glass 
84054e67e27SSimon Glass 	return ret;
84154e67e27SSimon Glass }
84254e67e27SSimon Glass 
wm8994_set_params(struct udevice * dev,int interface,int rate,int mclk_freq,int bits_per_sample,uint channels)843*d6cadd59SSimon Glass static int wm8994_set_params(struct udevice *dev, int interface, int rate,
844*d6cadd59SSimon Glass 			     int mclk_freq, int bits_per_sample, uint channels)
845*d6cadd59SSimon Glass {
846*d6cadd59SSimon Glass 	struct wm8994_priv *priv = dev_get_priv(dev);
847*d6cadd59SSimon Glass 
848*d6cadd59SSimon Glass 	return _wm8994_init(priv, interface, rate, mclk_freq, bits_per_sample,
849*d6cadd59SSimon Glass 			    channels);
850*d6cadd59SSimon Glass }
851*d6cadd59SSimon Glass 
wm8994_probe(struct udevice * dev)852*d6cadd59SSimon Glass static int wm8994_probe(struct udevice *dev)
853*d6cadd59SSimon Glass {
854*d6cadd59SSimon Glass 	struct wm8994_priv *priv = dev_get_priv(dev);
855*d6cadd59SSimon Glass 
856*d6cadd59SSimon Glass 	priv->dev = dev;
857*d6cadd59SSimon Glass 	return wm8994_device_init(priv);
858*d6cadd59SSimon Glass }
859*d6cadd59SSimon Glass 
860*d6cadd59SSimon Glass static const struct audio_codec_ops wm8994_ops = {
861*d6cadd59SSimon Glass 	.set_params	= wm8994_set_params,
862*d6cadd59SSimon Glass };
863*d6cadd59SSimon Glass 
864*d6cadd59SSimon Glass static const struct udevice_id wm8994_ids[] = {
865*d6cadd59SSimon Glass 	{ .compatible = "wolfson,wm8994" },
866*d6cadd59SSimon Glass 	{ }
867*d6cadd59SSimon Glass };
868*d6cadd59SSimon Glass 
869*d6cadd59SSimon Glass U_BOOT_DRIVER(wm8994) = {
870*d6cadd59SSimon Glass 	.name		= "wm8994",
871*d6cadd59SSimon Glass 	.id		= UCLASS_AUDIO_CODEC,
872*d6cadd59SSimon Glass 	.of_match	= wm8994_ids,
873*d6cadd59SSimon Glass 	.probe		= wm8994_probe,
874*d6cadd59SSimon Glass 	.ops		= &wm8994_ops,
875*d6cadd59SSimon Glass 	.priv_auto_alloc_size	= sizeof(struct wm8994_priv),
876*d6cadd59SSimon Glass };
877