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