Merge "msm: smd_pkt: Handle wakelocks appropriately to optimize power usage" into msm-3.0
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index 63c5fef..aeffbfd 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -66,6 +66,7 @@
 
 	int blocking_write;
 	int is_open;
+	int poll_mode;
 	unsigned ch_size;
 	uint open_modem_wait;
 
@@ -74,6 +75,7 @@
 	struct completion ch_allocated;
 	struct wake_lock pa_wake_lock;		/* Packet Arrival Wake lock*/
 	struct work_struct packet_arrival_work;
+	struct spinlock pa_spinlock;
 } *smd_pkt_devp[NUM_SMD_PKT_PORTS];
 
 struct class *smd_pkt_classp;
@@ -236,6 +238,7 @@
 	int pkt_size;
 	struct smd_pkt_dev *smd_pkt_devp;
 	struct smd_channel *chl;
+	unsigned long flags;
 
 	D(KERN_ERR "%s: read %i bytes\n",
 	  __func__, count);
@@ -316,6 +319,16 @@
 	D_DUMP_BUFFER("read: ", bytes_read, buf);
 	mutex_unlock(&smd_pkt_devp->rx_lock);
 
+	mutex_lock(&smd_pkt_devp->ch_lock);
+	spin_lock_irqsave(&smd_pkt_devp->pa_spinlock, flags);
+	if (smd_pkt_devp->poll_mode &&
+	    !smd_cur_packet_size(smd_pkt_devp->ch)) {
+		wake_unlock(&smd_pkt_devp->pa_wake_lock);
+		smd_pkt_devp->poll_mode = 0;
+	}
+	spin_unlock_irqrestore(&smd_pkt_devp->pa_spinlock, flags);
+	mutex_unlock(&smd_pkt_devp->ch_lock);
+
 	D(KERN_ERR "%s: just read %i bytes\n",
 	  __func__, bytes_read);
 
@@ -409,6 +422,7 @@
 	if (!smd_pkt_devp)
 		return POLLERR;
 
+	smd_pkt_devp->poll_mode = 1;
 	poll_wait(file, &smd_pkt_devp->ch_read_wait_queue, wait);
 	if (smd_read_avail(smd_pkt_devp->ch))
 		mask |= POLLIN | POLLRDNORM;
@@ -419,6 +433,7 @@
 static void check_and_wakeup_reader(struct smd_pkt_dev *smd_pkt_devp)
 {
 	int sz;
+	unsigned long flags;
 
 	if (!smd_pkt_devp || !smd_pkt_devp->ch)
 		return;
@@ -437,6 +452,9 @@
 
 	/* here we have a packet of size sz ready */
 	wake_up(&smd_pkt_devp->ch_read_wait_queue);
+	spin_lock_irqsave(&smd_pkt_devp->pa_spinlock, flags);
+	wake_lock(&smd_pkt_devp->pa_wake_lock);
+	spin_unlock_irqrestore(&smd_pkt_devp->pa_spinlock, flags);
 	schedule_work(&smd_pkt_devp->packet_arrival_work);
 	D(KERN_ERR "%s: after wake_up\n", __func__);
 }
@@ -707,6 +725,7 @@
 		r = smd_close(smd_pkt_devp->ch);
 		smd_pkt_devp->ch = 0;
 		smd_pkt_devp->blocking_write = 0;
+		smd_pkt_devp->poll_mode = 0;
 		if (smd_pkt_devp->pil)
 			pil_put(smd_pkt_devp->pil);
 	}
@@ -776,8 +795,10 @@
 		init_waitqueue_head(&smd_pkt_devp[i]->ch_read_wait_queue);
 		init_waitqueue_head(&smd_pkt_devp[i]->ch_write_wait_queue);
 		smd_pkt_devp[i]->is_open = 0;
+		smd_pkt_devp[i]->poll_mode = 0;
 		init_waitqueue_head(&smd_pkt_devp[i]->ch_opened_wait_queue);
 
+		spin_lock_init(&smd_pkt_devp[i]->pa_spinlock);
 		mutex_init(&smd_pkt_devp[i]->ch_lock);
 		mutex_init(&smd_pkt_devp[i]->rx_lock);
 		mutex_init(&smd_pkt_devp[i]->tx_lock);