cregit-Linux how code gets into the kernel

Release 4.11 drivers/usb/host/ehci-omap.c

Directory: drivers/usb/host
/*
 * ehci-omap.c - driver for USBHOST on OMAP3/4 processors
 *
 * Bus Glue for the EHCI controllers in OMAP3/4
 * Tested on several OMAP3 boards, and OMAP4 Pandaboard
 *
 * Copyright (C) 2007-2013 Texas Instruments, Inc.
 *      Author: Vikram Pandita <vikram.pandita@ti.com>
 *      Author: Anand Gadiyar <gadiyar@ti.com>
 *      Author: Keshava Munegowda <keshava_mgowda@ti.com>
 *      Author: Roger Quadros <rogerq@ti.com>
 *
 * Copyright (C) 2009 Nokia Corporation
 *      Contact: Felipe Balbi <felipe.balbi@nokia.com>
 *
 * Based on "ehci-fsl.c" and "ehci-au1xxx.c" ehci glue layers
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/usb/ulpi.h>
#include <linux/pm_runtime.h>
#include <linux/gpio.h>
#include <linux/clk.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <linux/of.h>
#include <linux/dma-mapping.h>

#include "ehci.h"

#include <linux/platform_data/usb-omap.h>

/* EHCI Register Set */

#define EHCI_INSNREG04					(0xA0)

#define EHCI_INSNREG04_DISABLE_UNSUSPEND		(1 << 5)

#define	EHCI_INSNREG05_ULPI				(0xA4)

#define	EHCI_INSNREG05_ULPI_CONTROL_SHIFT		31

#define	EHCI_INSNREG05_ULPI_PORTSEL_SHIFT		24

#define	EHCI_INSNREG05_ULPI_OPSEL_SHIFT			22

#define	EHCI_INSNREG05_ULPI_REGADD_SHIFT		16

#define	EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT		8

#define	EHCI_INSNREG05_ULPI_WRDATA_SHIFT		0


#define DRIVER_DESC "OMAP-EHCI Host Controller driver"


static const char hcd_name[] = "ehci-omap";

/*-------------------------------------------------------------------------*/


struct omap_hcd {
	
struct usb_phy *phy[OMAP3_HS_USB_PORTS]; /* one PHY for each port */
	
int nports;
};


static inline void ehci_write(void __iomem *base, u32 reg, u32 val) { __raw_writel(val, base + reg); }

Contributors

PersonTokensPropCommitsCommitProp
Keshava Munegowda2592.59%150.00%
Felipe Balbi27.41%150.00%
Total27100.00%2100.00%


static inline u32 ehci_read(void __iomem *base, u32 reg) { return __raw_readl(base + reg); }

Contributors

PersonTokensPropCommitsCommitProp
Felipe Balbi1252.17%150.00%
Keshava Munegowda1147.83%150.00%
Total23100.00%2100.00%

/* configure so an HC device and id are always provided */ /* always called with process context; sleeping is OK */ static struct hc_driver __read_mostly ehci_omap_hc_driver; static const struct ehci_driver_overrides ehci_omap_overrides __initconst = { .extra_priv_size = sizeof(struct omap_hcd), }; /** * ehci_hcd_omap_probe - initialize TI-based HCDs * * Allocates basic resources for this USB host controller, and * then invokes the start() method for the HCD associated with it * through the hotplug entry's driver_data. */
static int ehci_hcd_omap_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct usbhs_omap_platform_data *pdata = dev_get_platdata(dev); struct resource *res; struct usb_hcd *hcd; void __iomem *regs; int ret; int irq; int i; struct omap_hcd *omap; if (usb_disabled()) return -ENODEV; if (!dev->parent) { dev_err(dev, "Missing parent device\n"); return -ENODEV; } /* For DT boot, get platform data from parent. i.e. usbhshost */ if (dev->of_node) { pdata = dev_get_platdata(dev->parent); dev->platform_data = pdata; } if (!pdata) { dev_err(dev, "Missing platform data\n"); return -ENODEV; } irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(dev, "EHCI irq failed\n"); return -ENODEV; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(dev, res); if (IS_ERR(regs)) return PTR_ERR(regs); /* * Right now device-tree probed devices don't get dma_mask set. * Since shared usb code relies on it, set it here for now. * Once we have dma capability bindings this can go away. */ ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); if (ret) return ret; ret = -ENODEV; hcd = usb_create_hcd(&ehci_omap_hc_driver, dev, dev_name(dev)); if (!hcd) { dev_err(dev, "Failed to create HCD\n"); return -ENOMEM; } hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); hcd->regs = regs; hcd_to_ehci(hcd)->caps = regs; omap = (struct omap_hcd *)hcd_to_ehci(hcd)->priv; omap->nports = pdata->nports; platform_set_drvdata(pdev, hcd); /* get the PHY devices if needed */ for (i = 0 ; i < omap->nports ; i++) { struct usb_phy *phy; /* get the PHY device */ if (dev->of_node) phy = devm_usb_get_phy_by_phandle(dev, "phys", i); else phy = devm_usb_get_phy_dev(dev, i); if (IS_ERR(phy)) { /* Don't bail out if PHY is not absolutely necessary */ if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY) continue; ret = PTR_ERR(phy); dev_err(dev, "Can't get PHY device for port %d: %d\n", i, ret); goto err_phy; } omap->phy[i] = phy; if (pdata->port_mode[i] == OMAP_EHCI_PORT_MODE_PHY) { usb_phy_init(omap->phy[i]); /* bring PHY out of suspend */ usb_phy_set_suspend(omap->phy[i], 0); } } pm_runtime_enable(dev); pm_runtime_get_sync(dev); /* * An undocumented "feature" in the OMAP3 EHCI controller, * causes suspended ports to be taken out of suspend when * the USBCMD.Run/Stop bit is cleared (for example when * we do ehci_bus_suspend). * This breaks suspend-resume if the root-hub is allowed * to suspend. Writing 1 to this undocumented register bit * disables this feature and restores normal behavior. */ ehci_write(regs, EHCI_INSNREG04, EHCI_INSNREG04_DISABLE_UNSUSPEND); ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret) { dev_err(dev, "failed to add hcd with err %d\n", ret); goto err_pm_runtime; } device_wakeup_enable(hcd->self.controller); /* * Bring PHYs out of reset for non PHY modes. * Even though HSIC mode is a PHY-less mode, the reset * line exists between the chips and can be modelled * as a PHY device for reset control. */ for (i = 0; i < omap->nports; i++) { if (!omap->phy[i] || pdata->port_mode[i] == OMAP_EHCI_PORT_MODE_PHY) continue; usb_phy_init(omap->phy[i]); /* bring PHY out of suspend */ usb_phy_set_suspend(omap->phy[i], 0); } return 0; err_pm_runtime: pm_runtime_put_sync(dev); err_phy: for (i = 0; i < omap->nports; i++) { if (omap->phy[i]) usb_phy_shutdown(omap->phy[i]); } usb_put_hcd(hcd); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Roger Quadros33854.08%940.91%
Felipe Balbi10616.96%14.55%
Keshava Munegowda8914.24%313.64%
Russ Dill365.76%29.09%
Russell King182.88%29.09%
Ajay Kumar Gupta172.72%14.55%
Peter Chen91.44%14.55%
Jingoo Han60.96%14.55%
Stephen Warren50.80%14.55%
Jarkko Nikula10.16%14.55%
Total625100.00%22100.00%

/** * ehci_hcd_omap_remove - shutdown processing for EHCI HCDs * @pdev: USB Host Controller being removed * * Reverses the effect of usb_ehci_hcd_omap_probe(), first invoking * the HCD's stop() method. It is always called from a thread * context, normally "rmmod", "apmd", or something similar. */
static int ehci_hcd_omap_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct usb_hcd *hcd = dev_get_drvdata(dev); struct omap_hcd *omap = (struct omap_hcd *)hcd_to_ehci(hcd)->priv; int i; usb_remove_hcd(hcd); for (i = 0; i < omap->nports; i++) { if (omap->phy[i]) usb_phy_shutdown(omap->phy[i]); } usb_put_hcd(hcd); pm_runtime_put_sync(dev); pm_runtime_disable(dev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Roger Quadros5650.91%125.00%
Felipe Balbi3733.64%125.00%
Keshava Munegowda1715.45%250.00%
Total110100.00%4100.00%

static const struct of_device_id omap_ehci_dt_ids[] = { { .compatible = "ti,ehci-omap" }, { } }; MODULE_DEVICE_TABLE(of, omap_ehci_dt_ids); static struct platform_driver ehci_hcd_omap_driver = { .probe = ehci_hcd_omap_probe, .remove = ehci_hcd_omap_remove, .shutdown = usb_hcd_platform_shutdown, /*.suspend = ehci_hcd_omap_suspend, */ /*.resume = ehci_hcd_omap_resume, */ .driver = { .name = hcd_name, .of_match_table = omap_ehci_dt_ids, } }; /*-------------------------------------------------------------------------*/
static int __init ehci_omap_init(void) { if (usb_disabled()) return -ENODEV; pr_info("%s: " DRIVER_DESC "\n", hcd_name); ehci_init_driver(&ehci_omap_hc_driver, &ehci_omap_overrides); return platform_driver_register(&ehci_hcd_omap_driver); }

Contributors

PersonTokensPropCommitsCommitProp
Alan Stern3888.37%150.00%
Felipe Balbi511.63%150.00%
Total43100.00%2100.00%

module_init(ehci_omap_init);
static void __exit ehci_omap_cleanup(void) { platform_driver_unregister(&ehci_hcd_omap_driver); }

Contributors

PersonTokensPropCommitsCommitProp
Alan Stern15100.00%1100.00%
Total15100.00%1100.00%

module_exit(ehci_omap_cleanup); MODULE_ALIAS("platform:ehci-omap"); MODULE_AUTHOR("Texas Instruments, Inc."); MODULE_AUTHOR("Felipe Balbi <felipe.balbi@nokia.com>"); MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>"); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
Roger Quadros46242.42%1135.48%
Felipe Balbi24022.04%26.45%
Keshava Munegowda16715.34%412.90%
Alan Stern11810.84%13.23%
Russ Dill363.31%26.45%
Ajay Kumar Gupta201.84%26.45%
Russell King181.65%26.45%
Peter Chen90.83%13.23%
Jingoo Han60.55%13.23%
Stephen Warren50.46%13.23%
Tejun Heo30.28%13.23%
Anand Gadiyar30.28%13.23%
Nico Pitre10.09%13.23%
Jarkko Nikula10.09%13.23%
Total1089100.00%31100.00%
Directory: drivers/usb/host
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.