root/drivers/iio/light/cros_ec_light_prox.c

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

DEFINITIONS

This source file includes following definitions.
  1. cros_ec_light_prox_read
  2. cros_ec_light_prox_write
  3. cros_ec_light_prox_probe

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * cros_ec_light_prox - Driver for light and prox sensors behing CrosEC.
   4  *
   5  * Copyright (C) 2017 Google, Inc
   6  */
   7 
   8 #include <linux/device.h>
   9 #include <linux/iio/buffer.h>
  10 #include <linux/iio/common/cros_ec_sensors_core.h>
  11 #include <linux/iio/iio.h>
  12 #include <linux/iio/kfifo_buf.h>
  13 #include <linux/iio/trigger.h>
  14 #include <linux/iio/triggered_buffer.h>
  15 #include <linux/iio/trigger_consumer.h>
  16 #include <linux/kernel.h>
  17 #include <linux/mfd/cros_ec.h>
  18 #include <linux/module.h>
  19 #include <linux/platform_data/cros_ec_commands.h>
  20 #include <linux/platform_data/cros_ec_proto.h>
  21 #include <linux/platform_device.h>
  22 #include <linux/slab.h>
  23 
  24 /*
  25  * We only represent one entry for light or proximity. EC is merging different
  26  * light sensors to return the what the eye would see. For proximity, we
  27  * currently support only one light source.
  28  */
  29 #define CROS_EC_LIGHT_PROX_MAX_CHANNELS (1 + 1)
  30 
  31 /* State data for ec_sensors iio driver. */
  32 struct cros_ec_light_prox_state {
  33         /* Shared by all sensors */
  34         struct cros_ec_sensors_core_state core;
  35 
  36         struct iio_chan_spec channels[CROS_EC_LIGHT_PROX_MAX_CHANNELS];
  37 };
  38 
  39 static int cros_ec_light_prox_read(struct iio_dev *indio_dev,
  40                                    struct iio_chan_spec const *chan,
  41                                    int *val, int *val2, long mask)
  42 {
  43         struct cros_ec_light_prox_state *st = iio_priv(indio_dev);
  44         u16 data = 0;
  45         s64 val64;
  46         int ret;
  47         int idx = chan->scan_index;
  48 
  49         mutex_lock(&st->core.cmd_lock);
  50 
  51         switch (mask) {
  52         case IIO_CHAN_INFO_RAW:
  53                 if (chan->type == IIO_PROXIMITY) {
  54                         ret = cros_ec_sensors_read_cmd(indio_dev, 1 << idx,
  55                                                      (s16 *)&data);
  56                         if (ret)
  57                                 break;
  58                         *val = data;
  59                         ret = IIO_VAL_INT;
  60                 } else {
  61                         ret = -EINVAL;
  62                 }
  63                 break;
  64         case IIO_CHAN_INFO_PROCESSED:
  65                 if (chan->type == IIO_LIGHT) {
  66                         ret = cros_ec_sensors_read_cmd(indio_dev, 1 << idx,
  67                                                      (s16 *)&data);
  68                         if (ret)
  69                                 break;
  70                         /*
  71                          * The data coming from the light sensor is
  72                          * pre-processed and represents the ambient light
  73                          * illuminance reading expressed in lux.
  74                          */
  75                         *val = data;
  76                         ret = IIO_VAL_INT;
  77                 } else {
  78                         ret = -EINVAL;
  79                 }
  80                 break;
  81         case IIO_CHAN_INFO_CALIBBIAS:
  82                 st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_OFFSET;
  83                 st->core.param.sensor_offset.flags = 0;
  84 
  85                 ret = cros_ec_motion_send_host_cmd(&st->core, 0);
  86                 if (ret)
  87                         break;
  88 
  89                 /* Save values */
  90                 st->core.calib[0].offset =
  91                         st->core.resp->sensor_offset.offset[0];
  92 
  93                 *val = st->core.calib[idx].offset;
  94                 ret = IIO_VAL_INT;
  95                 break;
  96         case IIO_CHAN_INFO_CALIBSCALE:
  97                 /*
  98                  * RANGE is used for calibration
  99                  * scale is a number x.y, where x is coded on 16 bits,
 100                  * y coded on 16 bits, between 0 and 9999.
 101                  */
 102                 st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE;
 103                 st->core.param.sensor_range.data = EC_MOTION_SENSE_NO_VALUE;
 104 
 105                 ret = cros_ec_motion_send_host_cmd(&st->core, 0);
 106                 if (ret)
 107                         break;
 108 
 109                 val64 = st->core.resp->sensor_range.ret;
 110                 *val = val64 >> 16;
 111                 *val2 = (val64 & 0xffff) * 100;
 112                 ret = IIO_VAL_INT_PLUS_MICRO;
 113                 break;
 114         default:
 115                 ret = cros_ec_sensors_core_read(&st->core, chan, val, val2,
 116                                                 mask);
 117                 break;
 118         }
 119 
 120         mutex_unlock(&st->core.cmd_lock);
 121 
 122         return ret;
 123 }
 124 
 125 static int cros_ec_light_prox_write(struct iio_dev *indio_dev,
 126                                struct iio_chan_spec const *chan,
 127                                int val, int val2, long mask)
 128 {
 129         struct cros_ec_light_prox_state *st = iio_priv(indio_dev);
 130         int ret;
 131         int idx = chan->scan_index;
 132 
 133         mutex_lock(&st->core.cmd_lock);
 134 
 135         switch (mask) {
 136         case IIO_CHAN_INFO_CALIBBIAS:
 137                 st->core.calib[idx].offset = val;
 138                 /* Send to EC for each axis, even if not complete */
 139                 st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_OFFSET;
 140                 st->core.param.sensor_offset.flags = MOTION_SENSE_SET_OFFSET;
 141                 st->core.param.sensor_offset.offset[0] =
 142                         st->core.calib[0].offset;
 143                 st->core.param.sensor_offset.temp =
 144                                         EC_MOTION_SENSE_INVALID_CALIB_TEMP;
 145                 ret = cros_ec_motion_send_host_cmd(&st->core, 0);
 146                 break;
 147         case IIO_CHAN_INFO_CALIBSCALE:
 148                 st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE;
 149                 st->core.param.sensor_range.data = (val << 16) | (val2 / 100);
 150                 ret = cros_ec_motion_send_host_cmd(&st->core, 0);
 151                 break;
 152         default:
 153                 ret = cros_ec_sensors_core_write(&st->core, chan, val, val2,
 154                                                  mask);
 155                 break;
 156         }
 157 
 158         mutex_unlock(&st->core.cmd_lock);
 159 
 160         return ret;
 161 }
 162 
 163 static const struct iio_info cros_ec_light_prox_info = {
 164         .read_raw = &cros_ec_light_prox_read,
 165         .write_raw = &cros_ec_light_prox_write,
 166         .read_avail = &cros_ec_sensors_core_read_avail,
 167 };
 168 
 169 static int cros_ec_light_prox_probe(struct platform_device *pdev)
 170 {
 171         struct device *dev = &pdev->dev;
 172         struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent);
 173         struct iio_dev *indio_dev;
 174         struct cros_ec_light_prox_state *state;
 175         struct iio_chan_spec *channel;
 176         int ret;
 177 
 178         if (!ec_dev || !ec_dev->ec_dev) {
 179                 dev_warn(dev, "No CROS EC device found.\n");
 180                 return -EINVAL;
 181         }
 182 
 183         indio_dev = devm_iio_device_alloc(dev, sizeof(*state));
 184         if (!indio_dev)
 185                 return -ENOMEM;
 186 
 187         ret = cros_ec_sensors_core_init(pdev, indio_dev, true);
 188         if (ret)
 189                 return ret;
 190 
 191         indio_dev->info = &cros_ec_light_prox_info;
 192         state = iio_priv(indio_dev);
 193         state->core.type = state->core.resp->info.type;
 194         state->core.loc = state->core.resp->info.location;
 195         channel = state->channels;
 196 
 197         /* Common part */
 198         channel->info_mask_shared_by_all =
 199                 BIT(IIO_CHAN_INFO_SAMP_FREQ) |
 200                 BIT(IIO_CHAN_INFO_FREQUENCY);
 201         channel->info_mask_shared_by_all_available =
 202                 BIT(IIO_CHAN_INFO_SAMP_FREQ);
 203         channel->scan_type.realbits = CROS_EC_SENSOR_BITS;
 204         channel->scan_type.storagebits = CROS_EC_SENSOR_BITS;
 205         channel->scan_type.shift = 0;
 206         channel->scan_index = 0;
 207         channel->ext_info = cros_ec_sensors_ext_info;
 208         channel->scan_type.sign = 'u';
 209 
 210         /* Sensor specific */
 211         switch (state->core.type) {
 212         case MOTIONSENSE_TYPE_LIGHT:
 213                 channel->type = IIO_LIGHT;
 214                 channel->info_mask_separate =
 215                         BIT(IIO_CHAN_INFO_PROCESSED) |
 216                         BIT(IIO_CHAN_INFO_CALIBBIAS) |
 217                         BIT(IIO_CHAN_INFO_CALIBSCALE);
 218                 break;
 219         case MOTIONSENSE_TYPE_PROX:
 220                 channel->type = IIO_PROXIMITY;
 221                 channel->info_mask_separate =
 222                         BIT(IIO_CHAN_INFO_RAW) |
 223                         BIT(IIO_CHAN_INFO_CALIBBIAS) |
 224                         BIT(IIO_CHAN_INFO_CALIBSCALE);
 225                 break;
 226         default:
 227                 dev_warn(dev, "Unknown motion sensor\n");
 228                 return -EINVAL;
 229         }
 230 
 231         /* Timestamp */
 232         channel++;
 233         channel->type = IIO_TIMESTAMP;
 234         channel->channel = -1;
 235         channel->scan_index = 1;
 236         channel->scan_type.sign = 's';
 237         channel->scan_type.realbits = 64;
 238         channel->scan_type.storagebits = 64;
 239 
 240         indio_dev->channels = state->channels;
 241 
 242         indio_dev->num_channels = CROS_EC_LIGHT_PROX_MAX_CHANNELS;
 243 
 244         state->core.read_ec_sensors_data = cros_ec_sensors_read_cmd;
 245 
 246         ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
 247                                               cros_ec_sensors_capture, NULL);
 248         if (ret)
 249                 return ret;
 250 
 251         return devm_iio_device_register(dev, indio_dev);
 252 }
 253 
 254 static const struct platform_device_id cros_ec_light_prox_ids[] = {
 255         {
 256                 .name = "cros-ec-prox",
 257         },
 258         {
 259                 .name = "cros-ec-light",
 260         },
 261         { /* sentinel */ }
 262 };
 263 MODULE_DEVICE_TABLE(platform, cros_ec_light_prox_ids);
 264 
 265 static struct platform_driver cros_ec_light_prox_platform_driver = {
 266         .driver = {
 267                 .name   = "cros-ec-light-prox",
 268                 .pm     = &cros_ec_sensors_pm_ops,
 269         },
 270         .probe          = cros_ec_light_prox_probe,
 271         .id_table       = cros_ec_light_prox_ids,
 272 };
 273 module_platform_driver(cros_ec_light_prox_platform_driver);
 274 
 275 MODULE_DESCRIPTION("ChromeOS EC light/proximity sensors driver");
 276 MODULE_LICENSE("GPL v2");

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