From: lyz Date: Mon, 2 Mar 2015 03:23:43 +0000 (+0800) Subject: usb: can be wakeup by linestate change interrupt from GRF X-Git-Tag: firefly_0821_release~4263^2~21 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=77206fd74a8f1c694c5268284bdc5bf490209634;p=firefly-linux-kernel-4.4.55.git usb: can be wakeup by linestate change interrupt from GRF --- diff --git a/arch/arm/boot/dts/rk312x.dtsi b/arch/arm/boot/dts/rk312x.dtsi index ea52b54ff41f..4e0bc5ae0d2f 100755 --- a/arch/arm/boot/dts/rk312x.dtsi +++ b/arch/arm/boot/dts/rk312x.dtsi @@ -669,8 +669,12 @@ dwc_control_usb: dwc-control-usb@20008000 { compatible = "rockchip,rk3126-dwc-control-usb"; reg = <0x20008000 0x4>; - interrupts = ; - interrupt-names = "otg_bvalid"; + interrupts = , + , + ; + interrupt-names = "otg_bvalid", + "otg0_linestate", + "otg1_linestate"; clocks = <&clk_gates9 13>; clock-names = "hclk_usb_peri"; rockchip,remote_wakeup; diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index ada164e1b3a1..0463968b8a31 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -1183,6 +1183,7 @@ static int usbhid_start(struct hid_device *hid) usbhid_set_leds(hid); device_set_wakeup_enable(&dev->dev, 1); } + device_set_wakeup_enable(&dev->dev, 1); return 0; fail: diff --git a/drivers/usb/dwc_otg_310/dwc_otg_driver.c b/drivers/usb/dwc_otg_310/dwc_otg_driver.c index 21b05a8eeb42..69f212720015 100755 --- a/drivers/usb/dwc_otg_310/dwc_otg_driver.c +++ b/drivers/usb/dwc_otg_310/dwc_otg_driver.c @@ -1597,11 +1597,7 @@ void rk_usb_power_up(void) struct dwc_otg_platform_data *pldata_otg; struct dwc_otg_platform_data *pldata_host; struct rkehci_platform_data *pldata_ehci; - if (cpu_is_rk312x()) { - pldata_otg = &usb20otg_pdata_rk3126; - if (usb_to_uart_status) - pldata_otg->dwc_otg_uart_mode(pldata_otg, PHY_UART_MODE); - } + if (cpu_is_rk3288()) { #ifdef CONFIG_RK_USB_UART /* enable USB bypass UART function */ @@ -1638,6 +1634,15 @@ void rk_usb_power_up(void) } #endif + } else { + dwc_otg_device_t *otg_dev = g_otgdev; + + if (!otg_dev) + return; + + pldata_otg = otg_dev->pldata; + if (pldata_otg && pldata_otg->phy_power_down) + pldata_otg->phy_power_down(PHY_POWER_UP); } } @@ -1647,11 +1652,6 @@ void rk_usb_power_down(void) struct dwc_otg_platform_data *pldata_host; struct rkehci_platform_data *pldata_ehci; - if (cpu_is_rk312x()) { - pldata_otg = &usb20otg_pdata_rk3126; - usb_to_uart_status = pldata_otg->get_status(USB_STATUS_UARTMODE); - pldata_otg->dwc_otg_uart_mode(pldata_otg, PHY_USB_MODE); - } if (cpu_is_rk3288()) { #ifdef CONFIG_RK_USB_UART /* disable USB bypass UART function */ @@ -1695,6 +1695,15 @@ void rk_usb_power_down(void) RK3288_GRF_UOC1_CON0); } #endif + } else { + dwc_otg_device_t *otg_dev = g_otgdev; + + if (!otg_dev) + return; + + pldata_otg = otg_dev->pldata; + if (pldata_otg && pldata_otg->phy_power_down) + pldata_otg->phy_power_down(PHY_POWER_DOWN); } } diff --git a/drivers/usb/dwc_otg_310/usbdev_rk.h b/drivers/usb/dwc_otg_310/usbdev_rk.h index 16ef6d78c54b..32c88addbf3b 100755 --- a/drivers/usb/dwc_otg_310/usbdev_rk.h +++ b/drivers/usb/dwc_otg_310/usbdev_rk.h @@ -34,6 +34,9 @@ #define PHY_USB_MODE (0) #define PHY_UART_MODE (1) +#define PHY_POWER_DOWN (0) +#define PHY_POWER_UP (1) + #define USB_STATUS_BVABLID (1) #define USB_STATUS_DPDM (2) #define USB_STATUS_ID (3) @@ -89,6 +92,7 @@ struct dwc_otg_platform_data { void (*dwc_otg_uart_mode) (void *pdata, int enter_usb_uart_mode); void (*bc_detect_cb) (int bc_type); int (*get_status) (int id); + void (*phy_power_down)(int power_down); }; struct rkehci_platform_data { @@ -128,6 +132,7 @@ struct dwc_otg_control_usb { struct wake_lock usb_wakelock; int remote_wakeup; int usb_irq_wakeup; + int linestate_wakeup; int chip_id; }; diff --git a/drivers/usb/dwc_otg_310/usbdev_rk3126.c b/drivers/usb/dwc_otg_310/usbdev_rk3126.c index d71e8c3f7134..eaeca4324c52 100755 --- a/drivers/usb/dwc_otg_310/usbdev_rk3126.c +++ b/drivers/usb/dwc_otg_310/usbdev_rk3126.c @@ -23,9 +23,10 @@ static void usb20otg_hw_init(void) static void usb20otg_phy_suspend(void *pdata, int suspend) { struct dwc_otg_platform_data *usbpdata = pdata; + if (suspend) { /* enable soft control */ - writel(UOC_HIWORD_UPDATE(0x55, 0x7f, 0), + writel(UOC_HIWORD_UPDATE(0x1d1, 0x1ff, 0), RK_GRF_VIRT + RK312X_GRF_UOC0_CON0); usbpdata->phy_status = 1; } else { @@ -198,7 +199,21 @@ static void usb20otg_power_enable(int enable) gpio_set_value(control_usb->otg_gpios->gpio, 1); } } - +static void usb20otg_phy_power_down(int power_down) +{ + if (power_down == PHY_POWER_DOWN) { + if (control_usb->linestate_wakeup) { + /* enable otg0_linestate irq */ + writel(UOC_HIWORD_UPDATE(0x3, 0x3, 14), + RK_GRF_VIRT + RK312X_GRF_UOC1_CON5); + /* enable otg1_linestate irq */ + writel(UOC_HIWORD_UPDATE(0x3, 0x3, 12), + RK_GRF_VIRT + RK312X_GRF_UOC0_CON0); + } + } else if (power_down == PHY_POWER_UP) { + ; + } +} struct dwc_otg_platform_data usb20otg_pdata_rk3126 = { .phyclk = NULL, .ahbclk = NULL, @@ -213,6 +228,7 @@ struct dwc_otg_platform_data usb20otg_pdata_rk3126 = { .power_enable = usb20otg_power_enable, .dwc_otg_uart_mode = dwc_otg_uart_mode, .bc_detect_cb = rk_battery_charger_detect_cb, + .phy_power_down = usb20otg_phy_power_down, }; #endif @@ -540,6 +556,53 @@ static irqreturn_t bvalid_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } +/********** Handler for linestate irq **********/ +static irqreturn_t otg0_linestate_irq_handler(int irq, void *dev_id) +{ + /* + * Here is a chip hwrdware bug, when disable/enable + * linestate irq bit the state machine will not reset + * So here have to add a delay to wait the linestate filter + * timer run out (linestate filter time had been set to 100us) + */ + udelay(200); + + /* clear and disable irq */ + writel(UOC_HIWORD_UPDATE(0x2, 0x3, 12), + RK_GRF_VIRT + RK312X_GRF_UOC0_CON0); + + + if (control_usb->usb_irq_wakeup) { + wake_lock_timeout(&control_usb->usb_wakelock, + WAKE_LOCK_TIMEOUT); + } + + return IRQ_HANDLED; +} + +static irqreturn_t otg1_linestate_irq_handler(int irq, void *dev_id) +{ + /* + * Here is a chip hwrdware bug, when disable/enable + * linestate irq bit the state machine will not reset + * So here have to add a delay to wait the linestate filter + * timer run out (linestate filter time had been set to 100us) + */ + udelay(200); + + /* clear and disable irq */ + writel(UOC_HIWORD_UPDATE(0x2, 0x3, 14), + RK_GRF_VIRT + RK312X_GRF_UOC1_CON5); + + + if (control_usb->usb_irq_wakeup) { + wake_lock_timeout(&control_usb->usb_wakelock, + WAKE_LOCK_TIMEOUT); + } + + return IRQ_HANDLED; +} + /************* register usb detection irqs **************/ static int otg_irq_detect_init(struct platform_device *pdev) { @@ -552,7 +615,7 @@ static int otg_irq_detect_init(struct platform_device *pdev) INIT_DELAYED_WORK(&control_usb->usb_det_wakeup_work, do_wakeup); } - /*register otg_bvalid irq */ + /* register otg_bvalid irq */ irq = platform_get_irq_byname(pdev, "otg_bvalid"); if ((irq > 0) && control_usb->usb_irq_wakeup) { ret = request_irq(irq, bvalid_irq_handler, @@ -565,7 +628,41 @@ static int otg_irq_detect_init(struct platform_device *pdev) RK_GRF_VIRT + RK312X_GRF_UOC0_CON0); } } - return ret; + + if (!control_usb->linestate_wakeup) + return 0; + + /* Set otg0&1_linestate_filter time to 100us */ + writel(UOC_HIWORD_UPDATE(0x0, 0xf, 6), RK_GRF_VIRT + 0x1a0); + + /* Register otg0_linestate irq */ + irq = platform_get_irq_byname(pdev, "otg0_linestate"); + if (irq > 0) { + ret = request_irq(irq, otg0_linestate_irq_handler, + 0, "otg0_linestate", NULL); + if (ret < 0) { + dev_err(&pdev->dev, "request_irq %d failed!\n", irq); + } else { + /* Clear otg0_linestate irq */ + writel(UOC_HIWORD_UPDATE(0x2, 0x3, 12), + RK_GRF_VIRT + RK312X_GRF_UOC0_CON0); + } + } + + /* Register otg1_linestate irq */ + irq = platform_get_irq_byname(pdev, "otg1_linestate"); + if (irq > 0) { + ret = request_irq(irq, otg1_linestate_irq_handler, + 0, "otg1_linestate", NULL); + if (ret < 0) { + dev_err(&pdev->dev, "request_irq %d failed!\n", irq); + } else { + /* Clear otg1_linestate irq */ + writel(UOC_HIWORD_UPDATE(0x2, 0x3, 14), + RK_GRF_VIRT + RK312X_GRF_UOC1_CON5); + } + } + return 0; } /********** end of rk3126 usb detections **********/ @@ -588,6 +685,8 @@ static int rk_usb_control_probe(struct platform_device *pdev) "rockchip,remote_wakeup"); control_usb->usb_irq_wakeup = of_property_read_bool(np, "rockchip,usb_irq_wakeup"); + control_usb->linestate_wakeup = of_property_read_bool(np, + "rockchip,linestate_wakeup"); INIT_DELAYED_WORK(&control_usb->usb_charger_det_work, usb_battery_charger_detect_work);