blob: 728e0fd79abd2333dec2532f054ca009dc5b3fb7 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass6ca4ba02014-12-10 08:55:54 -07002/*
3 * Copyright (c) 2014 Google, Inc
Simon Glass6ca4ba02014-12-10 08:55:54 -07004 */
5
6#include <common.h>
Simon Glasseba6b8d2019-11-14 12:57:50 -07007#include <eeprom.h>
Masahiro Yamadaf9d52cc2014-12-18 20:00:26 +09008#include <linux/err.h>
Baruch Siach4e4c5ed2019-04-07 12:38:49 +03009#include <linux/kernel.h>
Simon Glass6ca4ba02014-12-10 08:55:54 -070010#include <dm.h>
Robert Beckettf030d6f2019-10-28 18:29:05 +000011#include <dm/device-internal.h>
Simon Glass6ca4ba02014-12-10 08:55:54 -070012#include <i2c.h>
13#include <i2c_eeprom.h>
14
Robert Beckett069ddc72019-10-28 18:29:06 +000015struct i2c_eeprom_drv_data {
16 u32 size; /* size in bytes */
17 u32 pagewidth; /* pagesize = 2^pagewidth */
Robert Beckett44cf4612020-01-31 15:07:52 +020018 u32 addr_offset_mask; /* bits in addr used for offset overflow */
19 u32 offset_len; /* size in bytes of offset */
Robert Beckett069ddc72019-10-28 18:29:06 +000020};
21
Jonas Karlman8427a242017-04-22 08:57:41 +000022int 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
32int 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
Robert Beckett069ddc72019-10-28 18:29:06 +000042int 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
Jonas Karlman8427a242017-04-22 08:57:41 +000052static int i2c_eeprom_std_read(struct udevice *dev, int offset, uint8_t *buf,
53 int size)
Simon Glass6ca4ba02014-12-10 08:55:54 -070054{
mario.six@gdsys.cc7559ac42016-06-22 15:14:16 +020055 return dm_i2c_read(dev, offset, buf, size);
Simon Glass6ca4ba02014-12-10 08:55:54 -070056}
57
Jonas Karlman8427a242017-04-22 08:57:41 +000058static int i2c_eeprom_std_write(struct udevice *dev, int offset,
59 const uint8_t *buf, int size)
Simon Glass6ca4ba02014-12-10 08:55:54 -070060{
Baruch Siach4e4c5ed2019-04-07 12:38:49 +030061 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;
Simon Glass6ca4ba02014-12-10 08:55:54 -070079}
80
Robert Beckett069ddc72019-10-28 18:29:06 +000081static 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
Masahiro Yamadaa7cc93e82017-06-22 16:51:22 +090088static const struct i2c_eeprom_ops i2c_eeprom_std_ops = {
Jonas Karlman8427a242017-04-22 08:57:41 +000089 .read = i2c_eeprom_std_read,
90 .write = i2c_eeprom_std_write,
Robert Beckett069ddc72019-10-28 18:29:06 +000091 .size = i2c_eeprom_std_size,
Simon Glass6ca4ba02014-12-10 08:55:54 -070092};
93
mario.six@gdsys.cc7559ac42016-06-22 15:14:16 +020094static int i2c_eeprom_std_ofdata_to_platdata(struct udevice *dev)
95{
96 struct i2c_eeprom *priv = dev_get_priv(dev);
Robert Beckett069ddc72019-10-28 18:29:06 +000097 struct i2c_eeprom_drv_data *data =
98 (struct i2c_eeprom_drv_data *)dev_get_driver_data(dev);
Baruch Siach263b5b02019-04-07 12:38:48 +030099 u32 pagesize;
Robert Beckett069ddc72019-10-28 18:29:06 +0000100 u32 size;
Baruch Siach263b5b02019-04-07 12:38:48 +0300101
Masahiro Yamadac8b5dc32020-02-28 22:04:13 +0900102 if (dev_read_u32(dev, "pagesize", &pagesize) == 0)
Baruch Siach263b5b02019-04-07 12:38:48 +0300103 priv->pagesize = pagesize;
Masahiro Yamadac8b5dc32020-02-28 22:04:13 +0900104 else
Robert Beckett069ddc72019-10-28 18:29:06 +0000105 /* 6 bit -> page size of up to 2^63 (should be sufficient) */
Masahiro Yamadac8b5dc32020-02-28 22:04:13 +0900106 priv->pagesize = 1 << data->pagewidth;
mario.six@gdsys.cc7559ac42016-06-22 15:14:16 +0200107
Robert Beckett069ddc72019-10-28 18:29:06 +0000108 if (dev_read_u32(dev, "size", &size) == 0)
109 priv->size = size;
110 else
111 priv->size = data->size;
mario.six@gdsys.cc7559ac42016-06-22 15:14:16 +0200112
113 return 0;
114}
115
Robert Beckettf030d6f2019-10-28 18:29:05 +0000116static 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
Masahiro Yamadaa7cc93e82017-06-22 16:51:22 +0900139static int i2c_eeprom_std_probe(struct udevice *dev)
Simon Glass6ca4ba02014-12-10 08:55:54 -0700140{
Baruch Siach38793e22019-08-05 09:03:30 +0300141 u8 test_byte;
142 int ret;
Robert Beckett44cf4612020-01-31 15:07:52 +0200143 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);
Baruch Siach38793e22019-08-05 09:03:30 +0300148
149 /* Verify that the chip is functional */
150 ret = i2c_eeprom_read(dev, 0, &test_byte, 1);
151 if (ret)
152 return -ENODEV;
153
Simon Glass6ca4ba02014-12-10 08:55:54 -0700154 return 0;
155}
156
Robert Beckett069ddc72019-10-28 18:29:06 +0000157static const struct i2c_eeprom_drv_data eeprom_data = {
158 .size = 0,
159 .pagewidth = 0,
Robert Beckett44cf4612020-01-31 15:07:52 +0200160 .addr_offset_mask = 0,
161 .offset_len = 1,
Robert Beckett069ddc72019-10-28 18:29:06 +0000162};
163
164static const struct i2c_eeprom_drv_data mc24aa02e48_data = {
165 .size = 256,
166 .pagewidth = 3,
Robert Beckett44cf4612020-01-31 15:07:52 +0200167 .addr_offset_mask = 0,
168 .offset_len = 1,
Robert Beckett069ddc72019-10-28 18:29:06 +0000169};
170
171static const struct i2c_eeprom_drv_data atmel24c01a_data = {
172 .size = 128,
173 .pagewidth = 3,
Robert Beckett44cf4612020-01-31 15:07:52 +0200174 .addr_offset_mask = 0,
175 .offset_len = 1,
Robert Beckett069ddc72019-10-28 18:29:06 +0000176};
177
178static const struct i2c_eeprom_drv_data atmel24c02_data = {
179 .size = 256,
180 .pagewidth = 3,
Robert Beckett44cf4612020-01-31 15:07:52 +0200181 .addr_offset_mask = 0,
182 .offset_len = 1,
Robert Beckett069ddc72019-10-28 18:29:06 +0000183};
184
185static const struct i2c_eeprom_drv_data atmel24c04_data = {
186 .size = 512,
187 .pagewidth = 4,
Robert Beckett44cf4612020-01-31 15:07:52 +0200188 .addr_offset_mask = 0x1,
189 .offset_len = 1,
Robert Beckett069ddc72019-10-28 18:29:06 +0000190};
191
192static const struct i2c_eeprom_drv_data atmel24c08_data = {
193 .size = 1024,
194 .pagewidth = 4,
Robert Beckett44cf4612020-01-31 15:07:52 +0200195 .addr_offset_mask = 0x3,
196 .offset_len = 1,
Robert Beckett069ddc72019-10-28 18:29:06 +0000197};
198
199static const struct i2c_eeprom_drv_data atmel24c08a_data = {
200 .size = 1024,
201 .pagewidth = 4,
Robert Beckett44cf4612020-01-31 15:07:52 +0200202 .addr_offset_mask = 0x3,
203 .offset_len = 1,
Robert Beckett069ddc72019-10-28 18:29:06 +0000204};
205
206static const struct i2c_eeprom_drv_data atmel24c16a_data = {
207 .size = 2048,
208 .pagewidth = 4,
Robert Beckett44cf4612020-01-31 15:07:52 +0200209 .addr_offset_mask = 0x7,
210 .offset_len = 1,
Robert Beckett069ddc72019-10-28 18:29:06 +0000211};
212
213static const struct i2c_eeprom_drv_data atmel24mac402_data = {
214 .size = 256,
215 .pagewidth = 4,
Robert Beckett44cf4612020-01-31 15:07:52 +0200216 .addr_offset_mask = 0,
217 .offset_len = 1,
Robert Beckett069ddc72019-10-28 18:29:06 +0000218};
219
220static const struct i2c_eeprom_drv_data atmel24c32_data = {
221 .size = 4096,
222 .pagewidth = 5,
Robert Beckett44cf4612020-01-31 15:07:52 +0200223 .addr_offset_mask = 0,
224 .offset_len = 2,
Robert Beckett069ddc72019-10-28 18:29:06 +0000225};
226
227static const struct i2c_eeprom_drv_data atmel24c64_data = {
228 .size = 8192,
229 .pagewidth = 5,
Robert Beckett44cf4612020-01-31 15:07:52 +0200230 .addr_offset_mask = 0,
231 .offset_len = 2,
Robert Beckett069ddc72019-10-28 18:29:06 +0000232};
233
234static const struct i2c_eeprom_drv_data atmel24c128_data = {
235 .size = 16384,
236 .pagewidth = 6,
Robert Beckett44cf4612020-01-31 15:07:52 +0200237 .addr_offset_mask = 0,
238 .offset_len = 2,
Robert Beckett069ddc72019-10-28 18:29:06 +0000239};
240
241static const struct i2c_eeprom_drv_data atmel24c256_data = {
242 .size = 32768,
243 .pagewidth = 6,
Robert Beckett44cf4612020-01-31 15:07:52 +0200244 .addr_offset_mask = 0,
245 .offset_len = 2,
Robert Beckett069ddc72019-10-28 18:29:06 +0000246};
247
248static const struct i2c_eeprom_drv_data atmel24c512_data = {
249 .size = 65536,
250 .pagewidth = 6,
Robert Beckett44cf4612020-01-31 15:07:52 +0200251 .addr_offset_mask = 0,
252 .offset_len = 2,
Robert Beckett069ddc72019-10-28 18:29:06 +0000253};
254
Simon Glass6ca4ba02014-12-10 08:55:54 -0700255static const struct udevice_id i2c_eeprom_std_ids[] = {
Robert Beckett069ddc72019-10-28 18:29:06 +0000256 { .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 },
Simon Glass6ca4ba02014-12-10 08:55:54 -0700270 { }
271};
272
273U_BOOT_DRIVER(i2c_eeprom_std) = {
mario.six@gdsys.cc7559ac42016-06-22 15:14:16 +0200274 .name = "i2c_eeprom",
275 .id = UCLASS_I2C_EEPROM,
276 .of_match = i2c_eeprom_std_ids,
Robert Beckettf030d6f2019-10-28 18:29:05 +0000277 .bind = i2c_eeprom_std_bind,
mario.six@gdsys.cc7559ac42016-06-22 15:14:16 +0200278 .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,
Simon Glass6ca4ba02014-12-10 08:55:54 -0700282};
283
Robert Beckettf030d6f2019-10-28 18:29:05 +0000284struct i2c_eeprom_partition {
285 u32 offset;
286 u32 size;
287};
288
289static int i2c_eeprom_partition_probe(struct udevice *dev)
290{
291 return 0;
292}
293
294static 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
314static 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
328static 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
Robert Beckett069ddc72019-10-28 18:29:06 +0000343static 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
Robert Beckettf030d6f2019-10-28 18:29:05 +0000350static const struct i2c_eeprom_ops i2c_eeprom_partition_ops = {
351 .read = i2c_eeprom_partition_read,
352 .write = i2c_eeprom_partition_write,
Robert Beckett069ddc72019-10-28 18:29:06 +0000353 .size = i2c_eeprom_partition_size,
Robert Beckettf030d6f2019-10-28 18:29:05 +0000354};
355
356U_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
Simon Glass6ca4ba02014-12-10 08:55:54 -0700365UCLASS_DRIVER(i2c_eeprom) = {
366 .id = UCLASS_I2C_EEPROM,
367 .name = "i2c_eeprom",
368};