blob: 0f17b6dd2c5260b6f979f1acf1d22dd66c6e5abb [file] [log] [blame]
/*
* Copyright (C) 2017-2018 InvenSense, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define pr_fmt(fmt) "inv_mpu: " fmt
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/sysfs.h>
#include <linux/jiffies.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/kfifo.h>
#include <linux/poll.h>
#include <linux/miscdevice.h>
#include <linux/math64.h>
#include "../inv_mpu_iio.h"
static char iden[] = { 1, 0, 0, 0, 1, 0, 0, 0, 1 };
static int inv_process_gyro(struct inv_mpu_state *st, u8 *d, u64 t)
{
s16 raw[3];
s32 calib[3];
int i;
#define BIAS_UNIT 2859
for (i = 0; i < 3; i++)
raw[i] = be16_to_cpup((__be16 *) (d + i * 2));
for (i = 0; i < 3; i++)
calib[i] = (raw[i] << 15);
inv_push_gyro_data(st, raw, calib, t);
return 0;
}
static int inv_check_fsync(struct inv_mpu_state *st, u8 fsync_status)
{
u8 data[1];
if (!st->chip_config.eis_enable)
return 0;
inv_plat_read(st, REG_FSYNC_INT, 1, data);
if (data[0] & BIT_FSYNC_INT) {
pr_debug("fsync\n");
st->eis.eis_triggered = true;
st->eis.fsync_delay = 1;
st->eis.prev_state = 1;
st->eis.frame_count++;
st->eis.eis_frame = true;
}
st->header_count--;
return 0;
}
static int inv_push_sensor(struct inv_mpu_state *st, int ind, u64 t, u8 *d)
{
#ifdef ACCEL_BIAS_TEST
s16 acc[3], avg[3];
#endif
switch (ind) {
case SENSOR_ACCEL:
inv_convert_and_push_8bytes(st, ind, d, t, iden);
#ifdef ACCEL_BIAS_TEST
acc[0] = be16_to_cpup((__be16 *) (d));
acc[1] = be16_to_cpup((__be16 *) (d + 2));
acc[2] = be16_to_cpup((__be16 *) (d + 4));
if(inv_get_3axis_average(acc, avg, 0)){
pr_debug("accel 200 samples average = %5d, %5d, %5d\n", avg[0], avg[1], avg[2]);
}
#endif
break;
case SENSOR_TEMP:
inv_check_fsync(st, d[1]);
break;
case SENSOR_GYRO:
inv_process_gyro(st, d, t);
break;
default:
break;
}
return 0;
}
static int inv_push_20680_data(struct inv_mpu_state *st, u8 *d)
{
u8 *dptr;
int i;
dptr = d;
for (i = 0; i < SENSOR_NUM_MAX; i++) {
if (st->sensor[i].on) {
inv_get_dmp_ts(st, i);
if (st->sensor[i].send && (!st->ts_algo.first_sample)) {
st->sensor[i].sample_calib++;
inv_push_sensor(st, i, st->sensor[i].ts, dptr);
}
dptr += st->sensor[i].sample_size;
}
}
if (st->ts_algo.first_sample)
st->ts_algo.first_sample--;
st->header_count--;
return 0;
}
static int inv_process_20680_data(struct inv_mpu_state *st)
{
int total_bytes, tmp, res, fifo_count, pk_size, i;
u8 *dptr, *d;
u8 data[14];
bool done_flag;
u8 v;
#ifdef SENSOR_DATA_FROM_REGISTERS
u8 reg;
int len;
#endif
if(st->gesture_only_on && (!st->batch.timeout)) {
res = inv_plat_read(st, REG_INT_STATUS, 1, data);
if (res)
return res;
pr_debug("ges cnt=%d, statu=%x\n",
st->gesture_int_count, data[0]);
if (data[0] & (BIT_WOM_ALL_INT_EN)) {
if (!st->gesture_int_count) {
inv_switch_power_in_lp(st, true);
res = inv_plat_single_write(st, REG_INT_ENABLE,
BIT_WOM_ALL_INT_EN | BIT_DATA_RDY_EN);
if (res)
return res;
v = 0;
if (st->chip_config.gyro_enable)
v |= BITS_GYRO_FIFO_EN;
if (st->chip_config.accel_enable)
v |= BIT_ACCEL_FIFO_EN;
res = inv_plat_single_write(st, REG_FIFO_EN, v);
if (res)
return res;
/* First time wake up from WOM.
We don't need data in the FIFO */
res = inv_reset_fifo(st, true);
if (res)
return res;
res = inv_switch_power_in_lp(st, false);
st->gesture_int_count = WOM_DELAY_THRESHOLD;
return res;
}
st->gesture_int_count = WOM_DELAY_THRESHOLD;
} else {
if (!st->gesture_int_count) {
inv_switch_power_in_lp(st, true);
res = inv_plat_single_write(st, REG_FIFO_EN, 0);
res = inv_plat_single_write(st, REG_INT_ENABLE,
BIT_WOM_ALL_INT_EN);
inv_switch_power_in_lp(st, false);
return res;
}
st->gesture_int_count--;
}
}
fifo_count = inv_get_last_run_time_non_dmp_record_mode(st);
pr_debug("fifc= %d\n", fifo_count);
if (!fifo_count) {
pr_debug("REG_FIFO_COUNT_H size is 0\n");
return 0;
}
pk_size = st->batch.pk_size;
if (!pk_size)
return -EINVAL;
if (fifo_count >= (HARDWARE_FIFO_SIZE / st->batch.pk_size)) {
pr_warn("fifo overflow pkt count=%d pkt sz=%d\n", fifo_count, st->batch.pk_size);
return -EOVERFLOW;
}
fifo_count *= st->batch.pk_size;
st->fifo_count = fifo_count;
d = st->fifo_data_store;
dptr = d;
total_bytes = fifo_count;
#ifdef SENSOR_DATA_FROM_REGISTERS
len = 0;
if (st->sensor[SENSOR_GYRO].on) {
reg = REG_RAW_GYRO;
len += BYTES_PER_SENSOR;
if (st->sensor[SENSOR_ACCEL].on && !st->sensor[SENSOR_TEMP].on)
len += BYTES_FOR_TEMP;
}
if (st->sensor[SENSOR_TEMP].on) {
reg = REG_RAW_TEMP;
len += BYTES_FOR_TEMP;
}
if (st->sensor[SENSOR_ACCEL].on) {
reg = REG_RAW_ACCEL;
len += BYTES_PER_SENSOR;
}
if (len == 0) {
pr_debug("No sensor is enabled\n");
return 0;
}
/* read data registers */
res = inv_plat_read(st, reg, len, data);
if (res < 0) {
pr_err("read data registers is failed\n");
return res;
}
/* copy sensor data to buffer as FIFO data format */
tmp = 0;
if (st->sensor[SENSOR_ACCEL].on) {
for (i = 0; i < BYTES_PER_SENSOR; i++)
dptr[i] = data[tmp + i];
dptr += BYTES_PER_SENSOR;
tmp += BYTES_PER_SENSOR;
}
if (st->sensor[SENSOR_TEMP].on) {
for (i = 0; i < BYTES_FOR_TEMP; i++)
dptr[i] = data[tmp + i];
dptr += BYTES_FOR_TEMP;
tmp += BYTES_FOR_TEMP;
}
if (st->sensor[SENSOR_GYRO].on) {
if (st->sensor[SENSOR_ACCEL].on && !st->sensor[SENSOR_TEMP].on)
tmp += BYTES_FOR_TEMP;
for (i = 0; i < BYTES_PER_SENSOR; i++)
dptr[i] = data[tmp + i];
}
#else
while (total_bytes > 0) {
if (total_bytes < pk_size * MAX_FIFO_PACKET_READ)
tmp = total_bytes;
else
tmp = pk_size * MAX_FIFO_PACKET_READ;
res = inv_plat_read(st, REG_FIFO_R_W, tmp, dptr);
if (res < 0) {
pr_err("read REG_FIFO_R_W is failed\n");
return res;
}
pr_debug("inside: %x, %x, %x, %x, %x, %x, %x, %x\n", dptr[0], dptr[1], dptr[2],
dptr[3], dptr[4], dptr[5], dptr[6], dptr[7]);
pr_debug("insid2: %x, %x, %x, %x, %x, %x, %x, %x\n", dptr[8], dptr[9], dptr[10],
dptr[11], dptr[12], dptr[13], dptr[14], dptr[15]);
dptr += tmp;
total_bytes -= tmp;
}
#endif /* SENSOR_DATA_FROM_REGISTERS */
dptr = d;
pr_debug("dd: %x, %x, %x, %x, %x, %x, %x, %x\n", d[0], d[1], d[2],
d[3], d[4], d[5], d[6], d[7]);
pr_debug("dd2: %x, %x, %x, %x, %x, %x, %x, %x\n", d[8], d[9], d[10],
d[11], d[12], d[13], d[14], d[15]);
total_bytes = fifo_count;
for (i = 0; i < SENSOR_NUM_MAX; i++) {
if (st->sensor[i].on) {
st->sensor[i].count = total_bytes / pk_size;
}
}
st->header_count = 0;
for (i = 0; i < SENSOR_NUM_MAX; i++) {
if (st->sensor[i].on)
st->header_count = max(st->header_count,
st->sensor[i].count);
}
st->ts_algo.calib_counter++;
inv_bound_timestamp(st);
dptr = d;
done_flag = false;
while (!done_flag) {
pr_debug("total%d, pk=%d\n", total_bytes, pk_size);
if (total_bytes >= pk_size) {
res = inv_push_20680_data(st, dptr);
if (res)
return res;
total_bytes -= pk_size;
dptr += pk_size;
} else {
done_flag = true;
}
}
return 0;
}
/*
* _inv_read_fifo() - Transfer data from FIFO to ring buffer.
*/
static void _inv_read_fifo(struct inv_mpu_state *st)
{
struct iio_dev *indio_dev = iio_priv_to_dev(st);
int result;
result = wait_event_interruptible_timeout(st->wait_queue,
st->resume_state, msecs_to_jiffies(300));
if (result <= 0)
return;
mutex_lock(&indio_dev->mlock);
#ifdef TIMER_BASED_BATCHING
if (st->batch_timeout) {
if (inv_plat_single_write(st, REG_INT_ENABLE, st->int_en))
pr_err("REG_INT_ENABLE write error\n");
}
#endif
st->wake_sensor_received = false;
result = inv_process_20680_data(st);
if (result)
goto err_reset_fifo;
mutex_unlock(&indio_dev->mlock);
if (st->wake_sensor_received)
#ifdef CONFIG_HAS_WAKELOCK
wake_lock_timeout(&st->wake_lock, msecs_to_jiffies(200));
#else
__pm_wakeup_event(&st->wake_lock, 200); /* 200 msecs */
#endif
return;
err_reset_fifo:
if ((!st->chip_config.gyro_enable) &&
(!st->chip_config.accel_enable) &&
(!st->chip_config.slave_enable) &&
(!st->chip_config.pressure_enable)) {
inv_switch_power_in_lp(st, false);
mutex_unlock(&indio_dev->mlock);
return;
}
pr_err("error to reset fifo\n");
inv_switch_power_in_lp(st, true);
inv_reset_fifo(st, true);
inv_switch_power_in_lp(st, false);
mutex_unlock(&indio_dev->mlock);
return;
}
irqreturn_t inv_read_fifo(int irq, void *dev_id)
{
struct inv_mpu_state *st = (struct inv_mpu_state *)dev_id;
_inv_read_fifo(st);
return IRQ_HANDLED;
}
#ifdef TIMER_BASED_BATCHING
void inv_batch_work(struct work_struct *work)
{
struct inv_mpu_state *st =
container_of(work, struct inv_mpu_state, batch_work);
struct iio_dev *indio_dev = iio_priv_to_dev(st);
mutex_lock(&indio_dev->mlock);
if (inv_plat_single_write(st, REG_INT_ENABLE, st->int_en | BIT_DATA_RDY_EN))
pr_err("REG_INT_ENABLE write error\n");
mutex_unlock(&indio_dev->mlock);
return;
}
#endif
int inv_flush_batch_data(struct iio_dev *indio_dev, int data)
{
struct inv_mpu_state *st = iio_priv(indio_dev);
#ifndef SENSOR_DATA_FROM_REGISTERS
if (st->chip_config.gyro_enable ||
st->chip_config.accel_enable ||
st->chip_config.slave_enable ||
st->chip_config.pressure_enable) {
st->wake_sensor_received = 0;
inv_process_20680_data(st);
if (st->wake_sensor_received)
#ifdef CONFIG_HAS_WAKELOCK
wake_lock_timeout(&st->wake_lock, msecs_to_jiffies(200));
#else
__pm_wakeup_event(&st->wake_lock, 200); /* 200 msecs */
#endif
inv_switch_power_in_lp(st, false);
}
#endif /* SENSOR_DATA_FROM_REGISTERS */
inv_push_marker_to_buffer(st, END_MARKER, data);
return 0;
}