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

Configure Feed

Select the types of activity you want to include in your feed.

iio: adc: ad_sigma_delta: use spi_optimize_message()

Use spi_optimize_message() to improve the performance of buffered reads.

By setting up the SPI message and pre-optimizing it in the buffer
postenable callback, we can reduce overhead during each sample read.

A rough estimate shows that this reduced the CPU usage of the interrupt
handler thread from 22% to 16% using an EVAL-AD4112ARDZ board on a
DE10-Nano (measuring a single channel at the default 6.2 kHz sample
rate).

Signed-off-by: David Lechner <dlechner@baylibre.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Nuno Sá <nuno.sa@analog.com>
Link: https://patch.msgid.link/20250701-iio-adc-ad7173-add-spi-offload-support-v3-8-42abb83e3dac@baylibre.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

David Lechner and committed by
Jonathan Cameron
db63e45a 1519bedf

+37 -38
+34 -38
drivers/iio/adc/ad_sigma_delta.c
··· 466 466 { 467 467 struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); 468 468 const struct iio_scan_type *scan_type = &indio_dev->channels[0].scan_type; 469 + struct spi_transfer *xfer = sigma_delta->sample_xfer; 469 470 unsigned int i, slot, samples_buf_size; 470 - unsigned int channel; 471 + unsigned int channel, scan_size; 471 472 u8 *samples_buf; 472 473 int ret; 473 474 ··· 511 510 return -ENOMEM; 512 511 513 512 sigma_delta->samples_buf = samples_buf; 513 + scan_size = BITS_TO_BYTES(scan_type->realbits + scan_type->shift); 514 + /* For 24-bit data, there is an extra byte of padding. */ 515 + xfer[1].rx_buf = &sigma_delta->rx_buf[scan_size == 3 ? 1 : 0]; 516 + xfer[1].len = scan_size + (sigma_delta->status_appended ? 1 : 0); 517 + xfer[1].cs_change = 1; 518 + 519 + if (sigma_delta->info->has_registers) { 520 + xfer[0].tx_buf = &sigma_delta->sample_addr; 521 + xfer[0].len = 1; 522 + 523 + ad_sd_set_read_reg_addr(sigma_delta, 524 + sigma_delta->info->data_reg ?: AD_SD_REG_DATA, 525 + &sigma_delta->sample_addr); 526 + spi_message_init_with_transfers(&sigma_delta->sample_msg, xfer, 2); 527 + } else { 528 + spi_message_init_with_transfers(&sigma_delta->sample_msg, 529 + &xfer[1], 1); 530 + } 531 + 532 + ret = spi_optimize_message(sigma_delta->spi, &sigma_delta->sample_msg); 533 + if (ret) 534 + return ret; 514 535 515 536 spi_bus_lock(sigma_delta->spi->controller); 516 537 sigma_delta->bus_locked = true; ··· 552 529 553 530 err_unlock: 554 531 spi_bus_unlock(sigma_delta->spi->controller); 532 + spi_unoptimize_message(&sigma_delta->sample_msg); 555 533 556 534 return ret; 557 535 } ··· 574 550 575 551 ad_sigma_delta_disable_all(sigma_delta); 576 552 sigma_delta->bus_locked = false; 577 - return spi_bus_unlock(sigma_delta->spi->controller); 553 + spi_bus_unlock(sigma_delta->spi->controller); 554 + spi_unoptimize_message(&sigma_delta->sample_msg); 555 + 556 + return 0; 578 557 } 579 558 580 559 static irqreturn_t ad_sd_trigger_handler(int irq, void *p) ··· 587 560 const struct iio_scan_type *scan_type = &indio_dev->channels[0].scan_type; 588 561 struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); 589 562 u8 *data = sigma_delta->rx_buf; 590 - unsigned int transfer_size; 591 563 unsigned int sample_size; 592 564 unsigned int sample_pos; 593 565 unsigned int status_pos; 594 566 unsigned int reg_size; 595 - unsigned int data_reg; 567 + int ret; 596 568 597 569 reg_size = BITS_TO_BYTES(scan_type->realbits + scan_type->shift); 570 + /* For 24-bit data, there is an extra byte of padding. */ 571 + status_pos = reg_size + (reg_size == 3 ? 1 : 0); 598 572 599 - if (sigma_delta->info->data_reg != 0) 600 - data_reg = sigma_delta->info->data_reg; 601 - else 602 - data_reg = AD_SD_REG_DATA; 603 - 604 - /* Status word will be appended to the sample during transfer */ 605 - if (sigma_delta->status_appended) 606 - transfer_size = reg_size + 1; 607 - else 608 - transfer_size = reg_size; 609 - 610 - switch (reg_size) { 611 - case 4: 612 - case 2: 613 - case 1: 614 - status_pos = reg_size; 615 - ad_sd_read_reg_raw(sigma_delta, data_reg, transfer_size, &data[0]); 616 - break; 617 - case 3: 618 - /* 619 - * Data array after transfer will look like (if status is appended): 620 - * data[] = { [0][sample][sample][sample][status] } 621 - * Keeping the first byte 0 shifts the status position by 1 byte to the right. 622 - */ 623 - status_pos = reg_size + 1; 624 - 625 - /* We store 24 bit samples in a 32 bit word. Keep the upper 626 - * byte set to zero. */ 627 - ad_sd_read_reg_raw(sigma_delta, data_reg, transfer_size, &data[1]); 628 - break; 629 - 630 - default: 631 - dev_err_ratelimited(&indio_dev->dev, "Unsupported reg_size: %u\n", reg_size); 573 + ret = spi_sync_locked(sigma_delta->spi, &sigma_delta->sample_msg); 574 + if (ret) 632 575 goto irq_handled; 633 - } 634 576 635 577 /* 636 578 * For devices sampling only one channel at
+3
include/linux/iio/adc/ad_sigma_delta.h
··· 105 105 bool status_appended; 106 106 /* map slots to channels in order to know what to expect from devices */ 107 107 unsigned int *slots; 108 + struct spi_message sample_msg; 109 + struct spi_transfer sample_xfer[2]; 108 110 u8 *samples_buf; 109 111 110 112 /* ··· 118 116 */ 119 117 u8 tx_buf[4] __aligned(IIO_DMA_MINALIGN); 120 118 u8 rx_buf[16] __aligned(8); 119 + u8 sample_addr; 121 120 }; 122 121 123 122 static inline int ad_sigma_delta_set_channel(struct ad_sigma_delta *sd,