blob: a65cdada895771dbfaed3327abc70d88d3c43e1b [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
51 const int ret = busdev->ops->ops_i2c_bus->
52 transfer(busdev, &msg, 1);
53 if (ret)
54 return ret;
55 else
56 return val;
57 } else if (busdev->ops->ops_smbus_bus->recv_byte) {
58 return busdev->ops->ops_smbus_bus->recv_byte(dev);
59 } else {
60 printk(BIOS_ERR, "%s Missing ops_smbus_bus->recv_byte",
61 dev_path(busdev));
62 return -1;
63 }
64}
65
Aaron Durbin439cee92018-01-22 21:24:35 -070066int i2c_dev_writeb(struct device *const dev, uint8_t val)
Nico Huber58173862017-08-01 17:09:35 +020067{
68 struct device *const busdev = i2c_busdev(dev);
69 if (!busdev)
70 return -1;
71
72 if (busdev->ops->ops_i2c_bus) {
73 const struct i2c_msg msg = {
74 .flags = 0,
75 .slave = dev->path.i2c.device,
76 .buf = &val,
77 .len = sizeof(val),
78 };
79 return busdev->ops->ops_i2c_bus->transfer(busdev, &msg, 1);
80 } else if (busdev->ops->ops_smbus_bus->send_byte) {
81 return busdev->ops->ops_smbus_bus->send_byte(dev, val);
82 } else {
83 printk(BIOS_ERR, "%s Missing ops_smbus_bus->send_byte",
84 dev_path(busdev));
85 return -1;
86 }
87}
88
Aaron Durbin439cee92018-01-22 21:24:35 -070089int i2c_dev_readb_at(struct device *const dev, uint8_t off)
Nico Huber58173862017-08-01 17:09:35 +020090{
91 struct device *const busdev = i2c_busdev(dev);
92 if (!busdev)
93 return -1;
94
95 if (busdev->ops->ops_i2c_bus) {
96 uint8_t val;
97 const struct i2c_msg msg[] = {
98 {
99 .flags = 0,
100 .slave = dev->path.i2c.device,
101 .buf = &off,
102 .len = sizeof(off),
103 },
104 {
105 .flags = I2C_M_RD,
106 .slave = dev->path.i2c.device,
107 .buf = &val,
108 .len = sizeof(val),
109 },
110 };
111
112 const int ret = busdev->ops->ops_i2c_bus->
113 transfer(busdev, msg, ARRAY_SIZE(msg));
114 if (ret)
115 return ret;
116 else
117 return val;
118 } else if (busdev->ops->ops_smbus_bus->read_byte) {
119 return busdev->ops->ops_smbus_bus->read_byte(dev, off);
120 } else {
121 printk(BIOS_ERR, "%s Missing ops_smbus_bus->read_byte",
122 dev_path(busdev));
123 return -1;
124 }
125}
126
Aaron Durbin439cee92018-01-22 21:24:35 -0700127int i2c_dev_writeb_at(struct device *const dev,
128 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);
145 } else {
146 printk(BIOS_ERR, "%s Missing ops_smbus_bus->write_byte",
147 dev_path(busdev));
148 return -1;
149 }
150}
Nico Huber9734af62017-11-01 13:15:33 +0100151
152int i2c_dev_read_at16(struct device *const dev,
153 uint8_t *const buf, const size_t len, uint16_t off)
154{
155 struct device *const busdev = i2c_busdev(dev);
156 if (!busdev)
157 return -1;
158
159 if (busdev->ops->ops_i2c_bus) {
160 const struct i2c_msg msg[] = {
161 {
162 .flags = 0,
163 .slave = dev->path.i2c.device,
164 .buf = (uint8_t *)&off,
165 .len = sizeof(off),
166 },
167 {
168 .flags = I2C_M_RD,
169 .slave = dev->path.i2c.device,
170 .buf = buf,
171 .len = len,
172 },
173 };
174
175 write_be16(&off, off);
176 const int ret = busdev->ops->ops_i2c_bus->transfer(
177 busdev, msg, ARRAY_SIZE(msg));
178 if (ret)
179 return ret;
180 else
181 return len;
182 } else {
183 printk(BIOS_ERR, "%s Missing ops_i2c_bus->transfer", dev_path(busdev));
184 return -1;
185 }
186}