diff options
Diffstat (limited to 'drivers/iio/imu/adis_buffer.c')
| -rw-r--r-- | drivers/iio/imu/adis_buffer.c | 161 |
1 files changed, 58 insertions, 103 deletions
diff --git a/drivers/iio/imu/adis_buffer.c b/drivers/iio/imu/adis_buffer.c index 5b4225ee09b9..cd3db2388164 100644 --- a/drivers/iio/imu/adis_buffer.c +++ b/drivers/iio/imu/adis_buffer.c @@ -20,18 +20,16 @@ #include <linux/iio/imu/adis.h> static int adis_update_scan_mode_burst(struct iio_dev *indio_dev, - const unsigned long *scan_mask) + const unsigned long *scan_mask) { struct adis *adis = iio_device_get_drvdata(indio_dev); unsigned int burst_length, burst_max_length; u8 *tx; - /* All but the timestamp channel */ - burst_length = (indio_dev->num_channels - 1) * sizeof(u16); - burst_length += adis->burst->extra_len + adis->burst_extra_len; + burst_length = adis->data->burst_len + adis->burst_extra_len; - if (adis->burst->burst_max_len) - burst_max_length = adis->burst->burst_max_len; + if (adis->data->burst_max_len) + burst_max_length = adis->data->burst_max_len; else burst_max_length = burst_length; @@ -47,15 +45,17 @@ static int adis_update_scan_mode_burst(struct iio_dev *indio_dev, } tx = adis->buffer + burst_max_length; - tx[0] = ADIS_READ_REG(adis->burst->reg_cmd); + tx[0] = ADIS_READ_REG(adis->data->burst_reg_cmd); tx[1] = 0; adis->xfer[0].tx_buf = tx; - adis->xfer[0].bits_per_word = 8; adis->xfer[0].len = 2; + if (adis->data->burst_max_speed_hz) + adis->xfer[0].speed_hz = adis->data->burst_max_speed_hz; adis->xfer[1].rx_buf = adis->buffer; - adis->xfer[1].bits_per_word = 8; adis->xfer[1].len = burst_length; + if (adis->data->burst_max_speed_hz) + adis->xfer[1].speed_hz = adis->data->burst_max_speed_hz; spi_message_init(&adis->msg); spi_message_add_tail(&adis->xfer[0], &adis->msg); @@ -65,7 +65,7 @@ static int adis_update_scan_mode_burst(struct iio_dev *indio_dev, } int adis_update_scan_mode(struct iio_dev *indio_dev, - const unsigned long *scan_mask) + const unsigned long *scan_mask) { struct adis *adis = iio_device_get_drvdata(indio_dev); const struct iio_chan_spec *chan; @@ -76,7 +76,7 @@ int adis_update_scan_mode(struct iio_dev *indio_dev, kfree(adis->xfer); kfree(adis->buffer); - if (adis->burst && adis->burst->en) + if (adis->data->burst_len) return adis_update_scan_mode_burst(indio_dev, scan_mask); scan_count = indio_dev->scan_bytes / 2; @@ -98,7 +98,6 @@ int adis_update_scan_mode(struct iio_dev *indio_dev, spi_message_init(&adis->msg); for (j = 0; j <= scan_count; j++) { - adis->xfer[j].bits_per_word = 8; if (j != scan_count) adis->xfer[j].cs_change = 1; adis->xfer[j].len = 2; @@ -122,40 +121,48 @@ int adis_update_scan_mode(struct iio_dev *indio_dev, return 0; } -EXPORT_SYMBOL_GPL(adis_update_scan_mode); +EXPORT_SYMBOL_NS_GPL(adis_update_scan_mode, "IIO_ADISLIB"); -static irqreturn_t adis_trigger_handler(int irq, void *p) +static int adis_paging_trigger_handler(struct adis *adis) { - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - struct adis *adis = iio_device_get_drvdata(indio_dev); int ret; - if (!adis->buffer) - return -ENOMEM; - - if (adis->data->has_paging) { - mutex_lock(&adis->state_lock); - if (adis->current_page != 0) { - adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID); - adis->tx[1] = 0; - spi_write(adis->spi, adis->tx, 2); + guard(mutex)(&adis->state_lock); + if (adis->current_page != 0) { + adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID); + adis->tx[1] = 0; + ret = spi_write(adis->spi, adis->tx, 2); + if (ret) { + dev_err(&adis->spi->dev, "Failed to change device page: %d\n", ret); + return ret; } + + adis->current_page = 0; } - ret = spi_sync(adis->spi, &adis->msg); - if (ret) - dev_err(&adis->spi->dev, "Failed to read data: %d", ret); + return spi_sync(adis->spi, &adis->msg); +} +static irqreturn_t adis_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct adis *adis = iio_device_get_drvdata(indio_dev); + int ret; - if (adis->data->has_paging) { - adis->current_page = 0; - mutex_unlock(&adis->state_lock); + if (adis->data->has_paging) + ret = adis_paging_trigger_handler(adis); + else + ret = spi_sync(adis->spi, &adis->msg); + if (ret) { + dev_err(&adis->spi->dev, "Failed to read data: %d", ret); + goto irq_done; } iio_push_to_buffers_with_timestamp(indio_dev, adis->buffer, - pf->timestamp); + pf->timestamp); +irq_done: iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; @@ -170,70 +177,36 @@ static void adis_buffer_cleanup(void *arg) } /** - * adis_setup_buffer_and_trigger() - Sets up buffer and trigger for the adis device - * @adis: The adis device. - * @indio_dev: The IIO device. - * @trigger_handler: Optional trigger handler, may be NULL. - * - * Returns 0 on success, a negative error code otherwise. - * - * This function sets up the buffer and trigger for a adis devices. If - * 'trigger_handler' is NULL the default trigger handler will be used. The - * default trigger handler will simply read the registers assigned to the - * currently active channels. - * - * adis_cleanup_buffer_and_trigger() should be called to free the resources - * allocated by this function. - */ -int adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev, - irqreturn_t (*trigger_handler)(int, void *)) -{ - int ret; - - if (!trigger_handler) - trigger_handler = adis_trigger_handler; - - ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, - trigger_handler, NULL); - if (ret) - return ret; - - if (adis->spi->irq) { - ret = adis_probe_trigger(adis, indio_dev); - if (ret) - goto error_buffer_cleanup; - } - return 0; - -error_buffer_cleanup: - iio_triggered_buffer_cleanup(indio_dev); - return ret; -} -EXPORT_SYMBOL_GPL(adis_setup_buffer_and_trigger); - -/** - * devm_adis_setup_buffer_and_trigger() - Sets up buffer and trigger for - * the managed adis device + * devm_adis_setup_buffer_and_trigger_with_attrs() - Sets up buffer and trigger + * for the managed adis device with buffer attributes. * @adis: The adis device * @indio_dev: The IIO device - * @trigger_handler: Optional trigger handler, may be NULL. + * @trigger_handler: Trigger handler: should handle the buffer readings. + * @ops: Optional buffer setup functions, may be NULL. + * @buffer_attrs: Extra buffer attributes. * * Returns 0 on success, a negative error code otherwise. * - * This function perfoms exactly the same as adis_setup_buffer_and_trigger() + * This function sets up the buffer (with buffer setup functions and extra + * buffer attributes) and trigger for a adis devices with buffer attributes. */ int -devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev, - irq_handler_t trigger_handler) +devm_adis_setup_buffer_and_trigger_with_attrs(struct adis *adis, struct iio_dev *indio_dev, + irq_handler_t trigger_handler, + const struct iio_buffer_setup_ops *ops, + const struct iio_dev_attr **buffer_attrs) { int ret; if (!trigger_handler) trigger_handler = adis_trigger_handler; - ret = devm_iio_triggered_buffer_setup(&adis->spi->dev, indio_dev, - &iio_pollfunc_store_time, - trigger_handler, NULL); + ret = devm_iio_triggered_buffer_setup_ext(&adis->spi->dev, indio_dev, + &iio_pollfunc_store_time, + trigger_handler, + IIO_BUFFER_DIRECTION_IN, + ops, + buffer_attrs); if (ret) return ret; @@ -246,22 +219,4 @@ devm_adis_setup_buffer_and_trigger(struct adis *adis, struct iio_dev *indio_dev, return devm_add_action_or_reset(&adis->spi->dev, adis_buffer_cleanup, adis); } -EXPORT_SYMBOL_GPL(devm_adis_setup_buffer_and_trigger); - -/** - * adis_cleanup_buffer_and_trigger() - Free buffer and trigger resources - * @adis: The adis device. - * @indio_dev: The IIO device. - * - * Frees resources allocated by adis_setup_buffer_and_trigger() - */ -void adis_cleanup_buffer_and_trigger(struct adis *adis, - struct iio_dev *indio_dev) -{ - if (adis->spi->irq) - adis_remove_trigger(adis); - kfree(adis->buffer); - kfree(adis->xfer); - iio_triggered_buffer_cleanup(indio_dev); -} -EXPORT_SYMBOL_GPL(adis_cleanup_buffer_and_trigger); +EXPORT_SYMBOL_NS_GPL(devm_adis_setup_buffer_and_trigger_with_attrs, "IIO_ADISLIB"); |
