blob: 68004187860f433fb13f9f0df8bed36c69e6f894 [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
Andrew de Quincey86f40cc2006-03-30 15:53:35 -030063/* GPIO Connections:
64 * 0 - Vcc/Reset (Reset is controlled by capacitor). Resets the frontend *AS WELL*!
65 * 1 - CI memory select 0=>IO memory, 1=>Attribute Memory
66 * 2 - CI Card Enable (Active Low)
67 * 3 - CI Card Detect
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -070068 */
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
Andrew de Quincey86f40cc2006-03-30 15:53:35 -0300217 /* reinitialise the frontend */
218 dvb_frontend_reinitialise(budget_av->budget.dvb_frontend);
219
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700220 if (timeout <= 0)
221 {
222 printk(KERN_ERR "budget-av: cam reset failed (timeout).\n");
223 saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700224 return -ETIMEDOUT;
225 }
226
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 return 0;
228}
229
230static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
231{
232 struct budget_av *budget_av = (struct budget_av *) ca->data;
233 struct saa7146_dev *saa = budget_av->budget.dev;
234
235 if (slot != 0)
236 return -EINVAL;
237
238 dprintk(1, "ciintf_slot_shutdown\n");
239
240 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
241 budget_av->slot_status = 0;
242 return 0;
243}
244
245static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
246{
247 struct budget_av *budget_av = (struct budget_av *) ca->data;
248 struct saa7146_dev *saa = budget_av->budget.dev;
249
250 if (slot != 0)
251 return -EINVAL;
252
253 dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status);
254
255 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
256 return 0;
257}
258
259static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
260{
261 struct budget_av *budget_av = (struct budget_av *) ca->data;
262 struct saa7146_dev *saa = budget_av->budget.dev;
Andrew de Quincey2d0235d2006-01-09 15:25:05 -0200263 int cam_present = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
265 if (slot != 0)
266 return -EINVAL;
267
Andrew de Quincey2d0235d2006-01-09 15:25:05 -0200268 if (!budget_av->slot_status)
269 {
270 // first of all test the card detect line
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
272 udelay(1);
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700273 if (saa7146_read(saa, PSR) & MASK_06)
274 {
Andrew de Quincey2d0235d2006-01-09 15:25:05 -0200275 cam_present = 1;
276 }
277 saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
278
279 // that is unreliable however, so try and read from IO memory
280 if (!cam_present)
281 {
Michael Krufky50c25ff2006-01-09 15:25:34 -0200282 saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
Andrew de Quincey2d0235d2006-01-09 15:25:05 -0200283 if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) != -ETIMEDOUT)
284 {
285 cam_present = 1;
286 }
287 }
288
289 // did we find something?
290 if (cam_present) {
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700291 printk(KERN_INFO "budget-av: cam inserted\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 budget_av->slot_status = 1;
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700293 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 } else if (!open) {
295 saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
296 if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT)
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700297 {
298 printk(KERN_INFO "budget-av: cam ejected\n");
299 saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 budget_av->slot_status = 0;
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700301 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 }
303
304 if (budget_av->slot_status == 1)
305 return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
306
307 return 0;
308}
309
310static int ciintf_init(struct budget_av *budget_av)
311{
312 struct saa7146_dev *saa = budget_av->budget.dev;
313 int result;
314
315 memset(&budget_av->ca, 0, sizeof(struct dvb_ca_en50221));
316
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700317 saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
318 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO);
320 saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
321
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 /* Enable DEBI pins */
323 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
324
325 /* register CI interface */
326 budget_av->ca.owner = THIS_MODULE;
327 budget_av->ca.read_attribute_mem = ciintf_read_attribute_mem;
328 budget_av->ca.write_attribute_mem = ciintf_write_attribute_mem;
329 budget_av->ca.read_cam_control = ciintf_read_cam_control;
330 budget_av->ca.write_cam_control = ciintf_write_cam_control;
331 budget_av->ca.slot_reset = ciintf_slot_reset;
332 budget_av->ca.slot_shutdown = ciintf_slot_shutdown;
333 budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable;
334 budget_av->ca.poll_slot_status = ciintf_poll_slot_status;
335 budget_av->ca.data = budget_av;
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700336
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700337 if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 &budget_av->ca, 0, 1)) != 0) {
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700339 printk(KERN_ERR "budget-av: ci initialisation failed.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 goto error;
341 }
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700342
343 printk(KERN_INFO "budget-av: ci interface initialised.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 budget_av->budget.ci_present = 1;
345 return 0;
346
347error:
348 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
349 return result;
350}
351
352static void ciintf_deinit(struct budget_av *budget_av)
353{
354 struct saa7146_dev *saa = budget_av->budget.dev;
355
356 saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
357 saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
358 saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
359 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
360
361 /* release the CA device */
362 dvb_ca_en50221_release(&budget_av->ca);
363
364 /* disable DEBI pins */
365 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
366}
367
368
369static const u8 saa7113_tab[] = {
370 0x01, 0x08,
371 0x02, 0xc0,
372 0x03, 0x33,
373 0x04, 0x00,
374 0x05, 0x00,
375 0x06, 0xeb,
376 0x07, 0xe0,
377 0x08, 0x28,
378 0x09, 0x00,
379 0x0a, 0x80,
380 0x0b, 0x47,
381 0x0c, 0x40,
382 0x0d, 0x00,
383 0x0e, 0x01,
384 0x0f, 0x44,
385
386 0x10, 0x08,
387 0x11, 0x0c,
388 0x12, 0x7b,
389 0x13, 0x00,
390 0x15, 0x00, 0x16, 0x00, 0x17, 0x00,
391
392 0x57, 0xff,
393 0x40, 0x82, 0x58, 0x00, 0x59, 0x54, 0x5a, 0x07,
394 0x5b, 0x83, 0x5e, 0x00,
395 0xff
396};
397
398static int saa7113_init(struct budget_av *budget_av)
399{
400 struct budget *budget = &budget_av->budget;
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700401 struct saa7146_dev *saa = budget->dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 const u8 *data = saa7113_tab;
403
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700404 saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTHI);
405 msleep(200);
406
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 if (i2c_writereg(&budget->i2c_adap, 0x4a, 0x01, 0x08) != 1) {
408 dprintk(1, "saa7113 not found on KNC card\n");
409 return -ENODEV;
410 }
411
412 dprintk(1, "saa7113 detected and initializing\n");
413
414 while (*data != 0xff) {
415 i2c_writereg(&budget->i2c_adap, 0x4a, *data, *(data + 1));
416 data += 2;
417 }
418
419 dprintk(1, "saa7113 status=%02x\n", i2c_readreg(&budget->i2c_adap, 0x4a, 0x1f));
420
421 return 0;
422}
423
424static int saa7113_setinput(struct budget_av *budget_av, int input)
425{
426 struct budget *budget = &budget_av->budget;
427
428 if (1 != budget_av->has_saa7113)
429 return -ENODEV;
430
431 if (input == 1) {
432 i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc7);
433 i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x80);
434 } else if (input == 0) {
435 i2c_writereg(&budget->i2c_adap, 0x4a, 0x02, 0xc0);
436 i2c_writereg(&budget->i2c_adap, 0x4a, 0x09, 0x00);
437 } else
438 return -EINVAL;
439
440 budget_av->cur_input = input;
441 return 0;
442}
443
444
445static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
446{
447 u8 aclk = 0;
448 u8 bclk = 0;
449 u8 m1;
450
451 aclk = 0xb5;
452 if (srate < 2000000)
453 bclk = 0x86;
454 else if (srate < 5000000)
455 bclk = 0x89;
456 else if (srate < 15000000)
457 bclk = 0x8f;
458 else if (srate < 45000000)
459 bclk = 0x95;
460
461 m1 = 0x14;
462 if (srate < 4000000)
463 m1 = 0x10;
464
465 stv0299_writereg(fe, 0x13, aclk);
466 stv0299_writereg(fe, 0x14, bclk);
467 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
468 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
469 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
470 stv0299_writereg(fe, 0x0f, 0x80 | m1);
471
472 return 0;
473}
474
Andrew de Quinceye87d41c2006-04-18 17:47:11 -0300475static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe,
476 struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 u32 div;
479 u8 buf[4];
Andrew de Quinceye87d41c2006-04-18 17:47:11 -0300480 struct budget *budget = (struct budget *) fe->dvb->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
482
483 if ((params->frequency < 950000) || (params->frequency > 2150000))
484 return -EINVAL;
485
486 div = (params->frequency + (125 - 1)) / 125; // round correctly
487 buf[0] = (div >> 8) & 0x7f;
488 buf[1] = div & 0xff;
489 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
490 buf[3] = 0x20;
491
492 if (params->u.qpsk.symbol_rate < 4000000)
493 buf[3] |= 1;
494
495 if (params->frequency < 1250000)
496 buf[3] |= 0;
497 else if (params->frequency < 1550000)
498 buf[3] |= 0x40;
499 else if (params->frequency < 2050000)
500 buf[3] |= 0x80;
501 else if (params->frequency < 2150000)
502 buf[3] |= 0xC0;
503
Andrew de Quinceye87d41c2006-04-18 17:47:11 -0300504 if (fe->ops->i2c_gate_ctrl)
505 fe->ops->i2c_gate_ctrl(fe, 1);
506 if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 return -EIO;
508 return 0;
509}
510
Andrew de Quinceyeffa7912006-01-09 15:25:09 -0200511#define MIN2(a,b) ((a) < (b) ? (a) : (b))
512#define MIN3(a,b,c) MIN2(MIN2(a,b),c)
513
Andrew de Quinceye87d41c2006-04-18 17:47:11 -0300514static int philips_su1278sh2_tua6100_tuner_set_params(struct dvb_frontend *fe,
515 struct dvb_frontend_parameters *params)
Andrew de Quinceyeffa7912006-01-09 15:25:09 -0200516{
517 u8 reg0 [2] = { 0x00, 0x00 };
518 u8 reg1 [4] = { 0x01, 0x00, 0x00, 0x00 };
519 u8 reg2 [3] = { 0x02, 0x00, 0x00 };
520 int _fband;
521 int first_ZF;
522 int R, A, N, P, M;
523 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = NULL,.len = 0 };
524 int freq = params->frequency;
Andrew de Quinceye87d41c2006-04-18 17:47:11 -0300525 struct budget *budget = (struct budget *) fe->dvb->priv;
Andrew de Quinceyeffa7912006-01-09 15:25:09 -0200526
527 first_ZF = (freq) / 1000;
528
529 if (abs(MIN2(abs(first_ZF-1190),abs(first_ZF-1790))) <
530 abs(MIN3(abs(first_ZF-1202),abs(first_ZF-1542),abs(first_ZF-1890))))
531 _fband = 2;
532 else
533 _fband = 3;
534
535 if (_fband == 2) {
536 if (((first_ZF >= 950) && (first_ZF < 1350)) ||
537 ((first_ZF >= 1430) && (first_ZF < 1950)))
538 reg0[1] = 0x07;
539 else if (((first_ZF >= 1350) && (first_ZF < 1430)) ||
540 ((first_ZF >= 1950) && (first_ZF < 2150)))
541 reg0[1] = 0x0B;
542 }
543
544 if(_fband == 3) {
545 if (((first_ZF >= 950) && (first_ZF < 1350)) ||
546 ((first_ZF >= 1455) && (first_ZF < 1950)))
547 reg0[1] = 0x07;
548 else if (((first_ZF >= 1350) && (first_ZF < 1420)) ||
549 ((first_ZF >= 1950) && (first_ZF < 2150)))
550 reg0[1] = 0x0B;
551 else if ((first_ZF >= 1420) && (first_ZF < 1455))
552 reg0[1] = 0x0F;
553 }
554
555 if (first_ZF > 1525)
556 reg1[1] |= 0x80;
557 else
558 reg1[1] &= 0x7F;
559
560 if (_fband == 2) {
561 if (first_ZF > 1430) { /* 1430MHZ */
562 reg1[1] &= 0xCF; /* N2 */
563 reg2[1] &= 0xCF; /* R2 */
564 reg2[1] |= 0x10;
565 } else {
566 reg1[1] &= 0xCF; /* N2 */
567 reg1[1] |= 0x20;
568 reg2[1] &= 0xCF; /* R2 */
569 reg2[1] |= 0x10;
570 }
571 }
572
573 if (_fband == 3) {
574 if ((first_ZF >= 1455) &&
575 (first_ZF < 1630)) {
576 reg1[1] &= 0xCF; /* N2 */
577 reg1[1] |= 0x20;
578 reg2[1] &= 0xCF; /* R2 */
579 } else {
580 if (first_ZF < 1455) {
581 reg1[1] &= 0xCF; /* N2 */
582 reg1[1] |= 0x20;
583 reg2[1] &= 0xCF; /* R2 */
584 reg2[1] |= 0x10;
585 } else {
586 if (first_ZF >= 1630) {
587 reg1[1] &= 0xCF; /* N2 */
588 reg2[1] &= 0xCF; /* R2 */
589 reg2[1] |= 0x10;
590 }
591 }
592 }
593 }
594
595 /* set ports, enable P0 for symbol rates > 4Ms/s */
596 if (params->u.qpsk.symbol_rate >= 4000000)
597 reg1[1] |= 0x0c;
598 else
599 reg1[1] |= 0x04;
600
601 reg2[1] |= 0x0c;
602
603 R = 64;
604 A = 64;
605 P = 64; //32
606
607 M = (freq * R) / 4; /* in Mhz */
608 N = (M - A * 1000) / (P * 1000);
609
610 reg1[1] |= (N >> 9) & 0x03;
611 reg1[2] = (N >> 1) & 0xff;
612 reg1[3] = (N << 7) & 0x80;
613
614 reg2[1] |= (R >> 8) & 0x03;
615 reg2[2] = R & 0xFF; /* R */
616
617 reg1[3] |= A & 0x7f; /* A */
618
619 if (P == 64)
620 reg1[1] |= 0x40; /* Prescaler 64/65 */
621
622 reg0[1] |= 0x03;
623
624 /* already enabled - do not reenable i2c repeater or TX fails */
Andrew de Quinceye87d41c2006-04-18 17:47:11 -0300625 if (fe->ops->i2c_gate_ctrl)
626 fe->ops->i2c_gate_ctrl(fe, 1);
Andrew de Quinceyeffa7912006-01-09 15:25:09 -0200627 msg.buf = reg0;
628 msg.len = sizeof(reg0);
Andrew de Quinceye87d41c2006-04-18 17:47:11 -0300629 if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
Andrew de Quinceyeffa7912006-01-09 15:25:09 -0200630 return -EIO;
631
Andrew de Quinceye87d41c2006-04-18 17:47:11 -0300632 if (fe->ops->i2c_gate_ctrl)
633 fe->ops->i2c_gate_ctrl(fe, 1);
Andrew de Quinceyeffa7912006-01-09 15:25:09 -0200634 msg.buf = reg1;
635 msg.len = sizeof(reg1);
Andrew de Quinceye87d41c2006-04-18 17:47:11 -0300636 if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
Andrew de Quinceyeffa7912006-01-09 15:25:09 -0200637 return -EIO;
638
Andrew de Quinceye87d41c2006-04-18 17:47:11 -0300639 if (fe->ops->i2c_gate_ctrl)
640 fe->ops->i2c_gate_ctrl(fe, 1);
Andrew de Quinceyeffa7912006-01-09 15:25:09 -0200641 msg.buf = reg2;
642 msg.len = sizeof(reg2);
Andrew de Quinceye87d41c2006-04-18 17:47:11 -0300643 if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
Andrew de Quinceyeffa7912006-01-09 15:25:09 -0200644 return -EIO;
645
646 return 0;
647}
648
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649static u8 typhoon_cinergy1200s_inittab[] = {
650 0x01, 0x15,
651 0x02, 0x30,
652 0x03, 0x00,
653 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
654 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
655 0x06, 0x40, /* DAC not used, set to high impendance mode */
656 0x07, 0x00, /* DAC LSB */
657 0x08, 0x40, /* DiSEqC off */
658 0x09, 0x00, /* FIFO */
659 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
660 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
661 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
662 0x10, 0x3f, // AGC2 0x3d
663 0x11, 0x84,
Oliver Endrissff29d062005-11-08 21:35:43 -0800664 0x12, 0xb9,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 0x15, 0xc9, // lock detector threshold
666 0x16, 0x00,
667 0x17, 0x00,
668 0x18, 0x00,
669 0x19, 0x00,
670 0x1a, 0x00,
671 0x1f, 0x50,
672 0x20, 0x00,
673 0x21, 0x00,
674 0x22, 0x00,
675 0x23, 0x00,
676 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
677 0x29, 0x1e, // 1/2 threshold
678 0x2a, 0x14, // 2/3 threshold
679 0x2b, 0x0f, // 3/4 threshold
680 0x2c, 0x09, // 5/6 threshold
681 0x2d, 0x05, // 7/8 threshold
682 0x2e, 0x01,
683 0x31, 0x1f, // test all FECs
684 0x32, 0x19, // viterbi and synchro search
685 0x33, 0xfc, // rs control
686 0x34, 0x93, // error control
687 0x0f, 0x92,
688 0xff, 0xff
689};
690
691static struct stv0299_config typhoon_config = {
692 .demod_address = 0x68,
693 .inittab = typhoon_cinergy1200s_inittab,
694 .mclk = 88000000UL,
695 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 .skip_reinit = 0,
697 .lock_output = STV0229_LOCKOUTPUT_1,
698 .volt13_op0_op1 = STV0299_VOLT13_OP0,
699 .min_delay_ms = 100,
700 .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701};
702
703
704static struct stv0299_config cinergy_1200s_config = {
705 .demod_address = 0x68,
706 .inittab = typhoon_cinergy1200s_inittab,
707 .mclk = 88000000UL,
708 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 .skip_reinit = 0,
710 .lock_output = STV0229_LOCKOUTPUT_0,
711 .volt13_op0_op1 = STV0299_VOLT13_OP0,
712 .min_delay_ms = 100,
713 .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714};
715
Andrew de Quinceyeffa7912006-01-09 15:25:09 -0200716static struct stv0299_config cinergy_1200s_1894_0010_config = {
717 .demod_address = 0x68,
718 .inittab = typhoon_cinergy1200s_inittab,
719 .mclk = 88000000UL,
720 .invert = 1,
721 .skip_reinit = 0,
722 .lock_output = STV0229_LOCKOUTPUT_1,
723 .volt13_op0_op1 = STV0299_VOLT13_OP0,
724 .min_delay_ms = 100,
725 .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
Andrew de Quinceyeffa7912006-01-09 15:25:09 -0200726};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727
Andrew de Quinceye87d41c2006-04-18 17:47:11 -0300728static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729{
730 struct budget *budget = (struct budget *) fe->dvb->priv;
731 u8 buf[4];
732 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
733
734#define TUNER_MUL 62500
735
736 u32 div = (params->frequency + 36125000 + TUNER_MUL / 2) / TUNER_MUL;
737
738 buf[0] = (div >> 8) & 0x7f;
739 buf[1] = div & 0xff;
Johannes Stezenbacheef57642005-07-07 17:57:58 -0700740 buf[2] = 0x86;
741 buf[3] = (params->frequency < 150000000 ? 0x01 :
742 params->frequency < 445000000 ? 0x02 : 0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
Andrew de Quinceye87d41c2006-04-18 17:47:11 -0300744 if (fe->ops->i2c_gate_ctrl)
745 fe->ops->i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
747 return -EIO;
748 return 0;
749}
750
751static struct tda10021_config philips_cu1216_config = {
752 .demod_address = 0x0c,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753};
754
755
756
757
Andrew de Quinceye87d41c2006-04-18 17:47:11 -0300758static int philips_tu1216_tuner_init(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759{
760 struct budget *budget = (struct budget *) fe->dvb->priv;
761 static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
762 struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
763
764 // setup PLL configuration
Andrew de Quinceye87d41c2006-04-18 17:47:11 -0300765 if (fe->ops->i2c_gate_ctrl)
766 fe->ops->i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
768 return -EIO;
769 msleep(1);
770
771 return 0;
772}
773
Andrew de Quinceye87d41c2006-04-18 17:47:11 -0300774static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775{
776 struct budget *budget = (struct budget *) fe->dvb->priv;
777 u8 tuner_buf[4];
778 struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len =
779 sizeof(tuner_buf) };
780 int tuner_frequency = 0;
781 u8 band, cp, filter;
782
783 // determine charge pump
784 tuner_frequency = params->frequency + 36166000;
785 if (tuner_frequency < 87000000)
786 return -EINVAL;
787 else if (tuner_frequency < 130000000)
788 cp = 3;
789 else if (tuner_frequency < 160000000)
790 cp = 5;
791 else if (tuner_frequency < 200000000)
792 cp = 6;
793 else if (tuner_frequency < 290000000)
794 cp = 3;
795 else if (tuner_frequency < 420000000)
796 cp = 5;
797 else if (tuner_frequency < 480000000)
798 cp = 6;
799 else if (tuner_frequency < 620000000)
800 cp = 3;
801 else if (tuner_frequency < 830000000)
802 cp = 5;
803 else if (tuner_frequency < 895000000)
804 cp = 7;
805 else
806 return -EINVAL;
807
808 // determine band
809 if (params->frequency < 49000000)
810 return -EINVAL;
811 else if (params->frequency < 161000000)
812 band = 1;
813 else if (params->frequency < 444000000)
814 band = 2;
815 else if (params->frequency < 861000000)
816 band = 4;
817 else
818 return -EINVAL;
819
820 // setup PLL filter
821 switch (params->u.ofdm.bandwidth) {
822 case BANDWIDTH_6_MHZ:
823 filter = 0;
824 break;
825
826 case BANDWIDTH_7_MHZ:
827 filter = 0;
828 break;
829
830 case BANDWIDTH_8_MHZ:
831 filter = 1;
832 break;
833
834 default:
835 return -EINVAL;
836 }
837
838 // calculate divisor
839 // ((36166000+((1000000/6)/2)) + Finput)/(1000000/6)
840 tuner_frequency = (((params->frequency / 1000) * 6) + 217496) / 1000;
841
842 // setup tuner buffer
843 tuner_buf[0] = (tuner_frequency >> 8) & 0x7f;
844 tuner_buf[1] = tuner_frequency & 0xff;
845 tuner_buf[2] = 0xca;
846 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
847
Andrew de Quinceye87d41c2006-04-18 17:47:11 -0300848 if (fe->ops->i2c_gate_ctrl)
849 fe->ops->i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
851 return -EIO;
852
853 msleep(1);
854 return 0;
855}
856
857static int philips_tu1216_request_firmware(struct dvb_frontend *fe,
858 const struct firmware **fw, char *name)
859{
860 struct budget *budget = (struct budget *) fe->dvb->priv;
861
862 return request_firmware(fw, name, &budget->dev->pci->dev);
863}
864
865static struct tda1004x_config philips_tu1216_config = {
866
867 .demod_address = 0x8,
868 .invert = 1,
869 .invert_oclk = 1,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700870 .xtal_freq = TDA10046_XTAL_4M,
871 .agc_config = TDA10046_AGC_DEFAULT,
872 .if_freq = TDA10046_FREQ_3617,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 .request_firmware = philips_tu1216_request_firmware,
874};
875
Regis Prevotf8bf1342006-01-11 23:31:53 -0200876static u8 philips_sd1878_inittab[] = {
877 0x01, 0x15,
878 0x02, 0x30,
879 0x03, 0x00,
880 0x04, 0x7d,
881 0x05, 0x35,
882 0x06, 0x40,
883 0x07, 0x00,
884 0x08, 0x43,
885 0x09, 0x02,
886 0x0C, 0x51,
887 0x0D, 0x82,
888 0x0E, 0x23,
889 0x10, 0x3f,
890 0x11, 0x84,
891 0x12, 0xb9,
892 0x15, 0xc9,
893 0x16, 0x19,
894 0x17, 0x8c,
895 0x18, 0x59,
896 0x19, 0xf8,
897 0x1a, 0xfe,
898 0x1c, 0x7f,
899 0x1d, 0x00,
900 0x1e, 0x00,
901 0x1f, 0x50,
902 0x20, 0x00,
903 0x21, 0x00,
904 0x22, 0x00,
905 0x23, 0x00,
906 0x28, 0x00,
907 0x29, 0x28,
908 0x2a, 0x14,
909 0x2b, 0x0f,
910 0x2c, 0x09,
911 0x2d, 0x09,
912 0x31, 0x1f,
913 0x32, 0x19,
914 0x33, 0xfc,
915 0x34, 0x93,
916 0xff, 0xff
917};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918
Andrew de Quinceye87d41c2006-04-18 17:47:11 -0300919static int philips_sd1878_tda8261_tuner_set_params(struct dvb_frontend *fe,
920 struct dvb_frontend_parameters *params)
Regis Prevotf8bf1342006-01-11 23:31:53 -0200921{
922 u8 buf[4];
923 int rc;
924 struct i2c_msg tuner_msg = {.addr=0x60,.flags=0,.buf=buf,.len=sizeof(buf)};
Andrew de Quinceye87d41c2006-04-18 17:47:11 -0300925 struct budget *budget = (struct budget *) fe->dvb->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926
Regis Prevotf8bf1342006-01-11 23:31:53 -0200927 if((params->frequency < 950000) || (params->frequency > 2150000))
928 return -EINVAL;
929
930 rc=dvb_pll_configure(&dvb_pll_philips_sd1878_tda8261, buf,
931 params->frequency, 0);
932 if(rc < 0) return rc;
933
Andrew de Quinceye87d41c2006-04-18 17:47:11 -0300934 if (fe->ops->i2c_gate_ctrl)
935 fe->ops->i2c_gate_ctrl(fe, 1);
936 if(i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
Regis Prevotf8bf1342006-01-11 23:31:53 -0200937 return -EIO;
938
939 return 0;
940}
941
942static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe,
943 u32 srate, u32 ratio)
944{
945 u8 aclk = 0;
946 u8 bclk = 0;
947 u8 m1;
948
949 aclk = 0xb5;
950 if (srate < 2000000)
951 bclk = 0x86;
952 else if (srate < 5000000)
953 bclk = 0x89;
954 else if (srate < 15000000)
955 bclk = 0x8f;
956 else if (srate < 45000000)
957 bclk = 0x95;
958
959 m1 = 0x14;
960 if (srate < 4000000)
961 m1 = 0x10;
962
963 stv0299_writereg(fe, 0x0e, 0x23);
964 stv0299_writereg(fe, 0x0f, 0x94);
965 stv0299_writereg(fe, 0x10, 0x39);
966 stv0299_writereg(fe, 0x13, aclk);
967 stv0299_writereg(fe, 0x14, bclk);
968 stv0299_writereg(fe, 0x15, 0xc9);
969 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
970 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
971 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
972 stv0299_writereg(fe, 0x0f, 0x80 | m1);
973
974 return 0;
975}
976
977static struct stv0299_config philips_sd1878_config = {
978 .demod_address = 0x68,
979 .inittab = philips_sd1878_inittab,
980 .mclk = 88000000UL,
981 .invert = 0,
982 .skip_reinit = 0,
983 .lock_output = STV0229_LOCKOUTPUT_1,
984 .volt13_op0_op1 = STV0299_VOLT13_OP0,
985 .min_delay_ms = 100,
986 .set_symbol_rate = philips_sd1878_ci_set_symbol_rate,
Regis Prevotf8bf1342006-01-11 23:31:53 -0200987};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
989static u8 read_pwm(struct budget_av *budget_av)
990{
991 u8 b = 0xff;
992 u8 pwm;
993 struct i2c_msg msg[] = { {.addr = 0x50,.flags = 0,.buf = &b,.len = 1},
994 {.addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1}
995 };
996
997 if ((i2c_transfer(&budget_av->budget.i2c_adap, msg, 2) != 2)
998 || (pwm == 0xff))
999 pwm = 0x48;
1000
1001 return pwm;
1002}
1003
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001004#define SUBID_DVBS_KNC1 0x0010
1005#define SUBID_DVBS_KNC1_PLUS 0x0011
1006#define SUBID_DVBS_TYPHOON 0x4f56
1007#define SUBID_DVBS_CINERGY1200 0x1154
Regis Prevotf8bf1342006-01-11 23:31:53 -02001008#define SUBID_DVBS_CYNERGY1200N 0x1155
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001009
Regis Prevotf8bf1342006-01-11 23:31:53 -02001010#define SUBID_DVBS_TV_STAR 0x0014
1011#define SUBID_DVBS_TV_STAR_CI 0x0016
Thilo Berger36f4f332006-02-27 00:09:08 -03001012#define SUBID_DVBS_EASYWATCH 0x001e
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001013#define SUBID_DVBC_KNC1 0x0020
1014#define SUBID_DVBC_KNC1_PLUS 0x0021
1015#define SUBID_DVBC_CINERGY1200 0x1156
1016
1017#define SUBID_DVBT_KNC1_PLUS 0x0031
1018#define SUBID_DVBT_KNC1 0x0030
1019#define SUBID_DVBT_CINERGY1200 0x1157
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020
1021static void frontend_init(struct budget_av *budget_av)
1022{
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001023 struct saa7146_dev * saa = budget_av->budget.dev;
1024 struct dvb_frontend * fe = NULL;
1025
Andrew de Quincey473f5422006-04-13 17:29:07 -03001026 /* Enable / PowerON Frontend */
1027 saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
1028
1029 /* additional setup necessary for the PLUS cards */
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001030 switch (saa->pci->subsystem_device) {
1031 case SUBID_DVBS_KNC1_PLUS:
1032 case SUBID_DVBC_KNC1_PLUS:
1033 case SUBID_DVBT_KNC1_PLUS:
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001034 saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 break;
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001036 }
1037
1038 switch (saa->pci->subsystem_device) {
1039
1040 case SUBID_DVBS_KNC1:
Andrew de Quinceyeffa7912006-01-09 15:25:09 -02001041 if (saa->pci->subsystem_vendor == 0x1894) {
1042 fe = stv0299_attach(&cinergy_1200s_1894_0010_config,
1043 &budget_av->budget.i2c_adap);
Andrew de Quinceye87d41c2006-04-18 17:47:11 -03001044 if (fe) {
1045 fe->ops->tuner_ops.set_params = philips_su1278sh2_tua6100_tuner_set_params;
1046 }
Andrew de Quinceyeffa7912006-01-09 15:25:09 -02001047 } else {
1048 fe = stv0299_attach(&typhoon_config,
1049 &budget_av->budget.i2c_adap);
Andrew de Quinceye87d41c2006-04-18 17:47:11 -03001050 if (fe) {
1051 fe->ops->tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
1052 }
Andrew de Quinceyeffa7912006-01-09 15:25:09 -02001053 }
1054 break;
1055
Regis Prevotf8bf1342006-01-11 23:31:53 -02001056 case SUBID_DVBS_TV_STAR:
1057 case SUBID_DVBS_TV_STAR_CI:
1058 case SUBID_DVBS_CYNERGY1200N:
Thilo Berger36f4f332006-02-27 00:09:08 -03001059 case SUBID_DVBS_EASYWATCH:
Regis Prevotf8bf1342006-01-11 23:31:53 -02001060 fe = stv0299_attach(&philips_sd1878_config,
1061 &budget_av->budget.i2c_adap);
Andrew de Quinceye87d41c2006-04-18 17:47:11 -03001062 if (fe) {
1063 fe->ops->tuner_ops.set_params = philips_sd1878_tda8261_tuner_set_params;
1064 }
Regis Prevotf8bf1342006-01-11 23:31:53 -02001065 break;
1066
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001067 case SUBID_DVBS_KNC1_PLUS:
1068 case SUBID_DVBS_TYPHOON:
1069 fe = stv0299_attach(&typhoon_config,
1070 &budget_av->budget.i2c_adap);
Andrew de Quinceye87d41c2006-04-18 17:47:11 -03001071 if (fe) {
1072 fe->ops->tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
1073 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 break;
1075
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001076 case SUBID_DVBS_CINERGY1200:
1077 fe = stv0299_attach(&cinergy_1200s_config,
1078 &budget_av->budget.i2c_adap);
Andrew de Quinceye87d41c2006-04-18 17:47:11 -03001079 if (fe) {
1080 fe->ops->tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
1081 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 break;
1083
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001084 case SUBID_DVBC_KNC1:
1085 case SUBID_DVBC_KNC1_PLUS:
1086 fe = tda10021_attach(&philips_cu1216_config,
1087 &budget_av->budget.i2c_adap,
1088 read_pwm(budget_av));
Andrew de Quinceye87d41c2006-04-18 17:47:11 -03001089 if (fe) {
1090 fe->ops->tuner_ops.set_params = philips_cu1216_tuner_set_params;
1091 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 break;
1093
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001094 case SUBID_DVBT_KNC1:
1095 case SUBID_DVBT_KNC1_PLUS:
1096 fe = tda10046_attach(&philips_tu1216_config,
1097 &budget_av->budget.i2c_adap);
Andrew de Quinceye87d41c2006-04-18 17:47:11 -03001098 if (fe) {
1099 fe->ops->tuner_ops.init = philips_tu1216_tuner_init;
1100 fe->ops->tuner_ops.set_params = philips_tu1216_tuner_set_params;
1101 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 break;
1103
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001104 case SUBID_DVBC_CINERGY1200:
1105 fe = tda10021_attach(&philips_cu1216_config,
1106 &budget_av->budget.i2c_adap,
1107 read_pwm(budget_av));
Andrew de Quinceye87d41c2006-04-18 17:47:11 -03001108 if (fe) {
1109 fe->ops->tuner_ops.set_params = philips_cu1216_tuner_set_params;
1110 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 break;
1112
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001113 case SUBID_DVBT_CINERGY1200:
1114 fe = tda10046_attach(&philips_tu1216_config,
1115 &budget_av->budget.i2c_adap);
Andrew de Quincey6b3ccab2006-04-20 12:01:47 -03001116 if (fe) {
1117 fe->ops->tuner_ops.init = philips_tu1216_tuner_init;
1118 fe->ops->tuner_ops.set_params = philips_tu1216_tuner_set_params;
1119 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 break;
1121 }
1122
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001123 if (fe == NULL) {
1124 printk(KERN_ERR "budget-av: A frontend driver was not found "
1125 "for device %04x/%04x subsystem %04x/%04x\n",
1126 saa->pci->vendor,
1127 saa->pci->device,
1128 saa->pci->subsystem_vendor,
1129 saa->pci->subsystem_device);
1130 return;
1131 }
1132
1133 budget_av->budget.dvb_frontend = fe;
1134
1135 if (dvb_register_frontend(&budget_av->budget.dvb_adapter,
1136 budget_av->budget.dvb_frontend)) {
1137 printk(KERN_ERR "budget-av: Frontend registration failed!\n");
1138 if (budget_av->budget.dvb_frontend->ops->release)
1139 budget_av->budget.dvb_frontend->ops->release(budget_av->budget.dvb_frontend);
1140 budget_av->budget.dvb_frontend = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 }
1142}
1143
1144
1145static void budget_av_irq(struct saa7146_dev *dev, u32 * isr)
1146{
1147 struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;
1148
1149 dprintk(8, "dev: %p, budget_av: %p\n", dev, budget_av);
1150
1151 if (*isr & MASK_10)
1152 ttpci_budget_irq10_handler(dev, isr);
1153}
1154
1155static int budget_av_detach(struct saa7146_dev *dev)
1156{
1157 struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;
1158 int err;
1159
1160 dprintk(2, "dev: %p\n", dev);
1161
1162 if (1 == budget_av->has_saa7113) {
1163 saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO);
1164
1165 msleep(200);
1166
1167 saa7146_unregister_device(&budget_av->vd, dev);
1168 }
1169
1170 if (budget_av->budget.ci_present)
1171 ciintf_deinit(budget_av);
1172
1173 if (budget_av->budget.dvb_frontend != NULL)
1174 dvb_unregister_frontend(budget_av->budget.dvb_frontend);
1175 err = ttpci_budget_deinit(&budget_av->budget);
1176
1177 kfree(budget_av);
1178
1179 return err;
1180}
1181
1182static struct saa7146_ext_vv vv_data;
1183
1184static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1185{
1186 struct budget_av *budget_av;
1187 u8 *mac;
1188 int err;
1189
1190 dprintk(2, "dev: %p\n", dev);
1191
Panagiotis Issaris74081872006-01-11 19:40:56 -02001192 if (!(budget_av = kzalloc(sizeof(struct budget_av), GFP_KERNEL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 return -ENOMEM;
1194
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001195 budget_av->has_saa7113 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 budget_av->budget.ci_present = 0;
1197
1198 dev->ext_priv = budget_av;
1199
1200 if ((err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE))) {
1201 kfree(budget_av);
1202 return err;
1203 }
1204
1205 /* knc1 initialization */
1206 saa7146_write(dev, DD1_STREAM_B, 0x04000000);
1207 saa7146_write(dev, DD1_INIT, 0x07000600);
1208 saa7146_write(dev, MC2, MASK_09 | MASK_25 | MASK_10 | MASK_26);
1209
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001210 if (saa7113_init(budget_av) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 budget_av->has_saa7113 = 1;
1212
1213 if (0 != saa7146_vv_init(dev, &vv_data)) {
1214 /* fixme: proper cleanup here */
1215 ERR(("cannot init vv subsystem.\n"));
1216 return err;
1217 }
1218
1219 if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) {
1220 /* fixme: proper cleanup here */
1221 ERR(("cannot register capture v4l2 device.\n"));
1222 return err;
1223 }
1224
1225 /* beware: this modifies dev->vv ... */
1226 saa7146_set_hps_source_and_sync(dev, SAA7146_HPS_SOURCE_PORT_A,
1227 SAA7146_HPS_SYNC_PORT_A);
1228
1229 saa7113_setinput(budget_av, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 }
1231
1232 /* fixme: find some sane values here... */
1233 saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
1234
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001235 mac = budget_av->budget.dvb_adapter.proposed_mac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 if (i2c_readregs(&budget_av->budget.i2c_adap, 0xa0, 0x30, mac, 6)) {
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001237 printk(KERN_ERR "KNC1-%d: Could not read MAC from KNC1 card\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001238 budget_av->budget.dvb_adapter.num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 memset(mac, 0, 6);
1240 } else {
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001241 printk(KERN_INFO "KNC1-%d: MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001242 budget_av->budget.dvb_adapter.num,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
1244 }
1245
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001246 budget_av->budget.dvb_adapter.priv = budget_av;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 frontend_init(budget_av);
1248
Andrew de Quincey71a8dff2006-04-06 09:42:46 -03001249 if (!budget_av->has_saa7113) {
1250 ciintf_init(budget_av);
1251 }
1252
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 return 0;
1254}
1255
1256#define KNC1_INPUTS 2
1257static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
1258 {0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
1259 {1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
1260};
1261
1262static struct saa7146_extension_ioctls ioctls[] = {
1263 {VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE},
1264 {VIDIOC_G_INPUT, SAA7146_EXCLUSIVE},
1265 {VIDIOC_S_INPUT, SAA7146_EXCLUSIVE},
1266 {0, 0}
1267};
1268
1269static int av_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
1270{
1271 struct saa7146_dev *dev = fh->dev;
1272 struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;
1273
1274 switch (cmd) {
1275 case VIDIOC_ENUMINPUT:{
1276 struct v4l2_input *i = arg;
1277
1278 dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index);
1279 if (i->index < 0 || i->index >= KNC1_INPUTS) {
1280 return -EINVAL;
1281 }
1282 memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input));
1283 return 0;
1284 }
1285 case VIDIOC_G_INPUT:{
1286 int *input = (int *) arg;
1287
1288 *input = budget_av->cur_input;
1289
1290 dprintk(1, "VIDIOC_G_INPUT %d.\n", *input);
1291 return 0;
1292 }
1293 case VIDIOC_S_INPUT:{
1294 int input = *(int *) arg;
1295 dprintk(1, "VIDIOC_S_INPUT %d.\n", input);
1296 return saa7113_setinput(budget_av, input);
1297 }
1298 default:
1299 return -ENOIOCTLCMD;
1300 }
1301 return 0;
1302}
1303
1304static struct saa7146_standard standard[] = {
1305 {.name = "PAL",.id = V4L2_STD_PAL,
1306 .v_offset = 0x17,.v_field = 288,
1307 .h_offset = 0x14,.h_pixels = 680,
1308 .v_max_out = 576,.h_max_out = 768 },
1309
1310 {.name = "NTSC",.id = V4L2_STD_NTSC,
1311 .v_offset = 0x16,.v_field = 240,
1312 .h_offset = 0x06,.h_pixels = 708,
1313 .v_max_out = 480,.h_max_out = 640, },
1314};
1315
1316static struct saa7146_ext_vv vv_data = {
1317 .inputs = 2,
1318 .capabilities = 0, // perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113
1319 .flags = 0,
1320 .stds = &standard[0],
1321 .num_stds = sizeof(standard) / sizeof(struct saa7146_standard),
1322 .ioctls = &ioctls[0],
1323 .ioctl = av_ioctl,
1324};
1325
1326static struct saa7146_extension budget_extension;
1327
1328MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S);
1329MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C);
1330MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
Regis Prevotf8bf1342006-01-11 23:31:53 -02001331MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
Thilo Berger36f4f332006-02-27 00:09:08 -03001332MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
Johannes Stezenbach2d4f2c22005-05-16 21:54:23 -07001333MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
1334MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP);
1335MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);
Regis Prevotf8bf1342006-01-11 23:31:53 -02001337MAKE_BUDGET_INFO(cin1200sn, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C);
1339MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T);
1340
1341static struct pci_device_id pci_tbl[] = {
1342 MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56),
Johannes Stezenbach2d4f2c22005-05-16 21:54:23 -07001343 MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010),
Andrew de Quinceyeffa7912006-01-09 15:25:09 -02001344 MAKE_EXTENSION_PCI(knc1s, 0x1894, 0x0010),
Johannes Stezenbach2d4f2c22005-05-16 21:54:23 -07001345 MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011),
Regis Prevotf8bf1342006-01-11 23:31:53 -02001346 MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014),
1347 MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
Thilo Berger36f4f332006-02-27 00:09:08 -03001348 MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
Johannes Stezenbach2d4f2c22005-05-16 21:54:23 -07001350 MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),
Johannes Stezenbach2d4f2c22005-05-16 21:54:23 -07001352 MAKE_EXTENSION_PCI(knc1tp, 0x1894, 0x0031),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154),
Regis Prevotf8bf1342006-01-11 23:31:53 -02001354 MAKE_EXTENSION_PCI(cin1200sn, 0x153b, 0x1155),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156),
1356 MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157),
1357 {
1358 .vendor = 0,
1359 }
1360};
1361
1362MODULE_DEVICE_TABLE(pci, pci_tbl);
1363
1364static struct saa7146_extension budget_extension = {
Julian Scheel27b05fd2005-07-12 13:58:39 -07001365 .name = "budget_av",
Oliver Endriss69459f32005-12-01 00:51:48 -08001366 .flags = SAA7146_I2C_SHORT_DELAY,
1367
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 .pci_tbl = pci_tbl,
1369
1370 .module = THIS_MODULE,
1371 .attach = budget_av_attach,
1372 .detach = budget_av_detach,
1373
1374 .irq_mask = MASK_10,
1375 .irq_func = budget_av_irq,
1376};
1377
1378static int __init budget_av_init(void)
1379{
1380 return saa7146_register_extension(&budget_extension);
1381}
1382
1383static void __exit budget_av_exit(void)
1384{
1385 saa7146_unregister_extension(&budget_extension);
1386}
1387
1388module_init(budget_av_init);
1389module_exit(budget_av_exit);
1390
1391MODULE_LICENSE("GPL");
1392MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others");
1393MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
1394 "budget PCI DVB w/ analog input and CI-module (e.g. the KNC cards)");