xref: /aosp_15_r20/external/coreboot/src/device/i2c_bus.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
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