blob: 741bae2727522fbd12ba70cfdeea36833db369c1 [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
Jonas Karlman8427a242017-04-22 08:57:41 +000015int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf, int size)
16{
17 const struct i2c_eeprom_ops *ops = device_get_ops(dev);
18
19 if (!ops->read)
20 return -ENOSYS;
21
22 return ops->read(dev, offset, buf, size);
23}
24
25int i2c_eeprom_write(struct udevice *dev, int offset, uint8_t *buf, int size)
26{
27 const struct i2c_eeprom_ops *ops = device_get_ops(dev);
28
29 if (!ops->write)
30 return -ENOSYS;
31
32 return ops->write(dev, offset, buf, size);
33}
34
35static int i2c_eeprom_std_read(struct udevice *dev, int offset, uint8_t *buf,
36 int size)
Simon Glass6ca4ba02014-12-10 08:55:54 -070037{
mario.six@gdsys.cc7559ac42016-06-22 15:14:16 +020038 return dm_i2c_read(dev, offset, buf, size);
Simon Glass6ca4ba02014-12-10 08:55:54 -070039}
40
Jonas Karlman8427a242017-04-22 08:57:41 +000041static int i2c_eeprom_std_write(struct udevice *dev, int offset,
42 const uint8_t *buf, int size)
Simon Glass6ca4ba02014-12-10 08:55:54 -070043{
Baruch Siach4e4c5ed2019-04-07 12:38:49 +030044 struct i2c_eeprom *priv = dev_get_priv(dev);
45 int ret;
46
47 while (size > 0) {
48 int write_size = min_t(int, size, priv->pagesize);
49
50 ret = dm_i2c_write(dev, offset, buf, write_size);
51 if (ret)
52 return ret;
53
54 offset += write_size;
55 buf += write_size;
56 size -= write_size;
57
58 udelay(10000);
59 }
60
61 return 0;
Simon Glass6ca4ba02014-12-10 08:55:54 -070062}
63
Masahiro Yamadaa7cc93e82017-06-22 16:51:22 +090064static const struct i2c_eeprom_ops i2c_eeprom_std_ops = {
Jonas Karlman8427a242017-04-22 08:57:41 +000065 .read = i2c_eeprom_std_read,
66 .write = i2c_eeprom_std_write,
Simon Glass6ca4ba02014-12-10 08:55:54 -070067};
68
mario.six@gdsys.cc7559ac42016-06-22 15:14:16 +020069static int i2c_eeprom_std_ofdata_to_platdata(struct udevice *dev)
70{
71 struct i2c_eeprom *priv = dev_get_priv(dev);
72 u64 data = dev_get_driver_data(dev);
Baruch Siach263b5b02019-04-07 12:38:48 +030073 u32 pagesize;
74
75 if (dev_read_u32(dev, "pagesize", &pagesize) == 0) {
76 priv->pagesize = pagesize;
77 return 0;
78 }
mario.six@gdsys.cc7559ac42016-06-22 15:14:16 +020079
80 /* 6 bit -> page size of up to 2^63 (should be sufficient) */
81 priv->pagewidth = data & 0x3F;
82 priv->pagesize = (1 << priv->pagewidth);
83
84 return 0;
85}
86
Robert Beckettf030d6f2019-10-28 18:29:05 +000087static int i2c_eeprom_std_bind(struct udevice *dev)
88{
89 ofnode partitions = ofnode_find_subnode(dev_ofnode(dev), "partitions");
90 ofnode partition;
91 const char *name;
92
93 if (!ofnode_valid(partitions))
94 return 0;
95 if (!ofnode_device_is_compatible(partitions, "fixed-partitions"))
96 return -ENOTSUPP;
97
98 ofnode_for_each_subnode(partition, partitions) {
99 name = ofnode_get_name(partition);
100 if (!name)
101 continue;
102
103 device_bind_ofnode(dev, DM_GET_DRIVER(i2c_eeprom_partition),
104 name, NULL, partition, NULL);
105 }
106
107 return 0;
108}
109
Masahiro Yamadaa7cc93e82017-06-22 16:51:22 +0900110static int i2c_eeprom_std_probe(struct udevice *dev)
Simon Glass6ca4ba02014-12-10 08:55:54 -0700111{
Baruch Siach38793e22019-08-05 09:03:30 +0300112 u8 test_byte;
113 int ret;
114
115 /* Verify that the chip is functional */
116 ret = i2c_eeprom_read(dev, 0, &test_byte, 1);
117 if (ret)
118 return -ENODEV;
119
Simon Glass6ca4ba02014-12-10 08:55:54 -0700120 return 0;
121}
122
123static const struct udevice_id i2c_eeprom_std_ids[] = {
mario.six@gdsys.cc7559ac42016-06-22 15:14:16 +0200124 { .compatible = "i2c-eeprom", .data = 0 },
Wenyou Yang6db50422017-07-31 11:25:30 +0800125 { .compatible = "microchip,24aa02e48", .data = 3 },
mario.six@gdsys.cc7559ac42016-06-22 15:14:16 +0200126 { .compatible = "atmel,24c01a", .data = 3 },
127 { .compatible = "atmel,24c02", .data = 3 },
128 { .compatible = "atmel,24c04", .data = 4 },
Michal Simek191d02e2019-01-21 13:54:57 +0100129 { .compatible = "atmel,24c08", .data = 4 },
mario.six@gdsys.cc7559ac42016-06-22 15:14:16 +0200130 { .compatible = "atmel,24c08a", .data = 4 },
131 { .compatible = "atmel,24c16a", .data = 4 },
Wenyou Yang911a6102017-07-31 11:25:31 +0800132 { .compatible = "atmel,24mac402", .data = 4 },
mario.six@gdsys.cc7559ac42016-06-22 15:14:16 +0200133 { .compatible = "atmel,24c32", .data = 5 },
134 { .compatible = "atmel,24c64", .data = 5 },
135 { .compatible = "atmel,24c128", .data = 6 },
136 { .compatible = "atmel,24c256", .data = 6 },
137 { .compatible = "atmel,24c512", .data = 6 },
Simon Glass6ca4ba02014-12-10 08:55:54 -0700138 { }
139};
140
141U_BOOT_DRIVER(i2c_eeprom_std) = {
mario.six@gdsys.cc7559ac42016-06-22 15:14:16 +0200142 .name = "i2c_eeprom",
143 .id = UCLASS_I2C_EEPROM,
144 .of_match = i2c_eeprom_std_ids,
Robert Beckettf030d6f2019-10-28 18:29:05 +0000145 .bind = i2c_eeprom_std_bind,
mario.six@gdsys.cc7559ac42016-06-22 15:14:16 +0200146 .probe = i2c_eeprom_std_probe,
147 .ofdata_to_platdata = i2c_eeprom_std_ofdata_to_platdata,
148 .priv_auto_alloc_size = sizeof(struct i2c_eeprom),
149 .ops = &i2c_eeprom_std_ops,
Simon Glass6ca4ba02014-12-10 08:55:54 -0700150};
151
Robert Beckettf030d6f2019-10-28 18:29:05 +0000152struct i2c_eeprom_partition {
153 u32 offset;
154 u32 size;
155};
156
157static int i2c_eeprom_partition_probe(struct udevice *dev)
158{
159 return 0;
160}
161
162static int i2c_eeprom_partition_ofdata_to_platdata(struct udevice *dev)
163{
164 struct i2c_eeprom_partition *priv = dev_get_priv(dev);
165 u32 offset, size;
166 int ret;
167
168 ret = dev_read_u32(dev, "offset", &offset);
169 if (ret)
170 return ret;
171
172 ret = dev_read_u32(dev, "size", &size);
173 if (ret)
174 return ret;
175
176 priv->offset = offset;
177 priv->size = size;
178
179 return 0;
180}
181
182static int i2c_eeprom_partition_read(struct udevice *dev, int offset,
183 u8 *buf, int size)
184{
185 struct i2c_eeprom_partition *priv = dev_get_priv(dev);
186 struct udevice *parent = dev_get_parent(dev);
187
188 if (!parent)
189 return -ENODEV;
190 if (offset + size > priv->size)
191 return -EINVAL;
192
193 return i2c_eeprom_read(parent, offset + priv->offset, buf, size);
194}
195
196static int i2c_eeprom_partition_write(struct udevice *dev, int offset,
197 const u8 *buf, int size)
198{
199 struct i2c_eeprom_partition *priv = dev_get_priv(dev);
200 struct udevice *parent = dev_get_parent(dev);
201
202 if (!parent)
203 return -ENODEV;
204 if (offset + size > priv->size)
205 return -EINVAL;
206
207 return i2c_eeprom_write(parent, offset + priv->offset, (uint8_t *)buf,
208 size);
209}
210
211static const struct i2c_eeprom_ops i2c_eeprom_partition_ops = {
212 .read = i2c_eeprom_partition_read,
213 .write = i2c_eeprom_partition_write,
214};
215
216U_BOOT_DRIVER(i2c_eeprom_partition) = {
217 .name = "i2c_eeprom_partition",
218 .id = UCLASS_I2C_EEPROM,
219 .probe = i2c_eeprom_partition_probe,
220 .ofdata_to_platdata = i2c_eeprom_partition_ofdata_to_platdata,
221 .priv_auto_alloc_size = sizeof(struct i2c_eeprom_partition),
222 .ops = &i2c_eeprom_partition_ops,
223};
224
Simon Glass6ca4ba02014-12-10 08:55:54 -0700225UCLASS_DRIVER(i2c_eeprom) = {
226 .id = UCLASS_I2C_EEPROM,
227 .name = "i2c_eeprom",
228};