rk3036: usb: add support of wakeup by GRF linestate change

This commit is contained in:
lyz
2015-04-10 11:44:49 +08:00
parent 796d448f7a
commit 9ca3a6b153
2 changed files with 105 additions and 4 deletions

View File

@@ -551,8 +551,12 @@
dwc_control_usb: dwc-control-usb@20008000 {
compatible = "rockchip,rk3036-dwc-control-usb";
reg = <0x20008000 0x4>;
interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "otg_bvalid";
interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "otg_bvalid",
"otg0_linestate",
"otg1_linestate";
clocks = <&clk_gates9 13>;
clock-names = "hclk_usb_peri";
rockchip,remote_wakeup;

View File

@@ -20,7 +20,7 @@ static void usb20otg_phy_suspend(void *pdata, int suspend)
if (suspend) {
/* enable soft control */
writel(UOC_HIWORD_UPDATE(0x55, 0x7f, 0),
writel(UOC_HIWORD_UPDATE(0x1d1, 0x1ff, 0),
RK_GRF_VIRT + RK3036_GRF_UOC0_CON5);
usbpdata->phy_status = 1;
} else {
@@ -190,7 +190,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, 12),
RK_GRF_VIRT + RK3036_GRF_UOC0_CON5);
/* enable otg1_linestate irq */
writel(UOC_HIWORD_UPDATE(0x3, 0x3, 14),
RK_GRF_VIRT + RK3036_GRF_UOC1_CON5);
}
} else if (power_down == PHY_POWER_UP) {
;
}
}
struct dwc_otg_platform_data usb20otg_pdata_rk3036 = {
.phyclk = NULL,
.ahbclk = NULL,
@@ -205,6 +219,7 @@ struct dwc_otg_platform_data usb20otg_pdata_rk3036 = {
.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
@@ -418,6 +433,52 @@ 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 + RK3036_GRF_UOC0_CON5);
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 + RK3036_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)
{
@@ -443,6 +504,40 @@ static int otg_irq_detect_init(struct platform_device *pdev)
RK_GRF_VIRT + RK3036_GRF_UOC0_CON5);
}
}
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 + RK3036_GRF_UOC0_CON5);
}
}
/* 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 + RK3036_GRF_UOC1_CON5);
}
}
return ret;
}
@@ -466,6 +561,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);