GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / drivers / staging / solo6x10 / solo6010-tw28.c
blob9f641093cf83452f6c52220a57e3287cbb62114c
1 /*
2 * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com
3 * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net>
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.
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.
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.
20 #include <linux/kernel.h>
22 #include "solo6010.h"
23 #include "solo6010-tw28.h"
25 #define DEFAULT_HDELAY_NTSC (32 - 4)
26 #define DEFAULT_HACTIVE_NTSC (720 + 16)
27 #define DEFAULT_VDELAY_NTSC (7 - 2)
28 #define DEFAULT_VACTIVE_NTSC (240 + 4)
30 #define DEFAULT_HDELAY_PAL (32 + 4)
31 #define DEFAULT_HACTIVE_PAL (864-DEFAULT_HDELAY_PAL)
32 #define DEFAULT_VDELAY_PAL (6)
33 #define DEFAULT_VACTIVE_PAL (312-DEFAULT_VDELAY_PAL)
35 static u8 tbl_tw2864_template[] = {
36 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, // 0x00
37 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
38 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, // 0x10
39 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
40 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, // 0x20
41 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
42 0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, // 0x30
43 0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
44 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x40
45 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
46 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50
47 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
49 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
50 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x70
51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00,
52 0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, // 0x80
53 0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00,
54 0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, // 0x90
55 0x00, 0x28, 0x44, 0x44, 0xa0, 0x88, 0x5a, 0x01,
56 0x08, 0x08, 0x08, 0x08, 0x1a, 0x1a, 0x1a, 0x1a, // 0xa0
57 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44,
58 0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, // 0xb0
59 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xc0
61 0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00,
62 0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, // 0xd0
63 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
64 0x10, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, // 0xe0
65 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
66 0x83, 0xb5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, // 0xf0
67 0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00,
70 static u8 tbl_tw2865_ntsc_template[] = {
71 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, // 0x00
72 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
73 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, // 0x10
74 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
75 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, // 0x20
76 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
77 0x00, 0xf0, 0x70, 0x48, 0x80, 0x80, 0x00, 0x02, // 0x30
78 0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
79 0x00, 0x00, 0x90, 0x68, 0x00, 0x38, 0x80, 0x80, // 0x40
80 0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
81 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50
82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
84 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
85 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, // 0x70
86 0xE9, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
87 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, // 0x80
88 0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
89 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, // 0x90
90 0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
91 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1B, 0x1A, // 0xa0
92 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
93 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, // 0xb0
94 0xFF, 0xE7, 0xE9, 0xE9, 0xEB, 0xFF, 0xD6, 0xD8,
95 0xD8, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xc0
96 0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
97 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, // 0xd0
98 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
99 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, // 0xe0
100 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
101 0x83, 0xB5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, // 0xf0
102 0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
105 static u8 tbl_tw2865_pal_template[] = {
106 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, // 0x00
107 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
108 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, // 0x10
109 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
110 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, // 0x20
111 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
112 0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, // 0x30
113 0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
114 0x00, 0x94, 0x90, 0x48, 0x00, 0x38, 0x7F, 0x80, // 0x40
115 0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
116 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x50
117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118 0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
119 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
120 0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, // 0x70
121 0xEA, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
122 0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, // 0x80
123 0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
124 0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, // 0x90
125 0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
126 0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1A, 0x1A, // 0xa0
127 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
128 0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, // 0xb0
129 0xFF, 0xE7, 0xE9, 0xE9, 0xE9, 0xFF, 0xD7, 0xD8,
130 0xD9, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0xc0
131 0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
132 0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, // 0xd0
133 0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
134 0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, // 0xe0
135 0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
136 0x83, 0xB5, 0x09, 0x00, 0xA0, 0x00, 0x01, 0x20, // 0xf0
137 0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
140 #define is_tw286x(__solo, __id) (!(__solo->tw2815 & (1 << __id)))
142 static u8 tw_readbyte(struct solo6010_dev *solo_dev, int chip_id, u8 tw6x_off,
143 u8 tw_off)
145 if (is_tw286x(solo_dev, chip_id))
146 return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
147 TW_CHIP_OFFSET_ADDR(chip_id),
148 tw6x_off);
149 else
150 return solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
151 TW_CHIP_OFFSET_ADDR(chip_id),
152 tw_off);
155 static void tw_writebyte(struct solo6010_dev *solo_dev, int chip_id,
156 u8 tw6x_off, u8 tw_off, u8 val)
158 if (is_tw286x(solo_dev, chip_id))
159 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
160 TW_CHIP_OFFSET_ADDR(chip_id),
161 tw6x_off, val);
162 else
163 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
164 TW_CHIP_OFFSET_ADDR(chip_id),
165 tw_off, val);
168 static void tw_write_and_verify(struct solo6010_dev *solo_dev, u8 addr, u8 off,
169 u8 val)
171 int i;
173 for (i = 0; i < 5; i++) {
174 u8 rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, addr, off);
175 if (rval == val)
176 return;
178 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, addr, off, val);
179 msleep_interruptible(1);
182 // printk("solo6010/tw28: Error writing register: %02x->%02x [%02x]\n",
183 // addr, off, val);
186 static int tw2865_setup(struct solo6010_dev *solo_dev, u8 dev_addr)
188 u8 tbl_tw2865_common[256];
189 int i;
191 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL)
192 memcpy(tbl_tw2865_common, tbl_tw2865_pal_template,
193 sizeof(tbl_tw2865_common));
194 else
195 memcpy(tbl_tw2865_common, tbl_tw2865_ntsc_template,
196 sizeof(tbl_tw2865_common));
198 /* ALINK Mode */
199 if (solo_dev->nr_chans == 4) {
200 tbl_tw2865_common[0xd2] = 0x01;
201 tbl_tw2865_common[0xcf] = 0x00;
202 } else if (solo_dev->nr_chans == 8) {
203 tbl_tw2865_common[0xd2] = 0x02;
204 if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
205 tbl_tw2865_common[0xcf] = 0x80;
206 } else if (solo_dev->nr_chans == 16) {
207 tbl_tw2865_common[0xd2] = 0x03;
208 if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
209 tbl_tw2865_common[0xcf] = 0x83;
210 else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
211 tbl_tw2865_common[0xcf] = 0x83;
212 else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
213 tbl_tw2865_common[0xcf] = 0x80;
216 for (i = 0; i < 0xff; i++) {
217 /* Skip read only registers */
218 if (i >= 0xb8 && i <= 0xc1 )
219 continue;
220 if ((i & ~0x30) == 0x00 ||
221 (i & ~0x30) == 0x0c ||
222 (i & ~0x30) == 0x0d)
223 continue;
224 if (i >= 0xc4 && i <= 0xc7)
225 continue;
226 if (i == 0xfd)
227 continue;
229 tw_write_and_verify(solo_dev, dev_addr, i,
230 tbl_tw2865_common[i]);
233 return 0;
236 static int tw2864_setup(struct solo6010_dev *solo_dev, u8 dev_addr)
238 u8 tbl_tw2864_common[sizeof(tbl_tw2864_template)];
239 int i;
241 memcpy(tbl_tw2864_common, tbl_tw2864_template,
242 sizeof(tbl_tw2864_common));
244 if (solo_dev->tw2865 == 0) {
245 /* IRQ Mode */
246 if (solo_dev->nr_chans == 4) {
247 tbl_tw2864_common[0xd2] = 0x01;
248 tbl_tw2864_common[0xcf] = 0x00;
249 } else if (solo_dev->nr_chans == 8) {
250 tbl_tw2864_common[0xd2] = 0x02;
251 if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
252 tbl_tw2864_common[0xcf] = 0x43;
253 else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
254 tbl_tw2864_common[0xcf] = 0x40;
255 } else if (solo_dev->nr_chans == 16) {
256 tbl_tw2864_common[0xd2] = 0x03;
257 if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
258 tbl_tw2864_common[0xcf] = 0x43;
259 else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
260 tbl_tw2864_common[0xcf] = 0x43;
261 else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
262 tbl_tw2864_common[0xcf] = 0x43;
263 else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
264 tbl_tw2864_common[0xcf] = 0x40;
266 } else {
267 /* ALINK Mode. Assumes that the first tw28xx is a
268 * 2865 and these are in cascade. */
269 for (i = 0; i <= 4; i++)
270 tbl_tw2864_common[0x08 | i << 4] = 0x12;
272 if (solo_dev->nr_chans == 8) {
273 tbl_tw2864_common[0xd2] = 0x02;
274 if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
275 tbl_tw2864_common[0xcf] = 0x80;
276 } else if (solo_dev->nr_chans == 16) {
277 tbl_tw2864_common[0xd2] = 0x03;
278 if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
279 tbl_tw2864_common[0xcf] = 0x83;
280 else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
281 tbl_tw2864_common[0xcf] = 0x83;
282 else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
283 tbl_tw2864_common[0xcf] = 0x80;
287 /* NTSC or PAL */
288 if (solo_dev->video_type == SOLO_VO_FMT_TYPE_PAL) {
289 for (i = 0; i < 4; i++) {
290 tbl_tw2864_common[0x07 | (i << 4)] |= 0x10;
291 tbl_tw2864_common[0x08 | (i << 4)] |= 0x06;
292 tbl_tw2864_common[0x0a | (i << 4)] |= 0x08;
293 tbl_tw2864_common[0x0b | (i << 4)] |= 0x13;
294 tbl_tw2864_common[0x0e | (i << 4)] |= 0x01;
296 tbl_tw2864_common[0x9d] = 0x90;
297 tbl_tw2864_common[0xf3] = 0x00;
298 tbl_tw2864_common[0xf4] = 0xa0;
301 for (i = 0; i < 0xff; i++) {
302 /* Skip read only registers */
303 if (i >= 0xb8 && i <= 0xc1 )
304 continue;
305 if ((i & ~0x30) == 0x00 ||
306 (i & ~0x30) == 0x0c ||
307 (i & ~0x30) == 0x0d)
308 continue;
309 if (i == 0x74 || i == 0x77 || i == 0x78 ||
310 i == 0x79 || i == 0x7a)
311 continue;
312 if (i == 0xfd)
313 continue;
315 tw_write_and_verify(solo_dev, dev_addr, i,
316 tbl_tw2864_common[i]);
319 return 0;
322 static int tw2815_setup(struct solo6010_dev *solo_dev, u8 dev_addr)
324 u8 tbl_ntsc_tw2815_common[] = {
325 0x00, 0xc8, 0x20, 0xd0, 0x06, 0xf0, 0x08, 0x80,
326 0x80, 0x80, 0x80, 0x02, 0x06, 0x00, 0x11,
329 u8 tbl_pal_tw2815_common[] = {
330 0x00, 0x88, 0x20, 0xd0, 0x05, 0x20, 0x28, 0x80,
331 0x80, 0x80, 0x80, 0x82, 0x06, 0x00, 0x11,
334 u8 tbl_tw2815_sfr[] = {
335 0x00, 0x00, 0x00, 0xc0, 0x45, 0xa0, 0xd0, 0x2f, // 0x00
336 0x64, 0x80, 0x80, 0x82, 0x82, 0x00, 0x00, 0x00,
337 0x00, 0x0f, 0x05, 0x00, 0x00, 0x80, 0x06, 0x00, // 0x10
338 0x00, 0x00, 0x00, 0xff, 0x8f, 0x00, 0x00, 0x00,
339 0x88, 0x88, 0xc0, 0x00, 0x20, 0x64, 0xa8, 0xec, // 0x20
340 0x31, 0x75, 0xb9, 0xfd, 0x00, 0x00, 0x88, 0x88,
341 0x88, 0x11, 0x00, 0x88, 0x88, 0x00, // 0x30
343 u8 *tbl_tw2815_common;
344 int i;
345 int ch;
347 tbl_ntsc_tw2815_common[0x06] = 0;
349 /* Horizontal Delay Control */
350 tbl_ntsc_tw2815_common[0x02] = DEFAULT_HDELAY_NTSC & 0xff;
351 tbl_ntsc_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_NTSC >> 8);
353 /* Horizontal Active Control */
354 tbl_ntsc_tw2815_common[0x03] = DEFAULT_HACTIVE_NTSC & 0xff;
355 tbl_ntsc_tw2815_common[0x06] |=
356 ((0x03 & (DEFAULT_HACTIVE_NTSC >> 8)) << 2);
358 /* Vertical Delay Control */
359 tbl_ntsc_tw2815_common[0x04] = DEFAULT_VDELAY_NTSC & 0xff;
360 tbl_ntsc_tw2815_common[0x06] |=
361 ((0x01 & (DEFAULT_VDELAY_NTSC >> 8)) << 4);
363 /* Vertical Active Control */
364 tbl_ntsc_tw2815_common[0x05] = DEFAULT_VACTIVE_NTSC & 0xff;
365 tbl_ntsc_tw2815_common[0x06] |=
366 ((0x01 & (DEFAULT_VACTIVE_NTSC >> 8)) << 5);
368 tbl_pal_tw2815_common[0x06] = 0;
370 /* Horizontal Delay Control */
371 tbl_pal_tw2815_common[0x02] = DEFAULT_HDELAY_PAL & 0xff;
372 tbl_pal_tw2815_common[0x06] |= 0x03 & (DEFAULT_HDELAY_PAL >> 8);
374 /* Horizontal Active Control */
375 tbl_pal_tw2815_common[0x03] = DEFAULT_HACTIVE_PAL & 0xff;
376 tbl_pal_tw2815_common[0x06] |=
377 ((0x03 & (DEFAULT_HACTIVE_PAL >> 8)) << 2);
379 /* Vertical Delay Control */
380 tbl_pal_tw2815_common[0x04] = DEFAULT_VDELAY_PAL & 0xff;
381 tbl_pal_tw2815_common[0x06] |=
382 ((0x01 & (DEFAULT_VDELAY_PAL >> 8)) << 4);
384 /* Vertical Active Control */
385 tbl_pal_tw2815_common[0x05] = DEFAULT_VACTIVE_PAL & 0xff;
386 tbl_pal_tw2815_common[0x06] |=
387 ((0x01 & (DEFAULT_VACTIVE_PAL >> 8)) << 5);
389 tbl_tw2815_common =
390 (solo_dev->video_type == SOLO_VO_FMT_TYPE_NTSC) ?
391 tbl_ntsc_tw2815_common : tbl_pal_tw2815_common;
393 /* Dual ITU-R BT.656 format */
394 tbl_tw2815_common[0x0d] |= 0x04;
396 /* Audio configuration */
397 tbl_tw2815_sfr[0x62 - 0x40] &= ~(3 << 6);
399 if (solo_dev->nr_chans == 4) {
400 tbl_tw2815_sfr[0x63 - 0x40] |= 1;
401 tbl_tw2815_sfr[0x62 - 0x40] |= 3 << 6;
402 } else if (solo_dev->nr_chans == 8) {
403 tbl_tw2815_sfr[0x63 - 0x40] |= 2;
404 if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
405 tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6;
406 else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
407 tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6;
408 } else if (solo_dev->nr_chans == 16) {
409 tbl_tw2815_sfr[0x63 - 0x40] |= 3;
410 if (dev_addr == TW_CHIP_OFFSET_ADDR(0))
411 tbl_tw2815_sfr[0x62 - 0x40] |= 1 << 6;
412 else if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
413 tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6;
414 else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
415 tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 6;
416 else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
417 tbl_tw2815_sfr[0x62 - 0x40] |= 2 << 6;
420 /* Output mode of R_ADATM pin (0 mixing, 1 record) */
421 /* tbl_tw2815_sfr[0x63 - 0x40] |= 0 << 2; */
423 /* 8KHz, used to be 16KHz, but changed for remote client compat */
424 tbl_tw2815_sfr[0x62 - 0x40] |= 0 << 2;
425 tbl_tw2815_sfr[0x6c - 0x40] |= 0 << 2;
427 /* Playback of right channel */
428 tbl_tw2815_sfr[0x6c - 0x40] |= 1 << 5;
430 tbl_tw2815_sfr[0x5c - 0x40] |= 1 << 5;
432 /* Analog output gain and mix ratio playback on full */
433 tbl_tw2815_sfr[0x70 - 0x40] |= 0xff;
434 /* Select playback audio and mute all except */
435 tbl_tw2815_sfr[0x71 - 0x40] |= 0x10;
436 tbl_tw2815_sfr[0x6d - 0x40] |= 0x0f;
438 /* End of audio configuration */
440 for (ch = 0; ch < 4; ch++) {
441 tbl_tw2815_common[0x0d] &= ~3;
442 switch (ch) {
443 case 0:
444 tbl_tw2815_common[0x0d] |= 0x21;
445 break;
446 case 1:
447 tbl_tw2815_common[0x0d] |= 0x20;
448 break;
449 case 2:
450 tbl_tw2815_common[0x0d] |= 0x23;
451 break;
452 case 3:
453 tbl_tw2815_common[0x0d] |= 0x22;
454 break;
457 for (i = 0; i < 0x0f; i++) {
458 if (i == 0x00)
459 continue; // read-only
460 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
461 dev_addr, (ch * 0x10) + i,
462 tbl_tw2815_common[i]);
466 for (i = 0x40; i < 0x76; i++) {
467 /* Skip read-only and nop registers */
468 if (i == 0x40 || i == 0x59 || i == 0x5a ||
469 i == 0x5d || i == 0x5e || i == 0x5f)
470 continue;
472 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW, dev_addr, i,
473 tbl_tw2815_sfr[i - 0x40]);
476 return 0;
479 #define FIRST_ACTIVE_LINE 0x0008
480 #define LAST_ACTIVE_LINE 0x0102
482 static void saa7128_setup(struct solo6010_dev *solo_dev)
484 int i;
485 unsigned char regs[128] = {
486 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
487 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
488 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
489 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
490 0x1C, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00,
491 0x59, 0x1d, 0x75, 0x3f, 0x06, 0x3f, 0x00, 0x00,
492 0x1c, 0x33, 0x00, 0x3f, 0x00, 0x00, 0x3f, 0x00,
493 0x1a, 0x1a, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
494 0x00, 0x00, 0x00, 0x68, 0x10, 0x97, 0x4c, 0x18,
495 0x9b, 0x93, 0x9f, 0xff, 0x7c, 0x34, 0x3f, 0x3f,
496 0x3f, 0x83, 0x83, 0x80, 0x0d, 0x0f, 0xc3, 0x06,
497 0x02, 0x80, 0x71, 0x77, 0xa7, 0x67, 0x66, 0x2e,
498 0x7b, 0x11, 0x4f, 0x1f, 0x7c, 0xf0, 0x21, 0x77,
499 0x41, 0x88, 0x41, 0x12, 0xed, 0x10, 0x10, 0x00,
500 0x41, 0xc3, 0x00, 0x3e, 0xb8, 0x02, 0x00, 0x00,
501 0x00, 0x00, 0x08, 0xff, 0x80, 0x00, 0xff, 0xff,
504 regs[0x7A] = FIRST_ACTIVE_LINE & 0xff;
505 regs[0x7B] = LAST_ACTIVE_LINE & 0xff;
506 regs[0x7C] = ((1 << 7) |
507 (((LAST_ACTIVE_LINE >> 8) & 1) << 6) |
508 (((FIRST_ACTIVE_LINE >> 8) & 1) << 4));
510 if (solo_dev->video_type != SOLO_VO_FMT_TYPE_NTSC) {
511 regs[0x28] = 0xE1;
513 regs[0x5A] = 0x0F;
514 regs[0x61] = 0x02;
515 regs[0x62] = 0x35;
516 regs[0x63] = 0xCB;
517 regs[0x64] = 0x8A;
518 regs[0x65] = 0x09;
519 regs[0x66] = 0x2A;
521 regs[0x6C] = 0xf1;
522 regs[0x6E] = 0x20;
524 regs[0x7A] = 0x06 + 12;
525 regs[0x7b] = 0x24 + 12;
526 regs[0x7c] |= 1 << 6;
529 /* First 0x25 bytes are read-only? */
530 for (i = 0x26; i < 128; i++) {
531 if (i == 0x60 || i == 0x7D)
532 continue;
533 solo_i2c_writebyte(solo_dev, SOLO_I2C_SAA, 0x46, i, regs[i]);
536 return;
539 int solo_tw28_init(struct solo6010_dev *solo_dev)
541 int i;
542 u8 value;
544 /* Detect techwell chip type */
545 for (i = 0; i < TW_NUM_CHIP; i++) {
546 value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
547 TW_CHIP_OFFSET_ADDR(i), 0xFF);
549 switch (value >> 3) {
550 case 0x18:
551 solo_dev->tw2865 |= 1 << i;
552 solo_dev->tw28_cnt++;
553 break;
554 case 0x0c:
555 solo_dev->tw2864 |= 1 << i;
556 solo_dev->tw28_cnt++;
557 break;
558 default:
559 value = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
560 TW_CHIP_OFFSET_ADDR(i), 0x59);
561 if ((value >> 3) == 0x04) {
562 solo_dev->tw2815 |= 1 << i;
563 solo_dev->tw28_cnt++;
568 if (!solo_dev->tw28_cnt)
569 return -EINVAL;
571 saa7128_setup(solo_dev);
573 for (i = 0; i < solo_dev->tw28_cnt; i++) {
574 if ((solo_dev->tw2865 & (1 << i)))
575 tw2865_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
576 else if ((solo_dev->tw2864 & (1 << i)))
577 tw2864_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
578 else
579 tw2815_setup(solo_dev, TW_CHIP_OFFSET_ADDR(i));
582 dev_info(&solo_dev->pdev->dev, "Initialized %d tw28xx chip%s:",
583 solo_dev->tw28_cnt, solo_dev->tw28_cnt == 1 ? "" : "s");
585 if (solo_dev->tw2865)
586 printk(" tw2865[%d]", hweight32(solo_dev->tw2865));
587 if (solo_dev->tw2864)
588 printk(" tw2864[%d]", hweight32(solo_dev->tw2864));
589 if (solo_dev->tw2815)
590 printk(" tw2815[%d]", hweight32(solo_dev->tw2815));
591 printk("\n");
593 return 0;
597 * We accessed the video status signal in the Techwell chip through
598 * iic/i2c because the video status reported by register REG_VI_STATUS1
599 * (address 0x012C) of the SOLO6010 chip doesn't give the correct video
600 * status signal values.
602 int tw28_get_video_status(struct solo6010_dev *solo_dev, u8 ch)
604 u8 val, chip_num;
606 /* Get the right chip and on-chip channel */
607 chip_num = ch / 4;
608 ch %= 4;
610 val = tw_readbyte(solo_dev, chip_num, TW286X_AV_STAT_ADDR,
611 TW_AV_STAT_ADDR) & 0x0f;
613 return val & (1 << ch) ? 1 : 0;
617 int tw28_set_ctrl_val(struct solo6010_dev *solo_dev, u32 ctrl, u8 ch,
618 s32 val)
620 char sval;
621 u8 chip_num;
623 /* Get the right chip and on-chip channel */
624 chip_num = ch / 4;
625 ch %= 4;
627 if (val > 255 || val < 0)
628 return -ERANGE;
630 switch (ctrl) {
631 case V4L2_CID_SHARPNESS:
632 /* Only 286x has sharpness */
633 if (val > 0x0f || val < 0)
634 return -ERANGE;
635 if (is_tw286x(solo_dev, chip_num)) {
636 u8 v = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
637 TW_CHIP_OFFSET_ADDR(chip_num),
638 TW286x_SHARPNESS(chip_num));
639 v &= 0xf0;
640 v |= val;
641 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
642 TW_CHIP_OFFSET_ADDR(chip_num),
643 TW286x_SHARPNESS(chip_num), v);
644 } else if (val != 0)
645 return -ERANGE;
646 break;
648 case V4L2_CID_HUE:
649 if (is_tw286x(solo_dev, chip_num))
650 sval = val - 128;
651 else
652 sval = (char)val;
653 tw_writebyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch),
654 TW_HUE_ADDR(ch), sval);
656 break;
658 case V4L2_CID_SATURATION:
659 if (is_tw286x(solo_dev, chip_num)) {
660 solo_i2c_writebyte(solo_dev, SOLO_I2C_TW,
661 TW_CHIP_OFFSET_ADDR(chip_num),
662 TW286x_SATURATIONU_ADDR(ch), val);
664 tw_writebyte(solo_dev, chip_num, TW286x_SATURATIONV_ADDR(ch),
665 TW_SATURATION_ADDR(ch), val);
667 break;
669 case V4L2_CID_CONTRAST:
670 tw_writebyte(solo_dev, chip_num, TW286x_CONTRAST_ADDR(ch),
671 TW_CONTRAST_ADDR(ch), val);
672 break;
674 case V4L2_CID_BRIGHTNESS:
675 if (is_tw286x(solo_dev, chip_num))
676 sval = val - 128;
677 else
678 sval = (char)val;
679 tw_writebyte(solo_dev, chip_num, TW286x_BRIGHTNESS_ADDR(ch),
680 TW_BRIGHTNESS_ADDR(ch), sval);
682 break;
683 default:
684 return -EINVAL;
687 return 0;
690 int tw28_get_ctrl_val(struct solo6010_dev *solo_dev, u32 ctrl, u8 ch,
691 s32 *val)
693 u8 rval, chip_num;
695 /* Get the right chip and on-chip channel */
696 chip_num = ch / 4;
697 ch %= 4;
699 switch (ctrl) {
700 case V4L2_CID_SHARPNESS:
701 /* Only 286x has sharpness */
702 if (is_tw286x(solo_dev, chip_num)) {
703 rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
704 TW_CHIP_OFFSET_ADDR(chip_num),
705 TW286x_SHARPNESS(chip_num));
706 *val = rval & 0x0f;
707 } else
708 *val = 0;
709 break;
710 case V4L2_CID_HUE:
711 rval = tw_readbyte(solo_dev, chip_num, TW286x_HUE_ADDR(ch),
712 TW_HUE_ADDR(ch));
713 if (is_tw286x(solo_dev, chip_num))
714 *val = (s32)((char)rval) + 128;
715 else
716 *val = rval;
717 break;
718 case V4L2_CID_SATURATION:
719 *val = tw_readbyte(solo_dev, chip_num,
720 TW286x_SATURATIONU_ADDR(ch),
721 TW_SATURATION_ADDR(ch));
722 break;
723 case V4L2_CID_CONTRAST:
724 *val = tw_readbyte(solo_dev, chip_num,
725 TW286x_CONTRAST_ADDR(ch),
726 TW_CONTRAST_ADDR(ch));
727 break;
728 case V4L2_CID_BRIGHTNESS:
729 rval = tw_readbyte(solo_dev, chip_num,
730 TW286x_BRIGHTNESS_ADDR(ch),
731 TW_BRIGHTNESS_ADDR(ch));
732 if (is_tw286x(solo_dev, chip_num))
733 *val = (s32)((char)rval) + 128;
734 else
735 *val = rval;
736 break;
737 default:
738 return -EINVAL;
741 return 0;
745 u8 tw28_get_audio_gain(struct solo6010_dev *solo_dev, u8 ch)
747 u8 val;
748 u8 chip_num;
750 /* Get the right chip and on-chip channel */
751 chip_num = ch / 4;
752 ch %= 4;
754 val = tw_readbyte(solo_dev, chip_num,
755 TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
756 TW_AUDIO_INPUT_GAIN_ADDR(ch));
758 return (ch % 2) ? (val >> 4) : (val & 0x0f);
761 void tw28_set_audio_gain(struct solo6010_dev *solo_dev, u8 ch, u8 val)
763 u8 old_val;
764 u8 chip_num;
766 /* Get the right chip and on-chip channel */
767 chip_num = ch / 4;
768 ch %= 4;
770 old_val = tw_readbyte(solo_dev, chip_num,
771 TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
772 TW_AUDIO_INPUT_GAIN_ADDR(ch));
774 val = (old_val & ((ch % 2) ? 0x0f : 0xf0)) |
775 ((ch % 2) ? (val << 4) : val);
777 tw_writebyte(solo_dev, chip_num, TW286x_AUDIO_INPUT_GAIN_ADDR(ch),
778 TW_AUDIO_INPUT_GAIN_ADDR(ch), val);