1
0
Fork 0

USB fixes for 4.4-rc2

Here are a number of USB fixes and new device ids for 4.4-rc2.  All have
 been in linux-next and the details are in the shortlog.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iEYEABECAAYFAlZSDW4ACgkQMUfUDdst+ymrlwCgha5PobWYrhVnhC/w5ODZxRaF
 oAQAn2tOK94L9sADvjbQlFUy+/Zaxxbj
 =x9f4
 -----END PGP SIGNATURE-----

Merge tag 'usb-4.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB fixes from Greg KH:
 "Here are a number of USB fixes and new device ids for 4.4-rc2.  All
  have been in linux-next and the details are in the shortlog"

* tag 'usb-4.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (28 commits)
  usblp: do not set TASK_INTERRUPTIBLE before lock
  USB: MAINTAINERS: cxacru
  usb: kconfig: fix warning of select USB_OTG
  USB: option: add XS Stick W100-2 from 4G Systems
  xhci: Fix a race in usb2 LPM resume, blocking U3 for usb2 devices
  usb: xhci: fix checking ep busy for CFC
  xhci: Workaround to get Intel xHCI reset working more reliably
  usb: chipidea: imx: fix a possible NULL dereference
  usb: chipidea: usbmisc_imx: fix a possible NULL dereference
  usb: chipidea: otg: gadget module load and unload support
  usb: chipidea: debug: disable usb irq while role switch
  ARM: dts: imx27.dtsi: change the clock information for usb
  usb: chipidea: imx: refine clock operations to adapt for all platforms
  usb: gadget: atmel_usba_udc: Expose correct device speed
  usb: musb: enable usb_dma parameter
  usb: phy: phy-mxs-usb: fix a possible NULL dereference
  usb: dwc3: gadget: let us set lower max_speed
  usb: musb: fix tx fifo flush handling
  usb: gadget: f_loopback: fix the warning during the enumeration
  usb: dwc2: host: Fix remote wakeup when not in DWC2_L2
  ...
hifive-unleashed-5.1
Linus Torvalds 2015-11-22 13:15:05 -08:00
commit 6d2d91b3e4
26 changed files with 343 additions and 113 deletions

View File

@ -2931,10 +2931,9 @@ S: Maintained
F: drivers/platform/x86/compal-laptop.c
CONEXANT ACCESSRUNNER USB DRIVER
M: Simon Arlott <cxacru@fire.lp0.eu>
L: accessrunner-general@lists.sourceforge.net
W: http://accessrunner.sourceforge.net/
S: Maintained
S: Orphan
F: drivers/usb/atm/cxacru.c
CONFIGFS

View File

@ -486,7 +486,10 @@
compatible = "fsl,imx27-usb";
reg = <0x10024000 0x200>;
interrupts = <56>;
clocks = <&clks IMX27_CLK_USB_IPG_GATE>;
clocks = <&clks IMX27_CLK_USB_IPG_GATE>,
<&clks IMX27_CLK_USB_AHB_GATE>,
<&clks IMX27_CLK_USB_DIV>;
clock-names = "ipg", "ahb", "per";
fsl,usbmisc = <&usbmisc 0>;
status = "disabled";
};
@ -495,7 +498,10 @@
compatible = "fsl,imx27-usb";
reg = <0x10024200 0x200>;
interrupts = <54>;
clocks = <&clks IMX27_CLK_USB_IPG_GATE>;
clocks = <&clks IMX27_CLK_USB_IPG_GATE>,
<&clks IMX27_CLK_USB_AHB_GATE>,
<&clks IMX27_CLK_USB_DIV>;
clock-names = "ipg", "ahb", "per";
fsl,usbmisc = <&usbmisc 1>;
dr_mode = "host";
status = "disabled";
@ -505,7 +511,10 @@
compatible = "fsl,imx27-usb";
reg = <0x10024400 0x200>;
interrupts = <55>;
clocks = <&clks IMX27_CLK_USB_IPG_GATE>;
clocks = <&clks IMX27_CLK_USB_IPG_GATE>,
<&clks IMX27_CLK_USB_AHB_GATE>,
<&clks IMX27_CLK_USB_DIV>;
clock-names = "ipg", "ahb", "per";
fsl,usbmisc = <&usbmisc 2>;
dr_mode = "host";
status = "disabled";
@ -515,7 +524,6 @@
#index-cells = <1>;
compatible = "fsl,imx27-usbmisc";
reg = <0x10024600 0x200>;
clocks = <&clks IMX27_CLK_USB_AHB_GATE>;
};
sahara2: sahara@10025000 {

View File

@ -84,6 +84,12 @@ struct ci_hdrc_imx_data {
struct imx_usbmisc_data *usbmisc_data;
bool supports_runtime_pm;
bool in_lpm;
/* SoC before i.mx6 (except imx23/imx28) needs three clks */
bool need_three_clks;
struct clk *clk_ipg;
struct clk *clk_ahb;
struct clk *clk_per;
/* --------------------------------- */
};
/* Common functions shared by usbmisc drivers */
@ -135,6 +141,102 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
}
/* End of common functions shared by usbmisc drivers*/
static int imx_get_clks(struct device *dev)
{
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
int ret = 0;
data->clk_ipg = devm_clk_get(dev, "ipg");
if (IS_ERR(data->clk_ipg)) {
/* If the platform only needs one clocks */
data->clk = devm_clk_get(dev, NULL);
if (IS_ERR(data->clk)) {
ret = PTR_ERR(data->clk);
dev_err(dev,
"Failed to get clks, err=%ld,%ld\n",
PTR_ERR(data->clk), PTR_ERR(data->clk_ipg));
return ret;
}
return ret;
}
data->clk_ahb = devm_clk_get(dev, "ahb");
if (IS_ERR(data->clk_ahb)) {
ret = PTR_ERR(data->clk_ahb);
dev_err(dev,
"Failed to get ahb clock, err=%d\n", ret);
return ret;
}
data->clk_per = devm_clk_get(dev, "per");
if (IS_ERR(data->clk_per)) {
ret = PTR_ERR(data->clk_per);
dev_err(dev,
"Failed to get per clock, err=%d\n", ret);
return ret;
}
data->need_three_clks = true;
return ret;
}
static int imx_prepare_enable_clks(struct device *dev)
{
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
int ret = 0;
if (data->need_three_clks) {
ret = clk_prepare_enable(data->clk_ipg);
if (ret) {
dev_err(dev,
"Failed to prepare/enable ipg clk, err=%d\n",
ret);
return ret;
}
ret = clk_prepare_enable(data->clk_ahb);
if (ret) {
dev_err(dev,
"Failed to prepare/enable ahb clk, err=%d\n",
ret);
clk_disable_unprepare(data->clk_ipg);
return ret;
}
ret = clk_prepare_enable(data->clk_per);
if (ret) {
dev_err(dev,
"Failed to prepare/enable per clk, err=%d\n",
ret);
clk_disable_unprepare(data->clk_ahb);
clk_disable_unprepare(data->clk_ipg);
return ret;
}
} else {
ret = clk_prepare_enable(data->clk);
if (ret) {
dev_err(dev,
"Failed to prepare/enable clk, err=%d\n",
ret);
return ret;
}
}
return ret;
}
static void imx_disable_unprepare_clks(struct device *dev)
{
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
if (data->need_three_clks) {
clk_disable_unprepare(data->clk_per);
clk_disable_unprepare(data->clk_ahb);
clk_disable_unprepare(data->clk_ipg);
} else {
clk_disable_unprepare(data->clk);
}
}
static int ci_hdrc_imx_probe(struct platform_device *pdev)
{
@ -145,31 +247,31 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
.flags = CI_HDRC_SET_NON_ZERO_TTHA,
};
int ret;
const struct of_device_id *of_id =
of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev);
const struct ci_hdrc_imx_platform_flag *imx_platform_flag = of_id->data;
const struct of_device_id *of_id;
const struct ci_hdrc_imx_platform_flag *imx_platform_flag;
of_id = of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev);
if (!of_id)
return -ENODEV;
imx_platform_flag = of_id->data;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
platform_set_drvdata(pdev, data);
data->usbmisc_data = usbmisc_get_init_data(&pdev->dev);
if (IS_ERR(data->usbmisc_data))
return PTR_ERR(data->usbmisc_data);
data->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(data->clk)) {
dev_err(&pdev->dev,
"Failed to get clock, err=%ld\n", PTR_ERR(data->clk));
return PTR_ERR(data->clk);
}
ret = clk_prepare_enable(data->clk);
if (ret) {
dev_err(&pdev->dev,
"Failed to prepare or enable clock, err=%d\n", ret);
ret = imx_get_clks(&pdev->dev);
if (ret)
return ret;
ret = imx_prepare_enable_clks(&pdev->dev);
if (ret)
return ret;
}
data->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "fsl,usbphy", 0);
if (IS_ERR(data->phy)) {
@ -212,8 +314,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
goto disable_device;
}
platform_set_drvdata(pdev, data);
if (data->supports_runtime_pm) {
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
@ -226,7 +326,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
disable_device:
ci_hdrc_remove_device(data->ci_pdev);
err_clk:
clk_disable_unprepare(data->clk);
imx_disable_unprepare_clks(&pdev->dev);
return ret;
}
@ -240,7 +340,7 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev)
pm_runtime_put_noidle(&pdev->dev);
}
ci_hdrc_remove_device(data->ci_pdev);
clk_disable_unprepare(data->clk);
imx_disable_unprepare_clks(&pdev->dev);
return 0;
}
@ -252,7 +352,7 @@ static int imx_controller_suspend(struct device *dev)
dev_dbg(dev, "at %s\n", __func__);
clk_disable_unprepare(data->clk);
imx_disable_unprepare_clks(dev);
data->in_lpm = true;
return 0;
@ -270,7 +370,7 @@ static int imx_controller_resume(struct device *dev)
return 0;
}
ret = clk_prepare_enable(data->clk);
ret = imx_prepare_enable_clks(dev);
if (ret)
return ret;
@ -285,7 +385,7 @@ static int imx_controller_resume(struct device *dev)
return 0;
clk_disable:
clk_disable_unprepare(data->clk);
imx_disable_unprepare_clks(dev);
return ret;
}

View File

@ -322,8 +322,10 @@ static ssize_t ci_role_write(struct file *file, const char __user *ubuf,
return -EINVAL;
pm_runtime_get_sync(ci->dev);
disable_irq(ci->irq);
ci_role_stop(ci);
ret = ci_role_start(ci, role);
enable_irq(ci->irq);
pm_runtime_put_sync(ci->dev);
return ret ? ret : count;

View File

@ -1751,6 +1751,22 @@ static int ci_udc_start(struct usb_gadget *gadget,
return retval;
}
static void ci_udc_stop_for_otg_fsm(struct ci_hdrc *ci)
{
if (!ci_otg_is_fsm_mode(ci))
return;
mutex_lock(&ci->fsm.lock);
if (ci->fsm.otg->state == OTG_STATE_A_PERIPHERAL) {
ci->fsm.a_bidl_adis_tmout = 1;
ci_hdrc_otg_fsm_start(ci);
} else if (ci->fsm.otg->state == OTG_STATE_B_PERIPHERAL) {
ci->fsm.protocol = PROTO_UNDEF;
ci->fsm.otg->state = OTG_STATE_UNDEFINED;
}
mutex_unlock(&ci->fsm.lock);
}
/**
* ci_udc_stop: unregister a gadget driver
*/
@ -1775,6 +1791,7 @@ static int ci_udc_stop(struct usb_gadget *gadget)
ci->driver = NULL;
spin_unlock_irqrestore(&ci->lock, flags);
ci_udc_stop_for_otg_fsm(ci);
return 0;
}

View File

@ -500,7 +500,11 @@ static int usbmisc_imx_probe(struct platform_device *pdev)
{
struct resource *res;
struct imx_usbmisc *data;
struct of_device_id *tmp_dev;
const struct of_device_id *of_id;
of_id = of_match_device(usbmisc_imx_dt_ids, &pdev->dev);
if (!of_id)
return -ENODEV;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
@ -513,9 +517,7 @@ static int usbmisc_imx_probe(struct platform_device *pdev)
if (IS_ERR(data->base))
return PTR_ERR(data->base);
tmp_dev = (struct of_device_id *)
of_match_device(usbmisc_imx_dt_ids, &pdev->dev);
data->ops = (const struct usbmisc_ops *)tmp_dev->data;
data->ops = (const struct usbmisc_ops *)of_id->data;
platform_set_drvdata(pdev, data);
return 0;

View File

@ -884,11 +884,11 @@ static int usblp_wwait(struct usblp *usblp, int nonblock)
add_wait_queue(&usblp->wwait, &waita);
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (mutex_lock_interruptible(&usblp->mut)) {
rc = -EINTR;
break;
}
set_current_state(TASK_INTERRUPTIBLE);
rc = usblp_wtest(usblp, nonblock);
mutex_unlock(&usblp->mut);
if (rc <= 0)

View File

@ -77,8 +77,7 @@ config USB_OTG_BLACKLIST_HUB
config USB_OTG_FSM
tristate "USB 2.0 OTG FSM implementation"
depends on USB
select USB_OTG
depends on USB && USB_OTG
select USB_PHY
help
Implements OTG Finite State Machine as specified in On-The-Go

View File

@ -324,12 +324,13 @@ void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg)
*/
static void dwc2_hcd_rem_wakeup(struct dwc2_hsotg *hsotg)
{
if (hsotg->lx_state == DWC2_L2) {
if (hsotg->bus_suspended) {
hsotg->flags.b.port_suspend_change = 1;
usb_hcd_resume_root_hub(hsotg->priv);
} else {
hsotg->flags.b.port_l1_change = 1;
}
if (hsotg->lx_state == DWC2_L1)
hsotg->flags.b.port_l1_change = 1;
}
/**
@ -1428,8 +1429,8 @@ static void dwc2_wakeup_detected(unsigned long data)
dev_dbg(hsotg->dev, "Clear Resume: HPRT0=%0x\n",
dwc2_readl(hsotg->regs + HPRT0));
hsotg->bus_suspended = 0;
dwc2_hcd_rem_wakeup(hsotg);
hsotg->bus_suspended = 0;
/* Change to L0 state */
hsotg->lx_state = DWC2_L0;

View File

@ -108,7 +108,8 @@ static const struct dwc2_core_params params_rk3066 = {
.host_ls_low_power_phy_clk = -1,
.ts_dline = -1,
.reload_ctl = -1,
.ahbcfg = 0x7, /* INCR16 */
.ahbcfg = GAHBCFG_HBSTLEN_INCR16 <<
GAHBCFG_HBSTLEN_SHIFT,
.uframe_sched = -1,
.external_id_pin_ctl = -1,
.hibernation = -1,

View File

@ -34,6 +34,8 @@
#define PCI_DEVICE_ID_INTEL_BSW 0x22b7
#define PCI_DEVICE_ID_INTEL_SPTLP 0x9d30
#define PCI_DEVICE_ID_INTEL_SPTH 0xa130
#define PCI_DEVICE_ID_INTEL_BXT 0x0aaa
#define PCI_DEVICE_ID_INTEL_APL 0x5aaa
static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
static const struct acpi_gpio_params cs_gpios = { 1, 0, false };
@ -210,6 +212,8 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTLP), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTH), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), },
{ } /* Terminating Entry */
};

View File

@ -2744,11 +2744,33 @@ int dwc3_gadget_init(struct dwc3 *dwc)
}
dwc->gadget.ops = &dwc3_gadget_ops;
dwc->gadget.max_speed = USB_SPEED_SUPER;
dwc->gadget.speed = USB_SPEED_UNKNOWN;
dwc->gadget.sg_supported = true;
dwc->gadget.name = "dwc3-gadget";
/*
* FIXME We might be setting max_speed to <SUPER, however versions
* <2.20a of dwc3 have an issue with metastability (documented
* elsewhere in this driver) which tells us we can't set max speed to
* anything lower than SUPER.
*
* Because gadget.max_speed is only used by composite.c and function
* drivers (i.e. it won't go into dwc3's registers) we are allowing this
* to happen so we avoid sending SuperSpeed Capability descriptor
* together with our BOS descriptor as that could confuse host into
* thinking we can handle super speed.
*
* Note that, in fact, we won't even support GetBOS requests when speed
* is less than super speed because we don't have means, yet, to tell
* composite.c that we are USB 2.0 + LPM ECN.
*/
if (dwc->revision < DWC3_REVISION_220A)
dwc3_trace(trace_dwc3_gadget,
"Changing max_speed on rev %08x\n",
dwc->revision);
dwc->gadget.max_speed = dwc->maximum_speed;
/*
* Per databook, DWC3 needs buffer size to be aligned to MaxPacketSize
* on ep out.

View File

@ -329,7 +329,7 @@ static int alloc_requests(struct usb_composite_dev *cdev,
for (i = 0; i < loop->qlen && result == 0; i++) {
result = -ENOMEM;
in_req = usb_ep_alloc_request(loop->in_ep, GFP_KERNEL);
in_req = usb_ep_alloc_request(loop->in_ep, GFP_ATOMIC);
if (!in_req)
goto fail;

View File

@ -1633,7 +1633,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
spin_lock(&udc->lock);
int_enb = usba_int_enb_get(udc);
status = usba_readl(udc, INT_STA) & int_enb;
status = usba_readl(udc, INT_STA) & (int_enb | USBA_HIGH_SPEED);
DBG(DBG_INT, "irq, status=%#08x\n", status);
if (status & USBA_DET_SUSPEND) {

View File

@ -782,12 +782,15 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
status |= USB_PORT_STAT_SUSPEND;
}
}
if ((raw_port_status & PORT_PLS_MASK) == XDEV_U0
&& (raw_port_status & PORT_POWER)
&& (bus_state->suspended_ports & (1 << wIndex))) {
bus_state->suspended_ports &= ~(1 << wIndex);
if (hcd->speed < HCD_USB3)
bus_state->port_c_suspend |= 1 << wIndex;
if ((raw_port_status & PORT_PLS_MASK) == XDEV_U0 &&
(raw_port_status & PORT_POWER)) {
if (bus_state->suspended_ports & (1 << wIndex)) {
bus_state->suspended_ports &= ~(1 << wIndex);
if (hcd->speed < HCD_USB3)
bus_state->port_c_suspend |= 1 << wIndex;
}
bus_state->resume_done[wIndex] = 0;
clear_bit(wIndex, &bus_state->resuming_ports);
}
if (raw_port_status & PORT_CONNECT) {
status |= USB_PORT_STAT_CONNECTION;

View File

@ -3896,28 +3896,6 @@ cleanup:
return ret;
}
static int ep_ring_is_processing(struct xhci_hcd *xhci,
int slot_id, unsigned int ep_index)
{
struct xhci_virt_device *xdev;
struct xhci_ring *ep_ring;
struct xhci_ep_ctx *ep_ctx;
struct xhci_virt_ep *xep;
dma_addr_t hw_deq;
xdev = xhci->devs[slot_id];
xep = &xhci->devs[slot_id]->eps[ep_index];
ep_ring = xep->ring;
ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
if ((le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) != EP_STATE_RUNNING)
return 0;
hw_deq = le64_to_cpu(ep_ctx->deq) & ~EP_CTX_CYCLE_MASK;
return (hw_deq !=
xhci_trb_virt_to_dma(ep_ring->enq_seg, ep_ring->enqueue));
}
/*
* Check transfer ring to guarantee there is enough room for the urb.
* Update ISO URB start_frame and interval.
@ -3983,10 +3961,12 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
}
/* Calculate the start frame and put it in urb->start_frame. */
if (HCC_CFC(xhci->hcc_params) &&
ep_ring_is_processing(xhci, slot_id, ep_index)) {
urb->start_frame = xep->next_frame_id;
goto skip_start_over;
if (HCC_CFC(xhci->hcc_params) && !list_empty(&ep_ring->td_list)) {
if ((le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) ==
EP_STATE_RUNNING) {
urb->start_frame = xep->next_frame_id;
goto skip_start_over;
}
}
start_frame = readl(&xhci->run_regs->microframe_index);

View File

@ -175,6 +175,16 @@ int xhci_reset(struct xhci_hcd *xhci)
command |= CMD_RESET;
writel(command, &xhci->op_regs->command);
/* Existing Intel xHCI controllers require a delay of 1 mS,
* after setting the CMD_RESET bit, and before accessing any
* HC registers. This allows the HC to complete the
* reset operation and be ready for HC register access.
* Without this delay, the subsequent HC register access,
* may result in a system hang very rarely.
*/
if (xhci->quirks & XHCI_INTEL_HOST)
udelay(1000);
ret = xhci_handshake(&xhci->op_regs->command,
CMD_RESET, 0, 10 * 1000 * 1000);
if (ret)

View File

@ -132,7 +132,7 @@ static inline struct musb *dev_to_musb(struct device *dev)
/*-------------------------------------------------------------------------*/
#ifndef CONFIG_BLACKFIN
static int musb_ulpi_read(struct usb_phy *phy, u32 offset)
static int musb_ulpi_read(struct usb_phy *phy, u32 reg)
{
void __iomem *addr = phy->io_priv;
int i = 0;
@ -151,7 +151,7 @@ static int musb_ulpi_read(struct usb_phy *phy, u32 offset)
* ULPICarKitControlDisableUTMI after clearing POWER_SUSPENDM.
*/
musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)offset);
musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)reg);
musb_writeb(addr, MUSB_ULPI_REG_CONTROL,
MUSB_ULPI_REG_REQ | MUSB_ULPI_RDN_WR);
@ -176,7 +176,7 @@ out:
return ret;
}
static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data)
static int musb_ulpi_write(struct usb_phy *phy, u32 val, u32 reg)
{
void __iomem *addr = phy->io_priv;
int i = 0;
@ -191,8 +191,8 @@ static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data)
power &= ~MUSB_POWER_SUSPENDM;
musb_writeb(addr, MUSB_POWER, power);
musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)offset);
musb_writeb(addr, MUSB_ULPI_REG_DATA, (u8)data);
musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)reg);
musb_writeb(addr, MUSB_ULPI_REG_DATA, (u8)val);
musb_writeb(addr, MUSB_ULPI_REG_CONTROL, MUSB_ULPI_REG_REQ);
while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL)
@ -1668,7 +1668,7 @@ EXPORT_SYMBOL_GPL(musb_interrupt);
static bool use_dma = 1;
/* "modprobe ... use_dma=0" etc */
module_param(use_dma, bool, 0);
module_param(use_dma, bool, 0644);
MODULE_PARM_DESC(use_dma, "enable/disable use of DMA");
void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit)

View File

@ -112,22 +112,32 @@ static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep)
struct musb *musb = ep->musb;
void __iomem *epio = ep->regs;
u16 csr;
u16 lastcsr = 0;
int retries = 1000;
csr = musb_readw(epio, MUSB_TXCSR);
while (csr & MUSB_TXCSR_FIFONOTEMPTY) {
if (csr != lastcsr)
dev_dbg(musb->controller, "Host TX FIFONOTEMPTY csr: %02x\n", csr);
lastcsr = csr;
csr |= MUSB_TXCSR_FLUSHFIFO | MUSB_TXCSR_TXPKTRDY;
musb_writew(epio, MUSB_TXCSR, csr);
csr = musb_readw(epio, MUSB_TXCSR);
if (WARN(retries-- < 1,
/*
* FIXME: sometimes the tx fifo flush failed, it has been
* observed during device disconnect on AM335x.
*
* To reproduce the issue, ensure tx urb(s) are queued when
* unplug the usb device which is connected to AM335x usb
* host port.
*
* I found using a usb-ethernet device and running iperf
* (client on AM335x) has very high chance to trigger it.
*
* Better to turn on dev_dbg() in musb_cleanup_urb() with
* CPPI enabled to see the issue when aborting the tx channel.
*/
if (dev_WARN_ONCE(musb->controller, retries-- < 1,
"Could not flush host TX%d fifo: csr: %04x\n",
ep->epnum, csr))
return;
mdelay(1);
}
}

View File

@ -21,7 +21,6 @@ config AB8500_USB
config FSL_USB2_OTG
bool "Freescale USB OTG Transceiver Driver"
depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_OTG_FSM && PM
select USB_OTG
select USB_PHY
help
Enable this to support Freescale USB OTG transceiver.
@ -168,8 +167,7 @@ config USB_QCOM_8X16_PHY
config USB_MV_OTG
tristate "Marvell USB OTG support"
depends on USB_EHCI_MV && USB_MV_UDC && PM
select USB_OTG
depends on USB_EHCI_MV && USB_MV_UDC && PM && USB_OTG
select USB_PHY
help
Say Y here if you want to build Marvell USB OTG transciever

View File

@ -452,10 +452,13 @@ static int mxs_phy_probe(struct platform_device *pdev)
struct clk *clk;
struct mxs_phy *mxs_phy;
int ret;
const struct of_device_id *of_id =
of_match_device(mxs_phy_dt_ids, &pdev->dev);
const struct of_device_id *of_id;
struct device_node *np = pdev->dev.of_node;
of_id = of_match_device(mxs_phy_dt_ids, &pdev->dev);
if (!of_id)
return -ENODEV;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))

View File

@ -105,7 +105,6 @@ static int omap_otg_probe(struct platform_device *pdev)
extcon = extcon_get_extcon_dev(config->extcon);
if (!extcon)
return -EPROBE_DEFER;
otg_dev->extcon = extcon;
otg_dev = devm_kzalloc(&pdev->dev, sizeof(*otg_dev), GFP_KERNEL);
if (!otg_dev)
@ -115,6 +114,7 @@ static int omap_otg_probe(struct platform_device *pdev)
if (IS_ERR(otg_dev->base))
return PTR_ERR(otg_dev->base);
otg_dev->extcon = extcon;
otg_dev->id_nb.notifier_call = omap_otg_id_notifier;
otg_dev->vbus_nb.notifier_call = omap_otg_vbus_notifier;

View File

@ -161,6 +161,7 @@ static void option_instat_callback(struct urb *urb);
#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED 0x9001
#define NOVATELWIRELESS_PRODUCT_E362 0x9010
#define NOVATELWIRELESS_PRODUCT_E371 0x9011
#define NOVATELWIRELESS_PRODUCT_U620L 0x9022
#define NOVATELWIRELESS_PRODUCT_G2 0xA010
#define NOVATELWIRELESS_PRODUCT_MC551 0xB001
@ -354,6 +355,7 @@ static void option_instat_callback(struct urb *urb);
/* This is the 4G XS Stick W14 a.k.a. Mobilcom Debitel Surf-Stick *
* It seems to contain a Qualcomm QSC6240/6290 chipset */
#define FOUR_G_SYSTEMS_PRODUCT_W14 0x9603
#define FOUR_G_SYSTEMS_PRODUCT_W100 0x9b01
/* iBall 3.5G connect wireless modem */
#define IBALL_3_5G_CONNECT 0x9605
@ -519,6 +521,11 @@ static const struct option_blacklist_info four_g_w14_blacklist = {
.sendsetup = BIT(0) | BIT(1),
};
static const struct option_blacklist_info four_g_w100_blacklist = {
.sendsetup = BIT(1) | BIT(2),
.reserved = BIT(3),
};
static const struct option_blacklist_info alcatel_x200_blacklist = {
.sendsetup = BIT(0) | BIT(1),
.reserved = BIT(4),
@ -1052,6 +1059,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC551, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E362, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E371, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U620L, 0xff, 0x00, 0x00) },
{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01) },
{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01A) },
@ -1641,6 +1649,9 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14),
.driver_info = (kernel_ulong_t)&four_g_w14_blacklist
},
{ USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W100),
.driver_info = (kernel_ulong_t)&four_g_w100_blacklist
},
{ USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, SPEEDUP_PRODUCT_SU9800, 0xff) },
{ USB_DEVICE(LONGCHEER_VENDOR_ID, ZOOM_PRODUCT_4597) },
{ USB_DEVICE(LONGCHEER_VENDOR_ID, IBALL_3_5G_CONNECT) },

View File

@ -22,6 +22,8 @@
#define DRIVER_AUTHOR "Qualcomm Inc"
#define DRIVER_DESC "Qualcomm USB Serial driver"
#define QUECTEL_EC20_PID 0x9215
/* standard device layouts supported by this driver */
enum qcserial_layouts {
QCSERIAL_G2K = 0, /* Gobi 2000 */
@ -171,6 +173,38 @@ static const struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
static int handle_quectel_ec20(struct device *dev, int ifnum)
{
int altsetting = 0;
/*
* Quectel EC20 Mini PCIe LTE module layout:
* 0: DM/DIAG (use libqcdm from ModemManager for communication)
* 1: NMEA
* 2: AT-capable modem port
* 3: Modem interface
* 4: NDIS
*/
switch (ifnum) {
case 0:
dev_dbg(dev, "Quectel EC20 DM/DIAG interface found\n");
break;
case 1:
dev_dbg(dev, "Quectel EC20 NMEA GPS interface found\n");
break;
case 2:
case 3:
dev_dbg(dev, "Quectel EC20 Modem port found\n");
break;
case 4:
/* Don't claim the QMI/net interface */
altsetting = -1;
break;
}
return altsetting;
}
static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
{
struct usb_host_interface *intf = serial->interface->cur_altsetting;
@ -181,6 +215,10 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
int altsetting = -1;
bool sendsetup = false;
/* we only support vendor specific functions */
if (intf->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
goto done;
nintf = serial->dev->actconfig->desc.bNumInterfaces;
dev_dbg(dev, "Num Interfaces = %d\n", nintf);
ifnum = intf->desc.bInterfaceNumber;
@ -240,6 +278,12 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
altsetting = -1;
break;
case QCSERIAL_G2K:
/* handle non-standard layouts */
if (nintf == 5 && id->idProduct == QUECTEL_EC20_PID) {
altsetting = handle_quectel_ec20(dev, ifnum);
goto done;
}
/*
* Gobi 2K+ USB layout:
* 0: QMI/net
@ -301,29 +345,39 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
break;
case QCSERIAL_HWI:
/*
* Huawei layout:
* 0: AT-capable modem port
* 1: DM/DIAG
* 2: AT-capable modem port
* 3: CCID-compatible PCSC interface
* 4: QMI/net
* 5: NMEA
* Huawei devices map functions by subclass + protocol
* instead of interface numbers. The protocol identify
* a specific function, while the subclass indicate a
* specific firmware source
*
* This is a blacklist of functions known to be
* non-serial. The rest are assumed to be serial and
* will be handled by this driver
*/
switch (ifnum) {
case 0:
case 2:
dev_dbg(dev, "Modem port found\n");
break;
case 1:
dev_dbg(dev, "DM/DIAG interface found\n");
break;
case 5:
dev_dbg(dev, "NMEA GPS interface found\n");
break;
default:
/* don't claim any unsupported interface */
switch (intf->desc.bInterfaceProtocol) {
/* QMI combined (qmi_wwan) */
case 0x07:
case 0x37:
case 0x67:
/* QMI data (qmi_wwan) */
case 0x08:
case 0x38:
case 0x68:
/* QMI control (qmi_wwan) */
case 0x09:
case 0x39:
case 0x69:
/* NCM like (huawei_cdc_ncm) */
case 0x16:
case 0x46:
case 0x76:
altsetting = -1;
break;
default:
dev_dbg(dev, "Huawei type serial port found (%02x/%02x/%02x)\n",
intf->desc.bInterfaceClass,
intf->desc.bInterfaceSubClass,
intf->desc.bInterfaceProtocol);
}
break;
default:

View File

@ -159,6 +159,7 @@ static const struct usb_device_id ti_id_table_3410[] = {
{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STEREO_PLUG_ID) },
{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
{ USB_DEVICE(HONEYWELL_VENDOR_ID, HONEYWELL_HGI80_PRODUCT_ID) },
{ } /* terminator */
};
@ -191,6 +192,7 @@ static const struct usb_device_id ti_id_table_combined[] = {
{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) },
{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
{ USB_DEVICE(HONEYWELL_VENDOR_ID, HONEYWELL_HGI80_PRODUCT_ID) },
{ } /* terminator */
};

View File

@ -56,6 +56,10 @@
#define ABBOTT_PRODUCT_ID ABBOTT_STEREO_PLUG_ID
#define ABBOTT_STRIP_PORT_ID 0x3420
/* Honeywell vendor and product IDs */
#define HONEYWELL_VENDOR_ID 0x10ac
#define HONEYWELL_HGI80_PRODUCT_ID 0x0102 /* Honeywell HGI80 */
/* Commands */
#define TI_GET_VERSION 0x01
#define TI_GET_PORT_STATUS 0x02