sbimmc.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. /*
  2. * Copyright (C) 2006 by egnite Software GmbH. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the copyright holders nor the names of
  14. * contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  24. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  25. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  26. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  27. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28. * SUCH DAMAGE.
  29. *
  30. * For additional information see http://www.ethernut.de/
  31. */
  32. /*!
  33. * \brief Low Level Multimedia Card Access.
  34. *
  35. * Low level MMC hardware routines for SPI emulation by software
  36. * (bit banging).
  37. *
  38. * These routines support SPI mode only and are required by the
  39. * basic MMC driver.
  40. *
  41. * \verbatim
  42. *
  43. * $Log$
  44. * Revision 1.7 2008/08/11 06:59:42 haraldkipp
  45. * BSD types replaced by stdint types (feature request #1282721).
  46. *
  47. * Revision 1.6 2006/06/28 17:22:34 haraldkipp
  48. * Make it compile for AT91SAM7X256.
  49. *
  50. * Revision 1.5 2006/04/07 12:48:41 haraldkipp
  51. * Port configuration is now honored.
  52. *
  53. * Revision 1.4 2006/03/16 19:07:36 haraldkipp
  54. * Disabled inline assembly routine for ARM bit banging SPI. Stopped working
  55. * with optimizing compiler.
  56. *
  57. * Revision 1.3 2006/03/02 19:58:16 haraldkipp
  58. * Too lazy to port the inline assembly to ICCARM.
  59. *
  60. * Revision 1.2 2006/02/28 02:16:12 hwmaier
  61. * Added macro definition MCU_AT90CAN128
  62. *
  63. * Revision 1.1 2006/02/23 15:38:03 haraldkipp
  64. * MMC low level bit banging SPI added. Compiles on all supported platforms,
  65. * but tested with AT91 only.
  66. *
  67. *
  68. * \endverbatim
  69. */
  70. #include <cfg/arch.h>
  71. #include <cfg/arch/gpio.h>
  72. #include <sys/event.h>
  73. #include <dev/irqreg.h>
  74. #include <dev/mmcard.h>
  75. #include <dev/sbimmc.h>
  76. #if 0
  77. /* Use for local debugging. */
  78. #define NUTDEBUG
  79. #include <stdio.h>
  80. #endif
  81. /*!
  82. * \addtogroup xgSbiMmc
  83. */
  84. /*@{*/
  85. #ifndef SPI0_CS_BIT
  86. /*! \brief Port bit for SPI chip select. */
  87. #define SPI0_CS_BIT 6
  88. #endif
  89. #ifndef SPI0_CLK_BIT
  90. /*! \brief Port bit for SPI clock. */
  91. #define SPI0_CLK_BIT 4
  92. #endif
  93. #ifndef SPI0_MOSI_BIT
  94. /*! \brief Port bit for SPI MOSI line. */
  95. #define SPI0_MOSI_BIT 5
  96. #endif
  97. #ifndef SPI0_MISO_BIT
  98. /*! \brief Port bit for SPI MISO line. */
  99. #define SPI0_MISO_BIT 3
  100. #endif
  101. #if defined(MCU_AT91R40008) || defined(MCU_AT91SAM7X) /* MCU ---------------------- */
  102. #ifndef SPI0_PE_REG
  103. /*! \brief SPI port enable register.
  104. */
  105. #define SPI0_PE_REG PIO_PER
  106. #endif
  107. #ifndef SPI0_PD_REG
  108. /*! \brief SPI port disable register.
  109. */
  110. #define SPI0_PD_REG PIO_PDR
  111. #endif
  112. #ifndef SPI0_OE_REG
  113. /*! \brief SPI output enable register. */
  114. #define SPI0_OE_REG PIO_OER
  115. #endif
  116. #ifndef SPI0_OD_REG
  117. /*! \brief SPI output disable register. */
  118. #define SPI0_OD_REG PIO_ODR
  119. #endif
  120. #ifndef SPI0_SOD_REG
  121. /*! \brief SPI set output data register. */
  122. #define SPI0_SOD_REG PIO_SODR
  123. #endif
  124. #ifndef SPI0_COD_REG
  125. /*! \brief SPI clear output data register. */
  126. #define SPI0_COD_REG PIO_CODR
  127. #endif
  128. #ifndef SPI0_PDS_REG
  129. /*! \brief SPI port data status register. */
  130. #define SPI0_PDS_REG PIO_PDSR
  131. #endif
  132. #ifndef SPI0_ODS_REG
  133. /*! \brief SPI port output status register. */
  134. #define SPI0_ODS_REG PIO_ODSR
  135. #endif
  136. #ifdef MMC0_CD_BIT
  137. #if MMC0_CD_BIT == 9
  138. #define SIG_MMC0DETECT sig_INTERRUPT0
  139. #elif MMC0_CD_BIT == 10
  140. #define SIG_MMC0DETECT sig_INTERRUPT1
  141. #elif MMC0_CD_BIT == 11
  142. #define SIG_MMC0DETECT sig_INTERRUPT2
  143. #else
  144. #warning "No external interrupt for card detect"
  145. #undef MMC0_CD_BIT
  146. #endif
  147. #endif
  148. #elif defined(MCU_ATMEGA2561) || defined(MCU_AT90CAN128) || defined(MCU_ATMEGA128) || defined(MCU_ATMEGA103) /* MCU */
  149. #ifndef inr
  150. #define inr(a) inb(a)
  151. #endif
  152. #ifndef outr
  153. #define outr(a, v) outb(a, v)
  154. #endif
  155. #ifndef SPI0_OE_REG
  156. #if SPI0_PORT == AVRPORTA
  157. #define SPI0_OE_REG DDRA
  158. #elif SPI0_PORT == AVRPORTC
  159. #define SPI0_OE_REG DDRC
  160. #elif SPI0_PORT == AVRPORTD
  161. #define SPI0_OE_REG DDRD
  162. #elif SPI0_PORT == AVRPORTE
  163. #define SPI0_OE_REG DDRE
  164. #elif SPI0_PORT == AVRPORTF
  165. #define SPI0_OE_REG DDRF
  166. #elif SPI0_PORT == AVRPORTG
  167. #define SPI0_OE_REG DDRG
  168. #else
  169. /*! \brief SPI port enable register. */
  170. #define SPI0_OE_REG DDRB
  171. #endif
  172. #endif
  173. #ifndef SPI0_SOD_REG
  174. #if SPI0_PORT == AVRPORTA
  175. #define SPI0_SOD_REG PORTA
  176. #elif SPI0_PORT == AVRPORTC
  177. #define SPI0_SOD_REG PORTC
  178. #elif SPI0_PORT == AVRPORTD
  179. #define SPI0_SOD_REG PORTD
  180. #elif SPI0_PORT == AVRPORTE
  181. #define SPI0_SOD_REG PORTE
  182. #elif SPI0_PORT == AVRPORTF
  183. #define SPI0_SOD_REG PORTF
  184. #elif SPI0_PORT == AVRPORTG
  185. #define SPI0_SOD_REG PORTG
  186. #else
  187. /*! \brief SPI port output register. */
  188. #define SPI0_SOD_REG PORTB
  189. #endif
  190. #endif
  191. #ifndef SPI0_PDS_REG
  192. #if SPI0_PORT == AVRPORTA
  193. #define SPI0_PDS_REG PINA
  194. #elif SPI0_PORT == AVRPORTC
  195. #define SPI0_PDS_REG PINC
  196. #elif SPI0_PORT == AVRPORTD
  197. #define SPI0_PDS_REG PIND
  198. #elif SPI0_PORT == AVRPORTE
  199. #define SPI0_PDS_REG PINE
  200. #elif SPI0_PORT == AVRPORTF
  201. #define SPI0_PDS_REG PINF
  202. #elif SPI0_PORT == AVRPORTG
  203. #define SPI0_PDS_REG PING
  204. #else
  205. /*! \brief SPI port input register. */
  206. #define SPI0_PDS_REG PINB
  207. #endif
  208. #endif
  209. #elif !defined(SPI0_OE_REG) || !defined(SPI0_SOD_REG) || !defined(SPI0_PDS_REG)
  210. #warning "No SPI bit banging registers for unknown CPU."
  211. #endif /* MCU ---------------------- */
  212. #ifdef SPI0_COD_REG
  213. /*! \brief Set specified MMC line low. */
  214. #define MMC0_CLR_BIT(n) outr(SPI0_COD_REG, _BV(n))
  215. /*! \brief Set specified MMC line high. */
  216. #define MMC0_SET_BIT(n) outr(SPI0_SOD_REG, _BV(n))
  217. #else
  218. #define MMC0_CLR_BIT(n) outr(SPI0_SOD_REG, inr(SPI0_SOD_REG) & ~_BV(n))
  219. #define MMC0_SET_BIT(n) outr(SPI0_SOD_REG, inr(SPI0_SOD_REG) | _BV(n))
  220. #endif
  221. #ifdef SPI0_ODS_REG
  222. /*! \brief Query status of a specified MMC output. */
  223. #define MMC0_IS_BIT_SET(n) ((inr(SPI0_ODS_REG) & _BV(n)) == _BV(n))
  224. #else
  225. #define MMC0_IS_BIT_SET(n) ((inr(SPI0_SOD_REG) & _BV(n)) == _BV(n))
  226. #endif
  227. /*! \brief Query status of a specified MMC input. */
  228. #define MMC0_TST_BIT(n) ((inr(SPI0_PDS_REG) & _BV(n)) == _BV(n))
  229. /*!
  230. * \brief Private data of NPL card interface.
  231. */
  232. typedef struct _MMCDCB {
  233. int dcb_avail; /*!< Card is available. */
  234. int dcb_changed; /*!< Card has changed. */
  235. int dcb_addr_mode; /*!< Card addressing mode (byte/block) */
  236. } MMCDCB;
  237. static MMCDCB mmc0_dcb;
  238. /*!
  239. * \brief Initialize the card in slot 0.
  240. *
  241. * Called by the MMC driver during card reset. The card change
  242. * detection flag will be cleared.
  243. *
  244. * \return 0 on success, -1 if no card is detected.
  245. */
  246. static int SbiMmCard0Init(void)
  247. {
  248. mmc0_dcb.dcb_changed = 0;
  249. if (mmc0_dcb.dcb_avail) {
  250. return 0;
  251. }
  252. return -1;
  253. }
  254. /*!
  255. * \brief Activate or deactivate chip select on card slot 0.
  256. *
  257. * \param on The card will be selected if 1, deselected if 0.
  258. * Any other value can be used to query the status.
  259. *
  260. * \return Previous select status. 1 if selected, 0 otherwise.
  261. */
  262. static int SbiMmCard0Select(int on)
  263. {
  264. int rc = MMC0_IS_BIT_SET(SPI0_CS_BIT);
  265. /* MMC select is low active. */
  266. if (on == 1) {
  267. MMC0_CLR_BIT(SPI0_CS_BIT);
  268. } else if (on == 0) {
  269. MMC0_SET_BIT(SPI0_CS_BIT);
  270. }
  271. return rc;
  272. }
  273. /*!
  274. * \brief Read the previously received byte and transmit a new one.
  275. *
  276. * \param val Byte to transmit.
  277. *
  278. * \return Last byte received.
  279. */
  280. static uint8_t SbiMmCard0Io(uint8_t val)
  281. {
  282. uint8_t msk = 0x80;
  283. #ifdef NUTDEBUG
  284. putchar('[');
  285. if (val != 0xFF) {
  286. printf("s%02X", val);
  287. }
  288. #endif
  289. #if defined(MCU_AT91R40008) && defined(__GNUC__) && 0
  290. /* ARM assembly version, tested on AT91R40008 only. */
  291. asm volatile (
  292. "\nspi_tran_l:\n\t"
  293. "str %7, [%3, %5]" "\n\t" /* SCK low. */
  294. "tst %0, %2" "\n\t" /* Check data bit. */
  295. "strne %8, [%3, %4]" "\n\t" /* MOSI high. */
  296. "streq %8, [%3, %5]" "\n\t" /* MOSI low. */
  297. "bic %0, %1, %2" "\n\t" /* Clear data bit */
  298. "str %7, [%3, %4]" "\n\t" /* SCK high. */
  299. "ldr r1, [%3, %6]" "\n\t" /* Read MISO */
  300. "tst r1, %9" "\n\t" /* Test MISO */
  301. "orrne %0, %1, %2" "\n\t" /* Set data bit if MOSI was high */
  302. "movs %2, %2, lsr #1""\n\t" /* msk <<= 1 */
  303. "bne spi_tran_l" /* Loop for next bit. */
  304. : "=r" (val) /* %0 output */
  305. : "0" (val) /* %1 input */
  306. , "r" (msk) /* %2 input */
  307. , "r" (PIO_BASE) /* %3 input */
  308. , "J" (PIO_SODR - PIO_BASE) /* %4 input */
  309. , "J" (PIO_CODR - PIO_BASE) /* %5 input */
  310. , "J" (PIO_PDSR - PIO_BASE) /* %6 input */
  311. , "r" _BV(SPI0_CLK_BIT) /* %7 input */
  312. , "r" _BV(SPI0_MOSI_BIT) /* %8 input */
  313. , "I" _BV(SPI0_MISO_BIT) /* %9 input */
  314. : "r1"
  315. );
  316. #else
  317. /* Generic code. */
  318. while (msk) {
  319. MMC0_CLR_BIT(SPI0_CLK_BIT);
  320. if (val & msk) {
  321. MMC0_SET_BIT(SPI0_MOSI_BIT);
  322. } else {
  323. MMC0_CLR_BIT(SPI0_MOSI_BIT);
  324. }
  325. MMC0_SET_BIT(SPI0_CLK_BIT);
  326. if (MMC0_TST_BIT(SPI0_MISO_BIT)) {
  327. val |= msk;
  328. }
  329. else {
  330. val &= ~msk;
  331. }
  332. msk >>= 1;
  333. }
  334. #endif
  335. #ifdef NUTDEBUG
  336. if (val != 0xFF) {
  337. printf("r%02X", val);
  338. }
  339. putchar(']');
  340. #endif
  341. return val;
  342. }
  343. /*!
  344. * \brief Check if card is available in slot 0.
  345. *
  346. * \todo Card change should verify the card identifier. Right now
  347. * any detection of removing and re-inserting a card counts
  348. * as a card change.
  349. *
  350. * \return 0 if no card is detected, 1 if a card is available or 2 if
  351. * a card change had been detected after the last mount.
  352. */
  353. int SbiMmCard0Avail(void)
  354. {
  355. if (mmc0_dcb.dcb_avail) {
  356. if (mmc0_dcb.dcb_changed) {
  357. return 2;
  358. }
  359. return 1;
  360. }
  361. return 0;
  362. }
  363. /*!
  364. * \brief Check if card in slot 0 is write protected.
  365. *
  366. * \todo Not implemented.
  367. *
  368. * \return Always 0.
  369. */
  370. int SbiMmCard0WrProt(void)
  371. {
  372. return 0;
  373. }
  374. /*!
  375. * \brief set addressing mode
  376. *
  377. */
  378. int SbiMmCard0SetAdrMode(int mode)
  379. {
  380. mmc0_dcb.dcb_addr_mode = mode;
  381. return(0);
  382. }
  383. /*!
  384. * \brief get addressing mode
  385. *
  386. */
  387. int SbiMmCard0GetAdrMode(void)
  388. {
  389. return(mmc0_dcb.dcb_addr_mode);
  390. }
  391. #ifdef MMC0_CD_BIT
  392. /*!
  393. * \brief Card slot 0 insertion interrupt routine.
  394. *
  395. * \todo A different routine is required to support multiple cards.
  396. *
  397. * \param arg Pointer to the device information structure.
  398. */
  399. static void SbiMmCard0DetectIrq(void *arg)
  400. {
  401. int mode = NutIrqSetMode(&SIG_MMC0DETECT, NUT_IRQMODE_LOWLEVEL);
  402. if (mode == NUT_IRQMODE_HIGHLEVEL) {
  403. mmc0_dcb.dcb_avail = 0;
  404. }
  405. else {
  406. NutIrqSetMode(&SIG_MMC0DETECT, NUT_IRQMODE_HIGHLEVEL);
  407. mmc0_dcb.dcb_avail = 1;
  408. }
  409. mmc0_dcb.dcb_changed = 1;
  410. }
  411. #endif
  412. /*!
  413. * \brief Initialize MMC hardware interface.
  414. *
  415. * This function is automatically executed during during device
  416. * registration via NutRegisterDevice().
  417. *
  418. * \param dev Identifies the device to initialize.
  419. */
  420. static int SbiMmcIfcInit(NUTDEVICE * dev)
  421. {
  422. #ifdef SPI0_PE_REG
  423. /* Enable all SPI ports, if a port enable register is defined. */
  424. outr(SPI0_PE_REG, _BV(SPI0_CLK_BIT) | _BV(SPI0_MOSI_BIT) | _BV(SPI0_CS_BIT) | _BV(SPI0_MISO_BIT));
  425. #endif
  426. #ifdef SPI0_OD_REG
  427. /* Enable CLK, MOSI and CS output pins. */
  428. outr(SPI0_OE_REG, _BV(SPI0_CLK_BIT) | _BV(SPI0_MOSI_BIT) | _BV(SPI0_CS_BIT));
  429. /* Enable MISO input pin. */
  430. outr(SPI0_OD_REG, _BV(SPI0_MISO_BIT));
  431. #else
  432. /*
  433. * If this CPU hasn't got a specific output disable register, we
  434. * assume that inputs are enabled by clearing the corresponding bit
  435. * in the output enable register.
  436. */
  437. outr(SPI0_OE_REG, (inr(SPI0_OE_REG) & ~_BV(SPI0_MISO_BIT))
  438. | _BV(SPI0_CLK_BIT) | _BV(SPI0_MOSI_BIT) | _BV(SPI0_CS_BIT));
  439. #endif
  440. /* Set all outputs high. */
  441. outr(SPI0_SOD_REG, _BV(SPI0_CLK_BIT) | _BV(SPI0_MOSI_BIT) | _BV(SPI0_CS_BIT));
  442. #ifdef MMC0_CD_BIT
  443. #ifdef SPI0_PD_REG
  444. outr(SPI0_PD_REG, _BV(MMC0_CD_BIT));
  445. #endif
  446. /* Register card detection interrupts. */
  447. if (NutRegisterIrqHandler(&SIG_MMC0DETECT, SbiMmCard0DetectIrq, 0)) {
  448. mmc0_dcb.dcb_avail = 1;
  449. }
  450. else {
  451. mmc0_dcb.dcb_avail = 0;
  452. NutIrqSetMode(&SIG_MMC0DETECT, NUT_IRQMODE_LOWLEVEL);
  453. NutIrqEnable(&SIG_MMC0DETECT);
  454. }
  455. #else
  456. mmc0_dcb.dcb_avail = 1;
  457. #endif /* MMC0_CD_BIT */
  458. mmc0_dcb.dcb_changed = 0;
  459. return MmCardDevInit(dev);
  460. }
  461. static MMCIFC mmc0_ifc = {
  462. SbiMmCard0Init, /*!< mmcifc_in */
  463. SbiMmCard0Io, /*!< mmcifc_io */
  464. SbiMmCard0Select, /*!< mmcifc_cs */
  465. SbiMmCard0Avail, /*!< mmcifc_cd */
  466. SbiMmCard0WrProt, /*!< mmcifc_wp */
  467. SbiMmCard0SetAdrMode, /*!< mmcifc_sm */
  468. SbiMmCard0GetAdrMode /*!< mmcifc_gm */
  469. };
  470. /*!
  471. * \brief Multimedia card device information structure.
  472. *
  473. * A pointer to this structure must be passed to NutRegisterDevice()
  474. * to bind this driver to the Nut/OS kernel. An application may then
  475. * call
  476. * /verbatim
  477. * _open("MMC0:", _O_RDWR | _O_BINARY);
  478. * /endverbatim
  479. * to mount the first active primary partition with any previously
  480. * registered file system driver (typically devPhat0).
  481. */
  482. NUTDEVICE devSbiMmc0 = {
  483. 0, /*!< Pointer to next device, dev_next. */
  484. {'M', 'M', 'C', '0', 0, 0, 0, 0, 0}
  485. , /*!< Unique device name, dev_name. */
  486. 0, /*!< Type of device, dev_type. Obsolete. */
  487. 0, /*!< Base address, dev_base. Unused. */
  488. 0, /*!< First interrupt number, dev_irq. Unused. */
  489. &mmc0_ifc, /*!< Interface control block, dev_icb. */
  490. &mmc0_dcb, /*!< Driver control block used by the low level part, dev_dcb. */
  491. SbiMmcIfcInit, /*!< Driver initialization routine, dev_init. */
  492. MmCardIOCtl, /*!< Driver specific control function, dev_ioctl. */
  493. MmCardBlockRead, /*!< Read data from a file, dev_read. */
  494. MmCardBlockWrite, /*!< Write data to a file, dev_write. */
  495. #ifdef __HARVARD_ARCH__
  496. MmCardBlockWrite_P, /*!< Write data from program space to a file, dev_write_P. */
  497. #endif
  498. MmCardMount, /*!< Mount a file system, dev_open. */
  499. MmCardUnmount, /*!< Unmount a file system, dev_close. */
  500. NULL, /*!< Return file size, dev_size. */
  501. NULL, /*!< Select function, optional, not yet implemented */
  502. };
  503. /*@}*/