misc: i2c_eeprom: add size query
[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 pagewidth; /* pagesize = 2^pagewidth */
18 };
19
20 int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf, int size)
21 {
22         const struct i2c_eeprom_ops *ops = device_get_ops(dev);
23
24         if (!ops->read)
25                 return -ENOSYS;
26
27         return ops->read(dev, offset, buf, size);
28 }
29
30 int i2c_eeprom_write(struct udevice *dev, int offset, uint8_t *buf, int size)
31 {
32         const struct i2c_eeprom_ops *ops = device_get_ops(dev);
33
34         if (!ops->write)
35                 return -ENOSYS;
36
37         return ops->write(dev, offset, buf, size);
38 }
39
40 int i2c_eeprom_size(struct udevice *dev)
41 {
42         const struct i2c_eeprom_ops *ops = device_get_ops(dev);
43
44         if (!ops->size)
45                 return -ENOSYS;
46
47         return ops->size(dev);
48 }
49
50 static int i2c_eeprom_std_read(struct udevice *dev, int offset, uint8_t *buf,
51                                int size)
52 {
53         return dm_i2c_read(dev, offset, buf, size);
54 }
55
56 static int i2c_eeprom_std_write(struct udevice *dev, int offset,
57                                 const uint8_t *buf, int size)
58 {
59         struct i2c_eeprom *priv = dev_get_priv(dev);
60         int ret;
61
62         while (size > 0) {
63                 int write_size = min_t(int, size, priv->pagesize);
64
65                 ret = dm_i2c_write(dev, offset, buf, write_size);
66                 if (ret)
67                         return ret;
68
69                 offset += write_size;
70                 buf += write_size;
71                 size -= write_size;
72
73                 udelay(10000);
74         }
75
76         return 0;
77 }
78
79 static int i2c_eeprom_std_size(struct udevice *dev)
80 {
81         struct i2c_eeprom *priv = dev_get_priv(dev);
82
83         return priv->size;
84 }
85
86 static const struct i2c_eeprom_ops i2c_eeprom_std_ops = {
87         .read   = i2c_eeprom_std_read,
88         .write  = i2c_eeprom_std_write,
89         .size   = i2c_eeprom_std_size,
90 };
91
92 static int i2c_eeprom_std_ofdata_to_platdata(struct udevice *dev)
93 {
94         struct i2c_eeprom *priv = dev_get_priv(dev);
95         struct i2c_eeprom_drv_data *data =
96                 (struct i2c_eeprom_drv_data *)dev_get_driver_data(dev);
97         u32 pagesize;
98         u32 size;
99
100         if (dev_read_u32(dev, "pagesize", &pagesize) == 0) {
101                 priv->pagesize = pagesize;
102         } else {
103                 /* 6 bit -> page size of up to 2^63 (should be sufficient) */
104                 priv->pagewidth = data->pagewidth;
105                 priv->pagesize = (1 << priv->pagewidth);
106         }
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
144         /* Verify that the chip is functional */
145         ret = i2c_eeprom_read(dev, 0, &test_byte, 1);
146         if (ret)
147                 return -ENODEV;
148
149         return 0;
150 }
151
152 static const struct i2c_eeprom_drv_data eeprom_data = {
153         .size = 0,
154         .pagewidth = 0,
155 };
156
157 static const struct i2c_eeprom_drv_data mc24aa02e48_data = {
158         .size = 256,
159         .pagewidth = 3,
160 };
161
162 static const struct i2c_eeprom_drv_data atmel24c01a_data = {
163         .size = 128,
164         .pagewidth = 3,
165 };
166
167 static const struct i2c_eeprom_drv_data atmel24c02_data = {
168         .size = 256,
169         .pagewidth = 3,
170 };
171
172 static const struct i2c_eeprom_drv_data atmel24c04_data = {
173         .size = 512,
174         .pagewidth = 4,
175 };
176
177 static const struct i2c_eeprom_drv_data atmel24c08_data = {
178         .size = 1024,
179         .pagewidth = 4,
180 };
181
182 static const struct i2c_eeprom_drv_data atmel24c08a_data = {
183         .size = 1024,
184         .pagewidth = 4,
185 };
186
187 static const struct i2c_eeprom_drv_data atmel24c16a_data = {
188         .size = 2048,
189         .pagewidth = 4,
190 };
191
192 static const struct i2c_eeprom_drv_data atmel24mac402_data = {
193         .size = 256,
194         .pagewidth = 4,
195 };
196
197 static const struct i2c_eeprom_drv_data atmel24c32_data = {
198         .size = 4096,
199         .pagewidth = 5,
200 };
201
202 static const struct i2c_eeprom_drv_data atmel24c64_data = {
203         .size = 8192,
204         .pagewidth = 5,
205 };
206
207 static const struct i2c_eeprom_drv_data atmel24c128_data = {
208         .size = 16384,
209         .pagewidth = 6,
210 };
211
212 static const struct i2c_eeprom_drv_data atmel24c256_data = {
213         .size = 32768,
214         .pagewidth = 6,
215 };
216
217 static const struct i2c_eeprom_drv_data atmel24c512_data = {
218         .size = 65536,
219         .pagewidth = 6,
220 };
221
222 static const struct udevice_id i2c_eeprom_std_ids[] = {
223         { .compatible = "i2c-eeprom", (ulong)&eeprom_data },
224         { .compatible = "microchip,24aa02e48", (ulong)&mc24aa02e48_data },
225         { .compatible = "atmel,24c01a", (ulong)&atmel24c01a_data },
226         { .compatible = "atmel,24c02", (ulong)&atmel24c02_data },
227         { .compatible = "atmel,24c04", (ulong)&atmel24c04_data },
228         { .compatible = "atmel,24c08", (ulong)&atmel24c08_data },
229         { .compatible = "atmel,24c08a", (ulong)&atmel24c08a_data },
230         { .compatible = "atmel,24c16a", (ulong)&atmel24c16a_data },
231         { .compatible = "atmel,24mac402", (ulong)&atmel24mac402_data },
232         { .compatible = "atmel,24c32", (ulong)&atmel24c32_data },
233         { .compatible = "atmel,24c64", (ulong)&atmel24c64_data },
234         { .compatible = "atmel,24c128", (ulong)&atmel24c128_data },
235         { .compatible = "atmel,24c256", (ulong)&atmel24c256_data },
236         { .compatible = "atmel,24c512", (ulong)&atmel24c512_data },
237         { }
238 };
239
240 U_BOOT_DRIVER(i2c_eeprom_std) = {
241         .name                   = "i2c_eeprom",
242         .id                     = UCLASS_I2C_EEPROM,
243         .of_match               = i2c_eeprom_std_ids,
244         .bind                   = i2c_eeprom_std_bind,
245         .probe                  = i2c_eeprom_std_probe,
246         .ofdata_to_platdata     = i2c_eeprom_std_ofdata_to_platdata,
247         .priv_auto_alloc_size   = sizeof(struct i2c_eeprom),
248         .ops                    = &i2c_eeprom_std_ops,
249 };
250
251 struct i2c_eeprom_partition {
252         u32 offset;
253         u32 size;
254 };
255
256 static int i2c_eeprom_partition_probe(struct udevice *dev)
257 {
258         return 0;
259 }
260
261 static int i2c_eeprom_partition_ofdata_to_platdata(struct udevice *dev)
262 {
263         struct i2c_eeprom_partition *priv = dev_get_priv(dev);
264         u32 offset, size;
265         int ret;
266
267         ret = dev_read_u32(dev, "offset", &offset);
268         if (ret)
269                 return ret;
270
271         ret = dev_read_u32(dev, "size", &size);
272         if (ret)
273                 return ret;
274
275         priv->offset = offset;
276         priv->size = size;
277
278         return 0;
279 }
280
281 static int i2c_eeprom_partition_read(struct udevice *dev, int offset,
282                                      u8 *buf, int size)
283 {
284         struct i2c_eeprom_partition *priv = dev_get_priv(dev);
285         struct udevice *parent = dev_get_parent(dev);
286
287         if (!parent)
288                 return -ENODEV;
289         if (offset + size > priv->size)
290                 return -EINVAL;
291
292         return i2c_eeprom_read(parent, offset + priv->offset, buf, size);
293 }
294
295 static int i2c_eeprom_partition_write(struct udevice *dev, int offset,
296                                       const u8 *buf, int size)
297 {
298         struct i2c_eeprom_partition *priv = dev_get_priv(dev);
299         struct udevice *parent = dev_get_parent(dev);
300
301         if (!parent)
302                 return -ENODEV;
303         if (offset + size > priv->size)
304                 return -EINVAL;
305
306         return i2c_eeprom_write(parent, offset + priv->offset, (uint8_t *)buf,
307                                 size);
308 }
309
310 static int i2c_eeprom_partition_size(struct udevice *dev)
311 {
312         struct i2c_eeprom_partition *priv = dev_get_priv(dev);
313
314         return priv->size;
315 }
316
317 static const struct i2c_eeprom_ops i2c_eeprom_partition_ops = {
318         .read   = i2c_eeprom_partition_read,
319         .write  = i2c_eeprom_partition_write,
320         .size   = i2c_eeprom_partition_size,
321 };
322
323 U_BOOT_DRIVER(i2c_eeprom_partition) = {
324         .name                   = "i2c_eeprom_partition",
325         .id                     = UCLASS_I2C_EEPROM,
326         .probe                  = i2c_eeprom_partition_probe,
327         .ofdata_to_platdata     = i2c_eeprom_partition_ofdata_to_platdata,
328         .priv_auto_alloc_size   = sizeof(struct i2c_eeprom_partition),
329         .ops                    = &i2c_eeprom_partition_ops,
330 };
331
332 UCLASS_DRIVER(i2c_eeprom) = {
333         .id             = UCLASS_I2C_EEPROM,
334         .name           = "i2c_eeprom",
335 };