xref: /openbmc/phosphor-power/gpio.cpp (revision 8b38b177315d40f1f9bc1e4d0784d45ea17cbd5c)
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 "gpio.hpp"
17 
18 #include <fcntl.h>
19 #include <sys/ioctl.h>
20 
21 #include <phosphor-logging/elog-errors.hpp>
22 #include <phosphor-logging/elog.hpp>
23 #include <phosphor-logging/lg2.hpp>
24 #include <xyz/openbmc_project/Common/error.hpp>
25 
26 #include <cassert>
27 
28 namespace phosphor
29 {
30 namespace gpio
31 {
32 
33 using namespace phosphor::logging;
34 
35 using InternalFailure =
36     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
37 
38 Value GPIO::read()
39 {
40     assert(direction == Direction::input);
41 
42     requestLine();
43 
44     gpiohandle_data data{};
45 
46     auto rc = ioctl(lineFD(), GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
47 
48     if (rc < 0)
49     {
50         auto e = errno;
51         lg2::error("Failed GET_LINE_VALUES ioctl ERRNO={ERRNO}", "ERRNO", e);
52         elog<InternalFailure>();
53     }
54 
55     return (data.values[0] == 0) ? Value::low : Value::high;
56 }
57 
58 void GPIO::set(Value value)
59 {
60     assert(direction == Direction::output);
61 
62     requestLine(value);
63 
64     gpiohandle_data data{};
65     data.values[0] = static_cast<gpioValue_t>(value);
66 
67     auto rc = ioctl(lineFD(), GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data);
68     if (rc == -1)
69     {
70         auto e = errno;
71         lg2::error("Failed SET_LINE_VALUES ioctl ERRNO={ERRNO}", "ERRNO", 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         lg2::error("Failed opening GPIO device DEVICE={DEVICE} ERRNO={ERRNO}",
89                    "DEVICE", device, "ERRNO", e);
90         elog<InternalFailure>();
91     }
92 
93     // Make an ioctl call to request the GPIO line, which will
94     // return the descriptor to use to access it.
95     gpiohandle_request request{};
96     strncpy(request.consumer_label, "phosphor-power",
97             sizeof(request.consumer_label));
98 
99     request.flags = (direction == Direction::input) ? GPIOHANDLE_REQUEST_INPUT
100                                                     : GPIOHANDLE_REQUEST_OUTPUT;
101 
102     request.lineoffsets[0] = gpio;
103     request.lines = 1;
104 
105     if (direction == Direction::output)
106     {
107         request.default_values[0] = static_cast<gpioValue_t>(defaultValue);
108     }
109 
110     auto rc = ioctl(fd(), GPIO_GET_LINEHANDLE_IOCTL, &request);
111     if (rc == -1)
112     {
113         auto e = errno;
114         lg2::error("Failed GET_LINEHANDLE ioctl GPIO={GPIO} ERRNO={ERRNO}",
115                    "GPIO", gpio, "ERRNO", e);
116         elog<InternalFailure>();
117     }
118 
119     lineFD.set(request.fd);
120 }
121 
122 } // namespace gpio
123 } // namespace phosphor
124