Xeon-SP boards: Factor out OCP VPD `get_cxl_mode()` impl
[coreboot2.git] / src / device / i2c_bus.c
blob41ef14a9235489c7ae9eb6d22315781efcdea97f
1 /* SPDX-License-Identifier: GPL-2.0-only */
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>
11 bool i2c_dev_detect(struct device *dev, unsigned int addr)
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;
19 struct bus *i2c_link(const struct device *const dev)
21 if (!dev || !dev->upstream)
22 return NULL;
24 struct bus *link = dev->upstream;
25 while (link) {
26 struct device *const parent = link->dev;
28 if (parent && parent->ops &&
29 (parent->ops->ops_i2c_bus || parent->ops->ops_smbus_bus))
30 break;
32 if (parent && parent->upstream && link != parent->upstream)
33 link = parent->upstream;
34 else
35 link = NULL;
38 if (!link)
39 printk(BIOS_ALERT, "%s Cannot find I2C or SMBus bus operations\n",
40 dev_path(dev));
42 return link;
45 int i2c_dev_readb(struct device *const dev)
47 struct device *const busdev = i2c_busdev(dev);
48 if (!busdev)
49 return -1;
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),
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);
69 printk(BIOS_ERR, "%s Missing ops_smbus_bus->recv_byte", dev_path(busdev));
70 return -1;
73 int i2c_dev_writeb(struct device *const dev, uint8_t val)
75 struct device *const busdev = i2c_busdev(dev);
76 if (!busdev)
77 return -1;
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),
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);
91 printk(BIOS_ERR, "%s Missing ops_smbus_bus->send_byte", dev_path(busdev));
92 return -1;
95 int i2c_dev_readb_at(struct device *const dev, uint8_t off)
97 struct device *const busdev = i2c_busdev(dev);
98 if (!busdev)
99 return -1;
101 if (busdev->ops->ops_i2c_bus) {
102 uint8_t val;
103 const struct i2c_msg msg[] = {
105 .flags = 0,
106 .slave = dev->path.i2c.device,
107 .buf = &off,
108 .len = sizeof(off),
111 .flags = I2C_M_RD,
112 .slave = dev->path.i2c.device,
113 .buf = &val,
114 .len = sizeof(val),
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);
128 printk(BIOS_ERR, "%s Missing ops_smbus_bus->read_byte", dev_path(busdev));
129 return -1;
132 int i2c_dev_writeb_at(struct device *const dev, const uint8_t off, const uint8_t val)
134 struct device *const busdev = i2c_busdev(dev);
135 if (!busdev)
136 return -1;
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),
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);
151 printk(BIOS_ERR, "%s Missing ops_smbus_bus->write_byte", dev_path(busdev));
152 return -1;
155 int i2c_dev_read_at16(struct device *const dev, uint8_t *const buf, const size_t len,
156 uint16_t off)
158 struct device *const busdev = i2c_busdev(dev);
159 if (!busdev)
160 return -1;
162 if (busdev->ops->ops_i2c_bus) {
163 const struct i2c_msg msg[] = {
165 .flags = 0,
166 .slave = dev->path.i2c.device,
167 .buf = (uint8_t *)&off,
168 .len = sizeof(off),
171 .flags = I2C_M_RD,
172 .slave = dev->path.i2c.device,
173 .buf = buf,
174 .len = len,
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;
191 int i2c_dev_read_at(struct device *const dev, uint8_t *const buf, const size_t len,
192 uint8_t off)
194 struct device *const busdev = i2c_busdev(dev);
195 if (!busdev)
196 return -1;
198 if (busdev->ops->ops_i2c_bus) {
199 const struct i2c_msg msg[] = {
201 .flags = 0,
202 .slave = dev->path.i2c.device,
203 .buf = &off,
204 .len = sizeof(off),
207 .flags = I2C_M_RD,
208 .slave = dev->path.i2c.device,
209 .buf = buf,
210 .len = len,
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;
226 int i2c_dev_write_at(struct device *const dev, uint8_t *const buf, const size_t len,
227 uint8_t off)
229 struct device *const busdev = i2c_busdev(dev);
230 if (!busdev)
231 return -1;
233 if (busdev->ops->ops_i2c_bus) {
234 const struct i2c_msg msg[] = {
236 .flags = 0,
237 .slave = dev->path.i2c.device,
238 .buf = &off,
239 .len = sizeof(off),
242 .flags = I2C_M_NOSTART,
243 .slave = dev->path.i2c.device,
244 .buf = buf,
245 .len = len,
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;