From patchwork Wed Dec 11 20:54:54 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Lechner X-Patchwork-Id: 13904165 Received: from mail-ot1-f49.google.com (mail-ot1-f49.google.com [209.85.210.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0534823A1A5 for ; Wed, 11 Dec 2024 20:55:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733950533; cv=none; b=ABzvC47mZ+6tGLuDv5SlrwqRy2/yw2XF/jeFciZutwtoGSizx69P0Ji5mkd9a0YBXKLgztfJ7h/pJ4XPDjWG0dXp9Wugcr4GaPP8/HUSWTmlfn7y1yv6sp/2p21iUbnvLpVLHglEZYG0PJoDU/5BmY/vg2ByLUPgEJxCJeJi0vo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733950533; c=relaxed/simple; bh=OzAu1y/H3v98Oh+obJXz2LVpGi8e3bYBOTQLvfGilLE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=TdwY38UcggoixbXGwt0M+0FbJ/46TXzBwUgkuVI9ecYPpTKc74wzuRqu5lema+wLt84wCnGk9nCSIQDD7eo4yNaQZIwZOnVG9ti2kmRtDYSSCMEKDih8jg9z6RvRBqrf4q5Oj/2hXlxTIY/hrdyW+P2mwRaf4G+a3SvN37DafTY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com; spf=pass smtp.mailfrom=baylibre.com; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b=bMSwM9xH; arc=none smtp.client-ip=209.85.210.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=baylibre.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=baylibre-com.20230601.gappssmtp.com header.i=@baylibre-com.20230601.gappssmtp.com header.b="bMSwM9xH" Received: by mail-ot1-f49.google.com with SMTP id 46e09a7af769-71e0351311eso726301a34.1 for ; Wed, 11 Dec 2024 12:55:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1733950530; x=1734555330; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=UIG6sINpyGyOIxw92FCk6jPcVNBP3Duj2CqVoFPTTHM=; b=bMSwM9xHzsq1QkBxECtKTZYr3usMseHCs9OeG4rs3pLB5gUTPv6CuFBuijIvI48Twd bhbblW5ui+wmAHA5TWSOz1iBQ//Yk4fOO9VBrKWJdS6lpCZ8tCxGc70CvU1MAjSuGDJv nywyZbydRprQbq560XJW+/6YHA22Swn8+FzVsLOE4JhE7kWlNafbOCTDvcCdMCluw+nF AjsLdJugpDHohNlv07Xs4XIrz2lLoOqxO+iPPIqchcKSpHifi4ZwhjUeZIRE4Ibs2OkK v/f41Bxdn17PoeFsZqNEe9uFbsorCT9GZ4oswLaLsecHqPNwr4eAYLYOCwAY7C10DFoL f/4Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733950530; x=1734555330; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=UIG6sINpyGyOIxw92FCk6jPcVNBP3Duj2CqVoFPTTHM=; b=PBVDEViNnb4vKzc0PyVMoGmyKsW6O/lihwh1QinzIV/GK8TyOuQ8sgF1H+16EwLYS3 ZCzPyyKeNI9D8JqnWQppGtgu0vIs3mSfgjKe36Y+HFdTYnAz3511Rz8aTvfpU1qJicm1 s8kXQqMtRjL83BlsmYcvbV1Av1theX1q52/y+vaeewZ3VhGBAUzl6vkW7kYfsn4Qu0Fn InFPmT4W8+uNPIsNs23Df8XI5uFwu1rJoAloagEwVlIZ2TFjg+jkoBUKBfyk9GLud2kl P6azZO9GIO7SXHI2YuKEL0PcSC4K2N5AS46EWbBsjcHPum7RcTUNy6PKv6mb6VgWn+rV Wcfw== X-Forwarded-Encrypted: i=1; AJvYcCWEPGqQF+GdyakDRBcN9tYjxX/VFy5wYL/1MYcxtKud06GCm9tqkx6JrSu9svr0QrieiMD0H1DaUOY=@vger.kernel.org X-Gm-Message-State: AOJu0YwZqi+HYuMBMUg03vKmHgaIwSBr0i5vsF7X/eDt/ZasSn9P1+Af HYd2ndEK7V6qCOwzl6B/FKYHnbENbozXM/fR4/nN19Lp5bVufkJw5D+0XKpvULQ= X-Gm-Gg: ASbGnctwwb9Ixu1t4AleWoINnLNeSPYyWsjd4bNyMmHxR1Pb/NgzwoiO1/VpZ/FmLpX iuaAfvLwFQj41XHWuDKhMErxwvGJ35hVxF+vf7G2OP2V84MgI2M1qd8hgqs2lb8oDxVTfhxK4u9 UbkuOA0jjplbta2tCloFO6sjOUqcV7C10L6+1gRwlgRs6DLJWyCwfbvTxh/uDNyEJagZlimum+r g/8nPMfUpX6shwuimngU/stZNb+JXTy+z+f4L6JvMAGNW3bSvKj5XQ3aUe0cittbjidi/B5bEdr qwqPVXR7fw== X-Google-Smtp-Source: AGHT+IEFT/scxcmkfgIOkKvLV+l02WCW6R4Q/Nhv22dR9dP0pLo0cFMOt9o0Fzd4itbazmNHYYYouQ== X-Received: by 2002:a05:6830:438d:b0:718:6da0:72b with SMTP id 46e09a7af769-71e29baca4emr609402a34.7.1733950530105; Wed, 11 Dec 2024 12:55:30 -0800 (PST) Received: from [127.0.1.1] (ip98-183-112-25.ok.ok.cox.net. [98.183.112.25]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-71def651fb2sm1888288a34.27.2024.12.11.12.55.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Dec 2024 12:55:29 -0800 (PST) From: David Lechner Date: Wed, 11 Dec 2024 14:54:54 -0600 Subject: [PATCH v6 17/17] iio: dac: ad5791: Add offload support Precedence: bulk X-Mailing-List: linux-iio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241211-dlech-mainline-spi-engine-offload-2-v6-17-88ee574d5d03@baylibre.com> References: <20241211-dlech-mainline-spi-engine-offload-2-v6-0-88ee574d5d03@baylibre.com> In-Reply-To: <20241211-dlech-mainline-spi-engine-offload-2-v6-0-88ee574d5d03@baylibre.com> To: Mark Brown , Jonathan Cameron , Rob Herring , Krzysztof Kozlowski , Conor Dooley , =?utf-8?q?Nuno_S=C3=A1?= Cc: =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Michael Hennerich , Lars-Peter Clausen , David Jander , Martin Sperl , linux-spi@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-iio@vger.kernel.org, linux-pwm@vger.kernel.org, Axel Haslam , David Lechner X-Mailer: b4 0.14.2 From: Axel Haslam Add SPI offload support to stream TX buffers using DMA. This allows loading samples to the DAC with a rate of 1 MSPS. Signed-off-by: Axel Haslam Signed-off-by: David Lechner Reviewed-by: Jonathan Cameron Reviewed-by: Nuno Sa --- v6 changes: new patch in v6 --- drivers/iio/dac/Kconfig | 3 + drivers/iio/dac/ad5791.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 4cde34e8c8e3356aa41bcd2cba38d67d5c6f8049..f6c5cb632acbdc2432f60b163452bb0c5f89fa72 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -296,6 +296,9 @@ config AD5770R config AD5791 tristate "Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC SPI driver" depends on SPI + select SPI_OFFLOAD + select IIO_BUFFER + select IIO_BUFFER_DMAENGINE help Say yes here to build support for Analog Devices AD5760, AD5780, AD5781, AD5790, AD5791 High Resolution Voltage Output Digital to diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c index 24462cb020e19e8e2c6faa13109ac047cf423c37..a2953a9a4e5d5bc17c9c4a8281be4b41b1af5de8 100644 --- a/drivers/iio/dac/ad5791.c +++ b/drivers/iio/dac/ad5791.c @@ -15,9 +15,12 @@ #include #include #include +#include #include #include +#include +#include #include #include #include @@ -64,11 +67,13 @@ * struct ad5791_chip_info - chip specific information * @name: name of the dac chip * @channel: channel specification + * @channel_offload: channel specification for offload * @get_lin_comp: function pointer to the device specific function */ struct ad5791_chip_info { const char *name; const struct iio_chan_spec channel; + const struct iio_chan_spec channel_offload; int (*get_lin_comp)(unsigned int span); }; @@ -81,6 +86,11 @@ struct ad5791_chip_info { * @gpio_clear: clear gpio * @gpio_ldac: load dac gpio * @chip_info: chip model specific constants + * @offload_msg: spi message used for offload + * @offload_xfer: spi transfer used for offload + * @offload: offload device + * @offload_trigger: offload trigger + * @offload_trigger_hz: offload sample rate * @vref_mv: actual reference voltage used * @vref_neg_mv: voltage of the negative supply * @ctrl: control register cache @@ -96,6 +106,11 @@ struct ad5791_state { struct gpio_desc *gpio_clear; struct gpio_desc *gpio_ldac; const struct ad5791_chip_info *chip_info; + struct spi_message offload_msg; + struct spi_transfer offload_xfer; + struct spi_offload *offload; + struct spi_offload_trigger *offload_trigger; + unsigned int offload_trigger_hz; unsigned short vref_mv; unsigned int vref_neg_mv; unsigned ctrl; @@ -232,6 +247,25 @@ static int ad5780_get_lin_comp(unsigned int span) return AD5780_LINCOMP_10_20; } +static int ad5791_set_sample_freq(struct ad5791_state *st, int val) +{ + struct spi_offload_trigger_config config = { + .type = SPI_OFFLOAD_TRIGGER_PERIODIC, + .periodic = { + .frequency_hz = val, + }, + }; + int ret; + + ret = spi_offload_trigger_validate(st->offload_trigger, &config); + if (ret) + return ret; + + st->offload_trigger_hz = config.periodic.frequency_hz; + + return 0; +} + static int ad5791_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, @@ -259,6 +293,9 @@ static int ad5791_read_raw(struct iio_dev *indio_dev, do_div(val64, st->vref_mv); *val = -val64; return IIO_VAL_INT; + case IIO_CHAN_INFO_SAMP_FREQ: + *val = st->offload_trigger_hz; + return IIO_VAL_INT; default: return -EINVAL; } @@ -299,6 +336,24 @@ static const struct ad5791_chip_info _name##_chip_info = { \ }, \ .ext_info = ad5791_ext_info, \ }, \ + .channel_offload = { \ + .type = IIO_VOLTAGE, \ + .output = 1, \ + .indexed = 1, \ + .address = AD5791_ADDR_DAC0, \ + .channel = 0, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ + .scan_type = { \ + .sign = 'u', \ + .realbits = (bits), \ + .storagebits = 32, \ + .shift = (_shift), \ + }, \ + .ext_info = ad5791_ext_info, \ + }, \ } AD5791_DEFINE_CHIP_INFO(ad5760, 16, 4, ad5780_get_lin_comp); @@ -322,16 +377,95 @@ static int ad5791_write_raw(struct iio_dev *indio_dev, return ad5791_spi_write(st, chan->address, val); + case IIO_CHAN_INFO_SAMP_FREQ: + if (val < 0 || val2 < 0) + return -EINVAL; + return ad5791_set_sample_freq(st, val); default: return -EINVAL; } } +static int ad5791_buffer_preenable(struct iio_dev *indio_dev) +{ + struct ad5791_state *st = iio_priv(indio_dev); + struct spi_offload_trigger_config config = { + .type = SPI_OFFLOAD_TRIGGER_PERIODIC, + .periodic = { + .frequency_hz = st->offload_trigger_hz, + }, + }; + + if (st->pwr_down) + return -EINVAL; + + return spi_offload_trigger_enable(st->offload, st->offload_trigger, + &config); +} + +static int ad5791_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ad5791_state *st = iio_priv(indio_dev); + + spi_offload_trigger_disable(st->offload, st->offload_trigger); + + return 0; +} + +static const struct iio_buffer_setup_ops ad5791_buffer_setup_ops = { + .preenable = &ad5791_buffer_preenable, + .postdisable = &ad5791_buffer_postdisable, +}; + +static int ad5791_offload_setup(struct iio_dev *indio_dev) +{ + struct ad5791_state *st = iio_priv(indio_dev); + struct spi_device *spi = st->spi; + struct dma_chan *tx_dma; + int ret; + + st->offload_trigger = devm_spi_offload_trigger_get(&spi->dev, + st->offload, SPI_OFFLOAD_TRIGGER_PERIODIC); + if (IS_ERR(st->offload_trigger)) + return dev_err_probe(&spi->dev, PTR_ERR(st->offload_trigger), + "failed to get offload trigger\n"); + + ret = ad5791_set_sample_freq(st, 1 * MEGA); + if (ret) + return dev_err_probe(&spi->dev, ret, + "failed to init sample rate\n"); + + tx_dma = devm_spi_offload_tx_stream_request_dma_chan(&spi->dev, + st->offload); + if (IS_ERR(tx_dma)) + return dev_err_probe(&spi->dev, PTR_ERR(tx_dma), + "failed to get offload TX DMA\n"); + + ret = devm_iio_dmaengine_buffer_setup_with_handle(&spi->dev, + indio_dev, tx_dma, IIO_BUFFER_DIRECTION_OUT); + if (ret) + return ret; + + st->offload_xfer.len = 4; + st->offload_xfer.bits_per_word = 24; + st->offload_xfer.offload_flags = SPI_OFFLOAD_XFER_TX_STREAM; + + spi_message_init_with_transfers(&st->offload_msg, &st->offload_xfer, 1); + st->offload_msg.offload = st->offload; + + return devm_spi_optimize_message(&spi->dev, st->spi, &st->offload_msg); +} + static const struct iio_info ad5791_info = { .read_raw = &ad5791_read_raw, .write_raw = &ad5791_write_raw, }; +static const struct spi_offload_config ad5791_offload_config = { + .capability_flags = SPI_OFFLOAD_CAP_TRIGGER | + SPI_OFFLOAD_CAP_TX_STREAM_DMA, +}; + static int ad5791_probe(struct spi_device *spi) { const struct ad5791_platform_data *pdata = dev_get_platdata(&spi->dev); @@ -416,6 +550,21 @@ static int ad5791_probe(struct spi_device *spi) indio_dev->channels = &st->chip_info->channel; indio_dev->num_channels = 1; indio_dev->name = st->chip_info->name; + + st->offload = devm_spi_offload_get(&spi->dev, spi, &ad5791_offload_config); + ret = PTR_ERR_OR_ZERO(st->offload); + if (ret && ret != -ENODEV) + return dev_err_probe(&spi->dev, ret, "failed to get offload\n"); + + if (ret != -ENODEV) { + indio_dev->channels = &st->chip_info->channel_offload; + indio_dev->setup_ops = &ad5791_buffer_setup_ops; + ret = ad5791_offload_setup(indio_dev); + if (ret) + return dev_err_probe(&spi->dev, ret, + "fail to setup offload\n"); + } + return devm_iio_device_register(&spi->dev, indio_dev); } @@ -452,3 +601,4 @@ module_spi_driver(ad5791_driver); MODULE_AUTHOR("Michael Hennerich "); MODULE_DESCRIPTION("Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER");