blob: 93ec854cf8107f76509ccbc637dca6b0a81df7c8 [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
9struct bus *i2c_link(struct device *const dev)
10{
11 if (!dev || !dev->bus)
12 return NULL;
13
14 struct bus *link = dev->bus;
15 while (link) {
16 struct device *const parent = link->dev;
17
18 if (parent && parent->ops &&
19 (parent->ops->ops_i2c_bus || parent->ops->ops_smbus_bus))
20 break;
21
22 if (parent && parent->bus)
23 link = parent->bus;
24 else
25 link = NULL;
26 }
27
28 if (!link) {
29 printk(BIOS_ALERT, "%s Cannot find I2C or SMBus bus operations",
30 dev_path(dev));
31 }
32
33 return link;
34}
35
Aaron Durbin439cee92018-01-22 21:24:35 -070036int i2c_dev_readb(struct device *const dev)
Nico Huber58173862017-08-01 17:09:35 +020037{
38 struct device *const busdev = i2c_busdev(dev);
39 if (!busdev)
40 return -1;
41
42 if (busdev->ops->ops_i2c_bus) {
43 uint8_t val;
44 const struct i2c_msg msg = {
45 .flags = I2C_M_RD,
46 .slave = dev->path.i2c.device,
47 .buf = &val,
48 .len = sizeof(val),
49 };
50
Frans Hendriksa9caa502021-02-01 11:44:37 +010051 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, &msg, 1);
Nico Huber58173862017-08-01 17:09:35 +020052 if (ret)
53 return ret;
54 else
55 return val;
56 } else if (busdev->ops->ops_smbus_bus->recv_byte) {
57 return busdev->ops->ops_smbus_bus->recv_byte(dev);
Nico Huber58173862017-08-01 17:09:35 +020058 }
Frans Hendriksa9caa502021-02-01 11:44:37 +010059
60 printk(BIOS_ERR, "%s Missing ops_smbus_bus->recv_byte", dev_path(busdev));
61 return -1;
Nico Huber58173862017-08-01 17:09:35 +020062}
63
Aaron Durbin439cee92018-01-22 21:24:35 -070064int i2c_dev_writeb(struct device *const dev, uint8_t val)
Nico Huber58173862017-08-01 17:09:35 +020065{
66 struct device *const busdev = i2c_busdev(dev);
67 if (!busdev)
68 return -1;
69
70 if (busdev->ops->ops_i2c_bus) {
71 const struct i2c_msg msg = {
72 .flags = 0,
73 .slave = dev->path.i2c.device,
74 .buf = &val,
75 .len = sizeof(val),
76 };
77 return busdev->ops->ops_i2c_bus->transfer(busdev, &msg, 1);
78 } else if (busdev->ops->ops_smbus_bus->send_byte) {
79 return busdev->ops->ops_smbus_bus->send_byte(dev, val);
Nico Huber58173862017-08-01 17:09:35 +020080 }
Frans Hendriksa9caa502021-02-01 11:44:37 +010081
82 printk(BIOS_ERR, "%s Missing ops_smbus_bus->send_byte",
83 dev_path(busdev));
84 return -1;
Nico Huber58173862017-08-01 17:09:35 +020085}
86
Aaron Durbin439cee92018-01-22 21:24:35 -070087int i2c_dev_readb_at(struct device *const dev, uint8_t off)
Nico Huber58173862017-08-01 17:09:35 +020088{
89 struct device *const busdev = i2c_busdev(dev);
90 if (!busdev)
91 return -1;
92
93 if (busdev->ops->ops_i2c_bus) {
94 uint8_t val;
95 const struct i2c_msg msg[] = {
96 {
97 .flags = 0,
98 .slave = dev->path.i2c.device,
99 .buf = &off,
100 .len = sizeof(off),
101 },
102 {
103 .flags = I2C_M_RD,
104 .slave = dev->path.i2c.device,
105 .buf = &val,
106 .len = sizeof(val),
107 },
108 };
109
Frans Hendriksa9caa502021-02-01 11:44:37 +0100110 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, msg,
111 ARRAY_SIZE(msg));
Nico Huber58173862017-08-01 17:09:35 +0200112 if (ret)
113 return ret;
114 else
115 return val;
116 } else if (busdev->ops->ops_smbus_bus->read_byte) {
117 return busdev->ops->ops_smbus_bus->read_byte(dev, off);
Nico Huber58173862017-08-01 17:09:35 +0200118 }
Frans Hendriksa9caa502021-02-01 11:44:37 +0100119
120 printk(BIOS_ERR, "%s Missing ops_smbus_bus->read_byte", dev_path(busdev));
121 return -1;
Nico Huber58173862017-08-01 17:09:35 +0200122}
123
Frans Hendriksa9caa502021-02-01 11:44:37 +0100124int i2c_dev_writeb_at(struct device *const dev, const uint8_t off, const uint8_t val)
Nico Huber58173862017-08-01 17:09:35 +0200125{
126 struct device *const busdev = i2c_busdev(dev);
127 if (!busdev)
128 return -1;
129
130 if (busdev->ops->ops_i2c_bus) {
131 uint8_t buf[] = { off, val };
132 const struct i2c_msg msg = {
133 .flags = 0,
134 .slave = dev->path.i2c.device,
135 .buf = buf,
136 .len = sizeof(buf),
137 };
138 return busdev->ops->ops_i2c_bus->transfer(busdev, &msg, 1);
139 } else if (busdev->ops->ops_smbus_bus->write_byte) {
140 return busdev->ops->ops_smbus_bus->write_byte(dev, off, val);
Nico Huber58173862017-08-01 17:09:35 +0200141 }
Frans Hendriksa9caa502021-02-01 11:44:37 +0100142
143 printk(BIOS_ERR, "%s Missing ops_smbus_bus->write_byte",
144 dev_path(busdev));
145 return -1;
Nico Huber58173862017-08-01 17:09:35 +0200146}
Nico Huber9734af62017-11-01 13:15:33 +0100147
Frans Hendriksa9caa502021-02-01 11:44:37 +0100148int i2c_dev_read_at16(struct device *const dev, uint8_t *const buf, const size_t len,
149 uint16_t off)
Nico Huber9734af62017-11-01 13:15:33 +0100150{
151 struct device *const busdev = i2c_busdev(dev);
152 if (!busdev)
153 return -1;
154
155 if (busdev->ops->ops_i2c_bus) {
156 const struct i2c_msg msg[] = {
157 {
158 .flags = 0,
159 .slave = dev->path.i2c.device,
160 .buf = (uint8_t *)&off,
161 .len = sizeof(off),
162 },
163 {
164 .flags = I2C_M_RD,
165 .slave = dev->path.i2c.device,
166 .buf = buf,
167 .len = len,
168 },
169 };
170
171 write_be16(&off, off);
Frans Hendriksa9caa502021-02-01 11:44:37 +0100172 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, msg,
173 ARRAY_SIZE(msg));
Nico Huber9734af62017-11-01 13:15:33 +0100174 if (ret)
175 return ret;
176 else
177 return len;
178 } else {
179 printk(BIOS_ERR, "%s Missing ops_i2c_bus->transfer", dev_path(busdev));
180 return -1;
181 }
182}