/* * driver information which will be used to maintain the software flow
*/ enum ad714x_device_state { IDLE, JITTER, ACTIVE, SPACE };
struct ad714x_slider_drv { int highest_stage; int abs_pos; int flt_pos; enum ad714x_device_state state; struct input_dev *input;
};
struct ad714x_wheel_drv { int abs_pos; int flt_pos; int pre_highest_stage; int highest_stage; enum ad714x_device_state state; struct input_dev *input;
};
struct ad714x_touchpad_drv { int x_highest_stage; int x_flt_pos; int x_abs_pos; int y_highest_stage; int y_flt_pos; int y_abs_pos; int left_ep; int left_ep_val; int right_ep; int right_ep_val; int top_ep; int top_ep_val; int bottom_ep; int bottom_ep_val; enum ad714x_device_state state; struct input_dev *input;
};
struct ad714x_button_drv { enum ad714x_device_state state; /* * Unlike slider/wheel/touchpad, all buttons point to * same input_dev instance
*/ struct input_dev *input;
};
/* * One button can connect to multi positive and negative of CDCs * Multi-buttons can connect to same positive/negative of one CDC
*/ staticvoid ad714x_button_state_machine(struct ad714x_chip *ad714x, int idx)
{ struct ad714x_button_plat *hw = &ad714x->hw->button[idx]; struct ad714x_button_drv *sw = &ad714x->sw->button[idx];
/* * The response of a sensor is defined by the absolute number of codes * between the current CDC value and the ambient value.
*/ staticvoid ad714x_slider_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
{ struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx]; int i;
/* * The formulae are very straight forward. It uses the sensor with the * highest response and the 2 adjacent ones. * When Sensor 0 has the highest response, only sensor 0 and sensor 1 * are used in the calculations. Similarly when the last sensor has the * highest response, only the last sensor and the second last sensors * are used in the calculations. * * For i= idx_of_peak_Sensor-1 to i= idx_of_peak_Sensor+1 * v += Sensor response(i)*i * w += Sensor response(i) * POS=(Number_of_Positions_Wanted/(Number_of_Sensors_Used-1)) *(v/w)
*/ staticvoid ad714x_slider_cal_abs_pos(struct ad714x_chip *ad714x, int idx)
{ struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx]; struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx];
/* * To minimise the Impact of the noise on the algorithm, ADI developed a * routine that filters the CDC results after they have been read by the * host processor. * The filter used is an Infinite Input Response(IIR) filter implemented * in firmware and attenuates the noise on the CDC results after they've * been read by the host processor. * Filtered_CDC_result = (Filtered_CDC_result * (10 - Coefficient) + * Latest_CDC_result * Coefficient)/10
*/ staticvoid ad714x_slider_cal_flt_pos(struct ad714x_chip *ad714x, int idx)
{ struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx];
case ACTIVE: if (c_state == mask) { if (h_state) {
ad714x_slider_cal_sensor_val(ad714x, idx);
ad714x_slider_cal_highest_stage(ad714x, idx);
ad714x_slider_cal_abs_pos(ad714x, idx);
ad714x_slider_cal_flt_pos(ad714x, idx);
input_report_abs(sw->input, ABS_X, sw->flt_pos);
input_report_key(sw->input, BTN_TOUCH, 1);
} else { /* When the user lifts off the sensor, configure * the AD714X back to threshold interrupt mode.
*/
ad714x_slider_use_thr_int(ad714x, idx);
sw->state = IDLE;
input_report_key(sw->input, BTN_TOUCH, 0);
dev_dbg(ad714x->dev, "slider %d released\n",
idx);
}
input_sync(sw->input);
} break;
default: break;
}
}
/* * When the scroll wheel is activated, we compute the absolute position based * on the sensor values. To calculate the position, we first determine the * sensor that has the greatest response among the 8 sensors that constitutes * the scrollwheel. Then we determined the 2 sensors on either sides of the * sensor with the highest response and we apply weights to these sensors.
*/ staticvoid ad714x_wheel_cal_highest_stage(struct ad714x_chip *ad714x, int idx)
{ struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
for (i = hw->start_stage; i <= hw->end_stage; i++) {
ad714x->read(ad714x, STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
&ad714x->amb_reg[i], 1); if (ad714x->adc_reg[i] > ad714x->amb_reg[i])
ad714x->sensor_val[i] =
ad714x->adc_reg[i] - ad714x->amb_reg[i]; else
ad714x->sensor_val[i] = 0;
}
}
/* * When the scroll wheel is activated, we compute the absolute position based * on the sensor values. To calculate the position, we first determine the * sensor that has the greatest response among the sensors that constitutes * the scrollwheel. Then we determined the sensors on either sides of the * sensor with the highest response and we apply weights to these sensors. The * result of this computation gives us the mean value.
*/
staticvoid ad714x_wheel_cal_abs_pos(struct ad714x_chip *ad714x, int idx)
{ struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx]; int stage_num = hw->end_stage - hw->start_stage + 1; int first_before, highest, first_after; int a_param, b_param;
case ACTIVE: if (c_state == mask) { if (h_state) {
ad714x_wheel_cal_sensor_val(ad714x, idx);
ad714x_wheel_cal_highest_stage(ad714x, idx);
ad714x_wheel_cal_abs_pos(ad714x, idx);
ad714x_wheel_cal_flt_pos(ad714x, idx);
input_report_abs(sw->input, ABS_WHEEL,
sw->flt_pos);
input_report_key(sw->input, BTN_TOUCH, 1);
} else { /* When the user lifts off the sensor, configure * the AD714X back to threshold interrupt mode.
*/
ad714x_wheel_use_thr_int(ad714x, idx);
sw->state = IDLE;
input_report_key(sw->input, BTN_TOUCH, 0);
/* * If 2 fingers are touching the sensor then 2 peaks can be observed in the * distribution. * The arithmetic doesn't support to get absolute coordinates for multi-touch * yet.
*/ staticint touchpad_check_second_peak(struct ad714x_chip *ad714x, int idx)
{ struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx]; int i;
for (i = hw->x_start_stage; i < sw->x_highest_stage; i++) { if ((ad714x->sensor_val[i] - ad714x->sensor_val[i + 1])
> (ad714x->sensor_val[i + 1] / 10)) return 1;
}
for (i = sw->x_highest_stage; i < hw->x_end_stage; i++) { if ((ad714x->sensor_val[i + 1] - ad714x->sensor_val[i])
> (ad714x->sensor_val[i] / 10)) return 1;
}
for (i = hw->y_start_stage; i < sw->y_highest_stage; i++) { if ((ad714x->sensor_val[i] - ad714x->sensor_val[i + 1])
> (ad714x->sensor_val[i + 1] / 10)) return 1;
}
for (i = sw->y_highest_stage; i < hw->y_end_stage; i++) { if ((ad714x->sensor_val[i + 1] - ad714x->sensor_val[i])
> (ad714x->sensor_val[i] / 10)) return 1;
}
return 0;
}
/* * If only one finger is used to activate the touch pad then only 1 peak will be * registered in the distribution. This peak and the 2 adjacent sensors will be * used in the calculation of the absolute position. This will prevent hand * shadows to affect the absolute position calculation.
*/ staticvoid touchpad_cal_abs_pos(struct ad714x_chip *ad714x, int idx)
{ struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx];
/* * To prevent distortion from showing in the absolute position, it is * necessary to detect the end points. When endpoints are detected, the * driver stops updating the status variables with absolute positions. * End points are detected on the 4 edges of the touchpad sensor. The * method to detect them is the same for all 4. * To detect the end points, the firmware computes the difference in * percent between the sensor on the edge and the adjacent one. The * difference is calculated in percent in order to make the end point * detection independent of the pressure.
*/
case AD7143_PARTID:
ad714x->product = 0x7143;
ad714x->version = data & 0xF;
dev_info(ad714x->dev, "found AD7143 captouch, rev:%d\n",
ad714x->version); return 0;
case AD7147_PARTID:
ad714x->product = 0x7147;
ad714x->version = data & 0xF;
dev_info(ad714x->dev, "found AD7147(A) captouch, rev:%d\n",
ad714x->version); return 0;
case AD7148_PARTID:
ad714x->product = 0x7148;
ad714x->version = data & 0xF;
dev_info(ad714x->dev, "found AD7148 captouch, rev:%d\n",
ad714x->version); return 0;
default:
dev_err(ad714x->dev, "fail to detect AD714X captouch, read ID is %04x\n",
data); return -ENODEV;
}
}
staticvoid ad714x_hw_init(struct ad714x_chip *ad714x)
{ int i, j; unsignedshort reg_base; unsignedshort data;
/* configuration CDC and interrupts */
for (i = 0; i < STAGE_NUM; i++) {
reg_base = AD714X_STAGECFG_REG + i * STAGE_CFGREG_NUM; for (j = 0; j < STAGE_CFGREG_NUM; j++)
ad714x->write(ad714x, reg_base + j,
ad714x->hw->stage_cfg_reg[i][j]);
}
for (i = 0; i < SYS_CFGREG_NUM; i++)
ad714x->write(ad714x, AD714X_SYSCFG_REG + i,
ad714x->hw->sys_cfg_reg[i]); for (i = 0; i < SYS_CFGREG_NUM; i++)
ad714x->read(ad714x, AD714X_SYSCFG_REG + i, &data, 1);
for (i = 0; i < ad714x->hw->button_num; i++)
ad714x_button_state_machine(ad714x, i); for (i = 0; i < ad714x->hw->slider_num; i++)
ad714x_slider_state_machine(ad714x, i); for (i = 0; i < ad714x->hw->wheel_num; i++)
ad714x_wheel_state_machine(ad714x, i); for (i = 0; i < ad714x->hw->touchpad_num; i++)
ad714x_touchpad_state_machine(ad714x, i);
return IRQ_HANDLED;
}
struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
ad714x_read_t read, ad714x_write_t write)
{ int i; int error; struct input_dev *input;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.