aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2009-06-29 10:35:05 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-07-05 13:30:05 -0400
commit02e7804b2135ff941b8846f5820cf48fbfdadd54 (patch)
tree58d3e596946d4c6b1bae23465f5d9b80e893d300 /drivers
parent6934e6fface7b7d5fe7e578c3f43cbe8f23af2d4 (diff)
V4L/DVB (12138): em28xx: add support for Silvercrest Webcam
This webcam uses a em2710 chipset, that identifies itself as em2820, plus a mt9v011 sensor, and a DY-301P lens. It needs a few different initializations than a normal em28xx device. Thanks to Hans de Goede <hdegoede@redhat.com> and Douglas Landgraf <dougsland@redhat.com> for providing the acces for the webcam during this weekend, I could make a patch for it while returning back from FISL/Fudcom LATAM 2009. Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/em28xx/Kconfig2
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c37
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c33
-rw-r--r--drivers/media/video/em28xx/em28xx.h3
4 files changed, 68 insertions, 7 deletions
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..bd9b637c7ea5 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -191,6 +191,13 @@ static struct em28xx_reg_seq terratec_av350_unmute_gpio[] = {
191 {EM28XX_R08_GPIO, 0xff, 0xff, 10}, 191 {EM28XX_R08_GPIO, 0xff, 0xff, 10},
192 { -1, -1, -1, -1}, 192 { -1, -1, -1, -1},
193}; 193};
194
195static struct em28xx_reg_seq silvercrest_reg_seq[] = {
196 {EM28XX_R08_GPIO, 0xff, 0xff, 10},
197 {EM28XX_R08_GPIO, 0x01, 0xf7, 10},
198 { -1, -1, -1, -1},
199};
200
194/* 201/*
195 * Board definitions 202 * Board definitions
196 */ 203 */
@@ -438,6 +445,18 @@ struct em28xx_board em28xx_boards[] = {
438 .amux = EM28XX_AMUX_VIDEO, 445 .amux = EM28XX_AMUX_VIDEO,
439 } }, 446 } },
440 }, 447 },
448 [EM2820_BOARD_SILVERCREST_WEBCAM] = {
449 .name = "Silvercrest Webcam 1.3mpix",
450 .tuner_type = TUNER_ABSENT,
451 .is_27xx = 1,
452 .decoder = EM28XX_MT9V011,
453 .input = { {
454 .type = EM28XX_VMUX_COMPOSITE1,
455 .vmux = 0,
456 .amux = EM28XX_AMUX_VIDEO,
457 .gpio = silvercrest_reg_seq,
458 } },
459 },
441 [EM2821_BOARD_SUPERCOMP_USB_2] = { 460 [EM2821_BOARD_SUPERCOMP_USB_2] = {
442 .name = "Supercomp USB 2.0 TV", 461 .name = "Supercomp USB 2.0 TV",
443 .valid = EM28XX_BOARD_NOT_VALIDATED, 462 .valid = EM28XX_BOARD_NOT_VALIDATED,
@@ -1639,6 +1658,11 @@ static unsigned short tvp5150_addrs[] = {
1639 I2C_CLIENT_END 1658 I2C_CLIENT_END
1640}; 1659};
1641 1660
1661static unsigned short mt9v011_addrs[] = {
1662 0xba >> 1,
1663 I2C_CLIENT_END
1664};
1665
1642static unsigned short msp3400_addrs[] = { 1666static unsigned short msp3400_addrs[] = {
1643 0x80 >> 1, 1667 0x80 >> 1,
1644 0x88 >> 1, 1668 0x88 >> 1,
@@ -1706,7 +1730,10 @@ void em28xx_pre_card_setup(struct em28xx *dev)
1706 em28xx_info("chip ID is em2750\n"); 1730 em28xx_info("chip ID is em2750\n");
1707 break; 1731 break;
1708 case CHIP_ID_EM2820: 1732 case CHIP_ID_EM2820:
1709 em28xx_info("chip ID is em2820\n"); 1733 if (dev->board.is_27xx)
1734 em28xx_info("chip is em2710\n");
1735 else
1736 em28xx_info("chip ID is em2820\n");
1710 break; 1737 break;
1711 case CHIP_ID_EM2840: 1738 case CHIP_ID_EM2840:
1712 em28xx_info("chip ID is em2840\n"); 1739 em28xx_info("chip ID is em2840\n");
@@ -2158,6 +2185,10 @@ void em28xx_card_setup(struct em28xx *dev)
2158 before probing the i2c bus. */ 2185 before probing the i2c bus. */
2159 em28xx_set_mode(dev, EM28XX_ANALOG_MODE); 2186 em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
2160 break; 2187 break;
2188 case EM2820_BOARD_SILVERCREST_WEBCAM:
2189 /* FIXME: need to document the registers bellow */
2190 em28xx_write_reg(dev, 0x0d, 0x42);
2191 em28xx_write_reg(dev, 0x13, 0x08);
2161 } 2192 }
2162 2193
2163 if (dev->board.has_snapshot_button) 2194 if (dev->board.has_snapshot_button)
@@ -2189,6 +2220,10 @@ void em28xx_card_setup(struct em28xx *dev)
2189 v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap, 2220 v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap,
2190 "tvp5150", "tvp5150", tvp5150_addrs); 2221 "tvp5150", "tvp5150", tvp5150_addrs);
2191 2222
2223 if (dev->board.decoder == EM28XX_MT9V011)
2224 v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap,
2225 "mt9v011", "mt9v011", mt9v011_addrs);
2226
2192 if (dev->board.adecoder == EM28XX_TVAUDIO) 2227 if (dev->board.adecoder == EM28XX_TVAUDIO)
2193 v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, 2228 v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
2194 "tvaudio", "tvaudio", dev->board.tvaudio_addr); 2229 "tvaudio", "tvaudio", dev->board.tvaudio_addr);
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index c8d7ce8fbd36..dda2721ee5b0 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -648,17 +648,29 @@ int em28xx_capture_start(struct em28xx *dev, int start)
648int em28xx_set_outfmt(struct em28xx *dev) 648int 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 outfmt = 0x24;
659 } else {
660 vinmode = 0x10;
661 vinctl = 0x11;
662 }
651 663
652 ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT, 664 ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT,
653 dev->format->reg | 0x20, 0x3f); 665 outfmt | 0x20, 0xff);
654 if (ret < 0) 666 if (ret < 0)
655 return ret; 667 return ret;
656 668
657 ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, 0x10); 669 ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, vinmode);
658 if (ret < 0) 670 if (ret < 0)
659 return ret; 671 return ret;
660 672
661 return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x11); 673 return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctl);
662} 674}
663 675
664static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, 676static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
@@ -695,13 +707,19 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
695{ 707{
696 u8 mode; 708 u8 mode;
697 /* the em2800 scaler only supports scaling down to 50% */ 709 /* the em2800 scaler only supports scaling down to 50% */
698 if (dev->board.is_em2800) 710
711 if (dev->board.is_27xx) {
712 /* FIXME: Don't use the scaler yet */
713 mode = 0;
714 } else if (dev->board.is_em2800) {
699 mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00); 715 mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
700 else { 716 } else {
701 u8 buf[2]; 717 u8 buf[2];
718
702 buf[0] = h; 719 buf[0] = h;
703 buf[1] = h >> 8; 720 buf[1] = h >> 8;
704 em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2); 721 em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
722
705 buf[0] = v; 723 buf[0] = v;
706 buf[1] = v >> 8; 724 buf[1] = v >> 8;
707 em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2); 725 em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
@@ -720,8 +738,11 @@ int em28xx_resolution_set(struct em28xx *dev)
720 height = norm_maxh(dev) >> 1; 738 height = norm_maxh(dev) >> 1;
721 739
722 em28xx_set_outfmt(dev); 740 em28xx_set_outfmt(dev);
741
742
723 em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2); 743 em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
724 em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2); 744 em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2);
745
725 return em28xx_scaler_set(dev, dev->hscale, dev->vscale); 746 return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
726} 747}
727 748
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
365enum em28xx_adecoder { 367enum 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;