13abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay/* 23abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay * drivers/usb/host/ehci-pxa168.c 33abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay * 43abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay * Tanmay Upadhyay <tanmay.upadhyay@einfochips.com> 53abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay * 63abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay * Based on drivers/usb/host/ehci-orion.c 73abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay * 83abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay * This file is licensed under the terms of the GNU General Public 93abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay * License version 2. This program is licensed "as is" without any 103abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay * warranty of any kind, whether express or implied. 113abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay */ 123abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 133abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#include <linux/kernel.h> 143abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#include <linux/module.h> 153abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#include <linux/platform_device.h> 163abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#include <linux/clk.h> 173abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#include <mach/pxa168.h> 183abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 193abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define USB_PHY_CTRL_REG 0x4 203abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define USB_PHY_PLL_REG 0x8 213abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define USB_PHY_TX_REG 0xc 223abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 233abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define FBDIV_SHIFT 4 243abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 253abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define ICP_SHIFT 12 263abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define ICP_15 2 273abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define ICP_20 3 283abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define ICP_25 4 293abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 303abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define KVCO_SHIFT 15 313abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 323abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define PLLCALI12_SHIFT 25 333abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define CALI12_VDD 0 343abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define CALI12_09 1 353abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define CALI12_10 2 363abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define CALI12_11 3 373abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 383abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define PLLVDD12_SHIFT 27 393abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define VDD12_VDD 0 403abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define VDD12_10 1 413abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define VDD12_11 2 423abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define VDD12_12 3 433abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 443abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define PLLVDD18_SHIFT 29 453abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define VDD18_19 0 463abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define VDD18_20 1 473abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define VDD18_21 2 483abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define VDD18_22 3 493abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 503abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 513abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define PLL_READY (1 << 23) 523abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define VCOCAL_START (1 << 21) 533abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay#define REG_RCAL_START (1 << 12) 543abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 553abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyaystruct pxa168_usb_drv_data { 563abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay struct ehci_hcd ehci; 573abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay struct clk *pxa168_usb_clk; 583abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay struct resource *usb_phy_res; 593abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay void __iomem *usb_phy_reg_base; 603abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay}; 613abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 623abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyaystatic int ehci_pxa168_setup(struct usb_hcd *hcd) 633abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay{ 643abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay struct ehci_hcd *ehci = hcd_to_ehci(hcd); 653abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay int retval; 663abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 673abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay ehci_reset(ehci); 683abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay retval = ehci_halt(ehci); 693abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay if (retval) 703abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay return retval; 713abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 723abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay /* 733abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay * data structure init 743abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay */ 753abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay retval = ehci_init(hcd); 763abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay if (retval) 773abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay return retval; 783abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 793abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay hcd->has_tt = 1; 803abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 813abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay ehci_port_power(ehci, 0); 823abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 833abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay return retval; 843abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay} 853abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 863abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyaystatic const struct hc_driver ehci_pxa168_hc_driver = { 873abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .description = hcd_name, 883abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .product_desc = "Marvell PXA168 EHCI", 893abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .hcd_priv_size = sizeof(struct pxa168_usb_drv_data), 903abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 913abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay /* 923abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay * generic hardware linkage 933abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay */ 943abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .irq = ehci_irq, 953abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .flags = HCD_MEMORY | HCD_USB2, 963abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 973abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay /* 983abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay * basic lifecycle operations 993abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay */ 1003abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .reset = ehci_pxa168_setup, 1013abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .start = ehci_run, 1023abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .stop = ehci_stop, 1033abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .shutdown = ehci_shutdown, 1043abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 1053abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay /* 1063abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay * managing i/o requests and associated device resources 1073abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay */ 1083abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .urb_enqueue = ehci_urb_enqueue, 1093abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .urb_dequeue = ehci_urb_dequeue, 1103abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .endpoint_disable = ehci_endpoint_disable, 1113abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .endpoint_reset = ehci_endpoint_reset, 1123abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 1133abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay /* 1143abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay * scheduling support 1153abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay */ 1163abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .get_frame_number = ehci_get_frame, 1173abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 1183abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay /* 1193abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay * root hub support 1203abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay */ 1213abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .hub_status_data = ehci_hub_status_data, 1223abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .hub_control = ehci_hub_control, 1233abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .bus_suspend = ehci_bus_suspend, 1243abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .bus_resume = ehci_bus_resume, 1253abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .relinquish_port = ehci_relinquish_port, 1263abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .port_handed_over = ehci_port_handed_over, 1273abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 1283abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, 1293abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay}; 1303abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 1313abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyaystatic int pxa168_usb_phy_init(struct platform_device *pdev) 1323abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay{ 1333abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay struct resource *res; 1343abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay void __iomem *usb_phy_reg_base; 1353abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay struct pxa168_usb_pdata *pdata; 1363abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay struct pxa168_usb_drv_data *drv_data; 1373abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay struct usb_hcd *hcd = platform_get_drvdata(pdev); 1383abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay unsigned long reg_val; 1393abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay int pll_retry_cont = 10000, err = 0; 1403abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 1413abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay drv_data = (struct pxa168_usb_drv_data *)hcd->hcd_priv; 1423abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay pdata = (struct pxa168_usb_pdata *)pdev->dev.platform_data; 1433abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 1443abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 1453abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay if (!res) { 1463abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay dev_err(&pdev->dev, 1473abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay "Found HC with no PHY register addr. Check %s setup!\n", 1483abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay dev_name(&pdev->dev)); 1493abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay return -ENODEV; 1503abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay } 1513abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 1523abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay if (!request_mem_region(res->start, resource_size(res), 1533abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay ehci_pxa168_hc_driver.description)) { 1543abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay dev_dbg(&pdev->dev, "controller already in use\n"); 1553abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay return -EBUSY; 1563abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay } 1573abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 1583abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay usb_phy_reg_base = ioremap(res->start, resource_size(res)); 1593abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay if (usb_phy_reg_base == NULL) { 1603abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay dev_dbg(&pdev->dev, "error mapping memory\n"); 1613abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay err = -EFAULT; 1623abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay goto err1; 1633abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay } 1643abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay drv_data->usb_phy_reg_base = usb_phy_reg_base; 1653abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay drv_data->usb_phy_res = res; 1663abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 1673abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay /* If someone wants to init USB phy in board specific way */ 1683abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay if (pdata && pdata->phy_init) 1693abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay return pdata->phy_init(usb_phy_reg_base); 1703abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 1713abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay /* Power up the PHY and PLL */ 1723abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay writel(readl(usb_phy_reg_base + USB_PHY_CTRL_REG) | 0x3, 1733abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay usb_phy_reg_base + USB_PHY_CTRL_REG); 1743abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 1753abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay /* Configure PHY PLL */ 1763abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay reg_val = readl(usb_phy_reg_base + USB_PHY_PLL_REG) & ~(0x7e03ffff); 1773abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay reg_val |= (VDD18_22 << PLLVDD18_SHIFT | VDD12_12 << PLLVDD12_SHIFT | 1783abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay CALI12_11 << PLLCALI12_SHIFT | 3 << KVCO_SHIFT | 1793abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay ICP_15 << ICP_SHIFT | 0xee << FBDIV_SHIFT | 0xb); 1803abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay writel(reg_val, usb_phy_reg_base + USB_PHY_PLL_REG); 1813abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 1823abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay /* Make sure PHY PLL is ready */ 1833abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay while (!(readl(usb_phy_reg_base + USB_PHY_PLL_REG) & PLL_READY)) { 1843abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay if (!(pll_retry_cont--)) { 1853abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay dev_dbg(&pdev->dev, "USB PHY PLL not ready\n"); 1863abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay err = -EIO; 1873abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay goto err2; 1883abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay } 1893abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay } 1903abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 1913abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay /* Toggle VCOCAL_START bit of U2PLL for PLL calibration */ 1923abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay udelay(200); 1933abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay writel(readl(usb_phy_reg_base + USB_PHY_PLL_REG) | VCOCAL_START, 1943abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay usb_phy_reg_base + USB_PHY_PLL_REG); 1953abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay udelay(40); 1963abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay writel(readl(usb_phy_reg_base + USB_PHY_PLL_REG) & ~VCOCAL_START, 1973abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay usb_phy_reg_base + USB_PHY_PLL_REG); 1983abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 1993abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay /* Toggle REG_RCAL_START bit of U2PTX for impedance calibration */ 2003abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay udelay(400); 2013abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay writel(readl(usb_phy_reg_base + USB_PHY_TX_REG) | REG_RCAL_START, 2023abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay usb_phy_reg_base + USB_PHY_TX_REG); 2033abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay udelay(40); 2043abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay writel(readl(usb_phy_reg_base + USB_PHY_TX_REG) & ~REG_RCAL_START, 2053abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay usb_phy_reg_base + USB_PHY_TX_REG); 2063abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 2073abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay /* Make sure PHY PLL is ready again */ 2083abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay pll_retry_cont = 0; 2093abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay while (!(readl(usb_phy_reg_base + USB_PHY_PLL_REG) & PLL_READY)) { 2103abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay if (!(pll_retry_cont--)) { 2113abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay dev_dbg(&pdev->dev, "USB PHY PLL not ready\n"); 2123abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay err = -EIO; 2133abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay goto err2; 2143abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay } 2153abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay } 2163abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 2173abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay return 0; 2183abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyayerr2: 2193abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay iounmap(usb_phy_reg_base); 2203abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyayerr1: 2213abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay release_mem_region(res->start, resource_size(res)); 2223abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay return err; 2233abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay} 2243abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 2253abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyaystatic int __devinit ehci_pxa168_drv_probe(struct platform_device *pdev) 2263abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay{ 2273abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay struct resource *res; 2283abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay struct usb_hcd *hcd; 2293abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay struct ehci_hcd *ehci; 2303abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay struct pxa168_usb_drv_data *drv_data; 2313abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay void __iomem *regs; 2323abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay int irq, err = 0; 2333abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 2343abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay if (usb_disabled()) 2353abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay return -ENODEV; 2363abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 2373abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay pr_debug("Initializing pxa168-SoC USB Host Controller\n"); 2383abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 2393abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay irq = platform_get_irq(pdev, 0); 2403abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay if (irq <= 0) { 2413abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay dev_err(&pdev->dev, 2423abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay "Found HC with no IRQ. Check %s setup!\n", 2433abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay dev_name(&pdev->dev)); 2443abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay err = -ENODEV; 2453abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay goto err1; 2463abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay } 2473abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 2483abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 2493abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay if (!res) { 2503abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay dev_err(&pdev->dev, 2513abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay "Found HC with no register addr. Check %s setup!\n", 2523abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay dev_name(&pdev->dev)); 2533abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay err = -ENODEV; 2543abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay goto err1; 2553abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay } 2563abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 2573abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay if (!request_mem_region(res->start, resource_size(res), 2583abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay ehci_pxa168_hc_driver.description)) { 2593abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay dev_dbg(&pdev->dev, "controller already in use\n"); 2603abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay err = -EBUSY; 2613abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay goto err1; 2623abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay } 2633abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 2643abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay regs = ioremap(res->start, resource_size(res)); 2653abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay if (regs == NULL) { 2663abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay dev_dbg(&pdev->dev, "error mapping memory\n"); 2673abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay err = -EFAULT; 2683abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay goto err2; 2693abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay } 2703abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 2713abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay hcd = usb_create_hcd(&ehci_pxa168_hc_driver, 2723abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay &pdev->dev, dev_name(&pdev->dev)); 2733abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay if (!hcd) { 2743abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay err = -ENOMEM; 2753abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay goto err3; 2763abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay } 2773abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 2783abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay drv_data = (struct pxa168_usb_drv_data *)hcd->hcd_priv; 2793abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 2803abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay /* Enable USB clock */ 2813abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay drv_data->pxa168_usb_clk = clk_get(&pdev->dev, "PXA168-USBCLK"); 2823abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay if (IS_ERR(drv_data->pxa168_usb_clk)) { 2833abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay dev_err(&pdev->dev, "Couldn't get USB clock\n"); 2843abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay err = PTR_ERR(drv_data->pxa168_usb_clk); 2853abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay goto err4; 2863abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay } 2873abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay clk_enable(drv_data->pxa168_usb_clk); 2883abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 2893abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay err = pxa168_usb_phy_init(pdev); 2903abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay if (err) { 2913abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay dev_err(&pdev->dev, "USB PHY initialization failed\n"); 2923abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay goto err5; 2933abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay } 2943abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 2953abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay hcd->rsrc_start = res->start; 2963abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay hcd->rsrc_len = resource_size(res); 2973abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay hcd->regs = regs; 2983abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 2993abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay ehci = hcd_to_ehci(hcd); 3003abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay ehci->caps = hcd->regs + 0x100; 3013abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay ehci->regs = hcd->regs + 0x100 + 30235657c4d72925936c7219cc5caac118ca632acc2Tanmay Upadhyay HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); 3033abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); 3043abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay hcd->has_tt = 1; 3053abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay ehci->sbrn = 0x20; 3063abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 3073abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay err = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_DISABLED); 3083abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay if (err) 3093abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay goto err5; 3103abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 3113abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay return 0; 3123abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 3133abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyayerr5: 3143abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay clk_disable(drv_data->pxa168_usb_clk); 3153abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay clk_put(drv_data->pxa168_usb_clk); 3163abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyayerr4: 3173abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay usb_put_hcd(hcd); 3183abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyayerr3: 3193abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay iounmap(regs); 3203abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyayerr2: 3213abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay release_mem_region(res->start, resource_size(res)); 3223abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyayerr1: 3233abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay dev_err(&pdev->dev, "init %s fail, %d\n", 3243abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay dev_name(&pdev->dev), err); 3253abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 3263abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay return err; 3273abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay} 3283abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 3293abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyaystatic int __exit ehci_pxa168_drv_remove(struct platform_device *pdev) 3303abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay{ 3313abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay struct usb_hcd *hcd = platform_get_drvdata(pdev); 3323abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay struct pxa168_usb_drv_data *drv_data = 3333abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay (struct pxa168_usb_drv_data *)hcd->hcd_priv; 3343abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 3353abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay usb_remove_hcd(hcd); 3363abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 3373abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay /* Power down PHY & PLL */ 3383abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay writel(readl(drv_data->usb_phy_reg_base + USB_PHY_CTRL_REG) & (~0x3), 3393abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay drv_data->usb_phy_reg_base + USB_PHY_CTRL_REG); 3403abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 3413abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay clk_disable(drv_data->pxa168_usb_clk); 3423abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay clk_put(drv_data->pxa168_usb_clk); 3433abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 3443abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay iounmap(hcd->regs); 3453abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay release_mem_region(hcd->rsrc_start, hcd->rsrc_len); 3463abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 3473abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay iounmap(drv_data->usb_phy_reg_base); 3483abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay release_mem_region(drv_data->usb_phy_res->start, 3493abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay resource_size(drv_data->usb_phy_res)); 3503abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 3513abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay usb_put_hcd(hcd); 3523abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 3533abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay return 0; 3543abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay} 3553abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 3563abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay UpadhyayMODULE_ALIAS("platform:pxa168-ehci"); 3573abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay 3583abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyaystatic struct platform_driver ehci_pxa168_driver = { 3593abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .probe = ehci_pxa168_drv_probe, 3603abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .remove = __exit_p(ehci_pxa168_drv_remove), 3613abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .shutdown = usb_hcd_platform_shutdown, 3623abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay .driver.name = "pxa168-ehci", 3633abd7f68b28dcf6394c71c998376fc7bc92342c4Tanmay Upadhyay}; 364