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

iio: accel: adxl355: Add triggered buffer support

Provide a way for continuous data capture by setting up buffer support. The
data ready signal exposed at the DRDY pin of the ADXL355 is exploited as
a hardware interrupt which triggers to fill the buffer.

Signed-off-by: Puranjay Mohan <puranjay12@gmail.com>
Link: https://lore.kernel.org/r/20210903184312.21009-3-puranjay12@gmail.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Puranjay Mohan and committed by
Jonathan Cameron
327a0eaf 86ff6cb1

+158 -1
+4
drivers/iio/accel/Kconfig
··· 98 98 depends on I2C 99 99 select ADXL355 100 100 select REGMAP_I2C 101 + select IIO_BUFFER 102 + select IIO_TRIGGERED_BUFFER 101 103 help 102 104 Say Y here if you want to build i2c support for the Analog Devices 103 105 ADXL355 3-axis digital accelerometer. ··· 113 111 depends on SPI 114 112 select ADXL355 115 113 select REGMAP_SPI 114 + select IIO_BUFFER 115 + select IIO_TRIGGERED_BUFFER 116 116 help 117 117 Say Y here if you want to build spi support for the Analog Devices 118 118 ADXL355 3-axis digital accelerometer.
+154 -1
drivers/iio/accel/adxl355_core.c
··· 9 9 10 10 #include <linux/bits.h> 11 11 #include <linux/bitfield.h> 12 + #include <linux/iio/buffer.h> 12 13 #include <linux/iio/iio.h> 14 + #include <linux/iio/trigger.h> 15 + #include <linux/iio/triggered_buffer.h> 16 + #include <linux/iio/trigger_consumer.h> 13 17 #include <linux/limits.h> 14 18 #include <linux/math64.h> 15 19 #include <linux/module.h> 16 20 #include <linux/mod_devicetable.h> 21 + #include <linux/of_irq.h> 17 22 #include <linux/regmap.h> 18 23 #include <asm/unaligned.h> 19 24 ··· 51 46 #define ADXL355_RANGE_REG 0x2C 52 47 #define ADXL355_POWER_CTL_REG 0x2D 53 48 #define ADXL355_POWER_CTL_MODE_MSK GENMASK(1, 0) 49 + #define ADXL355_POWER_CTL_DRDY_MSK BIT(2) 54 50 #define ADXL355_SELF_TEST_REG 0x2E 55 51 #define ADXL355_RESET_REG 0x2F 56 52 ··· 171 165 enum adxl355_hpf_3db hpf_3db; 172 166 int calibbias[3]; 173 167 int adxl355_hpf_3db_table[7][2]; 174 - u8 transf_buf[3] ____cacheline_aligned; 168 + struct iio_trigger *dready_trig; 169 + union { 170 + u8 transf_buf[3]; 171 + struct { 172 + u8 buf[14]; 173 + s64 ts; 174 + } buffer; 175 + } ____cacheline_aligned; 175 176 }; 176 177 177 178 static int adxl355_set_op_mode(struct adxl355_data *data, ··· 195 182 return ret; 196 183 197 184 data->op_mode = op_mode; 185 + 186 + return ret; 187 + } 188 + 189 + static int adxl355_data_rdy_trigger_set_state(struct iio_trigger *trig, 190 + bool state) 191 + { 192 + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); 193 + struct adxl355_data *data = iio_priv(indio_dev); 194 + int ret; 195 + 196 + mutex_lock(&data->lock); 197 + ret = regmap_update_bits(data->regmap, ADXL355_POWER_CTL_REG, 198 + ADXL355_POWER_CTL_DRDY_MSK, 199 + FIELD_PREP(ADXL355_POWER_CTL_DRDY_MSK, 200 + state ? 0 : 1)); 201 + mutex_unlock(&data->lock); 198 202 199 203 return ret; 200 204 } ··· 273 243 * state after start-up. 274 244 */ 275 245 ret = regmap_write(data->regmap, ADXL355_RESET_REG, ADXL355_RESET_CODE); 246 + if (ret) 247 + return ret; 248 + 249 + ret = regmap_update_bits(data->regmap, ADXL355_POWER_CTL_REG, 250 + ADXL355_POWER_CTL_DRDY_MSK, 251 + FIELD_PREP(ADXL355_POWER_CTL_DRDY_MSK, 1)); 276 252 if (ret) 277 253 return ret; 278 254 ··· 563 527 } 564 528 } 565 529 530 + static const unsigned long adxl355_avail_scan_masks[] = { 531 + GENMASK(3, 0), 532 + 0 533 + }; 534 + 566 535 static const struct iio_info adxl355_info = { 567 536 .read_raw = adxl355_read_raw, 568 537 .write_raw = adxl355_write_raw, 569 538 .read_avail = &adxl355_read_avail, 570 539 }; 540 + 541 + static const struct iio_trigger_ops adxl355_trigger_ops = { 542 + .set_trigger_state = &adxl355_data_rdy_trigger_set_state, 543 + .validate_device = &iio_trigger_validate_own_device, 544 + }; 545 + 546 + static irqreturn_t adxl355_trigger_handler(int irq, void *p) 547 + { 548 + struct iio_poll_func *pf = p; 549 + struct iio_dev *indio_dev = pf->indio_dev; 550 + struct adxl355_data *data = iio_priv(indio_dev); 551 + int ret; 552 + 553 + mutex_lock(&data->lock); 554 + 555 + /* 556 + * data->buffer is used both for triggered buffer support 557 + * and read/write_raw(), hence, it has to be zeroed here before usage. 558 + */ 559 + data->buffer.buf[0] = 0; 560 + 561 + /* 562 + * The acceleration data is 24 bits and big endian. It has to be saved 563 + * in 32 bits, hence, it is saved in the 2nd byte of the 4 byte buffer. 564 + * The buf array is 14 bytes as it includes 3x4=12 bytes for 565 + * accelaration data of x, y, and z axis. It also includes 2 bytes for 566 + * temperature data. 567 + */ 568 + ret = regmap_bulk_read(data->regmap, ADXL355_XDATA3_REG, 569 + &data->buffer.buf[1], 3); 570 + if (ret) 571 + goto out_unlock_notify; 572 + 573 + ret = regmap_bulk_read(data->regmap, ADXL355_YDATA3_REG, 574 + &data->buffer.buf[5], 3); 575 + if (ret) 576 + goto out_unlock_notify; 577 + 578 + ret = regmap_bulk_read(data->regmap, ADXL355_ZDATA3_REG, 579 + &data->buffer.buf[9], 3); 580 + if (ret) 581 + goto out_unlock_notify; 582 + 583 + ret = regmap_bulk_read(data->regmap, ADXL355_TEMP2_REG, 584 + &data->buffer.buf[12], 2); 585 + if (ret) 586 + goto out_unlock_notify; 587 + 588 + iio_push_to_buffers_with_timestamp(indio_dev, &data->buffer, 589 + pf->timestamp); 590 + 591 + out_unlock_notify: 592 + mutex_unlock(&data->lock); 593 + iio_trigger_notify_done(indio_dev->trig); 594 + 595 + return IRQ_HANDLED; 596 + } 571 597 572 598 #define ADXL355_ACCEL_CHANNEL(index, reg, axis) { \ 573 599 .type = IIO_ACCEL, \ ··· 644 546 .info_mask_shared_by_type_available = \ 645 547 BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ 646 548 BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \ 549 + .scan_index = index, \ 647 550 .scan_type = { \ 648 551 .sign = 's', \ 649 552 .realbits = 20, \ ··· 664 565 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 665 566 BIT(IIO_CHAN_INFO_SCALE) | 666 567 BIT(IIO_CHAN_INFO_OFFSET), 568 + .scan_index = 3, 667 569 .scan_type = { 668 570 .sign = 's', 669 571 .realbits = 12, ··· 672 572 .endianness = IIO_BE, 673 573 }, 674 574 }, 575 + IIO_CHAN_SOFT_TIMESTAMP(4), 675 576 }; 577 + 578 + static int adxl355_probe_trigger(struct iio_dev *indio_dev, int irq) 579 + { 580 + struct adxl355_data *data = iio_priv(indio_dev); 581 + int ret; 582 + 583 + data->dready_trig = devm_iio_trigger_alloc(data->dev, "%s-dev%d", 584 + indio_dev->name, 585 + iio_device_id(indio_dev)); 586 + if (!data->dready_trig) 587 + return -ENOMEM; 588 + 589 + data->dready_trig->ops = &adxl355_trigger_ops; 590 + iio_trigger_set_drvdata(data->dready_trig, indio_dev); 591 + 592 + ret = devm_request_irq(data->dev, irq, 593 + &iio_trigger_generic_data_rdy_poll, 594 + IRQF_ONESHOT, "adxl355_irq", data->dready_trig); 595 + if (ret) 596 + return dev_err_probe(data->dev, ret, "request irq %d failed\n", 597 + irq); 598 + 599 + ret = devm_iio_trigger_register(data->dev, data->dready_trig); 600 + if (ret) { 601 + dev_err(data->dev, "iio trigger register failed\n"); 602 + return ret; 603 + } 604 + 605 + indio_dev->trig = iio_trigger_get(data->dready_trig); 606 + 607 + return 0; 608 + } 676 609 677 610 int adxl355_core_probe(struct device *dev, struct regmap *regmap, 678 611 const char *name) ··· 713 580 struct adxl355_data *data; 714 581 struct iio_dev *indio_dev; 715 582 int ret; 583 + int irq; 716 584 717 585 indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 718 586 if (!indio_dev) ··· 730 596 indio_dev->modes = INDIO_DIRECT_MODE; 731 597 indio_dev->channels = adxl355_channels; 732 598 indio_dev->num_channels = ARRAY_SIZE(adxl355_channels); 599 + indio_dev->available_scan_masks = adxl355_avail_scan_masks; 733 600 734 601 ret = adxl355_setup(data); 735 602 if (ret) { 736 603 dev_err(dev, "ADXL355 setup failed\n"); 737 604 return ret; 605 + } 606 + 607 + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, 608 + &iio_pollfunc_store_time, 609 + &adxl355_trigger_handler, NULL); 610 + if (ret) { 611 + dev_err(dev, "iio triggered buffer setup failed\n"); 612 + return ret; 613 + } 614 + 615 + /* 616 + * TODO: Would be good to move it to the generic version. 617 + */ 618 + irq = of_irq_get_byname(dev->of_node, "DRDY"); 619 + if (irq > 0) { 620 + ret = adxl355_probe_trigger(indio_dev, irq); 621 + if (ret) 622 + return ret; 738 623 } 739 624 740 625 return devm_iio_device_register(dev, indio_dev);