diff options
Diffstat (limited to 'drivers/media/pci/ttpci/budget.c')
-rw-r--r-- | drivers/media/pci/ttpci/budget.c | 871 |
1 files changed, 871 insertions, 0 deletions
diff --git a/drivers/media/pci/ttpci/budget.c b/drivers/media/pci/ttpci/budget.c new file mode 100644 index 000000000000..7e6e43ae5c51 --- /dev/null +++ b/drivers/media/pci/ttpci/budget.c | |||
@@ -0,0 +1,871 @@ | |||
1 | /* | ||
2 | * budget.c: driver for the SAA7146 based Budget DVB cards | ||
3 | * | ||
4 | * Compiled from various sources by Michael Hunold <michael@mihu.de> | ||
5 | * | ||
6 | * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de> | ||
7 | * | ||
8 | * Copyright (C) 1999-2002 Ralph Metzler | ||
9 | * & Marcus Metzler for convergence integrated media GmbH | ||
10 | * | ||
11 | * 26feb2004 Support for FS Activy Card (Grundig tuner) by | ||
12 | * Michael Dreher <michael@5dot1.de>, | ||
13 | * Oliver Endriss <o.endriss@gmx.de> and | ||
14 | * Andreas 'randy' Weinberger | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or | ||
17 | * modify it under the terms of the GNU General Public License | ||
18 | * as published by the Free Software Foundation; either version 2 | ||
19 | * of the License, or (at your option) any later version. | ||
20 | * | ||
21 | * | ||
22 | * This program is distributed in the hope that it will be useful, | ||
23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
25 | * GNU General Public License for more details. | ||
26 | * | ||
27 | * | ||
28 | * You should have received a copy of the GNU General Public License | ||
29 | * along with this program; if not, write to the Free Software | ||
30 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
31 | * Or, point your browser to http://www.gnu.org/copyleft/gpl.html | ||
32 | * | ||
33 | * | ||
34 | * the project's page is at http://www.linuxtv.org/ | ||
35 | */ | ||
36 | |||
37 | #include "budget.h" | ||
38 | #include "stv0299.h" | ||
39 | #include "ves1x93.h" | ||
40 | #include "ves1820.h" | ||
41 | #include "l64781.h" | ||
42 | #include "tda8083.h" | ||
43 | #include "s5h1420.h" | ||
44 | #include "tda10086.h" | ||
45 | #include "tda826x.h" | ||
46 | #include "lnbp21.h" | ||
47 | #include "bsru6.h" | ||
48 | #include "bsbe1.h" | ||
49 | #include "tdhd1.h" | ||
50 | #include "stv6110x.h" | ||
51 | #include "stv090x.h" | ||
52 | #include "isl6423.h" | ||
53 | #include "lnbh24.h" | ||
54 | |||
55 | |||
56 | static int diseqc_method; | ||
57 | module_param(diseqc_method, int, 0444); | ||
58 | MODULE_PARM_DESC(diseqc_method, "Select DiSEqC method for subsystem id 13c2:1003, 0: default, 1: more reliable (for newer revisions only)"); | ||
59 | |||
60 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
61 | |||
62 | static void Set22K (struct budget *budget, int state) | ||
63 | { | ||
64 | struct saa7146_dev *dev=budget->dev; | ||
65 | dprintk(2, "budget: %p\n", budget); | ||
66 | saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO)); | ||
67 | } | ||
68 | |||
69 | /* Diseqc functions only for TT Budget card */ | ||
70 | /* taken from the Skyvision DVB driver by | ||
71 | Ralph Metzler <rjkm@metzlerbros.de> */ | ||
72 | |||
73 | static void DiseqcSendBit (struct budget *budget, int data) | ||
74 | { | ||
75 | struct saa7146_dev *dev=budget->dev; | ||
76 | dprintk(2, "budget: %p\n", budget); | ||
77 | |||
78 | saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); | ||
79 | udelay(data ? 500 : 1000); | ||
80 | saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); | ||
81 | udelay(data ? 1000 : 500); | ||
82 | } | ||
83 | |||
84 | static void DiseqcSendByte (struct budget *budget, int data) | ||
85 | { | ||
86 | int i, par=1, d; | ||
87 | |||
88 | dprintk(2, "budget: %p\n", budget); | ||
89 | |||
90 | for (i=7; i>=0; i--) { | ||
91 | d = (data>>i)&1; | ||
92 | par ^= d; | ||
93 | DiseqcSendBit(budget, d); | ||
94 | } | ||
95 | |||
96 | DiseqcSendBit(budget, par); | ||
97 | } | ||
98 | |||
99 | static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst) | ||
100 | { | ||
101 | struct saa7146_dev *dev=budget->dev; | ||
102 | int i; | ||
103 | |||
104 | dprintk(2, "budget: %p\n", budget); | ||
105 | |||
106 | saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); | ||
107 | mdelay(16); | ||
108 | |||
109 | for (i=0; i<len; i++) | ||
110 | DiseqcSendByte(budget, msg[i]); | ||
111 | |||
112 | mdelay(16); | ||
113 | |||
114 | if (burst!=-1) { | ||
115 | if (burst) | ||
116 | DiseqcSendByte(budget, 0xff); | ||
117 | else { | ||
118 | saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); | ||
119 | mdelay(12); | ||
120 | udelay(500); | ||
121 | saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); | ||
122 | } | ||
123 | msleep(20); | ||
124 | } | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | /* | ||
130 | * Routines for the Fujitsu Siemens Activy budget card | ||
131 | * 22 kHz tone and DiSEqC are handled by the frontend. | ||
132 | * Voltage must be set here. | ||
133 | * GPIO 1: LNBP EN, GPIO 2: LNBP VSEL | ||
134 | */ | ||
135 | static int SetVoltage_Activy (struct budget *budget, fe_sec_voltage_t voltage) | ||
136 | { | ||
137 | struct saa7146_dev *dev=budget->dev; | ||
138 | |||
139 | dprintk(2, "budget: %p\n", budget); | ||
140 | |||
141 | switch (voltage) { | ||
142 | case SEC_VOLTAGE_13: | ||
143 | saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); | ||
144 | saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO); | ||
145 | break; | ||
146 | case SEC_VOLTAGE_18: | ||
147 | saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); | ||
148 | saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI); | ||
149 | break; | ||
150 | case SEC_VOLTAGE_OFF: | ||
151 | saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); | ||
152 | break; | ||
153 | default: | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static int siemens_budget_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) | ||
161 | { | ||
162 | struct budget* budget = (struct budget*) fe->dvb->priv; | ||
163 | |||
164 | return SetVoltage_Activy (budget, voltage); | ||
165 | } | ||
166 | |||
167 | static int budget_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) | ||
168 | { | ||
169 | struct budget* budget = (struct budget*) fe->dvb->priv; | ||
170 | |||
171 | switch (tone) { | ||
172 | case SEC_TONE_ON: | ||
173 | Set22K (budget, 1); | ||
174 | break; | ||
175 | |||
176 | case SEC_TONE_OFF: | ||
177 | Set22K (budget, 0); | ||
178 | break; | ||
179 | |||
180 | default: | ||
181 | return -EINVAL; | ||
182 | } | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) | ||
188 | { | ||
189 | struct budget* budget = (struct budget*) fe->dvb->priv; | ||
190 | |||
191 | SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0); | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd) | ||
197 | { | ||
198 | struct budget* budget = (struct budget*) fe->dvb->priv; | ||
199 | |||
200 | SendDiSEqCMsg (budget, 0, NULL, minicmd); | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe) | ||
206 | { | ||
207 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
208 | struct budget* budget = (struct budget*) fe->dvb->priv; | ||
209 | u8 pwr = 0; | ||
210 | u8 buf[4]; | ||
211 | struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; | ||
212 | u32 div = (c->frequency + 479500) / 125; | ||
213 | |||
214 | if (c->frequency > 2000000) | ||
215 | pwr = 3; | ||
216 | else if (c->frequency > 1800000) | ||
217 | pwr = 2; | ||
218 | else if (c->frequency > 1600000) | ||
219 | pwr = 1; | ||
220 | else if (c->frequency > 1200000) | ||
221 | pwr = 0; | ||
222 | else if (c->frequency >= 1100000) | ||
223 | pwr = 1; | ||
224 | else pwr = 2; | ||
225 | |||
226 | buf[0] = (div >> 8) & 0x7f; | ||
227 | buf[1] = div & 0xff; | ||
228 | buf[2] = ((div & 0x18000) >> 10) | 0x95; | ||
229 | buf[3] = (pwr << 6) | 0x30; | ||
230 | |||
231 | // NOTE: since we're using a prescaler of 2, we set the | ||
232 | // divisor frequency to 62.5kHz and divide by 125 above | ||
233 | |||
234 | if (fe->ops.i2c_gate_ctrl) | ||
235 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
236 | if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static struct ves1x93_config alps_bsrv2_config = | ||
241 | { | ||
242 | .demod_address = 0x08, | ||
243 | .xin = 90100000UL, | ||
244 | .invert_pwm = 0, | ||
245 | }; | ||
246 | |||
247 | static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe) | ||
248 | { | ||
249 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
250 | struct budget* budget = (struct budget*) fe->dvb->priv; | ||
251 | u32 div; | ||
252 | u8 data[4]; | ||
253 | struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) }; | ||
254 | |||
255 | div = (c->frequency + 35937500 + 31250) / 62500; | ||
256 | |||
257 | data[0] = (div >> 8) & 0x7f; | ||
258 | data[1] = div & 0xff; | ||
259 | data[2] = 0x85 | ((div >> 10) & 0x60); | ||
260 | data[3] = (c->frequency < 174000000 ? 0x88 : c->frequency < 470000000 ? 0x84 : 0x81); | ||
261 | |||
262 | if (fe->ops.i2c_gate_ctrl) | ||
263 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
264 | if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; | ||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | static struct ves1820_config alps_tdbe2_config = { | ||
269 | .demod_address = 0x09, | ||
270 | .xin = 57840000UL, | ||
271 | .invert = 1, | ||
272 | .selagc = VES1820_SELAGC_SIGNAMPERR, | ||
273 | }; | ||
274 | |||
275 | static int grundig_29504_401_tuner_set_params(struct dvb_frontend *fe) | ||
276 | { | ||
277 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
278 | struct budget *budget = fe->dvb->priv; | ||
279 | u8 *tuner_addr = fe->tuner_priv; | ||
280 | u32 div; | ||
281 | u8 cfg, cpump, band_select; | ||
282 | u8 data[4]; | ||
283 | struct i2c_msg msg = { .flags = 0, .buf = data, .len = sizeof(data) }; | ||
284 | |||
285 | if (tuner_addr) | ||
286 | msg.addr = *tuner_addr; | ||
287 | else | ||
288 | msg.addr = 0x61; | ||
289 | |||
290 | div = (36125000 + c->frequency) / 166666; | ||
291 | |||
292 | cfg = 0x88; | ||
293 | |||
294 | if (c->frequency < 175000000) | ||
295 | cpump = 2; | ||
296 | else if (c->frequency < 390000000) | ||
297 | cpump = 1; | ||
298 | else if (c->frequency < 470000000) | ||
299 | cpump = 2; | ||
300 | else if (c->frequency < 750000000) | ||
301 | cpump = 1; | ||
302 | else | ||
303 | cpump = 3; | ||
304 | |||
305 | if (c->frequency < 175000000) | ||
306 | band_select = 0x0e; | ||
307 | else if (c->frequency < 470000000) | ||
308 | band_select = 0x05; | ||
309 | else | ||
310 | band_select = 0x03; | ||
311 | |||
312 | data[0] = (div >> 8) & 0x7f; | ||
313 | data[1] = div & 0xff; | ||
314 | data[2] = ((div >> 10) & 0x60) | cfg; | ||
315 | data[3] = (cpump << 6) | band_select; | ||
316 | |||
317 | if (fe->ops.i2c_gate_ctrl) | ||
318 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
319 | if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; | ||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | static struct l64781_config grundig_29504_401_config = { | ||
324 | .demod_address = 0x55, | ||
325 | }; | ||
326 | |||
327 | static struct l64781_config grundig_29504_401_config_activy = { | ||
328 | .demod_address = 0x54, | ||
329 | }; | ||
330 | |||
331 | static u8 tuner_address_grundig_29504_401_activy = 0x60; | ||
332 | |||
333 | static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe) | ||
334 | { | ||
335 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
336 | struct budget* budget = (struct budget*) fe->dvb->priv; | ||
337 | u32 div; | ||
338 | u8 data[4]; | ||
339 | struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; | ||
340 | |||
341 | div = c->frequency / 125; | ||
342 | data[0] = (div >> 8) & 0x7f; | ||
343 | data[1] = div & 0xff; | ||
344 | data[2] = 0x8e; | ||
345 | data[3] = 0x00; | ||
346 | |||
347 | if (fe->ops.i2c_gate_ctrl) | ||
348 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
349 | if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; | ||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | static struct tda8083_config grundig_29504_451_config = { | ||
354 | .demod_address = 0x68, | ||
355 | }; | ||
356 | |||
357 | static int s5h1420_tuner_set_params(struct dvb_frontend *fe) | ||
358 | { | ||
359 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
360 | struct budget* budget = (struct budget*) fe->dvb->priv; | ||
361 | u32 div; | ||
362 | u8 data[4]; | ||
363 | struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; | ||
364 | |||
365 | div = c->frequency / 1000; | ||
366 | data[0] = (div >> 8) & 0x7f; | ||
367 | data[1] = div & 0xff; | ||
368 | data[2] = 0xc2; | ||
369 | |||
370 | if (div < 1450) | ||
371 | data[3] = 0x00; | ||
372 | else if (div < 1850) | ||
373 | data[3] = 0x40; | ||
374 | else if (div < 2000) | ||
375 | data[3] = 0x80; | ||
376 | else | ||
377 | data[3] = 0xc0; | ||
378 | |||
379 | if (fe->ops.i2c_gate_ctrl) | ||
380 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
381 | if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; | ||
382 | |||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | static struct s5h1420_config s5h1420_config = { | ||
387 | .demod_address = 0x53, | ||
388 | .invert = 1, | ||
389 | .cdclk_polarity = 1, | ||
390 | }; | ||
391 | |||
392 | static struct tda10086_config tda10086_config = { | ||
393 | .demod_address = 0x0e, | ||
394 | .invert = 0, | ||
395 | .diseqc_tone = 1, | ||
396 | .xtal_freq = TDA10086_XTAL_16M, | ||
397 | }; | ||
398 | |||
399 | static struct stv0299_config alps_bsru6_config_activy = { | ||
400 | .demod_address = 0x68, | ||
401 | .inittab = alps_bsru6_inittab, | ||
402 | .mclk = 88000000UL, | ||
403 | .invert = 1, | ||
404 | .op0_off = 1, | ||
405 | .min_delay_ms = 100, | ||
406 | .set_symbol_rate = alps_bsru6_set_symbol_rate, | ||
407 | }; | ||
408 | |||
409 | static struct stv0299_config alps_bsbe1_config_activy = { | ||
410 | .demod_address = 0x68, | ||
411 | .inittab = alps_bsbe1_inittab, | ||
412 | .mclk = 88000000UL, | ||
413 | .invert = 1, | ||
414 | .op0_off = 1, | ||
415 | .min_delay_ms = 100, | ||
416 | .set_symbol_rate = alps_bsbe1_set_symbol_rate, | ||
417 | }; | ||
418 | |||
419 | static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name) | ||
420 | { | ||
421 | struct budget *budget = (struct budget *)fe->dvb->priv; | ||
422 | |||
423 | return request_firmware(fw, name, &budget->dev->pci->dev); | ||
424 | } | ||
425 | |||
426 | |||
427 | static int i2c_readreg(struct i2c_adapter *i2c, u8 adr, u8 reg) | ||
428 | { | ||
429 | u8 val; | ||
430 | struct i2c_msg msg[] = { | ||
431 | { .addr = adr, .flags = 0, .buf = ®, .len = 1 }, | ||
432 | { .addr = adr, .flags = I2C_M_RD, .buf = &val, .len = 1 } | ||
433 | }; | ||
434 | |||
435 | return (i2c_transfer(i2c, msg, 2) != 2) ? -EIO : val; | ||
436 | } | ||
437 | |||
438 | static u8 read_pwm(struct budget* budget) | ||
439 | { | ||
440 | u8 b = 0xff; | ||
441 | u8 pwm; | ||
442 | struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 }, | ||
443 | { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} }; | ||
444 | |||
445 | if ((i2c_transfer(&budget->i2c_adap, msg, 2) != 2) || (pwm == 0xff)) | ||
446 | pwm = 0x48; | ||
447 | |||
448 | return pwm; | ||
449 | } | ||
450 | |||
451 | static struct stv090x_config tt1600_stv090x_config = { | ||
452 | .device = STV0903, | ||
453 | .demod_mode = STV090x_SINGLE, | ||
454 | .clk_mode = STV090x_CLK_EXT, | ||
455 | |||
456 | .xtal = 13500000, | ||
457 | .address = 0x68, | ||
458 | |||
459 | .ts1_mode = STV090x_TSMODE_DVBCI, | ||
460 | .ts2_mode = STV090x_TSMODE_SERIAL_CONTINUOUS, | ||
461 | |||
462 | .repeater_level = STV090x_RPTLEVEL_16, | ||
463 | |||
464 | .tuner_init = NULL, | ||
465 | .tuner_sleep = NULL, | ||
466 | .tuner_set_mode = NULL, | ||
467 | .tuner_set_frequency = NULL, | ||
468 | .tuner_get_frequency = NULL, | ||
469 | .tuner_set_bandwidth = NULL, | ||
470 | .tuner_get_bandwidth = NULL, | ||
471 | .tuner_set_bbgain = NULL, | ||
472 | .tuner_get_bbgain = NULL, | ||
473 | .tuner_set_refclk = NULL, | ||
474 | .tuner_get_status = NULL, | ||
475 | }; | ||
476 | |||
477 | static struct stv6110x_config tt1600_stv6110x_config = { | ||
478 | .addr = 0x60, | ||
479 | .refclk = 27000000, | ||
480 | .clk_div = 2, | ||
481 | }; | ||
482 | |||
483 | static struct isl6423_config tt1600_isl6423_config = { | ||
484 | .current_max = SEC_CURRENT_515m, | ||
485 | .curlim = SEC_CURRENT_LIM_ON, | ||
486 | .mod_extern = 1, | ||
487 | .addr = 0x08, | ||
488 | }; | ||
489 | |||
490 | static void frontend_init(struct budget *budget) | ||
491 | { | ||
492 | (void)alps_bsbe1_config; /* avoid warning */ | ||
493 | |||
494 | switch(budget->dev->pci->subsystem_device) { | ||
495 | case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659)) | ||
496 | case 0x1013: | ||
497 | // try the ALPS BSRV2 first of all | ||
498 | budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap); | ||
499 | if (budget->dvb_frontend) { | ||
500 | budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; | ||
501 | budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; | ||
502 | budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; | ||
503 | budget->dvb_frontend->ops.set_tone = budget_set_tone; | ||
504 | break; | ||
505 | } | ||
506 | |||
507 | // try the ALPS BSRU6 now | ||
508 | budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap); | ||
509 | if (budget->dvb_frontend) { | ||
510 | budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; | ||
511 | budget->dvb_frontend->tuner_priv = &budget->i2c_adap; | ||
512 | if (budget->dev->pci->subsystem_device == 0x1003 && diseqc_method == 0) { | ||
513 | budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; | ||
514 | budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; | ||
515 | budget->dvb_frontend->ops.set_tone = budget_set_tone; | ||
516 | } | ||
517 | break; | ||
518 | } | ||
519 | break; | ||
520 | |||
521 | case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659)) | ||
522 | |||
523 | budget->dvb_frontend = dvb_attach(ves1820_attach, &alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget)); | ||
524 | if (budget->dvb_frontend) { | ||
525 | budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; | ||
526 | break; | ||
527 | } | ||
528 | break; | ||
529 | |||
530 | case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060)) | ||
531 | |||
532 | budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config, &budget->i2c_adap); | ||
533 | if (budget->dvb_frontend) { | ||
534 | budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params; | ||
535 | budget->dvb_frontend->tuner_priv = NULL; | ||
536 | break; | ||
537 | } | ||
538 | break; | ||
539 | |||
540 | case 0x4f60: /* Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/tsa5059) */ | ||
541 | { | ||
542 | int subtype = i2c_readreg(&budget->i2c_adap, 0x50, 0x67); | ||
543 | |||
544 | if (subtype < 0) | ||
545 | break; | ||
546 | /* fixme: find a better way to identify the card */ | ||
547 | if (subtype < 0x36) { | ||
548 | /* assume ALPS BSRU6 */ | ||
549 | budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config_activy, &budget->i2c_adap); | ||
550 | if (budget->dvb_frontend) { | ||
551 | printk(KERN_INFO "budget: tuner ALPS BSRU6 detected\n"); | ||
552 | budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; | ||
553 | budget->dvb_frontend->tuner_priv = &budget->i2c_adap; | ||
554 | budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage; | ||
555 | budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; | ||
556 | break; | ||
557 | } | ||
558 | } else { | ||
559 | /* assume ALPS BSBE1 */ | ||
560 | /* reset tuner */ | ||
561 | saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTLO); | ||
562 | msleep(50); | ||
563 | saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTHI); | ||
564 | msleep(250); | ||
565 | budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config_activy, &budget->i2c_adap); | ||
566 | if (budget->dvb_frontend) { | ||
567 | printk(KERN_INFO "budget: tuner ALPS BSBE1 detected\n"); | ||
568 | budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params; | ||
569 | budget->dvb_frontend->tuner_priv = &budget->i2c_adap; | ||
570 | budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage; | ||
571 | budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; | ||
572 | break; | ||
573 | } | ||
574 | } | ||
575 | break; | ||
576 | } | ||
577 | |||
578 | case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522)) | ||
579 | budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap); | ||
580 | if (budget->dvb_frontend) { | ||
581 | budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; | ||
582 | budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage; | ||
583 | budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; | ||
584 | } | ||
585 | break; | ||
586 | |||
587 | case 0x5f60: /* Fujitsu Siemens Activy Budget-T PCI rev AL (tda10046/ALPS TDHD1-204A) */ | ||
588 | budget->dvb_frontend = dvb_attach(tda10046_attach, &alps_tdhd1_204a_config, &budget->i2c_adap); | ||
589 | if (budget->dvb_frontend) { | ||
590 | budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdhd1_204a_tuner_set_params; | ||
591 | budget->dvb_frontend->tuner_priv = &budget->i2c_adap; | ||
592 | } | ||
593 | break; | ||
594 | |||
595 | case 0x5f61: /* Fujitsu Siemens Activy Budget-T PCI rev GR (L64781/Grundig 29504-401(tsa5060)) */ | ||
596 | budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config_activy, &budget->i2c_adap); | ||
597 | if (budget->dvb_frontend) { | ||
598 | budget->dvb_frontend->tuner_priv = &tuner_address_grundig_29504_401_activy; | ||
599 | budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params; | ||
600 | } | ||
601 | break; | ||
602 | |||
603 | case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260)) | ||
604 | budget->dvb_frontend = dvb_attach(s5h1420_attach, &s5h1420_config, &budget->i2c_adap); | ||
605 | if (budget->dvb_frontend) { | ||
606 | budget->dvb_frontend->ops.tuner_ops.set_params = s5h1420_tuner_set_params; | ||
607 | if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) { | ||
608 | printk("%s: No LNBP21 found!\n", __func__); | ||
609 | goto error_out; | ||
610 | } | ||
611 | break; | ||
612 | } | ||
613 | |||
614 | case 0x1018: // TT Budget-S-1401 (philips tda10086/philips tda8262) | ||
615 | // gpio2 is connected to CLB - reset it + leave it high | ||
616 | saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO); | ||
617 | msleep(1); | ||
618 | saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI); | ||
619 | msleep(1); | ||
620 | |||
621 | budget->dvb_frontend = dvb_attach(tda10086_attach, &tda10086_config, &budget->i2c_adap); | ||
622 | if (budget->dvb_frontend) { | ||
623 | if (dvb_attach(tda826x_attach, budget->dvb_frontend, 0x60, &budget->i2c_adap, 0) == NULL) | ||
624 | printk("%s: No tda826x found!\n", __func__); | ||
625 | if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) { | ||
626 | printk("%s: No LNBP21 found!\n", __func__); | ||
627 | goto error_out; | ||
628 | } | ||
629 | break; | ||
630 | } | ||
631 | |||
632 | case 0x101c: { /* TT S2-1600 */ | ||
633 | struct stv6110x_devctl *ctl; | ||
634 | saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO); | ||
635 | msleep(50); | ||
636 | saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI); | ||
637 | msleep(250); | ||
638 | |||
639 | budget->dvb_frontend = dvb_attach(stv090x_attach, | ||
640 | &tt1600_stv090x_config, | ||
641 | &budget->i2c_adap, | ||
642 | STV090x_DEMODULATOR_0); | ||
643 | |||
644 | if (budget->dvb_frontend) { | ||
645 | |||
646 | ctl = dvb_attach(stv6110x_attach, | ||
647 | budget->dvb_frontend, | ||
648 | &tt1600_stv6110x_config, | ||
649 | &budget->i2c_adap); | ||
650 | |||
651 | if (ctl) { | ||
652 | tt1600_stv090x_config.tuner_init = ctl->tuner_init; | ||
653 | tt1600_stv090x_config.tuner_sleep = ctl->tuner_sleep; | ||
654 | tt1600_stv090x_config.tuner_set_mode = ctl->tuner_set_mode; | ||
655 | tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency; | ||
656 | tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency; | ||
657 | tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth; | ||
658 | tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth; | ||
659 | tt1600_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain; | ||
660 | tt1600_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain; | ||
661 | tt1600_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk; | ||
662 | tt1600_stv090x_config.tuner_get_status = ctl->tuner_get_status; | ||
663 | |||
664 | /* call the init function once to initialize | ||
665 | tuner's clock output divider and demod's | ||
666 | master clock */ | ||
667 | if (budget->dvb_frontend->ops.init) | ||
668 | budget->dvb_frontend->ops.init(budget->dvb_frontend); | ||
669 | |||
670 | if (dvb_attach(isl6423_attach, | ||
671 | budget->dvb_frontend, | ||
672 | &budget->i2c_adap, | ||
673 | &tt1600_isl6423_config) == NULL) { | ||
674 | printk(KERN_ERR "%s: No Intersil ISL6423 found!\n", __func__); | ||
675 | goto error_out; | ||
676 | } | ||
677 | } else { | ||
678 | printk(KERN_ERR "%s: No STV6110(A) Silicon Tuner found!\n", __func__); | ||
679 | goto error_out; | ||
680 | } | ||
681 | } | ||
682 | } | ||
683 | break; | ||
684 | |||
685 | case 0x1020: { /* Omicom S2 */ | ||
686 | struct stv6110x_devctl *ctl; | ||
687 | saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO); | ||
688 | msleep(50); | ||
689 | saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI); | ||
690 | msleep(250); | ||
691 | |||
692 | budget->dvb_frontend = dvb_attach(stv090x_attach, | ||
693 | &tt1600_stv090x_config, | ||
694 | &budget->i2c_adap, | ||
695 | STV090x_DEMODULATOR_0); | ||
696 | |||
697 | if (budget->dvb_frontend) { | ||
698 | printk(KERN_INFO "budget: Omicom S2 detected\n"); | ||
699 | |||
700 | ctl = dvb_attach(stv6110x_attach, | ||
701 | budget->dvb_frontend, | ||
702 | &tt1600_stv6110x_config, | ||
703 | &budget->i2c_adap); | ||
704 | |||
705 | if (ctl) { | ||
706 | tt1600_stv090x_config.tuner_init = ctl->tuner_init; | ||
707 | tt1600_stv090x_config.tuner_sleep = ctl->tuner_sleep; | ||
708 | tt1600_stv090x_config.tuner_set_mode = ctl->tuner_set_mode; | ||
709 | tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency; | ||
710 | tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency; | ||
711 | tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth; | ||
712 | tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth; | ||
713 | tt1600_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain; | ||
714 | tt1600_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain; | ||
715 | tt1600_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk; | ||
716 | tt1600_stv090x_config.tuner_get_status = ctl->tuner_get_status; | ||
717 | |||
718 | /* call the init function once to initialize | ||
719 | tuner's clock output divider and demod's | ||
720 | master clock */ | ||
721 | if (budget->dvb_frontend->ops.init) | ||
722 | budget->dvb_frontend->ops.init(budget->dvb_frontend); | ||
723 | |||
724 | if (dvb_attach(lnbh24_attach, | ||
725 | budget->dvb_frontend, | ||
726 | &budget->i2c_adap, | ||
727 | LNBH24_PCL | LNBH24_TTX, | ||
728 | LNBH24_TEN, 0x14>>1) == NULL) { | ||
729 | printk(KERN_ERR | ||
730 | "No LNBH24 found!\n"); | ||
731 | goto error_out; | ||
732 | } | ||
733 | } else { | ||
734 | printk(KERN_ERR "%s: No STV6110(A) Silicon Tuner found!\n", __func__); | ||
735 | goto error_out; | ||
736 | } | ||
737 | } | ||
738 | } | ||
739 | break; | ||
740 | } | ||
741 | |||
742 | if (budget->dvb_frontend == NULL) { | ||
743 | printk("budget: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", | ||
744 | budget->dev->pci->vendor, | ||
745 | budget->dev->pci->device, | ||
746 | budget->dev->pci->subsystem_vendor, | ||
747 | budget->dev->pci->subsystem_device); | ||
748 | } else { | ||
749 | if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) | ||
750 | goto error_out; | ||
751 | } | ||
752 | return; | ||
753 | |||
754 | error_out: | ||
755 | printk("budget: Frontend registration failed!\n"); | ||
756 | dvb_frontend_detach(budget->dvb_frontend); | ||
757 | budget->dvb_frontend = NULL; | ||
758 | return; | ||
759 | } | ||
760 | |||
761 | static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) | ||
762 | { | ||
763 | struct budget *budget = NULL; | ||
764 | int err; | ||
765 | |||
766 | budget = kmalloc(sizeof(struct budget), GFP_KERNEL); | ||
767 | if( NULL == budget ) { | ||
768 | return -ENOMEM; | ||
769 | } | ||
770 | |||
771 | dprintk(2, "dev:%p, info:%p, budget:%p\n", dev, info, budget); | ||
772 | |||
773 | dev->ext_priv = budget; | ||
774 | |||
775 | err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr); | ||
776 | if (err) { | ||
777 | printk("==> failed\n"); | ||
778 | kfree (budget); | ||
779 | return err; | ||
780 | } | ||
781 | |||
782 | budget->dvb_adapter.priv = budget; | ||
783 | frontend_init(budget); | ||
784 | |||
785 | ttpci_budget_init_hooks(budget); | ||
786 | |||
787 | return 0; | ||
788 | } | ||
789 | |||
790 | static int budget_detach (struct saa7146_dev* dev) | ||
791 | { | ||
792 | struct budget *budget = (struct budget*) dev->ext_priv; | ||
793 | int err; | ||
794 | |||
795 | if (budget->dvb_frontend) { | ||
796 | dvb_unregister_frontend(budget->dvb_frontend); | ||
797 | dvb_frontend_detach(budget->dvb_frontend); | ||
798 | } | ||
799 | |||
800 | err = ttpci_budget_deinit (budget); | ||
801 | |||
802 | kfree (budget); | ||
803 | dev->ext_priv = NULL; | ||
804 | |||
805 | return err; | ||
806 | } | ||
807 | |||
808 | static struct saa7146_extension budget_extension; | ||
809 | |||
810 | MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S PCI", BUDGET_TT); | ||
811 | MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT); | ||
812 | MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT); | ||
813 | MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC); | ||
814 | MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT); | ||
815 | MAKE_BUDGET_INFO(tt1600, "TT-Budget S2-1600 PCI", BUDGET_TT); | ||
816 | MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY); | ||
817 | MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY); | ||
818 | MAKE_BUDGET_INFO(fsact, "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY); | ||
819 | MAKE_BUDGET_INFO(fsact1, "Fujitsu Siemens Activy Budget-T PCI (rev AL/ALPS TDHD1-204A)", BUDGET_FS_ACTIVY); | ||
820 | MAKE_BUDGET_INFO(omicom, "Omicom S2 PCI", BUDGET_TT); | ||
821 | |||
822 | static struct pci_device_id pci_tbl[] = { | ||
823 | MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003), | ||
824 | MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004), | ||
825 | MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005), | ||
826 | MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), | ||
827 | MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1016), | ||
828 | MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018), | ||
829 | MAKE_EXTENSION_PCI(tt1600, 0x13c2, 0x101c), | ||
830 | MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60), | ||
831 | MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61), | ||
832 | MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60), | ||
833 | MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61), | ||
834 | MAKE_EXTENSION_PCI(omicom, 0x14c4, 0x1020), | ||
835 | { | ||
836 | .vendor = 0, | ||
837 | } | ||
838 | }; | ||
839 | |||
840 | MODULE_DEVICE_TABLE(pci, pci_tbl); | ||
841 | |||
842 | static struct saa7146_extension budget_extension = { | ||
843 | .name = "budget dvb", | ||
844 | .flags = SAA7146_USE_I2C_IRQ, | ||
845 | |||
846 | .module = THIS_MODULE, | ||
847 | .pci_tbl = pci_tbl, | ||
848 | .attach = budget_attach, | ||
849 | .detach = budget_detach, | ||
850 | |||
851 | .irq_mask = MASK_10, | ||
852 | .irq_func = ttpci_budget_irq10_handler, | ||
853 | }; | ||
854 | |||
855 | static int __init budget_init(void) | ||
856 | { | ||
857 | return saa7146_register_extension(&budget_extension); | ||
858 | } | ||
859 | |||
860 | static void __exit budget_exit(void) | ||
861 | { | ||
862 | saa7146_unregister_extension(&budget_extension); | ||
863 | } | ||
864 | |||
865 | module_init(budget_init); | ||
866 | module_exit(budget_exit); | ||
867 | |||
868 | MODULE_LICENSE("GPL"); | ||
869 | MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others"); | ||
870 | MODULE_DESCRIPTION("driver for the SAA7146 based so-called " | ||
871 | "budget PCI DVB cards by Siemens, Technotrend, Hauppauge"); | ||