summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2009-02-26 21:02:33 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-02-26 21:02:33 -0300
commiteb20179da88acc42ffee334ce86bacdf77d4a438 (patch)
tree9f2196b723853e3d581b0b87b3f2ce666fc769be /linux/drivers/media/video
parent1e4553680f02af66c3282072f581425637b58f78 (diff)
parent7dab4777ac8eda4056484c99285d58b6b3a91235 (diff)
downloadmediapointer-dvb-s2-eb20179da88acc42ffee334ce86bacdf77d4a438.tar.gz
mediapointer-dvb-s2-eb20179da88acc42ffee334ce86bacdf77d4a438.tar.bz2
merge: http://www.linuxtv.org/hg/~hverkuil/v4l-dvb-zoran
From: Mauro Carvalho Chehab <mchehab@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'linux/drivers/media/video')
-rw-r--r--linux/drivers/media/video/Kconfig7
-rw-r--r--linux/drivers/media/video/Makefile5
-rw-r--r--linux/drivers/media/video/cx18/cx18-av-core.c7
-rw-r--r--linux/drivers/media/video/cx2341x.c108
-rw-r--r--linux/drivers/media/video/cx25840/cx25840-core.c7
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-audio.c2
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-cards.c3
-rw-r--r--linux/drivers/media/video/em28xx/em28xx.h6
-rw-r--r--linux/drivers/media/video/gspca/sonixj.c2
-rw-r--r--linux/drivers/media/video/gspca/zc3xx.c17
-rw-r--r--linux/drivers/media/video/msp3400-driver.c26
-rw-r--r--linux/drivers/media/video/mt9m001.c2
-rw-r--r--linux/drivers/media/video/mt9m111.c8
-rw-r--r--linux/drivers/media/video/mt9t031.c127
-rw-r--r--linux/drivers/media/video/mt9v022.c2
-rw-r--r--linux/drivers/media/video/mx3_camera.c1183
-rw-r--r--linux/drivers/media/video/ov772x.c289
-rw-r--r--linux/drivers/media/video/pxa_camera.c27
-rw-r--r--linux/drivers/media/video/saa7115.c4
-rw-r--r--linux/drivers/media/video/saa7134/saa6752hs.c12
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-empress.c2
-rw-r--r--linux/drivers/media/video/sh_mobile_ceu_camera.c60
-rw-r--r--linux/drivers/media/video/sn9c102/sn9c102_devtable.h2
-rw-r--r--linux/drivers/media/video/tda7432.c6
-rw-r--r--linux/drivers/media/video/tda9875.c3
-rw-r--r--linux/drivers/media/video/tvaudio.c17
-rw-r--r--linux/drivers/media/video/tvp514x.c111
-rw-r--r--linux/drivers/media/video/tw9910.c4
-rw-r--r--linux/drivers/media/video/usbvision/usbvision-core.c2
-rw-r--r--linux/drivers/media/video/usbvision/usbvision-i2c.c147
-rw-r--r--linux/drivers/media/video/usbvision/usbvision-video.c63
-rw-r--r--linux/drivers/media/video/usbvision/usbvision.h8
-rw-r--r--linux/drivers/media/video/uvc/uvc_driver.c9
-rw-r--r--linux/drivers/media/video/uvc/uvc_video.c54
-rw-r--r--linux/drivers/media/video/uvc/uvcvideo.h1
-rw-r--r--linux/drivers/media/video/v4l2-common.c190
36 files changed, 1923 insertions, 600 deletions
diff --git a/linux/drivers/media/video/Kconfig b/linux/drivers/media/video/Kconfig
index e671beb59..bb7df8c18 100644
--- a/linux/drivers/media/video/Kconfig
+++ b/linux/drivers/media/video/Kconfig
@@ -759,6 +759,13 @@ config SOC_CAMERA_OV772X
help
This is a ov772x camera driver
+config VIDEO_MX3
+ tristate "i.MX3x Camera Sensor Interface driver"
+ depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA
+ select VIDEOBUF_DMA_CONTIG
+ ---help---
+ This is a v4l2 driver for the i.MX3x Camera Sensor Interface
+
config VIDEO_PXA27x
tristate "PXA27x Quick Capture Interface driver"
depends on VIDEO_DEV && PXA27x && SOC_CAMERA
diff --git a/linux/drivers/media/video/Makefile b/linux/drivers/media/video/Makefile
index 263c2264d..307490ebc 100644
--- a/linux/drivers/media/video/Makefile
+++ b/linux/drivers/media/video/Makefile
@@ -132,10 +132,11 @@ obj-$(CONFIG_VIDEO_CX18) += cx18/
obj-$(CONFIG_VIDEO_VIVI) += vivi.o
obj-$(CONFIG_VIDEO_CX23885) += cx23885/
-obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
+obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o
+obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o
-obj-$(CONFIG_SOC_CAMERA) += soc_camera.o
+obj-$(CONFIG_SOC_CAMERA) += soc_camera.o
obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o
obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o
diff --git a/linux/drivers/media/video/cx18/cx18-av-core.c b/linux/drivers/media/video/cx18/cx18-av-core.c
index a3bd2c95f..fc576cf1a 100644
--- a/linux/drivers/media/video/cx18/cx18-av-core.c
+++ b/linux/drivers/media/video/cx18/cx18-av-core.c
@@ -788,10 +788,12 @@ int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg)
switch (qc->id) {
case V4L2_CID_BRIGHTNESS:
+ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
case V4L2_CID_CONTRAST:
case V4L2_CID_SATURATION:
+ return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
case V4L2_CID_HUE:
- return v4l2_ctrl_query_fill_std(qc);
+ return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
default:
break;
}
@@ -801,10 +803,11 @@ int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg)
return v4l2_ctrl_query_fill(qc, 0, 65535,
65535 / 100, state->default_volume);
case V4L2_CID_AUDIO_MUTE:
+ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
case V4L2_CID_AUDIO_BALANCE:
case V4L2_CID_AUDIO_BASS:
case V4L2_CID_AUDIO_TREBLE:
- return v4l2_ctrl_query_fill_std(qc);
+ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
default:
return -EINVAL;
}
diff --git a/linux/drivers/media/video/cx2341x.c b/linux/drivers/media/video/cx2341x.c
index 01c4d2d02..2cf0c5fee 100644
--- a/linux/drivers/media/video/cx2341x.c
+++ b/linux/drivers/media/video/cx2341x.c
@@ -501,6 +501,29 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
int err;
switch (qctrl->id) {
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, 1,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
+
+ case V4L2_CID_MPEG_STREAM_VBI_FMT:
+ if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI)
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_STREAM_VBI_FMT_NONE,
+ V4L2_MPEG_STREAM_VBI_FMT_IVTV, 1,
+ V4L2_MPEG_STREAM_VBI_FMT_NONE);
+ return cx2341x_ctrl_query_fill(qctrl,
+ V4L2_MPEG_STREAM_VBI_FMT_NONE,
+ V4L2_MPEG_STREAM_VBI_FMT_NONE, 1,
+ default_params.stream_vbi_fmt);
+
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 1,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
+
case V4L2_CID_MPEG_AUDIO_ENCODING:
if (params->capabilities & CX2341X_CAP_HAS_AC3) {
/*
@@ -532,9 +555,36 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
return 0;
- case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
- case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
- return -EINVAL;
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_MODE_STEREO,
+ V4L2_MPEG_AUDIO_MODE_MONO, 1,
+ V4L2_MPEG_AUDIO_MODE_STEREO);
+
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ err = v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 1,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4);
+ if (err == 0 &&
+ params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return err;
+
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_EMPHASIS_NONE,
+ V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 1,
+ V4L2_MPEG_AUDIO_EMPHASIS_NONE);
+
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_CRC_NONE,
+ V4L2_MPEG_AUDIO_CRC_CRC16, 1,
+ V4L2_MPEG_AUDIO_CRC_NONE);
+
+ case V4L2_CID_MPEG_AUDIO_MUTE:
+ return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
err = v4l2_ctrl_query_fill(qctrl,
@@ -551,13 +601,6 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
return 0;
- case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
- err = v4l2_ctrl_query_fill_std(qctrl);
- if (err == 0 &&
- params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
- qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
- return err;
-
case V4L2_CID_MPEG_VIDEO_ENCODING:
/* this setting is read-only for the cx2341x since the
V4L2_CID_MPEG_STREAM_TYPE really determines the
@@ -570,32 +613,51 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
return err;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_VIDEO_ASPECT_1x1,
+ V4L2_MPEG_VIDEO_ASPECT_221x100, 1,
+ V4L2_MPEG_VIDEO_ASPECT_4x3);
+
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ return v4l2_ctrl_query_fill(qctrl, 0, 33, 1, 2);
+
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ return v4l2_ctrl_query_fill(qctrl, 1, 34, 1,
+ params->is_50hz ? 12 : 15);
+
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1);
+
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
- err = v4l2_ctrl_query_fill_std(qctrl);
+ err = v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
if (err == 0 &&
params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
return err;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000);
+
case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
- err = v4l2_ctrl_query_fill_std(qctrl);
+ err = v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000);
if (err == 0 &&
params->video_bitrate_mode ==
V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
return err;
- case V4L2_CID_MPEG_STREAM_VBI_FMT:
- if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI)
- return v4l2_ctrl_query_fill_std(qctrl);
- return cx2341x_ctrl_query_fill(qctrl,
- V4L2_MPEG_STREAM_VBI_FMT_NONE,
- V4L2_MPEG_STREAM_VBI_FMT_NONE, 1,
- default_params.stream_vbi_fmt);
+ case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+ return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
- case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
- return v4l2_ctrl_query_fill(qctrl, 1, 34, 1,
- params->is_50hz ? 12 : 15);
+ case V4L2_CID_MPEG_VIDEO_MUTE:
+ return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+
+ case V4L2_CID_MPEG_VIDEO_MUTE_YUV: /* Init YUV (really YCbCr) to black */
+ return v4l2_ctrl_query_fill(qctrl, 0, 0xffffff, 1, 0x008080);
/* CX23415/6 specific */
case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
@@ -697,7 +759,7 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
default_params.stream_insert_nav_packets);
default:
- return v4l2_ctrl_query_fill_std(qctrl);
+ return -EINVAL;
}
}
diff --git a/linux/drivers/media/video/cx25840/cx25840-core.c b/linux/drivers/media/video/cx25840/cx25840-core.c
index d70dcd028..921cc96fc 100644
--- a/linux/drivers/media/video/cx25840/cx25840-core.c
+++ b/linux/drivers/media/video/cx25840/cx25840-core.c
@@ -1224,10 +1224,12 @@ static int cx25840_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
switch (qc->id) {
case V4L2_CID_BRIGHTNESS:
+ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
case V4L2_CID_CONTRAST:
case V4L2_CID_SATURATION:
+ return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
case V4L2_CID_HUE:
- return v4l2_ctrl_query_fill_std(qc);
+ return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
default:
break;
}
@@ -1239,10 +1241,11 @@ static int cx25840_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
return v4l2_ctrl_query_fill(qc, 0, 65535,
65535 / 100, state->default_volume);
case V4L2_CID_AUDIO_MUTE:
+ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
case V4L2_CID_AUDIO_BALANCE:
case V4L2_CID_AUDIO_BASS:
case V4L2_CID_AUDIO_TREBLE:
- return v4l2_ctrl_query_fill_std(qc);
+ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
default:
return -EINVAL;
}
diff --git a/linux/drivers/media/video/em28xx/em28xx-audio.c b/linux/drivers/media/video/em28xx/em28xx-audio.c
index bfa3986f5..eb49a1364 100644
--- a/linux/drivers/media/video/em28xx/em28xx-audio.c
+++ b/linux/drivers/media/video/em28xx/em28xx-audio.c
@@ -560,6 +560,8 @@ static int em28xx_audio_init(struct em28xx *dev)
pcm->info_flags = 0;
pcm->private_data = dev;
strcpy(pcm->name, "Empia 28xx Capture");
+
+ snd_card_set_dev(card, &dev->udev->dev);
strcpy(card->driver, "Empia Em28xx Audio");
strcpy(card->shortname, "Em28xx Audio");
strcpy(card->longname, "Empia Em28xx Audio");
diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c
index 5af4c417a..bab6340da 100644
--- a/linux/drivers/media/video/em28xx/em28xx-cards.c
+++ b/linux/drivers/media/video/em28xx/em28xx-cards.c
@@ -1309,6 +1309,7 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_LG_PAL_NEW_TAPC,
.tda9887_conf = TDA9887_PRESENT,
.decoder = EM28XX_TVP5150,
+ .adecoder = EM28XX_TVAUDIO,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
@@ -1986,6 +1987,8 @@ void em28xx_card_setup(struct em28xx *dev)
request_module("tvp5150");
if (dev->board.tuner_type != TUNER_ABSENT)
request_module("tuner");
+ if (dev->board.adecoder == EM28XX_TVAUDIO)
+ request_module("tvaudio");
#endif
em28xx_config_tuner(dev);
diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h
index 4aebda6c7..e21f29b99 100644
--- a/linux/drivers/media/video/em28xx/em28xx.h
+++ b/linux/drivers/media/video/em28xx/em28xx.h
@@ -358,6 +358,11 @@ enum em28xx_decoder {
EM28XX_SAA711X,
};
+enum em28xx_adecoder {
+ EM28XX_NOADECODER = 0,
+ EM28XX_TVAUDIO,
+};
+
struct em28xx_board {
char *name;
int vchannels;
@@ -383,6 +388,7 @@ struct em28xx_board {
unsigned char xclk, i2c_speed;
enum em28xx_decoder decoder;
+ enum em28xx_adecoder adecoder;
struct em28xx_input input[MAX_EM28XX_INPUT];
struct em28xx_input radio;
diff --git a/linux/drivers/media/video/gspca/sonixj.c b/linux/drivers/media/video/gspca/sonixj.c
index 5cdb643b8..36d6f50be 100644
--- a/linux/drivers/media/video/gspca/sonixj.c
+++ b/linux/drivers/media/video/gspca/sonixj.c
@@ -2199,9 +2199,9 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x21)},
#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x613b), BSI(SN9C120, OV7660, 0x21)},
+#endif
{USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)},
/* {USB_DEVICE(0x0c45, 0x613e), BSI(SN9C120, OV7630, 0x??)}, */
-#endif
{USB_DEVICE(0x0c45, 0x6143), BSI(SN9C120, SP80708, 0x18)},
{}
};
diff --git a/linux/drivers/media/video/gspca/zc3xx.c b/linux/drivers/media/video/gspca/zc3xx.c
index b93573f66..ad385b9a0 100644
--- a/linux/drivers/media/video/gspca/zc3xx.c
+++ b/linux/drivers/media/video/gspca/zc3xx.c
@@ -7016,7 +7016,7 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
static int zcxx_probeSensor(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int sensor, sensor2;
+ int sensor;
switch (sd->sensor) {
case SENSOR_MC501CB:
@@ -7031,16 +7031,9 @@ static int zcxx_probeSensor(struct gspca_dev *gspca_dev)
break;
}
sensor = vga_2wr_probe(gspca_dev);
- if (sensor >= 0) {
- if (sensor < 0x7600)
- return sensor;
- /* next probe is needed for OmniVision ? */
- }
- sensor2 = vga_3wr_probe(gspca_dev);
- if (sensor2 >= 0
- && sensor >= 0)
+ if (sensor >= 0)
return sensor;
- return sensor2;
+ return vga_3wr_probe(gspca_dev);
}
/* this function is called at probe time */
@@ -7177,6 +7170,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
PDEBUG(D_PROBE, "Find Sensor OV7620");
sd->sensor = SENSOR_OV7620;
break;
+ case 0x7631:
+ PDEBUG(D_PROBE, "Find Sensor OV7630C");
+ sd->sensor = SENSOR_OV7630C;
+ break;
case 0x7648:
PDEBUG(D_PROBE, "Find Sensor OV7648");
sd->sensor = SENSOR_OV7620; /* same sensor (?) */
diff --git a/linux/drivers/media/video/msp3400-driver.c b/linux/drivers/media/video/msp3400-driver.c
index 053f168bf..61b54317f 100644
--- a/linux/drivers/media/video/msp3400-driver.c
+++ b/linux/drivers/media/video/msp3400-driver.c
@@ -718,22 +718,24 @@ static int msp_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
struct msp_state *state = to_state(sd);
switch (qc->id) {
- case V4L2_CID_AUDIO_VOLUME:
- case V4L2_CID_AUDIO_MUTE:
- return v4l2_ctrl_query_fill_std(qc);
- default:
- break;
+ case V4L2_CID_AUDIO_VOLUME:
+ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
+ case V4L2_CID_AUDIO_MUTE:
+ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
+ default:
+ break;
}
if (!state->has_sound_processing)
return -EINVAL;
switch (qc->id) {
- case V4L2_CID_AUDIO_LOUDNESS:
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- return v4l2_ctrl_query_fill_std(qc);
- default:
- return -EINVAL;
+ case V4L2_CID_AUDIO_LOUDNESS:
+ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
+ default:
+ return -EINVAL;
}
return 0;
}
diff --git a/linux/drivers/media/video/mt9m001.c b/linux/drivers/media/video/mt9m001.c
index 3d8e6ed8d..c2e52100a 100644
--- a/linux/drivers/media/video/mt9m001.c
+++ b/linux/drivers/media/video/mt9m001.c
@@ -276,7 +276,7 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
/* MT9M001 has all capture_format parameters fixed */
unsigned long flags = SOCAM_DATAWIDTH_10 | SOCAM_PCLK_SAMPLE_RISING |
SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
- SOCAM_MASTER;
+ SOCAM_DATA_ACTIVE_HIGH | SOCAM_MASTER;
if (bus_switch_possible(mt9m001))
flags |= SOCAM_DATAWIDTH_8;
diff --git a/linux/drivers/media/video/mt9m111.c b/linux/drivers/media/video/mt9m111.c
index cdf3f38e2..3ae675a42 100644
--- a/linux/drivers/media/video/mt9m111.c
+++ b/linux/drivers/media/video/mt9m111.c
@@ -393,6 +393,8 @@ static int mt9m111_disable(struct soc_camera_device *icd)
static int mt9m111_reset(struct soc_camera_device *icd)
{
+ struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+ struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
int ret;
ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
@@ -401,6 +403,10 @@ static int mt9m111_reset(struct soc_camera_device *icd)
if (!ret)
ret = reg_clear(RESET, MT9M111_RESET_RESET_MODE
| MT9M111_RESET_RESET_SOC);
+
+ if (icl->reset)
+ icl->reset(&mt9m111->client->dev);
+
return ret;
}
@@ -420,7 +426,7 @@ static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd)
struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
unsigned long flags = SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING |
SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
- SOCAM_DATAWIDTH_8;
+ SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8;
return soc_camera_apply_sensor_flags(icl, flags);
}
diff --git a/linux/drivers/media/video/mt9t031.c b/linux/drivers/media/video/mt9t031.c
index dd5bd9dd0..aa0e8ec34 100644
--- a/linux/drivers/media/video/mt9t031.c
+++ b/linux/drivers/media/video/mt9t031.c
@@ -150,7 +150,7 @@ static int mt9t031_init(struct soc_camera_device *icd)
if (ret >= 0)
ret = reg_write(icd, MT9T031_RESET, 0);
if (ret >= 0)
- ret = reg_clear(icd, MT9T031_OUTPUT_CONTROL, 3);
+ ret = reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2);
return ret >= 0 ? 0 : -EIO;
}
@@ -158,14 +158,14 @@ static int mt9t031_init(struct soc_camera_device *icd)
static int mt9t031_release(struct soc_camera_device *icd)
{
/* Disable the chip */
- reg_clear(icd, MT9T031_OUTPUT_CONTROL, 3);
+ reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2);
return 0;
}
static int mt9t031_start_capture(struct soc_camera_device *icd)
{
/* Switch to master "normal" mode */
- if (reg_set(icd, MT9T031_OUTPUT_CONTROL, 3) < 0)
+ if (reg_set(icd, MT9T031_OUTPUT_CONTROL, 2) < 0)
return -EIO;
return 0;
}
@@ -173,7 +173,7 @@ static int mt9t031_start_capture(struct soc_camera_device *icd)
static int mt9t031_stop_capture(struct soc_camera_device *icd)
{
/* Stop sensor readout */
- if (reg_clear(icd, MT9T031_OUTPUT_CONTROL, 3) < 0)
+ if (reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2) < 0)
return -EIO;
return 0;
}
@@ -201,6 +201,18 @@ static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd)
return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM);
}
+/* Round up minima and round down maxima */
+static void recalculate_limits(struct soc_camera_device *icd,
+ u16 xskip, u16 yskip)
+{
+ icd->x_min = (MT9T031_COLUMN_SKIP + xskip - 1) / xskip;
+ icd->y_min = (MT9T031_ROW_SKIP + yskip - 1) / yskip;
+ icd->width_min = (MT9T031_MIN_WIDTH + xskip - 1) / xskip;
+ icd->height_min = (MT9T031_MIN_HEIGHT + yskip - 1) / yskip;
+ icd->width_max = MT9T031_MAX_WIDTH / xskip;
+ icd->height_max = MT9T031_MAX_HEIGHT / yskip;
+}
+
static int mt9t031_set_fmt(struct soc_camera_device *icd,
__u32 pixfmt, struct v4l2_rect *rect)
{
@@ -208,54 +220,70 @@ static int mt9t031_set_fmt(struct soc_camera_device *icd,
int ret;
const u16 hblank = MT9T031_HORIZONTAL_BLANK,
vblank = MT9T031_VERTICAL_BLANK;
- u16 xbin, xskip = mt9t031->xskip, ybin, yskip = mt9t031->yskip,
- width = rect->width * xskip, height = rect->height * yskip;
+ u16 xbin, xskip, ybin, yskip, width, height, left, top;
if (pixfmt) {
- /* S_FMT - use binning and skipping for scaling, recalculate */
+ /*
+ * try_fmt has put rectangle within limits.
+ * S_FMT - use binning and skipping for scaling, recalculate
+ * limits, used for cropping
+ */
/* Is this more optimal than just a division? */
for (xskip = 8; xskip > 1; xskip--)
- if (rect->width * xskip <= icd->width_max)
+ if (rect->width * xskip <= MT9T031_MAX_WIDTH)
break;
for (yskip = 8; yskip > 1; yskip--)
- if (rect->height * yskip <= icd->height_max)
+ if (rect->height * yskip <= MT9T031_MAX_HEIGHT)
break;
- width = rect->width * xskip;
- height = rect->height * yskip;
-
- dev_dbg(&icd->dev, "xskip %u, width %u, yskip %u, height %u\n",
- xskip, width, yskip, height);
+ recalculate_limits(icd, xskip, yskip);
+ } else {
+ /* CROP - no change in scaling, or in limits */
+ xskip = mt9t031->xskip;
+ yskip = mt9t031->yskip;
}
+ /* Make sure we don't exceed sensor limits */
+ if (rect->left + rect->width > icd->width_max)
+ rect->left = (icd->width_max - rect->width) / 2 + icd->x_min;
+
+ if (rect->top + rect->height > icd->height_max)
+ rect->top = (icd->height_max - rect->height) / 2 + icd->y_min;
+
+ width = rect->width * xskip;
+ height = rect->height * yskip;
+ left = rect->left * xskip;
+ top = rect->top * yskip;
+
xbin = min(xskip, (u16)3);
ybin = min(yskip, (u16)3);
- /* Make sure we don't exceed frame limits */
- if (rect->left + width > icd->width_max)
- rect->left = (icd->width_max - width) / 2;
+ dev_dbg(&icd->dev, "xskip %u, width %u/%u, yskip %u, height %u/%u\n",
+ xskip, width, rect->width, yskip, height, rect->height);
- if (rect->top + height > icd->height_max)
- rect->top = (icd->height_max - height) / 2;
-
- /* Could just do roundup(rect->left, [xy]bin); but this is cheaper */
+ /* Could just do roundup(rect->left, [xy]bin * 2); but this is cheaper */
switch (xbin) {
case 2:
- rect->left = (rect->left + 1) & ~1;
+ left = (left + 3) & ~3;
break;
case 3:
- rect->left = roundup(rect->left, 3);
+ left = roundup(left, 6);
}
switch (ybin) {
case 2:
- rect->top = (rect->top + 1) & ~1;
+ top = (top + 3) & ~3;
break;
case 3:
- rect->top = roundup(rect->top, 3);
+ top = roundup(top, 6);
}
+ /* Disable register update, reconfigure atomically */
+ ret = reg_set(icd, MT9T031_OUTPUT_CONTROL, 1);
+ if (ret < 0)
+ return ret;
+
/* Blanking and start values - default... */
ret = reg_write(icd, MT9T031_HORIZONTAL_BLANKING, hblank);
if (ret >= 0)
@@ -270,14 +298,14 @@ static int mt9t031_set_fmt(struct soc_camera_device *icd,
ret = reg_write(icd, MT9T031_ROW_ADDRESS_MODE,
((ybin - 1) << 4) | (yskip - 1));
}
- dev_dbg(&icd->dev, "new left %u, top %u\n", rect->left, rect->top);
+ dev_dbg(&icd->dev, "new physical left %u, top %u\n", left, top);
/* The caller provides a supported format, as guaranteed by
* icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() */
if (ret >= 0)
- ret = reg_write(icd, MT9T031_COLUMN_START, rect->left);
+ ret = reg_write(icd, MT9T031_COLUMN_START, left);
if (ret >= 0)
- ret = reg_write(icd, MT9T031_ROW_START, rect->top);
+ ret = reg_write(icd, MT9T031_ROW_START, top);
if (ret >= 0)
ret = reg_write(icd, MT9T031_WINDOW_WIDTH, width - 1);
if (ret >= 0)
@@ -302,6 +330,9 @@ static int mt9t031_set_fmt(struct soc_camera_device *icd,
mt9t031->yskip = yskip;
}
+ /* Re-enable register update, commit all changes */
+ reg_clear(icd, MT9T031_OUTPUT_CONTROL, 1);
+
return ret < 0 ? ret : 0;
}
@@ -310,14 +341,14 @@ static int mt9t031_try_fmt(struct soc_camera_device *icd,
{
struct v4l2_pix_format *pix = &f->fmt.pix;
- if (pix->height < icd->height_min)
- pix->height = icd->height_min;
- if (pix->height > icd->height_max)
- pix->height = icd->height_max;
- if (pix->width < icd->width_min)
- pix->width = icd->width_min;
- if (pix->width > icd->width_max)
- pix->width = icd->width_max;
+ if (pix->height < MT9T031_MIN_HEIGHT)
+ pix->height = MT9T031_MIN_HEIGHT;
+ if (pix->height > MT9T031_MAX_HEIGHT)
+ pix->height = MT9T031_MAX_HEIGHT;
+ if (pix->width < MT9T031_MIN_WIDTH)
+ pix->width = MT9T031_MIN_WIDTH;
+ if (pix->width > MT9T031_MAX_WIDTH)
+ pix->width = MT9T031_MAX_WIDTH;
pix->width &= ~0x01; /* has to be even */
pix->height &= ~0x01; /* has to be even */
@@ -390,6 +421,14 @@ static const struct v4l2_queryctrl mt9t031_controls[] = {
.step = 1,
.default_value = 0,
}, {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Flip Horizontally",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ }, {
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Gain",
@@ -513,21 +552,23 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
if (data < 0)
return -EIO;
} else {
- /* Pack it into 1.125..15 variable step, register values 9..67 */
+ /* Pack it into 1.125..128 variable step, register values 9..0x7860 */
/* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */
unsigned long range = qctrl->maximum - qctrl->default_value - 1;
+ /* calculated gain: map 65..127 to 9..1024 step 0.125 */
unsigned long gain = ((ctrl->value - qctrl->default_value - 1) *
- 111 + range / 2) / range + 9;
+ 1015 + range / 2) / range + 9;
- if (gain <= 32)
+ if (gain <= 32) /* calculated gain 9..32 -> 9..32 */
data = gain;
- else if (gain <= 64)
+ else if (gain <= 64) /* calculated gain 33..64 -> 0x51..0x60 */
data = ((gain - 32) * 16 + 16) / 32 + 80;
else
- data = ((gain - 64) * 7 + 28) / 56 + 96;
+ /* calculated gain 65..1024 -> (1..120) << 8 + 0x60 */
+ data = (((gain - 64 + 7) * 32) & 0xff00) | 0x60;
- dev_dbg(&icd->dev, "Setting gain from %d to %d\n",
- reg_read(icd, MT9T031_GLOBAL_GAIN), data);
+ dev_dbg(&icd->dev, "Setting gain from 0x%x to 0x%x\n",
+ reg_read(icd, MT9T031_GLOBAL_GAIN), data);
data = reg_write(icd, MT9T031_GLOBAL_GAIN, data);
if (data < 0)
return -EIO;
diff --git a/linux/drivers/media/video/mt9v022.c b/linux/drivers/media/video/mt9v022.c
index 9601884ca..59efb8ff0 100644
--- a/linux/drivers/media/video/mt9v022.c
+++ b/linux/drivers/media/video/mt9v022.c
@@ -336,7 +336,7 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
return SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING |
SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW |
SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW |
- SOCAM_MASTER | SOCAM_SLAVE |
+ SOCAM_DATA_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_SLAVE |
width_flag;
}
diff --git a/linux/drivers/media/video/mx3_camera.c b/linux/drivers/media/video/mx3_camera.c
new file mode 100644
index 000000000..f525dc48f
--- /dev/null
+++ b/linux/drivers/media/video/mx3_camera.c
@@ -0,0 +1,1183 @@
+/*
+ * V4L2 Driver for i.MX3x camera host
+ *
+ * Copyright (C) 2008
+ * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/videobuf-dma-contig.h>
+#include <media/soc_camera.h>
+
+#include <mach/ipu.h>
+#include <mach/mx3_camera.h>
+
+#define MX3_CAM_DRV_NAME "mx3-camera"
+
+/* CMOS Sensor Interface Registers */
+#define CSI_REG_START 0x60
+
+#define CSI_SENS_CONF (0x60 - CSI_REG_START)
+#define CSI_SENS_FRM_SIZE (0x64 - CSI_REG_START)
+#define CSI_ACT_FRM_SIZE (0x68 - CSI_REG_START)
+#define CSI_OUT_FRM_CTRL (0x6C - CSI_REG_START)
+#define CSI_TST_CTRL (0x70 - CSI_REG_START)
+#define CSI_CCIR_CODE_1 (0x74 - CSI_REG_START)
+#define CSI_CCIR_CODE_2 (0x78 - CSI_REG_START)
+#define CSI_CCIR_CODE_3 (0x7C - CSI_REG_START)
+#define CSI_FLASH_STROBE_1 (0x80 - CSI_REG_START)
+#define CSI_FLASH_STROBE_2 (0x84 - CSI_REG_START)
+
+#define CSI_SENS_CONF_VSYNC_POL_SHIFT 0
+#define CSI_SENS_CONF_HSYNC_POL_SHIFT 1
+#define CSI_SENS_CONF_DATA_POL_SHIFT 2
+#define CSI_SENS_CONF_PIX_CLK_POL_SHIFT 3
+#define CSI_SENS_CONF_SENS_PRTCL_SHIFT 4
+#define CSI_SENS_CONF_SENS_CLKSRC_SHIFT 7
+#define CSI_SENS_CONF_DATA_FMT_SHIFT 8
+#define CSI_SENS_CONF_DATA_WIDTH_SHIFT 10
+#define CSI_SENS_CONF_EXT_VSYNC_SHIFT 15
+#define CSI_SENS_CONF_DIVRATIO_SHIFT 16
+
+#define CSI_SENS_CONF_DATA_FMT_RGB_YUV444 (0UL << CSI_SENS_CONF_DATA_FMT_SHIFT)
+#define CSI_SENS_CONF_DATA_FMT_YUV422 (2UL << CSI_SENS_CONF_DATA_FMT_SHIFT)
+#define CSI_SENS_CONF_DATA_FMT_BAYER (3UL << CSI_SENS_CONF_DATA_FMT_SHIFT)
+
+#define MAX_VIDEO_MEM 16
+
+struct mx3_camera_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+ const struct soc_camera_data_format *fmt;
+
+ /* One descriptot per scatterlist (per frame) */
+ struct dma_async_tx_descriptor *txd;
+
+ /* We have to "build" a scatterlist ourselves - one element per frame */
+ struct scatterlist sg;
+};
+
+/**
+ * struct mx3_camera_dev - i.MX3x camera (CSI) object
+ * @dev: camera device, to which the coherent buffer is attached
+ * @icd: currently attached camera sensor
+ * @clk: pointer to clock
+ * @base: remapped register base address
+ * @pdata: platform data
+ * @platform_flags: platform flags
+ * @mclk: master clock frequency in Hz
+ * @capture: list of capture videobuffers
+ * @lock: protects video buffer lists
+ * @active: active video buffer
+ * @idmac_channel: array of pointers to IPU DMAC DMA channels
+ * @soc_host: embedded soc_host object
+ */
+struct mx3_camera_dev {
+ struct device *dev;
+ /*
+ * i.MX3x is only supposed to handle one camera on its Camera Sensor
+ * Interface. If anyone ever builds hardware to enable more than one
+ * camera _simultaneously_, they will have to modify this driver too
+ */
+ struct soc_camera_device *icd;
+ struct clk *clk;
+
+ void __iomem *base;
+
+ struct mx3_camera_pdata *pdata;
+
+ unsigned long platform_flags;
+ unsigned long mclk;
+
+ struct list_head capture;
+ spinlock_t lock; /* Protects video buffer lists */
+ struct mx3_camera_buffer *active;
+
+ /* IDMAC / dmaengine interface */
+ struct idmac_channel *idmac_channel[1]; /* We need one channel */
+
+ struct soc_camera_host soc_host;
+};
+
+struct dma_chan_request {
+ struct mx3_camera_dev *mx3_cam;
+ enum ipu_channel id;
+};
+
+static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt);
+
+static u32 csi_reg_read(struct mx3_camera_dev *mx3, off_t reg)
+{
+ return __raw_readl(mx3->base + reg);
+}
+
+static void csi_reg_write(struct mx3_camera_dev *mx3, u32 value, off_t reg)
+{
+ __raw_writel(value, mx3->base + reg);
+}
+
+/* Called from the IPU IDMAC ISR */
+static void mx3_cam_dma_done(void *arg)
+{
+ struct idmac_tx_desc *desc = to_tx_desc(arg);
+ struct dma_chan *chan = desc->txd.chan;
+ struct idmac_channel *ichannel = to_idmac_chan(chan);
+ struct mx3_camera_dev *mx3_cam = ichannel->client;
+ struct videobuf_buffer *vb;
+
+ dev_dbg(chan->device->dev, "callback cookie %d, active DMA 0x%08x\n",
+ desc->txd.cookie, mx3_cam->active ? sg_dma_address(&mx3_cam->active->sg) : 0);
+
+ spin_lock(&mx3_cam->lock);
+ if (mx3_cam->active) {
+ vb = &mx3_cam->active->vb;
+
+ list_del_init(&vb->queue);
+ vb->state = VIDEOBUF_DONE;
+ do_gettimeofday(&vb->ts);
+ vb->field_count++;
+ wake_up(&vb->done);
+ }
+
+ if (list_empty(&mx3_cam->capture)) {
+ mx3_cam->active = NULL;
+ spin_unlock(&mx3_cam->lock);
+
+ /*
+ * stop capture - without further buffers IPU_CHA_BUF0_RDY will
+ * not get updated
+ */
+ return;
+ }
+
+ mx3_cam->active = list_entry(mx3_cam->capture.next,
+ struct mx3_camera_buffer, vb.queue);
+ mx3_cam->active->vb.state = VIDEOBUF_ACTIVE;
+ spin_unlock(&mx3_cam->lock);
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct mx3_camera_buffer *buf)
+{
+ struct soc_camera_device *icd = vq->priv_data;
+ struct videobuf_buffer *vb = &buf->vb;
+ struct dma_async_tx_descriptor *txd = buf->txd;
+ struct idmac_channel *ichan;
+
+ BUG_ON(in_interrupt());
+
+ dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ vb, vb->baddr, vb->bsize);
+
+ /*
+ * This waits until this buffer is out of danger, i.e., until it is no
+ * longer in STATE_QUEUED or STATE_ACTIVE
+ */
+ videobuf_waiton(vb, 0, 0);
+ if (txd) {
+ ichan = to_idmac_chan(txd->chan);
+ async_tx_ack(txd);
+ }
+ videobuf_dma_contig_free(vq, vb);
+ buf->txd = NULL;
+
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+/*
+ * Videobuf operations
+ */
+
+/*
+ * Calculate the __buffer__ (not data) size and number of buffers.
+ * Called with .vb_lock held
+ */
+static int mx3_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct soc_camera_device *icd = vq->priv_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct mx3_camera_dev *mx3_cam = ici->priv;
+ /*
+ * bits-per-pixel (depth) as specified in camera's pixel format does
+ * not necessarily match what the camera interface writes to RAM, but
+ * it should be good enough for now.
+ */
+ unsigned int bpp = DIV_ROUND_UP(icd->current_fmt->depth, 8);
+
+ if (!mx3_cam->idmac_channel[0])
+ return -EINVAL;
+
+ *size = icd->width * icd->height * bpp;
+
+ if (!*count)
+ *count = 32;
+
+ if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
+ *count = MAX_VIDEO_MEM * 1024 * 1024 / *size;
+
+ return 0;
+}
+
+/* Called with .vb_lock held */
+static int mx3_videobuf_prepare(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb, enum v4l2_field field)
+{
+ struct soc_camera_device *icd = vq->priv_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct mx3_camera_dev *mx3_cam = ici->priv;
+ struct mx3_camera_buffer *buf =
+ container_of(vb, struct mx3_camera_buffer, vb);
+ /* current_fmt _must_ always be set */
+ size_t new_size = icd->width * icd->height *
+ ((icd->current_fmt->depth + 7) >> 3);
+ int ret;
+
+ /*
+ * I think, in buf_prepare you only have to protect global data,
+ * the actual buffer is yours
+ */
+
+ if (buf->fmt != icd->current_fmt ||
+ vb->width != icd->width ||
+ vb->height != icd->height ||
+ vb->field != field) {
+ buf->fmt = icd->current_fmt;
+ vb->width = icd->width;
+ vb->height = icd->height;
+ vb->field = field;
+ if (vb->state != VIDEOBUF_NEEDS_INIT)
+ free_buffer(vq, buf);
+ }
+
+ if (vb->baddr && vb->bsize < new_size) {
+ /* User provided buffer, but it is too small */
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
+ struct scatterlist *sg = &buf->sg;
+
+ /*
+ * The total size of video-buffers that will be allocated / mapped.
+ * *size that we calculated in videobuf_setup gets assigned to
+ * vb->bsize, and now we use the same calculation to get vb->size.
+ */
+ vb->size = new_size;
+
+ /* This actually (allocates and) maps buffers */
+ ret = videobuf_iolock(vq, vb, NULL);
+ if (ret)
+ goto fail;
+
+ /*
+ * We will have to configure the IDMAC channel. It has two slots
+ * for DMA buffers, we shall enter the first two buffers there,
+ * and then submit new buffers in DMA-ready interrupts
+ */
+ sg_init_table(sg, 1);
+ sg_dma_address(sg) = videobuf_to_dma_contig(vb);
+ sg_dma_len(sg) = vb->size;
+
+ buf->txd = ichan->dma_chan.device->device_prep_slave_sg(
+ &ichan->dma_chan, sg, 1, DMA_FROM_DEVICE,
+ DMA_PREP_INTERRUPT);
+ if (!buf->txd) {
+ ret = -EIO;
+ goto fail;
+ }
+
+ buf->txd->callback_param = buf->txd;
+ buf->txd->callback = mx3_cam_dma_done;
+
+ vb->state = VIDEOBUF_PREPARED;
+ }
+
+ return 0;
+
+fail:
+ free_buffer(vq, buf);
+out:
+ return ret;
+}
+
+static enum pixel_fmt fourcc_to_ipu_pix(__u32 fourcc)
+{
+ /* Add more formats as need arises and test possibilities appear... */
+ switch (fourcc) {
+ case V4L2_PIX_FMT_RGB565:
+ return IPU_PIX_FMT_RGB565;
+ case V4L2_PIX_FMT_RGB24:
+ return IPU_PIX_FMT_RGB24;
+ case V4L2_PIX_FMT_RGB332:
+ return IPU_PIX_FMT_RGB332;
+ case V4L2_PIX_FMT_YUV422P:
+ return IPU_PIX_FMT_YVU422P;
+ default:
+ return IPU_PIX_FMT_GENERIC;
+ }
+}
+
+/* Called with .vb_lock held */
+static void mx3_videobuf_queue(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct soc_camera_device *icd = vq->priv_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct mx3_camera_dev *mx3_cam = ici->priv;
+ struct mx3_camera_buffer *buf =
+ container_of(vb, struct mx3_camera_buffer, vb);
+ struct dma_async_tx_descriptor *txd = buf->txd;
+ struct idmac_channel *ichan = to_idmac_chan(txd->chan);
+ struct idmac_video_param *video = &ichan->params.video;
+ const struct soc_camera_data_format *data_fmt = icd->current_fmt;
+ dma_cookie_t cookie;
+ unsigned long flags;
+
+ /* This is the configuration of one sg-element */
+ video->out_pixel_fmt = fourcc_to_ipu_pix(data_fmt->fourcc);
+ video->out_width = icd->width;
+ video->out_height = icd->height;
+ video->out_stride = icd->width;
+
+#ifdef DEBUG
+ /* helps to see what DMA actually has written */
+ memset((void *)vb->baddr, 0xaa, vb->bsize);
+#endif
+
+ spin_lock_irqsave(&mx3_cam->lock, flags);
+
+ list_add_tail(&vb->queue, &mx3_cam->capture);
+
+ if (!mx3_cam->active) {
+ mx3_cam->active = buf;
+ vb->state = VIDEOBUF_ACTIVE;
+ } else {
+ vb->state = VIDEOBUF_QUEUED;
+ }
+
+ spin_unlock_irqrestore(&mx3_cam->lock, flags);
+
+ cookie = txd->tx_submit(txd);
+ dev_dbg(&icd->dev, "Submitted cookie %d DMA 0x%08x\n", cookie, sg_dma_address(&buf->sg));
+ if (cookie >= 0)
+ return;
+
+ /* Submit error */
+ vb->state = VIDEOBUF_PREPARED;
+
+ spin_lock_irqsave(&mx3_cam->lock, flags);
+
+ list_del_init(&vb->queue);
+
+ if (mx3_cam->active == buf)
+ mx3_cam->active = NULL;
+
+ spin_unlock_irqrestore(&mx3_cam->lock, flags);
+}
+
+/* Called with .vb_lock held */
+static void mx3_videobuf_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct soc_camera_device *icd = vq->priv_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct mx3_camera_dev *mx3_cam = ici->priv;
+ struct mx3_camera_buffer *buf =
+ container_of(vb, struct mx3_camera_buffer, vb);
+ unsigned long flags;
+
+ dev_dbg(&icd->dev, "Release%s DMA 0x%08x (state %d), queue %sempty\n",
+ mx3_cam->active == buf ? " active" : "", sg_dma_address(&buf->sg),
+ vb->state, list_empty(&vb->queue) ? "" : "not ");
+ spin_lock_irqsave(&mx3_cam->lock, flags);
+ if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) &&
+ !list_empty(&vb->queue)) {
+ vb->state = VIDEOBUF_ERROR;
+
+ list_del_init(&vb->queue);
+ if (mx3_cam->active == buf)
+ mx3_cam->active = NULL;
+ }
+ spin_unlock_irqrestore(&mx3_cam->lock, flags);
+ free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops mx3_videobuf_ops = {
+ .buf_setup = mx3_videobuf_setup,
+ .buf_prepare = mx3_videobuf_prepare,
+ .buf_queue = mx3_videobuf_queue,
+ .buf_release = mx3_videobuf_release,
+};
+
+static void mx3_camera_init_videobuf(struct videobuf_queue *q,
+ struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct mx3_camera_dev *mx3_cam = ici->priv;
+
+ videobuf_queue_dma_contig_init(q, &mx3_videobuf_ops, mx3_cam->dev,
+ &mx3_cam->lock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_NONE,
+ sizeof(struct mx3_camera_buffer), icd);
+}
+
+/* First part of ipu_csi_init_interface() */
+static void mx3_camera_activate(struct mx3_camera_dev *mx3_cam,
+ struct soc_camera_device *icd)
+{
+ u32 conf;
+ long rate;
+
+ /* Set default size: ipu_csi_set_window_size() */
+ csi_reg_write(mx3_cam, (640 - 1) | ((480 - 1) << 16), CSI_ACT_FRM_SIZE);
+ /* ...and position to 0:0: ipu_csi_set_window_pos() */
+ conf = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000;
+ csi_reg_write(mx3_cam, conf, CSI_OUT_FRM_CTRL);
+
+ /* We use only gated clock synchronisation mode so far */
+ conf = 0 << CSI_SENS_CONF_SENS_PRTCL_SHIFT;
+
+ /* Set generic data, platform-biggest bus-width */
+ conf |= CSI_SENS_CONF_DATA_FMT_BAYER;
+
+ if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15)
+ conf |= 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+ else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10)
+ conf |= 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+ else if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8)
+ conf |= 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+ else/* if (mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4)*/
+ conf |= 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+
+ if (mx3_cam->platform_flags & MX3_CAMERA_CLK_SRC)
+ conf |= 1 << CSI_SENS_CONF_SENS_CLKSRC_SHIFT;
+ if (mx3_cam->platform_flags & MX3_CAMERA_EXT_VSYNC)
+ conf |= 1 << CSI_SENS_CONF_EXT_VSYNC_SHIFT;
+ if (mx3_cam->platform_flags & MX3_CAMERA_DP)
+ conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT;
+ if (mx3_cam->platform_flags & MX3_CAMERA_PCP)
+ conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT;
+ if (mx3_cam->platform_flags & MX3_CAMERA_HSP)
+ conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT;
+ if (mx3_cam->platform_flags & MX3_CAMERA_VSP)
+ conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT;
+
+ /* ipu_csi_init_interface() */
+ csi_reg_write(mx3_cam, conf, CSI_SENS_CONF);
+
+ clk_enable(mx3_cam->clk);
+ rate = clk_round_rate(mx3_cam->clk, mx3_cam->mclk);
+ dev_dbg(&icd->dev, "Set SENS_CONF to %x, rate %ld\n", conf, rate);
+ if (rate)
+ clk_set_rate(mx3_cam->clk, rate);
+}
+
+/* Called with .video_lock held */
+static int mx3_camera_add_device(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct mx3_camera_dev *mx3_cam = ici->priv;
+ int ret;
+
+ if (mx3_cam->icd) {
+ ret = -EBUSY;
+ goto ebusy;
+ }
+
+ mx3_camera_activate(mx3_cam, icd);
+ ret = icd->ops->init(icd);
+ if (ret < 0) {
+ clk_disable(mx3_cam->clk);
+ goto einit;
+ }
+
+ mx3_cam->icd = icd;
+
+einit:
+ebusy:
+ if (!ret)
+ dev_info(&icd->dev, "MX3 Camera driver attached to camera %d\n",
+ icd->devnum);
+
+ return ret;
+}
+
+/* Called with .video_lock held */
+static void mx3_camera_remove_device(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct mx3_camera_dev *mx3_cam = ici->priv;
+ struct idmac_channel **ichan = &mx3_cam->idmac_channel[0];
+
+ BUG_ON(icd != mx3_cam->icd);
+
+ if (*ichan) {
+ dma_release_channel(&(*ichan)->dma_chan);
+ *ichan = NULL;
+ }
+
+ icd->ops->release(icd);
+
+ clk_disable(mx3_cam->clk);
+
+ mx3_cam->icd = NULL;
+
+ dev_info(&icd->dev, "MX3 Camera driver detached from camera %d\n",
+ icd->devnum);
+}
+
+static bool channel_change_requested(struct soc_camera_device *icd,
+ const struct soc_camera_format_xlate *xlate,
+ __u32 pixfmt, struct v4l2_rect *rect)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct mx3_camera_dev *mx3_cam = ici->priv;
+ struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
+
+ /* So far only one configuration is supported */
+ return pixfmt || (ichan && rect->width * rect->height >
+ icd->width * icd->height);
+}
+
+static int test_platform_param(struct mx3_camera_dev *mx3_cam,
+ unsigned char buswidth, unsigned long *flags)
+{
+ /*
+ * Platform specified synchronization and pixel clock polarities are
+ * only a recommendation and are only used during probing. MX3x
+ * camera interface only works in master mode, i.e., uses HSYNC and
+ * VSYNC signals from the sensor
+ */
+ *flags = SOCAM_MASTER |
+ SOCAM_HSYNC_ACTIVE_HIGH |
+ SOCAM_HSYNC_ACTIVE_LOW |
+ SOCAM_VSYNC_ACTIVE_HIGH |
+ SOCAM_VSYNC_ACTIVE_LOW |
+ SOCAM_PCLK_SAMPLE_RISING |
+ SOCAM_PCLK_SAMPLE_FALLING |
+ SOCAM_DATA_ACTIVE_HIGH |
+ SOCAM_DATA_ACTIVE_LOW;
+
+ /* If requested data width is supported by the platform, use it or any
+ * possible lower value - i.MX31 is smart enough to schift bits */
+ switch (buswidth) {
+ case 15:
+ if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15))
+ return -EINVAL;
+ *flags |= SOCAM_DATAWIDTH_15 | SOCAM_DATAWIDTH_10 |
+ SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4;
+ break;
+ case 10:
+ if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10))
+ return -EINVAL;
+ *flags |= SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_8 |
+ SOCAM_DATAWIDTH_4;
+ break;
+ case 8:
+ if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8))
+ return -EINVAL;
+ *flags |= SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_4;
+ break;
+ case 4:
+ if (!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4))
+ return -EINVAL;
+ *flags |= SOCAM_DATAWIDTH_4;
+ break;
+ default:
+ dev_info(mx3_cam->dev, "Unsupported bus width %d\n", buswidth);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mx3_camera_try_bus_param(struct soc_camera_device *icd,
+ const unsigned int depth)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct mx3_camera_dev *mx3_cam = ici->priv;
+ unsigned long bus_flags, camera_flags;
+ int ret = test_platform_param(mx3_cam, depth, &bus_flags);
+
+ dev_dbg(&ici->dev, "requested bus width %d bit: %d\n", depth, ret);
+
+ if (ret < 0)
+ return ret;
+
+ camera_flags = icd->ops->query_bus_param(icd);
+
+ ret = soc_camera_bus_param_compatible(camera_flags, bus_flags);
+ if (ret < 0)
+ dev_warn(&icd->dev, "Flags incompatible: camera %lx, host %lx\n",
+ camera_flags, bus_flags);
+
+ return ret;
+}
+
+static bool chan_filter(struct dma_chan *chan, void *arg)
+{
+ struct dma_chan_request *rq = arg;
+ struct mx3_camera_pdata *pdata;
+
+ if (!rq)
+ return false;
+
+ pdata = rq->mx3_cam->dev->platform_data;
+
+ return rq->id == chan->chan_id &&
+ pdata->dma_dev == chan->device->dev;
+}
+
+static const struct soc_camera_data_format mx3_camera_formats[] = {
+ {
+ .name = "Bayer (sRGB) 8 bit",
+ .depth = 8,
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ }, {
+ .name = "Monochrome 8 bit",
+ .depth = 8,
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
+};
+
+static bool buswidth_supported(struct soc_camera_host *ici, int depth)
+{
+ struct mx3_camera_dev *mx3_cam = ici->priv;
+
+ switch (depth) {
+ case 4:
+ return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_4);
+ case 8:
+ return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_8);
+ case 10:
+ return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_10);
+ case 15:
+ return !!(mx3_cam->platform_flags & MX3_CAMERA_DATAWIDTH_15);
+ }
+ return false;
+}
+
+static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx,
+ struct soc_camera_format_xlate *xlate)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ int formats = 0, buswidth, ret;
+
+ buswidth = icd->formats[idx].depth;
+
+ if (!buswidth_supported(ici, buswidth))
+ return 0;
+
+ ret = mx3_camera_try_bus_param(icd, buswidth);
+ if (ret < 0)
+ return 0;
+
+ switch (icd->formats[idx].fourcc) {
+ case V4L2_PIX_FMT_SGRBG10:
+ formats++;
+ if (xlate) {
+ xlate->host_fmt = &mx3_camera_formats[0];
+ xlate->cam_fmt = icd->formats + idx;
+ xlate->buswidth = buswidth;
+ xlate++;
+ dev_dbg(&ici->dev, "Providing format %s using %s\n",
+ mx3_camera_formats[0].name,
+ icd->formats[idx].name);
+ }
+ goto passthrough;
+ case V4L2_PIX_FMT_Y16:
+ formats++;
+ if (xlate) {
+ xlate->host_fmt = &mx3_camera_formats[1];
+ xlate->cam_fmt = icd->formats + idx;
+ xlate->buswidth = buswidth;
+ xlate++;
+ dev_dbg(&ici->dev, "Providing format %s using %s\n",
+ mx3_camera_formats[0].name,
+ icd->formats[idx].name);
+ }
+ default:
+passthrough:
+ /* Generic pass-through */
+ formats++;
+ if (xlate) {
+ xlate->host_fmt = icd->formats + idx;
+ xlate->cam_fmt = icd->formats + idx;
+ xlate->buswidth = buswidth;
+ xlate++;
+ dev_dbg(&ici->dev,
+ "Providing format %s in pass-through mode\n",
+ icd->formats[idx].name);
+ }
+ }
+
+ return formats;
+}
+
+static int mx3_camera_set_fmt(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct mx3_camera_dev *mx3_cam = ici->priv;
+ const struct soc_camera_format_xlate *xlate;
+ u32 ctrl, width_field, height_field;
+ int ret;
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+ if (pixfmt && !xlate) {
+ dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+ return -EINVAL;
+ }
+
+ /*
+ * We now know pixel formats and can decide upon DMA-channel(s)
+ * So far only direct camera-to-memory is supported
+ */
+ if (channel_change_requested(icd, xlate, pixfmt, rect)) {
+ dma_cap_mask_t mask;
+ struct dma_chan *chan;
+ struct idmac_channel **ichan = &mx3_cam->idmac_channel[0];
+ /* We have to use IDMAC_IC_7 for Bayer / generic data */
+ struct dma_chan_request rq = {.mx3_cam = mx3_cam,
+ .id = IDMAC_IC_7};
+
+ if (*ichan) {
+ struct videobuf_buffer *vb, *_vb;
+ dma_release_channel(&(*ichan)->dma_chan);
+ *ichan = NULL;
+ mx3_cam->active = NULL;
+ list_for_each_entry_safe(vb, _vb, &mx3_cam->capture, queue) {
+ list_del_init(&vb->queue);
+ vb->state = VIDEOBUF_ERROR;
+ wake_up(&vb->done);
+ }
+ }
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_cap_set(DMA_PRIVATE, mask);
+ chan = dma_request_channel(mask, chan_filter, &rq);
+ if (!chan)
+ return -EBUSY;
+
+ *ichan = to_idmac_chan(chan);
+ (*ichan)->client = mx3_cam;
+ }
+
+ /*
+ * Might have to perform a complete interface initialisation like in
+ * ipu_csi_init_interface() in mxc_v4l2_s_param(). Also consider
+ * mxc_v4l2_s_fmt()
+ */
+
+ /* Setup frame size - this cannot be changed on-the-fly... */
+ width_field = rect->width - 1;
+ height_field = rect->height - 1;
+ csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_SENS_FRM_SIZE);
+
+ csi_reg_write(mx3_cam, width_field << 16, CSI_FLASH_STROBE_1);
+ csi_reg_write(mx3_cam, (height_field << 16) | 0x22, CSI_FLASH_STROBE_2);
+
+ csi_reg_write(mx3_cam, width_field | (height_field << 16), CSI_ACT_FRM_SIZE);
+
+ /* ...and position */
+ ctrl = csi_reg_read(mx3_cam, CSI_OUT_FRM_CTRL) & 0xffff0000;
+ /* Sensor does the cropping */
+ csi_reg_write(mx3_cam, ctrl | 0 | (0 << 8), CSI_OUT_FRM_CTRL);
+
+ /*
+ * No need to free resources here if we fail, we'll see if we need to
+ * do this next time we are called
+ */
+
+ ret = icd->ops->set_fmt(icd, pixfmt ? xlate->cam_fmt->fourcc : 0, rect);
+ if (pixfmt && !ret) {
+ icd->buswidth = xlate->buswidth;
+ icd->current_fmt = xlate->host_fmt;
+ }
+
+ return ret;
+}
+
+static int mx3_camera_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ const struct soc_camera_format_xlate *xlate;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ __u32 pixfmt = pix->pixelformat;
+ enum v4l2_field field;
+ int ret;
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+ if (pixfmt && !xlate) {
+ dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+ return -EINVAL;
+ }
+
+ /* limit to MX3 hardware capabilities */
+ if (pix->height > 4096)
+ pix->height = 4096;
+ if (pix->width > 4096)
+ pix->width = 4096;
+
+ pix->bytesperline = pix->width *
+ DIV_ROUND_UP(xlate->host_fmt->depth, 8);
+ pix->sizeimage = pix->height * pix->bytesperline;
+
+ /* camera has to see its format, but the user the original one */
+ pix->pixelformat = xlate->cam_fmt->fourcc;
+ /* limit to sensor capabilities */
+ ret = icd->ops->try_fmt(icd, f);
+ pix->pixelformat = xlate->host_fmt->fourcc;
+
+ field = pix->field;
+
+ if (field == V4L2_FIELD_ANY) {
+ pix->field = V4L2_FIELD_NONE;
+ } else if (field != V4L2_FIELD_NONE) {
+ dev_err(&icd->dev, "Field type %d unsupported.\n", field);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int mx3_camera_reqbufs(struct soc_camera_file *icf,
+ struct v4l2_requestbuffers *p)
+{
+ return 0;
+}
+
+static unsigned int mx3_camera_poll(struct file *file, poll_table *pt)
+{
+ struct soc_camera_file *icf = file->private_data;
+
+ return videobuf_poll_stream(file, &icf->vb_vidq, pt);
+}
+
+static int mx3_camera_querycap(struct soc_camera_host *ici,
+ struct v4l2_capability *cap)
+{
+ /* cap->name is set by the firendly caller:-> */
+ strlcpy(cap->card, "i.MX3x Camera", sizeof(cap->card));
+ cap->version = KERNEL_VERSION(0, 2, 2);
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+ return 0;
+}
+
+static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct mx3_camera_dev *mx3_cam = ici->priv;
+ unsigned long bus_flags, camera_flags, common_flags;
+ u32 dw, sens_conf;
+ int ret = test_platform_param(mx3_cam, icd->buswidth, &bus_flags);
+ const struct soc_camera_format_xlate *xlate;
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+ if (!xlate) {
+ dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+ return -EINVAL;
+ }
+
+ dev_dbg(&ici->dev, "requested bus width %d bit: %d\n",
+ icd->buswidth, ret);
+
+ if (ret < 0)
+ return ret;
+
+ camera_flags = icd->ops->query_bus_param(icd);
+
+ common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
+ if (!common_flags) {
+ dev_dbg(&ici->dev, "no common flags: camera %lx, host %lx\n",
+ camera_flags, bus_flags);
+ return -EINVAL;
+ }
+
+ /* Make choices, based on platform preferences */
+ if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
+ (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
+ if (mx3_cam->platform_flags & MX3_CAMERA_HSP)
+ common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;
+ else
+ common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;
+ }
+
+ if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) &&
+ (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) {
+ if (mx3_cam->platform_flags & MX3_CAMERA_VSP)
+ common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH;
+ else
+ common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW;
+ }
+
+ if ((common_flags & SOCAM_DATA_ACTIVE_HIGH) &&
+ (common_flags & SOCAM_DATA_ACTIVE_LOW)) {
+ if (mx3_cam->platform_flags & MX3_CAMERA_DP)
+ common_flags &= ~SOCAM_DATA_ACTIVE_HIGH;
+ else
+ common_flags &= ~SOCAM_DATA_ACTIVE_LOW;
+ }
+
+ if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
+ (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
+ if (mx3_cam->platform_flags & MX3_CAMERA_PCP)
+ common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
+ else
+ common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
+ }
+
+ /* Make the camera work in widest common mode, we'll take care of
+ * the rest */
+ if (common_flags & SOCAM_DATAWIDTH_15)
+ common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) |
+ SOCAM_DATAWIDTH_15;
+ else if (common_flags & SOCAM_DATAWIDTH_10)
+ common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) |
+ SOCAM_DATAWIDTH_10;
+ else if (common_flags & SOCAM_DATAWIDTH_8)
+ common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) |
+ SOCAM_DATAWIDTH_8;
+ else
+ common_flags = (common_flags & ~SOCAM_DATAWIDTH_MASK) |
+ SOCAM_DATAWIDTH_4;
+
+ ret = icd->ops->set_bus_param(icd, common_flags);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * So far only gated clock mode is supported. Add a line
+ * (3 << CSI_SENS_CONF_SENS_PRTCL_SHIFT) |
+ * below and select the required mode when supporting other
+ * synchronisation protocols.
+ */
+ sens_conf = csi_reg_read(mx3_cam, CSI_SENS_CONF) &
+ ~((1 << CSI_SENS_CONF_VSYNC_POL_SHIFT) |
+ (1 << CSI_SENS_CONF_HSYNC_POL_SHIFT) |
+ (1 << CSI_SENS_CONF_DATA_POL_SHIFT) |
+ (1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT) |
+ (3 << CSI_SENS_CONF_DATA_FMT_SHIFT) |
+ (3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT));
+
+ /* TODO: Support RGB and YUV formats */
+
+ /* This has been set in mx3_camera_activate(), but we clear it above */
+ sens_conf |= CSI_SENS_CONF_DATA_FMT_BAYER;
+
+ if (common_flags & SOCAM_PCLK_SAMPLE_FALLING)
+ sens_conf |= 1 << CSI_SENS_CONF_PIX_CLK_POL_SHIFT;
+ if (common_flags & SOCAM_HSYNC_ACTIVE_LOW)
+ sens_conf |= 1 << CSI_SENS_CONF_HSYNC_POL_SHIFT;
+ if (common_flags & SOCAM_VSYNC_ACTIVE_LOW)
+ sens_conf |= 1 << CSI_SENS_CONF_VSYNC_POL_SHIFT;
+ if (common_flags & SOCAM_DATA_ACTIVE_LOW)
+ sens_conf |= 1 << CSI_SENS_CONF_DATA_POL_SHIFT;
+
+ /* Just do what we're asked to do */
+ switch (xlate->host_fmt->depth) {
+ case 4:
+ dw = 0 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+ break;
+ case 8:
+ dw = 1 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+ break;
+ case 10:
+ dw = 2 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+ break;
+ default:
+ /*
+ * Actually it can only be 15 now, default is just to silence
+ * compiler warnings
+ */
+ case 15:
+ dw = 3 << CSI_SENS_CONF_DATA_WIDTH_SHIFT;
+ }
+
+ csi_reg_write(mx3_cam, sens_conf | dw, CSI_SENS_CONF);
+
+ dev_dbg(&ici->dev, "Set SENS_CONF to %x\n", sens_conf | dw);
+
+ return 0;
+}
+
+static struct soc_camera_host_ops mx3_soc_camera_host_ops = {
+ .owner = THIS_MODULE,
+ .add = mx3_camera_add_device,
+ .remove = mx3_camera_remove_device,
+#ifdef CONFIG_PM
+ .suspend = mx3_camera_suspend,
+ .resume = mx3_camera_resume,
+#endif
+ .set_fmt = mx3_camera_set_fmt,
+ .try_fmt = mx3_camera_try_fmt,
+ .get_formats = mx3_camera_get_formats,
+ .init_videobuf = mx3_camera_init_videobuf,
+ .reqbufs = mx3_camera_reqbufs,
+ .poll = mx3_camera_poll,
+ .querycap = mx3_camera_querycap,
+ .set_bus_param = mx3_camera_set_bus_param,
+};
+
+static int mx3_camera_probe(struct platform_device *pdev)
+{
+ struct mx3_camera_dev *mx3_cam;
+ struct resource *res;
+ void __iomem *base;
+ int err = 0;
+ struct soc_camera_host *soc_host;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ err = -ENODEV;
+ goto egetres;
+ }
+
+ mx3_cam = vmalloc(sizeof(*mx3_cam));
+ if (!mx3_cam) {
+ dev_err(&pdev->dev, "Could not allocate mx3 camera object\n");
+ err = -ENOMEM;
+ goto ealloc;
+ }
+ memset(mx3_cam, 0, sizeof(*mx3_cam));
+
+ mx3_cam->clk = clk_get(&pdev->dev, "csi_clk");
+ if (IS_ERR(mx3_cam->clk)) {
+ err = PTR_ERR(mx3_cam->clk);
+ goto eclkget;
+ }
+
+ dev_set_drvdata(&pdev->dev, mx3_cam);
+
+ mx3_cam->pdata = pdev->dev.platform_data;
+ mx3_cam->platform_flags = mx3_cam->pdata->flags;
+ if (!(mx3_cam->platform_flags & (MX3_CAMERA_DATAWIDTH_4 |
+ MX3_CAMERA_DATAWIDTH_8 | MX3_CAMERA_DATAWIDTH_10 |
+ MX3_CAMERA_DATAWIDTH_15))) {
+ /* Platform hasn't set available data widths. This is bad.
+ * Warn and use a default. */
+ dev_warn(&pdev->dev, "WARNING! Platform hasn't set available "
+ "data widths, using default 8 bit\n");
+ mx3_cam->platform_flags |= MX3_CAMERA_DATAWIDTH_8;
+ }
+
+ mx3_cam->mclk = mx3_cam->pdata->mclk_10khz * 10000;
+ if (!mx3_cam->mclk) {
+ dev_warn(&pdev->dev,
+ "mclk_10khz == 0! Please, fix your platform data. "
+ "Using default 20MHz\n");
+ mx3_cam->mclk = 20000000;
+ }
+
+ /* list of video-buffers */
+ INIT_LIST_HEAD(&mx3_cam->capture);
+ spin_lock_init(&mx3_cam->lock);
+
+ base = ioremap(res->start, res->end - res->start + 1);
+ if (!base) {
+ err = -ENOMEM;
+ goto eioremap;
+ }
+
+ mx3_cam->base = base;
+ mx3_cam->dev = &pdev->dev;
+
+ soc_host = &mx3_cam->soc_host;
+ soc_host->drv_name = MX3_CAM_DRV_NAME;
+ soc_host->ops = &mx3_soc_camera_host_ops;
+ soc_host->priv = mx3_cam;
+ soc_host->dev.parent = &pdev->dev;
+ soc_host->nr = pdev->id;
+ err = soc_camera_host_register(soc_host);
+ if (err)
+ goto ecamhostreg;
+
+ /* IDMAC interface */
+ dmaengine_get();
+
+ return 0;
+
+ecamhostreg:
+ iounmap(base);
+eioremap:
+ clk_put(mx3_cam->clk);
+eclkget:
+ vfree(mx3_cam);
+ealloc:
+egetres:
+ return err;
+}
+
+static int __devexit mx3_camera_remove(struct platform_device *pdev)
+{
+ struct mx3_camera_dev *mx3_cam = platform_get_drvdata(pdev);
+
+ clk_put(mx3_cam->clk);
+
+ soc_camera_host_unregister(&mx3_cam->soc_host);
+
+ iounmap(mx3_cam->base);
+
+ /*
+ * The channel has either not been allocated,
+ * or should have been released
+ */
+ if (WARN_ON(mx3_cam->idmac_channel[0]))
+ dma_release_channel(&mx3_cam->idmac_channel[0]->dma_chan);
+
+ vfree(mx3_cam);
+
+ dmaengine_put();
+
+ dev_info(&pdev->dev, "i.MX3x Camera driver unloaded\n");
+
+ return 0;
+}
+
+static struct platform_driver mx3_camera_driver = {
+ .driver = {
+ .name = MX3_CAM_DRV_NAME,
+ },
+ .probe = mx3_camera_probe,
+ .remove = __exit_p(mx3_camera_remove),
+};
+
+
+static int __devinit mx3_camera_init(void)
+{
+ return platform_driver_register(&mx3_camera_driver);
+}
+
+static void __exit mx3_camera_exit(void)
+{
+ platform_driver_unregister(&mx3_camera_driver);
+}
+
+module_init(mx3_camera_init);
+module_exit(mx3_camera_exit);
+
+MODULE_DESCRIPTION("i.MX3x SoC Camera Host driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <lg@denx.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/linux/drivers/media/video/ov772x.c b/linux/drivers/media/video/ov772x.c
index ce389cacf..2f3313524 100644
--- a/linux/drivers/media/video/ov772x.c
+++ b/linux/drivers/media/video/ov772x.c
@@ -217,10 +217,11 @@
#define OCAP_4x 0x03 /* 4x */
/* COM3 */
-#define SWAP_MASK 0x38
+#define SWAP_MASK (SWAP_RGB | SWAP_YUV | SWAP_ML)
+#define IMG_MASK (VFLIP_IMG | HFLIP_IMG)
-#define VFIMG_ON_OFF 0x80 /* Vertical flip image ON/OFF selection */
-#define HMIMG_ON_OFF 0x40 /* Horizontal mirror image ON/OFF selection */
+#define VFLIP_IMG 0x80 /* Vertical flip image ON/OFF selection */
+#define HFLIP_IMG 0x40 /* Horizontal mirror image ON/OFF selection */
#define SWAP_RGB 0x20 /* Swap B/R output sequence in RGB mode */
#define SWAP_YUV 0x10 /* Swap Y/UV output sequence in YUV mode */
#define SWAP_ML 0x08 /* Swap output MSB/LSB */
@@ -271,11 +272,13 @@
#define SLCT_QVGA 0x40 /* 1 : QVGA */
#define ITU656_ON_OFF 0x20 /* ITU656 protocol ON/OFF selection */
/* RGB output format control */
+#define FMT_MASK 0x0c /* Mask of color format */
#define FMT_GBR422 0x00 /* 00 : GBR 4:2:2 */
#define FMT_RGB565 0x04 /* 01 : RGB 565 */
#define FMT_RGB555 0x08 /* 10 : RGB 555 */
#define FMT_RGB444 0x0c /* 11 : RGB 444 */
/* Output format control */
+#define OFMT_MASK 0x03 /* Mask of output format */
#define OFMT_YUV 0x00 /* 00 : YUV */
#define OFMT_P_BRAW 0x01 /* 01 : Processed Bayer RAW */
#define OFMT_RGB 0x02 /* 10 : RGB */
@@ -299,7 +302,7 @@
#define GAIN_2x 0x00 /* 000 : 2x */
#define GAIN_4x 0x10 /* 001 : 4x */
#define GAIN_8x 0x20 /* 010 : 8x */
-#define GAIN_16x 0x30 /* 011 : 16x */
+#define GAIN_16x 0x30 /* 011 : 16x */
#define GAIN_32x 0x40 /* 100 : 32x */
#define GAIN_64x 0x50 /* 101 : 64x */
#define GAIN_128x 0x60 /* 110 : 128x */
@@ -356,13 +359,6 @@
#define VOSZ_QVGA 0x78
/*
- * bit configure (32 bit)
- * this is used in struct ov772x_color_format :: option
- */
-#define OP_UV 0x00000001
-#define OP_SWAP_RGB 0x00000002
-
-/*
* ID
*/
#define OV7720 0x7720
@@ -380,8 +376,9 @@ struct regval_list {
struct ov772x_color_format {
char *name;
__u32 fourcc;
- const struct regval_list *regs;
- unsigned int option;
+ u8 dsp3;
+ u8 com3;
+ u8 com7;
};
struct ov772x_win_size {
@@ -399,39 +396,13 @@ struct ov772x_priv {
const struct ov772x_color_format *fmt;
const struct ov772x_win_size *win;
int model;
+ unsigned int flag_vflip:1;
+ unsigned int flag_hflip:1;
};
#define ENDMARKER { 0xff, 0xff }
/*
- * register setting for color format
- */
-static const struct regval_list ov772x_RGB555_regs[] = {
- { COM3, 0x00 },
- { COM7, FMT_RGB555 | OFMT_RGB },
- ENDMARKER,
-};
-
-static const struct regval_list ov772x_RGB565_regs[] = {
- { COM3, 0x00 },
- { COM7, FMT_RGB565 | OFMT_RGB },
- ENDMARKER,
-};
-
-static const struct regval_list ov772x_YYUV_regs[] = {
- { COM3, SWAP_YUV },
- { COM7, OFMT_YUV },
- ENDMARKER,
-};
-
-static const struct regval_list ov772x_UVYY_regs[] = {
- { COM3, 0x00 },
- { COM7, OFMT_YUV },
- ENDMARKER,
-};
-
-
-/*
* register setting for window size
*/
static const struct regval_list ov772x_qvga_regs[] = {
@@ -500,38 +471,48 @@ static const struct soc_camera_data_format ov772x_fmt_lists[] = {
/*
* color format list
*/
-#define T_YUYV 0
static const struct ov772x_color_format ov772x_cfmts[] = {
- [T_YUYV] = {
+ {
SETFOURCC(YUYV),
- .regs = ov772x_YYUV_regs,
+ .dsp3 = 0x0,
+ .com3 = SWAP_YUV,
+ .com7 = OFMT_YUV,
},
{
SETFOURCC(YVYU),
- .regs = ov772x_YYUV_regs,
- .option = OP_UV,
+ .dsp3 = UV_ON,
+ .com3 = SWAP_YUV,
+ .com7 = OFMT_YUV,
},
{
SETFOURCC(UYVY),
- .regs = ov772x_UVYY_regs,
+ .dsp3 = 0x0,
+ .com3 = 0x0,
+ .com7 = OFMT_YUV,
},
{
SETFOURCC(RGB555),
- .regs = ov772x_RGB555_regs,
- .option = OP_SWAP_RGB,
+ .dsp3 = 0x0,
+ .com3 = SWAP_RGB,
+ .com7 = FMT_RGB555 | OFMT_RGB,
},
{
SETFOURCC(RGB555X),
- .regs = ov772x_RGB555_regs,
+ .dsp3 = 0x0,
+ .com3 = 0x0,
+ .com7 = FMT_RGB555 | OFMT_RGB,
},
{
SETFOURCC(RGB565),
- .regs = ov772x_RGB565_regs,
- .option = OP_SWAP_RGB,
+ .dsp3 = 0x0,
+ .com3 = SWAP_RGB,
+ .com7 = FMT_RGB565 | OFMT_RGB,
},
{
SETFOURCC(RGB565X),
- .regs = ov772x_RGB565_regs,
+ .dsp3 = 0x0,
+ .com3 = 0x0,
+ .com7 = FMT_RGB565 | OFMT_RGB,
},
};
@@ -562,6 +543,27 @@ static const struct ov772x_win_size ov772x_win_qvga = {
.regs = ov772x_qvga_regs,
};
+static const struct v4l2_queryctrl ov772x_controls[] = {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Flip Vertically",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Flip Horizontally",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+};
+
/*
* general function
@@ -587,8 +589,11 @@ static int ov772x_mask_set(struct i2c_client *client,
u8 set)
{
s32 val = i2c_smbus_read_byte_data(client, command);
+ if (val < 0)
+ return val;
+
val &= ~mask;
- val |= set;
+ val |= set & mask;
return i2c_smbus_write_byte_data(client, command, val);
}
@@ -635,74 +640,20 @@ static int ov772x_release(struct soc_camera_device *icd)
static int ov772x_start_capture(struct soc_camera_device *icd)
{
struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
- int ret;
-
- if (!priv->win)
- priv->win = &ov772x_win_vga;
- if (!priv->fmt)
- priv->fmt = &ov772x_cfmts[T_YUYV];
-
- /*
- * reset hardware
- */
- ov772x_reset(priv->client);
-
- /*
- * set color format
- */
- ret = ov772x_write_array(priv->client, priv->fmt->regs);
- if (ret < 0)
- goto start_end;
- /*
- * set size format
- */
- ret = ov772x_write_array(priv->client, priv->win->regs);
- if (ret < 0)
- goto start_end;
-
- /*
- * set COM7 bit ( QVGA or VGA )
- */
- ret = ov772x_mask_set(priv->client,
- COM7, SLCT_MASK, priv->win->com7_bit);
- if (ret < 0)
- goto start_end;
-
- /*
- * set UV setting
- */
- if (priv->fmt->option & OP_UV) {
- ret = ov772x_mask_set(priv->client,
- DSP_CTRL3, UV_MASK, UV_ON);
- if (ret < 0)
- goto start_end;
- }
-
- /*
- * set SWAP setting
- */
- if (priv->fmt->option & OP_SWAP_RGB) {
- ret = ov772x_mask_set(priv->client,
- COM3, SWAP_MASK, SWAP_RGB);
- if (ret < 0)
- goto start_end;
+ if (!priv->win || !priv->fmt) {
+ dev_err(&icd->dev, "norm or win select error\n");
+ return -EPERM;
}
dev_dbg(&icd->dev,
"format %s, win %s\n", priv->fmt->name, priv->win->name);
-start_end:
- priv->fmt = NULL;
- priv->win = NULL;
-
- return ret;
+ return 0;
}
static int ov772x_stop_capture(struct soc_camera_device *icd)
{
- struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
- ov772x_reset(priv->client);
return 0;
}
@@ -718,11 +669,54 @@ static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd)
struct soc_camera_link *icl = priv->client->dev.platform_data;
unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
- priv->info->buswidth;
+ SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth;
return soc_camera_apply_sensor_flags(icl, flags);
}
+static int ov772x_get_control(struct soc_camera_device *icd,
+ struct v4l2_control *ctrl)
+{
+ struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ ctrl->value = priv->flag_vflip;
+ break;
+ case V4L2_CID_HFLIP:
+ ctrl->value = priv->flag_hflip;
+ break;
+ }
+ return 0;
+}
+
+static int ov772x_set_control(struct soc_camera_device *icd,
+ struct v4l2_control *ctrl)
+{
+ struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
+ int ret = 0;
+ u8 val;
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ val = ctrl->value ? VFLIP_IMG : 0x00;
+ priv->flag_vflip = ctrl->value;
+ if (priv->info->flags & OV772X_FLAG_VFLIP)
+ val ^= VFLIP_IMG;
+ ret = ov772x_mask_set(priv->client, COM3, VFLIP_IMG, val);
+ break;
+ case V4L2_CID_HFLIP:
+ val = ctrl->value ? HFLIP_IMG : 0x00;
+ priv->flag_hflip = ctrl->value;
+ if (priv->info->flags & OV772X_FLAG_HFLIP)
+ val ^= HFLIP_IMG;
+ ret = ov772x_mask_set(priv->client, COM3, HFLIP_IMG, val);
+ break;
+ }
+
+ return ret;
+}
+
static int ov772x_get_chip_id(struct soc_camera_device *icd,
struct v4l2_dbg_chip_ident *id)
{
@@ -787,13 +781,13 @@ ov772x_select_win(u32 width, u32 height)
return win;
}
-
static int ov772x_set_fmt(struct soc_camera_device *icd,
__u32 pixfmt,
struct v4l2_rect *rect)
{
struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd);
int ret = -EINVAL;
+ u8 val;
int i;
/*
@@ -803,16 +797,76 @@ static int ov772x_set_fmt(struct soc_camera_device *icd,
for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) {
if (pixfmt == ov772x_cfmts[i].fourcc) {
priv->fmt = ov772x_cfmts + i;
- ret = 0;
break;
}
}
+ if (!priv->fmt)
+ goto ov772x_set_fmt_error;
/*
* select win
*/
priv->win = ov772x_select_win(rect->width, rect->height);
+ /*
+ * reset hardware
+ */
+ ov772x_reset(priv->client);
+
+ /*
+ * set size format
+ */
+ ret = ov772x_write_array(priv->client, priv->win->regs);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+
+ /*
+ * set DSP_CTRL3
+ */
+ val = priv->fmt->dsp3;
+ if (val) {
+ ret = ov772x_mask_set(priv->client,
+ DSP_CTRL3, UV_MASK, val);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+ }
+
+ /*
+ * set COM3
+ */
+ val = priv->fmt->com3;
+ if (priv->info->flags & OV772X_FLAG_VFLIP)
+ val |= VFLIP_IMG;
+ if (priv->info->flags & OV772X_FLAG_HFLIP)
+ val |= HFLIP_IMG;
+ if (priv->flag_vflip)
+ val ^= VFLIP_IMG;
+ if (priv->flag_hflip)
+ val ^= HFLIP_IMG;
+
+ ret = ov772x_mask_set(priv->client,
+ COM3, SWAP_MASK | IMG_MASK, val);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+
+ /*
+ * set COM7
+ */
+ val = priv->win->com7_bit | priv->fmt->com7;
+ ret = ov772x_mask_set(priv->client,
+ COM7, (SLCT_MASK | FMT_MASK | OFMT_MASK),
+ val);
+ if (ret < 0)
+ goto ov772x_set_fmt_error;
+
+ return ret;
+
+ov772x_set_fmt_error:
+
+ ov772x_reset(priv->client);
+ priv->win = NULL;
+ priv->fmt = NULL;
+
return ret;
}
@@ -889,7 +943,6 @@ static int ov772x_video_probe(struct soc_camera_device *icd)
i2c_smbus_read_byte_data(priv->client, MIDH),
i2c_smbus_read_byte_data(priv->client, MIDL));
-
return soc_camera_video_start(icd);
}
@@ -910,6 +963,10 @@ static struct soc_camera_ops ov772x_ops = {
.try_fmt = ov772x_try_fmt,
.set_bus_param = ov772x_set_bus_param,
.query_bus_param = ov772x_query_bus_param,
+ .controls = ov772x_controls,
+ .num_controls = ARRAY_SIZE(ov772x_controls),
+ .get_control = ov772x_get_control,
+ .set_control = ov772x_set_control,
.get_chip_id = ov772x_get_chip_id,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.get_register = ov772x_get_register,
diff --git a/linux/drivers/media/video/pxa_camera.c b/linux/drivers/media/video/pxa_camera.c
index 2c283b82a..dd524b3c6 100644
--- a/linux/drivers/media/video/pxa_camera.c
+++ b/linux/drivers/media/video/pxa_camera.c
@@ -888,6 +888,7 @@ static int test_platform_param(struct pxa_camera_dev *pcdev,
SOCAM_HSYNC_ACTIVE_LOW |
SOCAM_VSYNC_ACTIVE_HIGH |
SOCAM_VSYNC_ACTIVE_LOW |
+ SOCAM_DATA_ACTIVE_HIGH |
SOCAM_PCLK_SAMPLE_RISING |
SOCAM_PCLK_SAMPLE_FALLING;
@@ -1164,23 +1165,23 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
- const struct soc_camera_data_format *host_fmt, *cam_fmt = NULL;
- const struct soc_camera_format_xlate *xlate;
+ const struct soc_camera_data_format *cam_fmt = NULL;
+ const struct soc_camera_format_xlate *xlate = NULL;
struct soc_camera_sense sense = {
.master_clock = pcdev->mclk,
.pixel_clock_max = pcdev->ciclk / 4,
};
- int ret, buswidth;
+ int ret;
- xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
- if (!xlate) {
- dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
- return -EINVAL;
- }
+ if (pixfmt) {
+ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+ if (!xlate) {
+ dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+ return -EINVAL;
+ }
- buswidth = xlate->buswidth;
- host_fmt = xlate->host_fmt;
- cam_fmt = xlate->cam_fmt;
+ cam_fmt = xlate->cam_fmt;
+ }
/* If PCLK is used to latch data from the sensor, check sense */
if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
@@ -1210,8 +1211,8 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
}
if (pixfmt && !ret) {
- icd->buswidth = buswidth;
- icd->current_fmt = host_fmt;
+ icd->buswidth = xlate->buswidth;
+ icd->current_fmt = xlate->host_fmt;
}
return ret;
diff --git a/linux/drivers/media/video/saa7115.c b/linux/drivers/media/video/saa7115.c
index 169b01f6d..2570ebf89 100644
--- a/linux/drivers/media/video/saa7115.c
+++ b/linux/drivers/media/video/saa7115.c
@@ -1207,10 +1207,12 @@ static int saa711x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
{
switch (qc->id) {
case V4L2_CID_BRIGHTNESS:
+ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
case V4L2_CID_CONTRAST:
case V4L2_CID_SATURATION:
+ return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
case V4L2_CID_HUE:
- return v4l2_ctrl_query_fill_std(qc);
+ return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
default:
return -EINVAL;
}
diff --git a/linux/drivers/media/video/saa7134/saa6752hs.c b/linux/drivers/media/video/saa7134/saa6752hs.c
index 2e2871de1..3af36d929 100644
--- a/linux/drivers/media/video/saa7134/saa6752hs.c
+++ b/linux/drivers/media/video/saa7134/saa6752hs.c
@@ -599,7 +599,7 @@ static int saa6752hs_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc
V4L2_MPEG_VIDEO_ASPECT_4x3);
case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
- err = v4l2_ctrl_query_fill_std(qctrl);
+ err = v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000);
if (err == 0 &&
params->vi_bitrate_mode ==
V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
@@ -613,12 +613,20 @@ static int saa6752hs_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc
V4L2_MPEG_STREAM_TYPE_MPEG2_TS);
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
case V4L2_CID_MPEG_VIDEO_BITRATE:
+ return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000);
case V4L2_CID_MPEG_STREAM_PID_PMT:
+ return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 16);
case V4L2_CID_MPEG_STREAM_PID_AUDIO:
+ return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 260);
case V4L2_CID_MPEG_STREAM_PID_VIDEO:
+ return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 256);
case V4L2_CID_MPEG_STREAM_PID_PCR:
- return v4l2_ctrl_query_fill_std(qctrl);
+ return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 259);
default:
break;
diff --git a/linux/drivers/media/video/saa7134/saa7134-empress.c b/linux/drivers/media/video/saa7134/saa7134-empress.c
index 813f5f88d..609342128 100644
--- a/linux/drivers/media/video/saa7134/saa7134-empress.c
+++ b/linux/drivers/media/video/saa7134/saa7134-empress.c
@@ -390,7 +390,7 @@ static int empress_queryctrl(struct file *file, void *priv,
if (c->id == 0)
return -EINVAL;
if (c->id == V4L2_CID_USER_CLASS || c->id == V4L2_CID_MPEG_CLASS)
- return v4l2_ctrl_query_fill_std(c);
+ return v4l2_ctrl_query_fill(c, 0, 0, 0, 0);
if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG)
return saa7134_queryctrl(file, priv, c);
return saa_call_empress(dev, core, queryctrl, c);
diff --git a/linux/drivers/media/video/sh_mobile_ceu_camera.c b/linux/drivers/media/video/sh_mobile_ceu_camera.c
index ae98eaf5f..29ff02802 100644
--- a/linux/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/linux/drivers/media/video/sh_mobile_ceu_camera.c
@@ -102,6 +102,30 @@ struct sh_mobile_ceu_dev {
const struct soc_camera_data_format *camera_fmt;
};
+static unsigned long make_bus_param(struct sh_mobile_ceu_dev *pcdev)
+{
+ unsigned long flags;
+
+ flags = SOCAM_MASTER |
+ SOCAM_PCLK_SAMPLE_RISING |
+ SOCAM_HSYNC_ACTIVE_HIGH |
+ SOCAM_HSYNC_ACTIVE_LOW |
+ SOCAM_VSYNC_ACTIVE_HIGH |
+ SOCAM_VSYNC_ACTIVE_LOW |
+ SOCAM_DATA_ACTIVE_HIGH;
+
+ if (pcdev->pdata->flags & SH_CEU_FLAG_USE_8BIT_BUS)
+ flags |= SOCAM_DATAWIDTH_8;
+
+ if (pcdev->pdata->flags & SH_CEU_FLAG_USE_16BIT_BUS)
+ flags |= SOCAM_DATAWIDTH_16;
+
+ if (flags & SOCAM_DATAWIDTH_MASK)
+ return flags;
+
+ return 0;
+}
+
static void ceu_write(struct sh_mobile_ceu_dev *priv,
unsigned long reg_offs, u32 data)
{
@@ -397,7 +421,7 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
camera_flags = icd->ops->query_bus_param(icd);
common_flags = soc_camera_bus_param_compatible(camera_flags,
- pcdev->pdata->flags);
+ make_bus_param(pcdev));
if (!common_flags)
return -EINVAL;
@@ -518,7 +542,7 @@ static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd)
camera_flags = icd->ops->query_bus_param(icd);
common_flags = soc_camera_bus_param_compatible(camera_flags,
- pcdev->pdata->flags);
+ make_bus_param(pcdev));
if (!common_flags)
return -EINVAL;
@@ -563,11 +587,29 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
if (ret < 0)
return 0;
+ /* Beginning of a pass */
+ if (!idx)
+ icd->host_priv = NULL;
+
switch (icd->formats[idx].fourcc) {
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_VYUY:
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YVYU:
+ if (icd->host_priv)
+ goto add_single_format;
+
+ /*
+ * Our case is simple so far: for any of the above four camera
+ * formats we add all our four synthesized NV* formats, so,
+ * just marking the device with a single flag suffices. If
+ * the format generation rules are more complex, you would have
+ * to actually hang your already added / counted formats onto
+ * the host_priv pointer and check whether the format you're
+ * going to add now is already there.
+ */
+ icd->host_priv = (void *)sh_mobile_ceu_formats;
+
n = ARRAY_SIZE(sh_mobile_ceu_formats);
formats += n;
for (k = 0; xlate && k < n; k++) {
@@ -580,6 +622,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
icd->formats[idx].name);
}
default:
+add_single_format:
/* Generic pass-through */
formats++;
if (xlate) {
@@ -604,21 +647,18 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
const struct soc_camera_format_xlate *xlate;
int ret;
+ if (!pixfmt)
+ return icd->ops->set_fmt(icd, pixfmt, rect);
+
xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
if (!xlate) {
dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
return -EINVAL;
}
- switch (pixfmt) {
- case 0: /* Only geometry change */
- ret = icd->ops->set_fmt(icd, pixfmt, rect);
- break;
- default:
- ret = icd->ops->set_fmt(icd, xlate->cam_fmt->fourcc, rect);
- }
+ ret = icd->ops->set_fmt(icd, xlate->cam_fmt->fourcc, rect);
- if (pixfmt && !ret) {
+ if (!ret) {
icd->buswidth = xlate->buswidth;
icd->current_fmt = xlate->host_fmt;
pcdev->camera_fmt = xlate->cam_fmt;
diff --git a/linux/drivers/media/video/sn9c102/sn9c102_devtable.h b/linux/drivers/media/video/sn9c102/sn9c102_devtable.h
index 8cb3457e7..41dfb60f4 100644
--- a/linux/drivers/media/video/sn9c102/sn9c102_devtable.h
+++ b/linux/drivers/media/video/sn9c102/sn9c102_devtable.h
@@ -123,7 +123,9 @@ static const struct usb_device_id sn9c102_id_table[] = {
{ SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), },
#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), },
+#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), },
+#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), },
{ }
};
diff --git a/linux/drivers/media/video/tda7432.c b/linux/drivers/media/video/tda7432.c
index 30f6f8a38..104fc4246 100644
--- a/linux/drivers/media/video/tda7432.c
+++ b/linux/drivers/media/video/tda7432.c
@@ -422,12 +422,14 @@ static int tda7432_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int tda7432_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
{
switch (qc->id) {
- case V4L2_CID_AUDIO_MUTE:
case V4L2_CID_AUDIO_VOLUME:
+ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
+ case V4L2_CID_AUDIO_MUTE:
+ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
case V4L2_CID_AUDIO_BALANCE:
case V4L2_CID_AUDIO_BASS:
case V4L2_CID_AUDIO_TREBLE:
- return v4l2_ctrl_query_fill_std(qc);
+ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
}
return -EINVAL;
}
diff --git a/linux/drivers/media/video/tda9875.c b/linux/drivers/media/video/tda9875.c
index 892d25a40..938bafbbd 100644
--- a/linux/drivers/media/video/tda9875.c
+++ b/linux/drivers/media/video/tda9875.c
@@ -327,9 +327,10 @@ static int tda9875_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
{
switch (qc->id) {
case V4L2_CID_AUDIO_VOLUME:
+ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
case V4L2_CID_AUDIO_BASS:
case V4L2_CID_AUDIO_TREBLE:
- return v4l2_ctrl_query_fill_std(qc);
+ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
}
return -EINVAL;
}
diff --git a/linux/drivers/media/video/tvaudio.c b/linux/drivers/media/video/tvaudio.c
index db03d1350..755418a31 100644
--- a/linux/drivers/media/video/tvaudio.c
+++ b/linux/drivers/media/video/tvaudio.c
@@ -1644,21 +1644,24 @@ static int tvaudio_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
switch (qc->id) {
case V4L2_CID_AUDIO_MUTE:
- break;
+ return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
case V4L2_CID_AUDIO_VOLUME:
+ if (desc->flags & CHIP_HAS_VOLUME)
+ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
+ break;
case V4L2_CID_AUDIO_BALANCE:
- if (!(desc->flags & CHIP_HAS_VOLUME))
- return -EINVAL;
+ if (desc->flags & CHIP_HAS_VOLUME)
+ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
break;
case V4L2_CID_AUDIO_BASS:
case V4L2_CID_AUDIO_TREBLE:
- if (!(desc->flags & CHIP_HAS_BASSTREBLE))
- return -EINVAL;
+ if (desc->flags & CHIP_HAS_BASSTREBLE)
+ return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
break;
default:
- return -EINVAL;
+ break;
}
- return v4l2_ctrl_query_fill_std(qc);
+ return -EINVAL;
}
static int tvaudio_s_routing(struct v4l2_subdev *sd, const struct v4l2_routing *rt)
diff --git a/linux/drivers/media/video/tvp514x.c b/linux/drivers/media/video/tvp514x.c
index 5f4cbc2b2..4262e60b8 100644
--- a/linux/drivers/media/video/tvp514x.c
+++ b/linux/drivers/media/video/tvp514x.c
@@ -86,9 +86,12 @@ struct tvp514x_std_info {
struct v4l2_standard standard;
};
+static struct tvp514x_reg tvp514x_reg_list_default[0x40];
/**
- * struct tvp514x_decoded - TVP5146/47 decoder object
+ * struct tvp514x_decoder - TVP5146/47 decoder object
* @v4l2_int_device: Slave handle
+ * @tvp514x_slave: Slave pointer which is used by @v4l2_int_device
+ * @tvp514x_regs: copy of hw's regs with preset values.
* @pdata: Board specific
* @client: I2C client data
* @id: Entry from I2C table
@@ -103,7 +106,9 @@ struct tvp514x_std_info {
* @route: input and output routing at chip level
*/
struct tvp514x_decoder {
- struct v4l2_int_device *v4l2_int_device;
+ struct v4l2_int_device v4l2_int_device;
+ struct v4l2_int_slave tvp514x_slave;
+ struct tvp514x_reg tvp514x_regs[ARRAY_SIZE(tvp514x_reg_list_default)];
const struct tvp514x_platform_data *pdata;
struct i2c_client *client;
@@ -124,7 +129,7 @@ struct tvp514x_decoder {
};
/* TVP514x default register values */
-static struct tvp514x_reg tvp514x_reg_list[] = {
+static struct tvp514x_reg tvp514x_reg_list_default[] = {
{TOK_WRITE, REG_INPUT_SEL, 0x05}, /* Composite selected */
{TOK_WRITE, REG_AFE_GAIN_CTRL, 0x0F},
{TOK_WRITE, REG_VIDEO_STD, 0x00}, /* Auto mode */
@@ -422,7 +427,7 @@ static int tvp514x_configure(struct tvp514x_decoder *decoder)
/* common register initialization */
err =
- tvp514x_write_regs(decoder->client, tvp514x_reg_list);
+ tvp514x_write_regs(decoder->client, decoder->tvp514x_regs);
if (err)
return err;
@@ -580,7 +585,8 @@ static int ioctl_s_std(struct v4l2_int_device *s, v4l2_std_id *std_id)
return err;
decoder->current_std = i;
- tvp514x_reg_list[REG_VIDEO_STD].val = decoder->std_list[i].video_std;
+ decoder->tvp514x_regs[REG_VIDEO_STD].val =
+ decoder->std_list[i].video_std;
v4l_dbg(1, debug, decoder->client, "Standard set to: %s",
decoder->std_list[i].standard.name);
@@ -625,8 +631,8 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
if (err)
return err;
- tvp514x_reg_list[REG_INPUT_SEL].val = input_sel;
- tvp514x_reg_list[REG_OUTPUT_FORMATTER1].val = output_sel;
+ decoder->tvp514x_regs[REG_INPUT_SEL].val = input_sel;
+ decoder->tvp514x_regs[REG_OUTPUT_FORMATTER1].val = output_sel;
/* Clear status */
msleep(LOCK_RETRY_DELAY);
@@ -719,10 +725,9 @@ ioctl_queryctrl(struct v4l2_int_device *s, struct v4l2_queryctrl *qctrl)
switch (qctrl->id) {
case V4L2_CID_BRIGHTNESS:
- /* Brightness supported is same as standard one (0-255),
- * so make use of standard API provided.
+ /* Brightness supported is (0-255),
*/
- err = v4l2_ctrl_query_fill_std(qctrl);
+ err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128);
break;
case V4L2_CID_CONTRAST:
case V4L2_CID_SATURATION:
@@ -779,16 +784,16 @@ ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- ctrl->value = tvp514x_reg_list[REG_BRIGHTNESS].val;
+ ctrl->value = decoder->tvp514x_regs[REG_BRIGHTNESS].val;
break;
case V4L2_CID_CONTRAST:
- ctrl->value = tvp514x_reg_list[REG_CONTRAST].val;
+ ctrl->value = decoder->tvp514x_regs[REG_CONTRAST].val;
break;
case V4L2_CID_SATURATION:
- ctrl->value = tvp514x_reg_list[REG_SATURATION].val;
+ ctrl->value = decoder->tvp514x_regs[REG_SATURATION].val;
break;
case V4L2_CID_HUE:
- ctrl->value = tvp514x_reg_list[REG_HUE].val;
+ ctrl->value = decoder->tvp514x_regs[REG_HUE].val;
if (ctrl->value == 0x7F)
ctrl->value = 180;
else if (ctrl->value == 0x80)
@@ -798,7 +803,7 @@ ioctl_g_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
break;
case V4L2_CID_AUTOGAIN:
- ctrl->value = tvp514x_reg_list[REG_AFE_GAIN_CTRL].val;
+ ctrl->value = decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val;
if ((ctrl->value & 0x3) == 3)
ctrl->value = 1;
else
@@ -848,7 +853,7 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
value);
if (err)
return err;
- tvp514x_reg_list[REG_BRIGHTNESS].val = value;
+ decoder->tvp514x_regs[REG_BRIGHTNESS].val = value;
break;
case V4L2_CID_CONTRAST:
if (ctrl->value < 0 || ctrl->value > 255) {
@@ -861,7 +866,7 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
value);
if (err)
return err;
- tvp514x_reg_list[REG_CONTRAST].val = value;
+ decoder->tvp514x_regs[REG_CONTRAST].val = value;
break;
case V4L2_CID_SATURATION:
if (ctrl->value < 0 || ctrl->value > 255) {
@@ -874,7 +879,7 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
value);
if (err)
return err;
- tvp514x_reg_list[REG_SATURATION].val = value;
+ decoder->tvp514x_regs[REG_SATURATION].val = value;
break;
case V4L2_CID_HUE:
if (value == 180)
@@ -893,7 +898,7 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
value);
if (err)
return err;
- tvp514x_reg_list[REG_HUE].val = value;
+ decoder->tvp514x_regs[REG_HUE].val = value;
break;
case V4L2_CID_AUTOGAIN:
if (value == 1)
@@ -910,7 +915,7 @@ ioctl_s_ctrl(struct v4l2_int_device *s, struct v4l2_control *ctrl)
value);
if (err)
return err;
- tvp514x_reg_list[REG_AFE_GAIN_CTRL].val = value;
+ decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val = value;
break;
default:
v4l_err(decoder->client,
@@ -1275,7 +1280,7 @@ static int ioctl_init(struct v4l2_int_device *s)
struct tvp514x_decoder *decoder = s->priv;
/* Set default standard to auto */
- tvp514x_reg_list[REG_VIDEO_STD].val =
+ decoder->tvp514x_regs[REG_VIDEO_STD].val =
VIDEO_STD_AUTO_SWITCH_BIT;
return tvp514x_configure(decoder);
@@ -1344,11 +1349,6 @@ static struct v4l2_int_ioctl_desc tvp514x_ioctl_desc[] = {
(v4l2_int_ioctl_func *) ioctl_s_routing},
};
-static struct v4l2_int_slave tvp514x_slave = {
- .ioctls = tvp514x_ioctl_desc,
- .num_ioctls = ARRAY_SIZE(tvp514x_ioctl_desc),
-};
-
static struct tvp514x_decoder tvp514x_dev = {
.state = STATE_NOT_DETECTED,
@@ -1369,17 +1369,15 @@ static struct tvp514x_decoder tvp514x_dev = {
.current_std = STD_NTSC_MJ,
.std_list = tvp514x_std_list,
.num_stds = ARRAY_SIZE(tvp514x_std_list),
-
-};
-
-static struct v4l2_int_device tvp514x_int_device = {
- .module = THIS_MODULE,
- .name = TVP514X_MODULE_NAME,
- .priv = &tvp514x_dev,
- .type = v4l2_int_type_slave,
- .u = {
- .slave = &tvp514x_slave,
- },
+ .v4l2_int_device = {
+ .module = THIS_MODULE,
+ .name = TVP514X_MODULE_NAME,
+ .type = v4l2_int_type_slave,
+ },
+ .tvp514x_slave = {
+ .ioctls = tvp514x_ioctl_desc,
+ .num_ioctls = ARRAY_SIZE(tvp514x_ioctl_desc),
+ },
};
/**
@@ -1392,26 +1390,37 @@ static struct v4l2_int_device tvp514x_int_device = {
static int
tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
- struct tvp514x_decoder *decoder = &tvp514x_dev;
+ struct tvp514x_decoder *decoder;
int err;
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
- decoder->pdata = client->dev.platform_data;
- if (!decoder->pdata) {
+ decoder = kzalloc(sizeof(*decoder), GFP_KERNEL);
+ if (!decoder)
+ return -ENOMEM;
+
+ if (!client->dev.platform_data) {
v4l_err(client, "No platform data!!\n");
- return -ENODEV;
+ err = -ENODEV;
+ goto out_free;
}
+
+ *decoder = tvp514x_dev;
+ decoder->v4l2_int_device.priv = decoder;
+ decoder->pdata = client->dev.platform_data;
+ decoder->v4l2_int_device.u.slave = &decoder->tvp514x_slave;
+ memcpy(decoder->tvp514x_regs, tvp514x_reg_list_default,
+ sizeof(tvp514x_reg_list_default));
/*
* Fetch platform specific data, and configure the
* tvp514x_reg_list[] accordingly. Since this is one
* time configuration, no need to preserve.
*/
- tvp514x_reg_list[REG_OUTPUT_FORMATTER2].val |=
+ decoder->tvp514x_regs[REG_OUTPUT_FORMATTER2].val |=
(decoder->pdata->clk_polarity << 1);
- tvp514x_reg_list[REG_SYNC_CONTROL].val |=
+ decoder->tvp514x_regs[REG_SYNC_CONTROL].val |=
((decoder->pdata->hs_polarity << 2) |
(decoder->pdata->vs_polarity << 3));
/*
@@ -1419,23 +1428,27 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
*/
decoder->id = (struct i2c_device_id *)id;
/* Attach to Master */
- strcpy(tvp514x_int_device.u.slave->attach_to, decoder->pdata->master);
- decoder->v4l2_int_device = &tvp514x_int_device;
+ strcpy(decoder->v4l2_int_device.u.slave->attach_to,
+ decoder->pdata->master);
decoder->client = client;
i2c_set_clientdata(client, decoder);
/* Register with V4L2 layer as slave device */
- err = v4l2_int_device_register(decoder->v4l2_int_device);
+ err = v4l2_int_device_register(&decoder->v4l2_int_device);
if (err) {
i2c_set_clientdata(client, NULL);
v4l_err(client,
"Unable to register to v4l2. Err[%d]\n", err);
+ goto out_free;
} else
v4l_info(client, "Registered to v4l2 master %s!!\n",
decoder->pdata->master);
-
return 0;
+
+out_free:
+ kfree(decoder);
+ return err;
}
/**
@@ -1452,9 +1465,9 @@ static int __exit tvp514x_remove(struct i2c_client *client)
if (!client->adapter)
return -ENODEV; /* our client isn't attached */
- v4l2_int_device_unregister(decoder->v4l2_int_device);
+ v4l2_int_device_unregister(&decoder->v4l2_int_device);
i2c_set_clientdata(client, NULL);
-
+ kfree(decoder);
return 0;
}
/*
diff --git a/linux/drivers/media/video/tw9910.c b/linux/drivers/media/video/tw9910.c
index 4593cdea7..ed8dca3bf 100644
--- a/linux/drivers/media/video/tw9910.c
+++ b/linux/drivers/media/video/tw9910.c
@@ -460,9 +460,11 @@ static int tw9910_mask_set(struct i2c_client *client, u8 command,
u8 mask, u8 set)
{
s32 val = i2c_smbus_read_byte_data(client, command);
+ if (val < 0)
+ return val;
val &= ~mask;
- val |= set;
+ val |= set & mask;
return i2c_smbus_write_byte_data(client, command, val);
}
diff --git a/linux/drivers/media/video/usbvision/usbvision-core.c b/linux/drivers/media/video/usbvision/usbvision-core.c
index 440f1b05a..412149bbe 100644
--- a/linux/drivers/media/video/usbvision/usbvision-core.c
+++ b/linux/drivers/media/video/usbvision/usbvision-core.c
@@ -2654,7 +2654,7 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
}
route.input = mode[channel];
route.output = 0;
- call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
+ call_all(usbvision, video, s_routing, &route);
usbvision_set_audio(usbvision, audio[channel]);
return 0;
}
diff --git a/linux/drivers/media/video/usbvision/usbvision-i2c.c b/linux/drivers/media/video/usbvision/usbvision-i2c.c
index 4c74861f4..addc1716e 100644
--- a/linux/drivers/media/video/usbvision/usbvision-i2c.c
+++ b/linux/drivers/media/video/usbvision/usbvision-i2c.c
@@ -206,72 +206,78 @@ static struct i2c_algorithm usbvision_algo = {
};
-/*
- * registering functions to load algorithms at runtime
- */
-static int usbvision_i2c_usb_add_bus(struct i2c_adapter *adap)
-{
- PDEBUG(DBG_I2C, "I2C debugging is enabled [i2c]");
- PDEBUG(DBG_I2C, "ALGO debugging is enabled [i2c]");
-
- /* register new adapter to i2c module... */
-
- adap->algo = &usbvision_algo;
-
- adap->timeout = 100; /* default values, should */
- adap->retries = 3; /* be replaced by defines */
-
- i2c_add_adapter(adap);
-
- PDEBUG(DBG_I2C,"i2c bus for %s registered", adap->name);
-
- return 0;
-}
-
/* ----------------------------------------------------------------------- */
/* usbvision specific I2C functions */
/* ----------------------------------------------------------------------- */
static struct i2c_adapter i2c_adap_template;
-static struct i2c_client i2c_client_template;
int usbvision_i2c_register(struct usb_usbvision *usbvision)
{
+ static unsigned short saa711x_addrs[] = {
+ 0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */
+ 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */
+ I2C_CLIENT_END };
+
memcpy(&usbvision->i2c_adap, &i2c_adap_template,
sizeof(struct i2c_adapter));
- memcpy(&usbvision->i2c_client, &i2c_client_template,
- sizeof(struct i2c_client));
sprintf(usbvision->i2c_adap.name + strlen(usbvision->i2c_adap.name),
" #%d", usbvision->vdev->num);
PDEBUG(DBG_I2C,"Adaptername: %s", usbvision->i2c_adap.name);
usbvision->i2c_adap.dev.parent = &usbvision->dev->dev;
- i2c_set_adapdata(&usbvision->i2c_adap, usbvision);
- i2c_set_clientdata(&usbvision->i2c_client, usbvision);
-
- usbvision->i2c_client.adapter = &usbvision->i2c_adap;
+ i2c_set_adapdata(&usbvision->i2c_adap, &usbvision->v4l2_dev);
if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) {
printk(KERN_ERR "usbvision_register: can't write reg\n");
return -EBUSY;
}
-#ifdef CONFIG_MODULES
+ PDEBUG(DBG_I2C, "I2C debugging is enabled [i2c]");
+ PDEBUG(DBG_I2C, "ALGO debugging is enabled [i2c]");
+
+ /* register new adapter to i2c module... */
+
+ usbvision->i2c_adap.algo = &usbvision_algo;
+
+ usbvision->i2c_adap.timeout = 100; /* default values, should */
+ usbvision->i2c_adap.retries = 3; /* be replaced by defines */
+
+ i2c_add_adapter(&usbvision->i2c_adap);
+
+ PDEBUG(DBG_I2C, "i2c bus for %s registered", usbvision->i2c_adap.name);
+
/* Request the load of the i2c modules we need */
switch (usbvision_device_data[usbvision->DevModel].Codec) {
case CODEC_SAA7113:
- request_module("saa7115");
- break;
case CODEC_SAA7111:
- request_module("saa7115");
+ v4l2_i2c_new_probed_subdev(&usbvision->i2c_adap, "saa7115",
+ "saa7115_auto", saa711x_addrs);
break;
}
if (usbvision_device_data[usbvision->DevModel].Tuner == 1) {
- request_module("tuner");
+ struct v4l2_subdev *sd;
+ enum v4l2_i2c_tuner_type type;
+ struct tuner_setup tun_setup;
+
+ sd = v4l2_i2c_new_probed_subdev(&usbvision->i2c_adap, "tuner",
+ "tuner", v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+ /* depending on whether we found a demod or not, select
+ the tuner type. */
+ type = sd ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
+
+ sd = v4l2_i2c_new_probed_subdev(&usbvision->i2c_adap, "tuner",
+ "tuner", v4l2_i2c_tuner_addrs(type));
+
+ if (usbvision->tuner_type != -1) {
+ tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+ tun_setup.type = usbvision->tuner_type;
+ tun_setup.addr = v4l2_i2c_subdev_addr(sd);
+ call_all(usbvision, tuner, s_type_addr, &tun_setup);
+ }
}
-#endif
- return usbvision_i2c_usb_add_bus(&usbvision->i2c_adap);
+ return 0;
}
int usbvision_i2c_unregister(struct usb_usbvision *usbvision)
@@ -284,67 +290,6 @@ int usbvision_i2c_unregister(struct usb_usbvision *usbvision)
return 0;
}
-void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,
- void *arg)
-{
- i2c_clients_command(&usbvision->i2c_adap, cmd, arg);
-}
-
-static int attach_inform(struct i2c_client *client)
-{
- struct usb_usbvision *usbvision;
-
- usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter);
-
- switch (client->addr << 1) {
- case 0x42 << 1:
- case 0x43 << 1:
- case 0x4a << 1:
- case 0x4b << 1:
- PDEBUG(DBG_I2C,"attach_inform: tda9887 detected.");
- break;
- case 0x42:
- PDEBUG(DBG_I2C,"attach_inform: saa7114 detected.");
- break;
- case 0x4a:
- PDEBUG(DBG_I2C,"attach_inform: saa7113 detected.");
- break;
- case 0x48:
- PDEBUG(DBG_I2C,"attach_inform: saa7111 detected.");
- break;
- case 0xa0:
- PDEBUG(DBG_I2C,"attach_inform: eeprom detected.");
- break;
-
- default:
- {
- struct tuner_setup tun_setup;
-
- PDEBUG(DBG_I2C,"attach inform: detected I2C address %x", client->addr << 1);
- usbvision->tuner_addr = client->addr;
-
- if ((usbvision->have_tuner) && (usbvision->tuner_type != -1)) {
- tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
- tun_setup.type = usbvision->tuner_type;
- tun_setup.addr = usbvision->tuner_addr;
- call_i2c_clients(usbvision, TUNER_SET_TYPE_ADDR, &tun_setup);
- }
- }
- break;
- }
- return 0;
-}
-
-static int detach_inform(struct i2c_client *client)
-{
- struct usb_usbvision *usbvision;
-
- usbvision = (struct usb_usbvision *)i2c_get_adapdata(client->adapter);
-
- PDEBUG(DBG_I2C,"usbvision[%d] detaches %s", usbvision->nr, client->name);
- return 0;
-}
-
static int
usbvision_i2c_read_max4(struct usb_usbvision *usbvision, unsigned char addr,
char *buf, short len)
@@ -517,14 +462,6 @@ static int usbvision_i2c_read(struct usb_usbvision *usbvision, unsigned char add
static struct i2c_adapter i2c_adap_template = {
.owner = THIS_MODULE,
.name = "usbvision",
- .id = I2C_HW_B_BT848, /* FIXME */
- .client_register = attach_inform,
- .client_unregister = detach_inform,
- .class = I2C_CLASS_TV_ANALOG,
-};
-
-static struct i2c_client i2c_client_template = {
- .name = "usbvision internal",
};
/*
diff --git a/linux/drivers/media/video/usbvision/usbvision-video.c b/linux/drivers/media/video/usbvision/usbvision-video.c
index 334c77d91..cfa184d63 100644
--- a/linux/drivers/media/video/usbvision/usbvision-video.c
+++ b/linux/drivers/media/video/usbvision/usbvision-video.c
@@ -212,7 +212,7 @@ static ssize_t show_hue(struct device *cd,
ctrl.id = V4L2_CID_HUE;
ctrl.value = 0;
if(usbvision->user)
- call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
+ call_all(usbvision, core, g_ctrl, &ctrl);
return sprintf(buf, "%d\n", ctrl.value);
}
static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
@@ -227,7 +227,7 @@ static ssize_t show_contrast(struct device *cd,
ctrl.id = V4L2_CID_CONTRAST;
ctrl.value = 0;
if(usbvision->user)
- call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
+ call_all(usbvision, core, g_ctrl, &ctrl);
return sprintf(buf, "%d\n", ctrl.value);
}
static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
@@ -242,7 +242,7 @@ static ssize_t show_brightness(struct device *cd,
ctrl.id = V4L2_CID_BRIGHTNESS;
ctrl.value = 0;
if(usbvision->user)
- call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
+ call_all(usbvision, core, g_ctrl, &ctrl);
return sprintf(buf, "%d\n", ctrl.value);
}
static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
@@ -257,7 +257,7 @@ static ssize_t show_saturation(struct device *cd,
ctrl.id = V4L2_CID_SATURATION;
ctrl.value = 0;
if(usbvision->user)
- call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
+ call_all(usbvision, core, g_ctrl, &ctrl);
return sprintf(buf, "%d\n", ctrl.value);
}
static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
@@ -622,8 +622,7 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
usbvision->tvnormId=*id;
mutex_lock(&usbvision->lock);
- call_i2c_clients(usbvision, VIDIOC_S_STD,
- &usbvision->tvnormId);
+ call_all(usbvision, tuner, s_std, usbvision->tvnormId);
mutex_unlock(&usbvision->lock);
/* propagate the change to the decoder */
usbvision_muxsel(usbvision, usbvision->ctl_input);
@@ -645,7 +644,7 @@ static int vidioc_g_tuner (struct file *file, void *priv,
strcpy(vt->name, "Television");
}
/* Let clients fill in the remainder of this struct */
- call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt);
+ call_all(usbvision, tuner, g_tuner, vt);
return 0;
}
@@ -659,7 +658,7 @@ static int vidioc_s_tuner (struct file *file, void *priv,
if (!usbvision->have_tuner || vt->index)
return -EINVAL;
/* let clients handle this */
- call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
+ call_all(usbvision, tuner, s_tuner, vt);
return 0;
}
@@ -690,7 +689,7 @@ static int vidioc_s_frequency (struct file *file, void *priv,
return -EINVAL;
usbvision->freq = freq->frequency;
- call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, freq);
+ call_all(usbvision, tuner, s_frequency, freq);
return 0;
}
@@ -728,7 +727,7 @@ static int vidioc_queryctrl (struct file *file, void *priv,
memset(ctrl,0,sizeof(*ctrl));
ctrl->id=id;
- call_i2c_clients(usbvision, VIDIOC_QUERYCTRL, ctrl);
+ call_all(usbvision, core, queryctrl, ctrl);
if (!ctrl->type)
return -EINVAL;
@@ -740,7 +739,7 @@ static int vidioc_g_ctrl (struct file *file, void *priv,
struct v4l2_control *ctrl)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
+ call_all(usbvision, core, g_ctrl, ctrl);
return 0;
}
@@ -749,7 +748,7 @@ static int vidioc_s_ctrl (struct file *file, void *priv,
struct v4l2_control *ctrl)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
+ call_all(usbvision, core, s_ctrl, ctrl);
return 0;
}
@@ -900,10 +899,9 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
usbvision->streaming = Stream_On;
- call_i2c_clients(usbvision,VIDIOC_STREAMON , &b);
+ call_all(usbvision, video, s_stream, 1);
return 0;
}
@@ -912,7 +910,6 @@ static int vidioc_streamoff(struct file *file,
void *priv, enum v4l2_buf_type type)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
@@ -920,7 +917,7 @@ static int vidioc_streamoff(struct file *file,
if(usbvision->streaming == Stream_On) {
usbvision_stream_interrupt(usbvision);
/* Stop all video streamings */
- call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b);
+ call_all(usbvision, video, s_stream, 0);
}
usbvision_empty_framequeues(usbvision);
@@ -1043,7 +1040,7 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
if(usbvision->streaming != Stream_On) {
/* no stream is running, make it running ! */
usbvision->streaming = Stream_On;
- call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL);
+ call_all(usbvision, video, s_stream, 1);
}
/* Then, enqueue as many frames as possible
@@ -1214,7 +1211,7 @@ static int usbvision_radio_open(struct file *file)
// If so far no errors then we shall start the radio
usbvision->radio = 1;
- call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type);
+ call_all(usbvision, tuner, s_radio);
usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO);
usbvision->user++;
}
@@ -1427,7 +1424,7 @@ static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision,
}
*vdev = *vdev_template;
// vdev->minor = -1;
- vdev->parent = &usb_dev->dev;
+ vdev->v4l2_dev = &usbvision->v4l2_dev;
snprintf(vdev->name, sizeof(vdev->name), "%s", name);
video_set_drvdata(vdev, usbvision);
return vdev;
@@ -1548,33 +1545,30 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev)
{
struct usb_usbvision *usbvision;
- if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) ==
- NULL) {
- goto err_exit;
- }
+ usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL);
+ if (usbvision == NULL)
+ return NULL;
usbvision->dev = dev;
+ if (v4l2_device_register(&dev->dev, &usbvision->v4l2_dev))
+ goto err_free;
mutex_init(&usbvision->lock); /* available */
// prepare control urb for control messages during interrupts
usbvision->ctrlUrb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
- if (usbvision->ctrlUrb == NULL) {
- goto err_exit;
- }
+ if (usbvision->ctrlUrb == NULL)
+ goto err_unreg;
init_waitqueue_head(&usbvision->ctrlUrb_wq);
usbvision_init_powerOffTimer(usbvision);
return usbvision;
-err_exit:
- if (usbvision && usbvision->ctrlUrb) {
- usb_free_urb(usbvision->ctrlUrb);
- }
- if (usbvision) {
- kfree(usbvision);
- }
+err_unreg:
+ v4l2_device_unregister(&usbvision->v4l2_dev);
+err_free:
+ kfree(usbvision);
return NULL;
}
@@ -1604,6 +1598,7 @@ static void usbvision_release(struct usb_usbvision *usbvision)
usb_free_urb(usbvision->ctrlUrb);
}
+ v4l2_device_unregister(&usbvision->v4l2_dev);
kfree(usbvision);
PDEBUG(DBG_PROBE, "success");
@@ -1739,8 +1734,6 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
usbvision->tuner_type = usbvision_device_data[model].TunerType;
}
- usbvision->tuner_addr = ADDR_UNSET;
-
usbvision->DevModel = model;
usbvision->remove_pending = 0;
usbvision->iface = ifnum;
diff --git a/linux/drivers/media/video/usbvision/usbvision.h b/linux/drivers/media/video/usbvision/usbvision.h
index 590ff1e19..dc86c2139 100644
--- a/linux/drivers/media/video/usbvision/usbvision.h
+++ b/linux/drivers/media/video/usbvision/usbvision.h
@@ -35,7 +35,7 @@
#include <linux/usb.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
#include <media/tuner.h>
#include <linux/videodev2.h>
#include "compat.h"
@@ -358,13 +358,13 @@ extern struct usbvision_device_data_st usbvision_device_data[];
extern struct usb_device_id usbvision_table[];
struct usb_usbvision {
+ struct v4l2_device v4l2_dev;
struct video_device *vdev; /* Video Device */
struct video_device *rdev; /* Radio Device */
struct video_device *vbi; /* VBI Device */
/* i2c Declaration Section*/
struct i2c_adapter i2c_adap;
- struct i2c_client i2c_client;
struct urb *ctrlUrb;
unsigned char ctrlUrbBuffer[8];
@@ -375,7 +375,6 @@ struct usb_usbvision {
/* configuration part */
int have_tuner;
int tuner_type;
- int tuner_addr;
int bridgeType; // NT1003, NT1004, NT1005
int radio;
int video_inputs; // # of inputs
@@ -465,6 +464,8 @@ struct usb_usbvision {
int ComprBlockTypes[4];
};
+#define call_all(usbvision, o, f, args...) \
+ v4l2_device_call_all(&usbvision->v4l2_dev, 0, o, f, ##args)
/* --------------------------------------------------------------- */
/* defined in usbvision-i2c.c */
@@ -476,7 +477,6 @@ struct usb_usbvision {
/* ----------------------------------------------------------------------- */
int usbvision_i2c_register(struct usb_usbvision *usbvision);
int usbvision_i2c_unregister(struct usb_usbvision *usbvision);
-void call_i2c_clients(struct usb_usbvision *usbvision, unsigned int cmd,void *arg);
/* defined in usbvision-core.c */
int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg);
diff --git a/linux/drivers/media/video/uvc/uvc_driver.c b/linux/drivers/media/video/uvc/uvc_driver.c
index 2a41eb418..0d2d87198 100644
--- a/linux/drivers/media/video/uvc/uvc_driver.c
+++ b/linux/drivers/media/video/uvc/uvc_driver.c
@@ -1863,6 +1863,15 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* ViMicro */
+ { .match_flags = USB_DEVICE_ID_MATCH_VENDOR
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x0ac8,
+ .idProduct = 0x0000,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_FIX_BANDWIDTH },
/* MT6227 */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
diff --git a/linux/drivers/media/video/uvc/uvc_video.c b/linux/drivers/media/video/uvc/uvc_video.c
index 04c791213..82a9999b6 100644
--- a/linux/drivers/media/video/uvc/uvc_video.c
+++ b/linux/drivers/media/video/uvc/uvc_video.c
@@ -61,7 +61,7 @@ int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
return 0;
}
-static void uvc_fixup_buffer_size(struct uvc_video_device *video,
+static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
struct uvc_streaming_control *ctrl)
{
struct uvc_format *format;
@@ -84,6 +84,31 @@ static void uvc_fixup_buffer_size(struct uvc_video_device *video,
video->dev->uvc_version < 0x0110))
ctrl->dwMaxVideoFrameSize =
frame->dwMaxVideoFrameBufferSize;
+
+ if (video->dev->quirks & UVC_QUIRK_FIX_BANDWIDTH &&
+ video->streaming->intf->num_altsetting > 1) {
+ u32 interval;
+ u32 bandwidth;
+
+ interval = (ctrl->dwFrameInterval > 100000)
+ ? ctrl->dwFrameInterval
+ : frame->dwFrameInterval[0];
+
+ /* Compute a bandwidth estimation by multiplying the frame
+ * size by the number of video frames per second, divide the
+ * result by the number of USB frames (or micro-frames for
+ * high-speed devices) per second and add the UVC header size
+ * (assumed to be 12 bytes long).
+ */
+ bandwidth = frame->wWidth * frame->wHeight / 8 * format->bpp;
+ bandwidth *= 10000000 / interval + 1;
+ bandwidth /= 1000;
+ if (video->dev->udev->speed == USB_SPEED_HIGH)
+ bandwidth /= 8;
+ bandwidth += 12;
+
+ ctrl->dwMaxPayloadTransferSize = bandwidth;
+ }
}
static int uvc_get_video_ctrl(struct uvc_video_device *video,
@@ -158,10 +183,11 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video,
ctrl->bMaxVersion = 0;
}
- /* Some broken devices return a null or wrong dwMaxVideoFrameSize.
- * Try to get the value from the format and frame descriptors.
+ /* Some broken devices return null or wrong dwMaxVideoFrameSize and
+ * dwMaxPayloadTransferSize fields. Try to get the value from the
+ * format and frame descriptors.
*/
- uvc_fixup_buffer_size(video, ctrl);
+ uvc_fixup_video_ctrl(video, ctrl);
ret = 0;
out:
@@ -540,6 +566,9 @@ static void uvc_video_decode_bulk(struct urb *urb,
u8 *mem;
int len, ret;
+ if (urb->actual_length == 0)
+ return;
+
mem = urb->transfer_buffer;
len = urb->actual_length;
video->bulk.payload_size += len;
@@ -1030,11 +1059,20 @@ int uvc_video_init(struct uvc_video_device *video)
*/
usb_set_interface(video->dev->udev, video->streaming->intfnum, 0);
- /* Some webcams don't suport GET_DEF requests on the probe control. We
- * fall back to GET_CUR if GET_DEF fails.
+ /* Set the streaming probe control with default streaming parameters
+ * retrieved from the device. Webcams that don't suport GET_DEF
+ * requests on the probe control will just keep their current streaming
+ * parameters.
+ */
+ if (uvc_get_video_ctrl(video, probe, 1, GET_DEF) == 0)
+ uvc_set_video_ctrl(video, probe, 1);
+
+ /* Initialize the streaming parameters with the probe control current
+ * value. This makes sure SET_CUR requests on the streaming commit
+ * control will always use values retrieved from a successful GET_CUR
+ * request on the probe control, as required by the UVC specification.
*/
- if ((ret = uvc_get_video_ctrl(video, probe, 1, GET_DEF)) < 0 &&
- (ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0)
+ if ((ret = uvc_get_video_ctrl(video, probe, 1, GET_CUR)) < 0)
return ret;
/* Check if the default format descriptor exists. Use the first
diff --git a/linux/drivers/media/video/uvc/uvcvideo.h b/linux/drivers/media/video/uvc/uvcvideo.h
index 408b8b846..53d5c9e0c 100644
--- a/linux/drivers/media/video/uvc/uvcvideo.h
+++ b/linux/drivers/media/video/uvc/uvcvideo.h
@@ -315,6 +315,7 @@ struct uvc_xu_control {
#define UVC_QUIRK_STREAM_NO_FID 0x00000010
#define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020
#define UVC_QUIRK_PRUNE_CONTROLS 0x00000040
+#define UVC_QUIRK_FIX_BANDWIDTH 0x00000080
/* Format flags */
#define UVC_FMT_FLAG_COMPRESSED 0x00000001
diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c
index 8ae8dd366..bc5b40012 100644
--- a/linux/drivers/media/video/v4l2-common.c
+++ b/linux/drivers/media/video/v4l2-common.c
@@ -335,6 +335,12 @@ const char **v4l2_ctrl_get_menu(u32 id)
"Aperture Priority Mode",
NULL
};
+ static const char *colorfx[] = {
+ "None",
+ "Black & White",
+ "Sepia",
+ NULL
+ };
switch (id) {
case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
@@ -371,6 +377,8 @@ const char **v4l2_ctrl_get_menu(u32 id)
return camera_power_line_frequency;
case V4L2_CID_EXPOSURE_AUTO:
return camera_exposure_auto;
+ case V4L2_CID_COLORFX:
+ return colorfx;
default:
return NULL;
}
@@ -383,16 +391,16 @@ const char *v4l2_ctrl_get_name(u32 id)
switch (id) {
/* USER controls */
case V4L2_CID_USER_CLASS: return "User Controls";
+ case V4L2_CID_BRIGHTNESS: return "Brightness";
+ case V4L2_CID_CONTRAST: return "Contrast";
+ case V4L2_CID_SATURATION: return "Saturation";
+ case V4L2_CID_HUE: return "Hue";
case V4L2_CID_AUDIO_VOLUME: return "Volume";
- case V4L2_CID_AUDIO_MUTE: return "Mute";
case V4L2_CID_AUDIO_BALANCE: return "Balance";
case V4L2_CID_AUDIO_BASS: return "Bass";
case V4L2_CID_AUDIO_TREBLE: return "Treble";
+ case V4L2_CID_AUDIO_MUTE: return "Mute";
case V4L2_CID_AUDIO_LOUDNESS: return "Loudness";
- case V4L2_CID_BRIGHTNESS: return "Brightness";
- case V4L2_CID_CONTRAST: return "Contrast";
- case V4L2_CID_SATURATION: return "Saturation";
- case V4L2_CID_HUE: return "Hue";
case V4L2_CID_BLACK_LEVEL: return "Black Level";
case V4L2_CID_AUTO_WHITE_BALANCE: return "White Balance, Automatic";
case V4L2_CID_DO_WHITE_BALANCE: return "Do White Balance";
@@ -413,6 +421,7 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_BACKLIGHT_COMPENSATION: return "Backlight Compensation";
case V4L2_CID_CHROMA_AGC: return "Chroma AGC";
case V4L2_CID_COLOR_KILLER: return "Color Killer";
+ case V4L2_CID_COLORFX: return "Color Effects";
/* MPEG controls */
case V4L2_CID_MPEG_CLASS: return "MPEG Encoder Controls";
@@ -491,16 +500,25 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
case V4L2_CID_HFLIP:
case V4L2_CID_VFLIP:
case V4L2_CID_HUE_AUTO:
+ case V4L2_CID_CHROMA_AGC:
+ case V4L2_CID_COLOR_KILLER:
case V4L2_CID_MPEG_AUDIO_MUTE:
case V4L2_CID_MPEG_VIDEO_MUTE:
case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
case V4L2_CID_MPEG_VIDEO_PULLDOWN:
case V4L2_CID_EXPOSURE_AUTO_PRIORITY:
+ case V4L2_CID_FOCUS_AUTO:
case V4L2_CID_PRIVACY:
qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
min = 0;
max = step = 1;
break;
+ case V4L2_CID_PAN_RESET:
+ case V4L2_CID_TILT_RESET:
+ qctrl->type = V4L2_CTRL_TYPE_BUTTON;
+ qctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
+ min = max = step = def = 0;
+ break;
case V4L2_CID_POWER_LINE_FREQUENCY:
case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
case V4L2_CID_MPEG_AUDIO_ENCODING:
@@ -518,6 +536,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
case V4L2_CID_MPEG_STREAM_TYPE:
case V4L2_CID_MPEG_STREAM_VBI_FMT:
case V4L2_CID_EXPOSURE_AUTO:
+ case V4L2_CID_COLORFX:
qctrl->type = V4L2_CTRL_TYPE_MENU;
step = 1;
break;
@@ -548,8 +567,17 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
case V4L2_CID_CONTRAST:
case V4L2_CID_SATURATION:
case V4L2_CID_HUE:
+ case V4L2_CID_RED_BALANCE:
+ case V4L2_CID_BLUE_BALANCE:
+ case V4L2_CID_GAMMA:
qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
break;
+ case V4L2_CID_PAN_RELATIVE:
+ case V4L2_CID_TILT_RELATIVE:
+ case V4L2_CID_FOCUS_RELATIVE:
+ case V4L2_CID_ZOOM_RELATIVE:
+ qctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
+ break;
}
qctrl->minimum = min;
qctrl->maximum = max;
@@ -561,148 +589,9 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste
}
EXPORT_SYMBOL(v4l2_ctrl_query_fill);
-/* Fill in a struct v4l2_queryctrl with standard values based on
- the control ID. */
-int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl)
-{
- switch (qctrl->id) {
- /* USER controls */
- case V4L2_CID_USER_CLASS:
- case V4L2_CID_MPEG_CLASS:
- return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0);
- case V4L2_CID_AUDIO_VOLUME:
- return v4l2_ctrl_query_fill(qctrl, 0, 65535, 65535 / 100, 58880);
- case V4L2_CID_AUDIO_MUTE:
- case V4L2_CID_AUDIO_LOUDNESS:
- return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- return v4l2_ctrl_query_fill(qctrl, 0, 65535, 65535 / 100, 32768);
- case V4L2_CID_BRIGHTNESS:
- return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128);
- case V4L2_CID_CONTRAST:
- case V4L2_CID_SATURATION:
- return v4l2_ctrl_query_fill(qctrl, 0, 127, 1, 64);
- case V4L2_CID_HUE:
- return v4l2_ctrl_query_fill(qctrl, -128, 127, 1, 0);
-
- /* MPEG controls */
- case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
- return v4l2_ctrl_query_fill(qctrl,
- V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100,
- V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 1,
- V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
- case V4L2_CID_MPEG_AUDIO_ENCODING:
- return v4l2_ctrl_query_fill(qctrl,
- V4L2_MPEG_AUDIO_ENCODING_LAYER_1,
- V4L2_MPEG_AUDIO_ENCODING_AC3, 1,
- V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
- case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
- return v4l2_ctrl_query_fill(qctrl,
- V4L2_MPEG_AUDIO_L1_BITRATE_32K,
- V4L2_MPEG_AUDIO_L1_BITRATE_448K, 1,
- V4L2_MPEG_AUDIO_L1_BITRATE_256K);
- case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
- return v4l2_ctrl_query_fill(qctrl,
- V4L2_MPEG_AUDIO_L2_BITRATE_32K,
- V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
- V4L2_MPEG_AUDIO_L2_BITRATE_224K);
- case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
- return v4l2_ctrl_query_fill(qctrl,
- V4L2_MPEG_AUDIO_L3_BITRATE_32K,
- V4L2_MPEG_AUDIO_L3_BITRATE_320K, 1,
- V4L2_MPEG_AUDIO_L3_BITRATE_192K);
- case V4L2_CID_MPEG_AUDIO_AAC_BITRATE:
- return v4l2_ctrl_query_fill(qctrl, 0, 6400, 1, 3200000);
- case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
- return v4l2_ctrl_query_fill(qctrl,
- V4L2_MPEG_AUDIO_AC3_BITRATE_32K,
- V4L2_MPEG_AUDIO_AC3_BITRATE_640K, 1,
- V4L2_MPEG_AUDIO_AC3_BITRATE_384K);
- case V4L2_CID_MPEG_AUDIO_MODE:
- return v4l2_ctrl_query_fill(qctrl,
- V4L2_MPEG_AUDIO_MODE_STEREO,
- V4L2_MPEG_AUDIO_MODE_MONO, 1,
- V4L2_MPEG_AUDIO_MODE_STEREO);
- case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
- return v4l2_ctrl_query_fill(qctrl,
- V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
- V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 1,
- V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4);
- case V4L2_CID_MPEG_AUDIO_EMPHASIS:
- return v4l2_ctrl_query_fill(qctrl,
- V4L2_MPEG_AUDIO_EMPHASIS_NONE,
- V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 1,
- V4L2_MPEG_AUDIO_EMPHASIS_NONE);
- case V4L2_CID_MPEG_AUDIO_CRC:
- return v4l2_ctrl_query_fill(qctrl,
- V4L2_MPEG_AUDIO_CRC_NONE,
- V4L2_MPEG_AUDIO_CRC_CRC16, 1,
- V4L2_MPEG_AUDIO_CRC_NONE);
- case V4L2_CID_MPEG_AUDIO_MUTE:
- return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
- case V4L2_CID_MPEG_VIDEO_ENCODING:
- return v4l2_ctrl_query_fill(qctrl,
- V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
- V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1,
- V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
- case V4L2_CID_MPEG_VIDEO_ASPECT:
- return v4l2_ctrl_query_fill(qctrl,
- V4L2_MPEG_VIDEO_ASPECT_1x1,
- V4L2_MPEG_VIDEO_ASPECT_221x100, 1,
- V4L2_MPEG_VIDEO_ASPECT_4x3);
- case V4L2_CID_MPEG_VIDEO_B_FRAMES:
- return v4l2_ctrl_query_fill(qctrl, 0, 33, 1, 2);
- case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
- return v4l2_ctrl_query_fill(qctrl, 1, 34, 1, 12);
- case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
- return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1);
- case V4L2_CID_MPEG_VIDEO_PULLDOWN:
- return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
- return v4l2_ctrl_query_fill(qctrl,
- V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
- V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
- V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
- case V4L2_CID_MPEG_VIDEO_BITRATE:
- return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000);
- case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
- return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000);
- case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
- return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
- case V4L2_CID_MPEG_VIDEO_MUTE:
+ case V4L2_CID_CAMERA_CLASS:
+ case V4L2_CID_COLORFX:
return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
- case V4L2_CID_MPEG_VIDEO_MUTE_YUV: /* Init YUV (really YCbCr) to black */
- return v4l2_ctrl_query_fill(qctrl, 0, 0xffffff, 1, 0x008080);
- case V4L2_CID_MPEG_STREAM_TYPE:
- return v4l2_ctrl_query_fill(qctrl,
- V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
- V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, 1,
- V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
- case V4L2_CID_MPEG_STREAM_PID_PMT:
- return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 16);
- case V4L2_CID_MPEG_STREAM_PID_AUDIO:
- return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 260);
- case V4L2_CID_MPEG_STREAM_PID_VIDEO:
- return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 256);
- case V4L2_CID_MPEG_STREAM_PID_PCR:
- return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 259);
- case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO:
- return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
- case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO:
- return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
- case V4L2_CID_MPEG_STREAM_VBI_FMT:
- return v4l2_ctrl_query_fill(qctrl,
- V4L2_MPEG_STREAM_VBI_FMT_NONE,
- V4L2_MPEG_STREAM_VBI_FMT_IVTV, 1,
- V4L2_MPEG_STREAM_VBI_FMT_NONE);
- default:
- return -EINVAL;
- }
-}
-EXPORT_SYMBOL(v4l2_ctrl_query_fill_std);
-
/* Fill in a struct v4l2_querymenu based on the struct v4l2_queryctrl and
the menu. The qctrl pointer may be NULL, in which case it is ignored.
If menu_items is NULL, then the menu items are retrieved using
@@ -1049,6 +938,15 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter,
}
EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev);
+/* Return i2c client address of v4l2_subdev. */
+unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return client ? client->addr : I2C_CLIENT_END;
+}
+EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_addr);
+
/* Return a list of I2C tuner addresses to probe. Use only if the tuner
addresses are unknown. */
const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type)