| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734 |
- /*
- * Copyright (C) 2008-2009 by egnite GmbH
- * Copyright (C) 2001-2007 by egnite Software GmbH
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * For additional information see http://www.ethernut.de/
- */
- /*
- * $Id: spi_vscodec0.c 5472 2013-12-06 00:16:28Z olereinhardt $
- */
- #include <dev/gpio.h>
- #include <dev/irqreg.h>
- #include <dev/vscodec.h>
- #include <dev/spibus.h>
- #include <sys/event.h>
- #include <sys/timer.h>
- #include <sys/heap.h>
- #include <sys/nutdebug.h>
- #include <sys/bankmem.h>
- #include <stdlib.h>
- #include <string.h>
- #if defined(VSCODEC0_SIGNAL_IRQ) && defined(VSCODEC0_DREQ_BIT) && defined(VSCODEC0_XCS_BIT)
- #define VSCODEC0_CONFIGURED 1
- #endif
- #if VSCODEC0_CONFIGURED
- #ifndef VSCODEC0_DREQ_PORT
- #define VSCODEC0_DREQ_PORT 0
- #endif
- #ifndef VSCODEC0_XCS_PORT
- #define VSCODEC0_XCS_PORT 0
- #endif
- /*!
- * \addtogroup xgVsCodec
- */
- /*@{*/
- #ifndef NUT_THREAD_VSCODEC0STACK
- #if defined(__AVR__)
- #if defined(__GNUC__)
- /* avr-gcc optimized code used 88 bytes. */
- #define NUT_THREAD_VSCODEC0STACK 128
- #else
- /* icc-avr stack usage is unknown. */
- #define NUT_THREAD_VSCODEC0STACK 384
- #endif
- #else
- /* arm-elf-gcc optimized code used 112 bytes. */
- #define NUT_THREAD_VSCODEC0STACK 192
- #endif
- #endif
- #ifndef VSCODEC0_HWRST_DURATION
- /*! \brief Minimum time in milliseconds to held hardware reset low. */
- #define VSCODEC0_HWRST_DURATION 1
- #endif
- #ifndef VSCODEC0_FREQ
- /*! \brief Decoder crystal frequency. */
- #define VSCODEC0_FREQ 12288000UL
- #endif
- #ifndef VSCODEC0_SPI_RATE
- /*! \brief Decoder's initial SPI rate. */
- #define VSCODEC0_SPI_RATE (VSCODEC0_FREQ / 8)
- #endif
- #ifndef VSCODEC0_SPI_MODE
- /*! \brief Decoder's SPI mode. */
- #define VSCODEC0_SPI_MODE SPI_MODE_0
- #endif
- #ifndef VSCODEC0_SPIBUS_WAIT
- /*! \brief Number of milliseconds to wait for SPI bus timeout. */
- #define VSCODEC0_SPIBUS_WAIT NUT_WAIT_INFINITE
- #endif
- #ifndef VSCODEC0_MAX_OUTPUT_BUFSIZ
- /*! \brief Output buffer size limit. */
- #define VSCODEC0_MAX_OUTPUT_BUFSIZ 16384
- #endif
- /*
- * Determine interrupt settings.
- */
- #if (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT0)
- #define VSCODEC0_DREQ_SIGNAL sig_INTERRUPT0
- #elif (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT1)
- #define VSCODEC0_DREQ_SIGNAL sig_INTERRUPT1
- #elif (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT2)
- #define VSCODEC0_DREQ_SIGNAL sig_INTERRUPT2
- #elif (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT3)
- #define VSCODEC0_DREQ_SIGNAL sig_INTERRUPT3
- #elif (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT4)
- #define VSCODEC0_DREQ_SIGNAL sig_INTERRUPT4
- #elif (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT5)
- #define VSCODEC0_DREQ_SIGNAL sig_INTERRUPT5
- #elif (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT6)
- #define VSCODEC0_DREQ_SIGNAL sig_INTERRUPT6
- #elif (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT7)
- #define VSCODEC0_DREQ_SIGNAL sig_INTERRUPT7
- #endif
- /*!
- * \brief VS10xx SPI node implementation structure.
- */
- static NUTSPINODE nodeSpiVsCodec0 = {
- NULL, /*!< \brief Pointer to the bus controller driver, node_bus. */
- NULL, /*!< \brief Pointer to device driver specific settings, node_stat. */
- VSCODEC0_SPI_RATE, /*!< \brief Initial clock rate, node_rate. */
- VSCODEC0_SPI_MODE, /*!< \brief Initial mode, node_mode. */
- 8, /*!< \brief Initial data bits, node_bits. */
- 0 /*!< \brief Chip select, node_cs. */
- };
- static VSDCB dcbVsCodec0;
- /*
- * VLSI codec 0 interrupt handler.
- *
- * \param arg Pointer to an event queue.
- */
- static void VsCodec0Interrupt(void *arg)
- {
- NutEventPostFromIrq((void **)arg);
- }
- /*!
- * \brief Check if codec 0 is ready.
- *
- * \return 0 if not.
- */
- static int VsCodec0IsReady(void)
- {
- return GpioPinGet(VSCODEC0_DREQ_PORT, VSCODEC0_DREQ_BIT) != 0;
- }
- /*
- * \brief Write to command channel of codec 0.
- *
- * This routine will not check the DREQ line.
- *
- * \param cmd Points to the buffer. On entry it contains the data to
- * send. On exit it will contain the data received from
- * the chip.
- * \param len Number of bytes to send and receive.
- */
- static int VsCodec0SendCmd(void *cmd, size_t len)
- {
- int rc;
- /* Allocate the SPI bus. */
- rc = (*nodeSpiVsCodec0.node_bus->bus_alloc) (&nodeSpiVsCodec0, VSCODEC0_SPIBUS_WAIT);
- if (rc == 0) {
- /* Activate chip selects. */
- #if defined(VSCODEC0_VSCS_PORT) && defined(VSCODEC0_VSCS_BIT)
- GpioPinSetLow(VSCODEC0_VSCS_PORT, VSCODEC0_VSCS_BIT);
- #endif
- GpioPinSetLow(VSCODEC0_XCS_PORT, VSCODEC0_XCS_BIT);
- /* Send command bytes and receive response. */
- rc = (*nodeSpiVsCodec0.node_bus->bus_transfer) (&nodeSpiVsCodec0, cmd, cmd, len);
- /* Dectivate chip selects. */
- GpioPinSetHigh(VSCODEC0_XCS_PORT, VSCODEC0_XCS_BIT);
- #if defined(VSCODEC0_VSCS_PORT) && defined(VSCODEC0_VSCS_BIT)
- GpioPinSetHigh(VSCODEC0_VSCS_PORT, VSCODEC0_VSCS_BIT);
- #endif
- /* Release the SPI bus. */
- (*nodeSpiVsCodec0.node_bus->bus_release) (&nodeSpiVsCodec0);
- }
- return rc;
- }
- /*
- * \brief Write to command channel of codec 0.
- *
- * This routine will not check the DREQ line.
- *
- * \param cmd Points to the buffer. On entry it contains the data to
- * send. On exit it will contain the data received from
- * the chip.
- * \param len Number of bytes to send and receive.
- */
- static int VsCodec0RecvData(void *buf, size_t len)
- {
- int rc;
- uint8_t *bp = (uint8_t *) buf;
- const uint8_t cmd[4] = { VS_OPCODE_READ, VS_HDAT0_REG, 0xFF, 0xFF };
- uint8_t rsp[4];
- VsCodecWaitReady(&devSpiVsCodec0, VSCODEC_CMD_TIMEOUT);
- //(*nodeSpiVsCodec0.node_bus->bus_set_rate) (&nodeSpiVsCodec0, 20000000);
- /* Allocate the SPI bus. */
- rc = (*nodeSpiVsCodec0.node_bus->bus_alloc) (&nodeSpiVsCodec0, VSCODEC0_SPIBUS_WAIT);
- if (rc == 0) {
- len >>= 1;
- while (len--) {
- /* Activate chip selects. */
- #if defined(VSCODEC0_VSCS_PORT) && defined(VSCODEC0_VSCS_BIT)
- GpioPinSetLow(VSCODEC0_VSCS_PORT, VSCODEC0_VSCS_BIT);
- #endif
- GpioPinSetLow(VSCODEC0_XCS_PORT, VSCODEC0_XCS_BIT); /* XCS=PA31 */
- /* Send command bytes and receive response. */
- rc = (*nodeSpiVsCodec0.node_bus->bus_transfer) (&nodeSpiVsCodec0, cmd, rsp, 4);
- /* Deactivate chip selects. */
- GpioPinSetHigh(VSCODEC0_XCS_PORT, VSCODEC0_XCS_BIT);
- #if defined(VSCODEC0_VSCS_PORT) && defined(VSCODEC0_VSCS_BIT)
- GpioPinSetHigh(VSCODEC0_VSCS_PORT, VSCODEC0_VSCS_BIT);
- #endif
- *bp++ = rsp[2];
- *bp++ = rsp[3];
- }
- /* Release the SPI bus. */
- (*nodeSpiVsCodec0.node_bus->bus_release) (&nodeSpiVsCodec0);
- }
- return rc;
- }
- /*
- * \brief Write data to the decoder.
- *
- * Data is sent in fixed chunks. The first one is sent without
- * checking the DREQ line. Any subsequent chunk is sent only if
- * the DREQ line is still high.
- *
- * \param node Specifies the SPI node.
- * \param buf Points to the data. May be NULL, in which case the routine
- * will send the specified number of zeros.
- * \param len Number of bytes to send.
- *
- * \return The number of bytes actually sent. This may be less than the
- * specified data length. Zero is returned in case of an error.
- */
- static int VsCodec0SendData(const uint8_t *buf, size_t len)
- {
- int rc = 0;
- const uint8_t *bp;
- size_t chunk;
- /* Allocate the SPI bus. */
- if ((*nodeSpiVsCodec0.node_bus->bus_alloc) (&nodeSpiVsCodec0, VSCODEC0_SPIBUS_WAIT) == 0) {
- #if defined(VSCODEC0_VSCS_PORT) && defined(VSCODEC0_VSCS_BIT)
- /* Activate optional VSCS line. */
- GpioPinSetLow(VSCODEC0_VSCS_PORT, VSCODEC0_VSCS_BIT);
- #endif
- #if defined(VSCODEC0_XDCS_PORT) && defined(VSCODEC0_XDCS_BIT)
- /* Activate optional XDCS line. */
- GpioPinSetLow(VSCODEC0_XDCS_PORT, VSCODEC0_XDCS_BIT);
- #endif
- /* Set our internal buffer pointer, either to the start of the
- ** encoded data or to a chunk of zeros. */
- bp = buf ? buf : zero_chunk;
- /* Loop until all data had been sent or DREQ goes low. */
- while (len) {
- /* Determine chunk size. */
- chunk = len > VSCODEC_DATA_CHUNK_SIZE ? VSCODEC_DATA_CHUNK_SIZE : len;
- /* Send the chunk, exit on errors. */
- if ((*nodeSpiVsCodec0.node_bus->bus_transfer) (&nodeSpiVsCodec0, bp, NULL, chunk)) {
- break;
- }
- /* Update function result. */
- rc += chunk;
- /* Check if decoder is ready for more. Exit, if not. */
- if (!VsCodec0IsReady()) {
- break;
- }
- /* Update remaining number of bytes and buffer pointer. */
- len -= chunk;
- if (buf) {
- bp += chunk;
- }
- }
- #if defined(VSCODEC0_XDCS_PORT) && defined(VSCODEC0_XDCS_BIT)
- /* Deactivate optional XDCS line. */
- GpioPinSetHigh(VSCODEC0_XDCS_PORT, VSCODEC0_XDCS_BIT);
- #endif
- #if defined(VSCODEC0_VSCS_PORT) && defined(VSCODEC0_VSCS_BIT)
- /* Deactivate optional VSCS line. */
- GpioPinSetHigh(VSCODEC0_VSCS_PORT, VSCODEC0_VSCS_BIT);
- #endif
- /* Release the SPI bus. */
- (*nodeSpiVsCodec0.node_bus->bus_release) (&nodeSpiVsCodec0);
- }
- return rc;
- }
- /*!
- * \brief Handle I/O controls for audio codec.
- *
- * \param dev Specifies the audio codec device.
- *
- * \return 0 on success, -1 otherwise.
- */
- static int VsCodec0Control(int req, void *conf)
- {
- int rc = 0;
- uint32_t *lvp = (uint32_t *) conf;
- switch (req) {
- case AUDIO_SET_DECFMTS:
- /* Enable or disable specific decoder formats. */
- #if defined(VS_SM_LAYER12)
- if (*lvp & (AUDIO_FMT_MPEG1_L1 | AUDIO_FMT_MPEG1_L2)) {
- VsCodecMode(&devSpiVsCodec0, VS_SM_LAYER12, VS_SM_LAYER12);
- } else {
- VsCodecMode(&devSpiVsCodec0, 0, VS_SM_LAYER12);
- }
- #endif
- break;
- case AUDIO_GET_DECFMTS:
- /* Retrieve decoder formats. */
- *lvp = VS_DECODER_CAPS;
- #if defined(VS_SM_LAYER12)
- {
- uint16_t mode = VsCodecMode(&devSpiVsCodec0, 0, 0);
- if ((mode & VS_SM_LAYER12) == 0) {
- *lvp &= ~(AUDIO_FMT_MPEG1_L1 | AUDIO_FMT_MPEG1_L2);
- }
- }
- #endif
- break;
- case AUDIO_GET_CODFMTS:
- /* Retrieve encoder formats. */
- *lvp = VS_ENCODER_CAPS;
- #if defined(VS_SM_ADPCM)
- {
- uint16_t mode = VsCodecMode(&devSpiVsCodec0, 0, 0);
- if ((mode & VS_SM_ADPCM) == 0) {
- *lvp &= ~(AUDIO_FMT_WAV_ADPCM | AUDIO_FMT_WAV_IMA_ADPCM);
- }
- }
- #endif
- break;
- case AUDIO_SET_CODFMTS:
- /* Enable or disable specific encoder formats. */
- if (*lvp & AUDIO_FMT_VORBIS) {
- }
- break;
- case AUDIO_IRQ_ENABLE:
- if (*lvp) {
- NutIrqEnable(&VSCODEC0_DREQ_SIGNAL);
- } else {
- NutIrqDisable(&VSCODEC0_DREQ_SIGNAL);
- }
- break;
- default:
- rc = -1;
- break;
- }
- return rc;
- }
- /*!
- * \brief Set VLSI audio codec clock.
- *
- * \param dev Specifies the audio codec device.
- * \param xtal Clock at the chip's XTAL input in Hertz.
- * \param dreq If zero, then the routine will ignore the status of the
- * DREQ input. This is useful for early clock configuration
- * immediately after releasing hardware reset, but will be
- * ignored on chips earlier than VS103x.
- *
- * \return 0 on success, -1 otherwise.
- */
- static int VsCodec0SetClock(uint32_t xtal, uint_fast8_t dreq)
- {
- int rc = 0;
- #if VS_HAS_SC_X3FREQ
- /* This hardware got the new CLOCKF register layout. */
- if (dreq) {
- /* Honor the DREQ line, if requested. */
- VsCodecWaitReady(&devSpiVsCodec0, VSCODEC_CMD_TIMEOUT);
- }
- {
- uint8_t cmd[4] = { VS_OPCODE_WRITE, VS_CLOCKF_REG, 0, 0 };
- uint16_t freq = (uint16_t)((xtal - 8000000UL) / 4000UL);
- freq |= (VS_SC_MULT_3_5 | VS_SC_ADD_1_0);
- cmd[2] = (uint8_t) (freq >> 8);
- cmd[3] = (uint8_t) freq;
- rc = VsCodec0SendCmd(cmd, 4);
- }
- #else
- /* Old hardware, requires clock doubler with lower frequence crystal. */
- if (xtal < 20000000UL) {
- VsCodecReg(&devSpiVsCodec0, VS_OPCODE_WRITE, VS_CLOCKF_REG, (uint16_t)(VS_CF_DOUBLER | (xtal / 2000UL)));
- } else {
- VsCodecReg(&devSpiVsCodec0, VS_OPCODE_WRITE, VS_CLOCKF_REG, (uint16_t)(xtal / 2000UL));
- }
- #endif
- /* Force frequency change (see VS1001 datasheet). */
- #if defined(AUDIO0_VS1001K)
- VsCodecReg(&devSpiVsCodec0, VS_OPCODE_WRITE, VS_INT_FCTLH_REG, 0x8008);
- #elif defined(AUDIO0_VSAUTO) && defined(VS_INT_FCTLH_REG)
- if (dcbVsCodec0.dcb_codec_ver == 1001) {
- VsCodecReg(&devSpiVsCodec0, VS_OPCODE_WRITE, VS_INT_FCTLH_REG, 0x8008);
- }
- #endif
- /* With higher clock we can increase the SPI rate. */
- if (rc == 0) {
- #if VS_HAS_SC_X3FREQ
- (*nodeSpiVsCodec0.node_bus->bus_set_rate) (&nodeSpiVsCodec0, xtal / 2);
- #endif
- }
- return rc;
- }
- /*!
- * \brief Detect VLSI audio codec version.
- *
- * If the codec type had been pre-configured, this routine will verify
- * the hardware. Otherwise it will try to determine the codec by reading
- * the version info in the status register.
- *
- * \param dev Specifies the audio codec device.
- *
- * \return 0 on success, -1 otherwise.
- */
- static int VsCodec0Detect(void)
- {
- int rc = -1;
- uint_fast16_t status;
- /*
- ** Verify the hardware if chip is pre-configured.
- */
- status = VsCodecReg(&devSpiVsCodec0, VS_OPCODE_READ, VS_STATUS_REG, 0);
- #if defined(AUDIO0_VS1001K)
- if ((status & VS_SS_VER) == (VS1001_SS_VER << VS_SS_VER_LSB)) {
- dcbVsCodec0.dcb_codec_ver = 1001;
- dcbVsCodec0.dcb_codec_rev = 'K';
- rc = 0;
- }
- #elif defined(AUDIO0_VS1011E)
- if ((status & VS_SS_VER) == (VS1011E_SS_VER << VS_SS_VER_LSB)) {
- dcbVsCodec0.dcb_codec_ver = 1011;
- dcbVsCodec0.dcb_codec_rev = 'E';
- rc = 0;
- }
- #elif defined(AUDIO0_VS1002D)
- if ((status & VS_SS_VER) == (VS1002_SS_VER << VS_SS_VER_LSB)) {
- dcbVsCodec0.dcb_codec_ver = 1002;
- dcbVsCodec0.dcb_codec_rev = 'D';
- rc = 0;
- }
- #elif defined(AUDIO0_VS1003B)
- if ((status & VS_SS_VER) == (VS1003_SS_VER << VS_SS_VER_LSB)) {
- dcbVsCodec0.dcb_codec_ver = 1003;
- dcbVsCodec0.dcb_codec_rev = 'B';
- rc = 0;
- }
- #elif defined(AUDIO0_VS1033C)
- if ((status & VS_SS_VER) == (VS1033_SS_VER << VS_SS_VER_LSB)) {
- dcbVsCodec0.dcb_codec_ver = 1033;
- dcbVsCodec0.dcb_codec_rev = 'C';
- rc = 0;
- }
- #elif defined(AUDIO0_VS1053B)
- if ((status & VS_SS_VER) == (VS1053_SS_VER << VS_SS_VER_LSB)) {
- dcbVsCodec0.dcb_codec_ver = 1053;
- dcbVsCodec0.dcb_codec_rev = 'B';
- rc = 0;
- }
- #elif defined(AUDIO0_VS1063A)
- if ((status & VS_SS_VER) == (VS1063_SS_VER << VS_SS_VER_LSB)) {
- dcbVsCodec0.dcb_codec_ver = 1063;
- dcbVsCodec0.dcb_codec_rev = 'A';
- rc = 0;
- }
- #else
- /*
- ** If not configured, try to figure it out.
- */
- rc = 0;
- switch ((status & VS_SS_VER) >> VS_SS_VER_LSB) {
- case VS1001_SS_VER:
- dcbVsCodec0.dcb_codec_ver = 1001;
- break;
- case VS1011_SS_VER:
- dcbVsCodec0.dcb_codec_ver = 1011;
- break;
- case VS1002_SS_VER:
- if (VsCodecReg(&devSpiVsCodec0, VS_OPCODE_READ, VS_MODE_REG, 0) & VS_SM_SDINEW) {
- dcbVsCodec0.dcb_codec_ver = 1002;
- } else {
- dcbVsCodec0.dcb_codec_ver = 1011;
- dcbVsCodec0.dcb_codec_rev = 'E';
- }
- break;
- case VS1003_SS_VER:
- dcbVsCodec0.dcb_codec_ver = 1003;
- break;
- case VS1053_SS_VER:
- dcbVsCodec0.dcb_codec_ver = 1053;
- break;
- case VS1033_SS_VER:
- dcbVsCodec0.dcb_codec_ver = 1033;
- break;
- case VS1103_SS_VER:
- dcbVsCodec0.dcb_codec_ver = 1103;
- break;
- default:
- rc = -1;
- break;
- }
- #endif
- return rc;
- }
- /*!
- * \brief VS10XX hardware reset.
- *
- * This routine requires, that the codecs reset line is tied to a GPIO
- * pin. However, VsCodec0ResetHardware(0) may be called during system boot
- * to recover from power-on reset.
- *
- * \param dev Specifies the audio codec device.
- * \param on If zero, the hardware reset will be released. Otherwise
- * the reset is activated.
- */
- static int VsCodec0ResetHardware(int on)
- {
- if (on) {
- /*
- ** Activate reset.
- */
- #if defined(VSCODEC0_XRESET_PORT) && defined(VSCODEC0_XRESET_BIT)
- /* Activate the reset line. */
- GpioPinSetLow(VSCODEC0_XRESET_PORT, VSCODEC0_XRESET_BIT);
- GpioPinConfigSet(VSCODEC0_XRESET_PORT, VSCODEC0_XRESET_BIT, GPIO_CFG_OUTPUT);
- NutSleep(VSCODEC0_HWRST_DURATION);
- #else
- return -1;
- #endif
- } else {
- /*
- ** Deactivate reset.
- */
- uint_fast8_t clkset = 0;
- #if defined(VSCODEC0_XRESET_PORT) && defined(VSCODEC0_XRESET_BIT)
- /* Release the reset line. */
- GpioPinSetHigh(VSCODEC0_XRESET_PORT, VSCODEC0_XRESET_BIT);
- #if VSCODEC0_FREQ >= 24000000UL
- /* With input clocks equal or above 24MHz we must set CLOCKF early
- ** and must not wait for rising DREQ. */
- csrc = VsCodec0SetClock(VSCODEC0_FREQ, 0) == 0;
- #endif /* VSCODEC0_FREQ */
- #endif /* VSCODEC0_XRESET_PORT */
- #if VSCODEC0_HWRST_RECOVER
- /* Optional delay after hardware reset. */
- NutSleep(VSCODEC0_HWRST_RECOVER);
- #endif
- /* Chip hardware detection. */
- if (VsCodec0Detect()) {
- return -1;
- }
- #if !defined(AUDIO0_VS1001K)
- if (dcbVsCodec0.dcb_codec_ver != 1001) {
- #if VS_HAS_SM_SDINEW
- #if defined(VSCODEC0_XDCS_PORT) && defined(VSCODEC0_XDCS_BIT)
- VsCodecMode(&devSpiVsCodec0, VS_SM_SDINEW, VS_SM_SDINEW);
- #else
- VsCodecMode(&devSpiVsCodec0, VS_SM_SDINEW | VS_SM_SDISHARE, VS_SM_SDINEW | VS_SM_SDISHARE);
- #endif
- #endif /* VS_HAS_SM_SDINEW */
- }
- #endif /* AUDIO0_VS1001K */
- /* Set clock now, if not done successfully before. */
- if (!clkset) {
- VsCodec0SetClock(VSCODEC0_FREQ, 1);
- }
- }
- return 0;
- }
- /*
- * Called via dev_init pointer when the device is registered.
- *
- * \param dev Specifies the audio codec device.
- *
- * \return 0 on success, -1 otherwise.
- */
- static int VsCodec0Init(NUTDEVICE * dev)
- {
- size_t avail;
- /* Activate hardware reset. */
- VsCodec0ResetHardware(1);
- /* Set function pointers. */
- dcbVsCodec0.dcb_isready = VsCodec0IsReady;
- dcbVsCodec0.dcb_sendcmd = VsCodec0SendCmd;
- dcbVsCodec0.dcb_senddata = VsCodec0SendData;
- dcbVsCodec0.dcb_recvdata = VsCodec0RecvData;
- dcbVsCodec0.dcb_control = VsCodec0Control;
- /* Set capabilities. */
- #ifdef VS_DECODER_CAPS
- dcbVsCodec0.dcb_dec_caps = VS_DECODER_CAPS;
- #endif
- #ifdef VS_ENCODER_CAPS
- dcbVsCodec0.dcb_cod_caps = VS_ENCODER_CAPS;
- #endif
- #ifdef VS_MIDI_CAPS
- dcbVsCodec0.dcb_midi_caps = VS_MIDI_CAPS;
- #endif
- /* Initialize DREQ input. Will be later used as an external interupt. */
- GpioPinConfigSet(VSCODEC0_DREQ_PORT, VSCODEC0_DREQ_BIT, 0);
- /* Initialize chip selects, XCS and optional XDCS. */
- GpioPinSetHigh(VSCODEC0_XCS_PORT, VSCODEC0_XCS_BIT);
- GpioPinConfigSet(VSCODEC0_XCS_PORT, VSCODEC0_XCS_BIT, GPIO_CFG_OUTPUT);
- #if defined(VSCODEC0_XDCS_PORT) && defined(VSCODEC0_XDCS_BIT)
- GpioPinSetHigh(VSCODEC0_XDCS_PORT, VSCODEC0_XDCS_BIT);
- GpioPinConfigSet(VSCODEC0_XDCS_PORT, VSCODEC0_XDCS_BIT, GPIO_CFG_OUTPUT);
- #endif
- #if defined(VSCODEC0_VSCS_PORT) && defined(VSCODEC0_VSCS_BIT)
- GpioPinSetHigh(VSCODEC0_VSCS_PORT, VSCODEC0_VSCS_BIT);
- GpioPinConfigSet(VSCODEC0_VSCS_PORT, VSCODEC0_VSCS_BIT, GPIO_CFG_OUTPUT);
- #endif
- /* Register the DREQ interrupt routine. */
- NutRegisterIrqHandler(&VSCODEC0_DREQ_SIGNAL, VsCodec0Interrupt, &dcbVsCodec0.dcb_feedme);
- /* Rising edge will generate an interrupt. */
- GpioPinConfigSet(VSCODEC0_DREQ_PORT, VSCODEC0_DREQ_BIT, GPIO_CFG_DISABLED);
- NutIrqSetMode(&VSCODEC0_DREQ_SIGNAL, NUT_IRQMODE_RISINGEDGE);
- NutIrqEnable(&VSCODEC0_DREQ_SIGNAL);
- /* Deactivate hardware reset. */
- if (VsCodec0ResetHardware(0)) {
- /* Probably failed to detect the hardware. */
- return -1;
- }
- /*
- ** Initialize the decoder stream buffer.
- */
- #ifdef VSCODEC0_OUTPUT_BUFSIZ
- avail = VSCODEC0_OUTPUT_BUFSIZ;
- #else
- avail = NutHeapAvailable() / 2;
- if (avail > VSCODEC0_MAX_OUTPUT_BUFSIZ) {
- avail = VSCODEC0_MAX_OUTPUT_BUFSIZ;
- }
- #endif
- if (VsDecoderBufferInit(dev, avail)) {
- return -1;
- }
- /* Start the feeder thread. */
- if (NutThreadCreate(dev->dev_name, FeederThread, dev,
- (NUT_THREAD_VSCODEC0STACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD) == 0) {
- return -1;
- }
- return 0;
- }
- /*!
- * \brief VS10XX device information structure.
- *
- * An application must pass a pointer to this structure to
- * NutRegisterDevice() before using this driver.
- *
- * The device is named \b audio0.
- *
- * \showinitializer
- */
- NUTDEVICE devSpiVsCodec0 = {
- 0, /* Pointer to next device, dev_next. */
- {'a', 'u', 'd', 'i', 'o', '0', 0, 0, 0}, /* Unique device name, dev_name. */
- IFTYP_CHAR, /* Type of device, dev_type. */
- 0, /* Codec number, dev_base. */
- 0, /* First interrupt number, dev_irq (not used). */
- &nodeSpiVsCodec0, /* Interface control block, dev_icb (not used). */
- &dcbVsCodec0, /* Driver control block, dev_dcb. */
- VsCodec0Init, /* Driver initialization routine, dev_init. */
- VsCodecIOCtl, /* Driver specific control function, dev_ioctl. */
- VsCodecRead, /* Read from device, dev_read. */
- VsCodecWrite, /* Write to device, dev_write. */
- #ifdef __HARVARD_ARCH__
- VsCodecWrite_P, /* Write data from program space to device, dev_write_P. */
- #endif
- VsCodecOpen, /* Open a device or file, dev_open. */
- VsCodecClose, /* Close a device or file, dev_close. */
- NULL, /* Request file size, dev_size. */
- NULL, /* Select function, optional, not yet implemented */
- };
- /*@}*/
- #endif
|