From: Benson Leung Date: Tue, 20 Nov 2012 07:16:54 +0000 (-0800) Subject: CHROMIUM: Input: cyapa - More reliable cyapa_get_state. X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=a1d28bd651e70f8175cce460c31b140eea4466b5;p=people%2Faperard%2Flinux-chromebook.git CHROMIUM: Input: cyapa - More reliable cyapa_get_state. In cyapa_get_state, add an additional check for OP_STATUS_SRC bit in REG_OP_STATUS. This bit should only be set when in operational mode. Under some conditions, the REG_OP_STATUS may return 0x89, with the device status bits being 0b01, indicating the operational mode firmware is busy executing a command from the host. Handle this status and return state CYAPA_STATE_OP if we are not in bootloader based on OP_STATUS_SRC. Signed-off-by: Benson Leung BUG=chrome-os-partner:16217 TEST=Test Lumpy (Samsung Series 5 550) and Snow (Samsung Chromebook ARM) using this driver. 1. Cold boot the system (power on the system from full on) 2. Warm reboot the system (reboot the system using command sudo reboot) Check that the touchpad is detected in both cases and is functional. 3. Force a firmware update and check that it succeeds. /opt/google/touchpad/firmware/chromeos_touch_firmwareupdate -d cyapa -f Furthermore, see crosbug.com/p/16217 for detailed repro steps. System with this patch should survive the suspend/resume test with a grounded metal probe touching the touchpad generating activity. suspend_stress_test --wake_min 0 --wake_max 0 --backup_rtc Change-Id: Ie2d513a3a868c6914776355222fad21935af88a5 Reviewed-on: https://gerrit.chromium.org/gerrit/38364 Reviewed-by: Daniel Kurtz Reviewed-by: Dudley Du Commit-Ready: Benson Leung Tested-by: Benson Leung --- diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index 1bd05dcc4721a..a05a4a17dcad5 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -177,6 +177,7 @@ * Other values indicate device is in an abnormal state and must be reset. */ #define CYAPA_DEV_NORMAL 0x03 +#define CYAPA_DEV_BUSY 0x01 enum cyapa_state { CYAPA_STATE_OP, @@ -578,32 +579,56 @@ static int cyapa_get_state(struct cyapa *cyapa) } if (ret != BL_STATUS_SIZE) - return (ret < 0) ? ret : -EAGAIN; + goto error; cyapa->status[REG_OP_STATUS] = status[REG_OP_STATUS]; cyapa->status[REG_BL_STATUS] = status[REG_BL_STATUS]; cyapa->status[REG_BL_ERROR] = status[REG_BL_ERROR]; - if ((status[REG_OP_STATUS] & OP_STATUS_DEV) == CYAPA_DEV_NORMAL) { - cyapa_dbg(cyapa, "device state: operational mode\n"); - cyapa->state = CYAPA_STATE_OP; - } else if (status[REG_BL_STATUS] & BL_STATUS_BUSY) { - cyapa_dbg(cyapa, "device state: bootloader busy\n"); - cyapa->state = CYAPA_STATE_BL_BUSY; - } else if (status[REG_BL_ERROR] & BL_ERROR_BOOTLOADING) { - cyapa_dbg(cyapa, "device state: bootloader active\n"); - cyapa->state = CYAPA_STATE_BL_ACTIVE; + if ((status[REG_OP_STATUS] & OP_STATUS_SRC) == OP_STATUS_SRC) { + switch (status[REG_OP_STATUS] & OP_STATUS_DEV) { + case CYAPA_DEV_NORMAL: + cyapa_dbg(cyapa, "device state: operational mode\n"); + cyapa->state = CYAPA_STATE_OP; + break; + case CYAPA_DEV_BUSY: + cyapa_dbg(cyapa, "device state: operational busy\n"); + cyapa->state = CYAPA_STATE_OP; + break; + default: + cyapa->debug = true; + cyapa_dbg(cyapa, "device state: unknown\n"); + cyapa_dbg(cyapa, "status[REG_OP_STATUS] = 0x%02x\n", + status[REG_OP_STATUS]); + cyapa_dbg(cyapa, "status[REG_BL_STATUS] = 0x%02x\n", + status[REG_BL_STATUS]); + cyapa_dbg(cyapa, "status[REG_BL_ERROR] = 0x%02x\n", + status[REG_BL_ERROR]); + cyapa->state = CYAPA_STATE_NO_DEVICE; + ret = -EAGAIN; + goto error; + } } else { - cyapa_dbg(cyapa, "device state: bootloader idle\n"); - cyapa_dbg(cyapa, "status[REG_OP_STATUS] = 0x%02x\n", - status[REG_OP_STATUS]); - cyapa_dbg(cyapa, "status[REG_BL_STATUS] = 0x%02x\n", - status[REG_BL_STATUS]); - cyapa_dbg(cyapa, "status[REG_BL_ERROR] = 0x%02x\n", - status[REG_BL_ERROR]); - cyapa->state = CYAPA_STATE_BL_IDLE; + if (status[REG_BL_STATUS] & BL_STATUS_BUSY) { + cyapa_dbg(cyapa, "device state: bootloader busy\n"); + cyapa->state = CYAPA_STATE_BL_BUSY; + } else if (status[REG_BL_ERROR] & BL_ERROR_BOOTLOADING) { + cyapa_dbg(cyapa, "device state: bootloader active\n"); + cyapa->state = CYAPA_STATE_BL_ACTIVE; + } else { + cyapa_dbg(cyapa, "device state: bootloader idle\n"); + cyapa_dbg(cyapa, "status[REG_OP_STATUS] = 0x%02x\n", + status[REG_OP_STATUS]); + cyapa_dbg(cyapa, "status[REG_BL_STATUS] = 0x%02x\n", + status[REG_BL_STATUS]); + cyapa_dbg(cyapa, "status[REG_BL_ERROR] = 0x%02x\n", + status[REG_BL_ERROR]); + cyapa->state = CYAPA_STATE_BL_IDLE; + } } return 0; +error: + return (ret < 0) ? ret : -EAGAIN; } /*