[media] solo6x10: sync to latest code from Bluecherry's git repo
[deliverable/linux.git] / drivers / staging / media / solo6x10 / tw28.c
index db56b42c56c6276063ebdd05885f1d85651f252b..365ab10128816fb913ae304ee542c2517b4d96fc 100644 (file)
@@ -1,6 +1,11 @@
 /*
- * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
- * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
+ * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
+ *
+ * Original author:
+ * Ben Collins <bcollins@ubuntu.com>
+ *
+ * Additional work by:
+ * John Brooks <john.brooks@bluecherry.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  */
 
 #include <linux/kernel.h>
+#include <linux/delay.h>
+
 #include "solo6x10.h"
 #include "tw28.h"
 
-/* XXX: Some of these values are masked into an 8-bit regs, and shifted
- * around for other 8-bit regs. What are the magic bits in these values? */
-#define DEFAULT_HDELAY_NTSC            (32 - 4)
+#define DEFAULT_HDELAY_NTSC            (32 - 8)
 #define DEFAULT_HACTIVE_NTSC           (720 + 16)
 #define DEFAULT_VDELAY_NTSC            (7 - 2)
 #define DEFAULT_VACTIVE_NTSC           (240 + 4)
 #define DEFAULT_VDELAY_PAL             (6)
 #define DEFAULT_VACTIVE_PAL            (312-DEFAULT_VDELAY_PAL)
 
-static u8 tbl_tw2864_template[] = {
-       0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x00 */
-       0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
-       0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x10 */
-       0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
-       0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x20 */
-       0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
-       0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x30 */
-       0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+
+static const u8 tbl_tw2864_ntsc_template[] = {
+       0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */
+       0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+       0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */
+       0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+       0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x20 */
+       0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+       0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x30 */
+       0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
@@ -61,14 +67,49 @@ static u8 tbl_tw2864_template[] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
        0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00,
        0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */
-       0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
-       0x10, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
+       0x64, 0xa8, 0xec, 0xc1, 0x0f, 0x11, 0x11, 0x81,
+       0x00, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
        0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
        0x83, 0xb5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */
        0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00,
 };
 
-static u8 tbl_tw2865_ntsc_template[] = {
+static const u8 tbl_tw2864_pal_template[] = {
+       0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */
+       0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f,
+       0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */
+       0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f,
+       0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x20 */
+       0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f,
+       0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x30 */
+       0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00,
+       0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
+       0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00,
+       0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, /* 0x90 */
+       0x00, 0x28, 0x44, 0x44, 0xa0, 0x90, 0x5a, 0x01,
+       0x0a, 0x0a, 0x0a, 0x0a, 0x1a, 0x1a, 0x1a, 0x1a, /* 0xa0 */
+       0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44,
+       0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, /* 0xb0 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
+       0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00,
+       0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */
+       0x64, 0xa8, 0xec, 0xc1, 0x0f, 0x11, 0x11, 0x81,
+       0x00, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
+       0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
+       0x83, 0xb5, 0x09, 0x00, 0xa0, 0x00, 0x01, 0x20, /* 0xf0 */
+       0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00,
+};
+
+static const u8 tbl_tw2865_ntsc_template[] = {
        0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */
        0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
        0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */
@@ -103,7 +144,7 @@ static u8 tbl_tw2865_ntsc_template[] = {
        0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
 };
 
-static u8 tbl_tw2865_pal_template[] = {
+static const u8 tbl_tw2865_pal_template[] = {
        0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */
        0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
        0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */
@@ -180,8 +221,8 @@ static void tw_write_and_verify(struct solo_dev *solo_dev, u8 addr, u8 off,
                msleep_interruptible(1);
        }
 
-/*     printk("solo6x10/tw28: Error writing register: %02x->%02x [%02x]\n",
-               addr, off, val); */
+/*     printk("solo6x10/tw28: Error writing register: %02x->%02x [%02x]\n", */
+/*             addr, off, val); */
 }
 
 static int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr)
@@ -216,16 +257,17 @@ static int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr)
 
        for (i = 0; i < 0xff; i++) {
                /* Skip read only registers */
-               if (i >= 0xb8 && i <= 0xc1)
-                       continue;
-               if ((i & ~0x30) == 0x00 ||
-                   (i & ~0x30) == 0x0c ||
-                   (i & ~0x30) == 0x0d)
-                       continue;
-               if (i >= 0xc4 && i <= 0xc7)
+               switch (i) {
+               case 0xb8 ... 0xc1:
+               case 0xc4 ... 0xc7:
+               case 0xfd:
                        continue;
-               if (i == 0xfd)
+               }
+               switch (i & ~0x30) {
+               case 0x00:
+               case 0x0c ... 0x0d:
                        continue;
+               }
 
                tw_write_and_verify(solo_dev, dev_addr, i,
                                    tbl_tw2865_common[i]);
@@ -236,11 +278,15 @@ static int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr)
 
 static int tw2864_setup(struct solo_dev *solo_dev, u8 dev_addr)
 {
-       u8 tbl_tw2864_common[sizeof(tbl_tw2864_template)];
+       u8 tbl_tw2864_common[256];
        int i;
 
-       memcpy(tbl_tw2864_common, tbl_tw2864_template,
-              sizeof(tbl_tw2864_common));
+       if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL)
+               memcpy(tbl_tw2864_common, tbl_tw2864_pal_template,
+                      sizeof(tbl_tw2864_common));
+       else
+               memcpy(tbl_tw2864_common, tbl_tw2864_ntsc_template,
+                      sizeof(tbl_tw2864_common));
 
        if (solo_dev->tw2865 == 0) {
                /* IRQ Mode */
@@ -285,33 +331,19 @@ static int tw2864_setup(struct solo_dev *solo_dev, u8 dev_addr)
                }
        }
 
-       /* NTSC or PAL */
-       if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL) {
-               for (i = 0; i < 4; i++) {
-                       tbl_tw2864_common[0x07 | (i << 4)] |= 0x10;
-                       tbl_tw2864_common[0x08 | (i << 4)] |= 0x06;
-                       tbl_tw2864_common[0x0a | (i << 4)] |= 0x08;
-                       tbl_tw2864_common[0x0b | (i << 4)] |= 0x13;
-                       tbl_tw2864_common[0x0e | (i << 4)] |= 0x01;
-               }
-               tbl_tw2864_common[0x9d] = 0x90;
-               tbl_tw2864_common[0xf3] = 0x00;
-               tbl_tw2864_common[0xf4] = 0xa0;
-       }
-
        for (i = 0; i < 0xff; i++) {
                /* Skip read only registers */
-               if (i >= 0xb8 && i <= 0xc1)
-                       continue;
-               if ((i & ~0x30) == 0x00 ||
-                   (i & ~0x30) == 0x0c ||
-                   (i & ~0x30) == 0x0d)
-                       continue;
-               if (i == 0x74 || i == 0x77 || i == 0x78 ||
-                   i == 0x79 || i == 0x7a)
+               switch (i) {
+               case 0xb8 ... 0xc1:
+               case 0xfd:
                        continue;
-               if (i == 0xfd)
+               }
+               switch (i & ~0x30) {
+               case 0x00:
+               case 0x0c:
+               case 0x0d:
                        continue;
+               }
 
                tw_write_and_verify(solo_dev, dev_addr, i,
                                    tbl_tw2864_common[i]);
@@ -544,8 +576,8 @@ int solo_tw28_init(struct solo_dev *solo_dev)
        int i;
        u8 value;
 
-       /* Detect techwell chip type */
-       for (i = 0; i < TW_NUM_CHIP; i++) {
+       /* Detect techwell chip type(s) */
+       for (i = 0; i < solo_dev->nr_chans / 4; i++) {
                value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
                                          TW_CHIP_OFFSET_ADDR(i), 0xFF);
 
@@ -560,7 +592,8 @@ int solo_tw28_init(struct solo_dev *solo_dev)
                        break;
                default:
                        value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
-                                                 TW_CHIP_OFFSET_ADDR(i), 0x59);
+                                                 TW_CHIP_OFFSET_ADDR(i),
+                                                 0x59);
                        if ((value >> 3) == 0x04) {
                                solo_dev->tw2815 |= 1 << i;
                                solo_dev->tw28_cnt++;
@@ -568,8 +601,11 @@ int solo_tw28_init(struct solo_dev *solo_dev)
                }
        }
 
-       if (!solo_dev->tw28_cnt)
+       if (solo_dev->tw28_cnt != (solo_dev->nr_chans >> 2)) {
+               dev_err(&solo_dev->pdev->dev,
+                       "Could not initialize any techwell chips\n");
                return -EINVAL;
+       }
 
        saa7128_setup(solo_dev);
 
@@ -582,17 +618,6 @@ int solo_tw28_init(struct solo_dev *solo_dev)
                        tw2815_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
        }
 
-       dev_info(&solo_dev->pdev->dev, "Initialized %d tw28xx chip%s:",
-                solo_dev->tw28_cnt, solo_dev->tw28_cnt == 1 ? "" : "s");
-
-       if (solo_dev->tw2865)
-               printk(" tw2865[%d]", hweight32(solo_dev->tw2865));
-       if (solo_dev->tw2864)
-               printk(" tw2864[%d]", hweight32(solo_dev->tw2864));
-       if (solo_dev->tw2815)
-               printk(" tw2815[%d]", hweight32(solo_dev->tw2815));
-       printk("\n");
-
        return 0;
 }
 
@@ -610,7 +635,7 @@ int tw28_get_video_status(struct solo_dev *solo_dev, u8 ch)
        chip_num = ch / 4;
        ch %= 4;
 
-       val = tw_readbyte(solo_dev, chip_num, TW286X_AV_STAT_ADDR,
+       val = tw_readbyte(solo_dev, chip_num, TW286x_AV_STAT_ADDR,
                          TW_AV_STAT_ADDR) & 0x0f;
 
        return val & (1 << ch) ? 1 : 0;
@@ -626,7 +651,7 @@ u16 tw28_get_audio_status(struct solo_dev *solo_dev)
        int i;
 
        for (i = 0; i < solo_dev->tw28_cnt; i++) {
-               val = (tw_readbyte(solo_dev, i, TW286X_AV_STAT_ADDR,
+               val = (tw_readbyte(solo_dev, i, TW286x_AV_STAT_ADDR,
                                   TW_AV_STAT_ADDR) & 0xf0) >> 4;
                status |= val << (i * 4);
        }
@@ -635,7 +660,8 @@ u16 tw28_get_audio_status(struct solo_dev *solo_dev)
 }
 #endif
 
-int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val)
+int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch,
+                     s32 val)
 {
        char sval;
        u8 chip_num;
@@ -676,6 +702,7 @@ int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val)
                break;
 
        case V4L2_CID_SATURATION:
+               /* 286x chips have a U and V component for saturation */
                if (is_tw286x(solo_dev, chip_num)) {
                        solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
                                           TW_CHIP_OFFSET_ADDR(chip_num),
This page took 0.041182 seconds and 5 git commands to generate.