xref: /openbmc/linux/tools/testing/selftests/gpio/gpio-sim.sh (revision fd5e9fccbd504c5179ab57ff695c610bca8809d6)
1#!/bin/sh
2# SPDX-License-Identifier: GPL-2.0
3# Copyright (C) 2021 Bartosz Golaszewski <brgl@bgdev.pl>
4
5BASE_DIR=`dirname $0`
6CONFIGFS_DIR="/sys/kernel/config/gpio-sim"
7MODULE="gpio-sim"
8
9fail() {
10	echo "$*" >&2
11	echo "GPIO $MODULE test FAIL"
12	exit 1
13}
14
15skip() {
16	echo "$*" >&2
17	echo "GPIO $MODULE test SKIP"
18	exit 4
19}
20
21remove_chip() {
22	local CHIP=$1
23
24	for FILE in $CONFIGFS_DIR/$CHIP/*; do
25		BANK=`basename $FILE`
26		if [ "$BANK" = "live" -o "$BANK" = "dev_name" ]; then
27			continue
28		fi
29
30		LINES=`ls $CONFIGFS_DIR/$CHIP/$BANK/ | grep -E ^line`
31		if [ "$?" = 0 ]; then
32			for LINE in $LINES; do
33				if [ -e $CONFIGFS_DIR/$CHIP/$BANK/$LINE/hog ]; then
34					rmdir $CONFIGFS_DIR/$CHIP/$BANK/$LINE/hog || \
35						fail "Unable to remove the hog"
36				fi
37
38				rmdir $CONFIGFS_DIR/$CHIP/$BANK/$LINE || \
39					fail "Unable to remove the line"
40			done
41		fi
42
43		rmdir $CONFIGFS_DIR/$CHIP/$BANK
44	done
45
46	rmdir $CONFIGFS_DIR/$CHIP || fail "Unable to remove the chip"
47}
48
49create_chip() {
50	local CHIP=$1
51
52	mkdir $CONFIGFS_DIR/$CHIP
53}
54
55create_bank() {
56	local CHIP=$1
57	local BANK=$2
58
59	mkdir $CONFIGFS_DIR/$CHIP/$BANK
60}
61
62set_label() {
63	local CHIP=$1
64	local BANK=$2
65	local LABEL=$3
66
67	echo $LABEL > $CONFIGFS_DIR/$CHIP/$BANK/label || fail "Unable to set the chip label"
68}
69
70set_num_lines() {
71	local CHIP=$1
72	local BANK=$2
73	local NUM_LINES=$3
74
75	echo $NUM_LINES > $CONFIGFS_DIR/$CHIP/$BANK/num_lines || \
76		fail "Unable to set the number of lines"
77}
78
79set_line_name() {
80	local CHIP=$1
81	local BANK=$2
82	local OFFSET=$3
83	local NAME=$4
84	local LINE_DIR=$CONFIGFS_DIR/$CHIP/$BANK/line$OFFSET
85
86	test -d $LINE_DIR || mkdir $LINE_DIR
87	echo $NAME > $LINE_DIR/name || fail "Unable to set the line name"
88}
89
90enable_chip() {
91	local CHIP=$1
92
93	echo 1 > $CONFIGFS_DIR/$CHIP/live || fail "Unable to enable the chip"
94}
95
96disable_chip() {
97	local CHIP=$1
98
99	echo 0 > $CONFIGFS_DIR/$CHIP/live || fail "Unable to disable the chip"
100}
101
102configfs_cleanup() {
103	for CHIP in `ls $CONFIGFS_DIR/`; do
104		disable_chip $CHIP
105		remove_chip $CHIP
106	done
107}
108
109configfs_chip_name() {
110	local CHIP=$1
111	local BANK=$2
112
113	cat $CONFIGFS_DIR/$CHIP/$BANK/chip_name 2> /dev/null || \
114		fail "unable to read the chip name from configfs"
115}
116
117configfs_dev_name() {
118	local CHIP=$1
119
120	cat $CONFIGFS_DIR/$CHIP/dev_name 2> /dev/null || \
121		fail "unable to read the device name from configfs"
122}
123
124get_chip_num_lines() {
125	local CHIP=$1
126	local BANK=$2
127
128	$BASE_DIR/gpio-chip-info /dev/`configfs_chip_name $CHIP $BANK` num-lines || \
129		fail "unable to read the number of lines from the character device"
130}
131
132get_chip_label() {
133	local CHIP=$1
134	local BANK=$2
135
136	$BASE_DIR/gpio-chip-info /dev/`configfs_chip_name $CHIP $BANK` label || \
137		fail "unable to read the chip label from the character device"
138}
139
140get_line_name() {
141	local CHIP=$1
142	local BANK=$2
143	local OFFSET=$3
144
145	$BASE_DIR/gpio-line-name /dev/`configfs_chip_name $CHIP $BANK` $OFFSET || \
146		fail "unable to read the line name from the character device"
147}
148
149sysfs_set_pull() {
150	local DEV=$1
151	local BANK=$2
152	local OFFSET=$3
153	local PULL=$4
154	local DEVNAME=`configfs_dev_name $DEV`
155	local CHIPNAME=`configfs_chip_name $DEV $BANK`
156	local SYSFS_PATH="/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio$OFFSET/pull"
157
158	echo $PULL > $SYSFS_PATH || fail "Unable to set line pull in sysfs"
159}
160
161# Load the gpio-sim module. This will pull in configfs if needed too.
162modprobe gpio-sim || skip "unable to load the gpio-sim module"
163# Make sure configfs is mounted at /sys/kernel/config. Wait a bit if needed.
164for IDX in `seq 5`; do
165	if [ "$IDX" -eq "5" ]; then
166		skip "configfs not mounted at /sys/kernel/config"
167	fi
168
169	mountpoint -q /sys/kernel/config && break
170	sleep 0.1
171done
172# If the module was already loaded: remove all previous chips
173configfs_cleanup
174
175trap "exit 1" SIGTERM SIGINT
176trap configfs_cleanup EXIT
177
178echo "1. chip_name and dev_name attributes"
179
180echo "1.1. Chip name is communicated to user"
181create_chip chip
182create_bank chip bank
183enable_chip chip
184test -n `cat $CONFIGFS_DIR/chip/bank/chip_name` || fail "chip_name doesn't work"
185disable_chip chip
186remove_chip chip
187
188echo "1.2. chip_name returns 'none' if the chip is still pending"
189create_chip chip
190create_bank chip bank
191test "`cat $CONFIGFS_DIR/chip/bank/chip_name`" = "none" || \
192	fail "chip_name doesn't return 'none' for a pending chip"
193remove_chip chip
194
195echo "1.3. Device name is communicated to user"
196create_chip chip
197create_bank chip bank
198enable_chip chip
199test -n `cat $CONFIGFS_DIR/chip/dev_name` || fail "dev_name doesn't work"
200disable_chip chip
201remove_chip chip
202
203echo "2. Creating and configuring simulated chips"
204
205echo "2.1. Default number of lines is 1"
206create_chip chip
207create_bank chip bank
208enable_chip chip
209test "`get_chip_num_lines chip bank`" = "1" || fail "default number of lines is not 1"
210disable_chip chip
211remove_chip chip
212
213echo "2.2. Number of lines can be specified"
214create_chip chip
215create_bank chip bank
216set_num_lines chip bank 16
217enable_chip chip
218test "`get_chip_num_lines chip bank`" = "16" || fail "number of lines is not 16"
219disable_chip chip
220remove_chip chip
221
222echo "2.3. Label can be set"
223create_chip chip
224create_bank chip bank
225set_label chip bank foobar
226enable_chip chip
227test "`get_chip_label chip bank`" = "foobar" || fail "label is incorrect"
228disable_chip chip
229remove_chip chip
230
231echo "2.4. Label can be left empty"
232create_chip chip
233create_bank chip bank
234enable_chip chip
235test -z "`cat $CONFIGFS_DIR/chip/bank/label`" || fail "label is not empty"
236disable_chip chip
237remove_chip chip
238
239echo "2.5. Line names can be configured"
240create_chip chip
241create_bank chip bank
242set_num_lines chip bank 16
243set_line_name chip bank 0 foo
244set_line_name chip bank 2 bar
245enable_chip chip
246test "`get_line_name chip bank 0`" = "foo" || fail "line name is incorrect"
247test "`get_line_name chip bank 2`" = "bar" || fail "line name is incorrect"
248disable_chip chip
249remove_chip chip
250
251echo "2.6. Line config can remain unused if offset is greater than number of lines"
252create_chip chip
253create_bank chip bank
254set_num_lines chip bank 2
255set_line_name chip bank 5 foobar
256enable_chip chip
257test "`get_line_name chip bank 0`" = "" || fail "line name is incorrect"
258test "`get_line_name chip bank 1`" = "" || fail "line name is incorrect"
259disable_chip chip
260remove_chip chip
261
262echo "2.7. Line configfs directory names are sanitized"
263create_chip chip
264create_bank chip bank
265mkdir $CONFIGFS_DIR/chip/bank/line12foobar 2> /dev/null && \
266	fail "invalid configfs line name accepted"
267mkdir $CONFIGFS_DIR/chip/bank/line_no_offset 2> /dev/null && \
268	fail "invalid configfs line name accepted"
269remove_chip chip
270
271echo "2.8. Multiple chips can be created"
272CHIPS="chip0 chip1 chip2"
273for CHIP in $CHIPS; do
274	create_chip $CHIP
275	create_bank $CHIP bank
276	enable_chip $CHIP
277done
278for CHIP in $CHIPS; do
279  disable_chip $CHIP
280	remove_chip $CHIP
281done
282
283echo "2.9. Can't modify settings when chip is live"
284create_chip chip
285create_bank chip bank
286enable_chip chip
287echo foobar > $CONFIGFS_DIR/chip/bank/label 2> /dev/null && \
288	fail "Setting label of a live chip should fail"
289echo 8 > $CONFIGFS_DIR/chip/bank/num_lines 2> /dev/null && \
290	fail "Setting number of lines of a live chip should fail"
291disable_chip chip
292remove_chip chip
293
294echo "2.10. Can't create line items when chip is live"
295create_chip chip
296create_bank chip bank
297enable_chip chip
298mkdir $CONFIGFS_DIR/chip/bank/line0 2> /dev/null && fail "Creating line item should fail"
299disable_chip chip
300remove_chip chip
301
302echo "2.11. Probe errors are propagated to user-space"
303create_chip chip
304create_bank chip bank
305set_num_lines chip bank 99999
306echo 1 > $CONFIGFS_DIR/chip/live 2> /dev/null && fail "Probe error was not propagated"
307remove_chip chip
308
309echo "2.12. Cannot enable a chip without any GPIO banks"
310create_chip chip
311echo 1 > $CONFIGFS_DIR/chip/live 2> /dev/null && fail "Chip enabled without any GPIO banks"
312remove_chip chip
313
314echo "2.13. Duplicate chip labels are not allowed"
315create_chip chip
316create_bank chip bank0
317set_label chip bank0 foobar
318create_bank chip bank1
319set_label chip bank1 foobar
320echo 1 > $CONFIGFS_DIR/chip/live 2> /dev/null && fail "Duplicate chip labels were not rejected"
321remove_chip chip
322
323echo "2.14. Lines can be hogged"
324create_chip chip
325create_bank chip bank
326set_num_lines chip bank 8
327mkdir -p $CONFIGFS_DIR/chip/bank/line4/hog
328enable_chip chip
329$BASE_DIR/gpio-mockup-cdev -s 1 /dev/`configfs_chip_name chip bank` 4 2> /dev/null && \
330	fail "Setting the value of a hogged line shouldn't succeed"
331disable_chip chip
332remove_chip chip
333
334echo "3. Controlling simulated chips"
335
336echo "3.1. Pull can be set over sysfs"
337create_chip chip
338create_bank chip bank
339set_num_lines chip bank 8
340enable_chip chip
341sysfs_set_pull chip bank 0 pull-up
342$BASE_DIR/gpio-mockup-cdev /dev/`configfs_chip_name chip bank` 0
343test "$?" = "1" || fail "pull set incorrectly"
344sysfs_set_pull chip bank 0 pull-down
345$BASE_DIR/gpio-mockup-cdev /dev/`configfs_chip_name chip bank` 1
346test "$?" = "0" || fail "pull set incorrectly"
347disable_chip chip
348remove_chip chip
349
350echo "3.2. Pull can be read from sysfs"
351create_chip chip
352create_bank chip bank
353set_num_lines chip bank 8
354enable_chip chip
355DEVNAME=`configfs_dev_name chip`
356CHIPNAME=`configfs_chip_name chip bank`
357SYSFS_PATH=/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio0/pull
358test `cat $SYSFS_PATH` = "pull-down" || fail "reading the pull failed"
359sysfs_set_pull chip bank 0 pull-up
360test `cat $SYSFS_PATH` = "pull-up" || fail "reading the pull failed"
361disable_chip chip
362remove_chip chip
363
364echo "3.3. Incorrect input in sysfs is rejected"
365create_chip chip
366create_bank chip bank
367set_num_lines chip bank 8
368enable_chip chip
369DEVNAME=`configfs_dev_name chip`
370CHIPNAME=`configfs_chip_name chip bank`
371SYSFS_PATH="/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio0/pull"
372echo foobar > $SYSFS_PATH 2> /dev/null && fail "invalid input not detected"
373disable_chip chip
374remove_chip chip
375
376echo "3.4. Can't write to value"
377create_chip chip
378create_bank chip bank
379enable_chip chip
380DEVNAME=`configfs_dev_name chip`
381CHIPNAME=`configfs_chip_name chip bank`
382SYSFS_PATH="/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio0/value"
383echo 1 > $SYSFS_PATH 2> /dev/null && fail "writing to 'value' succeeded unexpectedly"
384disable_chip chip
385remove_chip chip
386
387echo "4. Simulated GPIO chips are functional"
388
389echo "4.1. Values can be read from sysfs"
390create_chip chip
391create_bank chip bank
392set_num_lines chip bank 8
393enable_chip chip
394DEVNAME=`configfs_dev_name chip`
395CHIPNAME=`configfs_chip_name chip bank`
396SYSFS_PATH="/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio0/value"
397test `cat $SYSFS_PATH` = "0" || fail "incorrect value read from sysfs"
398$BASE_DIR/gpio-mockup-cdev -s 1 /dev/`configfs_chip_name chip bank` 0 &
399sleep 0.1 # FIXME Any better way?
400test `cat $SYSFS_PATH` = "1" || fail "incorrect value read from sysfs"
401kill $!
402disable_chip chip
403remove_chip chip
404
405echo "4.2. Bias settings work correctly"
406create_chip chip
407create_bank chip bank
408set_num_lines chip bank 8
409enable_chip chip
410DEVNAME=`configfs_dev_name chip`
411CHIPNAME=`configfs_chip_name chip bank`
412SYSFS_PATH="/sys/devices/platform/$DEVNAME/$CHIPNAME/sim_gpio0/value"
413$BASE_DIR/gpio-mockup-cdev -b pull-up /dev/`configfs_chip_name chip bank` 0
414test `cat $SYSFS_PATH` = "1" || fail "bias setting does not work"
415disable_chip chip
416remove_chip chip
417
418echo "GPIO $MODULE test PASS"
419