blob: 9dd4745f53123826b78707ee12118f119cbd6146 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * budget-av.c: driver for the SAA7146 based Budget DVB cards
3 * with analog video in
4 *
5 * Compiled from various sources by Michael Hunold <michael@mihu.de>
6 *
7 * CI interface support (c) 2004 Olivier Gournet <ogournet@anevia.com> &
8 * Andrew de Quincey <adq_dvb@lidskialf.net>
9 *
10 * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
11 *
12 * Copyright (C) 1999-2002 Ralph Metzler
13 * & Marcus Metzler for convergence integrated media GmbH
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
31 *
32 *
33 * the project's page is at http://www.linuxtv.org/dvb/
34 */
35
36#include "budget.h"
37#include "stv0299.h"
38#include "tda10021.h"
39#include "tda1004x.h"
Regis Prevotf8bf1342006-01-11 23:31:53 -020040#include "dvb-pll.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <media/saa7146_vv.h>
42#include <linux/module.h>
43#include <linux/errno.h>
44#include <linux/slab.h>
45#include <linux/interrupt.h>
46#include <linux/input.h>
47#include <linux/spinlock.h>
48
49#include "dvb_ca_en50221.h"
50
51#define DEBICICAM 0x02420000
52
53struct budget_av {
54 struct budget budget;
55 struct video_device *vd;
56 int cur_input;
57 int has_saa7113;
58 struct tasklet_struct ciintf_irq_tasklet;
59 int slot_status;
60 struct dvb_ca_en50221 ca;
61};
62
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -070063/* GPIO CI Connections:
64 * 0 - Vcc/Reset (Reset is controlled by capacitor)
65 * 1 - Attribute Memory
66 * 2 - Card Enable (Active Low)
67 * 3 - Card Detect
68 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
70/****************************************************************************
71 * INITIALIZATION
72 ****************************************************************************/
73
74static u8 i2c_readreg(struct i2c_adapter *i2c, u8 id, u8 reg)
75{
76 u8 mm1[] = { 0x00 };
77 u8 mm2[] = { 0x00 };
78 struct i2c_msg msgs[2];
79
80 msgs[0].flags = 0;
81 msgs[1].flags = I2C_M_RD;
82 msgs[0].addr = msgs[1].addr = id / 2;
83 mm1[0] = reg;
84 msgs[0].len = 1;
85 msgs[1].len = 1;
86 msgs[0].buf = mm1;
87 msgs[1].buf = mm2;
88
89 i2c_transfer(i2c, msgs, 2);
90
91 return mm2[0];
92}
93
94static int i2c_readregs(struct i2c_adapter *i2c, u8 id, u8 reg, u8 * buf, u8 len)
95{
96 u8 mm1[] = { reg };
97 struct i2c_msg msgs[2] = {
98 {.addr = id / 2,.flags = 0,.buf = mm1,.len = 1},
99 {.addr = id / 2,.flags = I2C_M_RD,.buf = buf,.len = len}
100 };
101
102 if (i2c_transfer(i2c, msgs, 2) != 2)
103 return -EIO;
104
105 return 0;
106}
107
108static int i2c_writereg(struct i2c_adapter *i2c, u8 id, u8 reg, u8 val)
109{
110 u8 msg[2] = { reg, val };
111 struct i2c_msg msgs;
112
113 msgs.flags = 0;
114 msgs.addr = id / 2;
115 msgs.len = 2;
116 msgs.buf = msg;
117 return i2c_transfer(i2c, &msgs, 1);
118}
119
120static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
121{
122 struct budget_av *budget_av = (struct budget_av *) ca->data;
123 int result;
124
125 if (slot != 0)
126 return -EINVAL;
127
128 saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
129 udelay(1);
130
Andrew de Quincey2d0235d2006-01-09 15:25:05 -0200131 result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
133 if (result == -ETIMEDOUT)
134 budget_av->slot_status = 0;
135 return result;
136}
137
138static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
139{
140 struct budget_av *budget_av = (struct budget_av *) ca->data;
141 int result;
142
143 if (slot != 0)
144 return -EINVAL;
145
146 saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTHI);
147 udelay(1);
148
Andrew de Quincey2d0235d2006-01-09 15:25:05 -0200149 result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
151 if (result == -ETIMEDOUT)
152 budget_av->slot_status = 0;
153 return result;
154}
155
156static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
157{
158 struct budget_av *budget_av = (struct budget_av *) ca->data;
159 int result;
160
161 if (slot != 0)
162 return -EINVAL;
163
164 saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
165 udelay(1);
166
167 result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0);
168
169 if (result == -ETIMEDOUT)
170 budget_av->slot_status = 0;
171 return result;
172}
173
174static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
175{
176 struct budget_av *budget_av = (struct budget_av *) ca->data;
177 int result;
178
179 if (slot != 0)
180 return -EINVAL;
181
182 saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
183 udelay(1);
184
185 result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0);
186
187 if (result == -ETIMEDOUT)
188 budget_av->slot_status = 0;
189 return result;
190}
191
192static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
193{
194 struct budget_av *budget_av = (struct budget_av *) ca->data;
195 struct saa7146_dev *saa = budget_av->budget.dev;
Andrew de Quincey2d0235d2006-01-09 15:25:05 -0200196 int timeout = 50; // 5 seconds (4.4.6 Ready)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
198 if (slot != 0)
199 return -EINVAL;
200
201 dprintk(1, "ciintf_slot_reset\n");
202
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700203 saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700205 saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI); /* Vcc off */
206 msleep(2);
207 saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); /* Vcc on */
208 msleep(20); /* 20 ms Vcc settling time */
209
210 saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); /* enable card */
211
212 /* This should have been based on pin 16 READY of the pcmcia port,
213 * but AFAICS it is not routed to the saa7146 */
214 while (--timeout > 0 && ciintf_read_attribute_mem(ca, slot, 0) != 0x1d)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 msleep(100);
216
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700217 if (timeout <= 0)
218 {
219 printk(KERN_ERR "budget-av: cam reset failed (timeout).\n");
220 saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700221 return -ETIMEDOUT;
222 }
223
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 return 0;
225}
226
227static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
228{
229 struct budget_av *budget_av = (struct budget_av *) ca->data;
230 struct saa7146_dev *saa = budget_av->budget.dev;
231
232 if (slot != 0)
233 return -EINVAL;
234
235 dprintk(1, "ciintf_slot_shutdown\n");
236
237 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
238 budget_av->slot_status = 0;
239 return 0;
240}
241
242static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
243{
244 struct budget_av *budget_av = (struct budget_av *) ca->data;
245 struct saa7146_dev *saa = budget_av->budget.dev;
246
247 if (slot != 0)
248 return -EINVAL;
249
250 dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status);
251
252 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
253 return 0;
254}
255
256static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
257{
258 struct budget_av *budget_av = (struct budget_av *) ca->data;
259 struct saa7146_dev *saa = budget_av->budget.dev;
Andrew de Quincey2d0235d2006-01-09 15:25:05 -0200260 int cam_present = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
262 if (slot != 0)
263 return -EINVAL;
264
Andrew de Quincey2d0235d2006-01-09 15:25:05 -0200265 if (!budget_av->slot_status)
266 {
267 // first of all test the card detect line
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
269 udelay(1);
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700270 if (saa7146_read(saa, PSR) & MASK_06)
271 {
Andrew de Quincey2d0235d2006-01-09 15:25:05 -0200272 cam_present = 1;
273 }
274 saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
275
276 // that is unreliable however, so try and read from IO memory
277 if (!cam_present)
278 {
Michael Krufky50c25ff2006-01-09 15:25:34 -0200279 saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
Andrew de Quincey2d0235d2006-01-09 15:25:05 -0200280 if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) != -ETIMEDOUT)
281 {
282 cam_present = 1;
283 }
284 }
285
286 // did we find something?
287 if (cam_present) {
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700288 printk(KERN_INFO "budget-av: cam inserted\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 budget_av->slot_status = 1;
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700290 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 } else if (!open) {
292 saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
293 if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT)
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700294 {
295 printk(KERN_INFO "budget-av: cam ejected\n");
296 saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 budget_av->slot_status = 0;
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700298 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 }
300
301 if (budget_av->slot_status == 1)
302 return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
303
304 return 0;
305}
306
307static int ciintf_init(struct budget_av *budget_av)
308{
309 struct saa7146_dev *saa = budget_av->budget.dev;
310 int result;
311
312 memset(&budget_av->ca, 0, sizeof(struct dvb_ca_en50221));
313
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700314 saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
315 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO);
317 saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
318
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 /* Enable DEBI pins */
320 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
321
322 /* register CI interface */
323 budget_av->ca.owner = THIS_MODULE;
324 budget_av->ca.read_attribute_mem = ciintf_read_attribute_mem;
325 budget_av->ca.write_attribute_mem = ciintf_write_attribute_mem;
326 budget_av->ca.read_cam_control = ciintf_read_cam_control;
327 budget_av->ca.write_cam_control = ciintf_write_cam_control;
328 budget_av->ca.slot_reset = ciintf_slot_reset;
329 budget_av->ca.slot_shutdown = ciintf_slot_shutdown;
330 budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable;
331 budget_av->ca.poll_slot_status = ciintf_poll_slot_status;
332 budget_av->ca.data = budget_av;
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700333
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700334 if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 &budget_av->ca, 0, 1)) != 0) {
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700336 printk(KERN_ERR "budget-av: ci initialisation failed.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 goto error;
338 }
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700339
340 printk(KERN_INFO "budget-av: ci interface initialised.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 budget_av->budget.ci_present = 1;
342 return 0;
343
344error:
345 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
346 return result;
347}
348
349static void ciintf_deinit(struct budget_av *budget_av)
350{
351 struct saa7146_dev *saa = budget_av->budget.dev;
352
353 saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
354 saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
355 saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
356 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
357
358 /* release the CA device */
359 dvb_ca_en50221_release(&budget_av->ca);
360
361 /* disable DEBI pins */
362 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
363}
364
365
366static const u8 saa7113_tab[] = {
367 0x01, 0x08,
368 0x02, 0xc0,
369 0x03, 0x33,
370 0x04, 0x00,
371 0x05, 0x00,
372 0x06, 0xeb,
373 0x07, 0xe0,
374 0x08, 0x28,
375 0x09, 0x00,
376 0x0a, 0x80,
377 0x0b, 0x47,
378 0x0c, 0x40,
379 0x0d, 0x00,
380 0x0e, 0x01,
381 0x0f, 0x44,
382
383 0x10, 0x08,
384 0x11, 0x0c,
385 0x12, 0x7b,
386 0x13, 0x00,
387 0x15, 0x00, 0x16, 0x00, 0x17, 0x00,
388
389 0x57, 0xff,
390 0x40, 0x82, 0x58, 0x00, 0x59, 0x54, 0x5a, 0x07,
391 0x5b, 0x83, 0x5e, 0x00,
392 0xff
393};
394
395static int saa7113_init(struct budget_av *budget_av)
396{
397 struct budget *budget = &budget_av->budget;
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700398 struct saa7146_dev *saa = budget->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 const u8 *data = saa7113_tab;
400
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700401 saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI);
402 msleep(200);
403
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 if (i2c_writereg(&budget->i2c_adap, 0x4a, 0x01, 0x08) != 1) {
405 dprintk(1, "saa7113 not found on KNC card\n");
406 return -ENODEV;
407 }
408
409 dprintk(1, "saa7113 detected and initializing\n");
410
411 while (*data != 0xff) {
412 i2c_writereg(&budget->i2c_adap, 0x4a, *data, *(data + 1));
413 data += 2;
414 }
415
416 dprintk(1, "saa7113 status=%02x\n", i2c_readreg(&budget->i2c_adap, 0x4a, 0x1f));
417
418 return 0;
419}
420
421static int saa7113_setinput(struct budget_av *budget_av, int input)
422{
423 struct budget *budget = &budget_av->budget;
424
425 if (1 != budget_av->has_saa7113)
426 return -ENODEV;
427
428 if (input == 1) {
429 i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc7);
430 i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x80);
431 } else if (input == 0) {
432 i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc0);
433 i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x00);
434 } else
435 return -EINVAL;
436
437 budget_av->cur_input = input;
438 return 0;
439}
440
441
442static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
443{
444 u8 aclk = 0;
445 u8 bclk = 0;
446 u8 m1;
447
448 aclk = 0xb5;
449 if (srate < 2000000)
450 bclk = 0x86;
451 else if (srate < 5000000)
452 bclk = 0x89;
453 else if (srate < 15000000)
454 bclk = 0x8f;
455 else if (srate < 45000000)
456 bclk = 0x95;
457
458 m1 = 0x14;
459 if (srate < 4000000)
460 m1 = 0x10;
461
462 stv0299_writereg(fe, 0x13, aclk);
463 stv0299_writereg(fe, 0x14, bclk);
464 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
465 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
466 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
467 stv0299_writereg(fe, 0x0f, 0x80 | m1);
468
469 return 0;
470}
471
472static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe,
Andreas Oberrittercfbfce12005-09-09 13:02:30 -0700473 struct i2c_adapter *i2c,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 struct dvb_frontend_parameters *params)
475{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 u32 div;
477 u8 buf[4];
478 struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
479
480 if ((params->frequency < 950000) || (params->frequency > 2150000))
481 return -EINVAL;
482
483 div = (params->frequency + (125 - 1)) / 125; // round correctly
484 buf[0] = (div >> 8) & 0x7f;
485 buf[1] = div & 0xff;
486 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
487 buf[3] = 0x20;
488
489 if (params->u.qpsk.symbol_rate < 4000000)
490 buf[3] |= 1;
491
492 if (params->frequency < 1250000)
493 buf[3] |= 0;
494 else if (params->frequency < 1550000)
495 buf[3] |= 0x40;
496 else if (params->frequency < 2050000)
497 buf[3] |= 0x80;
498 else if (params->frequency < 2150000)
499 buf[3] |= 0xC0;
500
Andreas Oberrittercfbfce12005-09-09 13:02:30 -0700501 if (i2c_transfer(i2c, &msg, 1) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 return -EIO;
503 return 0;
504}
505
Andrew de Quinceyeffa7912006-01-09 15:25:09 -0200506#define MIN2(a,b) ((a) < (b) ? (a) : (b))
507#define MIN3(a,b,c) MIN2(MIN2(a,b),c)
508
509static int philips_su1278sh2_tua6100_pll_set(struct dvb_frontend *fe,
510 struct i2c_adapter *i2c,
511 struct dvb_frontend_parameters *params)
512{
513 u8 reg0 [2] = { 0x00, 0x00 };
514 u8 reg1 [4] = { 0x01, 0x00, 0x00, 0x00 };
515 u8 reg2 [3] = { 0x02, 0x00, 0x00 };
516 int _fband;
517 int first_ZF;
518 int R, A, N, P, M;
519 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = NULL,.len = 0 };
520 int freq = params->frequency;
521
522 first_ZF = (freq) / 1000;
523
524 if (abs(MIN2(abs(first_ZF-1190),abs(first_ZF-1790))) <
525 abs(MIN3(abs(first_ZF-1202),abs(first_ZF-1542),abs(first_ZF-1890))))
526 _fband = 2;
527 else
528 _fband = 3;
529
530 if (_fband == 2) {
531 if (((first_ZF >= 950) && (first_ZF < 1350)) ||
532 ((first_ZF >= 1430) && (first_ZF < 1950)))
533 reg0[1] = 0x07;
534 else if (((first_ZF >= 1350) && (first_ZF < 1430)) ||
535 ((first_ZF >= 1950) && (first_ZF < 2150)))
536 reg0[1] = 0x0B;
537 }
538
539 if(_fband == 3) {
540 if (((first_ZF >= 950) && (first_ZF < 1350)) ||
541 ((first_ZF >= 1455) && (first_ZF < 1950)))
542 reg0[1] = 0x07;
543 else if (((first_ZF >= 1350) && (first_ZF < 1420)) ||
544 ((first_ZF >= 1950) && (first_ZF < 2150)))
545 reg0[1] = 0x0B;
546 else if ((first_ZF >= 1420) && (first_ZF < 1455))
547 reg0[1] = 0x0F;
548 }
549
550 if (first_ZF > 1525)
551 reg1[1] |= 0x80;
552 else
553 reg1[1] &= 0x7F;
554
555 if (_fband == 2) {
556 if (first_ZF > 1430) { /* 1430MHZ */
557 reg1[1] &= 0xCF; /* N2 */
558 reg2[1] &= 0xCF; /* R2 */
559 reg2[1] |= 0x10;
560 } else {
561 reg1[1] &= 0xCF; /* N2 */
562 reg1[1] |= 0x20;
563 reg2[1] &= 0xCF; /* R2 */
564 reg2[1] |= 0x10;
565 }
566 }
567
568 if (_fband == 3) {
569 if ((first_ZF >= 1455) &&
570 (first_ZF < 1630)) {
571 reg1[1] &= 0xCF; /* N2 */
572 reg1[1] |= 0x20;
573 reg2[1] &= 0xCF; /* R2 */
574 } else {
575 if (first_ZF < 1455) {
576 reg1[1] &= 0xCF; /* N2 */
577 reg1[1] |= 0x20;
578 reg2[1] &= 0xCF; /* R2 */
579 reg2[1] |= 0x10;
580 } else {
581 if (first_ZF >= 1630) {
582 reg1[1] &= 0xCF; /* N2 */
583 reg2[1] &= 0xCF; /* R2 */
584 reg2[1] |= 0x10;
585 }
586 }
587 }
588 }
589
590 /* set ports, enable P0 for symbol rates > 4Ms/s */
591 if (params->u.qpsk.symbol_rate >= 4000000)
592 reg1[1] |= 0x0c;
593 else
594 reg1[1] |= 0x04;
595
596 reg2[1] |= 0x0c;
597
598 R = 64;
599 A = 64;
600 P = 64; //32
601
602 M = (freq * R) / 4; /* in Mhz */
603 N = (M - A * 1000) / (P * 1000);
604
605 reg1[1] |= (N >> 9) & 0x03;
606 reg1[2] = (N >> 1) & 0xff;
607 reg1[3] = (N << 7) & 0x80;
608
609 reg2[1] |= (R >> 8) & 0x03;
610 reg2[2] = R & 0xFF; /* R */
611
612 reg1[3] |= A & 0x7f; /* A */
613
614 if (P == 64)
615 reg1[1] |= 0x40; /* Prescaler 64/65 */
616
617 reg0[1] |= 0x03;
618
619 /* already enabled - do not reenable i2c repeater or TX fails */
620 msg.buf = reg0;
621 msg.len = sizeof(reg0);
622 if (i2c_transfer(i2c, &msg, 1) != 1)
623 return -EIO;
624
625 stv0299_enable_plli2c(fe);
626 msg.buf = reg1;
627 msg.len = sizeof(reg1);
628 if (i2c_transfer(i2c, &msg, 1) != 1)
629 return -EIO;
630
631 stv0299_enable_plli2c(fe);
632 msg.buf = reg2;
633 msg.len = sizeof(reg2);
634 if (i2c_transfer(i2c, &msg, 1) != 1)
635 return -EIO;
636
637 return 0;
638}
639
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640static u8 typhoon_cinergy1200s_inittab[] = {
641 0x01, 0x15,
642 0x02, 0x30,
643 0x03, 0x00,
644 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
645 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
646 0x06, 0x40, /* DAC not used, set to high impendance mode */
647 0x07, 0x00, /* DAC LSB */
648 0x08, 0x40, /* DiSEqC off */
649 0x09, 0x00, /* FIFO */
650 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
651 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
652 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
653 0x10, 0x3f, // AGC2 0x3d
654 0x11, 0x84,
Oliver Endrissff29d062005-11-08 21:35:43 -0800655 0x12, 0xb9,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 0x15, 0xc9, // lock detector threshold
657 0x16, 0x00,
658 0x17, 0x00,
659 0x18, 0x00,
660 0x19, 0x00,
661 0x1a, 0x00,
662 0x1f, 0x50,
663 0x20, 0x00,
664 0x21, 0x00,
665 0x22, 0x00,
666 0x23, 0x00,
667 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
668 0x29, 0x1e, // 1/2 threshold
669 0x2a, 0x14, // 2/3 threshold
670 0x2b, 0x0f, // 3/4 threshold
671 0x2c, 0x09, // 5/6 threshold
672 0x2d, 0x05, // 7/8 threshold
673 0x2e, 0x01,
674 0x31, 0x1f, // test all FECs
675 0x32, 0x19, // viterbi and synchro search
676 0x33, 0xfc, // rs control
677 0x34, 0x93, // error control
678 0x0f, 0x92,
679 0xff, 0xff
680};
681
682static struct stv0299_config typhoon_config = {
683 .demod_address = 0x68,
684 .inittab = typhoon_cinergy1200s_inittab,
685 .mclk = 88000000UL,
686 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 .skip_reinit = 0,
688 .lock_output = STV0229_LOCKOUTPUT_1,
689 .volt13_op0_op1 = STV0299_VOLT13_OP0,
690 .min_delay_ms = 100,
691 .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
692 .pll_set = philips_su1278_ty_ci_pll_set,
693};
694
695
696static struct stv0299_config cinergy_1200s_config = {
697 .demod_address = 0x68,
698 .inittab = typhoon_cinergy1200s_inittab,
699 .mclk = 88000000UL,
700 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 .skip_reinit = 0,
702 .lock_output = STV0229_LOCKOUTPUT_0,
703 .volt13_op0_op1 = STV0299_VOLT13_OP0,
704 .min_delay_ms = 100,
705 .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
706 .pll_set = philips_su1278_ty_ci_pll_set,
707};
708
Andrew de Quinceyeffa7912006-01-09 15:25:09 -0200709static struct stv0299_config cinergy_1200s_1894_0010_config = {
710 .demod_address = 0x68,
711 .inittab = typhoon_cinergy1200s_inittab,
712 .mclk = 88000000UL,
713 .invert = 1,
714 .skip_reinit = 0,
715 .lock_output = STV0229_LOCKOUTPUT_1,
716 .volt13_op0_op1 = STV0299_VOLT13_OP0,
717 .min_delay_ms = 100,
718 .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
719 .pll_set = philips_su1278sh2_tua6100_pll_set,
720};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
722static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
723{
724 struct budget *budget = (struct budget *) fe->dvb->priv;
725 u8 buf[4];
726 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
727
728#define TUNER_MUL 62500
729
730 u32 div = (params->frequency + 36125000 + TUNER_MUL / 2) / TUNER_MUL;
731
732 buf[0] = (div >> 8) & 0x7f;
733 buf[1] = div & 0xff;
Johannes Stezenbacheef57642005-07-07 17:57:58 -0700734 buf[2] = 0x86;
735 buf[3] = (params->frequency < 150000000 ? 0x01 :
736 params->frequency < 445000000 ? 0x02 : 0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737
738 if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
739 return -EIO;
740 return 0;
741}
742
743static struct tda10021_config philips_cu1216_config = {
744 .demod_address = 0x0c,
745 .pll_set = philips_cu1216_pll_set,
746};
747
748
749
750
751static int philips_tu1216_pll_init(struct dvb_frontend *fe)
752{
753 struct budget *budget = (struct budget *) fe->dvb->priv;
754 static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
755 struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
756
757 // setup PLL configuration
758 if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
759 return -EIO;
760 msleep(1);
761
762 return 0;
763}
764
765static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
766{
767 struct budget *budget = (struct budget *) fe->dvb->priv;
768 u8 tuner_buf[4];
769 struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len =
770 sizeof(tuner_buf) };
771 int tuner_frequency = 0;
772 u8 band, cp, filter;
773
774 // determine charge pump
775 tuner_frequency = params->frequency + 36166000;
776 if (tuner_frequency < 87000000)
777 return -EINVAL;
778 else if (tuner_frequency < 130000000)
779 cp = 3;
780 else if (tuner_frequency < 160000000)
781 cp = 5;
782 else if (tuner_frequency < 200000000)
783 cp = 6;
784 else if (tuner_frequency < 290000000)
785 cp = 3;
786 else if (tuner_frequency < 420000000)
787 cp = 5;
788 else if (tuner_frequency < 480000000)
789 cp = 6;
790 else if (tuner_frequency < 620000000)
791 cp = 3;
792 else if (tuner_frequency < 830000000)
793 cp = 5;
794 else if (tuner_frequency < 895000000)
795 cp = 7;
796 else
797 return -EINVAL;
798
799 // determine band
800 if (params->frequency < 49000000)
801 return -EINVAL;
802 else if (params->frequency < 161000000)
803 band = 1;
804 else if (params->frequency < 444000000)
805 band = 2;
806 else if (params->frequency < 861000000)
807 band = 4;
808 else
809 return -EINVAL;
810
811 // setup PLL filter
812 switch (params->u.ofdm.bandwidth) {
813 case BANDWIDTH_6_MHZ:
814 filter = 0;
815 break;
816
817 case BANDWIDTH_7_MHZ:
818 filter = 0;
819 break;
820
821 case BANDWIDTH_8_MHZ:
822 filter = 1;
823 break;
824
825 default:
826 return -EINVAL;
827 }
828
829 // calculate divisor
830 // ((36166000+((1000000/6)/2)) + Finput)/(1000000/6)
831 tuner_frequency = (((params->frequency / 1000) * 6) + 217496) / 1000;
832
833 // setup tuner buffer
834 tuner_buf[0] = (tuner_frequency >> 8) & 0x7f;
835 tuner_buf[1] = tuner_frequency & 0xff;
836 tuner_buf[2] = 0xca;
837 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
838
839 if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
840 return -EIO;
841
842 msleep(1);
843 return 0;
844}
845
846static int philips_tu1216_request_firmware(struct dvb_frontend *fe,
847 const struct firmware **fw, char *name)
848{
849 struct budget *budget = (struct budget *) fe->dvb->priv;
850
851 return request_firmware(fw, name, &budget->dev->pci->dev);
852}
853
854static struct tda1004x_config philips_tu1216_config = {
855
856 .demod_address = 0x8,
857 .invert = 1,
858 .invert_oclk = 1,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700859 .xtal_freq = TDA10046_XTAL_4M,
860 .agc_config = TDA10046_AGC_DEFAULT,
861 .if_freq = TDA10046_FREQ_3617,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 .pll_init = philips_tu1216_pll_init,
863 .pll_set = philips_tu1216_pll_set,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700864 .pll_sleep = NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 .request_firmware = philips_tu1216_request_firmware,
866};
867
Regis Prevotf8bf1342006-01-11 23:31:53 -0200868static u8 philips_sd1878_inittab[] = {
869 0x01, 0x15,
870 0x02, 0x30,
871 0x03, 0x00,
872 0x04, 0x7d,
873 0x05, 0x35,
874 0x06, 0x40,
875 0x07, 0x00,
876 0x08, 0x43,
877 0x09, 0x02,
878 0x0C, 0x51,
879 0x0D, 0x82,
880 0x0E, 0x23,
881 0x10, 0x3f,
882 0x11, 0x84,
883 0x12, 0xb9,
884 0x15, 0xc9,
885 0x16, 0x19,
886 0x17, 0x8c,
887 0x18, 0x59,
888 0x19, 0xf8,
889 0x1a, 0xfe,
890 0x1c, 0x7f,
891 0x1d, 0x00,
892 0x1e, 0x00,
893 0x1f, 0x50,
894 0x20, 0x00,
895 0x21, 0x00,
896 0x22, 0x00,
897 0x23, 0x00,
898 0x28, 0x00,
899 0x29, 0x28,
900 0x2a, 0x14,
901 0x2b, 0x0f,
902 0x2c, 0x09,
903 0x2d, 0x09,
904 0x31, 0x1f,
905 0x32, 0x19,
906 0x33, 0xfc,
907 0x34, 0x93,
908 0xff, 0xff
909};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
Regis Prevotf8bf1342006-01-11 23:31:53 -0200911static int philips_sd1878_tda8261_pll_set(struct dvb_frontend *fe,
912 struct i2c_adapter *i2c,
913 struct dvb_frontend_parameters *params)
914{
915 u8 buf[4];
916 int rc;
917 struct i2c_msg tuner_msg = {.addr=0x60,.flags=0,.buf=buf,.len=sizeof(buf)};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
Regis Prevotf8bf1342006-01-11 23:31:53 -0200919 if((params->frequency < 950000) || (params->frequency > 2150000))
920 return -EINVAL;
921
922 rc=dvb_pll_configure(&dvb_pll_philips_sd1878_tda8261, buf,
923 params->frequency, 0);
924 if(rc < 0) return rc;
925
926 if(i2c_transfer(i2c, &tuner_msg, 1) != 1)
927 return -EIO;
928
929 return 0;
930}
931
932static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe,
933 u32 srate, u32 ratio)
934{
935 u8 aclk = 0;
936 u8 bclk = 0;
937 u8 m1;
938
939 aclk = 0xb5;
940 if (srate < 2000000)
941 bclk = 0x86;
942 else if (srate < 5000000)
943 bclk = 0x89;
944 else if (srate < 15000000)
945 bclk = 0x8f;
946 else if (srate < 45000000)
947 bclk = 0x95;
948
949 m1 = 0x14;
950 if (srate < 4000000)
951 m1 = 0x10;
952
953 stv0299_writereg(fe, 0x0e, 0x23);
954 stv0299_writereg(fe, 0x0f, 0x94);
955 stv0299_writereg(fe, 0x10, 0x39);
956 stv0299_writereg(fe, 0x13, aclk);
957 stv0299_writereg(fe, 0x14, bclk);
958 stv0299_writereg(fe, 0x15, 0xc9);
959 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
960 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
961 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
962 stv0299_writereg(fe, 0x0f, 0x80 | m1);
963
964 return 0;
965}
966
967static struct stv0299_config philips_sd1878_config = {
968 .demod_address = 0x68,
969 .inittab = philips_sd1878_inittab,
970 .mclk = 88000000UL,
971 .invert = 0,
972 .skip_reinit = 0,
973 .lock_output = STV0229_LOCKOUTPUT_1,
974 .volt13_op0_op1 = STV0299_VOLT13_OP0,
975 .min_delay_ms = 100,
976 .set_symbol_rate = philips_sd1878_ci_set_symbol_rate,
977 .pll_set = philips_sd1878_tda8261_pll_set,
978};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
980static u8 read_pwm(struct budget_av *budget_av)
981{
982 u8 b = 0xff;
983 u8 pwm;
984 struct i2c_msg msg[] = { {.addr = 0x50,.flags = 0,.buf = &b,.len = 1},
985 {.addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1}
986 };
987
988 if ((i2c_transfer(&budget_av->budget.i2c_adap, msg, 2) != 2)
989 || (pwm == 0xff))
990 pwm = 0x48;
991
992 return pwm;
993}
994
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700995#define SUBID_DVBS_KNC1 0x0010
996#define SUBID_DVBS_KNC1_PLUS 0x0011
997#define SUBID_DVBS_TYPHOON 0x4f56
998#define SUBID_DVBS_CINERGY1200 0x1154
Regis Prevotf8bf1342006-01-11 23:31:53 -0200999#define SUBID_DVBS_CYNERGY1200N 0x1155
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001000
Regis Prevotf8bf1342006-01-11 23:31:53 -02001001#define SUBID_DVBS_TV_STAR 0x0014
1002#define SUBID_DVBS_TV_STAR_CI 0x0016
Thilo Berger36f4f332006-02-27 00:09:08 -03001003#define SUBID_DVBS_EASYWATCH 0x001e
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001004#define SUBID_DVBC_KNC1 0x0020
1005#define SUBID_DVBC_KNC1_PLUS 0x0021
1006#define SUBID_DVBC_CINERGY1200 0x1156
1007
1008#define SUBID_DVBT_KNC1_PLUS 0x0031
1009#define SUBID_DVBT_KNC1 0x0030
1010#define SUBID_DVBT_CINERGY1200 0x1157
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011
1012static void frontend_init(struct budget_av *budget_av)
1013{
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001014 struct saa7146_dev * saa = budget_av->budget.dev;
1015 struct dvb_frontend * fe = NULL;
1016
1017 switch (saa->pci->subsystem_device) {
1018 case SUBID_DVBS_KNC1_PLUS:
1019 case SUBID_DVBC_KNC1_PLUS:
1020 case SUBID_DVBT_KNC1_PLUS:
1021 // Enable / PowerON Frontend
Andrew de Quincey87b2eca2005-09-09 13:03:09 -07001022 saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001023 saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 break;
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001025 }
1026
1027 switch (saa->pci->subsystem_device) {
1028
1029 case SUBID_DVBS_KNC1:
Andrew de Quinceyeffa7912006-01-09 15:25:09 -02001030 if (saa->pci->subsystem_vendor == 0x1894) {
1031 fe = stv0299_attach(&cinergy_1200s_1894_0010_config,
1032 &budget_av->budget.i2c_adap);
1033 } else {
1034 fe = stv0299_attach(&typhoon_config,
1035 &budget_av->budget.i2c_adap);
1036 }
1037 break;
1038
Regis Prevotf8bf1342006-01-11 23:31:53 -02001039 case SUBID_DVBS_TV_STAR:
1040 case SUBID_DVBS_TV_STAR_CI:
1041 case SUBID_DVBS_CYNERGY1200N:
Thilo Berger36f4f332006-02-27 00:09:08 -03001042 case SUBID_DVBS_EASYWATCH:
Regis Prevotf8bf1342006-01-11 23:31:53 -02001043 fe = stv0299_attach(&philips_sd1878_config,
1044 &budget_av->budget.i2c_adap);
1045 break;
1046
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001047 case SUBID_DVBS_KNC1_PLUS:
1048 case SUBID_DVBS_TYPHOON:
1049 fe = stv0299_attach(&typhoon_config,
1050 &budget_av->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 break;
1052
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001053 case SUBID_DVBS_CINERGY1200:
1054 fe = stv0299_attach(&cinergy_1200s_config,
1055 &budget_av->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 break;
1057
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001058 case SUBID_DVBC_KNC1:
1059 case SUBID_DVBC_KNC1_PLUS:
1060 fe = tda10021_attach(&philips_cu1216_config,
1061 &budget_av->budget.i2c_adap,
1062 read_pwm(budget_av));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 break;
1064
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001065 case SUBID_DVBT_KNC1:
1066 case SUBID_DVBT_KNC1_PLUS:
1067 fe = tda10046_attach(&philips_tu1216_config,
1068 &budget_av->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 break;
1070
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001071 case SUBID_DVBC_CINERGY1200:
1072 fe = tda10021_attach(&philips_cu1216_config,
1073 &budget_av->budget.i2c_adap,
1074 read_pwm(budget_av));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 break;
1076
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001077 case SUBID_DVBT_CINERGY1200:
1078 fe = tda10046_attach(&philips_tu1216_config,
1079 &budget_av->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 break;
1081 }
1082
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001083 if (fe == NULL) {
1084 printk(KERN_ERR "budget-av: A frontend driver was not found "
1085 "for device %04x/%04x subsystem %04x/%04x\n",
1086 saa->pci->vendor,
1087 saa->pci->device,
1088 saa->pci->subsystem_vendor,
1089 saa->pci->subsystem_device);
1090 return;
1091 }
1092
1093 budget_av->budget.dvb_frontend = fe;
1094
1095 if (dvb_register_frontend(&budget_av->budget.dvb_adapter,
1096 budget_av->budget.dvb_frontend)) {
1097 printk(KERN_ERR "budget-av: Frontend registration failed!\n");
1098 if (budget_av->budget.dvb_frontend->ops->release)
1099 budget_av->budget.dvb_frontend->ops->release(budget_av->budget.dvb_frontend);
1100 budget_av->budget.dvb_frontend = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 }
1102}
1103
1104
1105static void budget_av_irq(struct saa7146_dev *dev, u32 * isr)
1106{
1107 struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;
1108
1109 dprintk(8, "dev: %p, budget_av: %p\n", dev, budget_av);
1110
1111 if (*isr & MASK_10)
1112 ttpci_budget_irq10_handler(dev, isr);
1113}
1114
1115static int budget_av_detach(struct saa7146_dev *dev)
1116{
1117 struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;
1118 int err;
1119
1120 dprintk(2, "dev: %p\n", dev);
1121
1122 if (1 == budget_av->has_saa7113) {
1123 saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO);
1124
1125 msleep(200);
1126
1127 saa7146_unregister_device(&budget_av->vd, dev);
1128 }
1129
1130 if (budget_av->budget.ci_present)
1131 ciintf_deinit(budget_av);
1132
1133 if (budget_av->budget.dvb_frontend != NULL)
1134 dvb_unregister_frontend(budget_av->budget.dvb_frontend);
1135 err = ttpci_budget_deinit(&budget_av->budget);
1136
1137 kfree(budget_av);
1138
1139 return err;
1140}
1141
1142static struct saa7146_ext_vv vv_data;
1143
1144static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1145{
1146 struct budget_av *budget_av;
1147 u8 *mac;
1148 int err;
1149
1150 dprintk(2, "dev: %p\n", dev);
1151
Panagiotis Issaris74081872006-01-11 19:40:56 -02001152 if (!(budget_av = kzalloc(sizeof(struct budget_av), GFP_KERNEL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 return -ENOMEM;
1154
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001155 budget_av->has_saa7113 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 budget_av->budget.ci_present = 0;
1157
1158 dev->ext_priv = budget_av;
1159
1160 if ((err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE))) {
1161 kfree(budget_av);
1162 return err;
1163 }
1164
1165 /* knc1 initialization */
1166 saa7146_write(dev, DD1_STREAM_B, 0x04000000);
1167 saa7146_write(dev, DD1_INIT, 0x07000600);
1168 saa7146_write(dev, MC2, MASK_09 | MASK_25 | MASK_10 | MASK_26);
1169
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001170 if (saa7113_init(budget_av) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 budget_av->has_saa7113 = 1;
1172
1173 if (0 != saa7146_vv_init(dev, &vv_data)) {
1174 /* fixme: proper cleanup here */
1175 ERR(("cannot init vv subsystem.\n"));
1176 return err;
1177 }
1178
1179 if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) {
1180 /* fixme: proper cleanup here */
1181 ERR(("cannot register capture v4l2 device.\n"));
1182 return err;
1183 }
1184
1185 /* beware: this modifies dev->vv ... */
1186 saa7146_set_hps_source_and_sync(dev, SAA7146_HPS_SOURCE_PORT_A,
1187 SAA7146_HPS_SYNC_PORT_A);
1188
1189 saa7113_setinput(budget_av, 0);
1190 } else {
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001191 ciintf_init(budget_av);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 }
1193
1194 /* fixme: find some sane values here... */
1195 saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
1196
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001197 mac = budget_av->budget.dvb_adapter.proposed_mac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 if (i2c_readregs(&budget_av->budget.i2c_adap, 0xa0, 0x30, mac, 6)) {
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001199 printk(KERN_ERR "KNC1-%d: Could not read MAC from KNC1 card\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001200 budget_av->budget.dvb_adapter.num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 memset(mac, 0, 6);
1202 } else {
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001203 printk(KERN_INFO "KNC1-%d: MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001204 budget_av->budget.dvb_adapter.num,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
1206 }
1207
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001208 budget_av->budget.dvb_adapter.priv = budget_av;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 frontend_init(budget_av);
1210
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 return 0;
1212}
1213
1214#define KNC1_INPUTS 2
1215static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
1216 {0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
1217 {1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
1218};
1219
1220static struct saa7146_extension_ioctls ioctls[] = {
1221 {VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE},
1222 {VIDIOC_G_INPUT, SAA7146_EXCLUSIVE},
1223 {VIDIOC_S_INPUT, SAA7146_EXCLUSIVE},
1224 {0, 0}
1225};
1226
1227static int av_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
1228{
1229 struct saa7146_dev *dev = fh->dev;
1230 struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;
1231
1232 switch (cmd) {
1233 case VIDIOC_ENUMINPUT:{
1234 struct v4l2_input *i = arg;
1235
1236 dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index);
1237 if (i->index < 0 || i->index >= KNC1_INPUTS) {
1238 return -EINVAL;
1239 }
1240 memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input));
1241 return 0;
1242 }
1243 case VIDIOC_G_INPUT:{
1244 int *input = (int *) arg;
1245
1246 *input = budget_av->cur_input;
1247
1248 dprintk(1, "VIDIOC_G_INPUT %d.\n", *input);
1249 return 0;
1250 }
1251 case VIDIOC_S_INPUT:{
1252 int input = *(int *) arg;
1253 dprintk(1, "VIDIOC_S_INPUT %d.\n", input);
1254 return saa7113_setinput(budget_av, input);
1255 }
1256 default:
1257 return -ENOIOCTLCMD;
1258 }
1259 return 0;
1260}
1261
1262static struct saa7146_standard standard[] = {
1263 {.name = "PAL",.id = V4L2_STD_PAL,
1264 .v_offset = 0x17,.v_field = 288,
1265 .h_offset = 0x14,.h_pixels = 680,
1266 .v_max_out = 576,.h_max_out = 768 },
1267
1268 {.name = "NTSC",.id = V4L2_STD_NTSC,
1269 .v_offset = 0x16,.v_field = 240,
1270 .h_offset = 0x06,.h_pixels = 708,
1271 .v_max_out = 480,.h_max_out = 640, },
1272};
1273
1274static struct saa7146_ext_vv vv_data = {
1275 .inputs = 2,
1276 .capabilities = 0, // perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113
1277 .flags = 0,
1278 .stds = &standard[0],
1279 .num_stds = sizeof(standard) / sizeof(struct saa7146_standard),
1280 .ioctls = &ioctls[0],
1281 .ioctl = av_ioctl,
1282};
1283
1284static struct saa7146_extension budget_extension;
1285
1286MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S);
1287MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C);
1288MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
Regis Prevotf8bf1342006-01-11 23:31:53 -02001289MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
Thilo Berger36f4f332006-02-27 00:09:08 -03001290MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
Johannes Stezenbach2d4f2c22005-05-16 21:54:23 -07001291MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
1292MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP);
1293MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);
Regis Prevotf8bf1342006-01-11 23:31:53 -02001295MAKE_BUDGET_INFO(cin1200sn, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C);
1297MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T);
1298
1299static struct pci_device_id pci_tbl[] = {
1300 MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56),
Johannes Stezenbach2d4f2c22005-05-16 21:54:23 -07001301 MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010),
Andrew de Quinceyeffa7912006-01-09 15:25:09 -02001302 MAKE_EXTENSION_PCI(knc1s, 0x1894, 0x0010),
Johannes Stezenbach2d4f2c22005-05-16 21:54:23 -07001303 MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011),
Regis Prevotf8bf1342006-01-11 23:31:53 -02001304 MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014),
1305 MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
Thilo Berger36f4f332006-02-27 00:09:08 -03001306 MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
Johannes Stezenbach2d4f2c22005-05-16 21:54:23 -07001308 MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309 MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),
Johannes Stezenbach2d4f2c22005-05-16 21:54:23 -07001310 MAKE_EXTENSION_PCI(knc1tp, 0x1894, 0x0031),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154),
Regis Prevotf8bf1342006-01-11 23:31:53 -02001312 MAKE_EXTENSION_PCI(cin1200sn, 0x153b, 0x1155),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156),
1314 MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157),
1315 {
1316 .vendor = 0,
1317 }
1318};
1319
1320MODULE_DEVICE_TABLE(pci, pci_tbl);
1321
1322static struct saa7146_extension budget_extension = {
Julian Scheel27b05fd2005-07-12 13:58:39 -07001323 .name = "budget_av",
Oliver Endriss69459f3d2005-12-01 00:51:48 -08001324 .flags = SAA7146_I2C_SHORT_DELAY,
1325
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 .pci_tbl = pci_tbl,
1327
1328 .module = THIS_MODULE,
1329 .attach = budget_av_attach,
1330 .detach = budget_av_detach,
1331
1332 .irq_mask = MASK_10,
1333 .irq_func = budget_av_irq,
1334};
1335
1336static int __init budget_av_init(void)
1337{
1338 return saa7146_register_extension(&budget_extension);
1339}
1340
1341static void __exit budget_av_exit(void)
1342{
1343 saa7146_unregister_extension(&budget_extension);
1344}
1345
1346module_init(budget_av_init);
1347module_exit(budget_av_exit);
1348
1349MODULE_LICENSE("GPL");
1350MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others");
1351MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
1352 "budget PCI DVB w/ analog input and CI-module (e.g. the KNC cards)");