Merge "msm: 8064: Add sleep status data for 8064 and 8930" into msm-3.0
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
index f760e7b..fc89a11 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -148,7 +148,6 @@
 };
 VREG_CONSUMERS(S1) = {
 	REGULATOR_SUPPLY("8038_s1",		NULL),
-	REGULATOR_SUPPLY("HSUSB_VDDCX",		"msm_otg"),
 	REGULATOR_SUPPLY("riva_vddcx",		"wcnss_wlan.0"),
 };
 VREG_CONSUMERS(S2) = {
@@ -192,6 +191,7 @@
 };
 VREG_CONSUMERS(VDD_DIG_CORNER) = {
 	REGULATOR_SUPPLY("vdd_dig_corner",	NULL),
+	REGULATOR_SUPPLY("hsusb_vdd_dig",	"msm_otg"),
 };
 
 #define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
diff --git a/arch/arm/mach-msm/board-9615-gpiomux.c b/arch/arm/mach-msm/board-9615-gpiomux.c
index c600d53..0e18918 100644
--- a/arch/arm/mach-msm/board-9615-gpiomux.c
+++ b/arch/arm/mach-msm/board-9615-gpiomux.c
@@ -105,20 +105,6 @@
 };
 #endif
 
-static struct gpiomux_setting wlan_active_config = {
-	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_2MA,
-	.pull = GPIOMUX_PULL_NONE,
-	.dir = GPIOMUX_OUT_LOW,
-};
-
-static struct gpiomux_setting wlan_suspend_config = {
-	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_2MA,
-	.pull = GPIOMUX_PULL_NONE,
-	.dir = GPIOMUX_IN,
-};
-
 static struct msm_gpiomux_config msm9615_audio_codec_configs[] __initdata = {
 	{
 		.gpio = 24,
@@ -320,24 +306,6 @@
 };
 #endif
 
-static struct msm_gpiomux_config msm9615_wlan_configs[] __initdata = {
-	{
-		.gpio	= 2,	/* WLAN_PM_ENABLE */
-		.settings = {
-			[GPIOMUX_ACTIVE] = &wlan_active_config,
-			[GPIOMUX_SUSPENDED] = &wlan_suspend_config,
-		},
-	},
-	{
-		.gpio	= 21,	/* WLAN_RESET_N */
-		.settings = {
-			[GPIOMUX_ACTIVE] = &wlan_active_config,
-			[GPIOMUX_SUSPENDED] = &wlan_suspend_config,
-		},
-	},
-};
-
-
 int __init msm9615_init_gpiomux(void)
 {
 	int rc;
@@ -364,9 +332,6 @@
 	msm_gpiomux_install(msm9615_audio_codec_configs,
 			ARRAY_SIZE(msm9615_audio_codec_configs));
 
-	msm_gpiomux_install(msm9615_wlan_configs,
-			ARRAY_SIZE(msm9615_wlan_configs));
-
 #ifdef CONFIG_FB_MSM_EBI2
 	msm_gpiomux_install(msm9615_ebi2_lcdc_configs,
 			ARRAY_SIZE(msm9615_ebi2_lcdc_configs));
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index c1e4118..6b42325 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -354,6 +354,7 @@
 static void smd_fake_irq_handler(unsigned long arg);
 static void smsm_cb_snapshot(uint32_t use_wakelock);
 
+static struct workqueue_struct *smsm_cb_wq;
 static void notify_smsm_cb_clients_worker(struct work_struct *work);
 static DECLARE_WORK(smsm_cb_work, notify_smsm_cb_clients_worker);
 static DEFINE_MUTEX(smsm_lock);
@@ -2365,6 +2366,13 @@
 		return -ENOMEM;
 	}
 
+	smsm_cb_wq = create_singlethread_workqueue("smsm_cb_wq");
+	if (!smsm_cb_wq) {
+		pr_err("%s: smsm_cb_wq creation failed\n", __func__);
+		kfree(smsm_states);
+		return -EFAULT;
+	}
+
 	mutex_lock(&smsm_lock);
 	for (n = 0; n < SMSM_NUM_ENTRIES; n++) {
 		state_info = &smsm_states[n];
@@ -2540,7 +2548,7 @@
 		goto restore_snapshot_count;
 	}
 
-	schedule_work(&smsm_cb_work);
+	queue_work(smsm_cb_wq, &smsm_cb_work);
 	return;
 
 restore_snapshot_count:
@@ -2832,7 +2840,6 @@
 				state_info->last_value = new_state;
 			}
 		}
-		mutex_unlock(&smsm_lock);
 
 		/* read wakelock flag */
 		ret = kfifo_out(&smsm_snapshot_fifo, &use_wakelock,
@@ -2840,8 +2847,10 @@
 		if (ret != sizeof(use_wakelock)) {
 			pr_err("%s: snapshot underflow %d\n",
 				__func__, ret);
+			mutex_unlock(&smsm_lock);
 			return;
 		}
+		mutex_unlock(&smsm_lock);
 
 		if (use_wakelock) {
 			spin_lock_irqsave(&smsm_snapshot_count_lock, flags);
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index de9e2c4..84789ef 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -54,7 +54,7 @@
 
 	if (!offset) {
 		if ((carveout_heap->total_size -
-		      carveout_heap->allocated_bytes) > size)
+		      carveout_heap->allocated_bytes) >= size)
 			pr_debug("%s: heap %s has enough memory (%lx) but"
 				" the allocation of size %lx still failed."
 				" Memory is probably fragmented.",
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index c8db702..24ea571 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -511,6 +511,8 @@
 	KGSL_DRV_ERR(device, "snapshot created at va %p pa %lx size %d\n",
 			device->snapshot, __pa(device->snapshot),
 			device->snapshot_size);
+	if (hang)
+		sysfs_notify(&device->snapshot_kobj, NULL, "timestamp");
 	return 0;
 }
 EXPORT_SYMBOL(kgsl_device_snapshot);
diff --git a/drivers/net/msm_rmnet_sdio.c b/drivers/net/msm_rmnet_sdio.c
index 883c649..acdffd1 100644
--- a/drivers/net/msm_rmnet_sdio.c
+++ b/drivers/net/msm_rmnet_sdio.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -78,6 +78,7 @@
 #endif
 	struct sk_buff *skb;
 	spinlock_t lock;
+	spinlock_t tx_queue_lock;
 	struct tasklet_struct tsklt;
 	u32 operation_mode; /* IOCTL specified mode (protocol, QoS header) */
 	uint8_t device_up;
@@ -361,6 +362,7 @@
 static void sdio_write_done(void *dev, struct sk_buff *skb)
 {
 	struct rmnet_private *p = netdev_priv(dev);
+	unsigned long flags;
 
 	if (skb)
 		dev_kfree_skb_any(skb);
@@ -368,12 +370,14 @@
 	if (!p->in_reset) {
 		DBG1("%s: write complete skb=%p\n",	__func__, skb);
 
+		spin_lock_irqsave(&p->tx_queue_lock, flags);
 		if (netif_queue_stopped(dev) &&
 				msm_sdio_dmux_is_ch_low(p->ch_id)) {
 			DBG0("%s: Low WM hit, waking queue=%p\n",
 					__func__, skb);
 			netif_wake_queue(dev);
 		}
+		spin_unlock_irqrestore(&p->tx_queue_lock, flags);
 	} else {
 		DBG1("%s: write in reset skb=%p\n",	__func__, skb);
 	}
@@ -454,6 +458,7 @@
 static int rmnet_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct rmnet_private *p = netdev_priv(dev);
+	unsigned long flags;
 
 	if (netif_queue_stopped(dev)) {
 		pr_err("[%s]fatal: rmnet_xmit called when "
@@ -463,10 +468,12 @@
 
 	_rmnet_xmit(skb, dev);
 
+	spin_lock_irqsave(&p->tx_queue_lock, flags);
 	if (msm_sdio_dmux_is_ch_full(p->ch_id)) {
 		netif_stop_queue(dev);
 		DBG0("%s: High WM hit, stopping queue=%p\n",	__func__, skb);
 	}
+	spin_unlock_irqrestore(&p->tx_queue_lock, flags);
 
 	return 0;
 }
@@ -667,6 +674,7 @@
 		p->operation_mode = RMNET_MODE_LLP_ETH;
 		p->ch_id = n;
 		spin_lock_init(&p->lock);
+		spin_lock_init(&p->tx_queue_lock);
 #ifdef CONFIG_MSM_RMNET_DEBUG
 		p->timeout_us = timeout_us;
 		p->wakeups_xmit = p->wakeups_rcv = 0;
diff --git a/drivers/net/usb/rmnet_usb_data.c b/drivers/net/usb/rmnet_usb_data.c
index ae3f934..d4c2823 100644
--- a/drivers/net/usb/rmnet_usb_data.c
+++ b/drivers/net/usb/rmnet_usb_data.c
@@ -13,6 +13,8 @@
 #include <linux/mii.h>
 #include <linux/if_arp.h>
 #include <linux/etherdevice.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 #include <linux/usb.h>
 #include <linux/usb/usbnet.h>
 #include <linux/msm_rmnet.h>
@@ -416,6 +418,86 @@
 	dev->watchdog_timeo = 1000; /* 10 seconds? */
 }
 
+static int rmnet_usb_data_status(struct seq_file *s, void *unused)
+{
+	struct usbnet *unet = s->private;
+
+	seq_printf(s, "RMNET_MODE_LLP_IP:  %d\n",
+			test_bit(RMNET_MODE_LLP_IP, &unet->data[0]));
+	seq_printf(s, "RMNET_MODE_LLP_ETH: %d\n",
+			test_bit(RMNET_MODE_LLP_ETH, &unet->data[0]));
+	seq_printf(s, "RMNET_MODE_QOS:     %d\n",
+			test_bit(RMNET_MODE_QOS, &unet->data[0]));
+	seq_printf(s, "Net MTU:            %u\n", unet->net->mtu);
+	seq_printf(s, "rx_urb_size:        %u\n", unet->rx_urb_size);
+	seq_printf(s, "rx skb q len:       %u\n", unet->rxq.qlen);
+	seq_printf(s, "rx skb done q len:  %u\n", unet->done.qlen);
+	seq_printf(s, "rx errors:          %lu\n", unet->net->stats.rx_errors);
+	seq_printf(s, "rx over errors:     %lu\n",
+			unet->net->stats.rx_over_errors);
+	seq_printf(s, "rx length errors:   %lu\n",
+			unet->net->stats.rx_length_errors);
+	seq_printf(s, "rx packets:         %lu\n", unet->net->stats.rx_packets);
+	seq_printf(s, "rx bytes:           %lu\n", unet->net->stats.rx_bytes);
+	seq_printf(s, "tx skb q len:       %u\n", unet->txq.qlen);
+	seq_printf(s, "tx errors:          %lu\n", unet->net->stats.tx_errors);
+	seq_printf(s, "tx packets:         %lu\n", unet->net->stats.tx_packets);
+	seq_printf(s, "tx bytes:           %lu\n", unet->net->stats.tx_bytes);
+	seq_printf(s, "suspend count:      %d\n", unet->suspend_count);
+	seq_printf(s, "EVENT_DEV_OPEN:     %d\n",
+			test_bit(EVENT_DEV_OPEN, &unet->flags));
+	seq_printf(s, "EVENT_TX_HALT:      %d\n",
+			test_bit(EVENT_TX_HALT, &unet->flags));
+	seq_printf(s, "EVENT_RX_HALT:      %d\n",
+			test_bit(EVENT_RX_HALT, &unet->flags));
+	seq_printf(s, "EVENT_RX_MEMORY:    %d\n",
+			test_bit(EVENT_RX_MEMORY, &unet->flags));
+	seq_printf(s, "EVENT_DEV_ASLEEP:   %d\n",
+			test_bit(EVENT_DEV_ASLEEP, &unet->flags));
+
+	return 0;
+}
+
+static int rmnet_usb_data_status_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, rmnet_usb_data_status, inode->i_private);
+}
+
+const struct file_operations rmnet_usb_data_fops = {
+	.open = rmnet_usb_data_status_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static struct dentry *rmnet_usb_data_dbg_root;
+static int rmnet_usb_data_debugfs_init(struct usbnet *unet)
+{
+	struct dentry *rmnet_usb_data_dentry;
+
+	rmnet_usb_data_dbg_root = debugfs_create_dir(unet->net->name, NULL);
+
+	if (!rmnet_usb_data_dbg_root || IS_ERR(rmnet_usb_data_dbg_root))
+		return -ENODEV;
+
+	rmnet_usb_data_dentry = debugfs_create_file("status",
+		S_IRUGO | S_IWUSR,
+		rmnet_usb_data_dbg_root, unet,
+		&rmnet_usb_data_fops);
+
+	if (!rmnet_usb_data_dentry) {
+		debugfs_remove_recursive(rmnet_usb_data_dbg_root);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void rmnet_usb_data_debugfs_cleanup(void)
+{
+	debugfs_remove_recursive(rmnet_usb_data_dbg_root);
+}
+
 static int rmnet_usb_probe(struct usb_interface *iface,
 		const struct usb_device_id *prod)
 {
@@ -469,6 +551,10 @@
 	if (status)
 		goto out;
 
+	status = rmnet_usb_data_debugfs_init(unet);
+	if (status)
+		dev_dbg(&udev->dev, "mode debugfs file is not available\n");
+
 	/* allow modem to wake up suspended system */
 	device_set_wakeup_enable(&udev->dev, 1);
 out:
@@ -484,6 +570,8 @@
 	udev = interface_to_usbdev(intf);
 	device_set_wakeup_enable(&udev->dev, 0);
 
+	rmnet_usb_data_debugfs_cleanup();
+
 	unet = usb_get_intfdata(intf);
 	if (!unet) {
 		dev_err(&udev->dev, "%s:data device not found\n", __func__);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index b428bd2..2f7e250 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -45,6 +45,7 @@
 #include <mach/clk.h>
 #include <mach/msm_xo.h>
 #include <mach/msm_bus.h>
+#include <mach/rpm-regulator.h>
 
 #define MSM_USB_BASE	(motg->regs)
 #define DRIVER_NAME	"msm_otg"
@@ -61,6 +62,7 @@
 #define USB_PHY_1P8_HPM_LOAD	50000	/* uA */
 #define USB_PHY_1P8_LPM_LOAD	4000	/* uA */
 
+#define USB_PHY_VDD_DIG_VOL_NONE	0 /*uV */
 #define USB_PHY_VDD_DIG_VOL_MIN	1045000 /* uV */
 #define USB_PHY_VDD_DIG_VOL_MAX	1320000 /* uV */
 
@@ -104,53 +106,25 @@
 #endif
 }
 
-static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init)
-{
-	int ret = 0;
+enum usb_vdd_value {
+	VDD_NONE = 0,
+	VDD_MIN,
+	VDD_MAX,
+	VDD_VAL_MAX,
+};
 
-	if (init) {
-		hsusb_vddcx = devm_regulator_get(motg->otg.dev, "HSUSB_VDDCX");
-		if (IS_ERR(hsusb_vddcx)) {
-			dev_err(motg->otg.dev, "unable to get hsusb vddcx\n");
-			return PTR_ERR(hsusb_vddcx);
-		}
-
-		ret = regulator_set_voltage(hsusb_vddcx,
-				USB_PHY_VDD_DIG_VOL_MIN,
-				USB_PHY_VDD_DIG_VOL_MAX);
-		if (ret) {
-			dev_err(motg->otg.dev, "unable to set the voltage "
-					"for hsusb vddcx\n");
-			return ret;
-		}
-
-		ret = regulator_enable(hsusb_vddcx);
-		if (ret) {
-			regulator_set_voltage(hsusb_vddcx, 0,
-			USB_PHY_VDD_DIG_VOL_MIN);
-			dev_err(motg->otg.dev, "unable to enable the hsusb vddcx\n");
-			return ret;
-		}
-
-	} else {
-
-		ret = regulator_disable(hsusb_vddcx);
-		if (ret) {
-			dev_err(motg->otg.dev, "unable to disable hsusb vddcx\n");
-			return ret;
-		}
-
-		ret = regulator_set_voltage(hsusb_vddcx, 0,
-			USB_PHY_VDD_DIG_VOL_MIN);
-		if (ret) {
-			dev_err(motg->otg.dev, "unable to set the voltage"
-					"for hsusb vddcx\n");
-			return ret;
-		}
-	}
-
-	return ret;
-}
+static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
+		{  /* VDD_CX CORNER Voting */
+			[VDD_NONE]	= RPM_VREG_CORNER_NONE,
+			[VDD_MIN]	= RPM_VREG_CORNER_NOMINAL,
+			[VDD_MAX]	= RPM_VREG_CORNER_HIGH,
+		},
+		{ /* VDD_CX Voltage Voting */
+			[VDD_NONE]	= USB_PHY_VDD_DIG_VOL_NONE,
+			[VDD_MIN]	= USB_PHY_VDD_DIG_VOL_MIN,
+			[VDD_MAX]	= USB_PHY_VDD_DIG_VOL_MAX,
+		},
+};
 
 static int msm_hsusb_ldo_init(struct msm_otg *motg, int init)
 {
@@ -198,15 +172,13 @@
 #define USB_PHY_SUSP_DIG_VOL  500000
 static int msm_hsusb_config_vddcx(int high)
 {
-	int max_vol = USB_PHY_VDD_DIG_VOL_MAX;
+	struct msm_otg *motg = the_msm_otg;
+	enum usb_vdd_type vdd_type = motg->vdd_type;
+	int max_vol = vdd_val[vdd_type][VDD_MAX];
 	int min_vol;
 	int ret;
 
-	if (high)
-		min_vol = USB_PHY_VDD_DIG_VOL_MIN;
-	else
-		min_vol = USB_PHY_SUSP_DIG_VOL;
-
+	min_vol = vdd_val[vdd_type][!!high];
 	ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol);
 	if (ret) {
 		pr_err("%s: unable to set the voltage for regulator "
@@ -3321,22 +3293,33 @@
 
 	clk_prepare_enable(motg->pclk);
 
-	ret = msm_hsusb_init_vddcx(motg, 1);
-	if (ret) {
-		dev_err(&pdev->dev, "hsusb vddcx init failed\n");
-		goto devote_xo_handle;
+	motg->vdd_type = VDDCX_CORNER;
+	hsusb_vddcx = devm_regulator_get(motg->otg.dev, "hsusb_vdd_dig");
+	if (IS_ERR(hsusb_vddcx)) {
+		hsusb_vddcx = devm_regulator_get(motg->otg.dev, "HSUSB_VDDCX");
+		if (IS_ERR(hsusb_vddcx)) {
+			dev_err(motg->otg.dev, "unable to get hsusb vddcx\n");
+			goto devote_xo_handle;
+		}
+		motg->vdd_type = VDDCX;
 	}
 
 	ret = msm_hsusb_config_vddcx(1);
 	if (ret) {
 		dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
-		goto free_init_vddcx;
+		goto devote_xo_handle;
+	}
+
+	ret = regulator_enable(hsusb_vddcx);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to enable the hsusb vddcx\n");
+		goto free_config_vddcx;
 	}
 
 	ret = msm_hsusb_ldo_init(motg, 1);
 	if (ret) {
 		dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
-		goto free_init_vddcx;
+		goto free_hsusb_vddcx;
 	}
 
 	if (pdata->mhl_enable) {
@@ -3460,8 +3443,12 @@
 	msm_hsusb_ldo_enable(motg, 0);
 free_ldo_init:
 	msm_hsusb_ldo_init(motg, 0);
-free_init_vddcx:
-	msm_hsusb_init_vddcx(motg, 0);
+free_hsusb_vddcx:
+	regulator_disable(hsusb_vddcx);
+free_config_vddcx:
+	regulator_set_voltage(hsusb_vddcx,
+		vdd_val[motg->vdd_type][VDD_NONE],
+		vdd_val[motg->vdd_type][VDD_MAX]);
 devote_xo_handle:
 	clk_disable_unprepare(motg->pclk);
 	msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
@@ -3535,7 +3522,10 @@
 	msm_xo_put(motg->xo_handle);
 	msm_hsusb_ldo_enable(motg, 0);
 	msm_hsusb_ldo_init(motg, 0);
-	msm_hsusb_init_vddcx(motg, 0);
+	regulator_disable(hsusb_vddcx);
+	regulator_set_voltage(hsusb_vddcx,
+		vdd_val[motg->vdd_type][VDD_NONE],
+		vdd_val[motg->vdd_type][VDD_MAX]);
 
 	iounmap(motg->regs);
 	pm_runtime_set_suspended(&pdev->dev);
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index a731774..e84884c 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -149,6 +149,17 @@
 };
 
 /**
+ * Used different VDDCX voltage voting mechnism
+ * VDDCX_CORNER       Vote for VDDCX Corner voltage
+ * VDDCX              Vote for VDDCX Absolute voltage
+ */
+enum usb_vdd_type {
+	VDDCX_CORNER = 0,
+	VDDCX,
+	VDD_TYPE_MAX,
+};
+
+/**
  * SPS Pipes direction.
  *
  * USB_TO_PEER_PERIPHERAL	USB (as Producer) to other
@@ -342,6 +353,7 @@
 	unsigned long tmouts;
 	u8 active_tmout;
 	struct hrtimer timer;
+	enum usb_vdd_type vdd_type;
 };
 
 struct msm_hsic_host_platform_data {