/* optimize runtime pm ops - enable/disable device only if needed */ bool als_ps_need_en; bool pxs_ps_need_en; bool als_need_dis; bool pxs_need_dis;
struct regmap *regmap;
/* * Ensure correct naturally aligned timestamp. * Note that the read will put garbage data into * the padding but this should not be a problem
*/ struct {
__le16 channels[3];
u8 garbage;
aligned_s64 ts;
} scan;
};
/** * rpr0521_set_power_state - handles runtime PM state and sensors enabled status * * @data: rpr0521 device private data * @on: state to be set for devices in @device_mask * @device_mask: bitmask specifying for which device we need to update @on state * * Calls for this function must be balanced so that each ON should have matching * OFF. Otherwise pm usage_count gets out of sync.
*/ staticint rpr0521_set_power_state(struct rpr0521_data *data, bool on,
u8 device_mask)
{ #ifdef CONFIG_PM int ret;
/* * On: _resume() is called only when we are suspended * Off: _suspend() is called after delay if _resume() is not * called before that. * Note: If either measurement is re-enabled before _suspend(), * both stay enabled until _suspend().
*/ if (on) {
ret = pm_runtime_resume_and_get(&data->client->dev);
} else {
pm_runtime_mark_last_busy(&data->client->dev);
ret = pm_runtime_put_autosuspend(&data->client->dev);
} if (ret < 0) {
dev_err(&data->client->dev, "Failed: rpr0521_set_power_state for %d, ret %d\n",
on, ret); return ret;
}
if (on) { /* If _resume() was not called, enable measurement now. */ if (data->als_ps_need_en) {
ret = rpr0521_als_enable(data, RPR0521_MODE_ALS_ENABLE); if (ret) return ret;
data->als_ps_need_en = false;
}
if (data->pxs_ps_need_en) {
ret = rpr0521_pxs_enable(data, RPR0521_MODE_PXS_ENABLE); if (ret) return ret;
data->pxs_ps_need_en = false;
}
} #endif return 0;
}
/* Interrupt register tells if this sensor caused the interrupt or not. */ staticinlinebool rpr0521_is_triggered(struct rpr0521_data *data)
{ int ret; int reg;
ret = regmap_read(data->regmap, RPR0521_REG_INTERRUPT, ®); if (ret < 0) returnfalse; /* Reg read failed. */ if (reg &
(RPR0521_INTERRUPT_ALS_INT_STATUS_MASK |
RPR0521_INTERRUPT_PS_INT_STATUS_MASK)) returntrue; else returnfalse; /* Int not from this sensor. */
}
data->irq_timestamp = iio_get_time_ns(indio_dev); /* * We need to wake the thread to read the interrupt reg. It * is not possible to do that here because regmap_read takes a * mutex.
*/
/* Use irq timestamp when reasonable. */ if (iio_trigger_using_own(indio_dev) && data->irq_timestamp) {
pf->timestamp = data->irq_timestamp;
data->irq_timestamp = 0;
} /* Other chained trigger polls get timestamp only here. */ if (!pf->timestamp)
pf->timestamp = iio_get_time_ns(indio_dev);
staticint rpr0521_write_int_enable(struct rpr0521_data *data)
{ int err;
/* Interrupt after each measurement */
err = regmap_update_bits(data->regmap, RPR0521_REG_PXS_CTRL,
RPR0521_PXS_PERSISTENCE_MASK,
RPR0521_PXS_PERSISTENCE_DRDY); if (err) {
dev_err(&data->client->dev, "PS control reg write fail.\n"); return -EBUSY;
}
/* Ignore latch and mode because of drdy */
err = regmap_write(data->regmap, RPR0521_REG_INTERRUPT,
RPR0521_INTERRUPT_INT_REASSERT_DISABLE |
RPR0521_INTERRUPT_INT_TRIG_ALS_DISABLE |
RPR0521_INTERRUPT_INT_TRIG_PS_ENABLE
); if (err) {
dev_err(&data->client->dev, "Interrupt setup write fail.\n"); return -EBUSY;
}
return 0;
}
staticint rpr0521_write_int_disable(struct rpr0521_data *data)
{ /* Don't care of clearing mode, assert and latch. */ return regmap_write(data->regmap, RPR0521_REG_INTERRUPT,
RPR0521_INTERRUPT_INT_TRIG_ALS_DISABLE |
RPR0521_INTERRUPT_INT_TRIG_PS_DISABLE
);
}
/* * Trigger producer enable / disable. Note that there will be trigs only when * measurement data is ready to be read.
*/ staticint rpr0521_pxs_drdy_set_state(struct iio_trigger *trigger, bool enable_drdy)
{ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trigger); struct rpr0521_data *data = iio_priv(indio_dev); int err;
if (enable_drdy)
err = rpr0521_write_int_enable(data); else
err = rpr0521_write_int_disable(data); if (err)
dev_err(&data->client->dev, "rpr0521_pxs_drdy_set_state failed\n");
staticint rpr0521_set_gain(struct rpr0521_data *data, int chan, int val, int val2)
{ int i, idx = -EINVAL;
/* get gain index */ for (i = 0; i < rpr0521_gain[chan].size; i++) if (val == rpr0521_gain[chan].gain[i].scale &&
val2 == rpr0521_gain[chan].gain[i].uscale) {
idx = i; break;
}
staticint rpr0521_init(struct rpr0521_data *data)
{ int ret; int id;
ret = regmap_read(data->regmap, RPR0521_REG_ID, &id); if (ret < 0) {
dev_err(&data->client->dev, "Failed to read REG_ID register\n"); return ret;
}
if (id != RPR0521_MANUFACT_ID) {
dev_err(&data->client->dev, "Wrong id, got %x, expected %x\n",
id, RPR0521_MANUFACT_ID); return -ENODEV;
}
/* set default measurement time - 100 ms for both ALS and PS */
ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL,
RPR0521_MODE_MEAS_TIME_MASK,
RPR0521_DEFAULT_MEAS_TIME); if (ret) {
pr_err("regmap_update_bits returned %d\n", ret); return ret;
}
#ifndef CONFIG_PM
ret = rpr0521_als_enable(data, RPR0521_MODE_ALS_ENABLE); if (ret < 0) return ret;
ret = rpr0521_pxs_enable(data, RPR0521_MODE_PXS_ENABLE); if (ret < 0) return ret; #endif
data->irq_timestamp = 0;
return 0;
}
staticint rpr0521_poweroff(struct rpr0521_data *data)
{ int ret; int tmp;
ret = regmap_update_bits(data->regmap, RPR0521_REG_MODE_CTRL,
RPR0521_MODE_ALS_MASK |
RPR0521_MODE_PXS_MASK,
RPR0521_MODE_ALS_DISABLE |
RPR0521_MODE_PXS_DISABLE); if (ret < 0) return ret;
/* * Int pin keeps state after power off. Set pin to high impedance * mode to prevent power drain.
*/
ret = regmap_read(data->regmap, RPR0521_REG_INTERRUPT, &tmp); if (ret) {
dev_err(&data->client->dev, "Failed to reset int pin.\n"); return ret;
}
return 0;
}
staticbool rpr0521_is_volatile_reg(struct device *dev, unsignedint reg)
{ switch (reg) { case RPR0521_REG_MODE_CTRL: case RPR0521_REG_ALS_CTRL: case RPR0521_REG_PXS_CTRL: returnfalse; default: returntrue;
}
}
mutex_lock(&data->lock); /* If measurements are enabled, enable them on resume */ if (!data->als_need_dis)
data->als_ps_need_en = data->als_dev_en; if (!data->pxs_need_dis)
data->pxs_ps_need_en = data->pxs_dev_en;
/* disable channels and sets {als,pxs}_dev_en to false */
ret = rpr0521_poweroff(data);
regcache_mark_dirty(data->regmap);
mutex_unlock(&data->lock);
regcache_sync(data->regmap); if (data->als_ps_need_en) {
ret = rpr0521_als_enable(data, RPR0521_MODE_ALS_ENABLE); if (ret < 0) return ret;
data->als_ps_need_en = false;
}
if (data->pxs_ps_need_en) {
ret = rpr0521_pxs_enable(data, RPR0521_MODE_PXS_ENABLE); if (ret < 0) return ret;
data->pxs_ps_need_en = false;
}
msleep(100); //wait for first measurement result
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.