|
@@ -27,6 +27,7 @@
|
|
|
#include <linux/iio/sysfs.h>
|
|
|
#include <linux/iio/buffer.h>
|
|
|
#include <linux/iio/trigger.h>
|
|
|
+#include <linux/iio/events.h>
|
|
|
#include <linux/iio/trigger_consumer.h>
|
|
|
#include <linux/iio/triggered_buffer.h>
|
|
|
#include <linux/iio/accel/kxcjk_1013.h>
|
|
@@ -75,16 +76,30 @@
|
|
|
|
|
|
#define KXCJK1013_SLEEP_DELAY_MS 2000
|
|
|
|
|
|
+#define KXCJK1013_REG_INT_SRC2_BIT_ZP BIT(0)
|
|
|
+#define KXCJK1013_REG_INT_SRC2_BIT_ZN BIT(1)
|
|
|
+#define KXCJK1013_REG_INT_SRC2_BIT_YP BIT(2)
|
|
|
+#define KXCJK1013_REG_INT_SRC2_BIT_YN BIT(3)
|
|
|
+#define KXCJK1013_REG_INT_SRC2_BIT_XP BIT(4)
|
|
|
+#define KXCJK1013_REG_INT_SRC2_BIT_XN BIT(5)
|
|
|
+
|
|
|
+#define KXCJK1013_DEFAULT_WAKE_THRES 1
|
|
|
+
|
|
|
struct kxcjk1013_data {
|
|
|
struct i2c_client *client;
|
|
|
- struct iio_trigger *trig;
|
|
|
- bool trig_mode;
|
|
|
+ struct iio_trigger *dready_trig;
|
|
|
+ struct iio_trigger *motion_trig;
|
|
|
struct mutex mutex;
|
|
|
s16 buffer[8];
|
|
|
u8 odr_bits;
|
|
|
u8 range;
|
|
|
+ int wake_thres;
|
|
|
+ int wake_dur;
|
|
|
bool active_high_intr;
|
|
|
- bool trigger_on;
|
|
|
+ bool dready_trigger_on;
|
|
|
+ int ev_enable_state;
|
|
|
+ bool motion_trigger_on;
|
|
|
+ int64_t timestamp;
|
|
|
};
|
|
|
|
|
|
enum kxcjk1013_axis {
|
|
@@ -131,6 +146,23 @@ static const struct {
|
|
|
{19163, 1, 0},
|
|
|
{38326, 0, 1} };
|
|
|
|
|
|
+static const struct {
|
|
|
+ int val;
|
|
|
+ int val2;
|
|
|
+ int odr_bits;
|
|
|
+} wake_odr_data_rate_table[] = { {0, 781000, 0x00},
|
|
|
+ {1, 563000, 0x01},
|
|
|
+ {3, 125000, 0x02},
|
|
|
+ {6, 250000, 0x03},
|
|
|
+ {12, 500000, 0x04},
|
|
|
+ {25, 0, 0x05},
|
|
|
+ {50, 0, 0x06},
|
|
|
+ {100, 0, 0x06},
|
|
|
+ {200, 0, 0x06},
|
|
|
+ {400, 0, 0x06},
|
|
|
+ {800, 0, 0x06},
|
|
|
+ {1600, 0, 0x06} };
|
|
|
+
|
|
|
static int kxcjk1013_set_mode(struct kxcjk1013_data *data,
|
|
|
enum kxcjk1013_mode mode)
|
|
|
{
|
|
@@ -270,6 +302,8 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
|
|
|
if (ret < 0)
|
|
|
return ret;
|
|
|
|
|
|
+ data->wake_thres = KXCJK1013_DEFAULT_WAKE_THRES;
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -304,8 +338,96 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int kxcjk1013_chip_setup_interrupt(struct kxcjk1013_data *data,
|
|
|
- bool status)
|
|
|
+static int kxcjk1013_chip_update_thresholds(struct kxcjk1013_data *data)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = i2c_smbus_write_byte_data(data->client,
|
|
|
+ KXCJK1013_REG_WAKE_TIMER,
|
|
|
+ data->wake_dur);
|
|
|
+ if (ret < 0) {
|
|
|
+ dev_err(&data->client->dev,
|
|
|
+ "Error writing reg_wake_timer\n");
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = i2c_smbus_write_byte_data(data->client,
|
|
|
+ KXCJK1013_REG_WAKE_THRES,
|
|
|
+ data->wake_thres);
|
|
|
+ if (ret < 0) {
|
|
|
+ dev_err(&data->client->dev, "Error writing reg_wake_thres\n");
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int kxcjk1013_setup_any_motion_interrupt(struct kxcjk1013_data *data,
|
|
|
+ bool status)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ enum kxcjk1013_mode store_mode;
|
|
|
+
|
|
|
+ ret = kxcjk1013_get_mode(data, &store_mode);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ /* This is requirement by spec to change state to STANDBY */
|
|
|
+ ret = kxcjk1013_set_mode(data, STANDBY);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ ret = kxcjk1013_chip_update_thresholds(data);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_CTRL1);
|
|
|
+ if (ret < 0) {
|
|
|
+ dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n");
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (status)
|
|
|
+ ret |= KXCJK1013_REG_INT_REG1_BIT_IEN;
|
|
|
+ else
|
|
|
+ ret &= ~KXCJK1013_REG_INT_REG1_BIT_IEN;
|
|
|
+
|
|
|
+ ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1,
|
|
|
+ ret);
|
|
|
+ if (ret < 0) {
|
|
|
+ dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n");
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1);
|
|
|
+ if (ret < 0) {
|
|
|
+ dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (status)
|
|
|
+ ret |= KXCJK1013_REG_CTRL1_BIT_WUFE;
|
|
|
+ else
|
|
|
+ ret &= ~KXCJK1013_REG_CTRL1_BIT_WUFE;
|
|
|
+
|
|
|
+ ret = i2c_smbus_write_byte_data(data->client,
|
|
|
+ KXCJK1013_REG_CTRL1, ret);
|
|
|
+ if (ret < 0) {
|
|
|
+ dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (store_mode == OPERATION) {
|
|
|
+ ret = kxcjk1013_set_mode(data, OPERATION);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int kxcjk1013_setup_new_data_interrupt(struct kxcjk1013_data *data,
|
|
|
+ bool status)
|
|
|
{
|
|
|
int ret;
|
|
|
enum kxcjk1013_mode store_mode;
|
|
@@ -378,6 +500,20 @@ static int kxcjk1013_convert_freq_to_bit(int val, int val2)
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
+static int kxcjk1013_convert_wake_odr_to_bit(int val, int val2)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < ARRAY_SIZE(wake_odr_data_rate_table); ++i) {
|
|
|
+ if (wake_odr_data_rate_table[i].val == val &&
|
|
|
+ wake_odr_data_rate_table[i].val2 == val2) {
|
|
|
+ return wake_odr_data_rate_table[i].odr_bits;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2)
|
|
|
{
|
|
|
int ret;
|
|
@@ -406,6 +542,17 @@ static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2)
|
|
|
|
|
|
data->odr_bits = odr_bits;
|
|
|
|
|
|
+ odr_bits = kxcjk1013_convert_wake_odr_to_bit(val, val2);
|
|
|
+ if (odr_bits < 0)
|
|
|
+ return odr_bits;
|
|
|
+
|
|
|
+ ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_CTRL2,
|
|
|
+ odr_bits);
|
|
|
+ if (ret < 0) {
|
|
|
+ dev_err(&data->client->dev, "Error writing reg_ctrl2\n");
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
if (store_mode == OPERATION) {
|
|
|
ret = kxcjk1013_set_mode(data, OPERATION);
|
|
|
if (ret < 0)
|
|
@@ -557,12 +704,120 @@ static int kxcjk1013_write_raw(struct iio_dev *indio_dev,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static int kxcjk1013_read_event(struct iio_dev *indio_dev,
|
|
|
+ const struct iio_chan_spec *chan,
|
|
|
+ enum iio_event_type type,
|
|
|
+ enum iio_event_direction dir,
|
|
|
+ enum iio_event_info info,
|
|
|
+ int *val, int *val2)
|
|
|
+{
|
|
|
+ struct kxcjk1013_data *data = iio_priv(indio_dev);
|
|
|
+
|
|
|
+ *val2 = 0;
|
|
|
+ switch (info) {
|
|
|
+ case IIO_EV_INFO_VALUE:
|
|
|
+ *val = data->wake_thres;
|
|
|
+ break;
|
|
|
+ case IIO_EV_INFO_PERIOD:
|
|
|
+ *val = data->wake_dur;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return IIO_VAL_INT;
|
|
|
+}
|
|
|
+
|
|
|
+static int kxcjk1013_write_event(struct iio_dev *indio_dev,
|
|
|
+ const struct iio_chan_spec *chan,
|
|
|
+ enum iio_event_type type,
|
|
|
+ enum iio_event_direction dir,
|
|
|
+ enum iio_event_info info,
|
|
|
+ int val, int val2)
|
|
|
+{
|
|
|
+ struct kxcjk1013_data *data = iio_priv(indio_dev);
|
|
|
+
|
|
|
+ if (data->ev_enable_state)
|
|
|
+ return -EBUSY;
|
|
|
+
|
|
|
+ switch (info) {
|
|
|
+ case IIO_EV_INFO_VALUE:
|
|
|
+ data->wake_thres = val;
|
|
|
+ break;
|
|
|
+ case IIO_EV_INFO_PERIOD:
|
|
|
+ data->wake_dur = val;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int kxcjk1013_read_event_config(struct iio_dev *indio_dev,
|
|
|
+ const struct iio_chan_spec *chan,
|
|
|
+ enum iio_event_type type,
|
|
|
+ enum iio_event_direction dir)
|
|
|
+{
|
|
|
+
|
|
|
+ struct kxcjk1013_data *data = iio_priv(indio_dev);
|
|
|
+
|
|
|
+ return data->ev_enable_state;
|
|
|
+}
|
|
|
+
|
|
|
+static int kxcjk1013_write_event_config(struct iio_dev *indio_dev,
|
|
|
+ const struct iio_chan_spec *chan,
|
|
|
+ enum iio_event_type type,
|
|
|
+ enum iio_event_direction dir,
|
|
|
+ int state)
|
|
|
+{
|
|
|
+ struct kxcjk1013_data *data = iio_priv(indio_dev);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (state && data->ev_enable_state)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ mutex_lock(&data->mutex);
|
|
|
+
|
|
|
+ if (!state && data->motion_trigger_on) {
|
|
|
+ data->ev_enable_state = 0;
|
|
|
+ mutex_unlock(&data->mutex);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We will expect the enable and disable to do operation in
|
|
|
+ * in reverse order. This will happen here anyway as our
|
|
|
+ * resume operation uses sync mode runtime pm calls, the
|
|
|
+ * suspend operation will be delayed by autosuspend delay
|
|
|
+ * So the disable operation will still happen in reverse of
|
|
|
+ * enable operation. When runtime pm is disabled the mode
|
|
|
+ * is always on so sequence doesn't matter
|
|
|
+ */
|
|
|
+ ret = kxcjk1013_set_power_state(data, state);
|
|
|
+ if (ret < 0) {
|
|
|
+ mutex_unlock(&data->mutex);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = kxcjk1013_setup_any_motion_interrupt(data, state);
|
|
|
+ if (ret < 0) {
|
|
|
+ mutex_unlock(&data->mutex);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ data->ev_enable_state = state;
|
|
|
+ mutex_unlock(&data->mutex);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int kxcjk1013_validate_trigger(struct iio_dev *indio_dev,
|
|
|
struct iio_trigger *trig)
|
|
|
{
|
|
|
struct kxcjk1013_data *data = iio_priv(indio_dev);
|
|
|
|
|
|
- if (data->trig != trig)
|
|
|
+ if (data->dready_trig != trig && data->motion_trig != trig)
|
|
|
return -EINVAL;
|
|
|
|
|
|
return 0;
|
|
@@ -583,6 +838,14 @@ static const struct attribute_group kxcjk1013_attrs_group = {
|
|
|
.attrs = kxcjk1013_attributes,
|
|
|
};
|
|
|
|
|
|
+static const struct iio_event_spec kxcjk1013_event = {
|
|
|
+ .type = IIO_EV_TYPE_THRESH,
|
|
|
+ .dir = IIO_EV_DIR_RISING | IIO_EV_DIR_FALLING,
|
|
|
+ .mask_separate = BIT(IIO_EV_INFO_VALUE) |
|
|
|
+ BIT(IIO_EV_INFO_ENABLE) |
|
|
|
+ BIT(IIO_EV_INFO_PERIOD)
|
|
|
+};
|
|
|
+
|
|
|
#define KXCJK1013_CHANNEL(_axis) { \
|
|
|
.type = IIO_ACCEL, \
|
|
|
.modified = 1, \
|
|
@@ -598,6 +861,8 @@ static const struct attribute_group kxcjk1013_attrs_group = {
|
|
|
.shift = 4, \
|
|
|
.endianness = IIO_CPU, \
|
|
|
}, \
|
|
|
+ .event_spec = &kxcjk1013_event, \
|
|
|
+ .num_event_specs = 1 \
|
|
|
}
|
|
|
|
|
|
static const struct iio_chan_spec kxcjk1013_channels[] = {
|
|
@@ -611,6 +876,10 @@ static const struct iio_info kxcjk1013_info = {
|
|
|
.attrs = &kxcjk1013_attrs_group,
|
|
|
.read_raw = kxcjk1013_read_raw,
|
|
|
.write_raw = kxcjk1013_write_raw,
|
|
|
+ .read_event_value = kxcjk1013_read_event,
|
|
|
+ .write_event_value = kxcjk1013_write_event,
|
|
|
+ .write_event_config = kxcjk1013_write_event_config,
|
|
|
+ .read_event_config = kxcjk1013_read_event_config,
|
|
|
.validate_trigger = kxcjk1013_validate_trigger,
|
|
|
.driver_module = THIS_MODULE,
|
|
|
};
|
|
@@ -636,7 +905,7 @@ static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p)
|
|
|
mutex_unlock(&data->mutex);
|
|
|
|
|
|
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
|
|
|
- pf->timestamp);
|
|
|
+ data->timestamp);
|
|
|
err:
|
|
|
iio_trigger_notify_done(indio_dev->trig);
|
|
|
|
|
@@ -665,19 +934,32 @@ static int kxcjk1013_data_rdy_trigger_set_state(struct iio_trigger *trig,
|
|
|
struct kxcjk1013_data *data = iio_priv(indio_dev);
|
|
|
int ret;
|
|
|
|
|
|
- if (state && data->trigger_on)
|
|
|
+ mutex_lock(&data->mutex);
|
|
|
+
|
|
|
+ if (!state && data->ev_enable_state && data->motion_trigger_on) {
|
|
|
+ data->motion_trigger_on = false;
|
|
|
+ mutex_unlock(&data->mutex);
|
|
|
return 0;
|
|
|
+ }
|
|
|
|
|
|
- mutex_lock(&data->mutex);
|
|
|
- ret = kxcjk1013_chip_setup_interrupt(data, state);
|
|
|
- if (!ret) {
|
|
|
- ret = kxcjk1013_set_power_state(data, state);
|
|
|
- if (ret < 0) {
|
|
|
- mutex_unlock(&data->mutex);
|
|
|
- return ret;
|
|
|
- }
|
|
|
+ ret = kxcjk1013_set_power_state(data, state);
|
|
|
+ if (ret < 0) {
|
|
|
+ mutex_unlock(&data->mutex);
|
|
|
+ return ret;
|
|
|
}
|
|
|
- data->trigger_on = state;
|
|
|
+ if (data->motion_trig == trig)
|
|
|
+ ret = kxcjk1013_setup_any_motion_interrupt(data, state);
|
|
|
+ else
|
|
|
+ ret = kxcjk1013_setup_new_data_interrupt(data, state);
|
|
|
+ if (ret < 0) {
|
|
|
+ mutex_unlock(&data->mutex);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ if (data->motion_trig == trig)
|
|
|
+ data->motion_trigger_on = state;
|
|
|
+ else
|
|
|
+ data->dready_trigger_on = state;
|
|
|
+
|
|
|
mutex_unlock(&data->mutex);
|
|
|
|
|
|
return 0;
|
|
@@ -689,6 +971,109 @@ static const struct iio_trigger_ops kxcjk1013_trigger_ops = {
|
|
|
.owner = THIS_MODULE,
|
|
|
};
|
|
|
|
|
|
+static irqreturn_t kxcjk1013_event_handler(int irq, void *private)
|
|
|
+{
|
|
|
+ struct iio_dev *indio_dev = private;
|
|
|
+ struct kxcjk1013_data *data = iio_priv(indio_dev);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_SRC1);
|
|
|
+ if (ret < 0) {
|
|
|
+ dev_err(&data->client->dev, "Error reading reg_int_src1\n");
|
|
|
+ goto ack_intr;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ret & 0x02) {
|
|
|
+ ret = i2c_smbus_read_byte_data(data->client,
|
|
|
+ KXCJK1013_REG_INT_SRC2);
|
|
|
+ if (ret < 0) {
|
|
|
+ dev_err(&data->client->dev,
|
|
|
+ "Error reading reg_int_src2\n");
|
|
|
+ goto ack_intr;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ret & KXCJK1013_REG_INT_SRC2_BIT_XN)
|
|
|
+ iio_push_event(indio_dev,
|
|
|
+ IIO_MOD_EVENT_CODE(IIO_ACCEL,
|
|
|
+ 0,
|
|
|
+ IIO_MOD_X,
|
|
|
+ IIO_EV_TYPE_THRESH,
|
|
|
+ IIO_EV_DIR_FALLING),
|
|
|
+ data->timestamp);
|
|
|
+ if (ret & KXCJK1013_REG_INT_SRC2_BIT_XP)
|
|
|
+ iio_push_event(indio_dev,
|
|
|
+ IIO_MOD_EVENT_CODE(IIO_ACCEL,
|
|
|
+ 0,
|
|
|
+ IIO_MOD_X,
|
|
|
+ IIO_EV_TYPE_THRESH,
|
|
|
+ IIO_EV_DIR_RISING),
|
|
|
+ data->timestamp);
|
|
|
+
|
|
|
+
|
|
|
+ if (ret & KXCJK1013_REG_INT_SRC2_BIT_YN)
|
|
|
+ iio_push_event(indio_dev,
|
|
|
+ IIO_MOD_EVENT_CODE(IIO_ACCEL,
|
|
|
+ 0,
|
|
|
+ IIO_MOD_Y,
|
|
|
+ IIO_EV_TYPE_THRESH,
|
|
|
+ IIO_EV_DIR_FALLING),
|
|
|
+ data->timestamp);
|
|
|
+ if (ret & KXCJK1013_REG_INT_SRC2_BIT_YP)
|
|
|
+ iio_push_event(indio_dev,
|
|
|
+ IIO_MOD_EVENT_CODE(IIO_ACCEL,
|
|
|
+ 0,
|
|
|
+ IIO_MOD_Y,
|
|
|
+ IIO_EV_TYPE_THRESH,
|
|
|
+ IIO_EV_DIR_RISING),
|
|
|
+ data->timestamp);
|
|
|
+
|
|
|
+ if (ret & KXCJK1013_REG_INT_SRC2_BIT_ZN)
|
|
|
+ iio_push_event(indio_dev,
|
|
|
+ IIO_MOD_EVENT_CODE(IIO_ACCEL,
|
|
|
+ 0,
|
|
|
+ IIO_MOD_Z,
|
|
|
+ IIO_EV_TYPE_THRESH,
|
|
|
+ IIO_EV_DIR_FALLING),
|
|
|
+ data->timestamp);
|
|
|
+ if (ret & KXCJK1013_REG_INT_SRC2_BIT_ZP)
|
|
|
+ iio_push_event(indio_dev,
|
|
|
+ IIO_MOD_EVENT_CODE(IIO_ACCEL,
|
|
|
+ 0,
|
|
|
+ IIO_MOD_Z,
|
|
|
+ IIO_EV_TYPE_THRESH,
|
|
|
+ IIO_EV_DIR_RISING),
|
|
|
+ data->timestamp);
|
|
|
+ }
|
|
|
+
|
|
|
+ack_intr:
|
|
|
+ if (data->dready_trigger_on)
|
|
|
+ return IRQ_HANDLED;
|
|
|
+
|
|
|
+ ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_REL);
|
|
|
+ if (ret < 0)
|
|
|
+ dev_err(&data->client->dev, "Error reading reg_int_rel\n");
|
|
|
+
|
|
|
+ return IRQ_HANDLED;
|
|
|
+}
|
|
|
+
|
|
|
+static irqreturn_t kxcjk1013_data_rdy_trig_poll(int irq, void *private)
|
|
|
+{
|
|
|
+ struct iio_dev *indio_dev = private;
|
|
|
+ struct kxcjk1013_data *data = iio_priv(indio_dev);
|
|
|
+
|
|
|
+ data->timestamp = iio_get_time_ns();
|
|
|
+
|
|
|
+ if (data->dready_trigger_on)
|
|
|
+ iio_trigger_poll(data->dready_trig);
|
|
|
+ else if (data->motion_trigger_on)
|
|
|
+ iio_trigger_poll(data->motion_trig);
|
|
|
+
|
|
|
+ if (data->ev_enable_state)
|
|
|
+ return IRQ_WAKE_THREAD;
|
|
|
+ else
|
|
|
+ return IRQ_HANDLED;
|
|
|
+}
|
|
|
+
|
|
|
static int kxcjk1013_acpi_gpio_probe(struct i2c_client *client,
|
|
|
struct kxcjk1013_data *data)
|
|
|
{
|
|
@@ -731,7 +1116,6 @@ static int kxcjk1013_probe(struct i2c_client *client,
|
|
|
{
|
|
|
struct kxcjk1013_data *data;
|
|
|
struct iio_dev *indio_dev;
|
|
|
- struct iio_trigger *trig = NULL;
|
|
|
struct kxcjk_1013_platform_data *pdata;
|
|
|
int ret;
|
|
|
|
|
@@ -766,33 +1150,46 @@ static int kxcjk1013_probe(struct i2c_client *client,
|
|
|
client->irq = kxcjk1013_acpi_gpio_probe(client, data);
|
|
|
|
|
|
if (client->irq >= 0) {
|
|
|
- trig = iio_trigger_alloc("%s-dev%d", indio_dev->name,
|
|
|
- indio_dev->id);
|
|
|
- if (!trig)
|
|
|
- return -ENOMEM;
|
|
|
+ ret = devm_request_threaded_irq(&client->dev, client->irq,
|
|
|
+ kxcjk1013_data_rdy_trig_poll,
|
|
|
+ kxcjk1013_event_handler,
|
|
|
+ IRQF_TRIGGER_RISING,
|
|
|
+ KXCJK1013_IRQ_NAME,
|
|
|
+ indio_dev);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
|
|
|
- data->trig_mode = true;
|
|
|
+ data->dready_trig = devm_iio_trigger_alloc(&client->dev,
|
|
|
+ "%s-dev%d",
|
|
|
+ indio_dev->name,
|
|
|
+ indio_dev->id);
|
|
|
+ if (!data->dready_trig)
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
- ret = devm_request_irq(&client->dev, client->irq,
|
|
|
- iio_trigger_generic_data_rdy_poll,
|
|
|
- IRQF_TRIGGER_RISING,
|
|
|
- KXCJK1013_IRQ_NAME,
|
|
|
- trig);
|
|
|
- if (ret) {
|
|
|
- dev_err(&client->dev, "unable to request IRQ\n");
|
|
|
- goto err_trigger_free;
|
|
|
- }
|
|
|
+ data->motion_trig = devm_iio_trigger_alloc(&client->dev,
|
|
|
+ "%s-any-motion-dev%d",
|
|
|
+ indio_dev->name,
|
|
|
+ indio_dev->id);
|
|
|
+ if (!data->motion_trig)
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
- trig->dev.parent = &client->dev;
|
|
|
- trig->ops = &kxcjk1013_trigger_ops;
|
|
|
- iio_trigger_set_drvdata(trig, indio_dev);
|
|
|
- data->trig = trig;
|
|
|
- indio_dev->trig = trig;
|
|
|
+ data->dready_trig->dev.parent = &client->dev;
|
|
|
+ data->dready_trig->ops = &kxcjk1013_trigger_ops;
|
|
|
+ iio_trigger_set_drvdata(data->dready_trig, indio_dev);
|
|
|
+ indio_dev->trig = data->dready_trig;
|
|
|
iio_trigger_get(indio_dev->trig);
|
|
|
-
|
|
|
- ret = iio_trigger_register(trig);
|
|
|
+ ret = iio_trigger_register(data->dready_trig);
|
|
|
if (ret)
|
|
|
- goto err_trigger_free;
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ data->motion_trig->dev.parent = &client->dev;
|
|
|
+ data->motion_trig->ops = &kxcjk1013_trigger_ops;
|
|
|
+ iio_trigger_set_drvdata(data->motion_trig, indio_dev);
|
|
|
+ ret = iio_trigger_register(data->motion_trig);
|
|
|
+ if (ret) {
|
|
|
+ data->motion_trig = NULL;
|
|
|
+ goto err_trigger_unregister;
|
|
|
+ }
|
|
|
|
|
|
ret = iio_triggered_buffer_setup(indio_dev,
|
|
|
&iio_pollfunc_store_time,
|
|
@@ -825,14 +1222,13 @@ static int kxcjk1013_probe(struct i2c_client *client,
|
|
|
err_iio_unregister:
|
|
|
iio_device_unregister(indio_dev);
|
|
|
err_buffer_cleanup:
|
|
|
- if (data->trig_mode)
|
|
|
+ if (data->dready_trig)
|
|
|
iio_triggered_buffer_cleanup(indio_dev);
|
|
|
err_trigger_unregister:
|
|
|
- if (data->trig_mode)
|
|
|
- iio_trigger_unregister(trig);
|
|
|
-err_trigger_free:
|
|
|
- if (data->trig_mode)
|
|
|
- iio_trigger_free(trig);
|
|
|
+ if (data->dready_trig)
|
|
|
+ iio_trigger_unregister(data->dready_trig);
|
|
|
+ if (data->motion_trig)
|
|
|
+ iio_trigger_unregister(data->motion_trig);
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
@@ -848,10 +1244,10 @@ static int kxcjk1013_remove(struct i2c_client *client)
|
|
|
|
|
|
iio_device_unregister(indio_dev);
|
|
|
|
|
|
- if (data->trig_mode) {
|
|
|
+ if (data->dready_trig) {
|
|
|
iio_triggered_buffer_cleanup(indio_dev);
|
|
|
- iio_trigger_unregister(data->trig);
|
|
|
- iio_trigger_free(data->trig);
|
|
|
+ iio_trigger_unregister(data->dready_trig);
|
|
|
+ iio_trigger_unregister(data->motion_trig);
|
|
|
}
|
|
|
|
|
|
mutex_lock(&data->mutex);
|
|
@@ -883,7 +1279,8 @@ static int kxcjk1013_resume(struct device *dev)
|
|
|
|
|
|
mutex_lock(&data->mutex);
|
|
|
/* Check, if the suspend occured while active */
|
|
|
- if (data->trigger_on)
|
|
|
+ if (data->dready_trigger_on || data->motion_trigger_on ||
|
|
|
+ data->ev_enable_state)
|
|
|
ret = kxcjk1013_set_mode(data, OPERATION);
|
|
|
mutex_unlock(&data->mutex);
|
|
|
|