staticint apds9960_set_it_time(struct apds9960_data *data, int val2)
{ int ret = -EINVAL; int idx;
for (idx = 0; idx < ARRAY_SIZE(apds9960_int_time); idx++) { if (apds9960_int_time[idx][0] == val2) {
mutex_lock(&data->lock);
ret = regmap_write(data->regmap, APDS9960_REG_ATIME,
apds9960_int_time[idx][1]); if (!ret)
data->als_adc_int_us = val2;
mutex_unlock(&data->lock); break;
}
}
return ret;
}
staticint apds9960_set_pxs_gain(struct apds9960_data *data, int val)
{ int ret = -EINVAL; int idx;
for (idx = 0; idx < ARRAY_SIZE(apds9960_pxs_gain_map); idx++) { if (apds9960_pxs_gain_map[idx] == val) { /* pxs + gesture gains are mirrored */
mutex_lock(&data->lock);
ret = regmap_update_bits(data->regmap,
APDS9960_REG_CONTROL,
APDS9960_REG_CONTROL_PGAIN_MASK,
idx << APDS9960_REG_CONTROL_PGAIN_MASK_SHIFT); if (ret) {
mutex_unlock(&data->lock); break;
}
ret = regmap_update_bits(data->regmap,
APDS9960_REG_GCONF_2,
APDS9960_REG_GCONF_2_GGAIN_MASK,
idx << APDS9960_REG_GCONF_2_GGAIN_MASK_SHIFT); if (!ret)
data->pxs_gain = idx;
mutex_unlock(&data->lock); break;
}
}
return ret;
}
staticint apds9960_set_als_gain(struct apds9960_data *data, int val)
{ int ret = -EINVAL; int idx;
for (idx = 0; idx < ARRAY_SIZE(apds9960_als_gain_map); idx++) { if (apds9960_als_gain_map[idx] == val) {
mutex_lock(&data->lock);
ret = regmap_update_bits(data->regmap,
APDS9960_REG_CONTROL,
APDS9960_REG_CONTROL_AGAIN_MASK, idx); if (!ret)
data->als_gain = idx;
mutex_unlock(&data->lock); break;
}
}
return ret;
}
#ifdef CONFIG_PM staticint apds9960_set_power_state(struct apds9960_data *data, bool on)
{ struct device *dev = &data->client->dev; int ret = 0;
mutex_lock(&data->lock);
if (on) { int suspended;
suspended = pm_runtime_suspended(dev);
ret = pm_runtime_get_sync(dev);
/* Allow one integration cycle before allowing a reading */ if (suspended)
usleep_range(data->als_adc_int_us,
APDS9960_MAX_INT_TIME_IN_US);
} else {
pm_runtime_mark_last_busy(dev);
ret = pm_runtime_put_autosuspend(dev);
}
staticint apds9960_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{ struct apds9960_data *data = iio_priv(indio_dev);
__le16 buf; int ret = -EINVAL;
if (data->gesture_mode_running) return -EBUSY;
switch (mask) { case IIO_CHAN_INFO_RAW:
apds9960_set_power_state(data, true); switch (chan->type) { case IIO_PROXIMITY:
ret = regmap_read(data->regmap, chan->address, val); if (!ret)
ret = IIO_VAL_INT; break; case IIO_INTENSITY:
ret = regmap_bulk_read(data->regmap, chan->address,
&buf, 2); if (!ret) {
ret = IIO_VAL_INT;
*val = le16_to_cpu(buf);
} break; default:
ret = -EINVAL;
}
apds9960_set_power_state(data, false); break; case IIO_CHAN_INFO_INT_TIME: /* RGB + ALS sensors only have integration time */
mutex_lock(&data->lock); switch (chan->type) { case IIO_INTENSITY:
*val = 0;
*val2 = data->als_adc_int_us;
ret = IIO_VAL_INT_PLUS_MICRO; break; default:
ret = -EINVAL;
}
mutex_unlock(&data->lock); break; case IIO_CHAN_INFO_SCALE:
mutex_lock(&data->lock); switch (chan->type) { case IIO_PROXIMITY:
*val = apds9960_pxs_gain_map[data->pxs_gain];
ret = IIO_VAL_INT; break; case IIO_INTENSITY:
*val = apds9960_als_gain_map[data->als_gain];
ret = IIO_VAL_INT; break; default:
ret = -EINVAL;
}
mutex_unlock(&data->lock); break; case IIO_CHAN_INFO_CALIBBIAS:
mutex_lock(&data->lock);
*val = data->calibbias[chan->channel];
ret = IIO_VAL_INT;
mutex_unlock(&data->lock); break;
}
return ret;
};
staticint apds9960_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask)
{ struct apds9960_data *data = iio_priv(indio_dev);
switch (mask) { case IIO_CHAN_INFO_INT_TIME: /* RGB + ALS sensors only have int time */ switch (chan->type) { case IIO_INTENSITY: if (val != 0) return -EINVAL; return apds9960_set_it_time(data, val2); default: return -EINVAL;
} case IIO_CHAN_INFO_SCALE: if (val2 != 0) return -EINVAL; switch (chan->type) { case IIO_PROXIMITY: return apds9960_set_pxs_gain(data, val); case IIO_INTENSITY: return apds9960_set_als_gain(data, val); default: return -EINVAL;
} case IIO_CHAN_INFO_CALIBBIAS: if (val2 != 0) return -EINVAL; return apds9960_set_calibbias(data, chan, val); default: return -EINVAL;
}
data->reg_int_als = devm_regmap_field_alloc(dev, regmap,
apds9960_reg_field_int_als); if (IS_ERR(data->reg_int_als)) {
dev_err(dev, "INT ALS reg field init failed\n"); return PTR_ERR(data->reg_int_als);
}
data->reg_int_ges = devm_regmap_field_alloc(dev, regmap,
apds9960_reg_field_int_ges); if (IS_ERR(data->reg_int_ges)) {
dev_err(dev, "INT gesture reg field init failed\n"); return PTR_ERR(data->reg_int_ges);
}
data->reg_int_pxs = devm_regmap_field_alloc(dev, regmap,
apds9960_reg_field_int_pxs); if (IS_ERR(data->reg_int_pxs)) {
dev_err(dev, "INT pxs reg field init failed\n"); return PTR_ERR(data->reg_int_pxs);
}
data->reg_enable_als = devm_regmap_field_alloc(dev, regmap,
apds9960_reg_field_enable_als); if (IS_ERR(data->reg_enable_als)) {
dev_err(dev, "Enable ALS reg field init failed\n"); return PTR_ERR(data->reg_enable_als);
}
data->reg_enable_ges = devm_regmap_field_alloc(dev, regmap,
apds9960_reg_field_enable_ges); if (IS_ERR(data->reg_enable_ges)) {
dev_err(dev, "Enable gesture reg field init failed\n"); return PTR_ERR(data->reg_enable_ges);
}
data->reg_enable_pxs = devm_regmap_field_alloc(dev, regmap,
apds9960_reg_field_enable_pxs); if (IS_ERR(data->reg_enable_pxs)) {
dev_err(dev, "Enable PXS reg field init failed\n"); return PTR_ERR(data->reg_enable_pxs);
}
return 0;
}
staticint apds9960_chip_init(struct apds9960_data *data)
{ int ret;
/* Default IT for ALS of 28 ms */
ret = apds9960_set_it_time(data, 28000); if (ret) return ret;
/* Ensure gesture interrupt is OFF */
ret = regmap_field_write(data->reg_int_ges, 0); if (ret) return ret;
/* Disable gesture sensor, since polling is useless from user-space */
ret = regmap_field_write(data->reg_enable_ges, 0); if (ret) return ret;
/* Ensure proximity interrupt is OFF */
ret = regmap_field_write(data->reg_int_pxs, 0); if (ret) return ret;
/* Enable proximity sensor for polling */
ret = regmap_field_write(data->reg_enable_pxs, 1); if (ret) return ret;
/* Ensure ALS interrupt is OFF */
ret = regmap_field_write(data->reg_int_als, 0); if (ret) return ret;
/* Enable ALS sensor for polling */
ret = regmap_field_write(data->reg_enable_als, 1); if (ret) return ret; /* * When enabled trigger an interrupt after 3 readings * outside threshold for ALS + PXS
*/
ret = regmap_write(data->regmap, APDS9960_REG_PERS,
APDS9960_DEFAULT_PERS); if (ret) return ret;
/* * Wait for 4 event outside gesture threshold to prevent interrupt * flooding.
*/
ret = regmap_update_bits(data->regmap, APDS9960_REG_GCONF_1,
APDS9960_REG_GCONF_1_GFIFO_THRES_MASK,
BIT(0) << APDS9960_REG_GCONF_1_GFIFO_THRES_MASK_SHIFT); if (ret) return ret;
/* Default ENTER and EXIT thresholds for the GESTURE engine. */
ret = regmap_write(data->regmap, APDS9960_REG_GPENTH,
APDS9960_DEFAULT_GPENTH); if (ret) return ret;
ret = regmap_write(data->regmap, APDS9960_REG_GEXTH,
APDS9960_DEFAULT_GEXTH); if (ret) return ret;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.