1 /**
2  * Copyright © 2017 IBM 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 #include <fcntl.h>
17 #include <phosphor-logging/elog.hpp>
18 #include <phosphor-logging/elog-errors.hpp>
19 #include <phosphor-logging/log.hpp>
20 #include <sys/ioctl.h>
21 #include <xyz/openbmc_project/Common/error.hpp>
22 #include "gpio.hpp"
23 
24 namespace witherspoon
25 {
26 namespace gpio
27 {
28 
29 using namespace phosphor::logging;
30 
31 using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
32                         Error::InternalFailure;
33 
34 Value GPIO::read()
35 {
36     assert(direction == Direction::input);
37 
38     requestLine();
39 
40     gpiohandle_data data{};
41 
42     auto rc = ioctl(lineFD(),
43                     GPIOHANDLE_GET_LINE_VALUES_IOCTL,
44                     &data);
45 
46     if (rc < 0)
47     {
48         auto e = errno;
49         log<level::ERR>("Failed GET_LINE_VALUES ioctl",
50                         entry("ERRNO=%d", e));
51         elog<InternalFailure>();
52     }
53 
54     return (data.values[0] == 0) ? Value::low : Value::high;
55 }
56 
57 void GPIO::set(Value value)
58 {
59     assert(direction == Direction::output);
60 
61     requestLine(value);
62 
63     gpiohandle_data data{};
64     data.values[0] = static_cast<gpioValue_t>(value);
65 
66     auto rc = ioctl(lineFD(), GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data);
67     if (rc == -1)
68     {
69         auto e = errno;
70         log<level::ERR>("Failed SET_LINE_VALUES ioctl",
71                         entry("ERRNO=%d", e));
72         elog<InternalFailure>();
73     }
74 }
75 
76 void GPIO::requestLine(Value defaultValue)
77 {
78     //Only need to do this once
79     if (lineFD)
80     {
81         return;
82     }
83 
84     power::util::FileDescriptor fd{open(device.c_str(), 0)};
85     if (fd() == -1)
86     {
87         auto e = errno;
88         log<level::ERR>("Failed opening GPIO device",
89                         entry("DEVICE=%s", device.c_str()),
90                         entry("ERRNO=%d", e));
91         elog<InternalFailure>();
92     }
93 
94     //Make an ioctl call to request the GPIO line, which will
95     //return the descriptor to use to access it.
96     gpiohandle_request request{};
97     strncpy(request.consumer_label,
98             "witherspoon-pfault-analysis",
99             sizeof(request.consumer_label));
100 
101     request.flags = (direction == Direction::input) ?
102                     GPIOHANDLE_REQUEST_INPUT : GPIOHANDLE_REQUEST_OUTPUT;
103 
104     request.lineoffsets[0] = gpio;
105     request.lines = 1;
106 
107     if (direction == Direction::output)
108     {
109         request.default_values[0] = static_cast<gpioValue_t>(defaultValue);
110     }
111 
112     auto rc = ioctl(fd(), GPIO_GET_LINEHANDLE_IOCTL, &request);
113     if (rc == -1)
114     {
115         auto e = errno;
116         log<level::ERR>("Failed GET_LINEHANDLE ioctl",
117                         entry("GPIO=%d", gpio),
118                         entry("ERRNO=%d", e));
119         elog<InternalFailure>();
120     }
121 
122     lineFD.set(request.fd);
123 }
124 
125 }
126 }
127