162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Bt8xx based DVB adapter driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2002,2003 Florian Schirmer <jolt@tuxbox.org>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/bitops.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/init.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/device.h>
1562306a36Sopenharmony_ci#include <linux/delay.h>
1662306a36Sopenharmony_ci#include <linux/slab.h>
1762306a36Sopenharmony_ci#include <linux/i2c.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <media/dmxdev.h>
2062306a36Sopenharmony_ci#include <media/dvbdev.h>
2162306a36Sopenharmony_ci#include <media/dvb_demux.h>
2262306a36Sopenharmony_ci#include <media/dvb_frontend.h>
2362306a36Sopenharmony_ci#include "dvb-bt8xx.h"
2462306a36Sopenharmony_ci#include "bt878.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic int debug;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cimodule_param(debug, int, 0644);
2962306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define dprintk(fmt, arg...) do {				\
3462306a36Sopenharmony_ci	if (debug)						\
3562306a36Sopenharmony_ci		printk(KERN_DEBUG pr_fmt("%s: " fmt),		\
3662306a36Sopenharmony_ci		       __func__, ##arg);			\
3762306a36Sopenharmony_ci} while (0)
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic void dvb_bt8xx_task(struct tasklet_struct *t)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	struct bt878 *bt = from_tasklet(bt, t, tasklet);
4562306a36Sopenharmony_ci	struct dvb_bt8xx_card *card = dev_get_drvdata(&bt->adapter->dev);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	dprintk("%d\n", card->bt->finished_block);
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	while (card->bt->last_block != card->bt->finished_block) {
5062306a36Sopenharmony_ci		(card->bt->TS_Size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter)
5162306a36Sopenharmony_ci			(&card->demux,
5262306a36Sopenharmony_ci			 &card->bt->buf_cpu[card->bt->last_block *
5362306a36Sopenharmony_ci					    card->bt->block_bytes],
5462306a36Sopenharmony_ci			 card->bt->block_bytes);
5562306a36Sopenharmony_ci		card->bt->last_block = (card->bt->last_block + 1) %
5662306a36Sopenharmony_ci					card->bt->block_count;
5762306a36Sopenharmony_ci	}
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic int dvb_bt8xx_start_feed(struct dvb_demux_feed *dvbdmxfeed)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	struct dvb_demux*dvbdmx = dvbdmxfeed->demux;
6362306a36Sopenharmony_ci	struct dvb_bt8xx_card *card = dvbdmx->priv;
6462306a36Sopenharmony_ci	int rc;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	dprintk("dvb_bt8xx: start_feed\n");
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	if (!dvbdmx->dmx.frontend)
6962306a36Sopenharmony_ci		return -EINVAL;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	mutex_lock(&card->lock);
7262306a36Sopenharmony_ci	card->nfeeds++;
7362306a36Sopenharmony_ci	rc = card->nfeeds;
7462306a36Sopenharmony_ci	if (card->nfeeds == 1)
7562306a36Sopenharmony_ci		bt878_start(card->bt, card->gpio_mode,
7662306a36Sopenharmony_ci			    card->op_sync_orin, card->irq_err_ignore);
7762306a36Sopenharmony_ci	mutex_unlock(&card->lock);
7862306a36Sopenharmony_ci	return rc;
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistatic int dvb_bt8xx_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
8462306a36Sopenharmony_ci	struct dvb_bt8xx_card *card = dvbdmx->priv;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	dprintk("dvb_bt8xx: stop_feed\n");
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	if (!dvbdmx->dmx.frontend)
8962306a36Sopenharmony_ci		return -EINVAL;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	mutex_lock(&card->lock);
9262306a36Sopenharmony_ci	card->nfeeds--;
9362306a36Sopenharmony_ci	if (card->nfeeds == 0)
9462306a36Sopenharmony_ci		bt878_stop(card->bt);
9562306a36Sopenharmony_ci	mutex_unlock(&card->lock);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	return 0;
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic int is_pci_slot_eq(struct pci_dev* adev, struct pci_dev* bdev)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	if ((adev->subsystem_vendor == bdev->subsystem_vendor) &&
10362306a36Sopenharmony_ci		(adev->subsystem_device == bdev->subsystem_device) &&
10462306a36Sopenharmony_ci		(adev->bus->number == bdev->bus->number) &&
10562306a36Sopenharmony_ci		(PCI_SLOT(adev->devfn) == PCI_SLOT(bdev->devfn)))
10662306a36Sopenharmony_ci		return 1;
10762306a36Sopenharmony_ci	return 0;
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic struct bt878 *dvb_bt8xx_878_match(unsigned int bttv_nr,
11162306a36Sopenharmony_ci					 struct pci_dev* bttv_pci_dev)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	unsigned int card_nr;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	/* Hmm, n squared. Hope n is small */
11662306a36Sopenharmony_ci	for (card_nr = 0; card_nr < bt878_num; card_nr++)
11762306a36Sopenharmony_ci		if (is_pci_slot_eq(bt878[card_nr].dev, bttv_pci_dev))
11862306a36Sopenharmony_ci			return &bt878[card_nr];
11962306a36Sopenharmony_ci	return NULL;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic int thomson_dtt7579_demod_init(struct dvb_frontend* fe)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	static u8 mt352_clock_config [] = { 0x89, 0x38, 0x38 };
12562306a36Sopenharmony_ci	static u8 mt352_reset [] = { 0x50, 0x80 };
12662306a36Sopenharmony_ci	static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
12762306a36Sopenharmony_ci	static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0x20 };
12862306a36Sopenharmony_ci	static u8 mt352_gpp_ctl_cfg [] = { 0x8C, 0x33 };
12962306a36Sopenharmony_ci	static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
13262306a36Sopenharmony_ci	udelay(2000);
13362306a36Sopenharmony_ci	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
13462306a36Sopenharmony_ci	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
13762306a36Sopenharmony_ci	mt352_write(fe, mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg));
13862306a36Sopenharmony_ci	mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	return 0;
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend *fe, u8* pllbuf, int buf_len)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
14662306a36Sopenharmony_ci	u32 div;
14762306a36Sopenharmony_ci	unsigned char bs = 0;
14862306a36Sopenharmony_ci	unsigned char cp = 0;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	if (buf_len < 5)
15162306a36Sopenharmony_ci		return -EINVAL;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	if (c->frequency < 542000000)
15662306a36Sopenharmony_ci		cp = 0xb4;
15762306a36Sopenharmony_ci	else if (c->frequency < 771000000)
15862306a36Sopenharmony_ci		cp = 0xbc;
15962306a36Sopenharmony_ci	else
16062306a36Sopenharmony_ci		cp = 0xf4;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	if (c->frequency == 0)
16362306a36Sopenharmony_ci		bs = 0x03;
16462306a36Sopenharmony_ci	else if (c->frequency < 443250000)
16562306a36Sopenharmony_ci		bs = 0x02;
16662306a36Sopenharmony_ci	else
16762306a36Sopenharmony_ci		bs = 0x08;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	pllbuf[0] = 0x60;
17062306a36Sopenharmony_ci	pllbuf[1] = div >> 8;
17162306a36Sopenharmony_ci	pllbuf[2] = div & 0xff;
17262306a36Sopenharmony_ci	pllbuf[3] = cp;
17362306a36Sopenharmony_ci	pllbuf[4] = bs;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	return 5;
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic struct mt352_config thomson_dtt7579_config = {
17962306a36Sopenharmony_ci	.demod_address = 0x0f,
18062306a36Sopenharmony_ci	.demod_init = thomson_dtt7579_demod_init,
18162306a36Sopenharmony_ci};
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic struct zl10353_config thomson_dtt7579_zl10353_config = {
18462306a36Sopenharmony_ci	.demod_address = 0x0f,
18562306a36Sopenharmony_ci};
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic int cx24108_tuner_set_params(struct dvb_frontend *fe)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
19062306a36Sopenharmony_ci	u32 freq = c->frequency;
19162306a36Sopenharmony_ci	int i, a, n, pump;
19262306a36Sopenharmony_ci	u32 band, pll;
19362306a36Sopenharmony_ci	u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000,
19462306a36Sopenharmony_ci		1576000,1718000,1856000,2036000,2150000};
19562306a36Sopenharmony_ci	u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000,
19662306a36Sopenharmony_ci		0x00102000,0x00104000,0x00108000,0x00110000,
19762306a36Sopenharmony_ci		0x00120000,0x00140000};
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	#define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */
20062306a36Sopenharmony_ci	dprintk("cx24108 debug: entering SetTunerFreq, freq=%d\n", freq);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	/* This is really the bit driving the tuner chip cx24108 */
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	if (freq<950000)
20562306a36Sopenharmony_ci		freq = 950000; /* kHz */
20662306a36Sopenharmony_ci	else if (freq>2150000)
20762306a36Sopenharmony_ci		freq = 2150000; /* satellite IF is 950..2150MHz */
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	/* decide which VCO to use for the input frequency */
21062306a36Sopenharmony_ci	for(i = 1; (i < ARRAY_SIZE(osci) - 1) && (osci[i] < freq); i++);
21162306a36Sopenharmony_ci	dprintk("cx24108 debug: select vco #%d (f=%d)\n", i, freq);
21262306a36Sopenharmony_ci	band=bandsel[i];
21362306a36Sopenharmony_ci	/* the gain values must be set by SetSymbolrate */
21462306a36Sopenharmony_ci	/* compute the pll divider needed, from Conexant data sheet,
21562306a36Sopenharmony_ci	   resolved for (n*32+a), remember f(vco) is f(receive) *2 or *4,
21662306a36Sopenharmony_ci	   depending on the divider bit. It is set to /4 on the 2 lowest
21762306a36Sopenharmony_ci	   bands  */
21862306a36Sopenharmony_ci	n=((i<=2?2:1)*freq*10L)/(XTAL/100);
21962306a36Sopenharmony_ci	a=n%32; n/=32; if(a==0) n--;
22062306a36Sopenharmony_ci	pump=(freq<(osci[i-1]+osci[i])/2);
22162306a36Sopenharmony_ci	pll=0xf8000000|
22262306a36Sopenharmony_ci	    ((pump?1:2)<<(14+11))|
22362306a36Sopenharmony_ci	    ((n&0x1ff)<<(5+11))|
22462306a36Sopenharmony_ci	    ((a&0x1f)<<11);
22562306a36Sopenharmony_ci	/* everything is shifted left 11 bits to left-align the bits in the
22662306a36Sopenharmony_ci	   32bit word. Output to the tuner goes MSB-aligned, after all */
22762306a36Sopenharmony_ci	dprintk("cx24108 debug: pump=%d, n=%d, a=%d\n", pump, n, a);
22862306a36Sopenharmony_ci	cx24110_pll_write(fe,band);
22962306a36Sopenharmony_ci	/* set vga and vca to their widest-band settings, as a precaution.
23062306a36Sopenharmony_ci	   SetSymbolrate might not be called to set this up */
23162306a36Sopenharmony_ci	cx24110_pll_write(fe,0x500c0000);
23262306a36Sopenharmony_ci	cx24110_pll_write(fe,0x83f1f800);
23362306a36Sopenharmony_ci	cx24110_pll_write(fe,pll);
23462306a36Sopenharmony_ci	//writereg(client,0x56,0x7f);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	return 0;
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic int pinnsat_tuner_init(struct dvb_frontend* fe)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	struct dvb_bt8xx_card *card = fe->dvb->priv;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	bttv_gpio_enable(card->bttv_nr, 1, 1);  /* output */
24462306a36Sopenharmony_ci	bttv_write_gpio(card->bttv_nr, 1, 1);   /* relay on */
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	return 0;
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic int pinnsat_tuner_sleep(struct dvb_frontend* fe)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	struct dvb_bt8xx_card *card = fe->dvb->priv;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	bttv_write_gpio(card->bttv_nr, 1, 0);   /* relay off */
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	return 0;
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic struct cx24110_config pctvsat_config = {
25962306a36Sopenharmony_ci	.demod_address = 0x55,
26062306a36Sopenharmony_ci};
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend *fe)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
26562306a36Sopenharmony_ci	struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
26662306a36Sopenharmony_ci	u8 cfg, cpump, band_select;
26762306a36Sopenharmony_ci	u8 data[4];
26862306a36Sopenharmony_ci	u32 div;
26962306a36Sopenharmony_ci	struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) };
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	div = (36000000 + c->frequency + 83333) / 166666;
27262306a36Sopenharmony_ci	cfg = 0x88;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	if (c->frequency < 175000000)
27562306a36Sopenharmony_ci		cpump = 2;
27662306a36Sopenharmony_ci	else if (c->frequency < 390000000)
27762306a36Sopenharmony_ci		cpump = 1;
27862306a36Sopenharmony_ci	else if (c->frequency < 470000000)
27962306a36Sopenharmony_ci		cpump = 2;
28062306a36Sopenharmony_ci	else if (c->frequency < 750000000)
28162306a36Sopenharmony_ci		cpump = 2;
28262306a36Sopenharmony_ci	else
28362306a36Sopenharmony_ci		cpump = 3;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	if (c->frequency < 175000000)
28662306a36Sopenharmony_ci		band_select = 0x0e;
28762306a36Sopenharmony_ci	else if (c->frequency < 470000000)
28862306a36Sopenharmony_ci		band_select = 0x05;
28962306a36Sopenharmony_ci	else
29062306a36Sopenharmony_ci		band_select = 0x03;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	data[0] = (div >> 8) & 0x7f;
29362306a36Sopenharmony_ci	data[1] = div & 0xff;
29462306a36Sopenharmony_ci	data[2] = ((div >> 10) & 0x60) | cfg;
29562306a36Sopenharmony_ci	data[3] = (cpump << 6) | band_select;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	if (fe->ops.i2c_gate_ctrl)
29862306a36Sopenharmony_ci		fe->ops.i2c_gate_ctrl(fe, 1);
29962306a36Sopenharmony_ci	i2c_transfer(card->i2c_adapter, &msg, 1);
30062306a36Sopenharmony_ci	return (div * 166666 - 36000000);
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_cistatic int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	return request_firmware(fw, name, &bt->bt->dev->dev);
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_cistatic const struct sp887x_config microtune_mt7202dtf_config = {
31162306a36Sopenharmony_ci	.demod_address = 0x70,
31262306a36Sopenharmony_ci	.request_firmware = microtune_mt7202dtf_request_firmware,
31362306a36Sopenharmony_ci};
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_cistatic int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d };
31862306a36Sopenharmony_ci	static u8 mt352_reset [] = { 0x50, 0x80 };
31962306a36Sopenharmony_ci	static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
32062306a36Sopenharmony_ci	static u8 mt352_agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
32162306a36Sopenharmony_ci				       0x00, 0xFF, 0x00, 0x40, 0x40 };
32262306a36Sopenharmony_ci	static u8 mt352_av771_extra[] = { 0xB5, 0x7A };
32362306a36Sopenharmony_ci	static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
32662306a36Sopenharmony_ci	udelay(2000);
32762306a36Sopenharmony_ci	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
32862306a36Sopenharmony_ci	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg));
33162306a36Sopenharmony_ci	udelay(2000);
33262306a36Sopenharmony_ci	mt352_write(fe, mt352_av771_extra,sizeof(mt352_av771_extra));
33362306a36Sopenharmony_ci	mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	return 0;
33662306a36Sopenharmony_ci}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_cistatic int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend *fe, u8 *pllbuf, int buf_len)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
34162306a36Sopenharmony_ci	u32 div;
34262306a36Sopenharmony_ci	unsigned char bs = 0;
34362306a36Sopenharmony_ci	unsigned char cp = 0;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (buf_len < 5) return -EINVAL;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	if (c->frequency < 150000000)
35062306a36Sopenharmony_ci		cp = 0xB4;
35162306a36Sopenharmony_ci	else if (c->frequency < 173000000)
35262306a36Sopenharmony_ci		cp = 0xBC;
35362306a36Sopenharmony_ci	else if (c->frequency < 250000000)
35462306a36Sopenharmony_ci		cp = 0xB4;
35562306a36Sopenharmony_ci	else if (c->frequency < 400000000)
35662306a36Sopenharmony_ci		cp = 0xBC;
35762306a36Sopenharmony_ci	else if (c->frequency < 420000000)
35862306a36Sopenharmony_ci		cp = 0xF4;
35962306a36Sopenharmony_ci	else if (c->frequency < 470000000)
36062306a36Sopenharmony_ci		cp = 0xFC;
36162306a36Sopenharmony_ci	else if (c->frequency < 600000000)
36262306a36Sopenharmony_ci		cp = 0xBC;
36362306a36Sopenharmony_ci	else if (c->frequency < 730000000)
36462306a36Sopenharmony_ci		cp = 0xF4;
36562306a36Sopenharmony_ci	else
36662306a36Sopenharmony_ci		cp = 0xFC;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	if (c->frequency < 150000000)
36962306a36Sopenharmony_ci		bs = 0x01;
37062306a36Sopenharmony_ci	else if (c->frequency < 173000000)
37162306a36Sopenharmony_ci		bs = 0x01;
37262306a36Sopenharmony_ci	else if (c->frequency < 250000000)
37362306a36Sopenharmony_ci		bs = 0x02;
37462306a36Sopenharmony_ci	else if (c->frequency < 400000000)
37562306a36Sopenharmony_ci		bs = 0x02;
37662306a36Sopenharmony_ci	else if (c->frequency < 420000000)
37762306a36Sopenharmony_ci		bs = 0x02;
37862306a36Sopenharmony_ci	else if (c->frequency < 470000000)
37962306a36Sopenharmony_ci		bs = 0x02;
38062306a36Sopenharmony_ci	else
38162306a36Sopenharmony_ci		bs = 0x08;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	pllbuf[0] = 0x61;
38462306a36Sopenharmony_ci	pllbuf[1] = div >> 8;
38562306a36Sopenharmony_ci	pllbuf[2] = div & 0xff;
38662306a36Sopenharmony_ci	pllbuf[3] = cp;
38762306a36Sopenharmony_ci	pllbuf[4] = bs;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	return 5;
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic struct mt352_config advbt771_samsung_tdtc9251dh0_config = {
39362306a36Sopenharmony_ci	.demod_address = 0x0f,
39462306a36Sopenharmony_ci	.demod_init = advbt771_samsung_tdtc9251dh0_demod_init,
39562306a36Sopenharmony_ci};
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_cistatic const struct dst_config dst_config = {
39862306a36Sopenharmony_ci	.demod_address = 0x55,
39962306a36Sopenharmony_ci};
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_cistatic int or51211_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	return request_firmware(fw, name, &bt->bt->dev->dev);
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_cistatic void or51211_setmode(struct dvb_frontend * fe, int mode)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	struct dvb_bt8xx_card *bt = fe->dvb->priv;
41162306a36Sopenharmony_ci	bttv_write_gpio(bt->bttv_nr, 0x0002, mode);   /* Reset */
41262306a36Sopenharmony_ci	msleep(20);
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cistatic void or51211_reset(struct dvb_frontend * fe)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	struct dvb_bt8xx_card *bt = fe->dvb->priv;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	/* RESET DEVICE
42062306a36Sopenharmony_ci	 * reset is controlled by GPIO-0
42162306a36Sopenharmony_ci	 * when set to 0 causes reset and when to 1 for normal op
42262306a36Sopenharmony_ci	 * must remain reset for 128 clock cycles on a 50Mhz clock
42362306a36Sopenharmony_ci	 * also PRM1 PRM2 & PRM4 are controlled by GPIO-1,GPIO-2 & GPIO-4
42462306a36Sopenharmony_ci	 * We assume that the reset has be held low long enough or we
42562306a36Sopenharmony_ci	 * have been reset by a power on.  When the driver is unloaded
42662306a36Sopenharmony_ci	 * reset set to 0 so if reloaded we have been reset.
42762306a36Sopenharmony_ci	 */
42862306a36Sopenharmony_ci	/* reset & PRM1,2&4 are outputs */
42962306a36Sopenharmony_ci	int ret = bttv_gpio_enable(bt->bttv_nr, 0x001F, 0x001F);
43062306a36Sopenharmony_ci	if (ret != 0)
43162306a36Sopenharmony_ci		pr_warn("or51211: Init Error - Can't Reset DVR (%i)\n", ret);
43262306a36Sopenharmony_ci	bttv_write_gpio(bt->bttv_nr, 0x001F, 0x0000);   /* Reset */
43362306a36Sopenharmony_ci	msleep(20);
43462306a36Sopenharmony_ci	/* Now set for normal operation */
43562306a36Sopenharmony_ci	bttv_write_gpio(bt->bttv_nr, 0x0001F, 0x0001);
43662306a36Sopenharmony_ci	/* wait for operation to begin */
43762306a36Sopenharmony_ci	msleep(500);
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_cistatic void or51211_sleep(struct dvb_frontend * fe)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	struct dvb_bt8xx_card *bt = fe->dvb->priv;
44362306a36Sopenharmony_ci	bttv_write_gpio(bt->bttv_nr, 0x0001, 0x0000);
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_cistatic const struct or51211_config or51211_config = {
44762306a36Sopenharmony_ci	.demod_address = 0x15,
44862306a36Sopenharmony_ci	.request_firmware = or51211_request_firmware,
44962306a36Sopenharmony_ci	.setmode = or51211_setmode,
45062306a36Sopenharmony_ci	.reset = or51211_reset,
45162306a36Sopenharmony_ci	.sleep = or51211_sleep,
45262306a36Sopenharmony_ci};
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_cistatic int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend *fe)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
45762306a36Sopenharmony_ci	struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
45862306a36Sopenharmony_ci	u8 buf[4];
45962306a36Sopenharmony_ci	u32 div;
46062306a36Sopenharmony_ci	struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf) };
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	div = (c->frequency + 36166667) / 166667;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	buf[0] = (div >> 8) & 0x7F;
46562306a36Sopenharmony_ci	buf[1] = div & 0xFF;
46662306a36Sopenharmony_ci	buf[2] = 0x85;
46762306a36Sopenharmony_ci	if ((c->frequency >= 47000000) && (c->frequency < 153000000))
46862306a36Sopenharmony_ci		buf[3] = 0x01;
46962306a36Sopenharmony_ci	else if ((c->frequency >= 153000000) && (c->frequency < 430000000))
47062306a36Sopenharmony_ci		buf[3] = 0x02;
47162306a36Sopenharmony_ci	else if ((c->frequency >= 430000000) && (c->frequency < 824000000))
47262306a36Sopenharmony_ci		buf[3] = 0x0C;
47362306a36Sopenharmony_ci	else if ((c->frequency >= 824000000) && (c->frequency < 863000000))
47462306a36Sopenharmony_ci		buf[3] = 0x8C;
47562306a36Sopenharmony_ci	else
47662306a36Sopenharmony_ci		return -EINVAL;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	if (fe->ops.i2c_gate_ctrl)
47962306a36Sopenharmony_ci		fe->ops.i2c_gate_ctrl(fe, 1);
48062306a36Sopenharmony_ci	i2c_transfer(card->i2c_adapter, &msg, 1);
48162306a36Sopenharmony_ci	return 0;
48262306a36Sopenharmony_ci}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_cistatic struct nxt6000_config vp3021_alps_tded4_config = {
48562306a36Sopenharmony_ci	.demod_address = 0x0a,
48662306a36Sopenharmony_ci	.clock_inversion = 1,
48762306a36Sopenharmony_ci};
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_cistatic int digitv_alps_tded4_demod_init(struct dvb_frontend* fe)
49062306a36Sopenharmony_ci{
49162306a36Sopenharmony_ci	static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d };
49262306a36Sopenharmony_ci	static u8 mt352_reset [] = { 0x50, 0x80 };
49362306a36Sopenharmony_ci	static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
49462306a36Sopenharmony_ci	static u8 mt352_agc_cfg [] = { 0x67, 0x20, 0xa0 };
49562306a36Sopenharmony_ci	static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
49862306a36Sopenharmony_ci	udelay(2000);
49962306a36Sopenharmony_ci	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
50062306a36Sopenharmony_ci	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
50162306a36Sopenharmony_ci	mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg));
50262306a36Sopenharmony_ci	mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	return 0;
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_cistatic int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend *fe,  u8 *pllbuf, int buf_len)
50862306a36Sopenharmony_ci{
50962306a36Sopenharmony_ci	u32 div;
51062306a36Sopenharmony_ci	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	if (buf_len < 5)
51362306a36Sopenharmony_ci		return -EINVAL;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	div = (((c->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	pllbuf[0] = 0x61;
51862306a36Sopenharmony_ci	pllbuf[1] = (div >> 8) & 0x7F;
51962306a36Sopenharmony_ci	pllbuf[2] = div & 0xFF;
52062306a36Sopenharmony_ci	pllbuf[3] = 0x85;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	dprintk("frequency %u, div %u\n", c->frequency, div);
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	if (c->frequency < 470000000)
52562306a36Sopenharmony_ci		pllbuf[4] = 0x02;
52662306a36Sopenharmony_ci	else if (c->frequency > 823000000)
52762306a36Sopenharmony_ci		pllbuf[4] = 0x88;
52862306a36Sopenharmony_ci	else
52962306a36Sopenharmony_ci		pllbuf[4] = 0x08;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	if (c->bandwidth_hz == 8000000)
53262306a36Sopenharmony_ci		pllbuf[4] |= 0x04;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	return 5;
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_cistatic void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt)
53862306a36Sopenharmony_ci{
53962306a36Sopenharmony_ci	/*
54062306a36Sopenharmony_ci	 * Reset the frontend, must be called before trying
54162306a36Sopenharmony_ci	 * to initialise the MT352 or mt352_attach
54262306a36Sopenharmony_ci	 * will fail. Same goes for the nxt6000 frontend.
54362306a36Sopenharmony_ci	 *
54462306a36Sopenharmony_ci	 */
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	int ret = bttv_gpio_enable(bt->bttv_nr, 0x08, 0x08);
54762306a36Sopenharmony_ci	if (ret != 0)
54862306a36Sopenharmony_ci		pr_warn("digitv_alps_tded4: Init Error - Can't Reset DVR (%i)\n",
54962306a36Sopenharmony_ci			ret);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	/* Pulse the reset line */
55262306a36Sopenharmony_ci	bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */
55362306a36Sopenharmony_ci	bttv_write_gpio(bt->bttv_nr, 0x08, 0x00); /* Low  */
55462306a36Sopenharmony_ci	msleep(100);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */
55762306a36Sopenharmony_ci}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_cistatic struct mt352_config digitv_alps_tded4_config = {
56062306a36Sopenharmony_ci	.demod_address = 0x0a,
56162306a36Sopenharmony_ci	.demod_init = digitv_alps_tded4_demod_init,
56262306a36Sopenharmony_ci};
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_cistatic struct lgdt330x_config tdvs_tua6034_config = {
56562306a36Sopenharmony_ci	.demod_chip       = LGDT3303,
56662306a36Sopenharmony_ci	.serial_mpeg      = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
56762306a36Sopenharmony_ci};
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_cistatic void lgdt330x_reset(struct dvb_bt8xx_card *bt)
57062306a36Sopenharmony_ci{
57162306a36Sopenharmony_ci	/* Set pin 27 of the lgdt3303 chip high to reset the frontend */
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	/* Pulse the reset line */
57462306a36Sopenharmony_ci	bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */
57562306a36Sopenharmony_ci	bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000000); /* Low  */
57662306a36Sopenharmony_ci	msleep(100);
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */
57962306a36Sopenharmony_ci	msleep(100);
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_cistatic void frontend_init(struct dvb_bt8xx_card *card, u32 type)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	struct dst_state* state = NULL;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	switch(type) {
58762306a36Sopenharmony_ci	case BTTV_BOARD_DVICO_DVBT_LITE:
58862306a36Sopenharmony_ci		card->fe = dvb_attach(mt352_attach, &thomson_dtt7579_config, card->i2c_adapter);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci		if (card->fe == NULL)
59162306a36Sopenharmony_ci			card->fe = dvb_attach(zl10353_attach, &thomson_dtt7579_zl10353_config,
59262306a36Sopenharmony_ci						  card->i2c_adapter);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci		if (card->fe != NULL) {
59562306a36Sopenharmony_ci			card->fe->ops.tuner_ops.calc_regs = thomson_dtt7579_tuner_calc_regs;
59662306a36Sopenharmony_ci			card->fe->ops.info.frequency_min_hz = 174 * MHz;
59762306a36Sopenharmony_ci			card->fe->ops.info.frequency_max_hz = 862 * MHz;
59862306a36Sopenharmony_ci		}
59962306a36Sopenharmony_ci		break;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
60262306a36Sopenharmony_ci		lgdt330x_reset(card);
60362306a36Sopenharmony_ci		card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config,
60462306a36Sopenharmony_ci				      0x0e, card->i2c_adapter);
60562306a36Sopenharmony_ci		if (card->fe != NULL) {
60662306a36Sopenharmony_ci			dvb_attach(simple_tuner_attach, card->fe,
60762306a36Sopenharmony_ci				   card->i2c_adapter, 0x61,
60862306a36Sopenharmony_ci				   TUNER_LG_TDVS_H06XF);
60962306a36Sopenharmony_ci			dprintk("dvb_bt8xx: lgdt330x detected\n");
61062306a36Sopenharmony_ci		}
61162306a36Sopenharmony_ci		break;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	case BTTV_BOARD_NEBULA_DIGITV:
61462306a36Sopenharmony_ci		/*
61562306a36Sopenharmony_ci		 * It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK);
61662306a36Sopenharmony_ci		 * this would be a cleaner solution than trying each frontend in turn.
61762306a36Sopenharmony_ci		 */
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci		/* Old Nebula (marked (c)2003 on high profile pci card) has nxt6000 demod */
62062306a36Sopenharmony_ci		digitv_alps_tded4_reset(card);
62162306a36Sopenharmony_ci		card->fe = dvb_attach(nxt6000_attach, &vp3021_alps_tded4_config, card->i2c_adapter);
62262306a36Sopenharmony_ci		if (card->fe != NULL) {
62362306a36Sopenharmony_ci			card->fe->ops.tuner_ops.set_params = vp3021_alps_tded4_tuner_set_params;
62462306a36Sopenharmony_ci			dprintk("dvb_bt8xx: an nxt6000 was detected on your digitv card\n");
62562306a36Sopenharmony_ci			break;
62662306a36Sopenharmony_ci		}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci		/* New Nebula (marked (c)2005 on low profile pci card) has mt352 demod */
62962306a36Sopenharmony_ci		digitv_alps_tded4_reset(card);
63062306a36Sopenharmony_ci		card->fe = dvb_attach(mt352_attach, &digitv_alps_tded4_config, card->i2c_adapter);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci		if (card->fe != NULL) {
63362306a36Sopenharmony_ci			card->fe->ops.tuner_ops.calc_regs = digitv_alps_tded4_tuner_calc_regs;
63462306a36Sopenharmony_ci			dprintk("dvb_bt8xx: an mt352 was detected on your digitv card\n");
63562306a36Sopenharmony_ci		}
63662306a36Sopenharmony_ci		break;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	case BTTV_BOARD_AVDVBT_761:
63962306a36Sopenharmony_ci		card->fe = dvb_attach(sp887x_attach, &microtune_mt7202dtf_config, card->i2c_adapter);
64062306a36Sopenharmony_ci		if (card->fe) {
64162306a36Sopenharmony_ci			card->fe->ops.tuner_ops.set_params = microtune_mt7202dtf_tuner_set_params;
64262306a36Sopenharmony_ci		}
64362306a36Sopenharmony_ci		break;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	case BTTV_BOARD_AVDVBT_771:
64662306a36Sopenharmony_ci		card->fe = dvb_attach(mt352_attach, &advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter);
64762306a36Sopenharmony_ci		if (card->fe != NULL) {
64862306a36Sopenharmony_ci			card->fe->ops.tuner_ops.calc_regs = advbt771_samsung_tdtc9251dh0_tuner_calc_regs;
64962306a36Sopenharmony_ci			card->fe->ops.info.frequency_min_hz = 174 * MHz;
65062306a36Sopenharmony_ci			card->fe->ops.info.frequency_max_hz = 862 * MHz;
65162306a36Sopenharmony_ci		}
65262306a36Sopenharmony_ci		break;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	case BTTV_BOARD_TWINHAN_DST:
65562306a36Sopenharmony_ci		/*	DST is not a frontend driver !!!		*/
65662306a36Sopenharmony_ci		state = kmalloc(sizeof (struct dst_state), GFP_KERNEL);
65762306a36Sopenharmony_ci		if (!state) {
65862306a36Sopenharmony_ci			pr_err("No memory\n");
65962306a36Sopenharmony_ci			break;
66062306a36Sopenharmony_ci		}
66162306a36Sopenharmony_ci		/*	Setup the Card					*/
66262306a36Sopenharmony_ci		state->config = &dst_config;
66362306a36Sopenharmony_ci		state->i2c = card->i2c_adapter;
66462306a36Sopenharmony_ci		state->bt = card->bt;
66562306a36Sopenharmony_ci		state->dst_ca = NULL;
66662306a36Sopenharmony_ci		/*	DST is not a frontend, attaching the ASIC	*/
66762306a36Sopenharmony_ci		if (dvb_attach(dst_attach, state, &card->dvb_adapter) == NULL) {
66862306a36Sopenharmony_ci			pr_err("%s: Could not find a Twinhan DST\n", __func__);
66962306a36Sopenharmony_ci			kfree(state);
67062306a36Sopenharmony_ci			break;
67162306a36Sopenharmony_ci		}
67262306a36Sopenharmony_ci		/*	Attach other DST peripherals if any		*/
67362306a36Sopenharmony_ci		/*	Conditional Access device			*/
67462306a36Sopenharmony_ci		card->fe = &state->frontend;
67562306a36Sopenharmony_ci		if (state->dst_hw_cap & DST_TYPE_HAS_CA)
67662306a36Sopenharmony_ci			dvb_attach(dst_ca_attach, state, &card->dvb_adapter);
67762306a36Sopenharmony_ci		break;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	case BTTV_BOARD_PINNACLESAT:
68062306a36Sopenharmony_ci		card->fe = dvb_attach(cx24110_attach, &pctvsat_config, card->i2c_adapter);
68162306a36Sopenharmony_ci		if (card->fe) {
68262306a36Sopenharmony_ci			card->fe->ops.tuner_ops.init = pinnsat_tuner_init;
68362306a36Sopenharmony_ci			card->fe->ops.tuner_ops.sleep = pinnsat_tuner_sleep;
68462306a36Sopenharmony_ci			card->fe->ops.tuner_ops.set_params = cx24108_tuner_set_params;
68562306a36Sopenharmony_ci		}
68662306a36Sopenharmony_ci		break;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	case BTTV_BOARD_PC_HDTV:
68962306a36Sopenharmony_ci		card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter);
69062306a36Sopenharmony_ci		if (card->fe != NULL)
69162306a36Sopenharmony_ci			dvb_attach(simple_tuner_attach, card->fe,
69262306a36Sopenharmony_ci				   card->i2c_adapter, 0x61,
69362306a36Sopenharmony_ci				   TUNER_PHILIPS_FCV1236D);
69462306a36Sopenharmony_ci		break;
69562306a36Sopenharmony_ci	}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	if (card->fe == NULL)
69862306a36Sopenharmony_ci		pr_err("A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
69962306a36Sopenharmony_ci		       card->bt->dev->vendor,
70062306a36Sopenharmony_ci		       card->bt->dev->device,
70162306a36Sopenharmony_ci		       card->bt->dev->subsystem_vendor,
70262306a36Sopenharmony_ci		       card->bt->dev->subsystem_device);
70362306a36Sopenharmony_ci	else
70462306a36Sopenharmony_ci		if (dvb_register_frontend(&card->dvb_adapter, card->fe)) {
70562306a36Sopenharmony_ci			pr_err("Frontend registration failed!\n");
70662306a36Sopenharmony_ci			dvb_frontend_detach(card->fe);
70762306a36Sopenharmony_ci			card->fe = NULL;
70862306a36Sopenharmony_ci		}
70962306a36Sopenharmony_ci}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_cistatic int dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
71262306a36Sopenharmony_ci{
71362306a36Sopenharmony_ci	int result;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	result = dvb_register_adapter(&card->dvb_adapter, card->card_name,
71662306a36Sopenharmony_ci				      THIS_MODULE, &card->bt->dev->dev,
71762306a36Sopenharmony_ci				      adapter_nr);
71862306a36Sopenharmony_ci	if (result < 0) {
71962306a36Sopenharmony_ci		pr_err("dvb_register_adapter failed (errno = %d)\n", result);
72062306a36Sopenharmony_ci		return result;
72162306a36Sopenharmony_ci	}
72262306a36Sopenharmony_ci	card->dvb_adapter.priv = card;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	card->bt->adapter = card->i2c_adapter;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	memset(&card->demux, 0, sizeof(struct dvb_demux));
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	card->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	card->demux.priv = card;
73162306a36Sopenharmony_ci	card->demux.filternum = 256;
73262306a36Sopenharmony_ci	card->demux.feednum = 256;
73362306a36Sopenharmony_ci	card->demux.start_feed = dvb_bt8xx_start_feed;
73462306a36Sopenharmony_ci	card->demux.stop_feed = dvb_bt8xx_stop_feed;
73562306a36Sopenharmony_ci	card->demux.write_to_decoder = NULL;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	result = dvb_dmx_init(&card->demux);
73862306a36Sopenharmony_ci	if (result < 0) {
73962306a36Sopenharmony_ci		pr_err("dvb_dmx_init failed (errno = %d)\n", result);
74062306a36Sopenharmony_ci		goto err_unregister_adaptor;
74162306a36Sopenharmony_ci	}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	card->dmxdev.filternum = 256;
74462306a36Sopenharmony_ci	card->dmxdev.demux = &card->demux.dmx;
74562306a36Sopenharmony_ci	card->dmxdev.capabilities = 0;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	result = dvb_dmxdev_init(&card->dmxdev, &card->dvb_adapter);
74862306a36Sopenharmony_ci	if (result < 0) {
74962306a36Sopenharmony_ci		pr_err("dvb_dmxdev_init failed (errno = %d)\n", result);
75062306a36Sopenharmony_ci		goto err_dmx_release;
75162306a36Sopenharmony_ci	}
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	card->fe_hw.source = DMX_FRONTEND_0;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_hw);
75662306a36Sopenharmony_ci	if (result < 0) {
75762306a36Sopenharmony_ci		pr_err("dvb_dmx_init failed (errno = %d)\n", result);
75862306a36Sopenharmony_ci		goto err_dmxdev_release;
75962306a36Sopenharmony_ci	}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	card->fe_mem.source = DMX_MEMORY_FE;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_mem);
76462306a36Sopenharmony_ci	if (result < 0) {
76562306a36Sopenharmony_ci		pr_err("dvb_dmx_init failed (errno = %d)\n", result);
76662306a36Sopenharmony_ci		goto err_remove_hw_frontend;
76762306a36Sopenharmony_ci	}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	result = card->demux.dmx.connect_frontend(&card->demux.dmx, &card->fe_hw);
77062306a36Sopenharmony_ci	if (result < 0) {
77162306a36Sopenharmony_ci		pr_err("dvb_dmx_init failed (errno = %d)\n", result);
77262306a36Sopenharmony_ci		goto err_remove_mem_frontend;
77362306a36Sopenharmony_ci	}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	result = dvb_net_init(&card->dvb_adapter, &card->dvbnet, &card->demux.dmx);
77662306a36Sopenharmony_ci	if (result < 0) {
77762306a36Sopenharmony_ci		pr_err("dvb_net_init failed (errno = %d)\n", result);
77862306a36Sopenharmony_ci		goto err_disconnect_frontend;
77962306a36Sopenharmony_ci	}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	tasklet_setup(&card->bt->tasklet, dvb_bt8xx_task);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	frontend_init(card, type);
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	return 0;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_cierr_disconnect_frontend:
78862306a36Sopenharmony_ci	card->demux.dmx.disconnect_frontend(&card->demux.dmx);
78962306a36Sopenharmony_cierr_remove_mem_frontend:
79062306a36Sopenharmony_ci	card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem);
79162306a36Sopenharmony_cierr_remove_hw_frontend:
79262306a36Sopenharmony_ci	card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
79362306a36Sopenharmony_cierr_dmxdev_release:
79462306a36Sopenharmony_ci	dvb_dmxdev_release(&card->dmxdev);
79562306a36Sopenharmony_cierr_dmx_release:
79662306a36Sopenharmony_ci	dvb_dmx_release(&card->demux);
79762306a36Sopenharmony_cierr_unregister_adaptor:
79862306a36Sopenharmony_ci	dvb_unregister_adapter(&card->dvb_adapter);
79962306a36Sopenharmony_ci	return result;
80062306a36Sopenharmony_ci}
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_cistatic int dvb_bt8xx_probe(struct bttv_sub_device *sub)
80362306a36Sopenharmony_ci{
80462306a36Sopenharmony_ci	struct dvb_bt8xx_card *card;
80562306a36Sopenharmony_ci	struct pci_dev* bttv_pci_dev;
80662306a36Sopenharmony_ci	int ret;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	if (!(card = kzalloc(sizeof(struct dvb_bt8xx_card), GFP_KERNEL)))
80962306a36Sopenharmony_ci		return -ENOMEM;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	mutex_init(&card->lock);
81262306a36Sopenharmony_ci	card->bttv_nr = sub->core->nr;
81362306a36Sopenharmony_ci	strscpy(card->card_name, sub->core->v4l2_dev.name,
81462306a36Sopenharmony_ci		sizeof(card->card_name));
81562306a36Sopenharmony_ci	card->i2c_adapter = &sub->core->i2c_adap;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	switch(sub->core->type) {
81862306a36Sopenharmony_ci	case BTTV_BOARD_PINNACLESAT:
81962306a36Sopenharmony_ci		card->gpio_mode = 0x0400c060;
82062306a36Sopenharmony_ci		/* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR,
82162306a36Sopenharmony_ci			      BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */
82262306a36Sopenharmony_ci		card->op_sync_orin = BT878_RISC_SYNC_MASK;
82362306a36Sopenharmony_ci		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
82462306a36Sopenharmony_ci		break;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	case BTTV_BOARD_DVICO_DVBT_LITE:
82762306a36Sopenharmony_ci		card->gpio_mode = 0x0400C060;
82862306a36Sopenharmony_ci		card->op_sync_orin = BT878_RISC_SYNC_MASK;
82962306a36Sopenharmony_ci		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
83062306a36Sopenharmony_ci		/* 26, 15, 14, 6, 5
83162306a36Sopenharmony_ci		 * A_PWRDN  DA_DPM DA_SBR DA_IOM_DA
83262306a36Sopenharmony_ci		 * DA_APP(parallel) */
83362306a36Sopenharmony_ci		break;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
83662306a36Sopenharmony_ci		card->gpio_mode = 0x0400c060;
83762306a36Sopenharmony_ci		card->op_sync_orin = BT878_RISC_SYNC_MASK;
83862306a36Sopenharmony_ci		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
83962306a36Sopenharmony_ci		break;
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	case BTTV_BOARD_NEBULA_DIGITV:
84262306a36Sopenharmony_ci	case BTTV_BOARD_AVDVBT_761:
84362306a36Sopenharmony_ci		card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5);
84462306a36Sopenharmony_ci		card->op_sync_orin = BT878_RISC_SYNC_MASK;
84562306a36Sopenharmony_ci		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
84662306a36Sopenharmony_ci		/* A_PWRDN DA_SBR DA_APP (high speed serial) */
84762306a36Sopenharmony_ci		break;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	case BTTV_BOARD_AVDVBT_771: //case 0x07711461:
85062306a36Sopenharmony_ci		card->gpio_mode = 0x0400402B;
85162306a36Sopenharmony_ci		card->op_sync_orin = BT878_RISC_SYNC_MASK;
85262306a36Sopenharmony_ci		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
85362306a36Sopenharmony_ci		/* A_PWRDN DA_SBR  DA_APP[0] PKTP=10 RISC_ENABLE FIFO_ENABLE*/
85462306a36Sopenharmony_ci		break;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	case BTTV_BOARD_TWINHAN_DST:
85762306a36Sopenharmony_ci		card->gpio_mode = 0x2204f2c;
85862306a36Sopenharmony_ci		card->op_sync_orin = BT878_RISC_SYNC_MASK;
85962306a36Sopenharmony_ci		card->irq_err_ignore = BT878_APABORT | BT878_ARIPERR |
86062306a36Sopenharmony_ci				       BT878_APPERR | BT878_AFBUS;
86162306a36Sopenharmony_ci		/* 25,21,14,11,10,9,8,3,2 then
86262306a36Sopenharmony_ci		 * 0x33 = 5,4,1,0
86362306a36Sopenharmony_ci		 * A_SEL=SML, DA_MLB, DA_SBR,
86462306a36Sopenharmony_ci		 * DA_SDR=f, fifo trigger = 32 DWORDS
86562306a36Sopenharmony_ci		 * IOM = 0 == audio A/D
86662306a36Sopenharmony_ci		 * DPM = 0 == digital audio mode
86762306a36Sopenharmony_ci		 * == async data parallel port
86862306a36Sopenharmony_ci		 * then 0x33 (13 is set by start_capture)
86962306a36Sopenharmony_ci		 * DA_APP = async data parallel port,
87062306a36Sopenharmony_ci		 * ACAP_EN = 1,
87162306a36Sopenharmony_ci		 * RISC+FIFO ENABLE */
87262306a36Sopenharmony_ci		break;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	case BTTV_BOARD_PC_HDTV:
87562306a36Sopenharmony_ci		card->gpio_mode = 0x0100EC7B;
87662306a36Sopenharmony_ci		card->op_sync_orin = BT878_RISC_SYNC_MASK;
87762306a36Sopenharmony_ci		card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR;
87862306a36Sopenharmony_ci		break;
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	default:
88162306a36Sopenharmony_ci		pr_err("Unknown bttv card type: %d\n", sub->core->type);
88262306a36Sopenharmony_ci		kfree(card);
88362306a36Sopenharmony_ci		return -ENODEV;
88462306a36Sopenharmony_ci	}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	dprintk("dvb_bt8xx: identified card%d as %s\n", card->bttv_nr, card->card_name);
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	if (!(bttv_pci_dev = bttv_get_pcidev(card->bttv_nr))) {
88962306a36Sopenharmony_ci		pr_err("no pci device for card %d\n", card->bttv_nr);
89062306a36Sopenharmony_ci		kfree(card);
89162306a36Sopenharmony_ci		return -ENODEV;
89262306a36Sopenharmony_ci	}
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	if (!(card->bt = dvb_bt8xx_878_match(card->bttv_nr, bttv_pci_dev))) {
89562306a36Sopenharmony_ci		pr_err("unable to determine DMA core of card %d,\n", card->bttv_nr);
89662306a36Sopenharmony_ci		pr_err("if you have the ALSA bt87x audio driver installed, try removing it.\n");
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci		kfree(card);
89962306a36Sopenharmony_ci		return -ENODEV;
90062306a36Sopenharmony_ci	}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	mutex_init(&card->bt->gpio_lock);
90362306a36Sopenharmony_ci	card->bt->bttv_nr = sub->core->nr;
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	if ( (ret = dvb_bt8xx_load_card(card, sub->core->type)) ) {
90662306a36Sopenharmony_ci		kfree(card);
90762306a36Sopenharmony_ci		return ret;
90862306a36Sopenharmony_ci	}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	dev_set_drvdata(&sub->dev, card);
91162306a36Sopenharmony_ci	return 0;
91262306a36Sopenharmony_ci}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_cistatic void dvb_bt8xx_remove(struct bttv_sub_device *sub)
91562306a36Sopenharmony_ci{
91662306a36Sopenharmony_ci	struct dvb_bt8xx_card *card = dev_get_drvdata(&sub->dev);
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr);
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	bt878_stop(card->bt);
92162306a36Sopenharmony_ci	tasklet_kill(&card->bt->tasklet);
92262306a36Sopenharmony_ci	dvb_net_release(&card->dvbnet);
92362306a36Sopenharmony_ci	card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem);
92462306a36Sopenharmony_ci	card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
92562306a36Sopenharmony_ci	dvb_dmxdev_release(&card->dmxdev);
92662306a36Sopenharmony_ci	dvb_dmx_release(&card->demux);
92762306a36Sopenharmony_ci	if (card->fe) {
92862306a36Sopenharmony_ci		dvb_unregister_frontend(card->fe);
92962306a36Sopenharmony_ci		dvb_frontend_detach(card->fe);
93062306a36Sopenharmony_ci	}
93162306a36Sopenharmony_ci	dvb_unregister_adapter(&card->dvb_adapter);
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	kfree(card);
93462306a36Sopenharmony_ci}
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_cistatic struct bttv_sub_driver driver = {
93762306a36Sopenharmony_ci	.drv = {
93862306a36Sopenharmony_ci		.name		= "dvb-bt8xx",
93962306a36Sopenharmony_ci	},
94062306a36Sopenharmony_ci	.probe		= dvb_bt8xx_probe,
94162306a36Sopenharmony_ci	.remove		= dvb_bt8xx_remove,
94262306a36Sopenharmony_ci	/* FIXME:
94362306a36Sopenharmony_ci	 * .shutdown	= dvb_bt8xx_shutdown,
94462306a36Sopenharmony_ci	 * .suspend	= dvb_bt8xx_suspend,
94562306a36Sopenharmony_ci	 * .resume	= dvb_bt8xx_resume,
94662306a36Sopenharmony_ci	 */
94762306a36Sopenharmony_ci};
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_cistatic int __init dvb_bt8xx_init(void)
95062306a36Sopenharmony_ci{
95162306a36Sopenharmony_ci	return bttv_sub_register(&driver, "dvb");
95262306a36Sopenharmony_ci}
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_cistatic void __exit dvb_bt8xx_exit(void)
95562306a36Sopenharmony_ci{
95662306a36Sopenharmony_ci	bttv_sub_unregister(&driver);
95762306a36Sopenharmony_ci}
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_cimodule_init(dvb_bt8xx_init);
96062306a36Sopenharmony_cimodule_exit(dvb_bt8xx_exit);
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ciMODULE_DESCRIPTION("Bt8xx based DVB adapter driver");
96362306a36Sopenharmony_ciMODULE_AUTHOR("Florian Schirmer <jolt@tuxbox.org>");
96462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
965