0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/kernel.h>
0013 #include <linux/delay.h>
0014
0015 #include "solo6x10.h"
0016 #include "solo6x10-tw28.h"
0017
0018 #define DEFAULT_HDELAY_NTSC (32 - 8)
0019 #define DEFAULT_HACTIVE_NTSC (720 + 16)
0020 #define DEFAULT_VDELAY_NTSC (7 - 2)
0021 #define DEFAULT_VACTIVE_NTSC (240 + 4)
0022
0023 #define DEFAULT_HDELAY_PAL (32 + 4)
0024 #define DEFAULT_HACTIVE_PAL (864-DEFAULT_HDELAY_PAL)
0025 #define DEFAULT_VDELAY_PAL (6)
0026 #define DEFAULT_VACTIVE_PAL (312-DEFAULT_VDELAY_PAL)
0027
0028
0029 static const u8 tbl_tw2864_ntsc_template[] = {
0030 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02,
0031 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f,
0032 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02,
0033 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f,
0034 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02,
0035 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f,
0036 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02,
0037 0x12, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x00, 0x7f,
0038 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0039 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0040 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0041 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0042 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0043 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0044 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0045 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00,
0046 0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50,
0047 0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00,
0048 0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05,
0049 0x00, 0x28, 0x44, 0x44, 0xa0, 0x88, 0x5a, 0x01,
0050 0x08, 0x08, 0x08, 0x08, 0x1a, 0x1a, 0x1a, 0x1a,
0051 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44,
0052 0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef,
0053 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0054 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0055 0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00,
0056 0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20,
0057 0x64, 0xa8, 0xec, 0xc1, 0x0f, 0x11, 0x11, 0x81,
0058 0x00, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00,
0059 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
0060 0x83, 0xb5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20,
0061 0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00,
0062 };
0063
0064 static const u8 tbl_tw2864_pal_template[] = {
0065 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12,
0066 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f,
0067 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12,
0068 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f,
0069 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12,
0070 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f,
0071 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12,
0072 0x18, 0xf5, 0x0c, 0xd0, 0x00, 0x00, 0x01, 0x7f,
0073 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0074 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0075 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0076 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0077 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0078 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0079 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0080 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00,
0081 0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50,
0082 0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00,
0083 0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05,
0084 0x00, 0x28, 0x44, 0x44, 0xa0, 0x90, 0x5a, 0x01,
0085 0x0a, 0x0a, 0x0a, 0x0a, 0x1a, 0x1a, 0x1a, 0x1a,
0086 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44,
0087 0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef,
0088 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0089 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0090 0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00,
0091 0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20,
0092 0x64, 0xa8, 0xec, 0xc1, 0x0f, 0x11, 0x11, 0x81,
0093 0x00, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00,
0094 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
0095 0x83, 0xb5, 0x09, 0x00, 0xa0, 0x00, 0x01, 0x20,
0096 0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00,
0097 };
0098
0099 static const u8 tbl_tw2865_ntsc_template[] = {
0100 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02,
0101 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
0102 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02,
0103 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
0104 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02,
0105 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
0106 0x00, 0xf0, 0x70, 0x48, 0x80, 0x80, 0x00, 0x02,
0107 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
0108 0x00, 0x00, 0x90, 0x68, 0x00, 0x38, 0x80, 0x80,
0109 0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
0110 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0111 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0112 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0113 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
0114 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03,
0115 0xE9, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
0116 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50,
0117 0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
0118 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05,
0119 0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
0120 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1B, 0x1A,
0121 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
0122 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF,
0123 0xFF, 0xE7, 0xE9, 0xE9, 0xEB, 0xFF, 0xD6, 0xD8,
0124 0xD8, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0125 0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
0126 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31,
0127 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
0128 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00,
0129 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
0130 0x83, 0xB5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20,
0131 0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
0132 };
0133
0134 static const u8 tbl_tw2865_pal_template[] = {
0135 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12,
0136 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
0137 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12,
0138 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
0139 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12,
0140 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
0141 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12,
0142 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
0143 0x00, 0x94, 0x90, 0x48, 0x00, 0x38, 0x7F, 0x80,
0144 0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
0145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0146 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0147 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
0149 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03,
0150 0xEA, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
0151 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50,
0152 0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
0153 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05,
0154 0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
0155 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1A, 0x1A,
0156 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
0157 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF,
0158 0xFF, 0xE7, 0xE9, 0xE9, 0xE9, 0xFF, 0xD7, 0xD8,
0159 0xD9, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0160 0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
0161 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31,
0162 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
0163 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00,
0164 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
0165 0x83, 0xB5, 0x09, 0x00, 0xA0, 0x00, 0x01, 0x20,
0166 0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
0167 };
0168
0169 #define is_tw286x(__solo, __id) (!(__solo->tw2815 & (1 << __id)))
0170
0171 static u8 tw_readbyte(struct solo_dev *solo_dev, int chip_id, u8 tw6x_off,
0172 u8 tw_off)
0173 {
0174 if (is_tw286x(solo_dev, chip_id))
0175 return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
0176 TW_CHIP_OFFSET_ADDR(chip_id),
0177 tw6x_off);
0178 else
0179 return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
0180 TW_CHIP_OFFSET_ADDR(chip_id),
0181 tw_off);
0182 }
0183
0184 static void tw_writebyte(struct solo_dev *solo_dev, int chip_id,
0185 u8 tw6x_off, u8 tw_off, u8 val)
0186 {
0187 if (is_tw286x(solo_dev, chip_id))
0188 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
0189 TW_CHIP_OFFSET_ADDR(chip_id),
0190 tw6x_off, val);
0191 else
0192 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
0193 TW_CHIP_OFFSET_ADDR(chip_id),
0194 tw_off, val);
0195 }
0196
0197 static void tw_write_and_verify(struct solo_dev *solo_dev, u8 addr, u8 off,
0198 u8 val)
0199 {
0200 int i;
0201
0202 for (i = 0; i < 5; i++) {
0203 u8 rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, addr, off);
0204
0205 if (rval == val)
0206 return;
0207
0208 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, addr, off, val);
0209 msleep_interruptible(1);
0210 }
0211
0212
0213
0214 }
0215
0216 static int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr)
0217 {
0218 u8 tbl_tw2865_common[256];
0219 int i;
0220
0221 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL)
0222 memcpy(tbl_tw2865_common, tbl_tw2865_pal_template,
0223 sizeof(tbl_tw2865_common));
0224 else
0225 memcpy(tbl_tw2865_common, tbl_tw2865_ntsc_template,
0226 sizeof(tbl_tw2865_common));
0227
0228
0229 if (solo_dev->nr_chans == 4) {
0230 tbl_tw2865_common[0xd2] = 0x01;
0231 tbl_tw2865_common[0xcf] = 0x00;
0232 } else if (solo_dev->nr_chans == 8) {
0233 tbl_tw2865_common[0xd2] = 0x02;
0234 if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
0235 tbl_tw2865_common[0xcf] = 0x80;
0236 } else if (solo_dev->nr_chans == 16) {
0237 tbl_tw2865_common[0xd2] = 0x03;
0238 if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
0239 tbl_tw2865_common[0xcf] = 0x83;
0240 else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
0241 tbl_tw2865_common[0xcf] = 0x83;
0242 else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
0243 tbl_tw2865_common[0xcf] = 0x80;
0244 }
0245
0246 for (i = 0; i < 0xff; i++) {
0247
0248 switch (i) {
0249 case 0xb8 ... 0xc1:
0250 case 0xc4 ... 0xc7:
0251 case 0xfd:
0252 continue;
0253 }
0254 switch (i & ~0x30) {
0255 case 0x00:
0256 case 0x0c ... 0x0d:
0257 continue;
0258 }
0259
0260 tw_write_and_verify(solo_dev, dev_addr, i,
0261 tbl_tw2865_common[i]);
0262 }
0263
0264 return 0;
0265 }
0266
0267 static int tw2864_setup(struct solo_dev *solo_dev, u8 dev_addr)
0268 {
0269 u8 tbl_tw2864_common[256];
0270 int i;
0271
0272 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL)
0273 memcpy(tbl_tw2864_common, tbl_tw2864_pal_template,
0274 sizeof(tbl_tw2864_common));
0275 else
0276 memcpy(tbl_tw2864_common, tbl_tw2864_ntsc_template,
0277 sizeof(tbl_tw2864_common));
0278
0279 if (solo_dev->tw2865 == 0) {
0280
0281 if (solo_dev->nr_chans == 4) {
0282 tbl_tw2864_common[0xd2] = 0x01;
0283 tbl_tw2864_common[0xcf] = 0x00;
0284 } else if (solo_dev->nr_chans == 8) {
0285 tbl_tw2864_common[0xd2] = 0x02;
0286 if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
0287 tbl_tw2864_common[0xcf] = 0x43;
0288 else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
0289 tbl_tw2864_common[0xcf] = 0x40;
0290 } else if (solo_dev->nr_chans == 16) {
0291 tbl_tw2864_common[0xd2] = 0x03;
0292 if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
0293 tbl_tw2864_common[0xcf] = 0x43;
0294 else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
0295 tbl_tw2864_common[0xcf] = 0x43;
0296 else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
0297 tbl_tw2864_common[0xcf] = 0x43;
0298 else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
0299 tbl_tw2864_common[0xcf] = 0x40;
0300 }
0301 } else {
0302
0303
0304 for (i = 0; i <= 4; i++)
0305 tbl_tw2864_common[0x08 | i << 4] = 0x12;
0306
0307 if (solo_dev->nr_chans == 8) {
0308 tbl_tw2864_common[0xd2] = 0x02;
0309 if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
0310 tbl_tw2864_common[0xcf] = 0x80;
0311 } else if (solo_dev->nr_chans == 16) {
0312 tbl_tw2864_common[0xd2] = 0x03;
0313 if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
0314 tbl_tw2864_common[0xcf] = 0x83;
0315 else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
0316 tbl_tw2864_common[0xcf] = 0x83;
0317 else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
0318 tbl_tw2864_common[0xcf] = 0x80;
0319 }
0320 }
0321
0322 for (i = 0; i < 0xff; i++) {
0323
0324 switch (i) {
0325 case 0xb8 ... 0xc1:
0326 case 0xfd:
0327 continue;
0328 }
0329 switch (i & ~0x30) {
0330 case 0x00:
0331 case 0x0c:
0332 case 0x0d:
0333 continue;
0334 }
0335
0336 tw_write_and_verify(solo_dev, dev_addr, i,
0337 tbl_tw2864_common[i]);
0338 }
0339
0340 return 0;
0341 }
0342
0343 static int tw2815_setup(struct solo_dev *solo_dev, u8 dev_addr)
0344 {
0345 u8 tbl_ntsc_tw2815_common[] = {
0346 0x00, 0xc8, 0x20, 0xd0, 0x06, 0xf0, 0x08, 0x80,
0347 0x80, 0x80, 0x80, 0x02, 0x06, 0x00, 0x11,
0348 };
0349
0350 u8 tbl_pal_tw2815_common[] = {
0351 0x00, 0x88, 0x20, 0xd0, 0x05, 0x20, 0x28, 0x80,
0352 0x80, 0x80, 0x80, 0x82, 0x06, 0x00, 0x11,
0353 };
0354
0355 u8 tbl_tw2815_sfr[] = {
0356 0x00, 0x00, 0x00, 0xc0, 0x45, 0xa0, 0xd0, 0x2f,
0357 0x64, 0x80, 0x80, 0x82, 0x82, 0x00, 0x00, 0x00,
0358 0x00, 0x0f, 0x05, 0x00, 0x00, 0x80, 0x06, 0x00,
0359 0x00, 0x00, 0x00, 0xff, 0x8f, 0x00, 0x00, 0x00,
0360 0x88, 0x88, 0xc0, 0x00, 0x20, 0x64, 0xa8, 0xec,
0361 0x31, 0x75, 0xb9, 0xfd, 0x00, 0x00, 0x88, 0x88,
0362 0x88, 0x11, 0x00, 0x88, 0x88, 0x00,
0363 };
0364 u8 *tbl_tw2815_common;
0365 int i;
0366 int ch;
0367
0368 tbl_ntsc_tw2815_common[0x06] = 0;
0369
0370
0371 tbl_ntsc_tw2815_common[0x02] = DEFAULT_HDELAY_NTSC & 0xff;
0372 tbl_ntsc_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_NTSC >> 8);
0373
0374
0375 tbl_ntsc_tw2815_common[0x03] = DEFAULT_HACTIVE_NTSC & 0xff;
0376 tbl_ntsc_tw2815_common[0x06] |=
0377 ((0x03 & (DEFAULT_HACTIVE_NTSC >> 8)) << 2);
0378
0379
0380 tbl_ntsc_tw2815_common[0x04] = DEFAULT_VDELAY_NTSC & 0xff;
0381 tbl_ntsc_tw2815_common[0x06] |=
0382 ((0x01 & (DEFAULT_VDELAY_NTSC >> 8)) << 4);
0383
0384
0385 tbl_ntsc_tw2815_common[0x05] = DEFAULT_VACTIVE_NTSC & 0xff;
0386 tbl_ntsc_tw2815_common[0x06] |=
0387 ((0x01 & (DEFAULT_VACTIVE_NTSC >> 8)) << 5);
0388
0389 tbl_pal_tw2815_common[0x06] = 0;
0390
0391
0392 tbl_pal_tw2815_common[0x02] = DEFAULT_HDELAY_PAL & 0xff;
0393 tbl_pal_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_PAL >> 8);
0394
0395
0396 tbl_pal_tw2815_common[0x03] = DEFAULT_HACTIVE_PAL & 0xff;
0397 tbl_pal_tw2815_common[0x06] |=
0398 ((0x03 & (DEFAULT_HACTIVE_PAL >> 8)) << 2);
0399
0400
0401 tbl_pal_tw2815_common[0x04] = DEFAULT_VDELAY_PAL & 0xff;
0402 tbl_pal_tw2815_common[0x06] |=
0403 ((0x01 & (DEFAULT_VDELAY_PAL >> 8)) << 4);
0404
0405
0406 tbl_pal_tw2815_common[0x05] = DEFAULT_VACTIVE_PAL & 0xff;
0407 tbl_pal_tw2815_common[0x06] |=
0408 ((0x01 & (DEFAULT_VACTIVE_PAL >> 8)) << 5);
0409
0410 tbl_tw2815_common =
0411 (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) ?
0412 tbl_ntsc_tw2815_common : tbl_pal_tw2815_common;
0413
0414
0415 tbl_tw2815_common[0x0d] |= 0x04;
0416
0417
0418 tbl_tw2815_sfr[0x62 - 0x40] &= ~(3 << 6);
0419
0420 if (solo_dev->nr_chans == 4) {
0421 tbl_tw2815_sfr[0x63 - 0x40] |= 1;
0422 tbl_tw2815_sfr[0x62 - 0x40] |= 3 << 6;
0423 } else if (solo_dev->nr_chans == 8) {
0424 tbl_tw2815_sfr[0x63 - 0x40] |= 2;
0425 if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
0426 tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6;
0427 else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
0428 tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6;
0429 } else if (solo_dev->nr_chans == 16) {
0430 tbl_tw2815_sfr[0x63 - 0x40] |= 3;
0431 if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
0432 tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6;
0433 else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
0434 tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6;
0435 else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
0436 tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6;
0437 else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
0438 tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6;
0439 }
0440
0441
0442
0443
0444
0445 tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 2;
0446 tbl_tw2815_sfr[0x6c - 0x40] |= 0 << 2;
0447
0448
0449 tbl_tw2815_sfr[0x6c - 0x40] |= 1 << 5;
0450
0451
0452 tbl_tw2815_sfr[0x5c - 0x40] |= 1 << 5;
0453
0454
0455 tbl_tw2815_sfr[0x70 - 0x40] |= 0xff;
0456
0457 tbl_tw2815_sfr[0x71 - 0x40] |= 0x10;
0458 tbl_tw2815_sfr[0x6d - 0x40] |= 0x0f;
0459
0460
0461
0462 for (ch = 0; ch < 4; ch++) {
0463 tbl_tw2815_common[0x0d] &= ~3;
0464 switch (ch) {
0465 case 0:
0466 tbl_tw2815_common[0x0d] |= 0x21;
0467 break;
0468 case 1:
0469 tbl_tw2815_common[0x0d] |= 0x20;
0470 break;
0471 case 2:
0472 tbl_tw2815_common[0x0d] |= 0x23;
0473 break;
0474 case 3:
0475 tbl_tw2815_common[0x0d] |= 0x22;
0476 break;
0477 }
0478
0479 for (i = 0; i < 0x0f; i++) {
0480 if (i == 0x00)
0481 continue;
0482 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
0483 dev_addr, (ch * 0x10) + i,
0484 tbl_tw2815_common[i]);
0485 }
0486 }
0487
0488 for (i = 0x40; i < 0x76; i++) {
0489
0490 if (i == 0x40 || i == 0x59 || i == 0x5a ||
0491 i == 0x5d || i == 0x5e || i == 0x5f)
0492 continue;
0493
0494 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, dev_addr, i,
0495 tbl_tw2815_sfr[i - 0x40]);
0496 }
0497
0498 return 0;
0499 }
0500
0501 #define FIRST_ACTIVE_LINE 0x0008
0502 #define LAST_ACTIVE_LINE 0x0102
0503
0504 static void saa712x_write_regs(struct solo_dev *dev, const u8 *vals,
0505 int start, int n)
0506 {
0507 for (; start < n; start++, vals++) {
0508
0509 switch (start) {
0510
0511 case 0x2e ... 0x37:
0512 case 0x60:
0513 case 0x7d:
0514 continue;
0515 }
0516 solo_i2c_writebyte(dev, SOLO_I2C_SAA, 0x46, start, *vals);
0517 }
0518 }
0519
0520 #define SAA712x_reg7c (0x80 | ((LAST_ACTIVE_LINE & 0x100) >> 2) \
0521 | ((FIRST_ACTIVE_LINE & 0x100) >> 4))
0522
0523 static void saa712x_setup(struct solo_dev *dev)
0524 {
0525 const int reg_start = 0x26;
0526 static const u8 saa7128_regs_ntsc[] = {
0527
0528 0x0d, 0x00,
0529
0530 0x59, 0x1d, 0x75, 0x3f, 0x06, 0x3f,
0531
0532 0x00, 0x00,
0533 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0534
0535 0x1a, 0x1a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
0536
0537 0x00, 0x00, 0x00, 0x68, 0x10, 0x97, 0x4c, 0x18,
0538 0x9b, 0x93, 0x9f, 0xff, 0x7c, 0x34, 0x3f, 0x3f,
0539
0540 0x3f, 0x83, 0x83, 0x80, 0x0d, 0x0f, 0xc3, 0x06,
0541 0x02, 0x80, 0x71, 0x77, 0xa7, 0x67, 0x66, 0x2e,
0542
0543 0x7b, 0x11, 0x4f, 0x1f, 0x7c, 0xf0, 0x21, 0x77,
0544 0x41, 0x88, 0x41, 0x52, 0xed, 0x10, 0x10, 0x00,
0545
0546 0x41, 0xc3, 0x00, 0x3e, 0xb8, 0x02, 0x00, 0x00,
0547 0x00, 0x00, FIRST_ACTIVE_LINE, LAST_ACTIVE_LINE & 0xff,
0548 SAA712x_reg7c, 0x00, 0xff, 0xff,
0549 }, saa7128_regs_pal[] = {
0550
0551 0x0d, 0x00,
0552
0553 0xe1, 0x1d, 0x75, 0x3f, 0x06, 0x3f,
0554
0555 0x00, 0x00,
0556 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0557
0558 0x1a, 0x1a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
0559
0560 0x00, 0x00, 0x00, 0x68, 0x10, 0x97, 0x4c, 0x18,
0561 0x9b, 0x93, 0x9f, 0xff, 0x7c, 0x34, 0x3f, 0x3f,
0562
0563 0x3f, 0x83, 0x83, 0x80, 0x0d, 0x0f, 0xc3, 0x06,
0564 0x02, 0x80, 0x0f, 0x77, 0xa7, 0x67, 0x66, 0x2e,
0565
0566 0x7b, 0x02, 0x35, 0xcb, 0x8a, 0x09, 0x2a, 0x77,
0567 0x41, 0x88, 0x41, 0x52, 0xf1, 0x10, 0x20, 0x00,
0568
0569 0x41, 0xc3, 0x00, 0x3e, 0xb8, 0x02, 0x00, 0x00,
0570 0x00, 0x00, 0x12, 0x30,
0571 SAA712x_reg7c | 0x40, 0x00, 0xff, 0xff,
0572 };
0573
0574 if (dev->video_type == SOLO_VO_FMT_TYPE_PAL)
0575 saa712x_write_regs(dev, saa7128_regs_pal, reg_start,
0576 sizeof(saa7128_regs_pal));
0577 else
0578 saa712x_write_regs(dev, saa7128_regs_ntsc, reg_start,
0579 sizeof(saa7128_regs_ntsc));
0580 }
0581
0582 int solo_tw28_init(struct solo_dev *solo_dev)
0583 {
0584 int i;
0585 u8 value;
0586
0587 solo_dev->tw28_cnt = 0;
0588
0589
0590 for (i = 0; i < solo_dev->nr_chans / 4; i++) {
0591 value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
0592 TW_CHIP_OFFSET_ADDR(i), 0xFF);
0593
0594 switch (value >> 3) {
0595 case 0x18:
0596 solo_dev->tw2865 |= 1 << i;
0597 solo_dev->tw28_cnt++;
0598 break;
0599 case 0x0c:
0600 case 0x0d:
0601 solo_dev->tw2864 |= 1 << i;
0602 solo_dev->tw28_cnt++;
0603 break;
0604 default:
0605 value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
0606 TW_CHIP_OFFSET_ADDR(i),
0607 0x59);
0608 if ((value >> 3) == 0x04) {
0609 solo_dev->tw2815 |= 1 << i;
0610 solo_dev->tw28_cnt++;
0611 }
0612 }
0613 }
0614
0615 if (solo_dev->tw28_cnt != (solo_dev->nr_chans >> 2)) {
0616 dev_err(&solo_dev->pdev->dev,
0617 "Could not initialize any techwell chips\n");
0618 return -EINVAL;
0619 }
0620
0621 saa712x_setup(solo_dev);
0622
0623 for (i = 0; i < solo_dev->tw28_cnt; i++) {
0624 if ((solo_dev->tw2865 & (1 << i)))
0625 tw2865_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
0626 else if ((solo_dev->tw2864 & (1 << i)))
0627 tw2864_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
0628 else
0629 tw2815_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
0630 }
0631
0632 return 0;
0633 }
0634
0635
0636
0637
0638
0639
0640
0641 int tw28_get_video_status(struct solo_dev *solo_dev, u8 ch)
0642 {
0643 u8 val, chip_num;
0644
0645
0646 chip_num = ch / 4;
0647 ch %= 4;
0648
0649 val = tw_readbyte(solo_dev, chip_num, TW286x_AV_STAT_ADDR,
0650 TW_AV_STAT_ADDR) & 0x0f;
0651
0652 return val & (1 << ch) ? 1 : 0;
0653 }
0654
0655 #if 0
0656
0657
0658 u16 tw28_get_audio_status(struct solo_dev *solo_dev)
0659 {
0660 u8 val;
0661 u16 status = 0;
0662 int i;
0663
0664 for (i = 0; i < solo_dev->tw28_cnt; i++) {
0665 val = (tw_readbyte(solo_dev, i, TW286x_AV_STAT_ADDR,
0666 TW_AV_STAT_ADDR) & 0xf0) >> 4;
0667 status |= val << (i * 4);
0668 }
0669
0670 return status;
0671 }
0672 #endif
0673
0674 bool tw28_has_sharpness(struct solo_dev *solo_dev, u8 ch)
0675 {
0676 return is_tw286x(solo_dev, ch / 4);
0677 }
0678
0679 int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch,
0680 s32 val)
0681 {
0682 char sval;
0683 u8 chip_num;
0684
0685
0686 chip_num = ch / 4;
0687 ch %= 4;
0688
0689 if (val > 255 || val < 0)
0690 return -ERANGE;
0691
0692 switch (ctrl) {
0693 case V4L2_CID_SHARPNESS:
0694
0695 if (is_tw286x(solo_dev, chip_num)) {
0696 u8 v = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
0697 TW_CHIP_OFFSET_ADDR(chip_num),
0698 TW286x_SHARPNESS(chip_num));
0699 v &= 0xf0;
0700 v |= val;
0701 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
0702 TW_CHIP_OFFSET_ADDR(chip_num),
0703 TW286x_SHARPNESS(chip_num), v);
0704 } else {
0705 return -EINVAL;
0706 }
0707 break;
0708
0709 case V4L2_CID_HUE:
0710 if (is_tw286x(solo_dev, chip_num))
0711 sval = val - 128;
0712 else
0713 sval = (char)val;
0714 tw_writebyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch),
0715 TW_HUE_ADDR(ch), sval);
0716
0717 break;
0718
0719 case V4L2_CID_SATURATION:
0720
0721 if (is_tw286x(solo_dev, chip_num)) {
0722 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
0723 TW_CHIP_OFFSET_ADDR(chip_num),
0724 TW286x_SATURATIONU_ADDR(ch), val);
0725 }
0726 tw_writebyte(solo_dev, chip_num, TW286x_SATURATIONV_ADDR(ch),
0727 TW_SATURATION_ADDR(ch), val);
0728
0729 break;
0730
0731 case V4L2_CID_CONTRAST:
0732 tw_writebyte(solo_dev, chip_num, TW286x_CONTRAST_ADDR(ch),
0733 TW_CONTRAST_ADDR(ch), val);
0734 break;
0735
0736 case V4L2_CID_BRIGHTNESS:
0737 if (is_tw286x(solo_dev, chip_num))
0738 sval = val - 128;
0739 else
0740 sval = (char)val;
0741 tw_writebyte(solo_dev, chip_num, TW286x_BRIGHTNESS_ADDR(ch),
0742 TW_BRIGHTNESS_ADDR(ch), sval);
0743
0744 break;
0745 default:
0746 return -EINVAL;
0747 }
0748
0749 return 0;
0750 }
0751
0752 int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch,
0753 s32 *val)
0754 {
0755 u8 rval, chip_num;
0756
0757
0758 chip_num = ch / 4;
0759 ch %= 4;
0760
0761 switch (ctrl) {
0762 case V4L2_CID_SHARPNESS:
0763
0764 if (is_tw286x(solo_dev, chip_num)) {
0765 rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
0766 TW_CHIP_OFFSET_ADDR(chip_num),
0767 TW286x_SHARPNESS(chip_num));
0768 *val = rval & 0x0f;
0769 } else
0770 *val = 0;
0771 break;
0772 case V4L2_CID_HUE:
0773 rval = tw_readbyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch),
0774 TW_HUE_ADDR(ch));
0775 if (is_tw286x(solo_dev, chip_num))
0776 *val = (s32)((char)rval) + 128;
0777 else
0778 *val = rval;
0779 break;
0780 case V4L2_CID_SATURATION:
0781 *val = tw_readbyte(solo_dev, chip_num,
0782 TW286x_SATURATIONU_ADDR(ch),
0783 TW_SATURATION_ADDR(ch));
0784 break;
0785 case V4L2_CID_CONTRAST:
0786 *val = tw_readbyte(solo_dev, chip_num,
0787 TW286x_CONTRAST_ADDR(ch),
0788 TW_CONTRAST_ADDR(ch));
0789 break;
0790 case V4L2_CID_BRIGHTNESS:
0791 rval = tw_readbyte(solo_dev, chip_num,
0792 TW286x_BRIGHTNESS_ADDR(ch),
0793 TW_BRIGHTNESS_ADDR(ch));
0794 if (is_tw286x(solo_dev, chip_num))
0795 *val = (s32)((char)rval) + 128;
0796 else
0797 *val = rval;
0798 break;
0799 default:
0800 return -EINVAL;
0801 }
0802
0803 return 0;
0804 }
0805
0806 #if 0
0807
0808
0809
0810
0811
0812 void tw2815_Set_AudioOutVol(struct solo_dev *solo_dev, unsigned int u_val)
0813 {
0814 unsigned int val;
0815 unsigned int chip_num;
0816
0817 chip_num = (solo_dev->nr_chans - 1) / 4;
0818
0819 val = tw_readbyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR,
0820 TW_AUDIO_OUTPUT_VOL_ADDR);
0821
0822 u_val = (val & 0x0f) | (u_val << 4);
0823
0824 tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR,
0825 TW_AUDIO_OUTPUT_VOL_ADDR, u_val);
0826 }
0827 #endif
0828
0829 u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch)
0830 {
0831 u8 val;
0832 u8 chip_num;
0833
0834
0835 chip_num = ch / 4;
0836 ch %= 4;
0837
0838 val = tw_readbyte(solo_dev, chip_num,
0839 TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
0840 TW_AUDIO_INPUT_GAIN_ADDR(ch));
0841
0842 return (ch % 2) ? (val >> 4) : (val & 0x0f);
0843 }
0844
0845 void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val)
0846 {
0847 u8 old_val;
0848 u8 chip_num;
0849
0850
0851 chip_num = ch / 4;
0852 ch %= 4;
0853
0854 old_val = tw_readbyte(solo_dev, chip_num,
0855 TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
0856 TW_AUDIO_INPUT_GAIN_ADDR(ch));
0857
0858 val = (old_val & ((ch % 2) ? 0x0f : 0xf0)) |
0859 ((ch % 2) ? (val << 4) : val);
0860
0861 tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
0862 TW_AUDIO_INPUT_GAIN_ADDR(ch), val);
0863 }