/* * Accellerometer and magnetometer have the same ODR options, set in the * CTRL_REG1 register. ODR is halved when using both sensors at once in * hybrid mode.
*/ staticconststruct fxos8700_odr fxos8700_odr[] = {
{0x00, 800, 0},
{0x01, 400, 0},
{0x02, 200, 0},
{0x03, 100, 0},
{0x04, 50, 0},
{0x05, 12, 500000},
{0x06, 6, 250000},
{0x07, 1, 562500},
};
staticint fxos8700_set_scale(struct fxos8700_data *data, enum fxos8700_sensor t, int uscale)
{ int i, ret, val; bool active_mode; staticconstint scale_num = ARRAY_SIZE(fxos8700_accel_scale); struct device *dev = regmap_get_device(data->regmap);
if (t == FXOS8700_MAGN) {
dev_err(dev, "Magnetometer scale is locked at 0.001Gs\n"); return -EINVAL;
}
/* * When device is in active mode, it failed to set an ACCEL * full-scale range(2g/4g/8g) in FXOS8700_XYZ_DATA_CFG. * This is not align with the datasheet, but it is a fxos8700 * chip behavier. Set the device in standby mode before setting * an ACCEL full-scale range.
*/
ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val); if (ret) return ret;
active_mode = val & FXOS8700_ACTIVE; if (active_mode) {
ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1,
val & ~FXOS8700_ACTIVE); if (ret) return ret;
}
for (i = 0; i < scale_num; i++) if (fxos8700_accel_scale[i].uscale == uscale) break;
if (i == scale_num) return -EINVAL;
ret = regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG,
fxos8700_accel_scale[i].bits); if (ret) return ret; return regmap_write(data->regmap, FXOS8700_CTRL_REG1,
active_mode);
}
staticint fxos8700_get_scale(struct fxos8700_data *data, enum fxos8700_sensor t, int *uscale)
{ int i, ret, val; staticconstint scale_num = ARRAY_SIZE(fxos8700_accel_scale);
if (t == FXOS8700_MAGN) {
*uscale = 1000; /* Magnetometer is locked at 0.001Gs */ return 0;
}
ret = regmap_read(data->regmap, FXOS8700_XYZ_DATA_CFG, &val); if (ret) return ret;
for (i = 0; i < scale_num; i++) { if (fxos8700_accel_scale[i].bits == (val & 0x3)) {
*uscale = fxos8700_accel_scale[i].uscale; return 0;
}
}
return -EINVAL;
}
staticint fxos8700_get_data(struct fxos8700_data *data, int chan_type, int axis, int *val)
{
u8 base, reg;
s16 tmp; int ret;
/* * Different register base addresses varies with channel types. * This bug hasn't been noticed before because using an enum is * really hard to read. Use an a switch statement to take over that.
*/ switch (chan_type) { case IIO_ACCEL:
base = FXOS8700_OUT_X_MSB; break; case IIO_MAGN:
base = FXOS8700_M_OUT_X_MSB; break; default: return -EINVAL;
}
/* Block read 6 bytes of device output registers to avoid data loss */
ret = regmap_bulk_read(data->regmap, base, data->buf, sizeof(data->buf)); if (ret) return ret;
/* Convert axis to buffer index */
reg = axis - IIO_MOD_X;
/* * Convert to native endianness. The accel data and magn data * are signed, so a forced type conversion is needed.
*/
tmp = be16_to_cpu(data->buf[reg]);
/* * ACCEL output data registers contain the X-axis, Y-axis, and Z-axis * 14-bit left-justified sample data and MAGN output data registers * contain the X-axis, Y-axis, and Z-axis 16-bit sample data. Apply * a signed 2 bits right shift to the readback raw data from ACCEL * output data register and keep that from MAGN sensor as the origin. * Value should be extended to 32 bit.
*/ switch (chan_type) { case IIO_ACCEL:
tmp = tmp >> 2; break; case IIO_MAGN: /* Nothing to do */ break; default: return -EINVAL;
}
/* Convert to native endianness */
*val = sign_extend32(tmp, 15);
return 0;
}
staticint fxos8700_set_odr(struct fxos8700_data *data, enum fxos8700_sensor t, int odr, int uodr)
{ int i, ret, val; bool active_mode; staticconstint odr_num = ARRAY_SIZE(fxos8700_odr);
ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val); if (ret) return ret;
active_mode = val & FXOS8700_ACTIVE;
if (active_mode) { /* * The device must be in standby mode to change any of the * other fields within CTRL_REG1
*/
ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1,
val & ~FXOS8700_ACTIVE); if (ret) return ret;
}
for (i = 0; i < odr_num; i++) if (fxos8700_odr[i].odr == odr && fxos8700_odr[i].uodr == uodr) break;
if (i >= odr_num) return -EINVAL;
val &= ~FXOS8700_CTRL_ODR_MSK;
val |= FIELD_PREP(FXOS8700_CTRL_ODR_MSK, fxos8700_odr[i].bits) | FXOS8700_ACTIVE; return regmap_write(data->regmap, FXOS8700_CTRL_REG1, val);
}
staticint fxos8700_get_odr(struct fxos8700_data *data, enum fxos8700_sensor t, int *odr, int *uodr)
{ int i, val, ret; staticconstint odr_num = ARRAY_SIZE(fxos8700_odr);
ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val); if (ret) return ret;
val = FIELD_GET(FXOS8700_CTRL_ODR_MSK, val);
for (i = 0; i < odr_num; i++) if (val == fxos8700_odr[i].bits) break;
staticint fxos8700_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{ int ret; struct fxos8700_data *data = iio_priv(indio_dev);
switch (mask) { case IIO_CHAN_INFO_RAW:
ret = fxos8700_get_data(data, chan->type, chan->channel2, val); if (ret) return ret; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE:
*val = 0;
ret = fxos8700_get_scale(data, fxos8700_to_sensor(chan->type),
val2); return ret ? ret : IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SAMP_FREQ:
ret = fxos8700_get_odr(data, fxos8700_to_sensor(chan->type),
val, val2); return ret ? ret : IIO_VAL_INT_PLUS_MICRO; default: return -EINVAL;
}
}
staticint fxos8700_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask)
{ struct fxos8700_data *data = iio_priv(indio_dev);
ret = regmap_read(data->regmap, FXOS8700_WHO_AM_I, &val); if (ret) {
dev_err(dev, "Error reading chip id\n"); return ret;
} if (val != FXOS8700_DEVICE_ID && val != FXOS8700_PRE_DEVICE_ID) {
dev_err(dev, "Wrong chip id, got %x expected %x or %x\n",
val, FXOS8700_DEVICE_ID, FXOS8700_PRE_DEVICE_ID); return -ENODEV;
}
ret = fxos8700_set_active_mode(data, FXOS8700_ACCEL, true); if (ret) return ret;
ret = fxos8700_set_active_mode(data, FXOS8700_MAGN, true); if (ret) return ret;
/* * The device must be in standby mode to change any of the other fields * within CTRL_REG1
*/
ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, 0x00); if (ret) return ret;
/* Set max oversample ratio (OSR) and both devices active */
ret = regmap_write(data->regmap, FXOS8700_M_CTRL_REG1,
FXOS8700_HMS_MASK | FXOS8700_OS_MASK); if (ret) return ret;
/* Disable and rst min/max measurements & threshold */
ret = regmap_write(data->regmap, FXOS8700_M_CTRL_REG2,
FXOS8700_MAXMIN_RST | FXOS8700_MAXMIN_DIS_THS |
FXOS8700_MAXMIN_DIS); if (ret) return ret;
/* * Set max full-scale range (+/-8G) for ACCEL sensor in chip * initialization then activate the device.
*/
ret = regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, MODE_8G); if (ret) return ret;
/* Max ODR (800Hz individual or 400Hz hybrid), active mode */ return regmap_update_bits(data->regmap, FXOS8700_CTRL_REG1,
FXOS8700_CTRL_ODR_MSK | FXOS8700_ACTIVE,
FIELD_PREP(FXOS8700_CTRL_ODR_MSK, FXOS8700_CTRL_ODR_MAX) |
FXOS8700_ACTIVE);
}
MODULE_AUTHOR("Robert Jones ");
MODULE_DESCRIPTION("FXOS8700 6-Axis Acc and Mag Combo Sensor driver");
MODULE_LICENSE("GPL v2");
Messung V0.5
¤ 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.0.8Bemerkung:
¤
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.