V4L/DVB (5899): bttv: Fix Viewcast Osprey 440 support
authorTrent Piepho <xyzzy@speakeasy.org>
Sun, 22 Jul 2007 00:26:40 +0000 (21:26 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Mon, 30 Jul 2007 19:26:30 +0000 (16:26 -0300)
Various gpio and mux settings for the Osprey 440 weren't correct.  Fix them
and provide some documentation about how the gpios work.

The osprey eeprom routine wasn't run for the 440, add it.  It was also crap,
re-written to be better.

Add the Osprey 440 to the Bt878 ALSA driver's whitelist.  Currently the sample
rate is fixed at 32kHz, as the driver doesn't support different rates for
digital input mode, though the card can select the rate from 32, 44.1, or 48
kHz via gpio.

Setting the audio gain via ALSA isn't supported yet; a userspace tool that
programs the X9221 via i2c-dev must be used.

The Bt878 digital audio format isn't programmed correctly for the CS5331A ADC
used, resulting in extremely garbled sound.  That is fixed in a followup
patch.

Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
drivers/media/video/bt8xx/bttv-cards.c
sound/pci/bt87x.c

index 387cb21..f671500 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/pci.h>
 #include <linux/vmalloc.h>
 #include <linux/firmware.h>
+#include <net/checksum.h>
 
 #include <asm/io.h>
 
@@ -45,7 +46,7 @@ static void boot_msp34xx(struct bttv *btv, int pin);
 static void boot_bt832(struct bttv *btv);
 static void hauppauge_eeprom(struct bttv *btv);
 static void avermedia_eeprom(struct bttv *btv);
-static void osprey_eeprom(struct bttv *btv);
+static void osprey_eeprom(struct bttv *btv, const u8 ee[256]);
 static void modtec_eeprom(struct bttv *btv);
 static void init_PXC200(struct bttv *btv);
 static void init_RTV24(struct bttv *btv);
@@ -2843,13 +2844,28 @@ struct tvcard bttv_tvcards[] = {
                .has_remote     = 1,
        },
                /* ---- card 0x8c ---------------------------------- */
+       /* Has four Bt878 chips behind a PCI bridge, each chip has:
+            one external BNC composite input (mux 2)
+            three internal composite inputs (unknown muxes)
+            an 18-bit stereo A/D (CS5331A), which has:
+              one external stereo unblanced (RCA) audio connection
+              one (or 3?) internal stereo balanced (XLR) audio connection
+              input is selected via gpio to a 14052B mux
+                (mask=0x300, unbal=0x000, bal=0x100, ??=0x200,0x300)
+              gain is controlled via an X9221A chip on the I2C bus @0x28
+              sample rate is controlled via gpio to an MK1413S
+                (mask=0x3, 32kHz=0x0, 44.1kHz=0x1, 48kHz=0x2, ??=0x3)
+            There is neither a tuner nor an svideo input. */
        [BTTV_BOARD_OSPREY440]  = {
                .name           = "Osprey 440",
-               .video_inputs   = 1,
-               .audio_inputs   = 1,
+               .video_inputs   = 4,
+               .audio_inputs   = 2, /* this is meaningless */
                .tuner          = UNSET,
-               .svhs           = 1,
-               .muxsel         = { 2 },
+               .svhs           = UNSET,
+               .muxsel         = { 2, 3, 0, 1 }, /* 3,0,1 are guesses */
+               .gpiomask       = 0x303,
+               .gpiomute       = 0x000, /* int + 32kHz */
+               .gpiomux        = { 0, 0, 0x000, 0x100},
                .pll            = PLL_28,
                .tuner_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
@@ -3453,11 +3469,12 @@ void __devinit bttv_init_card2(struct bttv *btv)
        case BTTV_BOARD_OSPREY2xx:
        case BTTV_BOARD_OSPREY2x0_SVID:
        case BTTV_BOARD_OSPREY2x0:
+       case BTTV_BOARD_OSPREY440:
        case BTTV_BOARD_OSPREY500:
        case BTTV_BOARD_OSPREY540:
        case BTTV_BOARD_OSPREY2000:
                bttv_readee(btv,eeprom_data,0xa0);
-               osprey_eeprom(btv);
+               osprey_eeprom(btv, eeprom_data);
                break;
        case BTTV_BOARD_IDS_EAGLE:
                init_ids_eagle(btv);
@@ -3748,106 +3765,119 @@ static int __devinit pvr_boot(struct bttv *btv)
 /* ----------------------------------------------------------------------- */
 /* some osprey specific stuff                                              */
 
-static void __devinit osprey_eeprom(struct bttv *btv)
+static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256])
 {
-       int i = 0;
-       unsigned char *ee = eeprom_data;
-       unsigned long serial = 0;
-
-       if (btv->c.type == 0) {
-              /* this might be an antique... check for MMAC label in eeprom */
-              if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) {
-                      unsigned char checksum = 0;
-                      for (i = 0; i < 21; i++)
-                              checksum += ee[i];
-                      if (checksum != ee[21])
-                              return;
-                      btv->c.type = BTTV_BOARD_OSPREY1x0_848;
-                      for (i = 12; i < 21; i++)
-                              serial *= 10, serial += ee[i] - '0';
-              }
+       int i;
+       u32 serial = 0;
+       int cardid = -1;
+
+       /* This code will nevery actually get called in this case.... */
+       if (btv->c.type == BTTV_BOARD_UNKNOWN) {
+               /* this might be an antique... check for MMAC label in eeprom */
+               if (!strncmp(ee, "MMAC", 4)) {
+                       u8 checksum = 0;
+                       for (i = 0; i < 21; i++)
+                               checksum += ee[i];
+                       if (checksum != ee[21])
+                               return;
+                       cardid = BTTV_BOARD_OSPREY1x0_848;
+                       for (i = 12; i < 21; i++)
+                               serial *= 10, serial += ee[i] - '0';
+               }
        } else {
-              unsigned short type;
-              int offset = 4*16;
-
-              for (; offset < 8*16; offset += 16) {
-                      unsigned short checksum = 0;
-                      /* verify the checksum */
-                      for (i = 0; i < 14; i++)
-                               checksum += ee[i+offset];
-                       checksum = ~checksum;  /* no idea why */
-                       if ((((checksum>>8)&0x0FF) == ee[offset+14]) &&
-                                  ((checksum & 0x0FF) == ee[offset+15])) {
-                              break;
-                      }
-              }
-
-              if (offset >= 8*16)
-                      return;
-
-              /* found a valid descriptor */
-              type = (ee[offset+4]<<8) | (ee[offset+5]);
-
-              switch(type) {
-              /* 848 based */
-              case 0x0004:
-                      btv->c.type = BTTV_BOARD_OSPREY1x0_848;
-                      break;
-              case 0x0005:
-                      btv->c.type = BTTV_BOARD_OSPREY101_848;
-                      break;
-
-              /* 878 based */
-              case 0x0012:
-              case 0x0013:
-                      btv->c.type = BTTV_BOARD_OSPREY1x0;
-                      break;
-              case 0x0014:
-              case 0x0015:
-                      btv->c.type = BTTV_BOARD_OSPREY1x1;
-                      break;
-              case 0x0016:
-              case 0x0017:
-              case 0x0020:
-                      btv->c.type = BTTV_BOARD_OSPREY1x1_SVID;
-                      break;
-              case 0x0018:
-              case 0x0019:
-              case 0x001E:
-              case 0x001F:
-                      btv->c.type = BTTV_BOARD_OSPREY2xx;
-                      break;
-              case 0x001A:
-              case 0x001B:
-                      btv->c.type = BTTV_BOARD_OSPREY2x0_SVID;
-                      break;
-              case 0x0040:
-                      btv->c.type = BTTV_BOARD_OSPREY500;
-                      break;
-              case 0x0050:
-              case 0x0056:
-                      btv->c.type = BTTV_BOARD_OSPREY540;
-                      /* bttv_osprey_540_init(btv); */
-                      break;
-              case 0x0060:
-              case 0x0070:
-              case 0x00A0:
-                      btv->c.type = BTTV_BOARD_OSPREY2x0;
-                      /* enable output on select control lines */
-                      gpio_inout(0xffffff,0x000303);
-                      break;
-              default:
-                      /* unknown...leave generic, but get serial # */
-                      break;
-              }
-              serial =  (ee[offset+6] << 24)
-                      | (ee[offset+7] << 16)
-                      | (ee[offset+8] <<  8)
-                      | (ee[offset+9]);
-       }
-
-       printk(KERN_INFO "bttv%d: osprey eeprom: card=%d name=%s serial=%ld\n",
-             btv->c.nr, btv->c.type, bttv_tvcards[btv->c.type].name,serial);
+               unsigned short type;
+
+               for (i = 4*16; i < 8*16; i += 16) {
+                       u16 checksum = ip_compute_csum(ee + i, 16);
+
+                       if ((checksum&0xff) + (checksum>>8) == 0xff)
+                               break;
+               }
+               if (i >= 8*16)
+                       return;
+               ee += i;
+
+               /* found a valid descriptor */
+               type = be16_to_cpup((u16*)(ee+4));
+
+               switch(type) {
+               /* 848 based */
+               case 0x0004:
+                       cardid = BTTV_BOARD_OSPREY1x0_848;
+                       break;
+               case 0x0005:
+                       cardid = BTTV_BOARD_OSPREY101_848;
+                       break;
+
+               /* 878 based */
+               case 0x0012:
+               case 0x0013:
+                       cardid = BTTV_BOARD_OSPREY1x0;
+                       break;
+               case 0x0014:
+               case 0x0015:
+                       cardid = BTTV_BOARD_OSPREY1x1;
+                       break;
+               case 0x0016:
+               case 0x0017:
+               case 0x0020:
+                       cardid = BTTV_BOARD_OSPREY1x1_SVID;
+                       break;
+               case 0x0018:
+               case 0x0019:
+               case 0x001E:
+               case 0x001F:
+                       cardid = BTTV_BOARD_OSPREY2xx;
+                       break;
+               case 0x001A:
+               case 0x001B:
+                       cardid = BTTV_BOARD_OSPREY2x0_SVID;
+                       break;
+               case 0x0040:
+                       cardid = BTTV_BOARD_OSPREY500;
+                       break;
+               case 0x0050:
+               case 0x0056:
+                       cardid = BTTV_BOARD_OSPREY540;
+                       /* bttv_osprey_540_init(btv); */
+                       break;
+               case 0x0060:
+               case 0x0070:
+               case 0x00A0:
+                       cardid = BTTV_BOARD_OSPREY2x0;
+                       /* enable output on select control lines */
+                       gpio_inout(0xffffff,0x000303);
+                       break;
+               case 0x00D8:
+                       cardid = BTTV_BOARD_OSPREY440;
+                       break;
+               default:
+                       /* unknown...leave generic, but get serial # */
+                       printk(KERN_INFO "bttv%d: "
+                              "osprey eeprom: unknown card type 0x%04x\n",
+                              btv->c.nr, type);
+                       break;
+               }
+               serial = be32_to_cpup((u32*)(ee+6));
+       }
+
+       printk(KERN_INFO "bttv%d: osprey eeprom: card=%d '%s' serial=%u\n",
+              btv->c.nr, cardid,
+              cardid>0 ? bttv_tvcards[cardid].name : "Unknown", serial);
+
+       if (cardid<0 || btv->c.type == cardid)
+               return;
+
+       /* card type isn't set correctly */
+       if (card[btv->c.nr] < bttv_num_tvcards) {
+               printk(KERN_WARNING "bttv%d: osprey eeprom: "
+                      "Not overriding user specified card type\n", btv->c.nr);
+       } else {
+               printk(KERN_INFO "bttv%d: osprey eeprom: "
+                      "Changing card type from %d to %d\n", btv->c.nr,
+                      btv->c.type, cardid);
+               btv->c.type = cardid;
+       }
 }
 
 /* ----------------------------------------------------------------------- */
index 6523ba0..188c7cf 100644 (file)
@@ -781,6 +781,8 @@ static struct pci_device_id snd_bt87x_ids[] = {
        BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, 0x0070, 0x13eb, 32000),
        /* Viewcast Osprey 200 */
        BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff01, 44100),
+       /* Viewcast Osprey 440 (rate is configurable via gpio) */
+       BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0xff07, 32000),
        /* ATI TV-Wonder */
        BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1002, 0x0001, 32000),
        /* Leadtek Winfast tv 2000xp delux */