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

Commit bb8e958a 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 6d1a19d4 6ac9a42b
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -68,6 +68,7 @@ Optional properties :
- interrupt-names : Optional interrupt resource entries are:
- interrupt-names : Optional interrupt resource entries are:
    "async_irq" : Interrupt from HSPHY for asynchronous wakeup events in LPM.
    "async_irq" : Interrupt from HSPHY for asynchronous wakeup events in LPM.
    "pmic_id_irq" : Interrupt from PMIC for external ID pin notification.
    "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
- qcom,hsusb-otg-disable-reset: If present then core is RESET only during
	    init, otherwise core is RESET for every cable disconnect as well
	    init, otherwise core is RESET for every cable disconnect as well
- qcom,hsusb-otg-pnoc-errata-fix: If present then workaround for PNOC
- qcom,hsusb-otg-pnoc-errata-fix: If present then workaround for PNOC
+108 −5
Original line number Original line Diff line number Diff line
@@ -756,6 +756,9 @@ static int msm_otg_reset(struct usb_phy *phy)
			ULPI_SET(ULPI_PWR_CLK_MNG_REG));
			ULPI_SET(ULPI_PWR_CLK_MNG_REG));
		/* Enable PMIC pull-up */
		/* Enable PMIC pull-up */
		pm8xxx_usb_id_pullup(1);
		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)
	if (motg->caps & ALLOW_VDD_MIN_WITH_RETENTION_DISABLED)
@@ -1098,7 +1101,8 @@ static void msm_otg_enable_phy_hv_int(struct msm_otg *motg)
	bool dp_dm_hv_int = false;
	bool dp_dm_hv_int = false;
	u32 val;
	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;
		bsv_id_hv_int = true;
	if (motg->host_bus_suspend || motg->device_bus_suspend)
	if (motg->host_bus_suspend || motg->device_bus_suspend)
		dp_dm_hv_int = true;
		dp_dm_hv_int = true;
@@ -1130,6 +1134,8 @@ static void msm_otg_enable_phy_hv_int(struct msm_otg *motg)
	default:
	default:
		break;
		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)
static void msm_otg_disable_phy_hv_int(struct msm_otg *motg)
@@ -1138,7 +1144,8 @@ static void msm_otg_disable_phy_hv_int(struct msm_otg *motg)
	bool dp_dm_hv_int = false;
	bool dp_dm_hv_int = false;
	u32 val;
	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;
		bsv_id_hv_int = true;
	if (motg->host_bus_suspend || motg->device_bus_suspend)
	if (motg->host_bus_suspend || motg->device_bus_suspend)
		dp_dm_hv_int = true;
		dp_dm_hv_int = true;
@@ -1171,6 +1178,8 @@ static void msm_otg_disable_phy_hv_int(struct msm_otg *motg)
	default:
	default:
		break;
		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)
static void msm_otg_enter_phy_retention(struct msm_otg *motg)
@@ -1192,6 +1201,7 @@ static void msm_otg_enter_phy_retention(struct msm_otg *motg)
	default:
	default:
		break;
		break;
	}
	}
	pr_debug("USB PHY is in retention\n");
}
}


static void msm_otg_exit_phy_retention(struct msm_otg *motg)
static void msm_otg_exit_phy_retention(struct msm_otg *motg)
@@ -1214,6 +1224,25 @@ static void msm_otg_exit_phy_retention(struct msm_otg *motg)
	default:
	default:
		break;
		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)
#define PHY_SUSPEND_TIMEOUT_USEC	(500 * 1000)
@@ -1471,6 +1500,8 @@ phcd_retry:
		else
		else
			enable_irq_wake(motg->irq);
			enable_irq_wake(motg->irq);


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


		if (motg->phy_irq)
			disable_irq_wake(motg->phy_irq);
		if (motg->pdata->pmic_id_irq)
		if (motg->pdata->pmic_id_irq)
			disable_irq_wake(motg->pdata->pmic_id_irq);
			disable_irq_wake(motg->pdata->pmic_id_irq);
		if (motg->ext_id_irq)
		if (motg->ext_id_irq)
@@ -1691,6 +1724,11 @@ skip_phy_resume:
	if (motg->async_irq)
	if (motg->async_irq)
		disable_irq(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)
	if (motg->host_bus_suspend)
		usb_hcd_resume_root_hub(hcd);
		usb_hcd_resume_root_hub(hcd);


@@ -2212,6 +2250,31 @@ static bool msm_otg_read_pmic_id_state(struct msm_otg *motg)
	return !!id;
	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,
static int msm_otg_mhl_register_callback(struct msm_otg *motg,
						void (*callback)(int on))
						void (*callback)(int on))
{
{
@@ -2922,6 +2985,11 @@ static void msm_otg_init_sm(struct msm_otg *motg)
					set_bit(ID, &motg->inputs);
					set_bit(ID, &motg->inputs);
				else
				else
					clear_bit(ID, &motg->inputs);
					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
			 * VBUS initial state is reported after PMIC
@@ -3870,6 +3938,8 @@ static void msm_id_status_w(struct work_struct *w)
		id_state = msm_otg_read_pmic_id_state(motg);
		id_state = msm_otg_read_pmic_id_state(motg);
	else if (motg->ext_id_irq)
	else if (motg->ext_id_irq)
		id_state = gpio_get_value(motg->pdata->usb_id_gpio);
		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 (id_state) {
		if (!test_and_set_bit(ID, &motg->inputs)) {
		if (!test_and_set_bit(ID, &motg->inputs)) {
@@ -5313,12 +5383,38 @@ static int msm_otg_probe(struct platform_device *pdev)
		goto destroy_wlock;
		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) {
	if (motg->async_irq) {
		ret = request_irq(motg->async_irq, msm_otg_irq,
		ret = request_irq(motg->async_irq, msm_otg_irq,
					IRQF_TRIGGER_RISING, "msm_otg", motg);
					IRQF_TRIGGER_RISING, "msm_otg", motg);
		if (ret) {
		if (ret) {
			dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n");
			dev_err(&pdev->dev, "request irq failed (ASYNC INT)\n");
			goto free_irq;
			goto free_phy_irq;
		}
		}
		disable_irq(motg->async_irq);
		disable_irq(motg->async_irq);
	}
	}
@@ -5355,7 +5451,8 @@ static int msm_otg_probe(struct platform_device *pdev)
	}
	}


	if (motg->pdata->mode == USB_OTG &&
	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)) {
		if (gpio_is_valid(motg->pdata->usb_id_gpio)) {
			/* usb_id_gpio request */
			/* usb_id_gpio request */
@@ -5406,7 +5503,7 @@ static int msm_otg_probe(struct platform_device *pdev)
			 motg->pdata->pmic_id_irq || motg->ext_id_irq))
			 motg->pdata->pmic_id_irq || motg->ext_id_irq))
		motg->caps = ALLOW_PHY_POWER_COLLAPSE | ALLOW_PHY_RETENTION;
		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;
		motg->caps = ALLOW_PHY_RETENTION | ALLOW_PHY_REGULATORS_LPM;


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


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


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


struct ci13xxx_platform_data {
struct ci13xxx_platform_data {
+18 −0
Original line number Original line Diff line number Diff line
@@ -135,4 +135,22 @@
#define USB_PHY_CSR_PHY_CTRL3 (MSM_USB_PHY_CSR_BASE + 0x094)
#define USB_PHY_CSR_PHY_CTRL3 (MSM_USB_PHY_CSR_BASE + 0x094)
#define CLAMP_MPM_DPSE_DMSE_EN_N BIT(2)
#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__ */
#endif /* __LINUX_USB_GADGET_MSM72K_UDC_H__ */