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 .driver_module = THIS_MODULE, 129 .read_raw = &humidity_read_raw, 130 .write_raw = &humidity_write_raw, 131 }; 132 133 /* Callback handler to send event after all samples are received and captured */ 134 static int humidity_proc_event(struct hid_sensor_hub_device *hsdev, 135 unsigned int usage_id, void *pdev) 136 { 137 struct iio_dev *indio_dev = platform_get_drvdata(pdev); 138 struct hid_humidity_state *humid_st = iio_priv(indio_dev); 139 140 if (atomic_read(&humid_st->common_attributes.data_ready)) 141 iio_push_to_buffers_with_timestamp(indio_dev, 142 &humid_st->humidity_data, 143 iio_get_time_ns(indio_dev)); 144 145 return 0; 146 } 147 148 /* Capture samples in local storage */ 149 static int humidity_capture_sample(struct hid_sensor_hub_device *hsdev, 150 unsigned int usage_id, size_t raw_len, 151 char *raw_data, void *pdev) 152 { 153 struct iio_dev *indio_dev = platform_get_drvdata(pdev); 154 struct hid_humidity_state *humid_st = iio_priv(indio_dev); 155 156 switch (usage_id) { 157 case HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY: 158 humid_st->humidity_data = *(s32 *)raw_data; 159 160 return 0; 161 default: 162 return -EINVAL; 163 } 164 } 165 166 /* Parse report which is specific to an usage id */ 167 static int humidity_parse_report(struct platform_device *pdev, 168 struct hid_sensor_hub_device *hsdev, 169 struct iio_chan_spec *channels, 170 unsigned int usage_id, 171 struct hid_humidity_state *st) 172 { 173 int ret; 174 175 ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT, 176 usage_id, 177 HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY, 178 &st->humidity_attr); 179 if (ret < 0) 180 return ret; 181 182 humidity_adjust_channel_bit_mask(channels, 0, st->humidity_attr.size); 183 184 st->scale_precision = hid_sensor_format_scale( 185 HID_USAGE_SENSOR_HUMIDITY, 186 &st->humidity_attr, 187 &st->scale_pre_decml, 188 &st->scale_post_decml); 189 190 /* Set Sensitivity field ids, when there is no individual modifier */ 191 if (st->common_attributes.sensitivity.index < 0) 192 sensor_hub_input_get_attribute_info(hsdev, 193 HID_FEATURE_REPORT, usage_id, 194 HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | 195 HID_USAGE_SENSOR_ATMOSPHERIC_HUMIDITY, 196 &st->common_attributes.sensitivity); 197 198 return ret; 199 } 200 201 static struct hid_sensor_hub_callbacks humidity_callbacks = { 202 .send_event = &humidity_proc_event, 203 .capture_sample = &humidity_capture_sample, 204 }; 205 206 /* Function to initialize the processing for usage id */ 207 static int hid_humidity_probe(struct platform_device *pdev) 208 { 209 static const char *name = "humidity"; 210 struct iio_dev *indio_dev; 211 struct hid_humidity_state *humid_st; 212 struct iio_chan_spec *humid_chans; 213 struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); 214 int ret; 215 216 indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*humid_st)); 217 if (!indio_dev) 218 return -ENOMEM; 219 220 humid_st = iio_priv(indio_dev); 221 humid_st->common_attributes.hsdev = hsdev; 222 humid_st->common_attributes.pdev = pdev; 223 224 ret = hid_sensor_parse_common_attributes(hsdev, 225 HID_USAGE_SENSOR_HUMIDITY, 226 &humid_st->common_attributes); 227 if (ret) 228 return ret; 229 230 humid_chans = devm_kmemdup(&indio_dev->dev, humidity_channels, 231 sizeof(humidity_channels), GFP_KERNEL); 232 if (!humid_chans) 233 return -ENOMEM; 234 235 ret = humidity_parse_report(pdev, hsdev, humid_chans, 236 HID_USAGE_SENSOR_HUMIDITY, humid_st); 237 if (ret) 238 return ret; 239 240 indio_dev->channels = humid_chans; 241 indio_dev->num_channels = ARRAY_SIZE(humidity_channels); 242 indio_dev->dev.parent = &pdev->dev; 243 indio_dev->info = &humidity_info; 244 indio_dev->name = name; 245 indio_dev->modes = INDIO_DIRECT_MODE; 246 247 ret = devm_iio_triggered_buffer_setup(&pdev->dev, indio_dev, 248 &iio_pollfunc_store_time, NULL, NULL); 249 if (ret) 250 return ret; 251 252 atomic_set(&humid_st->common_attributes.data_ready, 0); 253 ret = hid_sensor_setup_trigger(indio_dev, name, 254 &humid_st->common_attributes); 255 if (ret) 256 return ret; 257 258 platform_set_drvdata(pdev, indio_dev); 259 260 humidity_callbacks.pdev = pdev; 261 ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY, 262 &humidity_callbacks); 263 if (ret) 264 goto error_remove_trigger; 265 266 ret = iio_device_register(indio_dev); 267 if (ret) 268 goto error_remove_callback; 269 270 return ret; 271 272 error_remove_callback: 273 sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY); 274 error_remove_trigger: 275 hid_sensor_remove_trigger(&humid_st->common_attributes); 276 return ret; 277 } 278 279 /* Function to deinitialize the processing for usage id */ 280 static int hid_humidity_remove(struct platform_device *pdev) 281 { 282 struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); 283 struct iio_dev *indio_dev = platform_get_drvdata(pdev); 284 struct hid_humidity_state *humid_st = iio_priv(indio_dev); 285 286 iio_device_unregister(indio_dev); 287 sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_HUMIDITY); 288 hid_sensor_remove_trigger(&humid_st->common_attributes); 289 290 return 0; 291 } 292 293 static const struct platform_device_id hid_humidity_ids[] = { 294 { 295 /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ 296 .name = "HID-SENSOR-200032", 297 }, 298 { /* sentinel */ } 299 }; 300 MODULE_DEVICE_TABLE(platform, hid_humidity_ids); 301 302 static struct platform_driver hid_humidity_platform_driver = { 303 .id_table = hid_humidity_ids, 304 .driver = { 305 .name = KBUILD_MODNAME, 306 .pm = &hid_sensor_pm_ops, 307 }, 308 .probe = hid_humidity_probe, 309 .remove = hid_humidity_remove, 310 }; 311 module_platform_driver(hid_humidity_platform_driver); 312 313 MODULE_DESCRIPTION("HID Environmental humidity sensor"); 314 MODULE_AUTHOR("Song Hongyan <hongyan.song@intel.com>"); 315 MODULE_LICENSE("GPL v2"); 316