xref: /openbmc/phosphor-power/tools/i2c/i2c.cpp (revision 92261f88729b618b1c31d20f28328a8aff73b83b)
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  #include <cstring>
11  #include <format>
12  
13  extern "C"
14  {
15  #include <i2c/smbus.h>
16  #include <linux/i2c-dev.h>
17  #include <linux/i2c.h>
18  }
19  
20  namespace i2c
21  {
22  
23  // Maximum number of data bytes in a block read/block write/block process call
24  // in SMBus 3.0. The maximum was 32 data bytes in SMBus 2.0 and earlier.
25  constexpr uint8_t I2C_SMBUS3_BLOCK_MAX = 255;
26  
getFuncs()27  unsigned long I2CDevice::getFuncs()
28  {
29      // If functionality has not been cached
30      if (cachedFuncs == NO_FUNCS)
31      {
32          // Get functionality from adapter
33          int ret = 0, retries = 0;
34          do
35          {
36              ret = ioctl(fd, I2C_FUNCS, &cachedFuncs);
37          } while ((ret < 0) && (++retries <= maxRetries));
38  
39          if (ret < 0)
40          {
41              cachedFuncs = NO_FUNCS;
42              throw I2CException("Failed to get funcs", busStr, devAddr, errno);
43          }
44      }
45  
46      return cachedFuncs;
47  }
48  
checkReadFuncs(int type)49  void I2CDevice::checkReadFuncs(int type)
50  {
51      unsigned long funcs = getFuncs();
52      switch (type)
53      {
54          case I2C_SMBUS_BYTE:
55              if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE))
56              {
57                  throw I2CException("Missing SMBUS_READ_BYTE", busStr, devAddr);
58              }
59              break;
60          case I2C_SMBUS_BYTE_DATA:
61              if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE_DATA))
62              {
63                  throw I2CException("Missing SMBUS_READ_BYTE_DATA", busStr,
64                                     devAddr);
65              }
66              break;
67          case I2C_SMBUS_WORD_DATA:
68              if (!(funcs & I2C_FUNC_SMBUS_READ_WORD_DATA))
69              {
70                  throw I2CException("Missing SMBUS_READ_WORD_DATA", busStr,
71                                     devAddr);
72              }
73              break;
74          case I2C_SMBUS_BLOCK_DATA:
75              if (!(funcs & I2C_FUNC_SMBUS_READ_BLOCK_DATA))
76              {
77                  throw I2CException("Missing SMBUS_READ_BLOCK_DATA", busStr,
78                                     devAddr);
79              }
80              break;
81          case I2C_SMBUS_I2C_BLOCK_DATA:
82              if (!(funcs & I2C_FUNC_SMBUS_READ_I2C_BLOCK))
83              {
84                  throw I2CException("Missing I2C_FUNC_SMBUS_READ_I2C_BLOCK",
85                                     busStr, devAddr);
86              }
87              break;
88          default:
89              fprintf(stderr, "Unexpected read size type: %d\n", type);
90              assert(false);
91              break;
92      }
93  }
94  
checkWriteFuncs(int type)95  void I2CDevice::checkWriteFuncs(int type)
96  {
97      unsigned long funcs = getFuncs();
98      switch (type)
99      {
100          case I2C_SMBUS_BYTE:
101              if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE))
102              {
103                  throw I2CException("Missing SMBUS_WRITE_BYTE", busStr, devAddr);
104              }
105              break;
106          case I2C_SMBUS_BYTE_DATA:
107              if (!(funcs & I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
108              {
109                  throw I2CException("Missing SMBUS_WRITE_BYTE_DATA", busStr,
110                                     devAddr);
111              }
112              break;
113          case I2C_SMBUS_WORD_DATA:
114              if (!(funcs & I2C_FUNC_SMBUS_WRITE_WORD_DATA))
115              {
116                  throw I2CException("Missing SMBUS_WRITE_WORD_DATA", busStr,
117                                     devAddr);
118              }
119              break;
120          case I2C_SMBUS_BLOCK_DATA:
121              if (!(funcs & I2C_FUNC_SMBUS_WRITE_BLOCK_DATA))
122              {
123                  throw I2CException("Missing SMBUS_WRITE_BLOCK_DATA", busStr,
124                                     devAddr);
125              }
126              break;
127          case I2C_SMBUS_I2C_BLOCK_DATA:
128              if (!(funcs & I2C_FUNC_SMBUS_WRITE_I2C_BLOCK))
129              {
130                  throw I2CException("Missing I2C_FUNC_SMBUS_WRITE_I2C_BLOCK",
131                                     busStr, devAddr);
132              }
133              break;
134          case I2C_SMBUS_PROC_CALL:
135              if (!(funcs & I2C_FUNC_SMBUS_PROC_CALL))
136              {
137                  throw I2CException("Missing I2C_FUNC_SMBUS_PROC_CALL", busStr,
138                                     devAddr);
139              }
140              break;
141          case I2C_SMBUS_BLOCK_PROC_CALL:
142              if (!(funcs & I2C_FUNC_SMBUS_BLOCK_PROC_CALL))
143              {
144                  throw I2CException("Missing I2C_FUNC_SMBUS_BLOCK_PROC_CALL",
145                                     busStr, devAddr);
146              }
147              break;
148          default:
149              fprintf(stderr, "Unexpected write size type: %d\n", type);
150              assert(false);
151      }
152  }
153  
processCallSMBus(uint8_t addr,uint8_t writeSize,const uint8_t * writeData,uint8_t & readSize,uint8_t * readData)154  void I2CDevice::processCallSMBus(uint8_t addr, uint8_t writeSize,
155                                   const uint8_t* writeData, uint8_t& readSize,
156                                   uint8_t* readData)
157  {
158      int ret = 0, retries = 0;
159      uint8_t buffer[I2C_SMBUS_BLOCK_MAX];
160      do
161      {
162          // Copy write data to buffer. Buffer is also used by SMBus function to
163          // store the data read from the device.
164          std::memcpy(buffer, writeData, writeSize);
165          ret = i2c_smbus_block_process_call(fd, addr, writeSize, buffer);
166      } while ((ret < 0) && (++retries <= maxRetries));
167  
168      if (ret < 0)
169      {
170          throw I2CException("Failed to execute block process call", busStr,
171                             devAddr, errno);
172      }
173  
174      readSize = static_cast<uint8_t>(ret);
175      std::memcpy(readData, buffer, readSize);
176  }
177  
processCallI2C(uint8_t addr,uint8_t writeSize,const uint8_t * writeData,uint8_t & readSize,uint8_t * readData)178  void I2CDevice::processCallI2C(uint8_t addr, uint8_t writeSize,
179                                 const uint8_t* writeData, uint8_t& readSize,
180                                 uint8_t* readData)
181  {
182      // Buffer for block write. Linux supports SMBus 3.0 max size for block
183      // write. Buffer will contain register address, byte count, and data bytes.
184      constexpr uint16_t writeBufferSize = I2C_SMBUS3_BLOCK_MAX + 2;
185      uint8_t writeBuffer[writeBufferSize];
186  
187      // Buffer for block read. Linux supports smaller SMBus 2.0 max size for
188      // block read. After ioctl() buffer will contain byte count and data bytes.
189      constexpr uint16_t readBufferSize = I2C_SMBUS_BLOCK_MAX + 1;
190      uint8_t readBuffer[readBufferSize];
191  
192      // i2c_msg and i2c_rdwr_ioctl_data structs required for ioctl()
193      constexpr unsigned int numMessages = 2;
194      struct i2c_msg messages[numMessages];
195      struct i2c_rdwr_ioctl_data readWriteData;
196      readWriteData.msgs = messages;
197      readWriteData.nmsgs = numMessages;
198  
199      int ret = 0, retries = 0;
200      do
201      {
202          // Initialize write buffer with reg addr, byte count, and data bytes
203          writeBuffer[0] = addr;
204          writeBuffer[1] = writeSize;
205          std::memcpy(&(writeBuffer[2]), writeData, writeSize);
206  
207          // Initialize first i2c_msg to perform block write
208          messages[0].addr = devAddr;
209          messages[0].flags = 0;
210          messages[0].len = writeSize + 2; // 2 == reg addr + byte count
211          messages[0].buf = writeBuffer;
212  
213          // Initialize read buffer. Set first byte to number of "extra bytes"
214          // that will be read in addition to data bytes. Set to 1 since only
215          // extra byte is the byte count.
216          readBuffer[0] = 1;
217  
218          // Initialize second i2c_msg to perform block read. Linux requires the
219          // len field to be set to the buffer size.
220          messages[1].addr = devAddr;
221          messages[1].flags = I2C_M_RD | I2C_M_RECV_LEN;
222          messages[1].len = readBufferSize;
223          messages[1].buf = readBuffer;
224  
225          // Call ioctl() to send the I2C messages
226          ret = ioctl(fd, I2C_RDWR, &readWriteData);
227      } while ((ret != numMessages) && (++retries <= maxRetries));
228  
229      if (ret < 0)
230      {
231          throw I2CException("Failed to execute I2C block process call", busStr,
232                             devAddr, errno);
233      }
234      else if (ret != numMessages)
235      {
236          throw I2CException(
237              std::format(
238                  "Failed to execute I2C block process call: {} messages sent",
239                  ret),
240              busStr, devAddr);
241      }
242  
243      // Read size is in first byte; copy remaining data bytes to readData param
244      readSize = readBuffer[0];
245      std::memcpy(readData, &(readBuffer[1]), readSize);
246  }
247  
open()248  void I2CDevice::open()
249  {
250      if (isOpen())
251      {
252          throw I2CException("Device already open", busStr, devAddr);
253      }
254  
255      int retries = 0;
256      do
257      {
258          fd = ::open(busStr.c_str(), O_RDWR);
259      } while ((fd == -1) && (++retries <= maxRetries));
260  
261      if (fd == -1)
262      {
263          throw I2CException("Failed to open", busStr, devAddr, errno);
264      }
265  
266      retries = 0;
267      int ret = 0;
268      do
269      {
270          ret = ioctl(fd, I2C_SLAVE, devAddr);
271      } while ((ret < 0) && (++retries <= maxRetries));
272  
273      if (ret < 0)
274      {
275          // Close device since setting slave address failed
276          closeWithoutException();
277  
278          throw I2CException("Failed to set I2C_SLAVE", busStr, devAddr, errno);
279      }
280  }
281  
close()282  void I2CDevice::close()
283  {
284      checkIsOpen();
285  
286      int ret = 0, retries = 0;
287      do
288      {
289          ret = ::close(fd);
290      } while ((ret == -1) && (++retries <= maxRetries));
291  
292      if (ret == -1)
293      {
294          throw I2CException("Failed to close", busStr, devAddr, errno);
295      }
296  
297      fd = INVALID_FD;
298      cachedFuncs = NO_FUNCS;
299  }
300  
read(uint8_t & data)301  void I2CDevice::read(uint8_t& data)
302  {
303      checkIsOpen();
304      checkReadFuncs(I2C_SMBUS_BYTE);
305  
306      int ret = 0, retries = 0;
307      do
308      {
309          ret = i2c_smbus_read_byte(fd);
310      } while ((ret < 0) && (++retries <= maxRetries));
311  
312      if (ret < 0)
313      {
314          throw I2CException("Failed to read byte", busStr, devAddr, errno);
315      }
316  
317      data = static_cast<uint8_t>(ret);
318  }
319  
read(uint8_t addr,uint8_t & data)320  void I2CDevice::read(uint8_t addr, uint8_t& data)
321  {
322      checkIsOpen();
323      checkReadFuncs(I2C_SMBUS_BYTE_DATA);
324  
325      int ret = 0, retries = 0;
326      do
327      {
328          ret = i2c_smbus_read_byte_data(fd, addr);
329      } while ((ret < 0) && (++retries <= maxRetries));
330  
331      if (ret < 0)
332      {
333          throw I2CException("Failed to read byte data", busStr, devAddr, errno);
334      }
335  
336      data = static_cast<uint8_t>(ret);
337  }
338  
read(uint8_t addr,uint16_t & data)339  void I2CDevice::read(uint8_t addr, uint16_t& data)
340  {
341      checkIsOpen();
342      checkReadFuncs(I2C_SMBUS_WORD_DATA);
343  
344      int ret = 0, retries = 0;
345      do
346      {
347          ret = i2c_smbus_read_word_data(fd, addr);
348      } while ((ret < 0) && (++retries <= maxRetries));
349  
350      if (ret < 0)
351      {
352          throw I2CException("Failed to read word data", busStr, devAddr, errno);
353      }
354  
355      data = static_cast<uint16_t>(ret);
356  }
357  
read(uint8_t addr,uint8_t & size,uint8_t * data,Mode mode)358  void I2CDevice::read(uint8_t addr, uint8_t& size, uint8_t* data, Mode mode)
359  {
360      checkIsOpen();
361  
362      int ret = -1, retries = 0;
363      switch (mode)
364      {
365          case Mode::SMBUS:
366              checkReadFuncs(I2C_SMBUS_BLOCK_DATA);
367              do
368              {
369                  ret = i2c_smbus_read_block_data(fd, addr, data);
370              } while ((ret < 0) && (++retries <= maxRetries));
371              break;
372          case Mode::I2C:
373              checkReadFuncs(I2C_SMBUS_I2C_BLOCK_DATA);
374              do
375              {
376                  ret = i2c_smbus_read_i2c_block_data(fd, addr, size, data);
377              } while ((ret < 0) && (++retries <= maxRetries));
378              if (ret != size)
379              {
380                  throw I2CException("Failed to read i2c block data", busStr,
381                                     devAddr, errno);
382              }
383              break;
384      }
385  
386      if (ret < 0)
387      {
388          throw I2CException("Failed to read block data", busStr, devAddr, errno);
389      }
390  
391      size = static_cast<uint8_t>(ret);
392  }
393  
write(uint8_t data)394  void I2CDevice::write(uint8_t data)
395  {
396      checkIsOpen();
397      checkWriteFuncs(I2C_SMBUS_BYTE);
398  
399      int ret = 0, retries = 0;
400      do
401      {
402          ret = i2c_smbus_write_byte(fd, data);
403      } while ((ret < 0) && (++retries <= maxRetries));
404  
405      if (ret < 0)
406      {
407          throw I2CException("Failed to write byte", busStr, devAddr, errno);
408      }
409  }
410  
write(uint8_t addr,uint8_t data)411  void I2CDevice::write(uint8_t addr, uint8_t data)
412  {
413      checkIsOpen();
414      checkWriteFuncs(I2C_SMBUS_BYTE_DATA);
415  
416      int ret = 0, retries = 0;
417      do
418      {
419          ret = i2c_smbus_write_byte_data(fd, addr, data);
420      } while ((ret < 0) && (++retries <= maxRetries));
421  
422      if (ret < 0)
423      {
424          throw I2CException("Failed to write byte data", busStr, devAddr, errno);
425      }
426  }
427  
write(uint8_t addr,uint16_t data)428  void I2CDevice::write(uint8_t addr, uint16_t data)
429  {
430      checkIsOpen();
431      checkWriteFuncs(I2C_SMBUS_WORD_DATA);
432  
433      int ret = 0, retries = 0;
434      do
435      {
436          ret = i2c_smbus_write_word_data(fd, addr, data);
437      } while ((ret < 0) && (++retries <= maxRetries));
438  
439      if (ret < 0)
440      {
441          throw I2CException("Failed to write word data", busStr, devAddr, errno);
442      }
443  }
444  
write(uint8_t addr,uint8_t size,const uint8_t * data,Mode mode)445  void I2CDevice::write(uint8_t addr, uint8_t size, const uint8_t* data,
446                        Mode mode)
447  {
448      checkIsOpen();
449  
450      int ret = -1, retries = 0;
451      switch (mode)
452      {
453          case Mode::SMBUS:
454              checkWriteFuncs(I2C_SMBUS_BLOCK_DATA);
455              do
456              {
457                  ret = i2c_smbus_write_block_data(fd, addr, size, data);
458              } while ((ret < 0) && (++retries <= maxRetries));
459              break;
460          case Mode::I2C:
461              checkWriteFuncs(I2C_SMBUS_I2C_BLOCK_DATA);
462              do
463              {
464                  ret = i2c_smbus_write_i2c_block_data(fd, addr, size, data);
465              } while ((ret < 0) && (++retries <= maxRetries));
466              break;
467      }
468  
469      if (ret < 0)
470      {
471          throw I2CException("Failed to write block data", busStr, devAddr,
472                             errno);
473      }
474  }
475  
processCall(uint8_t addr,uint16_t writeData,uint16_t & readData)476  void I2CDevice::processCall(uint8_t addr, uint16_t writeData,
477                              uint16_t& readData)
478  {
479      checkIsOpen();
480      checkWriteFuncs(I2C_SMBUS_PROC_CALL);
481  
482      int ret = 0, retries = 0;
483      do
484      {
485          ret = i2c_smbus_process_call(fd, addr, writeData);
486      } while ((ret < 0) && (++retries <= maxRetries));
487  
488      if (ret < 0)
489      {
490          throw I2CException("Failed to execute process call", busStr, devAddr,
491                             errno);
492      }
493  
494      readData = static_cast<uint16_t>(ret);
495  }
496  
processCall(uint8_t addr,uint8_t writeSize,const uint8_t * writeData,uint8_t & readSize,uint8_t * readData)497  void I2CDevice::processCall(uint8_t addr, uint8_t writeSize,
498                              const uint8_t* writeData, uint8_t& readSize,
499                              uint8_t* readData)
500  {
501      checkIsOpen();
502      unsigned long funcs = getFuncs();
503  
504      if ((funcs & I2C_FUNC_SMBUS_BLOCK_PROC_CALL) &&
505          (writeSize <= I2C_SMBUS_BLOCK_MAX))
506      {
507          // Use standard SMBus function which supports smaller SMBus 2.0 maximum
508          processCallSMBus(addr, writeSize, writeData, readSize, readData);
509      }
510      else if (funcs & I2C_FUNC_I2C)
511      {
512          // Use lower level I2C ioctl which supports larger SMBus 3.0 maximum
513          processCallI2C(addr, writeSize, writeData, readSize, readData);
514      }
515      else
516      {
517          throw I2CException(
518              std::format(
519                  "Block process call unsupported: writeSize={:d}, funcs={}",
520                  writeSize, funcs),
521              busStr, devAddr);
522      }
523  }
524  
create(uint8_t busId,uint8_t devAddr,InitialState initialState,int maxRetries)525  std::unique_ptr<I2CInterface> I2CDevice::create(
526      uint8_t busId, uint8_t devAddr, InitialState initialState, int maxRetries)
527  {
528      std::unique_ptr<I2CDevice> dev(
529          new I2CDevice(busId, devAddr, initialState, maxRetries));
530      return dev;
531  }
532  
create(uint8_t busId,uint8_t devAddr,I2CInterface::InitialState initialState,int maxRetries)533  std::unique_ptr<I2CInterface> create(uint8_t busId, uint8_t devAddr,
534                                       I2CInterface::InitialState initialState,
535                                       int maxRetries)
536  {
537      return I2CDevice::create(busId, devAddr, initialState, maxRetries);
538  }
539  
540  } // namespace i2c
541