Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d2f92e09 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: phy-msm-usb: Add support for the PHY based ID detection"

parents 948265e5 5c81e6ff
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@ Optional properties :
- interrupt-names : Optional interrupt resource entries are:
    "async_irq" : Interrupt from HSPHY for asynchronous wakeup events in LPM.
    "pmic_id_irq" : Interrupt from PMIC for external ID pin notification.
    "phy_irq" : Interrupt from PHY. Used for ID detection.
- qcom,hsusb-otg-disable-reset: If present then core is RESET only during
	    init, otherwise core is RESET for every cable disconnect as well
- qcom,hsusb-otg-pnoc-errata-fix: If present then workaround for PNOC
+108 −5
Original line number Diff line number Diff line
@@ -702,6 +702,9 @@ static int msm_otg_reset(struct usb_phy *phy)
			ULPI_SET(ULPI_PWR_CLK_MNG_REG));
		/* Enable PMIC pull-up */
		pm8xxx_usb_id_pullup(1);
		if (motg->phy_irq)
			writeb_relaxed(USB_PHY_ID_MASK,
				USB2_PHY_USB_PHY_INTERRUPT_MASK1);
	}

	if (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED)
@@ -1044,7 +1047,8 @@ static void msm_otg_enable_phy_hv_int(struct msm_otg *motg)
	bool dp_dm_hv_int = false;
	u32 val;

	if (motg->pdata->otg_control == OTG_PHY_CONTROL)
	if (motg->pdata->otg_control == OTG_PHY_CONTROL ||
				motg->phy_irq)
		bsv_id_hv_int = true;
	if (motg->host_bus_suspend || motg->device_bus_suspend)
		dp_dm_hv_int = true;
@@ -1076,6 +1080,8 @@ static void msm_otg_enable_phy_hv_int(struct msm_otg *motg)
	default:
		break;
	}
	pr_debug("%s: bsv_id_hv = %d dp_dm_hv_int = %d\n",
			__func__, bsv_id_hv_int, dp_dm_hv_int);
}

static void msm_otg_disable_phy_hv_int(struct msm_otg *motg)
@@ -1084,7 +1090,8 @@ static void msm_otg_disable_phy_hv_int(struct msm_otg *motg)
	bool dp_dm_hv_int = false;
	u32 val;

	if (motg->pdata->otg_control == OTG_PHY_CONTROL)
	if (motg->pdata->otg_control == OTG_PHY_CONTROL ||
				motg->phy_irq)
		bsv_id_hv_int = true;
	if (motg->host_bus_suspend || motg->device_bus_suspend)
		dp_dm_hv_int = true;
@@ -1117,6 +1124,8 @@ static void msm_otg_disable_phy_hv_int(struct msm_otg *motg)
	default:
		break;
	}
	pr_debug("%s: bsv_id_hv = %d dp_dm_hv_int = %d\n",
			__func__, bsv_id_hv_int, dp_dm_hv_int);
}

static void msm_otg_enter_phy_retention(struct msm_otg *motg)
@@ -1138,6 +1147,7 @@ static void msm_otg_enter_phy_retention(struct msm_otg *motg)
	default:
		break;
	}
	pr_debug("USB PHY is in retention\n");
}

static void msm_otg_exit_phy_retention(struct msm_otg *motg)
@@ -1160,6 +1170,25 @@ static void msm_otg_exit_phy_retention(struct msm_otg *motg)
	default:
		break;
	}
	pr_debug("USB PHY is exited from retention\n");
}

static void msm_id_status_w(struct work_struct *w);
static irqreturn_t msm_otg_phy_irq_handler(int irq, void *data)
{
	struct msm_otg *motg = data;

	if (atomic_read(&motg->in_lpm)) {
		pr_debug("PHY ID IRQ in LPM\n");
		motg->phy_irq_pending = true;
		if (!atomic_read(&motg->pm_suspended))
			pm_request_resume(motg->phy.dev);
	} else {
		pr_debug("PHY ID IRQ outside LPM\n");
		msm_id_status_w(&motg->id_status_work.work);
	}

	return IRQ_HANDLED;
}

#define PHY_SUSPEND_TIMEOUT_USEC	(500 * 1000)
@@ -1417,6 +1446,8 @@ phcd_retry:
		else
			enable_irq_wake(motg->irq);

		if (motg->phy_irq)
			enable_irq_wake(motg->phy_irq);
		if (motg->pdata->pmic_id_irq)
			enable_irq_wake(motg->pdata->pmic_id_irq);
		if (motg->ext_id_irq)
@@ -1604,6 +1635,8 @@ skip_phy_resume:
		else
			disable_irq_wake(motg->irq);

		if (motg->phy_irq)
			disable_irq_wake(motg->phy_irq);
		if (motg->pdata->pmic_id_irq)
			disable_irq_wake(motg->pdata->pmic_id_irq);
		if (motg->ext_id_irq)
@@ -1637,6 +1670,11 @@ skip_phy_resume:
	if (motg->async_irq)
		disable_irq(motg->async_irq);

	if (motg->phy_irq_pending) {
		motg->phy_irq_pending = false;
		msm_id_status_w(&motg->id_status_work.work);
	}

	if (motg->host_bus_suspend)
		usb_hcd_resume_root_hub(hcd);

@@ -2158,6 +2196,31 @@ static bool msm_otg_read_pmic_id_state(struct msm_otg *motg)
	return !!id;
}

static bool msm_otg_read_phy_id_state(struct msm_otg *motg)
{
	u8 val;

	/*
	 * clear the pending/outstanding interrupts and
	 * read the ID status from the SRC_STATUS register.
	 */
	writeb_relaxed(USB_PHY_ID_MASK, USB2_PHY_USB_PHY_INTERRUPT_CLEAR1);

	writeb_relaxed(0x1, USB2_PHY_USB_PHY_IRQ_CMD);
	/*
	 * Databook says 200 usec delay is required for
	 * clearing the interrupts.
	 */
	udelay(200);
	writeb_relaxed(0x0, USB2_PHY_USB_PHY_IRQ_CMD);

	val = readb_relaxed(USB2_PHY_USB_PHY_INTERRUPT_SRC_STATUS);
	if (val & USB_PHY_IDDIG_1_0)
		return false; /* ID is grounded */
	else
		return true;
}

static int msm_otg_mhl_register_callback(struct msm_otg *motg,
						void (*callback)(int on))
{
@@ -2868,6 +2931,11 @@ static void msm_otg_init_sm(struct msm_otg *motg)
					set_bit(ID, &motg->inputs);
				else
					clear_bit(ID, &motg->inputs);
			} else if (motg->phy_irq) {
				if (msm_otg_read_phy_id_state(motg))
					set_bit(ID, &motg->inputs);
				else
					clear_bit(ID, &motg->inputs);
			}
			/*
			 * VBUS initial state is reported after PMIC
@@ -3804,6 +3872,8 @@ static void msm_id_status_w(struct work_struct *w)
		id_state = msm_otg_read_pmic_id_state(motg);
	else if (motg->ext_id_irq)
		id_state = gpio_get_value(motg->pdata->usb_id_gpio);
	else if (motg->phy_irq)
		id_state = msm_otg_read_phy_id_state(motg);

	if (id_state) {
		if (!test_and_set_bit(ID, &motg->inputs)) {
@@ -5223,12 +5293,38 @@ static int msm_otg_probe(struct platform_device *pdev)
		goto destroy_wlock;
	}

	motg->phy_irq = platform_get_irq_byname(pdev, "phy_irq");
	if (motg->phy_irq < 0) {
		dev_dbg(&pdev->dev, "phy_irq is not present\n");
		motg->phy_irq = 0;
	} else {

		/* clear all interrupts before enabling the IRQ */
		writeb_relaxed(0xFF, USB2_PHY_USB_PHY_INTERRUPT_CLEAR0);
		writeb_relaxed(0xFF, USB2_PHY_USB_PHY_INTERRUPT_CLEAR1);

		writeb_relaxed(0x1, USB2_PHY_USB_PHY_IRQ_CMD);
		/*
		 * Databook says 200 usec delay is required for
		 * clearing the interrupts.
		 */
		udelay(200);
		writeb_relaxed(0x0, USB2_PHY_USB_PHY_IRQ_CMD);

		ret = request_irq(motg->phy_irq, msm_otg_phy_irq_handler,
				IRQF_TRIGGER_RISING, "msm_otg_phy_irq", motg);
		if (ret < 0) {
			dev_err(&pdev->dev, "phy_irq request fail %d\n", ret);
			goto free_irq;
		}
	}

	if (motg->async_irq) {
		ret = request_irq(motg->async_irq, msm_otg_irq,
					IRQF_TRIGGER_RISING, "msm_otg", motg);
		if (ret) {
			dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n");
			goto free_irq;
			goto free_phy_irq;
		}
		disable_irq(motg->async_irq);
	}
@@ -5265,7 +5361,8 @@ static int msm_otg_probe(struct platform_device *pdev)
	}

	if (motg->pdata->mode == USB_OTG &&
		motg->pdata->otg_control == OTG_PMIC_CONTROL) {
		motg->pdata->otg_control == OTG_PMIC_CONTROL &&
		!motg->phy_irq) {

		if (gpio_is_valid(motg->pdata->usb_id_gpio)) {
			/* usb_id_gpio request */
@@ -5316,7 +5413,7 @@ static int msm_otg_probe(struct platform_device *pdev)
			 motg->pdata->pmic_id_irq || motg->ext_id_irq))
		motg->caps = ALLOW_PHY_POWER_COLLAPSE | ALLOW_PHY_RETENTION;

	if (motg->pdata->otg_control == OTG_PHY_CONTROL)
	if (motg->pdata->otg_control == OTG_PHY_CONTROL || motg->phy_irq)
		motg->caps = ALLOW_PHY_RETENTION | ALLOW_PHY_REGULATORS_LPM;

	if (motg->pdata->mpm_dpshv_int || motg->pdata->mpm_dmshv_int)
@@ -5404,6 +5501,9 @@ remove_phy:
free_async_irq:
	if (motg->async_irq)
		free_irq(motg->async_irq, motg);
free_phy_irq:
	if (motg->phy_irq)
		free_irq(motg->phy_irq, motg);
free_irq:
	free_irq(motg->irq, motg);
destroy_wlock:
@@ -5495,6 +5595,8 @@ static int msm_otg_remove(struct platform_device *pdev)
	wake_lock_destroy(&motg->wlock);

	msm_hsusb_mhl_switch_enable(motg, 0);
	if (motg->phy_irq)
		free_irq(motg->phy_irq, motg);
	if (motg->pdata->pmic_id_irq)
		free_irq(motg->pdata->pmic_id_irq, motg);
	usb_remove_phy(phy);
@@ -5645,6 +5747,7 @@ static int msm_otg_pm_resume(struct device *dev)
	motg->pm_done = 0;

	if (motg->async_int || motg->sm_work_pending ||
			motg->phy_irq_pending ||
			!pm_runtime_suspended(dev)) {
		pm_runtime_get_noresume(dev);
		ret = msm_otg_resume(motg);
+5 −0
Original line number Diff line number Diff line
@@ -356,6 +356,8 @@ struct msm_otg_platform_data {
 * @pdata: otg device platform data.
 * @irq: IRQ number assigned for HSUSB controller.
 * @async_irq: IRQ number used by some controllers during low power state
 * @phy_irq: IRQ number assigned for PHY to notify events like id and line
		state changes.
 * @pclk: clock struct of iface_clk.
 * @core_clk: clock struct of core_bus_clk.
 * @sleep_clk: clock struct of sleep_clk for USB PHY.
@@ -405,12 +407,14 @@ struct msm_otg_platform_data {
	     the charger detection starts. When USB is disconnected and in lpm
	     pm_done is set to true.
 * @ext_id_irq: IRQ for ID interrupt.
 * @phy_irq_pending: Gets set when PHY IRQ arrives in LPM.
 */
struct msm_otg {
	struct usb_phy phy;
	struct msm_otg_platform_data *pdata;
	int irq;
	int async_irq;
	int phy_irq;
	struct clk *xo_clk;
	struct clk *pclk;
	struct clk *core_clk;
@@ -541,6 +545,7 @@ struct msm_otg {
	bool pm_done;
	struct qpnp_vadc_chip	*vadc_dev;
	int ext_id_irq;
	bool phy_irq_pending;
};

struct ci13xxx_platform_data {
+18 −0
Original line number Diff line number Diff line
@@ -135,4 +135,22 @@
#define USB_PHY_CSR_PHY_CTRL3 (MSM_USB_PHY_CSR_BASE + 0x094)
#define CLAMP_MPM_DPSE_DMSE_EN_N BIT(2)

#define USB2_PHY_USB_PHY_IRQ_CMD (MSM_USB_PHY_CSR_BASE + 0x0D0)
#define USB2_PHY_USB_PHY_INTERRUPT_SRC_STATUS (MSM_USB_PHY_CSR_BASE + 0x05C)

#define USB2_PHY_USB_PHY_INTERRUPT_STATUS0 (MSM_USB_PHY_CSR_BASE + 0x03C)
#define USB2_PHY_USB_PHY_INTERRUPT_STATUS1 (MSM_USB_PHY_CSR_BASE + 0x040)

#define USB2_PHY_USB_PHY_INTERRUPT_CLEAR0 (MSM_USB_PHY_CSR_BASE + 0x0DC)
#define USB2_PHY_USB_PHY_INTERRUPT_CLEAR1 (MSM_USB_PHY_CSR_BASE + 0x0E0)

#define USB2_PHY_USB_PHY_INTERRUPT_MASK0 (MSM_USB_PHY_CSR_BASE + 0x0D4)
#define USB2_PHY_USB_PHY_INTERRUPT_MASK1 (MSM_USB_PHY_CSR_BASE + 0x0D8)

#define USB_PHY_IDDIG_1_0 BIT(7)

#define USB_PHY_IDDIG_RISE_MASK BIT(0)
#define USB_PHY_IDDIG_FALL_MASK BIT(1)
#define USB_PHY_ID_MASK (USB_PHY_IDDIG_RISE_MASK | USB_PHY_IDDIG_FALL_MASK)

#endif /* __LINUX_USB_GADGET_MSM72K_UDC_H__ */