+#ifdef CONFIG_ARM
#include "usbdev_rk.h"
#include "usbdev_grf_regs.h"
#include "dwc_otg_regs.h"
{
/* Turn off differential receiver in suspend mode */
writel(UOC_HIWORD_UPDATE(0, 1, 2),
- RK_GRF_VIRT + RK312X_GRF_USBPHY1_CON6);
+ RK_GRF_VIRT + RK312X_GRF_USBPHY0_CON6);
+ /* Set disconnect detection trigger point to 600mv */
+ writel(UOC_HIWORD_UPDATE(0, 0xf, 11),
+ RK_GRF_VIRT + RK312X_GRF_USBPHY0_CON7);
/* other haredware init,include:
* DRV_VBUS GPIO init */
if (gpio_is_valid(control_usb->otg_gpios->gpio)) {
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 {
/* id in grf */
ret = soc_status0 & (0x1 << 8);
break;
+ case USB_STATUS_UARTMODE:
+ ret = readl(RK_GRF_VIRT + RK312X_GRF_UOC1_CON4) & (1 << 12);
+ break;
case USB_CHIP_ID:
ret = control_usb->chip_id;
break;
static void usb20otg_power_enable(int enable)
{
if (0 == enable) {
+ rk_battery_charger_detect_cb(USB_OTG_POWER_OFF);
/* disable otg_drv power */
if (gpio_is_valid(control_usb->otg_gpios->gpio))
gpio_set_value(control_usb->otg_gpios->gpio, 0);
} else if (1 == enable) {
+ rk_battery_charger_detect_cb(USB_OTG_POWER_ON);
/* enable otg_drv power */
if (gpio_is_valid(control_usb->otg_gpios->gpio))
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,
.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
-#ifdef CONFIG_USB20_HOST
+#if defined(CONFIG_USB20_HOST) || defined(CONFIG_USB_EHCI_RK)
static void usb20host_hw_init(void)
{
- /* Switch to DWC HOST */
- writel(UOC_HIWORD_UPDATE(1, 1, 3),
- RK_GRF_VIRT + RK312X_GRF_SOC_CON2);
/* Turn off differential receiver in suspend mode */
writel(UOC_HIWORD_UPDATE(0, 1, 2),
- RK_GRF_VIRT + RK312X_GRF_USBPHY0_CON6);
+ RK_GRF_VIRT + RK312X_GRF_USBPHY1_CON6);
+ /* Set disconnect detection trigger point to 600mv */
+ writel(UOC_HIWORD_UPDATE(1, 0xf, 11),
+ RK_GRF_VIRT + RK312X_GRF_USBPHY1_CON7);
/* other haredware init,include:
* DRV_VBUS GPIO init */
if (gpio_is_valid(control_usb->host_gpios->gpio)) {
};
#endif
+#ifdef CONFIG_USB_EHCI_RK
+static void usb20ehci_phy_suspend(void *pdata, int suspend)
+{
+ struct rkehci_platform_data *usbpdata = pdata;
+
+ if (suspend) {
+ /* enable soft control */
+ writel(UOC_HIWORD_UPDATE(0x1d1, 0x1ff, 0),
+ RK_GRF_VIRT + RK312X_GRF_UOC1_CON5);
+ usbpdata->phy_status = 1;
+ } else {
+ /* exit suspend */
+ writel(UOC_HIWORD_UPDATE(0x0, 0x1, 0),
+ RK_GRF_VIRT + RK312X_GRF_UOC1_CON5);
+ usbpdata->phy_status = 0;
+ }
+}
+
+static void usb20ehci_soft_reset(void *pdata, enum rkusb_rst_flag rst_type)
+{
+ struct rkehci_platform_data *usbpdata = pdata;
+ struct reset_control *rst_host_h, *rst_host_p, *rst_host_c;
+
+ rst_host_h = devm_reset_control_get(usbpdata->dev, "host_ahb");
+ rst_host_p = devm_reset_control_get(usbpdata->dev, "host_phy");
+ rst_host_c = devm_reset_control_get(usbpdata->dev, "host_controller");
+ if (IS_ERR(rst_host_h) || IS_ERR(rst_host_p) || IS_ERR(rst_host_c)) {
+ dev_err(usbpdata->dev, "Fail to get reset control from dts\n");
+ return;
+ }
+
+ switch(rst_type) {
+ case RST_POR:
+ /* PHY reset */
+ writel(UOC_HIWORD_UPDATE(0x1, 0x3, 0),
+ RK_GRF_VIRT + RK312X_GRF_UOC1_CON5);
+ reset_control_assert(rst_host_p);
+ udelay(15);
+ writel(UOC_HIWORD_UPDATE(0x2, 0x3, 0),
+ RK_GRF_VIRT + RK312X_GRF_UOC1_CON5);
+
+ udelay(1500);
+ reset_control_deassert(rst_host_p);
+
+ /* Controller reset */
+ reset_control_assert(rst_host_c);
+ reset_control_assert(rst_host_h);
+
+ udelay(5);
+
+ reset_control_deassert(rst_host_c);
+ reset_control_deassert(rst_host_h);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void usb20ehci_clock_init(void *pdata)
+{
+ struct rkehci_platform_data *usbpdata = pdata;
+ struct clk *ahbclk, *phyclk;
+
+ ahbclk = devm_clk_get(usbpdata->dev, "hclk_host0");
+ if (IS_ERR(ahbclk)) {
+ dev_err(usbpdata->dev, "Failed to get hclk_usb1\n");
+ return;
+ }
+
+ phyclk = devm_clk_get(usbpdata->dev, "clk_usbphy1");
+ if (IS_ERR(phyclk)) {
+ dev_err(usbpdata->dev, "Failed to get clk_usbphy1\n");
+ return;
+ }
+
+ usbpdata->phyclk = phyclk;
+ usbpdata->ahbclk = ahbclk;
+}
+
+static void usb20ehci_clock_enable(void *pdata, int enable)
+{
+ struct rkehci_platform_data *usbpdata = pdata;
+
+ if (enable) {
+ clk_prepare_enable(usbpdata->ahbclk);
+ clk_prepare_enable(usbpdata->phyclk);
+ } else {
+ clk_disable_unprepare(usbpdata->ahbclk);
+ clk_disable_unprepare(usbpdata->phyclk);
+ }
+}
+
+struct rkehci_platform_data usb20ehci_pdata_rk3126 = {
+ .phyclk = NULL,
+ .ahbclk = NULL,
+ .phy_status = 0,
+ .hw_init = usb20host_hw_init,
+ .phy_suspend = usb20ehci_phy_suspend,
+ .soft_reset = usb20ehci_soft_reset,
+ .clock_init = usb20ehci_clock_init,
+ .clock_enable = usb20ehci_clock_enable,
+ .get_status = usb20host_get_status,
+};
+#endif
+
+struct dwc_otg_platform_data usb20ohci_pdata_rk3126;
+
#ifdef CONFIG_OF
static const struct of_device_id rk_usb_control_id_table[] = {
{
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 **********/
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 + 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)
{
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,
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 **********/
"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);
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);
MODULE_AUTHOR("RockChip Inc.");
MODULE_DESCRIPTION("RockChip Control Module USB Driver");
MODULE_LICENSE("GPL v2");
-
+#endif