diff options
author | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-10-02 10:57:03 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-01-25 16:01:02 -0500 |
commit | 6cb45879dca84c667996d65a12880db6705a2b0e (patch) | |
tree | 1548d262b2bcf68eeaf07d5ec5fa33af5e0a11af /drivers/media/video | |
parent | 12466577853b0d057f4416f4c7020e544f3a4209 (diff) |
V4L/DVB (6423): Add tuner-xc2028 driver
Add support for Xceive XC2028/XC3028 tuner driver
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video')
-rw-r--r-- | drivers/media/video/Kconfig | 12 | ||||
-rw-r--r-- | drivers/media/video/Makefile | 4 | ||||
-rw-r--r-- | drivers/media/video/tuner-core.c | 5 | ||||
-rw-r--r-- | drivers/media/video/tuner-driver.h | 2 | ||||
-rw-r--r-- | drivers/media/video/tuner-xc2028.c | 391 | ||||
-rw-r--r-- | drivers/media/video/tuner-xc2028.h | 9 |
6 files changed, 423 insertions, 0 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index ea5be3711a7d..454846355e93 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig | |||
@@ -505,6 +505,18 @@ config TUNER_3036 | |||
505 | Say Y here to include support for Philips SAB3036 compatible tuners. | 505 | Say Y here to include support for Philips SAB3036 compatible tuners. |
506 | If in doubt, say N. | 506 | If in doubt, say N. |
507 | 507 | ||
508 | config TUNER_XC2028 | ||
509 | tristate "Xceive xc2028 support for tm5600/tm6000 driver" | ||
510 | depends on I2C | ||
511 | select VIDEO_TUNER | ||
512 | help | ||
513 | Say Y here to include support for Xceive xc2028 tuner. This is | ||
514 | required on a few tm5600/tm6000 designs. You should notice | ||
515 | that this module currently works only with the special | ||
516 | firmware versions used on those Trident chips. | ||
517 | |||
518 | If in doubt, say N. | ||
519 | |||
508 | config VIDEO_VINO | 520 | config VIDEO_VINO |
509 | tristate "SGI Vino Video For Linux (EXPERIMENTAL)" | 521 | tristate "SGI Vino Video For Linux (EXPERIMENTAL)" |
510 | depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2 | 522 | depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2 |
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index b5a064163e03..1fd775e0a0b0 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile | |||
@@ -6,6 +6,10 @@ zr36067-objs := zoran_procfs.o zoran_device.o \ | |||
6 | zoran_driver.o zoran_card.o | 6 | zoran_driver.o zoran_card.o |
7 | tuner-objs := tuner-core.o tuner-types.o tda9887.o | 7 | tuner-objs := tuner-core.o tuner-types.o tda9887.o |
8 | 8 | ||
9 | ifneq ($(CONFIG_TUNER_XC2028),) | ||
10 | tuner-objs += tuner-xc2028.o | ||
11 | endif | ||
12 | |||
9 | msp3400-objs := msp3400-driver.o msp3400-kthreads.o | 13 | msp3400-objs := msp3400-driver.o msp3400-kthreads.o |
10 | 14 | ||
11 | obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \ | 15 | obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \ |
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index d1d6c664bb09..ce817a17ccf1 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c | |||
@@ -193,6 +193,8 @@ static void set_freq(struct i2c_client *c, unsigned long freq) | |||
193 | set_tv_freq(c, freq); | 193 | set_tv_freq(c, freq); |
194 | t->tv_freq = freq; | 194 | t->tv_freq = freq; |
195 | break; | 195 | break; |
196 | default: | ||
197 | tuner_dbg("freq set: unknown mode: 0x%04x!\n",t->mode); | ||
196 | } | 198 | } |
197 | } | 199 | } |
198 | 200 | ||
@@ -320,6 +322,9 @@ static void set_type(struct i2c_client *c, unsigned int type, | |||
320 | i2c_master_send(c,buffer,4); | 322 | i2c_master_send(c,buffer,4); |
321 | attach_simple_tuner(t); | 323 | attach_simple_tuner(t); |
322 | break; | 324 | break; |
325 | case TUNER_XC2028: | ||
326 | xc2028_tuner_init(c); | ||
327 | break; | ||
323 | case TUNER_TDA9887: | 328 | case TUNER_TDA9887: |
324 | tda9887_tuner_init(t); | 329 | tda9887_tuner_init(t); |
325 | break; | 330 | break; |
diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h index 28a10da76d12..5e733bc8362d 100644 --- a/drivers/media/video/tuner-driver.h +++ b/drivers/media/video/tuner-driver.h | |||
@@ -70,6 +70,8 @@ struct tuner { | |||
70 | struct tuner_operations ops; | 70 | struct tuner_operations ops; |
71 | }; | 71 | }; |
72 | 72 | ||
73 | extern int xc2028_tuner_init(struct i2c_client *c); | ||
74 | |||
73 | /* ------------------------------------------------------------------------ */ | 75 | /* ------------------------------------------------------------------------ */ |
74 | 76 | ||
75 | extern int tda9887_tuner_init(struct tuner *t); | 77 | extern int tda9887_tuner_init(struct tuner *t); |
diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c new file mode 100644 index 000000000000..cfcc1fe68c5c --- /dev/null +++ b/drivers/media/video/tuner-xc2028.c | |||
@@ -0,0 +1,391 @@ | |||
1 | /* tuner-xc2028 | ||
2 | * | ||
3 | * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org) | ||
4 | * This code is placed under the terms of the GNU General Public License v2 | ||
5 | */ | ||
6 | |||
7 | #include <linux/i2c.h> | ||
8 | #include <asm/div64.h> | ||
9 | #include <linux/firmware.h> | ||
10 | #include <linux/videodev.h> | ||
11 | #include <linux/delay.h> | ||
12 | #include "tuner-driver.h" | ||
13 | #include "tuner-xc2028.h" | ||
14 | |||
15 | /* Firmwares used on tm5600/tm6000 + xc2028/xc3028 */ | ||
16 | static const char *firmware_6M = "tm6000_xc3028_DTV_6M.fw"; | ||
17 | static const char *firmware_8M = "tm6000_xc3028_78M.fw"; | ||
18 | static const char *firmware_DK = "tm6000_xc3028_DK_PAL_MTS.fw"; | ||
19 | static const char *firmware_MN = "tm6000_xc3028_MN_BTSC.fw"; | ||
20 | |||
21 | struct xc2028_data { | ||
22 | v4l2_std_id firm_type; /* video stds supported by current firmware */ | ||
23 | int bandwidth; /* Firmware bandwidth: 6M, 7M or 8M */ | ||
24 | int need_load_generic; /* The generic firmware were loaded? */ | ||
25 | }; | ||
26 | |||
27 | #define i2c_send(rc,c,buf,size) \ | ||
28 | if (size != (rc = i2c_master_send(c, buf, size))) \ | ||
29 | tuner_warn("i2c output error: rc = %d (should be %d)\n", \ | ||
30 | rc, (int)size); | ||
31 | |||
32 | #define i2c_rcv(rc,c,buf,size) \ | ||
33 | if (size != (rc = i2c_master_recv(c, buf, size))) \ | ||
34 | tuner_warn("i2c input error: rc = %d (should be %d)\n", \ | ||
35 | rc, (int)size); | ||
36 | |||
37 | #define send_seq(c, data...) \ | ||
38 | { int rc; \ | ||
39 | const static u8 _val[] = data; \ | ||
40 | if (sizeof(_val) != \ | ||
41 | (rc = i2c_master_send \ | ||
42 | (c, _val, sizeof(_val)))) { \ | ||
43 | printk(KERN_ERR "Error on line %d: %d\n",__LINE__,rc); \ | ||
44 | return; \ | ||
45 | } \ | ||
46 | msleep (10); \ | ||
47 | } | ||
48 | |||
49 | static int xc2028_get_reg(struct i2c_client *c, u16 reg) | ||
50 | { | ||
51 | int rc; | ||
52 | unsigned char buf[1]; | ||
53 | struct tuner *t = i2c_get_clientdata(c); | ||
54 | |||
55 | buf[0]= reg; | ||
56 | |||
57 | i2c_send(rc, c, buf, sizeof(buf)); | ||
58 | if (rc<0) | ||
59 | return rc; | ||
60 | |||
61 | if (t->tuner_callback) { | ||
62 | rc = t->tuner_callback( c->adapter->algo_data, | ||
63 | XC2028_RESET_CLK, 0); | ||
64 | if (rc<0) | ||
65 | return rc; | ||
66 | } | ||
67 | |||
68 | i2c_rcv(rc, c, buf, 2); | ||
69 | if (rc<0) | ||
70 | return rc; | ||
71 | |||
72 | return (buf[1])|(buf[0]<<8); | ||
73 | } | ||
74 | |||
75 | static int load_firmware (struct i2c_client *c, const char *name) | ||
76 | { | ||
77 | const struct firmware *fw=NULL; | ||
78 | struct tuner *t = i2c_get_clientdata(c); | ||
79 | unsigned char *p, *endp; | ||
80 | int len=0, rc=0; | ||
81 | static const char firmware_ver[] = "tm6000/xcv v1"; | ||
82 | |||
83 | tuner_info("Loading firmware %s\n", name); | ||
84 | rc = request_firmware(&fw, name, &c->dev); | ||
85 | if (rc < 0) { | ||
86 | tuner_info("Error %d while requesting firmware\n", rc); | ||
87 | return rc; | ||
88 | } | ||
89 | p=fw->data; | ||
90 | endp=p+fw->size; | ||
91 | |||
92 | if(fw->size==0) { | ||
93 | tuner_info("Error: firmware size is zero!\n"); | ||
94 | rc=-EINVAL; | ||
95 | goto err; | ||
96 | } | ||
97 | if (fw->size<sizeof(firmware_ver)-1) { | ||
98 | /* Firmware is incorrect */ | ||
99 | tuner_info("Error: firmware size is less than header (%d<%d)!\n", | ||
100 | (int)fw->size,(int)sizeof(firmware_ver)-1); | ||
101 | rc=-EINVAL; | ||
102 | goto err; | ||
103 | } | ||
104 | |||
105 | if (memcmp(p,firmware_ver,sizeof(firmware_ver)-1)) { | ||
106 | /* Firmware is incorrect */ | ||
107 | tuner_info("Error: firmware is not for tm5600/6000 + Xcv2028/3028!\n"); | ||
108 | rc=-EINVAL; | ||
109 | goto err; | ||
110 | } | ||
111 | p+=sizeof(firmware_ver)-1; | ||
112 | |||
113 | while(p<endp) { | ||
114 | if ((*p) & 0x80) { | ||
115 | /* Special callback command received */ | ||
116 | rc = t->tuner_callback(c->adapter->algo_data, | ||
117 | XC2028_TUNER_RESET, (*p)&0x7f); | ||
118 | if (rc<0) { | ||
119 | tuner_info("Error at RESET code %d\n", | ||
120 | (*p)&0x7f); | ||
121 | goto err; | ||
122 | } | ||
123 | p++; | ||
124 | continue; | ||
125 | } | ||
126 | len=*p; | ||
127 | p++; | ||
128 | if (p+len+1>endp) { | ||
129 | /* Firmware is incorrect */ | ||
130 | tuner_info("Error: firmware is truncated!\n"); | ||
131 | rc=-EINVAL; | ||
132 | goto err; | ||
133 | } | ||
134 | if (len<=0) { | ||
135 | tuner_info("Error: firmware file is corrupted!\n"); | ||
136 | rc=-EINVAL; | ||
137 | goto err; | ||
138 | } | ||
139 | |||
140 | i2c_send(rc, c, p, len); | ||
141 | if (rc<0) | ||
142 | goto err; | ||
143 | p+=len; | ||
144 | |||
145 | if (*p) | ||
146 | msleep(*p); | ||
147 | p++; | ||
148 | } | ||
149 | |||
150 | |||
151 | err: | ||
152 | release_firmware(fw); | ||
153 | |||
154 | return rc; | ||
155 | } | ||
156 | |||
157 | static int check_firmware(struct i2c_client *c) | ||
158 | { | ||
159 | int rc, version; | ||
160 | struct tuner *t = i2c_get_clientdata(c); | ||
161 | struct xc2028_data *xc2028 = t->priv; | ||
162 | const char *name; | ||
163 | |||
164 | if (!t->tuner_callback) { | ||
165 | printk(KERN_ERR "xc2028: need tuner_callback to load firmware\n"); | ||
166 | return -EINVAL; | ||
167 | } | ||
168 | |||
169 | if (xc2028->need_load_generic) { | ||
170 | if (xc2028->bandwidth==6) | ||
171 | name = firmware_6M; | ||
172 | else | ||
173 | name = firmware_8M; | ||
174 | |||
175 | /* Reset is needed before loading firmware */ | ||
176 | rc = t->tuner_callback(c->adapter->algo_data, | ||
177 | XC2028_TUNER_RESET, 0); | ||
178 | if (rc<0) | ||
179 | return rc; | ||
180 | |||
181 | rc = load_firmware(c,name); | ||
182 | if (rc<0) | ||
183 | return rc; | ||
184 | |||
185 | xc2028->need_load_generic=0; | ||
186 | xc2028->firm_type=0; | ||
187 | } | ||
188 | |||
189 | if (xc2028->firm_type & t->std) | ||
190 | return 0; | ||
191 | |||
192 | if (t->std & V4L2_STD_MN) | ||
193 | name=firmware_MN; | ||
194 | else | ||
195 | name=firmware_DK; | ||
196 | |||
197 | rc = load_firmware(c,name); | ||
198 | if (rc<0) | ||
199 | return rc; | ||
200 | |||
201 | version = xc2028_get_reg(c, 0x4); | ||
202 | tuner_info("Firmware version is %d.%d\n", | ||
203 | (version>>4)&0x0f,(version)&0x0f); | ||
204 | |||
205 | xc2028->firm_type=t->std; | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static int xc2028_signal(struct i2c_client *c) | ||
211 | { | ||
212 | int lock, signal; | ||
213 | |||
214 | if (check_firmware(c)<0) | ||
215 | return 0; | ||
216 | |||
217 | lock = xc2028_get_reg(c, 0x2); | ||
218 | if (lock<=0) | ||
219 | return lock; | ||
220 | |||
221 | /* Frequency is locked. Return signal quality */ | ||
222 | |||
223 | signal = xc2028_get_reg(c, 0x40); | ||
224 | |||
225 | if(signal<=0) | ||
226 | return lock; | ||
227 | |||
228 | return signal; | ||
229 | } | ||
230 | |||
231 | #define DIV 15625 | ||
232 | |||
233 | static void set_tv_freq(struct i2c_client *c, unsigned int freq) | ||
234 | { | ||
235 | int rc; | ||
236 | unsigned char buf[5]; | ||
237 | struct tuner *t = i2c_get_clientdata(c); | ||
238 | unsigned long div = (freq*62500l+DIV/2)/DIV; | ||
239 | |||
240 | if (check_firmware(c)<0) | ||
241 | return; | ||
242 | |||
243 | /* Reset GPIO 1 */ | ||
244 | if (t->tuner_callback) { | ||
245 | rc = t->tuner_callback( c->adapter->algo_data, | ||
246 | XC2028_TUNER_RESET, 0); | ||
247 | if (rc<0) | ||
248 | return; | ||
249 | } | ||
250 | msleep(10); | ||
251 | |||
252 | send_seq (c, {0x12, 0x39}); | ||
253 | send_seq (c, {0x0c, 0x80, 0xf0, 0xf7, 0x3e, 0x75, 0xc1, 0x8a, 0xe4}); | ||
254 | send_seq (c, {0x0c, 0x02, 0x00}); | ||
255 | send_seq (c, {0x05, 0x0f, 0xee, 0xaa, 0x5f, 0xea, 0x90}); | ||
256 | send_seq (c, {0x06, 0x00, 0x0a, 0x4d, 0x8c, 0xf2, 0xd8, 0xcf, 0x30}); | ||
257 | send_seq (c, {0x06, 0x79, 0x9f}); | ||
258 | send_seq (c, {0x0b, 0x0d, 0xa4, 0x6c}); | ||
259 | send_seq (c, {0x0a, 0x01, 0x67, 0x24, 0x40, 0x08, 0xc3, 0x20, 0x10}); | ||
260 | send_seq (c, {0x0a, 0x64, 0x3c, 0xfa, 0xf7, 0xe1, 0x0c, 0x2c}); | ||
261 | send_seq (c, {0x09, 0x0b}); | ||
262 | send_seq (c, {0x10, 0x13}); | ||
263 | send_seq (c, {0x16, 0x12}); | ||
264 | send_seq (c, {0x1f, 0x02}); | ||
265 | send_seq (c, {0x21, 0x02}); | ||
266 | send_seq (c, {0x01, 0x02}); | ||
267 | send_seq (c, {0x2b, 0x10}); | ||
268 | send_seq (c, {0x02, 0x02}); | ||
269 | send_seq (c, {0x02, 0x03}); | ||
270 | send_seq (c, {0x00, 0x8c}); | ||
271 | |||
272 | send_seq (c, {0x00, 0x01, 0x00, 0x00}); | ||
273 | send_seq (c, {0x00, 0xcc, 0x20, 0x06}); | ||
274 | send_seq (c, {0x2b, 0x1a}); | ||
275 | send_seq (c, {0x2b, 0x1b}); | ||
276 | send_seq (c, {0x14, 0x01, 0x1b, 0x19, 0xb5, 0x29, 0xab, 0x09, 0x55}); | ||
277 | send_seq (c, {0x14, 0x44, 0x05, 0x65}); | ||
278 | send_seq (c, {0x13, 0x18, 0x08, 0x00, 0x00, 0x6c, 0x18, 0x16, 0x8c}); | ||
279 | send_seq (c, {0x13, 0x49, 0x2a, 0xab}); | ||
280 | send_seq (c, {0x0d, 0x01, 0x4b, 0x03, 0x97, 0x55, 0xc7, 0xd7, 0x00}); | ||
281 | send_seq (c, {0x0d, 0xa1, 0xeb, 0x8f, 0x5c}); | ||
282 | send_seq (c, {0x1a, 0x00, 0x00, 0x16, 0x8a, 0x40, 0x00, 0x00, 0x00, 0x20}); | ||
283 | send_seq (c, {0x2d, 0x01}); | ||
284 | send_seq (c, {0x18, 0x00}); | ||
285 | send_seq (c, {0x1b, 0x0d, 0x86, 0x51, 0xd2, 0x35, 0xa4, 0x92, 0xa5}); | ||
286 | send_seq (c, {0x1b, 0xb5, 0x25, 0x65}); | ||
287 | send_seq (c, {0x1d, 0x00}); | ||
288 | send_seq (c, {0x0f, 0x00, 0x29, 0x56, 0xb0, 0x00, 0xb6}); | ||
289 | send_seq (c, {0x20, 0x00}); | ||
290 | send_seq (c, {0x1e, 0x09, 0x02, 0x5b, 0x6c, 0x00, 0x4b, 0x81, 0x56}); | ||
291 | send_seq (c, {0x1e, 0x46, 0x69, 0x0b}); | ||
292 | send_seq (c, {0x22, 0x32}); | ||
293 | send_seq (c, {0x23, 0x0a}); | ||
294 | send_seq (c, {0x25, 0x00, 0x09, 0x90, 0x09, 0x06, 0x64, 0x02, 0x41}); | ||
295 | send_seq (c, {0x26, 0xcc}); | ||
296 | send_seq (c, {0x29, 0x40}); | ||
297 | send_seq (c, {0x21, 0x03}); | ||
298 | send_seq (c, {0x00, 0x8c}); | ||
299 | send_seq (c, {0x00, 0x00, 0x00, 0x00}); | ||
300 | |||
301 | /* CMD= Set frequency */ | ||
302 | send_seq(c, {0x00, 0x02, 0x00, 0x00}); | ||
303 | if (t->tuner_callback) { | ||
304 | rc = t->tuner_callback( c->adapter->algo_data, | ||
305 | XC2028_RESET_CLK, 1); | ||
306 | if (rc<0) | ||
307 | return; | ||
308 | } | ||
309 | |||
310 | msleep(10); | ||
311 | // send_seq(c, {0x00, 0x00, 0x10, 0xd0, 0x00}); | ||
312 | // msleep(100); | ||
313 | buf[0]= 0xff & (div>>24); | ||
314 | buf[1]= 0xff & (div>>16); | ||
315 | buf[2]= 0xff & (div>>8); | ||
316 | buf[3]= 0xff & (div); | ||
317 | buf[4]= 0; | ||
318 | |||
319 | i2c_send(rc, c, buf, sizeof(buf)); | ||
320 | if (rc<0) | ||
321 | return; | ||
322 | msleep(100); | ||
323 | |||
324 | printk("divider= %02x %02x %02x %02x (freq=%d.%02d)\n", | ||
325 | buf[1],buf[2],buf[3],buf[4], | ||
326 | freq / 16, freq % 16 * 100 / 16); | ||
327 | // printk("signal=%d\n",xc2028_signal(c)); | ||
328 | } | ||
329 | |||
330 | |||
331 | static void xc2028_release(struct i2c_client *c) | ||
332 | { | ||
333 | struct tuner *t = i2c_get_clientdata(c); | ||
334 | |||
335 | kfree(t->priv); | ||
336 | t->priv = NULL; | ||
337 | } | ||
338 | |||
339 | static struct tuner_operations tea5767_tuner_ops = { | ||
340 | .set_tv_freq = set_tv_freq, | ||
341 | .has_signal = xc2028_signal, | ||
342 | .release = xc2028_release, | ||
343 | // .is_stereo = xc2028_stereo, | ||
344 | }; | ||
345 | |||
346 | |||
347 | static int init=0; | ||
348 | |||
349 | int xc2028_tuner_init(struct i2c_client *c) | ||
350 | { | ||
351 | struct tuner *t = i2c_get_clientdata(c); | ||
352 | int version = xc2028_get_reg(c, 0x4); | ||
353 | int prd_id = xc2028_get_reg(c, 0x8); | ||
354 | struct xc2028_data *xc2028; | ||
355 | |||
356 | if (init) { | ||
357 | printk (KERN_ERR "Module already initialized!\n"); | ||
358 | return 0; | ||
359 | } | ||
360 | init++; | ||
361 | |||
362 | xc2028 = kzalloc(sizeof(*xc2028), GFP_KERNEL); | ||
363 | if (!xc2028) | ||
364 | return -ENOMEM; | ||
365 | t->priv = xc2028; | ||
366 | |||
367 | #ifdef HACK | ||
368 | xc2028->firm_type=1; | ||
369 | xc2028->bandwidth=6; | ||
370 | #endif | ||
371 | xc2028->bandwidth=6; | ||
372 | xc2028->need_load_generic=1; | ||
373 | |||
374 | /* FIXME: Check where t->priv will be freed */ | ||
375 | |||
376 | if (version<0) | ||
377 | version=0; | ||
378 | |||
379 | if (prd_id<0) | ||
380 | prd_id=0; | ||
381 | |||
382 | strlcpy(c->name, "xc2028", sizeof(c->name)); | ||
383 | tuner_info("type set to %d (%s, hw ver=%d.%d, fw ver=%d.%d, id=0x%04x)\n", | ||
384 | t->type, c->name, | ||
385 | (version>>12)&0x0f,(version>>8)&0x0f, | ||
386 | (version>>4)&0x0f,(version)&0x0f, prd_id); | ||
387 | |||
388 | memcpy(&t->ops, &tea5767_tuner_ops, sizeof(struct tuner_operations)); | ||
389 | |||
390 | return 0; | ||
391 | } | ||
diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h new file mode 100644 index 000000000000..7c540c3871bf --- /dev/null +++ b/drivers/media/video/tuner-xc2028.h | |||
@@ -0,0 +1,9 @@ | |||
1 | /* tuner-xc2028 | ||
2 | * | ||
3 | * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org) | ||
4 | * This code is placed under the terms of the GNU General Public License v2 | ||
5 | */ | ||
6 | |||
7 | /* xc2028 commands for callback */ | ||
8 | #define XC2028_TUNER_RESET 0 | ||
9 | #define XC2028_RESET_CLK 1 | ||