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