static int 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] = 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]; 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_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); break; default: ret = cros_ec_sensors_core_write( &st->core, chan, val, val2, mask); break; } mutex_unlock(&st->core.cmd_lock); return ret; }
int cros_ec_sensors_core_init(struct platform_device *pdev, struct iio_dev *indio_dev, bool physical_device) { struct device *dev = &pdev->dev; struct cros_ec_sensors_core_state *state = iio_priv(indio_dev); struct cros_ec_dev *ec = dev_get_drvdata(pdev->dev.parent); struct cros_ec_sensor_platform *sensor_platform = dev_get_platdata(dev); platform_set_drvdata(pdev, indio_dev); state->ec = ec->ec_dev; state->msg = devm_kzalloc(&pdev->dev, max((u16)sizeof(struct ec_params_motion_sense), state->ec->max_response), GFP_KERNEL); if (!state->msg) return -ENOMEM; state->resp = (struct ec_response_motion_sense *)state->msg->data; mutex_init(&state->cmd_lock); /* Set up the host command structure. */ state->msg->version = 2; state->msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset; state->msg->outsize = sizeof(struct ec_params_motion_sense); indio_dev->dev.parent = &pdev->dev; indio_dev->name = pdev->name; if (physical_device) { indio_dev->modes = INDIO_DIRECT_MODE; state->param.cmd = MOTIONSENSE_CMD_INFO; state->param.info.sensor_num = sensor_platform->sensor_num; if (cros_ec_motion_send_host_cmd(state, 0)) { dev_warn(dev, "Can not access sensor info\n"); return -EIO; } state->type = state->resp->info.type; state->loc = state->resp->info.location; } return 0; }
static int 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] = st->core.resp->sensor_offset.offset[i]; ret = IIO_VAL_INT; *val = st->core.calib[idx]; break; case IIO_CHAN_INFO_SCALE: st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE; st->core.param.sensor_range.data = EC_MOTION_SENSE_NO_VALUE; 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 = div_s64(val64 * 314159 + 9000000ULL, 1000); *val2 = 18000 << (CROS_EC_SENSOR_BITS - 1); ret = IIO_VAL_FRACTIONAL; 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; }