Commit c92b67fa authored by Jean-Paul Saman's avatar Jean-Paul Saman

Neuros OSD2 board's tvp7000 video decoder driver (WIP)

parent 83d25e2d
......@@ -28,7 +28,14 @@
#include <linux/mtd/partitions.h>
#include <linux/clk.h>
#include <linux/videodev2.h>
#ifdef CONFIG_VIDEO_TVP5150
#include <media/tvp5150.h>
#endif
#ifdef CONFIG_VIDEO_TVP7000
#include <media/tvp7000.h>
#endif
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
......@@ -212,7 +219,7 @@ static struct v4l2_input tvp5150_inputs[] = {
#endif
#ifdef CONFIG_VIDEO_TVP7000
static struct v4l2_input tvp7000_inputs[] = {
static struct vl42_input tvp7000_inputs[] = {
{
.index = 0,
.name = "Component",
......@@ -255,6 +262,7 @@ static struct vpfe_route tvp7000_routes[] = {
};
#endif
#if defined(CONFIG_VIDEO_TVP5150) || defined(CONFIG_VIDEO_TVP7000)
static struct vpfe_subdev_info ntosd2_vpfe_sub_devs[] = {
#ifdef CONFIG_VIDEO_TVP5150
{
......@@ -289,7 +297,7 @@ static struct vpfe_subdev_info ntosd2_vpfe_sub_devs[] = {
.vdpol = VPFE_PINPOL_POSITIVE,
},
.board_info = {
I2C_BOARD_INFO("tvp7000", 0x5c), // 0xfa
I2C_BOARD_INFO("tvp7000", 0xfa), // 0x5c
.platform_data = NULL, // &tvp7000_pdata,
},
},
......@@ -302,6 +310,7 @@ static struct vpfe_config ntosd2_vpfe_cfg = {
.card_name = "DM6446 EVM",
.ccdc = "DM6446 CCDC",
};
#endif
static struct platform_device *davinci_ntosd2_devices[] __initdata = {
&davinci_fb_device,
......@@ -331,7 +340,7 @@ static struct i2c_board_info __initdata ntosd2_i2c_info[] = {
I2C_BOARD_INFO("neuros_osd2_msp", NTOSD2_MSP430_I2C_ADDR),
},
{
I2C_BOARD_INFO("tlv320aic3x", NTOSD2_AUDIOSOC_I2C_ADDR ),
I2C_BOARD_INFO("tlv320aic3x", NTOSD2_AUDIOSOC_I2C_ADDR),
},
};
......
......@@ -392,6 +392,15 @@ config VIDEO_TVP5150
To compile this driver as a module, choose M here: the
module will be called tvp5150.
config VIDEO_TVP7000
tristate "Texas Instruments TVP7000 video capture driver"
depends on VIDEO_V4L2 && I2C
---help---
Support for I2C bus based TVP7000 configuration.
To compile this driver as a module, choose M here: the
module will be called tvp7000.
config VIDEO_VPX3220
tristate "vpx3220a, vpx3216b & vpx3214c video decoders"
depends on VIDEO_V4L2 && I2C
......
......@@ -54,6 +54,7 @@ obj-$(CONFIG_VIDEO_BT866) += bt866.o
obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
obj-$(CONFIG_VIDEO_THS7303) += ths7303.o
obj-$(CONFIG_VIDEO_VINO) += indycam.o
obj-$(CONFIG_VIDEO_TVP7000) += tvp7000.o
obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
......
/*
* Copyright(C) 2006-2008 Neuros Technology International LLC.
* <www.neurostechnology.com>
* Copyright(C) 2009 M2X BV
* Jean-Paul Saman <jean-paul.saman@m2x.nl>
*
* 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 of the License.
*
* This program is distributed in the hope that, in addition to its
* original purpose to support Neuros hardware, it will be useful
* otherwise, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
****************************************************************************
*
* tvp7000 driver.
*
*/
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
#include <media/tvp7000.h>
#include <mach/gpio.h>
#include "tvp7000_regs.h"
#define I2C_RETRY_COUNT 5
#define INIT_DEFAULT 0
/* Debug functions */
static int debug;
module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
MODULE_DESCRIPTION("Texas Instruments TVP7000 video decoder driver");
MODULE_AUTHOR("Neuros Technology LLC");
MODULE_LICENSE("GPL");
static const struct tvp7000_reg tvp7000_init_reg_seq[] = {
{ /* 0x01 */TOK_WRITE, TVP7000_PLL_DIVIDE_MSB, 0x6b },
{ /* 0x02 */TOK_WRITE, TVP7000_PLL_DIVIDE_LSB, 0x40 },
{ /* 0x03 */TOK_WRITE, TVP7000_PLL_CTRL, 0x68 },
{ /* 0x04 */TOK_WRITE, TVP7000_PHASE_SELECT, 0xb1 },
{ /* 0x05 */TOK_WRITE, TVP7000_CLAMP_START, 0x06 },
{ /* 0x06 */TOK_WRITE, TVP7000_CLAMP_WIDTH, 0x10 },
{ /* 0x07 */TOK_WRITE, TVP7000_HSYNC_OUTPUT_WIDTH, 0x60 },
{ /* 0x08 */TOK_WRITE, TVP7000_BLUE_FINE_GAIN, 0x80 },
{ /* 0x09 */TOK_WRITE, TVP7000_GREEN_FINE_GAIN, 0x80 },
{ /* 0x0A */TOK_WRITE, TVP7000_RED_FINE_GAIN, 0x80 },
{ /* 0x0B */TOK_WRITE, TVP7000_BLUE_FINE_OFFSET, 0x80 },
{ /* 0x0C */TOK_WRITE, TVP7000_GREEN_FINE_OFFSET, 0x80 },
{ /* 0x0D */TOK_WRITE, TVP7000_RED_FINE_OFFSET, 0x80 },
{ /* 0x0E */TOK_WRITE, TVP7000_SYNC_CTRL_1, 0x20 },
{ /* 0x0F */TOK_WRITE, TVP7000_PLL_CLAMP_CTRL, 0x2E },
{ /* 0x10 */TOK_WRITE, TVP7000_SYNC_ON_GREEN, 0x85 },
{ /* 0x11 */TOK_WRITE, TVP7000_SYNC_SEPARATOR, 0x47 },
{ /* 0x12 */TOK_WRITE, TVP7000_PRE_COAST, 0x03 },
{ /* 0x13 */TOK_WRITE, TVP7000_POST_COAST, 0x0c },
{ /* 0x15 */TOK_WRITE, TVP7000_OUTPUT_FORMATTER, 0x02 },
{ /* 0x16 */TOK_WRITE, TVP7000_TEST_REG, 0xe5 },
{ /* 0x19 */TOK_WRITE, TVP7000_INPUT_MUX_1, 0x00 },
{ /* 0x1A */TOK_WRITE, TVP7000_INPUT_MUX_2, 0x85 },
{ /* 0x1B */TOK_WRITE, TVP7000_BLUE_GREEN_GAIN, 0x55 },
{ /* 0x1C */TOK_WRITE, TVP7000_RED_COARSE_GAIN, 0x05 },
{ /* 0x1D */TOK_WRITE, TVP7000_FINE_OFFSET_LSB, 0x00 },
{ /* 0x1E */TOK_WRITE, TVP7000_BLUE_COARSE_OFFSET, 0x1f },
{ /* 0x1F */TOK_WRITE, TVP7000_GREEN_COARSE_OFFSET, 0x1f },
{ /* 0x20 */TOK_WRITE, TVP7000_RED_COARSE_OFFSET, 0x1f },
{ /* 0x21 */TOK_WRITE, TVP7000_HSOUT_OUTPUT_START, 0x08 },
{ /* 0x22 */TOK_WRITE, TVP7000_MISC_CTRL, 0x08 },
{ /* 0x26 */TOK_WRITE, TVP7000_AUTO_CTRL_ENABLE, 0x80 },
{ /* 0x28 */TOK_WRITE, TVP7000_AUTO_CTRL_FILTER, 0x03 },
{ /* 0x2A */TOK_WRITE, TVP7000_FINE_CLAMP_CTRL, 0x07 },
{ /* 0x2B */TOK_WRITE, TVP7000_POWER_CTRL, 0x00 },
{ /* 0x2C */TOK_WRITE, TVP7000_ADC_SETUP, 0x50 },
{ /* 0x2D */TOK_WRITE, TVP7000_COARSE_CLAMP_CTRL_1, 0x00 },
{ /* 0x2E */TOK_WRITE, TVP7000_SOG_CLAMP, 0x80 },
{ /* 0x31 */TOK_WRITE, TVP7000_ALC_PLACEMENT, 0x18 },
{ TOK_TERM, 0, 0 },
};
#if INIT_DEFAULT
static const struct tvp7000_reg tvp7000_init_reg_default[] = {
{ /* 0x01 */TOK_WRITE, TVP7000_PLL_DIVIDE_MSB, 0x69 },
{ /* 0x02 */TOK_WRITE, TVP7000_PLL_DIVIDE_LSB, 0xD0 },
{ /* 0x03 */TOK_WRITE, TVP7000_PLL_CTRL, 0x48 },
{ /* 0x04 */TOK_WRITE, TVP7000_PHASE_SELECT, 0x80 },
{ /* 0x05 */TOK_WRITE, TVP7000_CLAMP_START, 0x80 },
{ /* 0x06 */TOK_WRITE, TVP7000_CLAMP_WIDTH, 0x80 },
{ /* 0x07 */TOK_WRITE, TVP7000_HSYNC_OUTPUT_WIDTH, 0x20 },
{ /* 0x08 */TOK_WRITE, TVP7000_BLUE_FINE_GAIN, 0x80 },
{ /* 0x09 */TOK_WRITE, TVP7000_GREEN_FINE_GAIN, 0x80 },
{ /* 0x0A */TOK_WRITE, TVP7000_RED_FINE_GAIN, 0x80 },
{ /* 0x0B */TOK_WRITE, TVP7000_BLUE_FINE_OFFSET, 0x80 },
{ /* 0x0C */TOK_WRITE, TVP7000_GREEN_FINE_OFFSET, 0x80 },
{ /* 0x0D */TOK_WRITE, TVP7000_RED_FINE_OFFSET, 0x80 },
{ /* 0x0E */TOK_WRITE, TVP7000_SYNC_CTRL_1, 0x40 },
{ /* 0x0F */TOK_WRITE, TVP7000_PLL_CLAMP_CTRL, 0x4E },
{ /* 0x10 */TOK_WRITE, TVP7000_SYNC_ON_GREEN, 0xB8 },
{ /* 0x11 */TOK_WRITE, TVP7000_SYNC_SEPARATOR, 0x20 },
{ /* 0x12 */TOK_WRITE, TVP7000_PRE_COAST, 0x00 },
{ /* 0x13 */TOK_WRITE, TVP7000_POST_COAST, 0x00 },
{ /* 0x15 */TOK_WRITE, TVP7000_OUTPUT_FORMATTER, 0x00 },
{ /* 0x16 */TOK_WRITE, TVP7000_TEST_REG, 0x00 },
{ /* 0x19 */TOK_WRITE, TVP7000_INPUT_MUX_1, 0x00 },
{ /* 0x1A */TOK_WRITE, TVP7000_INPUT_MUX_2, 0x00 },
{ /* 0x1B */TOK_WRITE, TVP7000_BLUE_GREEN_GAIN, 0x55 },
{ /* 0x1C */TOK_WRITE, TVP7000_RED_COARSE_GAIN, 0x05 },
{ /* 0x1D */TOK_WRITE, TVP7000_FINE_OFFSET_LSB, 0x00 },
{ /* 0x1E */TOK_WRITE, TVP7000_BLUE_COARSE_OFFSET, 0x20 },
{ /* 0x1F */TOK_WRITE, TVP7000_GREEN_COARSE_OFFSET, 0x20 },
{ /* 0x20 */TOK_WRITE, TVP7000_RED_COARSE_OFFSET, 0x20 },
{ /* 0x21 */TOK_WRITE, TVP7000_HSOUT_OUTPUT_START, 0x09 },
{ /* 0x22 */TOK_WRITE, TVP7000_MISC_CTRL, 0x00 },
{ /* 0x26 */TOK_WRITE, TVP7000_AUTO_CTRL_ENABLE, 0x00 },
{ /* 0x28 */TOK_WRITE, TVP7000_AUTO_CTRL_FILTER, 0x00 },
{ /* 0x2A */TOK_WRITE, TVP7000_FINE_CLAMP_CTRL, 0x00 },
{ /* 0x2B */TOK_WRITE, TVP7000_POWER_CTRL, 0x00 },
{ /* 0x2C */TOK_WRITE, TVP7000_ADC_SETUP, 0x00 },
{ /* 0x2D */TOK_WRITE, TVP7000_COARSE_CLAMP_CTRL_1, 0x00 },
{ /* 0x2E */TOK_WRITE, TVP7000_SOG_CLAMP, 0x00 },
{ /* 0x31 */TOK_WRITE, TVP7000_ALC_PLACEMENT, 0x00 },
{ TOK_TERM, 0, 0 },
};
#endif
/* Video Standards */
enum tvp7000_std {
VGA60HZ = 0,
VGA72HZ,
VGA75HZ,
VGA85HZ,
SVGA56HZ,
SVGA60HZ,
SVGA72HZ,
SVGA75HZ,
SVGA85HZ,
XGA60HZ,
XGA70HZ,
XGA75HZ,
XGA85HZ,
SXGA60HZ,
SXGA75HZ,
VIDEO480P60HZ,
VIDEO576P50HZ,
VIDEO720P60HZ,
VIDEO720P50HZ,
VIDEO1080I60HZ,
VIDEO1080I50HZ,
VIDEO1080P60HZ,
VIDEO1080P50HZ,
/* invalid standard */
STD_INVALID,
};
/**
* struct tvp7000_std_info - Structure to store standard informations
* @width: Line width in pixels
* @height:Number of active lines
* @video_std: Value to write in REG_VIDEO_STD register
* @standard: v4l2 standard structure information
*/
struct tvp7000_std_info
{
u8 plldiv_msb;
u8 plldiv_lsb;
u8 pll_ctrl;
u8 phase_select_bit0;
u8 pre_coast;
u8 post_coast;
u8 clamp_start;
u8 clamp_width;
u8 alc_placement;
unsigned long width;
unsigned long height;
enum tvp7000_std video_std;
struct v4l2_standard standard;
};
/**
* List of image formats supported by TVP7000 decoder
* Currently we are using 8 bit mode only, but can be
* extended to 10/20 bit mode.
*/
static const struct v4l2_fmtdesc tvp7000_fmt_list[] = {
{
.index = 0,
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
.flags = 0,
.description = "8-bit UYVY 4:2:2 Format",
.pixelformat = V4L2_PIX_FMT_UYVY,
},
};
static struct tvp7000_std_info video_info[] = {
{ /* VGA standard: 640*480 resolution,60HZ refresh rate,
31.5kHZ Horizontal frequency,25.175MHZ pixel rate,
*/
.plldiv_msb = 0x64,
.plldiv_lsb = 0x00,
.pll_ctrl = 0x68,
.phase_select_bit0 = 0x01,
.width = 640,
.height = 480,
.video_std = VGA60HZ,
.standard = {
.index = 0,
.id = V4L2_STD_NTSC,
.name = "VGA60HZ",
.frameperiod = {1001, 60000},
.framelines = 640
},
},
{ /* VGA standard: 640*480 resolution,72HZ refresh rate,
37.9kHZ Horizontal frequency,31.5MHZ pixel rate,
*/
.plldiv_msb = 0x68,
.plldiv_lsb = 0x00,
.pll_ctrl = 0x58,
.phase_select_bit0 = 0x01,
.width = 640,
.height = 480,
.video_std = VGA72HZ,
.standard = {
.index = 1,
.id = V4L2_STD_NTSC,
.name = "VGA72HZ",
.frameperiod = {1001, 72000},
.framelines = 640
},
},
{ /* VGA standard: 640*480 resolution,75HZ refresh rate,
37.5kHZ Horizontal frequency,31.5MHZ pixel rate,
*/
.plldiv_msb = 0x69,
.plldiv_lsb = 0x00,
.pll_ctrl = 0x58,
.phase_select_bit0 = 0x01,
.width = 640,
.height = 480,
.video_std = VGA75HZ,
.standard = {
.index = 2,
.id = V4L2_STD_NTSC,
.name = "VGA75HZ",
.frameperiod = {1001, 75000},
.framelines = 640
},
},
{ /* VGA standard: 640*480 resolution,85HZ refresh rate,
43.3kHZ Horizontal frequency,36MHZ pixel rate,
*/
.plldiv_msb = 0x34,
.plldiv_lsb = 0x00,
.pll_ctrl = 0x68,
.phase_select_bit0 = 0x00,
.width = 640,
.height = 480,
.video_std = VGA85HZ,
.standard = {
.index = 3,
.id = V4L2_STD_NTSC,
.name = "VGA85HZ",
.frameperiod = {1001, 85000},
.framelines = 640
},
},
{ /* SVGA standard: 800*600 resolution,56HZ refresh rate,
35.1kHZ Horizontal frequency,36MHZ pixel rate,
*/
.plldiv_msb = 0x40,
.plldiv_lsb = 0x00,
.pll_ctrl = 0x68,
.phase_select_bit0 = 0x00,
.width = 800,
.height = 600,
.video_std = SVGA56HZ,
.standard = {
.index = 4,
.id = V4L2_STD_PAL,
.name = "SVGA56HZ",
.frameperiod = {1001, 56000},
.framelines = 800
},
},
{ /* SVGA standard: 800*600 resolution,60HZ refresh rate,
37.9kHZ Horizontal frequency,40MHZ pixel rate,
*/
.plldiv_msb = 0x42,
.plldiv_lsb = 0x00,
.pll_ctrl = 0x68,
.phase_select_bit0 = 0x00,
.width = 800,
.height = 600,
.video_std = SVGA60HZ,
.standard = {
.index = 5,
.id = V4L2_STD_PAL,
.name = "SVGA60HZ",
.frameperiod = {1001, 60000},
.framelines = 800
},
},
{ /* SVGA standard: 800*600 resolution,72HZ refresh rate,
48.1kHZ Horizontal frequency,50MHZ pixel rate,
*/
.plldiv_msb = 0x41,
.plldiv_lsb = 0x00,
.pll_ctrl = 0x68,
.phase_select_bit0 = 0x00,
.width = 800,
.height = 600,
.video_std = SVGA72HZ,
.standard = {
.index = 6,
.id = V4L2_STD_PAL,
.name = "SVGA72HZ",
.frameperiod = {1001, 72000},
.framelines = 800
},
},
{ /* SVGA standard: 800*600 resolution,75HZ refresh rate,
46.9kHZ Horizontal frequency,49.5MHZ pixel rate,
*/
.plldiv_msb = 0x42,
.plldiv_lsb = 0x00,
.pll_ctrl = 0x68,
.phase_select_bit0 = 0x00,
.width = 800,
.height = 600,
.video_std = SVGA75HZ,
.standard = {
.index = 7,
.id = V4L2_STD_PAL,
.name = "SVGA75HZ",
.frameperiod = {1001, 75000},
.framelines = 800
},
},
{ /* SVGA standard: 800*600 resolution,85HZ refresh rate,
53.7kHZ Horizontal frequency,56.25MHZ pixel rate,
*/
.plldiv_msb = 0x41,
.plldiv_lsb = 0x80,
.pll_ctrl = 0x68,
.phase_select_bit0 = 0x00,
.width = 800,
.height = 600,
.video_std = SVGA85HZ,
.standard = {
.index = 8,
.id = V4L2_STD_PAL,
.name = "SVGA85HZ",
.frameperiod = {1001, 85000},
.framelines = 800
},
},
{ /* XGA standard: 1024*768 resolution,60HZ refresh rate,
48.4kHZ Horizontal frequency,65MHZ pixel rate,
*/
.plldiv_msb = 0x54,
.plldiv_lsb = 0x00,
.pll_ctrl = 0x58,
.phase_select_bit0 = 0x00,
.width = 1024,
.height = 768,
.video_std = XGA60HZ,
.standard = {
.index = 9,
.id = V4L2_STD_HD_720P,
.name = "XGA60HZ",
.frameperiod = {1001, 60000},
.framelines = 1024
},
},
{ /* XGA standard: 1024*768 resolution,70HZ refresh rate,
56.5kHZ Horizontal frequency,75MHZ pixel rate,
*/
.plldiv_msb = 0x53,
.plldiv_lsb = 0x00,
.pll_ctrl = 0xA8,
.phase_select_bit0 = 0x00,
.width = 1024,
.height = 768,
.video_std = XGA70HZ,
.standard = {
.index = 10,
.id = V4L2_STD_HD_720P,
.name = "XGA70HZ",
.frameperiod = {1001, 70000},
.framelines = 1024
},
},
{ /* XGA standard: 1024*768 resolution,75HZ refresh rate,
60kHZ Horizontal frequency,78.75MHZ pixel rate,
*/
.plldiv_msb = 0x52,
.plldiv_lsb = 0x00,
.pll_ctrl = 0xA8,
.phase_select_bit0 = 0x00,
.width = 1024,
.height = 768,
.video_std = XGA75HZ,
.standard = {
.index = 11,
.id = V4L2_STD_HD_720P,
.name = "XGA75HZ",
.frameperiod = {1001, 75000},
.framelines = 1024
},
},
{ /* XGA standard: 1024*768 resolution,85HZ refresh rate,
68.7kHZ Horizontal frequency,94.5MHZ pixel rate,
*/
.plldiv_msb = 0x56,
.plldiv_lsb = 0x00,
.pll_ctrl = 0xA8,
.phase_select_bit0 = 0x00,
.width = 1024,
.height = 768,
.video_std = XGA85HZ,
.standard = {
.index = 12,
.id = V4L2_STD_HD_720P,
.name = "XGA85HZ",
.frameperiod = {1001, 85000},
.framelines = 1024
},
},
{ /* SXGA standard: 1280*1024 resolution,60HZ refresh rate,
64kHZ Horizontal frequency,108MHZ pixel rate,
*/
.plldiv_msb = 0x69,
.plldiv_lsb = 0x80,
.pll_ctrl = 0xA8,
.phase_select_bit0 = 0x00,
.width = 1280,
.height = 1024,
.video_std = SXGA60HZ,
.standard = {
.index = 13,
.id = V4L2_STD_HD_720P,
.name = "SXGA60HZ",
.frameperiod = {1001, 60000},
.framelines = 1024
},
},
{ /* SXGA standard: 1280*1024 resolution,75HZ refresh rate,
80kHZ Horizontal frequency,135MHZ pixel rate,
*/
.plldiv_msb = 0x69,
.plldiv_lsb = 0x80,
.pll_ctrl = 0x98,
.phase_select_bit0 = 0x00,
.width = 1280,
.height = 1024,
.video_std = SXGA75HZ,
.standard = {
.index = 14,
.id = V4L2_STD_HD_1080P,
.name = "SXGA75HZ",
.frameperiod = {1001, 60000},
.framelines = 1280
},
},
{ /* Video standard: 720*480p resolution,60HZ refresh rate,
31.468kHZ Horizontal frequency,27MHZ pixel rate.
*/
.plldiv_msb = 0x6B,
.plldiv_lsb = 0x40,
.pll_ctrl = 0x68,
.phase_select_bit0 = 0x01,
.pre_coast = 0x03,
.post_coast = 0x0c,
.clamp_start = 0x06,
.clamp_width = 0x10,
.alc_placement = 0x18,
.video_std = VIDEO480P60HZ,
.width = 720,
.height = 480,
.standard = {
.index = 15,
.id = V4L2_STD_HD_480P,
.name = "480P",
.frameperiod = {1001, 60000},
.framelines = 720
},
},
{ /* Video standard: 720*576p resolution,50HZ refresh rate,
31.25kHZ Horizontal frequency,27MHZ pixel rate.
*/
.plldiv_msb = 0x6C,
.plldiv_lsb = 0x00,
.pll_ctrl = 0x68,
.phase_select_bit0 = 0x01,
.pre_coast = 0x03,
.post_coast = 0x0c,
.clamp_start = 0x06,
.clamp_width = 0x10,
.alc_placement = 0x18,
.width = 720,
.height = 576,
.video_std = VIDEO576P50HZ,
.standard = {
.index = 16,
.id = V4L2_STD_HD_576P,
.name = "576P",
.frameperiod = {1001, 50000},
.framelines = 625
},
},
{ /* Video standard: 1280*720p resolution,60HZ refresh rate,
45kHZ Horizontal frequency,74.25MHZ pixel rate.
*/
.plldiv_msb = 0x67,
.plldiv_lsb = 0x20,
.pll_ctrl = 0xA8,
.phase_select_bit0 = 0x00,
.pre_coast = 0x0,
.post_coast = 0x0,
.clamp_start = 0x32,
.clamp_width = 0x20,
.alc_placement = 0x5a,
.width = 1280,
.height = 720,
.video_std = VIDEO720P60HZ,
.standard = {
.index = 17,
.id = V4L2_STD_HD_720P,
.name = "720P",
.frameperiod = {1001, 60000},
.framelines = 1185
},
},
{ /* Video standard: 1280*720p resolution,50HZ refresh rate,
37.5kHZ Horizontal frequency,74.25MHZ pixel rate.
*/
.plldiv_msb = 0x7B,
.plldiv_lsb = 0xC0,
.pll_ctrl = 0xA8,
.phase_select_bit0 = 0x00,
.pre_coast = 0x0,
.post_coast = 0x0,
.clamp_start = 0x32,
.clamp_width = 0x20,
.alc_placement = 0x5a,
.width = 1280,
.height = 720,
.video_std = VIDEO720P50HZ,
.standard = {
.index = 18,
.id = V4L2_STD_HD_720P,
.name = "720P",
.frameperiod = {1001, 50000},
.framelines = 1185
},
},
{ /* Video standard: 1920*1080i resolution,60HZ refresh rate,
33.75kHZ Horizontal frequency,74.25MHZ pixel rate.
*/
.plldiv_msb = 0x89,
.plldiv_lsb = 0x80,
.pll_ctrl = 0xA8,
.phase_select_bit0 = 0x00,
.pre_coast = 0x03,
.post_coast = 0x0,
.clamp_start = 0x32,
.clamp_width = 0x20,
.alc_placement = 0x5a,
.width = 1920,
.height = 1080,
.video_std = VIDEO1080I60HZ,
.standard = {
.index = 19,
.id = V4L2_STD_HD_1080I,
.name = "1080I",
.frameperiod = {1001, 60000},
.framelines = 1825
},
},
{ /* Video standard: 1920*1080i resolution,50HZ refresh rate,
28.125kHZ Horizontal frequency,74.25MHZ pixel rate.
*/
.plldiv_msb = 0xA5,
.plldiv_lsb = 0x00,
.pll_ctrl = 0xA8,
.phase_select_bit0 = 0x00,
.pre_coast = 0x03,
.post_coast = 0x0,
.clamp_start = 0x32,
.clamp_width = 0x20,
.alc_placement = 0x5a,
.width = 1920,
.height = 1080,
.video_std = VIDEO1080I50HZ,
.standard = {
.index = 20,
.id = V4L2_STD_HD_1080I,
.name = "1080I",
.frameperiod = {1001, 50000},
.framelines = 1825
},
},
#ifndef MACH_NEUROS_OSD2
{ /* Video standard: 1920*1080p resolution,60HZ refresh rate,
67.5kHZ Horizontal frequency,148.5MHZ pixel rate.
*/
.plldiv_msb = 0x89,
.plldiv_lsb = 0x80,
.pll_ctrl = 0xD8,
.phase_select_bit0 = 0x00,
.pre_coast = 0x0,
.post_coast = 0x0,
.clamp_start = 0x32,
.clamp_width = 0x20,
.alc_placement = 0x5a,
.width = 1920,
.height = 1080,
.video_std = VIDEO1080P60HZ,
.standard = {
.index = 21,
.id = V4L2_STD_HD_1080P,
.name = "1080P",
.frameperiod = {1001, 60000},
.framelines = 1825
},
},
{ /* Video standard: 1920*1080p resolution,50HZ refresh rate,
56.25kHZ Horizontal frequency,148.5MHZ pixel rate.
*/
.plldiv_msb = 0xA5,
.plldiv_lsb = 0x00,
.pll_ctrl = 0xD8,
.phase_select_bit0 = 0x00,
.pre_coast = 0x0,
.post_coast = 0x0,
.clamp_start = 0x32,
.clamp_width = 0x20,
.alc_placement = 0x5a,
.width = 1920,
.height = 1080,
.video_std = VIDEO1080P50HZ,
.standard = {
.index = 22,
.id = V4L2_STD_HD_1080P,
.name = "1080P",
.frameperiod = {1001, 50000},
.framelines = 1825
},
},
#endif
};
/**
* struct tvp7000_decoder - TVP7000 decoder object
* @sd: Subdevice Slave handle
* @tvp7000_regs: copy of hw's regs with preset values.
* @pdata: Board specific
* @ver: Chip version
* @streaming: TVP7000 decoder streaming - enabled or disabled.
* @pix: Current pixel format
* @num_fmts: Number of formats
* @fmt_list: Format list
* @current_std: Current standard
* @num_stds: Number of standards
* @std_list: Standards list
* @input: Input routing at chip level
* @output: Output routing at chip level
*/
struct tvp7000_decoder {
struct v4l2_subdev sd;
struct tvp7000_reg tvp7000_regs[ARRAY_SIZE(tvp7000_init_reg_seq)];
const struct tvp7000_platform_data *pdata;
int ver;
int streaming;
struct v4l2_pix_format pix;
int num_fmts;
const struct v4l2_fmtdesc *fmt_list;
enum tvp7000_std current_std;
int num_stds;
struct tvp7000_std_info *std_list;
/* Input and Output Routing parameters */
u32 input;
u32 output;
};
static inline struct tvp7000_decoder *to_decoder(struct v4l2_subdev *sd)
{
return container_of(sd, struct tvp7000_decoder, sd);
}
/**
* tvp7000_read_reg() - Read a value from a register in an TVP7000.
* @sd: ptr to v4l2_subdev struct
* @reg: TVP7000 register address
*
* Returns value read if successful, or non-zero (-1) otherwise.
*/
static int tvp7000_read_reg(struct v4l2_subdev *sd, u8 reg)
{
int err, retry = 0;
struct i2c_client *client = v4l2_get_subdevdata(sd);
read_again:
err = i2c_smbus_read_byte_data(client, reg);
if (err == -1) {
if (retry <= I2C_RETRY_COUNT) {
v4l2_warn(sd, "Read: retry ... %d\n", retry);
retry++;
msleep_interruptible(10);
goto read_again;
}
}
return err;
}
/**
* dump_reg() - dump the register content of TVP7000.
* @sd: ptr to v4l2_subdev struct
* @reg: TVP7000 register address
*/
static void dump_reg(struct v4l2_subdev *sd, u8 reg)
{
u32 val;
val = tvp7000_read_reg(sd, reg);
v4l2_info(sd, "Reg(0x%.2X): 0x%.2X\n", reg, val);
}
/**
* tvp7000_write_reg() - Write a value to a register in TVP7000
* @sd: ptr to v4l2_subdev struct
* @reg: TVP7000 register address
* @val: value to be written to the register
*
* Write a value to a register in an TVP7000 decoder device.
* Returns zero if successful, or non-zero otherwise.
*/
static int tvp7000_write_reg(struct v4l2_subdev *sd, u8 reg, u8 val)
{
int err, retry = 0;
struct i2c_client *client = v4l2_get_subdevdata(sd);
write_again:
err = i2c_smbus_write_byte_data(client, reg, val);
if (err) {
if (retry <= I2C_RETRY_COUNT) {
v4l2_warn(sd, "Write: retry ... %d\n", retry);
retry++;
msleep_interruptible(10);
goto write_again;
}
}
return err;
}
static void tvp7000_device_power_on(bool on)
{
#define HD_CAP_GPIO GPIO(39)
s8 level = (on == true) ? 0 : 1;
/* enable the GPIO(39) direction mode as output */
gpio_direction_output(HD_CAP_GPIO, level);
/* when on == true */
/* set the Reset pin level as High for 5ms */
gpio_set_value(HD_CAP_GPIO, level);
mdelay(5);
/* pull down the Reset pin level for 5us,
reset the chip(Reset pin active in low) */
gpio_set_value(HD_CAP_GPIO, !level);
udelay(5);
/* pull up the Reset pin and delay for 5us,
now,tvp7000 is power up */
gpio_set_value(HD_CAP_GPIO, level);
udelay(5);
#undef HD_CAP_GPIO
}
static int tvp7000_setup_video_standard(struct v4l2_subdev *sd, const struct tvp7000_std_info *std)
{
int err = 0;
int val;
if (std == NULL)
return -EINVAL;
err |= tvp7000_write_reg(sd, TVP7000_PLL_DIVIDE_MSB, std->plldiv_msb);
err |= tvp7000_write_reg(sd, TVP7000_PLL_DIVIDE_LSB, std->plldiv_lsb);
err |= tvp7000_write_reg(sd, TVP7000_PLL_CTRL, std->pll_ctrl);
val = tvp7000_read_reg(sd, TVP7000_PHASE_SELECT);
val &= ~0x01;
err |= tvp7000_write_reg(sd, TVP7000_PHASE_SELECT, (std->phase_select_bit0 & 0x01) | val);
err |= tvp7000_write_reg(sd, TVP7000_PRE_COAST, std->pre_coast);
err |= tvp7000_write_reg(sd, TVP7000_POST_COAST, std->post_coast);
err |= tvp7000_write_reg(sd, TVP7000_CLAMP_START, std->clamp_start);
err |= tvp7000_write_reg(sd, TVP7000_CLAMP_WIDTH, std->clamp_width);
err |= tvp7000_write_reg(sd, TVP7000_ALC_PLACEMENT, std->alc_placement);
return err;
}
static inline int tvp7000_selmux(struct v4l2_subdev *sd)
{
if (tvp7000_write_reg(sd, TVP7000_INPUT_MUX_1, 0)) // set channel 1
return -1;
return 0;
}
static int input_signal_exist(struct v4l2_subdev *sd)
{
int val;
val = tvp7000_read_reg(sd, TVP7000_SYNC_DETECT_STATUS);
if ((val & 0x80) && (val & 0x10))
return 0;
return -1;
}
/**
* tvp7000_write_regs() : Initializes a list of TVP7000 registers
* @sd: ptr to v4l2_subdev struct
* @reglist: list of TVP7000 registers and values
*
* Initializes a list of TVP7000 registers:-
* if token is TOK_TERM, then entire write operation terminates
* if token is TOK_DELAY, then a delay of 'val' msec is introduced
* if token is TOK_SKIP, then the register write is skipped
* if token is TOK_WRITE, then the register write is performed
* Returns zero if successful, or non-zero otherwise.
*/
static int tvp7000_write_regs(struct v4l2_subdev *sd,
const struct tvp7000_reg reglist[])
{
int err;
const struct tvp7000_reg *next = reglist;
for (; next->token != TOK_TERM; next++) {
if (next->token == TOK_DELAY) {
msleep(next->val);
continue;
}
if (next->token == TOK_SKIP)
continue;
err = tvp7000_write_reg(sd, next->reg, (u8) next->val);
if (err) {
v4l2_err(sd, "Write failed. Err[%d]\n", err);
return err;
}
}
return 0;
}
/**
* tvp7000_configure() - Configure the TVP7000 registers
* @sd: ptr to v4l2_subdev struct
* @decoder: ptr to tvp7000_decoder structure
*
* Returns zero if successful, or non-zero otherwise.
*/
static int tvp7000_configure(struct v4l2_subdev *sd,
struct tvp7000_decoder *decoder)
{
int err;
#if INIT_DEFAULT
/* initialize TVP7000 as its default values */
tvp7000_write_regs(sd, tvp7000_init_reg_default);
#endif
/* common register initialization */
err = tvp7000_write_regs(sd, decoder->tvp7000_regs);
if (err)
return err;
if (tvp7000_selmux(sd))
return -1;
#if 0
if (debug)
tvp7000_reg_dump(sd);
#endif
return 0;
}
static int tvp7000_g_input_status(struct v4l2_subdev *sd, u32 *status)
{
if (input_signal_exist(sd) < 0)
return -EINVAL;
*status = TVP7000_COMPONENT;
return 0;
}
static int tvp7000_s_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
struct tvp7000_decoder *decoder = to_decoder(sd);
int err;
decoder->input = input;
decoder->output = output;
if (decoder->input != TVP7000_COMPONENT)
return -EINVAL;
err = tvp7000_configure(sd, decoder);
if (err)
return -EBUSY;
v4l2_dbg(1, debug, sd, "Selecting video route: route input=%i, output=%i "
"=> tvp7000 input=%i\n",
decoder->input, decoder->output,
input);
return 0;
}
static int tvp7000_reset(struct v4l2_subdev *sd, u32 val)
{
struct tvp7000_decoder *decoder = to_decoder(sd);
int err = tvp7000_configure(sd, decoder);
if (err)
printk(KERN_ERR "tvp7000_reset failed\n" );
return err;
}
/**
* tvp7000_querystd() - V4L2 decoder interface handler for querystd
* @sd: pointer to standard V4L2 sub-device structure
* @std_id: standard V4L2 std_id ioctl enum
*
* Returns the current standard detected by TVP5146/47. If no active input is
* detected, returns -EINVAL
*/
static int tvp7000_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
{
struct tvp7000_decoder *decoder = to_decoder(sd);
enum tvp7000_std current_std;
if (std_id == NULL)
return -EINVAL;
/* get the current standard */
current_std = decoder->current_std;
if (current_std == STD_INVALID)
return -EINVAL;
if (decoder->input != TVP7000_COMPONENT)
return -EINVAL;
if (input_signal_exist(sd) < 0)
return -EINVAL;
decoder->current_std = current_std;
*std_id = decoder->std_list[current_std].standard.id;
v4l2_dbg(1, debug, sd, "Current STD: %s",
decoder->std_list[current_std].standard.name);
return 0;
}
static int tvp7000_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
{
struct tvp7000_decoder *decoder = to_decoder(sd);
enum tvp7000_std mode = STD_INVALID;
int ret, i;
for (i = 0; i < decoder->num_stds; i++)
if (std & decoder->std_list[i].standard.id)
break;
if ((i == decoder->num_stds) || (i == STD_INVALID))
return -EINVAL;
switch (i)
{
case V4L2_STD_HD_480P:
mode = VIDEO480P60HZ;
break;
case V4L2_STD_HD_576P:
mode = VIDEO576P50HZ;
break;
case V4L2_STD_HD_720P:
mode = VIDEO720P60HZ;
break;
case V4L2_STD_HD_1080I:
mode = VIDEO1080I60HZ;
break;
default:
return -EINVAL;
}
ret = tvp7000_setup_video_standard(sd, &decoder->std_list[mode]);
if (!ret)
return -EIO;
decoder->current_std = mode;
v4l2_dbg(1, debug, sd, "Standard set to: %s",
decoder->std_list[i].standard.name);
return ret;
}
/**
* tvp7000_enum_fmt_cap() - V4L2 decoder interface handler for enum_fmt
* @sd: pointer to standard V4L2 sub-device structure
* @fmt: standard V4L2 VIDIOC_ENUM_FMT ioctl structure
*
* Implement the VIDIOC_ENUM_FMT ioctl to enumerate supported formats
*/
static int
tvp7000_enum_fmt_cap(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt)
{
struct tvp7000_decoder *decoder = to_decoder(sd);
int index;
if (fmt == NULL)
return -EINVAL;
index = fmt->index;
if ((index >= decoder->num_fmts) || (index < 0))
/* Index out of bound */
return -EINVAL;
if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
/* only capture is supported */
return -EINVAL;
memcpy(fmt, &decoder->fmt_list[index],
sizeof(struct v4l2_fmtdesc));
v4l2_dbg(1, debug, sd, "Current FMT: index - %d (%s)",
decoder->fmt_list[index].index,
decoder->fmt_list[index].description);
return 0;
}
/**
* tvp7000_try_fmt_cap() - V4L2 decoder interface handler for try_fmt
* @sd: pointer to standard V4L2 sub-device structure
* @f: pointer to standard V4L2 VIDIOC_TRY_FMT ioctl structure
*
* Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. This
* ioctl is used to negotiate the image capture size and pixel format
* without actually making it take effect.
*/
static int
tvp7000_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
{
struct tvp7000_decoder *decoder = to_decoder(sd);
int ifmt;
struct v4l2_pix_format *pix;
enum tvp7000_std current_std;
if (f == NULL)
return -EINVAL;
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
/* only capture is supported */
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
pix = &f->fmt.pix;
/* Calculate height and width based on current standard */
current_std = decoder->current_std;
if (current_std == STD_INVALID)
return -EINVAL;
pix->width = decoder->std_list[current_std].width;
pix->height = decoder->std_list[current_std].height;
for (ifmt = 0; ifmt < decoder->num_fmts; ifmt++) {
if (pix->pixelformat ==
decoder->fmt_list[ifmt].pixelformat)
break;
}
if (ifmt == decoder->num_fmts)
/* None of the format matched, select default */
ifmt = 0;
pix->pixelformat = decoder->fmt_list[ifmt].pixelformat;
pix->field = V4L2_FIELD_INTERLACED;
pix->bytesperline = pix->width * 2;
pix->sizeimage = pix->bytesperline * pix->height;
pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
pix->priv = 0;
v4l2_dbg(1, debug, sd, "Try FMT: pixelformat - %s, bytesperline - %d"
"Width - %d, Height - %d",
decoder->fmt_list[ifmt].description, pix->bytesperline,
pix->width, pix->height);
return 0;
}
/**
* tvp7000_s_fmt_cap() - V4L2 decoder interface handler for s_fmt
* @sd: pointer to standard V4L2 sub-device structure
* @f: pointer to standard V4L2 VIDIOC_S_FMT ioctl structure
*
* If the requested format is supported, configures the HW to use that
* format, returns error code if format not supported or HW can't be
* correctly configured.
*/
static int
tvp7000_s_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
{
struct tvp7000_decoder *decoder = to_decoder(sd);
struct v4l2_pix_format *pix;
int rval;
if (f == NULL)
return -EINVAL;
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
/* only capture is supported */
return -EINVAL;
pix = &f->fmt.pix;
rval = tvp7000_try_fmt_cap(sd, f);
if (rval)
return rval;
decoder->pix = *pix;
return rval;
}
/**
* tvp7000_g_fmt_cap() - V4L2 decoder interface handler for tvp7000_g_fmt_cap
* @sd: pointer to standard V4L2 sub-device structure
* @f: pointer to standard V4L2 v4l2_format structure
*
* Returns the decoder's current pixel format in the v4l2_format
* parameter.
*/
static int
tvp7000_g_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
{
struct tvp7000_decoder *decoder = to_decoder(sd);
if (f == NULL)
return -EINVAL;
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
/* only capture is supported */
return -EINVAL;
f->fmt.pix = decoder->pix;
v4l2_dbg(1, debug, sd, "Current FMT: bytesperline - %d"
"Width - %d, Height - %d",
decoder->pix.bytesperline,
decoder->pix.width, decoder->pix.height);
return 0;
}
/**
* tvp7000_g_parm() - V4L2 decoder interface handler for g_parm
* @sd: pointer to standard V4L2 sub-device structure
* @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
*
* Returns the decoder's video CAPTURE parameters.
*/
static int
tvp7000_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
{
struct tvp7000_decoder *decoder = to_decoder(sd);
struct v4l2_captureparm *cparm;
enum tvp7000_std current_std;
if (a == NULL)
return -EINVAL;
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
/* only capture is supported */
return -EINVAL;
memset(a, 0, sizeof(*a));
a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/* get the current standard */
current_std = decoder->current_std;
if (current_std == STD_INVALID)
return -EINVAL;
cparm = &a->parm.capture;
cparm->capability = V4L2_CAP_TIMEPERFRAME;
cparm->timeperframe =
decoder->std_list[current_std].standard.frameperiod;
return 0;
}
/**
* tvp7000_s_parm() - V4L2 decoder interface handler for s_parm
* @sd: pointer to standard V4L2 sub-device structure
* @a: pointer to standard V4L2 VIDIOC_S_PARM ioctl structure
*
* Configures the decoder to use the input parameters, if possible. If
* not possible, returns the appropriate error code.
*/
static int
tvp7000_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
{
struct tvp7000_decoder *decoder = to_decoder(sd);
struct v4l2_fract *timeperframe;
enum tvp7000_std current_std;
if (a == NULL)
return -EINVAL;
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
/* only capture is supported */
return -EINVAL;
timeperframe = &a->parm.capture.timeperframe;
/* get the current standard */
current_std = decoder->current_std;
if (current_std == STD_INVALID)
return -EINVAL;
*timeperframe =
decoder->std_list[current_std].standard.frameperiod;
return 0;
}
/**
* tvp7000_s_stream() - V4L2 decoder i/f handler for s_stream
* @sd: pointer to standard V4L2 sub-device structure
* @enable: streaming enable or disable
*
* Sets streaming to enable or disable, if possible.
*/
static int tvp7000_s_stream(struct v4l2_subdev *sd, int enable)
{
int err = 0;
struct tvp7000_decoder *decoder = to_decoder(sd);
if (decoder->streaming == enable)
return 0;
switch (enable) {
case 0:
{
/* Power Down Sequence */
tvp7000_device_power_on(false);
decoder->streaming = enable;
break;
}
case 1:
{
int err;
tvp7000_device_power_on(true);
err = tvp7000_configure(sd, decoder);
if (err) {
v4l2_err(sd, "Unable to configure decoder\n");
return -EBUSY;
}
decoder->streaming = enable;
break;
}
default:
err = -ENODEV;
break;
}
return err;
}
static int tvp7000_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *chip)
{
int rev;
struct i2c_client *client = v4l2_get_subdevdata(sd);
rev = tvp7000_read_reg(sd, TVP7000_CHIP_REVISION);
printk(KERN_INFO "tvp7000 detected Revision: %d\n", rev);
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_TVP7000,
rev);
}
static const struct v4l2_subdev_core_ops tvp7000_core_ops = {
.reset = tvp7000_reset,
.s_std = tvp7000_s_std,
.g_chip_ident = tvp7000_g_chip_ident,
};
static const struct v4l2_subdev_video_ops tvp7000_video_ops = {
.s_routing = tvp7000_s_routing,
.querystd = tvp7000_querystd,
.g_input_status = tvp7000_g_input_status,
.enum_fmt = tvp7000_enum_fmt_cap,
.g_fmt = tvp7000_g_fmt_cap,
.try_fmt = tvp7000_try_fmt_cap,
.s_fmt = tvp7000_s_fmt_cap,
.g_parm = tvp7000_g_parm,
.s_parm = tvp7000_s_parm,
.s_stream = tvp7000_s_stream,
};
static const struct v4l2_subdev_ops tvp7000_ops = {
.core = &tvp7000_core_ops,
.video = &tvp7000_video_ops,
};
static struct tvp7000_decoder tvp7000_dev = {
.streaming = 0,
.fmt_list = tvp7000_fmt_list,
.num_fmts = ARRAY_SIZE(tvp7000_fmt_list),
.pix = {
/* Default to PAL 8-bit YUV 422 */
.width = 720,
.height = 480,
.pixelformat = V4L2_PIX_FMT_UYVY,
.field = 0, //V4L2_FIELD_INTERLACED,
.bytesperline = 720 * 2,
.sizeimage = 720 * 2 * 480,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
},
.current_std = VIDEO480P60HZ,
.std_list = video_info,
.num_stds = ARRAY_SIZE(video_info),
};
/**
* tvp7000_probe() - decoder driver i2c probe handler
* @client: i2c driver client device structure
* @id: i2c driver id table
*
* Register decoder as an i2c client device and V4L2
* device.
*/
static int tvp7000_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct tvp7000_decoder *decoder;
struct v4l2_subdev *sd;
/* power on the tvp7000 Video decoder*/
tvp7000_device_power_on(true);
mdelay(500);
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_WRITE_BYTE))
return -EIO;
#if 0
if (!client->dev.platform_data) {
v4l2_err(client, "No platform data!!\n");
return -ENODEV;
}
#endif
decoder = kzalloc(sizeof(*decoder), GFP_KERNEL);
if (!decoder)
return -ENOMEM;
/* Initialize the tvp7000_decoder with default configuration */
*decoder = tvp7000_dev;
/* Copy default register configuration */
memcpy(decoder->tvp7000_regs, tvp7000_init_reg_seq,
sizeof(tvp7000_init_reg_seq));
/* Copy board specific information here */
decoder->pdata = client->dev.platform_data;
/* Register with V4L2 layer as slave device */
sd = &decoder->sd;
v4l2_i2c_subdev_init(sd, client, &tvp7000_ops);
v4l_info(client, "chip found @ 0x%02x (%s)\n",
client->addr << 1, client->adapter->name);
v4l2_info(sd, "%s decoder driver registered !!\n", sd->name);
return 0;
}
/**
* tvp7000_remove() - decoder driver i2c remove handler
* @client: i2c driver client device structure
*
* Unregister decoder as an i2c client device and V4L2
* device. Complement of tvp7000_probe().
*/
static int tvp7000_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct tvp7000_decoder *decoder = to_decoder(sd);
/* power down the tvp7000 Video decoder*/
tvp7000_device_power_on(false);
v4l2_device_unregister_subdev(sd);
kfree(decoder);
return 0;
}
/**
* I2C Device Table -
*
* name - Name of the actual device/chip.
* driver_data - Driver data
*/
static const struct i2c_device_id tvp7000_id[] = {
{"tvp7000", 0},
{},
};
MODULE_DEVICE_TABLE(i2c, tvp7000_id);
static struct i2c_driver tvp7000_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "tvp7000",
},
.probe = tvp7000_probe,
.remove = tvp7000_remove,
.id_table = tvp7000_id,
};
static __init int tvp7000_init(void)
{
printk(KERN_INFO "<%s> start:\n", __FUNCTION__);
return i2c_add_driver(&tvp7000_driver);
}
static __exit void tvp7000_exit(void)
{
printk(KERN_INFO "<%s> start:\n", __FUNCTION__);
i2c_del_driver(&tvp7000_driver);
}
module_init(tvp7000_init);
module_exit(tvp7000_exit);
/*
* Copyright(C) 2006-2008 Neuros Technology International LLC.
* <www.neurostechnology.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 of the License.
*
* This program is distributed in the hope that, in addition to its
* original purpose to support Neuros hardware, it will be useful
* otherwise, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
****************************************************************************
*
* tvp7000 driver header.
*
*/
#ifndef TVP7000_REGS_H__
#define TVP7000_REGS_H__
#define TVP7000_CHIP_REVISION 0x00
#define TVP7000_PLL_DIVIDE_MSB 0x01
#define TVP7000_PLL_DIVIDE_LSB 0x02
#define TVP7000_PLL_CTRL 0x03
#define TVP7000_PHASE_SELECT 0x04
#define TVP7000_CLAMP_START 0x05
#define TVP7000_CLAMP_WIDTH 0x06
#define TVP7000_HSYNC_OUTPUT_WIDTH 0x07
#define TVP7000_BLUE_FINE_GAIN 0x08
#define TVP7000_GREEN_FINE_GAIN 0x09
#define TVP7000_RED_FINE_GAIN 0x0A
#define TVP7000_BLUE_FINE_OFFSET 0x0B
#define TVP7000_GREEN_FINE_OFFSET 0x0C
#define TVP7000_RED_FINE_OFFSET 0x0D
#define TVP7000_SYNC_CTRL_1 0x0E
#define TVP7000_PLL_CLAMP_CTRL 0x0F
#define TVP7000_SYNC_ON_GREEN 0x10
#define TVP7000_SYNC_SEPARATOR 0x11
#define TVP7000_PRE_COAST 0x12
#define TVP7000_POST_COAST 0x13
#define TVP7000_SYNC_DETECT_STATUS 0x14
#define TVP7000_OUTPUT_FORMATTER 0x15
#define TVP7000_TEST_REG 0x16
/* Reserved 0x17 - 0x18 */
#define TVP7000_INPUT_MUX_1 0x19
#define TVP7000_INPUT_MUX_2 0x1A
#define TVP7000_BLUE_GREEN_GAIN 0x1B
#define TVP7000_RED_COARSE_GAIN 0x1C
#define TVP7000_FINE_OFFSET_LSB 0x1D
#define TVP7000_BLUE_COARSE_OFFSET 0x1E
#define TVP7000_GREEN_COARSE_OFFSET 0x1F
#define TVP7000_RED_COARSE_OFFSET 0x20
#define TVP7000_HSOUT_OUTPUT_START 0x21
#define TVP7000_MISC_CTRL 0x22
/* Reserved 0x23 - 0x25 */
#define TVP7000_AUTO_CTRL_ENABLE 0x26
/* Reserved 0x27 */
#define TVP7000_AUTO_CTRL_FILTER 0x28
/* Reserved 0x29 */
#define TVP7000_FINE_CLAMP_CTRL 0x2A
#define TVP7000_POWER_CTRL 0x2B
#define TVP7000_ADC_SETUP 0x2C
#define TVP7000_COARSE_CLAMP_CTRL_1 0x2D
#define TVP7000_SOG_CLAMP 0x2E
/* Reserved 0x2F - 0x30 */
#define TVP7000_ALC_PLACEMENT 0x31
/* Tokens for register write */
#define TOK_WRITE (0) /* token for write operation */
#define TOK_TERM (1) /* terminating token */
#define TOK_DELAY (2) /* delay token for reg list */
#define TOK_SKIP (3) /* token to skip a register */
/**
* struct tvp7000_reg - Structure for TVP7000 register initialization values
* @token - Token: TOK_WRITE, TOK_TERM etc..
* @reg - Register offset
* @val - Register Value for TOK_WRITE or delay in ms for TOK_DELAY
*/
struct tvp7000_reg {
u8 token;
u8 reg;
u8 val;
};
#endif /* TVP7000_REGS_H__ */
......@@ -665,6 +665,13 @@ typedef __u64 v4l2_std_id;
#define V4L2_STD_ATSC_8_VSB ((v4l2_std_id)0x01000000)
#define V4L2_STD_ATSC_16_VSB ((v4l2_std_id)0x02000000)
/*FOR COMPONENT*/
#define V4L2_STD_HD_480P ((v4l2_std_id)0x04000000)
#define V4L2_STD_HD_576P ((v4l2_std_id)0x08000000)
#define V4L2_STD_HD_720P ((v4l2_std_id)0x10000000)
#define V4L2_STD_HD_1080I ((v4l2_std_id)0x20000000)
#define V4L2_STD_HD_1080P ((v4l2_std_id)0x40000000)
/* FIXME:
Although std_id is 64 bits, there is an issue on PPC32 architecture that
makes switch(__u64) to break. So, there's a hack on v4l2-common.c rounding
......
/*
* Copyright(C) 2006-2008 Neuros Technology International LLC.
* <www.neurostechnology.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 of the License.
*
* This program is distributed in the hope that, in addition to its
* original purpose to support Neuros hardware, it will be useful
* otherwise, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
****************************************************************************
*
// * tvp7000 driver header.
*
*/
#ifndef TVP7000_H__
#define TVP7000_H__
#define TVP7000_COMPONENT 2
/* TVP7000 HW outputs */
#define TVP7000_NORMAL_SCREEN 0
#define TVP7000_BLACK_SCREEN 1
#endif /* TVP7000_H__ */
......@@ -129,6 +129,9 @@ enum {
V4L2_IDENT_SAA6752HS = 6752,
V4L2_IDENT_SAA6752HS_AC3 = 6753,
/* module tvp7000 */
V4L2_IDENT_TVP7000 = 7000,
/* module adv7170: just ident 7170 */
V4L2_IDENT_ADV7170 = 7170,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment