root/drivers/iio/humidity/hid-sensor-humidity.c

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

DEFINITIONS

This source file includes following definitions.
  1. humidity_adjust_channel_bit_mask
  2. humidity_read_raw
  3. humidity_write_raw
  4. humidity_proc_event
  5. humidity_capture_sample
  6. humidity_parse_report
  7. hid_humidity_probe
  8. hid_humidity_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * HID Sensors Driver
   4  * Copyright (c) 2017, Intel Corporation.
   5  */
   6 #include <linux/device.h>
   7 #include <linux/hid-sensor-hub.h>
   8 #include <linux/iio/buffer.h>
   9 #include <linux/iio/iio.h>
  10 #include <linux/iio/triggered_buffer.h>
  11 #include <linux/iio/trigger_consumer.h>
  12 #include <linux/module.h>
  13 #include <linux/platform_device.h>
  14 
  15 #include "hid-sensor-trigger.h"
  16 
  17 struct hid_humidity_state {
  18         struct hid_sensor_common common_attributes;
  19         struct hid_sensor_hub_attribute_info humidity_attr;
  20         s32 humidity_data;
  21         int scale_pre_decml;
  22         int scale_post_decml;
  23         int scale_precision;
  24         int value_offset;
  25 };
  26 
  27 /* Channel definitions */
  28 static const struct iio_chan_spec humidity_channels[] = {
  29         {
  30                 .type = IIO_HUMIDITYRELATIVE,
  31                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
  32                 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
  33                         BIT(IIO_CHAN_INFO_SCALE) |
  34                         BIT(IIO_CHAN_INFO_SAMP_FREQ) |
  35                         BIT(IIO_CHAN_INFO_HYSTERESIS),
  36         },
  37         IIO_CHAN_SOFT_TIMESTAMP(1)
  38 };
  39 
  40 /* Adjust channel real bits based on report descriptor */
  41 static void humidity_adjust_channel_bit_mask(struct iio_chan_spec *channels,
  42                                         int channel, int size)
  43 {
  44         channels[channel].scan_type.sign = 's';
  45         /* Real storage bits will change based on the report desc. */
  46         channels[channel].scan_type.realbits = size * 8;
  47         /* Maximum size of a sample to capture is s32 */
  48         channels[channel].scan_type.storagebits = sizeof(s32) * 8;
  49 }
  50 
  51 static int humidity_read_raw(struct iio_dev *indio_dev,
  52                                 struct iio_chan_spec const *chan,
  53                                 int *val, int *val2, long mask)
  54 {
  55         struct hid_humidity_state *humid_st = iio_priv(indio_dev);
  56 
  57         switch (mask) {
  58         case IIO_CHAN_INFO_RAW:
  59                 if (chan->type != IIO_HUMIDITYRELATIVE)
  60                         return -EINVAL;
  61                 hid_sensor_power_state(&humid_st->common_attributes, true);
  62                 *val = sensor_hub_input_attr_get_raw_value(
  63                                 humid_st->common_attributes.hsdev,
  64                                 HID_USAGE_SENSOR_HUMIDITY,
  65                                 HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY,
  66                                 humid_st->humidity_attr.report_id,
  67                                 SENSOR_HUB_SYNC,
  68                                 humid_st->humidity_attr.logical_minimum < 0);
  69                 hid_sensor_power_state(&humid_st->common_attributes, false);
  70 
  71                 return IIO_VAL_INT;
  72 
  73         case IIO_CHAN_INFO_SCALE:
  74                 *val = humid_st->scale_pre_decml;
  75                 *val2 = humid_st->scale_post_decml;
  76 
  77                 return humid_st->scale_precision;
  78 
  79         case IIO_CHAN_INFO_OFFSET:
  80                 *val = humid_st->value_offset;
  81 
  82                 return IIO_VAL_INT;
  83 
  84         case IIO_CHAN_INFO_SAMP_FREQ:
  85                 return hid_sensor_read_samp_freq_value(
  86                                 &humid_st->common_attributes, val, val2);
  87 
  88         case IIO_CHAN_INFO_HYSTERESIS:
  89                 return hid_sensor_read_raw_hyst_value(
  90                                 &humid_st->common_attributes, val, val2);
  91 
  92         default:
  93                 return -EINVAL;
  94         }
  95 }
  96 
  97 static int humidity_write_raw(struct iio_dev *indio_dev,
  98                                 struct iio_chan_spec const *chan,
  99                                 int val, int val2, long mask)
 100 {
 101         struct hid_humidity_state *humid_st = iio_priv(indio_dev);
 102 
 103         switch (mask) {
 104         case IIO_CHAN_INFO_SAMP_FREQ:
 105                 return hid_sensor_write_samp_freq_value(
 106                                 &humid_st->common_attributes, val, val2);
 107 
 108         case IIO_CHAN_INFO_HYSTERESIS:
 109                 return hid_sensor_write_raw_hyst_value(
 110                                 &humid_st->common_attributes, val, val2);
 111 
 112         default:
 113                 return -EINVAL;
 114         }
 115 }
 116 
 117 static const struct iio_info humidity_info = {
 118         .read_raw = &humidity_read_raw,
 119         .write_raw = &humidity_write_raw,
 120 };
 121 
 122 /* Callback handler to send event after all samples are received and captured */
 123 static int humidity_proc_event(struct hid_sensor_hub_device *hsdev,
 124                                 unsigned int usage_id, void *pdev)
 125 {
 126         struct iio_dev *indio_dev = platform_get_drvdata(pdev);
 127         struct hid_humidity_state *humid_st = iio_priv(indio_dev);
 128 
 129         if (atomic_read(&humid_st->common_attributes.data_ready))
 130                 iio_push_to_buffers_with_timestamp(indio_dev,
 131                                         &humid_st->humidity_data,
 132                                         iio_get_time_ns(indio_dev));
 133 
 134         return 0;
 135 }
 136 
 137 /* Capture samples in local storage */
 138 static int humidity_capture_sample(struct hid_sensor_hub_device *hsdev,
 139                                 unsigned int usage_id, size_t raw_len,
 140                                 char *raw_data, void *pdev)
 141 {
 142         struct iio_dev *indio_dev = platform_get_drvdata(pdev);
 143         struct hid_humidity_state *humid_st = iio_priv(indio_dev);
 144 
 145         switch (usage_id) {
 146         case HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY:
 147                 humid_st->humidity_data = *(s32 *)raw_data;
 148 
 149                 return 0;
 150         default:
 151                 return -EINVAL;
 152         }
 153 }
 154 
 155 /* Parse report which is specific to an usage id */
 156 static int humidity_parse_report(struct platform_device *pdev,
 157                                 struct hid_sensor_hub_device *hsdev,
 158                                 struct iio_chan_spec *channels,
 159                                 unsigned int usage_id,
 160                                 struct hid_humidity_state *st)
 161 {
 162         int ret;
 163 
 164         ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT,
 165                                         usage_id,
 166                                         HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY,
 167                                         &st->humidity_attr);
 168         if (ret < 0)
 169                 return ret;
 170 
 171         humidity_adjust_channel_bit_mask(channels, 0, st->humidity_attr.size);
 172 
 173         st->scale_precision = hid_sensor_format_scale(
 174                                                 HID_USAGE_SENSOR_HUMIDITY,
 175                                                 &st->humidity_attr,
 176                                                 &st->scale_pre_decml,
 177                                                 &st->scale_post_decml);
 178 
 179         /* Set Sensitivity field ids, when there is no individual modifier */
 180         if (st->common_attributes.sensitivity.index < 0)
 181                 sensor_hub_input_get_attribute_info(hsdev,
 182                         HID_FEATURE_REPORT, usage_id,
 183                         HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
 184                         HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY,
 185                         &st->common_attributes.sensitivity);
 186 
 187         return ret;
 188 }
 189 
 190 static struct hid_sensor_hub_callbacks humidity_callbacks = {
 191         .send_event = &humidity_proc_event,
 192         .capture_sample = &humidity_capture_sample,
 193 };
 194 
 195 /* Function to initialize the processing for usage id */
 196 static int hid_humidity_probe(struct platform_device *pdev)
 197 {
 198         static const char *name = "humidity";
 199         struct iio_dev *indio_dev;
 200         struct hid_humidity_state *humid_st;
 201         struct iio_chan_spec *humid_chans;
 202         struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev);
 203         int ret;
 204 
 205         indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*humid_st));
 206         if (!indio_dev)
 207                 return -ENOMEM;
 208 
 209         humid_st = iio_priv(indio_dev);
 210         humid_st->common_attributes.hsdev = hsdev;
 211         humid_st->common_attributes.pdev = pdev;
 212 
 213         ret = hid_sensor_parse_common_attributes(hsdev,
 214                                         HID_USAGE_SENSOR_HUMIDITY,
 215                                         &humid_st->common_attributes);
 216         if (ret)
 217                 return ret;
 218 
 219         humid_chans = devm_kmemdup(&indio_dev->dev, humidity_channels,
 220                                         sizeof(humidity_channels), GFP_KERNEL);
 221         if (!humid_chans)
 222                 return -ENOMEM;
 223 
 224         ret = humidity_parse_report(pdev, hsdev, humid_chans,
 225                                 HID_USAGE_SENSOR_HUMIDITY, humid_st);
 226         if (ret)
 227                 return ret;
 228 
 229         indio_dev->channels = humid_chans;
 230         indio_dev->num_channels = ARRAY_SIZE(humidity_channels);
 231         indio_dev->dev.parent = &pdev->dev;
 232         indio_dev->info = &humidity_info;
 233         indio_dev->name = name;
 234         indio_dev->modes = INDIO_DIRECT_MODE;
 235 
 236         ret = devm_iio_triggered_buffer_setup(&pdev->dev, indio_dev,
 237                                         &iio_pollfunc_store_time, NULL, NULL);
 238         if (ret)
 239                 return ret;
 240 
 241         atomic_set(&humid_st->common_attributes.data_ready, 0);
 242         ret = hid_sensor_setup_trigger(indio_dev, name,
 243                                 &humid_st->common_attributes);
 244         if (ret)
 245                 return ret;
 246 
 247         platform_set_drvdata(pdev, indio_dev);
 248 
 249         humidity_callbacks.pdev = pdev;
 250         ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY,
 251                                         &humidity_callbacks);
 252         if (ret)
 253                 goto error_remove_trigger;
 254 
 255         ret = iio_device_register(indio_dev);
 256         if (ret)
 257                 goto error_remove_callback;
 258 
 259         return ret;
 260 
 261 error_remove_callback:
 262         sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY);
 263 error_remove_trigger:
 264         hid_sensor_remove_trigger(&humid_st->common_attributes);
 265         return ret;
 266 }
 267 
 268 /* Function to deinitialize the processing for usage id */
 269 static int hid_humidity_remove(struct platform_device *pdev)
 270 {
 271         struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev);
 272         struct iio_dev *indio_dev = platform_get_drvdata(pdev);
 273         struct hid_humidity_state *humid_st = iio_priv(indio_dev);
 274 
 275         iio_device_unregister(indio_dev);
 276         sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY);
 277         hid_sensor_remove_trigger(&humid_st->common_attributes);
 278 
 279         return 0;
 280 }
 281 
 282 static const struct platform_device_id hid_humidity_ids[] = {
 283         {
 284                 /* Format: HID-SENSOR-usage_id_in_hex_lowercase */
 285                 .name = "HID-SENSOR-200032",
 286         },
 287         { /* sentinel */ }
 288 };
 289 MODULE_DEVICE_TABLE(platform, hid_humidity_ids);
 290 
 291 static struct platform_driver hid_humidity_platform_driver = {
 292         .id_table = hid_humidity_ids,
 293         .driver = {
 294                 .name   = KBUILD_MODNAME,
 295                 .pm     = &hid_sensor_pm_ops,
 296         },
 297         .probe          = hid_humidity_probe,
 298         .remove         = hid_humidity_remove,
 299 };
 300 module_platform_driver(hid_humidity_platform_driver);
 301 
 302 MODULE_DESCRIPTION("HID Environmental humidity sensor");
 303 MODULE_AUTHOR("Song Hongyan <hongyan.song@intel.com>");
 304 MODULE_LICENSE("GPL v2");

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