1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2016 Masaki Ota <masaki.ota@jp.alps.com>
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #include <linux/kernel.h>
7*4882a593Smuzhiyun #include <linux/hid.h>
8*4882a593Smuzhiyun #include <linux/input.h>
9*4882a593Smuzhiyun #include <linux/input/mt.h>
10*4882a593Smuzhiyun #include <linux/module.h>
11*4882a593Smuzhiyun #include <asm/unaligned.h>
12*4882a593Smuzhiyun #include "hid-ids.h"
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun /* ALPS Device Product ID */
15*4882a593Smuzhiyun #define HID_PRODUCT_ID_T3_BTNLESS 0xD0C0
16*4882a593Smuzhiyun #define HID_PRODUCT_ID_COSMO 0x1202
17*4882a593Smuzhiyun #define HID_PRODUCT_ID_U1_PTP_1 0x1207
18*4882a593Smuzhiyun #define HID_PRODUCT_ID_U1 0x1209
19*4882a593Smuzhiyun #define HID_PRODUCT_ID_U1_PTP_2 0x120A
20*4882a593Smuzhiyun #define HID_PRODUCT_ID_U1_DUAL 0x120B
21*4882a593Smuzhiyun #define HID_PRODUCT_ID_T4_BTNLESS 0x120C
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #define DEV_SINGLEPOINT 0x01
24*4882a593Smuzhiyun #define DEV_DUALPOINT 0x02
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #define U1_MOUSE_REPORT_ID 0x01 /* Mouse data ReportID */
27*4882a593Smuzhiyun #define U1_ABSOLUTE_REPORT_ID 0x03 /* Absolute data ReportID */
28*4882a593Smuzhiyun #define U1_ABSOLUTE_REPORT_ID_SECD 0x02 /* FW-PTP Absolute data ReportID */
29*4882a593Smuzhiyun #define U1_FEATURE_REPORT_ID 0x05 /* Feature ReportID */
30*4882a593Smuzhiyun #define U1_SP_ABSOLUTE_REPORT_ID 0x06 /* Feature ReportID */
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #define U1_FEATURE_REPORT_LEN 0x08 /* Feature Report Length */
33*4882a593Smuzhiyun #define U1_FEATURE_REPORT_LEN_ALL 0x0A
34*4882a593Smuzhiyun #define U1_CMD_REGISTER_READ 0xD1
35*4882a593Smuzhiyun #define U1_CMD_REGISTER_WRITE 0xD2
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #define U1_DEVTYPE_SP_SUPPORT 0x10 /* SP Support */
38*4882a593Smuzhiyun #define U1_DISABLE_DEV 0x01
39*4882a593Smuzhiyun #define U1_TP_ABS_MODE 0x02
40*4882a593Smuzhiyun #define U1_SP_ABS_MODE 0x80
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun #define ADDRESS_U1_DEV_CTRL_1 0x00800040
43*4882a593Smuzhiyun #define ADDRESS_U1_DEVICE_TYP 0x00800043
44*4882a593Smuzhiyun #define ADDRESS_U1_NUM_SENS_X 0x00800047
45*4882a593Smuzhiyun #define ADDRESS_U1_NUM_SENS_Y 0x00800048
46*4882a593Smuzhiyun #define ADDRESS_U1_PITCH_SENS_X 0x00800049
47*4882a593Smuzhiyun #define ADDRESS_U1_PITCH_SENS_Y 0x0080004A
48*4882a593Smuzhiyun #define ADDRESS_U1_RESO_DWN_ABS 0x0080004E
49*4882a593Smuzhiyun #define ADDRESS_U1_PAD_BTN 0x00800052
50*4882a593Smuzhiyun #define ADDRESS_U1_SP_BTN 0x0080009F
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun #define T4_INPUT_REPORT_LEN sizeof(struct t4_input_report)
53*4882a593Smuzhiyun #define T4_FEATURE_REPORT_LEN T4_INPUT_REPORT_LEN
54*4882a593Smuzhiyun #define T4_FEATURE_REPORT_ID 7
55*4882a593Smuzhiyun #define T4_CMD_REGISTER_READ 0x08
56*4882a593Smuzhiyun #define T4_CMD_REGISTER_WRITE 0x07
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun #define T4_ADDRESS_BASE 0xC2C0
59*4882a593Smuzhiyun #define PRM_SYS_CONFIG_1 (T4_ADDRESS_BASE + 0x0002)
60*4882a593Smuzhiyun #define T4_PRM_FEED_CONFIG_1 (T4_ADDRESS_BASE + 0x0004)
61*4882a593Smuzhiyun #define T4_PRM_FEED_CONFIG_4 (T4_ADDRESS_BASE + 0x001A)
62*4882a593Smuzhiyun #define T4_PRM_ID_CONFIG_3 (T4_ADDRESS_BASE + 0x00B0)
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun #define T4_FEEDCFG4_ADVANCED_ABS_ENABLE 0x01
66*4882a593Smuzhiyun #define T4_I2C_ABS 0x78
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun #define T4_COUNT_PER_ELECTRODE 256
69*4882a593Smuzhiyun #define MAX_TOUCHES 5
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun enum dev_num {
72*4882a593Smuzhiyun U1,
73*4882a593Smuzhiyun T4,
74*4882a593Smuzhiyun UNKNOWN,
75*4882a593Smuzhiyun };
76*4882a593Smuzhiyun /**
77*4882a593Smuzhiyun * struct u1_data
78*4882a593Smuzhiyun *
79*4882a593Smuzhiyun * @input: pointer to the kernel input device
80*4882a593Smuzhiyun * @input2: pointer to the kernel input2 device
81*4882a593Smuzhiyun * @hdev: pointer to the struct hid_device
82*4882a593Smuzhiyun *
83*4882a593Smuzhiyun * @dev_type: device type
84*4882a593Smuzhiyun * @max_fingers: total number of fingers
85*4882a593Smuzhiyun * @has_sp: boolean of sp existense
86*4882a593Smuzhiyun * @sp_btn_info: button information
87*4882a593Smuzhiyun * @x_active_len_mm: active area length of X (mm)
88*4882a593Smuzhiyun * @y_active_len_mm: active area length of Y (mm)
89*4882a593Smuzhiyun * @x_max: maximum x coordinate value
90*4882a593Smuzhiyun * @y_max: maximum y coordinate value
91*4882a593Smuzhiyun * @x_min: minimum x coordinate value
92*4882a593Smuzhiyun * @y_min: minimum y coordinate value
93*4882a593Smuzhiyun * @btn_cnt: number of buttons
94*4882a593Smuzhiyun * @sp_btn_cnt: number of stick buttons
95*4882a593Smuzhiyun */
96*4882a593Smuzhiyun struct alps_dev {
97*4882a593Smuzhiyun struct input_dev *input;
98*4882a593Smuzhiyun struct input_dev *input2;
99*4882a593Smuzhiyun struct hid_device *hdev;
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun enum dev_num dev_type;
102*4882a593Smuzhiyun u8 max_fingers;
103*4882a593Smuzhiyun u8 has_sp;
104*4882a593Smuzhiyun u8 sp_btn_info;
105*4882a593Smuzhiyun u32 x_active_len_mm;
106*4882a593Smuzhiyun u32 y_active_len_mm;
107*4882a593Smuzhiyun u32 x_max;
108*4882a593Smuzhiyun u32 y_max;
109*4882a593Smuzhiyun u32 x_min;
110*4882a593Smuzhiyun u32 y_min;
111*4882a593Smuzhiyun u32 btn_cnt;
112*4882a593Smuzhiyun u32 sp_btn_cnt;
113*4882a593Smuzhiyun };
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun struct t4_contact_data {
116*4882a593Smuzhiyun u8 palm;
117*4882a593Smuzhiyun u8 x_lo;
118*4882a593Smuzhiyun u8 x_hi;
119*4882a593Smuzhiyun u8 y_lo;
120*4882a593Smuzhiyun u8 y_hi;
121*4882a593Smuzhiyun };
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun struct t4_input_report {
124*4882a593Smuzhiyun u8 reportID;
125*4882a593Smuzhiyun u8 numContacts;
126*4882a593Smuzhiyun struct t4_contact_data contact[5];
127*4882a593Smuzhiyun u8 button;
128*4882a593Smuzhiyun u8 track[5];
129*4882a593Smuzhiyun u8 zx[5], zy[5];
130*4882a593Smuzhiyun u8 palmTime[5];
131*4882a593Smuzhiyun u8 kilroy;
132*4882a593Smuzhiyun u16 timeStamp;
133*4882a593Smuzhiyun };
134*4882a593Smuzhiyun
t4_calc_check_sum(u8 * buffer,unsigned long offset,unsigned long length)135*4882a593Smuzhiyun static u16 t4_calc_check_sum(u8 *buffer,
136*4882a593Smuzhiyun unsigned long offset, unsigned long length)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun u16 sum1 = 0xFF, sum2 = 0xFF;
139*4882a593Smuzhiyun unsigned long i = 0;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun if (offset + length >= 50)
142*4882a593Smuzhiyun return 0;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun while (length > 0) {
145*4882a593Smuzhiyun u32 tlen = length > 20 ? 20 : length;
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun length -= tlen;
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun do {
150*4882a593Smuzhiyun sum1 += buffer[offset + i];
151*4882a593Smuzhiyun sum2 += sum1;
152*4882a593Smuzhiyun i++;
153*4882a593Smuzhiyun } while (--tlen > 0);
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun sum1 = (sum1 & 0xFF) + (sum1 >> 8);
156*4882a593Smuzhiyun sum2 = (sum2 & 0xFF) + (sum2 >> 8);
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun sum1 = (sum1 & 0xFF) + (sum1 >> 8);
160*4882a593Smuzhiyun sum2 = (sum2 & 0xFF) + (sum2 >> 8);
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun return(sum2 << 8 | sum1);
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun
t4_read_write_register(struct hid_device * hdev,u32 address,u8 * read_val,u8 write_val,bool read_flag)165*4882a593Smuzhiyun static int t4_read_write_register(struct hid_device *hdev, u32 address,
166*4882a593Smuzhiyun u8 *read_val, u8 write_val, bool read_flag)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun int ret;
169*4882a593Smuzhiyun u16 check_sum;
170*4882a593Smuzhiyun u8 *input;
171*4882a593Smuzhiyun u8 *readbuf = NULL;
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun input = kzalloc(T4_FEATURE_REPORT_LEN, GFP_KERNEL);
174*4882a593Smuzhiyun if (!input)
175*4882a593Smuzhiyun return -ENOMEM;
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun input[0] = T4_FEATURE_REPORT_ID;
178*4882a593Smuzhiyun if (read_flag) {
179*4882a593Smuzhiyun input[1] = T4_CMD_REGISTER_READ;
180*4882a593Smuzhiyun input[8] = 0x00;
181*4882a593Smuzhiyun } else {
182*4882a593Smuzhiyun input[1] = T4_CMD_REGISTER_WRITE;
183*4882a593Smuzhiyun input[8] = write_val;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun put_unaligned_le32(address, input + 2);
186*4882a593Smuzhiyun input[6] = 1;
187*4882a593Smuzhiyun input[7] = 0;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun /* Calculate the checksum */
190*4882a593Smuzhiyun check_sum = t4_calc_check_sum(input, 1, 8);
191*4882a593Smuzhiyun input[9] = (u8)check_sum;
192*4882a593Smuzhiyun input[10] = (u8)(check_sum >> 8);
193*4882a593Smuzhiyun input[11] = 0;
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun ret = hid_hw_raw_request(hdev, T4_FEATURE_REPORT_ID, input,
196*4882a593Smuzhiyun T4_FEATURE_REPORT_LEN,
197*4882a593Smuzhiyun HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun if (ret < 0) {
200*4882a593Smuzhiyun dev_err(&hdev->dev, "failed to read command (%d)\n", ret);
201*4882a593Smuzhiyun goto exit;
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun if (read_flag) {
205*4882a593Smuzhiyun readbuf = kzalloc(T4_FEATURE_REPORT_LEN, GFP_KERNEL);
206*4882a593Smuzhiyun if (!readbuf) {
207*4882a593Smuzhiyun ret = -ENOMEM;
208*4882a593Smuzhiyun goto exit;
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun ret = hid_hw_raw_request(hdev, T4_FEATURE_REPORT_ID, readbuf,
212*4882a593Smuzhiyun T4_FEATURE_REPORT_LEN,
213*4882a593Smuzhiyun HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
214*4882a593Smuzhiyun if (ret < 0) {
215*4882a593Smuzhiyun dev_err(&hdev->dev, "failed read register (%d)\n", ret);
216*4882a593Smuzhiyun goto exit_readbuf;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun ret = -EINVAL;
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun if (*(u32 *)&readbuf[6] != address) {
222*4882a593Smuzhiyun dev_err(&hdev->dev, "read register address error (%x,%x)\n",
223*4882a593Smuzhiyun *(u32 *)&readbuf[6], address);
224*4882a593Smuzhiyun goto exit_readbuf;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun if (*(u16 *)&readbuf[10] != 1) {
228*4882a593Smuzhiyun dev_err(&hdev->dev, "read register size error (%x)\n",
229*4882a593Smuzhiyun *(u16 *)&readbuf[10]);
230*4882a593Smuzhiyun goto exit_readbuf;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun check_sum = t4_calc_check_sum(readbuf, 6, 7);
234*4882a593Smuzhiyun if (*(u16 *)&readbuf[13] != check_sum) {
235*4882a593Smuzhiyun dev_err(&hdev->dev, "read register checksum error (%x,%x)\n",
236*4882a593Smuzhiyun *(u16 *)&readbuf[13], check_sum);
237*4882a593Smuzhiyun goto exit_readbuf;
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun *read_val = readbuf[12];
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun ret = 0;
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun exit_readbuf:
246*4882a593Smuzhiyun kfree(readbuf);
247*4882a593Smuzhiyun exit:
248*4882a593Smuzhiyun kfree(input);
249*4882a593Smuzhiyun return ret;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun
u1_read_write_register(struct hid_device * hdev,u32 address,u8 * read_val,u8 write_val,bool read_flag)252*4882a593Smuzhiyun static int u1_read_write_register(struct hid_device *hdev, u32 address,
253*4882a593Smuzhiyun u8 *read_val, u8 write_val, bool read_flag)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun int ret, i;
256*4882a593Smuzhiyun u8 check_sum;
257*4882a593Smuzhiyun u8 *input;
258*4882a593Smuzhiyun u8 *readbuf;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun input = kzalloc(U1_FEATURE_REPORT_LEN, GFP_KERNEL);
261*4882a593Smuzhiyun if (!input)
262*4882a593Smuzhiyun return -ENOMEM;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun input[0] = U1_FEATURE_REPORT_ID;
265*4882a593Smuzhiyun if (read_flag) {
266*4882a593Smuzhiyun input[1] = U1_CMD_REGISTER_READ;
267*4882a593Smuzhiyun input[6] = 0x00;
268*4882a593Smuzhiyun } else {
269*4882a593Smuzhiyun input[1] = U1_CMD_REGISTER_WRITE;
270*4882a593Smuzhiyun input[6] = write_val;
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun put_unaligned_le32(address, input + 2);
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun /* Calculate the checksum */
276*4882a593Smuzhiyun check_sum = U1_FEATURE_REPORT_LEN_ALL;
277*4882a593Smuzhiyun for (i = 0; i < U1_FEATURE_REPORT_LEN - 1; i++)
278*4882a593Smuzhiyun check_sum += input[i];
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun input[7] = check_sum;
281*4882a593Smuzhiyun ret = hid_hw_raw_request(hdev, U1_FEATURE_REPORT_ID, input,
282*4882a593Smuzhiyun U1_FEATURE_REPORT_LEN,
283*4882a593Smuzhiyun HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun if (ret < 0) {
286*4882a593Smuzhiyun dev_err(&hdev->dev, "failed to read command (%d)\n", ret);
287*4882a593Smuzhiyun goto exit;
288*4882a593Smuzhiyun }
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun if (read_flag) {
291*4882a593Smuzhiyun readbuf = kzalloc(U1_FEATURE_REPORT_LEN, GFP_KERNEL);
292*4882a593Smuzhiyun if (!readbuf) {
293*4882a593Smuzhiyun ret = -ENOMEM;
294*4882a593Smuzhiyun goto exit;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun ret = hid_hw_raw_request(hdev, U1_FEATURE_REPORT_ID, readbuf,
298*4882a593Smuzhiyun U1_FEATURE_REPORT_LEN,
299*4882a593Smuzhiyun HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun if (ret < 0) {
302*4882a593Smuzhiyun dev_err(&hdev->dev, "failed read register (%d)\n", ret);
303*4882a593Smuzhiyun kfree(readbuf);
304*4882a593Smuzhiyun goto exit;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun *read_val = readbuf[6];
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun kfree(readbuf);
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun ret = 0;
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun exit:
315*4882a593Smuzhiyun kfree(input);
316*4882a593Smuzhiyun return ret;
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun
t4_raw_event(struct alps_dev * hdata,u8 * data,int size)319*4882a593Smuzhiyun static int t4_raw_event(struct alps_dev *hdata, u8 *data, int size)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun unsigned int x, y, z;
322*4882a593Smuzhiyun int i;
323*4882a593Smuzhiyun struct t4_input_report *p_report = (struct t4_input_report *)data;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun if (!data)
326*4882a593Smuzhiyun return 0;
327*4882a593Smuzhiyun for (i = 0; i < hdata->max_fingers; i++) {
328*4882a593Smuzhiyun x = p_report->contact[i].x_hi << 8 | p_report->contact[i].x_lo;
329*4882a593Smuzhiyun y = p_report->contact[i].y_hi << 8 | p_report->contact[i].y_lo;
330*4882a593Smuzhiyun y = hdata->y_max - y + hdata->y_min;
331*4882a593Smuzhiyun z = (p_report->contact[i].palm < 0x80 &&
332*4882a593Smuzhiyun p_report->contact[i].palm > 0) * 62;
333*4882a593Smuzhiyun if (x == 0xffff) {
334*4882a593Smuzhiyun x = 0;
335*4882a593Smuzhiyun y = 0;
336*4882a593Smuzhiyun z = 0;
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun input_mt_slot(hdata->input, i);
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun input_mt_report_slot_state(hdata->input,
341*4882a593Smuzhiyun MT_TOOL_FINGER, z != 0);
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun if (!z)
344*4882a593Smuzhiyun continue;
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun input_report_abs(hdata->input, ABS_MT_POSITION_X, x);
347*4882a593Smuzhiyun input_report_abs(hdata->input, ABS_MT_POSITION_Y, y);
348*4882a593Smuzhiyun input_report_abs(hdata->input, ABS_MT_PRESSURE, z);
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun input_mt_sync_frame(hdata->input);
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun input_report_key(hdata->input, BTN_LEFT, p_report->button);
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun input_sync(hdata->input);
355*4882a593Smuzhiyun return 1;
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun
u1_raw_event(struct alps_dev * hdata,u8 * data,int size)358*4882a593Smuzhiyun static int u1_raw_event(struct alps_dev *hdata, u8 *data, int size)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun unsigned int x, y, z;
361*4882a593Smuzhiyun int i;
362*4882a593Smuzhiyun short sp_x, sp_y;
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun if (!data)
365*4882a593Smuzhiyun return 0;
366*4882a593Smuzhiyun switch (data[0]) {
367*4882a593Smuzhiyun case U1_MOUSE_REPORT_ID:
368*4882a593Smuzhiyun break;
369*4882a593Smuzhiyun case U1_FEATURE_REPORT_ID:
370*4882a593Smuzhiyun break;
371*4882a593Smuzhiyun case U1_ABSOLUTE_REPORT_ID:
372*4882a593Smuzhiyun case U1_ABSOLUTE_REPORT_ID_SECD:
373*4882a593Smuzhiyun for (i = 0; i < hdata->max_fingers; i++) {
374*4882a593Smuzhiyun u8 *contact = &data[i * 5];
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun x = get_unaligned_le16(contact + 3);
377*4882a593Smuzhiyun y = get_unaligned_le16(contact + 5);
378*4882a593Smuzhiyun z = contact[7] & 0x7F;
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun input_mt_slot(hdata->input, i);
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun if (z != 0) {
383*4882a593Smuzhiyun input_mt_report_slot_state(hdata->input,
384*4882a593Smuzhiyun MT_TOOL_FINGER, 1);
385*4882a593Smuzhiyun input_report_abs(hdata->input,
386*4882a593Smuzhiyun ABS_MT_POSITION_X, x);
387*4882a593Smuzhiyun input_report_abs(hdata->input,
388*4882a593Smuzhiyun ABS_MT_POSITION_Y, y);
389*4882a593Smuzhiyun input_report_abs(hdata->input,
390*4882a593Smuzhiyun ABS_MT_PRESSURE, z);
391*4882a593Smuzhiyun } else {
392*4882a593Smuzhiyun input_mt_report_slot_inactive(hdata->input);
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun input_mt_sync_frame(hdata->input);
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun input_report_key(hdata->input, BTN_LEFT,
399*4882a593Smuzhiyun data[1] & 0x1);
400*4882a593Smuzhiyun input_report_key(hdata->input, BTN_RIGHT,
401*4882a593Smuzhiyun (data[1] & 0x2));
402*4882a593Smuzhiyun input_report_key(hdata->input, BTN_MIDDLE,
403*4882a593Smuzhiyun (data[1] & 0x4));
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun input_sync(hdata->input);
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun return 1;
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun case U1_SP_ABSOLUTE_REPORT_ID:
410*4882a593Smuzhiyun sp_x = get_unaligned_le16(data+2);
411*4882a593Smuzhiyun sp_y = get_unaligned_le16(data+4);
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun sp_x = sp_x / 8;
414*4882a593Smuzhiyun sp_y = sp_y / 8;
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun input_report_rel(hdata->input2, REL_X, sp_x);
417*4882a593Smuzhiyun input_report_rel(hdata->input2, REL_Y, sp_y);
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun input_report_key(hdata->input2, BTN_LEFT,
420*4882a593Smuzhiyun data[1] & 0x1);
421*4882a593Smuzhiyun input_report_key(hdata->input2, BTN_RIGHT,
422*4882a593Smuzhiyun (data[1] & 0x2));
423*4882a593Smuzhiyun input_report_key(hdata->input2, BTN_MIDDLE,
424*4882a593Smuzhiyun (data[1] & 0x4));
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun input_sync(hdata->input2);
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun return 1;
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun return 0;
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun
alps_raw_event(struct hid_device * hdev,struct hid_report * report,u8 * data,int size)434*4882a593Smuzhiyun static int alps_raw_event(struct hid_device *hdev,
435*4882a593Smuzhiyun struct hid_report *report, u8 *data, int size)
436*4882a593Smuzhiyun {
437*4882a593Smuzhiyun int ret = 0;
438*4882a593Smuzhiyun struct alps_dev *hdata = hid_get_drvdata(hdev);
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun switch (hdev->product) {
441*4882a593Smuzhiyun case HID_PRODUCT_ID_T4_BTNLESS:
442*4882a593Smuzhiyun ret = t4_raw_event(hdata, data, size);
443*4882a593Smuzhiyun break;
444*4882a593Smuzhiyun default:
445*4882a593Smuzhiyun ret = u1_raw_event(hdata, data, size);
446*4882a593Smuzhiyun break;
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun return ret;
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun
alps_post_reset(struct hid_device * hdev)451*4882a593Smuzhiyun static int __maybe_unused alps_post_reset(struct hid_device *hdev)
452*4882a593Smuzhiyun {
453*4882a593Smuzhiyun int ret = -1;
454*4882a593Smuzhiyun struct alps_dev *data = hid_get_drvdata(hdev);
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun switch (data->dev_type) {
457*4882a593Smuzhiyun case T4:
458*4882a593Smuzhiyun ret = t4_read_write_register(hdev, T4_PRM_FEED_CONFIG_1,
459*4882a593Smuzhiyun NULL, T4_I2C_ABS, false);
460*4882a593Smuzhiyun if (ret < 0) {
461*4882a593Smuzhiyun dev_err(&hdev->dev, "failed T4_PRM_FEED_CONFIG_1 (%d)\n",
462*4882a593Smuzhiyun ret);
463*4882a593Smuzhiyun goto exit;
464*4882a593Smuzhiyun }
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun ret = t4_read_write_register(hdev, T4_PRM_FEED_CONFIG_4,
467*4882a593Smuzhiyun NULL, T4_FEEDCFG4_ADVANCED_ABS_ENABLE, false);
468*4882a593Smuzhiyun if (ret < 0) {
469*4882a593Smuzhiyun dev_err(&hdev->dev, "failed T4_PRM_FEED_CONFIG_4 (%d)\n",
470*4882a593Smuzhiyun ret);
471*4882a593Smuzhiyun goto exit;
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun break;
474*4882a593Smuzhiyun case U1:
475*4882a593Smuzhiyun ret = u1_read_write_register(hdev,
476*4882a593Smuzhiyun ADDRESS_U1_DEV_CTRL_1, NULL,
477*4882a593Smuzhiyun U1_TP_ABS_MODE | U1_SP_ABS_MODE, false);
478*4882a593Smuzhiyun if (ret < 0) {
479*4882a593Smuzhiyun dev_err(&hdev->dev, "failed to change TP mode (%d)\n",
480*4882a593Smuzhiyun ret);
481*4882a593Smuzhiyun goto exit;
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun break;
484*4882a593Smuzhiyun default:
485*4882a593Smuzhiyun break;
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun exit:
489*4882a593Smuzhiyun return ret;
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun
alps_post_resume(struct hid_device * hdev)492*4882a593Smuzhiyun static int __maybe_unused alps_post_resume(struct hid_device *hdev)
493*4882a593Smuzhiyun {
494*4882a593Smuzhiyun return alps_post_reset(hdev);
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun
u1_init(struct hid_device * hdev,struct alps_dev * pri_data)497*4882a593Smuzhiyun static int u1_init(struct hid_device *hdev, struct alps_dev *pri_data)
498*4882a593Smuzhiyun {
499*4882a593Smuzhiyun int ret;
500*4882a593Smuzhiyun u8 tmp, dev_ctrl, sen_line_num_x, sen_line_num_y;
501*4882a593Smuzhiyun u8 pitch_x, pitch_y, resolution;
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun /* Device initialization */
504*4882a593Smuzhiyun ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
505*4882a593Smuzhiyun &dev_ctrl, 0, true);
506*4882a593Smuzhiyun if (ret < 0) {
507*4882a593Smuzhiyun dev_err(&hdev->dev, "failed U1_DEV_CTRL_1 (%d)\n", ret);
508*4882a593Smuzhiyun goto exit;
509*4882a593Smuzhiyun }
510*4882a593Smuzhiyun
511*4882a593Smuzhiyun dev_ctrl &= ~U1_DISABLE_DEV;
512*4882a593Smuzhiyun dev_ctrl |= U1_TP_ABS_MODE;
513*4882a593Smuzhiyun ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
514*4882a593Smuzhiyun NULL, dev_ctrl, false);
515*4882a593Smuzhiyun if (ret < 0) {
516*4882a593Smuzhiyun dev_err(&hdev->dev, "failed to change TP mode (%d)\n", ret);
517*4882a593Smuzhiyun goto exit;
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun ret = u1_read_write_register(hdev, ADDRESS_U1_NUM_SENS_X,
521*4882a593Smuzhiyun &sen_line_num_x, 0, true);
522*4882a593Smuzhiyun if (ret < 0) {
523*4882a593Smuzhiyun dev_err(&hdev->dev, "failed U1_NUM_SENS_X (%d)\n", ret);
524*4882a593Smuzhiyun goto exit;
525*4882a593Smuzhiyun }
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun ret = u1_read_write_register(hdev, ADDRESS_U1_NUM_SENS_Y,
528*4882a593Smuzhiyun &sen_line_num_y, 0, true);
529*4882a593Smuzhiyun if (ret < 0) {
530*4882a593Smuzhiyun dev_err(&hdev->dev, "failed U1_NUM_SENS_Y (%d)\n", ret);
531*4882a593Smuzhiyun goto exit;
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun ret = u1_read_write_register(hdev, ADDRESS_U1_PITCH_SENS_X,
535*4882a593Smuzhiyun &pitch_x, 0, true);
536*4882a593Smuzhiyun if (ret < 0) {
537*4882a593Smuzhiyun dev_err(&hdev->dev, "failed U1_PITCH_SENS_X (%d)\n", ret);
538*4882a593Smuzhiyun goto exit;
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun ret = u1_read_write_register(hdev, ADDRESS_U1_PITCH_SENS_Y,
542*4882a593Smuzhiyun &pitch_y, 0, true);
543*4882a593Smuzhiyun if (ret < 0) {
544*4882a593Smuzhiyun dev_err(&hdev->dev, "failed U1_PITCH_SENS_Y (%d)\n", ret);
545*4882a593Smuzhiyun goto exit;
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun ret = u1_read_write_register(hdev, ADDRESS_U1_RESO_DWN_ABS,
549*4882a593Smuzhiyun &resolution, 0, true);
550*4882a593Smuzhiyun if (ret < 0) {
551*4882a593Smuzhiyun dev_err(&hdev->dev, "failed U1_RESO_DWN_ABS (%d)\n", ret);
552*4882a593Smuzhiyun goto exit;
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun pri_data->x_active_len_mm =
555*4882a593Smuzhiyun (pitch_x * (sen_line_num_x - 1)) / 10;
556*4882a593Smuzhiyun pri_data->y_active_len_mm =
557*4882a593Smuzhiyun (pitch_y * (sen_line_num_y - 1)) / 10;
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun pri_data->x_max =
560*4882a593Smuzhiyun (resolution << 2) * (sen_line_num_x - 1);
561*4882a593Smuzhiyun pri_data->x_min = 1;
562*4882a593Smuzhiyun pri_data->y_max =
563*4882a593Smuzhiyun (resolution << 2) * (sen_line_num_y - 1);
564*4882a593Smuzhiyun pri_data->y_min = 1;
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun ret = u1_read_write_register(hdev, ADDRESS_U1_PAD_BTN,
567*4882a593Smuzhiyun &tmp, 0, true);
568*4882a593Smuzhiyun if (ret < 0) {
569*4882a593Smuzhiyun dev_err(&hdev->dev, "failed U1_PAD_BTN (%d)\n", ret);
570*4882a593Smuzhiyun goto exit;
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun if ((tmp & 0x0F) == (tmp & 0xF0) >> 4) {
573*4882a593Smuzhiyun pri_data->btn_cnt = (tmp & 0x0F);
574*4882a593Smuzhiyun } else {
575*4882a593Smuzhiyun /* Button pad */
576*4882a593Smuzhiyun pri_data->btn_cnt = 1;
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun pri_data->has_sp = 0;
580*4882a593Smuzhiyun /* Check StickPointer device */
581*4882a593Smuzhiyun ret = u1_read_write_register(hdev, ADDRESS_U1_DEVICE_TYP,
582*4882a593Smuzhiyun &tmp, 0, true);
583*4882a593Smuzhiyun if (ret < 0) {
584*4882a593Smuzhiyun dev_err(&hdev->dev, "failed U1_DEVICE_TYP (%d)\n", ret);
585*4882a593Smuzhiyun goto exit;
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun if (tmp & U1_DEVTYPE_SP_SUPPORT) {
588*4882a593Smuzhiyun dev_ctrl |= U1_SP_ABS_MODE;
589*4882a593Smuzhiyun ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1,
590*4882a593Smuzhiyun NULL, dev_ctrl, false);
591*4882a593Smuzhiyun if (ret < 0) {
592*4882a593Smuzhiyun dev_err(&hdev->dev, "failed SP mode (%d)\n", ret);
593*4882a593Smuzhiyun goto exit;
594*4882a593Smuzhiyun }
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun ret = u1_read_write_register(hdev, ADDRESS_U1_SP_BTN,
597*4882a593Smuzhiyun &pri_data->sp_btn_info, 0, true);
598*4882a593Smuzhiyun if (ret < 0) {
599*4882a593Smuzhiyun dev_err(&hdev->dev, "failed U1_SP_BTN (%d)\n", ret);
600*4882a593Smuzhiyun goto exit;
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun pri_data->has_sp = 1;
603*4882a593Smuzhiyun }
604*4882a593Smuzhiyun pri_data->max_fingers = 5;
605*4882a593Smuzhiyun exit:
606*4882a593Smuzhiyun return ret;
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun
T4_init(struct hid_device * hdev,struct alps_dev * pri_data)609*4882a593Smuzhiyun static int T4_init(struct hid_device *hdev, struct alps_dev *pri_data)
610*4882a593Smuzhiyun {
611*4882a593Smuzhiyun int ret;
612*4882a593Smuzhiyun u8 tmp, sen_line_num_x, sen_line_num_y;
613*4882a593Smuzhiyun
614*4882a593Smuzhiyun ret = t4_read_write_register(hdev, T4_PRM_ID_CONFIG_3, &tmp, 0, true);
615*4882a593Smuzhiyun if (ret < 0) {
616*4882a593Smuzhiyun dev_err(&hdev->dev, "failed T4_PRM_ID_CONFIG_3 (%d)\n", ret);
617*4882a593Smuzhiyun goto exit;
618*4882a593Smuzhiyun }
619*4882a593Smuzhiyun sen_line_num_x = 16 + ((tmp & 0x0F) | (tmp & 0x08 ? 0xF0 : 0));
620*4882a593Smuzhiyun sen_line_num_y = 12 + (((tmp & 0xF0) >> 4) | (tmp & 0x80 ? 0xF0 : 0));
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun pri_data->x_max = sen_line_num_x * T4_COUNT_PER_ELECTRODE;
623*4882a593Smuzhiyun pri_data->x_min = T4_COUNT_PER_ELECTRODE;
624*4882a593Smuzhiyun pri_data->y_max = sen_line_num_y * T4_COUNT_PER_ELECTRODE;
625*4882a593Smuzhiyun pri_data->y_min = T4_COUNT_PER_ELECTRODE;
626*4882a593Smuzhiyun pri_data->x_active_len_mm = pri_data->y_active_len_mm = 0;
627*4882a593Smuzhiyun pri_data->btn_cnt = 1;
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun ret = t4_read_write_register(hdev, PRM_SYS_CONFIG_1, &tmp, 0, true);
630*4882a593Smuzhiyun if (ret < 0) {
631*4882a593Smuzhiyun dev_err(&hdev->dev, "failed PRM_SYS_CONFIG_1 (%d)\n", ret);
632*4882a593Smuzhiyun goto exit;
633*4882a593Smuzhiyun }
634*4882a593Smuzhiyun tmp |= 0x02;
635*4882a593Smuzhiyun ret = t4_read_write_register(hdev, PRM_SYS_CONFIG_1, NULL, tmp, false);
636*4882a593Smuzhiyun if (ret < 0) {
637*4882a593Smuzhiyun dev_err(&hdev->dev, "failed PRM_SYS_CONFIG_1 (%d)\n", ret);
638*4882a593Smuzhiyun goto exit;
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun
641*4882a593Smuzhiyun ret = t4_read_write_register(hdev, T4_PRM_FEED_CONFIG_1,
642*4882a593Smuzhiyun NULL, T4_I2C_ABS, false);
643*4882a593Smuzhiyun if (ret < 0) {
644*4882a593Smuzhiyun dev_err(&hdev->dev, "failed T4_PRM_FEED_CONFIG_1 (%d)\n", ret);
645*4882a593Smuzhiyun goto exit;
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun
648*4882a593Smuzhiyun ret = t4_read_write_register(hdev, T4_PRM_FEED_CONFIG_4, NULL,
649*4882a593Smuzhiyun T4_FEEDCFG4_ADVANCED_ABS_ENABLE, false);
650*4882a593Smuzhiyun if (ret < 0) {
651*4882a593Smuzhiyun dev_err(&hdev->dev, "failed T4_PRM_FEED_CONFIG_4 (%d)\n", ret);
652*4882a593Smuzhiyun goto exit;
653*4882a593Smuzhiyun }
654*4882a593Smuzhiyun pri_data->max_fingers = 5;
655*4882a593Smuzhiyun pri_data->has_sp = 0;
656*4882a593Smuzhiyun exit:
657*4882a593Smuzhiyun return ret;
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun
alps_sp_open(struct input_dev * dev)660*4882a593Smuzhiyun static int alps_sp_open(struct input_dev *dev)
661*4882a593Smuzhiyun {
662*4882a593Smuzhiyun struct hid_device *hid = input_get_drvdata(dev);
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun return hid_hw_open(hid);
665*4882a593Smuzhiyun }
666*4882a593Smuzhiyun
alps_sp_close(struct input_dev * dev)667*4882a593Smuzhiyun static void alps_sp_close(struct input_dev *dev)
668*4882a593Smuzhiyun {
669*4882a593Smuzhiyun struct hid_device *hid = input_get_drvdata(dev);
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun hid_hw_close(hid);
672*4882a593Smuzhiyun }
673*4882a593Smuzhiyun
alps_input_configured(struct hid_device * hdev,struct hid_input * hi)674*4882a593Smuzhiyun static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi)
675*4882a593Smuzhiyun {
676*4882a593Smuzhiyun struct alps_dev *data = hid_get_drvdata(hdev);
677*4882a593Smuzhiyun struct input_dev *input = hi->input, *input2;
678*4882a593Smuzhiyun int ret;
679*4882a593Smuzhiyun int res_x, res_y, i;
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun data->input = input;
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun hid_dbg(hdev, "Opening low level driver\n");
684*4882a593Smuzhiyun ret = hid_hw_open(hdev);
685*4882a593Smuzhiyun if (ret)
686*4882a593Smuzhiyun return ret;
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun /* Allow incoming hid reports */
689*4882a593Smuzhiyun hid_device_io_start(hdev);
690*4882a593Smuzhiyun switch (data->dev_type) {
691*4882a593Smuzhiyun case T4:
692*4882a593Smuzhiyun ret = T4_init(hdev, data);
693*4882a593Smuzhiyun break;
694*4882a593Smuzhiyun case U1:
695*4882a593Smuzhiyun ret = u1_init(hdev, data);
696*4882a593Smuzhiyun break;
697*4882a593Smuzhiyun default:
698*4882a593Smuzhiyun break;
699*4882a593Smuzhiyun }
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun if (ret)
702*4882a593Smuzhiyun goto exit;
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun __set_bit(EV_ABS, input->evbit);
705*4882a593Smuzhiyun input_set_abs_params(input, ABS_MT_POSITION_X,
706*4882a593Smuzhiyun data->x_min, data->x_max, 0, 0);
707*4882a593Smuzhiyun input_set_abs_params(input, ABS_MT_POSITION_Y,
708*4882a593Smuzhiyun data->y_min, data->y_max, 0, 0);
709*4882a593Smuzhiyun
710*4882a593Smuzhiyun if (data->x_active_len_mm && data->y_active_len_mm) {
711*4882a593Smuzhiyun res_x = (data->x_max - 1) / data->x_active_len_mm;
712*4882a593Smuzhiyun res_y = (data->y_max - 1) / data->y_active_len_mm;
713*4882a593Smuzhiyun
714*4882a593Smuzhiyun input_abs_set_res(input, ABS_MT_POSITION_X, res_x);
715*4882a593Smuzhiyun input_abs_set_res(input, ABS_MT_POSITION_Y, res_y);
716*4882a593Smuzhiyun }
717*4882a593Smuzhiyun
718*4882a593Smuzhiyun input_set_abs_params(input, ABS_MT_PRESSURE, 0, 64, 0, 0);
719*4882a593Smuzhiyun
720*4882a593Smuzhiyun input_mt_init_slots(input, data->max_fingers, INPUT_MT_POINTER);
721*4882a593Smuzhiyun
722*4882a593Smuzhiyun __set_bit(EV_KEY, input->evbit);
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun if (data->btn_cnt == 1)
725*4882a593Smuzhiyun __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
726*4882a593Smuzhiyun
727*4882a593Smuzhiyun for (i = 0; i < data->btn_cnt; i++)
728*4882a593Smuzhiyun __set_bit(BTN_LEFT + i, input->keybit);
729*4882a593Smuzhiyun
730*4882a593Smuzhiyun /* Stick device initialization */
731*4882a593Smuzhiyun if (data->has_sp) {
732*4882a593Smuzhiyun input2 = input_allocate_device();
733*4882a593Smuzhiyun if (!input2) {
734*4882a593Smuzhiyun ret = -ENOMEM;
735*4882a593Smuzhiyun goto exit;
736*4882a593Smuzhiyun }
737*4882a593Smuzhiyun
738*4882a593Smuzhiyun data->input2 = input2;
739*4882a593Smuzhiyun input2->phys = input->phys;
740*4882a593Smuzhiyun input2->name = "DualPoint Stick";
741*4882a593Smuzhiyun input2->id.bustype = BUS_I2C;
742*4882a593Smuzhiyun input2->id.vendor = input->id.vendor;
743*4882a593Smuzhiyun input2->id.product = input->id.product;
744*4882a593Smuzhiyun input2->id.version = input->id.version;
745*4882a593Smuzhiyun input2->dev.parent = input->dev.parent;
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun input_set_drvdata(input2, hdev);
748*4882a593Smuzhiyun input2->open = alps_sp_open;
749*4882a593Smuzhiyun input2->close = alps_sp_close;
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun __set_bit(EV_KEY, input2->evbit);
752*4882a593Smuzhiyun data->sp_btn_cnt = (data->sp_btn_info & 0x0F);
753*4882a593Smuzhiyun for (i = 0; i < data->sp_btn_cnt; i++)
754*4882a593Smuzhiyun __set_bit(BTN_LEFT + i, input2->keybit);
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun __set_bit(EV_REL, input2->evbit);
757*4882a593Smuzhiyun __set_bit(REL_X, input2->relbit);
758*4882a593Smuzhiyun __set_bit(REL_Y, input2->relbit);
759*4882a593Smuzhiyun __set_bit(INPUT_PROP_POINTER, input2->propbit);
760*4882a593Smuzhiyun __set_bit(INPUT_PROP_POINTING_STICK, input2->propbit);
761*4882a593Smuzhiyun
762*4882a593Smuzhiyun if (input_register_device(data->input2)) {
763*4882a593Smuzhiyun input_free_device(input2);
764*4882a593Smuzhiyun ret = -ENOENT;
765*4882a593Smuzhiyun goto exit;
766*4882a593Smuzhiyun }
767*4882a593Smuzhiyun }
768*4882a593Smuzhiyun
769*4882a593Smuzhiyun exit:
770*4882a593Smuzhiyun hid_device_io_stop(hdev);
771*4882a593Smuzhiyun hid_hw_close(hdev);
772*4882a593Smuzhiyun return ret;
773*4882a593Smuzhiyun }
774*4882a593Smuzhiyun
alps_input_mapping(struct hid_device * hdev,struct hid_input * hi,struct hid_field * field,struct hid_usage * usage,unsigned long ** bit,int * max)775*4882a593Smuzhiyun static int alps_input_mapping(struct hid_device *hdev,
776*4882a593Smuzhiyun struct hid_input *hi, struct hid_field *field,
777*4882a593Smuzhiyun struct hid_usage *usage, unsigned long **bit, int *max)
778*4882a593Smuzhiyun {
779*4882a593Smuzhiyun return -1;
780*4882a593Smuzhiyun }
781*4882a593Smuzhiyun
alps_probe(struct hid_device * hdev,const struct hid_device_id * id)782*4882a593Smuzhiyun static int alps_probe(struct hid_device *hdev, const struct hid_device_id *id)
783*4882a593Smuzhiyun {
784*4882a593Smuzhiyun struct alps_dev *data = NULL;
785*4882a593Smuzhiyun int ret;
786*4882a593Smuzhiyun data = devm_kzalloc(&hdev->dev, sizeof(struct alps_dev), GFP_KERNEL);
787*4882a593Smuzhiyun if (!data)
788*4882a593Smuzhiyun return -ENOMEM;
789*4882a593Smuzhiyun
790*4882a593Smuzhiyun data->hdev = hdev;
791*4882a593Smuzhiyun hid_set_drvdata(hdev, data);
792*4882a593Smuzhiyun
793*4882a593Smuzhiyun hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
794*4882a593Smuzhiyun
795*4882a593Smuzhiyun ret = hid_parse(hdev);
796*4882a593Smuzhiyun if (ret) {
797*4882a593Smuzhiyun hid_err(hdev, "parse failed\n");
798*4882a593Smuzhiyun return ret;
799*4882a593Smuzhiyun }
800*4882a593Smuzhiyun
801*4882a593Smuzhiyun switch (hdev->product) {
802*4882a593Smuzhiyun case HID_DEVICE_ID_ALPS_T4_BTNLESS:
803*4882a593Smuzhiyun data->dev_type = T4;
804*4882a593Smuzhiyun break;
805*4882a593Smuzhiyun case HID_DEVICE_ID_ALPS_U1_DUAL:
806*4882a593Smuzhiyun case HID_DEVICE_ID_ALPS_U1:
807*4882a593Smuzhiyun case HID_DEVICE_ID_ALPS_U1_UNICORN_LEGACY:
808*4882a593Smuzhiyun data->dev_type = U1;
809*4882a593Smuzhiyun break;
810*4882a593Smuzhiyun default:
811*4882a593Smuzhiyun data->dev_type = UNKNOWN;
812*4882a593Smuzhiyun }
813*4882a593Smuzhiyun
814*4882a593Smuzhiyun ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
815*4882a593Smuzhiyun if (ret) {
816*4882a593Smuzhiyun hid_err(hdev, "hw start failed\n");
817*4882a593Smuzhiyun return ret;
818*4882a593Smuzhiyun }
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun return 0;
821*4882a593Smuzhiyun }
822*4882a593Smuzhiyun
alps_remove(struct hid_device * hdev)823*4882a593Smuzhiyun static void alps_remove(struct hid_device *hdev)
824*4882a593Smuzhiyun {
825*4882a593Smuzhiyun hid_hw_stop(hdev);
826*4882a593Smuzhiyun }
827*4882a593Smuzhiyun
828*4882a593Smuzhiyun static const struct hid_device_id alps_id[] = {
829*4882a593Smuzhiyun { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY,
830*4882a593Smuzhiyun USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_DUAL) },
831*4882a593Smuzhiyun { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY,
832*4882a593Smuzhiyun USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1) },
833*4882a593Smuzhiyun { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY,
834*4882a593Smuzhiyun USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_UNICORN_LEGACY) },
835*4882a593Smuzhiyun { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY,
836*4882a593Smuzhiyun USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_T4_BTNLESS) },
837*4882a593Smuzhiyun { }
838*4882a593Smuzhiyun };
839*4882a593Smuzhiyun MODULE_DEVICE_TABLE(hid, alps_id);
840*4882a593Smuzhiyun
841*4882a593Smuzhiyun static struct hid_driver alps_driver = {
842*4882a593Smuzhiyun .name = "hid-alps",
843*4882a593Smuzhiyun .id_table = alps_id,
844*4882a593Smuzhiyun .probe = alps_probe,
845*4882a593Smuzhiyun .remove = alps_remove,
846*4882a593Smuzhiyun .raw_event = alps_raw_event,
847*4882a593Smuzhiyun .input_mapping = alps_input_mapping,
848*4882a593Smuzhiyun .input_configured = alps_input_configured,
849*4882a593Smuzhiyun #ifdef CONFIG_PM
850*4882a593Smuzhiyun .resume = alps_post_resume,
851*4882a593Smuzhiyun .reset_resume = alps_post_reset,
852*4882a593Smuzhiyun #endif
853*4882a593Smuzhiyun };
854*4882a593Smuzhiyun
855*4882a593Smuzhiyun module_hid_driver(alps_driver);
856*4882a593Smuzhiyun
857*4882a593Smuzhiyun MODULE_AUTHOR("Masaki Ota <masaki.ota@jp.alps.com>");
858*4882a593Smuzhiyun MODULE_DESCRIPTION("ALPS HID driver");
859*4882a593Smuzhiyun MODULE_LICENSE("GPL");
860