summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEven Xu <Feng.Xu@freescale.com>2011-12-16 11:09:27 +0800
committerOliver Brown <oliver.brown@freescale.com>2012-02-21 16:47:18 -0600
commit313dc5ed31f70cd3141853f9234f71ef2da5ca8f (patch)
tree83b9aa93672f079e92450a7ea53ba992e95c1958
parent2fc66245e2287fdca0294d294a690358a22d4a3d (diff)
ENGR00170447 MX6Q: Fix CSI SMFC cannot disable normally
Root cause is: Ipu driver use msleep to wait for smfc idle, msleep isn't a Accurate timer, but CSI SMFC is a real-time channel, so use Interrupt handler to replace msleep. Signed-off-by: Even Xu <b21019@freescale.com>
-rw-r--r--drivers/mxc/ipu3/ipu_capture.c55
-rw-r--r--drivers/mxc/ipu3/ipu_common.c5
-rw-r--r--drivers/mxc/ipu3/ipu_prv.h4
3 files changed, 61 insertions, 3 deletions
diff --git a/drivers/mxc/ipu3/ipu_capture.c b/drivers/mxc/ipu3/ipu_capture.c
index ff7384530045..ca33f00e5e68 100644
--- a/drivers/mxc/ipu3/ipu_capture.c
+++ b/drivers/mxc/ipu3/ipu_capture.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008-2012 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -744,3 +744,56 @@ int _ipu_csi_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t csi)
err:
return retval;
}
+
+/*!
+ * csi_irq_handler
+ *
+ * @param irq interrupt id
+ * @param dev_id pointer to ipu handler
+ *
+ * @return Returns if irq is handled
+ */
+static irqreturn_t csi_irq_handler(int irq, void *dev_id)
+{
+ struct ipu_soc *ipu = dev_id;
+ struct completion *comp = &ipu->csi_comp;
+
+ complete(comp);
+ return IRQ_HANDLED;
+}
+
+/*!
+ * _ipu_csi_wait4eof
+ *
+ * @param ipu ipu handler
+ * @param channel IDMAC channel
+ *
+ */
+void _ipu_csi_wait4eof(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+ int ret;
+ int irq = 0;
+
+ if (channel == CSI_MEM0)
+ irq = IPU_IRQ_CSI0_OUT_EOF;
+ else if (channel == CSI_MEM1)
+ irq = IPU_IRQ_CSI1_OUT_EOF;
+ else if (channel == CSI_MEM2)
+ irq = IPU_IRQ_CSI2_OUT_EOF;
+ else if (channel == CSI_MEM3)
+ irq = IPU_IRQ_CSI3_OUT_EOF;
+ else{
+ dev_err(ipu->dev, "Not a CSI SMFC channel\n");
+ return;
+ }
+
+ init_completion(&ipu->csi_comp);
+ ret = ipu_request_irq(ipu, irq, csi_irq_handler, 0, NULL, ipu);
+ if (ret < 0) {
+ dev_err(ipu->dev, "CSI irq %d in use\n", irq);
+ return;
+ }
+ ret = wait_for_completion_timeout(&ipu->csi_comp, msecs_to_jiffies(50));
+ ipu_free_irq(ipu, irq, ipu);
+ dev_dbg(ipu->dev, "CSI stop timeout - %d * 10ms\n", 5 - ret);
+}
diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c
index b29402539582..b3f23afc5c30 100644
--- a/drivers/mxc/ipu3/ipu_common.c
+++ b/drivers/mxc/ipu3/ipu_common.c
@@ -2221,7 +2221,10 @@ int32_t ipu_disable_channel(struct ipu_soc *ipu, ipu_channel_t channel, bool wai
}
}
}
- } else if (wait_for_stop) {
+ } else if ((channel == CSI_MEM0) || (channel == CSI_MEM1) ||
+ (channel == CSI_MEM2) || (channel == CSI_MEM3))
+ _ipu_csi_wait4eof(ipu, channel);
+ else if (wait_for_stop) {
while (idma_is_set(ipu, IDMAC_CHA_BUSY, in_dma) ||
idma_is_set(ipu, IDMAC_CHA_BUSY, out_dma) ||
(ipu->sec_chan_en[IPU_CHAN_ID(channel)] &&
diff --git a/drivers/mxc/ipu3/ipu_prv.h b/drivers/mxc/ipu3/ipu_prv.h
index 42060c954a1f..4a0ca16002b0 100644
--- a/drivers/mxc/ipu3/ipu_prv.h
+++ b/drivers/mxc/ipu3/ipu_prv.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2005-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -117,6 +117,7 @@ struct ipu_soc {
bool color_key_4rgb;
bool dc_swap;
struct completion dc_comp;
+ struct completion csi_comp;
/* for power gating */
u32 ipu_conf_reg;
@@ -325,6 +326,7 @@ void ipu_csi_set_test_generator(struct ipu_soc *ipu, bool active, uint32_t r_val
uint32_t pix_clk, uint32_t csi);
void _ipu_csi_ccir_err_detection_enable(struct ipu_soc *ipu, uint32_t csi);
void _ipu_csi_ccir_err_detection_disable(struct ipu_soc *ipu, uint32_t csi);
+void _ipu_csi_wait4eof(struct ipu_soc *ipu, ipu_channel_t channel);
void _ipu_smfc_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t mipi_id, uint32_t csi);
void _ipu_smfc_set_burst_size(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t bs);
void _ipu_dp_set_csc_coefficients(struct ipu_soc *ipu, ipu_channel_t channel, int32_t param[][3]);