Merge tag '20191217-for-next' of https://gitlab.denx.de/u-boot/custodians/u-boot-i2c into next
i2c: for next - misc: i2c_eeprom: Add partition support and add ability to query size of eeprom device and partitions - i2c common: add support for offset overflow in to address and add sandbox tests for it.
This commit is contained in:
		
						commit
						533c9f5714
					
				|  | @ -72,6 +72,13 @@ void sandbox_i2c_eeprom_set_test_mode(struct udevice *dev, | ||||||
| 
 | 
 | ||||||
| void sandbox_i2c_eeprom_set_offset_len(struct udevice *dev, int offset_len); | void sandbox_i2c_eeprom_set_offset_len(struct udevice *dev, int offset_len); | ||||||
| 
 | 
 | ||||||
|  | void sandbox_i2c_eeprom_set_chip_addr_offset_mask(struct udevice *dev, | ||||||
|  | 						  uint mask); | ||||||
|  | 
 | ||||||
|  | uint sanbox_i2c_eeprom_get_prev_addr(struct udevice *dev); | ||||||
|  | 
 | ||||||
|  | uint sanbox_i2c_eeprom_get_prev_offset(struct udevice *dev); | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * sandbox_i2c_rtc_set_offset() - set the time offset from system/base time |  * sandbox_i2c_rtc_set_offset() - set the time offset from system/base time | ||||||
|  * |  * | ||||||
|  |  | ||||||
|  | @ -52,16 +52,19 @@ void i2c_dump_msgs(struct i2c_msg *msg, int nmsgs) | ||||||
| static int i2c_setup_offset(struct dm_i2c_chip *chip, uint offset, | static int i2c_setup_offset(struct dm_i2c_chip *chip, uint offset, | ||||||
| 			    uint8_t offset_buf[], struct i2c_msg *msg) | 			    uint8_t offset_buf[], struct i2c_msg *msg) | ||||||
| { | { | ||||||
| 	int offset_len; | 	int offset_len = chip->offset_len; | ||||||
| 
 | 
 | ||||||
| 	msg->addr = chip->chip_addr; | 	msg->addr = chip->chip_addr; | ||||||
|  | 	if (chip->chip_addr_offset_mask) | ||||||
|  | 		msg->addr |= (offset >> (8 * offset_len)) & | ||||||
|  | 			chip->chip_addr_offset_mask; | ||||||
| 	msg->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0; | 	msg->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0; | ||||||
| 	msg->len = chip->offset_len; | 	msg->len = chip->offset_len; | ||||||
| 	msg->buf = offset_buf; | 	msg->buf = offset_buf; | ||||||
| 	if (!chip->offset_len) | 	if (!offset_len) | ||||||
| 		return -EADDRNOTAVAIL; | 		return -EADDRNOTAVAIL; | ||||||
| 	assert(chip->offset_len <= I2C_MAX_OFFSET_LEN); | 	assert(offset_len <= I2C_MAX_OFFSET_LEN); | ||||||
| 	offset_len = chip->offset_len; | 
 | ||||||
| 	while (offset_len--) | 	while (offset_len--) | ||||||
| 		*offset_buf++ = offset >> (8 * offset_len); | 		*offset_buf++ = offset >> (8 * offset_len); | ||||||
| 
 | 
 | ||||||
|  | @ -83,7 +86,7 @@ static int i2c_read_bytewise(struct udevice *dev, uint offset, | ||||||
| 		if (i2c_setup_offset(chip, offset + i, offset_buf, msg)) | 		if (i2c_setup_offset(chip, offset + i, offset_buf, msg)) | ||||||
| 			return -EINVAL; | 			return -EINVAL; | ||||||
| 		ptr = msg + 1; | 		ptr = msg + 1; | ||||||
| 		ptr->addr = chip->chip_addr; | 		ptr->addr = msg->addr; | ||||||
| 		ptr->flags = msg->flags | I2C_M_RD; | 		ptr->flags = msg->flags | I2C_M_RD; | ||||||
| 		ptr->len = 1; | 		ptr->len = 1; | ||||||
| 		ptr->buf = &buffer[i]; | 		ptr->buf = &buffer[i]; | ||||||
|  | @ -139,7 +142,7 @@ int dm_i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, int len) | ||||||
| 		ptr++; | 		ptr++; | ||||||
| 
 | 
 | ||||||
| 	if (len) { | 	if (len) { | ||||||
| 		ptr->addr = chip->chip_addr; | 		ptr->addr = msg->addr; | ||||||
| 		ptr->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0; | 		ptr->flags = chip->flags & DM_I2C_CHIP_10BIT ? I2C_M_TEN : 0; | ||||||
| 		ptr->flags |= I2C_M_RD; | 		ptr->flags |= I2C_M_RD; | ||||||
| 		ptr->len = len; | 		ptr->len = len; | ||||||
|  | @ -323,7 +326,8 @@ int i2c_get_chip(struct udevice *bus, uint chip_addr, uint offset_len, | ||||||
| 		struct dm_i2c_chip *chip = dev_get_parent_platdata(dev); | 		struct dm_i2c_chip *chip = dev_get_parent_platdata(dev); | ||||||
| 		int ret; | 		int ret; | ||||||
| 
 | 
 | ||||||
| 		if (chip->chip_addr == chip_addr) { | 		if (chip->chip_addr == (chip_addr & | ||||||
|  | 					~chip->chip_addr_offset_mask)) { | ||||||
| 			ret = device_probe(dev); | 			ret = device_probe(dev); | ||||||
| 			debug("found, ret=%d\n", ret); | 			debug("found, ret=%d\n", ret); | ||||||
| 			if (ret) | 			if (ret) | ||||||
|  | @ -465,6 +469,22 @@ int i2c_get_chip_offset_len(struct udevice *dev) | ||||||
| 	return chip->offset_len; | 	return chip->offset_len; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | int i2c_set_chip_addr_offset_mask(struct udevice *dev, uint mask) | ||||||
|  | { | ||||||
|  | 	struct dm_i2c_chip *chip = dev_get_parent_platdata(dev); | ||||||
|  | 
 | ||||||
|  | 	chip->chip_addr_offset_mask = mask; | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint i2c_get_chip_addr_offset_mask(struct udevice *dev) | ||||||
|  | { | ||||||
|  | 	struct dm_i2c_chip *chip = dev_get_parent_platdata(dev); | ||||||
|  | 
 | ||||||
|  | 	return chip->chip_addr_offset_mask; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #ifdef CONFIG_DM_GPIO | #ifdef CONFIG_DM_GPIO | ||||||
| static void i2c_gpio_set_pin(struct gpio_desc *pin, int bit) | static void i2c_gpio_set_pin(struct gpio_desc *pin, int bit) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -8,9 +8,15 @@ | ||||||
| #include <linux/err.h> | #include <linux/err.h> | ||||||
| #include <linux/kernel.h> | #include <linux/kernel.h> | ||||||
| #include <dm.h> | #include <dm.h> | ||||||
|  | #include <dm/device-internal.h> | ||||||
| #include <i2c.h> | #include <i2c.h> | ||||||
| #include <i2c_eeprom.h> | #include <i2c_eeprom.h> | ||||||
| 
 | 
 | ||||||
|  | struct i2c_eeprom_drv_data { | ||||||
|  | 	u32 size; /* size in bytes */ | ||||||
|  | 	u32 pagewidth; /* pagesize = 2^pagewidth */ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf, int size) | int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf, int size) | ||||||
| { | { | ||||||
| 	const struct i2c_eeprom_ops *ops = device_get_ops(dev); | 	const struct i2c_eeprom_ops *ops = device_get_ops(dev); | ||||||
|  | @ -31,6 +37,16 @@ int i2c_eeprom_write(struct udevice *dev, int offset, uint8_t *buf, int size) | ||||||
| 	return ops->write(dev, offset, buf, size); | 	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, | static int i2c_eeprom_std_read(struct udevice *dev, int offset, uint8_t *buf, | ||||||
| 			       int size) | 			       int size) | ||||||
| { | { | ||||||
|  | @ -60,25 +76,62 @@ static int i2c_eeprom_std_write(struct udevice *dev, int offset, | ||||||
| 	return 0; | 	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 = { | static const struct i2c_eeprom_ops i2c_eeprom_std_ops = { | ||||||
| 	.read	= i2c_eeprom_std_read, | 	.read	= i2c_eeprom_std_read, | ||||||
| 	.write	= i2c_eeprom_std_write, | 	.write	= i2c_eeprom_std_write, | ||||||
|  | 	.size	= i2c_eeprom_std_size, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static int i2c_eeprom_std_ofdata_to_platdata(struct udevice *dev) | static int i2c_eeprom_std_ofdata_to_platdata(struct udevice *dev) | ||||||
| { | { | ||||||
| 	struct i2c_eeprom *priv = dev_get_priv(dev); | 	struct i2c_eeprom *priv = dev_get_priv(dev); | ||||||
| 	u64 data = dev_get_driver_data(dev); | 	struct i2c_eeprom_drv_data *data = | ||||||
|  | 		(struct i2c_eeprom_drv_data *)dev_get_driver_data(dev); | ||||||
| 	u32 pagesize; | 	u32 pagesize; | ||||||
|  | 	u32 size; | ||||||
| 
 | 
 | ||||||
| 	if (dev_read_u32(dev, "pagesize", &pagesize) == 0) { | 	if (dev_read_u32(dev, "pagesize", &pagesize) == 0) { | ||||||
| 		priv->pagesize = pagesize; | 		priv->pagesize = pagesize; | ||||||
| 		return 0; | 	} else { | ||||||
|  | 		/* 6 bit -> page size of up to 2^63 (should be sufficient) */ | ||||||
|  | 		priv->pagewidth = data->pagewidth; | ||||||
|  | 		priv->pagesize = (1 << priv->pagewidth); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* 6 bit -> page size of up to 2^63 (should be sufficient) */ | 	if (dev_read_u32(dev, "size", &size) == 0) | ||||||
| 	priv->pagewidth = data & 0x3F; | 		priv->size = size; | ||||||
| 	priv->pagesize = (1 << priv->pagewidth); | 	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; | 	return 0; | ||||||
| } | } | ||||||
|  | @ -96,21 +149,91 @@ static int i2c_eeprom_std_probe(struct udevice *dev) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static const struct i2c_eeprom_drv_data eeprom_data = { | ||||||
|  | 	.size = 0, | ||||||
|  | 	.pagewidth = 0, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct i2c_eeprom_drv_data mc24aa02e48_data = { | ||||||
|  | 	.size = 256, | ||||||
|  | 	.pagewidth = 3, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct i2c_eeprom_drv_data atmel24c01a_data = { | ||||||
|  | 	.size = 128, | ||||||
|  | 	.pagewidth = 3, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct i2c_eeprom_drv_data atmel24c02_data = { | ||||||
|  | 	.size = 256, | ||||||
|  | 	.pagewidth = 3, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct i2c_eeprom_drv_data atmel24c04_data = { | ||||||
|  | 	.size = 512, | ||||||
|  | 	.pagewidth = 4, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct i2c_eeprom_drv_data atmel24c08_data = { | ||||||
|  | 	.size = 1024, | ||||||
|  | 	.pagewidth = 4, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct i2c_eeprom_drv_data atmel24c08a_data = { | ||||||
|  | 	.size = 1024, | ||||||
|  | 	.pagewidth = 4, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct i2c_eeprom_drv_data atmel24c16a_data = { | ||||||
|  | 	.size = 2048, | ||||||
|  | 	.pagewidth = 4, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct i2c_eeprom_drv_data atmel24mac402_data = { | ||||||
|  | 	.size = 256, | ||||||
|  | 	.pagewidth = 4, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct i2c_eeprom_drv_data atmel24c32_data = { | ||||||
|  | 	.size = 4096, | ||||||
|  | 	.pagewidth = 5, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct i2c_eeprom_drv_data atmel24c64_data = { | ||||||
|  | 	.size = 8192, | ||||||
|  | 	.pagewidth = 5, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct i2c_eeprom_drv_data atmel24c128_data = { | ||||||
|  | 	.size = 16384, | ||||||
|  | 	.pagewidth = 6, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct i2c_eeprom_drv_data atmel24c256_data = { | ||||||
|  | 	.size = 32768, | ||||||
|  | 	.pagewidth = 6, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct i2c_eeprom_drv_data atmel24c512_data = { | ||||||
|  | 	.size = 65536, | ||||||
|  | 	.pagewidth = 6, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| static const struct udevice_id i2c_eeprom_std_ids[] = { | static const struct udevice_id i2c_eeprom_std_ids[] = { | ||||||
| 	{ .compatible = "i2c-eeprom", .data = 0 }, | 	{ .compatible = "i2c-eeprom", (ulong)&eeprom_data }, | ||||||
| 	{ .compatible = "microchip,24aa02e48", .data = 3 }, | 	{ .compatible = "microchip,24aa02e48", (ulong)&mc24aa02e48_data }, | ||||||
| 	{ .compatible = "atmel,24c01a", .data = 3 }, | 	{ .compatible = "atmel,24c01a", (ulong)&atmel24c01a_data }, | ||||||
| 	{ .compatible = "atmel,24c02", .data = 3 }, | 	{ .compatible = "atmel,24c02", (ulong)&atmel24c02_data }, | ||||||
| 	{ .compatible = "atmel,24c04", .data = 4 }, | 	{ .compatible = "atmel,24c04", (ulong)&atmel24c04_data }, | ||||||
| 	{ .compatible = "atmel,24c08", .data = 4 }, | 	{ .compatible = "atmel,24c08", (ulong)&atmel24c08_data }, | ||||||
| 	{ .compatible = "atmel,24c08a", .data = 4 }, | 	{ .compatible = "atmel,24c08a", (ulong)&atmel24c08a_data }, | ||||||
| 	{ .compatible = "atmel,24c16a", .data = 4 }, | 	{ .compatible = "atmel,24c16a", (ulong)&atmel24c16a_data }, | ||||||
| 	{ .compatible = "atmel,24mac402", .data = 4 }, | 	{ .compatible = "atmel,24mac402", (ulong)&atmel24mac402_data }, | ||||||
| 	{ .compatible = "atmel,24c32", .data = 5 }, | 	{ .compatible = "atmel,24c32", (ulong)&atmel24c32_data }, | ||||||
| 	{ .compatible = "atmel,24c64", .data = 5 }, | 	{ .compatible = "atmel,24c64", (ulong)&atmel24c64_data }, | ||||||
| 	{ .compatible = "atmel,24c128", .data = 6 }, | 	{ .compatible = "atmel,24c128", (ulong)&atmel24c128_data }, | ||||||
| 	{ .compatible = "atmel,24c256", .data = 6 }, | 	{ .compatible = "atmel,24c256", (ulong)&atmel24c256_data }, | ||||||
| 	{ .compatible = "atmel,24c512", .data = 6 }, | 	{ .compatible = "atmel,24c512", (ulong)&atmel24c512_data }, | ||||||
| 	{ } | 	{ } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -118,12 +241,94 @@ U_BOOT_DRIVER(i2c_eeprom_std) = { | ||||||
| 	.name			= "i2c_eeprom", | 	.name			= "i2c_eeprom", | ||||||
| 	.id			= UCLASS_I2C_EEPROM, | 	.id			= UCLASS_I2C_EEPROM, | ||||||
| 	.of_match		= i2c_eeprom_std_ids, | 	.of_match		= i2c_eeprom_std_ids, | ||||||
|  | 	.bind			= i2c_eeprom_std_bind, | ||||||
| 	.probe			= i2c_eeprom_std_probe, | 	.probe			= i2c_eeprom_std_probe, | ||||||
| 	.ofdata_to_platdata	= i2c_eeprom_std_ofdata_to_platdata, | 	.ofdata_to_platdata	= i2c_eeprom_std_ofdata_to_platdata, | ||||||
| 	.priv_auto_alloc_size	= sizeof(struct i2c_eeprom), | 	.priv_auto_alloc_size	= sizeof(struct i2c_eeprom), | ||||||
| 	.ops			= &i2c_eeprom_std_ops, | 	.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) = { | UCLASS_DRIVER(i2c_eeprom) = { | ||||||
| 	.id		= UCLASS_I2C_EEPROM, | 	.id		= UCLASS_I2C_EEPROM, | ||||||
| 	.name		= "i2c_eeprom", | 	.name		= "i2c_eeprom", | ||||||
|  |  | ||||||
|  | @ -23,10 +23,13 @@ struct sandbox_i2c_flash_plat_data { | ||||||
| 	const char *filename; | 	const char *filename; | ||||||
| 	int offset_len;		/* Length of an offset in bytes */ | 	int offset_len;		/* Length of an offset in bytes */ | ||||||
| 	int size;		/* Size of data buffer */ | 	int size;		/* Size of data buffer */ | ||||||
|  | 	uint chip_addr_offset_mask; /* mask of addr bits used for offset */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct sandbox_i2c_flash { | struct sandbox_i2c_flash { | ||||||
| 	uint8_t *data; | 	uint8_t *data; | ||||||
|  | 	uint prev_addr;		/* slave address of previous access */ | ||||||
|  | 	uint prev_offset;	/* offset of previous access */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void sandbox_i2c_eeprom_set_test_mode(struct udevice *dev, | void sandbox_i2c_eeprom_set_test_mode(struct udevice *dev, | ||||||
|  | @ -44,36 +47,65 @@ void sandbox_i2c_eeprom_set_offset_len(struct udevice *dev, int offset_len) | ||||||
| 	plat->offset_len = offset_len; | 	plat->offset_len = offset_len; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void sandbox_i2c_eeprom_set_chip_addr_offset_mask(struct udevice *dev, | ||||||
|  | 						  uint mask) | ||||||
|  | { | ||||||
|  | 	struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev); | ||||||
|  | 
 | ||||||
|  | 	plat->chip_addr_offset_mask = mask; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint sanbox_i2c_eeprom_get_prev_addr(struct udevice *dev) | ||||||
|  | { | ||||||
|  | 	struct sandbox_i2c_flash *priv = dev_get_priv(dev); | ||||||
|  | 
 | ||||||
|  | 	return priv->prev_addr; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint sanbox_i2c_eeprom_get_prev_offset(struct udevice *dev) | ||||||
|  | { | ||||||
|  | 	struct sandbox_i2c_flash *priv = dev_get_priv(dev); | ||||||
|  | 
 | ||||||
|  | 	return priv->prev_offset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int sandbox_i2c_eeprom_xfer(struct udevice *emul, struct i2c_msg *msg, | static int sandbox_i2c_eeprom_xfer(struct udevice *emul, struct i2c_msg *msg, | ||||||
| 				  int nmsgs) | 				  int nmsgs) | ||||||
| { | { | ||||||
| 	struct sandbox_i2c_flash *priv = dev_get_priv(emul); | 	struct sandbox_i2c_flash *priv = dev_get_priv(emul); | ||||||
| 	uint offset = 0; | 	struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(emul); | ||||||
|  | 	uint offset = msg->addr & plat->chip_addr_offset_mask; | ||||||
| 
 | 
 | ||||||
| 	debug("\n%s\n", __func__); | 	debug("\n%s\n", __func__); | ||||||
| 	debug_buffer(0, priv->data, 1, 16, 0); | 	debug_buffer(0, priv->data, 1, 16, 0); | ||||||
|  | 
 | ||||||
|  | 	/* store addr for testing visibity */ | ||||||
|  | 	priv->prev_addr = msg->addr; | ||||||
|  | 
 | ||||||
| 	for (; nmsgs > 0; nmsgs--, msg++) { | 	for (; nmsgs > 0; nmsgs--, msg++) { | ||||||
| 		struct sandbox_i2c_flash_plat_data *plat = |  | ||||||
| 				dev_get_platdata(emul); |  | ||||||
| 		int len; | 		int len; | ||||||
| 		u8 *ptr; | 		u8 *ptr; | ||||||
| 
 | 
 | ||||||
| 		if (!plat->size) | 		if (!plat->size) | ||||||
| 			return -ENODEV; | 			return -ENODEV; | ||||||
| 		if (msg->addr + msg->len > plat->size) { |  | ||||||
| 			debug("%s: Address %x, len %x is outside range 0..%x\n", |  | ||||||
| 			      __func__, msg->addr, msg->len, plat->size); |  | ||||||
| 			return -EINVAL; |  | ||||||
| 		} |  | ||||||
| 		len = msg->len; | 		len = msg->len; | ||||||
| 		debug("   %s: msg->len=%d", | 		debug("   %s: msg->addr=%x msg->len=%d", | ||||||
| 		      msg->flags & I2C_M_RD ? "read" : "write", | 		      msg->flags & I2C_M_RD ? "read" : "write", | ||||||
| 		      msg->len); | 		      msg->addr, msg->len); | ||||||
| 		if (msg->flags & I2C_M_RD) { | 		if (msg->flags & I2C_M_RD) { | ||||||
| 			if (plat->test_mode == SIE_TEST_MODE_SINGLE_BYTE) | 			if (plat->test_mode == SIE_TEST_MODE_SINGLE_BYTE) | ||||||
| 				len = 1; | 				len = 1; | ||||||
| 			debug(", offset %x, len %x: ", offset, len); | 			debug(", offset %x, len %x: ", offset, len); | ||||||
|  | 			if (offset + len > plat->size) { | ||||||
|  | 				int overflow = offset + len - plat->size; | ||||||
|  | 				int initial = len - overflow; | ||||||
|  | 
 | ||||||
|  | 				memcpy(msg->buf, priv->data + offset, initial); | ||||||
|  | 				memcpy(msg->buf + initial, priv->data, | ||||||
|  | 				       overflow); | ||||||
|  | 			} else { | ||||||
| 				memcpy(msg->buf, priv->data + offset, len); | 				memcpy(msg->buf, priv->data + offset, len); | ||||||
|  | 			} | ||||||
| 			memset(msg->buf + len, '\xff', msg->len - len); | 			memset(msg->buf + len, '\xff', msg->len - len); | ||||||
| 			debug_buffer(0, msg->buf, 1, msg->len, 0); | 			debug_buffer(0, msg->buf, 1, msg->len, 0); | ||||||
| 		} else if (len >= plat->offset_len) { | 		} else if (len >= plat->offset_len) { | ||||||
|  | @ -87,17 +119,26 @@ static int sandbox_i2c_eeprom_xfer(struct udevice *emul, struct i2c_msg *msg, | ||||||
| 			if (plat->test_mode == SIE_TEST_MODE_SINGLE_BYTE) | 			if (plat->test_mode == SIE_TEST_MODE_SINGLE_BYTE) | ||||||
| 				len = min(len, 1); | 				len = min(len, 1); | ||||||
| 
 | 
 | ||||||
| 			/* For testing, map offsets into our limited buffer */ | 			/* store offset for testing visibility */ | ||||||
| 			for (i = 24; i > 0; i -= 8) { | 			priv->prev_offset = offset; | ||||||
| 				if (offset > (1 << i)) { | 
 | ||||||
| 					offset = (offset >> i) | | 			/* For testing, map offsets into our limited buffer.
 | ||||||
| 						(offset & ((1 << i) - 1)); | 			 * offset wraps every 256 bytes | ||||||
| 					offset += i; | 			 */ | ||||||
| 				} | 			offset &= 0xff; | ||||||
| 			} | 			debug("mapped offset to %x\n", offset); | ||||||
|  | 
 | ||||||
|  | 			if (offset + len > plat->size) { | ||||||
|  | 				int overflow = offset + len - plat->size; | ||||||
|  | 				int initial = len - overflow; | ||||||
|  | 
 | ||||||
|  | 				memcpy(priv->data + offset, ptr, initial); | ||||||
|  | 				memcpy(priv->data, ptr + initial, overflow); | ||||||
|  | 			} else { | ||||||
| 				memcpy(priv->data + offset, ptr, len); | 				memcpy(priv->data + offset, ptr, len); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| 	debug_buffer(0, priv->data, 1, 16, 0); | 	debug_buffer(0, priv->data, 1, 16, 0); | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  | @ -120,6 +161,7 @@ static int sandbox_i2c_eeprom_ofdata_to_platdata(struct udevice *dev) | ||||||
| 	} | 	} | ||||||
| 	plat->test_mode = SIE_TEST_MODE_NONE; | 	plat->test_mode = SIE_TEST_MODE_NONE; | ||||||
| 	plat->offset_len = 1; | 	plat->offset_len = 1; | ||||||
|  | 	plat->chip_addr_offset_mask = 0; | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -45,12 +45,26 @@ struct udevice; | ||||||
|  *		represent up to 256 bytes. A value larger than 1 may be |  *		represent up to 256 bytes. A value larger than 1 may be | ||||||
|  *		needed for larger devices. |  *		needed for larger devices. | ||||||
|  * @flags:	Flags for this chip (dm_i2c_chip_flags) |  * @flags:	Flags for this chip (dm_i2c_chip_flags) | ||||||
|  |  * @chip_addr_offset_mask: Mask of offset bits within chip_addr. Used for | ||||||
|  |  *			   devices which steal addresses as part of offset. | ||||||
|  |  *			   If offset_len is zero, then the offset is encoded | ||||||
|  |  *			   completely within the chip address itself. | ||||||
|  |  *			   e.g. a devce with chip address of 0x2c with 512 | ||||||
|  |  *			   registers might use the bottom bit of the address | ||||||
|  |  *			   to indicate which half of the address space is being | ||||||
|  |  *			   accessed while still only using 1 byte offset. | ||||||
|  |  *			   This means it will respond to  chip address 0x2c and | ||||||
|  |  *			   0x2d. | ||||||
|  |  *			   A real world example is the Atmel AT24C04. It's | ||||||
|  |  *			   datasheet explains it's usage of this addressing | ||||||
|  |  *			   mode. | ||||||
|  * @emul: Emulator for this chip address (only used for emulation) |  * @emul: Emulator for this chip address (only used for emulation) | ||||||
|  */ |  */ | ||||||
| struct dm_i2c_chip { | struct dm_i2c_chip { | ||||||
| 	uint chip_addr; | 	uint chip_addr; | ||||||
| 	uint offset_len; | 	uint offset_len; | ||||||
| 	uint flags; | 	uint flags; | ||||||
|  | 	uint chip_addr_offset_mask; | ||||||
| #ifdef CONFIG_SANDBOX | #ifdef CONFIG_SANDBOX | ||||||
| 	struct udevice *emul; | 	struct udevice *emul; | ||||||
| 	bool test_mode; | 	bool test_mode; | ||||||
|  | @ -261,6 +275,25 @@ int i2c_set_chip_offset_len(struct udevice *dev, uint offset_len); | ||||||
|  */ |  */ | ||||||
| int i2c_get_chip_offset_len(struct udevice *dev); | int i2c_get_chip_offset_len(struct udevice *dev); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * i2c_set_chip_addr_offset_mask() - set mask of address bits usable by offset | ||||||
|  |  * | ||||||
|  |  * Some devices listen on multiple chip addresses to achieve larger offsets | ||||||
|  |  * than their single or multiple byte offsets would allow for. You can use this | ||||||
|  |  * function to set the bits that are valid to be used for offset overflow. | ||||||
|  |  * | ||||||
|  |  * @mask: The mask to be used for high offset bits within address | ||||||
|  |  * @return 0 if OK, other -ve value on error | ||||||
|  |  */ | ||||||
|  | int i2c_set_chip_addr_offset_mask(struct udevice *dev, uint mask); | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * i2c_get_chip_addr_offset_mask() - get mask of address bits usable by offset | ||||||
|  |  * | ||||||
|  |  * @return current chip addr offset mask | ||||||
|  |  */ | ||||||
|  | uint i2c_get_chip_addr_offset_mask(struct udevice *dev); | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * i2c_deblock() - recover a bus that is in an unknown state |  * i2c_deblock() - recover a bus that is in an unknown state | ||||||
|  * |  * | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ struct i2c_eeprom_ops { | ||||||
| 	int (*read)(struct udevice *dev, int offset, uint8_t *buf, int size); | 	int (*read)(struct udevice *dev, int offset, uint8_t *buf, int size); | ||||||
| 	int (*write)(struct udevice *dev, int offset, const uint8_t *buf, | 	int (*write)(struct udevice *dev, int offset, const uint8_t *buf, | ||||||
| 		     int size); | 		     int size); | ||||||
|  | 	int (*size)(struct udevice *dev); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct i2c_eeprom { | struct i2c_eeprom { | ||||||
|  | @ -17,6 +18,8 @@ struct i2c_eeprom { | ||||||
| 	unsigned long pagesize; | 	unsigned long pagesize; | ||||||
| 	/* The EEPROM's page width in bits (pagesize = 2^pagewidth) */ | 	/* The EEPROM's page width in bits (pagesize = 2^pagewidth) */ | ||||||
| 	unsigned pagewidth; | 	unsigned pagewidth; | ||||||
|  | 	/* The EEPROM's capacity in bytes */ | ||||||
|  | 	unsigned long size; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | @ -43,4 +46,13 @@ int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf, int size); | ||||||
|  */ |  */ | ||||||
| int i2c_eeprom_write(struct udevice *dev, int offset, uint8_t *buf, int size); | int i2c_eeprom_write(struct udevice *dev, int offset, uint8_t *buf, int size); | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * i2c_eeprom_size() - get size of I2C EEPROM chip | ||||||
|  |  * | ||||||
|  |  * @dev:	Chip to query | ||||||
|  |  * | ||||||
|  |  * @return +ve size in bytes on success, -ve on failure | ||||||
|  |  */ | ||||||
|  | int i2c_eeprom_size(struct udevice *dev); | ||||||
|  | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
							
								
								
									
										115
									
								
								test/dm/i2c.c
								
								
								
								
							
							
						
						
									
										115
									
								
								test/dm/i2c.c
								
								
								
								
							|  | @ -15,6 +15,7 @@ | ||||||
| #include <dm/test.h> | #include <dm/test.h> | ||||||
| #include <dm/uclass-internal.h> | #include <dm/uclass-internal.h> | ||||||
| #include <dm/util.h> | #include <dm/util.h> | ||||||
|  | #include <hexdump.h> | ||||||
| #include <test/ut.h> | #include <test/ut.h> | ||||||
| 
 | 
 | ||||||
| static const int busnum; | static const int busnum; | ||||||
|  | @ -185,35 +186,54 @@ static int dm_test_i2c_offset(struct unit_test_state *uts) | ||||||
| 	ut_assertok(i2c_set_chip_offset_len(dev, 0)); | 	ut_assertok(i2c_set_chip_offset_len(dev, 0)); | ||||||
| 	ut_assertok(dm_i2c_write(dev, 10 /* ignored */, (uint8_t *)"AB", 2)); | 	ut_assertok(dm_i2c_write(dev, 10 /* ignored */, (uint8_t *)"AB", 2)); | ||||||
| 	ut_assertok(dm_i2c_read(dev, 0, buf, 5)); | 	ut_assertok(dm_i2c_read(dev, 0, buf, 5)); | ||||||
| 	ut_assertok(memcmp(buf, "AB\0\0\0\0", sizeof(buf))); | 	ut_asserteq_mem("AB\0\0\0\0", buf, sizeof(buf)); | ||||||
|  | 	ut_asserteq(0, sanbox_i2c_eeprom_get_prev_offset(eeprom)); | ||||||
| 
 | 
 | ||||||
| 	/* Offset length 1 */ | 	/* Offset length 1 */ | ||||||
| 	sandbox_i2c_eeprom_set_offset_len(eeprom, 1); | 	sandbox_i2c_eeprom_set_offset_len(eeprom, 1); | ||||||
| 	ut_assertok(i2c_set_chip_offset_len(dev, 1)); | 	ut_assertok(i2c_set_chip_offset_len(dev, 1)); | ||||||
| 	ut_assertok(dm_i2c_write(dev, 2, (uint8_t *)"AB", 2)); | 	ut_assertok(dm_i2c_write(dev, 2, (uint8_t *)"AB", 2)); | ||||||
|  | 	ut_asserteq(2, sanbox_i2c_eeprom_get_prev_offset(eeprom)); | ||||||
| 	ut_assertok(dm_i2c_read(dev, 0, buf, 5)); | 	ut_assertok(dm_i2c_read(dev, 0, buf, 5)); | ||||||
| 	ut_assertok(memcmp(buf, "ABAB\0", sizeof(buf))); | 	ut_asserteq_mem("ABAB\0", buf, sizeof(buf)); | ||||||
|  | 	ut_asserteq(0, sanbox_i2c_eeprom_get_prev_offset(eeprom)); | ||||||
|  | 
 | ||||||
|  | 	/* Offset length 2 boundary - check model wrapping */ | ||||||
|  | 	sandbox_i2c_eeprom_set_offset_len(eeprom, 2); | ||||||
|  | 	ut_assertok(i2c_set_chip_offset_len(dev, 2)); | ||||||
|  | 	ut_assertok(dm_i2c_write(dev, 0xFF, (uint8_t *)"A", 1)); | ||||||
|  | 	ut_asserteq(0xFF, sanbox_i2c_eeprom_get_prev_offset(eeprom)); | ||||||
|  | 	ut_assertok(dm_i2c_write(dev, 0x100, (uint8_t *)"B", 1)); | ||||||
|  | 	ut_asserteq(0x100, sanbox_i2c_eeprom_get_prev_offset(eeprom)); | ||||||
|  | 	ut_assertok(dm_i2c_write(dev, 0x101, (uint8_t *)"C", 1)); | ||||||
|  | 	ut_asserteq(0x101, sanbox_i2c_eeprom_get_prev_offset(eeprom)); | ||||||
|  | 	ut_assertok(dm_i2c_read(dev, 0xFF, buf, 5)); | ||||||
|  | 	ut_asserteq_mem("ABCAB", buf, sizeof(buf)); | ||||||
|  | 	ut_asserteq(0xFF, sanbox_i2c_eeprom_get_prev_offset(eeprom)); | ||||||
| 
 | 
 | ||||||
| 	/* Offset length 2 */ | 	/* Offset length 2 */ | ||||||
| 	sandbox_i2c_eeprom_set_offset_len(eeprom, 2); | 	sandbox_i2c_eeprom_set_offset_len(eeprom, 2); | ||||||
| 	ut_assertok(i2c_set_chip_offset_len(dev, 2)); | 	ut_assertok(i2c_set_chip_offset_len(dev, 2)); | ||||||
| 	ut_assertok(dm_i2c_write(dev, 0x210, (uint8_t *)"AB", 2)); | 	ut_assertok(dm_i2c_write(dev, 0x2020, (uint8_t *)"AB", 2)); | ||||||
| 	ut_assertok(dm_i2c_read(dev, 0x210, buf, 5)); | 	ut_assertok(dm_i2c_read(dev, 0x2020, buf, 5)); | ||||||
| 	ut_assertok(memcmp(buf, "AB\0\0\0", sizeof(buf))); | 	ut_asserteq_mem("AB\0\0\0", buf, sizeof(buf)); | ||||||
|  | 	ut_asserteq(0x2020, sanbox_i2c_eeprom_get_prev_offset(eeprom)); | ||||||
| 
 | 
 | ||||||
| 	/* Offset length 3 */ | 	/* Offset length 3 */ | ||||||
| 	sandbox_i2c_eeprom_set_offset_len(eeprom, 2); | 	sandbox_i2c_eeprom_set_offset_len(eeprom, 3); | ||||||
| 	ut_assertok(i2c_set_chip_offset_len(dev, 2)); | 	ut_assertok(i2c_set_chip_offset_len(dev, 3)); | ||||||
| 	ut_assertok(dm_i2c_write(dev, 0x410, (uint8_t *)"AB", 2)); | 	ut_assertok(dm_i2c_write(dev, 0x303030, (uint8_t *)"AB", 2)); | ||||||
| 	ut_assertok(dm_i2c_read(dev, 0x410, buf, 5)); | 	ut_assertok(dm_i2c_read(dev, 0x303030, buf, 5)); | ||||||
| 	ut_assertok(memcmp(buf, "AB\0\0\0", sizeof(buf))); | 	ut_asserteq_mem("AB\0\0\0", buf, sizeof(buf)); | ||||||
|  | 	ut_asserteq(0x303030, sanbox_i2c_eeprom_get_prev_offset(eeprom)); | ||||||
| 
 | 
 | ||||||
| 	/* Offset length 4 */ | 	/* Offset length 4 */ | ||||||
| 	sandbox_i2c_eeprom_set_offset_len(eeprom, 2); | 	sandbox_i2c_eeprom_set_offset_len(eeprom, 4); | ||||||
| 	ut_assertok(i2c_set_chip_offset_len(dev, 2)); | 	ut_assertok(i2c_set_chip_offset_len(dev, 4)); | ||||||
| 	ut_assertok(dm_i2c_write(dev, 0x420, (uint8_t *)"AB", 2)); | 	ut_assertok(dm_i2c_write(dev, 0x40404040, (uint8_t *)"AB", 2)); | ||||||
| 	ut_assertok(dm_i2c_read(dev, 0x420, buf, 5)); | 	ut_assertok(dm_i2c_read(dev, 0x40404040, buf, 5)); | ||||||
| 	ut_assertok(memcmp(buf, "AB\0\0\0", sizeof(buf))); | 	ut_asserteq_mem("AB\0\0\0", buf, sizeof(buf)); | ||||||
|  | 	ut_asserteq(0x40404040, sanbox_i2c_eeprom_get_prev_offset(eeprom)); | ||||||
| 
 | 
 | ||||||
| 	/* Restore defaults */ | 	/* Restore defaults */ | ||||||
| 	sandbox_i2c_eeprom_set_offset_len(eeprom, 1); | 	sandbox_i2c_eeprom_set_offset_len(eeprom, 1); | ||||||
|  | @ -221,3 +241,68 @@ static int dm_test_i2c_offset(struct unit_test_state *uts) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| DM_TEST(dm_test_i2c_offset, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); | DM_TEST(dm_test_i2c_offset, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); | ||||||
|  | 
 | ||||||
|  | static int dm_test_i2c_addr_offset(struct unit_test_state *uts) | ||||||
|  | { | ||||||
|  | 	struct udevice *eeprom; | ||||||
|  | 	struct udevice *dev; | ||||||
|  | 	u8 buf[5]; | ||||||
|  | 
 | ||||||
|  | 	ut_assertok(i2c_get_chip_for_busnum(busnum, chip, 1, &dev)); | ||||||
|  | 
 | ||||||
|  | 	/* Do a transfer so we can find the emulator */ | ||||||
|  | 	ut_assertok(dm_i2c_read(dev, 0, buf, 5)); | ||||||
|  | 	ut_assertok(uclass_first_device(UCLASS_I2C_EMUL, &eeprom)); | ||||||
|  | 
 | ||||||
|  | 	/* Offset length 0 */ | ||||||
|  | 	sandbox_i2c_eeprom_set_offset_len(eeprom, 0); | ||||||
|  | 	sandbox_i2c_eeprom_set_chip_addr_offset_mask(eeprom, 0x3); | ||||||
|  | 	ut_assertok(i2c_set_chip_offset_len(dev, 0)); | ||||||
|  | 	ut_assertok(i2c_set_chip_addr_offset_mask(dev, 0x3)); | ||||||
|  | 	ut_assertok(dm_i2c_write(dev, 0x3, (uint8_t *)"AB", 2)); | ||||||
|  | 	ut_assertok(dm_i2c_read(dev, 0x3, buf, 5)); | ||||||
|  | 	ut_asserteq_mem("AB\0\0\0\0", buf, sizeof(buf)); | ||||||
|  | 	ut_asserteq(0x3, sanbox_i2c_eeprom_get_prev_offset(eeprom)); | ||||||
|  | 	ut_asserteq(chip | 0x3, sanbox_i2c_eeprom_get_prev_addr(eeprom)); | ||||||
|  | 
 | ||||||
|  | 	/* Offset length 1 */ | ||||||
|  | 	sandbox_i2c_eeprom_set_offset_len(eeprom, 1); | ||||||
|  | 	sandbox_i2c_eeprom_set_chip_addr_offset_mask(eeprom, 0x3); | ||||||
|  | 	ut_assertok(i2c_set_chip_offset_len(dev, 1)); | ||||||
|  | 	ut_assertok(i2c_set_chip_addr_offset_mask(dev, 0x3)); | ||||||
|  | 	ut_assertok(dm_i2c_write(dev, 0x310, (uint8_t *)"AB", 2)); | ||||||
|  | 	ut_assertok(dm_i2c_read(dev, 0x310, buf, 5)); | ||||||
|  | 	ut_asserteq_mem("AB\0\0\0\0", buf, sizeof(buf)); | ||||||
|  | 	ut_asserteq(0x310, sanbox_i2c_eeprom_get_prev_offset(eeprom)); | ||||||
|  | 	ut_asserteq(chip | 0x3, sanbox_i2c_eeprom_get_prev_addr(eeprom)); | ||||||
|  | 
 | ||||||
|  | 	/* Offset length 2 */ | ||||||
|  | 	sandbox_i2c_eeprom_set_offset_len(eeprom, 2); | ||||||
|  | 	sandbox_i2c_eeprom_set_chip_addr_offset_mask(eeprom, 0x3); | ||||||
|  | 	ut_assertok(i2c_set_chip_offset_len(dev, 2)); | ||||||
|  | 	ut_assertok(i2c_set_chip_addr_offset_mask(dev, 0x3)); | ||||||
|  | 	ut_assertok(dm_i2c_write(dev, 0x32020, (uint8_t *)"AB", 2)); | ||||||
|  | 	ut_assertok(dm_i2c_read(dev, 0x32020, buf, 5)); | ||||||
|  | 	ut_asserteq_mem("AB\0\0\0\0", buf, sizeof(buf)); | ||||||
|  | 	ut_asserteq(0x32020, sanbox_i2c_eeprom_get_prev_offset(eeprom)); | ||||||
|  | 	ut_asserteq(chip | 0x3, sanbox_i2c_eeprom_get_prev_addr(eeprom)); | ||||||
|  | 
 | ||||||
|  | 	/* Offset length 3 */ | ||||||
|  | 	sandbox_i2c_eeprom_set_offset_len(eeprom, 3); | ||||||
|  | 	sandbox_i2c_eeprom_set_chip_addr_offset_mask(eeprom, 0x3); | ||||||
|  | 	ut_assertok(i2c_set_chip_offset_len(dev, 3)); | ||||||
|  | 	ut_assertok(i2c_set_chip_addr_offset_mask(dev, 0x3)); | ||||||
|  | 	ut_assertok(dm_i2c_write(dev, 0x3303030, (uint8_t *)"AB", 2)); | ||||||
|  | 	ut_assertok(dm_i2c_read(dev, 0x3303030, buf, 5)); | ||||||
|  | 	ut_asserteq_mem("AB\0\0\0\0", buf, sizeof(buf)); | ||||||
|  | 	ut_asserteq(0x3303030, sanbox_i2c_eeprom_get_prev_offset(eeprom)); | ||||||
|  | 	ut_asserteq(chip | 0x3, sanbox_i2c_eeprom_get_prev_addr(eeprom)); | ||||||
|  | 
 | ||||||
|  | 	/* Restore defaults */ | ||||||
|  | 	sandbox_i2c_eeprom_set_offset_len(eeprom, 1); | ||||||
|  | 	sandbox_i2c_eeprom_set_chip_addr_offset_mask(eeprom, 0); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | DM_TEST(dm_test_i2c_addr_offset, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue