xref: /OK3568_Linux_fs/kernel/drivers/media/pci/ttpci/av7110_v4l.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * av7110_v4l.c: av7110 video4linux interface for DVB and Siemens DVB-C analog module
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 1999-2002 Ralph  Metzler
6*4882a593Smuzhiyun  *                       & Marcus Metzler for convergence integrated media GmbH
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * originally based on code by:
9*4882a593Smuzhiyun  * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * the project's page is at https://linuxtv.org
12*4882a593Smuzhiyun  */
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include <linux/kernel.h>
17*4882a593Smuzhiyun #include <linux/types.h>
18*4882a593Smuzhiyun #include <linux/delay.h>
19*4882a593Smuzhiyun #include <linux/fs.h>
20*4882a593Smuzhiyun #include <linux/timer.h>
21*4882a593Smuzhiyun #include <linux/poll.h>
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #include "av7110.h"
24*4882a593Smuzhiyun #include "av7110_hw.h"
25*4882a593Smuzhiyun #include "av7110_av.h"
26*4882a593Smuzhiyun 
msp_writereg(struct av7110 * av7110,u8 dev,u16 reg,u16 val)27*4882a593Smuzhiyun int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun 	u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8 , val & 0xff };
30*4882a593Smuzhiyun 	struct i2c_msg msgs = { .flags = 0, .len = 5, .buf = msg };
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 	switch (av7110->adac_type) {
33*4882a593Smuzhiyun 	case DVB_ADAC_MSP34x0:
34*4882a593Smuzhiyun 		msgs.addr = 0x40;
35*4882a593Smuzhiyun 		break;
36*4882a593Smuzhiyun 	case DVB_ADAC_MSP34x5:
37*4882a593Smuzhiyun 		msgs.addr = 0x42;
38*4882a593Smuzhiyun 		break;
39*4882a593Smuzhiyun 	default:
40*4882a593Smuzhiyun 		return 0;
41*4882a593Smuzhiyun 	}
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) {
44*4882a593Smuzhiyun 		dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n",
45*4882a593Smuzhiyun 		       av7110->dvb_adapter.num, reg, val);
46*4882a593Smuzhiyun 		return -EIO;
47*4882a593Smuzhiyun 	}
48*4882a593Smuzhiyun 	return 0;
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun 
msp_readreg(struct av7110 * av7110,u8 dev,u16 reg,u16 * val)51*4882a593Smuzhiyun static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun 	u8 msg1[3] = { dev, reg >> 8, reg & 0xff };
54*4882a593Smuzhiyun 	u8 msg2[2];
55*4882a593Smuzhiyun 	struct i2c_msg msgs[2] = {
56*4882a593Smuzhiyun 		{ .flags = 0	   , .len = 3, .buf = msg1 },
57*4882a593Smuzhiyun 		{ .flags = I2C_M_RD, .len = 2, .buf = msg2 }
58*4882a593Smuzhiyun 	};
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	switch (av7110->adac_type) {
61*4882a593Smuzhiyun 	case DVB_ADAC_MSP34x0:
62*4882a593Smuzhiyun 		msgs[0].addr = 0x40;
63*4882a593Smuzhiyun 		msgs[1].addr = 0x40;
64*4882a593Smuzhiyun 		break;
65*4882a593Smuzhiyun 	case DVB_ADAC_MSP34x5:
66*4882a593Smuzhiyun 		msgs[0].addr = 0x42;
67*4882a593Smuzhiyun 		msgs[1].addr = 0x42;
68*4882a593Smuzhiyun 		break;
69*4882a593Smuzhiyun 	default:
70*4882a593Smuzhiyun 		return 0;
71*4882a593Smuzhiyun 	}
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) {
74*4882a593Smuzhiyun 		dprintk(1, "dvb-ttpci: failed @ card %d, %u\n",
75*4882a593Smuzhiyun 		       av7110->dvb_adapter.num, reg);
76*4882a593Smuzhiyun 		return -EIO;
77*4882a593Smuzhiyun 	}
78*4882a593Smuzhiyun 	*val = (msg2[0] << 8) | msg2[1];
79*4882a593Smuzhiyun 	return 0;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun static struct v4l2_input inputs[4] = {
83*4882a593Smuzhiyun 	{
84*4882a593Smuzhiyun 		.index		= 0,
85*4882a593Smuzhiyun 		.name		= "DVB",
86*4882a593Smuzhiyun 		.type		= V4L2_INPUT_TYPE_CAMERA,
87*4882a593Smuzhiyun 		.audioset	= 1,
88*4882a593Smuzhiyun 		.tuner		= 0, /* ignored */
89*4882a593Smuzhiyun 		.std		= V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
90*4882a593Smuzhiyun 		.status		= 0,
91*4882a593Smuzhiyun 		.capabilities	= V4L2_IN_CAP_STD,
92*4882a593Smuzhiyun 	}, {
93*4882a593Smuzhiyun 		.index		= 1,
94*4882a593Smuzhiyun 		.name		= "Television",
95*4882a593Smuzhiyun 		.type		= V4L2_INPUT_TYPE_TUNER,
96*4882a593Smuzhiyun 		.audioset	= 1,
97*4882a593Smuzhiyun 		.tuner		= 0,
98*4882a593Smuzhiyun 		.std		= V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
99*4882a593Smuzhiyun 		.status		= 0,
100*4882a593Smuzhiyun 		.capabilities	= V4L2_IN_CAP_STD,
101*4882a593Smuzhiyun 	}, {
102*4882a593Smuzhiyun 		.index		= 2,
103*4882a593Smuzhiyun 		.name		= "Video",
104*4882a593Smuzhiyun 		.type		= V4L2_INPUT_TYPE_CAMERA,
105*4882a593Smuzhiyun 		.audioset	= 0,
106*4882a593Smuzhiyun 		.tuner		= 0,
107*4882a593Smuzhiyun 		.std		= V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
108*4882a593Smuzhiyun 		.status		= 0,
109*4882a593Smuzhiyun 		.capabilities	= V4L2_IN_CAP_STD,
110*4882a593Smuzhiyun 	}, {
111*4882a593Smuzhiyun 		.index		= 3,
112*4882a593Smuzhiyun 		.name		= "Y/C",
113*4882a593Smuzhiyun 		.type		= V4L2_INPUT_TYPE_CAMERA,
114*4882a593Smuzhiyun 		.audioset	= 0,
115*4882a593Smuzhiyun 		.tuner		= 0,
116*4882a593Smuzhiyun 		.std		= V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
117*4882a593Smuzhiyun 		.status		= 0,
118*4882a593Smuzhiyun 		.capabilities	= V4L2_IN_CAP_STD,
119*4882a593Smuzhiyun 	}
120*4882a593Smuzhiyun };
121*4882a593Smuzhiyun 
ves1820_writereg(struct saa7146_dev * dev,u8 addr,u8 reg,u8 data)122*4882a593Smuzhiyun static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun 	struct av7110 *av7110 = dev->ext_priv;
125*4882a593Smuzhiyun 	u8 buf[] = { 0x00, reg, data };
126*4882a593Smuzhiyun 	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	dprintk(4, "dev: %p\n", dev);
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1))
131*4882a593Smuzhiyun 		return -1;
132*4882a593Smuzhiyun 	return 0;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
tuner_write(struct saa7146_dev * dev,u8 addr,u8 data[4])135*4882a593Smuzhiyun static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4])
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun 	struct av7110 *av7110 = dev->ext_priv;
138*4882a593Smuzhiyun 	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 };
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	dprintk(4, "dev: %p\n", dev);
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1))
143*4882a593Smuzhiyun 		return -1;
144*4882a593Smuzhiyun 	return 0;
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun 
ves1820_set_tv_freq(struct saa7146_dev * dev,u32 freq)147*4882a593Smuzhiyun static int ves1820_set_tv_freq(struct saa7146_dev *dev, u32 freq)
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun 	u32 div;
150*4882a593Smuzhiyun 	u8 config;
151*4882a593Smuzhiyun 	u8 buf[4];
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	dprintk(4, "freq: 0x%08x\n", freq);
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	/* magic number: 614. tuning with the frequency given by v4l2
156*4882a593Smuzhiyun 	   is always off by 614*62.5 = 38375 kHz...*/
157*4882a593Smuzhiyun 	div = freq + 614;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	buf[0] = (div >> 8) & 0x7f;
160*4882a593Smuzhiyun 	buf[1] = div & 0xff;
161*4882a593Smuzhiyun 	buf[2] = 0x8e;
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	if (freq < 16U * 16825 / 100)
164*4882a593Smuzhiyun 		config = 0xa0;
165*4882a593Smuzhiyun 	else if (freq < 16U * 44725 / 100)
166*4882a593Smuzhiyun 		config = 0x90;
167*4882a593Smuzhiyun 	else
168*4882a593Smuzhiyun 		config = 0x30;
169*4882a593Smuzhiyun 	config &= ~0x02;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	buf[3] = config;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	return tuner_write(dev, 0x61, buf);
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun 
stv0297_set_tv_freq(struct saa7146_dev * dev,u32 freq)176*4882a593Smuzhiyun static int stv0297_set_tv_freq(struct saa7146_dev *dev, u32 freq)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun 	struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
179*4882a593Smuzhiyun 	u32 div;
180*4882a593Smuzhiyun 	u8 data[4];
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	div = (freq + 38900000 + 31250) / 62500;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	data[0] = (div >> 8) & 0x7f;
185*4882a593Smuzhiyun 	data[1] = div & 0xff;
186*4882a593Smuzhiyun 	data[2] = 0xce;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	if (freq < 45000000)
189*4882a593Smuzhiyun 		return -EINVAL;
190*4882a593Smuzhiyun 	else if (freq < 137000000)
191*4882a593Smuzhiyun 		data[3] = 0x01;
192*4882a593Smuzhiyun 	else if (freq < 403000000)
193*4882a593Smuzhiyun 		data[3] = 0x02;
194*4882a593Smuzhiyun 	else if (freq < 860000000)
195*4882a593Smuzhiyun 		data[3] = 0x04;
196*4882a593Smuzhiyun 	else
197*4882a593Smuzhiyun 		return -EINVAL;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	if (av7110->fe->ops.i2c_gate_ctrl)
200*4882a593Smuzhiyun 		av7110->fe->ops.i2c_gate_ctrl(av7110->fe, 1);
201*4882a593Smuzhiyun 	return tuner_write(dev, 0x63, data);
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun static struct saa7146_standard analog_standard[];
207*4882a593Smuzhiyun static struct saa7146_standard dvb_standard[];
208*4882a593Smuzhiyun static struct saa7146_standard standard[];
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun static const struct v4l2_audio msp3400_v4l2_audio = {
211*4882a593Smuzhiyun 	.index = 0,
212*4882a593Smuzhiyun 	.name = "Television",
213*4882a593Smuzhiyun 	.capability = V4L2_AUDCAP_STEREO
214*4882a593Smuzhiyun };
215*4882a593Smuzhiyun 
av7110_dvb_c_switch(struct saa7146_fh * fh)216*4882a593Smuzhiyun static int av7110_dvb_c_switch(struct saa7146_fh *fh)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun 	struct saa7146_dev *dev = fh->dev;
219*4882a593Smuzhiyun 	struct saa7146_vv *vv = dev->vv_data;
220*4882a593Smuzhiyun 	struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
221*4882a593Smuzhiyun 	u16 adswitch;
222*4882a593Smuzhiyun 	int source, sync, err;
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	dprintk(4, "%p\n", av7110);
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	if ((vv->video_status & STATUS_OVERLAY) != 0) {
227*4882a593Smuzhiyun 		vv->ov_suspend = vv->video_fh;
228*4882a593Smuzhiyun 		err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */
229*4882a593Smuzhiyun 		if (err != 0) {
230*4882a593Smuzhiyun 			dprintk(2, "suspending video failed\n");
231*4882a593Smuzhiyun 			vv->ov_suspend = NULL;
232*4882a593Smuzhiyun 		}
233*4882a593Smuzhiyun 	}
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	if (0 != av7110->current_input) {
236*4882a593Smuzhiyun 		dprintk(1, "switching to analog TV:\n");
237*4882a593Smuzhiyun 		adswitch = 1;
238*4882a593Smuzhiyun 		source = SAA7146_HPS_SOURCE_PORT_B;
239*4882a593Smuzhiyun 		sync = SAA7146_HPS_SYNC_PORT_B;
240*4882a593Smuzhiyun 		memcpy(standard, analog_standard, sizeof(struct saa7146_standard) * 2);
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 		switch (av7110->current_input) {
243*4882a593Smuzhiyun 		case 1:
244*4882a593Smuzhiyun 			dprintk(1, "switching SAA7113 to Analog Tuner Input\n");
245*4882a593Smuzhiyun 			msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0000); // loudspeaker source
246*4882a593Smuzhiyun 			msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0000); // headphone source
247*4882a593Smuzhiyun 			msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0000); // SCART 1 source
248*4882a593Smuzhiyun 			msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono
249*4882a593Smuzhiyun 			msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone
250*4882a593Smuzhiyun 			msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 			if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
253*4882a593Smuzhiyun 				if (ves1820_writereg(dev, 0x09, 0x0f, 0x60))
254*4882a593Smuzhiyun 					dprintk(1, "setting band in demodulator failed\n");
255*4882a593Smuzhiyun 			} else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
256*4882a593Smuzhiyun 				saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9819 pin9(STD)
257*4882a593Smuzhiyun 				saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9819 pin30(VIF)
258*4882a593Smuzhiyun 			}
259*4882a593Smuzhiyun 			if (i2c_writereg(av7110, 0x48, 0x02, 0xd0) != 1)
260*4882a593Smuzhiyun 				dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num);
261*4882a593Smuzhiyun 			break;
262*4882a593Smuzhiyun 		case 2:
263*4882a593Smuzhiyun 			dprintk(1, "switching SAA7113 to Video AV CVBS Input\n");
264*4882a593Smuzhiyun 			if (i2c_writereg(av7110, 0x48, 0x02, 0xd2) != 1)
265*4882a593Smuzhiyun 				dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num);
266*4882a593Smuzhiyun 			break;
267*4882a593Smuzhiyun 		case 3:
268*4882a593Smuzhiyun 			dprintk(1, "switching SAA7113 to Video AV Y/C Input\n");
269*4882a593Smuzhiyun 			if (i2c_writereg(av7110, 0x48, 0x02, 0xd9) != 1)
270*4882a593Smuzhiyun 				dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num);
271*4882a593Smuzhiyun 			break;
272*4882a593Smuzhiyun 		default:
273*4882a593Smuzhiyun 			dprintk(1, "switching SAA7113 to Input: AV7110: SAA7113: invalid input\n");
274*4882a593Smuzhiyun 		}
275*4882a593Smuzhiyun 	} else {
276*4882a593Smuzhiyun 		adswitch = 0;
277*4882a593Smuzhiyun 		source = SAA7146_HPS_SOURCE_PORT_A;
278*4882a593Smuzhiyun 		sync = SAA7146_HPS_SYNC_PORT_A;
279*4882a593Smuzhiyun 		memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2);
280*4882a593Smuzhiyun 		dprintk(1, "switching DVB mode\n");
281*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source
282*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source
283*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source
284*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DSP, 0x000e, 0x3000); // FM matrix, mono
285*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone
286*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 		if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
289*4882a593Smuzhiyun 			if (ves1820_writereg(dev, 0x09, 0x0f, 0x20))
290*4882a593Smuzhiyun 				dprintk(1, "setting band in demodulator failed\n");
291*4882a593Smuzhiyun 		} else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
292*4882a593Smuzhiyun 			saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD)
293*4882a593Smuzhiyun 			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF)
294*4882a593Smuzhiyun 		}
295*4882a593Smuzhiyun 	}
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	/* hmm, this does not do anything!? */
298*4882a593Smuzhiyun 	if (av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, adswitch))
299*4882a593Smuzhiyun 		dprintk(1, "ADSwitch error\n");
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	saa7146_set_hps_source_and_sync(dev, source, sync);
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	if (vv->ov_suspend != NULL) {
304*4882a593Smuzhiyun 		saa7146_start_preview(vv->ov_suspend);
305*4882a593Smuzhiyun 		vv->ov_suspend = NULL;
306*4882a593Smuzhiyun 	}
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	return 0;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun 
vidioc_g_tuner(struct file * file,void * fh,struct v4l2_tuner * t)311*4882a593Smuzhiyun static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
314*4882a593Smuzhiyun 	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
315*4882a593Smuzhiyun 	u16 stereo_det;
316*4882a593Smuzhiyun 	s8 stereo;
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	dprintk(2, "VIDIOC_G_TUNER: %d\n", t->index);
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	if (!av7110->analog_tuner_flags || t->index != 0)
321*4882a593Smuzhiyun 		return -EINVAL;
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	memset(t, 0, sizeof(*t));
324*4882a593Smuzhiyun 	strscpy((char *)t->name, "Television", sizeof(t->name));
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	t->type = V4L2_TUNER_ANALOG_TV;
327*4882a593Smuzhiyun 	t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
328*4882a593Smuzhiyun 		V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
329*4882a593Smuzhiyun 	t->rangelow = 772;	/* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */
330*4882a593Smuzhiyun 	t->rangehigh = 13684;	/* 855.25 MHz / 62.5 kHz = 13684 */
331*4882a593Smuzhiyun 	/* FIXME: add the real signal strength here */
332*4882a593Smuzhiyun 	t->signal = 0xffff;
333*4882a593Smuzhiyun 	t->afc = 0;
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	/* FIXME: standard / stereo detection is still broken */
336*4882a593Smuzhiyun 	msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det);
337*4882a593Smuzhiyun 	dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
338*4882a593Smuzhiyun 	msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det);
339*4882a593Smuzhiyun 	dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det);
340*4882a593Smuzhiyun 	stereo = (s8)(stereo_det >> 8);
341*4882a593Smuzhiyun 	if (stereo > 0x10) {
342*4882a593Smuzhiyun 		/* stereo */
343*4882a593Smuzhiyun 		t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
344*4882a593Smuzhiyun 		t->audmode = V4L2_TUNER_MODE_STEREO;
345*4882a593Smuzhiyun 	} else if (stereo < -0x10) {
346*4882a593Smuzhiyun 		/* bilingual */
347*4882a593Smuzhiyun 		t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
348*4882a593Smuzhiyun 		t->audmode = V4L2_TUNER_MODE_LANG1;
349*4882a593Smuzhiyun 	} else /* mono */
350*4882a593Smuzhiyun 		t->rxsubchans = V4L2_TUNER_SUB_MONO;
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	return 0;
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun 
vidioc_s_tuner(struct file * file,void * fh,const struct v4l2_tuner * t)355*4882a593Smuzhiyun static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *t)
356*4882a593Smuzhiyun {
357*4882a593Smuzhiyun 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
358*4882a593Smuzhiyun 	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
359*4882a593Smuzhiyun 	u16 fm_matrix, src;
360*4882a593Smuzhiyun 	dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index);
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	if (!av7110->analog_tuner_flags || av7110->current_input != 1)
363*4882a593Smuzhiyun 		return -EINVAL;
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	switch (t->audmode) {
366*4882a593Smuzhiyun 	case V4L2_TUNER_MODE_STEREO:
367*4882a593Smuzhiyun 		dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n");
368*4882a593Smuzhiyun 		fm_matrix = 0x3001; /* stereo */
369*4882a593Smuzhiyun 		src = 0x0020;
370*4882a593Smuzhiyun 		break;
371*4882a593Smuzhiyun 	case V4L2_TUNER_MODE_LANG1_LANG2:
372*4882a593Smuzhiyun 		dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n");
373*4882a593Smuzhiyun 		fm_matrix = 0x3000; /* bilingual */
374*4882a593Smuzhiyun 		src = 0x0020;
375*4882a593Smuzhiyun 		break;
376*4882a593Smuzhiyun 	case V4L2_TUNER_MODE_LANG1:
377*4882a593Smuzhiyun 		dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n");
378*4882a593Smuzhiyun 		fm_matrix = 0x3000; /* mono */
379*4882a593Smuzhiyun 		src = 0x0000;
380*4882a593Smuzhiyun 		break;
381*4882a593Smuzhiyun 	case V4L2_TUNER_MODE_LANG2:
382*4882a593Smuzhiyun 		dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n");
383*4882a593Smuzhiyun 		fm_matrix = 0x3000; /* mono */
384*4882a593Smuzhiyun 		src = 0x0010;
385*4882a593Smuzhiyun 		break;
386*4882a593Smuzhiyun 	default: /* case V4L2_TUNER_MODE_MONO: */
387*4882a593Smuzhiyun 		dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n");
388*4882a593Smuzhiyun 		fm_matrix = 0x3000; /* mono */
389*4882a593Smuzhiyun 		src = 0x0030;
390*4882a593Smuzhiyun 		break;
391*4882a593Smuzhiyun 	}
392*4882a593Smuzhiyun 	msp_writereg(av7110, MSP_WR_DSP, 0x000e, fm_matrix);
393*4882a593Smuzhiyun 	msp_writereg(av7110, MSP_WR_DSP, 0x0008, src);
394*4882a593Smuzhiyun 	msp_writereg(av7110, MSP_WR_DSP, 0x0009, src);
395*4882a593Smuzhiyun 	msp_writereg(av7110, MSP_WR_DSP, 0x000a, src);
396*4882a593Smuzhiyun 	return 0;
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun 
vidioc_g_frequency(struct file * file,void * fh,struct v4l2_frequency * f)399*4882a593Smuzhiyun static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
400*4882a593Smuzhiyun {
401*4882a593Smuzhiyun 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
402*4882a593Smuzhiyun 	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x\n", f->frequency);
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	if (!av7110->analog_tuner_flags || av7110->current_input != 1)
407*4882a593Smuzhiyun 		return -EINVAL;
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	memset(f, 0, sizeof(*f));
410*4882a593Smuzhiyun 	f->type = V4L2_TUNER_ANALOG_TV;
411*4882a593Smuzhiyun 	f->frequency =	av7110->current_freq;
412*4882a593Smuzhiyun 	return 0;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun 
vidioc_s_frequency(struct file * file,void * fh,const struct v4l2_frequency * f)415*4882a593Smuzhiyun static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *f)
416*4882a593Smuzhiyun {
417*4882a593Smuzhiyun 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
418*4882a593Smuzhiyun 	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x\n", f->frequency);
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	if (!av7110->analog_tuner_flags || av7110->current_input != 1)
423*4882a593Smuzhiyun 		return -EINVAL;
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	if (V4L2_TUNER_ANALOG_TV != f->type)
426*4882a593Smuzhiyun 		return -EINVAL;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); /* fast mute */
429*4882a593Smuzhiyun 	msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0);
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	/* tune in desired frequency */
432*4882a593Smuzhiyun 	if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820)
433*4882a593Smuzhiyun 		ves1820_set_tv_freq(dev, f->frequency);
434*4882a593Smuzhiyun 	else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297)
435*4882a593Smuzhiyun 		stv0297_set_tv_freq(dev, f->frequency);
436*4882a593Smuzhiyun 	av7110->current_freq = f->frequency;
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun 	msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); /* start stereo detection */
439*4882a593Smuzhiyun 	msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x0000);
440*4882a593Smuzhiyun 	msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); /* loudspeaker + headphone */
441*4882a593Smuzhiyun 	msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); /* SCART 1 volume */
442*4882a593Smuzhiyun 	return 0;
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun 
vidioc_enum_input(struct file * file,void * fh,struct v4l2_input * i)445*4882a593Smuzhiyun static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
446*4882a593Smuzhiyun {
447*4882a593Smuzhiyun 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
448*4882a593Smuzhiyun 	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 	dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index);
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	if (av7110->analog_tuner_flags) {
453*4882a593Smuzhiyun 		if (i->index >= 4)
454*4882a593Smuzhiyun 			return -EINVAL;
455*4882a593Smuzhiyun 	} else {
456*4882a593Smuzhiyun 		if (i->index != 0)
457*4882a593Smuzhiyun 			return -EINVAL;
458*4882a593Smuzhiyun 	}
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	memcpy(i, &inputs[i->index], sizeof(struct v4l2_input));
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	return 0;
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun 
vidioc_g_input(struct file * file,void * fh,unsigned int * input)465*4882a593Smuzhiyun static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
466*4882a593Smuzhiyun {
467*4882a593Smuzhiyun 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
468*4882a593Smuzhiyun 	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 	*input = av7110->current_input;
471*4882a593Smuzhiyun 	dprintk(2, "VIDIOC_G_INPUT: %d\n", *input);
472*4882a593Smuzhiyun 	return 0;
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun 
vidioc_s_input(struct file * file,void * fh,unsigned int input)475*4882a593Smuzhiyun static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
476*4882a593Smuzhiyun {
477*4882a593Smuzhiyun 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
478*4882a593Smuzhiyun 	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	dprintk(2, "VIDIOC_S_INPUT: %d\n", input);
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	if (!av7110->analog_tuner_flags)
483*4882a593Smuzhiyun 		return input ? -EINVAL : 0;
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	if (input >= 4)
486*4882a593Smuzhiyun 		return -EINVAL;
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 	av7110->current_input = input;
489*4882a593Smuzhiyun 	return av7110_dvb_c_switch(fh);
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun 
vidioc_enumaudio(struct file * file,void * fh,struct v4l2_audio * a)492*4882a593Smuzhiyun static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a)
493*4882a593Smuzhiyun {
494*4882a593Smuzhiyun 	dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index);
495*4882a593Smuzhiyun 	if (a->index != 0)
496*4882a593Smuzhiyun 		return -EINVAL;
497*4882a593Smuzhiyun 	*a = msp3400_v4l2_audio;
498*4882a593Smuzhiyun 	return 0;
499*4882a593Smuzhiyun }
500*4882a593Smuzhiyun 
vidioc_g_audio(struct file * file,void * fh,struct v4l2_audio * a)501*4882a593Smuzhiyun static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
502*4882a593Smuzhiyun {
503*4882a593Smuzhiyun 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
504*4882a593Smuzhiyun 	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index);
507*4882a593Smuzhiyun 	if (a->index != 0)
508*4882a593Smuzhiyun 		return -EINVAL;
509*4882a593Smuzhiyun 	if (av7110->current_input >= 2)
510*4882a593Smuzhiyun 		return -EINVAL;
511*4882a593Smuzhiyun 	*a = msp3400_v4l2_audio;
512*4882a593Smuzhiyun 	return 0;
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun 
vidioc_s_audio(struct file * file,void * fh,const struct v4l2_audio * a)515*4882a593Smuzhiyun static int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *a)
516*4882a593Smuzhiyun {
517*4882a593Smuzhiyun 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
518*4882a593Smuzhiyun 	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
521*4882a593Smuzhiyun 	if (av7110->current_input >= 2)
522*4882a593Smuzhiyun 		return -EINVAL;
523*4882a593Smuzhiyun 	return a->index ? -EINVAL : 0;
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun 
vidioc_g_sliced_vbi_cap(struct file * file,void * fh,struct v4l2_sliced_vbi_cap * cap)526*4882a593Smuzhiyun static int vidioc_g_sliced_vbi_cap(struct file *file, void *fh,
527*4882a593Smuzhiyun 					struct v4l2_sliced_vbi_cap *cap)
528*4882a593Smuzhiyun {
529*4882a593Smuzhiyun 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
530*4882a593Smuzhiyun 	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 	dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n");
533*4882a593Smuzhiyun 	if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT)
534*4882a593Smuzhiyun 		return -EINVAL;
535*4882a593Smuzhiyun 	if (FW_VERSION(av7110->arm_app) >= 0x2623) {
536*4882a593Smuzhiyun 		cap->service_set = V4L2_SLICED_WSS_625;
537*4882a593Smuzhiyun 		cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
538*4882a593Smuzhiyun 	}
539*4882a593Smuzhiyun 	return 0;
540*4882a593Smuzhiyun }
541*4882a593Smuzhiyun 
vidioc_g_fmt_sliced_vbi_out(struct file * file,void * fh,struct v4l2_format * f)542*4882a593Smuzhiyun static int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh,
543*4882a593Smuzhiyun 					struct v4l2_format *f)
544*4882a593Smuzhiyun {
545*4882a593Smuzhiyun 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
546*4882a593Smuzhiyun 	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	dprintk(2, "VIDIOC_G_FMT:\n");
549*4882a593Smuzhiyun 	if (FW_VERSION(av7110->arm_app) < 0x2623)
550*4882a593Smuzhiyun 		return -EINVAL;
551*4882a593Smuzhiyun 	memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
552*4882a593Smuzhiyun 	if (av7110->wssMode) {
553*4882a593Smuzhiyun 		f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
554*4882a593Smuzhiyun 		f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
555*4882a593Smuzhiyun 		f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data);
556*4882a593Smuzhiyun 	}
557*4882a593Smuzhiyun 	return 0;
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun 
vidioc_s_fmt_sliced_vbi_out(struct file * file,void * fh,struct v4l2_format * f)560*4882a593Smuzhiyun static int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh,
561*4882a593Smuzhiyun 					struct v4l2_format *f)
562*4882a593Smuzhiyun {
563*4882a593Smuzhiyun 	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
564*4882a593Smuzhiyun 	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	dprintk(2, "VIDIOC_S_FMT\n");
567*4882a593Smuzhiyun 	if (FW_VERSION(av7110->arm_app) < 0x2623)
568*4882a593Smuzhiyun 		return -EINVAL;
569*4882a593Smuzhiyun 	if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 &&
570*4882a593Smuzhiyun 	    f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) {
571*4882a593Smuzhiyun 		memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced));
572*4882a593Smuzhiyun 		/* WSS controlled by firmware */
573*4882a593Smuzhiyun 		av7110->wssMode = 0;
574*4882a593Smuzhiyun 		av7110->wssData = 0;
575*4882a593Smuzhiyun 		return av7110_fw_cmd(av7110, COMTYPE_ENCODER,
576*4882a593Smuzhiyun 				     SetWSSConfig, 1, 0);
577*4882a593Smuzhiyun 	} else {
578*4882a593Smuzhiyun 		memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced));
579*4882a593Smuzhiyun 		f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
580*4882a593Smuzhiyun 		f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
581*4882a593Smuzhiyun 		f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data);
582*4882a593Smuzhiyun 		/* WSS controlled by userspace */
583*4882a593Smuzhiyun 		av7110->wssMode = 1;
584*4882a593Smuzhiyun 		av7110->wssData = 0;
585*4882a593Smuzhiyun 	}
586*4882a593Smuzhiyun 	return 0;
587*4882a593Smuzhiyun }
588*4882a593Smuzhiyun 
av7110_vbi_reset(struct file * file)589*4882a593Smuzhiyun static int av7110_vbi_reset(struct file *file)
590*4882a593Smuzhiyun {
591*4882a593Smuzhiyun 	struct saa7146_fh *fh = file->private_data;
592*4882a593Smuzhiyun 	struct saa7146_dev *dev = fh->dev;
593*4882a593Smuzhiyun 	struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 	dprintk(2, "%s\n", __func__);
596*4882a593Smuzhiyun 	av7110->wssMode = 0;
597*4882a593Smuzhiyun 	av7110->wssData = 0;
598*4882a593Smuzhiyun 	if (FW_VERSION(av7110->arm_app) < 0x2623)
599*4882a593Smuzhiyun 		return 0;
600*4882a593Smuzhiyun 	else
601*4882a593Smuzhiyun 		return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 1, 0);
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun 
av7110_vbi_write(struct file * file,const char __user * data,size_t count,loff_t * ppos)604*4882a593Smuzhiyun static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun 	struct saa7146_fh *fh = file->private_data;
607*4882a593Smuzhiyun 	struct saa7146_dev *dev = fh->dev;
608*4882a593Smuzhiyun 	struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
609*4882a593Smuzhiyun 	struct v4l2_sliced_vbi_data d;
610*4882a593Smuzhiyun 	int rc;
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun 	dprintk(2, "%s\n", __func__);
613*4882a593Smuzhiyun 	if (FW_VERSION(av7110->arm_app) < 0x2623 || !av7110->wssMode || count != sizeof d)
614*4882a593Smuzhiyun 		return -EINVAL;
615*4882a593Smuzhiyun 	if (copy_from_user(&d, data, count))
616*4882a593Smuzhiyun 		return -EFAULT;
617*4882a593Smuzhiyun 	if ((d.id != 0 && d.id != V4L2_SLICED_WSS_625) || d.field != 0 || d.line != 23)
618*4882a593Smuzhiyun 		return -EINVAL;
619*4882a593Smuzhiyun 	if (d.id)
620*4882a593Smuzhiyun 		av7110->wssData = ((d.data[1] << 8) & 0x3f00) | d.data[0];
621*4882a593Smuzhiyun 	else
622*4882a593Smuzhiyun 		av7110->wssData = 0x8000;
623*4882a593Smuzhiyun 	rc = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 1, av7110->wssData);
624*4882a593Smuzhiyun 	return (rc < 0) ? rc : count;
625*4882a593Smuzhiyun }
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun /****************************************************************************
628*4882a593Smuzhiyun  * INITIALIZATION
629*4882a593Smuzhiyun  ****************************************************************************/
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun static u8 saa7113_init_regs[] = {
632*4882a593Smuzhiyun 	0x02, 0xd0,
633*4882a593Smuzhiyun 	0x03, 0x23,
634*4882a593Smuzhiyun 	0x04, 0x00,
635*4882a593Smuzhiyun 	0x05, 0x00,
636*4882a593Smuzhiyun 	0x06, 0xe9,
637*4882a593Smuzhiyun 	0x07, 0x0d,
638*4882a593Smuzhiyun 	0x08, 0x98,
639*4882a593Smuzhiyun 	0x09, 0x02,
640*4882a593Smuzhiyun 	0x0a, 0x80,
641*4882a593Smuzhiyun 	0x0b, 0x40,
642*4882a593Smuzhiyun 	0x0c, 0x40,
643*4882a593Smuzhiyun 	0x0d, 0x00,
644*4882a593Smuzhiyun 	0x0e, 0x01,
645*4882a593Smuzhiyun 	0x0f, 0x7c,
646*4882a593Smuzhiyun 	0x10, 0x48,
647*4882a593Smuzhiyun 	0x11, 0x0c,
648*4882a593Smuzhiyun 	0x12, 0x8b,
649*4882a593Smuzhiyun 	0x13, 0x1a,
650*4882a593Smuzhiyun 	0x14, 0x00,
651*4882a593Smuzhiyun 	0x15, 0x00,
652*4882a593Smuzhiyun 	0x16, 0x00,
653*4882a593Smuzhiyun 	0x17, 0x00,
654*4882a593Smuzhiyun 	0x18, 0x00,
655*4882a593Smuzhiyun 	0x19, 0x00,
656*4882a593Smuzhiyun 	0x1a, 0x00,
657*4882a593Smuzhiyun 	0x1b, 0x00,
658*4882a593Smuzhiyun 	0x1c, 0x00,
659*4882a593Smuzhiyun 	0x1d, 0x00,
660*4882a593Smuzhiyun 	0x1e, 0x00,
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	0x41, 0x77,
663*4882a593Smuzhiyun 	0x42, 0x77,
664*4882a593Smuzhiyun 	0x43, 0x77,
665*4882a593Smuzhiyun 	0x44, 0x77,
666*4882a593Smuzhiyun 	0x45, 0x77,
667*4882a593Smuzhiyun 	0x46, 0x77,
668*4882a593Smuzhiyun 	0x47, 0x77,
669*4882a593Smuzhiyun 	0x48, 0x77,
670*4882a593Smuzhiyun 	0x49, 0x77,
671*4882a593Smuzhiyun 	0x4a, 0x77,
672*4882a593Smuzhiyun 	0x4b, 0x77,
673*4882a593Smuzhiyun 	0x4c, 0x77,
674*4882a593Smuzhiyun 	0x4d, 0x77,
675*4882a593Smuzhiyun 	0x4e, 0x77,
676*4882a593Smuzhiyun 	0x4f, 0x77,
677*4882a593Smuzhiyun 	0x50, 0x77,
678*4882a593Smuzhiyun 	0x51, 0x77,
679*4882a593Smuzhiyun 	0x52, 0x77,
680*4882a593Smuzhiyun 	0x53, 0x77,
681*4882a593Smuzhiyun 	0x54, 0x77,
682*4882a593Smuzhiyun 	0x55, 0x77,
683*4882a593Smuzhiyun 	0x56, 0x77,
684*4882a593Smuzhiyun 	0x57, 0xff,
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	0xff
687*4882a593Smuzhiyun };
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun 
690*4882a593Smuzhiyun static struct saa7146_ext_vv av7110_vv_data_st;
691*4882a593Smuzhiyun static struct saa7146_ext_vv av7110_vv_data_c;
692*4882a593Smuzhiyun 
av7110_init_analog_module(struct av7110 * av7110)693*4882a593Smuzhiyun int av7110_init_analog_module(struct av7110 *av7110)
694*4882a593Smuzhiyun {
695*4882a593Smuzhiyun 	u16 version1, version2;
696*4882a593Smuzhiyun 
697*4882a593Smuzhiyun 	if (i2c_writereg(av7110, 0x80, 0x0, 0x80) == 1 &&
698*4882a593Smuzhiyun 	    i2c_writereg(av7110, 0x80, 0x0, 0) == 1) {
699*4882a593Smuzhiyun 		pr_info("DVB-C analog module @ card %d detected, initializing MSP3400\n",
700*4882a593Smuzhiyun 			av7110->dvb_adapter.num);
701*4882a593Smuzhiyun 		av7110->adac_type = DVB_ADAC_MSP34x0;
702*4882a593Smuzhiyun 	} else if (i2c_writereg(av7110, 0x84, 0x0, 0x80) == 1 &&
703*4882a593Smuzhiyun 		   i2c_writereg(av7110, 0x84, 0x0, 0) == 1) {
704*4882a593Smuzhiyun 		pr_info("DVB-C analog module @ card %d detected, initializing MSP3415\n",
705*4882a593Smuzhiyun 			av7110->dvb_adapter.num);
706*4882a593Smuzhiyun 		av7110->adac_type = DVB_ADAC_MSP34x5;
707*4882a593Smuzhiyun 	} else
708*4882a593Smuzhiyun 		return -ENODEV;
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	msleep(100); // the probing above resets the msp...
711*4882a593Smuzhiyun 	msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1);
712*4882a593Smuzhiyun 	msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2);
713*4882a593Smuzhiyun 	dprintk(1, "dvb-ttpci: @ card %d MSP34xx version 0x%04x 0x%04x\n",
714*4882a593Smuzhiyun 		av7110->dvb_adapter.num, version1, version2);
715*4882a593Smuzhiyun 	msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00);
716*4882a593Smuzhiyun 	msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone
717*4882a593Smuzhiyun 	msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); // loudspeaker source
718*4882a593Smuzhiyun 	msp_writereg(av7110, MSP_WR_DSP, 0x0009, 0x0220); // headphone source
719*4882a593Smuzhiyun 	msp_writereg(av7110, MSP_WR_DSP, 0x0004, 0x7f00); // loudspeaker volume
720*4882a593Smuzhiyun 	msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source
721*4882a593Smuzhiyun 	msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume
722*4882a593Smuzhiyun 	msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x1900); // prescale SCART
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) {
725*4882a593Smuzhiyun 		pr_info("saa7113 not accessible\n");
726*4882a593Smuzhiyun 	} else {
727*4882a593Smuzhiyun 		u8 *i = saa7113_init_regs;
728*4882a593Smuzhiyun 
729*4882a593Smuzhiyun 		if ((av7110->dev->pci->subsystem_vendor == 0x110a) && (av7110->dev->pci->subsystem_device == 0x0000)) {
730*4882a593Smuzhiyun 			/* Fujitsu/Siemens DVB-Cable */
731*4882a593Smuzhiyun 			av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820;
732*4882a593Smuzhiyun 		} else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x0002)) {
733*4882a593Smuzhiyun 			/* Hauppauge/TT DVB-C premium */
734*4882a593Smuzhiyun 			av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820;
735*4882a593Smuzhiyun 		} else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x000A)) {
736*4882a593Smuzhiyun 			/* Hauppauge/TT DVB-C premium */
737*4882a593Smuzhiyun 			av7110->analog_tuner_flags |= ANALOG_TUNER_STV0297;
738*4882a593Smuzhiyun 		}
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun 		/* setup for DVB by default */
741*4882a593Smuzhiyun 		if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
742*4882a593Smuzhiyun 			if (ves1820_writereg(av7110->dev, 0x09, 0x0f, 0x20))
743*4882a593Smuzhiyun 				dprintk(1, "setting band in demodulator failed\n");
744*4882a593Smuzhiyun 		} else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
745*4882a593Smuzhiyun 			saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD)
746*4882a593Smuzhiyun 			saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF)
747*4882a593Smuzhiyun 		}
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 		/* init the saa7113 */
750*4882a593Smuzhiyun 		while (*i != 0xff) {
751*4882a593Smuzhiyun 			if (i2c_writereg(av7110, 0x48, i[0], i[1]) != 1) {
752*4882a593Smuzhiyun 				dprintk(1, "saa7113 initialization failed @ card %d", av7110->dvb_adapter.num);
753*4882a593Smuzhiyun 				break;
754*4882a593Smuzhiyun 			}
755*4882a593Smuzhiyun 			i += 2;
756*4882a593Smuzhiyun 		}
757*4882a593Smuzhiyun 		/* setup msp for analog sound: B/G Dual-FM */
758*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DEM, 0x00bb, 0x02d0); // AD_CV
759*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DEM, 0x0001,  3); // FIR1
760*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DEM, 0x0001, 18); // FIR1
761*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DEM, 0x0001, 27); // FIR1
762*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DEM, 0x0001, 48); // FIR1
763*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DEM, 0x0001, 66); // FIR1
764*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DEM, 0x0001, 72); // FIR1
765*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DEM, 0x0005,  4); // FIR2
766*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DEM, 0x0005, 64); // FIR2
767*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DEM, 0x0005,  0); // FIR2
768*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DEM, 0x0005,  3); // FIR2
769*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DEM, 0x0005, 18); // FIR2
770*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DEM, 0x0005, 27); // FIR2
771*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DEM, 0x0005, 48); // FIR2
772*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DEM, 0x0005, 66); // FIR2
773*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DEM, 0x0005, 72); // FIR2
774*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DEM, 0x0083, 0xa000); // MODE_REG
775*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DEM, 0x0093, 0x00aa); // DCO1_LO 5.74MHz
776*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DEM, 0x009b, 0x04fc); // DCO1_HI
777*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DEM, 0x00a3, 0x038e); // DCO2_LO 5.5MHz
778*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DEM, 0x00ab, 0x04c6); // DCO2_HI
779*4882a593Smuzhiyun 		msp_writereg(av7110, MSP_WR_DEM, 0x0056, 0); // LOAD_REG 1/2
780*4882a593Smuzhiyun 	}
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun 	memcpy(standard, dvb_standard, sizeof(struct saa7146_standard) * 2);
783*4882a593Smuzhiyun 	/* set dd1 stream a & b */
784*4882a593Smuzhiyun 	saa7146_write(av7110->dev, DD1_STREAM_B, 0x00000000);
785*4882a593Smuzhiyun 	saa7146_write(av7110->dev, DD1_INIT, 0x03000700);
786*4882a593Smuzhiyun 	saa7146_write(av7110->dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun 	return 0;
789*4882a593Smuzhiyun }
790*4882a593Smuzhiyun 
av7110_init_v4l(struct av7110 * av7110)791*4882a593Smuzhiyun int av7110_init_v4l(struct av7110 *av7110)
792*4882a593Smuzhiyun {
793*4882a593Smuzhiyun 	struct saa7146_dev* dev = av7110->dev;
794*4882a593Smuzhiyun 	struct saa7146_ext_vv *vv_data;
795*4882a593Smuzhiyun 	int ret;
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun 	/* special case DVB-C: these cards have an analog tuner
798*4882a593Smuzhiyun 	   plus need some special handling, so we have separate
799*4882a593Smuzhiyun 	   saa7146_ext_vv data for these... */
800*4882a593Smuzhiyun 	if (av7110->analog_tuner_flags)
801*4882a593Smuzhiyun 		vv_data = &av7110_vv_data_c;
802*4882a593Smuzhiyun 	else
803*4882a593Smuzhiyun 		vv_data = &av7110_vv_data_st;
804*4882a593Smuzhiyun 	ret = saa7146_vv_init(dev, vv_data);
805*4882a593Smuzhiyun 
806*4882a593Smuzhiyun 	if (ret) {
807*4882a593Smuzhiyun 		ERR("cannot init capture device. skipping\n");
808*4882a593Smuzhiyun 		return -ENODEV;
809*4882a593Smuzhiyun 	}
810*4882a593Smuzhiyun 	vv_data->vid_ops.vidioc_enum_input = vidioc_enum_input;
811*4882a593Smuzhiyun 	vv_data->vid_ops.vidioc_g_input = vidioc_g_input;
812*4882a593Smuzhiyun 	vv_data->vid_ops.vidioc_s_input = vidioc_s_input;
813*4882a593Smuzhiyun 	vv_data->vid_ops.vidioc_g_tuner = vidioc_g_tuner;
814*4882a593Smuzhiyun 	vv_data->vid_ops.vidioc_s_tuner = vidioc_s_tuner;
815*4882a593Smuzhiyun 	vv_data->vid_ops.vidioc_g_frequency = vidioc_g_frequency;
816*4882a593Smuzhiyun 	vv_data->vid_ops.vidioc_s_frequency = vidioc_s_frequency;
817*4882a593Smuzhiyun 	vv_data->vid_ops.vidioc_enumaudio = vidioc_enumaudio;
818*4882a593Smuzhiyun 	vv_data->vid_ops.vidioc_g_audio = vidioc_g_audio;
819*4882a593Smuzhiyun 	vv_data->vid_ops.vidioc_s_audio = vidioc_s_audio;
820*4882a593Smuzhiyun 	vv_data->vid_ops.vidioc_g_fmt_vbi_cap = NULL;
821*4882a593Smuzhiyun 
822*4882a593Smuzhiyun 	vv_data->vbi_ops.vidioc_g_tuner = vidioc_g_tuner;
823*4882a593Smuzhiyun 	vv_data->vbi_ops.vidioc_s_tuner = vidioc_s_tuner;
824*4882a593Smuzhiyun 	vv_data->vbi_ops.vidioc_g_frequency = vidioc_g_frequency;
825*4882a593Smuzhiyun 	vv_data->vbi_ops.vidioc_s_frequency = vidioc_s_frequency;
826*4882a593Smuzhiyun 	vv_data->vbi_ops.vidioc_g_fmt_vbi_cap = NULL;
827*4882a593Smuzhiyun 	vv_data->vbi_ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap;
828*4882a593Smuzhiyun 	vv_data->vbi_ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out;
829*4882a593Smuzhiyun 	vv_data->vbi_ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out;
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun 	if (FW_VERSION(av7110->arm_app) < 0x2623)
832*4882a593Smuzhiyun 		vv_data->capabilities &= ~V4L2_CAP_SLICED_VBI_OUTPUT;
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun 	if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_VIDEO)) {
835*4882a593Smuzhiyun 		ERR("cannot register capture device. skipping\n");
836*4882a593Smuzhiyun 		saa7146_vv_release(dev);
837*4882a593Smuzhiyun 		return -ENODEV;
838*4882a593Smuzhiyun 	}
839*4882a593Smuzhiyun 	if (FW_VERSION(av7110->arm_app) >= 0x2623) {
840*4882a593Smuzhiyun 		if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI))
841*4882a593Smuzhiyun 			ERR("cannot register vbi v4l2 device. skipping\n");
842*4882a593Smuzhiyun 	}
843*4882a593Smuzhiyun 	return 0;
844*4882a593Smuzhiyun }
845*4882a593Smuzhiyun 
av7110_exit_v4l(struct av7110 * av7110)846*4882a593Smuzhiyun int av7110_exit_v4l(struct av7110 *av7110)
847*4882a593Smuzhiyun {
848*4882a593Smuzhiyun 	struct saa7146_dev* dev = av7110->dev;
849*4882a593Smuzhiyun 
850*4882a593Smuzhiyun 	saa7146_unregister_device(&av7110->v4l_dev, av7110->dev);
851*4882a593Smuzhiyun 	saa7146_unregister_device(&av7110->vbi_dev, av7110->dev);
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun 	saa7146_vv_release(dev);
854*4882a593Smuzhiyun 
855*4882a593Smuzhiyun 	return 0;
856*4882a593Smuzhiyun }
857*4882a593Smuzhiyun 
858*4882a593Smuzhiyun 
859*4882a593Smuzhiyun 
860*4882a593Smuzhiyun /* FIXME: these values are experimental values that look better than the
861*4882a593Smuzhiyun    values from the latest "official" driver -- at least for me... (MiHu) */
862*4882a593Smuzhiyun static struct saa7146_standard standard[] = {
863*4882a593Smuzhiyun 	{
864*4882a593Smuzhiyun 		.name	= "PAL",	.id		= V4L2_STD_PAL_BG,
865*4882a593Smuzhiyun 		.v_offset	= 0x15,	.v_field	= 288,
866*4882a593Smuzhiyun 		.h_offset	= 0x48,	.h_pixels	= 708,
867*4882a593Smuzhiyun 		.v_max_out	= 576,	.h_max_out	= 768,
868*4882a593Smuzhiyun 	}, {
869*4882a593Smuzhiyun 		.name	= "NTSC",	.id		= V4L2_STD_NTSC,
870*4882a593Smuzhiyun 		.v_offset	= 0x10,	.v_field	= 244,
871*4882a593Smuzhiyun 		.h_offset	= 0x40,	.h_pixels	= 708,
872*4882a593Smuzhiyun 		.v_max_out	= 480,	.h_max_out	= 640,
873*4882a593Smuzhiyun 	}
874*4882a593Smuzhiyun };
875*4882a593Smuzhiyun 
876*4882a593Smuzhiyun static struct saa7146_standard analog_standard[] = {
877*4882a593Smuzhiyun 	{
878*4882a593Smuzhiyun 		.name	= "PAL",	.id		= V4L2_STD_PAL_BG,
879*4882a593Smuzhiyun 		.v_offset	= 0x1b,	.v_field	= 288,
880*4882a593Smuzhiyun 		.h_offset	= 0x08,	.h_pixels	= 708,
881*4882a593Smuzhiyun 		.v_max_out	= 576,	.h_max_out	= 768,
882*4882a593Smuzhiyun 	}, {
883*4882a593Smuzhiyun 		.name	= "NTSC",	.id		= V4L2_STD_NTSC,
884*4882a593Smuzhiyun 		.v_offset	= 0x10,	.v_field	= 244,
885*4882a593Smuzhiyun 		.h_offset	= 0x40,	.h_pixels	= 708,
886*4882a593Smuzhiyun 		.v_max_out	= 480,	.h_max_out	= 640,
887*4882a593Smuzhiyun 	}
888*4882a593Smuzhiyun };
889*4882a593Smuzhiyun 
890*4882a593Smuzhiyun static struct saa7146_standard dvb_standard[] = {
891*4882a593Smuzhiyun 	{
892*4882a593Smuzhiyun 		.name	= "PAL",	.id		= V4L2_STD_PAL_BG,
893*4882a593Smuzhiyun 		.v_offset	= 0x14,	.v_field	= 288,
894*4882a593Smuzhiyun 		.h_offset	= 0x48,	.h_pixels	= 708,
895*4882a593Smuzhiyun 		.v_max_out	= 576,	.h_max_out	= 768,
896*4882a593Smuzhiyun 	}, {
897*4882a593Smuzhiyun 		.name	= "NTSC",	.id		= V4L2_STD_NTSC,
898*4882a593Smuzhiyun 		.v_offset	= 0x10,	.v_field	= 244,
899*4882a593Smuzhiyun 		.h_offset	= 0x40,	.h_pixels	= 708,
900*4882a593Smuzhiyun 		.v_max_out	= 480,	.h_max_out	= 640,
901*4882a593Smuzhiyun 	}
902*4882a593Smuzhiyun };
903*4882a593Smuzhiyun 
std_callback(struct saa7146_dev * dev,struct saa7146_standard * std)904*4882a593Smuzhiyun static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
905*4882a593Smuzhiyun {
906*4882a593Smuzhiyun 	struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
907*4882a593Smuzhiyun 
908*4882a593Smuzhiyun 	if (std->id & V4L2_STD_PAL) {
909*4882a593Smuzhiyun 		av7110->vidmode = AV7110_VIDEO_MODE_PAL;
910*4882a593Smuzhiyun 		av7110_set_vidmode(av7110, av7110->vidmode);
911*4882a593Smuzhiyun 	}
912*4882a593Smuzhiyun 	else if (std->id & V4L2_STD_NTSC) {
913*4882a593Smuzhiyun 		av7110->vidmode = AV7110_VIDEO_MODE_NTSC;
914*4882a593Smuzhiyun 		av7110_set_vidmode(av7110, av7110->vidmode);
915*4882a593Smuzhiyun 	}
916*4882a593Smuzhiyun 	else
917*4882a593Smuzhiyun 		return -1;
918*4882a593Smuzhiyun 
919*4882a593Smuzhiyun 	return 0;
920*4882a593Smuzhiyun }
921*4882a593Smuzhiyun 
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun static struct saa7146_ext_vv av7110_vv_data_st = {
924*4882a593Smuzhiyun 	.inputs		= 1,
925*4882a593Smuzhiyun 	.audios		= 1,
926*4882a593Smuzhiyun 	.capabilities	= V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO,
927*4882a593Smuzhiyun 	.flags		= 0,
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun 	.stds		= &standard[0],
930*4882a593Smuzhiyun 	.num_stds	= ARRAY_SIZE(standard),
931*4882a593Smuzhiyun 	.std_callback	= &std_callback,
932*4882a593Smuzhiyun 
933*4882a593Smuzhiyun 	.vbi_fops.open	= av7110_vbi_reset,
934*4882a593Smuzhiyun 	.vbi_fops.release = av7110_vbi_reset,
935*4882a593Smuzhiyun 	.vbi_fops.write	= av7110_vbi_write,
936*4882a593Smuzhiyun };
937*4882a593Smuzhiyun 
938*4882a593Smuzhiyun static struct saa7146_ext_vv av7110_vv_data_c = {
939*4882a593Smuzhiyun 	.inputs		= 1,
940*4882a593Smuzhiyun 	.audios		= 1,
941*4882a593Smuzhiyun 	.capabilities	= V4L2_CAP_TUNER | V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO,
942*4882a593Smuzhiyun 	.flags		= SAA7146_USE_PORT_B_FOR_VBI,
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun 	.stds		= &standard[0],
945*4882a593Smuzhiyun 	.num_stds	= ARRAY_SIZE(standard),
946*4882a593Smuzhiyun 	.std_callback	= &std_callback,
947*4882a593Smuzhiyun 
948*4882a593Smuzhiyun 	.vbi_fops.open	= av7110_vbi_reset,
949*4882a593Smuzhiyun 	.vbi_fops.release = av7110_vbi_reset,
950*4882a593Smuzhiyun 	.vbi_fops.write	= av7110_vbi_write,
951*4882a593Smuzhiyun };
952*4882a593Smuzhiyun 
953