xref: /openbmc/phosphor-power/tools/i2c/i2c.cpp (revision 34fb8bda)
1 #include "i2c.hpp"
2 
3 #include <fcntl.h>
4 #include <sys/ioctl.h>
5 #include <sys/stat.h>
6 #include <unistd.h>
7 
8 #include <cassert>
9 #include <cerrno>
10 
11 extern "C" {
12 #include <i2c/smbus.h>
13 #include <linux/i2c-dev.h>
14 #include <linux/i2c.h>
15 }
16 
17 namespace i2c
18 {
19 
20 void 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     }
27 
28     if (ioctl(fd, I2C_SLAVE, devAddr) < 0)
29     {
30         throw I2CException("Failed to set I2C_SLAVE", busStr, devAddr, errno);
31     }
32 }
33 
34 void I2CDevice::close()
35 {
36     ::close(fd);
37 }
38 
39 void 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;
79         default:
80             fprintf(stderr, "Unexpected read size type: %d\n", type);
81             assert(false);
82             break;
83     }
84 }
85 
86 void I2CDevice::checkWriteFuncs(int type)
87 {
88     unsigned long funcs;
89 
90     /* Check adapter functionality */
91     if (ioctl(fd, I2C_FUNCS, &funcs) < 0)
92     {
93         throw I2CException("Failed to get funcs", busStr, devAddr, errno);
94     }
95 
96     switch (type)
97     {
98         case I2C_SMBUS_BYTE:
99             if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE))
100             {
101                 throw I2CException("Missing SMBUS_WRITE_BYTE", busStr, devAddr);
102             }
103             break;
104         case I2C_SMBUS_BYTE_DATA:
105             if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
106             {
107                 throw I2CException("Missing SMBUS_WRITE_BYTE_DATA", busStr,
108                                    devAddr);
109             }
110             break;
111 
112         case I2C_SMBUS_WORD_DATA:
113             if (!(funcs & I2C_FUNC_SMBUS_WRITE_WORD_DATA))
114             {
115                 throw I2CException("Missing SMBUS_WRITE_WORD_DATA", busStr,
116                                    devAddr);
117             }
118             break;
119         case I2C_SMBUS_BLOCK_DATA:
120             if (!(funcs & I2C_FUNC_SMBUS_WRITE_BLOCK_DATA))
121             {
122                 throw I2CException("Missing SMBUS_WRITE_BLOCK_DATA", busStr,
123                                    devAddr);
124             }
125             break;
126         default:
127             fprintf(stderr, "Unexpected read size type: %d\n", type);
128             assert(false);
129     }
130 }
131 
132 void I2CDevice::read(uint8_t& data)
133 {
134     checkReadFuncs(I2C_SMBUS_BYTE);
135 
136     int ret = i2c_smbus_read_byte(fd);
137     if (ret < 0)
138     {
139         throw I2CException("Failed to read byte", busStr, devAddr, errno);
140     }
141     data = static_cast<uint8_t>(ret);
142 }
143 
144 void I2CDevice::read(uint8_t addr, uint8_t& data)
145 {
146     checkReadFuncs(I2C_SMBUS_BYTE_DATA);
147 
148     int ret = i2c_smbus_read_byte_data(fd, addr);
149     if (ret < 0)
150     {
151         throw I2CException("Failed to read byte data", busStr, devAddr, errno);
152     }
153     data = static_cast<uint8_t>(ret);
154 }
155 
156 void I2CDevice::read(uint8_t addr, uint16_t& data)
157 {
158     checkReadFuncs(I2C_SMBUS_WORD_DATA);
159     int ret = i2c_smbus_read_word_data(fd, addr);
160     if (ret < 0)
161     {
162         throw I2CException("Failed to read word data", busStr, devAddr, errno);
163     }
164     data = static_cast<uint16_t>(ret);
165 }
166 
167 void I2CDevice::read(uint8_t addr, uint8_t& size, uint8_t* data)
168 {
169     checkReadFuncs(I2C_SMBUS_BLOCK_DATA);
170 
171     int ret = i2c_smbus_read_block_data(fd, addr, data);
172     if (ret < 0)
173     {
174         throw I2CException("Failed to read block data", busStr, devAddr, errno);
175     }
176     size = static_cast<uint8_t>(ret);
177 }
178 
179 void I2CDevice::write(uint8_t data)
180 {
181     checkWriteFuncs(I2C_SMBUS_BYTE);
182 
183     if (i2c_smbus_write_byte(fd, data) < 0)
184     {
185         throw I2CException("Failed to write byte", busStr, devAddr, errno);
186     }
187 }
188 
189 void I2CDevice::write(uint8_t addr, uint8_t data)
190 {
191     checkWriteFuncs(I2C_SMBUS_BYTE_DATA);
192 
193     if (i2c_smbus_write_byte_data(fd, addr, data) < 0)
194     {
195         throw I2CException("Failed to write byte data", busStr, devAddr, errno);
196     }
197 }
198 
199 void I2CDevice::write(uint8_t addr, uint16_t data)
200 {
201     checkWriteFuncs(I2C_SMBUS_WORD_DATA);
202 
203     if (i2c_smbus_write_word_data(fd, addr, data) < 0)
204     {
205         throw I2CException("Failed to write word data", busStr, devAddr, errno);
206     }
207 }
208 
209 void I2CDevice::write(uint8_t addr, uint8_t size, const uint8_t* data)
210 {
211     checkWriteFuncs(I2C_SMBUS_BLOCK_DATA);
212 
213     if (i2c_smbus_write_block_data(fd, addr, size, data) < 0)
214     {
215         throw I2CException("Failed to write block data", busStr, devAddr,
216                            errno);
217     }
218 }
219 
220 std::unique_ptr<I2CInterface> I2CDevice::create(uint8_t busId, uint8_t devAddr)
221 {
222     std::unique_ptr<I2CDevice> dev(new I2CDevice(busId, devAddr));
223     return dev;
224 }
225 
226 std::unique_ptr<I2CInterface> create(uint8_t busId, uint8_t devAddr)
227 {
228     return I2CDevice::create(busId, devAddr);
229 }
230 
231 } // namespace i2c
232