Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
iio_dummy_evgen.c
Go to the documentation of this file.
1 
16 #include <linux/kernel.h>
17 #include <linux/slab.h>
18 #include <linux/interrupt.h>
19 #include <linux/irq.h>
20 #include <linux/mutex.h>
21 #include <linux/module.h>
22 #include <linux/sysfs.h>
23 
24 #include "iio_dummy_evgen.h"
25 #include <linux/iio/iio.h>
26 #include <linux/iio/sysfs.h>
27 
28 /* Fiddly bit of faking and irq without hardware */
29 #define IIO_EVENTGEN_NO 10
30 
39  struct irq_chip chip;
40  int base;
43  struct mutex lock;
44 };
45 
46 /* We can only ever have one instance of this 'device' */
47 static struct iio_dummy_eventgen *iio_evgen;
48 static const char *iio_evgen_name = "iio_dummy_evgen";
49 
50 static void iio_dummy_event_irqmask(struct irq_data *d)
51 {
52  struct irq_chip *chip = irq_data_get_irq_chip(d);
53  struct iio_dummy_eventgen *evgen =
54  container_of(chip, struct iio_dummy_eventgen, chip);
55 
56  evgen->enabled[d->irq - evgen->base] = false;
57 }
58 
59 static void iio_dummy_event_irqunmask(struct irq_data *d)
60 {
61  struct irq_chip *chip = irq_data_get_irq_chip(d);
62  struct iio_dummy_eventgen *evgen =
63  container_of(chip, struct iio_dummy_eventgen, chip);
64 
65  evgen->enabled[d->irq - evgen->base] = true;
66 }
67 
68 static int iio_dummy_evgen_create(void)
69 {
70  int ret, i;
71 
72  iio_evgen = kzalloc(sizeof(*iio_evgen), GFP_KERNEL);
73  if (iio_evgen == NULL)
74  return -ENOMEM;
75 
76  iio_evgen->base = irq_alloc_descs(-1, 0, IIO_EVENTGEN_NO, 0);
77  if (iio_evgen->base < 0) {
78  ret = iio_evgen->base;
79  kfree(iio_evgen);
80  return ret;
81  }
82  iio_evgen->chip.name = iio_evgen_name;
83  iio_evgen->chip.irq_mask = &iio_dummy_event_irqmask;
84  iio_evgen->chip.irq_unmask = &iio_dummy_event_irqunmask;
85  for (i = 0; i < IIO_EVENTGEN_NO; i++) {
86  irq_set_chip(iio_evgen->base + i, &iio_evgen->chip);
87  irq_set_handler(iio_evgen->base + i, &handle_simple_irq);
88  irq_modify_status(iio_evgen->base + i,
90  IRQ_NOPROBE);
91  }
92  mutex_init(&iio_evgen->lock);
93  return 0;
94 }
95 
103 {
104  int i, ret = 0;
105 
106  if (iio_evgen == NULL)
107  return -ENODEV;
108 
109  mutex_lock(&iio_evgen->lock);
110  for (i = 0; i < IIO_EVENTGEN_NO; i++)
111  if (iio_evgen->inuse[i] == false) {
112  ret = iio_evgen->base + i;
113  iio_evgen->inuse[i] = true;
114  break;
115  }
116  mutex_unlock(&iio_evgen->lock);
117  if (i == IIO_EVENTGEN_NO)
118  return -ENOMEM;
119  return ret;
120 }
122 
130 {
131  mutex_lock(&iio_evgen->lock);
132  iio_evgen->inuse[irq - iio_evgen->base] = false;
133  mutex_unlock(&iio_evgen->lock);
134 
135  return 0;
136 }
138 
139 static void iio_dummy_evgen_free(void)
140 {
141  irq_free_descs(iio_evgen->base, IIO_EVENTGEN_NO);
142  kfree(iio_evgen);
143 }
144 
145 static void iio_evgen_release(struct device *dev)
146 {
147  iio_dummy_evgen_free();
148 }
149 
150 static ssize_t iio_evgen_poke(struct device *dev,
151  struct device_attribute *attr,
152  const char *buf,
153  size_t len)
154 {
155  struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
156 
157  if (iio_evgen->enabled[this_attr->address])
158  handle_nested_irq(iio_evgen->base + this_attr->address);
159 
160  return len;
161 }
162 
163 static IIO_DEVICE_ATTR(poke_ev0, S_IWUSR, NULL, &iio_evgen_poke, 0);
164 static IIO_DEVICE_ATTR(poke_ev1, S_IWUSR, NULL, &iio_evgen_poke, 1);
165 static IIO_DEVICE_ATTR(poke_ev2, S_IWUSR, NULL, &iio_evgen_poke, 2);
166 static IIO_DEVICE_ATTR(poke_ev3, S_IWUSR, NULL, &iio_evgen_poke, 3);
167 static IIO_DEVICE_ATTR(poke_ev4, S_IWUSR, NULL, &iio_evgen_poke, 4);
168 static IIO_DEVICE_ATTR(poke_ev5, S_IWUSR, NULL, &iio_evgen_poke, 5);
169 static IIO_DEVICE_ATTR(poke_ev6, S_IWUSR, NULL, &iio_evgen_poke, 6);
170 static IIO_DEVICE_ATTR(poke_ev7, S_IWUSR, NULL, &iio_evgen_poke, 7);
171 static IIO_DEVICE_ATTR(poke_ev8, S_IWUSR, NULL, &iio_evgen_poke, 8);
172 static IIO_DEVICE_ATTR(poke_ev9, S_IWUSR, NULL, &iio_evgen_poke, 9);
173 
174 static struct attribute *iio_evgen_attrs[] = {
175  &iio_dev_attr_poke_ev0.dev_attr.attr,
176  &iio_dev_attr_poke_ev1.dev_attr.attr,
177  &iio_dev_attr_poke_ev2.dev_attr.attr,
178  &iio_dev_attr_poke_ev3.dev_attr.attr,
179  &iio_dev_attr_poke_ev4.dev_attr.attr,
180  &iio_dev_attr_poke_ev5.dev_attr.attr,
181  &iio_dev_attr_poke_ev6.dev_attr.attr,
182  &iio_dev_attr_poke_ev7.dev_attr.attr,
183  &iio_dev_attr_poke_ev8.dev_attr.attr,
184  &iio_dev_attr_poke_ev9.dev_attr.attr,
185  NULL,
186 };
187 
188 static const struct attribute_group iio_evgen_group = {
189  .attrs = iio_evgen_attrs,
190 };
191 
192 static const struct attribute_group *iio_evgen_groups[] = {
193  &iio_evgen_group,
194  NULL
195 };
196 
197 static struct device iio_evgen_dev = {
198  .bus = &iio_bus_type,
199  .groups = iio_evgen_groups,
200  .release = &iio_evgen_release,
201 };
202 static __init int iio_dummy_evgen_init(void)
203 {
204  int ret = iio_dummy_evgen_create();
205  if (ret < 0)
206  return ret;
207  device_initialize(&iio_evgen_dev);
208  dev_set_name(&iio_evgen_dev, "iio_evgen");
209  return device_add(&iio_evgen_dev);
210 }
211 module_init(iio_dummy_evgen_init);
212 
213 static __exit void iio_dummy_evgen_exit(void)
214 {
215  device_unregister(&iio_evgen_dev);
216 }
217 module_exit(iio_dummy_evgen_exit);
218 
219 MODULE_AUTHOR("Jonathan Cameron <[email protected]>");
220 MODULE_DESCRIPTION("IIO dummy driver");
221 MODULE_LICENSE("GPL v2");