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/lg2.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 lg2::error("Failed GET_LINE_VALUES ioctl ERRNO={ERRNO}", "ERRNO", 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 lg2::error("Failed SET_LINE_VALUES ioctl ERRNO={ERRNO}", "ERRNO", 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 lg2::error("Failed opening GPIO device DEVICE={DEVICE} ERRNO={ERRNO}", 89 "DEVICE", device, "ERRNO", 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 lg2::error("Failed GET_LINEHANDLE ioctl GPIO={GPIO} ERRNO={ERRNO}", 115 "GPIO", gpio, "ERRNO", e); 116 elog<InternalFailure>(); 117 } 118 119 lineFD.set(request.fd); 120 } 121 122 } // namespace gpio 123 } // namespace phosphor 124