Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iio: dac: ad5791: Add offload support

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 <ahaslam@baylibre.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Nuno Sa <nuno.sa@analog.com>
Signed-off-by: David Lechner <dlechner@baylibre.com>
Link: https://patch.msgid.link/20250207-dlech-mainline-spi-engine-offload-2-v8-17-e48a489be48c@baylibre.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Axel Haslam and committed by
Jonathan Cameron
192b669b c91c294c

+166
+3
drivers/iio/dac/Kconfig
··· 296 296 config AD5791 297 297 tristate "Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC SPI driver" 298 298 depends on SPI 299 + select SPI_OFFLOAD 300 + select IIO_BUFFER 301 + select IIO_BUFFER_DMAENGINE 299 302 help 300 303 Say yes here to build support for Analog Devices AD5760, AD5780, 301 304 AD5781, AD5790, AD5791 High Resolution Voltage Output Digital to
+163
drivers/iio/dac/ad5791.c
··· 15 15 #include <linux/module.h> 16 16 #include <linux/regulator/consumer.h> 17 17 #include <linux/slab.h> 18 + #include <linux/spi/offload/consumer.h> 18 19 #include <linux/spi/spi.h> 19 20 #include <linux/sysfs.h> 21 + #include <linux/units.h> 20 22 23 + #include <linux/iio/buffer-dmaengine.h> 21 24 #include <linux/iio/dac/ad5791.h> 22 25 #include <linux/iio/iio.h> 23 26 #include <linux/iio/sysfs.h> ··· 67 64 * struct ad5791_chip_info - chip specific information 68 65 * @name: name of the dac chip 69 66 * @channel: channel specification 67 + * @channel_offload: channel specification for offload 70 68 * @get_lin_comp: function pointer to the device specific function 71 69 */ 72 70 struct ad5791_chip_info { 73 71 const char *name; 74 72 const struct iio_chan_spec channel; 73 + const struct iio_chan_spec channel_offload; 75 74 int (*get_lin_comp)(unsigned int span); 76 75 }; 77 76 ··· 86 81 * @gpio_clear: clear gpio 87 82 * @gpio_ldac: load dac gpio 88 83 * @chip_info: chip model specific constants 84 + * @offload_msg: spi message used for offload 85 + * @offload_xfer: spi transfer used for offload 86 + * @offload: offload device 87 + * @offload_trigger: offload trigger 88 + * @offload_trigger_hz: offload sample rate 89 89 * @vref_mv: actual reference voltage used 90 90 * @vref_neg_mv: voltage of the negative supply 91 91 * @ctrl: control register cache ··· 106 96 struct gpio_desc *gpio_clear; 107 97 struct gpio_desc *gpio_ldac; 108 98 const struct ad5791_chip_info *chip_info; 99 + struct spi_message offload_msg; 100 + struct spi_transfer offload_xfer; 101 + struct spi_offload *offload; 102 + struct spi_offload_trigger *offload_trigger; 103 + unsigned int offload_trigger_hz; 109 104 unsigned short vref_mv; 110 105 unsigned int vref_neg_mv; 111 106 unsigned ctrl; ··· 247 232 return AD5780_LINCOMP_10_20; 248 233 } 249 234 235 + static int ad5791_set_sample_freq(struct ad5791_state *st, int val) 236 + { 237 + struct spi_offload_trigger_config config = { 238 + .type = SPI_OFFLOAD_TRIGGER_PERIODIC, 239 + .periodic = { 240 + .frequency_hz = val, 241 + }, 242 + }; 243 + int ret; 244 + 245 + ret = spi_offload_trigger_validate(st->offload_trigger, &config); 246 + if (ret) 247 + return ret; 248 + 249 + st->offload_trigger_hz = config.periodic.frequency_hz; 250 + 251 + return 0; 252 + } 253 + 250 254 static int ad5791_read_raw(struct iio_dev *indio_dev, 251 255 struct iio_chan_spec const *chan, 252 256 int *val, ··· 292 258 val64 = (((u64)st->vref_neg_mv) << chan->scan_type.realbits); 293 259 do_div(val64, st->vref_mv); 294 260 *val = -val64; 261 + return IIO_VAL_INT; 262 + case IIO_CHAN_INFO_SAMP_FREQ: 263 + *val = st->offload_trigger_hz; 295 264 return IIO_VAL_INT; 296 265 default: 297 266 return -EINVAL; ··· 336 299 }, \ 337 300 .ext_info = ad5791_ext_info, \ 338 301 }, \ 302 + .channel_offload = { \ 303 + .type = IIO_VOLTAGE, \ 304 + .output = 1, \ 305 + .indexed = 1, \ 306 + .address = AD5791_ADDR_DAC0, \ 307 + .channel = 0, \ 308 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 309 + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ 310 + BIT(IIO_CHAN_INFO_OFFSET), \ 311 + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),\ 312 + .scan_type = { \ 313 + .sign = 'u', \ 314 + .realbits = (bits), \ 315 + .storagebits = 32, \ 316 + .shift = (_shift), \ 317 + }, \ 318 + .ext_info = ad5791_ext_info, \ 319 + }, \ 339 320 } 340 321 341 322 AD5791_DEFINE_CHIP_INFO(ad5760, 16, 4, ad5780_get_lin_comp); ··· 377 322 378 323 return ad5791_spi_write(st, chan->address, val); 379 324 325 + case IIO_CHAN_INFO_SAMP_FREQ: 326 + if (val < 1) 327 + return -EINVAL; 328 + return ad5791_set_sample_freq(st, val); 380 329 default: 381 330 return -EINVAL; 382 331 } 383 332 } 384 333 334 + static int ad5791_write_raw_get_fmt(struct iio_dev *indio_dev, 335 + struct iio_chan_spec const *chan, 336 + long mask) 337 + { 338 + switch (mask) { 339 + case IIO_CHAN_INFO_SAMP_FREQ: 340 + return IIO_VAL_INT; 341 + default: 342 + return IIO_VAL_INT_PLUS_MICRO; 343 + } 344 + } 345 + 346 + static int ad5791_buffer_preenable(struct iio_dev *indio_dev) 347 + { 348 + struct ad5791_state *st = iio_priv(indio_dev); 349 + struct spi_offload_trigger_config config = { 350 + .type = SPI_OFFLOAD_TRIGGER_PERIODIC, 351 + .periodic = { 352 + .frequency_hz = st->offload_trigger_hz, 353 + }, 354 + }; 355 + 356 + if (st->pwr_down) 357 + return -EINVAL; 358 + 359 + return spi_offload_trigger_enable(st->offload, st->offload_trigger, 360 + &config); 361 + } 362 + 363 + static int ad5791_buffer_postdisable(struct iio_dev *indio_dev) 364 + { 365 + struct ad5791_state *st = iio_priv(indio_dev); 366 + 367 + spi_offload_trigger_disable(st->offload, st->offload_trigger); 368 + 369 + return 0; 370 + } 371 + 372 + static const struct iio_buffer_setup_ops ad5791_buffer_setup_ops = { 373 + .preenable = &ad5791_buffer_preenable, 374 + .postdisable = &ad5791_buffer_postdisable, 375 + }; 376 + 377 + static int ad5791_offload_setup(struct iio_dev *indio_dev) 378 + { 379 + struct ad5791_state *st = iio_priv(indio_dev); 380 + struct spi_device *spi = st->spi; 381 + struct dma_chan *tx_dma; 382 + int ret; 383 + 384 + st->offload_trigger = devm_spi_offload_trigger_get(&spi->dev, 385 + st->offload, SPI_OFFLOAD_TRIGGER_PERIODIC); 386 + if (IS_ERR(st->offload_trigger)) 387 + return dev_err_probe(&spi->dev, PTR_ERR(st->offload_trigger), 388 + "failed to get offload trigger\n"); 389 + 390 + ret = ad5791_set_sample_freq(st, 1 * MEGA); 391 + if (ret) 392 + return dev_err_probe(&spi->dev, ret, 393 + "failed to init sample rate\n"); 394 + 395 + tx_dma = devm_spi_offload_tx_stream_request_dma_chan(&spi->dev, 396 + st->offload); 397 + if (IS_ERR(tx_dma)) 398 + return dev_err_probe(&spi->dev, PTR_ERR(tx_dma), 399 + "failed to get offload TX DMA\n"); 400 + 401 + ret = devm_iio_dmaengine_buffer_setup_with_handle(&spi->dev, 402 + indio_dev, tx_dma, IIO_BUFFER_DIRECTION_OUT); 403 + if (ret) 404 + return ret; 405 + 406 + st->offload_xfer.len = 4; 407 + st->offload_xfer.bits_per_word = 24; 408 + st->offload_xfer.offload_flags = SPI_OFFLOAD_XFER_TX_STREAM; 409 + 410 + spi_message_init_with_transfers(&st->offload_msg, &st->offload_xfer, 1); 411 + st->offload_msg.offload = st->offload; 412 + 413 + return devm_spi_optimize_message(&spi->dev, st->spi, &st->offload_msg); 414 + } 415 + 385 416 static const struct iio_info ad5791_info = { 386 417 .read_raw = &ad5791_read_raw, 387 418 .write_raw = &ad5791_write_raw, 419 + .write_raw_get_fmt = &ad5791_write_raw_get_fmt, 420 + }; 421 + 422 + static const struct spi_offload_config ad5791_offload_config = { 423 + .capability_flags = SPI_OFFLOAD_CAP_TRIGGER | 424 + SPI_OFFLOAD_CAP_TX_STREAM_DMA, 388 425 }; 389 426 390 427 static int ad5791_probe(struct spi_device *spi) ··· 563 416 indio_dev->channels = &st->chip_info->channel; 564 417 indio_dev->num_channels = 1; 565 418 indio_dev->name = st->chip_info->name; 419 + 420 + st->offload = devm_spi_offload_get(&spi->dev, spi, &ad5791_offload_config); 421 + ret = PTR_ERR_OR_ZERO(st->offload); 422 + if (ret && ret != -ENODEV) 423 + return dev_err_probe(&spi->dev, ret, "failed to get offload\n"); 424 + 425 + if (ret != -ENODEV) { 426 + indio_dev->channels = &st->chip_info->channel_offload; 427 + indio_dev->setup_ops = &ad5791_buffer_setup_ops; 428 + ret = ad5791_offload_setup(indio_dev); 429 + if (ret) 430 + return dev_err_probe(&spi->dev, ret, 431 + "fail to setup offload\n"); 432 + } 433 + 566 434 return devm_iio_device_register(&spi->dev, indio_dev); 567 435 } 568 436 ··· 614 452 MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); 615 453 MODULE_DESCRIPTION("Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC"); 616 454 MODULE_LICENSE("GPL v2"); 455 + MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER");