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-12-12 Wayne First version
10 *
11 ******************************************************************************/
12
13 #include <rtconfig.h>
14
15 #if defined(NU_PKG_USING_NAU8822)
16
17 #include <rtthread.h>
18 #include <rtdevice.h>
19
20 #include "acodec_nau8822.h"
21 #include "drv_i2s.h"
22
23 #define DBG_ENABLE
24 #define DBG_LEVEL DBG_LOG
25 #define DBG_SECTION_NAME "acodec.nau8822"
26 #define DBG_COLOR
27 #include <rtdbg.h>
28
29 #define DEF_NAU8822_ADDR 0x1A
30
31 static struct rt_i2c_bus_device *g_I2cBusDev = NULL;
32 S_NU_NAU8822_CONFIG *g_psCodecConfig = NULL;
33
34 static rt_err_t nau8822_init(void);
35 static rt_err_t nau8822_reset(void);
36 static rt_err_t nau8822_dsp_control(struct rt_audio_configure *config);
37 static rt_err_t nau8822_mixer_control(rt_uint32_t ui32Units, rt_uint32_t ui32Value);
38 static rt_err_t nau8822_mixer_query(rt_uint32_t ui32Units, rt_uint32_t *ui32Value);
39
40 nu_acodec_ops nu_acodec_ops_nau8822 =
41 {
42 .name = "NAU8822",
43 .role = NU_ACODEC_ROLE_MASTER,
44 .config = { // Default settings.
45 .samplerate = 16000,
46 .channels = 2,
47 .samplebits = 16
48 },
49 .nu_acodec_init = nau8822_init,
50 .nu_acodec_reset = nau8822_reset,
51
52 .nu_acodec_dsp_control = nau8822_dsp_control,
53 .nu_acodec_mixer_control = nau8822_mixer_control,
54 .nu_acodec_mixer_query = nau8822_mixer_query
55 };
56
nau8822_delay_ms(rt_uint32_t nms)57 static void nau8822_delay_ms(rt_uint32_t nms)
58 {
59 rt_thread_mdelay(nms);
60 }
61
I2C_ReadNAU8822(uint8_t u8addr,uint16_t * pu16data)62 static int I2C_ReadNAU8822(uint8_t u8addr, uint16_t *pu16data)
63 {
64 struct rt_i2c_msg msgs[2];
65 uint8_t u8TxData = (u8addr << 1);
66
67 RT_ASSERT(g_I2cBusDev != NULL);
68 RT_ASSERT(pu16data != NULL);
69
70 msgs[0].addr = DEF_NAU8822_ADDR; /* Slave address */
71 msgs[0].flags = RT_I2C_WR; /* Write flag */
72 msgs[0].buf = (rt_uint8_t *)&u8TxData; /* Number of bytes sent */
73 msgs[0].len = sizeof(u8TxData); /* Number of bytes read */
74
75 msgs[1].addr = DEF_NAU8822_ADDR; /* Slave address */
76 msgs[1].flags = RT_I2C_RD; /* Read flag */
77 msgs[1].buf = (rt_uint8_t *)pu16data; /* Read data pointer */
78 msgs[1].len = 2; /* Number of bytes read */
79
80 if (rt_i2c_transfer(g_I2cBusDev, &msgs[0], 2) != 2)
81 {
82 return -RT_ERROR;
83 }
84
85 return RT_EOK;
86 }
87
I2C_WriteNAU8822(uint8_t u8addr,uint16_t u16data)88 static int I2C_WriteNAU8822(uint8_t u8addr, uint16_t u16data)
89 {
90 /* Write 9-bit data to 7-bit address register of NAU8822 */
91 struct rt_i2c_msg msg;
92 uint8_t au8TxData[2];
93
94 RT_ASSERT(g_I2cBusDev != NULL);
95
96 au8TxData[0] = (uint8_t)((u8addr << 1) | (u16data >> 8)); //u8addr [7:1] | u16data [8]
97 au8TxData[1] = (uint8_t)(u16data & 0x00FF); //data [7:0]
98
99 msg.addr = DEF_NAU8822_ADDR; /* Slave address */
100 msg.flags = RT_I2C_WR; /* Write flag */
101 msg.buf = (rt_uint8_t *)&au8TxData[0]; /* Slave register address */
102 msg.len = sizeof(au8TxData); /* Number of bytes sent */
103
104 if (g_I2cBusDev && rt_i2c_transfer(g_I2cBusDev, &msg, 1) != 1)
105 {
106 rt_kprintf("[Failed] addr=%x, data=%d\n", u8addr, u16data);
107 return -RT_ERROR;
108 }
109
110 {
111 /* Verify */
112 uint8_t au8RxData[2];
113 I2C_ReadNAU8822(u8addr, (uint16_t *)&au8RxData[0]);
114 rt_kprintf("Wrote addr %02x -> 0x%04x, read back -> 0x%02x%02x\n", u8addr, u16data, au8RxData[0], au8RxData[1]);
115 }
116
117 return RT_EOK;
118 }
119
nau8822_phonejack_set(S_NU_NAU8822_CONFIG * psCodecConfig,int bEnable)120 static void nau8822_phonejack_set(S_NU_NAU8822_CONFIG *psCodecConfig, int bEnable)
121 {
122 rt_pin_mode(psCodecConfig->pin_phonejack_en, PIN_MODE_OUTPUT);
123
124 if (bEnable)
125 {
126 rt_pin_write(psCodecConfig->pin_phonejack_en, PIN_LOW);
127 }
128 else
129 {
130 rt_pin_write(psCodecConfig->pin_phonejack_en, PIN_HIGH);
131 }
132 }
133
134
nau8822_probe(void)135 static rt_err_t nau8822_probe(void)
136 {
137 return RT_EOK;
138 }
139
nau8822_reset(void)140 static rt_err_t nau8822_reset(void)
141 {
142 I2C_WriteNAU8822(0, 0x000); /* Reset all registers */
143 nau8822_delay_ms(30);
144
145 LOG_I("Software Reset.\n");
146
147 return RT_EOK;
148 }
149
nau8822_dsp_config(rt_uint32_t ui32SamplRate,rt_uint8_t u8ChNum,rt_uint8_t u8SamplBit)150 static rt_err_t nau8822_dsp_config(rt_uint32_t ui32SamplRate, rt_uint8_t u8ChNum, rt_uint8_t u8SamplBit)
151 {
152 uint8_t bClkDiv;
153 uint8_t mClkDiv;
154 uint16_t u16AudIf = 0x010; /* I2S, 16-bit */
155 uint16_t u16ClkCtrl;
156 uint8_t u8WLEN;
157
158 if (ui32SamplRate > 48000)
159 return -RT_ERROR;
160
161 if (u8ChNum == 2)
162 {
163 u16AudIf = (u16AudIf & 0x1FE) | 0x0;
164 }
165 else
166 {
167 u16AudIf = (u16AudIf & 0x1FE) | 0x1;
168 }
169
170 /* Force to set Channel number to 2 */
171 u8ChNum = 2;
172
173 switch (u8SamplBit)
174 {
175 case 16:
176 u8WLEN = 0x0;
177 break;
178
179 case 20:
180 u8WLEN = 0x1;
181 break;
182
183 case 24:
184 u8WLEN = 0x2;
185 break;
186
187 case 32:
188 u8WLEN = 0x3;
189 break;
190
191 default:
192 LOG_E("sample rate not match!\n");
193 return -RT_ERROR;
194 }
195 u16AudIf = (u16AudIf & 0x19F) | (u8WLEN << 5);
196
197 if (ui32SamplRate % 11025)
198 {
199 I2C_WriteNAU8822(36, 0x008); //12.288Mhz
200 I2C_WriteNAU8822(37, 0x00C);
201 I2C_WriteNAU8822(38, 0x093);
202 I2C_WriteNAU8822(39, 0x0E9);
203
204 /* FIXME */
205 if (ui32SamplRate > 48000)
206 ui32SamplRate = 8000;
207
208 mClkDiv = (48000 * 256 * u8ChNum) / (ui32SamplRate * 256);
209 bClkDiv = (ui32SamplRate * 256) / (ui32SamplRate * u8ChNum * u8SamplBit);
210 }
211 else
212 {
213 I2C_WriteNAU8822(36, 0x007); //11.2896Mhz
214 I2C_WriteNAU8822(37, 0x021);
215 I2C_WriteNAU8822(38, 0x161);
216 I2C_WriteNAU8822(39, 0x026);
217
218 /* FIXME */
219 if (ui32SamplRate > 44100)
220 ui32SamplRate = 11025;
221
222 mClkDiv = (44100 * 256 * u8ChNum) / (ui32SamplRate * 256);
223 bClkDiv = (ui32SamplRate * 256) / (ui32SamplRate * u8ChNum * u8SamplBit);
224 }
225
226 switch (mClkDiv)
227 {
228 case 1:
229 mClkDiv = 0;
230 break;
231 case 2:
232 mClkDiv = 2;
233 break;
234 case 3:
235 mClkDiv = 3;
236 break;
237 case 4:
238 mClkDiv = 4;
239 break;
240 case 6:
241 mClkDiv = 5;
242 break;
243 case 8:
244 mClkDiv = 6;
245 break;
246 case 12:
247 mClkDiv = 7;
248 break;
249 default:
250 LOG_E("mclk divider not match!\n");
251 mClkDiv = 0;
252 return -RT_ERROR;
253 }
254
255 switch (bClkDiv)
256 {
257 case 1:
258 bClkDiv = 0;
259 break;
260 case 2:
261 bClkDiv = 1;
262 break;
263 case 4:
264 bClkDiv = 2;
265 break;
266 case 8:
267 bClkDiv = 3;
268 break;
269 case 16:
270 bClkDiv = 4;
271 break;
272 case 32:
273 bClkDiv = 5;
274 break;
275 default:
276 LOG_E("bclk divider not match!\n");
277 bClkDiv = 0;
278 return -RT_ERROR;
279 }
280
281 if (nu_acodec_ops_nau8822.role == NU_ACODEC_ROLE_MASTER)
282 {
283 u16ClkCtrl = (1 << 8) | (1 << 0); //Use internal PLL, FS/BCLK
284 }
285
286 u16ClkCtrl = (u16ClkCtrl & 0x11F) | (mClkDiv << 5);
287 u16ClkCtrl = (u16ClkCtrl & 0x1E3) | (bClkDiv << 2);
288
289 I2C_WriteNAU8822(4, u16AudIf);
290
291 I2C_WriteNAU8822(6, u16ClkCtrl);
292
293 return RT_EOK;
294 }
295
nau8822_init(void)296 static rt_err_t nau8822_init(void)
297 {
298 //input source is MIC
299 if (nu_acodec_ops_nau8822.role == NU_ACODEC_ROLE_MASTER)
300 {
301 I2C_WriteNAU8822(1, 0x03F); /* PLLEN, MICBIASEN, ABIASEN, IOBUFEN, REFIMP(3kohm) */
302 }
303 else
304 {
305 I2C_WriteNAU8822(1, 0x01F); /* MICBIASEN, ABIASEN, IOBUFEN, REFIMP(3kohm) */
306 }
307
308 I2C_WriteNAU8822(2, 0x1BF); /* Enable L/R Headphone, ADC Mix/Boost, ADC */
309 I2C_WriteNAU8822(3, 0x07F); /* Enable L/R main mixer, DAC */
310 I2C_WriteNAU8822(4, 0x010); /* 16-bit word length, I2S format, Stereo */
311 I2C_WriteNAU8822(5, 0x000); /* Companding control and loop back mode (all disable) */
312 nau8822_delay_ms(30);
313
314 I2C_WriteNAU8822(6, 0x1AD); /* Divide by 6, 16K */
315 I2C_WriteNAU8822(7, 0x006); /* 16K for internal filter coefficients */
316 I2C_WriteNAU8822(10, 0x008); /* DAC soft mute is disabled, DAC oversampling rate is 128x */
317 I2C_WriteNAU8822(14, 0x108); /* ADC HP filter is disabled, ADC oversampling rate is 128x */
318 I2C_WriteNAU8822(15, 0x1EF); /* ADC left digital volume control */
319 I2C_WriteNAU8822(16, 0x1EF); /* ADC right digital volume control */
320 I2C_WriteNAU8822(44, 0x033); /* LMICN/LMICP is connected to PGA */
321 I2C_WriteNAU8822(47, 0x100); /* Gain value */
322 I2C_WriteNAU8822(48, 0x100); /* Gain value */
323 I2C_WriteNAU8822(50, 0x001); /* Left DAC connected to LMIX */
324 I2C_WriteNAU8822(51, 0x001); /* Right DAC connected to RMIX */
325
326 I2C_WriteNAU8822(0x34, 0x13F);
327 I2C_WriteNAU8822(0x35, 0x13F);
328
329 nu_acodec_ops_nau8822.config.samplerate = 16000;
330 nu_acodec_ops_nau8822.config.channels = 2;
331 nu_acodec_ops_nau8822.config.samplebits = 16;
332
333 LOG_I("Initialized done.\n");
334
335 return RT_EOK;
336 }
337
nau8822_dsp_control(struct rt_audio_configure * config)338 static rt_err_t nau8822_dsp_control(struct rt_audio_configure *config)
339 {
340 rt_err_t result = RT_EOK;
341 RT_ASSERT(config != RT_NULL);
342
343 if (rt_memcmp((void *)config, (void *)&nu_acodec_ops_nau8822.config, sizeof(struct rt_audio_configure)) != 0)
344 {
345 if ((result = nau8822_dsp_config(config->samplerate, config->channels, config->samplebits)) == RT_EOK)
346 rt_memcpy((void *)&nu_acodec_ops_nau8822.config, (void *)config, sizeof(struct rt_audio_configure)) ;
347 }
348 return result;
349 }
350
nau8822_mixer_control(rt_uint32_t ui32Units,rt_uint32_t ui32Value)351 static rt_err_t nau8822_mixer_control(rt_uint32_t ui32Units, rt_uint32_t ui32Value)
352 {
353 switch (ui32Units)
354 {
355 case AUDIO_MIXER_MUTE:
356 {
357 uint16_t u16Data;
358 I2C_ReadNAU8822(10, &u16Data);
359 if (ui32Value)
360 {
361 I2C_WriteNAU8822(10, u16Data | (1 << 6));
362 nau8822_phonejack_set(g_psCodecConfig, 0);
363 }
364 else
365 {
366 I2C_WriteNAU8822(10, u16Data & ~(1 << 6));
367 nau8822_phonejack_set(g_psCodecConfig, 1);
368 }
369 }
370 break;
371 case AUDIO_MIXER_VOLUME:
372 {
373 uint8_t u8GAIN = 256 * ui32Value / 100;
374 I2C_WriteNAU8822(11, 0x100 | u8GAIN);
375 I2C_WriteNAU8822(12, 0x100 | u8GAIN);
376
377 u8GAIN = 0x3F * ui32Value / 100;
378 I2C_WriteNAU8822(54, 0x100 | u8GAIN);
379 I2C_WriteNAU8822(55, 0x100 | u8GAIN);
380 }
381 break;
382 case AUDIO_MIXER_QUERY:
383 case AUDIO_MIXER_BASS:
384 case AUDIO_MIXER_MID:
385 case AUDIO_MIXER_TREBLE:
386 case AUDIO_MIXER_EQUALIZER:
387 case AUDIO_MIXER_LINE:
388 case AUDIO_MIXER_DIGITAL:
389 case AUDIO_MIXER_MIC:
390 case AUDIO_MIXER_VITURAL:
391 case AUDIO_MIXER_EXTEND:
392 default:
393 return -RT_ERROR;
394 }
395
396 return RT_EOK;
397 }
398
nau8822_mixer_query(rt_uint32_t ui32Units,rt_uint32_t * pui32Value)399 static rt_err_t nau8822_mixer_query(rt_uint32_t ui32Units, rt_uint32_t *pui32Value)
400 {
401 RT_ASSERT(pui32Value != RT_NULL);
402 rt_uint16_t u16RV = 0;
403
404 switch (ui32Units)
405 {
406 case AUDIO_MIXER_QUERY:
407 *pui32Value = AUDIO_MIXER_VOLUME | AUDIO_MIXER_MUTE;
408 break;
409
410 case AUDIO_MIXER_MUTE:
411 I2C_ReadNAU8822(10, (uint16_t *)&u16RV);
412 if (u16RV & (1 << 6))
413 *pui32Value = 1;
414 else
415 *pui32Value = 0;
416 break;
417
418 case AUDIO_MIXER_VOLUME:
419 I2C_ReadNAU8822(11, (uint16_t *)&u16RV);
420 *pui32Value = u16RV * 100 / 256;
421 break;
422
423 case AUDIO_MIXER_BASS:
424 case AUDIO_MIXER_MID:
425 case AUDIO_MIXER_TREBLE:
426 case AUDIO_MIXER_EQUALIZER:
427 case AUDIO_MIXER_LINE:
428 case AUDIO_MIXER_DIGITAL:
429 case AUDIO_MIXER_MIC:
430 case AUDIO_MIXER_VITURAL:
431 case AUDIO_MIXER_EXTEND:
432 default:
433 return -RT_ERROR;
434 }
435 return RT_EOK;
436 }
437
nu_hw_nau8822_init(S_NU_NAU8822_CONFIG * psCodecConfig)438 int nu_hw_nau8822_init(S_NU_NAU8822_CONFIG *psCodecConfig)
439 {
440 RT_ASSERT(psCodecConfig != RT_NULL);
441 struct rt_i2c_bus_device *psI2cBusDev;
442 struct rt_audio_device *psAudioDev;
443 nu_i2s_t psNuI2s;
444
445 /* Find I2C bus */
446 psI2cBusDev = (struct rt_i2c_bus_device *)rt_device_find(psCodecConfig->i2c_bus_name);
447 if (psI2cBusDev == RT_NULL)
448 {
449 LOG_E("Can't found I2C bus - %s..!\n", psCodecConfig->i2c_bus_name);
450 goto exit_rt_hw_nau8822_init;
451 }
452
453 /* Find I2S bus */
454 psAudioDev = (struct rt_audio_device *)rt_device_find(psCodecConfig->i2s_bus_name);
455 if (psAudioDev == RT_NULL)
456 {
457 LOG_E("Can't found I2S bus - %s ..!\n", psCodecConfig->i2s_bus_name);
458 goto exit_rt_hw_nau8822_init;
459 }
460
461 if (nau8822_probe() != RT_EOK)
462 {
463 LOG_E("Can't found audio codec..!\n");
464 goto exit_rt_hw_nau8822_init;
465 }
466
467 /* Store this board setting. */
468 g_psCodecConfig = psCodecConfig;
469 g_I2cBusDev = psI2cBusDev;
470
471 /* Get NuI2S device instance. */
472 psNuI2s = (nu_i2s_t)psAudioDev;
473
474 /* Register Acodec Ops */
475 psNuI2s->AcodecOps = &nu_acodec_ops_nau8822;
476
477 /* Use Acodec default settings. */
478 rt_memcpy(&psNuI2s->config, &nu_acodec_ops_nau8822.config, sizeof(struct rt_audio_configure));
479
480 return RT_EOK;
481
482 exit_rt_hw_nau8822_init:
483
484 return -RT_ERROR;
485 }
486
487 #endif //#if defined(NU_PKG_USING_NAU8822)
488