mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 12:57:06 +09:00
rk3036: usb: add support of wakeup by GRF linestate change
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user