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