xref: /openbmc/phosphor-power/tools/i2c/i2c.hpp (revision 0c9a33d66f74a76c1842990f41da678f79fa0c05)
1 #pragma once
2 
3 #include "i2c_interface.hpp"
4 
5 namespace i2c
6 {
7 
8 class I2CDevice : public I2CInterface
9 {
10   private:
11     I2CDevice() = delete;
12 
13     /** @brief Constructor
14      *
15      * Construct I2CDevice object from the bus id and device address
16      *
17      * Automatically opens the I2CDevice if initialState is OPEN.
18      *
19      * @param[in] busId - The i2c bus ID
20      * @param[in] devAddr - The device address of the I2C device
21      * @param[in] initialState - Initial state of the I2CDevice object
22      */
23     explicit I2CDevice(uint8_t busId, uint8_t devAddr,
24                        InitialState initialState = InitialState::OPEN) :
25         busId(busId),
26         devAddr(devAddr)
27     {
28         busStr = "/dev/i2c-" + std::to_string(busId);
29         if (initialState == InitialState::OPEN)
30         {
31             open();
32         }
33     }
34 
35     /** @brief Invalid file descriptor */
36     static constexpr int INVALID_FD = -1;
37 
38     /** @brief Empty adapter functionality value with no bit flags set */
39     static constexpr unsigned long NO_FUNCS = 0;
40 
41     /** @brief The I2C bus ID */
42     uint8_t busId;
43 
44     /** @brief The i2c device address in the bus */
45     uint8_t devAddr;
46 
47     /** @brief The file descriptor of the opened i2c device */
48     int fd = INVALID_FD;
49 
50     /** @brief The i2c bus path in /dev */
51     std::string busStr;
52 
53     /** @brief Cached I2C adapter functionality value */
54     unsigned long cachedFuncs = NO_FUNCS;
55 
56     /** @brief Check that device interface is open
57      *
58      * @throw I2CException if device is not open
59      */
60     void checkIsOpen() const
61     {
62         if (!isOpen())
63         {
64             throw I2CException("Device not open", busStr, devAddr);
65         }
66     }
67 
68     /** @brief Close device without throwing an exception if an error occurs */
69     void closeWithoutException() noexcept
70     {
71         try
72         {
73             close();
74         }
75         catch (...)
76         {}
77     }
78 
79     /** @brief Get I2C adapter functionality
80      *
81      * Caches the adapter functionality value since it shouldn't change after
82      * opening the device.
83      *
84      * @throw I2CException on error
85      * @return Adapter functionality value
86      */
87     unsigned long getFuncs();
88 
89     /** @brief Check i2c adapter read functionality
90      *
91      * Check if the i2c adapter has the functionality specified by the SMBus
92      * transaction type
93      *
94      * @param[in] type - The SMBus transaction type defined in linux/i2c.h
95      *
96      * @throw I2CException if the function is not supported
97      */
98     void checkReadFuncs(int type);
99 
100     /** @brief Check i2c adapter write functionality
101      *
102      * Check if the i2c adapter has the functionality specified by the SMBus
103      * transaction type
104      *
105      * @param[in] type - The SMBus transaction type defined in linux/i2c.h
106      *
107      * @throw I2CException if the function is not supported
108      */
109     void checkWriteFuncs(int type);
110 
111   public:
112     /** @copydoc I2CInterface::~I2CInterface() */
113     ~I2CDevice()
114     {
115         if (isOpen())
116         {
117             // Note: destructors must not throw exceptions
118             closeWithoutException();
119         }
120     }
121 
122     /** @copydoc I2CInterface::open() */
123     void open();
124 
125     /** @copydoc I2CInterface::isOpen() */
126     bool isOpen() const
127     {
128         return (fd != INVALID_FD);
129     }
130 
131     /** @copydoc I2CInterface::close() */
132     void close();
133 
134     /** @copydoc I2CInterface::read(uint8_t&) */
135     void read(uint8_t& data) override;
136 
137     /** @copydoc I2CInterface::read(uint8_t,uint8_t&) */
138     void read(uint8_t addr, uint8_t& data) override;
139 
140     /** @copydoc I2CInterface::read(uint8_t,uint16_t&) */
141     void read(uint8_t addr, uint16_t& data) override;
142 
143     /** @copydoc I2CInterface::read(uint8_t,uint8_t&,uint8_t*,Mode) */
144     void read(uint8_t addr, uint8_t& size, uint8_t* data,
145               Mode mode = Mode::SMBUS) override;
146 
147     /** @copydoc I2CInterface::write(uint8_t) */
148     void write(uint8_t data) override;
149 
150     /** @copydoc I2CInterface::write(uint8_t,uint8_t) */
151     void write(uint8_t addr, uint8_t data) override;
152 
153     /** @copydoc I2CInterface::write(uint8_t,uint16_t) */
154     void write(uint8_t addr, uint16_t data) override;
155 
156     /** @copydoc I2CInterface::write(uint8_t,uint8_t,const uint8_t*,Mode) */
157     void write(uint8_t addr, uint8_t size, const uint8_t* data,
158                Mode mode = Mode::SMBUS) override;
159 
160     /** @brief Create an I2CInterface instance
161      *
162      * Automatically opens the I2CInterface if initialState is OPEN.
163      *
164      * @param[in] busId - The i2c bus ID
165      * @param[in] devAddr - The device address of the i2c
166      * @param[in] initialState - Initial state of the I2CInterface object
167      *
168      * @return The unique_ptr holding the I2CInterface
169      */
170     static std::unique_ptr<I2CInterface>
171         create(uint8_t busId, uint8_t devAddr,
172                InitialState initialState = InitialState::OPEN);
173 };
174 
175 } // namespace i2c
176