From ee6351f56aba7121f83acc8d1130d5066e5a7d48 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Tue, 22 Jun 2010 22:32:01 -0400 Subject: [PATCH 183/524] 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 Signed-off-by: Greg Kroah-Hartman --- drivers/staging/solo6x10/solo6010-tw28.c | 199 ++++++++++++++++++++++++++---- drivers/staging/solo6x10/solo6010.h | 2 +- 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 */ -- 1.7.1