V4L/DVB (12138): em28xx: add support for Silvercrest Webcam
authorMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 29 Jun 2009 14:35:05 +0000 (11:35 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Sun, 5 Jul 2009 17:30:05 +0000 (14:30 -0300)
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>
Documentation/video4linux/CARDLIST.em28xx
drivers/media/video/em28xx/Kconfig
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-core.c
drivers/media/video/em28xx/em28xx.h

index 873630e..014d255 100644 (file)
@@ -66,3 +66,4 @@
  68 -> Terratec AV350                           (em2860)        [0ccd:0084]
  69 -> KWorld ATSC 315U HDTV TV Box             (em2882)        [eb1a:a313]
  70 -> Evga inDtube                             (em2882)
+ 71 -> Silvercrest Webcam 1.3mpix               (em2820/em2840)
index 16a5af3..6524b49 100644 (file)
@@ -8,6 +8,8 @@ config VIDEO_EM28XX
        select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
        select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO
        select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO
+       select VIDEO_MT9V011 if VIDEO_HELPER_CHIPS_AUTO
+
        ---help---
          This is a video4linux driver for Empia 28xx based TV cards.
 
index c43fdb9..bd9b637 100644 (file)
@@ -191,6 +191,13 @@ static struct em28xx_reg_seq terratec_av350_unmute_gpio[] = {
        {EM28XX_R08_GPIO,       0xff,   0xff,           10},
        {       -1,             -1,     -1,             -1},
 };
+
+static struct em28xx_reg_seq silvercrest_reg_seq[] = {
+       {EM28XX_R08_GPIO,       0xff,   0xff,           10},
+       {EM28XX_R08_GPIO,       0x01,   0xf7,           10},
+       {       -1,             -1,     -1,             -1},
+};
+
 /*
  *  Board definitions
  */
@@ -438,6 +445,18 @@ struct em28xx_board em28xx_boards[] = {
                        .amux     = EM28XX_AMUX_VIDEO,
                } },
        },
+       [EM2820_BOARD_SILVERCREST_WEBCAM] = {
+               .name         = "Silvercrest Webcam 1.3mpix",
+               .tuner_type   = TUNER_ABSENT,
+               .is_27xx      = 1,
+               .decoder      = EM28XX_MT9V011,
+               .input        = { {
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = 0,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = silvercrest_reg_seq,
+               } },
+       },
        [EM2821_BOARD_SUPERCOMP_USB_2] = {
                .name         = "Supercomp USB 2.0 TV",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
@@ -1639,6 +1658,11 @@ static unsigned short tvp5150_addrs[] = {
        I2C_CLIENT_END
 };
 
+static unsigned short mt9v011_addrs[] = {
+       0xba >> 1,
+       I2C_CLIENT_END
+};
+
 static unsigned short msp3400_addrs[] = {
        0x80 >> 1,
        0x88 >> 1,
@@ -1706,7 +1730,10 @@ void em28xx_pre_card_setup(struct em28xx *dev)
                        em28xx_info("chip ID is em2750\n");
                        break;
                case CHIP_ID_EM2820:
-                       em28xx_info("chip ID is em2820\n");
+                       if (dev->board.is_27xx)
+                               em28xx_info("chip is em2710\n");
+                       else
+                               em28xx_info("chip ID is em2820\n");
                        break;
                case CHIP_ID_EM2840:
                        em28xx_info("chip ID is em2840\n");
@@ -2158,6 +2185,10 @@ void em28xx_card_setup(struct em28xx *dev)
                   before probing the i2c bus. */
                em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
                break;
+       case EM2820_BOARD_SILVERCREST_WEBCAM:
+               /* FIXME: need to document the registers bellow */
+               em28xx_write_reg(dev, 0x0d, 0x42);
+               em28xx_write_reg(dev, 0x13, 0x08);
        }
 
        if (dev->board.has_snapshot_button)
@@ -2189,6 +2220,10 @@ void em28xx_card_setup(struct em28xx *dev)
                v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap,
                        "tvp5150", "tvp5150", tvp5150_addrs);
 
+       if (dev->board.decoder == EM28XX_MT9V011)
+               v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+                       "mt9v011", "mt9v011", mt9v011_addrs);
+
        if (dev->board.adecoder == EM28XX_TVAUDIO)
                v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
                        "tvaudio", "tvaudio", dev->board.tvaudio_addr);
index c8d7ce8..dda2721 100644 (file)
@@ -648,17 +648,29 @@ int em28xx_capture_start(struct em28xx *dev, int start)
 int em28xx_set_outfmt(struct em28xx *dev)
 {
        int ret;
+       int vinmode, vinctl, outfmt;
+
+       outfmt  = dev->format->reg;
+
+       if (dev->board.is_27xx) {
+               vinmode = 0x0d;
+               vinctl  = 0x00;
+               outfmt  = 0x24;
+       } else {
+               vinmode = 0x10;
+               vinctl  = 0x11;
+       }
 
        ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT,
-                                   dev->format->reg | 0x20, 0x3f);
+                               outfmt | 0x20, 0xff);
        if (ret < 0)
-               return ret;
+                       return ret;
 
-       ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, 0x10);
+       ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, vinmode);
        if (ret < 0)
                return ret;
 
-       return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x11);
+       return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctl);
 }
 
 static 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)
 {
        u8 mode;
        /* the em2800 scaler only supports scaling down to 50% */
-       if (dev->board.is_em2800)
+
+       if (dev->board.is_27xx) {
+               /* FIXME: Don't use the scaler yet */
+               mode = 0;
+       } else if (dev->board.is_em2800) {
                mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
-       else {
+       else {
                u8 buf[2];
+
                buf[0] = h;
                buf[1] = h >> 8;
                em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
+
                buf[0] = v;
                buf[1] = v >> 8;
                em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
@@ -720,8 +738,11 @@ int em28xx_resolution_set(struct em28xx *dev)
        height = norm_maxh(dev) >> 1;
 
        em28xx_set_outfmt(dev);
+
+
        em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
        em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2);
+
        return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
 }
 
index 813ce45..d90fef4 100644 (file)
 #define EM2860_BOARD_TERRATEC_AV350              68
 #define EM2882_BOARD_KWORLD_ATSC_315U            69
 #define EM2882_BOARD_EVGA_INDTUBE                70
+#define EM2820_BOARD_SILVERCREST_WEBCAM           71
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
@@ -360,6 +361,7 @@ enum em28xx_decoder {
        EM28XX_NODECODER,
        EM28XX_TVP5150,
        EM28XX_SAA711X,
+       EM28XX_MT9V011,
 };
 
 enum em28xx_adecoder {
@@ -388,6 +390,7 @@ struct em28xx_board {
        unsigned int max_range_640_480:1;
        unsigned int has_dvb:1;
        unsigned int has_snapshot_button:1;
+       unsigned int is_27xx:1;
        unsigned int valid:1;
 
        unsigned char xclk, i2c_speed;