Merge tag 'for-v2019.10' of https://gitlab.denx.de/u-boot/custodians/u-boot-i2c
[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 <linux/err.h>
8 #include <linux/kernel.h>
9 #include <dm.h>
10 #include <i2c.h>
11 #include <i2c_eeprom.h>
12
13 int i2c_eeprom_read(struct udevice *dev, int offset, uint8_t *buf, int size)
14 {
15         const struct i2c_eeprom_ops *ops = device_get_ops(dev);
16
17         if (!ops->read)
18                 return -ENOSYS;
19
20         return ops->read(dev, offset, buf, size);
21 }
22
23 int i2c_eeprom_write(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->write)
28                 return -ENOSYS;
29
30         return ops->write(dev, offset, buf, size);
31 }
32
33 static int i2c_eeprom_std_read(struct udevice *dev, int offset, uint8_t *buf,
34                                int size)
35 {
36         return dm_i2c_read(dev, offset, buf, size);
37 }
38
39 static int i2c_eeprom_std_write(struct udevice *dev, int offset,
40                                 const uint8_t *buf, int size)
41 {
42         struct i2c_eeprom *priv = dev_get_priv(dev);
43         int ret;
44
45         while (size > 0) {
46                 int write_size = min_t(int, size, priv->pagesize);
47
48                 ret = dm_i2c_write(dev, offset, buf, write_size);
49                 if (ret)
50                         return ret;
51
52                 offset += write_size;
53                 buf += write_size;
54                 size -= write_size;
55
56                 udelay(10000);
57         }
58
59         return 0;
60 }
61
62 static const struct i2c_eeprom_ops i2c_eeprom_std_ops = {
63         .read   = i2c_eeprom_std_read,
64         .write  = i2c_eeprom_std_write,
65 };
66
67 static int i2c_eeprom_std_ofdata_to_platdata(struct udevice *dev)
68 {
69         struct i2c_eeprom *priv = dev_get_priv(dev);
70         u64 data = dev_get_driver_data(dev);
71         u32 pagesize;
72
73         if (dev_read_u32(dev, "pagesize", &pagesize) == 0) {
74                 priv->pagesize = pagesize;
75                 return 0;
76         }
77
78         /* 6 bit -> page size of up to 2^63 (should be sufficient) */
79         priv->pagewidth = data & 0x3F;
80         priv->pagesize = (1 << priv->pagewidth);
81
82         return 0;
83 }
84
85 static int i2c_eeprom_std_probe(struct udevice *dev)
86 {
87         u8 test_byte;
88         int ret;
89
90         /* Verify that the chip is functional */
91         ret = i2c_eeprom_read(dev, 0, &test_byte, 1);
92         if (ret)
93                 return -ENODEV;
94
95         return 0;
96 }
97
98 static const struct udevice_id i2c_eeprom_std_ids[] = {
99         { .compatible = "i2c-eeprom", .data = 0 },
100         { .compatible = "microchip,24aa02e48", .data = 3 },
101         { .compatible = "atmel,24c01a", .data = 3 },
102         { .compatible = "atmel,24c02", .data = 3 },
103         { .compatible = "atmel,24c04", .data = 4 },
104         { .compatible = "atmel,24c08", .data = 4 },
105         { .compatible = "atmel,24c08a", .data = 4 },
106         { .compatible = "atmel,24c16a", .data = 4 },
107         { .compatible = "atmel,24mac402", .data = 4 },
108         { .compatible = "atmel,24c32", .data = 5 },
109         { .compatible = "atmel,24c64", .data = 5 },
110         { .compatible = "atmel,24c128", .data = 6 },
111         { .compatible = "atmel,24c256", .data = 6 },
112         { .compatible = "atmel,24c512", .data = 6 },
113         { }
114 };
115
116 U_BOOT_DRIVER(i2c_eeprom_std) = {
117         .name                   = "i2c_eeprom",
118         .id                     = UCLASS_I2C_EEPROM,
119         .of_match               = i2c_eeprom_std_ids,
120         .probe                  = i2c_eeprom_std_probe,
121         .ofdata_to_platdata     = i2c_eeprom_std_ofdata_to_platdata,
122         .priv_auto_alloc_size   = sizeof(struct i2c_eeprom),
123         .ops                    = &i2c_eeprom_std_ops,
124 };
125
126 UCLASS_DRIVER(i2c_eeprom) = {
127         .id             = UCLASS_I2C_EEPROM,
128         .name           = "i2c_eeprom",
129 };