1da2e0fe9SMatt Spinler /**
2da2e0fe9SMatt Spinler  * Copyright © 2017 IBM Corporation
3da2e0fe9SMatt Spinler  *
4da2e0fe9SMatt Spinler  * Licensed under the Apache License, Version 2.0 (the "License");
5da2e0fe9SMatt Spinler  * you may not use this file except in compliance with the License.
6da2e0fe9SMatt Spinler  * You may obtain a copy of the License at
7da2e0fe9SMatt Spinler  *
8da2e0fe9SMatt Spinler  *     http://www.apache.org/licenses/LICENSE-2.0
9da2e0fe9SMatt Spinler  *
10da2e0fe9SMatt Spinler  * Unless required by applicable law or agreed to in writing, software
11da2e0fe9SMatt Spinler  * distributed under the License is distributed on an "AS IS" BASIS,
12da2e0fe9SMatt Spinler  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13da2e0fe9SMatt Spinler  * See the License for the specific language governing permissions and
14da2e0fe9SMatt Spinler  * limitations under the License.
15da2e0fe9SMatt Spinler  */
16da2e0fe9SMatt Spinler #include "gpio.hpp"
17da2e0fe9SMatt Spinler 
18f0f02b9aSMatt Spinler #include <fcntl.h>
19f0f02b9aSMatt Spinler #include <sys/ioctl.h>
20f0f02b9aSMatt Spinler 
21f0f02b9aSMatt Spinler #include <phosphor-logging/elog-errors.hpp>
22f0f02b9aSMatt Spinler #include <phosphor-logging/elog.hpp>
23f0f02b9aSMatt Spinler #include <phosphor-logging/log.hpp>
24f0f02b9aSMatt Spinler #include <xyz/openbmc_project/Common/error.hpp>
25f0f02b9aSMatt Spinler 
26*2c4fbc4cSPatrick Williams #include <cassert>
27*2c4fbc4cSPatrick Williams 
28da2e0fe9SMatt Spinler namespace witherspoon
29da2e0fe9SMatt Spinler {
30da2e0fe9SMatt Spinler namespace gpio
31da2e0fe9SMatt Spinler {
32da2e0fe9SMatt Spinler 
33da2e0fe9SMatt Spinler using namespace phosphor::logging;
34da2e0fe9SMatt Spinler 
35f0f02b9aSMatt Spinler using InternalFailure =
36f0f02b9aSMatt Spinler     sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
37da2e0fe9SMatt Spinler 
read()38da2e0fe9SMatt Spinler Value GPIO::read()
39da2e0fe9SMatt Spinler {
40da2e0fe9SMatt Spinler     assert(direction == Direction::input);
41da2e0fe9SMatt Spinler 
42da2e0fe9SMatt Spinler     requestLine();
43da2e0fe9SMatt Spinler 
44da2e0fe9SMatt Spinler     gpiohandle_data data{};
45da2e0fe9SMatt Spinler 
46f0f02b9aSMatt Spinler     auto rc = ioctl(lineFD(), GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
47da2e0fe9SMatt Spinler 
48da2e0fe9SMatt Spinler     if (rc < 0)
49da2e0fe9SMatt Spinler     {
50da2e0fe9SMatt Spinler         auto e = errno;
51f0f02b9aSMatt Spinler         log<level::ERR>("Failed GET_LINE_VALUES ioctl", entry("ERRNO=%d", e));
52da2e0fe9SMatt Spinler         elog<InternalFailure>();
53da2e0fe9SMatt Spinler     }
54da2e0fe9SMatt Spinler 
55da2e0fe9SMatt Spinler     return (data.values[0] == 0) ? Value::low : Value::high;
56da2e0fe9SMatt Spinler }
57da2e0fe9SMatt Spinler 
set(Value value)5835aa1433SMatt Spinler void GPIO::set(Value value)
5935aa1433SMatt Spinler {
6035aa1433SMatt Spinler     assert(direction == Direction::output);
61da2e0fe9SMatt Spinler 
6235aa1433SMatt Spinler     requestLine(value);
6335aa1433SMatt Spinler 
6435aa1433SMatt Spinler     gpiohandle_data data{};
6535aa1433SMatt Spinler     data.values[0] = static_cast<gpioValue_t>(value);
6635aa1433SMatt Spinler 
6735aa1433SMatt Spinler     auto rc = ioctl(lineFD(), GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data);
6835aa1433SMatt Spinler     if (rc == -1)
6935aa1433SMatt Spinler     {
7035aa1433SMatt Spinler         auto e = errno;
71f0f02b9aSMatt Spinler         log<level::ERR>("Failed SET_LINE_VALUES ioctl", entry("ERRNO=%d", e));
7235aa1433SMatt Spinler         elog<InternalFailure>();
7335aa1433SMatt Spinler     }
7435aa1433SMatt Spinler }
7535aa1433SMatt Spinler 
requestLine(Value defaultValue)7635aa1433SMatt Spinler void GPIO::requestLine(Value defaultValue)
77da2e0fe9SMatt Spinler {
78da2e0fe9SMatt Spinler     // Only need to do this once
79da2e0fe9SMatt Spinler     if (lineFD)
80da2e0fe9SMatt Spinler     {
81da2e0fe9SMatt Spinler         return;
82da2e0fe9SMatt Spinler     }
83da2e0fe9SMatt Spinler 
84da2e0fe9SMatt Spinler     power::util::FileDescriptor fd{open(device.c_str(), 0)};
85da2e0fe9SMatt Spinler     if (fd() == -1)
86da2e0fe9SMatt Spinler     {
87da2e0fe9SMatt Spinler         auto e = errno;
88da2e0fe9SMatt Spinler         log<level::ERR>("Failed opening GPIO device",
897475b1c1SMatt Spinler                         entry("DEVICE=%s", device.c_str()),
90da2e0fe9SMatt Spinler                         entry("ERRNO=%d", e));
91da2e0fe9SMatt Spinler         elog<InternalFailure>();
92da2e0fe9SMatt Spinler     }
93da2e0fe9SMatt Spinler 
94da2e0fe9SMatt Spinler     // Make an ioctl call to request the GPIO line, which will
95da2e0fe9SMatt Spinler     // return the descriptor to use to access it.
96da2e0fe9SMatt Spinler     gpiohandle_request request{};
97f0f02b9aSMatt Spinler     strncpy(request.consumer_label, "witherspoon-pfault-analysis",
98da2e0fe9SMatt Spinler             sizeof(request.consumer_label));
99da2e0fe9SMatt Spinler 
100f0f02b9aSMatt Spinler     request.flags = (direction == Direction::input) ? GPIOHANDLE_REQUEST_INPUT
101f0f02b9aSMatt Spinler                                                     : GPIOHANDLE_REQUEST_OUTPUT;
102da2e0fe9SMatt Spinler 
103da2e0fe9SMatt Spinler     request.lineoffsets[0] = gpio;
104da2e0fe9SMatt Spinler     request.lines = 1;
105da2e0fe9SMatt Spinler 
10635aa1433SMatt Spinler     if (direction == Direction::output)
10735aa1433SMatt Spinler     {
10835aa1433SMatt Spinler         request.default_values[0] = static_cast<gpioValue_t>(defaultValue);
10935aa1433SMatt Spinler     }
11035aa1433SMatt Spinler 
111da2e0fe9SMatt Spinler     auto rc = ioctl(fd(), GPIO_GET_LINEHANDLE_IOCTL, &request);
112da2e0fe9SMatt Spinler     if (rc == -1)
113da2e0fe9SMatt Spinler     {
114da2e0fe9SMatt Spinler         auto e = errno;
115f0f02b9aSMatt Spinler         log<level::ERR>("Failed GET_LINEHANDLE ioctl", entry("GPIO=%d", gpio),
116da2e0fe9SMatt Spinler                         entry("ERRNO=%d", e));
117da2e0fe9SMatt Spinler         elog<InternalFailure>();
118da2e0fe9SMatt Spinler     }
119da2e0fe9SMatt Spinler 
120da2e0fe9SMatt Spinler     lineFD.set(request.fd);
121da2e0fe9SMatt Spinler }
122da2e0fe9SMatt Spinler 
123f0f02b9aSMatt Spinler } // namespace gpio
124f0f02b9aSMatt Spinler } // namespace witherspoon
125