From 326261dd7d8ba55cbfe369cf990a7349cd2f7a41 Mon Sep 17 00:00:00 2001 From: Lucas Saavedra Vaz Date: Thu, 16 Mar 2023 22:54:34 -0300 Subject: [PATCH] drivers/audio/es8388: Add input support --- drivers/audio/Kconfig | 53 ++++ drivers/audio/es8388.c | 494 +++++++++++++++++++++++------------- drivers/audio/es8388.h | 8 +- include/nuttx/audio/audio.h | 5 - 4 files changed, 374 insertions(+), 186 deletions(-) diff --git a/drivers/audio/Kconfig b/drivers/audio/Kconfig index 0a4a689619..dd6c628a64 100644 --- a/drivers/audio/Kconfig +++ b/drivers/audio/Kconfig @@ -210,6 +210,7 @@ config AUDIO_ES8388 bool "ES8388 codec chip" default n depends on AUDIO + select AUDIO_DRIVER_SPECIFIC_BUFFERS ---help--- Select to enable support for the ES8388 Audio codec by Everest Semiconductor. @@ -223,10 +224,62 @@ config ES8388_INPUT_INITVOLUME int "ES8388 initial input volume setting" default 1000 +config ES8388_OUTPUT_CHANNEL + int + default 0 if ES8388_OUTPUT_CHANNEL_LINE1 + default 1 if ES8388_OUTPUT_CHANNEL_LINE2 + default 2 if ES8388_OUTPUT_CHANNEL_ALL + +choice + prompt "ES8388 output channel" + default ES8388_OUTPUT_CHANNEL_ALL + ---help--- + Select the codec channel that will output audio. + The actual device that will reproduce the audio signal depends + on the board implementation. + +config ES8388_OUTPUT_CHANNEL_LINE1 + bool "Line 1" + +config ES8388_OUTPUT_CHANNEL_LINE2 + bool "Line 2" + +config ES8388_OUTPUT_CHANNEL_ALL + bool "Both" + +endchoice + config ES8388_OUTPUT_INITVOLUME int "ES8388 initial output volume setting" default 400 +config ES8388_INPUT_CHANNEL + int + default 0 if ES8388_INPUT_CHANNEL_LINE1 + default 1 if ES8388_INPUT_CHANNEL_LINE2 + default 3 if ES8388_INPUT_CHANNEL_DIFFERENTIAL + +choice + prompt "ES8388 input channel" + default ES8388_INPUT_CHANNEL_LINE1 + ---help--- + Select the codec channel that will input audio. + The actual device that will reproduce the audio signal depends + on the board implementation. + The "Differential" option will take the difference between the Line 1 + left and right channels. + +config ES8388_INPUT_CHANNEL_LINE1 + bool "Line 1" + +config ES8388_INPUT_CHANNEL_LINE2 + bool "Line 2" + +config ES8388_INPUT_CHANNEL_DIFFERENTIAL + bool "Differential" + +endchoice + config ES8388_INFLIGHT int "ES8388 maximum in-flight audio buffers" default 2 diff --git a/drivers/audio/es8388.c b/drivers/audio/es8388.c index 7e81eba636..31821cbfa3 100644 --- a/drivers/audio/es8388.c +++ b/drivers/audio/es8388.c @@ -68,10 +68,16 @@ static void es8388_writereg(FAR struct es8388_dev_s *priv, uint16_t regval); #ifndef CONFIG_AUDIO_EXCLUDE_VOLUME static void es8388_setvolume(FAR struct es8388_dev_s *priv, + es8388_module_t module, uint16_t volume); #endif static void es8388_setmclkfrequency(FAR struct es8388_dev_s *priv); -static void es8388_setmute(FAR struct es8388_dev_s *priv, bool enable); +#ifndef CONFIG_AUDIO_EXCLUDE_MUTE +static void es8388_setmute(FAR struct es8388_dev_s *priv, + es8388_module_t module, + bool enable); +#endif +static void es8388_setmicgain(FAR struct es8388_dev_s *priv, uint32_t gain); static void es8388_setbitspersample(FAR struct es8388_dev_s *priv); static void es8388_setsamplerate(FAR struct es8388_dev_s *priv); static int es8388_getcaps(FAR struct audio_lowerhalf_s *dev, @@ -86,12 +92,12 @@ static int es8388_configure(FAR struct audio_lowerhalf_s *dev, FAR const struct audio_caps_s *caps); #endif static int es8388_shutdown(FAR struct audio_lowerhalf_s *dev); -static void es8388_senddone(FAR struct i2s_dev_s *i2s, - FAR struct ap_buffer_s *apb, - FAR void *arg, - int result); +static void es8388_processdone(FAR struct i2s_dev_s *i2s, + FAR struct ap_buffer_s *apb, + FAR void *arg, + int result); static void es8388_returnbuffers(FAR struct es8388_dev_s *priv); -static int es8388_sendbuffer(FAR struct es8388_dev_s *priv); +static int es8388_processbegin(FAR struct es8388_dev_s *priv); #ifdef CONFIG_AUDIO_MULTI_SESSION static int es8388_start(FAR struct audio_lowerhalf_s *dev, FAR void *session); @@ -138,9 +144,7 @@ static int es8388_release(FAR struct audio_lowerhalf_s *dev); #endif static void *es8388_workerthread(pthread_addr_t pvarg); static void es8388_audio_output(FAR struct es8388_dev_s *priv); -#if 0 static void es8388_audio_input(FAR struct es8388_dev_s *priv); -#endif static void es8388_reset(FAR struct es8388_dev_s *priv); /**************************************************************************** @@ -171,6 +175,10 @@ static const struct audio_ops_s g_audioops = es8388_release /* release */ }; +/**************************************************************************** + * Private Functions + ****************************************************************************/ + /**************************************************************************** * Name: es8388_readreg * @@ -232,11 +240,11 @@ uint8_t es8388_readreg(FAR struct es8388_dev_s *priv, uint8_t regaddr) ret = I2C_RESET(priv->i2c); if (ret < 0) { - auderr("ERROR: I2C_RESET failed: %d\n", ret); + auderr("I2C_RESET failed: %d\n", ret); break; } #else - auderr("ERROR: I2C_TRANSFER failed: %d\n", ret); + auderr("I2C_TRANSFER failed: %d\n", ret); #endif } else @@ -313,11 +321,11 @@ static void es8388_writereg(FAR struct es8388_dev_s *priv, ret = I2C_RESET(priv->i2c); if (ret < 0) { - auderr("ERROR: I2C_RESET failed: %d\n", ret); + auderr("I2C_RESET failed: %d\n", ret); break; } #else - auderr("ERROR: I2C_TRANSFER failed: %d\n", ret); + auderr("I2C_TRANSFER failed: %d\n", ret); #endif } else @@ -334,6 +342,43 @@ static void es8388_writereg(FAR struct es8388_dev_s *priv, } } +/**************************************************************************** + * Name: es8388_setmicgain + * + * Description: + * Set the microphone gain. + * + * Input Parameters: + * priv - A reference to the driver state structure. + * gain - The microphone gain to be set in the codec (0..24). + * + * Returned Value: + * None. + * + ****************************************************************************/ + +static void es8388_setmicgain(FAR struct es8388_dev_s *priv, uint32_t gain) +{ + static const es8388_mic_gain_t gain_map[] = + { + ES8388_MIC_GAIN_0DB, + ES8388_MIC_GAIN_3DB, + ES8388_MIC_GAIN_6DB, + ES8388_MIC_GAIN_9DB, + ES8388_MIC_GAIN_12DB, + ES8388_MIC_GAIN_15DB, + ES8388_MIC_GAIN_18DB, + ES8388_MIC_GAIN_21DB, + ES8388_MIC_GAIN_24DB, + }; + + priv->mic_gain = gain_map[MIN(gain, 24) / 3]; + + es8388_writereg(priv, ES8388_ADCCONTROL1, + ES8388_MICAMPR(priv->mic_gain) | + ES8388_MICAMPL(priv->mic_gain)); +} + /**************************************************************************** * Name: es8388_setvolume * @@ -351,7 +396,9 @@ static void es8388_writereg(FAR struct es8388_dev_s *priv, ****************************************************************************/ #ifndef CONFIG_AUDIO_EXCLUDE_VOLUME -static void es8388_setvolume(FAR struct es8388_dev_s *priv, uint16_t volume) +static void es8388_setvolume(FAR struct es8388_dev_s *priv, + es8388_module_t module, + uint16_t volume) { uint16_t leftlvl; int16_t dbleftlvl; @@ -400,16 +447,16 @@ static void es8388_setvolume(FAR struct es8388_dev_s *priv, uint16_t volume) } # else - leftlvl = priv->volume; - rightlvl = priv->volume; + leftlvl = volume; + rightlvl = volume; # endif /* Convert from (0..1000) to (-96..0) */ dbleftlvl = (int16_t) - (leftlvl ? (20 * log10f(rightlvl / AUDIO_VOLUME_MAX_FLOAT)) : -96); + (leftlvl ? (20 * log10f((float)rightlvl / AUDIO_VOLUME_MAX)) : -96); dbrightlvl = (int16_t) - (rightlvl ? (20 * log10f(rightlvl / AUDIO_VOLUME_MAX_FLOAT)) : -96); + (rightlvl ? (20 * log10f((float)rightlvl / AUDIO_VOLUME_MAX)) : -96); audinfo("Volume: dbleftlvl = %d, dbrightlvl = %d\n", dbleftlvl, dbrightlvl); @@ -421,23 +468,19 @@ static void es8388_setvolume(FAR struct es8388_dev_s *priv, uint16_t volume) /* Set the volume */ - if (priv->audio_mode == ES8388_MODULE_DAC || - priv->audio_mode == ES8388_MODULE_ADC_DAC) + if (module == ES8388_MODULE_DAC || module == ES8388_MODULE_ADC_DAC) { es8388_writereg(priv, ES8388_DACCONTROL4, ES8388_LDACVOL(dbleftlvl)); es8388_writereg(priv, ES8388_DACCONTROL5, ES8388_RDACVOL(dbrightlvl)); + priv->volume_out = volume; } - if (priv->audio_mode == ES8388_MODULE_ADC || - priv->audio_mode == ES8388_MODULE_ADC_DAC) + if (module == ES8388_MODULE_ADC || module == ES8388_MODULE_ADC_DAC) { es8388_writereg(priv, ES8388_ADCCONTROL8, ES8388_LADCVOL(dbleftlvl)); es8388_writereg(priv, ES8388_ADCCONTROL9, ES8388_RADCVOL(dbrightlvl)); + priv->volume_in = volume; } - - /* Remember the volume level and mute settings */ - - priv->volume = volume; } #endif /* CONFIG_AUDIO_EXCLUDE_VOLUME */ @@ -490,18 +533,18 @@ static void es8388_setmclkfrequency(FAR struct es8388_dev_s *priv) { if (ret != -ENOTTY) { - auderr("ERROR: Failed to set the MCLK on lower half\n"); + auderr("Failed to set the MCLK on lower half\n"); } else { priv->mclk = 0; - auderr("WARNING: MCLK cannot be set on lower half\n"); + auderr("MCLK cannot be set on lower half\n"); } } } else { - auderr("ERROR: Unsupported combination of sample rate and" + auderr("Unsupported combination of sample rate and" " data width\n"); } } @@ -521,16 +564,18 @@ static void es8388_setmclkfrequency(FAR struct es8388_dev_s *priv) * ****************************************************************************/ -static void es8388_setmute(FAR struct es8388_dev_s *priv, bool enable) +#ifndef CONFIG_AUDIO_EXCLUDE_MUTE +static void es8388_setmute(FAR struct es8388_dev_s *priv, + es8388_module_t module, + bool enable) { uint8_t reg = 0; - audinfo("Volume: mute=%d\n", (int)enable); + audinfo("module=%d, mute=%d\n", module, (int)enable); priv->mute = enable; - if (priv->audio_mode == ES8388_MODULE_DAC || - priv->audio_mode == ES8388_MODULE_ADC_DAC) + if (module == ES8388_MODULE_DAC || module == ES8388_MODULE_ADC_DAC) { reg = es8388_readreg(priv, ES8388_DACCONTROL3) & (~ES8388_DACMUTE_BITMASK); @@ -538,8 +583,7 @@ static void es8388_setmute(FAR struct es8388_dev_s *priv, bool enable) reg | ES8388_DACMUTE(enable)); } - if (priv->audio_mode == ES8388_MODULE_ADC || - priv->audio_mode == ES8388_MODULE_ADC_DAC) + if (module == ES8388_MODULE_ADC || module == ES8388_MODULE_ADC_DAC) { reg = es8388_readreg(priv, ES8388_ADCCONTROL7) & (~ES8388_ADCMUTE_BITMASK); @@ -547,6 +591,7 @@ static void es8388_setmute(FAR struct es8388_dev_s *priv, bool enable) reg | ES8388_ADCMUTE(enable)); } } +#endif /**************************************************************************** * Name: es8388_setbitspersample @@ -592,7 +637,7 @@ static void es8388_setbitspersample(FAR struct es8388_dev_s *priv) break; default: - audwarn("ERROR: Data length not supported.\n"); + audwarn("Data length not supported.\n"); return; } @@ -675,7 +720,7 @@ static void es8388_setsamplerate(FAR struct es8388_dev_s *priv) break; default: - audwarn("ERROR: Sample rate not supported.\n"); + audwarn("Sample rate not supported.\n"); return; } @@ -746,22 +791,17 @@ static int es8388_getcaps(FAR struct audio_lowerhalf_s *dev, int type, { case AUDIO_TYPE_QUERY: - /* We don't decode any formats! Only something above us in - * the audio stream can perform decoding on our behalf. - */ + /* The input formats we can decode / accept */ + +#ifdef CONFIG_AUDIO_FORMAT_PCM + caps->ac_format.hw |= (1 << (AUDIO_FMT_PCM - 1)); +#endif /* The types of audio units we implement */ - caps->ac_controls.b[0] = - AUDIO_TYPE_OUTPUT | AUDIO_TYPE_FEATURE | - AUDIO_TYPE_PROCESSING; - break; - - case AUDIO_FMT_MIDI: - - /* We only support Format 0 */ - - caps->ac_controls.b[0] = AUDIO_SUBFMT_END; + caps->ac_controls.b[0] = AUDIO_TYPE_INPUT | + AUDIO_TYPE_OUTPUT | + AUDIO_TYPE_FEATURE; break; default: @@ -789,11 +829,7 @@ static int es8388_getcaps(FAR struct audio_lowerhalf_s *dev, int type, AUDIO_SAMP_RATE_11K | AUDIO_SAMP_RATE_16K | AUDIO_SAMP_RATE_22K | AUDIO_SAMP_RATE_32K | AUDIO_SAMP_RATE_44K | AUDIO_SAMP_RATE_48K; - break; - - case AUDIO_FMT_MP3: - case AUDIO_FMT_WMA: - case AUDIO_FMT_PCM: + caps->ac_controls.b[1] = 0; break; default: @@ -802,6 +838,28 @@ static int es8388_getcaps(FAR struct audio_lowerhalf_s *dev, int type, break; + case AUDIO_TYPE_INPUT: + + caps->ac_channels = 2; + + switch (caps->ac_subtype) + { + case AUDIO_TYPE_QUERY: + + /* Report supported input sample rates */ + + caps->ac_controls.b[0] = + AUDIO_SAMP_RATE_11K | AUDIO_SAMP_RATE_16K | + AUDIO_SAMP_RATE_22K | AUDIO_SAMP_RATE_32K | + AUDIO_SAMP_RATE_44K | AUDIO_SAMP_RATE_48K; + caps->ac_controls.b[1] = 0; + break; + + default: + break; + } + break; + /* Provide capabilities of our FEATURE units */ case AUDIO_TYPE_FEATURE: @@ -816,41 +874,13 @@ static int es8388_getcaps(FAR struct audio_lowerhalf_s *dev, int type, * have. */ - caps->ac_controls.b[0] = AUDIO_FU_VOLUME; - caps->ac_controls.b[1] = AUDIO_FU_BALANCE >> 8; + caps->ac_controls.b[0] = AUDIO_FU_VOLUME | AUDIO_FU_MUTE; + caps->ac_controls.b[1] = (AUDIO_FU_BALANCE | + AUDIO_FU_INP_GAIN) >> 8; } break; - /* Provide capabilities of our PROCESSING unit */ - - case AUDIO_TYPE_PROCESSING: - - switch (caps->ac_subtype) - { - case AUDIO_PU_UNDEF: - - /* Provide the type of Processing Units we support */ - - caps->ac_controls.b[0] = AUDIO_PU_STEREO_EXTENDER; - break; - - case AUDIO_PU_STEREO_EXTENDER: - - /* Provide capabilities of our Stereo Extender */ - - caps->ac_controls.b[0] = - AUDIO_STEXT_ENABLE | AUDIO_STEXT_WIDTH; - break; - - default: - - /* Other types of processing uint we don't support */ - - break; - } - break; - /* All others we don't support */ default: @@ -922,7 +952,7 @@ static int es8388_configure(FAR struct audio_lowerhalf_s *dev, if (volume >= 0 && volume <= 1000) { - es8388_setvolume(priv, volume); + es8388_setvolume(priv, priv->audio_mode, volume); } else { @@ -932,6 +962,19 @@ static int es8388_configure(FAR struct audio_lowerhalf_s *dev, break; #endif /* CONFIG_AUDIO_EXCLUDE_VOLUME */ +#ifndef CONFIG_AUDIO_EXCLUDE_MUTE + case AUDIO_FU_MUTE: + { + /* Mute/Unmute */ + + bool mute = (bool)caps->ac_controls.hw[0]; + audinfo(" Mute: %d\n", mute); + + es8388_setmute(priv, ES8388_MODULE_DAC, mute); + } + break; +#endif /* CONFIG_AUDIO_EXCLUDE_MUTE */ + #ifndef CONFIG_AUDIO_EXCLUDE_BALANCE case AUDIO_FU_BALANCE: { @@ -942,7 +985,7 @@ static int es8388_configure(FAR struct audio_lowerhalf_s *dev, if (balance >= 0 && balance <= 1000) { priv->balance = balance; - es8388_setvolume(priv, priv->volume); + es8388_setvolume(priv, priv->audio_mode, priv->volume_out); } else { @@ -952,8 +995,19 @@ static int es8388_configure(FAR struct audio_lowerhalf_s *dev, break; #endif /* CONFIG_AUDIO_EXCLUDE_VOLUME */ + case AUDIO_FU_INP_GAIN: + { + /* Set the mic gain */ + + uint32_t mic_gain = caps->ac_controls.hw[0]; + audinfo(" Mic gain: %" PRIu32 "\n", mic_gain); + + es8388_setmicgain(priv, mic_gain); + } + break; + default: - auderr(" ERROR: Unrecognized feature unit\n"); + auderr(" Unrecognized feature unit\n"); ret = -ENOTTY; break; } @@ -971,7 +1025,7 @@ static int es8388_configure(FAR struct audio_lowerhalf_s *dev, ret = -ERANGE; if (caps->ac_channels != 1 && caps->ac_channels != 2) { - auderr("ERROR: Unsupported number of channels: %d\n", + auderr("Unsupported number of channels: %d\n", caps->ac_channels); break; } @@ -982,7 +1036,7 @@ static int es8388_configure(FAR struct audio_lowerhalf_s *dev, caps->ac_controls.b[2] != 24 && caps->ac_controls.b[2] != 32) { - auderr("ERROR: Unsupported bits per sample: %d\n", + auderr("Unsupported bits per sample: %d\n", caps->ac_controls.b[2]); break; } @@ -993,6 +1047,51 @@ static int es8388_configure(FAR struct audio_lowerhalf_s *dev, priv->nchannels = caps->ac_channels; priv->bpsamp = caps->ac_controls.b[2]; + es8388_audio_output(priv); + es8388_reset(priv); + es8388_setsamplerate(priv); + es8388_setbitspersample(priv); + + ret = OK; + } + break; + + case AUDIO_TYPE_INPUT: + { + audinfo(" AUDIO_TYPE_INPUT:\n"); + audinfo(" Number of channels: %u\n", caps->ac_channels); + audinfo(" Sample rate: %u\n", caps->ac_controls.hw[0]); + audinfo(" Sample width: %u\n", caps->ac_controls.b[2]); + + /* Verify that all of the requested values are supported */ + + ret = -ERANGE; + if (caps->ac_channels != 1 && caps->ac_channels != 2) + { + auderr("Unsupported number of channels: %d\n", + caps->ac_channels); + break; + } + + if (caps->ac_controls.b[2] != 16 && + caps->ac_controls.b[2] != 18 && + caps->ac_controls.b[2] != 20 && + caps->ac_controls.b[2] != 24 && + caps->ac_controls.b[2] != 32) + { + auderr("Unsupported bits per sample: %d\n", + caps->ac_controls.b[2]); + break; + } + + /* Save the current stream configuration */ + + priv->samprate = caps->ac_controls.hw[0]; + priv->nchannels = caps->ac_channels; + priv->bpsamp = caps->ac_controls.b[2]; + + es8388_audio_input(priv); + es8388_reset(priv); es8388_setsamplerate(priv); es8388_setbitspersample(priv); @@ -1038,7 +1137,7 @@ static int es8388_shutdown(FAR struct audio_lowerhalf_s *dev) } /**************************************************************************** - * Name: es8388_senddone + * Name: es8388_processdone * * Description: * This is the I2S callback function that is invoked when the transfer @@ -1055,9 +1154,10 @@ static int es8388_shutdown(FAR struct audio_lowerhalf_s *dev) * ****************************************************************************/ -static void es8388_senddone(FAR struct i2s_dev_s *i2s, - FAR struct ap_buffer_s *apb, FAR void *arg, - int result) +static void es8388_processdone(FAR struct i2s_dev_s *i2s, + FAR struct ap_buffer_s *apb, + FAR void *arg, + int result) { FAR struct es8388_dev_s *priv = (FAR struct es8388_dev_s *)arg; struct audio_msg_s msg; @@ -1065,7 +1165,7 @@ static void es8388_senddone(FAR struct i2s_dev_s *i2s, int ret; DEBUGASSERT(i2s && priv && priv->running && apb); - audinfo("senddone: apb=%p inflight=%d result=%d\n", + audinfo("Transfer done: apb=%p inflight=%d result=%d\n", apb, priv->inflight, result); /* We do not place any restriction on the context in which this function @@ -1102,7 +1202,7 @@ static void es8388_senddone(FAR struct i2s_dev_s *i2s, CONFIG_ES8388_MSG_PRIO); if (ret < 0) { - auderr("ERROR: file_mq_send failed: %d\n", ret); + auderr("file_mq_send failed: %d\n", ret); } } @@ -1180,12 +1280,12 @@ static void es8388_returnbuffers(FAR struct es8388_dev_s *priv) } /**************************************************************************** - * Name: es8388_sendbuffer + * Name: es8388_processbegin * * Description: * Start the transfer an audio buffer to the ES8388 via I2S. This * will not wait for the transfer to complete but will return immediately. - * the es8388_senddone called will be invoked when the transfer + * the es8388_processdone called will be invoked when the transfer * completes, stimulating the worker thread to call this function again. * * Input Parameters: @@ -1196,7 +1296,7 @@ static void es8388_returnbuffers(FAR struct es8388_dev_s *priv) * ****************************************************************************/ -static int es8388_sendbuffer(FAR struct es8388_dev_s *priv) +static int es8388_processbegin(FAR struct es8388_dev_s *priv) { FAR struct ap_buffer_s *apb; irqstate_t flags; @@ -1228,7 +1328,7 @@ static int es8388_sendbuffer(FAR struct es8388_dev_s *priv) /* Take next buffer from the queue of pending transfers */ apb = (FAR struct ap_buffer_s *)dq_remfirst(&priv->pendq); - audinfo("Sending apb=%p, size=%d inflight=%d\n", + audinfo("Transferring apb=%p, size=%d inflight=%d\n", apb, apb->nbytes, priv->inflight); /* Increment the number of buffers in-flight before sending in order @@ -1243,7 +1343,7 @@ static int es8388_sendbuffer(FAR struct es8388_dev_s *priv) * to use? This would depend on the bit rate and size of the buffer. * * Samples in the buffer (samples): - * = buffer_size * 8 / bpsamp samples + * = buffer_size * 8 / bpsamp * Sample rate (samples/second): * = samplerate * nchannels * Expected transfer time (seconds): @@ -1268,10 +1368,20 @@ static int es8388_sendbuffer(FAR struct es8388_dev_s *priv) timeout = MSEC2TICK(((uint32_t)(apb->nbytes - apb->curbyte) << shift) / (uint32_t)priv->samprate / (uint32_t)priv->bpsamp); - ret = I2S_SEND(priv->i2s, apb, es8388_senddone, priv, timeout); + if (priv->audio_mode == ES8388_MODULE_DAC) + { + ret = I2S_SEND(priv->i2s, apb, es8388_processdone, + priv, timeout); + } + else + { + ret = I2S_RECEIVE(priv->i2s, apb, es8388_processdone, + priv, timeout); + } + if (ret < 0) { - auderr("ERROR: I2S_SEND failed: %d\n", ret); + auderr("I2S transfer failed: %d\n", ret); break; } } @@ -1317,25 +1427,26 @@ static int es8388_start(FAR struct audio_lowerhalf_s *dev) if (priv->audio_mode == ES8388_MODULE_LINE) { es8388_writereg(priv, ES8388_DACCONTROL16, - ES8388_RMIXSEL_RIN2 | ES8388_LMIXSEL_LIN2); + ES8388_RMIXSEL_RIN2 | + ES8388_LMIXSEL_LIN2); es8388_writereg(priv, ES8388_DACCONTROL17, - ES8388_LI2LO_ENABLE | - ES8388_LD2LO_DISABLE | - ES8388_LI2LOVOL(ES8388_MIXER_GAIN_0DB)); + ES8388_LI2LOVOL(ES8388_MIXER_GAIN_0DB) | + ES8388_LI2LO_ENABLE | + ES8388_LD2LO_DISABLE); es8388_writereg(priv, ES8388_DACCONTROL20, - ES8388_RI2RO_ENABLE | - ES8388_RD2RO_DISABLE | - ES8388_RI2ROVOL(ES8388_MIXER_GAIN_0DB)); + ES8388_RI2ROVOL(ES8388_MIXER_GAIN_0DB) | + ES8388_RI2RO_ENABLE | + ES8388_RD2RO_DISABLE); es8388_writereg(priv, ES8388_DACCONTROL21, ES8388_DAC_DLL_PWD_NORMAL | ES8388_ADC_DLL_PWD_NORMAL | ES8388_MCLK_DIS_NORMAL | ES8388_OFFSET_DIS_DISABLE | - ES8388_SLRCK_SAME | - ES8388_LRCK_SEL_ADC); + ES8388_LRCK_SEL_ADC | + ES8388_SLRCK_SAME); } else { @@ -1344,8 +1455,8 @@ static int es8388_start(FAR struct audio_lowerhalf_s *dev) ES8388_ADC_DLL_PWD_NORMAL | ES8388_MCLK_DIS_NORMAL | ES8388_OFFSET_DIS_DISABLE | - ES8388_SLRCK_SAME | - ES8388_LRCK_SEL_DAC); + ES8388_LRCK_SEL_DAC | + ES8388_SLRCK_SAME); } regval = es8388_readreg(priv, ES8388_DACCONTROL21); @@ -1399,10 +1510,12 @@ static int es8388_start(FAR struct audio_lowerhalf_s *dev) ES8388_LOUT1_ENABLE | ES8388_PDNDACR_PWRUP | ES8388_PDNDACL_PWRUP); - - es8388_setmute(priv, false); } +#ifndef CONFIG_AUDIO_EXCLUDE_MUTE + es8388_setmute(priv, priv->audio_mode, false); +#endif + /* Create a message queue for the worker thread */ snprintf(priv->mqname, sizeof(priv->mqname), "/regconfig/%" PRIXPTR, @@ -1419,7 +1532,7 @@ static int es8388_start(FAR struct audio_lowerhalf_s *dev) { /* Error creating message queue! */ - auderr("ERROR: Couldn't allocate message queue\n"); + auderr("Couldn't allocate message queue\n"); return ret; } @@ -1431,7 +1544,7 @@ static int es8388_start(FAR struct audio_lowerhalf_s *dev) pthread_join(priv->threadid, &value); } - /* Start our thread for sending data to the device */ + /* Start our thread for processing device data */ pthread_attr_init(&tattr); sparam.sched_priority = sched_get_priority_max(SCHED_FIFO) - 3; @@ -1443,7 +1556,7 @@ static int es8388_start(FAR struct audio_lowerhalf_s *dev) (pthread_addr_t)priv); if (ret != OK) { - auderr("ERROR: pthread_create failed: %d\n", ret); + auderr("pthread_create failed: %d\n", ret); } else { @@ -1489,21 +1602,22 @@ static int es8388_stop(FAR struct audio_lowerhalf_s *dev) ES8388_ADC_DLL_PWD_NORMAL | ES8388_MCLK_DIS_NORMAL | ES8388_OFFSET_DIS_DISABLE | - ES8388_SLRCK_SAME | - ES8388_LRCK_SEL_DAC); + ES8388_LRCK_SEL_DAC | + ES8388_SLRCK_SAME); es8388_writereg(priv, ES8388_DACCONTROL16, - ES8388_RMIXSEL_RIN1 | ES8388_LMIXSEL_LIN1); + ES8388_RMIXSEL_RIN1 | + ES8388_LMIXSEL_LIN1); es8388_writereg(priv, ES8388_DACCONTROL17, - ES8388_LD2LO_ENABLE | - ES8388_LI2LO_DISABLE | - ES8388_LI2LOVOL(ES8388_MIXER_GAIN_0DB)); + ES8388_LI2LOVOL(ES8388_MIXER_GAIN_0DB) | + ES8388_LI2LO_DISABLE | + ES8388_LD2LO_ENABLE); es8388_writereg(priv, ES8388_DACCONTROL20, - ES8388_RD2RO_ENABLE | - ES8388_RI2RO_DISABLE | - ES8388_RI2ROVOL(ES8388_MIXER_GAIN_0DB)); + ES8388_RI2ROVOL(ES8388_MIXER_GAIN_0DB) | + ES8388_RI2RO_DISABLE | + ES8388_RD2RO_ENABLE); goto stop_msg; } @@ -1518,8 +1632,6 @@ static int es8388_stop(FAR struct audio_lowerhalf_s *dev) ES8388_LOUT1_DISABLE | ES8388_PDNDACR_PWRUP | ES8388_PDNDACL_PWRUP); - - es8388_setmute(priv, true); } if (priv->audio_mode == ES8388_MODULE_ADC || @@ -1549,6 +1661,10 @@ static int es8388_stop(FAR struct audio_lowerhalf_s *dev) stop_msg: +#ifndef CONFIG_AUDIO_EXCLUDE_MUTE + es8388_setmute(priv, priv->audio_mode, true); +#endif + /* Send a message to stop all audio streaming */ term_msg.msg_id = AUDIO_MSG_STOP; @@ -1595,7 +1711,9 @@ static int es8388_pause(FAR struct audio_lowerhalf_s *dev) if (priv->running && !priv->paused) { priv->paused = true; - es8388_setmute(priv, true); +#ifndef CONFIG_AUDIO_EXCLUDE_MUTE + es8388_setmute(priv, priv->audio_mode, true); +#endif } return OK; @@ -1631,8 +1749,10 @@ static int es8388_resume(FAR struct audio_lowerhalf_s *dev) if (priv->running && priv->paused) { priv->paused = false; - es8388_setmute(priv, false); - es8388_sendbuffer(priv); +#ifndef CONFIG_AUDIO_EXCLUDE_MUTE + es8388_setmute(priv, priv->audio_mode, false); +#endif + es8388_processbegin(priv); } return OK; @@ -1642,7 +1762,8 @@ static int es8388_resume(FAR struct audio_lowerhalf_s *dev) /**************************************************************************** * Name: es8388_enqueuebuffer * - * Description: Enqueue an Audio Pipeline Buffer for playback/ processing. + * Description: + * Enqueue an Audio Pipeline Buffer for processing. * * Input Parameters: * dev - A reference to the lower half state structure. @@ -1675,7 +1796,6 @@ static int es8388_enqueuebuffer(FAR struct audio_lowerhalf_s *dev, /* Add the new buffer to the tail of pending audio buffers */ - apb->flags |= AUDIO_APB_OUTPUT_ENQUEUED; dq_addlast(&apb->dq_entry, &priv->pendq); nxmutex_unlock(&priv->pendlock); @@ -1695,7 +1815,7 @@ static int es8388_enqueuebuffer(FAR struct audio_lowerhalf_s *dev, sizeof(term_msg), CONFIG_ES8388_MSG_PRIO); if (ret < 0) { - auderr("ERROR: file_mq_send failed: %d\n", ret); + auderr("file_mq_send failed: %d\n", ret); } } @@ -1750,7 +1870,7 @@ static int es8388_ioctl(FAR struct audio_lowerhalf_s *dev, int cmd, switch (cmd) { - /* Report our preferred buffer size and quantity */ + /* Report our preferred buffer size and quantity */ #ifdef CONFIG_AUDIO_DRIVER_SPECIFIC_BUFFERS case AUDIOIOC_GETBUFFERINFO: @@ -1765,7 +1885,7 @@ static int es8388_ioctl(FAR struct audio_lowerhalf_s *dev, int cmd, default: ret = -ENOTTY; - audwarn("IOCTL not available\n"); + audinfo("Unhandled ioctl: %d\n", cmd); break; } @@ -1914,8 +2034,6 @@ static void es8388_audio_output(FAR struct es8388_dev_s *priv) * ****************************************************************************/ -#if 0 - static void es8388_audio_input(FAR struct es8388_dev_s *priv) { audinfo("ES8388 set to input mode\n"); @@ -1923,8 +2041,6 @@ static void es8388_audio_input(FAR struct es8388_dev_s *priv) priv->audio_mode = ES8388_MODULE_ADC; } -#endif - /**************************************************************************** * Name: es8388_workerthread * @@ -1974,9 +2090,9 @@ static void *es8388_workerthread(pthread_addr_t pvarg) } else { - /* Check if we can send more audio buffers to the ES8388 */ + /* Check if we can process more audio buffers */ - es8388_sendbuffer(priv); + es8388_processbegin(priv); } /* Wait for messages from our message queue */ @@ -1988,7 +2104,7 @@ static void *es8388_workerthread(pthread_addr_t pvarg) if (msglen < sizeof(struct audio_msg_s)) { - auderr("ERROR: Message too small: %d\n", msglen); + auderr("Message too small: %d\n", msglen); continue; } @@ -2016,7 +2132,7 @@ static void *es8388_workerthread(pthread_addr_t pvarg) break; #endif - /* We have a new buffer to send. We will catch this case at + /* We have a new buffer to process. We will catch this case at * the top of the loop. */ @@ -2032,7 +2148,7 @@ static void *es8388_workerthread(pthread_addr_t pvarg) break; default: - auderr("ERROR: Ignoring message ID %d\n", msg.msg_id); + auderr("Ignoring message ID %d\n", msg.msg_id); break; } } @@ -2098,12 +2214,12 @@ static void *es8388_workerthread(pthread_addr_t pvarg) static void es8388_reset(FAR struct es8388_dev_s *priv) { - /* Put audio output back to its initial configuration */ + /* Put audio back to its initial configuration */ - audinfo("ES8388 Reset\n"); + audinfo("ES8388 reset triggered.\n"); - priv->dac_output = ES8388_DAC_OUTPUT_ALL; - priv->adc_input = ES8388_ADC_INPUT_ALL; + priv->dac_output = CONFIG_ES8388_OUTPUT_CHANNEL; + priv->adc_input = CONFIG_ES8388_INPUT_CHANNEL; priv->samprate = ES8388_DEFAULT_SAMPRATE; priv->nchannels = ES8388_DEFAULT_NCHANNELS; priv->bpsamp = ES8388_DEFAULT_BPSAMP; @@ -2117,8 +2233,6 @@ static void es8388_reset(FAR struct es8388_dev_s *priv) uint8_t regconfig; - es8388_audio_output(priv); - es8388_writereg(priv, ES8388_DACCONTROL3, ES8388_DACMUTE_MUTED | ES8388_DACLER_NORMAL | @@ -2135,7 +2249,7 @@ static void es8388_reset(FAR struct es8388_dev_s *priv) (1 << 6)); /* Default value of undocumented bit */ es8388_writereg(priv, ES8388_CHIPPOWER, - ES8388_DACVREF_PDN_SHIFT | + ES8388_DACVREF_PDN_PWRUP | ES8388_ADCVREF_PDN_PWRUP | ES8388_DACDLL_PDN_NORMAL | ES8388_ADCDLL_PDN_NORMAL | @@ -2144,6 +2258,12 @@ static void es8388_reset(FAR struct es8388_dev_s *priv) ES8388_DAC_DIGPDN_NORMAL | ES8388_ADC_DIGPDN_NORMAL); + /* Disable the internal DLL to improve 8K sample rate */ + + es8388_writereg(priv, 0x35, 0xa0); + es8388_writereg(priv, 0x37, 0xd0); + es8388_writereg(priv, 0x39, 0xd0); + es8388_writereg(priv, ES8388_MASTERMODE, ES8388_BCLKDIV(ES8388_MCLK_DIV_AUTO) | ES8388_BCLK_INV_NORMAL | @@ -2158,6 +2278,15 @@ static void es8388_reset(FAR struct es8388_dev_s *priv) ES8388_PDNDACR_PWRDN | ES8388_PDNDACL_PWRDN); + es8388_writereg(priv, ES8388_CONTROL1, + ES8388_VMIDSEL_500K | + ES8388_ENREF_DISABLE | + ES8388_SEQEN_DISABLE | + ES8388_SAMEFS_SAME | + ES8388_DACMCLK_ADCMCLK | + ES8388_LRCM_ISOLATED | + ES8388_SCPRESET_NORMAL); + es8388_writereg(priv, ES8388_DACCONTROL1, ES8388_DACFORMAT(ES8388_I2S_NORMAL) | ES8388_DACWL(ES8388_WORD_LENGTH_16BITS) | @@ -2172,22 +2301,22 @@ static void es8388_reset(FAR struct es8388_dev_s *priv) ES8388_RMIXSEL_RIN1 | ES8388_LMIXSEL_LIN1); es8388_writereg(priv, ES8388_DACCONTROL17, - ES8388_LD2LO_ENABLE | - ES8388_LI2LO_DISABLE | - ES8388_LI2LOVOL(ES8388_MIXER_GAIN_0DB)); + ES8388_LI2LOVOL(ES8388_MIXER_GAIN_0DB) | + ES8388_LI2LO_DISABLE | + ES8388_LD2LO_ENABLE); es8388_writereg(priv, ES8388_DACCONTROL20, - ES8388_RD2RO_ENABLE | - ES8388_RI2RO_DISABLE | - ES8388_RI2ROVOL(ES8388_MIXER_GAIN_0DB)); + ES8388_RI2ROVOL(ES8388_MIXER_GAIN_0DB) | + ES8388_RI2RO_DISABLE | + ES8388_RD2RO_ENABLE); es8388_writereg(priv, ES8388_DACCONTROL21, ES8388_DAC_DLL_PWD_NORMAL | ES8388_ADC_DLL_PWD_NORMAL | ES8388_MCLK_DIS_NORMAL | ES8388_OFFSET_DIS_DISABLE | - ES8388_SLRCK_SAME | - ES8388_LRCK_SEL_DAC); + ES8388_LRCK_SEL_DAC | + ES8388_SLRCK_SAME); es8388_writereg(priv, ES8388_DACCONTROL23, ES8388_VROI_1_5K); @@ -2203,9 +2332,13 @@ static void es8388_reset(FAR struct es8388_dev_s *priv) es8388_writereg(priv, ES8388_DACCONTROL27, ES8388_ROUT2VOL(ES8388_DAC_CHVOL_DB(0))); - es8388_setmute(priv, true); +#ifndef CONFIG_AUDIO_EXCLUDE_MUTE + es8388_setmute(priv, ES8388_MODULE_DAC, true); +#endif - regconfig = 0; +#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME + es8388_setvolume(priv, ES8388_MODULE_DAC, CONFIG_ES8388_OUTPUT_INITVOLUME); +#endif if (priv->dac_output == ES8388_DAC_OUTPUT_LINE2) { @@ -2233,11 +2366,7 @@ static void es8388_reset(FAR struct es8388_dev_s *priv) ES8388_PDNAINR_PWRDN | ES8388_PDNAINL_PWRDN); - es8388_writereg(priv, ES8388_ADCCONTROL1, - ES8388_MICAMPR(ES8388_MIC_GAIN_0DB) | - ES8388_MICAMPL(ES8388_MIC_GAIN_0DB)); - - regconfig = 0; + es8388_setmicgain(priv, 24); /* +24 dB */ if (priv->adc_input == ES8388_ADC_INPUT_LINE1) { @@ -2255,10 +2384,10 @@ static void es8388_reset(FAR struct es8388_dev_s *priv) es8388_writereg(priv, ES8388_ADCCONTROL2, regconfig); es8388_writereg(priv, ES8388_ADCCONTROL3, - ES8388_TRI_NORMAL | - ES8388_MONOMIX_STEREO | - ES8388_DS_LINPUT1_RINPUT1 | - (1 << 1)); /* Default value of undocumented bit */ + (1 << 1) | /* Default value of undocumented bit */ + ES8388_TRI_NORMAL | + ES8388_MONOMIX_STEREO | + ES8388_DS_LINPUT1_RINPUT1); es8388_writereg(priv, ES8388_ADCCONTROL4, ES8388_ADCFORMAT(ES8388_I2S_NORMAL) | @@ -2270,6 +2399,14 @@ static void es8388_reset(FAR struct es8388_dev_s *priv) ES8388_ADCFSRATIO(ES8388_LCLK_DIV_256) | ES8388_ADCFSMODE_SINGLE); +#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME + es8388_setvolume(priv, ES8388_MODULE_ADC, CONFIG_ES8388_INPUT_INITVOLUME); +#endif + +#ifndef CONFIG_AUDIO_EXCLUDE_MUTE + es8388_setmute(priv, ES8388_MODULE_ADC, true); +#endif + es8388_writereg(priv, ES8388_ADCPOWER, ES8388_INT1LP_LP | ES8388_FLASHLP_NORMAL | @@ -2318,8 +2455,6 @@ static void es8388_reset(FAR struct es8388_dev_s *priv) ES8388_LOUT1_DISABLE | ES8388_PDNDACR_PWRUP | ES8388_PDNDACL_PWRUP); - - es8388_setmute(priv, true); } if (priv->audio_mode == ES8388_MODULE_ADC || @@ -2350,7 +2485,11 @@ static void es8388_reset(FAR struct es8388_dev_s *priv) reset_finish: #ifndef CONFIG_AUDIO_EXCLUDE_VOLUME - es8388_setvolume(priv, CONFIG_ES8388_OUTPUT_INITVOLUME); + es8388_setvolume(priv, ES8388_MODULE_DAC, CONFIG_ES8388_OUTPUT_INITVOLUME); +#endif + +#ifndef CONFIG_AUDIO_EXCLUDE_MUTE + es8388_setmute(priv, ES8388_MODULE_DAC, true); #endif es8388_dump_registers(&priv->dev, "After reset"); @@ -2412,11 +2551,10 @@ FAR struct audio_lowerhalf_s * es8388_dump_registers(&priv->dev, "Before reset"); + es8388_audio_output(priv); es8388_reset(priv); return &priv->dev; } - nxmutex_destroy(&priv->pendlock); - kmm_free(priv); return NULL; } diff --git a/drivers/audio/es8388.h b/drivers/audio/es8388.h index 17b4c68e55..4577bba118 100644 --- a/drivers/audio/es8388.h +++ b/drivers/audio/es8388.h @@ -1072,10 +1072,10 @@ struct es8388_dev_s FAR const struct es8388_lower_s *lower; /* Pointer to the board lower functions */ FAR struct i2c_master_s *i2c; /* I2C driver to use */ FAR struct i2s_dev_s *i2s; /* I2S driver to use */ - struct dq_queue_s pendq; /* Queue of pending buffers to be sent */ + struct dq_queue_s pendq; /* Queue of pending buffers to be processed */ struct dq_queue_s doneq; /* Queue of sent buffers to be returned */ struct file mq; /* Message queue for receiving messages */ - char mqname[16]; /* Our message queue name */ + char mqname[NAME_MAX]; /* Our message queue name */ pthread_t threadid; /* ID of our thread */ uint32_t bitrate; /* Actual programmed bit rate */ mutex_t pendlock; /* Protect pendq */ @@ -1084,7 +1084,8 @@ struct es8388_dev_s #ifndef CONFIG_AUDIO_EXCLUDE_BALANCE uint16_t balance; /* Current balance level {0..1000} */ #endif /* CONFIG_AUDIO_EXCLUDE_BALANCE */ - uint16_t volume; /* Current volume level {0..1000} */ + uint16_t volume_out; /* Current output volume level {0..1000} */ + uint16_t volume_in; /* Current input volume level {0..1000} */ #endif /* CONFIG_AUDIO_EXCLUDE_VOLUME */ uint8_t nchannels; /* Number of channels (1 or 2) */ uint8_t bpsamp; /* Bits per sample */ @@ -1100,6 +1101,7 @@ struct es8388_dev_s es8388_module_t audio_mode; /* The current audio mode of the ES8388 chip */ es8388_dac_output_t dac_output; /* The current output of the ES8388 DAC */ es8388_adc_input_t adc_input; /* The current input of the ES8388 ADC */ + es8388_mic_gain_t mic_gain; /* The current microphone gain */ uint32_t mclk; /* The current MCLK frequency */ }; diff --git a/include/nuttx/audio/audio.h b/include/nuttx/audio/audio.h index eaf5d8b888..e4d9f5f4c2 100644 --- a/include/nuttx/audio/audio.h +++ b/include/nuttx/audio/audio.h @@ -240,9 +240,7 @@ */ #define AUDIO_VOLUME_MAX 1000 -#define AUDIO_VOLUME_MAX_FLOAT 1000.0f #define AUDIO_VOLUME_MIN 0 -#define AUDIO_VOLUME_MIN_FLOAT 0.0f /* Audio Balance Limits *****************************************************/ @@ -252,11 +250,8 @@ */ #define AUDIO_BALANCE_RIGHT 1000 -#define AUDIO_BALANCE_RIGHT_FLOAT 1000.0f #define AUDIO_BALANCE_CENTER 500 -#define AUDIO_BALANCE_CENTER_FLOAT 500.0f #define AUDIO_BALANCE_LEFT 0 -#define AUDIO_BALANCE_LEFT_FLOAT 0.0f /* Supported Feature Units controls *****************************************/