162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2016 Masaki Ota <masaki.ota@jp.alps.com> 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/kernel.h> 762306a36Sopenharmony_ci#include <linux/hid.h> 862306a36Sopenharmony_ci#include <linux/input.h> 962306a36Sopenharmony_ci#include <linux/input/mt.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <asm/unaligned.h> 1262306a36Sopenharmony_ci#include "hid-ids.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci/* ALPS Device Product ID */ 1562306a36Sopenharmony_ci#define HID_PRODUCT_ID_T3_BTNLESS 0xD0C0 1662306a36Sopenharmony_ci#define HID_PRODUCT_ID_COSMO 0x1202 1762306a36Sopenharmony_ci#define HID_PRODUCT_ID_U1_PTP_1 0x1207 1862306a36Sopenharmony_ci#define HID_PRODUCT_ID_U1 0x1209 1962306a36Sopenharmony_ci#define HID_PRODUCT_ID_U1_PTP_2 0x120A 2062306a36Sopenharmony_ci#define HID_PRODUCT_ID_U1_DUAL 0x120B 2162306a36Sopenharmony_ci#define HID_PRODUCT_ID_T4_BTNLESS 0x120C 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define DEV_SINGLEPOINT 0x01 2462306a36Sopenharmony_ci#define DEV_DUALPOINT 0x02 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define U1_MOUSE_REPORT_ID 0x01 /* Mouse data ReportID */ 2762306a36Sopenharmony_ci#define U1_ABSOLUTE_REPORT_ID 0x03 /* Absolute data ReportID */ 2862306a36Sopenharmony_ci#define U1_ABSOLUTE_REPORT_ID_SECD 0x02 /* FW-PTP Absolute data ReportID */ 2962306a36Sopenharmony_ci#define U1_FEATURE_REPORT_ID 0x05 /* Feature ReportID */ 3062306a36Sopenharmony_ci#define U1_SP_ABSOLUTE_REPORT_ID 0x06 /* Feature ReportID */ 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define U1_FEATURE_REPORT_LEN 0x08 /* Feature Report Length */ 3362306a36Sopenharmony_ci#define U1_FEATURE_REPORT_LEN_ALL 0x0A 3462306a36Sopenharmony_ci#define U1_CMD_REGISTER_READ 0xD1 3562306a36Sopenharmony_ci#define U1_CMD_REGISTER_WRITE 0xD2 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define U1_DEVTYPE_SP_SUPPORT 0x10 /* SP Support */ 3862306a36Sopenharmony_ci#define U1_DISABLE_DEV 0x01 3962306a36Sopenharmony_ci#define U1_TP_ABS_MODE 0x02 4062306a36Sopenharmony_ci#define U1_SP_ABS_MODE 0x80 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define ADDRESS_U1_DEV_CTRL_1 0x00800040 4362306a36Sopenharmony_ci#define ADDRESS_U1_DEVICE_TYP 0x00800043 4462306a36Sopenharmony_ci#define ADDRESS_U1_NUM_SENS_X 0x00800047 4562306a36Sopenharmony_ci#define ADDRESS_U1_NUM_SENS_Y 0x00800048 4662306a36Sopenharmony_ci#define ADDRESS_U1_PITCH_SENS_X 0x00800049 4762306a36Sopenharmony_ci#define ADDRESS_U1_PITCH_SENS_Y 0x0080004A 4862306a36Sopenharmony_ci#define ADDRESS_U1_RESO_DWN_ABS 0x0080004E 4962306a36Sopenharmony_ci#define ADDRESS_U1_PAD_BTN 0x00800052 5062306a36Sopenharmony_ci#define ADDRESS_U1_SP_BTN 0x0080009F 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define T4_INPUT_REPORT_LEN sizeof(struct t4_input_report) 5362306a36Sopenharmony_ci#define T4_FEATURE_REPORT_LEN T4_INPUT_REPORT_LEN 5462306a36Sopenharmony_ci#define T4_FEATURE_REPORT_ID 7 5562306a36Sopenharmony_ci#define T4_CMD_REGISTER_READ 0x08 5662306a36Sopenharmony_ci#define T4_CMD_REGISTER_WRITE 0x07 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#define T4_ADDRESS_BASE 0xC2C0 5962306a36Sopenharmony_ci#define PRM_SYS_CONFIG_1 (T4_ADDRESS_BASE + 0x0002) 6062306a36Sopenharmony_ci#define T4_PRM_FEED_CONFIG_1 (T4_ADDRESS_BASE + 0x0004) 6162306a36Sopenharmony_ci#define T4_PRM_FEED_CONFIG_4 (T4_ADDRESS_BASE + 0x001A) 6262306a36Sopenharmony_ci#define T4_PRM_ID_CONFIG_3 (T4_ADDRESS_BASE + 0x00B0) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#define T4_FEEDCFG4_ADVANCED_ABS_ENABLE 0x01 6662306a36Sopenharmony_ci#define T4_I2C_ABS 0x78 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#define T4_COUNT_PER_ELECTRODE 256 6962306a36Sopenharmony_ci#define MAX_TOUCHES 5 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cienum dev_num { 7262306a36Sopenharmony_ci U1, 7362306a36Sopenharmony_ci T4, 7462306a36Sopenharmony_ci UNKNOWN, 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci/** 7762306a36Sopenharmony_ci * struct alps_dev 7862306a36Sopenharmony_ci * 7962306a36Sopenharmony_ci * @input: pointer to the kernel input device 8062306a36Sopenharmony_ci * @input2: pointer to the kernel input2 device 8162306a36Sopenharmony_ci * @hdev: pointer to the struct hid_device 8262306a36Sopenharmony_ci * 8362306a36Sopenharmony_ci * @dev_type: device type 8462306a36Sopenharmony_ci * @max_fingers: total number of fingers 8562306a36Sopenharmony_ci * @has_sp: boolean of sp existense 8662306a36Sopenharmony_ci * @sp_btn_info: button information 8762306a36Sopenharmony_ci * @x_active_len_mm: active area length of X (mm) 8862306a36Sopenharmony_ci * @y_active_len_mm: active area length of Y (mm) 8962306a36Sopenharmony_ci * @x_max: maximum x coordinate value 9062306a36Sopenharmony_ci * @y_max: maximum y coordinate value 9162306a36Sopenharmony_ci * @x_min: minimum x coordinate value 9262306a36Sopenharmony_ci * @y_min: minimum y coordinate value 9362306a36Sopenharmony_ci * @btn_cnt: number of buttons 9462306a36Sopenharmony_ci * @sp_btn_cnt: number of stick buttons 9562306a36Sopenharmony_ci */ 9662306a36Sopenharmony_cistruct alps_dev { 9762306a36Sopenharmony_ci struct input_dev *input; 9862306a36Sopenharmony_ci struct input_dev *input2; 9962306a36Sopenharmony_ci struct hid_device *hdev; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci enum dev_num dev_type; 10262306a36Sopenharmony_ci u8 max_fingers; 10362306a36Sopenharmony_ci u8 has_sp; 10462306a36Sopenharmony_ci u8 sp_btn_info; 10562306a36Sopenharmony_ci u32 x_active_len_mm; 10662306a36Sopenharmony_ci u32 y_active_len_mm; 10762306a36Sopenharmony_ci u32 x_max; 10862306a36Sopenharmony_ci u32 y_max; 10962306a36Sopenharmony_ci u32 x_min; 11062306a36Sopenharmony_ci u32 y_min; 11162306a36Sopenharmony_ci u32 btn_cnt; 11262306a36Sopenharmony_ci u32 sp_btn_cnt; 11362306a36Sopenharmony_ci}; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistruct t4_contact_data { 11662306a36Sopenharmony_ci u8 palm; 11762306a36Sopenharmony_ci u8 x_lo; 11862306a36Sopenharmony_ci u8 x_hi; 11962306a36Sopenharmony_ci u8 y_lo; 12062306a36Sopenharmony_ci u8 y_hi; 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistruct t4_input_report { 12462306a36Sopenharmony_ci u8 reportID; 12562306a36Sopenharmony_ci u8 numContacts; 12662306a36Sopenharmony_ci struct t4_contact_data contact[5]; 12762306a36Sopenharmony_ci u8 button; 12862306a36Sopenharmony_ci u8 track[5]; 12962306a36Sopenharmony_ci u8 zx[5], zy[5]; 13062306a36Sopenharmony_ci u8 palmTime[5]; 13162306a36Sopenharmony_ci u8 kilroy; 13262306a36Sopenharmony_ci u16 timeStamp; 13362306a36Sopenharmony_ci}; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic u16 t4_calc_check_sum(u8 *buffer, 13662306a36Sopenharmony_ci unsigned long offset, unsigned long length) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci u16 sum1 = 0xFF, sum2 = 0xFF; 13962306a36Sopenharmony_ci unsigned long i = 0; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (offset + length >= 50) 14262306a36Sopenharmony_ci return 0; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci while (length > 0) { 14562306a36Sopenharmony_ci u32 tlen = length > 20 ? 20 : length; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci length -= tlen; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci do { 15062306a36Sopenharmony_ci sum1 += buffer[offset + i]; 15162306a36Sopenharmony_ci sum2 += sum1; 15262306a36Sopenharmony_ci i++; 15362306a36Sopenharmony_ci } while (--tlen > 0); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci sum1 = (sum1 & 0xFF) + (sum1 >> 8); 15662306a36Sopenharmony_ci sum2 = (sum2 & 0xFF) + (sum2 >> 8); 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci sum1 = (sum1 & 0xFF) + (sum1 >> 8); 16062306a36Sopenharmony_ci sum2 = (sum2 & 0xFF) + (sum2 >> 8); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci return(sum2 << 8 | sum1); 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic int t4_read_write_register(struct hid_device *hdev, u32 address, 16662306a36Sopenharmony_ci u8 *read_val, u8 write_val, bool read_flag) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci int ret; 16962306a36Sopenharmony_ci u16 check_sum; 17062306a36Sopenharmony_ci u8 *input; 17162306a36Sopenharmony_ci u8 *readbuf = NULL; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci input = kzalloc(T4_FEATURE_REPORT_LEN, GFP_KERNEL); 17462306a36Sopenharmony_ci if (!input) 17562306a36Sopenharmony_ci return -ENOMEM; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci input[0] = T4_FEATURE_REPORT_ID; 17862306a36Sopenharmony_ci if (read_flag) { 17962306a36Sopenharmony_ci input[1] = T4_CMD_REGISTER_READ; 18062306a36Sopenharmony_ci input[8] = 0x00; 18162306a36Sopenharmony_ci } else { 18262306a36Sopenharmony_ci input[1] = T4_CMD_REGISTER_WRITE; 18362306a36Sopenharmony_ci input[8] = write_val; 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci put_unaligned_le32(address, input + 2); 18662306a36Sopenharmony_ci input[6] = 1; 18762306a36Sopenharmony_ci input[7] = 0; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* Calculate the checksum */ 19062306a36Sopenharmony_ci check_sum = t4_calc_check_sum(input, 1, 8); 19162306a36Sopenharmony_ci input[9] = (u8)check_sum; 19262306a36Sopenharmony_ci input[10] = (u8)(check_sum >> 8); 19362306a36Sopenharmony_ci input[11] = 0; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci ret = hid_hw_raw_request(hdev, T4_FEATURE_REPORT_ID, input, 19662306a36Sopenharmony_ci T4_FEATURE_REPORT_LEN, 19762306a36Sopenharmony_ci HID_FEATURE_REPORT, HID_REQ_SET_REPORT); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (ret < 0) { 20062306a36Sopenharmony_ci dev_err(&hdev->dev, "failed to read command (%d)\n", ret); 20162306a36Sopenharmony_ci goto exit; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (read_flag) { 20562306a36Sopenharmony_ci readbuf = kzalloc(T4_FEATURE_REPORT_LEN, GFP_KERNEL); 20662306a36Sopenharmony_ci if (!readbuf) { 20762306a36Sopenharmony_ci ret = -ENOMEM; 20862306a36Sopenharmony_ci goto exit; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci ret = hid_hw_raw_request(hdev, T4_FEATURE_REPORT_ID, readbuf, 21262306a36Sopenharmony_ci T4_FEATURE_REPORT_LEN, 21362306a36Sopenharmony_ci HID_FEATURE_REPORT, HID_REQ_GET_REPORT); 21462306a36Sopenharmony_ci if (ret < 0) { 21562306a36Sopenharmony_ci dev_err(&hdev->dev, "failed read register (%d)\n", ret); 21662306a36Sopenharmony_ci goto exit_readbuf; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci ret = -EINVAL; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci if (*(u32 *)&readbuf[6] != address) { 22262306a36Sopenharmony_ci dev_err(&hdev->dev, "read register address error (%x,%x)\n", 22362306a36Sopenharmony_ci *(u32 *)&readbuf[6], address); 22462306a36Sopenharmony_ci goto exit_readbuf; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (*(u16 *)&readbuf[10] != 1) { 22862306a36Sopenharmony_ci dev_err(&hdev->dev, "read register size error (%x)\n", 22962306a36Sopenharmony_ci *(u16 *)&readbuf[10]); 23062306a36Sopenharmony_ci goto exit_readbuf; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci check_sum = t4_calc_check_sum(readbuf, 6, 7); 23462306a36Sopenharmony_ci if (*(u16 *)&readbuf[13] != check_sum) { 23562306a36Sopenharmony_ci dev_err(&hdev->dev, "read register checksum error (%x,%x)\n", 23662306a36Sopenharmony_ci *(u16 *)&readbuf[13], check_sum); 23762306a36Sopenharmony_ci goto exit_readbuf; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci *read_val = readbuf[12]; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci ret = 0; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ciexit_readbuf: 24662306a36Sopenharmony_ci kfree(readbuf); 24762306a36Sopenharmony_ciexit: 24862306a36Sopenharmony_ci kfree(input); 24962306a36Sopenharmony_ci return ret; 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic int u1_read_write_register(struct hid_device *hdev, u32 address, 25362306a36Sopenharmony_ci u8 *read_val, u8 write_val, bool read_flag) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci int ret, i; 25662306a36Sopenharmony_ci u8 check_sum; 25762306a36Sopenharmony_ci u8 *input; 25862306a36Sopenharmony_ci u8 *readbuf; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci input = kzalloc(U1_FEATURE_REPORT_LEN, GFP_KERNEL); 26162306a36Sopenharmony_ci if (!input) 26262306a36Sopenharmony_ci return -ENOMEM; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci input[0] = U1_FEATURE_REPORT_ID; 26562306a36Sopenharmony_ci if (read_flag) { 26662306a36Sopenharmony_ci input[1] = U1_CMD_REGISTER_READ; 26762306a36Sopenharmony_ci input[6] = 0x00; 26862306a36Sopenharmony_ci } else { 26962306a36Sopenharmony_ci input[1] = U1_CMD_REGISTER_WRITE; 27062306a36Sopenharmony_ci input[6] = write_val; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci put_unaligned_le32(address, input + 2); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci /* Calculate the checksum */ 27662306a36Sopenharmony_ci check_sum = U1_FEATURE_REPORT_LEN_ALL; 27762306a36Sopenharmony_ci for (i = 0; i < U1_FEATURE_REPORT_LEN - 1; i++) 27862306a36Sopenharmony_ci check_sum += input[i]; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci input[7] = check_sum; 28162306a36Sopenharmony_ci ret = hid_hw_raw_request(hdev, U1_FEATURE_REPORT_ID, input, 28262306a36Sopenharmony_ci U1_FEATURE_REPORT_LEN, 28362306a36Sopenharmony_ci HID_FEATURE_REPORT, HID_REQ_SET_REPORT); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (ret < 0) { 28662306a36Sopenharmony_ci dev_err(&hdev->dev, "failed to read command (%d)\n", ret); 28762306a36Sopenharmony_ci goto exit; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (read_flag) { 29162306a36Sopenharmony_ci readbuf = kzalloc(U1_FEATURE_REPORT_LEN, GFP_KERNEL); 29262306a36Sopenharmony_ci if (!readbuf) { 29362306a36Sopenharmony_ci ret = -ENOMEM; 29462306a36Sopenharmony_ci goto exit; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci ret = hid_hw_raw_request(hdev, U1_FEATURE_REPORT_ID, readbuf, 29862306a36Sopenharmony_ci U1_FEATURE_REPORT_LEN, 29962306a36Sopenharmony_ci HID_FEATURE_REPORT, HID_REQ_GET_REPORT); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci if (ret < 0) { 30262306a36Sopenharmony_ci dev_err(&hdev->dev, "failed read register (%d)\n", ret); 30362306a36Sopenharmony_ci kfree(readbuf); 30462306a36Sopenharmony_ci goto exit; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci *read_val = readbuf[6]; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci kfree(readbuf); 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci ret = 0; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ciexit: 31562306a36Sopenharmony_ci kfree(input); 31662306a36Sopenharmony_ci return ret; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic int t4_raw_event(struct alps_dev *hdata, u8 *data, int size) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci unsigned int x, y, z; 32262306a36Sopenharmony_ci int i; 32362306a36Sopenharmony_ci struct t4_input_report *p_report = (struct t4_input_report *)data; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if (!data) 32662306a36Sopenharmony_ci return 0; 32762306a36Sopenharmony_ci for (i = 0; i < hdata->max_fingers; i++) { 32862306a36Sopenharmony_ci x = p_report->contact[i].x_hi << 8 | p_report->contact[i].x_lo; 32962306a36Sopenharmony_ci y = p_report->contact[i].y_hi << 8 | p_report->contact[i].y_lo; 33062306a36Sopenharmony_ci y = hdata->y_max - y + hdata->y_min; 33162306a36Sopenharmony_ci z = (p_report->contact[i].palm < 0x80 && 33262306a36Sopenharmony_ci p_report->contact[i].palm > 0) * 62; 33362306a36Sopenharmony_ci if (x == 0xffff) { 33462306a36Sopenharmony_ci x = 0; 33562306a36Sopenharmony_ci y = 0; 33662306a36Sopenharmony_ci z = 0; 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci input_mt_slot(hdata->input, i); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci input_mt_report_slot_state(hdata->input, 34162306a36Sopenharmony_ci MT_TOOL_FINGER, z != 0); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (!z) 34462306a36Sopenharmony_ci continue; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci input_report_abs(hdata->input, ABS_MT_POSITION_X, x); 34762306a36Sopenharmony_ci input_report_abs(hdata->input, ABS_MT_POSITION_Y, y); 34862306a36Sopenharmony_ci input_report_abs(hdata->input, ABS_MT_PRESSURE, z); 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci input_mt_sync_frame(hdata->input); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci input_report_key(hdata->input, BTN_LEFT, p_report->button); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci input_sync(hdata->input); 35562306a36Sopenharmony_ci return 1; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic int u1_raw_event(struct alps_dev *hdata, u8 *data, int size) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci unsigned int x, y, z; 36162306a36Sopenharmony_ci int i; 36262306a36Sopenharmony_ci short sp_x, sp_y; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (!data) 36562306a36Sopenharmony_ci return 0; 36662306a36Sopenharmony_ci switch (data[0]) { 36762306a36Sopenharmony_ci case U1_MOUSE_REPORT_ID: 36862306a36Sopenharmony_ci break; 36962306a36Sopenharmony_ci case U1_FEATURE_REPORT_ID: 37062306a36Sopenharmony_ci break; 37162306a36Sopenharmony_ci case U1_ABSOLUTE_REPORT_ID: 37262306a36Sopenharmony_ci case U1_ABSOLUTE_REPORT_ID_SECD: 37362306a36Sopenharmony_ci for (i = 0; i < hdata->max_fingers; i++) { 37462306a36Sopenharmony_ci u8 *contact = &data[i * 5]; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci x = get_unaligned_le16(contact + 3); 37762306a36Sopenharmony_ci y = get_unaligned_le16(contact + 5); 37862306a36Sopenharmony_ci z = contact[7] & 0x7F; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci input_mt_slot(hdata->input, i); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci if (z != 0) { 38362306a36Sopenharmony_ci input_mt_report_slot_state(hdata->input, 38462306a36Sopenharmony_ci MT_TOOL_FINGER, 1); 38562306a36Sopenharmony_ci input_report_abs(hdata->input, 38662306a36Sopenharmony_ci ABS_MT_POSITION_X, x); 38762306a36Sopenharmony_ci input_report_abs(hdata->input, 38862306a36Sopenharmony_ci ABS_MT_POSITION_Y, y); 38962306a36Sopenharmony_ci input_report_abs(hdata->input, 39062306a36Sopenharmony_ci ABS_MT_PRESSURE, z); 39162306a36Sopenharmony_ci } else { 39262306a36Sopenharmony_ci input_mt_report_slot_inactive(hdata->input); 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci input_mt_sync_frame(hdata->input); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci input_report_key(hdata->input, BTN_LEFT, 39962306a36Sopenharmony_ci data[1] & 0x1); 40062306a36Sopenharmony_ci input_report_key(hdata->input, BTN_RIGHT, 40162306a36Sopenharmony_ci (data[1] & 0x2)); 40262306a36Sopenharmony_ci input_report_key(hdata->input, BTN_MIDDLE, 40362306a36Sopenharmony_ci (data[1] & 0x4)); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci input_sync(hdata->input); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci return 1; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci case U1_SP_ABSOLUTE_REPORT_ID: 41062306a36Sopenharmony_ci sp_x = get_unaligned_le16(data+2); 41162306a36Sopenharmony_ci sp_y = get_unaligned_le16(data+4); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci sp_x = sp_x / 8; 41462306a36Sopenharmony_ci sp_y = sp_y / 8; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci input_report_rel(hdata->input2, REL_X, sp_x); 41762306a36Sopenharmony_ci input_report_rel(hdata->input2, REL_Y, sp_y); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci input_report_key(hdata->input2, BTN_LEFT, 42062306a36Sopenharmony_ci data[1] & 0x1); 42162306a36Sopenharmony_ci input_report_key(hdata->input2, BTN_RIGHT, 42262306a36Sopenharmony_ci (data[1] & 0x2)); 42362306a36Sopenharmony_ci input_report_key(hdata->input2, BTN_MIDDLE, 42462306a36Sopenharmony_ci (data[1] & 0x4)); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci input_sync(hdata->input2); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci return 1; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci return 0; 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic int alps_raw_event(struct hid_device *hdev, 43562306a36Sopenharmony_ci struct hid_report *report, u8 *data, int size) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci int ret = 0; 43862306a36Sopenharmony_ci struct alps_dev *hdata = hid_get_drvdata(hdev); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci switch (hdev->product) { 44162306a36Sopenharmony_ci case HID_PRODUCT_ID_T4_BTNLESS: 44262306a36Sopenharmony_ci ret = t4_raw_event(hdata, data, size); 44362306a36Sopenharmony_ci break; 44462306a36Sopenharmony_ci default: 44562306a36Sopenharmony_ci ret = u1_raw_event(hdata, data, size); 44662306a36Sopenharmony_ci break; 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci return ret; 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic int __maybe_unused alps_post_reset(struct hid_device *hdev) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci int ret = -1; 45462306a36Sopenharmony_ci struct alps_dev *data = hid_get_drvdata(hdev); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci switch (data->dev_type) { 45762306a36Sopenharmony_ci case T4: 45862306a36Sopenharmony_ci ret = t4_read_write_register(hdev, T4_PRM_FEED_CONFIG_1, 45962306a36Sopenharmony_ci NULL, T4_I2C_ABS, false); 46062306a36Sopenharmony_ci if (ret < 0) { 46162306a36Sopenharmony_ci dev_err(&hdev->dev, "failed T4_PRM_FEED_CONFIG_1 (%d)\n", 46262306a36Sopenharmony_ci ret); 46362306a36Sopenharmony_ci goto exit; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci ret = t4_read_write_register(hdev, T4_PRM_FEED_CONFIG_4, 46762306a36Sopenharmony_ci NULL, T4_FEEDCFG4_ADVANCED_ABS_ENABLE, false); 46862306a36Sopenharmony_ci if (ret < 0) { 46962306a36Sopenharmony_ci dev_err(&hdev->dev, "failed T4_PRM_FEED_CONFIG_4 (%d)\n", 47062306a36Sopenharmony_ci ret); 47162306a36Sopenharmony_ci goto exit; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci break; 47462306a36Sopenharmony_ci case U1: 47562306a36Sopenharmony_ci ret = u1_read_write_register(hdev, 47662306a36Sopenharmony_ci ADDRESS_U1_DEV_CTRL_1, NULL, 47762306a36Sopenharmony_ci U1_TP_ABS_MODE | U1_SP_ABS_MODE, false); 47862306a36Sopenharmony_ci if (ret < 0) { 47962306a36Sopenharmony_ci dev_err(&hdev->dev, "failed to change TP mode (%d)\n", 48062306a36Sopenharmony_ci ret); 48162306a36Sopenharmony_ci goto exit; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci break; 48462306a36Sopenharmony_ci default: 48562306a36Sopenharmony_ci break; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ciexit: 48962306a36Sopenharmony_ci return ret; 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_cistatic int __maybe_unused alps_post_resume(struct hid_device *hdev) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci return alps_post_reset(hdev); 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic int u1_init(struct hid_device *hdev, struct alps_dev *pri_data) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci int ret; 50062306a36Sopenharmony_ci u8 tmp, dev_ctrl, sen_line_num_x, sen_line_num_y; 50162306a36Sopenharmony_ci u8 pitch_x, pitch_y, resolution; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci /* Device initialization */ 50462306a36Sopenharmony_ci ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1, 50562306a36Sopenharmony_ci &dev_ctrl, 0, true); 50662306a36Sopenharmony_ci if (ret < 0) { 50762306a36Sopenharmony_ci dev_err(&hdev->dev, "failed U1_DEV_CTRL_1 (%d)\n", ret); 50862306a36Sopenharmony_ci goto exit; 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci dev_ctrl &= ~U1_DISABLE_DEV; 51262306a36Sopenharmony_ci dev_ctrl |= U1_TP_ABS_MODE; 51362306a36Sopenharmony_ci ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1, 51462306a36Sopenharmony_ci NULL, dev_ctrl, false); 51562306a36Sopenharmony_ci if (ret < 0) { 51662306a36Sopenharmony_ci dev_err(&hdev->dev, "failed to change TP mode (%d)\n", ret); 51762306a36Sopenharmony_ci goto exit; 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci ret = u1_read_write_register(hdev, ADDRESS_U1_NUM_SENS_X, 52162306a36Sopenharmony_ci &sen_line_num_x, 0, true); 52262306a36Sopenharmony_ci if (ret < 0) { 52362306a36Sopenharmony_ci dev_err(&hdev->dev, "failed U1_NUM_SENS_X (%d)\n", ret); 52462306a36Sopenharmony_ci goto exit; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci ret = u1_read_write_register(hdev, ADDRESS_U1_NUM_SENS_Y, 52862306a36Sopenharmony_ci &sen_line_num_y, 0, true); 52962306a36Sopenharmony_ci if (ret < 0) { 53062306a36Sopenharmony_ci dev_err(&hdev->dev, "failed U1_NUM_SENS_Y (%d)\n", ret); 53162306a36Sopenharmony_ci goto exit; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci ret = u1_read_write_register(hdev, ADDRESS_U1_PITCH_SENS_X, 53562306a36Sopenharmony_ci &pitch_x, 0, true); 53662306a36Sopenharmony_ci if (ret < 0) { 53762306a36Sopenharmony_ci dev_err(&hdev->dev, "failed U1_PITCH_SENS_X (%d)\n", ret); 53862306a36Sopenharmony_ci goto exit; 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci ret = u1_read_write_register(hdev, ADDRESS_U1_PITCH_SENS_Y, 54262306a36Sopenharmony_ci &pitch_y, 0, true); 54362306a36Sopenharmony_ci if (ret < 0) { 54462306a36Sopenharmony_ci dev_err(&hdev->dev, "failed U1_PITCH_SENS_Y (%d)\n", ret); 54562306a36Sopenharmony_ci goto exit; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci ret = u1_read_write_register(hdev, ADDRESS_U1_RESO_DWN_ABS, 54962306a36Sopenharmony_ci &resolution, 0, true); 55062306a36Sopenharmony_ci if (ret < 0) { 55162306a36Sopenharmony_ci dev_err(&hdev->dev, "failed U1_RESO_DWN_ABS (%d)\n", ret); 55262306a36Sopenharmony_ci goto exit; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci pri_data->x_active_len_mm = 55562306a36Sopenharmony_ci (pitch_x * (sen_line_num_x - 1)) / 10; 55662306a36Sopenharmony_ci pri_data->y_active_len_mm = 55762306a36Sopenharmony_ci (pitch_y * (sen_line_num_y - 1)) / 10; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci pri_data->x_max = 56062306a36Sopenharmony_ci (resolution << 2) * (sen_line_num_x - 1); 56162306a36Sopenharmony_ci pri_data->x_min = 1; 56262306a36Sopenharmony_ci pri_data->y_max = 56362306a36Sopenharmony_ci (resolution << 2) * (sen_line_num_y - 1); 56462306a36Sopenharmony_ci pri_data->y_min = 1; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci ret = u1_read_write_register(hdev, ADDRESS_U1_PAD_BTN, 56762306a36Sopenharmony_ci &tmp, 0, true); 56862306a36Sopenharmony_ci if (ret < 0) { 56962306a36Sopenharmony_ci dev_err(&hdev->dev, "failed U1_PAD_BTN (%d)\n", ret); 57062306a36Sopenharmony_ci goto exit; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci if ((tmp & 0x0F) == (tmp & 0xF0) >> 4) { 57362306a36Sopenharmony_ci pri_data->btn_cnt = (tmp & 0x0F); 57462306a36Sopenharmony_ci } else { 57562306a36Sopenharmony_ci /* Button pad */ 57662306a36Sopenharmony_ci pri_data->btn_cnt = 1; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci pri_data->has_sp = 0; 58062306a36Sopenharmony_ci /* Check StickPointer device */ 58162306a36Sopenharmony_ci ret = u1_read_write_register(hdev, ADDRESS_U1_DEVICE_TYP, 58262306a36Sopenharmony_ci &tmp, 0, true); 58362306a36Sopenharmony_ci if (ret < 0) { 58462306a36Sopenharmony_ci dev_err(&hdev->dev, "failed U1_DEVICE_TYP (%d)\n", ret); 58562306a36Sopenharmony_ci goto exit; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci if (tmp & U1_DEVTYPE_SP_SUPPORT) { 58862306a36Sopenharmony_ci dev_ctrl |= U1_SP_ABS_MODE; 58962306a36Sopenharmony_ci ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1, 59062306a36Sopenharmony_ci NULL, dev_ctrl, false); 59162306a36Sopenharmony_ci if (ret < 0) { 59262306a36Sopenharmony_ci dev_err(&hdev->dev, "failed SP mode (%d)\n", ret); 59362306a36Sopenharmony_ci goto exit; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci ret = u1_read_write_register(hdev, ADDRESS_U1_SP_BTN, 59762306a36Sopenharmony_ci &pri_data->sp_btn_info, 0, true); 59862306a36Sopenharmony_ci if (ret < 0) { 59962306a36Sopenharmony_ci dev_err(&hdev->dev, "failed U1_SP_BTN (%d)\n", ret); 60062306a36Sopenharmony_ci goto exit; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci pri_data->has_sp = 1; 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci pri_data->max_fingers = 5; 60562306a36Sopenharmony_ciexit: 60662306a36Sopenharmony_ci return ret; 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistatic int T4_init(struct hid_device *hdev, struct alps_dev *pri_data) 61062306a36Sopenharmony_ci{ 61162306a36Sopenharmony_ci int ret; 61262306a36Sopenharmony_ci u8 tmp, sen_line_num_x, sen_line_num_y; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci ret = t4_read_write_register(hdev, T4_PRM_ID_CONFIG_3, &tmp, 0, true); 61562306a36Sopenharmony_ci if (ret < 0) { 61662306a36Sopenharmony_ci dev_err(&hdev->dev, "failed T4_PRM_ID_CONFIG_3 (%d)\n", ret); 61762306a36Sopenharmony_ci goto exit; 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci sen_line_num_x = 16 + ((tmp & 0x0F) | (tmp & 0x08 ? 0xF0 : 0)); 62062306a36Sopenharmony_ci sen_line_num_y = 12 + (((tmp & 0xF0) >> 4) | (tmp & 0x80 ? 0xF0 : 0)); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci pri_data->x_max = sen_line_num_x * T4_COUNT_PER_ELECTRODE; 62362306a36Sopenharmony_ci pri_data->x_min = T4_COUNT_PER_ELECTRODE; 62462306a36Sopenharmony_ci pri_data->y_max = sen_line_num_y * T4_COUNT_PER_ELECTRODE; 62562306a36Sopenharmony_ci pri_data->y_min = T4_COUNT_PER_ELECTRODE; 62662306a36Sopenharmony_ci pri_data->x_active_len_mm = pri_data->y_active_len_mm = 0; 62762306a36Sopenharmony_ci pri_data->btn_cnt = 1; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci ret = t4_read_write_register(hdev, PRM_SYS_CONFIG_1, &tmp, 0, true); 63062306a36Sopenharmony_ci if (ret < 0) { 63162306a36Sopenharmony_ci dev_err(&hdev->dev, "failed PRM_SYS_CONFIG_1 (%d)\n", ret); 63262306a36Sopenharmony_ci goto exit; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci tmp |= 0x02; 63562306a36Sopenharmony_ci ret = t4_read_write_register(hdev, PRM_SYS_CONFIG_1, NULL, tmp, false); 63662306a36Sopenharmony_ci if (ret < 0) { 63762306a36Sopenharmony_ci dev_err(&hdev->dev, "failed PRM_SYS_CONFIG_1 (%d)\n", ret); 63862306a36Sopenharmony_ci goto exit; 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci ret = t4_read_write_register(hdev, T4_PRM_FEED_CONFIG_1, 64262306a36Sopenharmony_ci NULL, T4_I2C_ABS, false); 64362306a36Sopenharmony_ci if (ret < 0) { 64462306a36Sopenharmony_ci dev_err(&hdev->dev, "failed T4_PRM_FEED_CONFIG_1 (%d)\n", ret); 64562306a36Sopenharmony_ci goto exit; 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci ret = t4_read_write_register(hdev, T4_PRM_FEED_CONFIG_4, NULL, 64962306a36Sopenharmony_ci T4_FEEDCFG4_ADVANCED_ABS_ENABLE, false); 65062306a36Sopenharmony_ci if (ret < 0) { 65162306a36Sopenharmony_ci dev_err(&hdev->dev, "failed T4_PRM_FEED_CONFIG_4 (%d)\n", ret); 65262306a36Sopenharmony_ci goto exit; 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci pri_data->max_fingers = 5; 65562306a36Sopenharmony_ci pri_data->has_sp = 0; 65662306a36Sopenharmony_ciexit: 65762306a36Sopenharmony_ci return ret; 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic int alps_sp_open(struct input_dev *dev) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci struct hid_device *hid = input_get_drvdata(dev); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci return hid_hw_open(hid); 66562306a36Sopenharmony_ci} 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_cistatic void alps_sp_close(struct input_dev *dev) 66862306a36Sopenharmony_ci{ 66962306a36Sopenharmony_ci struct hid_device *hid = input_get_drvdata(dev); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci hid_hw_close(hid); 67262306a36Sopenharmony_ci} 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_cistatic int alps_input_configured(struct hid_device *hdev, struct hid_input *hi) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci struct alps_dev *data = hid_get_drvdata(hdev); 67762306a36Sopenharmony_ci struct input_dev *input = hi->input, *input2; 67862306a36Sopenharmony_ci int ret; 67962306a36Sopenharmony_ci int res_x, res_y, i; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci data->input = input; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci hid_dbg(hdev, "Opening low level driver\n"); 68462306a36Sopenharmony_ci ret = hid_hw_open(hdev); 68562306a36Sopenharmony_ci if (ret) 68662306a36Sopenharmony_ci return ret; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci /* Allow incoming hid reports */ 68962306a36Sopenharmony_ci hid_device_io_start(hdev); 69062306a36Sopenharmony_ci switch (data->dev_type) { 69162306a36Sopenharmony_ci case T4: 69262306a36Sopenharmony_ci ret = T4_init(hdev, data); 69362306a36Sopenharmony_ci break; 69462306a36Sopenharmony_ci case U1: 69562306a36Sopenharmony_ci ret = u1_init(hdev, data); 69662306a36Sopenharmony_ci break; 69762306a36Sopenharmony_ci default: 69862306a36Sopenharmony_ci break; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci if (ret) 70262306a36Sopenharmony_ci goto exit; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci __set_bit(EV_ABS, input->evbit); 70562306a36Sopenharmony_ci input_set_abs_params(input, ABS_MT_POSITION_X, 70662306a36Sopenharmony_ci data->x_min, data->x_max, 0, 0); 70762306a36Sopenharmony_ci input_set_abs_params(input, ABS_MT_POSITION_Y, 70862306a36Sopenharmony_ci data->y_min, data->y_max, 0, 0); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if (data->x_active_len_mm && data->y_active_len_mm) { 71162306a36Sopenharmony_ci res_x = (data->x_max - 1) / data->x_active_len_mm; 71262306a36Sopenharmony_ci res_y = (data->y_max - 1) / data->y_active_len_mm; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci input_abs_set_res(input, ABS_MT_POSITION_X, res_x); 71562306a36Sopenharmony_ci input_abs_set_res(input, ABS_MT_POSITION_Y, res_y); 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci input_set_abs_params(input, ABS_MT_PRESSURE, 0, 64, 0, 0); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci input_mt_init_slots(input, data->max_fingers, INPUT_MT_POINTER); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci __set_bit(EV_KEY, input->evbit); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci if (data->btn_cnt == 1) 72562306a36Sopenharmony_ci __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci for (i = 0; i < data->btn_cnt; i++) 72862306a36Sopenharmony_ci __set_bit(BTN_LEFT + i, input->keybit); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci /* Stick device initialization */ 73162306a36Sopenharmony_ci if (data->has_sp) { 73262306a36Sopenharmony_ci input2 = input_allocate_device(); 73362306a36Sopenharmony_ci if (!input2) { 73462306a36Sopenharmony_ci ret = -ENOMEM; 73562306a36Sopenharmony_ci goto exit; 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci data->input2 = input2; 73962306a36Sopenharmony_ci input2->phys = input->phys; 74062306a36Sopenharmony_ci input2->name = "DualPoint Stick"; 74162306a36Sopenharmony_ci input2->id.bustype = BUS_I2C; 74262306a36Sopenharmony_ci input2->id.vendor = input->id.vendor; 74362306a36Sopenharmony_ci input2->id.product = input->id.product; 74462306a36Sopenharmony_ci input2->id.version = input->id.version; 74562306a36Sopenharmony_ci input2->dev.parent = input->dev.parent; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci input_set_drvdata(input2, hdev); 74862306a36Sopenharmony_ci input2->open = alps_sp_open; 74962306a36Sopenharmony_ci input2->close = alps_sp_close; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci __set_bit(EV_KEY, input2->evbit); 75262306a36Sopenharmony_ci data->sp_btn_cnt = (data->sp_btn_info & 0x0F); 75362306a36Sopenharmony_ci for (i = 0; i < data->sp_btn_cnt; i++) 75462306a36Sopenharmony_ci __set_bit(BTN_LEFT + i, input2->keybit); 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci __set_bit(EV_REL, input2->evbit); 75762306a36Sopenharmony_ci __set_bit(REL_X, input2->relbit); 75862306a36Sopenharmony_ci __set_bit(REL_Y, input2->relbit); 75962306a36Sopenharmony_ci __set_bit(INPUT_PROP_POINTER, input2->propbit); 76062306a36Sopenharmony_ci __set_bit(INPUT_PROP_POINTING_STICK, input2->propbit); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci if (input_register_device(data->input2)) { 76362306a36Sopenharmony_ci input_free_device(input2); 76462306a36Sopenharmony_ci ret = -ENOENT; 76562306a36Sopenharmony_ci goto exit; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ciexit: 77062306a36Sopenharmony_ci hid_device_io_stop(hdev); 77162306a36Sopenharmony_ci hid_hw_close(hdev); 77262306a36Sopenharmony_ci return ret; 77362306a36Sopenharmony_ci} 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_cistatic int alps_input_mapping(struct hid_device *hdev, 77662306a36Sopenharmony_ci struct hid_input *hi, struct hid_field *field, 77762306a36Sopenharmony_ci struct hid_usage *usage, unsigned long **bit, int *max) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci return -1; 78062306a36Sopenharmony_ci} 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_cistatic int alps_probe(struct hid_device *hdev, const struct hid_device_id *id) 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci struct alps_dev *data = NULL; 78562306a36Sopenharmony_ci int ret; 78662306a36Sopenharmony_ci data = devm_kzalloc(&hdev->dev, sizeof(struct alps_dev), GFP_KERNEL); 78762306a36Sopenharmony_ci if (!data) 78862306a36Sopenharmony_ci return -ENOMEM; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci data->hdev = hdev; 79162306a36Sopenharmony_ci hid_set_drvdata(hdev, data); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci ret = hid_parse(hdev); 79662306a36Sopenharmony_ci if (ret) { 79762306a36Sopenharmony_ci hid_err(hdev, "parse failed\n"); 79862306a36Sopenharmony_ci return ret; 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci switch (hdev->product) { 80262306a36Sopenharmony_ci case HID_DEVICE_ID_ALPS_T4_BTNLESS: 80362306a36Sopenharmony_ci data->dev_type = T4; 80462306a36Sopenharmony_ci break; 80562306a36Sopenharmony_ci case HID_DEVICE_ID_ALPS_U1_DUAL: 80662306a36Sopenharmony_ci case HID_DEVICE_ID_ALPS_U1: 80762306a36Sopenharmony_ci case HID_DEVICE_ID_ALPS_U1_UNICORN_LEGACY: 80862306a36Sopenharmony_ci data->dev_type = U1; 80962306a36Sopenharmony_ci break; 81062306a36Sopenharmony_ci default: 81162306a36Sopenharmony_ci data->dev_type = UNKNOWN; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 81562306a36Sopenharmony_ci if (ret) { 81662306a36Sopenharmony_ci hid_err(hdev, "hw start failed\n"); 81762306a36Sopenharmony_ci return ret; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci return 0; 82162306a36Sopenharmony_ci} 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_cistatic const struct hid_device_id alps_id[] = { 82462306a36Sopenharmony_ci { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, 82562306a36Sopenharmony_ci USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_DUAL) }, 82662306a36Sopenharmony_ci { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, 82762306a36Sopenharmony_ci USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1) }, 82862306a36Sopenharmony_ci { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, 82962306a36Sopenharmony_ci USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_UNICORN_LEGACY) }, 83062306a36Sopenharmony_ci { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, 83162306a36Sopenharmony_ci USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_T4_BTNLESS) }, 83262306a36Sopenharmony_ci { } 83362306a36Sopenharmony_ci}; 83462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(hid, alps_id); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_cistatic struct hid_driver alps_driver = { 83762306a36Sopenharmony_ci .name = "hid-alps", 83862306a36Sopenharmony_ci .id_table = alps_id, 83962306a36Sopenharmony_ci .probe = alps_probe, 84062306a36Sopenharmony_ci .raw_event = alps_raw_event, 84162306a36Sopenharmony_ci .input_mapping = alps_input_mapping, 84262306a36Sopenharmony_ci .input_configured = alps_input_configured, 84362306a36Sopenharmony_ci#ifdef CONFIG_PM 84462306a36Sopenharmony_ci .resume = alps_post_resume, 84562306a36Sopenharmony_ci .reset_resume = alps_post_reset, 84662306a36Sopenharmony_ci#endif 84762306a36Sopenharmony_ci}; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_cimodule_hid_driver(alps_driver); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ciMODULE_AUTHOR("Masaki Ota <masaki.ota@jp.alps.com>"); 85262306a36Sopenharmony_ciMODULE_DESCRIPTION("ALPS HID driver"); 85362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 854