1*da2e0fe9SMatt Spinler /**
2*da2e0fe9SMatt Spinler  * Copyright © 2017 IBM Corporation
3*da2e0fe9SMatt Spinler  *
4*da2e0fe9SMatt Spinler  * Licensed under the Apache License, Version 2.0 (the "License");
5*da2e0fe9SMatt Spinler  * you may not use this file except in compliance with the License.
6*da2e0fe9SMatt Spinler  * You may obtain a copy of the License at
7*da2e0fe9SMatt Spinler  *
8*da2e0fe9SMatt Spinler  *     http://www.apache.org/licenses/LICENSE-2.0
9*da2e0fe9SMatt Spinler  *
10*da2e0fe9SMatt Spinler  * Unless required by applicable law or agreed to in writing, software
11*da2e0fe9SMatt Spinler  * distributed under the License is distributed on an "AS IS" BASIS,
12*da2e0fe9SMatt Spinler  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*da2e0fe9SMatt Spinler  * See the License for the specific language governing permissions and
14*da2e0fe9SMatt Spinler  * limitations under the License.
15*da2e0fe9SMatt Spinler  */
16*da2e0fe9SMatt Spinler #include <fcntl.h>
17*da2e0fe9SMatt Spinler #include <phosphor-logging/elog.hpp>
18*da2e0fe9SMatt Spinler #include <phosphor-logging/elog-errors.hpp>
19*da2e0fe9SMatt Spinler #include <phosphor-logging/log.hpp>
20*da2e0fe9SMatt Spinler #include <sys/ioctl.h>
21*da2e0fe9SMatt Spinler #include <xyz/openbmc_project/Common/error.hpp>
22*da2e0fe9SMatt Spinler #include "gpio.hpp"
23*da2e0fe9SMatt Spinler 
24*da2e0fe9SMatt Spinler namespace witherspoon
25*da2e0fe9SMatt Spinler {
26*da2e0fe9SMatt Spinler namespace gpio
27*da2e0fe9SMatt Spinler {
28*da2e0fe9SMatt Spinler 
29*da2e0fe9SMatt Spinler using namespace phosphor::logging;
30*da2e0fe9SMatt Spinler 
31*da2e0fe9SMatt Spinler using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
32*da2e0fe9SMatt Spinler                         Error::InternalFailure;
33*da2e0fe9SMatt Spinler 
34*da2e0fe9SMatt Spinler Value GPIO::read()
35*da2e0fe9SMatt Spinler {
36*da2e0fe9SMatt Spinler     assert(direction == Direction::input);
37*da2e0fe9SMatt Spinler 
38*da2e0fe9SMatt Spinler     requestLine();
39*da2e0fe9SMatt Spinler 
40*da2e0fe9SMatt Spinler     gpiohandle_data data{};
41*da2e0fe9SMatt Spinler 
42*da2e0fe9SMatt Spinler     auto rc = ioctl(lineFD(),
43*da2e0fe9SMatt Spinler                     GPIOHANDLE_GET_LINE_VALUES_IOCTL,
44*da2e0fe9SMatt Spinler                     &data);
45*da2e0fe9SMatt Spinler 
46*da2e0fe9SMatt Spinler     if (rc < 0)
47*da2e0fe9SMatt Spinler     {
48*da2e0fe9SMatt Spinler         auto e = errno;
49*da2e0fe9SMatt Spinler         log<level::ERR>("Failed GET_LINE_VALUES ioctl",
50*da2e0fe9SMatt Spinler                         entry("ERRNO=%d", e));
51*da2e0fe9SMatt Spinler         elog<InternalFailure>();
52*da2e0fe9SMatt Spinler     }
53*da2e0fe9SMatt Spinler 
54*da2e0fe9SMatt Spinler     return (data.values[0] == 0) ? Value::low : Value::high;
55*da2e0fe9SMatt Spinler }
56*da2e0fe9SMatt Spinler 
57*da2e0fe9SMatt Spinler 
58*da2e0fe9SMatt Spinler void GPIO::requestLine()
59*da2e0fe9SMatt Spinler {
60*da2e0fe9SMatt Spinler     //Only need to do this once
61*da2e0fe9SMatt Spinler     if (lineFD)
62*da2e0fe9SMatt Spinler     {
63*da2e0fe9SMatt Spinler         return;
64*da2e0fe9SMatt Spinler     }
65*da2e0fe9SMatt Spinler 
66*da2e0fe9SMatt Spinler     power::util::FileDescriptor fd{open(device.c_str(), 0)};
67*da2e0fe9SMatt Spinler     if (fd() == -1)
68*da2e0fe9SMatt Spinler     {
69*da2e0fe9SMatt Spinler         auto e = errno;
70*da2e0fe9SMatt Spinler         log<level::ERR>("Failed opening GPIO device",
71*da2e0fe9SMatt Spinler                         entry("DEVICE=%s", device),
72*da2e0fe9SMatt Spinler                         entry("ERRNO=%d", e));
73*da2e0fe9SMatt Spinler         elog<InternalFailure>();
74*da2e0fe9SMatt Spinler     }
75*da2e0fe9SMatt Spinler 
76*da2e0fe9SMatt Spinler     //Make an ioctl call to request the GPIO line, which will
77*da2e0fe9SMatt Spinler     //return the descriptor to use to access it.
78*da2e0fe9SMatt Spinler     gpiohandle_request request{};
79*da2e0fe9SMatt Spinler     strncpy(request.consumer_label,
80*da2e0fe9SMatt Spinler             "witherspoon-pfault-analysis",
81*da2e0fe9SMatt Spinler             sizeof(request.consumer_label));
82*da2e0fe9SMatt Spinler 
83*da2e0fe9SMatt Spinler     request.flags = (direction == Direction::input) ?
84*da2e0fe9SMatt Spinler                     GPIOHANDLE_REQUEST_INPUT : GPIOHANDLE_REQUEST_OUTPUT;
85*da2e0fe9SMatt Spinler 
86*da2e0fe9SMatt Spinler     request.lineoffsets[0] = gpio;
87*da2e0fe9SMatt Spinler     request.lines = 1;
88*da2e0fe9SMatt Spinler 
89*da2e0fe9SMatt Spinler     auto rc = ioctl(fd(), GPIO_GET_LINEHANDLE_IOCTL, &request);
90*da2e0fe9SMatt Spinler     if (rc == -1)
91*da2e0fe9SMatt Spinler     {
92*da2e0fe9SMatt Spinler         auto e = errno;
93*da2e0fe9SMatt Spinler         log<level::ERR>("Failed GET_LINEHANDLE ioctl",
94*da2e0fe9SMatt Spinler                         entry("GPIO=%d", gpio),
95*da2e0fe9SMatt Spinler                         entry("ERRNO=%d", e));
96*da2e0fe9SMatt Spinler         elog<InternalFailure>();
97*da2e0fe9SMatt Spinler     }
98*da2e0fe9SMatt Spinler 
99*da2e0fe9SMatt Spinler     lineFD.set(request.fd);
100*da2e0fe9SMatt Spinler }
101*da2e0fe9SMatt Spinler 
102*da2e0fe9SMatt Spinler }
103*da2e0fe9SMatt Spinler }
104