xref: /openbmc/linux/drivers/gpio/gpio-mockup.c (revision 2a9d742c2699f7d4a7c23f330520d75872810ade)
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  * Copyright (C) 2017 Bartosz Golaszewski <brgl@bgdev.pl>
7  *
8  * This program is free software; you can redistribute  it and/or modify it
9  * under  the terms of  the GNU General  Public License as published by the
10  * Free Software Foundation;  either version 2 of the  License, or (at your
11  * option) any later version.
12  *
13  */
14 
15 #include <linux/init.h>
16 #include <linux/module.h>
17 #include <linux/gpio/driver.h>
18 #include <linux/gpio/consumer.h>
19 #include <linux/platform_device.h>
20 #include <linux/slab.h>
21 #include <linux/interrupt.h>
22 #include <linux/irq.h>
23 #include <linux/irq_sim.h>
24 #include <linux/debugfs.h>
25 #include <linux/uaccess.h>
26 
27 #include "gpiolib.h"
28 
29 #define GPIO_MOCKUP_NAME	"gpio-mockup"
30 #define GPIO_MOCKUP_MAX_GC	10
31 /*
32  * We're storing two values per chip: the GPIO base and the number
33  * of GPIO lines.
34  */
35 #define GPIO_MOCKUP_MAX_RANGES	(GPIO_MOCKUP_MAX_GC * 2)
36 
37 #define gpio_mockup_err(...)	pr_err(GPIO_MOCKUP_NAME ": " __VA_ARGS__)
38 
39 enum {
40 	GPIO_MOCKUP_DIR_OUT = 0,
41 	GPIO_MOCKUP_DIR_IN = 1,
42 };
43 
44 /*
45  * struct gpio_pin_status - structure describing a GPIO status
46  * @dir:       Configures direction of gpio as "in" or "out", 0=in, 1=out
47  * @value:     Configures status of the gpio as 0(low) or 1(high)
48  */
49 struct gpio_mockup_line_status {
50 	int dir;
51 	int value;
52 };
53 
54 struct gpio_mockup_chip {
55 	struct gpio_chip gc;
56 	struct gpio_mockup_line_status *lines;
57 	struct irq_sim irqsim;
58 	struct dentry *dbg_dir;
59 };
60 
61 struct gpio_mockup_dbgfs_private {
62 	struct gpio_mockup_chip *chip;
63 	struct gpio_desc *desc;
64 	int offset;
65 };
66 
67 struct gpio_mockup_platform_data {
68 	int base;
69 	int ngpio;
70 	int index;
71 	bool named_lines;
72 };
73 
74 static int gpio_mockup_ranges[GPIO_MOCKUP_MAX_RANGES];
75 static int gpio_mockup_params_nr;
76 module_param_array(gpio_mockup_ranges, int, &gpio_mockup_params_nr, 0400);
77 
78 static bool gpio_mockup_named_lines;
79 module_param_named(gpio_mockup_named_lines,
80 		   gpio_mockup_named_lines, bool, 0400);
81 
82 static struct dentry *gpio_mockup_dbg_dir;
83 
84 static int gpio_mockup_get(struct gpio_chip *gc, unsigned int offset)
85 {
86 	struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
87 
88 	return chip->lines[offset].value;
89 }
90 
91 static void gpio_mockup_set(struct gpio_chip *gc,
92 			    unsigned int offset, int value)
93 {
94 	struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
95 
96 	chip->lines[offset].value = !!value;
97 }
98 
99 static int gpio_mockup_dirout(struct gpio_chip *gc,
100 			      unsigned int offset, int value)
101 {
102 	struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
103 
104 	gpio_mockup_set(gc, offset, value);
105 	chip->lines[offset].dir = GPIO_MOCKUP_DIR_OUT;
106 
107 	return 0;
108 }
109 
110 static int gpio_mockup_dirin(struct gpio_chip *gc, unsigned int offset)
111 {
112 	struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
113 
114 	chip->lines[offset].dir = GPIO_MOCKUP_DIR_IN;
115 
116 	return 0;
117 }
118 
119 static int gpio_mockup_get_direction(struct gpio_chip *gc, unsigned int offset)
120 {
121 	struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
122 
123 	return chip->lines[offset].dir;
124 }
125 
126 static int gpio_mockup_to_irq(struct gpio_chip *gc, unsigned int offset)
127 {
128 	struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
129 
130 	return irq_sim_irqnum(&chip->irqsim, offset);
131 }
132 
133 static ssize_t gpio_mockup_event_write(struct file *file,
134 				       const char __user *usr_buf,
135 				       size_t size, loff_t *ppos)
136 {
137 	struct gpio_mockup_dbgfs_private *priv;
138 	struct gpio_mockup_chip *chip;
139 	struct seq_file *sfile;
140 	struct gpio_desc *desc;
141 	int rv, val;
142 
143 	rv = kstrtoint_from_user(usr_buf, size, 0, &val);
144 	if (rv)
145 		return rv;
146 	if (val != 0 && val != 1)
147 		return -EINVAL;
148 
149 	sfile = file->private_data;
150 	priv = sfile->private;
151 	desc = priv->desc;
152 	chip = priv->chip;
153 
154 	gpiod_set_value_cansleep(desc, val);
155 	irq_sim_fire(&chip->irqsim, priv->offset);
156 
157 	return size;
158 }
159 
160 static int gpio_mockup_event_open(struct inode *inode, struct file *file)
161 {
162 	return single_open(file, NULL, inode->i_private);
163 }
164 
165 static const struct file_operations gpio_mockup_event_ops = {
166 	.owner = THIS_MODULE,
167 	.open = gpio_mockup_event_open,
168 	.write = gpio_mockup_event_write,
169 	.llseek = no_llseek,
170 };
171 
172 static void gpio_mockup_debugfs_setup(struct device *dev,
173 				      struct gpio_mockup_chip *chip)
174 {
175 	struct gpio_mockup_dbgfs_private *priv;
176 	struct dentry *evfile, *link;
177 	struct gpio_chip *gc;
178 	const char *devname;
179 	char *name;
180 	int i;
181 
182 	gc = &chip->gc;
183 	devname = dev_name(&gc->gpiodev->dev);
184 
185 	chip->dbg_dir = debugfs_create_dir(devname, gpio_mockup_dbg_dir);
186 	if (IS_ERR_OR_NULL(chip->dbg_dir))
187 		goto err;
188 
189 	link = debugfs_create_symlink(gc->label, gpio_mockup_dbg_dir, devname);
190 	if (IS_ERR_OR_NULL(link))
191 		goto err;
192 
193 	for (i = 0; i < gc->ngpio; i++) {
194 		name = devm_kasprintf(dev, GFP_KERNEL, "%d", i);
195 		if (!name)
196 			goto err;
197 
198 		priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
199 		if (!priv)
200 			goto err;
201 
202 		priv->chip = chip;
203 		priv->offset = i;
204 		priv->desc = &gc->gpiodev->descs[i];
205 
206 		evfile = debugfs_create_file(name, 0200, chip->dbg_dir, priv,
207 					     &gpio_mockup_event_ops);
208 		if (IS_ERR_OR_NULL(evfile))
209 			goto err;
210 	}
211 
212 	return;
213 
214 err:
215 	dev_err(dev, "error creating debugfs event files\n");
216 }
217 
218 static int gpio_mockup_name_lines(struct device *dev,
219 				  struct gpio_mockup_chip *chip)
220 {
221 	struct gpio_chip *gc = &chip->gc;
222 	char **names;
223 	int i;
224 
225 	names = devm_kcalloc(dev, gc->ngpio, sizeof(char *), GFP_KERNEL);
226 	if (!names)
227 		return -ENOMEM;
228 
229 	for (i = 0; i < gc->ngpio; i++) {
230 		names[i] = devm_kasprintf(dev, GFP_KERNEL,
231 					  "%s-%d", gc->label, i);
232 		if (!names[i])
233 			return -ENOMEM;
234 	}
235 
236 	gc->names = (const char *const *)names;
237 
238 	return 0;
239 }
240 
241 static int gpio_mockup_probe(struct platform_device *pdev)
242 {
243 	struct gpio_mockup_platform_data *pdata;
244 	struct gpio_mockup_chip *chip;
245 	struct gpio_chip *gc;
246 	int rv, base, ngpio;
247 	struct device *dev;
248 	char *name;
249 
250 	dev = &pdev->dev;
251 	pdata = dev_get_platdata(dev);
252 	base = pdata->base;
253 	ngpio = pdata->ngpio;
254 
255 	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
256 	if (!chip)
257 		return -ENOMEM;
258 
259 	name = devm_kasprintf(dev, GFP_KERNEL, "%s-%c",
260 			      pdev->name, pdata->index);
261 	if (!name)
262 		return -ENOMEM;
263 
264 	gc = &chip->gc;
265 	gc->base = base;
266 	gc->ngpio = ngpio;
267 	gc->label = name;
268 	gc->owner = THIS_MODULE;
269 	gc->parent = dev;
270 	gc->get = gpio_mockup_get;
271 	gc->set = gpio_mockup_set;
272 	gc->direction_output = gpio_mockup_dirout;
273 	gc->direction_input = gpio_mockup_dirin;
274 	gc->get_direction = gpio_mockup_get_direction;
275 	gc->to_irq = gpio_mockup_to_irq;
276 
277 	chip->lines = devm_kcalloc(dev, gc->ngpio,
278 				   sizeof(*chip->lines), GFP_KERNEL);
279 	if (!chip->lines)
280 		return -ENOMEM;
281 
282 	if (pdata->named_lines) {
283 		rv = gpio_mockup_name_lines(dev, chip);
284 		if (rv)
285 			return rv;
286 	}
287 
288 	rv = devm_irq_sim_init(dev, &chip->irqsim, gc->ngpio);
289 	if (rv)
290 		return rv;
291 
292 	rv = devm_gpiochip_add_data(dev, &chip->gc, chip);
293 	if (rv)
294 		return rv;
295 
296 	if (gpio_mockup_dbg_dir)
297 		gpio_mockup_debugfs_setup(dev, chip);
298 
299 	return 0;
300 }
301 
302 static struct platform_driver gpio_mockup_driver = {
303 	.driver = {
304 		.name = GPIO_MOCKUP_NAME,
305 	},
306 	.probe = gpio_mockup_probe,
307 };
308 
309 static struct platform_device *gpio_mockup_pdevs[GPIO_MOCKUP_MAX_GC];
310 
311 static void gpio_mockup_unregister_pdevs(void)
312 {
313 	struct platform_device *pdev;
314 	int i;
315 
316 	for (i = 0; i < GPIO_MOCKUP_MAX_GC; i++) {
317 		pdev = gpio_mockup_pdevs[i];
318 
319 		if (pdev)
320 			platform_device_unregister(pdev);
321 	}
322 }
323 
324 static int __init gpio_mockup_init(void)
325 {
326 	int i, num_chips, err = 0, index = 'A';
327 	struct gpio_mockup_platform_data pdata;
328 	struct platform_device *pdev;
329 
330 	if ((gpio_mockup_params_nr < 2) ||
331 	    (gpio_mockup_params_nr % 2) ||
332 	    (gpio_mockup_params_nr > GPIO_MOCKUP_MAX_RANGES))
333 		return -EINVAL;
334 
335 	/* Each chip is described by two values. */
336 	num_chips = gpio_mockup_params_nr / 2;
337 
338 	/*
339 	 * The second value in the <base GPIO - number of GPIOS> pair must
340 	 * always be greater than 0.
341 	 */
342 	for (i = 0; i < num_chips; i++) {
343 		if (gpio_mockup_ranges[i * 2 + 1] < 0)
344 			return -EINVAL;
345 	}
346 
347 	gpio_mockup_dbg_dir = debugfs_create_dir("gpio-mockup-event", NULL);
348 	if (IS_ERR_OR_NULL(gpio_mockup_dbg_dir))
349 		gpio_mockup_err("error creating debugfs directory\n");
350 
351 	err = platform_driver_register(&gpio_mockup_driver);
352 	if (err) {
353 		gpio_mockup_err("error registering platform driver\n");
354 		return err;
355 	}
356 
357 	for (i = 0; i < num_chips; i++) {
358 		pdata.index = index++;
359 		pdata.base = gpio_mockup_ranges[i * 2];
360 		pdata.ngpio = pdata.base < 0
361 				? gpio_mockup_ranges[i * 2 + 1]
362 				: gpio_mockup_ranges[i * 2 + 1] - pdata.base;
363 		pdata.named_lines = gpio_mockup_named_lines;
364 
365 		pdev = platform_device_register_resndata(NULL,
366 							 GPIO_MOCKUP_NAME,
367 							 i, NULL, 0, &pdata,
368 							 sizeof(pdata));
369 		if (!pdev) {
370 			gpio_mockup_err("error registering device");
371 			platform_driver_unregister(&gpio_mockup_driver);
372 			gpio_mockup_unregister_pdevs();
373 			return -ENOMEM;
374 		}
375 
376 		gpio_mockup_pdevs[i] = pdev;
377 	}
378 
379 	return 0;
380 }
381 
382 static void __exit gpio_mockup_exit(void)
383 {
384 	debugfs_remove_recursive(gpio_mockup_dbg_dir);
385 	platform_driver_unregister(&gpio_mockup_driver);
386 	gpio_mockup_unregister_pdevs();
387 }
388 
389 module_init(gpio_mockup_init);
390 module_exit(gpio_mockup_exit);
391 
392 MODULE_AUTHOR("Kamlakant Patel <kamlakant.patel@broadcom.com>");
393 MODULE_AUTHOR("Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>");
394 MODULE_AUTHOR("Bartosz Golaszewski <brgl@bgdev.pl>");
395 MODULE_DESCRIPTION("GPIO Testing driver");
396 MODULE_LICENSE("GPL v2");
397