123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * Copyright (c) 2014 Google, Inc
- */
- #include <common.h>
- #include <eeprom.h>
- #include <linux/err.h>
- #include <linux/kernel.h>
- #include <dm.h>
- #include <dm/device-internal.h>
- #include <i2c.h>
- #include <i2c_eeprom.h>
- struct i2c_eeprom_drv_data {
- u32 size; /* size in bytes */
- u32 pagewidth; /* pagesize = 2^pagewidth */
- u32 addr_offset_mask; /* bits in addr used for offset overflow */
- u32 offset_len; /* size in bytes of offset */
- };
- int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf, int size)
- {
- const struct i2c_eeprom_ops *ops = device_get_ops(dev);
- if (!ops->read)
- return -ENOSYS;
- return ops->read(dev, offset, buf, size);
- }
- int i2c_eeprom_write(struct udevice *dev, int offset, uint8_t *buf, int size)
- {
- const struct i2c_eeprom_ops *ops = device_get_ops(dev);
- if (!ops->write)
- return -ENOSYS;
- return ops->write(dev, offset, buf, size);
- }
- int i2c_eeprom_size(struct udevice *dev)
- {
- const struct i2c_eeprom_ops *ops = device_get_ops(dev);
- if (!ops->size)
- return -ENOSYS;
- return ops->size(dev);
- }
- static int i2c_eeprom_std_read(struct udevice *dev, int offset, uint8_t *buf,
- int size)
- {
- return dm_i2c_read(dev, offset, buf, size);
- }
- static int i2c_eeprom_std_write(struct udevice *dev, int offset,
- const uint8_t *buf, int size)
- {
- struct i2c_eeprom *priv = dev_get_priv(dev);
- int ret;
- while (size > 0) {
- int write_size = min_t(int, size, priv->pagesize);
- ret = dm_i2c_write(dev, offset, buf, write_size);
- if (ret)
- return ret;
- offset += write_size;
- buf += write_size;
- size -= write_size;
- udelay(10000);
- }
- return 0;
- }
- static int i2c_eeprom_std_size(struct udevice *dev)
- {
- struct i2c_eeprom *priv = dev_get_priv(dev);
- return priv->size;
- }
- static const struct i2c_eeprom_ops i2c_eeprom_std_ops = {
- .read = i2c_eeprom_std_read,
- .write = i2c_eeprom_std_write,
- .size = i2c_eeprom_std_size,
- };
- static int i2c_eeprom_std_ofdata_to_platdata(struct udevice *dev)
- {
- struct i2c_eeprom *priv = dev_get_priv(dev);
- struct i2c_eeprom_drv_data *data =
- (struct i2c_eeprom_drv_data *)dev_get_driver_data(dev);
- u32 pagesize;
- u32 size;
- if (dev_read_u32(dev, "pagesize", &pagesize) == 0)
- priv->pagesize = pagesize;
- else
- /* 6 bit -> page size of up to 2^63 (should be sufficient) */
- priv->pagesize = 1 << data->pagewidth;
- if (dev_read_u32(dev, "size", &size) == 0)
- priv->size = size;
- else
- priv->size = data->size;
- return 0;
- }
- static int i2c_eeprom_std_bind(struct udevice *dev)
- {
- ofnode partitions = ofnode_find_subnode(dev_ofnode(dev), "partitions");
- ofnode partition;
- const char *name;
- if (!ofnode_valid(partitions))
- return 0;
- if (!ofnode_device_is_compatible(partitions, "fixed-partitions"))
- return -ENOTSUPP;
- ofnode_for_each_subnode(partition, partitions) {
- name = ofnode_get_name(partition);
- if (!name)
- continue;
- device_bind_ofnode(dev, DM_GET_DRIVER(i2c_eeprom_partition),
- name, NULL, partition, NULL);
- }
- return 0;
- }
- static int i2c_eeprom_std_probe(struct udevice *dev)
- {
- u8 test_byte;
- int ret;
- struct i2c_eeprom_drv_data *data =
- (struct i2c_eeprom_drv_data *)dev_get_driver_data(dev);
- i2c_set_chip_offset_len(dev, data->offset_len);
- i2c_set_chip_addr_offset_mask(dev, data->addr_offset_mask);
- /* Verify that the chip is functional */
- ret = i2c_eeprom_read(dev, 0, &test_byte, 1);
- if (ret)
- return -ENODEV;
- return 0;
- }
- static const struct i2c_eeprom_drv_data eeprom_data = {
- .size = 0,
- .pagewidth = 0,
- .addr_offset_mask = 0,
- .offset_len = 1,
- };
- static const struct i2c_eeprom_drv_data mc24aa02e48_data = {
- .size = 256,
- .pagewidth = 3,
- .addr_offset_mask = 0,
- .offset_len = 1,
- };
- static const struct i2c_eeprom_drv_data atmel24c01a_data = {
- .size = 128,
- .pagewidth = 3,
- .addr_offset_mask = 0,
- .offset_len = 1,
- };
- static const struct i2c_eeprom_drv_data atmel24c02_data = {
- .size = 256,
- .pagewidth = 3,
- .addr_offset_mask = 0,
- .offset_len = 1,
- };
- static const struct i2c_eeprom_drv_data atmel24c04_data = {
- .size = 512,
- .pagewidth = 4,
- .addr_offset_mask = 0x1,
- .offset_len = 1,
- };
- static const struct i2c_eeprom_drv_data atmel24c08_data = {
- .size = 1024,
- .pagewidth = 4,
- .addr_offset_mask = 0x3,
- .offset_len = 1,
- };
- static const struct i2c_eeprom_drv_data atmel24c08a_data = {
- .size = 1024,
- .pagewidth = 4,
- .addr_offset_mask = 0x3,
- .offset_len = 1,
- };
- static const struct i2c_eeprom_drv_data atmel24c16a_data = {
- .size = 2048,
- .pagewidth = 4,
- .addr_offset_mask = 0x7,
- .offset_len = 1,
- };
- static const struct i2c_eeprom_drv_data atmel24mac402_data = {
- .size = 256,
- .pagewidth = 4,
- .addr_offset_mask = 0,
- .offset_len = 1,
- };
- static const struct i2c_eeprom_drv_data atmel24c32_data = {
- .size = 4096,
- .pagewidth = 5,
- .addr_offset_mask = 0,
- .offset_len = 2,
- };
- static const struct i2c_eeprom_drv_data atmel24c64_data = {
- .size = 8192,
- .pagewidth = 5,
- .addr_offset_mask = 0,
- .offset_len = 2,
- };
- static const struct i2c_eeprom_drv_data atmel24c128_data = {
- .size = 16384,
- .pagewidth = 6,
- .addr_offset_mask = 0,
- .offset_len = 2,
- };
- static const struct i2c_eeprom_drv_data atmel24c256_data = {
- .size = 32768,
- .pagewidth = 6,
- .addr_offset_mask = 0,
- .offset_len = 2,
- };
- static const struct i2c_eeprom_drv_data atmel24c512_data = {
- .size = 65536,
- .pagewidth = 6,
- .addr_offset_mask = 0,
- .offset_len = 2,
- };
- static const struct udevice_id i2c_eeprom_std_ids[] = {
- { .compatible = "i2c-eeprom", (ulong)&eeprom_data },
- { .compatible = "microchip,24aa02e48", (ulong)&mc24aa02e48_data },
- { .compatible = "atmel,24c01a", (ulong)&atmel24c01a_data },
- { .compatible = "atmel,24c02", (ulong)&atmel24c02_data },
- { .compatible = "atmel,24c04", (ulong)&atmel24c04_data },
- { .compatible = "atmel,24c08", (ulong)&atmel24c08_data },
- { .compatible = "atmel,24c08a", (ulong)&atmel24c08a_data },
- { .compatible = "atmel,24c16a", (ulong)&atmel24c16a_data },
- { .compatible = "atmel,24mac402", (ulong)&atmel24mac402_data },
- { .compatible = "atmel,24c32", (ulong)&atmel24c32_data },
- { .compatible = "atmel,24c64", (ulong)&atmel24c64_data },
- { .compatible = "atmel,24c128", (ulong)&atmel24c128_data },
- { .compatible = "atmel,24c256", (ulong)&atmel24c256_data },
- { .compatible = "atmel,24c512", (ulong)&atmel24c512_data },
- { }
- };
- U_BOOT_DRIVER(i2c_eeprom_std) = {
- .name = "i2c_eeprom",
- .id = UCLASS_I2C_EEPROM,
- .of_match = i2c_eeprom_std_ids,
- .bind = i2c_eeprom_std_bind,
- .probe = i2c_eeprom_std_probe,
- .ofdata_to_platdata = i2c_eeprom_std_ofdata_to_platdata,
- .priv_auto_alloc_size = sizeof(struct i2c_eeprom),
- .ops = &i2c_eeprom_std_ops,
- };
- struct i2c_eeprom_partition {
- u32 offset;
- u32 size;
- };
- static int i2c_eeprom_partition_probe(struct udevice *dev)
- {
- return 0;
- }
- static int i2c_eeprom_partition_ofdata_to_platdata(struct udevice *dev)
- {
- struct i2c_eeprom_partition *priv = dev_get_priv(dev);
- u32 offset, size;
- int ret;
- ret = dev_read_u32(dev, "offset", &offset);
- if (ret)
- return ret;
- ret = dev_read_u32(dev, "size", &size);
- if (ret)
- return ret;
- priv->offset = offset;
- priv->size = size;
- return 0;
- }
- static int i2c_eeprom_partition_read(struct udevice *dev, int offset,
- u8 *buf, int size)
- {
- struct i2c_eeprom_partition *priv = dev_get_priv(dev);
- struct udevice *parent = dev_get_parent(dev);
- if (!parent)
- return -ENODEV;
- if (offset + size > priv->size)
- return -EINVAL;
- return i2c_eeprom_read(parent, offset + priv->offset, buf, size);
- }
- static int i2c_eeprom_partition_write(struct udevice *dev, int offset,
- const u8 *buf, int size)
- {
- struct i2c_eeprom_partition *priv = dev_get_priv(dev);
- struct udevice *parent = dev_get_parent(dev);
- if (!parent)
- return -ENODEV;
- if (offset + size > priv->size)
- return -EINVAL;
- return i2c_eeprom_write(parent, offset + priv->offset, (uint8_t *)buf,
- size);
- }
- static int i2c_eeprom_partition_size(struct udevice *dev)
- {
- struct i2c_eeprom_partition *priv = dev_get_priv(dev);
- return priv->size;
- }
- static const struct i2c_eeprom_ops i2c_eeprom_partition_ops = {
- .read = i2c_eeprom_partition_read,
- .write = i2c_eeprom_partition_write,
- .size = i2c_eeprom_partition_size,
- };
- U_BOOT_DRIVER(i2c_eeprom_partition) = {
- .name = "i2c_eeprom_partition",
- .id = UCLASS_I2C_EEPROM,
- .probe = i2c_eeprom_partition_probe,
- .ofdata_to_platdata = i2c_eeprom_partition_ofdata_to_platdata,
- .priv_auto_alloc_size = sizeof(struct i2c_eeprom_partition),
- .ops = &i2c_eeprom_partition_ops,
- };
- UCLASS_DRIVER(i2c_eeprom) = {
- .id = UCLASS_I2C_EEPROM,
- .name = "i2c_eeprom",
- };
|