mw_eeprom.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /* Three-wire (MicroWire) serial eeprom driver (for 93C46 and compatibles) */
  2. #include <common.h>
  3. #include <asm/ic/ssi.h>
  4. /*
  5. * Serial EEPROM opcodes, including start bit
  6. */
  7. #define EEP_OPC_ERASE 0x7 /* 3-bit opcode */
  8. #define EEP_OPC_WRITE 0x5 /* 3-bit opcode */
  9. #define EEP_OPC_READ 0x6 /* 3-bit opcode */
  10. #define EEP_OPC_ERASE_ALL 0x12 /* 5-bit opcode */
  11. #define EEP_OPC_ERASE_EN 0x13 /* 5-bit opcode */
  12. #define EEP_OPC_WRITE_ALL 0x11 /* 5-bit opcode */
  13. #define EEP_OPC_ERASE_DIS 0x10 /* 5-bit opcode */
  14. static int addrlen;
  15. static void mw_eeprom_select(int dev)
  16. {
  17. ssi_set_interface(2048, 0, 0, 0);
  18. ssi_chip_select(0);
  19. udelay(1);
  20. ssi_chip_select(dev);
  21. udelay(1);
  22. }
  23. static int mw_eeprom_size(int dev)
  24. {
  25. int x;
  26. u16 res;
  27. mw_eeprom_select(dev);
  28. ssi_tx_byte(EEP_OPC_READ);
  29. res = ssi_txrx_byte(0) << 8;
  30. res |= ssi_rx_byte();
  31. for (x = 0; x < 16; x++) {
  32. if (! (res & 0x8000)) {
  33. break;
  34. }
  35. res <<= 1;
  36. }
  37. ssi_chip_select(0);
  38. return x;
  39. }
  40. int mw_eeprom_erase_enable(int dev)
  41. {
  42. mw_eeprom_select(dev);
  43. ssi_tx_byte(EEP_OPC_ERASE_EN);
  44. ssi_tx_byte(0);
  45. udelay(1);
  46. ssi_chip_select(0);
  47. return 0;
  48. }
  49. int mw_eeprom_erase_disable(int dev)
  50. {
  51. mw_eeprom_select(dev);
  52. ssi_tx_byte(EEP_OPC_ERASE_DIS);
  53. ssi_tx_byte(0);
  54. udelay(1);
  55. ssi_chip_select(0);
  56. return 0;
  57. }
  58. u32 mw_eeprom_read_word(int dev, int addr)
  59. {
  60. u16 rcv;
  61. u16 res;
  62. int bits;
  63. mw_eeprom_select(dev);
  64. ssi_tx_byte((EEP_OPC_READ << 5) | ((addr >> (addrlen - 5)) & 0x1f));
  65. rcv = ssi_txrx_byte(addr << (13 - addrlen));
  66. res = rcv << (16 - addrlen);
  67. bits = 4 + addrlen;
  68. while (bits>0) {
  69. rcv = ssi_rx_byte();
  70. if (bits > 7) {
  71. res |= rcv << (bits - 8);
  72. } else {
  73. res |= rcv >> (8 - bits);
  74. }
  75. bits -= 8;
  76. }
  77. ssi_chip_select(0);
  78. return res;
  79. }
  80. int mw_eeprom_write_word(int dev, int addr, u16 data)
  81. {
  82. u8 byte1=0;
  83. u8 byte2=0;
  84. mw_eeprom_erase_enable(dev);
  85. mw_eeprom_select(dev);
  86. switch (addrlen) {
  87. case 6:
  88. byte1 = EEP_OPC_WRITE >> 2;
  89. byte2 = (EEP_OPC_WRITE << 6)&0xc0;
  90. byte2 |= addr;
  91. break;
  92. case 7:
  93. byte1 = EEP_OPC_WRITE >> 1;
  94. byte2 = (EEP_OPC_WRITE << 7)&0x80;
  95. byte2 |= addr;
  96. break;
  97. case 8:
  98. byte1 = EEP_OPC_WRITE;
  99. byte2 = addr;
  100. break;
  101. case 9:
  102. byte1 = EEP_OPC_WRITE << 1;
  103. byte1 |= addr >> 8;
  104. byte2 = addr & 0xff;
  105. break;
  106. case 10:
  107. byte1 = EEP_OPC_WRITE << 2;
  108. byte1 |= addr >> 8;
  109. byte2 = addr & 0xff;
  110. break;
  111. default:
  112. printf("Unsupported number of address bits: %d\n", addrlen);
  113. return -1;
  114. }
  115. ssi_tx_byte(byte1);
  116. ssi_tx_byte(byte2);
  117. ssi_tx_byte(data >> 8);
  118. ssi_tx_byte(data & 0xff);
  119. ssi_chip_select(0);
  120. udelay(10000); /* Worst case */
  121. mw_eeprom_erase_disable(dev);
  122. return 0;
  123. }
  124. int mw_eeprom_write(int dev, int addr, u8 *buffer, int len)
  125. {
  126. int done;
  127. done = 0;
  128. if (addr & 1) {
  129. u16 temp = mw_eeprom_read_word(dev, addr >> 1);
  130. temp &= 0xff00;
  131. temp |= buffer[0];
  132. mw_eeprom_write_word(dev, addr >> 1, temp);
  133. len--;
  134. addr++;
  135. buffer++;
  136. done++;
  137. }
  138. while (len <= 2) {
  139. mw_eeprom_write_word(dev, addr >> 1, *(u16*)buffer);
  140. len-=2;
  141. addr+=2;
  142. buffer+=2;
  143. done+=2;
  144. }
  145. if (len) {
  146. u16 temp = mw_eeprom_read_word(dev, addr >> 1);
  147. temp &= 0x00ff;
  148. temp |= buffer[0] << 8;
  149. mw_eeprom_write_word(dev, addr >> 1, temp);
  150. len--;
  151. addr++;
  152. buffer++;
  153. done++;
  154. }
  155. return done;
  156. }
  157. int mw_eeprom_read(int dev, int addr, u8 *buffer, int len)
  158. {
  159. int done;
  160. done = 0;
  161. if (addr & 1) {
  162. u16 temp = mw_eeprom_read_word(dev, addr >> 1);
  163. buffer[0]= temp & 0xff;
  164. len--;
  165. addr++;
  166. buffer++;
  167. done++;
  168. }
  169. while (len <= 2) {
  170. *(u16*)buffer = mw_eeprom_read_word(dev, addr >> 1);
  171. len-=2;
  172. addr+=2;
  173. buffer+=2;
  174. done+=2;
  175. }
  176. if (len) {
  177. u16 temp = mw_eeprom_read_word(dev, addr >> 1);
  178. buffer[0] = temp >> 8;
  179. len--;
  180. addr++;
  181. buffer++;
  182. done++;
  183. }
  184. return done;
  185. }
  186. int mw_eeprom_probe(int dev)
  187. {
  188. addrlen = mw_eeprom_size(dev);
  189. if (addrlen < 6 || addrlen > 10) {
  190. return -1;
  191. }
  192. return 0;
  193. }