xref: /OK3568_Linux_fs/kernel/drivers/input/misc/ad714x.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * AD714X CapTouch Programmable Controller driver supporting AD7142/3/7/8/7A
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright 2009-2011 Analog Devices Inc.
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/device.h>
9*4882a593Smuzhiyun #include <linux/input.h>
10*4882a593Smuzhiyun #include <linux/interrupt.h>
11*4882a593Smuzhiyun #include <linux/slab.h>
12*4882a593Smuzhiyun #include <linux/input/ad714x.h>
13*4882a593Smuzhiyun #include <linux/module.h>
14*4882a593Smuzhiyun #include "ad714x.h"
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #define AD714X_PWR_CTRL           0x0
17*4882a593Smuzhiyun #define AD714X_STG_CAL_EN_REG     0x1
18*4882a593Smuzhiyun #define AD714X_AMB_COMP_CTRL0_REG 0x2
19*4882a593Smuzhiyun #define AD714X_PARTID_REG         0x17
20*4882a593Smuzhiyun #define AD7142_PARTID             0xE620
21*4882a593Smuzhiyun #define AD7143_PARTID             0xE630
22*4882a593Smuzhiyun #define AD7147_PARTID             0x1470
23*4882a593Smuzhiyun #define AD7148_PARTID             0x1480
24*4882a593Smuzhiyun #define AD714X_STAGECFG_REG       0x80
25*4882a593Smuzhiyun #define AD714X_SYSCFG_REG         0x0
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #define STG_LOW_INT_EN_REG     0x5
28*4882a593Smuzhiyun #define STG_HIGH_INT_EN_REG    0x6
29*4882a593Smuzhiyun #define STG_COM_INT_EN_REG     0x7
30*4882a593Smuzhiyun #define STG_LOW_INT_STA_REG    0x8
31*4882a593Smuzhiyun #define STG_HIGH_INT_STA_REG   0x9
32*4882a593Smuzhiyun #define STG_COM_INT_STA_REG    0xA
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #define CDC_RESULT_S0          0xB
35*4882a593Smuzhiyun #define CDC_RESULT_S1          0xC
36*4882a593Smuzhiyun #define CDC_RESULT_S2          0xD
37*4882a593Smuzhiyun #define CDC_RESULT_S3          0xE
38*4882a593Smuzhiyun #define CDC_RESULT_S4          0xF
39*4882a593Smuzhiyun #define CDC_RESULT_S5          0x10
40*4882a593Smuzhiyun #define CDC_RESULT_S6          0x11
41*4882a593Smuzhiyun #define CDC_RESULT_S7          0x12
42*4882a593Smuzhiyun #define CDC_RESULT_S8          0x13
43*4882a593Smuzhiyun #define CDC_RESULT_S9          0x14
44*4882a593Smuzhiyun #define CDC_RESULT_S10         0x15
45*4882a593Smuzhiyun #define CDC_RESULT_S11         0x16
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun #define STAGE0_AMBIENT		0xF1
48*4882a593Smuzhiyun #define STAGE1_AMBIENT		0x115
49*4882a593Smuzhiyun #define STAGE2_AMBIENT		0x139
50*4882a593Smuzhiyun #define STAGE3_AMBIENT		0x15D
51*4882a593Smuzhiyun #define STAGE4_AMBIENT		0x181
52*4882a593Smuzhiyun #define STAGE5_AMBIENT		0x1A5
53*4882a593Smuzhiyun #define STAGE6_AMBIENT		0x1C9
54*4882a593Smuzhiyun #define STAGE7_AMBIENT		0x1ED
55*4882a593Smuzhiyun #define STAGE8_AMBIENT		0x211
56*4882a593Smuzhiyun #define STAGE9_AMBIENT		0x234
57*4882a593Smuzhiyun #define STAGE10_AMBIENT		0x259
58*4882a593Smuzhiyun #define STAGE11_AMBIENT		0x27D
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun #define PER_STAGE_REG_NUM      36
61*4882a593Smuzhiyun #define STAGE_CFGREG_NUM       8
62*4882a593Smuzhiyun #define SYS_CFGREG_NUM         8
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun /*
65*4882a593Smuzhiyun  * driver information which will be used to maintain the software flow
66*4882a593Smuzhiyun  */
67*4882a593Smuzhiyun enum ad714x_device_state { IDLE, JITTER, ACTIVE, SPACE };
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun struct ad714x_slider_drv {
70*4882a593Smuzhiyun 	int highest_stage;
71*4882a593Smuzhiyun 	int abs_pos;
72*4882a593Smuzhiyun 	int flt_pos;
73*4882a593Smuzhiyun 	enum ad714x_device_state state;
74*4882a593Smuzhiyun 	struct input_dev *input;
75*4882a593Smuzhiyun };
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun struct ad714x_wheel_drv {
78*4882a593Smuzhiyun 	int abs_pos;
79*4882a593Smuzhiyun 	int flt_pos;
80*4882a593Smuzhiyun 	int pre_highest_stage;
81*4882a593Smuzhiyun 	int highest_stage;
82*4882a593Smuzhiyun 	enum ad714x_device_state state;
83*4882a593Smuzhiyun 	struct input_dev *input;
84*4882a593Smuzhiyun };
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun struct ad714x_touchpad_drv {
87*4882a593Smuzhiyun 	int x_highest_stage;
88*4882a593Smuzhiyun 	int x_flt_pos;
89*4882a593Smuzhiyun 	int x_abs_pos;
90*4882a593Smuzhiyun 	int y_highest_stage;
91*4882a593Smuzhiyun 	int y_flt_pos;
92*4882a593Smuzhiyun 	int y_abs_pos;
93*4882a593Smuzhiyun 	int left_ep;
94*4882a593Smuzhiyun 	int left_ep_val;
95*4882a593Smuzhiyun 	int right_ep;
96*4882a593Smuzhiyun 	int right_ep_val;
97*4882a593Smuzhiyun 	int top_ep;
98*4882a593Smuzhiyun 	int top_ep_val;
99*4882a593Smuzhiyun 	int bottom_ep;
100*4882a593Smuzhiyun 	int bottom_ep_val;
101*4882a593Smuzhiyun 	enum ad714x_device_state state;
102*4882a593Smuzhiyun 	struct input_dev *input;
103*4882a593Smuzhiyun };
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun struct ad714x_button_drv {
106*4882a593Smuzhiyun 	enum ad714x_device_state state;
107*4882a593Smuzhiyun 	/*
108*4882a593Smuzhiyun 	 * Unlike slider/wheel/touchpad, all buttons point to
109*4882a593Smuzhiyun 	 * same input_dev instance
110*4882a593Smuzhiyun 	 */
111*4882a593Smuzhiyun 	struct input_dev *input;
112*4882a593Smuzhiyun };
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun struct ad714x_driver_data {
115*4882a593Smuzhiyun 	struct ad714x_slider_drv *slider;
116*4882a593Smuzhiyun 	struct ad714x_wheel_drv *wheel;
117*4882a593Smuzhiyun 	struct ad714x_touchpad_drv *touchpad;
118*4882a593Smuzhiyun 	struct ad714x_button_drv *button;
119*4882a593Smuzhiyun };
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun /*
122*4882a593Smuzhiyun  * information to integrate all things which will be private data
123*4882a593Smuzhiyun  * of spi/i2c device
124*4882a593Smuzhiyun  */
125*4882a593Smuzhiyun 
ad714x_use_com_int(struct ad714x_chip * ad714x,int start_stage,int end_stage)126*4882a593Smuzhiyun static void ad714x_use_com_int(struct ad714x_chip *ad714x,
127*4882a593Smuzhiyun 				int start_stage, int end_stage)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun 	unsigned short data;
130*4882a593Smuzhiyun 	unsigned short mask;
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	ad714x->read(ad714x, STG_COM_INT_EN_REG, &data, 1);
135*4882a593Smuzhiyun 	data |= 1 << end_stage;
136*4882a593Smuzhiyun 	ad714x->write(ad714x, STG_COM_INT_EN_REG, data);
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	ad714x->read(ad714x, STG_HIGH_INT_EN_REG, &data, 1);
139*4882a593Smuzhiyun 	data &= ~mask;
140*4882a593Smuzhiyun 	ad714x->write(ad714x, STG_HIGH_INT_EN_REG, data);
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun 
ad714x_use_thr_int(struct ad714x_chip * ad714x,int start_stage,int end_stage)143*4882a593Smuzhiyun static void ad714x_use_thr_int(struct ad714x_chip *ad714x,
144*4882a593Smuzhiyun 				int start_stage, int end_stage)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	unsigned short data;
147*4882a593Smuzhiyun 	unsigned short mask;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	ad714x->read(ad714x, STG_COM_INT_EN_REG, &data, 1);
152*4882a593Smuzhiyun 	data &= ~(1 << end_stage);
153*4882a593Smuzhiyun 	ad714x->write(ad714x, STG_COM_INT_EN_REG, data);
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	ad714x->read(ad714x, STG_HIGH_INT_EN_REG, &data, 1);
156*4882a593Smuzhiyun 	data |= mask;
157*4882a593Smuzhiyun 	ad714x->write(ad714x, STG_HIGH_INT_EN_REG, data);
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun 
ad714x_cal_highest_stage(struct ad714x_chip * ad714x,int start_stage,int end_stage)160*4882a593Smuzhiyun static int ad714x_cal_highest_stage(struct ad714x_chip *ad714x,
161*4882a593Smuzhiyun 					int start_stage, int end_stage)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun 	int max_res = 0;
164*4882a593Smuzhiyun 	int max_idx = 0;
165*4882a593Smuzhiyun 	int i;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	for (i = start_stage; i <= end_stage; i++) {
168*4882a593Smuzhiyun 		if (ad714x->sensor_val[i] > max_res) {
169*4882a593Smuzhiyun 			max_res = ad714x->sensor_val[i];
170*4882a593Smuzhiyun 			max_idx = i;
171*4882a593Smuzhiyun 		}
172*4882a593Smuzhiyun 	}
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	return max_idx;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun 
ad714x_cal_abs_pos(struct ad714x_chip * ad714x,int start_stage,int end_stage,int highest_stage,int max_coord)177*4882a593Smuzhiyun static int ad714x_cal_abs_pos(struct ad714x_chip *ad714x,
178*4882a593Smuzhiyun 				int start_stage, int end_stage,
179*4882a593Smuzhiyun 				int highest_stage, int max_coord)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun 	int a_param, b_param;
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	if (highest_stage == start_stage) {
184*4882a593Smuzhiyun 		a_param = ad714x->sensor_val[start_stage + 1];
185*4882a593Smuzhiyun 		b_param = ad714x->sensor_val[start_stage] +
186*4882a593Smuzhiyun 			ad714x->sensor_val[start_stage + 1];
187*4882a593Smuzhiyun 	} else if (highest_stage == end_stage) {
188*4882a593Smuzhiyun 		a_param = ad714x->sensor_val[end_stage] *
189*4882a593Smuzhiyun 			(end_stage - start_stage) +
190*4882a593Smuzhiyun 			ad714x->sensor_val[end_stage - 1] *
191*4882a593Smuzhiyun 			(end_stage - start_stage - 1);
192*4882a593Smuzhiyun 		b_param = ad714x->sensor_val[end_stage] +
193*4882a593Smuzhiyun 			ad714x->sensor_val[end_stage - 1];
194*4882a593Smuzhiyun 	} else {
195*4882a593Smuzhiyun 		a_param = ad714x->sensor_val[highest_stage] *
196*4882a593Smuzhiyun 			(highest_stage - start_stage) +
197*4882a593Smuzhiyun 			ad714x->sensor_val[highest_stage - 1] *
198*4882a593Smuzhiyun 			(highest_stage - start_stage - 1) +
199*4882a593Smuzhiyun 			ad714x->sensor_val[highest_stage + 1] *
200*4882a593Smuzhiyun 			(highest_stage - start_stage + 1);
201*4882a593Smuzhiyun 		b_param = ad714x->sensor_val[highest_stage] +
202*4882a593Smuzhiyun 			ad714x->sensor_val[highest_stage - 1] +
203*4882a593Smuzhiyun 			ad714x->sensor_val[highest_stage + 1];
204*4882a593Smuzhiyun 	}
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	return (max_coord / (end_stage - start_stage)) * a_param / b_param;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun /*
210*4882a593Smuzhiyun  * One button can connect to multi positive and negative of CDCs
211*4882a593Smuzhiyun  * Multi-buttons can connect to same positive/negative of one CDC
212*4882a593Smuzhiyun  */
ad714x_button_state_machine(struct ad714x_chip * ad714x,int idx)213*4882a593Smuzhiyun static void ad714x_button_state_machine(struct ad714x_chip *ad714x, int idx)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun 	struct ad714x_button_plat *hw = &ad714x->hw->button[idx];
216*4882a593Smuzhiyun 	struct ad714x_button_drv *sw = &ad714x->sw->button[idx];
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	switch (sw->state) {
219*4882a593Smuzhiyun 	case IDLE:
220*4882a593Smuzhiyun 		if (((ad714x->h_state & hw->h_mask) == hw->h_mask) &&
221*4882a593Smuzhiyun 		    ((ad714x->l_state & hw->l_mask) == hw->l_mask)) {
222*4882a593Smuzhiyun 			dev_dbg(ad714x->dev, "button %d touched\n", idx);
223*4882a593Smuzhiyun 			input_report_key(sw->input, hw->keycode, 1);
224*4882a593Smuzhiyun 			input_sync(sw->input);
225*4882a593Smuzhiyun 			sw->state = ACTIVE;
226*4882a593Smuzhiyun 		}
227*4882a593Smuzhiyun 		break;
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	case ACTIVE:
230*4882a593Smuzhiyun 		if (((ad714x->h_state & hw->h_mask) != hw->h_mask) ||
231*4882a593Smuzhiyun 		    ((ad714x->l_state & hw->l_mask) != hw->l_mask)) {
232*4882a593Smuzhiyun 			dev_dbg(ad714x->dev, "button %d released\n", idx);
233*4882a593Smuzhiyun 			input_report_key(sw->input, hw->keycode, 0);
234*4882a593Smuzhiyun 			input_sync(sw->input);
235*4882a593Smuzhiyun 			sw->state = IDLE;
236*4882a593Smuzhiyun 		}
237*4882a593Smuzhiyun 		break;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	default:
240*4882a593Smuzhiyun 		break;
241*4882a593Smuzhiyun 	}
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun /*
245*4882a593Smuzhiyun  * The response of a sensor is defined by the absolute number of codes
246*4882a593Smuzhiyun  * between the current CDC value and the ambient value.
247*4882a593Smuzhiyun  */
ad714x_slider_cal_sensor_val(struct ad714x_chip * ad714x,int idx)248*4882a593Smuzhiyun static void ad714x_slider_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun 	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
251*4882a593Smuzhiyun 	int i;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	ad714x->read(ad714x, CDC_RESULT_S0 + hw->start_stage,
254*4882a593Smuzhiyun 			&ad714x->adc_reg[hw->start_stage],
255*4882a593Smuzhiyun 			hw->end_stage - hw->start_stage + 1);
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	for (i = hw->start_stage; i <= hw->end_stage; i++) {
258*4882a593Smuzhiyun 		ad714x->read(ad714x, STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
259*4882a593Smuzhiyun 				&ad714x->amb_reg[i], 1);
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 		ad714x->sensor_val[i] =
262*4882a593Smuzhiyun 			abs(ad714x->adc_reg[i] - ad714x->amb_reg[i]);
263*4882a593Smuzhiyun 	}
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun 
ad714x_slider_cal_highest_stage(struct ad714x_chip * ad714x,int idx)266*4882a593Smuzhiyun static void ad714x_slider_cal_highest_stage(struct ad714x_chip *ad714x, int idx)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun 	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
269*4882a593Smuzhiyun 	struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx];
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	sw->highest_stage = ad714x_cal_highest_stage(ad714x, hw->start_stage,
272*4882a593Smuzhiyun 			hw->end_stage);
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	dev_dbg(ad714x->dev, "slider %d highest_stage:%d\n", idx,
275*4882a593Smuzhiyun 		sw->highest_stage);
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun /*
279*4882a593Smuzhiyun  * The formulae are very straight forward. It uses the sensor with the
280*4882a593Smuzhiyun  * highest response and the 2 adjacent ones.
281*4882a593Smuzhiyun  * When Sensor 0 has the highest response, only sensor 0 and sensor 1
282*4882a593Smuzhiyun  * are used in the calculations. Similarly when the last sensor has the
283*4882a593Smuzhiyun  * highest response, only the last sensor and the second last sensors
284*4882a593Smuzhiyun  * are used in the calculations.
285*4882a593Smuzhiyun  *
286*4882a593Smuzhiyun  * For i= idx_of_peak_Sensor-1 to i= idx_of_peak_Sensor+1
287*4882a593Smuzhiyun  *         v += Sensor response(i)*i
288*4882a593Smuzhiyun  *         w += Sensor response(i)
289*4882a593Smuzhiyun  * POS=(Number_of_Positions_Wanted/(Number_of_Sensors_Used-1)) *(v/w)
290*4882a593Smuzhiyun  */
ad714x_slider_cal_abs_pos(struct ad714x_chip * ad714x,int idx)291*4882a593Smuzhiyun static void ad714x_slider_cal_abs_pos(struct ad714x_chip *ad714x, int idx)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun 	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
294*4882a593Smuzhiyun 	struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx];
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	sw->abs_pos = ad714x_cal_abs_pos(ad714x, hw->start_stage, hw->end_stage,
297*4882a593Smuzhiyun 		sw->highest_stage, hw->max_coord);
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	dev_dbg(ad714x->dev, "slider %d absolute position:%d\n", idx,
300*4882a593Smuzhiyun 		sw->abs_pos);
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun /*
304*4882a593Smuzhiyun  * To minimise the Impact of the noise on the algorithm, ADI developed a
305*4882a593Smuzhiyun  * routine that filters the CDC results after they have been read by the
306*4882a593Smuzhiyun  * host processor.
307*4882a593Smuzhiyun  * The filter used is an Infinite Input Response(IIR) filter implemented
308*4882a593Smuzhiyun  * in firmware and attenuates the noise on the CDC results after they've
309*4882a593Smuzhiyun  * been read by the host processor.
310*4882a593Smuzhiyun  * Filtered_CDC_result = (Filtered_CDC_result * (10 - Coefficient) +
311*4882a593Smuzhiyun  *				Latest_CDC_result * Coefficient)/10
312*4882a593Smuzhiyun  */
ad714x_slider_cal_flt_pos(struct ad714x_chip * ad714x,int idx)313*4882a593Smuzhiyun static void ad714x_slider_cal_flt_pos(struct ad714x_chip *ad714x, int idx)
314*4882a593Smuzhiyun {
315*4882a593Smuzhiyun 	struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx];
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	sw->flt_pos = (sw->flt_pos * (10 - 4) +
318*4882a593Smuzhiyun 			sw->abs_pos * 4)/10;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	dev_dbg(ad714x->dev, "slider %d filter position:%d\n", idx,
321*4882a593Smuzhiyun 		sw->flt_pos);
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun 
ad714x_slider_use_com_int(struct ad714x_chip * ad714x,int idx)324*4882a593Smuzhiyun static void ad714x_slider_use_com_int(struct ad714x_chip *ad714x, int idx)
325*4882a593Smuzhiyun {
326*4882a593Smuzhiyun 	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	ad714x_use_com_int(ad714x, hw->start_stage, hw->end_stage);
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun 
ad714x_slider_use_thr_int(struct ad714x_chip * ad714x,int idx)331*4882a593Smuzhiyun static void ad714x_slider_use_thr_int(struct ad714x_chip *ad714x, int idx)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun 	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	ad714x_use_thr_int(ad714x, hw->start_stage, hw->end_stage);
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun 
ad714x_slider_state_machine(struct ad714x_chip * ad714x,int idx)338*4882a593Smuzhiyun static void ad714x_slider_state_machine(struct ad714x_chip *ad714x, int idx)
339*4882a593Smuzhiyun {
340*4882a593Smuzhiyun 	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
341*4882a593Smuzhiyun 	struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx];
342*4882a593Smuzhiyun 	unsigned short h_state, c_state;
343*4882a593Smuzhiyun 	unsigned short mask;
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	mask = ((1 << (hw->end_stage + 1)) - 1) - ((1 << hw->start_stage) - 1);
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	h_state = ad714x->h_state & mask;
348*4882a593Smuzhiyun 	c_state = ad714x->c_state & mask;
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	switch (sw->state) {
351*4882a593Smuzhiyun 	case IDLE:
352*4882a593Smuzhiyun 		if (h_state) {
353*4882a593Smuzhiyun 			sw->state = JITTER;
354*4882a593Smuzhiyun 			/* In End of Conversion interrupt mode, the AD714X
355*4882a593Smuzhiyun 			 * continuously generates hardware interrupts.
356*4882a593Smuzhiyun 			 */
357*4882a593Smuzhiyun 			ad714x_slider_use_com_int(ad714x, idx);
358*4882a593Smuzhiyun 			dev_dbg(ad714x->dev, "slider %d touched\n", idx);
359*4882a593Smuzhiyun 		}
360*4882a593Smuzhiyun 		break;
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	case JITTER:
363*4882a593Smuzhiyun 		if (c_state == mask) {
364*4882a593Smuzhiyun 			ad714x_slider_cal_sensor_val(ad714x, idx);
365*4882a593Smuzhiyun 			ad714x_slider_cal_highest_stage(ad714x, idx);
366*4882a593Smuzhiyun 			ad714x_slider_cal_abs_pos(ad714x, idx);
367*4882a593Smuzhiyun 			sw->flt_pos = sw->abs_pos;
368*4882a593Smuzhiyun 			sw->state = ACTIVE;
369*4882a593Smuzhiyun 		}
370*4882a593Smuzhiyun 		break;
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	case ACTIVE:
373*4882a593Smuzhiyun 		if (c_state == mask) {
374*4882a593Smuzhiyun 			if (h_state) {
375*4882a593Smuzhiyun 				ad714x_slider_cal_sensor_val(ad714x, idx);
376*4882a593Smuzhiyun 				ad714x_slider_cal_highest_stage(ad714x, idx);
377*4882a593Smuzhiyun 				ad714x_slider_cal_abs_pos(ad714x, idx);
378*4882a593Smuzhiyun 				ad714x_slider_cal_flt_pos(ad714x, idx);
379*4882a593Smuzhiyun 				input_report_abs(sw->input, ABS_X, sw->flt_pos);
380*4882a593Smuzhiyun 				input_report_key(sw->input, BTN_TOUCH, 1);
381*4882a593Smuzhiyun 			} else {
382*4882a593Smuzhiyun 				/* When the user lifts off the sensor, configure
383*4882a593Smuzhiyun 				 * the AD714X back to threshold interrupt mode.
384*4882a593Smuzhiyun 				 */
385*4882a593Smuzhiyun 				ad714x_slider_use_thr_int(ad714x, idx);
386*4882a593Smuzhiyun 				sw->state = IDLE;
387*4882a593Smuzhiyun 				input_report_key(sw->input, BTN_TOUCH, 0);
388*4882a593Smuzhiyun 				dev_dbg(ad714x->dev, "slider %d released\n",
389*4882a593Smuzhiyun 					idx);
390*4882a593Smuzhiyun 			}
391*4882a593Smuzhiyun 			input_sync(sw->input);
392*4882a593Smuzhiyun 		}
393*4882a593Smuzhiyun 		break;
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	default:
396*4882a593Smuzhiyun 		break;
397*4882a593Smuzhiyun 	}
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun /*
401*4882a593Smuzhiyun  * When the scroll wheel is activated, we compute the absolute position based
402*4882a593Smuzhiyun  * on the sensor values. To calculate the position, we first determine the
403*4882a593Smuzhiyun  * sensor that has the greatest response among the 8 sensors that constitutes
404*4882a593Smuzhiyun  * the scrollwheel. Then we determined the 2 sensors on either sides of the
405*4882a593Smuzhiyun  * sensor with the highest response and we apply weights to these sensors.
406*4882a593Smuzhiyun  */
ad714x_wheel_cal_highest_stage(struct ad714x_chip * ad714x,int idx)407*4882a593Smuzhiyun static void ad714x_wheel_cal_highest_stage(struct ad714x_chip *ad714x, int idx)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun 	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
410*4882a593Smuzhiyun 	struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	sw->pre_highest_stage = sw->highest_stage;
413*4882a593Smuzhiyun 	sw->highest_stage = ad714x_cal_highest_stage(ad714x, hw->start_stage,
414*4882a593Smuzhiyun 			hw->end_stage);
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	dev_dbg(ad714x->dev, "wheel %d highest_stage:%d\n", idx,
417*4882a593Smuzhiyun 		sw->highest_stage);
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun 
ad714x_wheel_cal_sensor_val(struct ad714x_chip * ad714x,int idx)420*4882a593Smuzhiyun static void ad714x_wheel_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
421*4882a593Smuzhiyun {
422*4882a593Smuzhiyun 	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
423*4882a593Smuzhiyun 	int i;
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	ad714x->read(ad714x, CDC_RESULT_S0 + hw->start_stage,
426*4882a593Smuzhiyun 			&ad714x->adc_reg[hw->start_stage],
427*4882a593Smuzhiyun 			hw->end_stage - hw->start_stage + 1);
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	for (i = hw->start_stage; i <= hw->end_stage; i++) {
430*4882a593Smuzhiyun 		ad714x->read(ad714x, STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
431*4882a593Smuzhiyun 				&ad714x->amb_reg[i], 1);
432*4882a593Smuzhiyun 		if (ad714x->adc_reg[i] > ad714x->amb_reg[i])
433*4882a593Smuzhiyun 			ad714x->sensor_val[i] =
434*4882a593Smuzhiyun 				ad714x->adc_reg[i] - ad714x->amb_reg[i];
435*4882a593Smuzhiyun 		else
436*4882a593Smuzhiyun 			ad714x->sensor_val[i] = 0;
437*4882a593Smuzhiyun 	}
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun /*
441*4882a593Smuzhiyun  * When the scroll wheel is activated, we compute the absolute position based
442*4882a593Smuzhiyun  * on the sensor values. To calculate the position, we first determine the
443*4882a593Smuzhiyun  * sensor that has the greatest response among the sensors that constitutes
444*4882a593Smuzhiyun  * the scrollwheel. Then we determined the sensors on either sides of the
445*4882a593Smuzhiyun  * sensor with the highest response and we apply weights to these sensors. The
446*4882a593Smuzhiyun  * result of this computation gives us the mean value.
447*4882a593Smuzhiyun  */
448*4882a593Smuzhiyun 
ad714x_wheel_cal_abs_pos(struct ad714x_chip * ad714x,int idx)449*4882a593Smuzhiyun static void ad714x_wheel_cal_abs_pos(struct ad714x_chip *ad714x, int idx)
450*4882a593Smuzhiyun {
451*4882a593Smuzhiyun 	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
452*4882a593Smuzhiyun 	struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
453*4882a593Smuzhiyun 	int stage_num = hw->end_stage - hw->start_stage + 1;
454*4882a593Smuzhiyun 	int first_before, highest, first_after;
455*4882a593Smuzhiyun 	int a_param, b_param;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	first_before = (sw->highest_stage + stage_num - 1) % stage_num;
458*4882a593Smuzhiyun 	highest = sw->highest_stage;
459*4882a593Smuzhiyun 	first_after = (sw->highest_stage + stage_num + 1) % stage_num;
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	a_param = ad714x->sensor_val[highest] *
462*4882a593Smuzhiyun 		(highest - hw->start_stage) +
463*4882a593Smuzhiyun 		ad714x->sensor_val[first_before] *
464*4882a593Smuzhiyun 		(highest - hw->start_stage - 1) +
465*4882a593Smuzhiyun 		ad714x->sensor_val[first_after] *
466*4882a593Smuzhiyun 		(highest - hw->start_stage + 1);
467*4882a593Smuzhiyun 	b_param = ad714x->sensor_val[highest] +
468*4882a593Smuzhiyun 		ad714x->sensor_val[first_before] +
469*4882a593Smuzhiyun 		ad714x->sensor_val[first_after];
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	sw->abs_pos = ((hw->max_coord / (hw->end_stage - hw->start_stage)) *
472*4882a593Smuzhiyun 			a_param) / b_param;
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	if (sw->abs_pos > hw->max_coord)
475*4882a593Smuzhiyun 		sw->abs_pos = hw->max_coord;
476*4882a593Smuzhiyun 	else if (sw->abs_pos < 0)
477*4882a593Smuzhiyun 		sw->abs_pos = 0;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun 
ad714x_wheel_cal_flt_pos(struct ad714x_chip * ad714x,int idx)480*4882a593Smuzhiyun static void ad714x_wheel_cal_flt_pos(struct ad714x_chip *ad714x, int idx)
481*4882a593Smuzhiyun {
482*4882a593Smuzhiyun 	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
483*4882a593Smuzhiyun 	struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
484*4882a593Smuzhiyun 	if (((sw->pre_highest_stage == hw->end_stage) &&
485*4882a593Smuzhiyun 			(sw->highest_stage == hw->start_stage)) ||
486*4882a593Smuzhiyun 	    ((sw->pre_highest_stage == hw->start_stage) &&
487*4882a593Smuzhiyun 			(sw->highest_stage == hw->end_stage)))
488*4882a593Smuzhiyun 		sw->flt_pos = sw->abs_pos;
489*4882a593Smuzhiyun 	else
490*4882a593Smuzhiyun 		sw->flt_pos = ((sw->flt_pos * 30) + (sw->abs_pos * 71)) / 100;
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	if (sw->flt_pos > hw->max_coord)
493*4882a593Smuzhiyun 		sw->flt_pos = hw->max_coord;
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun 
ad714x_wheel_use_com_int(struct ad714x_chip * ad714x,int idx)496*4882a593Smuzhiyun static void ad714x_wheel_use_com_int(struct ad714x_chip *ad714x, int idx)
497*4882a593Smuzhiyun {
498*4882a593Smuzhiyun 	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	ad714x_use_com_int(ad714x, hw->start_stage, hw->end_stage);
501*4882a593Smuzhiyun }
502*4882a593Smuzhiyun 
ad714x_wheel_use_thr_int(struct ad714x_chip * ad714x,int idx)503*4882a593Smuzhiyun static void ad714x_wheel_use_thr_int(struct ad714x_chip *ad714x, int idx)
504*4882a593Smuzhiyun {
505*4882a593Smuzhiyun 	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	ad714x_use_thr_int(ad714x, hw->start_stage, hw->end_stage);
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun 
ad714x_wheel_state_machine(struct ad714x_chip * ad714x,int idx)510*4882a593Smuzhiyun static void ad714x_wheel_state_machine(struct ad714x_chip *ad714x, int idx)
511*4882a593Smuzhiyun {
512*4882a593Smuzhiyun 	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
513*4882a593Smuzhiyun 	struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
514*4882a593Smuzhiyun 	unsigned short h_state, c_state;
515*4882a593Smuzhiyun 	unsigned short mask;
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	mask = ((1 << (hw->end_stage + 1)) - 1) - ((1 << hw->start_stage) - 1);
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	h_state = ad714x->h_state & mask;
520*4882a593Smuzhiyun 	c_state = ad714x->c_state & mask;
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 	switch (sw->state) {
523*4882a593Smuzhiyun 	case IDLE:
524*4882a593Smuzhiyun 		if (h_state) {
525*4882a593Smuzhiyun 			sw->state = JITTER;
526*4882a593Smuzhiyun 			/* In End of Conversion interrupt mode, the AD714X
527*4882a593Smuzhiyun 			 * continuously generates hardware interrupts.
528*4882a593Smuzhiyun 			 */
529*4882a593Smuzhiyun 			ad714x_wheel_use_com_int(ad714x, idx);
530*4882a593Smuzhiyun 			dev_dbg(ad714x->dev, "wheel %d touched\n", idx);
531*4882a593Smuzhiyun 		}
532*4882a593Smuzhiyun 		break;
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 	case JITTER:
535*4882a593Smuzhiyun 		if (c_state == mask)	{
536*4882a593Smuzhiyun 			ad714x_wheel_cal_sensor_val(ad714x, idx);
537*4882a593Smuzhiyun 			ad714x_wheel_cal_highest_stage(ad714x, idx);
538*4882a593Smuzhiyun 			ad714x_wheel_cal_abs_pos(ad714x, idx);
539*4882a593Smuzhiyun 			sw->flt_pos = sw->abs_pos;
540*4882a593Smuzhiyun 			sw->state = ACTIVE;
541*4882a593Smuzhiyun 		}
542*4882a593Smuzhiyun 		break;
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	case ACTIVE:
545*4882a593Smuzhiyun 		if (c_state == mask) {
546*4882a593Smuzhiyun 			if (h_state) {
547*4882a593Smuzhiyun 				ad714x_wheel_cal_sensor_val(ad714x, idx);
548*4882a593Smuzhiyun 				ad714x_wheel_cal_highest_stage(ad714x, idx);
549*4882a593Smuzhiyun 				ad714x_wheel_cal_abs_pos(ad714x, idx);
550*4882a593Smuzhiyun 				ad714x_wheel_cal_flt_pos(ad714x, idx);
551*4882a593Smuzhiyun 				input_report_abs(sw->input, ABS_WHEEL,
552*4882a593Smuzhiyun 					sw->flt_pos);
553*4882a593Smuzhiyun 				input_report_key(sw->input, BTN_TOUCH, 1);
554*4882a593Smuzhiyun 			} else {
555*4882a593Smuzhiyun 				/* When the user lifts off the sensor, configure
556*4882a593Smuzhiyun 				 * the AD714X back to threshold interrupt mode.
557*4882a593Smuzhiyun 				 */
558*4882a593Smuzhiyun 				ad714x_wheel_use_thr_int(ad714x, idx);
559*4882a593Smuzhiyun 				sw->state = IDLE;
560*4882a593Smuzhiyun 				input_report_key(sw->input, BTN_TOUCH, 0);
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 				dev_dbg(ad714x->dev, "wheel %d released\n",
563*4882a593Smuzhiyun 					idx);
564*4882a593Smuzhiyun 			}
565*4882a593Smuzhiyun 			input_sync(sw->input);
566*4882a593Smuzhiyun 		}
567*4882a593Smuzhiyun 		break;
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	default:
570*4882a593Smuzhiyun 		break;
571*4882a593Smuzhiyun 	}
572*4882a593Smuzhiyun }
573*4882a593Smuzhiyun 
touchpad_cal_sensor_val(struct ad714x_chip * ad714x,int idx)574*4882a593Smuzhiyun static void touchpad_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
575*4882a593Smuzhiyun {
576*4882a593Smuzhiyun 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
577*4882a593Smuzhiyun 	int i;
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	ad714x->read(ad714x, CDC_RESULT_S0 + hw->x_start_stage,
580*4882a593Smuzhiyun 			&ad714x->adc_reg[hw->x_start_stage],
581*4882a593Smuzhiyun 			hw->x_end_stage - hw->x_start_stage + 1);
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	for (i = hw->x_start_stage; i <= hw->x_end_stage; i++) {
584*4882a593Smuzhiyun 		ad714x->read(ad714x, STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
585*4882a593Smuzhiyun 				&ad714x->amb_reg[i], 1);
586*4882a593Smuzhiyun 		if (ad714x->adc_reg[i] > ad714x->amb_reg[i])
587*4882a593Smuzhiyun 			ad714x->sensor_val[i] =
588*4882a593Smuzhiyun 				ad714x->adc_reg[i] - ad714x->amb_reg[i];
589*4882a593Smuzhiyun 		else
590*4882a593Smuzhiyun 			ad714x->sensor_val[i] = 0;
591*4882a593Smuzhiyun 	}
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun 
touchpad_cal_highest_stage(struct ad714x_chip * ad714x,int idx)594*4882a593Smuzhiyun static void touchpad_cal_highest_stage(struct ad714x_chip *ad714x, int idx)
595*4882a593Smuzhiyun {
596*4882a593Smuzhiyun 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
597*4882a593Smuzhiyun 	struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 	sw->x_highest_stage = ad714x_cal_highest_stage(ad714x,
600*4882a593Smuzhiyun 		hw->x_start_stage, hw->x_end_stage);
601*4882a593Smuzhiyun 	sw->y_highest_stage = ad714x_cal_highest_stage(ad714x,
602*4882a593Smuzhiyun 		hw->y_start_stage, hw->y_end_stage);
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	dev_dbg(ad714x->dev,
605*4882a593Smuzhiyun 		"touchpad %d x_highest_stage:%d, y_highest_stage:%d\n",
606*4882a593Smuzhiyun 		idx, sw->x_highest_stage, sw->y_highest_stage);
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun /*
610*4882a593Smuzhiyun  * If 2 fingers are touching the sensor then 2 peaks can be observed in the
611*4882a593Smuzhiyun  * distribution.
612*4882a593Smuzhiyun  * The arithmetic doesn't support to get absolute coordinates for multi-touch
613*4882a593Smuzhiyun  * yet.
614*4882a593Smuzhiyun  */
touchpad_check_second_peak(struct ad714x_chip * ad714x,int idx)615*4882a593Smuzhiyun static int touchpad_check_second_peak(struct ad714x_chip *ad714x, int idx)
616*4882a593Smuzhiyun {
617*4882a593Smuzhiyun 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
618*4882a593Smuzhiyun 	struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
619*4882a593Smuzhiyun 	int i;
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	for (i = hw->x_start_stage; i < sw->x_highest_stage; i++) {
622*4882a593Smuzhiyun 		if ((ad714x->sensor_val[i] - ad714x->sensor_val[i + 1])
623*4882a593Smuzhiyun 			> (ad714x->sensor_val[i + 1] / 10))
624*4882a593Smuzhiyun 			return 1;
625*4882a593Smuzhiyun 	}
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun 	for (i = sw->x_highest_stage; i < hw->x_end_stage; i++) {
628*4882a593Smuzhiyun 		if ((ad714x->sensor_val[i + 1] - ad714x->sensor_val[i])
629*4882a593Smuzhiyun 			> (ad714x->sensor_val[i] / 10))
630*4882a593Smuzhiyun 			return 1;
631*4882a593Smuzhiyun 	}
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun 	for (i = hw->y_start_stage; i < sw->y_highest_stage; i++) {
634*4882a593Smuzhiyun 		if ((ad714x->sensor_val[i] - ad714x->sensor_val[i + 1])
635*4882a593Smuzhiyun 			> (ad714x->sensor_val[i + 1] / 10))
636*4882a593Smuzhiyun 			return 1;
637*4882a593Smuzhiyun 	}
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun 	for (i = sw->y_highest_stage; i < hw->y_end_stage; i++) {
640*4882a593Smuzhiyun 		if ((ad714x->sensor_val[i + 1] - ad714x->sensor_val[i])
641*4882a593Smuzhiyun 			> (ad714x->sensor_val[i] / 10))
642*4882a593Smuzhiyun 			return 1;
643*4882a593Smuzhiyun 	}
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 	return 0;
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun /*
649*4882a593Smuzhiyun  * If only one finger is used to activate the touch pad then only 1 peak will be
650*4882a593Smuzhiyun  * registered in the distribution. This peak and the 2 adjacent sensors will be
651*4882a593Smuzhiyun  * used in the calculation of the absolute position. This will prevent hand
652*4882a593Smuzhiyun  * shadows to affect the absolute position calculation.
653*4882a593Smuzhiyun  */
touchpad_cal_abs_pos(struct ad714x_chip * ad714x,int idx)654*4882a593Smuzhiyun static void touchpad_cal_abs_pos(struct ad714x_chip *ad714x, int idx)
655*4882a593Smuzhiyun {
656*4882a593Smuzhiyun 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
657*4882a593Smuzhiyun 	struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun 	sw->x_abs_pos = ad714x_cal_abs_pos(ad714x, hw->x_start_stage,
660*4882a593Smuzhiyun 			hw->x_end_stage, sw->x_highest_stage, hw->x_max_coord);
661*4882a593Smuzhiyun 	sw->y_abs_pos = ad714x_cal_abs_pos(ad714x, hw->y_start_stage,
662*4882a593Smuzhiyun 			hw->y_end_stage, sw->y_highest_stage, hw->y_max_coord);
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 	dev_dbg(ad714x->dev, "touchpad %d absolute position:(%d, %d)\n", idx,
665*4882a593Smuzhiyun 			sw->x_abs_pos, sw->y_abs_pos);
666*4882a593Smuzhiyun }
667*4882a593Smuzhiyun 
touchpad_cal_flt_pos(struct ad714x_chip * ad714x,int idx)668*4882a593Smuzhiyun static void touchpad_cal_flt_pos(struct ad714x_chip *ad714x, int idx)
669*4882a593Smuzhiyun {
670*4882a593Smuzhiyun 	struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun 	sw->x_flt_pos = (sw->x_flt_pos * (10 - 4) +
673*4882a593Smuzhiyun 			sw->x_abs_pos * 4)/10;
674*4882a593Smuzhiyun 	sw->y_flt_pos = (sw->y_flt_pos * (10 - 4) +
675*4882a593Smuzhiyun 			sw->y_abs_pos * 4)/10;
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun 	dev_dbg(ad714x->dev, "touchpad %d filter position:(%d, %d)\n",
678*4882a593Smuzhiyun 			idx, sw->x_flt_pos, sw->y_flt_pos);
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun 
681*4882a593Smuzhiyun /*
682*4882a593Smuzhiyun  * To prevent distortion from showing in the absolute position, it is
683*4882a593Smuzhiyun  * necessary to detect the end points. When endpoints are detected, the
684*4882a593Smuzhiyun  * driver stops updating the status variables with absolute positions.
685*4882a593Smuzhiyun  * End points are detected on the 4 edges of the touchpad sensor. The
686*4882a593Smuzhiyun  * method to detect them is the same for all 4.
687*4882a593Smuzhiyun  * To detect the end points, the firmware computes the difference in
688*4882a593Smuzhiyun  * percent between the sensor on the edge and the adjacent one. The
689*4882a593Smuzhiyun  * difference is calculated in percent in order to make the end point
690*4882a593Smuzhiyun  * detection independent of the pressure.
691*4882a593Smuzhiyun  */
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun #define LEFT_END_POINT_DETECTION_LEVEL                  550
694*4882a593Smuzhiyun #define RIGHT_END_POINT_DETECTION_LEVEL                 750
695*4882a593Smuzhiyun #define LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL         850
696*4882a593Smuzhiyun #define TOP_END_POINT_DETECTION_LEVEL                   550
697*4882a593Smuzhiyun #define BOTTOM_END_POINT_DETECTION_LEVEL                950
698*4882a593Smuzhiyun #define TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL         700
touchpad_check_endpoint(struct ad714x_chip * ad714x,int idx)699*4882a593Smuzhiyun static int touchpad_check_endpoint(struct ad714x_chip *ad714x, int idx)
700*4882a593Smuzhiyun {
701*4882a593Smuzhiyun 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
702*4882a593Smuzhiyun 	struct ad714x_touchpad_drv *sw  = &ad714x->sw->touchpad[idx];
703*4882a593Smuzhiyun 	int percent_sensor_diff;
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 	/* left endpoint detect */
706*4882a593Smuzhiyun 	percent_sensor_diff = (ad714x->sensor_val[hw->x_start_stage] -
707*4882a593Smuzhiyun 			ad714x->sensor_val[hw->x_start_stage + 1]) * 100 /
708*4882a593Smuzhiyun 			ad714x->sensor_val[hw->x_start_stage + 1];
709*4882a593Smuzhiyun 	if (!sw->left_ep) {
710*4882a593Smuzhiyun 		if (percent_sensor_diff >= LEFT_END_POINT_DETECTION_LEVEL)  {
711*4882a593Smuzhiyun 			sw->left_ep = 1;
712*4882a593Smuzhiyun 			sw->left_ep_val =
713*4882a593Smuzhiyun 				ad714x->sensor_val[hw->x_start_stage + 1];
714*4882a593Smuzhiyun 		}
715*4882a593Smuzhiyun 	} else {
716*4882a593Smuzhiyun 		if ((percent_sensor_diff < LEFT_END_POINT_DETECTION_LEVEL) &&
717*4882a593Smuzhiyun 		    (ad714x->sensor_val[hw->x_start_stage + 1] >
718*4882a593Smuzhiyun 		     LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL + sw->left_ep_val))
719*4882a593Smuzhiyun 			sw->left_ep = 0;
720*4882a593Smuzhiyun 	}
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun 	/* right endpoint detect */
723*4882a593Smuzhiyun 	percent_sensor_diff = (ad714x->sensor_val[hw->x_end_stage] -
724*4882a593Smuzhiyun 			ad714x->sensor_val[hw->x_end_stage - 1]) * 100 /
725*4882a593Smuzhiyun 			ad714x->sensor_val[hw->x_end_stage - 1];
726*4882a593Smuzhiyun 	if (!sw->right_ep) {
727*4882a593Smuzhiyun 		if (percent_sensor_diff >= RIGHT_END_POINT_DETECTION_LEVEL)  {
728*4882a593Smuzhiyun 			sw->right_ep = 1;
729*4882a593Smuzhiyun 			sw->right_ep_val =
730*4882a593Smuzhiyun 				ad714x->sensor_val[hw->x_end_stage - 1];
731*4882a593Smuzhiyun 		}
732*4882a593Smuzhiyun 	} else {
733*4882a593Smuzhiyun 		if ((percent_sensor_diff < RIGHT_END_POINT_DETECTION_LEVEL) &&
734*4882a593Smuzhiyun 		(ad714x->sensor_val[hw->x_end_stage - 1] >
735*4882a593Smuzhiyun 		LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL + sw->right_ep_val))
736*4882a593Smuzhiyun 			sw->right_ep = 0;
737*4882a593Smuzhiyun 	}
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun 	/* top endpoint detect */
740*4882a593Smuzhiyun 	percent_sensor_diff = (ad714x->sensor_val[hw->y_start_stage] -
741*4882a593Smuzhiyun 			ad714x->sensor_val[hw->y_start_stage + 1]) * 100 /
742*4882a593Smuzhiyun 			ad714x->sensor_val[hw->y_start_stage + 1];
743*4882a593Smuzhiyun 	if (!sw->top_ep) {
744*4882a593Smuzhiyun 		if (percent_sensor_diff >= TOP_END_POINT_DETECTION_LEVEL)  {
745*4882a593Smuzhiyun 			sw->top_ep = 1;
746*4882a593Smuzhiyun 			sw->top_ep_val =
747*4882a593Smuzhiyun 				ad714x->sensor_val[hw->y_start_stage + 1];
748*4882a593Smuzhiyun 		}
749*4882a593Smuzhiyun 	} else {
750*4882a593Smuzhiyun 		if ((percent_sensor_diff < TOP_END_POINT_DETECTION_LEVEL) &&
751*4882a593Smuzhiyun 		(ad714x->sensor_val[hw->y_start_stage + 1] >
752*4882a593Smuzhiyun 		TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL + sw->top_ep_val))
753*4882a593Smuzhiyun 			sw->top_ep = 0;
754*4882a593Smuzhiyun 	}
755*4882a593Smuzhiyun 
756*4882a593Smuzhiyun 	/* bottom endpoint detect */
757*4882a593Smuzhiyun 	percent_sensor_diff = (ad714x->sensor_val[hw->y_end_stage] -
758*4882a593Smuzhiyun 		ad714x->sensor_val[hw->y_end_stage - 1]) * 100 /
759*4882a593Smuzhiyun 		ad714x->sensor_val[hw->y_end_stage - 1];
760*4882a593Smuzhiyun 	if (!sw->bottom_ep) {
761*4882a593Smuzhiyun 		if (percent_sensor_diff >= BOTTOM_END_POINT_DETECTION_LEVEL)  {
762*4882a593Smuzhiyun 			sw->bottom_ep = 1;
763*4882a593Smuzhiyun 			sw->bottom_ep_val =
764*4882a593Smuzhiyun 				ad714x->sensor_val[hw->y_end_stage - 1];
765*4882a593Smuzhiyun 		}
766*4882a593Smuzhiyun 	} else {
767*4882a593Smuzhiyun 		if ((percent_sensor_diff < BOTTOM_END_POINT_DETECTION_LEVEL) &&
768*4882a593Smuzhiyun 		(ad714x->sensor_val[hw->y_end_stage - 1] >
769*4882a593Smuzhiyun 		 TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL + sw->bottom_ep_val))
770*4882a593Smuzhiyun 			sw->bottom_ep = 0;
771*4882a593Smuzhiyun 	}
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	return sw->left_ep || sw->right_ep || sw->top_ep || sw->bottom_ep;
774*4882a593Smuzhiyun }
775*4882a593Smuzhiyun 
touchpad_use_com_int(struct ad714x_chip * ad714x,int idx)776*4882a593Smuzhiyun static void touchpad_use_com_int(struct ad714x_chip *ad714x, int idx)
777*4882a593Smuzhiyun {
778*4882a593Smuzhiyun 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 	ad714x_use_com_int(ad714x, hw->x_start_stage, hw->x_end_stage);
781*4882a593Smuzhiyun }
782*4882a593Smuzhiyun 
touchpad_use_thr_int(struct ad714x_chip * ad714x,int idx)783*4882a593Smuzhiyun static void touchpad_use_thr_int(struct ad714x_chip *ad714x, int idx)
784*4882a593Smuzhiyun {
785*4882a593Smuzhiyun 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
786*4882a593Smuzhiyun 
787*4882a593Smuzhiyun 	ad714x_use_thr_int(ad714x, hw->x_start_stage, hw->x_end_stage);
788*4882a593Smuzhiyun 	ad714x_use_thr_int(ad714x, hw->y_start_stage, hw->y_end_stage);
789*4882a593Smuzhiyun }
790*4882a593Smuzhiyun 
ad714x_touchpad_state_machine(struct ad714x_chip * ad714x,int idx)791*4882a593Smuzhiyun static void ad714x_touchpad_state_machine(struct ad714x_chip *ad714x, int idx)
792*4882a593Smuzhiyun {
793*4882a593Smuzhiyun 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
794*4882a593Smuzhiyun 	struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
795*4882a593Smuzhiyun 	unsigned short h_state, c_state;
796*4882a593Smuzhiyun 	unsigned short mask;
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun 	mask = (((1 << (hw->x_end_stage + 1)) - 1) -
799*4882a593Smuzhiyun 		((1 << hw->x_start_stage) - 1)) +
800*4882a593Smuzhiyun 		(((1 << (hw->y_end_stage + 1)) - 1) -
801*4882a593Smuzhiyun 		((1 << hw->y_start_stage) - 1));
802*4882a593Smuzhiyun 
803*4882a593Smuzhiyun 	h_state = ad714x->h_state & mask;
804*4882a593Smuzhiyun 	c_state = ad714x->c_state & mask;
805*4882a593Smuzhiyun 
806*4882a593Smuzhiyun 	switch (sw->state) {
807*4882a593Smuzhiyun 	case IDLE:
808*4882a593Smuzhiyun 		if (h_state) {
809*4882a593Smuzhiyun 			sw->state = JITTER;
810*4882a593Smuzhiyun 			/* In End of Conversion interrupt mode, the AD714X
811*4882a593Smuzhiyun 			 * continuously generates hardware interrupts.
812*4882a593Smuzhiyun 			 */
813*4882a593Smuzhiyun 			touchpad_use_com_int(ad714x, idx);
814*4882a593Smuzhiyun 			dev_dbg(ad714x->dev, "touchpad %d touched\n", idx);
815*4882a593Smuzhiyun 		}
816*4882a593Smuzhiyun 		break;
817*4882a593Smuzhiyun 
818*4882a593Smuzhiyun 	case JITTER:
819*4882a593Smuzhiyun 		if (c_state == mask) {
820*4882a593Smuzhiyun 			touchpad_cal_sensor_val(ad714x, idx);
821*4882a593Smuzhiyun 			touchpad_cal_highest_stage(ad714x, idx);
822*4882a593Smuzhiyun 			if ((!touchpad_check_second_peak(ad714x, idx)) &&
823*4882a593Smuzhiyun 				(!touchpad_check_endpoint(ad714x, idx))) {
824*4882a593Smuzhiyun 				dev_dbg(ad714x->dev,
825*4882a593Smuzhiyun 					"touchpad%d, 2 fingers or endpoint\n",
826*4882a593Smuzhiyun 					idx);
827*4882a593Smuzhiyun 				touchpad_cal_abs_pos(ad714x, idx);
828*4882a593Smuzhiyun 				sw->x_flt_pos = sw->x_abs_pos;
829*4882a593Smuzhiyun 				sw->y_flt_pos = sw->y_abs_pos;
830*4882a593Smuzhiyun 				sw->state = ACTIVE;
831*4882a593Smuzhiyun 			}
832*4882a593Smuzhiyun 		}
833*4882a593Smuzhiyun 		break;
834*4882a593Smuzhiyun 
835*4882a593Smuzhiyun 	case ACTIVE:
836*4882a593Smuzhiyun 		if (c_state == mask) {
837*4882a593Smuzhiyun 			if (h_state) {
838*4882a593Smuzhiyun 				touchpad_cal_sensor_val(ad714x, idx);
839*4882a593Smuzhiyun 				touchpad_cal_highest_stage(ad714x, idx);
840*4882a593Smuzhiyun 				if ((!touchpad_check_second_peak(ad714x, idx))
841*4882a593Smuzhiyun 				  && (!touchpad_check_endpoint(ad714x, idx))) {
842*4882a593Smuzhiyun 					touchpad_cal_abs_pos(ad714x, idx);
843*4882a593Smuzhiyun 					touchpad_cal_flt_pos(ad714x, idx);
844*4882a593Smuzhiyun 					input_report_abs(sw->input, ABS_X,
845*4882a593Smuzhiyun 						sw->x_flt_pos);
846*4882a593Smuzhiyun 					input_report_abs(sw->input, ABS_Y,
847*4882a593Smuzhiyun 						sw->y_flt_pos);
848*4882a593Smuzhiyun 					input_report_key(sw->input, BTN_TOUCH,
849*4882a593Smuzhiyun 						1);
850*4882a593Smuzhiyun 				}
851*4882a593Smuzhiyun 			} else {
852*4882a593Smuzhiyun 				/* When the user lifts off the sensor, configure
853*4882a593Smuzhiyun 				 * the AD714X back to threshold interrupt mode.
854*4882a593Smuzhiyun 				 */
855*4882a593Smuzhiyun 				touchpad_use_thr_int(ad714x, idx);
856*4882a593Smuzhiyun 				sw->state = IDLE;
857*4882a593Smuzhiyun 				input_report_key(sw->input, BTN_TOUCH, 0);
858*4882a593Smuzhiyun 				dev_dbg(ad714x->dev, "touchpad %d released\n",
859*4882a593Smuzhiyun 					idx);
860*4882a593Smuzhiyun 			}
861*4882a593Smuzhiyun 			input_sync(sw->input);
862*4882a593Smuzhiyun 		}
863*4882a593Smuzhiyun 		break;
864*4882a593Smuzhiyun 
865*4882a593Smuzhiyun 	default:
866*4882a593Smuzhiyun 		break;
867*4882a593Smuzhiyun 	}
868*4882a593Smuzhiyun }
869*4882a593Smuzhiyun 
ad714x_hw_detect(struct ad714x_chip * ad714x)870*4882a593Smuzhiyun static int ad714x_hw_detect(struct ad714x_chip *ad714x)
871*4882a593Smuzhiyun {
872*4882a593Smuzhiyun 	unsigned short data;
873*4882a593Smuzhiyun 
874*4882a593Smuzhiyun 	ad714x->read(ad714x, AD714X_PARTID_REG, &data, 1);
875*4882a593Smuzhiyun 	switch (data & 0xFFF0) {
876*4882a593Smuzhiyun 	case AD7142_PARTID:
877*4882a593Smuzhiyun 		ad714x->product = 0x7142;
878*4882a593Smuzhiyun 		ad714x->version = data & 0xF;
879*4882a593Smuzhiyun 		dev_info(ad714x->dev, "found AD7142 captouch, rev:%d\n",
880*4882a593Smuzhiyun 				ad714x->version);
881*4882a593Smuzhiyun 		return 0;
882*4882a593Smuzhiyun 
883*4882a593Smuzhiyun 	case AD7143_PARTID:
884*4882a593Smuzhiyun 		ad714x->product = 0x7143;
885*4882a593Smuzhiyun 		ad714x->version = data & 0xF;
886*4882a593Smuzhiyun 		dev_info(ad714x->dev, "found AD7143 captouch, rev:%d\n",
887*4882a593Smuzhiyun 				ad714x->version);
888*4882a593Smuzhiyun 		return 0;
889*4882a593Smuzhiyun 
890*4882a593Smuzhiyun 	case AD7147_PARTID:
891*4882a593Smuzhiyun 		ad714x->product = 0x7147;
892*4882a593Smuzhiyun 		ad714x->version = data & 0xF;
893*4882a593Smuzhiyun 		dev_info(ad714x->dev, "found AD7147(A) captouch, rev:%d\n",
894*4882a593Smuzhiyun 				ad714x->version);
895*4882a593Smuzhiyun 		return 0;
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun 	case AD7148_PARTID:
898*4882a593Smuzhiyun 		ad714x->product = 0x7148;
899*4882a593Smuzhiyun 		ad714x->version = data & 0xF;
900*4882a593Smuzhiyun 		dev_info(ad714x->dev, "found AD7148 captouch, rev:%d\n",
901*4882a593Smuzhiyun 				ad714x->version);
902*4882a593Smuzhiyun 		return 0;
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun 	default:
905*4882a593Smuzhiyun 		dev_err(ad714x->dev,
906*4882a593Smuzhiyun 			"fail to detect AD714X captouch, read ID is %04x\n",
907*4882a593Smuzhiyun 			data);
908*4882a593Smuzhiyun 		return -ENODEV;
909*4882a593Smuzhiyun 	}
910*4882a593Smuzhiyun }
911*4882a593Smuzhiyun 
ad714x_hw_init(struct ad714x_chip * ad714x)912*4882a593Smuzhiyun static void ad714x_hw_init(struct ad714x_chip *ad714x)
913*4882a593Smuzhiyun {
914*4882a593Smuzhiyun 	int i, j;
915*4882a593Smuzhiyun 	unsigned short reg_base;
916*4882a593Smuzhiyun 	unsigned short data;
917*4882a593Smuzhiyun 
918*4882a593Smuzhiyun 	/* configuration CDC and interrupts */
919*4882a593Smuzhiyun 
920*4882a593Smuzhiyun 	for (i = 0; i < STAGE_NUM; i++) {
921*4882a593Smuzhiyun 		reg_base = AD714X_STAGECFG_REG + i * STAGE_CFGREG_NUM;
922*4882a593Smuzhiyun 		for (j = 0; j < STAGE_CFGREG_NUM; j++)
923*4882a593Smuzhiyun 			ad714x->write(ad714x, reg_base + j,
924*4882a593Smuzhiyun 					ad714x->hw->stage_cfg_reg[i][j]);
925*4882a593Smuzhiyun 	}
926*4882a593Smuzhiyun 
927*4882a593Smuzhiyun 	for (i = 0; i < SYS_CFGREG_NUM; i++)
928*4882a593Smuzhiyun 		ad714x->write(ad714x, AD714X_SYSCFG_REG + i,
929*4882a593Smuzhiyun 			ad714x->hw->sys_cfg_reg[i]);
930*4882a593Smuzhiyun 	for (i = 0; i < SYS_CFGREG_NUM; i++)
931*4882a593Smuzhiyun 		ad714x->read(ad714x, AD714X_SYSCFG_REG + i, &data, 1);
932*4882a593Smuzhiyun 
933*4882a593Smuzhiyun 	ad714x->write(ad714x, AD714X_STG_CAL_EN_REG, 0xFFF);
934*4882a593Smuzhiyun 
935*4882a593Smuzhiyun 	/* clear all interrupts */
936*4882a593Smuzhiyun 	ad714x->read(ad714x, STG_LOW_INT_STA_REG, &ad714x->l_state, 3);
937*4882a593Smuzhiyun }
938*4882a593Smuzhiyun 
ad714x_interrupt_thread(int irq,void * data)939*4882a593Smuzhiyun static irqreturn_t ad714x_interrupt_thread(int irq, void *data)
940*4882a593Smuzhiyun {
941*4882a593Smuzhiyun 	struct ad714x_chip *ad714x = data;
942*4882a593Smuzhiyun 	int i;
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun 	mutex_lock(&ad714x->mutex);
945*4882a593Smuzhiyun 
946*4882a593Smuzhiyun 	ad714x->read(ad714x, STG_LOW_INT_STA_REG, &ad714x->l_state, 3);
947*4882a593Smuzhiyun 
948*4882a593Smuzhiyun 	for (i = 0; i < ad714x->hw->button_num; i++)
949*4882a593Smuzhiyun 		ad714x_button_state_machine(ad714x, i);
950*4882a593Smuzhiyun 	for (i = 0; i < ad714x->hw->slider_num; i++)
951*4882a593Smuzhiyun 		ad714x_slider_state_machine(ad714x, i);
952*4882a593Smuzhiyun 	for (i = 0; i < ad714x->hw->wheel_num; i++)
953*4882a593Smuzhiyun 		ad714x_wheel_state_machine(ad714x, i);
954*4882a593Smuzhiyun 	for (i = 0; i < ad714x->hw->touchpad_num; i++)
955*4882a593Smuzhiyun 		ad714x_touchpad_state_machine(ad714x, i);
956*4882a593Smuzhiyun 
957*4882a593Smuzhiyun 	mutex_unlock(&ad714x->mutex);
958*4882a593Smuzhiyun 
959*4882a593Smuzhiyun 	return IRQ_HANDLED;
960*4882a593Smuzhiyun }
961*4882a593Smuzhiyun 
ad714x_probe(struct device * dev,u16 bus_type,int irq,ad714x_read_t read,ad714x_write_t write)962*4882a593Smuzhiyun struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
963*4882a593Smuzhiyun 				 ad714x_read_t read, ad714x_write_t write)
964*4882a593Smuzhiyun {
965*4882a593Smuzhiyun 	int i;
966*4882a593Smuzhiyun 	int error;
967*4882a593Smuzhiyun 	struct input_dev *input;
968*4882a593Smuzhiyun 
969*4882a593Smuzhiyun 	struct ad714x_platform_data *plat_data = dev_get_platdata(dev);
970*4882a593Smuzhiyun 	struct ad714x_chip *ad714x;
971*4882a593Smuzhiyun 	void *drv_mem;
972*4882a593Smuzhiyun 	unsigned long irqflags;
973*4882a593Smuzhiyun 
974*4882a593Smuzhiyun 	struct ad714x_button_drv *bt_drv;
975*4882a593Smuzhiyun 	struct ad714x_slider_drv *sd_drv;
976*4882a593Smuzhiyun 	struct ad714x_wheel_drv *wl_drv;
977*4882a593Smuzhiyun 	struct ad714x_touchpad_drv *tp_drv;
978*4882a593Smuzhiyun 
979*4882a593Smuzhiyun 
980*4882a593Smuzhiyun 	if (irq <= 0) {
981*4882a593Smuzhiyun 		dev_err(dev, "IRQ not configured!\n");
982*4882a593Smuzhiyun 		error = -EINVAL;
983*4882a593Smuzhiyun 		return ERR_PTR(error);
984*4882a593Smuzhiyun 	}
985*4882a593Smuzhiyun 
986*4882a593Smuzhiyun 	if (dev_get_platdata(dev) == NULL) {
987*4882a593Smuzhiyun 		dev_err(dev, "platform data for ad714x doesn't exist\n");
988*4882a593Smuzhiyun 		error = -EINVAL;
989*4882a593Smuzhiyun 		return ERR_PTR(error);
990*4882a593Smuzhiyun 	}
991*4882a593Smuzhiyun 
992*4882a593Smuzhiyun 	ad714x = devm_kzalloc(dev, sizeof(*ad714x) + sizeof(*ad714x->sw) +
993*4882a593Smuzhiyun 				   sizeof(*sd_drv) * plat_data->slider_num +
994*4882a593Smuzhiyun 				   sizeof(*wl_drv) * plat_data->wheel_num +
995*4882a593Smuzhiyun 				   sizeof(*tp_drv) * plat_data->touchpad_num +
996*4882a593Smuzhiyun 				   sizeof(*bt_drv) * plat_data->button_num,
997*4882a593Smuzhiyun 			      GFP_KERNEL);
998*4882a593Smuzhiyun 	if (!ad714x) {
999*4882a593Smuzhiyun 		error = -ENOMEM;
1000*4882a593Smuzhiyun 		return ERR_PTR(error);
1001*4882a593Smuzhiyun 	}
1002*4882a593Smuzhiyun 	ad714x->hw = plat_data;
1003*4882a593Smuzhiyun 
1004*4882a593Smuzhiyun 	drv_mem = ad714x + 1;
1005*4882a593Smuzhiyun 	ad714x->sw = drv_mem;
1006*4882a593Smuzhiyun 	drv_mem += sizeof(*ad714x->sw);
1007*4882a593Smuzhiyun 	ad714x->sw->slider = sd_drv = drv_mem;
1008*4882a593Smuzhiyun 	drv_mem += sizeof(*sd_drv) * ad714x->hw->slider_num;
1009*4882a593Smuzhiyun 	ad714x->sw->wheel = wl_drv = drv_mem;
1010*4882a593Smuzhiyun 	drv_mem += sizeof(*wl_drv) * ad714x->hw->wheel_num;
1011*4882a593Smuzhiyun 	ad714x->sw->touchpad = tp_drv = drv_mem;
1012*4882a593Smuzhiyun 	drv_mem += sizeof(*tp_drv) * ad714x->hw->touchpad_num;
1013*4882a593Smuzhiyun 	ad714x->sw->button = bt_drv = drv_mem;
1014*4882a593Smuzhiyun 	drv_mem += sizeof(*bt_drv) * ad714x->hw->button_num;
1015*4882a593Smuzhiyun 
1016*4882a593Smuzhiyun 	ad714x->read = read;
1017*4882a593Smuzhiyun 	ad714x->write = write;
1018*4882a593Smuzhiyun 	ad714x->irq = irq;
1019*4882a593Smuzhiyun 	ad714x->dev = dev;
1020*4882a593Smuzhiyun 
1021*4882a593Smuzhiyun 	error = ad714x_hw_detect(ad714x);
1022*4882a593Smuzhiyun 	if (error)
1023*4882a593Smuzhiyun 		return ERR_PTR(error);
1024*4882a593Smuzhiyun 
1025*4882a593Smuzhiyun 	/* initialize and request sw/hw resources */
1026*4882a593Smuzhiyun 
1027*4882a593Smuzhiyun 	ad714x_hw_init(ad714x);
1028*4882a593Smuzhiyun 	mutex_init(&ad714x->mutex);
1029*4882a593Smuzhiyun 
1030*4882a593Smuzhiyun 	/* a slider uses one input_dev instance */
1031*4882a593Smuzhiyun 	if (ad714x->hw->slider_num > 0) {
1032*4882a593Smuzhiyun 		struct ad714x_slider_plat *sd_plat = ad714x->hw->slider;
1033*4882a593Smuzhiyun 
1034*4882a593Smuzhiyun 		for (i = 0; i < ad714x->hw->slider_num; i++) {
1035*4882a593Smuzhiyun 			input = devm_input_allocate_device(dev);
1036*4882a593Smuzhiyun 			if (!input)
1037*4882a593Smuzhiyun 				return ERR_PTR(-ENOMEM);
1038*4882a593Smuzhiyun 
1039*4882a593Smuzhiyun 			__set_bit(EV_ABS, input->evbit);
1040*4882a593Smuzhiyun 			__set_bit(EV_KEY, input->evbit);
1041*4882a593Smuzhiyun 			__set_bit(ABS_X, input->absbit);
1042*4882a593Smuzhiyun 			__set_bit(BTN_TOUCH, input->keybit);
1043*4882a593Smuzhiyun 			input_set_abs_params(input,
1044*4882a593Smuzhiyun 				ABS_X, 0, sd_plat->max_coord, 0, 0);
1045*4882a593Smuzhiyun 
1046*4882a593Smuzhiyun 			input->id.bustype = bus_type;
1047*4882a593Smuzhiyun 			input->id.product = ad714x->product;
1048*4882a593Smuzhiyun 			input->id.version = ad714x->version;
1049*4882a593Smuzhiyun 			input->name = "ad714x_captouch_slider";
1050*4882a593Smuzhiyun 			input->dev.parent = dev;
1051*4882a593Smuzhiyun 
1052*4882a593Smuzhiyun 			error = input_register_device(input);
1053*4882a593Smuzhiyun 			if (error)
1054*4882a593Smuzhiyun 				return ERR_PTR(error);
1055*4882a593Smuzhiyun 
1056*4882a593Smuzhiyun 			sd_drv[i].input = input;
1057*4882a593Smuzhiyun 		}
1058*4882a593Smuzhiyun 	}
1059*4882a593Smuzhiyun 
1060*4882a593Smuzhiyun 	/* a wheel uses one input_dev instance */
1061*4882a593Smuzhiyun 	if (ad714x->hw->wheel_num > 0) {
1062*4882a593Smuzhiyun 		struct ad714x_wheel_plat *wl_plat = ad714x->hw->wheel;
1063*4882a593Smuzhiyun 
1064*4882a593Smuzhiyun 		for (i = 0; i < ad714x->hw->wheel_num; i++) {
1065*4882a593Smuzhiyun 			input = devm_input_allocate_device(dev);
1066*4882a593Smuzhiyun 			if (!input)
1067*4882a593Smuzhiyun 				return ERR_PTR(-ENOMEM);
1068*4882a593Smuzhiyun 
1069*4882a593Smuzhiyun 			__set_bit(EV_KEY, input->evbit);
1070*4882a593Smuzhiyun 			__set_bit(EV_ABS, input->evbit);
1071*4882a593Smuzhiyun 			__set_bit(ABS_WHEEL, input->absbit);
1072*4882a593Smuzhiyun 			__set_bit(BTN_TOUCH, input->keybit);
1073*4882a593Smuzhiyun 			input_set_abs_params(input,
1074*4882a593Smuzhiyun 				ABS_WHEEL, 0, wl_plat->max_coord, 0, 0);
1075*4882a593Smuzhiyun 
1076*4882a593Smuzhiyun 			input->id.bustype = bus_type;
1077*4882a593Smuzhiyun 			input->id.product = ad714x->product;
1078*4882a593Smuzhiyun 			input->id.version = ad714x->version;
1079*4882a593Smuzhiyun 			input->name = "ad714x_captouch_wheel";
1080*4882a593Smuzhiyun 			input->dev.parent = dev;
1081*4882a593Smuzhiyun 
1082*4882a593Smuzhiyun 			error = input_register_device(input);
1083*4882a593Smuzhiyun 			if (error)
1084*4882a593Smuzhiyun 				return ERR_PTR(error);
1085*4882a593Smuzhiyun 
1086*4882a593Smuzhiyun 			wl_drv[i].input = input;
1087*4882a593Smuzhiyun 		}
1088*4882a593Smuzhiyun 	}
1089*4882a593Smuzhiyun 
1090*4882a593Smuzhiyun 	/* a touchpad uses one input_dev instance */
1091*4882a593Smuzhiyun 	if (ad714x->hw->touchpad_num > 0) {
1092*4882a593Smuzhiyun 		struct ad714x_touchpad_plat *tp_plat = ad714x->hw->touchpad;
1093*4882a593Smuzhiyun 
1094*4882a593Smuzhiyun 		for (i = 0; i < ad714x->hw->touchpad_num; i++) {
1095*4882a593Smuzhiyun 			input = devm_input_allocate_device(dev);
1096*4882a593Smuzhiyun 			if (!input)
1097*4882a593Smuzhiyun 				return ERR_PTR(-ENOMEM);
1098*4882a593Smuzhiyun 
1099*4882a593Smuzhiyun 			__set_bit(EV_ABS, input->evbit);
1100*4882a593Smuzhiyun 			__set_bit(EV_KEY, input->evbit);
1101*4882a593Smuzhiyun 			__set_bit(ABS_X, input->absbit);
1102*4882a593Smuzhiyun 			__set_bit(ABS_Y, input->absbit);
1103*4882a593Smuzhiyun 			__set_bit(BTN_TOUCH, input->keybit);
1104*4882a593Smuzhiyun 			input_set_abs_params(input,
1105*4882a593Smuzhiyun 				ABS_X, 0, tp_plat->x_max_coord, 0, 0);
1106*4882a593Smuzhiyun 			input_set_abs_params(input,
1107*4882a593Smuzhiyun 				ABS_Y, 0, tp_plat->y_max_coord, 0, 0);
1108*4882a593Smuzhiyun 
1109*4882a593Smuzhiyun 			input->id.bustype = bus_type;
1110*4882a593Smuzhiyun 			input->id.product = ad714x->product;
1111*4882a593Smuzhiyun 			input->id.version = ad714x->version;
1112*4882a593Smuzhiyun 			input->name = "ad714x_captouch_pad";
1113*4882a593Smuzhiyun 			input->dev.parent = dev;
1114*4882a593Smuzhiyun 
1115*4882a593Smuzhiyun 			error = input_register_device(input);
1116*4882a593Smuzhiyun 			if (error)
1117*4882a593Smuzhiyun 				return ERR_PTR(error);
1118*4882a593Smuzhiyun 
1119*4882a593Smuzhiyun 			tp_drv[i].input = input;
1120*4882a593Smuzhiyun 		}
1121*4882a593Smuzhiyun 	}
1122*4882a593Smuzhiyun 
1123*4882a593Smuzhiyun 	/* all buttons use one input node */
1124*4882a593Smuzhiyun 	if (ad714x->hw->button_num > 0) {
1125*4882a593Smuzhiyun 		struct ad714x_button_plat *bt_plat = ad714x->hw->button;
1126*4882a593Smuzhiyun 
1127*4882a593Smuzhiyun 		input = devm_input_allocate_device(dev);
1128*4882a593Smuzhiyun 		if (!input) {
1129*4882a593Smuzhiyun 			error = -ENOMEM;
1130*4882a593Smuzhiyun 			return ERR_PTR(error);
1131*4882a593Smuzhiyun 		}
1132*4882a593Smuzhiyun 
1133*4882a593Smuzhiyun 		__set_bit(EV_KEY, input->evbit);
1134*4882a593Smuzhiyun 		for (i = 0; i < ad714x->hw->button_num; i++) {
1135*4882a593Smuzhiyun 			bt_drv[i].input = input;
1136*4882a593Smuzhiyun 			__set_bit(bt_plat[i].keycode, input->keybit);
1137*4882a593Smuzhiyun 		}
1138*4882a593Smuzhiyun 
1139*4882a593Smuzhiyun 		input->id.bustype = bus_type;
1140*4882a593Smuzhiyun 		input->id.product = ad714x->product;
1141*4882a593Smuzhiyun 		input->id.version = ad714x->version;
1142*4882a593Smuzhiyun 		input->name = "ad714x_captouch_button";
1143*4882a593Smuzhiyun 		input->dev.parent = dev;
1144*4882a593Smuzhiyun 
1145*4882a593Smuzhiyun 		error = input_register_device(input);
1146*4882a593Smuzhiyun 		if (error)
1147*4882a593Smuzhiyun 			return ERR_PTR(error);
1148*4882a593Smuzhiyun 	}
1149*4882a593Smuzhiyun 
1150*4882a593Smuzhiyun 	irqflags = plat_data->irqflags ?: IRQF_TRIGGER_FALLING;
1151*4882a593Smuzhiyun 	irqflags |= IRQF_ONESHOT;
1152*4882a593Smuzhiyun 
1153*4882a593Smuzhiyun 	error = devm_request_threaded_irq(dev, ad714x->irq, NULL,
1154*4882a593Smuzhiyun 					  ad714x_interrupt_thread,
1155*4882a593Smuzhiyun 					  irqflags, "ad714x_captouch", ad714x);
1156*4882a593Smuzhiyun 	if (error) {
1157*4882a593Smuzhiyun 		dev_err(dev, "can't allocate irq %d\n", ad714x->irq);
1158*4882a593Smuzhiyun 		return ERR_PTR(error);
1159*4882a593Smuzhiyun 	}
1160*4882a593Smuzhiyun 
1161*4882a593Smuzhiyun 	return ad714x;
1162*4882a593Smuzhiyun }
1163*4882a593Smuzhiyun EXPORT_SYMBOL(ad714x_probe);
1164*4882a593Smuzhiyun 
1165*4882a593Smuzhiyun #ifdef CONFIG_PM
ad714x_disable(struct ad714x_chip * ad714x)1166*4882a593Smuzhiyun int ad714x_disable(struct ad714x_chip *ad714x)
1167*4882a593Smuzhiyun {
1168*4882a593Smuzhiyun 	unsigned short data;
1169*4882a593Smuzhiyun 
1170*4882a593Smuzhiyun 	dev_dbg(ad714x->dev, "%s enter\n", __func__);
1171*4882a593Smuzhiyun 
1172*4882a593Smuzhiyun 	mutex_lock(&ad714x->mutex);
1173*4882a593Smuzhiyun 
1174*4882a593Smuzhiyun 	data = ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL] | 0x3;
1175*4882a593Smuzhiyun 	ad714x->write(ad714x, AD714X_PWR_CTRL, data);
1176*4882a593Smuzhiyun 
1177*4882a593Smuzhiyun 	mutex_unlock(&ad714x->mutex);
1178*4882a593Smuzhiyun 
1179*4882a593Smuzhiyun 	return 0;
1180*4882a593Smuzhiyun }
1181*4882a593Smuzhiyun EXPORT_SYMBOL(ad714x_disable);
1182*4882a593Smuzhiyun 
ad714x_enable(struct ad714x_chip * ad714x)1183*4882a593Smuzhiyun int ad714x_enable(struct ad714x_chip *ad714x)
1184*4882a593Smuzhiyun {
1185*4882a593Smuzhiyun 	dev_dbg(ad714x->dev, "%s enter\n", __func__);
1186*4882a593Smuzhiyun 
1187*4882a593Smuzhiyun 	mutex_lock(&ad714x->mutex);
1188*4882a593Smuzhiyun 
1189*4882a593Smuzhiyun 	/* resume to non-shutdown mode */
1190*4882a593Smuzhiyun 
1191*4882a593Smuzhiyun 	ad714x->write(ad714x, AD714X_PWR_CTRL,
1192*4882a593Smuzhiyun 			ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL]);
1193*4882a593Smuzhiyun 
1194*4882a593Smuzhiyun 	/* make sure the interrupt output line is not low level after resume,
1195*4882a593Smuzhiyun 	 * otherwise we will get no chance to enter falling-edge irq again
1196*4882a593Smuzhiyun 	 */
1197*4882a593Smuzhiyun 
1198*4882a593Smuzhiyun 	ad714x->read(ad714x, STG_LOW_INT_STA_REG, &ad714x->l_state, 3);
1199*4882a593Smuzhiyun 
1200*4882a593Smuzhiyun 	mutex_unlock(&ad714x->mutex);
1201*4882a593Smuzhiyun 
1202*4882a593Smuzhiyun 	return 0;
1203*4882a593Smuzhiyun }
1204*4882a593Smuzhiyun EXPORT_SYMBOL(ad714x_enable);
1205*4882a593Smuzhiyun #endif
1206*4882a593Smuzhiyun 
1207*4882a593Smuzhiyun MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor Driver");
1208*4882a593Smuzhiyun MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
1209*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1210