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, µtune_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