X-Git-Url: http://plrg.eecs.uci.edu/git/?p=firefly-linux-kernel-4.4.55.git;a=blobdiff_plain;f=drivers%2Fusb%2Fdwc_otg_310%2Fusbdev_rk3036.c;h=02dec704802250ce37e0ad48628d9a348ed32825;hp=a8186c15d99f824bf4817cbaf5bce84031fc63f3;hb=9a47b6de548a83d198e2a92b53fe735c62832515;hpb=2ddac0b093e9b9e47d8212424b9f1b89b8440ed4 diff --git a/drivers/usb/dwc_otg_310/usbdev_rk3036.c b/drivers/usb/dwc_otg_310/usbdev_rk3036.c index a8186c15d99f..02dec7048022 100755 --- a/drivers/usb/dwc_otg_310/usbdev_rk3036.c +++ b/drivers/usb/dwc_otg_310/usbdev_rk3036.c @@ -1,3 +1,4 @@ +#ifdef CONFIG_ARM #include "usbdev_rk.h" #include "usbdev_grf_regs.h" #include "dwc_otg_regs.h" @@ -20,7 +21,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 { @@ -111,7 +112,7 @@ static void usb20otg_clock_enable(void *pdata, int enable) static int usb20otg_get_status(int id) { int ret = -1; - u32 soc_status0 = readl(RK_GRF_VIRT + RK3036_GRF_CPU_STATUS0); + u32 soc_status0 = readl(RK_GRF_VIRT + RK3036_GRF_SOC_STATUS0); switch (id) { case USB_STATUS_BVABLID: @@ -141,20 +142,42 @@ static int usb20otg_get_status(int id) return ret; } +#ifdef CONFIG_RK_USB_UART +/** + * dwc_otg_uart_enabled - check if a usb-uart bypass func is enabled in DT + * + * Returns true if the status property of node "usb_uart" is set to "okay" + * or "ok", if this property is absent it will use the default status "ok" + * 0 otherwise + */ +static bool dwc_otg_uart_enabled(void) +{ + struct device_node *np; + + np = of_find_node_by_name(NULL, "usb_uart"); + if (np && of_device_is_available(np)) + return true; + + return false; +} + static void dwc_otg_uart_mode(void *pdata, int enter_usb_uart_mode) { -#ifdef CONFIG_RK_USB_UART - if (1 == enter_usb_uart_mode) { + if ((1 == enter_usb_uart_mode) && dwc_otg_uart_enabled()) { /* bypass dm, enter uart mode */ - writel(UOC_HIWORD_UPDATE(0x3, 0x3, 12), - RK_GRF_VIRT + RK3036_GRF_UOC1_CON4); + writel(UOC_HIWORD_UPDATE(0x3, 0x3, 12), RK_GRF_VIRT + + RK3036_GRF_UOC1_CON4); } else if (0 == enter_usb_uart_mode) { /* enter usb mode */ - writel(UOC_HIWORD_UPDATE(0x0, 0x3, 12), - RK_GRF_VIRT + RK3036_GRF_UOC1_CON4); + writel(UOC_HIWORD_UPDATE(0x0, 0x3, 12), RK_GRF_VIRT + + RK3036_GRF_UOC1_CON4); } -#endif } +#else +static void dwc_otg_uart_mode(void *pdata, int enter_usb_uart_mode) +{ +} +#endif static void usb20otg_power_enable(int enable) { @@ -162,13 +185,32 @@ static void usb20otg_power_enable(int enable) /* disable otg_drv power */ if (gpio_is_valid(control_usb->otg_gpios->gpio)) gpio_set_value(control_usb->otg_gpios->gpio, 0); + + rk_battery_charger_detect_cb(USB_OTG_POWER_OFF); } else if (1 == enable) { /* enable otg_drv power */ if (gpio_is_valid(control_usb->otg_gpios->gpio)) gpio_set_value(control_usb->otg_gpios->gpio, 1); + + if (!usb20otg_get_status(USB_STATUS_BVABLID)) + rk_battery_charger_detect_cb(USB_OTG_POWER_ON); + } +} +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, @@ -182,7 +224,8 @@ struct dwc_otg_platform_data usb20otg_pdata_rk3036 = { .get_status = usb20otg_get_status, .power_enable = usb20otg_power_enable, .dwc_otg_uart_mode = dwc_otg_uart_mode, - .bc_detect_cb = usb20otg_battery_charger_detect_cb, + .bc_detect_cb = rk_battery_charger_detect_cb, + .phy_power_down = usb20otg_phy_power_down, }; #endif @@ -292,7 +335,7 @@ static void usb20host_clock_enable(void *pdata, int enable) static int usb20host_get_status(int id) { int ret = -1; - u32 soc_status0 = readl(RK_GRF_VIRT + RK3036_GRF_CPU_STATUS0); + u32 soc_status0 = readl(RK_GRF_VIRT + RK3036_GRF_SOC_STATUS0); switch (id) { case USB_STATUS_BVABLID: @@ -370,7 +413,7 @@ static inline void do_wakeup(struct work_struct *work) static void usb_battery_charger_detect_work(struct work_struct *work) { - rk_usb_charger_status = usb_battery_charger_detect(0); + rk_battery_charger_detect_cb(usb_battery_charger_detect(1)); } /********** handler for bvalid irq **********/ @@ -391,12 +434,57 @@ static irqreturn_t bvalid_irq_handler(int irq, void *dev_id) HZ / 10); } - rk_usb_charger_status = USB_BC_TYPE_SDP; schedule_delayed_work(&control_usb->usb_charger_det_work, HZ / 10); 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) { @@ -422,6 +510,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; } @@ -445,6 +567,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); @@ -549,11 +673,9 @@ static int dwc_otg_control_usb_probe(struct platform_device *pdev) clk_prepare_enable(hclk_usb_peri); #ifdef CONFIG_USB20_OTG - if (usb20otg_get_status(USB_STATUS_BVABLID)) { - rk_usb_charger_status = USB_BC_TYPE_SDP; + if (usb20otg_get_status(USB_STATUS_BVABLID)) schedule_delayed_work(&control_usb->usb_charger_det_work, HZ / 10); - } #endif ret = otg_irq_detect_init(pdev); @@ -606,3 +728,4 @@ MODULE_ALIAS("platform: dwc_control_usb"); MODULE_AUTHOR("RockChip Inc."); MODULE_DESCRIPTION("RockChip Control Module USB Driver"); MODULE_LICENSE("GPL v2"); +#endif