USB:Enable GPIO configuration at connect

GPIO alternate configuration is set when the USB is
connected and reset at USB disconnect.

Change-Id: I07d9c2ed5028879ecff309aa9e4ac25deac148f5
Signed-off-by: Sakethram Bommisetti <sakethram.bommisetti@stericsson.com>
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/27203
Reviewed-by: QATOOLS
Reviewed-by: Praveena NADAHALLY <praveen.nadahally@stericsson.com>
Reviewed-by: Philippe LANGLAIS <philippe.langlais@stericsson.com>
diff --git a/arch/arm/mach-ux500/board-mop500-usb.h b/arch/arm/mach-ux500/board-mop500-usb.h
new file mode 100644
index 0000000..8528846
--- /dev/null
+++ b/arch/arm/mach-ux500/board-mop500-usb.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ *
+ * Author: Saketh Ram Bommisetti <sakethram.bommisetti@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __BOARD_MOP500_USB_H
+#define __BOARD_MOP500_USB_H
+
+extern struct ab8500_usbgpio_platform_data ab8500_usbgpio_plat_data;
+
+#endif
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
index be1730b..62418a4 100644
--- a/arch/arm/mach-ux500/board-mop500.c
+++ b/arch/arm/mach-ux500/board-mop500.c
@@ -60,6 +60,7 @@
 #include "board-mop500-regulators.h"
 #include "board-mop500-bm.h"
 #include "board-mop500-wlan.h"
+#include "board-mop500-usb.h"
 #include "pins.h"
 
 #ifdef CONFIG_AB8500_DENC
@@ -258,6 +259,7 @@
 	.fg		= &ab8500_fg_plat_data,
 	.chargalg	= &ab8500_chargalg_plat_data,
 	.gpio		= &ab8500_gpio_pdata,
+	.usb		= &ab8500_usbgpio_plat_data,
 #ifdef CONFIG_INPUT_AB8500_ACCDET
 	.accdet = &ab8500_accdet_pdata,
 #endif
diff --git a/arch/arm/mach-ux500/include/mach/usb.h b/arch/arm/mach-ux500/include/mach/usb.h
index d3739d4..5c27a72 100644
--- a/arch/arm/mach-ux500/include/mach/usb.h
+++ b/arch/arm/mach-ux500/include/mach/usb.h
@@ -22,4 +22,12 @@
 
 void ux500_add_usb(resource_size_t base, int irq, int *dma_rx_cfg,
 	int *dma_tx_cfg);
+
+struct ab8500_usbgpio_platform_data {
+	int (*get)(struct device *device);
+	void (*enable)(void);
+	void (*disable)(void);
+	void (*put)(void);
+};
+
 #endif
diff --git a/arch/arm/mach-ux500/usb.c b/arch/arm/mach-ux500/usb.c
index 82e5359..dc6a697 100644
--- a/arch/arm/mach-ux500/usb.c
+++ b/arch/arm/mach-ux500/usb.c
@@ -9,6 +9,9 @@
 #include <plat/ste_dma40.h>
 #include <mach/hardware.h>
 #include <mach/usb.h>
+#include <plat/pincfg.h>
+#include "pins.h"
+#include "board-mop500-usb.h"
 
 #define MUSB_DMA40_RX_CH { \
 		.mode = STEDMA40_MODE_LOGICAL, \
@@ -85,6 +88,7 @@
 };
 
 static u64 ux500_musb_dmamask = DMA_BIT_MASK(32);
+static struct ux500_pins *usb_gpio_pins;
 
 static struct musb_hdrc_config musb_hdrc_config = {
 	.multipoint	= true,
@@ -129,6 +133,37 @@
 	.resource = usb_resources,
 };
 
+static void enable_gpio(void)
+{
+	ux500_pins_enable(usb_gpio_pins);
+}
+static void disable_gpio(void)
+{
+	ux500_pins_disable(usb_gpio_pins);
+}
+static int get_gpio(struct device *device)
+{
+	usb_gpio_pins = ux500_pins_get(dev_name(device));
+
+	if (usb_gpio_pins == NULL) {
+		dev_err(device, "Could not get %s:usb_gpio_pins structure\n",
+				dev_name(device));
+
+		return PTR_ERR(usb_gpio_pins);
+	}
+	return 0;
+}
+static void put_gpio(void)
+{
+	ux500_pins_put(usb_gpio_pins);
+}
+struct ab8500_usbgpio_platform_data ab8500_usbgpio_plat_data = {
+	.get		= &get_gpio,
+	.enable		= &enable_gpio,
+	.disable	= &disable_gpio,
+	.put		= &put_gpio,
+};
+
 static inline void ux500_usb_dma_update_rx_ch_config(int *src_dev_type)
 {
 	u32 idx;
diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c
index fd5943b..fcd3847 100644
--- a/drivers/usb/otg/ab8500-usb.c
+++ b/drivers/usb/otg/ab8500-usb.c
@@ -35,6 +35,7 @@
 #include <linux/mfd/ab8500.h>
 #include <linux/regulator/consumer.h>
 #include <mach/prcmu.h>
+#include <mach/usb.h>
 
 #define AB8500_MAIN_WD_CTRL_REG 0x01
 #define AB8500_USB_LINE_STAT_REG 0x80
@@ -99,6 +100,7 @@
 	struct regulator *v_ape;
 	struct regulator *v_musb;
 	struct regulator *v_ulpi;
+	struct ab8500_usbgpio_platform_data *usb_gpio;
 };
 
 static inline struct ab8500_usb *xceiv_to_ab(struct otg_transceiver *x)
@@ -168,6 +170,8 @@
 	bit = sel_host ? AB8500_BIT_PHY_CTRL_HOST_EN :
 			AB8500_BIT_PHY_CTRL_DEVICE_EN;
 
+	ab->usb_gpio->enable();
+
 	clk_enable(ab->sysclk);
 
 	ab8500_usb_regulator_ctrl(ab, sel_host, true);
@@ -215,6 +219,8 @@
 
 	ab8500_usb_regulator_ctrl(ab, sel_host, false);
 
+	ab->usb_gpio->disable();
+
 	prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP,
 				(char *)dev_name(ab->dev), 50);
 }
@@ -354,6 +360,7 @@
 
 	if (!ab->otg.gadget)
 		ab8500_usb_peri_phy_dis(ab);
+
 }
 
 static unsigned ab8500_eyediagram_workaroud(struct ab8500_usb *ab, unsigned mA)
@@ -621,6 +628,8 @@
 static int __devinit ab8500_usb_probe(struct platform_device *pdev)
 {
 	struct ab8500_usb	*ab;
+	struct ab8500_platform_data *ab8500_pdata =
+				dev_get_platdata(pdev->dev.parent);
 	int err;
 	int rev;
 
@@ -646,6 +655,7 @@
 	ab->otg.set_peripheral	= ab8500_usb_set_peripheral;
 	ab->otg.set_suspend	= ab8500_usb_set_suspend;
 	ab->otg.set_power	= ab8500_usb_set_power;
+	ab->usb_gpio		=	ab8500_pdata->usb;
 
 	platform_set_drvdata(pdev, ab);
 
@@ -685,6 +695,10 @@
 	/* Needed to enable ID detection. */
 	ab8500_usb_wd_workaround(ab);
 
+	err = ab->usb_gpio->get(ab->dev);
+	if (err < 0)
+		goto fail3;
+
 	prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP,
 			(char *)dev_name(ab->dev), 50);
 
@@ -723,6 +737,8 @@
 
 	ab8500_usb_regulator_put(ab);
 
+	ab->usb_gpio->put();
+
 	platform_set_drvdata(pdev, NULL);
 
 	kfree(ab);
diff --git a/include/linux/mfd/ab8500.h b/include/linux/mfd/ab8500.h
index dbf80e5..b81df84 100644
--- a/include/linux/mfd/ab8500.h
+++ b/include/linux/mfd/ab8500.h
@@ -207,6 +207,7 @@
 	struct ab8500_fg_platform_data *fg;
 	struct ab8500_chargalg_platform_data *chargalg;
 	struct ab8500_gpio_platform_data *gpio;
+	struct ab8500_usbgpio_platform_data *usb;
 };
 
 extern int __devinit ab8500_init(struct ab8500 *ab8500);