1 /**************************************************************************//**
2 *
3 * @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Change Logs:
8 * Date Author Notes
9 * 2020-1-16 Wayne First version
10 *
11 ******************************************************************************/
12
13 #include <rtconfig.h>
14
15 #if defined(NU_PKG_USING_NAU88L25)
16
17 #include <rtthread.h>
18 #include <rtdevice.h>
19
20 #include "acodec_nau88l25.h"
21 #include "drv_i2s.h"
22
23 #define DBG_ENABLE
24 #define DBG_LEVEL DBG_LOG
25 #define DBG_SECTION_NAME "acodec.nau88l25"
26 #define DBG_COLOR
27 #include <rtdbg.h>
28
29 #define DEF_NAU88L25_ADDR 0x1A
30
31 static struct rt_i2c_bus_device *g_I2cBusDev = NULL;
32 S_NU_NAU88L25_CONFIG *g_psCodecConfig = NULL;
33
34 static rt_err_t nau88l25_init(void);
35 static rt_err_t nau88l25_reset(void);
36 static rt_err_t nau88l25_dsp_control(struct rt_audio_configure *config);
37 static rt_err_t nau88l25_mixer_control(rt_uint32_t ui32Units, rt_uint32_t ui32Value);
38 static rt_err_t nau88l25_mixer_query(rt_uint32_t ui32Units, rt_uint32_t *ui32Value);
39
40 nu_acodec_ops nu_acodec_ops_nau88l25 =
41 {
42 .name = "NAU88L25",
43 .role = NU_ACODEC_ROLE_MASTER,
44 .config = { // Default settings.
45 .samplerate = 48000,
46 .channels = 2,
47 .samplebits = 16
48 },
49 .nu_acodec_init = nau88l25_init,
50 .nu_acodec_reset = nau88l25_reset,
51
52 .nu_acodec_dsp_control = nau88l25_dsp_control,
53 .nu_acodec_mixer_control = nau88l25_mixer_control,
54 .nu_acodec_mixer_query = nau88l25_mixer_query
55 };
56
nau88l25_delay_ms(rt_uint32_t nms)57 static void nau88l25_delay_ms(rt_uint32_t nms)
58 {
59 rt_thread_mdelay(nms);
60 }
61
I2C_WriteNAU88L25(uint16_t u16addr,uint16_t u16data)62 static int I2C_WriteNAU88L25(uint16_t u16addr, uint16_t u16data)
63 {
64 struct rt_i2c_msg msg;
65 char au8TxData[4];
66
67 RT_ASSERT(g_I2cBusDev != NULL);
68
69 au8TxData[0] = (uint8_t)((u16addr >> 8) & 0x00FF); //addr [15:8]
70 au8TxData[1] = (uint8_t)(u16addr & 0x00FF); //addr [ 7:0]
71 au8TxData[2] = (uint8_t)((u16data >> 8) & 0x00FF); //data [15:8]
72 au8TxData[3] = (uint8_t)(u16data & 0x00FF); //data [ 7:0]
73
74 msg.addr = DEF_NAU88L25_ADDR; /* Slave address */
75 msg.flags = RT_I2C_WR; /* Write flag */
76 msg.buf = (rt_uint8_t *)&au8TxData[0]; /* Slave register address */
77 msg.len = sizeof(au8TxData); /* Number of bytes sent */
78
79 if (g_I2cBusDev && rt_i2c_transfer(g_I2cBusDev, &msg, 1) != 1)
80 {
81 rt_kprintf("[Failed] addr=%x, data=%d\n", u16addr, u16data);
82 return -RT_ERROR;
83 }
84
85 return RT_EOK;
86 }
87
I2C_ReadNAU88L25(uint16_t u16addr,uint16_t * pu16data)88 static int I2C_ReadNAU88L25(uint16_t u16addr, uint16_t *pu16data)
89 {
90 struct rt_i2c_msg msgs[2];
91 char au8TxData[2];
92
93 RT_ASSERT(g_I2cBusDev != NULL);
94 RT_ASSERT(pu16data != NULL);
95
96 au8TxData[0] = (uint8_t)((u16addr >> 8) & 0x00FF); //addr [15:8]
97 au8TxData[1] = (uint8_t)(u16addr & 0x00FF); //addr [ 7:0]
98
99 msgs[0].addr = DEF_NAU88L25_ADDR; /* Slave address */
100 msgs[0].flags = RT_I2C_WR; /* Write flag */
101 msgs[0].buf = (rt_uint8_t *)&au8TxData; /* Number of bytes sent */
102 msgs[0].len = sizeof(au8TxData); /* Number of bytes read */
103
104 msgs[1].addr = DEF_NAU88L25_ADDR; /* Slave address */
105 msgs[1].flags = RT_I2C_RD; /* Read flag */
106 msgs[1].buf = (rt_uint8_t *)pu16data; /* Read data pointer */
107 msgs[1].len = sizeof(uint16_t); /* Number of bytes read */
108
109 if (rt_i2c_transfer(g_I2cBusDev, &msgs[0], 2) != 2)
110 {
111 return -RT_ERROR;
112 }
113
114 return RT_EOK;
115 }
116
nau88l25_phonejack_set(S_NU_NAU88L25_CONFIG * psCodecConfig,int bEnable)117 static void nau88l25_phonejack_set(S_NU_NAU88L25_CONFIG *psCodecConfig, int bEnable)
118 {
119 rt_pin_mode(psCodecConfig->pin_phonejack_en, PIN_MODE_OUTPUT);
120
121 if (bEnable)
122 {
123 rt_pin_write(psCodecConfig->pin_phonejack_en, PIN_LOW);
124 }
125 else
126 {
127 rt_pin_write(psCodecConfig->pin_phonejack_en, PIN_HIGH);
128 }
129 }
130
nau88l25_probe(void)131 static rt_err_t nau88l25_probe(void)
132 {
133 return RT_EOK;
134 }
135
nau88l25_reset(void)136 static rt_err_t nau88l25_reset(void)
137 {
138 I2C_WriteNAU88L25(0, 0x1);
139 I2C_WriteNAU88L25(0, 0); // Reset all registers
140 nau88l25_delay_ms(30);
141
142 LOG_I("Software Reset.\n");
143
144 return RT_EOK;
145 }
146
nau88l25_dsp_config(rt_uint32_t ui32SamplRate,rt_uint8_t u8ChNum,rt_uint8_t u8SamplBit)147 static rt_err_t nau88l25_dsp_config(rt_uint32_t ui32SamplRate, rt_uint8_t u8ChNum, rt_uint8_t u8SamplBit)
148 {
149 int clkDivider;
150 int i2sPcmCtrl2;
151 int lrClkDiv;
152 char bClkDiv;
153 char mClkDiv;
154
155 /* Force to set Channel number to 2 */
156 u8ChNum = 2;
157
158 I2C_WriteNAU88L25(REG_I2S_PCM_CTRL1, AIFMT0_STANDI2S | ((u8SamplBit <= 24) ? ((u8SamplBit - 16) >> 2) : WLEN0_32BIT));
159 u8SamplBit = (u8SamplBit > 16) ? 32 : 16;
160
161 if (ui32SamplRate % 11025)
162 {
163 /* 48000 series 12.288Mhz */
164 I2C_WriteNAU88L25(REG_FLL2, 0x3126);
165 I2C_WriteNAU88L25(REG_FLL3, 0x0008);
166
167 mClkDiv = 49152000 / (ui32SamplRate * 256);
168 }
169 else
170 {
171 /* 44100 series 11.2896Mhz */
172 I2C_WriteNAU88L25(REG_FLL2, 0x86C2);
173 I2C_WriteNAU88L25(REG_FLL3, 0x0007);
174
175 /* FIXME */
176 if (ui32SamplRate > 44100)
177 ui32SamplRate = 11025;
178
179 mClkDiv = 45158400 / (ui32SamplRate * 256);
180 }
181
182 lrClkDiv = u8ChNum * u8SamplBit;
183 bClkDiv = 256 / lrClkDiv;
184
185 switch (mClkDiv)
186 {
187 case 1:
188 mClkDiv = 0;
189 break;
190 case 2:
191 mClkDiv = 2;
192 break;
193 case 4:
194 mClkDiv = 3;
195 break;
196 case 8:
197 mClkDiv = 4;
198 break;
199 case 16:
200 mClkDiv = 5;
201 break;
202 case 32:
203 mClkDiv = 6;
204 break;
205 case 3:
206 mClkDiv = 7;
207 break;
208 case 6:
209 mClkDiv = 10;
210 break;
211 case 12:
212 mClkDiv = 11;
213 break;
214 case 24:
215 mClkDiv = 12;
216 break;
217 case 48:
218 mClkDiv = 13;
219 break;
220 case 96:
221 mClkDiv = 14;
222 break;
223 case 5:
224 mClkDiv = 15;
225 break;
226 default:
227 LOG_E("mclk divider not match!\n");
228 mClkDiv = 0;
229 return -RT_ERROR;
230 }
231
232 clkDivider = CLK_SYSCLK_SRC_VCO | CLK_ADC_SRC_DIV2 | CLK_DAC_SRC_DIV2 | mClkDiv;
233 I2C_WriteNAU88L25(REG_CLK_DIVIDER, clkDivider);
234
235 switch (bClkDiv)
236 {
237 case 2:
238 bClkDiv = 0;
239 break;
240 case 4:
241 bClkDiv = 1;
242 break;
243 case 8:
244 bClkDiv = 2;
245 break;
246 case 16:
247 bClkDiv = 3;
248 break;
249 case 32:
250 bClkDiv = 4;
251 break;
252 case 64:
253 bClkDiv = 5;
254 break;
255 default:
256 LOG_E("bclk divider not match!\n");
257 bClkDiv = 0;
258 return -RT_ERROR;
259 }
260
261 switch (lrClkDiv)
262 {
263 case 256:
264 lrClkDiv = 0;
265 break;
266 case 128:
267 lrClkDiv = 1;
268 break;
269 case 64:
270 lrClkDiv = 2;
271 break;
272 case 32:
273 lrClkDiv = 3;
274 break;
275 default:
276 LOG_E("lrclk divider not match!\n");
277 lrClkDiv = 0;
278 return -RT_ERROR;
279 }
280
281 i2sPcmCtrl2 = ADCDAT0_OE | MS0_MASTER | (lrClkDiv << 12) | bClkDiv;
282
283 I2C_WriteNAU88L25(REG_I2S_PCM_CTRL2, i2sPcmCtrl2);
284
285 return RT_EOK;
286 }
287
nau88l25_init(void)288 static rt_err_t nau88l25_init(void)
289 {
290 I2C_WriteNAU88L25(REG_CLK_DIVIDER, CLK_SYSCLK_SRC_VCO | CLK_ADC_SRC_DIV2 | CLK_DAC_SRC_DIV2 | MCLK_SRC_DIV4);
291 I2C_WriteNAU88L25(REG_FLL1, FLL_RATIO_512K);
292 I2C_WriteNAU88L25(REG_FLL2, 0x3126);
293 I2C_WriteNAU88L25(REG_FLL3, 0x0008);
294 I2C_WriteNAU88L25(REG_FLL4, 0x0010);
295 I2C_WriteNAU88L25(REG_FLL5, PDB_DACICTRL | CHB_FILTER_EN);
296 I2C_WriteNAU88L25(REG_FLL6, SDM_EN | CUTOFF500);
297 I2C_WriteNAU88L25(REG_FLL_VCO_RSV, 0xF13C);
298 I2C_WriteNAU88L25(REG_HSD_CTRL, HSD_AUTO_MODE | MANU_ENGND1_GND);
299 I2C_WriteNAU88L25(REG_SAR_CTRL, RES_SEL_70K_OHMS | COMP_SPEED_1US | SAMPLE_SPEED_4US);
300 I2C_WriteNAU88L25(REG_I2S_PCM_CTRL1, AIFMT0_STANDI2S);
301
302 if (nu_acodec_ops_nau88l25.role == NU_ACODEC_ROLE_MASTER)
303 {
304 I2C_WriteNAU88L25(REG_I2S_PCM_CTRL2, LRC_DIV_DIV32 | ADCDAT0_OE | MS0_MASTER | BLCKDIV_DIV8); //301A:Master 3012:Slave
305 }
306 else
307 {
308 I2C_WriteNAU88L25(REG_I2S_PCM_CTRL2, LRC_DIV_DIV32 | ADCDAT0_OE | MS0_SLAVE | BLCKDIV_DIV8);
309 I2C_WriteNAU88L25(REG_LEFT_TIME_SLOT, DIS_FS_SHORT_DET);
310 }
311
312 I2C_WriteNAU88L25(REG_ADC_RATE, 0x10 | ADC_RATE_128);
313 I2C_WriteNAU88L25(REG_DAC_CTRL1, 0x80 | DAC_RATE_128);
314
315 I2C_WriteNAU88L25(REG_MUTE_CTRL, 0x0000); // 0x10000
316 I2C_WriteNAU88L25(REG_ADC_DGAIN_CTRL, DGAINL_ADC0(0xEF));
317 I2C_WriteNAU88L25(REG_DACL_CTRL, DGAINL_DAC(0xAE));
318 I2C_WriteNAU88L25(REG_DACR_CTRL, DGAINR_DAC(0xAE) | DAC_CH_SEL1_RIGHT);
319
320 I2C_WriteNAU88L25(REG_CLASSG_CTRL, CLASSG_TIMER_64MS | CLASSG_CMP_EN_R_DAC | CLASSG_CMP_EN_L_DAC | CLASSG_EN);
321 I2C_WriteNAU88L25(REG_BIAS_ADJ, VMIDEN | VMIDSEL_125K_OHM);
322 I2C_WriteNAU88L25(REG_TRIM_SETTINGS, DRV_IBCTRHS | DRV_ICUTHS | INTEG_IBCTRHS | INTEG_ICUTHS);
323 I2C_WriteNAU88L25(REG_ANALOG_CONTROL_2, AB_ADJ | CAP_1 | CAP_0);
324 I2C_WriteNAU88L25(REG_ANALOG_ADC_1, CHOPRESETN | CHOPF0_DIV4);
325 I2C_WriteNAU88L25(REG_ANALOG_ADC_2, VREFSEL_VMIDE_P5DB | PDNOTL | LFSRRESETN);
326 I2C_WriteNAU88L25(REG_RDAC, DAC_EN_L | DAC_EN_R | CLK_DAC_EN_L | CLK_DAC_EN_R | CLK_DAC_DELAY_2NSEC | DACVREFSEL(0x3));
327 I2C_WriteNAU88L25(REG_MIC_BIAS, INT2KB | LOWNOISE | POWERUP | MICBIASLVL1_1P1x);
328 I2C_WriteNAU88L25(REG_BOOST, PDVMDFST | BIASEN | BOOSTGDIS | EN_SHRT_SHTDWN);
329 I2C_WriteNAU88L25(REG_POWER_UP_CONTROL, PUFEPGA | FEPGA_GAIN(21) | PUP_INTEG_LEFT_HP | PUP_INTEG_RIGHT_HP | PUP_DRV_INSTG_RIGHT_HP | PUP_DRV_INSTG_LEFT_HP | PUP_MAIN_DRV_RIGHT_HP | PUP_MAIN_DRV_LEFT_HP);
330 I2C_WriteNAU88L25(REG_CHARGE_PUMP_AND_DOWN_CONTROL, JAMNODCLOW | RNIN);
331 I2C_WriteNAU88L25(REG_ENA_CTRL, RDAC_EN | LDAC_EN | ADC_EN | DCLK_ADC_EN | DCLK_DAC_EN | CLK_I2S_EN | 0x4);
332
333 nu_acodec_ops_nau88l25.config.samplerate = 48000;
334 nu_acodec_ops_nau88l25.config.channels = 2;
335 nu_acodec_ops_nau88l25.config.samplebits = 16;
336
337 LOG_I("Initialized done.\n");
338
339 return RT_EOK;
340 }
341
nau88l25_dsp_control(struct rt_audio_configure * config)342 static rt_err_t nau88l25_dsp_control(struct rt_audio_configure *config)
343 {
344 rt_err_t result = RT_EOK;
345
346 RT_ASSERT(config != RT_NULL);
347
348 if (rt_memcmp((void *)config, (void *)&nu_acodec_ops_nau88l25.config, sizeof(struct rt_audio_configure)) != 0)
349 {
350 if ((result = nau88l25_dsp_config(config->samplerate, config->channels, config->samplebits)) == RT_EOK)
351 rt_memcpy((void *)&nu_acodec_ops_nau88l25.config, (void *)config, sizeof(struct rt_audio_configure)) ;
352 }
353 return result;
354 }
355
nau88l25_mixer_control(rt_uint32_t ui32Units,rt_uint32_t ui32Value)356 static rt_err_t nau88l25_mixer_control(rt_uint32_t ui32Units, rt_uint32_t ui32Value)
357 {
358 switch (ui32Units)
359 {
360 case AUDIO_MIXER_MUTE:
361 if (ui32Value)
362 {
363 I2C_WriteNAU88L25(REG_MUTE_CTRL, SMUTE_EN);
364 nau88l25_phonejack_set(g_psCodecConfig, 0);
365 }
366 else
367 {
368 I2C_WriteNAU88L25(REG_MUTE_CTRL, 0x0000);
369 nau88l25_phonejack_set(g_psCodecConfig, 1);
370 }
371 break;
372
373 case AUDIO_MIXER_VOLUME:
374 I2C_WriteNAU88L25(REG_DACL_CTRL, DGAINL_DAC(ui32Value * 2));
375 I2C_WriteNAU88L25(REG_DACR_CTRL, DGAINR_DAC(ui32Value * 2) | DAC_CH_SEL1_RIGHT);
376 break;
377
378 case AUDIO_MIXER_QUERY:
379 case AUDIO_MIXER_BASS:
380 case AUDIO_MIXER_MID:
381 case AUDIO_MIXER_TREBLE:
382 case AUDIO_MIXER_EQUALIZER:
383 case AUDIO_MIXER_LINE:
384 case AUDIO_MIXER_DIGITAL:
385 case AUDIO_MIXER_MIC:
386 case AUDIO_MIXER_VITURAL:
387 case AUDIO_MIXER_EXTEND:
388 default:
389 return -RT_ERROR;
390 }
391 return RT_EOK;
392 }
393
nau88l25_mixer_query(rt_uint32_t ui32Units,rt_uint32_t * pui32Value)394 static rt_err_t nau88l25_mixer_query(rt_uint32_t ui32Units, rt_uint32_t *pui32Value)
395 {
396 RT_ASSERT(pui32Value != RT_NULL);
397 rt_uint16_t u16RV = 0;
398
399 switch (ui32Units)
400 {
401 case AUDIO_MIXER_QUERY:
402 *pui32Value = AUDIO_MIXER_VOLUME | AUDIO_MIXER_MUTE;
403 break;
404
405 case AUDIO_MIXER_MUTE:
406 I2C_ReadNAU88L25(REG_MUTE_CTRL, (uint16_t *)&u16RV);
407 if (u16RV & SMUTE_EN)
408 *pui32Value = 1;
409 else
410 *pui32Value = 0;
411 break;
412
413 case AUDIO_MIXER_VOLUME:
414 I2C_ReadNAU88L25(REG_DACL_CTRL, (uint16_t *)&u16RV);
415 *pui32Value = u16RV / 2;
416 break;
417
418 case AUDIO_MIXER_BASS:
419 case AUDIO_MIXER_MID:
420 case AUDIO_MIXER_TREBLE:
421 case AUDIO_MIXER_EQUALIZER:
422 case AUDIO_MIXER_LINE:
423 case AUDIO_MIXER_DIGITAL:
424 case AUDIO_MIXER_MIC:
425 case AUDIO_MIXER_VITURAL:
426 case AUDIO_MIXER_EXTEND:
427 default:
428 return -RT_ERROR;
429 }
430 return RT_EOK;
431 }
432
nu_hw_nau88l25_init(S_NU_NAU88L25_CONFIG * psCodecConfig)433 int nu_hw_nau88l25_init(S_NU_NAU88L25_CONFIG *psCodecConfig)
434 {
435 RT_ASSERT(psCodecConfig != RT_NULL);
436 struct rt_i2c_bus_device *psI2cBusDev;
437 struct rt_audio_device *psAudioDev;
438 nu_i2s_t psNuI2s;
439
440 /* Find I2C bus */
441 psI2cBusDev = (struct rt_i2c_bus_device *)rt_device_find(psCodecConfig->i2c_bus_name);
442 if (psI2cBusDev == RT_NULL)
443 {
444 LOG_E("Can't found I2C bus - %s..!\n", psCodecConfig->i2c_bus_name);
445 goto exit_rt_hw_nau88l25_init;
446 }
447
448 /* Find I2S bus */
449 psAudioDev = (struct rt_audio_device *)rt_device_find(psCodecConfig->i2s_bus_name);
450 if (psAudioDev == RT_NULL)
451 {
452 LOG_E("Can't found I2S bus - %s ..!\n", psCodecConfig->i2s_bus_name);
453 goto exit_rt_hw_nau88l25_init;
454 }
455
456 if (nau88l25_probe() != RT_EOK)
457 {
458 LOG_E("Can't found audio codec..!\n");
459 goto exit_rt_hw_nau88l25_init;
460 }
461
462 /* Store this board setting. */
463 g_psCodecConfig = psCodecConfig;
464 g_I2cBusDev = psI2cBusDev;
465
466 /* Get NuI2S device instance. */
467 psNuI2s = (nu_i2s_t)psAudioDev;
468
469 /* Register Acodec Ops */
470 psNuI2s->AcodecOps = &nu_acodec_ops_nau88l25;
471
472 /* Use Acodec default settings. */
473 rt_memcpy(&psNuI2s->config, &nu_acodec_ops_nau88l25.config, sizeof(struct rt_audio_configure));
474
475 return RT_EOK;
476
477 exit_rt_hw_nau88l25_init:
478
479 return -RT_ERROR;
480 }
481
482 #endif //#if defined(NU_PKG_USING_NAU88L25)
483