xref: /OK3568_Linux_fs/kernel/drivers/hid/hid-alps.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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