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

Commit 1f911e71 authored by Saket Saurabh's avatar Saket Saurabh
Browse files

msm: USB: Add support for USB ID detection



For USB Host mode, ID detection for USB connect and disconnect is
done using PMIC or PHY based on the platforms supporting PMIC or PHY
based ID detection. For PMIC and PHY based ID detection, support is
already added in driver.
For platform like MSM8916 where ID line is neither routed to PMIC nor
PHY, hence PMIC and PHY cannot be used for USB ID detection on these
platforms.
This change enables support for USB ID detection using external ID line
connected to msm gpio.

CRs-fixed: 601057
Change-Id: If8a585002145df4175441008bae7681774587e24
Signed-off-by: default avatarSaket Saurabh <ssaurabh@codeaurora.org>
parent 27a70795
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -112,6 +112,7 @@ Optional properties :
	vdd min.
- qcom,usbin-vadc: Corresponding vadc device's phandle to read usbin voltage using VADC.
	This will be used to get value of usb power supply's VOLTAGE_NOW property.
- qcom,usbid-gpio: This corresponds to gpio which is used for USB ID detection.

Example HSUSB OTG controller device node :
	usb@f9690000 {
@@ -151,6 +152,7 @@ Example HSUSB OTG controller device node :
		qcom,hsusb-otg-rw-during-lpm-workaround = <1>;
		qcom,disable-retention-with-vdd-min;
		qcom,usbin-vadc = <&pm8226_vadc>;
		qcom,usbid-gpio = <&msm_gpio 110 0>;
	};

MSM HSUSB EHCI controller
+52 −19
Original line number Diff line number Diff line
@@ -2571,6 +2571,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->ext_id_irq) {
				if (gpio_get_value(pdata->usb_id_gpio))
					set_bit(ID, &motg->inputs);
				else
					clear_bit(ID, &motg->inputs);
			}
			/*
			 * VBUS initial state is reported after PMIC
@@ -3481,20 +3486,26 @@ static void msm_otg_set_vbus_state(int online)
		queue_work(system_nrt_wq, &motg->sm_work);
}

static void msm_pmic_id_status_w(struct work_struct *w)
static void msm_id_status_w(struct work_struct *w)
{
	struct msm_otg *motg = container_of(w, struct msm_otg,
						pmic_id_status_work.work);
						id_status_work.work);
	int work = 0;
	int id_state = 0;

	if (msm_otg_read_pmic_id_state(motg)) {
	if (motg->pdata->pmic_id_irq)
		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);

	if (id_state) {
		if (!test_and_set_bit(ID, &motg->inputs)) {
			pr_debug("PMIC: ID set\n");
			pr_debug("ID set\n");
			work = 1;
		}
	} else {
		if (test_and_clear_bit(ID, &motg->inputs)) {
			pr_debug("PMIC: ID clear\n");
			pr_debug("ID clear\n");
			set_bit(A_BUS_REQ, &motg->inputs);
			work = 1;
		}
@@ -3509,8 +3520,8 @@ static void msm_pmic_id_status_w(struct work_struct *w)

}

#define MSM_PMIC_ID_STATUS_DELAY	5 /* 5msec */
static irqreturn_t msm_pmic_id_irq(int irq, void *data)
#define MSM_ID_STATUS_DELAY	5 /* 5msec */
static irqreturn_t msm_id_irq(int irq, void *data)
{
	struct msm_otg *motg = data;

@@ -3522,8 +3533,8 @@ static irqreturn_t msm_pmic_id_irq(int irq, void *data)

	if (!aca_id_turned_on)
		/*schedule delayed work for 5msec for ID line state to settle*/
		queue_delayed_work(system_nrt_wq, &motg->pmic_id_status_work,
				msecs_to_jiffies(MSM_PMIC_ID_STATUS_DELAY));
		queue_delayed_work(system_nrt_wq, &motg->id_status_work,
				msecs_to_jiffies(MSM_ID_STATUS_DELAY));

	return IRQ_HANDLED;
}
@@ -4376,6 +4387,10 @@ struct msm_otg_platform_data *msm_otg_dt_to_pdata(struct platform_device *pdev)
	if (pdata->pmic_id_irq < 0)
		pdata->pmic_id_irq = 0;

	pdata->usb_id_gpio = of_get_named_gpio(node, "qcom,usbid-gpio", 0);
	if (pdata->usb_id_gpio < 0)
		pr_debug("usb_id_gpio is not available\n");

	pdata->l1_supported = of_property_read_bool(node,
				"qcom,hsusb-l1-supported");
	pdata->enable_ahb2ahb_bypass = of_property_read_bool(node,
@@ -4404,6 +4419,7 @@ static int msm_otg_probe(struct platform_device *pdev)
	struct usb_phy *phy;
	struct msm_otg_platform_data *pdata;
	void __iomem *tcsr;
	int id_irq = 0;

	dev_info(&pdev->dev, "msm_otg probe\n");

@@ -4714,7 +4730,7 @@ static int msm_otg_probe(struct platform_device *pdev)
	msm_otg_init_timer(motg);
	INIT_WORK(&motg->sm_work, msm_otg_sm_work);
	INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work);
	INIT_DELAYED_WORK(&motg->pmic_id_status_work, msm_pmic_id_status_w);
	INIT_DELAYED_WORK(&motg->id_status_work, msm_id_status_w);
	INIT_DELAYED_WORK(&motg->suspend_work, msm_otg_suspend_work);
	setup_timer(&motg->id_timer, msm_otg_id_timer_func,
				(unsigned long) motg);
@@ -4770,19 +4786,36 @@ static int msm_otg_probe(struct platform_device *pdev)

	if (motg->pdata->mode == USB_OTG &&
		motg->pdata->otg_control == OTG_PMIC_CONTROL) {
		if (motg->pdata->pmic_id_irq) {
			ret = request_irq(motg->pdata->pmic_id_irq,
						msm_pmic_id_irq,

		if (gpio_is_valid(motg->pdata->usb_id_gpio)) {
			/* usb_id_gpio request */
			ret = gpio_request(motg->pdata->usb_id_gpio,
							"USB_ID_GPIO");
			if (ret < 0) {
				dev_err(&pdev->dev, "gpio req failed for id\n");
				motg->pdata->usb_id_gpio = 0;
				goto remove_phy;
			}
			/* usb_id_gpio to irq */
			id_irq = gpio_to_irq(motg->pdata->usb_id_gpio);
			motg->ext_id_irq = id_irq;
		} else if (motg->pdata->pmic_id_irq) {
			id_irq = motg->pdata->pmic_id_irq;
		}

		if (id_irq) {
			ret = request_irq(id_irq,
					  msm_id_irq,
					  IRQF_TRIGGER_RISING |
					  IRQF_TRIGGER_FALLING,
					  "msm_otg", motg);
			if (ret) {
				dev_err(&pdev->dev, "request irq failed for PMIC ID\n");
				dev_err(&pdev->dev, "request irq failed for ID\n");
				goto remove_phy;
			}
		} else {
			ret = -ENODEV;
			dev_err(&pdev->dev, "PMIC IRQ for ID notifications doesn't exist\n");
			dev_err(&pdev->dev, "ID IRQ doesn't exist\n");
			goto remove_phy;
		}
	}
@@ -4958,7 +4991,7 @@ static int msm_otg_remove(struct platform_device *pdev)
	msm_otg_mhl_register_callback(motg, NULL);
	msm_otg_debugfs_cleanup();
	cancel_delayed_work_sync(&motg->chg_work);
	cancel_delayed_work_sync(&motg->pmic_id_status_work);
	cancel_delayed_work_sync(&motg->id_status_work);
	cancel_delayed_work_sync(&motg->suspend_work);
	cancel_work_sync(&motg->sm_work);

+5 −1
Original line number Diff line number Diff line
@@ -250,6 +250,7 @@ enum usb_ctrl {
 *		mode with controller in device mode.
 * @bool disable_retention_with_vdd_min: Indicates whether to enable
		allowing VDDmin without putting PHY into retention.
 * @usb_id_gpio: Gpio used for USB ID detection.
 */
struct msm_otg_platform_data {
	int *phy_init_seq;
@@ -281,6 +282,7 @@ struct msm_otg_platform_data {
	bool rw_during_lpm_workaround;
	bool enable_ahb2ahb_bypass;
	bool disable_retention_with_vdd_min;
	int usb_id_gpio;
};

/* phy related flags */
@@ -369,6 +371,7 @@ struct msm_otg_platform_data {
 *               very slow plug in of wall charger.
 * @ui_enabled: USB Intterupt is enabled or disabled.
 * @pm_done: Indicates whether USB is PM resumed
 * @ext_id_irq: IRQ for ID interrupt.
 */
struct msm_otg {
	struct usb_phy phy;
@@ -412,7 +415,7 @@ struct msm_otg {
	int async_int;
	unsigned cur_power;
	struct delayed_work chg_work;
	struct delayed_work pmic_id_status_work;
	struct delayed_work id_status_work;
	struct delayed_work suspend_work;
	enum usb_chg_state chg_state;
	enum usb_chg_type chg_type;
@@ -490,6 +493,7 @@ struct msm_otg {
	int ui_enabled;
	bool pm_done;
	struct qpnp_vadc_chip	*vadc_dev;
	int ext_id_irq;
};

struct ci13xxx_platform_data {