/*
* ispccp2.c
*
* TI OMAP3 ISP - CCP2 module
*
* Copyright (C) 2010 Nokia Corporation
* Copyright (C) 2010 Texas Instruments, Inc.
*
* Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
* Sakari Ailus <sakari.ailus@iki.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
#include <linux/regulator/consumer.h>
#include "isp.h"
#include "ispreg.h"
#include "ispccp2.h"
/* Number of LCX channels */
#define CCP2_LCx_CHANS_NUM 3
/* Max/Min size for CCP2 video port */
#define ISPCCP2_DAT_START_MIN 0
#define ISPCCP2_DAT_START_MAX 4095
#define ISPCCP2_DAT_SIZE_MIN 0
#define ISPCCP2_DAT_SIZE_MAX 4095
#define ISPCCP2_VPCLK_FRACDIV 65536
#define ISPCCP2_LCx_CTRL_FORMAT_RAW8_DPCM10_VP 0x12
#define ISPCCP2_LCx_CTRL_FORMAT_RAW10_VP 0x16
/* Max/Min size for CCP2 memory channel */
#define ISPCCP2_LCM_HSIZE_COUNT_MIN 16
#define ISPCCP2_LCM_HSIZE_COUNT_MAX 8191
#define ISPCCP2_LCM_HSIZE_SKIP_MIN 0
#define ISPCCP2_LCM_HSIZE_SKIP_MAX 8191
#define ISPCCP2_LCM_VSIZE_MIN 1
#define ISPCCP2_LCM_VSIZE_MAX 8191
#define ISPCCP2_LCM_HWORDS_MIN 1
#define ISPCCP2_LCM_HWORDS_MAX 4095
#define ISPCCP2_LCM_CTRL_BURST_SIZE_32X 5
#define ISPCCP2_LCM_CTRL_READ_THROTTLE_FULL 0
#define ISPCCP2_LCM_CTRL_SRC_DECOMPR_DPCM10 2
#define ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW8 2
#define ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW10 3
#define ISPCCP2_LCM_CTRL_DST_FORMAT_RAW10 3
#define ISPCCP2_LCM_CTRL_DST_PORT_VP 0
#define ISPCCP2_LCM_CTRL_DST_PORT_MEM 1
/* Set only the required bits */
#define BIT_SET(var, shift, mask, val) \
do { \
var = ((var) & ~((mask) << (shift))) \
| ((val) << (shift)); \
} while (0)
/*
* ccp2_print_status - Print current CCP2 module register values.
*/
#define CCP2_PRINT_REGISTER(isp, name)\
dev_dbg(isp->dev, "###CCP2 " #name "=0x%08x\n", \
isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_##name))
static void ccp2_print_status(struct isp_ccp2_device *ccp2)
{
struct isp_device *isp = to_isp_device(ccp2);
dev_dbg(isp->dev, "-------------CCP2 Register dump-------------\n");
CCP2_PRINT_REGISTER(isp, SYSCONFIG);
CCP2_PRINT_REGISTER(isp, SYSSTATUS);
CCP2_PRINT_REGISTER(isp, LC01_IRQENABLE);
CCP2_PRINT_REGISTER(isp, LC01_IRQSTATUS);
CCP2_PRINT_REGISTER(isp, LC23_IRQENABLE);
CCP2_PRINT_REGISTER(isp, LC23_IRQSTATUS);
CCP2_PRINT_REGISTER(isp, LCM_IRQENABLE);
CCP2_PRINT_REGISTER(isp, LCM_IRQSTATUS);
CCP2_PRINT_REGISTER(isp, CTRL);
CCP2_PRINT_REGISTER(isp, LCx_CTRL(0));
CCP2_PRINT_REGISTER(isp, LCx_CODE(0));
CCP2_PRINT_REGISTER(isp, LCx_STAT_START(0));
CCP2_PRINT_REGISTER(isp, LCx_STAT_SIZE(0));
CCP2_PRINT_REGISTER(isp, LCx_SOF_ADDR(0));
CCP2_PRINT_REGISTER(isp, LCx_EOF_ADDR(0));
CCP2_PRINT_REGISTER(isp, LCx_DAT_START(0));
CCP2_PRINT_REGISTER(isp, LCx_DAT_SIZE(0));
CCP2_PRINT_REGISTER(isp, LCx_DAT_PING_ADDR(0));
CCP2_PRINT_REGISTER(isp, LCx_DAT_PONG_ADDR(0));
CCP2_PRINT_REGISTER(isp, LCx_DAT_OFST(0));
CCP2_PRINT_REGISTER(isp, LCM_CTRL);
CCP2_PRINT_REGISTER(isp, LCM_VSIZE);
CCP2_PRINT_REGISTER(isp, LCM_HSIZE);
CCP2_PRINT_REGISTER(isp, LCM_PREFETCH);
CCP2_PRINT_REGISTER(isp, LCM_SRC_ADDR);
CCP2_PRINT_REGISTER(isp, LCM_SRC_OFST);
CCP2_PRINT_REGISTER(isp, LCM_DST_ADDR);
CCP2_PRINT_REGISTER(isp, LCM_DST_OFST);
dev_dbg(isp->dev, "--------------------------------------------\n");
}
/*
* ccp2_reset - Reset the CCP2
* @ccp2: pointer to ISP CCP2 device
*/
static void ccp2_reset(struct isp_ccp2_device *ccp2)
{
struct isp_device *isp = to_isp_device(ccp2);
int i = 0;
/* Reset the CSI1/CCP2B and wait for reset to complete */
isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSCONFIG,
ISPCCP2_SYSCONFIG_SOFT_RESET);
while (!(isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSSTATUS) &
ISPCCP2_SYSSTATUS_RESET_DON