Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * HID Sensors Driver
0004  * Copyright (c) 2012, Intel Corporation.
0005  */
0006 #include <linux/device.h>
0007 #include <linux/platform_device.h>
0008 #include <linux/module.h>
0009 #include <linux/mod_devicetable.h>
0010 #include <linux/slab.h>
0011 #include <linux/hid-sensor-hub.h>
0012 #include <linux/iio/iio.h>
0013 #include <linux/iio/buffer.h>
0014 #include "../common/hid-sensors/hid-sensor-trigger.h"
0015 
0016 enum accel_3d_channel {
0017     CHANNEL_SCAN_INDEX_X,
0018     CHANNEL_SCAN_INDEX_Y,
0019     CHANNEL_SCAN_INDEX_Z,
0020     ACCEL_3D_CHANNEL_MAX,
0021 };
0022 
0023 #define CHANNEL_SCAN_INDEX_TIMESTAMP ACCEL_3D_CHANNEL_MAX
0024 struct accel_3d_state {
0025     struct hid_sensor_hub_callbacks callbacks;
0026     struct hid_sensor_common common_attributes;
0027     struct hid_sensor_hub_attribute_info accel[ACCEL_3D_CHANNEL_MAX];
0028     /* Ensure timestamp is naturally aligned */
0029     struct {
0030         u32 accel_val[3];
0031         s64 timestamp __aligned(8);
0032     } scan;
0033     int scale_pre_decml;
0034     int scale_post_decml;
0035     int scale_precision;
0036     int value_offset;
0037     int64_t timestamp;
0038 };
0039 
0040 static const u32 accel_3d_addresses[ACCEL_3D_CHANNEL_MAX] = {
0041     HID_USAGE_SENSOR_ACCEL_X_AXIS,
0042     HID_USAGE_SENSOR_ACCEL_Y_AXIS,
0043     HID_USAGE_SENSOR_ACCEL_Z_AXIS
0044 };
0045 
0046 static const u32 accel_3d_sensitivity_addresses[] = {
0047     HID_USAGE_SENSOR_DATA_ACCELERATION,
0048 };
0049 
0050 /* Channel definitions */
0051 static const struct iio_chan_spec accel_3d_channels[] = {
0052     {
0053         .type = IIO_ACCEL,
0054         .modified = 1,
0055         .channel2 = IIO_MOD_X,
0056         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0057         .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
0058         BIT(IIO_CHAN_INFO_SCALE) |
0059         BIT(IIO_CHAN_INFO_SAMP_FREQ) |
0060         BIT(IIO_CHAN_INFO_HYSTERESIS),
0061         .scan_index = CHANNEL_SCAN_INDEX_X,
0062     }, {
0063         .type = IIO_ACCEL,
0064         .modified = 1,
0065         .channel2 = IIO_MOD_Y,
0066         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0067         .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
0068         BIT(IIO_CHAN_INFO_SCALE) |
0069         BIT(IIO_CHAN_INFO_SAMP_FREQ) |
0070         BIT(IIO_CHAN_INFO_HYSTERESIS),
0071         .scan_index = CHANNEL_SCAN_INDEX_Y,
0072     }, {
0073         .type = IIO_ACCEL,
0074         .modified = 1,
0075         .channel2 = IIO_MOD_Z,
0076         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0077         .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
0078         BIT(IIO_CHAN_INFO_SCALE) |
0079         BIT(IIO_CHAN_INFO_SAMP_FREQ) |
0080         BIT(IIO_CHAN_INFO_HYSTERESIS),
0081         .scan_index = CHANNEL_SCAN_INDEX_Z,
0082     },
0083     IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP)
0084 };
0085 
0086 /* Channel definitions */
0087 static const struct iio_chan_spec gravity_channels[] = {
0088     {
0089         .type = IIO_GRAVITY,
0090         .modified = 1,
0091         .channel2 = IIO_MOD_X,
0092         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0093         .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
0094         BIT(IIO_CHAN_INFO_SCALE) |
0095         BIT(IIO_CHAN_INFO_SAMP_FREQ) |
0096         BIT(IIO_CHAN_INFO_HYSTERESIS),
0097         .scan_index = CHANNEL_SCAN_INDEX_X,
0098     }, {
0099         .type = IIO_GRAVITY,
0100         .modified = 1,
0101         .channel2 = IIO_MOD_Y,
0102         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0103         .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
0104         BIT(IIO_CHAN_INFO_SCALE) |
0105         BIT(IIO_CHAN_INFO_SAMP_FREQ) |
0106         BIT(IIO_CHAN_INFO_HYSTERESIS),
0107         .scan_index = CHANNEL_SCAN_INDEX_Y,
0108     }, {
0109         .type = IIO_GRAVITY,
0110         .modified = 1,
0111         .channel2 = IIO_MOD_Z,
0112         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
0113         .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
0114         BIT(IIO_CHAN_INFO_SCALE) |
0115         BIT(IIO_CHAN_INFO_SAMP_FREQ) |
0116         BIT(IIO_CHAN_INFO_HYSTERESIS),
0117         .scan_index = CHANNEL_SCAN_INDEX_Z,
0118     },
0119     IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP),
0120 };
0121 
0122 /* Adjust channel real bits based on report descriptor */
0123 static void accel_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels,
0124                         int channel, int size)
0125 {
0126     channels[channel].scan_type.sign = 's';
0127     /* Real storage bits will change based on the report desc. */
0128     channels[channel].scan_type.realbits = size * 8;
0129     /* Maximum size of a sample to capture is u32 */
0130     channels[channel].scan_type.storagebits = sizeof(u32) * 8;
0131 }
0132 
0133 /* Channel read_raw handler */
0134 static int accel_3d_read_raw(struct iio_dev *indio_dev,
0135                   struct iio_chan_spec const *chan,
0136                   int *val, int *val2,
0137                   long mask)
0138 {
0139     struct accel_3d_state *accel_state = iio_priv(indio_dev);
0140     int report_id = -1;
0141     u32 address;
0142     int ret_type;
0143     s32 min;
0144     struct hid_sensor_hub_device *hsdev =
0145                     accel_state->common_attributes.hsdev;
0146 
0147     *val = 0;
0148     *val2 = 0;
0149     switch (mask) {
0150     case IIO_CHAN_INFO_RAW:
0151         hid_sensor_power_state(&accel_state->common_attributes, true);
0152         report_id = accel_state->accel[chan->scan_index].report_id;
0153         min = accel_state->accel[chan->scan_index].logical_minimum;
0154         address = accel_3d_addresses[chan->scan_index];
0155         if (report_id >= 0)
0156             *val = sensor_hub_input_attr_get_raw_value(
0157                     accel_state->common_attributes.hsdev,
0158                     hsdev->usage, address, report_id,
0159                     SENSOR_HUB_SYNC,
0160                     min < 0);
0161         else {
0162             *val = 0;
0163             hid_sensor_power_state(&accel_state->common_attributes,
0164                          false);
0165             return -EINVAL;
0166         }
0167         hid_sensor_power_state(&accel_state->common_attributes, false);
0168         ret_type = IIO_VAL_INT;
0169         break;
0170     case IIO_CHAN_INFO_SCALE:
0171         *val = accel_state->scale_pre_decml;
0172         *val2 = accel_state->scale_post_decml;
0173         ret_type = accel_state->scale_precision;
0174         break;
0175     case IIO_CHAN_INFO_OFFSET:
0176         *val = accel_state->value_offset;
0177         ret_type = IIO_VAL_INT;
0178         break;
0179     case IIO_CHAN_INFO_SAMP_FREQ:
0180         ret_type = hid_sensor_read_samp_freq_value(
0181             &accel_state->common_attributes, val, val2);
0182         break;
0183     case IIO_CHAN_INFO_HYSTERESIS:
0184         ret_type = hid_sensor_read_raw_hyst_value(
0185             &accel_state->common_attributes, val, val2);
0186         break;
0187     default:
0188         ret_type = -EINVAL;
0189         break;
0190     }
0191 
0192     return ret_type;
0193 }
0194 
0195 /* Channel write_raw handler */
0196 static int accel_3d_write_raw(struct iio_dev *indio_dev,
0197                    struct iio_chan_spec const *chan,
0198                    int val,
0199                    int val2,
0200                    long mask)
0201 {
0202     struct accel_3d_state *accel_state = iio_priv(indio_dev);
0203     int ret = 0;
0204 
0205     switch (mask) {
0206     case IIO_CHAN_INFO_SAMP_FREQ:
0207         ret = hid_sensor_write_samp_freq_value(
0208                 &accel_state->common_attributes, val, val2);
0209         break;
0210     case IIO_CHAN_INFO_HYSTERESIS:
0211         ret = hid_sensor_write_raw_hyst_value(
0212                 &accel_state->common_attributes, val, val2);
0213         break;
0214     default:
0215         ret = -EINVAL;
0216     }
0217 
0218     return ret;
0219 }
0220 
0221 static const struct iio_info accel_3d_info = {
0222     .read_raw = &accel_3d_read_raw,
0223     .write_raw = &accel_3d_write_raw,
0224 };
0225 
0226 /* Function to push data to buffer */
0227 static void hid_sensor_push_data(struct iio_dev *indio_dev, void *data,
0228                  int len, int64_t timestamp)
0229 {
0230     dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
0231     iio_push_to_buffers_with_timestamp(indio_dev, data, timestamp);
0232 }
0233 
0234 /* Callback handler to send event after all samples are received and captured */
0235 static int accel_3d_proc_event(struct hid_sensor_hub_device *hsdev,
0236                 unsigned usage_id,
0237                 void *priv)
0238 {
0239     struct iio_dev *indio_dev = platform_get_drvdata(priv);
0240     struct accel_3d_state *accel_state = iio_priv(indio_dev);
0241 
0242     dev_dbg(&indio_dev->dev, "accel_3d_proc_event\n");
0243     if (atomic_read(&accel_state->common_attributes.data_ready)) {
0244         if (!accel_state->timestamp)
0245             accel_state->timestamp = iio_get_time_ns(indio_dev);
0246 
0247         hid_sensor_push_data(indio_dev,
0248                      &accel_state->scan,
0249                      sizeof(accel_state->scan),
0250                      accel_state->timestamp);
0251 
0252         accel_state->timestamp = 0;
0253     }
0254 
0255     return 0;
0256 }
0257 
0258 /* Capture samples in local storage */
0259 static int accel_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
0260                 unsigned usage_id,
0261                 size_t raw_len, char *raw_data,
0262                 void *priv)
0263 {
0264     struct iio_dev *indio_dev = platform_get_drvdata(priv);
0265     struct accel_3d_state *accel_state = iio_priv(indio_dev);
0266     int offset;
0267     int ret = -EINVAL;
0268 
0269     switch (usage_id) {
0270     case HID_USAGE_SENSOR_ACCEL_X_AXIS:
0271     case HID_USAGE_SENSOR_ACCEL_Y_AXIS:
0272     case HID_USAGE_SENSOR_ACCEL_Z_AXIS:
0273         offset = usage_id - HID_USAGE_SENSOR_ACCEL_X_AXIS;
0274         accel_state->scan.accel_val[CHANNEL_SCAN_INDEX_X + offset] =
0275                         *(u32 *)raw_data;
0276         ret = 0;
0277     break;
0278     case HID_USAGE_SENSOR_TIME_TIMESTAMP:
0279         accel_state->timestamp =
0280             hid_sensor_convert_timestamp(
0281                     &accel_state->common_attributes,
0282                     *(int64_t *)raw_data);
0283     break;
0284     default:
0285         break;
0286     }
0287 
0288     return ret;
0289 }
0290 
0291 /* Parse report which is specific to an usage id*/
0292 static int accel_3d_parse_report(struct platform_device *pdev,
0293                 struct hid_sensor_hub_device *hsdev,
0294                 struct iio_chan_spec *channels,
0295                 unsigned usage_id,
0296                 struct accel_3d_state *st)
0297 {
0298     int ret;
0299     int i;
0300 
0301     for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) {
0302         ret = sensor_hub_input_get_attribute_info(hsdev,
0303                 HID_INPUT_REPORT,
0304                 usage_id,
0305                 HID_USAGE_SENSOR_ACCEL_X_AXIS + i,
0306                 &st->accel[CHANNEL_SCAN_INDEX_X + i]);
0307         if (ret < 0)
0308             break;
0309         accel_3d_adjust_channel_bit_mask(channels,
0310                 CHANNEL_SCAN_INDEX_X + i,
0311                 st->accel[CHANNEL_SCAN_INDEX_X + i].size);
0312     }
0313     dev_dbg(&pdev->dev, "accel_3d %x:%x, %x:%x, %x:%x\n",
0314             st->accel[0].index,
0315             st->accel[0].report_id,
0316             st->accel[1].index, st->accel[1].report_id,
0317             st->accel[2].index, st->accel[2].report_id);
0318 
0319     st->scale_precision = hid_sensor_format_scale(
0320                 hsdev->usage,
0321                 &st->accel[CHANNEL_SCAN_INDEX_X],
0322                 &st->scale_pre_decml, &st->scale_post_decml);
0323 
0324     return ret;
0325 }
0326 
0327 /* Function to initialize the processing for usage id */
0328 static int hid_accel_3d_probe(struct platform_device *pdev)
0329 {
0330     int ret = 0;
0331     const char *name;
0332     struct iio_dev *indio_dev;
0333     struct accel_3d_state *accel_state;
0334     const struct iio_chan_spec *channel_spec;
0335     int channel_size;
0336 
0337     struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
0338 
0339     indio_dev = devm_iio_device_alloc(&pdev->dev,
0340                       sizeof(struct accel_3d_state));
0341     if (indio_dev == NULL)
0342         return -ENOMEM;
0343 
0344     platform_set_drvdata(pdev, indio_dev);
0345 
0346     accel_state = iio_priv(indio_dev);
0347     accel_state->common_attributes.hsdev = hsdev;
0348     accel_state->common_attributes.pdev = pdev;
0349 
0350     if (hsdev->usage == HID_USAGE_SENSOR_ACCEL_3D) {
0351         name = "accel_3d";
0352         channel_spec = accel_3d_channels;
0353         channel_size = sizeof(accel_3d_channels);
0354         indio_dev->num_channels = ARRAY_SIZE(accel_3d_channels);
0355     } else {
0356         name = "gravity";
0357         channel_spec = gravity_channels;
0358         channel_size = sizeof(gravity_channels);
0359         indio_dev->num_channels = ARRAY_SIZE(gravity_channels);
0360     }
0361     ret = hid_sensor_parse_common_attributes(hsdev,
0362                          hsdev->usage,
0363                          &accel_state->common_attributes,
0364                          accel_3d_sensitivity_addresses,
0365                          ARRAY_SIZE(accel_3d_sensitivity_addresses));
0366     if (ret) {
0367         dev_err(&pdev->dev, "failed to setup common attributes\n");
0368         return ret;
0369     }
0370     indio_dev->channels = devm_kmemdup(&pdev->dev, channel_spec,
0371                        channel_size, GFP_KERNEL);
0372 
0373     if (!indio_dev->channels) {
0374         dev_err(&pdev->dev, "failed to duplicate channels\n");
0375         return -ENOMEM;
0376     }
0377     ret = accel_3d_parse_report(pdev, hsdev,
0378                 (struct iio_chan_spec *)indio_dev->channels,
0379                 hsdev->usage, accel_state);
0380     if (ret) {
0381         dev_err(&pdev->dev, "failed to setup attributes\n");
0382         return ret;
0383     }
0384 
0385     indio_dev->info = &accel_3d_info;
0386     indio_dev->name = name;
0387     indio_dev->modes = INDIO_DIRECT_MODE;
0388 
0389     atomic_set(&accel_state->common_attributes.data_ready, 0);
0390 
0391     ret = hid_sensor_setup_trigger(indio_dev, name,
0392                     &accel_state->common_attributes);
0393     if (ret < 0) {
0394         dev_err(&pdev->dev, "trigger setup failed\n");
0395         return ret;
0396     }
0397 
0398     ret = iio_device_register(indio_dev);
0399     if (ret) {
0400         dev_err(&pdev->dev, "device register failed\n");
0401         goto error_remove_trigger;
0402     }
0403 
0404     accel_state->callbacks.send_event = accel_3d_proc_event;
0405     accel_state->callbacks.capture_sample = accel_3d_capture_sample;
0406     accel_state->callbacks.pdev = pdev;
0407     ret = sensor_hub_register_callback(hsdev, hsdev->usage,
0408                     &accel_state->callbacks);
0409     if (ret < 0) {
0410         dev_err(&pdev->dev, "callback reg failed\n");
0411         goto error_iio_unreg;
0412     }
0413 
0414     return ret;
0415 
0416 error_iio_unreg:
0417     iio_device_unregister(indio_dev);
0418 error_remove_trigger:
0419     hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes);
0420     return ret;
0421 }
0422 
0423 /* Function to deinitialize the processing for usage id */
0424 static int hid_accel_3d_remove(struct platform_device *pdev)
0425 {
0426     struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
0427     struct iio_dev *indio_dev = platform_get_drvdata(pdev);
0428     struct accel_3d_state *accel_state = iio_priv(indio_dev);
0429 
0430     sensor_hub_remove_callback(hsdev, hsdev->usage);
0431     iio_device_unregister(indio_dev);
0432     hid_sensor_remove_trigger(indio_dev, &accel_state->common_attributes);
0433 
0434     return 0;
0435 }
0436 
0437 static const struct platform_device_id hid_accel_3d_ids[] = {
0438     {
0439         /* Format: HID-SENSOR-usage_id_in_hex_lowercase */
0440         .name = "HID-SENSOR-200073",
0441     },
0442     {   /* gravity sensor */
0443         .name = "HID-SENSOR-20007b",
0444     },
0445     { /* sentinel */ }
0446 };
0447 MODULE_DEVICE_TABLE(platform, hid_accel_3d_ids);
0448 
0449 static struct platform_driver hid_accel_3d_platform_driver = {
0450     .id_table = hid_accel_3d_ids,
0451     .driver = {
0452         .name   = KBUILD_MODNAME,
0453         .pm = &hid_sensor_pm_ops,
0454     },
0455     .probe      = hid_accel_3d_probe,
0456     .remove     = hid_accel_3d_remove,
0457 };
0458 module_platform_driver(hid_accel_3d_platform_driver);
0459 
0460 MODULE_DESCRIPTION("HID Sensor Accel 3D");
0461 MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
0462 MODULE_LICENSE("GPL");
0463 MODULE_IMPORT_NS(IIO_HID);