blob: bccd9a8c973ed2de155ad3a564742d36fe70389b [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
Nico Huber58173862017-08-01 17:09:35 +02003#include <stdint.h>
4#include <console/console.h>
5#include <device/smbus.h>
6#include <device/i2c_bus.h>
Nico Huber9734af62017-11-01 13:15:33 +01007#include <commonlib/endian.h>
Nico Huber58173862017-08-01 17:09:35 +02008
Matt DeVillieree849ba2022-05-19 19:03:07 -05009bool i2c_dev_detect(struct device *dev, unsigned int addr)
10{
11 struct i2c_msg seg = { .flags = 0, .slave = addr, .buf = NULL, .len = 0 };
12 return dev->ops->ops_i2c_bus->transfer(dev, &seg, 0) == 0;
13}
14
Matt DeVillier190086e2022-03-28 22:24:30 -050015struct bus *i2c_link(const struct device *const dev)
Nico Huber58173862017-08-01 17:09:35 +020016{
17 if (!dev || !dev->bus)
18 return NULL;
19
20 struct bus *link = dev->bus;
21 while (link) {
22 struct device *const parent = link->dev;
23
24 if (parent && parent->ops &&
25 (parent->ops->ops_i2c_bus || parent->ops->ops_smbus_bus))
26 break;
27
Matt DeVillier06abb912022-06-18 15:22:47 -050028 if (parent && parent->bus && link != parent->bus)
Nico Huber58173862017-08-01 17:09:35 +020029 link = parent->bus;
30 else
31 link = NULL;
32 }
33
Frans Hendriks68dc3692021-02-01 11:52:51 +010034 if (!link)
Matt DeVilliere97eb8f2022-06-18 15:28:00 -050035 printk(BIOS_ALERT, "%s Cannot find I2C or SMBus bus operations\n",
36 dev_path(dev));
Nico Huber58173862017-08-01 17:09:35 +020037
38 return link;
39}
40
Aaron Durbin439cee92018-01-22 21:24:35 -070041int i2c_dev_readb(struct device *const dev)
Nico Huber58173862017-08-01 17:09:35 +020042{
43 struct device *const busdev = i2c_busdev(dev);
44 if (!busdev)
45 return -1;
46
47 if (busdev->ops->ops_i2c_bus) {
48 uint8_t val;
49 const struct i2c_msg msg = {
50 .flags = I2C_M_RD,
51 .slave = dev->path.i2c.device,
52 .buf = &val,
53 .len = sizeof(val),
54 };
55
Frans Hendriksa9caa502021-02-01 11:44:37 +010056 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, &msg, 1);
Nico Huber58173862017-08-01 17:09:35 +020057 if (ret)
58 return ret;
59 else
60 return val;
61 } else if (busdev->ops->ops_smbus_bus->recv_byte) {
62 return busdev->ops->ops_smbus_bus->recv_byte(dev);
Nico Huber58173862017-08-01 17:09:35 +020063 }
Frans Hendriksa9caa502021-02-01 11:44:37 +010064
65 printk(BIOS_ERR, "%s Missing ops_smbus_bus->recv_byte", dev_path(busdev));
66 return -1;
Nico Huber58173862017-08-01 17:09:35 +020067}
68
Aaron Durbin439cee92018-01-22 21:24:35 -070069int i2c_dev_writeb(struct device *const dev, uint8_t val)
Nico Huber58173862017-08-01 17:09:35 +020070{
71 struct device *const busdev = i2c_busdev(dev);
72 if (!busdev)
73 return -1;
74
75 if (busdev->ops->ops_i2c_bus) {
76 const struct i2c_msg msg = {
77 .flags = 0,
78 .slave = dev->path.i2c.device,
79 .buf = &val,
80 .len = sizeof(val),
81 };
82 return busdev->ops->ops_i2c_bus->transfer(busdev, &msg, 1);
83 } else if (busdev->ops->ops_smbus_bus->send_byte) {
84 return busdev->ops->ops_smbus_bus->send_byte(dev, val);
Nico Huber58173862017-08-01 17:09:35 +020085 }
Frans Hendriksa9caa502021-02-01 11:44:37 +010086
Frans Hendriks68dc3692021-02-01 11:52:51 +010087 printk(BIOS_ERR, "%s Missing ops_smbus_bus->send_byte", dev_path(busdev));
Frans Hendriksa9caa502021-02-01 11:44:37 +010088 return -1;
Nico Huber58173862017-08-01 17:09:35 +020089}
90
Aaron Durbin439cee92018-01-22 21:24:35 -070091int i2c_dev_readb_at(struct device *const dev, uint8_t off)
Nico Huber58173862017-08-01 17:09:35 +020092{
93 struct device *const busdev = i2c_busdev(dev);
94 if (!busdev)
95 return -1;
96
97 if (busdev->ops->ops_i2c_bus) {
98 uint8_t val;
99 const struct i2c_msg msg[] = {
100 {
101 .flags = 0,
102 .slave = dev->path.i2c.device,
103 .buf = &off,
104 .len = sizeof(off),
105 },
106 {
107 .flags = I2C_M_RD,
108 .slave = dev->path.i2c.device,
109 .buf = &val,
110 .len = sizeof(val),
111 },
112 };
113
Frans Hendriksa9caa502021-02-01 11:44:37 +0100114 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, msg,
115 ARRAY_SIZE(msg));
Nico Huber58173862017-08-01 17:09:35 +0200116 if (ret)
117 return ret;
118 else
119 return val;
120 } else if (busdev->ops->ops_smbus_bus->read_byte) {
121 return busdev->ops->ops_smbus_bus->read_byte(dev, off);
Nico Huber58173862017-08-01 17:09:35 +0200122 }
Frans Hendriksa9caa502021-02-01 11:44:37 +0100123
124 printk(BIOS_ERR, "%s Missing ops_smbus_bus->read_byte", dev_path(busdev));
125 return -1;
Nico Huber58173862017-08-01 17:09:35 +0200126}
127
Frans Hendriksa9caa502021-02-01 11:44:37 +0100128int i2c_dev_writeb_at(struct device *const dev, const uint8_t off, const uint8_t val)
Nico Huber58173862017-08-01 17:09:35 +0200129{
130 struct device *const busdev = i2c_busdev(dev);
131 if (!busdev)
132 return -1;
133
134 if (busdev->ops->ops_i2c_bus) {
135 uint8_t buf[] = { off, val };
136 const struct i2c_msg msg = {
137 .flags = 0,
138 .slave = dev->path.i2c.device,
139 .buf = buf,
140 .len = sizeof(buf),
141 };
142 return busdev->ops->ops_i2c_bus->transfer(busdev, &msg, 1);
143 } else if (busdev->ops->ops_smbus_bus->write_byte) {
144 return busdev->ops->ops_smbus_bus->write_byte(dev, off, val);
Nico Huber58173862017-08-01 17:09:35 +0200145 }
Frans Hendriksa9caa502021-02-01 11:44:37 +0100146
Frans Hendriks68dc3692021-02-01 11:52:51 +0100147 printk(BIOS_ERR, "%s Missing ops_smbus_bus->write_byte", dev_path(busdev));
Frans Hendriksa9caa502021-02-01 11:44:37 +0100148 return -1;
Nico Huber58173862017-08-01 17:09:35 +0200149}
Nico Huber9734af62017-11-01 13:15:33 +0100150
Frans Hendriksa9caa502021-02-01 11:44:37 +0100151int i2c_dev_read_at16(struct device *const dev, uint8_t *const buf, const size_t len,
152 uint16_t off)
Nico Huber9734af62017-11-01 13:15:33 +0100153{
154 struct device *const busdev = i2c_busdev(dev);
155 if (!busdev)
156 return -1;
157
158 if (busdev->ops->ops_i2c_bus) {
159 const struct i2c_msg msg[] = {
160 {
161 .flags = 0,
162 .slave = dev->path.i2c.device,
163 .buf = (uint8_t *)&off,
164 .len = sizeof(off),
165 },
166 {
167 .flags = I2C_M_RD,
168 .slave = dev->path.i2c.device,
169 .buf = buf,
170 .len = len,
171 },
172 };
173
174 write_be16(&off, off);
Frans Hendriksa9caa502021-02-01 11:44:37 +0100175 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, msg,
176 ARRAY_SIZE(msg));
Nico Huber9734af62017-11-01 13:15:33 +0100177 if (ret)
178 return ret;
179 else
180 return len;
181 } else {
182 printk(BIOS_ERR, "%s Missing ops_i2c_bus->transfer", dev_path(busdev));
183 return -1;
184 }
185}