/* Timings (ms) */ #define MLX90635_TIMING_RST_MIN 200 /* Minimum time after addressed reset command */ #define MLX90635_TIMING_RST_MAX 250 /* Maximum time after addressed reset command */ #define MLX90635_TIMING_POLLING 10000 /* Time between bit polling*/ #define MLX90635_TIMING_EE_ACTIVE_MIN 100 /* Minimum time after activating the EEPROM for read */ #define MLX90635_TIMING_EE_ACTIVE_MAX 150 /* Maximum time after activating the EEPROM for read */
/* Magic constants */ #define MLX90635_ID_DSPv1 0x01 /* EEPROM DSP version */ #define MLX90635_RESET_CMD 0x0006 /* Reset sensor (address or global) */ #define MLX90635_MAX_MEAS_NUM 31 /* Maximum number of measurements in list */ #define MLX90635_PTAT_DIV 12 /* Used to divide the PTAT value in pre-processing */ #define MLX90635_IR_DIV 24 /* Used to divide the IR value in pre-processing */ #define MLX90635_SLEEP_DELAY_MS 6000 /* Autosleep delay */ #define MLX90635_MEAS_MAX_TIME 2000 /* Max measurement time in ms for the lowest refresh rate */ #define MLX90635_READ_RETRIES 100 /* Number of read retries before quitting with timeout error */ #define MLX90635_VERSION_MASK (GENMASK(15, 12) | GENMASK(7, 4)) #define MLX90635_DSP_VERSION(reg) (((reg & GENMASK(14, 12)) >> 9) | ((reg & GENMASK(6, 4)) >> 4)) #define MLX90635_DSP_FIXED BIT(15)
/** * struct mlx90635_data - private data for the MLX90635 device * @client: I2C client of the device * @lock: Internal mutex because multiple reads are needed for single triggered * measurement to ensure data consistency * @regmap: Regmap of the device registers * @regmap_ee: Regmap of the device EEPROM which can be cached * @emissivity: Object emissivity from 0 to 1000 where 1000 = 1 * @regulator: Regulator of the device * @powerstatus: Current POWER status of the device * @interaction_ts: Timestamp of the last temperature read that is used * for power management in jiffies
*/ struct mlx90635_data { struct i2c_client *client; struct mutex lock; struct regmap *regmap; struct regmap *regmap_ee;
u16 emissivity; struct regulator *regulator; int powerstatus; unsignedlong interaction_ts;
};
/** * mlx90635_reset_delay() - Give the mlx90635 some time to reset properly * If this is not done, the following I2C command(s) will not be accepted.
*/ staticvoid mlx90635_reset_delay(void)
{
usleep_range(MLX90635_TIMING_RST_MIN, MLX90635_TIMING_RST_MAX);
}
staticint mlx90635_pwr_sleep_step(struct mlx90635_data *data)
{ int ret;
if (data->powerstatus == MLX90635_PWR_STATUS_SLEEP_STEP) return 0;
ret = regmap_write_bits(data->regmap, MLX90635_REG_CTRL2, MLX90635_CTRL2_MODE_MASK,
FIELD_PREP(MLX90635_CTRL2_MODE_MASK, MLX90635_PWR_STATUS_SLEEP_STEP)); if (ret < 0) return ret;
/* Iterations of calculation as described in datasheet */ for (i = 0; i < 5; ++i) {
temp = mlx90635_calc_temp_object_iteration(temp, object, TAdut, TAdut4,
Ga, Fa, Fa_scale, Fb, Ha, Hb,
tmp_emi);
} return temp;
}
staticint mlx90635_calc_object(struct mlx90635_data *data, int *val)
{
s16 ambient_new_raw, ambient_old_raw, object_raw;
s16 Fb, Ga, Gb, Ha, Hb;
s64 object, ambient;
u32 Ea, Eb, Fa;
u16 Fa_scale; int ret;
ret = mlx90635_read_ee_object(data->regmap_ee, &Ea, &Eb, &Fa, &Fb, &Ga, &Gb, &Ha, &Hb, &Fa_scale); if (ret < 0) return ret;
ret = mlx90635_read_all_channel(data,
&ambient_new_raw, &ambient_old_raw,
&object_raw); if (ret < 0) return ret;
/** * mlx90635_pm_interaction_wakeup() - Measure time between user interactions to change powermode * @data: pointer to mlx90635_data object containing interaction_ts information * * Switch to continuous mode when interaction is faster than MLX90635_MEAS_MAX_TIME. Update the * interaction_ts for each function call with the jiffies to enable measurement between function * calls. Initial value of the interaction_ts needs to be set before this function call.
*/ staticint mlx90635_pm_interaction_wakeup(struct mlx90635_data *data)
{ unsignedlong now; int ret;
now = jiffies; if (time_in_range(now, data->interaction_ts,
data->interaction_ts +
msecs_to_jiffies(MLX90635_MEAS_MAX_TIME + 100))) {
ret = mlx90635_pwr_continuous(data); if (ret < 0) return ret;
}
data->interaction_ts = now;
return 0;
}
staticint mlx90635_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *channel, int *val, int *val2, long mask)
{ struct mlx90635_data *data = iio_priv(indio_dev); int ret; int cr;
pm_runtime_get_sync(&data->client->dev);
ret = mlx90635_pm_interaction_wakeup(data); if (ret < 0) goto mlx90635_read_raw_pm;
switch (mask) { case IIO_CHAN_INFO_PROCESSED: switch (channel->channel2) { case IIO_MOD_TEMP_AMBIENT:
ret = mlx90635_calc_ambient(data, val); if (ret < 0) goto mlx90635_read_raw_pm;
ret = IIO_VAL_INT; break; case IIO_MOD_TEMP_OBJECT:
ret = mlx90635_calc_object(data, val); if (ret < 0) goto mlx90635_read_raw_pm;
ret = IIO_VAL_INT; break; default:
ret = -EINVAL; break;
} break; case IIO_CHAN_INFO_CALIBEMISSIVITY: if (data->emissivity == 1000) {
*val = 1;
*val2 = 0;
} else {
*val = 0;
*val2 = data->emissivity * 1000;
}
ret = IIO_VAL_INT_PLUS_MICRO; break; case IIO_CHAN_INFO_SAMP_FREQ:
ret = mlx90635_get_refresh_rate(data, &cr); if (ret < 0) goto mlx90635_read_raw_pm;
*val = mlx90635_freqs[cr].val;
*val2 = mlx90635_freqs[cr].val2;
ret = IIO_VAL_INT_PLUS_MICRO; break; default:
ret = -EINVAL; break;
}
staticint mlx90635_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *channel, int val, int val2, long mask)
{ struct mlx90635_data *data = iio_priv(indio_dev); int ret; int i;
switch (mask) { case IIO_CHAN_INFO_CALIBEMISSIVITY: /* Confirm we are within 0 and 1.0 */ if (val < 0 || val2 < 0 || val > 1 ||
(val == 1 && val2 != 0)) return -EINVAL;
data->emissivity = val * 1000 + val2 / 1000; return 0; case IIO_CHAN_INFO_SAMP_FREQ: for (i = 0; i < ARRAY_SIZE(mlx90635_freqs); i++) { if (val == mlx90635_freqs[i].val &&
val2 == mlx90635_freqs[i].val2) break;
} if (i == ARRAY_SIZE(mlx90635_freqs)) return -EINVAL;
ret = regmap_write_bits(data->regmap, MLX90635_REG_CTRL1,
MLX90635_CTRL1_REFRESH_RATE_MASK, i);
ret = mlx90635_pwr_continuous(data); if (ret < 0) {
dev_err(&data->client->dev, "Switch to continuous mode failed\n"); return ret;
}
ret = regmap_write_bits(data->regmap, MLX90635_REG_EE,
MLX90635_EE_ACTIVE, MLX90635_EE_ACTIVE); if (ret < 0) {
dev_err(&data->client->dev, "Powering EEPROM failed\n"); return ret;
}
usleep_range(MLX90635_TIMING_EE_ACTIVE_MIN, MLX90635_TIMING_EE_ACTIVE_MAX);
regcache_mark_dirty(data->regmap_ee);
ret = regcache_sync(data->regmap_ee); if (ret < 0) {
dev_err(&data->client->dev, "Failed to sync cache: %d\n", ret); return ret;
}
ret = mlx90635_read_ee_ambient(data->regmap_ee, &PG, &PO, &Gb); if (ret < 0) {
dev_err(&data->client->dev, "Failed to read to cache Ambient coefficients EEPROM region: %d\n", ret); return ret;
}
ret = mlx90635_read_ee_object(data->regmap_ee, &Ea, &Eb, &Fa, &Fb, &Ga, &Gb, &Ha, &Hb, &Fa_scale); if (ret < 0) {
dev_err(&data->client->dev, "Failed to read to cache Object coefficients EEPROM region: %d\n", ret); return ret;
}
ret = regmap_read(data->regmap_ee, MLX90635_EE_VERSION, &dsp_version); if (ret < 0) {
dev_err(&data->client->dev, "Failed to read to cache of EEPROM version: %d\n", ret); return ret;
}
mlx90635->regulator = devm_regulator_get(&client->dev, "vdd"); if (IS_ERR(mlx90635->regulator)) return dev_err_probe(&client->dev, PTR_ERR(mlx90635->regulator), "failed to get vdd regulator");
ret = mlx90635_enable_regulator(mlx90635); if (ret < 0) return ret;
ret = devm_add_action_or_reset(&client->dev, mlx90635_disable_regulator,
mlx90635); if (ret < 0) return dev_err_probe(&client->dev, ret, "failed to setup regulator cleanup action\n");
ret = mlx90635_wakeup(mlx90635); if (ret < 0) return dev_err_probe(&client->dev, ret, "wakeup failed\n");
ret = devm_add_action_or_reset(&client->dev, mlx90635_sleep, mlx90635); if (ret < 0) return dev_err_probe(&client->dev, ret, "failed to setup low power cleanup\n");
ret = regmap_read(mlx90635->regmap_ee, MLX90635_EE_VERSION, &dsp_version); if (ret < 0) return dev_err_probe(&client->dev, ret, "read of version failed\n");
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.