aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/solo6x10
diff options
context:
space:
mode:
authorBen Collins <bcollins@bluecherry.net>2010-06-22 22:32:01 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-06-23 15:20:20 -0700
commitee6351f56aba7121f83acc8d1130d5066e5a7d48 (patch)
treea4a796caa7c83892b397fbbcd475a041db0d87e9 /drivers/staging/solo6x10
parent6227157f0cceb092d3e9c6d16ac33f2539a10400 (diff)
downloadkernel_samsung_smdk4412-ee6351f56aba7121f83acc8d1130d5066e5a7d48.zip
kernel_samsung_smdk4412-ee6351f56aba7121f83acc8d1130d5066e5a7d48.tar.gz
kernel_samsung_smdk4412-ee6351f56aba7121f83acc8d1130d5066e5a7d48.tar.bz2
Staging: solo6x10: Support for tw2865 in cascade/full modes
Finally got ahold of a card with a tw2865 video/audio multiplexer and the spec sheet to go along with it. Signed-off-by: Ben Collins <bcollins@bluecherry.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/solo6x10')
-rw-r--r--drivers/staging/solo6x10/solo6010-tw28.c199
-rw-r--r--drivers/staging/solo6x10/solo6010.h2
2 files changed, 173 insertions, 28 deletions
diff --git a/drivers/staging/solo6x10/solo6010-tw28.c b/drivers/staging/solo6x10/solo6010-tw28.c
index b4446b9..0159c83 100644
--- a/drivers/staging/solo6x10/solo6010-tw28.c
+++ b/drivers/staging/solo6x10/solo6010-tw28.c
@@ -69,6 +69,76 @@ static u8 tbl_tw2864_template[] = {
0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00,
};
+static 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
+ 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, // 0x20
+ 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0xf0, 0x70, 0x48, 0x80, 0x80, 0x00, 0x02, // 0x30
+ 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x00, 0x90, 0x68, 0x00, 0x38, 0x80, 0x80, // 0x40
+ 0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
+ 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, // 0x70
+ 0xE9, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
+ 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, // 0x80
+ 0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
+ 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, // 0x90
+ 0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
+ 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1B, 0x1A, // 0xa0
+ 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
+ 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, // 0xb0
+ 0xFF, 0xE7, 0xE9, 0xE9, 0xEB, 0xFF, 0xD6, 0xD8,
+ 0xD8, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xc0
+ 0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
+ 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, // 0xd0
+ 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
+ 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, // 0xe0
+ 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
+ 0x83, 0xB5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, // 0xf0
+ 0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
+};
+
+static 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
+ 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, // 0x20
+ 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
+ 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, // 0x30
+ 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
+ 0x00, 0x94, 0x90, 0x48, 0x00, 0x38, 0x7F, 0x80, // 0x40
+ 0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
+ 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, // 0x70
+ 0xEA, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
+ 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, // 0x80
+ 0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
+ 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, // 0x90
+ 0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
+ 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1A, 0x1A, // 0xa0
+ 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
+ 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, // 0xb0
+ 0xFF, 0xE7, 0xE9, 0xE9, 0xE9, 0xFF, 0xD7, 0xD8,
+ 0xD9, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xc0
+ 0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
+ 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, // 0xd0
+ 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
+ 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, // 0xe0
+ 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
+ 0x83, 0xB5, 0x09, 0x00, 0xA0, 0x00, 0x01, 0x20, // 0xf0
+ 0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
+};
+
#define is_tw286x(__solo, __id) (!(__solo->tw2815 & (1 << __id)))
static u8 tw_readbyte(struct solo6010_dev *solo_dev, int chip_id, u8 tw6x_off,
@@ -111,38 +181,109 @@ static void tw_write_and_verify(struct solo6010_dev *solo_dev, u8 addr, u8 off,
msleep_interruptible(1);
}
- printk("solo6010/tw28: Error writing register: %02x->%02x [%02x]\n",
- addr, off, val);
+// printk("solo6010/tw28: Error writing register: %02x->%02x [%02x]\n",
+// addr, off, val);
}
-static int tw2864_setup(struct solo6010_dev *solo_dev, u8 dev_addr)
+static int tw2865_setup(struct solo6010_dev *solo_dev, u8 dev_addr)
{
- u8 tbl_tw2864_common[256];
+ u8 tbl_tw2865_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_tw2865_common, tbl_tw2865_pal_template,
+ sizeof(tbl_tw2865_common));
+ else
+ memcpy(tbl_tw2865_common, tbl_tw2865_ntsc_template,
+ sizeof(tbl_tw2865_common));
- /* IRQ Mode */
+ /* ALINK Mode */
if (solo_dev->nr_chans == 4) {
- tbl_tw2864_common[0xd2] = 0x01;
- tbl_tw2864_common[0xcf] = 0x00;
+ tbl_tw2865_common[0xd2] = 0x01;
+ tbl_tw2865_common[0xcf] = 0x00;
} else if (solo_dev->nr_chans == 8) {
- tbl_tw2864_common[0xd2] = 0x02;
- if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
- tbl_tw2864_common[0xcf] = 0x43;
- else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
- tbl_tw2864_common[0xcf] = 0x40;
+ tbl_tw2865_common[0xd2] = 0x02;
+ if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+ tbl_tw2865_common[0xcf] = 0x80;
} else if (solo_dev->nr_chans == 16) {
- tbl_tw2864_common[0xd2] = 0x03;
- if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
- tbl_tw2864_common[0xcf] = 0x43;
- else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
- tbl_tw2864_common[0xcf] = 0x43;
+ tbl_tw2865_common[0xd2] = 0x03;
+ if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+ tbl_tw2865_common[0xcf] = 0x83;
else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
- tbl_tw2864_common[0xcf] = 0x43;
+ tbl_tw2865_common[0xcf] = 0x83;
else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
- tbl_tw2864_common[0xcf] = 0x40;
+ tbl_tw2865_common[0xcf] = 0x80;
+ }
+
+ 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)
+ continue;
+ if (i == 0xfd)
+ continue;
+
+ tw_write_and_verify(solo_dev, dev_addr, i,
+ tbl_tw2865_common[i]);
+ }
+
+ return 0;
+}
+
+static int tw2864_setup(struct solo6010_dev *solo_dev, u8 dev_addr)
+{
+ u8 tbl_tw2864_common[sizeof(tbl_tw2864_template)];
+ int i;
+
+ memcpy(tbl_tw2864_common, tbl_tw2864_template,
+ sizeof(tbl_tw2864_common));
+
+ if (solo_dev->tw2865 == 0) {
+ /* IRQ Mode */
+ if (solo_dev->nr_chans == 4) {
+ tbl_tw2864_common[0xd2] = 0x01;
+ tbl_tw2864_common[0xcf] = 0x00;
+ } else if (solo_dev->nr_chans == 8) {
+ tbl_tw2864_common[0xd2] = 0x02;
+ if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
+ tbl_tw2864_common[0xcf] = 0x43;
+ else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+ tbl_tw2864_common[0xcf] = 0x40;
+ } else if (solo_dev->nr_chans == 16) {
+ tbl_tw2864_common[0xd2] = 0x03;
+ if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
+ tbl_tw2864_common[0xcf] = 0x43;
+ else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+ tbl_tw2864_common[0xcf] = 0x43;
+ else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
+ tbl_tw2864_common[0xcf] = 0x43;
+ else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
+ tbl_tw2864_common[0xcf] = 0x40;
+ }
+ } else {
+ /* ALINK Mode. Assumes that the first tw28xx is a
+ * 2865 and these are in cascade. */
+ for (i = 0; i <= 4; i++)
+ tbl_tw2864_common[0x08 | i << 4] = 0x12;
+
+ if (solo_dev->nr_chans == 8) {
+ tbl_tw2864_common[0xd2] = 0x02;
+ if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+ tbl_tw2864_common[0xcf] = 0x80;
+ } else if (solo_dev->nr_chans == 16) {
+ tbl_tw2864_common[0xd2] = 0x03;
+ if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
+ tbl_tw2864_common[0xcf] = 0x83;
+ else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
+ tbl_tw2864_common[0xcf] = 0x83;
+ else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
+ tbl_tw2864_common[0xcf] = 0x80;
+ }
}
/* NTSC or PAL */
@@ -170,8 +311,8 @@ static int tw2864_setup(struct solo6010_dev *solo_dev, u8 dev_addr)
if (i == 0x74 || i == 0x77 || i == 0x78 ||
i == 0x79 || i == 0x7a)
continue;
- if (i == 0xfd)
- continue;
+ if (i == 0xfd)
+ continue;
tw_write_and_verify(solo_dev, dev_addr, i,
tbl_tw2864_common[i]);
@@ -411,8 +552,8 @@ int solo_tw28_init(struct solo6010_dev *solo_dev)
switch (value >> 3) {
case 0x18:
- printk("solo6010: 2865 support not enabled\n");
- return -EINVAL;
+ solo_dev->tw2865 |= 1 << i;
+ solo_dev->tw28_cnt++;
break;
case 0x0c:
solo_dev->tw2864 |= 1 << i;
@@ -434,7 +575,9 @@ int solo_tw28_init(struct solo6010_dev *solo_dev)
saa7128_setup(solo_dev);
for (i = 0; i < solo_dev->tw28_cnt; i++) {
- if ((solo_dev->tw2864 & (1 << i)))
+ if ((solo_dev->tw2865 & (1 << i)))
+ tw2865_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
+ else if ((solo_dev->tw2864 & (1 << i)))
tw2864_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
else
tw2815_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
@@ -443,6 +586,8 @@ int solo_tw28_init(struct solo6010_dev *solo_dev)
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)
@@ -577,7 +722,7 @@ int tw28_get_ctrl_val(struct solo6010_dev *solo_dev, u32 ctrl, u8 ch,
case V4L2_CID_SHARPNESS:
/* Only 286x has sharpness */
if (is_tw286x(solo_dev, chip_num)) {
- rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
+ rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
TW_CHIP_OFFSET_ADDR(chip_num),
TW286x_SHARPNESS(chip_num));
*val = rval & 0x0f;
diff --git a/drivers/staging/solo6x10/solo6010.h b/drivers/staging/solo6x10/solo6010.h
index 1c913d5..984b19e 100644
--- a/drivers/staging/solo6x10/solo6010.h
+++ b/drivers/staging/solo6x10/solo6010.h
@@ -178,7 +178,7 @@ struct solo6010_dev {
spinlock_t reg_io_lock;
/* tw28xx accounting */
- u8 tw2864, tw2815;
+ u8 tw2865, tw2864, tw2815;
u8 tw28_cnt;
/* i2c related items */