Proximity and gesture offset registers perform offset correction to improve cross-talk performance. Add support for reading from and writing to proximity and gesture offset registers. Create sysfs attributes for them via iio to expose them to userspace. Signed-off-by: Abhash Jha <abhashkumarjha123@xxxxxxxxx> --- drivers/iio/light/apds9960.c | 245 +++++++++++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c index 1065a340b..bccf9a8c7 100644 --- a/drivers/iio/light/apds9960.c +++ b/drivers/iio/light/apds9960.c @@ -101,6 +101,10 @@ #define APDS9960_MAX_ALS_THRES_VAL 0xffff #define APDS9960_MAX_INT_TIME_IN_US 1000000 +/* MIN and MAX offset from pg: 26 of the datasheet */ +#define MIN_OFFSET -127 +#define MAX_OFFSET 127 + enum apds9960_als_channel_idx { IDX_ALS_CLEAR, IDX_ALS_RED, IDX_ALS_GREEN, IDX_ALS_BLUE, }; @@ -316,6 +320,234 @@ static const struct iio_chan_spec apds9960_channels[] = { APDS9960_INTENSITY_CHANNEL(BLUE), }; +static ssize_t apds9960_proximity_offset_ur_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct apds9960_data *data = iio_priv(indio_dev); + int offset; + int ret; + + if (kstrtoint(buf, 10, &offset)) + return -EINVAL; + + if (offset < MIN_OFFSET || offset > MAX_OFFSET) + return -EINVAL; + + ret = regmap_write(data->regmap, APDS9960_REG_POFFSET_UR, offset); + if (ret < 0) { + dev_err(&data->client->dev, "proximity offset reg write failed\n"); + return ret; + } + + return count; +} + +static ssize_t apds9960_proximity_offset_dl_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct apds9960_data *data = iio_priv(indio_dev); + int offset; + int ret; + + if (kstrtoint(buf, 10, &offset)) + return -EINVAL; + + if (offset < MIN_OFFSET || offset > MAX_OFFSET) + return -EINVAL; + + ret = regmap_write(data->regmap, APDS9960_REG_POFFSET_DL, offset); + if (ret < 0) { + dev_err(&data->client->dev, "proximity offset reg write failed\n"); + return ret; + } + + return count; +} + +static ssize_t apds9960_proximity_offset_ur_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct apds9960_data *data = iio_priv(indio_dev); + int offset; + int ret; + + ret = regmap_read(data->regmap, APDS9960_REG_POFFSET_UR, &offset); + if (ret < 0) { + dev_err(&data->client->dev, "proximity offset reg read failed\n"); + return ret; + } + + return scnprintf(buf, PAGE_SIZE, "%d\n", offset); +} + +static ssize_t apds9960_proximity_offset_dl_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct apds9960_data *data = iio_priv(indio_dev); + int offset; + int ret; + + ret = regmap_read(data->regmap, APDS9960_REG_POFFSET_DL, &offset); + if (ret < 0) { + dev_err(&data->client->dev, "proximity offset reg read failed\n"); + return ret; + } + + return scnprintf(buf, PAGE_SIZE, "%d\n", offset); +} + +static ssize_t apds9960_gesture_offset_u_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct apds9960_data *data = iio_priv(indio_dev); + int offset; + int ret; + + if (kstrtoint(buf, 10, &offset)) + return -EINVAL; + + if (offset < MIN_OFFSET || offset > MAX_OFFSET) + return -EINVAL; + + ret = regmap_write(data->regmap, APDS9960_REG_GOFFSET_U, offset); + if (ret < 0) { + dev_err(&data->client->dev, "gesture offset reg write failed\n"); + return ret; + } + + return count; +} + +static ssize_t apds9960_gesture_offset_d_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct apds9960_data *data = iio_priv(indio_dev); + int offset; + int ret; + + if (kstrtoint(buf, 10, &offset)) + return -EINVAL; + + if (offset < MIN_OFFSET || offset > MAX_OFFSET) + return -EINVAL; + + ret = regmap_write(data->regmap, APDS9960_REG_GOFFSET_D, offset); + if (ret < 0) { + dev_err(&data->client->dev, "gesture offset reg write failed\n"); + return ret; + } + + return count; +} + +static ssize_t apds9960_gesture_offset_l_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct apds9960_data *data = iio_priv(indio_dev); + int offset; + int ret; + + if (kstrtoint(buf, 10, &offset)) + return -EINVAL; + + if (offset < MIN_OFFSET || offset > MAX_OFFSET) + return -EINVAL; + + ret = regmap_write(data->regmap, APDS9960_REG_GOFFSET_L, offset); + if (ret < 0) { + dev_err(&data->client->dev, "gesture offset reg write failed\n"); + return ret; + } + + return count; +} + +static ssize_t apds9960_gesture_offset_r_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct apds9960_data *data = iio_priv(indio_dev); + int offset; + int ret; + + if (kstrtoint(buf, 10, &offset)) + return -EINVAL; + + if (offset < MIN_OFFSET || offset > MAX_OFFSET) + return -EINVAL; + + ret = regmap_write(data->regmap, APDS9960_REG_GOFFSET_R, offset); + if (ret < 0) { + dev_err(&data->client->dev, "gesture offset reg write failed\n"); + return ret; + } + + return count; +} + +static ssize_t apds9960_gesture_offset_u_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct apds9960_data *data = iio_priv(indio_dev); + int offset; + int ret; + + ret = regmap_read(data->regmap, APDS9960_REG_GOFFSET_U, &offset); + if (ret < 0) { + dev_err(&data->client->dev, "gesture offset reg read failed\n"); + return ret; + } + + return scnprintf(buf, PAGE_SIZE, "%d\n", offset); +} + +static ssize_t apds9960_gesture_offset_d_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct apds9960_data *data = iio_priv(indio_dev); + int offset; + int ret; + + ret = regmap_read(data->regmap, APDS9960_REG_GOFFSET_D, &offset); + if (ret < 0) { + dev_err(&data->client->dev, "gesture offset reg read failed\n"); + return ret; + } + + return scnprintf(buf, PAGE_SIZE, "%d\n", offset); +} + +static ssize_t apds9960_gesture_offset_l_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct apds9960_data *data = iio_priv(indio_dev); + int offset; + int ret; + + ret = regmap_read(data->regmap, APDS9960_REG_GOFFSET_L, &offset); + if (ret < 0) { + dev_err(&data->client->dev, "gesture offset reg read failed\n"); + return ret; + } + + return scnprintf(buf, PAGE_SIZE, "%d\n", offset); +} + +static ssize_t apds9960_gesture_offset_r_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct apds9960_data *data = iio_priv(indio_dev); + int offset; + int ret; + + ret = regmap_read(data->regmap, APDS9960_REG_GOFFSET_R, &offset); + if (ret < 0) { + dev_err(&data->client->dev, "gesture offset reg read failed\n"); + return ret; + } + + return scnprintf(buf, PAGE_SIZE, "%d\n", offset); +} + /* integration time in us */ static const int apds9960_int_time[][2] = { { 28000, 246}, @@ -332,10 +564,23 @@ static IIO_CONST_ATTR(proximity_scale_available, "1 2 4 8"); static IIO_CONST_ATTR(intensity_scale_available, "1 4 16 64"); static IIO_CONST_ATTR_INT_TIME_AVAIL("0.028 0.1 0.2 0.7"); +static IIO_DEVICE_ATTR(proximity_offset_ur, S_IRUGO | S_IWUSR, apds9960_proximity_offset_ur_show, apds9960_proximity_offset_ur_store, 0); +static IIO_DEVICE_ATTR(proximity_offset_dl, S_IRUGO | S_IWUSR, apds9960_proximity_offset_dl_show, apds9960_proximity_offset_dl_store, 0); +static IIO_DEVICE_ATTR(gesture_offset_u, S_IRUGO | S_IWUSR, apds9960_gesture_offset_u_show, apds9960_gesture_offset_u_store, 0); +static IIO_DEVICE_ATTR(gesture_offset_d, S_IRUGO | S_IWUSR, apds9960_gesture_offset_d_show, apds9960_gesture_offset_d_store, 0); +static IIO_DEVICE_ATTR(gesture_offset_l, S_IRUGO | S_IWUSR, apds9960_gesture_offset_l_show, apds9960_gesture_offset_l_store, 0); +static IIO_DEVICE_ATTR(gesture_offset_r, S_IRUGO | S_IWUSR, apds9960_gesture_offset_r_show, apds9960_gesture_offset_r_store, 0); + static struct attribute *apds9960_attributes[] = { &iio_const_attr_proximity_scale_available.dev_attr.attr, &iio_const_attr_intensity_scale_available.dev_attr.attr, &iio_const_attr_integration_time_available.dev_attr.attr, + &iio_dev_attr_proximity_offset_ur.dev_attr.attr, + &iio_dev_attr_proximity_offset_dl.dev_attr.attr, + &iio_dev_attr_gesture_offset_u.dev_attr.attr, + &iio_dev_attr_gesture_offset_d.dev_attr.attr, + &iio_dev_attr_gesture_offset_l.dev_attr.attr, + &iio_dev_attr_gesture_offset_r.dev_attr.attr, NULL, }; -- 2.43.0