blob: ee8ee1d481fa57003e1fdde762d362d15484a4e2 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * av7110_v4l.c: av7110 video4linux interface for DVB and Siemens DVB-C analog module
3 *
4 * Copyright (C) 1999-2002 Ralph Metzler
5 * & Marcus Metzler for convergence integrated media GmbH
6 *
7 * originally based on code by:
8 * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
24 *
Justin P. Mattock631dd1a2010-10-18 11:03:14 +020025 * the project's page is at http://www.linuxtv.org/
Linus Torvalds1da177e2005-04-16 15:20:36 -070026 */
27
Joe Perches44d0b802011-08-21 19:56:44 -030028#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
29
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <linux/types.h>
32#include <linux/delay.h>
33#include <linux/fs.h>
34#include <linux/timer.h>
35#include <linux/poll.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
37#include "av7110.h"
38#include "av7110_hw.h"
39#include "av7110_av.h"
40
41int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val)
42{
43 u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8 , val & 0xff };
Tim Kaiser61391e02006-06-25 09:14:07 -030044 struct i2c_msg msgs = { .flags = 0, .len = 5, .buf = msg };
45
46 switch (av7110->adac_type) {
47 case DVB_ADAC_MSP34x0:
48 msgs.addr = 0x40;
49 break;
50 case DVB_ADAC_MSP34x5:
51 msgs.addr = 0x42;
52 break;
53 default:
54 return 0;
55 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
57 if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) {
58 dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -070059 av7110->dvb_adapter.num, reg, val);
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 return -EIO;
61 }
62 return 0;
63}
64
Johannes Stezenbachd91b7302005-05-16 21:54:38 -070065static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val)
Linus Torvalds1da177e2005-04-16 15:20:36 -070066{
67 u8 msg1[3] = { dev, reg >> 8, reg & 0xff };
68 u8 msg2[2];
69 struct i2c_msg msgs[2] = {
Tim Kaiser61391e02006-06-25 09:14:07 -030070 { .flags = 0 , .len = 3, .buf = msg1 },
71 { .flags = I2C_M_RD, .len = 2, .buf = msg2 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 };
73
Tim Kaiser61391e02006-06-25 09:14:07 -030074 switch (av7110->adac_type) {
75 case DVB_ADAC_MSP34x0:
76 msgs[0].addr = 0x40;
77 msgs[1].addr = 0x40;
78 break;
79 case DVB_ADAC_MSP34x5:
80 msgs[0].addr = 0x42;
81 msgs[1].addr = 0x42;
82 break;
83 default:
84 return 0;
85 }
86
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) {
88 dprintk(1, "dvb-ttpci: failed @ card %d, %u\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -070089 av7110->dvb_adapter.num, reg);
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 return -EIO;
91 }
92 *val = (msg2[0] << 8) | msg2[1];
93 return 0;
94}
95
thomas schorppf63f5342005-09-09 13:03:06 -070096static struct v4l2_input inputs[4] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 {
98 .index = 0,
99 .name = "DVB",
100 .type = V4L2_INPUT_TYPE_CAMERA,
101 .audioset = 1,
102 .tuner = 0, /* ignored */
103 .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
104 .status = 0,
Hans Verkuil657f2272010-12-29 14:29:55 -0300105 .capabilities = V4L2_IN_CAP_STD,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 }, {
107 .index = 1,
108 .name = "Television",
109 .type = V4L2_INPUT_TYPE_TUNER,
110 .audioset = 2,
111 .tuner = 0,
112 .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
113 .status = 0,
Hans Verkuil657f2272010-12-29 14:29:55 -0300114 .capabilities = V4L2_IN_CAP_STD,
thomas schorppf63f5342005-09-09 13:03:06 -0700115 }, {
116 .index = 2,
117 .name = "Video",
118 .type = V4L2_INPUT_TYPE_CAMERA,
119 .audioset = 0,
120 .tuner = 0,
121 .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
122 .status = 0,
Hans Verkuil657f2272010-12-29 14:29:55 -0300123 .capabilities = V4L2_IN_CAP_STD,
thomas schorppf63f5342005-09-09 13:03:06 -0700124 }, {
125 .index = 3,
126 .name = "Y/C",
127 .type = V4L2_INPUT_TYPE_CAMERA,
128 .audioset = 0,
129 .tuner = 0,
130 .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
131 .status = 0,
Hans Verkuil657f2272010-12-29 14:29:55 -0300132 .capabilities = V4L2_IN_CAP_STD,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 }
134};
135
136static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data)
137{
Oliver Endriss36c15f82007-07-23 13:59:55 -0300138 struct av7110 *av7110 = dev->ext_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 u8 buf[] = { 0x00, reg, data };
140 struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
141
142 dprintk(4, "dev: %p\n", dev);
143
Oliver Endriss36c15f82007-07-23 13:59:55 -0300144 if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 return -1;
146 return 0;
147}
148
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4])
150{
Oliver Endriss36c15f82007-07-23 13:59:55 -0300151 struct av7110 *av7110 = dev->ext_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 };
153
154 dprintk(4, "dev: %p\n", dev);
155
Oliver Endriss36c15f82007-07-23 13:59:55 -0300156 if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 return -1;
158 return 0;
159}
160
161static int ves1820_set_tv_freq(struct saa7146_dev *dev, u32 freq)
162{
163 u32 div;
164 u8 config;
165 u8 buf[4];
166
167 dprintk(4, "freq: 0x%08x\n", freq);
168
169 /* magic number: 614. tuning with the frequency given by v4l2
170 is always off by 614*62.5 = 38375 kHz...*/
171 div = freq + 614;
172
173 buf[0] = (div >> 8) & 0x7f;
174 buf[1] = div & 0xff;
175 buf[2] = 0x8e;
176
177 if (freq < (u32) (16 * 168.25))
178 config = 0xa0;
179 else if (freq < (u32) (16 * 447.25))
180 config = 0x90;
181 else
182 config = 0x30;
183 config &= ~0x02;
184
185 buf[3] = config;
186
187 return tuner_write(dev, 0x61, buf);
188}
189
190static int stv0297_set_tv_freq(struct saa7146_dev *dev, u32 freq)
191{
Marco Schluessler89e4d592007-02-13 09:31:07 -0300192 struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 u32 div;
194 u8 data[4];
195
196 div = (freq + 38900000 + 31250) / 62500;
197
198 data[0] = (div >> 8) & 0x7f;
199 data[1] = div & 0xff;
200 data[2] = 0xce;
201
202 if (freq < 45000000)
203 return -EINVAL;
204 else if (freq < 137000000)
205 data[3] = 0x01;
206 else if (freq < 403000000)
207 data[3] = 0x02;
208 else if (freq < 860000000)
209 data[3] = 0x04;
210 else
211 return -EINVAL;
212
Marco Schluessler89e4d592007-02-13 09:31:07 -0300213 if (av7110->fe->ops.i2c_gate_ctrl)
214 av7110->fe->ops.i2c_gate_ctrl(av7110->fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 return tuner_write(dev, 0x63, data);
216}
217
218
219
220static struct saa7146_standard analog_standard[];
221static struct saa7146_standard dvb_standard[];
222static struct saa7146_standard standard[];
223
224static struct v4l2_audio msp3400_v4l2_audio = {
225 .index = 0,
226 .name = "Television",
227 .capability = V4L2_AUDCAP_STEREO
228};
229
230static int av7110_dvb_c_switch(struct saa7146_fh *fh)
231{
232 struct saa7146_dev *dev = fh->dev;
233 struct saa7146_vv *vv = dev->vv_data;
234 struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
235 u16 adswitch;
236 int source, sync, err;
237
238 dprintk(4, "%p\n", av7110);
239
240 if ((vv->video_status & STATUS_OVERLAY) != 0) {
241 vv->ov_suspend = vv->video_fh;
242 err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
243 if (err != 0) {
244 dprintk(2, "suspending video failed\n");
245 vv->ov_suspend = NULL;
246 }
247 }
248
249 if (0 != av7110->current_input) {
thomas schorppf63f5342005-09-09 13:03:06 -0700250 dprintk(1, "switching to analog TV:\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 adswitch = 1;
252 source = SAA7146_HPS_SOURCE_PORT_B;
253 sync = SAA7146_HPS_SYNC_PORT_B;
254 memcpy(standard, analog_standard, sizeof(struct saa7146_standard) * 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
thomas schorppf63f5342005-09-09 13:03:06 -0700256 switch (av7110->current_input) {
257 case 1:
Joe Perches44d0b802011-08-21 19:56:44 -0300258 dprintk(1, "switching SAA7113 to Analog Tuner Input\n");
thomas schorppf63f5342005-09-09 13:03:06 -0700259 msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0000); // loudspeaker source
260 msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0000); // headphone source
261 msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0000); // SCART 1 source
262 msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono
263 msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone
264 msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume
265
266 if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
267 if (ves1820_writereg(dev, 0x09, 0x0f, 0x60))
Joe Perches44d0b802011-08-21 19:56:44 -0300268 dprintk(1, "setting band in demodulator failed\n");
thomas schorppf63f5342005-09-09 13:03:06 -0700269 } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
Marco Schluessler6a857742006-07-10 03:34:16 -0300270 saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9819 pin9(STD)
271 saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9819 pin30(VIF)
thomas schorppf63f5342005-09-09 13:03:06 -0700272 }
273 if (i2c_writereg(av7110, 0x48, 0x02, 0xd0) != 1)
274 dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num);
275 break;
276 case 2:
Joe Perches44d0b802011-08-21 19:56:44 -0300277 dprintk(1, "switching SAA7113 to Video AV CVBS Input\n");
thomas schorppf63f5342005-09-09 13:03:06 -0700278 if (i2c_writereg(av7110, 0x48, 0x02, 0xd2) != 1)
279 dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num);
280 break;
281 case 3:
Joe Perches44d0b802011-08-21 19:56:44 -0300282 dprintk(1, "switching SAA7113 to Video AV Y/C Input\n");
thomas schorppf63f5342005-09-09 13:03:06 -0700283 if (i2c_writereg(av7110, 0x48, 0x02, 0xd9) != 1)
284 dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num);
285 break;
286 default:
Joe Perches44d0b802011-08-21 19:56:44 -0300287 dprintk(1, "switching SAA7113 to Input: AV7110: SAA7113: invalid input\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 }
289 } else {
290 adswitch = 0;
291 source = SAA7146_HPS_SOURCE_PORT_A;
292 sync = SAA7146_HPS_SYNC_PORT_A;
293 memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2);
294 dprintk(1, "switching DVB mode\n");
295 msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source
296 msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source
297 msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source
298 msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono
299 msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone
300 msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume
301
302 if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
303 if (ves1820_writereg(dev, 0x09, 0x0f, 0x20))
Joe Perches44d0b802011-08-21 19:56:44 -0300304 dprintk(1, "setting band in demodulator failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
Marco Schluessler6a857742006-07-10 03:34:16 -0300306 saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD)
307 saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 }
309 }
310
311 /* hmm, this does not do anything!? */
312 if (av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, adswitch))
313 dprintk(1, "ADSwitch error\n");
314
315 saa7146_set_hps_source_and_sync(dev, source, sync);
316
317 if (vv->ov_suspend != NULL) {
318 saa7146_start_preview(vv->ov_suspend);
319 vv->ov_suspend = NULL;
320 }
321
322 return 0;
323}
324
Hans Verkuilb9600742009-01-18 19:59:11 -0300325static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326{
Hans Verkuilb9600742009-01-18 19:59:11 -0300327 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
328 struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
329 u16 stereo_det;
330 s8 stereo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
Hans Verkuilb9600742009-01-18 19:59:11 -0300332 dprintk(2, "VIDIOC_G_TUNER: %d\n", t->index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
Hans Verkuilb9600742009-01-18 19:59:11 -0300334 if (!av7110->analog_tuner_flags || t->index != 0)
335 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
Hans Verkuilb9600742009-01-18 19:59:11 -0300337 memset(t, 0, sizeof(*t));
338 strcpy((char *)t->name, "Television");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
Hans Verkuilb9600742009-01-18 19:59:11 -0300340 t->type = V4L2_TUNER_ANALOG_TV;
341 t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
342 V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
343 t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */
344 t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */
345 /* FIXME: add the real signal strength here */
346 t->signal = 0xffff;
347 t->afc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
Hans Verkuilb9600742009-01-18 19:59:11 -0300349 /* FIXME: standard / stereo detection is still broken */
350 msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det);
351 dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
352 msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det);
353 dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det);
354 stereo = (s8)(stereo_det >> 8);
355 if (stereo > 0x10) {
356 /* stereo */
357 t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
358 t->audmode = V4L2_TUNER_MODE_STEREO;
359 } else if (stereo < -0x10) {
360 /* bilingual */
361 t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
362 t->audmode = V4L2_TUNER_MODE_LANG1;
363 } else /* mono */
364 t->rxsubchans = V4L2_TUNER_SUB_MONO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
Hans Verkuilb9600742009-01-18 19:59:11 -0300366 return 0;
367}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
Hans Verkuilb9600742009-01-18 19:59:11 -0300369static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
370{
371 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
372 struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
373 u16 fm_matrix, src;
374 dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
Hans Verkuilb9600742009-01-18 19:59:11 -0300376 if (!av7110->analog_tuner_flags || av7110->current_input != 1)
377 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
Hans Verkuilb9600742009-01-18 19:59:11 -0300379 switch (t->audmode) {
380 case V4L2_TUNER_MODE_STEREO:
381 dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n");
382 fm_matrix = 0x3001; /* stereo */
383 src = 0x0020;
384 break;
385 case V4L2_TUNER_MODE_LANG1_LANG2:
386 dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n");
387 fm_matrix = 0x3000; /* bilingual */
388 src = 0x0020;
389 break;
390 case V4L2_TUNER_MODE_LANG1:
391 dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n");
392 fm_matrix = 0x3000; /* mono */
393 src = 0x0000;
394 break;
395 case V4L2_TUNER_MODE_LANG2:
396 dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n");
397 fm_matrix = 0x3000; /* mono */
398 src = 0x0010;
399 break;
400 default: /* case V4L2_TUNER_MODE_MONO: */
401 dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n");
402 fm_matrix = 0x3000; /* mono */
403 src = 0x0030;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 break;
405 }
Hans Verkuilb9600742009-01-18 19:59:11 -0300406 msp_writereg(av7110, MSP_WR_DSP, 0x000e, fm_matrix);
407 msp_writereg(av7110, MSP_WR_DSP, 0x0008, src);
408 msp_writereg(av7110, MSP_WR_DSP, 0x0009, src);
409 msp_writereg(av7110, MSP_WR_DSP, 0x000a, src);
410 return 0;
411}
412
413static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
414{
415 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
416 struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
417
Joe Perches44d0b802011-08-21 19:56:44 -0300418 dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x\n", f->frequency);
Hans Verkuilb9600742009-01-18 19:59:11 -0300419
420 if (!av7110->analog_tuner_flags || av7110->current_input != 1)
421 return -EINVAL;
422
423 memset(f, 0, sizeof(*f));
424 f->type = V4L2_TUNER_ANALOG_TV;
425 f->frequency = av7110->current_freq;
426 return 0;
427}
428
429static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
430{
431 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
432 struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
433
Joe Perches44d0b802011-08-21 19:56:44 -0300434 dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x\n", f->frequency);
Hans Verkuilb9600742009-01-18 19:59:11 -0300435
436 if (!av7110->analog_tuner_flags || av7110->current_input != 1)
437 return -EINVAL;
438
439 if (V4L2_TUNER_ANALOG_TV != f->type)
440 return -EINVAL;
441
442 msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); /* fast mute */
443 msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0);
444
445 /* tune in desired frequency */
446 if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820)
447 ves1820_set_tv_freq(dev, f->frequency);
448 else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297)
449 stv0297_set_tv_freq(dev, f->frequency);
450 av7110->current_freq = f->frequency;
451
452 msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); /* start stereo detection */
453 msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x0000);
454 msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); /* loudspeaker + headphone */
455 msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); /* SCART 1 volume */
456 return 0;
457}
458
459static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
460{
461 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
462 struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
463
464 dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index);
465
466 if (av7110->analog_tuner_flags) {
Roel Kluin223ffe52009-05-02 16:38:47 -0300467 if (i->index >= 4)
Hans Verkuilb9600742009-01-18 19:59:11 -0300468 return -EINVAL;
469 } else {
470 if (i->index != 0)
471 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 }
Hans Verkuilb9600742009-01-18 19:59:11 -0300473
474 memcpy(i, &inputs[i->index], sizeof(struct v4l2_input));
475
476 return 0;
477}
478
479static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
480{
481 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
482 struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
483
484 *input = av7110->current_input;
485 dprintk(2, "VIDIOC_G_INPUT: %d\n", *input);
486 return 0;
487}
488
489static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
490{
491 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
492 struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
493
494 dprintk(2, "VIDIOC_S_INPUT: %d\n", input);
495
496 if (!av7110->analog_tuner_flags)
497 return 0;
498
Roel Kluinde81c3c2009-07-02 16:09:25 -0300499 if (input >= 4)
Hans Verkuilb9600742009-01-18 19:59:11 -0300500 return -EINVAL;
501
502 av7110->current_input = input;
503 return av7110_dvb_c_switch(fh);
504}
505
506static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
507{
508 dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index);
509 if (a->index != 0)
510 return -EINVAL;
511 memcpy(a, &msp3400_v4l2_audio, sizeof(struct v4l2_audio));
512 return 0;
513}
514
515static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
516{
517 dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
518 return 0;
519}
520
521static int vidioc_g_sliced_vbi_cap(struct file *file, void *fh,
522 struct v4l2_sliced_vbi_cap *cap)
523{
524 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
525 struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
526
527 dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n");
Hans Verkuilf97d2072009-01-19 04:14:17 -0300528 if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT)
529 return -EINVAL;
Hans Verkuilb9600742009-01-18 19:59:11 -0300530 if (FW_VERSION(av7110->arm_app) >= 0x2623) {
531 cap->service_set = V4L2_SLICED_WSS_625;
532 cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200533 }
Hans Verkuilb9600742009-01-18 19:59:11 -0300534 return 0;
535}
536
537static int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh,
538 struct v4l2_format *f)
539{
540 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
541 struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
542
543 dprintk(2, "VIDIOC_G_FMT:\n");
544 if (FW_VERSION(av7110->arm_app) < 0x2623)
545 return -EINVAL;
546 memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
547 if (av7110->wssMode) {
548 f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
549 f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
550 f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data);
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200551 }
Hans Verkuilb9600742009-01-18 19:59:11 -0300552 return 0;
553}
554
555static int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh,
556 struct v4l2_format *f)
557{
558 struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
559 struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
560
561 dprintk(2, "VIDIOC_S_FMT\n");
562 if (FW_VERSION(av7110->arm_app) < 0x2623)
563 return -EINVAL;
564 if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 &&
565 f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) {
566 memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced));
567 /* WSS controlled by firmware */
568 av7110->wssMode = 0;
569 av7110->wssData = 0;
570 return av7110_fw_cmd(av7110, COMTYPE_ENCODER,
571 SetWSSConfig, 1, 0);
572 } else {
573 memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced));
574 f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
575 f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
576 f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data);
577 /* WSS controlled by userspace */
578 av7110->wssMode = 1;
579 av7110->wssData = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 }
581 return 0;
582}
583
Hans Verkuilbec43662008-12-30 06:58:20 -0300584static int av7110_vbi_reset(struct file *file)
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200585{
586 struct saa7146_fh *fh = file->private_data;
587 struct saa7146_dev *dev = fh->dev;
588 struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
589
Harvey Harrison3ca7fc82008-04-08 23:20:00 -0300590 dprintk(2, "%s\n", __func__);
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200591 av7110->wssMode = 0;
592 av7110->wssData = 0;
593 if (FW_VERSION(av7110->arm_app) < 0x2623)
594 return 0;
595 else
596 return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0);
597}
598
599static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
600{
601 struct saa7146_fh *fh = file->private_data;
602 struct saa7146_dev *dev = fh->dev;
603 struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
604 struct v4l2_sliced_vbi_data d;
605 int rc;
606
Harvey Harrison3ca7fc82008-04-08 23:20:00 -0300607 dprintk(2, "%s\n", __func__);
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200608 if (FW_VERSION(av7110->arm_app) < 0x2623 || !av7110->wssMode || count != sizeof d)
609 return -EINVAL;
610 if (copy_from_user(&d, data, count))
611 return -EFAULT;
612 if ((d.id != 0 && d.id != V4L2_SLICED_WSS_625) || d.field != 0 || d.line != 23)
613 return -EINVAL;
Oliver Endriss4caba422006-03-17 05:29:15 -0300614 if (d.id)
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200615 av7110->wssData = ((d.data[1] << 8) & 0x3f00) | d.data[0];
Oliver Endriss4caba422006-03-17 05:29:15 -0300616 else
617 av7110->wssData = 0x8000;
618 rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 1, av7110->wssData);
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200619 return (rc < 0) ? rc : count;
620}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621
622/****************************************************************************
623 * INITIALIZATION
624 ****************************************************************************/
625
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626static u8 saa7113_init_regs[] = {
627 0x02, 0xd0,
628 0x03, 0x23,
629 0x04, 0x00,
630 0x05, 0x00,
631 0x06, 0xe9,
632 0x07, 0x0d,
633 0x08, 0x98,
634 0x09, 0x02,
635 0x0a, 0x80,
636 0x0b, 0x40,
637 0x0c, 0x40,
638 0x0d, 0x00,
639 0x0e, 0x01,
640 0x0f, 0x7c,
641 0x10, 0x48,
642 0x11, 0x0c,
643 0x12, 0x8b,
644 0x13, 0x1a,
645 0x14, 0x00,
646 0x15, 0x00,
647 0x16, 0x00,
648 0x17, 0x00,
649 0x18, 0x00,
650 0x19, 0x00,
651 0x1a, 0x00,
652 0x1b, 0x00,
653 0x1c, 0x00,
654 0x1d, 0x00,
655 0x1e, 0x00,
656
657 0x41, 0x77,
658 0x42, 0x77,
659 0x43, 0x77,
660 0x44, 0x77,
661 0x45, 0x77,
662 0x46, 0x77,
663 0x47, 0x77,
664 0x48, 0x77,
665 0x49, 0x77,
666 0x4a, 0x77,
667 0x4b, 0x77,
668 0x4c, 0x77,
669 0x4d, 0x77,
670 0x4e, 0x77,
671 0x4f, 0x77,
672 0x50, 0x77,
673 0x51, 0x77,
674 0x52, 0x77,
675 0x53, 0x77,
676 0x54, 0x77,
677 0x55, 0x77,
678 0x56, 0x77,
679 0x57, 0xff,
680
681 0xff
682};
683
684
685static struct saa7146_ext_vv av7110_vv_data_st;
686static struct saa7146_ext_vv av7110_vv_data_c;
687
688int av7110_init_analog_module(struct av7110 *av7110)
689{
690 u16 version1, version2;
691
Tim Kaiser61391e02006-06-25 09:14:07 -0300692 if (i2c_writereg(av7110, 0x80, 0x0, 0x80) == 1 &&
693 i2c_writereg(av7110, 0x80, 0x0, 0) == 1) {
Joe Perches44d0b802011-08-21 19:56:44 -0300694 pr_info("DVB-C analog module @ card %d detected, initializing MSP3400\n",
Tim Kaiser61391e02006-06-25 09:14:07 -0300695 av7110->dvb_adapter.num);
696 av7110->adac_type = DVB_ADAC_MSP34x0;
697 } else if (i2c_writereg(av7110, 0x84, 0x0, 0x80) == 1 &&
698 i2c_writereg(av7110, 0x84, 0x0, 0) == 1) {
Joe Perches44d0b802011-08-21 19:56:44 -0300699 pr_info("DVB-C analog module @ card %d detected, initializing MSP3415\n",
Tim Kaiser61391e02006-06-25 09:14:07 -0300700 av7110->dvb_adapter.num);
701 av7110->adac_type = DVB_ADAC_MSP34x5;
702 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 return -ENODEV;
704
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 msleep(100); // the probing above resets the msp...
706 msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1);
707 msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2);
Tim Kaiser61391e02006-06-25 09:14:07 -0300708 dprintk(1, "dvb-ttpci: @ card %d MSP34xx version 0x%04x 0x%04x\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700709 av7110->dvb_adapter.num, version1, version2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00);
711 msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone
712 msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source
713 msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source
714 msp_writereg(av7110, MSP_WR_DSP, 0x0004, 0x7f00); // loudspeaker volume
715 msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source
716 msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume
Tim Kaiser61391e02006-06-25 09:14:07 -0300717 msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x1900); // prescale SCART
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
719 if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) {
Joe Perches44d0b802011-08-21 19:56:44 -0300720 pr_info("saa7113 not accessible\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 } else {
722 u8 *i = saa7113_init_regs;
723
724 if ((av7110->dev->pci->subsystem_vendor == 0x110a) && (av7110->dev->pci->subsystem_device == 0x0000)) {
725 /* Fujitsu/Siemens DVB-Cable */
726 av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820;
727 } else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x0002)) {
728 /* Hauppauge/TT DVB-C premium */
729 av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820;
730 } else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x000A)) {
731 /* Hauppauge/TT DVB-C premium */
732 av7110->analog_tuner_flags |= ANALOG_TUNER_STV0297;
733 }
734
735 /* setup for DVB by default */
736 if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
737 if (ves1820_writereg(av7110->dev, 0x09, 0x0f, 0x20))
Joe Perches44d0b802011-08-21 19:56:44 -0300738 dprintk(1, "setting band in demodulator failed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
Marco Schluessler6a857742006-07-10 03:34:16 -0300740 saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD)
741 saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 }
743
744 /* init the saa7113 */
745 while (*i != 0xff) {
746 if (i2c_writereg(av7110, 0x48, i[0], i[1]) != 1) {
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700747 dprintk(1, "saa7113 initialization failed @ card %d", av7110->dvb_adapter.num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 break;
749 }
750 i += 2;
751 }
752 /* setup msp for analog sound: B/G Dual-FM */
753 msp_writereg(av7110, MSP_WR_DEM, 0x00bb, 0x02d0); // AD_CV
754 msp_writereg(av7110, MSP_WR_DEM, 0x0001, 3); // FIR1
755 msp_writereg(av7110, MSP_WR_DEM, 0x0001, 18); // FIR1
756 msp_writereg(av7110, MSP_WR_DEM, 0x0001, 27); // FIR1
757 msp_writereg(av7110, MSP_WR_DEM, 0x0001, 48); // FIR1
758 msp_writereg(av7110, MSP_WR_DEM, 0x0001, 66); // FIR1
759 msp_writereg(av7110, MSP_WR_DEM, 0x0001, 72); // FIR1
760 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 4); // FIR2
761 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 64); // FIR2
762 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 0); // FIR2
763 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 3); // FIR2
764 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 18); // FIR2
765 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 27); // FIR2
766 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 48); // FIR2
767 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 66); // FIR2
768 msp_writereg(av7110, MSP_WR_DEM, 0x0005, 72); // FIR2
769 msp_writereg(av7110, MSP_WR_DEM, 0x0083, 0xa000); // MODE_REG
770 msp_writereg(av7110, MSP_WR_DEM, 0x0093, 0x00aa); // DCO1_LO 5.74MHz
771 msp_writereg(av7110, MSP_WR_DEM, 0x009b, 0x04fc); // DCO1_HI
772 msp_writereg(av7110, MSP_WR_DEM, 0x00a3, 0x038e); // DCO2_LO 5.5MHz
773 msp_writereg(av7110, MSP_WR_DEM, 0x00ab, 0x04c6); // DCO2_HI
774 msp_writereg(av7110, MSP_WR_DEM, 0x0056, 0); // LOAD_REG 1/2
775 }
776
777 memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2);
778 /* set dd1 stream a & b */
779 saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000);
780 saa7146_write(av7110->dev, DD1_INIT, 0x03000700);
781 saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
782
783 return 0;
784}
785
786int av7110_init_v4l(struct av7110 *av7110)
787{
788 struct saa7146_dev* dev = av7110->dev;
Hans Verkuilb9600742009-01-18 19:59:11 -0300789 struct saa7146_ext_vv *vv_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 int ret;
791
792 /* special case DVB-C: these cards have an analog tuner
793 plus need some special handling, so we have separate
794 saa7146_ext_vv data for these... */
795 if (av7110->analog_tuner_flags)
Hans Verkuilb9600742009-01-18 19:59:11 -0300796 vv_data = &av7110_vv_data_c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 else
Hans Verkuilb9600742009-01-18 19:59:11 -0300798 vv_data = &av7110_vv_data_st;
799 ret = saa7146_vv_init(dev, vv_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800
801 if (ret) {
Joe Perches44d0b802011-08-21 19:56:44 -0300802 ERR("cannot init capture device. skipping\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 return -ENODEV;
804 }
Hans Verkuilb9600742009-01-18 19:59:11 -0300805 vv_data->ops.vidioc_enum_input = vidioc_enum_input;
806 vv_data->ops.vidioc_g_input = vidioc_g_input;
807 vv_data->ops.vidioc_s_input = vidioc_s_input;
808 vv_data->ops.vidioc_g_tuner = vidioc_g_tuner;
809 vv_data->ops.vidioc_s_tuner = vidioc_s_tuner;
810 vv_data->ops.vidioc_g_frequency = vidioc_g_frequency;
811 vv_data->ops.vidioc_s_frequency = vidioc_s_frequency;
812 vv_data->ops.vidioc_g_audio = vidioc_g_audio;
813 vv_data->ops.vidioc_s_audio = vidioc_s_audio;
814 vv_data->ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap;
815 vv_data->ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out;
816 vv_data->ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817
818 if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) {
Joe Perches44d0b802011-08-21 19:56:44 -0300819 ERR("cannot register capture device. skipping\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 saa7146_vv_release(dev);
821 return -ENODEV;
822 }
Oliver Endriss78577352007-01-27 21:13:06 -0300823 if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI))
Joe Perches44d0b802011-08-21 19:56:44 -0300824 ERR("cannot register vbi v4l2 device. skipping\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 return 0;
826}
827
828int av7110_exit_v4l(struct av7110 *av7110)
829{
Marco Schluesslere19c55f2007-01-31 14:32:29 -0300830 struct saa7146_dev* dev = av7110->dev;
831
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 saa7146_unregister_device(&av7110->v4l_dev, av7110->dev);
Oliver Endriss78577352007-01-27 21:13:06 -0300833 saa7146_unregister_device(&av7110->vbi_dev, av7110->dev);
Marco Schluesslere19c55f2007-01-31 14:32:29 -0300834
835 saa7146_vv_release(dev);
836
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 return 0;
838}
839
840
841
842/* FIXME: these values are experimental values that look better than the
843 values from the latest "official" driver -- at least for me... (MiHu) */
844static struct saa7146_standard standard[] = {
845 {
846 .name = "PAL", .id = V4L2_STD_PAL_BG,
847 .v_offset = 0x15, .v_field = 288,
848 .h_offset = 0x48, .h_pixels = 708,
849 .v_max_out = 576, .h_max_out = 768,
850 }, {
851 .name = "NTSC", .id = V4L2_STD_NTSC,
852 .v_offset = 0x10, .v_field = 244,
853 .h_offset = 0x40, .h_pixels = 708,
854 .v_max_out = 480, .h_max_out = 640,
855 }
856};
857
858static struct saa7146_standard analog_standard[] = {
859 {
860 .name = "PAL", .id = V4L2_STD_PAL_BG,
861 .v_offset = 0x1b, .v_field = 288,
862 .h_offset = 0x08, .h_pixels = 708,
863 .v_max_out = 576, .h_max_out = 768,
864 }, {
865 .name = "NTSC", .id = V4L2_STD_NTSC,
866 .v_offset = 0x10, .v_field = 244,
867 .h_offset = 0x40, .h_pixels = 708,
868 .v_max_out = 480, .h_max_out = 640,
869 }
870};
871
872static struct saa7146_standard dvb_standard[] = {
873 {
874 .name = "PAL", .id = V4L2_STD_PAL_BG,
875 .v_offset = 0x14, .v_field = 288,
876 .h_offset = 0x48, .h_pixels = 708,
877 .v_max_out = 576, .h_max_out = 768,
878 }, {
879 .name = "NTSC", .id = V4L2_STD_NTSC,
880 .v_offset = 0x10, .v_field = 244,
881 .h_offset = 0x40, .h_pixels = 708,
882 .v_max_out = 480, .h_max_out = 640,
883 }
884};
885
886static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
887{
888 struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
889
Johannes Stezenbach4ab3f082005-05-16 21:54:27 -0700890 if (std->id & V4L2_STD_PAL) {
Marco Schluessler58a44042007-10-31 01:20:42 -0300891 av7110->vidmode = AV7110_VIDEO_MODE_PAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 av7110_set_vidmode(av7110, av7110->vidmode);
893 }
Johannes Stezenbach4ab3f082005-05-16 21:54:27 -0700894 else if (std->id & V4L2_STD_NTSC) {
Marco Schluessler58a44042007-10-31 01:20:42 -0300895 av7110->vidmode = AV7110_VIDEO_MODE_NTSC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 av7110_set_vidmode(av7110, av7110->vidmode);
897 }
898 else
899 return -1;
900
901 return 0;
902}
903
904
905static struct saa7146_ext_vv av7110_vv_data_st = {
906 .inputs = 1,
907 .audios = 1,
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200908 .capabilities = V4L2_CAP_SLICED_VBI_OUTPUT,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 .flags = 0,
910
911 .stds = &standard[0],
912 .num_stds = ARRAY_SIZE(standard),
913 .std_callback = &std_callback,
914
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200915 .vbi_fops.open = av7110_vbi_reset,
916 .vbi_fops.release = av7110_vbi_reset,
917 .vbi_fops.write = av7110_vbi_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918};
919
920static struct saa7146_ext_vv av7110_vv_data_c = {
921 .inputs = 1,
922 .audios = 1,
Oliver Endrissd7e7a152006-09-14 00:43:22 -0300923 .capabilities = V4L2_CAP_TUNER | V4L2_CAP_SLICED_VBI_OUTPUT,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 .flags = SAA7146_USE_PORT_B_FOR_VBI,
925
926 .stds = &standard[0],
927 .num_stds = ARRAY_SIZE(standard),
928 .std_callback = &std_callback,
929
Oliver Endriss5b0fa4f2006-01-09 18:21:37 -0200930 .vbi_fops.open = av7110_vbi_reset,
931 .vbi_fops.release = av7110_vbi_reset,
932 .vbi_fops.write = av7110_vbi_write,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933};
934