// SPDX-License-Identifier: GPL-2.0 /* * cros_ec_sensors - Driver for Chrome OS Embedded Controller sensors. * * Copyright (C) 2016 Google, Inc * * This driver uses the cros-ec interface to communicate with the Chrome OS * EC about sensors data. Data access is presented through iio sysfs.
*/
staticint cros_ec_sensors_read(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{ struct cros_ec_sensors_state *st = iio_priv(indio_dev);
s16 data = 0;
s64 val64; int i; int ret; int idx = chan->scan_index;
mutex_lock(&st->core.cmd_lock);
switch (mask) { case IIO_CHAN_INFO_RAW:
ret = st->core.read_ec_sensors_data(indio_dev, 1 << idx, &data); if (ret < 0) break;
ret = IIO_VAL_INT;
*val = data; break; case IIO_CHAN_INFO_CALIBBIAS:
st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_OFFSET;
st->core.param.sensor_offset.flags = 0;
ret = cros_ec_motion_send_host_cmd(&st->core, 0); if (ret < 0) break;
/* Save values */ for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++)
st->core.calib[i].offset =
st->core.resp->sensor_offset.offset[i];
ret = IIO_VAL_INT;
*val = st->core.calib[idx].offset; break; case IIO_CHAN_INFO_CALIBSCALE:
st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_SCALE;
st->core.param.sensor_offset.flags = 0;
ret = cros_ec_motion_send_host_cmd(&st->core, 0); if (ret == -EPROTO || ret == -EOPNOTSUPP) { /* Reading calibscale is not supported on older EC. */
*val = 1;
*val2 = 0;
ret = IIO_VAL_INT_PLUS_MICRO; break;
} elseif (ret) { break;
}
/* Save values */ for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++)
st->core.calib[i].scale =
st->core.resp->sensor_scale.scale[i];
ret = cros_ec_motion_send_host_cmd(&st->core, 0); if (ret < 0) break;
val64 = st->core.resp->sensor_range.ret; switch (st->core.type) { case MOTIONSENSE_TYPE_ACCEL: /* * EC returns data in g, iio exepects m/s^2. * Do not use IIO_G_TO_M_S_2 to avoid precision loss.
*/
*val = div_s64(val64 * 980665, 10);
*val2 = 10000 << (CROS_EC_SENSOR_BITS - 1);
ret = IIO_VAL_FRACTIONAL; break; case MOTIONSENSE_TYPE_GYRO: /* * EC returns data in dps, iio expects rad/s. * Do not use IIO_DEGREE_TO_RAD to avoid precision * loss. Round to the nearest integer.
*/
*val = 0;
*val2 = div_s64(val64 * 3141592653ULL,
180 << (CROS_EC_SENSOR_BITS - 1));
ret = IIO_VAL_INT_PLUS_NANO; break; case MOTIONSENSE_TYPE_MAG: /* * EC returns data in 16LSB / uT, * iio expects Gauss
*/
*val = val64;
*val2 = 100 << (CROS_EC_SENSOR_BITS - 1);
ret = IIO_VAL_FRACTIONAL; break; default:
ret = -EINVAL;
} break; default:
ret = cros_ec_sensors_core_read(&st->core, chan, val, val2,
mask); break;
}
mutex_unlock(&st->core.cmd_lock);
return ret;
}
staticint cros_ec_sensors_write(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask)
{ struct cros_ec_sensors_state *st = iio_priv(indio_dev); int i; int ret; int idx = chan->scan_index;
mutex_lock(&st->core.cmd_lock);
switch (mask) { case IIO_CHAN_INFO_CALIBBIAS:
st->core.calib[idx].offset = val;
/* Send to EC for each axis, even if not complete */
st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_OFFSET;
st->core.param.sensor_offset.flags =
MOTION_SENSE_SET_OFFSET; for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++)
st->core.param.sensor_offset.offset[i] =
st->core.calib[i].offset;
st->core.param.sensor_offset.temp =
EC_MOTION_SENSE_INVALID_CALIB_TEMP;
ret = cros_ec_motion_send_host_cmd(&st->core, 0); break; case IIO_CHAN_INFO_CALIBSCALE:
st->core.calib[idx].scale = val; /* Send to EC for each axis, even if not complete */
st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_SCALE;
st->core.param.sensor_offset.flags =
MOTION_SENSE_SET_OFFSET; for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++)
st->core.param.sensor_scale.scale[i] =
st->core.calib[i].scale;
st->core.param.sensor_scale.temp =
EC_MOTION_SENSE_INVALID_CALIB_TEMP;
ret = cros_ec_motion_send_host_cmd(&st->core, 0); break; case IIO_CHAN_INFO_SCALE: if (st->core.type == MOTIONSENSE_TYPE_MAG) {
ret = -EINVAL; break;
}
st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE;
st->core.param.sensor_range.data = val;
/* Always roundup, so caller gets at least what it asks for. */
st->core.param.sensor_range.roundup = 1;
ret = cros_ec_motion_send_host_cmd(&st->core, 0); if (ret == 0) {
st->core.range_updated = true;
st->core.curr_range = val;
} break; default:
ret = cros_ec_sensors_core_write(
&st->core, chan, val, val2, mask); break;
}
/* There is only enough room for accel and gyro in the io space */ if ((state->core.ec->cmd_readmem != NULL) &&
(state->core.type != MOTIONSENSE_TYPE_MAG))
state->core.read_ec_sensors_data = cros_ec_sensors_read_lpc; else
state->core.read_ec_sensors_data = cros_ec_sensors_read_cmd;
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.