xref: /openbmc/linux/drivers/input/misc/ad714x.c (revision c5c18a06)
131a62963SBryan Wu /*
26c04d7b3SBarry Song  * AD714X CapTouch Programmable Controller driver supporting AD7142/3/7/8/7A
331a62963SBryan Wu  *
49eff794bSMichael Hennerich  * Copyright 2009-2011 Analog Devices Inc.
531a62963SBryan Wu  *
631a62963SBryan Wu  * Licensed under the GPL-2 or later.
731a62963SBryan Wu  */
831a62963SBryan Wu 
931a62963SBryan Wu #include <linux/device.h>
1031a62963SBryan Wu #include <linux/input.h>
1131a62963SBryan Wu #include <linux/interrupt.h>
1231a62963SBryan Wu #include <linux/slab.h>
1331a62963SBryan Wu #include <linux/input/ad714x.h>
14d2d8442dSPaul Gortmaker #include <linux/module.h>
1531a62963SBryan Wu #include "ad714x.h"
1631a62963SBryan Wu 
1731a62963SBryan Wu #define AD714X_PWR_CTRL           0x0
1831a62963SBryan Wu #define AD714X_STG_CAL_EN_REG     0x1
1931a62963SBryan Wu #define AD714X_AMB_COMP_CTRL0_REG 0x2
2031a62963SBryan Wu #define AD714X_PARTID_REG         0x17
2131a62963SBryan Wu #define AD7142_PARTID             0xE620
226c04d7b3SBarry Song #define AD7143_PARTID             0xE630
236c04d7b3SBarry Song #define AD7147_PARTID             0x1470
246c04d7b3SBarry Song #define AD7148_PARTID             0x1480
2531a62963SBryan Wu #define AD714X_STAGECFG_REG       0x80
2631a62963SBryan Wu #define AD714X_SYSCFG_REG         0x0
2731a62963SBryan Wu 
2831a62963SBryan Wu #define STG_LOW_INT_EN_REG     0x5
2931a62963SBryan Wu #define STG_HIGH_INT_EN_REG    0x6
3031a62963SBryan Wu #define STG_COM_INT_EN_REG     0x7
3131a62963SBryan Wu #define STG_LOW_INT_STA_REG    0x8
3231a62963SBryan Wu #define STG_HIGH_INT_STA_REG   0x9
3331a62963SBryan Wu #define STG_COM_INT_STA_REG    0xA
3431a62963SBryan Wu 
3531a62963SBryan Wu #define CDC_RESULT_S0          0xB
3631a62963SBryan Wu #define CDC_RESULT_S1          0xC
3731a62963SBryan Wu #define CDC_RESULT_S2          0xD
3831a62963SBryan Wu #define CDC_RESULT_S3          0xE
3931a62963SBryan Wu #define CDC_RESULT_S4          0xF
4031a62963SBryan Wu #define CDC_RESULT_S5          0x10
4131a62963SBryan Wu #define CDC_RESULT_S6          0x11
4231a62963SBryan Wu #define CDC_RESULT_S7          0x12
4331a62963SBryan Wu #define CDC_RESULT_S8          0x13
4431a62963SBryan Wu #define CDC_RESULT_S9          0x14
4531a62963SBryan Wu #define CDC_RESULT_S10         0x15
4631a62963SBryan Wu #define CDC_RESULT_S11         0x16
4731a62963SBryan Wu 
4831a62963SBryan Wu #define STAGE0_AMBIENT		0xF1
4931a62963SBryan Wu #define STAGE1_AMBIENT		0x115
5031a62963SBryan Wu #define STAGE2_AMBIENT		0x139
5131a62963SBryan Wu #define STAGE3_AMBIENT		0x15D
5231a62963SBryan Wu #define STAGE4_AMBIENT		0x181
5331a62963SBryan Wu #define STAGE5_AMBIENT		0x1A5
5431a62963SBryan Wu #define STAGE6_AMBIENT		0x1C9
5531a62963SBryan Wu #define STAGE7_AMBIENT		0x1ED
5631a62963SBryan Wu #define STAGE8_AMBIENT		0x211
5731a62963SBryan Wu #define STAGE9_AMBIENT		0x234
5831a62963SBryan Wu #define STAGE10_AMBIENT		0x259
5931a62963SBryan Wu #define STAGE11_AMBIENT		0x27D
6031a62963SBryan Wu 
6131a62963SBryan Wu #define PER_STAGE_REG_NUM      36
6231a62963SBryan Wu #define STAGE_CFGREG_NUM       8
6331a62963SBryan Wu #define SYS_CFGREG_NUM         8
6431a62963SBryan Wu 
6531a62963SBryan Wu /*
6631a62963SBryan Wu  * driver information which will be used to maintain the software flow
6731a62963SBryan Wu  */
6831a62963SBryan Wu enum ad714x_device_state { IDLE, JITTER, ACTIVE, SPACE };
6931a62963SBryan Wu 
7031a62963SBryan Wu struct ad714x_slider_drv {
7131a62963SBryan Wu 	int highest_stage;
7231a62963SBryan Wu 	int abs_pos;
7331a62963SBryan Wu 	int flt_pos;
7431a62963SBryan Wu 	enum ad714x_device_state state;
7531a62963SBryan Wu 	struct input_dev *input;
7631a62963SBryan Wu };
7731a62963SBryan Wu 
7831a62963SBryan Wu struct ad714x_wheel_drv {
7931a62963SBryan Wu 	int abs_pos;
8031a62963SBryan Wu 	int flt_pos;
8131a62963SBryan Wu 	int pre_highest_stage;
8231a62963SBryan Wu 	int highest_stage;
8331a62963SBryan Wu 	enum ad714x_device_state state;
8431a62963SBryan Wu 	struct input_dev *input;
8531a62963SBryan Wu };
8631a62963SBryan Wu 
8731a62963SBryan Wu struct ad714x_touchpad_drv {
8831a62963SBryan Wu 	int x_highest_stage;
8931a62963SBryan Wu 	int x_flt_pos;
9031a62963SBryan Wu 	int x_abs_pos;
9131a62963SBryan Wu 	int y_highest_stage;
9231a62963SBryan Wu 	int y_flt_pos;
9331a62963SBryan Wu 	int y_abs_pos;
9431a62963SBryan Wu 	int left_ep;
9531a62963SBryan Wu 	int left_ep_val;
9631a62963SBryan Wu 	int right_ep;
9731a62963SBryan Wu 	int right_ep_val;
9831a62963SBryan Wu 	int top_ep;
9931a62963SBryan Wu 	int top_ep_val;
10031a62963SBryan Wu 	int bottom_ep;
10131a62963SBryan Wu 	int bottom_ep_val;
10231a62963SBryan Wu 	enum ad714x_device_state state;
10331a62963SBryan Wu 	struct input_dev *input;
10431a62963SBryan Wu };
10531a62963SBryan Wu 
10631a62963SBryan Wu struct ad714x_button_drv {
10731a62963SBryan Wu 	enum ad714x_device_state state;
10831a62963SBryan Wu 	/*
10931a62963SBryan Wu 	 * Unlike slider/wheel/touchpad, all buttons point to
11031a62963SBryan Wu 	 * same input_dev instance
11131a62963SBryan Wu 	 */
11231a62963SBryan Wu 	struct input_dev *input;
11331a62963SBryan Wu };
11431a62963SBryan Wu 
11531a62963SBryan Wu struct ad714x_driver_data {
11631a62963SBryan Wu 	struct ad714x_slider_drv *slider;
11731a62963SBryan Wu 	struct ad714x_wheel_drv *wheel;
11831a62963SBryan Wu 	struct ad714x_touchpad_drv *touchpad;
11931a62963SBryan Wu 	struct ad714x_button_drv *button;
12031a62963SBryan Wu };
12131a62963SBryan Wu 
12231a62963SBryan Wu /*
12331a62963SBryan Wu  * information to integrate all things which will be private data
12431a62963SBryan Wu  * of spi/i2c device
12531a62963SBryan Wu  */
1269eff794bSMichael Hennerich 
12731a62963SBryan Wu static void ad714x_use_com_int(struct ad714x_chip *ad714x,
12831a62963SBryan Wu 				int start_stage, int end_stage)
12931a62963SBryan Wu {
13031a62963SBryan Wu 	unsigned short data;
13131a62963SBryan Wu 	unsigned short mask;
13231a62963SBryan Wu 
133e223cc7eSMichael Hennerich 	mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);
13431a62963SBryan Wu 
1359eff794bSMichael Hennerich 	ad714x->read(ad714x, STG_COM_INT_EN_REG, &data, 1);
136e223cc7eSMichael Hennerich 	data |= 1 << end_stage;
137c0409febSDmitry Torokhov 	ad714x->write(ad714x, STG_COM_INT_EN_REG, data);
13831a62963SBryan Wu 
1399eff794bSMichael Hennerich 	ad714x->read(ad714x, STG_HIGH_INT_EN_REG, &data, 1);
14031a62963SBryan Wu 	data &= ~mask;
141c0409febSDmitry Torokhov 	ad714x->write(ad714x, STG_HIGH_INT_EN_REG, data);
14231a62963SBryan Wu }
14331a62963SBryan Wu 
14431a62963SBryan Wu static void ad714x_use_thr_int(struct ad714x_chip *ad714x,
14531a62963SBryan Wu 				int start_stage, int end_stage)
14631a62963SBryan Wu {
14731a62963SBryan Wu 	unsigned short data;
14831a62963SBryan Wu 	unsigned short mask;
14931a62963SBryan Wu 
150e223cc7eSMichael Hennerich 	mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);
15131a62963SBryan Wu 
1529eff794bSMichael Hennerich 	ad714x->read(ad714x, STG_COM_INT_EN_REG, &data, 1);
153e223cc7eSMichael Hennerich 	data &= ~(1 << end_stage);
154c0409febSDmitry Torokhov 	ad714x->write(ad714x, STG_COM_INT_EN_REG, data);
15531a62963SBryan Wu 
1569eff794bSMichael Hennerich 	ad714x->read(ad714x, STG_HIGH_INT_EN_REG, &data, 1);
15731a62963SBryan Wu 	data |= mask;
158c0409febSDmitry Torokhov 	ad714x->write(ad714x, STG_HIGH_INT_EN_REG, data);
15931a62963SBryan Wu }
16031a62963SBryan Wu 
16131a62963SBryan Wu static int ad714x_cal_highest_stage(struct ad714x_chip *ad714x,
16231a62963SBryan Wu 					int start_stage, int end_stage)
16331a62963SBryan Wu {
16431a62963SBryan Wu 	int max_res = 0;
16531a62963SBryan Wu 	int max_idx = 0;
16631a62963SBryan Wu 	int i;
16731a62963SBryan Wu 
16831a62963SBryan Wu 	for (i = start_stage; i <= end_stage; i++) {
16931a62963SBryan Wu 		if (ad714x->sensor_val[i] > max_res) {
17031a62963SBryan Wu 			max_res = ad714x->sensor_val[i];
17131a62963SBryan Wu 			max_idx = i;
17231a62963SBryan Wu 		}
17331a62963SBryan Wu 	}
17431a62963SBryan Wu 
17531a62963SBryan Wu 	return max_idx;
17631a62963SBryan Wu }
17731a62963SBryan Wu 
17831a62963SBryan Wu static int ad714x_cal_abs_pos(struct ad714x_chip *ad714x,
17931a62963SBryan Wu 				int start_stage, int end_stage,
18031a62963SBryan Wu 				int highest_stage, int max_coord)
18131a62963SBryan Wu {
18231a62963SBryan Wu 	int a_param, b_param;
18331a62963SBryan Wu 
18431a62963SBryan Wu 	if (highest_stage == start_stage) {
18531a62963SBryan Wu 		a_param = ad714x->sensor_val[start_stage + 1];
18631a62963SBryan Wu 		b_param = ad714x->sensor_val[start_stage] +
18731a62963SBryan Wu 			ad714x->sensor_val[start_stage + 1];
18831a62963SBryan Wu 	} else if (highest_stage == end_stage) {
18931a62963SBryan Wu 		a_param = ad714x->sensor_val[end_stage] *
19031a62963SBryan Wu 			(end_stage - start_stage) +
19131a62963SBryan Wu 			ad714x->sensor_val[end_stage - 1] *
19231a62963SBryan Wu 			(end_stage - start_stage - 1);
19331a62963SBryan Wu 		b_param = ad714x->sensor_val[end_stage] +
19431a62963SBryan Wu 			ad714x->sensor_val[end_stage - 1];
19531a62963SBryan Wu 	} else {
19631a62963SBryan Wu 		a_param = ad714x->sensor_val[highest_stage] *
19731a62963SBryan Wu 			(highest_stage - start_stage) +
19831a62963SBryan Wu 			ad714x->sensor_val[highest_stage - 1] *
19931a62963SBryan Wu 			(highest_stage - start_stage - 1) +
20031a62963SBryan Wu 			ad714x->sensor_val[highest_stage + 1] *
20131a62963SBryan Wu 			(highest_stage - start_stage + 1);
20231a62963SBryan Wu 		b_param = ad714x->sensor_val[highest_stage] +
20331a62963SBryan Wu 			ad714x->sensor_val[highest_stage - 1] +
20431a62963SBryan Wu 			ad714x->sensor_val[highest_stage + 1];
20531a62963SBryan Wu 	}
20631a62963SBryan Wu 
20731a62963SBryan Wu 	return (max_coord / (end_stage - start_stage)) * a_param / b_param;
20831a62963SBryan Wu }
20931a62963SBryan Wu 
21031a62963SBryan Wu /*
21131a62963SBryan Wu  * One button can connect to multi positive and negative of CDCs
21231a62963SBryan Wu  * Multi-buttons can connect to same positive/negative of one CDC
21331a62963SBryan Wu  */
21431a62963SBryan Wu static void ad714x_button_state_machine(struct ad714x_chip *ad714x, int idx)
21531a62963SBryan Wu {
21631a62963SBryan Wu 	struct ad714x_button_plat *hw = &ad714x->hw->button[idx];
21731a62963SBryan Wu 	struct ad714x_button_drv *sw = &ad714x->sw->button[idx];
21831a62963SBryan Wu 
21931a62963SBryan Wu 	switch (sw->state) {
22031a62963SBryan Wu 	case IDLE:
22131a62963SBryan Wu 		if (((ad714x->h_state & hw->h_mask) == hw->h_mask) &&
22231a62963SBryan Wu 		    ((ad714x->l_state & hw->l_mask) == hw->l_mask)) {
22331a62963SBryan Wu 			dev_dbg(ad714x->dev, "button %d touched\n", idx);
22431a62963SBryan Wu 			input_report_key(sw->input, hw->keycode, 1);
22531a62963SBryan Wu 			input_sync(sw->input);
22631a62963SBryan Wu 			sw->state = ACTIVE;
22731a62963SBryan Wu 		}
22831a62963SBryan Wu 		break;
22931a62963SBryan Wu 
23031a62963SBryan Wu 	case ACTIVE:
23131a62963SBryan Wu 		if (((ad714x->h_state & hw->h_mask) != hw->h_mask) ||
23231a62963SBryan Wu 		    ((ad714x->l_state & hw->l_mask) != hw->l_mask)) {
23331a62963SBryan Wu 			dev_dbg(ad714x->dev, "button %d released\n", idx);
23431a62963SBryan Wu 			input_report_key(sw->input, hw->keycode, 0);
23531a62963SBryan Wu 			input_sync(sw->input);
23631a62963SBryan Wu 			sw->state = IDLE;
23731a62963SBryan Wu 		}
23831a62963SBryan Wu 		break;
23931a62963SBryan Wu 
24031a62963SBryan Wu 	default:
24131a62963SBryan Wu 		break;
24231a62963SBryan Wu 	}
24331a62963SBryan Wu }
24431a62963SBryan Wu 
24531a62963SBryan Wu /*
24631a62963SBryan Wu  * The response of a sensor is defined by the absolute number of codes
24731a62963SBryan Wu  * between the current CDC value and the ambient value.
24831a62963SBryan Wu  */
24931a62963SBryan Wu static void ad714x_slider_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
25031a62963SBryan Wu {
25131a62963SBryan Wu 	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
25231a62963SBryan Wu 	int i;
25331a62963SBryan Wu 
2549eff794bSMichael Hennerich 	ad714x->read(ad714x, CDC_RESULT_S0 + hw->start_stage,
2559eff794bSMichael Hennerich 			&ad714x->adc_reg[hw->start_stage],
2569eff794bSMichael Hennerich 			hw->end_stage - hw->start_stage + 1);
25731a62963SBryan Wu 
2589eff794bSMichael Hennerich 	for (i = hw->start_stage; i <= hw->end_stage; i++) {
2599eff794bSMichael Hennerich 		ad714x->read(ad714x, STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
2609eff794bSMichael Hennerich 				&ad714x->amb_reg[i], 1);
2619eff794bSMichael Hennerich 
2629eff794bSMichael Hennerich 		ad714x->sensor_val[i] =
2639eff794bSMichael Hennerich 			abs(ad714x->adc_reg[i] - ad714x->amb_reg[i]);
26431a62963SBryan Wu 	}
26531a62963SBryan Wu }
26631a62963SBryan Wu 
26731a62963SBryan Wu static void ad714x_slider_cal_highest_stage(struct ad714x_chip *ad714x, int idx)
26831a62963SBryan Wu {
26931a62963SBryan Wu 	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
27031a62963SBryan Wu 	struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx];
27131a62963SBryan Wu 
27231a62963SBryan Wu 	sw->highest_stage = ad714x_cal_highest_stage(ad714x, hw->start_stage,
27331a62963SBryan Wu 			hw->end_stage);
27431a62963SBryan Wu 
27531a62963SBryan Wu 	dev_dbg(ad714x->dev, "slider %d highest_stage:%d\n", idx,
27631a62963SBryan Wu 		sw->highest_stage);
27731a62963SBryan Wu }
27831a62963SBryan Wu 
27931a62963SBryan Wu /*
28031a62963SBryan Wu  * The formulae are very straight forward. It uses the sensor with the
28131a62963SBryan Wu  * highest response and the 2 adjacent ones.
28231a62963SBryan Wu  * When Sensor 0 has the highest response, only sensor 0 and sensor 1
28331a62963SBryan Wu  * are used in the calculations. Similarly when the last sensor has the
28431a62963SBryan Wu  * highest response, only the last sensor and the second last sensors
28531a62963SBryan Wu  * are used in the calculations.
28631a62963SBryan Wu  *
28731a62963SBryan Wu  * For i= idx_of_peak_Sensor-1 to i= idx_of_peak_Sensor+1
28831a62963SBryan Wu  *         v += Sensor response(i)*i
28931a62963SBryan Wu  *         w += Sensor response(i)
29031a62963SBryan Wu  * POS=(Number_of_Positions_Wanted/(Number_of_Sensors_Used-1)) *(v/w)
29131a62963SBryan Wu  */
29231a62963SBryan Wu static void ad714x_slider_cal_abs_pos(struct ad714x_chip *ad714x, int idx)
29331a62963SBryan Wu {
29431a62963SBryan Wu 	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
29531a62963SBryan Wu 	struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx];
29631a62963SBryan Wu 
29731a62963SBryan Wu 	sw->abs_pos = ad714x_cal_abs_pos(ad714x, hw->start_stage, hw->end_stage,
29831a62963SBryan Wu 		sw->highest_stage, hw->max_coord);
29931a62963SBryan Wu 
30031a62963SBryan Wu 	dev_dbg(ad714x->dev, "slider %d absolute position:%d\n", idx,
30131a62963SBryan Wu 		sw->abs_pos);
30231a62963SBryan Wu }
30331a62963SBryan Wu 
30431a62963SBryan Wu /*
30531a62963SBryan Wu  * To minimise the Impact of the noise on the algorithm, ADI developed a
30631a62963SBryan Wu  * routine that filters the CDC results after they have been read by the
30731a62963SBryan Wu  * host processor.
30831a62963SBryan Wu  * The filter used is an Infinite Input Response(IIR) filter implemented
30931a62963SBryan Wu  * in firmware and attenuates the noise on the CDC results after they've
31031a62963SBryan Wu  * been read by the host processor.
31131a62963SBryan Wu  * Filtered_CDC_result = (Filtered_CDC_result * (10 - Coefficient) +
31231a62963SBryan Wu  *				Latest_CDC_result * Coefficient)/10
31331a62963SBryan Wu  */
31431a62963SBryan Wu static void ad714x_slider_cal_flt_pos(struct ad714x_chip *ad714x, int idx)
31531a62963SBryan Wu {
31631a62963SBryan Wu 	struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx];
31731a62963SBryan Wu 
31831a62963SBryan Wu 	sw->flt_pos = (sw->flt_pos * (10 - 4) +
31931a62963SBryan Wu 			sw->abs_pos * 4)/10;
32031a62963SBryan Wu 
32131a62963SBryan Wu 	dev_dbg(ad714x->dev, "slider %d filter position:%d\n", idx,
32231a62963SBryan Wu 		sw->flt_pos);
32331a62963SBryan Wu }
32431a62963SBryan Wu 
32531a62963SBryan Wu static void ad714x_slider_use_com_int(struct ad714x_chip *ad714x, int idx)
32631a62963SBryan Wu {
32731a62963SBryan Wu 	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
32831a62963SBryan Wu 
32931a62963SBryan Wu 	ad714x_use_com_int(ad714x, hw->start_stage, hw->end_stage);
33031a62963SBryan Wu }
33131a62963SBryan Wu 
33231a62963SBryan Wu static void ad714x_slider_use_thr_int(struct ad714x_chip *ad714x, int idx)
33331a62963SBryan Wu {
33431a62963SBryan Wu 	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
33531a62963SBryan Wu 
33631a62963SBryan Wu 	ad714x_use_thr_int(ad714x, hw->start_stage, hw->end_stage);
33731a62963SBryan Wu }
33831a62963SBryan Wu 
33931a62963SBryan Wu static void ad714x_slider_state_machine(struct ad714x_chip *ad714x, int idx)
34031a62963SBryan Wu {
34131a62963SBryan Wu 	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
34231a62963SBryan Wu 	struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx];
34331a62963SBryan Wu 	unsigned short h_state, c_state;
34431a62963SBryan Wu 	unsigned short mask;
34531a62963SBryan Wu 
34631a62963SBryan Wu 	mask = ((1 << (hw->end_stage + 1)) - 1) - ((1 << hw->start_stage) - 1);
34731a62963SBryan Wu 
34831a62963SBryan Wu 	h_state = ad714x->h_state & mask;
34931a62963SBryan Wu 	c_state = ad714x->c_state & mask;
35031a62963SBryan Wu 
35131a62963SBryan Wu 	switch (sw->state) {
35231a62963SBryan Wu 	case IDLE:
35331a62963SBryan Wu 		if (h_state) {
35431a62963SBryan Wu 			sw->state = JITTER;
35531a62963SBryan Wu 			/* In End of Conversion interrupt mode, the AD714X
35631a62963SBryan Wu 			 * continuously generates hardware interrupts.
35731a62963SBryan Wu 			 */
35831a62963SBryan Wu 			ad714x_slider_use_com_int(ad714x, idx);
35931a62963SBryan Wu 			dev_dbg(ad714x->dev, "slider %d touched\n", idx);
36031a62963SBryan Wu 		}
36131a62963SBryan Wu 		break;
36231a62963SBryan Wu 
36331a62963SBryan Wu 	case JITTER:
36431a62963SBryan Wu 		if (c_state == mask) {
36531a62963SBryan Wu 			ad714x_slider_cal_sensor_val(ad714x, idx);
36631a62963SBryan Wu 			ad714x_slider_cal_highest_stage(ad714x, idx);
36731a62963SBryan Wu 			ad714x_slider_cal_abs_pos(ad714x, idx);
36831a62963SBryan Wu 			sw->flt_pos = sw->abs_pos;
36931a62963SBryan Wu 			sw->state = ACTIVE;
37031a62963SBryan Wu 		}
37131a62963SBryan Wu 		break;
37231a62963SBryan Wu 
37331a62963SBryan Wu 	case ACTIVE:
37431a62963SBryan Wu 		if (c_state == mask) {
37531a62963SBryan Wu 			if (h_state) {
37631a62963SBryan Wu 				ad714x_slider_cal_sensor_val(ad714x, idx);
37731a62963SBryan Wu 				ad714x_slider_cal_highest_stage(ad714x, idx);
37831a62963SBryan Wu 				ad714x_slider_cal_abs_pos(ad714x, idx);
37931a62963SBryan Wu 				ad714x_slider_cal_flt_pos(ad714x, idx);
38031a62963SBryan Wu 				input_report_abs(sw->input, ABS_X, sw->flt_pos);
38131a62963SBryan Wu 				input_report_key(sw->input, BTN_TOUCH, 1);
38231a62963SBryan Wu 			} else {
38331a62963SBryan Wu 				/* When the user lifts off the sensor, configure
38431a62963SBryan Wu 				 * the AD714X back to threshold interrupt mode.
38531a62963SBryan Wu 				 */
38631a62963SBryan Wu 				ad714x_slider_use_thr_int(ad714x, idx);
38731a62963SBryan Wu 				sw->state = IDLE;
38831a62963SBryan Wu 				input_report_key(sw->input, BTN_TOUCH, 0);
38931a62963SBryan Wu 				dev_dbg(ad714x->dev, "slider %d released\n",
39031a62963SBryan Wu 					idx);
39131a62963SBryan Wu 			}
39231a62963SBryan Wu 			input_sync(sw->input);
39331a62963SBryan Wu 		}
39431a62963SBryan Wu 		break;
39531a62963SBryan Wu 
39631a62963SBryan Wu 	default:
39731a62963SBryan Wu 		break;
39831a62963SBryan Wu 	}
39931a62963SBryan Wu }
40031a62963SBryan Wu 
40131a62963SBryan Wu /*
40231a62963SBryan Wu  * When the scroll wheel is activated, we compute the absolute position based
40331a62963SBryan Wu  * on the sensor values. To calculate the position, we first determine the
40431a62963SBryan Wu  * sensor that has the greatest response among the 8 sensors that constitutes
40531a62963SBryan Wu  * the scrollwheel. Then we determined the 2 sensors on either sides of the
40631a62963SBryan Wu  * sensor with the highest response and we apply weights to these sensors.
40731a62963SBryan Wu  */
40831a62963SBryan Wu static void ad714x_wheel_cal_highest_stage(struct ad714x_chip *ad714x, int idx)
40931a62963SBryan Wu {
41031a62963SBryan Wu 	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
41131a62963SBryan Wu 	struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
41231a62963SBryan Wu 
41331a62963SBryan Wu 	sw->pre_highest_stage = sw->highest_stage;
41431a62963SBryan Wu 	sw->highest_stage = ad714x_cal_highest_stage(ad714x, hw->start_stage,
41531a62963SBryan Wu 			hw->end_stage);
41631a62963SBryan Wu 
41731a62963SBryan Wu 	dev_dbg(ad714x->dev, "wheel %d highest_stage:%d\n", idx,
41831a62963SBryan Wu 		sw->highest_stage);
41931a62963SBryan Wu }
42031a62963SBryan Wu 
42131a62963SBryan Wu static void ad714x_wheel_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
42231a62963SBryan Wu {
42331a62963SBryan Wu 	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
42431a62963SBryan Wu 	int i;
42531a62963SBryan Wu 
4269eff794bSMichael Hennerich 	ad714x->read(ad714x, CDC_RESULT_S0 + hw->start_stage,
4279eff794bSMichael Hennerich 			&ad714x->adc_reg[hw->start_stage],
4289eff794bSMichael Hennerich 			hw->end_stage - hw->start_stage + 1);
4299eff794bSMichael Hennerich 
43031a62963SBryan Wu 	for (i = hw->start_stage; i <= hw->end_stage; i++) {
431c0409febSDmitry Torokhov 		ad714x->read(ad714x, STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
4329eff794bSMichael Hennerich 				&ad714x->amb_reg[i], 1);
43331a62963SBryan Wu 		if (ad714x->adc_reg[i] > ad714x->amb_reg[i])
4349eff794bSMichael Hennerich 			ad714x->sensor_val[i] =
4359eff794bSMichael Hennerich 				ad714x->adc_reg[i] - ad714x->amb_reg[i];
43631a62963SBryan Wu 		else
43731a62963SBryan Wu 			ad714x->sensor_val[i] = 0;
43831a62963SBryan Wu 	}
43931a62963SBryan Wu }
44031a62963SBryan Wu 
44131a62963SBryan Wu /*
44231a62963SBryan Wu  * When the scroll wheel is activated, we compute the absolute position based
44331a62963SBryan Wu  * on the sensor values. To calculate the position, we first determine the
444f1e430e6SMichael Hennerich  * sensor that has the greatest response among the sensors that constitutes
445f1e430e6SMichael Hennerich  * the scrollwheel. Then we determined the sensors on either sides of the
44631a62963SBryan Wu  * sensor with the highest response and we apply weights to these sensors. The
447f1e430e6SMichael Hennerich  * result of this computation gives us the mean value.
44831a62963SBryan Wu  */
44931a62963SBryan Wu 
45031a62963SBryan Wu static void ad714x_wheel_cal_abs_pos(struct ad714x_chip *ad714x, int idx)
45131a62963SBryan Wu {
45231a62963SBryan Wu 	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
45331a62963SBryan Wu 	struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
45431a62963SBryan Wu 	int stage_num = hw->end_stage - hw->start_stage + 1;
455f1e430e6SMichael Hennerich 	int first_before, highest, first_after;
45631a62963SBryan Wu 	int a_param, b_param;
45731a62963SBryan Wu 
45831a62963SBryan Wu 	first_before = (sw->highest_stage + stage_num - 1) % stage_num;
45931a62963SBryan Wu 	highest = sw->highest_stage;
46031a62963SBryan Wu 	first_after = (sw->highest_stage + stage_num + 1) % stage_num;
46131a62963SBryan Wu 
462f1e430e6SMichael Hennerich 	a_param = ad714x->sensor_val[highest] *
463f1e430e6SMichael Hennerich 		(highest - hw->start_stage) +
46431a62963SBryan Wu 		ad714x->sensor_val[first_before] *
465f1e430e6SMichael Hennerich 		(highest - hw->start_stage - 1) +
46631a62963SBryan Wu 		ad714x->sensor_val[first_after] *
467f1e430e6SMichael Hennerich 		(highest - hw->start_stage + 1);
468f1e430e6SMichael Hennerich 	b_param = ad714x->sensor_val[highest] +
46931a62963SBryan Wu 		ad714x->sensor_val[first_before] +
470f1e430e6SMichael Hennerich 		ad714x->sensor_val[first_after];
47131a62963SBryan Wu 
472f1e430e6SMichael Hennerich 	sw->abs_pos = ((hw->max_coord / (hw->end_stage - hw->start_stage)) *
473f1e430e6SMichael Hennerich 			a_param) / b_param;
47431a62963SBryan Wu 
47531a62963SBryan Wu 	if (sw->abs_pos > hw->max_coord)
47631a62963SBryan Wu 		sw->abs_pos = hw->max_coord;
477f1e430e6SMichael Hennerich 	else if (sw->abs_pos < 0)
478f1e430e6SMichael Hennerich 		sw->abs_pos = 0;
47931a62963SBryan Wu }
48031a62963SBryan Wu 
48131a62963SBryan Wu static void ad714x_wheel_cal_flt_pos(struct ad714x_chip *ad714x, int idx)
48231a62963SBryan Wu {
48331a62963SBryan Wu 	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
48431a62963SBryan Wu 	struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
48531a62963SBryan Wu 	if (((sw->pre_highest_stage == hw->end_stage) &&
48631a62963SBryan Wu 			(sw->highest_stage == hw->start_stage)) ||
48731a62963SBryan Wu 	    ((sw->pre_highest_stage == hw->start_stage) &&
48831a62963SBryan Wu 			(sw->highest_stage == hw->end_stage)))
48931a62963SBryan Wu 		sw->flt_pos = sw->abs_pos;
49031a62963SBryan Wu 	else
49131a62963SBryan Wu 		sw->flt_pos = ((sw->flt_pos * 30) + (sw->abs_pos * 71)) / 100;
49231a62963SBryan Wu 
49331a62963SBryan Wu 	if (sw->flt_pos > hw->max_coord)
49431a62963SBryan Wu 		sw->flt_pos = hw->max_coord;
49531a62963SBryan Wu }
49631a62963SBryan Wu 
49731a62963SBryan Wu static void ad714x_wheel_use_com_int(struct ad714x_chip *ad714x, int idx)
49831a62963SBryan Wu {
49931a62963SBryan Wu 	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
50031a62963SBryan Wu 
50131a62963SBryan Wu 	ad714x_use_com_int(ad714x, hw->start_stage, hw->end_stage);
50231a62963SBryan Wu }
50331a62963SBryan Wu 
50431a62963SBryan Wu static void ad714x_wheel_use_thr_int(struct ad714x_chip *ad714x, int idx)
50531a62963SBryan Wu {
50631a62963SBryan Wu 	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
50731a62963SBryan Wu 
50831a62963SBryan Wu 	ad714x_use_thr_int(ad714x, hw->start_stage, hw->end_stage);
50931a62963SBryan Wu }
51031a62963SBryan Wu 
51131a62963SBryan Wu static void ad714x_wheel_state_machine(struct ad714x_chip *ad714x, int idx)
51231a62963SBryan Wu {
51331a62963SBryan Wu 	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
51431a62963SBryan Wu 	struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
51531a62963SBryan Wu 	unsigned short h_state, c_state;
51631a62963SBryan Wu 	unsigned short mask;
51731a62963SBryan Wu 
51831a62963SBryan Wu 	mask = ((1 << (hw->end_stage + 1)) - 1) - ((1 << hw->start_stage) - 1);
51931a62963SBryan Wu 
52031a62963SBryan Wu 	h_state = ad714x->h_state & mask;
52131a62963SBryan Wu 	c_state = ad714x->c_state & mask;
52231a62963SBryan Wu 
52331a62963SBryan Wu 	switch (sw->state) {
52431a62963SBryan Wu 	case IDLE:
52531a62963SBryan Wu 		if (h_state) {
52631a62963SBryan Wu 			sw->state = JITTER;
52731a62963SBryan Wu 			/* In End of Conversion interrupt mode, the AD714X
52831a62963SBryan Wu 			 * continuously generates hardware interrupts.
52931a62963SBryan Wu 			 */
53031a62963SBryan Wu 			ad714x_wheel_use_com_int(ad714x, idx);
53131a62963SBryan Wu 			dev_dbg(ad714x->dev, "wheel %d touched\n", idx);
53231a62963SBryan Wu 		}
53331a62963SBryan Wu 		break;
53431a62963SBryan Wu 
53531a62963SBryan Wu 	case JITTER:
53631a62963SBryan Wu 		if (c_state == mask)	{
53731a62963SBryan Wu 			ad714x_wheel_cal_sensor_val(ad714x, idx);
53831a62963SBryan Wu 			ad714x_wheel_cal_highest_stage(ad714x, idx);
53931a62963SBryan Wu 			ad714x_wheel_cal_abs_pos(ad714x, idx);
54031a62963SBryan Wu 			sw->flt_pos = sw->abs_pos;
54131a62963SBryan Wu 			sw->state = ACTIVE;
54231a62963SBryan Wu 		}
54331a62963SBryan Wu 		break;
54431a62963SBryan Wu 
54531a62963SBryan Wu 	case ACTIVE:
54631a62963SBryan Wu 		if (c_state == mask) {
54731a62963SBryan Wu 			if (h_state) {
54831a62963SBryan Wu 				ad714x_wheel_cal_sensor_val(ad714x, idx);
54931a62963SBryan Wu 				ad714x_wheel_cal_highest_stage(ad714x, idx);
55031a62963SBryan Wu 				ad714x_wheel_cal_abs_pos(ad714x, idx);
55131a62963SBryan Wu 				ad714x_wheel_cal_flt_pos(ad714x, idx);
55231a62963SBryan Wu 				input_report_abs(sw->input, ABS_WHEEL,
553f1e430e6SMichael Hennerich 					sw->flt_pos);
55431a62963SBryan Wu 				input_report_key(sw->input, BTN_TOUCH, 1);
55531a62963SBryan Wu 			} else {
55631a62963SBryan Wu 				/* When the user lifts off the sensor, configure
55731a62963SBryan Wu 				 * the AD714X back to threshold interrupt mode.
55831a62963SBryan Wu 				 */
55931a62963SBryan Wu 				ad714x_wheel_use_thr_int(ad714x, idx);
56031a62963SBryan Wu 				sw->state = IDLE;
56131a62963SBryan Wu 				input_report_key(sw->input, BTN_TOUCH, 0);
56231a62963SBryan Wu 
56331a62963SBryan Wu 				dev_dbg(ad714x->dev, "wheel %d released\n",
56431a62963SBryan Wu 					idx);
56531a62963SBryan Wu 			}
56631a62963SBryan Wu 			input_sync(sw->input);
56731a62963SBryan Wu 		}
56831a62963SBryan Wu 		break;
56931a62963SBryan Wu 
57031a62963SBryan Wu 	default:
57131a62963SBryan Wu 		break;
57231a62963SBryan Wu 	}
57331a62963SBryan Wu }
57431a62963SBryan Wu 
57531a62963SBryan Wu static void touchpad_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
57631a62963SBryan Wu {
57731a62963SBryan Wu 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
57831a62963SBryan Wu 	int i;
57931a62963SBryan Wu 
5809eff794bSMichael Hennerich 	ad714x->read(ad714x, CDC_RESULT_S0 + hw->x_start_stage,
5819eff794bSMichael Hennerich 			&ad714x->adc_reg[hw->x_start_stage],
5829eff794bSMichael Hennerich 			hw->x_end_stage - hw->x_start_stage + 1);
5839eff794bSMichael Hennerich 
58431a62963SBryan Wu 	for (i = hw->x_start_stage; i <= hw->x_end_stage; i++) {
585c0409febSDmitry Torokhov 		ad714x->read(ad714x, STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
5869eff794bSMichael Hennerich 				&ad714x->amb_reg[i], 1);
58731a62963SBryan Wu 		if (ad714x->adc_reg[i] > ad714x->amb_reg[i])
5889eff794bSMichael Hennerich 			ad714x->sensor_val[i] =
5899eff794bSMichael Hennerich 				ad714x->adc_reg[i] - ad714x->amb_reg[i];
59031a62963SBryan Wu 		else
59131a62963SBryan Wu 			ad714x->sensor_val[i] = 0;
59231a62963SBryan Wu 	}
59331a62963SBryan Wu }
59431a62963SBryan Wu 
59531a62963SBryan Wu static void touchpad_cal_highest_stage(struct ad714x_chip *ad714x, int idx)
59631a62963SBryan Wu {
59731a62963SBryan Wu 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
59831a62963SBryan Wu 	struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
59931a62963SBryan Wu 
60031a62963SBryan Wu 	sw->x_highest_stage = ad714x_cal_highest_stage(ad714x,
60131a62963SBryan Wu 		hw->x_start_stage, hw->x_end_stage);
60231a62963SBryan Wu 	sw->y_highest_stage = ad714x_cal_highest_stage(ad714x,
60331a62963SBryan Wu 		hw->y_start_stage, hw->y_end_stage);
60431a62963SBryan Wu 
60531a62963SBryan Wu 	dev_dbg(ad714x->dev,
60631a62963SBryan Wu 		"touchpad %d x_highest_stage:%d, y_highest_stage:%d\n",
60731a62963SBryan Wu 		idx, sw->x_highest_stage, sw->y_highest_stage);
60831a62963SBryan Wu }
60931a62963SBryan Wu 
61031a62963SBryan Wu /*
61131a62963SBryan Wu  * If 2 fingers are touching the sensor then 2 peaks can be observed in the
61231a62963SBryan Wu  * distribution.
61331a62963SBryan Wu  * The arithmetic doesn't support to get absolute coordinates for multi-touch
61431a62963SBryan Wu  * yet.
61531a62963SBryan Wu  */
61631a62963SBryan Wu static int touchpad_check_second_peak(struct ad714x_chip *ad714x, int idx)
61731a62963SBryan Wu {
61831a62963SBryan Wu 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
61931a62963SBryan Wu 	struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
62031a62963SBryan Wu 	int i;
62131a62963SBryan Wu 
62231a62963SBryan Wu 	for (i = hw->x_start_stage; i < sw->x_highest_stage; i++) {
62331a62963SBryan Wu 		if ((ad714x->sensor_val[i] - ad714x->sensor_val[i + 1])
62431a62963SBryan Wu 			> (ad714x->sensor_val[i + 1] / 10))
62531a62963SBryan Wu 			return 1;
62631a62963SBryan Wu 	}
62731a62963SBryan Wu 
62831a62963SBryan Wu 	for (i = sw->x_highest_stage; i < hw->x_end_stage; i++) {
62931a62963SBryan Wu 		if ((ad714x->sensor_val[i + 1] - ad714x->sensor_val[i])
63031a62963SBryan Wu 			> (ad714x->sensor_val[i] / 10))
63131a62963SBryan Wu 			return 1;
63231a62963SBryan Wu 	}
63331a62963SBryan Wu 
63431a62963SBryan Wu 	for (i = hw->y_start_stage; i < sw->y_highest_stage; i++) {
63531a62963SBryan Wu 		if ((ad714x->sensor_val[i] - ad714x->sensor_val[i + 1])
63631a62963SBryan Wu 			> (ad714x->sensor_val[i + 1] / 10))
63731a62963SBryan Wu 			return 1;
63831a62963SBryan Wu 	}
63931a62963SBryan Wu 
64031a62963SBryan Wu 	for (i = sw->y_highest_stage; i < hw->y_end_stage; i++) {
64131a62963SBryan Wu 		if ((ad714x->sensor_val[i + 1] - ad714x->sensor_val[i])
64231a62963SBryan Wu 			> (ad714x->sensor_val[i] / 10))
64331a62963SBryan Wu 			return 1;
64431a62963SBryan Wu 	}
64531a62963SBryan Wu 
64631a62963SBryan Wu 	return 0;
64731a62963SBryan Wu }
64831a62963SBryan Wu 
64931a62963SBryan Wu /*
65031a62963SBryan Wu  * If only one finger is used to activate the touch pad then only 1 peak will be
65131a62963SBryan Wu  * registered in the distribution. This peak and the 2 adjacent sensors will be
65231a62963SBryan Wu  * used in the calculation of the absolute position. This will prevent hand
65331a62963SBryan Wu  * shadows to affect the absolute position calculation.
65431a62963SBryan Wu  */
65531a62963SBryan Wu static void touchpad_cal_abs_pos(struct ad714x_chip *ad714x, int idx)
65631a62963SBryan Wu {
65731a62963SBryan Wu 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
65831a62963SBryan Wu 	struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
65931a62963SBryan Wu 
66031a62963SBryan Wu 	sw->x_abs_pos = ad714x_cal_abs_pos(ad714x, hw->x_start_stage,
66131a62963SBryan Wu 			hw->x_end_stage, sw->x_highest_stage, hw->x_max_coord);
66231a62963SBryan Wu 	sw->y_abs_pos = ad714x_cal_abs_pos(ad714x, hw->y_start_stage,
66331a62963SBryan Wu 			hw->y_end_stage, sw->y_highest_stage, hw->y_max_coord);
66431a62963SBryan Wu 
66531a62963SBryan Wu 	dev_dbg(ad714x->dev, "touchpad %d absolute position:(%d, %d)\n", idx,
66631a62963SBryan Wu 			sw->x_abs_pos, sw->y_abs_pos);
66731a62963SBryan Wu }
66831a62963SBryan Wu 
66931a62963SBryan Wu static void touchpad_cal_flt_pos(struct ad714x_chip *ad714x, int idx)
67031a62963SBryan Wu {
67131a62963SBryan Wu 	struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
67231a62963SBryan Wu 
67331a62963SBryan Wu 	sw->x_flt_pos = (sw->x_flt_pos * (10 - 4) +
67431a62963SBryan Wu 			sw->x_abs_pos * 4)/10;
67531a62963SBryan Wu 	sw->y_flt_pos = (sw->y_flt_pos * (10 - 4) +
67631a62963SBryan Wu 			sw->y_abs_pos * 4)/10;
67731a62963SBryan Wu 
67831a62963SBryan Wu 	dev_dbg(ad714x->dev, "touchpad %d filter position:(%d, %d)\n",
67931a62963SBryan Wu 			idx, sw->x_flt_pos, sw->y_flt_pos);
68031a62963SBryan Wu }
68131a62963SBryan Wu 
68231a62963SBryan Wu /*
68331a62963SBryan Wu  * To prevent distortion from showing in the absolute position, it is
68431a62963SBryan Wu  * necessary to detect the end points. When endpoints are detected, the
68531a62963SBryan Wu  * driver stops updating the status variables with absolute positions.
68631a62963SBryan Wu  * End points are detected on the 4 edges of the touchpad sensor. The
68731a62963SBryan Wu  * method to detect them is the same for all 4.
68831a62963SBryan Wu  * To detect the end points, the firmware computes the difference in
68931a62963SBryan Wu  * percent between the sensor on the edge and the adjacent one. The
69031a62963SBryan Wu  * difference is calculated in percent in order to make the end point
69131a62963SBryan Wu  * detection independent of the pressure.
69231a62963SBryan Wu  */
69331a62963SBryan Wu 
69431a62963SBryan Wu #define LEFT_END_POINT_DETECTION_LEVEL                  550
69531a62963SBryan Wu #define RIGHT_END_POINT_DETECTION_LEVEL                 750
69631a62963SBryan Wu #define LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL         850
69731a62963SBryan Wu #define TOP_END_POINT_DETECTION_LEVEL                   550
69831a62963SBryan Wu #define BOTTOM_END_POINT_DETECTION_LEVEL                950
69931a62963SBryan Wu #define TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL         700
70031a62963SBryan Wu static int touchpad_check_endpoint(struct ad714x_chip *ad714x, int idx)
70131a62963SBryan Wu {
70231a62963SBryan Wu 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
70331a62963SBryan Wu 	struct ad714x_touchpad_drv *sw  = &ad714x->sw->touchpad[idx];
70431a62963SBryan Wu 	int percent_sensor_diff;
70531a62963SBryan Wu 
70631a62963SBryan Wu 	/* left endpoint detect */
70731a62963SBryan Wu 	percent_sensor_diff = (ad714x->sensor_val[hw->x_start_stage] -
70831a62963SBryan Wu 			ad714x->sensor_val[hw->x_start_stage + 1]) * 100 /
70931a62963SBryan Wu 			ad714x->sensor_val[hw->x_start_stage + 1];
71031a62963SBryan Wu 	if (!sw->left_ep) {
71131a62963SBryan Wu 		if (percent_sensor_diff >= LEFT_END_POINT_DETECTION_LEVEL)  {
71231a62963SBryan Wu 			sw->left_ep = 1;
71331a62963SBryan Wu 			sw->left_ep_val =
71431a62963SBryan Wu 				ad714x->sensor_val[hw->x_start_stage + 1];
71531a62963SBryan Wu 		}
71631a62963SBryan Wu 	} else {
71731a62963SBryan Wu 		if ((percent_sensor_diff < LEFT_END_POINT_DETECTION_LEVEL) &&
71831a62963SBryan Wu 		    (ad714x->sensor_val[hw->x_start_stage + 1] >
71931a62963SBryan Wu 		     LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL + sw->left_ep_val))
72031a62963SBryan Wu 			sw->left_ep = 0;
72131a62963SBryan Wu 	}
72231a62963SBryan Wu 
72331a62963SBryan Wu 	/* right endpoint detect */
72431a62963SBryan Wu 	percent_sensor_diff = (ad714x->sensor_val[hw->x_end_stage] -
72531a62963SBryan Wu 			ad714x->sensor_val[hw->x_end_stage - 1]) * 100 /
72631a62963SBryan Wu 			ad714x->sensor_val[hw->x_end_stage - 1];
72731a62963SBryan Wu 	if (!sw->right_ep) {
72831a62963SBryan Wu 		if (percent_sensor_diff >= RIGHT_END_POINT_DETECTION_LEVEL)  {
72931a62963SBryan Wu 			sw->right_ep = 1;
73031a62963SBryan Wu 			sw->right_ep_val =
73131a62963SBryan Wu 				ad714x->sensor_val[hw->x_end_stage - 1];
73231a62963SBryan Wu 		}
73331a62963SBryan Wu 	} else {
73431a62963SBryan Wu 		if ((percent_sensor_diff < RIGHT_END_POINT_DETECTION_LEVEL) &&
73531a62963SBryan Wu 		(ad714x->sensor_val[hw->x_end_stage - 1] >
73631a62963SBryan Wu 		LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL + sw->right_ep_val))
73731a62963SBryan Wu 			sw->right_ep = 0;
73831a62963SBryan Wu 	}
73931a62963SBryan Wu 
74031a62963SBryan Wu 	/* top endpoint detect */
74131a62963SBryan Wu 	percent_sensor_diff = (ad714x->sensor_val[hw->y_start_stage] -
74231a62963SBryan Wu 			ad714x->sensor_val[hw->y_start_stage + 1]) * 100 /
74331a62963SBryan Wu 			ad714x->sensor_val[hw->y_start_stage + 1];
74431a62963SBryan Wu 	if (!sw->top_ep) {
74531a62963SBryan Wu 		if (percent_sensor_diff >= TOP_END_POINT_DETECTION_LEVEL)  {
74631a62963SBryan Wu 			sw->top_ep = 1;
74731a62963SBryan Wu 			sw->top_ep_val =
74831a62963SBryan Wu 				ad714x->sensor_val[hw->y_start_stage + 1];
74931a62963SBryan Wu 		}
75031a62963SBryan Wu 	} else {
75131a62963SBryan Wu 		if ((percent_sensor_diff < TOP_END_POINT_DETECTION_LEVEL) &&
75231a62963SBryan Wu 		(ad714x->sensor_val[hw->y_start_stage + 1] >
75331a62963SBryan Wu 		TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL + sw->top_ep_val))
75431a62963SBryan Wu 			sw->top_ep = 0;
75531a62963SBryan Wu 	}
75631a62963SBryan Wu 
75731a62963SBryan Wu 	/* bottom endpoint detect */
75831a62963SBryan Wu 	percent_sensor_diff = (ad714x->sensor_val[hw->y_end_stage] -
75931a62963SBryan Wu 		ad714x->sensor_val[hw->y_end_stage - 1]) * 100 /
76031a62963SBryan Wu 		ad714x->sensor_val[hw->y_end_stage - 1];
76131a62963SBryan Wu 	if (!sw->bottom_ep) {
76231a62963SBryan Wu 		if (percent_sensor_diff >= BOTTOM_END_POINT_DETECTION_LEVEL)  {
76331a62963SBryan Wu 			sw->bottom_ep = 1;
76431a62963SBryan Wu 			sw->bottom_ep_val =
76531a62963SBryan Wu 				ad714x->sensor_val[hw->y_end_stage - 1];
76631a62963SBryan Wu 		}
76731a62963SBryan Wu 	} else {
76831a62963SBryan Wu 		if ((percent_sensor_diff < BOTTOM_END_POINT_DETECTION_LEVEL) &&
76931a62963SBryan Wu 		(ad714x->sensor_val[hw->y_end_stage - 1] >
77031a62963SBryan Wu 		 TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL + sw->bottom_ep_val))
77131a62963SBryan Wu 			sw->bottom_ep = 0;
77231a62963SBryan Wu 	}
77331a62963SBryan Wu 
77431a62963SBryan Wu 	return sw->left_ep || sw->right_ep || sw->top_ep || sw->bottom_ep;
77531a62963SBryan Wu }
77631a62963SBryan Wu 
77731a62963SBryan Wu static void touchpad_use_com_int(struct ad714x_chip *ad714x, int idx)
77831a62963SBryan Wu {
77931a62963SBryan Wu 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
78031a62963SBryan Wu 
78131a62963SBryan Wu 	ad714x_use_com_int(ad714x, hw->x_start_stage, hw->x_end_stage);
78231a62963SBryan Wu }
78331a62963SBryan Wu 
78431a62963SBryan Wu static void touchpad_use_thr_int(struct ad714x_chip *ad714x, int idx)
78531a62963SBryan Wu {
78631a62963SBryan Wu 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
78731a62963SBryan Wu 
78831a62963SBryan Wu 	ad714x_use_thr_int(ad714x, hw->x_start_stage, hw->x_end_stage);
78931a62963SBryan Wu 	ad714x_use_thr_int(ad714x, hw->y_start_stage, hw->y_end_stage);
79031a62963SBryan Wu }
79131a62963SBryan Wu 
79231a62963SBryan Wu static void ad714x_touchpad_state_machine(struct ad714x_chip *ad714x, int idx)
79331a62963SBryan Wu {
79431a62963SBryan Wu 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
79531a62963SBryan Wu 	struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
79631a62963SBryan Wu 	unsigned short h_state, c_state;
79731a62963SBryan Wu 	unsigned short mask;
79831a62963SBryan Wu 
79931a62963SBryan Wu 	mask = (((1 << (hw->x_end_stage + 1)) - 1) -
80031a62963SBryan Wu 		((1 << hw->x_start_stage) - 1)) +
80131a62963SBryan Wu 		(((1 << (hw->y_end_stage + 1)) - 1) -
80231a62963SBryan Wu 		((1 << hw->y_start_stage) - 1));
80331a62963SBryan Wu 
80431a62963SBryan Wu 	h_state = ad714x->h_state & mask;
80531a62963SBryan Wu 	c_state = ad714x->c_state & mask;
80631a62963SBryan Wu 
80731a62963SBryan Wu 	switch (sw->state) {
80831a62963SBryan Wu 	case IDLE:
80931a62963SBryan Wu 		if (h_state) {
81031a62963SBryan Wu 			sw->state = JITTER;
81131a62963SBryan Wu 			/* In End of Conversion interrupt mode, the AD714X
81231a62963SBryan Wu 			 * continuously generates hardware interrupts.
81331a62963SBryan Wu 			 */
81431a62963SBryan Wu 			touchpad_use_com_int(ad714x, idx);
81531a62963SBryan Wu 			dev_dbg(ad714x->dev, "touchpad %d touched\n", idx);
81631a62963SBryan Wu 		}
81731a62963SBryan Wu 		break;
81831a62963SBryan Wu 
81931a62963SBryan Wu 	case JITTER:
82031a62963SBryan Wu 		if (c_state == mask) {
82131a62963SBryan Wu 			touchpad_cal_sensor_val(ad714x, idx);
82231a62963SBryan Wu 			touchpad_cal_highest_stage(ad714x, idx);
82331a62963SBryan Wu 			if ((!touchpad_check_second_peak(ad714x, idx)) &&
82431a62963SBryan Wu 				(!touchpad_check_endpoint(ad714x, idx))) {
82531a62963SBryan Wu 				dev_dbg(ad714x->dev,
82631a62963SBryan Wu 					"touchpad%d, 2 fingers or endpoint\n",
82731a62963SBryan Wu 					idx);
82831a62963SBryan Wu 				touchpad_cal_abs_pos(ad714x, idx);
82931a62963SBryan Wu 				sw->x_flt_pos = sw->x_abs_pos;
83031a62963SBryan Wu 				sw->y_flt_pos = sw->y_abs_pos;
83131a62963SBryan Wu 				sw->state = ACTIVE;
83231a62963SBryan Wu 			}
83331a62963SBryan Wu 		}
83431a62963SBryan Wu 		break;
83531a62963SBryan Wu 
83631a62963SBryan Wu 	case ACTIVE:
83731a62963SBryan Wu 		if (c_state == mask) {
83831a62963SBryan Wu 			if (h_state) {
83931a62963SBryan Wu 				touchpad_cal_sensor_val(ad714x, idx);
84031a62963SBryan Wu 				touchpad_cal_highest_stage(ad714x, idx);
84131a62963SBryan Wu 				if ((!touchpad_check_second_peak(ad714x, idx))
84231a62963SBryan Wu 				  && (!touchpad_check_endpoint(ad714x, idx))) {
84331a62963SBryan Wu 					touchpad_cal_abs_pos(ad714x, idx);
84431a62963SBryan Wu 					touchpad_cal_flt_pos(ad714x, idx);
84531a62963SBryan Wu 					input_report_abs(sw->input, ABS_X,
84631a62963SBryan Wu 						sw->x_flt_pos);
84731a62963SBryan Wu 					input_report_abs(sw->input, ABS_Y,
84831a62963SBryan Wu 						sw->y_flt_pos);
84931a62963SBryan Wu 					input_report_key(sw->input, BTN_TOUCH,
85031a62963SBryan Wu 						1);
85131a62963SBryan Wu 				}
85231a62963SBryan Wu 			} else {
85331a62963SBryan Wu 				/* When the user lifts off the sensor, configure
85431a62963SBryan Wu 				 * the AD714X back to threshold interrupt mode.
85531a62963SBryan Wu 				 */
85631a62963SBryan Wu 				touchpad_use_thr_int(ad714x, idx);
85731a62963SBryan Wu 				sw->state = IDLE;
85831a62963SBryan Wu 				input_report_key(sw->input, BTN_TOUCH, 0);
85931a62963SBryan Wu 				dev_dbg(ad714x->dev, "touchpad %d released\n",
86031a62963SBryan Wu 					idx);
86131a62963SBryan Wu 			}
86231a62963SBryan Wu 			input_sync(sw->input);
86331a62963SBryan Wu 		}
86431a62963SBryan Wu 		break;
86531a62963SBryan Wu 
86631a62963SBryan Wu 	default:
86731a62963SBryan Wu 		break;
86831a62963SBryan Wu 	}
86931a62963SBryan Wu }
87031a62963SBryan Wu 
87131a62963SBryan Wu static int ad714x_hw_detect(struct ad714x_chip *ad714x)
87231a62963SBryan Wu {
87331a62963SBryan Wu 	unsigned short data;
87431a62963SBryan Wu 
8759eff794bSMichael Hennerich 	ad714x->read(ad714x, AD714X_PARTID_REG, &data, 1);
87631a62963SBryan Wu 	switch (data & 0xFFF0) {
87731a62963SBryan Wu 	case AD7142_PARTID:
87831a62963SBryan Wu 		ad714x->product = 0x7142;
87931a62963SBryan Wu 		ad714x->version = data & 0xF;
88031a62963SBryan Wu 		dev_info(ad714x->dev, "found AD7142 captouch, rev:%d\n",
88131a62963SBryan Wu 				ad714x->version);
88231a62963SBryan Wu 		return 0;
88331a62963SBryan Wu 
8846c04d7b3SBarry Song 	case AD7143_PARTID:
8856c04d7b3SBarry Song 		ad714x->product = 0x7143;
8866c04d7b3SBarry Song 		ad714x->version = data & 0xF;
8876c04d7b3SBarry Song 		dev_info(ad714x->dev, "found AD7143 captouch, rev:%d\n",
8886c04d7b3SBarry Song 				ad714x->version);
8896c04d7b3SBarry Song 		return 0;
8906c04d7b3SBarry Song 
8916c04d7b3SBarry Song 	case AD7147_PARTID:
8926c04d7b3SBarry Song 		ad714x->product = 0x7147;
8936c04d7b3SBarry Song 		ad714x->version = data & 0xF;
8946c04d7b3SBarry Song 		dev_info(ad714x->dev, "found AD7147(A) captouch, rev:%d\n",
8956c04d7b3SBarry Song 				ad714x->version);
8966c04d7b3SBarry Song 		return 0;
8976c04d7b3SBarry Song 
8986c04d7b3SBarry Song 	case AD7148_PARTID:
8996c04d7b3SBarry Song 		ad714x->product = 0x7148;
9006c04d7b3SBarry Song 		ad714x->version = data & 0xF;
9016c04d7b3SBarry Song 		dev_info(ad714x->dev, "found AD7148 captouch, rev:%d\n",
9026c04d7b3SBarry Song 				ad714x->version);
9036c04d7b3SBarry Song 		return 0;
9046c04d7b3SBarry Song 
90531a62963SBryan Wu 	default:
90631a62963SBryan Wu 		dev_err(ad714x->dev,
90731a62963SBryan Wu 			"fail to detect AD714X captouch, read ID is %04x\n",
90831a62963SBryan Wu 			data);
90931a62963SBryan Wu 		return -ENODEV;
91031a62963SBryan Wu 	}
91131a62963SBryan Wu }
91231a62963SBryan Wu 
91331a62963SBryan Wu static void ad714x_hw_init(struct ad714x_chip *ad714x)
91431a62963SBryan Wu {
91531a62963SBryan Wu 	int i, j;
91631a62963SBryan Wu 	unsigned short reg_base;
91731a62963SBryan Wu 	unsigned short data;
91831a62963SBryan Wu 
91931a62963SBryan Wu 	/* configuration CDC and interrupts */
92031a62963SBryan Wu 
92131a62963SBryan Wu 	for (i = 0; i < STAGE_NUM; i++) {
92231a62963SBryan Wu 		reg_base = AD714X_STAGECFG_REG + i * STAGE_CFGREG_NUM;
92331a62963SBryan Wu 		for (j = 0; j < STAGE_CFGREG_NUM; j++)
924c0409febSDmitry Torokhov 			ad714x->write(ad714x, reg_base + j,
92531a62963SBryan Wu 					ad714x->hw->stage_cfg_reg[i][j]);
92631a62963SBryan Wu 	}
92731a62963SBryan Wu 
92831a62963SBryan Wu 	for (i = 0; i < SYS_CFGREG_NUM; i++)
929c0409febSDmitry Torokhov 		ad714x->write(ad714x, AD714X_SYSCFG_REG + i,
93031a62963SBryan Wu 			ad714x->hw->sys_cfg_reg[i]);
93131a62963SBryan Wu 	for (i = 0; i < SYS_CFGREG_NUM; i++)
9329eff794bSMichael Hennerich 		ad714x->read(ad714x, AD714X_SYSCFG_REG + i, &data, 1);
93331a62963SBryan Wu 
934c0409febSDmitry Torokhov 	ad714x->write(ad714x, AD714X_STG_CAL_EN_REG, 0xFFF);
93531a62963SBryan Wu 
93631a62963SBryan Wu 	/* clear all interrupts */
9379eff794bSMichael Hennerich 	ad714x->read(ad714x, STG_LOW_INT_STA_REG, &ad714x->l_state, 3);
93831a62963SBryan Wu }
93931a62963SBryan Wu 
94031a62963SBryan Wu static irqreturn_t ad714x_interrupt_thread(int irq, void *data)
94131a62963SBryan Wu {
94231a62963SBryan Wu 	struct ad714x_chip *ad714x = data;
94331a62963SBryan Wu 	int i;
94431a62963SBryan Wu 
94531a62963SBryan Wu 	mutex_lock(&ad714x->mutex);
94631a62963SBryan Wu 
9479eff794bSMichael Hennerich 	ad714x->read(ad714x, STG_LOW_INT_STA_REG, &ad714x->l_state, 3);
94831a62963SBryan Wu 
94931a62963SBryan Wu 	for (i = 0; i < ad714x->hw->button_num; i++)
95031a62963SBryan Wu 		ad714x_button_state_machine(ad714x, i);
95131a62963SBryan Wu 	for (i = 0; i < ad714x->hw->slider_num; i++)
95231a62963SBryan Wu 		ad714x_slider_state_machine(ad714x, i);
95331a62963SBryan Wu 	for (i = 0; i < ad714x->hw->wheel_num; i++)
95431a62963SBryan Wu 		ad714x_wheel_state_machine(ad714x, i);
95531a62963SBryan Wu 	for (i = 0; i < ad714x->hw->touchpad_num; i++)
95631a62963SBryan Wu 		ad714x_touchpad_state_machine(ad714x, i);
95731a62963SBryan Wu 
95831a62963SBryan Wu 	mutex_unlock(&ad714x->mutex);
95931a62963SBryan Wu 
96031a62963SBryan Wu 	return IRQ_HANDLED;
96131a62963SBryan Wu }
96231a62963SBryan Wu 
96331a62963SBryan Wu struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
96431a62963SBryan Wu 				 ad714x_read_t read, ad714x_write_t write)
96531a62963SBryan Wu {
966c5c18a06SVaishali Thakkar 	int i;
96731a62963SBryan Wu 	int error;
968c5c18a06SVaishali Thakkar 	struct input_dev *input;
96931a62963SBryan Wu 
970c838cb3dSJingoo Han 	struct ad714x_platform_data *plat_data = dev_get_platdata(dev);
97131a62963SBryan Wu 	struct ad714x_chip *ad714x;
97231a62963SBryan Wu 	void *drv_mem;
9739b7e31bbSLars-Peter Clausen 	unsigned long irqflags;
97431a62963SBryan Wu 
97531a62963SBryan Wu 	struct ad714x_button_drv *bt_drv;
97631a62963SBryan Wu 	struct ad714x_slider_drv *sd_drv;
97731a62963SBryan Wu 	struct ad714x_wheel_drv *wl_drv;
97831a62963SBryan Wu 	struct ad714x_touchpad_drv *tp_drv;
97931a62963SBryan Wu 
98031a62963SBryan Wu 
98131a62963SBryan Wu 	if (irq <= 0) {
98231a62963SBryan Wu 		dev_err(dev, "IRQ not configured!\n");
98331a62963SBryan Wu 		error = -EINVAL;
984c5c18a06SVaishali Thakkar 		return ERR_PTR(error);
98531a62963SBryan Wu 	}
98631a62963SBryan Wu 
987c838cb3dSJingoo Han 	if (dev_get_platdata(dev) == NULL) {
98831a62963SBryan Wu 		dev_err(dev, "platform data for ad714x doesn't exist\n");
98931a62963SBryan Wu 		error = -EINVAL;
990c5c18a06SVaishali Thakkar 		return ERR_PTR(error);
99131a62963SBryan Wu 	}
99231a62963SBryan Wu 
993c5c18a06SVaishali Thakkar 	ad714x = devm_kzalloc(dev, sizeof(*ad714x) + sizeof(*ad714x->sw) +
99431a62963SBryan Wu 				   sizeof(*sd_drv) * plat_data->slider_num +
99531a62963SBryan Wu 				   sizeof(*wl_drv) * plat_data->wheel_num +
99631a62963SBryan Wu 				   sizeof(*tp_drv) * plat_data->touchpad_num +
997c5c18a06SVaishali Thakkar 				   sizeof(*bt_drv) * plat_data->button_num,
998c5c18a06SVaishali Thakkar 			      GFP_KERNEL);
99931a62963SBryan Wu 	if (!ad714x) {
100031a62963SBryan Wu 		error = -ENOMEM;
1001c5c18a06SVaishali Thakkar 		return ERR_PTR(error);
100231a62963SBryan Wu 	}
100331a62963SBryan Wu 	ad714x->hw = plat_data;
100431a62963SBryan Wu 
100531a62963SBryan Wu 	drv_mem = ad714x + 1;
100631a62963SBryan Wu 	ad714x->sw = drv_mem;
100731a62963SBryan Wu 	drv_mem += sizeof(*ad714x->sw);
100831a62963SBryan Wu 	ad714x->sw->slider = sd_drv = drv_mem;
100931a62963SBryan Wu 	drv_mem += sizeof(*sd_drv) * ad714x->hw->slider_num;
101031a62963SBryan Wu 	ad714x->sw->wheel = wl_drv = drv_mem;
101131a62963SBryan Wu 	drv_mem += sizeof(*wl_drv) * ad714x->hw->wheel_num;
101231a62963SBryan Wu 	ad714x->sw->touchpad = tp_drv = drv_mem;
101331a62963SBryan Wu 	drv_mem += sizeof(*tp_drv) * ad714x->hw->touchpad_num;
101431a62963SBryan Wu 	ad714x->sw->button = bt_drv = drv_mem;
101531a62963SBryan Wu 	drv_mem += sizeof(*bt_drv) * ad714x->hw->button_num;
101631a62963SBryan Wu 
101731a62963SBryan Wu 	ad714x->read = read;
101831a62963SBryan Wu 	ad714x->write = write;
101931a62963SBryan Wu 	ad714x->irq = irq;
102031a62963SBryan Wu 	ad714x->dev = dev;
102131a62963SBryan Wu 
102231a62963SBryan Wu 	error = ad714x_hw_detect(ad714x);
102331a62963SBryan Wu 	if (error)
1024c5c18a06SVaishali Thakkar 		return ERR_PTR(error);
102531a62963SBryan Wu 
1026421f91d2SUwe Kleine-König 	/* initialize and request sw/hw resources */
102731a62963SBryan Wu 
102831a62963SBryan Wu 	ad714x_hw_init(ad714x);
102931a62963SBryan Wu 	mutex_init(&ad714x->mutex);
103031a62963SBryan Wu 
103131a62963SBryan Wu 	/* a slider uses one input_dev instance */
103231a62963SBryan Wu 	if (ad714x->hw->slider_num > 0) {
103331a62963SBryan Wu 		struct ad714x_slider_plat *sd_plat = ad714x->hw->slider;
103431a62963SBryan Wu 
103531a62963SBryan Wu 		for (i = 0; i < ad714x->hw->slider_num; i++) {
1036c5c18a06SVaishali Thakkar 			input = devm_input_allocate_device(dev);
1037c5c18a06SVaishali Thakkar 			if (!input)
1038c5c18a06SVaishali Thakkar 				return ERR_PTR(-ENOMEM);
103931a62963SBryan Wu 
1040c5c18a06SVaishali Thakkar 			__set_bit(EV_ABS, input->evbit);
1041c5c18a06SVaishali Thakkar 			__set_bit(EV_KEY, input->evbit);
1042c5c18a06SVaishali Thakkar 			__set_bit(ABS_X, input->absbit);
1043c5c18a06SVaishali Thakkar 			__set_bit(BTN_TOUCH, input->keybit);
1044c5c18a06SVaishali Thakkar 			input_set_abs_params(input,
104531a62963SBryan Wu 				ABS_X, 0, sd_plat->max_coord, 0, 0);
104631a62963SBryan Wu 
1047c5c18a06SVaishali Thakkar 			input->id.bustype = bus_type;
1048c5c18a06SVaishali Thakkar 			input->id.product = ad714x->product;
1049c5c18a06SVaishali Thakkar 			input->id.version = ad714x->version;
1050c5c18a06SVaishali Thakkar 			input->name = "ad714x_captouch_slider";
1051c5c18a06SVaishali Thakkar 			input->dev.parent = dev;
105231a62963SBryan Wu 
1053c5c18a06SVaishali Thakkar 			error = input_register_device(input);
105431a62963SBryan Wu 			if (error)
1055c5c18a06SVaishali Thakkar 				return ERR_PTR(error);
105631a62963SBryan Wu 
1057c5c18a06SVaishali Thakkar 			sd_drv[i].input = input;
105831a62963SBryan Wu 		}
105931a62963SBryan Wu 	}
106031a62963SBryan Wu 
106131a62963SBryan Wu 	/* a wheel uses one input_dev instance */
106231a62963SBryan Wu 	if (ad714x->hw->wheel_num > 0) {
106331a62963SBryan Wu 		struct ad714x_wheel_plat *wl_plat = ad714x->hw->wheel;
106431a62963SBryan Wu 
106531a62963SBryan Wu 		for (i = 0; i < ad714x->hw->wheel_num; i++) {
1066c5c18a06SVaishali Thakkar 			input = devm_input_allocate_device(dev);
1067c5c18a06SVaishali Thakkar 			if (!input)
1068c5c18a06SVaishali Thakkar 				return ERR_PTR(-ENOMEM);
106931a62963SBryan Wu 
1070c5c18a06SVaishali Thakkar 			__set_bit(EV_KEY, input->evbit);
1071c5c18a06SVaishali Thakkar 			__set_bit(EV_ABS, input->evbit);
1072c5c18a06SVaishali Thakkar 			__set_bit(ABS_WHEEL, input->absbit);
1073c5c18a06SVaishali Thakkar 			__set_bit(BTN_TOUCH, input->keybit);
1074c5c18a06SVaishali Thakkar 			input_set_abs_params(input,
107531a62963SBryan Wu 				ABS_WHEEL, 0, wl_plat->max_coord, 0, 0);
107631a62963SBryan Wu 
1077c5c18a06SVaishali Thakkar 			input->id.bustype = bus_type;
1078c5c18a06SVaishali Thakkar 			input->id.product = ad714x->product;
1079c5c18a06SVaishali Thakkar 			input->id.version = ad714x->version;
1080c5c18a06SVaishali Thakkar 			input->name = "ad714x_captouch_wheel";
1081c5c18a06SVaishali Thakkar 			input->dev.parent = dev;
108231a62963SBryan Wu 
1083c5c18a06SVaishali Thakkar 			error = input_register_device(input);
108431a62963SBryan Wu 			if (error)
1085c5c18a06SVaishali Thakkar 				return ERR_PTR(error);
108631a62963SBryan Wu 
1087c5c18a06SVaishali Thakkar 			wl_drv[i].input = input;
108831a62963SBryan Wu 		}
108931a62963SBryan Wu 	}
109031a62963SBryan Wu 
109131a62963SBryan Wu 	/* a touchpad uses one input_dev instance */
109231a62963SBryan Wu 	if (ad714x->hw->touchpad_num > 0) {
109331a62963SBryan Wu 		struct ad714x_touchpad_plat *tp_plat = ad714x->hw->touchpad;
109431a62963SBryan Wu 
109531a62963SBryan Wu 		for (i = 0; i < ad714x->hw->touchpad_num; i++) {
1096c5c18a06SVaishali Thakkar 			input = devm_input_allocate_device(dev);
1097c5c18a06SVaishali Thakkar 			if (!input)
1098c5c18a06SVaishali Thakkar 				return ERR_PTR(-ENOMEM);
109931a62963SBryan Wu 
1100c5c18a06SVaishali Thakkar 			__set_bit(EV_ABS, input->evbit);
1101c5c18a06SVaishali Thakkar 			__set_bit(EV_KEY, input->evbit);
1102c5c18a06SVaishali Thakkar 			__set_bit(ABS_X, input->absbit);
1103c5c18a06SVaishali Thakkar 			__set_bit(ABS_Y, input->absbit);
1104c5c18a06SVaishali Thakkar 			__set_bit(BTN_TOUCH, input->keybit);
1105c5c18a06SVaishali Thakkar 			input_set_abs_params(input,
110631a62963SBryan Wu 				ABS_X, 0, tp_plat->x_max_coord, 0, 0);
1107c5c18a06SVaishali Thakkar 			input_set_abs_params(input,
110831a62963SBryan Wu 				ABS_Y, 0, tp_plat->y_max_coord, 0, 0);
110931a62963SBryan Wu 
1110c5c18a06SVaishali Thakkar 			input->id.bustype = bus_type;
1111c5c18a06SVaishali Thakkar 			input->id.product = ad714x->product;
1112c5c18a06SVaishali Thakkar 			input->id.version = ad714x->version;
1113c5c18a06SVaishali Thakkar 			input->name = "ad714x_captouch_pad";
1114c5c18a06SVaishali Thakkar 			input->dev.parent = dev;
111531a62963SBryan Wu 
1116c5c18a06SVaishali Thakkar 			error = input_register_device(input);
111731a62963SBryan Wu 			if (error)
1118c5c18a06SVaishali Thakkar 				return ERR_PTR(error);
111931a62963SBryan Wu 
1120c5c18a06SVaishali Thakkar 			tp_drv[i].input = input;
112131a62963SBryan Wu 		}
112231a62963SBryan Wu 	}
112331a62963SBryan Wu 
112431a62963SBryan Wu 	/* all buttons use one input node */
112531a62963SBryan Wu 	if (ad714x->hw->button_num > 0) {
112631a62963SBryan Wu 		struct ad714x_button_plat *bt_plat = ad714x->hw->button;
112731a62963SBryan Wu 
1128c5c18a06SVaishali Thakkar 		input = devm_input_allocate_device(dev);
1129c5c18a06SVaishali Thakkar 		if (!input) {
113031a62963SBryan Wu 			error = -ENOMEM;
1131c5c18a06SVaishali Thakkar 			return ERR_PTR(error);
113231a62963SBryan Wu 		}
113331a62963SBryan Wu 
1134c5c18a06SVaishali Thakkar 		__set_bit(EV_KEY, input->evbit);
113531a62963SBryan Wu 		for (i = 0; i < ad714x->hw->button_num; i++) {
1136c5c18a06SVaishali Thakkar 			bt_drv[i].input = input;
1137c5c18a06SVaishali Thakkar 			__set_bit(bt_plat[i].keycode, input->keybit);
113831a62963SBryan Wu 		}
113931a62963SBryan Wu 
1140c5c18a06SVaishali Thakkar 		input->id.bustype = bus_type;
1141c5c18a06SVaishali Thakkar 		input->id.product = ad714x->product;
1142c5c18a06SVaishali Thakkar 		input->id.version = ad714x->version;
1143c5c18a06SVaishali Thakkar 		input->name = "ad714x_captouch_button";
1144c5c18a06SVaishali Thakkar 		input->dev.parent = dev;
114531a62963SBryan Wu 
1146c5c18a06SVaishali Thakkar 		error = input_register_device(input);
114731a62963SBryan Wu 		if (error)
1148c5c18a06SVaishali Thakkar 			return ERR_PTR(error);
114931a62963SBryan Wu 	}
115031a62963SBryan Wu 
11519b7e31bbSLars-Peter Clausen 	irqflags = plat_data->irqflags ?: IRQF_TRIGGER_FALLING;
11529b7e31bbSLars-Peter Clausen 	irqflags |= IRQF_ONESHOT;
11539b7e31bbSLars-Peter Clausen 
1154c5c18a06SVaishali Thakkar 	error = devm_request_threaded_irq(dev, ad714x->irq, NULL,
1155c5c18a06SVaishali Thakkar 					  ad714x_interrupt_thread,
11569b7e31bbSLars-Peter Clausen 					  irqflags, "ad714x_captouch", ad714x);
115731a62963SBryan Wu 	if (error) {
115831a62963SBryan Wu 		dev_err(dev, "can't allocate irq %d\n", ad714x->irq);
1159c5c18a06SVaishali Thakkar 		return ERR_PTR(error);
116031a62963SBryan Wu 	}
116131a62963SBryan Wu 
116231a62963SBryan Wu 	return ad714x;
116331a62963SBryan Wu }
116431a62963SBryan Wu EXPORT_SYMBOL(ad714x_probe);
116531a62963SBryan Wu 
116631a62963SBryan Wu #ifdef CONFIG_PM
116731a62963SBryan Wu int ad714x_disable(struct ad714x_chip *ad714x)
116831a62963SBryan Wu {
116931a62963SBryan Wu 	unsigned short data;
117031a62963SBryan Wu 
117131a62963SBryan Wu 	dev_dbg(ad714x->dev, "%s enter\n", __func__);
117231a62963SBryan Wu 
117331a62963SBryan Wu 	mutex_lock(&ad714x->mutex);
117431a62963SBryan Wu 
117531a62963SBryan Wu 	data = ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL] | 0x3;
1176c0409febSDmitry Torokhov 	ad714x->write(ad714x, AD714X_PWR_CTRL, data);
117731a62963SBryan Wu 
117831a62963SBryan Wu 	mutex_unlock(&ad714x->mutex);
117931a62963SBryan Wu 
118031a62963SBryan Wu 	return 0;
118131a62963SBryan Wu }
118231a62963SBryan Wu EXPORT_SYMBOL(ad714x_disable);
118331a62963SBryan Wu 
118431a62963SBryan Wu int ad714x_enable(struct ad714x_chip *ad714x)
118531a62963SBryan Wu {
118631a62963SBryan Wu 	dev_dbg(ad714x->dev, "%s enter\n", __func__);
118731a62963SBryan Wu 
118831a62963SBryan Wu 	mutex_lock(&ad714x->mutex);
118931a62963SBryan Wu 
119031a62963SBryan Wu 	/* resume to non-shutdown mode */
119131a62963SBryan Wu 
1192c0409febSDmitry Torokhov 	ad714x->write(ad714x, AD714X_PWR_CTRL,
119331a62963SBryan Wu 			ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL]);
119431a62963SBryan Wu 
119531a62963SBryan Wu 	/* make sure the interrupt output line is not low level after resume,
119631a62963SBryan Wu 	 * otherwise we will get no chance to enter falling-edge irq again
119731a62963SBryan Wu 	 */
119831a62963SBryan Wu 
11999eff794bSMichael Hennerich 	ad714x->read(ad714x, STG_LOW_INT_STA_REG, &ad714x->l_state, 3);
120031a62963SBryan Wu 
120131a62963SBryan Wu 	mutex_unlock(&ad714x->mutex);
120231a62963SBryan Wu 
120331a62963SBryan Wu 	return 0;
120431a62963SBryan Wu }
120531a62963SBryan Wu EXPORT_SYMBOL(ad714x_enable);
120631a62963SBryan Wu #endif
120731a62963SBryan Wu 
120831a62963SBryan Wu MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor Driver");
120931a62963SBryan Wu MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
121031a62963SBryan Wu MODULE_LICENSE("GPL");
1211