162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2011-2016 Synaptics Incorporated 462306a36Sopenharmony_ci * Copyright (c) 2011 Unixphere 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/device.h> 962306a36Sopenharmony_ci#include <linux/of.h> 1062306a36Sopenharmony_ci#include <linux/input.h> 1162306a36Sopenharmony_ci#include <linux/input/mt.h> 1262306a36Sopenharmony_ci#include <linux/rmi.h> 1362306a36Sopenharmony_ci#include "rmi_driver.h" 1462306a36Sopenharmony_ci#include "rmi_2d_sensor.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define RMI_2D_REL_POS_MIN -128 1762306a36Sopenharmony_ci#define RMI_2D_REL_POS_MAX 127 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* maximum ABS_MT_POSITION displacement (in mm) */ 2062306a36Sopenharmony_ci#define DMAX 10 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_civoid rmi_2d_sensor_abs_process(struct rmi_2d_sensor *sensor, 2362306a36Sopenharmony_ci struct rmi_2d_sensor_abs_object *obj, 2462306a36Sopenharmony_ci int slot) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci struct rmi_2d_axis_alignment *axis_align = &sensor->axis_align; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci /* we keep the previous values if the finger is released */ 2962306a36Sopenharmony_ci if (obj->type == RMI_2D_OBJECT_NONE) 3062306a36Sopenharmony_ci return; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci if (axis_align->flip_x) 3362306a36Sopenharmony_ci obj->x = sensor->max_x - obj->x; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci if (axis_align->flip_y) 3662306a36Sopenharmony_ci obj->y = sensor->max_y - obj->y; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci if (axis_align->swap_axes) 3962306a36Sopenharmony_ci swap(obj->x, obj->y); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci /* 4262306a36Sopenharmony_ci * Here checking if X offset or y offset are specified is 4362306a36Sopenharmony_ci * redundant. We just add the offsets or clip the values. 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * Note: offsets need to be applied before clipping occurs, 4662306a36Sopenharmony_ci * or we could get funny values that are outside of 4762306a36Sopenharmony_ci * clipping boundaries. 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_ci obj->x += axis_align->offset_x; 5062306a36Sopenharmony_ci obj->y += axis_align->offset_y; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci obj->x = max(axis_align->clip_x_low, obj->x); 5362306a36Sopenharmony_ci obj->y = max(axis_align->clip_y_low, obj->y); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (axis_align->clip_x_high) 5662306a36Sopenharmony_ci obj->x = min(sensor->max_x, obj->x); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci if (axis_align->clip_y_high) 5962306a36Sopenharmony_ci obj->y = min(sensor->max_y, obj->y); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci sensor->tracking_pos[slot].x = obj->x; 6262306a36Sopenharmony_ci sensor->tracking_pos[slot].y = obj->y; 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rmi_2d_sensor_abs_process); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_civoid rmi_2d_sensor_abs_report(struct rmi_2d_sensor *sensor, 6762306a36Sopenharmony_ci struct rmi_2d_sensor_abs_object *obj, 6862306a36Sopenharmony_ci int slot) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci struct rmi_2d_axis_alignment *axis_align = &sensor->axis_align; 7162306a36Sopenharmony_ci struct input_dev *input = sensor->input; 7262306a36Sopenharmony_ci int wide, major, minor; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (sensor->kernel_tracking) 7562306a36Sopenharmony_ci input_mt_slot(input, sensor->tracking_slots[slot]); 7662306a36Sopenharmony_ci else 7762306a36Sopenharmony_ci input_mt_slot(input, slot); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci input_mt_report_slot_state(input, obj->mt_tool, 8062306a36Sopenharmony_ci obj->type != RMI_2D_OBJECT_NONE); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (obj->type != RMI_2D_OBJECT_NONE) { 8362306a36Sopenharmony_ci obj->x = sensor->tracking_pos[slot].x; 8462306a36Sopenharmony_ci obj->y = sensor->tracking_pos[slot].y; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (axis_align->swap_axes) 8762306a36Sopenharmony_ci swap(obj->wx, obj->wy); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci wide = (obj->wx > obj->wy); 9062306a36Sopenharmony_ci major = max(obj->wx, obj->wy); 9162306a36Sopenharmony_ci minor = min(obj->wx, obj->wy); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (obj->type == RMI_2D_OBJECT_STYLUS) { 9462306a36Sopenharmony_ci major = max(1, major); 9562306a36Sopenharmony_ci minor = max(1, minor); 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci input_event(sensor->input, EV_ABS, ABS_MT_POSITION_X, obj->x); 9962306a36Sopenharmony_ci input_event(sensor->input, EV_ABS, ABS_MT_POSITION_Y, obj->y); 10062306a36Sopenharmony_ci input_event(sensor->input, EV_ABS, ABS_MT_ORIENTATION, wide); 10162306a36Sopenharmony_ci input_event(sensor->input, EV_ABS, ABS_MT_PRESSURE, obj->z); 10262306a36Sopenharmony_ci input_event(sensor->input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); 10362306a36Sopenharmony_ci input_event(sensor->input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci rmi_dbg(RMI_DEBUG_2D_SENSOR, &sensor->input->dev, 10662306a36Sopenharmony_ci "%s: obj[%d]: type: 0x%02x X: %d Y: %d Z: %d WX: %d WY: %d\n", 10762306a36Sopenharmony_ci __func__, slot, obj->type, obj->x, obj->y, obj->z, 10862306a36Sopenharmony_ci obj->wx, obj->wy); 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rmi_2d_sensor_abs_report); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_civoid rmi_2d_sensor_rel_report(struct rmi_2d_sensor *sensor, int x, int y) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct rmi_2d_axis_alignment *axis_align = &sensor->axis_align; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci x = min(RMI_2D_REL_POS_MAX, max(RMI_2D_REL_POS_MIN, (int)x)); 11862306a36Sopenharmony_ci y = min(RMI_2D_REL_POS_MAX, max(RMI_2D_REL_POS_MIN, (int)y)); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (axis_align->flip_x) 12162306a36Sopenharmony_ci x = min(RMI_2D_REL_POS_MAX, -x); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (axis_align->flip_y) 12462306a36Sopenharmony_ci y = min(RMI_2D_REL_POS_MAX, -y); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (axis_align->swap_axes) 12762306a36Sopenharmony_ci swap(x, y); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci if (x || y) { 13062306a36Sopenharmony_ci input_report_rel(sensor->input, REL_X, x); 13162306a36Sopenharmony_ci input_report_rel(sensor->input, REL_Y, y); 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rmi_2d_sensor_rel_report); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic void rmi_2d_sensor_set_input_params(struct rmi_2d_sensor *sensor) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci struct input_dev *input = sensor->input; 13962306a36Sopenharmony_ci int res_x; 14062306a36Sopenharmony_ci int res_y; 14162306a36Sopenharmony_ci int max_x, max_y; 14262306a36Sopenharmony_ci int input_flags = 0; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (sensor->report_abs) { 14562306a36Sopenharmony_ci sensor->min_x = sensor->axis_align.clip_x_low; 14662306a36Sopenharmony_ci if (sensor->axis_align.clip_x_high) 14762306a36Sopenharmony_ci sensor->max_x = min(sensor->max_x, 14862306a36Sopenharmony_ci sensor->axis_align.clip_x_high); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci sensor->min_y = sensor->axis_align.clip_y_low; 15162306a36Sopenharmony_ci if (sensor->axis_align.clip_y_high) 15262306a36Sopenharmony_ci sensor->max_y = min(sensor->max_y, 15362306a36Sopenharmony_ci sensor->axis_align.clip_y_high); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci set_bit(EV_ABS, input->evbit); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci max_x = sensor->max_x; 15862306a36Sopenharmony_ci max_y = sensor->max_y; 15962306a36Sopenharmony_ci if (sensor->axis_align.swap_axes) 16062306a36Sopenharmony_ci swap(max_x, max_y); 16162306a36Sopenharmony_ci input_set_abs_params(input, ABS_MT_POSITION_X, 0, max_x, 0, 0); 16262306a36Sopenharmony_ci input_set_abs_params(input, ABS_MT_POSITION_Y, 0, max_y, 0, 0); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (sensor->x_mm && sensor->y_mm) { 16562306a36Sopenharmony_ci res_x = (sensor->max_x - sensor->min_x) / sensor->x_mm; 16662306a36Sopenharmony_ci res_y = (sensor->max_y - sensor->min_y) / sensor->y_mm; 16762306a36Sopenharmony_ci if (sensor->axis_align.swap_axes) 16862306a36Sopenharmony_ci swap(res_x, res_y); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci input_abs_set_res(input, ABS_X, res_x); 17162306a36Sopenharmony_ci input_abs_set_res(input, ABS_Y, res_y); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci input_abs_set_res(input, ABS_MT_POSITION_X, res_x); 17462306a36Sopenharmony_ci input_abs_set_res(input, ABS_MT_POSITION_Y, res_y); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci if (!sensor->dmax) 17762306a36Sopenharmony_ci sensor->dmax = DMAX * res_x; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xff, 0, 0); 18162306a36Sopenharmony_ci input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0); 18262306a36Sopenharmony_ci input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0); 18362306a36Sopenharmony_ci input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0); 18462306a36Sopenharmony_ci input_set_abs_params(input, ABS_MT_TOOL_TYPE, 18562306a36Sopenharmony_ci 0, MT_TOOL_MAX, 0, 0); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (sensor->sensor_type == rmi_sensor_touchpad) 18862306a36Sopenharmony_ci input_flags = INPUT_MT_POINTER; 18962306a36Sopenharmony_ci else 19062306a36Sopenharmony_ci input_flags = INPUT_MT_DIRECT; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (sensor->kernel_tracking) 19362306a36Sopenharmony_ci input_flags |= INPUT_MT_TRACK; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci input_mt_init_slots(input, sensor->nbr_fingers, input_flags); 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (sensor->report_rel) { 19962306a36Sopenharmony_ci set_bit(EV_REL, input->evbit); 20062306a36Sopenharmony_ci set_bit(REL_X, input->relbit); 20162306a36Sopenharmony_ci set_bit(REL_Y, input->relbit); 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (sensor->topbuttonpad) 20562306a36Sopenharmony_ci set_bit(INPUT_PROP_TOPBUTTONPAD, input->propbit); 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ciint rmi_2d_sensor_configure_input(struct rmi_function *fn, 20962306a36Sopenharmony_ci struct rmi_2d_sensor *sensor) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci struct rmi_device *rmi_dev = fn->rmi_dev; 21262306a36Sopenharmony_ci struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (!drv_data->input) 21562306a36Sopenharmony_ci return -ENODEV; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci sensor->input = drv_data->input; 21862306a36Sopenharmony_ci rmi_2d_sensor_set_input_params(sensor); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci return 0; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rmi_2d_sensor_configure_input); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci#ifdef CONFIG_OF 22562306a36Sopenharmony_ciint rmi_2d_sensor_of_probe(struct device *dev, 22662306a36Sopenharmony_ci struct rmi_2d_sensor_platform_data *pdata) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci int retval; 22962306a36Sopenharmony_ci u32 val; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci pdata->axis_align.swap_axes = of_property_read_bool(dev->of_node, 23262306a36Sopenharmony_ci "touchscreen-swapped-x-y"); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci pdata->axis_align.flip_x = of_property_read_bool(dev->of_node, 23562306a36Sopenharmony_ci "touchscreen-inverted-x"); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci pdata->axis_align.flip_y = of_property_read_bool(dev->of_node, 23862306a36Sopenharmony_ci "touchscreen-inverted-y"); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci retval = rmi_of_property_read_u32(dev, &val, "syna,clip-x-low", 1); 24162306a36Sopenharmony_ci if (retval) 24262306a36Sopenharmony_ci return retval; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci pdata->axis_align.clip_x_low = val; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci retval = rmi_of_property_read_u32(dev, &val, "syna,clip-y-low", 1); 24762306a36Sopenharmony_ci if (retval) 24862306a36Sopenharmony_ci return retval; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci pdata->axis_align.clip_y_low = val; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci retval = rmi_of_property_read_u32(dev, &val, "syna,clip-x-high", 1); 25362306a36Sopenharmony_ci if (retval) 25462306a36Sopenharmony_ci return retval; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci pdata->axis_align.clip_x_high = val; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci retval = rmi_of_property_read_u32(dev, &val, "syna,clip-y-high", 1); 25962306a36Sopenharmony_ci if (retval) 26062306a36Sopenharmony_ci return retval; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci pdata->axis_align.clip_y_high = val; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci retval = rmi_of_property_read_u32(dev, &val, "syna,offset-x", 1); 26562306a36Sopenharmony_ci if (retval) 26662306a36Sopenharmony_ci return retval; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci pdata->axis_align.offset_x = val; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci retval = rmi_of_property_read_u32(dev, &val, "syna,offset-y", 1); 27162306a36Sopenharmony_ci if (retval) 27262306a36Sopenharmony_ci return retval; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci pdata->axis_align.offset_y = val; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci retval = rmi_of_property_read_u32(dev, &val, "syna,delta-x-threshold", 27762306a36Sopenharmony_ci 1); 27862306a36Sopenharmony_ci if (retval) 27962306a36Sopenharmony_ci return retval; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci pdata->axis_align.delta_x_threshold = val; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci retval = rmi_of_property_read_u32(dev, &val, "syna,delta-y-threshold", 28462306a36Sopenharmony_ci 1); 28562306a36Sopenharmony_ci if (retval) 28662306a36Sopenharmony_ci return retval; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci pdata->axis_align.delta_y_threshold = val; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci retval = rmi_of_property_read_u32(dev, (u32 *)&pdata->sensor_type, 29162306a36Sopenharmony_ci "syna,sensor-type", 1); 29262306a36Sopenharmony_ci if (retval) 29362306a36Sopenharmony_ci return retval; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci retval = rmi_of_property_read_u32(dev, &val, "touchscreen-x-mm", 1); 29662306a36Sopenharmony_ci if (retval) 29762306a36Sopenharmony_ci return retval; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci pdata->x_mm = val; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci retval = rmi_of_property_read_u32(dev, &val, "touchscreen-y-mm", 1); 30262306a36Sopenharmony_ci if (retval) 30362306a36Sopenharmony_ci return retval; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci pdata->y_mm = val; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci retval = rmi_of_property_read_u32(dev, &val, 30862306a36Sopenharmony_ci "syna,disable-report-mask", 1); 30962306a36Sopenharmony_ci if (retval) 31062306a36Sopenharmony_ci return retval; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci pdata->disable_report_mask = val; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci retval = rmi_of_property_read_u32(dev, &val, "syna,rezero-wait-ms", 31562306a36Sopenharmony_ci 1); 31662306a36Sopenharmony_ci if (retval) 31762306a36Sopenharmony_ci return retval; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci pdata->rezero_wait = val; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci return 0; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci#else 32462306a36Sopenharmony_ciinline int rmi_2d_sensor_of_probe(struct device *dev, 32562306a36Sopenharmony_ci struct rmi_2d_sensor_platform_data *pdata) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci return -ENODEV; 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci#endif 33062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rmi_2d_sensor_of_probe); 331