| /* |
| * xhci-comcerto.c - Comcerto-2000 Platform specific routienes. |
| * |
| * Author: Makarand Pawagi |
| */ |
| |
| |
| #include <linux/platform_device.h> |
| #include <linux/module.h> |
| #include <linux/slab.h> |
| #include "xhci.h" |
| |
| #include <linux/clk.h> |
| #include <mach/reset.h> |
| #include <mach/hardware.h> |
| |
| extern int usb3_clk_internal; |
| /* USB 3.0 clock */ |
| static struct clk *usb3_clk; |
| |
| #ifdef CONFIG_PM |
| |
| u32 usb3_suspended = 0; |
| |
| int comcerto_xhci_bus_suspend(struct usb_hcd *hcd) |
| { |
| int error_status = 0; |
| int val; |
| |
| if (usb3_suspended) { |
| pr_err("comcerto_xhci_bus_suspend: USB 3.0 Already Suspended \n"); |
| return error_status; |
| } |
| |
| error_status = xhci_bus_suspend(hcd); |
| |
| if (!error_status) { |
| |
| /* APPLYING THE RESET TO USB3 UTMI */ |
| c2000_block_reset(COMPONENT_UTMI_USB1, 1); |
| |
| /* APPLYING THE RESET TO USB3 PHY */ |
| c2000_block_reset(COMPONENT_USB1_PHY, 1); |
| |
| /* Disable the Clock */ |
| clk_disable(usb3_clk); |
| |
| usb3_suspended = 1; |
| } |
| |
| return error_status; |
| } |
| |
| int comcerto_xhci_bus_resume(struct usb_hcd *hcd) |
| { |
| int val; |
| int error_status = 0; |
| |
| if (!usb3_suspended) { |
| pr_err("comcerto_xhci_bus_resume: USB 3.0 Already in Resume state \n"); |
| return error_status; |
| } |
| |
| /* Enable the Clock */ |
| if (clk_enable(usb3_clk)){ |
| pr_err("comcerto_start_xhc:Unable to enable the usb1 clock \n"); |
| } |
| |
| /* Bring usb3 PHY out of reset */ |
| c2000_block_reset(COMPONENT_USB1_PHY, 0); |
| |
| for (val = 0 ; val < 50 ; val++) |
| udelay(1000); |
| |
| /* Bring usb3 UTMI out of reset */ |
| c2000_block_reset(COMPONENT_UTMI_USB1, 0); |
| |
| for (val = 0 ; val < 50 ; val++) |
| udelay(1000); |
| |
| error_status = xhci_bus_resume(hcd); |
| |
| if (error_status) { |
| /* xhci_bus_resume is not successfull keep USB3 in suspend mode */ |
| |
| /* Put USB3 PHY, UTMI and Controller in Reset */ |
| |
| /* APPLYING THE RESET TO USB3 UTMI */ |
| c2000_block_reset(COMPONENT_UTMI_USB1, 1); |
| |
| /* APPLYING THE RESET TO USB3 PHY */ |
| c2000_block_reset(COMPONENT_USB1_PHY, 1); |
| |
| /* Disable the Clock */ |
| clk_disable(usb3_clk); |
| |
| return error_status; |
| } |
| |
| usb3_suspended = 0; |
| |
| return error_status; |
| } |
| #endif |
| |
| static void comcerto_usb3_phy_init(void) |
| { |
| u32 val; |
| |
| writel(0x00E00080, USB3_PHY_BASE + 0x10); |
| |
| //Configuration for internal clock |
| if(usb3_clk_internal) |
| { |
| printk(KERN_INFO "USB3.0 clock selected: internal\n", __func__); |
| |
| if(HAL_get_ref_clk() == REF_CLK_24MHZ) |
| val = 0x420E82A8; |
| else |
| val = 0x420E82A9; |
| } |
| else |
| { |
| val = 0x4209927A; |
| printk(KERN_INFO "USB3.0 clock selected: external\n", __func__); |
| } |
| |
| writel(val, USB3_PHY_BASE + 0x20); |
| writel(0x69C34F53, USB3_PHY_BASE + 0x24); |
| writel(0x0005D815, USB3_PHY_BASE + 0x28); |
| writel(0x00000801, USB3_PHY_BASE + 0x2C); |
| } |
| |
| |
| void comcerto_start_xhci(void) |
| { |
| u32 val; |
| |
| printk(KERN_INFO "### %s\n", __func__); |
| |
| #if defined(CONFIG_C2K_MFCN_EVM) |
| printk("%s: Reseting usb3...\n", __func__); |
| GPIO_reset_external_device(COMPONENT_USB_HUB, 0); |
| #endif |
| /* Enable the USB 3.0 controller clock */ |
| /* Get the usb3 clock structure */ |
| usb3_clk = clk_get(NULL,"usb1"); |
| |
| /* Enable the Clock */ |
| if (clk_enable(usb3_clk)){ |
| pr_err("comcerto_start_xhci:Unable to enable the usb1 clock \n"); |
| } |
| |
| /* APPLYING THE RESET TO USB3 UTMI */ |
| c2000_block_reset(COMPONENT_UTMI_USB1, 1); |
| |
| /* APPLYING THE RESET TO USB3 PHY */ |
| c2000_block_reset(COMPONENT_USB1_PHY, 1); |
| |
| /* APLLYING RESET TO USB3 AXI RESET */ |
| c2000_block_reset(COMPONENT_AXI_USB1, 1); |
| |
| comcerto_usb3_phy_init(); |
| |
| |
| /* Bring usb3 PHY out of reset */ |
| c2000_block_reset(COMPONENT_USB1_PHY, 0); |
| |
| udelay(1000); |
| |
| /* Bring usb3 UTMI out of reset */ |
| c2000_block_reset(COMPONENT_UTMI_USB1, 0); |
| |
| udelay(1000); |
| |
| /* Bring usb3 Controller out of reset */ |
| c2000_block_reset(COMPONENT_AXI_USB1, 0); |
| |
| udelay(1000); |
| } |
| |
| void comcerto_stop_xhci(void) |
| { |
| u32 val; |
| |
| printk(KERN_INFO "### %s\n", __func__); |
| |
| /* APPLYING THE RESET TO USB3 UTMI */ |
| c2000_block_reset(COMPONENT_UTMI_USB1, 1); |
| |
| /* APPLYING THE RESET TO USB3 PHY */ |
| c2000_block_reset(COMPONENT_USB1_PHY, 1); |
| |
| /* APLLYING RESET TO USB3 AXI RESET */ |
| c2000_block_reset(COMPONENT_AXI_USB1, 1); |
| |
| /* Disable the Clock */ |
| clk_disable(usb3_clk); |
| |
| /* Release the clock */ |
| clk_put(usb3_clk); |
| } |
| |