1da2e0fe9SMatt Spinler /**
2da2e0fe9SMatt Spinler  * Copyright © 2017 IBM Corporation
3da2e0fe9SMatt Spinler  *
4da2e0fe9SMatt Spinler  * Licensed under the Apache License, Version 2.0 (the "License");
5da2e0fe9SMatt Spinler  * you may not use this file except in compliance with the License.
6da2e0fe9SMatt Spinler  * You may obtain a copy of the License at
7da2e0fe9SMatt Spinler  *
8da2e0fe9SMatt Spinler  *     http://www.apache.org/licenses/LICENSE-2.0
9da2e0fe9SMatt Spinler  *
10da2e0fe9SMatt Spinler  * Unless required by applicable law or agreed to in writing, software
11da2e0fe9SMatt Spinler  * distributed under the License is distributed on an "AS IS" BASIS,
12da2e0fe9SMatt Spinler  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13da2e0fe9SMatt Spinler  * See the License for the specific language governing permissions and
14da2e0fe9SMatt Spinler  * limitations under the License.
15da2e0fe9SMatt Spinler  */
16da2e0fe9SMatt Spinler #include <fcntl.h>
17da2e0fe9SMatt Spinler #include <phosphor-logging/elog.hpp>
18da2e0fe9SMatt Spinler #include <phosphor-logging/elog-errors.hpp>
19da2e0fe9SMatt Spinler #include <phosphor-logging/log.hpp>
20da2e0fe9SMatt Spinler #include <sys/ioctl.h>
21da2e0fe9SMatt Spinler #include <xyz/openbmc_project/Common/error.hpp>
22da2e0fe9SMatt Spinler #include "gpio.hpp"
23da2e0fe9SMatt Spinler 
24da2e0fe9SMatt Spinler namespace witherspoon
25da2e0fe9SMatt Spinler {
26da2e0fe9SMatt Spinler namespace gpio
27da2e0fe9SMatt Spinler {
28da2e0fe9SMatt Spinler 
29da2e0fe9SMatt Spinler using namespace phosphor::logging;
30da2e0fe9SMatt Spinler 
31da2e0fe9SMatt Spinler using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
32da2e0fe9SMatt Spinler                         Error::InternalFailure;
33da2e0fe9SMatt Spinler 
34da2e0fe9SMatt Spinler Value GPIO::read()
35da2e0fe9SMatt Spinler {
36da2e0fe9SMatt Spinler     assert(direction == Direction::input);
37da2e0fe9SMatt Spinler 
38da2e0fe9SMatt Spinler     requestLine();
39da2e0fe9SMatt Spinler 
40da2e0fe9SMatt Spinler     gpiohandle_data data{};
41da2e0fe9SMatt Spinler 
42da2e0fe9SMatt Spinler     auto rc = ioctl(lineFD(),
43da2e0fe9SMatt Spinler                     GPIOHANDLE_GET_LINE_VALUES_IOCTL,
44da2e0fe9SMatt Spinler                     &data);
45da2e0fe9SMatt Spinler 
46da2e0fe9SMatt Spinler     if (rc < 0)
47da2e0fe9SMatt Spinler     {
48da2e0fe9SMatt Spinler         auto e = errno;
49da2e0fe9SMatt Spinler         log<level::ERR>("Failed GET_LINE_VALUES ioctl",
50da2e0fe9SMatt Spinler                         entry("ERRNO=%d", e));
51da2e0fe9SMatt Spinler         elog<InternalFailure>();
52da2e0fe9SMatt Spinler     }
53da2e0fe9SMatt Spinler 
54da2e0fe9SMatt Spinler     return (data.values[0] == 0) ? Value::low : Value::high;
55da2e0fe9SMatt Spinler }
56da2e0fe9SMatt Spinler 
5735aa1433SMatt Spinler void GPIO::set(Value value)
5835aa1433SMatt Spinler {
5935aa1433SMatt Spinler     assert(direction == Direction::output);
60da2e0fe9SMatt Spinler 
6135aa1433SMatt Spinler     requestLine(value);
6235aa1433SMatt Spinler 
6335aa1433SMatt Spinler     gpiohandle_data data{};
6435aa1433SMatt Spinler     data.values[0] = static_cast<gpioValue_t>(value);
6535aa1433SMatt Spinler 
6635aa1433SMatt Spinler     auto rc = ioctl(lineFD(), GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data);
6735aa1433SMatt Spinler     if (rc == -1)
6835aa1433SMatt Spinler     {
6935aa1433SMatt Spinler         auto e = errno;
7035aa1433SMatt Spinler         log<level::ERR>("Failed SET_LINE_VALUES ioctl",
7135aa1433SMatt Spinler                         entry("ERRNO=%d", e));
7235aa1433SMatt Spinler         elog<InternalFailure>();
7335aa1433SMatt Spinler     }
7435aa1433SMatt Spinler }
7535aa1433SMatt Spinler 
7635aa1433SMatt Spinler void GPIO::requestLine(Value defaultValue)
77da2e0fe9SMatt Spinler {
78da2e0fe9SMatt Spinler     //Only need to do this once
79da2e0fe9SMatt Spinler     if (lineFD)
80da2e0fe9SMatt Spinler     {
81da2e0fe9SMatt Spinler         return;
82da2e0fe9SMatt Spinler     }
83da2e0fe9SMatt Spinler 
84da2e0fe9SMatt Spinler     power::util::FileDescriptor fd{open(device.c_str(), 0)};
85da2e0fe9SMatt Spinler     if (fd() == -1)
86da2e0fe9SMatt Spinler     {
87da2e0fe9SMatt Spinler         auto e = errno;
88da2e0fe9SMatt Spinler         log<level::ERR>("Failed opening GPIO device",
89*7475b1c1SMatt Spinler                         entry("DEVICE=%s", device.c_str()),
90da2e0fe9SMatt Spinler                         entry("ERRNO=%d", e));
91da2e0fe9SMatt Spinler         elog<InternalFailure>();
92da2e0fe9SMatt Spinler     }
93da2e0fe9SMatt Spinler 
94da2e0fe9SMatt Spinler     //Make an ioctl call to request the GPIO line, which will
95da2e0fe9SMatt Spinler     //return the descriptor to use to access it.
96da2e0fe9SMatt Spinler     gpiohandle_request request{};
97da2e0fe9SMatt Spinler     strncpy(request.consumer_label,
98da2e0fe9SMatt Spinler             "witherspoon-pfault-analysis",
99da2e0fe9SMatt Spinler             sizeof(request.consumer_label));
100da2e0fe9SMatt Spinler 
101da2e0fe9SMatt Spinler     request.flags = (direction == Direction::input) ?
102da2e0fe9SMatt Spinler                     GPIOHANDLE_REQUEST_INPUT : GPIOHANDLE_REQUEST_OUTPUT;
103da2e0fe9SMatt Spinler 
104da2e0fe9SMatt Spinler     request.lineoffsets[0] = gpio;
105da2e0fe9SMatt Spinler     request.lines = 1;
106da2e0fe9SMatt Spinler 
10735aa1433SMatt Spinler     if (direction == Direction::output)
10835aa1433SMatt Spinler     {
10935aa1433SMatt Spinler         request.default_values[0] = static_cast<gpioValue_t>(defaultValue);
11035aa1433SMatt Spinler     }
11135aa1433SMatt Spinler 
112da2e0fe9SMatt Spinler     auto rc = ioctl(fd(), GPIO_GET_LINEHANDLE_IOCTL, &request);
113da2e0fe9SMatt Spinler     if (rc == -1)
114da2e0fe9SMatt Spinler     {
115da2e0fe9SMatt Spinler         auto e = errno;
116da2e0fe9SMatt Spinler         log<level::ERR>("Failed GET_LINEHANDLE ioctl",
117da2e0fe9SMatt Spinler                         entry("GPIO=%d", gpio),
118da2e0fe9SMatt Spinler                         entry("ERRNO=%d", e));
119da2e0fe9SMatt Spinler         elog<InternalFailure>();
120da2e0fe9SMatt Spinler     }
121da2e0fe9SMatt Spinler 
122da2e0fe9SMatt Spinler     lineFD.set(request.fd);
123da2e0fe9SMatt Spinler }
124da2e0fe9SMatt Spinler 
125da2e0fe9SMatt Spinler }
126da2e0fe9SMatt Spinler }
127