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