diff --git a/arch/arm/src/lc823450/lc823450_i2s.c b/arch/arm/src/lc823450/lc823450_i2s.c index 5ea825d73ba..9d1c01c1e1d 100644 --- a/arch/arm/src/lc823450/lc823450_i2s.c +++ b/arch/arm/src/lc823450/lc823450_i2s.c @@ -66,48 +66,92 @@ * Pre-processor Definitions ****************************************************************************/ +#define I2S_HAS_IOCTL + +#define BUFID(n) (n - 'A') + #define LC823450_AUDIO_REGBASE 0x40060000 #define ABUF_REGBASE (LC823450_AUDIO_REGBASE + 0x0000) +#define SSRC_REGBASE (LC823450_AUDIO_REGBASE + 0x1000) #define BEEP_REGBASE (LC823450_AUDIO_REGBASE + 0x1200) +#define DGMIC_REGBASE (LC823450_AUDIO_REGBASE + 0x1500) #define PCKGEN_REGBASE (LC823450_AUDIO_REGBASE + 0x1600) +#define ASRC_REGBASE (LC823450_AUDIO_REGBASE + 0x1a00) +#define MP3DEC_REGBASE (LC823450_AUDIO_REGBASE + 0x2000) #define AUDCTL_REGBASE (LC823450_AUDIO_REGBASE + 0x4000) +/* Audio Buffer */ + #define ABUFCLR (ABUF_REGBASE + 0x0000) #define ABUFACCEN (ABUF_REGBASE + 0x0004) -#define ABUFACCEN_CDCFEN (1 << 5) +#define ABUFACCEN_RDCTEN(n) (1 << (BUFID(n) + 16)) +#define ABUFACCEN_CDCEN(n) (1 << (BUFID(n) + 0)) #define ABUFIRQEN0 (ABUF_REGBASE + 0x0008) -#define ABUFIRQEN0_BFULIRQEN (1 << 5) +#define ABUFIRQEN0_BOLIRQEN(n) (1 << (BUFID(n) + 16)) +#define ABUFIRQEN0_BULIRQEN(n) (1 << (BUFID(n) + 0)) #define ABUFSTS1 (ABUF_REGBASE + 0x0034) +#define ABUFSTS1_BOLVL(n) (1 << (BUFID(n) + 16)) +#define ABUFSTS1_BULVL(n) (1 << (BUFID(n) + 0)) -#define BUF_F_BASE (ABUF_REGBASE + 0x00c0 + (0x4 * 5)) -#define BUF_F_SIZE (ABUF_REGBASE + 0x0100 + (0x4 * 5)) -#define BUF_F_ULVL (ABUF_REGBASE + 0x0140 + (0x4 * 5)) -#define BUF_F_DTCAP (ABUF_REGBASE + 0x01c0 + (0x4 * 5)) -#define BUF_F_ACCESS (ABUF_REGBASE + 0x0300 + (0x4 * 5)) +#define BUF_BASE(n) (ABUF_REGBASE + 0x00c0 + (4 * BUFID(n))) +#define BUF_SIZE(n) (ABUF_REGBASE + 0x0100 + (4 * BUFID(n))) +#define BUF_ULVL(n) (ABUF_REGBASE + 0x0140 + (4 * BUFID(n))) +#define BUF_OLVL(n) (ABUF_REGBASE + 0x0180 + (4 * BUFID(n))) +#define BUF_DTCAP(n) (ABUF_REGBASE + 0x01c0 + (4 * BUFID(n))) +#define BUF_ACCESS(n) (ABUF_REGBASE + 0x0300 + (4 * BUFID(n))) -#define CLOCKEN (AUDCTL_REGBASE + 0x0000) +#define BUFCTL(n) (ABUF_REGBASE + 0x0080 + (4 * BUFID(n))) +#define BUFCTL_MONO (1 << 0) + +/* SSRC */ + +#define SSRC_MODE (SSRC_REGBASE + 0x0000) +#define SSRC_FSI (SSRC_REGBASE + 0x0004) +#define SSRC_FSO (SSRC_REGBASE + 0x0008) +#define SSRC_SRESETB (SSRC_REGBASE + 0x0010) +#define SSRC_STATUS (SSRC_REGBASE + 0x0014) + +/* Audio Control */ + +#define CLOCKEN (AUDCTL_REGBASE + 0x000) +#define CLOCKEN_FCE_ASRC (1 << 29) #define CLOCKEN_FCE_PCKGEN (1 << 28) #define CLOCKEN_FCE_PCMPS0 (1 << 17) #define CLOCKEN_FCE_BEEP (1 << 16) #define CLOCKEN_FCE_VOLPS0 (1 << 13) +#define CLOCKEN_FCE_VOLSP0 (1 << 11) +#define CLOCKEN_FCE_DGMIC (1 << 7) +#define CLOCKEN_FCE_VOLD (1 << 6) +#define CLOCKEN_FCE_SSRC (1 << 4) +#define CLOCKEN_FCE_MUTED (1 << 3) +#define CLOCKEN_FCE_MP3DEC (1 << 2) -#define AUDSEL (AUDCTL_REGBASE + 0x001c) +#define AUDSEL (AUDCTL_REGBASE + 0x01c) #define AUDSEL_PCM0_MODE (1 << 17) #define AUDSEL_PCM0_MODEM (1 << 16) +#define AUDSEL_PCMSEL (1 << 4) +#define AUDSEL_DECSEL (1 << 0) -#define PSCTL (AUDCTL_REGBASE + 0x0110) +#define PSCTL (AUDCTL_REGBASE + 0x110) -#define PCMOUTEN (AUDCTL_REGBASE + 0x0500) +/* Volume (SP0) */ + +#define VOLSP0_CONT (AUDCTL_REGBASE + 0x320) +#define VOL_CONT_DIRECT (1 << 20) + +#define PCMOUTEN (AUDCTL_REGBASE + 0x500) #define PCMOUTEN_DOUT0EN (1 << 3) #define PCMOUTEN_LRCK0EN (1 << 2) #define PCMOUTEN_MCLK0EN (1 << 1) #define PCMOUTEN_BCK0EN (1 << 0) -#define PCMCTL (AUDCTL_REGBASE + 0x0504) +#define PCMCTL (AUDCTL_REGBASE + 0x504) + +/* BEEP */ #define BEEP_CTL (BEEP_REGBASE + 0x0000) #define BEEP_BYPASS (BEEP_REGBASE + 0x0004) @@ -121,6 +165,23 @@ #define AUDPLLMDIV (AUDIOPLL_REGBASE + 0x04) #define AUDPLLNDIV (AUDIOPLL_REGBASE + 0x08) +#define DGMICCTL (DGMIC_REGBASE + 0x00) +#define ALCCTL (DGMIC_REGBASE + 0x30) + +/* ASRC */ + +#define ASRC_MODE (ASRC_REGBASE + 0x0000) +#define ASRC_FSI (ASRC_REGBASE + 0x0004) +#define ASRC_FSO (ASRC_REGBASE + 0x0008) +#define ASRC_SRESETB (ASRC_REGBASE + 0x0010) +#define ASRC_STATUS (ASRC_REGBASE + 0x0014) + +/* MP3 Decoder */ + +#define MP3DEC_ERR (MP3DEC_REGBASE + 0x08) +#define MP3DEC_BUFM (MP3DEC_REGBASE + 0x1c) +#define MP3DEC_ERRMODE (MP3DEC_REGBASE + 0x20) + /**************************************************************************** * Private Types ****************************************************************************/ @@ -136,12 +197,24 @@ struct lc823450_i2s_s * Private Function Prototypes ****************************************************************************/ +static uint32_t lc823450_i2s_rxsamplerate(struct i2s_dev_s *dev, uint32_t rate); +static uint32_t lc823450_i2s_rxdatawidth(struct i2s_dev_s *dev, int bits); +static int lc823450_i2s_receive(struct i2s_dev_s *dev, struct ap_buffer_s *apb, + i2s_callback_t callback, void *arg, + uint32_t timeout); + static uint32_t lc823450_i2s_txsamplerate(struct i2s_dev_s *dev, uint32_t rate); static uint32_t lc823450_i2s_txdatawidth(struct i2s_dev_s *dev, int bits); static int lc823450_i2s_send(struct i2s_dev_s *dev, struct ap_buffer_s *apb, i2s_callback_t callback, void *arg, uint32_t timeout); +static void lc823450_i2s_setchannel(char id, uint8_t ch); +static void lc823450_i2s_mp3dec(bool enable); + +static int lc823450_i2s_ioctl(struct i2s_dev_s *dev, + int cmd, unsigned long arg); + /**************************************************************************** * Private Data ****************************************************************************/ @@ -150,13 +223,29 @@ static int lc823450_i2s_send(struct i2s_dev_s *dev, struct ap_buffer_s *apb static const struct i2s_ops_s g_i2sops = { + /* Receiver methods */ + + .i2s_rxsamplerate = lc823450_i2s_rxsamplerate, + .i2s_rxdatawidth = lc823450_i2s_rxdatawidth, + .i2s_receive = lc823450_i2s_receive, + /* Transmitter methods */ .i2s_txsamplerate = lc823450_i2s_txsamplerate, .i2s_txdatawidth = lc823450_i2s_txdatawidth, .i2s_send = lc823450_i2s_send, + +#ifdef I2S_HAS_IOCTL + /* Ioctl */ + + .i2s_ioctl = lc823450_i2s_ioctl, +#endif }; +static DMA_HANDLE _hrxdma; +static sem_t _sem_rxdma; +static sem_t _sem_buf_over; + static DMA_HANDLE _htxdma; static sem_t _sem_txdma; static sem_t _sem_buf_under; @@ -226,16 +315,6 @@ static void _setup_audio_pll(uint32_t freq) ); } -/**************************************************************************** - * Name: _i2s_txdma_callback - ****************************************************************************/ - -static void _i2s_txdma_callback(DMA_HANDLE hdma, void *arg, int result) -{ - sem_t *waitsem = (sem_t *)arg; - nxsem_post(waitsem); -} - /**************************************************************************** * Name: _i2s_semtake ****************************************************************************/ @@ -259,13 +338,239 @@ static void _i2s_semtake(FAR sem_t *sem) while (ret == -EINTR); } +/**************************************************************************** + * Name: lc823450_i2s_rxsamplerate + ****************************************************************************/ + +static uint32_t lc823450_i2s_rxsamplerate(struct i2s_dev_s *dev, uint32_t rate) +{ + /* Change ASRC FSO rate */ + + /* Stop/Reset/Unreset ASRC */ + + putreg32(0, ASRC_MODE); + putreg32(0, ASRC_SRESETB); + putreg32(1, ASRC_SRESETB); + while (getreg32(ASRC_STATUS) & 0x1); + + /* Setup FSO */ + + putreg32((rate) << 0, ASRC_FSO); + + /* Restart ASRC */ + + putreg32(0x1, ASRC_MODE); + while (getreg32(ASRC_STATUS) != 0x1); + + return 0; +} + +/**************************************************************************** + * Name: lc823450_i2s_rxdatawidth + ****************************************************************************/ + +static uint32_t lc823450_i2s_rxdatawidth(struct i2s_dev_s *dev, int bits) +{ + return 0; +} + +/**************************************************************************** + * Name: lc823450_i2s_setchannel + ****************************************************************************/ + +static void lc823450_i2s_setchannel(char id, uint8_t ch) +{ + switch (ch) + { + case 1: + modifyreg32(BUFCTL(id), 0, BUFCTL_MONO); + break; + + case 2: + modifyreg32(BUFCTL(id), BUFCTL_MONO, 0); + break; + + default: + ASSERT(false); + break; + } + + modifyreg32(ABUFCLR, 0, BUFID(id)); +} + +/**************************************************************************** + * Name: lc823450_i2s_rxdatawidth + ****************************************************************************/ + +static int lc823450_i2s_ioctl(struct i2s_dev_s *dev, int cmd, unsigned long arg) +{ + FAR const struct audio_caps_desc_s *cap_desc; + uint32_t rate[2]; + uint8_t ch[2]; + uint8_t fmt[2]; + + switch (cmd) + { + case AUDIOIOC_CONFIGURE: + cap_desc = (FAR const struct audio_caps_desc_s *)((uintptr_t)arg); + ASSERT(NULL != cap_desc); + + rate[1] = cap_desc->caps.ac_controls.w; + ch[1] = cap_desc->caps.ac_channels; + fmt[1] = cap_desc->caps.ac_format.hw; + + if (cap_desc->caps.ac_type & AUDIO_TYPE_OUTPUT) + { + rate[0] = getreg32(SSRC_FSI) >> 13; + ch[0] = (getreg32(BUFCTL('C')) & BUFCTL_MONO) ? 1 : 2; + fmt[0] = getreg32(AUDSEL) & AUDSEL_DECSEL ? AUDIO_FMT_MP3 : AUDIO_FMT_PCM; + + if (rate[0] != rate[1]) + { + audinfo("change output rate: %d -> %d \n", rate[0], rate[1]); + lc823450_i2s_txsamplerate(dev, rate[1]); + } + + if (ch[0] != ch[1]) + { + audinfo("change output ch: %d -> %d \n", ch[0], ch[1]); + lc823450_i2s_setchannel('C', ch[1]); + } + + if (fmt[0] != fmt[1]) + { + lc823450_i2s_mp3dec(fmt[1] == AUDIO_FMT_MP3 ? true : false); + } + } + + if (cap_desc->caps.ac_type & AUDIO_TYPE_INPUT) + { + rate[0] = getreg32(ASRC_FSO); + ch[0] = (getreg32(BUFCTL('J')) & BUFCTL_MONO) ? 1 : 2; + + if (rate[0] != rate[1]) + { + audinfo("change input rate: %d -> %d \n", rate[0], rate[1]); + lc823450_i2s_rxsamplerate(dev, rate[1]); + } + + if (ch[0] != ch[1]) + { + audinfo("change input ch: %d -> %d \n", ch[0], ch[1]); + lc823450_i2s_setchannel('J', ch[1]); + } + } + + break; + + default: + break; + } + + return 0; +} + +/**************************************************************************** + * Name: _i2s_rxdma_callback + ****************************************************************************/ + +static void _i2s_rxdma_callback(DMA_HANDLE hdma, void *arg, int result) +{ + sem_t *waitsem = (sem_t *)arg; + nxsem_post(waitsem); +} + +static bool _b_input_started = false; + +/**************************************************************************** + * Name: lc823450_i2s_receive + ****************************************************************************/ + +static int lc823450_i2s_receive(struct i2s_dev_s *dev, struct ap_buffer_s *apb, + i2s_callback_t callback, void *arg, + uint32_t timeout) +{ +#if 1 /* TODO: should move to rxsamplerate later */ + if (false == _b_input_started) + { + _b_input_started = true; + + /* Start J Buffer */ + + modifyreg32(ABUFACCEN, 0, ABUFACCEN_CDCEN('J')); + + + /* J Buffer : ACLTALN=0, ACLTEN=0 */ + + modifyreg32(BUFCTL('J'), 0x3 << 8, 0); + } +#endif + + /* Enable J Buffer Over Level IRQ */ + + modifyreg32(ABUFIRQEN0, 0, ABUFIRQEN0_BOLIRQEN('J')); + + /* Wait for Audio Buffer */ + + _i2s_semtake(&_sem_buf_over); + + volatile uint32_t *ptr = (uint32_t *)&apb->samp[apb->curbyte]; + uint32_t n = apb->nmaxbytes; + + /* Setup and start DMA for I2S */ + + lc823450_dmasetup(_hrxdma, + LC823450_DMA_DSTINC | + LC823450_DMA_SRCWIDTH_WORD | + LC823450_DMA_DSTWIDTH_WORD, + (uint32_t)BUF_ACCESS('J'), (uint32_t)ptr, n / 4); + + lc823450_dmastart(_hrxdma, + _i2s_rxdma_callback, + &_sem_rxdma); + + _i2s_semtake(&_sem_rxdma); + + /* Invoke the callback handler */ + + callback(dev, apb, arg, 0); + return OK; +} + +/**************************************************************************** + * Name: _i2s_txdma_callback + ****************************************************************************/ + +static void _i2s_txdma_callback(DMA_HANDLE hdma, void *arg, int result) +{ + sem_t *waitsem = (sem_t *)arg; + nxsem_post(waitsem); +} + /**************************************************************************** * Name: lc823450_i2s_txsamplerate ****************************************************************************/ static uint32_t lc823450_i2s_txsamplerate(struct i2s_dev_s *dev, uint32_t rate) { - /* TODO */ + /* Change SSRC FSI rate */ + + /* Stop/Reset/Unreset SSRC */ + + putreg32(0, SSRC_MODE); + putreg32(0, SSRC_SRESETB); + putreg32(1, SSRC_SRESETB); + while (getreg32(SSRC_STATUS) & 0x1); + + /* Setup FSI */ + + putreg32(rate << 13, SSRC_FSI); + + /* Restart SSRC */ + + putreg32(0x1, SSRC_MODE); + while (getreg32(SSRC_STATUS) != 0x1); + return 0; } @@ -275,7 +580,6 @@ static uint32_t lc823450_i2s_txsamplerate(struct i2s_dev_s *dev, uint32_t rate) static uint32_t lc823450_i2s_txdatawidth(struct i2s_dev_s *dev, int bits) { - /* TODO */ return 0; } @@ -285,13 +589,35 @@ static uint32_t lc823450_i2s_txdatawidth(struct i2s_dev_s *dev, int bits) static int _i2s_isr(int irq, FAR void *context, FAR void *arg) { - /* Disable Buffer F Under Level IRQ */ + uint32_t status = getreg32(ABUFSTS1); + uint32_t irqen0 = getreg32(ABUFIRQEN0); - putreg32(0, ABUFIRQEN0); + /* Check C Buffer Under Level */ - /* post semaphore for the waiter */ + if ((irqen0 & ABUFIRQEN0_BULIRQEN('C')) && (status & ABUFSTS1_BULVL('C'))) + { + /* Disable C Buffer Under Level IRQ */ + + modifyreg32(ABUFIRQEN0, ABUFIRQEN0_BULIRQEN('C'), 0); + + /* post semaphore for the waiter */ + + nxsem_post(&_sem_buf_under); + } + + /* Check J Buffer Over Level */ + + if ((irqen0 & ABUFIRQEN0_BOLIRQEN('J')) && (status & ABUFSTS1_BOLVL('J'))) + { + /* Disable J Buffer Over Level IRQ */ + + modifyreg32(ABUFIRQEN0, ABUFIRQEN0_BOLIRQEN('J'), 0); + + /* post semaphore for the waiter */ + + nxsem_post(&_sem_buf_over); + } - nxsem_post(&_sem_buf_under); return 0; } @@ -303,9 +629,9 @@ static int lc823450_i2s_send(struct i2s_dev_s *dev, struct ap_buffer_s *apb, i2s_callback_t callback, void *arg, uint32_t timeout) { - /* Enable Buffer F Under Level IRQ */ + /* Enable C Buffer Under Level IRQ */ - putreg32(ABUFIRQEN0_BFULIRQEN, ABUFIRQEN0); + modifyreg32(ABUFIRQEN0, 0, ABUFIRQEN0_BULIRQEN('C')); /* Wait for Audio Buffer */ @@ -320,7 +646,7 @@ static int lc823450_i2s_send(struct i2s_dev_s *dev, struct ap_buffer_s *apb, LC823450_DMA_SRCINC | LC823450_DMA_SRCWIDTH_WORD | LC823450_DMA_DSTWIDTH_WORD, - (uint32_t)ptr, (uint32_t)BUF_F_ACCESS, n / 4); + (uint32_t)ptr, (uint32_t)BUF_ACCESS('C'), n / 4); lc823450_dmastart(_htxdma, _i2s_txdma_callback, @@ -328,12 +654,113 @@ static int lc823450_i2s_send(struct i2s_dev_s *dev, struct ap_buffer_s *apb, _i2s_semtake(&_sem_txdma); + /* Start C Buffer : TODO threshould */ + + if (getreg32(BUF_DTCAP('C')) >= 1024) + { + modifyreg32(ABUFACCEN, 0, ABUFACCEN_CDCEN('C')); + } + /* Invoke the callback handler */ callback(dev, apb, arg, 0); return OK; } +/**************************************************************************** + * Name: lc823450_dmic_enable + ****************************************************************************/ + +static void lc823450_dmic_enable() +{ + /* Disable clock for DGMIC */ + + modifyreg32(CLOCKEN, CLOCKEN_FCE_DGMIC, 0); + + /* ALC=off */ + + modifyreg32(ALCCTL, 0x1, 0x0); + + /* DGMICCTL: XFDSP=direct,XEQT=XHPF=off,XMOD=75%,XFS64=64fs */ + + putreg32(0x70000009, DGMICCTL); + + /* Enable clock for DGMIC */ + + modifyreg32(CLOCKEN, 0, CLOCKEN_FCE_DGMIC); + + /* AUDSEL: PCMSEL=1 (dmic) */ + + modifyreg32(AUDSEL, 0, AUDSEL_PCMSEL); + +#if 1 + /* TODO: should be moved to another function */ + + /* Enable clock for VOLUME(SP0) */ + + modifyreg32(CLOCKEN, 0, CLOCKEN_FCE_VOLSP0); + + /* Audio Buffer Access Control: enable redirect E */ + + modifyreg32(ABUFACCEN, 0, ABUFACCEN_RDCTEN('E')); + + /* Set the redirect source of I Buffer to E */ + + modifyreg32(BUFCTL('I'), 0, BUFID('E') << 16); + + /* Enable CDCI */ + + modifyreg32(ABUFACCEN, 0, ABUFACCEN_CDCEN('I')); + + /* Enable ASRC clock */ + + modifyreg32(CLOCKEN, 0, CLOCKEN_FCE_ASRC); + + /* ASRC = 44.1k(in)/44.1k(out) */ + + putreg32(44100 << 13, ASRC_FSI); + putreg32(44100 << 0, ASRC_FSO); + + /* Adjust volume SP0 (+33dB) */ + + putreg32(VOL_CONT_DIRECT | + 33 << 8 | 33, + VOLSP0_CONT); + + audinfo("ASRC_FSIO=%d \n", getreg32(ASRC_FSO)); + audinfo("DTCAP(I)=0x%x \n", getreg32(BUF_DTCAP('I'))); + audinfo("DTCAP(J)=0x%x \n", getreg32(BUF_DTCAP('J'))); + + /* Start ASRC */ + + putreg32(0x1, ASRC_MODE); + while (getreg32(ASRC_STATUS) != 0x1); + + /* J Buffer : ACLTALN=1, ACLTEN=1 */ + + modifyreg32(BUFCTL('J'), 0, 0x3 << 8); +#endif +} + +/**************************************************************************** + * Name: lc823450_i2s_mp3dec + ****************************************************************************/ + +static void lc823450_i2s_mp3dec(bool enable) +{ + if (enable) + { + modifyreg32(AUDSEL, 0, AUDSEL_DECSEL); + modifyreg32(CLOCKEN, 0, CLOCKEN_FCE_MP3DEC); + putreg32(0x1, MP3DEC_ERRMODE); + } + else + { + modifyreg32(CLOCKEN, CLOCKEN_FCE_MP3DEC, 0); + modifyreg32(AUDSEL, AUDSEL_DECSEL, 0); + } +} + /**************************************************************************** * Name: lc823450_i2s_beeptest ****************************************************************************/ @@ -341,6 +768,10 @@ static int lc823450_i2s_send(struct i2s_dev_s *dev, struct ap_buffer_s *apb, #ifdef BEEP_TEST static void lc823450_i2s_beeptest(void) { + /* Enable clock */ + + modifyreg32(CLOCKEN, 0, CLOCKEN_FCE_BEEP); + /* Set BEEP params */ putreg32(0x0, BEEP_BYPASS); @@ -359,6 +790,8 @@ static void lc823450_i2s_beeptest(void) static int lc823450_i2s_configure(void) { + uint32_t base = 0; + _setup_audio_pll(44100); /* Unreset Audio Buffer */ @@ -371,13 +804,31 @@ static int lc823450_i2s_configure(void) putreg32(MCLKCNTEXT3_AUDIOBUF_CLKEN, MCLKCNTEXT3); - /* F Buffer = 32KB */ + /* C Buffer : size=32KB, under level=1kB */ - putreg32(4096 * 8, BUF_F_SIZE); + putreg32(base, BUF_BASE('C')); + putreg32(4096 * 8, BUF_SIZE('C')); + base += 4096 * 8; + putreg32(1024, BUF_ULVL('C')); - /* Buffer Under Level = 1KB */ + /* Setup F Buffer : size=512B */ - putreg32(1024, BUF_F_ULVL); + putreg32(base, BUF_BASE('F')); + putreg32(512, BUF_SIZE('F')); + base += 512; + + /* Setup I Buffer : size=2KB (TODO) */ + + putreg32(base, BUF_BASE('I')); + putreg32(2048 * 2, BUF_SIZE('I')); + base += (2048 * 2); + + /* Setup J Buffer: size=4KB, over level=1KB */ + + putreg32(base, BUF_BASE('J')); + putreg32(4096, BUF_SIZE('J')); + base += 4096; + putreg32(1024, BUF_OLVL('J')); /* Clear Audio Buffer */ @@ -385,7 +836,15 @@ static int lc823450_i2s_configure(void) /* Access Enable */ - putreg32(ABUFACCEN_CDCFEN, ABUFACCEN); + modifyreg32(ABUFACCEN, + 0, + ABUFACCEN_RDCTEN('D') | + ABUFACCEN_CDCEN('F') + ); + + /* Source of F Buffer is D */ + + modifyreg32(BUFCTL('F'), 0, BUFID('D') << 16); /* PCM0: BCK0/LRCK0=master, MCLK0=master */ @@ -412,14 +871,29 @@ static int lc823450_i2s_configure(void) putreg32(0x64, PSCTL); - /* Enable PCMPS0 */ + /* Enable function clocks */ putreg32(CLOCKEN_FCE_PCKGEN | - CLOCKEN_FCE_BEEP | CLOCKEN_FCE_PCMPS0 | - CLOCKEN_FCE_VOLPS0, + CLOCKEN_FCE_VOLPS0 | + CLOCKEN_FCE_MUTED | + CLOCKEN_FCE_SSRC | + CLOCKEN_FCE_VOLD, CLOCKEN); + /* SSRC = 44.1k(in)/44.1k(out) */ + + putreg32(44100 << 13, SSRC_FSI); + putreg32(44100 << 0, SSRC_FSO); + + /* Start SSRC */ + + putreg32(0x1, SSRC_MODE); + while (getreg32(SSRC_STATUS) != 0x1); + + audinfo("DTCAP(C)=0x%08x \n", BUF_DTCAP('C')); + audinfo("DTCAP(I)=0x%08x \n", BUF_DTCAP('I')); + audinfo("DTCAP(J)=0x%08x \n", BUF_DTCAP('J')); return 0; } @@ -461,6 +935,16 @@ FAR struct i2s_dev_s *lc823450_i2sdev_initialize(void) lc823450_i2s_beeptest(); #endif +#if 1 + /* NOTE: should be moved to another codec driver */ + + lc823450_dmic_enable(); +#endif + + _hrxdma = lc823450_dmachannel(DMA_CHANNEL_VIRTUAL); + nxsem_init(&_sem_rxdma, 0, 0); + nxsem_init(&_sem_buf_over, 0, 0); + _htxdma = lc823450_dmachannel(DMA_CHANNEL_VIRTUAL); nxsem_init(&_sem_txdma, 0, 0); nxsem_init(&_sem_buf_under, 0, 0); diff --git a/configs/lc823450-xgevk/README.txt b/configs/lc823450-xgevk/README.txt index 4697e0db325..c2e8023c56a 100644 --- a/configs/lc823450-xgevk/README.txt +++ b/configs/lc823450-xgevk/README.txt @@ -252,14 +252,6 @@ Dropped 0001 0000 0000 0000 Sent 0003 0000 0003 0000 Rexmit ---- 0000 ---- ---- -However, you might need to add a routing table if you want to send -a packet via the router. - -nsh> addroute 0.0.0.0/0 192.168.1.1 -nsh> route -SEQ TARGET NETMASK ROUTER - 1. 0.0.0.0 0.0.0.0 192.168.1.1 - 12. DVFS (Dynamic Voltage and Frequency Scaling) lc823450-xgevk/audio and rndis configurations support DVFS. diff --git a/configs/lc823450-xgevk/audio/defconfig b/configs/lc823450-xgevk/audio/defconfig index 90a3a67b449..cb1f77fcc3a 100644 --- a/configs/lc823450-xgevk/audio/defconfig +++ b/configs/lc823450-xgevk/audio/defconfig @@ -1,3 +1,7 @@ +# CONFIG_AUDIO_FORMAT_MP3 is not set +# CONFIG_NSH_ARGCAT is not set +# CONFIG_NX_DISABLE_1BPP is not set +# CONFIG_SPI_EXCHANGE is not set CONFIG_AQM_1248A=y CONFIG_ARCH="arm" CONFIG_ARCH_BOARD="lc823450-xgevk" @@ -6,13 +10,13 @@ CONFIG_ARCH_CHIP_LC823450=y CONFIG_ARCH_FLOAT_H=y CONFIG_ARCH_INTERRUPTSTACK=2048 CONFIG_ARCH_STDARG_H=y +CONFIG_AUDIO=y CONFIG_AUDIO_BUFFER_NUMBYTES=1024 CONFIG_AUDIO_EXCLUDE_BALANCE=y CONFIG_AUDIO_EXCLUDE_FFORWARD=y CONFIG_AUDIO_EXCLUDE_TONE=y -# CONFIG_AUDIO_FORMAT_MP3 is not set +CONFIG_AUDIO_I2SCHAR=y CONFIG_AUDIO_WM8776=y -CONFIG_AUDIO=y CONFIG_BOARDCTL_RESET=y CONFIG_BOARD_LOOPSPERMSEC=12061 CONFIG_BUILTIN=y @@ -30,23 +34,24 @@ CONFIG_DISABLE_POSIX_TIMERS=y CONFIG_DRIVERS_AUDIO=y CONFIG_DVFS=y CONFIG_EXAMPLES_HELLO=y +CONFIG_EXAMPLES_I2SLOOP=y CONFIG_EXAMPLES_NSH=y -CONFIG_EXAMPLES_NXHELLO_BPP=1 CONFIG_EXAMPLES_NXHELLO=y +CONFIG_EXAMPLES_NXHELLO_BPP=1 CONFIG_EXAMPLES_OSTEST=y CONFIG_EXAMPLES_PIPE=y CONFIG_EXAMPLES_SMP=y CONFIG_EXPERIMENTAL=y CONFIG_FAT_LCNAMES=y CONFIG_FAT_LFN=y -CONFIG_FS_FATTIME=y CONFIG_FS_FAT=y -CONFIG_FS_PROCFS_REGISTER=y +CONFIG_FS_FATTIME=y CONFIG_FS_PROCFS=y +CONFIG_FS_PROCFS_REGISTER=y CONFIG_HRT_TIMER=y -CONFIG_I2C_RESET=y -CONFIG_I2CTOOL_MAXBUS=1 CONFIG_I2C=y +CONFIG_I2CTOOL_MAXBUS=1 +CONFIG_I2C_RESET=y CONFIG_I2S=y CONFIG_INTELHEX_BINARY=y CONFIG_LC823450_I2C0=y @@ -57,10 +62,10 @@ CONFIG_LC823450_MTM0_TICK=y CONFIG_LC823450_SDIF_SDC=y CONFIG_LC823450_SPI_DMA=y CONFIG_LC823450_UART0=y -CONFIG_LCD_ST7565=y CONFIG_LCD=y -CONFIG_LIB_KBDCODEC=y +CONFIG_LCD_ST7565=y CONFIG_LIBM=y +CONFIG_LIB_KBDCODEC=y CONFIG_MAX_TASKS=64 CONFIG_MAX_WDOGPARMS=2 CONFIG_MEMSET_OPTSPEED=y @@ -71,7 +76,6 @@ CONFIG_NETUTILS_CODECS=y CONFIG_NFILE_DESCRIPTORS=45 CONFIG_NFILE_STREAMS=8 CONFIG_NSH_ARCHINIT=y -# CONFIG_NSH_ARGCAT is not set CONFIG_NSH_BUILTIN_APPS=y CONFIG_NSH_CMDOPT_DD_STATS=y CONFIG_NSH_DISABLE_BASENAME=y @@ -90,11 +94,10 @@ CONFIG_NSH_FILEIOSIZE=512 CONFIG_NSH_LINELEN=128 CONFIG_NSH_MAXARGUMENTS=10 CONFIG_NSH_READLINE=y -CONFIG_NX_BLOCKING=y -# CONFIG_NX_DISABLE_1BPP is not set +CONFIG_NX=y CONFIG_NXFONT_MONO5X8=y CONFIG_NXPLAYER_DEFAULT_MEDIADIR="/mnt/sd1" -CONFIG_NX=y +CONFIG_NX_BLOCKING=y CONFIG_PIPES=y CONFIG_POSIX_SPAWN_PROXY_STACKSIZE=2048 CONFIG_PREALLOC_MQ_MSGS=4 @@ -106,45 +109,44 @@ CONFIG_RAM_SIZE=1044480 CONFIG_RAM_START=0x02001000 CONFIG_RAW_BINARY=y CONFIG_READLINE_CMD_HISTORY=y -CONFIG_RTC_HIRES=y CONFIG_RTC=y +CONFIG_RTC_HIRES=y CONFIG_SCHED_ATEXIT=y CONFIG_SCHED_CHILD_STATUS=y CONFIG_SCHED_HAVE_PARENT=y -CONFIG_SCHED_ONEXIT_MAX=32 CONFIG_SCHED_ONEXIT=y +CONFIG_SCHED_ONEXIT_MAX=32 CONFIG_SCHED_STARTHOOK=y CONFIG_SCHED_WAITPID=y CONFIG_SDCLONE_DISABLE=y CONFIG_SERIAL_TERMIOS=y -CONFIG_SMP_NCPUS=2 CONFIG_SMP=y -# CONFIG_SPI_EXCHANGE is not set -CONFIG_SPINLOCK_IRQ=y +CONFIG_SMP_NCPUS=2 CONFIG_SPI=y +CONFIG_SPINLOCK_IRQ=y CONFIG_START_DAY=3 CONFIG_START_MONTH=10 CONFIG_START_YEAR=2013 CONFIG_SYSTEM_I2CTOOL=y CONFIG_SYSTEM_NXPLAYER=y CONFIG_SYSTEM_TIME64=y +CONFIG_SYSTEM_USBMSC=y CONFIG_SYSTEM_USBMSC_CMD_STACKSIZE=2048 CONFIG_SYSTEM_USBMSC_DEVPATH1="/dev/mtdblock0p10" CONFIG_SYSTEM_USBMSC_DEVPATH2="/dev/mtdblock1" CONFIG_SYSTEM_USBMSC_NLUNS=2 -CONFIG_SYSTEM_USBMSC=y CONFIG_TASK_NAME_SIZE=24 CONFIG_UART0_RXBUFSIZE=512 CONFIG_UART0_SERIAL_CONSOLE=y CONFIG_UART0_TXBUFSIZE=2048 +CONFIG_USBDEV=y CONFIG_USBDEV_BUSPOWERED=y CONFIG_USBDEV_DUALSPEED=y CONFIG_USBDEV_MAXPOWER=500 -CONFIG_USBDEV=y +CONFIG_USBMSC=y CONFIG_USBMSC_EPBULKIN=2 CONFIG_USBMSC_EPBULKOUT=1 CONFIG_USBMSC_REMOVABLE=y -CONFIG_USBMSC=y -CONFIG_USER_ENTRYPOINT="nsh_main" CONFIG_USERMAIN_STACKSIZE=3072 +CONFIG_USER_ENTRYPOINT="nsh_main" CONFIG_WM8776_SWAP_HPOUT=y diff --git a/configs/lc823450-xgevk/src/lc823450-xgevk_mux.h b/configs/lc823450-xgevk/src/lc823450-xgevk_mux.h index e9ef37aa39e..470b02f6722 100644 --- a/configs/lc823450-xgevk/src/lc823450-xgevk_mux.h +++ b/configs/lc823450-xgevk/src/lc823450-xgevk_mux.h @@ -152,7 +152,7 @@ 1 << 16 | /* 0: GPIO18, 1:MCLK0, 2:MCLK1 */ \ 1 << 18 | /* 0: GPIO19, 1:BCK0, 2:DMCKO1 */ \ 1 << 20 | /* 0: GPIO1A, 1:LRCK0, 2:DMDIN1 */ \ - 1 << 22 | /* 0: GPIO1B, 1:DIN0, 2:DMDIN0 */ \ + 2 << 22 | /* 0: GPIO1B, 1:DIN0, 2:DMDIN0 */ \ 1 << 24 | /* 0: GPIO1C, 1:DOUT0, 2:DMCKO0 */ \ 1 << 26 | /* 0: GPIO1D, 1:SCK0 */ \ 0 << 28 | /* 0: GPIO1E, 1:SDI0 */ \ diff --git a/configs/lc823450-xgevk/src/lc823450_wm8776.c b/configs/lc823450-xgevk/src/lc823450_wm8776.c index f52be83cc56..bffc1ccbc7b 100644 --- a/configs/lc823450-xgevk/src/lc823450_wm8776.c +++ b/configs/lc823450-xgevk/src/lc823450_wm8776.c @@ -100,6 +100,10 @@ int lc823450_wm8776initialize(int minor) i2s = lc823450_i2sdev_initialize(); +#ifdef CONFIG_AUDIO_I2SCHAR + i2schar_register(i2s, 0); +#endif + wm8776 = wm8776_initialize(i2c, i2s, &g_wm8776info); if (!wm8776) diff --git a/drivers/audio/i2schar.c b/drivers/audio/i2schar.c index 7b412d6da11..c70b311a444 100644 --- a/drivers/audio/i2schar.c +++ b/drivers/audio/i2schar.c @@ -103,6 +103,8 @@ static ssize_t i2schar_read(FAR struct file *filep, FAR char *buffer, static ssize_t i2schar_write(FAR struct file *filep, FAR const char *buffer, size_t buflen); +static int i2schar_ioctl(FAR struct file *filep, int cmd, unsigned long arg); + /**************************************************************************** * Private Data ****************************************************************************/ @@ -114,7 +116,7 @@ static const struct file_operations i2schar_fops = i2schar_read, /* read */ i2schar_write, /* write */ NULL, /* seek */ - NULL, /* ioctl */ + i2schar_ioctl, /* ioctl */ #ifndef CONFIG_DISABLE_POLL NULL, /* poll */ #endif @@ -344,6 +346,39 @@ errout_with_reference: return ret; } + +/************************************************************************************ + * Name: i2char_ioctl + * + * Description: + * Perform I2S device ioctl if exists + * + ************************************************************************************/ + +static int i2schar_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct i2schar_dev_s *priv; + int ret = -ENOTTY; + + /* Get our private data structure */ + + DEBUGASSERT(filep); + + inode = filep->f_inode; + DEBUGASSERT(inode); + + priv = (FAR struct i2schar_dev_s *)inode->i_private; + DEBUGASSERT(priv && priv->i2s && priv->i2s->ops); + + if (priv->i2s->ops->i2s_ioctl) + { + ret = priv->i2s->ops->i2s_ioctl(priv->i2s, cmd, arg); + } + + return ret; +} + /**************************************************************************** * Public Functions ****************************************************************************/ diff --git a/include/nuttx/audio/i2s.h b/include/nuttx/audio/i2s.h index 21489271b38..ae38a714c71 100644 --- a/include/nuttx/audio/i2s.h +++ b/include/nuttx/audio/i2s.h @@ -223,6 +223,12 @@ struct i2s_ops_s CODE int (*i2s_send)(FAR struct i2s_dev_s *dev, FAR struct ap_buffer_s *apb, i2s_callback_t callback, FAR void *arg, uint32_t timeout); + + /* Ioctl */ + + CODE int (*i2s_ioctl)(FAR struct i2s_dev_s *dev, + int cmd, unsigned long arg); + }; /* I2S private data. This structure only defines the initial fields of the