Files
linux-legacy/drivers/mxc/ipu/ipu_csi.c
Sammy He 9fe0e34c9f ENGR00124683-1 Add CCIR interlaced mode for TV decoder
Add CCIR interlaced mode for TV decoder. And add pwdn callback
function in mxc_camera_platform_data.

Signed-off-by: Sammy He <r62914@freescale.com>
2010-08-10 11:51:15 -05:00

226 lines
5.9 KiB
C

/*
* Copyright 2005-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
/*!
* @file ipu_csi.c
*
* @brief IPU CMOS Sensor interface functions
*
* @ingroup IPU
*/
#include <linux/types.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/ipu.h>
#include "ipu_prv.h"
#include "ipu_regs.h"
static bool gipu_csi_get_mclk_flag = false;
static int csi_mclk_flag = 0;
extern void gpio_sensor_suspend(bool flag);
/*!
* ipu_csi_init_interface
* Sets initial values for the CSI registers.
* The width and height of the sensor and the actual frame size will be
* set to the same values.
* @param width Sensor width
* @param height Sensor height
* @param pixel_fmt pixel format
* @param sig ipu_csi_signal_cfg_t structure
*
* @return 0 for success, -EINVAL for error
*/
int32_t
ipu_csi_init_interface(uint16_t width, uint16_t height, uint32_t pixel_fmt,
ipu_csi_signal_cfg_t sig)
{
uint32_t data = 0;
/* Set SENS_DATA_FORMAT bits (8 and 9)
RGB or YUV444 is 0 which is current value in data so not set explicitly
This is also the default value if attempts are made to set it to
something invalid. */
switch (pixel_fmt) {
case IPU_PIX_FMT_UYVY:
data = CSI_SENS_CONF_DATA_FMT_YUV422;
break;
case IPU_PIX_FMT_RGB24:
case IPU_PIX_FMT_BGR24:
data = CSI_SENS_CONF_DATA_FMT_RGB_YUV444;
break;
case IPU_PIX_FMT_GENERIC:
data = CSI_SENS_CONF_DATA_FMT_BAYER;
break;
default:
return -EINVAL;
}
/* Set the CSI_SENS_CONF register remaining fields */
data |= sig.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
sig.data_pol << CSI_SENS_CONF_DATA_POL_SHIFT |
sig.Vsync_pol << CSI_SENS_CONF_VSYNC_POL_SHIFT |
sig.Hsync_pol << CSI_SENS_CONF_HSYNC_POL_SHIFT |
sig.pixclk_pol << CSI_SENS_CONF_PIX_CLK_POL_SHIFT |
sig.ext_vsync << CSI_SENS_CONF_EXT_VSYNC_SHIFT |
sig.clk_mode << CSI_SENS_CONF_SENS_PRTCL_SHIFT |
sig.sens_clksrc << CSI_SENS_CONF_SENS_CLKSRC_SHIFT;
__raw_writel(data, CSI_SENS_CONF);
/* Setup frame size */
__raw_writel(width | height << 16, CSI_SENS_FRM_SIZE);
__raw_writel(width << 16, CSI_FLASH_STROBE_1);
__raw_writel(height << 16 | 0x22, CSI_FLASH_STROBE_2);
/* Set CCIR registers */
if (sig.clk_mode == IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE) {
__raw_writel(0x40030, CSI_CCIR_CODE_1);
__raw_writel(0xFF0000, CSI_CCIR_CODE_3);
} else if (sig.clk_mode == IPU_CSI_CLK_MODE_CCIR656_INTERLACED) {
__raw_writel(0xD07DF, CSI_CCIR_CODE_1);
__raw_writel(0x40596, CSI_CCIR_CODE_2);
__raw_writel(0xFF0000, CSI_CCIR_CODE_3);
}
dev_dbg(g_ipu_dev, "CSI_SENS_CONF = 0x%08X\n",
__raw_readl(CSI_SENS_CONF));
dev_dbg(g_ipu_dev, "CSI_ACT_FRM_SIZE = 0x%08X\n",
__raw_readl(CSI_ACT_FRM_SIZE));
return 0;
}
/*!
* ipu_csi_flash_strobe
*
* @param flag true to turn on flash strobe
*
* @return 0 for success
*/
void ipu_csi_flash_strobe(bool flag)
{
if (flag == true) {
__raw_writel(__raw_readl(CSI_FLASH_STROBE_2) | 0x1,
CSI_FLASH_STROBE_2);
}
}
/*!
* ipu_csi_enable_mclk
*
* @param src enum define which source to control the clk
* CSI_MCLK_VF CSI_MCLK_ENC CSI_MCLK_RAW CSI_MCLK_I2C
* @param flag true to enable mclk, false to disable mclk
* @param wait true to wait 100ms make clock stable, false not wait
*
* @return 0 for success
*/
int32_t ipu_csi_enable_mclk(int src, bool flag, bool wait)
{
if (flag == true) {
csi_mclk_flag |= src;
} else {
csi_mclk_flag &= ~src;
}
if (gipu_csi_get_mclk_flag == flag)
return 0;
if (flag == true) {
clk_enable(g_ipu_csi_clk);
if (wait == true)
msleep(10);
/*printk("enable csi clock from source %d\n", src); */
gipu_csi_get_mclk_flag = true;
} else if (csi_mclk_flag == 0) {
clk_disable(g_ipu_csi_clk);
/*printk("disable csi clock from source %d\n", src); */
gipu_csi_get_mclk_flag = flag;
}
return 0;
}
/*!
* ipu_csi_read_mclk_flag
*
* @return csi_mclk_flag
*/
int ipu_csi_read_mclk_flag(void)
{
return csi_mclk_flag;
}
/*!
* ipu_csi_get_window_size
*
* @param width pointer to window width
* @param height pointer to window height
* @param dummy dummy for IPUv1 to keep the same interface with IPUv3
*
*/
void ipu_csi_get_window_size(uint32_t *width, uint32_t *height,
uint32_t dummy)
{
uint32_t reg;
reg = __raw_readl(CSI_ACT_FRM_SIZE);
*width = (reg & 0xFFFF) + 1;
*height = (reg >> 16 & 0xFFFF) + 1;
}
/*!
* ipu_csi_set_window_size
*
* @param width window width
* @param height window height
* @param dummy dummy for IPUv1 to keep the same interface with IPUv3
*
*/
void ipu_csi_set_window_size(uint32_t width, uint32_t height, uint32_t dummy)
{
__raw_writel((width - 1) | (height - 1) << 16, CSI_ACT_FRM_SIZE);
}
/*!
* ipu_csi_set_window_pos
*
* @param left uint32 window x start
* @param top uint32 window y start
* @param dummy dummy for IPUv1 to keep the same interface with IPUv3
*
*/
void ipu_csi_set_window_pos(uint32_t left, uint32_t top, uint32_t dummy)
{
uint32_t temp = __raw_readl(CSI_OUT_FRM_CTRL);
temp &= 0xffff0000;
temp = top | (left << 8) | temp;
__raw_writel(temp, CSI_OUT_FRM_CTRL);
}
/* Exported symbols for modules. */
EXPORT_SYMBOL(ipu_csi_set_window_pos);
EXPORT_SYMBOL(ipu_csi_set_window_size);
EXPORT_SYMBOL(ipu_csi_get_window_size);
EXPORT_SYMBOL(ipu_csi_read_mclk_flag);
EXPORT_SYMBOL(ipu_csi_enable_mclk);
EXPORT_SYMBOL(ipu_csi_flash_strobe);
EXPORT_SYMBOL(ipu_csi_init_interface);