Commit 32d3adcd authored by 薛德章's avatar 薛德章

Merge branch 'neuros' of...

Merge branch 'neuros' of ssh://git@git.neuros.com.cn/git/git-pub/osd20/linux-davinci-2.6 into neuros
parents 0acae4f3 9523d091
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
LDFLAGS_vmlinux :=-p --no-undefined -X LDFLAGS_vmlinux :=-p --no-undefined -X
CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET) CPPFLAGS_vmlinux.lds = -DTEXT_OFFSET=$(TEXT_OFFSET)
OBJCOPYFLAGS :=-O binary -R .note -R .comment -S OBJCOPYFLAGS :=-O binary -R .note -R .note.gnu.build-id -R .comment -S
GZFLAGS :=-9 GZFLAGS :=-9
#CFLAGS +=-pipe #CFLAGS +=-pipe
# Explicitly specifiy 32-bit ARM ISA since toolchain default can be -mthumb: # Explicitly specifiy 32-bit ARM ISA since toolchain default can be -mthumb:
......
...@@ -372,6 +372,22 @@ config VIDEO_VIVI ...@@ -372,6 +372,22 @@ config VIDEO_VIVI
Say Y here if you want to test video apps or debug V4L devices. Say Y here if you want to test video apps or debug V4L devices.
In doubt, say N. In doubt, say N.
config VIDEO_DAVINCI
tristate "Davinci Video Capture"
depends on VIDEO_DEV && ARCH_DAVINCI
select VIDEO_BUF
help
Support for Davinci based frame grabber through CCDC.
To compile this driver as a module, choose M here: the
module will be called vpfe.
choice
prompt "Video Capture Decoder"
optional
depends on VIDEO_DAVINCI
config VIDEO_TVP5146 config VIDEO_TVP5146
tristate "TVP5146 video decoder" tristate "TVP5146 video decoder"
depends on I2C && ARCH_DAVINCI depends on I2C && ARCH_DAVINCI
...@@ -381,15 +397,15 @@ config VIDEO_TVP5146 ...@@ -381,15 +397,15 @@ config VIDEO_TVP5146
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called tvp5146. module will be called tvp5146.
config VIDEO_DAVINCI config VIDEO_TVP5150
tristate "Davinci Video Capture" tristate "TVP5150 video decoder"
depends on VIDEO_DEV && VIDEO_TVP5146 && ARCH_DAVINCI depends on I2C && ARCH_DAVINCI
select VIDEO_BUF
help help
Support for Davinci based frame grabber through CCDC. Support for I2C bus based TVP5150 configuration.
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called vpfe. module will be called tvp5150.
endchoice
source "drivers/media/video/bt8xx/Kconfig" source "drivers/media/video/bt8xx/Kconfig"
......
...@@ -20,6 +20,7 @@ ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y) ...@@ -20,6 +20,7 @@ ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y)
obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o
endif endif
obj-$(CONFIG_VIDEO_DAVINCI) += davinci-vpfe.o
obj-$(CONFIG_VIDEO_BT848) += bt8xx/ obj-$(CONFIG_VIDEO_BT848) += bt8xx/
obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
...@@ -69,7 +70,6 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/ ...@@ -69,7 +70,6 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/
obj-$(CONFIG_VIDEO_IVTV) += ivtv/ obj-$(CONFIG_VIDEO_IVTV) += ivtv/
obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
...@@ -122,8 +122,8 @@ obj-$(CONFIG_USB_KONICAWC) += usbvideo/ ...@@ -122,8 +122,8 @@ obj-$(CONFIG_USB_KONICAWC) += usbvideo/
obj-$(CONFIG_USB_VICAM) += usbvideo/ obj-$(CONFIG_USB_VICAM) += usbvideo/
obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/ obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/
obj-$(CONFIG_VIDEO_DAVINCI) += davinci-vpfe.o
obj-$(CONFIG_VIDEO_TVP5146) += tvp5146.o obj-$(CONFIG_VIDEO_TVP5146) += tvp5146.o
obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
obj-$(CONFIG_VIDEO_VIVI) += vivi.o obj-$(CONFIG_VIDEO_VIVI) += vivi.o
......
...@@ -45,6 +45,44 @@ ...@@ -45,6 +45,44 @@
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/* These routines must be called after device
lock is obtained. */
#define ACTIVE_DEVICE() (vpfe_device.active_device)
#define SET_ACTIVE_DEVICE(x) (vpfe_device.active_device = (x))
#define IS_ACTIVE(x) \
((x) && ACTIVE_DEVICE() && ((x)->id == ACTIVE_DEVICE()->id))
#define DEVICE_DEACTIVATE(x) do { \
if ((x) && (x)->capture_device_deactive && \
(x)->capture_device_deactive()) \
debug_print(KERN_ERR\
"capture device %s deactivate failed\n", \
(x)->name); \
} while (0)
#define DEVICE_ACTIVATE(x) do { \
if ((x) && (x)->capture_device_active && \
(x)->capture_device_active()) \
debug_print(KERN_ERR \
"capture device %s activate failed\n", \
(x)->name); \
} while (0)
#define DEVICE_INIT(x, params) do { \
if ((x) && (x)->capture_device_init && \
(x)->capture_device_init(params)) \
debug_print(KERN_ERR \
"capture device %s init failed\n", \
(x)->name); \
} while (0)
#define DEVICE_CLEANUP(x) do { \
if ((x) && (x)->capture_device_cleanup && \
(x)->capture_device_cleanup()) \
debug_print(KERN_ERR \
"capture device %s cleanup failed\n", \
(x)->name); \
} while (0)
#define DEVICE_CMD(dev, cmd, arg) \
((dev) && (dev)->capture_device_cmd && \
(dev)->capture_device_cmd(cmd, arg));
static struct v4l2_rect ntsc_bounds = VPFE_WIN_NTSC; static struct v4l2_rect ntsc_bounds = VPFE_WIN_NTSC;
static struct v4l2_rect pal_bounds = VPFE_WIN_PAL; static struct v4l2_rect pal_bounds = VPFE_WIN_PAL;
static struct v4l2_fract ntsc_aspect = VPFE_PIXELASPECT_NTSC; static struct v4l2_fract ntsc_aspect = VPFE_PIXELASPECT_NTSC;
...@@ -74,10 +112,11 @@ static vpfe_obj vpfe_device = { /* the default format is NTSC */ ...@@ -74,10 +112,11 @@ static vpfe_obj vpfe_device = { /* the default format is NTSC */
.pix_order = CCDC_PIXORDER_CBYCRY, .pix_order = CCDC_PIXORDER_CBYCRY,
.buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED .buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
}, },
.tvp5146_params = { .capture_params = {
.mode = TVP5146_MODE_AUTO, .mode = VPFE_STD_AUTO,
.amuxmode = TVP5146_AMUX_COMPOSITE, .amuxmode = VPFE_AMUX_COMPOSITE,
.enablebt656sync = TRUE .enablebt656sync = TRUE,
.squarepixel = FALSE,
}, },
.irqlock = SPIN_LOCK_UNLOCKED .irqlock = SPIN_LOCK_UNLOCKED
}; };
...@@ -90,48 +129,6 @@ struct v4l2_capability vpfe_drvcap = { ...@@ -90,48 +129,6 @@ struct v4l2_capability vpfe_drvcap = {
.capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING
}; };
static int sense_std(v4l2_std_id* std_id)
{
v4l2_std_id id = 0;
tvp5146_mode mode;
int ret;
ret = tvp5146_ctrl(TVP5146_GET_STD, &mode);
if(ret < 0)
return ret;
switch (mode & 0x7) {
case TVP5146_MODE_NTSC:
id = V4L2_STD_NTSC;
break;
case TVP5146_MODE_PAL:
id = V4L2_STD_PAL;
break;
case TVP5146_MODE_PAL_M:
id = V4L2_STD_PAL_M;
break;
case TVP5146_MODE_PAL_CN:
id = V4L2_STD_PAL_N;
break;
case TVP5146_MODE_SECAM:
id = V4L2_STD_SECAM;
break;
case TVP5146_MODE_PAL_60:
id = V4L2_STD_PAL_60;
break;
}
if (mode & 0x8) { /* square pixel mode */
id <<= 32;
}
if (mode == TVP5146_MODE_AUTO) {
id = VPFE_STD_AUTO; /* auto-detection for all other modes */
} else if (mode == TVP5146_MODE_AUTO_SQP) {
id = VPFE_STD_AUTO_SQP;
}
if(id == 0)
return -EINVAL;
*std_id = id;
return 0;
}
static irqreturn_t vpfe_isr(int irq, void *dev_id) static irqreturn_t vpfe_isr(int irq, void *dev_id)
{ {
vpfe_obj *vpfe = &vpfe_device; vpfe_obj *vpfe = &vpfe_device;
...@@ -282,14 +279,52 @@ static struct videobuf_queue_ops video_qops = { ...@@ -282,14 +279,52 @@ static struct videobuf_queue_ops video_qops = {
.buf_config = buffer_config, .buf_config = buffer_config,
}; };
static int vpfe_capture_device_active(struct vpfe_capture_device *device)
{
int ret = 0;
if (device == NULL)
return -EINVAL;
down_interruptible(&vpfe_device.lock);
/* deactivate the activated device */
DEVICE_DEACTIVATE(ACTIVE_DEVICE());
/* set device state as active */
SET_ACTIVE_DEVICE(device);
/* call device specific routine to do the active job. */
DEVICE_ACTIVATE(device);
up(&vpfe_device.lock);
return ret;
}
static int vpfe_select_capture_device(int id)
{
int err = 0;
struct vpfe_capture_device *device;
down_interruptible(&vpfe_device.device_list_lock);
list_for_each_entry(device, &vpfe_device.capture_device_list,
device_list){
if (device->id == id) {
err = vpfe_capture_device_active(device);
up(&vpfe_device.device_list_lock);
return err;
}
}
up(&vpfe_device.device_list_lock);
return -ENODEV;
}
static int vpfe_doioctl(struct inode *inode, struct file *file, static int vpfe_doioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg) unsigned int cmd, void *arg)
{ {
vpfe_obj *vpfe = &vpfe_device; vpfe_obj *vpfe = &vpfe_device;
vpfe_fh *fh = file->private_data; vpfe_fh *fh = file->private_data;
int ret = 0; int ret = 0;
switch (cmd) { switch (cmd) {
case VIDIOC_S_CTRL: case VIDIOC_S_CTRL:
...@@ -407,6 +442,9 @@ static int vpfe_doioctl(struct inode *inode, struct file *file, ...@@ -407,6 +442,9 @@ static int vpfe_doioctl(struct inode *inode, struct file *file,
} else { } else {
ret = -EINVAL; ret = -EINVAL;
} }
ret |= DEVICE_CMD(ACTIVE_DEVICE(), VIDIOC_S_FMT, arg);
up(&vpfe->lock); up(&vpfe->lock);
break; break;
} }
...@@ -436,7 +474,6 @@ static int vpfe_doioctl(struct inode *inode, struct file *file, ...@@ -436,7 +474,6 @@ static int vpfe_doioctl(struct inode *inode, struct file *file,
case VIDIOC_S_STD: case VIDIOC_S_STD:
{ {
v4l2_std_id id = *(v4l2_std_id *) arg; v4l2_std_id id = *(v4l2_std_id *) arg;
tvp5146_mode mode = TVP5146_MODE_INV;
int sqp = 0; int sqp = 0;
if (vpfe->started) { /* make sure streaming is not started */ if (vpfe->started) { /* make sure streaming is not started */
...@@ -470,7 +507,6 @@ static int vpfe_doioctl(struct inode *inode, struct file *file, ...@@ -470,7 +507,6 @@ static int vpfe_doioctl(struct inode *inode, struct file *file,
vpfe->pixelaspect = sp_aspect; vpfe->pixelaspect = sp_aspect;
vpfe->ccdc_params.win = ntscsp_bounds; vpfe->ccdc_params.win = ntscsp_bounds;
} else if (id & VPFE_STD_AUTO) { } else if (id & VPFE_STD_AUTO) {
mode = TVP5146_MODE_AUTO;
vpfe->bounds = vpfe->vwin = pal_bounds; vpfe->bounds = vpfe->vwin = pal_bounds;
vpfe->pixelaspect = pal_aspect; vpfe->pixelaspect = pal_aspect;
vpfe->ccdc_params.win = pal_bounds; vpfe->ccdc_params.win = pal_bounds;
...@@ -480,27 +516,17 @@ static int vpfe_doioctl(struct inode *inode, struct file *file, ...@@ -480,27 +516,17 @@ static int vpfe_doioctl(struct inode *inode, struct file *file,
vpfe->bounds = vpfe->vwin = palsp_bounds; vpfe->bounds = vpfe->vwin = palsp_bounds;
vpfe->pixelaspect = sp_aspect; vpfe->pixelaspect = sp_aspect;
sqp = 1; sqp = 1;
mode = TVP5146_MODE_AUTO_SQP;
vpfe->pixelaspect = sp_aspect; vpfe->pixelaspect = sp_aspect;
} else { } else {
ret = -EINVAL; ret = -EINVAL;
} }
if (id == V4L2_STD_PAL_60) {
mode = TVP5146_MODE_PAL_60; vpfe->capture_params.mode = id;
} else if (id == V4L2_STD_PAL_M) { vpfe->capture_params.squarepixel = sqp;
mode = TVP5146_MODE_PAL_M;
} else if (id == V4L2_STD_PAL_Nc ret |= DEVICE_CMD(ACTIVE_DEVICE(),
|| id == V4L2_STD_PAL_N) { VPFE_CMD_CONFIG_CAPTURE,
mode = TVP5146_MODE_PAL_CN; &vpfe->capture_params);
} else if (id & V4L2_STD_PAL) {
mode = TVP5146_MODE_PAL;
} else if (id & V4L2_STD_NTSC) {
mode = TVP5146_MODE_NTSC;
} else if (id & V4L2_STD_SECAM) {
mode = TVP5146_MODE_SECAM;
}
vpfe->tvp5146_params.mode = mode | (sqp << 3);
ret = tvp5146_ctrl(TVP5146_CONFIG, &vpfe->tvp5146_params);
up(&vpfe->lock); up(&vpfe->lock);
break; break;
...@@ -576,7 +602,7 @@ static int vpfe_doioctl(struct inode *inode, struct file *file, ...@@ -576,7 +602,7 @@ static int vpfe_doioctl(struct inode *inode, struct file *file,
case VIDIOC_G_INPUT: case VIDIOC_G_INPUT:
{ {
int *index = (int *)arg; int *index = (int *)arg;
*index = vpfe->tvp5146_params.amuxmode; *index = vpfe->capture_params.amuxmode;
break; break;
} }
case VIDIOC_S_INPUT: case VIDIOC_S_INPUT:
...@@ -585,8 +611,10 @@ static int vpfe_doioctl(struct inode *inode, struct file *file, ...@@ -585,8 +611,10 @@ static int vpfe_doioctl(struct inode *inode, struct file *file,
if (*index > 1 || *index < 0) { if (*index > 1 || *index < 0) {
ret = -EINVAL; ret = -EINVAL;
} }
vpfe->tvp5146_params.amuxmode = *index; vpfe->capture_params.amuxmode = *index;
ret = tvp5146_ctrl(TVP5146_SET_AMUXMODE, index);
ret |= DEVICE_CMD(ACTIVE_DEVICE(),
VIDIOC_S_INPUT, index);
break; break;
} }
case VIDIOC_CROPCAP: case VIDIOC_CROPCAP:
...@@ -627,17 +655,26 @@ static int vpfe_doioctl(struct inode *inode, struct file *file, ...@@ -627,17 +655,26 @@ static int vpfe_doioctl(struct inode *inode, struct file *file,
} }
case VIDIOC_G_CTRL: case VIDIOC_G_CTRL:
down_interruptible(&vpfe->lock); down_interruptible(&vpfe->lock);
ret = tvp5146_ctrl(VIDIOC_G_CTRL, arg);
ret |= DEVICE_CMD(ACTIVE_DEVICE(),
VIDIOC_G_CTRL, arg);
up(&vpfe->lock); up(&vpfe->lock);
break; break;
case VIDIOC_S_CTRL: case VIDIOC_S_CTRL:
down_interruptible(&vpfe->lock); down_interruptible(&vpfe->lock);
ret = tvp5146_ctrl(VIDIOC_S_CTRL, arg);
ret |= DEVICE_CMD(ACTIVE_DEVICE(),
VIDIOC_S_CTRL, arg);
up(&vpfe->lock); up(&vpfe->lock);
break; break;
case VIDIOC_QUERYCTRL: case VIDIOC_QUERYCTRL:
down_interruptible(&vpfe->lock); down_interruptible(&vpfe->lock);
ret = tvp5146_ctrl(VIDIOC_QUERYCTRL, arg);
ret |= DEVICE_CMD(ACTIVE_DEVICE(),
VIDIOC_QUERYCTRL, arg);
up(&vpfe->lock); up(&vpfe->lock);
break; break;
case VIDIOC_G_CROP: case VIDIOC_G_CROP:
...@@ -681,7 +718,10 @@ static int vpfe_doioctl(struct inode *inode, struct file *file, ...@@ -681,7 +718,10 @@ static int vpfe_doioctl(struct inode *inode, struct file *file,
{ {
v4l2_std_id *id = (v4l2_std_id *) arg; v4l2_std_id *id = (v4l2_std_id *) arg;
down_interruptible(&vpfe->lock); down_interruptible(&vpfe->lock);
ret = sense_std(id);
ret |= DEVICE_CMD(ACTIVE_DEVICE(),
VIDIOC_QUERYSTD, id);
up(&vpfe->lock); up(&vpfe->lock);
break; break;
} }
...@@ -761,7 +801,9 @@ static int vpfe_doioctl(struct inode *inode, struct file *file, ...@@ -761,7 +801,9 @@ static int vpfe_doioctl(struct inode *inode, struct file *file,
vpfe->curFrm->state = STATE_ACTIVE; vpfe->curFrm->state = STATE_ACTIVE;
/* sense the current video input standard */ /* sense the current video input standard */
ret = tvp5146_ctrl(TVP5146_CONFIG, &vpfe->tvp5146_params); ret |= DEVICE_CMD(ACTIVE_DEVICE(),
VPFE_CMD_CONFIG_CAPTURE,
&vpfe->capture_params);
/* configure the ccdc and resizer as needed */ /* configure the ccdc and resizer as needed */
/* start capture by enabling CCDC and resizer */ /* start capture by enabling CCDC and resizer */
ccdc_config_ycbcr(&vpfe->ccdc_params); ccdc_config_ycbcr(&vpfe->ccdc_params);
...@@ -823,12 +865,13 @@ static int vpfe_doioctl(struct inode *inode, struct file *file, ...@@ -823,12 +865,13 @@ static int vpfe_doioctl(struct inode *inode, struct file *file,
up(&vpfe->lock); up(&vpfe->lock);
break; break;
} }
case VPFE_CMD_CONFIG_TVP5146: case VPFE_CMD_CONFIG_CAPTURE:
/* this can be used directly and bypass the V4L2 APIs */ /* this can be used directly and bypass the V4L2 APIs */
{ {
/* the settings here must be consistant with that of the CCDC's, /* the settings here must be consistant with that of the CCDC's,
driver does not check the consistancy */ driver does not check the consistancy */
tvp5146_params *params = (tvp5146_params *) arg; struct vpfe_capture_params *params =
(struct vpfe_capture_param *) arg;
v4l2_std_id std = 0; v4l2_std_id std = 0;
if(vpfe->started){ if(vpfe->started){
/* only allowed if streaming is not started */ /* only allowed if streaming is not started */
...@@ -836,38 +879,12 @@ static int vpfe_doioctl(struct inode *inode, struct file *file, ...@@ -836,38 +879,12 @@ static int vpfe_doioctl(struct inode *inode, struct file *file,
break; break;
} }
down_interruptible(&vpfe->lock); down_interruptible(&vpfe->lock);
/*make sure the other v4l2 related fields have consistant settings */
switch (params->mode & 0x7) {
case TVP5146_MODE_NTSC:
std = V4L2_STD_NTSC;
break;
case TVP5146_MODE_PAL:
std = V4L2_STD_PAL;
break;
case TVP5146_MODE_PAL_M:
std = V4L2_STD_PAL_M;
break;
case TVP5146_MODE_PAL_CN:
std = V4L2_STD_PAL_N;
break;
case TVP5146_MODE_SECAM:
std = V4L2_STD_SECAM;
break;
case TVP5146_MODE_PAL_60:
std = V4L2_STD_PAL_60;
break;
}
if (params->mode & 0x8) { /* square pixel mode */ std = params->mode;
if (params->squarepixel) { /* square pixel mode */
std <<= 32; std <<= 32;
} }
if (params->mode == TVP5146_MODE_AUTO) { /* auto-detection modes */
std = VPFE_STD_AUTO;
} else if (params->mode == TVP5146_MODE_AUTO_SQP) {
std = VPFE_STD_AUTO_SQP;
}
if (std & V4L2_STD_625_50) { if (std & V4L2_STD_625_50) {
vpfe->bounds = pal_bounds; vpfe->bounds = pal_bounds;
vpfe->pixelaspect = pal_aspect; vpfe->pixelaspect = pal_aspect;
...@@ -882,11 +899,19 @@ static int vpfe_doioctl(struct inode *inode, struct file *file, ...@@ -882,11 +899,19 @@ static int vpfe_doioctl(struct inode *inode, struct file *file,
vpfe->pixelaspect = sp_aspect; vpfe->pixelaspect = sp_aspect;
} }
vpfe->std = std; vpfe->std = std;
ret = tvp5146_ctrl(TVP5146_CONFIG, params); ret |= DEVICE_CMD(ACTIVE_DEVICE(),
vpfe->tvp5146_params = *params; VPFE_CMD_CONFIG_CAPTURE,
params);
vpfe->capture_params = *params;
up(&vpfe->lock); up(&vpfe->lock);
break; break;
} }
case VPFE_CMD_CAPTURE_ACTIVE:
{
int device_id = *((int *)arg);
ret = vpfe_select_capture_device(device_id);
break;
}
default: default:
ret = -ENOIOCTLCMD; ret = -ENOIOCTLCMD;
break; break;
...@@ -1007,6 +1032,10 @@ static int __init vpfe_probe(struct device *device) ...@@ -1007,6 +1032,10 @@ static int __init vpfe_probe(struct device *device)
v4l2_prio_init(&vpfe->prio); v4l2_prio_init(&vpfe->prio);
init_MUTEX(&vpfe->lock); init_MUTEX(&vpfe->lock);
init_MUTEX(&vpfe->device_list_lock);
INIT_LIST_HEAD(&vpfe->capture_device_list);
SET_ACTIVE_DEVICE(NULL);
/* register video device */ /* register video device */
debug_print(KERN_INFO "trying to register vpfe device.\n"); debug_print(KERN_INFO "trying to register vpfe device.\n");
debug_print(KERN_INFO "vpfe=%x,vpfe->video_dev=%x\n", (int)vpfe, debug_print(KERN_INFO "vpfe=%x,vpfe->video_dev=%x\n", (int)vpfe,
...@@ -1029,6 +1058,69 @@ static int __init vpfe_probe(struct device *device) ...@@ -1029,6 +1058,69 @@ static int __init vpfe_probe(struct device *device)
return 0; return 0;
} }
int vpfe_capture_device_register(struct vpfe_capture_device *device)
{
if (device == NULL)
return -EINVAL;
/* register capture device to vpfe. */
down_interruptible(&vpfe_device.device_list_lock);
list_add_tail(&device->device_list, &vpfe_device.capture_device_list);
up(&vpfe_device.device_list_lock);
/* call capture device specific init routine */
down_interruptible(&vpfe_device.lock);
DEVICE_INIT(device, &vpfe_device.capture_params);
up(&vpfe_device.lock);
debug_print(KERN_INFO "VPFE Capture device %s registered, id = %d.\n",
device->name, device->id);
return 0;
}
EXPORT_SYMBOL(vpfe_capture_device_register);
int vpfe_capture_device_unregister(struct vpfe_capture_device *device)
{
if (device == NULL)
return -EINVAL;
/* unregister it from vpfe. */
down_interruptible(&vpfe_device.device_list_lock);
list_del(&device->device_list);
up(&vpfe_device.device_list_lock);
down_interruptible(&vpfe_device.lock);
/* if the device to be unregistered is active,
deactivate it! */
if (IS_ACTIVE(device)) {
DEVICE_DEACTIVATE(device);
SET_ACTIVE_DEVICE(NULL);
}
/* call device specific routine to do the clean up. */
DEVICE_CLEANUP(device);
up(&vpfe_device.lock);
debug_print(KERN_INFO "VPFE Capture device %s unregistered, id = %d\n",
device->name, device->id);
return 0;
}
EXPORT_SYMBOL(vpfe_capture_device_unregister);
static int capture_device_all_unrigister(void)
{
int ret = 0;
struct vpfe_capture_device *device;
down_interruptible(&vpfe_device.lock);
list_for_each_entry(device, &vpfe_device.capture_device_list,
device_list){
ret |= vpfe_capture_device_unregister(device);
}
up(&vpfe_device.lock);
return ret;
}
static int vpfe_remove(struct device *device) static int vpfe_remove(struct device *device)
{ {
/* un-register device */ /* un-register device */
...@@ -1106,9 +1198,6 @@ static int vpfe_init(void) ...@@ -1106,9 +1198,6 @@ static int vpfe_init(void)
} }
ccdc_reset(); ccdc_reset();
tvp5146_ctrl(TVP5146_RESET, NULL);
/* configure the tvp5146 to default parameters */
tvp5146_ctrl(TVP5146_CONFIG, &vpfe_device.tvp5146_params);
/* setup interrupt handling */ /* setup interrupt handling */
request_irq(IRQ_VDINT0, vpfe_isr, SA_INTERRUPT, request_irq(IRQ_VDINT0, vpfe_isr, SA_INTERRUPT,
"dm644xv4l2", (void *)&vpfe_device); "dm644xv4l2", (void *)&vpfe_device);
...@@ -1122,6 +1211,9 @@ static void vpfe_cleanup(void) ...@@ -1122,6 +1211,9 @@ static void vpfe_cleanup(void)
int i = vpfe_device.numbuffers; int i = vpfe_device.numbuffers;
platform_device_unregister(&_vpfe_device); platform_device_unregister(&_vpfe_device);
driver_unregister(&vpfe_driver); driver_unregister(&vpfe_driver);
capture_device_all_unrigister();
/* disable interrupt */ /* disable interrupt */
free_irq(IRQ_VDINT0, &vpfe_device); free_irq(IRQ_VDINT0, &vpfe_device);
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/video_decoder.h> #include <linux/video_decoder.h>
#include <media/v4l2-common.h> #include <media/v4l2-common.h>
#include <media/tvp5150.h> #include <media/tvp5150.h>
#include <asm/arch/gpio.h>
#include "tvp5150_reg.h" #include "tvp5150_reg.h"
...@@ -45,6 +46,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); ...@@ -45,6 +46,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
i2c_adapter_id(c->adapter), \ i2c_adapter_id(c->adapter), \
c->addr , ## arg); } while (0) c->addr , ## arg); } while (0)
#define SD_CAP_GPIO GPIO(37)
/* supported controls */ /* supported controls */
static struct v4l2_queryctrl tvp5150_qctrl[] = { static struct v4l2_queryctrl tvp5150_qctrl[] = {
{ {
...@@ -98,6 +100,8 @@ struct tvp5150 { ...@@ -98,6 +100,8 @@ struct tvp5150 {
int sat; int sat;
}; };
static struct i2c_client *tvp5150_client;
static int tvp5150_read(struct i2c_client *c, unsigned char addr) static int tvp5150_read(struct i2c_client *c, unsigned char addr)
{ {
unsigned char buffer[1]; unsigned char buffer[1];
...@@ -296,7 +300,7 @@ static inline void tvp5150_selmux(struct i2c_client *c) ...@@ -296,7 +300,7 @@ static inline void tvp5150_selmux(struct i2c_client *c)
switch (decoder->route.input) { switch (decoder->route.input) {
case TVP5150_COMPOSITE1: case TVP5150_COMPOSITE1:
input |= 2; input |= 0;
/* fall through */ /* fall through */
case TVP5150_COMPOSITE0: case TVP5150_COMPOSITE0:
opmode=0x30; /* TV Mode */ opmode=0x30; /* TV Mode */
...@@ -828,6 +832,39 @@ static int tvp5150_get_ctrl(struct i2c_client *c, struct v4l2_control *ctrl) ...@@ -828,6 +832,39 @@ static int tvp5150_get_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
return -EINVAL; return -EINVAL;
} }
static int tvp5150_get_std(struct i2c_client *c, v4l2_std_id *id)
{
int fmt = tvp5150_read(c, TVP5150_VIDEO_STD);
fmt &= 0x0F;
switch (fmt) {
case 0x00:
*id = V4L2_STD_ALL;
break;
case 0x02:
*id = V4L2_STD_NTSC;
break;
case 0x04:
*id = V4L2_STD_PAL;
break;
case 0x06:
*id = V4L2_STD_PAL_M;
break;
case 0x08:
*id = V4L2_STD_PAL_N | V4L2_STD_PAL_Nc;
break;
case 0x0A:
*id = V4L2_STD_NTSC_443;
break;
case 0x0C:
*id = V4L2_STD_SECAM;
break;
default:
*id = V4L2_STD_UNKNOWN;
break;
}
return 0;
}
static int tvp5150_set_ctrl(struct i2c_client *c, struct v4l2_control *ctrl) static int tvp5150_set_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
{ {
/* struct tvp5150 *decoder = i2c_get_clientdata(c); */ /* struct tvp5150 *decoder = i2c_get_clientdata(c); */
...@@ -878,6 +915,16 @@ static int tvp5150_command(struct i2c_client *c, ...@@ -878,6 +915,16 @@ static int tvp5150_command(struct i2c_client *c,
tvp5150_selmux(c); tvp5150_selmux(c);
break; break;
} }
case VIDIOC_S_INPUT:
{
int input = *(int *)arg;
if (input == 0)
decoder->route.input = TVP5150_COMPOSITE1;
else
decoder->route.input = TVP5150_SVIDEO;
tvp5150_selmux(c);
break;
}
case VIDIOC_S_STD: case VIDIOC_S_STD:
if (decoder->norm == *(v4l2_std_id *)arg) if (decoder->norm == *(v4l2_std_id *)arg)
break; break;
...@@ -1021,6 +1068,27 @@ static int tvp5150_command(struct i2c_client *c, ...@@ -1021,6 +1068,27 @@ static int tvp5150_command(struct i2c_client *c,
} }
return -EINVAL; return -EINVAL;
} }
case VIDIOC_QUERYSTD:
{
v4l2_std_id *id = (v4l2_std_id *)arg;
tvp5150_get_std(c, id);
break;
}
case VPFE_CMD_CONFIG_CAPTURE:
{
struct vpfe_capture_params *params =
(struct vpfe_capture_params *)arg;
if (params->amuxmode == VPFE_AMUX_COMPOSITE) {
decoder->route.input = TVP5150_COMPOSITE1;
} else {
decoder->route.input = TVP5150_SVIDEO;
}
tvp5150_selmux(c);
tvp5150_set_std(c, params->mode);
decoder->norm = params->mode;
break;
}
default: default:
return -EINVAL; return -EINVAL;
...@@ -1042,7 +1110,6 @@ static struct i2c_client client_template = { ...@@ -1042,7 +1110,6 @@ static struct i2c_client client_template = {
static int tvp5150_detect_client(struct i2c_adapter *adapter, static int tvp5150_detect_client(struct i2c_adapter *adapter,
int address, int kind) int address, int kind)
{ {
struct i2c_client *c;
struct tvp5150 *core; struct tvp5150 *core;
int rv; int rv;
...@@ -1060,19 +1127,19 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter, ...@@ -1060,19 +1127,19 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter,
I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
return 0; return 0;
c = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); tvp5150_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
if (c == 0) if (tvp5150_client == 0)
return -ENOMEM; return -ENOMEM;
memcpy(c, &client_template, sizeof(struct i2c_client)); memcpy(tvp5150_client, &client_template, sizeof(struct i2c_client));
core = kzalloc(sizeof(struct tvp5150), GFP_KERNEL); core = kzalloc(sizeof(struct tvp5150), GFP_KERNEL);
if (core == 0) { if (core == 0) {
kfree(c); kfree(tvp5150_client);
return -ENOMEM; return -ENOMEM;
} }
i2c_set_clientdata(c, core); i2c_set_clientdata(tvp5150_client, core);
rv = i2c_attach_client(c); rv = i2c_attach_client(tvp5150_client);
core->norm = V4L2_STD_ALL; /* Default is autodetect */ core->norm = V4L2_STD_ALL; /* Default is autodetect */
core->route.input = TVP5150_COMPOSITE1; core->route.input = TVP5150_COMPOSITE1;
...@@ -1083,13 +1150,13 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter, ...@@ -1083,13 +1150,13 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter,
core->sat = 32768; core->sat = 32768;
if (rv) { if (rv) {
kfree(c); kfree(tvp5150_client);
kfree(core); kfree(core);
return rv; return rv;
} }
if (debug > 1) if (debug > 1)
dump_reg(c); dump_reg(tvp5150_client);
return 0; return 0;
} }
...@@ -1122,6 +1189,45 @@ static int tvp5150_detach_client(struct i2c_client *c) ...@@ -1122,6 +1189,45 @@ static int tvp5150_detach_client(struct i2c_client *c)
return 0; return 0;
} }
static inline int tvp5150_device_init(struct vpfe_capture_params *params)
{
return tvp5150_command(tvp5150_client, VIDIOC_INT_RESET, NULL);
}
static inline int tvp5150_device_cmd(u32 cmd, void *arg)
{
return tvp5150_command(tvp5150_client, cmd, arg);
}
static inline void davinci_enable_sdclk(bool on)
{
s8 enable = (on == true ? 0 : 1);
gpio_direction_output(SD_CAP_GPIO, enable);
gpio_set_value(SD_CAP_GPIO, enable);
}
static inline int tvp5150_device_active(void)
{
/* enable the SD_PCLK */
davinci_enable_sdclk(true);
return 0;
}
static inline int tvp5150_device_deactive(void)
{
/* disable the SD_PCLK */
davinci_enable_sdclk(false);
return 0;
}
static inline int tvp5150_device_cleanup(void)
{
/* do nothing */
return 0;
}
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
static struct i2c_driver driver = { static struct i2c_driver driver = {
...@@ -1136,13 +1242,28 @@ static struct i2c_driver driver = { ...@@ -1136,13 +1242,28 @@ static struct i2c_driver driver = {
.command = tvp5150_command, .command = tvp5150_command,
}; };
static struct vpfe_capture_device tvp5150_device = {
.name = "TVP5150",
.id = VPFE_CAPTURE_ID_TVP5150,
.capture_device_init = tvp5150_device_init,
.capture_device_cmd = tvp5150_device_cmd,
.capture_device_active = tvp5150_device_active,
.capture_device_deactive = tvp5150_device_deactive,
.capture_device_cleanup = tvp5150_device_cleanup,
};
static int __init tvp5150_init(void) static int __init tvp5150_init(void)
{ {
return i2c_add_driver(&driver); i2c_add_driver(&driver);
return vpfe_capture_device_register(&tvp5150_device);
} }
static void __exit tvp5150_exit(void) static void __exit tvp5150_exit(void)
{ {
/* disable the SD_PCLK */
davinci_enable_sdclk(false);
vpfe_capture_device_unregister(&tvp5150_device);
i2c_del_driver(&driver); i2c_del_driver(&driver);
} }
......
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
#endif #endif
#include <media/ccdc_davinci.h> #include <media/ccdc_davinci.h>
#include <media/tvp5146.h>
#define TRUE 1 #define TRUE 1
#define FALSE 0 #define FALSE 0
...@@ -37,7 +36,12 @@ ...@@ -37,7 +36,12 @@
#define VPFE_CMD_CONFIG_CCDC _IOW('V',BASE_VIDIOC_PRIVATE + 1,ccdc_params_ycbcr) #define VPFE_CMD_CONFIG_CCDC _IOW('V',BASE_VIDIOC_PRIVATE + 1,ccdc_params_ycbcr)
#define VPFE_CMD_LATEST_FRM_ONLY _IOW('V',BASE_VIDIOC_PRIVATE + 2,int) #define VPFE_CMD_LATEST_FRM_ONLY _IOW('V',BASE_VIDIOC_PRIVATE + 2,int)
#define VPFE_CMD_CONFIG_TVP5146 _IOW('V',BASE_VIDIOC_PRIVATE + 3,tvp5146_params) #define VPFE_CMD_CONFIG_CAPTURE _IOW('V', BASE_VIDIOC_PRIVATE + 3,\
struct vpfe_capture_params)
#define VPFE_CMD_CAPTURE_ACTIVE _IOW('V', BASE_VIDIOC_PRIVATE + 4, long int)
#define VPFE_AMUX_COMPOSITE 0
#define VPFE_AMUX_SVIDEO 1
/* settings for commonly used video formats */ /* settings for commonly used video formats */
#define VPFE_WIN_NTSC {0,0,720,480} #define VPFE_WIN_NTSC {0,0,720,480}
...@@ -49,6 +53,9 @@ ...@@ -49,6 +53,9 @@
#define VPFE_WIN_QVGA {0,0,320,240} #define VPFE_WIN_QVGA {0,0,320,240}
#define VPFE_WIN_SIF {0,0,352,240} #define VPFE_WIN_SIF {0,0,352,240}
#define VPFE_CAPTURE_ID_TVP5146 0
#define VPFE_CAPTURE_ID_TVP5150 1
#ifdef __KERNEL__ #ifdef __KERNEL__
...@@ -80,6 +87,26 @@ ...@@ -80,6 +87,26 @@
#define VPFE_MAX_FBUF_ORDER \ #define VPFE_MAX_FBUF_ORDER \
get_order(roundup_pow_of_two(VPFE_MAX_FBUF_SIZE)) get_order(roundup_pow_of_two(VPFE_MAX_FBUF_SIZE))
struct vpfe_capture_params{
v4l2_std_id mode;
int amuxmode;
int enablebt656sync;
int squarepixel;
};
struct vpfe_capture_device
{
const char *name;
int id;
struct list_head device_list;
int (*capture_device_init)(struct vpfe_capture_params *param);
int (*capture_device_active)(void);
int (*capture_device_deactive)(void);
int (*capture_device_cmd)(u32 cmd, void *arg);
int (*capture_device_cleanup)(void);
};
/* device object */ /* device object */
typedef struct vpfe_obj { typedef struct vpfe_obj {
struct video_device *video_dev; struct video_device *video_dev;
...@@ -106,7 +133,10 @@ typedef struct vpfe_obj { ...@@ -106,7 +133,10 @@ typedef struct vpfe_obj {
int mode_changed; int mode_changed;
int started; int started;
int field_offset; int field_offset;
tvp5146_params tvp5146_params; struct semaphore device_list_lock;
struct vpfe_capture_params capture_params;
struct list_head capture_device_list;
struct vpfe_capture_device *active_device;
ccdc_params_ycbcr ccdc_params; ccdc_params_ycbcr ccdc_params;
} vpfe_obj; } vpfe_obj;
...@@ -116,6 +146,24 @@ typedef struct vpfe_fh { ...@@ -116,6 +146,24 @@ typedef struct vpfe_fh {
int io_allowed; int io_allowed;
enum v4l2_priority prio; enum v4l2_priority prio;
} vpfe_fh; } vpfe_fh;
/**
* register the capture device
* @param device
* device that to be registered.
* @return int
* 0:sucess, otherwise, failed.
*/
int vpfe_capture_device_register(struct vpfe_capture_device *device);
/**
* unregister the capture device
* @param device
* device that to be unregistered.
* @return int
* 0:sucess, otherwise, failed.
*/
int vpfe_capture_device_unregister(struct vpfe_capture_device *device);
#endif #endif
#endif /* DAVINCI_VPFE_H */ #endif /* DAVINCI_VPFE_H */
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#ifndef _TVP5150_H_ #ifndef _TVP5150_H_
#define _TVP5150_H_ #define _TVP5150_H_
/* VPFE driver */
#include <media/davinci_vpfe.h>
/* TVP5150 HW inputs */ /* TVP5150 HW inputs */
#define TVP5150_COMPOSITE0 0 #define TVP5150_COMPOSITE0 0
......
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