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