root/drivers/iio/light/hid-sensor-prox.c

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

DEFINITIONS

This source file includes following definitions.
  1. prox_adjust_channel_bit_mask
  2. prox_read_raw
  3. prox_write_raw
  4. hid_sensor_push_data
  5. prox_proc_event
  6. prox_capture_sample
  7. prox_parse_report
  8. hid_prox_probe
  9. hid_prox_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * HID Sensors Driver
   4  * Copyright (c) 2014, Intel Corporation.
   5  */
   6 #include <linux/device.h>
   7 #include <linux/platform_device.h>
   8 #include <linux/module.h>
   9 #include <linux/interrupt.h>
  10 #include <linux/irq.h>
  11 #include <linux/slab.h>
  12 #include <linux/delay.h>
  13 #include <linux/hid-sensor-hub.h>
  14 #include <linux/iio/iio.h>
  15 #include <linux/iio/sysfs.h>
  16 #include <linux/iio/buffer.h>
  17 #include <linux/iio/trigger_consumer.h>
  18 #include <linux/iio/triggered_buffer.h>
  19 #include "../common/hid-sensors/hid-sensor-trigger.h"
  20 
  21 #define CHANNEL_SCAN_INDEX_PRESENCE 0
  22 
  23 struct prox_state {
  24         struct hid_sensor_hub_callbacks callbacks;
  25         struct hid_sensor_common common_attributes;
  26         struct hid_sensor_hub_attribute_info prox_attr;
  27         u32 human_presence;
  28 };
  29 
  30 /* Channel definitions */
  31 static const struct iio_chan_spec prox_channels[] = {
  32         {
  33                 .type = IIO_PROXIMITY,
  34                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
  35                 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
  36                 BIT(IIO_CHAN_INFO_SCALE) |
  37                 BIT(IIO_CHAN_INFO_SAMP_FREQ) |
  38                 BIT(IIO_CHAN_INFO_HYSTERESIS),
  39                 .scan_index = CHANNEL_SCAN_INDEX_PRESENCE,
  40         }
  41 };
  42 
  43 /* Adjust channel real bits based on report descriptor */
  44 static void prox_adjust_channel_bit_mask(struct iio_chan_spec *channels,
  45                                         int channel, int size)
  46 {
  47         channels[channel].scan_type.sign = 's';
  48         /* Real storage bits will change based on the report desc. */
  49         channels[channel].scan_type.realbits = size * 8;
  50         /* Maximum size of a sample to capture is u32 */
  51         channels[channel].scan_type.storagebits = sizeof(u32) * 8;
  52 }
  53 
  54 /* Channel read_raw handler */
  55 static int prox_read_raw(struct iio_dev *indio_dev,
  56                               struct iio_chan_spec const *chan,
  57                               int *val, int *val2,
  58                               long mask)
  59 {
  60         struct prox_state *prox_state = iio_priv(indio_dev);
  61         int report_id = -1;
  62         u32 address;
  63         int ret_type;
  64         s32 min;
  65 
  66         *val = 0;
  67         *val2 = 0;
  68         switch (mask) {
  69         case IIO_CHAN_INFO_RAW:
  70                 switch (chan->scan_index) {
  71                 case  CHANNEL_SCAN_INDEX_PRESENCE:
  72                         report_id = prox_state->prox_attr.report_id;
  73                         min = prox_state->prox_attr.logical_minimum;
  74                         address = HID_USAGE_SENSOR_HUMAN_PRESENCE;
  75                         break;
  76                 default:
  77                         report_id = -1;
  78                         break;
  79                 }
  80                 if (report_id >= 0) {
  81                         hid_sensor_power_state(&prox_state->common_attributes,
  82                                                 true);
  83                         *val = sensor_hub_input_attr_get_raw_value(
  84                                 prox_state->common_attributes.hsdev,
  85                                 HID_USAGE_SENSOR_PROX, address,
  86                                 report_id,
  87                                 SENSOR_HUB_SYNC,
  88                                 min < 0);
  89                         hid_sensor_power_state(&prox_state->common_attributes,
  90                                                 false);
  91                 } else {
  92                         *val = 0;
  93                         return -EINVAL;
  94                 }
  95                 ret_type = IIO_VAL_INT;
  96                 break;
  97         case IIO_CHAN_INFO_SCALE:
  98                 *val = prox_state->prox_attr.units;
  99                 ret_type = IIO_VAL_INT;
 100                 break;
 101         case IIO_CHAN_INFO_OFFSET:
 102                 *val = hid_sensor_convert_exponent(
 103                                 prox_state->prox_attr.unit_expo);
 104                 ret_type = IIO_VAL_INT;
 105                 break;
 106         case IIO_CHAN_INFO_SAMP_FREQ:
 107                 ret_type = hid_sensor_read_samp_freq_value(
 108                                 &prox_state->common_attributes, val, val2);
 109                 break;
 110         case IIO_CHAN_INFO_HYSTERESIS:
 111                 ret_type = hid_sensor_read_raw_hyst_value(
 112                                 &prox_state->common_attributes, val, val2);
 113                 break;
 114         default:
 115                 ret_type = -EINVAL;
 116                 break;
 117         }
 118 
 119         return ret_type;
 120 }
 121 
 122 /* Channel write_raw handler */
 123 static int prox_write_raw(struct iio_dev *indio_dev,
 124                                struct iio_chan_spec const *chan,
 125                                int val,
 126                                int val2,
 127                                long mask)
 128 {
 129         struct prox_state *prox_state = iio_priv(indio_dev);
 130         int ret = 0;
 131 
 132         switch (mask) {
 133         case IIO_CHAN_INFO_SAMP_FREQ:
 134                 ret = hid_sensor_write_samp_freq_value(
 135                                 &prox_state->common_attributes, val, val2);
 136                 break;
 137         case IIO_CHAN_INFO_HYSTERESIS:
 138                 ret = hid_sensor_write_raw_hyst_value(
 139                                 &prox_state->common_attributes, val, val2);
 140                 break;
 141         default:
 142                 ret = -EINVAL;
 143         }
 144 
 145         return ret;
 146 }
 147 
 148 static const struct iio_info prox_info = {
 149         .read_raw = &prox_read_raw,
 150         .write_raw = &prox_write_raw,
 151 };
 152 
 153 /* Function to push data to buffer */
 154 static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data,
 155                                         int len)
 156 {
 157         dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
 158         iio_push_to_buffers(indio_dev, data);
 159 }
 160 
 161 /* Callback handler to send event after all samples are received and captured */
 162 static int prox_proc_event(struct hid_sensor_hub_device *hsdev,
 163                                 unsigned usage_id,
 164                                 void *priv)
 165 {
 166         struct iio_dev *indio_dev = platform_get_drvdata(priv);
 167         struct prox_state *prox_state = iio_priv(indio_dev);
 168 
 169         dev_dbg(&indio_dev->dev, "prox_proc_event\n");
 170         if (atomic_read(&prox_state->common_attributes.data_ready))
 171                 hid_sensor_push_data(indio_dev,
 172                                 &prox_state->human_presence,
 173                                 sizeof(prox_state->human_presence));
 174 
 175         return 0;
 176 }
 177 
 178 /* Capture samples in local storage */
 179 static int prox_capture_sample(struct hid_sensor_hub_device *hsdev,
 180                                 unsigned usage_id,
 181                                 size_t raw_len, char *raw_data,
 182                                 void *priv)
 183 {
 184         struct iio_dev *indio_dev = platform_get_drvdata(priv);
 185         struct prox_state *prox_state = iio_priv(indio_dev);
 186         int ret = -EINVAL;
 187 
 188         switch (usage_id) {
 189         case HID_USAGE_SENSOR_HUMAN_PRESENCE:
 190                 prox_state->human_presence = *(u32 *)raw_data;
 191                 ret = 0;
 192                 break;
 193         default:
 194                 break;
 195         }
 196 
 197         return ret;
 198 }
 199 
 200 /* Parse report which is specific to an usage id*/
 201 static int prox_parse_report(struct platform_device *pdev,
 202                                 struct hid_sensor_hub_device *hsdev,
 203                                 struct iio_chan_spec *channels,
 204                                 unsigned usage_id,
 205                                 struct prox_state *st)
 206 {
 207         int ret;
 208 
 209         ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
 210                         usage_id,
 211                         HID_USAGE_SENSOR_HUMAN_PRESENCE,
 212                         &st->prox_attr);
 213         if (ret < 0)
 214                 return ret;
 215         prox_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_PRESENCE,
 216                                         st->prox_attr.size);
 217 
 218         dev_dbg(&pdev->dev, "prox %x:%x\n", st->prox_attr.index,
 219                         st->prox_attr.report_id);
 220 
 221         /* Set Sensitivity field ids, when there is no individual modifier */
 222         if (st->common_attributes.sensitivity.index < 0) {
 223                 sensor_hub_input_get_attribute_info(hsdev,
 224                         HID_FEATURE_REPORT, usage_id,
 225                         HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
 226                         HID_USAGE_SENSOR_DATA_PRESENCE,
 227                         &st->common_attributes.sensitivity);
 228                 dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
 229                         st->common_attributes.sensitivity.index,
 230                         st->common_attributes.sensitivity.report_id);
 231         }
 232         if (st->common_attributes.sensitivity.index < 0)
 233                 sensor_hub_input_get_attribute_info(hsdev,
 234                         HID_FEATURE_REPORT, usage_id,
 235                         HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
 236                         HID_USAGE_SENSOR_HUMAN_PRESENCE,
 237                         &st->common_attributes.sensitivity);
 238 
 239         return ret;
 240 }
 241 
 242 /* Function to initialize the processing for usage id */
 243 static int hid_prox_probe(struct platform_device *pdev)
 244 {
 245         int ret = 0;
 246         static const char *name = "prox";
 247         struct iio_dev *indio_dev;
 248         struct prox_state *prox_state;
 249         struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
 250 
 251         indio_dev = devm_iio_device_alloc(&pdev->dev,
 252                                 sizeof(struct prox_state));
 253         if (!indio_dev)
 254                 return -ENOMEM;
 255         platform_set_drvdata(pdev, indio_dev);
 256 
 257         prox_state = iio_priv(indio_dev);
 258         prox_state->common_attributes.hsdev = hsdev;
 259         prox_state->common_attributes.pdev = pdev;
 260 
 261         ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_PROX,
 262                                         &prox_state->common_attributes);
 263         if (ret) {
 264                 dev_err(&pdev->dev, "failed to setup common attributes\n");
 265                 return ret;
 266         }
 267 
 268         indio_dev->channels = kmemdup(prox_channels, sizeof(prox_channels),
 269                                       GFP_KERNEL);
 270         if (!indio_dev->channels) {
 271                 dev_err(&pdev->dev, "failed to duplicate channels\n");
 272                 return -ENOMEM;
 273         }
 274 
 275         ret = prox_parse_report(pdev, hsdev,
 276                                 (struct iio_chan_spec *)indio_dev->channels,
 277                                 HID_USAGE_SENSOR_PROX, prox_state);
 278         if (ret) {
 279                 dev_err(&pdev->dev, "failed to setup attributes\n");
 280                 goto error_free_dev_mem;
 281         }
 282 
 283         indio_dev->num_channels = ARRAY_SIZE(prox_channels);
 284         indio_dev->dev.parent = &pdev->dev;
 285         indio_dev->info = &prox_info;
 286         indio_dev->name = name;
 287         indio_dev->modes = INDIO_DIRECT_MODE;
 288 
 289         ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
 290                 NULL, NULL);
 291         if (ret) {
 292                 dev_err(&pdev->dev, "failed to initialize trigger buffer\n");
 293                 goto error_free_dev_mem;
 294         }
 295         atomic_set(&prox_state->common_attributes.data_ready, 0);
 296         ret = hid_sensor_setup_trigger(indio_dev, name,
 297                                 &prox_state->common_attributes);
 298         if (ret) {
 299                 dev_err(&pdev->dev, "trigger setup failed\n");
 300                 goto error_unreg_buffer_funcs;
 301         }
 302 
 303         ret = iio_device_register(indio_dev);
 304         if (ret) {
 305                 dev_err(&pdev->dev, "device register failed\n");
 306                 goto error_remove_trigger;
 307         }
 308 
 309         prox_state->callbacks.send_event = prox_proc_event;
 310         prox_state->callbacks.capture_sample = prox_capture_sample;
 311         prox_state->callbacks.pdev = pdev;
 312         ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_PROX,
 313                                         &prox_state->callbacks);
 314         if (ret < 0) {
 315                 dev_err(&pdev->dev, "callback reg failed\n");
 316                 goto error_iio_unreg;
 317         }
 318 
 319         return ret;
 320 
 321 error_iio_unreg:
 322         iio_device_unregister(indio_dev);
 323 error_remove_trigger:
 324         hid_sensor_remove_trigger(&prox_state->common_attributes);
 325 error_unreg_buffer_funcs:
 326         iio_triggered_buffer_cleanup(indio_dev);
 327 error_free_dev_mem:
 328         kfree(indio_dev->channels);
 329         return ret;
 330 }
 331 
 332 /* Function to deinitialize the processing for usage id */
 333 static int hid_prox_remove(struct platform_device *pdev)
 334 {
 335         struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
 336         struct iio_dev *indio_dev = platform_get_drvdata(pdev);
 337         struct prox_state *prox_state = iio_priv(indio_dev);
 338 
 339         sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PROX);
 340         iio_device_unregister(indio_dev);
 341         hid_sensor_remove_trigger(&prox_state->common_attributes);
 342         iio_triggered_buffer_cleanup(indio_dev);
 343         kfree(indio_dev->channels);
 344 
 345         return 0;
 346 }
 347 
 348 static const struct platform_device_id hid_prox_ids[] = {
 349         {
 350                 /* Format: HID-SENSOR-usage_id_in_hex_lowercase */
 351                 .name = "HID-SENSOR-200011",
 352         },
 353         { /* sentinel */ }
 354 };
 355 MODULE_DEVICE_TABLE(platform, hid_prox_ids);
 356 
 357 static struct platform_driver hid_prox_platform_driver = {
 358         .id_table = hid_prox_ids,
 359         .driver = {
 360                 .name   = KBUILD_MODNAME,
 361                 .pm     = &hid_sensor_pm_ops,
 362         },
 363         .probe          = hid_prox_probe,
 364         .remove         = hid_prox_remove,
 365 };
 366 module_platform_driver(hid_prox_platform_driver);
 367 
 368 MODULE_DESCRIPTION("HID Sensor Proximity");
 369 MODULE_AUTHOR("Archana Patni <archana.patni@intel.com>");
 370 MODULE_LICENSE("GPL");

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