mw_eeprom.c 3.8 KB

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