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 <cassert> 17 #include <fcntl.h> 18 #include <phosphor-logging/elog.hpp> 19 #include <phosphor-logging/elog-errors.hpp> 20 #include <phosphor-logging/log.hpp> 21 #include <sys/ioctl.h> 22 #include <xyz/openbmc_project/Common/error.hpp> 23 #include "gpio.hpp" 24 25 namespace witherspoon 26 { 27 namespace gpio 28 { 29 30 using namespace phosphor::logging; 31 32 using InternalFailure = sdbusplus::xyz::openbmc_project::Common:: 33 Error::InternalFailure; 34 35 Value GPIO::read() 36 { 37 assert(direction == Direction::input); 38 39 requestLine(); 40 41 gpiohandle_data data{}; 42 43 auto rc = ioctl(lineFD(), 44 GPIOHANDLE_GET_LINE_VALUES_IOCTL, 45 &data); 46 47 if (rc < 0) 48 { 49 auto e = errno; 50 log<level::ERR>("Failed GET_LINE_VALUES ioctl", 51 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", 72 entry("ERRNO=%d", e)); 73 elog<InternalFailure>(); 74 } 75 } 76 77 void GPIO::requestLine(Value defaultValue) 78 { 79 //Only need to do this once 80 if (lineFD) 81 { 82 return; 83 } 84 85 power::util::FileDescriptor fd{open(device.c_str(), 0)}; 86 if (fd() == -1) 87 { 88 auto e = errno; 89 log<level::ERR>("Failed opening GPIO device", 90 entry("DEVICE=%s", device.c_str()), 91 entry("ERRNO=%d", e)); 92 elog<InternalFailure>(); 93 } 94 95 //Make an ioctl call to request the GPIO line, which will 96 //return the descriptor to use to access it. 97 gpiohandle_request request{}; 98 strncpy(request.consumer_label, 99 "witherspoon-pfault-analysis", 100 sizeof(request.consumer_label)); 101 102 request.flags = (direction == Direction::input) ? 103 GPIOHANDLE_REQUEST_INPUT : GPIOHANDLE_REQUEST_OUTPUT; 104 105 request.lineoffsets[0] = gpio; 106 request.lines = 1; 107 108 if (direction == Direction::output) 109 { 110 request.default_values[0] = static_cast<gpioValue_t>(defaultValue); 111 } 112 113 auto rc = ioctl(fd(), GPIO_GET_LINEHANDLE_IOCTL, &request); 114 if (rc == -1) 115 { 116 auto e = errno; 117 log<level::ERR>("Failed GET_LINEHANDLE ioctl", 118 entry("GPIO=%d", gpio), 119 entry("ERRNO=%d", e)); 120 elog<InternalFailure>(); 121 } 122 123 lineFD.set(request.fd); 124 } 125 126 } 127 } 128