mv64x60_i2c.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /*
  2. * Bootloader version of the i2c driver for the MV64x60.
  3. *
  4. * Author: Dale Farnsworth <dfarnsworth@mvista.com>
  5. * Maintained by: Mark A. Greer <mgreer@mvista.com>
  6. *
  7. * 2003, 2007 (c) MontaVista, Software, Inc. This file is licensed under
  8. * the terms of the GNU General Public License version 2. This program is
  9. * licensed "as is" without any warranty of any kind, whether express or
  10. * implied.
  11. */
  12. #include <stdarg.h>
  13. #include <stddef.h>
  14. #include "types.h"
  15. #include "elf.h"
  16. #include "page.h"
  17. #include "string.h"
  18. #include "stdio.h"
  19. #include "io.h"
  20. #include "ops.h"
  21. #include "mv64x60.h"
  22. extern void udelay(long);
  23. /* Register defines */
  24. #define MV64x60_I2C_REG_SLAVE_ADDR 0x00
  25. #define MV64x60_I2C_REG_DATA 0x04
  26. #define MV64x60_I2C_REG_CONTROL 0x08
  27. #define MV64x60_I2C_REG_STATUS 0x0c
  28. #define MV64x60_I2C_REG_BAUD 0x0c
  29. #define MV64x60_I2C_REG_EXT_SLAVE_ADDR 0x10
  30. #define MV64x60_I2C_REG_SOFT_RESET 0x1c
  31. #define MV64x60_I2C_CONTROL_ACK 0x04
  32. #define MV64x60_I2C_CONTROL_IFLG 0x08
  33. #define MV64x60_I2C_CONTROL_STOP 0x10
  34. #define MV64x60_I2C_CONTROL_START 0x20
  35. #define MV64x60_I2C_CONTROL_TWSIEN 0x40
  36. #define MV64x60_I2C_CONTROL_INTEN 0x80
  37. #define MV64x60_I2C_STATUS_BUS_ERR 0x00
  38. #define MV64x60_I2C_STATUS_MAST_START 0x08
  39. #define MV64x60_I2C_STATUS_MAST_REPEAT_START 0x10
  40. #define MV64x60_I2C_STATUS_MAST_WR_ADDR_ACK 0x18
  41. #define MV64x60_I2C_STATUS_MAST_WR_ADDR_NO_ACK 0x20
  42. #define MV64x60_I2C_STATUS_MAST_WR_ACK 0x28
  43. #define MV64x60_I2C_STATUS_MAST_WR_NO_ACK 0x30
  44. #define MV64x60_I2C_STATUS_MAST_LOST_ARB 0x38
  45. #define MV64x60_I2C_STATUS_MAST_RD_ADDR_ACK 0x40
  46. #define MV64x60_I2C_STATUS_MAST_RD_ADDR_NO_ACK 0x48
  47. #define MV64x60_I2C_STATUS_MAST_RD_DATA_ACK 0x50
  48. #define MV64x60_I2C_STATUS_MAST_RD_DATA_NO_ACK 0x58
  49. #define MV64x60_I2C_STATUS_MAST_WR_ADDR_2_ACK 0xd0
  50. #define MV64x60_I2C_STATUS_MAST_WR_ADDR_2_NO_ACK 0xd8
  51. #define MV64x60_I2C_STATUS_MAST_RD_ADDR_2_ACK 0xe0
  52. #define MV64x60_I2C_STATUS_MAST_RD_ADDR_2_NO_ACK 0xe8
  53. #define MV64x60_I2C_STATUS_NO_STATUS 0xf8
  54. static u8 *ctlr_base;
  55. static int mv64x60_i2c_wait_for_status(int wanted)
  56. {
  57. int i;
  58. int status;
  59. for (i=0; i<1000; i++) {
  60. udelay(10);
  61. status = in_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_STATUS))
  62. & 0xff;
  63. if (status == wanted)
  64. return status;
  65. }
  66. return -status;
  67. }
  68. static int mv64x60_i2c_control(int control, int status)
  69. {
  70. out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_CONTROL), control & 0xff);
  71. return mv64x60_i2c_wait_for_status(status);
  72. }
  73. static int mv64x60_i2c_read_byte(int control, int status)
  74. {
  75. out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_CONTROL), control & 0xff);
  76. if (mv64x60_i2c_wait_for_status(status) < 0)
  77. return -1;
  78. return in_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_DATA)) & 0xff;
  79. }
  80. static int mv64x60_i2c_write_byte(int data, int control, int status)
  81. {
  82. out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_DATA), data & 0xff);
  83. out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_CONTROL), control & 0xff);
  84. return mv64x60_i2c_wait_for_status(status);
  85. }
  86. int mv64x60_i2c_read(u32 devaddr, u8 *buf, u32 offset, u32 offset_size,
  87. u32 count)
  88. {
  89. int i;
  90. int data;
  91. int control;
  92. int status;
  93. if (ctlr_base == NULL)
  94. return -1;
  95. /* send reset */
  96. out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_SOFT_RESET), 0);
  97. out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_SLAVE_ADDR), 0);
  98. out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_EXT_SLAVE_ADDR), 0);
  99. out_le32((u32 *)(ctlr_base + MV64x60_I2C_REG_BAUD), (4 << 3) | 0x4);
  100. if (mv64x60_i2c_control(MV64x60_I2C_CONTROL_TWSIEN,
  101. MV64x60_I2C_STATUS_NO_STATUS) < 0)
  102. return -1;
  103. /* send start */
  104. control = MV64x60_I2C_CONTROL_START | MV64x60_I2C_CONTROL_TWSIEN;
  105. status = MV64x60_I2C_STATUS_MAST_START;
  106. if (mv64x60_i2c_control(control, status) < 0)
  107. return -1;
  108. /* select device for writing */
  109. data = devaddr & ~0x1;
  110. control = MV64x60_I2C_CONTROL_TWSIEN;
  111. status = MV64x60_I2C_STATUS_MAST_WR_ADDR_ACK;
  112. if (mv64x60_i2c_write_byte(data, control, status) < 0)
  113. return -1;
  114. /* send offset of data */
  115. control = MV64x60_I2C_CONTROL_TWSIEN;
  116. status = MV64x60_I2C_STATUS_MAST_WR_ACK;
  117. if (offset_size > 1) {
  118. if (mv64x60_i2c_write_byte(offset >> 8, control, status) < 0)
  119. return -1;
  120. }
  121. if (mv64x60_i2c_write_byte(offset, control, status) < 0)
  122. return -1;
  123. /* resend start */
  124. control = MV64x60_I2C_CONTROL_START | MV64x60_I2C_CONTROL_TWSIEN;
  125. status = MV64x60_I2C_STATUS_MAST_REPEAT_START;
  126. if (mv64x60_i2c_control(control, status) < 0)
  127. return -1;
  128. /* select device for reading */
  129. data = devaddr | 0x1;
  130. control = MV64x60_I2C_CONTROL_TWSIEN;
  131. status = MV64x60_I2C_STATUS_MAST_RD_ADDR_ACK;
  132. if (mv64x60_i2c_write_byte(data, control, status) < 0)
  133. return -1;
  134. /* read all but last byte of data */
  135. control = MV64x60_I2C_CONTROL_ACK | MV64x60_I2C_CONTROL_TWSIEN;
  136. status = MV64x60_I2C_STATUS_MAST_RD_DATA_ACK;
  137. for (i=1; i<count; i++) {
  138. data = mv64x60_i2c_read_byte(control, status);
  139. if (data < 0) {
  140. printf("errors on iteration %d\n", i);
  141. return -1;
  142. }
  143. *buf++ = data;
  144. }
  145. /* read last byte of data */
  146. control = MV64x60_I2C_CONTROL_TWSIEN;
  147. status = MV64x60_I2C_STATUS_MAST_RD_DATA_NO_ACK;
  148. data = mv64x60_i2c_read_byte(control, status);
  149. if (data < 0)
  150. return -1;
  151. *buf++ = data;
  152. /* send stop */
  153. control = MV64x60_I2C_CONTROL_STOP | MV64x60_I2C_CONTROL_TWSIEN;
  154. status = MV64x60_I2C_STATUS_NO_STATUS;
  155. if (mv64x60_i2c_control(control, status) < 0)
  156. return -1;
  157. return count;
  158. }
  159. int mv64x60_i2c_open(void)
  160. {
  161. u32 v;
  162. void *devp;
  163. devp = finddevice("/mv64x60/i2c");
  164. if (devp == NULL)
  165. goto err_out;
  166. if (getprop(devp, "virtual-reg", &v, sizeof(v)) != sizeof(v))
  167. goto err_out;
  168. ctlr_base = (u8 *)v;
  169. return 0;
  170. err_out:
  171. return -1;
  172. }
  173. void mv64x60_i2c_close(void)
  174. {
  175. ctlr_base = NULL;
  176. }