]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/gpio/gpio-mockup.c
gpio: mockup: don't return magic numbers from probe()
[linux.git] / drivers / gpio / gpio-mockup.c
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/gpio/consumer.h>
18 #include <linux/platform_device.h>
19 #include <linux/slab.h>
20 #include <linux/interrupt.h>
21 #include <linux/irq.h>
22 #include <linux/irq_work.h>
23 #include <linux/debugfs.h>
24 #include <linux/uaccess.h>
25
26 #include "gpiolib.h"
27
28 #define GPIO_MOCKUP_NAME        "gpio-mockup"
29 #define GPIO_MOCKUP_MAX_GC      10
30 /*
31  * We're storing two values per chip: the GPIO base and the number
32  * of GPIO lines.
33  */
34 #define GPIO_MOCKUP_MAX_RANGES  (GPIO_MOCKUP_MAX_GC * 2)
35
36 enum {
37         GPIO_MOCKUP_DIR_OUT = 0,
38         GPIO_MOCKUP_DIR_IN = 1,
39 };
40
41 /*
42  * struct gpio_pin_status - structure describing a GPIO status
43  * @dir:       Configures direction of gpio as "in" or "out", 0=in, 1=out
44  * @value:     Configures status of the gpio as 0(low) or 1(high)
45  */
46 struct gpio_mockup_line_status {
47         int dir;
48         bool value;
49         bool irq_enabled;
50 };
51
52 struct gpio_mockup_irq_context {
53         struct irq_work work;
54         int irq;
55 };
56
57 struct gpio_mockup_chip {
58         struct gpio_chip gc;
59         struct gpio_mockup_line_status *lines;
60         struct gpio_mockup_irq_context irq_ctx;
61         struct dentry *dbg_dir;
62 };
63
64 struct gpio_mockup_dbgfs_private {
65         struct gpio_mockup_chip *chip;
66         struct gpio_desc *desc;
67         int offset;
68 };
69
70 static int gpio_mockup_ranges[GPIO_MOCKUP_MAX_RANGES];
71 static int gpio_mockup_params_nr;
72 module_param_array(gpio_mockup_ranges, int, &gpio_mockup_params_nr, 0400);
73
74 static bool gpio_mockup_named_lines;
75 module_param_named(gpio_mockup_named_lines,
76                    gpio_mockup_named_lines, bool, 0400);
77
78 static const char gpio_mockup_name_start = 'A';
79 static struct dentry *gpio_mockup_dbg_dir;
80
81 static int gpio_mockup_get(struct gpio_chip *gc, unsigned int offset)
82 {
83         struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
84
85         return chip->lines[offset].value;
86 }
87
88 static void gpio_mockup_set(struct gpio_chip *gc, unsigned int offset,
89                             int value)
90 {
91         struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
92
93         chip->lines[offset].value = !!value;
94 }
95
96 static int gpio_mockup_dirout(struct gpio_chip *gc, unsigned int offset,
97                               int value)
98 {
99         struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
100
101         gpio_mockup_set(gc, offset, value);
102         chip->lines[offset].dir = GPIO_MOCKUP_DIR_OUT;
103
104         return 0;
105 }
106
107 static int gpio_mockup_dirin(struct gpio_chip *gc, unsigned int offset)
108 {
109         struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
110
111         chip->lines[offset].dir = GPIO_MOCKUP_DIR_IN;
112
113         return 0;
114 }
115
116 static int gpio_mockup_get_direction(struct gpio_chip *gc, unsigned int offset)
117 {
118         struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
119
120         return chip->lines[offset].dir;
121 }
122
123 static int gpio_mockup_name_lines(struct device *dev,
124                                   struct gpio_mockup_chip *chip)
125 {
126         struct gpio_chip *gc = &chip->gc;
127         char **names;
128         int i;
129
130         names = devm_kzalloc(dev, sizeof(char *) * gc->ngpio, GFP_KERNEL);
131         if (!names)
132                 return -ENOMEM;
133
134         for (i = 0; i < gc->ngpio; i++) {
135                 names[i] = devm_kasprintf(dev, GFP_KERNEL,
136                                           "%s-%d", gc->label, i);
137                 if (!names[i])
138                         return -ENOMEM;
139         }
140
141         gc->names = (const char *const *)names;
142
143         return 0;
144 }
145
146 static int gpio_mockup_to_irq(struct gpio_chip *chip, unsigned int offset)
147 {
148         return chip->irq_base + offset;
149 }
150
151 static void gpio_mockup_irqmask(struct irq_data *data)
152 {
153         struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
154         struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
155
156         chip->lines[data->irq - gc->irq_base].irq_enabled = false;
157 }
158
159 static void gpio_mockup_irqunmask(struct irq_data *data)
160 {
161         struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
162         struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
163
164         chip->lines[data->irq - gc->irq_base].irq_enabled = true;
165 }
166
167 static struct irq_chip gpio_mockup_irqchip = {
168         .name           = GPIO_MOCKUP_NAME,
169         .irq_mask       = gpio_mockup_irqmask,
170         .irq_unmask     = gpio_mockup_irqunmask,
171 };
172
173 static void gpio_mockup_handle_irq(struct irq_work *work)
174 {
175         struct gpio_mockup_irq_context *irq_ctx;
176
177         irq_ctx = container_of(work, struct gpio_mockup_irq_context, work);
178         handle_simple_irq(irq_to_desc(irq_ctx->irq));
179 }
180
181 static int gpio_mockup_irqchip_setup(struct device *dev,
182                                      struct gpio_mockup_chip *chip)
183 {
184         struct gpio_chip *gc = &chip->gc;
185         int irq_base, i;
186
187         irq_base = devm_irq_alloc_descs(dev, -1, 0, gc->ngpio, 0);
188         if (irq_base < 0)
189                 return irq_base;
190
191         gc->irq_base = irq_base;
192         gc->irqchip = &gpio_mockup_irqchip;
193
194         for (i = 0; i < gc->ngpio; i++) {
195                 irq_set_chip(irq_base + i, gc->irqchip);
196                 irq_set_chip_data(irq_base + i, gc);
197                 irq_set_handler(irq_base + i, &handle_simple_irq);
198                 irq_modify_status(irq_base + i,
199                                   IRQ_NOREQUEST | IRQ_NOAUTOEN, IRQ_NOPROBE);
200         }
201
202         init_irq_work(&chip->irq_ctx.work, gpio_mockup_handle_irq);
203
204         return 0;
205 }
206
207 static ssize_t gpio_mockup_event_write(struct file *file,
208                                        const char __user *usr_buf,
209                                        size_t size, loff_t *ppos)
210 {
211         struct gpio_mockup_dbgfs_private *priv;
212         struct gpio_mockup_chip *chip;
213         struct seq_file *sfile;
214         struct gpio_desc *desc;
215         struct gpio_chip *gc;
216         int rv, val;
217
218         rv = kstrtoint_from_user(usr_buf, size, 0, &val);
219         if (rv)
220                 return rv;
221         if (val != 0 && val != 1)
222                 return -EINVAL;
223
224         sfile = file->private_data;
225         priv = sfile->private;
226         desc = priv->desc;
227         chip = priv->chip;
228         gc = &chip->gc;
229
230         if (chip->lines[priv->offset].irq_enabled) {
231                 gpiod_set_value_cansleep(desc, val);
232                 priv->chip->irq_ctx.irq = gc->irq_base + priv->offset;
233                 irq_work_queue(&priv->chip->irq_ctx.work);
234         }
235
236         return size;
237 }
238
239 static int gpio_mockup_event_open(struct inode *inode, struct file *file)
240 {
241         return single_open(file, NULL, inode->i_private);
242 }
243
244 static const struct file_operations gpio_mockup_event_ops = {
245         .owner = THIS_MODULE,
246         .open = gpio_mockup_event_open,
247         .write = gpio_mockup_event_write,
248         .llseek = no_llseek,
249 };
250
251 static void gpio_mockup_debugfs_setup(struct device *dev,
252                                       struct gpio_mockup_chip *chip)
253 {
254         struct gpio_mockup_dbgfs_private *priv;
255         struct dentry *evfile;
256         struct gpio_chip *gc;
257         char *name;
258         int i;
259
260         gc = &chip->gc;
261
262         chip->dbg_dir = debugfs_create_dir(gc->label, gpio_mockup_dbg_dir);
263         if (!chip->dbg_dir)
264                 goto err;
265
266         for (i = 0; i < gc->ngpio; i++) {
267                 name = devm_kasprintf(dev, GFP_KERNEL, "%d", i);
268                 if (!name)
269                         goto err;
270
271                 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
272                 if (!priv)
273                         goto err;
274
275                 priv->chip = chip;
276                 priv->offset = i;
277                 priv->desc = &gc->gpiodev->descs[i];
278
279                 evfile = debugfs_create_file(name, 0200, chip->dbg_dir, priv,
280                                              &gpio_mockup_event_ops);
281                 if (!evfile)
282                         goto err;
283         }
284
285         return;
286
287 err:
288         dev_err(dev, "error creating debugfs directory\n");
289 }
290
291 static int gpio_mockup_add(struct device *dev,
292                            struct gpio_mockup_chip *chip,
293                            const char *name, int base, int ngpio)
294 {
295         struct gpio_chip *gc = &chip->gc;
296         int ret;
297
298         gc->base = base;
299         gc->ngpio = ngpio;
300         gc->label = name;
301         gc->owner = THIS_MODULE;
302         gc->parent = dev;
303         gc->get = gpio_mockup_get;
304         gc->set = gpio_mockup_set;
305         gc->direction_output = gpio_mockup_dirout;
306         gc->direction_input = gpio_mockup_dirin;
307         gc->get_direction = gpio_mockup_get_direction;
308         gc->to_irq = gpio_mockup_to_irq;
309
310         chip->lines = devm_kzalloc(dev, sizeof(*chip->lines) * gc->ngpio,
311                                    GFP_KERNEL);
312         if (!chip->lines)
313                 return -ENOMEM;
314
315         if (gpio_mockup_named_lines) {
316                 ret = gpio_mockup_name_lines(dev, chip);
317                 if (ret)
318                         return ret;
319         }
320
321         ret = gpio_mockup_irqchip_setup(dev, chip);
322         if (ret)
323                 return ret;
324
325         ret = devm_gpiochip_add_data(dev, &chip->gc, chip);
326         if (ret)
327                 return ret;
328
329         if (gpio_mockup_dbg_dir)
330                 gpio_mockup_debugfs_setup(dev, chip);
331
332         return 0;
333 }
334
335 static int gpio_mockup_probe(struct platform_device *pdev)
336 {
337         int ret, i, base, ngpio, num_chips;
338         struct device *dev = &pdev->dev;
339         struct gpio_mockup_chip *chips;
340         char *chip_name;
341
342         if (gpio_mockup_params_nr < 2 || (gpio_mockup_params_nr % 2))
343                 return -EINVAL;
344
345         /* Each chip is described by two values. */
346         num_chips = gpio_mockup_params_nr / 2;
347
348         chips = devm_kzalloc(dev, sizeof(*chips) * num_chips, GFP_KERNEL);
349         if (!chips)
350                 return -ENOMEM;
351
352         platform_set_drvdata(pdev, chips);
353
354         for (i = 0; i < num_chips; i++) {
355                 base = gpio_mockup_ranges[i * 2];
356
357                 if (base == -1)
358                         ngpio = gpio_mockup_ranges[i * 2 + 1];
359                 else
360                         ngpio = gpio_mockup_ranges[i * 2 + 1] - base;
361
362                 if (ngpio >= 0) {
363                         chip_name = devm_kasprintf(dev, GFP_KERNEL,
364                                                    "%s-%c", GPIO_MOCKUP_NAME,
365                                                    gpio_mockup_name_start + i);
366                         if (!chip_name)
367                                 return -ENOMEM;
368
369                         ret = gpio_mockup_add(dev, &chips[i],
370                                               chip_name, base, ngpio);
371                 } else {
372                         ret = -EINVAL;
373                 }
374
375                 if (ret) {
376                         dev_err(dev, "gpio<%d..%d> add failed\n",
377                                 base, base < 0 ? ngpio : base + ngpio);
378
379                         return ret;
380                 }
381         }
382
383         return 0;
384 }
385
386 static struct platform_driver gpio_mockup_driver = {
387         .driver = {
388                 .name = GPIO_MOCKUP_NAME,
389         },
390         .probe = gpio_mockup_probe,
391 };
392
393 static struct platform_device *pdev;
394 static int __init mock_device_init(void)
395 {
396         int err;
397
398         gpio_mockup_dbg_dir = debugfs_create_dir("gpio-mockup-event", NULL);
399         if (!gpio_mockup_dbg_dir)
400                 pr_err("%s: error creating debugfs directory\n",
401                        GPIO_MOCKUP_NAME);
402
403         pdev = platform_device_alloc(GPIO_MOCKUP_NAME, -1);
404         if (!pdev)
405                 return -ENOMEM;
406
407         err = platform_device_add(pdev);
408         if (err) {
409                 platform_device_put(pdev);
410                 return err;
411         }
412
413         err = platform_driver_register(&gpio_mockup_driver);
414         if (err) {
415                 platform_device_unregister(pdev);
416                 return err;
417         }
418
419         return 0;
420 }
421
422 static void __exit mock_device_exit(void)
423 {
424         debugfs_remove_recursive(gpio_mockup_dbg_dir);
425         platform_driver_unregister(&gpio_mockup_driver);
426         platform_device_unregister(pdev);
427 }
428
429 module_init(mock_device_init);
430 module_exit(mock_device_exit);
431
432 MODULE_AUTHOR("Kamlakant Patel <kamlakant.patel@broadcom.com>");
433 MODULE_AUTHOR("Bamvor Jian Zhang <bamvor.zhangjian@linaro.org>");
434 MODULE_DESCRIPTION("GPIO Testing driver");
435 MODULE_LICENSE("GPL v2");