/* * The G-range selection may be one of 2g, 4g, 8, or 16g. The scale may * be selected with the acc_range bits of the ACC_CONFIG1 register. * NB: This buffer is populated in the device init.
*/ staticint bma400_scales[8];
/* * See the ACC_CONFIG1 section of the datasheet. * NB: This buffer is populated in the device init.
*/ staticint bma400_sample_freqs[14];
staticbool bma400_is_writable_reg(struct device *dev, unsignedint reg)
{ switch (reg) { case BMA400_CHIP_ID_REG: case BMA400_ERR_REG: case BMA400_STATUS_REG: case BMA400_X_AXIS_LSB_REG: case BMA400_X_AXIS_MSB_REG: case BMA400_Y_AXIS_LSB_REG: case BMA400_Y_AXIS_MSB_REG: case BMA400_Z_AXIS_LSB_REG: case BMA400_Z_AXIS_MSB_REG: case BMA400_SENSOR_TIME0: case BMA400_SENSOR_TIME1: case BMA400_SENSOR_TIME2: case BMA400_EVENT_REG: case BMA400_INT_STAT0_REG: case BMA400_INT_STAT1_REG: case BMA400_INT_STAT2_REG: case BMA400_TEMP_DATA_REG: case BMA400_FIFO_LENGTH0_REG: case BMA400_FIFO_LENGTH1_REG: case BMA400_FIFO_DATA_REG: case BMA400_STEP_CNT0_REG: case BMA400_STEP_CNT1_REG: case BMA400_STEP_CNT3_REG: case BMA400_STEP_STAT_REG: returnfalse; default: returntrue;
}
}
staticbool bma400_is_volatile_reg(struct device *dev, unsignedint reg)
{ switch (reg) { case BMA400_ERR_REG: case BMA400_STATUS_REG: case BMA400_X_AXIS_LSB_REG: case BMA400_X_AXIS_MSB_REG: case BMA400_Y_AXIS_LSB_REG: case BMA400_Y_AXIS_MSB_REG: case BMA400_Z_AXIS_LSB_REG: case BMA400_Z_AXIS_MSB_REG: case BMA400_SENSOR_TIME0: case BMA400_SENSOR_TIME1: case BMA400_SENSOR_TIME2: case BMA400_EVENT_REG: case BMA400_INT_STAT0_REG: case BMA400_INT_STAT1_REG: case BMA400_INT_STAT2_REG: case BMA400_TEMP_DATA_REG: case BMA400_FIFO_LENGTH0_REG: case BMA400_FIFO_LENGTH1_REG: case BMA400_FIFO_DATA_REG: case BMA400_STEP_CNT0_REG: case BMA400_STEP_CNT1_REG: case BMA400_STEP_CNT3_REG: case BMA400_STEP_STAT_REG: returntrue; default: returnfalse;
}
}
/* * Tap interrupts works with 200 Hz input data rate and the time based tap * controls are in the terms of data samples so the below calculation is * used to convert the configuration values into seconds. * e.g.: * 60 data samples * 0.005 ms = 0.3 seconds. * 80 data samples * 0.005 ms = 0.4 seconds.
*/
staticint bma400_get_temp_reg(struct bma400_data *data, int *val, int *val2)
{ unsignedint raw_temp; int host_temp; int ret;
if (data->power_mode == POWER_MODE_SLEEP) return -EBUSY;
ret = regmap_read(data->regmap, BMA400_TEMP_DATA_REG, &raw_temp); if (ret) return ret;
host_temp = sign_extend32(raw_temp, 7); /* * The formula for the TEMP_DATA register in the datasheet * is: x * 0.5 + 23
*/
*val = (host_temp >> 1) + 23;
*val2 = (host_temp & 0x1) * 500000; return IIO_VAL_INT_PLUS_MICRO;
}
staticint bma400_get_accel_reg(struct bma400_data *data, conststruct iio_chan_spec *chan, int *val)
{
__le16 raw_accel; int lsb_reg; int ret;
if (data->power_mode == POWER_MODE_SLEEP) return -EBUSY;
switch (chan->channel2) { case IIO_MOD_X:
lsb_reg = BMA400_X_AXIS_LSB_REG; break; case IIO_MOD_Y:
lsb_reg = BMA400_Y_AXIS_LSB_REG; break; case IIO_MOD_Z:
lsb_reg = BMA400_Z_AXIS_LSB_REG; break; default:
dev_err(data->dev, "invalid axis channel modifier\n"); return -EINVAL;
}
/* bulk read two registers, with the base being the LSB register */
ret = regmap_bulk_read(data->regmap, lsb_reg, &raw_accel, sizeof(raw_accel)); if (ret) return ret;
switch (data->power_mode) { case POWER_MODE_LOW: /* * Runs at a fixed rate in low-power mode. See section 4.3 * in the datasheet.
*/
bma400_output_data_rate_from_raw(BMA400_ACC_ODR_LP_RAW,
&data->sample_freq.hz,
&data->sample_freq.uhz); return 0; case POWER_MODE_NORMAL: /* * In normal mode the ODR can be found in the ACC_CONFIG1 * register.
*/
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG, &val); if (ret) goto error;
odr = val & BMA400_ACC_ODR_MASK; if (odr < BMA400_ACC_ODR_MIN_RAW ||
odr > BMA400_ACC_ODR_MAX_RAW) {
ret = -EINVAL; goto error;
}
/* * The oversampling ratio is stored in a different register * based on the power-mode. In normal mode the OSR is stored * in ACC_CONFIG1. In low-power mode it is stored in * ACC_CONFIG0.
*/ switch (data->power_mode) { case POWER_MODE_LOW:
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG0_REG, &val); if (ret) {
data->oversampling_ratio = -1; return ret;
}
staticint bma400_set_accel_oversampling_ratio(struct bma400_data *data, int val)
{ unsignedint acc_config; int ret;
if (val & ~BMA400_TWO_BITS_MASK) return -EINVAL;
/* * The oversampling ratio is stored in a different register * based on the power-mode.
*/ switch (data->power_mode) { case POWER_MODE_LOW:
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG0_REG,
&acc_config); if (ret) return ret;
ret = regmap_write(data->regmap, BMA400_ACC_CONFIG0_REG,
(acc_config & ~BMA400_LP_OSR_MASK) |
(val << BMA400_LP_OSR_SHIFT)); if (ret) {
dev_err(data->dev, "Failed to write out OSR\n"); return ret;
}
data->oversampling_ratio = val; return 0; case POWER_MODE_NORMAL:
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG1_REG,
&acc_config); if (ret) return ret;
ret = regmap_write(data->regmap, BMA400_ACC_CONFIG1_REG,
(acc_config & ~BMA400_NP_OSR_MASK) |
(val << BMA400_NP_OSR_SHIFT)); if (ret) {
dev_err(data->dev, "Failed to write out OSR\n"); return ret;
}
ret = regmap_read(data->regmap, BMA400_ACC_CONFIG0_REG, &val); if (ret) return ret;
if (data->power_mode == mode) return 0;
if (mode == POWER_MODE_INVALID) return -EINVAL;
/* Preserve the low-power oversample ratio etc */
ret = regmap_write(data->regmap, BMA400_ACC_CONFIG0_REG,
mode | (val & ~BMA400_TWO_BITS_MASK)); if (ret) {
dev_err(data->dev, "Failed to write to power-mode\n"); return ret;
}
data->power_mode = mode;
/* * Update our cached osr and odr based on the new * power-mode.
*/
bma400_get_accel_output_data_rate(data);
bma400_get_accel_oversampling_ratio(data); return 0;
}
staticint bma400_enable_steps(struct bma400_data *data, int val)
{ int ret;
if (data->steps_enabled == val) return 0;
ret = regmap_update_bits(data->regmap, BMA400_INT_CONFIG1_REG,
BMA400_STEP_INT_MSK,
FIELD_PREP(BMA400_STEP_INT_MSK, val ? 1 : 0)); if (ret) return ret;
data->steps_enabled = val; return ret;
}
staticint bma400_get_steps_reg(struct bma400_data *data, int *val)
{ int ret;
u8 *steps_raw __free(kfree) = kmalloc(BMA400_STEP_RAW_LEN, GFP_KERNEL); if (!steps_raw) return -ENOMEM;
ret = regmap_bulk_read(data->regmap, BMA400_STEP_CNT0_REG,
steps_raw, BMA400_STEP_RAW_LEN); if (ret) return ret;
*val = get_unaligned_le24(steps_raw);
return IIO_VAL_INT;
}
staticvoid bma400_init_tables(void)
{ int raw; int i;
for (i = 0; i + 1 < ARRAY_SIZE(bma400_sample_freqs); i += 2) {
raw = (i / 2) + 5;
bma400_output_data_rate_from_raw(raw, &bma400_sample_freqs[i],
&bma400_sample_freqs[i + 1]);
}
for (i = 0; i + 1 < ARRAY_SIZE(bma400_scales); i += 2) {
raw = i / 2;
bma400_scales[i] = 0;
bma400_scales[i + 1] = BMA400_SCALE_MIN << raw;
}
}
mutex_lock(&data->mutex);
ret = bma400_set_power_mode(data, POWER_MODE_SLEEP);
mutex_unlock(&data->mutex); if (ret)
dev_warn(data->dev, "Failed to put device into sleep mode (%pe)\n",
ERR_PTR(ret));
}
staticenum iio_modifier bma400_act_to_mod(enum bma400_activity activity)
{ switch (activity) { case BMA400_STILL: return IIO_MOD_STILL; case BMA400_WALKING: return IIO_MOD_WALKING; case BMA400_RUNNING: return IIO_MOD_RUNNING; default: return IIO_NO_MOD;
}
}
ret = devm_regulator_bulk_get_enable(data->dev,
ARRAY_SIZE(regulator_names),
regulator_names); if (ret) return dev_err_probe(data->dev, ret, "Failed to get regulators\n");
/* Try to read chip_id register. It must return 0x90. */
ret = regmap_read(data->regmap, BMA400_CHIP_ID_REG, &val); if (ret) {
dev_err(data->dev, "Failed to read chip id register\n"); return ret;
}
if (val != BMA400_ID_REG_VAL) {
dev_err(data->dev, "Chip ID mismatch\n"); return -ENODEV;
}
ret = bma400_get_power_mode(data); if (ret) {
dev_err(data->dev, "Failed to get the initial power-mode\n"); return ret;
}
if (data->power_mode != POWER_MODE_NORMAL) {
ret = bma400_set_power_mode(data, POWER_MODE_NORMAL); if (ret) {
dev_err(data->dev, "Failed to wake up the device\n"); return ret;
} /* * TODO: The datasheet waits 1500us here in the example, but * lists 2/ODR as the wakeup time.
*/
usleep_range(1500, 2000);
}
ret = devm_add_action_or_reset(data->dev, bma400_power_disable, data); if (ret) return ret;
bma400_init_tables();
ret = bma400_get_accel_output_data_rate(data); if (ret) return ret;
ret = bma400_get_accel_oversampling_ratio(data); if (ret) return ret;
ret = bma400_get_accel_scale(data); if (ret) return ret;
/* Configure INT1 pin to open drain */
ret = regmap_write(data->regmap, BMA400_INT_IO_CTRL_REG, 0x06); if (ret) return ret; /* * Once the interrupt engine is supported we might use the * data_src_reg, but for now ensure this is set to the * variable ODR filter selectable by the sample frequency * channel.
*/ return regmap_write(data->regmap, BMA400_ACC_CONFIG2_REG, 0x00);
}
staticint bma400_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{ struct bma400_data *data = iio_priv(indio_dev); unsignedint activity; int ret;
switch (mask) { case IIO_CHAN_INFO_PROCESSED: switch (chan->type) { case IIO_TEMP:
mutex_lock(&data->mutex);
ret = bma400_get_temp_reg(data, val, val2);
mutex_unlock(&data->mutex); return ret; case IIO_STEPS: return bma400_get_steps_reg(data, val); case IIO_ACTIVITY:
ret = regmap_read(data->regmap, BMA400_STEP_STAT_REG,
&activity); if (ret) return ret; /* * The device does not support confidence value levels, * so we will always have 100% for current activity and * 0% for the others.
*/ if (chan->channel2 == bma400_act_to_mod(activity))
*val = 100; else
*val = 0; return IIO_VAL_INT; default: return -EINVAL;
} case IIO_CHAN_INFO_RAW:
mutex_lock(&data->mutex);
ret = bma400_get_accel_reg(data, chan, val);
mutex_unlock(&data->mutex); return ret; case IIO_CHAN_INFO_SAMP_FREQ: switch (chan->type) { case IIO_ACCEL: if (data->sample_freq.hz < 0) return -EINVAL;
*val = data->sample_freq.hz;
*val2 = data->sample_freq.uhz; return IIO_VAL_INT_PLUS_MICRO; case IIO_TEMP: /* * Runs at a fixed sampling frequency. See Section 4.4 * of the datasheet.
*/
*val = 6;
*val2 = 250000; return IIO_VAL_INT_PLUS_MICRO; default: return -EINVAL;
} case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = data->scale; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: /* * TODO: We could avoid this logic and returning -EINVAL here if * we set both the low-power and normal mode OSR registers when * we configure the device.
*/ if (data->oversampling_ratio < 0) return -EINVAL;
staticint bma400_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask)
{ struct bma400_data *data = iio_priv(indio_dev); int ret;
switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: /* * The sample frequency is readonly for the temperature * register and a fixed value in low-power mode.
*/ if (chan->type != IIO_ACCEL) return -EINVAL;
mutex_lock(&data->mutex);
ret = bma400_set_accel_output_data_rate(data, val, val2);
mutex_unlock(&data->mutex); return ret; case IIO_CHAN_INFO_SCALE: if (val != 0 ||
val2 < BMA400_SCALE_MIN || val2 > BMA400_SCALE_MAX) return -EINVAL;
mutex_lock(&data->mutex);
ret = bma400_set_accel_scale(data, val2);
mutex_unlock(&data->mutex); return ret; case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
mutex_lock(&data->mutex);
ret = bma400_set_accel_oversampling_ratio(data, val);
mutex_unlock(&data->mutex); return ret; case IIO_CHAN_INFO_ENABLE:
mutex_lock(&data->mutex);
ret = bma400_enable_steps(data, val);
mutex_unlock(&data->mutex); return ret; default: return -EINVAL;
}
}
staticint bma400_write_raw_get_fmt(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, long mask)
{ switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SCALE: return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: return IIO_VAL_INT; case IIO_CHAN_INFO_ENABLE: return IIO_VAL_INT; default: return -EINVAL;
}
}
switch (chan->type) { case IIO_ACCEL: switch (dir) { case IIO_EV_DIR_RISING: return FIELD_GET(BMA400_INT_GEN1_MSK,
data->generic_event_en); case IIO_EV_DIR_FALLING: return FIELD_GET(BMA400_INT_GEN2_MSK,
data->generic_event_en); case IIO_EV_DIR_SINGLETAP: return FIELD_GET(BMA400_S_TAP_MSK,
data->tap_event_en_bitmask); case IIO_EV_DIR_DOUBLETAP: return FIELD_GET(BMA400_D_TAP_MSK,
data->tap_event_en_bitmask); default: return -EINVAL;
} case IIO_STEPS: return data->step_event_en; case IIO_ACTIVITY: return data->activity_event_en; default: return -EINVAL;
}
}
staticint bma400_steps_event_enable(struct bma400_data *data, int state)
{ int ret;
ret = bma400_enable_steps(data, 1); if (ret) return ret;
ret = regmap_update_bits(data->regmap, BMA400_INT12_MAP_REG,
BMA400_STEP_INT_MSK,
FIELD_PREP(BMA400_STEP_INT_MSK,
state)); if (ret) return ret;
data->step_event_en = state; return 0;
}
staticint bma400_activity_event_en(struct bma400_data *data, enum iio_event_direction dir, int state)
{ int ret, reg, msk, value; int field_value = 0;
switch (dir) { case IIO_EV_DIR_RISING:
reg = BMA400_GEN1INT_CONFIG0;
msk = BMA400_INT_GEN1_MSK;
value = 2;
set_mask_bits(&field_value, BMA400_INT_GEN1_MSK,
FIELD_PREP(BMA400_INT_GEN1_MSK, state)); break; case IIO_EV_DIR_FALLING:
reg = BMA400_GEN2INT_CONFIG0;
msk = BMA400_INT_GEN2_MSK;
value = 0;
set_mask_bits(&field_value, BMA400_INT_GEN2_MSK,
FIELD_PREP(BMA400_INT_GEN2_MSK, state)); break; default: return -EINVAL;
}
/* Enabling all axis for interrupt evaluation */
ret = regmap_write(data->regmap, reg, 0xF8); if (ret) return ret;
/* OR combination of all axis for interrupt evaluation */
ret = regmap_write(data->regmap, reg + BMA400_GEN_CONFIG1_OFF, value); if (ret) return ret;
/* Initial value to avoid interrupts while enabling*/
ret = regmap_write(data->regmap, reg + BMA400_GEN_CONFIG2_OFF, 0x0A); if (ret) return ret;
/* Initial duration value to avoid interrupts while enabling*/
ret = regmap_write(data->regmap, reg + BMA400_GEN_CONFIG31_OFF, 0x0F); if (ret) return ret;
ret = regmap_update_bits(data->regmap, BMA400_INT1_MAP_REG, msk,
field_value); if (ret) return ret;
ret = regmap_update_bits(data->regmap, BMA400_INT_CONFIG0_REG, msk,
field_value); if (ret) return ret;
staticint bma400_tap_event_en(struct bma400_data *data, enum iio_event_direction dir, int state)
{ unsignedint mask; unsignedint field_value = 0; int ret;
/* * Tap interrupts can be configured only in normal mode. * See table in section 4.3 "Power modes - performance modes" of * datasheet v1.2.
*/ if (data->power_mode != POWER_MODE_NORMAL) return -EINVAL;
/* * Tap interrupts are operating with a data rate of 200Hz. * See section 4.7 "Tap sensing interrupt" in datasheet v1.2.
*/ if (data->sample_freq.hz != 200 && state) {
dev_err(data->dev, "Invalid data rate for tap interrupts.\n"); return -EINVAL;
}
ret = regmap_update_bits(data->regmap, BMA400_INT12_MAP_REG,
BMA400_S_TAP_MSK,
FIELD_PREP(BMA400_S_TAP_MSK, state)); if (ret) return ret;
/* Lock to protect the data->buffer */
mutex_lock(&data->mutex);
/* bulk read six registers, with the base being the LSB register */
ret = regmap_bulk_read(data->regmap, BMA400_X_AXIS_LSB_REG,
&data->buffer.buff, sizeof(data->buffer.buff)); if (ret) goto unlock_err;
if (test_bit(BMA400_TEMP, indio_dev->active_scan_mask)) {
ret = regmap_read(data->regmap, BMA400_TEMP_DATA_REG, &temp); if (ret) goto unlock_err;
/* Lock to protect the data->status */
mutex_lock(&data->mutex);
ret = regmap_bulk_read(data->regmap, BMA400_INT_STAT0_REG,
&data->status, sizeof(data->status)); /* * if none of the bit is set in the status register then it is * spurious interrupt.
*/ if (ret || !data->status) goto unlock_err;
/* * Disable all advance interrupts if interrupt engine overrun occurs. * See section 4.7 "Interrupt engine overrun" in datasheet v1.2.
*/ if (FIELD_GET(BMA400_INT_ENG_OVRUN_MSK, le16_to_cpu(data->status))) {
bma400_disable_adv_interrupt(data);
dev_err(data->dev, "Interrupt engine overrun\n"); goto unlock_err;
}
if (FIELD_GET(BMA400_INT_S_TAP_MSK, le16_to_cpu(data->status)))
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
IIO_MOD_X_OR_Y_OR_Z,
IIO_EV_TYPE_GESTURE,
IIO_EV_DIR_SINGLETAP),
timestamp);
if (FIELD_GET(BMA400_INT_D_TAP_MSK, le16_to_cpu(data->status)))
iio_push_event(indio_dev,
IIO_MOD_EVENT_CODE(IIO_ACCEL, 0,
IIO_MOD_X_OR_Y_OR_Z,
IIO_EV_TYPE_GESTURE,
IIO_EV_DIR_DOUBLETAP),
timestamp);
if (FIELD_GET(BMA400_INT_GEN1_MSK, le16_to_cpu(data->status)))
ev_dir = IIO_EV_DIR_RISING;
if (FIELD_GET(BMA400_INT_GEN2_MSK, le16_to_cpu(data->status)))
ev_dir = IIO_EV_DIR_FALLING;
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.