xref: /openbmc/phosphor-power/gpio.cpp (revision ad8d4542)
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 <cassert>
22 #include <phosphor-logging/elog-errors.hpp>
23 #include <phosphor-logging/elog.hpp>
24 #include <phosphor-logging/log.hpp>
25 #include <xyz/openbmc_project/Common/error.hpp>
26 
27 namespace phosphor
28 {
29 namespace gpio
30 {
31 
32 using namespace phosphor::logging;
33 
34 using InternalFailure =
35     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
36 
37 Value GPIO::read()
38 {
39     assert(direction == Direction::input);
40 
41     requestLine();
42 
43     gpiohandle_data data{};
44 
45     auto rc = ioctl(lineFD(), GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
46 
47     if (rc < 0)
48     {
49         auto e = errno;
50         log<level::ERR>("Failed GET_LINE_VALUES ioctl", 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", entry("ERRNO=%d", e));
71         elog<InternalFailure>();
72     }
73 }
74 
75 void GPIO::requestLine(Value defaultValue)
76 {
77     // Only need to do this once
78     if (lineFD)
79     {
80         return;
81     }
82 
83     power::util::FileDescriptor fd{open(device.c_str(), 0)};
84     if (fd() == -1)
85     {
86         auto e = errno;
87         log<level::ERR>("Failed opening GPIO device",
88                         entry("DEVICE=%s", device.c_str()),
89                         entry("ERRNO=%d", 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         log<level::ERR>("Failed GET_LINEHANDLE ioctl", entry("GPIO=%d", gpio),
115                         entry("ERRNO=%d", e));
116         elog<InternalFailure>();
117     }
118 
119     lineFD.set(request.fd);
120 }
121 
122 } // namespace gpio
123 } // namespace phosphor
124