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>
21 #include "solo6x10.h"
22 #include "tw28.h"
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 
36 static u8 tbl_tw2864_template[] = {
37 	0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x00 */
38 	0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
39 	0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x10 */
40 	0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
41 	0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x20 */
42 	0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
43 	0x00, 0x00, 0x80, 0x10, 0x80, 0x80, 0x00, 0x02, /* 0x30 */
44 	0x12, 0xf5, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
45 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */
46 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
47 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
48 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
50 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
51 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */
52 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0x00,
53 	0x00, 0x02, 0x00, 0xcc, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
54 	0x22, 0x01, 0xd8, 0xbc, 0xb8, 0x44, 0x38, 0x00,
55 	0x00, 0x78, 0x72, 0x3e, 0x14, 0xa5, 0xe4, 0x05, /* 0x90 */
56 	0x00, 0x28, 0x44, 0x44, 0xa0, 0x88, 0x5a, 0x01,
57 	0x08, 0x08, 0x08, 0x08, 0x1a, 0x1a, 0x1a, 0x1a, /* 0xa0 */
58 	0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x44,
59 	0x44, 0x0a, 0x00, 0xff, 0xef, 0xef, 0xef, 0xef, /* 0xb0 */
60 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
62 	0x00, 0x00, 0x55, 0x00, 0xb1, 0xe4, 0x40, 0x00,
63 	0x77, 0x77, 0x01, 0x13, 0x57, 0x9b, 0xdf, 0x20, /* 0xd0 */
64 	0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
65 	0x10, 0xe0, 0xbb, 0xbb, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
66 	0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
67 	0x83, 0xb5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */
68 	0x64, 0x11, 0x40, 0xaf, 0xff, 0x00, 0x00, 0x00,
69 };
70 
71 static u8 tbl_tw2865_ntsc_template[] = {
72 	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x00 */
73 	0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
74 	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x10 */
75 	0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
76 	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x02, /* 0x20 */
77 	0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
78 	0x00, 0xf0, 0x70, 0x48, 0x80, 0x80, 0x00, 0x02, /* 0x30 */
79 	0x12, 0xff, 0x09, 0xd0, 0x00, 0x00, 0x00, 0x7f,
80 	0x00, 0x00, 0x90, 0x68, 0x00, 0x38, 0x80, 0x80, /* 0x40 */
81 	0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
82 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
83 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84 	0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
85 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
86 	0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */
87 	0xE9, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
88 	0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
89 	0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
90 	0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */
91 	0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
92 	0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1B, 0x1A, /* 0xa0 */
93 	0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
94 	0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */
95 	0xFF, 0xE7, 0xE9, 0xE9, 0xEB, 0xFF, 0xD6, 0xD8,
96 	0xD8, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
97 	0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
98 	0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */
99 	0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
100 	0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
101 	0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
102 	0x83, 0xB5, 0x09, 0x78, 0x85, 0x00, 0x01, 0x20, /* 0xf0 */
103 	0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
104 };
105 
106 static u8 tbl_tw2865_pal_template[] = {
107 	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x00 */
108 	0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
109 	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x10 */
110 	0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
111 	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x20 */
112 	0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
113 	0x00, 0xf0, 0x70, 0x30, 0x80, 0x80, 0x00, 0x12, /* 0x30 */
114 	0x11, 0xff, 0x01, 0xc3, 0x00, 0x00, 0x01, 0x7f,
115 	0x00, 0x94, 0x90, 0x48, 0x00, 0x38, 0x7F, 0x80, /* 0x40 */
116 	0x80, 0x80, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00,
117 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
118 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
119 	0x45, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
120 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x43,
121 	0x08, 0x00, 0x00, 0x01, 0xf1, 0x03, 0xEF, 0x03, /* 0x70 */
122 	0xEA, 0x03, 0xD9, 0x15, 0x15, 0xE4, 0xA3, 0x80,
123 	0x00, 0x02, 0x00, 0xCC, 0x00, 0x80, 0x44, 0x50, /* 0x80 */
124 	0x22, 0x01, 0xD8, 0xBC, 0xB8, 0x44, 0x38, 0x00,
125 	0x00, 0x78, 0x44, 0x3D, 0x14, 0xA5, 0xE0, 0x05, /* 0x90 */
126 	0x00, 0x28, 0x44, 0x44, 0xA0, 0x90, 0x52, 0x13,
127 	0x08, 0x08, 0x08, 0x08, 0x1A, 0x1A, 0x1A, 0x1A, /* 0xa0 */
128 	0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0xF0, 0x44,
129 	0x44, 0x4A, 0x00, 0xFF, 0xEF, 0xEF, 0xEF, 0xEF, /* 0xb0 */
130 	0xFF, 0xE7, 0xE9, 0xE9, 0xE9, 0xFF, 0xD7, 0xD8,
131 	0xD9, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
132 	0x00, 0x00, 0x55, 0x00, 0xE4, 0x39, 0x00, 0x80,
133 	0x77, 0x77, 0x03, 0x20, 0x57, 0x9b, 0xdf, 0x31, /* 0xd0 */
134 	0x64, 0xa8, 0xec, 0xd1, 0x0f, 0x11, 0x11, 0x81,
135 	0x10, 0xC0, 0xAA, 0xAA, 0x00, 0x11, 0x00, 0x00, /* 0xe0 */
136 	0x11, 0x00, 0x00, 0x11, 0x00, 0x00, 0x11, 0x00,
137 	0x83, 0xB5, 0x09, 0x00, 0xA0, 0x00, 0x01, 0x20, /* 0xf0 */
138 	0x64, 0x51, 0x40, 0xaf, 0xFF, 0xF0, 0x00, 0xC0,
139 };
140 
141 #define is_tw286x(__solo, __id) (!(__solo->tw2815 & (1 << __id)))
142 
tw_readbyte(struct solo_dev * solo_dev,int chip_id,u8 tw6x_off,u8 tw_off)143 static u8 tw_readbyte(struct solo_dev *solo_dev, int chip_id, u8 tw6x_off,
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 
tw_writebyte(struct solo_dev * solo_dev,int chip_id,u8 tw6x_off,u8 tw_off,u8 val)156 static void tw_writebyte(struct solo_dev *solo_dev, int chip_id,
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 
tw_write_and_verify(struct solo_dev * solo_dev,u8 addr,u8 off,u8 val)169 static void tw_write_and_verify(struct solo_dev *solo_dev, u8 addr, u8 off,
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 
183 /*	printk("solo6x10/tw28: Error writing register: %02x->%02x [%02x]\n",
184 		addr, off, val); */
185 }
186 
tw2865_setup(struct solo_dev * solo_dev,u8 dev_addr)187 static int tw2865_setup(struct solo_dev *solo_dev, u8 dev_addr)
188 {
189 	u8 tbl_tw2865_common[256];
190 	int i;
191 
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));
198 
199 	/* ALINK Mode */
200 	if (solo_dev->nr_chans == 4) {
201 		tbl_tw2865_common[0xd2] = 0x01;
202 		tbl_tw2865_common[0xcf] = 0x00;
203 	} else if (solo_dev->nr_chans == 8) {
204 		tbl_tw2865_common[0xd2] = 0x02;
205 		if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
206 			tbl_tw2865_common[0xcf] = 0x80;
207 	} else if (solo_dev->nr_chans == 16) {
208 		tbl_tw2865_common[0xd2] = 0x03;
209 		if (dev_addr == TW_CHIP_OFFSET_ADDR(1))
210 			tbl_tw2865_common[0xcf] = 0x83;
211 		else if (dev_addr == TW_CHIP_OFFSET_ADDR(2))
212 			tbl_tw2865_common[0xcf] = 0x83;
213 		else if (dev_addr == TW_CHIP_OFFSET_ADDR(3))
214 			tbl_tw2865_common[0xcf] = 0x80;
215 	}
216 
217 	for (i = 0; i < 0xff; i++) {
218 		/* Skip read only registers */
219 		if (i >= 0xb8 && i <= 0xc1)
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 
tw2864_setup(struct solo_dev * solo_dev,u8 dev_addr)237 static int tw2864_setup(struct solo_dev *solo_dev, u8 dev_addr)
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 		}
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 */
304 		if (i >= 0xb8 && i <= 0xc1)
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;
313 		if (i == 0xfd)
314 			continue;
315 
316 		tw_write_and_verify(solo_dev, dev_addr, i,
317 				    tbl_tw2864_common[i]);
318 	}
319 
320 	return 0;
321 }
322 
tw2815_setup(struct solo_dev * solo_dev,u8 dev_addr)323 static int tw2815_setup(struct solo_dev *solo_dev, u8 dev_addr)
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[] = {
336 		0x00, 0x00, 0x00, 0xc0, 0x45, 0xa0, 0xd0, 0x2f, /* 0x00 */
337 		0x64, 0x80, 0x80, 0x82, 0x82, 0x00, 0x00, 0x00,
338 		0x00, 0x0f, 0x05, 0x00, 0x00, 0x80, 0x06, 0x00, /* 0x10 */
339 		0x00, 0x00, 0x00, 0xff, 0x8f, 0x00, 0x00, 0x00,
340 		0x88, 0x88, 0xc0, 0x00, 0x20, 0x64, 0xa8, 0xec, /* 0x20 */
341 		0x31, 0x75, 0xb9, 0xfd, 0x00, 0x00, 0x88, 0x88,
342 		0x88, 0x11, 0x00, 0x88, 0x88, 0x00,		/* 0x30 */
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)
461 				continue;	/* read-only */
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 
saa7128_setup(struct solo_dev * solo_dev)484 static void saa7128_setup(struct solo_dev *solo_dev)
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 
solo_tw28_init(struct solo_dev * solo_dev)542 int solo_tw28_init(struct solo_dev *solo_dev)
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:
554 			solo_dev->tw2865 |= 1 << i;
555 			solo_dev->tw28_cnt++;
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++) {
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)))
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 
588 	if (solo_dev->tw2865)
589 		printk(" tw2865[%d]", hweight32(solo_dev->tw2865));
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 
599 /*
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  */
tw28_get_video_status(struct solo_dev * solo_dev,u8 ch)605 int tw28_get_video_status(struct solo_dev *solo_dev, u8 ch)
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. */
622 u16 tw28_get_audio_status(struct solo_dev *solo_dev)
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 
tw28_set_ctrl_val(struct solo_dev * solo_dev,u32 ctrl,u8 ch,s32 val)638 int tw28_set_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch, s32 val)
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 
tw28_get_ctrl_val(struct solo_dev * solo_dev,u32 ctrl,u8 ch,s32 * val)710 int tw28_get_ctrl_val(struct solo_dev *solo_dev, u32 ctrl, u8 ch,
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)) {
723 			rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW,
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));
752 		if (is_tw286x(solo_dev, chip_num))
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  */
770 void tw2815_Set_AudioOutVol(struct solo_dev *solo_dev, unsigned int u_val)
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 
tw28_get_audio_gain(struct solo_dev * solo_dev,u8 ch)787 u8 tw28_get_audio_gain(struct solo_dev *solo_dev, u8 ch)
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 
tw28_set_audio_gain(struct solo_dev * solo_dev,u8 ch,u8 val)803 void tw28_set_audio_gain(struct solo_dev *solo_dev, u8 ch, u8 val)
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 }
822