// SPDX-License-Identifier: GPL-2.0 /* * MEMSensing digital 3-Axis accelerometer * * MSA311 is a tri-axial, low-g accelerometer with I2C digital output for * sensitivity consumer applications. It has dynamic user-selectable full * scales range of +-2g/+-4g/+-8g/+-16g and allows acceleration measurements * with output data rates from 1Hz to 1000Hz. * * MSA311 is available in an ultra small (2mm x 2mm, height 0.95mm) LGA package * and is guaranteed to operate over -40C to +85C. * * This driver supports following MSA311 features: * - IIO interface * - Different power modes: NORMAL, SUSPEND * - ODR (Output Data Rate) selection * - Scale selection * - IIO triggered buffer * - NEW_DATA interrupt + trigger * * Below features to be done: * - Motion Events: ACTIVE, TAP, ORIENT, FREEFALL * - Low Power mode * * Copyright (c) 2022, SberDevices. All Rights Reserved. * * Author: Dmitry Rokosov <ddrokosov@sberdevices.ru>
*/
/** * struct msa311_priv - MSA311 internal private state * @regs: Underlying I2C bus adapter used to abstract slave * register accesses * @fields: Abstract objects for each registers fields access * @dev: Device handler associated with appropriate bus client * @lock: Protects msa311 device state between setup and data access routines * (power transitions, samp_freq/scale tune, retrieving axes data, etc) * @chip_name: Chip name in the format "msa311-%02x" % partid * @new_data_trig: Optional NEW_DATA interrupt driven trigger used * to notify external consumers a new sample is ready
*/ struct msa311_priv { struct regmap *regs; struct regmap_field *fields[F_MAX_FIELDS];
/** * msa311_get_odr() - Read Output Data Rate (ODR) value from MSA311 accel * @msa311: MSA311 internal private state * @odr: output ODR value * * This function should be called under msa311->lock. * * Return: 0 on success, -ERRNO in other failures
*/ staticint msa311_get_odr(struct msa311_priv *msa311, unsignedint *odr)
{ int err;
err = regmap_field_read(msa311->fields[F_ODR], odr); if (err) return err;
/* * Filter the same 1000Hz ODR register values based on datasheet info. * ODR can be equal to 1010-1111 for 1000Hz, but function returns 1010 * all the time.
*/ if (*odr > MSA311_ODR_1000_HZ)
*odr = MSA311_ODR_1000_HZ;
return 0;
}
/** * msa311_set_odr() - Setup Output Data Rate (ODR) value for MSA311 accel * @msa311: MSA311 internal private state * @odr: requested ODR value * * This function should be called under msa311->lock. Possible ODR values: * - 1Hz (not available in normal mode) * - 1.95Hz (not available in normal mode) * - 3.9Hz * - 7.81Hz * - 15.63Hz * - 31.25Hz * - 62.5Hz * - 125Hz * - 250Hz * - 500Hz * - 1000Hz * * Return: 0 on success, -EINVAL for bad ODR value in the certain power mode, * -ERRNO in other failures
*/ staticint msa311_set_odr(struct msa311_priv *msa311, unsignedint odr)
{ struct device *dev = msa311->dev; unsignedint pwr_mode; bool good_odr; int err;
err = regmap_field_read(msa311->fields[F_PWR_MODE], &pwr_mode); if (err) return err;
/* Filter bad ODR values */ if (pwr_mode == MSA311_PWR_MODE_NORMAL)
good_odr = (odr > MSA311_ODR_1_95_HZ); else
good_odr = false;
if (!good_odr) {
dev_err(dev, "can't set odr %u.%06uHz, not available in %s mode\n",
msa311_odr_table[odr].integral,
msa311_odr_table[odr].microfract,
msa311_pwr_modes[pwr_mode]); return -EINVAL;
}
/** * msa311_wait_for_next_data() - Wait next accel data available after resume * @msa311: MSA311 internal private state * * Return: 0 on success, -EINTR if msleep() was interrupted, * -ERRNO in other failures
*/ staticint msa311_wait_for_next_data(struct msa311_priv *msa311)
{ staticconstunsignedint unintr_thresh_ms = 20; struct device *dev = msa311->dev; unsignedlong freq_uhz; unsignedlong wait_ms; unsignedint odr; int err;
err = msa311_get_odr(msa311, &odr); if (err) {
dev_err(dev, "can't get actual frequency (%pe)\n",
ERR_PTR(err)); return err;
}
/* * After msa311 resuming is done, we need to wait for data * to be refreshed by accel logic. * A certain timeout is calculated based on the current ODR value. * If requested timeout isn't so long (let's assume 20ms), * we can wait for next data in uninterruptible sleep.
*/
freq_uhz = msa311_odr_table[odr].integral * MICROHZ_PER_HZ +
msa311_odr_table[odr].microfract;
wait_ms = (MICROHZ_PER_HZ / freq_uhz) * MSEC_PER_SEC;
/** * msa311_set_pwr_mode() - Install certain MSA311 power mode * @msa311: MSA311 internal private state * @mode: Power mode can be equal to NORMAL or SUSPEND * * This function should be called under msa311->lock. * * Return: 0 on success, -ERRNO on failure
*/ staticint msa311_set_pwr_mode(struct msa311_priv *msa311, unsignedint mode)
{ struct device *dev = msa311->dev; unsignedint prev_mode; int err;
if (mode >= ARRAY_SIZE(msa311_pwr_modes)) return -EINVAL;
dev_dbg(dev, "transition to %s mode\n", msa311_pwr_modes[mode]);
err = regmap_field_read(msa311->fields[F_PWR_MODE], &prev_mode); if (err) return err;
err = regmap_field_write(msa311->fields[F_PWR_MODE], mode); if (err) return err;
/* Wait actual data if we wake up */ if (prev_mode == MSA311_PWR_MODE_SUSPEND &&
mode == MSA311_PWR_MODE_NORMAL) return msa311_wait_for_next_data(msa311);
return 0;
}
/** * msa311_get_axis() - Read MSA311 accel data for certain IIO channel axis spec * @msa311: MSA311 internal private state * @chan: IIO channel specification * @axis: Output accel axis data for requested IIO channel spec * * This function should be called under msa311->lock. * * Return: 0 on success, -EINVAL for unknown IIO channel specification, * -ERRNO in other failures
*/ staticint msa311_get_axis(struct msa311_priv *msa311, conststruct iio_chan_spec * const chan,
__le16 *axis)
{ struct device *dev = msa311->dev; unsignedint axis_reg;
if (chan->scan_index < MSA311_SI_X || chan->scan_index > MSA311_SI_Z) {
dev_err(dev, "invalid scan_index value [%d]\n",
chan->scan_index); return -EINVAL;
}
/* Axes data layout has 2 byte gap for each axis starting from X axis */
axis_reg = MSA311_ACC_X_REG + (chan->scan_index << 1);
staticint msa311_read_samp_freq(struct iio_dev *indio_dev, int *val, int *val2)
{ struct msa311_priv *msa311 = iio_priv(indio_dev); struct device *dev = msa311->dev; unsignedint odr; int err;
mutex_lock(&msa311->lock);
err = msa311_get_odr(msa311, &odr);
mutex_unlock(&msa311->lock); if (err) {
dev_err(dev, "can't get actual frequency (%pe)\n",
ERR_PTR(err)); return err;
}
if (err)
dev_err(dev, "can't update scale (%pe)\n", ERR_PTR(err));
return err;
}
staticint msa311_write_samp_freq(struct iio_dev *indio_dev, int val, int val2)
{ struct msa311_priv *msa311 = iio_priv(indio_dev); struct device *dev = msa311->dev; unsignedint odr; int err;
/* * Sampling frequency changing is prohibited when buffer mode is * enabled, because sometimes MSA311 chip returns outliers during * frequency values growing up in the read operation moment.
*/ if (!iio_device_claim_direct(indio_dev)) return -EBUSY;
err = pm_runtime_resume_and_get(dev); if (err) {
iio_device_release_direct(indio_dev); return err;
}
/* * We do not check NEW_DATA int status, because based on the * specification it's cleared automatically after a fixed time. * So just check that is enabled by driver logic.
*/
err = regmap_field_read(msa311->fields[F_NEW_DATA_INT_EN],
&new_data_int_enabled);
mutex_unlock(&msa311->lock); if (err) {
dev_err(dev, "can't read new_data interrupt state (%pe)\n",
ERR_PTR(err)); return IRQ_NONE;
}
if (new_data_int_enabled)
iio_trigger_poll_nested(msa311->new_data_trig);
err = regmap_field_write(msa311->fields[F_INT1_LVL],
MSA311_INT1_LVL_HIGH); if (err) return dev_err_probe(dev, err, "can't set active interrupt level\n");
err = msa311_regmap_init(msa311); if (err) return err;
mutex_init(&msa311->lock);
err = devm_regulator_get_enable(dev, "vdd"); if (err) return dev_err_probe(dev, err, "can't get vdd supply\n");
err = msa311_check_partid(msa311); if (err) return err;
err = msa311_soft_reset(msa311); if (err) return err;
err = msa311_set_pwr_mode(msa311, MSA311_PWR_MODE_NORMAL); if (err) return dev_err_probe(dev, err, "failed to power on device\n");
/* * Register powerdown deferred callback which suspends the chip * after module unloaded. * * MSA311 should be in SUSPEND mode in the two cases: * 1) When driver is loaded, but we do not have any data or * configuration requests to it (we are solving it using * autosuspend feature). * 2) When driver is unloaded and device is not used (devm action is * used in this case).
*/
err = devm_add_action_or_reset(dev, msa311_powerdown, msa311); if (err) return dev_err_probe(dev, err, "can't add powerdown action\n");
err = pm_runtime_set_active(dev); if (err) return err;
err = devm_pm_runtime_enable(dev); if (err) return err;
mutex_lock(&msa311->lock);
err = msa311_set_pwr_mode(msa311, MSA311_PWR_MODE_SUSPEND);
mutex_unlock(&msa311->lock); if (err)
dev_err(dev, "failed to power off device (%pe)\n",
ERR_PTR(err));
mutex_lock(&msa311->lock);
err = msa311_set_pwr_mode(msa311, MSA311_PWR_MODE_NORMAL);
mutex_unlock(&msa311->lock); if (err)
dev_err(dev, "failed to power on device (%pe)\n",
ERR_PTR(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.