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