@@ -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,
};
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@gmail.com> --- drivers/iio/light/apds9960.c | 245 +++++++++++++++++++++++++++++++++++ 1 file changed, 245 insertions(+)