xref: /openbmc/linux/drivers/input/misc/ad714x.c (revision f1e430e6)
131a62963SBryan Wu /*
26c04d7b3SBarry Song  * AD714X CapTouch Programmable Controller driver supporting AD7142/3/7/8/7A
331a62963SBryan Wu  *
431a62963SBryan Wu  * Copyright 2009 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/init.h>
1131a62963SBryan Wu #include <linux/input.h>
1231a62963SBryan Wu #include <linux/interrupt.h>
1331a62963SBryan Wu #include <linux/slab.h>
1431a62963SBryan Wu #include <linux/input/ad714x.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_NUM              12
6331a62963SBryan Wu #define STAGE_CFGREG_NUM       8
6431a62963SBryan Wu #define SYS_CFGREG_NUM         8
6531a62963SBryan Wu 
6631a62963SBryan Wu /*
6731a62963SBryan Wu  * driver information which will be used to maintain the software flow
6831a62963SBryan Wu  */
6931a62963SBryan Wu enum ad714x_device_state { IDLE, JITTER, ACTIVE, SPACE };
7031a62963SBryan Wu 
7131a62963SBryan Wu struct ad714x_slider_drv {
7231a62963SBryan Wu 	int highest_stage;
7331a62963SBryan Wu 	int abs_pos;
7431a62963SBryan Wu 	int flt_pos;
7531a62963SBryan Wu 	enum ad714x_device_state state;
7631a62963SBryan Wu 	struct input_dev *input;
7731a62963SBryan Wu };
7831a62963SBryan Wu 
7931a62963SBryan Wu struct ad714x_wheel_drv {
8031a62963SBryan Wu 	int abs_pos;
8131a62963SBryan Wu 	int flt_pos;
8231a62963SBryan Wu 	int pre_highest_stage;
8331a62963SBryan Wu 	int highest_stage;
8431a62963SBryan Wu 	enum ad714x_device_state state;
8531a62963SBryan Wu 	struct input_dev *input;
8631a62963SBryan Wu };
8731a62963SBryan Wu 
8831a62963SBryan Wu struct ad714x_touchpad_drv {
8931a62963SBryan Wu 	int x_highest_stage;
9031a62963SBryan Wu 	int x_flt_pos;
9131a62963SBryan Wu 	int x_abs_pos;
9231a62963SBryan Wu 	int y_highest_stage;
9331a62963SBryan Wu 	int y_flt_pos;
9431a62963SBryan Wu 	int y_abs_pos;
9531a62963SBryan Wu 	int left_ep;
9631a62963SBryan Wu 	int left_ep_val;
9731a62963SBryan Wu 	int right_ep;
9831a62963SBryan Wu 	int right_ep_val;
9931a62963SBryan Wu 	int top_ep;
10031a62963SBryan Wu 	int top_ep_val;
10131a62963SBryan Wu 	int bottom_ep;
10231a62963SBryan Wu 	int bottom_ep_val;
10331a62963SBryan Wu 	enum ad714x_device_state state;
10431a62963SBryan Wu 	struct input_dev *input;
10531a62963SBryan Wu };
10631a62963SBryan Wu 
10731a62963SBryan Wu struct ad714x_button_drv {
10831a62963SBryan Wu 	enum ad714x_device_state state;
10931a62963SBryan Wu 	/*
11031a62963SBryan Wu 	 * Unlike slider/wheel/touchpad, all buttons point to
11131a62963SBryan Wu 	 * same input_dev instance
11231a62963SBryan Wu 	 */
11331a62963SBryan Wu 	struct input_dev *input;
11431a62963SBryan Wu };
11531a62963SBryan Wu 
11631a62963SBryan Wu struct ad714x_driver_data {
11731a62963SBryan Wu 	struct ad714x_slider_drv *slider;
11831a62963SBryan Wu 	struct ad714x_wheel_drv *wheel;
11931a62963SBryan Wu 	struct ad714x_touchpad_drv *touchpad;
12031a62963SBryan Wu 	struct ad714x_button_drv *button;
12131a62963SBryan Wu };
12231a62963SBryan Wu 
12331a62963SBryan Wu /*
12431a62963SBryan Wu  * information to integrate all things which will be private data
12531a62963SBryan Wu  * of spi/i2c device
12631a62963SBryan Wu  */
12731a62963SBryan Wu struct ad714x_chip {
12831a62963SBryan Wu 	unsigned short h_state;
12931a62963SBryan Wu 	unsigned short l_state;
13031a62963SBryan Wu 	unsigned short c_state;
13131a62963SBryan Wu 	unsigned short adc_reg[STAGE_NUM];
13231a62963SBryan Wu 	unsigned short amb_reg[STAGE_NUM];
13331a62963SBryan Wu 	unsigned short sensor_val[STAGE_NUM];
13431a62963SBryan Wu 
13531a62963SBryan Wu 	struct ad714x_platform_data *hw;
13631a62963SBryan Wu 	struct ad714x_driver_data *sw;
13731a62963SBryan Wu 
13831a62963SBryan Wu 	int irq;
13931a62963SBryan Wu 	struct device *dev;
14031a62963SBryan Wu 	ad714x_read_t read;
14131a62963SBryan Wu 	ad714x_write_t write;
14231a62963SBryan Wu 
14331a62963SBryan Wu 	struct mutex mutex;
14431a62963SBryan Wu 
14531a62963SBryan Wu 	unsigned product;
14631a62963SBryan Wu 	unsigned version;
14731a62963SBryan Wu };
14831a62963SBryan Wu 
14931a62963SBryan Wu static void ad714x_use_com_int(struct ad714x_chip *ad714x,
15031a62963SBryan Wu 				int start_stage, int end_stage)
15131a62963SBryan Wu {
15231a62963SBryan Wu 	unsigned short data;
15331a62963SBryan Wu 	unsigned short mask;
15431a62963SBryan Wu 
155e223cc7eSMichael Hennerich 	mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);
15631a62963SBryan Wu 
15731a62963SBryan Wu 	ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data);
158e223cc7eSMichael Hennerich 	data |= 1 << end_stage;
15931a62963SBryan Wu 	ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data);
16031a62963SBryan Wu 
16131a62963SBryan Wu 	ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data);
16231a62963SBryan Wu 	data &= ~mask;
16331a62963SBryan Wu 	ad714x->write(ad714x->dev, STG_HIGH_INT_EN_REG, data);
16431a62963SBryan Wu }
16531a62963SBryan Wu 
16631a62963SBryan Wu static void ad714x_use_thr_int(struct ad714x_chip *ad714x,
16731a62963SBryan Wu 				int start_stage, int end_stage)
16831a62963SBryan Wu {
16931a62963SBryan Wu 	unsigned short data;
17031a62963SBryan Wu 	unsigned short mask;
17131a62963SBryan Wu 
172e223cc7eSMichael Hennerich 	mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);
17331a62963SBryan Wu 
17431a62963SBryan Wu 	ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data);
175e223cc7eSMichael Hennerich 	data &= ~(1 << end_stage);
17631a62963SBryan Wu 	ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data);
17731a62963SBryan Wu 
17831a62963SBryan Wu 	ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data);
17931a62963SBryan Wu 	data |= mask;
18031a62963SBryan Wu 	ad714x->write(ad714x->dev, STG_HIGH_INT_EN_REG, data);
18131a62963SBryan Wu }
18231a62963SBryan Wu 
18331a62963SBryan Wu static int ad714x_cal_highest_stage(struct ad714x_chip *ad714x,
18431a62963SBryan Wu 					int start_stage, int end_stage)
18531a62963SBryan Wu {
18631a62963SBryan Wu 	int max_res = 0;
18731a62963SBryan Wu 	int max_idx = 0;
18831a62963SBryan Wu 	int i;
18931a62963SBryan Wu 
19031a62963SBryan Wu 	for (i = start_stage; i <= end_stage; i++) {
19131a62963SBryan Wu 		if (ad714x->sensor_val[i] > max_res) {
19231a62963SBryan Wu 			max_res = ad714x->sensor_val[i];
19331a62963SBryan Wu 			max_idx = i;
19431a62963SBryan Wu 		}
19531a62963SBryan Wu 	}
19631a62963SBryan Wu 
19731a62963SBryan Wu 	return max_idx;
19831a62963SBryan Wu }
19931a62963SBryan Wu 
20031a62963SBryan Wu static int ad714x_cal_abs_pos(struct ad714x_chip *ad714x,
20131a62963SBryan Wu 				int start_stage, int end_stage,
20231a62963SBryan Wu 				int highest_stage, int max_coord)
20331a62963SBryan Wu {
20431a62963SBryan Wu 	int a_param, b_param;
20531a62963SBryan Wu 
20631a62963SBryan Wu 	if (highest_stage == start_stage) {
20731a62963SBryan Wu 		a_param = ad714x->sensor_val[start_stage + 1];
20831a62963SBryan Wu 		b_param = ad714x->sensor_val[start_stage] +
20931a62963SBryan Wu 			ad714x->sensor_val[start_stage + 1];
21031a62963SBryan Wu 	} else if (highest_stage == end_stage) {
21131a62963SBryan Wu 		a_param = ad714x->sensor_val[end_stage] *
21231a62963SBryan Wu 			(end_stage - start_stage) +
21331a62963SBryan Wu 			ad714x->sensor_val[end_stage - 1] *
21431a62963SBryan Wu 			(end_stage - start_stage - 1);
21531a62963SBryan Wu 		b_param = ad714x->sensor_val[end_stage] +
21631a62963SBryan Wu 			ad714x->sensor_val[end_stage - 1];
21731a62963SBryan Wu 	} else {
21831a62963SBryan Wu 		a_param = ad714x->sensor_val[highest_stage] *
21931a62963SBryan Wu 			(highest_stage - start_stage) +
22031a62963SBryan Wu 			ad714x->sensor_val[highest_stage - 1] *
22131a62963SBryan Wu 			(highest_stage - start_stage - 1) +
22231a62963SBryan Wu 			ad714x->sensor_val[highest_stage + 1] *
22331a62963SBryan Wu 			(highest_stage - start_stage + 1);
22431a62963SBryan Wu 		b_param = ad714x->sensor_val[highest_stage] +
22531a62963SBryan Wu 			ad714x->sensor_val[highest_stage - 1] +
22631a62963SBryan Wu 			ad714x->sensor_val[highest_stage + 1];
22731a62963SBryan Wu 	}
22831a62963SBryan Wu 
22931a62963SBryan Wu 	return (max_coord / (end_stage - start_stage)) * a_param / b_param;
23031a62963SBryan Wu }
23131a62963SBryan Wu 
23231a62963SBryan Wu /*
23331a62963SBryan Wu  * One button can connect to multi positive and negative of CDCs
23431a62963SBryan Wu  * Multi-buttons can connect to same positive/negative of one CDC
23531a62963SBryan Wu  */
23631a62963SBryan Wu static void ad714x_button_state_machine(struct ad714x_chip *ad714x, int idx)
23731a62963SBryan Wu {
23831a62963SBryan Wu 	struct ad714x_button_plat *hw = &ad714x->hw->button[idx];
23931a62963SBryan Wu 	struct ad714x_button_drv *sw = &ad714x->sw->button[idx];
24031a62963SBryan Wu 
24131a62963SBryan Wu 	switch (sw->state) {
24231a62963SBryan Wu 	case IDLE:
24331a62963SBryan Wu 		if (((ad714x->h_state & hw->h_mask) == hw->h_mask) &&
24431a62963SBryan Wu 		    ((ad714x->l_state & hw->l_mask) == hw->l_mask)) {
24531a62963SBryan Wu 			dev_dbg(ad714x->dev, "button %d touched\n", idx);
24631a62963SBryan Wu 			input_report_key(sw->input, hw->keycode, 1);
24731a62963SBryan Wu 			input_sync(sw->input);
24831a62963SBryan Wu 			sw->state = ACTIVE;
24931a62963SBryan Wu 		}
25031a62963SBryan Wu 		break;
25131a62963SBryan Wu 
25231a62963SBryan Wu 	case ACTIVE:
25331a62963SBryan Wu 		if (((ad714x->h_state & hw->h_mask) != hw->h_mask) ||
25431a62963SBryan Wu 		    ((ad714x->l_state & hw->l_mask) != hw->l_mask)) {
25531a62963SBryan Wu 			dev_dbg(ad714x->dev, "button %d released\n", idx);
25631a62963SBryan Wu 			input_report_key(sw->input, hw->keycode, 0);
25731a62963SBryan Wu 			input_sync(sw->input);
25831a62963SBryan Wu 			sw->state = IDLE;
25931a62963SBryan Wu 		}
26031a62963SBryan Wu 		break;
26131a62963SBryan Wu 
26231a62963SBryan Wu 	default:
26331a62963SBryan Wu 		break;
26431a62963SBryan Wu 	}
26531a62963SBryan Wu }
26631a62963SBryan Wu 
26731a62963SBryan Wu /*
26831a62963SBryan Wu  * The response of a sensor is defined by the absolute number of codes
26931a62963SBryan Wu  * between the current CDC value and the ambient value.
27031a62963SBryan Wu  */
27131a62963SBryan Wu static void ad714x_slider_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
27231a62963SBryan Wu {
27331a62963SBryan Wu 	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
27431a62963SBryan Wu 	int i;
27531a62963SBryan Wu 
27631a62963SBryan Wu 	for (i = hw->start_stage; i <= hw->end_stage; i++) {
27731a62963SBryan Wu 		ad714x->read(ad714x->dev, CDC_RESULT_S0 + i,
27831a62963SBryan Wu 			&ad714x->adc_reg[i]);
27931a62963SBryan Wu 		ad714x->read(ad714x->dev,
28031a62963SBryan Wu 				STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
28131a62963SBryan Wu 				&ad714x->amb_reg[i]);
28231a62963SBryan Wu 
28331a62963SBryan Wu 		ad714x->sensor_val[i] = abs(ad714x->adc_reg[i] -
28431a62963SBryan Wu 				ad714x->amb_reg[i]);
28531a62963SBryan Wu 	}
28631a62963SBryan Wu }
28731a62963SBryan Wu 
28831a62963SBryan Wu static void ad714x_slider_cal_highest_stage(struct ad714x_chip *ad714x, int idx)
28931a62963SBryan Wu {
29031a62963SBryan Wu 	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
29131a62963SBryan Wu 	struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx];
29231a62963SBryan Wu 
29331a62963SBryan Wu 	sw->highest_stage = ad714x_cal_highest_stage(ad714x, hw->start_stage,
29431a62963SBryan Wu 			hw->end_stage);
29531a62963SBryan Wu 
29631a62963SBryan Wu 	dev_dbg(ad714x->dev, "slider %d highest_stage:%d\n", idx,
29731a62963SBryan Wu 		sw->highest_stage);
29831a62963SBryan Wu }
29931a62963SBryan Wu 
30031a62963SBryan Wu /*
30131a62963SBryan Wu  * The formulae are very straight forward. It uses the sensor with the
30231a62963SBryan Wu  * highest response and the 2 adjacent ones.
30331a62963SBryan Wu  * When Sensor 0 has the highest response, only sensor 0 and sensor 1
30431a62963SBryan Wu  * are used in the calculations. Similarly when the last sensor has the
30531a62963SBryan Wu  * highest response, only the last sensor and the second last sensors
30631a62963SBryan Wu  * are used in the calculations.
30731a62963SBryan Wu  *
30831a62963SBryan Wu  * For i= idx_of_peak_Sensor-1 to i= idx_of_peak_Sensor+1
30931a62963SBryan Wu  *         v += Sensor response(i)*i
31031a62963SBryan Wu  *         w += Sensor response(i)
31131a62963SBryan Wu  * POS=(Number_of_Positions_Wanted/(Number_of_Sensors_Used-1)) *(v/w)
31231a62963SBryan Wu  */
31331a62963SBryan Wu static void ad714x_slider_cal_abs_pos(struct ad714x_chip *ad714x, int idx)
31431a62963SBryan Wu {
31531a62963SBryan Wu 	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
31631a62963SBryan Wu 	struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx];
31731a62963SBryan Wu 
31831a62963SBryan Wu 	sw->abs_pos = ad714x_cal_abs_pos(ad714x, hw->start_stage, hw->end_stage,
31931a62963SBryan Wu 		sw->highest_stage, hw->max_coord);
32031a62963SBryan Wu 
32131a62963SBryan Wu 	dev_dbg(ad714x->dev, "slider %d absolute position:%d\n", idx,
32231a62963SBryan Wu 		sw->abs_pos);
32331a62963SBryan Wu }
32431a62963SBryan Wu 
32531a62963SBryan Wu /*
32631a62963SBryan Wu  * To minimise the Impact of the noise on the algorithm, ADI developed a
32731a62963SBryan Wu  * routine that filters the CDC results after they have been read by the
32831a62963SBryan Wu  * host processor.
32931a62963SBryan Wu  * The filter used is an Infinite Input Response(IIR) filter implemented
33031a62963SBryan Wu  * in firmware and attenuates the noise on the CDC results after they've
33131a62963SBryan Wu  * been read by the host processor.
33231a62963SBryan Wu  * Filtered_CDC_result = (Filtered_CDC_result * (10 - Coefficient) +
33331a62963SBryan Wu  *				Latest_CDC_result * Coefficient)/10
33431a62963SBryan Wu  */
33531a62963SBryan Wu static void ad714x_slider_cal_flt_pos(struct ad714x_chip *ad714x, int idx)
33631a62963SBryan Wu {
33731a62963SBryan Wu 	struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx];
33831a62963SBryan Wu 
33931a62963SBryan Wu 	sw->flt_pos = (sw->flt_pos * (10 - 4) +
34031a62963SBryan Wu 			sw->abs_pos * 4)/10;
34131a62963SBryan Wu 
34231a62963SBryan Wu 	dev_dbg(ad714x->dev, "slider %d filter position:%d\n", idx,
34331a62963SBryan Wu 		sw->flt_pos);
34431a62963SBryan Wu }
34531a62963SBryan Wu 
34631a62963SBryan Wu static void ad714x_slider_use_com_int(struct ad714x_chip *ad714x, int idx)
34731a62963SBryan Wu {
34831a62963SBryan Wu 	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
34931a62963SBryan Wu 
35031a62963SBryan Wu 	ad714x_use_com_int(ad714x, hw->start_stage, hw->end_stage);
35131a62963SBryan Wu }
35231a62963SBryan Wu 
35331a62963SBryan Wu static void ad714x_slider_use_thr_int(struct ad714x_chip *ad714x, int idx)
35431a62963SBryan Wu {
35531a62963SBryan Wu 	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
35631a62963SBryan Wu 
35731a62963SBryan Wu 	ad714x_use_thr_int(ad714x, hw->start_stage, hw->end_stage);
35831a62963SBryan Wu }
35931a62963SBryan Wu 
36031a62963SBryan Wu static void ad714x_slider_state_machine(struct ad714x_chip *ad714x, int idx)
36131a62963SBryan Wu {
36231a62963SBryan Wu 	struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
36331a62963SBryan Wu 	struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx];
36431a62963SBryan Wu 	unsigned short h_state, c_state;
36531a62963SBryan Wu 	unsigned short mask;
36631a62963SBryan Wu 
36731a62963SBryan Wu 	mask = ((1 << (hw->end_stage + 1)) - 1) - ((1 << hw->start_stage) - 1);
36831a62963SBryan Wu 
36931a62963SBryan Wu 	h_state = ad714x->h_state & mask;
37031a62963SBryan Wu 	c_state = ad714x->c_state & mask;
37131a62963SBryan Wu 
37231a62963SBryan Wu 	switch (sw->state) {
37331a62963SBryan Wu 	case IDLE:
37431a62963SBryan Wu 		if (h_state) {
37531a62963SBryan Wu 			sw->state = JITTER;
37631a62963SBryan Wu 			/* In End of Conversion interrupt mode, the AD714X
37731a62963SBryan Wu 			 * continuously generates hardware interrupts.
37831a62963SBryan Wu 			 */
37931a62963SBryan Wu 			ad714x_slider_use_com_int(ad714x, idx);
38031a62963SBryan Wu 			dev_dbg(ad714x->dev, "slider %d touched\n", idx);
38131a62963SBryan Wu 		}
38231a62963SBryan Wu 		break;
38331a62963SBryan Wu 
38431a62963SBryan Wu 	case JITTER:
38531a62963SBryan Wu 		if (c_state == mask) {
38631a62963SBryan Wu 			ad714x_slider_cal_sensor_val(ad714x, idx);
38731a62963SBryan Wu 			ad714x_slider_cal_highest_stage(ad714x, idx);
38831a62963SBryan Wu 			ad714x_slider_cal_abs_pos(ad714x, idx);
38931a62963SBryan Wu 			sw->flt_pos = sw->abs_pos;
39031a62963SBryan Wu 			sw->state = ACTIVE;
39131a62963SBryan Wu 		}
39231a62963SBryan Wu 		break;
39331a62963SBryan Wu 
39431a62963SBryan Wu 	case ACTIVE:
39531a62963SBryan Wu 		if (c_state == mask) {
39631a62963SBryan Wu 			if (h_state) {
39731a62963SBryan Wu 				ad714x_slider_cal_sensor_val(ad714x, idx);
39831a62963SBryan Wu 				ad714x_slider_cal_highest_stage(ad714x, idx);
39931a62963SBryan Wu 				ad714x_slider_cal_abs_pos(ad714x, idx);
40031a62963SBryan Wu 				ad714x_slider_cal_flt_pos(ad714x, idx);
40131a62963SBryan Wu 				input_report_abs(sw->input, ABS_X, sw->flt_pos);
40231a62963SBryan Wu 				input_report_key(sw->input, BTN_TOUCH, 1);
40331a62963SBryan Wu 			} else {
40431a62963SBryan Wu 				/* When the user lifts off the sensor, configure
40531a62963SBryan Wu 				 * the AD714X back to threshold interrupt mode.
40631a62963SBryan Wu 				 */
40731a62963SBryan Wu 				ad714x_slider_use_thr_int(ad714x, idx);
40831a62963SBryan Wu 				sw->state = IDLE;
40931a62963SBryan Wu 				input_report_key(sw->input, BTN_TOUCH, 0);
41031a62963SBryan Wu 				dev_dbg(ad714x->dev, "slider %d released\n",
41131a62963SBryan Wu 					idx);
41231a62963SBryan Wu 			}
41331a62963SBryan Wu 			input_sync(sw->input);
41431a62963SBryan Wu 		}
41531a62963SBryan Wu 		break;
41631a62963SBryan Wu 
41731a62963SBryan Wu 	default:
41831a62963SBryan Wu 		break;
41931a62963SBryan Wu 	}
42031a62963SBryan Wu }
42131a62963SBryan Wu 
42231a62963SBryan Wu /*
42331a62963SBryan Wu  * When the scroll wheel is activated, we compute the absolute position based
42431a62963SBryan Wu  * on the sensor values. To calculate the position, we first determine the
42531a62963SBryan Wu  * sensor that has the greatest response among the 8 sensors that constitutes
42631a62963SBryan Wu  * the scrollwheel. Then we determined the 2 sensors on either sides of the
42731a62963SBryan Wu  * sensor with the highest response and we apply weights to these sensors.
42831a62963SBryan Wu  */
42931a62963SBryan Wu static void ad714x_wheel_cal_highest_stage(struct ad714x_chip *ad714x, int idx)
43031a62963SBryan Wu {
43131a62963SBryan Wu 	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
43231a62963SBryan Wu 	struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
43331a62963SBryan Wu 
43431a62963SBryan Wu 	sw->pre_highest_stage = sw->highest_stage;
43531a62963SBryan Wu 	sw->highest_stage = ad714x_cal_highest_stage(ad714x, hw->start_stage,
43631a62963SBryan Wu 			hw->end_stage);
43731a62963SBryan Wu 
43831a62963SBryan Wu 	dev_dbg(ad714x->dev, "wheel %d highest_stage:%d\n", idx,
43931a62963SBryan Wu 		sw->highest_stage);
44031a62963SBryan Wu }
44131a62963SBryan Wu 
44231a62963SBryan Wu static void ad714x_wheel_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
44331a62963SBryan Wu {
44431a62963SBryan Wu 	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
44531a62963SBryan Wu 	int i;
44631a62963SBryan Wu 
44731a62963SBryan Wu 	for (i = hw->start_stage; i <= hw->end_stage; i++) {
44831a62963SBryan Wu 		ad714x->read(ad714x->dev, CDC_RESULT_S0 + i,
44931a62963SBryan Wu 			&ad714x->adc_reg[i]);
45031a62963SBryan Wu 		ad714x->read(ad714x->dev,
45131a62963SBryan Wu 				STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
45231a62963SBryan Wu 				&ad714x->amb_reg[i]);
45331a62963SBryan Wu 		if (ad714x->adc_reg[i] > ad714x->amb_reg[i])
45431a62963SBryan Wu 			ad714x->sensor_val[i] = ad714x->adc_reg[i] -
45531a62963SBryan Wu 				ad714x->amb_reg[i];
45631a62963SBryan Wu 		else
45731a62963SBryan Wu 			ad714x->sensor_val[i] = 0;
45831a62963SBryan Wu 	}
45931a62963SBryan Wu }
46031a62963SBryan Wu 
46131a62963SBryan Wu /*
46231a62963SBryan Wu  * When the scroll wheel is activated, we compute the absolute position based
46331a62963SBryan Wu  * on the sensor values. To calculate the position, we first determine the
464f1e430e6SMichael Hennerich  * sensor that has the greatest response among the sensors that constitutes
465f1e430e6SMichael Hennerich  * the scrollwheel. Then we determined the sensors on either sides of the
46631a62963SBryan Wu  * sensor with the highest response and we apply weights to these sensors. The
467f1e430e6SMichael Hennerich  * result of this computation gives us the mean value.
46831a62963SBryan Wu  */
46931a62963SBryan Wu 
47031a62963SBryan Wu static void ad714x_wheel_cal_abs_pos(struct ad714x_chip *ad714x, int idx)
47131a62963SBryan Wu {
47231a62963SBryan Wu 	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
47331a62963SBryan Wu 	struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
47431a62963SBryan Wu 	int stage_num = hw->end_stage - hw->start_stage + 1;
475f1e430e6SMichael Hennerich 	int first_before, highest, first_after;
47631a62963SBryan Wu 	int a_param, b_param;
47731a62963SBryan Wu 
47831a62963SBryan Wu 	first_before = (sw->highest_stage + stage_num - 1) % stage_num;
47931a62963SBryan Wu 	highest = sw->highest_stage;
48031a62963SBryan Wu 	first_after = (sw->highest_stage + stage_num + 1) % stage_num;
48131a62963SBryan Wu 
482f1e430e6SMichael Hennerich 	a_param = ad714x->sensor_val[highest] *
483f1e430e6SMichael Hennerich 		(highest - hw->start_stage) +
48431a62963SBryan Wu 		ad714x->sensor_val[first_before] *
485f1e430e6SMichael Hennerich 		(highest - hw->start_stage - 1) +
48631a62963SBryan Wu 		ad714x->sensor_val[first_after] *
487f1e430e6SMichael Hennerich 		(highest - hw->start_stage + 1);
488f1e430e6SMichael Hennerich 	b_param = ad714x->sensor_val[highest] +
48931a62963SBryan Wu 		ad714x->sensor_val[first_before] +
490f1e430e6SMichael Hennerich 		ad714x->sensor_val[first_after];
49131a62963SBryan Wu 
492f1e430e6SMichael Hennerich 	sw->abs_pos = ((hw->max_coord / (hw->end_stage - hw->start_stage)) *
493f1e430e6SMichael Hennerich 			a_param) / b_param;
49431a62963SBryan Wu 
49531a62963SBryan Wu 	if (sw->abs_pos > hw->max_coord)
49631a62963SBryan Wu 		sw->abs_pos = hw->max_coord;
497f1e430e6SMichael Hennerich 	else if (sw->abs_pos < 0)
498f1e430e6SMichael Hennerich 		sw->abs_pos = 0;
49931a62963SBryan Wu }
50031a62963SBryan Wu 
50131a62963SBryan Wu static void ad714x_wheel_cal_flt_pos(struct ad714x_chip *ad714x, int idx)
50231a62963SBryan Wu {
50331a62963SBryan Wu 	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
50431a62963SBryan Wu 	struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
50531a62963SBryan Wu 	if (((sw->pre_highest_stage == hw->end_stage) &&
50631a62963SBryan Wu 			(sw->highest_stage == hw->start_stage)) ||
50731a62963SBryan Wu 	    ((sw->pre_highest_stage == hw->start_stage) &&
50831a62963SBryan Wu 			(sw->highest_stage == hw->end_stage)))
50931a62963SBryan Wu 		sw->flt_pos = sw->abs_pos;
51031a62963SBryan Wu 	else
51131a62963SBryan Wu 		sw->flt_pos = ((sw->flt_pos * 30) + (sw->abs_pos * 71)) / 100;
51231a62963SBryan Wu 
51331a62963SBryan Wu 	if (sw->flt_pos > hw->max_coord)
51431a62963SBryan Wu 		sw->flt_pos = hw->max_coord;
51531a62963SBryan Wu }
51631a62963SBryan Wu 
51731a62963SBryan Wu static void ad714x_wheel_use_com_int(struct ad714x_chip *ad714x, int idx)
51831a62963SBryan Wu {
51931a62963SBryan Wu 	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
52031a62963SBryan Wu 
52131a62963SBryan Wu 	ad714x_use_com_int(ad714x, hw->start_stage, hw->end_stage);
52231a62963SBryan Wu }
52331a62963SBryan Wu 
52431a62963SBryan Wu static void ad714x_wheel_use_thr_int(struct ad714x_chip *ad714x, int idx)
52531a62963SBryan Wu {
52631a62963SBryan Wu 	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
52731a62963SBryan Wu 
52831a62963SBryan Wu 	ad714x_use_thr_int(ad714x, hw->start_stage, hw->end_stage);
52931a62963SBryan Wu }
53031a62963SBryan Wu 
53131a62963SBryan Wu static void ad714x_wheel_state_machine(struct ad714x_chip *ad714x, int idx)
53231a62963SBryan Wu {
53331a62963SBryan Wu 	struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
53431a62963SBryan Wu 	struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
53531a62963SBryan Wu 	unsigned short h_state, c_state;
53631a62963SBryan Wu 	unsigned short mask;
53731a62963SBryan Wu 
53831a62963SBryan Wu 	mask = ((1 << (hw->end_stage + 1)) - 1) - ((1 << hw->start_stage) - 1);
53931a62963SBryan Wu 
54031a62963SBryan Wu 	h_state = ad714x->h_state & mask;
54131a62963SBryan Wu 	c_state = ad714x->c_state & mask;
54231a62963SBryan Wu 
54331a62963SBryan Wu 	switch (sw->state) {
54431a62963SBryan Wu 	case IDLE:
54531a62963SBryan Wu 		if (h_state) {
54631a62963SBryan Wu 			sw->state = JITTER;
54731a62963SBryan Wu 			/* In End of Conversion interrupt mode, the AD714X
54831a62963SBryan Wu 			 * continuously generates hardware interrupts.
54931a62963SBryan Wu 			 */
55031a62963SBryan Wu 			ad714x_wheel_use_com_int(ad714x, idx);
55131a62963SBryan Wu 			dev_dbg(ad714x->dev, "wheel %d touched\n", idx);
55231a62963SBryan Wu 		}
55331a62963SBryan Wu 		break;
55431a62963SBryan Wu 
55531a62963SBryan Wu 	case JITTER:
55631a62963SBryan Wu 		if (c_state == mask)	{
55731a62963SBryan Wu 			ad714x_wheel_cal_sensor_val(ad714x, idx);
55831a62963SBryan Wu 			ad714x_wheel_cal_highest_stage(ad714x, idx);
55931a62963SBryan Wu 			ad714x_wheel_cal_abs_pos(ad714x, idx);
56031a62963SBryan Wu 			sw->flt_pos = sw->abs_pos;
56131a62963SBryan Wu 			sw->state = ACTIVE;
56231a62963SBryan Wu 		}
56331a62963SBryan Wu 		break;
56431a62963SBryan Wu 
56531a62963SBryan Wu 	case ACTIVE:
56631a62963SBryan Wu 		if (c_state == mask) {
56731a62963SBryan Wu 			if (h_state) {
56831a62963SBryan Wu 				ad714x_wheel_cal_sensor_val(ad714x, idx);
56931a62963SBryan Wu 				ad714x_wheel_cal_highest_stage(ad714x, idx);
57031a62963SBryan Wu 				ad714x_wheel_cal_abs_pos(ad714x, idx);
57131a62963SBryan Wu 				ad714x_wheel_cal_flt_pos(ad714x, idx);
57231a62963SBryan Wu 				input_report_abs(sw->input, ABS_WHEEL,
573f1e430e6SMichael Hennerich 					sw->flt_pos);
57431a62963SBryan Wu 				input_report_key(sw->input, BTN_TOUCH, 1);
57531a62963SBryan Wu 			} else {
57631a62963SBryan Wu 				/* When the user lifts off the sensor, configure
57731a62963SBryan Wu 				 * the AD714X back to threshold interrupt mode.
57831a62963SBryan Wu 				 */
57931a62963SBryan Wu 				ad714x_wheel_use_thr_int(ad714x, idx);
58031a62963SBryan Wu 				sw->state = IDLE;
58131a62963SBryan Wu 				input_report_key(sw->input, BTN_TOUCH, 0);
58231a62963SBryan Wu 
58331a62963SBryan Wu 				dev_dbg(ad714x->dev, "wheel %d released\n",
58431a62963SBryan Wu 					idx);
58531a62963SBryan Wu 			}
58631a62963SBryan Wu 			input_sync(sw->input);
58731a62963SBryan Wu 		}
58831a62963SBryan Wu 		break;
58931a62963SBryan Wu 
59031a62963SBryan Wu 	default:
59131a62963SBryan Wu 		break;
59231a62963SBryan Wu 	}
59331a62963SBryan Wu }
59431a62963SBryan Wu 
59531a62963SBryan Wu static void touchpad_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
59631a62963SBryan Wu {
59731a62963SBryan Wu 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
59831a62963SBryan Wu 	int i;
59931a62963SBryan Wu 
60031a62963SBryan Wu 	for (i = hw->x_start_stage; i <= hw->x_end_stage; i++) {
60131a62963SBryan Wu 		ad714x->read(ad714x->dev, CDC_RESULT_S0 + i,
60231a62963SBryan Wu 				&ad714x->adc_reg[i]);
60331a62963SBryan Wu 		ad714x->read(ad714x->dev,
60431a62963SBryan Wu 				STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
60531a62963SBryan Wu 				&ad714x->amb_reg[i]);
60631a62963SBryan Wu 		if (ad714x->adc_reg[i] > ad714x->amb_reg[i])
60731a62963SBryan Wu 			ad714x->sensor_val[i] = ad714x->adc_reg[i] -
60831a62963SBryan Wu 				ad714x->amb_reg[i];
60931a62963SBryan Wu 		else
61031a62963SBryan Wu 			ad714x->sensor_val[i] = 0;
61131a62963SBryan Wu 	}
61231a62963SBryan Wu }
61331a62963SBryan Wu 
61431a62963SBryan Wu static void touchpad_cal_highest_stage(struct ad714x_chip *ad714x, int idx)
61531a62963SBryan Wu {
61631a62963SBryan Wu 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
61731a62963SBryan Wu 	struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
61831a62963SBryan Wu 
61931a62963SBryan Wu 	sw->x_highest_stage = ad714x_cal_highest_stage(ad714x,
62031a62963SBryan Wu 		hw->x_start_stage, hw->x_end_stage);
62131a62963SBryan Wu 	sw->y_highest_stage = ad714x_cal_highest_stage(ad714x,
62231a62963SBryan Wu 		hw->y_start_stage, hw->y_end_stage);
62331a62963SBryan Wu 
62431a62963SBryan Wu 	dev_dbg(ad714x->dev,
62531a62963SBryan Wu 		"touchpad %d x_highest_stage:%d, y_highest_stage:%d\n",
62631a62963SBryan Wu 		idx, sw->x_highest_stage, sw->y_highest_stage);
62731a62963SBryan Wu }
62831a62963SBryan Wu 
62931a62963SBryan Wu /*
63031a62963SBryan Wu  * If 2 fingers are touching the sensor then 2 peaks can be observed in the
63131a62963SBryan Wu  * distribution.
63231a62963SBryan Wu  * The arithmetic doesn't support to get absolute coordinates for multi-touch
63331a62963SBryan Wu  * yet.
63431a62963SBryan Wu  */
63531a62963SBryan Wu static int touchpad_check_second_peak(struct ad714x_chip *ad714x, int idx)
63631a62963SBryan Wu {
63731a62963SBryan Wu 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
63831a62963SBryan Wu 	struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
63931a62963SBryan Wu 	int i;
64031a62963SBryan Wu 
64131a62963SBryan Wu 	for (i = hw->x_start_stage; i < sw->x_highest_stage; i++) {
64231a62963SBryan Wu 		if ((ad714x->sensor_val[i] - ad714x->sensor_val[i + 1])
64331a62963SBryan Wu 			> (ad714x->sensor_val[i + 1] / 10))
64431a62963SBryan Wu 			return 1;
64531a62963SBryan Wu 	}
64631a62963SBryan Wu 
64731a62963SBryan Wu 	for (i = sw->x_highest_stage; i < hw->x_end_stage; i++) {
64831a62963SBryan Wu 		if ((ad714x->sensor_val[i + 1] - ad714x->sensor_val[i])
64931a62963SBryan Wu 			> (ad714x->sensor_val[i] / 10))
65031a62963SBryan Wu 			return 1;
65131a62963SBryan Wu 	}
65231a62963SBryan Wu 
65331a62963SBryan Wu 	for (i = hw->y_start_stage; i < sw->y_highest_stage; i++) {
65431a62963SBryan Wu 		if ((ad714x->sensor_val[i] - ad714x->sensor_val[i + 1])
65531a62963SBryan Wu 			> (ad714x->sensor_val[i + 1] / 10))
65631a62963SBryan Wu 			return 1;
65731a62963SBryan Wu 	}
65831a62963SBryan Wu 
65931a62963SBryan Wu 	for (i = sw->y_highest_stage; i < hw->y_end_stage; i++) {
66031a62963SBryan Wu 		if ((ad714x->sensor_val[i + 1] - ad714x->sensor_val[i])
66131a62963SBryan Wu 			> (ad714x->sensor_val[i] / 10))
66231a62963SBryan Wu 			return 1;
66331a62963SBryan Wu 	}
66431a62963SBryan Wu 
66531a62963SBryan Wu 	return 0;
66631a62963SBryan Wu }
66731a62963SBryan Wu 
66831a62963SBryan Wu /*
66931a62963SBryan Wu  * If only one finger is used to activate the touch pad then only 1 peak will be
67031a62963SBryan Wu  * registered in the distribution. This peak and the 2 adjacent sensors will be
67131a62963SBryan Wu  * used in the calculation of the absolute position. This will prevent hand
67231a62963SBryan Wu  * shadows to affect the absolute position calculation.
67331a62963SBryan Wu  */
67431a62963SBryan Wu static void touchpad_cal_abs_pos(struct ad714x_chip *ad714x, int idx)
67531a62963SBryan Wu {
67631a62963SBryan Wu 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
67731a62963SBryan Wu 	struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
67831a62963SBryan Wu 
67931a62963SBryan Wu 	sw->x_abs_pos = ad714x_cal_abs_pos(ad714x, hw->x_start_stage,
68031a62963SBryan Wu 			hw->x_end_stage, sw->x_highest_stage, hw->x_max_coord);
68131a62963SBryan Wu 	sw->y_abs_pos = ad714x_cal_abs_pos(ad714x, hw->y_start_stage,
68231a62963SBryan Wu 			hw->y_end_stage, sw->y_highest_stage, hw->y_max_coord);
68331a62963SBryan Wu 
68431a62963SBryan Wu 	dev_dbg(ad714x->dev, "touchpad %d absolute position:(%d, %d)\n", idx,
68531a62963SBryan Wu 			sw->x_abs_pos, sw->y_abs_pos);
68631a62963SBryan Wu }
68731a62963SBryan Wu 
68831a62963SBryan Wu static void touchpad_cal_flt_pos(struct ad714x_chip *ad714x, int idx)
68931a62963SBryan Wu {
69031a62963SBryan Wu 	struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
69131a62963SBryan Wu 
69231a62963SBryan Wu 	sw->x_flt_pos = (sw->x_flt_pos * (10 - 4) +
69331a62963SBryan Wu 			sw->x_abs_pos * 4)/10;
69431a62963SBryan Wu 	sw->y_flt_pos = (sw->y_flt_pos * (10 - 4) +
69531a62963SBryan Wu 			sw->y_abs_pos * 4)/10;
69631a62963SBryan Wu 
69731a62963SBryan Wu 	dev_dbg(ad714x->dev, "touchpad %d filter position:(%d, %d)\n",
69831a62963SBryan Wu 			idx, sw->x_flt_pos, sw->y_flt_pos);
69931a62963SBryan Wu }
70031a62963SBryan Wu 
70131a62963SBryan Wu /*
70231a62963SBryan Wu  * To prevent distortion from showing in the absolute position, it is
70331a62963SBryan Wu  * necessary to detect the end points. When endpoints are detected, the
70431a62963SBryan Wu  * driver stops updating the status variables with absolute positions.
70531a62963SBryan Wu  * End points are detected on the 4 edges of the touchpad sensor. The
70631a62963SBryan Wu  * method to detect them is the same for all 4.
70731a62963SBryan Wu  * To detect the end points, the firmware computes the difference in
70831a62963SBryan Wu  * percent between the sensor on the edge and the adjacent one. The
70931a62963SBryan Wu  * difference is calculated in percent in order to make the end point
71031a62963SBryan Wu  * detection independent of the pressure.
71131a62963SBryan Wu  */
71231a62963SBryan Wu 
71331a62963SBryan Wu #define LEFT_END_POINT_DETECTION_LEVEL                  550
71431a62963SBryan Wu #define RIGHT_END_POINT_DETECTION_LEVEL                 750
71531a62963SBryan Wu #define LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL         850
71631a62963SBryan Wu #define TOP_END_POINT_DETECTION_LEVEL                   550
71731a62963SBryan Wu #define BOTTOM_END_POINT_DETECTION_LEVEL                950
71831a62963SBryan Wu #define TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL         700
71931a62963SBryan Wu static int touchpad_check_endpoint(struct ad714x_chip *ad714x, int idx)
72031a62963SBryan Wu {
72131a62963SBryan Wu 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
72231a62963SBryan Wu 	struct ad714x_touchpad_drv *sw  = &ad714x->sw->touchpad[idx];
72331a62963SBryan Wu 	int percent_sensor_diff;
72431a62963SBryan Wu 
72531a62963SBryan Wu 	/* left endpoint detect */
72631a62963SBryan Wu 	percent_sensor_diff = (ad714x->sensor_val[hw->x_start_stage] -
72731a62963SBryan Wu 			ad714x->sensor_val[hw->x_start_stage + 1]) * 100 /
72831a62963SBryan Wu 			ad714x->sensor_val[hw->x_start_stage + 1];
72931a62963SBryan Wu 	if (!sw->left_ep) {
73031a62963SBryan Wu 		if (percent_sensor_diff >= LEFT_END_POINT_DETECTION_LEVEL)  {
73131a62963SBryan Wu 			sw->left_ep = 1;
73231a62963SBryan Wu 			sw->left_ep_val =
73331a62963SBryan Wu 				ad714x->sensor_val[hw->x_start_stage + 1];
73431a62963SBryan Wu 		}
73531a62963SBryan Wu 	} else {
73631a62963SBryan Wu 		if ((percent_sensor_diff < LEFT_END_POINT_DETECTION_LEVEL) &&
73731a62963SBryan Wu 		    (ad714x->sensor_val[hw->x_start_stage + 1] >
73831a62963SBryan Wu 		     LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL + sw->left_ep_val))
73931a62963SBryan Wu 			sw->left_ep = 0;
74031a62963SBryan Wu 	}
74131a62963SBryan Wu 
74231a62963SBryan Wu 	/* right endpoint detect */
74331a62963SBryan Wu 	percent_sensor_diff = (ad714x->sensor_val[hw->x_end_stage] -
74431a62963SBryan Wu 			ad714x->sensor_val[hw->x_end_stage - 1]) * 100 /
74531a62963SBryan Wu 			ad714x->sensor_val[hw->x_end_stage - 1];
74631a62963SBryan Wu 	if (!sw->right_ep) {
74731a62963SBryan Wu 		if (percent_sensor_diff >= RIGHT_END_POINT_DETECTION_LEVEL)  {
74831a62963SBryan Wu 			sw->right_ep = 1;
74931a62963SBryan Wu 			sw->right_ep_val =
75031a62963SBryan Wu 				ad714x->sensor_val[hw->x_end_stage - 1];
75131a62963SBryan Wu 		}
75231a62963SBryan Wu 	} else {
75331a62963SBryan Wu 		if ((percent_sensor_diff < RIGHT_END_POINT_DETECTION_LEVEL) &&
75431a62963SBryan Wu 		(ad714x->sensor_val[hw->x_end_stage - 1] >
75531a62963SBryan Wu 		LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL + sw->right_ep_val))
75631a62963SBryan Wu 			sw->right_ep = 0;
75731a62963SBryan Wu 	}
75831a62963SBryan Wu 
75931a62963SBryan Wu 	/* top endpoint detect */
76031a62963SBryan Wu 	percent_sensor_diff = (ad714x->sensor_val[hw->y_start_stage] -
76131a62963SBryan Wu 			ad714x->sensor_val[hw->y_start_stage + 1]) * 100 /
76231a62963SBryan Wu 			ad714x->sensor_val[hw->y_start_stage + 1];
76331a62963SBryan Wu 	if (!sw->top_ep) {
76431a62963SBryan Wu 		if (percent_sensor_diff >= TOP_END_POINT_DETECTION_LEVEL)  {
76531a62963SBryan Wu 			sw->top_ep = 1;
76631a62963SBryan Wu 			sw->top_ep_val =
76731a62963SBryan Wu 				ad714x->sensor_val[hw->y_start_stage + 1];
76831a62963SBryan Wu 		}
76931a62963SBryan Wu 	} else {
77031a62963SBryan Wu 		if ((percent_sensor_diff < TOP_END_POINT_DETECTION_LEVEL) &&
77131a62963SBryan Wu 		(ad714x->sensor_val[hw->y_start_stage + 1] >
77231a62963SBryan Wu 		TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL + sw->top_ep_val))
77331a62963SBryan Wu 			sw->top_ep = 0;
77431a62963SBryan Wu 	}
77531a62963SBryan Wu 
77631a62963SBryan Wu 	/* bottom endpoint detect */
77731a62963SBryan Wu 	percent_sensor_diff = (ad714x->sensor_val[hw->y_end_stage] -
77831a62963SBryan Wu 		ad714x->sensor_val[hw->y_end_stage - 1]) * 100 /
77931a62963SBryan Wu 		ad714x->sensor_val[hw->y_end_stage - 1];
78031a62963SBryan Wu 	if (!sw->bottom_ep) {
78131a62963SBryan Wu 		if (percent_sensor_diff >= BOTTOM_END_POINT_DETECTION_LEVEL)  {
78231a62963SBryan Wu 			sw->bottom_ep = 1;
78331a62963SBryan Wu 			sw->bottom_ep_val =
78431a62963SBryan Wu 				ad714x->sensor_val[hw->y_end_stage - 1];
78531a62963SBryan Wu 		}
78631a62963SBryan Wu 	} else {
78731a62963SBryan Wu 		if ((percent_sensor_diff < BOTTOM_END_POINT_DETECTION_LEVEL) &&
78831a62963SBryan Wu 		(ad714x->sensor_val[hw->y_end_stage - 1] >
78931a62963SBryan Wu 		 TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL + sw->bottom_ep_val))
79031a62963SBryan Wu 			sw->bottom_ep = 0;
79131a62963SBryan Wu 	}
79231a62963SBryan Wu 
79331a62963SBryan Wu 	return sw->left_ep || sw->right_ep || sw->top_ep || sw->bottom_ep;
79431a62963SBryan Wu }
79531a62963SBryan Wu 
79631a62963SBryan Wu static void touchpad_use_com_int(struct ad714x_chip *ad714x, int idx)
79731a62963SBryan Wu {
79831a62963SBryan Wu 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
79931a62963SBryan Wu 
80031a62963SBryan Wu 	ad714x_use_com_int(ad714x, hw->x_start_stage, hw->x_end_stage);
80131a62963SBryan Wu }
80231a62963SBryan Wu 
80331a62963SBryan Wu static void touchpad_use_thr_int(struct ad714x_chip *ad714x, int idx)
80431a62963SBryan Wu {
80531a62963SBryan Wu 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
80631a62963SBryan Wu 
80731a62963SBryan Wu 	ad714x_use_thr_int(ad714x, hw->x_start_stage, hw->x_end_stage);
80831a62963SBryan Wu 	ad714x_use_thr_int(ad714x, hw->y_start_stage, hw->y_end_stage);
80931a62963SBryan Wu }
81031a62963SBryan Wu 
81131a62963SBryan Wu static void ad714x_touchpad_state_machine(struct ad714x_chip *ad714x, int idx)
81231a62963SBryan Wu {
81331a62963SBryan Wu 	struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
81431a62963SBryan Wu 	struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
81531a62963SBryan Wu 	unsigned short h_state, c_state;
81631a62963SBryan Wu 	unsigned short mask;
81731a62963SBryan Wu 
81831a62963SBryan Wu 	mask = (((1 << (hw->x_end_stage + 1)) - 1) -
81931a62963SBryan Wu 		((1 << hw->x_start_stage) - 1)) +
82031a62963SBryan Wu 		(((1 << (hw->y_end_stage + 1)) - 1) -
82131a62963SBryan Wu 		((1 << hw->y_start_stage) - 1));
82231a62963SBryan Wu 
82331a62963SBryan Wu 	h_state = ad714x->h_state & mask;
82431a62963SBryan Wu 	c_state = ad714x->c_state & mask;
82531a62963SBryan Wu 
82631a62963SBryan Wu 	switch (sw->state) {
82731a62963SBryan Wu 	case IDLE:
82831a62963SBryan Wu 		if (h_state) {
82931a62963SBryan Wu 			sw->state = JITTER;
83031a62963SBryan Wu 			/* In End of Conversion interrupt mode, the AD714X
83131a62963SBryan Wu 			 * continuously generates hardware interrupts.
83231a62963SBryan Wu 			 */
83331a62963SBryan Wu 			touchpad_use_com_int(ad714x, idx);
83431a62963SBryan Wu 			dev_dbg(ad714x->dev, "touchpad %d touched\n", idx);
83531a62963SBryan Wu 		}
83631a62963SBryan Wu 		break;
83731a62963SBryan Wu 
83831a62963SBryan Wu 	case JITTER:
83931a62963SBryan Wu 		if (c_state == mask) {
84031a62963SBryan Wu 			touchpad_cal_sensor_val(ad714x, idx);
84131a62963SBryan Wu 			touchpad_cal_highest_stage(ad714x, idx);
84231a62963SBryan Wu 			if ((!touchpad_check_second_peak(ad714x, idx)) &&
84331a62963SBryan Wu 				(!touchpad_check_endpoint(ad714x, idx))) {
84431a62963SBryan Wu 				dev_dbg(ad714x->dev,
84531a62963SBryan Wu 					"touchpad%d, 2 fingers or endpoint\n",
84631a62963SBryan Wu 					idx);
84731a62963SBryan Wu 				touchpad_cal_abs_pos(ad714x, idx);
84831a62963SBryan Wu 				sw->x_flt_pos = sw->x_abs_pos;
84931a62963SBryan Wu 				sw->y_flt_pos = sw->y_abs_pos;
85031a62963SBryan Wu 				sw->state = ACTIVE;
85131a62963SBryan Wu 			}
85231a62963SBryan Wu 		}
85331a62963SBryan Wu 		break;
85431a62963SBryan Wu 
85531a62963SBryan Wu 	case ACTIVE:
85631a62963SBryan Wu 		if (c_state == mask) {
85731a62963SBryan Wu 			if (h_state) {
85831a62963SBryan Wu 				touchpad_cal_sensor_val(ad714x, idx);
85931a62963SBryan Wu 				touchpad_cal_highest_stage(ad714x, idx);
86031a62963SBryan Wu 				if ((!touchpad_check_second_peak(ad714x, idx))
86131a62963SBryan Wu 				  && (!touchpad_check_endpoint(ad714x, idx))) {
86231a62963SBryan Wu 					touchpad_cal_abs_pos(ad714x, idx);
86331a62963SBryan Wu 					touchpad_cal_flt_pos(ad714x, idx);
86431a62963SBryan Wu 					input_report_abs(sw->input, ABS_X,
86531a62963SBryan Wu 						sw->x_flt_pos);
86631a62963SBryan Wu 					input_report_abs(sw->input, ABS_Y,
86731a62963SBryan Wu 						sw->y_flt_pos);
86831a62963SBryan Wu 					input_report_key(sw->input, BTN_TOUCH,
86931a62963SBryan Wu 						1);
87031a62963SBryan Wu 				}
87131a62963SBryan Wu 			} else {
87231a62963SBryan Wu 				/* When the user lifts off the sensor, configure
87331a62963SBryan Wu 				 * the AD714X back to threshold interrupt mode.
87431a62963SBryan Wu 				 */
87531a62963SBryan Wu 				touchpad_use_thr_int(ad714x, idx);
87631a62963SBryan Wu 				sw->state = IDLE;
87731a62963SBryan Wu 				input_report_key(sw->input, BTN_TOUCH, 0);
87831a62963SBryan Wu 				dev_dbg(ad714x->dev, "touchpad %d released\n",
87931a62963SBryan Wu 					idx);
88031a62963SBryan Wu 			}
88131a62963SBryan Wu 			input_sync(sw->input);
88231a62963SBryan Wu 		}
88331a62963SBryan Wu 		break;
88431a62963SBryan Wu 
88531a62963SBryan Wu 	default:
88631a62963SBryan Wu 		break;
88731a62963SBryan Wu 	}
88831a62963SBryan Wu }
88931a62963SBryan Wu 
89031a62963SBryan Wu static int ad714x_hw_detect(struct ad714x_chip *ad714x)
89131a62963SBryan Wu {
89231a62963SBryan Wu 	unsigned short data;
89331a62963SBryan Wu 
89431a62963SBryan Wu 	ad714x->read(ad714x->dev, AD714X_PARTID_REG, &data);
89531a62963SBryan Wu 	switch (data & 0xFFF0) {
89631a62963SBryan Wu 	case AD7142_PARTID:
89731a62963SBryan Wu 		ad714x->product = 0x7142;
89831a62963SBryan Wu 		ad714x->version = data & 0xF;
89931a62963SBryan Wu 		dev_info(ad714x->dev, "found AD7142 captouch, rev:%d\n",
90031a62963SBryan Wu 				ad714x->version);
90131a62963SBryan Wu 		return 0;
90231a62963SBryan Wu 
9036c04d7b3SBarry Song 	case AD7143_PARTID:
9046c04d7b3SBarry Song 		ad714x->product = 0x7143;
9056c04d7b3SBarry Song 		ad714x->version = data & 0xF;
9066c04d7b3SBarry Song 		dev_info(ad714x->dev, "found AD7143 captouch, rev:%d\n",
9076c04d7b3SBarry Song 				ad714x->version);
9086c04d7b3SBarry Song 		return 0;
9096c04d7b3SBarry Song 
9106c04d7b3SBarry Song 	case AD7147_PARTID:
9116c04d7b3SBarry Song 		ad714x->product = 0x7147;
9126c04d7b3SBarry Song 		ad714x->version = data & 0xF;
9136c04d7b3SBarry Song 		dev_info(ad714x->dev, "found AD7147(A) captouch, rev:%d\n",
9146c04d7b3SBarry Song 				ad714x->version);
9156c04d7b3SBarry Song 		return 0;
9166c04d7b3SBarry Song 
9176c04d7b3SBarry Song 	case AD7148_PARTID:
9186c04d7b3SBarry Song 		ad714x->product = 0x7148;
9196c04d7b3SBarry Song 		ad714x->version = data & 0xF;
9206c04d7b3SBarry Song 		dev_info(ad714x->dev, "found AD7148 captouch, rev:%d\n",
9216c04d7b3SBarry Song 				ad714x->version);
9226c04d7b3SBarry Song 		return 0;
9236c04d7b3SBarry Song 
92431a62963SBryan Wu 	default:
92531a62963SBryan Wu 		dev_err(ad714x->dev,
92631a62963SBryan Wu 			"fail to detect AD714X captouch, read ID is %04x\n",
92731a62963SBryan Wu 			data);
92831a62963SBryan Wu 		return -ENODEV;
92931a62963SBryan Wu 	}
93031a62963SBryan Wu }
93131a62963SBryan Wu 
93231a62963SBryan Wu static void ad714x_hw_init(struct ad714x_chip *ad714x)
93331a62963SBryan Wu {
93431a62963SBryan Wu 	int i, j;
93531a62963SBryan Wu 	unsigned short reg_base;
93631a62963SBryan Wu 	unsigned short data;
93731a62963SBryan Wu 
93831a62963SBryan Wu 	/* configuration CDC and interrupts */
93931a62963SBryan Wu 
94031a62963SBryan Wu 	for (i = 0; i < STAGE_NUM; i++) {
94131a62963SBryan Wu 		reg_base = AD714X_STAGECFG_REG + i * STAGE_CFGREG_NUM;
94231a62963SBryan Wu 		for (j = 0; j < STAGE_CFGREG_NUM; j++)
94331a62963SBryan Wu 			ad714x->write(ad714x->dev, reg_base + j,
94431a62963SBryan Wu 					ad714x->hw->stage_cfg_reg[i][j]);
94531a62963SBryan Wu 	}
94631a62963SBryan Wu 
94731a62963SBryan Wu 	for (i = 0; i < SYS_CFGREG_NUM; i++)
94831a62963SBryan Wu 		ad714x->write(ad714x->dev, AD714X_SYSCFG_REG + i,
94931a62963SBryan Wu 			ad714x->hw->sys_cfg_reg[i]);
95031a62963SBryan Wu 	for (i = 0; i < SYS_CFGREG_NUM; i++)
95131a62963SBryan Wu 		ad714x->read(ad714x->dev, AD714X_SYSCFG_REG + i,
95231a62963SBryan Wu 			&data);
95331a62963SBryan Wu 
95431a62963SBryan Wu 	ad714x->write(ad714x->dev, AD714X_STG_CAL_EN_REG, 0xFFF);
95531a62963SBryan Wu 
95631a62963SBryan Wu 	/* clear all interrupts */
95731a62963SBryan Wu 	ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &data);
95831a62963SBryan Wu 	ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &data);
95931a62963SBryan Wu 	ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &data);
96031a62963SBryan Wu }
96131a62963SBryan Wu 
96231a62963SBryan Wu static irqreturn_t ad714x_interrupt_thread(int irq, void *data)
96331a62963SBryan Wu {
96431a62963SBryan Wu 	struct ad714x_chip *ad714x = data;
96531a62963SBryan Wu 	int i;
96631a62963SBryan Wu 
96731a62963SBryan Wu 	mutex_lock(&ad714x->mutex);
96831a62963SBryan Wu 
96931a62963SBryan Wu 	ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &ad714x->l_state);
97031a62963SBryan Wu 	ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &ad714x->h_state);
97131a62963SBryan Wu 	ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &ad714x->c_state);
97231a62963SBryan Wu 
97331a62963SBryan Wu 	for (i = 0; i < ad714x->hw->button_num; i++)
97431a62963SBryan Wu 		ad714x_button_state_machine(ad714x, i);
97531a62963SBryan Wu 	for (i = 0; i < ad714x->hw->slider_num; i++)
97631a62963SBryan Wu 		ad714x_slider_state_machine(ad714x, i);
97731a62963SBryan Wu 	for (i = 0; i < ad714x->hw->wheel_num; i++)
97831a62963SBryan Wu 		ad714x_wheel_state_machine(ad714x, i);
97931a62963SBryan Wu 	for (i = 0; i < ad714x->hw->touchpad_num; i++)
98031a62963SBryan Wu 		ad714x_touchpad_state_machine(ad714x, i);
98131a62963SBryan Wu 
98231a62963SBryan Wu 	mutex_unlock(&ad714x->mutex);
98331a62963SBryan Wu 
98431a62963SBryan Wu 	return IRQ_HANDLED;
98531a62963SBryan Wu }
98631a62963SBryan Wu 
98731a62963SBryan Wu #define MAX_DEVICE_NUM 8
98831a62963SBryan Wu struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
98931a62963SBryan Wu 				 ad714x_read_t read, ad714x_write_t write)
99031a62963SBryan Wu {
99131a62963SBryan Wu 	int i, alloc_idx;
99231a62963SBryan Wu 	int error;
99331a62963SBryan Wu 	struct input_dev *input[MAX_DEVICE_NUM];
99431a62963SBryan Wu 
99531a62963SBryan Wu 	struct ad714x_platform_data *plat_data = dev->platform_data;
99631a62963SBryan Wu 	struct ad714x_chip *ad714x;
99731a62963SBryan Wu 	void *drv_mem;
99831a62963SBryan Wu 
99931a62963SBryan Wu 	struct ad714x_button_drv *bt_drv;
100031a62963SBryan Wu 	struct ad714x_slider_drv *sd_drv;
100131a62963SBryan Wu 	struct ad714x_wheel_drv *wl_drv;
100231a62963SBryan Wu 	struct ad714x_touchpad_drv *tp_drv;
100331a62963SBryan Wu 
100431a62963SBryan Wu 
100531a62963SBryan Wu 	if (irq <= 0) {
100631a62963SBryan Wu 		dev_err(dev, "IRQ not configured!\n");
100731a62963SBryan Wu 		error = -EINVAL;
100831a62963SBryan Wu 		goto err_out;
100931a62963SBryan Wu 	}
101031a62963SBryan Wu 
101131a62963SBryan Wu 	if (dev->platform_data == NULL) {
101231a62963SBryan Wu 		dev_err(dev, "platform data for ad714x doesn't exist\n");
101331a62963SBryan Wu 		error = -EINVAL;
101431a62963SBryan Wu 		goto err_out;
101531a62963SBryan Wu 	}
101631a62963SBryan Wu 
101731a62963SBryan Wu 	ad714x = kzalloc(sizeof(*ad714x) + sizeof(*ad714x->sw) +
101831a62963SBryan Wu 			 sizeof(*sd_drv) * plat_data->slider_num +
101931a62963SBryan Wu 			 sizeof(*wl_drv) * plat_data->wheel_num +
102031a62963SBryan Wu 			 sizeof(*tp_drv) * plat_data->touchpad_num +
102131a62963SBryan Wu 			 sizeof(*bt_drv) * plat_data->button_num, GFP_KERNEL);
102231a62963SBryan Wu 	if (!ad714x) {
102331a62963SBryan Wu 		error = -ENOMEM;
102431a62963SBryan Wu 		goto err_out;
102531a62963SBryan Wu 	}
102631a62963SBryan Wu 
102731a62963SBryan Wu 	ad714x->hw = plat_data;
102831a62963SBryan Wu 
102931a62963SBryan Wu 	drv_mem = ad714x + 1;
103031a62963SBryan Wu 	ad714x->sw = drv_mem;
103131a62963SBryan Wu 	drv_mem += sizeof(*ad714x->sw);
103231a62963SBryan Wu 	ad714x->sw->slider = sd_drv = drv_mem;
103331a62963SBryan Wu 	drv_mem += sizeof(*sd_drv) * ad714x->hw->slider_num;
103431a62963SBryan Wu 	ad714x->sw->wheel = wl_drv = drv_mem;
103531a62963SBryan Wu 	drv_mem += sizeof(*wl_drv) * ad714x->hw->wheel_num;
103631a62963SBryan Wu 	ad714x->sw->touchpad = tp_drv = drv_mem;
103731a62963SBryan Wu 	drv_mem += sizeof(*tp_drv) * ad714x->hw->touchpad_num;
103831a62963SBryan Wu 	ad714x->sw->button = bt_drv = drv_mem;
103931a62963SBryan Wu 	drv_mem += sizeof(*bt_drv) * ad714x->hw->button_num;
104031a62963SBryan Wu 
104131a62963SBryan Wu 	ad714x->read = read;
104231a62963SBryan Wu 	ad714x->write = write;
104331a62963SBryan Wu 	ad714x->irq = irq;
104431a62963SBryan Wu 	ad714x->dev = dev;
104531a62963SBryan Wu 
104631a62963SBryan Wu 	error = ad714x_hw_detect(ad714x);
104731a62963SBryan Wu 	if (error)
104831a62963SBryan Wu 		goto err_free_mem;
104931a62963SBryan Wu 
1050421f91d2SUwe Kleine-König 	/* initialize and request sw/hw resources */
105131a62963SBryan Wu 
105231a62963SBryan Wu 	ad714x_hw_init(ad714x);
105331a62963SBryan Wu 	mutex_init(&ad714x->mutex);
105431a62963SBryan Wu 
105531a62963SBryan Wu 	/*
105631a62963SBryan Wu 	 * Allocate and register AD714X input device
105731a62963SBryan Wu 	 */
105831a62963SBryan Wu 	alloc_idx = 0;
105931a62963SBryan Wu 
106031a62963SBryan Wu 	/* a slider uses one input_dev instance */
106131a62963SBryan Wu 	if (ad714x->hw->slider_num > 0) {
106231a62963SBryan Wu 		struct ad714x_slider_plat *sd_plat = ad714x->hw->slider;
106331a62963SBryan Wu 
106431a62963SBryan Wu 		for (i = 0; i < ad714x->hw->slider_num; i++) {
106531a62963SBryan Wu 			sd_drv[i].input = input[alloc_idx] = input_allocate_device();
106631a62963SBryan Wu 			if (!input[alloc_idx]) {
106731a62963SBryan Wu 				error = -ENOMEM;
106831a62963SBryan Wu 				goto err_free_dev;
106931a62963SBryan Wu 			}
107031a62963SBryan Wu 
107131a62963SBryan Wu 			__set_bit(EV_ABS, input[alloc_idx]->evbit);
107231a62963SBryan Wu 			__set_bit(EV_KEY, input[alloc_idx]->evbit);
107331a62963SBryan Wu 			__set_bit(ABS_X, input[alloc_idx]->absbit);
107431a62963SBryan Wu 			__set_bit(BTN_TOUCH, input[alloc_idx]->keybit);
107531a62963SBryan Wu 			input_set_abs_params(input[alloc_idx],
107631a62963SBryan Wu 				ABS_X, 0, sd_plat->max_coord, 0, 0);
107731a62963SBryan Wu 
107831a62963SBryan Wu 			input[alloc_idx]->id.bustype = bus_type;
107931a62963SBryan Wu 			input[alloc_idx]->id.product = ad714x->product;
108031a62963SBryan Wu 			input[alloc_idx]->id.version = ad714x->version;
1081dc5f4f5eSMichael Hennerich 			input[alloc_idx]->name = "ad714x_captouch_slider";
1082dc5f4f5eSMichael Hennerich 			input[alloc_idx]->dev.parent = dev;
108331a62963SBryan Wu 
108431a62963SBryan Wu 			error = input_register_device(input[alloc_idx]);
108531a62963SBryan Wu 			if (error)
108631a62963SBryan Wu 				goto err_free_dev;
108731a62963SBryan Wu 
108831a62963SBryan Wu 			alloc_idx++;
108931a62963SBryan Wu 		}
109031a62963SBryan Wu 	}
109131a62963SBryan Wu 
109231a62963SBryan Wu 	/* a wheel uses one input_dev instance */
109331a62963SBryan Wu 	if (ad714x->hw->wheel_num > 0) {
109431a62963SBryan Wu 		struct ad714x_wheel_plat *wl_plat = ad714x->hw->wheel;
109531a62963SBryan Wu 
109631a62963SBryan Wu 		for (i = 0; i < ad714x->hw->wheel_num; i++) {
109731a62963SBryan Wu 			wl_drv[i].input = input[alloc_idx] = input_allocate_device();
109831a62963SBryan Wu 			if (!input[alloc_idx]) {
109931a62963SBryan Wu 				error = -ENOMEM;
110031a62963SBryan Wu 				goto err_free_dev;
110131a62963SBryan Wu 			}
110231a62963SBryan Wu 
110331a62963SBryan Wu 			__set_bit(EV_KEY, input[alloc_idx]->evbit);
110431a62963SBryan Wu 			__set_bit(EV_ABS, input[alloc_idx]->evbit);
110531a62963SBryan Wu 			__set_bit(ABS_WHEEL, input[alloc_idx]->absbit);
110631a62963SBryan Wu 			__set_bit(BTN_TOUCH, input[alloc_idx]->keybit);
110731a62963SBryan Wu 			input_set_abs_params(input[alloc_idx],
110831a62963SBryan Wu 				ABS_WHEEL, 0, wl_plat->max_coord, 0, 0);
110931a62963SBryan Wu 
111031a62963SBryan Wu 			input[alloc_idx]->id.bustype = bus_type;
111131a62963SBryan Wu 			input[alloc_idx]->id.product = ad714x->product;
111231a62963SBryan Wu 			input[alloc_idx]->id.version = ad714x->version;
1113dc5f4f5eSMichael Hennerich 			input[alloc_idx]->name = "ad714x_captouch_wheel";
1114dc5f4f5eSMichael Hennerich 			input[alloc_idx]->dev.parent = dev;
111531a62963SBryan Wu 
111631a62963SBryan Wu 			error = input_register_device(input[alloc_idx]);
111731a62963SBryan Wu 			if (error)
111831a62963SBryan Wu 				goto err_free_dev;
111931a62963SBryan Wu 
112031a62963SBryan Wu 			alloc_idx++;
112131a62963SBryan Wu 		}
112231a62963SBryan Wu 	}
112331a62963SBryan Wu 
112431a62963SBryan Wu 	/* a touchpad uses one input_dev instance */
112531a62963SBryan Wu 	if (ad714x->hw->touchpad_num > 0) {
112631a62963SBryan Wu 		struct ad714x_touchpad_plat *tp_plat = ad714x->hw->touchpad;
112731a62963SBryan Wu 
112831a62963SBryan Wu 		for (i = 0; i < ad714x->hw->touchpad_num; i++) {
112931a62963SBryan Wu 			tp_drv[i].input = input[alloc_idx] = input_allocate_device();
113031a62963SBryan Wu 			if (!input[alloc_idx]) {
113131a62963SBryan Wu 				error = -ENOMEM;
113231a62963SBryan Wu 				goto err_free_dev;
113331a62963SBryan Wu 			}
113431a62963SBryan Wu 
113531a62963SBryan Wu 			__set_bit(EV_ABS, input[alloc_idx]->evbit);
113631a62963SBryan Wu 			__set_bit(EV_KEY, input[alloc_idx]->evbit);
113731a62963SBryan Wu 			__set_bit(ABS_X, input[alloc_idx]->absbit);
113831a62963SBryan Wu 			__set_bit(ABS_Y, input[alloc_idx]->absbit);
113931a62963SBryan Wu 			__set_bit(BTN_TOUCH, input[alloc_idx]->keybit);
114031a62963SBryan Wu 			input_set_abs_params(input[alloc_idx],
114131a62963SBryan Wu 				ABS_X, 0, tp_plat->x_max_coord, 0, 0);
114231a62963SBryan Wu 			input_set_abs_params(input[alloc_idx],
114331a62963SBryan Wu 				ABS_Y, 0, tp_plat->y_max_coord, 0, 0);
114431a62963SBryan Wu 
114531a62963SBryan Wu 			input[alloc_idx]->id.bustype = bus_type;
114631a62963SBryan Wu 			input[alloc_idx]->id.product = ad714x->product;
114731a62963SBryan Wu 			input[alloc_idx]->id.version = ad714x->version;
1148dc5f4f5eSMichael Hennerich 			input[alloc_idx]->name = "ad714x_captouch_pad";
1149dc5f4f5eSMichael Hennerich 			input[alloc_idx]->dev.parent = dev;
115031a62963SBryan Wu 
115131a62963SBryan Wu 			error = input_register_device(input[alloc_idx]);
115231a62963SBryan Wu 			if (error)
115331a62963SBryan Wu 				goto err_free_dev;
115431a62963SBryan Wu 
115531a62963SBryan Wu 			alloc_idx++;
115631a62963SBryan Wu 		}
115731a62963SBryan Wu 	}
115831a62963SBryan Wu 
115931a62963SBryan Wu 	/* all buttons use one input node */
116031a62963SBryan Wu 	if (ad714x->hw->button_num > 0) {
116131a62963SBryan Wu 		struct ad714x_button_plat *bt_plat = ad714x->hw->button;
116231a62963SBryan Wu 
116331a62963SBryan Wu 		input[alloc_idx] = input_allocate_device();
116431a62963SBryan Wu 		if (!input[alloc_idx]) {
116531a62963SBryan Wu 			error = -ENOMEM;
116631a62963SBryan Wu 			goto err_free_dev;
116731a62963SBryan Wu 		}
116831a62963SBryan Wu 
116931a62963SBryan Wu 		__set_bit(EV_KEY, input[alloc_idx]->evbit);
117031a62963SBryan Wu 		for (i = 0; i < ad714x->hw->button_num; i++) {
117131a62963SBryan Wu 			bt_drv[i].input = input[alloc_idx];
117231a62963SBryan Wu 			__set_bit(bt_plat[i].keycode, input[alloc_idx]->keybit);
117331a62963SBryan Wu 		}
117431a62963SBryan Wu 
117531a62963SBryan Wu 		input[alloc_idx]->id.bustype = bus_type;
117631a62963SBryan Wu 		input[alloc_idx]->id.product = ad714x->product;
117731a62963SBryan Wu 		input[alloc_idx]->id.version = ad714x->version;
1178dc5f4f5eSMichael Hennerich 		input[alloc_idx]->name = "ad714x_captouch_button";
1179dc5f4f5eSMichael Hennerich 		input[alloc_idx]->dev.parent = dev;
118031a62963SBryan Wu 
118131a62963SBryan Wu 		error = input_register_device(input[alloc_idx]);
118231a62963SBryan Wu 		if (error)
118331a62963SBryan Wu 			goto err_free_dev;
118431a62963SBryan Wu 
118531a62963SBryan Wu 		alloc_idx++;
118631a62963SBryan Wu 	}
118731a62963SBryan Wu 
118831a62963SBryan Wu 	error = request_threaded_irq(ad714x->irq, NULL, ad714x_interrupt_thread,
11893532cb0cSMichael Hennerich 				plat_data->irqflags ?
11903532cb0cSMichael Hennerich 					plat_data->irqflags : IRQF_TRIGGER_FALLING,
11913532cb0cSMichael Hennerich 				"ad714x_captouch", ad714x);
119231a62963SBryan Wu 	if (error) {
119331a62963SBryan Wu 		dev_err(dev, "can't allocate irq %d\n", ad714x->irq);
119431a62963SBryan Wu 		goto err_unreg_dev;
119531a62963SBryan Wu 	}
119631a62963SBryan Wu 
119731a62963SBryan Wu 	return ad714x;
119831a62963SBryan Wu 
119931a62963SBryan Wu  err_free_dev:
120031a62963SBryan Wu 	dev_err(dev, "failed to setup AD714x input device %i\n", alloc_idx);
120131a62963SBryan Wu 	input_free_device(input[alloc_idx]);
120231a62963SBryan Wu  err_unreg_dev:
120331a62963SBryan Wu 	while (--alloc_idx >= 0)
120431a62963SBryan Wu 		input_unregister_device(input[alloc_idx]);
120531a62963SBryan Wu  err_free_mem:
120631a62963SBryan Wu 	kfree(ad714x);
120731a62963SBryan Wu  err_out:
120831a62963SBryan Wu 	return ERR_PTR(error);
120931a62963SBryan Wu }
121031a62963SBryan Wu EXPORT_SYMBOL(ad714x_probe);
121131a62963SBryan Wu 
121231a62963SBryan Wu void ad714x_remove(struct ad714x_chip *ad714x)
121331a62963SBryan Wu {
121431a62963SBryan Wu 	struct ad714x_platform_data *hw = ad714x->hw;
121531a62963SBryan Wu 	struct ad714x_driver_data *sw = ad714x->sw;
121631a62963SBryan Wu 	int i;
121731a62963SBryan Wu 
121831a62963SBryan Wu 	free_irq(ad714x->irq, ad714x);
121931a62963SBryan Wu 
122031a62963SBryan Wu 	/* unregister and free all input devices */
122131a62963SBryan Wu 
122231a62963SBryan Wu 	for (i = 0; i < hw->slider_num; i++)
122331a62963SBryan Wu 		input_unregister_device(sw->slider[i].input);
122431a62963SBryan Wu 
122531a62963SBryan Wu 	for (i = 0; i < hw->wheel_num; i++)
122631a62963SBryan Wu 		input_unregister_device(sw->wheel[i].input);
122731a62963SBryan Wu 
122831a62963SBryan Wu 	for (i = 0; i < hw->touchpad_num; i++)
122931a62963SBryan Wu 		input_unregister_device(sw->touchpad[i].input);
123031a62963SBryan Wu 
123131a62963SBryan Wu 	if (hw->button_num)
123231a62963SBryan Wu 		input_unregister_device(sw->button[0].input);
123331a62963SBryan Wu 
123431a62963SBryan Wu 	kfree(ad714x);
123531a62963SBryan Wu }
123631a62963SBryan Wu EXPORT_SYMBOL(ad714x_remove);
123731a62963SBryan Wu 
123831a62963SBryan Wu #ifdef CONFIG_PM
123931a62963SBryan Wu int ad714x_disable(struct ad714x_chip *ad714x)
124031a62963SBryan Wu {
124131a62963SBryan Wu 	unsigned short data;
124231a62963SBryan Wu 
124331a62963SBryan Wu 	dev_dbg(ad714x->dev, "%s enter\n", __func__);
124431a62963SBryan Wu 
124531a62963SBryan Wu 	mutex_lock(&ad714x->mutex);
124631a62963SBryan Wu 
124731a62963SBryan Wu 	data = ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL] | 0x3;
124831a62963SBryan Wu 	ad714x->write(ad714x->dev, AD714X_PWR_CTRL, data);
124931a62963SBryan Wu 
125031a62963SBryan Wu 	mutex_unlock(&ad714x->mutex);
125131a62963SBryan Wu 
125231a62963SBryan Wu 	return 0;
125331a62963SBryan Wu }
125431a62963SBryan Wu EXPORT_SYMBOL(ad714x_disable);
125531a62963SBryan Wu 
125631a62963SBryan Wu int ad714x_enable(struct ad714x_chip *ad714x)
125731a62963SBryan Wu {
125831a62963SBryan Wu 	unsigned short data;
125931a62963SBryan Wu 
126031a62963SBryan Wu 	dev_dbg(ad714x->dev, "%s enter\n", __func__);
126131a62963SBryan Wu 
126231a62963SBryan Wu 	mutex_lock(&ad714x->mutex);
126331a62963SBryan Wu 
126431a62963SBryan Wu 	/* resume to non-shutdown mode */
126531a62963SBryan Wu 
126631a62963SBryan Wu 	ad714x->write(ad714x->dev, AD714X_PWR_CTRL,
126731a62963SBryan Wu 			ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL]);
126831a62963SBryan Wu 
126931a62963SBryan Wu 	/* make sure the interrupt output line is not low level after resume,
127031a62963SBryan Wu 	 * otherwise we will get no chance to enter falling-edge irq again
127131a62963SBryan Wu 	 */
127231a62963SBryan Wu 
127331a62963SBryan Wu 	ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &data);
127431a62963SBryan Wu 	ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &data);
127531a62963SBryan Wu 	ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &data);
127631a62963SBryan Wu 
127731a62963SBryan Wu 	mutex_unlock(&ad714x->mutex);
127831a62963SBryan Wu 
127931a62963SBryan Wu 	return 0;
128031a62963SBryan Wu }
128131a62963SBryan Wu EXPORT_SYMBOL(ad714x_enable);
128231a62963SBryan Wu #endif
128331a62963SBryan Wu 
128431a62963SBryan Wu MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor Driver");
128531a62963SBryan Wu MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
128631a62963SBryan Wu MODULE_LICENSE("GPL");
1287