blob: 8a7cd7d505cf533997dc76f2613f5e98a1d0c0d8 [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
475static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe,
Andreas Oberrittercfbfce12005-09-09 13:02:30 -0700476 struct i2c_adapter *i2c,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 struct dvb_frontend_parameters *params)
478{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 u32 div;
480 u8 buf[4];
481 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
Andreas Oberrittercfbfce12005-09-09 13:02:30 -0700504 if (i2c_transfer(i2c, &msg, 1) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 return -EIO;
506 return 0;
507}
508
Andrew de Quinceyeffa7912006-01-09 15:25:09 -0200509#define MIN2(a,b) ((a) < (b) ? (a) : (b))
510#define MIN3(a,b,c) MIN2(MIN2(a,b),c)
511
512static int philips_su1278sh2_tua6100_pll_set(struct dvb_frontend *fe,
513 struct i2c_adapter *i2c,
514 struct dvb_frontend_parameters *params)
515{
516 u8 reg0 [2] = { 0x00, 0x00 };
517 u8 reg1 [4] = { 0x01, 0x00, 0x00, 0x00 };
518 u8 reg2 [3] = { 0x02, 0x00, 0x00 };
519 int _fband;
520 int first_ZF;
521 int R, A, N, P, M;
522 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = NULL,.len = 0 };
523 int freq = params->frequency;
524
525 first_ZF = (freq) / 1000;
526
527 if (abs(MIN2(abs(first_ZF-1190),abs(first_ZF-1790))) <
528 abs(MIN3(abs(first_ZF-1202),abs(first_ZF-1542),abs(first_ZF-1890))))
529 _fband = 2;
530 else
531 _fband = 3;
532
533 if (_fband == 2) {
534 if (((first_ZF >= 950) && (first_ZF < 1350)) ||
535 ((first_ZF >= 1430) && (first_ZF < 1950)))
536 reg0[1] = 0x07;
537 else if (((first_ZF >= 1350) && (first_ZF < 1430)) ||
538 ((first_ZF >= 1950) && (first_ZF < 2150)))
539 reg0[1] = 0x0B;
540 }
541
542 if(_fband == 3) {
543 if (((first_ZF >= 950) && (first_ZF < 1350)) ||
544 ((first_ZF >= 1455) && (first_ZF < 1950)))
545 reg0[1] = 0x07;
546 else if (((first_ZF >= 1350) && (first_ZF < 1420)) ||
547 ((first_ZF >= 1950) && (first_ZF < 2150)))
548 reg0[1] = 0x0B;
549 else if ((first_ZF >= 1420) && (first_ZF < 1455))
550 reg0[1] = 0x0F;
551 }
552
553 if (first_ZF > 1525)
554 reg1[1] |= 0x80;
555 else
556 reg1[1] &= 0x7F;
557
558 if (_fband == 2) {
559 if (first_ZF > 1430) { /* 1430MHZ */
560 reg1[1] &= 0xCF; /* N2 */
561 reg2[1] &= 0xCF; /* R2 */
562 reg2[1] |= 0x10;
563 } else {
564 reg1[1] &= 0xCF; /* N2 */
565 reg1[1] |= 0x20;
566 reg2[1] &= 0xCF; /* R2 */
567 reg2[1] |= 0x10;
568 }
569 }
570
571 if (_fband == 3) {
572 if ((first_ZF >= 1455) &&
573 (first_ZF < 1630)) {
574 reg1[1] &= 0xCF; /* N2 */
575 reg1[1] |= 0x20;
576 reg2[1] &= 0xCF; /* R2 */
577 } else {
578 if (first_ZF < 1455) {
579 reg1[1] &= 0xCF; /* N2 */
580 reg1[1] |= 0x20;
581 reg2[1] &= 0xCF; /* R2 */
582 reg2[1] |= 0x10;
583 } else {
584 if (first_ZF >= 1630) {
585 reg1[1] &= 0xCF; /* N2 */
586 reg2[1] &= 0xCF; /* R2 */
587 reg2[1] |= 0x10;
588 }
589 }
590 }
591 }
592
593 /* set ports, enable P0 for symbol rates > 4Ms/s */
594 if (params->u.qpsk.symbol_rate >= 4000000)
595 reg1[1] |= 0x0c;
596 else
597 reg1[1] |= 0x04;
598
599 reg2[1] |= 0x0c;
600
601 R = 64;
602 A = 64;
603 P = 64; //32
604
605 M = (freq * R) / 4; /* in Mhz */
606 N = (M - A * 1000) / (P * 1000);
607
608 reg1[1] |= (N >> 9) & 0x03;
609 reg1[2] = (N >> 1) & 0xff;
610 reg1[3] = (N << 7) & 0x80;
611
612 reg2[1] |= (R >> 8) & 0x03;
613 reg2[2] = R & 0xFF; /* R */
614
615 reg1[3] |= A & 0x7f; /* A */
616
617 if (P == 64)
618 reg1[1] |= 0x40; /* Prescaler 64/65 */
619
620 reg0[1] |= 0x03;
621
622 /* already enabled - do not reenable i2c repeater or TX fails */
623 msg.buf = reg0;
624 msg.len = sizeof(reg0);
625 if (i2c_transfer(i2c, &msg, 1) != 1)
626 return -EIO;
627
628 stv0299_enable_plli2c(fe);
629 msg.buf = reg1;
630 msg.len = sizeof(reg1);
631 if (i2c_transfer(i2c, &msg, 1) != 1)
632 return -EIO;
633
634 stv0299_enable_plli2c(fe);
635 msg.buf = reg2;
636 msg.len = sizeof(reg2);
637 if (i2c_transfer(i2c, &msg, 1) != 1)
638 return -EIO;
639
640 return 0;
641}
642
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643static u8 typhoon_cinergy1200s_inittab[] = {
644 0x01, 0x15,
645 0x02, 0x30,
646 0x03, 0x00,
647 0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
648 0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
649 0x06, 0x40, /* DAC not used, set to high impendance mode */
650 0x07, 0x00, /* DAC LSB */
651 0x08, 0x40, /* DiSEqC off */
652 0x09, 0x00, /* FIFO */
653 0x0c, 0x51, /* OP1 ctl = Normal, OP1 val = 1 (LNB Power ON) */
654 0x0d, 0x82, /* DC offset compensation = ON, beta_agc1 = 2 */
655 0x0e, 0x23, /* alpha_tmg = 2, beta_tmg = 3 */
656 0x10, 0x3f, // AGC2 0x3d
657 0x11, 0x84,
Oliver Endrissff29d062005-11-08 21:35:43 -0800658 0x12, 0xb9,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 0x15, 0xc9, // lock detector threshold
660 0x16, 0x00,
661 0x17, 0x00,
662 0x18, 0x00,
663 0x19, 0x00,
664 0x1a, 0x00,
665 0x1f, 0x50,
666 0x20, 0x00,
667 0x21, 0x00,
668 0x22, 0x00,
669 0x23, 0x00,
670 0x28, 0x00, // out imp: normal out type: parallel FEC mode:0
671 0x29, 0x1e, // 1/2 threshold
672 0x2a, 0x14, // 2/3 threshold
673 0x2b, 0x0f, // 3/4 threshold
674 0x2c, 0x09, // 5/6 threshold
675 0x2d, 0x05, // 7/8 threshold
676 0x2e, 0x01,
677 0x31, 0x1f, // test all FECs
678 0x32, 0x19, // viterbi and synchro search
679 0x33, 0xfc, // rs control
680 0x34, 0x93, // error control
681 0x0f, 0x92,
682 0xff, 0xff
683};
684
685static struct stv0299_config typhoon_config = {
686 .demod_address = 0x68,
687 .inittab = typhoon_cinergy1200s_inittab,
688 .mclk = 88000000UL,
689 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 .skip_reinit = 0,
691 .lock_output = STV0229_LOCKOUTPUT_1,
692 .volt13_op0_op1 = STV0299_VOLT13_OP0,
693 .min_delay_ms = 100,
694 .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
695 .pll_set = philips_su1278_ty_ci_pll_set,
696};
697
698
699static struct stv0299_config cinergy_1200s_config = {
700 .demod_address = 0x68,
701 .inittab = typhoon_cinergy1200s_inittab,
702 .mclk = 88000000UL,
703 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 .skip_reinit = 0,
705 .lock_output = STV0229_LOCKOUTPUT_0,
706 .volt13_op0_op1 = STV0299_VOLT13_OP0,
707 .min_delay_ms = 100,
708 .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
709 .pll_set = philips_su1278_ty_ci_pll_set,
710};
711
Andrew de Quinceyeffa7912006-01-09 15:25:09 -0200712static struct stv0299_config cinergy_1200s_1894_0010_config = {
713 .demod_address = 0x68,
714 .inittab = typhoon_cinergy1200s_inittab,
715 .mclk = 88000000UL,
716 .invert = 1,
717 .skip_reinit = 0,
718 .lock_output = STV0229_LOCKOUTPUT_1,
719 .volt13_op0_op1 = STV0299_VOLT13_OP0,
720 .min_delay_ms = 100,
721 .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
722 .pll_set = philips_su1278sh2_tua6100_pll_set,
723};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
725static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
726{
727 struct budget *budget = (struct budget *) fe->dvb->priv;
728 u8 buf[4];
729 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
730
731#define TUNER_MUL 62500
732
733 u32 div = (params->frequency + 36125000 + TUNER_MUL / 2) / TUNER_MUL;
734
735 buf[0] = (div >> 8) & 0x7f;
736 buf[1] = div & 0xff;
Johannes Stezenbacheef57642005-07-07 17:57:58 -0700737 buf[2] = 0x86;
738 buf[3] = (params->frequency < 150000000 ? 0x01 :
739 params->frequency < 445000000 ? 0x02 : 0x04);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740
741 if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
742 return -EIO;
743 return 0;
744}
745
746static struct tda10021_config philips_cu1216_config = {
747 .demod_address = 0x0c,
748 .pll_set = philips_cu1216_pll_set,
749};
750
751
752
753
754static int philips_tu1216_pll_init(struct dvb_frontend *fe)
755{
756 struct budget *budget = (struct budget *) fe->dvb->priv;
757 static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
758 struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
759
760 // setup PLL configuration
761 if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
762 return -EIO;
763 msleep(1);
764
765 return 0;
766}
767
768static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
769{
770 struct budget *budget = (struct budget *) fe->dvb->priv;
771 u8 tuner_buf[4];
772 struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len =
773 sizeof(tuner_buf) };
774 int tuner_frequency = 0;
775 u8 band, cp, filter;
776
777 // determine charge pump
778 tuner_frequency = params->frequency + 36166000;
779 if (tuner_frequency < 87000000)
780 return -EINVAL;
781 else if (tuner_frequency < 130000000)
782 cp = 3;
783 else if (tuner_frequency < 160000000)
784 cp = 5;
785 else if (tuner_frequency < 200000000)
786 cp = 6;
787 else if (tuner_frequency < 290000000)
788 cp = 3;
789 else if (tuner_frequency < 420000000)
790 cp = 5;
791 else if (tuner_frequency < 480000000)
792 cp = 6;
793 else if (tuner_frequency < 620000000)
794 cp = 3;
795 else if (tuner_frequency < 830000000)
796 cp = 5;
797 else if (tuner_frequency < 895000000)
798 cp = 7;
799 else
800 return -EINVAL;
801
802 // determine band
803 if (params->frequency < 49000000)
804 return -EINVAL;
805 else if (params->frequency < 161000000)
806 band = 1;
807 else if (params->frequency < 444000000)
808 band = 2;
809 else if (params->frequency < 861000000)
810 band = 4;
811 else
812 return -EINVAL;
813
814 // setup PLL filter
815 switch (params->u.ofdm.bandwidth) {
816 case BANDWIDTH_6_MHZ:
817 filter = 0;
818 break;
819
820 case BANDWIDTH_7_MHZ:
821 filter = 0;
822 break;
823
824 case BANDWIDTH_8_MHZ:
825 filter = 1;
826 break;
827
828 default:
829 return -EINVAL;
830 }
831
832 // calculate divisor
833 // ((36166000+((1000000/6)/2)) + Finput)/(1000000/6)
834 tuner_frequency = (((params->frequency / 1000) * 6) + 217496) / 1000;
835
836 // setup tuner buffer
837 tuner_buf[0] = (tuner_frequency >> 8) & 0x7f;
838 tuner_buf[1] = tuner_frequency & 0xff;
839 tuner_buf[2] = 0xca;
840 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
841
842 if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
843 return -EIO;
844
845 msleep(1);
846 return 0;
847}
848
849static int philips_tu1216_request_firmware(struct dvb_frontend *fe,
850 const struct firmware **fw, char *name)
851{
852 struct budget *budget = (struct budget *) fe->dvb->priv;
853
854 return request_firmware(fw, name, &budget->dev->pci->dev);
855}
856
857static struct tda1004x_config philips_tu1216_config = {
858
859 .demod_address = 0x8,
860 .invert = 1,
861 .invert_oclk = 1,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700862 .xtal_freq = TDA10046_XTAL_4M,
863 .agc_config = TDA10046_AGC_DEFAULT,
864 .if_freq = TDA10046_FREQ_3617,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 .pll_init = philips_tu1216_pll_init,
866 .pll_set = philips_tu1216_pll_set,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700867 .pll_sleep = NULL,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 .request_firmware = philips_tu1216_request_firmware,
869};
870
Regis Prevotf8bf1342006-01-11 23:31:53 -0200871static u8 philips_sd1878_inittab[] = {
872 0x01, 0x15,
873 0x02, 0x30,
874 0x03, 0x00,
875 0x04, 0x7d,
876 0x05, 0x35,
877 0x06, 0x40,
878 0x07, 0x00,
879 0x08, 0x43,
880 0x09, 0x02,
881 0x0C, 0x51,
882 0x0D, 0x82,
883 0x0E, 0x23,
884 0x10, 0x3f,
885 0x11, 0x84,
886 0x12, 0xb9,
887 0x15, 0xc9,
888 0x16, 0x19,
889 0x17, 0x8c,
890 0x18, 0x59,
891 0x19, 0xf8,
892 0x1a, 0xfe,
893 0x1c, 0x7f,
894 0x1d, 0x00,
895 0x1e, 0x00,
896 0x1f, 0x50,
897 0x20, 0x00,
898 0x21, 0x00,
899 0x22, 0x00,
900 0x23, 0x00,
901 0x28, 0x00,
902 0x29, 0x28,
903 0x2a, 0x14,
904 0x2b, 0x0f,
905 0x2c, 0x09,
906 0x2d, 0x09,
907 0x31, 0x1f,
908 0x32, 0x19,
909 0x33, 0xfc,
910 0x34, 0x93,
911 0xff, 0xff
912};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
Regis Prevotf8bf1342006-01-11 23:31:53 -0200914static int philips_sd1878_tda8261_pll_set(struct dvb_frontend *fe,
915 struct i2c_adapter *i2c,
916 struct dvb_frontend_parameters *params)
917{
918 u8 buf[4];
919 int rc;
920 struct i2c_msg tuner_msg = {.addr=0x60,.flags=0,.buf=buf,.len=sizeof(buf)};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921
Regis Prevotf8bf1342006-01-11 23:31:53 -0200922 if((params->frequency < 950000) || (params->frequency > 2150000))
923 return -EINVAL;
924
925 rc=dvb_pll_configure(&dvb_pll_philips_sd1878_tda8261, buf,
926 params->frequency, 0);
927 if(rc < 0) return rc;
928
929 if(i2c_transfer(i2c, &tuner_msg, 1) != 1)
930 return -EIO;
931
932 return 0;
933}
934
935static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe,
936 u32 srate, u32 ratio)
937{
938 u8 aclk = 0;
939 u8 bclk = 0;
940 u8 m1;
941
942 aclk = 0xb5;
943 if (srate < 2000000)
944 bclk = 0x86;
945 else if (srate < 5000000)
946 bclk = 0x89;
947 else if (srate < 15000000)
948 bclk = 0x8f;
949 else if (srate < 45000000)
950 bclk = 0x95;
951
952 m1 = 0x14;
953 if (srate < 4000000)
954 m1 = 0x10;
955
956 stv0299_writereg(fe, 0x0e, 0x23);
957 stv0299_writereg(fe, 0x0f, 0x94);
958 stv0299_writereg(fe, 0x10, 0x39);
959 stv0299_writereg(fe, 0x13, aclk);
960 stv0299_writereg(fe, 0x14, bclk);
961 stv0299_writereg(fe, 0x15, 0xc9);
962 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
963 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
964 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
965 stv0299_writereg(fe, 0x0f, 0x80 | m1);
966
967 return 0;
968}
969
970static struct stv0299_config philips_sd1878_config = {
971 .demod_address = 0x68,
972 .inittab = philips_sd1878_inittab,
973 .mclk = 88000000UL,
974 .invert = 0,
975 .skip_reinit = 0,
976 .lock_output = STV0229_LOCKOUTPUT_1,
977 .volt13_op0_op1 = STV0299_VOLT13_OP0,
978 .min_delay_ms = 100,
979 .set_symbol_rate = philips_sd1878_ci_set_symbol_rate,
980 .pll_set = philips_sd1878_tda8261_pll_set,
981};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
983static u8 read_pwm(struct budget_av *budget_av)
984{
985 u8 b = 0xff;
986 u8 pwm;
987 struct i2c_msg msg[] = { {.addr = 0x50,.flags = 0,.buf = &b,.len = 1},
988 {.addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1}
989 };
990
991 if ((i2c_transfer(&budget_av->budget.i2c_adap, msg, 2) != 2)
992 || (pwm == 0xff))
993 pwm = 0x48;
994
995 return pwm;
996}
997
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -0700998#define SUBID_DVBS_KNC1 0x0010
999#define SUBID_DVBS_KNC1_PLUS 0x0011
1000#define SUBID_DVBS_TYPHOON 0x4f56
1001#define SUBID_DVBS_CINERGY1200 0x1154
Regis Prevotf8bf1342006-01-11 23:31:53 -02001002#define SUBID_DVBS_CYNERGY1200N 0x1155
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001003
Regis Prevotf8bf1342006-01-11 23:31:53 -02001004#define SUBID_DVBS_TV_STAR 0x0014
1005#define SUBID_DVBS_TV_STAR_CI 0x0016
Thilo Berger36f4f332006-02-27 00:09:08 -03001006#define SUBID_DVBS_EASYWATCH 0x001e
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001007#define SUBID_DVBC_KNC1 0x0020
1008#define SUBID_DVBC_KNC1_PLUS 0x0021
1009#define SUBID_DVBC_CINERGY1200 0x1156
1010
1011#define SUBID_DVBT_KNC1_PLUS 0x0031
1012#define SUBID_DVBT_KNC1 0x0030
1013#define SUBID_DVBT_CINERGY1200 0x1157
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014
1015static void frontend_init(struct budget_av *budget_av)
1016{
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001017 struct saa7146_dev * saa = budget_av->budget.dev;
1018 struct dvb_frontend * fe = NULL;
1019
1020 switch (saa->pci->subsystem_device) {
1021 case SUBID_DVBS_KNC1_PLUS:
1022 case SUBID_DVBC_KNC1_PLUS:
1023 case SUBID_DVBT_KNC1_PLUS:
1024 // Enable / PowerON Frontend
Andrew de Quincey87b2eca2005-09-09 13:03:09 -07001025 saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001026 saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 break;
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001028 }
1029
1030 switch (saa->pci->subsystem_device) {
1031
1032 case SUBID_DVBS_KNC1:
Andrew de Quinceyeffa7912006-01-09 15:25:09 -02001033 if (saa->pci->subsystem_vendor == 0x1894) {
1034 fe = stv0299_attach(&cinergy_1200s_1894_0010_config,
1035 &budget_av->budget.i2c_adap);
1036 } else {
1037 fe = stv0299_attach(&typhoon_config,
1038 &budget_av->budget.i2c_adap);
1039 }
1040 break;
1041
Regis Prevotf8bf1342006-01-11 23:31:53 -02001042 case SUBID_DVBS_TV_STAR:
1043 case SUBID_DVBS_TV_STAR_CI:
1044 case SUBID_DVBS_CYNERGY1200N:
Thilo Berger36f4f332006-02-27 00:09:08 -03001045 case SUBID_DVBS_EASYWATCH:
Regis Prevotf8bf1342006-01-11 23:31:53 -02001046 fe = stv0299_attach(&philips_sd1878_config,
1047 &budget_av->budget.i2c_adap);
1048 break;
1049
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001050 case SUBID_DVBS_KNC1_PLUS:
1051 case SUBID_DVBS_TYPHOON:
1052 fe = stv0299_attach(&typhoon_config,
1053 &budget_av->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 break;
1055
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001056 case SUBID_DVBS_CINERGY1200:
1057 fe = stv0299_attach(&cinergy_1200s_config,
1058 &budget_av->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 break;
1060
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001061 case SUBID_DVBC_KNC1:
1062 case SUBID_DVBC_KNC1_PLUS:
1063 fe = tda10021_attach(&philips_cu1216_config,
1064 &budget_av->budget.i2c_adap,
1065 read_pwm(budget_av));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 break;
1067
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001068 case SUBID_DVBT_KNC1:
1069 case SUBID_DVBT_KNC1_PLUS:
1070 fe = tda10046_attach(&philips_tu1216_config,
1071 &budget_av->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 break;
1073
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001074 case SUBID_DVBC_CINERGY1200:
1075 fe = tda10021_attach(&philips_cu1216_config,
1076 &budget_av->budget.i2c_adap,
1077 read_pwm(budget_av));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 break;
1079
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001080 case SUBID_DVBT_CINERGY1200:
1081 fe = tda10046_attach(&philips_tu1216_config,
1082 &budget_av->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 break;
1084 }
1085
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001086 if (fe == NULL) {
1087 printk(KERN_ERR "budget-av: A frontend driver was not found "
1088 "for device %04x/%04x subsystem %04x/%04x\n",
1089 saa->pci->vendor,
1090 saa->pci->device,
1091 saa->pci->subsystem_vendor,
1092 saa->pci->subsystem_device);
1093 return;
1094 }
1095
1096 budget_av->budget.dvb_frontend = fe;
1097
1098 if (dvb_register_frontend(&budget_av->budget.dvb_adapter,
1099 budget_av->budget.dvb_frontend)) {
1100 printk(KERN_ERR "budget-av: Frontend registration failed!\n");
1101 if (budget_av->budget.dvb_frontend->ops->release)
1102 budget_av->budget.dvb_frontend->ops->release(budget_av->budget.dvb_frontend);
1103 budget_av->budget.dvb_frontend = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 }
1105}
1106
1107
1108static void budget_av_irq(struct saa7146_dev *dev, u32 * isr)
1109{
1110 struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;
1111
1112 dprintk(8, "dev: %p, budget_av: %p\n", dev, budget_av);
1113
1114 if (*isr & MASK_10)
1115 ttpci_budget_irq10_handler(dev, isr);
1116}
1117
1118static int budget_av_detach(struct saa7146_dev *dev)
1119{
1120 struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;
1121 int err;
1122
1123 dprintk(2, "dev: %p\n", dev);
1124
1125 if (1 == budget_av->has_saa7113) {
1126 saa7146_setgpio(dev, 0, SAA7146_GPIO_OUTLO);
1127
1128 msleep(200);
1129
1130 saa7146_unregister_device(&budget_av->vd, dev);
1131 }
1132
1133 if (budget_av->budget.ci_present)
1134 ciintf_deinit(budget_av);
1135
1136 if (budget_av->budget.dvb_frontend != NULL)
1137 dvb_unregister_frontend(budget_av->budget.dvb_frontend);
1138 err = ttpci_budget_deinit(&budget_av->budget);
1139
1140 kfree(budget_av);
1141
1142 return err;
1143}
1144
1145static struct saa7146_ext_vv vv_data;
1146
1147static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1148{
1149 struct budget_av *budget_av;
1150 u8 *mac;
1151 int err;
1152
1153 dprintk(2, "dev: %p\n", dev);
1154
Panagiotis Issaris74081872006-01-11 19:40:56 -02001155 if (!(budget_av = kzalloc(sizeof(struct budget_av), GFP_KERNEL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 return -ENOMEM;
1157
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001158 budget_av->has_saa7113 = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 budget_av->budget.ci_present = 0;
1160
1161 dev->ext_priv = budget_av;
1162
1163 if ((err = ttpci_budget_init(&budget_av->budget, dev, info, THIS_MODULE))) {
1164 kfree(budget_av);
1165 return err;
1166 }
1167
1168 /* knc1 initialization */
1169 saa7146_write(dev, DD1_STREAM_B, 0x04000000);
1170 saa7146_write(dev, DD1_INIT, 0x07000600);
1171 saa7146_write(dev, MC2, MASK_09 | MASK_25 | MASK_10 | MASK_26);
1172
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001173 if (saa7113_init(budget_av) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 budget_av->has_saa7113 = 1;
1175
1176 if (0 != saa7146_vv_init(dev, &vv_data)) {
1177 /* fixme: proper cleanup here */
1178 ERR(("cannot init vv subsystem.\n"));
1179 return err;
1180 }
1181
1182 if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) {
1183 /* fixme: proper cleanup here */
1184 ERR(("cannot register capture v4l2 device.\n"));
1185 return err;
1186 }
1187
1188 /* beware: this modifies dev->vv ... */
1189 saa7146_set_hps_source_and_sync(dev, SAA7146_HPS_SOURCE_PORT_A,
1190 SAA7146_HPS_SYNC_PORT_A);
1191
1192 saa7113_setinput(budget_av, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 }
1194
1195 /* fixme: find some sane values here... */
1196 saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
1197
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001198 mac = budget_av->budget.dvb_adapter.proposed_mac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 if (i2c_readregs(&budget_av->budget.i2c_adap, 0xa0, 0x30, mac, 6)) {
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001200 printk(KERN_ERR "KNC1-%d: Could not read MAC from KNC1 card\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001201 budget_av->budget.dvb_adapter.num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 memset(mac, 0, 6);
1203 } else {
Johannes Stezenbachb82a96a2005-05-16 21:54:49 -07001204 printk(KERN_INFO "KNC1-%d: MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001205 budget_av->budget.dvb_adapter.num,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
1207 }
1208
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001209 budget_av->budget.dvb_adapter.priv = budget_av;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 frontend_init(budget_av);
1211
Andrew de Quincey71a8dff2006-04-06 09:42:46 -03001212 if (!budget_av->has_saa7113) {
1213 ciintf_init(budget_av);
1214 }
1215
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 return 0;
1217}
1218
1219#define KNC1_INPUTS 2
1220static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
1221 {0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
1222 {1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
1223};
1224
1225static struct saa7146_extension_ioctls ioctls[] = {
1226 {VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE},
1227 {VIDIOC_G_INPUT, SAA7146_EXCLUSIVE},
1228 {VIDIOC_S_INPUT, SAA7146_EXCLUSIVE},
1229 {0, 0}
1230};
1231
1232static int av_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
1233{
1234 struct saa7146_dev *dev = fh->dev;
1235 struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;
1236
1237 switch (cmd) {
1238 case VIDIOC_ENUMINPUT:{
1239 struct v4l2_input *i = arg;
1240
1241 dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index);
1242 if (i->index < 0 || i->index >= KNC1_INPUTS) {
1243 return -EINVAL;
1244 }
1245 memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input));
1246 return 0;
1247 }
1248 case VIDIOC_G_INPUT:{
1249 int *input = (int *) arg;
1250
1251 *input = budget_av->cur_input;
1252
1253 dprintk(1, "VIDIOC_G_INPUT %d.\n", *input);
1254 return 0;
1255 }
1256 case VIDIOC_S_INPUT:{
1257 int input = *(int *) arg;
1258 dprintk(1, "VIDIOC_S_INPUT %d.\n", input);
1259 return saa7113_setinput(budget_av, input);
1260 }
1261 default:
1262 return -ENOIOCTLCMD;
1263 }
1264 return 0;
1265}
1266
1267static struct saa7146_standard standard[] = {
1268 {.name = "PAL",.id = V4L2_STD_PAL,
1269 .v_offset = 0x17,.v_field = 288,
1270 .h_offset = 0x14,.h_pixels = 680,
1271 .v_max_out = 576,.h_max_out = 768 },
1272
1273 {.name = "NTSC",.id = V4L2_STD_NTSC,
1274 .v_offset = 0x16,.v_field = 240,
1275 .h_offset = 0x06,.h_pixels = 708,
1276 .v_max_out = 480,.h_max_out = 640, },
1277};
1278
1279static struct saa7146_ext_vv vv_data = {
1280 .inputs = 2,
1281 .capabilities = 0, // perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113
1282 .flags = 0,
1283 .stds = &standard[0],
1284 .num_stds = sizeof(standard) / sizeof(struct saa7146_standard),
1285 .ioctls = &ioctls[0],
1286 .ioctl = av_ioctl,
1287};
1288
1289static struct saa7146_extension budget_extension;
1290
1291MAKE_BUDGET_INFO(knc1s, "KNC1 DVB-S", BUDGET_KNC1S);
1292MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C);
1293MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
Regis Prevotf8bf1342006-01-11 23:31:53 -02001294MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
Thilo Berger36f4f332006-02-27 00:09:08 -03001295MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
Johannes Stezenbach2d4f2c22005-05-16 21:54:23 -07001296MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
1297MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP);
1298MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299MAKE_BUDGET_INFO(cin1200s, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);
Regis Prevotf8bf1342006-01-11 23:31:53 -02001300MAKE_BUDGET_INFO(cin1200sn, "TerraTec Cinergy 1200 DVB-S", BUDGET_CIN1200S);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301MAKE_BUDGET_INFO(cin1200c, "Terratec Cinergy 1200 DVB-C", BUDGET_CIN1200C);
1302MAKE_BUDGET_INFO(cin1200t, "Terratec Cinergy 1200 DVB-T", BUDGET_CIN1200T);
1303
1304static struct pci_device_id pci_tbl[] = {
1305 MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x4f56),
Johannes Stezenbach2d4f2c22005-05-16 21:54:23 -07001306 MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010),
Andrew de Quinceyeffa7912006-01-09 15:25:09 -02001307 MAKE_EXTENSION_PCI(knc1s, 0x1894, 0x0010),
Johannes Stezenbach2d4f2c22005-05-16 21:54:23 -07001308 MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011),
Regis Prevotf8bf1342006-01-11 23:31:53 -02001309 MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014),
1310 MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
Thilo Berger36f4f332006-02-27 00:09:08 -03001311 MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
Johannes Stezenbach2d4f2c22005-05-16 21:54:23 -07001313 MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),
Johannes Stezenbach2d4f2c22005-05-16 21:54:23 -07001315 MAKE_EXTENSION_PCI(knc1tp, 0x1894, 0x0031),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 MAKE_EXTENSION_PCI(cin1200s, 0x153b, 0x1154),
Regis Prevotf8bf1342006-01-11 23:31:53 -02001317 MAKE_EXTENSION_PCI(cin1200sn, 0x153b, 0x1155),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 MAKE_EXTENSION_PCI(cin1200c, 0x153b, 0x1156),
1319 MAKE_EXTENSION_PCI(cin1200t, 0x153b, 0x1157),
1320 {
1321 .vendor = 0,
1322 }
1323};
1324
1325MODULE_DEVICE_TABLE(pci, pci_tbl);
1326
1327static struct saa7146_extension budget_extension = {
Julian Scheel27b05fd2005-07-12 13:58:39 -07001328 .name = "budget_av",
Oliver Endriss69459f3d2005-12-01 00:51:48 -08001329 .flags = SAA7146_I2C_SHORT_DELAY,
1330
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 .pci_tbl = pci_tbl,
1332
1333 .module = THIS_MODULE,
1334 .attach = budget_av_attach,
1335 .detach = budget_av_detach,
1336
1337 .irq_mask = MASK_10,
1338 .irq_func = budget_av_irq,
1339};
1340
1341static int __init budget_av_init(void)
1342{
1343 return saa7146_register_extension(&budget_extension);
1344}
1345
1346static void __exit budget_av_exit(void)
1347{
1348 saa7146_unregister_extension(&budget_extension);
1349}
1350
1351module_init(budget_av_init);
1352module_exit(budget_av_exit);
1353
1354MODULE_LICENSE("GPL");
1355MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others");
1356MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
1357 "budget PCI DVB w/ analog input and CI-module (e.g. the KNC cards)");