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$
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	}
92275396Srpaulo	cfgs = calloc(maxpins + 1, 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
122279761Sloosgpio_pin_set_name(gpio_handle_t handle, gpio_pin_t pin, char *name)
123279761Sloos{
124279761Sloos	struct gpio_pin gppin;
125279761Sloos
126279761Sloos	if (name == NULL)
127279761Sloos		return (-1);
128279761Sloos	bzero(&gppin, sizeof(gppin));
129279761Sloos	gppin.gp_pin = pin;
130279761Sloos	strlcpy(gppin.gp_name, name, GPIOMAXNAME);
131279761Sloos	if (ioctl(handle, GPIOSETNAME, &gppin) < 0)
132279761Sloos		return (-1);
133279761Sloos
134279761Sloos	return (0);
135279761Sloos}
136279761Sloos
137279761Sloosint
138274987Srpaulogpio_pin_set_flags(gpio_handle_t handle, gpio_config_t *cfg)
139274987Srpaulo{
140274987Srpaulo	struct gpio_pin gppin;
141274987Srpaulo
142274987Srpaulo	if (cfg == NULL)
143274987Srpaulo		return (-1);
144274987Srpaulo	gppin.gp_pin = cfg->g_pin;
145274987Srpaulo	gppin.gp_flags = cfg->g_flags;
146274987Srpaulo	if (ioctl(handle, GPIOSETCONFIG, &gppin) < 0)
147274987Srpaulo		return (-1);
148274987Srpaulo
149274987Srpaulo	return (0);
150274987Srpaulo}
151274987Srpaulo
152274987Srpaulogpio_value_t
153274987Srpaulogpio_pin_get(gpio_handle_t handle, gpio_pin_t pin)
154274987Srpaulo{
155274987Srpaulo	struct gpio_req gpreq;
156274987Srpaulo
157274987Srpaulo	bzero(&gpreq, sizeof(gpreq));
158274987Srpaulo	gpreq.gp_pin = pin;
159274987Srpaulo	if (ioctl(handle, GPIOGET, &gpreq) < 0)
160274987Srpaulo		return (GPIO_VALUE_INVALID);
161274987Srpaulo
162274987Srpaulo	return (gpreq.gp_value);
163274987Srpaulo}
164274987Srpaulo
165274987Srpauloint
166274987Srpaulogpio_pin_set(gpio_handle_t handle, gpio_pin_t pin, gpio_value_t value)
167274987Srpaulo{
168274987Srpaulo	struct gpio_req gpreq;
169274987Srpaulo
170274987Srpaulo	if (value == GPIO_VALUE_INVALID)
171274987Srpaulo		return (-1);
172274987Srpaulo	bzero(&gpreq, sizeof(gpreq));
173274987Srpaulo	gpreq.gp_pin = pin;
174274987Srpaulo	gpreq.gp_value = value;
175274987Srpaulo	if (ioctl(handle, GPIOSET, &gpreq) < 0)
176274987Srpaulo		return (-1);
177274987Srpaulo
178274987Srpaulo	return (0);
179274987Srpaulo}
180274987Srpaulo
181274987Srpauloint
182274987Srpaulogpio_pin_toggle(gpio_handle_t handle, gpio_pin_t pin)
183274987Srpaulo{
184298272Sloos	struct gpio_req gpreq;
185274987Srpaulo
186298272Sloos	bzero(&gpreq, sizeof(gpreq));
187298272Sloos	gpreq.gp_pin = pin;
188298272Sloos	if (ioctl(handle, GPIOTOGGLE, &gpreq) < 0)
189274987Srpaulo		return (-1);
190274987Srpaulo
191298272Sloos	return (0);
192274987Srpaulo}
193274987Srpaulo
194274987Srpauloint
195274987Srpaulogpio_pin_low(gpio_handle_t handle, gpio_pin_t pin)
196274987Srpaulo{
197274987Srpaulo	return (gpio_pin_set(handle, pin, GPIO_VALUE_LOW));
198274987Srpaulo}
199274987Srpaulo
200274987Srpauloint
201274987Srpaulogpio_pin_high(gpio_handle_t handle, gpio_pin_t pin)
202274987Srpaulo{
203274987Srpaulo	return (gpio_pin_set(handle, pin, GPIO_VALUE_HIGH));
204274987Srpaulo}
205274987Srpaulo
206274987Srpaulostatic int
207274987Srpaulogpio_pin_set_flag(gpio_handle_t handle, gpio_pin_t pin, uint32_t flag)
208274987Srpaulo{
209274987Srpaulo	gpio_config_t cfg;
210274987Srpaulo
211274987Srpaulo	bzero(&cfg, sizeof(cfg));
212274987Srpaulo	cfg.g_pin = pin;
213274987Srpaulo	if (gpio_pin_config(handle, &cfg) < 0)
214274987Srpaulo		return (-1);
215274987Srpaulo	cfg.g_flags = flag;
216274987Srpaulo
217274987Srpaulo	return (gpio_pin_set_flags(handle, &cfg));
218274987Srpaulo}
219274987Srpaulo
220274987Srpauloint
221274987Srpaulogpio_pin_input(gpio_handle_t handle, gpio_pin_t pin)
222274987Srpaulo{
223274987Srpaulo	return (gpio_pin_set_flag(handle, pin, GPIO_PIN_INPUT));
224274987Srpaulo}
225274987Srpaulo
226274987Srpauloint
227274987Srpaulogpio_pin_output(gpio_handle_t handle, gpio_pin_t pin)
228274987Srpaulo{
229274987Srpaulo	return (gpio_pin_set_flag(handle, pin, GPIO_PIN_OUTPUT));
230274987Srpaulo}
231274987Srpaulo
232274987Srpauloint
233274987Srpaulogpio_pin_opendrain(gpio_handle_t handle, gpio_pin_t pin)
234274987Srpaulo{
235274987Srpaulo	return (gpio_pin_set_flag(handle, pin, GPIO_PIN_OPENDRAIN));
236274987Srpaulo}
237274987Srpaulo
238274987Srpauloint
239274987Srpaulogpio_pin_pushpull(gpio_handle_t handle, gpio_pin_t pin)
240274987Srpaulo{
241274987Srpaulo	return (gpio_pin_set_flag(handle, pin, GPIO_PIN_PUSHPULL));
242274987Srpaulo}
243274987Srpaulo
244274987Srpauloint
245274987Srpaulogpio_pin_tristate(gpio_handle_t handle, gpio_pin_t pin)
246274987Srpaulo{
247274987Srpaulo	return (gpio_pin_set_flag(handle, pin, GPIO_PIN_TRISTATE));
248274987Srpaulo}
249274987Srpaulo
250274987Srpauloint
251274987Srpaulogpio_pin_pullup(gpio_handle_t handle, gpio_pin_t pin)
252274987Srpaulo{
253274987Srpaulo	return (gpio_pin_set_flag(handle, pin, GPIO_PIN_PULLUP));
254274987Srpaulo}
255274987Srpaulo
256274987Srpauloint
257274987Srpaulogpio_pin_pulldown(gpio_handle_t handle, gpio_pin_t pin)
258274987Srpaulo{
259274987Srpaulo	return (gpio_pin_set_flag(handle, pin, GPIO_PIN_PULLDOWN));
260274987Srpaulo}
261274987Srpaulo
262274987Srpauloint
263274987Srpaulogpio_pin_invin(gpio_handle_t handle, gpio_pin_t pin)
264274987Srpaulo{
265274987Srpaulo	return (gpio_pin_set_flag(handle, pin, GPIO_PIN_INVIN));
266274987Srpaulo}
267274987Srpaulo
268274987Srpauloint
269274987Srpaulogpio_pin_invout(gpio_handle_t handle, gpio_pin_t pin)
270274987Srpaulo{
271274987Srpaulo	return (gpio_pin_set_flag(handle, pin, GPIO_PIN_INVOUT));
272274987Srpaulo}
273274987Srpaulo
274274987Srpauloint
275274987Srpaulogpio_pin_pulsate(gpio_handle_t handle, gpio_pin_t pin)
276274987Srpaulo{
277274987Srpaulo	return (gpio_pin_set_flag(handle, pin, GPIO_PIN_PULSATE));
278274987Srpaulo}
279