xref: /rk3399_rockchip-uboot/drivers/misc/i2c_eeprom_emul.c (revision 6ec1b7535873dee4c73895e430494e12be4e3e4d)
1*6ec1b753SSimon Glass /*
2*6ec1b753SSimon Glass  * Simulate an I2C eeprom
3*6ec1b753SSimon Glass  *
4*6ec1b753SSimon Glass  * Copyright (c) 2014 Google, Inc
5*6ec1b753SSimon Glass  *
6*6ec1b753SSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
7*6ec1b753SSimon Glass  */
8*6ec1b753SSimon Glass 
9*6ec1b753SSimon Glass #include <common.h>
10*6ec1b753SSimon Glass #include <dm.h>
11*6ec1b753SSimon Glass #include <fdtdec.h>
12*6ec1b753SSimon Glass #include <i2c.h>
13*6ec1b753SSimon Glass #include <malloc.h>
14*6ec1b753SSimon Glass #include <asm/test.h>
15*6ec1b753SSimon Glass 
16*6ec1b753SSimon Glass #ifdef DEBUG
17*6ec1b753SSimon Glass #define debug_buffer print_buffer
18*6ec1b753SSimon Glass #else
19*6ec1b753SSimon Glass #define debug_buffer(x, ...)
20*6ec1b753SSimon Glass #endif
21*6ec1b753SSimon Glass 
22*6ec1b753SSimon Glass DECLARE_GLOBAL_DATA_PTR;
23*6ec1b753SSimon Glass 
24*6ec1b753SSimon Glass struct sandbox_i2c_flash_plat_data {
25*6ec1b753SSimon Glass 	enum sandbox_i2c_eeprom_test_mode test_mode;
26*6ec1b753SSimon Glass 	const char *filename;
27*6ec1b753SSimon Glass 	int offset_len;		/* Length of an offset in bytes */
28*6ec1b753SSimon Glass 	int size;		/* Size of data buffer */
29*6ec1b753SSimon Glass };
30*6ec1b753SSimon Glass 
31*6ec1b753SSimon Glass struct sandbox_i2c_flash {
32*6ec1b753SSimon Glass 	uint8_t *data;
33*6ec1b753SSimon Glass };
34*6ec1b753SSimon Glass 
35*6ec1b753SSimon Glass void sandbox_i2c_eeprom_set_test_mode(struct udevice *dev,
36*6ec1b753SSimon Glass 				      enum sandbox_i2c_eeprom_test_mode mode)
37*6ec1b753SSimon Glass {
38*6ec1b753SSimon Glass 	struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
39*6ec1b753SSimon Glass 
40*6ec1b753SSimon Glass 	plat->test_mode = mode;
41*6ec1b753SSimon Glass }
42*6ec1b753SSimon Glass 
43*6ec1b753SSimon Glass void sandbox_i2c_eeprom_set_offset_len(struct udevice *dev, int offset_len)
44*6ec1b753SSimon Glass {
45*6ec1b753SSimon Glass 	struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
46*6ec1b753SSimon Glass 
47*6ec1b753SSimon Glass 	plat->offset_len = offset_len;
48*6ec1b753SSimon Glass }
49*6ec1b753SSimon Glass 
50*6ec1b753SSimon Glass static int sandbox_i2c_eeprom_xfer(struct udevice *emul, struct i2c_msg *msg,
51*6ec1b753SSimon Glass 				  int nmsgs)
52*6ec1b753SSimon Glass {
53*6ec1b753SSimon Glass 	struct sandbox_i2c_flash *priv = dev_get_priv(emul);
54*6ec1b753SSimon Glass 	uint offset = 0;
55*6ec1b753SSimon Glass 
56*6ec1b753SSimon Glass 	debug("\n%s\n", __func__);
57*6ec1b753SSimon Glass 	debug_buffer(0, priv->data, 1, 16, 0);
58*6ec1b753SSimon Glass 	for (; nmsgs > 0; nmsgs--, msg++) {
59*6ec1b753SSimon Glass 		struct sandbox_i2c_flash_plat_data *plat =
60*6ec1b753SSimon Glass 				dev_get_platdata(emul);
61*6ec1b753SSimon Glass 		int len;
62*6ec1b753SSimon Glass 		u8 *ptr;
63*6ec1b753SSimon Glass 
64*6ec1b753SSimon Glass 		if (!plat->size)
65*6ec1b753SSimon Glass 			return -ENODEV;
66*6ec1b753SSimon Glass 		if (msg->addr + msg->len > plat->size) {
67*6ec1b753SSimon Glass 			debug("%s: Address %x, len %x is outside range 0..%x\n",
68*6ec1b753SSimon Glass 			      __func__, msg->addr, msg->len, plat->size);
69*6ec1b753SSimon Glass 			return -EINVAL;
70*6ec1b753SSimon Glass 		}
71*6ec1b753SSimon Glass 		len = msg->len;
72*6ec1b753SSimon Glass 		debug("   %s: msg->len=%d",
73*6ec1b753SSimon Glass 		      msg->flags & I2C_M_RD ? "read" : "write",
74*6ec1b753SSimon Glass 		      msg->len);
75*6ec1b753SSimon Glass 		if (msg->flags & I2C_M_RD) {
76*6ec1b753SSimon Glass 			if (plat->test_mode == SIE_TEST_MODE_SINGLE_BYTE)
77*6ec1b753SSimon Glass 				len = 1;
78*6ec1b753SSimon Glass 			debug(", offset %x, len %x: ", offset, len);
79*6ec1b753SSimon Glass 			memcpy(msg->buf, priv->data + offset, len);
80*6ec1b753SSimon Glass 			memset(msg->buf + len, '\xff', msg->len - len);
81*6ec1b753SSimon Glass 			debug_buffer(0, msg->buf, 1, msg->len, 0);
82*6ec1b753SSimon Glass 		} else if (len >= plat->offset_len) {
83*6ec1b753SSimon Glass 			int i;
84*6ec1b753SSimon Glass 
85*6ec1b753SSimon Glass 			ptr = msg->buf;
86*6ec1b753SSimon Glass 			for (i = 0; i < plat->offset_len; i++, len--)
87*6ec1b753SSimon Glass 				offset = (offset << 8) | *ptr++;
88*6ec1b753SSimon Glass 			debug(", set offset %x: ", offset);
89*6ec1b753SSimon Glass 			debug_buffer(0, msg->buf, 1, msg->len, 0);
90*6ec1b753SSimon Glass 			if (plat->test_mode == SIE_TEST_MODE_SINGLE_BYTE)
91*6ec1b753SSimon Glass 				len = min(len, 1);
92*6ec1b753SSimon Glass 
93*6ec1b753SSimon Glass 			/* For testing, map offsets into our limited buffer */
94*6ec1b753SSimon Glass 			for (i = 24; i > 0; i -= 8) {
95*6ec1b753SSimon Glass 				if (offset > (1 << i)) {
96*6ec1b753SSimon Glass 					offset = (offset >> i) |
97*6ec1b753SSimon Glass 						(offset & ((1 << i) - 1));
98*6ec1b753SSimon Glass 					offset += i;
99*6ec1b753SSimon Glass 				}
100*6ec1b753SSimon Glass 			}
101*6ec1b753SSimon Glass 			memcpy(priv->data + offset, ptr, len);
102*6ec1b753SSimon Glass 		}
103*6ec1b753SSimon Glass 	}
104*6ec1b753SSimon Glass 	debug_buffer(0, priv->data, 1, 16, 0);
105*6ec1b753SSimon Glass 
106*6ec1b753SSimon Glass 	return 0;
107*6ec1b753SSimon Glass }
108*6ec1b753SSimon Glass 
109*6ec1b753SSimon Glass struct dm_i2c_ops sandbox_i2c_emul_ops = {
110*6ec1b753SSimon Glass 	.xfer = sandbox_i2c_eeprom_xfer,
111*6ec1b753SSimon Glass };
112*6ec1b753SSimon Glass 
113*6ec1b753SSimon Glass static int sandbox_i2c_eeprom_ofdata_to_platdata(struct udevice *dev)
114*6ec1b753SSimon Glass {
115*6ec1b753SSimon Glass 	struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
116*6ec1b753SSimon Glass 
117*6ec1b753SSimon Glass 	plat->size = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
118*6ec1b753SSimon Glass 				    "sandbox,size", 32);
119*6ec1b753SSimon Glass 	plat->filename = fdt_getprop(gd->fdt_blob, dev->of_offset,
120*6ec1b753SSimon Glass 				     "sandbox,filename", NULL);
121*6ec1b753SSimon Glass 	if (!plat->filename) {
122*6ec1b753SSimon Glass 		debug("%s: No filename for device '%s'\n", __func__,
123*6ec1b753SSimon Glass 		      dev->name);
124*6ec1b753SSimon Glass 		return -EINVAL;
125*6ec1b753SSimon Glass 	}
126*6ec1b753SSimon Glass 	plat->test_mode = SIE_TEST_MODE_NONE;
127*6ec1b753SSimon Glass 	plat->offset_len = 1;
128*6ec1b753SSimon Glass 
129*6ec1b753SSimon Glass 	return 0;
130*6ec1b753SSimon Glass }
131*6ec1b753SSimon Glass 
132*6ec1b753SSimon Glass static int sandbox_i2c_eeprom_probe(struct udevice *dev)
133*6ec1b753SSimon Glass {
134*6ec1b753SSimon Glass 	struct sandbox_i2c_flash_plat_data *plat = dev_get_platdata(dev);
135*6ec1b753SSimon Glass 	struct sandbox_i2c_flash *priv = dev_get_priv(dev);
136*6ec1b753SSimon Glass 
137*6ec1b753SSimon Glass 	priv->data = calloc(1, plat->size);
138*6ec1b753SSimon Glass 	if (!priv->data)
139*6ec1b753SSimon Glass 		return -ENOMEM;
140*6ec1b753SSimon Glass 
141*6ec1b753SSimon Glass 	return 0;
142*6ec1b753SSimon Glass }
143*6ec1b753SSimon Glass 
144*6ec1b753SSimon Glass static int sandbox_i2c_eeprom_remove(struct udevice *dev)
145*6ec1b753SSimon Glass {
146*6ec1b753SSimon Glass 	struct sandbox_i2c_flash *priv = dev_get_priv(dev);
147*6ec1b753SSimon Glass 
148*6ec1b753SSimon Glass 	free(priv->data);
149*6ec1b753SSimon Glass 
150*6ec1b753SSimon Glass 	return 0;
151*6ec1b753SSimon Glass }
152*6ec1b753SSimon Glass 
153*6ec1b753SSimon Glass static const struct udevice_id sandbox_i2c_ids[] = {
154*6ec1b753SSimon Glass 	{ .compatible = "sandbox,i2c-eeprom" },
155*6ec1b753SSimon Glass 	{ }
156*6ec1b753SSimon Glass };
157*6ec1b753SSimon Glass 
158*6ec1b753SSimon Glass U_BOOT_DRIVER(sandbox_i2c_emul) = {
159*6ec1b753SSimon Glass 	.name		= "sandbox_i2c_eeprom_emul",
160*6ec1b753SSimon Glass 	.id		= UCLASS_I2C_EMUL,
161*6ec1b753SSimon Glass 	.of_match	= sandbox_i2c_ids,
162*6ec1b753SSimon Glass 	.ofdata_to_platdata = sandbox_i2c_eeprom_ofdata_to_platdata,
163*6ec1b753SSimon Glass 	.probe		= sandbox_i2c_eeprom_probe,
164*6ec1b753SSimon Glass 	.remove		= sandbox_i2c_eeprom_remove,
165*6ec1b753SSimon Glass 	.priv_auto_alloc_size = sizeof(struct sandbox_i2c_flash),
166*6ec1b753SSimon Glass 	.platdata_auto_alloc_size = sizeof(struct sandbox_i2c_flash_plat_data),
167*6ec1b753SSimon Glass 	.ops		= &sandbox_i2c_emul_ops,
168*6ec1b753SSimon Glass };
169