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, ®_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, ®_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, ®_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