diff options
Diffstat (limited to 'drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c')
-rw-r--r-- | drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c new file mode 100644 index 000000000..f9a8c02d5 --- /dev/null +++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AMD SFH Report Descriptor generator + * Copyright 2020-2021 Advanced Micro Devices, Inc. + * Authors: Nehal Bakulchandra Shah <Nehal-Bakulchandra.Shah@amd.com> + * Sandeep Singh <sandeep.singh@amd.com> + * Basavaraj Natikar <Basavaraj.Natikar@amd.com> + */ + +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/slab.h> +#include "amd_sfh_pcie.h" +#include "amd_sfh_hid_desc.h" +#include "amd_sfh_hid_report_desc.h" +#include "amd_sfh_hid.h" + +#define AMD_SFH_FW_MULTIPLIER (1000) +#define HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM 0x41 +#define HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM 0x51 +#define HID_DEFAULT_REPORT_INTERVAL 0x50 +#define HID_DEFAULT_MIN_VALUE 0X7F +#define HID_DEFAULT_MAX_VALUE 0x80 +#define HID_DEFAULT_SENSITIVITY 0x7F +#define HID_USAGE_SENSOR_PROPERTY_CONNECTION_TYPE_PC_INTEGRATED_ENUM 0x01 +/* state enums */ +#define HID_USAGE_SENSOR_STATE_READY_ENUM 0x02 +#define HID_USAGE_SENSOR_STATE_INITIALIZING_ENUM 0x05 +#define HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM 0x04 +#define ILLUMINANCE_MASK GENMASK(14, 0) + +static int get_report_descriptor(int sensor_idx, u8 *rep_desc) +{ + switch (sensor_idx) { + case accel_idx: /* accel */ + memset(rep_desc, 0, sizeof(accel3_report_descriptor)); + memcpy(rep_desc, accel3_report_descriptor, + sizeof(accel3_report_descriptor)); + break; + case gyro_idx: /* gyro */ + memset(rep_desc, 0, sizeof(gyro3_report_descriptor)); + memcpy(rep_desc, gyro3_report_descriptor, + sizeof(gyro3_report_descriptor)); + break; + case mag_idx: /* Magnetometer */ + memset(rep_desc, 0, sizeof(comp3_report_descriptor)); + memcpy(rep_desc, comp3_report_descriptor, + sizeof(comp3_report_descriptor)); + break; + case als_idx: /* ambient light sensor */ + memset(rep_desc, 0, sizeof(als_report_descriptor)); + memcpy(rep_desc, als_report_descriptor, + sizeof(als_report_descriptor)); + break; + case HPD_IDX: /* HPD sensor */ + memset(rep_desc, 0, sizeof(hpd_report_descriptor)); + memcpy(rep_desc, hpd_report_descriptor, + sizeof(hpd_report_descriptor)); + break; + default: + break; + } + return 0; +} + +static u32 get_descr_sz(int sensor_idx, int descriptor_name) +{ + switch (sensor_idx) { + case accel_idx: + switch (descriptor_name) { + case descr_size: + return sizeof(accel3_report_descriptor); + case input_size: + return sizeof(struct accel3_input_report); + case feature_size: + return sizeof(struct accel3_feature_report); + } + break; + case gyro_idx: + switch (descriptor_name) { + case descr_size: + return sizeof(gyro3_report_descriptor); + case input_size: + return sizeof(struct gyro_input_report); + case feature_size: + return sizeof(struct gyro_feature_report); + } + break; + case mag_idx: + switch (descriptor_name) { + case descr_size: + return sizeof(comp3_report_descriptor); + case input_size: + return sizeof(struct magno_input_report); + case feature_size: + return sizeof(struct magno_feature_report); + } + break; + case als_idx: + switch (descriptor_name) { + case descr_size: + return sizeof(als_report_descriptor); + case input_size: + return sizeof(struct als_input_report); + case feature_size: + return sizeof(struct als_feature_report); + } + break; + case HPD_IDX: + switch (descriptor_name) { + case descr_size: + return sizeof(hpd_report_descriptor); + case input_size: + return sizeof(struct hpd_input_report); + case feature_size: + return sizeof(struct hpd_feature_report); + } + break; + + default: + break; + } + return 0; +} + +static void get_common_features(struct common_feature_property *common, int report_id) +{ + common->report_id = report_id; + common->connection_type = HID_USAGE_SENSOR_PROPERTY_CONNECTION_TYPE_PC_INTEGRATED_ENUM; + common->report_state = HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM; + common->power_state = HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM; + common->sensor_state = HID_USAGE_SENSOR_STATE_INITIALIZING_ENUM; + common->report_interval = HID_DEFAULT_REPORT_INTERVAL; +} + +static u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report) +{ + struct accel3_feature_report acc_feature; + struct gyro_feature_report gyro_feature; + struct magno_feature_report magno_feature; + struct hpd_feature_report hpd_feature; + struct als_feature_report als_feature; + u8 report_size = 0; + + if (!feature_report) + return report_size; + + switch (sensor_idx) { + case accel_idx: /* accel */ + get_common_features(&acc_feature.common_property, report_id); + acc_feature.accel_change_sesnitivity = HID_DEFAULT_SENSITIVITY; + acc_feature.accel_sensitivity_min = HID_DEFAULT_MIN_VALUE; + acc_feature.accel_sensitivity_max = HID_DEFAULT_MAX_VALUE; + memcpy(feature_report, &acc_feature, sizeof(acc_feature)); + report_size = sizeof(acc_feature); + break; + case gyro_idx: /* gyro */ + get_common_features(&gyro_feature.common_property, report_id); + gyro_feature.gyro_change_sesnitivity = HID_DEFAULT_SENSITIVITY; + gyro_feature.gyro_sensitivity_min = HID_DEFAULT_MIN_VALUE; + gyro_feature.gyro_sensitivity_max = HID_DEFAULT_MAX_VALUE; + memcpy(feature_report, &gyro_feature, sizeof(gyro_feature)); + report_size = sizeof(gyro_feature); + break; + case mag_idx: /* Magnetometer */ + get_common_features(&magno_feature.common_property, report_id); + magno_feature.magno_headingchange_sensitivity = HID_DEFAULT_SENSITIVITY; + magno_feature.heading_min = HID_DEFAULT_MIN_VALUE; + magno_feature.heading_max = HID_DEFAULT_MAX_VALUE; + magno_feature.flux_change_sensitivity = HID_DEFAULT_MIN_VALUE; + magno_feature.flux_min = HID_DEFAULT_MIN_VALUE; + magno_feature.flux_max = HID_DEFAULT_MAX_VALUE; + memcpy(feature_report, &magno_feature, sizeof(magno_feature)); + report_size = sizeof(magno_feature); + break; + case als_idx: /* ambient light sensor */ + get_common_features(&als_feature.common_property, report_id); + als_feature.als_change_sesnitivity = HID_DEFAULT_SENSITIVITY; + als_feature.als_sensitivity_min = HID_DEFAULT_MIN_VALUE; + als_feature.als_sensitivity_max = HID_DEFAULT_MAX_VALUE; + memcpy(feature_report, &als_feature, sizeof(als_feature)); + report_size = sizeof(als_feature); + break; + case HPD_IDX: /* human presence detection sensor */ + get_common_features(&hpd_feature.common_property, report_id); + memcpy(feature_report, &hpd_feature, sizeof(hpd_feature)); + report_size = sizeof(hpd_feature); + break; + + default: + break; + } + return report_size; +} + +static void get_common_inputs(struct common_input_property *common, int report_id) +{ + common->report_id = report_id; + common->sensor_state = HID_USAGE_SENSOR_STATE_READY_ENUM; + common->event_type = HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM; +} + +static u8 get_input_report(u8 current_index, int sensor_idx, int report_id, + struct amd_input_data *in_data) +{ + struct amd_mp2_dev *privdata = container_of(in_data, struct amd_mp2_dev, in_data); + u32 *sensor_virt_addr = in_data->sensor_virt_addr[current_index]; + u8 *input_report = in_data->input_report[current_index]; + u8 supported_input = privdata->mp2_acs & GENMASK(3, 0); + struct magno_input_report magno_input; + struct accel3_input_report acc_input; + struct gyro_input_report gyro_input; + struct hpd_input_report hpd_input; + struct als_input_report als_input; + struct hpd_status hpdstatus; + u8 report_size = 0; + + if (!sensor_virt_addr || !input_report) + return report_size; + + switch (sensor_idx) { + case accel_idx: /* accel */ + get_common_inputs(&acc_input.common_property, report_id); + acc_input.in_accel_x_value = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER; + acc_input.in_accel_y_value = (int)sensor_virt_addr[1] / AMD_SFH_FW_MULTIPLIER; + acc_input.in_accel_z_value = (int)sensor_virt_addr[2] / AMD_SFH_FW_MULTIPLIER; + memcpy(input_report, &acc_input, sizeof(acc_input)); + report_size = sizeof(acc_input); + break; + case gyro_idx: /* gyro */ + get_common_inputs(&gyro_input.common_property, report_id); + gyro_input.in_angel_x_value = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER; + gyro_input.in_angel_y_value = (int)sensor_virt_addr[1] / AMD_SFH_FW_MULTIPLIER; + gyro_input.in_angel_z_value = (int)sensor_virt_addr[2] / AMD_SFH_FW_MULTIPLIER; + memcpy(input_report, &gyro_input, sizeof(gyro_input)); + report_size = sizeof(gyro_input); + break; + case mag_idx: /* Magnetometer */ + get_common_inputs(&magno_input.common_property, report_id); + magno_input.in_magno_x = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER; + magno_input.in_magno_y = (int)sensor_virt_addr[1] / AMD_SFH_FW_MULTIPLIER; + magno_input.in_magno_z = (int)sensor_virt_addr[2] / AMD_SFH_FW_MULTIPLIER; + magno_input.in_magno_accuracy = (u16)sensor_virt_addr[3] / AMD_SFH_FW_MULTIPLIER; + memcpy(input_report, &magno_input, sizeof(magno_input)); + report_size = sizeof(magno_input); + break; + case als_idx: /* Als */ + get_common_inputs(&als_input.common_property, report_id); + /* For ALS ,V2 Platforms uses C2P_MSG5 register instead of DRAM access method */ + if (supported_input == V2_STATUS) + als_input.illuminance_value = + readl(privdata->mmio + AMD_C2P_MSG(5)) & ILLUMINANCE_MASK; + else + als_input.illuminance_value = + (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER; + report_size = sizeof(als_input); + memcpy(input_report, &als_input, sizeof(als_input)); + break; + case HPD_IDX: /* hpd */ + get_common_inputs(&hpd_input.common_property, report_id); + hpdstatus.val = readl(privdata->mmio + AMD_C2P_MSG(4)); + hpd_input.human_presence = hpdstatus.shpd.human_presence_actual; + report_size = sizeof(hpd_input); + memcpy(input_report, &hpd_input, sizeof(hpd_input)); + break; + default: + break; + } + return report_size; +} + +void amd_sfh_set_desc_ops(struct amd_mp2_ops *mp2_ops) +{ + mp2_ops->get_rep_desc = get_report_descriptor; + mp2_ops->get_feat_rep = get_feature_report; + mp2_ops->get_in_rep = get_input_report; + mp2_ops->get_desc_sz = get_descr_sz; +} |