at91_twi.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. /*
  2. * Copyright (C) 2001-2005 by EmbeddedIT, Ole Reinhardt
  3. * Copyright (C) 2009 by Rittal GmbH & Co. KG, Ulrich Prinz
  4. * Copyright 2009 by egnite GmbH
  5. *
  6. * All rights reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. * 3. Neither the name of the copyright holders nor the names of
  18. * contributors may be used to endorse or promote products derived
  19. * from this software without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  29. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  30. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  31. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32. * SUCH DAMAGE.
  33. *
  34. * For additional information see http://www.ethernut.de/
  35. *
  36. */
  37. /*
  38. * $Id: at91_twi.c 5472 2013-12-06 00:16:28Z olereinhardt $
  39. */
  40. #include <arch/arm.h>
  41. #include <dev/irqreg.h>
  42. #include <string.h>
  43. #include <sys/event.h>
  44. #include <sys/atom.h>
  45. #include <sys/timer.h>
  46. #include <sys/thread.h>
  47. #include <sys/heap.h>
  48. #include <dev/twif.h>
  49. /*!
  50. * \addtogroup xgNutArchArmAt91Twi
  51. */
  52. /*@{*/
  53. /*
  54. * Set ports for known targets.
  55. */
  56. #if defined(MCU_AT91SAM7X)
  57. #define TWI_TWD PA10_TWD_A
  58. #define TWI_TWCK PA11_TWCK_A
  59. #elif defined(MCU_AT91SAM7S) || defined(MCU_AT91SAM7SE)
  60. #define TWI_TWD PA3_TWD_A
  61. #define TWI_TWCK PA4_TWCK_A
  62. #elif defined (MCU_AT91SAM9260) || defined(MCU_AT91SAM9XE)
  63. #define TWI_TWD PA23_TWD_A
  64. #define TWI_TWCK PA24_TWCK_A
  65. #elif defined (MCU_AT91SAM9G45)
  66. #define TWI_TWD PA20_TWD0_A
  67. #define TWI_TWCK PA21_TWCK0_A
  68. #endif
  69. /*
  70. * Set port defaults, assume PIOA.
  71. */
  72. #ifndef TWI_PIO_ASR
  73. #define TWI_PIO_ASR PIOA_ASR
  74. #endif
  75. #ifndef TWI_PIO_PDR
  76. #define TWI_PIO_PDR PIOA_PDR
  77. #endif
  78. #ifndef TWI_PIO_MDER
  79. #define TWI_PIO_MDER PIOA_MDER
  80. #endif
  81. #if 0
  82. static uint8_t *tw_mm_buf; /* Pointer to the master transfer buffer. */
  83. static volatile size_t tw_mm_len; /* Number of bytes to transmit in master mode. */
  84. static volatile size_t tw_mm_idx; /* Current master transmit buffer index. */
  85. #endif
  86. /*
  87. * TWI interrupt handler.
  88. */
  89. static void TwInterrupt(void *arg)
  90. {
  91. register unsigned int twsr;
  92. NUTTWIBUS *bus = arg;
  93. NUTTWIICB *icb = bus->bus_icb;
  94. /* Read the status register and check for errors. */
  95. twsr = inr(TWI_SR);
  96. if (twsr & (TWI_NACK | TWI_OVRE | TWI_ARBLST)) {
  97. if (twsr & TWI_NACK) {
  98. icb->tw_mm_err = TWERR_SLA_NACK;
  99. } else {
  100. icb->tw_mm_err = TWERR_BUS;
  101. }
  102. }
  103. /* Mask inactive interrupt flags. */
  104. twsr &= inr(TWI_IMR);
  105. if (twsr & TWI_TXRDY) {
  106. /* Byte has been transmitted. */
  107. if (icb->tw_mm_idx < icb->tw_mm_len) {
  108. /* More bytes in buffer, send next one. */
  109. outb(TWI_THR, icb->tw_mm_buf[icb->tw_mm_idx]);
  110. icb->tw_mm_idx++;
  111. } else {
  112. /* All bytes sent, wait for completion. */
  113. #if defined(MCU_AT91SAM9XE)
  114. /* On the SAM9XE the stop condition is not sent automatically
  115. when the transmitter runs out of data. */
  116. outr(TWI_CR, TWI_STOP);
  117. #endif
  118. outr(TWI_IDR, TWI_TXRDY);
  119. outr(TWI_IER, TWI_TXCOMP);
  120. }
  121. } else if (twsr & TWI_RXRDY) {
  122. /* Byte has been received. */
  123. if (icb->tw_mm_idx < icb->tw_mm_len) {
  124. /* Store byte in receive buffer. */
  125. icb->tw_mm_buf[icb->tw_mm_idx++] = inb(TWI_RHR);
  126. if (icb->tw_mm_idx == icb->tw_mm_len - 1) {
  127. /* Next byte will be last, set STOP condition. */
  128. outr(TWI_CR, TWI_STOP);
  129. } else if (icb->tw_mm_idx == icb->tw_mm_len) {
  130. /* This was the last byte, wait for completion. */
  131. outr(TWI_IDR, TWI_RXRDY);
  132. outr(TWI_IER, TWI_TXCOMP);
  133. }
  134. }
  135. } else if (twsr & TWI_TXCOMP) {
  136. /* Transfer is complete, disable interrupts
  137. ** and signal waiting threads */
  138. outr(TWI_IDR, 0xFFFFFFFF);
  139. NutEventPostFromIrq(&icb->tw_mm_mtx);
  140. }
  141. }
  142. /*!
  143. * \brief Transmit and/or receive data as a master.
  144. *
  145. * The two-wire serial interface must have been initialized by calling
  146. * TwInit() before this function can be used.
  147. *
  148. * \param sla Slave address of the destination. This slave address
  149. * must be specified as a 7-bit address. For example, the
  150. * PCF8574A may be configured to slave addresses from 0x38
  151. * to 0x3F.
  152. * \param txdata Points to the data to transmit. Ignored, if the number
  153. * of data bytes to transmit is zero.
  154. * \param txlen Number of data bytes to transmit. If zero, then the
  155. * interface will not send any data to the slave device
  156. * and will directly enter the master receive mode.
  157. * \param rxdata Points to a buffer, where the received data will be
  158. * stored. Ignored, if the maximum number of bytes to
  159. * receive is zero.
  160. * \param rxsiz Maximum number of bytes to receive. Set to zero, if
  161. * no bytes are expected from the slave device.
  162. * \param tmo Timeout in milliseconds. To disable timeout, set this
  163. * parameter to NUT_WAIT_INFINITE.
  164. *
  165. * \return The number of bytes received, -1 in case of an error or timeout.
  166. */
  167. int NutTwiMasterTranceive(NUTTWIBUS *bus, uint8_t sla, const void *txdata, uint16_t txlen, void *rxdata, uint16_t rxsiz, uint32_t tmo)
  168. {
  169. int rc = -1;
  170. NUTTWIICB *icb = bus->bus_icb;
  171. /* This routine is marked reentrant, so lock the interface. */
  172. if (NutEventWait(&bus->bus_mutex, tmo)) {
  173. icb->tw_mm_error = TWERR_IF_LOCKED;
  174. return -1;
  175. }
  176. /* Clear errors. */
  177. icb->tw_mm_err = 0;
  178. /* Check if there is something to transmit. */
  179. if (txlen) {
  180. /* Set transmit parameters. */
  181. icb->tw_mm_buf = (uint8_t *) txdata;
  182. icb->tw_mm_len = (size_t) txlen;
  183. icb->tw_mm_idx = 1;
  184. /* Start transmit to specified slave address. */
  185. outr(TWI_MMR, (unsigned int) sla << TWI_DADR_LSB);
  186. outr(TWI_THR, icb->tw_mm_buf[0]);
  187. outr(TWI_IER, TWI_TXRDY);
  188. /* Wait for transmission complete. */
  189. // TODO: Mustn't this be NutEventWaitNext() ??
  190. if (NutEventWait(&icb->tw_mm_mtx, tmo)) {
  191. icb->tw_mm_err = TWERR_TIMEOUT;
  192. }
  193. }
  194. if (icb->tw_mm_err == 0) {
  195. /* Reset receive counter. We need this below to set
  196. ** the return value. */
  197. icb->tw_mm_idx = 0;
  198. /* Check if there is something to receive. */
  199. if (rxsiz) {
  200. /* Set remaining receive parameters. */
  201. icb->tw_mm_buf = (uint8_t *) rxdata;
  202. icb->tw_mm_len = (size_t) rxsiz;
  203. /* Start receive from specified slave address. */
  204. outr(TWI_MMR, ((unsigned int) sla << TWI_DADR_LSB) | TWI_MREAD);
  205. if (rxsiz == 1) {
  206. /* Set STOP condition if this is the last byte. */
  207. outr(TWI_CR, TWI_START | TWI_STOP);
  208. } else {
  209. outr(TWI_CR, TWI_START);
  210. }
  211. outr(TWI_IER, TWI_RXRDY);
  212. /* Wait for receiver complete. */
  213. if (NutEventWait(&icb->tw_mm_mtx, tmo)) {
  214. icb->tw_mm_err = TWERR_TIMEOUT;
  215. }
  216. }
  217. }
  218. /* Make sure that all interrupts are disabled. */
  219. outr(TWI_IDR, 0xFFFFFFFF);
  220. /* Check for errors that may have been detected
  221. ** by the interrupt routine. */
  222. if (icb->tw_mm_err) {
  223. icb->tw_mm_error = icb->tw_mm_err;
  224. } else {
  225. rc = (int) icb->tw_mm_idx;
  226. }
  227. /* Release the interface. */
  228. NutEventPost(&bus->bus_mutex);
  229. return rc;
  230. }
  231. /*!
  232. * \brief Receive data as a master from a device having internal addressable registers
  233. *
  234. * The two-wire serial interface must have been initialized by calling
  235. * TwInit() before this function can be used.
  236. *
  237. * \param sla Slave address of the destination. This slave address
  238. * must be specified as a 7-bit address. For example, the
  239. * PCF8574A may be configured to slave addresses from 0x38
  240. * to 0x3F.
  241. * \param iadr Address send to the device to access certain registers
  242. * or memory addresses of it.
  243. * \param iadrlen Number of bytes to send as address, maximum 3 bytes are
  244. * supported from AT91SAM7
  245. * \param rxdata Points to a buffer, where the received data will be
  246. * stored.
  247. * \param rxsiz Maximum number of bytes to receive.
  248. * \param tmo Timeout in milliseconds. To disable timeout, set this
  249. * parameter to NUT_WAIT_INFINITE.
  250. *
  251. * \return The number of bytes received, -1 in case of an error or timeout.
  252. */
  253. int NutTwiMasterRegRead(NUTTWIBUS *bus, uint8_t sla, uint32_t iadr, uint8_t iadrlen, void *rxdata, uint16_t rxsiz, uint32_t tmo)
  254. {
  255. int rc = -1;
  256. NUTTWIICB *icb = bus->bus_icb;
  257. if (rxsiz == 0) {
  258. return -1;
  259. }
  260. /* This routine is marked reentrant, so lock the interface. */
  261. if (NutEventWait(&bus->bus_mutex, tmo)) {
  262. icb->tw_mm_error = TWERR_IF_LOCKED;
  263. return -1;
  264. }
  265. icb->tw_mm_err = 0;
  266. if (rxsiz) {
  267. icb->tw_mm_buf = rxdata;
  268. icb->tw_mm_len = (size_t) rxsiz;
  269. icb->tw_mm_idx = 0;
  270. /* Set TWI Internal Address Register if needed */
  271. outr(TWI_IADRR, iadr);
  272. /* Set the TWI Master Mode Register */
  273. outr(TWI_MMR, ((unsigned int) sla << TWI_DADR_LSB) | (((unsigned int) iadrlen & 3) << 8) | TWI_MREAD);
  274. /* Send start condition. If read only one byte send stop as well */
  275. if (rxsiz == 1) {
  276. outr(TWI_CR, TWI_START | TWI_STOP);
  277. } else {
  278. outr(TWI_CR, TWI_START);
  279. }
  280. outr(TWI_IER, TWI_RXRDY);
  281. /* Wait for master transmission to be done. */
  282. if (NutEventWait(&icb->tw_mm_mtx, tmo)) {
  283. icb->tw_mm_error = TWERR_TIMEOUT;
  284. } else if (icb->tw_mm_err) {
  285. icb->tw_mm_error = icb->tw_mm_err;
  286. } else {
  287. rc = (int) icb->tw_mm_idx;
  288. }
  289. outr(TWI_IDR, 0xFFFFFFFF);
  290. }
  291. /* Release the interface. */
  292. NutEventPost(&bus->bus_mutex);
  293. return rc;
  294. }
  295. /*!
  296. * \brief Transmit data as a master to a device having internal addressable registers
  297. *
  298. * The two-wire serial interface must have been initialized by calling
  299. * TwInit() before this function can be used.
  300. *
  301. * \param sla Slave address of the destination. This slave address
  302. * must be specified as a 7-bit address. For example, the
  303. * PCF8574A may be configured to slave addresses from 0x38
  304. * to 0x3F.
  305. * \param iadr Address send to the device to access certain registers
  306. * or memory addresses of it.
  307. * \param iadrlen Number of bytes to send as address, maximum 3 bytes are
  308. * supported from AT91SAM7
  309. * \param txdata Points to a buffer, where the data to transmit will be
  310. * stored.
  311. * \param txsiz Maximum number of bytes to transmit.
  312. * \param tmo Timeout in milliseconds. To disable timeout, set this
  313. * parameter to NUT_WAIT_INFINITE.
  314. *
  315. * \return The number of bytes transmitted, -1 in case of an error
  316. * or timeout. Number could be less if slave end transmission
  317. * with NAK.
  318. */
  319. int NutTwiMasterRegWrite(NUTTWIBUS *bus,
  320. uint8_t sla,
  321. uint32_t iadr,
  322. uint8_t iadrlen,
  323. const void *txdata,
  324. uint16_t txsiz,
  325. uint32_t tmo)
  326. {
  327. int rc = -1;
  328. NUTTWIICB *icb = bus->bus_icb;
  329. /* This routine is marked reentrant, so lock the interface. */
  330. if (NutEventWait(&bus->bus_mutex, tmo)) {
  331. icb->tw_mm_err = TWERR_IF_LOCKED;
  332. return -1;
  333. }
  334. icb->tw_mm_err = 0;
  335. if (txsiz) {
  336. icb->tw_mm_buf = (uint8_t *) txdata;
  337. icb->tw_mm_len = (size_t) txsiz;
  338. icb->tw_mm_idx = 1;
  339. /* Set TWI Internal Address Register */
  340. outr(TWI_IADRR, iadr);
  341. /* Set the TWI Master Mode Register */
  342. outr(TWI_MMR, ((unsigned int) sla << TWI_DADR_LSB) | (((unsigned int) iadrlen & 3) << 8));
  343. outb(TWI_THR, icb->tw_mm_buf[0]);
  344. outr(TWI_IER, TWI_TXRDY);
  345. /* Wait for master transmission to be done. */
  346. if (NutEventWait(&icb->tw_mm_mtx, tmo)) {
  347. icb->tw_mm_error = TWERR_TIMEOUT;
  348. } else if (icb->tw_mm_err) {
  349. icb->tw_mm_error = icb->tw_mm_err;
  350. } else {
  351. rc = (int) icb->tw_mm_idx;
  352. }
  353. outr(TWI_IDR, 0xFFFFFFFF);
  354. }
  355. /* Release the interface. */
  356. NutEventPost(&bus->bus_mutex);
  357. return rc;
  358. }
  359. /*!
  360. * \brief Get last master mode error.
  361. *
  362. * You may call this function to determine the specific cause
  363. * of an error after twi transaction failed.
  364. *
  365. */
  366. int NutTwiMasterError(NUTTWIBUS *bus)
  367. {
  368. int rc = bus->bus_icb->tw_mm_error;
  369. bus->bus_icb->tw_mm_error = 0;
  370. return rc;
  371. }
  372. /*!
  373. * \brief Listen for incoming data from a master.
  374. *
  375. * If this function returns without error, the bus is blocked. The caller
  376. * must immediately process the request and return a response by calling
  377. * TwSlaveRespond().
  378. *
  379. * \note Slave mode is not implemented in the AT91 driver.
  380. * Thus the function always returns -1.
  381. *
  382. * \param sla Points to a byte variable, which receives the slave
  383. * address sent by the master. This can be used by the
  384. * caller to determine whether the the interface has been
  385. * addressed by a general call or its individual address.
  386. * \param rxdata Points to a data buffer where the received data bytes
  387. * are stored.
  388. * \param rxsiz Specifies the maximum number of data bytes to receive.
  389. * \param tmo Timeout in milliseconds. To disable timeout,
  390. * set this parameter to NUT_WAIT_INFINITE.
  391. *
  392. * \return The number of bytes received, -1 in case of an error or timeout.
  393. *
  394. */
  395. int NutTwiSlaveListen(NUTTWIBUS *bus, uint8_t *sla, void *rxdata, uint16_t rxsiz, uint32_t tmo)
  396. {
  397. return -1;
  398. }
  399. /*!
  400. * \brief Send response to a master.
  401. *
  402. * This function must be called as soon as possible after TwSlaveListen()
  403. * returned successfully, even if no data needs to be returned. Not doing
  404. * so will completely block the bus.
  405. *
  406. * \note Slave mode is not implemented in the AT91 driver.
  407. * Thus the function always returns -1.
  408. *
  409. * \param txdata Points to the data to transmit. Ignored, if the
  410. * number of bytes to transmit is zero.
  411. * \param txlen Number of data bytes to transmit.
  412. * \param tmo Timeout in milliseconds. To disable timeout,
  413. * set this parameter to NUT_WAIT_INFINITE.
  414. *
  415. * \return The number of bytes transmitted, -1 in case of an error or timeout.
  416. */
  417. extern int NutTwiSlaveRespond(NUTTWIBUS *bus, void *txdata, uint16_t txlen, uint32_t tmo)
  418. {
  419. return -1;
  420. }
  421. /*!
  422. * \brief Get last slave mode error.
  423. *
  424. * You may call this function to determine the specific cause
  425. * of an error after TwSlaveListen() or TwSlaveRespond() failed.
  426. *
  427. * \return Error code or 0 if no error occurred.
  428. *
  429. * \note Slave mode is not implemented in the AT91 driver.
  430. * Thus the function always returns TWERR_BUS.
  431. */
  432. extern int NutTwiSlaveError(NUTTWIBUS *bus)
  433. {
  434. return TWERR_BUS;
  435. }
  436. /*!
  437. * \brief Get last transfer results.
  438. *
  439. * \todo Do we really need this. It may not work with competing threads.
  440. *
  441. * You may call this function to determine how many bytes where
  442. * transferred before the twi transaction failed.
  443. *
  444. */
  445. uint16_t NutTwiIndexes( NUTTWIBUS *bus, uint8_t idx )
  446. {
  447. NUTTWIICB *icb = bus->bus_icb;
  448. switch ( idx ) {
  449. case 0:
  450. return (uint16_t) icb->tw_mm_error;
  451. case 1:
  452. return (uint16_t) icb->tw_mm_len;
  453. case 2:
  454. return (uint16_t) icb->tw_mm_len;
  455. default:
  456. return 0;
  457. }
  458. }
  459. /*!
  460. * \brief Set Speed of I2C Interface.
  461. *
  462. * Setup Interface Speed
  463. */
  464. int NutTwiSetSpeed( NUTTWIBUS *bus, uint32_t speed)
  465. {
  466. int rc = -1;
  467. uint32_t ckdiv = 1;
  468. uint32_t cldiv;
  469. if (speed > 400000) {
  470. /* Speed out of range */
  471. return rc;
  472. }
  473. if (bus==NULL) {
  474. /* No bus selected */
  475. return rc;
  476. }
  477. /*
  478. * CLDIV = ((Tlow x 2^CKDIV) -3) x Tmck
  479. * CHDIV = ((THigh x 2^CKDIV) -3) x Tmck
  480. * Only CLDIV is computed since CLDIV = CHDIV (50% duty cycle)
  481. */
  482. while ((cldiv = ((NutClockGet(NUT_HWCLK_PERIPHERAL) / (2 * speed)) - 3) / (1 << ckdiv)) > 255) {
  483. ckdiv++;
  484. }
  485. /* BUG 41.2.7.1, datasheet SAM7X256 p. 626 */
  486. if (cldiv * (1 << ckdiv) > 8191) {
  487. return rc;
  488. }
  489. else {
  490. outr(TWI_CWGR, (ckdiv << 16) | ((unsigned int) cldiv << 8) | (unsigned int) cldiv);
  491. rc = 0;
  492. }
  493. return 0;
  494. }
  495. /*!
  496. * \brief Request Current Speed of I2C Interface.
  497. *
  498. * \return 0..400000 for speed, -1 in case of error.
  499. */
  500. uint32_t NutTwiGetSpeed( NUTTWIBUS *bus)
  501. {
  502. uint32_t rc;
  503. uint32_t ckdiv = 1;
  504. uint32_t cldiv;
  505. if (bus) {
  506. cldiv = inr(TWI_CWGR) & 0x000000FF;
  507. ckdiv = (inr(TWI_CWGR) >> 16) & 0x00000007;
  508. rc = NutGetCpuClock() / ((cldiv * 2 << ckdiv) - 3);
  509. }
  510. else
  511. rc = -1;
  512. return rc;
  513. }
  514. /*!
  515. * \brief Perform TWI control functions.
  516. *
  517. * \param req Requested control function. May be set to one of the
  518. * following constants:
  519. * - TWI_SETSPEED, if conf points to an uint32_t value containing the bitrate.
  520. * - TWI_GETSPEED, if conf points to an uint32_t value receiving the current bitrate.
  521. * \param conf Points to a buffer that contains any data required for
  522. * the given control function or receives data from that
  523. * function.
  524. * \return 0 on success, -1 otherwise.
  525. *
  526. * \note Timeout is limited to the granularity of the system timer.
  527. *
  528. */
  529. int NutTwiIOCtl( NUTTWIBUS *bus, int req, void *conf )
  530. {
  531. int rc = 0;
  532. NUTTWIICB *icb = bus->bus_icb;
  533. switch (req) {
  534. case TWI_SETSPEED:
  535. rc = NutTwiSetSpeed(bus, *((uint32_t *)conf));
  536. break;
  537. case TWI_GETSPEED:
  538. *((uint32_t *)conf) = NutTwiGetSpeed(bus);
  539. break;
  540. case TWI_GETSTATUS:
  541. rc = 0;
  542. break;
  543. case TWI_SETSTATUS:
  544. rc = 0;
  545. break;
  546. case TWI_GETSLAVEADDRESS:
  547. // TODO: Slave handling
  548. *(uint32_t*)conf = (uint32_t)icb->tw_mm_sla;
  549. break;
  550. case TWI_SETSLAVEADDRESS:
  551. // TODO: Slave handling
  552. icb->tw_mm_sla = *((uint16_t*)conf);
  553. break;
  554. default:
  555. rc = -1;
  556. break;
  557. }
  558. return rc;
  559. }
  560. /*!
  561. * \brief Initialize TWI interface hardware.
  562. */
  563. int At91TwiInit(void)
  564. {
  565. int rc = 0;
  566. /* Set TWD and TWCK as peripheral line. */
  567. outr(TWI_PIO_ASR, _BV(TWI_TWD) | _BV(TWI_TWCK));
  568. /* Let periperal control the PIO lines. */
  569. outr(TWI_PIO_PDR, _BV(TWI_TWD) | _BV(TWI_TWCK));
  570. /* Enabled OpenDrain output on both lines. */
  571. outr(TWI_PIO_MDER, _BV(TWI_TWD) | _BV(TWI_TWCK));
  572. /* Enable TWI clock in PMC. */
  573. outr(PMC_PCER, _BV(TWI_ID));
  574. /* Disable all interrupts. */
  575. outr(TWI_IDR, 0xFFFFFFFF);
  576. /* Reset bus. */
  577. outr(TWI_CR, TWI_SWRST);
  578. /* Enable master mode. */
  579. outr(TWI_CR, TWI_MSEN | TWI_SVDIS);
  580. return rc;
  581. }
  582. /*!
  583. * \brief Initialize TWI interface bus.
  584. *
  585. * The specified slave address is not used here as we don't support twi-slave
  586. * on AT91SAM7X
  587. *
  588. * \note This function is only available on AT91SAM7xxxx systems.
  589. *
  590. * \param sla Slave address, must be specified as a 7-bit address,
  591. * always lower than 128.
  592. */
  593. int NutRegisterTwiBus( NUTTWIBUS *bus, uint8_t sla )
  594. {
  595. int rc = 0;
  596. uint32_t speed = 100000;
  597. NUTTWIICB *icb = NULL;
  598. /* Check if bus was already registered */
  599. if( bus->bus_icb) {
  600. return 0;
  601. }
  602. /* Allocate ICB for this bus */
  603. icb = NutHeapAlloc(sizeof(NUTTWIICB));
  604. if( icb == NULL) {
  605. return rc;
  606. }
  607. memset( icb, 0, sizeof(NUTTWIICB));
  608. /* Link bus and ICB */
  609. bus->bus_icb = icb;
  610. /* Initialize interface hardware */
  611. if (bus->bus_initbus) {
  612. rc = bus->bus_initbus();
  613. }
  614. #ifdef I2C_DEFAULT_SPEED
  615. speed = I2C_DEFAULT_SPEED*1000UL;
  616. #endif
  617. /* Set initial rate. */
  618. if( (rc = NutTwiSetSpeed( bus, speed))) {
  619. return rc;
  620. }
  621. /* Register IRQ Handler */
  622. if( (rc = NutRegisterIrqHandler( bus->bus_sig_ev, TwInterrupt, bus))) {
  623. return rc;
  624. }
  625. /* Enable level triggered interrupts. */
  626. NutIrqSetMode(bus->bus_sig_ev, NUT_IRQMODE_LEVEL);
  627. NutIrqEnable(bus->bus_sig_ev);
  628. /* Initialize mutex semaphores. */
  629. NutEventPost(&bus->bus_mutex);
  630. return rc;
  631. }
  632. int NutDestroyTwiBus( NUTTWIBUS *bus)
  633. {
  634. if (bus->bus_icb) {
  635. NutIrqDisable(bus->bus_sig_ev);
  636. NutHeapFree( bus->bus_icb);
  637. }
  638. return 0;
  639. }
  640. /*!
  641. * \brief TWI/I2C bus structure.
  642. */
  643. NUTTWIBUS At91TwiBus = {
  644. /*.bus_base = */ TWI_CR, /* Bus base address. */
  645. /*.bus_sig_ev = */ &sig_TWI, /* Bus data and event interrupt handler. */
  646. /*.bus_sig_er = */ NULL, /* Bus error interrupt handler. */
  647. /*.bus_mutex = */ NULL, /* Bus lock queue. */
  648. /*.bus_icb = */ NULL, /* Bus Runtime Data Pointer */
  649. /*.bus_dma_tx = */ 0, /* DMA channel for TX direction. */
  650. /*.bus_dma_rx = */ 0, /* DMA channel for RX direction. */
  651. /*.bus_initbus =*/ At91TwiInit, /* Initialize bus controller. */
  652. /*.bus_recover =*/ NULL, /* Recover bus controller */
  653. };
  654. /*@}*/