tsi108_i2c.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. /*
  2. * (C) Copyright 2004 Tundra Semiconductor Corp.
  3. * Author: Alex Bounine
  4. *
  5. * See file CREDITS for list of people who contributed to this
  6. * project.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21. * MA 02111-1307 USA
  22. *
  23. */
  24. #include <config.h>
  25. #include <common.h>
  26. #include <tsi108.h>
  27. #if defined(CONFIG_CMD_I2C)
  28. #define I2C_DELAY 100000
  29. #undef DEBUG_I2C
  30. #ifdef DEBUG_I2C
  31. #define DPRINT(x) printf (x)
  32. #else
  33. #define DPRINT(x)
  34. #endif
  35. /* All functions assume that Tsi108 I2C block is the only master on the bus */
  36. /* I2C read helper function */
  37. static int i2c_read_byte (
  38. uint i2c_chan, /* I2C channel number: 0 - main, 1 - SDC SPD */
  39. uchar chip_addr,/* I2C device address on the bus */
  40. uint byte_addr, /* Byte address within I2C device */
  41. uchar * buffer /* pointer to data buffer */
  42. )
  43. {
  44. u32 temp;
  45. u32 to_count = I2C_DELAY;
  46. u32 op_status = TSI108_I2C_TIMEOUT_ERR;
  47. u32 chan_offset = TSI108_I2C_OFFSET;
  48. DPRINT (("I2C read_byte() %d 0x%02x 0x%02x\n",
  49. i2c_chan, chip_addr, byte_addr));
  50. if (0 != i2c_chan)
  51. chan_offset = TSI108_I2C_SDRAM_OFFSET;
  52. /* Check if I2C operation is in progress */
  53. temp = *(u32 *) (CFG_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2);
  54. if (0 == (temp & (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_WR_STATUS |
  55. I2C_CNTRL2_START))) {
  56. /* Set device address and operation (read = 0) */
  57. temp = (byte_addr << 16) | ((chip_addr & 0x07) << 8) |
  58. ((chip_addr >> 3) & 0x0F);
  59. *(u32 *) (CFG_TSI108_CSR_BASE + chan_offset + I2C_CNTRL1) =
  60. temp;
  61. /* Issue the read command
  62. * (at this moment all other parameters are 0
  63. * (size = 1 byte, lane = 0)
  64. */
  65. *(u32 *) (CFG_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2) =
  66. (I2C_CNTRL2_START);
  67. /* Wait until operation completed */
  68. do {
  69. /* Read I2C operation status */
  70. temp = *(u32 *) (CFG_TSI108_CSR_BASE + chan_offset + I2C_CNTRL2);
  71. if (0 == (temp & (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_START))) {
  72. if (0 == (temp &
  73. (I2C_CNTRL2_I2C_CFGERR |
  74. I2C_CNTRL2_I2C_TO_ERR))
  75. ) {
  76. op_status = TSI108_I2C_SUCCESS;
  77. temp = *(u32 *) (CFG_TSI108_CSR_BASE +
  78. chan_offset +
  79. I2C_RD_DATA);
  80. *buffer = (u8) (temp & 0xFF);
  81. } else {
  82. /* report HW error */
  83. op_status = TSI108_I2C_IF_ERROR;
  84. DPRINT (("I2C HW error reported: 0x%02x\n", temp));
  85. }
  86. break;
  87. }
  88. } while (to_count--);
  89. } else {
  90. op_status = TSI108_I2C_IF_BUSY;
  91. DPRINT (("I2C Transaction start failed: 0x%02x\n", temp));
  92. }
  93. DPRINT (("I2C read_byte() status: 0x%02x\n", op_status));
  94. return op_status;
  95. }
  96. /*
  97. * I2C Read interface as defined in "include/i2c.h" :
  98. * chip_addr: I2C chip address, range 0..127
  99. * (to read from SPD channel EEPROM use (0xD0 ... 0xD7)
  100. * NOTE: The bit 7 in the chip_addr serves as a channel select.
  101. * This hack is for enabling "isdram" command on Tsi108 boards
  102. * without changes to common code. Used for I2C reads only.
  103. * byte_addr: Memory or register address within the chip
  104. * alen: Number of bytes to use for addr (typically 1, 2 for larger
  105. * memories, 0 for register type devices with only one
  106. * register)
  107. * buffer: Pointer to destination buffer for data to be read
  108. * len: How many bytes to read
  109. *
  110. * Returns: 0 on success, not 0 on failure
  111. */
  112. int i2c_read (uchar chip_addr, uint byte_addr, int alen,
  113. uchar * buffer, int len)
  114. {
  115. u32 op_status = TSI108_I2C_PARAM_ERR;
  116. u32 i2c_if = 0;
  117. /* Hack to support second (SPD) I2C controller (SPD EEPROM read only).*/
  118. if (0xD0 == (chip_addr & ~0x07)) {
  119. i2c_if = 1;
  120. chip_addr &= 0x7F;
  121. }
  122. /* Check for valid I2C address */
  123. if (chip_addr <= 0x7F && (byte_addr + len) <= (0x01 << (alen * 8))) {
  124. while (len--) {
  125. op_status = i2c_read_byte(i2c_if, chip_addr, byte_addr++, buffer++);
  126. if (TSI108_I2C_SUCCESS != op_status) {
  127. DPRINT (("I2C read_byte() failed: 0x%02x (%d left)\n", op_status, len));
  128. break;
  129. }
  130. }
  131. }
  132. DPRINT (("I2C read() status: 0x%02x\n", op_status));
  133. return op_status;
  134. }
  135. /* I2C write helper function */
  136. static int i2c_write_byte (uchar chip_addr,/* I2C device address on the bus */
  137. uint byte_addr, /* Byte address within I2C device */
  138. uchar * buffer /* pointer to data buffer */
  139. )
  140. {
  141. u32 temp;
  142. u32 to_count = I2C_DELAY;
  143. u32 op_status = TSI108_I2C_TIMEOUT_ERR;
  144. /* Check if I2C operation is in progress */
  145. temp = *(u32 *) (CFG_TSI108_CSR_BASE + TSI108_I2C_OFFSET + I2C_CNTRL2);
  146. if (0 == (temp & (I2C_CNTRL2_RD_STATUS | I2C_CNTRL2_WR_STATUS | I2C_CNTRL2_START))) {
  147. /* Place data into the I2C Tx Register */
  148. *(u32 *) (CFG_TSI108_CSR_BASE + TSI108_I2C_OFFSET +
  149. I2C_TX_DATA) = (u32) * buffer;
  150. /* Set device address and operation */
  151. temp =
  152. I2C_CNTRL1_I2CWRITE | (byte_addr << 16) |
  153. ((chip_addr & 0x07) << 8) | ((chip_addr >> 3) & 0x0F);
  154. *(u32 *) (CFG_TSI108_CSR_BASE + TSI108_I2C_OFFSET +
  155. I2C_CNTRL1) = temp;
  156. /* Issue the write command (at this moment all other parameters
  157. * are 0 (size = 1 byte, lane = 0)
  158. */
  159. *(u32 *) (CFG_TSI108_CSR_BASE + TSI108_I2C_OFFSET +
  160. I2C_CNTRL2) = (I2C_CNTRL2_START);
  161. op_status = TSI108_I2C_TIMEOUT_ERR;
  162. /* Wait until operation completed */
  163. do {
  164. /* Read I2C operation status */
  165. temp = *(u32 *) (CFG_TSI108_CSR_BASE + TSI108_I2C_OFFSET + I2C_CNTRL2);
  166. if (0 == (temp & (I2C_CNTRL2_WR_STATUS | I2C_CNTRL2_START))) {
  167. if (0 == (temp &
  168. (I2C_CNTRL2_I2C_CFGERR |
  169. I2C_CNTRL2_I2C_TO_ERR))) {
  170. op_status = TSI108_I2C_SUCCESS;
  171. } else {
  172. /* report detected HW error */
  173. op_status = TSI108_I2C_IF_ERROR;
  174. DPRINT (("I2C HW error reported: 0x%02x\n", temp));
  175. }
  176. break;
  177. }
  178. } while (to_count--);
  179. } else {
  180. op_status = TSI108_I2C_IF_BUSY;
  181. DPRINT (("I2C Transaction start failed: 0x%02x\n", temp));
  182. }
  183. return op_status;
  184. }
  185. /*
  186. * I2C Write interface as defined in "include/i2c.h" :
  187. * chip_addr: I2C chip address, range 0..127
  188. * byte_addr: Memory or register address within the chip
  189. * alen: Number of bytes to use for addr (typically 1, 2 for larger
  190. * memories, 0 for register type devices with only one
  191. * register)
  192. * buffer: Pointer to data to be written
  193. * len: How many bytes to write
  194. *
  195. * Returns: 0 on success, not 0 on failure
  196. */
  197. int i2c_write (uchar chip_addr, uint byte_addr, int alen, uchar * buffer,
  198. int len)
  199. {
  200. u32 op_status = TSI108_I2C_PARAM_ERR;
  201. /* Check for valid I2C address */
  202. if (chip_addr <= 0x7F && (byte_addr + len) <= (0x01 << (alen * 8))) {
  203. while (len--) {
  204. op_status =
  205. i2c_write_byte (chip_addr, byte_addr++, buffer++);
  206. if (TSI108_I2C_SUCCESS != op_status) {
  207. DPRINT (("I2C write_byte() failed: 0x%02x (%d left)\n", op_status, len));
  208. break;
  209. }
  210. }
  211. }
  212. return op_status;
  213. }
  214. /*
  215. * I2C interface function as defined in "include/i2c.h".
  216. * Probe the given I2C chip address by reading single byte from offset 0.
  217. * Returns 0 if a chip responded, not 0 on failure.
  218. */
  219. int i2c_probe (uchar chip)
  220. {
  221. u32 tmp;
  222. /*
  223. * Try to read the first location of the chip.
  224. * The Tsi108 HW doesn't support sending just the chip address
  225. * and checkong for an <ACK> back.
  226. */
  227. return i2c_read (chip, 0, 1, (uchar *)&tmp, 1);
  228. }
  229. #endif