gpio-mockup.c 10.1 KB
Newer Older
1 2 3 4 5
/*
 * GPIO Testing Device Driver
 *
 * Copyright (C) 2014  Kamlakant Patel <kamlakant.patel@broadcom.com>
 * Copyright (C) 2015-2016  Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>
6
 * Copyright (C) 2017 Bartosz Golaszewski <brgl@bgdev.pl>
7 8 9 10 11 12 13 14 15 16 17
 *
 * This program is free software; you can redistribute  it and/or modify it
 * under  the terms of  the GNU General  Public License as published by the
 * Free Software Foundation;  either version 2 of the  License, or (at your
 * option) any later version.
 *
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/gpio/driver.h>
18
#include <linux/gpio/consumer.h>
19
#include <linux/platform_device.h>
20
#include <linux/slab.h>
21 22 23
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irq_work.h>
24 25 26 27
#include <linux/debugfs.h>
#include <linux/uaccess.h>

#include "gpiolib.h"
28

29 30
#define GPIO_MOCKUP_NAME	"gpio-mockup"
#define	GPIO_MOCKUP_MAX_GC	10
31 32 33 34 35
/*
 * We're storing two values per chip: the GPIO base and the number
 * of GPIO lines.
 */
#define GPIO_MOCKUP_MAX_RANGES	(GPIO_MOCKUP_MAX_GC * 2)
36

37
enum {
38 39
	GPIO_MOCKUP_DIR_OUT = 0,
	GPIO_MOCKUP_DIR_IN = 1,
40 41 42 43 44 45 46
};

/*
 * struct gpio_pin_status - structure describing a GPIO status
 * @dir:       Configures direction of gpio as "in" or "out", 0=in, 1=out
 * @value:     Configures status of the gpio as 0(low) or 1(high)
 */
47 48
struct gpio_mockup_line_status {
	int dir;
49
	bool value;
50
	bool irq_enabled;
51 52
};

53 54 55 56 57
struct gpio_mockup_irq_context {
	struct irq_work work;
	int irq;
};

58
struct gpio_mockup_chip {
59
	struct gpio_chip gc;
60
	struct gpio_mockup_line_status *lines;
61
	struct gpio_mockup_irq_context irq_ctx;
62 63 64 65 66 67 68
	struct dentry *dbg_dir;
};

struct gpio_mockup_dbgfs_private {
	struct gpio_mockup_chip *chip;
	struct gpio_desc *desc;
	int offset;
69 70
};

71
static int gpio_mockup_ranges[GPIO_MOCKUP_MAX_RANGES];
72 73 74
static int gpio_mockup_params_nr;
module_param_array(gpio_mockup_ranges, int, &gpio_mockup_params_nr, 0400);

75 76 77 78
static bool gpio_mockup_named_lines;
module_param_named(gpio_mockup_named_lines,
		   gpio_mockup_named_lines, bool, 0400);

79
static const char gpio_mockup_name_start = 'A';
80
static struct dentry *gpio_mockup_dbg_dir;
81

82
static int gpio_mockup_get(struct gpio_chip *gc, unsigned int offset)
83
{
84
	struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
85

86
	return chip->lines[offset].value;
87 88
}

89
static void gpio_mockup_set(struct gpio_chip *gc, unsigned int offset,
90 91
			    int value)
{
92
	struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
93

94
	chip->lines[offset].value = !!value;
95 96
}

97
static int gpio_mockup_dirout(struct gpio_chip *gc, unsigned int offset,
98 99
			      int value)
{
100 101 102
	struct gpio_mockup_chip *chip = gpiochip_get_data(gc);

	gpio_mockup_set(gc, offset, value);
103
	chip->lines[offset].dir = GPIO_MOCKUP_DIR_OUT;
104 105 106 107

	return 0;
}

108
static int gpio_mockup_dirin(struct gpio_chip *gc, unsigned int offset)
109
{
110 111
	struct gpio_mockup_chip *chip = gpiochip_get_data(gc);

112
	chip->lines[offset].dir = GPIO_MOCKUP_DIR_IN;
113 114 115 116

	return 0;
}

117
static int gpio_mockup_get_direction(struct gpio_chip *gc, unsigned int offset)
118
{
119
	struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
120

121
	return chip->lines[offset].dir;
122 123
}

124 125 126 127 128 129 130
static int gpio_mockup_name_lines(struct device *dev,
				  struct gpio_mockup_chip *chip)
{
	struct gpio_chip *gc = &chip->gc;
	char **names;
	int i;

131
	names = devm_kcalloc(dev, gc->ngpio, sizeof(char *), GFP_KERNEL);
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
	if (!names)
		return -ENOMEM;

	for (i = 0; i < gc->ngpio; i++) {
		names[i] = devm_kasprintf(dev, GFP_KERNEL,
					  "%s-%d", gc->label, i);
		if (!names[i])
			return -ENOMEM;
	}

	gc->names = (const char *const *)names;

	return 0;
}

147 148 149 150 151
static int gpio_mockup_to_irq(struct gpio_chip *chip, unsigned int offset)
{
	return chip->irq_base + offset;
}

152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
static void gpio_mockup_irqmask(struct irq_data *data)
{
	struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
	struct gpio_mockup_chip *chip = gpiochip_get_data(gc);

	chip->lines[data->irq - gc->irq_base].irq_enabled = false;
}

static void gpio_mockup_irqunmask(struct irq_data *data)
{
	struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
	struct gpio_mockup_chip *chip = gpiochip_get_data(gc);

	chip->lines[data->irq - gc->irq_base].irq_enabled = true;
}
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187

static struct irq_chip gpio_mockup_irqchip = {
	.name		= GPIO_MOCKUP_NAME,
	.irq_mask	= gpio_mockup_irqmask,
	.irq_unmask	= gpio_mockup_irqunmask,
};

static void gpio_mockup_handle_irq(struct irq_work *work)
{
	struct gpio_mockup_irq_context *irq_ctx;

	irq_ctx = container_of(work, struct gpio_mockup_irq_context, work);
	handle_simple_irq(irq_to_desc(irq_ctx->irq));
}

static int gpio_mockup_irqchip_setup(struct device *dev,
				     struct gpio_mockup_chip *chip)
{
	struct gpio_chip *gc = &chip->gc;
	int irq_base, i;

188
	irq_base = devm_irq_alloc_descs(dev, -1, 0, gc->ngpio, 0);
189 190 191 192 193 194 195 196
	if (irq_base < 0)
		return irq_base;

	gc->irq_base = irq_base;
	gc->irqchip = &gpio_mockup_irqchip;

	for (i = 0; i < gc->ngpio; i++) {
		irq_set_chip(irq_base + i, gc->irqchip);
197
		irq_set_chip_data(irq_base + i, gc);
198 199 200 201 202 203 204 205 206 207
		irq_set_handler(irq_base + i, &handle_simple_irq);
		irq_modify_status(irq_base + i,
				  IRQ_NOREQUEST | IRQ_NOAUTOEN, IRQ_NOPROBE);
	}

	init_irq_work(&chip->irq_ctx.work, gpio_mockup_handle_irq);

	return 0;
}

208 209 210 211 212 213 214 215 216
static ssize_t gpio_mockup_event_write(struct file *file,
				       const char __user *usr_buf,
				       size_t size, loff_t *ppos)
{
	struct gpio_mockup_dbgfs_private *priv;
	struct gpio_mockup_chip *chip;
	struct seq_file *sfile;
	struct gpio_desc *desc;
	struct gpio_chip *gc;
217
	int rv, val;
218

219 220 221 222 223 224
	rv = kstrtoint_from_user(usr_buf, size, 0, &val);
	if (rv)
		return rv;
	if (val != 0 && val != 1)
		return -EINVAL;

225 226 227 228 229
	sfile = file->private_data;
	priv = sfile->private;
	desc = priv->desc;
	chip = priv->chip;
	gc = &chip->gc;
230

231 232 233 234 235
	if (chip->lines[priv->offset].irq_enabled) {
		gpiod_set_value_cansleep(desc, val);
		priv->chip->irq_ctx.irq = gc->irq_base + priv->offset;
		irq_work_queue(&priv->chip->irq_ctx.work);
	}
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291

	return size;
}

static int gpio_mockup_event_open(struct inode *inode, struct file *file)
{
	return single_open(file, NULL, inode->i_private);
}

static const struct file_operations gpio_mockup_event_ops = {
	.owner = THIS_MODULE,
	.open = gpio_mockup_event_open,
	.write = gpio_mockup_event_write,
	.llseek = no_llseek,
};

static void gpio_mockup_debugfs_setup(struct device *dev,
				      struct gpio_mockup_chip *chip)
{
	struct gpio_mockup_dbgfs_private *priv;
	struct dentry *evfile;
	struct gpio_chip *gc;
	char *name;
	int i;

	gc = &chip->gc;

	chip->dbg_dir = debugfs_create_dir(gc->label, gpio_mockup_dbg_dir);
	if (!chip->dbg_dir)
		goto err;

	for (i = 0; i < gc->ngpio; i++) {
		name = devm_kasprintf(dev, GFP_KERNEL, "%d", i);
		if (!name)
			goto err;

		priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
		if (!priv)
			goto err;

		priv->chip = chip;
		priv->offset = i;
		priv->desc = &gc->gpiodev->descs[i];

		evfile = debugfs_create_file(name, 0200, chip->dbg_dir, priv,
					     &gpio_mockup_event_ops);
		if (!evfile)
			goto err;
	}

	return;

err:
	dev_err(dev, "error creating debugfs directory\n");
}

292 293
static int gpio_mockup_add(struct device *dev,
			   struct gpio_mockup_chip *chip,
294 295
			   const char *name, int base, int ngpio)
{
296
	struct gpio_chip *gc = &chip->gc;
297
	int ret;
298

299 300 301 302 303 304 305 306 307 308
	gc->base = base;
	gc->ngpio = ngpio;
	gc->label = name;
	gc->owner = THIS_MODULE;
	gc->parent = dev;
	gc->get = gpio_mockup_get;
	gc->set = gpio_mockup_set;
	gc->direction_output = gpio_mockup_dirout;
	gc->direction_input = gpio_mockup_dirin;
	gc->get_direction = gpio_mockup_get_direction;
309
	gc->to_irq = gpio_mockup_to_irq;
310

311 312
	chip->lines = devm_kcalloc(dev, gc->ngpio,
				   sizeof(*chip->lines), GFP_KERNEL);
313 314
	if (!chip->lines)
		return -ENOMEM;
315

316 317 318 319 320 321
	if (gpio_mockup_named_lines) {
		ret = gpio_mockup_name_lines(dev, chip);
		if (ret)
			return ret;
	}

322 323 324 325
	ret = gpio_mockup_irqchip_setup(dev, chip);
	if (ret)
		return ret;

326 327 328 329 330 331 332 333
	ret = devm_gpiochip_add_data(dev, &chip->gc, chip);
	if (ret)
		return ret;

	if (gpio_mockup_dbg_dir)
		gpio_mockup_debugfs_setup(dev, chip);

	return 0;
334 335
}

336
static int gpio_mockup_probe(struct platform_device *pdev)
337
{
338
	int ret, i, base, ngpio, num_chips;
339
	struct device *dev = &pdev->dev;
340
	struct gpio_mockup_chip *chips;
341
	char *chip_name;
342

343
	if (gpio_mockup_params_nr < 2 || (gpio_mockup_params_nr % 2))
344 345
		return -EINVAL;

346 347 348
	/* Each chip is described by two values. */
	num_chips = gpio_mockup_params_nr / 2;

349
	chips = devm_kcalloc(dev, num_chips, sizeof(*chips), GFP_KERNEL);
350
	if (!chips)
351 352
		return -ENOMEM;

353
	platform_set_drvdata(pdev, chips);
354

355
	for (i = 0; i < num_chips; i++) {
356
		base = gpio_mockup_ranges[i * 2];
357

358 359 360 361 362 363
		if (base == -1)
			ngpio = gpio_mockup_ranges[i * 2 + 1];
		else
			ngpio = gpio_mockup_ranges[i * 2 + 1] - base;

		if (ngpio >= 0) {
364
			chip_name = devm_kasprintf(dev, GFP_KERNEL,
365 366
						   "%s-%c", GPIO_MOCKUP_NAME,
						   gpio_mockup_name_start + i);
367 368 369
			if (!chip_name)
				return -ENOMEM;

370
			ret = gpio_mockup_add(dev, &chips[i],
371 372
					      chip_name, base, ngpio);
		} else {
373
			ret = -EINVAL;
374
		}
375

376
		if (ret) {
377 378 379
			dev_err(dev,
				"adding gpiochip failed: %d (base: %d, ngpio: %d)\n",
				ret, base, base < 0 ? ngpio : base + ngpio);
380 381 382 383 384 385 386 387

			return ret;
		}
	}

	return 0;
}

388
static struct platform_driver gpio_mockup_driver = {
389
	.driver = {
390
		.name = GPIO_MOCKUP_NAME,
391
	},
392
	.probe = gpio_mockup_probe,
393 394 395 396 397 398 399
};

static struct platform_device *pdev;
static int __init mock_device_init(void)
{
	int err;

400 401 402 403 404
	gpio_mockup_dbg_dir = debugfs_create_dir("gpio-mockup-event", NULL);
	if (!gpio_mockup_dbg_dir)
		pr_err("%s: error creating debugfs directory\n",
		       GPIO_MOCKUP_NAME);

405
	pdev = platform_device_alloc(GPIO_MOCKUP_NAME, -1);
406 407 408 409 410 411 412 413 414
	if (!pdev)
		return -ENOMEM;

	err = platform_device_add(pdev);
	if (err) {
		platform_device_put(pdev);
		return err;
	}

415
	err = platform_driver_register(&gpio_mockup_driver);
416 417 418 419 420 421 422 423 424 425
	if (err) {
		platform_device_unregister(pdev);
		return err;
	}

	return 0;
}

static void __exit mock_device_exit(void)
{
426
	debugfs_remove_recursive(gpio_mockup_dbg_dir);
427
	platform_driver_unregister(&gpio_mockup_driver);
428 429 430 431 432 433 434 435
	platform_device_unregister(pdev);
}

module_init(mock_device_init);
module_exit(mock_device_exit);

MODULE_AUTHOR("Kamlakant Patel <kamlakant.patel@broadcom.com>");
MODULE_AUTHOR("Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>");
436
MODULE_AUTHOR("Bartosz Golaszewski <brgl@bgdev.pl>");
437 438
MODULE_DESCRIPTION("GPIO Testing driver");
MODULE_LICENSE("GPL v2");