1 /*
2 * Copyright (c) 2016, Freescale Semiconductor, Inc.
3 * Copyright 2016-2021 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_wm8904.h"
10 #if WM8904_DEBUG_REGISTER
11 #include "fsl_debug_console.h"
12 #endif
13 /*******************************************************************************
14 * Definitions
15 ******************************************************************************/
16 /*! @brief wm8904 volume mapping */
17 #define WM8904_SWAP_UINT16_BYTE_SEQUENCE(x) ((((x) & 0x00ffU) << 8U) | (((x) & 0xff00U) >> 8U))
18 #define WM8904_MAP_SAMPLERATE(x) \
19 ((x) == kWM8904_SampleRate8kHz ? \
20 8000U : \
21 (x) == kWM8904_SampleRate12kHz ? \
22 12000U : \
23 (x) == kWM8904_SampleRate16kHz ? \
24 16000U : \
25 (x) == kWM8904_SampleRate24kHz ? \
26 24000U : \
27 (x) == kWM8904_SampleRate32kHz ? \
28 32000U : \
29 (x) == kWM8904_SampleRate48kHz ? \
30 48000U : \
31 (x) == kWM8904_SampleRate11025Hz ? 11025U : (x) == kWM8904_SampleRate22050Hz ? 22050U : 44100U)
32 #define WM8904_MAP_BITWIDTH(x) \
33 ((x) == kWM8904_BitWidth16 ? 16 : (x) == kWM8904_BitWidth20 ? 20 : (x) == kWM8904_BitWidth24 ? 24 : 32)
34 /*******************************************************************************
35 * Prototypes
36 ******************************************************************************/
37 /*!
38 * @brief WM8904 update format.
39 *
40 * @param handle WM8904 handle structure.
41 * @param fsRatio fs ratio.
42 * @param sampleRate sample rate.
43 * @param bitWidth bit width.
44 * @return kStatus_Success, else failed.
45 */
46 static status_t WM8904_UpdateFormat(wm8904_handle_t *handle,
47 wm8904_fs_ratio_t fsRatio,
48 wm8904_sample_rate_t sampleRate,
49 wm8904_bit_width_t bitWidth);
50
51 /*!
52 * @brief WM8904 wait on write sequencer.
53 *
54 * @param handle WM8904 handle structure.
55 * @return kStatus_Success, else failed.
56 */
57 static status_t WM8904_WaitOnWriteSequencer(wm8904_handle_t *handle);
58 /*******************************************************************************
59 * Variables
60 ******************************************************************************/
61 #if WM8904_DEBUG_REGISTER
62 /*! @brief register definition */
63 static const uint8_t allRegisters[] = {
64 0x00, 0x04, 0x05, 0x06, 0x07, 0x0A, 0x0C, 0x0E, 0x0F, 0x12, 0x14, 0x15, 0x16, 0x18, 0x19, 0x1A, 0x1B,
65 0x1E, 0x1F, 0x20, 0x21, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x39,
66 0x3A, 0x3B, 0x3C, 0x3D, 0x43, 0x44, 0x45, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x5A, 0x5E, 0x62,
67 0x68, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7E, 0x7F,
68 0x80, 0x81, 0x82, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93,
69 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0xC6, 0xF7, 0xF8};
70 #endif
71 /*******************************************************************************
72 * Code
73 ******************************************************************************/
WM8904_UpdateFormat(wm8904_handle_t * handle,wm8904_fs_ratio_t fsRatio,wm8904_sample_rate_t sampleRate,wm8904_bit_width_t bitWidth)74 static status_t WM8904_UpdateFormat(wm8904_handle_t *handle,
75 wm8904_fs_ratio_t fsRatio,
76 wm8904_sample_rate_t sampleRate,
77 wm8904_bit_width_t bitWidth)
78 {
79 status_t result = kStatus_Success;
80
81 /* Disable SYSCLK */
82 result = WM8904_WriteRegister(handle, WM8904_CLK_RATES_2, 0x00);
83 if (result != kStatus_WM8904_Success)
84 {
85 return result;
86 }
87
88 /* Set Clock ratio and sample rate */
89 result = WM8904_WriteRegister(handle, WM8904_CLK_RATES_1,
90 (uint16_t)(((uint16_t)(fsRatio) << 10U) | (uint16_t)(sampleRate)));
91 if (result != kStatus_WM8904_Success)
92 {
93 return result;
94 }
95
96 /* Set bit resolution */
97 result = WM8904_ModifyRegister(handle, WM8904_AUDIO_IF_1, (0x000CU), ((uint16_t)(bitWidth) << 2U));
98 if (result != kStatus_WM8904_Success)
99 {
100 return result;
101 }
102
103 /* Enable SYSCLK */
104 result = WM8904_WriteRegister(handle, WM8904_CLK_RATES_2, 0x1007);
105 if (result != kStatus_WM8904_Success)
106 {
107 return result;
108 }
109
110 return kStatus_WM8904_Success;
111 }
112
WM8904_WaitOnWriteSequencer(wm8904_handle_t * handle)113 static status_t WM8904_WaitOnWriteSequencer(wm8904_handle_t *handle)
114 {
115 status_t result = kStatus_Success;
116 uint16_t value;
117
118 do
119 {
120 result = WM8904_ReadRegister(handle, WM8904_WRT_SEQUENCER_4, &value);
121 } while ((result == kStatus_WM8904_Success) && ((value & 1U) != 0U));
122
123 return result;
124 }
125
126 /*!
127 * brief WM8904 write register.
128 *
129 * param handle WM8904 handle structure.
130 * param reg register address.
131 * param value value to write.
132 * return kStatus_Success, else failed.
133 */
WM8904_WriteRegister(wm8904_handle_t * handle,uint8_t reg,uint16_t value)134 status_t WM8904_WriteRegister(wm8904_handle_t *handle, uint8_t reg, uint16_t value)
135 {
136 assert(handle->config != NULL);
137 assert(handle->config->slaveAddress != 0U);
138
139 uint16_t writeValue = (uint16_t)WM8904_SWAP_UINT16_BYTE_SEQUENCE(value);
140
141 return CODEC_I2C_Send(handle->i2cHandle, handle->config->slaveAddress, reg, 1U, (uint8_t *)&writeValue, 2U);
142 }
143
144 /*!
145 * brief WM8904 write register.
146 *
147 * param handle WM8904 handle structure.
148 * param reg register address.
149 * param value value to read.
150 * return kStatus_Success, else failed.
151 */
WM8904_ReadRegister(wm8904_handle_t * handle,uint8_t reg,uint16_t * value)152 status_t WM8904_ReadRegister(wm8904_handle_t *handle, uint8_t reg, uint16_t *value)
153 {
154 assert(handle->config != NULL);
155 assert(handle->config->slaveAddress != 0U);
156
157 status_t retval = 0;
158 uint16_t readValue = 0U;
159
160 retval = CODEC_I2C_Receive(handle->i2cHandle, handle->config->slaveAddress, (uint32_t)reg, 1U,
161 (uint8_t *)&readValue, 2U);
162
163 *value = (uint16_t)WM8904_SWAP_UINT16_BYTE_SEQUENCE(readValue);
164
165 return retval;
166 }
167
168 /*!
169 * brief WM8904 modify register.
170 *
171 * param handle WM8904 handle structure.
172 * param reg register address.
173 * oaram mask register bits mask.
174 * param value value to write.
175 * return kStatus_Success, else failed.
176 */
WM8904_ModifyRegister(wm8904_handle_t * handle,uint8_t reg,uint16_t mask,uint16_t value)177 status_t WM8904_ModifyRegister(wm8904_handle_t *handle, uint8_t reg, uint16_t mask, uint16_t value)
178 {
179 status_t result = kStatus_Success;
180 uint16_t regValue;
181
182 result = WM8904_ReadRegister(handle, reg, ®Value);
183 if (result != kStatus_WM8904_Success)
184 {
185 return result;
186 }
187
188 regValue &= (uint16_t)~mask;
189 regValue |= value;
190
191 return WM8904_WriteRegister(handle, reg, regValue);
192 }
193
194 /*!
195 * brief Initializes WM8904.
196 *
197 * param handle WM8904 handle structure.
198 * param codec_config WM8904 configuration structure.
199 */
WM8904_Init(wm8904_handle_t * handle,wm8904_config_t * wm8904Config)200 status_t WM8904_Init(wm8904_handle_t *handle, wm8904_config_t *wm8904Config)
201 {
202 assert(handle != NULL);
203 assert(wm8904Config != NULL);
204
205 status_t result = kStatus_Success;
206 uint32_t sysclk = 0U;
207 wm8904_config_t *config = wm8904Config;
208 handle->config = config;
209
210 /* i2c bus initialization */
211 result = CODEC_I2C_Init(handle->i2cHandle, wm8904Config->i2cConfig.codecI2CInstance, WM8904_I2C_BITRATE,
212 wm8904Config->i2cConfig.codecI2CSourceClock);
213 if (result != (status_t)kStatus_HAL_I2cSuccess)
214 {
215 return kStatus_WM8904_Fail;
216 }
217
218 /* reset */
219 result = WM8904_WriteRegister(handle, WM8904_RESET, 0x0000);
220 if (result != kStatus_WM8904_Success)
221 {
222 return result;
223 }
224
225 /* MCLK_INV=0, SYSCLK_SRC=0, TOCLK_RATE=0, OPCLK_ENA=1,
226 * CLK_SYS_ENA=1, CLK_DSP_ENA=1, TOCLK_ENA=1 */
227 result = WM8904_WriteRegister(handle, WM8904_CLK_RATES_2, 0x000F);
228 if (result != kStatus_WM8904_Success)
229 {
230 return result;
231 }
232
233 /* WSEQ_ENA=1, WSEQ_WRITE_INDEX=0_0000 */
234 result = WM8904_WriteRegister(handle, WM8904_WRT_SEQUENCER_0, 0x0100);
235 if (result != kStatus_WM8904_Success)
236 {
237 return result;
238 }
239
240 /* WSEQ_ABORT=0, WSEQ_START=1, WSEQ_START_INDEX=00_0000 */
241 result = WM8904_WriteRegister(handle, WM8904_WRT_SEQUENCER_3, 0x0100);
242 if (result != kStatus_WM8904_Success)
243 {
244 return result;
245 }
246
247 result = WM8904_WaitOnWriteSequencer(handle);
248 if (result != kStatus_WM8904_Success)
249 {
250 return result;
251 }
252
253 /* TOCLK_RATE_DIV16=0, TOCLK_RATE_x4=1, SR_MODE=0, MCLK_DIV=1
254 * (Required for MMCs: SGY, KRT see erratum CE000546) */
255 result = WM8904_WriteRegister(handle, WM8904_CLK_RATES_0, 0xA45F);
256 if (result != kStatus_WM8904_Success)
257 {
258 return result;
259 }
260
261 /* INL_ENA=1, INR ENA=1 */
262 result = WM8904_WriteRegister(handle, WM8904_POWER_MGMT_0, 0x0003);
263 if (result != kStatus_WM8904_Success)
264 {
265 return result;
266 }
267
268 /* HPL_PGA_ENA=1, HPR_PGA_ENA=1 */
269 result = WM8904_WriteRegister(handle, WM8904_POWER_MGMT_2, 0x0003);
270 if (result != kStatus_WM8904_Success)
271 {
272 return result;
273 }
274
275 /* DACL_ENA=1, DACR_ENA=1, ADCL_ENA=1, ADCR_ENA=1 */
276 result = WM8904_WriteRegister(handle, WM8904_POWER_MGMT_6, 0x000F);
277 if (result != kStatus_WM8904_Success)
278 {
279 return result;
280 }
281
282 /* ADC_OSR128=1 */
283 result = WM8904_WriteRegister(handle, WM8904_ANALOG_ADC_0, 0x0001);
284 if (result != kStatus_WM8904_Success)
285 {
286 return result;
287 }
288
289 /* DACL_DATINV=0, DACR_DATINV=0, DAC_BOOST=00, LOOPBACK=0, AIFADCL_SRC=0,
290 * AIFADCR_SRC=1, AIFDACL_SRC=0, AIFDACR_SRC=1, ADC_COMP=0, ADC_COMPMODE=0,
291 * DAC_COMP=0, DAC_COMPMODE=0 */
292 result = WM8904_WriteRegister(handle, WM8904_AUDIO_IF_0, 0x0050);
293 if (result != kStatus_WM8904_Success)
294 {
295 return result;
296 }
297
298 /* DAC_MONO=0, DAC_SB_FILT-0, DAC_MUTERATE=0, DAC_UNMUTE RAMP=0,
299 * DAC_OSR128=1, DAC_MUTE=0, DEEMPH=0 (none) */
300 result = WM8904_WriteRegister(handle, WM8904_DAC_DIG_1, 0x0040);
301 if (result != kStatus_WM8904_Success)
302 {
303 return result;
304 }
305
306 /* LINMUTE=0, LIN_VOL=0_0101 */
307 result = WM8904_WriteRegister(handle, WM8904_ANALOG_LEFT_IN_0, 0x0005);
308 if (result != kStatus_WM8904_Success)
309 {
310 return result;
311 }
312
313 /* RINMUTE=0, RIN VOL=0_0101 LINEOUTL RMV SHORT-1, LINEOUTL ENA_OUTP=1,
314 * LINEOUTL_ENA_DLY=1, LINEOUTL_ENA=1, LINEOUTR_RMV_SHORT-1,
315 * LINEOUTR_ENA_OUTP=1 */
316 result = WM8904_WriteRegister(handle, WM8904_ANALOG_RIGHT_IN_0, 0x0005);
317 if (result != kStatus_WM8904_Success)
318 {
319 return result;
320 }
321
322 /* HPOUTL_MUTE=0, HPOUT_VU=0, HPOUTLZC=0, HPOUTL_VOL=10_1101 */
323 result = WM8904_WriteRegister(handle, WM8904_ANALOG_OUT1_LEFT, 0x00AD);
324 if (result != kStatus_WM8904_Success)
325 {
326 return result;
327 }
328
329 /* HPOUTR_MUTE=0, HPOUT_VU=0, HPOUTRZC=0, HPOUTR_VOL=10_1101 */
330 result = WM8904_WriteRegister(handle, WM8904_ANALOG_OUT1_RIGHT, 0x00AD);
331 if (result != kStatus_WM8904_Success)
332 {
333 return result;
334 }
335
336 /* Enable DC servos for headphone out */
337 result = WM8904_WriteRegister(handle, WM8904_DC_SERVO_0, 0x0003);
338 if (result != kStatus_WM8904_Success)
339 {
340 return result;
341 }
342
343 /* HPL_RMV_SHORT=1, HPL_ENA_OUTP=1, HPL_ENA_DLY=1, HPL_ENA=1,
344 * HPR_RMV_SHORT=1, HPR_ENA_OUTP=1, HPR_ENA_DLY=1, HPR_ENA=1 */
345 result = WM8904_WriteRegister(handle, WM8904_ANALOG_HP_0, 0x00FF);
346 if (result != kStatus_WM8904_Success)
347 {
348 return result;
349 }
350
351 /* CP_DYN_PWR=1 */
352 result = WM8904_WriteRegister(handle, WM8904_CLS_W_0, 0x0001);
353 if (result != kStatus_WM8904_Success)
354 {
355 return result;
356 }
357
358 /* CP_ENA=1 */
359 result = WM8904_WriteRegister(handle, WM8904_CHRG_PUMP_0, 0x0001);
360 if (result != kStatus_WM8904_Success)
361 {
362 return result;
363 }
364
365 /* set audio format */
366 result = WM8904_SetProtocol(handle, config->protocol);
367 if (result != kStatus_WM8904_Success)
368 {
369 return result;
370 }
371
372 if (config->sysClkSource == kWM8904_SysClkSourceFLL)
373 {
374 result = WM8904_SetFLLConfig(handle, config->fll);
375 if (result != kStatus_WM8904_Success)
376 {
377 return result;
378 }
379 sysclk = config->fll->outputClock_HZ;
380 }
381 else
382 {
383 sysclk = config->mclk_HZ;
384 }
385
386 result = WM8904_CheckAudioFormat(handle, &config->format, sysclk);
387 if (result != kStatus_WM8904_Success)
388 {
389 return result;
390 }
391
392 result =
393 WM8904_ModifyRegister(handle, WM8904_CLK_RATES_2, (uint16_t)(1UL << 14U), (uint16_t)(config->sysClkSource));
394 if (kStatus_WM8904_Success != result)
395 {
396 return result;
397 }
398
399 if (config->master)
400 {
401 result = WM8904_SetMasterClock(handle, sysclk, (uint32_t)(WM8904_MAP_SAMPLERATE(config->format.sampleRate)),
402 (uint32_t)(WM8904_MAP_BITWIDTH(config->format.bitWidth)));
403 if (result != kStatus_WM8904_Success)
404 {
405 return result;
406 }
407 }
408 else
409 {
410 /* BCLK/LRCLK default direction input */
411 result = WM8904_ModifyRegister(handle, WM8904_AUDIO_IF_1, 1U << 6U, 0U);
412 if (kStatus_WM8904_Success != result)
413 {
414 return result;
415 }
416
417 result = WM8904_ModifyRegister(handle, WM8904_AUDIO_IF_3, (uint16_t)(1UL << 11U), 0U);
418 if (kStatus_WM8904_Success != result)
419 {
420 return result;
421 }
422 }
423
424 /* set record source and channel */
425 result = WM8904_SetRecord(handle, config->recordSource);
426 if (result != kStatus_WM8904_Success)
427 {
428 return result;
429 }
430 result = WM8904_SetRecordChannel(handle, config->recordChannelLeft, config->recordChannelRight);
431 if (result != kStatus_WM8904_Success)
432 {
433 return result;
434 }
435 /* set play source */
436 result = WM8904_SetPlay(handle, config->playSource);
437 if (result != kStatus_WM8904_Success)
438 {
439 return result;
440 }
441
442 return result;
443 }
444
445 /*!
446 * brief Deinitializes the WM8904 codec.
447 *
448 * This function resets WM8904.
449 *
450 * param handle WM8904 handle structure.
451 *
452 * return kStatus_WM8904_Success if successful, different code otherwise.
453 */
WM8904_Deinit(wm8904_handle_t * handle)454 status_t WM8904_Deinit(wm8904_handle_t *handle)
455 {
456 /* reset */
457 if (WM8904_WriteRegister(handle, WM8904_RESET, 0x0000) == kStatus_WM8904_Success)
458 {
459 return CODEC_I2C_Deinit(handle->i2cHandle);
460 }
461
462 return kStatus_WM8904_Fail;
463 }
464
465 /*!
466 * brief Fills the configuration structure with default values.
467 *
468 * The default values are:
469 *
470 * master = false;
471 * protocol = kWM8904_ProtocolI2S;
472 * format.fsRatio = kWM8904_FsRatio64X;
473 * format.sampleRate = kWM8904_SampleRate48kHz;
474 * format.bitWidth = kWM8904_BitWidth16;
475 *
476 * param handle WM8904 handle structure to be filled with default values.
477 */
WM8904_GetDefaultConfig(wm8904_config_t * config)478 void WM8904_GetDefaultConfig(wm8904_config_t *config)
479 {
480 (void)memset(config, 0, sizeof(wm8904_config_t));
481
482 config->master = false;
483 config->protocol = kWM8904_ProtocolI2S;
484 config->format.sampleRate = kWM8904_SampleRate48kHz;
485 config->format.bitWidth = kWM8904_BitWidth16;
486 }
487
488 /*!
489 * brief Sets WM8904 as master or slave.
490 * deprecated DO NOT USE THIS API ANYMORE. IT HAS BEEN SUPERCEDED BY @ref WM8904_SetMasterClock
491 * param handle WM8904 handle structure.
492 * param master true for master, false for slave.
493 *
494 * return kStatus_WM8904_Success if successful, different code otherwise.
495 */
WM8904_SetMasterSlave(wm8904_handle_t * handle,bool master)496 status_t WM8904_SetMasterSlave(wm8904_handle_t *handle, bool master)
497 {
498 if (master)
499 {
500 /* only slave currently supported */
501 return kStatus_WM8904_Fail;
502 }
503
504 return kStatus_WM8904_Success;
505 }
506
507 /*!
508 * brief Sets WM8904 master clock configuration.
509 *
510 * param handle WM8904 handle structure.
511 * param sysclk system clock rate.
512 * param sampleRate sample rate
513 * param bitWidth bit width
514 *
515 * return kStatus_WM8904_Success if successful, different code otherwise.
516 */
WM8904_SetMasterClock(wm8904_handle_t * handle,uint32_t sysclk,uint32_t sampleRate,uint32_t bitWidth)517 status_t WM8904_SetMasterClock(wm8904_handle_t *handle, uint32_t sysclk, uint32_t sampleRate, uint32_t bitWidth)
518 {
519 uint32_t bclk = sampleRate * bitWidth * 2U;
520 uint32_t bclkDiv = 0U;
521 uint16_t audioInterface = 0U;
522 status_t result = kStatus_WM8904_Success;
523 uint16_t sysclkDiv = 0U;
524
525 result = WM8904_ReadRegister(handle, WM8904_CLK_RATES_0, &sysclkDiv);
526 sysclk = sysclk >> (sysclkDiv & 0x1U);
527
528 if ((sysclk / bclk > 48U) || (bclk / sampleRate > 2047U) || (bclk / sampleRate < 8U))
529 {
530 return kStatus_InvalidArgument;
531 }
532
533 result = WM8904_ReadRegister(handle, WM8904_AUDIO_IF_2, &audioInterface);
534 if (kStatus_WM8904_Success != result)
535 {
536 return result;
537 }
538
539 audioInterface &= ~(uint16_t)0x1FU;
540 bclkDiv = (sysclk * 10U) / bclk;
541
542 switch (bclkDiv)
543 {
544 case 10:
545 audioInterface |= 0U;
546 break;
547 case 15:
548 audioInterface |= 1U;
549 break;
550 case 20:
551 audioInterface |= 2U;
552 break;
553 case 30:
554 audioInterface |= 3U;
555 break;
556 case 40:
557 audioInterface |= 4U;
558 break;
559 case 50:
560 audioInterface |= 5U;
561 break;
562 case 55:
563 audioInterface |= 6U;
564 break;
565 case 60:
566 audioInterface |= 7U;
567 break;
568 case 80:
569 audioInterface |= 8U;
570 break;
571 case 100:
572 audioInterface |= 9U;
573 break;
574 case 110:
575 audioInterface |= 10U;
576 break;
577 case 120:
578 audioInterface |= 11U;
579 break;
580 case 160:
581 audioInterface |= 12U;
582 break;
583 case 200:
584 audioInterface |= 13U;
585 break;
586 case 220:
587 audioInterface |= 14U;
588 break;
589 case 240:
590 audioInterface |= 15U;
591 break;
592 case 250:
593 audioInterface |= 16U;
594 break;
595 case 300:
596 audioInterface |= 17U;
597 break;
598 case 320:
599 audioInterface |= 18U;
600 break;
601 case 440:
602 audioInterface |= 19U;
603 break;
604 case 480:
605 audioInterface |= 20U;
606 break;
607 default:
608 result = kStatus_InvalidArgument;
609 break;
610 }
611
612 if (kStatus_WM8904_Success != result)
613 {
614 return result;
615 }
616
617 /* bclk divider */
618 result = WM8904_WriteRegister(handle, WM8904_AUDIO_IF_2, audioInterface);
619 if (kStatus_WM8904_Success != result)
620 {
621 return result;
622 }
623 /* bclk direction output */
624 result = WM8904_ModifyRegister(handle, WM8904_AUDIO_IF_1, 1U << 6U, 1U << 6U);
625 if (kStatus_WM8904_Success != result)
626 {
627 return result;
628 }
629
630 result = WM8904_ModifyRegister(handle, WM8904_GPIO_CONTROL_4, 0x8FU, 1U);
631 if (kStatus_WM8904_Success != result)
632 {
633 return result;
634 }
635 /* LRCLK direction and divider */
636 audioInterface = (uint16_t)((1UL << 11U) | (bclk / sampleRate));
637 result = WM8904_ModifyRegister(handle, WM8904_AUDIO_IF_3, 0xFFFU, audioInterface);
638 if (kStatus_WM8904_Success != result)
639 {
640 return result;
641 }
642
643 return kStatus_WM8904_Success;
644 }
645
646 /*!
647 * brief WM8904 set PLL configuration
648 * This function will enable the GPIO1 FLL clock output function, so user can see
649 * the generated fll output clock frequency from WM8904 GPIO1.
650 *
651 * param handle wm8904 handler pointer.
652 * param config FLL configuration pointer.
653 *
654 */
WM8904_SetFLLConfig(wm8904_handle_t * handle,wm8904_fll_config_t * config)655 status_t WM8904_SetFLLConfig(wm8904_handle_t *handle, wm8904_fll_config_t *config)
656 {
657 assert(config != NULL);
658 assert(handle != NULL);
659
660 uint32_t referenceClock = config->refClock_HZ;
661 uint32_t inputDivider = 0U;
662 uint32_t fvco = 0U, outputDiv = 0U, ratio = 0U;
663 uint32_t n = 0U, k = 0U;
664
665 /* it is recommended that the highest possible frequency - within the 13.5MHz limit - should be selected */
666 if (referenceClock < 13500000U)
667 {
668 inputDivider = 0;
669 }
670 else if (referenceClock / 2U < 13500000U)
671 {
672 inputDivider = 1;
673 }
674 else if (referenceClock / 4U < 13500000U)
675 {
676 inputDivider = 2;
677 }
678 else
679 {
680 inputDivider = 3;
681 }
682
683 if (referenceClock / (1UL << inputDivider) > 13500000U)
684 {
685 return kStatus_InvalidArgument;
686 }
687
688 referenceClock = referenceClock / (1UL << inputDivider);
689
690 for (outputDiv = 4U; outputDiv <= 64U; outputDiv++)
691 {
692 fvco = outputDiv * config->outputClock_HZ;
693 if ((fvco >= 90000000U) && (fvco <= 100000000U))
694 {
695 break;
696 }
697 }
698
699 if (referenceClock <= 64000U)
700 {
701 ratio = 4U;
702 }
703 else if (referenceClock <= 128000U)
704 {
705 ratio = 3U;
706 }
707 else if (referenceClock <= 256000U)
708 {
709 ratio = 2U;
710 }
711 else if (referenceClock <= 1000000U)
712 {
713 ratio = 1U;
714 }
715 else
716 {
717 ratio = 0U;
718 }
719
720 n = fvco / ((ratio + 1U) * referenceClock);
721 k = (uint32_t)((uint64_t)fvco * 1000000U) / ((ratio + 1U) * referenceClock);
722 if (n != 0U)
723 {
724 k = k - n * 1000000U;
725 }
726 k = (uint32_t)((uint64_t)k * 65536U) / 1000000U;
727
728 /* configure WM8904 */
729 if (WM8904_ModifyRegister(handle, WM8904_FLL_CONTROL_1, 7U, 4U) != kStatus_Success)
730 {
731 return kStatus_WM8904_Fail;
732 }
733
734 /* configure WM8904 */
735 if (WM8904_ModifyRegister(handle, WM8904_FLL_CONTROL_2, 0x3F07U, (uint16_t)(((outputDiv - 1U) << 8U) | ratio)) !=
736 kStatus_Success)
737 {
738 return kStatus_WM8904_Fail;
739 }
740
741 if (kStatus_WM8904_Success != WM8904_WriteRegister(handle, WM8904_FLL_CONTROL_3, (uint16_t)k))
742 {
743 return kStatus_WM8904_Fail;
744 }
745
746 if (WM8904_ModifyRegister(handle, WM8904_FLL_CONTROL_4, 0x7FE0U, (uint16_t)(n << 5U)) != kStatus_Success)
747 {
748 return kStatus_WM8904_Fail;
749 }
750
751 if (kStatus_WM8904_Success !=
752 WM8904_WriteRegister(handle, WM8904_FLL_CONTROL_5, (uint16_t)((inputDivider << 3U) | (uint16_t)config->source)))
753 {
754 return kStatus_WM8904_Fail;
755 }
756
757 if (WM8904_ModifyRegister(handle, WM8904_FLL_CONTROL_1, 1U, 1) != kStatus_Success)
758 {
759 return kStatus_WM8904_Fail;
760 }
761
762 /* enable GPIO1 output fll output clock */
763 if (kStatus_WM8904_Success != WM8904_WriteRegister(handle, 0x79U, (uint16_t)9U))
764 {
765 return kStatus_WM8904_Fail;
766 }
767
768 return kStatus_Success;
769 }
770
771 /*!
772 * brief Sets the audio data transfer protocol.
773 *
774 * param handle WM8904 handle structure.
775 * param protocol Audio transfer protocol.
776 *
777 * return kStatus_WM8904_Success if successful, different code otherwise.
778 */
WM8904_SetProtocol(wm8904_handle_t * handle,wm8904_protocol_t protocol)779 status_t WM8904_SetProtocol(wm8904_handle_t *handle, wm8904_protocol_t protocol)
780 {
781 return WM8904_ModifyRegister(handle, WM8904_AUDIO_IF_1, (0x0003U | (1U << 4U)), (uint16_t)protocol);
782 }
783
784 /*!
785 * brief Select LRC polarity.
786 *
787 * param handle WM8904 handle structure.
788 * param polarity LRC clock polarity.
789 *
790 * return kStatus_WM8904_Success if successful, different code otherwise.
791 */
WM8904_SelectLRCPolarity(wm8904_handle_t * handle,uint32_t polarity)792 status_t WM8904_SelectLRCPolarity(wm8904_handle_t *handle, uint32_t polarity)
793 {
794 return WM8904_ModifyRegister(handle, WM8904_AUDIO_IF_1, 0x0010U, (uint16_t)polarity);
795 }
796
797 /*!
798 * brief Enable WM8904 DAC time slot.
799 *
800 * param handle WM8904 handle structure.
801 * param timeslot timeslot number.
802 *
803 * return kStatus_WM8904_Success if successful, different code otherwise.
804 */
WM8904_EnableDACTDMMode(wm8904_handle_t * handle,wm8904_timeslot_t timeSlot)805 status_t WM8904_EnableDACTDMMode(wm8904_handle_t *handle, wm8904_timeslot_t timeSlot)
806 {
807 return WM8904_ModifyRegister(handle, WM8904_AUDIO_IF_1, ((uint16_t)3U << 12U),
808 (((uint16_t)1U << 13U) | ((uint16_t)timeSlot << 12U)));
809 }
810
811 /*!
812 * brief Enable WM8904 ADC time slot.
813 *
814 * param handle WM8904 handle structure.
815 * param timeslot timeslot number.
816 *
817 * return kStatus_WM8904_Success if successful, different code otherwise.
818 */
WM8904_EnableADCTDMMode(wm8904_handle_t * handle,wm8904_timeslot_t timeSlot)819 status_t WM8904_EnableADCTDMMode(wm8904_handle_t *handle, wm8904_timeslot_t timeSlot)
820 {
821 return WM8904_ModifyRegister(handle, WM8904_AUDIO_IF_1, ((uint16_t)3U << 10U),
822 (((uint16_t)1U << 11U) | ((uint16_t)timeSlot << 10U)));
823 }
824
825 /*!
826 * brief check and update the audio data format.
827 * This api is used check the fsRatio setting based on the mclk and sample rate, if fsRatio setting
828 * is not correct, it will correct it according to mclk and sample rate.
829 * param handle WM8904 handle structure.
830 * param format audio data format
831 * param mclkFreq mclk frequency
832 *
833 * return kStatus_WM8904_Success if successful, different code otherwise.
834 */
WM8904_CheckAudioFormat(wm8904_handle_t * handle,wm8904_audio_format_t * format,uint32_t mclkFreq)835 status_t WM8904_CheckAudioFormat(wm8904_handle_t *handle, wm8904_audio_format_t *format, uint32_t mclkFreq)
836 {
837 assert((handle != NULL) && (format != NULL));
838
839 status_t result = kStatus_Success;
840 uint16_t mclkDiv = 0U;
841 uint32_t sampleRate = 0U;
842 uint32_t fsRatio = 0U;
843 wm8904_sample_rate_t regSamplerate = format->sampleRate;
844 status_t error = kStatus_WM8904_Success;
845
846 result = WM8904_ReadRegister(handle, WM8904_CLK_RATES_0, &mclkDiv);
847 if (kStatus_WM8904_Success != result)
848 {
849 return result;
850 }
851
852 switch (format->sampleRate)
853 {
854 case kWM8904_SampleRate8kHz:
855 sampleRate = 8000;
856 break;
857 case kWM8904_SampleRate11025Hz:
858 sampleRate = 11025;
859 regSamplerate = kWM8904_SampleRate12kHz;
860 break;
861 case kWM8904_SampleRate12kHz:
862 sampleRate = 12000;
863 break;
864 case kWM8904_SampleRate16kHz:
865 sampleRate = 16000;
866 break;
867 case kWM8904_SampleRate22050Hz:
868 sampleRate = 22050;
869 regSamplerate = kWM8904_SampleRate24kHz;
870 break;
871 case kWM8904_SampleRate24kHz:
872 sampleRate = 24000;
873 break;
874 case kWM8904_SampleRate32kHz:
875 sampleRate = 32000;
876 break;
877 case kWM8904_SampleRate44100Hz:
878 sampleRate = 44100;
879 regSamplerate = kWM8904_SampleRate48kHz;
880 break;
881 case kWM8904_SampleRate48kHz:
882 sampleRate = 48000;
883 break;
884 default:
885 error = kStatus_WM8904_Fail;
886 break;
887 }
888
889 if (error != kStatus_WM8904_Success)
890 {
891 return error;
892 }
893
894 fsRatio = (mclkFreq >> (mclkDiv & 0x1U)) / sampleRate;
895
896 switch (fsRatio)
897 {
898 case 64:
899 format->fsRatio = kWM8904_FsRatio64X;
900 break;
901 case 128:
902 format->fsRatio = kWM8904_FsRatio128X;
903 break;
904 case 192:
905 format->fsRatio = kWM8904_FsRatio192X;
906 break;
907 case 256:
908 format->fsRatio = kWM8904_FsRatio256X;
909 break;
910 case 384:
911 format->fsRatio = kWM8904_FsRatio384X;
912 break;
913 case 512:
914 format->fsRatio = kWM8904_FsRatio512X;
915 break;
916 case 768:
917 format->fsRatio = kWM8904_FsRatio768X;
918 break;
919 case 1024:
920 format->fsRatio = kWM8904_FsRatio1024X;
921 break;
922 case 1408:
923 format->fsRatio = kWM8904_FsRatio1408X;
924 break;
925 case 1536:
926 format->fsRatio = kWM8904_FsRatio1536X;
927 break;
928 default:
929 error = kStatus_WM8904_Fail;
930 break;
931 }
932
933 if (error != kStatus_WM8904_Success)
934 {
935 return error;
936 }
937
938 return WM8904_UpdateFormat(handle, format->fsRatio, regSamplerate, format->bitWidth);
939 }
940
941 /*!
942 * brief Sets the audio data format.
943 *
944 * param handle WM8904 handle structure.
945 * param sysclk external input clock frequency used as WM8904 system clock.
946 * param sampleRate Sample rate frequency in Hz.
947 * param bitWidth Audio data bit width.
948 *
949 * return kStatus_WM8904_Success if successful, different code otherwise.
950 */
WM8904_SetAudioFormat(wm8904_handle_t * handle,uint32_t sysclk,uint32_t sampleRate,uint32_t bitWidth)951 status_t WM8904_SetAudioFormat(wm8904_handle_t *handle, uint32_t sysclk, uint32_t sampleRate, uint32_t bitWidth)
952 {
953 uint32_t ratio = 0;
954 status_t error = kStatus_WM8904_Success;
955 wm8904_bit_width_t regBitWidth = kWM8904_BitWidth32;
956 wm8904_sample_rate_t regSamplerate = kWM8904_SampleRate48kHz;
957 wm8904_fs_ratio_t regFsRatio = kWM8904_FsRatio1536X;
958 uint16_t tempReg = 0U;
959
960 error = WM8904_ReadRegister(handle, WM8904_CLK_RATES_0, &tempReg);
961 if (error != kStatus_WM8904_Success)
962 {
963 return error;
964 }
965
966 switch (sampleRate)
967 {
968 case 8000:
969 regSamplerate = kWM8904_SampleRate8kHz;
970 break;
971 case 11025:
972 regSamplerate = kWM8904_SampleRate12kHz;
973 break;
974 case 12000:
975 regSamplerate = kWM8904_SampleRate12kHz;
976 break;
977 case 16000:
978 regSamplerate = kWM8904_SampleRate16kHz;
979 break;
980 case 22050:
981 regSamplerate = kWM8904_SampleRate24kHz;
982 break;
983 case 24000:
984 regSamplerate = kWM8904_SampleRate24kHz;
985 break;
986 case 32000:
987 regSamplerate = kWM8904_SampleRate32kHz;
988 break;
989 case 44100:
990 regSamplerate = kWM8904_SampleRate48kHz;
991 break;
992 case 48000:
993 regSamplerate = kWM8904_SampleRate48kHz;
994 break;
995 default:
996 error = kStatus_WM8904_Fail;
997 break;
998 }
999
1000 if (error != kStatus_WM8904_Success)
1001 {
1002 return error;
1003 }
1004
1005 switch (bitWidth)
1006 {
1007 case 16:
1008 regBitWidth = kWM8904_BitWidth16;
1009 break;
1010 case 20:
1011 regBitWidth = kWM8904_BitWidth20;
1012 break;
1013 case 24:
1014 regBitWidth = kWM8904_BitWidth24;
1015 break;
1016 case 32:
1017 regBitWidth = kWM8904_BitWidth32;
1018 break;
1019 default:
1020 error = kStatus_WM8904_Fail;
1021 break;
1022 }
1023
1024 if (error != kStatus_WM8904_Success)
1025 {
1026 return error;
1027 }
1028
1029 ratio = (sysclk >> (tempReg & 0x1U)) / sampleRate;
1030
1031 switch (ratio)
1032 {
1033 case 64:
1034 regFsRatio = kWM8904_FsRatio64X;
1035 break;
1036 case 128:
1037 regFsRatio = kWM8904_FsRatio128X;
1038 break;
1039 case 192:
1040 regFsRatio = kWM8904_FsRatio192X;
1041 break;
1042 case 256:
1043 regFsRatio = kWM8904_FsRatio256X;
1044 break;
1045 case 384:
1046 regFsRatio = kWM8904_FsRatio384X;
1047 break;
1048 case 512:
1049 regFsRatio = kWM8904_FsRatio512X;
1050 break;
1051 case 768:
1052 regFsRatio = kWM8904_FsRatio768X;
1053 break;
1054 case 1024:
1055 regFsRatio = kWM8904_FsRatio1024X;
1056 break;
1057 case 1408:
1058 regFsRatio = kWM8904_FsRatio1408X;
1059 break;
1060 case 1536:
1061 regFsRatio = kWM8904_FsRatio1536X;
1062 break;
1063 default:
1064 error = kStatus_WM8904_Fail;
1065 break;
1066 }
1067
1068 if (error == kStatus_WM8904_Success)
1069 {
1070 if (kStatus_WM8904_Success == WM8904_UpdateFormat(handle, regFsRatio, regSamplerate, regBitWidth))
1071 {
1072 /* check codec in master or not */
1073 error = WM8904_ReadRegister(handle, WM8904_AUDIO_IF_1, &tempReg);
1074 if (kStatus_WM8904_Success == error)
1075 {
1076 if ((tempReg & (1UL << 6U)) != 0U)
1077 {
1078 error = WM8904_SetMasterClock(handle, sysclk, sampleRate, bitWidth);
1079 }
1080 }
1081 }
1082 }
1083
1084 return error;
1085 }
1086
1087 /*!
1088 * brief Sets the headphone output volume.
1089 *
1090 * The parameter should be from 0 to 63.
1091 * The resulting volume will be (parameter - 57 dB).
1092 * 0 for -57 dB, 57 for 0 dB, 63 for +6 dB etc.
1093 *
1094 * param handle WM8904 handle structure.
1095 * param volumeLeft Volume of the left channel.
1096 * param volumeRight Volume of the right channel.
1097 *
1098 * return kStatus_WM8904_Success if successful, different code otherwise.
1099 */
WM8904_SetVolume(wm8904_handle_t * handle,uint16_t volumeLeft,uint16_t volumeRight)1100 status_t WM8904_SetVolume(wm8904_handle_t *handle, uint16_t volumeLeft, uint16_t volumeRight)
1101 {
1102 assert(volumeRight <= WM8904_MAP_HEADPHONE_LINEOUT_MAX_VOLUME);
1103 assert(volumeLeft <= WM8904_MAP_HEADPHONE_LINEOUT_MAX_VOLUME);
1104
1105 status_t result = kStatus_Success;
1106
1107 /* 0x1BF means unmute the OUT and reset the OUT volume update bit and volume range fields*/
1108 result = WM8904_ModifyRegister(handle, WM8904_ANALOG_OUT1_LEFT, 0x1BF, volumeLeft);
1109 if (result != kStatus_WM8904_Success)
1110 {
1111 return result;
1112 }
1113
1114 result = WM8904_ModifyRegister(handle, WM8904_ANALOG_OUT1_RIGHT, 0x1BFU, ((uint16_t)volumeRight | 0x0080U));
1115 if (result != kStatus_WM8904_Success)
1116 {
1117 return result;
1118 }
1119
1120 return kStatus_WM8904_Success;
1121 }
1122
1123 /*!
1124 * brief Sets the headphone output mute.
1125 *
1126 * param handle WM8904 handle structure.
1127 * param muteLeft true to mute left channel, false to unmute.
1128 * param muteRight true to mute right channel, false to unmute.
1129 *
1130 * return kStatus_WM8904_Success if successful, different code otherwise.
1131 */
WM8904_SetMute(wm8904_handle_t * handle,bool muteLeft,bool muteRight)1132 status_t WM8904_SetMute(wm8904_handle_t *handle, bool muteLeft, bool muteRight)
1133 {
1134 status_t result = kStatus_Success;
1135 uint16_t left = (uint16_t)(muteLeft ? 0x0100U : 0x0000U);
1136 uint16_t right = (uint16_t)(muteRight ? 0x0100U : 0x0000U);
1137
1138 result = WM8904_ModifyRegister(handle, WM8904_ANALOG_OUT1_LEFT, 0x0100, left);
1139 if (result != kStatus_WM8904_Success)
1140 {
1141 return result;
1142 }
1143
1144 result = WM8904_ModifyRegister(handle, WM8904_ANALOG_OUT1_RIGHT, 0x0180U, ((uint16_t)right | 0x0080U));
1145 if (result != kStatus_WM8904_Success)
1146 {
1147 return result;
1148 }
1149
1150 return kStatus_WM8904_Success;
1151 }
1152
1153 #if WM8904_DEBUG_REGISTER
1154 /*!
1155 * brief Reads content of all WM8904 registers and prints it to debug console.
1156 *
1157 * param handle WM8904 handle structure.
1158 *
1159 * return kStatus_WM8904_Success if successful, different code otherwise.
1160 */
WM8904_PrintRegisters(wm8904_handle_t * handle)1161 status_t WM8904_PrintRegisters(wm8904_handle_t *handle)
1162 {
1163 status_t result = kStatus_Success;
1164 uint16_t value;
1165 uint32_t i;
1166
1167 for (i = 0; i < sizeof(allRegisters); i++)
1168 {
1169 result = WM8904_ReadRegister(handle, allRegisters[i], &value);
1170 if (result != kStatus_WM8904_Success)
1171 {
1172 PRINTF("\r\n");
1173 return result;
1174 }
1175 PRINTF("%s", ((i % 8) == 0) ? "\r\n" : "\t");
1176 PRINTF("%02X:%04X", allRegisters[i], value);
1177 }
1178
1179 PRINTF("\r\n");
1180 return result;
1181 }
1182 #endif
1183
1184 /*!
1185 * brief Sets the channel output volume.
1186 *
1187 * The parameter should be from 0 to 63.
1188 * The resulting volume will be.
1189 * 0 for -57dB, 63 for 6DB.
1190 *
1191 * param handle codec handle structure.
1192 * param channel codec channel.
1193 * param volume volume value from 0 -63.
1194 *
1195 * return kStatus_WM8904_Success if successful, different code otherwise.
1196 */
WM8904_SetChannelVolume(wm8904_handle_t * handle,uint32_t channel,uint32_t volume)1197 status_t WM8904_SetChannelVolume(wm8904_handle_t *handle, uint32_t channel, uint32_t volume)
1198 {
1199 assert(volume <= WM8904_MAP_HEADPHONE_LINEOUT_MAX_VOLUME);
1200
1201 status_t ret = kStatus_Fail;
1202
1203 /* headphone left channel
1204 * 0x1BF means unmute the OUT and reset the OUT volume update bit and volume range fields
1205 */
1206 if ((channel & (uint32_t)kWM8904_HeadphoneLeft) != 0U)
1207 {
1208 ret = WM8904_ModifyRegister(handle, WM8904_ANALOG_OUT1_LEFT, 0x1BFU, (uint16_t)volume | 0x80U);
1209 }
1210 /* headphone right channel */
1211 if ((channel & (uint32_t)kWM8904_HeadphoneRight) != 0U)
1212 {
1213 ret = WM8904_ModifyRegister(handle, WM8904_ANALOG_OUT1_RIGHT, 0x1BFU, ((uint16_t)volume | 0x80U));
1214 }
1215 /* line out left channel */
1216 if ((channel & (uint32_t)kWM8904_LineoutLeft) != 0U)
1217 {
1218 ret = WM8904_ModifyRegister(handle, WM8904_ANALOG_OUT2_LEFT, 0x1BFU, (uint16_t)volume | 0X80U);
1219 }
1220 /* line out right channel */
1221 if ((channel & (uint32_t)kWM8904_LineoutRight) != 0U)
1222 {
1223 ret = WM8904_ModifyRegister(handle, WM8904_ANALOG_OUT2_RIGHT, 0x1BFU, (uint16_t)volume | 0x80U);
1224 }
1225
1226 return ret;
1227 }
1228
1229 /*!
1230 * brief Sets the channel mute.
1231 *
1232 * param handle codec handle structure.
1233 * param channel codec module name.
1234 * param isMute true is mute, false unmute.
1235 *
1236 * return kStatus_WM8904_Success if successful, different code otherwise.
1237 */
WM8904_SetChannelMute(wm8904_handle_t * handle,uint32_t channel,bool isMute)1238 status_t WM8904_SetChannelMute(wm8904_handle_t *handle, uint32_t channel, bool isMute)
1239 {
1240 status_t ret = kStatus_Fail;
1241 uint16_t regValue = 0U, regMask = 0U;
1242
1243 regValue = isMute ? 0x180U : 0x80U;
1244 regMask = 0x100U;
1245
1246 /* headphone left channel */
1247 if ((channel & (uint32_t)kWM8904_HeadphoneLeft) != 0U)
1248 {
1249 ret = WM8904_ModifyRegister(handle, WM8904_ANALOG_OUT1_LEFT, regMask, regValue);
1250 }
1251
1252 /* headphone right channel */
1253 if ((channel & (uint32_t)kWM8904_HeadphoneRight) != 0U)
1254 {
1255 ret = WM8904_ModifyRegister(handle, WM8904_ANALOG_OUT1_RIGHT, regMask, regValue);
1256 }
1257
1258 /* line out left channel */
1259 if ((channel & (uint32_t)kWM8904_LineoutLeft) != 0U)
1260 {
1261 ret = WM8904_ModifyRegister(handle, WM8904_ANALOG_OUT2_LEFT, regMask, regValue);
1262 }
1263
1264 /* line out right channel */
1265 if ((channel & (uint32_t)kWM8904_LineoutRight) != 0U)
1266 {
1267 ret = WM8904_ModifyRegister(handle, WM8904_ANALOG_OUT2_RIGHT, regMask, regValue);
1268 }
1269
1270 return ret;
1271 }
1272
1273 /*!
1274 * brief SET the DAC module volume.
1275 *
1276 * param handle WM8904 handle structure.
1277 * param volume volume to be configured.
1278 *
1279 * return kStatus_WM8904_Success if successful, different code otherwise..
1280 */
WM8904_SetDACVolume(wm8904_handle_t * handle,uint8_t volume)1281 status_t WM8904_SetDACVolume(wm8904_handle_t *handle, uint8_t volume)
1282 {
1283 status_t error = kStatus_WM8904_Success;
1284
1285 error = WM8904_WriteRegister(handle, WM8904_DAC_DIGITAL_VOLUME_LEFT, (uint16_t)(volume | 0x100UL));
1286 if (error == kStatus_WM8904_Success)
1287 {
1288 error = WM8904_WriteRegister(handle, WM8904_DAC_DIGITAL_VOLUME_RIGHT, (uint16_t)(volume | 0x100UL));
1289 }
1290
1291 return error;
1292 }
1293
1294 /*!
1295 * brief SET the module output power.
1296 *
1297 * param handle WM8904 handle structure.
1298 * param module wm8904 module.
1299 * param isEnabled, true is power on, false is power down.
1300 *
1301 * return kStatus_WM8904_Success if successful, different code otherwise..
1302 */
WM8904_SetModulePower(wm8904_handle_t * handle,wm8904_module_t module,bool isEnabled)1303 status_t WM8904_SetModulePower(wm8904_handle_t *handle, wm8904_module_t module, bool isEnabled)
1304 {
1305 uint8_t regAddr = 0, regBitMask = 0U, regValue = 0U;
1306 status_t error = kStatus_WM8904_Success;
1307
1308 switch (module)
1309 {
1310 case kWM8904_ModuleADC:
1311 regAddr = WM8904_POWER_MGMT_6;
1312 regBitMask = 3U;
1313 regValue = isEnabled ? 3U : 0U;
1314 break;
1315 case kWM8904_ModuleDAC:
1316 regAddr = WM8904_POWER_MGMT_6;
1317 regBitMask = 0xCU;
1318 regValue = isEnabled ? 0xCU : 0U;
1319
1320 break;
1321 case kWM8904_ModulePGA:
1322 regAddr = WM8904_POWER_MGMT_0;
1323 regBitMask = 3U;
1324 regValue = isEnabled ? 3U : 0U;
1325
1326 break;
1327 case kWM8904_ModuleHeadphone:
1328 regAddr = WM8904_POWER_MGMT_2;
1329 regBitMask = 3U;
1330 regValue = isEnabled ? 3U : 0U;
1331 break;
1332 case kWM8904_ModuleLineout:
1333 regAddr = WM8904_POWER_MGMT_3;
1334 regBitMask = 3U;
1335 regValue = isEnabled ? 3U : 0U;
1336 break;
1337 default:
1338 error = kStatus_InvalidArgument;
1339 break;
1340 }
1341
1342 if (error == kStatus_WM8904_Success)
1343 {
1344 error = WM8904_ModifyRegister(handle, regAddr, regBitMask, regValue);
1345 }
1346
1347 return error;
1348 }
1349
1350 /*!
1351 * brief SET the WM8904 record source.
1352 *
1353 * param handle WM8904 handle structure.
1354 * param recordSource record source , can be a value of kWM8904_ModuleRecordSourceDifferentialLine,
1355 * kWM8904_ModuleRecordSourceDifferentialMic, kWM8904_ModuleRecordSourceSingleEndMic,
1356 * kWM8904_ModuleRecordSourceDigitalMic.
1357 *
1358 * return kStatus_WM8904_Success if successful, different code otherwise.
1359 */
WM8904_SetRecord(wm8904_handle_t * handle,uint32_t recordSource)1360 status_t WM8904_SetRecord(wm8904_handle_t *handle, uint32_t recordSource)
1361 {
1362 uint8_t regLeftAddr = WM8904_ANALOG_LEFT_IN_1, regRightAddr = WM8904_ANALOG_RIGHT_IN_1;
1363 uint16_t regLeftValue = 0U, regRightValue = 0U, regBitMask = 0U;
1364 status_t error = kStatus_Success;
1365
1366 switch (recordSource)
1367 {
1368 case kWM8904_RecordSourceDifferentialLine:
1369 regLeftValue = 1U;
1370 regRightValue = 1U;
1371 regBitMask = 0x3FU;
1372 break;
1373 case kWM8904_RecordSourceDifferentialMic:
1374 regLeftValue = 2U;
1375 regRightValue = 2U;
1376 regBitMask = 0x3FU;
1377 break;
1378 case kWM8904_RecordSourceLineInput:
1379 regLeftValue = 0U;
1380 regRightValue = 0U;
1381 regBitMask = 0x3FU;
1382 break;
1383 case kWM8904_RecordSourceDigitalMic:
1384 regLeftValue = ((uint16_t)1U << 12);
1385 regLeftAddr = WM8904_DAC_DIG_0;
1386 regRightAddr = 0U;
1387 regBitMask = ((uint16_t)1U << 12);
1388 break;
1389
1390 default:
1391 error = kStatus_InvalidArgument;
1392 break;
1393 }
1394
1395 if (error == kStatus_Success)
1396 {
1397 error = WM8904_ModifyRegister(handle, regLeftAddr, regBitMask, regLeftValue);
1398 }
1399
1400 if ((error == kStatus_Success) && (regRightAddr != 0U))
1401 {
1402 error = WM8904_ModifyRegister(handle, regRightAddr, regBitMask, regRightValue);
1403 }
1404
1405 return error;
1406 }
1407
1408 /*!
1409 * brief SET the WM8904 record source.
1410 *
1411 * param handle WM8904 handle structure.
1412 * param leftRecordChannel channel number of left record channel when using differential source, channel number of
1413 * single end left channel when using single end source, channel number of digital mic when using digital mic source.
1414 * param rightRecordChannel channel number of right record channel when using differential source, channel number
1415 * of single end right channel when using single end source.
1416 *
1417 * return kStatus_WM8904_Success if successful, different code otherwise..
1418 */
WM8904_SetRecordChannel(wm8904_handle_t * handle,uint32_t leftRecordChannel,uint32_t rightRecordChannel)1419 status_t WM8904_SetRecordChannel(wm8904_handle_t *handle, uint32_t leftRecordChannel, uint32_t rightRecordChannel)
1420 {
1421 uint8_t regLeftAddr = WM8904_ANALOG_LEFT_IN_1, regRightAddr = WM8904_ANALOG_RIGHT_IN_1;
1422 uint16_t regLeftValue = 0U, regRightValue = 0U, regBitMask;
1423 status_t ret = kStatus_Success;
1424 uint8_t leftPositiveChannel = 0U, leftNegativeChannel = 0U, rightPositiveChannel = 0U, rightNegativeChannel = 0U;
1425
1426 if ((leftRecordChannel & (uint32_t)kWM8904_RecordChannelDifferentialPositive1) != 0U)
1427 {
1428 leftPositiveChannel = 0U;
1429 }
1430 else if ((leftRecordChannel & (uint32_t)kWM8904_RecordChannelDifferentialPositive2) != 0U)
1431 {
1432 leftPositiveChannel = 1U;
1433 }
1434 else
1435 {
1436 leftPositiveChannel = 2U;
1437 }
1438
1439 if ((leftRecordChannel & (uint32_t)kWM8904_RecordChannelDifferentialNegative1) != 0U)
1440 {
1441 leftNegativeChannel = 0U;
1442 }
1443 else if ((leftRecordChannel & (uint32_t)kWM8904_RecordChannelDifferentialNegative2) != 0U)
1444 {
1445 leftNegativeChannel = 1U;
1446 }
1447 else if ((leftRecordChannel & (uint32_t)kWM8904_RecordChannelDifferentialNegative3) != 0U)
1448 {
1449 leftNegativeChannel = 2U;
1450 }
1451 else
1452 {
1453 leftNegativeChannel = leftPositiveChannel;
1454 }
1455
1456 if ((rightRecordChannel & (uint32_t)kWM8904_RecordChannelDifferentialPositive1) != 0U)
1457 {
1458 rightPositiveChannel = 0U;
1459 }
1460 else if ((rightRecordChannel & (uint32_t)kWM8904_RecordChannelDifferentialPositive2) != 0U)
1461 {
1462 rightPositiveChannel = 1U;
1463 }
1464 else
1465 {
1466 rightPositiveChannel = 2U;
1467 }
1468
1469 if ((rightRecordChannel & (uint32_t)kWM8904_RecordChannelDifferentialNegative1) != 0U)
1470 {
1471 rightNegativeChannel = 0U;
1472 }
1473 else if ((rightRecordChannel & (uint32_t)kWM8904_RecordChannelDifferentialNegative2) != 0U)
1474 {
1475 rightNegativeChannel = 1U;
1476 }
1477 else if ((rightRecordChannel & (uint32_t)kWM8904_RecordChannelDifferentialNegative3) != 0U)
1478 {
1479 rightNegativeChannel = 2U;
1480 }
1481 else
1482 {
1483 rightNegativeChannel = rightPositiveChannel;
1484 }
1485
1486 regLeftValue = (((uint16_t)leftNegativeChannel & 3U) << 4U) | (((uint16_t)leftPositiveChannel & 3U) << 2U);
1487 regRightValue = (((uint16_t)rightNegativeChannel & 3U) << 4U) | (((uint16_t)rightPositiveChannel & 3U) << 2U);
1488 regBitMask = 0x3CU;
1489
1490 ret = WM8904_ModifyRegister(handle, regLeftAddr, regBitMask, regLeftValue);
1491
1492 if (ret == kStatus_Success)
1493 {
1494 return WM8904_ModifyRegister(handle, regRightAddr, regBitMask, regRightValue);
1495 }
1496
1497 return kStatus_Success;
1498 }
1499
1500 /*!
1501 * brief SET the WM8904 play source.
1502 *
1503 * param handle WM8904 handle structure.
1504 * param playSource play source , can be a value of kWM8904_PlaySourcePGA/kWM8904_PlaySourceDAC.
1505 *
1506 * return kStatus_WM8904_Success if successful, different code otherwise..
1507 */
WM8904_SetPlay(wm8904_handle_t * handle,uint32_t playSource)1508 status_t WM8904_SetPlay(wm8904_handle_t *handle, uint32_t playSource)
1509 {
1510 uint16_t regValue = 0U, regBitMask = 0xFU;
1511
1512 /* source form PGA*/
1513 if (playSource == (uint32_t)kWM8904_PlaySourcePGA)
1514 {
1515 regValue |= (3U << 2U) | 3U;
1516 }
1517 /* source from DAC*/
1518 if (playSource == (uint32_t)kWM8904_PlaySourceDAC)
1519 {
1520 regValue &= (uint16_t) ~((3U << 2U) | 3U);
1521 }
1522
1523 return WM8904_ModifyRegister(handle, WM8904_ANALOG_OUT12_ZC, regBitMask, regValue);
1524 }
1525