mcf5_i2c.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. /*
  2. * Copyright 2012 by Embedded Technologies s.r.o
  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. #include <string.h>
  33. #include <cfg/twi.h>
  34. #include <arch/m68k.h>
  35. #include <dev/twif.h>
  36. #include <sys/event.h>
  37. #include <sys/timer.h>
  38. #include <sys/heap.h>
  39. #define MODE_READ 1 /* Work as Receiver */
  40. #define MODE_WRITE 0 /* Work as Transmitter */
  41. /*
  42. * TWI interrupt handler.
  43. */
  44. static void TwInterrupt(void *arg)
  45. {
  46. NUTTWIBUS *bus = (NUTTWIBUS *) arg;
  47. NUTTWIICB *icb = bus->bus_icb;
  48. /* Is device in master mode? */
  49. if (MCF_I2C_I2CR(bus->bus_base) & MCF_I2C_I2CR_MSTA) {
  50. /* Is device in Tx mode? */
  51. if (MCF_I2C_I2CR(bus->bus_base) & MCF_I2C_I2CR_MTX) {
  52. /* Terminate transaction if NACK received */
  53. if (MCF_I2C_I2SR(bus->bus_base) & MCF_I2C_I2SR_RXAK) {
  54. icb->tw_mm_err = icb->tw_mm_sla_found ? TWERR_DATA_NACK : TWERR_SLA_NACK;
  55. goto stop;
  56. }
  57. /* ACK Received - transmit next byte or switch to receive mode */
  58. else {
  59. /* Slave device is responding */
  60. icb->tw_mm_sla_found = 1;
  61. /* Transmit address byte is any */
  62. if (icb->tw_mm_iadrlen) {
  63. icb->tw_mm_iadrlen--;
  64. MCF_I2C_I2DR(bus->bus_base) = *(icb->tw_mm_iadr)++;
  65. }
  66. /* Or transmit data byte if any */
  67. else if (icb->tw_mm_txlen) {
  68. icb->tw_mm_txlen--;
  69. MCF_I2C_I2DR(bus->bus_base) = *(icb->tw_mm_txbuf)++;
  70. }
  71. /* Or switch to Rx mode if receiving is configured */
  72. else if (icb->tw_mm_rxlen) {
  73. /* Repeated start is required for changing from Tx mode to Rx mode */
  74. if (icb->tw_mm_dir == MODE_WRITE) {
  75. icb->tw_mm_dir = MODE_READ;
  76. /* Generate repeated START condition */
  77. MCF_I2C_I2CR(bus->bus_base) |= MCF_I2C_I2CR_RSTA;
  78. /* Write slave id byte with READ flag */
  79. MCF_I2C_I2DR(bus->bus_base) = (uint8_t) (icb->tw_mm_sla | 0x01);
  80. }
  81. /* Start receiving */
  82. else {
  83. /* Suppress ACK signal in response if only one char to receive */
  84. if (icb->tw_mm_rxlen == 1U) {
  85. MCF_I2C_I2CR(bus->bus_base) |= MCF_I2C_I2CR_TXAK;
  86. } else {
  87. MCF_I2C_I2CR(bus->bus_base) &= ~MCF_I2C_I2CR_TXAK;
  88. }
  89. /* Switch to Rx mode */
  90. MCF_I2C_I2CR(bus->bus_base) &= ~MCF_I2C_I2CR_MTX;
  91. /* Start receiving by dummy read */
  92. (void) MCF_I2C_I2DR(bus->bus_base);
  93. }
  94. }
  95. /* Or finish the transaction */
  96. else {
  97. goto stop;
  98. }
  99. }
  100. } else {
  101. /* Decrease number of chars for the receive */
  102. icb->tw_mm_rxlen--;
  103. /* Suppress ACK signal in response if only one char to receive */
  104. if (icb->tw_mm_rxlen == 1U) {
  105. MCF_I2C_I2CR(bus->bus_base) |= MCF_I2C_I2CR_TXAK;
  106. }
  107. /* Finish the transaction (Generate STOP) if all data are received */
  108. else if (!icb->tw_mm_rxlen) {
  109. MCF_I2C_I2CR(bus->bus_base) &= ~MCF_I2C_I2CR_MSTA;
  110. }
  111. /* Receive character */
  112. *(icb->tw_mm_rxbuf)++ = MCF_I2C_I2DR(bus->bus_base);
  113. /* Finish the transaction (Generate STOP) if all data are received */
  114. if (!icb->tw_mm_rxlen)
  115. goto stop;
  116. }
  117. } else {
  118. /* Arbitration lost? */
  119. if (MCF_I2C_I2SR(bus->bus_base) & MCF_I2C_I2SR_IAL) {
  120. icb->tw_mm_err = TWERR_ARBLOST;
  121. goto stop;
  122. }
  123. }
  124. return;
  125. stop:
  126. /* Switch master to slave if required (Generate STOP) */
  127. if (MCF_I2C_I2CR(bus->bus_base) & MCF_I2C_I2CR_MSTA)
  128. MCF_I2C_I2CR(bus->bus_base) &= ~MCF_I2C_I2CR_MSTA;
  129. /* Switch to Rx mode */
  130. MCF_I2C_I2CR(bus->bus_base) &= ~MCF_I2C_I2CR_MTX;
  131. /* Wake up waiting thread */
  132. NutEventPostFromIrq(&icb->tw_mm_mtx);
  133. return;
  134. }
  135. /*
  136. * TWI Transfer starter
  137. */
  138. static int TwiInitTransfer(NUTTWIBUS *bus, uint32_t tmo)
  139. {
  140. NUTTWIICB *icb = bus->bus_icb;
  141. /* Wait until the bus is not busy (e.g. another master is communicating) */
  142. while (MCF_I2C_I2SR(bus->bus_base) & MCF_I2C_I2SR_IBB) {
  143. NutSleep(1);
  144. if (tmo == NUT_WAIT_INFINITE) {
  145. continue;
  146. }
  147. if (!--tmo) {
  148. icb->tw_mm_error = TWERR_BUSY;
  149. return -1;
  150. }
  151. }
  152. /* Set TX mode */
  153. MCF_I2C_I2CR(bus->bus_base) |= MCF_I2C_I2CR_MTX;
  154. /* Clear status register */
  155. MCF_I2C_I2SR(bus->bus_base) = 0;
  156. // TODO: I'm not sure this critical section is really required
  157. // try to use NutSleep() here to simulate interrupt
  158. //NutEnterCritical();
  159. /* Generate "start" or "repeat start" */
  160. if (MCF_I2C_I2CR(bus->bus_base) & MCF_I2C_I2CR_MSTA) {
  161. MCF_I2C_I2CR(bus->bus_base) |= MCF_I2C_I2CR_RSTA;
  162. } else {
  163. MCF_I2C_I2CR(bus->bus_base) |= MCF_I2C_I2CR_MSTA;
  164. }
  165. /* Transmit the slave address */
  166. MCF_I2C_I2DR(bus->bus_base) = icb->tw_mm_sla;
  167. //NutExitCritical();
  168. return 0;
  169. }
  170. /*
  171. * TWI Transfer
  172. */
  173. static int TwiMasterLow(NUTTWIBUS *bus, uint8_t sla, uint32_t iadr, uint8_t iadrlen, CONST void *txdata, uint16_t txlen,
  174. void *rxdata, uint16_t rxsiz, uint32_t tmo)
  175. {
  176. int rc = -1;
  177. NUTTWIICB *icb = bus->bus_icb;
  178. /* Quit if nothing to do */
  179. if ((txlen == 0) && (rxsiz == 0)) {
  180. return 0;
  181. }
  182. /* This routine is marked reentrant, so lock the interface. */
  183. if (NutEventWait(&bus->bus_mutex, tmo)) {
  184. icb->tw_mm_error = TWERR_IF_LOCKED;
  185. return rc;
  186. }
  187. /* Fetch transfer parameters for current transaction */
  188. icb->tw_mm_sla = sla << 1;
  189. icb->tw_mm_sla_found = 0;
  190. icb->tw_mm_iadrlen = iadrlen;
  191. if (iadrlen) {
  192. /* Big-endian machine! */
  193. icb->tw_mm_iadr = ((uint8_t*) &iadr) + 4 - iadrlen;
  194. }
  195. icb->tw_mm_txbuf = (uint8_t*) txdata;
  196. icb->tw_mm_txlen = txlen;
  197. icb->tw_mm_rxbuf = rxdata;
  198. icb->tw_mm_rxlen = rxsiz;
  199. icb->tw_mm_err = TWERR_OK;
  200. if (icb->tw_mm_iadrlen | icb->tw_mm_txlen)
  201. icb->tw_mm_dir = MODE_WRITE;
  202. else
  203. icb->tw_mm_dir = MODE_READ;
  204. /* Issue start and wait till transmission completed */
  205. if (!TwiInitTransfer(bus, tmo)) {
  206. /* Wait for transfer complete. */
  207. if (NutEventWait(&icb->tw_mm_mtx, tmo)) {
  208. icb->tw_mm_error = TWERR_TIMEOUT;
  209. }
  210. /* Check for errors that may have been detected by the interrupt routine. */
  211. if (icb->tw_mm_err) {
  212. icb->tw_mm_error = icb->tw_mm_err;
  213. } else {
  214. if (rxsiz)
  215. rc = (int) (rxsiz - icb->tw_mm_rxlen);
  216. else
  217. rc = (int) (txlen - icb->tw_mm_txlen);
  218. }
  219. }
  220. /* Release the interface. */
  221. NutEventPost(&bus->bus_mutex);
  222. return rc;
  223. }
  224. /*!
  225. * \brief Transmit and/or receive data as a master.
  226. *
  227. * The two-wire serial interface must have been initialized by calling
  228. * TwInit() before this function can be used.
  229. *
  230. * \param bus Pointer to the \ref NUTTWIBUS structure, which is provided
  231. * by the bus controller driver.
  232. * \param sla Slave address of the destination. This slave address
  233. * must be specified as a 7-bit address. For example, the
  234. * PCF8574A may be configured to slave addresses from 0x38
  235. * to 0x3F.
  236. * \param txdata Points to the data to transmit. Ignored, if the number
  237. * of data bytes to transmit is zero.
  238. * \param txlen Number of data bytes to transmit. If zero, then the
  239. * interface will not send any data to the slave device
  240. * and will directly enter the master receive mode.
  241. * \param rxdata Points to a buffer, where the received data will be
  242. * stored. Ignored, if the maximum number of bytes to
  243. * receive is zero.
  244. * \param rxsiz Maximum number of bytes to receive. Set to zero, if
  245. * no bytes are expected from the slave device.
  246. * \param tmo Timeout in milliseconds. To disable timeout, set this
  247. * parameter to NUT_WAIT_INFINITE.
  248. *
  249. * \return The number of bytes received, -1 in case of an error or timeout.
  250. */
  251. int NutTwiMasterTranceive(NUTTWIBUS *bus, uint8_t sla, CONST void *txdata, uint16_t txlen, void *rxdata, uint16_t rxsiz,
  252. uint32_t tmo)
  253. {
  254. return TwiMasterLow(bus, sla, 0, 0, txdata, txlen, rxdata, rxsiz, tmo);
  255. }
  256. /*!
  257. * \brief Receive data as a master from a device having internal addressable registers
  258. *
  259. * The two-wire serial interface must have been initialized by calling
  260. * TwInit() before this function can be used.
  261. *
  262. * \param bus Pointer to the \ref NUTTWIBUS structure, which is provided
  263. * by the bus controller driver.
  264. * \param sla Slave address of the destination. This slave address
  265. * must be specified as a 7-bit address. For example, the
  266. * PCF8574A may be configured to slave addresses from 0x38
  267. * to 0x3F.
  268. * \param iadr Address send to the device to access certain registers
  269. * or memory addresses of it.
  270. * \param iadrlen Number of bytes to send as address, maximum 3 bytes are
  271. * supported from AT91SAM7
  272. * \param rxdata Points to a buffer, where the received data will be
  273. * stored.
  274. * \param rxsiz Maximum number of bytes to receive.
  275. * \param tmo Timeout in milliseconds. To disable timeout, set this
  276. * parameter to NUT_WAIT_INFINITE.
  277. *
  278. * \return The number of bytes received, -1 in case of an error or timeout.
  279. */
  280. int NutTwiMasterRegRead(NUTTWIBUS *bus, uint8_t sla, uint32_t iadr, uint8_t iadrlen, void *rxdata, uint16_t rxsiz, uint32_t tmo)
  281. {
  282. return TwiMasterLow(bus, sla, iadr, iadrlen, NULL, 0, rxdata, rxsiz, tmo);
  283. }
  284. /*!
  285. * \brief Transmit data as a master to a device having internal addressable registers
  286. *
  287. * The two-wire serial interface must have been initialized by calling
  288. * TwInit() before this function can be used.
  289. *
  290. * \param bus Pointer to the \ref NUTTWIBUS structure, which is provided
  291. * by the bus controller driver.
  292. * \param sla Slave address of the destination. This slave address
  293. * must be specified as a 7-bit address. For example, the
  294. * PCF8574A may be configured to slave addresses from 0x38
  295. * to 0x3F.
  296. * \param iadr Address send to the device to access certain registers
  297. * or memory addresses of it.
  298. * \param iadrlen Number of bytes to send as address, maximum 3 bytes are
  299. * supported from AT91SAM7
  300. * \param txdata Points to a buffer, where the data to transmit will be
  301. * stored.
  302. * \param txsiz Maximum number of bytes to transmit.
  303. * \param tmo Timeout in milliseconds. To disable timeout, set this
  304. * parameter to NUT_WAIT_INFINITE.
  305. *
  306. * \return The number of bytes transmitted, -1 in case of an error
  307. * or timeout. Number could be less if slave end transmission
  308. * with NAK.
  309. */
  310. int NutTwiMasterRegWrite(NUTTWIBUS *bus, uint8_t sla, uint32_t iadr, uint8_t iadrlen, CONST void *txdata, uint16_t txsiz,
  311. uint32_t tmo)
  312. {
  313. return TwiMasterLow(bus, sla, iadr, iadrlen, txdata, txsiz, NULL, 0, tmo);
  314. }
  315. /*!
  316. * \brief Get last master mode error.
  317. *
  318. * You may call this function to determine the specific cause
  319. * of an error after twi transaction failed.
  320. *
  321. * \param bus Pointer to the \ref NUTTWIBUS structure, which is provided
  322. * by the bus controller driver.
  323. *
  324. */
  325. int NutTwiMasterError(NUTTWIBUS *bus)
  326. {
  327. int rc = bus->bus_icb->tw_mm_error;
  328. bus->bus_icb->tw_mm_error = 0;
  329. return rc;
  330. }
  331. /*!
  332. * \brief Listen for incoming data from a master.
  333. *
  334. * If this function returns without error, the bus is blocked. The caller
  335. * must immediately process the request and return a response by calling
  336. * TwSlaveRespond().
  337. *
  338. * \note Slave mode is not implemented in the COLDFIRE driver.
  339. * Thus the function always returns -1.
  340. *
  341. * \param bus Pointer to the \ref NUTTWIBUS structure, which is provided
  342. * by the bus controller driver.
  343. * \param sla Points to a byte variable, which receives the slave
  344. * address sent by the master. This can be used by the
  345. * caller to determine whether the the interface has been
  346. * addressed by a general call or its individual address.
  347. * \param rxdata Points to a data buffer where the received data bytes
  348. * are stored.
  349. * \param rxsiz Specifies the maximum number of data bytes to receive.
  350. * \param tmo Timeout in milliseconds. To disable timeout,
  351. * set this parameter to NUT_WAIT_INFINITE.
  352. *
  353. * \return The number of bytes received, -1 in case of an error or timeout.
  354. *
  355. */
  356. int NutTwiSlaveListen(NUTTWIBUS *bus, uint8_t *sla, void *rxdata, uint16_t rxsiz, uint32_t tmo)
  357. {
  358. return -1;
  359. }
  360. /*!
  361. * \brief Send response to a master.
  362. *
  363. * This function must be called as soon as possible after TwSlaveListen()
  364. * returned successfully, even if no data needs to be returned. Not doing
  365. * so will completely block the bus.
  366. *
  367. * \note Slave mode is not implemented in the COLDFIRE driver.
  368. * Thus the function always returns -1.
  369. *
  370. * \param bus Pointer to the \ref NUTTWIBUS structure, which is provided
  371. * by the bus controller driver.
  372. * \param txdata Points to the data to transmit. Ignored, if the
  373. * number of bytes to transmit is zero.
  374. * \param txlen Number of data bytes to transmit.
  375. * \param tmo Timeout in milliseconds. To disable timeout,
  376. * set this parameter to NUT_WAIT_INFINITE.
  377. *
  378. * \return The number of bytes transmitted, -1 in case of an error or timeout.
  379. */
  380. extern int NutTwiSlaveRespond(NUTTWIBUS *bus, void *txdata, uint16_t txlen, uint32_t tmo)
  381. {
  382. return -1;
  383. }
  384. /*!
  385. * \brief Get last slave mode error.
  386. *
  387. * You may call this function to determine the specific cause
  388. * of an error after TwSlaveListen() or TwSlaveRespond() failed.
  389. *
  390. * \param bus Pointer to the \ref NUTTWIBUS structure, which is provided
  391. * by the bus controller driver.
  392. *
  393. * \return Error code or 0 if no error occurred.
  394. *
  395. * \note Slave mode is not implemented in the COLDFIRE driver.
  396. * Thus the function always returns TWERR_BUS.
  397. */
  398. extern int NutTwiSlaveError(NUTTWIBUS *bus)
  399. {
  400. return TWERR_BUS;
  401. }
  402. /*!
  403. * \brief Get last transfer results.
  404. *
  405. * \param bus Pointer to the \ref NUTTWIBUS structure, which is provided
  406. * by the bus controller driver.
  407. * \param idx Index requested
  408. * \todo Do we really need this. It may not work with competing threads.
  409. * Answer: We really need this! It is bus dependand and is used by
  410. * EEPROM driver to determine the number of bytes transferred and
  411. * detection of EEPROM busy event (ACK-Polling).
  412. *
  413. * You may call this function to determine how many bytes where
  414. * transferred before the twi transaction failed.
  415. *
  416. */
  417. uint16_t NutTwiIndexes(NUTTWIBUS *bus, uint8_t idx)
  418. {
  419. NUTTWIICB *icb = bus->bus_icb;
  420. switch (idx) {
  421. case 0:
  422. return (uint16_t) icb->tw_mm_error;
  423. case 1:
  424. return (uint16_t) icb->tw_mm_rxlen;
  425. case 2:
  426. return (uint16_t) icb->tw_mm_txlen;
  427. default:
  428. return 0;
  429. }
  430. }
  431. /*
  432. * Set Speed of I2C Interface.
  433. */
  434. #define IC_SIZE 64
  435. uint16_t Dividers[IC_SIZE] = { 28, 30, 34, 40, 44, 48, 56, 68, 80, 88, 104, 128, 144, 160, 192, 240, 288, 320, 384, 480, 576,
  436. 640, 768, 960, 1152, 1280, 1536, 1920, 2304, 2560, 3072, 3840, 20, 22, 24, 26, 28, 32, 36, 40, 48, 56, 64, 72, 80, 96,
  437. 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 640, 768, 896, 1024, 1280, 1536, 1792, 2048 };
  438. static int TwiSetSpeed(NUTTWIBUS *bus, uint32_t speed)
  439. {
  440. uint8_t ic = 0x1F;
  441. uint16_t div_selected = 0xFFFF;
  442. uint16_t div_counted = NutGetCpuClock() / speed;
  443. int i;
  444. for (i = 0; i < IC_SIZE; ++i) {
  445. if (Dividers[i] >= div_counted && Dividers[i] < div_selected) {
  446. div_selected = Dividers[i];
  447. ic = i;
  448. }
  449. }
  450. MCF_I2C_I2FDR(bus->bus_base) = MCF_I2C_I2FDR_IC(ic);
  451. return 0;
  452. }
  453. /*
  454. * Request Current Speed of I2C Interface.
  455. */
  456. static int TwiGetSpeed(NUTTWIBUS *bus)
  457. {
  458. return NutGetCpuClock() / Dividers[MCF_I2C_I2FDR(bus->bus_base)];
  459. }
  460. /*!
  461. * \brief Perform TWI control functions.
  462. *
  463. * \param bus Pointer to the \ref NUTTWIBUS structure, which is provided
  464. * by the bus controller driver.
  465. * \param req Requested control function. May be set to one of the
  466. * following constants:
  467. * - TWI_SETSPEED, if conf points to an uint32_t value containing the bitrate.
  468. * - TWI_GETSPEED, if conf points to an uint32_t value receiving the current bitrate.
  469. * \param conf Points to a buffer that contains any data required for
  470. * the given control function or receives data from that
  471. * function.
  472. * \return 0 on success, -1 otherwise.
  473. *
  474. */
  475. int NutTwiIOCtl(NUTTWIBUS *bus, int req, void *conf)
  476. {
  477. int rc = 0;
  478. NUTTWIICB *icb = bus->bus_icb;
  479. switch (req) {
  480. case TWI_SETSPEED:
  481. TwiSetSpeed(bus, *(uint32_t*) conf);
  482. break;
  483. case TWI_GETSPEED:
  484. *(uint32_t*) conf = TwiGetSpeed(bus);
  485. break;
  486. case TWI_GETSTATUS:
  487. break;
  488. case TWI_SETSTATUS:
  489. break;
  490. case TWI_GETSLAVEADDRESS:
  491. *((uint32_t*) conf) = icb->tw_mm_sla;
  492. break;
  493. case TWI_SETSLAVEADDRESS:
  494. icb->tw_mm_sla = MCF_I2C_I2ADR_ADR(*(uint32_t*)conf);
  495. MCF_I2C_I2ADR(bus->bus_base) = icb->tw_mm_sla;
  496. break;
  497. default:
  498. rc = -1;
  499. break;
  500. }
  501. return rc;
  502. }
  503. /*!
  504. * \brief Initialize TWI interface.
  505. *
  506. * The specified slave address is not used here as we don't support twi-slave
  507. * on this architecture for now.
  508. *
  509. * \note This function is only available on AT91SAM7xxxx systems.
  510. *
  511. * \param bus Pointer to the \ref NUTTWIBUS structure, which is provided
  512. * by the bus controller driver.
  513. * \param sla Slave address, must be specified as a 7-bit address,
  514. * always lower than 128.
  515. */
  516. int NutRegisterTwiBus(NUTTWIBUS *bus, uint8_t sla)
  517. {
  518. int rc = -1;
  519. NUTTWIICB *icb = NULL;
  520. uint32_t speed = 100000;
  521. /* Check if bus was already registered */
  522. if (bus->bus_icb) {
  523. return 0;
  524. }
  525. /* Allocate ICB for this bus */
  526. if ((icb = NutHeapAllocClear(sizeof(NUTTWIICB))) == NULL) {
  527. return rc;
  528. }
  529. /* Link bus and ICB */
  530. bus->bus_icb = icb;
  531. if (NutRegisterIrqHandler(bus->bus_sig_ev, TwInterrupt, bus)) {
  532. goto err;
  533. }
  534. /* Initialize GPIO Hardware */
  535. if ((bus->bus_initbus == NULL) || ((rc = bus->bus_initbus()))) {
  536. goto err;
  537. }
  538. /* Disable and reset this bus */
  539. MCF_I2C_I2CR(bus->bus_base) = 0;
  540. /* Set initial rate. */
  541. #ifdef I2CBUS0_DEFAULT_SPEED
  542. if (bus->bus_base == 0)
  543. speed = I2CBUS0_DEFAULT_SPEED * 1000UL;
  544. #endif
  545. #ifdef I2CBUS1_DEFAULT_SPEED
  546. if (bus->bus_base == 1)
  547. speed = I2CBUS1_DEFAULT_SPEED * 1000UL;
  548. #endif
  549. if ((rc = TwiSetSpeed(bus, speed))) {
  550. goto err;
  551. }
  552. /* Define slave address (the address the I2C responds to when addressed as a slave) */
  553. icb->tw_mm_sla = MCF_I2C_I2ADR_ADR(sla);
  554. MCF_I2C_I2ADR(bus->bus_base) = icb->tw_mm_sla;
  555. /* Enable the I2C */
  556. MCF_I2C_I2CR(bus->bus_base) = MCF_I2C_I2CR_IEN;
  557. /* Recover the bus if a slave hangs with SCL low */
  558. if (MCF_I2C_I2SR(bus->bus_base) & MCF_I2C_I2SR_IBB) {
  559. /* Send a START condition*/
  560. MCF_I2C_I2CR(bus->bus_base) |= MCF_I2C_I2CR_MSTA;
  561. /* Dummy read */
  562. (void) MCF_I2C_I2DR(bus->bus_base);
  563. /* Clear status register */
  564. MCF_I2C_I2SR(bus->bus_base) = 0;
  565. /* Clear control register */
  566. MCF_I2C_I2CR(bus->bus_base) = 0;
  567. /* Enable the I2C */
  568. MCF_I2C_I2CR(bus->bus_base) = MCF_I2C_I2CR_IEN;
  569. }
  570. /* Enable I2C Interrupts */
  571. MCF_I2C_I2CR(bus->bus_base) |= MCF_I2C_I2CR_IIEN;
  572. if ((rc = NutIrqEnable(bus->bus_sig_ev))) {
  573. goto err;
  574. }
  575. /* Initialize mutex semaphores. */
  576. NutEventPost(&bus->bus_mutex);
  577. return rc;
  578. err:
  579. if (icb) {
  580. NutHeapFree(icb);
  581. }
  582. return rc;
  583. }
  584. /*@}*/