linux/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * cros_ec_sensors - Driver for Chrome OS Embedded Controller sensors.
   4 *
   5 * Copyright (C) 2016 Google, Inc
   6 *
   7 * This driver uses the cros-ec interface to communicate with the Chrome OS
   8 * EC about sensors data. Data access is presented through iio sysfs.
   9 */
  10
  11#include <linux/device.h>
  12#include <linux/iio/buffer.h>
  13#include <linux/iio/common/cros_ec_sensors_core.h>
  14#include <linux/iio/iio.h>
  15#include <linux/iio/kfifo_buf.h>
  16#include <linux/iio/trigger_consumer.h>
  17#include <linux/iio/triggered_buffer.h>
  18#include <linux/kernel.h>
  19#include <linux/module.h>
  20#include <linux/platform_data/cros_ec_commands.h>
  21#include <linux/platform_data/cros_ec_proto.h>
  22#include <linux/platform_device.h>
  23#include <linux/slab.h>
  24
  25#define CROS_EC_SENSORS_MAX_CHANNELS 4
  26
  27/* State data for ec_sensors iio driver. */
  28struct cros_ec_sensors_state {
  29        /* Shared by all sensors */
  30        struct cros_ec_sensors_core_state core;
  31
  32        struct iio_chan_spec channels[CROS_EC_SENSORS_MAX_CHANNELS];
  33};
  34
  35static int cros_ec_sensors_read(struct iio_dev *indio_dev,
  36                          struct iio_chan_spec const *chan,
  37                          int *val, int *val2, long mask)
  38{
  39        struct cros_ec_sensors_state *st = iio_priv(indio_dev);
  40        s16 data = 0;
  41        s64 val64;
  42        int i;
  43        int ret;
  44        int idx = chan->scan_index;
  45
  46        mutex_lock(&st->core.cmd_lock);
  47
  48        switch (mask) {
  49        case IIO_CHAN_INFO_RAW:
  50                ret = st->core.read_ec_sensors_data(indio_dev, 1 << idx, &data);
  51                if (ret < 0)
  52                        break;
  53                ret = IIO_VAL_INT;
  54                *val = data;
  55                break;
  56        case IIO_CHAN_INFO_CALIBBIAS:
  57                st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_OFFSET;
  58                st->core.param.sensor_offset.flags = 0;
  59
  60                ret = cros_ec_motion_send_host_cmd(&st->core, 0);
  61                if (ret < 0)
  62                        break;
  63
  64                /* Save values */
  65                for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++)
  66                        st->core.calib[i].offset =
  67                                st->core.resp->sensor_offset.offset[i];
  68                ret = IIO_VAL_INT;
  69                *val = st->core.calib[idx].offset;
  70                break;
  71        case IIO_CHAN_INFO_CALIBSCALE:
  72                st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_SCALE;
  73                st->core.param.sensor_offset.flags = 0;
  74
  75                ret = cros_ec_motion_send_host_cmd(&st->core, 0);
  76                if (ret == -EPROTO || ret == -EOPNOTSUPP) {
  77                        /* Reading calibscale is not supported on older EC. */
  78                        *val = 1;
  79                        *val2 = 0;
  80                        ret = IIO_VAL_INT_PLUS_MICRO;
  81                        break;
  82                } else if (ret) {
  83                        break;
  84                }
  85
  86                /* Save values */
  87                for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++)
  88                        st->core.calib[i].scale =
  89                                st->core.resp->sensor_scale.scale[i];
  90
  91                *val = st->core.calib[idx].scale >> 15;
  92                *val2 = ((st->core.calib[idx].scale & 0x7FFF) * 1000000LL) /
  93                        MOTION_SENSE_DEFAULT_SCALE;
  94                ret = IIO_VAL_INT_PLUS_MICRO;
  95                break;
  96        case IIO_CHAN_INFO_SCALE:
  97                st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE;
  98                st->core.param.sensor_range.data = EC_MOTION_SENSE_NO_VALUE;
  99
 100                ret = cros_ec_motion_send_host_cmd(&st->core, 0);
 101                if (ret < 0)
 102                        break;
 103
 104                val64 = st->core.resp->sensor_range.ret;
 105                switch (st->core.type) {
 106                case MOTIONSENSE_TYPE_ACCEL:
 107                        /*
 108                         * EC returns data in g, iio exepects m/s^2.
 109                         * Do not use IIO_G_TO_M_S_2 to avoid precision loss.
 110                         */
 111                        *val = div_s64(val64 * 980665, 10);
 112                        *val2 = 10000 << (CROS_EC_SENSOR_BITS - 1);
 113                        ret = IIO_VAL_FRACTIONAL;
 114                        break;
 115                case MOTIONSENSE_TYPE_GYRO:
 116                        /*
 117                         * EC returns data in dps, iio expects rad/s.
 118                         * Do not use IIO_DEGREE_TO_RAD to avoid precision
 119                         * loss. Round to the nearest integer.
 120                         */
 121                        *val = 0;
 122                        *val2 = div_s64(val64 * 3141592653ULL,
 123                                        180 << (CROS_EC_SENSOR_BITS - 1));
 124                        ret = IIO_VAL_INT_PLUS_NANO;
 125                        break;
 126                case MOTIONSENSE_TYPE_MAG:
 127                        /*
 128                         * EC returns data in 16LSB / uT,
 129                         * iio expects Gauss
 130                         */
 131                        *val = val64;
 132                        *val2 = 100 << (CROS_EC_SENSOR_BITS - 1);
 133                        ret = IIO_VAL_FRACTIONAL;
 134                        break;
 135                default:
 136                        ret = -EINVAL;
 137                }
 138                break;
 139        default:
 140                ret = cros_ec_sensors_core_read(&st->core, chan, val, val2,
 141                                                mask);
 142                break;
 143        }
 144        mutex_unlock(&st->core.cmd_lock);
 145
 146        return ret;
 147}
 148
 149static int cros_ec_sensors_write(struct iio_dev *indio_dev,
 150                               struct iio_chan_spec const *chan,
 151                               int val, int val2, long mask)
 152{
 153        struct cros_ec_sensors_state *st = iio_priv(indio_dev);
 154        int i;
 155        int ret;
 156        int idx = chan->scan_index;
 157
 158        mutex_lock(&st->core.cmd_lock);
 159
 160        switch (mask) {
 161        case IIO_CHAN_INFO_CALIBBIAS:
 162                st->core.calib[idx].offset = val;
 163
 164                /* Send to EC for each axis, even if not complete */
 165                st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_OFFSET;
 166                st->core.param.sensor_offset.flags =
 167                        MOTION_SENSE_SET_OFFSET;
 168                for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++)
 169                        st->core.param.sensor_offset.offset[i] =
 170                                st->core.calib[i].offset;
 171                st->core.param.sensor_offset.temp =
 172                        EC_MOTION_SENSE_INVALID_CALIB_TEMP;
 173
 174                ret = cros_ec_motion_send_host_cmd(&st->core, 0);
 175                break;
 176        case IIO_CHAN_INFO_CALIBSCALE:
 177                st->core.calib[idx].scale = val;
 178                /* Send to EC for each axis, even if not complete */
 179
 180                st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_SCALE;
 181                st->core.param.sensor_offset.flags =
 182                        MOTION_SENSE_SET_OFFSET;
 183                for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++)
 184                        st->core.param.sensor_scale.scale[i] =
 185                                st->core.calib[i].scale;
 186                st->core.param.sensor_scale.temp =
 187                        EC_MOTION_SENSE_INVALID_CALIB_TEMP;
 188
 189                ret = cros_ec_motion_send_host_cmd(&st->core, 0);
 190                break;
 191        case IIO_CHAN_INFO_SCALE:
 192                if (st->core.type == MOTIONSENSE_TYPE_MAG) {
 193                        ret = -EINVAL;
 194                        break;
 195                }
 196                st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE;
 197                st->core.param.sensor_range.data = val;
 198
 199                /* Always roundup, so caller gets at least what it asks for. */
 200                st->core.param.sensor_range.roundup = 1;
 201
 202                ret = cros_ec_motion_send_host_cmd(&st->core, 0);
 203                if (ret == 0) {
 204                        st->core.range_updated = true;
 205                        st->core.curr_range = val;
 206                }
 207                break;
 208        default:
 209                ret = cros_ec_sensors_core_write(
 210                                &st->core, chan, val, val2, mask);
 211                break;
 212        }
 213
 214        mutex_unlock(&st->core.cmd_lock);
 215
 216        return ret;
 217}
 218
 219static const struct iio_info ec_sensors_info = {
 220        .read_raw = &cros_ec_sensors_read,
 221        .write_raw = &cros_ec_sensors_write,
 222        .read_avail = &cros_ec_sensors_core_read_avail,
 223};
 224
 225static int cros_ec_sensors_probe(struct platform_device *pdev)
 226{
 227        struct device *dev = &pdev->dev;
 228        struct iio_dev *indio_dev;
 229        struct cros_ec_sensors_state *state;
 230        struct iio_chan_spec *channel;
 231        int ret, i;
 232
 233        indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*state));
 234        if (!indio_dev)
 235                return -ENOMEM;
 236
 237        ret = cros_ec_sensors_core_init(pdev, indio_dev, true,
 238                                        cros_ec_sensors_capture,
 239                                        cros_ec_sensors_push_data);
 240        if (ret)
 241                return ret;
 242
 243        indio_dev->info = &ec_sensors_info;
 244        state = iio_priv(indio_dev);
 245        for (channel = state->channels, i = CROS_EC_SENSOR_X;
 246             i < CROS_EC_SENSOR_MAX_AXIS; i++, channel++) {
 247                /* Common part */
 248                channel->info_mask_separate =
 249                        BIT(IIO_CHAN_INFO_RAW) |
 250                        BIT(IIO_CHAN_INFO_CALIBBIAS) |
 251                        BIT(IIO_CHAN_INFO_CALIBSCALE);
 252                channel->info_mask_shared_by_all =
 253                        BIT(IIO_CHAN_INFO_SCALE) |
 254                        BIT(IIO_CHAN_INFO_SAMP_FREQ);
 255                channel->info_mask_shared_by_all_available =
 256                        BIT(IIO_CHAN_INFO_SAMP_FREQ);
 257                channel->scan_type.realbits = CROS_EC_SENSOR_BITS;
 258                channel->scan_type.storagebits = CROS_EC_SENSOR_BITS;
 259                channel->scan_index = i;
 260                channel->ext_info = cros_ec_sensors_ext_info;
 261                channel->modified = 1;
 262                channel->channel2 = IIO_MOD_X + i;
 263                channel->scan_type.sign = 's';
 264
 265                /* Sensor specific */
 266                switch (state->core.type) {
 267                case MOTIONSENSE_TYPE_ACCEL:
 268                        channel->type = IIO_ACCEL;
 269                        break;
 270                case MOTIONSENSE_TYPE_GYRO:
 271                        channel->type = IIO_ANGL_VEL;
 272                        break;
 273                case MOTIONSENSE_TYPE_MAG:
 274                        channel->type = IIO_MAGN;
 275                        break;
 276                default:
 277                        dev_err(&pdev->dev, "Unknown motion sensor\n");
 278                        return -EINVAL;
 279                }
 280        }
 281
 282        /* Timestamp */
 283        channel->type = IIO_TIMESTAMP;
 284        channel->channel = -1;
 285        channel->scan_index = CROS_EC_SENSOR_MAX_AXIS;
 286        channel->scan_type.sign = 's';
 287        channel->scan_type.realbits = 64;
 288        channel->scan_type.storagebits = 64;
 289
 290        indio_dev->channels = state->channels;
 291        indio_dev->num_channels = CROS_EC_SENSORS_MAX_CHANNELS;
 292
 293        /* There is only enough room for accel and gyro in the io space */
 294        if ((state->core.ec->cmd_readmem != NULL) &&
 295            (state->core.type != MOTIONSENSE_TYPE_MAG))
 296                state->core.read_ec_sensors_data = cros_ec_sensors_read_lpc;
 297        else
 298                state->core.read_ec_sensors_data = cros_ec_sensors_read_cmd;
 299
 300        return devm_iio_device_register(dev, indio_dev);
 301}
 302
 303static const struct platform_device_id cros_ec_sensors_ids[] = {
 304        {
 305                .name = "cros-ec-accel",
 306        },
 307        {
 308                .name = "cros-ec-gyro",
 309        },
 310        {
 311                .name = "cros-ec-mag",
 312        },
 313        { /* sentinel */ }
 314};
 315MODULE_DEVICE_TABLE(platform, cros_ec_sensors_ids);
 316
 317static struct platform_driver cros_ec_sensors_platform_driver = {
 318        .driver = {
 319                .name   = "cros-ec-sensors",
 320                .pm     = &cros_ec_sensors_pm_ops,
 321        },
 322        .probe          = cros_ec_sensors_probe,
 323        .id_table       = cros_ec_sensors_ids,
 324};
 325module_platform_driver(cros_ec_sensors_platform_driver);
 326
 327MODULE_DESCRIPTION("ChromeOS EC 3-axis sensors driver");
 328MODULE_LICENSE("GPL v2");
 329