Nut/OS  4.10.3
API Reference
spi_vscodec0.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008-2009 by egnite GmbH
00003  * Copyright (C) 2001-2007 by egnite Software GmbH
00004  *
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted provided that the following conditions
00009  * are met:
00010  *
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  * 3. Neither the name of the copyright holders nor the names of
00017  *    contributors may be used to endorse or promote products derived
00018  *    from this software without specific prior written permission.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00021  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00022  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00023  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00024  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00025  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00026  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00027  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00028  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00029  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00030  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00031  * SUCH DAMAGE.
00032  *
00033  * For additional information see http://www.ethernut.de/
00034  */
00035 
00036 /*
00037  * $Id: spi_vscodec0.c 2702 2009-09-17 11:01:21Z haraldkipp $
00038  */
00039 
00040 #include <dev/gpio.h>
00041 #include <dev/irqreg.h>
00042 #include <dev/vscodec.h>
00043 #include <dev/spibus.h>
00044 
00045 #include <sys/event.h>
00046 #include <sys/timer.h>
00047 #include <sys/heap.h>
00048 #include <sys/nutdebug.h>
00049 #include <sys/bankmem.h>
00050 
00051 #include <stdlib.h>
00052 #include <string.h>
00053 
00054 #if defined(VSCODEC0_SIGNAL_IRQ) && defined(VSCODEC0_DREQ_BIT) && defined(VSCODEC0_XCS_BIT)
00055 #define VSCODEC0_CONFIGURED 1
00056 #endif
00057 
00058 #if VSCODEC0_CONFIGURED
00059 
00060 #ifndef VSCODEC0_DREQ_PORT
00061 #define VSCODEC0_DREQ_PORT  0
00062 #endif
00063 #ifndef VSCODEC0_XCS_PORT
00064 #define VSCODEC0_XCS_PORT   0
00065 #endif
00066 
00071 
00072 #ifndef NUT_THREAD_VSCODEC0STACK
00073 #if defined(__AVR__)
00074 #if defined(__GNUC__)
00075 /* avr-gcc optimized code used 88 bytes. */
00076 #define NUT_THREAD_VSCODEC0STACK    128
00077 #else
00078 /* icc-avr stack usage is unknown. */
00079 #define NUT_THREAD_VSCODEC0STACK    384
00080 #endif
00081 #else
00082 /* arm-elf-gcc optimized code used 112 bytes. */
00083 #define NUT_THREAD_VSCODEC0STACK    192
00084 #endif
00085 #endif
00086 
00087 #ifndef VSCODEC0_HWRST_DURATION
00088 
00089 #define VSCODEC0_HWRST_DURATION     1
00090 #endif
00091 
00092 #ifndef VSCODEC0_FREQ
00093 
00094 #define VSCODEC0_FREQ               12288000UL
00095 #endif
00096 
00097 #ifndef VSCODEC0_SPI_RATE
00098 
00099 #define VSCODEC0_SPI_RATE           (VSCODEC0_FREQ / 8)
00100 #endif
00101 
00102 #ifndef VSCODEC0_SPI_MODE
00103 
00104 #define VSCODEC0_SPI_MODE           SPI_MODE_0
00105 #endif
00106 
00107 #ifndef VSCODEC0_SPIBUS_WAIT
00108 
00109 #define VSCODEC0_SPIBUS_WAIT        NUT_WAIT_INFINITE
00110 #endif
00111 
00112 #ifndef VSCODEC0_MAX_OUTPUT_BUFSIZ
00113 
00114 #define VSCODEC0_MAX_OUTPUT_BUFSIZ  16384
00115 #endif
00116 
00117 /*
00118  * Determine interrupt settings.
00119  */
00120 #if (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT0)
00121 #define VSCODEC0_DREQ_SIGNAL  sig_INTERRUPT0
00122 #elif (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT1)
00123 #define VSCODEC0_DREQ_SIGNAL  sig_INTERRUPT1
00124 #elif (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT2)
00125 #define VSCODEC0_DREQ_SIGNAL  sig_INTERRUPT2
00126 #elif (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT3)
00127 #define VSCODEC0_DREQ_SIGNAL  sig_INTERRUPT3
00128 #elif (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT4)
00129 #define VSCODEC0_DREQ_SIGNAL  sig_INTERRUPT4
00130 #elif (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT5)
00131 #define VSCODEC0_DREQ_SIGNAL  sig_INTERRUPT5
00132 #elif (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT6)
00133 #define VSCODEC0_DREQ_SIGNAL  sig_INTERRUPT6
00134 #elif (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT7)
00135 #define VSCODEC0_DREQ_SIGNAL  sig_INTERRUPT7
00136 #endif
00137 
00141 static NUTSPINODE nodeSpiVsCodec0 = {
00142     NULL,               
00143     NULL,               
00144     VSCODEC0_SPI_RATE,  
00145     VSCODEC0_SPI_MODE,  
00146     8,                  
00147     0                   
00148 };
00149 
00150 static VSDCB dcbVsCodec0;
00151 
00152 /*
00153  * VLSI codec 0 interrupt handler.
00154  *
00155  * \param arg Pointer to an event queue.
00156  */
00157 static void VsCodec0Interrupt(void *arg)
00158 {
00159     NutEventPostFromIrq((void **)arg);
00160 }
00161 
00167 static int VsCodec0IsReady(void)
00168 {
00169     return GpioPinGet(VSCODEC0_DREQ_PORT, VSCODEC0_DREQ_BIT) != 0;
00170 }
00171 
00172 /*
00173  * \brief Write to command channel of codec 0.
00174  *
00175  * This routine will not check the DREQ line.
00176  *
00177  * \param cmd  Points to the buffer. On entry it contains the data to 
00178  *             send. On exit it will contain the data received from
00179  *             the chip.
00180  * \param len  Number of bytes to send and receive.
00181  */
00182 static int VsCodec0SendCmd(void *cmd, size_t len)
00183 {
00184     int rc;
00185 
00186     /* Allocate the SPI bus. */
00187     rc = (*nodeSpiVsCodec0.node_bus->bus_alloc) (&nodeSpiVsCodec0, VSCODEC0_SPIBUS_WAIT);
00188     if (rc == 0) {
00189         /* Activate chip selects. */
00190 #if defined(VSCODEC0_VSCS_PORT) && defined(VSCODEC0_VSCS_BIT)
00191         GpioPinSetLow(VSCODEC0_VSCS_PORT, VSCODEC0_VSCS_BIT);
00192 #endif
00193         GpioPinSetLow(VSCODEC0_XCS_PORT, VSCODEC0_XCS_BIT);
00194         /* Send command bytes and receive response. */
00195         rc = (*nodeSpiVsCodec0.node_bus->bus_transfer) (&nodeSpiVsCodec0, cmd, cmd, len);
00196         /* Dectivate chip selects. */
00197         GpioPinSetHigh(VSCODEC0_XCS_PORT, VSCODEC0_XCS_BIT);
00198 #if defined(VSCODEC0_VSCS_PORT) && defined(VSCODEC0_VSCS_BIT)
00199         GpioPinSetHigh(VSCODEC0_VSCS_PORT, VSCODEC0_VSCS_BIT);
00200 #endif
00201         /* Release the SPI bus. */
00202         (*nodeSpiVsCodec0.node_bus->bus_release) (&nodeSpiVsCodec0);
00203     }
00204     return rc;
00205 }
00206 
00207 /*
00208  * \brief Write data to the decoder.
00209  *
00210  * Data is sent in fixed chunks. The first one is sent without
00211  * checking the DREQ line. Any subsequent chunk is sent only if
00212  * the DREQ line is still high.
00213  *
00214  * \param node Specifies the SPI node.
00215  * \param buf  Points to the data. May be NULL, in which case the routine
00216  *             will send the specified number of zeros.
00217  * \param len  Number of bytes to send.
00218  *
00219  * \return The number of bytes actually sent. This may be less than the
00220  *         specified data length. Zero is returned in case of an error.
00221  */
00222 static int VsCodec0SendData(CONST uint8_t *buf, size_t len)
00223 {
00224     int rc = 0;
00225     CONST uint8_t *bp;
00226     size_t chunk;
00227 
00228     /* Allocate the SPI bus. */
00229     if ((*nodeSpiVsCodec0.node_bus->bus_alloc) (&nodeSpiVsCodec0, VSCODEC0_SPIBUS_WAIT) == 0) {
00230 #if defined(VSCODEC0_VSCS_PORT) && defined(VSCODEC0_VSCS_BIT)
00231         /* Activate optional VSCS line. */
00232         GpioPinSetLow(VSCODEC0_VSCS_PORT, VSCODEC0_VSCS_BIT);
00233 #endif
00234 #if defined(VSCODEC0_XDCS_PORT) && defined(VSCODEC0_XDCS_BIT)
00235         /* Activate optional XDCS line. */
00236         GpioPinSetLow(VSCODEC0_XDCS_PORT, VSCODEC0_XDCS_BIT);
00237 #endif
00238         /* Set our internal buffer pointer, either to the start of the 
00239         ** encoded data or to a chunk of zeros. */
00240         bp = buf ? buf : zero_chunk;
00241         /* Loop until all data had been sent or DREQ goes low. */
00242         while (len) {
00243             /* Determine chunk size. */
00244             chunk = len > VSCODEC_DATA_CHUNK_SIZE ? VSCODEC_DATA_CHUNK_SIZE : len;
00245             /* Send the chunk, exit on errors. */
00246             if ((*nodeSpiVsCodec0.node_bus->bus_transfer) (&nodeSpiVsCodec0, bp, NULL, chunk)) {
00247                 break;
00248             }
00249             /* Update function result. */
00250             rc += chunk;
00251             /* Check if decoder is ready for more. Exit, if not. */
00252             if (!VsCodec0IsReady()) {
00253                 break;
00254             }
00255             /* Update remaining number of bytes and buffer pointer. */
00256             len -= chunk;
00257             if (buf) {
00258                 bp += chunk;
00259             }
00260         }
00261 #if defined(VSCODEC0_XDCS_PORT) && defined(VSCODEC0_XDCS_BIT)
00262         /* Deactivate optional XDCS line. */
00263         GpioPinSetHigh(VSCODEC0_XDCS_PORT, VSCODEC0_XDCS_BIT);
00264 #endif
00265 #if defined(VSCODEC0_VSCS_PORT) && defined(VSCODEC0_VSCS_BIT)
00266         /* Deactivate optional VSCS line. */
00267         GpioPinSetHigh(VSCODEC0_VSCS_PORT, VSCODEC0_VSCS_BIT);
00268 #endif
00269         /* Release the SPI bus. */
00270         (*nodeSpiVsCodec0.node_bus->bus_release) (&nodeSpiVsCodec0);
00271     }
00272     return rc;
00273 }
00274 
00282 static int VsCodec0Control(int req, void *conf)
00283 {
00284     int rc = 0;
00285     uint32_t *lvp = (uint32_t *) conf;
00286 
00287     switch (req) {
00288     case AUDIO_SET_DECFMTS:
00289         /* Enable or disable specific decoder formats. */
00290 #if defined(VS_SM_LAYER12)
00291         if (*lvp & (AUDIO_FMT_MPEG1_L1 | AUDIO_FMT_MPEG1_L2)) {
00292             VsCodecMode(&devSpiVsCodec0, VS_SM_LAYER12, VS_SM_LAYER12);
00293         } else {
00294             VsCodecMode(&devSpiVsCodec0, 0, VS_SM_LAYER12);
00295         }
00296 #endif
00297         break;
00298     case AUDIO_GET_DECFMTS:
00299         /* Retrieve decoder formats. */
00300         *lvp = VS_DECODER_CAPS;
00301 #if defined(VS_SM_LAYER12)
00302         {
00303             uint16_t mode = VsCodecMode(&devSpiVsCodec0, 0, 0);
00304 
00305             if ((mode & VS_SM_LAYER12) == 0) {
00306                 *lvp &= ~(AUDIO_FMT_MPEG1_L1 | AUDIO_FMT_MPEG1_L2);
00307             }
00308         }
00309 #endif
00310         break;
00311     case AUDIO_GET_CODFMTS:
00312         /* Retrieve encoder formats. */
00313         *lvp = VS_ENCODER_CAPS;
00314 #if defined(VS_SM_ADPCM)
00315         {
00316             uint16_t mode = VsCodecMode(&devSpiVsCodec0, 0, 0);
00317 
00318             if ((mode & VS_SM_ADPCM) == 0) {
00319                 *lvp &= ~(AUDIO_FMT_WAV_ADPCM | AUDIO_FMT_WAV_IMA_ADPCM);
00320             }
00321         }
00322 #endif
00323         break;
00324     case AUDIO_SET_CODFMTS:
00325         /* Enable or disable specific encoder formats. */
00326         if (*lvp & AUDIO_FMT_VORBIS) {
00327         }
00328         break;
00329     case AUDIO_IRQ_ENABLE:
00330         if (*lvp) {
00331             NutIrqEnable(&VSCODEC0_DREQ_SIGNAL);
00332         } else {
00333             NutIrqDisable(&VSCODEC0_DREQ_SIGNAL);
00334         }
00335         break;
00336     default:
00337         rc = -1;
00338         break;
00339     }
00340     return rc;
00341 }
00342 
00355 static int VsCodec0SetClock(uint32_t xtal, uint_fast8_t dreq)
00356 {
00357     int rc = 0;
00358 
00359 #if VS_HAS_SC_X3FREQ
00360     /* This hardware got the new CLOCKF register layout. */
00361     if (dreq) {
00362         /* Honor the DREQ line, if requested. */
00363         VsCodecWaitReady(&devSpiVsCodec0, VSCODEC_CMD_TIMEOUT);
00364     }
00365     {
00366         uint8_t cmd[4] = { VS_OPCODE_WRITE, VS_CLOCKF_REG, 0, 0 };
00367         uint16_t freq = (uint16_t)((xtal - 8000000UL) / 4000UL);
00368 
00369         freq |= (VS_SC_MULT_3_5 | VS_SC_ADD_1_0);
00370         cmd[2] = (uint8_t) (freq >> 8);
00371         cmd[3] = (uint8_t) freq;
00372         rc = VsCodec0SendCmd(cmd, 4);
00373     }
00374 #else
00375     /* Old hardware, requires clock doubler with lower frequence crystal. */
00376     if (xtal < 20000000UL) {
00377         VsCodecReg(&devSpiVsCodec0, VS_OPCODE_WRITE, VS_CLOCKF_REG, (uint16_t)(VS_CF_DOUBLER | (xtal / 2000UL)));
00378     } else {
00379         VsCodecReg(&devSpiVsCodec0, VS_OPCODE_WRITE, VS_CLOCKF_REG, (uint16_t)(xtal / 2000UL));
00380     }
00381 #endif
00382 
00383     /* Force frequency change (see VS1001 datasheet). */
00384 #if defined(AUDIO0_VS1001K)
00385     VsCodecReg(&devSpiVsCodec0, VS_OPCODE_WRITE, VS_INT_FCTLH_REG, 0x8008);
00386 #elif defined(AUDIO0_VSAUTO) && defined(VS_INT_FCTLH_REG)
00387     if (dcbVsCodec0.dcb_codec_ver == 1001) {
00388         VsCodecReg(&devSpiVsCodec0, VS_OPCODE_WRITE, VS_INT_FCTLH_REG, 0x8008);
00389     }
00390 #endif
00391 
00392     /* With higher clock we can increase the SPI rate. */
00393     if (rc == 0) {
00394 #if VS_HAS_SC_X3FREQ
00395         (*nodeSpiVsCodec0.node_bus->bus_set_rate) (&nodeSpiVsCodec0, xtal / 2);
00396 #endif
00397     }
00398     return rc;
00399 }
00400 
00412 static int VsCodec0Detect(void)
00413 {
00414     int rc = -1;
00415     uint_fast16_t status;
00416 
00417     /*
00418     ** Verify the hardware if chip is pre-configured.
00419     */
00420     status = VsCodecReg(&devSpiVsCodec0, VS_OPCODE_READ, VS_STATUS_REG, 0);
00421 #if defined(AUDIO0_VS1001K)
00422     if ((status & VS_SS_VER) == (VS1001_SS_VER << VS_SS_VER_LSB)) {
00423         dcbVsCodec0.dcb_codec_ver = 1001;
00424         dcbVsCodec0.dcb_codec_rev = 'K';
00425         rc = 0;
00426     }
00427 #elif defined(AUDIO0_VS1011E)
00428     if ((status & VS_SS_VER) == (VS1011E_SS_VER << VS_SS_VER_LSB)) {
00429         dcbVsCodec0.dcb_codec_ver = 1011;
00430         dcbVsCodec0.dcb_codec_rev = 'E';
00431         rc = 0;
00432     }
00433 #elif defined(AUDIO0_VS1002D)
00434     if ((status & VS_SS_VER) == (VS1002_SS_VER << VS_SS_VER_LSB)) {
00435         dcbVsCodec0.dcb_codec_ver = 1002;
00436         dcbVsCodec0.dcb_codec_rev = 'D';
00437         rc = 0;
00438     }
00439 #elif defined(AUDIO0_VS1003B)
00440     if ((status & VS_SS_VER) == (VS1003_SS_VER << VS_SS_VER_LSB)) {
00441         dcbVsCodec0.dcb_codec_ver = 1003;
00442         dcbVsCodec0.dcb_codec_rev = 'B';
00443         rc = 0;
00444     }
00445 #elif defined(AUDIO0_VS1033C)
00446     if ((status & VS_SS_VER) == (VS1033_SS_VER << VS_SS_VER_LSB)) {
00447         dcbVsCodec0.dcb_codec_ver = 1033;
00448         dcbVsCodec0.dcb_codec_rev = 'C';
00449         rc = 0;
00450     }
00451 #elif defined(AUDIO0_VS1053B)
00452     if ((status & VS_SS_VER) == (VS1053_SS_VER << VS_SS_VER_LSB)) {
00453         dcbVsCodec0.dcb_codec_ver = 1053;
00454         dcbVsCodec0.dcb_codec_rev = 'B';
00455         rc = 0;
00456     }
00457 #else
00458     /*
00459     ** If not configured, try to figure it out.
00460     */
00461     rc = 0;
00462     switch ((status & VS_SS_VER) >> VS_SS_VER_LSB) {
00463     case VS1001_SS_VER:
00464         dcbVsCodec0.dcb_codec_ver = 1001;
00465         break;
00466     case VS1011_SS_VER:
00467         dcbVsCodec0.dcb_codec_ver = 1011;
00468         break;
00469     case VS1002_SS_VER:
00470         if (VsCodecReg(&devSpiVsCodec0, VS_OPCODE_READ, VS_MODE_REG, 0) & VS_SM_SDINEW) {
00471             dcbVsCodec0.dcb_codec_ver = 1002;
00472         } else {
00473             dcbVsCodec0.dcb_codec_ver = 1011;
00474             dcbVsCodec0.dcb_codec_rev = 'E';
00475         }
00476         break;
00477     case VS1003_SS_VER:
00478         dcbVsCodec0.dcb_codec_ver = 1003;
00479         break;
00480     case VS1053_SS_VER:
00481         dcbVsCodec0.dcb_codec_ver = 1053;
00482         break;
00483     case VS1033_SS_VER:
00484         dcbVsCodec0.dcb_codec_ver = 1033;
00485         break;
00486     case VS1103_SS_VER:
00487         dcbVsCodec0.dcb_codec_ver = 1103;
00488         break;
00489     default:
00490         rc = -1;
00491         break;
00492     }
00493 #endif
00494     return rc;
00495 }
00496 
00508 static int VsCodec0ResetHardware(int on)
00509 {
00510     if (on) {
00511         /*
00512         ** Activate reset.
00513         */
00514 #if defined(VSCODEC0_XRESET_PORT) && defined(VSCODEC0_XRESET_BIT)
00515         /* Activate the reset line. */
00516         GpioPinSetLow(VSCODEC0_XRESET_PORT, VSCODEC0_XRESET_BIT);
00517         GpioPinConfigSet(VSCODEC0_XRESET_PORT, VSCODEC0_XRESET_BIT, GPIO_CFG_OUTPUT);
00518         NutSleep(VSCODEC0_HWRST_DURATION);
00519 #else
00520         return -1;
00521 #endif
00522     } else {
00523         /*
00524         ** Deactivate reset.
00525         */
00526         uint_fast8_t clkset = 0;
00527 
00528 #if defined(VSCODEC0_XRESET_PORT) && defined(VSCODEC0_XRESET_BIT)
00529         /* Release the reset line. */
00530         GpioPinSetHigh(VSCODEC0_XRESET_PORT, VSCODEC0_XRESET_BIT);
00531 #if VSCODEC0_FREQ >= 24000000UL
00532         /* With input clocks equal or above 24MHz we must set CLOCKF early 
00533         ** and must not wait for rising DREQ. */
00534         csrc = VsCodec0SetClock(VSCODEC0_FREQ, 0) == 0;
00535 #endif /* VSCODEC0_FREQ */
00536 #endif /* VSCODEC0_XRESET_PORT */
00537 
00538 #if VSCODEC0_HWRST_RECOVER
00539         /* Optional delay after hardware reset. */
00540         NutSleep(VSCODEC0_HWRST_RECOVER);
00541 #endif
00542         /* Chip hardware detection. */
00543         if (VsCodec0Detect()) {
00544             return -1;
00545         }
00546 #if !defined(AUDIO0_VS1001K)
00547         if (dcbVsCodec0.dcb_codec_ver != 1001) {
00548 #if VS_HAS_SM_SDINEW
00549 #if defined(VSCODEC0_XDCS_PORT) && defined(VSCODEC0_XDCS_BIT)
00550             VsCodecMode(&devSpiVsCodec0, VS_SM_SDINEW, VS_SM_SDINEW);
00551 #else
00552             VsCodecMode(&devSpiVsCodec0, VS_SM_SDINEW | VS_SM_SDISHARE, VS_SM_SDINEW | VS_SM_SDISHARE);
00553 #endif
00554 #endif /* VS_HAS_SM_SDINEW */
00555         }
00556 #endif /* AUDIO0_VS1001K */
00557 
00558         /* Set clock now, if not done successfully before. */
00559         if (!clkset) {
00560             VsCodec0SetClock(VSCODEC0_FREQ, 1);
00561         }
00562     }
00563     return 0;
00564 }
00565 
00566 
00567 /*
00568  * Called via dev_init pointer when the device is registered.
00569  *
00570  * \param dev Specifies the audio codec device.
00571  *
00572  * \return 0 on success, -1 otherwise.
00573  */
00574 static int VsCodec0Init(NUTDEVICE * dev)
00575 {
00576     size_t avail;
00577 
00578     /* Activate hardware reset. */
00579     VsCodec0ResetHardware(1);
00580 
00581     /* Set function pointers. */
00582     dcbVsCodec0.dcb_isready = VsCodec0IsReady;
00583     dcbVsCodec0.dcb_sendcmd = VsCodec0SendCmd;
00584     dcbVsCodec0.dcb_senddata = VsCodec0SendData;
00585     dcbVsCodec0.dcb_control = VsCodec0Control;
00586 
00587     /* Set capabilities. */
00588 #ifdef VS_DECODER_CAPS
00589     dcbVsCodec0.dcb_dec_caps = VS_DECODER_CAPS;
00590 #endif
00591 #ifdef VS_ENCODER_CAPS
00592     dcbVsCodec0.dcb_cod_caps = VS_ENCODER_CAPS;
00593 #endif
00594 #ifdef VS_MIDI_CAPS
00595     dcbVsCodec0.dcb_midi_caps = VS_MIDI_CAPS;
00596 #endif
00597 
00598     /* Initialize DREQ input. Will be later used as an external interupt. */
00599     GpioPinConfigSet(VSCODEC0_DREQ_PORT, VSCODEC0_DREQ_BIT, 0);
00600     /* Initialize chip selects, XCS and optional XDCS. */
00601     GpioPinSetHigh(VSCODEC0_XCS_PORT, VSCODEC0_XCS_BIT);
00602     GpioPinConfigSet(VSCODEC0_XCS_PORT, VSCODEC0_XCS_BIT, GPIO_CFG_OUTPUT);
00603 #if defined(VSCODEC0_XDCS_PORT) && defined(VSCODEC0_XDCS_BIT)
00604     GpioPinSetHigh(VSCODEC0_XDCS_PORT, VSCODEC0_XDCS_BIT);
00605     GpioPinConfigSet(VSCODEC0_XDCS_PORT, VSCODEC0_XDCS_BIT, GPIO_CFG_OUTPUT);
00606 #endif
00607 #if defined(VSCODEC0_VSCS_PORT) && defined(VSCODEC0_VSCS_BIT)
00608     GpioPinSetHigh(VSCODEC0_VSCS_PORT, VSCODEC0_VSCS_BIT);
00609     GpioPinConfigSet(VSCODEC0_VSCS_PORT, VSCODEC0_VSCS_BIT, GPIO_CFG_OUTPUT);
00610 #endif
00611 
00612     /* Register the DREQ interrupt routine. */
00613     NutRegisterIrqHandler(&VSCODEC0_DREQ_SIGNAL, VsCodec0Interrupt, &dcbVsCodec0.dcb_feedme);
00614 
00615     /* Rising edge will generate an interrupt. */
00616     GpioPinConfigSet(VSCODEC0_DREQ_PORT, VSCODEC0_DREQ_BIT, GPIO_CFG_DISABLED);
00617     NutIrqSetMode(&VSCODEC0_DREQ_SIGNAL, NUT_IRQMODE_RISINGEDGE);
00618     NutIrqEnable(&VSCODEC0_DREQ_SIGNAL);
00619 
00620     /* Deactivate hardware reset. */
00621     if (VsCodec0ResetHardware(0)) {
00622         /* Probably failed to detect the hardware. */
00623         return -1;
00624     }
00625 
00626     /*
00627     ** Initialize the decoder stream buffer.
00628     */
00629 #ifdef VSCODEC0_OUTPUT_BUFSIZ
00630     avail = VSCODEC0_OUTPUT_BUFSIZ;
00631 #else
00632     avail = NutHeapAvailable() / 2;
00633     if (avail > VSCODEC0_MAX_OUTPUT_BUFSIZ) {
00634         avail = VSCODEC0_MAX_OUTPUT_BUFSIZ;
00635     }
00636 #endif
00637     if (VsDecoderBufferInit(dev, avail)) {
00638         return -1;
00639     }
00640 
00641     /* Start the feeder thread. */
00642     if (NutThreadCreate(dev->dev_name, FeederThread, dev, 
00643         (NUT_THREAD_VSCODEC0STACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD) == 0) {
00644         return -1;
00645     }
00646     return 0;
00647 }
00648 
00659 NUTDEVICE devSpiVsCodec0 = {
00660     0,                  /* Pointer to next device, dev_next. */
00661     {'a', 'u', 'd', 'i', 'o', '0', 0, 0, 0},    /* Unique device name, dev_name. */
00662     IFTYP_CHAR,         /* Type of device, dev_type. */
00663     0,                  /* Codec number, dev_base. */
00664     0,                  /* First interrupt number, dev_irq (not used). */
00665     &nodeSpiVsCodec0,   /* Interface control block, dev_icb (not used). */
00666     &dcbVsCodec0,       /* Driver control block, dev_dcb. */
00667     VsCodec0Init,       /* Driver initialization routine, dev_init. */
00668     VsCodecIOCtl,       /* Driver specific control function, dev_ioctl. */
00669     VsCodecRead,        /* Read from device, dev_read. */
00670     VsCodecWrite,       /* Write to device, dev_write. */
00671 #ifdef __HARVARD_ARCH__
00672     VsCodecWrite_P,     /* Write data from program space to device, dev_write_P. */
00673 #endif
00674     VsCodecOpen,        /* Open a device or file, dev_open. */
00675     VsCodecClose,       /* Close a device or file, dev_close. */
00676     NULL                /* Request file size, dev_size. */
00677 };
00678 
00681 #endif