diff options
Diffstat (limited to 'drivers/input/touchscreen/atmel_mxt_ts.c')
| -rw-r--r-- | drivers/input/touchscreen/atmel_mxt_ts.c | 117 | 
1 files changed, 58 insertions, 59 deletions
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index b55f5ed11f5..d63c7bb56de 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -28,6 +28,7 @@  #include <linux/slab.h>  #include <linux/regulator/consumer.h>  #include <linux/gpio.h> +#include <linux/workqueue.h>  #ifdef CONFIG_OF  #include <linux/of_gpio.h> @@ -200,6 +201,7 @@ enum t100_type {  #define MXT_REGULATOR_DELAY	150	/* msec */  #define MXT_CHG_DELAY	        100	/* msec */  #define MXT_POWERON_DELAY	150	/* msec */ +#define MXT_BOOTLOADER_WAIT	36E5	/* 1 minute */  /* Command to unlock bootloader */  #define MXT_UNLOCK_CMD_MSB	0xaa @@ -249,6 +251,7 @@ struct mxt_fw_frame {  /* Firmware update context */  struct mxt_flash { +	struct mxt_data *data;  	const struct firmware *fw;  	struct mxt_fw_frame *frame;  	loff_t pos; @@ -256,7 +259,8 @@ struct mxt_flash {  	unsigned int count;  	unsigned int retry;  	u8 previous; -	bool complete; +	struct completion flash_completion; +	struct delayed_work work;  };  /* Each client has this additional data */ @@ -302,6 +306,7 @@ struct mxt_data {  	struct regulator *reg_avdd;  	char *fw_name;  	char *cfg_name; +	struct mxt_flash *flash;  	/* Cached parameters from object table */  	u16 T5_address; @@ -664,28 +669,17 @@ static int mxt_write_firmware_frame(struct mxt_data *data, struct mxt_flash *f)  				   f->frame_size);  } -static int mxt_check_bootloader(struct mxt_data *data, struct mxt_flash *f) +static int mxt_check_bootloader(struct mxt_data *data)  {  	struct device *dev = &data->client->dev; +	struct mxt_flash *f = data->flash;  	u8 state;  	int 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. -	 */ -	ret = mxt_wait_for_completion(data, &data->chg_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_warn(dev, "Update wait error %d\n", ret); +	/* Handle interrupt after download/flash process */ +	if (f->pos >= f->fw->size) { +		complete(&f->flash_completion); +		return 0;  	}  	ret = mxt_bootloader_read(data, &state, 1); @@ -731,14 +725,12 @@ static int mxt_check_bootloader(struct mxt_data *data, struct mxt_flash *f)  		f->pos += f->frame_size;  		f->count++; -		if (f->pos >= f->fw->size) { -			f->complete = true; +		if (f->pos >= f->fw->size)  			dev_info(dev, "Sent %u frames, %zu bytes\n",  				f->count, f->fw->size); -		} else if (f->count % 50 == 0) { +		else if (f->count % 50 == 0)  			dev_dbg(dev, "Sent %u frames, %lld/%zu bytes\n",  				f->count, f->pos, f->fw->size); -		}  		break; @@ -763,6 +755,9 @@ static int mxt_check_bootloader(struct mxt_data *data, struct mxt_flash *f)  	f->previous = state; +	/* Poll after 0.1s if no interrupt received */ +	schedule_delayed_work(&f->work, HZ / 10); +  	return 0;  unexpected: @@ -1490,8 +1485,12 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id)  	complete(&data->chg_completion); -	if (data->in_bootloader) -		return IRQ_HANDLED; +	if (data->in_bootloader) { +		if (data->flash && &data->flash->work) +			cancel_delayed_work_sync(&data->flash->work); + +		return IRQ_RETVAL(mxt_check_bootloader(data)); +	}  	if (!data->object_table)  		return IRQ_HANDLED; @@ -2957,16 +2956,11 @@ static int mxt_enter_bootloader(struct mxt_data *data)  		if (data->pdata->suspend_mode == MXT_SUSPEND_REGULATOR)  			mxt_regulator_enable(data); -		if (data->pdata->suspend_mode == MXT_SUSPEND_DEEP_SLEEP) -			enable_irq(data->irq); -  		data->suspended = false;  	}  	if (!data->in_bootloader) {  		/* Change to the bootloader mode */ -		data->in_bootloader = true; -  		ret = mxt_t6_command(data, MXT_COMMAND_RESET,  				     MXT_BOOT_VALUE, false);  		if (ret) @@ -2979,66 +2973,71 @@ static int mxt_enter_bootloader(struct mxt_data *data)  		if (ret)  			return ret; +		data->in_bootloader = true;  		mxt_free_input_device(data);  		mxt_free_object_table(data); -	} else { -		enable_irq(data->irq);  	} -	INIT_COMPLETION(data->chg_completion); +	dev_dbg(&data->client->dev, "Entered bootloader\n");  	return 0;  } +static void mxt_fw_work(struct work_struct *work) +{ +	struct mxt_flash *f = +		container_of(work, struct mxt_flash, work.work); + +	mxt_check_bootloader(f->data); +} +  static int mxt_load_fw(struct device *dev)  {  	struct mxt_data *data = dev_get_drvdata(dev); -	struct mxt_flash f = { 0, };  	int ret; -	ret = request_firmware(&f.fw, data->fw_name, dev); +	data->flash = devm_kzalloc(dev, sizeof(struct mxt_flash), GFP_KERNEL); +	if (!data->flash) +		return -ENOMEM; + +	data->flash->data = data; + +	ret = request_firmware(&data->flash->fw, data->fw_name, dev);  	if (ret) {  		dev_err(dev, "Unable to open firmware %s\n", data->fw_name); -		return ret; +		goto free;  	}  	/* Check for incorrect enc file */ -	ret = mxt_check_firmware_format(dev, f.fw); +	ret = mxt_check_firmware_format(dev, data->flash->fw);  	if (ret)  		goto release_firmware; -	ret = mxt_enter_bootloader(data); -	if (ret) -		goto release_firmware; +	init_completion(&data->flash->flash_completion); +	INIT_DELAYED_WORK(&data->flash->work, mxt_fw_work); -	while (true) { -		ret = mxt_check_bootloader(data, &f); +	if (!data->in_bootloader) { +		ret = mxt_enter_bootloader(data);  		if (ret) -			return ret; - -		if (f.complete) -			break; +			goto release_firmware;  	} -	/* Wait for flash. */ -	ret = mxt_wait_for_completion(data, &data->chg_completion, -				      MXT_FW_RESET_TIME); -	if (ret) -		goto disable_irq; +	enable_irq(data->irq); +	/* Poll after 0.1s if no interrupt received */ +	schedule_delayed_work(&data->flash->work, HZ / 10); -	/* -	 * Wait for device to reset. Some bootloader versions do not assert -	 * the CHG line after bootloading has finished, so ignore potential -	 * errors. -	 */ -	mxt_wait_for_completion(data, &data->chg_completion, MXT_FW_RESET_TIME); +	/* Wait for flash. */ +	ret = mxt_wait_for_completion(data, &data->flash->flash_completion, +				      MXT_BOOTLOADER_WAIT); -	data->in_bootloader = false; -disable_irq:  	disable_irq(data->irq); +	cancel_delayed_work_sync(&data->flash->work); +	data->in_bootloader = false;  release_firmware: -	release_firmware(f.fw); +	release_firmware(data->flash->fw); +free: +	devm_kfree(dev, data->flash);  	return ret;  }  |