summaryrefslogtreecommitdiff
path: root/drivers/mxc
diff options
context:
space:
mode:
authorEven Xu <Feng.Xu@freescale.com>2011-12-16 11:09:27 +0800
committerJason Liu <r64343@freescale.com>2012-01-09 21:11:18 +0800
commit8756f361dc0db9cb0b540ad3f033edaf8db3d290 (patch)
tree79c43d54716f30e9ec5b065f8cebece60456cb38 /drivers/mxc
parentd5ced8687fe46c8bb78003408c954746727c92f0 (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>
Diffstat (limited to 'drivers/mxc')
-rw-r--r--drivers/mxc/ipu3/ipu_capture.c53
-rw-r--r--drivers/mxc/ipu3/ipu_common.c5
-rw-r--r--drivers/mxc/ipu3/ipu_prv.h2
3 files changed, 59 insertions, 1 deletions
diff --git a/drivers/mxc/ipu3/ipu_capture.c b/drivers/mxc/ipu3/ipu_capture.c
index ff7384530045..e35d1b53016c 100644
--- a/drivers/mxc/ipu3/ipu_capture.c
+++ b/drivers/mxc/ipu3/ipu_capture.c
@@ -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 e7713199abcb..40297a8718af 100644
--- a/drivers/mxc/ipu3/ipu_common.c
+++ b/drivers/mxc/ipu3/ipu_common.c
@@ -2193,7 +2193,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..68cb87a910fa 100644
--- a/drivers/mxc/ipu3/ipu_prv.h
+++ b/drivers/mxc/ipu3/ipu_prv.h
@@ -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]);