vscodec.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937
  1. /*
  2. * Copyright (C) 2008 by egnite GmbH. All rights reserved.
  3. * Copyright (C) 2001-2007 by egnite Software GmbH. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of the copyright holders nor the names of
  15. * contributors may be used to endorse or promote products derived
  16. * from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  21. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  22. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  23. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  24. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  25. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  26. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  27. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  28. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  29. * SUCH DAMAGE.
  30. *
  31. * For additional information see http://www.ethernut.de/
  32. * -
  33. *
  34. * This software has been inspired by all the valuable work done by
  35. * Jesper Hansen and Pavel Chromy. Many thanks for all their help.
  36. */
  37. /*
  38. * $Log$
  39. * Revision 1.8 2009/02/13 14:52:05 haraldkipp
  40. * Include memdebug.h for heap management debugging support.
  41. *
  42. * Revision 1.7 2009/01/30 08:59:30 haraldkipp
  43. * Make sure, that used registers are defined.
  44. *
  45. * Revision 1.6 2009/01/17 11:26:46 haraldkipp
  46. * Getting rid of two remaining BSD types in favor of stdint.
  47. * Replaced 'u_int' by 'unsinged int' and 'uptr_t' by 'uintptr_t'.
  48. *
  49. * Revision 1.5 2008/10/23 08:54:07 haraldkipp
  50. * Include the correct header file.
  51. *
  52. * Revision 1.4 2008/09/18 09:51:58 haraldkipp
  53. * Use the correct PORT macros.
  54. *
  55. * Revision 1.3 2008/08/11 06:59:42 haraldkipp
  56. * BSD types replaced by stdint types (feature request #1282721).
  57. *
  58. * Revision 1.2 2008/04/01 10:15:27 haraldkipp
  59. * VS10xx ioctl() returned -1 on success. Fixed.
  60. *
  61. * Revision 1.1 2008/02/15 16:45:41 haraldkipp
  62. * First release.
  63. *
  64. * Revision 1.1 2007/04/12 08:59:55 haraldkipp
  65. * VS10XX decoder support added.
  66. *
  67. */
  68. #include <sys/atom.h>
  69. #include <sys/event.h>
  70. #include <sys/timer.h>
  71. #include <sys/heap.h>
  72. #include <cfg/arch/gpio.h>
  73. #include <cfg/audio.h>
  74. #include <dev/irqreg.h>
  75. #include <dev/vscodec.h>
  76. #include <sys/bankmem.h>
  77. #include <stdlib.h>
  78. #include <stddef.h>
  79. #include <string.h>
  80. #include <memdebug.h>
  81. /*!
  82. * \addtogroup xgVsCodec
  83. */
  84. /*@{*/
  85. #if !defined(AUDIO_VS1001K) && !defined(AUDIO_VS1011E) && !defined(AUDIO_VS1002D) && !defined(AUDIO_VS1003B) && !defined(AUDIO_VS1033C) && !defined(AUDIO_VS1053C)
  86. #define AUDIO_VS1001K
  87. #endif
  88. #ifndef VS10XX_FREQ
  89. /*! \brief Decoder crystal frequency. */
  90. #define VS10XX_FREQ 12288000UL
  91. #endif
  92. #ifndef VS10XX_HWRST_DURATION
  93. /*! \brief Minimum time in milliseconds to held hardware reset low. */
  94. #define VS10XX_HWRST_DURATION 1
  95. #endif
  96. #ifndef VS10XX_HWRST_RECOVER
  97. /*! \brief Milliseconds to wait after hardware reset. */
  98. #define VS10XX_HWRST_RECOVER 4
  99. #endif
  100. #ifndef VS10XX_SWRST_RECOVER
  101. /*! \brief Milliseconds to wait after software reset. */
  102. #define VS10XX_SWRST_RECOVER 2
  103. #endif
  104. #ifndef VS10XX_SCI_MODE
  105. #define VS10XX_SCI_MODE 0
  106. #endif
  107. #ifndef VS10XX_SCI_RATE
  108. #define VS10XX_SCI_RATE (VS10XX_FREQ / 6)
  109. #endif
  110. #ifndef VS10XX_SDI_MODE
  111. #define VS10XX_SDI_MODE 0
  112. #endif
  113. #ifndef VS10XX_SDI_RATE
  114. #define VS10XX_SDI_RATE (VS10XX_FREQ / 6)
  115. #endif
  116. /* -------------------------------------------------
  117. * AT91 port specifications.
  118. */
  119. #if defined (MCU_AT91R40008) || defined (MCU_AT91SAM7X) || defined (MCU_AT91SAM7SE512) || defined (MCU_AT91SAM9260)
  120. #if defined(ELEKTOR_IR1)
  121. #define VS_XRESET_BIT 31 /* PB31 */
  122. #define VS10XX_XCS_BIT PA31_SPI0_NPCS1_A
  123. #define VS10XX_XCS_PORT PIOA_ID
  124. #define VS10XX_XDCS_BIT PB30_SPI0_NPCS2_A
  125. #define VS10XX_XDCS_PORT PIOB_ID
  126. #define VS10XX_DREQ_BIT PA30_IRQ1_A
  127. #define VS10XX_DREQ_PIO_ID PIOA_ID
  128. #define VS10XX_SIGNAL sig_INTERRUPT1
  129. #endif /* ELEKTOR_IR1 */
  130. #if defined(VS10XX_XCS_BIT)
  131. #if !defined(VS10XX_XCS_PORT)
  132. #define VS10XX_XCS_PE_REG PIO_PER
  133. #define VS10XX_XCS_OE_REG PIO_OER
  134. #define VS10XX_XCS_COD_REG PIO_CODR
  135. #define VS10XX_XCS_SOD_REG PIO_SODR
  136. #elif VS10XX_XCS_PORT == PIOA_ID
  137. #define VS10XX_XCS_PE_REG PIOA_PER
  138. #define VS10XX_XCS_OE_REG PIOA_OER
  139. #define VS10XX_XCS_COD_REG PIOA_CODR
  140. #define VS10XX_XCS_SOD_REG PIOA_SODR
  141. #elif VS10XX_XCS_PORT == PIOB_ID
  142. #define VS10XX_XCS_PE_REG PIOB_PER
  143. #define VS10XX_XCS_OE_REG PIOB_OER
  144. #define VS10XX_XCS_COD_REG PIOB_CODR
  145. #define VS10XX_XCS_SOD_REG PIOB_SODR
  146. #elif VS10XX_XCS_PORT == PIOC_ID
  147. #define VS10XX_XCS_PE_REG PIOC_PER
  148. #define VS10XX_XCS_OE_REG PIOC_OER
  149. #define VS10XX_XCS_COD_REG PIOC_CODR
  150. #define VS10XX_XCS_SOD_REG PIOC_SODR
  151. #endif
  152. #define VS10XX_XCS_ENA() \
  153. outr(VS10XX_XCS_PE_REG, _BV(VS10XX_XCS_BIT)); \
  154. outr(VS10XX_XCS_OE_REG, _BV(VS10XX_XCS_BIT))
  155. #define VS10XX_XCS_CLR() outr(VS10XX_XCS_COD_REG, _BV(VS10XX_XCS_BIT))
  156. #define VS10XX_XCS_SET() outr(VS10XX_XCS_SOD_REG, _BV(VS10XX_XCS_BIT))
  157. #else /* VS10XX_XCS_BIT */
  158. #define VS10XX_XCS_ENA()
  159. #define VS10XX_XCS_CLR()
  160. #define VS10XX_XCS_SET()
  161. #endif /* VS10XX_XCS_BIT */
  162. #if defined(VS10XX_XDCS_BIT)
  163. #if !defined(VS10XX_XDCS_PORT)
  164. #define VS10XX_XDCS_PE_REG PIO_PER
  165. #define VS10XX_XDCS_OE_REG PIO_OER
  166. #define VS10XX_XDCS_COD_REG PIO_CODR
  167. #define VS10XX_XDCS_SOD_REG PIO_SODR
  168. #elif VS10XX_XDCS_PORT == PIOA_ID
  169. #define VS10XX_XDCS_PE_REG PIOA_PER
  170. #define VS10XX_XDCS_OE_REG PIOA_OER
  171. #define VS10XX_XDCS_COD_REG PIOA_CODR
  172. #define VS10XX_XDCS_SOD_REG PIOA_SODR
  173. #elif VS10XX_XDCS_PORT == PIOB_ID
  174. #define VS10XX_XDCS_PE_REG PIOB_PER
  175. #define VS10XX_XDCS_OE_REG PIOB_OER
  176. #define VS10XX_XDCS_COD_REG PIOB_CODR
  177. #define VS10XX_XDCS_SOD_REG PIOB_SODR
  178. #elif VS10XX_XDCS_PORT == PIOC_ID
  179. #define VS10XX_XDCS_PE_REG PIOC_PER
  180. #define VS10XX_XDCS_OE_REG PIOC_OER
  181. #define VS10XX_XDCS_COD_REG PIOC_CODR
  182. #define VS10XX_XDCS_SOD_REG PIOC_SODR
  183. #endif
  184. #define VS10XX_XDCS_ENA() \
  185. outr(VS10XX_XDCS_PE_REG, _BV(VS10XX_XDCS_BIT)); \
  186. outr(VS10XX_XDCS_OE_REG, _BV(VS10XX_XDCS_BIT))
  187. #define VS10XX_XDCS_CLR() outr(VS10XX_XDCS_COD_REG, _BV(VS10XX_XDCS_BIT))
  188. #define VS10XX_XDCS_SET() outr(VS10XX_XDCS_SOD_REG, _BV(VS10XX_XDCS_BIT))
  189. #else /* VS10XX_XDCS_BIT */
  190. #define VS10XX_XDCS_ENA()
  191. #define VS10XX_XDCS_CLR()
  192. #define VS10XX_XDCS_SET()
  193. #endif /* VS10XX_XDCS_BIT */
  194. #if defined(VS10XX_DREQ_BIT)
  195. #if !defined(VS10XX_DREQ_PIO_ID)
  196. #define VS10XX_DREQ_PD_REG PIO_PDR
  197. #define VS10XX_DREQ_OD_REG PIO_ODR
  198. #define VS10XX_DREQ_PDS_REG PIO_PDSR
  199. #elif VS10XX_DREQ_PIO_ID == PIOA_ID
  200. #define VS10XX_DREQ_PD_REG PIOA_PDR
  201. #define VS10XX_DREQ_OD_REG PIOA_ODR
  202. #define VS10XX_DREQ_PDS_REG PIOA_PDSR
  203. #elif VS10XX_DREQ_PIO_ID == PIOB_ID
  204. #define VS10XX_DREQ_PD_REG PIOB_PDR
  205. #define VS10XX_DREQ_OD_REG PIOB_ODR
  206. #define VS10XX_DREQ_PDS_REG PIOB_PDSR
  207. #elif VS10XX_DREQ_PIO_ID == PIOC_ID
  208. #define VS10XX_DREQ_PD_REG PIOC_PDR
  209. #define VS10XX_DREQ_OD_REG PIOC_ODR
  210. #define VS10XX_DREQ_PDS_REG PIOC_PDSR
  211. #endif
  212. #define VS10XX_DREQ_ENA() \
  213. outr(VS10XX_DREQ_PD_REG, _BV(VS10XX_DREQ_BIT)); \
  214. outr(VS10XX_DREQ_OD_REG, _BV(VS10XX_DREQ_BIT))
  215. #define VS10XX_DREQ_TST() ((inr(VS10XX_DREQ_PDS_REG) & _BV(VS10XX_DREQ_BIT)) == _BV(VS10XX_DREQ_BIT))
  216. #else /* VS10XX_DREQ_BIT */
  217. #define VS10XX_DREQ_ENA()
  218. #define VS10XX_DREQ_TST() 0
  219. #endif /* VS10XX_DREQ_BIT */
  220. /* -------------------------------------------------
  221. * End of port specifications.
  222. */
  223. #endif
  224. #define VSREQ_PLAY 0x00000001
  225. #define VSREQ_CANCEL 0x00000002
  226. #define VSREQ_BEEP 0x00000004
  227. typedef struct _VSDCB {
  228. int dcb_pbstat; /*!< \brief Playback status. */
  229. uint32_t dcb_scmd; /*!< \brief Requested command flags, see VSREQ_ flags. */
  230. int dcb_crvol; /*!< \brief Current volume of right channel. */
  231. int dcb_srvol; /*!< \brief Requested volume of right channel. */
  232. int dcb_clvol; /*!< \brief Current volume of left channel. */
  233. int dcb_slvol; /*!< \brief Requested volume of left channel. */
  234. int dcb_ctreb; /*!< \brief Current bass enhancement. */
  235. int dcb_streb; /*!< \brief Requested bass enhancement. */
  236. int dcb_ctfin; /*!< \brief Current bass frequency.*/
  237. int dcb_stfin; /*!< \brief Requested bass frequency. */
  238. int dcb_cbass; /*!< \brief Current treble enhancement. */
  239. int dcb_sbass; /*!< \brief Requested bass enhancement. */
  240. int dcb_cbfin; /*!< \brief Current treble frequency. */
  241. int dcb_sbfin; /*!< \brief Requested treble frequency. */
  242. uint32_t dcb_pbwlo; /*!< \brief Playback buffer low watermark. */
  243. uint32_t dcb_pbwhi; /*!< \brief Playback buffer high watermark. */
  244. } VSDCB;
  245. static VSDCB dcb;
  246. static unsigned int vs_chip;
  247. /*
  248. * Interlink not ready yet. Provide some basic SPI routines.
  249. */
  250. static uint8_t SpiByte(uint8_t val)
  251. {
  252. /* Transmission is started by writing the transmit data. */
  253. outr(SPI0_TDR, val);
  254. /* Wait for receiver data register full. */
  255. while((inr(SPI0_SR) & SPI_RDRF) == 0);
  256. /* Read data. */
  257. val = (uint8_t)inr(SPI0_RDR);
  258. return val;
  259. }
  260. static void SciSelect(void)
  261. {
  262. outr(SPI0_CSR0, (24 << SPI_SCBR_LSB) | SPI_NCPHA);
  263. outr(SPI0_MR, SPI_MODFDIS | SPI_MSTR);
  264. outr(PIOA_CODR, _BV(VS10XX_XCS_BIT));
  265. }
  266. static void SciDeselect(void)
  267. {
  268. outr(PIOA_SODR, _BV(VS10XX_XCS_BIT));
  269. }
  270. /*!
  271. * \brief Wait for decoder ready.
  272. *
  273. * This function will check the DREQ line. Decoder interrupts must have
  274. * been disabled before calling this function.
  275. */
  276. static int VsWaitReady(void)
  277. {
  278. int tmo = 16384;
  279. do {
  280. if (VS10XX_DREQ_TST()) {
  281. return 0;
  282. }
  283. } while (tmo--);
  284. return -1;
  285. }
  286. /*
  287. * \brief Write a specified number of bytes to the VS10XX data interface.
  288. *
  289. * This function will check the DREQ line. Decoder interrupts must have
  290. * been disabled before calling this function.
  291. */
  292. static int VsSdiWrite(const uint8_t * data, size_t len)
  293. {
  294. while (len--) {
  295. if (!VS10XX_DREQ_TST() && VsWaitReady()) {
  296. return -1;
  297. }
  298. SpiByte(*data);
  299. data++;
  300. }
  301. return 0;
  302. }
  303. /*
  304. * \brief Write a specified number of bytes from program space to the
  305. * VS10XX data interface.
  306. *
  307. * This function is similar to VsSdiWrite() except that the data is
  308. * located in program space.
  309. */
  310. static int VsSdiWrite_P(PGM_P data, size_t len)
  311. {
  312. while (len--) {
  313. if (!VS10XX_DREQ_TST() && VsWaitReady()) {
  314. return -1;
  315. }
  316. SpiByte(PRG_RDB(data));
  317. data++;
  318. }
  319. return 0;
  320. }
  321. /*
  322. * \brief Write to a decoder register.
  323. *
  324. * Decoder interrupts must have been disabled before calling this function.
  325. */
  326. static void VsRegWrite(ureg_t reg, uint16_t data)
  327. {
  328. VsWaitReady();
  329. SciSelect();
  330. SpiByte(VS_OPCODE_WRITE);
  331. SpiByte((uint8_t) reg);
  332. SpiByte((uint8_t) (data >> 8));
  333. SpiByte((uint8_t) data);
  334. SciDeselect();
  335. }
  336. /*
  337. * \brief Read from a register.
  338. *
  339. * Decoder interrupts must have been disabled before calling this function.
  340. *
  341. * \return Register contents.
  342. */
  343. static uint16_t VsRegRead(ureg_t reg)
  344. {
  345. uint16_t data;
  346. VsWaitReady();
  347. SciSelect();
  348. SpiByte(VS_OPCODE_READ);
  349. SpiByte((uint8_t) reg);
  350. data = (uint16_t)SpiByte(0) << 8;
  351. data |= SpiByte(0);
  352. SciDeselect();
  353. return data;
  354. }
  355. /*!
  356. * \brief Sine wave beep.
  357. *
  358. * Untested.
  359. *
  360. * \param fsin Frequency.
  361. * \param ms Duration.
  362. *
  363. * \return Always 0.
  364. */
  365. static int VsBeep(uint8_t fsin, uint8_t ms)
  366. {
  367. static const char on[] PROGMEM = { 0x53, 0xEF, 0x6E };
  368. static const char off[] PROGMEM = { 0x45, 0x78, 0x69, 0x74 };
  369. static const char end[] PROGMEM = { 0x00, 0x00, 0x00, 0x00 };
  370. VsRegWrite(VS_MODE_REG, VS_SM_TESTS | VS_SM_SDINEW);
  371. fsin = 56 + (fsin & 7) * 9;
  372. VsSdiWrite_P(on, sizeof(on));
  373. VsSdiWrite(&fsin, 1);
  374. VsSdiWrite_P(end, sizeof(end));
  375. NutDelay(ms);
  376. VsSdiWrite_P(off, sizeof(off));
  377. VsSdiWrite_P(end, sizeof(end));
  378. VsRegWrite(VS_MODE_REG, VS_SM_SDINEW);
  379. return 0;
  380. }
  381. static HANDLE vs_ready;
  382. static void VsInterrupt(void *arg)
  383. {
  384. NutEventPostFromIrq(&vs_ready);
  385. }
  386. THREAD(FeederThread, arg)
  387. {
  388. char *bp;
  389. size_t avail;
  390. int filled;
  391. uint8_t crgain;
  392. uint8_t srgain;
  393. uint8_t clgain;
  394. uint8_t slgain;
  395. NutSleep(500);
  396. dcb.dcb_slvol = dcb.dcb_clvol = -12;
  397. dcb.dcb_srvol = dcb.dcb_crvol = -12;
  398. srgain = (uint8_t)(-2 * dcb.dcb_srvol);
  399. crgain = 254;
  400. slgain = (uint8_t)(-2 * dcb.dcb_slvol);
  401. clgain = 254;
  402. VsRegWrite(VS_VOL_REG, ((uint16_t)clgain << VS_VOL_LEFT_LSB) | ((uint16_t)crgain << VS_VOL_RIGHT_LSB));
  403. /* Register the interrupt routine */
  404. while (NutRegisterIrqHandler(&VS10XX_SIGNAL, VsInterrupt, NULL)) {
  405. NutSleep(1000);
  406. }
  407. /* Rising edge will generate an interrupt. */
  408. NutIrqSetMode(&VS10XX_SIGNAL, NUT_IRQMODE_RISINGEDGE);
  409. VS10XX_DREQ_ENA();
  410. NutIrqEnable(&VS10XX_SIGNAL);
  411. for (;;) {
  412. NutEventWait(&vs_ready, 100);
  413. if (!VS10XX_DREQ_TST()) {
  414. continue;
  415. }
  416. if (dcb.dcb_scmd) {
  417. if (dcb.dcb_scmd & VSREQ_CANCEL) {
  418. NutSegBufReset();
  419. }
  420. if (dcb.dcb_scmd & VSREQ_BEEP) {
  421. VsBeep(2, 100);
  422. }
  423. dcb.dcb_scmd &= VSREQ_PLAY;
  424. }
  425. if (NutSegBufUsed() < dcb.dcb_pbwlo) {
  426. dcb.dcb_pbstat = CODEC_STATUS_IDLE;
  427. if (crgain != 254) {
  428. clgain = crgain = 254;
  429. VsRegWrite(VS_VOL_REG, ((uint16_t)clgain << VS_VOL_LEFT_LSB) | ((uint16_t)crgain << VS_VOL_RIGHT_LSB));
  430. }
  431. while (NutSegBufUsed() < dcb.dcb_pbwhi) {
  432. if (dcb.dcb_scmd) {
  433. if (dcb.dcb_scmd & VSREQ_PLAY) {
  434. dcb.dcb_pbwhi = dcb.dcb_pbwlo = NutSegBufUsed() / 2;
  435. }
  436. break;
  437. }
  438. NutSleep(100);
  439. }
  440. }
  441. dcb.dcb_scmd &= ~VSREQ_PLAY;
  442. if (dcb.dcb_scmd) {
  443. continue;
  444. }
  445. outr(SPI0_CSR0, (12 << SPI_SCBR_LSB) | SPI_NCPHA);
  446. outr(SPI0_MR, SPI_MODFDIS | SPI_MSTR);
  447. if (dcb.dcb_pbstat != CODEC_STATUS_PLAYING) {
  448. outr(PIOB_CODR, _BV(30));
  449. while (!VS10XX_DREQ_TST()) {
  450. SpiByte(0);
  451. }
  452. outr(PIOB_SODR, _BV(30));
  453. }
  454. for (;;) {
  455. if (!VS10XX_DREQ_TST()) {
  456. break;
  457. }
  458. bp = NutSegBufReadRequest(&avail);
  459. if (avail == 0) {
  460. dcb.dcb_pbstat = CODEC_STATUS_IDLE;
  461. if (crgain != 254) {
  462. clgain = crgain = 254;
  463. VsRegWrite(VS_VOL_REG, ((uint16_t)clgain << VS_VOL_LEFT_LSB) | ((uint16_t)crgain << VS_VOL_RIGHT_LSB));
  464. }
  465. break;
  466. }
  467. outr(PIOB_CODR, _BV(30));
  468. for (filled = 0; avail--; filled++, bp++) {
  469. if (!VS10XX_DREQ_TST()) {
  470. dcb.dcb_pbstat = CODEC_STATUS_PLAYING;
  471. break;
  472. }
  473. SpiByte(*bp);
  474. }
  475. outr(PIOB_SODR, _BV(30));
  476. NutSegBufReadLast(filled);
  477. }
  478. if (dcb.dcb_clvol != dcb.dcb_slvol || dcb.dcb_crvol != dcb.dcb_srvol) {
  479. srgain = (uint8_t)(-2 * dcb.dcb_srvol);
  480. slgain = (uint8_t)(-2 * dcb.dcb_slvol);
  481. dcb.dcb_clvol = dcb.dcb_slvol;
  482. dcb.dcb_crvol = dcb.dcb_srvol;
  483. }
  484. else if (srgain != crgain || slgain != clgain) {
  485. int diff = (int)srgain - (int)crgain;
  486. if (diff > 4) {
  487. diff = 4;
  488. }
  489. else if (diff < -4) {
  490. diff = -4;
  491. }
  492. crgain = (uint8_t)((int)crgain + diff);
  493. diff = (int)slgain - (int)clgain;
  494. if (diff > 4) {
  495. diff = 4;
  496. }
  497. else if (diff < -4) {
  498. diff = -4;
  499. }
  500. clgain = (uint8_t)((int)clgain + diff);
  501. VsRegWrite(VS_VOL_REG, ((uint16_t)clgain << VS_VOL_LEFT_LSB) | ((uint16_t)crgain << VS_VOL_RIGHT_LSB));
  502. }
  503. }
  504. }
  505. static int VsPlayerFlush(void)
  506. {
  507. int tmo = 1000; /* TODO: Configurable timeout. */
  508. /* Stupid polling for now. */
  509. while(dcb.dcb_pbstat == CODEC_STATUS_PLAYING) {
  510. NutSleep(1);
  511. if (tmo-- <= 0) {
  512. return -1;
  513. }
  514. }
  515. return 0;
  516. }
  517. /*!
  518. * \brief Send data to the decoder.
  519. *
  520. * A carriage return character will be automatically appended
  521. * to any linefeed.
  522. *
  523. * \return Number of characters sent.
  524. */
  525. static int VsWrite(NUTFILE * fp, const void *data, int len)
  526. {
  527. char *buf;
  528. size_t rbytes;
  529. /* Flush buffer if data pointer is a NULL pointer. */
  530. if (data == NULL || len == 0) {
  531. return VsPlayerFlush();
  532. }
  533. if (len) {
  534. buf = NutSegBufWriteRequest(&rbytes);
  535. if (len > rbytes) {
  536. len = rbytes;
  537. }
  538. if (len) {
  539. memcpy(buf, data, len);
  540. }
  541. NutSegBufWriteLast(len);
  542. }
  543. return len;
  544. }
  545. #ifdef __HARVARD_ARCH__
  546. /*!
  547. * \brief Write to device.
  548. *
  549. * Similar to VsWrite() except that the data is expected in program memory.
  550. *
  551. * This function is implemented for CPUs with Harvard Architecture only.
  552. *
  553. * This function is called by the low level output routines of the
  554. * \ref xrCrtLowio "C runtime library", using the
  555. * \ref _NUTDEVICE::dev_write_P entry.
  556. *
  557. * \param nfp Pointer to a \ref NUTFILE structure, obtained by a previous
  558. * call to PnutFileOpen().
  559. * \param buffer Pointer to the data in program space. If zero, then the
  560. * output buffer will be flushed.
  561. * \param len Number of bytes to write.
  562. *
  563. * \return The number of bytes written. A return value of -1 indicates an
  564. * error. Currently this function is not implemented and always
  565. * returns -1.
  566. *
  567. */
  568. static int VsWrite_P(NUTFILE * nfp, PGM_P buffer, int len)
  569. {
  570. return -1;
  571. }
  572. #endif
  573. /*!
  574. * \brief Open codec device.
  575. *
  576. * \return Pointer to a static NUTFILE structure.
  577. */
  578. static NUTFILE *VsOpen(NUTDEVICE * dev, const char *name, int mode, int acc)
  579. {
  580. NUTFILE *nfp;
  581. VsRegWrite(VS_MODE_REG, VS_SM_RESET | VS_SM_SDINEW);
  582. NutSleep(2);
  583. nfp = malloc(sizeof(NUTFILE));
  584. nfp->nf_dev = dev;
  585. nfp->nf_fcb = NULL;
  586. NutSegBufReset();
  587. return nfp;
  588. }
  589. /*!
  590. * \brief Close codec device.
  591. */
  592. static int VsClose(NUTFILE * nfp)
  593. {
  594. int rc = VsPlayerFlush();
  595. if (nfp) {
  596. free(nfp);
  597. }
  598. return rc;
  599. }
  600. static int VsPlayBufferInit(uint32_t size)
  601. {
  602. if (dcb.dcb_pbstat != CODEC_STATUS_IDLE) {
  603. return -1;
  604. }
  605. if (NutSegBufInit((size_t)size) == NULL) {
  606. return -1;
  607. }
  608. dcb.dcb_pbwlo = NutSegBufAvailable() / 3;
  609. dcb.dcb_pbwhi = dcb.dcb_pbwlo * 2;
  610. return 0;
  611. }
  612. /*!
  613. * \brief Handle I/O controls for audio codec.
  614. *
  615. * - AUDIO_PLAY Force playback start, even if the buffer level is too lower.
  616. * - AUDIO_CANCEL Cancel playback and discard all buffered data.
  617. * - AUDIO_GET_STATUS Sets an int to 1 if the player is running, 0 if idle.
  618. * - AUDIO_GET_PLAYGAIN Sets an int to the current playback gain, 0..-127.
  619. * - AUDIO_SET_PLAYGAIN Reads the requested playback gain from an int, 0..-127.
  620. * - AUDIO_GET_TREB Reads audio enhancement treble value as int in 1.5dB steps
  621. * - AUDIO_SET_TREB Sets audio enhancement treble value as int in 1.5dB steps
  622. * - AUDIO_GET_TFIN Reads audio enhancement treable cutoff frequency in 1000Hz steps
  623. * - AUDIO_SET_TFIN Sets audio enhancement treable cutoff frequency in 1000Hz steps
  624. * - AUDIO_GET_BASS Reads audio enhancement bass value as int in 1dB steps
  625. * - AUDIO_SET_BASS Sets audio enhancement bass value as int in 1dB steps
  626. * - AUDIO_GET_BFIN Reads audio enhancement bass cutoff frequency in 10Hz steps
  627. * - AUDIO_SET_BFIN Sets audio enhancement bass cutoff frequency in 10Hz steps
  628. * - AUDIO_GET_PBSIZE Sets an unsigned long with the size of the playback buffer.
  629. * - AUDIO_SET_PBSIZE Sets the size the playback buffer using an unsigned long.
  630. * - AUDIO_GET_PBLEVEL Sets an unsigned long with the number of bytes in the playback buffer.
  631. * - AUDIO_GET_PBWLOW Sets an unsigned long with the low watermark of the playback buffer.
  632. * - AUDIO_SET_PBWLOW Sets the low watermark (unsigned long) of the playback buffer.
  633. * - AUDIO_GET_PBWHIGH Sets an unsigned long with the high watermark of the playback buffer.
  634. * - AUDIO_SET_PBWHIGH Sets the high watermark (unsigned long) of the playback buffer.
  635. * - AUDIO_BEEP Plays a short sine wave beep.
  636. *
  637. * \return 0 on success, -1 otherwise.
  638. */
  639. static int VsIOCtl(NUTDEVICE * dev, int req, void *conf)
  640. {
  641. int rc = 0;
  642. uint32_t *lvp = (uint32_t *) conf;
  643. int *ivp = (int *) conf;
  644. int iv = *ivp;
  645. switch (req) {
  646. case AUDIO_PLAY:
  647. /* Immediately start playing. */
  648. if (dcb.dcb_pbstat != CODEC_STATUS_PLAYING) {
  649. dcb.dcb_scmd |= VSREQ_PLAY;
  650. }
  651. break;
  652. case AUDIO_CANCEL:
  653. /* Immediately stop playing and discard buffer. */
  654. if (dcb.dcb_pbstat == CODEC_STATUS_PLAYING) {
  655. dcb.dcb_scmd |= VSREQ_CANCEL;
  656. }
  657. break;
  658. case AUDIO_GET_STATUS:
  659. *ivp = dcb.dcb_pbstat;
  660. break;
  661. case AUDIO_GET_PLAYGAIN:
  662. if (dcb.dcb_crvol >= dcb.dcb_clvol) {
  663. *ivp = dcb.dcb_crvol;
  664. }
  665. else {
  666. *ivp = dcb.dcb_clvol;
  667. }
  668. break;
  669. case AUDIO_SET_PLAYGAIN:
  670. if (iv > AUDIO_DAC_MAX_GAIN) {
  671. iv = AUDIO_DAC_MAX_GAIN;
  672. }
  673. if (iv < AUDIO_DAC_MIN_GAIN) {
  674. iv = AUDIO_DAC_MIN_GAIN;
  675. }
  676. dcb.dcb_slvol = dcb.dcb_srvol = iv;
  677. break;
  678. case AUDIO_GET_TREB:
  679. *lvp = dcb.dcb_ctreb;
  680. break;
  681. case AUDIO_SET_TREB:
  682. if( iv > AUDIO_DAC_MAX_TREB) {
  683. iv = AUDIO_DAC_MAX_TREB;
  684. }
  685. dcb.dcb_streb = iv;
  686. break;
  687. case AUDIO_GET_TFIN:
  688. *lvp = dcb.dcb_ctfin;
  689. break;
  690. case AUDIO_SET_TFIN:
  691. if( iv > AUDIO_DAC_MAX_TFIN) {
  692. iv = AUDIO_DAC_MAX_TFIN;
  693. }
  694. dcb.dcb_stfin = iv;
  695. break;
  696. case AUDIO_GET_BASS:
  697. *lvp = dcb.dcb_cbass;
  698. break;
  699. case AUDIO_SET_BASS:
  700. if( iv > AUDIO_DAC_MAX_BASS) {
  701. iv = AUDIO_DAC_MAX_BASS;
  702. }
  703. dcb.dcb_sbass = iv;
  704. case AUDIO_GET_BFIN:
  705. *lvp = dcb.dcb_cbass;
  706. break;
  707. case AUDIO_SET_BFIN:
  708. if( iv > AUDIO_DAC_MAX_BFIN) {
  709. iv = AUDIO_DAC_MAX_BFIN;
  710. }
  711. dcb.dcb_sbass = iv;
  712. case AUDIO_GET_PBSIZE:
  713. *lvp = NutSegBufAvailable() + NutSegBufUsed();
  714. break;
  715. case AUDIO_SET_PBSIZE:
  716. rc = VsPlayBufferInit(*lvp);
  717. break;
  718. case AUDIO_GET_PBLEVEL:
  719. *lvp = NutSegBufUsed();
  720. break;
  721. case AUDIO_GET_PBWLOW:
  722. *lvp = dcb.dcb_pbwlo;
  723. break;
  724. case AUDIO_SET_PBWLOW:
  725. dcb.dcb_pbwlo = *lvp;
  726. break;
  727. case AUDIO_GET_PBWHIGH:
  728. *lvp = dcb.dcb_pbwhi;
  729. break;
  730. case AUDIO_SET_PBWHIGH:
  731. dcb.dcb_pbwhi = *lvp;
  732. break;
  733. case AUDIO_BEEP:
  734. dcb.dcb_scmd |= VSREQ_BEEP;
  735. break;
  736. #if 0
  737. case AUDIO_GET_DECINFO:
  738. /* Retrieve decoder information. */
  739. break;
  740. case AUDIO_GET_DECCAPS:
  741. /* Retrieve decoder capabilities. */
  742. break;
  743. case AUDIO_GET_DECFMTS:
  744. /* Retrieve decoder formats. */
  745. break;
  746. case AUDIO_SET_DECFMTS:
  747. /* Enable or disable specific decoder formats. */
  748. break;
  749. case AUDIO_GET_CODINFO:
  750. /* Retrieve encoder information. */
  751. break;
  752. case AUDIO_GET_CODCAPS:
  753. /* Retrieve encoder capabilities. */
  754. break;
  755. case AUDIO_GET_CODFMTS:
  756. /* Retrieve encoder formats. */
  757. break;
  758. case AUDIO_SET_CODFMTS:
  759. /* Enable or disable specific encoder formats. */
  760. break;
  761. case AUDIO_GET_MIDINFO:
  762. /* Retrieve midi information. */
  763. break;
  764. case AUDIO_GET_MIDCAPS:
  765. /* Retrieve midi capabilities. */
  766. break;
  767. #endif
  768. default:
  769. rc = -1;
  770. break;
  771. }
  772. return rc;
  773. }
  774. /*
  775. * Called via dev_init pointer when the device is registered.
  776. */
  777. static int VsInit(NUTDEVICE * dev)
  778. {
  779. uint16_t mode;
  780. /* Release reset line and read the status register. */
  781. outr(PIOB_PER, _BV(VS_XRESET_BIT));
  782. outr(PIOB_SODR, _BV(VS_XRESET_BIT));
  783. outr(PIOB_OER, _BV(VS_XRESET_BIT));
  784. NutSleep(3);
  785. VsRegRead(VS_MODE_REG); /* Dummy read. TODO: Why? */
  786. mode = VsRegRead(VS_MODE_REG);
  787. if ((mode & VS_SM_SDINEW) == 0) {
  788. VsRegWrite(VS_MODE_REG, VS_SM_RESET | VS_SM_SDINEW);
  789. NutSleep(2);
  790. }
  791. vs_chip = (VsRegRead(VS_STATUS_REG) & VS_SS_VER) >> VS_SS_VER_LSB;
  792. #if VS10XX_FREQ < 20000000UL && defined(VS_CF_DOUBLER)
  793. VsRegWrite(VS_CLOCKF_REG, (uint16_t)(VS_CF_DOUBLER | (VS10XX_FREQ / 2000UL)));
  794. #else
  795. VsRegWrite(VS_CLOCKF_REG, (uint16_t)(VS10XX_FREQ / 2000UL));
  796. #endif
  797. #if defined(VS_INT_FCTLH_REG)
  798. if (vs_chip == 0) {
  799. /* Force frequency change (see datasheet). */
  800. VsRegWrite(VS_INT_FCTLH_REG, 0x8008);
  801. }
  802. #endif
  803. if (VsPlayBufferInit(0)) {
  804. return -1;
  805. }
  806. if (NutThreadCreate("vsdeco", FeederThread, NULL, 1024) == 0) {
  807. return -1;
  808. }
  809. return 0;
  810. }
  811. /*!
  812. * \brief VS10XX device information structure.
  813. *
  814. * An application must pass a pointer to this structure to
  815. * NutRegisterDevice() before using this driver.
  816. *
  817. * The device is named \b audio0.
  818. *
  819. * \showinitializer
  820. */
  821. NUTDEVICE devVsCodec = {
  822. 0, /* Pointer to next device, dev_next. */
  823. {'a', 'u', 'd', 'i', 'o', '0', 0, 0, 0}, /* Unique device name, dev_name. */
  824. IFTYP_CHAR, /* Type of device, dev_type. */
  825. 0, /* Base address, dev_base (not used). */
  826. 0, /* First interrupt number, dev_irq (not used). */
  827. 0, /* Interface control block, dev_icb (not used). */
  828. &dcb, /* Driver control block, dev_dcb. */
  829. VsInit, /* Driver initialization routine, dev_init. */
  830. VsIOCtl, /* Driver specific control function, dev_ioctl. */
  831. NULL, /* Read from device, dev_read. */
  832. VsWrite, /* Write to device, dev_write. */
  833. #ifdef __HARVARD_ARCH__
  834. VsWrite_P, /* Write data from program space to device, dev_write_P. */
  835. #endif
  836. VsOpen, /* Open a device or file, dev_open. */
  837. VsClose, /* Close a device or file, dev_close. */
  838. NULL, /* Request file size, dev_size. */
  839. NULL, /* Select function, optional, not yet implemented */
  840. };
  841. /*@}*/