From patchwork Wed Aug 5 12:10:19 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sanchayan X-Patchwork-Id: 6948401 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 9EE419F39D for ; Wed, 5 Aug 2015 12:16:08 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 90BC620425 for ; Wed, 5 Aug 2015 12:16:07 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 7FDA5203A9 for ; Wed, 5 Aug 2015 12:16:06 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZMxaA-0001wj-2M; Wed, 05 Aug 2015 12:14:06 +0000 Received: from mail-wi0-x22d.google.com ([2a00:1450:400c:c05::22d]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1ZMxZz-0001pe-4y for linux-arm-kernel@lists.infradead.org; Wed, 05 Aug 2015 12:13:57 +0000 Received: by wibxm9 with SMTP id xm9so205745730wib.0 for ; Wed, 05 Aug 2015 05:13:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references; bh=UA/0b8b6StSvtALCnuAIy4ICg4EOXEjwyrpbupkNFgw=; b=qC57wCh5EuTb+EwKmaR7WHT6sdfqpN5FxF19vcCP1rkDgXLQil9xlfhVnxY4k/oCXN zmZa6HEJiYTXWfXh0xS9zmYDcUrEZeCiaWob4ZnHKVk/rlOUVZp8J2cLLn2lSViYWByE QidbS2Waj9uHSGhTLdtCZtz4446ykdowqwiHt03wWDXt5Pny4oxLGyl6zC2NCOqbaBkU 8bfbluhS0bh4JvmAHJcGGusCDPd58IRevO1MIfvxEPn//5aFGHvdkV4j2uIWUDN1g6aN zV6+Qb4n35GpdrgSZ1uP0lL9OBt4RslhnNBA6p2z9REfMmOoXrcjq6C9pLLsI6xQ4xBf lLCQ== X-Received: by 10.194.100.69 with SMTP id ew5mr10941377wjb.51.1438776812495; Wed, 05 Aug 2015 05:13:32 -0700 (PDT) Received: from localhost ([46.140.72.82]) by smtp.gmail.com with ESMTPSA id z5sm3820877wjr.42.2015.08.05.05.13.31 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 05 Aug 2015 05:13:31 -0700 (PDT) From: Sanchayan Maity To: jic23@kernel.org, linux-iio@vger.kernel.org Subject: [PATCH v2] iio: adc: vf610: Add IIO buffer support for Vybrid ADC Date: Wed, 5 Aug 2015 17:40:19 +0530 Message-Id: <1bb1f290da601bbda41875a92ba6e983b423d7b0.1438775572.git.maitysanchayan@gmail.com> X-Mailer: git-send-email 2.5.0 In-Reply-To: References: In-Reply-To: References: X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150805_051355_480610_22F67EB0 X-CRM114-Status: GOOD ( 20.67 ) X-Spam-Score: -2.7 (--) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: fabio.estevam@freescale.com, lars@metafoo.de, B38611@freescale.com, antoine.tenart@free-electrons.com, hofrat@osadl.org, linux-kernel@vger.kernel.org, stefan@agner.ch, Sanchayan Maity , pmeerw@pmeerw.net, knaack.h@gmx.de, sanjeev_sharma@mentor.com, linux-arm-kernel@lists.infradead.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds support for IIO buffer to the Vybrid ADC driver. IIO triggered buffer infrastructure along with iio sysfs trigger is used to leverage continuous sampling support provided by the ADC block. Signed-off-by: Sanchayan Maity --- drivers/iio/adc/Kconfig | 4 ++ drivers/iio/adc/vf610_adc.c | 107 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 105 insertions(+), 6 deletions(-) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 7c55658..4661241 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -337,6 +337,10 @@ config TWL6030_GPADC config VF610_ADC tristate "Freescale vf610 ADC driver" depends on OF + select IIO_BUFFER + select IIO_TRIGGER + select IIO_SYSFS_TRIGGER + select IIO_TRIGGERED_BUFFER help Say yes here to support for Vybrid board analog-to-digital converter. Since the IP is used for i.MX6SLX, the driver also support i.MX6SLX. diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index 23b8fb9..97cb2ed 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -34,8 +34,11 @@ #include #include +#include #include -#include +#include +#include +#include /* This will be the driver name the kernel reports */ #define DRIVER_NAME "vf610-adc" @@ -170,6 +173,7 @@ struct vf610_adc { u32 sample_freq_avail[5]; struct completion completion; + u16 buffer[2]; }; static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 }; @@ -505,12 +509,22 @@ static const struct iio_chan_spec_ext_info vf610_ext_info[] = { .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .ext_info = vf610_ext_info, \ + .address = (_idx), \ + .scan_index = (_idx), \ + .scan_type.sign = 'u', \ + .scan_type.realbits = 12, \ + .scan_type.storagebits = 16, \ } #define VF610_ADC_TEMPERATURE_CHAN(_idx, _chan_type) { \ .type = (_chan_type), \ .channel = (_idx), \ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \ + .address = (_idx), \ + .scan_index = (_idx), \ + .scan_type.sign = 'u', \ + .scan_type.realbits = 12, \ + .scan_type.storagebits = 16, \ } static const struct iio_chan_spec vf610_adc_iio_channels[] = { @@ -531,6 +545,7 @@ static const struct iio_chan_spec vf610_adc_iio_channels[] = { VF610_ADC_CHAN(14, IIO_VOLTAGE), VF610_ADC_CHAN(15, IIO_VOLTAGE), VF610_ADC_TEMPERATURE_CHAN(26, IIO_TEMP), + IIO_CHAN_SOFT_TIMESTAMP(32), /* sentinel */ }; @@ -559,13 +574,20 @@ static int vf610_adc_read_data(struct vf610_adc *info) static irqreturn_t vf610_adc_isr(int irq, void *dev_id) { - struct vf610_adc *info = (struct vf610_adc *)dev_id; + struct iio_dev *indio_dev = (struct iio_dev *)dev_id; + struct vf610_adc *info = iio_priv(indio_dev); int coco; coco = readl(info->regs + VF610_REG_ADC_HS); if (coco & VF610_ADC_HS_COCO0) { info->value = vf610_adc_read_data(info); - complete(&info->completion); + if (iio_buffer_enabled(indio_dev)) { + info->buffer[0] = info->value; + iio_push_to_buffers_with_timestamp(indio_dev, + info->buffer, iio_get_time_ns()); + iio_trigger_notify_done(indio_dev->trig); + } else + complete(&info->completion); } return IRQ_HANDLED; @@ -612,6 +634,9 @@ static int vf610_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_PROCESSED: + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; + mutex_lock(&indio_dev->mlock); reinit_completion(&info->completion); @@ -694,6 +719,68 @@ static int vf610_write_raw(struct iio_dev *indio_dev, return -EINVAL; } +static int vf610_adc_buffer_postenable(struct iio_dev *indio_dev) +{ + struct vf610_adc *info = iio_priv(indio_dev); + unsigned int channel; + int ret; + int val; + + ret = iio_triggered_buffer_postenable(indio_dev); + if (ret) + return ret; + + val = readl(info->regs + VF610_REG_ADC_GC); + val |= VF610_ADC_ADCON; + writel(val, info->regs + VF610_REG_ADC_GC); + + channel = find_first_bit(indio_dev->active_scan_mask, + indio_dev->masklength); + + val = VF610_ADC_ADCHC(channel); + val |= VF610_ADC_AIEN; + + writel(val, info->regs + VF610_REG_ADC_HC0); + + return 0; +} + +static int vf610_adc_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct vf610_adc *info = iio_priv(indio_dev); + unsigned int hc_cfg = 0; + int val; + + val = readl(info->regs + VF610_REG_ADC_GC); + val &= ~VF610_ADC_ADCON; + writel(val, info->regs + VF610_REG_ADC_GC); + + hc_cfg |= VF610_ADC_CONV_DISABLE; + hc_cfg &= ~VF610_ADC_AIEN; + + writel(hc_cfg, info->regs + VF610_REG_ADC_HC0); + + return 0; +} + +static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = { + .postenable = &vf610_adc_buffer_postenable, + .predisable = &iio_triggered_buffer_predisable, + .postdisable = &vf610_adc_buffer_postdisable, + .validate_scan_mask = &iio_validate_scan_mask_onehot, +}; + +static int vf610_adc_buffer_init(struct iio_dev *indio_dev) +{ + return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + NULL, &iio_triggered_buffer_setup_ops); +} + +static void vf610_adc_buffer_remove(struct iio_dev *indio_dev) +{ + iio_triggered_buffer_cleanup(indio_dev); +} + static int vf610_adc_reg_access(struct iio_dev *indio_dev, unsigned reg, unsigned writeval, unsigned *readval) @@ -753,7 +840,7 @@ static int vf610_adc_probe(struct platform_device *pdev) ret = devm_request_irq(info->dev, irq, vf610_adc_isr, 0, - dev_name(&pdev->dev), info); + dev_name(&pdev->dev), indio_dev); if (ret < 0) { dev_err(&pdev->dev, "failed requesting irq, irq = %d\n", irq); return ret; @@ -806,15 +893,22 @@ static int vf610_adc_probe(struct platform_device *pdev) vf610_adc_cfg_init(info); vf610_adc_hw_init(info); + ret = vf610_adc_buffer_init(indio_dev); + if (ret < 0) { + dev_err(&pdev->dev, "Couldn't initialise the buffer\n"); + goto error_iio_device_register; + } + ret = iio_device_register(indio_dev); if (ret) { dev_err(&pdev->dev, "Couldn't register the device.\n"); - goto error_iio_device_register; + goto error_adc_buffer_init; } return 0; - +error_adc_buffer_init: + vf610_adc_buffer_remove(indio_dev); error_iio_device_register: clk_disable_unprepare(info->clk); error_adc_clk_enable: @@ -829,6 +923,7 @@ static int vf610_adc_remove(struct platform_device *pdev) struct vf610_adc *info = iio_priv(indio_dev); iio_device_unregister(indio_dev); + vf610_adc_buffer_remove(indio_dev); regulator_disable(info->vref); clk_disable_unprepare(info->clk);