summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnshul Jain <anshulj@nvidia.com>2013-06-14 18:10:31 -0700
committerMandar Padmawar <mpadmawar@nvidia.com>2013-06-17 02:39:53 -0700
commitbe97c59c55b9bf547cf0030a7dc469319bd8de94 (patch)
tree25105cd0623e19fb073fa6bd714143abdd9b73e2
parent775f7c0f628c42e6fefd43e4990cf809d80c76c2 (diff)
drivers:misc:issp: Reset Device on USB resume fail
This is a WAR to reset the USB device if the device fails to resume. We assume that the resume failure is because of the uC hang. Signed-off-by: Anshul Jain <anshulj@nvidia.com> Change-Id: I6fc85cd0ce2fad7a7dbff5b6ddee0a96149a5d76 Reviewed-on: http://git-master/r/239086 GVS: Gerrit_Virtual_Submit Reviewed-by: Tao Xie <txie@nvidia.com> Tested-by: Tao Xie <txie@nvidia.com> Reviewed-by: Ankit Pashiney <apashiney@nvidia.com>
-rw-r--r--drivers/misc/issp/issp.c8
-rw-r--r--drivers/misc/issp/issp_steps.c18
-rw-r--r--drivers/usb/core/hub.c27
-rw-r--r--drivers/usb/core/quirks.c3
-rw-r--r--include/linux/usb/quirks.h4
5 files changed, 57 insertions, 3 deletions
diff --git a/drivers/misc/issp/issp.c b/drivers/misc/issp/issp.c
index 05ed51684993..083a22b0c681 100644
--- a/drivers/misc/issp/issp.c
+++ b/drivers/misc/issp/issp.c
@@ -128,6 +128,8 @@ static int issp_need_update(struct issp_host *host, bool *update)
return 0;
}
+struct issp_host *g_issp_host;
+
static int __init issp_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -162,6 +164,7 @@ static int __init issp_probe(struct platform_device *pdev)
host->pdev = pdev;
host->pdata = pdata;
+ g_issp_host = host;
ret = request_ihex_firmware(&host->fw, pdata->fw_name, dev);
if (ret) {
dev_err(dev, "Request firmware %s failed!\n", pdata->fw_name);
@@ -197,6 +200,10 @@ static int __init issp_probe(struct platform_device *pdev)
err_id:
issp_uc_run(host);
+ gpio_direction_input(pdata->data_gpio);
+ gpio_direction_input(pdata->clk_gpio);
+ release_firmware(host->fw);
+ return 0;
err:
gpio_direction_input(pdata->data_gpio);
@@ -209,6 +216,7 @@ err:
static int __exit issp_remove(struct platform_device *pdev)
{
+ g_issp_host = NULL;
return 0;
}
diff --git a/drivers/misc/issp/issp_steps.c b/drivers/misc/issp/issp_steps.c
index d552e9187c29..f666b59ed7a7 100644
--- a/drivers/misc/issp/issp_steps.c
+++ b/drivers/misc/issp/issp_steps.c
@@ -652,6 +652,24 @@ static int issp_verify_checksum(struct issp_host *host)
}
/* global functions */
+extern struct issp_host *g_issp_host;
+
+void issp_uc_reset(void)
+{
+ struct issp_host *host = g_issp_host;
+
+ if (!host) {
+ pr_err("%s: !host\n", __func__);
+ return;
+ }
+
+ /* reset */
+ usleep_range(ISSP_RESET_ASSERT_DELAY, ISSP_RESET_ASSERT_DELAY);
+ pin_reset_lo(host);
+ udelay(ISSP_RESET_PULSE_LENGTH);
+ pin_reset_hi(host);
+ udelay(ISSP_RESET_POST_DELAY);
+}
int issp_uc_program(struct issp_host *host)
{
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index e727b876726c..b1b0fe41e07b 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2569,6 +2569,17 @@ static int finish_port_resume(struct usb_device *udev)
retry_reset_resume:
status = usb_reset_and_verify_device(udev);
+/* For testing reset on every resume */
+#if 0
+ if (udev->quirks & USB_QUIRK_RESET_DEVICE_ON_RESUME_FAIL) {
+ extern void issp_uc_reset(void);
+ dev_err(&udev->dev, "USB_QUIRK_RESET_DEVICE_ON_RESUME_FAIL\n");
+ issp_uc_reset();
+ /* device is gone after we reset it */
+ status = -ENODEV;
+ }
+#endif
+
/* 10.5.4.5 says be sure devices in the tree are still there.
* For now let's assume the device didn't go crazy on resume,
* and device drivers will know about any resume quirks.
@@ -2581,9 +2592,19 @@ static int finish_port_resume(struct usb_device *udev)
/* If a normal resume failed, try doing a reset-resume */
if (status && !udev->reset_resume && udev->persist_enabled) {
- dev_dbg(&udev->dev, "retry with reset-resume\n");
- udev->reset_resume = 1;
- goto retry_reset_resume;
+ dev_err(&udev->dev, "retry with reset-resume\n");
+ if (udev->quirks &
+ USB_QUIRK_RESET_DEVICE_ON_RESUME_FAIL) {
+ extern void issp_uc_reset(void);
+ dev_err(&udev->dev,
+ "USB_QUIRK_RESET_DEVICE_ON_RESUME_FAIL\n");
+ issp_uc_reset();
+ /* device is gone after we reset it */
+ status = -ENODEV;
+ } else {
+ udev->reset_resume = 1;
+ goto retry_reset_resume;
+ }
}
}
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 32d3adc315f5..ef3275bd24e5 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -28,6 +28,9 @@
* devices is broken...
*/
static const struct usb_device_id usb_quirk_list[] = {
+ /* Nvidia JS*/
+ { USB_DEVICE(0x0955, 0x7203), .driver_info = USB_QUIRK_RESET_DEVICE_ON_RESUME_FAIL },
+
/* CBM - Flash disk */
{ USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME },
diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h
index 3e93de7ecbc3..9f338a69ddf1 100644
--- a/include/linux/usb/quirks.h
+++ b/include/linux/usb/quirks.h
@@ -30,4 +30,8 @@
descriptor */
#define USB_QUIRK_DELAY_INIT 0x00000040
+/* reset device if bus resume fails - assume that resume failure is
+ due to usb device crash */
+#define USB_QUIRK_RESET_DEVICE_ON_RESUME_FAIL 0x00000100
+
#endif /* __LINUX_USB_QUIRKS_H */