--- zzzz-none-000/linux-3.10.107/drivers/iio/magnetometer/hid-sensor-magn-3d.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/iio/magnetometer/hid-sensor-magn-3d.c 2021-02-04 17:41:59.000000000 +0000 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -30,14 +31,14 @@ #include #include "../common/hid-sensors/hid-sensor-trigger.h" -/*Format: HID-SENSOR-usage_id_in_hex*/ -/*Usage ID from spec for Magnetometer-3D: 0x200083*/ -#define DRIVER_NAME "HID-SENSOR-200083" - enum magn_3d_channel { CHANNEL_SCAN_INDEX_X, CHANNEL_SCAN_INDEX_Y, CHANNEL_SCAN_INDEX_Z, + CHANNEL_SCAN_INDEX_NORTH_MAGN_TILT_COMP, + CHANNEL_SCAN_INDEX_NORTH_TRUE_TILT_COMP, + CHANNEL_SCAN_INDEX_NORTH_MAGN, + CHANNEL_SCAN_INDEX_NORTH_TRUE, MAGN_3D_CHANNEL_MAX, }; @@ -45,13 +46,26 @@ struct hid_sensor_hub_callbacks callbacks; struct hid_sensor_common common_attributes; struct hid_sensor_hub_attribute_info magn[MAGN_3D_CHANNEL_MAX]; - u32 magn_val[MAGN_3D_CHANNEL_MAX]; + + /* dynamically sized array to hold sensor values */ + u32 *iio_vals; + /* array of pointers to sensor value */ + u32 *magn_val_addr[MAGN_3D_CHANNEL_MAX]; + + int scale_pre_decml; + int scale_post_decml; + int scale_precision; + int value_offset; }; static const u32 magn_3d_addresses[MAGN_3D_CHANNEL_MAX] = { HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS, HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS, - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS + HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS, + HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH, + HID_USAGE_SENSOR_ORIENT_COMP_TRUE_NORTH, + HID_USAGE_SENSOR_ORIENT_MAGN_NORTH, + HID_USAGE_SENSOR_ORIENT_TRUE_NORTH, }; /* Channel definitions */ @@ -60,29 +74,65 @@ .type = IIO_MAGN, .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) | BIT(IIO_CHAN_INFO_HYSTERESIS), - .scan_index = CHANNEL_SCAN_INDEX_X, }, { .type = IIO_MAGN, .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) | BIT(IIO_CHAN_INFO_HYSTERESIS), - .scan_index = CHANNEL_SCAN_INDEX_Y, }, { .type = IIO_MAGN, .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), + }, { + .type = IIO_ROT, + .modified = 1, + .channel2 = IIO_MOD_NORTH_MAGN_TILT_COMP, + .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), + }, { + .type = IIO_ROT, + .modified = 1, + .channel2 = IIO_MOD_NORTH_TRUE_TILT_COMP, + .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), + }, { + .type = IIO_ROT, + .modified = 1, + .channel2 = IIO_MOD_NORTH_MAGN, + .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), + }, { + .type = IIO_ROT, + .modified = 1, + .channel2 = IIO_MOD_NORTH_TRUE, + .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, } }; @@ -106,45 +156,47 @@ struct magn_3d_state *magn_state = iio_priv(indio_dev); int report_id = -1; u32 address; - int ret; int ret_type; *val = 0; *val2 = 0; switch (mask) { case 0: + hid_sensor_power_state(&magn_state->common_attributes, true); report_id = - magn_state->magn[chan->scan_index].report_id; - address = magn_3d_addresses[chan->scan_index]; + magn_state->magn[chan->address].report_id; + address = magn_3d_addresses[chan->address]; if (report_id >= 0) *val = sensor_hub_input_attr_get_raw_value( magn_state->common_attributes.hsdev, HID_USAGE_SENSOR_COMPASS_3D, address, - report_id); + report_id, + SENSOR_HUB_SYNC); else { *val = 0; + hid_sensor_power_state(&magn_state->common_attributes, + false); return -EINVAL; } + hid_sensor_power_state(&magn_state->common_attributes, false); ret_type = IIO_VAL_INT; break; case IIO_CHAN_INFO_SCALE: - *val = magn_state->magn[CHANNEL_SCAN_INDEX_X].units; - ret_type = IIO_VAL_INT; + *val = magn_state->scale_pre_decml; + *val2 = magn_state->scale_post_decml; + ret_type = magn_state->scale_precision; break; case IIO_CHAN_INFO_OFFSET: - *val = hid_sensor_convert_exponent( - magn_state->magn[CHANNEL_SCAN_INDEX_X].unit_expo); + *val = magn_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( &magn_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( &magn_state->common_attributes, val, val2); - ret_type = IIO_VAL_INT_PLUS_MICRO; break; default: ret_type = -EINVAL; @@ -180,25 +232,17 @@ return ret; } -static int magn_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 magn_3d_info = { .driver_module = THIS_MODULE, .read_raw = &magn_3d_read_raw, .write_raw = &magn_3d_write_raw, - .write_raw_get_fmt = &magn_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) +static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data) { dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); - iio_push_to_buffers(indio_dev, (u8 *)data); + iio_push_to_buffers(indio_dev, data); } /* Callback handler to send event after all samples are received and captured */ @@ -209,12 +253,9 @@ struct iio_dev *indio_dev = platform_get_drvdata(priv); struct magn_3d_state *magn_state = iio_priv(indio_dev); - dev_dbg(&indio_dev->dev, "magn_3d_proc_event [%d]\n", - magn_state->common_attributes.data_ready); - if (magn_state->common_attributes.data_ready) - hid_sensor_push_data(indio_dev, - (u8 *)magn_state->magn_val, - sizeof(magn_state->magn_val)); + dev_dbg(&indio_dev->dev, "magn_3d_proc_event\n"); + if (atomic_read(&magn_state->common_attributes.data_ready)) + hid_sensor_push_data(indio_dev, magn_state->iio_vals); return 0; } @@ -228,53 +269,144 @@ struct iio_dev *indio_dev = platform_get_drvdata(priv); struct magn_3d_state *magn_state = iio_priv(indio_dev); int offset; - int ret = -EINVAL; + int ret = 0; + u32 *iio_val = NULL; switch (usage_id) { case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS: case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS: case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS: - offset = usage_id - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS; - magn_state->magn_val[CHANNEL_SCAN_INDEX_X + offset] = - *(u32 *)raw_data; - ret = 0; + offset = (usage_id - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS) + + CHANNEL_SCAN_INDEX_X; + break; + case HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH: + case HID_USAGE_SENSOR_ORIENT_COMP_TRUE_NORTH: + case HID_USAGE_SENSOR_ORIENT_MAGN_NORTH: + case HID_USAGE_SENSOR_ORIENT_TRUE_NORTH: + offset = (usage_id - HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH) + + CHANNEL_SCAN_INDEX_NORTH_MAGN_TILT_COMP; break; default: - break; + return -EINVAL; } + iio_val = magn_state->magn_val_addr[offset]; + + if (iio_val != NULL) + *iio_val = *((u32 *)raw_data); + else + ret = -EINVAL; + return ret; } /* Parse report which is specific to an usage id*/ static int magn_3d_parse_report(struct platform_device *pdev, struct hid_sensor_hub_device *hsdev, - struct iio_chan_spec *channels, + struct iio_chan_spec **channels, + int *chan_count, unsigned usage_id, struct magn_3d_state *st) { - int ret; int i; + int attr_count = 0; + struct iio_chan_spec *_channels; - for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) { - ret = sensor_hub_input_get_attribute_info(hsdev, - HID_INPUT_REPORT, - usage_id, - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS + i, - &st->magn[CHANNEL_SCAN_INDEX_X + i]); - if (ret < 0) - break; - magn_3d_adjust_channel_bit_mask(channels, - CHANNEL_SCAN_INDEX_X + i, - st->magn[CHANNEL_SCAN_INDEX_X + i].size); - } - dev_dbg(&pdev->dev, "magn_3d %x:%x, %x:%x, %x:%x\n", + /* Scan for each usage attribute supported */ + for (i = 0; i < MAGN_3D_CHANNEL_MAX; i++) { + int status; + u32 address = magn_3d_addresses[i]; + + /* Check if usage attribute exists in the sensor hub device */ + status = sensor_hub_input_get_attribute_info(hsdev, + HID_INPUT_REPORT, + usage_id, + address, + &(st->magn[i])); + if (!status) + attr_count++; + } + + if (attr_count <= 0) { + dev_err(&pdev->dev, + "failed to find any supported usage attributes in report\n"); + return -EINVAL; + } + + dev_dbg(&pdev->dev, "magn_3d Found %d usage attributes\n", + attr_count); + dev_dbg(&pdev->dev, "magn_3d X: %x:%x Y: %x:%x Z: %x:%x\n", st->magn[0].index, st->magn[0].report_id, st->magn[1].index, st->magn[1].report_id, st->magn[2].index, st->magn[2].report_id); - return ret; + /* Setup IIO channel array */ + _channels = devm_kcalloc(&pdev->dev, attr_count, + sizeof(struct iio_chan_spec), + GFP_KERNEL); + if (!_channels) { + dev_err(&pdev->dev, + "failed to allocate space for iio channels\n"); + return -ENOMEM; + } + + st->iio_vals = devm_kcalloc(&pdev->dev, attr_count, + sizeof(u32), + GFP_KERNEL); + if (!st->iio_vals) { + dev_err(&pdev->dev, + "failed to allocate space for iio values array\n"); + return -ENOMEM; + } + + for (i = 0, *chan_count = 0; + i < MAGN_3D_CHANNEL_MAX && *chan_count < attr_count; + i++){ + if (st->magn[i].index >= 0) { + /* Setup IIO channel struct */ + (_channels[*chan_count]) = magn_3d_channels[i]; + (_channels[*chan_count]).scan_index = *chan_count; + (_channels[*chan_count]).address = i; + + /* Set magn_val_addr to iio value address */ + st->magn_val_addr[i] = &(st->iio_vals[*chan_count]); + magn_3d_adjust_channel_bit_mask(_channels, + *chan_count, + st->magn[i].size); + (*chan_count)++; + } + } + + if (*chan_count <= 0) { + dev_err(&pdev->dev, + "failed to find any magnetic channels setup\n"); + return -EINVAL; + } + + *channels = _channels; + + dev_dbg(&pdev->dev, "magn_3d Setup %d IIO channels\n", + *chan_count); + + st->scale_precision = hid_sensor_format_scale( + HID_USAGE_SENSOR_COMPASS_3D, + &st->magn[CHANNEL_SCAN_INDEX_X], + &st->scale_pre_decml, &st->scale_post_decml); + + /* Set Sensitivity field ids, when there is no individual modifier */ + if (st->common_attributes.sensitivity.index < 0) { + sensor_hub_input_get_attribute_info(hsdev, + HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | + HID_USAGE_SENSOR_DATA_ORIENTATION, + &st->common_attributes.sensitivity); + dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", + st->common_attributes.sensitivity.index, + st->common_attributes.sensitivity.report_id); + } + + return 0; } /* Function to initialize the processing for usage id */ @@ -286,12 +418,13 @@ struct magn_3d_state *magn_state; struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_chan_spec *channels; + int chan_count = 0; + + indio_dev = devm_iio_device_alloc(&pdev->dev, + sizeof(struct magn_3d_state)); + if (indio_dev == NULL) + return -ENOMEM; - indio_dev = iio_device_alloc(sizeof(struct magn_3d_state)); - if (indio_dev == NULL) { - ret = -ENOMEM; - goto error_ret; - } platform_set_drvdata(pdev, indio_dev); magn_state = iio_priv(indio_dev); @@ -303,26 +436,19 @@ &magn_state->common_attributes); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); - goto error_free_dev; + return ret; } - channels = kmemdup(magn_3d_channels, sizeof(magn_3d_channels), - GFP_KERNEL); - if (!channels) { - ret = -ENOMEM; - dev_err(&pdev->dev, "failed to duplicate channels\n"); - goto error_free_dev; - } - - ret = magn_3d_parse_report(pdev, hsdev, channels, + ret = magn_3d_parse_report(pdev, hsdev, + &channels, &chan_count, HID_USAGE_SENSOR_COMPASS_3D, magn_state); if (ret) { - dev_err(&pdev->dev, "failed to setup attributes\n"); - goto error_free_dev_mem; + dev_err(&pdev->dev, "failed to parse report\n"); + return ret; } indio_dev->channels = channels; - indio_dev->num_channels = ARRAY_SIZE(magn_3d_channels); + indio_dev->num_channels = chan_count; indio_dev->dev.parent = &pdev->dev; indio_dev->info = &magn_3d_info; indio_dev->name = name; @@ -332,9 +458,9 @@ NULL, NULL); if (ret) { dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); - goto error_free_dev_mem; + return ret; } - magn_state->common_attributes.data_ready = false; + atomic_set(&magn_state->common_attributes.data_ready, 0); ret = hid_sensor_setup_trigger(indio_dev, name, &magn_state->common_attributes); if (ret < 0) { @@ -363,14 +489,9 @@ error_iio_unreg: iio_device_unregister(indio_dev); error_remove_trigger: - hid_sensor_remove_trigger(indio_dev); + hid_sensor_remove_trigger(&magn_state->common_attributes); 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: return ret; } @@ -379,21 +500,30 @@ { struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct magn_3d_state *magn_state = iio_priv(indio_dev); sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D); iio_device_unregister(indio_dev); - hid_sensor_remove_trigger(indio_dev); + hid_sensor_remove_trigger(&magn_state->common_attributes); iio_triggered_buffer_cleanup(indio_dev); - kfree(indio_dev->channels); - iio_device_free(indio_dev); return 0; } +static const struct platform_device_id hid_magn_3d_ids[] = { + { + /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ + .name = "HID-SENSOR-200083", + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, hid_magn_3d_ids); + static struct platform_driver hid_magn_3d_platform_driver = { + .id_table = hid_magn_3d_ids, .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, + .name = KBUILD_MODNAME, + .pm = &hid_sensor_pm_ops, }, .probe = hid_magn_3d_probe, .remove = hid_magn_3d_remove,