i2c_eeprom.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (c) 2014 Google, Inc
  4. */
  5. #define LOG_CATEGORY UCLASS_I2C_EEPROM
  6. #include <common.h>
  7. #include <eeprom.h>
  8. #include <linux/delay.h>
  9. #include <linux/err.h>
  10. #include <linux/kernel.h>
  11. #include <dm.h>
  12. #include <dm/device-internal.h>
  13. #include <i2c.h>
  14. #include <i2c_eeprom.h>
  15. struct i2c_eeprom_drv_data {
  16. u32 size; /* size in bytes */
  17. u32 pagesize; /* page size in bytes */
  18. u32 addr_offset_mask; /* bits in addr used for offset overflow */
  19. u32 offset_len; /* size in bytes of offset */
  20. u32 start_offset; /* valid start offset inside memory, by default 0 */
  21. };
  22. int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf, int size)
  23. {
  24. const struct i2c_eeprom_ops *ops = device_get_ops(dev);
  25. if (!ops->read)
  26. return -ENOSYS;
  27. return ops->read(dev, offset, buf, size);
  28. }
  29. int i2c_eeprom_write(struct udevice *dev, int offset, uint8_t *buf, int size)
  30. {
  31. const struct i2c_eeprom_ops *ops = device_get_ops(dev);
  32. if (!ops->write)
  33. return -ENOSYS;
  34. return ops->write(dev, offset, buf, size);
  35. }
  36. int i2c_eeprom_size(struct udevice *dev)
  37. {
  38. const struct i2c_eeprom_ops *ops = device_get_ops(dev);
  39. if (!ops->size)
  40. return -ENOSYS;
  41. return ops->size(dev);
  42. }
  43. static int i2c_eeprom_std_read(struct udevice *dev, int offset, uint8_t *buf,
  44. int size)
  45. {
  46. return dm_i2c_read(dev, offset, buf, size);
  47. }
  48. static int i2c_eeprom_std_write(struct udevice *dev, int offset,
  49. const uint8_t *buf, int size)
  50. {
  51. struct i2c_eeprom *priv = dev_get_priv(dev);
  52. int ret;
  53. while (size > 0) {
  54. int write_size = min_t(int, size, priv->pagesize);
  55. ret = dm_i2c_write(dev, offset, buf, write_size);
  56. if (ret)
  57. return ret;
  58. offset += write_size;
  59. buf += write_size;
  60. size -= write_size;
  61. udelay(10000);
  62. }
  63. return 0;
  64. }
  65. static int i2c_eeprom_std_size(struct udevice *dev)
  66. {
  67. struct i2c_eeprom *priv = dev_get_priv(dev);
  68. return priv->size;
  69. }
  70. static const struct i2c_eeprom_ops i2c_eeprom_std_ops = {
  71. .read = i2c_eeprom_std_read,
  72. .write = i2c_eeprom_std_write,
  73. .size = i2c_eeprom_std_size,
  74. };
  75. static int i2c_eeprom_std_of_to_plat(struct udevice *dev)
  76. {
  77. struct i2c_eeprom *priv = dev_get_priv(dev);
  78. struct i2c_eeprom_drv_data *data =
  79. (struct i2c_eeprom_drv_data *)dev_get_driver_data(dev);
  80. u32 pagesize;
  81. u32 size;
  82. if (dev_read_u32(dev, "pagesize", &pagesize) == 0)
  83. priv->pagesize = pagesize;
  84. else
  85. /* 6 bit -> page size of up to 2^63 (should be sufficient) */
  86. priv->pagesize = data->pagesize;
  87. if (dev_read_u32(dev, "size", &size) == 0)
  88. priv->size = size;
  89. else
  90. priv->size = data->size;
  91. return 0;
  92. }
  93. static int i2c_eeprom_std_bind(struct udevice *dev)
  94. {
  95. ofnode partitions = ofnode_find_subnode(dev_ofnode(dev), "partitions");
  96. ofnode partition;
  97. const char *name;
  98. if (!ofnode_valid(partitions))
  99. return 0;
  100. if (!ofnode_device_is_compatible(partitions, "fixed-partitions"))
  101. return -ENOTSUPP;
  102. ofnode_for_each_subnode(partition, partitions) {
  103. name = ofnode_get_name(partition);
  104. if (!name)
  105. continue;
  106. device_bind(dev, DM_DRIVER_GET(i2c_eeprom_partition), name,
  107. NULL, partition, NULL);
  108. }
  109. return 0;
  110. }
  111. static int i2c_eeprom_std_probe(struct udevice *dev)
  112. {
  113. u8 test_byte;
  114. int ret;
  115. struct i2c_eeprom_drv_data *data =
  116. (struct i2c_eeprom_drv_data *)dev_get_driver_data(dev);
  117. i2c_set_chip_offset_len(dev, data->offset_len);
  118. i2c_set_chip_addr_offset_mask(dev, data->addr_offset_mask);
  119. /* Verify that the chip is functional */
  120. /*
  121. * Not all eeproms start from offset 0. Valid offset is available
  122. * in the platform data struct.
  123. */
  124. ret = i2c_eeprom_read(dev, data->start_offset, &test_byte, 1);
  125. if (ret)
  126. return -ENODEV;
  127. return 0;
  128. }
  129. static const struct i2c_eeprom_drv_data eeprom_data = {
  130. .size = 0,
  131. .pagesize = 1,
  132. .addr_offset_mask = 0,
  133. .offset_len = 1,
  134. };
  135. static const struct i2c_eeprom_drv_data mc24aa02e48_data = {
  136. .size = 256,
  137. .pagesize = 8,
  138. .addr_offset_mask = 0,
  139. .offset_len = 1,
  140. };
  141. static const struct i2c_eeprom_drv_data atmel24c01a_data = {
  142. .size = 128,
  143. .pagesize = 8,
  144. .addr_offset_mask = 0,
  145. .offset_len = 1,
  146. };
  147. static const struct i2c_eeprom_drv_data atmel24c02_data = {
  148. .size = 256,
  149. .pagesize = 8,
  150. .addr_offset_mask = 0,
  151. .offset_len = 1,
  152. };
  153. static const struct i2c_eeprom_drv_data atmel24c04_data = {
  154. .size = 512,
  155. .pagesize = 16,
  156. .addr_offset_mask = 0x1,
  157. .offset_len = 1,
  158. };
  159. static const struct i2c_eeprom_drv_data atmel24c08_data = {
  160. .size = 1024,
  161. .pagesize = 16,
  162. .addr_offset_mask = 0x3,
  163. .offset_len = 1,
  164. };
  165. static const struct i2c_eeprom_drv_data atmel24c08a_data = {
  166. .size = 1024,
  167. .pagesize = 16,
  168. .addr_offset_mask = 0x3,
  169. .offset_len = 1,
  170. };
  171. static const struct i2c_eeprom_drv_data atmel24c16a_data = {
  172. .size = 2048,
  173. .pagesize = 16,
  174. .addr_offset_mask = 0x7,
  175. .offset_len = 1,
  176. };
  177. static const struct i2c_eeprom_drv_data atmel24mac402_data = {
  178. .size = 256,
  179. .pagesize = 16,
  180. .addr_offset_mask = 0,
  181. .offset_len = 1,
  182. .start_offset = 0x80,
  183. };
  184. static const struct i2c_eeprom_drv_data atmel24c32_data = {
  185. .size = 4096,
  186. .pagesize = 32,
  187. .addr_offset_mask = 0,
  188. .offset_len = 2,
  189. };
  190. static const struct i2c_eeprom_drv_data atmel24c64_data = {
  191. .size = 8192,
  192. .pagesize = 32,
  193. .addr_offset_mask = 0,
  194. .offset_len = 2,
  195. };
  196. static const struct i2c_eeprom_drv_data atmel24c128_data = {
  197. .size = 16384,
  198. .pagesize = 64,
  199. .addr_offset_mask = 0,
  200. .offset_len = 2,
  201. };
  202. static const struct i2c_eeprom_drv_data atmel24c256_data = {
  203. .size = 32768,
  204. .pagesize = 64,
  205. .addr_offset_mask = 0,
  206. .offset_len = 2,
  207. };
  208. static const struct i2c_eeprom_drv_data atmel24c512_data = {
  209. .size = 65536,
  210. .pagesize = 64,
  211. .addr_offset_mask = 0,
  212. .offset_len = 2,
  213. };
  214. static const struct udevice_id i2c_eeprom_std_ids[] = {
  215. { .compatible = "i2c-eeprom", (ulong)&eeprom_data },
  216. { .compatible = "microchip,24aa02e48", (ulong)&mc24aa02e48_data },
  217. { .compatible = "atmel,24c01a", (ulong)&atmel24c01a_data },
  218. { .compatible = "atmel,24c02", (ulong)&atmel24c02_data },
  219. { .compatible = "atmel,24c04", (ulong)&atmel24c04_data },
  220. { .compatible = "atmel,24c08", (ulong)&atmel24c08_data },
  221. { .compatible = "atmel,24c08a", (ulong)&atmel24c08a_data },
  222. { .compatible = "atmel,24c16a", (ulong)&atmel24c16a_data },
  223. { .compatible = "atmel,24mac402", (ulong)&atmel24mac402_data },
  224. { .compatible = "atmel,24c32", (ulong)&atmel24c32_data },
  225. { .compatible = "atmel,24c64", (ulong)&atmel24c64_data },
  226. { .compatible = "atmel,24c128", (ulong)&atmel24c128_data },
  227. { .compatible = "atmel,24c256", (ulong)&atmel24c256_data },
  228. { .compatible = "atmel,24c512", (ulong)&atmel24c512_data },
  229. { }
  230. };
  231. U_BOOT_DRIVER(i2c_eeprom_std) = {
  232. .name = "i2c_eeprom",
  233. .id = UCLASS_I2C_EEPROM,
  234. .of_match = i2c_eeprom_std_ids,
  235. .bind = i2c_eeprom_std_bind,
  236. .probe = i2c_eeprom_std_probe,
  237. .of_to_plat = i2c_eeprom_std_of_to_plat,
  238. .priv_auto = sizeof(struct i2c_eeprom),
  239. .ops = &i2c_eeprom_std_ops,
  240. };
  241. struct i2c_eeprom_partition {
  242. u32 offset;
  243. u32 size;
  244. };
  245. static int i2c_eeprom_partition_probe(struct udevice *dev)
  246. {
  247. return 0;
  248. }
  249. static int i2c_eeprom_partition_of_to_plat(struct udevice *dev)
  250. {
  251. struct i2c_eeprom_partition *priv = dev_get_priv(dev);
  252. u32 reg[2];
  253. int ret;
  254. ret = dev_read_u32_array(dev, "reg", reg, 2);
  255. if (ret)
  256. return ret;
  257. if (!reg[1])
  258. return -EINVAL;
  259. priv->offset = reg[0];
  260. priv->size = reg[1];
  261. debug("%s: base %x, size %x\n", __func__, priv->offset, priv->size);
  262. return 0;
  263. }
  264. static int i2c_eeprom_partition_read(struct udevice *dev, int offset,
  265. u8 *buf, int size)
  266. {
  267. struct i2c_eeprom_partition *priv = dev_get_priv(dev);
  268. struct udevice *parent = dev_get_parent(dev);
  269. if (!parent)
  270. return -ENODEV;
  271. if (offset + size > priv->size)
  272. return -EINVAL;
  273. return i2c_eeprom_read(parent, offset + priv->offset, buf, size);
  274. }
  275. static int i2c_eeprom_partition_write(struct udevice *dev, int offset,
  276. const u8 *buf, int size)
  277. {
  278. struct i2c_eeprom_partition *priv = dev_get_priv(dev);
  279. struct udevice *parent = dev_get_parent(dev);
  280. if (!parent)
  281. return -ENODEV;
  282. if (offset + size > priv->size)
  283. return -EINVAL;
  284. return i2c_eeprom_write(parent, offset + priv->offset, (uint8_t *)buf,
  285. size);
  286. }
  287. static int i2c_eeprom_partition_size(struct udevice *dev)
  288. {
  289. struct i2c_eeprom_partition *priv = dev_get_priv(dev);
  290. return priv->size;
  291. }
  292. static const struct i2c_eeprom_ops i2c_eeprom_partition_ops = {
  293. .read = i2c_eeprom_partition_read,
  294. .write = i2c_eeprom_partition_write,
  295. .size = i2c_eeprom_partition_size,
  296. };
  297. U_BOOT_DRIVER(i2c_eeprom_partition) = {
  298. .name = "i2c_eeprom_partition",
  299. .id = UCLASS_I2C_EEPROM,
  300. .probe = i2c_eeprom_partition_probe,
  301. .of_to_plat = i2c_eeprom_partition_of_to_plat,
  302. .priv_auto = sizeof(struct i2c_eeprom_partition),
  303. .ops = &i2c_eeprom_partition_ops,
  304. };
  305. UCLASS_DRIVER(i2c_eeprom) = {
  306. .id = UCLASS_I2C_EEPROM,
  307. .name = "i2c_eeprom",
  308. };