Commit 213356fe authored by Linus Torvalds's avatar Linus Torvalds

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

Pull USB/PHY fixes from Greg KH:
 "Here are a number of USB and PHY driver fixes for 5.5-rc6

  Nothing all that unusual, just the a bunch of small fixes for a lot of
  different reported issues. The PHY driver fixes are in here as they
  interacted with the usb drivers.

  Full details of the patches are in the shortlog, and all of these have
  been in linux-next with no reported issues"

* tag 'usb-5.5-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (24 commits)
  usb: missing parentheses in USE_NEW_SCHEME
  usb: ohci-da8xx: ensure error return on variable error is set
  usb: musb: Disable pullup at init
  usb: musb: fix idling for suspend after disconnect interrupt
  usb: typec: ucsi: Fix the notification bit offsets
  USB: Fix: Don't skip endpoint descriptors with maxpacket=0
  USB-PD tcpm: bad warning+size, PPS adapters
  phy/rockchip: inno-hdmi: round clock rate down to closest 1000 Hz
  usb: chipidea: host: Disable port power only if previously enabled
  usb: cdns3: should not use the same dev_id for shared interrupt handler
  usb: dwc3: gadget: Fix request complete check
  usb: musb: dma: Correct parameter passed to IRQ handler
  usb: musb: jz4740: Silence error if code is -EPROBE_DEFER
  usb: udc: tegra: select USB_ROLE_SWITCH
  USB: core: fix check for duplicate endpoints
  phy: cpcap-usb: Drop extra write to usb2 register
  phy: cpcap-usb: Improve host vs docked mode detection
  phy: cpcap-usb: Prevent USB line glitches from waking up modem
  phy: mapphone-mdm6600: Fix uninitialized status value regression
  phy: cpcap-usb: Fix flakey host idling and enumerating of devices
  ...
parents 9fb7007d 1530f6f5
...@@ -115,7 +115,7 @@ struct cpcap_usb_ints_state { ...@@ -115,7 +115,7 @@ struct cpcap_usb_ints_state {
enum cpcap_gpio_mode { enum cpcap_gpio_mode {
CPCAP_DM_DP, CPCAP_DM_DP,
CPCAP_MDM_RX_TX, CPCAP_MDM_RX_TX,
CPCAP_UNKNOWN, CPCAP_UNKNOWN_DISABLED, /* Seems to disable USB lines */
CPCAP_OTG_DM_DP, CPCAP_OTG_DM_DP,
}; };
...@@ -134,6 +134,8 @@ struct cpcap_phy_ddata { ...@@ -134,6 +134,8 @@ struct cpcap_phy_ddata {
struct iio_channel *id; struct iio_channel *id;
struct regulator *vusb; struct regulator *vusb;
atomic_t active; atomic_t active;
unsigned int vbus_provider:1;
unsigned int docked:1;
}; };
static bool cpcap_usb_vbus_valid(struct cpcap_phy_ddata *ddata) static bool cpcap_usb_vbus_valid(struct cpcap_phy_ddata *ddata)
...@@ -207,6 +209,19 @@ static int cpcap_phy_get_ints_state(struct cpcap_phy_ddata *ddata, ...@@ -207,6 +209,19 @@ static int cpcap_phy_get_ints_state(struct cpcap_phy_ddata *ddata,
static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata); static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata);
static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata); static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata);
static void cpcap_usb_try_musb_mailbox(struct cpcap_phy_ddata *ddata,
enum musb_vbus_id_status status)
{
int error;
error = musb_mailbox(status);
if (!error)
return;
dev_dbg(ddata->dev, "%s: musb_mailbox failed: %i\n",
__func__, error);
}
static void cpcap_usb_detect(struct work_struct *work) static void cpcap_usb_detect(struct work_struct *work)
{ {
struct cpcap_phy_ddata *ddata; struct cpcap_phy_ddata *ddata;
...@@ -220,15 +235,13 @@ static void cpcap_usb_detect(struct work_struct *work) ...@@ -220,15 +235,13 @@ static void cpcap_usb_detect(struct work_struct *work)
if (error) if (error)
return; return;
if (s.id_ground) { vbus = cpcap_usb_vbus_valid(ddata);
dev_dbg(ddata->dev, "id ground, USB host mode\n");
error = cpcap_usb_set_usb_mode(ddata);
if (error)
goto out_err;
error = musb_mailbox(MUSB_ID_GROUND); /* We need to kick the VBUS as USB A-host */
if (error) if (s.id_ground && ddata->vbus_provider) {
goto out_err; dev_dbg(ddata->dev, "still in USB A-host mode, kicking VBUS\n");
cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);
error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3, error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,
CPCAP_BIT_VBUSSTBY_EN | CPCAP_BIT_VBUSSTBY_EN |
...@@ -240,51 +253,86 @@ static void cpcap_usb_detect(struct work_struct *work) ...@@ -240,51 +253,86 @@ static void cpcap_usb_detect(struct work_struct *work)
return; return;
} }
error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3, if (vbus && s.id_ground && ddata->docked) {
CPCAP_BIT_VBUSSTBY_EN | dev_dbg(ddata->dev, "still docked as A-host, signal ID down\n");
CPCAP_BIT_VBUSEN_SPI, 0);
cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);
return;
}
/* No VBUS needed with docks */
if (vbus && s.id_ground && !ddata->vbus_provider) {
dev_dbg(ddata->dev, "connected to a dock\n");
ddata->docked = true;
error = cpcap_usb_set_usb_mode(ddata);
if (error) if (error)
goto out_err; goto out_err;
vbus = cpcap_usb_vbus_valid(ddata); cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);
if (vbus) { /*
/* Are we connected to a docking station with vbus? */ * Force check state again after musb has reoriented,
if (s.id_ground) { * otherwise devices won't enumerate after loading PHY
dev_dbg(ddata->dev, "connected to a dock\n"); * driver.
*/
schedule_delayed_work(&ddata->detect_work,
msecs_to_jiffies(1000));
return;
}
if (s.id_ground && !ddata->docked) {
dev_dbg(ddata->dev, "id ground, USB host mode\n");
ddata->vbus_provider = true;
/* No VBUS needed with docks */
error = cpcap_usb_set_usb_mode(ddata); error = cpcap_usb_set_usb_mode(ddata);
if (error) if (error)
goto out_err; goto out_err;
error = musb_mailbox(MUSB_ID_GROUND);
cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);
error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,
CPCAP_BIT_VBUSSTBY_EN |
CPCAP_BIT_VBUSEN_SPI,
CPCAP_BIT_VBUSEN_SPI);
if (error) if (error)
goto out_err; goto out_err;
return; return;
} }
error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,
CPCAP_BIT_VBUSSTBY_EN |
CPCAP_BIT_VBUSEN_SPI, 0);
if (error)
goto out_err;
vbus = cpcap_usb_vbus_valid(ddata);
/* Otherwise assume we're connected to a USB host */ /* Otherwise assume we're connected to a USB host */
if (vbus) {
dev_dbg(ddata->dev, "connected to USB host\n"); dev_dbg(ddata->dev, "connected to USB host\n");
error = cpcap_usb_set_usb_mode(ddata); error = cpcap_usb_set_usb_mode(ddata);
if (error) if (error)
goto out_err; goto out_err;
error = musb_mailbox(MUSB_VBUS_VALID); cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_VALID);
if (error)
goto out_err;
return; return;
} }
ddata->vbus_provider = false;
ddata->docked = false;
cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_OFF);
/* Default to debug UART mode */ /* Default to debug UART mode */
error = cpcap_usb_set_uart_mode(ddata); error = cpcap_usb_set_uart_mode(ddata);
if (error) if (error)
goto out_err; goto out_err;
error = musb_mailbox(MUSB_VBUS_OFF);
if (error)
goto out_err;
dev_dbg(ddata->dev, "set UART mode\n"); dev_dbg(ddata->dev, "set UART mode\n");
return; return;
...@@ -376,7 +424,8 @@ static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata) ...@@ -376,7 +424,8 @@ static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata)
{ {
int error; int error;
error = cpcap_usb_gpio_set_mode(ddata, CPCAP_DM_DP); /* Disable lines to prevent glitches from waking up mdm6600 */
error = cpcap_usb_gpio_set_mode(ddata, CPCAP_UNKNOWN_DISABLED);
if (error) if (error)
goto out_err; goto out_err;
...@@ -403,6 +452,11 @@ static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata) ...@@ -403,6 +452,11 @@ static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata)
if (error) if (error)
goto out_err; goto out_err;
/* Enable UART mode */
error = cpcap_usb_gpio_set_mode(ddata, CPCAP_DM_DP);
if (error)
goto out_err;
return 0; return 0;
out_err: out_err:
...@@ -415,7 +469,8 @@ static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata) ...@@ -415,7 +469,8 @@ static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata)
{ {
int error; int error;
error = cpcap_usb_gpio_set_mode(ddata, CPCAP_OTG_DM_DP); /* Disable lines to prevent glitches from waking up mdm6600 */
error = cpcap_usb_gpio_set_mode(ddata, CPCAP_UNKNOWN_DISABLED);
if (error) if (error)
return error; return error;
...@@ -434,12 +489,6 @@ static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata) ...@@ -434,12 +489,6 @@ static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata)
if (error) if (error)
goto out_err; goto out_err;
error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC2,
CPCAP_BIT_USBXCVREN,
CPCAP_BIT_USBXCVREN);
if (error)
goto out_err;
error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3, error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,
CPCAP_BIT_PU_SPI | CPCAP_BIT_PU_SPI |
CPCAP_BIT_DMPD_SPI | CPCAP_BIT_DMPD_SPI |
...@@ -455,6 +504,11 @@ static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata) ...@@ -455,6 +504,11 @@ static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata)
if (error) if (error)
goto out_err; goto out_err;
/* Enable USB mode */
error = cpcap_usb_gpio_set_mode(ddata, CPCAP_OTG_DM_DP);
if (error)
goto out_err;
return 0; return 0;
out_err: out_err:
...@@ -649,9 +703,7 @@ static int cpcap_usb_phy_remove(struct platform_device *pdev) ...@@ -649,9 +703,7 @@ static int cpcap_usb_phy_remove(struct platform_device *pdev)
if (error) if (error)
dev_err(ddata->dev, "could not set UART mode\n"); dev_err(ddata->dev, "could not set UART mode\n");
error = musb_mailbox(MUSB_VBUS_OFF); cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_OFF);
if (error)
dev_err(ddata->dev, "could not set mailbox\n");
usb_remove_phy(&ddata->phy); usb_remove_phy(&ddata->phy);
cancel_delayed_work_sync(&ddata->detect_work); cancel_delayed_work_sync(&ddata->detect_work);
......
...@@ -200,7 +200,7 @@ static void phy_mdm6600_status(struct work_struct *work) ...@@ -200,7 +200,7 @@ static void phy_mdm6600_status(struct work_struct *work)
struct phy_mdm6600 *ddata; struct phy_mdm6600 *ddata;
struct device *dev; struct device *dev;
DECLARE_BITMAP(values, PHY_MDM6600_NR_STATUS_LINES); DECLARE_BITMAP(values, PHY_MDM6600_NR_STATUS_LINES);
int error, i, val = 0; int error;
ddata = container_of(work, struct phy_mdm6600, status_work.work); ddata = container_of(work, struct phy_mdm6600, status_work.work);
dev = ddata->dev; dev = ddata->dev;
...@@ -212,16 +212,11 @@ static void phy_mdm6600_status(struct work_struct *work) ...@@ -212,16 +212,11 @@ static void phy_mdm6600_status(struct work_struct *work)
if (error) if (error)
return; return;
for (i = 0; i < PHY_MDM6600_NR_STATUS_LINES; i++) { ddata->status = values[0] & ((1 << PHY_MDM6600_NR_STATUS_LINES) - 1);
val |= test_bit(i, values) << i;
dev_dbg(ddata->dev, "XXX %s: i: %i values[i]: %i val: %i\n",
__func__, i, test_bit(i, values), val);
}
ddata->status = values[0];
dev_info(dev, "modem status: %i %s\n", dev_info(dev, "modem status: %i %s\n",
ddata->status, ddata->status,
phy_mdm6600_status_name[ddata->status & 7]); phy_mdm6600_status_name[ddata->status]);
complete(&ddata->ack); complete(&ddata->ack);
} }
......
...@@ -66,7 +66,7 @@ ...@@ -66,7 +66,7 @@
/* QPHY_V3_PCS_MISC_CLAMP_ENABLE register bits */ /* QPHY_V3_PCS_MISC_CLAMP_ENABLE register bits */
#define CLAMP_EN BIT(0) /* enables i/o clamp_n */ #define CLAMP_EN BIT(0) /* enables i/o clamp_n */
#define PHY_INIT_COMPLETE_TIMEOUT 1000 #define PHY_INIT_COMPLETE_TIMEOUT 10000
#define POWER_DOWN_DELAY_US_MIN 10 #define POWER_DOWN_DELAY_US_MIN 10
#define POWER_DOWN_DELAY_US_MAX 11 #define POWER_DOWN_DELAY_US_MAX 11
......
...@@ -603,6 +603,8 @@ static long inno_hdmi_phy_rk3228_clk_round_rate(struct clk_hw *hw, ...@@ -603,6 +603,8 @@ static long inno_hdmi_phy_rk3228_clk_round_rate(struct clk_hw *hw,
{ {
const struct pre_pll_config *cfg = pre_pll_cfg_table; const struct pre_pll_config *cfg = pre_pll_cfg_table;
rate = (rate / 1000) * 1000;
for (; cfg->pixclock != 0; cfg++) for (; cfg->pixclock != 0; cfg++)
if (cfg->pixclock == rate && !cfg->fracdiv) if (cfg->pixclock == rate && !cfg->fracdiv)
break; break;
...@@ -755,6 +757,8 @@ static long inno_hdmi_phy_rk3328_clk_round_rate(struct clk_hw *hw, ...@@ -755,6 +757,8 @@ static long inno_hdmi_phy_rk3328_clk_round_rate(struct clk_hw *hw,
{ {
const struct pre_pll_config *cfg = pre_pll_cfg_table; const struct pre_pll_config *cfg = pre_pll_cfg_table;
rate = (rate / 1000) * 1000;
for (; cfg->pixclock != 0; cfg++) for (; cfg->pixclock != 0; cfg++)
if (cfg->pixclock == rate) if (cfg->pixclock == rate)
break; break;
......
...@@ -1375,13 +1375,10 @@ static void cdns3_check_usb_interrupt_proceed(struct cdns3_device *priv_dev, ...@@ -1375,13 +1375,10 @@ static void cdns3_check_usb_interrupt_proceed(struct cdns3_device *priv_dev,
*/ */
static irqreturn_t cdns3_device_irq_handler(int irq, void *data) static irqreturn_t cdns3_device_irq_handler(int irq, void *data)
{ {
struct cdns3_device *priv_dev; struct cdns3_device *priv_dev = data;
struct cdns3 *cdns = data;
irqreturn_t ret = IRQ_NONE; irqreturn_t ret = IRQ_NONE;
u32 reg; u32 reg;
priv_dev = cdns->gadget_dev;
/* check USB device interrupt */ /* check USB device interrupt */
reg = readl(&priv_dev->regs->usb_ists); reg = readl(&priv_dev->regs->usb_ists);
if (reg) { if (reg) {
...@@ -1419,14 +1416,12 @@ static irqreturn_t cdns3_device_irq_handler(int irq, void *data) ...@@ -1419,14 +1416,12 @@ static irqreturn_t cdns3_device_irq_handler(int irq, void *data)
*/ */
static irqreturn_t cdns3_device_thread_irq_handler(int irq, void *data) static irqreturn_t cdns3_device_thread_irq_handler(int irq, void *data)
{ {
struct cdns3_device *priv_dev; struct cdns3_device *priv_dev = data;
struct cdns3 *cdns = data;
irqreturn_t ret = IRQ_NONE; irqreturn_t ret = IRQ_NONE;
unsigned long flags; unsigned long flags;
int bit; int bit;
u32 reg; u32 reg;
priv_dev = cdns->gadget_dev;
spin_lock_irqsave(&priv_dev->lock, flags); spin_lock_irqsave(&priv_dev->lock, flags);
reg = readl(&priv_dev->regs->usb_ists); reg = readl(&priv_dev->regs->usb_ists);
...@@ -2539,7 +2534,7 @@ void cdns3_gadget_exit(struct cdns3 *cdns) ...@@ -2539,7 +2534,7 @@ void cdns3_gadget_exit(struct cdns3 *cdns)
priv_dev = cdns->gadget_dev; priv_dev = cdns->gadget_dev;
devm_free_irq(cdns->dev, cdns->dev_irq, cdns); devm_free_irq(cdns->dev, cdns->dev_irq, priv_dev);
pm_runtime_mark_last_busy(cdns->dev); pm_runtime_mark_last_busy(cdns->dev);
pm_runtime_put_autosuspend(cdns->dev); pm_runtime_put_autosuspend(cdns->dev);
...@@ -2710,7 +2705,8 @@ static int __cdns3_gadget_init(struct cdns3 *cdns) ...@@ -2710,7 +2705,8 @@ static int __cdns3_gadget_init(struct cdns3 *cdns)
ret = devm_request_threaded_irq(cdns->dev, cdns->dev_irq, ret = devm_request_threaded_irq(cdns->dev, cdns->dev_irq,
cdns3_device_irq_handler, cdns3_device_irq_handler,
cdns3_device_thread_irq_handler, cdns3_device_thread_irq_handler,
IRQF_SHARED, dev_name(cdns->dev), cdns); IRQF_SHARED, dev_name(cdns->dev),
cdns->gadget_dev);
if (ret) if (ret)
goto err0; goto err0;
......
...@@ -26,6 +26,7 @@ static int (*orig_bus_suspend)(struct usb_hcd *hcd); ...@@ -26,6 +26,7 @@ static int (*orig_bus_suspend)(struct usb_hcd *hcd);
struct ehci_ci_priv { struct ehci_ci_priv {
struct regulator *reg_vbus; struct regulator *reg_vbus;
bool enabled;
}; };
static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable) static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable)
...@@ -37,7 +38,7 @@ static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable) ...@@ -37,7 +38,7 @@ static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable)
int ret = 0; int ret = 0;
int port = HCS_N_PORTS(ehci->hcs_params); int port = HCS_N_PORTS(ehci->hcs_params);
if (priv->reg_vbus) { if (priv->reg_vbus && enable != priv->enabled) {
if (port > 1) { if (port > 1) {
dev_warn(dev, dev_warn(dev,
"Not support multi-port regulator control\n"); "Not support multi-port regulator control\n");
...@@ -53,6 +54,7 @@ static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable) ...@@ -53,6 +54,7 @@ static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable)
enable ? "enable" : "disable", ret); enable ? "enable" : "disable", ret);
return ret; return ret;
} }
priv->enabled = enable;
} }
if (enable && (ci->platdata->phy_mode == USBPHY_INTERFACE_MODE_HSIC)) { if (enable && (ci->platdata->phy_mode == USBPHY_INTERFACE_MODE_HSIC)) {
......
...@@ -203,8 +203,57 @@ static const unsigned short super_speed_maxpacket_maxes[4] = { ...@@ -203,8 +203,57 @@ static const unsigned short super_speed_maxpacket_maxes[4] = {
[USB_ENDPOINT_XFER_INT] = 1024, [USB_ENDPOINT_XFER_INT] = 1024,
}; };
static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, static bool endpoint_is_duplicate(struct usb_endpoint_descriptor *e1,
int asnum, struct usb_host_interface *ifp, int num_ep, struct usb_endpoint_descriptor *e2)
{
if (e1->bEndpointAddress == e2->bEndpointAddress)
return true;
if (usb_endpoint_xfer_control(e1) || usb_endpoint_xfer_control(e2)) {
if (usb_endpoint_num(e1) == usb_endpoint_num(e2))
return true;
}
return false;
}
/*
* Check for duplicate endpoint addresses in other interfaces and in the
* altsetting currently being parsed.
*/
static bool config_endpoint_is_duplicate(struct usb_host_config *config,
int inum, int asnum, struct usb_endpoint_descriptor *d)
{
struct usb_endpoint_descriptor *epd;
struct usb_interface_cache *intfc;
struct usb_host_interface *alt;
int i, j, k;
for (i = 0; i < config->desc.bNumInterfaces; ++i) {
intfc = config->intf_cache[i];
for (j = 0; j < intfc->num_altsetting; ++j) {
alt = &intfc->altsetting[j];
if (alt->desc.bInterfaceNumber == inum &&
alt->desc.bAlternateSetting != asnum)
continue;
for (k = 0; k < alt->desc.bNumEndpoints; ++k) {
epd = &alt->endpoint[k].desc;
if (endpoint_is_duplicate(epd, d))
return true;
}
}
}
return false;
}
static int usb_parse_endpoint(struct device *ddev, int cfgno,
struct usb_host_config *config, int inum, int asnum,
struct usb_host_interface *ifp, int num_ep,
unsigned char *buffer, int size) unsigned char *buffer, int size)
{ {
unsigned char *buffer0 = buffer; unsigned char *buffer0 = buffer;
...@@ -242,14 +291,11 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, ...@@ -242,14 +291,11 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
goto skip_to_next_endpoint_or_interface_descriptor; goto skip_to_next_endpoint_or_interface_descriptor;
/* Check for duplicate endpoint addresses */ /* Check for duplicate endpoint addresses */
for (i = 0; i < ifp->desc.bNumEndpoints; ++i) { if (config_endpoint_is_duplicate(config, inum, asnum, d)) {
if (ifp->endpoint[i].desc.bEndpointAddress ==
d->bEndpointAddress) {
dev_warn(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n", dev_warn(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n",
cfgno, inum, asnum, d->bEndpointAddress); cfgno, inum, asnum, d->bEndpointAddress);
goto skip_to_next_endpoint_or_interface_descriptor; goto skip_to_next_endpoint_or_interface_descriptor;
} }
}
endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints]; endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints];
++ifp->desc.bNumEndpoints; ++ifp->desc.bNumEndpoints;
...@@ -346,12 +392,16 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, ...@@ -346,12 +392,16 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
endpoint->desc.wMaxPacketSize = cpu_to_le16(8); endpoint->desc.wMaxPacketSize = cpu_to_le16(8);
} }
/* Validate the wMaxPacketSize field */ /*
* Validate the wMaxPacketSize field.
* Some devices have isochronous endpoints in altsetting 0;
* the USB-2 spec requires such endpoints to have wMaxPacketSize = 0
* (see the end of section 5.6.3), so don't warn about them.
*/
maxp = usb_endpoint_maxp(&endpoint->desc); maxp = usb_endpoint_maxp(&endpoint->desc);
if (maxp == 0) { if (maxp == 0 && !(usb_endpoint_xfer_isoc(d) && asnum == 0)) {
dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has wMaxPacketSize 0, skipping\n", dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has invalid wMaxPacketSize 0\n",
cfgno, inum, asnum, d->bEndpointAddress); cfgno, inum, asnum, d->bEndpointAddress);
goto skip_to_next_endpoint_or_interface_descriptor;
} }
/* Find the highest legal maxpacket size for this endpoint */ /* Find the highest legal maxpacket size for this endpoint */
...@@ -522,8 +572,8 @@ static int usb_parse_interface(struct device *ddev, int cfgno, ...@@ -522,8 +572,8 @@ static int usb_parse_interface(struct device *ddev, int cfgno,
if (((struct usb_descriptor_header *) buffer)->bDescriptorType if (((struct usb_descriptor_header *) buffer)->bDescriptorType
== USB_DT_INTERFACE) == USB_DT_INTERFACE)
break; break;
retval = usb_parse_endpoint(ddev, cfgno, inum, asnum, alt, retval = usb_parse_endpoint(ddev, cfgno, config, inum, asnum,
num_ep, buffer, size); alt, num_ep, buffer, size);
if (retval < 0) if (retval < 0)
return retval; return retval;
++n; ++n;
......
...@@ -2692,7 +2692,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub) ...@@ -2692,7 +2692,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
#define SET_ADDRESS_TRIES 2 #define SET_ADDRESS_TRIES 2
#define GET_DESCRIPTOR_TRIES 2 #define GET_DESCRIPTOR_TRIES 2
#define SET_CONFIG_TRIES (2 * (use_both_schemes + 1)) #define SET_CONFIG_TRIES (2 * (use_both_schemes + 1))
#define USE_NEW_SCHEME(i, scheme) ((i) / 2 == (int)scheme) #define USE_NEW_SCHEME(i, scheme) ((i) / 2 == (int)(scheme))
#define HUB_ROOT_RESET_TIME 60 /* times are in msec */ #define HUB_ROOT_RESET_TIME 60 /* times are in msec */
#define HUB_SHORT_RESET_TIME 10 #define HUB_SHORT_RESET_TIME 10
......
...@@ -2467,6 +2467,13 @@ static int dwc3_gadget_ep_reclaim_trb_linear(struct dwc3_ep *dep, ...@@ -2467,6 +2467,13 @@ static int dwc3_gadget_ep_reclaim_trb_linear(struct dwc3_ep *dep,
static bool dwc3_gadget_ep_request_completed(struct dwc3_request *req) static bool dwc3_gadget_ep_request_completed(struct dwc3_request *req)
{ {
/*
* For OUT direction, host may send less than the setup
* length. Return true for all OUT requests.
*/
if (!req->direction)
return true;
return req->request.actual == req->request.length; return req->request.actual == req->request.length;
} }
......
...@@ -445,6 +445,7 @@ config USB_TEGRA_XUDC ...@@ -445,6 +445,7 @@ config USB_TEGRA_XUDC
tristate "NVIDIA Tegra Superspeed USB 3.0 Device Controller" tristate "NVIDIA Tegra Superspeed USB 3.0 Device Controller"
depends on ARCH_TEGRA || COMPILE_TEST depends on ARCH_TEGRA || COMPILE_TEST
depends on PHY_TEGRA_XUSB depends on PHY_TEGRA_XUSB
select USB_ROLE_SWITCH
help help
Enables NVIDIA Tegra USB 3.0 device mode controller driver. Enables NVIDIA Tegra USB 3.0 device mode controller driver.
......
...@@ -415,13 +415,17 @@ static int ohci_da8xx_probe(struct platform_device *pdev) ...@@ -415,13 +415,17 @@ static int ohci_da8xx_probe(struct platform_device *pdev)
} }
da8xx_ohci->oc_gpio = devm_gpiod_get_optional(dev, "oc", GPIOD_IN); da8xx_ohci->oc_gpio = devm_gpiod_get_optional(dev, "oc", GPIOD_IN);
if (IS_ERR(da8xx_ohci->oc_gpio)) if (IS_ERR(da8xx_ohci->oc_gpio)) {
error = PTR_ERR(da8xx_ohci->oc_gpio);
goto err; goto err;
}
if (da8xx_ohci->oc_gpio) { if (da8xx_ohci->oc_gpio) {
oc_irq = gpiod_to_irq(da8xx_ohci->oc_gpio); oc_irq = gpiod_to_irq(da8xx_ohci->oc_gpio);
if (oc_irq < 0) if (oc_irq < 0) {
error = oc_irq;
goto err; goto err;
}
error = devm_request_threaded_irq(dev, oc_irq, NULL, error = devm_request_threaded_irq(dev, oc_irq, NULL,
ohci_da8xx_oc_thread, IRQF_TRIGGER_RISING | ohci_da8xx_oc_thread, IRQF_TRIGGER_RISING |
......
...@@ -75,14 +75,17 @@ static struct musb_hdrc_platform_data jz4740_musb_platform_data = { ...@@ -75,14 +75,17 @@ static struct musb_hdrc_platform_data jz4740_musb_platform_data = {
static int jz4740_musb_init(struct musb *musb) static int jz4740_musb_init(struct musb *musb)
{ {
struct device *dev = musb->controller->parent; struct device *dev = musb->controller->parent;
int err;
if (dev->of_node) if (dev->of_node)
musb->xceiv = devm_usb_get_phy_by_phandle(dev, "phys", 0); musb->xceiv = devm_usb_get_phy_by_phandle(dev, "phys", 0);
else else
musb->xceiv = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); musb->xceiv = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
if (IS_ERR(musb->xceiv)) { if (IS_ERR(musb->xceiv)) {
dev_err(dev, "No transceiver configured\n"); err = PTR_ERR(musb->xceiv);
return PTR_ERR(musb->xceiv); if (err != -EPROBE_DEFER)
dev_err(dev, "No transceiver configured: %d", err);
return err;
} }
/* Silicon does not implement ConfigData register. /* Silicon does not implement ConfigData register.
......
...@@ -1840,6 +1840,9 @@ ATTRIBUTE_GROUPS(musb); ...@@ -1840,6 +1840,9 @@ ATTRIBUTE_GROUPS(musb);
#define MUSB_QUIRK_B_INVALID_VBUS_91 (MUSB_DEVCTL_BDEVICE | \ #define MUSB_QUIRK_B_INVALID_VBUS_91 (MUSB_DEVCTL_BDEVICE | \
(2 << MUSB_DEVCTL_VBUS_SHIFT) | \ (2 << MUSB_DEVCTL_VBUS_SHIFT) | \
MUSB_DEVCTL_SESSION) MUSB_DEVCTL_SESSION)
#define MUSB_QUIRK_B_DISCONNECT_99 (MUSB_DEVCTL_BDEVICE | \
(3 << MUSB_DEVCTL_VBUS_SHIFT) | \
MUSB_DEVCTL_SESSION)
#define MUSB_QUIRK_A_DISCONNECT_19 ((3 << MUSB_DEVCTL_VBUS_SHIFT) | \ #define MUSB_QUIRK_A_DISCONNECT_19 ((3 << MUSB_DEVCTL_VBUS_SHIFT) | \
MUSB_DEVCTL_SESSION) MUSB_DEVCTL_SESSION)
...@@ -1862,6 +1865,11 @@ static void musb_pm_runtime_check_session(struct musb *musb) ...@@ -1862,6 +1865,11 @@ static void musb_pm_runtime_check_session(struct musb *musb)
s = MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV | s = MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV |
MUSB_DEVCTL_HR; MUSB_DEVCTL_HR;
switch (devctl & ~s) { switch (devctl & ~s) {
case MUSB_QUIRK_B_DISCONNECT_99:
musb_dbg(musb, "Poll devctl in case of suspend after disconnect\n");
schedule_delayed_work(&musb->irq_work,
msecs_to_jiffies(1000));
break;
case MUSB_QUIRK_B_INVALID_VBUS_91: case MUSB_QUIRK_B_INVALID_VBUS_91:
if (musb->quirk_retries && !musb->flush_irq_work) { if (musb->quirk_retries && !musb->flush_irq_work) {
musb_dbg(musb, musb_dbg(musb,
...@@ -2310,6 +2318,9 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) ...@@ -2310,6 +2318,9 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
musb_disable_interrupts(musb); musb_disable_interrupts(musb);
musb_writeb(musb->mregs, MUSB_DEVCTL, 0); musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
/* MUSB_POWER_SOFTCONN might be already set, JZ4740 does this. */
musb_writeb(musb->mregs, MUSB_POWER, 0);
/* Init IRQ workqueue before request_irq */ /* Init IRQ workqueue before request_irq */
INIT_DELAYED_WORK(&musb->irq_work, musb_irq_work); INIT_DELAYED_WORK(&musb->irq_work, musb_irq_work);
INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset); INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset);
......
...@@ -425,7 +425,7 @@ struct dma_controller *musbhs_dma_controller_create(struct musb *musb, ...@@ -425,7 +425,7 @@ struct dma_controller *musbhs_dma_controller_create(struct musb *musb,
controller->controller.channel_abort = dma_channel_abort; controller->controller.channel_abort = dma_channel_abort;
if (request_irq(irq, dma_controller_irq, 0, if (request_irq(irq, dma_controller_irq, 0,
dev_name(musb->controller), &controller->controller)) { dev_name(musb->controller), controller)) {
dev_err(dev, "request_irq %d failed!\n", irq); dev_err(dev, "request_irq %d failed!\n", irq);
musb_dma_controller_destroy(&controller->controller); musb_dma_controller_destroy(&controller->controller);
......
...@@ -567,6 +567,9 @@ static void option_instat_callback(struct urb *urb); ...@@ -567,6 +567,9 @@ static void option_instat_callback(struct urb *urb);
/* Interface must have two endpoints */ /* Interface must have two endpoints */
#define NUMEP2 BIT(16) #define NUMEP2 BIT(16)
/* Device needs ZLP */
#define ZLP BIT(17)
static const struct usb_device_id option_ids[] = { static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
...@@ -1172,6 +1175,8 @@ static const struct usb_device_id option_ids[] = { ...@@ -1172,6 +1175,8 @@ static const struct usb_device_id option_ids[] = {
.driver_info = NCTRL(0) | RSVD(3) }, .driver_info = NCTRL(0) | RSVD(3) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1102, 0xff), /* Telit ME910 (ECM) */ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1102, 0xff), /* Telit ME910 (ECM) */
.driver_info = NCTRL(0) }, .driver_info = NCTRL(0) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x110a, 0xff), /* Telit ME910G1 */
.driver_info = NCTRL(0) | RSVD(3) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910), { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910),
.driver_info = NCTRL(0) | RSVD(1) | RSVD(2) }, .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910_USBCFG4), { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910_USBCFG4),
...@@ -1196,6 +1201,8 @@ static const struct usb_device_id option_ids[] = { ...@@ -1196,6 +1201,8 @@ static const struct usb_device_id option_ids[] = {
.driver_info = NCTRL(0) | RSVD(1) }, .driver_info = NCTRL(0) | RSVD(1) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1901, 0xff), /* Telit LN940 (MBIM) */ { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1901, 0xff), /* Telit LN940 (MBIM) */
.driver_info = NCTRL(0) }, .driver_info = NCTRL(0) },
{ USB_DEVICE(TELIT_VENDOR_ID, 0x9010), /* Telit SBL FN980 flashing device */
.driver_info = NCTRL(0) | ZLP },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff), { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff),
.driver_info = RSVD(1) }, .driver_info = RSVD(1) },
...@@ -2097,6 +2104,9 @@ static int option_attach(struct usb_serial *serial) ...@@ -2097,6 +2104,9 @@ static int option_attach(struct usb_serial *serial)
if (!(device_flags & NCTRL(iface_desc->bInterfaceNumber))) if (!(device_flags & NCTRL(iface_desc->bInterfaceNumber)))
data->use_send_setup = 1; data->use_send_setup = 1;
if (device_flags & ZLP)
data->use_zlp = 1;
spin_lock_init(&data->susp_lock); spin_lock_init(&data->susp_lock);
usb_set_serial_data(serial, data); usb_set_serial_data(serial, data);
......
...@@ -38,6 +38,7 @@ struct usb_wwan_intf_private { ...@@ -38,6 +38,7 @@ struct usb_wwan_intf_private {
spinlock_t susp_lock; spinlock_t susp_lock;
unsigned int suspended:1; unsigned int suspended:1;
unsigned int use_send_setup:1; unsigned int use_send_setup:1;
unsigned int use_zlp:1;
int in_flight; int in_flight;
unsigned int open_ports; unsigned int open_ports;
void *private; void *private;
......
...@@ -461,6 +461,7 @@ static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port, ...@@ -461,6 +461,7 @@ static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port,
void (*callback) (struct urb *)) void (*callback) (struct urb *))
{ {
struct usb_serial *serial = port->serial; struct usb_serial *serial = port->serial;
struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial);
struct urb *urb; struct urb *urb;
urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */ urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
...@@ -471,6 +472,9 @@ static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port, ...@@ -471,6 +472,9 @@ static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port,
usb_sndbulkpipe(serial->dev, endpoint) | dir, usb_sndbulkpipe(serial->dev, endpoint) | dir,
buf, len, callback, ctx); buf, len, callback, ctx);
if (intfdata->use_zlp && dir == USB_DIR_OUT)
urb->transfer_flags |= URB_ZERO_PACKET;
return urb; return urb;
} }
......
...@@ -432,20 +432,30 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci) ...@@ -432,20 +432,30 @@ irqreturn_t tcpci_irq(struct tcpci *tcpci)
if (status & TCPC_ALERT_RX_STATUS) { if (status & TCPC_ALERT_RX_STATUS) {
struct pd_message msg; struct pd_message msg;
unsigned int cnt; unsigned int cnt, payload_cnt;
u16 header; u16 header;
regmap_read(tcpci->regmap, TCPC_RX_BYTE_CNT, &cnt); regmap_read(tcpci->regmap, TCPC_RX_BYTE_CNT, &cnt);
/*
* 'cnt' corresponds to READABLE_BYTE_COUNT in section 4.4.14
* of the TCPCI spec [Rev 2.0 Ver 1.0 October 2017] and is
* defined in table 4-36 as one greater than the number of
* bytes received. And that number includes the header. So:
*/
if (cnt > 3)
payload_cnt = cnt - (1 + sizeof(msg.header));
else
payload_cnt = 0;
tcpci_read16(tcpci, TCPC_RX_HDR, &header); tcpci_read16(tcpci, TCPC_RX_HDR, &header);
msg.header = cpu_to_le16(header); msg.header = cpu_to_le16(header);
if (WARN_ON(cnt > sizeof(msg.payload))) if (WARN_ON(payload_cnt > sizeof(msg.payload)))
cnt = sizeof(msg.payload); payload_cnt = sizeof(msg.payload);
if (cnt > 0) if (payload_cnt > 0)
regmap_raw_read(tcpci->regmap, TCPC_RX_DATA, regmap_raw_read(tcpci->regmap, TCPC_RX_DATA,
&msg.payload, cnt); &msg.payload, payload_cnt);
/* Read complete, clear RX status alert bit */ /* Read complete, clear RX status alert bit */
tcpci_write16(tcpci, TCPC_ALERT, TCPC_ALERT_RX_STATUS); tcpci_write16(tcpci, TCPC_ALERT, TCPC_ALERT_RX_STATUS);
......
...@@ -94,15 +94,15 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num); ...@@ -94,15 +94,15 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num);
#define UCSI_ENABLE_NTFY_CMD_COMPLETE BIT(16) #define UCSI_ENABLE_NTFY_CMD_COMPLETE BIT(16)
#define UCSI_ENABLE_NTFY_EXT_PWR_SRC_CHANGE BIT(17) #define UCSI_ENABLE_NTFY_EXT_PWR_SRC_CHANGE BIT(17)
#define UCSI_ENABLE_NTFY_PWR_OPMODE_CHANGE BIT(18) #define UCSI_ENABLE_NTFY_PWR_OPMODE_CHANGE BIT(18)
#define UCSI_ENABLE_NTFY_CAP_CHANGE BIT(19) #define UCSI_ENABLE_NTFY_CAP_CHANGE BIT(21)
#define UCSI_ENABLE_NTFY_PWR_LEVEL_CHANGE BIT(20) #define UCSI_ENABLE_NTFY_PWR_LEVEL_CHANGE BIT(22)
#define UCSI_ENABLE_NTFY_PD_RESET_COMPLETE BIT(21) #define UCSI_ENABLE_NTFY_PD_RESET_COMPLETE BIT(23)
#define UCSI_ENABLE_NTFY_CAM_CHANGE BIT(22) #define UCSI_ENABLE_NTFY_CAM_CHANGE BIT(24)
#define UCSI_ENABLE_NTFY_BAT_STATUS_CHANGE BIT(23) #define UCSI_ENABLE_NTFY_BAT_STATUS_CHANGE BIT(25)
#define UCSI_ENABLE_NTFY_PARTNER_CHANGE BIT(24) #define UCSI_ENABLE_NTFY_PARTNER_CHANGE BIT(27)
#define UCSI_ENABLE_NTFY_PWR_DIR_CHANGE BIT(25) #define UCSI_ENABLE_NTFY_PWR_DIR_CHANGE BIT(28)
#define UCSI_ENABLE_NTFY_CONNECTOR_CHANGE BIT(26) #define UCSI_ENABLE_NTFY_CONNECTOR_CHANGE BIT(30)
#define UCSI_ENABLE_NTFY_ERROR BIT(27) #define UCSI_ENABLE_NTFY_ERROR BIT(31)
#define UCSI_ENABLE_NTFY_ALL 0xdbe70000 #define UCSI_ENABLE_NTFY_ALL 0xdbe70000
/* SET_UOR command bits */ /* SET_UOR command bits */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment