ds4510.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. /*
  2. * Copyright 2008 Extreme Engineering Solutions, Inc.
  3. *
  4. * SPDX-License-Identifier: GPL-2.0
  5. */
  6. /*
  7. * Driver for DS4510, a CPU supervisor with integrated EEPROM, SRAM,
  8. * and 4 programmable non-volatile GPIO pins.
  9. */
  10. #include <common.h>
  11. #include <i2c.h>
  12. #include <command.h>
  13. #include <ds4510.h>
  14. /* Default to an address that hopefully won't corrupt other i2c devices */
  15. #ifndef CONFIG_SYS_I2C_DS4510_ADDR
  16. #define CONFIG_SYS_I2C_DS4510_ADDR (~0)
  17. #endif
  18. enum {
  19. DS4510_CMD_INFO,
  20. DS4510_CMD_DEVICE,
  21. DS4510_CMD_NV,
  22. DS4510_CMD_RSTDELAY,
  23. DS4510_CMD_OUTPUT,
  24. DS4510_CMD_INPUT,
  25. DS4510_CMD_PULLUP,
  26. DS4510_CMD_EEPROM,
  27. DS4510_CMD_SEEPROM,
  28. DS4510_CMD_SRAM,
  29. };
  30. /*
  31. * Write to DS4510, taking page boundaries into account
  32. */
  33. int ds4510_mem_write(uint8_t chip, int offset, uint8_t *buf, int count)
  34. {
  35. int wrlen;
  36. int i = 0;
  37. do {
  38. wrlen = DS4510_EEPROM_PAGE_SIZE -
  39. DS4510_EEPROM_PAGE_OFFSET(offset);
  40. if (count < wrlen)
  41. wrlen = count;
  42. if (i2c_write(chip, offset, 1, &buf[i], wrlen))
  43. return -1;
  44. /*
  45. * This delay isn't needed for SRAM writes but shouldn't delay
  46. * things too much, so do it unconditionally for simplicity
  47. */
  48. udelay(DS4510_EEPROM_PAGE_WRITE_DELAY_MS * 1000);
  49. count -= wrlen;
  50. offset += wrlen;
  51. i += wrlen;
  52. } while (count > 0);
  53. return 0;
  54. }
  55. /*
  56. * General read from DS4510
  57. */
  58. int ds4510_mem_read(uint8_t chip, int offset, uint8_t *buf, int count)
  59. {
  60. return i2c_read(chip, offset, 1, buf, count);
  61. }
  62. /*
  63. * Write SEE bit in config register.
  64. * nv = 0 - Writes to SEEPROM registers behave like EEPROM
  65. * nv = 1 - Writes to SEEPROM registers behave like SRAM
  66. */
  67. int ds4510_see_write(uint8_t chip, uint8_t nv)
  68. {
  69. uint8_t data;
  70. if (i2c_read(chip, DS4510_CFG, 1, &data, 1))
  71. return -1;
  72. if (nv) /* Treat SEEPROM bits as EEPROM */
  73. data &= ~DS4510_CFG_SEE;
  74. else /* Treat SEEPROM bits as SRAM */
  75. data |= DS4510_CFG_SEE;
  76. return ds4510_mem_write(chip, DS4510_CFG, &data, 1);
  77. }
  78. /*
  79. * Write de-assertion of reset signal delay
  80. */
  81. int ds4510_rstdelay_write(uint8_t chip, uint8_t delay)
  82. {
  83. uint8_t data;
  84. if (i2c_read(chip, DS4510_RSTDELAY, 1, &data, 1))
  85. return -1;
  86. data &= ~DS4510_RSTDELAY_MASK;
  87. data |= delay & DS4510_RSTDELAY_MASK;
  88. return ds4510_mem_write(chip, DS4510_RSTDELAY, &data, 1);
  89. }
  90. /*
  91. * Write pullup characteristics of IO pins
  92. */
  93. int ds4510_pullup_write(uint8_t chip, uint8_t val)
  94. {
  95. val &= DS4510_IO_MASK;
  96. return ds4510_mem_write(chip, DS4510_PULLUP, (uint8_t *)&val, 1);
  97. }
  98. /*
  99. * Read pullup characteristics of IO pins
  100. */
  101. int ds4510_pullup_read(uint8_t chip)
  102. {
  103. uint8_t val;
  104. if (i2c_read(chip, DS4510_PULLUP, 1, &val, 1))
  105. return -1;
  106. return val & DS4510_IO_MASK;
  107. }
  108. /*
  109. * Write drive level of IO pins
  110. */
  111. int ds4510_gpio_write(uint8_t chip, uint8_t val)
  112. {
  113. uint8_t data;
  114. int i;
  115. for (i = 0; i < DS4510_NUM_IO; i++) {
  116. if (i2c_read(chip, DS4510_IO0 - i, 1, &data, 1))
  117. return -1;
  118. if (val & (0x1 << i))
  119. data |= 0x1;
  120. else
  121. data &= ~0x1;
  122. if (ds4510_mem_write(chip, DS4510_IO0 - i, &data, 1))
  123. return -1;
  124. }
  125. return 0;
  126. }
  127. /*
  128. * Read drive level of IO pins
  129. */
  130. int ds4510_gpio_read(uint8_t chip)
  131. {
  132. uint8_t data;
  133. int val = 0;
  134. int i;
  135. for (i = 0; i < DS4510_NUM_IO; i++) {
  136. if (i2c_read(chip, DS4510_IO0 - i, 1, &data, 1))
  137. return -1;
  138. if (data & 1)
  139. val |= (1 << i);
  140. }
  141. return val;
  142. }
  143. /*
  144. * Read physical level of IO pins
  145. */
  146. int ds4510_gpio_read_val(uint8_t chip)
  147. {
  148. uint8_t val;
  149. if (i2c_read(chip, DS4510_IO_STATUS, 1, &val, 1))
  150. return -1;
  151. return val & DS4510_IO_MASK;
  152. }
  153. #ifdef CONFIG_CMD_DS4510
  154. #ifdef CONFIG_CMD_DS4510_INFO
  155. /*
  156. * Display DS4510 information
  157. */
  158. static int ds4510_info(uint8_t chip)
  159. {
  160. int i;
  161. int tmp;
  162. uint8_t data;
  163. printf("DS4510 @ 0x%x:\n\n", chip);
  164. if (i2c_read(chip, DS4510_RSTDELAY, 1, &data, 1))
  165. return -1;
  166. printf("rstdelay = 0x%x\n\n", data & DS4510_RSTDELAY_MASK);
  167. if (i2c_read(chip, DS4510_CFG, 1, &data, 1))
  168. return -1;
  169. printf("config = 0x%x\n", data);
  170. printf(" /ready = %d\n", data & DS4510_CFG_READY ? 1 : 0);
  171. printf(" trip pt = %d\n", data & DS4510_CFG_TRIP_POINT ? 1 : 0);
  172. printf(" rst sts = %d\n", data & DS4510_CFG_RESET ? 1 : 0);
  173. printf(" /see = %d\n", data & DS4510_CFG_SEE ? 1 : 0);
  174. printf(" swrst = %d\n\n", data & DS4510_CFG_SWRST ? 1 : 0);
  175. printf("gpio pins: 3210\n");
  176. printf("---------------\n");
  177. printf("pullup ");
  178. tmp = ds4510_pullup_read(chip);
  179. if (tmp == -1)
  180. return tmp;
  181. for (i = DS4510_NUM_IO - 1; i >= 0; i--)
  182. printf("%d", (tmp & (1 << i)) ? 1 : 0);
  183. printf("\n");
  184. printf("driven ");
  185. tmp = ds4510_gpio_read(chip);
  186. if (tmp == -1)
  187. return -1;
  188. for (i = DS4510_NUM_IO - 1; i >= 0; i--)
  189. printf("%d", (tmp & (1 << i)) ? 1 : 0);
  190. printf("\n");
  191. printf("read ");
  192. tmp = ds4510_gpio_read_val(chip);
  193. if (tmp == -1)
  194. return -1;
  195. for (i = DS4510_NUM_IO - 1; i >= 0; i--)
  196. printf("%d", (tmp & (1 << i)) ? 1 : 0);
  197. printf("\n");
  198. return 0;
  199. }
  200. #endif /* CONFIG_CMD_DS4510_INFO */
  201. cmd_tbl_t cmd_ds4510[] = {
  202. U_BOOT_CMD_MKENT(device, 3, 0, (void *)DS4510_CMD_DEVICE, "", ""),
  203. U_BOOT_CMD_MKENT(nv, 3, 0, (void *)DS4510_CMD_NV, "", ""),
  204. U_BOOT_CMD_MKENT(output, 4, 0, (void *)DS4510_CMD_OUTPUT, "", ""),
  205. U_BOOT_CMD_MKENT(input, 3, 0, (void *)DS4510_CMD_INPUT, "", ""),
  206. U_BOOT_CMD_MKENT(pullup, 4, 0, (void *)DS4510_CMD_PULLUP, "", ""),
  207. #ifdef CONFIG_CMD_DS4510_INFO
  208. U_BOOT_CMD_MKENT(info, 2, 0, (void *)DS4510_CMD_INFO, "", ""),
  209. #endif
  210. #ifdef CONFIG_CMD_DS4510_RST
  211. U_BOOT_CMD_MKENT(rstdelay, 3, 0, (void *)DS4510_CMD_RSTDELAY, "", ""),
  212. #endif
  213. #ifdef CONFIG_CMD_DS4510_MEM
  214. U_BOOT_CMD_MKENT(eeprom, 6, 0, (void *)DS4510_CMD_EEPROM, "", ""),
  215. U_BOOT_CMD_MKENT(seeprom, 6, 0, (void *)DS4510_CMD_SEEPROM, "", ""),
  216. U_BOOT_CMD_MKENT(sram, 6, 0, (void *)DS4510_CMD_SRAM, "", ""),
  217. #endif
  218. };
  219. int do_ds4510(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  220. {
  221. static uint8_t chip = CONFIG_SYS_I2C_DS4510_ADDR;
  222. cmd_tbl_t *c;
  223. ulong ul_arg2 = 0;
  224. ulong ul_arg3 = 0;
  225. int tmp;
  226. #ifdef CONFIG_CMD_DS4510_MEM
  227. ulong addr;
  228. ulong off;
  229. ulong cnt;
  230. int end;
  231. int (*rw_func)(uint8_t, int, uint8_t *, int);
  232. #endif
  233. c = find_cmd_tbl(argv[1], cmd_ds4510, ARRAY_SIZE(cmd_ds4510));
  234. /* All commands but "device" require 'maxargs' arguments */
  235. if (!c || !((argc == (c->maxargs)) ||
  236. (((int)c->cmd == DS4510_CMD_DEVICE) &&
  237. (argc == (c->maxargs - 1))))) {
  238. return cmd_usage(cmdtp);
  239. }
  240. /* arg2 used as chip addr and pin number */
  241. if (argc > 2)
  242. ul_arg2 = simple_strtoul(argv[2], NULL, 16);
  243. /* arg3 used as output/pullup value */
  244. if (argc > 3)
  245. ul_arg3 = simple_strtoul(argv[3], NULL, 16);
  246. switch ((int)c->cmd) {
  247. case DS4510_CMD_DEVICE:
  248. if (argc == 3)
  249. chip = ul_arg2;
  250. printf("Current device address: 0x%x\n", chip);
  251. return 0;
  252. case DS4510_CMD_NV:
  253. return ds4510_see_write(chip, ul_arg2);
  254. case DS4510_CMD_OUTPUT:
  255. tmp = ds4510_gpio_read(chip);
  256. if (tmp == -1)
  257. return -1;
  258. if (ul_arg3)
  259. tmp |= (1 << ul_arg2);
  260. else
  261. tmp &= ~(1 << ul_arg2);
  262. return ds4510_gpio_write(chip, tmp);
  263. case DS4510_CMD_INPUT:
  264. tmp = ds4510_gpio_read_val(chip);
  265. if (tmp == -1)
  266. return -1;
  267. return (tmp & (1 << ul_arg2)) != 0;
  268. case DS4510_CMD_PULLUP:
  269. tmp = ds4510_pullup_read(chip);
  270. if (tmp == -1)
  271. return -1;
  272. if (ul_arg3)
  273. tmp |= (1 << ul_arg2);
  274. else
  275. tmp &= ~(1 << ul_arg2);
  276. return ds4510_pullup_write(chip, tmp);
  277. #ifdef CONFIG_CMD_DS4510_INFO
  278. case DS4510_CMD_INFO:
  279. return ds4510_info(chip);
  280. #endif
  281. #ifdef CONFIG_CMD_DS4510_RST
  282. case DS4510_CMD_RSTDELAY:
  283. return ds4510_rstdelay_write(chip, ul_arg2);
  284. #endif
  285. #ifdef CONFIG_CMD_DS4510_MEM
  286. case DS4510_CMD_EEPROM:
  287. end = DS4510_EEPROM + DS4510_EEPROM_SIZE;
  288. off = DS4510_EEPROM;
  289. break;
  290. case DS4510_CMD_SEEPROM:
  291. end = DS4510_SEEPROM + DS4510_SEEPROM_SIZE;
  292. off = DS4510_SEEPROM;
  293. break;
  294. case DS4510_CMD_SRAM:
  295. end = DS4510_SRAM + DS4510_SRAM_SIZE;
  296. off = DS4510_SRAM;
  297. break;
  298. #endif
  299. default:
  300. /* We should never get here... */
  301. return 1;
  302. }
  303. #ifdef CONFIG_CMD_DS4510_MEM
  304. /* Only eeprom, seeprom, and sram commands should make it here */
  305. if (strcmp(argv[2], "read") == 0)
  306. rw_func = ds4510_mem_read;
  307. else if (strcmp(argv[2], "write") == 0)
  308. rw_func = ds4510_mem_write;
  309. else
  310. return cmd_usage(cmdtp);
  311. addr = simple_strtoul(argv[3], NULL, 16);
  312. off += simple_strtoul(argv[4], NULL, 16);
  313. cnt = simple_strtoul(argv[5], NULL, 16);
  314. if ((off + cnt) > end) {
  315. printf("ERROR: invalid len\n");
  316. return -1;
  317. }
  318. return rw_func(chip, off, (uint8_t *)addr, cnt);
  319. #endif
  320. }
  321. U_BOOT_CMD(
  322. ds4510, 6, 1, do_ds4510,
  323. "ds4510 eeprom/seeprom/sram/gpio access",
  324. "device [dev]\n"
  325. " - show or set current device address\n"
  326. #ifdef CONFIG_CMD_DS4510_INFO
  327. "ds4510 info\n"
  328. " - display ds4510 info\n"
  329. #endif
  330. "ds4510 output pin 0|1\n"
  331. " - set pin low or high-Z\n"
  332. "ds4510 input pin\n"
  333. " - read value of pin\n"
  334. "ds4510 pullup pin 0|1\n"
  335. " - disable/enable pullup on specified pin\n"
  336. "ds4510 nv 0|1\n"
  337. " - make gpio and seeprom writes volatile/non-volatile"
  338. #ifdef CONFIG_CMD_DS4510_RST
  339. "\n"
  340. "ds4510 rstdelay 0-3\n"
  341. " - set reset output delay"
  342. #endif
  343. #ifdef CONFIG_CMD_DS4510_MEM
  344. "\n"
  345. "ds4510 eeprom read addr off cnt\n"
  346. "ds4510 eeprom write addr off cnt\n"
  347. " - read/write 'cnt' bytes at EEPROM offset 'off'\n"
  348. "ds4510 seeprom read addr off cnt\n"
  349. "ds4510 seeprom write addr off cnt\n"
  350. " - read/write 'cnt' bytes at SRAM-shadowed EEPROM offset 'off'\n"
  351. "ds4510 sram read addr off cnt\n"
  352. "ds4510 sram write addr off cnt\n"
  353. " - read/write 'cnt' bytes at SRAM offset 'off'"
  354. #endif
  355. );
  356. #endif /* CONFIG_CMD_DS4510 */