diff options
Diffstat (limited to 'drivers/iio/gyro/hid-sensor-gyro-3d.c')
| -rw-r--r-- | drivers/iio/gyro/hid-sensor-gyro-3d.c | 206 |
1 files changed, 99 insertions, 107 deletions
diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c index bc943dd47da5..c43990c518f7 100644 --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -1,39 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HID Sensors Driver * Copyright (c) 2012, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * */ #include <linux/device.h> #include <linux/platform_device.h> #include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/irq.h> +#include <linux/mod_devicetable.h> #include <linux/slab.h> #include <linux/hid-sensor-hub.h> #include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> #include <linux/iio/buffer.h> -#include <linux/iio/trigger_consumer.h> -#include <linux/iio/triggered_buffer.h> #include "../common/hid-sensors/hid-sensor-trigger.h" -/*Format: HID-SENSOR-usage_id_in_hex*/ -/*Usage ID from spec for Gyro-3D: 0x200076*/ -#define DRIVER_NAME "HID-SENSOR-200076" - enum gyro_3d_channel { CHANNEL_SCAN_INDEX_X, CHANNEL_SCAN_INDEX_Y, @@ -41,11 +20,20 @@ enum gyro_3d_channel { GYRO_3D_CHANNEL_MAX, }; +#define CHANNEL_SCAN_INDEX_TIMESTAMP GYRO_3D_CHANNEL_MAX struct gyro_3d_state { struct hid_sensor_hub_callbacks callbacks; struct hid_sensor_common common_attributes; struct hid_sensor_hub_attribute_info gyro[GYRO_3D_CHANNEL_MAX]; - u32 gyro_val[GYRO_3D_CHANNEL_MAX]; + struct { + u32 gyro_val[GYRO_3D_CHANNEL_MAX]; + aligned_s64 timestamp; + } scan; + int scale_pre_decml; + int scale_post_decml; + int scale_precision; + int value_offset; + s64 timestamp; }; static const u32 gyro_3d_addresses[GYRO_3D_CHANNEL_MAX] = { @@ -54,12 +42,17 @@ static const u32 gyro_3d_addresses[GYRO_3D_CHANNEL_MAX] = { HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS }; +static const u32 gryo_3d_sensitivity_addresses[] = { + HID_USAGE_SENSOR_DATA_ANGL_VELOCITY, +}; + /* Channel definitions */ static const struct iio_chan_spec gyro_3d_channels[] = { { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_X, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | @@ -69,6 +62,7 @@ static const struct iio_chan_spec gyro_3d_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_Y, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | @@ -78,12 +72,14 @@ static const struct iio_chan_spec gyro_3d_channels[] = { .type = IIO_ANGL_VEL, .modified = 1, .channel2 = IIO_MOD_Z, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_HYSTERESIS), .scan_index = CHANNEL_SCAN_INDEX_Z, - } + }, + IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP) }; /* Adjust channel real bits based on report descriptor */ @@ -106,44 +102,49 @@ static int gyro_3d_read_raw(struct iio_dev *indio_dev, struct gyro_3d_state *gyro_state = iio_priv(indio_dev); int report_id = -1; u32 address; - int ret; int ret_type; + s32 min; *val = 0; *val2 = 0; switch (mask) { - case 0: + case IIO_CHAN_INFO_RAW: + hid_sensor_power_state(&gyro_state->common_attributes, true); report_id = gyro_state->gyro[chan->scan_index].report_id; + min = gyro_state->gyro[chan->scan_index].logical_minimum; address = gyro_3d_addresses[chan->scan_index]; if (report_id >= 0) *val = sensor_hub_input_attr_get_raw_value( - gyro_state->common_attributes.hsdev, - HID_USAGE_SENSOR_GYRO_3D, address, - report_id); + gyro_state->common_attributes.hsdev, + HID_USAGE_SENSOR_GYRO_3D, address, + report_id, + SENSOR_HUB_SYNC, + min < 0); else { *val = 0; + hid_sensor_power_state(&gyro_state->common_attributes, + false); return -EINVAL; } + hid_sensor_power_state(&gyro_state->common_attributes, false); ret_type = IIO_VAL_INT; break; case IIO_CHAN_INFO_SCALE: - *val = gyro_state->gyro[CHANNEL_SCAN_INDEX_X].units; - ret_type = IIO_VAL_INT; + *val = gyro_state->scale_pre_decml; + *val2 = gyro_state->scale_post_decml; + ret_type = gyro_state->scale_precision; break; case IIO_CHAN_INFO_OFFSET: - *val = hid_sensor_convert_exponent( - gyro_state->gyro[CHANNEL_SCAN_INDEX_X].unit_expo); + *val = gyro_state->value_offset; ret_type = IIO_VAL_INT; break; case IIO_CHAN_INFO_SAMP_FREQ: - ret = hid_sensor_read_samp_freq_value( + ret_type = hid_sensor_read_samp_freq_value( &gyro_state->common_attributes, val, val2); - ret_type = IIO_VAL_INT_PLUS_MICRO; break; case IIO_CHAN_INFO_HYSTERESIS: - ret = hid_sensor_read_raw_hyst_value( + ret_type = hid_sensor_read_raw_hyst_value( &gyro_state->common_attributes, val, val2); - ret_type = IIO_VAL_INT_PLUS_MICRO; break; default: ret_type = -EINVAL; @@ -179,27 +180,11 @@ static int gyro_3d_write_raw(struct iio_dev *indio_dev, return ret; } -static int gyro_3d_write_raw_get_fmt(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - long mask) -{ - return IIO_VAL_INT_PLUS_MICRO; -} - static const struct iio_info gyro_3d_info = { - .driver_module = THIS_MODULE, .read_raw = &gyro_3d_read_raw, .write_raw = &gyro_3d_write_raw, - .write_raw_get_fmt = &gyro_3d_write_raw_get_fmt, }; -/* Function to push data to buffer */ -static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len) -{ - dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); - iio_push_to_buffers(indio_dev, (u8 *)data); -} - /* Callback handler to send event after all samples are received and captured */ static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev, unsigned usage_id, @@ -208,12 +193,16 @@ static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev, struct iio_dev *indio_dev = platform_get_drvdata(priv); struct gyro_3d_state *gyro_state = iio_priv(indio_dev); - dev_dbg(&indio_dev->dev, "gyro_3d_proc_event [%d]\n", - gyro_state->common_attributes.data_ready); - if (gyro_state->common_attributes.data_ready) - hid_sensor_push_data(indio_dev, - (u8 *)gyro_state->gyro_val, - sizeof(gyro_state->gyro_val)); + dev_dbg(&indio_dev->dev, "gyro_3d_proc_event\n"); + if (atomic_read(&gyro_state->common_attributes.data_ready)) { + if (!gyro_state->timestamp) + gyro_state->timestamp = iio_get_time_ns(indio_dev); + + iio_push_to_buffers_with_timestamp(indio_dev, &gyro_state->scan, + gyro_state->timestamp); + + gyro_state->timestamp = 0; + } return 0; } @@ -234,8 +223,14 @@ static int gyro_3d_capture_sample(struct hid_sensor_hub_device *hsdev, case HID_USAGE_SENSOR_ANGL_VELOCITY_Y_AXIS: case HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS: offset = usage_id - HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS; - gyro_state->gyro_val[CHANNEL_SCAN_INDEX_X + offset] = - *(u32 *)raw_data; + gyro_state->scan.gyro_val[CHANNEL_SCAN_INDEX_X + offset] = + *(u32 *)raw_data; + ret = 0; + break; + case HID_USAGE_SENSOR_TIME_TIMESTAMP: + gyro_state->timestamp = + hid_sensor_convert_timestamp(&gyro_state->common_attributes, + *(s64 *)raw_data); ret = 0; break; default: @@ -273,24 +268,26 @@ static int gyro_3d_parse_report(struct platform_device *pdev, st->gyro[1].index, st->gyro[1].report_id, st->gyro[2].index, st->gyro[2].report_id); + st->scale_precision = hid_sensor_format_scale( + HID_USAGE_SENSOR_GYRO_3D, + &st->gyro[CHANNEL_SCAN_INDEX_X], + &st->scale_pre_decml, &st->scale_post_decml); + return ret; } /* Function to initialize the processing for usage id */ static int hid_gyro_3d_probe(struct platform_device *pdev) { + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); int ret = 0; static const char *name = "gyro_3d"; struct iio_dev *indio_dev; struct gyro_3d_state *gyro_state; - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; - struct iio_chan_spec *channels; - indio_dev = iio_device_alloc(sizeof(struct gyro_3d_state)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*gyro_state)); + if (!indio_dev) + return -ENOMEM; platform_set_drvdata(pdev, indio_dev); gyro_state = iio_priv(indio_dev); @@ -299,46 +296,41 @@ static int hid_gyro_3d_probe(struct platform_device *pdev) ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_GYRO_3D, - &gyro_state->common_attributes); + &gyro_state->common_attributes, + gryo_3d_sensitivity_addresses, + ARRAY_SIZE(gryo_3d_sensitivity_addresses)); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); - goto error_free_dev; + return ret; } - channels = kmemdup(gyro_3d_channels, sizeof(gyro_3d_channels), - GFP_KERNEL); - if (!channels) { - ret = -ENOMEM; + indio_dev->channels = devm_kmemdup(&pdev->dev, gyro_3d_channels, + sizeof(gyro_3d_channels), GFP_KERNEL); + if (!indio_dev->channels) { dev_err(&pdev->dev, "failed to duplicate channels\n"); - goto error_free_dev; + return -ENOMEM; } - ret = gyro_3d_parse_report(pdev, hsdev, channels, - HID_USAGE_SENSOR_GYRO_3D, gyro_state); + ret = gyro_3d_parse_report(pdev, hsdev, + (struct iio_chan_spec *)indio_dev->channels, + HID_USAGE_SENSOR_GYRO_3D, gyro_state); if (ret) { dev_err(&pdev->dev, "failed to setup attributes\n"); - goto error_free_dev_mem; + return ret; } - indio_dev->channels = channels; indio_dev->num_channels = ARRAY_SIZE(gyro_3d_channels); - indio_dev->dev.parent = &pdev->dev; indio_dev->info = &gyro_3d_info; indio_dev->name = name; indio_dev->modes = INDIO_DIRECT_MODE; - ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, - NULL, NULL); - if (ret) { - dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); - goto error_free_dev_mem; - } - gyro_state->common_attributes.data_ready = false; + atomic_set(&gyro_state->common_attributes.data_ready, 0); + ret = hid_sensor_setup_trigger(indio_dev, name, &gyro_state->common_attributes); if (ret < 0) { dev_err(&pdev->dev, "trigger setup failed\n"); - goto error_unreg_buffer_funcs; + return ret; } ret = iio_device_register(indio_dev); @@ -362,37 +354,36 @@ static int hid_gyro_3d_probe(struct platform_device *pdev) error_iio_unreg: iio_device_unregister(indio_dev); error_remove_trigger: - hid_sensor_remove_trigger(indio_dev); -error_unreg_buffer_funcs: - iio_triggered_buffer_cleanup(indio_dev); -error_free_dev_mem: - kfree(indio_dev->channels); -error_free_dev: - iio_device_free(indio_dev); -error_ret: + hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes); return ret; } /* Function to deinitialize the processing for usage id */ -static int hid_gyro_3d_remove(struct platform_device *pdev) +static void hid_gyro_3d_remove(struct platform_device *pdev) { - struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct gyro_3d_state *gyro_state = iio_priv(indio_dev); sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D); iio_device_unregister(indio_dev); - hid_sensor_remove_trigger(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - kfree(indio_dev->channels); - iio_device_free(indio_dev); - - return 0; + hid_sensor_remove_trigger(indio_dev, &gyro_state->common_attributes); } +static const struct platform_device_id hid_gyro_3d_ids[] = { + { + /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ + .name = "HID-SENSOR-200076", + }, + { } +}; +MODULE_DEVICE_TABLE(platform, hid_gyro_3d_ids); + static struct platform_driver hid_gyro_3d_platform_driver = { + .id_table = hid_gyro_3d_ids, .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, + .name = KBUILD_MODNAME, + .pm = &hid_sensor_pm_ops, }, .probe = hid_gyro_3d_probe, .remove = hid_gyro_3d_remove, @@ -402,3 +393,4 @@ module_platform_driver(hid_gyro_3d_platform_driver); MODULE_DESCRIPTION("HID Sensor Gyroscope 3D"); MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("IIO_HID"); |
