Merged in masayuki2009/nuttx.nuttx/lc823450_i2s_tx_threshold (pull request #667)

arch/arm/src/lc823450: Add tx start threshold to lc823450_i2s.c

In addition, lc823450_i2s_send() now accepts byte-aligned stream.

Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>

Approved-by: GregoryN <gnutt@nuttx.org>
This commit is contained in:
Masayuki Ishikawa 2018-07-03 12:59:03 +00:00 committed by GregoryN
parent f3bb2728d4
commit 88f8a09a25

View File

@ -66,6 +66,8 @@
* Pre-processor Definitions * Pre-processor Definitions
****************************************************************************/ ****************************************************************************/
/* #define SHOW_BUFFERING */
#define I2S_HAS_IOCTL #define I2S_HAS_IOCTL
#define BUFID(n) (n - 'A') #define BUFID(n) (n - 'A')
@ -193,6 +195,9 @@ struct lc823450_i2s_s
struct i2s_dev_s dev; /* Externally visible I2S interface */ struct i2s_dev_s dev; /* Externally visible I2S interface */
}; };
static bool _b_input_started = false;
static uint32_t _i2s_tx_th_bytes;
/**************************************************************************** /****************************************************************************
* Private Function Prototypes * Private Function Prototypes
****************************************************************************/ ****************************************************************************/
@ -398,6 +403,28 @@ static void lc823450_i2s_setchannel(char id, uint8_t ch)
modifyreg32(ABUFCLR, 0, BUFID(id)); modifyreg32(ABUFCLR, 0, BUFID(id));
} }
/****************************************************************************
* Name: _setup_tx_threshold
****************************************************************************/
static void _setup_tx_threshold(uint32_t tx_th)
{
if (0 == tx_th)
{
/* default tx threshould : 1024bytes */
_i2s_tx_th_bytes = 1024;
}
else
{
/* tx_th: 0 to 100 (%) */
_i2s_tx_th_bytes = getreg32(BUF_SIZE('C')) * tx_th / 100;
}
putreg32(_i2s_tx_th_bytes, BUF_ULVL('C'));
}
/**************************************************************************** /****************************************************************************
* Name: lc823450_i2s_rxdatawidth * Name: lc823450_i2s_rxdatawidth
****************************************************************************/ ****************************************************************************/
@ -405,6 +432,7 @@ static void lc823450_i2s_setchannel(char id, uint8_t ch)
static int lc823450_i2s_ioctl(struct i2s_dev_s *dev, int cmd, unsigned long arg) static int lc823450_i2s_ioctl(struct i2s_dev_s *dev, int cmd, unsigned long arg)
{ {
FAR const struct audio_caps_desc_s *cap_desc; FAR const struct audio_caps_desc_s *cap_desc;
uint32_t tx_th;
uint32_t rate[2]; uint32_t rate[2];
uint8_t ch[2]; uint8_t ch[2];
uint8_t fmt[2]; uint8_t fmt[2];
@ -415,12 +443,15 @@ static int lc823450_i2s_ioctl(struct i2s_dev_s *dev, int cmd, unsigned long arg)
cap_desc = (FAR const struct audio_caps_desc_s *)((uintptr_t)arg); cap_desc = (FAR const struct audio_caps_desc_s *)((uintptr_t)arg);
ASSERT(NULL != cap_desc); ASSERT(NULL != cap_desc);
rate[1] = cap_desc->caps.ac_controls.w; tx_th = cap_desc->caps.ac_controls.w >> 24;
rate[1] = cap_desc->caps.ac_controls.w & 0xfffff;
ch[1] = cap_desc->caps.ac_channels; ch[1] = cap_desc->caps.ac_channels;
fmt[1] = cap_desc->caps.ac_format.hw; fmt[1] = cap_desc->caps.ac_format.hw;
if (cap_desc->caps.ac_type & AUDIO_TYPE_OUTPUT) if (cap_desc->caps.ac_type & AUDIO_TYPE_OUTPUT)
{ {
_setup_tx_threshold(tx_th);
rate[0] = getreg32(SSRC_FSI) >> 13; rate[0] = getreg32(SSRC_FSI) >> 13;
ch[0] = (getreg32(BUFCTL('C')) & BUFCTL_MONO) ? 1 : 2; ch[0] = (getreg32(BUFCTL('C')) & BUFCTL_MONO) ? 1 : 2;
fmt[0] = getreg32(AUDSEL) & AUDSEL_DECSEL ? AUDIO_FMT_MP3 : AUDIO_FMT_PCM; fmt[0] = getreg32(AUDSEL) & AUDSEL_DECSEL ? AUDIO_FMT_MP3 : AUDIO_FMT_PCM;
@ -480,8 +511,6 @@ static void _i2s_rxdma_callback(DMA_HANDLE hdma, void *arg, int result)
nxsem_post(waitsem); nxsem_post(waitsem);
} }
static bool _b_input_started = false;
/**************************************************************************** /****************************************************************************
* Name: lc823450_i2s_receive * Name: lc823450_i2s_receive
****************************************************************************/ ****************************************************************************/
@ -629,6 +658,18 @@ static int lc823450_i2s_send(struct i2s_dev_s *dev, struct ap_buffer_s *apb,
i2s_callback_t callback, void *arg, i2s_callback_t callback, void *arg,
uint32_t timeout) uint32_t timeout)
{ {
volatile uint32_t *ptr = (uint32_t *)&apb->samp[apb->curbyte];
uint32_t n = apb->nbytes;
if (0 == getreg32(BUF_DTCAP('C')))
{
/* C buffer is empty. Start buffering by disabling access control */
modifyreg32(ABUFACCEN, ABUFACCEN_CDCEN('C'), 0);
}
if (getreg32(ABUFACCEN) & ABUFACCEN_CDCEN('C'))
{
/* Enable C Buffer Under Level IRQ */ /* Enable C Buffer Under Level IRQ */
modifyreg32(ABUFIRQEN0, 0, ABUFIRQEN0_BULIRQEN('C')); modifyreg32(ABUFIRQEN0, 0, ABUFIRQEN0_BULIRQEN('C'));
@ -636,17 +677,26 @@ static int lc823450_i2s_send(struct i2s_dev_s *dev, struct ap_buffer_s *apb,
/* Wait for Audio Buffer */ /* Wait for Audio Buffer */
_i2s_semtake(&_sem_buf_under); _i2s_semtake(&_sem_buf_under);
}
volatile uint32_t *ptr = (uint32_t *)&apb->samp[apb->curbyte];
uint32_t n = apb->nbytes;
/* Setup and start DMA for I2S */ /* Setup and start DMA for I2S */
if (0 == (n % 4))
{
lc823450_dmasetup(_htxdma, lc823450_dmasetup(_htxdma,
LC823450_DMA_SRCINC | LC823450_DMA_SRCINC |
LC823450_DMA_SRCWIDTH_WORD | LC823450_DMA_SRCWIDTH_WORD |
LC823450_DMA_DSTWIDTH_WORD, LC823450_DMA_DSTWIDTH_WORD,
(uint32_t)ptr, (uint32_t)BUF_ACCESS('C'), n / 4); (uint32_t)ptr, (uint32_t)BUF_ACCESS('C'), n / 4);
}
else
{
lc823450_dmasetup(_htxdma,
LC823450_DMA_SRCINC |
LC823450_DMA_SRCWIDTH_BYTE |
LC823450_DMA_DSTWIDTH_BYTE,
(uint32_t)ptr, (uint32_t)BUF_ACCESS('C'), n);
}
lc823450_dmastart(_htxdma, lc823450_dmastart(_htxdma,
_i2s_txdma_callback, _i2s_txdma_callback,
@ -654,9 +704,16 @@ static int lc823450_i2s_send(struct i2s_dev_s *dev, struct ap_buffer_s *apb,
_i2s_semtake(&_sem_txdma); _i2s_semtake(&_sem_txdma);
/* Start C Buffer : TODO threshould */ #ifdef SHOW_BUFFERING
if (0 == (getreg32(ABUFACCEN) & ABUFACCEN_CDCEN('C')))
{
audinfo("buffering (remain=%d) \n", getreg32(BUF_DTCAP('C')));
}
#endif
if (getreg32(BUF_DTCAP('C')) >= 1024) /* Start C Buffer */
if (_i2s_tx_th_bytes < getreg32(BUF_DTCAP('C')))
{ {
modifyreg32(ABUFACCEN, 0, ABUFACCEN_CDCEN('C')); modifyreg32(ABUFACCEN, 0, ABUFACCEN_CDCEN('C'));
} }
@ -804,11 +861,11 @@ static int lc823450_i2s_configure(void)
putreg32(MCLKCNTEXT3_AUDIOBUF_CLKEN, putreg32(MCLKCNTEXT3_AUDIOBUF_CLKEN,
MCLKCNTEXT3); MCLKCNTEXT3);
/* C Buffer : size=32KB, under level=1kB */ /* C Buffer : size=56KB, under level=1kB */
putreg32(base, BUF_BASE('C')); putreg32(base, BUF_BASE('C'));
putreg32(4096 * 8, BUF_SIZE('C')); putreg32(1024 * 56, BUF_SIZE('C'));
base += 4096 * 8; base += 1024 * 56;
putreg32(1024, BUF_ULVL('C')); putreg32(1024, BUF_ULVL('C'));
/* Setup F Buffer : size=512B */ /* Setup F Buffer : size=512B */
@ -894,6 +951,10 @@ static int lc823450_i2s_configure(void)
audinfo("DTCAP(C)=0x%08x \n", BUF_DTCAP('C')); audinfo("DTCAP(C)=0x%08x \n", BUF_DTCAP('C'));
audinfo("DTCAP(I)=0x%08x \n", BUF_DTCAP('I')); audinfo("DTCAP(I)=0x%08x \n", BUF_DTCAP('I'));
audinfo("DTCAP(J)=0x%08x \n", BUF_DTCAP('J')); audinfo("DTCAP(J)=0x%08x \n", BUF_DTCAP('J'));
/* Setup default tx threshold */
_setup_tx_threshold(0);
return 0; return 0;
} }
@ -983,3 +1044,12 @@ FAR struct i2s_dev_s *lc823450_i2sdev_initialize(void)
return &priv->dev; return &priv->dev;
} }
/****************************************************************************
* Name: up_audio_bufcapacity
****************************************************************************/
uint32_t up_audio_bufcapacity(void)
{
return (100 * getreg32(BUF_DTCAP('C'))) / getreg32(BUF_SIZE('C'));
}