blob: 04b9c27a345ed662cae61d4fff2d807affa47cb1 [file] [log] [blame]
Lei YUab1327c2019-11-04 16:53:39 +08001#include "i2c.hpp"
2
Lei YU9af82a52019-11-06 14:51:22 +08003#include <fcntl.h>
Lei YU92e89eb2019-11-06 18:08:25 +08004#include <sys/ioctl.h>
Lei YU9af82a52019-11-06 14:51:22 +08005#include <sys/stat.h>
6#include <unistd.h>
7
Lei YU92e89eb2019-11-06 18:08:25 +08008#include <cassert>
Lei YU9af82a52019-11-06 14:51:22 +08009#include <cerrno>
10
Lei YU92e89eb2019-11-06 18:08:25 +080011extern "C" {
12#include <i2c/smbus.h>
13#include <linux/i2c-dev.h>
14#include <linux/i2c.h>
15}
16
Lei YUab1327c2019-11-04 16:53:39 +080017namespace i2c
18{
19
Lei YU92e89eb2019-11-06 18:08:25 +080020void I2CDevice::checkReadFuncs(int type)
21{
22 unsigned long funcs;
23
24 /* Check adapter functionality */
25 if (ioctl(fd, I2C_FUNCS, &funcs) < 0)
26 {
27 throw I2CException("Failed to get funcs", busStr, devAddr, errno);
28 }
29
30 switch (type)
31 {
32 case I2C_SMBUS_BYTE:
33 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE))
34 {
35 throw I2CException("Missing SMBUS_READ_BYTE", busStr, devAddr);
36 }
37 break;
38 case I2C_SMBUS_BYTE_DATA:
39 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA))
40 {
41 throw I2CException("Missing SMBUS_READ_BYTE_DATA", busStr,
42 devAddr);
43 }
44 break;
45
46 case I2C_SMBUS_WORD_DATA:
47 if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA))
48 {
49 throw I2CException("Missing SMBUS_READ_WORD_DATA", busStr,
50 devAddr);
51 }
52 break;
53 case I2C_SMBUS_BLOCK_DATA:
54 if (!(funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA))
55 {
56 throw I2CException("Missing SMBUS_READ_BLOCK_DATA", busStr,
57 devAddr);
58 }
59 break;
Lei YU1d103422019-11-29 14:00:02 +080060 case I2C_SMBUS_I2C_BLOCK_DATA:
61 if (!(funcs & I2C_FUNC_SMBUS_READ_I2C_BLOCK))
62 {
63 throw I2CException("Missing I2C_FUNC_SMBUS_READ_I2C_BLOCK",
64 busStr, devAddr);
65 }
66 break;
Lei YU92e89eb2019-11-06 18:08:25 +080067 default:
68 fprintf(stderr, "Unexpected read size type: %d\n", type);
69 assert(false);
70 break;
71 }
72}
73
Lei YU34fb8bd2019-11-07 14:24:20 +080074void I2CDevice::checkWriteFuncs(int type)
75{
76 unsigned long funcs;
77
78 /* Check adapter functionality */
79 if (ioctl(fd, I2C_FUNCS, &funcs) < 0)
80 {
81 throw I2CException("Failed to get funcs", busStr, devAddr, errno);
82 }
83
84 switch (type)
85 {
86 case I2C_SMBUS_BYTE:
87 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE))
88 {
89 throw I2CException("Missing SMBUS_WRITE_BYTE", busStr, devAddr);
90 }
91 break;
92 case I2C_SMBUS_BYTE_DATA:
93 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
94 {
95 throw I2CException("Missing SMBUS_WRITE_BYTE_DATA", busStr,
96 devAddr);
97 }
98 break;
99
100 case I2C_SMBUS_WORD_DATA:
101 if (!(funcs & I2C_FUNC_SMBUS_WRITE_WORD_DATA))
102 {
103 throw I2CException("Missing SMBUS_WRITE_WORD_DATA", busStr,
104 devAddr);
105 }
106 break;
107 case I2C_SMBUS_BLOCK_DATA:
108 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BLOCK_DATA))
109 {
110 throw I2CException("Missing SMBUS_WRITE_BLOCK_DATA", busStr,
111 devAddr);
112 }
113 break;
Lei YU1d103422019-11-29 14:00:02 +0800114 case I2C_SMBUS_I2C_BLOCK_DATA:
115 if (!(funcs & I2C_FUNC_SMBUS_WRITE_I2C_BLOCK))
116 {
117 throw I2CException("Missing I2C_FUNC_SMBUS_WRITE_I2C_BLOCK",
118 busStr, devAddr);
119 }
120 break;
Lei YU34fb8bd2019-11-07 14:24:20 +0800121 default:
122 fprintf(stderr, "Unexpected read size type: %d\n", type);
123 assert(false);
124 }
125}
126
Shawn McCarneyd45a9a62019-12-10 18:35:44 -0600127void I2CDevice::open()
128{
129 if (isOpen())
130 {
131 throw I2CException("Device already open", busStr, devAddr);
132 }
133
134 fd = ::open(busStr.c_str(), O_RDWR);
135 if (fd == -1)
136 {
137 throw I2CException("Failed to open", busStr, devAddr, errno);
138 }
139
140 if (ioctl(fd, I2C_SLAVE, devAddr) < 0)
141 {
142 // Close device since setting slave address failed
143 closeWithoutException();
144
145 throw I2CException("Failed to set I2C_SLAVE", busStr, devAddr, errno);
146 }
147}
148
149void I2CDevice::close()
150{
151 checkIsOpen();
152 if (::close(fd) == -1)
153 {
154 throw I2CException("Failed to close", busStr, devAddr, errno);
155 }
156 fd = INVALID_FD;
157}
158
Lei YUab1327c2019-11-04 16:53:39 +0800159void I2CDevice::read(uint8_t& data)
160{
Shawn McCarneyd45a9a62019-12-10 18:35:44 -0600161 checkIsOpen();
Lei YU92e89eb2019-11-06 18:08:25 +0800162 checkReadFuncs(I2C_SMBUS_BYTE);
163
164 int ret = i2c_smbus_read_byte(fd);
165 if (ret < 0)
166 {
167 throw I2CException("Failed to read byte", busStr, devAddr, errno);
168 }
169 data = static_cast<uint8_t>(ret);
Lei YUab1327c2019-11-04 16:53:39 +0800170}
171
172void I2CDevice::read(uint8_t addr, uint8_t& data)
173{
Shawn McCarneyd45a9a62019-12-10 18:35:44 -0600174 checkIsOpen();
Lei YU92e89eb2019-11-06 18:08:25 +0800175 checkReadFuncs(I2C_SMBUS_BYTE_DATA);
176
177 int ret = i2c_smbus_read_byte_data(fd, addr);
178 if (ret < 0)
179 {
180 throw I2CException("Failed to read byte data", busStr, devAddr, errno);
181 }
182 data = static_cast<uint8_t>(ret);
Lei YUab1327c2019-11-04 16:53:39 +0800183}
184
185void I2CDevice::read(uint8_t addr, uint16_t& data)
186{
Shawn McCarneyd45a9a62019-12-10 18:35:44 -0600187 checkIsOpen();
Lei YU92e89eb2019-11-06 18:08:25 +0800188 checkReadFuncs(I2C_SMBUS_WORD_DATA);
189 int ret = i2c_smbus_read_word_data(fd, addr);
190 if (ret < 0)
191 {
192 throw I2CException("Failed to read word data", busStr, devAddr, errno);
193 }
194 data = static_cast<uint16_t>(ret);
Lei YUab1327c2019-11-04 16:53:39 +0800195}
196
Lei YU1d103422019-11-29 14:00:02 +0800197void I2CDevice::read(uint8_t addr, uint8_t& size, uint8_t* data, Mode mode)
Lei YUab1327c2019-11-04 16:53:39 +0800198{
Shawn McCarneyd45a9a62019-12-10 18:35:44 -0600199 checkIsOpen();
Lei YU1d103422019-11-29 14:00:02 +0800200 int ret;
201 switch (mode)
202 {
203 case Mode::SMBUS:
204 checkReadFuncs(I2C_SMBUS_BLOCK_DATA);
205 ret = i2c_smbus_read_block_data(fd, addr, data);
206 break;
207 case Mode::I2C:
208 checkReadFuncs(I2C_SMBUS_I2C_BLOCK_DATA);
209 ret = i2c_smbus_read_i2c_block_data(fd, addr, size, data);
210 if (ret != size)
211 {
212 throw I2CException("Failed to read i2c block data", busStr,
213 devAddr, errno);
214 }
215 break;
216 }
Lei YU92e89eb2019-11-06 18:08:25 +0800217 if (ret < 0)
218 {
219 throw I2CException("Failed to read block data", busStr, devAddr, errno);
220 }
221 size = static_cast<uint8_t>(ret);
Lei YUab1327c2019-11-04 16:53:39 +0800222}
223
224void I2CDevice::write(uint8_t data)
225{
Shawn McCarneyd45a9a62019-12-10 18:35:44 -0600226 checkIsOpen();
Lei YU34fb8bd2019-11-07 14:24:20 +0800227 checkWriteFuncs(I2C_SMBUS_BYTE);
228
229 if (i2c_smbus_write_byte(fd, data) < 0)
230 {
231 throw I2CException("Failed to write byte", busStr, devAddr, errno);
232 }
Lei YUab1327c2019-11-04 16:53:39 +0800233}
234
235void I2CDevice::write(uint8_t addr, uint8_t data)
236{
Shawn McCarneyd45a9a62019-12-10 18:35:44 -0600237 checkIsOpen();
Lei YU34fb8bd2019-11-07 14:24:20 +0800238 checkWriteFuncs(I2C_SMBUS_BYTE_DATA);
239
240 if (i2c_smbus_write_byte_data(fd, addr, data) < 0)
241 {
242 throw I2CException("Failed to write byte data", busStr, devAddr, errno);
243 }
Lei YUab1327c2019-11-04 16:53:39 +0800244}
245
246void I2CDevice::write(uint8_t addr, uint16_t data)
247{
Shawn McCarneyd45a9a62019-12-10 18:35:44 -0600248 checkIsOpen();
Lei YU34fb8bd2019-11-07 14:24:20 +0800249 checkWriteFuncs(I2C_SMBUS_WORD_DATA);
250
251 if (i2c_smbus_write_word_data(fd, addr, data) < 0)
252 {
253 throw I2CException("Failed to write word data", busStr, devAddr, errno);
254 }
Lei YUab1327c2019-11-04 16:53:39 +0800255}
256
Lei YU1d103422019-11-29 14:00:02 +0800257void I2CDevice::write(uint8_t addr, uint8_t size, const uint8_t* data,
258 Mode mode)
Lei YUab1327c2019-11-04 16:53:39 +0800259{
Shawn McCarneyd45a9a62019-12-10 18:35:44 -0600260 checkIsOpen();
Lei YU1d103422019-11-29 14:00:02 +0800261 int ret;
262 switch (mode)
263 {
264 case Mode::SMBUS:
265 checkWriteFuncs(I2C_SMBUS_BLOCK_DATA);
266 ret = i2c_smbus_write_block_data(fd, addr, size, data);
267 break;
268 case Mode::I2C:
269 checkWriteFuncs(I2C_SMBUS_I2C_BLOCK_DATA);
270 ret = i2c_smbus_write_i2c_block_data(fd, addr, size, data);
271 break;
272 }
273 if (ret < 0)
Lei YU34fb8bd2019-11-07 14:24:20 +0800274 {
275 throw I2CException("Failed to write block data", busStr, devAddr,
276 errno);
277 }
Lei YUab1327c2019-11-04 16:53:39 +0800278}
279
Shawn McCarneyd45a9a62019-12-10 18:35:44 -0600280std::unique_ptr<I2CInterface> I2CDevice::create(uint8_t busId, uint8_t devAddr,
281 InitialState initialState)
Lei YUab1327c2019-11-04 16:53:39 +0800282{
Shawn McCarneyd45a9a62019-12-10 18:35:44 -0600283 std::unique_ptr<I2CDevice> dev(new I2CDevice(busId, devAddr, initialState));
Lei YUab1327c2019-11-04 16:53:39 +0800284 return dev;
285}
286
Shawn McCarneyd45a9a62019-12-10 18:35:44 -0600287std::unique_ptr<I2CInterface> create(uint8_t busId, uint8_t devAddr,
288 I2CInterface::InitialState initialState)
Lei YUab1327c2019-11-04 16:53:39 +0800289{
Shawn McCarneyd45a9a62019-12-10 18:35:44 -0600290 return I2CDevice::create(busId, devAddr, initialState);
Lei YUab1327c2019-11-04 16:53:39 +0800291}
292
293} // namespace i2c