Release 4.7 drivers/usb/host/ehci-tegra.c
/*
* EHCI-compliant USB host controller driver for NVIDIA Tegra 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 <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/usb/ehci_def.h>
#include <linux/usb/tegra_usb_phy.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <linux/usb/otg.h>
#include "ehci.h"
#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
#define TEGRA_USB_DMA_ALIGN 32
#define DRIVER_DESC "Tegra EHCI driver"
#define DRV_NAME "tegra-ehci"
static struct hc_driver __read_mostly tegra_ehci_hc_driver;
static bool usb1_reset_attempted;
struct tegra_ehci_soc_config {
bool has_hostpc;
};
struct tegra_ehci_hcd {
struct tegra_usb_phy *phy;
struct clk *clk;
struct reset_control *rst;
int port_resuming;
bool needs_double_reset;
enum tegra_usb_phy_port_speed port_speed;
};
/*
* The 1st USB controller contains some UTMI pad registers that are global for
* all the controllers on the chip. Those registers are also cleared when
* reset is asserted to the 1st controller. This means that the 1st controller
* can only be reset when no other controlled has finished probing. So we'll
* reset the 1st controller before doing any other setup on any of the
* controllers, and then never again.
*
* Since this is a PHY issue, the Tegra PHY driver should probably be doing
* the resetting of the USB controllers. But to keep compatibility with old
* device trees that don't have reset phandles in the PHYs, do it here.
* Those old DTs will be vulnerable to total USB breakage if the 1st EHCI
* device isn't the first one to finish probing, so warn them.
*/
static int tegra_reset_usb_controller(struct platform_device *pdev)
{
struct device_node *phy_np;
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct tegra_ehci_hcd *tegra =
(struct tegra_ehci_hcd *)hcd_to_ehci(hcd)->priv;
bool has_utmi_pad_registers = false;
phy_np = of_parse_phandle(pdev->dev.of_node, "nvidia,phy", 0);
if (!phy_np)
return -ENOENT;
if (of_property_read_bool(phy_np, "nvidia,has-utmi-pad-registers"))
has_utmi_pad_registers = true;
if (!usb1_reset_attempted) {
struct reset_control *usb1_reset;
if (!has_utmi_pad_registers)
usb1_reset = of_reset_control_get(phy_np, "utmi-pads");
else
usb1_reset = tegra->rst;
if (IS_ERR(usb1_reset)) {
dev_warn(&pdev->dev,
"can't get utmi-pads reset from the PHY\n");
dev_warn(&pdev->dev,
"continuing, but please update your DT\n");
} else {
reset_control_assert(usb1_reset);
udelay(1);
reset_control_deassert(usb1_reset);
if (!has_utmi_pad_registers)
reset_control_put(usb1_reset);
}
usb1_reset_attempted = true;
}
if (!has_utmi_pad_registers) {
reset_control_assert(tegra->rst);
udelay(1);
reset_control_deassert(tegra->rst);
}
of_node_put(phy_np);
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
tuomas tynkkynen | tuomas tynkkynen | 175 | 82.16% | 1 | 33.33% |
thierry reding | thierry reding | 38 | 17.84% | 2 | 66.67% |
| Total | 213 | 100.00% | 3 | 100.00% |
static int tegra_ehci_internal_port_reset(
struct ehci_hcd *ehci,
u32 __iomem *portsc_reg
)
{
u32 temp;
unsigned long flags;
int retval = 0;
int i, tries;
u32 saved_usbintr;
spin_lock_irqsave(&ehci->lock, flags);
saved_usbintr = ehci_readl(ehci, &ehci->regs->intr_enable);
/* disable USB interrupt */
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
spin_unlock_irqrestore(&ehci->lock, flags);
/*
* Here we have to do Port Reset at most twice for
* Port Enable bit to be set.
*/
for (i = 0; i < 2; i++) {
temp = ehci_readl(ehci, portsc_reg);
temp |= PORT_RESET;
ehci_writel(ehci, temp, portsc_reg);
mdelay(10);
temp &= ~PORT_RESET;
ehci_writel(ehci, temp, portsc_reg);
mdelay(1);
tries = 100;
do {
mdelay(1);
/*
* Up to this point, Port Enable bit is
* expected to be set after 2 ms waiting.
* USB1 usually takes extra 45 ms, for safety,
* we take 100 ms as timeout.
*/
temp = ehci_readl(ehci, portsc_reg);
} while (!(temp & PORT_PE) && tries--);
if (temp & PORT_PE)
break;
}
if (i == 2)
retval = -ETIMEDOUT;
/*
* Clear Connect Status Change bit if it's set.
* We can't clear PORT_PEC. It will also cause PORT_PE to be cleared.
*/
if (temp & PORT_CSC)
ehci_writel(ehci, PORT_CSC, portsc_reg);
/*
* Write to clear any interrupt status bits that might be set
* during port reset.
*/
temp = ehci_readl(ehci, &ehci->regs->status);
ehci_writel(ehci, temp, &ehci->regs->status);
/* restore original interrupt enable bits */
ehci_writel(ehci, saved_usbintr, &ehci->regs->intr_enable);
return retval;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jim lin | jim lin | 263 | 100.00% | 1 | 100.00% |
| Total | 263 | 100.00% | 1 | 100.00% |
static int tegra_ehci_hub_control(
struct usb_hcd *hcd,
u16 typeReq,
u16 wValue,
u16 wIndex,
char *buf,
u16 wLength
)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct tegra_ehci_hcd *tegra = (struct tegra_ehci_hcd *)ehci->priv;
u32 __iomem *status_reg;
u32 temp;
unsigned long flags;
int retval = 0;
status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1];
spin_lock_irqsave(&ehci->lock, flags);
if (typeReq == GetPortStatus) {
temp = ehci_readl(ehci, status_reg);
if (tegra->port_resuming && !(temp & PORT_SUSPEND)) {
/* Resume completed, re-enable disconnect detection */
tegra->port_resuming = 0;
tegra_usb_phy_postresume(hcd->usb_phy);
}
}
else if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) {
temp = ehci_readl(ehci, status_reg);
if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) {
retval = -EPIPE;
goto done;
}
temp &= ~(PORT_RWC_BITS | PORT_WKCONN_E);
temp |= PORT_WKDISC_E | PORT_WKOC_E;
ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
/*
* If a transaction is in progress, there may be a delay in
* suspending the port. Poll until the port is suspended.
*/
if (ehci_handshake(ehci, status_reg, PORT_SUSPEND,
PORT_SUSPEND, 5000))
pr_err("%s: timeout waiting for SUSPEND\n", __func__);
set_bit((wIndex & 0xff) - 1, &ehci->suspended_ports);
goto done;
}
/* For USB1 port we need to issue Port Reset twice internally */
if (tegra->needs_double_reset &&
(typeReq == SetPortFeature && wValue == USB_PORT_FEAT_RESET)) {
spin_unlock_irqrestore(&ehci->lock, flags);
return tegra_ehci_internal_port_reset(ehci, status_reg);
}
/*
* Tegra host controller will time the resume operation to clear the bit
* when the port control state switches to HS or FS Idle. This behavior
* is different from EHCI where the host controller driver is required
* to set this bit to a zero after the resume duration is timed in the
* driver.
*/
else if (typeReq == ClearPortFeature &&
wValue == USB_PORT_FEAT_SUSPEND) {
temp = ehci_readl(ehci, status_reg);
if ((temp & PORT_RESET) || !(temp & PORT_PE)) {
retval = -EPIPE;
goto done;
}
if (!(temp & PORT_SUSPEND))
goto done;
/* Disable disconnect detection during port resume */
tegra_usb_phy_preresume(hcd->usb_phy);
ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25);
temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
/* start resume signalling */
ehci_writel(ehci, temp | PORT_RESUME, status_reg);
set_bit(wIndex-1, &ehci->resuming_ports);
spin_unlock_irqrestore(&ehci->lock, flags);
msleep(20);
spin_lock_irqsave(&ehci->lock, flags);
/* Poll until the controller clears RESUME and SUSPEND */
if (ehci_handshake(ehci, status_reg, PORT_RESUME, 0, 2000))
pr_err("%s: timeout waiting for RESUME\n", __func__);
if (ehci_handshake(ehci, status_reg, PORT_SUSPEND, 0, 2000))
pr_err("%s: timeout waiting for SUSPEND\n", __func__);
ehci->reset_done[wIndex-1] = 0;
clear_bit(wIndex-1, &ehci->resuming_ports);
tegra->port_resuming = 1;
goto done;
}
spin_unlock_irqrestore(&ehci->lock, flags);
/* Handle the hub control events here */
return ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
done:
spin_unlock_irqrestore(&ehci->lock, flags);
return retval;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
benoit goby | benoit goby | 478 | 85.66% | 1 | 10.00% |
jim lin | jim lin | 36 | 6.45% | 1 | 10.00% |
alan stern | alan stern | 24 | 4.30% | 1 | 10.00% |
stephen warren | stephen warren | 11 | 1.97% | 2 | 20.00% |
venu byravarasu | venu byravarasu | 3 | 0.54% | 2 | 20.00% |
manjunath goudar | manjunath goudar | 3 | 0.54% | 1 | 10.00% |
antoine tenart | antoine tenart | 2 | 0.36% | 1 | 10.00% |
laurent pinchart | laurent pinchart | 1 | 0.18% | 1 | 10.00% |
| Total | 558 | 100.00% | 10 | 100.00% |
struct dma_aligned_buffer {
void *kmalloc_ptr;
void *old_xfer_buffer;
u8 data[0];
};
static void free_dma_aligned_buffer(struct urb *urb)
{
struct dma_aligned_buffer *temp;
size_t length;
if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER))
return;
temp = container_of(urb->transfer_buffer,
struct dma_aligned_buffer, data);
if (usb_urb_dir_in(urb)) {
if (usb_pipeisoc(urb->pipe))
length = urb->transfer_buffer_length;
else
length = urb->actual_length;
memcpy(temp->old_xfer_buffer, temp->data, length);
}
urb->transfer_buffer = temp->old_xfer_buffer;
kfree(temp->kmalloc_ptr);
urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
alan stern | alan stern | 56 | 50.45% | 1 | 25.00% |
johan hovold | johan hovold | 28 | 25.23% | 1 | 25.00% |
benoit goby | benoit goby | 22 | 19.82% | 1 | 25.00% |
greg kroah-hartman | greg kroah-hartman | 5 | 4.50% | 1 | 25.00% |
| Total | 111 | 100.00% | 4 | 100.00% |
static int alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags)
{
struct dma_aligned_buffer *temp, *kmalloc_ptr;
size_t kmalloc_size;
if (urb->num_sgs || urb->sg ||
urb->transfer_buffer_length == 0 ||
!((uintptr_t)urb->transfer_buffer & (TEGRA_USB_DMA_ALIGN - 1)))
return 0;
/* Allocate a buffer with enough padding for alignment */
kmalloc_size = urb->transfer_buffer_length +
sizeof(struct dma_aligned_buffer) + TEGRA_USB_DMA_ALIGN - 1;
kmalloc_ptr = kmalloc(kmalloc_size, mem_flags);
if (!kmalloc_ptr)
return -ENOMEM;
/* Position our struct dma_aligned_buffer such that data is aligned */
temp = PTR_ALIGN(kmalloc_ptr + 1, TEGRA_USB_DMA_ALIGN) - 1;
temp->kmalloc_ptr = kmalloc_ptr;
temp->old_xfer_buffer = urb->transfer_buffer;
if (usb_urb_dir_out(urb))
memcpy(temp->data, urb->transfer_buffer,
urb->transfer_buffer_length);
urb->transfer_buffer = temp->data;
urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER;
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
alan stern | alan stern | 118 | 72.84% | 1 | 33.33% |
benoit goby | benoit goby | 38 | 23.46% | 1 | 33.33% |
greg kroah-hartman | greg kroah-hartman | 6 | 3.70% | 1 | 33.33% |
| Total | 162 | 100.00% | 3 | 100.00% |
static int tegra_ehci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
gfp_t mem_flags)
{
int ret;
ret = alloc_dma_aligned_buffer(urb, mem_flags);
if (ret)
return ret;
ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
if (ret)
free_dma_aligned_buffer(urb);
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
benoit goby | benoit goby | 36 | 59.02% | 1 | 33.33% |
alan stern | alan stern | 23 | 37.70% | 1 | 33.33% |
greg kroah-hartman | greg kroah-hartman | 2 | 3.28% | 1 | 33.33% |
| Total | 61 | 100.00% | 3 | 100.00% |
static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
{
usb_hcd_unmap_urb_for_dma(hcd, urb);
free_dma_aligned_buffer(urb);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
benoit goby | benoit goby | 16 | 57.14% | 1 | 33.33% |
alan stern | alan stern | 11 | 39.29% | 1 | 33.33% |
greg kroah-hartman | greg kroah-hartman | 1 | 3.57% | 1 | 33.33% |
| Total | 28 | 100.00% | 3 | 100.00% |
static const struct tegra_ehci_soc_config tegra30_soc_config = {
.has_hostpc = true,
};
static const struct tegra_ehci_soc_config tegra20_soc_config = {
.has_hostpc = false,
};
static const struct of_device_id tegra_ehci_of_match[] = {
{ .compatible = "nvidia,tegra30-ehci", .data = &tegra30_soc_config },
{ .compatible = "nvidia,tegra20-ehci", .data = &tegra20_soc_config },
{ },
};
static int tegra_ehci_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
const struct tegra_ehci_soc_config *soc_config;
struct resource *res;
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
struct tegra_ehci_hcd *tegra;
int err = 0;
int irq;
struct usb_phy *u_phy;
match = of_match_device(tegra_ehci_of_match, &pdev->dev);
if (!match) {
dev_err(&pdev->dev, "Error: No device match found\n");
return -ENODEV;
}
soc_config = match->data;
/* 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.
*/
err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (err)
return err;
hcd = usb_create_hcd(&tegra_ehci_hc_driver, &pdev->dev,
dev_name(&pdev->dev));
if (!hcd) {
dev_err(&pdev->dev, "Unable to create HCD\n");
return -ENOMEM;
}
platform_set_drvdata(pdev, hcd);
ehci = hcd_to_ehci(hcd);
tegra = (struct tegra_ehci_hcd *)ehci->priv;
hcd->has_tt = 1;
tegra->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(tegra->clk)) {
dev_err(&pdev->dev, "Can't get ehci clock\n");
err = PTR_ERR(tegra->clk);
goto cleanup_hcd_create;
}
tegra->rst = devm_reset_control_get(&pdev->dev, "usb");
if (IS_ERR(tegra->rst)) {
dev_err(&pdev->dev, "Can't get ehci reset\n");
err = PTR_ERR(tegra->rst);
goto cleanup_hcd_create;
}
err = clk_prepare_enable(tegra->clk);
if (err)
goto cleanup_hcd_create;
err = tegra_reset_usb_controller(pdev);
if (err)
goto cleanup_clk_en;
u_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0);
if (IS_ERR(u_phy)) {
err = -EPROBE_DEFER;
goto cleanup_clk_en;
}
hcd->usb_phy = u_phy;
tegra->needs_double_reset = of_property_read_bool(pdev->dev.of_node,
"nvidia,needs-double-reset");
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(hcd->regs)) {
err = PTR_ERR(hcd->regs);
goto cleanup_clk_en;
}
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
ehci->caps = hcd->regs + 0x100;
ehci->has_hostpc = soc_config->has_hostpc;
err = usb_phy_init(hcd->usb_phy);
if (err) {
dev_err(&pdev->dev, "Failed to initialize phy\n");
goto cleanup_clk_en;
}
u_phy->otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg),
GFP_KERNEL);
if (!u_phy->otg) {
err = -ENOMEM;
goto cleanup_phy;
}
u_phy->otg->host = hcd_to_bus(hcd);
err = usb_phy_set_suspend(hcd->usb_phy, 0);
if (err) {
dev_err(&pdev->dev, "Failed to power on the phy\n");
goto cleanup_phy;
}
irq = platform_get_irq(pdev, 0);
if (!irq) {
dev_err(&pdev->dev, "Failed to get IRQ\n");
err = -ENODEV;
goto cleanup_phy;
}
otg_set_host(u_phy->otg, &hcd->self);
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err) {
dev_err(&pdev->dev, "Failed to add USB HCD\n");
goto cleanup_otg_set_host;
}
device_wakeup_enable(hcd->self.controller);
return err;
cleanup_otg_set_host:
otg_set_host(u_phy->otg, NULL);
cleanup_phy:
usb_phy_shutdown(hcd->usb_phy);
cleanup_clk_en:
clk_disable_unprepare(tegra->clk);
cleanup_hcd_create:
usb_put_hcd(hcd);
return err;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
benoit goby | benoit goby | 270 | 39.53% | 1 | 3.45% |
stephen warren | stephen warren | 141 | 20.64% | 3 | 10.34% |
venu byravarasu | venu byravarasu | 105 | 15.37% | 6 | 20.69% |
tuomas tynkkynen | tuomas tynkkynen | 77 | 11.27% | 4 | 13.79% |
varka bhadram | varka bhadram | 17 | 2.49% | 1 | 3.45% |
russell king | russell king | 12 | 1.76% | 2 | 6.90% |
julia lawall | julia lawall | 11 | 1.61% | 1 | 3.45% |
manjunath goudar | manjunath goudar | 10 | 1.46% | 1 | 3.45% |
peter chen | peter chen | 9 | 1.32% | 1 | 3.45% |
vivek gautam | vivek gautam | 9 | 1.32% | 1 | 3.45% |
olof johansson | olof johansson | 6 | 0.88% | 1 | 3.45% |
antoine tenart | antoine tenart | 4 | 0.59% | 1 | 3.45% |
heikki krogerus | heikki krogerus | 4 | 0.59% | 1 | 3.45% |
mikko perttunen | mikko perttunen | 2 | 0.29% | 1 | 3.45% |
vince hsu | vince hsu | 2 | 0.29% | 1 | 3.45% |
thierry reding | thierry reding | 2 | 0.29% | 1 | 3.45% |
prashant gaikwad | prashant gaikwad | 1 | 0.15% | 1 | 3.45% |
wei yongjun | wei yongjun | 1 | 0.15% | 1 | 3.45% |
| Total | 683 | 100.00% | 29 | 100.00% |
static int tegra_ehci_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct tegra_ehci_hcd *tegra =
(struct tegra_ehci_hcd *)hcd_to_ehci(hcd)->priv;
otg_set_host(hcd->usb_phy->otg, NULL);
usb_phy_shutdown(hcd->usb_phy);
usb_remove_hcd(hcd);
clk_disable_unprepare(tegra->clk);
usb_put_hcd(hcd);
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
benoit goby | benoit goby | 48 | 63.16% | 1 | 11.11% |
stephen warren | stephen warren | 13 | 17.11% | 1 | 11.11% |
tuomas tynkkynen | tuomas tynkkynen | 6 | 7.89% | 2 | 22.22% |
venu byravarasu | venu byravarasu | 3 | 3.95% | 1 | 11.11% |
heikki krogerus | heikki krogerus | 2 | 2.63% | 1 | 11.11% |
antoine tenart | antoine tenart | 2 | 2.63% | 1 | 11.11% |
prashant gaikwad | prashant gaikwad | 1 | 1.32% | 1 | 11.11% |
alan stern | alan stern | 1 | 1.32% | 1 | 11.11% |
| Total | 76 | 100.00% | 9 | 100.00% |
static void tegra_ehci_hcd_shutdown(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
if (hcd->driver->shutdown)
hcd->driver->shutdown(hcd);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
benoit goby | benoit goby | 36 | 94.74% | 1 | 50.00% |
stephen warren | stephen warren | 2 | 5.26% | 1 | 50.00% |
| Total | 38 | 100.00% | 2 | 100.00% |
static struct platform_driver tegra_ehci_driver = {
.probe = tegra_ehci_probe,
.remove = tegra_ehci_remove,
.shutdown = tegra_ehci_hcd_shutdown,
.driver = {
.name = DRV_NAME,
.of_match_table = tegra_ehci_of_match,
}
};
static int tegra_ehci_reset(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int retval;
int txfifothresh;
retval = ehci_setup(hcd);
if (retval)
return retval;
/*
* We should really pull this value out of tegra_ehci_soc_config, but
* to avoid needing access to it, make use of the fact that Tegra20 is
* the only one so far that needs a value of 10, and Tegra20 is the
* only one which doesn't set has_hostpc.
*/
txfifothresh = ehci->has_hostpc ? 0x10 : 10;
ehci_writel(ehci, txfifothresh << 16, &ehci->regs->txfill_tuning);
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
stephen warren | stephen warren | 71 | 100.00% | 1 | 100.00% |
| Total | 71 | 100.00% | 1 | 100.00% |
static const struct ehci_driver_overrides tegra_overrides __initconst = {
.extra_priv_size = sizeof(struct tegra_ehci_hcd),
.reset = tegra_ehci_reset,
};
static int __init ehci_tegra_init(void)
{
if (usb_disabled())
return -ENODEV;
pr_info(DRV_NAME ": " DRIVER_DESC "\n");
ehci_init_driver(&tegra_ehci_hc_driver, &tegra_overrides);
/*
* The Tegra HW has some unusual quirks, which require Tegra-specific
* workarounds. We override certain hc_driver functions here to
* achieve that. We explicitly do not enhance ehci_driver_overrides to
* allow this more easily, since this is an unusual case, and we don't
* want to encourage others to override these functions by making it
* too easy.
*/
tegra_ehci_hc_driver.map_urb_for_dma = tegra_ehci_map_urb_for_dma;
tegra_ehci_hc_driver.unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma;
tegra_ehci_hc_driver.hub_control = tegra_ehci_hub_control;
return platform_driver_register(&tegra_ehci_driver);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
manjunath goudar | manjunath goudar | 61 | 100.00% | 1 | 100.00% |
| Total | 61 | 100.00% | 1 | 100.00% |
module_init(ehci_tegra_init);
static void __exit ehci_tegra_cleanup(void)
{
platform_driver_unregister(&tegra_ehci_driver);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
manjunath goudar | manjunath goudar | 15 | 100.00% | 1 | 100.00% |
| Total | 15 | 100.00% | 1 | 100.00% |
module_exit(ehci_tegra_cleanup);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DRV_NAME);
MODULE_DEVICE_TABLE(of, tegra_ehci_of_match);
Overall Contributors
| Person | Tokens | Prop | Commits | CommitProp |
benoit goby | benoit goby | 1009 | 38.21% | 1 | 2.27% |
tuomas tynkkynen | tuomas tynkkynen | 336 | 12.72% | 5 | 11.36% |
jim lin | jim lin | 299 | 11.32% | 1 | 2.27% |
alan stern | alan stern | 254 | 9.62% | 2 | 4.55% |
stephen warren | stephen warren | 252 | 9.54% | 6 | 13.64% |
manjunath goudar | manjunath goudar | 183 | 6.93% | 2 | 4.55% |
venu byravarasu | venu byravarasu | 121 | 4.58% | 6 | 13.64% |
thierry reding | thierry reding | 40 | 1.51% | 3 | 6.82% |
johan hovold | johan hovold | 28 | 1.06% | 1 | 2.27% |
olof johansson | olof johansson | 19 | 0.72% | 1 | 2.27% |
varka bhadram | varka bhadram | 17 | 0.64% | 1 | 2.27% |
greg kroah-hartman | greg kroah-hartman | 15 | 0.57% | 1 | 2.27% |
russell king | russell king | 12 | 0.45% | 2 | 4.55% |
julia lawall | julia lawall | 11 | 0.42% | 1 | 2.27% |
vivek gautam | vivek gautam | 9 | 0.34% | 1 | 2.27% |
peter chen | peter chen | 9 | 0.34% | 1 | 2.27% |
antoine tenart | antoine tenart | 8 | 0.30% | 1 | 2.27% |
heikki krogerus | heikki krogerus | 6 | 0.23% | 1 | 2.27% |
robert morell | robert morell | 4 | 0.15% | 1 | 2.27% |
mikko perttunen | mikko perttunen | 2 | 0.08% | 1 | 2.27% |
vince hsu | vince hsu | 2 | 0.08% | 1 | 2.27% |
prashant gaikwad | prashant gaikwad | 2 | 0.08% | 1 | 2.27% |
laurent pinchart | laurent pinchart | 1 | 0.04% | 1 | 2.27% |
wei yongjun | wei yongjun | 1 | 0.04% | 1 | 2.27% |
jingoo han | jingoo han | 1 | 0.04% | 1 | 2.27% |
| Total | 2641 | 100.00% | 44 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.