iio: proximity: vcnl3020: add proximity rate
authorIvan Mikhaylov <i.mikhaylov@yadro.com>
Thu, 25 Feb 2021 20:14:44 +0000 (23:14 +0300)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Thu, 25 Mar 2021 19:13:49 +0000 (19:13 +0000)
Add the proximity rate optional option and handling of it for
vishay vcnl3020.

Signed-off-by: Ivan Mikhaylov <i.mikhaylov@yadro.com>
Link: https://lore.kernel.org/r/20210225201444.12983-2-i.mikhaylov@yadro.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
drivers/iio/proximity/vcnl3020.c

index 37264f8..43817f6 100644 (file)
 #define VCNL_ON_DEMAND_TIMEOUT_US      100000
 #define VCNL_POLL_US                   20000
 
+static const int vcnl3020_prox_sampling_frequency[][2] = {
+       {1, 950000},
+       {3, 906250},
+       {7, 812500},
+       {16, 625000},
+       {31, 250000},
+       {62, 500000},
+       {125, 0},
+       {250, 0},
+};
+
 /**
  * struct vcnl3020_data - vcnl3020 specific data.
  * @regmap:    device register map.
@@ -165,10 +176,51 @@ err_unlock:
        return rc;
 }
 
+static int vcnl3020_read_proxy_samp_freq(struct vcnl3020_data *data, int *val,
+                                        int *val2)
+{
+       int rc;
+       unsigned int prox_rate;
+
+       rc = regmap_read(data->regmap, VCNL_PROXIMITY_RATE, &prox_rate);
+       if (rc)
+               return rc;
+
+       if (prox_rate >= ARRAY_SIZE(vcnl3020_prox_sampling_frequency))
+               return -EINVAL;
+
+       *val = vcnl3020_prox_sampling_frequency[prox_rate][0];
+       *val2 = vcnl3020_prox_sampling_frequency[prox_rate][1];
+
+       return 0;
+}
+
+static int vcnl3020_write_proxy_samp_freq(struct vcnl3020_data *data, int val,
+                                         int val2)
+{
+       unsigned int i;
+       int index = -1;
+
+       for (i = 0; i < ARRAY_SIZE(vcnl3020_prox_sampling_frequency); i++) {
+               if (val == vcnl3020_prox_sampling_frequency[i][0] &&
+                   val2 == vcnl3020_prox_sampling_frequency[i][1]) {
+                       index = i;
+                       break;
+               }
+       }
+
+       if (index < 0)
+               return -EINVAL;
+
+       return regmap_write(data->regmap, VCNL_PROXIMITY_RATE, index);
+}
+
 static const struct iio_chan_spec vcnl3020_channels[] = {
        {
                .type = IIO_PROXIMITY,
-               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+               .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                                     BIT(IIO_CHAN_INFO_SAMP_FREQ),
+               .info_mask_separate_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
        },
 };
 
@@ -185,6 +237,47 @@ static int vcnl3020_read_raw(struct iio_dev *indio_dev,
                if (rc)
                        return rc;
                return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               rc = vcnl3020_read_proxy_samp_freq(data, val, val2);
+               if (rc < 0)
+                       return rc;
+               return IIO_VAL_INT_PLUS_MICRO;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int vcnl3020_write_raw(struct iio_dev *indio_dev,
+                             struct iio_chan_spec const *chan,
+                             int val, int val2, long mask)
+{
+       int rc;
+       struct vcnl3020_data *data = iio_priv(indio_dev);
+
+       switch (mask) {
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               rc = iio_device_claim_direct_mode(indio_dev);
+               if (rc)
+                       return rc;
+               rc = vcnl3020_write_proxy_samp_freq(data, val, val2);
+               iio_device_release_direct_mode(indio_dev);
+               return rc;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int vcnl3020_read_avail(struct iio_dev *indio_dev,
+                              struct iio_chan_spec const *chan,
+                              const int **vals, int *type, int *length,
+                              long mask)
+{
+       switch (mask) {
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               *vals = (int *)vcnl3020_prox_sampling_frequency;
+               *type = IIO_VAL_INT_PLUS_MICRO;
+               *length = 2 * ARRAY_SIZE(vcnl3020_prox_sampling_frequency);
+               return IIO_AVAIL_LIST;
        default:
                return -EINVAL;
        }
@@ -192,6 +285,8 @@ static int vcnl3020_read_raw(struct iio_dev *indio_dev,
 
 static const struct iio_info vcnl3020_info = {
        .read_raw = vcnl3020_read_raw,
+       .write_raw = vcnl3020_write_raw,
+       .read_avail = vcnl3020_read_avail,
 };
 
 static const struct regmap_config vcnl3020_regmap_config = {