0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/kernel.h>
0014 #include <linux/slab.h>
0015 #include <linux/interrupt.h>
0016 #include <linux/irq.h>
0017 #include <linux/mutex.h>
0018 #include <linux/module.h>
0019 #include <linux/sysfs.h>
0020
0021 #include "iio_dummy_evgen.h"
0022 #include <linux/iio/iio.h>
0023 #include <linux/iio/sysfs.h>
0024 #include <linux/irq_sim.h>
0025
0026
0027 #define IIO_EVENTGEN_NO 10
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038 struct iio_dummy_eventgen {
0039 struct iio_dummy_regs regs[IIO_EVENTGEN_NO];
0040 struct mutex lock;
0041 bool inuse[IIO_EVENTGEN_NO];
0042 struct irq_domain *irq_sim_domain;
0043 };
0044
0045
0046 static struct iio_dummy_eventgen *iio_evgen;
0047
0048 static int iio_dummy_evgen_create(void)
0049 {
0050 int ret;
0051
0052 iio_evgen = kzalloc(sizeof(*iio_evgen), GFP_KERNEL);
0053 if (!iio_evgen)
0054 return -ENOMEM;
0055
0056 iio_evgen->irq_sim_domain = irq_domain_create_sim(NULL,
0057 IIO_EVENTGEN_NO);
0058 if (IS_ERR(iio_evgen->irq_sim_domain)) {
0059 ret = PTR_ERR(iio_evgen->irq_sim_domain);
0060 kfree(iio_evgen);
0061 return ret;
0062 }
0063
0064 mutex_init(&iio_evgen->lock);
0065
0066 return 0;
0067 }
0068
0069
0070
0071
0072
0073
0074
0075 int iio_dummy_evgen_get_irq(void)
0076 {
0077 int i, ret = 0;
0078
0079 if (!iio_evgen)
0080 return -ENODEV;
0081
0082 mutex_lock(&iio_evgen->lock);
0083 for (i = 0; i < IIO_EVENTGEN_NO; i++) {
0084 if (!iio_evgen->inuse[i]) {
0085 ret = irq_create_mapping(iio_evgen->irq_sim_domain, i);
0086 iio_evgen->inuse[i] = true;
0087 break;
0088 }
0089 }
0090 mutex_unlock(&iio_evgen->lock);
0091 if (i == IIO_EVENTGEN_NO)
0092 return -ENOMEM;
0093
0094 return ret;
0095 }
0096 EXPORT_SYMBOL_GPL(iio_dummy_evgen_get_irq);
0097
0098
0099
0100
0101
0102
0103
0104 void iio_dummy_evgen_release_irq(int irq)
0105 {
0106 struct irq_data *irqd = irq_get_irq_data(irq);
0107
0108 mutex_lock(&iio_evgen->lock);
0109 iio_evgen->inuse[irqd_to_hwirq(irqd)] = false;
0110 irq_dispose_mapping(irq);
0111 mutex_unlock(&iio_evgen->lock);
0112 }
0113 EXPORT_SYMBOL_GPL(iio_dummy_evgen_release_irq);
0114
0115 struct iio_dummy_regs *iio_dummy_evgen_get_regs(int irq)
0116 {
0117 struct irq_data *irqd = irq_get_irq_data(irq);
0118
0119 return &iio_evgen->regs[irqd_to_hwirq(irqd)];
0120
0121 }
0122 EXPORT_SYMBOL_GPL(iio_dummy_evgen_get_regs);
0123
0124 static void iio_dummy_evgen_free(void)
0125 {
0126 irq_domain_remove_sim(iio_evgen->irq_sim_domain);
0127 kfree(iio_evgen);
0128 }
0129
0130 static void iio_evgen_release(struct device *dev)
0131 {
0132 iio_dummy_evgen_free();
0133 }
0134
0135 static ssize_t iio_evgen_poke(struct device *dev,
0136 struct device_attribute *attr,
0137 const char *buf,
0138 size_t len)
0139 {
0140 struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
0141 unsigned long event;
0142 int ret, irq;
0143
0144 ret = kstrtoul(buf, 10, &event);
0145 if (ret)
0146 return ret;
0147
0148 iio_evgen->regs[this_attr->address].reg_id = this_attr->address;
0149 iio_evgen->regs[this_attr->address].reg_data = event;
0150
0151 irq = irq_find_mapping(iio_evgen->irq_sim_domain, this_attr->address);
0152 ret = irq_set_irqchip_state(irq, IRQCHIP_STATE_PENDING, true);
0153 if (ret)
0154 return ret;
0155
0156 return len;
0157 }
0158
0159 static IIO_DEVICE_ATTR(poke_ev0, S_IWUSR, NULL, &iio_evgen_poke, 0);
0160 static IIO_DEVICE_ATTR(poke_ev1, S_IWUSR, NULL, &iio_evgen_poke, 1);
0161 static IIO_DEVICE_ATTR(poke_ev2, S_IWUSR, NULL, &iio_evgen_poke, 2);
0162 static IIO_DEVICE_ATTR(poke_ev3, S_IWUSR, NULL, &iio_evgen_poke, 3);
0163 static IIO_DEVICE_ATTR(poke_ev4, S_IWUSR, NULL, &iio_evgen_poke, 4);
0164 static IIO_DEVICE_ATTR(poke_ev5, S_IWUSR, NULL, &iio_evgen_poke, 5);
0165 static IIO_DEVICE_ATTR(poke_ev6, S_IWUSR, NULL, &iio_evgen_poke, 6);
0166 static IIO_DEVICE_ATTR(poke_ev7, S_IWUSR, NULL, &iio_evgen_poke, 7);
0167 static IIO_DEVICE_ATTR(poke_ev8, S_IWUSR, NULL, &iio_evgen_poke, 8);
0168 static IIO_DEVICE_ATTR(poke_ev9, S_IWUSR, NULL, &iio_evgen_poke, 9);
0169
0170 static struct attribute *iio_evgen_attrs[] = {
0171 &iio_dev_attr_poke_ev0.dev_attr.attr,
0172 &iio_dev_attr_poke_ev1.dev_attr.attr,
0173 &iio_dev_attr_poke_ev2.dev_attr.attr,
0174 &iio_dev_attr_poke_ev3.dev_attr.attr,
0175 &iio_dev_attr_poke_ev4.dev_attr.attr,
0176 &iio_dev_attr_poke_ev5.dev_attr.attr,
0177 &iio_dev_attr_poke_ev6.dev_attr.attr,
0178 &iio_dev_attr_poke_ev7.dev_attr.attr,
0179 &iio_dev_attr_poke_ev8.dev_attr.attr,
0180 &iio_dev_attr_poke_ev9.dev_attr.attr,
0181 NULL,
0182 };
0183
0184 static const struct attribute_group iio_evgen_group = {
0185 .attrs = iio_evgen_attrs,
0186 };
0187
0188 static const struct attribute_group *iio_evgen_groups[] = {
0189 &iio_evgen_group,
0190 NULL
0191 };
0192
0193 static struct device iio_evgen_dev = {
0194 .bus = &iio_bus_type,
0195 .groups = iio_evgen_groups,
0196 .release = &iio_evgen_release,
0197 };
0198
0199 static __init int iio_dummy_evgen_init(void)
0200 {
0201 int ret = iio_dummy_evgen_create();
0202
0203 if (ret < 0)
0204 return ret;
0205 device_initialize(&iio_evgen_dev);
0206 dev_set_name(&iio_evgen_dev, "iio_evgen");
0207 ret = device_add(&iio_evgen_dev);
0208 if (ret)
0209 put_device(&iio_evgen_dev);
0210 return ret;
0211 }
0212 module_init(iio_dummy_evgen_init);
0213
0214 static __exit void iio_dummy_evgen_exit(void)
0215 {
0216 device_unregister(&iio_evgen_dev);
0217 }
0218 module_exit(iio_dummy_evgen_exit);
0219
0220 MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
0221 MODULE_DESCRIPTION("IIO dummy driver");
0222 MODULE_LICENSE("GPL v2");