Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * cros_ec_sensors - Driver for Chrome OS Embedded Controller sensors.
0004  *
0005  * Copyright (C) 2016 Google, Inc
0006  *
0007  * This driver uses the cros-ec interface to communicate with the Chrome OS
0008  * EC about sensors data. Data access is presented through iio sysfs.
0009  */
0010 
0011 #include <linux/device.h>
0012 #include <linux/iio/buffer.h>
0013 #include <linux/iio/common/cros_ec_sensors_core.h>
0014 #include <linux/iio/iio.h>
0015 #include <linux/iio/kfifo_buf.h>
0016 #include <linux/iio/trigger_consumer.h>
0017 #include <linux/iio/triggered_buffer.h>
0018 #include <linux/kernel.h>
0019 #include <linux/mod_devicetable.h>
0020 #include <linux/module.h>
0021 #include <linux/platform_data/cros_ec_commands.h>
0022 #include <linux/platform_data/cros_ec_proto.h>
0023 #include <linux/platform_device.h>
0024 #include <linux/slab.h>
0025 
0026 #define CROS_EC_SENSORS_MAX_CHANNELS 4
0027 
0028 /* State data for ec_sensors iio driver. */
0029 struct cros_ec_sensors_state {
0030     /* Shared by all sensors */
0031     struct cros_ec_sensors_core_state core;
0032 
0033     struct iio_chan_spec channels[CROS_EC_SENSORS_MAX_CHANNELS];
0034 };
0035 
0036 static int cros_ec_sensors_read(struct iio_dev *indio_dev,
0037               struct iio_chan_spec const *chan,
0038               int *val, int *val2, long mask)
0039 {
0040     struct cros_ec_sensors_state *st = iio_priv(indio_dev);
0041     s16 data = 0;
0042     s64 val64;
0043     int i;
0044     int ret;
0045     int idx = chan->scan_index;
0046 
0047     mutex_lock(&st->core.cmd_lock);
0048 
0049     switch (mask) {
0050     case IIO_CHAN_INFO_RAW:
0051         ret = st->core.read_ec_sensors_data(indio_dev, 1 << idx, &data);
0052         if (ret < 0)
0053             break;
0054         ret = IIO_VAL_INT;
0055         *val = data;
0056         break;
0057     case IIO_CHAN_INFO_CALIBBIAS:
0058         st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_OFFSET;
0059         st->core.param.sensor_offset.flags = 0;
0060 
0061         ret = cros_ec_motion_send_host_cmd(&st->core, 0);
0062         if (ret < 0)
0063             break;
0064 
0065         /* Save values */
0066         for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++)
0067             st->core.calib[i].offset =
0068                 st->core.resp->sensor_offset.offset[i];
0069         ret = IIO_VAL_INT;
0070         *val = st->core.calib[idx].offset;
0071         break;
0072     case IIO_CHAN_INFO_CALIBSCALE:
0073         st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_SCALE;
0074         st->core.param.sensor_offset.flags = 0;
0075 
0076         ret = cros_ec_motion_send_host_cmd(&st->core, 0);
0077         if (ret == -EPROTO || ret == -EOPNOTSUPP) {
0078             /* Reading calibscale is not supported on older EC. */
0079             *val = 1;
0080             *val2 = 0;
0081             ret = IIO_VAL_INT_PLUS_MICRO;
0082             break;
0083         } else if (ret) {
0084             break;
0085         }
0086 
0087         /* Save values */
0088         for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++)
0089             st->core.calib[i].scale =
0090                 st->core.resp->sensor_scale.scale[i];
0091 
0092         *val = st->core.calib[idx].scale >> 15;
0093         *val2 = ((st->core.calib[idx].scale & 0x7FFF) * 1000000LL) /
0094             MOTION_SENSE_DEFAULT_SCALE;
0095         ret = IIO_VAL_INT_PLUS_MICRO;
0096         break;
0097     case IIO_CHAN_INFO_SCALE:
0098         st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE;
0099         st->core.param.sensor_range.data = EC_MOTION_SENSE_NO_VALUE;
0100 
0101         ret = cros_ec_motion_send_host_cmd(&st->core, 0);
0102         if (ret < 0)
0103             break;
0104 
0105         val64 = st->core.resp->sensor_range.ret;
0106         switch (st->core.type) {
0107         case MOTIONSENSE_TYPE_ACCEL:
0108             /*
0109              * EC returns data in g, iio exepects m/s^2.
0110              * Do not use IIO_G_TO_M_S_2 to avoid precision loss.
0111              */
0112             *val = div_s64(val64 * 980665, 10);
0113             *val2 = 10000 << (CROS_EC_SENSOR_BITS - 1);
0114             ret = IIO_VAL_FRACTIONAL;
0115             break;
0116         case MOTIONSENSE_TYPE_GYRO:
0117             /*
0118              * EC returns data in dps, iio expects rad/s.
0119              * Do not use IIO_DEGREE_TO_RAD to avoid precision
0120              * loss. Round to the nearest integer.
0121              */
0122             *val = 0;
0123             *val2 = div_s64(val64 * 3141592653ULL,
0124                     180 << (CROS_EC_SENSOR_BITS - 1));
0125             ret = IIO_VAL_INT_PLUS_NANO;
0126             break;
0127         case MOTIONSENSE_TYPE_MAG:
0128             /*
0129              * EC returns data in 16LSB / uT,
0130              * iio expects Gauss
0131              */
0132             *val = val64;
0133             *val2 = 100 << (CROS_EC_SENSOR_BITS - 1);
0134             ret = IIO_VAL_FRACTIONAL;
0135             break;
0136         default:
0137             ret = -EINVAL;
0138         }
0139         break;
0140     default:
0141         ret = cros_ec_sensors_core_read(&st->core, chan, val, val2,
0142                         mask);
0143         break;
0144     }
0145     mutex_unlock(&st->core.cmd_lock);
0146 
0147     return ret;
0148 }
0149 
0150 static int cros_ec_sensors_write(struct iio_dev *indio_dev,
0151                    struct iio_chan_spec const *chan,
0152                    int val, int val2, long mask)
0153 {
0154     struct cros_ec_sensors_state *st = iio_priv(indio_dev);
0155     int i;
0156     int ret;
0157     int idx = chan->scan_index;
0158 
0159     mutex_lock(&st->core.cmd_lock);
0160 
0161     switch (mask) {
0162     case IIO_CHAN_INFO_CALIBBIAS:
0163         st->core.calib[idx].offset = val;
0164 
0165         /* Send to EC for each axis, even if not complete */
0166         st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_OFFSET;
0167         st->core.param.sensor_offset.flags =
0168             MOTION_SENSE_SET_OFFSET;
0169         for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++)
0170             st->core.param.sensor_offset.offset[i] =
0171                 st->core.calib[i].offset;
0172         st->core.param.sensor_offset.temp =
0173             EC_MOTION_SENSE_INVALID_CALIB_TEMP;
0174 
0175         ret = cros_ec_motion_send_host_cmd(&st->core, 0);
0176         break;
0177     case IIO_CHAN_INFO_CALIBSCALE:
0178         st->core.calib[idx].scale = val;
0179         /* Send to EC for each axis, even if not complete */
0180 
0181         st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_SCALE;
0182         st->core.param.sensor_offset.flags =
0183             MOTION_SENSE_SET_OFFSET;
0184         for (i = CROS_EC_SENSOR_X; i < CROS_EC_SENSOR_MAX_AXIS; i++)
0185             st->core.param.sensor_scale.scale[i] =
0186                 st->core.calib[i].scale;
0187         st->core.param.sensor_scale.temp =
0188             EC_MOTION_SENSE_INVALID_CALIB_TEMP;
0189 
0190         ret = cros_ec_motion_send_host_cmd(&st->core, 0);
0191         break;
0192     case IIO_CHAN_INFO_SCALE:
0193         if (st->core.type == MOTIONSENSE_TYPE_MAG) {
0194             ret = -EINVAL;
0195             break;
0196         }
0197         st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE;
0198         st->core.param.sensor_range.data = val;
0199 
0200         /* Always roundup, so caller gets at least what it asks for. */
0201         st->core.param.sensor_range.roundup = 1;
0202 
0203         ret = cros_ec_motion_send_host_cmd(&st->core, 0);
0204         if (ret == 0) {
0205             st->core.range_updated = true;
0206             st->core.curr_range = val;
0207         }
0208         break;
0209     default:
0210         ret = cros_ec_sensors_core_write(
0211                 &st->core, chan, val, val2, mask);
0212         break;
0213     }
0214 
0215     mutex_unlock(&st->core.cmd_lock);
0216 
0217     return ret;
0218 }
0219 
0220 static const struct iio_info ec_sensors_info = {
0221     .read_raw = &cros_ec_sensors_read,
0222     .write_raw = &cros_ec_sensors_write,
0223     .read_avail = &cros_ec_sensors_core_read_avail,
0224 };
0225 
0226 static int cros_ec_sensors_probe(struct platform_device *pdev)
0227 {
0228     struct device *dev = &pdev->dev;
0229     struct iio_dev *indio_dev;
0230     struct cros_ec_sensors_state *state;
0231     struct iio_chan_spec *channel;
0232     int ret, i;
0233 
0234     indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*state));
0235     if (!indio_dev)
0236         return -ENOMEM;
0237 
0238     ret = cros_ec_sensors_core_init(pdev, indio_dev, true,
0239                     cros_ec_sensors_capture);
0240     if (ret)
0241         return ret;
0242 
0243     indio_dev->info = &ec_sensors_info;
0244     state = iio_priv(indio_dev);
0245     for (channel = state->channels, i = CROS_EC_SENSOR_X;
0246          i < CROS_EC_SENSOR_MAX_AXIS; i++, channel++) {
0247         /* Common part */
0248         channel->info_mask_separate =
0249             BIT(IIO_CHAN_INFO_RAW) |
0250             BIT(IIO_CHAN_INFO_CALIBBIAS) |
0251             BIT(IIO_CHAN_INFO_CALIBSCALE);
0252         channel->info_mask_shared_by_all =
0253             BIT(IIO_CHAN_INFO_SCALE) |
0254             BIT(IIO_CHAN_INFO_SAMP_FREQ);
0255         channel->info_mask_shared_by_all_available =
0256             BIT(IIO_CHAN_INFO_SAMP_FREQ);
0257         channel->scan_type.realbits = CROS_EC_SENSOR_BITS;
0258         channel->scan_type.storagebits = CROS_EC_SENSOR_BITS;
0259         channel->scan_index = i;
0260         channel->ext_info = cros_ec_sensors_ext_info;
0261         channel->modified = 1;
0262         channel->channel2 = IIO_MOD_X + i;
0263         channel->scan_type.sign = 's';
0264 
0265         /* Sensor specific */
0266         switch (state->core.type) {
0267         case MOTIONSENSE_TYPE_ACCEL:
0268             channel->type = IIO_ACCEL;
0269             break;
0270         case MOTIONSENSE_TYPE_GYRO:
0271             channel->type = IIO_ANGL_VEL;
0272             break;
0273         case MOTIONSENSE_TYPE_MAG:
0274             channel->type = IIO_MAGN;
0275             break;
0276         default:
0277             dev_err(&pdev->dev, "Unknown motion sensor\n");
0278             return -EINVAL;
0279         }
0280     }
0281 
0282     /* Timestamp */
0283     channel->type = IIO_TIMESTAMP;
0284     channel->channel = -1;
0285     channel->scan_index = CROS_EC_SENSOR_MAX_AXIS;
0286     channel->scan_type.sign = 's';
0287     channel->scan_type.realbits = 64;
0288     channel->scan_type.storagebits = 64;
0289 
0290     indio_dev->channels = state->channels;
0291     indio_dev->num_channels = CROS_EC_SENSORS_MAX_CHANNELS;
0292 
0293     /* There is only enough room for accel and gyro in the io space */
0294     if ((state->core.ec->cmd_readmem != NULL) &&
0295         (state->core.type != MOTIONSENSE_TYPE_MAG))
0296         state->core.read_ec_sensors_data = cros_ec_sensors_read_lpc;
0297     else
0298         state->core.read_ec_sensors_data = cros_ec_sensors_read_cmd;
0299 
0300     return cros_ec_sensors_core_register(dev, indio_dev,
0301             cros_ec_sensors_push_data);
0302 }
0303 
0304 static const struct platform_device_id cros_ec_sensors_ids[] = {
0305     {
0306         .name = "cros-ec-accel",
0307     },
0308     {
0309         .name = "cros-ec-gyro",
0310     },
0311     {
0312         .name = "cros-ec-mag",
0313     },
0314     { /* sentinel */ }
0315 };
0316 MODULE_DEVICE_TABLE(platform, cros_ec_sensors_ids);
0317 
0318 static struct platform_driver cros_ec_sensors_platform_driver = {
0319     .driver = {
0320         .name   = "cros-ec-sensors",
0321         .pm = &cros_ec_sensors_pm_ops,
0322     },
0323     .probe      = cros_ec_sensors_probe,
0324     .id_table   = cros_ec_sensors_ids,
0325 };
0326 module_platform_driver(cros_ec_sensors_platform_driver);
0327 
0328 MODULE_DESCRIPTION("ChromeOS EC 3-axis sensors driver");
0329 MODULE_LICENSE("GPL v2");