spi_vscodec0.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734
  1. /*
  2. * Copyright (C) 2008-2009 by egnite GmbH
  3. * Copyright (C) 2001-2007 by egnite Software GmbH
  4. *
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. * 3. Neither the name of the copyright holders nor the names of
  17. * contributors may be used to endorse or promote products derived
  18. * from this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  24. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  27. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  28. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  29. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  30. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. *
  33. * For additional information see http://www.ethernut.de/
  34. */
  35. /*
  36. * $Id: spi_vscodec0.c 5472 2013-12-06 00:16:28Z olereinhardt $
  37. */
  38. #include <dev/gpio.h>
  39. #include <dev/irqreg.h>
  40. #include <dev/vscodec.h>
  41. #include <dev/spibus.h>
  42. #include <sys/event.h>
  43. #include <sys/timer.h>
  44. #include <sys/heap.h>
  45. #include <sys/nutdebug.h>
  46. #include <sys/bankmem.h>
  47. #include <stdlib.h>
  48. #include <string.h>
  49. #if defined(VSCODEC0_SIGNAL_IRQ) && defined(VSCODEC0_DREQ_BIT) && defined(VSCODEC0_XCS_BIT)
  50. #define VSCODEC0_CONFIGURED 1
  51. #endif
  52. #if VSCODEC0_CONFIGURED
  53. #ifndef VSCODEC0_DREQ_PORT
  54. #define VSCODEC0_DREQ_PORT 0
  55. #endif
  56. #ifndef VSCODEC0_XCS_PORT
  57. #define VSCODEC0_XCS_PORT 0
  58. #endif
  59. /*!
  60. * \addtogroup xgVsCodec
  61. */
  62. /*@{*/
  63. #ifndef NUT_THREAD_VSCODEC0STACK
  64. #if defined(__AVR__)
  65. #if defined(__GNUC__)
  66. /* avr-gcc optimized code used 88 bytes. */
  67. #define NUT_THREAD_VSCODEC0STACK 128
  68. #else
  69. /* icc-avr stack usage is unknown. */
  70. #define NUT_THREAD_VSCODEC0STACK 384
  71. #endif
  72. #else
  73. /* arm-elf-gcc optimized code used 112 bytes. */
  74. #define NUT_THREAD_VSCODEC0STACK 192
  75. #endif
  76. #endif
  77. #ifndef VSCODEC0_HWRST_DURATION
  78. /*! \brief Minimum time in milliseconds to held hardware reset low. */
  79. #define VSCODEC0_HWRST_DURATION 1
  80. #endif
  81. #ifndef VSCODEC0_FREQ
  82. /*! \brief Decoder crystal frequency. */
  83. #define VSCODEC0_FREQ 12288000UL
  84. #endif
  85. #ifndef VSCODEC0_SPI_RATE
  86. /*! \brief Decoder's initial SPI rate. */
  87. #define VSCODEC0_SPI_RATE (VSCODEC0_FREQ / 8)
  88. #endif
  89. #ifndef VSCODEC0_SPI_MODE
  90. /*! \brief Decoder's SPI mode. */
  91. #define VSCODEC0_SPI_MODE SPI_MODE_0
  92. #endif
  93. #ifndef VSCODEC0_SPIBUS_WAIT
  94. /*! \brief Number of milliseconds to wait for SPI bus timeout. */
  95. #define VSCODEC0_SPIBUS_WAIT NUT_WAIT_INFINITE
  96. #endif
  97. #ifndef VSCODEC0_MAX_OUTPUT_BUFSIZ
  98. /*! \brief Output buffer size limit. */
  99. #define VSCODEC0_MAX_OUTPUT_BUFSIZ 16384
  100. #endif
  101. /*
  102. * Determine interrupt settings.
  103. */
  104. #if (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT0)
  105. #define VSCODEC0_DREQ_SIGNAL sig_INTERRUPT0
  106. #elif (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT1)
  107. #define VSCODEC0_DREQ_SIGNAL sig_INTERRUPT1
  108. #elif (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT2)
  109. #define VSCODEC0_DREQ_SIGNAL sig_INTERRUPT2
  110. #elif (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT3)
  111. #define VSCODEC0_DREQ_SIGNAL sig_INTERRUPT3
  112. #elif (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT4)
  113. #define VSCODEC0_DREQ_SIGNAL sig_INTERRUPT4
  114. #elif (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT5)
  115. #define VSCODEC0_DREQ_SIGNAL sig_INTERRUPT5
  116. #elif (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT6)
  117. #define VSCODEC0_DREQ_SIGNAL sig_INTERRUPT6
  118. #elif (VSCODEC0_SIGNAL_IRQ == NUTGPIO_EXTINT7)
  119. #define VSCODEC0_DREQ_SIGNAL sig_INTERRUPT7
  120. #endif
  121. /*!
  122. * \brief VS10xx SPI node implementation structure.
  123. */
  124. static NUTSPINODE nodeSpiVsCodec0 = {
  125. NULL, /*!< \brief Pointer to the bus controller driver, node_bus. */
  126. NULL, /*!< \brief Pointer to device driver specific settings, node_stat. */
  127. VSCODEC0_SPI_RATE, /*!< \brief Initial clock rate, node_rate. */
  128. VSCODEC0_SPI_MODE, /*!< \brief Initial mode, node_mode. */
  129. 8, /*!< \brief Initial data bits, node_bits. */
  130. 0 /*!< \brief Chip select, node_cs. */
  131. };
  132. static VSDCB dcbVsCodec0;
  133. /*
  134. * VLSI codec 0 interrupt handler.
  135. *
  136. * \param arg Pointer to an event queue.
  137. */
  138. static void VsCodec0Interrupt(void *arg)
  139. {
  140. NutEventPostFromIrq((void **)arg);
  141. }
  142. /*!
  143. * \brief Check if codec 0 is ready.
  144. *
  145. * \return 0 if not.
  146. */
  147. static int VsCodec0IsReady(void)
  148. {
  149. return GpioPinGet(VSCODEC0_DREQ_PORT, VSCODEC0_DREQ_BIT) != 0;
  150. }
  151. /*
  152. * \brief Write to command channel of codec 0.
  153. *
  154. * This routine will not check the DREQ line.
  155. *
  156. * \param cmd Points to the buffer. On entry it contains the data to
  157. * send. On exit it will contain the data received from
  158. * the chip.
  159. * \param len Number of bytes to send and receive.
  160. */
  161. static int VsCodec0SendCmd(void *cmd, size_t len)
  162. {
  163. int rc;
  164. /* Allocate the SPI bus. */
  165. rc = (*nodeSpiVsCodec0.node_bus->bus_alloc) (&nodeSpiVsCodec0, VSCODEC0_SPIBUS_WAIT);
  166. if (rc == 0) {
  167. /* Activate chip selects. */
  168. #if defined(VSCODEC0_VSCS_PORT) && defined(VSCODEC0_VSCS_BIT)
  169. GpioPinSetLow(VSCODEC0_VSCS_PORT, VSCODEC0_VSCS_BIT);
  170. #endif
  171. GpioPinSetLow(VSCODEC0_XCS_PORT, VSCODEC0_XCS_BIT);
  172. /* Send command bytes and receive response. */
  173. rc = (*nodeSpiVsCodec0.node_bus->bus_transfer) (&nodeSpiVsCodec0, cmd, cmd, len);
  174. /* Dectivate chip selects. */
  175. GpioPinSetHigh(VSCODEC0_XCS_PORT, VSCODEC0_XCS_BIT);
  176. #if defined(VSCODEC0_VSCS_PORT) && defined(VSCODEC0_VSCS_BIT)
  177. GpioPinSetHigh(VSCODEC0_VSCS_PORT, VSCODEC0_VSCS_BIT);
  178. #endif
  179. /* Release the SPI bus. */
  180. (*nodeSpiVsCodec0.node_bus->bus_release) (&nodeSpiVsCodec0);
  181. }
  182. return rc;
  183. }
  184. /*
  185. * \brief Write to command channel of codec 0.
  186. *
  187. * This routine will not check the DREQ line.
  188. *
  189. * \param cmd Points to the buffer. On entry it contains the data to
  190. * send. On exit it will contain the data received from
  191. * the chip.
  192. * \param len Number of bytes to send and receive.
  193. */
  194. static int VsCodec0RecvData(void *buf, size_t len)
  195. {
  196. int rc;
  197. uint8_t *bp = (uint8_t *) buf;
  198. const uint8_t cmd[4] = { VS_OPCODE_READ, VS_HDAT0_REG, 0xFF, 0xFF };
  199. uint8_t rsp[4];
  200. VsCodecWaitReady(&devSpiVsCodec0, VSCODEC_CMD_TIMEOUT);
  201. //(*nodeSpiVsCodec0.node_bus->bus_set_rate) (&nodeSpiVsCodec0, 20000000);
  202. /* Allocate the SPI bus. */
  203. rc = (*nodeSpiVsCodec0.node_bus->bus_alloc) (&nodeSpiVsCodec0, VSCODEC0_SPIBUS_WAIT);
  204. if (rc == 0) {
  205. len >>= 1;
  206. while (len--) {
  207. /* Activate chip selects. */
  208. #if defined(VSCODEC0_VSCS_PORT) && defined(VSCODEC0_VSCS_BIT)
  209. GpioPinSetLow(VSCODEC0_VSCS_PORT, VSCODEC0_VSCS_BIT);
  210. #endif
  211. GpioPinSetLow(VSCODEC0_XCS_PORT, VSCODEC0_XCS_BIT); /* XCS=PA31 */
  212. /* Send command bytes and receive response. */
  213. rc = (*nodeSpiVsCodec0.node_bus->bus_transfer) (&nodeSpiVsCodec0, cmd, rsp, 4);
  214. /* Deactivate chip selects. */
  215. GpioPinSetHigh(VSCODEC0_XCS_PORT, VSCODEC0_XCS_BIT);
  216. #if defined(VSCODEC0_VSCS_PORT) && defined(VSCODEC0_VSCS_BIT)
  217. GpioPinSetHigh(VSCODEC0_VSCS_PORT, VSCODEC0_VSCS_BIT);
  218. #endif
  219. *bp++ = rsp[2];
  220. *bp++ = rsp[3];
  221. }
  222. /* Release the SPI bus. */
  223. (*nodeSpiVsCodec0.node_bus->bus_release) (&nodeSpiVsCodec0);
  224. }
  225. return rc;
  226. }
  227. /*
  228. * \brief Write data to the decoder.
  229. *
  230. * Data is sent in fixed chunks. The first one is sent without
  231. * checking the DREQ line. Any subsequent chunk is sent only if
  232. * the DREQ line is still high.
  233. *
  234. * \param node Specifies the SPI node.
  235. * \param buf Points to the data. May be NULL, in which case the routine
  236. * will send the specified number of zeros.
  237. * \param len Number of bytes to send.
  238. *
  239. * \return The number of bytes actually sent. This may be less than the
  240. * specified data length. Zero is returned in case of an error.
  241. */
  242. static int VsCodec0SendData(const uint8_t *buf, size_t len)
  243. {
  244. int rc = 0;
  245. const uint8_t *bp;
  246. size_t chunk;
  247. /* Allocate the SPI bus. */
  248. if ((*nodeSpiVsCodec0.node_bus->bus_alloc) (&nodeSpiVsCodec0, VSCODEC0_SPIBUS_WAIT) == 0) {
  249. #if defined(VSCODEC0_VSCS_PORT) && defined(VSCODEC0_VSCS_BIT)
  250. /* Activate optional VSCS line. */
  251. GpioPinSetLow(VSCODEC0_VSCS_PORT, VSCODEC0_VSCS_BIT);
  252. #endif
  253. #if defined(VSCODEC0_XDCS_PORT) && defined(VSCODEC0_XDCS_BIT)
  254. /* Activate optional XDCS line. */
  255. GpioPinSetLow(VSCODEC0_XDCS_PORT, VSCODEC0_XDCS_BIT);
  256. #endif
  257. /* Set our internal buffer pointer, either to the start of the
  258. ** encoded data or to a chunk of zeros. */
  259. bp = buf ? buf : zero_chunk;
  260. /* Loop until all data had been sent or DREQ goes low. */
  261. while (len) {
  262. /* Determine chunk size. */
  263. chunk = len > VSCODEC_DATA_CHUNK_SIZE ? VSCODEC_DATA_CHUNK_SIZE : len;
  264. /* Send the chunk, exit on errors. */
  265. if ((*nodeSpiVsCodec0.node_bus->bus_transfer) (&nodeSpiVsCodec0, bp, NULL, chunk)) {
  266. break;
  267. }
  268. /* Update function result. */
  269. rc += chunk;
  270. /* Check if decoder is ready for more. Exit, if not. */
  271. if (!VsCodec0IsReady()) {
  272. break;
  273. }
  274. /* Update remaining number of bytes and buffer pointer. */
  275. len -= chunk;
  276. if (buf) {
  277. bp += chunk;
  278. }
  279. }
  280. #if defined(VSCODEC0_XDCS_PORT) && defined(VSCODEC0_XDCS_BIT)
  281. /* Deactivate optional XDCS line. */
  282. GpioPinSetHigh(VSCODEC0_XDCS_PORT, VSCODEC0_XDCS_BIT);
  283. #endif
  284. #if defined(VSCODEC0_VSCS_PORT) && defined(VSCODEC0_VSCS_BIT)
  285. /* Deactivate optional VSCS line. */
  286. GpioPinSetHigh(VSCODEC0_VSCS_PORT, VSCODEC0_VSCS_BIT);
  287. #endif
  288. /* Release the SPI bus. */
  289. (*nodeSpiVsCodec0.node_bus->bus_release) (&nodeSpiVsCodec0);
  290. }
  291. return rc;
  292. }
  293. /*!
  294. * \brief Handle I/O controls for audio codec.
  295. *
  296. * \param dev Specifies the audio codec device.
  297. *
  298. * \return 0 on success, -1 otherwise.
  299. */
  300. static int VsCodec0Control(int req, void *conf)
  301. {
  302. int rc = 0;
  303. uint32_t *lvp = (uint32_t *) conf;
  304. switch (req) {
  305. case AUDIO_SET_DECFMTS:
  306. /* Enable or disable specific decoder formats. */
  307. #if defined(VS_SM_LAYER12)
  308. if (*lvp & (AUDIO_FMT_MPEG1_L1 | AUDIO_FMT_MPEG1_L2)) {
  309. VsCodecMode(&devSpiVsCodec0, VS_SM_LAYER12, VS_SM_LAYER12);
  310. } else {
  311. VsCodecMode(&devSpiVsCodec0, 0, VS_SM_LAYER12);
  312. }
  313. #endif
  314. break;
  315. case AUDIO_GET_DECFMTS:
  316. /* Retrieve decoder formats. */
  317. *lvp = VS_DECODER_CAPS;
  318. #if defined(VS_SM_LAYER12)
  319. {
  320. uint16_t mode = VsCodecMode(&devSpiVsCodec0, 0, 0);
  321. if ((mode & VS_SM_LAYER12) == 0) {
  322. *lvp &= ~(AUDIO_FMT_MPEG1_L1 | AUDIO_FMT_MPEG1_L2);
  323. }
  324. }
  325. #endif
  326. break;
  327. case AUDIO_GET_CODFMTS:
  328. /* Retrieve encoder formats. */
  329. *lvp = VS_ENCODER_CAPS;
  330. #if defined(VS_SM_ADPCM)
  331. {
  332. uint16_t mode = VsCodecMode(&devSpiVsCodec0, 0, 0);
  333. if ((mode & VS_SM_ADPCM) == 0) {
  334. *lvp &= ~(AUDIO_FMT_WAV_ADPCM | AUDIO_FMT_WAV_IMA_ADPCM);
  335. }
  336. }
  337. #endif
  338. break;
  339. case AUDIO_SET_CODFMTS:
  340. /* Enable or disable specific encoder formats. */
  341. if (*lvp & AUDIO_FMT_VORBIS) {
  342. }
  343. break;
  344. case AUDIO_IRQ_ENABLE:
  345. if (*lvp) {
  346. NutIrqEnable(&VSCODEC0_DREQ_SIGNAL);
  347. } else {
  348. NutIrqDisable(&VSCODEC0_DREQ_SIGNAL);
  349. }
  350. break;
  351. default:
  352. rc = -1;
  353. break;
  354. }
  355. return rc;
  356. }
  357. /*!
  358. * \brief Set VLSI audio codec clock.
  359. *
  360. * \param dev Specifies the audio codec device.
  361. * \param xtal Clock at the chip's XTAL input in Hertz.
  362. * \param dreq If zero, then the routine will ignore the status of the
  363. * DREQ input. This is useful for early clock configuration
  364. * immediately after releasing hardware reset, but will be
  365. * ignored on chips earlier than VS103x.
  366. *
  367. * \return 0 on success, -1 otherwise.
  368. */
  369. static int VsCodec0SetClock(uint32_t xtal, uint_fast8_t dreq)
  370. {
  371. int rc = 0;
  372. #if VS_HAS_SC_X3FREQ
  373. /* This hardware got the new CLOCKF register layout. */
  374. if (dreq) {
  375. /* Honor the DREQ line, if requested. */
  376. VsCodecWaitReady(&devSpiVsCodec0, VSCODEC_CMD_TIMEOUT);
  377. }
  378. {
  379. uint8_t cmd[4] = { VS_OPCODE_WRITE, VS_CLOCKF_REG, 0, 0 };
  380. uint16_t freq = (uint16_t)((xtal - 8000000UL) / 4000UL);
  381. freq |= (VS_SC_MULT_3_5 | VS_SC_ADD_1_0);
  382. cmd[2] = (uint8_t) (freq >> 8);
  383. cmd[3] = (uint8_t) freq;
  384. rc = VsCodec0SendCmd(cmd, 4);
  385. }
  386. #else
  387. /* Old hardware, requires clock doubler with lower frequence crystal. */
  388. if (xtal < 20000000UL) {
  389. VsCodecReg(&devSpiVsCodec0, VS_OPCODE_WRITE, VS_CLOCKF_REG, (uint16_t)(VS_CF_DOUBLER | (xtal / 2000UL)));
  390. } else {
  391. VsCodecReg(&devSpiVsCodec0, VS_OPCODE_WRITE, VS_CLOCKF_REG, (uint16_t)(xtal / 2000UL));
  392. }
  393. #endif
  394. /* Force frequency change (see VS1001 datasheet). */
  395. #if defined(AUDIO0_VS1001K)
  396. VsCodecReg(&devSpiVsCodec0, VS_OPCODE_WRITE, VS_INT_FCTLH_REG, 0x8008);
  397. #elif defined(AUDIO0_VSAUTO) && defined(VS_INT_FCTLH_REG)
  398. if (dcbVsCodec0.dcb_codec_ver == 1001) {
  399. VsCodecReg(&devSpiVsCodec0, VS_OPCODE_WRITE, VS_INT_FCTLH_REG, 0x8008);
  400. }
  401. #endif
  402. /* With higher clock we can increase the SPI rate. */
  403. if (rc == 0) {
  404. #if VS_HAS_SC_X3FREQ
  405. (*nodeSpiVsCodec0.node_bus->bus_set_rate) (&nodeSpiVsCodec0, xtal / 2);
  406. #endif
  407. }
  408. return rc;
  409. }
  410. /*!
  411. * \brief Detect VLSI audio codec version.
  412. *
  413. * If the codec type had been pre-configured, this routine will verify
  414. * the hardware. Otherwise it will try to determine the codec by reading
  415. * the version info in the status register.
  416. *
  417. * \param dev Specifies the audio codec device.
  418. *
  419. * \return 0 on success, -1 otherwise.
  420. */
  421. static int VsCodec0Detect(void)
  422. {
  423. int rc = -1;
  424. uint_fast16_t status;
  425. /*
  426. ** Verify the hardware if chip is pre-configured.
  427. */
  428. status = VsCodecReg(&devSpiVsCodec0, VS_OPCODE_READ, VS_STATUS_REG, 0);
  429. #if defined(AUDIO0_VS1001K)
  430. if ((status & VS_SS_VER) == (VS1001_SS_VER << VS_SS_VER_LSB)) {
  431. dcbVsCodec0.dcb_codec_ver = 1001;
  432. dcbVsCodec0.dcb_codec_rev = 'K';
  433. rc = 0;
  434. }
  435. #elif defined(AUDIO0_VS1011E)
  436. if ((status & VS_SS_VER) == (VS1011E_SS_VER << VS_SS_VER_LSB)) {
  437. dcbVsCodec0.dcb_codec_ver = 1011;
  438. dcbVsCodec0.dcb_codec_rev = 'E';
  439. rc = 0;
  440. }
  441. #elif defined(AUDIO0_VS1002D)
  442. if ((status & VS_SS_VER) == (VS1002_SS_VER << VS_SS_VER_LSB)) {
  443. dcbVsCodec0.dcb_codec_ver = 1002;
  444. dcbVsCodec0.dcb_codec_rev = 'D';
  445. rc = 0;
  446. }
  447. #elif defined(AUDIO0_VS1003B)
  448. if ((status & VS_SS_VER) == (VS1003_SS_VER << VS_SS_VER_LSB)) {
  449. dcbVsCodec0.dcb_codec_ver = 1003;
  450. dcbVsCodec0.dcb_codec_rev = 'B';
  451. rc = 0;
  452. }
  453. #elif defined(AUDIO0_VS1033C)
  454. if ((status & VS_SS_VER) == (VS1033_SS_VER << VS_SS_VER_LSB)) {
  455. dcbVsCodec0.dcb_codec_ver = 1033;
  456. dcbVsCodec0.dcb_codec_rev = 'C';
  457. rc = 0;
  458. }
  459. #elif defined(AUDIO0_VS1053B)
  460. if ((status & VS_SS_VER) == (VS1053_SS_VER << VS_SS_VER_LSB)) {
  461. dcbVsCodec0.dcb_codec_ver = 1053;
  462. dcbVsCodec0.dcb_codec_rev = 'B';
  463. rc = 0;
  464. }
  465. #elif defined(AUDIO0_VS1063A)
  466. if ((status & VS_SS_VER) == (VS1063_SS_VER << VS_SS_VER_LSB)) {
  467. dcbVsCodec0.dcb_codec_ver = 1063;
  468. dcbVsCodec0.dcb_codec_rev = 'A';
  469. rc = 0;
  470. }
  471. #else
  472. /*
  473. ** If not configured, try to figure it out.
  474. */
  475. rc = 0;
  476. switch ((status & VS_SS_VER) >> VS_SS_VER_LSB) {
  477. case VS1001_SS_VER:
  478. dcbVsCodec0.dcb_codec_ver = 1001;
  479. break;
  480. case VS1011_SS_VER:
  481. dcbVsCodec0.dcb_codec_ver = 1011;
  482. break;
  483. case VS1002_SS_VER:
  484. if (VsCodecReg(&devSpiVsCodec0, VS_OPCODE_READ, VS_MODE_REG, 0) & VS_SM_SDINEW) {
  485. dcbVsCodec0.dcb_codec_ver = 1002;
  486. } else {
  487. dcbVsCodec0.dcb_codec_ver = 1011;
  488. dcbVsCodec0.dcb_codec_rev = 'E';
  489. }
  490. break;
  491. case VS1003_SS_VER:
  492. dcbVsCodec0.dcb_codec_ver = 1003;
  493. break;
  494. case VS1053_SS_VER:
  495. dcbVsCodec0.dcb_codec_ver = 1053;
  496. break;
  497. case VS1033_SS_VER:
  498. dcbVsCodec0.dcb_codec_ver = 1033;
  499. break;
  500. case VS1103_SS_VER:
  501. dcbVsCodec0.dcb_codec_ver = 1103;
  502. break;
  503. default:
  504. rc = -1;
  505. break;
  506. }
  507. #endif
  508. return rc;
  509. }
  510. /*!
  511. * \brief VS10XX hardware reset.
  512. *
  513. * This routine requires, that the codecs reset line is tied to a GPIO
  514. * pin. However, VsCodec0ResetHardware(0) may be called during system boot
  515. * to recover from power-on reset.
  516. *
  517. * \param dev Specifies the audio codec device.
  518. * \param on If zero, the hardware reset will be released. Otherwise
  519. * the reset is activated.
  520. */
  521. static int VsCodec0ResetHardware(int on)
  522. {
  523. if (on) {
  524. /*
  525. ** Activate reset.
  526. */
  527. #if defined(VSCODEC0_XRESET_PORT) && defined(VSCODEC0_XRESET_BIT)
  528. /* Activate the reset line. */
  529. GpioPinSetLow(VSCODEC0_XRESET_PORT, VSCODEC0_XRESET_BIT);
  530. GpioPinConfigSet(VSCODEC0_XRESET_PORT, VSCODEC0_XRESET_BIT, GPIO_CFG_OUTPUT);
  531. NutSleep(VSCODEC0_HWRST_DURATION);
  532. #else
  533. return -1;
  534. #endif
  535. } else {
  536. /*
  537. ** Deactivate reset.
  538. */
  539. uint_fast8_t clkset = 0;
  540. #if defined(VSCODEC0_XRESET_PORT) && defined(VSCODEC0_XRESET_BIT)
  541. /* Release the reset line. */
  542. GpioPinSetHigh(VSCODEC0_XRESET_PORT, VSCODEC0_XRESET_BIT);
  543. #if VSCODEC0_FREQ >= 24000000UL
  544. /* With input clocks equal or above 24MHz we must set CLOCKF early
  545. ** and must not wait for rising DREQ. */
  546. csrc = VsCodec0SetClock(VSCODEC0_FREQ, 0) == 0;
  547. #endif /* VSCODEC0_FREQ */
  548. #endif /* VSCODEC0_XRESET_PORT */
  549. #if VSCODEC0_HWRST_RECOVER
  550. /* Optional delay after hardware reset. */
  551. NutSleep(VSCODEC0_HWRST_RECOVER);
  552. #endif
  553. /* Chip hardware detection. */
  554. if (VsCodec0Detect()) {
  555. return -1;
  556. }
  557. #if !defined(AUDIO0_VS1001K)
  558. if (dcbVsCodec0.dcb_codec_ver != 1001) {
  559. #if VS_HAS_SM_SDINEW
  560. #if defined(VSCODEC0_XDCS_PORT) && defined(VSCODEC0_XDCS_BIT)
  561. VsCodecMode(&devSpiVsCodec0, VS_SM_SDINEW, VS_SM_SDINEW);
  562. #else
  563. VsCodecMode(&devSpiVsCodec0, VS_SM_SDINEW | VS_SM_SDISHARE, VS_SM_SDINEW | VS_SM_SDISHARE);
  564. #endif
  565. #endif /* VS_HAS_SM_SDINEW */
  566. }
  567. #endif /* AUDIO0_VS1001K */
  568. /* Set clock now, if not done successfully before. */
  569. if (!clkset) {
  570. VsCodec0SetClock(VSCODEC0_FREQ, 1);
  571. }
  572. }
  573. return 0;
  574. }
  575. /*
  576. * Called via dev_init pointer when the device is registered.
  577. *
  578. * \param dev Specifies the audio codec device.
  579. *
  580. * \return 0 on success, -1 otherwise.
  581. */
  582. static int VsCodec0Init(NUTDEVICE * dev)
  583. {
  584. size_t avail;
  585. /* Activate hardware reset. */
  586. VsCodec0ResetHardware(1);
  587. /* Set function pointers. */
  588. dcbVsCodec0.dcb_isready = VsCodec0IsReady;
  589. dcbVsCodec0.dcb_sendcmd = VsCodec0SendCmd;
  590. dcbVsCodec0.dcb_senddata = VsCodec0SendData;
  591. dcbVsCodec0.dcb_recvdata = VsCodec0RecvData;
  592. dcbVsCodec0.dcb_control = VsCodec0Control;
  593. /* Set capabilities. */
  594. #ifdef VS_DECODER_CAPS
  595. dcbVsCodec0.dcb_dec_caps = VS_DECODER_CAPS;
  596. #endif
  597. #ifdef VS_ENCODER_CAPS
  598. dcbVsCodec0.dcb_cod_caps = VS_ENCODER_CAPS;
  599. #endif
  600. #ifdef VS_MIDI_CAPS
  601. dcbVsCodec0.dcb_midi_caps = VS_MIDI_CAPS;
  602. #endif
  603. /* Initialize DREQ input. Will be later used as an external interupt. */
  604. GpioPinConfigSet(VSCODEC0_DREQ_PORT, VSCODEC0_DREQ_BIT, 0);
  605. /* Initialize chip selects, XCS and optional XDCS. */
  606. GpioPinSetHigh(VSCODEC0_XCS_PORT, VSCODEC0_XCS_BIT);
  607. GpioPinConfigSet(VSCODEC0_XCS_PORT, VSCODEC0_XCS_BIT, GPIO_CFG_OUTPUT);
  608. #if defined(VSCODEC0_XDCS_PORT) && defined(VSCODEC0_XDCS_BIT)
  609. GpioPinSetHigh(VSCODEC0_XDCS_PORT, VSCODEC0_XDCS_BIT);
  610. GpioPinConfigSet(VSCODEC0_XDCS_PORT, VSCODEC0_XDCS_BIT, GPIO_CFG_OUTPUT);
  611. #endif
  612. #if defined(VSCODEC0_VSCS_PORT) && defined(VSCODEC0_VSCS_BIT)
  613. GpioPinSetHigh(VSCODEC0_VSCS_PORT, VSCODEC0_VSCS_BIT);
  614. GpioPinConfigSet(VSCODEC0_VSCS_PORT, VSCODEC0_VSCS_BIT, GPIO_CFG_OUTPUT);
  615. #endif
  616. /* Register the DREQ interrupt routine. */
  617. NutRegisterIrqHandler(&VSCODEC0_DREQ_SIGNAL, VsCodec0Interrupt, &dcbVsCodec0.dcb_feedme);
  618. /* Rising edge will generate an interrupt. */
  619. GpioPinConfigSet(VSCODEC0_DREQ_PORT, VSCODEC0_DREQ_BIT, GPIO_CFG_DISABLED);
  620. NutIrqSetMode(&VSCODEC0_DREQ_SIGNAL, NUT_IRQMODE_RISINGEDGE);
  621. NutIrqEnable(&VSCODEC0_DREQ_SIGNAL);
  622. /* Deactivate hardware reset. */
  623. if (VsCodec0ResetHardware(0)) {
  624. /* Probably failed to detect the hardware. */
  625. return -1;
  626. }
  627. /*
  628. ** Initialize the decoder stream buffer.
  629. */
  630. #ifdef VSCODEC0_OUTPUT_BUFSIZ
  631. avail = VSCODEC0_OUTPUT_BUFSIZ;
  632. #else
  633. avail = NutHeapAvailable() / 2;
  634. if (avail > VSCODEC0_MAX_OUTPUT_BUFSIZ) {
  635. avail = VSCODEC0_MAX_OUTPUT_BUFSIZ;
  636. }
  637. #endif
  638. if (VsDecoderBufferInit(dev, avail)) {
  639. return -1;
  640. }
  641. /* Start the feeder thread. */
  642. if (NutThreadCreate(dev->dev_name, FeederThread, dev,
  643. (NUT_THREAD_VSCODEC0STACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD) == 0) {
  644. return -1;
  645. }
  646. return 0;
  647. }
  648. /*!
  649. * \brief VS10XX device information structure.
  650. *
  651. * An application must pass a pointer to this structure to
  652. * NutRegisterDevice() before using this driver.
  653. *
  654. * The device is named \b audio0.
  655. *
  656. * \showinitializer
  657. */
  658. NUTDEVICE devSpiVsCodec0 = {
  659. 0, /* Pointer to next device, dev_next. */
  660. {'a', 'u', 'd', 'i', 'o', '0', 0, 0, 0}, /* Unique device name, dev_name. */
  661. IFTYP_CHAR, /* Type of device, dev_type. */
  662. 0, /* Codec number, dev_base. */
  663. 0, /* First interrupt number, dev_irq (not used). */
  664. &nodeSpiVsCodec0, /* Interface control block, dev_icb (not used). */
  665. &dcbVsCodec0, /* Driver control block, dev_dcb. */
  666. VsCodec0Init, /* Driver initialization routine, dev_init. */
  667. VsCodecIOCtl, /* Driver specific control function, dev_ioctl. */
  668. VsCodecRead, /* Read from device, dev_read. */
  669. VsCodecWrite, /* Write to device, dev_write. */
  670. #ifdef __HARVARD_ARCH__
  671. VsCodecWrite_P, /* Write data from program space to device, dev_write_P. */
  672. #endif
  673. VsCodecOpen, /* Open a device or file, dev_open. */
  674. VsCodecClose, /* Close a device or file, dev_close. */
  675. NULL, /* Request file size, dev_size. */
  676. NULL, /* Select function, optional, not yet implemented */
  677. };
  678. /*@}*/
  679. #endif