diff options
25 files changed, 1027 insertions, 112 deletions
diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware index a52adfc9a57f..3d1b0ab70c8e 100644 --- a/Documentation/dvb/get_dvb_firmware +++ b/Documentation/dvb/get_dvb_firmware | |||
| @@ -25,7 +25,7 @@ use IO::Handle; | |||
| 25 | "tda10046lifeview", "av7110", "dec2000t", "dec2540t", | 25 | "tda10046lifeview", "av7110", "dec2000t", "dec2540t", |
| 26 | "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004", | 26 | "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004", |
| 27 | "or51211", "or51132_qam", "or51132_vsb", "bluebird", | 27 | "or51211", "or51132_qam", "or51132_vsb", "bluebird", |
| 28 | "opera1", "cx231xx", "cx18", "cx23885", "pvrusb2" ); | 28 | "opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718" ); |
| 29 | 29 | ||
| 30 | # Check args | 30 | # Check args |
| 31 | syntax() if (scalar(@ARGV) != 1); | 31 | syntax() if (scalar(@ARGV) != 1); |
| @@ -381,6 +381,57 @@ sub cx18 { | |||
| 381 | $allfiles; | 381 | $allfiles; |
| 382 | } | 382 | } |
| 383 | 383 | ||
| 384 | sub mpc718 { | ||
| 385 | my $archive = 'Yuan MPC718 TV Tuner Card 2.13.10.1016.zip'; | ||
| 386 | my $url = "ftp://ftp.work.acer-euro.com/desktop/aspire_idea510/vista/Drivers/$archive"; | ||
| 387 | my $fwfile = "dvb-cx18-mpc718-mt352.fw"; | ||
| 388 | my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); | ||
| 389 | |||
| 390 | checkstandard(); | ||
| 391 | wgetfile($archive, $url); | ||
| 392 | unzip($archive, $tmpdir); | ||
| 393 | |||
| 394 | my $sourcefile = "$tmpdir/Yuan MPC718 TV Tuner Card 2.13.10.1016/mpc718_32bit/yuanrap.sys"; | ||
| 395 | my $found = 0; | ||
| 396 | |||
| 397 | open IN, '<', $sourcefile or die "Couldn't open $sourcefile to extract $fwfile data\n"; | ||
| 398 | binmode IN; | ||
| 399 | open OUT, '>', $fwfile; | ||
| 400 | binmode OUT; | ||
| 401 | { | ||
| 402 | # Block scope because we change the line terminator variable $/ | ||
| 403 | my $prevlen = 0; | ||
| 404 | my $currlen; | ||
| 405 | |||
| 406 | # Buried in the data segment are 3 runs of almost identical | ||
| 407 | # register-value pairs that end in 0x5d 0x01 which is a "TUNER GO" | ||
| 408 | # command for the MT352. | ||
| 409 | # Pull out the middle run (because it's easy) of register-value | ||
| 410 | # pairs to make the "firmware" file. | ||
| 411 | |||
| 412 | local $/ = "\x5d\x01"; # MT352 "TUNER GO" | ||
| 413 | |||
| 414 | while (<IN>) { | ||
| 415 | $currlen = length($_); | ||
| 416 | if ($prevlen == $currlen && $currlen <= 64) { | ||
| 417 | chop; chop; # Get rid of "TUNER GO" | ||
| 418 | s/^\0\0//; # get rid of leading 00 00 if it's there | ||
| 419 | printf OUT "$_"; | ||
| 420 | $found = 1; | ||
| 421 | last; | ||
| 422 | } | ||
| 423 | $prevlen = $currlen; | ||
| 424 | } | ||
| 425 | } | ||
| 426 | close OUT; | ||
| 427 | close IN; | ||
| 428 | if (!$found) { | ||
| 429 | unlink $fwfile; | ||
| 430 | die "Couldn't find valid register-value sequence in $sourcefile for $fwfile\n"; | ||
| 431 | } | ||
| 432 | $fwfile; | ||
| 433 | } | ||
| 434 | |||
| 384 | sub cx23885 { | 435 | sub cx23885 { |
| 385 | my $url = "http://linuxtv.org/downloads/firmware/"; | 436 | my $url = "http://linuxtv.org/downloads/firmware/"; |
| 386 | 437 | ||
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index 873630e7e53e..014d255231fc 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx | |||
| @@ -66,3 +66,4 @@ | |||
| 66 | 68 -> Terratec AV350 (em2860) [0ccd:0084] | 66 | 68 -> Terratec AV350 (em2860) [0ccd:0084] |
| 67 | 69 -> KWorld ATSC 315U HDTV TV Box (em2882) [eb1a:a313] | 67 | 69 -> KWorld ATSC 315U HDTV TV Box (em2882) [eb1a:a313] |
| 68 | 70 -> Evga inDtube (em2882) | 68 | 70 -> Evga inDtube (em2882) |
| 69 | 71 -> Silvercrest Webcam 1.3mpix (em2820/em2840) | ||
diff --git a/drivers/media/common/tuners/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c index b6da9c3873fe..aa20ce8cc668 100644 --- a/drivers/media/common/tuners/tuner-xc2028.c +++ b/drivers/media/common/tuners/tuner-xc2028.c | |||
| @@ -1096,8 +1096,19 @@ static int xc2028_set_params(struct dvb_frontend *fe, | |||
| 1096 | } | 1096 | } |
| 1097 | 1097 | ||
| 1098 | /* All S-code tables need a 200kHz shift */ | 1098 | /* All S-code tables need a 200kHz shift */ |
| 1099 | if (priv->ctrl.demod) | 1099 | if (priv->ctrl.demod) { |
| 1100 | demod = priv->ctrl.demod + 200; | 1100 | demod = priv->ctrl.demod + 200; |
| 1101 | /* | ||
| 1102 | * The DTV7 S-code table needs a 700 kHz shift. | ||
| 1103 | * Thanks to Terry Wu <terrywu2009@gmail.com> for reporting this | ||
| 1104 | * | ||
| 1105 | * DTV7 is only used in Australia. Germany or Italy may also | ||
| 1106 | * use this firmware after initialization, but a tune to a UHF | ||
| 1107 | * channel should then cause DTV78 to be used. | ||
| 1108 | */ | ||
| 1109 | if (type & DTV7) | ||
| 1110 | demod += 500; | ||
| 1111 | } | ||
| 1101 | 1112 | ||
| 1102 | return generic_set_freq(fe, p->frequency, | 1113 | return generic_set_freq(fe, p->frequency, |
| 1103 | T_DIGITAL_TV, type, 0, demod); | 1114 | T_DIGITAL_TV, type, 0, demod); |
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index 68eb4493f991..d8d4214fd65f 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | config TTPCI_EEPROM | 1 | config TTPCI_EEPROM |
| 2 | tristate | 2 | tristate |
| 3 | depends on I2C | ||
| 3 | default n | 4 | default n |
| 4 | 5 | ||
| 5 | config DVB_AV7110 | 6 | config DVB_AV7110 |
diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c index 640421ceb24a..46d216329611 100644 --- a/drivers/media/radio/radio-si470x.c +++ b/drivers/media/radio/radio-si470x.c | |||
| @@ -1200,7 +1200,7 @@ static int si470x_fops_release(struct file *file) | |||
| 1200 | video_unregister_device(radio->videodev); | 1200 | video_unregister_device(radio->videodev); |
| 1201 | kfree(radio->buffer); | 1201 | kfree(radio->buffer); |
| 1202 | kfree(radio); | 1202 | kfree(radio); |
| 1203 | goto done; | 1203 | goto unlock; |
| 1204 | } | 1204 | } |
| 1205 | 1205 | ||
| 1206 | /* stop rds reception */ | 1206 | /* stop rds reception */ |
| @@ -1213,9 +1213,8 @@ static int si470x_fops_release(struct file *file) | |||
| 1213 | retval = si470x_stop(radio); | 1213 | retval = si470x_stop(radio); |
| 1214 | usb_autopm_put_interface(radio->intf); | 1214 | usb_autopm_put_interface(radio->intf); |
| 1215 | } | 1215 | } |
| 1216 | 1216 | unlock: | |
| 1217 | mutex_unlock(&radio->disconnect_lock); | 1217 | mutex_unlock(&radio->disconnect_lock); |
| 1218 | |||
| 1219 | done: | 1218 | done: |
| 1220 | return retval; | 1219 | return retval; |
| 1221 | } | 1220 | } |
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 061e147f6f26..84b6fc15519d 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig | |||
| @@ -312,6 +312,14 @@ config VIDEO_OV7670 | |||
| 312 | OV7670 VGA camera. It currently only works with the M88ALP01 | 312 | OV7670 VGA camera. It currently only works with the M88ALP01 |
| 313 | controller. | 313 | controller. |
| 314 | 314 | ||
| 315 | config VIDEO_MT9V011 | ||
| 316 | tristate "Micron mt9v011 sensor support" | ||
| 317 | depends on I2C && VIDEO_V4L2 | ||
| 318 | ---help--- | ||
| 319 | This is a Video4Linux2 sensor-level driver for the Micron | ||
| 320 | mt0v011 1.3 Mpixel camera. It currently only works with the | ||
| 321 | em28xx driver. | ||
| 322 | |||
| 315 | config VIDEO_TCM825X | 323 | config VIDEO_TCM825X |
| 316 | tristate "TCM825x camera sensor support" | 324 | tristate "TCM825x camera sensor support" |
| 317 | depends on I2C && VIDEO_V4L2 | 325 | depends on I2C && VIDEO_V4L2 |
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 7fb3add1b387..9f2e3214a482 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile | |||
| @@ -69,6 +69,7 @@ obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o | |||
| 69 | obj-$(CONFIG_VIDEO_OV7670) += ov7670.o | 69 | obj-$(CONFIG_VIDEO_OV7670) += ov7670.o |
| 70 | obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o | 70 | obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o |
| 71 | obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o | 71 | obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o |
| 72 | obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o | ||
| 72 | 73 | ||
| 73 | obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o | 74 | obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o |
| 74 | obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o | 75 | obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o |
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c index c92a25036f0e..36f2d76006fd 100644 --- a/drivers/media/video/cx18/cx18-cards.c +++ b/drivers/media/video/cx18/cx18-cards.c | |||
| @@ -198,11 +198,14 @@ static const struct cx18_card_pci_info cx18_pci_mpc718[] = { | |||
| 198 | 198 | ||
| 199 | static const struct cx18_card cx18_card_mpc718 = { | 199 | static const struct cx18_card cx18_card_mpc718 = { |
| 200 | .type = CX18_CARD_YUAN_MPC718, | 200 | .type = CX18_CARD_YUAN_MPC718, |
| 201 | .name = "Yuan MPC718", | 201 | .name = "Yuan MPC718 MiniPCI DVB-T/Analog", |
| 202 | .comment = "Analog video capture works; some audio line in may not.\n", | 202 | .comment = "Experimenters needed for device to work well.\n" |
| 203 | "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", | ||
| 203 | .v4l2_capabilities = CX18_CAP_ENCODER, | 204 | .v4l2_capabilities = CX18_CAP_ENCODER, |
| 204 | .hw_audio_ctrl = CX18_HW_418_AV, | 205 | .hw_audio_ctrl = CX18_HW_418_AV, |
| 205 | .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_RESET_CTRL, | 206 | .hw_muxer = CX18_HW_GPIO_MUX, |
| 207 | .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | | ||
| 208 | CX18_HW_GPIO_MUX | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL, | ||
| 206 | .video_inputs = { | 209 | .video_inputs = { |
| 207 | { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, | 210 | { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, |
| 208 | { CX18_CARD_INPUT_SVIDEO1, 1, | 211 | { CX18_CARD_INPUT_SVIDEO1, 1, |
| @@ -211,27 +214,34 @@ static const struct cx18_card cx18_card_mpc718 = { | |||
| 211 | { CX18_CARD_INPUT_SVIDEO2, 2, | 214 | { CX18_CARD_INPUT_SVIDEO2, 2, |
| 212 | CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 }, | 215 | CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 }, |
| 213 | { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 }, | 216 | { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 }, |
| 214 | { CX18_CARD_INPUT_COMPOSITE3, 2, CX18_AV_COMPOSITE3 }, | ||
| 215 | }, | 217 | }, |
| 216 | .audio_inputs = { | 218 | .audio_inputs = { |
| 217 | { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, | 219 | { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, |
| 218 | { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 0 }, | 220 | { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, |
| 219 | { CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL1, 0 }, | 221 | { CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL2, 1 }, |
| 220 | }, | 222 | }, |
| 221 | .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL1, 0 }, | ||
| 222 | .tuners = { | 223 | .tuners = { |
| 223 | /* XC3028 tuner */ | 224 | /* XC3028 tuner */ |
| 224 | { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, | 225 | { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, |
| 225 | }, | 226 | }, |
| 227 | /* FIXME - the FM radio is just a guess and driver doesn't use SIF */ | ||
| 228 | .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 }, | ||
| 226 | .ddr = { | 229 | .ddr = { |
| 227 | /* Probably Samsung K4D263238G-VC33 memory */ | 230 | /* Hynix HY5DU283222B DDR RAM */ |
| 228 | .chip_config = 0x003, | 231 | .chip_config = 0x303, |
| 229 | .refresh = 0x30c, | 232 | .refresh = 0x3bd, |
| 230 | .timing1 = 0x23230b73, | 233 | .timing1 = 0x36320966, |
| 231 | .timing2 = 0x08, | 234 | .timing2 = 0x1f, |
| 232 | .tune_lane = 0, | 235 | .tune_lane = 0, |
| 233 | .initial_emrs = 2, | 236 | .initial_emrs = 2, |
| 234 | }, | 237 | }, |
| 238 | .gpio_init.initial_value = 0x1, | ||
| 239 | .gpio_init.direction = 0x3, | ||
| 240 | /* FIXME - these GPIO's are just guesses */ | ||
| 241 | .gpio_audio_input = { .mask = 0x3, | ||
| 242 | .tuner = 0x1, | ||
| 243 | .linein = 0x3, | ||
| 244 | .radio = 0x1 }, | ||
| 235 | .xceive_pin = 0, | 245 | .xceive_pin = 0, |
| 236 | .pci_list = cx18_pci_mpc718, | 246 | .pci_list = cx18_pci_mpc718, |
| 237 | .i2c = &cx18_i2c_std, | 247 | .i2c = &cx18_i2c_std, |
diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c index 6ea3fe623ef4..51a0c33b25b7 100644 --- a/drivers/media/video/cx18/cx18-dvb.c +++ b/drivers/media/video/cx18/cx18-dvb.c | |||
| @@ -30,6 +30,10 @@ | |||
| 30 | #include "s5h1409.h" | 30 | #include "s5h1409.h" |
| 31 | #include "mxl5005s.h" | 31 | #include "mxl5005s.h" |
| 32 | #include "zl10353.h" | 32 | #include "zl10353.h" |
| 33 | |||
| 34 | #include <linux/firmware.h> | ||
| 35 | #include "mt352.h" | ||
| 36 | #include "mt352_priv.h" | ||
| 33 | #include "tuner-xc2028.h" | 37 | #include "tuner-xc2028.h" |
| 34 | 38 | ||
| 35 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | 39 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
| @@ -38,6 +42,11 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | |||
| 38 | #define CX18_CLOCK_ENABLE2 0xc71024 | 42 | #define CX18_CLOCK_ENABLE2 0xc71024 |
| 39 | #define CX18_DMUX_CLK_MASK 0x0080 | 43 | #define CX18_DMUX_CLK_MASK 0x0080 |
| 40 | 44 | ||
| 45 | /* | ||
| 46 | * CX18_CARD_HVR_1600_ESMT | ||
| 47 | * CX18_CARD_HVR_1600_SAMSUNG | ||
| 48 | */ | ||
| 49 | |||
| 41 | static struct mxl5005s_config hauppauge_hvr1600_tuner = { | 50 | static struct mxl5005s_config hauppauge_hvr1600_tuner = { |
| 42 | .i2c_address = 0xC6 >> 1, | 51 | .i2c_address = 0xC6 >> 1, |
| 43 | .if_freq = IF_FREQ_5380000HZ, | 52 | .if_freq = IF_FREQ_5380000HZ, |
| @@ -65,6 +74,9 @@ static struct s5h1409_config hauppauge_hvr1600_config = { | |||
| 65 | .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK | 74 | .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK |
| 66 | }; | 75 | }; |
| 67 | 76 | ||
| 77 | /* | ||
| 78 | * CX18_CARD_LEADTEK_DVR3100H | ||
| 79 | */ | ||
| 68 | /* Information/confirmation of proper config values provided by Terry Wu */ | 80 | /* Information/confirmation of proper config values provided by Terry Wu */ |
| 69 | static struct zl10353_config leadtek_dvr3100h_demod = { | 81 | static struct zl10353_config leadtek_dvr3100h_demod = { |
| 70 | .demod_address = 0x1e >> 1, /* Datasheet suggested straps */ | 82 | .demod_address = 0x1e >> 1, /* Datasheet suggested straps */ |
| @@ -74,6 +86,121 @@ static struct zl10353_config leadtek_dvr3100h_demod = { | |||
| 74 | .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */ | 86 | .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */ |
| 75 | }; | 87 | }; |
| 76 | 88 | ||
| 89 | /* | ||
| 90 | * CX18_CARD_YUAN_MPC718 | ||
| 91 | */ | ||
| 92 | /* | ||
| 93 | * Due to | ||
| 94 | * | ||
| 95 | * 1. an absence of information on how to prgram the MT352 | ||
| 96 | * 2. the Linux mt352 module pushing MT352 initialzation off onto us here | ||
| 97 | * | ||
| 98 | * We have to use an init sequence that *you* must extract from the Windows | ||
| 99 | * driver (yuanrap.sys) and which we load as a firmware. | ||
| 100 | * | ||
| 101 | * If someone can provide me with a Zarlink MT352 (Intel CE6352?) Design Manual | ||
| 102 | * with chip programming details, then I can remove this annoyance. | ||
| 103 | */ | ||
| 104 | static int yuan_mpc718_mt352_reqfw(struct cx18_stream *stream, | ||
| 105 | const struct firmware **fw) | ||
| 106 | { | ||
| 107 | struct cx18 *cx = stream->cx; | ||
| 108 | const char *fn = "dvb-cx18-mpc718-mt352.fw"; | ||
| 109 | int ret; | ||
| 110 | |||
| 111 | ret = request_firmware(fw, fn, &cx->pci_dev->dev); | ||
| 112 | if (ret) | ||
| 113 | CX18_ERR("Unable to open firmware file %s\n", fn); | ||
| 114 | else { | ||
| 115 | size_t sz = (*fw)->size; | ||
| 116 | if (sz < 2 || sz > 64 || (sz % 2) != 0) { | ||
| 117 | CX18_ERR("Firmware %s has a bad size: %lu bytes\n", | ||
| 118 | fn, (unsigned long) sz); | ||
| 119 | ret = -EILSEQ; | ||
| 120 | release_firmware(*fw); | ||
| 121 | *fw = NULL; | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | if (ret) { | ||
| 126 | CX18_ERR("The MPC718 board variant with the MT352 DVB-T" | ||
| 127 | "demodualtor will not work without it\n"); | ||
| 128 | CX18_ERR("Run 'linux/Documentation/dvb/get_dvb_firmware " | ||
| 129 | "mpc718' if you need the firmware\n"); | ||
| 130 | } | ||
| 131 | return ret; | ||
| 132 | } | ||
| 133 | |||
| 134 | static int yuan_mpc718_mt352_init(struct dvb_frontend *fe) | ||
| 135 | { | ||
| 136 | struct cx18_dvb *dvb = container_of(fe->dvb, | ||
| 137 | struct cx18_dvb, dvb_adapter); | ||
| 138 | struct cx18_stream *stream = container_of(dvb, struct cx18_stream, dvb); | ||
| 139 | const struct firmware *fw = NULL; | ||
| 140 | int ret; | ||
| 141 | int i; | ||
| 142 | u8 buf[3]; | ||
| 143 | |||
| 144 | ret = yuan_mpc718_mt352_reqfw(stream, &fw); | ||
| 145 | if (ret) | ||
| 146 | return ret; | ||
| 147 | |||
| 148 | /* Loop through all the register-value pairs in the firmware file */ | ||
| 149 | for (i = 0; i < fw->size; i += 2) { | ||
| 150 | buf[0] = fw->data[i]; | ||
| 151 | /* Intercept a few registers we want to set ourselves */ | ||
| 152 | switch (buf[0]) { | ||
| 153 | case TRL_NOMINAL_RATE_0: | ||
| 154 | /* Set our custom OFDM bandwidth in the case below */ | ||
| 155 | break; | ||
| 156 | case TRL_NOMINAL_RATE_1: | ||
| 157 | /* 6 MHz: 64/7 * 6/8 / 20.48 * 2^16 = 0x55b6.db6 */ | ||
| 158 | /* 7 MHz: 64/7 * 7/8 / 20.48 * 2^16 = 0x6400 */ | ||
| 159 | /* 8 MHz: 64/7 * 8/8 / 20.48 * 2^16 = 0x7249.249 */ | ||
| 160 | buf[1] = 0x72; | ||
| 161 | buf[2] = 0x49; | ||
| 162 | mt352_write(fe, buf, 3); | ||
| 163 | break; | ||
| 164 | case INPUT_FREQ_0: | ||
| 165 | /* Set our custom IF in the case below */ | ||
| 166 | break; | ||
| 167 | case INPUT_FREQ_1: | ||
| 168 | /* 4.56 MHz IF: (20.48 - 4.56)/20.48 * 2^14 = 0x31c0 */ | ||
| 169 | buf[1] = 0x31; | ||
| 170 | buf[2] = 0xc0; | ||
| 171 | mt352_write(fe, buf, 3); | ||
| 172 | break; | ||
| 173 | default: | ||
| 174 | /* Pass through the register-value pair from the fw */ | ||
| 175 | buf[1] = fw->data[i+1]; | ||
| 176 | mt352_write(fe, buf, 2); | ||
| 177 | break; | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | buf[0] = (u8) TUNER_GO; | ||
| 182 | buf[1] = 0x01; /* Go */ | ||
| 183 | mt352_write(fe, buf, 2); | ||
| 184 | release_firmware(fw); | ||
| 185 | return 0; | ||
| 186 | } | ||
| 187 | |||
| 188 | static struct mt352_config yuan_mpc718_mt352_demod = { | ||
| 189 | .demod_address = 0x1e >> 1, | ||
| 190 | .adc_clock = 20480, /* 20.480 MHz */ | ||
| 191 | .if2 = 4560, /* 4.560 MHz */ | ||
| 192 | .no_tuner = 1, /* XC3028 is not behind the gate */ | ||
| 193 | .demod_init = yuan_mpc718_mt352_init, | ||
| 194 | }; | ||
| 195 | |||
| 196 | static struct zl10353_config yuan_mpc718_zl10353_demod = { | ||
| 197 | .demod_address = 0x1e >> 1, /* Datasheet suggested straps */ | ||
| 198 | .if2 = 45600, /* 4.560 MHz IF from the XC3028 */ | ||
| 199 | .parallel_ts = 1, /* Not a serial TS */ | ||
| 200 | .no_tuner = 1, /* XC3028 is not behind the gate */ | ||
| 201 | .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */ | ||
| 202 | }; | ||
| 203 | |||
| 77 | static int dvb_register(struct cx18_stream *stream); | 204 | static int dvb_register(struct cx18_stream *stream); |
| 78 | 205 | ||
| 79 | /* Kernel DVB framework calls this when the feed needs to start. | 206 | /* Kernel DVB framework calls this when the feed needs to start. |
| @@ -113,6 +240,7 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed) | |||
| 113 | break; | 240 | break; |
| 114 | 241 | ||
| 115 | case CX18_CARD_LEADTEK_DVR3100H: | 242 | case CX18_CARD_LEADTEK_DVR3100H: |
| 243 | case CX18_CARD_YUAN_MPC718: | ||
| 116 | default: | 244 | default: |
| 117 | /* Assumption - Parallel transport - Signalling | 245 | /* Assumption - Parallel transport - Signalling |
| 118 | * undefined or default. | 246 | * undefined or default. |
| @@ -326,6 +454,38 @@ static int dvb_register(struct cx18_stream *stream) | |||
| 326 | fe->ops.tuner_ops.set_config(fe, &ctrl); | 454 | fe->ops.tuner_ops.set_config(fe, &ctrl); |
| 327 | } | 455 | } |
| 328 | break; | 456 | break; |
| 457 | case CX18_CARD_YUAN_MPC718: | ||
| 458 | /* | ||
| 459 | * TODO | ||
| 460 | * Apparently, these cards also could instead have a | ||
| 461 | * DiBcom demod supported by one of the db7000 drivers | ||
| 462 | */ | ||
| 463 | dvb->fe = dvb_attach(mt352_attach, | ||
| 464 | &yuan_mpc718_mt352_demod, | ||
| 465 | &cx->i2c_adap[1]); | ||
| 466 | if (dvb->fe == NULL) | ||
| 467 | dvb->fe = dvb_attach(zl10353_attach, | ||
| 468 | &yuan_mpc718_zl10353_demod, | ||
| 469 | &cx->i2c_adap[1]); | ||
| 470 | if (dvb->fe != NULL) { | ||
| 471 | struct dvb_frontend *fe; | ||
| 472 | struct xc2028_config cfg = { | ||
| 473 | .i2c_adap = &cx->i2c_adap[1], | ||
| 474 | .i2c_addr = 0xc2 >> 1, | ||
| 475 | .ctrl = NULL, | ||
| 476 | }; | ||
| 477 | static struct xc2028_ctrl ctrl = { | ||
| 478 | .fname = XC2028_DEFAULT_FIRMWARE, | ||
| 479 | .max_len = 64, | ||
| 480 | .demod = XC3028_FE_ZARLINK456, | ||
| 481 | .type = XC2028_AUTO, | ||
| 482 | }; | ||
| 483 | |||
| 484 | fe = dvb_attach(xc2028_attach, dvb->fe, &cfg); | ||
| 485 | if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) | ||
| 486 | fe->ops.tuner_ops.set_config(fe, &ctrl); | ||
| 487 | } | ||
| 488 | break; | ||
| 329 | default: | 489 | default: |
| 330 | /* No Digital Tv Support */ | 490 | /* No Digital Tv Support */ |
| 331 | break; | 491 | break; |
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 48a975134ac5..86ac529e62be 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c | |||
| @@ -463,6 +463,30 @@ static struct xc5000_config mygica_x8506_xc5000_config = { | |||
| 463 | .if_khz = 5380, | 463 | .if_khz = 5380, |
| 464 | }; | 464 | }; |
| 465 | 465 | ||
| 466 | static int cx23885_dvb_set_frontend(struct dvb_frontend *fe, | ||
| 467 | struct dvb_frontend_parameters *param) | ||
| 468 | { | ||
| 469 | struct cx23885_tsport *port = fe->dvb->priv; | ||
| 470 | struct cx23885_dev *dev = port->dev; | ||
| 471 | |||
| 472 | switch (dev->board) { | ||
| 473 | case CX23885_BOARD_HAUPPAUGE_HVR1275: | ||
| 474 | switch (param->u.vsb.modulation) { | ||
| 475 | case VSB_8: | ||
| 476 | cx23885_gpio_clear(dev, GPIO_5); | ||
| 477 | break; | ||
| 478 | case QAM_64: | ||
| 479 | case QAM_256: | ||
| 480 | default: | ||
| 481 | cx23885_gpio_set(dev, GPIO_5); | ||
| 482 | break; | ||
| 483 | } | ||
| 484 | break; | ||
| 485 | } | ||
| 486 | return (port->set_frontend_save) ? | ||
| 487 | port->set_frontend_save(fe, param) : -ENODEV; | ||
| 488 | } | ||
| 489 | |||
| 466 | static int dvb_register(struct cx23885_tsport *port) | 490 | static int dvb_register(struct cx23885_tsport *port) |
| 467 | { | 491 | { |
| 468 | struct cx23885_dev *dev = port->dev; | 492 | struct cx23885_dev *dev = port->dev; |
| @@ -502,6 +526,12 @@ static int dvb_register(struct cx23885_tsport *port) | |||
| 502 | 0x60, &dev->i2c_bus[1].i2c_adap, | 526 | 0x60, &dev->i2c_bus[1].i2c_adap, |
| 503 | &hauppauge_hvr127x_config); | 527 | &hauppauge_hvr127x_config); |
| 504 | } | 528 | } |
| 529 | |||
| 530 | /* FIXME: temporary hack */ | ||
| 531 | /* define bridge override to set_frontend */ | ||
| 532 | port->set_frontend_save = fe0->dvb.frontend->ops.set_frontend; | ||
| 533 | fe0->dvb.frontend->ops.set_frontend = cx23885_dvb_set_frontend; | ||
| 534 | |||
| 505 | break; | 535 | break; |
| 506 | case CX23885_BOARD_HAUPPAUGE_HVR1255: | 536 | case CX23885_BOARD_HAUPPAUGE_HVR1255: |
| 507 | i2c_bus = &dev->i2c_bus[0]; | 537 | i2c_bus = &dev->i2c_bus[0]; |
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 1a2ac518a3f1..214a55e943b7 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h | |||
| @@ -288,6 +288,10 @@ struct cx23885_tsport { | |||
| 288 | /* Allow a single tsport to have multiple frontends */ | 288 | /* Allow a single tsport to have multiple frontends */ |
| 289 | u32 num_frontends; | 289 | u32 num_frontends; |
| 290 | void *port_priv; | 290 | void *port_priv; |
| 291 | |||
| 292 | /* FIXME: temporary hack */ | ||
| 293 | int (*set_frontend_save) (struct dvb_frontend *, | ||
| 294 | struct dvb_frontend_parameters *); | ||
| 291 | }; | 295 | }; |
| 292 | 296 | ||
| 293 | struct cx23885_dev { | 297 | struct cx23885_dev { |
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig index 16a5af30e9d1..6524b493e033 100644 --- a/drivers/media/video/em28xx/Kconfig +++ b/drivers/media/video/em28xx/Kconfig | |||
| @@ -8,6 +8,8 @@ config VIDEO_EM28XX | |||
| 8 | select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO | 8 | select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO |
| 9 | select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO | 9 | select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO |
| 10 | select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO | 10 | select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO |
| 11 | select VIDEO_MT9V011 if VIDEO_HELPER_CHIPS_AUTO | ||
| 12 | |||
| 11 | ---help--- | 13 | ---help--- |
| 12 | This is a video4linux driver for Empia 28xx based TV cards. | 14 | This is a video4linux driver for Empia 28xx based TV cards. |
| 13 | 15 | ||
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index c43fdb9bc888..ebd24a25fb85 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c | |||
| @@ -58,6 +58,8 @@ static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; | |||
| 58 | module_param_array(card, int, NULL, 0444); | 58 | module_param_array(card, int, NULL, 0444); |
| 59 | MODULE_PARM_DESC(card, "card type"); | 59 | MODULE_PARM_DESC(card, "card type"); |
| 60 | 60 | ||
| 61 | #define MT9V011_VERSION 0x8243 | ||
| 62 | |||
| 61 | /* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */ | 63 | /* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */ |
| 62 | static unsigned long em28xx_devused; | 64 | static unsigned long em28xx_devused; |
| 63 | 65 | ||
| @@ -191,6 +193,13 @@ static struct em28xx_reg_seq terratec_av350_unmute_gpio[] = { | |||
| 191 | {EM28XX_R08_GPIO, 0xff, 0xff, 10}, | 193 | {EM28XX_R08_GPIO, 0xff, 0xff, 10}, |
| 192 | { -1, -1, -1, -1}, | 194 | { -1, -1, -1, -1}, |
| 193 | }; | 195 | }; |
| 196 | |||
| 197 | static struct em28xx_reg_seq silvercrest_reg_seq[] = { | ||
| 198 | {EM28XX_R08_GPIO, 0xff, 0xff, 10}, | ||
| 199 | {EM28XX_R08_GPIO, 0x01, 0xf7, 10}, | ||
| 200 | { -1, -1, -1, -1}, | ||
| 201 | }; | ||
| 202 | |||
| 194 | /* | 203 | /* |
| 195 | * Board definitions | 204 | * Board definitions |
| 196 | */ | 205 | */ |
| @@ -438,6 +447,18 @@ struct em28xx_board em28xx_boards[] = { | |||
| 438 | .amux = EM28XX_AMUX_VIDEO, | 447 | .amux = EM28XX_AMUX_VIDEO, |
| 439 | } }, | 448 | } }, |
| 440 | }, | 449 | }, |
| 450 | [EM2820_BOARD_SILVERCREST_WEBCAM] = { | ||
| 451 | .name = "Silvercrest Webcam 1.3mpix", | ||
| 452 | .tuner_type = TUNER_ABSENT, | ||
| 453 | .is_27xx = 1, | ||
| 454 | .decoder = EM28XX_MT9V011, | ||
| 455 | .input = { { | ||
| 456 | .type = EM28XX_VMUX_COMPOSITE1, | ||
| 457 | .vmux = 0, | ||
| 458 | .amux = EM28XX_AMUX_VIDEO, | ||
| 459 | .gpio = silvercrest_reg_seq, | ||
| 460 | } }, | ||
| 461 | }, | ||
| 441 | [EM2821_BOARD_SUPERCOMP_USB_2] = { | 462 | [EM2821_BOARD_SUPERCOMP_USB_2] = { |
| 442 | .name = "Supercomp USB 2.0 TV", | 463 | .name = "Supercomp USB 2.0 TV", |
| 443 | .valid = EM28XX_BOARD_NOT_VALIDATED, | 464 | .valid = EM28XX_BOARD_NOT_VALIDATED, |
| @@ -826,7 +847,7 @@ struct em28xx_board em28xx_boards[] = { | |||
| 826 | .tuner_gpio = default_tuner_gpio, | 847 | .tuner_gpio = default_tuner_gpio, |
| 827 | .decoder = EM28XX_TVP5150, | 848 | .decoder = EM28XX_TVP5150, |
| 828 | .has_dvb = 1, | 849 | .has_dvb = 1, |
| 829 | .dvb_gpio = default_analog, | 850 | .dvb_gpio = default_digital, |
| 830 | .input = { { | 851 | .input = { { |
| 831 | .type = EM28XX_VMUX_TELEVISION, | 852 | .type = EM28XX_VMUX_TELEVISION, |
| 832 | .vmux = TVP5150_COMPOSITE0, | 853 | .vmux = TVP5150_COMPOSITE0, |
| @@ -1639,6 +1660,11 @@ static unsigned short tvp5150_addrs[] = { | |||
| 1639 | I2C_CLIENT_END | 1660 | I2C_CLIENT_END |
| 1640 | }; | 1661 | }; |
| 1641 | 1662 | ||
| 1663 | static unsigned short mt9v011_addrs[] = { | ||
| 1664 | 0xba >> 1, | ||
| 1665 | I2C_CLIENT_END | ||
| 1666 | }; | ||
| 1667 | |||
| 1642 | static unsigned short msp3400_addrs[] = { | 1668 | static unsigned short msp3400_addrs[] = { |
| 1643 | 0x80 >> 1, | 1669 | 0x80 >> 1, |
| 1644 | 0x88 >> 1, | 1670 | 0x88 >> 1, |
| @@ -1678,6 +1704,46 @@ static inline void em28xx_set_model(struct em28xx *dev) | |||
| 1678 | EM28XX_I2C_FREQ_100_KHZ; | 1704 | EM28XX_I2C_FREQ_100_KHZ; |
| 1679 | } | 1705 | } |
| 1680 | 1706 | ||
| 1707 | /* HINT method: webcam I2C chips | ||
| 1708 | * | ||
| 1709 | * This method work for webcams with Micron sensors | ||
| 1710 | */ | ||
| 1711 | static int em28xx_hint_sensor(struct em28xx *dev) | ||
| 1712 | { | ||
| 1713 | int rc; | ||
| 1714 | char *sensor_name; | ||
| 1715 | unsigned char cmd; | ||
| 1716 | __be16 version_be; | ||
| 1717 | u16 version; | ||
| 1718 | |||
| 1719 | if (dev->model != EM2820_BOARD_UNKNOWN) | ||
| 1720 | return 0; | ||
| 1721 | |||
| 1722 | dev->i2c_client.addr = 0xba >> 1; | ||
| 1723 | cmd = 0; | ||
| 1724 | i2c_master_send(&dev->i2c_client, &cmd, 1); | ||
| 1725 | rc = i2c_master_recv(&dev->i2c_client, (char *)&version_be, 2); | ||
| 1726 | if (rc != 2) | ||
| 1727 | return -EINVAL; | ||
| 1728 | |||
| 1729 | version = be16_to_cpu(version_be); | ||
| 1730 | |||
| 1731 | switch (version) { | ||
| 1732 | case MT9V011_VERSION: | ||
| 1733 | dev->model = EM2820_BOARD_SILVERCREST_WEBCAM; | ||
| 1734 | sensor_name = "mt9v011"; | ||
| 1735 | break; | ||
| 1736 | default: | ||
| 1737 | printk("Unknown Sensor 0x%04x\n", be16_to_cpu(version)); | ||
| 1738 | return -EINVAL; | ||
| 1739 | } | ||
| 1740 | |||
| 1741 | em28xx_errdev("Sensor is %s, assuming that webcam is %s\n", | ||
| 1742 | sensor_name, em28xx_boards[dev->model].name); | ||
| 1743 | |||
| 1744 | return 0; | ||
| 1745 | } | ||
| 1746 | |||
| 1681 | /* Since em28xx_pre_card_setup() requires a proper dev->model, | 1747 | /* Since em28xx_pre_card_setup() requires a proper dev->model, |
| 1682 | * this won't work for boards with generic PCI IDs | 1748 | * this won't work for boards with generic PCI IDs |
| 1683 | */ | 1749 | */ |
| @@ -1706,7 +1772,10 @@ void em28xx_pre_card_setup(struct em28xx *dev) | |||
| 1706 | em28xx_info("chip ID is em2750\n"); | 1772 | em28xx_info("chip ID is em2750\n"); |
| 1707 | break; | 1773 | break; |
| 1708 | case CHIP_ID_EM2820: | 1774 | case CHIP_ID_EM2820: |
| 1709 | em28xx_info("chip ID is em2820\n"); | 1775 | if (dev->board.is_27xx) |
| 1776 | em28xx_info("chip is em2710\n"); | ||
| 1777 | else | ||
| 1778 | em28xx_info("chip ID is em2820\n"); | ||
| 1710 | break; | 1779 | break; |
| 1711 | case CHIP_ID_EM2840: | 1780 | case CHIP_ID_EM2840: |
| 1712 | em28xx_info("chip ID is em2840\n"); | 1781 | em28xx_info("chip ID is em2840\n"); |
| @@ -2158,6 +2227,10 @@ void em28xx_card_setup(struct em28xx *dev) | |||
| 2158 | before probing the i2c bus. */ | 2227 | before probing the i2c bus. */ |
| 2159 | em28xx_set_mode(dev, EM28XX_ANALOG_MODE); | 2228 | em28xx_set_mode(dev, EM28XX_ANALOG_MODE); |
| 2160 | break; | 2229 | break; |
| 2230 | case EM2820_BOARD_SILVERCREST_WEBCAM: | ||
| 2231 | /* FIXME: need to document the registers bellow */ | ||
| 2232 | em28xx_write_reg(dev, 0x0d, 0x42); | ||
| 2233 | em28xx_write_reg(dev, 0x13, 0x08); | ||
| 2161 | } | 2234 | } |
| 2162 | 2235 | ||
| 2163 | if (dev->board.has_snapshot_button) | 2236 | if (dev->board.has_snapshot_button) |
| @@ -2189,6 +2262,10 @@ void em28xx_card_setup(struct em28xx *dev) | |||
| 2189 | v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap, | 2262 | v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap, |
| 2190 | "tvp5150", "tvp5150", tvp5150_addrs); | 2263 | "tvp5150", "tvp5150", tvp5150_addrs); |
| 2191 | 2264 | ||
| 2265 | if (dev->board.decoder == EM28XX_MT9V011) | ||
| 2266 | v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap, | ||
| 2267 | "mt9v011", "mt9v011", mt9v011_addrs); | ||
| 2268 | |||
| 2192 | if (dev->board.adecoder == EM28XX_TVAUDIO) | 2269 | if (dev->board.adecoder == EM28XX_TVAUDIO) |
| 2193 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, | 2270 | v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, |
| 2194 | "tvaudio", "tvaudio", dev->board.tvaudio_addr); | 2271 | "tvaudio", "tvaudio", dev->board.tvaudio_addr); |
| @@ -2333,6 +2410,8 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, | |||
| 2333 | return errCode; | 2410 | return errCode; |
| 2334 | } | 2411 | } |
| 2335 | 2412 | ||
| 2413 | em28xx_hint_sensor(dev); | ||
| 2414 | |||
| 2336 | /* Do board specific init and eeprom reading */ | 2415 | /* Do board specific init and eeprom reading */ |
| 2337 | em28xx_card_setup(dev); | 2416 | em28xx_card_setup(dev); |
| 2338 | 2417 | ||
| @@ -2573,6 +2652,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, | |||
| 2573 | retval = em28xx_init_dev(&dev, udev, interface, nr); | 2652 | retval = em28xx_init_dev(&dev, udev, interface, nr); |
| 2574 | if (retval) { | 2653 | if (retval) { |
| 2575 | em28xx_devused &= ~(1<<dev->devno); | 2654 | em28xx_devused &= ~(1<<dev->devno); |
| 2655 | mutex_unlock(&dev->lock); | ||
| 2576 | kfree(dev); | 2656 | kfree(dev); |
| 2577 | goto err; | 2657 | goto err; |
| 2578 | } | 2658 | } |
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index c8d7ce8fbd36..079ab4d563a6 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c | |||
| @@ -648,17 +648,28 @@ int em28xx_capture_start(struct em28xx *dev, int start) | |||
| 648 | int em28xx_set_outfmt(struct em28xx *dev) | 648 | int em28xx_set_outfmt(struct em28xx *dev) |
| 649 | { | 649 | { |
| 650 | int ret; | 650 | int ret; |
| 651 | int vinmode, vinctl, outfmt; | ||
| 652 | |||
| 653 | outfmt = dev->format->reg; | ||
| 654 | |||
| 655 | if (dev->board.is_27xx) { | ||
| 656 | vinmode = 0x0d; | ||
| 657 | vinctl = 0x00; | ||
| 658 | } else { | ||
| 659 | vinmode = 0x10; | ||
| 660 | vinctl = 0x11; | ||
| 661 | } | ||
| 651 | 662 | ||
| 652 | ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT, | 663 | ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT, |
| 653 | dev->format->reg | 0x20, 0x3f); | 664 | outfmt | 0x20, 0xff); |
| 654 | if (ret < 0) | 665 | if (ret < 0) |
| 655 | return ret; | 666 | return ret; |
| 656 | 667 | ||
| 657 | ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, 0x10); | 668 | ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, vinmode); |
| 658 | if (ret < 0) | 669 | if (ret < 0) |
| 659 | return ret; | 670 | return ret; |
| 660 | 671 | ||
| 661 | return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x11); | 672 | return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctl); |
| 662 | } | 673 | } |
| 663 | 674 | ||
| 664 | static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, | 675 | static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, |
| @@ -695,13 +706,19 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v) | |||
| 695 | { | 706 | { |
| 696 | u8 mode; | 707 | u8 mode; |
| 697 | /* the em2800 scaler only supports scaling down to 50% */ | 708 | /* the em2800 scaler only supports scaling down to 50% */ |
| 698 | if (dev->board.is_em2800) | 709 | |
| 710 | if (dev->board.is_27xx) { | ||
| 711 | /* FIXME: Don't use the scaler yet */ | ||
| 712 | mode = 0; | ||
| 713 | } else if (dev->board.is_em2800) { | ||
| 699 | mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00); | 714 | mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00); |
| 700 | else { | 715 | } else { |
| 701 | u8 buf[2]; | 716 | u8 buf[2]; |
| 717 | |||
| 702 | buf[0] = h; | 718 | buf[0] = h; |
| 703 | buf[1] = h >> 8; | 719 | buf[1] = h >> 8; |
| 704 | em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2); | 720 | em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2); |
| 721 | |||
| 705 | buf[0] = v; | 722 | buf[0] = v; |
| 706 | buf[1] = v >> 8; | 723 | buf[1] = v >> 8; |
| 707 | em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2); | 724 | em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2); |
| @@ -720,8 +737,11 @@ int em28xx_resolution_set(struct em28xx *dev) | |||
| 720 | height = norm_maxh(dev) >> 1; | 737 | height = norm_maxh(dev) >> 1; |
| 721 | 738 | ||
| 722 | em28xx_set_outfmt(dev); | 739 | em28xx_set_outfmt(dev); |
| 740 | |||
| 741 | |||
| 723 | em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2); | 742 | em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2); |
| 724 | em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2); | 743 | em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2); |
| 744 | |||
| 725 | return em28xx_scaler_set(dev, dev->hscale, dev->vscale); | 745 | return em28xx_scaler_set(dev, dev->hscale, dev->vscale); |
| 726 | } | 746 | } |
| 727 | 747 | ||
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c index e7b47c8da8f3..3da97c32b8fa 100644 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ b/drivers/media/video/em28xx/em28xx-dvb.c | |||
| @@ -243,6 +243,14 @@ static struct s5h1409_config em28xx_s5h1409_with_xc3028 = { | |||
| 243 | .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK | 243 | .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK |
| 244 | }; | 244 | }; |
| 245 | 245 | ||
| 246 | static struct zl10353_config em28xx_terratec_xs_zl10353_xc3028 = { | ||
| 247 | .demod_address = (0x1e >> 1), | ||
| 248 | .no_tuner = 1, | ||
| 249 | .disable_i2c_gate_ctrl = 1, | ||
| 250 | .parallel_ts = 1, | ||
| 251 | .if2 = 45600, | ||
| 252 | }; | ||
| 253 | |||
| 246 | #ifdef EM28XX_DRX397XD_SUPPORT | 254 | #ifdef EM28XX_DRX397XD_SUPPORT |
| 247 | /* [TODO] djh - not sure yet what the device config needs to contain */ | 255 | /* [TODO] djh - not sure yet what the device config needs to contain */ |
| 248 | static struct drx397xD_config em28xx_drx397xD_with_xc3028 = { | 256 | static struct drx397xD_config em28xx_drx397xD_with_xc3028 = { |
| @@ -433,7 +441,6 @@ static int dvb_init(struct em28xx *dev) | |||
| 433 | } | 441 | } |
| 434 | break; | 442 | break; |
| 435 | case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: | 443 | case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: |
| 436 | case EM2880_BOARD_TERRATEC_HYBRID_XS: | ||
| 437 | case EM2880_BOARD_KWORLD_DVB_310U: | 444 | case EM2880_BOARD_KWORLD_DVB_310U: |
| 438 | case EM2880_BOARD_EMPIRE_DUAL_TV: | 445 | case EM2880_BOARD_EMPIRE_DUAL_TV: |
| 439 | dvb->frontend = dvb_attach(zl10353_attach, | 446 | dvb->frontend = dvb_attach(zl10353_attach, |
| @@ -444,6 +451,25 @@ static int dvb_init(struct em28xx *dev) | |||
| 444 | goto out_free; | 451 | goto out_free; |
| 445 | } | 452 | } |
| 446 | break; | 453 | break; |
| 454 | case EM2880_BOARD_TERRATEC_HYBRID_XS: | ||
| 455 | dvb->frontend = dvb_attach(zl10353_attach, | ||
| 456 | &em28xx_terratec_xs_zl10353_xc3028, | ||
| 457 | &dev->i2c_adap); | ||
| 458 | if (dvb->frontend == NULL) { | ||
| 459 | /* This board could have either a zl10353 or a mt352. | ||
| 460 | If the chip id isn't for zl10353, try mt352 */ | ||
| 461 | |||
| 462 | /* FIXME: make support for mt352 work */ | ||
| 463 | printk(KERN_ERR "version of this board with mt352 not " | ||
| 464 | "currently supported\n"); | ||
| 465 | result = -EINVAL; | ||
| 466 | goto out_free; | ||
| 467 | } | ||
| 468 | if (attach_xc3028(0x61, dev) < 0) { | ||
| 469 | result = -EINVAL; | ||
| 470 | goto out_free; | ||
| 471 | } | ||
| 472 | break; | ||
| 447 | case EM2883_BOARD_KWORLD_HYBRID_330U: | 473 | case EM2883_BOARD_KWORLD_HYBRID_330U: |
| 448 | case EM2882_BOARD_EVGA_INDTUBE: | 474 | case EM2882_BOARD_EVGA_INDTUBE: |
| 449 | dvb->frontend = dvb_attach(s5h1409_attach, | 475 | dvb->frontend = dvb_attach(s5h1409_attach, |
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c index 2c86fcf089f5..27e33a287dfc 100644 --- a/drivers/media/video/em28xx/em28xx-i2c.c +++ b/drivers/media/video/em28xx/em28xx-i2c.c | |||
| @@ -483,7 +483,7 @@ static char *i2c_devs[128] = { | |||
| 483 | [0xa0 >> 1] = "eeprom", | 483 | [0xa0 >> 1] = "eeprom", |
| 484 | [0xb0 >> 1] = "tda9874", | 484 | [0xb0 >> 1] = "tda9874", |
| 485 | [0xb8 >> 1] = "tvp5150a", | 485 | [0xb8 >> 1] = "tvp5150a", |
| 486 | [0xba >> 1] = "tvp5150a", | 486 | [0xba >> 1] = "webcam sensor or tvp5150a", |
| 487 | [0xc0 >> 1] = "tuner (analog)", | 487 | [0xc0 >> 1] = "tuner (analog)", |
| 488 | [0xc2 >> 1] = "tuner (analog)", | 488 | [0xc2 >> 1] = "tuner (analog)", |
| 489 | [0xc4 >> 1] = "tuner (analog)", | 489 | [0xc4 >> 1] = "tuner (analog)", |
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 8fe1beecfffa..14316c912179 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c | |||
| @@ -90,10 +90,35 @@ MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); | |||
| 90 | /* supported video standards */ | 90 | /* supported video standards */ |
| 91 | static struct em28xx_fmt format[] = { | 91 | static struct em28xx_fmt format[] = { |
| 92 | { | 92 | { |
| 93 | .name = "16bpp YUY2, 4:2:2, packed", | 93 | .name = "16 bpp YUY2, 4:2:2, packed", |
| 94 | .fourcc = V4L2_PIX_FMT_YUYV, | 94 | .fourcc = V4L2_PIX_FMT_YUYV, |
| 95 | .depth = 16, | 95 | .depth = 16, |
| 96 | .reg = EM28XX_OUTFMT_YUV422_Y0UY1V, | 96 | .reg = EM28XX_OUTFMT_YUV422_Y0UY1V, |
| 97 | }, { | ||
| 98 | .name = "16 bpp RGB 565, LE", | ||
| 99 | .fourcc = V4L2_PIX_FMT_RGB565, | ||
| 100 | .depth = 16, | ||
| 101 | .reg = EM28XX_OUTFMT_RGB_16_656, | ||
| 102 | }, { | ||
| 103 | .name = "8 bpp Bayer BGBG..GRGR", | ||
| 104 | .fourcc = V4L2_PIX_FMT_SBGGR8, | ||
| 105 | .depth = 8, | ||
| 106 | .reg = EM28XX_OUTFMT_RGB_8_BGBG, | ||
| 107 | }, { | ||
| 108 | .name = "8 bpp Bayer GRGR..BGBG", | ||
| 109 | .fourcc = V4L2_PIX_FMT_SGRBG8, | ||
| 110 | .depth = 8, | ||
| 111 | .reg = EM28XX_OUTFMT_RGB_8_GRGR, | ||
| 112 | }, { | ||
| 113 | .name = "8 bpp Bayer GBGB..RGRG", | ||
| 114 | .fourcc = V4L2_PIX_FMT_SGBRG8, | ||
| 115 | .depth = 8, | ||
| 116 | .reg = EM28XX_OUTFMT_RGB_8_GBGB, | ||
| 117 | }, { | ||
| 118 | .name = "12 bpp YUV411", | ||
| 119 | .fourcc = V4L2_PIX_FMT_YUV411P, | ||
| 120 | .depth = 12, | ||
| 121 | .reg = EM28XX_OUTFMT_YUV411, | ||
| 97 | }, | 122 | }, |
| 98 | }; | 123 | }; |
| 99 | 124 | ||
| @@ -701,7 +726,11 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, | |||
| 701 | return -EINVAL; | 726 | return -EINVAL; |
| 702 | } | 727 | } |
| 703 | 728 | ||
| 704 | if (dev->board.is_em2800) { | 729 | if (dev->board.is_27xx) { |
| 730 | /* FIXME: This is the only supported fmt */ | ||
| 731 | width = 640; | ||
| 732 | height = 480; | ||
| 733 | } else if (dev->board.is_em2800) { | ||
| 705 | /* the em2800 can only scale down to 50% */ | 734 | /* the em2800 can only scale down to 50% */ |
| 706 | height = height > (3 * maxh / 4) ? maxh : maxh / 2; | 735 | height = height > (3 * maxh / 4) ? maxh : maxh / 2; |
| 707 | width = width > (3 * maxw / 4) ? maxw : maxw / 2; | 736 | width = width > (3 * maxw / 4) ? maxw : maxw / 2; |
| @@ -733,13 +762,40 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, | |||
| 733 | return 0; | 762 | return 0; |
| 734 | } | 763 | } |
| 735 | 764 | ||
| 765 | static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc, | ||
| 766 | unsigned width, unsigned height) | ||
| 767 | { | ||
| 768 | struct em28xx_fmt *fmt; | ||
| 769 | |||
| 770 | /* FIXME: This is the only supported fmt */ | ||
| 771 | if (dev->board.is_27xx) { | ||
| 772 | width = 640; | ||
| 773 | height = 480; | ||
| 774 | } | ||
| 775 | |||
| 776 | fmt = format_by_fourcc(fourcc); | ||
| 777 | if (!fmt) | ||
| 778 | return -EINVAL; | ||
| 779 | |||
| 780 | dev->format = fmt; | ||
| 781 | dev->width = width; | ||
| 782 | dev->height = height; | ||
| 783 | |||
| 784 | /* set new image size */ | ||
| 785 | get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); | ||
| 786 | |||
| 787 | em28xx_set_alternate(dev); | ||
| 788 | em28xx_resolution_set(dev); | ||
| 789 | |||
| 790 | return 0; | ||
| 791 | } | ||
| 792 | |||
| 736 | static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | 793 | static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, |
| 737 | struct v4l2_format *f) | 794 | struct v4l2_format *f) |
| 738 | { | 795 | { |
| 739 | struct em28xx_fh *fh = priv; | 796 | struct em28xx_fh *fh = priv; |
| 740 | struct em28xx *dev = fh->dev; | 797 | struct em28xx *dev = fh->dev; |
| 741 | int rc; | 798 | int rc; |
| 742 | struct em28xx_fmt *fmt; | ||
| 743 | 799 | ||
| 744 | rc = check_dev(dev); | 800 | rc = check_dev(dev); |
| 745 | if (rc < 0) | 801 | if (rc < 0) |
| @@ -749,12 +805,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | |||
| 749 | 805 | ||
| 750 | vidioc_try_fmt_vid_cap(file, priv, f); | 806 | vidioc_try_fmt_vid_cap(file, priv, f); |
| 751 | 807 | ||
| 752 | fmt = format_by_fourcc(f->fmt.pix.pixelformat); | ||
| 753 | if (!fmt) { | ||
| 754 | rc = -EINVAL; | ||
| 755 | goto out; | ||
| 756 | } | ||
| 757 | |||
| 758 | if (videobuf_queue_is_busy(&fh->vb_vidq)) { | 808 | if (videobuf_queue_is_busy(&fh->vb_vidq)) { |
| 759 | em28xx_errdev("%s queue busy\n", __func__); | 809 | em28xx_errdev("%s queue busy\n", __func__); |
| 760 | rc = -EBUSY; | 810 | rc = -EBUSY; |
| @@ -767,16 +817,8 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | |||
| 767 | goto out; | 817 | goto out; |
| 768 | } | 818 | } |
| 769 | 819 | ||
| 770 | /* set new image size */ | 820 | rc = em28xx_set_video_format(dev, f->fmt.pix.pixelformat, |
| 771 | dev->width = f->fmt.pix.width; | 821 | f->fmt.pix.width, f->fmt.pix.height); |
| 772 | dev->height = f->fmt.pix.height; | ||
| 773 | dev->format = fmt; | ||
| 774 | get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); | ||
| 775 | |||
| 776 | em28xx_set_alternate(dev); | ||
| 777 | em28xx_resolution_set(dev); | ||
| 778 | |||
| 779 | rc = 0; | ||
| 780 | 822 | ||
| 781 | out: | 823 | out: |
| 782 | mutex_unlock(&dev->lock); | 824 | mutex_unlock(&dev->lock); |
| @@ -1616,11 +1658,6 @@ static int em28xx_v4l2_open(struct file *filp) | |||
| 1616 | filp->private_data = fh; | 1658 | filp->private_data = fh; |
| 1617 | 1659 | ||
| 1618 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { | 1660 | if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { |
| 1619 | dev->width = norm_maxw(dev); | ||
| 1620 | dev->height = norm_maxh(dev); | ||
| 1621 | dev->hscale = 0; | ||
| 1622 | dev->vscale = 0; | ||
| 1623 | |||
| 1624 | em28xx_set_mode(dev, EM28XX_ANALOG_MODE); | 1661 | em28xx_set_mode(dev, EM28XX_ANALOG_MODE); |
| 1625 | em28xx_set_alternate(dev); | 1662 | em28xx_set_alternate(dev); |
| 1626 | em28xx_resolution_set(dev); | 1663 | em28xx_resolution_set(dev); |
| @@ -1962,15 +1999,14 @@ int em28xx_register_analog_devices(struct em28xx *dev) | |||
| 1962 | 1999 | ||
| 1963 | /* set default norm */ | 2000 | /* set default norm */ |
| 1964 | dev->norm = em28xx_video_template.current_norm; | 2001 | dev->norm = em28xx_video_template.current_norm; |
| 1965 | dev->width = norm_maxw(dev); | ||
| 1966 | dev->height = norm_maxh(dev); | ||
| 1967 | dev->interlaced = EM28XX_INTERLACED_DEFAULT; | 2002 | dev->interlaced = EM28XX_INTERLACED_DEFAULT; |
| 1968 | dev->hscale = 0; | ||
| 1969 | dev->vscale = 0; | ||
| 1970 | dev->ctl_input = 0; | 2003 | dev->ctl_input = 0; |
| 1971 | 2004 | ||
| 1972 | /* Analog specific initialization */ | 2005 | /* Analog specific initialization */ |
| 1973 | dev->format = &format[0]; | 2006 | dev->format = &format[0]; |
| 2007 | em28xx_set_video_format(dev, format[0].fourcc, | ||
| 2008 | norm_maxw(dev), norm_maxh(dev)); | ||
| 2009 | |||
| 1974 | video_mux(dev, dev->ctl_input); | 2010 | video_mux(dev, dev->ctl_input); |
| 1975 | 2011 | ||
| 1976 | /* Audio defaults */ | 2012 | /* Audio defaults */ |
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 813ce45c2f99..d90fef463764 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h | |||
| @@ -107,6 +107,7 @@ | |||
| 107 | #define EM2860_BOARD_TERRATEC_AV350 68 | 107 | #define EM2860_BOARD_TERRATEC_AV350 68 |
| 108 | #define EM2882_BOARD_KWORLD_ATSC_315U 69 | 108 | #define EM2882_BOARD_KWORLD_ATSC_315U 69 |
| 109 | #define EM2882_BOARD_EVGA_INDTUBE 70 | 109 | #define EM2882_BOARD_EVGA_INDTUBE 70 |
| 110 | #define EM2820_BOARD_SILVERCREST_WEBCAM 71 | ||
| 110 | 111 | ||
| 111 | /* Limits minimum and default number of buffers */ | 112 | /* Limits minimum and default number of buffers */ |
| 112 | #define EM28XX_MIN_BUF 4 | 113 | #define EM28XX_MIN_BUF 4 |
| @@ -360,6 +361,7 @@ enum em28xx_decoder { | |||
| 360 | EM28XX_NODECODER, | 361 | EM28XX_NODECODER, |
| 361 | EM28XX_TVP5150, | 362 | EM28XX_TVP5150, |
| 362 | EM28XX_SAA711X, | 363 | EM28XX_SAA711X, |
| 364 | EM28XX_MT9V011, | ||
| 363 | }; | 365 | }; |
| 364 | 366 | ||
| 365 | enum em28xx_adecoder { | 367 | enum em28xx_adecoder { |
| @@ -388,6 +390,7 @@ struct em28xx_board { | |||
| 388 | unsigned int max_range_640_480:1; | 390 | unsigned int max_range_640_480:1; |
| 389 | unsigned int has_dvb:1; | 391 | unsigned int has_dvb:1; |
| 390 | unsigned int has_snapshot_button:1; | 392 | unsigned int has_snapshot_button:1; |
| 393 | unsigned int is_27xx:1; | ||
| 391 | unsigned int valid:1; | 394 | unsigned int valid:1; |
| 392 | 395 | ||
| 393 | unsigned char xclk, i2c_speed; | 396 | unsigned char xclk, i2c_speed; |
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.h b/drivers/media/video/gspca/stv06xx/stv06xx.h index 9df7137fe67e..992ce530f138 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx.h | |||
| @@ -36,10 +36,6 @@ | |||
| 36 | 36 | ||
| 37 | #define STV_ISOC_ENDPOINT_ADDR 0x81 | 37 | #define STV_ISOC_ENDPOINT_ADDR 0x81 |
| 38 | 38 | ||
| 39 | #ifndef V4L2_PIX_FMT_SGRBG8 | ||
| 40 | #define V4L2_PIX_FMT_SGRBG8 v4l2_fourcc('G', 'R', 'B', 'G') | ||
| 41 | #endif | ||
| 42 | |||
| 43 | #define STV_REG23 0x0423 | 39 | #define STV_REG23 0x0423 |
| 44 | 40 | ||
| 45 | /* Control registers of the STV0600 ASIC */ | 41 | /* Control registers of the STV0600 ASIC */ |
diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c new file mode 100644 index 000000000000..1fe8fc9183a7 --- /dev/null +++ b/drivers/media/video/mt9v011.c | |||
| @@ -0,0 +1,431 @@ | |||
| 1 | /* | ||
| 2 | * mt9v011 -Micron 1/4-Inch VGA Digital Image Sensor | ||
| 3 | * | ||
| 4 | * Copyright (c) 2009 Mauro Carvalho Chehab (mchehab@redhat.com) | ||
| 5 | * This code is placed under the terms of the GNU General Public License v2 | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/i2c.h> | ||
| 9 | #include <linux/videodev2.h> | ||
| 10 | #include <linux/delay.h> | ||
| 11 | #include <media/v4l2-device.h> | ||
| 12 | #include "mt9v011.h" | ||
| 13 | #include <media/v4l2-i2c-drv.h> | ||
| 14 | #include <media/v4l2-chip-ident.h> | ||
| 15 | |||
| 16 | MODULE_DESCRIPTION("Micron mt9v011 sensor driver"); | ||
| 17 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); | ||
| 18 | MODULE_LICENSE("GPL"); | ||
| 19 | |||
| 20 | |||
| 21 | static int debug; | ||
| 22 | module_param(debug, int, 0); | ||
| 23 | MODULE_PARM_DESC(debug, "Debug level (0-2)"); | ||
| 24 | |||
| 25 | /* supported controls */ | ||
| 26 | static struct v4l2_queryctrl mt9v011_qctrl[] = { | ||
| 27 | { | ||
| 28 | .id = V4L2_CID_GAIN, | ||
| 29 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 30 | .name = "Gain", | ||
| 31 | .minimum = 0, | ||
| 32 | .maximum = (1 << 10) - 1, | ||
| 33 | .step = 1, | ||
| 34 | .default_value = 0x0020, | ||
| 35 | .flags = 0, | ||
| 36 | }, { | ||
| 37 | .id = V4L2_CID_RED_BALANCE, | ||
| 38 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 39 | .name = "Red Balance", | ||
| 40 | .minimum = -1 << 9, | ||
| 41 | .maximum = (1 << 9) - 1, | ||
| 42 | .step = 1, | ||
| 43 | .default_value = 0, | ||
| 44 | .flags = 0, | ||
| 45 | }, { | ||
| 46 | .id = V4L2_CID_BLUE_BALANCE, | ||
| 47 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
| 48 | .name = "Blue Balance", | ||
| 49 | .minimum = -1 << 9, | ||
| 50 | .maximum = (1 << 9) - 1, | ||
| 51 | .step = 1, | ||
| 52 | .default_value = 0, | ||
| 53 | .flags = 0, | ||
| 54 | }, | ||
| 55 | }; | ||
| 56 | |||
| 57 | struct mt9v011 { | ||
| 58 | struct v4l2_subdev sd; | ||
| 59 | unsigned width, height; | ||
| 60 | |||
| 61 | u16 global_gain, red_bal, blue_bal; | ||
| 62 | }; | ||
| 63 | |||
| 64 | static inline struct mt9v011 *to_mt9v011(struct v4l2_subdev *sd) | ||
| 65 | { | ||
| 66 | return container_of(sd, struct mt9v011, sd); | ||
| 67 | } | ||
| 68 | |||
| 69 | static int mt9v011_read(struct v4l2_subdev *sd, unsigned char addr) | ||
| 70 | { | ||
| 71 | struct i2c_client *c = v4l2_get_subdevdata(sd); | ||
| 72 | __be16 buffer; | ||
| 73 | int rc, val; | ||
| 74 | |||
| 75 | rc = i2c_master_send(c, &addr, 1); | ||
| 76 | if (rc != 1) | ||
| 77 | v4l2_dbg(0, debug, sd, | ||
| 78 | "i2c i/o error: rc == %d (should be 1)\n", rc); | ||
| 79 | |||
| 80 | msleep(10); | ||
| 81 | |||
| 82 | rc = i2c_master_recv(c, (char *)&buffer, 2); | ||
| 83 | if (rc != 2) | ||
| 84 | v4l2_dbg(0, debug, sd, | ||
| 85 | "i2c i/o error: rc == %d (should be 2)\n", rc); | ||
| 86 | |||
| 87 | val = be16_to_cpu(buffer); | ||
| 88 | |||
| 89 | v4l2_dbg(2, debug, sd, "mt9v011: read 0x%02x = 0x%04x\n", addr, val); | ||
| 90 | |||
| 91 | return val; | ||
| 92 | } | ||
| 93 | |||
| 94 | static void mt9v011_write(struct v4l2_subdev *sd, unsigned char addr, | ||
| 95 | u16 value) | ||
| 96 | { | ||
| 97 | struct i2c_client *c = v4l2_get_subdevdata(sd); | ||
| 98 | unsigned char buffer[3]; | ||
| 99 | int rc; | ||
| 100 | |||
| 101 | buffer[0] = addr; | ||
| 102 | buffer[1] = value >> 8; | ||
| 103 | buffer[2] = value & 0xff; | ||
| 104 | |||
| 105 | v4l2_dbg(2, debug, sd, | ||
| 106 | "mt9v011: writing 0x%02x 0x%04x\n", buffer[0], value); | ||
| 107 | rc = i2c_master_send(c, buffer, 3); | ||
| 108 | if (rc != 3) | ||
| 109 | v4l2_dbg(0, debug, sd, | ||
| 110 | "i2c i/o error: rc == %d (should be 3)\n", rc); | ||
| 111 | } | ||
| 112 | |||
| 113 | |||
| 114 | struct i2c_reg_value { | ||
| 115 | unsigned char reg; | ||
| 116 | u16 value; | ||
| 117 | }; | ||
| 118 | |||
| 119 | /* | ||
| 120 | * Values used at the original driver | ||
| 121 | * Some values are marked as Reserved at the datasheet | ||
| 122 | */ | ||
| 123 | static const struct i2c_reg_value mt9v011_init_default[] = { | ||
| 124 | { R0D_MT9V011_RESET, 0x0001 }, | ||
| 125 | { R0D_MT9V011_RESET, 0x0000 }, | ||
| 126 | |||
| 127 | { R0C_MT9V011_SHUTTER_DELAY, 0x0000 }, | ||
| 128 | { R09_MT9V011_SHUTTER_WIDTH, 0x1fc }, | ||
| 129 | |||
| 130 | { R0A_MT9V011_CLK_SPEED, 0x0000 }, | ||
| 131 | { R1E_MT9V011_DIGITAL_ZOOM, 0x0000 }, | ||
| 132 | { R20_MT9V011_READ_MODE, 0x1000 }, | ||
| 133 | |||
| 134 | { R07_MT9V011_OUT_CTRL, 0x000a }, /* chip enable */ | ||
| 135 | }; | ||
| 136 | |||
| 137 | static void set_balance(struct v4l2_subdev *sd) | ||
| 138 | { | ||
| 139 | struct mt9v011 *core = to_mt9v011(sd); | ||
| 140 | u16 green1_gain, green2_gain, blue_gain, red_gain; | ||
| 141 | |||
| 142 | green1_gain = core->global_gain; | ||
| 143 | green2_gain = core->global_gain; | ||
| 144 | |||
| 145 | blue_gain = core->global_gain + | ||
| 146 | core->global_gain * core->blue_bal / (1 << 9); | ||
| 147 | |||
| 148 | red_gain = core->global_gain + | ||
| 149 | core->global_gain * core->blue_bal / (1 << 9); | ||
| 150 | |||
| 151 | mt9v011_write(sd, R2B_MT9V011_GREEN_1_GAIN, green1_gain); | ||
| 152 | mt9v011_write(sd, R2E_MT9V011_GREEN_2_GAIN, green1_gain); | ||
| 153 | mt9v011_write(sd, R2C_MT9V011_BLUE_GAIN, blue_gain); | ||
| 154 | mt9v011_write(sd, R2D_MT9V011_RED_GAIN, red_gain); | ||
| 155 | } | ||
| 156 | |||
| 157 | static void set_res(struct v4l2_subdev *sd) | ||
| 158 | { | ||
| 159 | struct mt9v011 *core = to_mt9v011(sd); | ||
| 160 | unsigned vstart, hstart; | ||
| 161 | |||
| 162 | /* | ||
| 163 | * The mt9v011 doesn't have scaling. So, in order to select the desired | ||
| 164 | * resolution, we're cropping at the middle of the sensor. | ||
| 165 | * hblank and vblank should be adjusted, in order to warrant that | ||
| 166 | * we'll preserve the line timings for 30 fps, no matter what resolution | ||
| 167 | * is selected. | ||
| 168 | * NOTE: datasheet says that width (and height) should be filled with | ||
| 169 | * width-1. However, this doesn't work, since one pixel per line will | ||
| 170 | * be missing. | ||
| 171 | */ | ||
| 172 | |||
| 173 | hstart = 14 + (640 - core->width) / 2; | ||
| 174 | mt9v011_write(sd, R02_MT9V011_COLSTART, hstart); | ||
| 175 | mt9v011_write(sd, R04_MT9V011_WIDTH, core->width); | ||
| 176 | mt9v011_write(sd, R05_MT9V011_HBLANK, 771 - core->width); | ||
| 177 | |||
| 178 | vstart = 8 + (640 - core->height) / 2; | ||
| 179 | mt9v011_write(sd, R01_MT9V011_ROWSTART, vstart); | ||
| 180 | mt9v011_write(sd, R03_MT9V011_HEIGHT, core->height); | ||
| 181 | mt9v011_write(sd, R06_MT9V011_VBLANK, 508 - core->height); | ||
| 182 | }; | ||
| 183 | |||
| 184 | static int mt9v011_reset(struct v4l2_subdev *sd, u32 val) | ||
| 185 | { | ||
| 186 | int i; | ||
| 187 | |||
| 188 | for (i = 0; i < ARRAY_SIZE(mt9v011_init_default); i++) | ||
| 189 | mt9v011_write(sd, mt9v011_init_default[i].reg, | ||
| 190 | mt9v011_init_default[i].value); | ||
| 191 | |||
| 192 | set_balance(sd); | ||
| 193 | set_res(sd); | ||
| 194 | |||
| 195 | return 0; | ||
| 196 | }; | ||
| 197 | |||
| 198 | static int mt9v011_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
| 199 | { | ||
| 200 | struct mt9v011 *core = to_mt9v011(sd); | ||
| 201 | |||
| 202 | v4l2_dbg(1, debug, sd, "g_ctrl called\n"); | ||
| 203 | |||
| 204 | switch (ctrl->id) { | ||
| 205 | case V4L2_CID_GAIN: | ||
| 206 | ctrl->value = core->global_gain; | ||
| 207 | return 0; | ||
| 208 | case V4L2_CID_RED_BALANCE: | ||
| 209 | ctrl->value = core->red_bal; | ||
| 210 | return 0; | ||
| 211 | case V4L2_CID_BLUE_BALANCE: | ||
| 212 | ctrl->value = core->blue_bal; | ||
| 213 | return 0; | ||
| 214 | } | ||
| 215 | return -EINVAL; | ||
| 216 | } | ||
| 217 | |||
| 218 | static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
| 219 | { | ||
| 220 | struct mt9v011 *core = to_mt9v011(sd); | ||
| 221 | u8 i, n; | ||
| 222 | n = ARRAY_SIZE(mt9v011_qctrl); | ||
| 223 | |||
| 224 | for (i = 0; i < n; i++) { | ||
| 225 | if (ctrl->id != mt9v011_qctrl[i].id) | ||
| 226 | continue; | ||
| 227 | if (ctrl->value < mt9v011_qctrl[i].minimum || | ||
| 228 | ctrl->value > mt9v011_qctrl[i].maximum) | ||
| 229 | return -ERANGE; | ||
| 230 | v4l2_dbg(1, debug, sd, "s_ctrl: id=%d, value=%d\n", | ||
| 231 | ctrl->id, ctrl->value); | ||
| 232 | break; | ||
| 233 | } | ||
| 234 | |||
| 235 | switch (ctrl->id) { | ||
| 236 | case V4L2_CID_GAIN: | ||
| 237 | core->global_gain = ctrl->value; | ||
| 238 | break; | ||
| 239 | case V4L2_CID_RED_BALANCE: | ||
| 240 | core->red_bal = ctrl->value; | ||
| 241 | break; | ||
| 242 | case V4L2_CID_BLUE_BALANCE: | ||
| 243 | core->blue_bal = ctrl->value; | ||
| 244 | break; | ||
| 245 | default: | ||
| 246 | return -EINVAL; | ||
| 247 | } | ||
| 248 | |||
| 249 | set_balance(sd); | ||
| 250 | |||
| 251 | return 0; | ||
| 252 | } | ||
| 253 | |||
| 254 | static int mt9v011_enum_fmt(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt) | ||
| 255 | { | ||
| 256 | if (fmt->index > 0) | ||
| 257 | return -EINVAL; | ||
| 258 | |||
| 259 | fmt->flags = 0; | ||
| 260 | strcpy(fmt->description, "8 bpp Bayer GRGR..BGBG"); | ||
| 261 | fmt->pixelformat = V4L2_PIX_FMT_SGRBG8; | ||
| 262 | |||
| 263 | return 0; | ||
| 264 | } | ||
| 265 | |||
| 266 | static int mt9v011_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) | ||
| 267 | { | ||
| 268 | struct v4l2_pix_format *pix = &fmt->fmt.pix; | ||
| 269 | |||
| 270 | if (pix->pixelformat != V4L2_PIX_FMT_SGRBG8) | ||
| 271 | return -EINVAL; | ||
| 272 | |||
| 273 | v4l_bound_align_image(&pix->width, 48, 639, 1, | ||
| 274 | &pix->height, 32, 480, 1, 0); | ||
| 275 | |||
| 276 | return 0; | ||
| 277 | } | ||
| 278 | |||
| 279 | static int mt9v011_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) | ||
| 280 | { | ||
| 281 | struct v4l2_pix_format *pix = &fmt->fmt.pix; | ||
| 282 | struct mt9v011 *core = to_mt9v011(sd); | ||
| 283 | int rc; | ||
| 284 | |||
| 285 | rc = mt9v011_try_fmt(sd, fmt); | ||
| 286 | if (rc < 0) | ||
| 287 | return -EINVAL; | ||
| 288 | |||
| 289 | core->width = pix->width; | ||
| 290 | core->height = pix->height; | ||
| 291 | |||
| 292 | set_res(sd); | ||
| 293 | |||
| 294 | return 0; | ||
| 295 | } | ||
| 296 | |||
| 297 | |||
| 298 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
| 299 | static int mt9v011_g_register(struct v4l2_subdev *sd, | ||
| 300 | struct v4l2_dbg_register *reg) | ||
| 301 | { | ||
| 302 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 303 | |||
| 304 | if (!v4l2_chip_match_i2c_client(client, ®->match)) | ||
| 305 | return -EINVAL; | ||
| 306 | if (!capable(CAP_SYS_ADMIN)) | ||
| 307 | return -EPERM; | ||
| 308 | |||
| 309 | reg->val = mt9v011_read(sd, reg->reg & 0xff); | ||
| 310 | reg->size = 2; | ||
| 311 | |||
| 312 | return 0; | ||
| 313 | } | ||
| 314 | |||
| 315 | static int mt9v011_s_register(struct v4l2_subdev *sd, | ||
| 316 | struct v4l2_dbg_register *reg) | ||
| 317 | { | ||
| 318 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 319 | |||
| 320 | if (!v4l2_chip_match_i2c_client(client, ®->match)) | ||
| 321 | return -EINVAL; | ||
| 322 | if (!capable(CAP_SYS_ADMIN)) | ||
| 323 | return -EPERM; | ||
| 324 | |||
| 325 | mt9v011_write(sd, reg->reg & 0xff, reg->val & 0xffff); | ||
| 326 | |||
| 327 | return 0; | ||
| 328 | } | ||
| 329 | #endif | ||
| 330 | |||
| 331 | static int mt9v011_g_chip_ident(struct v4l2_subdev *sd, | ||
| 332 | struct v4l2_dbg_chip_ident *chip) | ||
| 333 | { | ||
| 334 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 335 | |||
| 336 | return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_MT9V011, | ||
| 337 | MT9V011_VERSION); | ||
| 338 | } | ||
| 339 | |||
| 340 | static const struct v4l2_subdev_core_ops mt9v011_core_ops = { | ||
| 341 | .g_ctrl = mt9v011_g_ctrl, | ||
| 342 | .s_ctrl = mt9v011_s_ctrl, | ||
| 343 | .reset = mt9v011_reset, | ||
| 344 | .g_chip_ident = mt9v011_g_chip_ident, | ||
| 345 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
| 346 | .g_register = mt9v011_g_register, | ||
| 347 | .s_register = mt9v011_s_register, | ||
| 348 | #endif | ||
| 349 | }; | ||
| 350 | |||
| 351 | static const struct v4l2_subdev_video_ops mt9v011_video_ops = { | ||
| 352 | .enum_fmt = mt9v011_enum_fmt, | ||
| 353 | .try_fmt = mt9v011_try_fmt, | ||
| 354 | .s_fmt = mt9v011_s_fmt, | ||
| 355 | }; | ||
| 356 | |||
| 357 | static const struct v4l2_subdev_ops mt9v011_ops = { | ||
| 358 | .core = &mt9v011_core_ops, | ||
| 359 | .video = &mt9v011_video_ops, | ||
| 360 | }; | ||
| 361 | |||
| 362 | |||
| 363 | /**************************************************************************** | ||
| 364 | I2C Client & Driver | ||
| 365 | ****************************************************************************/ | ||
| 366 | |||
| 367 | static int mt9v011_probe(struct i2c_client *c, | ||
| 368 | const struct i2c_device_id *id) | ||
| 369 | { | ||
| 370 | u16 version; | ||
| 371 | struct mt9v011 *core; | ||
| 372 | struct v4l2_subdev *sd; | ||
| 373 | |||
| 374 | /* Check if the adapter supports the needed features */ | ||
| 375 | if (!i2c_check_functionality(c->adapter, | ||
| 376 | I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) | ||
| 377 | return -EIO; | ||
| 378 | |||
| 379 | core = kzalloc(sizeof(struct mt9v011), GFP_KERNEL); | ||
| 380 | if (!core) | ||
| 381 | return -ENOMEM; | ||
| 382 | |||
| 383 | sd = &core->sd; | ||
| 384 | v4l2_i2c_subdev_init(sd, c, &mt9v011_ops); | ||
| 385 | |||
| 386 | /* Check if the sensor is really a MT9V011 */ | ||
| 387 | version = mt9v011_read(sd, R00_MT9V011_CHIP_VERSION); | ||
| 388 | if (version != MT9V011_VERSION) { | ||
| 389 | v4l2_info(sd, "*** unknown micron chip detected (0x%04x.\n", | ||
| 390 | version); | ||
| 391 | kfree(core); | ||
| 392 | return -EINVAL; | ||
| 393 | } | ||
| 394 | |||
| 395 | core->global_gain = 0x0024; | ||
| 396 | core->width = 640; | ||
| 397 | core->height = 480; | ||
| 398 | |||
| 399 | v4l_info(c, "chip found @ 0x%02x (%s)\n", | ||
| 400 | c->addr << 1, c->adapter->name); | ||
| 401 | |||
| 402 | return 0; | ||
| 403 | } | ||
| 404 | |||
| 405 | static int mt9v011_remove(struct i2c_client *c) | ||
| 406 | { | ||
| 407 | struct v4l2_subdev *sd = i2c_get_clientdata(c); | ||
| 408 | |||
| 409 | v4l2_dbg(1, debug, sd, | ||
| 410 | "mt9v011.c: removing mt9v011 adapter on address 0x%x\n", | ||
| 411 | c->addr << 1); | ||
| 412 | |||
| 413 | v4l2_device_unregister_subdev(sd); | ||
| 414 | kfree(to_mt9v011(sd)); | ||
| 415 | return 0; | ||
| 416 | } | ||
| 417 | |||
| 418 | /* ----------------------------------------------------------------------- */ | ||
| 419 | |||
| 420 | static const struct i2c_device_id mt9v011_id[] = { | ||
| 421 | { "mt9v011", 0 }, | ||
| 422 | { } | ||
| 423 | }; | ||
| 424 | MODULE_DEVICE_TABLE(i2c, mt9v011_id); | ||
| 425 | |||
| 426 | static struct v4l2_i2c_driver_data v4l2_i2c_data = { | ||
| 427 | .name = "mt9v011", | ||
| 428 | .probe = mt9v011_probe, | ||
| 429 | .remove = mt9v011_remove, | ||
| 430 | .id_table = mt9v011_id, | ||
| 431 | }; | ||
diff --git a/drivers/media/video/mt9v011.h b/drivers/media/video/mt9v011.h new file mode 100644 index 000000000000..9e443ee30558 --- /dev/null +++ b/drivers/media/video/mt9v011.h | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | /* | ||
| 2 | * mt9v011 -Micron 1/4-Inch VGA Digital Image Sensor | ||
| 3 | * | ||
| 4 | * Copyright (c) 2009 Mauro Carvalho Chehab (mchehab@redhat.com) | ||
| 5 | * This code is placed under the terms of the GNU General Public License v2 | ||
| 6 | */ | ||
| 7 | |||
| 8 | #ifndef MT9V011_H_ | ||
| 9 | #define MT9V011_H_ | ||
| 10 | |||
| 11 | #define R00_MT9V011_CHIP_VERSION 0x00 | ||
| 12 | #define R01_MT9V011_ROWSTART 0x01 | ||
| 13 | #define R02_MT9V011_COLSTART 0x02 | ||
| 14 | #define R03_MT9V011_HEIGHT 0x03 | ||
| 15 | #define R04_MT9V011_WIDTH 0x04 | ||
| 16 | #define R05_MT9V011_HBLANK 0x05 | ||
| 17 | #define R06_MT9V011_VBLANK 0x06 | ||
| 18 | #define R07_MT9V011_OUT_CTRL 0x07 | ||
| 19 | #define R09_MT9V011_SHUTTER_WIDTH 0x09 | ||
| 20 | #define R0A_MT9V011_CLK_SPEED 0x0a | ||
| 21 | #define R0B_MT9V011_RESTART 0x0b | ||
| 22 | #define R0C_MT9V011_SHUTTER_DELAY 0x0c | ||
| 23 | #define R0D_MT9V011_RESET 0x0d | ||
| 24 | #define R1E_MT9V011_DIGITAL_ZOOM 0x1e | ||
| 25 | #define R20_MT9V011_READ_MODE 0x20 | ||
| 26 | #define R2B_MT9V011_GREEN_1_GAIN 0x2b | ||
| 27 | #define R2C_MT9V011_BLUE_GAIN 0x2c | ||
| 28 | #define R2D_MT9V011_RED_GAIN 0x2d | ||
| 29 | #define R2E_MT9V011_GREEN_2_GAIN 0x2e | ||
| 30 | #define R35_MT9V011_GLOBAL_GAIN 0x35 | ||
| 31 | #define RF1_MT9V011_CHIP_ENABLE 0xf1 | ||
| 32 | |||
| 33 | #define MT9V011_VERSION 0x8243 | ||
| 34 | |||
| 35 | #endif | ||
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index 16f595d4337a..9f5ae8167855 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c | |||
| @@ -237,11 +237,11 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) | |||
| 237 | return -ENOMEM; | 237 | return -ENOMEM; |
| 238 | 238 | ||
| 239 | icd->num_user_formats = fmts; | 239 | icd->num_user_formats = fmts; |
| 240 | fmts = 0; | ||
| 241 | 240 | ||
| 242 | dev_dbg(&icd->dev, "Found %d supported formats.\n", fmts); | 241 | dev_dbg(&icd->dev, "Found %d supported formats.\n", fmts); |
| 243 | 242 | ||
| 244 | /* Second pass - actually fill data formats */ | 243 | /* Second pass - actually fill data formats */ |
| 244 | fmts = 0; | ||
| 245 | for (i = 0; i < icd->num_formats; i++) | 245 | for (i = 0; i < icd->num_formats; i++) |
| 246 | if (!ici->ops->get_formats) { | 246 | if (!ici->ops->get_formats) { |
| 247 | icd->user_formats[i].host_fmt = icd->formats + i; | 247 | icd->user_formats[i].host_fmt = icd->formats + i; |
| @@ -877,8 +877,11 @@ static int soc_camera_probe(struct device *dev) | |||
| 877 | (unsigned short)~0; | 877 | (unsigned short)~0; |
| 878 | 878 | ||
| 879 | ret = soc_camera_init_user_formats(icd); | 879 | ret = soc_camera_init_user_formats(icd); |
| 880 | if (ret < 0) | 880 | if (ret < 0) { |
| 881 | if (icd->ops->remove) | ||
| 882 | icd->ops->remove(icd); | ||
| 881 | goto eiufmt; | 883 | goto eiufmt; |
| 884 | } | ||
| 882 | 885 | ||
| 883 | icd->height = DEFAULT_HEIGHT; | 886 | icd->height = DEFAULT_HEIGHT; |
| 884 | icd->width = DEFAULT_WIDTH; | 887 | icd->width = DEFAULT_WIDTH; |
| @@ -902,8 +905,10 @@ static int soc_camera_remove(struct device *dev) | |||
| 902 | { | 905 | { |
| 903 | struct soc_camera_device *icd = to_soc_camera_dev(dev); | 906 | struct soc_camera_device *icd = to_soc_camera_dev(dev); |
| 904 | 907 | ||
| 908 | mutex_lock(&icd->video_lock); | ||
| 905 | if (icd->ops->remove) | 909 | if (icd->ops->remove) |
| 906 | icd->ops->remove(icd); | 910 | icd->ops->remove(icd); |
| 911 | mutex_unlock(&icd->video_lock); | ||
| 907 | 912 | ||
| 908 | soc_camera_free_user_formats(icd); | 913 | soc_camera_free_user_formats(icd); |
| 909 | 914 | ||
| @@ -1145,6 +1150,7 @@ evidallocd: | |||
| 1145 | } | 1150 | } |
| 1146 | EXPORT_SYMBOL(soc_camera_video_start); | 1151 | EXPORT_SYMBOL(soc_camera_video_start); |
| 1147 | 1152 | ||
| 1153 | /* Called from client .remove() methods with .video_lock held */ | ||
| 1148 | void soc_camera_video_stop(struct soc_camera_device *icd) | 1154 | void soc_camera_video_stop(struct soc_camera_device *icd) |
| 1149 | { | 1155 | { |
| 1150 | struct video_device *vdev = icd->vdev; | 1156 | struct video_device *vdev = icd->vdev; |
| @@ -1154,10 +1160,8 @@ void soc_camera_video_stop(struct soc_camera_device *icd) | |||
| 1154 | if (!icd->dev.parent || !vdev) | 1160 | if (!icd->dev.parent || !vdev) |
| 1155 | return; | 1161 | return; |
| 1156 | 1162 | ||
| 1157 | mutex_lock(&icd->video_lock); | ||
| 1158 | video_unregister_device(vdev); | 1163 | video_unregister_device(vdev); |
| 1159 | icd->vdev = NULL; | 1164 | icd->vdev = NULL; |
| 1160 | mutex_unlock(&icd->video_lock); | ||
| 1161 | } | 1165 | } |
| 1162 | EXPORT_SYMBOL(soc_camera_video_stop); | 1166 | EXPORT_SYMBOL(soc_camera_video_stop); |
| 1163 | 1167 | ||
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index cd7266858462..7705fc6baf00 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c | |||
| @@ -343,6 +343,53 @@ static struct bar_std bars[] = { | |||
| 343 | #define TO_U(r, g, b) \ | 343 | #define TO_U(r, g, b) \ |
| 344 | (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128) | 344 | (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128) |
| 345 | 345 | ||
| 346 | /* precalculate color bar values to speed up rendering */ | ||
| 347 | static void precalculate_bars(struct vivi_fh *fh) | ||
| 348 | { | ||
| 349 | struct vivi_dev *dev = fh->dev; | ||
| 350 | unsigned char r, g, b; | ||
| 351 | int k, is_yuv; | ||
| 352 | |||
| 353 | fh->input = dev->input; | ||
| 354 | |||
| 355 | for (k = 0; k < 8; k++) { | ||
| 356 | r = bars[fh->input].bar[k][0]; | ||
| 357 | g = bars[fh->input].bar[k][1]; | ||
| 358 | b = bars[fh->input].bar[k][2]; | ||
| 359 | is_yuv = 0; | ||
| 360 | |||
| 361 | switch (fh->fmt->fourcc) { | ||
| 362 | case V4L2_PIX_FMT_YUYV: | ||
| 363 | case V4L2_PIX_FMT_UYVY: | ||
| 364 | is_yuv = 1; | ||
| 365 | break; | ||
| 366 | case V4L2_PIX_FMT_RGB565: | ||
| 367 | case V4L2_PIX_FMT_RGB565X: | ||
| 368 | r >>= 3; | ||
| 369 | g >>= 2; | ||
| 370 | b >>= 3; | ||
| 371 | break; | ||
| 372 | case V4L2_PIX_FMT_RGB555: | ||
| 373 | case V4L2_PIX_FMT_RGB555X: | ||
| 374 | r >>= 3; | ||
| 375 | g >>= 3; | ||
| 376 | b >>= 3; | ||
| 377 | break; | ||
| 378 | } | ||
| 379 | |||
| 380 | if (is_yuv) { | ||
| 381 | fh->bars[k][0] = TO_Y(r, g, b); /* Luma */ | ||
| 382 | fh->bars[k][1] = TO_U(r, g, b); /* Cb */ | ||
| 383 | fh->bars[k][2] = TO_V(r, g, b); /* Cr */ | ||
| 384 | } else { | ||
| 385 | fh->bars[k][0] = r; | ||
| 386 | fh->bars[k][1] = g; | ||
| 387 | fh->bars[k][2] = b; | ||
| 388 | } | ||
| 389 | } | ||
| 390 | |||
| 391 | } | ||
| 392 | |||
| 346 | #define TSTAMP_MIN_Y 24 | 393 | #define TSTAMP_MIN_Y 24 |
| 347 | #define TSTAMP_MAX_Y (TSTAMP_MIN_Y + 15) | 394 | #define TSTAMP_MAX_Y (TSTAMP_MIN_Y + 15) |
| 348 | #define TSTAMP_INPUT_X 10 | 395 | #define TSTAMP_INPUT_X 10 |
| @@ -755,6 +802,8 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, | |||
| 755 | buf->vb.height = fh->height; | 802 | buf->vb.height = fh->height; |
| 756 | buf->vb.field = field; | 803 | buf->vb.field = field; |
| 757 | 804 | ||
| 805 | precalculate_bars(fh); | ||
| 806 | |||
| 758 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | 807 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { |
| 759 | rc = videobuf_iolock(vq, &buf->vb, NULL); | 808 | rc = videobuf_iolock(vq, &buf->vb, NULL); |
| 760 | if (rc < 0) | 809 | if (rc < 0) |
| @@ -893,53 +942,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, | |||
| 893 | return 0; | 942 | return 0; |
| 894 | } | 943 | } |
| 895 | 944 | ||
| 896 | /* precalculate color bar values to speed up rendering */ | ||
| 897 | static void precalculate_bars(struct vivi_fh *fh) | ||
| 898 | { | ||
| 899 | struct vivi_dev *dev = fh->dev; | ||
| 900 | unsigned char r, g, b; | ||
| 901 | int k, is_yuv; | ||
| 902 | |||
| 903 | fh->input = dev->input; | ||
| 904 | |||
| 905 | for (k = 0; k < 8; k++) { | ||
| 906 | r = bars[fh->input].bar[k][0]; | ||
| 907 | g = bars[fh->input].bar[k][1]; | ||
| 908 | b = bars[fh->input].bar[k][2]; | ||
| 909 | is_yuv = 0; | ||
| 910 | |||
| 911 | switch (fh->fmt->fourcc) { | ||
| 912 | case V4L2_PIX_FMT_YUYV: | ||
| 913 | case V4L2_PIX_FMT_UYVY: | ||
| 914 | is_yuv = 1; | ||
| 915 | break; | ||
| 916 | case V4L2_PIX_FMT_RGB565: | ||
| 917 | case V4L2_PIX_FMT_RGB565X: | ||
| 918 | r >>= 3; | ||
| 919 | g >>= 2; | ||
| 920 | b >>= 3; | ||
| 921 | break; | ||
| 922 | case V4L2_PIX_FMT_RGB555: | ||
| 923 | case V4L2_PIX_FMT_RGB555X: | ||
| 924 | r >>= 3; | ||
| 925 | g >>= 3; | ||
| 926 | b >>= 3; | ||
| 927 | break; | ||
| 928 | } | ||
| 929 | |||
| 930 | if (is_yuv) { | ||
| 931 | fh->bars[k][0] = TO_Y(r, g, b); /* Luma */ | ||
| 932 | fh->bars[k][1] = TO_U(r, g, b); /* Cb */ | ||
| 933 | fh->bars[k][2] = TO_V(r, g, b); /* Cr */ | ||
| 934 | } else { | ||
| 935 | fh->bars[k][0] = r; | ||
| 936 | fh->bars[k][1] = g; | ||
| 937 | fh->bars[k][2] = b; | ||
| 938 | } | ||
| 939 | } | ||
| 940 | |||
| 941 | } | ||
| 942 | |||
| 943 | /*FIXME: This seems to be generic enough to be at videodev2 */ | 945 | /*FIXME: This seems to be generic enough to be at videodev2 */ |
| 944 | static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | 946 | static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, |
| 945 | struct v4l2_format *f) | 947 | struct v4l2_format *f) |
| @@ -965,8 +967,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | |||
| 965 | fh->vb_vidq.field = f->fmt.pix.field; | 967 | fh->vb_vidq.field = f->fmt.pix.field; |
| 966 | fh->type = f->type; | 968 | fh->type = f->type; |
| 967 | 969 | ||
| 968 | precalculate_bars(fh); | ||
| 969 | |||
| 970 | ret = 0; | 970 | ret = 0; |
| 971 | out: | 971 | out: |
| 972 | mutex_unlock(&q->vb_lock); | 972 | mutex_unlock(&q->vb_lock); |
| @@ -1357,6 +1357,7 @@ static int __init vivi_create_instance(int inst) | |||
| 1357 | goto unreg_dev; | 1357 | goto unreg_dev; |
| 1358 | 1358 | ||
| 1359 | *vfd = vivi_template; | 1359 | *vfd = vivi_template; |
| 1360 | vfd->debug = debug; | ||
| 1360 | 1361 | ||
| 1361 | ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); | 1362 | ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); |
| 1362 | if (ret < 0) | 1363 | if (ret < 0) |
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 8a025d510904..95846d988011 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h | |||
| @@ -318,6 +318,8 @@ struct v4l2_pix_format { | |||
| 318 | /* see http://www.siliconimaging.com/RGB%20Bayer.htm */ | 318 | /* see http://www.siliconimaging.com/RGB%20Bayer.htm */ |
| 319 | #define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B', 'A', '8', '1') /* 8 BGBG.. GRGR.. */ | 319 | #define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B', 'A', '8', '1') /* 8 BGBG.. GRGR.. */ |
| 320 | #define V4L2_PIX_FMT_SGBRG8 v4l2_fourcc('G', 'B', 'R', 'G') /* 8 GBGB.. RGRG.. */ | 320 | #define V4L2_PIX_FMT_SGBRG8 v4l2_fourcc('G', 'B', 'R', 'G') /* 8 GBGB.. RGRG.. */ |
| 321 | #define V4L2_PIX_FMT_SGRBG8 v4l2_fourcc('G', 'R', 'B', 'G') /* 8 GRGR.. BGBG.. */ | ||
| 322 | |||
| 321 | /* | 323 | /* |
| 322 | * 10bit raw bayer, expanded to 16 bits | 324 | * 10bit raw bayer, expanded to 16 bits |
| 323 | * xxxxrrrrrrrrrrxxxxgggggggggg xxxxggggggggggxxxxbbbbbbbbbb... | 325 | * xxxxrrrrrrrrrrxxxxgggggggggg xxxxggggggggggxxxxbbbbbbbbbb... |
diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h index 4d7e2272c42f..11a4a2d3e364 100644 --- a/include/media/v4l2-chip-ident.h +++ b/include/media/v4l2-chip-ident.h | |||
| @@ -155,6 +155,9 @@ enum { | |||
| 155 | /* module cafe_ccic, just ident 8801 */ | 155 | /* module cafe_ccic, just ident 8801 */ |
| 156 | V4L2_IDENT_CAFE = 8801, | 156 | V4L2_IDENT_CAFE = 8801, |
| 157 | 157 | ||
| 158 | /* module mt9v011, just ident 8243 */ | ||
| 159 | V4L2_IDENT_MT9V011 = 8243, | ||
| 160 | |||
| 158 | /* module tw9910: just ident 9910 */ | 161 | /* module tw9910: just ident 9910 */ |
| 159 | V4L2_IDENT_TW9910 = 9910, | 162 | V4L2_IDENT_TW9910 = 9910, |
| 160 | 163 | ||
