misc: i2c_eeprom: set offset len and chip addr offset mask
[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         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->pagewidth = data->pagewidth;
107                 priv->pagesize = (1 << priv->pagewidth);
108         }
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
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_ofnode(dev, DM_GET_DRIVER(i2c_eeprom_partition),
135                                    name, NULL, partition, NULL);
136         }
137
138         return 0;
139 }
140
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         ret = i2c_eeprom_read(dev, 0, &test_byte, 1);
153         if (ret)
154                 return -ENODEV;
155
156         return 0;
157 }
158
159 static const struct i2c_eeprom_drv_data eeprom_data = {
160         .size = 0,
161         .pagewidth = 0,
162         .addr_offset_mask = 0,
163         .offset_len = 1,
164 };
165
166 static const struct i2c_eeprom_drv_data mc24aa02e48_data = {
167         .size = 256,
168         .pagewidth = 3,
169         .addr_offset_mask = 0,
170         .offset_len = 1,
171 };
172
173 static const struct i2c_eeprom_drv_data atmel24c01a_data = {
174         .size = 128,
175         .pagewidth = 3,
176         .addr_offset_mask = 0,
177         .offset_len = 1,
178 };
179
180 static const struct i2c_eeprom_drv_data atmel24c02_data = {
181         .size = 256,
182         .pagewidth = 3,
183         .addr_offset_mask = 0,
184         .offset_len = 1,
185 };
186
187 static const struct i2c_eeprom_drv_data atmel24c04_data = {
188         .size = 512,
189         .pagewidth = 4,
190         .addr_offset_mask = 0x1,
191         .offset_len = 1,
192 };
193
194 static const struct i2c_eeprom_drv_data atmel24c08_data = {
195         .size = 1024,
196         .pagewidth = 4,
197         .addr_offset_mask = 0x3,
198         .offset_len = 1,
199 };
200
201 static const struct i2c_eeprom_drv_data atmel24c08a_data = {
202         .size = 1024,
203         .pagewidth = 4,
204         .addr_offset_mask = 0x3,
205         .offset_len = 1,
206 };
207
208 static const struct i2c_eeprom_drv_data atmel24c16a_data = {
209         .size = 2048,
210         .pagewidth = 4,
211         .addr_offset_mask = 0x7,
212         .offset_len = 1,
213 };
214
215 static const struct i2c_eeprom_drv_data atmel24mac402_data = {
216         .size = 256,
217         .pagewidth = 4,
218         .addr_offset_mask = 0,
219         .offset_len = 1,
220 };
221
222 static const struct i2c_eeprom_drv_data atmel24c32_data = {
223         .size = 4096,
224         .pagewidth = 5,
225         .addr_offset_mask = 0,
226         .offset_len = 2,
227 };
228
229 static const struct i2c_eeprom_drv_data atmel24c64_data = {
230         .size = 8192,
231         .pagewidth = 5,
232         .addr_offset_mask = 0,
233         .offset_len = 2,
234 };
235
236 static const struct i2c_eeprom_drv_data atmel24c128_data = {
237         .size = 16384,
238         .pagewidth = 6,
239         .addr_offset_mask = 0,
240         .offset_len = 2,
241 };
242
243 static const struct i2c_eeprom_drv_data atmel24c256_data = {
244         .size = 32768,
245         .pagewidth = 6,
246         .addr_offset_mask = 0,
247         .offset_len = 2,
248 };
249
250 static const struct i2c_eeprom_drv_data atmel24c512_data = {
251         .size = 65536,
252         .pagewidth = 6,
253         .addr_offset_mask = 0,
254         .offset_len = 2,
255 };
256
257 static const struct udevice_id i2c_eeprom_std_ids[] = {
258         { .compatible = "i2c-eeprom", (ulong)&eeprom_data },
259         { .compatible = "microchip,24aa02e48", (ulong)&mc24aa02e48_data },
260         { .compatible = "atmel,24c01a", (ulong)&atmel24c01a_data },
261         { .compatible = "atmel,24c02", (ulong)&atmel24c02_data },
262         { .compatible = "atmel,24c04", (ulong)&atmel24c04_data },
263         { .compatible = "atmel,24c08", (ulong)&atmel24c08_data },
264         { .compatible = "atmel,24c08a", (ulong)&atmel24c08a_data },
265         { .compatible = "atmel,24c16a", (ulong)&atmel24c16a_data },
266         { .compatible = "atmel,24mac402", (ulong)&atmel24mac402_data },
267         { .compatible = "atmel,24c32", (ulong)&atmel24c32_data },
268         { .compatible = "atmel,24c64", (ulong)&atmel24c64_data },
269         { .compatible = "atmel,24c128", (ulong)&atmel24c128_data },
270         { .compatible = "atmel,24c256", (ulong)&atmel24c256_data },
271         { .compatible = "atmel,24c512", (ulong)&atmel24c512_data },
272         { }
273 };
274
275 U_BOOT_DRIVER(i2c_eeprom_std) = {
276         .name                   = "i2c_eeprom",
277         .id                     = UCLASS_I2C_EEPROM,
278         .of_match               = i2c_eeprom_std_ids,
279         .bind                   = i2c_eeprom_std_bind,
280         .probe                  = i2c_eeprom_std_probe,
281         .ofdata_to_platdata     = i2c_eeprom_std_ofdata_to_platdata,
282         .priv_auto_alloc_size   = sizeof(struct i2c_eeprom),
283         .ops                    = &i2c_eeprom_std_ops,
284 };
285
286 struct i2c_eeprom_partition {
287         u32 offset;
288         u32 size;
289 };
290
291 static int i2c_eeprom_partition_probe(struct udevice *dev)
292 {
293         return 0;
294 }
295
296 static int i2c_eeprom_partition_ofdata_to_platdata(struct udevice *dev)
297 {
298         struct i2c_eeprom_partition *priv = dev_get_priv(dev);
299         u32 offset, size;
300         int ret;
301
302         ret = dev_read_u32(dev, "offset", &offset);
303         if (ret)
304                 return ret;
305
306         ret = dev_read_u32(dev, "size", &size);
307         if (ret)
308                 return ret;
309
310         priv->offset = offset;
311         priv->size = size;
312
313         return 0;
314 }
315
316 static int i2c_eeprom_partition_read(struct udevice *dev, int offset,
317                                      u8 *buf, int size)
318 {
319         struct i2c_eeprom_partition *priv = dev_get_priv(dev);
320         struct udevice *parent = dev_get_parent(dev);
321
322         if (!parent)
323                 return -ENODEV;
324         if (offset + size > priv->size)
325                 return -EINVAL;
326
327         return i2c_eeprom_read(parent, offset + priv->offset, buf, size);
328 }
329
330 static int i2c_eeprom_partition_write(struct udevice *dev, int offset,
331                                       const u8 *buf, int size)
332 {
333         struct i2c_eeprom_partition *priv = dev_get_priv(dev);
334         struct udevice *parent = dev_get_parent(dev);
335
336         if (!parent)
337                 return -ENODEV;
338         if (offset + size > priv->size)
339                 return -EINVAL;
340
341         return i2c_eeprom_write(parent, offset + priv->offset, (uint8_t *)buf,
342                                 size);
343 }
344
345 static int i2c_eeprom_partition_size(struct udevice *dev)
346 {
347         struct i2c_eeprom_partition *priv = dev_get_priv(dev);
348
349         return priv->size;
350 }
351
352 static const struct i2c_eeprom_ops i2c_eeprom_partition_ops = {
353         .read   = i2c_eeprom_partition_read,
354         .write  = i2c_eeprom_partition_write,
355         .size   = i2c_eeprom_partition_size,
356 };
357
358 U_BOOT_DRIVER(i2c_eeprom_partition) = {
359         .name                   = "i2c_eeprom_partition",
360         .id                     = UCLASS_I2C_EEPROM,
361         .probe                  = i2c_eeprom_partition_probe,
362         .ofdata_to_platdata     = i2c_eeprom_partition_ofdata_to_platdata,
363         .priv_auto_alloc_size   = sizeof(struct i2c_eeprom_partition),
364         .ops                    = &i2c_eeprom_partition_ops,
365 };
366
367 UCLASS_DRIVER(i2c_eeprom) = {
368         .id             = UCLASS_I2C_EEPROM,
369         .name           = "i2c_eeprom",
370 };