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