diff options
Diffstat (limited to 'drivers/input/touchscreen/atmel_mxt_ts.c')
| -rw-r--r-- | drivers/input/touchscreen/atmel_mxt_ts.c | 188 | 
1 files changed, 102 insertions, 86 deletions
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 85672e0233e..7a4ed198d7e 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -255,6 +255,8 @@ struct mxt_flash {  	size_t frame_size;  	unsigned int count;  	unsigned int retry; +	u8 previous; +	bool complete;  };  /* Each client has this additional data */ @@ -648,67 +650,127 @@ static int mxt_probe_bootloader(struct mxt_data *data, bool alt_address)  	return 0;  } -static int mxt_check_bootloader(struct mxt_data *data, unsigned int state, -				bool wait) +static int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock); + +static int mxt_write_firmware_frame(struct mxt_data *data, struct mxt_flash *f) +{ +	f->frame = (struct mxt_fw_frame*)(f->fw->data + f->pos); + +	/* Take account of CRC bytes */ +	f->frame_size = __be16_to_cpu(f->frame->size) + 2U; + +	/* Write one frame to device */ +	return mxt_bootloader_write(data, f->fw->data + f->pos, +				   f->frame_size); +} + +static int mxt_check_bootloader(struct mxt_data *data, struct mxt_flash *f)  {  	struct device *dev = &data->client->dev; -	u8 val; +	u8 state;  	int ret; -recheck: -	if (wait) { +	/* +	 * In application update mode, the interrupt +	 * line signals state transitions. We must wait for the +	 * CHG assertion before reading the status byte. +	 * Once the status byte has been read, the line is deasserted. +	 */ +	ret = mxt_wait_for_completion(data, &data->bl_completion, +				      MXT_FW_CHG_TIMEOUT); +	if (ret) {  		/* -		 * In application update mode, the interrupt -		 * line signals state transitions. We must wait for the -		 * CHG assertion before reading the status byte. -		 * Once the status byte has been read, the line is deasserted. +		 * TODO: handle -ERESTARTSYS better by terminating +		 * fw update process before returning to userspace +		 * by writing length 0x000 to device (iff we are in +		 * WAITING_FRAME_DATA state).  		 */ -		ret = mxt_wait_for_completion(data, &data->bl_completion, -					      MXT_FW_CHG_TIMEOUT); -		if (ret) { -			/* -			 * TODO: handle -ERESTARTSYS better by terminating -			 * fw update process before returning to userspace -			 * by writing length 0x000 to device (iff we are in -			 * WAITING_FRAME_DATA state). -			 */ -			dev_err(dev, "Update wait error %d\n", ret); -			return ret; -		} +		dev_warn(dev, "Update wait error %d\n", ret);  	} -	ret = mxt_bootloader_read(data, &val, 1); +	ret = mxt_bootloader_read(data, &state, 1);  	if (ret)  		return ret; +	/* Remove don't care bits */ +	if (state & ~MXT_BOOT_STATUS_MASK) +		state &= ~MXT_BOOT_STATUS_MASK; +  	switch (state) {  	case MXT_WAITING_BOOTLOAD_CMD: +		dev_info(dev, "Unlocking bootloader\n"); +		ret = mxt_send_bootloader_cmd(data, true); +		if (ret) +			return ret; + +		break; +  	case MXT_WAITING_FRAME_DATA: -	case MXT_APP_CRC_FAIL: -		val &= ~MXT_BOOT_STATUS_MASK; +		if ((f->previous != MXT_WAITING_BOOTLOAD_CMD) +		    && (f->previous != MXT_FRAME_CRC_PASS) +		    && (f->previous != MXT_FRAME_CRC_FAIL)) +			goto unexpected; + +		ret = mxt_write_firmware_frame(data, f); +		if (ret) +			return ret; +  		break; + +	case MXT_FRAME_CRC_CHECK: +		if (f->previous != MXT_WAITING_FRAME_DATA) +			goto unexpected; +		break; +  	case MXT_FRAME_CRC_PASS: -		if (val == MXT_FRAME_CRC_CHECK) { -			goto recheck; -		} else if (val == MXT_FRAME_CRC_FAIL) { -			dev_err(dev, "Bootloader CRC fail\n"); -			return -EINVAL; +		if (f->previous != MXT_FRAME_CRC_CHECK) +			goto unexpected; + +		/* Next frame */ +		f->retry = 0; +		f->pos += f->frame_size; +		f->count++; + +		if (f->pos >= f->fw->size) { +			f->complete = true; +			dev_info(dev, "Sent %u frames, %zu bytes\n", +				f->count, f->fw->size); +		} else if (f->count % 50 == 0) { +			dev_dbg(dev, "Sent %u frames, %lld/%zu bytes\n", +				f->count, f->pos, f->fw->size);  		} +  		break; + +	case MXT_FRAME_CRC_FAIL: +		f->retry++; + +		if (f->retry > 20) { +			dev_err(dev, "Retry count exceeded\n"); +			return -EIO; +		} else { +			dev_dbg(dev, "Bootloader frame CRC failure\n"); +		} + +		/* Back off by 20ms per retry */ +		msleep(f->retry * 20); + +		break; +  	default:  		return -EINVAL;  	} -	if (val != state) { -		dev_err(dev, "Invalid bootloader state %02X != %02X\n", -			val, state); -		return -EINVAL; -	} +	f->previous = state;  	return 0; + +unexpected: +	dev_err(dev, "Unexpected state transition\n"); +	return -EINVAL;  } -static int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock) +int mxt_send_bootloader_cmd(struct mxt_data *data, bool unlock)  {  	int ret;  	u8 buf[2]; @@ -2950,57 +3012,13 @@ static int mxt_load_fw(struct device *dev)  	if (ret)  		goto release_firmware; -	ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD, false); -	if (ret) { -		/* Bootloader may still be unlocked from previous attempt */ -		ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, false); -		if (ret) -			goto disable_irq; -	} else { -		dev_info(dev, "Unlocking bootloader\n"); - -		/* Unlock bootloader */ -		ret = mxt_send_bootloader_cmd(data, true); +	while (true) { +		ret = mxt_check_bootloader(data, &f);  		if (ret) -			goto disable_irq; -	} - -	while (f.pos < f.fw->size) { -		f.frame = (struct mxt_fw_frame*)(f.fw->data + f.pos); - -		ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, true); -		if (ret) -			goto disable_irq; - -		/* Take account of CRC bytes */ -		f.frame_size = __be16_to_cpu(f.frame->size) + 2U; - -		/* Write one frame to device */ -		ret = mxt_bootloader_write(data, f.fw->data + f.pos, -					   f.frame_size); -		if (ret) -			goto disable_irq; - -		ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS, true); -		if (ret) { -			f.retry++; - -			/* Back off by 20ms per retry */ -			msleep(f.retry * 20); - -			if (f.retry > 20) { -				dev_err(dev, "Retry count exceeded\n"); -				goto disable_irq; -			} -		} else { -			f.retry = 0; -			f.pos += f.frame_size; -			f.count++; -		} +			return ret; -		if (f.count % 50 == 0) -			dev_dbg(dev, "Sent %u frames, %lld/%zu bytes\n", -				f.count, f.pos, f.fw->size); +		if (f.complete) +			break;  	}  	/* Wait for flash. */ @@ -3009,7 +3027,6 @@ static int mxt_load_fw(struct device *dev)  	if (ret)  		goto disable_irq; -	dev_dbg(dev, "Sent %u frames, %lld bytes\n", f.count, f.pos);  	/*  	 * Wait for device to reset. Some bootloader versions do not assert @@ -3019,7 +3036,6 @@ static int mxt_load_fw(struct device *dev)  	mxt_wait_for_completion(data, &data->bl_completion, MXT_FW_RESET_TIME);  	data->in_bootloader = false; -  disable_irq:  	disable_irq(data->irq);  release_firmware:  |