Skip to content

Commit 87fbc38

Browse files
committed
Add local gpio control
This driver permits controlling local (on the system) gpios by using the libgpiod library. Support for gpiod v1 and v2 is added, and parses the options via the yaml parser. This can be tested with the gpio-sim module: https://docs.kernel.org/admin-guide/gpio/gpio-sim.html Signed-off-by: Neil Armstrong <[email protected]>
1 parent 55902b7 commit 87fbc38

File tree

13 files changed

+522
-0
lines changed

13 files changed

+522
-0
lines changed

README

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,26 @@ devices:
6161
fastboot: 91671140
6262
fastboot_set_active: true
6363
fastboot_key_timeout: 2
64+
65+
- board: testboard
66+
console: /dev/serial/by-id/usb-1234-if00-port0
67+
name: GPIO controller board
68+
local_gpio:
69+
- power:
70+
chip: gpiochip0
71+
line: 7
72+
active_low: true
73+
- fastboot_key:
74+
chip: gpiochip0
75+
line: 8
76+
active_low: true
77+
- power_key:
78+
chip: gpiochip0
79+
line: 14
80+
active_low: true
81+
- usb_disconnect:
82+
chip: gpiochip1
83+
line: 4
84+
fastboot: cacafada
85+
fastboot_set_active: true
86+
fastboot_key_timeout: 2

ci/archlinux.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pacman -Syu --noconfirm \
2020
libftdi-compat \
2121
libyaml \
2222
systemd-libs \
23+
libgpiod \
2324
pkgconf \
2425
meson \
2526
$PKGS_CC

ci/debian.cross-compile.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ apt install -y --no-install-recommends \
2222
libftdi-dev:${ARCH} \
2323
libudev-dev:${ARCH} \
2424
libyaml-dev:${ARCH} \
25+
libgpiod-dev:${ARCH} \
2526
gcc-`dpkg-architecture -a ${ARCH} -q DEB_TARGET_GNU_TYPE`
2627

2728
echo "Install finished: $0"

ci/debian.i386.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ apt install -y --no-install-recommends \
2323
libftdi-dev:i386 \
2424
libudev-dev:i386 \
2525
libyaml-dev:i386 \
26+
libgpiod-dev:i386 \
2627
$PKGS_CC
2728

2829
echo "Install finished: $0"

ci/debian.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ apt install -y --no-install-recommends \
3232
libftdi-dev \
3333
libudev-dev \
3434
libyaml-dev \
35+
libgpiod-dev \
3536
meson \
3637
$PKGS_CC
3738

ci/fedora.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ dnf -y install \
2020
libftdi-devel \
2121
libudev-devel \
2222
libyaml-devel \
23+
libgpiod-devel \
2324
meson \
2425
$PKGS_CC
2526

device.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ extern const struct control_ops alpaca_ops;
9393
extern const struct control_ops cdb_assist_ops;
9494
extern const struct control_ops conmux_ops;
9595
extern const struct control_ops ftdi_gpio_ops;
96+
extern const struct control_ops local_gpio_ops;
9697
extern const struct control_ops external_ops;
9798
extern const struct control_ops qcomlt_dbg_ops;
9899

device_parser.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,13 @@ static void parse_board(struct device_parser *dp)
129129
continue;
130130
}
131131

132+
if (!strcmp(key, "local_gpio")) {
133+
dev->control_options = local_gpio_ops.parse_options(dp);
134+
if (dev->control_options)
135+
set_control_ops(dev, &local_gpio_ops);
136+
continue;
137+
}
138+
132139
device_parser_expect(dp, YAML_SCALAR_EVENT, value, TOKEN_LENGTH);
133140

134141
if (!strcmp(key, "board")) {

local-gpio-v1.c

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright (c) 2023, Linaro Ltd.
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are met:
7+
*
8+
* 1. Redistributions of source code must retain the above copyright notice,
9+
* this list of conditions and the following disclaimer.
10+
*
11+
* 2. Redistributions in binary form must reproduce the above copyright notice,
12+
* this list of conditions and the following disclaimer in the documentation
13+
* and/or other materials provided with the distribution.
14+
*
15+
* 3. Neither the name of the copyright holder nor the names of its contributors
16+
* may be used to endorse or promote products derived from this software without
17+
* specific prior written permission.
18+
*
19+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29+
* POSSIBILITY OF SUCH DAMAGE.
30+
*/
31+
#include <ctype.h>
32+
#include <err.h>
33+
#include <errno.h>
34+
#include <fcntl.h>
35+
#include <stdio.h>
36+
#include <string.h>
37+
#include <stdlib.h>
38+
#include <unistd.h>
39+
#include <stdbool.h>
40+
41+
/* local-gpio implementation for libgpiod major version 1 */
42+
43+
#include "local-gpio.h"
44+
45+
#include <gpiod.h>
46+
47+
int local_gpio_init(struct local_gpio *local_gpio)
48+
{
49+
int i;
50+
51+
for (i = 0; i < GPIO_COUNT; ++i) {
52+
struct gpiod_line_request_config cfg;
53+
54+
if (!local_gpio->options->gpios[i].present)
55+
continue;
56+
57+
local_gpio->gpios[i].chip =
58+
gpiod_chip_open_lookup(local_gpio->options->gpios[i].chip);
59+
if (!local_gpio->gpios[i].chip) {
60+
err(1, "Unable to open gpiochip '%s'",
61+
local_gpio->options->gpios[i].chip);
62+
return -1;
63+
}
64+
65+
cfg.consumer = "cdba";
66+
cfg.request_type = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT;
67+
cfg.flags = 0;
68+
69+
if (local_gpio->options->gpios[i].active_low)
70+
cfg.flags = GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
71+
72+
local_gpio->gpios[i].line = gpiod_chip_get_line(local_gpio->gpios[i].chip,
73+
local_gpio->options->gpios[i].offset);
74+
75+
if (!local_gpio->gpios[i].line) {
76+
err(1, "Unable to find gpio %d offset %u",
77+
i, local_gpio->options->gpios[i].offset);
78+
return -1;
79+
}
80+
81+
if (gpiod_line_request(local_gpio->gpios[i].line, &cfg, 0)) {
82+
err(1, "Unable to request gpio %d offset %u",
83+
i, local_gpio->options->gpios[i].offset);
84+
return -1;
85+
}
86+
}
87+
88+
return 0;
89+
}
90+
91+
int local_gpio_set_value(struct local_gpio *local_gpio, unsigned int gpio, bool on)
92+
{
93+
return gpiod_line_set_value(local_gpio->gpios[gpio].line, on);
94+
}

local-gpio-v2.c

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* Copyright (c) 2023, Linaro Ltd.
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are met:
7+
*
8+
* 1. Redistributions of source code must retain the above copyright notice,
9+
* this list of conditions and the following disclaimer.
10+
*
11+
* 2. Redistributions in binary form must reproduce the above copyright notice,
12+
* this list of conditions and the following disclaimer in the documentation
13+
* and/or other materials provided with the distribution.
14+
*
15+
* 3. Neither the name of the copyright holder nor the names of its contributors
16+
* may be used to endorse or promote products derived from this software without
17+
* specific prior written permission.
18+
*
19+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29+
* POSSIBILITY OF SUCH DAMAGE.
30+
*/
31+
#define _GNU_SOURCE
32+
#include <ctype.h>
33+
#include <err.h>
34+
#include <errno.h>
35+
#include <fcntl.h>
36+
#include <stdio.h>
37+
#include <string.h>
38+
#include <stdlib.h>
39+
#include <unistd.h>
40+
#include <stdbool.h>
41+
42+
/* local-gpio implementation for libgpiod major version 2 */
43+
44+
#include "local-gpio.h"
45+
46+
#include <gpiod.h>
47+
48+
int local_gpio_init(struct local_gpio *local_gpio)
49+
{
50+
struct gpiod_request_config *req_cfg;
51+
int i;
52+
53+
req_cfg = gpiod_request_config_new();
54+
if (!req_cfg) {
55+
err(1, "Unable to allocate request config");
56+
return -1;
57+
}
58+
gpiod_request_config_set_consumer(req_cfg, "cdba");
59+
60+
for (i = 0; i < GPIO_COUNT; ++i) {
61+
struct gpiod_line_settings *line_settings;
62+
struct gpiod_line_config *line_cfg;
63+
char *gpiochip_path;
64+
65+
if (!local_gpio->options->gpios[i].present)
66+
continue;
67+
68+
if (asprintf(&gpiochip_path, "/dev/%s", local_gpio->options->gpios[i].chip) < 0) {
69+
free(local_gpio);
70+
return -1;
71+
}
72+
73+
local_gpio->gpios[i].chip = gpiod_chip_open(gpiochip_path);
74+
if (!local_gpio->gpios[i].chip) {
75+
err(1, "Unable to open gpiochip '%s'", local_gpio->options->gpios[i].chip);
76+
return -1;
77+
}
78+
79+
line_settings = gpiod_line_settings_new();
80+
if (!line_settings) {
81+
err(1, "Unable to allocate gpio line settings");
82+
return -1;
83+
}
84+
if (gpiod_line_settings_set_direction(line_settings,
85+
GPIOD_LINE_DIRECTION_OUTPUT) < 0) {
86+
err(1, "Unable to set line direction");
87+
return -1;
88+
}
89+
if (local_gpio->options->gpios[i].active_low)
90+
gpiod_line_settings_set_active_low(line_settings, true);
91+
if (gpiod_line_settings_set_output_value(line_settings,
92+
GPIOD_LINE_VALUE_INACTIVE) < 0) {
93+
err(1, "Unable to set line output value");
94+
return -1;
95+
}
96+
97+
line_cfg = gpiod_line_config_new();
98+
if (!line_cfg) {
99+
err(1, "Unable to allocate gpio line settings");
100+
return -1;
101+
}
102+
if (gpiod_line_config_add_line_settings(line_cfg,
103+
&local_gpio->options->gpios[i].offset, 1,
104+
line_settings) < 0) {
105+
err(1, "Unable to set line config");
106+
return -1;
107+
}
108+
109+
local_gpio->gpios[i].line = gpiod_chip_request_lines(local_gpio->gpios[i].chip,
110+
req_cfg, line_cfg);
111+
112+
if (!local_gpio->gpios[i].line) {
113+
err(1, "Unable to request gpio %d offset %u",
114+
i, local_gpio->options->gpios[i].offset);
115+
return -1;
116+
}
117+
}
118+
119+
return 0;
120+
}
121+
122+
int local_gpio_set_value(struct local_gpio *local_gpio, unsigned int gpio, bool on)
123+
{
124+
return gpiod_line_request_set_value(local_gpio->gpios[gpio].line,
125+
local_gpio->options->gpios[gpio].offset,
126+
on ? GPIOD_LINE_VALUE_ACTIVE
127+
: GPIOD_LINE_VALUE_INACTIVE);
128+
}

0 commit comments

Comments
 (0)