blob: 597a530d88ecdd6dc3f7205bcd588abaab154ebf [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
Frans Hendriks68dc3692021-02-01 11:52:51 +010028 if (!link)
29 printk(BIOS_ALERT, "%s Cannot find I2C or SMBus bus operations", dev_path(dev));
Nico Huber58173862017-08-01 17:09:35 +020030
31 return link;
32}
33
Aaron Durbin439cee92018-01-22 21:24:35 -070034int i2c_dev_readb(struct device *const dev)
Nico Huber58173862017-08-01 17:09:35 +020035{
36 struct device *const busdev = i2c_busdev(dev);
37 if (!busdev)
38 return -1;
39
40 if (busdev->ops->ops_i2c_bus) {
41 uint8_t val;
42 const struct i2c_msg msg = {
43 .flags = I2C_M_RD,
44 .slave = dev->path.i2c.device,
45 .buf = &val,
46 .len = sizeof(val),
47 };
48
Frans Hendriksa9caa502021-02-01 11:44:37 +010049 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, &msg, 1);
Nico Huber58173862017-08-01 17:09:35 +020050 if (ret)
51 return ret;
52 else
53 return val;
54 } else if (busdev->ops->ops_smbus_bus->recv_byte) {
55 return busdev->ops->ops_smbus_bus->recv_byte(dev);
Nico Huber58173862017-08-01 17:09:35 +020056 }
Frans Hendriksa9caa502021-02-01 11:44:37 +010057
58 printk(BIOS_ERR, "%s Missing ops_smbus_bus->recv_byte", dev_path(busdev));
59 return -1;
Nico Huber58173862017-08-01 17:09:35 +020060}
61
Aaron Durbin439cee92018-01-22 21:24:35 -070062int i2c_dev_writeb(struct device *const dev, uint8_t val)
Nico Huber58173862017-08-01 17:09:35 +020063{
64 struct device *const busdev = i2c_busdev(dev);
65 if (!busdev)
66 return -1;
67
68 if (busdev->ops->ops_i2c_bus) {
69 const struct i2c_msg msg = {
70 .flags = 0,
71 .slave = dev->path.i2c.device,
72 .buf = &val,
73 .len = sizeof(val),
74 };
75 return busdev->ops->ops_i2c_bus->transfer(busdev, &msg, 1);
76 } else if (busdev->ops->ops_smbus_bus->send_byte) {
77 return busdev->ops->ops_smbus_bus->send_byte(dev, val);
Nico Huber58173862017-08-01 17:09:35 +020078 }
Frans Hendriksa9caa502021-02-01 11:44:37 +010079
Frans Hendriks68dc3692021-02-01 11:52:51 +010080 printk(BIOS_ERR, "%s Missing ops_smbus_bus->send_byte", dev_path(busdev));
Frans Hendriksa9caa502021-02-01 11:44:37 +010081 return -1;
Nico Huber58173862017-08-01 17:09:35 +020082}
83
Aaron Durbin439cee92018-01-22 21:24:35 -070084int i2c_dev_readb_at(struct device *const dev, uint8_t off)
Nico Huber58173862017-08-01 17:09:35 +020085{
86 struct device *const busdev = i2c_busdev(dev);
87 if (!busdev)
88 return -1;
89
90 if (busdev->ops->ops_i2c_bus) {
91 uint8_t val;
92 const struct i2c_msg msg[] = {
93 {
94 .flags = 0,
95 .slave = dev->path.i2c.device,
96 .buf = &off,
97 .len = sizeof(off),
98 },
99 {
100 .flags = I2C_M_RD,
101 .slave = dev->path.i2c.device,
102 .buf = &val,
103 .len = sizeof(val),
104 },
105 };
106
Frans Hendriksa9caa502021-02-01 11:44:37 +0100107 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, msg,
108 ARRAY_SIZE(msg));
Nico Huber58173862017-08-01 17:09:35 +0200109 if (ret)
110 return ret;
111 else
112 return val;
113 } else if (busdev->ops->ops_smbus_bus->read_byte) {
114 return busdev->ops->ops_smbus_bus->read_byte(dev, off);
Nico Huber58173862017-08-01 17:09:35 +0200115 }
Frans Hendriksa9caa502021-02-01 11:44:37 +0100116
117 printk(BIOS_ERR, "%s Missing ops_smbus_bus->read_byte", dev_path(busdev));
118 return -1;
Nico Huber58173862017-08-01 17:09:35 +0200119}
120
Frans Hendriksa9caa502021-02-01 11:44:37 +0100121int i2c_dev_writeb_at(struct device *const dev, const uint8_t off, const uint8_t val)
Nico Huber58173862017-08-01 17:09:35 +0200122{
123 struct device *const busdev = i2c_busdev(dev);
124 if (!busdev)
125 return -1;
126
127 if (busdev->ops->ops_i2c_bus) {
128 uint8_t buf[] = { off, val };
129 const struct i2c_msg msg = {
130 .flags = 0,
131 .slave = dev->path.i2c.device,
132 .buf = buf,
133 .len = sizeof(buf),
134 };
135 return busdev->ops->ops_i2c_bus->transfer(busdev, &msg, 1);
136 } else if (busdev->ops->ops_smbus_bus->write_byte) {
137 return busdev->ops->ops_smbus_bus->write_byte(dev, off, val);
Nico Huber58173862017-08-01 17:09:35 +0200138 }
Frans Hendriksa9caa502021-02-01 11:44:37 +0100139
Frans Hendriks68dc3692021-02-01 11:52:51 +0100140 printk(BIOS_ERR, "%s Missing ops_smbus_bus->write_byte", dev_path(busdev));
Frans Hendriksa9caa502021-02-01 11:44:37 +0100141 return -1;
Nico Huber58173862017-08-01 17:09:35 +0200142}
Nico Huber9734af62017-11-01 13:15:33 +0100143
Frans Hendriksa9caa502021-02-01 11:44:37 +0100144int i2c_dev_read_at16(struct device *const dev, uint8_t *const buf, const size_t len,
145 uint16_t off)
Nico Huber9734af62017-11-01 13:15:33 +0100146{
147 struct device *const busdev = i2c_busdev(dev);
148 if (!busdev)
149 return -1;
150
151 if (busdev->ops->ops_i2c_bus) {
152 const struct i2c_msg msg[] = {
153 {
154 .flags = 0,
155 .slave = dev->path.i2c.device,
156 .buf = (uint8_t *)&off,
157 .len = sizeof(off),
158 },
159 {
160 .flags = I2C_M_RD,
161 .slave = dev->path.i2c.device,
162 .buf = buf,
163 .len = len,
164 },
165 };
166
167 write_be16(&off, off);
Frans Hendriksa9caa502021-02-01 11:44:37 +0100168 const int ret = busdev->ops->ops_i2c_bus->transfer(busdev, msg,
169 ARRAY_SIZE(msg));
Nico Huber9734af62017-11-01 13:15:33 +0100170 if (ret)
171 return ret;
172 else
173 return len;
174 } else {
175 printk(BIOS_ERR, "%s Missing ops_i2c_bus->transfer", dev_path(busdev));
176 return -1;
177 }
178}