File Index
Files and directories
Sign in
FILE

budget.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/pci/ttpci/budget.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * budget.ko: driver for the SAA7146 based Budget DVB cards
  4 *            without analog video input or CI
  5 *
  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  Metzler
 11 *                       & Marcus Metzler for convergence integrated media GmbH
 12 *
 13 * 26feb2004 Support for FS Activy Card (Grundig tuner) by
 14 *           Michael Dreher <michael@5dot1.de>,
 15 *           Oliver Endriss <o.endriss@gmx.de> and
 16 *           Andreas 'randy' Weinberger
 17 *
 18 * the project's page is at https://linuxtv.org
 19 */
 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 card
 56 * taken from the Skyvision DVB driver by
 57 * 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 card
119 *   22 kHz tone and DiSEqC are handled by the frontend.
120 *   Voltage must be set here.
121 *   GPIO 1: LNBP EN, GPIO 2: LNBP VSEL
122 */
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	else
217		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 the
225	// divisor frequency to 62.5kHz and divide by 125 above
226
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	else
282		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	else
297		cpump = 3;
298
299	if (c->frequency < 175000000)
300		band_select = 0x0e;
301	else if (c->frequency < 470000000)
302		band_select = 0x05;
303	else
304		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	else
373		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 = &reg, .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 all
495		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 now
505		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 high
632		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 initialize
688					 * tuner's clock output divider and demod's
689					 * master clock
690					 */
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 initialize
745					 * tuner's clock output divider and demod's
746					 * master clock
747					 */
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");
~/ Read-only file preview.