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