/* Ensure correct alignment of time stamp when present */ struct {
__be16 channels[3];
aligned_s64 ts;
} buffer;
};
/** * struct mma8452_event_regs - chip specific data related to events * @ev_cfg: event config register address * @ev_cfg_ele: latch bit in event config register * @ev_cfg_chan_shift: number of the bit to enable events in X * direction; in event config register * @ev_src: event source register address * @ev_ths: event threshold register address * @ev_ths_mask: mask for the threshold value * @ev_count: event count (period) register address * * Since not all chips supported by the driver support comparing high pass * filtered data for events (interrupts), different interrupt sources are * used for different chips and the relevant registers are included here.
*/ struct mma8452_event_regs {
u8 ev_cfg;
u8 ev_cfg_ele;
u8 ev_cfg_chan_shift;
u8 ev_src;
u8 ev_ths;
u8 ev_ths_mask;
u8 ev_count;
};
/** * struct mma_chip_info - chip specific data * @name: part number of device reported via 'name' attr * @chip_id: WHO_AM_I register's value * @channels: struct iio_chan_spec matching the device's * capabilities * @num_channels: number of channels * @mma_scales: scale factors for converting register values * to m/s^2; 3 modes: 2g, 4g, 8g; 2 integers * per mode: m/s^2 and micro m/s^2 * @all_events: all events supported by this chip * @enabled_events: event flags enabled and handled by this driver
*/ struct mma_chip_info { constchar *name;
u8 chip_id; conststruct iio_chan_spec *channels; int num_channels; constint mma_scales[3][2]; int all_events; int enabled_events;
};
enum {
idx_x,
idx_y,
idx_z,
idx_ts,
};
staticint mma8452_drdy(struct mma8452_data *data)
{ int tries = 150;
while (tries-- > 0) { int ret = i2c_smbus_read_byte_data(data->client,
MMA8452_STATUS); if (ret < 0) return ret; if ((ret & MMA8452_STATUS_DRDY) == MMA8452_STATUS_DRDY) return 0;
if (on) {
ret = pm_runtime_resume_and_get(&client->dev);
} else {
pm_runtime_mark_last_busy(&client->dev);
ret = pm_runtime_put_autosuspend(&client->dev);
}
if (ret < 0) {
dev_err(&client->dev, "failed to change power state to %d\n", on);
return ret;
} #endif
return 0;
}
staticint mma8452_read(struct mma8452_data *data, __be16 buf[3])
{ int ret = mma8452_drdy(data);
if (ret < 0) return ret;
ret = mma8452_set_runtime_pm_state(data->client, true); if (ret) return ret;
ret = i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X,
3 * sizeof(__be16), (u8 *)buf);
ret = mma8452_set_runtime_pm_state(data->client, false);
return ret;
}
static ssize_t mma8452_show_int_plus_micros(char *buf, constint (*vals)[2], int n)
{
size_t len = 0;
while (n-- > 0)
len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ",
vals[n][0], vals[n][1]);
/* replace trailing space by newline */
buf[len - 1] = '\n';
return len;
}
staticint mma8452_get_int_plus_micros_index(constint (*vals)[2], int n, int val, int val2)
{ while (n-- > 0) if (val == vals[n][0] && val2 == vals[n][1]) return n;
staticint mma8452_read_hp_filter(struct mma8452_data *data, int *hz, int *uHz)
{ int j, i, ret;
ret = i2c_smbus_read_byte_data(data->client, MMA8452_HP_FILTER_CUTOFF); if (ret < 0) return ret;
i = mma8452_get_odr_index(data);
j = mma8452_get_power_mode(data); if (j < 0) return j;
ret &= MMA8452_HP_FILTER_CUTOFF_SEL_MASK;
*hz = mma8452_hp_filter_cutoff[j][i][ret][0];
*uHz = mma8452_hp_filter_cutoff[j][i][ret][1];
return 0;
}
staticint mma8452_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{ struct mma8452_data *data = iio_priv(indio_dev);
__be16 buffer[3]; int i, ret;
switch (mask) { case IIO_CHAN_INFO_RAW: if (!iio_device_claim_direct(indio_dev)) return -EBUSY;
mutex_lock(&data->lock);
ret = mma8452_read(data, buffer);
mutex_unlock(&data->lock);
iio_device_release_direct(indio_dev); if (ret < 0) return ret;
/* returns >0 if in freefall mode, 0 if not or <0 if an error occurred */ staticint mma8452_freefall_mode_enabled(struct mma8452_data *data)
{ int val;
val = i2c_smbus_read_byte_data(data->client, MMA8452_FF_MT_CFG); if (val < 0) return val;
return !(val & MMA8452_FF_MT_CFG_OAE);
}
staticint mma8452_set_freefall_mode(struct mma8452_data *data, bool state)
{ int val;
if ((state && mma8452_freefall_mode_enabled(data)) ||
(!state && !(mma8452_freefall_mode_enabled(data)))) return 0;
val = i2c_smbus_read_byte_data(data->client, MMA8452_FF_MT_CFG); if (val < 0) return val;
if (state) {
val |= BIT(idx_x + MMA8452_FF_MT_CHAN_SHIFT);
val |= BIT(idx_y + MMA8452_FF_MT_CHAN_SHIFT);
val |= BIT(idx_z + MMA8452_FF_MT_CHAN_SHIFT);
val &= ~MMA8452_FF_MT_CFG_OAE;
} else {
val &= ~BIT(idx_x + MMA8452_FF_MT_CHAN_SHIFT);
val &= ~BIT(idx_y + MMA8452_FF_MT_CHAN_SHIFT);
val &= ~BIT(idx_z + MMA8452_FF_MT_CHAN_SHIFT);
val |= MMA8452_FF_MT_CFG_OAE;
}
staticint __mma8452_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask)
{ struct mma8452_data *data = iio_priv(indio_dev); int i, j, ret;
switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ:
i = mma8452_get_samp_freq_index(data, val, val2); if (i < 0) return i;
data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK;
data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT;
ret = mma8452_get_event_regs(data, chan, dir, &ev_regs); if (ret) return ret;
switch (dir) { case IIO_EV_DIR_FALLING: return mma8452_freefall_mode_enabled(data); case IIO_EV_DIR_RISING:
ret = i2c_smbus_read_byte_data(data->client,
ev_regs->ev_cfg); if (ret < 0) return ret;
ret = mma8452_get_event_regs(data, chan, dir, &ev_regs); if (ret) return ret;
ret = mma8452_set_runtime_pm_state(data->client, state); if (ret) return ret;
switch (dir) { case IIO_EV_DIR_FALLING: return mma8452_set_freefall_mode(data, state); case IIO_EV_DIR_RISING:
val = i2c_smbus_read_byte_data(data->client, ev_regs->ev_cfg); if (val < 0) return val;
if (state) { if (mma8452_freefall_mode_enabled(data)) {
val &= ~BIT(idx_x + ev_regs->ev_cfg_chan_shift);
val &= ~BIT(idx_y + ev_regs->ev_cfg_chan_shift);
val &= ~BIT(idx_z + ev_regs->ev_cfg_chan_shift);
val |= MMA8452_FF_MT_CFG_OAE;
}
val |= BIT(chan->scan_index +
ev_regs->ev_cfg_chan_shift);
} else { if (mma8452_freefall_mode_enabled(data)) return 0;
val &= ~BIT(chan->scan_index +
ev_regs->ev_cfg_chan_shift);
}
/* * Threshold is configured in fixed 8G/127 steps regardless of * currently selected scale for measurement.
*/ static IIO_CONST_ATTR_NAMED(accel_transient_scale, in_accel_scale, "0.617742");
staticconststruct mma_chip_info mma_chip_info_table[] = {
[mma8451] = {
.name = "mma8451",
.chip_id = MMA8451_DEVICE_ID,
.channels = mma8451_channels,
.num_channels = ARRAY_SIZE(mma8451_channels), /* * Hardware has fullscale of -2G, -4G, -8G corresponding to * raw value -8192 for 14 bit, -2048 for 12 bit or -512 for 10 * bit. * The userspace interface uses m/s^2 and we declare micro units * So scale factor for 12 bit here is given by: * g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665
*/
.mma_scales = { {0, 2394}, {0, 4788}, {0, 9577} }, /* * Although we enable the interrupt sources once and for * all here the event detection itself is not enabled until * userspace asks for it by mma8452_write_event_config()
*/
.all_events = MMA8452_INT_DRDY |
MMA8452_INT_TRANS |
MMA8452_INT_FF_MT,
.enabled_events = MMA8452_INT_TRANS |
MMA8452_INT_FF_MT,
},
[mma8452] = {
.name = "mma8452",
.chip_id = MMA8452_DEVICE_ID,
.channels = mma8452_channels,
.num_channels = ARRAY_SIZE(mma8452_channels),
.mma_scales = { {0, 9577}, {0, 19154}, {0, 38307} }, /* * Although we enable the interrupt sources once and for * all here the event detection itself is not enabled until * userspace asks for it by mma8452_write_event_config()
*/
.all_events = MMA8452_INT_DRDY |
MMA8452_INT_TRANS |
MMA8452_INT_FF_MT,
.enabled_events = MMA8452_INT_TRANS |
MMA8452_INT_FF_MT,
},
[mma8453] = {
.name = "mma8453",
.chip_id = MMA8453_DEVICE_ID,
.channels = mma8453_channels,
.num_channels = ARRAY_SIZE(mma8453_channels),
.mma_scales = { {0, 38307}, {0, 76614}, {0, 153228} }, /* * Although we enable the interrupt sources once and for * all here the event detection itself is not enabled until * userspace asks for it by mma8452_write_event_config()
*/
.all_events = MMA8452_INT_DRDY |
MMA8452_INT_TRANS |
MMA8452_INT_FF_MT,
.enabled_events = MMA8452_INT_TRANS |
MMA8452_INT_FF_MT,
},
[mma8652] = {
.name = "mma8652",
.chip_id = MMA8652_DEVICE_ID,
.channels = mma8652_channels,
.num_channels = ARRAY_SIZE(mma8652_channels),
.mma_scales = { {0, 9577}, {0, 19154}, {0, 38307} },
.all_events = MMA8452_INT_DRDY |
MMA8452_INT_FF_MT,
.enabled_events = MMA8452_INT_FF_MT,
},
[mma8653] = {
.name = "mma8653",
.chip_id = MMA8653_DEVICE_ID,
.channels = mma8653_channels,
.num_channels = ARRAY_SIZE(mma8653_channels),
.mma_scales = { {0, 38307}, {0, 76614}, {0, 153228} }, /* * Although we enable the interrupt sources once and for * all here the event detection itself is not enabled until * userspace asks for it by mma8452_write_event_config()
*/
.all_events = MMA8452_INT_DRDY |
MMA8452_INT_FF_MT,
.enabled_events = MMA8452_INT_FF_MT,
},
[fxls8471] = {
.name = "fxls8471",
.chip_id = FXLS8471_DEVICE_ID,
.channels = mma8451_channels,
.num_channels = ARRAY_SIZE(mma8451_channels),
.mma_scales = { {0, 2394}, {0, 4788}, {0, 9577} }, /* * Although we enable the interrupt sources once and for * all here the event detection itself is not enabled until * userspace asks for it by mma8452_write_event_config()
*/
.all_events = MMA8452_INT_DRDY |
MMA8452_INT_TRANS |
MMA8452_INT_FF_MT,
.enabled_events = MMA8452_INT_TRANS |
MMA8452_INT_FF_MT,
},
};
ret = iio_trigger_register(trig); if (ret) return ret;
indio_dev->trig = iio_trigger_get(trig);
return 0;
}
staticvoid mma8452_trigger_cleanup(struct iio_dev *indio_dev)
{ if (indio_dev->trig)
iio_trigger_unregister(indio_dev->trig);
}
staticint mma8452_reset(struct i2c_client *client)
{ int i; int ret;
/* * Find on fxls8471, after config reset bit, it reset immediately, * and will not give ACK, so here do not check the return value. * The following code will read the reset register, and check whether * this reset works.
*/
i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG2,
MMA8452_CTRL_REG2_RST);
for (i = 0; i < 10; i++) {
usleep_range(100, 200);
ret = i2c_smbus_read_byte_data(client, MMA8452_CTRL_REG2); if (ret == -EIO) continue; /* I2C comm reset */ if (ret < 0) return ret; if (!(ret & MMA8452_CTRL_REG2_RST)) return 0;
}
ret = iio_read_mount_matrix(&client->dev, &data->orientation); if (ret) return ret;
data->vdd_reg = devm_regulator_get(&client->dev, "vdd"); if (IS_ERR(data->vdd_reg)) return dev_err_probe(&client->dev, PTR_ERR(data->vdd_reg), "failed to get VDD regulator!\n");
data->vddio_reg = devm_regulator_get(&client->dev, "vddio"); if (IS_ERR(data->vddio_reg)) return dev_err_probe(&client->dev, PTR_ERR(data->vddio_reg), "failed to get VDDIO regulator!\n");
ret = regulator_enable(data->vdd_reg); if (ret) {
dev_err(&client->dev, "failed to enable VDD regulator!\n"); return ret;
}
ret = regulator_enable(data->vddio_reg); if (ret) {
dev_err(&client->dev, "failed to enable VDDIO regulator!\n"); goto disable_regulator_vdd;
}
ret = i2c_smbus_read_byte_data(client, MMA8452_WHO_AM_I); if (ret < 0) goto disable_regulators;
switch (ret) { case MMA8451_DEVICE_ID: case MMA8452_DEVICE_ID: case MMA8453_DEVICE_ID: case MMA8652_DEVICE_ID: case MMA8653_DEVICE_ID: case FXLS8471_DEVICE_ID: if (ret == data->chip_info->chip_id) break;
fallthrough; default:
ret = -ENODEV; goto disable_regulators;
}
dev_info(&client->dev, "registering %s accelerometer; ID 0x%x\n",
data->chip_info->name, data->chip_info->chip_id);
ret = mma8452_reset(client); if (ret < 0) goto disable_regulators;
data->data_cfg = MMA8452_DATA_CFG_FS_2G;
ret = i2c_smbus_write_byte_data(client, MMA8452_DATA_CFG,
data->data_cfg); if (ret < 0) goto disable_regulators;
/* * By default set transient threshold to max to avoid events if * enabling without configuring threshold.
*/
ret = i2c_smbus_write_byte_data(client, MMA8452_TRANSIENT_THS,
MMA8452_TRANSIENT_THS_MASK); if (ret < 0) goto disable_regulators;
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.