blob: df364046603f9f0bf530485290ef6dd5f5e88328 [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)
35 printk(BIOS_ALERT, "%s Cannot find I2C or SMBus bus operations", dev_path(dev));
Nico Huber58173862017-08-01 17:09:35 +020036
37 return link;
38}
39
Aaron Durbin439cee92018-01-22 21:24:35 -070040int i2c_dev_readb(struct device *const dev)
Nico Huber58173862017-08-01 17:09:35 +020041{
42 struct device *const busdev = i2c_busdev(dev);
43 if (!busdev)
44 return -1;
45
46 if (busdev->ops->ops_i2c_bus) {
47 uint8_t val;
48 const struct i2c_msg msg = {
49 .flags = I2C_M_RD,
50 .slave = dev->path.i2c.device,
51 .buf = &val,
52 .len = sizeof(val),
53 };
54
Frans Hendriksa9caa502021-02-01 11:44:37 +010055 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, &msg, 1);
Nico Huber58173862017-08-01 17:09:35 +020056 if (ret)
57 return ret;
58 else
59 return val;
60 } else if (busdev->ops->ops_smbus_bus->recv_byte) {
61 return busdev->ops->ops_smbus_bus->recv_byte(dev);
Nico Huber58173862017-08-01 17:09:35 +020062 }
Frans Hendriksa9caa502021-02-01 11:44:37 +010063
64 printk(BIOS_ERR, "%s Missing ops_smbus_bus->recv_byte", dev_path(busdev));
65 return -1;
Nico Huber58173862017-08-01 17:09:35 +020066}
67
Aaron Durbin439cee92018-01-22 21:24:35 -070068int i2c_dev_writeb(struct device *const dev, uint8_t val)
Nico Huber58173862017-08-01 17:09:35 +020069{
70 struct device *const busdev = i2c_busdev(dev);
71 if (!busdev)
72 return -1;
73
74 if (busdev->ops->ops_i2c_bus) {
75 const struct i2c_msg msg = {
76 .flags = 0,
77 .slave = dev->path.i2c.device,
78 .buf = &val,
79 .len = sizeof(val),
80 };
81 return busdev->ops->ops_i2c_bus->transfer(busdev, &msg, 1);
82 } else if (busdev->ops->ops_smbus_bus->send_byte) {
83 return busdev->ops->ops_smbus_bus->send_byte(dev, val);
Nico Huber58173862017-08-01 17:09:35 +020084 }
Frans Hendriksa9caa502021-02-01 11:44:37 +010085
Frans Hendriks68dc3692021-02-01 11:52:51 +010086 printk(BIOS_ERR, "%s Missing ops_smbus_bus->send_byte", dev_path(busdev));
Frans Hendriksa9caa502021-02-01 11:44:37 +010087 return -1;
Nico Huber58173862017-08-01 17:09:35 +020088}
89
Aaron Durbin439cee92018-01-22 21:24:35 -070090int i2c_dev_readb_at(struct device *const dev, uint8_t off)
Nico Huber58173862017-08-01 17:09:35 +020091{
92 struct device *const busdev = i2c_busdev(dev);
93 if (!busdev)
94 return -1;
95
96 if (busdev->ops->ops_i2c_bus) {
97 uint8_t val;
98 const struct i2c_msg msg[] = {
99 {
100 .flags = 0,
101 .slave = dev->path.i2c.device,
102 .buf = &off,
103 .len = sizeof(off),
104 },
105 {
106 .flags = I2C_M_RD,
107 .slave = dev->path.i2c.device,
108 .buf = &val,
109 .len = sizeof(val),
110 },
111 };
112
Frans Hendriksa9caa502021-02-01 11:44:37 +0100113 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, msg,
114 ARRAY_SIZE(msg));
Nico Huber58173862017-08-01 17:09:35 +0200115 if (ret)
116 return ret;
117 else
118 return val;
119 } else if (busdev->ops->ops_smbus_bus->read_byte) {
120 return busdev->ops->ops_smbus_bus->read_byte(dev, off);
Nico Huber58173862017-08-01 17:09:35 +0200121 }
Frans Hendriksa9caa502021-02-01 11:44:37 +0100122
123 printk(BIOS_ERR, "%s Missing ops_smbus_bus->read_byte", dev_path(busdev));
124 return -1;
Nico Huber58173862017-08-01 17:09:35 +0200125}
126
Frans Hendriksa9caa502021-02-01 11:44:37 +0100127int i2c_dev_writeb_at(struct device *const dev, const uint8_t off, const uint8_t val)
Nico Huber58173862017-08-01 17:09:35 +0200128{
129 struct device *const busdev = i2c_busdev(dev);
130 if (!busdev)
131 return -1;
132
133 if (busdev->ops->ops_i2c_bus) {
134 uint8_t buf[] = { off, val };
135 const struct i2c_msg msg = {
136 .flags = 0,
137 .slave = dev->path.i2c.device,
138 .buf = buf,
139 .len = sizeof(buf),
140 };
141 return busdev->ops->ops_i2c_bus->transfer(busdev, &msg, 1);
142 } else if (busdev->ops->ops_smbus_bus->write_byte) {
143 return busdev->ops->ops_smbus_bus->write_byte(dev, off, val);
Nico Huber58173862017-08-01 17:09:35 +0200144 }
Frans Hendriksa9caa502021-02-01 11:44:37 +0100145
Frans Hendriks68dc3692021-02-01 11:52:51 +0100146 printk(BIOS_ERR, "%s Missing ops_smbus_bus->write_byte", dev_path(busdev));
Frans Hendriksa9caa502021-02-01 11:44:37 +0100147 return -1;
Nico Huber58173862017-08-01 17:09:35 +0200148}
Nico Huber9734af62017-11-01 13:15:33 +0100149
Frans Hendriksa9caa502021-02-01 11:44:37 +0100150int i2c_dev_read_at16(struct device *const dev, uint8_t *const buf, const size_t len,
151 uint16_t off)
Nico Huber9734af62017-11-01 13:15:33 +0100152{
153 struct device *const busdev = i2c_busdev(dev);
154 if (!busdev)
155 return -1;
156
157 if (busdev->ops->ops_i2c_bus) {
158 const struct i2c_msg msg[] = {
159 {
160 .flags = 0,
161 .slave = dev->path.i2c.device,
162 .buf = (uint8_t *)&off,
163 .len = sizeof(off),
164 },
165 {
166 .flags = I2C_M_RD,
167 .slave = dev->path.i2c.device,
168 .buf = buf,
169 .len = len,
170 },
171 };
172
173 write_be16(&off, off);
Frans Hendriksa9caa502021-02-01 11:44:37 +0100174 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, msg,
175 ARRAY_SIZE(msg));
Nico Huber9734af62017-11-01 13:15:33 +0100176 if (ret)
177 return ret;
178 else
179 return len;
180 } else {
181 printk(BIOS_ERR, "%s Missing ops_i2c_bus->transfer", dev_path(busdev));
182 return -1;
183 }
184}