]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
a2d8e0a7 RS |
2 | /* |
3 | * Copyright (C) 2012 Samsung Electronics | |
4 | * R. Chandrasekar <[email protected]> | |
a2d8e0a7 | 5 | */ |
150c5afe | 6 | #include <common.h> |
d6cadd59 SG |
7 | #include <audio_codec.h> |
8 | #include <dm.h> | |
a2d8e0a7 | 9 | #include <div64.h> |
6647c7ac | 10 | #include <fdtdec.h> |
a2d8e0a7 RS |
11 | #include <i2c.h> |
12 | #include <i2s.h> | |
f7ae49fc | 13 | #include <log.h> |
a2d8e0a7 | 14 | #include <sound.h> |
a1efd49e SG |
15 | #include <asm/gpio.h> |
16 | #include <asm/io.h> | |
17 | #include <asm/arch/clk.h> | |
18 | #include <asm/arch/cpu.h> | |
6647c7ac | 19 | #include <asm/arch/sound.h> |
a2d8e0a7 RS |
20 | #include "wm8994.h" |
21 | #include "wm8994_registers.h" | |
22 | ||
23 | /* defines for wm8994 system clock selection */ | |
24 | #define SEL_MCLK1 0x00 | |
25 | #define SEL_MCLK2 0x08 | |
26 | #define SEL_FLL1 0x10 | |
27 | #define SEL_FLL2 0x18 | |
28 | ||
29 | /* fll config to configure fll */ | |
30 | struct wm8994_fll_config { | |
31 | int src; /* Source */ | |
32 | int in; /* Input frequency in Hz */ | |
33 | int out; /* output frequency in Hz */ | |
34 | }; | |
35 | ||
36 | /* codec private data */ | |
37 | struct wm8994_priv { | |
38 | enum wm8994_type type; /* codec type of wolfson */ | |
39 | int revision; /* Revision */ | |
40 | int sysclk[WM8994_MAX_AIF]; /* System clock frequency in Hz */ | |
41 | int mclk[WM8994_MAX_AIF]; /* master clock frequency in Hz */ | |
42 | int aifclk[WM8994_MAX_AIF]; /* audio interface clock in Hz */ | |
43 | struct wm8994_fll_config fll[2]; /* fll config to configure fll */ | |
d6cadd59 | 44 | struct udevice *dev; |
a2d8e0a7 RS |
45 | }; |
46 | ||
47 | /* wm 8994 supported sampling rate values */ | |
48 | static unsigned int src_rate[] = { | |
49 | 8000, 11025, 12000, 16000, 22050, 24000, | |
50 | 32000, 44100, 48000, 88200, 96000 | |
51 | }; | |
52 | ||
53 | /* op clock divisions */ | |
54 | static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 }; | |
55 | ||
56 | /* lr clock frame size ratio */ | |
57 | static int fs_ratios[] = { | |
58 | 64, 128, 192, 256, 348, 512, 768, 1024, 1408, 1536 | |
59 | }; | |
60 | ||
61 | /* bit clock divisors */ | |
62 | static int bclk_divs[] = { | |
63 | 10, 15, 20, 30, 40, 50, 60, 80, 110, 120, 160, 220, 240, 320, 440, 480, | |
64 | 640, 880, 960, 1280, 1760, 1920 | |
65 | }; | |
66 | ||
a2d8e0a7 RS |
67 | /* |
68 | * Writes value to a device register through i2c | |
69 | * | |
107ab83e | 70 | * @param priv Private data for driver |
a2d8e0a7 RS |
71 | * @param reg reg number to be write |
72 | * @param data data to be writen to the above registor | |
73 | * | |
185f812c | 74 | * Return: int value 1 for change, 0 for no change or negative error code. |
a2d8e0a7 | 75 | */ |
107ab83e SG |
76 | static int wm8994_i2c_write(struct wm8994_priv *priv, unsigned int reg, |
77 | unsigned short data) | |
a2d8e0a7 RS |
78 | { |
79 | unsigned char val[2]; | |
80 | ||
81 | val[0] = (unsigned char)((data >> 8) & 0xff); | |
82 | val[1] = (unsigned char)(data & 0xff); | |
83 | debug("Write Addr : 0x%04X, Data : 0x%04X\n", reg, data); | |
84 | ||
d6cadd59 | 85 | return dm_i2c_write(priv->dev, reg, val, 2); |
a2d8e0a7 RS |
86 | } |
87 | ||
88 | /* | |
89 | * Read a value from a device register through i2c | |
90 | * | |
107ab83e | 91 | * @param priv Private data for driver |
a2d8e0a7 RS |
92 | * @param reg reg number to be read |
93 | * @param data address of read data to be stored | |
94 | * | |
185f812c | 95 | * Return: int value 0 for success, -1 in case of error. |
a2d8e0a7 | 96 | */ |
107ab83e SG |
97 | static unsigned int wm8994_i2c_read(struct wm8994_priv *priv, unsigned int reg, |
98 | unsigned short *data) | |
a2d8e0a7 RS |
99 | { |
100 | unsigned char val[2]; | |
101 | int ret; | |
102 | ||
d6cadd59 | 103 | ret = dm_i2c_read(priv->dev, reg, val, 1); |
a2d8e0a7 RS |
104 | if (ret != 0) { |
105 | debug("%s: Error while reading register %#04x\n", | |
106 | __func__, reg); | |
107 | return -1; | |
108 | } | |
109 | ||
110 | *data = val[0]; | |
111 | *data <<= 8; | |
112 | *data |= val[1]; | |
113 | ||
114 | return 0; | |
115 | } | |
116 | ||
117 | /* | |
118 | * update device register bits through i2c | |
119 | * | |
107ab83e | 120 | * @param priv Private data for driver |
a2d8e0a7 RS |
121 | * @param reg codec register |
122 | * @param mask register mask | |
123 | * @param value new value | |
124 | * | |
185f812c | 125 | * Return: int value 1 if change in the register value, |
a2d8e0a7 RS |
126 | * 0 for no change or negative error code. |
127 | */ | |
107ab83e SG |
128 | static int wm8994_bic_or(struct wm8994_priv *priv, unsigned int reg, |
129 | unsigned short mask, unsigned short value) | |
a2d8e0a7 RS |
130 | { |
131 | int change , ret = 0; | |
132 | unsigned short old, new; | |
133 | ||
107ab83e | 134 | if (wm8994_i2c_read(priv, reg, &old) != 0) |
a2d8e0a7 RS |
135 | return -1; |
136 | new = (old & ~mask) | (value & mask); | |
137 | change = (old != new) ? 1 : 0; | |
138 | if (change) | |
107ab83e | 139 | ret = wm8994_i2c_write(priv, reg, new); |
a2d8e0a7 RS |
140 | if (ret < 0) |
141 | return ret; | |
142 | ||
143 | return change; | |
144 | } | |
145 | ||
146 | /* | |
147 | * Sets i2s set format | |
148 | * | |
107ab83e | 149 | * @param priv wm8994 information |
a2d8e0a7 RS |
150 | * @param aif_id Interface ID |
151 | * @param fmt i2S format | |
152 | * | |
185f812c | 153 | * Return: -1 for error and 0 Success. |
a2d8e0a7 | 154 | */ |
107ab83e | 155 | static int wm8994_set_fmt(struct wm8994_priv *priv, int aif_id, uint fmt) |
a2d8e0a7 RS |
156 | { |
157 | int ms_reg; | |
158 | int aif_reg; | |
159 | int ms = 0; | |
160 | int aif = 0; | |
161 | int aif_clk = 0; | |
162 | int error = 0; | |
163 | ||
164 | switch (aif_id) { | |
165 | case 1: | |
166 | ms_reg = WM8994_AIF1_MASTER_SLAVE; | |
167 | aif_reg = WM8994_AIF1_CONTROL_1; | |
168 | aif_clk = WM8994_AIF1_CLOCKING_1; | |
169 | break; | |
170 | case 2: | |
171 | ms_reg = WM8994_AIF2_MASTER_SLAVE; | |
172 | aif_reg = WM8994_AIF2_CONTROL_1; | |
173 | aif_clk = WM8994_AIF2_CLOCKING_1; | |
174 | break; | |
175 | default: | |
176 | debug("%s: Invalid audio interface selection\n", __func__); | |
177 | return -1; | |
178 | } | |
179 | ||
180 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | |
181 | case SND_SOC_DAIFMT_CBS_CFS: | |
182 | break; | |
183 | case SND_SOC_DAIFMT_CBM_CFM: | |
184 | ms = WM8994_AIF1_MSTR; | |
185 | break; | |
186 | default: | |
187 | debug("%s: Invalid i2s master selection\n", __func__); | |
188 | return -1; | |
189 | } | |
190 | ||
191 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | |
192 | case SND_SOC_DAIFMT_DSP_B: | |
193 | aif |= WM8994_AIF1_LRCLK_INV; | |
194 | case SND_SOC_DAIFMT_DSP_A: | |
195 | aif |= 0x18; | |
196 | break; | |
197 | case SND_SOC_DAIFMT_I2S: | |
198 | aif |= 0x10; | |
199 | break; | |
200 | case SND_SOC_DAIFMT_RIGHT_J: | |
201 | break; | |
202 | case SND_SOC_DAIFMT_LEFT_J: | |
203 | aif |= 0x8; | |
204 | break; | |
205 | default: | |
206 | debug("%s: Invalid i2s format selection\n", __func__); | |
207 | return -1; | |
208 | } | |
209 | ||
210 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | |
211 | case SND_SOC_DAIFMT_DSP_A: | |
212 | case SND_SOC_DAIFMT_DSP_B: | |
213 | /* frame inversion not valid for DSP modes */ | |
214 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | |
215 | case SND_SOC_DAIFMT_NB_NF: | |
216 | break; | |
217 | case SND_SOC_DAIFMT_IB_NF: | |
218 | aif |= WM8994_AIF1_BCLK_INV; | |
219 | break; | |
220 | default: | |
221 | debug("%s: Invalid i2s frame inverse selection\n", | |
222 | __func__); | |
223 | return -1; | |
224 | } | |
225 | break; | |
226 | ||
227 | case SND_SOC_DAIFMT_I2S: | |
228 | case SND_SOC_DAIFMT_RIGHT_J: | |
229 | case SND_SOC_DAIFMT_LEFT_J: | |
230 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | |
231 | case SND_SOC_DAIFMT_NB_NF: | |
232 | break; | |
233 | case SND_SOC_DAIFMT_IB_IF: | |
234 | aif |= WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV; | |
235 | break; | |
236 | case SND_SOC_DAIFMT_IB_NF: | |
237 | aif |= WM8994_AIF1_BCLK_INV; | |
238 | break; | |
239 | case SND_SOC_DAIFMT_NB_IF: | |
240 | aif |= WM8994_AIF1_LRCLK_INV; | |
241 | break; | |
242 | default: | |
243 | debug("%s: Invalid i2s clock polarity selection\n", | |
244 | __func__); | |
245 | return -1; | |
246 | } | |
247 | break; | |
248 | default: | |
249 | debug("%s: Invalid i2s format selection\n", __func__); | |
250 | return -1; | |
251 | } | |
252 | ||
107ab83e SG |
253 | error = wm8994_bic_or(priv, aif_reg, WM8994_AIF1_BCLK_INV | |
254 | WM8994_AIF1_LRCLK_INV_MASK | | |
255 | WM8994_AIF1_FMT_MASK, aif); | |
a2d8e0a7 | 256 | |
107ab83e SG |
257 | error |= wm8994_bic_or(priv, ms_reg, WM8994_AIF1_MSTR_MASK, ms); |
258 | error |= wm8994_bic_or(priv, aif_clk, WM8994_AIF1CLK_ENA_MASK, | |
259 | WM8994_AIF1CLK_ENA); | |
a2d8e0a7 RS |
260 | if (error < 0) { |
261 | debug("%s: codec register access error\n", __func__); | |
262 | return -1; | |
263 | } | |
264 | ||
265 | return 0; | |
266 | } | |
267 | ||
268 | /* | |
269 | * Sets hw params FOR WM8994 | |
270 | * | |
107ab83e | 271 | * @param priv wm8994 information pointer |
a2d8e0a7 RS |
272 | * @param aif_id Audio interface ID |
273 | * @param sampling_rate Sampling rate | |
274 | * @param bits_per_sample Bits per sample | |
275 | * @param Channels Channels in the given audio input | |
276 | * | |
185f812c | 277 | * Return: -1 for error and 0 Success. |
a2d8e0a7 | 278 | */ |
107ab83e SG |
279 | static int wm8994_hw_params(struct wm8994_priv *priv, int aif_id, |
280 | uint sampling_rate, uint bits_per_sample, | |
281 | uint channels) | |
a2d8e0a7 RS |
282 | { |
283 | int aif1_reg; | |
284 | int aif2_reg; | |
285 | int bclk_reg; | |
286 | int bclk = 0; | |
287 | int rate_reg; | |
288 | int aif1 = 0; | |
289 | int aif2 = 0; | |
290 | int rate_val = 0; | |
291 | int id = aif_id - 1; | |
292 | int i, cur_val, best_val, bclk_rate, best; | |
293 | unsigned short reg_data; | |
294 | int ret = 0; | |
295 | ||
296 | switch (aif_id) { | |
297 | case 1: | |
298 | aif1_reg = WM8994_AIF1_CONTROL_1; | |
299 | aif2_reg = WM8994_AIF1_CONTROL_2; | |
300 | bclk_reg = WM8994_AIF1_BCLK; | |
301 | rate_reg = WM8994_AIF1_RATE; | |
302 | break; | |
303 | case 2: | |
304 | aif1_reg = WM8994_AIF2_CONTROL_1; | |
305 | aif2_reg = WM8994_AIF2_CONTROL_2; | |
306 | bclk_reg = WM8994_AIF2_BCLK; | |
307 | rate_reg = WM8994_AIF2_RATE; | |
308 | break; | |
309 | default: | |
310 | return -1; | |
311 | } | |
312 | ||
313 | bclk_rate = sampling_rate * 32; | |
314 | switch (bits_per_sample) { | |
315 | case 16: | |
316 | bclk_rate *= 16; | |
317 | break; | |
318 | case 20: | |
319 | bclk_rate *= 20; | |
320 | aif1 |= 0x20; | |
321 | break; | |
322 | case 24: | |
323 | bclk_rate *= 24; | |
324 | aif1 |= 0x40; | |
325 | break; | |
326 | case 32: | |
327 | bclk_rate *= 32; | |
328 | aif1 |= 0x60; | |
329 | break; | |
330 | default: | |
331 | return -1; | |
332 | } | |
333 | ||
334 | /* Try to find an appropriate sample rate; look for an exact match. */ | |
335 | for (i = 0; i < ARRAY_SIZE(src_rate); i++) | |
336 | if (src_rate[i] == sampling_rate) | |
337 | break; | |
338 | ||
339 | if (i == ARRAY_SIZE(src_rate)) { | |
340 | debug("%s: Could not get the best matching samplingrate\n", | |
341 | __func__); | |
342 | return -1; | |
343 | } | |
344 | ||
345 | rate_val |= i << WM8994_AIF1_SR_SHIFT; | |
346 | ||
347 | /* AIFCLK/fs ratio; look for a close match in either direction */ | |
348 | best = 0; | |
107ab83e | 349 | best_val = abs((fs_ratios[0] * sampling_rate) - priv->aifclk[id]); |
a2d8e0a7 RS |
350 | |
351 | for (i = 1; i < ARRAY_SIZE(fs_ratios); i++) { | |
107ab83e | 352 | cur_val = abs(fs_ratios[i] * sampling_rate - priv->aifclk[id]); |
a2d8e0a7 RS |
353 | if (cur_val >= best_val) |
354 | continue; | |
355 | best = i; | |
356 | best_val = cur_val; | |
357 | } | |
358 | ||
359 | rate_val |= best; | |
360 | ||
361 | /* | |
362 | * We may not get quite the right frequency if using | |
363 | * approximate clocks so look for the closest match that is | |
364 | * higher than the target (we need to ensure that there enough | |
365 | * BCLKs to clock out the samples). | |
366 | */ | |
367 | best = 0; | |
368 | for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { | |
107ab83e | 369 | cur_val = (priv->aifclk[id] * 10 / bclk_divs[i]) - bclk_rate; |
a2d8e0a7 RS |
370 | if (cur_val < 0) /* BCLK table is sorted */ |
371 | break; | |
372 | best = i; | |
373 | } | |
374 | ||
375 | if (i == ARRAY_SIZE(bclk_divs)) { | |
376 | debug("%s: Could not get the best matching bclk division\n", | |
377 | __func__); | |
378 | return -1; | |
379 | } | |
380 | ||
107ab83e | 381 | bclk_rate = priv->aifclk[id] * 10 / bclk_divs[best]; |
a2d8e0a7 RS |
382 | bclk |= best << WM8994_AIF1_BCLK_DIV_SHIFT; |
383 | ||
107ab83e | 384 | if (wm8994_i2c_read(priv, aif1_reg, ®_data) != 0) { |
a2d8e0a7 RS |
385 | debug("%s: AIF1 register read Failed\n", __func__); |
386 | return -1; | |
387 | } | |
388 | ||
389 | if ((channels == 1) && ((reg_data & 0x18) == 0x18)) | |
390 | aif2 |= WM8994_AIF1_MONO; | |
391 | ||
107ab83e | 392 | if (priv->aifclk[id] == 0) { |
a2d8e0a7 RS |
393 | debug("%s:Audio interface clock not set\n", __func__); |
394 | return -1; | |
395 | } | |
396 | ||
107ab83e SG |
397 | ret = wm8994_bic_or(priv, aif1_reg, WM8994_AIF1_WL_MASK, aif1); |
398 | ret |= wm8994_bic_or(priv, aif2_reg, WM8994_AIF1_MONO, aif2); | |
399 | ret |= wm8994_bic_or(priv, bclk_reg, WM8994_AIF1_BCLK_DIV_MASK, | |
400 | bclk); | |
401 | ret |= wm8994_bic_or(priv, rate_reg, WM8994_AIF1_SR_MASK | | |
402 | WM8994_AIF1CLK_RATE_MASK, rate_val); | |
a2d8e0a7 RS |
403 | |
404 | debug("rate vale = %x , bclk val= %x\n", rate_val, bclk); | |
405 | ||
406 | if (ret < 0) { | |
407 | debug("%s: codec register access error\n", __func__); | |
408 | return -1; | |
409 | } | |
410 | ||
411 | return 0; | |
412 | } | |
413 | ||
414 | /* | |
415 | * Configures Audio interface Clock | |
416 | * | |
107ab83e | 417 | * @param priv wm8994 information pointer |
a2d8e0a7 RS |
418 | * @param aif Audio Interface ID |
419 | * | |
185f812c | 420 | * Return: -1 for error and 0 Success. |
a2d8e0a7 | 421 | */ |
107ab83e | 422 | static int configure_aif_clock(struct wm8994_priv *priv, int aif) |
a2d8e0a7 RS |
423 | { |
424 | int rate; | |
425 | int reg1 = 0; | |
426 | int offset; | |
427 | int ret; | |
428 | ||
429 | /* AIF(1/0) register adress offset calculated */ | |
d981d80d | 430 | if (aif-1) |
a2d8e0a7 RS |
431 | offset = 4; |
432 | else | |
433 | offset = 0; | |
434 | ||
107ab83e | 435 | switch (priv->sysclk[aif - 1]) { |
a2d8e0a7 RS |
436 | case WM8994_SYSCLK_MCLK1: |
437 | reg1 |= SEL_MCLK1; | |
107ab83e | 438 | rate = priv->mclk[0]; |
a2d8e0a7 RS |
439 | break; |
440 | ||
441 | case WM8994_SYSCLK_MCLK2: | |
442 | reg1 |= SEL_MCLK2; | |
107ab83e | 443 | rate = priv->mclk[1]; |
a2d8e0a7 RS |
444 | break; |
445 | ||
446 | case WM8994_SYSCLK_FLL1: | |
447 | reg1 |= SEL_FLL1; | |
107ab83e | 448 | rate = priv->fll[0].out; |
a2d8e0a7 RS |
449 | break; |
450 | ||
451 | case WM8994_SYSCLK_FLL2: | |
452 | reg1 |= SEL_FLL2; | |
107ab83e | 453 | rate = priv->fll[1].out; |
a2d8e0a7 RS |
454 | break; |
455 | ||
456 | default: | |
457 | debug("%s: Invalid input clock selection [%d]\n", | |
107ab83e | 458 | __func__, priv->sysclk[aif - 1]); |
a2d8e0a7 RS |
459 | return -1; |
460 | } | |
461 | ||
462 | /* if input clock frequenct is more than 135Mhz then divide */ | |
463 | if (rate >= WM8994_MAX_INPUT_CLK_FREQ) { | |
464 | rate /= 2; | |
465 | reg1 |= WM8994_AIF1CLK_DIV; | |
466 | } | |
467 | ||
107ab83e | 468 | priv->aifclk[aif - 1] = rate; |
a2d8e0a7 | 469 | |
107ab83e SG |
470 | ret = wm8994_bic_or(priv, WM8994_AIF1_CLOCKING_1 + offset, |
471 | WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV, | |
472 | reg1); | |
a2d8e0a7 | 473 | |
d981d80d | 474 | if (aif == WM8994_AIF1) |
107ab83e | 475 | ret |= wm8994_bic_or(priv, WM8994_CLOCKING_1, |
d981d80d DKM |
476 | WM8994_AIF1DSPCLK_ENA_MASK | WM8994_SYSDSPCLK_ENA_MASK, |
477 | WM8994_AIF1DSPCLK_ENA | WM8994_SYSDSPCLK_ENA); | |
478 | else if (aif == WM8994_AIF2) | |
107ab83e | 479 | ret |= wm8994_bic_or(priv, WM8994_CLOCKING_1, |
a2d8e0a7 RS |
480 | WM8994_SYSCLK_SRC | WM8994_AIF2DSPCLK_ENA_MASK | |
481 | WM8994_SYSDSPCLK_ENA_MASK, WM8994_SYSCLK_SRC | | |
482 | WM8994_AIF2DSPCLK_ENA | WM8994_SYSDSPCLK_ENA); | |
483 | ||
484 | if (ret < 0) { | |
485 | debug("%s: codec register access error\n", __func__); | |
486 | return -1; | |
487 | } | |
488 | ||
489 | return 0; | |
490 | } | |
491 | ||
492 | /* | |
493 | * Configures Audio interface for the given frequency | |
494 | * | |
107ab83e | 495 | * @param priv wm8994 information |
a2d8e0a7 RS |
496 | * @param aif_id Audio Interface |
497 | * @param clk_id Input Clock ID | |
498 | * @param freq Sampling frequency in Hz | |
499 | * | |
185f812c | 500 | * Return: -1 for error and 0 success. |
a2d8e0a7 | 501 | */ |
107ab83e SG |
502 | static int wm8994_set_sysclk(struct wm8994_priv *priv, int aif_id, int clk_id, |
503 | unsigned int freq) | |
a2d8e0a7 RS |
504 | { |
505 | int i; | |
506 | int ret = 0; | |
507 | ||
107ab83e | 508 | priv->sysclk[aif_id - 1] = clk_id; |
a2d8e0a7 RS |
509 | |
510 | switch (clk_id) { | |
511 | case WM8994_SYSCLK_MCLK1: | |
107ab83e | 512 | priv->mclk[0] = freq; |
a2d8e0a7 | 513 | if (aif_id == 2) { |
107ab83e SG |
514 | ret = wm8994_bic_or(priv, WM8994_AIF1_CLOCKING_2, |
515 | WM8994_AIF2DAC_DIV_MASK, 0); | |
a2d8e0a7 RS |
516 | } |
517 | break; | |
518 | ||
519 | case WM8994_SYSCLK_MCLK2: | |
520 | /* TODO: Set GPIO AF */ | |
107ab83e | 521 | priv->mclk[1] = freq; |
a2d8e0a7 RS |
522 | break; |
523 | ||
524 | case WM8994_SYSCLK_FLL1: | |
525 | case WM8994_SYSCLK_FLL2: | |
526 | break; | |
527 | ||
528 | case WM8994_SYSCLK_OPCLK: | |
529 | /* | |
530 | * Special case - a division (times 10) is given and | |
531 | * no effect on main clocking. | |
532 | */ | |
533 | if (freq) { | |
534 | for (i = 0; i < ARRAY_SIZE(opclk_divs); i++) | |
535 | if (opclk_divs[i] == freq) | |
536 | break; | |
537 | if (i == ARRAY_SIZE(opclk_divs)) { | |
538 | debug("%s frequency divisor not found\n", | |
d981d80d | 539 | __func__); |
a2d8e0a7 RS |
540 | return -1; |
541 | } | |
107ab83e | 542 | ret = wm8994_bic_or(priv, WM8994_CLOCKING_2, |
a2d8e0a7 | 543 | WM8994_OPCLK_DIV_MASK, i); |
107ab83e SG |
544 | ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_2, |
545 | WM8994_OPCLK_ENA, | |
546 | WM8994_OPCLK_ENA); | |
a2d8e0a7 | 547 | } else { |
107ab83e SG |
548 | ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_2, |
549 | WM8994_OPCLK_ENA, 0); | |
a2d8e0a7 RS |
550 | } |
551 | ||
552 | default: | |
553 | debug("%s Invalid input clock selection [%d]\n", | |
554 | __func__, clk_id); | |
555 | return -1; | |
556 | } | |
557 | ||
107ab83e | 558 | ret |= configure_aif_clock(priv, aif_id); |
a2d8e0a7 RS |
559 | |
560 | if (ret < 0) { | |
561 | debug("%s: codec register access error\n", __func__); | |
562 | return -1; | |
563 | } | |
564 | ||
565 | return 0; | |
566 | } | |
567 | ||
568 | /* | |
569 | * Initializes Volume for AIF2 to HP path | |
570 | * | |
107ab83e | 571 | * @param priv wm8994 information |
a2d8e0a7 RS |
572 | * @returns -1 for error and 0 Success. |
573 | * | |
574 | */ | |
107ab83e | 575 | static int wm8994_init_volume_aif2_dac1(struct wm8994_priv *priv) |
a2d8e0a7 RS |
576 | { |
577 | int ret; | |
578 | ||
579 | /* Unmute AIF2DAC */ | |
107ab83e SG |
580 | ret = wm8994_bic_or(priv, WM8994_AIF2_DAC_FILTERS_1, |
581 | WM8994_AIF2DAC_MUTE_MASK, 0); | |
a2d8e0a7 RS |
582 | |
583 | ||
107ab83e SG |
584 | ret |= wm8994_bic_or(priv, WM8994_AIF2_DAC_LEFT_VOLUME, |
585 | WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACL_VOL_MASK, | |
586 | WM8994_AIF2DAC_VU | 0xff); | |
a2d8e0a7 | 587 | |
107ab83e SG |
588 | ret |= wm8994_bic_or(priv, WM8994_AIF2_DAC_RIGHT_VOLUME, |
589 | WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACR_VOL_MASK, | |
590 | WM8994_AIF2DAC_VU | 0xff); | |
a2d8e0a7 RS |
591 | |
592 | ||
107ab83e SG |
593 | ret |= wm8994_bic_or(priv, WM8994_DAC1_LEFT_VOLUME, |
594 | WM8994_DAC1_VU_MASK | WM8994_DAC1L_VOL_MASK | | |
595 | WM8994_DAC1L_MUTE_MASK, WM8994_DAC1_VU | 0xc0); | |
a2d8e0a7 | 596 | |
107ab83e SG |
597 | ret |= wm8994_bic_or(priv, WM8994_DAC1_RIGHT_VOLUME, |
598 | WM8994_DAC1_VU_MASK | WM8994_DAC1R_VOL_MASK | | |
599 | WM8994_DAC1R_MUTE_MASK, WM8994_DAC1_VU | 0xc0); | |
a2d8e0a7 | 600 | /* Head Phone Volume */ |
107ab83e SG |
601 | ret |= wm8994_i2c_write(priv, WM8994_LEFT_OUTPUT_VOLUME, 0x12D); |
602 | ret |= wm8994_i2c_write(priv, WM8994_RIGHT_OUTPUT_VOLUME, 0x12D); | |
a2d8e0a7 RS |
603 | |
604 | if (ret < 0) { | |
605 | debug("%s: codec register access error\n", __func__); | |
606 | return -1; | |
607 | } | |
608 | ||
609 | return 0; | |
610 | } | |
611 | ||
d981d80d DKM |
612 | /* |
613 | * Initializes Volume for AIF1 to HP path | |
614 | * | |
107ab83e | 615 | * @param priv wm8994 information |
d981d80d DKM |
616 | * @returns -1 for error and 0 Success. |
617 | * | |
618 | */ | |
107ab83e | 619 | static int wm8994_init_volume_aif1_dac1(struct wm8994_priv *priv) |
d981d80d DKM |
620 | { |
621 | int ret = 0; | |
622 | ||
623 | /* Unmute AIF1DAC */ | |
107ab83e | 624 | ret |= wm8994_i2c_write(priv, WM8994_AIF1_DAC_FILTERS_1, 0x0000); |
d981d80d | 625 | |
107ab83e SG |
626 | ret |= wm8994_bic_or(priv, WM8994_DAC1_LEFT_VOLUME, |
627 | WM8994_DAC1_VU_MASK | WM8994_DAC1L_VOL_MASK | | |
628 | WM8994_DAC1L_MUTE_MASK, WM8994_DAC1_VU | 0xc0); | |
d981d80d | 629 | |
107ab83e SG |
630 | ret |= wm8994_bic_or(priv, WM8994_DAC1_RIGHT_VOLUME, |
631 | WM8994_DAC1_VU_MASK | WM8994_DAC1R_VOL_MASK | | |
632 | WM8994_DAC1R_MUTE_MASK, WM8994_DAC1_VU | 0xc0); | |
d981d80d | 633 | /* Head Phone Volume */ |
107ab83e SG |
634 | ret |= wm8994_i2c_write(priv, WM8994_LEFT_OUTPUT_VOLUME, 0x12D); |
635 | ret |= wm8994_i2c_write(priv, WM8994_RIGHT_OUTPUT_VOLUME, 0x12D); | |
d981d80d DKM |
636 | |
637 | if (ret < 0) { | |
638 | debug("%s: codec register access error\n", __func__); | |
639 | return -1; | |
640 | } | |
641 | ||
642 | return 0; | |
643 | } | |
644 | ||
a2d8e0a7 RS |
645 | /* |
646 | * Intialise wm8994 codec device | |
647 | * | |
107ab83e | 648 | * @param priv wm8994 information |
a2d8e0a7 RS |
649 | * |
650 | * @returns -1 for error and 0 Success. | |
651 | */ | |
cfbe7623 | 652 | static int wm8994_device_init(struct wm8994_priv *priv) |
a2d8e0a7 RS |
653 | { |
654 | const char *devname; | |
655 | unsigned short reg_data; | |
656 | int ret; | |
657 | ||
107ab83e | 658 | wm8994_i2c_write(priv, WM8994_SOFTWARE_RESET, WM8994_SW_RESET); |
a2d8e0a7 | 659 | |
107ab83e | 660 | ret = wm8994_i2c_read(priv, WM8994_SOFTWARE_RESET, ®_data); |
a2d8e0a7 RS |
661 | if (ret < 0) { |
662 | debug("Failed to read ID register\n"); | |
cfbe7623 | 663 | return ret; |
a2d8e0a7 RS |
664 | } |
665 | ||
666 | if (reg_data == WM8994_ID) { | |
667 | devname = "WM8994"; | |
107ab83e SG |
668 | debug("Device registered as type %d\n", priv->type); |
669 | priv->type = WM8994; | |
a2d8e0a7 RS |
670 | } else { |
671 | debug("Device is not a WM8994, ID is %x\n", ret); | |
cfbe7623 | 672 | return -ENXIO; |
a2d8e0a7 RS |
673 | } |
674 | ||
107ab83e | 675 | ret = wm8994_i2c_read(priv, WM8994_CHIP_REVISION, ®_data); |
a2d8e0a7 RS |
676 | if (ret < 0) { |
677 | debug("Failed to read revision register: %d\n", ret); | |
cfbe7623 | 678 | return ret; |
a2d8e0a7 | 679 | } |
107ab83e SG |
680 | priv->revision = reg_data; |
681 | debug("%s revision %c\n", devname, 'A' + priv->revision); | |
a2d8e0a7 | 682 | |
cfbe7623 SG |
683 | return 0; |
684 | } | |
685 | ||
686 | static int wm8994_setup_interface(struct wm8994_priv *priv, | |
687 | enum en_audio_interface aif_id) | |
688 | { | |
689 | int ret; | |
690 | ||
a2d8e0a7 | 691 | /* VMID Selection */ |
cfbe7623 SG |
692 | ret = wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_1, |
693 | WM8994_VMID_SEL_MASK | WM8994_BIAS_ENA_MASK, 0x3); | |
a2d8e0a7 RS |
694 | |
695 | /* Charge Pump Enable */ | |
107ab83e SG |
696 | ret |= wm8994_bic_or(priv, WM8994_CHARGE_PUMP_1, WM8994_CP_ENA_MASK, |
697 | WM8994_CP_ENA); | |
a2d8e0a7 RS |
698 | |
699 | /* Head Phone Power Enable */ | |
107ab83e SG |
700 | ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_1, |
701 | WM8994_HPOUT1L_ENA_MASK, WM8994_HPOUT1L_ENA); | |
a2d8e0a7 | 702 | |
107ab83e SG |
703 | ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_1, |
704 | WM8994_HPOUT1R_ENA_MASK, WM8994_HPOUT1R_ENA); | |
a2d8e0a7 | 705 | |
d981d80d | 706 | if (aif_id == WM8994_AIF1) { |
107ab83e | 707 | ret |= wm8994_i2c_write(priv, WM8994_POWER_MANAGEMENT_2, |
d981d80d DKM |
708 | WM8994_TSHUT_ENA | WM8994_MIXINL_ENA | |
709 | WM8994_MIXINR_ENA | WM8994_IN2L_ENA | | |
710 | WM8994_IN2R_ENA); | |
711 | ||
107ab83e | 712 | ret |= wm8994_i2c_write(priv, WM8994_POWER_MANAGEMENT_4, |
d981d80d DKM |
713 | WM8994_ADCL_ENA | WM8994_ADCR_ENA | |
714 | WM8994_AIF1ADC1R_ENA | | |
715 | WM8994_AIF1ADC1L_ENA); | |
716 | ||
717 | /* Power enable for AIF1 and DAC1 */ | |
107ab83e | 718 | ret |= wm8994_i2c_write(priv, WM8994_POWER_MANAGEMENT_5, |
d981d80d DKM |
719 | WM8994_AIF1DACL_ENA | |
720 | WM8994_AIF1DACR_ENA | | |
721 | WM8994_DAC1L_ENA | WM8994_DAC1R_ENA); | |
722 | } else if (aif_id == WM8994_AIF2) { | |
723 | /* Power enable for AIF2 and DAC1 */ | |
107ab83e | 724 | ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_5, |
d981d80d DKM |
725 | WM8994_AIF2DACL_ENA_MASK | WM8994_AIF2DACR_ENA_MASK | |
726 | WM8994_DAC1L_ENA_MASK | WM8994_DAC1R_ENA_MASK, | |
727 | WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA | | |
728 | WM8994_DAC1L_ENA | WM8994_DAC1R_ENA); | |
729 | } | |
a2d8e0a7 | 730 | /* Head Phone Initialisation */ |
107ab83e | 731 | ret |= wm8994_bic_or(priv, WM8994_ANALOGUE_HP_1, |
a2d8e0a7 RS |
732 | WM8994_HPOUT1L_DLY_MASK | WM8994_HPOUT1R_DLY_MASK, |
733 | WM8994_HPOUT1L_DLY | WM8994_HPOUT1R_DLY); | |
734 | ||
107ab83e | 735 | ret |= wm8994_bic_or(priv, WM8994_DC_SERVO_1, |
a2d8e0a7 RS |
736 | WM8994_DCS_ENA_CHAN_0_MASK | |
737 | WM8994_DCS_ENA_CHAN_1_MASK , WM8994_DCS_ENA_CHAN_0 | | |
738 | WM8994_DCS_ENA_CHAN_1); | |
739 | ||
107ab83e | 740 | ret |= wm8994_bic_or(priv, WM8994_ANALOGUE_HP_1, |
a2d8e0a7 RS |
741 | WM8994_HPOUT1L_DLY_MASK | |
742 | WM8994_HPOUT1R_DLY_MASK | WM8994_HPOUT1L_OUTP_MASK | | |
743 | WM8994_HPOUT1R_OUTP_MASK | | |
744 | WM8994_HPOUT1L_RMV_SHORT_MASK | | |
745 | WM8994_HPOUT1R_RMV_SHORT_MASK, WM8994_HPOUT1L_DLY | | |
746 | WM8994_HPOUT1R_DLY | WM8994_HPOUT1L_OUTP | | |
747 | WM8994_HPOUT1R_OUTP | WM8994_HPOUT1L_RMV_SHORT | | |
748 | WM8994_HPOUT1R_RMV_SHORT); | |
749 | ||
750 | /* MIXER Config DAC1 to HP */ | |
107ab83e SG |
751 | ret |= wm8994_bic_or(priv, WM8994_OUTPUT_MIXER_1, |
752 | WM8994_DAC1L_TO_HPOUT1L_MASK, | |
753 | WM8994_DAC1L_TO_HPOUT1L); | |
a2d8e0a7 | 754 | |
107ab83e SG |
755 | ret |= wm8994_bic_or(priv, WM8994_OUTPUT_MIXER_2, |
756 | WM8994_DAC1R_TO_HPOUT1R_MASK, | |
757 | WM8994_DAC1R_TO_HPOUT1R); | |
a2d8e0a7 | 758 | |
d981d80d DKM |
759 | if (aif_id == WM8994_AIF1) { |
760 | /* Routing AIF1 to DAC1 */ | |
107ab83e SG |
761 | ret |= wm8994_i2c_write(priv, WM8994_DAC1_LEFT_MIXER_ROUTING, |
762 | WM8994_AIF1DAC1L_TO_DAC1L); | |
d981d80d | 763 | |
107ab83e | 764 | ret |= wm8994_i2c_write(priv, WM8994_DAC1_RIGHT_MIXER_ROUTING, |
d981d80d DKM |
765 | WM8994_AIF1DAC1R_TO_DAC1R); |
766 | ||
767 | /* GPIO Settings for AIF1 */ | |
107ab83e SG |
768 | ret |= wm8994_i2c_write(priv, WM8994_GPIO_1, |
769 | WM8994_GPIO_DIR_OUTPUT | | |
770 | WM8994_GPIO_FUNCTION_I2S_CLK | | |
771 | WM8994_GPIO_INPUT_DEBOUNCE); | |
d981d80d | 772 | |
107ab83e | 773 | ret |= wm8994_init_volume_aif1_dac1(priv); |
d981d80d DKM |
774 | } else if (aif_id == WM8994_AIF2) { |
775 | /* Routing AIF2 to DAC1 */ | |
107ab83e SG |
776 | ret |= wm8994_bic_or(priv, WM8994_DAC1_LEFT_MIXER_ROUTING, |
777 | WM8994_AIF2DACL_TO_DAC1L_MASK, | |
778 | WM8994_AIF2DACL_TO_DAC1L); | |
d981d80d | 779 | |
107ab83e SG |
780 | ret |= wm8994_bic_or(priv, WM8994_DAC1_RIGHT_MIXER_ROUTING, |
781 | WM8994_AIF2DACR_TO_DAC1R_MASK, | |
782 | WM8994_AIF2DACR_TO_DAC1R); | |
d981d80d DKM |
783 | |
784 | /* GPIO Settings for AIF2 */ | |
785 | /* B CLK */ | |
107ab83e SG |
786 | ret |= wm8994_bic_or(priv, WM8994_GPIO_3, WM8994_GPIO_DIR_MASK | |
787 | WM8994_GPIO_FUNCTION_MASK, | |
788 | WM8994_GPIO_DIR_OUTPUT); | |
d981d80d DKM |
789 | |
790 | /* LR CLK */ | |
107ab83e SG |
791 | ret |= wm8994_bic_or(priv, WM8994_GPIO_4, WM8994_GPIO_DIR_MASK | |
792 | WM8994_GPIO_FUNCTION_MASK, | |
793 | WM8994_GPIO_DIR_OUTPUT); | |
d981d80d DKM |
794 | |
795 | /* DATA */ | |
107ab83e SG |
796 | ret |= wm8994_bic_or(priv, WM8994_GPIO_5, WM8994_GPIO_DIR_MASK | |
797 | WM8994_GPIO_FUNCTION_MASK, | |
798 | WM8994_GPIO_DIR_OUTPUT); | |
d981d80d | 799 | |
107ab83e | 800 | ret |= wm8994_init_volume_aif2_dac1(priv); |
d981d80d DKM |
801 | } |
802 | ||
a2d8e0a7 RS |
803 | if (ret < 0) |
804 | goto err; | |
805 | ||
cfbe7623 | 806 | debug("%s: Codec chip setup ok\n", __func__); |
a2d8e0a7 RS |
807 | return 0; |
808 | err: | |
cfbe7623 | 809 | debug("%s: Codec chip setup error\n", __func__); |
a2d8e0a7 RS |
810 | return -1; |
811 | } | |
812 | ||
54e67e27 SG |
813 | static int _wm8994_init(struct wm8994_priv *priv, |
814 | enum en_audio_interface aif_id, int sampling_rate, | |
815 | int mclk_freq, int bits_per_sample, | |
816 | unsigned int channels) | |
a2d8e0a7 | 817 | { |
54e67e27 | 818 | int ret; |
a2d8e0a7 | 819 | |
cfbe7623 | 820 | ret = wm8994_setup_interface(priv, aif_id); |
a2d8e0a7 RS |
821 | if (ret < 0) { |
822 | debug("%s: wm8994 codec chip init failed\n", __func__); | |
823 | return ret; | |
824 | } | |
825 | ||
d6cadd59 | 826 | ret = wm8994_set_sysclk(priv, aif_id, WM8994_SYSCLK_MCLK1, mclk_freq); |
a2d8e0a7 RS |
827 | if (ret < 0) { |
828 | debug("%s: wm8994 codec set sys clock failed\n", __func__); | |
829 | return ret; | |
830 | } | |
831 | ||
54e67e27 SG |
832 | ret = wm8994_hw_params(priv, aif_id, sampling_rate, bits_per_sample, |
833 | channels); | |
a2d8e0a7 RS |
834 | |
835 | if (ret == 0) { | |
54e67e27 SG |
836 | ret = wm8994_set_fmt(priv, aif_id, SND_SOC_DAIFMT_I2S | |
837 | SND_SOC_DAIFMT_NB_NF | | |
107ab83e | 838 | SND_SOC_DAIFMT_CBS_CFS); |
a2d8e0a7 | 839 | } |
54e67e27 | 840 | |
a2d8e0a7 RS |
841 | return ret; |
842 | } | |
54e67e27 | 843 | |
d6cadd59 SG |
844 | static int wm8994_set_params(struct udevice *dev, int interface, int rate, |
845 | int mclk_freq, int bits_per_sample, uint channels) | |
846 | { | |
847 | struct wm8994_priv *priv = dev_get_priv(dev); | |
848 | ||
849 | return _wm8994_init(priv, interface, rate, mclk_freq, bits_per_sample, | |
850 | channels); | |
851 | } | |
852 | ||
853 | static int wm8994_probe(struct udevice *dev) | |
854 | { | |
855 | struct wm8994_priv *priv = dev_get_priv(dev); | |
856 | ||
857 | priv->dev = dev; | |
858 | return wm8994_device_init(priv); | |
859 | } | |
860 | ||
861 | static const struct audio_codec_ops wm8994_ops = { | |
862 | .set_params = wm8994_set_params, | |
863 | }; | |
864 | ||
865 | static const struct udevice_id wm8994_ids[] = { | |
866 | { .compatible = "wolfson,wm8994" }, | |
867 | { } | |
868 | }; | |
869 | ||
870 | U_BOOT_DRIVER(wm8994) = { | |
871 | .name = "wm8994", | |
872 | .id = UCLASS_AUDIO_CODEC, | |
873 | .of_match = wm8994_ids, | |
874 | .probe = wm8994_probe, | |
875 | .ops = &wm8994_ops, | |
41575d8e | 876 | .priv_auto = sizeof(struct wm8994_priv), |
d6cadd59 | 877 | }; |