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;
}
}
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;
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;
/* *Theoversamplingratioisstoredinadifferentregister *basedonthepower-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; return0; 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) return0;
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;
}
staticint bma400_enable_steps(struct bma400_data *data, int val)
{ int ret;
if (data->steps_enabled == val) return0;
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:Thedatasheetwaits1500ushereintheexample,but *lists2/ODRasthewakeuptime.
*/
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; /* *Oncetheinterruptengineissupportedwemightusethe *data_src_reg,butfornowensurethisissettothe *variableODRfilterselectablebythesamplefrequency *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; /* *Thedevicedoesnotsupportconfidencevaluelevels, *sowewillalwayshave100%forcurrentactivityand *0%fortheothers.
*/ 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;
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; return0;
}
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;
/* 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;
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.