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: accel: adxl313: add buffered FIFO watermark with interrupt handling

Cover the following tasks:
- Add scan_mask and scan_index to the IIO channel configuration. The
scan_index sets up buffer usage. According to the datasheet, the ADXL313
uses a 13-bit wide data field in full-resolution mode. Set the
signedness, number of storage bits, and endianness accordingly.

- Parse the devicetree for an optional interrupt line and configure the
interrupt mapping based on its presence. If no interrupt line is
specified, keep the FIFO in bypass mode as currently implemented.

- Set up the interrupt handler. Add register access to detect and
evaluate interrupts. Implement functions to clear status registers and
reset the FIFO.

- Implement FIFO watermark configuration and handling. Allow the
watermark level to be set, evaluate the corresponding interrupt, read
the FIFO contents, and push the data to the IIO channel.

Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://patch.msgid.link/20250702230819.19353-4-l.rubusch@gmail.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Lothar Rubusch and committed by
Jonathan Cameron
ff8093fa a1576623

+280 -6
+22
drivers/iio/accel/adxl313.h
··· 21 21 #define ADXL313_REG_ACT_INACT_CTL 0x27 22 22 #define ADXL313_REG_BW_RATE 0x2C 23 23 #define ADXL313_REG_POWER_CTL 0x2D 24 + #define ADXL313_REG_INT_ENABLE 0x2E 24 25 #define ADXL313_REG_INT_MAP 0x2F 25 26 #define ADXL313_REG_INT_SOURCE 0x30 26 27 #define ADXL313_REG_DATA_FORMAT 0x31 ··· 47 46 #define ADXL313_SPI_3WIRE BIT(6) 48 47 #define ADXL313_I2C_DISABLE BIT(6) 49 48 49 + #define ADXL313_INT_OVERRUN BIT(0) 50 + #define ADXL313_INT_WATERMARK BIT(1) 51 + #define ADXL313_INT_INACTIVITY BIT(3) 52 + #define ADXL313_INT_ACTIVITY BIT(4) 53 + #define ADXL313_INT_DREADY BIT(7) 54 + 55 + /* FIFO entries: how many values are stored in the FIFO */ 56 + #define ADXL313_REG_FIFO_STATUS_ENTRIES_MSK GENMASK(5, 0) 57 + /* FIFO samples: number of samples needed for watermark (FIFO mode) */ 58 + #define ADXL313_REG_FIFO_CTL_SAMPLES_MSK GENMASK(4, 0) 59 + #define ADXL313_REG_FIFO_CTL_MODE_MSK GENMASK(7, 6) 60 + 61 + #define ADXL313_FIFO_BYPASS 0 62 + #define ADXL313_FIFO_STREAM 2 63 + 64 + #define ADXL313_FIFO_SIZE 32 65 + 66 + #define ADXL313_NUM_AXIS 3 67 + 50 68 extern const struct regmap_access_table adxl312_readable_regs_table; 51 69 extern const struct regmap_access_table adxl313_readable_regs_table; 52 70 extern const struct regmap_access_table adxl314_readable_regs_table; ··· 86 66 struct regmap *regmap; 87 67 const struct adxl313_chip_info *chip_info; 88 68 struct mutex lock; /* lock to protect transf_buf */ 69 + u8 watermark; 89 70 __le16 transf_buf __aligned(IIO_DMA_MINALIGN); 71 + __le16 fifo_buf[ADXL313_NUM_AXIS * ADXL313_FIFO_SIZE + 1]; 90 72 }; 91 73 92 74 struct adxl313_chip_info {
+258 -6
drivers/iio/accel/adxl313_core.c
··· 8 8 */ 9 9 10 10 #include <linux/bitfield.h> 11 + #include <linux/interrupt.h> 11 12 #include <linux/module.h> 13 + #include <linux/overflow.h> 14 + #include <linux/property.h> 12 15 #include <linux/regmap.h> 13 16 17 + #include <linux/iio/buffer.h> 18 + #include <linux/iio/kfifo_buf.h> 19 + 14 20 #include "adxl313.h" 21 + 22 + #define ADXL313_INT_NONE U8_MAX 23 + #define ADXL313_INT1 1 24 + #define ADXL313_INT2 2 25 + 26 + #define ADXL313_REG_XYZ_BASE ADXL313_REG_DATA_AXIS(0) 15 27 16 28 static const struct regmap_range adxl312_readable_reg_range[] = { 17 29 regmap_reg_range(ADXL313_REG_DEVID0, ADXL313_REG_DEVID0), ··· 207 195 [9] = { 3200, 0 }, 208 196 }; 209 197 210 - #define ADXL313_ACCEL_CHANNEL(index, axis) { \ 198 + #define ADXL313_ACCEL_CHANNEL(index, reg, axis) { \ 211 199 .type = IIO_ACCEL, \ 212 - .address = index, \ 200 + .scan_index = (index), \ 201 + .address = (reg), \ 213 202 .modified = 1, \ 214 203 .channel2 = IIO_MOD_##axis, \ 215 204 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ ··· 220 207 .info_mask_shared_by_type_available = \ 221 208 BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 222 209 .scan_type = { \ 210 + .sign = 's', \ 223 211 .realbits = 13, \ 212 + .storagebits = 16, \ 213 + .endianness = IIO_BE, \ 224 214 }, \ 225 215 } 226 216 217 + enum adxl313_chans { 218 + chan_x, chan_y, chan_z, 219 + }; 220 + 227 221 static const struct iio_chan_spec adxl313_channels[] = { 228 - ADXL313_ACCEL_CHANNEL(0, X), 229 - ADXL313_ACCEL_CHANNEL(1, Y), 230 - ADXL313_ACCEL_CHANNEL(2, Z), 222 + ADXL313_ACCEL_CHANNEL(0, chan_x, X), 223 + ADXL313_ACCEL_CHANNEL(1, chan_y, Y), 224 + ADXL313_ACCEL_CHANNEL(2, chan_z, Z), 225 + }; 226 + 227 + static const unsigned long adxl313_scan_masks[] = { 228 + BIT(chan_x) | BIT(chan_y) | BIT(chan_z), 229 + 0 231 230 }; 232 231 233 232 static int adxl313_set_odr(struct adxl313_data *data, ··· 370 345 } 371 346 } 372 347 348 + static int adxl313_set_watermark(struct iio_dev *indio_dev, unsigned int value) 349 + { 350 + struct adxl313_data *data = iio_priv(indio_dev); 351 + int ret; 352 + 353 + value = min(value, ADXL313_FIFO_SIZE - 1); 354 + 355 + ret = adxl313_set_measure_en(data, false); 356 + if (ret) 357 + return ret; 358 + 359 + ret = regmap_update_bits(data->regmap, ADXL313_REG_FIFO_CTL, 360 + ADXL313_REG_FIFO_CTL_MODE_MSK, value); 361 + if (ret) 362 + return ret; 363 + 364 + data->watermark = value; 365 + 366 + ret = regmap_set_bits(data->regmap, ADXL313_REG_INT_ENABLE, 367 + ADXL313_INT_WATERMARK); 368 + if (ret) 369 + return ret; 370 + 371 + return adxl313_set_measure_en(data, true); 372 + } 373 + 374 + static int adxl313_get_samples(struct adxl313_data *data) 375 + { 376 + unsigned int regval; 377 + int ret; 378 + 379 + ret = regmap_read(data->regmap, ADXL313_REG_FIFO_STATUS, &regval); 380 + if (ret) 381 + return ret; 382 + 383 + return FIELD_GET(ADXL313_REG_FIFO_STATUS_ENTRIES_MSK, regval); 384 + } 385 + 386 + static int adxl313_fifo_transfer(struct adxl313_data *data, int samples) 387 + { 388 + unsigned int i; 389 + int ret; 390 + 391 + for (i = 0; i < samples; i++) { 392 + ret = regmap_bulk_read(data->regmap, ADXL313_REG_XYZ_BASE, 393 + data->fifo_buf + (i * ADXL313_NUM_AXIS), 394 + sizeof(data->fifo_buf[0]) * ADXL313_NUM_AXIS); 395 + if (ret) 396 + return ret; 397 + } 398 + 399 + return 0; 400 + } 401 + 402 + /** 403 + * adxl313_fifo_reset() - Reset the FIFO and interrupt status registers. 404 + * @data: The device data. 405 + * 406 + * Reset the FIFO status registers. Reading out status registers clears the 407 + * FIFO and interrupt configuration. Thus do not evaluate regmap return values. 408 + * Ignore particular read register content. Register content is not processed 409 + * any further. Therefore the function returns void. 410 + */ 411 + static void adxl313_fifo_reset(struct adxl313_data *data) 412 + { 413 + unsigned int regval; 414 + int samples; 415 + 416 + adxl313_set_measure_en(data, false); 417 + 418 + samples = adxl313_get_samples(data); 419 + if (samples > 0) 420 + adxl313_fifo_transfer(data, samples); 421 + 422 + regmap_read(data->regmap, ADXL313_REG_INT_SOURCE, &regval); 423 + 424 + adxl313_set_measure_en(data, true); 425 + } 426 + 427 + static int adxl313_buffer_postenable(struct iio_dev *indio_dev) 428 + { 429 + struct adxl313_data *data = iio_priv(indio_dev); 430 + int ret; 431 + 432 + /* Set FIFO modes with measurement turned off, according to datasheet */ 433 + ret = adxl313_set_measure_en(data, false); 434 + if (ret) 435 + return ret; 436 + 437 + ret = regmap_write(data->regmap, ADXL313_REG_FIFO_CTL, 438 + FIELD_PREP(ADXL313_REG_FIFO_CTL_SAMPLES_MSK, data->watermark) | 439 + FIELD_PREP(ADXL313_REG_FIFO_CTL_MODE_MSK, ADXL313_FIFO_STREAM)); 440 + if (ret) 441 + return ret; 442 + 443 + return adxl313_set_measure_en(data, true); 444 + } 445 + 446 + static int adxl313_buffer_predisable(struct iio_dev *indio_dev) 447 + { 448 + struct adxl313_data *data = iio_priv(indio_dev); 449 + int ret; 450 + 451 + ret = adxl313_set_measure_en(data, false); 452 + if (ret) 453 + return ret; 454 + 455 + ret = regmap_write(data->regmap, ADXL313_REG_FIFO_CTL, 456 + FIELD_PREP(ADXL313_REG_FIFO_CTL_MODE_MSK, ADXL313_FIFO_BYPASS)); 457 + 458 + ret = regmap_write(data->regmap, ADXL313_REG_INT_ENABLE, 0); 459 + if (ret) 460 + return ret; 461 + 462 + return adxl313_set_measure_en(data, true); 463 + } 464 + 465 + static const struct iio_buffer_setup_ops adxl313_buffer_ops = { 466 + .postenable = adxl313_buffer_postenable, 467 + .predisable = adxl313_buffer_predisable, 468 + }; 469 + 470 + static int adxl313_fifo_push(struct iio_dev *indio_dev, int samples) 471 + { 472 + struct adxl313_data *data = iio_priv(indio_dev); 473 + unsigned int i; 474 + int ret; 475 + 476 + ret = adxl313_fifo_transfer(data, samples); 477 + if (ret) 478 + return ret; 479 + 480 + for (i = 0; i < ADXL313_NUM_AXIS * samples; i += ADXL313_NUM_AXIS) 481 + iio_push_to_buffers(indio_dev, &data->fifo_buf[i]); 482 + 483 + return 0; 484 + } 485 + 486 + static irqreturn_t adxl313_irq_handler(int irq, void *p) 487 + { 488 + struct iio_dev *indio_dev = p; 489 + struct adxl313_data *data = iio_priv(indio_dev); 490 + int samples, int_stat; 491 + 492 + if (regmap_read(data->regmap, ADXL313_REG_INT_SOURCE, &int_stat)) 493 + return IRQ_NONE; 494 + 495 + if (FIELD_GET(ADXL313_INT_WATERMARK, int_stat)) { 496 + samples = adxl313_get_samples(data); 497 + if (samples < 0) 498 + goto err_reset_fifo; 499 + 500 + if (adxl313_fifo_push(indio_dev, samples)) 501 + goto err_reset_fifo; 502 + } 503 + 504 + if (FIELD_GET(ADXL313_INT_OVERRUN, int_stat)) 505 + goto err_reset_fifo; 506 + 507 + return IRQ_HANDLED; 508 + 509 + err_reset_fifo: 510 + adxl313_fifo_reset(data); 511 + 512 + return IRQ_HANDLED; 513 + } 514 + 373 515 static int adxl313_reg_access(struct iio_dev *indio_dev, unsigned int reg, 374 516 unsigned int writeval, unsigned int *readval) 375 517 { ··· 551 359 .read_raw = adxl313_read_raw, 552 360 .write_raw = adxl313_write_raw, 553 361 .read_avail = adxl313_read_freq_avail, 362 + .hwfifo_set_watermark = adxl313_set_watermark, 554 363 .debugfs_reg_access = &adxl313_reg_access, 555 364 }; 556 365 ··· 600 407 return adxl313_set_measure_en(data, true); 601 408 } 602 409 410 + static unsigned int adxl313_get_int_type(struct device *dev, int *irq) 411 + { 412 + *irq = fwnode_irq_get_byname(dev_fwnode(dev), "INT1"); 413 + if (*irq > 0) 414 + return ADXL313_INT1; 415 + 416 + *irq = fwnode_irq_get_byname(dev_fwnode(dev), "INT2"); 417 + if (*irq > 0) 418 + return ADXL313_INT2; 419 + 420 + return ADXL313_INT_NONE; 421 + } 422 + 603 423 /** 604 424 * adxl313_core_probe() - probe and setup for adxl313 accelerometer 605 425 * @dev: Driver model representation of the device ··· 630 424 { 631 425 struct adxl313_data *data; 632 426 struct iio_dev *indio_dev; 633 - int ret; 427 + u8 int_line; 428 + u8 int_map_msk; 429 + int irq, ret; 634 430 635 431 indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 636 432 if (!indio_dev) ··· 649 441 indio_dev->modes = INDIO_DIRECT_MODE; 650 442 indio_dev->channels = adxl313_channels; 651 443 indio_dev->num_channels = ARRAY_SIZE(adxl313_channels); 444 + indio_dev->available_scan_masks = adxl313_scan_masks; 652 445 653 446 ret = adxl313_setup(dev, data, setup); 654 447 if (ret) { 655 448 dev_err(dev, "ADXL313 setup failed\n"); 656 449 return ret; 450 + } 451 + 452 + int_line = adxl313_get_int_type(dev, &irq); 453 + if (int_line == ADXL313_INT_NONE) { 454 + /* 455 + * FIFO_BYPASSED mode 456 + * 457 + * When no interrupt lines are specified, the driver falls back 458 + * to use the sensor in FIFO_BYPASS mode. This means turning off 459 + * internal FIFO and interrupt generation (since there is no 460 + * line specified). Unmaskable interrupts such as overrun or 461 + * data ready won't interfere. Even that a FIFO_STREAM mode w/o 462 + * connected interrupt line might allow for obtaining raw 463 + * measurements, a fallback to disable interrupts when no 464 + * interrupt lines are connected seems to be the cleaner 465 + * solution. 466 + */ 467 + ret = regmap_write(data->regmap, ADXL313_REG_FIFO_CTL, 468 + FIELD_PREP(ADXL313_REG_FIFO_CTL_MODE_MSK, 469 + ADXL313_FIFO_BYPASS)); 470 + if (ret) 471 + return ret; 472 + } else { 473 + /* FIFO_STREAM mode */ 474 + int_map_msk = ADXL313_INT_DREADY | ADXL313_INT_ACTIVITY | 475 + ADXL313_INT_INACTIVITY | ADXL313_INT_WATERMARK | 476 + ADXL313_INT_OVERRUN; 477 + ret = regmap_assign_bits(data->regmap, ADXL313_REG_INT_MAP, 478 + int_map_msk, int_line == ADXL313_INT2); 479 + if (ret) 480 + return ret; 481 + 482 + ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, 483 + &adxl313_buffer_ops); 484 + if (ret) 485 + return ret; 486 + 487 + ret = devm_request_threaded_irq(dev, irq, NULL, 488 + &adxl313_irq_handler, 489 + IRQF_SHARED | IRQF_ONESHOT, 490 + indio_dev->name, indio_dev); 491 + if (ret) 492 + return ret; 657 493 } 658 494 659 495 return devm_iio_device_register(dev, indio_dev);