MA Lite 8.1.5
Module: * 8.1.2-simple-test1 Supported Kernel Versions: * 3.18 * 4.4 * 4.9 Supported TDK-InvenSense Sensors: * IAM20680 Change log: * Timer based batch mode support for IAM20680
This commit is contained in:
parent
a71da78c6d
commit
b1c8f25f65
8 changed files with 143 additions and 19 deletions
|
@ -19,10 +19,17 @@
|
||||||
* sysfs entries */
|
* sysfs entries */
|
||||||
#define SUPPORT_ONLY_BASIC_FEATURES
|
#define SUPPORT_ONLY_BASIC_FEATURES
|
||||||
|
|
||||||
/* Uncomment to read data registers for sensor data
|
/* Uncomment to read data registers for sensor data instead of FIFO */
|
||||||
* instead of FIFO */
|
|
||||||
//#define SENSOR_DATA_FROM_REGISTERS
|
//#define SENSOR_DATA_FROM_REGISTERS
|
||||||
|
|
||||||
|
/* Uncomment to enable timer based batching */
|
||||||
|
#define TIMER_BASED_BATCHING
|
||||||
|
|
||||||
|
/* Polling (batch mode) can be enabled only when FIFO read */
|
||||||
|
#if defined(SENSOR_DATA_FROM_REGISTERS)
|
||||||
|
#undef TIMER_BASED_BATCHING
|
||||||
|
#endif
|
||||||
|
|
||||||
/*register and associated bit definition*/
|
/*register and associated bit definition*/
|
||||||
#define REG_XA_OFFS_H 0x77
|
#define REG_XA_OFFS_H 0x77
|
||||||
#define REG_YA_OFFS_H 0x7A
|
#define REG_YA_OFFS_H 0x7A
|
||||||
|
@ -140,7 +147,7 @@
|
||||||
#define BYTES_FOR_TEMP 2
|
#define BYTES_FOR_TEMP 2
|
||||||
#define FIFO_COUNT_BYTE 2
|
#define FIFO_COUNT_BYTE 2
|
||||||
#define HARDWARE_FIFO_SIZE 512
|
#define HARDWARE_FIFO_SIZE 512
|
||||||
#define FIFO_SIZE (HARDWARE_FIFO_SIZE * 7 / 8)
|
#define FIFO_SIZE (HARDWARE_FIFO_SIZE * 7 / 10)
|
||||||
#define POWER_UP_TIME 100
|
#define POWER_UP_TIME 100
|
||||||
#define REG_UP_TIME_USEC 100
|
#define REG_UP_TIME_USEC 100
|
||||||
#define LEFT_OVER_BYTES 128
|
#define LEFT_OVER_BYTES 128
|
||||||
|
@ -190,7 +197,7 @@ enum inv_filter_e {
|
||||||
#define GESTURE_ACCEL_RATE 50
|
#define GESTURE_ACCEL_RATE 50
|
||||||
#define ESI_GYRO_RATE 1000
|
#define ESI_GYRO_RATE 1000
|
||||||
#define MAX_FIFO_PACKET_READ 6
|
#define MAX_FIFO_PACKET_READ 6
|
||||||
#define MAX_BATCH_FIFO_SIZE 896
|
#define MAX_BATCH_FIFO_SIZE FIFO_SIZE
|
||||||
|
|
||||||
#define MIN_MST_ODR_CONFIG 4
|
#define MIN_MST_ODR_CONFIG 4
|
||||||
#define MAX_MST_ODR_CONFIG 5
|
#define MAX_MST_ODR_CONFIG 5
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2017-2017 InvenSense, Inc.
|
* Copyright (C) 2017-2018 InvenSense, Inc.
|
||||||
*
|
*
|
||||||
* This software is licensed under the terms of the GNU General Public
|
* This software is licensed under the terms of the GNU General Public
|
||||||
* License version 2, as published by the Free Software Foundation, and
|
* License version 2, as published by the Free Software Foundation, and
|
||||||
|
@ -172,6 +172,10 @@ static int inv_init_config(struct inv_mpu_state *st)
|
||||||
st->eis.count_precision = NSEC_PER_MSEC;
|
st->eis.count_precision = NSEC_PER_MSEC;
|
||||||
st->firmware = 0;
|
st->firmware = 0;
|
||||||
st->fifo_count_mode = BYTE_MODE;
|
st->fifo_count_mode = BYTE_MODE;
|
||||||
|
#ifdef TIMER_BASED_BATCHING
|
||||||
|
st->batch_timeout = 0;
|
||||||
|
st->is_batch_timer_running = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
st->eng_info[ENGINE_GYRO].base_time = NSEC_PER_SEC;
|
st->eng_info[ENGINE_GYRO].base_time = NSEC_PER_SEC;
|
||||||
st->eng_info[ENGINE_ACCEL].base_time = NSEC_PER_SEC;
|
st->eng_info[ENGINE_ACCEL].base_time = NSEC_PER_SEC;
|
||||||
|
|
|
@ -193,6 +193,11 @@ static int inv_process_20680_data(struct inv_mpu_state *st)
|
||||||
if (!pk_size)
|
if (!pk_size)
|
||||||
return -EINVAL;
|
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;
|
fifo_count *= st->batch.pk_size;
|
||||||
st->fifo_count = fifo_count;
|
st->fifo_count = fifo_count;
|
||||||
d = st->fifo_data_store;
|
d = st->fifo_data_store;
|
||||||
|
@ -312,20 +317,24 @@ static int inv_process_20680_data(struct inv_mpu_state *st)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* inv_read_fifo() - Transfer data from FIFO to ring buffer.
|
* _inv_read_fifo() - Transfer data from FIFO to ring buffer.
|
||||||
*/
|
*/
|
||||||
irqreturn_t inv_read_fifo(int irq, void *dev_id)
|
static void _inv_read_fifo(struct inv_mpu_state *st)
|
||||||
{
|
{
|
||||||
|
|
||||||
struct inv_mpu_state *st = (struct inv_mpu_state *)dev_id;
|
|
||||||
struct iio_dev *indio_dev = iio_priv_to_dev(st);
|
struct iio_dev *indio_dev = iio_priv_to_dev(st);
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
result = wait_event_interruptible_timeout(st->wait_queue,
|
result = wait_event_interruptible_timeout(st->wait_queue,
|
||||||
st->resume_state, msecs_to_jiffies(300));
|
st->resume_state, msecs_to_jiffies(300));
|
||||||
if (result <= 0)
|
if (result <= 0)
|
||||||
return IRQ_HANDLED;
|
return;
|
||||||
mutex_lock(&indio_dev->mlock);
|
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;
|
st->wake_sensor_received = false;
|
||||||
result = inv_process_20680_data(st);
|
result = inv_process_20680_data(st);
|
||||||
if (result)
|
if (result)
|
||||||
|
@ -338,7 +347,7 @@ irqreturn_t inv_read_fifo(int irq, void *dev_id)
|
||||||
#else
|
#else
|
||||||
__pm_wakeup_event(&st->wake_lock, 200); /* 200 msecs */
|
__pm_wakeup_event(&st->wake_lock, 200); /* 200 msecs */
|
||||||
#endif
|
#endif
|
||||||
return IRQ_HANDLED;
|
return;
|
||||||
|
|
||||||
err_reset_fifo:
|
err_reset_fifo:
|
||||||
if ((!st->chip_config.gyro_enable) &&
|
if ((!st->chip_config.gyro_enable) &&
|
||||||
|
@ -348,7 +357,7 @@ err_reset_fifo:
|
||||||
inv_switch_power_in_lp(st, false);
|
inv_switch_power_in_lp(st, false);
|
||||||
mutex_unlock(&indio_dev->mlock);
|
mutex_unlock(&indio_dev->mlock);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_err("error to reset fifo\n");
|
pr_err("error to reset fifo\n");
|
||||||
|
@ -357,10 +366,34 @@ err_reset_fifo:
|
||||||
inv_switch_power_in_lp(st, false);
|
inv_switch_power_in_lp(st, false);
|
||||||
mutex_unlock(&indio_dev->mlock);
|
mutex_unlock(&indio_dev->mlock);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
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)
|
int inv_flush_batch_data(struct iio_dev *indio_dev, int data)
|
||||||
{
|
{
|
||||||
struct inv_mpu_state *st = iio_priv(indio_dev);
|
struct inv_mpu_state *st = iio_priv(indio_dev);
|
||||||
|
|
|
@ -44,6 +44,13 @@ static int inv_turn_on_fifo(struct inv_mpu_state *st)
|
||||||
st->gesture_int_count = WOM_DELAY_THRESHOLD;
|
st->gesture_int_count = WOM_DELAY_THRESHOLD;
|
||||||
int_en |= BIT_WOM_ALL_INT_EN;
|
int_en |= BIT_WOM_ALL_INT_EN;
|
||||||
}
|
}
|
||||||
|
#ifdef TIMER_BASED_BATCHING
|
||||||
|
if (st->chip_config.eis_enable)
|
||||||
|
int_en |= BIT_FSYNC_INT_EN;
|
||||||
|
if (!st->batch_timeout) {
|
||||||
|
int_en |= BIT_DATA_RDY_EN;
|
||||||
|
}
|
||||||
|
#else
|
||||||
if (st->batch.timeout) {
|
if (st->batch.timeout) {
|
||||||
if(!st->batch.fifo_wm_th)
|
if(!st->batch.fifo_wm_th)
|
||||||
int_en = BIT_DATA_RDY_EN;
|
int_en = BIT_DATA_RDY_EN;
|
||||||
|
@ -52,6 +59,7 @@ static int inv_turn_on_fifo(struct inv_mpu_state *st)
|
||||||
if (st->chip_config.eis_enable)
|
if (st->chip_config.eis_enable)
|
||||||
int_en |= BIT_FSYNC_INT_EN;
|
int_en |= BIT_FSYNC_INT_EN;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if (st->sensor[SENSOR_GYRO].on)
|
if (st->sensor[SENSOR_GYRO].on)
|
||||||
fifo_en |= BITS_GYRO_FIFO_EN;
|
fifo_en |= BITS_GYRO_FIFO_EN;
|
||||||
|
|
||||||
|
@ -60,6 +68,7 @@ static int inv_turn_on_fifo(struct inv_mpu_state *st)
|
||||||
r = inv_plat_single_write(st, REG_FIFO_EN, fifo_en);
|
r = inv_plat_single_write(st, REG_FIFO_EN, fifo_en);
|
||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
|
st->int_en = int_en;
|
||||||
r = inv_plat_single_write(st, REG_INT_ENABLE, int_en);
|
r = inv_plat_single_write(st, REG_INT_ENABLE, int_en);
|
||||||
if (r)
|
if (r)
|
||||||
return r;
|
return r;
|
||||||
|
@ -75,6 +84,19 @@ static int inv_turn_on_fifo(struct inv_mpu_state *st)
|
||||||
user = BIT_FIFO_EN;
|
user = BIT_FIFO_EN;
|
||||||
#endif
|
#endif
|
||||||
r = inv_plat_single_write(st, REG_USER_CTRL, user | st->i2c_dis);
|
r = inv_plat_single_write(st, REG_USER_CTRL, user | st->i2c_dis);
|
||||||
|
#ifdef TIMER_BASED_BATCHING
|
||||||
|
if (fifo_en && st->batch_timeout) {
|
||||||
|
if (st->is_batch_timer_running)
|
||||||
|
hrtimer_cancel(&st ->hr_batch_timer);
|
||||||
|
st->is_batch_timer_running = true;
|
||||||
|
hrtimer_start(&st ->hr_batch_timer,
|
||||||
|
ns_to_ktime(st->batch_timeout), HRTIMER_MODE_REL);
|
||||||
|
} else {
|
||||||
|
if (st->is_batch_timer_running)
|
||||||
|
hrtimer_cancel(&st ->hr_batch_timer);
|
||||||
|
st->is_batch_timer_running = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -245,6 +267,27 @@ static int inv_set_div(struct inv_mpu_state *st, int a_d, int g_d)
|
||||||
// 20680 does not support batching
|
// 20680 does not support batching
|
||||||
static int inv_set_batch(struct inv_mpu_state *st)
|
static int inv_set_batch(struct inv_mpu_state *st)
|
||||||
{
|
{
|
||||||
|
#ifdef TIMER_BASED_BATCHING
|
||||||
|
u64 timeout;
|
||||||
|
int required_fifo_size;
|
||||||
|
|
||||||
|
if (st->batch.timeout) {
|
||||||
|
required_fifo_size = st->batch.timeout * st->eng_info[ENGINE_GYRO].running_rate
|
||||||
|
* st->batch.pk_size / 1000;
|
||||||
|
if (required_fifo_size > MAX_BATCH_FIFO_SIZE) {
|
||||||
|
required_fifo_size = MAX_BATCH_FIFO_SIZE;
|
||||||
|
timeout = (required_fifo_size / st->batch.pk_size) * (1000 / st->eng_info[ENGINE_GYRO].running_rate);
|
||||||
|
} else {
|
||||||
|
timeout = st->batch.timeout;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
timeout = 1000 / st->eng_info[ENGINE_GYRO].running_rate;
|
||||||
|
}
|
||||||
|
if (timeout <= 1000 / st->eng_info[ENGINE_GYRO].running_rate)
|
||||||
|
st->batch_timeout = 0;
|
||||||
|
else
|
||||||
|
st->batch_timeout = timeout * 1000000; // ms to ns
|
||||||
|
#endif
|
||||||
st->batch.fifo_wm_th = 0;
|
st->batch.fifo_wm_th = 0;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2012-2017 InvenSense, Inc.
|
* Copyright (C) 2012-2018 InvenSense, Inc.
|
||||||
*
|
*
|
||||||
* This software is licensed under the terms of the GNU General Public
|
* This software is licensed under the terms of the GNU General Public
|
||||||
* License version 2, as published by the Free Software Foundation, and
|
* License version 2, as published by the Free Software Foundation, and
|
||||||
|
@ -417,6 +417,9 @@ static int inv_mpu_probe(struct i2c_client *client,
|
||||||
#else
|
#else
|
||||||
pr_info("Data read from FIFO\n");
|
pr_info("Data read from FIFO\n");
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef TIMER_BASED_BATCHING
|
||||||
|
pr_info("Timer based batching\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
#ifdef KERNEL_VERSION_4_X
|
#ifdef KERNEL_VERSION_4_X
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2012-2017 InvenSense, Inc.
|
* Copyright (C) 2012-2018 InvenSense, Inc.
|
||||||
*
|
*
|
||||||
* This software is licensed under the terms of the GNU General Public
|
* This software is licensed under the terms of the GNU General Public
|
||||||
* License version 2, as published by the Free Software Foundation, and
|
* License version 2, as published by the Free Software Foundation, and
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
#include "iam20680/inv_mpu_iio_reg_20680.h"
|
#include "iam20680/inv_mpu_iio_reg_20680.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define INVENSENSE_DRIVER_VERSION "8.1.1-simple-test1a"
|
#define INVENSENSE_DRIVER_VERSION "8.1.2-simple-test1"
|
||||||
|
|
||||||
/* #define DEBUG */
|
/* #define DEBUG */
|
||||||
|
|
||||||
|
@ -722,6 +722,12 @@ struct inv_mpu_state {
|
||||||
struct wake_lock wake_lock;
|
struct wake_lock wake_lock;
|
||||||
#else
|
#else
|
||||||
struct wakeup_source wake_lock;
|
struct wakeup_source wake_lock;
|
||||||
|
#endif
|
||||||
|
#ifdef TIMER_BASED_BATCHING
|
||||||
|
struct hrtimer hr_batch_timer;
|
||||||
|
u64 batch_timeout;
|
||||||
|
bool is_batch_timer_running;
|
||||||
|
struct work_struct batch_work;
|
||||||
#endif
|
#endif
|
||||||
struct i2c_client *client;
|
struct i2c_client *client;
|
||||||
struct mpu_platform_data plat_data;
|
struct mpu_platform_data plat_data;
|
||||||
|
@ -1018,7 +1024,9 @@ int inv_create_dmp_sysfs(struct iio_dev *ind);
|
||||||
int inv_check_chip_type(struct iio_dev *indio_dev, const char *name);
|
int inv_check_chip_type(struct iio_dev *indio_dev, const char *name);
|
||||||
int inv_write_compass_matrix(struct inv_mpu_state *st, int *adj);
|
int inv_write_compass_matrix(struct inv_mpu_state *st, int *adj);
|
||||||
irqreturn_t inv_read_fifo(int irq, void *dev_id);
|
irqreturn_t inv_read_fifo(int irq, void *dev_id);
|
||||||
|
#ifdef TIMER_BASED_BATCHING
|
||||||
|
void inv_batch_work(struct work_struct *work);
|
||||||
|
#endif
|
||||||
int inv_flush_batch_data(struct iio_dev *indio_dev, int data);
|
int inv_flush_batch_data(struct iio_dev *indio_dev, int data);
|
||||||
static inline int mpu_memory_write(struct inv_mpu_state *st, u8 mpu_addr,
|
static inline int mpu_memory_write(struct inv_mpu_state *st, u8 mpu_addr,
|
||||||
u16 mem_addr, u32 len, u8 const *data)
|
u16 mem_addr, u32 len, u8 const *data)
|
||||||
|
|
|
@ -533,6 +533,23 @@ static irqreturn_t inv_irq_handler(int irq, void *dev_id)
|
||||||
return IRQ_WAKE_THREAD;
|
return IRQ_WAKE_THREAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TIMER_BASED_BATCHING
|
||||||
|
static enum hrtimer_restart inv_batch_timer_handler(struct hrtimer *timer)
|
||||||
|
{
|
||||||
|
struct inv_mpu_state *st =
|
||||||
|
container_of(timer, struct inv_mpu_state, hr_batch_timer);
|
||||||
|
|
||||||
|
if (st->chip_config.gyro_enable || st->chip_config.accel_enable) {
|
||||||
|
hrtimer_forward_now(&st->hr_batch_timer,
|
||||||
|
ns_to_ktime(st->batch_timeout));
|
||||||
|
schedule_work(&st->batch_work);
|
||||||
|
return HRTIMER_RESTART;
|
||||||
|
}
|
||||||
|
st->is_batch_timer_running = 0;
|
||||||
|
return HRTIMER_NORESTART;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void inv_mpu_unconfigure_ring(struct iio_dev *indio_dev)
|
void inv_mpu_unconfigure_ring(struct iio_dev *indio_dev)
|
||||||
{
|
{
|
||||||
struct inv_mpu_state *st = iio_priv(indio_dev);
|
struct inv_mpu_state *st = iio_priv(indio_dev);
|
||||||
|
@ -569,6 +586,12 @@ int inv_mpu_configure_ring(struct iio_dev *indio_dev)
|
||||||
struct inv_mpu_state *st = iio_priv(indio_dev);
|
struct inv_mpu_state *st = iio_priv(indio_dev);
|
||||||
struct iio_buffer *ring;
|
struct iio_buffer *ring;
|
||||||
|
|
||||||
|
#ifdef TIMER_BASED_BATCHING
|
||||||
|
/* configure hrtimer */
|
||||||
|
hrtimer_init(&st->hr_batch_timer, CLOCK_BOOTTIME, HRTIMER_MODE_REL);
|
||||||
|
st->hr_batch_timer.function = inv_batch_timer_handler;
|
||||||
|
INIT_WORK(&st->batch_work, inv_batch_work);
|
||||||
|
#endif
|
||||||
#ifdef KERNEL_VERSION_4_X
|
#ifdef KERNEL_VERSION_4_X
|
||||||
ring = devm_iio_kfifo_allocate(st->dev);
|
ring = devm_iio_kfifo_allocate(st->dev);
|
||||||
if (!ring)
|
if (!ring)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2012-2017 InvenSense, Inc.
|
* Copyright (C) 2012-2018 InvenSense, Inc.
|
||||||
*
|
*
|
||||||
* This software is licensed under the terms of the GNU General Public
|
* This software is licensed under the terms of the GNU General Public
|
||||||
* License version 2, as published by the Free Software Foundation, and
|
* License version 2, as published by the Free Software Foundation, and
|
||||||
|
@ -271,6 +271,9 @@ static int inv_mpu_probe(struct spi_device *spi)
|
||||||
#else
|
#else
|
||||||
pr_info("Data read from FIFO\n");
|
pr_info("Data read from FIFO\n");
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef TIMER_BASED_BATCHING
|
||||||
|
pr_info("Timer based batching\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
#ifdef KERNEL_VERSION_4_X
|
#ifdef KERNEL_VERSION_4_X
|
||||||
|
|
Loading…
Add table
Reference in a new issue