blob: 624bc60cb010871394511ddb04eced75b708c772 [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 YU9af82a52019-11-06 14:51:22 +080020void I2CDevice::open()
21{
22 fd = ::open(busStr.c_str(), O_RDWR);
23 if (fd == -1)
24 {
25 throw I2CException("Failed to open", busStr, devAddr, errno);
26 }
Lei YU92e89eb2019-11-06 18:08:25 +080027
28 if (ioctl(fd, I2C_SLAVE, devAddr) < 0)
29 {
30 throw I2CException("Failed to set I2C_SLAVE", busStr, devAddr, errno);
31 }
Lei YU9af82a52019-11-06 14:51:22 +080032}
33
34void I2CDevice::close()
35{
36 ::close(fd);
37}
38
Lei YU92e89eb2019-11-06 18:08:25 +080039void I2CDevice::checkReadFuncs(int type)
40{
41 unsigned long funcs;
42
43 /* Check adapter functionality */
44 if (ioctl(fd, I2C_FUNCS, &funcs) < 0)
45 {
46 throw I2CException("Failed to get funcs", busStr, devAddr, errno);
47 }
48
49 switch (type)
50 {
51 case I2C_SMBUS_BYTE:
52 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE))
53 {
54 throw I2CException("Missing SMBUS_READ_BYTE", busStr, devAddr);
55 }
56 break;
57 case I2C_SMBUS_BYTE_DATA:
58 if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA))
59 {
60 throw I2CException("Missing SMBUS_READ_BYTE_DATA", busStr,
61 devAddr);
62 }
63 break;
64
65 case I2C_SMBUS_WORD_DATA:
66 if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA))
67 {
68 throw I2CException("Missing SMBUS_READ_WORD_DATA", busStr,
69 devAddr);
70 }
71 break;
72 case I2C_SMBUS_BLOCK_DATA:
73 if (!(funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA))
74 {
75 throw I2CException("Missing SMBUS_READ_BLOCK_DATA", busStr,
76 devAddr);
77 }
78 break;
Lei YU1d103422019-11-29 14:00:02 +080079 case I2C_SMBUS_I2C_BLOCK_DATA:
80 if (!(funcs & I2C_FUNC_SMBUS_READ_I2C_BLOCK))
81 {
82 throw I2CException("Missing I2C_FUNC_SMBUS_READ_I2C_BLOCK",
83 busStr, devAddr);
84 }
85 break;
Lei YU92e89eb2019-11-06 18:08:25 +080086 default:
87 fprintf(stderr, "Unexpected read size type: %d\n", type);
88 assert(false);
89 break;
90 }
91}
92
Lei YU34fb8bd2019-11-07 14:24:20 +080093void I2CDevice::checkWriteFuncs(int type)
94{
95 unsigned long funcs;
96
97 /* Check adapter functionality */
98 if (ioctl(fd, I2C_FUNCS, &funcs) < 0)
99 {
100 throw I2CException("Failed to get funcs", busStr, devAddr, errno);
101 }
102
103 switch (type)
104 {
105 case I2C_SMBUS_BYTE:
106 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE))
107 {
108 throw I2CException("Missing SMBUS_WRITE_BYTE", busStr, devAddr);
109 }
110 break;
111 case I2C_SMBUS_BYTE_DATA:
112 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
113 {
114 throw I2CException("Missing SMBUS_WRITE_BYTE_DATA", busStr,
115 devAddr);
116 }
117 break;
118
119 case I2C_SMBUS_WORD_DATA:
120 if (!(funcs & I2C_FUNC_SMBUS_WRITE_WORD_DATA))
121 {
122 throw I2CException("Missing SMBUS_WRITE_WORD_DATA", busStr,
123 devAddr);
124 }
125 break;
126 case I2C_SMBUS_BLOCK_DATA:
127 if (!(funcs & I2C_FUNC_SMBUS_WRITE_BLOCK_DATA))
128 {
129 throw I2CException("Missing SMBUS_WRITE_BLOCK_DATA", busStr,
130 devAddr);
131 }
132 break;
Lei YU1d103422019-11-29 14:00:02 +0800133 case I2C_SMBUS_I2C_BLOCK_DATA:
134 if (!(funcs & I2C_FUNC_SMBUS_WRITE_I2C_BLOCK))
135 {
136 throw I2CException("Missing I2C_FUNC_SMBUS_WRITE_I2C_BLOCK",
137 busStr, devAddr);
138 }
139 break;
Lei YU34fb8bd2019-11-07 14:24:20 +0800140 default:
141 fprintf(stderr, "Unexpected read size type: %d\n", type);
142 assert(false);
143 }
144}
145
Lei YUab1327c2019-11-04 16:53:39 +0800146void I2CDevice::read(uint8_t& data)
147{
Lei YU92e89eb2019-11-06 18:08:25 +0800148 checkReadFuncs(I2C_SMBUS_BYTE);
149
150 int ret = i2c_smbus_read_byte(fd);
151 if (ret < 0)
152 {
153 throw I2CException("Failed to read byte", busStr, devAddr, errno);
154 }
155 data = static_cast<uint8_t>(ret);
Lei YUab1327c2019-11-04 16:53:39 +0800156}
157
158void I2CDevice::read(uint8_t addr, uint8_t& data)
159{
Lei YU92e89eb2019-11-06 18:08:25 +0800160 checkReadFuncs(I2C_SMBUS_BYTE_DATA);
161
162 int ret = i2c_smbus_read_byte_data(fd, addr);
163 if (ret < 0)
164 {
165 throw I2CException("Failed to read byte data", busStr, devAddr, errno);
166 }
167 data = static_cast<uint8_t>(ret);
Lei YUab1327c2019-11-04 16:53:39 +0800168}
169
170void I2CDevice::read(uint8_t addr, uint16_t& data)
171{
Lei YU92e89eb2019-11-06 18:08:25 +0800172 checkReadFuncs(I2C_SMBUS_WORD_DATA);
173 int ret = i2c_smbus_read_word_data(fd, addr);
174 if (ret < 0)
175 {
176 throw I2CException("Failed to read word data", busStr, devAddr, errno);
177 }
178 data = static_cast<uint16_t>(ret);
Lei YUab1327c2019-11-04 16:53:39 +0800179}
180
Lei YU1d103422019-11-29 14:00:02 +0800181void I2CDevice::read(uint8_t addr, uint8_t& size, uint8_t* data, Mode mode)
Lei YUab1327c2019-11-04 16:53:39 +0800182{
Lei YU1d103422019-11-29 14:00:02 +0800183 int ret;
184 switch (mode)
185 {
186 case Mode::SMBUS:
187 checkReadFuncs(I2C_SMBUS_BLOCK_DATA);
188 ret = i2c_smbus_read_block_data(fd, addr, data);
189 break;
190 case Mode::I2C:
191 checkReadFuncs(I2C_SMBUS_I2C_BLOCK_DATA);
192 ret = i2c_smbus_read_i2c_block_data(fd, addr, size, data);
193 if (ret != size)
194 {
195 throw I2CException("Failed to read i2c block data", busStr,
196 devAddr, errno);
197 }
198 break;
199 }
Lei YU92e89eb2019-11-06 18:08:25 +0800200 if (ret < 0)
201 {
202 throw I2CException("Failed to read block data", busStr, devAddr, errno);
203 }
204 size = static_cast<uint8_t>(ret);
Lei YUab1327c2019-11-04 16:53:39 +0800205}
206
207void I2CDevice::write(uint8_t data)
208{
Lei YU34fb8bd2019-11-07 14:24:20 +0800209 checkWriteFuncs(I2C_SMBUS_BYTE);
210
211 if (i2c_smbus_write_byte(fd, data) < 0)
212 {
213 throw I2CException("Failed to write byte", busStr, devAddr, errno);
214 }
Lei YUab1327c2019-11-04 16:53:39 +0800215}
216
217void I2CDevice::write(uint8_t addr, uint8_t data)
218{
Lei YU34fb8bd2019-11-07 14:24:20 +0800219 checkWriteFuncs(I2C_SMBUS_BYTE_DATA);
220
221 if (i2c_smbus_write_byte_data(fd, addr, data) < 0)
222 {
223 throw I2CException("Failed to write byte data", busStr, devAddr, errno);
224 }
Lei YUab1327c2019-11-04 16:53:39 +0800225}
226
227void I2CDevice::write(uint8_t addr, uint16_t data)
228{
Lei YU34fb8bd2019-11-07 14:24:20 +0800229 checkWriteFuncs(I2C_SMBUS_WORD_DATA);
230
231 if (i2c_smbus_write_word_data(fd, addr, data) < 0)
232 {
233 throw I2CException("Failed to write word data", busStr, devAddr, errno);
234 }
Lei YUab1327c2019-11-04 16:53:39 +0800235}
236
Lei YU1d103422019-11-29 14:00:02 +0800237void I2CDevice::write(uint8_t addr, uint8_t size, const uint8_t* data,
238 Mode mode)
Lei YUab1327c2019-11-04 16:53:39 +0800239{
Lei YU1d103422019-11-29 14:00:02 +0800240 int ret;
241 switch (mode)
242 {
243 case Mode::SMBUS:
244 checkWriteFuncs(I2C_SMBUS_BLOCK_DATA);
245 ret = i2c_smbus_write_block_data(fd, addr, size, data);
246 break;
247 case Mode::I2C:
248 checkWriteFuncs(I2C_SMBUS_I2C_BLOCK_DATA);
249 ret = i2c_smbus_write_i2c_block_data(fd, addr, size, data);
250 break;
251 }
252 if (ret < 0)
Lei YU34fb8bd2019-11-07 14:24:20 +0800253 {
254 throw I2CException("Failed to write block data", busStr, devAddr,
255 errno);
256 }
Lei YUab1327c2019-11-04 16:53:39 +0800257}
258
259std::unique_ptr<I2CInterface> I2CDevice::create(uint8_t busId, uint8_t devAddr)
260{
261 std::unique_ptr<I2CDevice> dev(new I2CDevice(busId, devAddr));
262 return dev;
263}
264
265std::unique_ptr<I2CInterface> create(uint8_t busId, uint8_t devAddr)
266{
267 return I2CDevice::create(busId, devAddr);
268}
269
270} // namespace i2c