Commit 02e7804b authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab

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: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 6934e6ff
...@@ -66,3 +66,4 @@ ...@@ -66,3 +66,4 @@
68 -> Terratec AV350 (em2860) [0ccd:0084] 68 -> Terratec AV350 (em2860) [0ccd:0084]
69 -> KWorld ATSC 315U HDTV TV Box (em2882) [eb1a:a313] 69 -> KWorld ATSC 315U HDTV TV Box (em2882) [eb1a:a313]
70 -> Evga inDtube (em2882) 70 -> Evga inDtube (em2882)
71 -> Silvercrest Webcam 1.3mpix (em2820/em2840)
...@@ -8,6 +8,8 @@ config VIDEO_EM28XX ...@@ -8,6 +8,8 @@ config VIDEO_EM28XX
select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO
select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO
select VIDEO_MT9V011 if VIDEO_HELPER_CHIPS_AUTO
---help--- ---help---
This is a video4linux driver for Empia 28xx based TV cards. This is a video4linux driver for Empia 28xx based TV cards.
......
...@@ -191,6 +191,13 @@ static struct em28xx_reg_seq terratec_av350_unmute_gpio[] = { ...@@ -191,6 +191,13 @@ static struct em28xx_reg_seq terratec_av350_unmute_gpio[] = {
{EM28XX_R08_GPIO, 0xff, 0xff, 10}, {EM28XX_R08_GPIO, 0xff, 0xff, 10},
{ -1, -1, -1, -1}, { -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 * Board definitions
*/ */
...@@ -438,6 +445,18 @@ struct em28xx_board em28xx_boards[] = { ...@@ -438,6 +445,18 @@ struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_VIDEO, .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] = { [EM2821_BOARD_SUPERCOMP_USB_2] = {
.name = "Supercomp USB 2.0 TV", .name = "Supercomp USB 2.0 TV",
.valid = EM28XX_BOARD_NOT_VALIDATED, .valid = EM28XX_BOARD_NOT_VALIDATED,
...@@ -1639,6 +1658,11 @@ static unsigned short tvp5150_addrs[] = { ...@@ -1639,6 +1658,11 @@ static unsigned short tvp5150_addrs[] = {
I2C_CLIENT_END I2C_CLIENT_END
}; };
static unsigned short mt9v011_addrs[] = {
0xba >> 1,
I2C_CLIENT_END
};
static unsigned short msp3400_addrs[] = { static unsigned short msp3400_addrs[] = {
0x80 >> 1, 0x80 >> 1,
0x88 >> 1, 0x88 >> 1,
...@@ -1706,7 +1730,10 @@ void em28xx_pre_card_setup(struct em28xx *dev) ...@@ -1706,7 +1730,10 @@ void em28xx_pre_card_setup(struct em28xx *dev)
em28xx_info("chip ID is em2750\n"); em28xx_info("chip ID is em2750\n");
break; break;
case CHIP_ID_EM2820: 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; break;
case CHIP_ID_EM2840: case CHIP_ID_EM2840:
em28xx_info("chip ID is em2840\n"); em28xx_info("chip ID is em2840\n");
...@@ -2158,6 +2185,10 @@ void em28xx_card_setup(struct em28xx *dev) ...@@ -2158,6 +2185,10 @@ void em28xx_card_setup(struct em28xx *dev)
before probing the i2c bus. */ before probing the i2c bus. */
em28xx_set_mode(dev, EM28XX_ANALOG_MODE); em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
break; 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) if (dev->board.has_snapshot_button)
...@@ -2189,6 +2220,10 @@ void em28xx_card_setup(struct em28xx *dev) ...@@ -2189,6 +2220,10 @@ void em28xx_card_setup(struct em28xx *dev)
v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap, v4l2_i2c_new_probed_subdev(&dev->v4l2_dev, &dev->i2c_adap,
"tvp5150", "tvp5150", tvp5150_addrs); "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) if (dev->board.adecoder == EM28XX_TVAUDIO)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
"tvaudio", "tvaudio", dev->board.tvaudio_addr); "tvaudio", "tvaudio", dev->board.tvaudio_addr);
......
...@@ -648,17 +648,29 @@ int em28xx_capture_start(struct em28xx *dev, int start) ...@@ -648,17 +648,29 @@ int em28xx_capture_start(struct em28xx *dev, int start)
int em28xx_set_outfmt(struct em28xx *dev) int em28xx_set_outfmt(struct em28xx *dev)
{ {
int ret; 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, ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT,
dev->format->reg | 0x20, 0x3f); outfmt | 0x20, 0xff);
if (ret < 0) 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) if (ret < 0)
return ret; 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, 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) ...@@ -695,13 +707,19 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
{ {
u8 mode; u8 mode;
/* the em2800 scaler only supports scaling down to 50% */ /* 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); mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
else { } else {
u8 buf[2]; u8 buf[2];
buf[0] = h; buf[0] = h;
buf[1] = h >> 8; buf[1] = h >> 8;
em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2); em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
buf[0] = v; buf[0] = v;
buf[1] = v >> 8; buf[1] = v >> 8;
em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2); em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
...@@ -720,8 +738,11 @@ int em28xx_resolution_set(struct em28xx *dev) ...@@ -720,8 +738,11 @@ int em28xx_resolution_set(struct em28xx *dev)
height = norm_maxh(dev) >> 1; height = norm_maxh(dev) >> 1;
em28xx_set_outfmt(dev); em28xx_set_outfmt(dev);
em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2); em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2); em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2);
return em28xx_scaler_set(dev, dev->hscale, dev->vscale); return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
} }
......
...@@ -107,6 +107,7 @@ ...@@ -107,6 +107,7 @@
#define EM2860_BOARD_TERRATEC_AV350 68 #define EM2860_BOARD_TERRATEC_AV350 68
#define EM2882_BOARD_KWORLD_ATSC_315U 69 #define EM2882_BOARD_KWORLD_ATSC_315U 69
#define EM2882_BOARD_EVGA_INDTUBE 70 #define EM2882_BOARD_EVGA_INDTUBE 70
#define EM2820_BOARD_SILVERCREST_WEBCAM 71
/* Limits minimum and default number of buffers */ /* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4 #define EM28XX_MIN_BUF 4
...@@ -360,6 +361,7 @@ enum em28xx_decoder { ...@@ -360,6 +361,7 @@ enum em28xx_decoder {
EM28XX_NODECODER, EM28XX_NODECODER,
EM28XX_TVP5150, EM28XX_TVP5150,
EM28XX_SAA711X, EM28XX_SAA711X,
EM28XX_MT9V011,
}; };
enum em28xx_adecoder { enum em28xx_adecoder {
...@@ -388,6 +390,7 @@ struct em28xx_board { ...@@ -388,6 +390,7 @@ struct em28xx_board {
unsigned int max_range_640_480:1; unsigned int max_range_640_480:1;
unsigned int has_dvb:1; unsigned int has_dvb:1;
unsigned int has_snapshot_button:1; unsigned int has_snapshot_button:1;
unsigned int is_27xx:1;
unsigned int valid:1; unsigned int valid:1;
unsigned char xclk, i2c_speed; unsigned char xclk, i2c_speed;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment