Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S934347AbcJTJ1H (ORCPT ); Thu, 20 Oct 2016 05:27:07 -0400 Received: from mail-db5eur01on0119.outbound.protection.outlook.com ([104.47.2.119]:41664 "EHLO EUR01-DB5-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S933799AbcJTJ1C (ORCPT ); Thu, 20 Oct 2016 05:27:02 -0400 Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=peda@axentia.se; From: Peter Rosin To: CC: Peter Rosin , Jonathan Cameron , Hartmut Knaack , Lars-Peter Clausen , Peter Meerwald-Stadler , Rob Herring , Mark Rutland , , Subject: [PATCH 4/4] iio: envelope-detector: ADC driver based on a DAC and a comparator Date: Thu, 20 Oct 2016 11:26:02 +0200 Message-ID: <1476955562-13673-5-git-send-email-peda@axentia.se> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1476955562-13673-1-git-send-email-peda@axentia.se> References: <1476955562-13673-1-git-send-email-peda@axentia.se> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [217.210.101.82] X-ClientProxiedBy: DB6P18901CA0022.EURP189.PROD.OUTLOOK.COM (10.169.208.160) To AM5PR0201MB2308.eurprd02.prod.outlook.com (10.169.243.7) X-MS-Office365-Filtering-Correlation-Id: 2fa6ce25-7ee3-4493-8f28-08d3f8cb3e56 X-Microsoft-Exchange-Diagnostics: 1;AM5PR0201MB2308;2:FpjZCAOBdevbkqDAykurPLfbh/dDJLe8eqcDViCxWVO93kRuP8XO5nctNe+mlzeSg82tIgV/Q8mb1fD4rtQnZOqK6KFLNqwvO5gTwaeI9uE6LTezhkqTxGiJmiWqONxYQUjA1nCgsAgx/cRlKNavs1+XRteYmeABabklL1o9ZEyFxaP4EYl/UgdKDWIpkFpEcPUqm+bGlXZxB5SH+fT6Mw==;3:p87nOIxroZ7DsvYL+WRaXd9wv3u1ch1IlpUvmWvmcjLp/b1KgJoPDnrdcOfyznPKjGbaPgtPVhVyW2HmobuRUAGxzeBXhsyJ8NHykGXvcU6gibnbYgt7IPZd8ZJIail8WgeLB+DLFmXiMo2c+loa0Q== X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:AM5PR0201MB2308; X-Microsoft-Exchange-Diagnostics: 1;AM5PR0201MB2308;25:7TVZhPZkFdATBB1hjJt4FwSCIER8p3Ysw9T2ieMH5kc2DTivPOEaB3irHNAsyltI1J/5Rj5uW+2RgsdedQHtPGh1bgduvRGOC0f7d6cUa3qhax2Hl0DTC+cbG7UTh+MCVBUXmmNlmI9Rw/Jke48hqae1fE4k+w1qxArlx8d/7J8zJrRQOQy5kV7R+aGmhX9kbaCpXkEbBvF71W0/fKYIkOYi2NvrJJxEsbk0baEMrv8zRXetXH39uRS2r5x+r0NRf2MJEFMa6gEYqNIpkBCKpO62hBN5QDt0ZVJi0exX2S0SHjbDjLelEg2H5NmyPf7nBDururD9kiJE0zTraY69n79cKvfycVXKD4StTS8dsDztDpcSN0QJ/EkIEGyjifvdWTvIvtABKhoqgimQ55J4wesevsX5xHCnmPzVII86ybyic5B1tW318L6zbsJf4nHA+Z7wtu2L+pX/DLFKUKgYJsqYFVgbCP+th1gYvyCRvu9jro9TY/nqJYa1pBlGYznaGkR3fU0P2R80DFzW64d8YxSvg/MFCoAl/q45fkwXMID73M9FzjCp1p3ln18IjMqQU/So232uS5aJncV0I3QeJ1RmDZqaIOlpUTLQp3mhMw8Tr1Vxp5IU/eisGtjfOpVwluHhvT4noputFvJy1DNcECehlpM6LKtPE7iBf/DxemQyq2hckQ3SLAtU9Z0cX8TI+Xbm2rk1Mt578jmjDUtlSzvzIKMoIlJ6fKQniI8PdiwtYVrm696wqnV1rSXyiHwD X-Microsoft-Exchange-Diagnostics: 1;AM5PR0201MB2308;31:MTYdXV3Y+WiFFXP41/PHmC3oL/vcxg8/KBoHyUTwWj2otU5Ji8I6rhQsOaR40rCtbnsMQXyMyghsCnHLxXNZKi4GcRYoe3VVckvzK+/onufvTzgBhJtfTCZOxE3V11U+PakFXxpIvLDhLGt5mUYz/ZtlhVvVtWNDftkdxi5aKgKLgBHeuL/OBptbLqaHMB5ka/lnGQvkgmQFc9YC+rXE6z7KMFQNtwCZqafZwYXDN7AKFBUkU/CKjXRZ8WiJw8ga;4:T/f3h2wb5LJNsk8vRdNOd8Yog038fjrPDbMVgmKVdrt3h2IA+3t+XQhQKq46dGyDx/mqjZDVit6RuN2EhgD/bq2mmlGSzuHPMno/azsV9ZaMLYSkSaCMTST9cD4STaKkwApPaHjlpmOPg69K4Ka8g7AFp0TFkMZdqbjTgOB/C1Tp+FVVl0VkTvD/9ojlAX3OssSvCp+8+7A9nrScEOE8ASbGjHxrLzpnvN0Z8w1nqZFSOBbvMS157pqMHlazLY1Eo1S8BJgnnVy7kwwikgIPqLiHwqluqVi8wA4D3pi7lcujT/WiQiiRXQ+VeZ+9zqEQIjCsPTymqgGinkTFLyndQ6BbOKUalrFSgo5r/GkygKpgVgToPkKXpkNTpV9MXT2Cccx2ENBGy+EjDwcCEnvroc3VqQZqiH9x/mMt8b02NI8GVxsn5DuhzsSfnoByJ1eLVkKjgKKtiB4HooPqez+xFPI7ZrPKygXcQ2OsSz9ctvU= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(9452136761055); X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(6040176)(601004)(2401047)(5005006)(8121501046)(10201501046)(3002001)(6043046)(6042046);SRVR:AM5PR0201MB2308;BCL:0;PCL:0;RULEID:;SRVR:AM5PR0201MB2308; X-Forefront-PRVS: 01018CB5B3 X-Forefront-Antispam-Report: SFV:NSPM;SFS:(10019020)(4630300001)(6009001)(6069001)(7916002)(189002)(199003)(6116002)(8666005)(77096005)(97736004)(50226002)(2351001)(19580405001)(19580395003)(68736007)(8676002)(229853001)(36756003)(101416001)(66066001)(189998001)(81166006)(81156014)(92566002)(47776003)(76176999)(50986999)(110136003)(7846002)(6916009)(2906002)(586003)(105586002)(3846002)(6666003)(7736002)(5660300001)(4326007)(50466002)(305945005)(48376002)(74482002)(106356001)(33646002)(86362001)(5003940100001)(2950100002)(42186005)(7059030)(2004002)(42262002);DIR:OUT;SFP:1102;SCL:1;SRVR:AM5PR0201MB2308;H:localhost.localdomain;FPR:;SPF:None;PTR:InfoNoRecords;MX:1;A:1;LANG:en; X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1;AM5PR0201MB2308;23:cvzsr5sDq22sSl84cRXhJSCu9K3i+BjAOiJgL+M?= =?us-ascii?Q?/Kpp61gqGyAjfYc6yUV9sHSgTt3/v3CNQIZkYChqg1KcVlwutvV81MTozwJr?= =?us-ascii?Q?5ppPY6JxSIgVGwSpk9FSLmErg/Zb62A8Gq1mzjmW7hNTsWzmyiSElHcSVeem?= =?us-ascii?Q?4gD6V71cLTXLlm6oOvbLGPIr5kFj/TgG20csYa3WjLsACFhH1heWNNzfQL0/?= =?us-ascii?Q?pPRqDRGBHKxPB/6OEr0WY1FUvGGl36dRSrV5y47cCgNcOOm2Bjy2XcxKfKr6?= =?us-ascii?Q?o+3nrQBFvP4+ujP48EsPRdVrgLCHOodz5Wk1qvsWJ2SQLp7q1N/cdda3iHMt?= =?us-ascii?Q?fkBjNEzkT4RkwGV7pnCstrjN3olet8VPiwU+3C6AD0AMOkTA8VFcAYSW1KJR?= =?us-ascii?Q?5x/U2cESnCldernp74ylCA6JhKZduylBhHuFHycv1o3a6HPepPVsYJcoxwpc?= =?us-ascii?Q?t2ex8jQSUBR4M2zl3WTmpXuqoq/HWBj22BBsK5D7M5jXFkWvI1iDloG6UBjj?= =?us-ascii?Q?wc13aZT4JDtb3mV2IPZwE1kr0eJlO5BQ1l8FWff/VcgpXKcnK6PHKWEeWiZN?= =?us-ascii?Q?DCaW4YkYRMR0mPBcZsJJ/kQTizlJEA/J6OAMJ8fMIScoD09lNJ18O1l2lg1I?= =?us-ascii?Q?L2S59fFlT1Qu0DLisvpAYrlXV2eizqsjpLaYRduU8W1/K6MlZZp59D9IRB2Y?= =?us-ascii?Q?3TpQDq/1G9Lbe1v3PdXetIOhq9ddvcja2rg5BHk8PBF/t4J5d2mjNjNkXUwl?= =?us-ascii?Q?HSGDaZi0j/HyyD6d4qDCnFlo90QdniDW6OO/wfld2mBxBbMynFFvP8O8PP8J?= =?us-ascii?Q?F1jO6v3F4hnN6cjvqUYRHYA8It36fhoKjCDTRLDvJeOEK2TDn1zUK3Yqex2L?= =?us-ascii?Q?gtEPIuKQoKL1zToU4rznqXRhrG9wd8cQu55NBiS//K7p8LTs3kxMgSMTB6Gp?= =?us-ascii?Q?tRt+SQxcBmvyV7IlSTdaAjfnkISHCNb4ztMJxa8QHCHaxY9+UHsrAShf/zHO?= =?us-ascii?Q?DUnftwcLXUQR4Mr4rwESHSpfhznNudFV0chI38GS1/WObvMJf6VMxLJ8fQaF?= =?us-ascii?Q?cy10xRbwsW6LGPLff42K5kjj+KHUf/tYXAWq8CGUjsCUn3HMNcmXKL6L2iqJ?= =?us-ascii?Q?jXk+9pFiL/KR10ABaEWBPBevfeVIMz9YscyMu6B4cUGVlDCXG9U4LyVYU3ht?= =?us-ascii?Q?1Aae4Aty3RxRqJXP/v+oddHGqVYIH3PFxVSmz?= X-Microsoft-Exchange-Diagnostics: 1;AM5PR0201MB2308;6:dcDaYYX9JDjxg6Wp4/xJnqbiPfBTMUqFJu6Jh/W0/xxJMv4qMNzyCoPGTCKSXwq5/Ya11wO9wxCKONXQNVszqYeZAky+5kKrPB4tBwXa8vrm4zpA+m8D7Fohf/0Uc2ckU7P8Ls55O8AFK3+X/ISkm1aGJlYx0l4W3DYaE3yysQniKK6+qp6Anxo2j2NJ6QxZlzigjLoDG4+YXhvPbvtMLSpDGrwNjFWKmU/AhhSekVDULk0Xt2oAinkar5HsiB3ofePBTfhMpy+vi4jYE0RR0ASIgshxfJYsC6sEQmzxOL+JibK0pkaBsF+3/klBJ65aVYGzL8qhgWLIjQgkKaohjg==;5:21D5DnL6klobmw6abIWY2zjN9UMDFyz/wW+gjsgkVQgxVgfvnMGo5wp2EAy3EQ/KT4d32Cgn8mlo4fF9Ltc4MLmR2Ez5t0rsViKnlcwo2UNuZVoTnDn+SvSlXyGEoFL7YgisN8jEHtKKrDxLt0aMLS8VSdC/Sl/CIyz/tHCSC1c=;24:8aVsdNW9AGzZM41H+kJMuUnswAe4PBuCt5RI7kY6C5hXgCELy3aGF15r/xQzxukCm3WHgBz3Fnx++JlkxnRL7YUhtMXlOVUnocZwSX0uru0= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1;AM5PR0201MB2308;7:f2Luoeopz9hPIEshPZDo2css454UH2iQ5mS13ozHJQHGiJ/c49aRkPv1zncqmH3F/tqE8+gT8Zoe5GBInjqkgq6Z77W9orMyIrtFvLSCgDj0epNxMLILCfxGZQLFVHrBEz57H2+TK2/gdQXVAxIEmf90GCfhuhjtlNOQWCu/ky9CxCLkYcOlRWBcsgtiuPhkW+jFCDRKsUS72kTNGrwrrn5oCErIPPv1t4GJN3y6FaRSBR7bCLzExW5+XOmPQ0mTWKMWJrov8hlgurUnlrlpmYdJA9KRCavmvaW9pVJF8UbbhCPCc1AaGzFrnTq+6bje5I/GghpaZTq4Y/8TG5ckCXlCAC9OI2A57TKXXbehd8I= X-OriginatorOrg: axentia.se X-MS-Exchange-CrossTenant-OriginalArrivalTime: 20 Oct 2016 09:26:58.3870 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM5PR0201MB2308 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 11048 Lines: 384 The DAC is used to find the peak level of an alternating voltage input signal by a binary search using the output of a comparator wired to an interrupt pin. Like so: _ | \ input +------>-------|+ \ | \ .-------. | }---. | | | / | | dac|-->--|- / | | | |_/ | | | | | | | | irq|------<-------' | | '-------' Signed-off-by: Peter Rosin --- MAINTAINERS | 1 + drivers/iio/adc/Kconfig | 10 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/envelope-detector.c | 305 ++++++++++++++++++++++++++++++++++++ 4 files changed, 317 insertions(+) create mode 100644 drivers/iio/adc/envelope-detector.c diff --git a/MAINTAINERS b/MAINTAINERS index 4b6f6ec1b703..d9a58b5f2b6f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6123,6 +6123,7 @@ M: Peter Rosin L: linux-iio@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/iio/adc/envelope-detector.txt +F: drivers/iio/adc/envelope-detector.c IIO SUBSYSTEM AND DRIVERS M: Jonathan Cameron diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 7edcf3238620..d5c4a95855c2 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -195,6 +195,16 @@ config DA9150_GPADC To compile this driver as a module, choose M here: the module will be called berlin2-adc. +config ENVELOPE_DETECTOR + tristate "Envelope detector using a DAC and a comparator" + depends on OF + help + Say yes here to build support for an envelope detector using a DAC + and a comparator. + + To compile this driver as a module, choose M here: the module will be + called iio-envelope-detector. + config EXYNOS_ADC tristate "Exynos ADC driver support" depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST) diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 7a40c04c311f..0d773c6a0578 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_BCM_IPROC_ADC) += bcm_iproc_adc.o obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o +obj-$(CONFIG_ENVELOPE_DETECTOR) += envelope-detector.o obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o obj-$(CONFIG_FSL_MX25_ADC) += fsl-imx25-gcq.o obj-$(CONFIG_HI8435) += hi8435.o diff --git a/drivers/iio/adc/envelope-detector.c b/drivers/iio/adc/envelope-detector.c new file mode 100644 index 000000000000..837646107beb --- /dev/null +++ b/drivers/iio/adc/envelope-detector.c @@ -0,0 +1,305 @@ +/* + * Driver for an envelope detector using a DAC and a comparator + * + * Copyright (C) 2016 Axentia Technologies AB + * + * Author: Peter Rosin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * The DAC is used to find the peak level of an alternating voltage input + * signal by a binary search using the output of a comparator wired to + * an interrupt pin. Like so: + * _ + * | \ + * input +------>-------|+ \ + * | \ + * .-------. | }---. + * | | | / | + * | dac|-->--|- / | + * | | |_/ | + * | | | + * | | | + * | irq|------<-------' + * | | + * '-------' + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct envelope { + struct iio_channel *dac; + struct delayed_work comp_timeout; + int comp_irq; + + spinlock_t comp_lock; /* protects comp */ + int comp; + + struct mutex read_lock; /* protects everything below */ + + u32 dac_max; + u32 comp_interval; + bool invert; + + int high; + int level; + int low; + + struct completion done; +}; + +static int envelope_detector_latch(struct envelope *env) +{ + int comp; + + spin_lock_irq(&env->comp_lock); + comp = env->comp; + env->comp = 0; + spin_unlock_irq(&env->comp_lock); + + if (comp) + enable_irq(env->comp_irq); + + return comp; +} + +static irqreturn_t envelope_detector_isr(int irq, void *ctx) +{ + struct envelope *env = ctx; + + spin_lock(&env->comp_lock); + env->comp = 1; + disable_irq_nosync(env->comp_irq); + spin_unlock(&env->comp_lock); + + return IRQ_HANDLED; +} + +static void envelope_detector_setup_compare(struct envelope *env) +{ + int ret; + + /* + * Do a binary search for the peak input level, and stop + * when that level is "trapped" between two adjacent DAC + * values. + * When invert is active, use the midpoint floor so that + * env->level ends up as env->low when the termination + * criteria below is fulfilled, and use the midpoint + * ceiling when invert is not active so that env->level + * ends up as env->high in that case. + */ + env->level = (env->high + env->low + !env->invert) / 2; + + if (env->high == env->low + 1) { + complete(&env->done); + return; + } + + /* Set a "safe" DAC level (if there is such a thing)... */ + ret = iio_write_channel_raw(env->dac, env->invert ? 0 : env->dac_max); + if (ret < 0) + goto err; + + /* ...clear the comparison result... */ + envelope_detector_latch(env); + + /* ...set the real DAC level... */ + ret = iio_write_channel_raw(env->dac, env->level); + if (ret < 0) + goto err; + + /* ...and wait for a bit to see if the latch catches anything. */ + schedule_delayed_work(&env->comp_timeout, + msecs_to_jiffies(env->comp_interval)); + return; + +err: + env->level = ret; + complete(&env->done); +} + +static void envelope_detector_timeout(struct work_struct *work) +{ + struct envelope *env = container_of(work, struct envelope, + comp_timeout.work); + + /* Adjust low/high depending on the latch content... */ + if (!envelope_detector_latch(env) ^ !env->invert) + env->low = env->level; + else + env->high = env->level; + + /* ...and continue the search. */ + envelope_detector_setup_compare(env); +} + +static int envelope_detector_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct envelope *env = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + /* + * When invert is active, start with high=max+1 and low=0 + * since we will end up with the low value when the + * termination criteria is fulfilled (rounding down). And + * start with high=max and low=-1 when invert is not active + * since we will end up with the high value in that case. + * This ensures that we in both cases return a value in the + * same range as the DAC and that as not triggered the + * comparator. + */ + mutex_lock(&env->read_lock); + env->high = env->dac_max + 1 - !env->invert; + env->low = 0 - !env->invert; + envelope_detector_setup_compare(env); + wait_for_completion(&env->done); + if (env->level < 0) { + ret = env->level; + goto err_unlock; + } + *val = env->invert ? env->dac_max - env->level : env->level; + mutex_unlock(&env->read_lock); + + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + return iio_read_channel_scale(env->dac, val, val2); + } + + return -EINVAL; + +err_unlock: + mutex_unlock(&env->read_lock); + return ret; +} + +static const struct iio_chan_spec envelope_detector_iio_channel = { + .type = IIO_ALTVOLTAGE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) + | BIT(IIO_CHAN_INFO_SCALE), + .output = 1, +}; + +static const struct iio_info envelope_detector_info = { + .read_raw = &envelope_detector_read_raw, + .driver_module = THIS_MODULE, +}; + +static int envelope_detector_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct iio_dev *indio_dev; + struct envelope *env; + enum iio_chan_type type; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*env)); + if (!indio_dev) + return -ENOMEM; + + platform_set_drvdata(pdev, indio_dev); + env = iio_priv(indio_dev); + + spin_lock_init(&env->comp_lock); + mutex_init(&env->read_lock); + init_completion(&env->done); + INIT_DELAYED_WORK(&env->comp_timeout, envelope_detector_timeout); + + indio_dev->name = dev_name(dev); + indio_dev->dev.parent = dev; + indio_dev->dev.of_node = dev->of_node; + indio_dev->info = &envelope_detector_info; + indio_dev->channels = &envelope_detector_iio_channel; + indio_dev->num_channels = 1; + + env->dac = devm_iio_channel_get(dev, "dac"); + if (IS_ERR(env->dac)) { + if (PTR_ERR(env->dac) != -EPROBE_DEFER) + dev_err(dev, "failed to get dac input channel\n"); + return PTR_ERR(env->dac); + } + + env->comp_irq = platform_get_irq_byname(pdev, "comp"); + if (env->comp_irq < 0) { + if (env->comp_irq != -EPROBE_DEFER) + dev_err(dev, "failed to get compare interrupt\n"); + return env->comp_irq; + } + + ret = devm_request_irq(dev, env->comp_irq, envelope_detector_isr, 0, + "env-env-dac-comp", env); + if (ret) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to request interrupt\n"); + return ret; + } + + ret = iio_get_channel_type(env->dac, &type); + if (ret < 0) + return ret; + + if (type != IIO_VOLTAGE) { + dev_err(dev, "dac is of the wrong type\n"); + return -EINVAL; + } + + ret = of_property_read_u32(dev->of_node, "envelope-detector,dac-max", + &env->dac_max); + if (ret) { + dev_err(dev, "the dac-max property is missing\n"); + return ret; + } + + ret = of_property_read_u32(dev->of_node, + "envelope-detector,comp-interval-ms", + &env->comp_interval); + if (ret) { + dev_err(dev, "the comp-interval-ms property is missing\n"); + return ret; + } + + env->invert = of_property_read_bool(dev->of_node, + "envelope-detector,inverted"); + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct of_device_id envelope_detector_match[] = { + { .compatible = "envelope-detector" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, envelope_detector_match); + +static struct platform_driver envelope_detector_driver = { + .probe = envelope_detector_probe, + .driver = { + .name = "iio-envelope-detector", + .of_match_table = envelope_detector_match, + }, +}; +module_platform_driver(envelope_detector_driver); + +MODULE_DESCRIPTION("Envelope detector using a DAC and a comparator"); +MODULE_AUTHOR("Peter Rosin "); +MODULE_LICENSE("GPL v2"); -- 2.1.4