gpio.c revision 274987
1274987Srpaulo/*-
2274987Srpaulo * Copyright (c) 2013-2014 Rui Paulo <rpaulo@FreeBSD.org>
3274987Srpaulo * All rights reserved.
4274987Srpaulo *
5274987Srpaulo * Redistribution and use in source and binary forms, with or without
6274987Srpaulo * modification, are permitted provided that the following conditions
7274987Srpaulo * are met:
8274987Srpaulo * 1. Redistributions of source code must retain the above copyright
9274987Srpaulo *    notice, this list of conditions and the following disclaimer.
10274987Srpaulo * 2. Redistributions in binary form must reproduce the above copyright
11274987Srpaulo *    notice, this list of conditions and the following disclaimer in the
12274987Srpaulo *    documentation and/or other materials provided with the distribution.
13274987Srpaulo *
14274987Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15274987Srpaulo * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16274987Srpaulo * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17274987Srpaulo * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
18274987Srpaulo * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19274987Srpaulo * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20274987Srpaulo * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21274987Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22274987Srpaulo * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
23274987Srpaulo * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24274987Srpaulo * POSSIBILITY OF SUCH DAMAGE.
25274987Srpaulo *
26274987Srpaulo * $FreeBSD: head/lib/libgpio/gpio.c 274987 2014-11-24 21:49:40Z rpaulo $
27274987Srpaulo */
28274987Srpaulo#include <stdio.h>
29274987Srpaulo#include <fcntl.h>
30274987Srpaulo#include <unistd.h>
31274987Srpaulo#include <stdlib.h>
32274987Srpaulo#include <string.h>
33274987Srpaulo#include <errno.h>
34274987Srpaulo
35274987Srpaulo#include <sys/ioctl.h>
36274987Srpaulo#include <sys/types.h>
37274987Srpaulo
38274987Srpaulo#include <libgpio.h>
39274987Srpaulo
40274987Srpaulogpio_handle_t
41274987Srpaulogpio_open(unsigned int unit)
42274987Srpaulo{
43274987Srpaulo	char device[16];
44274987Srpaulo
45274987Srpaulo	snprintf(device, sizeof(device), "/dev/gpioc%u", unit);
46274987Srpaulo
47274987Srpaulo	return (gpio_open_device(device));
48274987Srpaulo}
49274987Srpaulo
50274987Srpaulogpio_handle_t
51274987Srpaulogpio_open_device(const char *device)
52274987Srpaulo{
53274987Srpaulo	int fd, maxpins;
54274987Srpaulo	int serr;
55274987Srpaulo
56274987Srpaulo	fd = open(device, O_RDONLY);
57274987Srpaulo	if (fd < 0)
58274987Srpaulo		return (GPIO_INVALID_HANDLE);
59274987Srpaulo	/*
60274987Srpaulo	 * Check whether a simple ioctl works.
61274987Srpaulo	 */
62274987Srpaulo	if (ioctl(fd, GPIOMAXPIN, &maxpins) < 0) {
63274987Srpaulo		serr = errno;
64274987Srpaulo		close(fd);
65274987Srpaulo		errno = serr;
66274987Srpaulo		return (GPIO_INVALID_HANDLE);
67274987Srpaulo	}
68274987Srpaulo
69274987Srpaulo	return (fd);
70274987Srpaulo}
71274987Srpaulo
72274987Srpaulovoid
73274987Srpaulogpio_close(gpio_handle_t handle)
74274987Srpaulo{
75274987Srpaulo	close(handle);
76274987Srpaulo}
77274987Srpaulo
78274987Srpauloint
79274987Srpaulogpio_pin_list(gpio_handle_t handle, gpio_config_t **pcfgs)
80274987Srpaulo{
81274987Srpaulo	int maxpins, i;
82274987Srpaulo	gpio_config_t *cfgs;
83274987Srpaulo
84274987Srpaulo	*pcfgs = NULL;
85274987Srpaulo	if (ioctl(handle, GPIOMAXPIN, &maxpins) < 0)
86274987Srpaulo		return (-1);
87274987Srpaulo	/* Reasonable values. */
88274987Srpaulo	if (maxpins < 0 || maxpins > 4096) {
89274987Srpaulo		errno = EINVAL;
90274987Srpaulo		return (-1);
91274987Srpaulo	}
92274987Srpaulo	cfgs = calloc(maxpins, sizeof(*cfgs));
93274987Srpaulo	if (cfgs == NULL)
94274987Srpaulo		return (-1);
95274987Srpaulo	for (i = 0; i <= maxpins; i++) {
96274987Srpaulo		cfgs[i].g_pin = i;
97274987Srpaulo		gpio_pin_config(handle, &cfgs[i]);
98274987Srpaulo	}
99274987Srpaulo	*pcfgs = cfgs;
100274987Srpaulo
101274987Srpaulo	return (maxpins);
102274987Srpaulo}
103274987Srpaulo
104274987Srpauloint
105274987Srpaulogpio_pin_config(gpio_handle_t handle, gpio_config_t *cfg)
106274987Srpaulo{
107274987Srpaulo	struct gpio_pin gppin;
108274987Srpaulo
109274987Srpaulo	if (cfg == NULL)
110274987Srpaulo		return (-1);
111274987Srpaulo	gppin.gp_pin = cfg->g_pin;
112274987Srpaulo	if (ioctl(handle, GPIOGETCONFIG, &gppin) < 0)
113274987Srpaulo		return (-1);
114274987Srpaulo	strlcpy(cfg->g_name, gppin.gp_name, GPIOMAXNAME);
115274987Srpaulo	cfg->g_caps = gppin.gp_caps;
116274987Srpaulo	cfg->g_flags = gppin.gp_flags;
117274987Srpaulo
118274987Srpaulo	return (0);
119274987Srpaulo}
120274987Srpaulo
121274987Srpauloint
122274987Srpaulogpio_pin_set_flags(gpio_handle_t handle, gpio_config_t *cfg)
123274987Srpaulo{
124274987Srpaulo	struct gpio_pin gppin;
125274987Srpaulo
126274987Srpaulo	if (cfg == NULL)
127274987Srpaulo		return (-1);
128274987Srpaulo	gppin.gp_pin = cfg->g_pin;
129274987Srpaulo	gppin.gp_flags = cfg->g_flags;
130274987Srpaulo	if (ioctl(handle, GPIOSETCONFIG, &gppin) < 0)
131274987Srpaulo		return (-1);
132274987Srpaulo
133274987Srpaulo	return (0);
134274987Srpaulo}
135274987Srpaulo
136274987Srpaulogpio_value_t
137274987Srpaulogpio_pin_get(gpio_handle_t handle, gpio_pin_t pin)
138274987Srpaulo{
139274987Srpaulo	struct gpio_req gpreq;
140274987Srpaulo
141274987Srpaulo	bzero(&gpreq, sizeof(gpreq));
142274987Srpaulo	gpreq.gp_pin = pin;
143274987Srpaulo	if (ioctl(handle, GPIOGET, &gpreq) < 0)
144274987Srpaulo		return (GPIO_VALUE_INVALID);
145274987Srpaulo
146274987Srpaulo	return (gpreq.gp_value);
147274987Srpaulo}
148274987Srpaulo
149274987Srpauloint
150274987Srpaulogpio_pin_set(gpio_handle_t handle, gpio_pin_t pin, gpio_value_t value)
151274987Srpaulo{
152274987Srpaulo	struct gpio_req gpreq;
153274987Srpaulo
154274987Srpaulo	if (value == GPIO_VALUE_INVALID)
155274987Srpaulo		return (-1);
156274987Srpaulo	bzero(&gpreq, sizeof(gpreq));
157274987Srpaulo	gpreq.gp_pin = pin;
158274987Srpaulo	gpreq.gp_value = value;
159274987Srpaulo	if (ioctl(handle, GPIOSET, &gpreq) < 0)
160274987Srpaulo		return (-1);
161274987Srpaulo
162274987Srpaulo	return (0);
163274987Srpaulo}
164274987Srpaulo
165274987Srpauloint
166274987Srpaulogpio_pin_toggle(gpio_handle_t handle, gpio_pin_t pin)
167274987Srpaulo{
168274987Srpaulo	gpio_value_t value;
169274987Srpaulo
170274987Srpaulo	value = gpio_pin_get(handle, pin);
171274987Srpaulo	if (value == GPIO_VALUE_INVALID)
172274987Srpaulo		return (-1);
173274987Srpaulo	value = !value;
174274987Srpaulo
175274987Srpaulo	return (gpio_pin_set(handle, pin, value));
176274987Srpaulo}
177274987Srpaulo
178274987Srpauloint
179274987Srpaulogpio_pin_low(gpio_handle_t handle, gpio_pin_t pin)
180274987Srpaulo{
181274987Srpaulo	return (gpio_pin_set(handle, pin, GPIO_VALUE_LOW));
182274987Srpaulo}
183274987Srpaulo
184274987Srpauloint
185274987Srpaulogpio_pin_high(gpio_handle_t handle, gpio_pin_t pin)
186274987Srpaulo{
187274987Srpaulo	return (gpio_pin_set(handle, pin, GPIO_VALUE_HIGH));
188274987Srpaulo}
189274987Srpaulo
190274987Srpaulostatic int
191274987Srpaulogpio_pin_set_flag(gpio_handle_t handle, gpio_pin_t pin, uint32_t flag)
192274987Srpaulo{
193274987Srpaulo	gpio_config_t cfg;
194274987Srpaulo
195274987Srpaulo	bzero(&cfg, sizeof(cfg));
196274987Srpaulo	cfg.g_pin = pin;
197274987Srpaulo	if (gpio_pin_config(handle, &cfg) < 0)
198274987Srpaulo		return (-1);
199274987Srpaulo	cfg.g_flags = flag;
200274987Srpaulo
201274987Srpaulo	return (gpio_pin_set_flags(handle, &cfg));
202274987Srpaulo}
203274987Srpaulo
204274987Srpauloint
205274987Srpaulogpio_pin_input(gpio_handle_t handle, gpio_pin_t pin)
206274987Srpaulo{
207274987Srpaulo	return (gpio_pin_set_flag(handle, pin, GPIO_PIN_INPUT));
208274987Srpaulo}
209274987Srpaulo
210274987Srpauloint
211274987Srpaulogpio_pin_output(gpio_handle_t handle, gpio_pin_t pin)
212274987Srpaulo{
213274987Srpaulo	return (gpio_pin_set_flag(handle, pin, GPIO_PIN_OUTPUT));
214274987Srpaulo}
215274987Srpaulo
216274987Srpauloint
217274987Srpaulogpio_pin_opendrain(gpio_handle_t handle, gpio_pin_t pin)
218274987Srpaulo{
219274987Srpaulo	return (gpio_pin_set_flag(handle, pin, GPIO_PIN_OPENDRAIN));
220274987Srpaulo}
221274987Srpaulo
222274987Srpauloint
223274987Srpaulogpio_pin_pushpull(gpio_handle_t handle, gpio_pin_t pin)
224274987Srpaulo{
225274987Srpaulo	return (gpio_pin_set_flag(handle, pin, GPIO_PIN_PUSHPULL));
226274987Srpaulo}
227274987Srpaulo
228274987Srpauloint
229274987Srpaulogpio_pin_tristate(gpio_handle_t handle, gpio_pin_t pin)
230274987Srpaulo{
231274987Srpaulo	return (gpio_pin_set_flag(handle, pin, GPIO_PIN_TRISTATE));
232274987Srpaulo}
233274987Srpaulo
234274987Srpauloint
235274987Srpaulogpio_pin_pullup(gpio_handle_t handle, gpio_pin_t pin)
236274987Srpaulo{
237274987Srpaulo	return (gpio_pin_set_flag(handle, pin, GPIO_PIN_PULLUP));
238274987Srpaulo}
239274987Srpaulo
240274987Srpauloint
241274987Srpaulogpio_pin_pulldown(gpio_handle_t handle, gpio_pin_t pin)
242274987Srpaulo{
243274987Srpaulo	return (gpio_pin_set_flag(handle, pin, GPIO_PIN_PULLDOWN));
244274987Srpaulo}
245274987Srpaulo
246274987Srpauloint
247274987Srpaulogpio_pin_invin(gpio_handle_t handle, gpio_pin_t pin)
248274987Srpaulo{
249274987Srpaulo	return (gpio_pin_set_flag(handle, pin, GPIO_PIN_INVIN));
250274987Srpaulo}
251274987Srpaulo
252274987Srpauloint
253274987Srpaulogpio_pin_invout(gpio_handle_t handle, gpio_pin_t pin)
254274987Srpaulo{
255274987Srpaulo	return (gpio_pin_set_flag(handle, pin, GPIO_PIN_INVOUT));
256274987Srpaulo}
257274987Srpaulo
258274987Srpauloint
259274987Srpaulogpio_pin_pulsate(gpio_handle_t handle, gpio_pin_t pin)
260274987Srpaulo{
261274987Srpaulo	return (gpio_pin_set_flag(handle, pin, GPIO_PIN_PULSATE));
262274987Srpaulo}
263