msm: bam_dmux: provide api for starting ul wakeup from atomic context

Change-Id: I117ed84c6cf343fa2d3e50e2beb033c6d03678c3
Signed-off-by: Jeffrey Hugo <jhugo@codeaurora.org>
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 59503e1..603b031 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -147,6 +147,7 @@
 	uint16_t pkt_len;
 };
 
+static void notify_all(int event, unsigned long data);
 static void bam_mux_write_done(struct work_struct *work);
 static void handle_bam_mux_cmd(struct work_struct *work);
 static void rx_timer_work_func(struct work_struct *work);
@@ -166,6 +167,7 @@
 static void ul_timeout(struct work_struct *work);
 static void vote_dfab(void);
 static void unvote_dfab(void);
+static void kickoff_ul_wakeup_func(struct work_struct *work);
 
 static int bam_is_connected;
 static DEFINE_MUTEX(wakeup_lock);
@@ -175,6 +177,7 @@
 static int ul_packet_written;
 static struct clk *dfab_clk;
 static DEFINE_RWLOCK(ul_wakeup_lock);
+static DECLARE_WORK(kickoff_ul_wakeup, kickoff_ul_wakeup_func);
 /* End A2 power collaspe */
 
 #define bam_ch_is_open(x)						\
@@ -393,6 +396,7 @@
 		read_unlock(&ul_wakeup_lock);
 		ul_wakeup();
 		read_lock(&ul_wakeup_lock);
+		notify_all(BAM_DMUX_UL_CONNECTED, (unsigned long)(NULL));
 	}
 
 	/* if skb do not have any tailroom for padding,
@@ -501,6 +505,7 @@
 		read_unlock(&ul_wakeup_lock);
 		ul_wakeup();
 		read_lock(&ul_wakeup_lock);
+		notify_all(BAM_DMUX_UL_CONNECTED, (unsigned long)(NULL));
 	}
 
 	hdr->magic_num = BAM_MUX_HDR_MAGIC_NO;
@@ -535,6 +540,7 @@
 		read_unlock(&ul_wakeup_lock);
 		ul_wakeup();
 		read_lock(&ul_wakeup_lock);
+		notify_all(BAM_DMUX_UL_CONNECTED, (unsigned long)(NULL));
 	}
 
 	spin_lock_irqsave(&bam_ch[id].lock, flags);
@@ -756,6 +762,34 @@
 
 #endif
 
+static void notify_all(int event, unsigned long data)
+{
+	int i;
+
+	for (i = 0; i < BAM_DMUX_NUM_CHANNELS; ++i) {
+		if (bam_ch_is_open(i))
+			bam_ch[i].notify(bam_ch[i].priv, event, data);
+	}
+}
+
+static void kickoff_ul_wakeup_func(struct work_struct *work)
+{
+	read_lock(&ul_wakeup_lock);
+	if (!bam_is_connected) {
+		read_unlock(&ul_wakeup_lock);
+		ul_wakeup();
+		read_lock(&ul_wakeup_lock);
+		ul_packet_written = 1;
+		notify_all(BAM_DMUX_UL_CONNECTED, (unsigned long)(NULL));
+	}
+	read_unlock(&ul_wakeup_lock);
+}
+
+void msm_bam_dmux_kickoff_ul_wakeup(void)
+{
+	queue_work(bam_mux_tx_workqueue, &kickoff_ul_wakeup);
+}
+
 static void ul_timeout(struct work_struct *work)
 {
 	write_lock(&ul_wakeup_lock);
@@ -766,6 +800,7 @@
 	} else {
 		smsm_change_state(SMSM_APPS_STATE, SMSM_A2_POWER_CONTROL, 0);
 		bam_is_connected = 0;
+		notify_all(BAM_DMUX_UL_DISCONNECTED, (unsigned long)(NULL));
 	}
 	write_unlock(&ul_wakeup_lock);
 }
diff --git a/arch/arm/mach-msm/include/mach/bam_dmux.h b/arch/arm/mach-msm/include/mach/bam_dmux.h
index e5ec166..a2b0126 100644
--- a/arch/arm/mach-msm/include/mach/bam_dmux.h
+++ b/arch/arm/mach-msm/include/mach/bam_dmux.h
@@ -35,6 +35,8 @@
 enum {
 	BAM_DMUX_RECEIVE, /* data is struct sk_buff */
 	BAM_DMUX_WRITE_DONE, /* data is struct sk_buff */
+	BAM_DMUX_UL_CONNECTED, /* data is null */
+	BAM_DMUX_UL_DISCONNECTED, /*data is null */
 };
 
 /*
@@ -55,6 +57,8 @@
 int msm_bam_dmux_close(uint32_t id);
 
 int msm_bam_dmux_write(uint32_t id, struct sk_buff *skb);
+
+void msm_bam_dmux_kickoff_ul_wakeup(void);
 #else
 int msm_bam_dmux_open(uint32_t id, void *priv,
 		       void (*notify)(void *priv, int event_type,
@@ -72,5 +76,9 @@
 {
 	return -ENODEV;
 }
+
+void msm_bam_dmux_kickoff_ul_wakeup(void)
+{
+}
 #endif
 #endif /* _BAM_DMUX_H */