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