aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBamvor Jian Zhang <bamvor.zhangjian@linaro.org>2016-08-31 05:45:46 -0400
committerLinus Walleij <linus.walleij@linaro.org>2016-09-26 14:47:14 -0400
commit0f98dd1b27d27412af3aef6a49ea6975988e33e7 (patch)
treea26a7625f099135f2849cd5fdc86c75626fe518b
parente3296f19c8620a9c47b6734df84c4b3126d2fe46 (diff)
gpio/mockup: add virtual gpio device
This patch add basic structure of a virtual gpio device(gpio-mockup) for testing gpio subsystem. The tester could manipulate such device through userspace(sysfs or char device) and check the result from debugfs. Currently, it support one or more gpiochip(determined by module parameters with base,ngpio pair). One could test the overlap of different gpiochip and test the direction and/or output values of these chips. Signed-off-by: Kamlakant Patel <kamlakant.patel@broadcom.com> Signed-off-by: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r--Documentation/kernel-parameters.txt4
-rw-r--r--drivers/gpio/Kconfig12
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/gpio-mockup.c214
4 files changed, 231 insertions, 0 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 46c030a49186..61f4dbf9d97e 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1364,6 +1364,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
1364 Format: <unsigned int> such that (rxsize & ~0x1fffc0) == 0. 1364 Format: <unsigned int> such that (rxsize & ~0x1fffc0) == 0.
1365 Default: 1024 1365 Default: 1024
1366 1366
1367 gpio-mockup.gpio_mockup_ranges
1368 [HW] Sets the ranges of gpiochip of for this device.
1369 Format: <start1>,<end1>,<start2>,<end2>...
1370
1367 hardlockup_all_cpu_backtrace= 1371 hardlockup_all_cpu_backtrace=
1368 [KNL] Should the hard-lockup detector generate 1372 [KNL] Should the hard-lockup detector generate
1369 backtraces on all cpus. 1373 backtraces on all cpus.
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 0e41c45a2936..79429b9b4e20 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -279,6 +279,18 @@ config GPIO_MM_LANTIQ
279 (EBU) found on Lantiq SoCs. The gpios are output only as they are 279 (EBU) found on Lantiq SoCs. The gpios are output only as they are
280 created by attaching a 16bit latch to the bus. 280 created by attaching a 16bit latch to the bus.
281 281
282config GPIO_MOCKUP
283 tristate "GPIO Testing Driver"
284 depends on GPIOLIB
285 select GPIO_SYSFS
286 help
287 This enables GPIO Testing driver, which provides a way to test GPIO
288 subsystem through sysfs(or char device) and debugfs. GPIO_SYSFS
289 must be selected for this test.
290 User could use it through the script in
291 tools/testing/selftests/gpio/gpio-mockup.sh. Reference the usage in
292 it.
293
282config GPIO_MOXART 294config GPIO_MOXART
283 bool "MOXART GPIO support" 295 bool "MOXART GPIO support"
284 depends on ARCH_MOXART || COMPILE_TEST 296 depends on ARCH_MOXART || COMPILE_TEST
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index b3e039c3ae8d..915c7de1dd1b 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -74,6 +74,7 @@ obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o
74obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o 74obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o
75obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o 75obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o
76obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o 76obj-$(CONFIG_GPIO_MM_LANTIQ) += gpio-mm-lantiq.o
77obj-$(CONFIG_GPIO_MOCKUP) += gpio-mockup.o
77obj-$(CONFIG_GPIO_MOXART) += gpio-moxart.o 78obj-$(CONFIG_GPIO_MOXART) += gpio-moxart.o
78obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o 79obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o
79obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o 80obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o
diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c
new file mode 100644
index 000000000000..1ef85b0c2b1f
--- /dev/null
+++ b/drivers/gpio/gpio-mockup.c
@@ -0,0 +1,214 @@
1/*
2 * GPIO Testing Device Driver
3 *
4 * Copyright (C) 2014 Kamlakant Patel <kamlakant.patel@broadcom.com>
5 * Copyright (C) 2015-2016 Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 */
13
14#include <linux/init.h>
15#include <linux/module.h>
16#include <linux/gpio/driver.h>
17#include <linux/platform_device.h>
18
19#define GPIO_NAME "gpio-mockup"
20#define MAX_GC 10
21
22enum direction {
23 OUT,
24 IN
25};
26
27/*
28 * struct gpio_pin_status - structure describing a GPIO status
29 * @dir: Configures direction of gpio as "in" or "out", 0=in, 1=out
30 * @value: Configures status of the gpio as 0(low) or 1(high)
31 */
32struct gpio_pin_status {
33 enum direction dir;
34 bool value;
35};
36
37struct mockup_gpio_controller {
38 struct gpio_chip gc;
39 struct gpio_pin_status *stats;
40};
41
42static int gpio_mockup_ranges[MAX_GC << 1];
43static int gpio_mockup_params_nr;
44module_param_array(gpio_mockup_ranges, int, &gpio_mockup_params_nr, 0400);
45
46const char pins_name_start = 'A';
47
48static int mockup_gpio_get(struct gpio_chip *gc, unsigned int offset)
49{
50 struct mockup_gpio_controller *cntr = gpiochip_get_data(gc);
51
52 return cntr->stats[offset].value;
53}
54
55static void mockup_gpio_set(struct gpio_chip *gc, unsigned int offset,
56 int value)
57{
58 struct mockup_gpio_controller *cntr = gpiochip_get_data(gc);
59
60 cntr->stats[offset].value = !!value;
61}
62
63static int mockup_gpio_dirout(struct gpio_chip *gc, unsigned int offset,
64 int value)
65{
66 struct mockup_gpio_controller *cntr = gpiochip_get_data(gc);
67
68 mockup_gpio_set(gc, offset, value);
69 cntr->stats[offset].dir = OUT;
70 return 0;
71}
72
73static int mockup_gpio_dirin(struct gpio_chip *gc, unsigned int offset)
74{
75 struct mockup_gpio_controller *cntr = gpiochip_get_data(gc);
76
77 cntr->stats[offset].dir = IN;
78 return 0;
79}
80
81static int mockup_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
82{
83 struct mockup_gpio_controller *cntr = gpiochip_get_data(gc);
84
85 return cntr->stats[offset].dir;
86}
87
88static int mockup_gpio_add(struct device *dev,
89 struct mockup_gpio_controller *cntr,
90 const char *name, int base, int ngpio)
91{
92 int ret;
93
94 cntr->gc.base = base;
95 cntr->gc.ngpio = ngpio;
96 cntr->gc.label = name;
97 cntr->gc.owner = THIS_MODULE;
98 cntr->gc.parent = dev;
99 cntr->gc.get = mockup_gpio_get;
100 cntr->gc.set = mockup_gpio_set;
101 cntr->gc.direction_output = mockup_gpio_dirout;
102 cntr->gc.direction_input = mockup_gpio_dirin;
103 cntr->gc.get_direction = mockup_gpio_get_direction;
104 cntr->stats = devm_kzalloc(dev, sizeof(*cntr->stats) * cntr->gc.ngpio,
105 GFP_KERNEL);
106 if (!cntr->stats) {
107 ret = -ENOMEM;
108 goto err;
109 }
110 ret = devm_gpiochip_add_data(dev, &cntr->gc, cntr);
111 if (ret)
112 goto err;
113
114 dev_info(dev, "gpio<%d..%d> add successful!", base, base + ngpio);
115 return 0;
116err:
117 dev_err(dev, "gpio<%d..%d> add failed!", base, base + ngpio);
118 return ret;
119}
120
121static int mockup_gpio_probe(struct platform_device *pdev)
122{
123 struct device *dev = &pdev->dev;
124 struct mockup_gpio_controller *cntr;
125 int ret;
126 int i;
127 int base;
128 int ngpio;
129 char chip_name[sizeof(GPIO_NAME) + 3];
130
131 if (gpio_mockup_params_nr < 2)
132 return -EINVAL;
133
134 cntr = devm_kzalloc(dev, sizeof(*cntr) * (gpio_mockup_params_nr >> 1),
135 GFP_KERNEL);
136 if (!cntr)
137 return -ENOMEM;
138
139 platform_set_drvdata(pdev, cntr);
140
141 for (i = 0; i < gpio_mockup_params_nr >> 1; i++) {
142 base = gpio_mockup_ranges[i * 2];
143 if (base == -1)
144 ngpio = gpio_mockup_ranges[i * 2 + 1];
145 else
146 ngpio = gpio_mockup_ranges[i * 2 + 1] - base;
147
148 if (ngpio >= 0) {
149 sprintf(chip_name, "%s-%c", GPIO_NAME,
150 pins_name_start + i);
151 ret = mockup_gpio_add(dev, &cntr[i],
152 chip_name, base, ngpio);
153 } else {
154 ret = -1;
155 }
156 if (ret) {
157 if (base < 0)
158 dev_err(dev, "gpio<%d..%d> add failed\n",
159 base, ngpio);
160 else
161 dev_err(dev, "gpio<%d..%d> add failed\n",
162 base, base + ngpio);
163
164 return ret;
165 }
166 }
167
168 return 0;
169}
170
171static struct platform_driver mockup_gpio_driver = {
172 .driver = {
173 .name = GPIO_NAME,
174 },
175 .probe = mockup_gpio_probe,
176};
177
178static struct platform_device *pdev;
179static int __init mock_device_init(void)
180{
181 int err;
182
183 pdev = platform_device_alloc(GPIO_NAME, -1);
184 if (!pdev)
185 return -ENOMEM;
186
187 err = platform_device_add(pdev);
188 if (err) {
189 platform_device_put(pdev);
190 return err;
191 }
192
193 err = platform_driver_register(&mockup_gpio_driver);
194 if (err) {
195 platform_device_unregister(pdev);
196 return err;
197 }
198
199 return 0;
200}
201
202static void __exit mock_device_exit(void)
203{
204 platform_driver_unregister(&mockup_gpio_driver);
205 platform_device_unregister(pdev);
206}
207
208module_init(mock_device_init);
209module_exit(mock_device_exit);
210
211MODULE_AUTHOR("Kamlakant Patel <kamlakant.patel@broadcom.com>");
212MODULE_AUTHOR("Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>");
213MODULE_DESCRIPTION("GPIO Testing driver");
214MODULE_LICENSE("GPL v2");