blob: bb7f79be89b464ffb4ce6fe0bde16dc6e627dda4 [file] [log] [blame]
Kuiying Wanga9d39e32018-08-14 13:47:32 +08001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
Patrick Venture0d9377d2018-11-01 19:34:59 -070017#include "gpio.hpp"
18
Matt Spinler8f2c95a2018-11-05 15:17:29 -060019#include "settings.hpp"
20
Kuiying Wanga9d39e32018-08-14 13:47:32 +080021#include <fcntl.h>
Patrick Venture0d9377d2018-11-01 19:34:59 -070022#include <unistd.h>
23
Patrick Williams8eca9bb2022-06-16 17:11:51 -050024#include <filesystem>
Kuiying Wanga9d39e32018-08-14 13:47:32 +080025#include <fstream>
Matt Spinler8f2c95a2018-11-05 15:17:29 -060026#include <gpioplus/utility/aspeed.hpp>
Matt Spinler8605bdf2018-11-05 14:55:46 -060027#include <nlohmann/json.hpp>
Matt Spinler8605bdf2018-11-05 14:55:46 -060028#include <phosphor-logging/log.hpp>
Kuiying Wanga9d39e32018-08-14 13:47:32 +080029
Matt Spinler8f2c95a2018-11-05 15:17:29 -060030const std::string gpioDev = "/sys/class/gpio";
Matt Spinler8605bdf2018-11-05 14:55:46 -060031
32using namespace phosphor::logging;
Patrick Williams8eca9bb2022-06-16 17:11:51 -050033namespace fs = std::filesystem;
Matt Spinler8605bdf2018-11-05 14:55:46 -060034
Kuiying Wanga9d39e32018-08-14 13:47:32 +080035void closeGpio(int fd)
36{
37 if (fd > 0)
38 {
39 ::close(fd);
40 }
41}
42
Matt Spinler8f2c95a2018-11-05 15:17:29 -060043uint32_t getGpioBase()
44{
45 // Look for a /sys/class/gpio/gpiochip*/label file
46 // with a value of GPIO_BASE_LABEL_NAME. Then read
47 // the base value from the 'base' file in that directory.
48#ifdef LOOKUP_GPIO_BASE
49 for (auto& f : fs::directory_iterator(gpioDev))
50 {
51 std::string path{f.path()};
52 if (path.find("gpiochip") == std::string::npos)
53 {
54 continue;
55 }
56
57 std::ifstream labelStream{path + "/label"};
58 std::string label;
59 labelStream >> label;
60
61 if (label == GPIO_BASE_LABEL_NAME)
62 {
63 uint32_t base;
64 std::ifstream baseStream{path + "/base"};
65 baseStream >> base;
66 return base;
67 }
68 }
69
70 log<level::ERR>("Could not find GPIO base");
71 throw std::runtime_error("Could not find GPIO base!");
72#else
73 return 0;
74#endif
75}
76
77uint32_t getGpioNum(const std::string& gpioPin)
78{
79 // gpioplus promises that they will figure out how to easily
80 // support multiple BMC vendors when the time comes.
81 auto offset = gpioplus::utility::aspeed::nameToOffset(gpioPin);
82
83 return getGpioBase() + offset;
84}
85
Naveen Mosesa1af3292021-12-15 11:47:01 +053086int configGroupGpio(buttonConfig& buttonIFConfig)
Matt Spinler8605bdf2018-11-05 14:55:46 -060087{
Naveen Mosesdd5495c2021-12-03 22:40:46 +053088 int result = 0;
89 // iterate the list of gpios from the button interface config
90 // and initialize them
91 for (auto& gpioCfg : buttonIFConfig.gpios)
Matt Spinler8605bdf2018-11-05 14:55:46 -060092 {
Naveen Mosesa1af3292021-12-15 11:47:01 +053093 result = configGpio(gpioCfg);
Naveen Mosesdd5495c2021-12-03 22:40:46 +053094 if (result < 0)
Matt Spinler8605bdf2018-11-05 14:55:46 -060095 {
Naveen Mosesdd5495c2021-12-03 22:40:46 +053096
97 std::string errorMsg =
98 "Error configuring gpio: GPIO_NUM=" +
99 std::to_string(gpioCfg.number) +
100 ",BUTTON_NAME=" + buttonIFConfig.formFactorName;
101 log<level::ERR>(errorMsg.c_str());
102
103 break;
Matt Spinler8605bdf2018-11-05 14:55:46 -0600104 }
105 }
Naveen Mosesdd5495c2021-12-03 22:40:46 +0530106
107 return result;
Matt Spinler8605bdf2018-11-05 14:55:46 -0600108}
109
Naveen Mosesa1af3292021-12-15 11:47:01 +0530110int configGpio(gpioInfo& gpioConfig)
Matt Spinler8f2c95a2018-11-05 15:17:29 -0600111{
112
Naveen Mosesdd5495c2021-12-03 22:40:46 +0530113 auto gpioNum = gpioConfig.number;
114 auto gpioDirection = gpioConfig.direction;
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800115
Matt Spinler8f2c95a2018-11-05 15:17:29 -0600116 std::string devPath{gpioDev};
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800117
118 std::fstream stream;
119
120 stream.exceptions(std::ifstream::failbit | std::ifstream::badbit);
121
Matt Spinler8f2c95a2018-11-05 15:17:29 -0600122 devPath += "/gpio" + std::to_string(gpioNum) + "/value";
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800123
Matt Spinler8f2c95a2018-11-05 15:17:29 -0600124 fs::path fullPath(devPath);
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800125
Matt Spinler8f2c95a2018-11-05 15:17:29 -0600126 if (fs::exists(fullPath))
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800127 {
Matt Spinler8605bdf2018-11-05 14:55:46 -0600128 log<level::INFO>("GPIO exported", entry("PATH=%s", devPath.c_str()));
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800129 }
130 else
131 {
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800132 devPath = gpioDev + "/export";
133
134 stream.open(devPath, std::fstream::out);
135 try
136 {
137 stream << gpioNum;
138 stream.close();
139 }
140
Patrick Venture0d9377d2018-11-01 19:34:59 -0700141 catch (const std::exception& e)
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800142 {
Matt Spinler8605bdf2018-11-05 14:55:46 -0600143 log<level::ERR>("Error in writing!",
144 entry("PATH=%s", devPath.c_str()),
145 entry("NUM=%d", gpioNum));
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800146 return -1;
147 }
148 }
149
150 if (gpioDirection == "out")
151 {
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800152 devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/value";
153
154 uint32_t currentValue;
155
156 stream.open(devPath, std::fstream::in);
157 try
158 {
159 stream >> currentValue;
160 stream.close();
161 }
162
163 catch (const std::exception& e)
164 {
Matt Spinler8605bdf2018-11-05 14:55:46 -0600165 log<level::ERR>("Error in reading!",
166 entry("PATH=%s", devPath.c_str()));
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800167 return -1;
168 }
169
170 const char* direction = currentValue ? "high" : "low";
171
172 devPath.clear();
173 devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/direction";
174
175 stream.open(devPath, std::fstream::out);
176 try
177 {
178 stream << direction;
179 stream.close();
180 }
181
182 catch (const std::exception& e)
183 {
Matt Spinler8605bdf2018-11-05 14:55:46 -0600184 log<level::ERR>("Error in writing!");
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800185 return -1;
186 }
187 }
188 else if (gpioDirection == "in")
189 {
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800190 devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/direction";
191
192 stream.open(devPath, std::fstream::out);
193 try
194 {
195 stream << gpioDirection;
196 stream.close();
197 }
198
199 catch (const std::exception& e)
200 {
Matt Spinler8605bdf2018-11-05 14:55:46 -0600201 log<level::ERR>("Error in writing!");
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800202 return -1;
203 }
204 }
205 else if ((gpioDirection == "both"))
206 {
Tim Lee582b3f02019-01-03 15:39:27 +0800207 // Before set gpio configure as an interrupt pin, need to set direction
208 // as 'in' or edge can't set as 'rising', 'falling' and 'both'
209 const char* in_direction = "in";
210 devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/direction";
211
212 stream.open(devPath, std::fstream::out);
213 try
214 {
215 stream << in_direction;
216 stream.close();
217 }
218
219 catch (const std::exception& e)
220 {
221 log<level::ERR>("Error in writing!");
222 return -1;
223 }
224 devPath.clear();
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800225
226 // For gpio configured as ‘both’, it is an interrupt pin and trigged on
227 // both rising and falling signals
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800228 devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/edge";
229
230 stream.open(devPath, std::fstream::out);
231 try
232 {
233 stream << gpioDirection;
234 stream.close();
235 }
236
237 catch (const std::exception& e)
238 {
Matt Spinler8605bdf2018-11-05 14:55:46 -0600239 log<level::ERR>("Error in writing!");
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800240 return -1;
241 }
242 }
243
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800244 devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/value";
245
Naveen Mosesdd5495c2021-12-03 22:40:46 +0530246 auto fd = ::open(devPath.c_str(), O_RDWR | O_NONBLOCK);
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800247
Naveen Mosesdd5495c2021-12-03 22:40:46 +0530248 if (fd < 0)
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800249 {
Matt Spinler8605bdf2018-11-05 14:55:46 -0600250 log<level::ERR>("open error!");
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800251 return -1;
252 }
253
Naveen Mosesdd5495c2021-12-03 22:40:46 +0530254 gpioConfig.fd = fd;
255
Kuiying Wanga9d39e32018-08-14 13:47:32 +0800256 return 0;
257}