1275970Scy/*- 2275970Scy * Copyright (c) 2013-2014 Rui Paulo <rpaulo@FreeBSD.org> 3275970Scy * All rights reserved. 4275970Scy * 5275970Scy * Redistribution and use in source and binary forms, with or without 6275970Scy * modification, are permitted provided that the following conditions 7275970Scy * are met: 8275970Scy * 1. Redistributions of source code must retain the above copyright 9275970Scy * notice, this list of conditions and the following disclaimer. 10275970Scy * 2. Redistributions in binary form must reproduce the above copyright 11275970Scy * notice, this list of conditions and the following disclaimer in the 12275970Scy * documentation and/or other materials provided with the distribution. 13275970Scy * 14275970Scy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15275970Scy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16275970Scy * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17275970Scy * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 18275970Scy * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19275970Scy * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20275970Scy * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21275970Scy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22275970Scy * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 23275970Scy * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24275970Scy * POSSIBILITY OF SUCH DAMAGE. 25275970Scy * 26275970Scy * $FreeBSD: releng/11.0/lib/libgpio/gpio.c 298272 2016-04-19 15:18:31Z loos $ 27275970Scy */ 28275970Scy#include <stdio.h> 29275970Scy#include <fcntl.h> 30275970Scy#include <unistd.h> 31275970Scy#include <stdlib.h> 32275970Scy#include <string.h> 33275970Scy#include <errno.h> 34275970Scy 35275970Scy#include <sys/ioctl.h> 36275970Scy#include <sys/types.h> 37275970Scy 38275970Scy#include <libgpio.h> 39275970Scy 40275970Scygpio_handle_t 41275970Scygpio_open(unsigned int unit) 42275970Scy{ 43275970Scy char device[16]; 44275970Scy 45275970Scy snprintf(device, sizeof(device), "/dev/gpioc%u", unit); 46275970Scy 47275970Scy return (gpio_open_device(device)); 48275970Scy} 49275970Scy 50275970Scygpio_handle_t 51275970Scygpio_open_device(const char *device) 52275970Scy{ 53275970Scy int fd, maxpins; 54275970Scy int serr; 55275970Scy 56275970Scy fd = open(device, O_RDONLY); 57275970Scy if (fd < 0) 58275970Scy return (GPIO_INVALID_HANDLE); 59275970Scy /* 60275970Scy * Check whether a simple ioctl works. 61275970Scy */ 62275970Scy if (ioctl(fd, GPIOMAXPIN, &maxpins) < 0) { 63275970Scy serr = errno; 64275970Scy close(fd); 65275970Scy errno = serr; 66275970Scy return (GPIO_INVALID_HANDLE); 67275970Scy } 68275970Scy 69275970Scy return (fd); 70275970Scy} 71275970Scy 72275970Scyvoid 73275970Scygpio_close(gpio_handle_t handle) 74275970Scy{ 75275970Scy close(handle); 76275970Scy} 77275970Scy 78275970Scyint 79275970Scygpio_pin_list(gpio_handle_t handle, gpio_config_t **pcfgs) 80275970Scy{ 81275970Scy int maxpins, i; 82275970Scy gpio_config_t *cfgs; 83275970Scy 84275970Scy *pcfgs = NULL; 85275970Scy if (ioctl(handle, GPIOMAXPIN, &maxpins) < 0) 86275970Scy return (-1); 87275970Scy /* Reasonable values. */ 88275970Scy if (maxpins < 0 || maxpins > 4096) { 89275970Scy errno = EINVAL; 90275970Scy return (-1); 91275970Scy } 92275970Scy cfgs = calloc(maxpins + 1, sizeof(*cfgs)); 93275970Scy if (cfgs == NULL) 94275970Scy return (-1); 95275970Scy for (i = 0; i <= maxpins; i++) { 96275970Scy cfgs[i].g_pin = i; 97275970Scy gpio_pin_config(handle, &cfgs[i]); 98275970Scy } 99275970Scy *pcfgs = cfgs; 100275970Scy 101275970Scy return (maxpins); 102275970Scy} 103275970Scy 104275970Scyint 105275970Scygpio_pin_config(gpio_handle_t handle, gpio_config_t *cfg) 106275970Scy{ 107275970Scy struct gpio_pin gppin; 108275970Scy 109275970Scy if (cfg == NULL) 110275970Scy return (-1); 111275970Scy gppin.gp_pin = cfg->g_pin; 112275970Scy if (ioctl(handle, GPIOGETCONFIG, &gppin) < 0) 113275970Scy return (-1); 114275970Scy strlcpy(cfg->g_name, gppin.gp_name, GPIOMAXNAME); 115275970Scy cfg->g_caps = gppin.gp_caps; 116275970Scy cfg->g_flags = gppin.gp_flags; 117275970Scy 118275970Scy return (0); 119275970Scy} 120275970Scy 121275970Scyint 122275970Scygpio_pin_set_name(gpio_handle_t handle, gpio_pin_t pin, char *name) 123275970Scy{ 124275970Scy struct gpio_pin gppin; 125275970Scy 126275970Scy if (name == NULL) 127275970Scy return (-1); 128275970Scy bzero(&gppin, sizeof(gppin)); 129275970Scy gppin.gp_pin = pin; 130275970Scy strlcpy(gppin.gp_name, name, GPIOMAXNAME); 131275970Scy if (ioctl(handle, GPIOSETNAME, &gppin) < 0) 132275970Scy return (-1); 133275970Scy 134275970Scy return (0); 135275970Scy} 136275970Scy 137275970Scyint 138275970Scygpio_pin_set_flags(gpio_handle_t handle, gpio_config_t *cfg) 139275970Scy{ 140275970Scy struct gpio_pin gppin; 141275970Scy 142275970Scy if (cfg == NULL) 143275970Scy return (-1); 144275970Scy gppin.gp_pin = cfg->g_pin; 145275970Scy gppin.gp_flags = cfg->g_flags; 146275970Scy if (ioctl(handle, GPIOSETCONFIG, &gppin) < 0) 147275970Scy return (-1); 148275970Scy 149275970Scy return (0); 150275970Scy} 151275970Scy 152275970Scygpio_value_t 153275970Scygpio_pin_get(gpio_handle_t handle, gpio_pin_t pin) 154275970Scy{ 155275970Scy struct gpio_req gpreq; 156275970Scy 157275970Scy bzero(&gpreq, sizeof(gpreq)); 158275970Scy gpreq.gp_pin = pin; 159275970Scy if (ioctl(handle, GPIOGET, &gpreq) < 0) 160275970Scy return (GPIO_VALUE_INVALID); 161275970Scy 162275970Scy return (gpreq.gp_value); 163275970Scy} 164275970Scy 165275970Scyint 166275970Scygpio_pin_set(gpio_handle_t handle, gpio_pin_t pin, gpio_value_t value) 167275970Scy{ 168275970Scy struct gpio_req gpreq; 169275970Scy 170275970Scy if (value == GPIO_VALUE_INVALID) 171275970Scy return (-1); 172275970Scy bzero(&gpreq, sizeof(gpreq)); 173275970Scy gpreq.gp_pin = pin; 174275970Scy gpreq.gp_value = value; 175275970Scy if (ioctl(handle, GPIOSET, &gpreq) < 0) 176275970Scy return (-1); 177275970Scy 178275970Scy return (0); 179275970Scy} 180275970Scy 181275970Scyint 182275970Scygpio_pin_toggle(gpio_handle_t handle, gpio_pin_t pin) 183275970Scy{ 184275970Scy struct gpio_req gpreq; 185275970Scy 186275970Scy bzero(&gpreq, sizeof(gpreq)); 187275970Scy gpreq.gp_pin = pin; 188275970Scy if (ioctl(handle, GPIOTOGGLE, &gpreq) < 0) 189275970Scy return (-1); 190275970Scy 191275970Scy return (0); 192275970Scy} 193275970Scy 194275970Scyint 195275970Scygpio_pin_low(gpio_handle_t handle, gpio_pin_t pin) 196275970Scy{ 197275970Scy return (gpio_pin_set(handle, pin, GPIO_VALUE_LOW)); 198275970Scy} 199275970Scy 200275970Scyint 201275970Scygpio_pin_high(gpio_handle_t handle, gpio_pin_t pin) 202275970Scy{ 203275970Scy return (gpio_pin_set(handle, pin, GPIO_VALUE_HIGH)); 204275970Scy} 205275970Scy 206275970Scystatic int 207275970Scygpio_pin_set_flag(gpio_handle_t handle, gpio_pin_t pin, uint32_t flag) 208275970Scy{ 209275970Scy gpio_config_t cfg; 210275970Scy 211275970Scy bzero(&cfg, sizeof(cfg)); 212275970Scy cfg.g_pin = pin; 213275970Scy if (gpio_pin_config(handle, &cfg) < 0) 214275970Scy return (-1); 215275970Scy cfg.g_flags = flag; 216275970Scy 217275970Scy return (gpio_pin_set_flags(handle, &cfg)); 218275970Scy} 219275970Scy 220275970Scyint 221275970Scygpio_pin_input(gpio_handle_t handle, gpio_pin_t pin) 222275970Scy{ 223275970Scy return (gpio_pin_set_flag(handle, pin, GPIO_PIN_INPUT)); 224275970Scy} 225275970Scy 226275970Scyint 227275970Scygpio_pin_output(gpio_handle_t handle, gpio_pin_t pin) 228275970Scy{ 229275970Scy return (gpio_pin_set_flag(handle, pin, GPIO_PIN_OUTPUT)); 230275970Scy} 231275970Scy 232275970Scyint 233275970Scygpio_pin_opendrain(gpio_handle_t handle, gpio_pin_t pin) 234275970Scy{ 235275970Scy return (gpio_pin_set_flag(handle, pin, GPIO_PIN_OPENDRAIN)); 236275970Scy} 237275970Scy 238275970Scyint 239275970Scygpio_pin_pushpull(gpio_handle_t handle, gpio_pin_t pin) 240275970Scy{ 241275970Scy return (gpio_pin_set_flag(handle, pin, GPIO_PIN_PUSHPULL)); 242275970Scy} 243275970Scy 244275970Scyint 245275970Scygpio_pin_tristate(gpio_handle_t handle, gpio_pin_t pin) 246275970Scy{ 247275970Scy return (gpio_pin_set_flag(handle, pin, GPIO_PIN_TRISTATE)); 248275970Scy} 249275970Scy 250275970Scyint 251275970Scygpio_pin_pullup(gpio_handle_t handle, gpio_pin_t pin) 252275970Scy{ 253275970Scy return (gpio_pin_set_flag(handle, pin, GPIO_PIN_PULLUP)); 254275970Scy} 255275970Scy 256275970Scyint 257275970Scygpio_pin_pulldown(gpio_handle_t handle, gpio_pin_t pin) 258275970Scy{ 259275970Scy return (gpio_pin_set_flag(handle, pin, GPIO_PIN_PULLDOWN)); 260275970Scy} 261275970Scy 262275970Scyint 263275970Scygpio_pin_invin(gpio_handle_t handle, gpio_pin_t pin) 264275970Scy{ 265275970Scy return (gpio_pin_set_flag(handle, pin, GPIO_PIN_INVIN)); 266275970Scy} 267275970Scy 268275970Scyint 269275970Scygpio_pin_invout(gpio_handle_t handle, gpio_pin_t pin) 270275970Scy{ 271275970Scy return (gpio_pin_set_flag(handle, pin, GPIO_PIN_INVOUT)); 272275970Scy} 273275970Scy 274275970Scyint 275275970Scygpio_pin_pulsate(gpio_handle_t handle, gpio_pin_t pin) 276275970Scy{ 277275970Scy return (gpio_pin_set_flag(handle, pin, GPIO_PIN_PULSATE)); 278275970Scy} 279275970Scy