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