in touchscreen/rohm_bu21023.c [313:514]
static int rohm_ts_manual_calibration(struct rohm_ts_data *ts)
{
struct i2c_client *client = ts->client;
struct device *dev = &client->dev;
u8 buf[33]; /* for PRM1_X_H(0x08)-TOUCH(0x28) */
int retry;
bool success = false;
bool first_time = true;
bool calibration_done;
u8 reg1, reg2, reg3;
s32 reg1_orig, reg2_orig, reg3_orig;
s32 val;
int calib_x = 0, calib_y = 0;
int reg_x, reg_y;
int err_x, err_y;
int error, error2;
int i;
reg1_orig = i2c_smbus_read_byte_data(client, CALIBRATION_REG1);
if (reg1_orig < 0)
return reg1_orig;
reg2_orig = i2c_smbus_read_byte_data(client, CALIBRATION_REG2);
if (reg2_orig < 0)
return reg2_orig;
reg3_orig = i2c_smbus_read_byte_data(client, CALIBRATION_REG3);
if (reg3_orig < 0)
return reg3_orig;
error = i2c_smbus_write_byte_data(client, INT_MASK,
COORD_UPDATE | SLEEP_IN | SLEEP_OUT |
PROGRAM_LOAD_DONE);
if (error)
goto out;
error = i2c_smbus_write_byte_data(client, TEST1,
DUALTOUCH_STABILIZE_ON);
if (error)
goto out;
for (retry = 0; retry < CALIBRATION_RETRY_MAX; retry++) {
/* wait 2 sampling for update */
mdelay(2 * SAMPLING_DELAY);
#define READ_CALIB_BUF(reg) buf[((reg) - PRM1_X_H)]
error = rohm_i2c_burst_read(client, PRM1_X_H, buf, sizeof(buf));
if (error)
goto out;
if (READ_CALIB_BUF(TOUCH) & TOUCH_DETECT)
continue;
if (first_time) {
/* generate calibration parameter */
calib_x = ((int)READ_CALIB_BUF(PRM1_X_H) << 2 |
READ_CALIB_BUF(PRM1_X_L)) - AXIS_OFFSET;
calib_y = ((int)READ_CALIB_BUF(PRM1_Y_H) << 2 |
READ_CALIB_BUF(PRM1_Y_L)) - AXIS_OFFSET;
error = i2c_smbus_write_byte_data(client, TEST1,
DUALTOUCH_STABILIZE_ON | DUALTOUCH_REG_ON);
if (error)
goto out;
first_time = false;
} else {
/* generate adjustment parameter */
err_x = (int)READ_CALIB_BUF(PRM1_X_H) << 2 |
READ_CALIB_BUF(PRM1_X_L);
err_y = (int)READ_CALIB_BUF(PRM1_Y_H) << 2 |
READ_CALIB_BUF(PRM1_Y_L);
/* X axis ajust */
if (err_x <= 4)
calib_x -= AXIS_ADJUST;
else if (err_x >= 60)
calib_x += AXIS_ADJUST;
/* Y axis ajust */
if (err_y <= 4)
calib_y -= AXIS_ADJUST;
else if (err_y >= 60)
calib_y += AXIS_ADJUST;
}
/* generate calibration setting value */
reg_x = calib_x + ((calib_x & 0x200) << 1);
reg_y = calib_y + ((calib_y & 0x200) << 1);
/* convert for register format */
reg1 = reg_x >> 3;
reg2 = (reg_y & 0x7) << 4 | (reg_x & 0x7);
reg3 = reg_y >> 3;
error = i2c_smbus_write_byte_data(client,
CALIBRATION_REG1, reg1);
if (error)
goto out;
error = i2c_smbus_write_byte_data(client,
CALIBRATION_REG2, reg2);
if (error)
goto out;
error = i2c_smbus_write_byte_data(client,
CALIBRATION_REG3, reg3);
if (error)
goto out;
/*
* force calibration sequcence
*/
error = i2c_smbus_write_byte_data(client, FORCE_CALIBRATION,
FORCE_CALIBRATION_OFF);
if (error)
goto out;
error = i2c_smbus_write_byte_data(client, FORCE_CALIBRATION,
FORCE_CALIBRATION_ON);
if (error)
goto out;
/* clear all interrupts */
error = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff);
if (error)
goto out;
/*
* Wait for the status change of calibration, max 10 sampling
*/
calibration_done = false;
for (i = 0; i < 10; i++) {
mdelay(SAMPLING_DELAY);
val = i2c_smbus_read_byte_data(client, TOUCH_GESTURE);
if (!(val & CALIBRATION_MASK)) {
calibration_done = true;
break;
} else if (val < 0) {
error = val;
goto out;
}
}
if (calibration_done) {
val = i2c_smbus_read_byte_data(client, INT_STATUS);
if (val == CALIBRATION_DONE) {
success = true;
break;
} else if (val < 0) {
error = val;
goto out;
}
} else {
dev_warn(dev, "calibration timeout\n");
}
}
if (!success) {
error = i2c_smbus_write_byte_data(client, CALIBRATION_REG1,
reg1_orig);
if (error)
goto out;
error = i2c_smbus_write_byte_data(client, CALIBRATION_REG2,
reg2_orig);
if (error)
goto out;
error = i2c_smbus_write_byte_data(client, CALIBRATION_REG3,
reg3_orig);
if (error)
goto out;
/* calibration data enable */
error = i2c_smbus_write_byte_data(client, TEST1,
DUALTOUCH_STABILIZE_ON |
DUALTOUCH_REG_ON);
if (error)
goto out;
/* wait 10 sampling */
mdelay(10 * SAMPLING_DELAY);
error = -EBUSY;
}
out:
error2 = i2c_smbus_write_byte_data(client, INT_MASK, INT_ALL);
if (!error2)
/* Clear all interrupts */
error2 = i2c_smbus_write_byte_data(client, INT_CLEAR, 0xff);
return error ? error : error2;
}