From 0d688f64985379da9575b5a9e63e374e95c60951 Mon Sep 17 00:00:00 2001 From: wlf Date: Tue, 4 Mar 2014 15:30:07 +0800 Subject: [PATCH] USB: renamed ehci-rk.c -> ehci-rkhsic.c for support HSIC and EHCI --- drivers/usb/dwc_otg_310/usbdev_rk30.c | 2 +- drivers/usb/host/Kconfig | 13 +- drivers/usb/host/ehci-hcd.c | 5 + drivers/usb/host/ehci-rk.c | 535 +++++++++----------------- drivers/usb/host/ehci-rkhsic.c | 359 +++++++++++++++++ 5 files changed, 551 insertions(+), 363 deletions(-) create mode 100755 drivers/usb/host/ehci-rkhsic.c diff --git a/drivers/usb/dwc_otg_310/usbdev_rk30.c b/drivers/usb/dwc_otg_310/usbdev_rk30.c index e994e8a1ec86..447a723eb9c9 100755 --- a/drivers/usb/dwc_otg_310/usbdev_rk30.c +++ b/drivers/usb/dwc_otg_310/usbdev_rk30.c @@ -283,7 +283,7 @@ struct dwc_otg_platform_data usb20host_pdata = { }; #endif -#ifdef CONFIG_USB_EHCI_RK +#ifdef CONFIG_USB_EHCI_RKHSIC void rk_hsic_hw_init(void) { unsigned int * phy_con0 = (control_usb->grf_uoc0_base); diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index cbb1c88a471b..f70e0f0af0b3 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -100,12 +100,19 @@ config USB_FSL_MPH_DR_OF if USB_EHCI_HCD -config USB_EHCI_RK +config USB_EHCI_RKHSIC tristate "Rockchip EHCI HSIC support" select USB_EHCI_ROOT_HUB_TT - default y + default n + ---help--- + Enables support for the HSIC USB controller on the RK platform. + +config USB_EHCI_RK + tristate "Rockchip EHCI HOST20 support" + select USB_EHCI_ROOT_HUB_TT + default n ---help--- - Enables support for the HSIC USB controller on the RK platform + Enables support EHCI for RK3288 and later chips. config USB_EHCI_PCI tristate diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 4517d22dc73d..a17d73217e65 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1266,6 +1266,11 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_rk_driver #endif +#ifdef CONFIG_USB_EHCI_RKHSIC +#include "ehci-rkhsic.c" +#define PLATFORM_DRIVER ehci_rkhsic_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 index db8fb507f801..9b6fae73c0c1 100755 --- a/drivers/usb/host/ehci-rk.c +++ b/drivers/usb/host/ehci-rk.c @@ -1,359 +1,176 @@ -/* 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 -# include -# include "ehci.h" -#ifdef CONFIG_DWC_OTG_274 -# include "../dwc_otg/usbdev_rk.h" -#endif -#ifdef CONFIG_DWC_OTG_310 -# include "../dwc_otg_310/usbdev_rk.h" -#endif - -static int rkehci_status = 1; -static struct ehci_hcd *g_ehci; -#define EHCI_DEVICE_FILE "/sys/devices/platform/rk_hsusb_host/ehci_power" -#define EHCI_PRINT(x...) printk( KERN_INFO "EHCI: " x ) - -extern struct rkehci_platform_data rkhsic_pdata; - -static void ehci_port_power (struct ehci_hcd *ehci, int is_on) -{ - unsigned port; - - if (!HCS_PPC (ehci->hcs_params)) - return; - - ehci_dbg (ehci, "...power%s ports...\n", is_on ? "up" : "down"); - for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) - (void) ehci_hub_control(ehci_to_hcd(ehci), - is_on ? SetPortFeature : ClearPortFeature, - USB_PORT_FEAT_POWER, - port--, NULL, 0); - /* Flush those writes */ - ehci_readl(ehci, &ehci->regs->command); - msleep(20); -} - -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 - */ -#ifdef CONFIG_PM - .bus_suspend = ehci_bus_suspend, - .bus_resume = ehci_bus_resume, -#endif -}; - -static ssize_t ehci_power_show( struct device *_dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", rkehci_status); -} -static ssize_t ehci_power_store( struct device *_dev, - struct device_attribute *attr, - const char *buf, size_t count ) -{ - uint32_t val = simple_strtoul(buf, NULL, 16); - struct usb_hcd *hcd = dev_get_drvdata(_dev); - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - struct rkehci_platform_data *pldata = _dev->platform_data; - - printk("%s: %d setting to: %d\n", __func__, rkehci_status, val); - if(val == rkehci_status) - goto out; - - rkehci_status = val; - switch(val){ - case 0: //power down - ehci_port_power(ehci, 0); - writel_relaxed(0 ,hcd->regs +0xb0); - dsb(); - msleep(5); - usb_remove_hcd(hcd); - break; - case 1: // power on - pldata->soft_reset(); - usb_add_hcd(hcd, hcd->irq, IRQF_DISABLED | IRQF_SHARED); - - ehci_port_power(ehci, 1); - writel_relaxed(1 ,hcd->regs +0xb0); - writel_relaxed(0x1d4d ,hcd->regs +0x90); - writel_relaxed(0x4 ,hcd->regs +0xa0); - dsb(); - break; - default: - break; - } -out: - return count; -} -static DEVICE_ATTR(ehci_power, S_IRUGO|S_IWUSR, ehci_power_show, ehci_power_store); - -static ssize_t debug_show( struct device *_dev, - struct device_attribute *attr, char *buf) -{ - volatile uint32_t *addr; - - EHCI_PRINT("******** EHCI Capability Registers **********\n"); - addr = &g_ehci->caps->hc_capbase; - EHCI_PRINT("HCIVERSION / CAPLENGTH @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); - addr = &g_ehci->caps->hcs_params; - EHCI_PRINT("HCSPARAMS @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); - addr = &g_ehci->caps->hcc_params; - EHCI_PRINT("HCCPARAMS @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); - EHCI_PRINT("********* EHCI Operational Registers *********\n"); - addr = &g_ehci->regs->command; - EHCI_PRINT("USBCMD @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); - addr = &g_ehci->regs->status; - EHCI_PRINT("USBSTS @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); - addr = &g_ehci->regs->intr_enable; - EHCI_PRINT("USBINTR @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); - addr = &g_ehci->regs->frame_index; - EHCI_PRINT("FRINDEX @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); - addr = &g_ehci->regs->segment; - EHCI_PRINT("CTRLDSSEGMENT @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); - addr = &g_ehci->regs->frame_list; - EHCI_PRINT("PERIODICLISTBASE @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); - addr = &g_ehci->regs->async_next; - EHCI_PRINT("ASYNCLISTADDR @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); - addr = &g_ehci->regs->configured_flag; - EHCI_PRINT("CONFIGFLAG @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); - addr = g_ehci->regs->port_status; - EHCI_PRINT("PORTSC @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); - return sprintf(buf, "EHCI Registers Dump\n"); -} -static DEVICE_ATTR(debug_ehci, S_IRUGO, debug_show, NULL); - -static int ehci_rk_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - struct ehci_hcd *ehci; - struct resource *res; - struct device *dev = &pdev->dev; - struct rkehci_platform_data *pldata; - int ret; - int retval = 0; - static u64 usb_dmamask = 0xffffffffUL; - struct device_node *node = pdev->dev.of_node; - - dev_dbg(&pdev->dev, "ehci_rk proble\n"); - - dev->platform_data = &rkhsic_pdata; - pldata = dev->platform_data; - pldata->dev = dev; - - if (!node) { - dev_err(dev, "device node not found\n"); - return -EINVAL; - } - - dev->dma_mask = &usb_dmamask; - - retval = device_create_file(dev, &dev_attr_ehci_power); - retval = device_create_file(dev, &dev_attr_debug_ehci); - 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; - } - - pldata->hw_init(); - pldata->clock_init(pldata); - pldata->clock_enable(pldata, 1); - - 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 = devm_ioremap_resource(dev, res); - - 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; - } - - g_ehci = ehci; - 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 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 of_device_id rk_hsic_of_match[] = { - { .compatible = "rockchip,rk_hsic_host", }, - { }, -}; - -MODULE_DEVICE_TABLE(of, rk_hsic_of_match); - -static struct platform_driver ehci_rk_driver = { - .probe = ehci_rk_probe, - .remove = ehci_rk_remove, - .driver = { - .name = "rk_hsic_host", - .of_match_table = of_match_ptr(rk_hsic_of_match), -#ifdef CONFIG_PM - .pm = &ehci_rk_dev_pm_ops, -#endif - }, -}; - +/* + * EHCI-compliant USB host controller driver for Rockchip SoCs + * + * Copyright (C) 2010 Google, Inc. + * Copyright (C) 2009 - 2013 NVIDIA Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * 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. + * + */ +# include +# include +# include +# include +# include +# include +# include "ehci.h" +#ifdef CONFIG_DWC_OTG_274 +# include "../dwc_otg/usbdev_rk.h" +#endif +#ifdef CONFIG_DWC_OTG_310 +# include "../dwc_otg_310/usbdev_rk.h" +#endif + +static int rkehci_status = 1; +static void ehci_port_power (struct ehci_hcd *ehci, int is_on) +{ + +} + +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 + */ +#ifdef CONFIG_PM + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, +#endif +}; +static ssize_t ehci_power_show( struct device *_dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", rkehci_status); +} +static ssize_t ehci_power_store( struct device *_dev, + struct device_attribute *attr, + const char *buf, size_t count ) +{ + return count; +} +static DEVICE_ATTR(ehci_power, S_IRUGO|S_IWUSR, ehci_power_show, ehci_power_store); +static ssize_t debug_show( struct device *_dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "EHCI Registers Dump\n"); +} +static DEVICE_ATTR(debug_ehci, S_IRUGO, debug_show, NULL); +static int ehci_rk_probe(struct platform_device *pdev) +{ + dev_dbg(&pdev->dev, "ehci_rk proble\n"); + return 0; +} +static int 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 of_device_id rk_ehci_of_match[] = { + { .compatible = "rockchip,rk_ehci_host", }, + { }, +}; + +MODULE_DEVICE_TABLE(of, rk_ehci_of_match); + +static struct platform_driver ehci_rk_driver = { + .probe = ehci_rk_probe, + .remove = ehci_rk_remove, + .driver = { + .name = "rk_ehci_host", + .of_match_table = of_match_ptr(rk_ehci_of_match), +#ifdef CONFIG_PM + .pm = &ehci_rk_dev_pm_ops, +#endif + }, +}; diff --git a/drivers/usb/host/ehci-rkhsic.c b/drivers/usb/host/ehci-rkhsic.c new file mode 100755 index 000000000000..37e19e3e8ca6 --- /dev/null +++ b/drivers/usb/host/ehci-rkhsic.c @@ -0,0 +1,359 @@ +/* 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 +# include +# include "ehci.h" +#ifdef CONFIG_DWC_OTG_274 +# include "../dwc_otg/usbdev_rk.h" +#endif +#ifdef CONFIG_DWC_OTG_310 +# include "../dwc_otg_310/usbdev_rk.h" +#endif + +static int rkehci_status = 1; +static struct ehci_hcd *g_ehci; +#define EHCI_DEVICE_FILE "/sys/devices/platform/rk_hsusb_host/ehci_power" +#define EHCI_PRINT(x...) printk( KERN_INFO "EHCI: " x ) + +extern struct rkehci_platform_data rkhsic_pdata; + +static void ehci_port_power (struct ehci_hcd *ehci, int is_on) +{ + unsigned port; + + if (!HCS_PPC (ehci->hcs_params)) + return; + + ehci_dbg (ehci, "...power%s ports...\n", is_on ? "up" : "down"); + for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) + (void) ehci_hub_control(ehci_to_hcd(ehci), + is_on ? SetPortFeature : ClearPortFeature, + USB_PORT_FEAT_POWER, + port--, NULL, 0); + /* Flush those writes */ + ehci_readl(ehci, &ehci->regs->command); + msleep(20); +} + +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 + */ +#ifdef CONFIG_PM + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, +#endif +}; + +static ssize_t ehci_power_show( struct device *_dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", rkehci_status); +} +static ssize_t ehci_power_store( struct device *_dev, + struct device_attribute *attr, + const char *buf, size_t count ) +{ + uint32_t val = simple_strtoul(buf, NULL, 16); + struct usb_hcd *hcd = dev_get_drvdata(_dev); + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + struct rkehci_platform_data *pldata = _dev->platform_data; + + printk("%s: %d setting to: %d\n", __func__, rkehci_status, val); + if(val == rkehci_status) + goto out; + + rkehci_status = val; + switch(val){ + case 0: //power down + ehci_port_power(ehci, 0); + writel_relaxed(0 ,hcd->regs +0xb0); + dsb(); + msleep(5); + usb_remove_hcd(hcd); + break; + case 1: // power on + pldata->soft_reset(); + usb_add_hcd(hcd, hcd->irq, IRQF_DISABLED | IRQF_SHARED); + + ehci_port_power(ehci, 1); + writel_relaxed(1 ,hcd->regs +0xb0); + writel_relaxed(0x1d4d ,hcd->regs +0x90); + writel_relaxed(0x4 ,hcd->regs +0xa0); + dsb(); + break; + default: + break; + } +out: + return count; +} +static DEVICE_ATTR(ehci_power, S_IRUGO|S_IWUSR, ehci_power_show, ehci_power_store); + +static ssize_t debug_show( struct device *_dev, + struct device_attribute *attr, char *buf) +{ + volatile uint32_t *addr; + + EHCI_PRINT("******** EHCI Capability Registers **********\n"); + addr = &g_ehci->caps->hc_capbase; + EHCI_PRINT("HCIVERSION / CAPLENGTH @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); + addr = &g_ehci->caps->hcs_params; + EHCI_PRINT("HCSPARAMS @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); + addr = &g_ehci->caps->hcc_params; + EHCI_PRINT("HCCPARAMS @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); + EHCI_PRINT("********* EHCI Operational Registers *********\n"); + addr = &g_ehci->regs->command; + EHCI_PRINT("USBCMD @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); + addr = &g_ehci->regs->status; + EHCI_PRINT("USBSTS @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); + addr = &g_ehci->regs->intr_enable; + EHCI_PRINT("USBINTR @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); + addr = &g_ehci->regs->frame_index; + EHCI_PRINT("FRINDEX @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); + addr = &g_ehci->regs->segment; + EHCI_PRINT("CTRLDSSEGMENT @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); + addr = &g_ehci->regs->frame_list; + EHCI_PRINT("PERIODICLISTBASE @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); + addr = &g_ehci->regs->async_next; + EHCI_PRINT("ASYNCLISTADDR @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); + addr = &g_ehci->regs->configured_flag; + EHCI_PRINT("CONFIGFLAG @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); + addr = g_ehci->regs->port_status; + EHCI_PRINT("PORTSC @0x%08x: 0x%08x\n", (uint32_t)addr, readl_relaxed(addr)); + return sprintf(buf, "EHCI Registers Dump\n"); +} +static DEVICE_ATTR(debug_ehci, S_IRUGO, debug_show, NULL); + +static int ehci_rkhsic_probe(struct platform_device *pdev) +{ + struct usb_hcd *hcd; + struct ehci_hcd *ehci; + struct resource *res; + struct device *dev = &pdev->dev; + struct rkehci_platform_data *pldata; + int ret; + int retval = 0; + static u64 usb_dmamask = 0xffffffffUL; + struct device_node *node = pdev->dev.of_node; + + dev_dbg(&pdev->dev, "ehci_rkhsic proble\n"); + + dev->platform_data = &rkhsic_pdata; + pldata = dev->platform_data; + pldata->dev = dev; + + if (!node) { + dev_err(dev, "device node not found\n"); + return -EINVAL; + } + + dev->dma_mask = &usb_dmamask; + + retval = device_create_file(dev, &dev_attr_ehci_power); + retval = device_create_file(dev, &dev_attr_debug_ehci); + 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; + } + + pldata->hw_init(); + pldata->clock_init(pldata); + pldata->clock_enable(pldata, 1); + + 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 = devm_ioremap_resource(dev, res); + + 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; + } + + g_ehci = ehci; + 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 ehci_rkhsic_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_rkhsic_pm_suspend(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + bool wakeup = device_may_wakeup(dev); + + dev_dbg(dev, "ehci-rkhsic 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_rkhsic_pm_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + + dev_dbg(dev, "ehci-rkhsic PM resume\n"); + ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd)); + + return 0; +} +#else +#define ehci_rkhsic_pm_suspend NULL +#define ehci_rkhsic_pm_resume NULL +#endif + +static const struct dev_pm_ops ehci_rkhsic_dev_pm_ops = { + .suspend = ehci_rkhsic_pm_suspend, + .resume = ehci_rkhsic_pm_resume, +}; + +static struct of_device_id rk_hsic_of_match[] = { + { .compatible = "rockchip,rk_hsic_host", }, + { }, +}; + +MODULE_DEVICE_TABLE(of, rk_hsic_of_match); + +static struct platform_driver ehci_rkhsic_driver = { + .probe = ehci_rkhsic_probe, + .remove = ehci_rkhsic_remove, + .driver = { + .name = "rk_hsic_host", + .of_match_table = of_match_ptr(rk_hsic_of_match), +#ifdef CONFIG_PM + .pm = &ehci_rkhsic_dev_pm_ops, +#endif + }, +}; + -- 2.34.1