nb/intel/haswell: Add 9-series PCH IDs
[coreboot.git] / src / device / i2c_bus.c
blob361bb67df89edec491a8508c5fb493fa46d7e6f5
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 return dev->ops->ops_i2c_bus->transfer(dev, &seg, 1) == 0;
17 struct bus *i2c_link(const struct device *const dev)
19 if (!dev || !dev->bus)
20 return NULL;
22 struct bus *link = dev->bus;
23 while (link) {
24 struct device *const parent = link->dev;
26 if (parent && parent->ops &&
27 (parent->ops->ops_i2c_bus || parent->ops->ops_smbus_bus))
28 break;
30 if (parent && parent->bus && link != parent->bus)
31 link = parent->bus;
32 else
33 link = NULL;
36 if (!link)
37 printk(BIOS_ALERT, "%s Cannot find I2C or SMBus bus operations\n",
38 dev_path(dev));
40 return link;
43 int i2c_dev_readb(struct device *const dev)
45 struct device *const busdev = i2c_busdev(dev);
46 if (!busdev)
47 return -1;
49 if (busdev->ops->ops_i2c_bus) {
50 uint8_t val;
51 const struct i2c_msg msg = {
52 .flags = I2C_M_RD,
53 .slave = dev->path.i2c.device,
54 .buf = &val,
55 .len = sizeof(val),
58 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, &msg, 1);
59 if (ret)
60 return ret;
61 else
62 return val;
63 } else if (busdev->ops->ops_smbus_bus->recv_byte) {
64 return busdev->ops->ops_smbus_bus->recv_byte(dev);
67 printk(BIOS_ERR, "%s Missing ops_smbus_bus->recv_byte", dev_path(busdev));
68 return -1;
71 int i2c_dev_writeb(struct device *const dev, uint8_t val)
73 struct device *const busdev = i2c_busdev(dev);
74 if (!busdev)
75 return -1;
77 if (busdev->ops->ops_i2c_bus) {
78 const struct i2c_msg msg = {
79 .flags = 0,
80 .slave = dev->path.i2c.device,
81 .buf = &val,
82 .len = sizeof(val),
84 return busdev->ops->ops_i2c_bus->transfer(busdev, &msg, 1);
85 } else if (busdev->ops->ops_smbus_bus->send_byte) {
86 return busdev->ops->ops_smbus_bus->send_byte(dev, val);
89 printk(BIOS_ERR, "%s Missing ops_smbus_bus->send_byte", dev_path(busdev));
90 return -1;
93 int i2c_dev_readb_at(struct device *const dev, uint8_t off)
95 struct device *const busdev = i2c_busdev(dev);
96 if (!busdev)
97 return -1;
99 if (busdev->ops->ops_i2c_bus) {
100 uint8_t val;
101 const struct i2c_msg msg[] = {
103 .flags = 0,
104 .slave = dev->path.i2c.device,
105 .buf = &off,
106 .len = sizeof(off),
109 .flags = I2C_M_RD,
110 .slave = dev->path.i2c.device,
111 .buf = &val,
112 .len = sizeof(val),
116 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, msg,
117 ARRAY_SIZE(msg));
118 if (ret)
119 return ret;
120 else
121 return val;
122 } else if (busdev->ops->ops_smbus_bus->read_byte) {
123 return busdev->ops->ops_smbus_bus->read_byte(dev, off);
126 printk(BIOS_ERR, "%s Missing ops_smbus_bus->read_byte", dev_path(busdev));
127 return -1;
130 int i2c_dev_writeb_at(struct device *const dev, const uint8_t off, const uint8_t val)
132 struct device *const busdev = i2c_busdev(dev);
133 if (!busdev)
134 return -1;
136 if (busdev->ops->ops_i2c_bus) {
137 uint8_t buf[] = { off, val };
138 const struct i2c_msg msg = {
139 .flags = 0,
140 .slave = dev->path.i2c.device,
141 .buf = buf,
142 .len = sizeof(buf),
144 return busdev->ops->ops_i2c_bus->transfer(busdev, &msg, 1);
145 } else if (busdev->ops->ops_smbus_bus->write_byte) {
146 return busdev->ops->ops_smbus_bus->write_byte(dev, off, val);
149 printk(BIOS_ERR, "%s Missing ops_smbus_bus->write_byte", dev_path(busdev));
150 return -1;
153 int i2c_dev_read_at16(struct device *const dev, uint8_t *const buf, const size_t len,
154 uint16_t off)
156 struct device *const busdev = i2c_busdev(dev);
157 if (!busdev)
158 return -1;
160 if (busdev->ops->ops_i2c_bus) {
161 const struct i2c_msg msg[] = {
163 .flags = 0,
164 .slave = dev->path.i2c.device,
165 .buf = (uint8_t *)&off,
166 .len = sizeof(off),
169 .flags = I2C_M_RD,
170 .slave = dev->path.i2c.device,
171 .buf = buf,
172 .len = len,
176 write_be16(&off, off);
177 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, msg,
178 ARRAY_SIZE(msg));
179 if (ret)
180 return ret;
181 else
182 return len;
183 } else {
184 printk(BIOS_ERR, "%s Missing ops_i2c_bus->transfer", dev_path(busdev));
185 return -1;
189 int i2c_dev_read_at(struct device *const dev, uint8_t *const buf, const size_t len,
190 uint8_t off)
192 struct device *const busdev = i2c_busdev(dev);
193 if (!busdev)
194 return -1;
196 if (busdev->ops->ops_i2c_bus) {
197 const struct i2c_msg msg[] = {
199 .flags = 0,
200 .slave = dev->path.i2c.device,
201 .buf = &off,
202 .len = sizeof(off),
205 .flags = I2C_M_RD,
206 .slave = dev->path.i2c.device,
207 .buf = buf,
208 .len = len,
212 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, msg,
213 ARRAY_SIZE(msg));
214 if (ret)
215 return ret;
216 else
217 return len;
218 } else {
219 printk(BIOS_ERR, "%s Missing ops_i2c_bus->transfer", dev_path(busdev));
220 return -1;
224 int i2c_dev_write_at(struct device *const dev, uint8_t *const buf, const size_t len,
225 uint8_t off)
227 struct device *const busdev = i2c_busdev(dev);
228 if (!busdev)
229 return -1;
231 if (busdev->ops->ops_i2c_bus) {
232 const struct i2c_msg msg[] = {
234 .flags = 0,
235 .slave = dev->path.i2c.device,
236 .buf = &off,
237 .len = sizeof(off),
240 .flags = I2C_M_NOSTART,
241 .slave = dev->path.i2c.device,
242 .buf = buf,
243 .len = len,
247 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, msg,
248 ARRAY_SIZE(msg));
249 if (ret)
250 return ret;
251 else
252 return len;
253 } else {
254 printk(BIOS_ERR, "%s Missing ops_i2c_bus->transfer", dev_path(busdev));
255 return -1;