1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #include <commonlib/bsd/helpers.h>
4 #include <console/console.h>
5 #include <device/device.h>
6 #include <device/smbus.h>
7 #include <device/i2c_bus.h>
8 #include <commonlib/endian.h>
9 #include <types.h>
10
i2c_dev_detect(struct device * dev,unsigned int addr)11 bool i2c_dev_detect(struct device *dev, unsigned int addr)
12 {
13 struct i2c_msg seg = { .flags = 0, .slave = addr, .buf = NULL, .len = 0 };
14 if (!dev)
15 return false;
16 return dev->ops->ops_i2c_bus->transfer(dev, &seg, 1) == 0;
17 }
18
i2c_link(const struct device * const dev)19 struct bus *i2c_link(const struct device *const dev)
20 {
21 if (!dev || !dev->upstream)
22 return NULL;
23
24 struct bus *link = dev->upstream;
25 while (link) {
26 struct device *const parent = link->dev;
27
28 if (parent && parent->ops &&
29 (parent->ops->ops_i2c_bus || parent->ops->ops_smbus_bus))
30 break;
31
32 if (parent && parent->upstream && link != parent->upstream)
33 link = parent->upstream;
34 else
35 link = NULL;
36 }
37
38 if (!link)
39 printk(BIOS_ALERT, "%s Cannot find I2C or SMBus bus operations\n",
40 dev_path(dev));
41
42 return link;
43 }
44
i2c_dev_readb(struct device * const dev)45 int i2c_dev_readb(struct device *const dev)
46 {
47 struct device *const busdev = i2c_busdev(dev);
48 if (!busdev)
49 return -1;
50
51 if (busdev->ops->ops_i2c_bus) {
52 uint8_t val;
53 const struct i2c_msg msg = {
54 .flags = I2C_M_RD,
55 .slave = dev->path.i2c.device,
56 .buf = &val,
57 .len = sizeof(val),
58 };
59
60 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, &msg, 1);
61 if (ret)
62 return ret;
63 else
64 return val;
65 } else if (busdev->ops->ops_smbus_bus->recv_byte) {
66 return busdev->ops->ops_smbus_bus->recv_byte(dev);
67 }
68
69 printk(BIOS_ERR, "%s Missing ops_smbus_bus->recv_byte", dev_path(busdev));
70 return -1;
71 }
72
i2c_dev_writeb(struct device * const dev,uint8_t val)73 int i2c_dev_writeb(struct device *const dev, uint8_t val)
74 {
75 struct device *const busdev = i2c_busdev(dev);
76 if (!busdev)
77 return -1;
78
79 if (busdev->ops->ops_i2c_bus) {
80 const struct i2c_msg msg = {
81 .flags = 0,
82 .slave = dev->path.i2c.device,
83 .buf = &val,
84 .len = sizeof(val),
85 };
86 return busdev->ops->ops_i2c_bus->transfer(busdev, &msg, 1);
87 } else if (busdev->ops->ops_smbus_bus->send_byte) {
88 return busdev->ops->ops_smbus_bus->send_byte(dev, val);
89 }
90
91 printk(BIOS_ERR, "%s Missing ops_smbus_bus->send_byte", dev_path(busdev));
92 return -1;
93 }
94
i2c_dev_readb_at(struct device * const dev,uint8_t off)95 int i2c_dev_readb_at(struct device *const dev, uint8_t off)
96 {
97 struct device *const busdev = i2c_busdev(dev);
98 if (!busdev)
99 return -1;
100
101 if (busdev->ops->ops_i2c_bus) {
102 uint8_t val;
103 const struct i2c_msg msg[] = {
104 {
105 .flags = 0,
106 .slave = dev->path.i2c.device,
107 .buf = &off,
108 .len = sizeof(off),
109 },
110 {
111 .flags = I2C_M_RD,
112 .slave = dev->path.i2c.device,
113 .buf = &val,
114 .len = sizeof(val),
115 },
116 };
117
118 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, msg,
119 ARRAY_SIZE(msg));
120 if (ret)
121 return ret;
122 else
123 return val;
124 } else if (busdev->ops->ops_smbus_bus->read_byte) {
125 return busdev->ops->ops_smbus_bus->read_byte(dev, off);
126 }
127
128 printk(BIOS_ERR, "%s Missing ops_smbus_bus->read_byte", dev_path(busdev));
129 return -1;
130 }
131
i2c_dev_writeb_at(struct device * const dev,const uint8_t off,const uint8_t val)132 int i2c_dev_writeb_at(struct device *const dev, const uint8_t off, const uint8_t val)
133 {
134 struct device *const busdev = i2c_busdev(dev);
135 if (!busdev)
136 return -1;
137
138 if (busdev->ops->ops_i2c_bus) {
139 uint8_t buf[] = { off, val };
140 const struct i2c_msg msg = {
141 .flags = 0,
142 .slave = dev->path.i2c.device,
143 .buf = buf,
144 .len = sizeof(buf),
145 };
146 return busdev->ops->ops_i2c_bus->transfer(busdev, &msg, 1);
147 } else if (busdev->ops->ops_smbus_bus->write_byte) {
148 return busdev->ops->ops_smbus_bus->write_byte(dev, off, val);
149 }
150
151 printk(BIOS_ERR, "%s Missing ops_smbus_bus->write_byte", dev_path(busdev));
152 return -1;
153 }
154
i2c_dev_read_at16(struct device * const dev,uint8_t * const buf,const size_t len,uint16_t off)155 int i2c_dev_read_at16(struct device *const dev, uint8_t *const buf, const size_t len,
156 uint16_t off)
157 {
158 struct device *const busdev = i2c_busdev(dev);
159 if (!busdev)
160 return -1;
161
162 if (busdev->ops->ops_i2c_bus) {
163 const struct i2c_msg msg[] = {
164 {
165 .flags = 0,
166 .slave = dev->path.i2c.device,
167 .buf = (uint8_t *)&off,
168 .len = sizeof(off),
169 },
170 {
171 .flags = I2C_M_RD,
172 .slave = dev->path.i2c.device,
173 .buf = buf,
174 .len = len,
175 },
176 };
177
178 write_be16(&off, off);
179 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, msg,
180 ARRAY_SIZE(msg));
181 if (ret)
182 return ret;
183 else
184 return len;
185 } else {
186 printk(BIOS_ERR, "%s Missing ops_i2c_bus->transfer", dev_path(busdev));
187 return -1;
188 }
189 }
190
i2c_dev_read_at(struct device * const dev,uint8_t * const buf,const size_t len,uint8_t off)191 int i2c_dev_read_at(struct device *const dev, uint8_t *const buf, const size_t len,
192 uint8_t off)
193 {
194 struct device *const busdev = i2c_busdev(dev);
195 if (!busdev)
196 return -1;
197
198 if (busdev->ops->ops_i2c_bus) {
199 const struct i2c_msg msg[] = {
200 {
201 .flags = 0,
202 .slave = dev->path.i2c.device,
203 .buf = &off,
204 .len = sizeof(off),
205 },
206 {
207 .flags = I2C_M_RD,
208 .slave = dev->path.i2c.device,
209 .buf = buf,
210 .len = len,
211 },
212 };
213
214 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, msg,
215 ARRAY_SIZE(msg));
216 if (ret)
217 return ret;
218 else
219 return len;
220 } else {
221 printk(BIOS_ERR, "%s Missing ops_i2c_bus->transfer", dev_path(busdev));
222 return -1;
223 }
224 }
225
i2c_dev_write_at(struct device * const dev,uint8_t * const buf,const size_t len,uint8_t off)226 int i2c_dev_write_at(struct device *const dev, uint8_t *const buf, const size_t len,
227 uint8_t off)
228 {
229 struct device *const busdev = i2c_busdev(dev);
230 if (!busdev)
231 return -1;
232
233 if (busdev->ops->ops_i2c_bus) {
234 const struct i2c_msg msg[] = {
235 {
236 .flags = 0,
237 .slave = dev->path.i2c.device,
238 .buf = &off,
239 .len = sizeof(off),
240 },
241 {
242 .flags = I2C_M_NOSTART,
243 .slave = dev->path.i2c.device,
244 .buf = buf,
245 .len = len,
246 },
247 };
248
249 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, msg,
250 ARRAY_SIZE(msg));
251 if (ret)
252 return ret;
253 else
254 return len;
255 } else {
256 printk(BIOS_ERR, "%s Missing ops_i2c_bus->transfer", dev_path(busdev));
257 return -1;
258 }
259 }
260