From 4b955ffded47fa9afc4075d49b6dc7e15a64db07 Mon Sep 17 00:00:00 2001 From: yangkai Date: Thu, 21 Feb 2013 15:01:21 +0800 Subject: [PATCH] EHCI&HSIC support --- arch/arm/mach-rk30/Kconfig | 3 + drivers/usb/dwc_otg/usbdev_rk30.c | 30 +++- drivers/usb/host/Kconfig | 8 ++ drivers/usb/host/ehci-hcd.c | 5 + drivers/usb/host/ehci-rk.c | 224 ++++++++++++++++++++++++++++++ 5 files changed, 268 insertions(+), 2 deletions(-) mode change 100644 => 100755 drivers/usb/host/Kconfig mode change 100644 => 100755 drivers/usb/host/ehci-hcd.c create mode 100755 drivers/usb/host/ehci-rk.c diff --git a/arch/arm/mach-rk30/Kconfig b/arch/arm/mach-rk30/Kconfig index dc7b6ec59ebf..377883062c16 100755 --- a/arch/arm/mach-rk30/Kconfig +++ b/arch/arm/mach-rk30/Kconfig @@ -25,14 +25,17 @@ config SOC_RK3068 config SOC_RK3066B bool "RK3066B" select ARCH_RK3066B + select USB_ARCH_HAS_EHCI config SOC_RK3108 bool "RK3108" select ARCH_RK3066B + select USB_ARCH_HAS_EHCI config SOC_RK3168 bool "RK3168" select ARCH_RK3066B + select USB_ARCH_HAS_EHCI endchoice diff --git a/drivers/usb/dwc_otg/usbdev_rk30.c b/drivers/usb/dwc_otg/usbdev_rk30.c index 85d6f54de1f2..67dc21e46aa2 100755 --- a/drivers/usb/dwc_otg/usbdev_rk30.c +++ b/drivers/usb/dwc_otg/usbdev_rk30.c @@ -357,12 +357,12 @@ void usb20host_soft_reset(void) cru_set_soft_reset(SOFT_RST_USBOTG1, true); cru_set_soft_reset(SOFT_RST_USBPHY1, true); cru_set_soft_reset(SOFT_RST_OTGC1, true); - udelay(1); + udelay(5); cru_set_soft_reset(SOFT_RST_USBOTG1, false); cru_set_soft_reset(SOFT_RST_USBPHY1, false); cru_set_soft_reset(SOFT_RST_OTGC1, false); - mdelay(1); + mdelay(2); } void usb20host_clock_init(void* pdata) { @@ -473,8 +473,34 @@ struct platform_device device_usb20_host = { }, }; #endif +static struct resource resources_hsusb_host[] = { + { + .start = IRQ_HSIC, + .end = IRQ_HSIC, + .flags = IORESOURCE_IRQ, + }, + { + .start = RK30_HSIC_PHYS, + .end = RK30_HSIC_PHYS + RK30_HSIC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device device_hsusb_host = { + .name = "rk_hsusb_host", + .id = -1, + .num_resources = ARRAY_SIZE(resources_hsusb_host), + .resource = resources_hsusb_host, + .dev = { + .coherent_dma_mask = 0xffffffff, + }, +}; + static int __init usbdev_init_devices(void) { +#ifdef CONFIG_USB_EHCI_RK + platform_device_register(&device_hsusb_host); +#endif #ifdef CONFIG_USB20_OTG platform_device_register(&device_usb20_otg); #endif diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig old mode 100644 new mode 100755 index ab085f12d570..0ba9e7b25828 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -91,6 +91,14 @@ config USB_EHCI_TT_NEWSCHED If unsure, say Y. +config USB_EHCI_RK + bool "Rockchip EHCI HSIC support" + depends on USB_EHCI_HCD + select USB_EHCI_ROOT_HUB_TT + default y + ---help--- + Enables support for the onchip USB controller on the RK3108. + config USB_EHCI_HCD_PMC_MSP tristate "EHCI support for on-chip PMC MSP71xx USB controller" depends on USB_EHCI_HCD && MSP_HAS_USB diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c old mode 100644 new mode 100755 index f89f77f1b339..1990062de29a --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1292,6 +1292,11 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_msm_driver #endif +#ifdef CONFIG_USB_EHCI_RK +#include "ehci-rk.c" +#define PLATFORM_DRIVER ehci_rk_driver +#endif + #ifdef CONFIG_USB_EHCI_HCD_PMC_MSP #include "ehci-pmcmsp.c" #define PLATFORM_DRIVER ehci_hcd_msp_driver diff --git a/drivers/usb/host/ehci-rk.c b/drivers/usb/host/ehci-rk.c new file mode 100755 index 000000000000..e5e8b7eb2342 --- /dev/null +++ b/drivers/usb/host/ehci-rk.c @@ -0,0 +1,224 @@ +/* ehci-msm.c - HSUSB Host Controller Driver Implementation + * + * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved. + * + * Partly derived from ehci-fsl.c and ehci-hcd.c + * Copyright (c) 2000-2004 by David Brownell + * Copyright (c) 2005 MontaVista Software + * + * All source code in this file is licensed under the following license except + * where indicated. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can find it at http://www.fsf.org + */ + +#include +#include +#include +#include + +#include "ehci.h" + + +static struct hc_driver rk_hc_driver = { + .description = hcd_name, + .product_desc = "Rockchip On-Chip EHCI Host Controller", + .hcd_priv_size = sizeof(struct ehci_hcd), + + /* + * generic hardware linkage + */ + .irq = ehci_irq, + .flags = HCD_USB2 | HCD_MEMORY, + + .reset = ehci_init, + .start = ehci_run, + + .stop = ehci_stop, + .shutdown = ehci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + .endpoint_reset = ehci_endpoint_reset, + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, + + /* + * scheduling support + */ + .get_frame_number = ehci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, + .relinquish_port = ehci_relinquish_port, + .port_handed_over = ehci_port_handed_over, + + /* + * PM support + */ + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, +}; + +static int ehci_rk_probe(struct platform_device *pdev) +{ + struct usb_hcd *hcd; + struct ehci_hcd *ehci; + struct resource *res; + struct clk *clk1; + struct clk *clk2; + struct clk *clk3; + struct device *dev = &pdev->dev; + int ret; + static u64 usb_dmamask = 0xffffffffUL; + + dev_dbg(&pdev->dev, "ehci_rk proble\n"); + + dev->dma_mask = &usb_dmamask; + + hcd = usb_create_hcd(&rk_hc_driver, &pdev->dev, dev_name(&pdev->dev)); + if (!hcd) { + dev_err(&pdev->dev, "Unable to create HCD\n"); + return -ENOMEM; + } + clk1 = clk_get(NULL, "hclk_hsic"); + clk2 = clk_get(NULL, "hsicphy_480m"); + clk3 = clk_get(NULL, "hsicphy_12m"); + clk_enable(clk1); + clk_enable(clk2); + clk_enable(clk3); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Unable to get memory resource\n"); + ret = -ENODEV; + goto put_hcd; + } + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) { + dev_err(&pdev->dev, "ioremap failed\n"); + ret = -ENOMEM; + goto put_hcd; + } + + hcd->irq = platform_get_irq(pdev, 0); + if (hcd->irq < 0) { + dev_err(&pdev->dev, "Unable to get IRQ resource\n"); + ret = hcd->irq; + goto put_hcd; + } + + ehci = hcd_to_ehci(hcd); + ehci->caps = hcd->regs; + ehci->regs = hcd->regs + 0x10; + printk("%s %p %p\n", __func__, ehci->caps, ehci->regs); + + dbg_hcs_params(ehci, "reset"); + dbg_hcc_params(ehci, "reset"); + + ehci->hcs_params = readl(&ehci->caps->hcs_params); + + ret = usb_add_hcd(hcd, hcd->irq, IRQF_DISABLED | IRQF_SHARED); + if (ret) { + dev_err(&pdev->dev, "Failed to add USB HCD\n"); + goto unmap; + } + + ehci_port_power(ehci, 1); + writel_relaxed(1 ,hcd->regs +0xb0); + writel_relaxed(0x1d4d ,hcd->regs +0x90); + writel_relaxed(0x4 ,hcd->regs +0xa0); + dsb(); + + + printk("%s ok\n", __func__); + + return 0; + +unmap: + iounmap(hcd->regs); +put_hcd: + usb_put_hcd(hcd); + + return ret; +} + +static int __devexit ehci_rk_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_put_hcd(hcd); + + return 0; +} + +#ifdef CONFIG_PM +static int ehci_rk_pm_suspend(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + bool wakeup = device_may_wakeup(dev); + + dev_dbg(dev, "ehci-rk PM suspend\n"); + + /* + * EHCI helper function has also the same check before manipulating + * port wakeup flags. We do check here the same condition before + * calling the same helper function to avoid bringing hardware + * from Low power mode when there is no need for adjusting port + * wakeup flags. + */ + if (hcd->self.root_hub->do_remote_wakeup && !wakeup) { + pm_runtime_resume(dev); + ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd), + wakeup); + } + + return 0; +} + +static int ehci_rk_pm_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + + dev_dbg(dev, "ehci-rk PM resume\n"); + ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd)); + + return 0; +} +#else +#define ehci_rk_pm_suspend NULL +#define ehci_rk_pm_resume NULL +#endif + +static const struct dev_pm_ops ehci_rk_dev_pm_ops = { + .suspend = ehci_rk_pm_suspend, + .resume = ehci_rk_pm_resume, +}; + +static struct platform_driver ehci_rk_driver = { + .probe = ehci_rk_probe, + .remove = __devexit_p(ehci_rk_remove), + .driver = { + .name = "rk_hsusb_host", + .pm = &ehci_rk_dev_pm_ops, + }, +}; + -- 2.34.1