aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio/proximity
diff options
context:
space:
mode:
authorStephen Boyd <swboyd@chromium.org>2020-10-06 18:17:31 -0700
committerJonathan Cameron <Jonathan.Cameron@huawei.com>2020-10-10 17:38:36 +0100
commitad2b473e2ba39b43df4d2cad77ab6130665d8c31 (patch)
tree2ff610b7557de9db599777278715a698a75ae8d2 /drivers/iio/proximity
parentiio: sx9310: Support hardware gain factor (diff)
downloadlinux-dev-ad2b473e2ba39b43df4d2cad77ab6130665d8c31.tar.xz
linux-dev-ad2b473e2ba39b43df4d2cad77ab6130665d8c31.zip
iio: sx9310: Support setting proximity thresholds
Add support to set the proximity thresholds for each channel. Signed-off-by: Stephen Boyd <swboyd@chromium.org> Cc: Daniel Campello <campello@chromium.org> Cc: Lars-Peter Clausen <lars@metafoo.de> Cc: Peter Meerwald-Stadler <pmeerw@pmeerw.net> Cc: Douglas Anderson <dianders@chromium.org> Cc: Gwendal Grignou <gwendal@chromium.org> Cc: Evan Green <evgreen@chromium.org> Link: https://lore.kernel.org/r/20201007011735.1346994-3-swboyd@chromium.org Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Diffstat (limited to 'drivers/iio/proximity')
-rw-r--r--drivers/iio/proximity/sx9310.c114
1 files changed, 114 insertions, 0 deletions
diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c
index 68a39c11c7bf..148f2d862601 100644
--- a/drivers/iio/proximity/sx9310.c
+++ b/drivers/iio/proximity/sx9310.c
@@ -68,6 +68,7 @@
#define SX9310_REG_PROX_CTRL7_AVGNEGFILT_2 (0x01 << 3)
#define SX9310_REG_PROX_CTRL7_AVGPOSFILT_512 0x05
#define SX9310_REG_PROX_CTRL8 0x18
+#define SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK GENMASK(7, 3)
#define SX9310_REG_PROX_CTRL9 0x19
#define SX9310_REG_PROX_CTRL8_9_PTHRESH_28 (0x08 << 3)
#define SX9310_REG_PROX_CTRL8_9_PTHRESH_96 (0x11 << 3)
@@ -531,6 +532,117 @@ static int sx9310_read_avail(struct iio_dev *indio_dev,
return -EINVAL;
}
+static const unsigned int sx9310_pthresh_codes[] = {
+ 2, 4, 6, 8, 12, 16, 20, 24, 28, 32, 40, 48, 56, 64, 72, 80, 88, 96, 112,
+ 128, 144, 160, 192, 224, 256, 320, 384, 512, 640, 768, 1024, 1536
+};
+
+static int sx9310_get_thresh_reg(unsigned int channel)
+{
+ switch (channel) {
+ case 0:
+ case 3:
+ return SX9310_REG_PROX_CTRL8;
+ case 1:
+ case 2:
+ return SX9310_REG_PROX_CTRL9;
+ }
+
+ return -EINVAL;
+}
+
+static int sx9310_read_thresh(struct sx9310_data *data,
+ const struct iio_chan_spec *chan, int *val)
+{
+ unsigned int reg;
+ unsigned int regval;
+ int ret;
+
+ reg = ret = sx9310_get_thresh_reg(chan->channel);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(data->regmap, reg, &regval);
+ if (ret)
+ return ret;
+
+ regval = FIELD_GET(SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval);
+ if (regval > ARRAY_SIZE(sx9310_pthresh_codes))
+ return -EINVAL;
+
+ *val = sx9310_pthresh_codes[regval];
+ return IIO_VAL_INT;
+}
+
+static int sx9310_read_event_val(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 sx9310_data *data = iio_priv(indio_dev);
+
+ if (chan->type != IIO_PROXIMITY)
+ return -EINVAL;
+
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ return sx9310_read_thresh(data, chan, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int sx9310_write_thresh(struct sx9310_data *data,
+ const struct iio_chan_spec *chan, int val)
+{
+ unsigned int reg;
+ unsigned int regval;
+ int ret, i;
+
+ reg = ret = sx9310_get_thresh_reg(chan->channel);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(sx9310_pthresh_codes); i++) {
+ if (sx9310_pthresh_codes[i] == val) {
+ regval = i;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(sx9310_pthresh_codes))
+ return -EINVAL;
+
+ regval = FIELD_PREP(SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval);
+ mutex_lock(&data->mutex);
+ ret = regmap_update_bits(data->regmap, reg,
+ SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval);
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+
+static int sx9310_write_event_val(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 sx9310_data *data = iio_priv(indio_dev);
+
+ if (chan->type != IIO_PROXIMITY)
+ return -EINVAL;
+
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ return sx9310_write_thresh(data, chan, val);
+ default:
+ return -EINVAL;
+ }
+}
+
static int sx9310_set_samp_freq(struct sx9310_data *data, int val, int val2)
{
int i, ret;
@@ -744,6 +856,8 @@ static const struct iio_info sx9310_info = {
.attrs = &sx9310_attribute_group,
.read_raw = sx9310_read_raw,
.read_avail = sx9310_read_avail,
+ .read_event_value = sx9310_read_event_val,
+ .write_event_value = sx9310_write_event_val,
.write_raw = sx9310_write_raw,
.read_event_config = sx9310_read_event_config,
.write_event_config = sx9310_write_event_config,