usb: phy: msm: Add D+/D- lines route control
apq8016-sbc board is using Dual SPDT USB Switch (TC7USB40MU), witch is controlled by GPIO to de/multiplex D+/D- USB lines to USB2513B Hub and uB connector. Add support for this. Signed-off-by: Ivan T. Ivanov <ivan.ivanov@linaro.org> Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
		
							parent
							
								
									736d093b59
								
							
						
					
					
						commit
						6f98f545b0
					
				| @ -52,6 +52,10 @@ Required properties: | ||||
| Optional properties: | ||||
| - dr_mode:      One of "host", "peripheral" or "otg". Defaults to "otg" | ||||
| 
 | ||||
| - switch-gpio:  A phandle + gpio-specifier pair. Some boards are using Dual | ||||
|                 SPDT USB Switch, witch is cotrolled by GPIO to de/multiplex | ||||
|                 D+/D- USB lines between connectors. | ||||
| 
 | ||||
| - qcom,phy-init-sequence: PHY configuration sequence values. This is related to Device | ||||
|                 Mode Eye Diagram test. Start address at which these values will be | ||||
|                 written is ULPI_EXT_VENDOR_SPECIFIC. Value of -1 is reserved as | ||||
|  | ||||
| @ -18,6 +18,7 @@ | ||||
| 
 | ||||
| #include <linux/module.h> | ||||
| #include <linux/device.h> | ||||
| #include <linux/gpio/consumer.h> | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/clk.h> | ||||
| #include <linux/slab.h> | ||||
| @ -32,6 +33,7 @@ | ||||
| #include <linux/pm_runtime.h> | ||||
| #include <linux/of.h> | ||||
| #include <linux/of_device.h> | ||||
| #include <linux/reboot.h> | ||||
| #include <linux/reset.h> | ||||
| 
 | ||||
| #include <linux/usb.h> | ||||
| @ -1471,6 +1473,14 @@ static int msm_otg_vbus_notifier(struct notifier_block *nb, unsigned long event, | ||||
| 	else | ||||
| 		clear_bit(B_SESS_VLD, &motg->inputs); | ||||
| 
 | ||||
| 	if (test_bit(B_SESS_VLD, &motg->inputs)) { | ||||
| 		/* Switch D+/D- lines to Device connector */ | ||||
| 		gpiod_set_value_cansleep(motg->switch_gpio, 0); | ||||
| 	} else { | ||||
| 		/* Switch D+/D- lines to Hub */ | ||||
| 		gpiod_set_value_cansleep(motg->switch_gpio, 1); | ||||
| 	} | ||||
| 
 | ||||
| 	schedule_work(&motg->sm_work); | ||||
| 
 | ||||
| 	return NOTIFY_DONE; | ||||
| @ -1546,6 +1556,11 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) | ||||
| 
 | ||||
| 	motg->manual_pullup = of_property_read_bool(node, "qcom,manual-pullup"); | ||||
| 
 | ||||
| 	motg->switch_gpio = devm_gpiod_get_optional(&pdev->dev, "switch", | ||||
| 						    GPIOD_OUT_LOW); | ||||
| 	if (IS_ERR(motg->switch_gpio)) | ||||
| 		return PTR_ERR(motg->switch_gpio); | ||||
| 
 | ||||
| 	ext_id = ERR_PTR(-ENODEV); | ||||
| 	ext_vbus = ERR_PTR(-ENODEV); | ||||
| 	if (of_property_read_bool(node, "extcon")) { | ||||
| @ -1617,6 +1632,19 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int msm_otg_reboot_notify(struct notifier_block *this, | ||||
| 				 unsigned long code, void *unused) | ||||
| { | ||||
| 	struct msm_otg *motg = container_of(this, struct msm_otg, reboot); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Ensure that D+/D- lines are routed to uB connector, so | ||||
| 	 * we could load bootloader/kernel at next reboot | ||||
| 	 */ | ||||
| 	gpiod_set_value_cansleep(motg->switch_gpio, 0); | ||||
| 	return NOTIFY_DONE; | ||||
| } | ||||
| 
 | ||||
| static int msm_otg_probe(struct platform_device *pdev) | ||||
| { | ||||
| 	struct regulator_bulk_data regs[3]; | ||||
| @ -1781,6 +1809,17 @@ static int msm_otg_probe(struct platform_device *pdev) | ||||
| 			dev_dbg(&pdev->dev, "Can not create mode change file\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	if (test_bit(B_SESS_VLD, &motg->inputs)) { | ||||
| 		/* Switch D+/D- lines to Device connector */ | ||||
| 		gpiod_set_value_cansleep(motg->switch_gpio, 0); | ||||
| 	} else { | ||||
| 		/* Switch D+/D- lines to Hub */ | ||||
| 		gpiod_set_value_cansleep(motg->switch_gpio, 1); | ||||
| 	} | ||||
| 
 | ||||
| 	motg->reboot.notifier_call = msm_otg_reboot_notify; | ||||
| 	register_reboot_notifier(&motg->reboot); | ||||
| 
 | ||||
| 	pm_runtime_set_active(&pdev->dev); | ||||
| 	pm_runtime_enable(&pdev->dev); | ||||
| 
 | ||||
| @ -1807,6 +1846,14 @@ static int msm_otg_remove(struct platform_device *pdev) | ||||
| 	if (phy->otg->host || phy->otg->gadget) | ||||
| 		return -EBUSY; | ||||
| 
 | ||||
| 	unregister_reboot_notifier(&motg->reboot); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Ensure that D+/D- lines are routed to uB connector, so | ||||
| 	 * we could load bootloader/kernel at next reboot | ||||
| 	 */ | ||||
| 	gpiod_set_value_cansleep(motg->switch_gpio, 0); | ||||
| 
 | ||||
| 	extcon_unregister_notifier(motg->id.extcon, EXTCON_USB_HOST, &motg->id.nb); | ||||
| 	extcon_unregister_notifier(motg->vbus.extcon, EXTCON_USB, &motg->vbus.nb); | ||||
| 
 | ||||
|  | ||||
| @ -155,6 +155,10 @@ struct msm_usb_cable { | ||||
|  *	starting controller using usbcmd run/stop bit. | ||||
|  * @vbus: VBUS signal state trakining, using extcon framework | ||||
|  * @id: ID signal state trakining, using extcon framework | ||||
|  * @switch_gpio: Descriptor for GPIO used to control external Dual | ||||
|  *               SPDT USB Switch. | ||||
|  * @reboot: Used to inform the driver to route USB D+/D- line to Device | ||||
|  *	    connector | ||||
|  */ | ||||
| struct msm_otg { | ||||
| 	struct usb_phy phy; | ||||
| @ -188,6 +192,9 @@ struct msm_otg { | ||||
| 
 | ||||
| 	struct msm_usb_cable vbus; | ||||
| 	struct msm_usb_cable id; | ||||
| 
 | ||||
| 	struct gpio_desc *switch_gpio; | ||||
| 	struct notifier_block reboot; | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user