cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

omap-usb-host.c (22990B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * omap-usb-host.c - The USBHS core driver for OMAP EHCI & OHCI
      4 *
      5 * Copyright (C) 2011-2013 Texas Instruments Incorporated - https://www.ti.com
      6 * Author: Keshava Munegowda <keshava_mgowda@ti.com>
      7 * Author: Roger Quadros <rogerq@ti.com>
      8 */
      9#include <linux/kernel.h>
     10#include <linux/module.h>
     11#include <linux/types.h>
     12#include <linux/slab.h>
     13#include <linux/delay.h>
     14#include <linux/clk.h>
     15#include <linux/dma-mapping.h>
     16#include <linux/gpio.h>
     17#include <linux/platform_device.h>
     18#include <linux/platform_data/usb-omap.h>
     19#include <linux/pm_runtime.h>
     20#include <linux/of.h>
     21#include <linux/of_platform.h>
     22#include <linux/err.h>
     23
     24#include "omap-usb.h"
     25
     26#define USBHS_DRIVER_NAME	"usbhs_omap"
     27#define OMAP_EHCI_DEVICE	"ehci-omap"
     28#define OMAP_OHCI_DEVICE	"ohci-omap3"
     29
     30/* OMAP USBHOST Register addresses  */
     31
     32/* UHH Register Set */
     33#define	OMAP_UHH_REVISION				(0x00)
     34#define	OMAP_UHH_SYSCONFIG				(0x10)
     35#define	OMAP_UHH_SYSCONFIG_MIDLEMODE			(1 << 12)
     36#define	OMAP_UHH_SYSCONFIG_CACTIVITY			(1 << 8)
     37#define	OMAP_UHH_SYSCONFIG_SIDLEMODE			(1 << 3)
     38#define	OMAP_UHH_SYSCONFIG_ENAWAKEUP			(1 << 2)
     39#define	OMAP_UHH_SYSCONFIG_SOFTRESET			(1 << 1)
     40#define	OMAP_UHH_SYSCONFIG_AUTOIDLE			(1 << 0)
     41
     42#define	OMAP_UHH_SYSSTATUS				(0x14)
     43#define	OMAP_UHH_HOSTCONFIG				(0x40)
     44#define	OMAP_UHH_HOSTCONFIG_ULPI_BYPASS			(1 << 0)
     45#define	OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS		(1 << 0)
     46#define	OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS		(1 << 11)
     47#define	OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS		(1 << 12)
     48#define OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN		(1 << 2)
     49#define OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN		(1 << 3)
     50#define OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN		(1 << 4)
     51#define OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN		(1 << 5)
     52#define OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS		(1 << 8)
     53#define OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS		(1 << 9)
     54#define OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS		(1 << 10)
     55#define OMAP4_UHH_HOSTCONFIG_APP_START_CLK		(1 << 31)
     56
     57/* OMAP4-specific defines */
     58#define OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR		(3 << 2)
     59#define OMAP4_UHH_SYSCONFIG_NOIDLE			(1 << 2)
     60#define OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR		(3 << 4)
     61#define OMAP4_UHH_SYSCONFIG_NOSTDBY			(1 << 4)
     62#define OMAP4_UHH_SYSCONFIG_SOFTRESET			(1 << 0)
     63
     64#define OMAP4_P1_MODE_CLEAR				(3 << 16)
     65#define OMAP4_P1_MODE_TLL				(1 << 16)
     66#define OMAP4_P1_MODE_HSIC				(3 << 16)
     67#define OMAP4_P2_MODE_CLEAR				(3 << 18)
     68#define OMAP4_P2_MODE_TLL				(1 << 18)
     69#define OMAP4_P2_MODE_HSIC				(3 << 18)
     70
     71#define	OMAP_UHH_DEBUG_CSR				(0x44)
     72
     73/* Values of UHH_REVISION - Note: these are not given in the TRM */
     74#define OMAP_USBHS_REV1		0x00000010	/* OMAP3 */
     75#define OMAP_USBHS_REV2		0x50700100	/* OMAP4 */
     76
     77#define is_omap_usbhs_rev1(x)	(x->usbhs_rev == OMAP_USBHS_REV1)
     78#define is_omap_usbhs_rev2(x)	(x->usbhs_rev == OMAP_USBHS_REV2)
     79
     80#define is_ehci_phy_mode(x)	(x == OMAP_EHCI_PORT_MODE_PHY)
     81#define is_ehci_tll_mode(x)	(x == OMAP_EHCI_PORT_MODE_TLL)
     82#define is_ehci_hsic_mode(x)	(x == OMAP_EHCI_PORT_MODE_HSIC)
     83
     84
     85struct usbhs_hcd_omap {
     86	int				nports;
     87	struct clk			**utmi_clk;
     88	struct clk			**hsic60m_clk;
     89	struct clk			**hsic480m_clk;
     90
     91	struct clk			*xclk60mhsp1_ck;
     92	struct clk			*xclk60mhsp2_ck;
     93	struct clk			*utmi_p1_gfclk;
     94	struct clk			*utmi_p2_gfclk;
     95	struct clk			*init_60m_fclk;
     96	struct clk			*ehci_logic_fck;
     97
     98	void __iomem			*uhh_base;
     99
    100	struct usbhs_omap_platform_data	*pdata;
    101
    102	u32				usbhs_rev;
    103};
    104/*-------------------------------------------------------------------------*/
    105
    106static const char usbhs_driver_name[] = USBHS_DRIVER_NAME;
    107static u64 usbhs_dmamask = DMA_BIT_MASK(32);
    108
    109/*-------------------------------------------------------------------------*/
    110
    111static inline void usbhs_write(void __iomem *base, u32 reg, u32 val)
    112{
    113	writel_relaxed(val, base + reg);
    114}
    115
    116static inline u32 usbhs_read(void __iomem *base, u32 reg)
    117{
    118	return readl_relaxed(base + reg);
    119}
    120
    121/*-------------------------------------------------------------------------*/
    122
    123/*
    124 * Map 'enum usbhs_omap_port_mode' found in <linux/platform_data/usb-omap.h>
    125 * to the device tree binding portN-mode found in
    126 * 'Documentation/devicetree/bindings/mfd/omap-usb-host.txt'
    127 */
    128static const char * const port_modes[] = {
    129	[OMAP_USBHS_PORT_MODE_UNUSED]	= "",
    130	[OMAP_EHCI_PORT_MODE_PHY]	= "ehci-phy",
    131	[OMAP_EHCI_PORT_MODE_TLL]	= "ehci-tll",
    132	[OMAP_EHCI_PORT_MODE_HSIC]	= "ehci-hsic",
    133	[OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0]	= "ohci-phy-6pin-datse0",
    134	[OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM]	= "ohci-phy-6pin-dpdm",
    135	[OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0]	= "ohci-phy-3pin-datse0",
    136	[OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM]	= "ohci-phy-4pin-dpdm",
    137	[OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0]	= "ohci-tll-6pin-datse0",
    138	[OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM]	= "ohci-tll-6pin-dpdm",
    139	[OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0]	= "ohci-tll-3pin-datse0",
    140	[OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM]	= "ohci-tll-4pin-dpdm",
    141	[OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0]	= "ohci-tll-2pin-datse0",
    142	[OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM]	= "ohci-tll-2pin-dpdm",
    143};
    144
    145static struct platform_device *omap_usbhs_alloc_child(const char *name,
    146			struct resource	*res, int num_resources, void *pdata,
    147			size_t pdata_size, struct device *dev)
    148{
    149	struct platform_device	*child;
    150	int			ret;
    151
    152	child = platform_device_alloc(name, 0);
    153
    154	if (!child) {
    155		dev_err(dev, "platform_device_alloc %s failed\n", name);
    156		goto err_end;
    157	}
    158
    159	ret = platform_device_add_resources(child, res, num_resources);
    160	if (ret) {
    161		dev_err(dev, "platform_device_add_resources failed\n");
    162		goto err_alloc;
    163	}
    164
    165	ret = platform_device_add_data(child, pdata, pdata_size);
    166	if (ret) {
    167		dev_err(dev, "platform_device_add_data failed\n");
    168		goto err_alloc;
    169	}
    170
    171	child->dev.dma_mask		= &usbhs_dmamask;
    172	dma_set_coherent_mask(&child->dev, DMA_BIT_MASK(32));
    173	child->dev.parent		= dev;
    174
    175	ret = platform_device_add(child);
    176	if (ret) {
    177		dev_err(dev, "platform_device_add failed\n");
    178		goto err_alloc;
    179	}
    180
    181	return child;
    182
    183err_alloc:
    184	platform_device_put(child);
    185
    186err_end:
    187	return NULL;
    188}
    189
    190static int omap_usbhs_alloc_children(struct platform_device *pdev)
    191{
    192	struct device				*dev = &pdev->dev;
    193	struct usbhs_omap_platform_data		*pdata = dev_get_platdata(dev);
    194	struct platform_device			*ehci;
    195	struct platform_device			*ohci;
    196	struct resource				*res;
    197	struct resource				resources[2];
    198	int					ret;
    199
    200	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ehci");
    201	if (!res) {
    202		dev_err(dev, "EHCI get resource IORESOURCE_MEM failed\n");
    203		ret = -ENODEV;
    204		goto err_end;
    205	}
    206	resources[0] = *res;
    207
    208	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ehci-irq");
    209	if (!res) {
    210		dev_err(dev, " EHCI get resource IORESOURCE_IRQ failed\n");
    211		ret = -ENODEV;
    212		goto err_end;
    213	}
    214	resources[1] = *res;
    215
    216	ehci = omap_usbhs_alloc_child(OMAP_EHCI_DEVICE, resources, 2, pdata,
    217		sizeof(*pdata), dev);
    218
    219	if (!ehci) {
    220		dev_err(dev, "omap_usbhs_alloc_child failed\n");
    221		ret = -ENOMEM;
    222		goto err_end;
    223	}
    224
    225	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ohci");
    226	if (!res) {
    227		dev_err(dev, "OHCI get resource IORESOURCE_MEM failed\n");
    228		ret = -ENODEV;
    229		goto err_ehci;
    230	}
    231	resources[0] = *res;
    232
    233	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ohci-irq");
    234	if (!res) {
    235		dev_err(dev, "OHCI get resource IORESOURCE_IRQ failed\n");
    236		ret = -ENODEV;
    237		goto err_ehci;
    238	}
    239	resources[1] = *res;
    240
    241	ohci = omap_usbhs_alloc_child(OMAP_OHCI_DEVICE, resources, 2, pdata,
    242		sizeof(*pdata), dev);
    243	if (!ohci) {
    244		dev_err(dev, "omap_usbhs_alloc_child failed\n");
    245		ret = -ENOMEM;
    246		goto err_ehci;
    247	}
    248
    249	return 0;
    250
    251err_ehci:
    252	platform_device_unregister(ehci);
    253
    254err_end:
    255	return ret;
    256}
    257
    258static bool is_ohci_port(enum usbhs_omap_port_mode pmode)
    259{
    260	switch (pmode) {
    261	case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0:
    262	case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM:
    263	case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0:
    264	case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM:
    265	case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0:
    266	case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM:
    267	case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0:
    268	case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM:
    269	case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0:
    270	case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM:
    271		return true;
    272
    273	default:
    274		return false;
    275	}
    276}
    277
    278static int usbhs_runtime_resume(struct device *dev)
    279{
    280	struct usbhs_hcd_omap		*omap = dev_get_drvdata(dev);
    281	struct usbhs_omap_platform_data	*pdata = omap->pdata;
    282	int i, r;
    283
    284	dev_dbg(dev, "usbhs_runtime_resume\n");
    285
    286	omap_tll_enable(pdata);
    287
    288	if (!IS_ERR(omap->ehci_logic_fck))
    289		clk_prepare_enable(omap->ehci_logic_fck);
    290
    291	for (i = 0; i < omap->nports; i++) {
    292		switch (pdata->port_mode[i]) {
    293		case OMAP_EHCI_PORT_MODE_HSIC:
    294			if (!IS_ERR(omap->hsic60m_clk[i])) {
    295				r = clk_prepare_enable(omap->hsic60m_clk[i]);
    296				if (r) {
    297					dev_err(dev,
    298					 "Can't enable port %d hsic60m clk:%d\n",
    299					 i, r);
    300				}
    301			}
    302
    303			if (!IS_ERR(omap->hsic480m_clk[i])) {
    304				r = clk_prepare_enable(omap->hsic480m_clk[i]);
    305				if (r) {
    306					dev_err(dev,
    307					 "Can't enable port %d hsic480m clk:%d\n",
    308					 i, r);
    309				}
    310			}
    311			fallthrough;	/* as HSIC mode needs utmi_clk */
    312
    313		case OMAP_EHCI_PORT_MODE_TLL:
    314			if (!IS_ERR(omap->utmi_clk[i])) {
    315				r = clk_prepare_enable(omap->utmi_clk[i]);
    316				if (r) {
    317					dev_err(dev,
    318					 "Can't enable port %d clk : %d\n",
    319					 i, r);
    320				}
    321			}
    322			break;
    323		default:
    324			break;
    325		}
    326	}
    327
    328	return 0;
    329}
    330
    331static int usbhs_runtime_suspend(struct device *dev)
    332{
    333	struct usbhs_hcd_omap		*omap = dev_get_drvdata(dev);
    334	struct usbhs_omap_platform_data	*pdata = omap->pdata;
    335	int i;
    336
    337	dev_dbg(dev, "usbhs_runtime_suspend\n");
    338
    339	for (i = 0; i < omap->nports; i++) {
    340		switch (pdata->port_mode[i]) {
    341		case OMAP_EHCI_PORT_MODE_HSIC:
    342			if (!IS_ERR(omap->hsic60m_clk[i]))
    343				clk_disable_unprepare(omap->hsic60m_clk[i]);
    344
    345			if (!IS_ERR(omap->hsic480m_clk[i]))
    346				clk_disable_unprepare(omap->hsic480m_clk[i]);
    347			fallthrough;	/* as utmi_clks were used in HSIC mode */
    348
    349		case OMAP_EHCI_PORT_MODE_TLL:
    350			if (!IS_ERR(omap->utmi_clk[i]))
    351				clk_disable_unprepare(omap->utmi_clk[i]);
    352			break;
    353		default:
    354			break;
    355		}
    356	}
    357
    358	if (!IS_ERR(omap->ehci_logic_fck))
    359		clk_disable_unprepare(omap->ehci_logic_fck);
    360
    361	omap_tll_disable(pdata);
    362
    363	return 0;
    364}
    365
    366static unsigned omap_usbhs_rev1_hostconfig(struct usbhs_hcd_omap *omap,
    367						unsigned reg)
    368{
    369	struct usbhs_omap_platform_data	*pdata = omap->pdata;
    370	int i;
    371
    372	for (i = 0; i < omap->nports; i++) {
    373		switch (pdata->port_mode[i]) {
    374		case OMAP_USBHS_PORT_MODE_UNUSED:
    375			reg &= ~(OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS << i);
    376			break;
    377		case OMAP_EHCI_PORT_MODE_PHY:
    378			if (pdata->single_ulpi_bypass)
    379				break;
    380
    381			if (i == 0)
    382				reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
    383			else
    384				reg &= ~(OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS
    385								<< (i-1));
    386			break;
    387		default:
    388			if (pdata->single_ulpi_bypass)
    389				break;
    390
    391			if (i == 0)
    392				reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS;
    393			else
    394				reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS
    395								<< (i-1);
    396			break;
    397		}
    398	}
    399
    400	if (pdata->single_ulpi_bypass) {
    401		/* bypass ULPI only if none of the ports use PHY mode */
    402		reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
    403
    404		for (i = 0; i < omap->nports; i++) {
    405			if (is_ehci_phy_mode(pdata->port_mode[i])) {
    406				reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS;
    407				break;
    408			}
    409		}
    410	}
    411
    412	return reg;
    413}
    414
    415static unsigned omap_usbhs_rev2_hostconfig(struct usbhs_hcd_omap *omap,
    416						unsigned reg)
    417{
    418	struct usbhs_omap_platform_data	*pdata = omap->pdata;
    419	int i;
    420
    421	for (i = 0; i < omap->nports; i++) {
    422		/* Clear port mode fields for PHY mode */
    423		reg &= ~(OMAP4_P1_MODE_CLEAR << 2 * i);
    424
    425		if (is_ehci_tll_mode(pdata->port_mode[i]) ||
    426				(is_ohci_port(pdata->port_mode[i])))
    427			reg |= OMAP4_P1_MODE_TLL << 2 * i;
    428		else if (is_ehci_hsic_mode(pdata->port_mode[i]))
    429			reg |= OMAP4_P1_MODE_HSIC << 2 * i;
    430	}
    431
    432	return reg;
    433}
    434
    435static void omap_usbhs_init(struct device *dev)
    436{
    437	struct usbhs_hcd_omap		*omap = dev_get_drvdata(dev);
    438	unsigned			reg;
    439
    440	dev_dbg(dev, "starting TI HSUSB Controller\n");
    441
    442	pm_runtime_get_sync(dev);
    443
    444	reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
    445	/* setup ULPI bypass and burst configurations */
    446	reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
    447			| OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN
    448			| OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN);
    449	reg |= OMAP4_UHH_HOSTCONFIG_APP_START_CLK;
    450	reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN;
    451
    452	switch (omap->usbhs_rev) {
    453	case OMAP_USBHS_REV1:
    454		reg = omap_usbhs_rev1_hostconfig(omap, reg);
    455		break;
    456
    457	case OMAP_USBHS_REV2:
    458		reg = omap_usbhs_rev2_hostconfig(omap, reg);
    459		break;
    460
    461	default:	/* newer revisions */
    462		reg = omap_usbhs_rev2_hostconfig(omap, reg);
    463		break;
    464	}
    465
    466	usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg);
    467	dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg);
    468
    469	pm_runtime_put_sync(dev);
    470}
    471
    472static int usbhs_omap_get_dt_pdata(struct device *dev,
    473					struct usbhs_omap_platform_data *pdata)
    474{
    475	int ret, i;
    476	struct device_node *node = dev->of_node;
    477
    478	ret = of_property_read_u32(node, "num-ports", &pdata->nports);
    479	if (ret)
    480		pdata->nports = 0;
    481
    482	if (pdata->nports > OMAP3_HS_USB_PORTS) {
    483		dev_warn(dev, "Too many num_ports <%d> in device tree. Max %d\n",
    484				pdata->nports, OMAP3_HS_USB_PORTS);
    485		return -ENODEV;
    486	}
    487
    488	/* get port modes */
    489	for (i = 0; i < OMAP3_HS_USB_PORTS; i++) {
    490		char prop[11];
    491		const char *mode;
    492
    493		pdata->port_mode[i] = OMAP_USBHS_PORT_MODE_UNUSED;
    494
    495		snprintf(prop, sizeof(prop), "port%d-mode", i + 1);
    496		ret = of_property_read_string(node, prop, &mode);
    497		if (ret < 0)
    498			continue;
    499
    500		/* get 'enum usbhs_omap_port_mode' from port mode string */
    501		ret = match_string(port_modes, ARRAY_SIZE(port_modes), mode);
    502		if (ret < 0) {
    503			dev_warn(dev, "Invalid port%d-mode \"%s\" in device tree\n",
    504					i, mode);
    505			return -ENODEV;
    506		}
    507
    508		dev_dbg(dev, "port%d-mode: %s -> %d\n", i, mode, ret);
    509		pdata->port_mode[i] = ret;
    510	}
    511
    512	/* get flags */
    513	pdata->single_ulpi_bypass = of_property_read_bool(node,
    514						"single-ulpi-bypass");
    515
    516	return 0;
    517}
    518
    519static const struct of_device_id usbhs_child_match_table[] = {
    520	{ .compatible = "ti,ehci-omap", },
    521	{ .compatible = "ti,ohci-omap3", },
    522	{ }
    523};
    524
    525/**
    526 * usbhs_omap_probe - initialize TI-based HCDs
    527 *
    528 * Allocates basic resources for this USB host controller.
    529 *
    530 * @pdev: Pointer to this device's platform device structure
    531 */
    532static int usbhs_omap_probe(struct platform_device *pdev)
    533{
    534	struct device			*dev =  &pdev->dev;
    535	struct usbhs_omap_platform_data	*pdata = dev_get_platdata(dev);
    536	struct usbhs_hcd_omap		*omap;
    537	struct resource			*res;
    538	int				ret = 0;
    539	int				i;
    540	bool				need_logic_fck;
    541
    542	if (dev->of_node) {
    543		/* For DT boot we populate platform data from OF node */
    544		pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
    545		if (!pdata)
    546			return -ENOMEM;
    547
    548		ret = usbhs_omap_get_dt_pdata(dev, pdata);
    549		if (ret)
    550			return ret;
    551
    552		dev->platform_data = pdata;
    553	}
    554
    555	if (!pdata) {
    556		dev_err(dev, "Missing platform data\n");
    557		return -ENODEV;
    558	}
    559
    560	if (pdata->nports > OMAP3_HS_USB_PORTS) {
    561		dev_info(dev, "Too many num_ports <%d> in platform_data. Max %d\n",
    562				pdata->nports, OMAP3_HS_USB_PORTS);
    563		return -ENODEV;
    564	}
    565
    566	omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL);
    567	if (!omap) {
    568		dev_err(dev, "Memory allocation failed\n");
    569		return -ENOMEM;
    570	}
    571
    572	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    573	omap->uhh_base = devm_ioremap_resource(dev, res);
    574	if (IS_ERR(omap->uhh_base))
    575		return PTR_ERR(omap->uhh_base);
    576
    577	omap->pdata = pdata;
    578
    579	/* Initialize the TLL subsystem */
    580	omap_tll_init(pdata);
    581
    582	pm_runtime_enable(dev);
    583
    584	platform_set_drvdata(pdev, omap);
    585	pm_runtime_get_sync(dev);
    586
    587	omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
    588
    589	/* we need to call runtime suspend before we update omap->nports
    590	 * to prevent unbalanced clk_disable()
    591	 */
    592	pm_runtime_put_sync(dev);
    593
    594	/*
    595	 * If platform data contains nports then use that
    596	 * else make out number of ports from USBHS revision
    597	 */
    598	if (pdata->nports) {
    599		omap->nports = pdata->nports;
    600	} else {
    601		switch (omap->usbhs_rev) {
    602		case OMAP_USBHS_REV1:
    603			omap->nports = 3;
    604			break;
    605		case OMAP_USBHS_REV2:
    606			omap->nports = 2;
    607			break;
    608		default:
    609			omap->nports = OMAP3_HS_USB_PORTS;
    610			dev_dbg(dev,
    611			 "USB HOST Rev:0x%x not recognized, assuming %d ports\n",
    612			 omap->usbhs_rev, omap->nports);
    613			break;
    614		}
    615		pdata->nports = omap->nports;
    616	}
    617
    618	i = sizeof(struct clk *) * omap->nports;
    619	omap->utmi_clk = devm_kzalloc(dev, i, GFP_KERNEL);
    620	omap->hsic480m_clk = devm_kzalloc(dev, i, GFP_KERNEL);
    621	omap->hsic60m_clk = devm_kzalloc(dev, i, GFP_KERNEL);
    622
    623	if (!omap->utmi_clk || !omap->hsic480m_clk || !omap->hsic60m_clk) {
    624		dev_err(dev, "Memory allocation failed\n");
    625		ret = -ENOMEM;
    626		goto err_mem;
    627	}
    628
    629	/* Set all clocks as invalid to begin with */
    630	omap->ehci_logic_fck = ERR_PTR(-ENODEV);
    631	omap->init_60m_fclk = ERR_PTR(-ENODEV);
    632	omap->utmi_p1_gfclk = ERR_PTR(-ENODEV);
    633	omap->utmi_p2_gfclk = ERR_PTR(-ENODEV);
    634	omap->xclk60mhsp1_ck = ERR_PTR(-ENODEV);
    635	omap->xclk60mhsp2_ck = ERR_PTR(-ENODEV);
    636
    637	for (i = 0; i < omap->nports; i++) {
    638		omap->utmi_clk[i] = ERR_PTR(-ENODEV);
    639		omap->hsic480m_clk[i] = ERR_PTR(-ENODEV);
    640		omap->hsic60m_clk[i] = ERR_PTR(-ENODEV);
    641	}
    642
    643	/* for OMAP3 i.e. USBHS REV1 */
    644	if (omap->usbhs_rev == OMAP_USBHS_REV1) {
    645		need_logic_fck = false;
    646		for (i = 0; i < omap->nports; i++) {
    647			if (is_ehci_phy_mode(pdata->port_mode[i]) ||
    648			    is_ehci_tll_mode(pdata->port_mode[i]) ||
    649			    is_ehci_hsic_mode(pdata->port_mode[i]))
    650
    651				need_logic_fck |= true;
    652		}
    653
    654		if (need_logic_fck) {
    655			omap->ehci_logic_fck = devm_clk_get(dev,
    656							    "usbhost_120m_fck");
    657			if (IS_ERR(omap->ehci_logic_fck)) {
    658				ret = PTR_ERR(omap->ehci_logic_fck);
    659				dev_err(dev, "usbhost_120m_fck failed:%d\n",
    660					ret);
    661				goto err_mem;
    662			}
    663		}
    664		goto initialize;
    665	}
    666
    667	/* for OMAP4+ i.e. USBHS REV2+ */
    668	omap->utmi_p1_gfclk = devm_clk_get(dev, "utmi_p1_gfclk");
    669	if (IS_ERR(omap->utmi_p1_gfclk)) {
    670		ret = PTR_ERR(omap->utmi_p1_gfclk);
    671		dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
    672		goto err_mem;
    673	}
    674
    675	omap->utmi_p2_gfclk = devm_clk_get(dev, "utmi_p2_gfclk");
    676	if (IS_ERR(omap->utmi_p2_gfclk)) {
    677		ret = PTR_ERR(omap->utmi_p2_gfclk);
    678		dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
    679		goto err_mem;
    680	}
    681
    682	omap->xclk60mhsp1_ck = devm_clk_get(dev, "refclk_60m_ext_p1");
    683	if (IS_ERR(omap->xclk60mhsp1_ck)) {
    684		ret = PTR_ERR(omap->xclk60mhsp1_ck);
    685		dev_err(dev, "refclk_60m_ext_p1 failed error:%d\n", ret);
    686		goto err_mem;
    687	}
    688
    689	omap->xclk60mhsp2_ck = devm_clk_get(dev, "refclk_60m_ext_p2");
    690	if (IS_ERR(omap->xclk60mhsp2_ck)) {
    691		ret = PTR_ERR(omap->xclk60mhsp2_ck);
    692		dev_err(dev, "refclk_60m_ext_p2 failed error:%d\n", ret);
    693		goto err_mem;
    694	}
    695
    696	omap->init_60m_fclk = devm_clk_get(dev, "refclk_60m_int");
    697	if (IS_ERR(omap->init_60m_fclk)) {
    698		ret = PTR_ERR(omap->init_60m_fclk);
    699		dev_err(dev, "refclk_60m_int failed error:%d\n", ret);
    700		goto err_mem;
    701	}
    702
    703	for (i = 0; i < omap->nports; i++) {
    704		char clkname[30];
    705
    706		/* clock names are indexed from 1*/
    707		snprintf(clkname, sizeof(clkname),
    708				"usb_host_hs_utmi_p%d_clk", i + 1);
    709
    710		/* If a clock is not found we won't bail out as not all
    711		 * platforms have all clocks and we can function without
    712		 * them
    713		 */
    714		omap->utmi_clk[i] = devm_clk_get(dev, clkname);
    715		if (IS_ERR(omap->utmi_clk[i])) {
    716			ret = PTR_ERR(omap->utmi_clk[i]);
    717			dev_err(dev, "Failed to get clock : %s : %d\n",
    718				clkname, ret);
    719			goto err_mem;
    720		}
    721
    722		snprintf(clkname, sizeof(clkname),
    723				"usb_host_hs_hsic480m_p%d_clk", i + 1);
    724		omap->hsic480m_clk[i] = devm_clk_get(dev, clkname);
    725		if (IS_ERR(omap->hsic480m_clk[i])) {
    726			ret = PTR_ERR(omap->hsic480m_clk[i]);
    727			dev_err(dev, "Failed to get clock : %s : %d\n",
    728				clkname, ret);
    729			goto err_mem;
    730		}
    731
    732		snprintf(clkname, sizeof(clkname),
    733				"usb_host_hs_hsic60m_p%d_clk", i + 1);
    734		omap->hsic60m_clk[i] = devm_clk_get(dev, clkname);
    735		if (IS_ERR(omap->hsic60m_clk[i])) {
    736			ret = PTR_ERR(omap->hsic60m_clk[i]);
    737			dev_err(dev, "Failed to get clock : %s : %d\n",
    738				clkname, ret);
    739			goto err_mem;
    740		}
    741	}
    742
    743	if (is_ehci_phy_mode(pdata->port_mode[0])) {
    744		ret = clk_set_parent(omap->utmi_p1_gfclk,
    745					omap->xclk60mhsp1_ck);
    746		if (ret != 0) {
    747			dev_err(dev, "xclk60mhsp1_ck set parent failed: %d\n",
    748				ret);
    749			goto err_mem;
    750		}
    751	} else if (is_ehci_tll_mode(pdata->port_mode[0])) {
    752		ret = clk_set_parent(omap->utmi_p1_gfclk,
    753					omap->init_60m_fclk);
    754		if (ret != 0) {
    755			dev_err(dev, "P0 init_60m_fclk set parent failed: %d\n",
    756				ret);
    757			goto err_mem;
    758		}
    759	}
    760
    761	if (is_ehci_phy_mode(pdata->port_mode[1])) {
    762		ret = clk_set_parent(omap->utmi_p2_gfclk,
    763					omap->xclk60mhsp2_ck);
    764		if (ret != 0) {
    765			dev_err(dev, "xclk60mhsp2_ck set parent failed: %d\n",
    766				ret);
    767			goto err_mem;
    768		}
    769	} else if (is_ehci_tll_mode(pdata->port_mode[1])) {
    770		ret = clk_set_parent(omap->utmi_p2_gfclk,
    771						omap->init_60m_fclk);
    772		if (ret != 0) {
    773			dev_err(dev, "P1 init_60m_fclk set parent failed: %d\n",
    774				ret);
    775			goto err_mem;
    776		}
    777	}
    778
    779initialize:
    780	omap_usbhs_init(dev);
    781
    782	if (dev->of_node) {
    783		ret = of_platform_populate(dev->of_node,
    784				usbhs_child_match_table, NULL, dev);
    785
    786		if (ret) {
    787			dev_err(dev, "Failed to create DT children: %d\n", ret);
    788			goto err_mem;
    789		}
    790
    791	} else {
    792		ret = omap_usbhs_alloc_children(pdev);
    793		if (ret) {
    794			dev_err(dev, "omap_usbhs_alloc_children failed: %d\n",
    795						ret);
    796			goto err_mem;
    797		}
    798	}
    799
    800	return 0;
    801
    802err_mem:
    803	pm_runtime_disable(dev);
    804
    805	return ret;
    806}
    807
    808static int usbhs_omap_remove_child(struct device *dev, void *data)
    809{
    810	dev_info(dev, "unregistering\n");
    811	platform_device_unregister(to_platform_device(dev));
    812	return 0;
    813}
    814
    815/**
    816 * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs
    817 * @pdev: USB Host Controller being removed
    818 *
    819 * Reverses the effect of usbhs_omap_probe().
    820 */
    821static int usbhs_omap_remove(struct platform_device *pdev)
    822{
    823	pm_runtime_disable(&pdev->dev);
    824
    825	/* remove children */
    826	device_for_each_child(&pdev->dev, NULL, usbhs_omap_remove_child);
    827	return 0;
    828}
    829
    830static const struct dev_pm_ops usbhsomap_dev_pm_ops = {
    831	.runtime_suspend	= usbhs_runtime_suspend,
    832	.runtime_resume		= usbhs_runtime_resume,
    833};
    834
    835static const struct of_device_id usbhs_omap_dt_ids[] = {
    836	{ .compatible = "ti,usbhs-host" },
    837	{ }
    838};
    839
    840MODULE_DEVICE_TABLE(of, usbhs_omap_dt_ids);
    841
    842
    843static struct platform_driver usbhs_omap_driver = {
    844	.driver = {
    845		.name		= usbhs_driver_name,
    846		.pm		= &usbhsomap_dev_pm_ops,
    847		.of_match_table = usbhs_omap_dt_ids,
    848	},
    849	.probe		= usbhs_omap_probe,
    850	.remove		= usbhs_omap_remove,
    851};
    852
    853MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>");
    854MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>");
    855MODULE_ALIAS("platform:" USBHS_DRIVER_NAME);
    856MODULE_LICENSE("GPL v2");
    857MODULE_DESCRIPTION("usb host common core driver for omap EHCI and OHCI");
    858
    859static int omap_usbhs_drvinit(void)
    860{
    861	return platform_driver_register(&usbhs_omap_driver);
    862}
    863
    864/*
    865 * init before ehci and ohci drivers;
    866 * The usbhs core driver should be initialized much before
    867 * the omap ehci and ohci probe functions are called.
    868 * This usbhs core driver should be initialized after
    869 * usb tll driver
    870 */
    871fs_initcall_sync(omap_usbhs_drvinit);
    872
    873static void omap_usbhs_drvexit(void)
    874{
    875	platform_driver_unregister(&usbhs_omap_driver);
    876}
    877module_exit(omap_usbhs_drvexit);