Commit 213356fe authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+90 −38
Original line number Diff line number Diff line
@@ -115,7 +115,7 @@ struct cpcap_usb_ints_state {
enum cpcap_gpio_mode {
	CPCAP_DM_DP,
	CPCAP_MDM_RX_TX,
	CPCAP_UNKNOWN,
	CPCAP_UNKNOWN_DISABLED,	/* Seems to disable USB lines */
	CPCAP_OTG_DM_DP,
};

@@ -134,6 +134,8 @@ struct cpcap_phy_ddata {
	struct iio_channel *id;
	struct regulator *vusb;
	atomic_t active;
	unsigned int vbus_provider:1;
	unsigned int docked:1;
};

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,
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 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)
{
	struct cpcap_phy_ddata *ddata;
@@ -220,15 +235,13 @@ static void cpcap_usb_detect(struct work_struct *work)
	if (error)
		return;

	if (s.id_ground) {
		dev_dbg(ddata->dev, "id ground, USB host mode\n");
		error = cpcap_usb_set_usb_mode(ddata);
		if (error)
			goto out_err;
	vbus = cpcap_usb_vbus_valid(ddata);

		error = musb_mailbox(MUSB_ID_GROUND);
		if (error)
			goto out_err;
	/* We need to kick the VBUS as USB A-host */
	if (s.id_ground && ddata->vbus_provider) {
		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,
					   CPCAP_BIT_VBUSSTBY_EN |
@@ -240,51 +253,86 @@ static void cpcap_usb_detect(struct work_struct *work)
		return;
	}

	error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,
				   CPCAP_BIT_VBUSSTBY_EN |
				   CPCAP_BIT_VBUSEN_SPI, 0);
	if (vbus && s.id_ground && ddata->docked) {
		dev_dbg(ddata->dev, "still docked as A-host, signal ID down\n");

		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)
			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? */
		if (s.id_ground) {
			dev_dbg(ddata->dev, "connected to a dock\n");
		/*
		 * Force check state again after musb has reoriented,
		 * otherwise devices won't enumerate after loading PHY
		 * 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);
		if (error)
			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)
			goto out_err;

		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 */
	if (vbus) {
		dev_dbg(ddata->dev, "connected to USB host\n");
		error = cpcap_usb_set_usb_mode(ddata);
		if (error)
			goto out_err;
		error = musb_mailbox(MUSB_VBUS_VALID);
		if (error)
			goto out_err;
		cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_VALID);

		return;
	}

	ddata->vbus_provider = false;
	ddata->docked = false;
	cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_OFF);

	/* Default to debug UART mode */
	error = cpcap_usb_set_uart_mode(ddata);
	if (error)
		goto out_err;

	error = musb_mailbox(MUSB_VBUS_OFF);
	if (error)
		goto out_err;

	dev_dbg(ddata->dev, "set UART mode\n");

	return;
@@ -376,7 +424,8 @@ static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata)
{
	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)
		goto out_err;

@@ -403,6 +452,11 @@ static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata)
	if (error)
		goto out_err;

	/* Enable UART mode */
	error = cpcap_usb_gpio_set_mode(ddata, CPCAP_DM_DP);
	if (error)
		goto out_err;

	return 0;

out_err:
@@ -415,7 +469,8 @@ static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata)
{
	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)
		return error;

@@ -434,12 +489,6 @@ static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata)
	if (error)
		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,
				   CPCAP_BIT_PU_SPI |
				   CPCAP_BIT_DMPD_SPI |
@@ -455,6 +504,11 @@ static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata)
	if (error)
		goto out_err;

	/* Enable USB mode */
	error = cpcap_usb_gpio_set_mode(ddata, CPCAP_OTG_DM_DP);
	if (error)
		goto out_err;

	return 0;

out_err:
@@ -649,9 +703,7 @@ static int cpcap_usb_phy_remove(struct platform_device *pdev)
	if (error)
		dev_err(ddata->dev, "could not set UART mode\n");

	error = musb_mailbox(MUSB_VBUS_OFF);
	if (error)
		dev_err(ddata->dev, "could not set mailbox\n");
	cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_OFF);

	usb_remove_phy(&ddata->phy);
	cancel_delayed_work_sync(&ddata->detect_work);
+3 −8
Original line number Diff line number Diff line
@@ -200,7 +200,7 @@ static void phy_mdm6600_status(struct work_struct *work)
	struct phy_mdm6600 *ddata;
	struct device *dev;
	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);
	dev = ddata->dev;
@@ -212,16 +212,11 @@ static void phy_mdm6600_status(struct work_struct *work)
	if (error)
		return;

	for (i = 0; i < PHY_MDM6600_NR_STATUS_LINES; i++) {
		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];
	ddata->status = values[0] & ((1 << PHY_MDM6600_NR_STATUS_LINES) - 1);

	dev_info(dev, "modem status: %i %s\n",
		 ddata->status,
		 phy_mdm6600_status_name[ddata->status & 7]);
		 phy_mdm6600_status_name[ddata->status]);
	complete(&ddata->ack);
}

+1 −1
Original line number Diff line number Diff line
@@ -66,7 +66,7 @@
/* QPHY_V3_PCS_MISC_CLAMP_ENABLE register bits */
#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_MAX			11

+4 −0
Original line number Diff line number Diff line
@@ -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;

	rate = (rate / 1000) * 1000;

	for (; cfg->pixclock != 0; cfg++)
		if (cfg->pixclock == rate && !cfg->fracdiv)
			break;
@@ -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;

	rate = (rate / 1000) * 1000;

	for (; cfg->pixclock != 0; cfg++)
		if (cfg->pixclock == rate)
			break;
+5 −9
Original line number Diff line number Diff line
@@ -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)
{
	struct cdns3_device *priv_dev;
	struct cdns3 *cdns = data;
	struct cdns3_device *priv_dev = data;
	irqreturn_t ret = IRQ_NONE;
	u32 reg;

	priv_dev = cdns->gadget_dev;

	/* check USB device interrupt */
	reg = readl(&priv_dev->regs->usb_ists);
	if (reg) {
@@ -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)
{
	struct cdns3_device *priv_dev;
	struct cdns3 *cdns = data;
	struct cdns3_device *priv_dev = data;
	irqreturn_t ret = IRQ_NONE;
	unsigned long flags;
	int bit;
	u32 reg;

	priv_dev = cdns->gadget_dev;
	spin_lock_irqsave(&priv_dev->lock, flags);

	reg = readl(&priv_dev->regs->usb_ists);
@@ -2539,7 +2534,7 @@ void cdns3_gadget_exit(struct cdns3 *cdns)

	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_put_autosuspend(cdns->dev);
@@ -2710,7 +2705,8 @@ static int __cdns3_gadget_init(struct cdns3 *cdns)
	ret = devm_request_threaded_irq(cdns->dev, cdns->dev_irq,
					cdns3_device_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)
		goto err0;
Loading