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