Merge branch 'for-2.6.40' of git://linux-nfs.org/~bfields/linux
[linux-2.6-block.git] / drivers / staging / solo6x10 / tw28.c
CommitLineData
faa4fd2a
BC
1/*
2 * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
3 * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20#include <linux/kernel.h>
ae69b22c
KH
21#include "solo6x10.h"
22#include "tw28.h"
faa4fd2a
BC
23
24/* XXX: Some of these values are masked into an 8-bit regs, and shifted
25 * around for other 8-bit regs. What are the magic bits in these values? */
26#define DEFAULT_HDELAY_NTSC (32 - 4)
27#define DEFAULT_HACTIVE_NTSC (720 + 16)
28#define DEFAULT_VDELAY_NTSC (7 - 2)
29#define DEFAULT_VACTIVE_NTSC (240 + 4)
30
31#define DEFAULT_HDELAY_PAL (32 + 4)
32#define DEFAULT_HACTIVE_PAL (864-DEFAULT_HDELAY_PAL)
33#define DEFAULT_VDELAY_PAL (6)
34#define DEFAULT_VACTIVE_PAL (312-DEFAULT_VDELAY_PAL)
35
36static u8 tbl_tw2864_template[] = {
afabbe6d 37 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x00 */
faa4fd2a 38 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
afabbe6d 39 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x10 */
faa4fd2a 40 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
afabbe6d 41 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x20 */
faa4fd2a 42 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
afabbe6d 43 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x30 */
faa4fd2a 44 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
afabbe6d 45 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */
faa4fd2a 46 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
afabbe6d 47 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
faa4fd2a 48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
afabbe6d 49 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
faa4fd2a 50 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
afabbe6d 51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */
faa4fd2a 52 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00,
afabbe6d 53 0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
faa4fd2a 54 0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00,
afabbe6d 55 0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, /* 0x90 */
faa4fd2a 56 0x00, 0x28, 0x44, 0x44, 0xa0, 0x88, 0x5a, 0x01,
afabbe6d 57 0x08, 0x08, 0x08, 0x08, 0x1a, 0x1a, 0x1a, 0x1a, /* 0xa0 */
faa4fd2a 58 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44,
afabbe6d 59 0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, /* 0xb0 */
faa4fd2a 60 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
afabbe6d 61 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
faa4fd2a 62 0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00,
afabbe6d 63 0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */
faa4fd2a 64 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
afabbe6d 65 0x10, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
faa4fd2a 66 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
afabbe6d 67 0x83, 0xb5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */
faa4fd2a
BC
68 0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00,
69};
70
ee6351f5 71static u8 tbl_tw2865_ntsc_template[] = {
afabbe6d 72 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */
ee6351f5 73 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
afabbe6d 74 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */
ee6351f5 75 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
afabbe6d 76 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x20 */
ee6351f5 77 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
afabbe6d 78 0x00, 0xf0, 0x70, 0x48, 0x80, 0x80, 0x00, 0x02, /* 0x30 */
ee6351f5 79 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
afabbe6d 80 0x00, 0x00, 0x90, 0x68, 0x00, 0x38, 0x80, 0x80, /* 0x40 */
ee6351f5 81 0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
afabbe6d 82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
ee6351f5 83 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
afabbe6d 84 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
ee6351f5 85 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
afabbe6d 86 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */
ee6351f5 87 0xE9, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
afabbe6d 88 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
ee6351f5 89 0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
afabbe6d 90 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */
ee6351f5 91 0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
afabbe6d 92 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1B, 0x1A, /* 0xa0 */
ee6351f5 93 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
afabbe6d 94 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */
ee6351f5 95 0xFF, 0xE7, 0xE9, 0xE9, 0xEB, 0xFF, 0xD6, 0xD8,
afabbe6d 96 0xD8, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
ee6351f5 97 0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
afabbe6d 98 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */
ee6351f5 99 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
afabbe6d 100 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
ee6351f5 101 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
afabbe6d 102 0x83, 0xB5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */
ee6351f5
BC
103 0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
104};
105
106static u8 tbl_tw2865_pal_template[] = {
afabbe6d 107 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */
ee6351f5 108 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
afabbe6d 109 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */
ee6351f5 110 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
afabbe6d 111 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x20 */
ee6351f5 112 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
afabbe6d 113 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x30 */
ee6351f5 114 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
afabbe6d 115 0x00, 0x94, 0x90, 0x48, 0x00, 0x38, 0x7F, 0x80, /* 0x40 */
ee6351f5 116 0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
afabbe6d 117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
ee6351f5 118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
afabbe6d 119 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
ee6351f5 120 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
afabbe6d 121 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */
ee6351f5 122 0xEA, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
afabbe6d 123 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
ee6351f5 124 0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
afabbe6d 125 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */
ee6351f5 126 0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
afabbe6d 127 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1A, 0x1A, /* 0xa0 */
ee6351f5 128 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
afabbe6d 129 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */
ee6351f5 130 0xFF, 0xE7, 0xE9, 0xE9, 0xE9, 0xFF, 0xD7, 0xD8,
afabbe6d 131 0xD9, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
ee6351f5 132 0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
afabbe6d 133 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */
ee6351f5 134 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
afabbe6d 135 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
ee6351f5 136 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
afabbe6d 137 0x83, 0xB5, 0x09, 0x00, 0xA0, 0x00, 0x01, 0x20, /* 0xf0 */
ee6351f5
BC
138 0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
139};
140
faa4fd2a
BC
141#define is_tw286x(__solo, __id) (!(__solo->tw2815 & (1 << __id)))
142
decebabf 143static u8 tw_readbyte(struct solo_dev *solo_dev, int chip_id, u8 tw6x_off,
faa4fd2a
BC
144 u8 tw_off)
145{
146 if (is_tw286x(solo_dev, chip_id))
147 return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
148 TW_CHIP_OFFSET_ADDR(chip_id),
149 tw6x_off);
150 else
151 return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
152 TW_CHIP_OFFSET_ADDR(chip_id),
153 tw_off);
154}
155
decebabf 156static void tw_writebyte(struct solo_dev *solo_dev, int chip_id,
faa4fd2a
BC
157 u8 tw6x_off, u8 tw_off, u8 val)
158{
159 if (is_tw286x(solo_dev, chip_id))
160 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
161 TW_CHIP_OFFSET_ADDR(chip_id),
162 tw6x_off, val);
163 else
164 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
165 TW_CHIP_OFFSET_ADDR(chip_id),
166 tw_off, val);
167}
168
decebabf 169static void tw_write_and_verify(struct solo_dev *solo_dev, u8 addr, u8 off,
faa4fd2a
BC
170 u8 val)
171{
172 int i;
173
174 for (i = 0; i < 5; i++) {
175 u8 rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, addr, off);
176 if (rval == val)
177 return;
178
179 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, addr, off, val);
180 msleep_interruptible(1);
181 }
182
decebabf 183/* printk("solo6x10/tw28: Error writing register: %02x->%02x [%02x]\n",
afabbe6d 184 addr, off, val); */
faa4fd2a
BC
185}
186
decebabf 187static int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr)
faa4fd2a 188{
ee6351f5 189 u8 tbl_tw2865_common[256];
faa4fd2a
BC
190 int i;
191
ee6351f5
BC
192 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL)
193 memcpy(tbl_tw2865_common, tbl_tw2865_pal_template,
194 sizeof(tbl_tw2865_common));
195 else
196 memcpy(tbl_tw2865_common, tbl_tw2865_ntsc_template,
197 sizeof(tbl_tw2865_common));
faa4fd2a 198
ee6351f5 199 /* ALINK Mode */
faa4fd2a 200 if (solo_dev->nr_chans == 4) {
ee6351f5
BC
201 tbl_tw2865_common[0xd2] = 0x01;
202 tbl_tw2865_common[0xcf] = 0x00;
faa4fd2a 203 } else if (solo_dev->nr_chans == 8) {
ee6351f5
BC
204 tbl_tw2865_common[0xd2] = 0x02;
205 if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
206 tbl_tw2865_common[0xcf] = 0x80;
faa4fd2a 207 } else if (solo_dev->nr_chans == 16) {
ee6351f5
BC
208 tbl_tw2865_common[0xd2] = 0x03;
209 if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
210 tbl_tw2865_common[0xcf] = 0x83;
faa4fd2a 211 else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
ee6351f5 212 tbl_tw2865_common[0xcf] = 0x83;
faa4fd2a 213 else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
ee6351f5
BC
214 tbl_tw2865_common[0xcf] = 0x80;
215 }
216
217 for (i = 0; i < 0xff; i++) {
218 /* Skip read only registers */
afabbe6d 219 if (i >= 0xb8 && i <= 0xc1)
ee6351f5
BC
220 continue;
221 if ((i & ~0x30) == 0x00 ||
222 (i & ~0x30) == 0x0c ||
223 (i & ~0x30) == 0x0d)
224 continue;
225 if (i >= 0xc4 && i <= 0xc7)
226 continue;
227 if (i == 0xfd)
228 continue;
229
230 tw_write_and_verify(solo_dev, dev_addr, i,
231 tbl_tw2865_common[i]);
232 }
233
234 return 0;
235}
236
decebabf 237static int tw2864_setup(struct solo_dev *solo_dev, u8 dev_addr)
ee6351f5
BC
238{
239 u8 tbl_tw2864_common[sizeof(tbl_tw2864_template)];
240 int i;
241
242 memcpy(tbl_tw2864_common, tbl_tw2864_template,
243 sizeof(tbl_tw2864_common));
244
245 if (solo_dev->tw2865 == 0) {
246 /* IRQ Mode */
247 if (solo_dev->nr_chans == 4) {
248 tbl_tw2864_common[0xd2] = 0x01;
249 tbl_tw2864_common[0xcf] = 0x00;
250 } else if (solo_dev->nr_chans == 8) {
251 tbl_tw2864_common[0xd2] = 0x02;
252 if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
253 tbl_tw2864_common[0xcf] = 0x43;
254 else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
255 tbl_tw2864_common[0xcf] = 0x40;
256 } else if (solo_dev->nr_chans == 16) {
257 tbl_tw2864_common[0xd2] = 0x03;
258 if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
259 tbl_tw2864_common[0xcf] = 0x43;
260 else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
261 tbl_tw2864_common[0xcf] = 0x43;
262 else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
263 tbl_tw2864_common[0xcf] = 0x43;
264 else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
265 tbl_tw2864_common[0xcf] = 0x40;
266 }
267 } else {
268 /* ALINK Mode. Assumes that the first tw28xx is a
269 * 2865 and these are in cascade. */
270 for (i = 0; i <= 4; i++)
271 tbl_tw2864_common[0x08 | i << 4] = 0x12;
272
273 if (solo_dev->nr_chans == 8) {
274 tbl_tw2864_common[0xd2] = 0x02;
275 if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
276 tbl_tw2864_common[0xcf] = 0x80;
277 } else if (solo_dev->nr_chans == 16) {
278 tbl_tw2864_common[0xd2] = 0x03;
279 if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
280 tbl_tw2864_common[0xcf] = 0x83;
281 else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
282 tbl_tw2864_common[0xcf] = 0x83;
283 else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
284 tbl_tw2864_common[0xcf] = 0x80;
285 }
faa4fd2a
BC
286 }
287
288 /* NTSC or PAL */
289 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL) {
290 for (i = 0; i < 4; i++) {
291 tbl_tw2864_common[0x07 | (i << 4)] |= 0x10;
292 tbl_tw2864_common[0x08 | (i << 4)] |= 0x06;
293 tbl_tw2864_common[0x0a | (i << 4)] |= 0x08;
294 tbl_tw2864_common[0x0b | (i << 4)] |= 0x13;
295 tbl_tw2864_common[0x0e | (i << 4)] |= 0x01;
296 }
297 tbl_tw2864_common[0x9d] = 0x90;
298 tbl_tw2864_common[0xf3] = 0x00;
299 tbl_tw2864_common[0xf4] = 0xa0;
300 }
301
302 for (i = 0; i < 0xff; i++) {
303 /* Skip read only registers */
afabbe6d 304 if (i >= 0xb8 && i <= 0xc1)
faa4fd2a
BC
305 continue;
306 if ((i & ~0x30) == 0x00 ||
307 (i & ~0x30) == 0x0c ||
308 (i & ~0x30) == 0x0d)
309 continue;
310 if (i == 0x74 || i == 0x77 || i == 0x78 ||
311 i == 0x79 || i == 0x7a)
312 continue;
ee6351f5
BC
313 if (i == 0xfd)
314 continue;
faa4fd2a
BC
315
316 tw_write_and_verify(solo_dev, dev_addr, i,
317 tbl_tw2864_common[i]);
318 }
319
320 return 0;
321}
322
decebabf 323static int tw2815_setup(struct solo_dev *solo_dev, u8 dev_addr)
faa4fd2a
BC
324{
325 u8 tbl_ntsc_tw2815_common[] = {
326 0x00, 0xc8, 0x20, 0xd0, 0x06, 0xf0, 0x08, 0x80,
327 0x80, 0x80, 0x80, 0x02, 0x06, 0x00, 0x11,
328 };
329
330 u8 tbl_pal_tw2815_common[] = {
331 0x00, 0x88, 0x20, 0xd0, 0x05, 0x20, 0x28, 0x80,
332 0x80, 0x80, 0x80, 0x82, 0x06, 0x00, 0x11,
333 };
334
335 u8 tbl_tw2815_sfr[] = {
afabbe6d 336 0x00, 0x00, 0x00, 0xc0, 0x45, 0xa0, 0xd0, 0x2f, /* 0x00 */
faa4fd2a 337 0x64, 0x80, 0x80, 0x82, 0x82, 0x00, 0x00, 0x00,
afabbe6d 338 0x00, 0x0f, 0x05, 0x00, 0x00, 0x80, 0x06, 0x00, /* 0x10 */
faa4fd2a 339 0x00, 0x00, 0x00, 0xff, 0x8f, 0x00, 0x00, 0x00,
afabbe6d 340 0x88, 0x88, 0xc0, 0x00, 0x20, 0x64, 0xa8, 0xec, /* 0x20 */
faa4fd2a 341 0x31, 0x75, 0xb9, 0xfd, 0x00, 0x00, 0x88, 0x88,
afabbe6d 342 0x88, 0x11, 0x00, 0x88, 0x88, 0x00, /* 0x30 */
faa4fd2a
BC
343 };
344 u8 *tbl_tw2815_common;
345 int i;
346 int ch;
347
348 tbl_ntsc_tw2815_common[0x06] = 0;
349
350 /* Horizontal Delay Control */
351 tbl_ntsc_tw2815_common[0x02] = DEFAULT_HDELAY_NTSC & 0xff;
352 tbl_ntsc_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_NTSC >> 8);
353
354 /* Horizontal Active Control */
355 tbl_ntsc_tw2815_common[0x03] = DEFAULT_HACTIVE_NTSC & 0xff;
356 tbl_ntsc_tw2815_common[0x06] |=
357 ((0x03 & (DEFAULT_HACTIVE_NTSC >> 8)) << 2);
358
359 /* Vertical Delay Control */
360 tbl_ntsc_tw2815_common[0x04] = DEFAULT_VDELAY_NTSC & 0xff;
361 tbl_ntsc_tw2815_common[0x06] |=
362 ((0x01 & (DEFAULT_VDELAY_NTSC >> 8)) << 4);
363
364 /* Vertical Active Control */
365 tbl_ntsc_tw2815_common[0x05] = DEFAULT_VACTIVE_NTSC & 0xff;
366 tbl_ntsc_tw2815_common[0x06] |=
367 ((0x01 & (DEFAULT_VACTIVE_NTSC >> 8)) << 5);
368
369 tbl_pal_tw2815_common[0x06] = 0;
370
371 /* Horizontal Delay Control */
372 tbl_pal_tw2815_common[0x02] = DEFAULT_HDELAY_PAL & 0xff;
373 tbl_pal_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_PAL >> 8);
374
375 /* Horizontal Active Control */
376 tbl_pal_tw2815_common[0x03] = DEFAULT_HACTIVE_PAL & 0xff;
377 tbl_pal_tw2815_common[0x06] |=
378 ((0x03 & (DEFAULT_HACTIVE_PAL >> 8)) << 2);
379
380 /* Vertical Delay Control */
381 tbl_pal_tw2815_common[0x04] = DEFAULT_VDELAY_PAL & 0xff;
382 tbl_pal_tw2815_common[0x06] |=
383 ((0x01 & (DEFAULT_VDELAY_PAL >> 8)) << 4);
384
385 /* Vertical Active Control */
386 tbl_pal_tw2815_common[0x05] = DEFAULT_VACTIVE_PAL & 0xff;
387 tbl_pal_tw2815_common[0x06] |=
388 ((0x01 & (DEFAULT_VACTIVE_PAL >> 8)) << 5);
389
390 tbl_tw2815_common =
391 (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) ?
392 tbl_ntsc_tw2815_common : tbl_pal_tw2815_common;
393
394 /* Dual ITU-R BT.656 format */
395 tbl_tw2815_common[0x0d] |= 0x04;
396
397 /* Audio configuration */
398 tbl_tw2815_sfr[0x62 - 0x40] &= ~(3 << 6);
399
400 if (solo_dev->nr_chans == 4) {
401 tbl_tw2815_sfr[0x63 - 0x40] |= 1;
402 tbl_tw2815_sfr[0x62 - 0x40] |= 3 << 6;
403 } else if (solo_dev->nr_chans == 8) {
404 tbl_tw2815_sfr[0x63 - 0x40] |= 2;
405 if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
406 tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6;
407 else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
408 tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6;
409 } else if (solo_dev->nr_chans == 16) {
410 tbl_tw2815_sfr[0x63 - 0x40] |= 3;
411 if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
412 tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6;
413 else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
414 tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6;
415 else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
416 tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6;
417 else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
418 tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6;
419 }
420
421 /* Output mode of R_ADATM pin (0 mixing, 1 record) */
422 /* tbl_tw2815_sfr[0x63 - 0x40] |= 0 << 2; */
423
424 /* 8KHz, used to be 16KHz, but changed for remote client compat */
425 tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 2;
426 tbl_tw2815_sfr[0x6c - 0x40] |= 0 << 2;
427
428 /* Playback of right channel */
429 tbl_tw2815_sfr[0x6c - 0x40] |= 1 << 5;
430
431 /* Reserved value (XXX ??) */
432 tbl_tw2815_sfr[0x5c - 0x40] |= 1 << 5;
433
434 /* Analog output gain and mix ratio playback on full */
435 tbl_tw2815_sfr[0x70 - 0x40] |= 0xff;
436 /* Select playback audio and mute all except */
437 tbl_tw2815_sfr[0x71 - 0x40] |= 0x10;
438 tbl_tw2815_sfr[0x6d - 0x40] |= 0x0f;
439
440 /* End of audio configuration */
441
442 for (ch = 0; ch < 4; ch++) {
443 tbl_tw2815_common[0x0d] &= ~3;
444 switch (ch) {
445 case 0:
446 tbl_tw2815_common[0x0d] |= 0x21;
447 break;
448 case 1:
449 tbl_tw2815_common[0x0d] |= 0x20;
450 break;
451 case 2:
452 tbl_tw2815_common[0x0d] |= 0x23;
453 break;
454 case 3:
455 tbl_tw2815_common[0x0d] |= 0x22;
456 break;
457 }
458
459 for (i = 0; i < 0x0f; i++) {
460 if (i == 0x00)
afabbe6d 461 continue; /* read-only */
faa4fd2a
BC
462 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
463 dev_addr, (ch * 0x10) + i,
464 tbl_tw2815_common[i]);
465 }
466 }
467
468 for (i = 0x40; i < 0x76; i++) {
469 /* Skip read-only and nop registers */
470 if (i == 0x40 || i == 0x59 || i == 0x5a ||
471 i == 0x5d || i == 0x5e || i == 0x5f)
472 continue;
473
474 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, dev_addr, i,
475 tbl_tw2815_sfr[i - 0x40]);
476 }
477
478 return 0;
479}
480
481#define FIRST_ACTIVE_LINE 0x0008
482#define LAST_ACTIVE_LINE 0x0102
483
decebabf 484static void saa7128_setup(struct solo_dev *solo_dev)
faa4fd2a
BC
485{
486 int i;
487 unsigned char regs[128] = {
488 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
489 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
490 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
491 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
492 0x1C, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00,
493 0x59, 0x1d, 0x75, 0x3f, 0x06, 0x3f, 0x00, 0x00,
494 0x1c, 0x33, 0x00, 0x3f, 0x00, 0x00, 0x3f, 0x00,
495 0x1a, 0x1a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
496 0x00, 0x00, 0x00, 0x68, 0x10, 0x97, 0x4c, 0x18,
497 0x9b, 0x93, 0x9f, 0xff, 0x7c, 0x34, 0x3f, 0x3f,
498 0x3f, 0x83, 0x83, 0x80, 0x0d, 0x0f, 0xc3, 0x06,
499 0x02, 0x80, 0x71, 0x77, 0xa7, 0x67, 0x66, 0x2e,
500 0x7b, 0x11, 0x4f, 0x1f, 0x7c, 0xf0, 0x21, 0x77,
501 0x41, 0x88, 0x41, 0x12, 0xed, 0x10, 0x10, 0x00,
502 0x41, 0xc3, 0x00, 0x3e, 0xb8, 0x02, 0x00, 0x00,
503 0x00, 0x00, 0x08, 0xff, 0x80, 0x00, 0xff, 0xff,
504 };
505
506 regs[0x7A] = FIRST_ACTIVE_LINE & 0xff;
507 regs[0x7B] = LAST_ACTIVE_LINE & 0xff;
508 regs[0x7C] = ((1 << 7) |
509 (((LAST_ACTIVE_LINE >> 8) & 1) << 6) |
510 (((FIRST_ACTIVE_LINE >> 8) & 1) << 4));
511
512 /* PAL: XXX: We could do a second set of regs to avoid this */
513 if (solo_dev->video_type != SOLO_VO_FMT_TYPE_NTSC) {
514 regs[0x28] = 0xE1;
515
516 regs[0x5A] = 0x0F;
517 regs[0x61] = 0x02;
518 regs[0x62] = 0x35;
519 regs[0x63] = 0xCB;
520 regs[0x64] = 0x8A;
521 regs[0x65] = 0x09;
522 regs[0x66] = 0x2A;
523
524 regs[0x6C] = 0xf1;
525 regs[0x6E] = 0x20;
526
527 regs[0x7A] = 0x06 + 12;
528 regs[0x7b] = 0x24 + 12;
529 regs[0x7c] |= 1 << 6;
530 }
531
532 /* First 0x25 bytes are read-only? */
533 for (i = 0x26; i < 128; i++) {
534 if (i == 0x60 || i == 0x7D)
535 continue;
536 solo_i2c_writebyte(solo_dev, SOLO_I2C_SAA, 0x46, i, regs[i]);
537 }
538
539 return;
540}
541
decebabf 542int solo_tw28_init(struct solo_dev *solo_dev)
faa4fd2a
BC
543{
544 int i;
545 u8 value;
546
547 /* Detect techwell chip type */
548 for (i = 0; i < TW_NUM_CHIP; i++) {
549 value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
550 TW_CHIP_OFFSET_ADDR(i), 0xFF);
551
552 switch (value >> 3) {
553 case 0x18:
ee6351f5
BC
554 solo_dev->tw2865 |= 1 << i;
555 solo_dev->tw28_cnt++;
faa4fd2a
BC
556 break;
557 case 0x0c:
558 solo_dev->tw2864 |= 1 << i;
559 solo_dev->tw28_cnt++;
560 break;
561 default:
562 value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
563 TW_CHIP_OFFSET_ADDR(i), 0x59);
564 if ((value >> 3) == 0x04) {
565 solo_dev->tw2815 |= 1 << i;
566 solo_dev->tw28_cnt++;
567 }
568 }
569 }
570
571 if (!solo_dev->tw28_cnt)
572 return -EINVAL;
573
574 saa7128_setup(solo_dev);
575
576 for (i = 0; i < solo_dev->tw28_cnt; i++) {
ee6351f5
BC
577 if ((solo_dev->tw2865 & (1 << i)))
578 tw2865_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
579 else if ((solo_dev->tw2864 & (1 << i)))
faa4fd2a
BC
580 tw2864_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
581 else
582 tw2815_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
583 }
584
585 dev_info(&solo_dev->pdev->dev, "Initialized %d tw28xx chip%s:",
586 solo_dev->tw28_cnt, solo_dev->tw28_cnt == 1 ? "" : "s");
587
ee6351f5
BC
588 if (solo_dev->tw2865)
589 printk(" tw2865[%d]", hweight32(solo_dev->tw2865));
faa4fd2a
BC
590 if (solo_dev->tw2864)
591 printk(" tw2864[%d]", hweight32(solo_dev->tw2864));
592 if (solo_dev->tw2815)
593 printk(" tw2815[%d]", hweight32(solo_dev->tw2815));
594 printk("\n");
595
596 return 0;
597}
598
afabbe6d 599/*
faa4fd2a
BC
600 * We accessed the video status signal in the Techwell chip through
601 * iic/i2c because the video status reported by register REG_VI_STATUS1
602 * (address 0x012C) of the SOLO6010 chip doesn't give the correct video
603 * status signal values.
604 */
decebabf 605int tw28_get_video_status(struct solo_dev *solo_dev, u8 ch)
faa4fd2a
BC
606{
607 u8 val, chip_num;
608
609 /* Get the right chip and on-chip channel */
610 chip_num = ch / 4;
611 ch %= 4;
612
613 val = tw_readbyte(solo_dev, chip_num, TW286X_AV_STAT_ADDR,
614 TW_AV_STAT_ADDR) & 0x0f;
615
616 return val & (1 << ch) ? 1 : 0;
617}
618
619#if 0
620/* Status of audio from up to 4 techwell chips are combined into 1 variable.
621 * See techwell datasheet for details. */
decebabf 622u16 tw28_get_audio_status(struct solo_dev *solo_dev)
faa4fd2a
BC
623{
624 u8 val;
625 u16 status = 0;
626 int i;
627
628 for (i = 0; i < solo_dev->tw28_cnt; i++) {
629 val = (tw_readbyte(solo_dev, i, TW286X_AV_STAT_ADDR,
630 TW_AV_STAT_ADDR) & 0xf0) >> 4;
631 status |= val << (i * 4);
632 }
633
634 return status;
635}
636#endif
637
decebabf 638int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val)
faa4fd2a
BC
639{
640 char sval;
641 u8 chip_num;
642
643 /* Get the right chip and on-chip channel */
644 chip_num = ch / 4;
645 ch %= 4;
646
647 if (val > 255 || val < 0)
648 return -ERANGE;
649
650 switch (ctrl) {
651 case V4L2_CID_SHARPNESS:
652 /* Only 286x has sharpness */
653 if (val > 0x0f || val < 0)
654 return -ERANGE;
655 if (is_tw286x(solo_dev, chip_num)) {
656 u8 v = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
657 TW_CHIP_OFFSET_ADDR(chip_num),
658 TW286x_SHARPNESS(chip_num));
659 v &= 0xf0;
660 v |= val;
661 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
662 TW_CHIP_OFFSET_ADDR(chip_num),
663 TW286x_SHARPNESS(chip_num), v);
664 } else if (val != 0)
665 return -ERANGE;
666 break;
667
668 case V4L2_CID_HUE:
669 if (is_tw286x(solo_dev, chip_num))
670 sval = val - 128;
671 else
672 sval = (char)val;
673 tw_writebyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch),
674 TW_HUE_ADDR(ch), sval);
675
676 break;
677
678 case V4L2_CID_SATURATION:
679 if (is_tw286x(solo_dev, chip_num)) {
680 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
681 TW_CHIP_OFFSET_ADDR(chip_num),
682 TW286x_SATURATIONU_ADDR(ch), val);
683 }
684 tw_writebyte(solo_dev, chip_num, TW286x_SATURATIONV_ADDR(ch),
685 TW_SATURATION_ADDR(ch), val);
686
687 break;
688
689 case V4L2_CID_CONTRAST:
690 tw_writebyte(solo_dev, chip_num, TW286x_CONTRAST_ADDR(ch),
691 TW_CONTRAST_ADDR(ch), val);
692 break;
693
694 case V4L2_CID_BRIGHTNESS:
695 if (is_tw286x(solo_dev, chip_num))
696 sval = val - 128;
697 else
698 sval = (char)val;
699 tw_writebyte(solo_dev, chip_num, TW286x_BRIGHTNESS_ADDR(ch),
700 TW_BRIGHTNESS_ADDR(ch), sval);
701
702 break;
703 default:
704 return -EINVAL;
705 }
706
707 return 0;
708}
709
decebabf 710int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch,
faa4fd2a
BC
711 s32 *val)
712{
713 u8 rval, chip_num;
714
715 /* Get the right chip and on-chip channel */
716 chip_num = ch / 4;
717 ch %= 4;
718
719 switch (ctrl) {
720 case V4L2_CID_SHARPNESS:
721 /* Only 286x has sharpness */
722 if (is_tw286x(solo_dev, chip_num)) {
ee6351f5 723 rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
faa4fd2a
BC
724 TW_CHIP_OFFSET_ADDR(chip_num),
725 TW286x_SHARPNESS(chip_num));
726 *val = rval & 0x0f;
727 } else
728 *val = 0;
729 break;
730 case V4L2_CID_HUE:
731 rval = tw_readbyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch),
732 TW_HUE_ADDR(ch));
733 if (is_tw286x(solo_dev, chip_num))
734 *val = (s32)((char)rval) + 128;
735 else
736 *val = rval;
737 break;
738 case V4L2_CID_SATURATION:
739 *val = tw_readbyte(solo_dev, chip_num,
740 TW286x_SATURATIONU_ADDR(ch),
741 TW_SATURATION_ADDR(ch));
742 break;
743 case V4L2_CID_CONTRAST:
744 *val = tw_readbyte(solo_dev, chip_num,
745 TW286x_CONTRAST_ADDR(ch),
746 TW_CONTRAST_ADDR(ch));
747 break;
748 case V4L2_CID_BRIGHTNESS:
749 rval = tw_readbyte(solo_dev, chip_num,
750 TW286x_BRIGHTNESS_ADDR(ch),
751 TW_BRIGHTNESS_ADDR(ch));
afabbe6d 752 if (is_tw286x(solo_dev, chip_num))
faa4fd2a
BC
753 *val = (s32)((char)rval) + 128;
754 else
755 *val = rval;
756 break;
757 default:
758 return -EINVAL;
759 }
760
761 return 0;
762}
763
764#if 0
765/*
766 * For audio output volume, the output channel is only 1. In this case we
767 * don't need to offset TW_CHIP_OFFSET_ADDR. The TW_CHIP_OFFSET_ADDR used
768 * is the base address of the techwell chip.
769 */
decebabf 770void tw2815_Set_AudioOutVol(struct solo_dev *solo_dev, unsigned int u_val)
faa4fd2a
BC
771{
772 unsigned int val;
773 unsigned int chip_num;
774
775 chip_num = (solo_dev->nr_chans - 1) / 4;
776
777 val = tw_readbyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR,
778 TW_AUDIO_OUTPUT_VOL_ADDR);
779
780 u_val = (val & 0x0f) | (u_val << 4);
781
782 tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_OUTPUT_VOL_ADDR,
783 TW_AUDIO_OUTPUT_VOL_ADDR, u_val);
784}
785#endif
786
decebabf 787u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch)
faa4fd2a
BC
788{
789 u8 val;
790 u8 chip_num;
791
792 /* Get the right chip and on-chip channel */
793 chip_num = ch / 4;
794 ch %= 4;
795
796 val = tw_readbyte(solo_dev, chip_num,
797 TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
798 TW_AUDIO_INPUT_GAIN_ADDR(ch));
799
800 return (ch % 2) ? (val >> 4) : (val & 0x0f);
801}
802
decebabf 803void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val)
faa4fd2a
BC
804{
805 u8 old_val;
806 u8 chip_num;
807
808 /* Get the right chip and on-chip channel */
809 chip_num = ch / 4;
810 ch %= 4;
811
812 old_val = tw_readbyte(solo_dev, chip_num,
813 TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
814 TW_AUDIO_INPUT_GAIN_ADDR(ch));
815
816 val = (old_val & ((ch % 2) ? 0x0f : 0xf0)) |
817 ((ch % 2) ? (val << 4) : val);
818
819 tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
820 TW_AUDIO_INPUT_GAIN_ADDR(ch), val);
821}