This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

OMAP-L138: How to check VPIF, ISR has been called?

Other Parts Discussed in Thread: OMAP-L138, OMAPL138, TVP5147

I use OMAP-L138 LCDK to capture the RAW data from a CMOS image sensor. VPIF interface is used. However, there is no interrupt signals generated. The first thing I want to check is whether the ISR has been called. Does anyone know how to check that? Moreover, any other possible reasons could cause there is no interrupt signals? The code and the registers values for VPIF are attached. Thanks.

board-omapl138-lcdk.c
/*
 * TI's OMAP-L138 LCDK Development Board
 *
 * Initial code: Syed Mohammed Khasim
 *
 * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com
 *
 * This file is licensed under the terms of the GNU General Public License
 * version 2. This program is licensed "as is" without any warranty of
 * any kind, whether express or implied.
 */
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/i2c-gpio.h>
#include <linux/leds.h>
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/mfd/davinci_aemif.h>
#include <linux/videodev2.h>

#include <asm/mach-types.h>
#include <asm/mach/arch.h>

#include <mach/cp_intc.h>
#include <mach/da8xx.h>
#include <mach/mux.h>
#include <mach/nand.h>
#include <media/tvp514x.h>

#define LCDKBOARD_PHY_ID		"davinci_mdio-0:07"
#define DA850_LCDK_MMCSD_CD_PIN		GPIO_TO_PIN(4, 0)

#define DA850_USB1_VBUS_PIN		GPIO_TO_PIN(2, 4)
#define DA850_USB1_OC_PIN		GPIO_TO_PIN(6, 13)

#define LCDKBOARD_SATA_REFCLKPN_RATE   (100 * 1000 * 1000)

#define DA850_LCDK_USER_LED0		GPIO_TO_PIN(6, 12)
#define DA850_LCDK_USER_LED1		GPIO_TO_PIN(6, 13)
#define DA850_LCDK_USER_LED2		GPIO_TO_PIN(2, 12)
#define DA850_LCDK_USER_LED3		GPIO_TO_PIN(0, 9)

#define	DA850_LCDK_USER_KEY0            GPIO_TO_PIN(2, 4)
#define	DA850_LCDK_USER_KEY1            GPIO_TO_PIN(2, 5)

#if defined(CONFIG_USB_OHCI_HCD)
#define HAS_OHCI               1
#else
#define HAS_OHCI               0
#endif

#define        DA850_LCDK_KEYS_DEBOUNCE_MS     10
#define        DA850_LCDK_GPIO_KEYS_POLL_MS    200

#define DA850_LCD_PWR_PIN              GPIO_TO_PIN(2, 8)
#define DA850_LCD_BL_PIN               GPIO_TO_PIN(2, 15)

#if defined(CONFIG_MTD_NAND_DAVINCI) || \
	defined(CONFIG_MTD_NAND_DAVINCI_MODULE)
struct mtd_partition omapl138_lcdk_nandflash_partition[] = {
	{
		.name           = "ubl",
		.offset         = 0x20000,
		.size           = SZ_128K * 5,
		.mask_flags     = MTD_WRITEABLE,
	},
	{
		.name           = "uboot",
		.offset         = MTDPART_OFS_APPEND,
		.size           = SZ_1M * 5,
		.mask_flags     = MTD_WRITEABLE,
	},
	{
		.name           = "env",
		.offset         = MTDPART_OFS_APPEND,
		.size           = SZ_1M * 5,
		.mask_flags     = MTD_WRITEABLE,
	},
	{
		.name           = "kernel",
		.offset         = MTDPART_OFS_APPEND,
		.size           = SZ_1M * 20,
		.mask_flags     = 0,
	},
	{
		.name		= "rootfs",
		.offset 	= MTDPART_OFS_APPEND,
		.size		= SZ_1M * 100,
		.mask_flags	= 0,
	},
	{
		.name		= "user0",
		.offset 	= MTDPART_OFS_APPEND,
		.size		= SZ_1M * 100,
		.mask_flags	= 0,
	},
	{
		.name		= "user1",
		.offset 	= MTDPART_OFS_APPEND,
		.size		= SZ_1M * 100,
		.mask_flags	= 0,
	},
	{
		.name           = "append",
		.offset         = MTDPART_OFS_APPEND,
		.size           = MTDPART_SIZ_FULL,
		.mask_flags     = 0,
	},
};

static struct davinci_nand_pdata omapl138_lcdk_nandflash_data = {
	.parts          = omapl138_lcdk_nandflash_partition,
	.nr_parts       = ARRAY_SIZE(omapl138_lcdk_nandflash_partition),
	.ecc_mode       = NAND_ECC_NONE,//NAND_ECC_HW_OOB_FIRST,//
	.options        = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE,
	.ecc_bits       = 1, /* 4 bit mode is not
			      * supported with 16 bit NAND */
	.bbt_options    = NAND_BBT_USE_FLASH,
};

static const short omapl138_lcdk_nand_pins[] = {
	DA850_EMA_D_0, DA850_EMA_D_1, DA850_EMA_D_2, DA850_EMA_D_3,
	DA850_EMA_D_4, DA850_EMA_D_5, DA850_EMA_D_6, DA850_EMA_D_7,
	DA850_EMA_D_8, DA850_EMA_D_9, DA850_EMA_D_10, DA850_EMA_D_11,
	DA850_EMA_D_12, DA850_EMA_D_13, DA850_EMA_D_14, DA850_EMA_D_15,
	DA850_EMA_A_1, DA850_EMA_A_2, DA850_NEMA_CS_3, DA850_NEMA_CS_4,
	DA850_NEMA_WE, DA850_NEMA_OE,
	-1
};

static struct resource omapl138_lcdk_nandflash_resource[] = {
	{
		.start  = DA8XX_AEMIF_CS3_BASE,
		.end    = DA8XX_AEMIF_CS3_BASE + SZ_512K + 2 * SZ_1K - 1,
		.flags  = IORESOURCE_MEM,
	},
	{
		.start  = DA8XX_AEMIF_CTL_BASE,
		.end    = DA8XX_AEMIF_CTL_BASE + SZ_32K - 1,
		.flags  = IORESOURCE_MEM,
	},
};

static struct platform_device omapl138_lcdk_nandflash_device = {
	.name           = "davinci_nand",
	.id             = 1,
	.dev            = {
		.platform_data  = &omapl138_lcdk_nandflash_data,
	},
	.resource       = omapl138_lcdk_nandflash_resource,
	.num_resources  = ARRAY_SIZE(omapl138_lcdk_nandflash_resource),
};

static __init void omapl138_lcdk_nand_init(void)
{
	int ret;

	ret = davinci_cfg_reg_list(omapl138_lcdk_nand_pins);
	if (ret) {
		pr_warn("da850_lcdk_init:"
				"nand mux setup failed: %d\n", ret);
		return;
	}
	platform_device_register(&omapl138_lcdk_nandflash_device);
}
#else
static void omapl138_lcdk_nand_init(void) { }
#endif


static short omapl138_lcdk_mii_pins[] __initdata = {
	DA850_MII_TXEN, DA850_MII_TXCLK, DA850_MII_COL, DA850_MII_TXD_3,
	DA850_MII_TXD_2, DA850_MII_TXD_1, DA850_MII_TXD_0, DA850_MII_RXER,
	DA850_MII_CRS, DA850_MII_RXCLK, DA850_MII_RXDV, DA850_MII_RXD_3,
	DA850_MII_RXD_2, DA850_MII_RXD_1, DA850_MII_RXD_0, DA850_MDIO_CLK,
	DA850_MDIO_D,
	-1
};

static __init void omapl138_lcdk_config_emac(void)
{
	void __iomem *cfgchip3 = DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG);
	int ret;
	u32 val;
	struct davinci_soc_info *soc_info = &davinci_soc_info;

	val = __raw_readl(cfgchip3);
	val &= ~BIT(8);
	ret = davinci_cfg_reg_list(omapl138_lcdk_mii_pins);
	if (ret) {
		pr_warning("%s: cpgmac/mii mux setup failed: %d\n",
			__func__, ret);
		return;
	}

	/* configure the CFGCHIP3 register for MII */
	__raw_writel(val, cfgchip3);
	pr_info("EMAC: MII PHY configured\n");

	soc_info->emac_pdata->phy_id = LCDKBOARD_PHY_ID;

	ret = da8xx_register_emac();
	if (ret)
		pr_warning("%s: emac registration failed: %d\n",
			__func__, ret);
}

/*
 * The following EDMA channels/slots are not being used by drivers (for
 * example: Timer, GPIO, UART events etc) on da850/omap-l138 LCDK EVM,
 * hence they are being reserved for codecs on the DSP side.
 */
static const s16 da850_dma0_rsv_chans[][2] = {
	/* (offset, number) */
	{ 8,  6},
	{24,  4},
	{30,  2},
	{-1, -1}
};

static const s16 da850_dma0_rsv_slots[][2] = {
	/* (offset, number) */
	{ 8,  6},
	{24,  4},
	{30, 50},
	{-1, -1}
};

static const s16 da850_dma1_rsv_chans[][2] = {
	/* (offset, number) */
	{ 0, 28},
	{30,  2},
	{-1, -1}
};

static const s16 da850_dma1_rsv_slots[][2] = {
	/* (offset, number) */
	{ 0, 28},
	{30, 90},
	{-1, -1}
};

static struct edma_rsv_info da850_edma_cc0_rsv = {
	.rsv_chans	= da850_dma0_rsv_chans,
	.rsv_slots	= da850_dma0_rsv_slots,
};

static struct edma_rsv_info da850_edma_cc1_rsv = {
	.rsv_chans	= da850_dma1_rsv_chans,
	.rsv_slots	= da850_dma1_rsv_slots,
};

static struct edma_rsv_info *da850_edma_rsv[2] = {
	&da850_edma_cc0_rsv,
	&da850_edma_cc1_rsv,
};

static const short lcdk_mmcsd0_pins[] = {
	DA850_MMCSD0_DAT_0, DA850_MMCSD0_DAT_1, DA850_MMCSD0_DAT_2,
	DA850_MMCSD0_DAT_3, DA850_MMCSD0_CLK, DA850_MMCSD0_CMD,
	DA850_GPIO3_12, DA850_GPIO3_13,
	-1
};

static int da850_lcdk_mmc_get_ro(int index)
{
	return 0;
}

static int da850_lcdk_mmc_get_cd(int index)
{
	return !gpio_get_value(DA850_LCDK_MMCSD_CD_PIN);
}

static struct davinci_mmc_config da850_mmc_config = {
	.get_ro		= da850_lcdk_mmc_get_ro,
	.get_cd		= da850_lcdk_mmc_get_cd,
	.wires		= 4,
	.max_freq	= 50000000,
	.caps		= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
	.version	= MMC_CTLR_VERSION_2,
};

static __init void omapl138_lcdk_mmc_init(void)
{
	int ret;

	ret = davinci_cfg_reg_list(lcdk_mmcsd0_pins);
	if (ret) {
		pr_warning("%s: MMC/SD0 mux setup failed: %d\n",
			__func__, ret);
		return;
	}

	ret = gpio_request_one(DA850_LCDK_MMCSD_CD_PIN,
			GPIOF_DIR_IN, "MMC CD");
	if (ret < 0) {
		pr_warning("%s: can not open GPIO %d\n",
			__func__, DA850_LCDK_MMCSD_CD_PIN);
		return;
	}

	ret = da8xx_register_mmcsd0(&da850_mmc_config);
	if (ret) {
		pr_warning("%s: MMC/SD0 registration failed: %d\n",
			__func__, ret);
		goto mmc_setup_mmcsd_fail;
	}

	return;

mmc_setup_mmcsd_fail:
	gpio_free(DA850_LCDK_MMCSD_CD_PIN);
}

static irqreturn_t omapl138_lcdk_usb_ocic_irq(int irq, void *dev_id);

static const short da850_lcdk_usb11_pins[] = {
	DA850_GPIO2_4, DA850_GPIO6_13,
	-1
};

static struct da8xx_ohci_root_hub omapl138_lcdk_usb11_pdata = {
	.type	= GPIO_BASED,
	.method	= {
		.gpio_method = {
			.power_control_pin	= DA850_USB1_VBUS_PIN,
			.over_current_indicator = DA850_USB1_OC_PIN,
		},
	},
	.board_ocic_handler	= omapl138_lcdk_usb_ocic_irq,
};

static irqreturn_t omapl138_lcdk_usb_ocic_irq(int irq, void *handler)
{
	if (handler != NULL)
		((da8xx_ocic_handler_t)handler)(&omapl138_lcdk_usb11_pdata, 1);
	return IRQ_HANDLED;
}

/* VGA */
static const short omapl138_lcdk_lcdc_pins[] = {
	DA850_GPIO2_8, DA850_GPIO2_15,
	-1
};

/* Backlight and power is for use with LCD expansion header only */
static void da850_panel_power_ctrl(int val)
{
	/* lcd backlight */
	gpio_set_value(DA850_LCD_BL_PIN, val);
	/* lcd power */
	gpio_set_value(DA850_LCD_PWR_PIN, val);
}

static int da850_lcd_hw_init(void)
{
	void __iomem *cfg_mstpri1_base;
	void __iomem *cfg_mstpri2_base;
	void __iomem *emifb;
	void __iomem *myptr;
	int status;
	u32 val;

	/*
	 * Default master priorities in reg 0 are all lower by default than LCD
	 * which is set below to 0. Hence don't need to change here.
	 */

	/* set EDMA30TC0 and TC1 to lower than LCDC (4 < 0) */
	cfg_mstpri1_base = DA8XX_SYSCFG0_VIRT(DA8XX_MSTPRI1_REG);
	val = __raw_readl(cfg_mstpri1_base);
	val &= 0xFFFF00FF;
	val |= 4 << 8;             /* 0-high, 7-low priority*/
	val |= 4 << 12;            /* 0-high, 7-low priority*/
	__raw_writel(val, cfg_mstpri1_base);

	/*
	 * Reconfigure the LCDC priority to the highest to ensure that
	 * the throughput/latency requirements for the LCDC are met.
	 */
	cfg_mstpri2_base = DA8XX_SYSCFG0_VIRT(DA8XX_MSTPRI2_REG);

	val = __raw_readl(cfg_mstpri2_base);
	val &= 0x0fffffff;
	__raw_writel(val, cfg_mstpri2_base);

	/* set BPRIO */
#define DA8XX_EMIF30_CONTROL_BASE               0xB0000000
#define DA8XX_EMIF30_BPRIO_OFFSET               0x20
#define DA8XX_EMIFB_VIRT(x)     (emifb + (x))
	emifb = ioremap(DA8XX_EMIF30_CONTROL_BASE, SZ_4K);
	myptr = DA8XX_EMIFB_VIRT(0x20);
	__raw_writel(0x20, myptr);

	status = gpio_request(DA850_LCD_BL_PIN, "lcd bl\n");
	if (status < 0)
		return status;

	status = gpio_request(DA850_LCD_PWR_PIN, "lcd pwr\n");
	if (status < 0) {
		gpio_free(DA850_LCD_BL_PIN);
		return status;
	}

	gpio_direction_output(DA850_LCD_BL_PIN, 0);
	gpio_direction_output(DA850_LCD_PWR_PIN, 0);

	/* Switch off panel power and backlight */
	da850_panel_power_ctrl(0);

	/* Switch on panel power and backlight */
	da850_panel_power_ctrl(1);

	return 0;
}

static void omapl138_lcdk_display_init(void)
{
	int ret;

	ret = davinci_cfg_reg_list(da850_lcdcntl_pins);
	if (ret)
		pr_warn("omapl138_lcdk_init: lcdcntl mux setup failed:%d\n",
				ret);

	ret = davinci_cfg_reg_list(omapl138_lcdk_lcdc_pins);
	if (ret)
		pr_warn("omapl138_lcdk_init: evm specific lcd mux setup "
				"failed: %d\n", ret);

	da850_lcd_hw_init();

	ret = da8xx_register_lcdc(&vga_monitor_pdata);
	if (ret)
		pr_warn("omapl138_lcdk_init: lcdc registration failed: %d\n",
				ret);
}

static __init void omapl138_lcdk_usb_init(void)
{
	u32 cfgchip2;
	int ret;

	/* Setup the Ref. clock frequency for the LCDK at 24 MHz. */

	cfgchip2 = __raw_readl(DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));
	cfgchip2 &= ~CFGCHIP2_REFFREQ;
	cfgchip2 |=  CFGCHIP2_REFFREQ_24MHZ;

	/*
	 * Select internal reference clock for USB 2.0 PHY
	 * and use it as a clock source for USB 1.1 PHY
	 * (this is the default setting anyway).
	 */
	cfgchip2 &= ~CFGCHIP2_USB1PHYCLKMUX;
	cfgchip2 |=  CFGCHIP2_USB2PHYCLKMUX;

	/*
	 * We have to override VBUS/ID signals when MUSB is configured into the
	 * host-only mode -- ID pin will float if no cable is connected, so the
	 * controller won't be able to drive VBUS thinking that it's a B-device.
	 * Otherwise, we want to use the OTG mode and enable VBUS comparators.
	 */
	cfgchip2 &= ~CFGCHIP2_OTGMODE;
	cfgchip2 |=  CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN;

	/*
	 * TPS2065 switch @ 5V supplies 1 A (sustains 1.5 A),
	 * with the power on to power good time of 3 ms.
	 */
	ret = da8xx_register_usb20(1000, 3);
	if (ret)
		pr_warn("%s: USB 2.0 registration failed: %d\n",
				__func__, ret);

	__raw_writel(cfgchip2, DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP2_REG));

	if (HAS_OHCI)
		da8xx_board_usb_init(da850_lcdk_usb11_pins,
				     &omapl138_lcdk_usb11_pdata);

	return;
}

static struct davinci_uart_config omapl138_lcdk_uart_config __initdata = {
	.enabled_uarts = 0x7,
};

/* I2C */
static struct i2c_board_info __initdata omapl138_lcdk_i2c_devices[] = {
	{
		I2C_BOARD_INFO("tlv320aic3x", 0x18),
	},
};

static struct i2c_gpio_platform_data da850_gpio_i2c_pdata = {
	.sda_pin        = GPIO_TO_PIN(1, 4),
	.scl_pin        = GPIO_TO_PIN(1, 5),
	.udelay         = 2,                    /* 250 KHz */
};

static struct platform_device da850_gpio_i2c = {
	.name           = "i2c-gpio",
	.id             = 1,
	.dev            = {
		.platform_data  = &da850_gpio_i2c_pdata,
	},
};

static void omapl138_lcdk_i2c_init(void)
{
	int ret;
	ret = davinci_cfg_reg_list(da850_i2c0_pins);
	if (ret)
		pr_warn("omapl138_lcdk_init: i2c0 mux setup failed: %d\n",
				ret);

	platform_device_register(&da850_gpio_i2c);

	if (ret)
		pr_warn("omapl138_lcdk_init: i2c0 registration failed: %d\n",
				ret);
	i2c_register_board_info(1, omapl138_lcdk_i2c_devices,
			ARRAY_SIZE(omapl138_lcdk_i2c_devices));
}

/* Set up OMAP-L138 LCDK low-level McASP driver */
static u8 da850_iis_serializer_direction[] = {
	INACTIVE_MODE,  INACTIVE_MODE,  INACTIVE_MODE,  INACTIVE_MODE,
	INACTIVE_MODE,  INACTIVE_MODE,  INACTIVE_MODE,  INACTIVE_MODE,
	INACTIVE_MODE,  INACTIVE_MODE,  INACTIVE_MODE,  INACTIVE_MODE,
	INACTIVE_MODE,  TX_MODE,        RX_MODE,        INACTIVE_MODE,
};

static struct snd_platform_data omapl138_lcdk_snd_data = {
	.tx_dma_offset  = 0x2000,
	.rx_dma_offset  = 0x2000,
	.op_mode        = DAVINCI_MCASP_IIS_MODE,
	.num_serializer = ARRAY_SIZE(da850_iis_serializer_direction),
	.tdm_slots      = 2,
	.serial_dir     = da850_iis_serializer_direction,
	.asp_chan_q     = EVENTQ_0,
	.version        = MCASP_VERSION_2,
	.txnumevt       = 1,
	.rxnumevt       = 1,
};

static const short omapl138_lcdk_mcasp_pins[] __initconst = {
	DA850_AHCLKX,   DA850_ACLKX,    DA850_AFSX,
	DA850_AHCLKR,   DA850_ACLKR,    DA850_AFSR,     DA850_AMUTE,
	DA850_AXR_13,   DA850_AXR_14,
	-1
};

static void omapl138_lcdk_sound_init(void)
{
	int ret;
	ret = davinci_cfg_reg_list(omapl138_lcdk_mcasp_pins);
	if (ret)
		pr_warn("omapl138_lcdk_init: mcasp mux setup failed: %d\n",
				ret);

	da8xx_register_mcasp(0, &omapl138_lcdk_snd_data);
}

static const short omapl138_lcdk_led_pin_mux[] __initconst = {
	DA850_GPIO6_12,
#if !HAS_OHCI
	DA850_GPIO6_13,
#endif
	DA850_GPIO2_12,
	DA850_GPIO0_9,
	-1
};

static struct gpio_led gpio_leds[] = {
	{
		.active_low = 1,
		.gpio = DA850_LCDK_USER_LED0,
		.name = "user_led0",
	},
#if !HAS_OHCI
	{
		.active_low = 1,
		.gpio   = DA850_LCDK_USER_LED1,
		.name   = "user_led1",
	},
#endif
	{
		.active_low = 1,
		.gpio = DA850_LCDK_USER_LED2,
		.name = "user_led2",
	},
	{
		.active_low = 1,
		.gpio   = DA850_LCDK_USER_LED3,
		.name   = "user_led3",
	},
};

static struct gpio_led_platform_data gpio_led_info = {
	.leds           = gpio_leds,
	.num_leds       = ARRAY_SIZE(gpio_leds),
};

static struct platform_device leds_gpio = {
	.name   = "leds-gpio",
	.id     = -1,
	.dev    = {
		.platform_data  = &gpio_led_info,
	},
};

static  __init void omapl138_lcdk_led_init(void)
{
	int err;

	davinci_cfg_reg_list(omapl138_lcdk_led_pin_mux);
	err = platform_device_register(&leds_gpio);
	if (err)
		pr_err("failed to register leds_gpio device\n");
	return;
};

static const short omapl138_lcdk_keys_pin_mux[] __initconst = {
#if !HAS_OHCI
	DA850_GPIO2_4,
#endif
	DA850_GPIO2_5,
	-1
};

static struct gpio_keys_button omapl138_lcdk_evm_keys[] = {
#if !HAS_OHCI
	{
		.type                   = EV_KEY,
		.active_low             = 1,
		.wakeup                 = 0,
		.debounce_interval      = DA850_LCDK_KEYS_DEBOUNCE_MS,
		.code                   = KEY_F8,
		.gpio                   = DA850_LCDK_USER_KEY0,
		.desc                   = "pb1",
	},
#endif
	{
		.type                   = EV_KEY,
		.active_low             = 1,
		.wakeup                 = 0,
		.debounce_interval      = DA850_LCDK_KEYS_DEBOUNCE_MS,
		.code                   = KEY_F7,
		.gpio                   = DA850_LCDK_USER_KEY1,
		.desc                   = "pb2",
	},
};

static struct gpio_keys_platform_data omapl138_lcdk_evm_keys_pdata = {
	.buttons = omapl138_lcdk_evm_keys,
	.nbuttons = ARRAY_SIZE(omapl138_lcdk_evm_keys),
	.poll_interval = DA850_LCDK_GPIO_KEYS_POLL_MS,
};

static struct platform_device omapl138_lcdk_evm_keys_device = {
	.name = "gpio-keys-polled",
	.id = 0,
	.dev = {
		.platform_data = &omapl138_lcdk_evm_keys_pdata
	},
};

static  __init void omapl138_lcdk_keys_init(void)
{
	int err;

	davinci_cfg_reg_list(omapl138_lcdk_keys_pin_mux);
	err = platform_device_register(&omapl138_lcdk_evm_keys_device);
	if (err)
		pr_err("failed to register omapl138_lcdk_evm_keys_device\n");
	return;
};

static struct davinci_pm_config da850_pm_pdata = {
	.sleepcount = 128,
};

static struct platform_device da850_pm_device = {
	.name           = "pm-davinci",
	.dev = {
		.platform_data  = &da850_pm_pdata,
	},
	.id             = -1,
};

#define TVP5147_CH0		"tvp514x-0"
#define TVP5147_CH1		"tvp514x-1"

#define VPIF_STATUS	(0x002C)
#define VPIF_STATUS_CLR	(0x0030)

/* Retaining these APIs, since the VPIF drivers do not check NULL handlers */
static int da850_set_vpif_clock(int mux_mode, int hd)
{
	return 0;
}

static int da850_setup_vpif_input_channel_mode(int mux_mode)
{
	return 0;
}

static int da850_vpif_setup_input_path(int ch, const char *name)
{
	if (!strcmp(name, "ov2715")) {
		printk("set up ov2715 input path\n");

	} else if (!strcmp(name, "tvp5147")) {
		printk("set up tvp5147 input path\n");

	} else {
		printk("unknown input path\n");
	}

	return 1;
}

static int da850_vpif_intr_status(void __iomem *vpif_base, int channel)
{
	int status = 0;
	int mask;

	if (channel < 0 || channel > 3)
		return 0;

	mask = 1 << channel;
	status = __raw_readl((vpif_base + VPIF_STATUS)) & mask;
	__raw_writel(status, (vpif_base + VPIF_STATUS_CLR));

	return status;
}

//#define CONFIG_LCDK_UI_SD_VIDEO_PORT  1
#define CONFIG_LCDK_UI_CAMERA         2

#if defined(CONFIG_LCDK_UI_SD_VIDEO_PORT)
/* VPIF capture configuration */
static struct tvp514x_platform_data tvp5147_pdata = {
	.clk_polarity = 0,
	.hs_polarity = 1,
	.vs_polarity = 1
};
#endif

#define TVP514X_STD_ALL (V4L2_STD_NTSC | V4L2_STD_PAL)

static struct vpif_subdev_info da850_vpif_capture_sdev_info[] = {
#if defined(CONFIG_LCDK_UI_CAMERA)
	{
		.name	= "ov2715",
		.board_info = {
			I2C_BOARD_INFO("ov2715", 0x6C>>1),
			.platform_data = (void *)1,
		},
		.vpif_if = {
			.if_type = VPIF_IF_RAW_BAYER,
			.hd_pol = 0,
			.vd_pol = 0,
			.fid_pol = 0,
		},
	},
#elif defined(CONFIG_LCDK_UI_SD_VIDEO_PORT)
	{
		.name	= TVP5147_CH0,
		.board_info = {
			I2C_BOARD_INFO("tvp5147", 0xBA>>1),
			.platform_data = &tvp5147_pdata,
		},
		.input = INPUT_CVBS_VI2B,
		.output = OUTPUT_10BIT_422_EMBEDDED_SYNC,
		.can_route = 1,
		.vpif_if = {
			.if_type = VPIF_IF_BT656,
			.hd_pol = 1,
			.vd_pol = 1,
			.fid_pol = 0,
		},
	},
#endif
};

#if defined(CONFIG_LCDK_UI_CAMERA)

static const struct vpif_input da850_ch0_inputs[] = {
	{
		.input = {
			.index = 0,
			.name = "ov2715",
			.type = V4L2_INPUT_TYPE_CAMERA,
			.std  = V4L2_STD_BAYER_720,//V4L2_STD_BAYER_1920,
		},
		.subdev_name = "ov2715",
	},
};

static const struct vpif_input da850_ch1_inputs[] = {
	{
		.input = {
			.index = 0,
			.name  = "ov2715",
			.type  = V4L2_INPUT_TYPE_CAMERA,
			.std   = V4L2_STD_BAYER_720,//V4L2_STD_BAYER_1920,
		},
		.subdev_name = "ov2715",
	},
};

#elif defined(CONFIG_LCDK_UI_SD_VIDEO_PORT)

static const struct vpif_input da850_ch0_inputs[] = {
	{
		.input = {
			.index = 0,
			.name = "Composite",
			.type = V4L2_INPUT_TYPE_CAMERA,
			.std = TVP514X_STD_ALL,
		},
		.subdev_name = TVP5147_CH0,
	},
};

static const struct vpif_input da850_ch1_inputs[] = {
	{
		.input = {
			.index = 0,
			.name = "Composite",
			.type = V4L2_INPUT_TYPE_CAMERA,
			.std = TVP514X_STD_ALL,
		},
		.subdev_name = TVP5147_CH1,
	},
};
#endif

static struct vpif_capture_config da850_vpif_capture_config = {
	.setup_input_channel_mode = da850_setup_vpif_input_channel_mode,
	.setup_input_path = da850_vpif_setup_input_path,
	.intr_status = da850_vpif_intr_status,
	.subdev_info = da850_vpif_capture_sdev_info,
	.subdev_count = ARRAY_SIZE(da850_vpif_capture_sdev_info),
	.chan_config[0] = {
		.inputs = da850_ch0_inputs,
		.input_count = ARRAY_SIZE(da850_ch0_inputs),
	},
	.chan_config[1] = {
		.inputs = da850_ch1_inputs,
		.input_count = ARRAY_SIZE(da850_ch1_inputs),
	},
	.card_name      = "DA850/OMAP-L138 Video Capture",
};

static const char *vpif_output[] = {
	"Composite",
	"Component",
	"S-Video",
};

static struct vpif_display_config da850_vpif_display_config = {
	.set_clock	= da850_set_vpif_clock,
	.intr_status	= da850_vpif_intr_status,
	.subdevinfo	= NULL,
	.subdev_count	= 0,
	.output		= vpif_output,
	.output_count	= ARRAY_SIZE(vpif_output),
	.card_name	= "DA850/OMAP-L138 Video Display",
};


#if defined(CONFIG_VIDEO_DAVINCI_VPIF_DISPLAY) ||\
		defined(CONFIG_VIDEO_DAVINCI_VPIF_DISPLAY_MODULE)
#define HAS_VPIF_DISPLAY 1
#else
#define HAS_VPIF_DISPLAY 0
#endif

#if defined(CONFIG_VIDEO_DAVINCI_VPIF_CAPTURE) ||\
		defined(CONFIG_VIDEO_DAVINCI_VPIF_CAPTURE_MODULE)
#define HAS_VPIF_CAPTURE 1
#else
#define HAS_VPIF_CAPTURE 0
#endif




static __init void omapl138_lcdk_init(void)
{
	int ret;

	davinci_serial_init(&omapl138_lcdk_uart_config);

	/*
	 * shut down uart 0 and 1; they are not used on this board and
	 * accessing them causes endless "too much work in irq53" messages
	 * with arago fs
	 */
	__raw_writel(0, IO_ADDRESS(DA8XX_UART1_BASE) + 0x30);
	__raw_writel(0, IO_ADDRESS(DA8XX_UART0_BASE) + 0x30);

	omapl138_lcdk_config_emac();

	ret = da850_register_edma(da850_edma_rsv);
	if (ret)
		pr_warning("%s: EDMA registration failed: %d\n",
			__func__, ret);

	omapl138_lcdk_mmc_init();

	omapl138_lcdk_usb_init();

	ret = da8xx_register_watchdog();
	if (ret)
		pr_warning("omapl138_lcdk_init: "
			"watchdog registration failed: %d\n",
			ret);

	ret = da8xx_register_rtc();
	if (ret)
		pr_warning("omapl138_lcdk_init: rtc setup failed: %d\n", ret);

	omapl138_lcdk_i2c_init();
	omapl138_lcdk_sound_init();

	ret = da850_register_sata(LCDKBOARD_SATA_REFCLKPN_RATE);
	if (ret)
		pr_warning("omapl138_lcdk_init: sata registration failed: %d\n",
				ret);

	ret = da850_register_pm(&da850_pm_device);
	if (ret)
		pr_warning("da850_evm_init: suspend registration failed: %d\n",
				ret);

	if (HAS_VPIF_DISPLAY || HAS_VPIF_CAPTURE) {
		ret = da850_register_vpif();
		if (ret)
			pr_warning("da850_evm_init: VPIF setup failed: %d\n",
				   ret);
	}

	if (HAS_VPIF_CAPTURE) {
		ret = davinci_cfg_reg_list(da850_vpif_capture_pins);
		if (ret)
			pr_warning("da850_evm_init: VPIF capture mux failed:"
					"%d\n", ret);

		ret = da850_register_vpif_capture(&da850_vpif_capture_config);
		if (ret)
			pr_warning("da850_evm_init: VPIF capture setup failed:"
					"%d\n", ret);
	}

	if (HAS_VPIF_DISPLAY) {
		ret = davinci_cfg_reg_list(da850_vpif_display_pins);
		if (ret)
			pr_warning("da850_evm_init : VPIF capture mux failed :"
					"%d\n", ret);

		ret = da850_register_vpif_display(&da850_vpif_display_config);
		if (ret)
			pr_warning("da850_evm_init: VPIF display setup failed:"
					"%d\n", ret);
	}


	omapl138_lcdk_led_init();
	omapl138_lcdk_keys_init();
	omapl138_lcdk_nand_init();
	omapl138_lcdk_display_init();
}

#ifdef CONFIG_SERIAL_8250_CONSOLE
static int __init omapl138_lcdk_console_init(void)
{
	if (!machine_is_omapl138_lcdkboard())
		return 0;

	return add_preferred_console("ttyS", 2, "115200");
}
console_initcall(omapl138_lcdk_console_init);
#endif

static void __init omapl138_lcdk_map_io(void)
{
	da850_init();
}

MACHINE_START(OMAPL138_LCDKBOARD, "AM18x/OMAP-L138 lcdk board")
	.atag_offset	= 0x100,
	.map_io		= omapl138_lcdk_map_io,
	.init_irq	= cp_intc_init,
	.timer		= &davinci_timer,
	.init_machine	= omapl138_lcdk_init,
	.dma_zone_size	= SZ_128M,
	.restart	= da8xx_restart,
MACHINE_END
vpif.c
/*
 * vpif - Video Port Interface driver
 * VPIF is a receiver and transmitter for video data. It has two channels(0, 1)
 * that receiveing video byte stream and two channels(2, 3) for video output.
 * The hardware supports SDTV, HDTV formats, raw data capture.
 * Currently, the driver supports NTSC and PAL standards.
 *
 * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation version 2.
 *
 * This program is distributed .as is. WITHOUT ANY WARRANTY of any
 * kind, whether express or implied; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <mach/hardware.h>
#include <linux/uaccess.h>
#include <linux/proc_fs.h>

#include "vpif.h"

MODULE_DESCRIPTION("TI DaVinci Video Port Interface driver");
MODULE_LICENSE("GPL");

#define VPIF_CH0_MAX_MODES	(22)
#define VPIF_CH1_MAX_MODES	(02)
#define VPIF_CH2_MAX_MODES	(15)
#define VPIF_CH3_MAX_MODES	(02)

static resource_size_t	res_len;
static struct resource	*res;
spinlock_t vpif_lock;

void __iomem *vpif_base;
struct clk *vpif_clk;

/**
 * ch_params: video standard configuration parameters for vpif
 * The table must include all presets from supported subdevices.
 */
const struct vpif_channel_config_params ch_params[] = {
	/* raw bayer Camera standars */
	{
		.name = "CAMERA",
		.width = 640,
		.height = 480,
		.frm_fmt = 1,
		.ycmux_mode = 0,
		.eav2sav = 0,
		.sav2eav = 0,
		.l1 = 0,
		.l3 = 0,
		.l5 = 0,
		.l7 = 0,
		.l9 = 0,
		.l11 = 0,
		.vsize = 0,
		.capture_format = 1,
		.vbi_supported = 0,
		.hd_sd = 0,
		.stdid = V4L2_STD_BAYER_640,
	},
	{
		.name = "CAMERA",
		.width = 1024,
		.height = 768,
		.frm_fmt = 1,
		.ycmux_mode = 0,
		.eav2sav = 0,
		.sav2eav = 0,
		.l1 = 0,
		.l3 = 0,
		.l5 = 0,
		.l7 = 0,
		.l9 = 0,
		.l11 = 0,
		.vsize = 0,
		.capture_format = 1,
		.vbi_supported = 0,
		.hd_sd = 0,
		.stdid = V4L2_STD_BAYER_1024,
	},
	{
		.name = "CAMERA",
		.width = 1280,
		.height = 1024,
		.frm_fmt = 1,
		.ycmux_mode = 0,
		.eav2sav = 0,
		.sav2eav = 0,
		.l1 = 0,
		.l3 = 0,
		.l5 = 0,
		.l7 = 0,
		.l9 = 0,
		.l11 = 0,
		.vsize = 0,
		.capture_format = 1,
		.vbi_supported = 0,
		.hd_sd = 0,
		.stdid = V4L2_STD_BAYER_1280,
	},
	{
		.name = "CAMERA",
		.width = 1600,
		.height = 1200,
		.frm_fmt = 1,
		.ycmux_mode = 0,
		.eav2sav = 0,
		.sav2eav = 0,
		.l1 = 0,
		.l3 = 0,
		.l5 = 0,
		.l7 = 0,
		.l9 = 0,
		.l11 = 0,
		.vsize = 0,
		.capture_format = 1,
		.vbi_supported = 0,
		.hd_sd = 0,
		.stdid = V4L2_STD_BAYER_1600,
	},
	{
		.name = "CAMERA",
		.width = 2048,
		.height = 1536,
		.frm_fmt = 1,
		.ycmux_mode = 0,
		.eav2sav = 0,
		.sav2eav = 0,
		.l1 = 0,
		.l3 = 0,
		.l5 = 0,
		.l7 = 0,
		.l9 = 0,
		.l11 = 0,
		.vsize = 0,
		.capture_format = 1,
		.vbi_supported = 0,
		.hd_sd = 0,
		.stdid = V4L2_STD_BAYER_2048,
	},
	{
		.name = "CAMERA",
		.width = 1920,
		.height = 1080,
		.frm_fmt = 1,
		.ycmux_mode = 0,
		.eav2sav = 0,
		.sav2eav = 0,
		.l1 = 0,
		.l3 = 0,
		.l5 = 0,
		.l7 = 0,
		.l9 = 0,
		.l11 = 0,
		.vsize = 0,
		.capture_format = 1,
		.vbi_supported = 0,
		.hd_sd = 0,
		.stdid = V4L2_STD_BAYER_1920,
	},
	{
		.name = "CAMERA",
		.width = 1280,
		.height = 720,
		.frm_fmt = 1,
		.ycmux_mode = 0,
		.eav2sav = 0,
		.sav2eav = 0,
		.l1 = 0,
		.l3 = 0,
		.l5 = 0,
		.l7 = 0,
		.l9 = 0,
		.l11 = 0,
		.vsize = 0,
		.capture_format = 1,
		.vbi_supported = 0,
		.hd_sd = 0,
		.stdid = V4L2_STD_BAYER_720,
	},
	/* HDTV formats */
	{
		.name = "480p59_94",
		.width = 720,
		.height = 480,
		.frm_fmt = 1,
		.ycmux_mode = 0,
		.eav2sav = 138-8,
		.sav2eav = 720,
		.l1 = 1,
		.l3 = 43,
		.l5 = 523,
		.vsize = 525,
		.capture_format = 0,
		.vbi_supported = 0,
		.hd_sd = 1,
		.dv_preset = V4L2_DV_480P59_94,
	},
	{
		.name = "576p50",
		.width = 720,
		.height = 576,
		.frm_fmt = 1,
		.ycmux_mode = 0,
		.eav2sav = 144-8,
		.sav2eav = 720,
		.l1 = 1,
		.l3 = 45,
		.l5 = 621,
		.vsize = 625,
		.capture_format = 0,
		.vbi_supported = 0,
		.hd_sd = 1,
		.dv_preset = V4L2_DV_576P50,
	},
	{
		.name = "720p50",
		.width = 1280,
		.height = 720,
		.frm_fmt = 1,
		.ycmux_mode = 0,
		.eav2sav = 700-8,
		.sav2eav = 1280,
		.l1 = 1,
		.l3 = 26,
		.l5 = 746,
		.vsize = 750,
		.capture_format = 0,
		.vbi_supported = 0,
		.hd_sd = 1,
		.dv_preset = V4L2_DV_720P50,
	},
	{
		.name = "720p60",
		.width = 1280,
		.height = 720,
		.frm_fmt = 1,
		.ycmux_mode = 0,
		.eav2sav = 370 - 8,
		.sav2eav = 1280,
		.l1 = 1,
		.l3 = 26,
		.l5 = 746,
		.vsize = 750,
		.capture_format = 0,
		.vbi_supported = 0,
		.hd_sd = 1,
		.dv_preset = V4L2_DV_720P60,
	},
	{
		.name = "1080I50",
		.width = 1920,
		.height = 1080,
		.frm_fmt = 0,
		.ycmux_mode = 0,
		.eav2sav = 720 - 8,
		.sav2eav = 1920,
		.l1 = 1,
		.l3 = 21,
		.l5 = 561,
		.l7 = 563,
		.l9 = 584,
		.l11 = 1124,
		.vsize = 1125,
		.capture_format = 0,
		.vbi_supported = 0,
		.hd_sd = 1,
		.dv_preset = V4L2_DV_1080I50,
	},
	{
		.name = "1080I60",
		.width = 1920,
		.height = 1080,
		.frm_fmt = 0,
		.ycmux_mode = 0,
		.eav2sav = 280 - 8,
		.sav2eav = 1920,
		.l1 = 1,
		.l3 = 21,
		.l5 = 561,
		.l7 = 563,
		.l9 = 584,
		.l11 = 1124,
		.vsize = 1125,
		.capture_format = 0,
		.vbi_supported = 0,
		.hd_sd = 1,
		.dv_preset = V4L2_DV_1080I60,
	},
	{
		.name = "1080p60",
		.width = 1920,
		.height = 1080,
		.frm_fmt = 1,
		.ycmux_mode = 0,
		.eav2sav = 280 - 8,
		.sav2eav = 1920,
		.l1 = 1,
		.l3 = 42,
		.l5 = 1122,
		.vsize = 1125,
		.capture_format = 0,
		.vbi_supported = 0,
		.hd_sd = 1,
		.dv_preset = V4L2_DV_1080P60,
	},

	/* SDTV formats */
	{
		.name = "NTSC_M",
		.width = 720,
		.height = 480,
		.frm_fmt = 0,
		.ycmux_mode = 1,
		.eav2sav = 268,
		.sav2eav = 1440,
		.l1 = 1,
		.l3 = 23,
		.l5 = 263,
		.l7 = 266,
		.l9 = 286,
		.l11 = 525,
		.vsize = 525,
		.capture_format = 0,
		.vbi_supported = 1,
		.hd_sd = 0,
		.stdid = V4L2_STD_525_60,
	},
	{
		.name = "PAL_BDGHIK",
		.width = 720,
		.height = 576,
		.frm_fmt = 0,
		.ycmux_mode = 1,
		.eav2sav = 280,
		.sav2eav = 1440,
		.l1 = 1,
		.l3 = 23,
		.l5 = 311,
		.l7 = 313,
		.l9 = 336,
		.l11 = 624,
		.vsize = 625,
		.capture_format = 0,
		.vbi_supported = 1,
		.hd_sd = 0,
		.stdid = V4L2_STD_625_50,
	},
};

const unsigned int vpif_ch_params_count = ARRAY_SIZE(ch_params);

static inline void vpif_wr_bit(u32 reg, u32 bit, u32 val)
{
	if (val)
		vpif_set_bit(reg, bit);
	else
		vpif_clr_bit(reg, bit);
}

/* This structure is used to keep track of VPIF size register's offsets */
struct vpif_registers {
	u32 h_cfg, v_cfg_00, v_cfg_01, v_cfg_02, v_cfg, ch_ctrl;
	u32 line_offset, vanc0_strt, vanc0_size, vanc1_strt;
	u32 vanc1_size, width_mask, len_mask;
	u8 max_modes;
};

static const struct vpif_registers vpifregs[VPIF_NUM_CHANNELS] = {
	/* Channel0 */
	{
		VPIF_CH0_H_CFG, VPIF_CH0_V_CFG_00, VPIF_CH0_V_CFG_01,
		VPIF_CH0_V_CFG_02, VPIF_CH0_V_CFG_03, VPIF_CH0_CTRL,
		VPIF_CH0_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF,
		VPIF_CH0_MAX_MODES,
	},
	/* Channel1 */
	{
		VPIF_CH1_H_CFG, VPIF_CH1_V_CFG_00, VPIF_CH1_V_CFG_01,
		VPIF_CH1_V_CFG_02, VPIF_CH1_V_CFG_03, VPIF_CH1_CTRL,
		VPIF_CH1_IMG_ADD_OFST, 0, 0, 0, 0, 0x1FFF, 0xFFF,
		VPIF_CH1_MAX_MODES,
	},
	/* Channel2 */
	{
		VPIF_CH2_H_CFG, VPIF_CH2_V_CFG_00, VPIF_CH2_V_CFG_01,
		VPIF_CH2_V_CFG_02, VPIF_CH2_V_CFG_03, VPIF_CH2_CTRL,
		VPIF_CH2_IMG_ADD_OFST, VPIF_CH2_VANC0_STRT, VPIF_CH2_VANC0_SIZE,
		VPIF_CH2_VANC1_STRT, VPIF_CH2_VANC1_SIZE, 0x7FF, 0x7FF,
		VPIF_CH2_MAX_MODES
	},
	/* Channel3 */
	{
		VPIF_CH3_H_CFG, VPIF_CH3_V_CFG_00, VPIF_CH3_V_CFG_01,
		VPIF_CH3_V_CFG_02, VPIF_CH3_V_CFG_03, VPIF_CH3_CTRL,
		VPIF_CH3_IMG_ADD_OFST, VPIF_CH3_VANC0_STRT, VPIF_CH3_VANC0_SIZE,
		VPIF_CH3_VANC1_STRT, VPIF_CH3_VANC1_SIZE, 0x7FF, 0x7FF,
		VPIF_CH3_MAX_MODES
	},
};

/* vpif_set_mode_info:
 * This function is used to set horizontal and vertical config parameters
 * As per the standard in the channel, configure the values of L1, L3,
 * L5, L7  L9, L11 in VPIF Register , also write width and height
 */
static void vpif_set_mode_info(const struct vpif_channel_config_params *config,
				u8 channel_id, u8 config_channel_id)
{
	u32 value;

	value = (config->eav2sav & vpifregs[config_channel_id].width_mask);
	value <<= VPIF_CH_LEN_SHIFT;
	value |= (config->sav2eav & vpifregs[config_channel_id].width_mask);
	regw(value, vpifregs[channel_id].h_cfg);

	value = (config->l1 & vpifregs[config_channel_id].len_mask);
	value <<= VPIF_CH_LEN_SHIFT;
	value |= (config->l3 & vpifregs[config_channel_id].len_mask);
	regw(value, vpifregs[channel_id].v_cfg_00);

	value = (config->l5 & vpifregs[config_channel_id].len_mask);
	value <<= VPIF_CH_LEN_SHIFT;
	value |= (config->l7 & vpifregs[config_channel_id].len_mask);
	regw(value, vpifregs[channel_id].v_cfg_01);

	value = (config->l9 & vpifregs[config_channel_id].len_mask);
	value <<= VPIF_CH_LEN_SHIFT;
	value |= (config->l11 & vpifregs[config_channel_id].len_mask);
	regw(value, vpifregs[channel_id].v_cfg_02);

	value = (config->vsize & vpifregs[config_channel_id].len_mask);
	regw(value, vpifregs[channel_id].v_cfg);
}

#if 0
#define DATA_IS_CAPTURED_ON_RISING_EDGE   0
#define DATE_BIT_WIDTH                    0     /*8-bit*/
#define INTLINE_INTERVAL                  0xFF
#define FIELD_ID_POLARITY_INVERT          0
#define VVINV_POLARITY_INVERT             0
#define HVINV_POLARITY_INVERT             0
#define INTFRAME                          2
#endif
#define DATE_BIT_WIDTH                    0x02     /*8-bit*/
#define INTLINE_INTERVAL                  0xFF

#define DATA_IS_CAPTURED_ON_RISING_EDGE   0
#define FIELD_ID_POLARITY_INVERT          0
#define VVINV_POLARITY_INVERT             0
#define HVINV_POLARITY_INVERT             0

#define INTFRAME                          0



/* config_vpif_params
 * Function to set the parameters of a channel
 * Mainly modifies the channel ciontrol register
 * It sets frame format, yc mux mode
 */
static void config_vpif_params(struct vpif_params *vpifparams,
				u8 channel_id, u8 found)
{
	const struct vpif_channel_config_params *config = &vpifparams->std_info;
	u32 value, ch_nip, reg;
	u8 start, end;
	int i;

	start = channel_id;
	end = channel_id + found;

	vpifparams->params.data_sz = DATE_BIT_WIDTH;//0x02;//12-bits/pixel

	for (i = start; i < end; i++) {
		reg = vpifregs[i].ch_ctrl;
		if (channel_id < 2)
			ch_nip = VPIF_CAPTURE_CH_NIP;
		else
			ch_nip = VPIF_DISPLAY_CH_NIP;


		vpif_wr_bit(reg, ch_nip, config->frm_fmt);
		vpif_wr_bit(reg, VPIF_CH_YC_MUX_BIT, config->ycmux_mode);
		vpif_wr_bit(reg, VPIF_CH_INPUT_FIELD_FRAME_BIT,
					vpifparams->video_params.storage_mode);

		/* Set raster scanning SDR Format */
		vpif_clr_bit(reg, VPIF_CH_SDR_FMT_BIT);
		vpif_wr_bit(reg, VPIF_CH_DATA_MODE_BIT, config->capture_format);

		if (channel_id > 1)	/* Set the Pixel enable bit */
			vpif_set_bit(reg, VPIF_DISPLAY_PIX_EN_BIT);
		else if (config->capture_format) {
			/* Set the polarity of various pins */
			vpif_wr_bit(reg, VPIF_CH_FID_POLARITY_BIT,
					vpifparams->iface.fid_pol);
			vpif_wr_bit(reg, VPIF_CH_V_VALID_POLARITY_BIT,
					vpifparams->iface.vd_pol);
			vpif_wr_bit(reg, VPIF_CH_H_VALID_POLARITY_BIT,
					vpifparams->iface.hd_pol);

			value = regr(reg);
			/* Set data width */
			value &= ~(((unsigned int)(0x3)) <<
					VPIF_CH_DATA_WIDTH_BIT);
			value |= ((vpifparams->params.data_sz) <<
						     VPIF_CH_DATA_WIDTH_BIT);
			regw(value, reg);
		}

		vpif_wr_bit(reg, 16, INTLINE_INTERVAL);
		vpif_wr_bit(reg, 17, INTLINE_INTERVAL);
		vpif_wr_bit(reg, 18, INTLINE_INTERVAL);
		vpif_wr_bit(reg, 19, INTLINE_INTERVAL);
		vpif_wr_bit(reg, 7, INTFRAME&0x02);
		vpif_wr_bit(reg, 6, INTFRAME&0x01);

		/* Write the pitch in the driver */
		regw((vpifparams->video_params.hpitch),
						vpifregs[i].line_offset);
	}

}

/* vpif_set_video_params
 * This function is used to set video parameters in VPIF register
 */
int vpif_set_video_params(struct vpif_params *vpifparams, u8 channel_id)
{
	const struct vpif_channel_config_params *config = &vpifparams->std_info;
	int found = 1;

	vpif_set_mode_info(config, channel_id, channel_id);
	if (!config->ycmux_mode) {
		/* YC are on separate channels (HDTV formats) */
		printk("YC are on separate channel\n");
		vpif_set_mode_info(config, channel_id + 1, channel_id);
		found = 2;
	}

	config_vpif_params(vpifparams, channel_id, found);

	regw(0x80, VPIF_REQ_SIZE);
	regw(0x01, VPIF_EMULATION_CTRL);

	return found;
}
EXPORT_SYMBOL(vpif_set_video_params);

void vpif_set_vbi_display_params(struct vpif_vbi_params *vbiparams,
				u8 channel_id)
{
	u32 value;

	value = 0x3F8 & (vbiparams->hstart0);
	value |= 0x3FFFFFF & ((vbiparams->vstart0) << 16);
	regw(value, vpifregs[channel_id].vanc0_strt);

	value = 0x3F8 & (vbiparams->hstart1);
	value |= 0x3FFFFFF & ((vbiparams->vstart1) << 16);
	regw(value, vpifregs[channel_id].vanc1_strt);

	value = 0x3F8 & (vbiparams->hsize0);
	value |= 0x3FFFFFF & ((vbiparams->vsize0) << 16);
	regw(value, vpifregs[channel_id].vanc0_size);

	value = 0x3F8 & (vbiparams->hsize1);
	value |= 0x3FFFFFF & ((vbiparams->vsize1) << 16);
	regw(value, vpifregs[channel_id].vanc1_size);

}
EXPORT_SYMBOL(vpif_set_vbi_display_params);

int vpif_channel_getfid(u8 channel_id)
{
	return (regr(vpifregs[channel_id].ch_ctrl) & VPIF_CH_FID_MASK)
					>> VPIF_CH_FID_SHIFT;
}
EXPORT_SYMBOL(vpif_channel_getfid);



int vpif_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data)
{
	count = 0;
	off=0;

	memset(page, 0, PAGE_SIZE);

	count = sprintf(page, "Help:\n"
			"\tcmd          value1(cmd id)\n"
			"\tstate         0          ---state info  :[id]\n"
			"\twrite reg     1          ---write reg   :[id off val]\n"
			"\tread  reg     2          ---read reg    :[id off]\n"
			);

	return count;

}

extern void __iomem *da8xx_syscfg0_base;

int vpif_proc_write(struct file *file, const char *buffer, unsigned long count, void *data)
{
	char buf[100];
	char *p = (char *)buf;
	unsigned long len = min((sizeof(buf)-1), (u32)count);
	unsigned long val[4]={0,0,0,0};
	char *end=NULL;
	int i=0, j=0;

	u32 reg_value;
	u8 reg_offset;
	u32 pinmuxbase;

	memset(buf, 0, sizeof(char)*100);

	if(copy_from_user(buf, buffer, len))
		return count;
	buf[len] = ' ';

	i=0;
	while(i++<len && j<4){
		if(*p==' '){
			p++;
			continue;
		}

		if(p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X'){
			p++;
			if(p[0] == 'x' || p[0] == 'X')
				p++;
			val[j++] = simple_strtoul(p, &end, 16);
			p = end;
		}else{
			val[j++] = simple_strtoul(p, &end, 10);
			p = end;
		}
	}
	printk("val[0]=0x%x, val[1]=0x%x, val[2]=0x%x, val[3]=0x%x\n\n", val[0], val[1], val[2], val[3]);

	switch(val[0]){
	case 0:
		
	case 1:
		reg_value  = val[1];
		reg_offset = val[2];
		regw(reg_value, reg_offset);
		break;
	case 2:
		reg_offset = val[1];
		reg_value  = regr(reg_offset);
		printk("read [0x%x] value is 0x%x\n", reg_offset, reg_value);
		break;

	case 3:
		printk("pinmux 15=0x%x\n", __raw_readl(da8xx_syscfg0_base + 0x120/4 + 15) );
		printk("pinmux 15=0x%x\n", __raw_readl(da8xx_syscfg0_base) );
		printk("pinmux 15=0x%x\n", __raw_readl(da8xx_syscfg0_base + 1) );
		printk("pinmux 15=0x%x\n", __raw_readl(da8xx_syscfg0_base + 2) );
		printk("pinmux 15=0x%x\n", __raw_readl(da8xx_syscfg0_base + 3) );
		printk("pinmux 15=0x%x\n", __raw_readl(da8xx_syscfg0_base + 4) );
		printk("pinmux 15=0x%x\n", __raw_readl(da8xx_syscfg0_base + 5) );
		printk("pinmux 15=0x%x\n", __raw_readl(da8xx_syscfg0_base + 6) );
		printk("pinmux 15=0x%x\n", __raw_readl(da8xx_syscfg0_base + 7) );
		printk("pinmux 15=0x%x\n", __raw_readl(da8xx_syscfg0_base + 8) );
		printk("pinmux 15=0x%x\n", __raw_readl(da8xx_syscfg0_base + 0x18) );
		printk("pinmux 15=0x%x\n", __raw_readl(da8xx_syscfg0_base + 0x15c) );
		break;

	default :
		break;
		
	}

	return len;
}


int vpif_proc_init()
{
	struct proc_dir_entry *proc_cmd;

	proc_cmd = create_proc_entry("vpif", S_IFREG | S_IRUGO, NULL);
	if (!proc_cmd) {
		printk("create_proc_entry: %s return failure \n", "vpif");
	}
	proc_cmd->write_proc = vpif_proc_write;
	proc_cmd->read_proc  = vpif_proc_read;

	return 0;
}


static int __init vpif_probe(struct platform_device *pdev)
{
	int status = 0;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res)
		return -ENOENT;

	res_len = resource_size(res);

	res = request_mem_region(res->start, res_len, res->name);
	if (!res)
		return -EBUSY;

	vpif_base = ioremap(res->start, res_len);
	if (!vpif_base) {
		status = -EBUSY;
		goto fail;
	}

	vpif_clk = clk_get(&pdev->dev, "vpif");
	if (IS_ERR(vpif_clk)) {
		status = PTR_ERR(vpif_clk);
		goto clk_fail;
	}
	clk_enable(vpif_clk);

	spin_lock_init(&vpif_lock);
	dev_info(&pdev->dev, "vpif probe success\n");

	vpif_proc_init();


	return 0;

clk_fail:
	iounmap(vpif_base);
fail:
	release_mem_region(res->start, res_len);
	return status;
}

static int __devexit vpif_remove(struct platform_device *pdev)
{
	if (vpif_clk) {
		clk_disable(vpif_clk);
		clk_put(vpif_clk);
	}

	iounmap(vpif_base);
	release_mem_region(res->start, res_len);
	return 0;
}

#ifdef CONFIG_PM
static int vpif_suspend(struct device *dev)
{
	clk_disable(vpif_clk);
	return 0;
}

static int vpif_resume(struct device *dev)
{
	clk_enable(vpif_clk);
	return 0;
}

static const struct dev_pm_ops vpif_pm = {
	.suspend        = vpif_suspend,
	.resume         = vpif_resume,
};

#define vpif_pm_ops (&vpif_pm)
#else
#define vpif_pm_ops NULL
#endif

static struct platform_driver vpif_driver = {
	.driver = {
		.name	= "vpif",
		.owner = THIS_MODULE,
		.pm	= vpif_pm_ops,
	},
	.remove = __devexit_p(vpif_remove),
	.probe = vpif_probe,
};

static void vpif_exit(void)
{
	platform_driver_unregister(&vpif_driver);
}

static int __init vpif_init(void)
{
	return platform_driver_register(&vpif_driver);
}
subsys_initcall(vpif_init);
module_exit(vpif_exit);

vpif_capture.c
vpif register configure.txt
reg[0x  0]=0x4c080a01  
reg[0x  4]=0x20011405  reg[0x  8]=0x     405  reg[0x  c]=0x       0  reg[0x 10]=0x       0  
reg[0x 14]=0x       0  reg[0x 18]=0x       0  reg[0x 1c]=0x       0  reg[0x 20]=0x      13  
reg[0x 24]=0x      13  reg[0x 28]=0x       0  reg[0x 2c]=0x       0  reg[0x 30]=0x       0  
reg[0x 34]=0x       1  reg[0x 38]=0x     100  reg[0x 3c]=0x       0  reg[0x 40]=0xc6400400  
reg[0x 44]=0xc6400e00  reg[0x 48]=0xc6400400  reg[0x 4c]=0xc6400e00  reg[0x 50]=0x       0  
reg[0x 54]=0x       0  reg[0x 58]=0x       0  reg[0x 5c]=0x       0  reg[0x 60]=0x       0  
reg[0x 64]=0x     a00  reg[0x 68]=0x       0  reg[0x 6c]=0x  640500  reg[0x 70]=0x       0  
reg[0x 74]=0x 2d00000  reg[0x 78]=0x       0  reg[0x 7c]=0x     2d0  reg[0x 80]=0xc6400400  
reg[0x 84]=0x       0  reg[0x 88]=0xc64e1400  reg[0x 8c]=0xc64e1e00  reg[0x 90]=0x       0  
reg[0x 94]=0x       0  reg[0x 98]=0x       0  reg[0x 9c]=0x       0  reg[0x a0]=0x       0  
reg[0x a4]=0x     a00  reg[0x a8]=0x       0  reg[0x ac]=0x       0  reg[0x b0]=0x       0  
reg[0x b4]=0x       0  reg[0x b8]=0x       0  reg[0x bc]=0x     2d0  reg[0x c0]=0x       0  
reg[0x c4]=0x       0  reg[0x c8]=0x       0  reg[0x cc]=0x       0  reg[0x d0]=0x       0  
reg[0x d4]=0x       0  reg[0x d8]=0x       0  reg[0x dc]=0x       0  reg[0x e0]=0x       0  
reg[0x e4]=0x       0  reg[0x e8]=0x       0  reg[0x ec]=0x       0  reg[0x f0]=0x       0  
reg[0x f4]=0x       0  reg[0x f8]=0x       0  reg[0x fc]=0x       0  reg[0x100]=0x       0  
reg[0x104]=0x       0  reg[0x108]=0x       0  reg[0x10c]=0x       0  reg[0x110]=0x       0  
reg[0x114]=0x       0  reg[0x118]=0x       0  reg[0x11c]=0x       0  reg[0x120]=0x       0  
reg[0x124]=0x       0  reg[0x128]=0x       0  reg[0x12c]=0x       0  reg[0x130]=0x       0  
reg[0x134]=0x       0  reg[0x138]=0x       0  reg[0x13c]=0x       0  reg[0x140]=0x       0  
reg[0x144]=0x       0  reg[0x148]=0x       0  reg[0x14c]=0x       0  reg[0x150]=0x       0  
reg[0x154]=0x       0  reg[0x158]=0x       0  reg[0x15c]=0x       0  reg[0x160]=0x       0  
reg[0x164]=0x       0  reg[0x168]=0x       0  reg[0x16c]=0x       0  reg[0x170]=0x       0  
reg[0x174]=0x       0  reg[0x178]=0x       0  reg[0x17c]=0x       0  reg[0x180]=0x       0  
reg[0x184]=0x       0  reg[0x188]=0x       0  reg[0x18c]=0x       0  reg[0x190]=0x       0  
reg[0x194]=0x       0  reg[0x198]=0x       0  reg[0x19c]=0x       0  
root@omapl138-lcdk:/proc# 

  • Hi Xiaowen Liu,

    For OMAPL138 LCDK, to demonstrate the interface with Sensor through VPIF, TI has released the sample driver code supporting the Leopard Imaging Camera Sensor. pleaese do have a look at those sources and check how interrupt signals are generated.

    The name of the package is OMAPL138_StarterWare_1_10_04_01 and after installtion of that package, the VPIF loop back example will be located under "ti\OMAPL138_StarterWare_1_10_04_01\examples\lcdkOMAPL138\vpif_lcd_loopback"

    Regards,

    Shankari

    -------------------------------------------------------------------------------------------------------

    Please click the Verify Answer button on this post if it answers your question.

    --------------------------------------------------------------------------------------------------------

  • Hi Shankari G.,

    The "ti\OMAPL138_StarterWare_1_10_04_01\examples\lcdkOMAPL138\vpif_lcd_loopback" is an example for image capture by composite, not RAW data capture mode. Thus, I reference the link
    processors.wiki.ti.com/.../OMAP-L138_running_Linux

    I thought this is a VPIF RAW data capture example. Am I right?
  • Hi Liu,

    The application does raw capture & later converts it YUV format from user space (as the omapl138 has no hardware support to do it.)

    Thanks,
    --Prabhakar Lad
  • Hi Xiaowen,

    Thanks for your post.

    It is for sure VPIFIsr is called through "SetupIntc()" which configures the DSP interrupt controller in which "VPIFIsr" is registered to DSP maskable interrupt vector table as below:

    /* Register VPIF ISR to vector table */

       IntRegister(C674X_MASK_INT5, VPIFIsr);

    If you check the main() function, it initializes the DSP INTC through SetupIntc(), please check the "VPIF_lcd_loopback.c" source code targetted for LCDK from the OMAPL138 starterware package.

    As Prabhakar said in his post, that the loopback application code does supports raw data capture which initializes the TVP5147 to accept composite video and later, it calls the color space conversion routine "cbcr422sp_to_rgb565_c()" which does colorspace conversion from YCbCr422 semi-planar to RGB565 planar and used by DSP core. Please refer the "cbcr422sp_to_rgb565_dsp.c" source file for the same.

    Please keep breakpoint inside 'VPIFIsr()" and ensure it enters the VPIF interrupt as well check whether the DSP interupt controller registers VPIF ISR to the  interrupt vector table.

    After installing OMAPL138 starterware package, please refer the below path for the VPIF loopback example source files and CCS project path:

    ~\ti\OMAPL138_StarterWare_1_10_04_01\examples\lcdkOMAPL138\vpif_lcd_loopback

    ~\ti\OMAPL138_StarterWare_1_10_04_01\build\c674x\cgt_ccs\omapl138\lcdkOMAPL138\vpif_lcd_loopback

    Thanks & regards,

    Sivaraj K

    -------------------------------------------------------------------------------------------------------

    Please click the Verify Answer button on this post if it answers your question.

    -------------------------------------------------------------------------------------------------------

  • Hi Xiaowen Liu,
    What software are you using ?
    Is starterware or Linux ?

    I presume that you are using linux OS and will check your VPIF register settings.

    Also I presume that you've connected your CMOS camera on J16 connector, please correct me if I'm wrong.

    Just put one printk in "vpif_channel_isr" function (vpif_capture.c) to know whether the VPIF's ISR get called or not.
  • Hi Titus,
    You are correct. We use Linux and connect Leopard camera with J16 connector. I will follow your suggestions and check the interrupt signals. Really appreciated Sivaraj and Titus's help.