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, &regValue);
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