xref: /openbmc/phosphor-bmc-code-mgmt/common/src/gpio_controller.cpp (revision e634411ba7c22d18ae01a0b03ce4f7b881c38fcc)
1*e634411bSHenry Wu #include "gpio_controller.hpp"
2*e634411bSHenry Wu 
3*e634411bSHenry Wu #include <phosphor-logging/lg2.hpp>
4*e634411bSHenry Wu 
5*e634411bSHenry Wu #include <fstream>
6*e634411bSHenry Wu #include <map>
7*e634411bSHenry Wu 
8*e634411bSHenry Wu PHOSPHOR_LOG2_USING;
9*e634411bSHenry Wu 
GPIOGroup(std::vector<std::string> linesIn,std::vector<bool> polaritiesIn)10*e634411bSHenry Wu GPIOGroup::GPIOGroup(std::vector<std::string> linesIn,
11*e634411bSHenry Wu                      std::vector<bool> polaritiesIn) :
12*e634411bSHenry Wu     lines(std::move(linesIn)), polarities(std::move(polaritiesIn))
13*e634411bSHenry Wu {}
14*e634411bSHenry Wu 
~GPIOGroup()15*e634411bSHenry Wu GPIOGroup::~GPIOGroup()
16*e634411bSHenry Wu {
17*e634411bSHenry Wu     releaseAll();
18*e634411bSHenry Wu }
19*e634411bSHenry Wu 
GPIOGroup(GPIOGroup && other)20*e634411bSHenry Wu GPIOGroup::GPIOGroup(GPIOGroup&& other) noexcept :
21*e634411bSHenry Wu     lines(std::move(other.lines)), polarities(std::move(other.polarities)),
22*e634411bSHenry Wu     activeBulks(std::move(other.activeBulks))
23*e634411bSHenry Wu {}
24*e634411bSHenry Wu 
operator =(GPIOGroup && other)25*e634411bSHenry Wu GPIOGroup& GPIOGroup::operator=(GPIOGroup&& other) noexcept
26*e634411bSHenry Wu {
27*e634411bSHenry Wu     if (this != &other)
28*e634411bSHenry Wu     {
29*e634411bSHenry Wu         releaseAll();
30*e634411bSHenry Wu         lines = std::move(other.lines);
31*e634411bSHenry Wu         polarities = std::move(other.polarities);
32*e634411bSHenry Wu         activeBulks = std::move(other.activeBulks);
33*e634411bSHenry Wu     }
34*e634411bSHenry Wu     return *this;
35*e634411bSHenry Wu }
36*e634411bSHenry Wu 
muxToBMC()37*e634411bSHenry Wu bool GPIOGroup::muxToBMC()
38*e634411bSHenry Wu {
39*e634411bSHenry Wu     return mux(false);
40*e634411bSHenry Wu }
muxToDevice()41*e634411bSHenry Wu bool GPIOGroup::muxToDevice()
42*e634411bSHenry Wu {
43*e634411bSHenry Wu     return mux(true);
44*e634411bSHenry Wu }
45*e634411bSHenry Wu 
releaseAll()46*e634411bSHenry Wu void GPIOGroup::releaseAll()
47*e634411bSHenry Wu {
48*e634411bSHenry Wu     for (auto& b : activeBulks)
49*e634411bSHenry Wu     {
50*e634411bSHenry Wu         if (b)
51*e634411bSHenry Wu         {
52*e634411bSHenry Wu             b->release();
53*e634411bSHenry Wu         }
54*e634411bSHenry Wu     }
55*e634411bSHenry Wu     activeBulks.clear();
56*e634411bSHenry Wu }
57*e634411bSHenry Wu 
mux(bool inverted)58*e634411bSHenry Wu bool GPIOGroup::mux(bool inverted)
59*e634411bSHenry Wu {
60*e634411bSHenry Wu     if (lines.empty())
61*e634411bSHenry Wu     {
62*e634411bSHenry Wu         return true;
63*e634411bSHenry Wu     }
64*e634411bSHenry Wu 
65*e634411bSHenry Wu     activeBulks = requestMuxGPIOs(lines, polarities, inverted);
66*e634411bSHenry Wu     if (activeBulks.empty())
67*e634411bSHenry Wu     {
68*e634411bSHenry Wu         error("Failed to mux GPIOs", "INVERTED", inverted);
69*e634411bSHenry Wu         return false;
70*e634411bSHenry Wu     }
71*e634411bSHenry Wu     return true;
72*e634411bSHenry Wu }
73*e634411bSHenry Wu 
ScopedBmcMux(GPIOGroup & g)74*e634411bSHenry Wu ScopedBmcMux::ScopedBmcMux(GPIOGroup& g) : gpioGroup(g)
75*e634411bSHenry Wu {
76*e634411bSHenry Wu     if (!gpioGroup.muxToBMC())
77*e634411bSHenry Wu     {
78*e634411bSHenry Wu         throw std::runtime_error("Failed to mux GPIOs to BMC");
79*e634411bSHenry Wu     }
80*e634411bSHenry Wu }
~ScopedBmcMux()81*e634411bSHenry Wu ScopedBmcMux::~ScopedBmcMux()
82*e634411bSHenry Wu {
83*e634411bSHenry Wu     gpioGroup.releaseAll();
84*e634411bSHenry Wu     if (!gpioGroup.muxToDevice())
85*e634411bSHenry Wu     {
86*e634411bSHenry Wu         error("Failed to mux GPIOs back to device");
87*e634411bSHenry Wu     }
88*e634411bSHenry Wu     gpioGroup.releaseAll();
89*e634411bSHenry Wu }
90*e634411bSHenry Wu 
requestMuxGPIOs(const std::vector<std::string> & gpioLines,const std::vector<bool> & gpioPolarities,bool inverted)91*e634411bSHenry Wu std::vector<std::unique_ptr<::gpiod::line_bulk>> requestMuxGPIOs(
92*e634411bSHenry Wu     const std::vector<std::string>& gpioLines,
93*e634411bSHenry Wu     const std::vector<bool>& gpioPolarities, bool inverted)
94*e634411bSHenry Wu {
95*e634411bSHenry Wu     std::map<std::string, std::vector<std::string>> groupLineNames;
96*e634411bSHenry Wu     std::map<std::string, std::vector<int>> groupValues;
97*e634411bSHenry Wu 
98*e634411bSHenry Wu     for (size_t i = 0; i < gpioLines.size(); ++i)
99*e634411bSHenry Wu     {
100*e634411bSHenry Wu         auto line = ::gpiod::find_line(gpioLines[i]);
101*e634411bSHenry Wu 
102*e634411bSHenry Wu         if (!line)
103*e634411bSHenry Wu         {
104*e634411bSHenry Wu             error("Failed to find GPIO line: {LINE}", "LINE", gpioLines[i]);
105*e634411bSHenry Wu             return {};
106*e634411bSHenry Wu         }
107*e634411bSHenry Wu 
108*e634411bSHenry Wu         if (line.is_used())
109*e634411bSHenry Wu         {
110*e634411bSHenry Wu             error("GPIO line {LINE} was still used", "LINE", gpioLines[i]);
111*e634411bSHenry Wu             return {};
112*e634411bSHenry Wu         }
113*e634411bSHenry Wu 
114*e634411bSHenry Wu         std::string chipName = line.get_chip().name();
115*e634411bSHenry Wu         groupLineNames[chipName].push_back(gpioLines[i]);
116*e634411bSHenry Wu         groupValues[chipName].push_back(gpioPolarities[i] ^ inverted ? 1 : 0);
117*e634411bSHenry Wu     }
118*e634411bSHenry Wu 
119*e634411bSHenry Wu     std::vector<std::unique_ptr<::gpiod::line_bulk>> lineBulks;
120*e634411bSHenry Wu     ::gpiod::line_request config{"", ::gpiod::line_request::DIRECTION_OUTPUT,
121*e634411bSHenry Wu                                  0};
122*e634411bSHenry Wu 
123*e634411bSHenry Wu     for (auto& [chipName, lineNames] : groupLineNames)
124*e634411bSHenry Wu     {
125*e634411bSHenry Wu         ::gpiod::chip chip(chipName);
126*e634411bSHenry Wu         std::vector<::gpiod::line> lines;
127*e634411bSHenry Wu 
128*e634411bSHenry Wu         for (size_t i = 0; i < lineNames.size(); ++i)
129*e634411bSHenry Wu         {
130*e634411bSHenry Wu             const auto& name = lineNames[i];
131*e634411bSHenry Wu             auto line = chip.find_line(name);
132*e634411bSHenry Wu 
133*e634411bSHenry Wu             if (!line)
134*e634411bSHenry Wu             {
135*e634411bSHenry Wu                 error("Failed to get {LINE} from chip {CHIP}", "LINE", name,
136*e634411bSHenry Wu                       "CHIP", chipName);
137*e634411bSHenry Wu                 return {};
138*e634411bSHenry Wu             }
139*e634411bSHenry Wu 
140*e634411bSHenry Wu             lg2::info("Requesting chip {CHIP}, GPIO line {LINE} to {VALUE}",
141*e634411bSHenry Wu                       "CHIP", chip.name(), "LINE", line.name(), "VALUE",
142*e634411bSHenry Wu                       groupValues[chipName][i]);
143*e634411bSHenry Wu 
144*e634411bSHenry Wu             lines.push_back(std::move(line));
145*e634411bSHenry Wu         }
146*e634411bSHenry Wu 
147*e634411bSHenry Wu         auto lineBulk = std::make_unique<::gpiod::line_bulk>(lines);
148*e634411bSHenry Wu 
149*e634411bSHenry Wu         if (!lineBulk)
150*e634411bSHenry Wu         {
151*e634411bSHenry Wu             error("Failed to create line bulk for chip={CHIP}", "CHIP",
152*e634411bSHenry Wu                   chipName);
153*e634411bSHenry Wu             return {};
154*e634411bSHenry Wu         }
155*e634411bSHenry Wu 
156*e634411bSHenry Wu         lineBulk->request(config, groupValues[chipName]);
157*e634411bSHenry Wu 
158*e634411bSHenry Wu         lineBulks.push_back(std::move(lineBulk));
159*e634411bSHenry Wu     }
160*e634411bSHenry Wu 
161*e634411bSHenry Wu     return lineBulks;
162*e634411bSHenry Wu }
163