|
@@ -19,6 +19,7 @@
|
|
#include <linux/gpio/consumer.h>
|
|
#include <linux/gpio/consumer.h>
|
|
#include <linux/regmap.h>
|
|
#include <linux/regmap.h>
|
|
#include <linux/pm.h>
|
|
#include <linux/pm.h>
|
|
|
|
+#include <linux/delay.h>
|
|
|
|
|
|
#include <linux/iio/iio.h>
|
|
#include <linux/iio/iio.h>
|
|
#include <linux/iio/buffer.h>
|
|
#include <linux/iio/buffer.h>
|
|
@@ -75,6 +76,7 @@
|
|
#define SX9500_CONVDONE_IRQ BIT(3)
|
|
#define SX9500_CONVDONE_IRQ BIT(3)
|
|
|
|
|
|
#define SX9500_PROXSTAT_SHIFT 4
|
|
#define SX9500_PROXSTAT_SHIFT 4
|
|
|
|
+#define SX9500_COMPSTAT_MASK GENMASK(3, 0)
|
|
|
|
|
|
#define SX9500_NUM_CHANNELS 4
|
|
#define SX9500_NUM_CHANNELS 4
|
|
|
|
|
|
@@ -93,6 +95,9 @@ struct sx9500_data {
|
|
u16 *buffer;
|
|
u16 *buffer;
|
|
/* Remember enabled channels and sample rate during suspend. */
|
|
/* Remember enabled channels and sample rate during suspend. */
|
|
unsigned int suspend_ctrl0;
|
|
unsigned int suspend_ctrl0;
|
|
|
|
+ struct completion completion;
|
|
|
|
+ int data_rdy_users, close_far_users;
|
|
|
|
+ int channel_users[SX9500_NUM_CHANNELS];
|
|
};
|
|
};
|
|
|
|
|
|
static const struct iio_event_spec sx9500_events[] = {
|
|
static const struct iio_event_spec sx9500_events[] = {
|
|
@@ -143,6 +148,10 @@ static const struct {
|
|
{2, 500000},
|
|
{2, 500000},
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static const unsigned int sx9500_scan_period_table[] = {
|
|
|
|
+ 30, 60, 90, 120, 150, 200, 300, 400,
|
|
|
|
+};
|
|
|
|
+
|
|
static const struct regmap_range sx9500_writable_reg_ranges[] = {
|
|
static const struct regmap_range sx9500_writable_reg_ranges[] = {
|
|
regmap_reg_range(SX9500_REG_IRQ_MSK, SX9500_REG_IRQ_MSK),
|
|
regmap_reg_range(SX9500_REG_IRQ_MSK, SX9500_REG_IRQ_MSK),
|
|
regmap_reg_range(SX9500_REG_PROX_CTRL0, SX9500_REG_PROX_CTRL8),
|
|
regmap_reg_range(SX9500_REG_PROX_CTRL0, SX9500_REG_PROX_CTRL8),
|
|
@@ -195,7 +204,67 @@ static const struct regmap_config sx9500_regmap_config = {
|
|
.volatile_table = &sx9500_volatile_regs,
|
|
.volatile_table = &sx9500_volatile_regs,
|
|
};
|
|
};
|
|
|
|
|
|
-static int sx9500_read_proximity(struct sx9500_data *data,
|
|
|
|
|
|
+static int sx9500_inc_users(struct sx9500_data *data, int *counter,
|
|
|
|
+ unsigned int reg, unsigned int bitmask)
|
|
|
|
+{
|
|
|
|
+ (*counter)++;
|
|
|
|
+ if (*counter != 1)
|
|
|
|
+ /* Bit is already active, nothing to do. */
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ return regmap_update_bits(data->regmap, reg, bitmask, bitmask);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int sx9500_dec_users(struct sx9500_data *data, int *counter,
|
|
|
|
+ unsigned int reg, unsigned int bitmask)
|
|
|
|
+{
|
|
|
|
+ (*counter)--;
|
|
|
|
+ if (*counter != 0)
|
|
|
|
+ /* There are more users, do not deactivate. */
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ return regmap_update_bits(data->regmap, reg, bitmask, 0);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int sx9500_inc_chan_users(struct sx9500_data *data, int chan)
|
|
|
|
+{
|
|
|
|
+ return sx9500_inc_users(data, &data->channel_users[chan],
|
|
|
|
+ SX9500_REG_PROX_CTRL0, BIT(chan));
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int sx9500_dec_chan_users(struct sx9500_data *data, int chan)
|
|
|
|
+{
|
|
|
|
+ return sx9500_dec_users(data, &data->channel_users[chan],
|
|
|
|
+ SX9500_REG_PROX_CTRL0, BIT(chan));
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int sx9500_inc_data_rdy_users(struct sx9500_data *data)
|
|
|
|
+{
|
|
|
|
+ return sx9500_inc_users(data, &data->data_rdy_users,
|
|
|
|
+ SX9500_REG_IRQ_MSK, SX9500_CONVDONE_IRQ);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int sx9500_dec_data_rdy_users(struct sx9500_data *data)
|
|
|
|
+{
|
|
|
|
+ return sx9500_dec_users(data, &data->data_rdy_users,
|
|
|
|
+ SX9500_REG_IRQ_MSK, SX9500_CONVDONE_IRQ);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int sx9500_inc_close_far_users(struct sx9500_data *data)
|
|
|
|
+{
|
|
|
|
+ return sx9500_inc_users(data, &data->close_far_users,
|
|
|
|
+ SX9500_REG_IRQ_MSK,
|
|
|
|
+ SX9500_CLOSE_IRQ | SX9500_FAR_IRQ);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int sx9500_dec_close_far_users(struct sx9500_data *data)
|
|
|
|
+{
|
|
|
|
+ return sx9500_dec_users(data, &data->close_far_users,
|
|
|
|
+ SX9500_REG_IRQ_MSK,
|
|
|
|
+ SX9500_CLOSE_IRQ | SX9500_FAR_IRQ);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int sx9500_read_prox_data(struct sx9500_data *data,
|
|
const struct iio_chan_spec *chan,
|
|
const struct iio_chan_spec *chan,
|
|
int *val)
|
|
int *val)
|
|
{
|
|
{
|
|
@@ -215,6 +284,79 @@ static int sx9500_read_proximity(struct sx9500_data *data,
|
|
return IIO_VAL_INT;
|
|
return IIO_VAL_INT;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * If we have no interrupt support, we have to wait for a scan period
|
|
|
|
+ * after enabling a channel to get a result.
|
|
|
|
+ */
|
|
|
|
+static int sx9500_wait_for_sample(struct sx9500_data *data)
|
|
|
|
+{
|
|
|
|
+ int ret;
|
|
|
|
+ unsigned int val;
|
|
|
|
+
|
|
|
|
+ ret = regmap_read(data->regmap, SX9500_REG_PROX_CTRL0, &val);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ val = (val & SX9500_SCAN_PERIOD_MASK) >> SX9500_SCAN_PERIOD_SHIFT;
|
|
|
|
+
|
|
|
|
+ msleep(sx9500_scan_period_table[val]);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int sx9500_read_proximity(struct sx9500_data *data,
|
|
|
|
+ const struct iio_chan_spec *chan,
|
|
|
|
+ int *val)
|
|
|
|
+{
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ mutex_lock(&data->mutex);
|
|
|
|
+
|
|
|
|
+ ret = sx9500_inc_chan_users(data, chan->channel);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ ret = sx9500_inc_data_rdy_users(data);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ goto out_dec_chan;
|
|
|
|
+
|
|
|
|
+ mutex_unlock(&data->mutex);
|
|
|
|
+
|
|
|
|
+ if (data->client->irq > 0)
|
|
|
|
+ ret = wait_for_completion_interruptible(&data->completion);
|
|
|
|
+ else
|
|
|
|
+ ret = sx9500_wait_for_sample(data);
|
|
|
|
+
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ mutex_lock(&data->mutex);
|
|
|
|
+
|
|
|
|
+ ret = sx9500_read_prox_data(data, chan, val);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ ret = sx9500_dec_chan_users(data, chan->channel);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ ret = sx9500_dec_data_rdy_users(data);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ ret = IIO_VAL_INT;
|
|
|
|
+
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+out_dec_chan:
|
|
|
|
+ sx9500_dec_chan_users(data, chan->channel);
|
|
|
|
+out:
|
|
|
|
+ mutex_unlock(&data->mutex);
|
|
|
|
+ reinit_completion(&data->completion);
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
static int sx9500_read_samp_freq(struct sx9500_data *data,
|
|
static int sx9500_read_samp_freq(struct sx9500_data *data,
|
|
int *val, int *val2)
|
|
int *val, int *val2)
|
|
{
|
|
{
|
|
@@ -240,7 +382,6 @@ static int sx9500_read_raw(struct iio_dev *indio_dev,
|
|
int *val, int *val2, long mask)
|
|
int *val, int *val2, long mask)
|
|
{
|
|
{
|
|
struct sx9500_data *data = iio_priv(indio_dev);
|
|
struct sx9500_data *data = iio_priv(indio_dev);
|
|
- int ret;
|
|
|
|
|
|
|
|
switch (chan->type) {
|
|
switch (chan->type) {
|
|
case IIO_PROXIMITY:
|
|
case IIO_PROXIMITY:
|
|
@@ -248,10 +389,7 @@ static int sx9500_read_raw(struct iio_dev *indio_dev,
|
|
case IIO_CHAN_INFO_RAW:
|
|
case IIO_CHAN_INFO_RAW:
|
|
if (iio_buffer_enabled(indio_dev))
|
|
if (iio_buffer_enabled(indio_dev))
|
|
return -EBUSY;
|
|
return -EBUSY;
|
|
- mutex_lock(&data->mutex);
|
|
|
|
- ret = sx9500_read_proximity(data, chan, val);
|
|
|
|
- mutex_unlock(&data->mutex);
|
|
|
|
- return ret;
|
|
|
|
|
|
+ return sx9500_read_proximity(data, chan, val);
|
|
case IIO_CHAN_INFO_SAMP_FREQ:
|
|
case IIO_CHAN_INFO_SAMP_FREQ:
|
|
return sx9500_read_samp_freq(data, val, val2);
|
|
return sx9500_read_samp_freq(data, val, val2);
|
|
default:
|
|
default:
|
|
@@ -322,28 +460,16 @@ static irqreturn_t sx9500_irq_handler(int irq, void *private)
|
|
return IRQ_WAKE_THREAD;
|
|
return IRQ_WAKE_THREAD;
|
|
}
|
|
}
|
|
|
|
|
|
-static irqreturn_t sx9500_irq_thread_handler(int irq, void *private)
|
|
|
|
|
|
+static void sx9500_push_events(struct iio_dev *indio_dev)
|
|
{
|
|
{
|
|
- struct iio_dev *indio_dev = private;
|
|
|
|
- struct sx9500_data *data = iio_priv(indio_dev);
|
|
|
|
int ret;
|
|
int ret;
|
|
unsigned int val, chan;
|
|
unsigned int val, chan;
|
|
-
|
|
|
|
- mutex_lock(&data->mutex);
|
|
|
|
-
|
|
|
|
- ret = regmap_read(data->regmap, SX9500_REG_IRQ_SRC, &val);
|
|
|
|
- if (ret < 0) {
|
|
|
|
- dev_err(&data->client->dev, "i2c transfer error in irq\n");
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (!(val & (SX9500_CLOSE_IRQ | SX9500_FAR_IRQ)))
|
|
|
|
- goto out;
|
|
|
|
|
|
+ struct sx9500_data *data = iio_priv(indio_dev);
|
|
|
|
|
|
ret = regmap_read(data->regmap, SX9500_REG_STAT, &val);
|
|
ret = regmap_read(data->regmap, SX9500_REG_STAT, &val);
|
|
if (ret < 0) {
|
|
if (ret < 0) {
|
|
dev_err(&data->client->dev, "i2c transfer error in irq\n");
|
|
dev_err(&data->client->dev, "i2c transfer error in irq\n");
|
|
- goto out;
|
|
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
|
|
val >>= SX9500_PROXSTAT_SHIFT;
|
|
val >>= SX9500_PROXSTAT_SHIFT;
|
|
@@ -358,15 +484,34 @@ static irqreturn_t sx9500_irq_thread_handler(int irq, void *private)
|
|
/* No change on this channel. */
|
|
/* No change on this channel. */
|
|
continue;
|
|
continue;
|
|
|
|
|
|
- dir = new_prox ? IIO_EV_DIR_FALLING :
|
|
|
|
- IIO_EV_DIR_RISING;
|
|
|
|
- ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY,
|
|
|
|
- chan,
|
|
|
|
- IIO_EV_TYPE_THRESH,
|
|
|
|
- dir);
|
|
|
|
|
|
+ dir = new_prox ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING;
|
|
|
|
+ ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan,
|
|
|
|
+ IIO_EV_TYPE_THRESH, dir);
|
|
iio_push_event(indio_dev, ev, iio_get_time_ns());
|
|
iio_push_event(indio_dev, ev, iio_get_time_ns());
|
|
data->prox_stat[chan] = new_prox;
|
|
data->prox_stat[chan] = new_prox;
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static irqreturn_t sx9500_irq_thread_handler(int irq, void *private)
|
|
|
|
+{
|
|
|
|
+ struct iio_dev *indio_dev = private;
|
|
|
|
+ struct sx9500_data *data = iio_priv(indio_dev);
|
|
|
|
+ int ret;
|
|
|
|
+ unsigned int val;
|
|
|
|
+
|
|
|
|
+ mutex_lock(&data->mutex);
|
|
|
|
+
|
|
|
|
+ ret = regmap_read(data->regmap, SX9500_REG_IRQ_SRC, &val);
|
|
|
|
+ if (ret < 0) {
|
|
|
|
+ dev_err(&data->client->dev, "i2c transfer error in irq\n");
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (val & (SX9500_CLOSE_IRQ | SX9500_FAR_IRQ))
|
|
|
|
+ sx9500_push_events(indio_dev);
|
|
|
|
+
|
|
|
|
+ if (val & SX9500_CONVDONE_IRQ)
|
|
|
|
+ complete_all(&data->completion);
|
|
|
|
|
|
out:
|
|
out:
|
|
mutex_unlock(&data->mutex);
|
|
mutex_unlock(&data->mutex);
|
|
@@ -395,9 +540,7 @@ static int sx9500_write_event_config(struct iio_dev *indio_dev,
|
|
int state)
|
|
int state)
|
|
{
|
|
{
|
|
struct sx9500_data *data = iio_priv(indio_dev);
|
|
struct sx9500_data *data = iio_priv(indio_dev);
|
|
- int ret, i;
|
|
|
|
- bool any_active = false;
|
|
|
|
- unsigned int irqmask;
|
|
|
|
|
|
+ int ret;
|
|
|
|
|
|
if (chan->type != IIO_PROXIMITY || type != IIO_EV_TYPE_THRESH ||
|
|
if (chan->type != IIO_PROXIMITY || type != IIO_EV_TYPE_THRESH ||
|
|
dir != IIO_EV_DIR_EITHER)
|
|
dir != IIO_EV_DIR_EITHER)
|
|
@@ -405,24 +548,32 @@ static int sx9500_write_event_config(struct iio_dev *indio_dev,
|
|
|
|
|
|
mutex_lock(&data->mutex);
|
|
mutex_lock(&data->mutex);
|
|
|
|
|
|
- data->event_enabled[chan->channel] = state;
|
|
|
|
|
|
+ if (state == 1) {
|
|
|
|
+ ret = sx9500_inc_chan_users(data, chan->channel);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ goto out_unlock;
|
|
|
|
+ ret = sx9500_inc_close_far_users(data);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ goto out_undo_chan;
|
|
|
|
+ } else {
|
|
|
|
+ ret = sx9500_dec_chan_users(data, chan->channel);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ goto out_unlock;
|
|
|
|
+ ret = sx9500_dec_close_far_users(data);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ goto out_undo_chan;
|
|
|
|
+ }
|
|
|
|
|
|
- for (i = 0; i < SX9500_NUM_CHANNELS; i++)
|
|
|
|
- if (data->event_enabled[i]) {
|
|
|
|
- any_active = true;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
|
|
+ data->event_enabled[chan->channel] = state;
|
|
|
|
+ goto out_unlock;
|
|
|
|
|
|
- irqmask = SX9500_CLOSE_IRQ | SX9500_FAR_IRQ;
|
|
|
|
- if (any_active)
|
|
|
|
- ret = regmap_update_bits(data->regmap, SX9500_REG_IRQ_MSK,
|
|
|
|
- irqmask, irqmask);
|
|
|
|
|
|
+out_undo_chan:
|
|
|
|
+ if (state == 1)
|
|
|
|
+ sx9500_dec_chan_users(data, chan->channel);
|
|
else
|
|
else
|
|
- ret = regmap_update_bits(data->regmap, SX9500_REG_IRQ_MSK,
|
|
|
|
- irqmask, 0);
|
|
|
|
-
|
|
|
|
|
|
+ sx9500_inc_chan_users(data, chan->channel);
|
|
|
|
+out_unlock:
|
|
mutex_unlock(&data->mutex);
|
|
mutex_unlock(&data->mutex);
|
|
-
|
|
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -473,12 +624,16 @@ static int sx9500_set_trigger_state(struct iio_trigger *trig,
|
|
|
|
|
|
mutex_lock(&data->mutex);
|
|
mutex_lock(&data->mutex);
|
|
|
|
|
|
- ret = regmap_update_bits(data->regmap, SX9500_REG_IRQ_MSK,
|
|
|
|
- SX9500_CONVDONE_IRQ,
|
|
|
|
- state ? SX9500_CONVDONE_IRQ : 0);
|
|
|
|
- if (ret == 0)
|
|
|
|
- data->trigger_enabled = state;
|
|
|
|
|
|
+ if (state)
|
|
|
|
+ ret = sx9500_inc_data_rdy_users(data);
|
|
|
|
+ else
|
|
|
|
+ ret = sx9500_dec_data_rdy_users(data);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ data->trigger_enabled = state;
|
|
|
|
|
|
|
|
+out:
|
|
mutex_unlock(&data->mutex);
|
|
mutex_unlock(&data->mutex);
|
|
|
|
|
|
return ret;
|
|
return ret;
|
|
@@ -500,7 +655,7 @@ static irqreturn_t sx9500_trigger_handler(int irq, void *private)
|
|
|
|
|
|
for_each_set_bit(bit, indio_dev->active_scan_mask,
|
|
for_each_set_bit(bit, indio_dev->active_scan_mask,
|
|
indio_dev->masklength) {
|
|
indio_dev->masklength) {
|
|
- ret = sx9500_read_proximity(data, &indio_dev->channels[bit],
|
|
|
|
|
|
+ ret = sx9500_read_prox_data(data, &indio_dev->channels[bit],
|
|
&val);
|
|
&val);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
goto out;
|
|
goto out;
|
|
@@ -519,6 +674,62 @@ out:
|
|
return IRQ_HANDLED;
|
|
return IRQ_HANDLED;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int sx9500_buffer_preenable(struct iio_dev *indio_dev)
|
|
|
|
+{
|
|
|
|
+ struct sx9500_data *data = iio_priv(indio_dev);
|
|
|
|
+ int ret, i;
|
|
|
|
+
|
|
|
|
+ mutex_lock(&data->mutex);
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < SX9500_NUM_CHANNELS; i++)
|
|
|
|
+ if (test_bit(i, indio_dev->active_scan_mask)) {
|
|
|
|
+ ret = sx9500_inc_chan_users(data, i);
|
|
|
|
+ if (ret)
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (ret)
|
|
|
|
+ for (i = i - 1; i >= 0; i--)
|
|
|
|
+ if (test_bit(i, indio_dev->active_scan_mask))
|
|
|
|
+ sx9500_dec_chan_users(data, i);
|
|
|
|
+
|
|
|
|
+ mutex_unlock(&data->mutex);
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int sx9500_buffer_predisable(struct iio_dev *indio_dev)
|
|
|
|
+{
|
|
|
|
+ struct sx9500_data *data = iio_priv(indio_dev);
|
|
|
|
+ int ret, i;
|
|
|
|
+
|
|
|
|
+ iio_triggered_buffer_predisable(indio_dev);
|
|
|
|
+
|
|
|
|
+ mutex_lock(&data->mutex);
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < SX9500_NUM_CHANNELS; i++)
|
|
|
|
+ if (test_bit(i, indio_dev->active_scan_mask)) {
|
|
|
|
+ ret = sx9500_dec_chan_users(data, i);
|
|
|
|
+ if (ret)
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (ret)
|
|
|
|
+ for (i = i - 1; i >= 0; i--)
|
|
|
|
+ if (test_bit(i, indio_dev->active_scan_mask))
|
|
|
|
+ sx9500_inc_chan_users(data, i);
|
|
|
|
+
|
|
|
|
+ mutex_unlock(&data->mutex);
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static const struct iio_buffer_setup_ops sx9500_buffer_setup_ops = {
|
|
|
|
+ .preenable = sx9500_buffer_preenable,
|
|
|
|
+ .postenable = iio_triggered_buffer_postenable,
|
|
|
|
+ .predisable = sx9500_buffer_predisable,
|
|
|
|
+};
|
|
|
|
+
|
|
struct sx9500_reg_default {
|
|
struct sx9500_reg_default {
|
|
u8 reg;
|
|
u8 reg;
|
|
u8 def;
|
|
u8 def;
|
|
@@ -574,11 +785,44 @@ static const struct sx9500_reg_default sx9500_default_regs[] = {
|
|
},
|
|
},
|
|
{
|
|
{
|
|
.reg = SX9500_REG_PROX_CTRL0,
|
|
.reg = SX9500_REG_PROX_CTRL0,
|
|
- /* Scan period: 30ms, all sensors enabled. */
|
|
|
|
- .def = 0x0f,
|
|
|
|
|
|
+ /* Scan period: 30ms, all sensors disabled. */
|
|
|
|
+ .def = 0x00,
|
|
},
|
|
},
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+/* Activate all channels and perform an initial compensation. */
|
|
|
|
+static int sx9500_init_compensation(struct iio_dev *indio_dev)
|
|
|
|
+{
|
|
|
|
+ struct sx9500_data *data = iio_priv(indio_dev);
|
|
|
|
+ int i, ret;
|
|
|
|
+ unsigned int val;
|
|
|
|
+
|
|
|
|
+ ret = regmap_update_bits(data->regmap, SX9500_REG_PROX_CTRL0,
|
|
|
|
+ GENMASK(SX9500_NUM_CHANNELS, 0),
|
|
|
|
+ GENMASK(SX9500_NUM_CHANNELS, 0));
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ for (i = 10; i >= 0; i--) {
|
|
|
|
+ usleep_range(10000, 20000);
|
|
|
|
+ ret = regmap_read(data->regmap, SX9500_REG_STAT, &val);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ goto out;
|
|
|
|
+ if (!(val & SX9500_COMPSTAT_MASK))
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (i < 0) {
|
|
|
|
+ dev_err(&data->client->dev, "initial compensation timed out");
|
|
|
|
+ ret = -ETIMEDOUT;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+out:
|
|
|
|
+ regmap_update_bits(data->regmap, SX9500_REG_PROX_CTRL0,
|
|
|
|
+ GENMASK(SX9500_NUM_CHANNELS, 0), 0);
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
static int sx9500_init_device(struct iio_dev *indio_dev)
|
|
static int sx9500_init_device(struct iio_dev *indio_dev)
|
|
{
|
|
{
|
|
struct sx9500_data *data = iio_priv(indio_dev);
|
|
struct sx9500_data *data = iio_priv(indio_dev);
|
|
@@ -606,6 +850,10 @@ static int sx9500_init_device(struct iio_dev *indio_dev)
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ ret = sx9500_init_compensation(indio_dev);
|
|
|
|
+ if (ret < 0)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -649,6 +897,7 @@ static int sx9500_probe(struct i2c_client *client,
|
|
data = iio_priv(indio_dev);
|
|
data = iio_priv(indio_dev);
|
|
data->client = client;
|
|
data->client = client;
|
|
mutex_init(&data->mutex);
|
|
mutex_init(&data->mutex);
|
|
|
|
+ init_completion(&data->completion);
|
|
data->trigger_enabled = false;
|
|
data->trigger_enabled = false;
|
|
|
|
|
|
data->regmap = devm_regmap_init_i2c(client, &sx9500_regmap_config);
|
|
data->regmap = devm_regmap_init_i2c(client, &sx9500_regmap_config);
|
|
@@ -668,7 +917,9 @@ static int sx9500_probe(struct i2c_client *client,
|
|
if (client->irq <= 0)
|
|
if (client->irq <= 0)
|
|
client->irq = sx9500_gpio_probe(client, data);
|
|
client->irq = sx9500_gpio_probe(client, data);
|
|
|
|
|
|
- if (client->irq > 0) {
|
|
|
|
|
|
+ if (client->irq <= 0)
|
|
|
|
+ dev_warn(&client->dev, "no valid irq found\n");
|
|
|
|
+ else {
|
|
ret = devm_request_threaded_irq(&client->dev, client->irq,
|
|
ret = devm_request_threaded_irq(&client->dev, client->irq,
|
|
sx9500_irq_handler, sx9500_irq_thread_handler,
|
|
sx9500_irq_handler, sx9500_irq_thread_handler,
|
|
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
|
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
|
@@ -691,7 +942,8 @@ static int sx9500_probe(struct i2c_client *client,
|
|
}
|
|
}
|
|
|
|
|
|
ret = iio_triggered_buffer_setup(indio_dev, NULL,
|
|
ret = iio_triggered_buffer_setup(indio_dev, NULL,
|
|
- sx9500_trigger_handler, NULL);
|
|
|
|
|
|
+ sx9500_trigger_handler,
|
|
|
|
+ &sx9500_buffer_setup_ops);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
goto out_trigger_unregister;
|
|
goto out_trigger_unregister;
|
|
|
|
|