xref: /openbmc/linux/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c (revision 46eeaa11bdd1bc9e077bdf741d32ca7235d263c6)
19c92ab61SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
209a642b7SGe Gao /*
309a642b7SGe Gao * Copyright (C) 2012 Invensense, Inc.
409a642b7SGe Gao */
509a642b7SGe Gao 
609a642b7SGe Gao #include <linux/module.h>
709a642b7SGe Gao #include <linux/slab.h>
809a642b7SGe Gao #include <linux/err.h>
909a642b7SGe Gao #include <linux/delay.h>
1009a642b7SGe Gao #include <linux/sysfs.h>
1109a642b7SGe Gao #include <linux/jiffies.h>
1209a642b7SGe Gao #include <linux/irq.h>
1309a642b7SGe Gao #include <linux/interrupt.h>
1409a642b7SGe Gao #include <linux/poll.h>
154bcc19f1SJean-Baptiste Maneyrol #include <linux/math64.h>
16111e1abdSJean-Baptiste Maneyrol 
17111e1abdSJean-Baptiste Maneyrol #include <linux/iio/common/inv_sensors_timestamp.h>
18111e1abdSJean-Baptiste Maneyrol 
1909a642b7SGe Gao #include "inv_mpu_iio.h"
2009a642b7SGe Gao 
inv_reset_fifo(struct iio_dev * indio_dev)214c1e0147SJean-Baptiste Maneyrol static int inv_reset_fifo(struct iio_dev *indio_dev)
2209a642b7SGe Gao {
2309a642b7SGe Gao 	int result;
2409a642b7SGe Gao 	struct inv_mpu6050_state  *st = iio_priv(indio_dev);
2509a642b7SGe Gao 
264c1e0147SJean-Baptiste Maneyrol 	/* disable fifo and reenable it */
274c1e0147SJean-Baptiste Maneyrol 	inv_mpu6050_prepare_fifo(st, false);
284c1e0147SJean-Baptiste Maneyrol 	result = inv_mpu6050_prepare_fifo(st, true);
2909a642b7SGe Gao 	if (result)
3009a642b7SGe Gao 		goto reset_fifo_fail;
3109a642b7SGe Gao 
3209a642b7SGe Gao 	return 0;
3309a642b7SGe Gao 
3409a642b7SGe Gao reset_fifo_fail:
35b3eea8daSAdriana Reus 	dev_err(regmap_get_device(st->map), "reset fifo failed %d\n", result);
36d430f3c3SAdriana Reus 	result = regmap_write(st->map, st->reg->int_enable,
3709a642b7SGe Gao 			      INV_MPU6050_BIT_DATA_RDY_EN);
3809a642b7SGe Gao 
3909a642b7SGe Gao 	return result;
4009a642b7SGe Gao }
4109a642b7SGe Gao 
423c979784SLee Jones /*
4309a642b7SGe Gao  * inv_mpu6050_read_fifo() - Transfer data from hardware FIFO to KFIFO.
4409a642b7SGe Gao  */
inv_mpu6050_read_fifo(int irq,void * p)4509a642b7SGe Gao irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
4609a642b7SGe Gao {
4709a642b7SGe Gao 	struct iio_poll_func *pf = p;
4809a642b7SGe Gao 	struct iio_dev *indio_dev = pf->indio_dev;
4909a642b7SGe Gao 	struct inv_mpu6050_state *st = iio_priv(indio_dev);
5009a642b7SGe Gao 	size_t bytes_per_datum;
5109a642b7SGe Gao 	int result;
5209a642b7SGe Gao 	u16 fifo_count;
53111e1abdSJean-Baptiste Maneyrol 	u32 fifo_period;
544bcc19f1SJean-Baptiste Maneyrol 	s64 timestamp;
550829edc4SJean-Baptiste Maneyrol 	u8 data[INV_MPU6050_OUTPUT_DATA_SIZE];
565ec6486dSMartin Kelly 	int int_status;
575cba7caaSJean-Baptiste Maneyrol 	size_t i, nb;
5809a642b7SGe Gao 
5968cd6e5bSJean-Baptiste Maneyrol 	mutex_lock(&st->lock);
605ec6486dSMartin Kelly 
615ec6486dSMartin Kelly 	/* ack interrupt and check status */
625ec6486dSMartin Kelly 	result = regmap_read(st->map, st->reg->int_status, &int_status);
635ec6486dSMartin Kelly 	if (result) {
645ec6486dSMartin Kelly 		dev_err(regmap_get_device(st->map),
655ec6486dSMartin Kelly 			"failed to ack interrupt\n");
665ec6486dSMartin Kelly 		goto flush_fifo;
675ec6486dSMartin Kelly 	}
6884961af7SMichał Mirosław 	if (!(int_status & INV_MPU6050_BIT_RAW_DATA_RDY_INT))
695ec6486dSMartin Kelly 		goto end_session;
705ec6486dSMartin Kelly 
7109a642b7SGe Gao 	if (!(st->chip_config.accl_fifo_enable |
72e764fb4eSJean-Baptiste Maneyrol 		st->chip_config.gyro_fifo_enable |
73e764fb4eSJean-Baptiste Maneyrol 		st->chip_config.magn_fifo_enable))
7409a642b7SGe Gao 		goto end_session;
7509a642b7SGe Gao 	bytes_per_datum = 0;
7609a642b7SGe Gao 	if (st->chip_config.accl_fifo_enable)
7709a642b7SGe Gao 		bytes_per_datum += INV_MPU6050_BYTES_PER_3AXIS_SENSOR;
7809a642b7SGe Gao 
7909a642b7SGe Gao 	if (st->chip_config.gyro_fifo_enable)
8009a642b7SGe Gao 		bytes_per_datum += INV_MPU6050_BYTES_PER_3AXIS_SENSOR;
8109a642b7SGe Gao 
822e4c0a5eSJean-Baptiste Maneyrol 	if (st->chip_config.temp_fifo_enable)
832e4c0a5eSJean-Baptiste Maneyrol 		bytes_per_datum += INV_MPU6050_BYTES_PER_TEMP_SENSOR;
841615fe41SSteve Moskovchenko 
85e764fb4eSJean-Baptiste Maneyrol 	if (st->chip_config.magn_fifo_enable)
86e764fb4eSJean-Baptiste Maneyrol 		bytes_per_datum += INV_MPU9X50_BYTES_MAGN;
87e764fb4eSJean-Baptiste Maneyrol 
8809a642b7SGe Gao 	/*
89d8b40181SMartin Kelly 	 * read fifo_count register to know how many bytes are inside the FIFO
9009a642b7SGe Gao 	 * right now
9109a642b7SGe Gao 	 */
926b0cc5dcSJonathan Cameron 	result = regmap_bulk_read(st->map, st->reg->fifo_count_h,
936b0cc5dcSJonathan Cameron 				  st->data, INV_MPU6050_FIFO_COUNT_BYTE);
94d430f3c3SAdriana Reus 	if (result)
9509a642b7SGe Gao 		goto end_session;
966b0cc5dcSJonathan Cameron 	fifo_count = be16_to_cpup((__be16 *)&st->data[0]);
976e82ae6bSJean-Baptiste Maneyrol 
986e82ae6bSJean-Baptiste Maneyrol 	/*
996e82ae6bSJean-Baptiste Maneyrol 	 * Handle fifo overflow by resetting fifo.
1006e82ae6bSJean-Baptiste Maneyrol 	 * Reset if there is only 3 data set free remaining to mitigate
1016e82ae6bSJean-Baptiste Maneyrol 	 * possible delay between reading fifo count and fifo data.
1026e82ae6bSJean-Baptiste Maneyrol 	 */
1036e82ae6bSJean-Baptiste Maneyrol 	nb = 3 * bytes_per_datum;
1046e82ae6bSJean-Baptiste Maneyrol 	if (fifo_count >= st->hw->fifo_size - nb) {
1056e82ae6bSJean-Baptiste Maneyrol 		dev_warn(regmap_get_device(st->map), "fifo overflow reset\n");
1066e82ae6bSJean-Baptiste Maneyrol 		goto flush_fifo;
1076e82ae6bSJean-Baptiste Maneyrol 	}
1086e82ae6bSJean-Baptiste Maneyrol 
1090829edc4SJean-Baptiste Maneyrol 	/* compute and process only all complete datum */
1105cba7caaSJean-Baptiste Maneyrol 	nb = fifo_count / bytes_per_datum;
1110829edc4SJean-Baptiste Maneyrol 	fifo_count = nb * bytes_per_datum;
112*60b9d188SJean-Baptiste Maneyrol 	if (nb == 0)
113*60b9d188SJean-Baptiste Maneyrol 		goto end_session;
114111e1abdSJean-Baptiste Maneyrol 	/* Each FIFO data contains all sensors, so same number for FIFO and sensor data */
115111e1abdSJean-Baptiste Maneyrol 	fifo_period = NSEC_PER_SEC / INV_MPU6050_DIVIDER_TO_FIFO_RATE(st->chip_config.divider);
116111e1abdSJean-Baptiste Maneyrol 	inv_sensors_timestamp_interrupt(&st->timestamp, fifo_period, nb, nb, pf->timestamp);
117111e1abdSJean-Baptiste Maneyrol 	inv_sensors_timestamp_apply_odr(&st->timestamp, fifo_period, nb, 0);
1180829edc4SJean-Baptiste Maneyrol 
1190829edc4SJean-Baptiste Maneyrol 	/* clear internal data buffer for avoiding kernel data leak */
1200829edc4SJean-Baptiste Maneyrol 	memset(data, 0, sizeof(data));
1210829edc4SJean-Baptiste Maneyrol 
1220829edc4SJean-Baptiste Maneyrol 	/* read all data once and process every samples */
1230829edc4SJean-Baptiste Maneyrol 	result = regmap_noinc_read(st->map, st->reg->fifo_r_w, st->data, fifo_count);
124d430f3c3SAdriana Reus 	if (result)
12509a642b7SGe Gao 		goto flush_fifo;
1260829edc4SJean-Baptiste Maneyrol 	for (i = 0; i < nb; ++i) {
127c2b82a69SJean-Baptiste Maneyrol 		/* skip first samples if needed */
1285cba7caaSJean-Baptiste Maneyrol 		if (st->skip_samples) {
129c2b82a69SJean-Baptiste Maneyrol 			st->skip_samples--;
1305cba7caaSJean-Baptiste Maneyrol 			continue;
1315cba7caaSJean-Baptiste Maneyrol 		}
1320829edc4SJean-Baptiste Maneyrol 		memcpy(data, &st->data[i * bytes_per_datum], bytes_per_datum);
133111e1abdSJean-Baptiste Maneyrol 		timestamp = inv_sensors_timestamp_pop(&st->timestamp);
1340829edc4SJean-Baptiste Maneyrol 		iio_push_to_buffers_with_timestamp(indio_dev, data, timestamp);
1355cba7caaSJean-Baptiste Maneyrol 	}
13609a642b7SGe Gao 
13709a642b7SGe Gao end_session:
13868cd6e5bSJean-Baptiste Maneyrol 	mutex_unlock(&st->lock);
13909a642b7SGe Gao 	iio_trigger_notify_done(indio_dev->trig);
14009a642b7SGe Gao 
14109a642b7SGe Gao 	return IRQ_HANDLED;
14209a642b7SGe Gao 
14309a642b7SGe Gao flush_fifo:
14409a642b7SGe Gao 	/* Flush HW and SW FIFOs. */
14509a642b7SGe Gao 	inv_reset_fifo(indio_dev);
14668cd6e5bSJean-Baptiste Maneyrol 	mutex_unlock(&st->lock);
14709a642b7SGe Gao 	iio_trigger_notify_done(indio_dev->trig);
14809a642b7SGe Gao 
14909a642b7SGe Gao 	return IRQ_HANDLED;
15009a642b7SGe Gao }
151