0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029 #include <linux/completion.h>
0030 #include <linux/device.h>
0031 #include <linux/err.h>
0032 #include <linux/kernel.h>
0033 #include <linux/module.h>
0034 #include <linux/mod_devicetable.h>
0035 #include <linux/mutex.h>
0036 #include <linux/iio/consumer.h>
0037 #include <linux/iio/iio.h>
0038 #include <linux/iio/sysfs.h>
0039 #include <linux/interrupt.h>
0040 #include <linux/irq.h>
0041 #include <linux/platform_device.h>
0042 #include <linux/spinlock.h>
0043 #include <linux/workqueue.h>
0044
0045 struct envelope {
0046 spinlock_t comp_lock;
0047 int comp;
0048
0049 struct mutex read_lock;
0050
0051 int comp_irq;
0052 u32 comp_irq_trigger;
0053 u32 comp_irq_trigger_inv;
0054
0055 struct iio_channel *dac;
0056 struct delayed_work comp_timeout;
0057
0058 unsigned int comp_interval;
0059 bool invert;
0060 u32 dac_max;
0061
0062 int high;
0063 int level;
0064 int low;
0065
0066 struct completion done;
0067 };
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079 static int envelope_detector_comp_latch(struct envelope *env)
0080 {
0081 int comp;
0082
0083 spin_lock_irq(&env->comp_lock);
0084 comp = env->comp;
0085 env->comp = 0;
0086 spin_unlock_irq(&env->comp_lock);
0087
0088 if (!comp)
0089 return 0;
0090
0091
0092
0093
0094
0095
0096
0097
0098 enable_irq(env->comp_irq);
0099
0100
0101 synchronize_irq(env->comp_irq);
0102
0103
0104 spin_lock_irq(&env->comp_lock);
0105 comp = env->comp;
0106 env->comp = 0;
0107 spin_unlock_irq(&env->comp_lock);
0108
0109 if (comp)
0110 enable_irq(env->comp_irq);
0111
0112 return 1;
0113 }
0114
0115 static irqreturn_t envelope_detector_comp_isr(int irq, void *ctx)
0116 {
0117 struct envelope *env = ctx;
0118
0119 spin_lock(&env->comp_lock);
0120 env->comp = 1;
0121 disable_irq_nosync(env->comp_irq);
0122 spin_unlock(&env->comp_lock);
0123
0124 return IRQ_HANDLED;
0125 }
0126
0127 static void envelope_detector_setup_compare(struct envelope *env)
0128 {
0129 int ret;
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141 env->level = (env->high + env->low + !env->invert) / 2;
0142
0143 if (env->high == env->low + 1) {
0144 complete(&env->done);
0145 return;
0146 }
0147
0148
0149 ret = iio_write_channel_raw(env->dac, env->invert ? 0 : env->dac_max);
0150 if (ret < 0)
0151 goto err;
0152
0153
0154 envelope_detector_comp_latch(env);
0155
0156
0157 ret = iio_write_channel_raw(env->dac, env->level);
0158 if (ret < 0)
0159 goto err;
0160
0161
0162 schedule_delayed_work(&env->comp_timeout,
0163 msecs_to_jiffies(env->comp_interval));
0164 return;
0165
0166 err:
0167 env->level = ret;
0168 complete(&env->done);
0169 }
0170
0171 static void envelope_detector_timeout(struct work_struct *work)
0172 {
0173 struct envelope *env = container_of(work, struct envelope,
0174 comp_timeout.work);
0175
0176
0177 if (!envelope_detector_comp_latch(env) ^ !env->invert)
0178 env->low = env->level;
0179 else
0180 env->high = env->level;
0181
0182
0183 envelope_detector_setup_compare(env);
0184 }
0185
0186 static int envelope_detector_read_raw(struct iio_dev *indio_dev,
0187 struct iio_chan_spec const *chan,
0188 int *val, int *val2, long mask)
0189 {
0190 struct envelope *env = iio_priv(indio_dev);
0191 int ret;
0192
0193 switch (mask) {
0194 case IIO_CHAN_INFO_RAW:
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205 mutex_lock(&env->read_lock);
0206 env->high = env->dac_max + env->invert;
0207 env->low = -1 + env->invert;
0208 envelope_detector_setup_compare(env);
0209 wait_for_completion(&env->done);
0210 if (env->level < 0) {
0211 ret = env->level;
0212 goto err_unlock;
0213 }
0214 *val = env->invert ? env->dac_max - env->level : env->level;
0215 mutex_unlock(&env->read_lock);
0216
0217 return IIO_VAL_INT;
0218
0219 case IIO_CHAN_INFO_SCALE:
0220 return iio_read_channel_scale(env->dac, val, val2);
0221 }
0222
0223 return -EINVAL;
0224
0225 err_unlock:
0226 mutex_unlock(&env->read_lock);
0227 return ret;
0228 }
0229
0230 static ssize_t envelope_show_invert(struct iio_dev *indio_dev,
0231 uintptr_t private,
0232 struct iio_chan_spec const *ch, char *buf)
0233 {
0234 struct envelope *env = iio_priv(indio_dev);
0235
0236 return sprintf(buf, "%u\n", env->invert);
0237 }
0238
0239 static ssize_t envelope_store_invert(struct iio_dev *indio_dev,
0240 uintptr_t private,
0241 struct iio_chan_spec const *ch,
0242 const char *buf, size_t len)
0243 {
0244 struct envelope *env = iio_priv(indio_dev);
0245 unsigned long invert;
0246 int ret;
0247 u32 trigger;
0248
0249 ret = kstrtoul(buf, 0, &invert);
0250 if (ret < 0)
0251 return ret;
0252 if (invert > 1)
0253 return -EINVAL;
0254
0255 trigger = invert ? env->comp_irq_trigger_inv : env->comp_irq_trigger;
0256
0257 mutex_lock(&env->read_lock);
0258 if (invert != env->invert)
0259 ret = irq_set_irq_type(env->comp_irq, trigger);
0260 if (!ret) {
0261 env->invert = invert;
0262 ret = len;
0263 }
0264 mutex_unlock(&env->read_lock);
0265
0266 return ret;
0267 }
0268
0269 static ssize_t envelope_show_comp_interval(struct iio_dev *indio_dev,
0270 uintptr_t private,
0271 struct iio_chan_spec const *ch,
0272 char *buf)
0273 {
0274 struct envelope *env = iio_priv(indio_dev);
0275
0276 return sprintf(buf, "%u\n", env->comp_interval);
0277 }
0278
0279 static ssize_t envelope_store_comp_interval(struct iio_dev *indio_dev,
0280 uintptr_t private,
0281 struct iio_chan_spec const *ch,
0282 const char *buf, size_t len)
0283 {
0284 struct envelope *env = iio_priv(indio_dev);
0285 unsigned long interval;
0286 int ret;
0287
0288 ret = kstrtoul(buf, 0, &interval);
0289 if (ret < 0)
0290 return ret;
0291 if (interval > 1000)
0292 return -EINVAL;
0293
0294 mutex_lock(&env->read_lock);
0295 env->comp_interval = interval;
0296 mutex_unlock(&env->read_lock);
0297
0298 return len;
0299 }
0300
0301 static const struct iio_chan_spec_ext_info envelope_detector_ext_info[] = {
0302 { .name = "invert",
0303 .read = envelope_show_invert,
0304 .write = envelope_store_invert, },
0305 { .name = "compare_interval",
0306 .read = envelope_show_comp_interval,
0307 .write = envelope_store_comp_interval, },
0308 { }
0309 };
0310
0311 static const struct iio_chan_spec envelope_detector_iio_channel = {
0312 .type = IIO_ALTVOLTAGE,
0313 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
0314 | BIT(IIO_CHAN_INFO_SCALE),
0315 .ext_info = envelope_detector_ext_info,
0316 .indexed = 1,
0317 };
0318
0319 static const struct iio_info envelope_detector_info = {
0320 .read_raw = &envelope_detector_read_raw,
0321 };
0322
0323 static int envelope_detector_probe(struct platform_device *pdev)
0324 {
0325 struct device *dev = &pdev->dev;
0326 struct iio_dev *indio_dev;
0327 struct envelope *env;
0328 enum iio_chan_type type;
0329 int ret;
0330
0331 indio_dev = devm_iio_device_alloc(dev, sizeof(*env));
0332 if (!indio_dev)
0333 return -ENOMEM;
0334
0335 platform_set_drvdata(pdev, indio_dev);
0336 env = iio_priv(indio_dev);
0337 env->comp_interval = 50;
0338
0339 spin_lock_init(&env->comp_lock);
0340 mutex_init(&env->read_lock);
0341 init_completion(&env->done);
0342 INIT_DELAYED_WORK(&env->comp_timeout, envelope_detector_timeout);
0343
0344 indio_dev->name = dev_name(dev);
0345 indio_dev->info = &envelope_detector_info;
0346 indio_dev->channels = &envelope_detector_iio_channel;
0347 indio_dev->num_channels = 1;
0348
0349 env->dac = devm_iio_channel_get(dev, "dac");
0350 if (IS_ERR(env->dac))
0351 return dev_err_probe(dev, PTR_ERR(env->dac),
0352 "failed to get dac input channel\n");
0353
0354 env->comp_irq = platform_get_irq_byname(pdev, "comp");
0355 if (env->comp_irq < 0)
0356 return env->comp_irq;
0357
0358 ret = devm_request_irq(dev, env->comp_irq, envelope_detector_comp_isr,
0359 0, "envelope-detector", env);
0360 if (ret)
0361 return dev_err_probe(dev, ret, "failed to request interrupt\n");
0362
0363 env->comp_irq_trigger = irq_get_trigger_type(env->comp_irq);
0364 if (env->comp_irq_trigger & IRQF_TRIGGER_RISING)
0365 env->comp_irq_trigger_inv |= IRQF_TRIGGER_FALLING;
0366 if (env->comp_irq_trigger & IRQF_TRIGGER_FALLING)
0367 env->comp_irq_trigger_inv |= IRQF_TRIGGER_RISING;
0368 if (env->comp_irq_trigger & IRQF_TRIGGER_HIGH)
0369 env->comp_irq_trigger_inv |= IRQF_TRIGGER_LOW;
0370 if (env->comp_irq_trigger & IRQF_TRIGGER_LOW)
0371 env->comp_irq_trigger_inv |= IRQF_TRIGGER_HIGH;
0372
0373 ret = iio_get_channel_type(env->dac, &type);
0374 if (ret < 0)
0375 return ret;
0376
0377 if (type != IIO_VOLTAGE) {
0378 dev_err(dev, "dac is of the wrong type\n");
0379 return -EINVAL;
0380 }
0381
0382 ret = iio_read_max_channel_raw(env->dac, &env->dac_max);
0383 if (ret < 0) {
0384 dev_err(dev, "dac does not indicate its raw maximum value\n");
0385 return ret;
0386 }
0387
0388 return devm_iio_device_register(dev, indio_dev);
0389 }
0390
0391 static const struct of_device_id envelope_detector_match[] = {
0392 { .compatible = "axentia,tse850-envelope-detector", },
0393 { }
0394 };
0395 MODULE_DEVICE_TABLE(of, envelope_detector_match);
0396
0397 static struct platform_driver envelope_detector_driver = {
0398 .probe = envelope_detector_probe,
0399 .driver = {
0400 .name = "iio-envelope-detector",
0401 .of_match_table = envelope_detector_match,
0402 },
0403 };
0404 module_platform_driver(envelope_detector_driver);
0405
0406 MODULE_DESCRIPTION("Envelope detector using a DAC and a comparator");
0407 MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
0408 MODULE_LICENSE("GPL v2");