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