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