Merge branch 'for-linus' of git://git.infradead.org/users/eparis/notify
[pandora-kernel.git] / drivers / media / video / em28xx / em28xx-cards.c
index ebd24a2..320f1f6 100644 (file)
@@ -58,8 +58,6 @@ static unsigned int card[]     = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
 module_param_array(card,  int, NULL, 0444);
 MODULE_PARM_DESC(card,     "card type");
 
-#define MT9V011_VERSION                 0x8243
-
 /* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
 static unsigned long em28xx_devused;
 
@@ -159,6 +157,20 @@ static struct em28xx_reg_seq evga_indtube_digital[] = {
        { -1,                   -1,     -1,             -1},
 };
 
+/* Pinnacle Hybrid Pro eb1a:2881 */
+static struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = {
+       {EM28XX_R08_GPIO,       0xfd,   ~EM_GPIO_4,     10},
+       {       -1,             -1,     -1,             -1},
+};
+
+static struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = {
+       {EM28XX_R08_GPIO,       0x6e,   ~EM_GPIO_4,     10},
+       {EM2880_R04_GPO,        0x04,   0xff,          100},/* zl10353 reset */
+       {EM2880_R04_GPO,        0x0c,   0xff,            1},
+       {       -1,             -1,     -1,             -1},
+};
+
+
 /* Callback for the most boards */
 static struct em28xx_reg_seq default_tuner_gpio[] = {
        {EM28XX_R08_GPIO,       EM_GPIO_4,      EM_GPIO_4,      10},
@@ -205,13 +217,15 @@ static struct em28xx_reg_seq silvercrest_reg_seq[] = {
  */
 struct em28xx_board em28xx_boards[] = {
        [EM2750_BOARD_UNKNOWN] = {
-               .name          = "Unknown EM2750/EM2751 webcam grabber",
+               .name          = "EM2710/EM2750/EM2751 webcam grabber",
                .xclk          = EM28XX_XCLK_FREQUENCY_48MHZ,
-               .tuner_type    = TUNER_ABSENT,  /* This is a webcam */
+               .tuner_type    = TUNER_ABSENT,
+               .is_webcam     = 1,
                .input         = { {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = 0,
                        .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = silvercrest_reg_seq,
                } },
        },
        [EM2800_BOARD_UNKNOWN] = {
@@ -233,13 +247,15 @@ struct em28xx_board em28xx_boards[] = {
        [EM2820_BOARD_UNKNOWN] = {
                .name          = "Unknown EM2750/28xx video grabber",
                .tuner_type    = TUNER_ABSENT,
+               .is_webcam     = 1,     /* To enable sensor probe */
        },
        [EM2750_BOARD_DLCW_130] = {
                /* Beijing Huaqi Information Digital Technology Co., Ltd */
                .name          = "Huaqi DLCW-130",
                .valid         = EM28XX_BOARD_NOT_VALIDATED,
                .xclk          = EM28XX_XCLK_FREQUENCY_48MHZ,
-               .tuner_type    = TUNER_ABSENT,  /* This is a webcam */
+               .tuner_type    = TUNER_ABSENT,
+               .is_webcam     = 1,
                .input         = { {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = 0,
@@ -440,7 +456,8 @@ struct em28xx_board em28xx_boards[] = {
        [EM2820_BOARD_VIDEOLOGY_20K14XUSB] = {
                .name         = "Videology 20K14XUSB USB2.0",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .tuner_type   = TUNER_ABSENT,   /* This is a webcam */
+               .tuner_type   = TUNER_ABSENT,
+               .is_webcam    = 1,
                .input        = { {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = 0,
@@ -450,8 +467,7 @@ struct em28xx_board em28xx_boards[] = {
        [EM2820_BOARD_SILVERCREST_WEBCAM] = {
                .name         = "Silvercrest Webcam 1.3mpix",
                .tuner_type   = TUNER_ABSENT,
-               .is_27xx      = 1,
-               .decoder      = EM28XX_MT9V011,
+               .is_webcam    = 1,
                .input        = { {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = 0,
@@ -500,7 +516,8 @@ struct em28xx_board em28xx_boards[] = {
                /* Beijing Huaqi Information Digital Technology Co., Ltd */
                .name         = "NetGMBH Cam",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
-               .tuner_type   = TUNER_ABSENT,   /* This is a webcam */
+               .tuner_type   = TUNER_ABSENT,
+               .is_webcam    = 1,
                .input        = { {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = 0,
@@ -1250,25 +1267,26 @@ struct em28xx_board em28xx_boards[] = {
        },
        [EM2881_BOARD_PINNACLE_HYBRID_PRO] = {
                .name         = "Pinnacle Hybrid Pro",
-               .valid        = EM28XX_BOARD_NOT_VALIDATED,
                .tuner_type   = TUNER_XC2028,
                .tuner_gpio   = default_tuner_gpio,
                .decoder      = EM28XX_TVP5150,
+               .has_dvb      = 1,
+               .dvb_gpio     = pinnacle_hybrid_pro_digital,
                .input        = { {
                        .type     = EM28XX_VMUX_TELEVISION,
                        .vmux     = TVP5150_COMPOSITE0,
                        .amux     = EM28XX_AMUX_VIDEO,
-                       .gpio     = default_analog,
+                       .gpio     = pinnacle_hybrid_pro_analog,
                }, {
                        .type     = EM28XX_VMUX_COMPOSITE1,
                        .vmux     = TVP5150_COMPOSITE1,
                        .amux     = EM28XX_AMUX_LINE_IN,
-                       .gpio     = default_analog,
+                       .gpio     = pinnacle_hybrid_pro_analog,
                }, {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = TVP5150_SVIDEO,
                        .amux     = EM28XX_AMUX_LINE_IN,
-                       .gpio     = default_analog,
+                       .gpio     = pinnacle_hybrid_pro_analog,
                } },
        },
        [EM2882_BOARD_PINNACLE_HYBRID_PRO] = {
@@ -1638,6 +1656,7 @@ static struct em28xx_hash_table em28xx_eeprom_hash[] = {
        {0x966a0441, EM2880_BOARD_KWORLD_DVB_310U, TUNER_XC2028},
        {0x9567eb1a, EM2880_BOARD_EMPIRE_DUAL_TV, TUNER_XC2028},
        {0xcee44a99, EM2882_BOARD_EVGA_INDTUBE, TUNER_XC2028},
+       {0xb8846b20, EM2881_BOARD_PINNACLE_HYBRID_PRO, TUNER_XC2028},
 };
 
 /* I2C devicelist hash table for devices with generic USB IDs */
@@ -1704,6 +1723,32 @@ static inline void em28xx_set_model(struct em28xx *dev)
                                       EM28XX_I2C_FREQ_100_KHZ;
 }
 
+/* FIXME: Should be replaced by a proper mt9m001 driver */
+static int em28xx_initialize_mt9m001(struct em28xx *dev)
+{
+       int i;
+       unsigned char regs[][3] = {
+               { 0x0d, 0x00, 0x01, },
+               { 0x0d, 0x00, 0x00, },
+               { 0x04, 0x05, 0x00, },  /* hres = 1280 */
+               { 0x03, 0x04, 0x00, },  /* vres = 1024 */
+               { 0x20, 0x11, 0x00, },
+               { 0x06, 0x00, 0x10, },
+               { 0x2b, 0x00, 0x24, },
+               { 0x2e, 0x00, 0x24, },
+               { 0x35, 0x00, 0x24, },
+               { 0x2d, 0x00, 0x20, },
+               { 0x2c, 0x00, 0x20, },
+               { 0x09, 0x0a, 0xd4, },
+               { 0x35, 0x00, 0x57, },
+       };
+
+       for (i = 0; i < ARRAY_SIZE(regs); i++)
+               i2c_master_send(&dev->i2c_client, &regs[i][0], 3);
+
+       return 0;
+}
+
 /* HINT method: webcam I2C chips
  *
  * This method work for webcams with Micron sensors
@@ -1716,9 +1761,6 @@ static int em28xx_hint_sensor(struct em28xx *dev)
        __be16 version_be;
        u16 version;
 
-       if (dev->model != EM2820_BOARD_UNKNOWN)
-               return 0;
-
        dev->i2c_client.addr = 0xba >> 1;
        cmd = 0;
        i2c_master_send(&dev->i2c_client, &cmd, 1);
@@ -1729,16 +1771,38 @@ static int em28xx_hint_sensor(struct em28xx *dev)
        version = be16_to_cpu(version_be);
 
        switch (version) {
-       case MT9V011_VERSION:
+       case 0x8243:            /* mt9v011 640x480 1.3 Mpix sensor */
                dev->model = EM2820_BOARD_SILVERCREST_WEBCAM;
                sensor_name = "mt9v011";
+               dev->em28xx_sensor = EM28XX_MT9V011;
+               dev->sensor_xres = 640;
+               dev->sensor_yres = 480;
+               dev->sensor_xtal = 6300000;
+
+               /* probably means GRGB 16 bit bayer */
+               dev->vinmode = 0x0d;
+               dev->vinctl = 0x00;
+
+               break;
+       case 0x8431:
+               dev->model = EM2750_BOARD_UNKNOWN;
+               sensor_name = "mt9m001";
+               dev->em28xx_sensor = EM28XX_MT9M001;
+               em28xx_initialize_mt9m001(dev);
+               dev->sensor_xres = 1280;
+               dev->sensor_yres = 1024;
+
+               /* probably means BGGR 16 bit bayer */
+               dev->vinmode = 0x0c;
+               dev->vinctl = 0x00;
+
                break;
        default:
-               printk("Unknown Sensor 0x%04x\n", be16_to_cpu(version));
+               printk("Unknown Micron Sensor 0x%04x\n", be16_to_cpu(version));
                return -EINVAL;
        }
 
-       em28xx_errdev("Sensor is %s, assuming that webcam is %s\n",
+       em28xx_errdev("Sensor is %s, using model %s entry.\n",
                      sensor_name, em28xx_boards[dev->model].name);
 
        return 0;
@@ -1772,10 +1836,7 @@ void em28xx_pre_card_setup(struct em28xx *dev)
                        em28xx_info("chip ID is em2750\n");
                        break;
                case CHIP_ID_EM2820:
-                       if (dev->board.is_27xx)
-                               em28xx_info("chip is em2710\n");
-                       else
-                               em28xx_info("chip ID is em2820\n");
+                       em28xx_info("chip ID is em2710 or em2820\n");
                        break;
                case CHIP_ID_EM2840:
                        em28xx_info("chip ID is em2840\n");
@@ -1929,6 +1990,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
                ctl->demod = XC3028_FE_ZARLINK456;
                break;
        case EM2880_BOARD_TERRATEC_HYBRID_XS:
+       case EM2881_BOARD_PINNACLE_HYBRID_PRO:
                ctl->demod = XC3028_FE_ZARLINK456;
                break;
        case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
@@ -2225,6 +2287,7 @@ void em28xx_card_setup(struct em28xx *dev)
                   em28xx_set_mode() in em28xx_pre_card_setup() was a no-op,
                   so make the call now so the analog GPIOs are set properly
                   before probing the i2c bus. */
+               em28xx_gpio_set(dev, dev->board.tuner_gpio);
                em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
                break;
        case EM2820_BOARD_SILVERCREST_WEBCAM:
@@ -2262,9 +2325,14 @@ 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->em28xx_sensor == EM28XX_MT9V011) {
+               struct v4l2_subdev *sd;
+
+               sd = v4l2_i2c_new_probed_subdev(&dev->v4l2_dev,
+                        &dev->i2c_adap, "mt9v011", "mt9v011", mt9v011_addrs);
+               v4l2_subdev_call(sd, core, s_config, 0, &dev->sensor_xtal);
+       }
+
 
        if (dev->board.adecoder == EM28XX_TVAUDIO)
                v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
@@ -2410,7 +2478,19 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
                return errCode;
        }
 
-       em28xx_hint_sensor(dev);
+       /*
+        * Default format, used for tvp5150 or saa711x output formats
+        */
+       dev->vinmode = 0x10;
+       dev->vinctl  = 0x11;
+
+       /*
+        * If the device can be a webcam, seek for a sensor.
+        * If sensor is not found, then it isn't a webcam.
+        */
+       if (dev->board.is_webcam)
+               if (em28xx_hint_sensor(dev) < 0)
+                       dev->board.is_webcam = 0;
 
        /* Do board specific init and eeprom reading */
        em28xx_card_setup(dev);