blob: 361bb67df89edec491a8508c5fb493fa46d7e6f5 [file] [log] [blame]
Angel Ponsc74dae92020-04-02 23:48:16 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Nico Huber58173862017-08-01 17:09:35 +02002
Elyes Haouas04c3b5a2022-10-07 10:08:05 +02003#include <commonlib/bsd/helpers.h>
Nico Huber58173862017-08-01 17:09:35 +02004#include <console/console.h>
Elyes Haouas04c3b5a2022-10-07 10:08:05 +02005#include <device/device.h>
Nico Huber58173862017-08-01 17:09:35 +02006#include <device/smbus.h>
7#include <device/i2c_bus.h>
Nico Huber9734af62017-11-01 13:15:33 +01008#include <commonlib/endian.h>
Elyes Haouas04c3b5a2022-10-07 10:08:05 +02009#include <types.h>
Nico Huber58173862017-08-01 17:09:35 +020010
Matt DeVillieree849ba2022-05-19 19:03:07 -050011bool i2c_dev_detect(struct device *dev, unsigned int addr)
12{
13 struct i2c_msg seg = { .flags = 0, .slave = addr, .buf = NULL, .len = 0 };
Nico Huber51a357642022-08-01 19:32:37 +020014 return dev->ops->ops_i2c_bus->transfer(dev, &seg, 1) == 0;
Matt DeVillieree849ba2022-05-19 19:03:07 -050015}
16
Matt DeVillier190086e2022-03-28 22:24:30 -050017struct bus *i2c_link(const struct device *const dev)
Nico Huber58173862017-08-01 17:09:35 +020018{
19 if (!dev || !dev->bus)
20 return NULL;
21
22 struct bus *link = dev->bus;
23 while (link) {
24 struct device *const parent = link->dev;
25
26 if (parent && parent->ops &&
27 (parent->ops->ops_i2c_bus || parent->ops->ops_smbus_bus))
28 break;
29
Matt DeVillier06abb912022-06-18 15:22:47 -050030 if (parent && parent->bus && link != parent->bus)
Nico Huber58173862017-08-01 17:09:35 +020031 link = parent->bus;
32 else
33 link = NULL;
34 }
35
Frans Hendriks68dc3692021-02-01 11:52:51 +010036 if (!link)
Matt DeVilliere97eb8f2022-06-18 15:28:00 -050037 printk(BIOS_ALERT, "%s Cannot find I2C or SMBus bus operations\n",
38 dev_path(dev));
Nico Huber58173862017-08-01 17:09:35 +020039
40 return link;
41}
42
Aaron Durbin439cee92018-01-22 21:24:35 -070043int i2c_dev_readb(struct device *const dev)
Nico Huber58173862017-08-01 17:09:35 +020044{
45 struct device *const busdev = i2c_busdev(dev);
46 if (!busdev)
47 return -1;
48
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),
56 };
57
Frans Hendriksa9caa502021-02-01 11:44:37 +010058 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, &msg, 1);
Nico Huber58173862017-08-01 17:09:35 +020059 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);
Nico Huber58173862017-08-01 17:09:35 +020065 }
Frans Hendriksa9caa502021-02-01 11:44:37 +010066
67 printk(BIOS_ERR, "%s Missing ops_smbus_bus->recv_byte", dev_path(busdev));
68 return -1;
Nico Huber58173862017-08-01 17:09:35 +020069}
70
Aaron Durbin439cee92018-01-22 21:24:35 -070071int i2c_dev_writeb(struct device *const dev, uint8_t val)
Nico Huber58173862017-08-01 17:09:35 +020072{
73 struct device *const busdev = i2c_busdev(dev);
74 if (!busdev)
75 return -1;
76
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),
83 };
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);
Nico Huber58173862017-08-01 17:09:35 +020087 }
Frans Hendriksa9caa502021-02-01 11:44:37 +010088
Frans Hendriks68dc3692021-02-01 11:52:51 +010089 printk(BIOS_ERR, "%s Missing ops_smbus_bus->send_byte", dev_path(busdev));
Frans Hendriksa9caa502021-02-01 11:44:37 +010090 return -1;
Nico Huber58173862017-08-01 17:09:35 +020091}
92
Aaron Durbin439cee92018-01-22 21:24:35 -070093int i2c_dev_readb_at(struct device *const dev, uint8_t off)
Nico Huber58173862017-08-01 17:09:35 +020094{
95 struct device *const busdev = i2c_busdev(dev);
96 if (!busdev)
97 return -1;
98
99 if (busdev->ops->ops_i2c_bus) {
100 uint8_t val;
101 const struct i2c_msg msg[] = {
102 {
103 .flags = 0,
104 .slave = dev->path.i2c.device,
105 .buf = &off,
106 .len = sizeof(off),
107 },
108 {
109 .flags = I2C_M_RD,
110 .slave = dev->path.i2c.device,
111 .buf = &val,
112 .len = sizeof(val),
113 },
114 };
115
Frans Hendriksa9caa502021-02-01 11:44:37 +0100116 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, msg,
117 ARRAY_SIZE(msg));
Nico Huber58173862017-08-01 17:09:35 +0200118 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);
Nico Huber58173862017-08-01 17:09:35 +0200124 }
Frans Hendriksa9caa502021-02-01 11:44:37 +0100125
126 printk(BIOS_ERR, "%s Missing ops_smbus_bus->read_byte", dev_path(busdev));
127 return -1;
Nico Huber58173862017-08-01 17:09:35 +0200128}
129
Frans Hendriksa9caa502021-02-01 11:44:37 +0100130int i2c_dev_writeb_at(struct device *const dev, const uint8_t off, const uint8_t val)
Nico Huber58173862017-08-01 17:09:35 +0200131{
132 struct device *const busdev = i2c_busdev(dev);
133 if (!busdev)
134 return -1;
135
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),
143 };
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);
Nico Huber58173862017-08-01 17:09:35 +0200147 }
Frans Hendriksa9caa502021-02-01 11:44:37 +0100148
Frans Hendriks68dc3692021-02-01 11:52:51 +0100149 printk(BIOS_ERR, "%s Missing ops_smbus_bus->write_byte", dev_path(busdev));
Frans Hendriksa9caa502021-02-01 11:44:37 +0100150 return -1;
Nico Huber58173862017-08-01 17:09:35 +0200151}
Nico Huber9734af62017-11-01 13:15:33 +0100152
Frans Hendriksa9caa502021-02-01 11:44:37 +0100153int i2c_dev_read_at16(struct device *const dev, uint8_t *const buf, const size_t len,
154 uint16_t off)
Nico Huber9734af62017-11-01 13:15:33 +0100155{
156 struct device *const busdev = i2c_busdev(dev);
157 if (!busdev)
158 return -1;
159
160 if (busdev->ops->ops_i2c_bus) {
161 const struct i2c_msg msg[] = {
162 {
163 .flags = 0,
164 .slave = dev->path.i2c.device,
165 .buf = (uint8_t *)&off,
166 .len = sizeof(off),
167 },
168 {
169 .flags = I2C_M_RD,
170 .slave = dev->path.i2c.device,
171 .buf = buf,
172 .len = len,
173 },
174 };
175
176 write_be16(&off, off);
Frans Hendriksa9caa502021-02-01 11:44:37 +0100177 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, msg,
178 ARRAY_SIZE(msg));
Nico Huber9734af62017-11-01 13:15:33 +0100179 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;
186 }
187}
Werner Zeh63f72f02022-08-26 13:17:52 +0200188
189int i2c_dev_read_at(struct device *const dev, uint8_t *const buf, const size_t len,
190 uint8_t off)
191{
192 struct device *const busdev = i2c_busdev(dev);
193 if (!busdev)
194 return -1;
195
196 if (busdev->ops->ops_i2c_bus) {
197 const struct i2c_msg msg[] = {
198 {
199 .flags = 0,
200 .slave = dev->path.i2c.device,
201 .buf = &off,
202 .len = sizeof(off),
203 },
204 {
205 .flags = I2C_M_RD,
206 .slave = dev->path.i2c.device,
207 .buf = buf,
208 .len = len,
209 },
210 };
211
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;
221 }
222}
223
224int i2c_dev_write_at(struct device *const dev, uint8_t *const buf, const size_t len,
225 uint8_t off)
226{
227 struct device *const busdev = i2c_busdev(dev);
228 if (!busdev)
229 return -1;
230
231 if (busdev->ops->ops_i2c_bus) {
232 const struct i2c_msg msg[] = {
233 {
234 .flags = 0,
235 .slave = dev->path.i2c.device,
236 .buf = &off,
237 .len = sizeof(off),
238 },
239 {
240 .flags = I2C_M_NOSTART,
241 .slave = dev->path.i2c.device,
242 .buf = buf,
243 .len = len,
244 },
245 };
246
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;
256 }
257}