diff options
| author | Doug Zobel <dzobel1@motorola.com> | 2013-12-16 13:19:40 -0600 | 
|---|---|---|
| committer | James Wylder <jwylder@motorola.com> | 2014-03-05 17:46:59 -0600 | 
| commit | 5b712f6b46caa76fc55d41658e36814ee35ef2cd (patch) | |
| tree | ddfe5e94409ab1240b72cd2a17d4153dd2d368da | |
| parent | a6d25ae83a8ef2d4b363533c2e10f02d16a13305 (diff) | |
| download | olio-linux-3.10-5b712f6b46caa76fc55d41658e36814ee35ef2cd.tar.xz olio-linux-3.10-5b712f6b46caa76fc55d41658e36814ee35ef2cd.zip | |
IKXCLOCK-32 tusb dts: Add TUSB USB phy driver
Add support for TI TUSB1211 USB phy driver.  Enable phy when
VBUS is sensed, and disable when VBUS is not present
Change-Id: I80854285bdc15e7949c453b2efd6bacf829cd54b
Reviewed-on: http://gerrit.pcs.mot.com/590175
SLTApproved: Slta Waiver <sltawvr@motorola.com>
Tested-by: Jira Key <jirakey@motorola.com>
Reviewed-by: Jee Su Chang <w20740@motorola.com>
Reviewed-by: James Wylder <jwylder@motorola.com>
Submit-Approved: Jira Key <jirakey@motorola.com>
| -rw-r--r-- | arch/arm/boot/dts/omap3-minnow-p0.dts | 26 | ||||
| -rw-r--r-- | arch/arm/boot/dts/omap3-minnow.dtsi | 7 | ||||
| -rwxr-xr-x | arch/arm/configs/minnow_defconfig | 1 | ||||
| -rw-r--r-- | arch/arm/mach-omap2/board-minnow.c | 1 | ||||
| -rw-r--r-- | drivers/usb/phy/Kconfig | 11 | ||||
| -rw-r--r-- | drivers/usb/phy/Makefile | 3 | ||||
| -rw-r--r-- | drivers/usb/phy/phy-tusb.c | 300 | 
7 files changed, 347 insertions, 2 deletions
| diff --git a/arch/arm/boot/dts/omap3-minnow-p0.dts b/arch/arm/boot/dts/omap3-minnow-p0.dts index 10dca9e08b2..2d3eecfea2a 100644 --- a/arch/arm/boot/dts/omap3-minnow-p0.dts +++ b/arch/arm/boot/dts/omap3-minnow-p0.dts @@ -18,6 +18,32 @@  		compatible = "mot,vib-gpio";  		vib-gpio-supply = <&ldo6_reg>;  	}; + +	tusb_phy: tusb-usb@0 { +		compatible = "ti,tusb-usb"; +		irq-gpio = <142>; +		resetn-gpio = <15>; +		cs-gpio = <16>; +		csn-gpio = <27>; +		reg = <0 0>; +	}; +}; + +&usb_phy_pins { +	pinctrl-single,pins = < +		0x140 0x104     /* MCBSP3_CLKX, MODE4 (GPIO-142) | INPUT */ +		0x5ae 0x004     /* ETK_D1, MODE4 (GPIO_15) | OUTPUT */ +		0x5b0 0x004     /* ETK_D2, MODE4 (GPIO_16) | OUTPUT */ +		0x5c6 0x004     /* EDK_D13, MODE4 (GPIO_27) | OUTPUT */ +	>; +}; + +&usb_otg_hs { +	interface-type = <0>; +	usb-phy = <&tusb_phy>; +	mode = <3>; +	power = <50>; +  };  &mcspi1 { diff --git a/arch/arm/boot/dts/omap3-minnow.dtsi b/arch/arm/boot/dts/omap3-minnow.dtsi index 5997b6cdb2c..7140a47cca1 100644 --- a/arch/arm/boot/dts/omap3-minnow.dtsi +++ b/arch/arm/boot/dts/omap3-minnow.dtsi @@ -150,7 +150,10 @@  &omap3_pmx_core {  	pinctrl-names = "default"; -	pinctrl-0 = <&board_pins>; +	pinctrl-0 = < +		&board_pins +		&usb_phy_pins +	>;  	board_pins: pinmux_board_pins {  		pinctrl-single,pins = < @@ -196,7 +199,9 @@  			0x5c0 0x004	/* ETK_D10, MODE4 | OUTPUT */  			0x5c8 0x004	/* ETK_D14, MODE4 | OUTPUT */  		>; +	}; +	usb_phy_pins: pinmux_board_pins {  	};  }; diff --git a/arch/arm/configs/minnow_defconfig b/arch/arm/configs/minnow_defconfig index 90323b3d6be..72070b266eb 100755 --- a/arch/arm/configs/minnow_defconfig +++ b/arch/arm/configs/minnow_defconfig @@ -1836,6 +1836,7 @@ CONFIG_USB_PHY=y  # CONFIG_USB_RCAR_PHY is not set  # CONFIG_USB_ULPI is not set  CONFIG_CPCAP_USB=y +CONFIG_USB_TUSB=y  CONFIG_USB_GADGET=y  # CONFIG_USB_GADGET_DEBUG is not set  # CONFIG_USB_GADGET_DEBUG_FILES is not set diff --git a/arch/arm/mach-omap2/board-minnow.c b/arch/arm/mach-omap2/board-minnow.c index 209bd9031b5..47f6da16e3d 100644 --- a/arch/arm/mach-omap2/board-minnow.c +++ b/arch/arm/mach-omap2/board-minnow.c @@ -37,6 +37,7 @@ static const char *omap3_gp_boards_compat[] __initdata = {  };  static void __init minnow_musb_init(void)  { +	usb_bind_phy("musb-hdrc.0.auto", 0, "tps-usb");  	usb_bind_phy("musb-hdrc.1.auto", 0, "cpcap_usb");  	usb_musb_init(NULL);  } diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 6fcfa960fad..181c7f6a586 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -217,6 +217,17 @@ config USB_ULPI_VIEWPORT  	help  	  Provides read/write operations to the ULPI phy register set for  	  controllers with a viewport register (e.g. Chipidea/ARC controllers). +config USB_TUSB +	bool "TI TUSB-1211 Transceiver Driver" +	depends on USB || USB_GADGET +	help +	  Say Y here to add support for TI TUSB-1211 USB phy tranceiver and +          dynamic enable/disable based on the presence of VBUS. + +          To compile this driver as a module, choose M here. + +	  If you're not sure if this applies to you, it probably doesn't; +	  say N here.  config CPCAP_USB  	bool "CPCAP USB Transceiver Driver"  	help diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index bef5f525ab8..ba432e9ad9e 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -32,4 +32,5 @@ obj-$(CONFIG_USB_MXS_PHY)		+= phy-mxs-usb.o  obj-$(CONFIG_USB_RCAR_PHY)		+= phy-rcar-usb.o  obj-$(CONFIG_USB_ULPI)			+= phy-ulpi.o  obj-$(CONFIG_USB_ULPI_VIEWPORT)		+= phy-ulpi-viewport.o -obj-$(CONFIG_CPCAP_USB)		+= cpcap-usb.o +obj-$(CONFIG_USB_TUSB)			+= phy-tusb.o +obj-$(CONFIG_CPCAP_USB)			+= cpcap-usb.o diff --git a/drivers/usb/phy/phy-tusb.c b/drivers/usb/phy/phy-tusb.c new file mode 100644 index 00000000000..03e9a587a8c --- /dev/null +++ b/drivers/usb/phy/phy-tusb.c @@ -0,0 +1,300 @@ +/* + * tusb - TI TUSB transceiver driver, talking to OMAP OTG controller + * + * Copyright (C) 2013 Motorola Mobility + * Copyright (C) 2004-2007 Texas Instruments + * Copyright (C) 2008 Nokia Corporation + * Copyright (C) 2009 Google, Inc. + * Contact: Erik Gilling <konkers@android.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Based on twl4030-usb.c + * + */ + +#include <linux/platform_device.h> +#include <linux/usb/otg.h> +#include <linux/gpio.h> +#include <linux/irq.h> +#include <linux/workqueue.h> +#include <linux/wakelock.h> +#include <linux/of.h> +#include <linux/module.h> + +struct tusb_usb { +	struct usb_phy		phy; +	struct device		*dev; +	struct work_struct work; +	struct workqueue_struct *workqueue; +	struct wake_lock wake_lock; +	int			irq; +	int			irq_gpio; +	int			resetn_gpio; +	int			cs_gpio; +	int			csn_gpio; +}; + +static int tusb_set_suspend(struct usb_phy *x, int suspend) +{ +	return 0; +} + +static int tusb_set_peripheral(struct usb_otg *otg, +		struct usb_gadget *gadget) +{ +	struct usb_phy	*phy = otg->phy; + +	otg->gadget = gadget; +	if (!gadget) +		phy->state = OTG_STATE_UNDEFINED; + +	return 0; +} + +static int tusb_set_host(struct usb_otg *otg, struct usb_bus *host) +{ +	struct usb_phy	*phy = otg->phy; + +	otg->host = host; +	if (!host) +		phy->state = OTG_STATE_UNDEFINED; + +	return 0; +} + + +static int tusb_usb_set_vbus(struct usb_otg *otg, bool enabled) +{ +	return 0; +} +static int tusb_usb_start_srp(struct usb_otg *otg) +{ +	return 0; +} + +static void tusb_usb_work_func(struct work_struct *work) +{ +	struct tusb_usb *tusb = +		container_of(work, struct tusb_usb, work); +	int vbus_stat = gpio_get_value(tusb->irq_gpio); + +	if (vbus_stat) { +		if (tusb->resetn_gpio >= 0) +			gpio_set_value(tusb->resetn_gpio, 1); +		if (tusb->cs_gpio >= 0) +			gpio_set_value(tusb->cs_gpio, 1); +		if (tusb->csn_gpio >= 0) +			gpio_set_value(tusb->csn_gpio, 0); +	} else { +		if (tusb->resetn_gpio >= 0) +			gpio_set_value(tusb->resetn_gpio, 0); +		if (tusb->cs_gpio >= 0) +			gpio_set_value(tusb->cs_gpio, 0); +		if (tusb->csn_gpio >= 0) +			gpio_set_value(tusb->csn_gpio, 1); +	} + +	if (wake_lock_active(&tusb->wake_lock)) +		wake_unlock(&tusb->wake_lock); +} + + +static irqreturn_t tusb_usb_isr(int irq, void *data) +{ +	struct tusb_usb *tusb = data; +	wake_lock(&tusb->wake_lock); +	queue_work(tusb->workqueue, &tusb->work); + +	return IRQ_HANDLED; +} + +static int  tusb_usb_probe(struct platform_device *pdev) +{ +	struct tusb_usb	*tusb; +	struct usb_otg	*otg; +	struct device_node *np; +	int gpio; + +	np = pdev->dev.of_node; +	if (!np) { +		dev_err(&pdev->dev, "devtree data not found\n"); +		return -EINVAL; +	} +	tusb = devm_kzalloc(&pdev->dev, sizeof(*tusb), GFP_KERNEL); +	if (!tusb) { +		dev_err(&pdev->dev, "unable to allocate memory for tusb PHY\n"); +		return -ENOMEM; +	} +	tusb->irq = -1; +	tusb->irq_gpio = -1; +	tusb->resetn_gpio = -1; +	tusb->cs_gpio = -1; +	tusb->csn_gpio = -1; + +	otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL); +	if (!otg) { +		dev_err(&pdev->dev, "unable to allocate memory for tusb OTG\n"); +		return -ENOMEM; +	} + +	wake_lock_init(&tusb->wake_lock, WAKE_LOCK_SUSPEND, "tusb"); + +	tusb->workqueue = create_workqueue("tusb"); +	INIT_WORK(&tusb->work, tusb_usb_work_func); + +	if (!of_property_read_u32(np, "resetn-gpio", &gpio)) { +		if (!gpio_request(gpio, "tusb-resetn")) { +			if (!gpio_direction_output(gpio, 1)) +				tusb->resetn_gpio = gpio; +			else +				gpio_free(gpio); +		} +	} + +	if (!of_property_read_u32(np, "cs-gpio", &gpio)) { +		if (!gpio_request(gpio, "tusb-cs")) { +			if (!gpio_direction_output(gpio, 1)) +				tusb->cs_gpio = gpio; +			else +				gpio_free(gpio); +		} +	} + +	if (!of_property_read_u32(np, "csn-gpio", &gpio)) { +		if (!gpio_request(gpio, "tusb-csn")) { +			if (!gpio_direction_output(gpio, 0)) +				tusb->csn_gpio = gpio; +			else +				gpio_free(gpio); +		} +	} + +	if (!of_property_read_u32(np, "irq-gpio", &gpio)) { +		tusb->irq_gpio = gpio; +		if (!gpio_request(tusb->irq_gpio, "tusb-irq")) { +			if (!gpio_direction_input(tusb->irq_gpio)) { +				tusb->irq = gpio_to_irq(tusb->irq_gpio); +				irq_set_irq_type(tusb->irq, +						 IRQ_TYPE_EDGE_RISING | +						 IRQ_TYPE_EDGE_FALLING); + +				if (request_irq(tusb->irq, tusb_usb_isr, +						IRQF_DISABLED | +						IRQF_TRIGGER_RISING, +						"tsub-irq", tusb)) { +					gpio_free(tusb->irq_gpio); +					tusb->irq = -1; +					tusb->irq_gpio = -1; +				} +			} else { +				gpio_free(tusb->irq_gpio); +			} +		} +	} +	if (tusb->irq == -1) +		dev_info(&pdev->dev, "Unable to get enable irq;" +				     " no interrupt support\n"); + +	tusb->dev		= &pdev->dev; +	tusb->phy.dev		= tusb->dev; +	tusb->phy.label		= "tusb"; +	tusb->phy.set_suspend	= tusb_set_suspend; +	tusb->phy.otg		= otg; +	tusb->phy.type		= USB_PHY_TYPE_USB2; + + +	otg->set_host		= tusb_set_host; +	otg->set_peripheral	= tusb_set_peripheral; +	otg->set_vbus		= tusb_usb_set_vbus; +	otg->start_srp		= tusb_usb_start_srp; +	otg->phy		= &tusb->phy; + +	usb_add_phy_dev(&tusb->phy); + +	platform_set_drvdata(pdev, tusb); + +	return 0; +} + +static int tusb_usb_remove(struct platform_device *pdev) +{ +	struct tusb_usb	*tusb = platform_get_drvdata(pdev); + + +	if (tusb->irq >= 0) { +		disable_irq_wake(tusb->irq); +		free_irq(tusb->irq, tusb); +		gpio_free(tusb->irq_gpio); +	} + +	if (tusb->csn_gpio >= 0) +		gpio_free(tusb->csn_gpio); +	if (tusb->cs_gpio >= 0) +		gpio_free(tusb->csn_gpio); +	if (tusb->resetn_gpio >= 0) +		gpio_free(tusb->csn_gpio); + +	cancel_work_sync(&tusb->work); +	destroy_workqueue(tusb->workqueue); + +	if (wake_lock_active(&tusb->wake_lock)) +		wake_unlock(&tusb->wake_lock); +	wake_lock_destroy(&tusb->wake_lock); + +	return 0; +} +#ifdef CONFIG_OF +static const struct of_device_id tusb_usb_id_table[] = { +	{ .compatible = "ti,tusb-usb" }, +	{} +}; +MODULE_DEVICE_TABLE(of, tusb_usb_id_table); +#endif + +static const struct platform_device_id tusb_usb_platform_id_table[] = { +	{"tusb-usb", 0}, +	{}, +}; +MODULE_DEVICE_TABLE(of, tusb_usb_platform_id_table); + +static struct platform_driver tusb_usb_driver = { +	.probe		= tusb_usb_probe, +	.remove		= (tusb_usb_remove), +	.driver		= { +		.name	= "tusb_usb", +		.owner	= THIS_MODULE, +#ifdef CONFIG_OF +		.of_match_table = of_match_ptr(tusb_usb_id_table), +#endif +	}, +	.id_table = tusb_usb_platform_id_table, +}; + +static int __init tusb_usb_init(void) +{ +	return platform_driver_register(&tusb_usb_driver); +} +subsys_initcall(tusb_usb_init); + +static void __exit tusb_usb_exit(void) +{ +	platform_driver_unregister(&tusb_usb_driver); +} +module_exit(tusb_usb_exit); + +MODULE_ALIAS("platform:tusb_usb stub"); +MODULE_DESCRIPTION("TUSB transceiver driver"); +MODULE_LICENSE("GPL"); |