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