From ecb5c94436e011ad301b31b71ed30eb8ea316b2f Mon Sep 17 00:00:00 2001 From: Even Xu Date: Mon, 28 Nov 2011 14:29:32 +0800 Subject: [PATCH] ENGR00163247-2 MX6Q: MIPI sensor add prp viewfinder and prp enc support 1. Enable ipu channel mipi setting 2. Change mipi csi2 driver common API to use lock Signed-off-by: Even Xu --- drivers/mxc/ipu3/ipu_common.c | 26 +++-- drivers/mxc/mipi/mxc_mipi_csi2.c | 176 ++++++++++++++++++++++++++++--- drivers/mxc/mipi/mxc_mipi_csi2.h | 13 ++- 3 files changed, 187 insertions(+), 28 deletions(-) diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c index 68062616a1c3..e7713199abcb 100644 --- a/drivers/mxc/ipu3/ipu_common.c +++ b/drivers/mxc/ipu3/ipu_common.c @@ -688,9 +688,16 @@ int32_t ipu_init_channel(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel ipu->ic_use_count++; ipu->csi_channel[params->csi_prp_enc_mem.csi] = channel; - /*Without SMFC, CSI only support parallel data source*/ - ipu_conf &= ~(1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET + - params->csi_prp_enc_mem.csi)); + if (params->csi_prp_enc_mem.mipi_en) { + ipu_conf |= (1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET + + params->csi_prp_enc_mem.csi)); + _ipu_csi_set_mipi_di(ipu, + params->csi_prp_enc_mem.mipi_vc, + params->csi_prp_enc_mem.mipi_id, + params->csi_prp_enc_mem.csi); + } else + ipu_conf &= ~(1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET + + params->csi_prp_enc_mem.csi)); /*CSI0/1 feed into IC*/ ipu_conf &= ~IPU_CONF_IC_INPUT; @@ -721,9 +728,16 @@ int32_t ipu_init_channel(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel ipu->ic_use_count++; ipu->csi_channel[params->csi_prp_vf_mem.csi] = channel; - /*Without SMFC, CSI only support parallel data source*/ - ipu_conf &= ~(1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET + - params->csi_prp_vf_mem.csi)); + if (params->csi_prp_vf_mem.mipi_en) { + ipu_conf |= (1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET + + params->csi_prp_vf_mem.csi)); + _ipu_csi_set_mipi_di(ipu, + params->csi_prp_vf_mem.mipi_vc, + params->csi_prp_vf_mem.mipi_id, + params->csi_prp_vf_mem.csi); + } else + ipu_conf &= ~(1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET + + params->csi_prp_vf_mem.csi)); /*CSI0/1 feed into IC*/ ipu_conf &= ~IPU_CONF_IC_INPUT; diff --git a/drivers/mxc/mipi/mxc_mipi_csi2.c b/drivers/mxc/mipi/mxc_mipi_csi2.c index 89592a84745c..1f051dff88bd 100644 --- a/drivers/mxc/mipi/mxc_mipi_csi2.c +++ b/drivers/mxc/mipi/mxc_mipi_csi2.c @@ -17,6 +17,9 @@ */ #include +#include +#include +#include #include #include #include @@ -24,14 +27,10 @@ #include #include #include -#include -#include -#include -#include -#include #include #include +#include #include #include #include @@ -40,6 +39,18 @@ static struct mipi_csi2_info *gmipi_csi2; +void _mipi_csi2_lock(struct mipi_csi2_info *info) +{ + if (!in_irq() && !in_softirq()) + mutex_lock(&info->mutex_lock); +} + +void _mipi_csi2_unlock(struct mipi_csi2_info *info) +{ + if (!in_irq() && !in_softirq()) + mutex_unlock(&info->mutex_lock); +} + static inline void mipi_csi2_write(struct mipi_csi2_info *info, unsigned value, unsigned offset) { writel(value, info->mipi_csi2_base + offset); @@ -50,6 +61,76 @@ static inline unsigned int mipi_csi2_read(struct mipi_csi2_info *info, unsigned return readl(info->mipi_csi2_base + offset); } +/*! + * This function is called to enable the mipi csi2 interface. + * + * @param info mipi csi2 hander + * @return Returns setted value + */ +bool mipi_csi2_enable(struct mipi_csi2_info *info) +{ + bool status; + + _mipi_csi2_lock(info); + + if (!info->mipi_en) { + info->mipi_en = true; + clk_enable(info->dphy_clk); + } else + mipi_dbg("mipi csi2 already enabled!\n"); + + status = info->mipi_en; + + _mipi_csi2_unlock(info); + + return status; +} +EXPORT_SYMBOL(mipi_csi2_enable); + +/*! + * This function is called to disable the mipi csi2 interface. + * + * @param info mipi csi2 hander + * @return Returns setted value + */ +bool mipi_csi2_disable(struct mipi_csi2_info *info) +{ + bool status; + + _mipi_csi2_lock(info); + + if (info->mipi_en) { + info->mipi_en = false; + clk_disable(info->dphy_clk); + } else + mipi_dbg("mipi csi2 already disabled!\n"); + + status = info->mipi_en; + + _mipi_csi2_unlock(info); + + return status; +} +EXPORT_SYMBOL(mipi_csi2_disable); + +/*! + * This function is called to get mipi csi2 disable/enable status. + * + * @param info mipi csi2 hander + * @return Returns mipi csi2 status + */ +bool mipi_csi2_get_status(struct mipi_csi2_info *info) +{ + bool status; + + _mipi_csi2_lock(info); + status = info->mipi_en; + _mipi_csi2_unlock(info); + + return status; +} +EXPORT_SYMBOL(mipi_csi2_get_status); + /*! * This function is called to set mipi lanes. * @@ -58,9 +139,14 @@ static inline unsigned int mipi_csi2_read(struct mipi_csi2_info *info, unsigned */ unsigned int mipi_csi2_set_lanes(struct mipi_csi2_info *info) { + unsigned int lanes; + + _mipi_csi2_lock(info); mipi_csi2_write(info, info->lanes - 1, CSI2_N_LANES); + lanes = mipi_csi2_read(info, CSI2_N_LANES); + _mipi_csi2_unlock(info); - return mipi_csi2_read(info, CSI2_N_LANES); + return lanes; } EXPORT_SYMBOL(mipi_csi2_set_lanes); @@ -71,11 +157,16 @@ EXPORT_SYMBOL(mipi_csi2_set_lanes); * @return Returns setted value */ unsigned int mipi_csi2_set_datatype(struct mipi_csi2_info *info, - unsigned int datatype) + unsigned int datatype) { + unsigned int dtype; + + _mipi_csi2_lock(info); info->datatype = datatype; + dtype = info->datatype; + _mipi_csi2_unlock(info); - return info->datatype; + return dtype; } EXPORT_SYMBOL(mipi_csi2_set_datatype); @@ -87,7 +178,13 @@ EXPORT_SYMBOL(mipi_csi2_set_datatype); */ unsigned int mipi_csi2_get_datatype(struct mipi_csi2_info *info) { - return info->datatype; + unsigned int dtype; + + _mipi_csi2_lock(info); + dtype = info->datatype; + _mipi_csi2_unlock(info); + + return dtype; } EXPORT_SYMBOL(mipi_csi2_get_datatype); @@ -99,7 +196,13 @@ EXPORT_SYMBOL(mipi_csi2_get_datatype); */ unsigned int mipi_csi2_dphy_status(struct mipi_csi2_info *info) { - return mipi_csi2_read(info, CSI2_PHY_STATE); + unsigned int status; + + _mipi_csi2_lock(info); + status = mipi_csi2_read(info, CSI2_PHY_STATE); + _mipi_csi2_unlock(info); + + return status; } EXPORT_SYMBOL(mipi_csi2_dphy_status); @@ -111,7 +214,13 @@ EXPORT_SYMBOL(mipi_csi2_dphy_status); */ unsigned int mipi_csi2_get_error1(struct mipi_csi2_info *info) { - return mipi_csi2_read(info, CSI2_ERR1); + unsigned int err1; + + _mipi_csi2_lock(info); + err1 = mipi_csi2_read(info, CSI2_ERR1); + _mipi_csi2_unlock(info); + + return err1; } EXPORT_SYMBOL(mipi_csi2_get_error1); @@ -123,7 +232,13 @@ EXPORT_SYMBOL(mipi_csi2_get_error1); */ unsigned int mipi_csi2_get_error2(struct mipi_csi2_info *info) { - return mipi_csi2_read(info, CSI2_ERR2); + unsigned int err2; + + _mipi_csi2_lock(info); + err2 = mipi_csi2_read(info, CSI2_ERR2); + _mipi_csi2_unlock(info); + + return err2; } EXPORT_SYMBOL(mipi_csi2_get_error2); @@ -159,6 +274,8 @@ EXPORT_SYMBOL(mipi_csi2_pixelclk_disable); */ int mipi_csi2_reset(struct mipi_csi2_info *info) { + _mipi_csi2_lock(info); + mipi_csi2_write(info, 0x0, CSI2_PHY_SHUTDOWNZ); mipi_csi2_write(info, 0x0, CSI2_DPHY_RSTZ); mipi_csi2_write(info, 0x0, CSI2_RESETN); @@ -177,6 +294,8 @@ int mipi_csi2_reset(struct mipi_csi2_info *info) mipi_csi2_write(info, 0xffffffff, CSI2_DPHY_RSTZ); mipi_csi2_write(info, 0xffffffff, CSI2_RESETN); + _mipi_csi2_unlock(info); + return 0; } EXPORT_SYMBOL(mipi_csi2_reset); @@ -199,7 +318,13 @@ EXPORT_SYMBOL(mipi_csi2_get_info); */ int mipi_csi2_get_bind_ipu(struct mipi_csi2_info *info) { - return info->ipu_id; + int ipu_id; + + _mipi_csi2_lock(info); + ipu_id = info->ipu_id; + _mipi_csi2_unlock(info); + + return ipu_id; } EXPORT_SYMBOL(mipi_csi2_get_bind_ipu); @@ -210,7 +335,13 @@ EXPORT_SYMBOL(mipi_csi2_get_bind_ipu); */ unsigned int mipi_csi2_get_bind_csi(struct mipi_csi2_info *info) { - return info->csi_id; + unsigned int csi_id; + + _mipi_csi2_lock(info); + csi_id = info->csi_id; + _mipi_csi2_unlock(info); + + return csi_id; } EXPORT_SYMBOL(mipi_csi2_get_bind_csi); @@ -221,7 +352,13 @@ EXPORT_SYMBOL(mipi_csi2_get_bind_csi); */ unsigned int mipi_csi2_get_virtual_channel(struct mipi_csi2_info *info) { - return info->v_channel; + unsigned int v_channel; + + _mipi_csi2_lock(info); + v_channel = info->v_channel; + _mipi_csi2_unlock(info); + + return v_channel; } EXPORT_SYMBOL(mipi_csi2_get_virtual_channel); @@ -254,8 +391,12 @@ static int mipi_csi2_probe(struct platform_device *pdev) goto alloc_failed; } + /* initialize mutex */ + mutex_init(&gmipi_csi2->mutex_lock); + /* get mipi csi2 informaiton */ gmipi_csi2->pdev = pdev; + gmipi_csi2->mipi_en = false; gmipi_csi2->ipu_id = plat_data->ipu_id; gmipi_csi2->csi_id = plat_data->csi_id; gmipi_csi2->v_channel = plat_data->v_channel; @@ -295,6 +436,8 @@ static int mipi_csi2_probe(struct platform_device *pdev) /* get mipi csi2 dphy version */ mipi_csi2_dphy_ver = mipi_csi2_read(gmipi_csi2, CSI2_VERSION); + clk_disable(gmipi_csi2->dphy_clk); + platform_set_drvdata(pdev, gmipi_csi2); dev_info(&pdev->dev, "i.MX MIPI CSI2 driver probed\n"); @@ -320,7 +463,6 @@ static int __devexit mipi_csi2_remove(struct platform_device *pdev) iounmap(gmipi_csi2->mipi_csi2_base); /* disable mipi dphy clk */ - clk_disable(gmipi_csi2->dphy_clk); clk_put(gmipi_csi2->dphy_clk); clk_put(gmipi_csi2->pixel_clk); @@ -360,7 +502,7 @@ static void __exit mipi_csi2_cleanup(void) platform_driver_unregister(&mipi_csi2_driver); } -module_init(mipi_csi2_init); +subsys_initcall(mipi_csi2_init); module_exit(mipi_csi2_cleanup); MODULE_AUTHOR("Freescale Semiconductor, Inc."); diff --git a/drivers/mxc/mipi/mxc_mipi_csi2.h b/drivers/mxc/mipi/mxc_mipi_csi2.h index d7c4ba1e36da..9bccff7d6ce2 100644 --- a/drivers/mxc/mipi/mxc_mipi_csi2.h +++ b/drivers/mxc/mipi/mxc_mipi_csi2.h @@ -28,15 +28,18 @@ /* driver private data */ struct mipi_csi2_info { - int ipu_id; + bool mipi_en; + int ipu_id; unsigned int csi_id; unsigned int v_channel; unsigned int lanes; unsigned int datatype; - struct clk *dphy_clk; - struct clk *pixel_clk; - unsigned int *mipi_csi2_base; - struct platform_device *pdev; + struct clk *dphy_clk; + struct clk *pixel_clk; + unsigned int *mipi_csi2_base; + struct platform_device *pdev; + + struct mutex mutex_lock; }; #endif -- 2.39.5