xref: /openbmc/phosphor-power/tools/i2c/i2c.hpp (revision 92261f88729b618b1c31d20f28328a8aff73b83b)
1ab1327c3SLei YU #pragma once
2ab1327c3SLei YU 
3ab1327c3SLei YU #include "i2c_interface.hpp"
4ab1327c3SLei YU 
5ab1327c3SLei YU namespace i2c
6ab1327c3SLei YU {
7ab1327c3SLei YU 
8ab1327c3SLei YU class I2CDevice : public I2CInterface
9ab1327c3SLei YU {
10ab1327c3SLei YU   private:
11ab1327c3SLei YU     I2CDevice() = delete;
12ab1327c3SLei YU 
139af82a5cSLei YU     /** @brief Constructor
149af82a5cSLei YU      *
159af82a5cSLei YU      * Construct I2CDevice object from the bus id and device address
169af82a5cSLei YU      *
17d45a9a6dSShawn McCarney      * Automatically opens the I2CDevice if initialState is OPEN.
18d45a9a6dSShawn McCarney      *
199af82a5cSLei YU      * @param[in] busId - The i2c bus ID
209af82a5cSLei YU      * @param[in] devAddr - The device address of the I2C device
21d45a9a6dSShawn McCarney      * @param[in] initialState - Initial state of the I2CDevice object
22770de580SShawn McCarney      * @param[in] maxRetries - Maximum number of times to retry an I2C operation
239af82a5cSLei YU      */
I2CDevice(uint8_t busId,uint8_t devAddr,InitialState initialState=InitialState::OPEN,int maxRetries=0)24d45a9a6dSShawn McCarney     explicit I2CDevice(uint8_t busId, uint8_t devAddr,
25770de580SShawn McCarney                        InitialState initialState = InitialState::OPEN,
26770de580SShawn McCarney                        int maxRetries = 0) :
2728a2ca4bSJayanth Othayoth         devAddr(devAddr), maxRetries(maxRetries),
28b9cf0d2bSGeorge Liu         busStr("/dev/i2c-" + std::to_string(busId))
29ab1327c3SLei YU     {
30d45a9a6dSShawn McCarney         if (initialState == InitialState::OPEN)
31d45a9a6dSShawn McCarney         {
329af82a5cSLei YU             open();
33ab1327c3SLei YU         }
34d45a9a6dSShawn McCarney     }
35ab1327c3SLei YU 
36d45a9a6dSShawn McCarney     /** @brief Invalid file descriptor */
37d45a9a6dSShawn McCarney     static constexpr int INVALID_FD = -1;
389af82a5cSLei YU 
3938ed88d6SShawn McCarney     /** @brief Empty adapter functionality value with no bit flags set */
4038ed88d6SShawn McCarney     static constexpr unsigned long NO_FUNCS = 0;
4138ed88d6SShawn McCarney 
429af82a5cSLei YU     /** @brief The i2c device address in the bus */
439af82a5cSLei YU     uint8_t devAddr;
449af82a5cSLei YU 
45770de580SShawn McCarney     /** @brief Maximum number of times to retry an I2C operation */
46770de580SShawn McCarney     int maxRetries = 0;
47770de580SShawn McCarney 
489af82a5cSLei YU     /** @brief The file descriptor of the opened i2c device */
4938ed88d6SShawn McCarney     int fd = INVALID_FD;
509af82a5cSLei YU 
519af82a5cSLei YU     /** @brief The i2c bus path in /dev */
529af82a5cSLei YU     std::string busStr;
539af82a5cSLei YU 
5438ed88d6SShawn McCarney     /** @brief Cached I2C adapter functionality value */
5538ed88d6SShawn McCarney     unsigned long cachedFuncs = NO_FUNCS;
5638ed88d6SShawn McCarney 
57d45a9a6dSShawn McCarney     /** @brief Check that device interface is open
58d45a9a6dSShawn McCarney      *
59d45a9a6dSShawn McCarney      * @throw I2CException if device is not open
60d45a9a6dSShawn McCarney      */
checkIsOpen() const61d45a9a6dSShawn McCarney     void checkIsOpen() const
62d45a9a6dSShawn McCarney     {
63d45a9a6dSShawn McCarney         if (!isOpen())
64d45a9a6dSShawn McCarney         {
65d45a9a6dSShawn McCarney             throw I2CException("Device not open", busStr, devAddr);
66d45a9a6dSShawn McCarney         }
67d45a9a6dSShawn McCarney     }
68d45a9a6dSShawn McCarney 
69d45a9a6dSShawn McCarney     /** @brief Close device without throwing an exception if an error occurs */
closeWithoutException()70d45a9a6dSShawn McCarney     void closeWithoutException() noexcept
71d45a9a6dSShawn McCarney     {
72d45a9a6dSShawn McCarney         try
73d45a9a6dSShawn McCarney         {
74d45a9a6dSShawn McCarney             close();
75d45a9a6dSShawn McCarney         }
76d45a9a6dSShawn McCarney         catch (...)
770c9a33d6SAdriana Kobylak         {}
78d45a9a6dSShawn McCarney     }
79d45a9a6dSShawn McCarney 
8038ed88d6SShawn McCarney     /** @brief Get I2C adapter functionality
8138ed88d6SShawn McCarney      *
8238ed88d6SShawn McCarney      * Caches the adapter functionality value since it shouldn't change after
8338ed88d6SShawn McCarney      * opening the device.
8438ed88d6SShawn McCarney      *
8538ed88d6SShawn McCarney      * @throw I2CException on error
8638ed88d6SShawn McCarney      * @return Adapter functionality value
8738ed88d6SShawn McCarney      */
8838ed88d6SShawn McCarney     unsigned long getFuncs();
8938ed88d6SShawn McCarney 
9092e89eb5SLei YU     /** @brief Check i2c adapter read functionality
9192e89eb5SLei YU      *
9292e89eb5SLei YU      * Check if the i2c adapter has the functionality specified by the SMBus
9392e89eb5SLei YU      * transaction type
9492e89eb5SLei YU      *
9592e89eb5SLei YU      * @param[in] type - The SMBus transaction type defined in linux/i2c.h
9692e89eb5SLei YU      *
9792e89eb5SLei YU      * @throw I2CException if the function is not supported
9892e89eb5SLei YU      */
9992e89eb5SLei YU     void checkReadFuncs(int type);
10092e89eb5SLei YU 
10134fb8bdaSLei YU     /** @brief Check i2c adapter write functionality
10234fb8bdaSLei YU      *
10334fb8bdaSLei YU      * Check if the i2c adapter has the functionality specified by the SMBus
10434fb8bdaSLei YU      * transaction type
10534fb8bdaSLei YU      *
10634fb8bdaSLei YU      * @param[in] type - The SMBus transaction type defined in linux/i2c.h
10734fb8bdaSLei YU      *
10834fb8bdaSLei YU      * @throw I2CException if the function is not supported
10934fb8bdaSLei YU      */
11034fb8bdaSLei YU     void checkWriteFuncs(int type);
11134fb8bdaSLei YU 
112a3ff7e71SShawn McCarney     /** @brief SMBus Block Write-Block Read Process Call using SMBus function
113a3ff7e71SShawn McCarney      *
114a3ff7e71SShawn McCarney      * In SMBus 2.0 the maximum write size + read size is <= 32 bytes.
115a3ff7e71SShawn McCarney      * In SMBus 3.0 the maximum write size + read size is <= 255 bytes.
116a3ff7e71SShawn McCarney      * The Linux SMBus function currently only supports the SMBus 2.0 maximum.
117a3ff7e71SShawn McCarney      *
118a3ff7e71SShawn McCarney      * @param[in] addr - The register address of the i2c device
119a3ff7e71SShawn McCarney      * @param[in] writeSize - The size of data to write. Write size + read size
120a3ff7e71SShawn McCarney      *                        must be <= 32 bytes.
121a3ff7e71SShawn McCarney      * @param[in] writeData - The data to write to the i2c device
122a3ff7e71SShawn McCarney      * @param[out] readSize - The size of data read from i2c device. Write size
123a3ff7e71SShawn McCarney      *                        + read size must be <= 32 bytes.
124a3ff7e71SShawn McCarney      * @param[out] readData - Pointer to buffer to hold the data read from the
125a3ff7e71SShawn McCarney      *                        i2c device. Must be large enough to hold the data
126a3ff7e71SShawn McCarney      *                        returned by the device (max is 32 bytes).
127a3ff7e71SShawn McCarney      *
128a3ff7e71SShawn McCarney      * @throw I2CException on error
129a3ff7e71SShawn McCarney      */
130a3ff7e71SShawn McCarney     void processCallSMBus(uint8_t addr, uint8_t writeSize,
131a3ff7e71SShawn McCarney                           const uint8_t* writeData, uint8_t& readSize,
132a3ff7e71SShawn McCarney                           uint8_t* readData);
133a3ff7e71SShawn McCarney 
134a3ff7e71SShawn McCarney     /** @brief SMBus Block Write-Block Read Process Call using I2C messages
135a3ff7e71SShawn McCarney      *
136a3ff7e71SShawn McCarney      * This method supports block writes of more than 32 bytes.  It can also be
137a3ff7e71SShawn McCarney      * used with I2C adapters that do not support the block process call
138a3ff7e71SShawn McCarney      * protocol but do support I2C-level commands.
139a3ff7e71SShawn McCarney      *
140a3ff7e71SShawn McCarney      * This method implements the block process call using the lower level
141a3ff7e71SShawn McCarney      * I2C_RDWR ioctl to send I2C messages.  Using this ioctl allows for writes
142a3ff7e71SShawn McCarney      * up to 255 bytes.  The write size + read size must be <= 255 bytes.
143a3ff7e71SShawn McCarney      *
144a3ff7e71SShawn McCarney      * @param[in] addr - The register address of the i2c device
145a3ff7e71SShawn McCarney      * @param[in] writeSize - The size of data to write. Write size + read size
146a3ff7e71SShawn McCarney      *                        must be <= 255 bytes.
147a3ff7e71SShawn McCarney      * @param[in] writeData - The data to write to the i2c device
148a3ff7e71SShawn McCarney      * @param[out] readSize - The size of data read from i2c device. Max read
149a3ff7e71SShawn McCarney      *                        size is 32 bytes, and write size + read size must
150a3ff7e71SShawn McCarney      *                        be <= 255 bytes.
151a3ff7e71SShawn McCarney      * @param[out] readData - Pointer to buffer to hold the data read from the
152a3ff7e71SShawn McCarney      *                        i2c device. Must be large enough to hold the data
153a3ff7e71SShawn McCarney      *                        returned by the device (max is 32 bytes).
154a3ff7e71SShawn McCarney      *
155a3ff7e71SShawn McCarney      * @throw I2CException on error
156a3ff7e71SShawn McCarney      */
157a3ff7e71SShawn McCarney     void processCallI2C(uint8_t addr, uint8_t writeSize,
158a3ff7e71SShawn McCarney                         const uint8_t* writeData, uint8_t& readSize,
159a3ff7e71SShawn McCarney                         uint8_t* readData);
160a3ff7e71SShawn McCarney 
161ab1327c3SLei YU   public:
162d45a9a6dSShawn McCarney     /** @copydoc I2CInterface::~I2CInterface() */
~I2CDevice()1639af82a5cSLei YU     ~I2CDevice()
1649af82a5cSLei YU     {
165d45a9a6dSShawn McCarney         if (isOpen())
166d45a9a6dSShawn McCarney         {
167d45a9a6dSShawn McCarney             // Note: destructors must not throw exceptions
168d45a9a6dSShawn McCarney             closeWithoutException();
1699af82a5cSLei YU         }
170d45a9a6dSShawn McCarney     }
171d45a9a6dSShawn McCarney 
172d45a9a6dSShawn McCarney     /** @copydoc I2CInterface::open() */
17312c4a420SJayanth Othayoth     void open() override;
174d45a9a6dSShawn McCarney 
175d45a9a6dSShawn McCarney     /** @copydoc I2CInterface::isOpen() */
isOpen() const17612c4a420SJayanth Othayoth     bool isOpen() const override
177d45a9a6dSShawn McCarney     {
178d45a9a6dSShawn McCarney         return (fd != INVALID_FD);
179d45a9a6dSShawn McCarney     }
180d45a9a6dSShawn McCarney 
181d45a9a6dSShawn McCarney     /** @copydoc I2CInterface::close() */
18212c4a420SJayanth Othayoth     void close() override;
183ab1327c3SLei YU 
184ab1327c3SLei YU     /** @copydoc I2CInterface::read(uint8_t&) */
185ab1327c3SLei YU     void read(uint8_t& data) override;
186ab1327c3SLei YU 
187ab1327c3SLei YU     /** @copydoc I2CInterface::read(uint8_t,uint8_t&) */
188ab1327c3SLei YU     void read(uint8_t addr, uint8_t& data) override;
189ab1327c3SLei YU 
190ab1327c3SLei YU     /** @copydoc I2CInterface::read(uint8_t,uint16_t&) */
191ab1327c3SLei YU     void read(uint8_t addr, uint16_t& data) override;
192ab1327c3SLei YU 
1931d103428SLei YU     /** @copydoc I2CInterface::read(uint8_t,uint8_t&,uint8_t*,Mode) */
1941d103428SLei YU     void read(uint8_t addr, uint8_t& size, uint8_t* data,
1951d103428SLei YU               Mode mode = Mode::SMBUS) override;
196ab1327c3SLei YU 
197ab1327c3SLei YU     /** @copydoc I2CInterface::write(uint8_t) */
198ab1327c3SLei YU     void write(uint8_t data) override;
199ab1327c3SLei YU 
200ab1327c3SLei YU     /** @copydoc I2CInterface::write(uint8_t,uint8_t) */
201ab1327c3SLei YU     void write(uint8_t addr, uint8_t data) override;
202ab1327c3SLei YU 
203ab1327c3SLei YU     /** @copydoc I2CInterface::write(uint8_t,uint16_t) */
204ab1327c3SLei YU     void write(uint8_t addr, uint16_t data) override;
205ab1327c3SLei YU 
2061d103428SLei YU     /** @copydoc I2CInterface::write(uint8_t,uint8_t,const uint8_t*,Mode) */
2071d103428SLei YU     void write(uint8_t addr, uint8_t size, const uint8_t* data,
2081d103428SLei YU                Mode mode = Mode::SMBUS) override;
209ab1327c3SLei YU 
210a3ff7e71SShawn McCarney     /** @copydoc I2CInterface::processCall(uint8_t,uint16_t,uint16_t&) */
211a3ff7e71SShawn McCarney     void processCall(uint8_t addr, uint16_t writeData,
212a3ff7e71SShawn McCarney                      uint16_t& readData) override;
213a3ff7e71SShawn McCarney 
214a3ff7e71SShawn McCarney     /** @copydoc I2CInterface::processCall(uint8_t,uint8_t,const
215a3ff7e71SShawn McCarney      *                                     uint8_t*,uint8_t&,uint8_t*) */
216a3ff7e71SShawn McCarney     void processCall(uint8_t addr, uint8_t writeSize, const uint8_t* writeData,
217a3ff7e71SShawn McCarney                      uint8_t& readSize, uint8_t* readData) override;
218a3ff7e71SShawn McCarney 
219ab1327c3SLei YU     /** @brief Create an I2CInterface instance
220ab1327c3SLei YU      *
221d45a9a6dSShawn McCarney      * Automatically opens the I2CInterface if initialState is OPEN.
222d45a9a6dSShawn McCarney      *
223ab1327c3SLei YU      * @param[in] busId - The i2c bus ID
224ab1327c3SLei YU      * @param[in] devAddr - The device address of the i2c
225d45a9a6dSShawn McCarney      * @param[in] initialState - Initial state of the I2CInterface object
226770de580SShawn McCarney      * @param[in] maxRetries - Maximum number of times to retry an I2C operation
227ab1327c3SLei YU      *
228ab1327c3SLei YU      * @return The unique_ptr holding the I2CInterface
229ab1327c3SLei YU      */
230*92261f88SPatrick Williams     static std::unique_ptr<I2CInterface> create(
231*92261f88SPatrick Williams         uint8_t busId, uint8_t devAddr,
232*92261f88SPatrick Williams         InitialState initialState = InitialState::OPEN, int maxRetries = 0);
233ab1327c3SLei YU };
234ab1327c3SLei YU 
235ab1327c3SLei YU } // namespace i2c
236