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