123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487 |
- /**************************************************************************//**
- *
- * @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2020-12-12 Wayne First version
- *
- ******************************************************************************/
- #include <rtconfig.h>
- #if defined(NU_PKG_USING_NAU8822)
- #include <rtthread.h>
- #include <rtdevice.h>
- #include "acodec_nau8822.h"
- #include "drv_i2s.h"
- #define DBG_ENABLE
- #define DBG_LEVEL DBG_LOG
- #define DBG_SECTION_NAME "acodec.nau8822"
- #define DBG_COLOR
- #include <rtdbg.h>
- #define DEF_NAU8822_ADDR 0x1A
- static struct rt_i2c_bus_device *g_I2cBusDev = NULL;
- S_NU_NAU8822_CONFIG *g_psCodecConfig = NULL;
- static rt_err_t nau8822_init(void);
- static rt_err_t nau8822_reset(void);
- static rt_err_t nau8822_dsp_control(struct rt_audio_configure *config);
- static rt_err_t nau8822_mixer_control(rt_uint32_t ui32Units, rt_uint32_t ui32Value);
- static rt_err_t nau8822_mixer_query(rt_uint32_t ui32Units, rt_uint32_t *ui32Value);
- nu_acodec_ops nu_acodec_ops_nau8822 =
- {
- .name = "NAU8822",
- .role = NU_ACODEC_ROLE_MASTER,
- .config = { // Default settings.
- .samplerate = 16000,
- .channels = 2,
- .samplebits = 16
- },
- .nu_acodec_init = nau8822_init,
- .nu_acodec_reset = nau8822_reset,
- .nu_acodec_dsp_control = nau8822_dsp_control,
- .nu_acodec_mixer_control = nau8822_mixer_control,
- .nu_acodec_mixer_query = nau8822_mixer_query
- };
- static void nau8822_delay_ms(rt_uint32_t nms)
- {
- rt_thread_mdelay(nms);
- }
- static int I2C_ReadNAU8822(uint8_t u8addr, uint16_t *pu16data)
- {
- struct rt_i2c_msg msgs[2];
- uint8_t u8TxData = (u8addr << 1);
- RT_ASSERT(g_I2cBusDev != NULL);
- RT_ASSERT(pu16data != NULL);
- msgs[0].addr = DEF_NAU8822_ADDR; /* Slave address */
- msgs[0].flags = RT_I2C_WR; /* Write flag */
- msgs[0].buf = (rt_uint8_t *)&u8TxData; /* Number of bytes sent */
- msgs[0].len = sizeof(u8TxData); /* Number of bytes read */
- msgs[1].addr = DEF_NAU8822_ADDR; /* Slave address */
- msgs[1].flags = RT_I2C_RD; /* Read flag */
- msgs[1].buf = (rt_uint8_t *)pu16data; /* Read data pointer */
- msgs[1].len = 2; /* Number of bytes read */
- if (rt_i2c_transfer(g_I2cBusDev, &msgs[0], 2) != 2)
- {
- return -RT_ERROR;
- }
- return RT_EOK;
- }
- static int I2C_WriteNAU8822(uint8_t u8addr, uint16_t u16data)
- {
- /* Write 9-bit data to 7-bit address register of NAU8822 */
- struct rt_i2c_msg msg;
- uint8_t au8TxData[2];
- RT_ASSERT(g_I2cBusDev != NULL);
- au8TxData[0] = (uint8_t)((u8addr << 1) | (u16data >> 8)); //u8addr [7:1] | u16data [8]
- au8TxData[1] = (uint8_t)(u16data & 0x00FF); //data [7:0]
- msg.addr = DEF_NAU8822_ADDR; /* Slave address */
- msg.flags = RT_I2C_WR; /* Write flag */
- msg.buf = (rt_uint8_t *)&au8TxData[0]; /* Slave register address */
- msg.len = sizeof(au8TxData); /* Number of bytes sent */
- if (g_I2cBusDev && rt_i2c_transfer(g_I2cBusDev, &msg, 1) != 1)
- {
- rt_kprintf("[Failed] addr=%x, data=%d\n", u8addr, u16data);
- return -RT_ERROR;
- }
- {
- /* Verify */
- uint8_t au8RxData[2];
- I2C_ReadNAU8822(u8addr, (uint16_t *)&au8RxData[0]);
- rt_kprintf("Wrote addr %02x -> 0x%04x, read back -> 0x%02x%02x\n", u8addr, u16data, au8RxData[0], au8RxData[1]);
- }
- return RT_EOK;
- }
- static void nau8822_phonejack_set(S_NU_NAU8822_CONFIG *psCodecConfig, int bEnable)
- {
- rt_pin_mode(psCodecConfig->pin_phonejack_en, PIN_MODE_OUTPUT);
- if (bEnable)
- {
- rt_pin_write(psCodecConfig->pin_phonejack_en, PIN_LOW);
- }
- else
- {
- rt_pin_write(psCodecConfig->pin_phonejack_en, PIN_HIGH);
- }
- }
- static rt_err_t nau8822_probe(void)
- {
- return RT_EOK;
- }
- static rt_err_t nau8822_reset(void)
- {
- I2C_WriteNAU8822(0, 0x000); /* Reset all registers */
- nau8822_delay_ms(30);
- LOG_I("Software Reset.\n");
- return RT_EOK;
- }
- static rt_err_t nau8822_dsp_config(rt_uint32_t ui32SamplRate, rt_uint8_t u8ChNum, rt_uint8_t u8SamplBit)
- {
- uint8_t bClkDiv;
- uint8_t mClkDiv;
- uint16_t u16AudIf = 0x010; /* I2S, 16-bit */
- uint16_t u16ClkCtrl;
- uint8_t u8WLEN;
- if (ui32SamplRate > 48000)
- return -RT_ERROR;
- if (u8ChNum == 2)
- {
- u16AudIf = (u16AudIf & 0x1FE) | 0x0;
- }
- else
- {
- u16AudIf = (u16AudIf & 0x1FE) | 0x1;
- }
- /* Force to set Channel number to 2 */
- u8ChNum = 2;
- switch (u8SamplBit)
- {
- case 16:
- u8WLEN = 0x0;
- break;
- case 20:
- u8WLEN = 0x1;
- break;
- case 24:
- u8WLEN = 0x2;
- break;
- case 32:
- u8WLEN = 0x3;
- break;
- default:
- LOG_E("sample rate not match!\n");
- return -RT_ERROR;
- }
- u16AudIf = (u16AudIf & 0x19F) | (u8WLEN << 5);
- if (ui32SamplRate % 11025)
- {
- I2C_WriteNAU8822(36, 0x008); //12.288Mhz
- I2C_WriteNAU8822(37, 0x00C);
- I2C_WriteNAU8822(38, 0x093);
- I2C_WriteNAU8822(39, 0x0E9);
- /* FIXME */
- if (ui32SamplRate > 48000)
- ui32SamplRate = 8000;
- mClkDiv = (48000 * 256 * u8ChNum) / (ui32SamplRate * 256);
- bClkDiv = (ui32SamplRate * 256) / (ui32SamplRate * u8ChNum * u8SamplBit);
- }
- else
- {
- I2C_WriteNAU8822(36, 0x007); //11.2896Mhz
- I2C_WriteNAU8822(37, 0x021);
- I2C_WriteNAU8822(38, 0x161);
- I2C_WriteNAU8822(39, 0x026);
- /* FIXME */
- if (ui32SamplRate > 44100)
- ui32SamplRate = 11025;
- mClkDiv = (44100 * 256 * u8ChNum) / (ui32SamplRate * 256);
- bClkDiv = (ui32SamplRate * 256) / (ui32SamplRate * u8ChNum * u8SamplBit);
- }
- switch (mClkDiv)
- {
- case 1:
- mClkDiv = 0;
- break;
- case 2:
- mClkDiv = 2;
- break;
- case 3:
- mClkDiv = 3;
- break;
- case 4:
- mClkDiv = 4;
- break;
- case 6:
- mClkDiv = 5;
- break;
- case 8:
- mClkDiv = 6;
- break;
- case 12:
- mClkDiv = 7;
- break;
- default:
- LOG_E("mclk divider not match!\n");
- mClkDiv = 0;
- return -RT_ERROR;
- }
- switch (bClkDiv)
- {
- case 1:
- bClkDiv = 0;
- break;
- case 2:
- bClkDiv = 1;
- break;
- case 4:
- bClkDiv = 2;
- break;
- case 8:
- bClkDiv = 3;
- break;
- case 16:
- bClkDiv = 4;
- break;
- case 32:
- bClkDiv = 5;
- break;
- default:
- LOG_E("bclk divider not match!\n");
- bClkDiv = 0;
- return -RT_ERROR;
- }
- if (nu_acodec_ops_nau8822.role == NU_ACODEC_ROLE_MASTER)
- {
- u16ClkCtrl = (1 << 8) | (1 << 0); //Use internal PLL, FS/BCLK
- }
- u16ClkCtrl = (u16ClkCtrl & 0x11F) | (mClkDiv << 5);
- u16ClkCtrl = (u16ClkCtrl & 0x1E3) | (bClkDiv << 2);
- I2C_WriteNAU8822(4, u16AudIf);
- I2C_WriteNAU8822(6, u16ClkCtrl);
- return RT_EOK;
- }
- static rt_err_t nau8822_init(void)
- {
- //input source is MIC
- if (nu_acodec_ops_nau8822.role == NU_ACODEC_ROLE_MASTER)
- {
- I2C_WriteNAU8822(1, 0x03F); /* PLLEN, MICBIASEN, ABIASEN, IOBUFEN, REFIMP(3kohm) */
- }
- else
- {
- I2C_WriteNAU8822(1, 0x01F); /* MICBIASEN, ABIASEN, IOBUFEN, REFIMP(3kohm) */
- }
- I2C_WriteNAU8822(2, 0x1BF); /* Enable L/R Headphone, ADC Mix/Boost, ADC */
- I2C_WriteNAU8822(3, 0x07F); /* Enable L/R main mixer, DAC */
- I2C_WriteNAU8822(4, 0x010); /* 16-bit word length, I2S format, Stereo */
- I2C_WriteNAU8822(5, 0x000); /* Companding control and loop back mode (all disable) */
- nau8822_delay_ms(30);
- I2C_WriteNAU8822(6, 0x1AD); /* Divide by 6, 16K */
- I2C_WriteNAU8822(7, 0x006); /* 16K for internal filter coefficients */
- I2C_WriteNAU8822(10, 0x008); /* DAC soft mute is disabled, DAC oversampling rate is 128x */
- I2C_WriteNAU8822(14, 0x108); /* ADC HP filter is disabled, ADC oversampling rate is 128x */
- I2C_WriteNAU8822(15, 0x1EF); /* ADC left digital volume control */
- I2C_WriteNAU8822(16, 0x1EF); /* ADC right digital volume control */
- I2C_WriteNAU8822(44, 0x033); /* LMICN/LMICP is connected to PGA */
- I2C_WriteNAU8822(47, 0x100); /* Gain value */
- I2C_WriteNAU8822(48, 0x100); /* Gain value */
- I2C_WriteNAU8822(50, 0x001); /* Left DAC connected to LMIX */
- I2C_WriteNAU8822(51, 0x001); /* Right DAC connected to RMIX */
- I2C_WriteNAU8822(0x34, 0x13F);
- I2C_WriteNAU8822(0x35, 0x13F);
- nu_acodec_ops_nau8822.config.samplerate = 16000;
- nu_acodec_ops_nau8822.config.channels = 2;
- nu_acodec_ops_nau8822.config.samplebits = 16;
- LOG_I("Initialized done.\n");
- return RT_EOK;
- }
- static rt_err_t nau8822_dsp_control(struct rt_audio_configure *config)
- {
- rt_err_t result = RT_EOK;
- RT_ASSERT(config != RT_NULL);
- if (rt_memcmp((void *)config, (void *)&nu_acodec_ops_nau8822.config, sizeof(struct rt_audio_configure)) != 0)
- {
- if ((result = nau8822_dsp_config(config->samplerate, config->channels, config->samplebits)) == RT_EOK)
- rt_memcpy((void *)&nu_acodec_ops_nau8822.config, (void *)config, sizeof(struct rt_audio_configure)) ;
- }
- return result;
- }
- static rt_err_t nau8822_mixer_control(rt_uint32_t ui32Units, rt_uint32_t ui32Value)
- {
- switch (ui32Units)
- {
- case AUDIO_MIXER_MUTE:
- {
- uint16_t u16Data;
- I2C_ReadNAU8822(10, &u16Data);
- if (ui32Value)
- {
- I2C_WriteNAU8822(10, u16Data | (1 << 6));
- nau8822_phonejack_set(g_psCodecConfig, 0);
- }
- else
- {
- I2C_WriteNAU8822(10, u16Data & ~(1 << 6));
- nau8822_phonejack_set(g_psCodecConfig, 1);
- }
- }
- break;
- case AUDIO_MIXER_VOLUME:
- {
- uint8_t u8GAIN = 256 * ui32Value / 100;
- I2C_WriteNAU8822(11, 0x100 | u8GAIN);
- I2C_WriteNAU8822(12, 0x100 | u8GAIN);
- u8GAIN = 0x3F * ui32Value / 100;
- I2C_WriteNAU8822(54, 0x100 | u8GAIN);
- I2C_WriteNAU8822(55, 0x100 | u8GAIN);
- }
- break;
- case AUDIO_MIXER_QUERY:
- case AUDIO_MIXER_BASS:
- case AUDIO_MIXER_MID:
- case AUDIO_MIXER_TREBLE:
- case AUDIO_MIXER_EQUALIZER:
- case AUDIO_MIXER_LINE:
- case AUDIO_MIXER_DIGITAL:
- case AUDIO_MIXER_MIC:
- case AUDIO_MIXER_VITURAL:
- case AUDIO_MIXER_EXTEND:
- default:
- return -RT_ERROR;
- }
- return RT_EOK;
- }
- static rt_err_t nau8822_mixer_query(rt_uint32_t ui32Units, rt_uint32_t *pui32Value)
- {
- RT_ASSERT(pui32Value != RT_NULL);
- rt_uint16_t u16RV = 0;
- switch (ui32Units)
- {
- case AUDIO_MIXER_QUERY:
- *pui32Value = AUDIO_MIXER_VOLUME | AUDIO_MIXER_MUTE;
- break;
- case AUDIO_MIXER_MUTE:
- I2C_ReadNAU8822(10, (uint16_t *)&u16RV);
- if (u16RV & (1 << 6))
- *pui32Value = 1;
- else
- *pui32Value = 0;
- break;
- case AUDIO_MIXER_VOLUME:
- I2C_ReadNAU8822(11, (uint16_t *)&u16RV);
- *pui32Value = u16RV * 100 / 256;
- break;
- case AUDIO_MIXER_BASS:
- case AUDIO_MIXER_MID:
- case AUDIO_MIXER_TREBLE:
- case AUDIO_MIXER_EQUALIZER:
- case AUDIO_MIXER_LINE:
- case AUDIO_MIXER_DIGITAL:
- case AUDIO_MIXER_MIC:
- case AUDIO_MIXER_VITURAL:
- case AUDIO_MIXER_EXTEND:
- default:
- return -RT_ERROR;
- }
- return RT_EOK;
- }
- int nu_hw_nau8822_init(S_NU_NAU8822_CONFIG *psCodecConfig)
- {
- RT_ASSERT(psCodecConfig != RT_NULL);
- struct rt_i2c_bus_device *psI2cBusDev;
- struct rt_audio_device *psAudioDev;
- nu_i2s_t psNuI2s;
- /* Find I2C bus */
- psI2cBusDev = (struct rt_i2c_bus_device *)rt_device_find(psCodecConfig->i2c_bus_name);
- if (psI2cBusDev == RT_NULL)
- {
- LOG_E("Can't found I2C bus - %s..!\n", psCodecConfig->i2c_bus_name);
- goto exit_rt_hw_nau8822_init;
- }
- /* Find I2S bus */
- psAudioDev = (struct rt_audio_device *)rt_device_find(psCodecConfig->i2s_bus_name);
- if (psAudioDev == RT_NULL)
- {
- LOG_E("Can't found I2S bus - %s ..!\n", psCodecConfig->i2s_bus_name);
- goto exit_rt_hw_nau8822_init;
- }
- if (nau8822_probe() != RT_EOK)
- {
- LOG_E("Can't found audio codec..!\n");
- goto exit_rt_hw_nau8822_init;
- }
- /* Store this board setting. */
- g_psCodecConfig = psCodecConfig;
- g_I2cBusDev = psI2cBusDev;
- /* Get NuI2S device instance. */
- psNuI2s = (nu_i2s_t)psAudioDev;
- /* Register Acodec Ops */
- psNuI2s->AcodecOps = &nu_acodec_ops_nau8822;
- /* Use Acodec default settings. */
- rt_memcpy(&psNuI2s->config, &nu_acodec_ops_nau8822.config, sizeof(struct rt_audio_configure));
- return RT_EOK;
- exit_rt_hw_nau8822_init:
- return -RT_ERROR;
- }
- #endif //#if defined(NU_PKG_USING_NAU8822)
|