root/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cros_ec_sensors_read
  2. cros_ec_sensors_write
  3. cros_ec_sensors_probe

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

/* [<][>][^][v][top][bottom][index][help] */