xref: /openbmc/phosphor-power/gpio.cpp (revision cd9ab087)
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/log.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         log<level::ERR>("Failed GET_LINE_VALUES ioctl", entry("ERRNO=%d", 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         log<level::ERR>("Failed SET_LINE_VALUES ioctl", 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, "phosphor-power",
98             sizeof(request.consumer_label));
99 
100     request.flags = (direction == Direction::input) ? GPIOHANDLE_REQUEST_INPUT
101                                                     : GPIOHANDLE_REQUEST_OUTPUT;
102 
103     request.lineoffsets[0] = gpio;
104     request.lines = 1;
105 
106     if (direction == Direction::output)
107     {
108         request.default_values[0] = static_cast<gpioValue_t>(defaultValue);
109     }
110 
111     auto rc = ioctl(fd(), GPIO_GET_LINEHANDLE_IOCTL, &request);
112     if (rc == -1)
113     {
114         auto e = errno;
115         log<level::ERR>("Failed GET_LINEHANDLE ioctl", entry("GPIO=%d", gpio),
116                         entry("ERRNO=%d", e));
117         elog<InternalFailure>();
118     }
119 
120     lineFD.set(request.fd);
121 }
122 
123 } // namespace gpio
124 } // namespace phosphor
125