xref: /linux/drivers/media/pci/cx88/cx88-dvb.c (revision 00ae4ebc2d07db50d8432ebec3158c96b36f1a6d)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * device driver for Conexant 2388x based TV cards
41da177e4SLinus Torvalds  * MPEG Transport Stream (DVB) routines
51da177e4SLinus Torvalds  *
6fc40b261SChris Pascoe  * (c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
71da177e4SLinus Torvalds  * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
81da177e4SLinus Torvalds  */
91da177e4SLinus Torvalds 
1065bc2fe8SMauro Carvalho Chehab #include "cx88.h"
1165bc2fe8SMauro Carvalho Chehab #include "dvb-pll.h"
1265bc2fe8SMauro Carvalho Chehab 
131da177e4SLinus Torvalds #include <linux/module.h>
141da177e4SLinus Torvalds #include <linux/init.h>
151da177e4SLinus Torvalds #include <linux/device.h>
161da177e4SLinus Torvalds #include <linux/fs.h>
171da177e4SLinus Torvalds #include <linux/kthread.h>
181da177e4SLinus Torvalds #include <linux/file.h>
191da177e4SLinus Torvalds #include <linux/suspend.h>
201da177e4SLinus Torvalds 
215e453dc7SMichael Krufky #include <media/v4l2-common.h>
2241ef7c1eSMauro Carvalho Chehab 
231da177e4SLinus Torvalds #include "mt352.h"
241da177e4SLinus Torvalds #include "mt352_priv.h"
25fc40b261SChris Pascoe #include "cx88-vp3054-i2c.h"
26780dfef3SChris Pascoe #include "zl10353.h"
271da177e4SLinus Torvalds #include "cx22702.h"
281da177e4SLinus Torvalds #include "or51132.h"
296ddcc919SMichael Krufky #include "lgdt330x.h"
3060464da8SSteven Toth #include "s5h1409.h"
31c21973e8Sistvan_v@mailbox.hu #include "xc4000.h"
3260464da8SSteven Toth #include "xc5000.h"
33fde6d31eSKirk Lapray #include "nxt200x.h"
340fa14aa6SSteven Toth #include "cx24123.h"
35cd20ca9fSAndrew de Quincey #include "isl6421.h"
360df31f83SMichael Krufky #include "tuner-simple.h"
37827855d3SMichael Krufky #include "tda9887.h"
38d893d5dcSSteven Toth #include "s5h1411.h"
39e4aab64cSIgor M. Liplianin #include "stv0299.h"
40e4aab64cSIgor M. Liplianin #include "z0194a.h"
41e4aab64cSIgor M. Liplianin #include "stv0288.h"
42e4aab64cSIgor M. Liplianin #include "stb6000.h"
435bd1b663SSteven Toth #include "cx24116.h"
44b699c271SIgor M. Liplianin #include "stv0900.h"
45b699c271SIgor M. Liplianin #include "stb6100.h"
46b699c271SIgor M. Liplianin #include "stb6100_proc.h"
47111ac84aSSergey Ivanov #include "mb86a16.h"
4873f0af44SKonstantin Dimitrov #include "ts2020.h"
490cb73639SIgor M. Liplianin #include "ds3000.h"
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
521da177e4SLinus Torvalds MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
531da177e4SLinus Torvalds MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
541da177e4SLinus Torvalds MODULE_LICENSE("GPL");
551990d50bSMauro Carvalho Chehab MODULE_VERSION(CX88_VERSION);
561da177e4SLinus Torvalds 
57ff699e6bSDouglas Schilling Landgraf static unsigned int debug;
581da177e4SLinus Torvalds module_param(debug, int, 0644);
591da177e4SLinus Torvalds MODULE_PARM_DESC(debug, "enable debug messages [dvb]");
601da177e4SLinus Torvalds 
6144c6e2a7SAng Way Chuang static unsigned int dvb_buf_tscnt = 32;
6244c6e2a7SAng Way Chuang module_param(dvb_buf_tscnt, int, 0644);
6344c6e2a7SAng Way Chuang MODULE_PARM_DESC(dvb_buf_tscnt, "DVB Buffer TS count [dvb]");
6444c6e2a7SAng Way Chuang 
6578e92006SJanne Grunau DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
6678e92006SJanne Grunau 
6765bc2fe8SMauro Carvalho Chehab #define dprintk(level, fmt, arg...) do {				\
6865bc2fe8SMauro Carvalho Chehab 	if (debug >= level)						\
6965bc2fe8SMauro Carvalho Chehab 		printk(KERN_DEBUG pr_fmt("%s: dvb:" fmt),		\
7065bc2fe8SMauro Carvalho Chehab 			__func__, ##arg);				\
7165bc2fe8SMauro Carvalho Chehab } while (0)
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds /* ------------------------------------------------------------------ */
741da177e4SLinus Torvalds 
75df9ecb0cSHans Verkuil static int queue_setup(struct vb2_queue *q,
760b6b6302SHans Verkuil 		       unsigned int *num_buffers, unsigned int *num_planes,
7736c0f8b3SHans Verkuil 		       unsigned int sizes[], struct device *alloc_devs[])
781da177e4SLinus Torvalds {
790b6b6302SHans Verkuil 	struct cx8802_dev *dev = q->drv_priv;
801da177e4SLinus Torvalds 
810b6b6302SHans Verkuil 	*num_planes = 1;
821da177e4SLinus Torvalds 	dev->ts_packet_size  = 188 * 4;
8344c6e2a7SAng Way Chuang 	dev->ts_packet_count = dvb_buf_tscnt;
840b6b6302SHans Verkuil 	sizes[0] = dev->ts_packet_size * dev->ts_packet_count;
850b6b6302SHans Verkuil 	*num_buffers = dvb_buf_tscnt;
861da177e4SLinus Torvalds 	return 0;
871da177e4SLinus Torvalds }
881da177e4SLinus Torvalds 
890b6b6302SHans Verkuil static int buffer_prepare(struct vb2_buffer *vb)
901da177e4SLinus Torvalds {
912d700715SJunghak Sung 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
920b6b6302SHans Verkuil 	struct cx8802_dev *dev = vb->vb2_queue->drv_priv;
932d700715SJunghak Sung 	struct cx88_buffer *buf = container_of(vbuf, struct cx88_buffer, vb);
940b6b6302SHans Verkuil 
95ccd6f1d4SHans Verkuil 	return cx8802_buf_prepare(vb->vb2_queue, dev, buf);
961da177e4SLinus Torvalds }
971da177e4SLinus Torvalds 
980b6b6302SHans Verkuil static void buffer_finish(struct vb2_buffer *vb)
991da177e4SLinus Torvalds {
1002d700715SJunghak Sung 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1010b6b6302SHans Verkuil 	struct cx8802_dev *dev = vb->vb2_queue->drv_priv;
1022d700715SJunghak Sung 	struct cx88_buffer *buf = container_of(vbuf, struct cx88_buffer, vb);
1035e7045e3SHans Verkuil 	struct cx88_riscmem *risc = &buf->risc;
1040b6b6302SHans Verkuil 
1055e7045e3SHans Verkuil 	if (risc->cpu)
10600ae4ebcSChristophe JAILLET 		dma_free_coherent(&dev->pci->dev, risc->size, risc->cpu,
10700ae4ebcSChristophe JAILLET 				  risc->dma);
1085e7045e3SHans Verkuil 	memset(risc, 0, sizeof(*risc));
1091da177e4SLinus Torvalds }
1101da177e4SLinus Torvalds 
1110b6b6302SHans Verkuil static void buffer_queue(struct vb2_buffer *vb)
1121da177e4SLinus Torvalds {
1132d700715SJunghak Sung 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1140b6b6302SHans Verkuil 	struct cx8802_dev *dev = vb->vb2_queue->drv_priv;
1152d700715SJunghak Sung 	struct cx88_buffer    *buf = container_of(vbuf, struct cx88_buffer, vb);
1160b6b6302SHans Verkuil 
1170b6b6302SHans Verkuil 	cx8802_buf_queue(dev, buf);
1181da177e4SLinus Torvalds }
1191da177e4SLinus Torvalds 
1200b6b6302SHans Verkuil static int start_streaming(struct vb2_queue *q, unsigned int count)
1210b6b6302SHans Verkuil {
1220b6b6302SHans Verkuil 	struct cx8802_dev *dev = q->drv_priv;
1230b6b6302SHans Verkuil 	struct cx88_dmaqueue *dmaq = &dev->mpegq;
1240b6b6302SHans Verkuil 	struct cx88_buffer *buf;
1250b6b6302SHans Verkuil 
1260b6b6302SHans Verkuil 	buf = list_entry(dmaq->active.next, struct cx88_buffer, list);
1270b6b6302SHans Verkuil 	cx8802_start_dma(dev, dmaq, buf);
1280b6b6302SHans Verkuil 	return 0;
1290b6b6302SHans Verkuil }
1300b6b6302SHans Verkuil 
1310b6b6302SHans Verkuil static void stop_streaming(struct vb2_queue *q)
1320b6b6302SHans Verkuil {
1330b6b6302SHans Verkuil 	struct cx8802_dev *dev = q->drv_priv;
1340b6b6302SHans Verkuil 	struct cx88_dmaqueue *dmaq = &dev->mpegq;
1350b6b6302SHans Verkuil 	unsigned long flags;
1360b6b6302SHans Verkuil 
1370b6b6302SHans Verkuil 	cx8802_cancel_buffers(dev);
1380b6b6302SHans Verkuil 
1390b6b6302SHans Verkuil 	spin_lock_irqsave(&dev->slock, flags);
1400b6b6302SHans Verkuil 	while (!list_empty(&dmaq->active)) {
1410b6b6302SHans Verkuil 		struct cx88_buffer *buf = list_entry(dmaq->active.next,
1420b6b6302SHans Verkuil 			struct cx88_buffer, list);
1430b6b6302SHans Verkuil 
1440b6b6302SHans Verkuil 		list_del(&buf->list);
1452d700715SJunghak Sung 		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
1460b6b6302SHans Verkuil 	}
1470b6b6302SHans Verkuil 	spin_unlock_irqrestore(&dev->slock, flags);
1480b6b6302SHans Verkuil }
1490b6b6302SHans Verkuil 
15010accd2eSJulia Lawall static const struct vb2_ops dvb_qops = {
1510b6b6302SHans Verkuil 	.queue_setup    = queue_setup,
1520b6b6302SHans Verkuil 	.buf_prepare  = buffer_prepare,
1530b6b6302SHans Verkuil 	.buf_finish = buffer_finish,
1540b6b6302SHans Verkuil 	.buf_queue    = buffer_queue,
1550b6b6302SHans Verkuil 	.wait_prepare = vb2_ops_wait_prepare,
1560b6b6302SHans Verkuil 	.wait_finish = vb2_ops_wait_finish,
1570b6b6302SHans Verkuil 	.start_streaming = start_streaming,
1580b6b6302SHans Verkuil 	.stop_streaming = stop_streaming,
1591da177e4SLinus Torvalds };
1601da177e4SLinus Torvalds 
1611da177e4SLinus Torvalds /* ------------------------------------------------------------------ */
16222f3f17dSMichael Krufky 
16322f3f17dSMichael Krufky static int cx88_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
16422f3f17dSMichael Krufky {
16522f3f17dSMichael Krufky 	struct cx8802_dev *dev = fe->dvb->priv;
16622f3f17dSMichael Krufky 	struct cx8802_driver *drv = NULL;
16722f3f17dSMichael Krufky 	int ret = 0;
168363c35fcSSteven Toth 	int fe_id;
169363c35fcSSteven Toth 
1700b6b6302SHans Verkuil 	fe_id = vb2_dvb_find_frontend(&dev->frontends, fe);
171363c35fcSSteven Toth 	if (!fe_id) {
17265bc2fe8SMauro Carvalho Chehab 		pr_err("%s() No frontend found\n", __func__);
173363c35fcSSteven Toth 		return -EINVAL;
174363c35fcSSteven Toth 	}
175363c35fcSSteven Toth 
1768a317a87SJonathan Nieder 	mutex_lock(&dev->core->lock);
17722f3f17dSMichael Krufky 	drv = cx8802_get_driver(dev, CX88_MPEG_DVB);
17822f3f17dSMichael Krufky 	if (drv) {
179363c35fcSSteven Toth 		if (acquire) {
180363c35fcSSteven Toth 			dev->frontends.active_fe_id = fe_id;
18122f3f17dSMichael Krufky 			ret = drv->request_acquire(drv);
182363c35fcSSteven Toth 		} else {
18322f3f17dSMichael Krufky 			ret = drv->request_release(drv);
184363c35fcSSteven Toth 			dev->frontends.active_fe_id = 0;
185363c35fcSSteven Toth 		}
18622f3f17dSMichael Krufky 	}
1871fe70e96SJonathan Nieder 	mutex_unlock(&dev->core->lock);
18822f3f17dSMichael Krufky 
18922f3f17dSMichael Krufky 	return ret;
19022f3f17dSMichael Krufky }
19122f3f17dSMichael Krufky 
192e32fadc4SMauro Carvalho Chehab static void cx88_dvb_gate_ctrl(struct cx88_core  *core, int open)
193e32fadc4SMauro Carvalho Chehab {
1940b6b6302SHans Verkuil 	struct vb2_dvb_frontends *f;
1950b6b6302SHans Verkuil 	struct vb2_dvb_frontend *fe;
196e32fadc4SMauro Carvalho Chehab 
197e32fadc4SMauro Carvalho Chehab 	if (!core->dvbdev)
198e32fadc4SMauro Carvalho Chehab 		return;
199e32fadc4SMauro Carvalho Chehab 
200e32fadc4SMauro Carvalho Chehab 	f = &core->dvbdev->frontends;
201e32fadc4SMauro Carvalho Chehab 
202e32fadc4SMauro Carvalho Chehab 	if (!f)
203e32fadc4SMauro Carvalho Chehab 		return;
204e32fadc4SMauro Carvalho Chehab 
205e32fadc4SMauro Carvalho Chehab 	if (f->gate <= 1) /* undefined or fe0 */
2060b6b6302SHans Verkuil 		fe = vb2_dvb_get_frontend(f, 1);
207e32fadc4SMauro Carvalho Chehab 	else
2080b6b6302SHans Verkuil 		fe = vb2_dvb_get_frontend(f, f->gate);
209e32fadc4SMauro Carvalho Chehab 
210e32fadc4SMauro Carvalho Chehab 	if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl)
211e32fadc4SMauro Carvalho Chehab 		fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open);
212e32fadc4SMauro Carvalho Chehab }
213e32fadc4SMauro Carvalho Chehab 
21422f3f17dSMichael Krufky /* ------------------------------------------------------------------ */
21522f3f17dSMichael Krufky 
2163d7d027aSChris Pascoe static int dvico_fusionhdtv_demod_init(struct dvb_frontend *fe)
2171da177e4SLinus Torvalds {
2182e4e98e7Slawrence rust 	static const u8 clock_config[]  = { CLOCK_CTL,  0x38, 0x39 };
2192e4e98e7Slawrence rust 	static const u8 reset[]         = { RESET,      0x80 };
2202e4e98e7Slawrence rust 	static const u8 adc_ctl_1_cfg[] = { ADC_CTL_1,  0x40 };
2212e4e98e7Slawrence rust 	static const u8 agc_cfg[]       = { AGC_TARGET, 0x24, 0x20 };
2222e4e98e7Slawrence rust 	static const u8 gpp_ctl_cfg[]   = { GPP_CTL,    0x33 };
2232e4e98e7Slawrence rust 	static const u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
2241da177e4SLinus Torvalds 
2251da177e4SLinus Torvalds 	mt352_write(fe, clock_config,   sizeof(clock_config));
2261da177e4SLinus Torvalds 	udelay(200);
2271da177e4SLinus Torvalds 	mt352_write(fe, reset,          sizeof(reset));
2281da177e4SLinus Torvalds 	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
2291da177e4SLinus Torvalds 
2301da177e4SLinus Torvalds 	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
2311da177e4SLinus Torvalds 	mt352_write(fe, gpp_ctl_cfg,    sizeof(gpp_ctl_cfg));
2321da177e4SLinus Torvalds 	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
2331da177e4SLinus Torvalds 	return 0;
2341da177e4SLinus Torvalds }
2351da177e4SLinus Torvalds 
23643eabb4eSChris Pascoe static int dvico_dual_demod_init(struct dvb_frontend *fe)
23743eabb4eSChris Pascoe {
2382e4e98e7Slawrence rust 	static const u8 clock_config[]  = { CLOCK_CTL,  0x38, 0x38 };
2392e4e98e7Slawrence rust 	static const u8 reset[]         = { RESET,      0x80 };
2402e4e98e7Slawrence rust 	static const u8 adc_ctl_1_cfg[] = { ADC_CTL_1,  0x40 };
2412e4e98e7Slawrence rust 	static const u8 agc_cfg[]       = { AGC_TARGET, 0x28, 0x20 };
2422e4e98e7Slawrence rust 	static const u8 gpp_ctl_cfg[]   = { GPP_CTL,    0x33 };
2432e4e98e7Slawrence rust 	static const u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
24443eabb4eSChris Pascoe 
24543eabb4eSChris Pascoe 	mt352_write(fe, clock_config,   sizeof(clock_config));
24643eabb4eSChris Pascoe 	udelay(200);
24743eabb4eSChris Pascoe 	mt352_write(fe, reset,          sizeof(reset));
24843eabb4eSChris Pascoe 	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
24943eabb4eSChris Pascoe 
25043eabb4eSChris Pascoe 	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
25143eabb4eSChris Pascoe 	mt352_write(fe, gpp_ctl_cfg,    sizeof(gpp_ctl_cfg));
25243eabb4eSChris Pascoe 	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
25343eabb4eSChris Pascoe 
25443eabb4eSChris Pascoe 	return 0;
25543eabb4eSChris Pascoe }
25643eabb4eSChris Pascoe 
2571da177e4SLinus Torvalds static int dntv_live_dvbt_demod_init(struct dvb_frontend *fe)
2581da177e4SLinus Torvalds {
2592e4e98e7Slawrence rust 	static const u8 clock_config[]  = { 0x89, 0x38, 0x39 };
2602e4e98e7Slawrence rust 	static const u8 reset[]         = { 0x50, 0x80 };
2612e4e98e7Slawrence rust 	static const u8 adc_ctl_1_cfg[] = { 0x8E, 0x40 };
2622e4e98e7Slawrence rust 	static const u8 agc_cfg[]       = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
2631da177e4SLinus Torvalds 				       0x00, 0xFF, 0x00, 0x40, 0x40 };
2642e4e98e7Slawrence rust 	static const u8 dntv_extra[]     = { 0xB5, 0x7A };
2652e4e98e7Slawrence rust 	static const u8 capt_range_cfg[] = { 0x75, 0x32 };
2661da177e4SLinus Torvalds 
2671da177e4SLinus Torvalds 	mt352_write(fe, clock_config,   sizeof(clock_config));
2681da177e4SLinus Torvalds 	udelay(2000);
2691da177e4SLinus Torvalds 	mt352_write(fe, reset,          sizeof(reset));
2701da177e4SLinus Torvalds 	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds 	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
2731da177e4SLinus Torvalds 	udelay(2000);
2741da177e4SLinus Torvalds 	mt352_write(fe, dntv_extra,     sizeof(dntv_extra));
2751da177e4SLinus Torvalds 	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
2761da177e4SLinus Torvalds 
2771da177e4SLinus Torvalds 	return 0;
2781da177e4SLinus Torvalds }
2791da177e4SLinus Torvalds 
2802e4e98e7Slawrence rust static const struct mt352_config dvico_fusionhdtv = {
281f7b54b10SMichael Krufky 	.demod_address = 0x0f,
2823d7d027aSChris Pascoe 	.demod_init    = dvico_fusionhdtv_demod_init,
2831da177e4SLinus Torvalds };
2841da177e4SLinus Torvalds 
2852e4e98e7Slawrence rust static const struct mt352_config dntv_live_dvbt_config = {
2861da177e4SLinus Torvalds 	.demod_address = 0x0f,
2871da177e4SLinus Torvalds 	.demod_init    = dntv_live_dvbt_demod_init,
2881da177e4SLinus Torvalds };
289fc40b261SChris Pascoe 
2902e4e98e7Slawrence rust static const struct mt352_config dvico_fusionhdtv_dual = {
291f7b54b10SMichael Krufky 	.demod_address = 0x0f,
29243eabb4eSChris Pascoe 	.demod_init    = dvico_dual_demod_init,
29343eabb4eSChris Pascoe };
29443eabb4eSChris Pascoe 
2952e4e98e7Slawrence rust static const struct zl10353_config cx88_terratec_cinergy_ht_pci_mkii_config = {
29670101a27SStephan Wienczny 	.demod_address = (0x1e >> 1),
29770101a27SStephan Wienczny 	.no_tuner      = 1,
29870101a27SStephan Wienczny 	.if2           = 45600,
29970101a27SStephan Wienczny };
30070101a27SStephan Wienczny 
3010244fd78SBhumika Goyal static const struct mb86a16_config twinhan_vp1027 = {
302111ac84aSSergey Ivanov 	.demod_address  = 0x08,
303111ac84aSSergey Ivanov };
304111ac84aSSergey Ivanov 
3057b34be71SPeter Senna Tschudin #if IS_ENABLED(CONFIG_VIDEO_CX88_VP3054)
3063d7d027aSChris Pascoe static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend *fe)
3073d7d027aSChris Pascoe {
3082e4e98e7Slawrence rust 	static const u8 clock_config[]  = { 0x89, 0x38, 0x38 };
3092e4e98e7Slawrence rust 	static const u8 reset[]         = { 0x50, 0x80 };
3102e4e98e7Slawrence rust 	static const u8 adc_ctl_1_cfg[] = { 0x8E, 0x40 };
3112e4e98e7Slawrence rust 	static const u8 agc_cfg[]       = { 0x67, 0x10, 0x20, 0x00, 0xFF, 0xFF,
3123d7d027aSChris Pascoe 				       0x00, 0xFF, 0x00, 0x40, 0x40 };
3132e4e98e7Slawrence rust 	static const u8 dntv_extra[]     = { 0xB5, 0x7A };
3142e4e98e7Slawrence rust 	static const u8 capt_range_cfg[] = { 0x75, 0x32 };
3153d7d027aSChris Pascoe 
3163d7d027aSChris Pascoe 	mt352_write(fe, clock_config,   sizeof(clock_config));
3173d7d027aSChris Pascoe 	udelay(2000);
3183d7d027aSChris Pascoe 	mt352_write(fe, reset,          sizeof(reset));
3193d7d027aSChris Pascoe 	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
3203d7d027aSChris Pascoe 
3213d7d027aSChris Pascoe 	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
3223d7d027aSChris Pascoe 	udelay(2000);
3233d7d027aSChris Pascoe 	mt352_write(fe, dntv_extra,     sizeof(dntv_extra));
3243d7d027aSChris Pascoe 	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
3253d7d027aSChris Pascoe 
3263d7d027aSChris Pascoe 	return 0;
3273d7d027aSChris Pascoe }
3283d7d027aSChris Pascoe 
3292e4e98e7Slawrence rust static const struct mt352_config dntv_live_dvbt_pro_config = {
330fc40b261SChris Pascoe 	.demod_address = 0x0f,
331fc40b261SChris Pascoe 	.no_tuner      = 1,
3323d7d027aSChris Pascoe 	.demod_init    = dntv_live_dvbt_pro_demod_init,
333fc40b261SChris Pascoe };
334fc40b261SChris Pascoe #endif
3351da177e4SLinus Torvalds 
3362e4e98e7Slawrence rust static const struct zl10353_config dvico_fusionhdtv_hybrid = {
337f7b54b10SMichael Krufky 	.demod_address = 0x0f,
338f54376e2SAndrew de Quincey 	.no_tuner      = 1,
339780dfef3SChris Pascoe };
340780dfef3SChris Pascoe 
3412e4e98e7Slawrence rust static const struct zl10353_config dvico_fusionhdtv_xc3028 = {
342b3fb91d2SChris Pascoe 	.demod_address = 0x0f,
343b3fb91d2SChris Pascoe 	.if2           = 45600,
344b3fb91d2SChris Pascoe 	.no_tuner      = 1,
345b3fb91d2SChris Pascoe };
346b3fb91d2SChris Pascoe 
3472e4e98e7Slawrence rust static const struct mt352_config dvico_fusionhdtv_mt352_xc3028 = {
348b3fb91d2SChris Pascoe 	.demod_address = 0x0f,
349b3fb91d2SChris Pascoe 	.if2 = 4560,
350b3fb91d2SChris Pascoe 	.no_tuner = 1,
351b3fb91d2SChris Pascoe 	.demod_init = dvico_fusionhdtv_demod_init,
352b3fb91d2SChris Pascoe };
353b3fb91d2SChris Pascoe 
3542e4e98e7Slawrence rust static const struct zl10353_config dvico_fusionhdtv_plus_v1_1 = {
355f7b54b10SMichael Krufky 	.demod_address = 0x0f,
356780dfef3SChris Pascoe };
357780dfef3SChris Pascoe 
3582e4e98e7Slawrence rust static const struct cx22702_config connexant_refboard_config = {
3591da177e4SLinus Torvalds 	.demod_address = 0x43,
36038d84c3bSPatrick Boettcher 	.output_mode   = CX22702_SERIAL_OUTPUT,
3611da177e4SLinus Torvalds };
3621da177e4SLinus Torvalds 
3632e4e98e7Slawrence rust static const struct cx22702_config hauppauge_hvr_config = {
364aa481a65SSteven Toth 	.demod_address = 0x63,
365aa481a65SSteven Toth 	.output_mode   = CX22702_SERIAL_OUTPUT,
366aa481a65SSteven Toth };
3671da177e4SLinus Torvalds 
3684a390558SMichael Krufky static int or51132_set_ts_param(struct dvb_frontend *fe, int is_punctured)
3691da177e4SLinus Torvalds {
3701da177e4SLinus Torvalds 	struct cx8802_dev *dev = fe->dvb->priv;
3717b61ba8fSMauro Carvalho Chehab 
3721da177e4SLinus Torvalds 	dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00;
3731da177e4SLinus Torvalds 	return 0;
3741da177e4SLinus Torvalds }
3751da177e4SLinus Torvalds 
3762e4e98e7Slawrence rust static const struct or51132_config pchdtv_hd3000 = {
3771da177e4SLinus Torvalds 	.demod_address = 0x15,
3781da177e4SLinus Torvalds 	.set_ts_params = or51132_set_ts_param,
3791da177e4SLinus Torvalds };
3801da177e4SLinus Torvalds 
3816ddcc919SMichael Krufky static int lgdt330x_pll_rf_set(struct dvb_frontend *fe, int index)
3820ccef6dbSMichael Krufky {
3830ccef6dbSMichael Krufky 	struct cx8802_dev *dev = fe->dvb->priv;
3840ccef6dbSMichael Krufky 	struct cx88_core *core = dev->core;
3850ccef6dbSMichael Krufky 
38632d83efcSHarvey Harrison 	dprintk(1, "%s: index = %d\n", __func__, index);
3870ccef6dbSMichael Krufky 	if (index == 0)
3880ccef6dbSMichael Krufky 		cx_clear(MO_GP0_IO, 8);
3890ccef6dbSMichael Krufky 	else
3900ccef6dbSMichael Krufky 		cx_set(MO_GP0_IO, 8);
3910ccef6dbSMichael Krufky 	return 0;
3920ccef6dbSMichael Krufky }
3930ccef6dbSMichael Krufky 
3946ddcc919SMichael Krufky static int lgdt330x_set_ts_param(struct dvb_frontend *fe, int is_punctured)
395f1798495SMichael Krufky {
396f1798495SMichael Krufky 	struct cx8802_dev *dev = fe->dvb->priv;
3977b61ba8fSMauro Carvalho Chehab 
398f1798495SMichael Krufky 	if (is_punctured)
399f1798495SMichael Krufky 		dev->ts_gen_cntrl |= 0x04;
400f1798495SMichael Krufky 	else
401f1798495SMichael Krufky 		dev->ts_gen_cntrl &= ~0x04;
402f1798495SMichael Krufky 	return 0;
403f1798495SMichael Krufky }
404f1798495SMichael Krufky 
4056ddcc919SMichael Krufky static struct lgdt330x_config fusionhdtv_3_gold = {
4061963c907SMichael Krufky 	.demod_chip    = LGDT3302,
4071963c907SMichael Krufky 	.serial_mpeg   = 0x04, /* TPSERIAL for 3302 in TOP_CONTROL */
4086ddcc919SMichael Krufky 	.set_ts_params = lgdt330x_set_ts_param,
4090d723c09SMichael Krufky };
410e52e98a7SMauro Carvalho Chehab 
4112e4e98e7Slawrence rust static const struct lgdt330x_config fusionhdtv_5_gold = {
412e52e98a7SMauro Carvalho Chehab 	.demod_chip    = LGDT3303,
413e52e98a7SMauro Carvalho Chehab 	.serial_mpeg   = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
414e52e98a7SMauro Carvalho Chehab 	.set_ts_params = lgdt330x_set_ts_param,
415e52e98a7SMauro Carvalho Chehab };
416da215d22SRusty Scott 
4172e4e98e7Slawrence rust static const struct lgdt330x_config pchdtv_hd5500 = {
418da215d22SRusty Scott 	.demod_chip    = LGDT3303,
419da215d22SRusty Scott 	.serial_mpeg   = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
420da215d22SRusty Scott 	.set_ts_params = lgdt330x_set_ts_param,
421da215d22SRusty Scott };
422f1798495SMichael Krufky 
4234a390558SMichael Krufky static int nxt200x_set_ts_param(struct dvb_frontend *fe, int is_punctured)
424fde6d31eSKirk Lapray {
425fde6d31eSKirk Lapray 	struct cx8802_dev *dev = fe->dvb->priv;
4267b61ba8fSMauro Carvalho Chehab 
427fde6d31eSKirk Lapray 	dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00;
428fde6d31eSKirk Lapray 	return 0;
429fde6d31eSKirk Lapray }
430fde6d31eSKirk Lapray 
4312e4e98e7Slawrence rust static const struct nxt200x_config ati_hdtvwonder = {
432fde6d31eSKirk Lapray 	.demod_address = 0x0a,
433fde6d31eSKirk Lapray 	.set_ts_params = nxt200x_set_ts_param,
434fde6d31eSKirk Lapray };
435fde6d31eSKirk Lapray 
4360fa14aa6SSteven Toth static int cx24123_set_ts_param(struct dvb_frontend *fe,
4370fa14aa6SSteven Toth 				int is_punctured)
4380fa14aa6SSteven Toth {
4390fa14aa6SSteven Toth 	struct cx8802_dev *dev = fe->dvb->priv;
4407b61ba8fSMauro Carvalho Chehab 
441f7b54b10SMichael Krufky 	dev->ts_gen_cntrl = 0x02;
4420fa14aa6SSteven Toth 	return 0;
4430fa14aa6SSteven Toth }
4440fa14aa6SSteven Toth 
445f7b54b10SMichael Krufky static int kworld_dvbs_100_set_voltage(struct dvb_frontend *fe,
4460df289a2SMauro Carvalho Chehab 				       enum fe_sec_voltage voltage)
4470e0351e3SVadim Catana {
4480e0351e3SVadim Catana 	struct cx8802_dev *dev = fe->dvb->priv;
4490e0351e3SVadim Catana 	struct cx88_core *core = dev->core;
4500e0351e3SVadim Catana 
4514a390558SMichael Krufky 	if (voltage == SEC_VOLTAGE_OFF)
452f7b54b10SMichael Krufky 		cx_write(MO_GP0_IO, 0x000006fb);
4534a390558SMichael Krufky 	else
454cd20ca9fSAndrew de Quincey 		cx_write(MO_GP0_IO, 0x000006f9);
455cd20ca9fSAndrew de Quincey 
456cd20ca9fSAndrew de Quincey 	if (core->prev_set_voltage)
457cd20ca9fSAndrew de Quincey 		return core->prev_set_voltage(fe, voltage);
458cd20ca9fSAndrew de Quincey 	return 0;
4590e0351e3SVadim Catana }
4600e0351e3SVadim Catana 
461f7b54b10SMichael Krufky static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe,
4620df289a2SMauro Carvalho Chehab 				      enum fe_sec_voltage voltage)
463c02a34f4SSaqeb Akhter {
464c02a34f4SSaqeb Akhter 	struct cx8802_dev *dev = fe->dvb->priv;
465c02a34f4SSaqeb Akhter 	struct cx88_core *core = dev->core;
466c02a34f4SSaqeb Akhter 
467c02a34f4SSaqeb Akhter 	if (voltage == SEC_VOLTAGE_OFF) {
468c02a34f4SSaqeb Akhter 		dprintk(1, "LNB Voltage OFF\n");
469c02a34f4SSaqeb Akhter 		cx_write(MO_GP0_IO, 0x0000efff);
470c02a34f4SSaqeb Akhter 	}
471c02a34f4SSaqeb Akhter 
472c02a34f4SSaqeb Akhter 	if (core->prev_set_voltage)
473c02a34f4SSaqeb Akhter 		return core->prev_set_voltage(fe, voltage);
474c02a34f4SSaqeb Akhter 	return 0;
475c02a34f4SSaqeb Akhter }
476c02a34f4SSaqeb Akhter 
477af832623SIgor M. Liplianin static int tevii_dvbs_set_voltage(struct dvb_frontend *fe,
4780df289a2SMauro Carvalho Chehab 				  enum fe_sec_voltage voltage)
479af832623SIgor M. Liplianin {
480af832623SIgor M. Liplianin 	struct cx8802_dev *dev = fe->dvb->priv;
481af832623SIgor M. Liplianin 	struct cx88_core *core = dev->core;
482af832623SIgor M. Liplianin 
483ad5f74c0SIgor M. Liplianin 	cx_set(MO_GP0_IO, 0x6040);
484af832623SIgor M. Liplianin 	switch (voltage) {
485af832623SIgor M. Liplianin 	case SEC_VOLTAGE_13:
486ad5f74c0SIgor M. Liplianin 		cx_clear(MO_GP0_IO, 0x20);
487af832623SIgor M. Liplianin 		break;
488af832623SIgor M. Liplianin 	case SEC_VOLTAGE_18:
489ad5f74c0SIgor M. Liplianin 		cx_set(MO_GP0_IO, 0x20);
490af832623SIgor M. Liplianin 		break;
491af832623SIgor M. Liplianin 	case SEC_VOLTAGE_OFF:
492ad5f74c0SIgor M. Liplianin 		cx_clear(MO_GP0_IO, 0x20);
493af832623SIgor M. Liplianin 		break;
494af832623SIgor M. Liplianin 	}
495af832623SIgor M. Liplianin 
496af832623SIgor M. Liplianin 	if (core->prev_set_voltage)
497af832623SIgor M. Liplianin 		return core->prev_set_voltage(fe, voltage);
498af832623SIgor M. Liplianin 	return 0;
499af832623SIgor M. Liplianin }
500af832623SIgor M. Liplianin 
501111ac84aSSergey Ivanov static int vp1027_set_voltage(struct dvb_frontend *fe,
5020df289a2SMauro Carvalho Chehab 			      enum fe_sec_voltage voltage)
503111ac84aSSergey Ivanov {
504111ac84aSSergey Ivanov 	struct cx8802_dev *dev = fe->dvb->priv;
505111ac84aSSergey Ivanov 	struct cx88_core *core = dev->core;
506111ac84aSSergey Ivanov 
507111ac84aSSergey Ivanov 	switch (voltage) {
508111ac84aSSergey Ivanov 	case SEC_VOLTAGE_13:
509111ac84aSSergey Ivanov 		dprintk(1, "LNB SEC Voltage=13\n");
510111ac84aSSergey Ivanov 		cx_write(MO_GP0_IO, 0x00001220);
511111ac84aSSergey Ivanov 		break;
512111ac84aSSergey Ivanov 	case SEC_VOLTAGE_18:
513111ac84aSSergey Ivanov 		dprintk(1, "LNB SEC Voltage=18\n");
514111ac84aSSergey Ivanov 		cx_write(MO_GP0_IO, 0x00001222);
515111ac84aSSergey Ivanov 		break;
516111ac84aSSergey Ivanov 	case SEC_VOLTAGE_OFF:
517111ac84aSSergey Ivanov 		dprintk(1, "LNB Voltage OFF\n");
518111ac84aSSergey Ivanov 		cx_write(MO_GP0_IO, 0x00001230);
519111ac84aSSergey Ivanov 		break;
520111ac84aSSergey Ivanov 	}
521111ac84aSSergey Ivanov 
522111ac84aSSergey Ivanov 	if (core->prev_set_voltage)
523111ac84aSSergey Ivanov 		return core->prev_set_voltage(fe, voltage);
524111ac84aSSergey Ivanov 	return 0;
525111ac84aSSergey Ivanov }
526111ac84aSSergey Ivanov 
5272e4e98e7Slawrence rust static const struct cx24123_config geniatech_dvbs_config = {
528c02a34f4SSaqeb Akhter 	.demod_address = 0x55,
529c02a34f4SSaqeb Akhter 	.set_ts_params = cx24123_set_ts_param,
530c02a34f4SSaqeb Akhter };
531c02a34f4SSaqeb Akhter 
5322e4e98e7Slawrence rust static const struct cx24123_config hauppauge_novas_config = {
5330fa14aa6SSteven Toth 	.demod_address = 0x55,
5340fa14aa6SSteven Toth 	.set_ts_params = cx24123_set_ts_param,
5350fa14aa6SSteven Toth };
5360e0351e3SVadim Catana 
5372e4e98e7Slawrence rust static const struct cx24123_config kworld_dvbs_100_config = {
5380e0351e3SVadim Catana 	.demod_address = 0x15,
5390e0351e3SVadim Catana 	.set_ts_params = cx24123_set_ts_param,
540ef76856dSYeasah Pell 	.lnb_polarity  = 1,
5410e0351e3SVadim Catana };
5420fa14aa6SSteven Toth 
5432e4e98e7Slawrence rust static const struct s5h1409_config pinnacle_pctv_hd_800i_config = {
54460464da8SSteven Toth 	.demod_address = 0x32 >> 1,
54560464da8SSteven Toth 	.output_mode   = S5H1409_PARALLEL_OUTPUT,
54660464da8SSteven Toth 	.gpio	       = S5H1409_GPIO_ON,
54760464da8SSteven Toth 	.qam_if	       = 44000,
54860464da8SSteven Toth 	.inversion     = S5H1409_INVERSION_OFF,
54960464da8SSteven Toth 	.status_mode   = S5H1409_DEMODLOCKING,
550ad05ff09SMauro Carvalho Chehab 	.mpeg_timing   = S5H1409_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK,
55160464da8SSteven Toth };
55260464da8SSteven Toth 
5532e4e98e7Slawrence rust static const struct s5h1409_config dvico_hdtv5_pci_nano_config = {
5545c00fac0SSteven Toth 	.demod_address = 0x32 >> 1,
5555c00fac0SSteven Toth 	.output_mode   = S5H1409_SERIAL_OUTPUT,
5565c00fac0SSteven Toth 	.gpio          = S5H1409_GPIO_OFF,
5575c00fac0SSteven Toth 	.inversion     = S5H1409_INVERSION_OFF,
5585c00fac0SSteven Toth 	.status_mode   = S5H1409_DEMODLOCKING,
559ad05ff09SMauro Carvalho Chehab 	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,
5605c00fac0SSteven Toth };
5615c00fac0SSteven Toth 
5622e4e98e7Slawrence rust static const struct s5h1409_config kworld_atsc_120_config = {
56399e09eacSMauro Carvalho Chehab 	.demod_address = 0x32 >> 1,
56499e09eacSMauro Carvalho Chehab 	.output_mode   = S5H1409_SERIAL_OUTPUT,
56599e09eacSMauro Carvalho Chehab 	.gpio	       = S5H1409_GPIO_OFF,
56699e09eacSMauro Carvalho Chehab 	.inversion     = S5H1409_INVERSION_OFF,
56799e09eacSMauro Carvalho Chehab 	.status_mode   = S5H1409_DEMODLOCKING,
568ad05ff09SMauro Carvalho Chehab 	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,
56999e09eacSMauro Carvalho Chehab };
57099e09eacSMauro Carvalho Chehab 
5712e4e98e7Slawrence rust static const struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = {
57260464da8SSteven Toth 	.i2c_address	= 0x64,
57360464da8SSteven Toth 	.if_khz		= 5380,
57460464da8SSteven Toth };
57560464da8SSteven Toth 
5762e4e98e7Slawrence rust static const struct zl10353_config cx88_pinnacle_hybrid_pctv = {
5773f6014fcSStéphane Voltz 	.demod_address = (0x1e >> 1),
5783f6014fcSStéphane Voltz 	.no_tuner      = 1,
5793f6014fcSStéphane Voltz 	.if2           = 45600,
5803f6014fcSStéphane Voltz };
5813f6014fcSStéphane Voltz 
5822e4e98e7Slawrence rust static const struct zl10353_config cx88_geniatech_x8000_mt = {
5839507901eSMauro Carvalho Chehab 	.demod_address = (0x1e >> 1),
5849507901eSMauro Carvalho Chehab 	.no_tuner = 1,
58511db9069SDevin Heitmueller 	.disable_i2c_gate_ctrl = 1,
5869507901eSMauro Carvalho Chehab };
5879507901eSMauro Carvalho Chehab 
5882e4e98e7Slawrence rust static const struct s5h1411_config dvico_fusionhdtv7_config = {
589d893d5dcSSteven Toth 	.output_mode   = S5H1411_SERIAL_OUTPUT,
590d893d5dcSSteven Toth 	.gpio          = S5H1411_GPIO_ON,
591ad05ff09SMauro Carvalho Chehab 	.mpeg_timing   = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK,
592d893d5dcSSteven Toth 	.qam_if        = S5H1411_IF_44000,
593d893d5dcSSteven Toth 	.vsb_if        = S5H1411_IF_44000,
594d893d5dcSSteven Toth 	.inversion     = S5H1411_INVERSION_OFF,
595d893d5dcSSteven Toth 	.status_mode   = S5H1411_DEMODLOCKING
596d893d5dcSSteven Toth };
597d893d5dcSSteven Toth 
5982e4e98e7Slawrence rust static const struct xc5000_config dvico_fusionhdtv7_tuner_config = {
599d893d5dcSSteven Toth 	.i2c_address    = 0xc2 >> 1,
600d893d5dcSSteven Toth 	.if_khz         = 5380,
601d893d5dcSSteven Toth };
602d893d5dcSSteven Toth 
60323fb348dSMauro Carvalho Chehab static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
60423fb348dSMauro Carvalho Chehab {
60523fb348dSMauro Carvalho Chehab 	struct dvb_frontend *fe;
6060b6b6302SHans Verkuil 	struct vb2_dvb_frontend *fe0 = NULL;
60799e09eacSMauro Carvalho Chehab 	struct xc2028_ctrl ctl;
60823fb348dSMauro Carvalho Chehab 	struct xc2028_config cfg = {
60923fb348dSMauro Carvalho Chehab 		.i2c_adap  = &dev->core->i2c_adap,
61023fb348dSMauro Carvalho Chehab 		.i2c_addr  = addr,
61199e09eacSMauro Carvalho Chehab 		.ctrl      = &ctl,
61223fb348dSMauro Carvalho Chehab 	};
61323fb348dSMauro Carvalho Chehab 
614363c35fcSSteven Toth 	/* Get the first frontend */
6150b6b6302SHans Verkuil 	fe0 = vb2_dvb_get_frontend(&dev->frontends, 1);
616363c35fcSSteven Toth 	if (!fe0)
617363c35fcSSteven Toth 		return -EINVAL;
618363c35fcSSteven Toth 
619363c35fcSSteven Toth 	if (!fe0->dvb.frontend) {
62065bc2fe8SMauro Carvalho Chehab 		pr_err("dvb frontend not attached. Can't attach xc3028\n");
621ddd5441dSMauro Carvalho Chehab 		return -EINVAL;
622ddd5441dSMauro Carvalho Chehab 	}
623ddd5441dSMauro Carvalho Chehab 
62499e09eacSMauro Carvalho Chehab 	/*
62599e09eacSMauro Carvalho Chehab 	 * Some xc3028 devices may be hidden by an I2C gate. This is known
62699e09eacSMauro Carvalho Chehab 	 * to happen with some s5h1409-based devices.
62799e09eacSMauro Carvalho Chehab 	 * Now that I2C gate is open, sets up xc3028 configuration
62899e09eacSMauro Carvalho Chehab 	 */
62999e09eacSMauro Carvalho Chehab 	cx88_setup_xc3028(dev->core, &ctl);
63099e09eacSMauro Carvalho Chehab 
631363c35fcSSteven Toth 	fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg);
63223fb348dSMauro Carvalho Chehab 	if (!fe) {
63365bc2fe8SMauro Carvalho Chehab 		pr_err("xc3028 attach failed\n");
634363c35fcSSteven Toth 		dvb_frontend_detach(fe0->dvb.frontend);
635363c35fcSSteven Toth 		dvb_unregister_frontend(fe0->dvb.frontend);
636363c35fcSSteven Toth 		fe0->dvb.frontend = NULL;
63723fb348dSMauro Carvalho Chehab 		return -EINVAL;
63823fb348dSMauro Carvalho Chehab 	}
63923fb348dSMauro Carvalho Chehab 
64065bc2fe8SMauro Carvalho Chehab 	pr_info("xc3028 attached\n");
64123fb348dSMauro Carvalho Chehab 
64223fb348dSMauro Carvalho Chehab 	return 0;
64323fb348dSMauro Carvalho Chehab }
6449507901eSMauro Carvalho Chehab 
645c21973e8Sistvan_v@mailbox.hu static int attach_xc4000(struct cx8802_dev *dev, struct xc4000_config *cfg)
646c21973e8Sistvan_v@mailbox.hu {
647c21973e8Sistvan_v@mailbox.hu 	struct dvb_frontend *fe;
6480b6b6302SHans Verkuil 	struct vb2_dvb_frontend *fe0 = NULL;
649c21973e8Sistvan_v@mailbox.hu 
650c21973e8Sistvan_v@mailbox.hu 	/* Get the first frontend */
6510b6b6302SHans Verkuil 	fe0 = vb2_dvb_get_frontend(&dev->frontends, 1);
652c21973e8Sistvan_v@mailbox.hu 	if (!fe0)
653c21973e8Sistvan_v@mailbox.hu 		return -EINVAL;
654c21973e8Sistvan_v@mailbox.hu 
655c21973e8Sistvan_v@mailbox.hu 	if (!fe0->dvb.frontend) {
65665bc2fe8SMauro Carvalho Chehab 		pr_err("dvb frontend not attached. Can't attach xc4000\n");
657c21973e8Sistvan_v@mailbox.hu 		return -EINVAL;
658c21973e8Sistvan_v@mailbox.hu 	}
659c21973e8Sistvan_v@mailbox.hu 
660c21973e8Sistvan_v@mailbox.hu 	fe = dvb_attach(xc4000_attach, fe0->dvb.frontend, &dev->core->i2c_adap,
661c21973e8Sistvan_v@mailbox.hu 			cfg);
662c21973e8Sistvan_v@mailbox.hu 	if (!fe) {
66365bc2fe8SMauro Carvalho Chehab 		pr_err("xc4000 attach failed\n");
664c21973e8Sistvan_v@mailbox.hu 		dvb_frontend_detach(fe0->dvb.frontend);
665c21973e8Sistvan_v@mailbox.hu 		dvb_unregister_frontend(fe0->dvb.frontend);
666c21973e8Sistvan_v@mailbox.hu 		fe0->dvb.frontend = NULL;
667c21973e8Sistvan_v@mailbox.hu 		return -EINVAL;
668c21973e8Sistvan_v@mailbox.hu 	}
669c21973e8Sistvan_v@mailbox.hu 
67065bc2fe8SMauro Carvalho Chehab 	pr_info("xc4000 attached\n");
671c21973e8Sistvan_v@mailbox.hu 
672c21973e8Sistvan_v@mailbox.hu 	return 0;
673c21973e8Sistvan_v@mailbox.hu }
674c21973e8Sistvan_v@mailbox.hu 
6755bd1b663SSteven Toth static int cx24116_set_ts_param(struct dvb_frontend *fe,
6765bd1b663SSteven Toth 				int is_punctured)
6775bd1b663SSteven Toth {
6785bd1b663SSteven Toth 	struct cx8802_dev *dev = fe->dvb->priv;
6797b61ba8fSMauro Carvalho Chehab 
6805bd1b663SSteven Toth 	dev->ts_gen_cntrl = 0x2;
6815bd1b663SSteven Toth 
6825bd1b663SSteven Toth 	return 0;
6835bd1b663SSteven Toth }
6845bd1b663SSteven Toth 
685b699c271SIgor M. Liplianin static int stv0900_set_ts_param(struct dvb_frontend *fe,
686b699c271SIgor M. Liplianin 				int is_punctured)
687b699c271SIgor M. Liplianin {
688b699c271SIgor M. Liplianin 	struct cx8802_dev *dev = fe->dvb->priv;
6897b61ba8fSMauro Carvalho Chehab 
690b699c271SIgor M. Liplianin 	dev->ts_gen_cntrl = 0;
691b699c271SIgor M. Liplianin 
692b699c271SIgor M. Liplianin 	return 0;
693b699c271SIgor M. Liplianin }
694b699c271SIgor M. Liplianin 
6955bd1b663SSteven Toth static int cx24116_reset_device(struct dvb_frontend *fe)
6965bd1b663SSteven Toth {
6975bd1b663SSteven Toth 	struct cx8802_dev *dev = fe->dvb->priv;
6985bd1b663SSteven Toth 	struct cx88_core *core = dev->core;
6995bd1b663SSteven Toth 
7005bd1b663SSteven Toth 	/* Reset the part */
701363c35fcSSteven Toth 	/* Put the cx24116 into reset */
7025bd1b663SSteven Toth 	cx_write(MO_SRST_IO, 0);
703399426caSMauro Carvalho Chehab 	usleep_range(10000, 20000);
704363c35fcSSteven Toth 	/* Take the cx24116 out of reset */
7055bd1b663SSteven Toth 	cx_write(MO_SRST_IO, 1);
706399426caSMauro Carvalho Chehab 	usleep_range(10000, 20000);
7075bd1b663SSteven Toth 
7085bd1b663SSteven Toth 	return 0;
7095bd1b663SSteven Toth }
7105bd1b663SSteven Toth 
7112e4e98e7Slawrence rust static const struct cx24116_config hauppauge_hvr4000_config = {
7125bd1b663SSteven Toth 	.demod_address          = 0x05,
7135bd1b663SSteven Toth 	.set_ts_params          = cx24116_set_ts_param,
7145bd1b663SSteven Toth 	.reset_device           = cx24116_reset_device,
7155bd1b663SSteven Toth };
7165bd1b663SSteven Toth 
7172e4e98e7Slawrence rust static const struct cx24116_config tevii_s460_config = {
718af832623SIgor M. Liplianin 	.demod_address = 0x55,
719af832623SIgor M. Liplianin 	.set_ts_params = cx24116_set_ts_param,
720af832623SIgor M. Liplianin 	.reset_device  = cx24116_reset_device,
721af832623SIgor M. Liplianin };
722af832623SIgor M. Liplianin 
7230cb73639SIgor M. Liplianin static int ds3000_set_ts_param(struct dvb_frontend *fe,
7240cb73639SIgor M. Liplianin 			       int is_punctured)
7250cb73639SIgor M. Liplianin {
7260cb73639SIgor M. Liplianin 	struct cx8802_dev *dev = fe->dvb->priv;
7277b61ba8fSMauro Carvalho Chehab 
7280cb73639SIgor M. Liplianin 	dev->ts_gen_cntrl = 4;
7290cb73639SIgor M. Liplianin 
7300cb73639SIgor M. Liplianin 	return 0;
7310cb73639SIgor M. Liplianin }
7320cb73639SIgor M. Liplianin 
7330cb73639SIgor M. Liplianin static struct ds3000_config tevii_ds3000_config = {
7340cb73639SIgor M. Liplianin 	.demod_address = 0x68,
7350cb73639SIgor M. Liplianin 	.set_ts_params = ds3000_set_ts_param,
7360cb73639SIgor M. Liplianin };
7370cb73639SIgor M. Liplianin 
73873f0af44SKonstantin Dimitrov static struct ts2020_config tevii_ts2020_config  = {
73973f0af44SKonstantin Dimitrov 	.tuner_address = 0x60,
740b858c331SIgor M. Liplianin 	.clk_out_div = 1,
74173f0af44SKonstantin Dimitrov };
74273f0af44SKonstantin Dimitrov 
7432e4e98e7Slawrence rust static const struct stv0900_config prof_7301_stv0900_config = {
744b699c271SIgor M. Liplianin 	.demod_address = 0x6a,
745b699c271SIgor M. Liplianin /*	demod_mode = 0,*/
746b699c271SIgor M. Liplianin 	.xtal = 27000000,
747b699c271SIgor M. Liplianin 	.clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
748b699c271SIgor M. Liplianin 	.diseqc_mode = 2,/* 2/3 PWM */
749b699c271SIgor M. Liplianin 	.tun1_maddress = 0,/* 0x60 */
750b699c271SIgor M. Liplianin 	.tun1_adc = 0,/* 2 Vpp */
751b699c271SIgor M. Liplianin 	.path1_mode = 3,
752b699c271SIgor M. Liplianin 	.set_ts_params = stv0900_set_ts_param,
753b699c271SIgor M. Liplianin };
754b699c271SIgor M. Liplianin 
7552e4e98e7Slawrence rust static const struct stb6100_config prof_7301_stb6100_config = {
756b699c271SIgor M. Liplianin 	.tuner_address = 0x60,
757b699c271SIgor M. Liplianin 	.refclock = 27000000,
758b699c271SIgor M. Liplianin };
759b699c271SIgor M. Liplianin 
7602e4e98e7Slawrence rust static const struct stv0299_config tevii_tuner_sharp_config = {
761e4aab64cSIgor M. Liplianin 	.demod_address = 0x68,
762d4305c68SIgor M. Liplianin 	.inittab = sharp_z0194a_inittab,
763e4aab64cSIgor M. Liplianin 	.mclk = 88000000UL,
764e4aab64cSIgor M. Liplianin 	.invert = 1,
765e4aab64cSIgor M. Liplianin 	.skip_reinit = 0,
766e4aab64cSIgor M. Liplianin 	.lock_output = 1,
767e4aab64cSIgor M. Liplianin 	.volt13_op0_op1 = STV0299_VOLT13_OP1,
768e4aab64cSIgor M. Liplianin 	.min_delay_ms = 100,
769d4305c68SIgor M. Liplianin 	.set_symbol_rate = sharp_z0194a_set_symbol_rate,
770e4aab64cSIgor M. Liplianin 	.set_ts_params = cx24116_set_ts_param,
771e4aab64cSIgor M. Liplianin };
772e4aab64cSIgor M. Liplianin 
7732e4e98e7Slawrence rust static const struct stv0288_config tevii_tuner_earda_config = {
774e4aab64cSIgor M. Liplianin 	.demod_address = 0x68,
775e4aab64cSIgor M. Liplianin 	.min_delay_ms = 100,
776e4aab64cSIgor M. Liplianin 	.set_ts_params = cx24116_set_ts_param,
777e4aab64cSIgor M. Liplianin };
778e4aab64cSIgor M. Liplianin 
7796e0e12f1SAndy Walls static int cx8802_alloc_frontends(struct cx8802_dev *dev)
7806e0e12f1SAndy Walls {
7816e0e12f1SAndy Walls 	struct cx88_core *core = dev->core;
7820b6b6302SHans Verkuil 	struct vb2_dvb_frontend *fe = NULL;
7836e0e12f1SAndy Walls 	int i;
7846e0e12f1SAndy Walls 
7856e0e12f1SAndy Walls 	mutex_init(&dev->frontends.lock);
7866e0e12f1SAndy Walls 	INIT_LIST_HEAD(&dev->frontends.felist);
7876e0e12f1SAndy Walls 
7886e0e12f1SAndy Walls 	if (!core->board.num_frontends)
7896e0e12f1SAndy Walls 		return -ENODEV;
7906e0e12f1SAndy Walls 
79165bc2fe8SMauro Carvalho Chehab 	pr_info("%s: allocating %d frontend(s)\n", __func__,
7926e0e12f1SAndy Walls 		core->board.num_frontends);
7936e0e12f1SAndy Walls 	for (i = 1; i <= core->board.num_frontends; i++) {
7940b6b6302SHans Verkuil 		fe = vb2_dvb_alloc_frontend(&dev->frontends, i);
7956e0e12f1SAndy Walls 		if (!fe) {
79665bc2fe8SMauro Carvalho Chehab 			pr_err("%s() failed to alloc\n", __func__);
7970b6b6302SHans Verkuil 			vb2_dvb_dealloc_frontends(&dev->frontends);
7986e0e12f1SAndy Walls 			return -ENOMEM;
7996e0e12f1SAndy Walls 		}
8006e0e12f1SAndy Walls 	}
8016e0e12f1SAndy Walls 	return 0;
8026e0e12f1SAndy Walls }
8036e0e12f1SAndy Walls 
8042e4e98e7Slawrence rust static const u8 samsung_smt_7020_inittab[] = {
8054f3ca2f1SDirk Herrendoerfer 	     0x01, 0x15,
8064f3ca2f1SDirk Herrendoerfer 	     0x02, 0x00,
8074f3ca2f1SDirk Herrendoerfer 	     0x03, 0x00,
8084f3ca2f1SDirk Herrendoerfer 	     0x04, 0x7D,
8094f3ca2f1SDirk Herrendoerfer 	     0x05, 0x0F,
8104f3ca2f1SDirk Herrendoerfer 	     0x06, 0x02,
8114f3ca2f1SDirk Herrendoerfer 	     0x07, 0x00,
8124f3ca2f1SDirk Herrendoerfer 	     0x08, 0x60,
8134f3ca2f1SDirk Herrendoerfer 
8144f3ca2f1SDirk Herrendoerfer 	     0x0A, 0xC2,
8154f3ca2f1SDirk Herrendoerfer 	     0x0B, 0x00,
8164f3ca2f1SDirk Herrendoerfer 	     0x0C, 0x01,
8174f3ca2f1SDirk Herrendoerfer 	     0x0D, 0x81,
8184f3ca2f1SDirk Herrendoerfer 	     0x0E, 0x44,
8194f3ca2f1SDirk Herrendoerfer 	     0x0F, 0x09,
8204f3ca2f1SDirk Herrendoerfer 	     0x10, 0x3C,
8214f3ca2f1SDirk Herrendoerfer 	     0x11, 0x84,
8224f3ca2f1SDirk Herrendoerfer 	     0x12, 0xDA,
8234f3ca2f1SDirk Herrendoerfer 	     0x13, 0x99,
8244f3ca2f1SDirk Herrendoerfer 	     0x14, 0x8D,
8254f3ca2f1SDirk Herrendoerfer 	     0x15, 0xCE,
8264f3ca2f1SDirk Herrendoerfer 	     0x16, 0xE8,
8274f3ca2f1SDirk Herrendoerfer 	     0x17, 0x43,
8284f3ca2f1SDirk Herrendoerfer 	     0x18, 0x1C,
8294f3ca2f1SDirk Herrendoerfer 	     0x19, 0x1B,
8304f3ca2f1SDirk Herrendoerfer 	     0x1A, 0x1D,
8314f3ca2f1SDirk Herrendoerfer 
8324f3ca2f1SDirk Herrendoerfer 	     0x1C, 0x12,
8334f3ca2f1SDirk Herrendoerfer 	     0x1D, 0x00,
8344f3ca2f1SDirk Herrendoerfer 	     0x1E, 0x00,
8354f3ca2f1SDirk Herrendoerfer 	     0x1F, 0x00,
8364f3ca2f1SDirk Herrendoerfer 	     0x20, 0x00,
8374f3ca2f1SDirk Herrendoerfer 	     0x21, 0x00,
8384f3ca2f1SDirk Herrendoerfer 	     0x22, 0x00,
8394f3ca2f1SDirk Herrendoerfer 	     0x23, 0x00,
8404f3ca2f1SDirk Herrendoerfer 
8414f3ca2f1SDirk Herrendoerfer 	     0x28, 0x02,
8424f3ca2f1SDirk Herrendoerfer 	     0x29, 0x28,
8434f3ca2f1SDirk Herrendoerfer 	     0x2A, 0x14,
8444f3ca2f1SDirk Herrendoerfer 	     0x2B, 0x0F,
8454f3ca2f1SDirk Herrendoerfer 	     0x2C, 0x09,
8464f3ca2f1SDirk Herrendoerfer 	     0x2D, 0x05,
8474f3ca2f1SDirk Herrendoerfer 
8484f3ca2f1SDirk Herrendoerfer 	     0x31, 0x1F,
8494f3ca2f1SDirk Herrendoerfer 	     0x32, 0x19,
8504f3ca2f1SDirk Herrendoerfer 	     0x33, 0xFC,
8514f3ca2f1SDirk Herrendoerfer 	     0x34, 0x13,
8524f3ca2f1SDirk Herrendoerfer 	     0xff, 0xff,
8534f3ca2f1SDirk Herrendoerfer };
8544f3ca2f1SDirk Herrendoerfer 
85514d24d14SMauro Carvalho Chehab static int samsung_smt_7020_tuner_set_params(struct dvb_frontend *fe)
8564f3ca2f1SDirk Herrendoerfer {
857b738ae16SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
8584f3ca2f1SDirk Herrendoerfer 	struct cx8802_dev *dev = fe->dvb->priv;
8594f3ca2f1SDirk Herrendoerfer 	u8 buf[4];
8604f3ca2f1SDirk Herrendoerfer 	u32 div;
8614f3ca2f1SDirk Herrendoerfer 	struct i2c_msg msg = {
8624f3ca2f1SDirk Herrendoerfer 		.addr = 0x61,
8634f3ca2f1SDirk Herrendoerfer 		.flags = 0,
8644f3ca2f1SDirk Herrendoerfer 		.buf = buf,
8654f3ca2f1SDirk Herrendoerfer 		.len = sizeof(buf) };
8664f3ca2f1SDirk Herrendoerfer 
867b738ae16SMauro Carvalho Chehab 	div = c->frequency / 125;
8684f3ca2f1SDirk Herrendoerfer 
8694f3ca2f1SDirk Herrendoerfer 	buf[0] = (div >> 8) & 0x7f;
8704f3ca2f1SDirk Herrendoerfer 	buf[1] = div & 0xff;
8714f3ca2f1SDirk Herrendoerfer 	buf[2] = 0x84;  /* 0xC4 */
8724f3ca2f1SDirk Herrendoerfer 	buf[3] = 0x00;
8734f3ca2f1SDirk Herrendoerfer 
874b738ae16SMauro Carvalho Chehab 	if (c->frequency < 1500000)
8754f3ca2f1SDirk Herrendoerfer 		buf[3] |= 0x10;
8764f3ca2f1SDirk Herrendoerfer 
8774f3ca2f1SDirk Herrendoerfer 	if (fe->ops.i2c_gate_ctrl)
8784f3ca2f1SDirk Herrendoerfer 		fe->ops.i2c_gate_ctrl(fe, 1);
8794f3ca2f1SDirk Herrendoerfer 
8804f3ca2f1SDirk Herrendoerfer 	if (i2c_transfer(&dev->core->i2c_adap, &msg, 1) != 1)
8814f3ca2f1SDirk Herrendoerfer 		return -EIO;
8824f3ca2f1SDirk Herrendoerfer 
8834f3ca2f1SDirk Herrendoerfer 	return 0;
8844f3ca2f1SDirk Herrendoerfer }
8854f3ca2f1SDirk Herrendoerfer 
8864f3ca2f1SDirk Herrendoerfer static int samsung_smt_7020_set_tone(struct dvb_frontend *fe,
8870df289a2SMauro Carvalho Chehab 				     enum fe_sec_tone_mode tone)
8884f3ca2f1SDirk Herrendoerfer {
8894f3ca2f1SDirk Herrendoerfer 	struct cx8802_dev *dev = fe->dvb->priv;
8904f3ca2f1SDirk Herrendoerfer 	struct cx88_core *core = dev->core;
8914f3ca2f1SDirk Herrendoerfer 
8924f3ca2f1SDirk Herrendoerfer 	cx_set(MO_GP0_IO, 0x0800);
8934f3ca2f1SDirk Herrendoerfer 
8944f3ca2f1SDirk Herrendoerfer 	switch (tone) {
8954f3ca2f1SDirk Herrendoerfer 	case SEC_TONE_ON:
8964f3ca2f1SDirk Herrendoerfer 		cx_set(MO_GP0_IO, 0x08);
8974f3ca2f1SDirk Herrendoerfer 		break;
8984f3ca2f1SDirk Herrendoerfer 	case SEC_TONE_OFF:
8994f3ca2f1SDirk Herrendoerfer 		cx_clear(MO_GP0_IO, 0x08);
9004f3ca2f1SDirk Herrendoerfer 		break;
9014f3ca2f1SDirk Herrendoerfer 	default:
9024f3ca2f1SDirk Herrendoerfer 		return -EINVAL;
9034f3ca2f1SDirk Herrendoerfer 	}
9044f3ca2f1SDirk Herrendoerfer 
9054f3ca2f1SDirk Herrendoerfer 	return 0;
9064f3ca2f1SDirk Herrendoerfer }
9074f3ca2f1SDirk Herrendoerfer 
9084f3ca2f1SDirk Herrendoerfer static int samsung_smt_7020_set_voltage(struct dvb_frontend *fe,
9090df289a2SMauro Carvalho Chehab 					enum fe_sec_voltage voltage)
9104f3ca2f1SDirk Herrendoerfer {
9114f3ca2f1SDirk Herrendoerfer 	struct cx8802_dev *dev = fe->dvb->priv;
9124f3ca2f1SDirk Herrendoerfer 	struct cx88_core *core = dev->core;
9134f3ca2f1SDirk Herrendoerfer 
9144f3ca2f1SDirk Herrendoerfer 	u8 data;
9154f3ca2f1SDirk Herrendoerfer 	struct i2c_msg msg = {
9164f3ca2f1SDirk Herrendoerfer 		.addr = 8,
9174f3ca2f1SDirk Herrendoerfer 		.flags = 0,
9184f3ca2f1SDirk Herrendoerfer 		.buf = &data,
9194f3ca2f1SDirk Herrendoerfer 		.len = sizeof(data) };
9204f3ca2f1SDirk Herrendoerfer 
9214f3ca2f1SDirk Herrendoerfer 	cx_set(MO_GP0_IO, 0x8000);
9224f3ca2f1SDirk Herrendoerfer 
9234f3ca2f1SDirk Herrendoerfer 	switch (voltage) {
9244f3ca2f1SDirk Herrendoerfer 	case SEC_VOLTAGE_OFF:
9254f3ca2f1SDirk Herrendoerfer 		break;
9264f3ca2f1SDirk Herrendoerfer 	case SEC_VOLTAGE_13:
9274f3ca2f1SDirk Herrendoerfer 		data = ISL6421_EN1 | ISL6421_LLC1;
9284f3ca2f1SDirk Herrendoerfer 		cx_clear(MO_GP0_IO, 0x80);
9294f3ca2f1SDirk Herrendoerfer 		break;
9304f3ca2f1SDirk Herrendoerfer 	case SEC_VOLTAGE_18:
9314f3ca2f1SDirk Herrendoerfer 		data = ISL6421_EN1 | ISL6421_LLC1 | ISL6421_VSEL1;
9324f3ca2f1SDirk Herrendoerfer 		cx_clear(MO_GP0_IO, 0x80);
9334f3ca2f1SDirk Herrendoerfer 		break;
9344f3ca2f1SDirk Herrendoerfer 	default:
9354f3ca2f1SDirk Herrendoerfer 		return -EINVAL;
936c2c1b415SPeter Senna Tschudin 	}
9374f3ca2f1SDirk Herrendoerfer 
9384f3ca2f1SDirk Herrendoerfer 	return (i2c_transfer(&dev->core->i2c_adap, &msg, 1) == 1) ? 0 : -EIO;
9394f3ca2f1SDirk Herrendoerfer }
9404f3ca2f1SDirk Herrendoerfer 
9414f3ca2f1SDirk Herrendoerfer static int samsung_smt_7020_stv0299_set_symbol_rate(struct dvb_frontend *fe,
9424f3ca2f1SDirk Herrendoerfer 						    u32 srate, u32 ratio)
9434f3ca2f1SDirk Herrendoerfer {
9444f3ca2f1SDirk Herrendoerfer 	u8 aclk = 0;
9454f3ca2f1SDirk Herrendoerfer 	u8 bclk = 0;
9464f3ca2f1SDirk Herrendoerfer 
9474f3ca2f1SDirk Herrendoerfer 	if (srate < 1500000) {
9484f3ca2f1SDirk Herrendoerfer 		aclk = 0xb7;
9494f3ca2f1SDirk Herrendoerfer 		bclk = 0x47;
9504f3ca2f1SDirk Herrendoerfer 	} else if (srate < 3000000) {
9514f3ca2f1SDirk Herrendoerfer 		aclk = 0xb7;
9524f3ca2f1SDirk Herrendoerfer 		bclk = 0x4b;
9534f3ca2f1SDirk Herrendoerfer 	} else if (srate < 7000000) {
9544f3ca2f1SDirk Herrendoerfer 		aclk = 0xb7;
9554f3ca2f1SDirk Herrendoerfer 		bclk = 0x4f;
9564f3ca2f1SDirk Herrendoerfer 	} else if (srate < 14000000) {
9574f3ca2f1SDirk Herrendoerfer 		aclk = 0xb7;
9584f3ca2f1SDirk Herrendoerfer 		bclk = 0x53;
9594f3ca2f1SDirk Herrendoerfer 	} else if (srate < 30000000) {
9604f3ca2f1SDirk Herrendoerfer 		aclk = 0xb6;
9614f3ca2f1SDirk Herrendoerfer 		bclk = 0x53;
9624f3ca2f1SDirk Herrendoerfer 	} else if (srate < 45000000) {
9634f3ca2f1SDirk Herrendoerfer 		aclk = 0xb4;
9644f3ca2f1SDirk Herrendoerfer 		bclk = 0x51;
9654f3ca2f1SDirk Herrendoerfer 	}
9664f3ca2f1SDirk Herrendoerfer 
9674f3ca2f1SDirk Herrendoerfer 	stv0299_writereg(fe, 0x13, aclk);
9684f3ca2f1SDirk Herrendoerfer 	stv0299_writereg(fe, 0x14, bclk);
9694f3ca2f1SDirk Herrendoerfer 	stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
9704f3ca2f1SDirk Herrendoerfer 	stv0299_writereg(fe, 0x20, (ratio >>  8) & 0xff);
9714f3ca2f1SDirk Herrendoerfer 	stv0299_writereg(fe, 0x21, ratio & 0xf0);
9724f3ca2f1SDirk Herrendoerfer 
9734f3ca2f1SDirk Herrendoerfer 	return 0;
9744f3ca2f1SDirk Herrendoerfer }
9754f3ca2f1SDirk Herrendoerfer 
9762e4e98e7Slawrence rust static const struct stv0299_config samsung_stv0299_config = {
9774f3ca2f1SDirk Herrendoerfer 	.demod_address = 0x68,
9784f3ca2f1SDirk Herrendoerfer 	.inittab = samsung_smt_7020_inittab,
9794f3ca2f1SDirk Herrendoerfer 	.mclk = 88000000UL,
9804f3ca2f1SDirk Herrendoerfer 	.invert = 0,
9814f3ca2f1SDirk Herrendoerfer 	.skip_reinit = 0,
9824f3ca2f1SDirk Herrendoerfer 	.lock_output = STV0299_LOCKOUTPUT_LK,
9834f3ca2f1SDirk Herrendoerfer 	.volt13_op0_op1 = STV0299_VOLT13_OP1,
9844f3ca2f1SDirk Herrendoerfer 	.min_delay_ms = 100,
9854f3ca2f1SDirk Herrendoerfer 	.set_symbol_rate = samsung_smt_7020_stv0299_set_symbol_rate,
9864f3ca2f1SDirk Herrendoerfer };
9874f3ca2f1SDirk Herrendoerfer 
9881da177e4SLinus Torvalds static int dvb_register(struct cx8802_dev *dev)
9891da177e4SLinus Torvalds {
990363c35fcSSteven Toth 	struct cx88_core *core = dev->core;
9910b6b6302SHans Verkuil 	struct vb2_dvb_frontend *fe0, *fe1 = NULL;
99259b1842dSDarron Broad 	int mfe_shared = 0; /* bus not shared by default */
9937b0962d3SDavid Fries 	int res = -EINVAL;
994363c35fcSSteven Toth 
9957b61ba8fSMauro Carvalho Chehab 	if (core->i2c_rc != 0) {
99665bc2fe8SMauro Carvalho Chehab 		pr_err("no i2c-bus available, cannot attach dvb drivers\n");
9970e8bac97SMatthias Schwarzott 		goto frontend_detach;
9980e8bac97SMatthias Schwarzott 	}
9990e8bac97SMatthias Schwarzott 
1000363c35fcSSteven Toth 	/* Get the first frontend */
10010b6b6302SHans Verkuil 	fe0 = vb2_dvb_get_frontend(&dev->frontends, 1);
1002363c35fcSSteven Toth 	if (!fe0)
100360a5a927SDarron Broad 		goto frontend_detach;
10041da177e4SLinus Torvalds 
10058e739090SDarron Broad 	/* multi-frontend gate control is undefined or defaults to fe0 */
10068e739090SDarron Broad 	dev->frontends.gate = 0;
10078e739090SDarron Broad 
1008e32fadc4SMauro Carvalho Chehab 	/* Sets the gate control callback to be used by i2c command calls */
1009e32fadc4SMauro Carvalho Chehab 	core->gate_ctrl = cx88_dvb_gate_ctrl;
1010e32fadc4SMauro Carvalho Chehab 
10118e739090SDarron Broad 	/* init frontend(s) */
10120590d91cSMauro Carvalho Chehab 	switch (core->boardnr) {
10131da177e4SLinus Torvalds 	case CX88_BOARD_HAUPPAUGE_DVB_T1:
1014363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(cx22702_attach,
1015ed355260SMichael Krufky 					       &connexant_refboard_config,
10160590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1017399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
1018363c35fcSSteven Toth 			if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
10190590d91cSMauro Carvalho Chehab 					0x61, &core->i2c_adap,
10200590d91cSMauro Carvalho Chehab 					DVB_PLL_THOMSON_DTT759X))
10210590d91cSMauro Carvalho Chehab 				goto frontend_detach;
1022f54376e2SAndrew de Quincey 		}
10231da177e4SLinus Torvalds 		break;
1024e057ee11SMichael Krufky 	case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
10251da177e4SLinus Torvalds 	case CX88_BOARD_CONEXANT_DVB_T1:
1026f39624fdSManenti Marco 	case CX88_BOARD_KWORLD_DVB_T_CX22702:
10272b5200a7SDavid Shirley 	case CX88_BOARD_WINFAST_DTV1000:
1028363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(cx22702_attach,
1029f7b54b10SMichael Krufky 					       &connexant_refboard_config,
10300590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1031399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
1032363c35fcSSteven Toth 			if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
10330590d91cSMauro Carvalho Chehab 					0x60, &core->i2c_adap,
10340590d91cSMauro Carvalho Chehab 					DVB_PLL_THOMSON_DTT7579))
10350590d91cSMauro Carvalho Chehab 				goto frontend_detach;
1036f54376e2SAndrew de Quincey 		}
10371da177e4SLinus Torvalds 		break;
10384bd6e9d9SMalcolm Valentine 	case CX88_BOARD_WINFAST_DTV2000H:
1039611900c1SSteven Toth 	case CX88_BOARD_HAUPPAUGE_HVR1100:
1040611900c1SSteven Toth 	case CX88_BOARD_HAUPPAUGE_HVR1100LP:
1041a5a2ecfcSTrent Piepho 	case CX88_BOARD_HAUPPAUGE_HVR1300:
1042363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(cx22702_attach,
1043ed355260SMichael Krufky 					       &hauppauge_hvr_config,
10440590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1045399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
1046363c35fcSSteven Toth 			if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
10470590d91cSMauro Carvalho Chehab 					&core->i2c_adap, 0x61,
10480590d91cSMauro Carvalho Chehab 					TUNER_PHILIPS_FMD1216ME_MK3))
10490590d91cSMauro Carvalho Chehab 				goto frontend_detach;
1050f54376e2SAndrew de Quincey 		}
1051611900c1SSteven Toth 		break;
105227b93d8aSMiroslav Slugen 	case CX88_BOARD_WINFAST_DTV2000H_J:
105327b93d8aSMiroslav Slugen 		fe0->dvb.frontend = dvb_attach(cx22702_attach,
105427b93d8aSMiroslav Slugen 					       &hauppauge_hvr_config,
105527b93d8aSMiroslav Slugen 					       &core->i2c_adap);
1056399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
105727b93d8aSMiroslav Slugen 			if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
105827b93d8aSMiroslav Slugen 					&core->i2c_adap, 0x61,
105927b93d8aSMiroslav Slugen 					TUNER_PHILIPS_FMD1216MEX_MK3))
106027b93d8aSMiroslav Slugen 				goto frontend_detach;
106127b93d8aSMiroslav Slugen 		}
106227b93d8aSMiroslav Slugen 		break;
1063363c35fcSSteven Toth 	case CX88_BOARD_HAUPPAUGE_HVR3000:
106460a5a927SDarron Broad 		/* MFE frontend 1 */
106560a5a927SDarron Broad 		mfe_shared = 1;
106660a5a927SDarron Broad 		dev->frontends.gate = 2;
1067363c35fcSSteven Toth 		/* DVB-S init */
1068363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(cx24123_attach,
1069363c35fcSSteven Toth 					       &hauppauge_novas_config,
1070363c35fcSSteven Toth 					       &dev->core->i2c_adap);
1071363c35fcSSteven Toth 		if (fe0->dvb.frontend) {
107260a5a927SDarron Broad 			if (!dvb_attach(isl6421_attach,
107360a5a927SDarron Broad 					fe0->dvb.frontend,
107460a5a927SDarron Broad 					&dev->core->i2c_adap,
107548a8a03bSMauro Carvalho Chehab 					0x08, ISL6421_DCL, 0x00, false))
107660a5a927SDarron Broad 				goto frontend_detach;
1077363c35fcSSteven Toth 		}
107860a5a927SDarron Broad 		/* MFE frontend 2 */
10790b6b6302SHans Verkuil 		fe1 = vb2_dvb_get_frontend(&dev->frontends, 2);
108060a5a927SDarron Broad 		if (!fe1)
108160a5a927SDarron Broad 			goto frontend_detach;
108260a5a927SDarron Broad 		/* DVB-T init */
1083363c35fcSSteven Toth 		fe1->dvb.frontend = dvb_attach(cx22702_attach,
1084363c35fcSSteven Toth 					       &hauppauge_hvr_config,
1085363c35fcSSteven Toth 					       &dev->core->i2c_adap);
1086363c35fcSSteven Toth 		if (fe1->dvb.frontend) {
1087363c35fcSSteven Toth 			fe1->dvb.frontend->id = 1;
108860a5a927SDarron Broad 			if (!dvb_attach(simple_tuner_attach,
108960a5a927SDarron Broad 					fe1->dvb.frontend,
109060a5a927SDarron Broad 					&dev->core->i2c_adap,
109160a5a927SDarron Broad 					0x61, TUNER_PHILIPS_FMD1216ME_MK3))
109260a5a927SDarron Broad 				goto frontend_detach;
1093363c35fcSSteven Toth 		}
1094363c35fcSSteven Toth 		break;
1095780dfef3SChris Pascoe 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
1096363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(mt352_attach,
1097f7b54b10SMichael Krufky 					       &dvico_fusionhdtv,
10980590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1099399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
1100363c35fcSSteven Toth 			if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
11010590d91cSMauro Carvalho Chehab 					0x60, NULL, DVB_PLL_THOMSON_DTT7579))
11020590d91cSMauro Carvalho Chehab 				goto frontend_detach;
1103780dfef3SChris Pascoe 			break;
1104f54376e2SAndrew de Quincey 		}
1105780dfef3SChris Pascoe 		/* ZL10353 replaces MT352 on later cards */
1106363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(zl10353_attach,
1107f7b54b10SMichael Krufky 					       &dvico_fusionhdtv_plus_v1_1,
11080590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1109399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
1110363c35fcSSteven Toth 			if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
11110590d91cSMauro Carvalho Chehab 					0x60, NULL, DVB_PLL_THOMSON_DTT7579))
11120590d91cSMauro Carvalho Chehab 				goto frontend_detach;
1113f54376e2SAndrew de Quincey 		}
1114780dfef3SChris Pascoe 		break;
1115c2af3cd6SMichael Krufky 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
1116399426caSMauro Carvalho Chehab 		/*
1117399426caSMauro Carvalho Chehab 		 * The tin box says DEE1601, but it seems to be DTT7579
1118399426caSMauro Carvalho Chehab 		 * compatible, with a slightly different MT352 AGC gain.
1119399426caSMauro Carvalho Chehab 		 */
1120363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(mt352_attach,
1121f7b54b10SMichael Krufky 					       &dvico_fusionhdtv_dual,
11220590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1123399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
1124363c35fcSSteven Toth 			if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
11250590d91cSMauro Carvalho Chehab 					0x61, NULL, DVB_PLL_THOMSON_DTT7579))
11260590d91cSMauro Carvalho Chehab 				goto frontend_detach;
1127c2af3cd6SMichael Krufky 			break;
1128c2af3cd6SMichael Krufky 		}
1129c2af3cd6SMichael Krufky 		/* ZL10353 replaces MT352 on later cards */
1130363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(zl10353_attach,
1131f7b54b10SMichael Krufky 					       &dvico_fusionhdtv_plus_v1_1,
11320590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1133399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
1134363c35fcSSteven Toth 			if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
11350590d91cSMauro Carvalho Chehab 					0x61, NULL, DVB_PLL_THOMSON_DTT7579))
11360590d91cSMauro Carvalho Chehab 				goto frontend_detach;
1137c2af3cd6SMichael Krufky 		}
1138c2af3cd6SMichael Krufky 		break;
11391da177e4SLinus Torvalds 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
1140363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(mt352_attach,
1141f7b54b10SMichael Krufky 					       &dvico_fusionhdtv,
11420590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1143399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
1144363c35fcSSteven Toth 			if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
11450590d91cSMauro Carvalho Chehab 					0x61, NULL, DVB_PLL_LG_Z201))
11460590d91cSMauro Carvalho Chehab 				goto frontend_detach;
1147f54376e2SAndrew de Quincey 		}
11481da177e4SLinus Torvalds 		break;
11491da177e4SLinus Torvalds 	case CX88_BOARD_KWORLD_DVB_T:
11501da177e4SLinus Torvalds 	case CX88_BOARD_DNTV_LIVE_DVB_T:
1151a82decf6SMauro Carvalho Chehab 	case CX88_BOARD_ADSTECH_DVB_T_PCI:
1152363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(mt352_attach,
1153f7b54b10SMichael Krufky 					       &dntv_live_dvbt_config,
11540590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1155399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
1156363c35fcSSteven Toth 			if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend,
11570590d91cSMauro Carvalho Chehab 					0x61, NULL, DVB_PLL_UNKNOWN_1))
11580590d91cSMauro Carvalho Chehab 				goto frontend_detach;
1159f54376e2SAndrew de Quincey 		}
11601da177e4SLinus Torvalds 		break;
1161fc40b261SChris Pascoe 	case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
11627b34be71SPeter Senna Tschudin #if IS_ENABLED(CONFIG_VIDEO_CX88_VP3054)
1163f0ad9097STrent Piepho 		/* MT352 is on a secondary I2C bus made from some GPIO lines */
1164399426caSMauro Carvalho Chehab 		fe0->dvb.frontend = dvb_attach(mt352_attach,
1165399426caSMauro Carvalho Chehab 					       &dntv_live_dvbt_pro_config,
1166f0ad9097STrent Piepho 					       &dev->vp3054->adap);
1167399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
1168363c35fcSSteven Toth 			if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
11690590d91cSMauro Carvalho Chehab 					&core->i2c_adap, 0x61,
11700590d91cSMauro Carvalho Chehab 					TUNER_PHILIPS_FMD1216ME_MK3))
11710590d91cSMauro Carvalho Chehab 				goto frontend_detach;
1172f54376e2SAndrew de Quincey 		}
1173fc40b261SChris Pascoe #else
117465bc2fe8SMauro Carvalho Chehab 		pr_err("built without vp3054 support\n");
1175fc40b261SChris Pascoe #endif
1176fc40b261SChris Pascoe 		break;
1177780dfef3SChris Pascoe 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
1178363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(zl10353_attach,
1179f7b54b10SMichael Krufky 					       &dvico_fusionhdtv_hybrid,
11800590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1181399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
1182363c35fcSSteven Toth 			if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
11830590d91cSMauro Carvalho Chehab 					&core->i2c_adap, 0x61,
11840590d91cSMauro Carvalho Chehab 					TUNER_THOMSON_FE6600))
11850590d91cSMauro Carvalho Chehab 				goto frontend_detach;
1186f54376e2SAndrew de Quincey 		}
1187780dfef3SChris Pascoe 		break;
1188b3fb91d2SChris Pascoe 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
1189363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(zl10353_attach,
1190b3fb91d2SChris Pascoe 					       &dvico_fusionhdtv_xc3028,
11910590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1192399426caSMauro Carvalho Chehab 		if (!fe0->dvb.frontend)
1193363c35fcSSteven Toth 			fe0->dvb.frontend = dvb_attach(mt352_attach,
1194b3fb91d2SChris Pascoe 						&dvico_fusionhdtv_mt352_xc3028,
11950590d91cSMauro Carvalho Chehab 						&core->i2c_adap);
11968765561fSChris Pascoe 		/*
11978765561fSChris Pascoe 		 * On this board, the demod provides the I2C bus pullup.
11988765561fSChris Pascoe 		 * We must not permit gate_ctrl to be performed, or
11998765561fSChris Pascoe 		 * the xc3028 cannot communicate on the bus.
12008765561fSChris Pascoe 		 */
1201363c35fcSSteven Toth 		if (fe0->dvb.frontend)
1202363c35fcSSteven Toth 			fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
120323fb348dSMauro Carvalho Chehab 		if (attach_xc3028(0x61, dev) < 0)
1204becd4305SDarron Broad 			goto frontend_detach;
1205b3fb91d2SChris Pascoe 		break;
12061da177e4SLinus Torvalds 	case CX88_BOARD_PCHDTV_HD3000:
1207363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000,
12080590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1209399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
1210363c35fcSSteven Toth 			if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
12110590d91cSMauro Carvalho Chehab 					&core->i2c_adap, 0x61,
12120590d91cSMauro Carvalho Chehab 					TUNER_THOMSON_DTT761X))
12130590d91cSMauro Carvalho Chehab 				goto frontend_detach;
1214f54376e2SAndrew de Quincey 		}
12151da177e4SLinus Torvalds 		break;
1216f1798495SMichael Krufky 	case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
1217f1798495SMichael Krufky 		dev->ts_gen_cntrl = 0x08;
1218f1798495SMichael Krufky 
12190590d91cSMauro Carvalho Chehab 		/* Do a hardware reset of chip before using it. */
1220f1798495SMichael Krufky 		cx_clear(MO_GP0_IO, 1);
12219d08ba6dSJia-Ju Bai 		msleep(100);
12220ccef6dbSMichael Krufky 		cx_set(MO_GP0_IO, 1);
12239d08ba6dSJia-Ju Bai 		msleep(200);
12240ccef6dbSMichael Krufky 
12250ccef6dbSMichael Krufky 		/* Select RF connector callback */
12266ddcc919SMichael Krufky 		fusionhdtv_3_gold.pll_rf_set = lgdt330x_pll_rf_set;
1227363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
1228f7b54b10SMichael Krufky 					       &fusionhdtv_3_gold,
122923ba635dSMauro Carvalho Chehab 					       0x0e,
12300590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1231399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
1232363c35fcSSteven Toth 			if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
12330590d91cSMauro Carvalho Chehab 					&core->i2c_adap, 0x61,
12340590d91cSMauro Carvalho Chehab 					TUNER_MICROTUNE_4042FI5))
12350590d91cSMauro Carvalho Chehab 				goto frontend_detach;
1236f1798495SMichael Krufky 		}
1237f1798495SMichael Krufky 		break;
12380d723c09SMichael Krufky 	case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
12390d723c09SMichael Krufky 		dev->ts_gen_cntrl = 0x08;
12400d723c09SMichael Krufky 
12410590d91cSMauro Carvalho Chehab 		/* Do a hardware reset of chip before using it. */
12420d723c09SMichael Krufky 		cx_clear(MO_GP0_IO, 1);
12439d08ba6dSJia-Ju Bai 		msleep(100);
1244d975872cSMichael Krufky 		cx_set(MO_GP0_IO, 9);
12459d08ba6dSJia-Ju Bai 		msleep(200);
1246363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
1247f7b54b10SMichael Krufky 					       &fusionhdtv_3_gold,
124823ba635dSMauro Carvalho Chehab 					       0x0e,
12490590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1250399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
1251363c35fcSSteven Toth 			if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
12520590d91cSMauro Carvalho Chehab 					&core->i2c_adap, 0x61,
12530590d91cSMauro Carvalho Chehab 					TUNER_THOMSON_DTT761X))
12540590d91cSMauro Carvalho Chehab 				goto frontend_detach;
12550d723c09SMichael Krufky 		}
12560d723c09SMichael Krufky 		break;
1257e52e98a7SMauro Carvalho Chehab 	case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
1258e52e98a7SMauro Carvalho Chehab 		dev->ts_gen_cntrl = 0x08;
1259e52e98a7SMauro Carvalho Chehab 
12600590d91cSMauro Carvalho Chehab 		/* Do a hardware reset of chip before using it. */
1261e52e98a7SMauro Carvalho Chehab 		cx_clear(MO_GP0_IO, 1);
12629d08ba6dSJia-Ju Bai 		msleep(100);
1263e52e98a7SMauro Carvalho Chehab 		cx_set(MO_GP0_IO, 1);
12649d08ba6dSJia-Ju Bai 		msleep(200);
1265363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
1266f7b54b10SMichael Krufky 					       &fusionhdtv_5_gold,
126723ba635dSMauro Carvalho Chehab 					       0x0e,
12680590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1269399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
1270363c35fcSSteven Toth 			if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
12710590d91cSMauro Carvalho Chehab 					&core->i2c_adap, 0x61,
12720590d91cSMauro Carvalho Chehab 					TUNER_LG_TDVS_H06XF))
12730590d91cSMauro Carvalho Chehab 				goto frontend_detach;
1274363c35fcSSteven Toth 			if (!dvb_attach(tda9887_attach, fe0->dvb.frontend,
12750590d91cSMauro Carvalho Chehab 					&core->i2c_adap, 0x43))
12760590d91cSMauro Carvalho Chehab 				goto frontend_detach;
1277e52e98a7SMauro Carvalho Chehab 		}
1278e52e98a7SMauro Carvalho Chehab 		break;
1279da215d22SRusty Scott 	case CX88_BOARD_PCHDTV_HD5500:
1280da215d22SRusty Scott 		dev->ts_gen_cntrl = 0x08;
1281da215d22SRusty Scott 
12820590d91cSMauro Carvalho Chehab 		/* Do a hardware reset of chip before using it. */
1283da215d22SRusty Scott 		cx_clear(MO_GP0_IO, 1);
12849d08ba6dSJia-Ju Bai 		msleep(100);
1285da215d22SRusty Scott 		cx_set(MO_GP0_IO, 1);
12869d08ba6dSJia-Ju Bai 		msleep(200);
1287363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
1288f7b54b10SMichael Krufky 					       &pchdtv_hd5500,
128923ba635dSMauro Carvalho Chehab 					       0x59,
12900590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1291399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
1292363c35fcSSteven Toth 			if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
12930590d91cSMauro Carvalho Chehab 					&core->i2c_adap, 0x61,
12940590d91cSMauro Carvalho Chehab 					TUNER_LG_TDVS_H06XF))
12950590d91cSMauro Carvalho Chehab 				goto frontend_detach;
1296363c35fcSSteven Toth 			if (!dvb_attach(tda9887_attach, fe0->dvb.frontend,
12970590d91cSMauro Carvalho Chehab 					&core->i2c_adap, 0x43))
12980590d91cSMauro Carvalho Chehab 				goto frontend_detach;
1299da215d22SRusty Scott 		}
1300da215d22SRusty Scott 		break;
1301fde6d31eSKirk Lapray 	case CX88_BOARD_ATI_HDTVWONDER:
1302363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(nxt200x_attach,
1303f7b54b10SMichael Krufky 					       &ati_hdtvwonder,
13040590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1305399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
1306363c35fcSSteven Toth 			if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
13070590d91cSMauro Carvalho Chehab 					&core->i2c_adap, 0x61,
13080590d91cSMauro Carvalho Chehab 					TUNER_PHILIPS_TUV1236D))
13090590d91cSMauro Carvalho Chehab 				goto frontend_detach;
1310f54376e2SAndrew de Quincey 		}
1311fde6d31eSKirk Lapray 		break;
13120fa14aa6SSteven Toth 	case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
13130fa14aa6SSteven Toth 	case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
1314363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(cx24123_attach,
1315f7b54b10SMichael Krufky 					       &hauppauge_novas_config,
13160590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1317363c35fcSSteven Toth 		if (fe0->dvb.frontend) {
131848a8a03bSMauro Carvalho Chehab 			bool override_tone;
131948a8a03bSMauro Carvalho Chehab 
132048a8a03bSMauro Carvalho Chehab 			if (core->model == 92001)
132148a8a03bSMauro Carvalho Chehab 				override_tone = true;
132248a8a03bSMauro Carvalho Chehab 			else
132348a8a03bSMauro Carvalho Chehab 				override_tone = false;
132448a8a03bSMauro Carvalho Chehab 
1325363c35fcSSteven Toth 			if (!dvb_attach(isl6421_attach, fe0->dvb.frontend,
1326399426caSMauro Carvalho Chehab 					&core->i2c_adap, 0x08, ISL6421_DCL,
1327399426caSMauro Carvalho Chehab 					0x00, override_tone))
13280590d91cSMauro Carvalho Chehab 				goto frontend_detach;
1329cd20ca9fSAndrew de Quincey 		}
13300fa14aa6SSteven Toth 		break;
13310e0351e3SVadim Catana 	case CX88_BOARD_KWORLD_DVBS_100:
1332363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(cx24123_attach,
1333f7b54b10SMichael Krufky 					       &kworld_dvbs_100_config,
13340590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1335363c35fcSSteven Toth 		if (fe0->dvb.frontend) {
1336363c35fcSSteven Toth 			core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
1337363c35fcSSteven Toth 			fe0->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
1338cd20ca9fSAndrew de Quincey 		}
13390e0351e3SVadim Catana 		break;
1340c02a34f4SSaqeb Akhter 	case CX88_BOARD_GENIATECH_DVBS:
1341363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(cx24123_attach,
1342f7b54b10SMichael Krufky 					       &geniatech_dvbs_config,
13430590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1344363c35fcSSteven Toth 		if (fe0->dvb.frontend) {
1345363c35fcSSteven Toth 			core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
1346363c35fcSSteven Toth 			fe0->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
1347c02a34f4SSaqeb Akhter 		}
1348c02a34f4SSaqeb Akhter 		break;
134960464da8SSteven Toth 	case CX88_BOARD_PINNACLE_PCTV_HD_800i:
1350363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(s5h1409_attach,
135160464da8SSteven Toth 					       &pinnacle_pctv_hd_800i_config,
13520590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1353399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
1354363c35fcSSteven Toth 			if (!dvb_attach(xc5000_attach, fe0->dvb.frontend,
13550590d91cSMauro Carvalho Chehab 					&core->i2c_adap,
135630650961SMichael Krufky 					&pinnacle_pctv_hd_800i_tuner_config))
13570590d91cSMauro Carvalho Chehab 				goto frontend_detach;
135860464da8SSteven Toth 		}
135960464da8SSteven Toth 		break;
13605c00fac0SSteven Toth 	case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
1361363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(s5h1409_attach,
13625c00fac0SSteven Toth 					       &dvico_hdtv5_pci_nano_config,
13630590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1364399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
13655c00fac0SSteven Toth 			struct dvb_frontend *fe;
13665c00fac0SSteven Toth 			struct xc2028_config cfg = {
13670590d91cSMauro Carvalho Chehab 				.i2c_adap  = &core->i2c_adap,
13685c00fac0SSteven Toth 				.i2c_addr  = 0x61,
13695c00fac0SSteven Toth 			};
13705c00fac0SSteven Toth 			static struct xc2028_ctrl ctl = {
1371ef80bfebSMichael Krufky 				.fname       = XC2028_DEFAULT_FIRMWARE,
13725c00fac0SSteven Toth 				.max_len     = 64,
137333e53161SMauro Carvalho Chehab 				.scode_table = XC3028_FE_OREN538,
13745c00fac0SSteven Toth 			};
13755c00fac0SSteven Toth 
13765c00fac0SSteven Toth 			fe = dvb_attach(xc2028_attach,
1377363c35fcSSteven Toth 					fe0->dvb.frontend, &cfg);
1378399426caSMauro Carvalho Chehab 			if (fe && fe->ops.tuner_ops.set_config)
13795c00fac0SSteven Toth 				fe->ops.tuner_ops.set_config(fe, &ctl);
13805c00fac0SSteven Toth 		}
13815c00fac0SSteven Toth 		break;
1382e6f45ea2SDaniel Gonzalez Cabanelas 	case CX88_BOARD_NOTONLYTV_LV3H:
13839507901eSMauro Carvalho Chehab 	case CX88_BOARD_PINNACLE_HYBRID_PCTV:
13843047a176SMiroslav Sustek 	case CX88_BOARD_WINFAST_DTV1800H:
1385363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(zl10353_attach,
13863f6014fcSStéphane Voltz 					       &cx88_pinnacle_hybrid_pctv,
13870590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1388363c35fcSSteven Toth 		if (fe0->dvb.frontend) {
1389363c35fcSSteven Toth 			fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
139023fb348dSMauro Carvalho Chehab 			if (attach_xc3028(0x61, dev) < 0)
13910590d91cSMauro Carvalho Chehab 				goto frontend_detach;
13923f6014fcSStéphane Voltz 		}
13939507901eSMauro Carvalho Chehab 		break;
13948eb79c0bSistvan_v@mailbox.hu 	case CX88_BOARD_WINFAST_DTV1800H_XC4000:
1395f271a3afSistvan_v@mailbox.hu 	case CX88_BOARD_WINFAST_DTV2000H_PLUS:
1396f271a3afSistvan_v@mailbox.hu 		fe0->dvb.frontend = dvb_attach(zl10353_attach,
1397f271a3afSistvan_v@mailbox.hu 					       &cx88_pinnacle_hybrid_pctv,
1398f271a3afSistvan_v@mailbox.hu 					       &core->i2c_adap);
1399f271a3afSistvan_v@mailbox.hu 		if (fe0->dvb.frontend) {
1400f271a3afSistvan_v@mailbox.hu 			struct xc4000_config cfg = {
1401f271a3afSistvan_v@mailbox.hu 				.i2c_address	  = 0x61,
1402f271a3afSistvan_v@mailbox.hu 				.default_pm	  = 0,
1403f271a3afSistvan_v@mailbox.hu 				.dvb_amplitude	  = 134,
1404f271a3afSistvan_v@mailbox.hu 				.set_smoothedcvbs = 1,
1405f271a3afSistvan_v@mailbox.hu 				.if_khz		  = 4560
1406f271a3afSistvan_v@mailbox.hu 			};
1407f271a3afSistvan_v@mailbox.hu 			fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
1408f271a3afSistvan_v@mailbox.hu 			if (attach_xc4000(dev, &cfg) < 0)
1409f271a3afSistvan_v@mailbox.hu 				goto frontend_detach;
1410f271a3afSistvan_v@mailbox.hu 		}
1411f271a3afSistvan_v@mailbox.hu 		break;
14129507901eSMauro Carvalho Chehab 	case CX88_BOARD_GENIATECH_X8000_MT:
14139507901eSMauro Carvalho Chehab 		dev->ts_gen_cntrl = 0x00;
14149507901eSMauro Carvalho Chehab 
1415363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(zl10353_attach,
14169507901eSMauro Carvalho Chehab 					       &cx88_geniatech_x8000_mt,
14170590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
141823fb348dSMauro Carvalho Chehab 		if (attach_xc3028(0x61, dev) < 0)
14190590d91cSMauro Carvalho Chehab 			goto frontend_detach;
14209507901eSMauro Carvalho Chehab 		break;
142199e09eacSMauro Carvalho Chehab 	case CX88_BOARD_KWORLD_ATSC_120:
1422363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(s5h1409_attach,
142399e09eacSMauro Carvalho Chehab 					       &kworld_atsc_120_config,
14240590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
142599e09eacSMauro Carvalho Chehab 		if (attach_xc3028(0x61, dev) < 0)
14260590d91cSMauro Carvalho Chehab 			goto frontend_detach;
142799e09eacSMauro Carvalho Chehab 		break;
1428d893d5dcSSteven Toth 	case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
1429363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(s5h1411_attach,
1430d893d5dcSSteven Toth 					       &dvico_fusionhdtv7_config,
14310590d91cSMauro Carvalho Chehab 					       &core->i2c_adap);
1432399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
1433363c35fcSSteven Toth 			if (!dvb_attach(xc5000_attach, fe0->dvb.frontend,
14340590d91cSMauro Carvalho Chehab 					&core->i2c_adap,
143530650961SMichael Krufky 					&dvico_fusionhdtv7_tuner_config))
14360590d91cSMauro Carvalho Chehab 				goto frontend_detach;
1437d893d5dcSSteven Toth 		}
1438d893d5dcSSteven Toth 		break;
14395bd1b663SSteven Toth 	case CX88_BOARD_HAUPPAUGE_HVR4000:
144060a5a927SDarron Broad 		/* MFE frontend 1 */
144160a5a927SDarron Broad 		mfe_shared = 1;
144260a5a927SDarron Broad 		dev->frontends.gate = 2;
1443363c35fcSSteven Toth 		/* DVB-S/S2 Init */
1444363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(cx24116_attach,
14455bd1b663SSteven Toth 					       &hauppauge_hvr4000_config,
14465bd1b663SSteven Toth 					       &dev->core->i2c_adap);
1447363c35fcSSteven Toth 		if (fe0->dvb.frontend) {
144860a5a927SDarron Broad 			if (!dvb_attach(isl6421_attach,
144960a5a927SDarron Broad 					fe0->dvb.frontend,
145060a5a927SDarron Broad 					&dev->core->i2c_adap,
145148a8a03bSMauro Carvalho Chehab 					0x08, ISL6421_DCL, 0x00, false))
145260a5a927SDarron Broad 				goto frontend_detach;
1453363c35fcSSteven Toth 		}
145460a5a927SDarron Broad 		/* MFE frontend 2 */
14550b6b6302SHans Verkuil 		fe1 = vb2_dvb_get_frontend(&dev->frontends, 2);
145660a5a927SDarron Broad 		if (!fe1)
145760a5a927SDarron Broad 			goto frontend_detach;
145860a5a927SDarron Broad 		/* DVB-T Init */
1459363c35fcSSteven Toth 		fe1->dvb.frontend = dvb_attach(cx22702_attach,
1460363c35fcSSteven Toth 					       &hauppauge_hvr_config,
1461363c35fcSSteven Toth 					       &dev->core->i2c_adap);
1462363c35fcSSteven Toth 		if (fe1->dvb.frontend) {
1463363c35fcSSteven Toth 			fe1->dvb.frontend->id = 1;
146460a5a927SDarron Broad 			if (!dvb_attach(simple_tuner_attach,
146560a5a927SDarron Broad 					fe1->dvb.frontend,
146660a5a927SDarron Broad 					&dev->core->i2c_adap,
146760a5a927SDarron Broad 					0x61, TUNER_PHILIPS_FMD1216ME_MK3))
146860a5a927SDarron Broad 				goto frontend_detach;
1469363c35fcSSteven Toth 		}
1470363c35fcSSteven Toth 		break;
1471363c35fcSSteven Toth 	case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
1472363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(cx24116_attach,
1473363c35fcSSteven Toth 					       &hauppauge_hvr4000_config,
1474363c35fcSSteven Toth 					       &dev->core->i2c_adap);
1475363c35fcSSteven Toth 		if (fe0->dvb.frontend) {
147660a5a927SDarron Broad 			if (!dvb_attach(isl6421_attach,
147760a5a927SDarron Broad 					fe0->dvb.frontend,
14785bd1b663SSteven Toth 					&dev->core->i2c_adap,
147948a8a03bSMauro Carvalho Chehab 					0x08, ISL6421_DCL, 0x00, false))
148060a5a927SDarron Broad 				goto frontend_detach;
14815bd1b663SSteven Toth 		}
14825bd1b663SSteven Toth 		break;
1483cd3cde12SIgor M. Liplianin 	case CX88_BOARD_PROF_6200:
14844b29631dSIgor M. Liplianin 	case CX88_BOARD_TBS_8910:
1485e4aab64cSIgor M. Liplianin 	case CX88_BOARD_TEVII_S420:
1486363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(stv0299_attach,
1487e4aab64cSIgor M. Liplianin 						&tevii_tuner_sharp_config,
1488e4aab64cSIgor M. Liplianin 						&core->i2c_adap);
1489399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
1490363c35fcSSteven Toth 			if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60,
1491e4aab64cSIgor M. Liplianin 					&core->i2c_adap, DVB_PLL_OPERA1))
1492e4aab64cSIgor M. Liplianin 				goto frontend_detach;
1493363c35fcSSteven Toth 			core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
1494363c35fcSSteven Toth 			fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
1495e4aab64cSIgor M. Liplianin 
1496e4aab64cSIgor M. Liplianin 		} else {
1497363c35fcSSteven Toth 			fe0->dvb.frontend = dvb_attach(stv0288_attach,
1498e4aab64cSIgor M. Liplianin 							    &tevii_tuner_earda_config,
1499e4aab64cSIgor M. Liplianin 							    &core->i2c_adap);
1500399426caSMauro Carvalho Chehab 			if (fe0->dvb.frontend) {
1501399426caSMauro Carvalho Chehab 				if (!dvb_attach(stb6000_attach,
1502399426caSMauro Carvalho Chehab 						fe0->dvb.frontend, 0x61,
1503e4aab64cSIgor M. Liplianin 						&core->i2c_adap))
1504e4aab64cSIgor M. Liplianin 					goto frontend_detach;
1505363c35fcSSteven Toth 				core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
1506363c35fcSSteven Toth 				fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
1507e4aab64cSIgor M. Liplianin 			}
1508e4aab64cSIgor M. Liplianin 		}
1509e4aab64cSIgor M. Liplianin 		break;
1510af832623SIgor M. Liplianin 	case CX88_BOARD_TEVII_S460:
1511363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(cx24116_attach,
1512af832623SIgor M. Liplianin 					       &tevii_s460_config,
1513af832623SIgor M. Liplianin 					       &core->i2c_adap);
1514399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend)
1515363c35fcSSteven Toth 			fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
1516af832623SIgor M. Liplianin 		break;
15170cb73639SIgor M. Liplianin 	case CX88_BOARD_TEVII_S464:
15180cb73639SIgor M. Liplianin 		fe0->dvb.frontend = dvb_attach(ds3000_attach,
15190cb73639SIgor M. Liplianin 						&tevii_ds3000_config,
15200cb73639SIgor M. Liplianin 						&core->i2c_adap);
1521399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
152273f0af44SKonstantin Dimitrov 			dvb_attach(ts2020_attach, fe0->dvb.frontend,
152373f0af44SKonstantin Dimitrov 				   &tevii_ts2020_config, &core->i2c_adap);
15240cb73639SIgor M. Liplianin 			fe0->dvb.frontend->ops.set_voltage =
15250cb73639SIgor M. Liplianin 							tevii_dvbs_set_voltage;
152673f0af44SKonstantin Dimitrov 		}
15270cb73639SIgor M. Liplianin 		break;
15284cd7fb87SOleg Roitburd 	case CX88_BOARD_OMICOM_SS4_PCI:
1529ee73042cSOleg Roitburd 	case CX88_BOARD_TBS_8920:
153057f51dbcSOleg Roitburd 	case CX88_BOARD_PROF_7300:
15314b29631dSIgor M. Liplianin 	case CX88_BOARD_SATTRADE_ST4200:
1532363c35fcSSteven Toth 		fe0->dvb.frontend = dvb_attach(cx24116_attach,
1533ee73042cSOleg Roitburd 					       &hauppauge_hvr4000_config,
1534ee73042cSOleg Roitburd 					       &core->i2c_adap);
1535399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend)
1536363c35fcSSteven Toth 			fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage;
1537ee73042cSOleg Roitburd 		break;
153870101a27SStephan Wienczny 	case CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII:
153970101a27SStephan Wienczny 		fe0->dvb.frontend = dvb_attach(zl10353_attach,
154070101a27SStephan Wienczny 					       &cx88_terratec_cinergy_ht_pci_mkii_config,
154170101a27SStephan Wienczny 					       &core->i2c_adap);
154270101a27SStephan Wienczny 		if (fe0->dvb.frontend) {
154370101a27SStephan Wienczny 			fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
154470101a27SStephan Wienczny 			if (attach_xc3028(0x61, dev) < 0)
154570101a27SStephan Wienczny 				goto frontend_detach;
154670101a27SStephan Wienczny 		}
154770101a27SStephan Wienczny 		break;
1548b699c271SIgor M. Liplianin 	case CX88_BOARD_PROF_7301:{
1549b699c271SIgor M. Liplianin 		struct dvb_tuner_ops *tuner_ops = NULL;
1550b699c271SIgor M. Liplianin 
1551b699c271SIgor M. Liplianin 		fe0->dvb.frontend = dvb_attach(stv0900_attach,
1552b699c271SIgor M. Liplianin 					       &prof_7301_stv0900_config,
1553b699c271SIgor M. Liplianin 					       &core->i2c_adap, 0);
1554399426caSMauro Carvalho Chehab 		if (fe0->dvb.frontend) {
1555b699c271SIgor M. Liplianin 			if (!dvb_attach(stb6100_attach, fe0->dvb.frontend,
1556b699c271SIgor M. Liplianin 					&prof_7301_stb6100_config,
1557b699c271SIgor M. Liplianin 					&core->i2c_adap))
1558b699c271SIgor M. Liplianin 				goto frontend_detach;
1559b699c271SIgor M. Liplianin 
1560b699c271SIgor M. Liplianin 			tuner_ops = &fe0->dvb.frontend->ops.tuner_ops;
1561b699c271SIgor M. Liplianin 			tuner_ops->set_frequency = stb6100_set_freq;
1562b699c271SIgor M. Liplianin 			tuner_ops->get_frequency = stb6100_get_freq;
1563b699c271SIgor M. Liplianin 			tuner_ops->set_bandwidth = stb6100_set_bandw;
1564b699c271SIgor M. Liplianin 			tuner_ops->get_bandwidth = stb6100_get_bandw;
1565b699c271SIgor M. Liplianin 
1566b699c271SIgor M. Liplianin 			core->prev_set_voltage =
1567b699c271SIgor M. Liplianin 					fe0->dvb.frontend->ops.set_voltage;
1568b699c271SIgor M. Liplianin 			fe0->dvb.frontend->ops.set_voltage =
1569b699c271SIgor M. Liplianin 					tevii_dvbs_set_voltage;
1570b699c271SIgor M. Liplianin 		}
1571b699c271SIgor M. Liplianin 		break;
1572b699c271SIgor M. Liplianin 		}
15734f3ca2f1SDirk Herrendoerfer 	case CX88_BOARD_SAMSUNG_SMT_7020:
15744f3ca2f1SDirk Herrendoerfer 		dev->ts_gen_cntrl = 0x08;
15754f3ca2f1SDirk Herrendoerfer 
15764f3ca2f1SDirk Herrendoerfer 		cx_set(MO_GP0_IO, 0x0101);
15774f3ca2f1SDirk Herrendoerfer 
15784f3ca2f1SDirk Herrendoerfer 		cx_clear(MO_GP0_IO, 0x01);
15799d08ba6dSJia-Ju Bai 		msleep(100);
15804f3ca2f1SDirk Herrendoerfer 		cx_set(MO_GP0_IO, 0x01);
15819d08ba6dSJia-Ju Bai 		msleep(200);
15824f3ca2f1SDirk Herrendoerfer 
15834f3ca2f1SDirk Herrendoerfer 		fe0->dvb.frontend = dvb_attach(stv0299_attach,
15844f3ca2f1SDirk Herrendoerfer 					       &samsung_stv0299_config,
15854f3ca2f1SDirk Herrendoerfer 					       &dev->core->i2c_adap);
15864f3ca2f1SDirk Herrendoerfer 		if (fe0->dvb.frontend) {
15874f3ca2f1SDirk Herrendoerfer 			fe0->dvb.frontend->ops.tuner_ops.set_params =
15884f3ca2f1SDirk Herrendoerfer 				samsung_smt_7020_tuner_set_params;
15894f3ca2f1SDirk Herrendoerfer 			fe0->dvb.frontend->tuner_priv =
15904f3ca2f1SDirk Herrendoerfer 				&dev->core->i2c_adap;
15914f3ca2f1SDirk Herrendoerfer 			fe0->dvb.frontend->ops.set_voltage =
15924f3ca2f1SDirk Herrendoerfer 				samsung_smt_7020_set_voltage;
15934f3ca2f1SDirk Herrendoerfer 			fe0->dvb.frontend->ops.set_tone =
15944f3ca2f1SDirk Herrendoerfer 				samsung_smt_7020_set_tone;
15954f3ca2f1SDirk Herrendoerfer 		}
15964f3ca2f1SDirk Herrendoerfer 
15974f3ca2f1SDirk Herrendoerfer 		break;
1598111ac84aSSergey Ivanov 	case CX88_BOARD_TWINHAN_VP1027_DVBS:
1599111ac84aSSergey Ivanov 		dev->ts_gen_cntrl = 0x00;
1600111ac84aSSergey Ivanov 		fe0->dvb.frontend = dvb_attach(mb86a16_attach,
1601111ac84aSSergey Ivanov 					       &twinhan_vp1027,
1602111ac84aSSergey Ivanov 					       &core->i2c_adap);
1603111ac84aSSergey Ivanov 		if (fe0->dvb.frontend) {
1604111ac84aSSergey Ivanov 			core->prev_set_voltage =
1605111ac84aSSergey Ivanov 					fe0->dvb.frontend->ops.set_voltage;
1606111ac84aSSergey Ivanov 			fe0->dvb.frontend->ops.set_voltage =
1607111ac84aSSergey Ivanov 					vp1027_set_voltage;
1608111ac84aSSergey Ivanov 		}
1609111ac84aSSergey Ivanov 		break;
16104f3ca2f1SDirk Herrendoerfer 
16111da177e4SLinus Torvalds 	default:
161265bc2fe8SMauro Carvalho Chehab 		pr_err("The frontend of your DVB/ATSC card isn't supported yet\n");
16131da177e4SLinus Torvalds 		break;
16141da177e4SLinus Torvalds 	}
1615363c35fcSSteven Toth 
1616363c35fcSSteven Toth 	if ((NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend)) {
161765bc2fe8SMauro Carvalho Chehab 		pr_err("frontend initialization failed\n");
161860a5a927SDarron Broad 		goto frontend_detach;
16199507901eSMauro Carvalho Chehab 	}
1620d7cba043SMichael Krufky 	/* define general-purpose callback pointer */
1621363c35fcSSteven Toth 	fe0->dvb.frontend->callback = cx88_tuner_callback;
16229507901eSMauro Carvalho Chehab 
16236c5be74cSSteven Toth 	/* Ensure all frontends negotiate bus access */
1624363c35fcSSteven Toth 	fe0->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
1625363c35fcSSteven Toth 	if (fe1)
1626363c35fcSSteven Toth 		fe1->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
16271da177e4SLinus Torvalds 
16283aab15afSHans Verkuil 	/* Put the tuner in standby to keep it quiet */
16293aab15afSHans Verkuil 	call_all(core, tuner, standby);
163093352f5cSMauro Carvalho Chehab 
16311da177e4SLinus Torvalds 	/* register everything */
16320b6b6302SHans Verkuil 	res = vb2_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
16332773b0e9SMauro Carvalho Chehab 				   &dev->pci->dev, NULL, adapter_nr,
16342773b0e9SMauro Carvalho Chehab 				   mfe_shared);
16357b0962d3SDavid Fries 	if (res)
16367b0962d3SDavid Fries 		goto frontend_detach;
16377b0962d3SDavid Fries 	return res;
16380590d91cSMauro Carvalho Chehab 
16390590d91cSMauro Carvalho Chehab frontend_detach:
1640e32fadc4SMauro Carvalho Chehab 	core->gate_ctrl = NULL;
16410b6b6302SHans Verkuil 	vb2_dvb_dealloc_frontends(&dev->frontends);
16427b0962d3SDavid Fries 	return res;
16431da177e4SLinus Torvalds }
16441da177e4SLinus Torvalds 
16451da177e4SLinus Torvalds /* ----------------------------------------------------------- */
16461da177e4SLinus Torvalds 
16476c5be74cSSteven Toth /* CX8802 MPEG -> mini driver - We have been given the hardware */
16486c5be74cSSteven Toth static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv)
16491da177e4SLinus Torvalds {
16506c5be74cSSteven Toth 	struct cx88_core *core = drv->core;
16516c5be74cSSteven Toth 	int err = 0;
16527b61ba8fSMauro Carvalho Chehab 
165332d83efcSHarvey Harrison 	dprintk(1, "%s\n", __func__);
16546c5be74cSSteven Toth 
16556a59d64cSTrent Piepho 	switch (core->boardnr) {
16566c5be74cSSteven Toth 	case CX88_BOARD_HAUPPAUGE_HVR1300:
16576c5be74cSSteven Toth 		/* We arrive here with either the cx23416 or the cx22702
16586c5be74cSSteven Toth 		 * on the bus. Take the bus from the cx23416 and enable the
16596c5be74cSSteven Toth 		 * cx22702 demod
16606c5be74cSSteven Toth 		 */
166179392737SDarron Broad 		/* Toggle reset on cx22702 leaving i2c active */
166279392737SDarron Broad 		cx_set(MO_GP0_IO, 0x00000080);
166379392737SDarron Broad 		udelay(1000);
166479392737SDarron Broad 		cx_clear(MO_GP0_IO, 0x00000080);
166579392737SDarron Broad 		udelay(50);
166679392737SDarron Broad 		cx_set(MO_GP0_IO, 0x00000080);
166779392737SDarron Broad 		udelay(1000);
166879392737SDarron Broad 		/* enable the cx22702 pins */
16696c5be74cSSteven Toth 		cx_clear(MO_GP0_IO, 0x00000004);
16706c5be74cSSteven Toth 		udelay(1000);
16716c5be74cSSteven Toth 		break;
1672363c35fcSSteven Toth 
167392abe9eeSDarron Broad 	case CX88_BOARD_HAUPPAUGE_HVR3000:
1674363c35fcSSteven Toth 	case CX88_BOARD_HAUPPAUGE_HVR4000:
1675363c35fcSSteven Toth 		/* Toggle reset on cx22702 leaving i2c active */
167679392737SDarron Broad 		cx_set(MO_GP0_IO, 0x00000080);
1677363c35fcSSteven Toth 		udelay(1000);
1678363c35fcSSteven Toth 		cx_clear(MO_GP0_IO, 0x00000080);
1679363c35fcSSteven Toth 		udelay(50);
168079392737SDarron Broad 		cx_set(MO_GP0_IO, 0x00000080);
1681363c35fcSSteven Toth 		udelay(1000);
168279392737SDarron Broad 		switch (core->dvbdev->frontends.active_fe_id) {
168379392737SDarron Broad 		case 1: /* DVB-S/S2 Enabled */
168479392737SDarron Broad 			/* tri-state the cx22702 pins */
168579392737SDarron Broad 			cx_set(MO_GP0_IO, 0x00000004);
168679392737SDarron Broad 			/* Take the cx24116/cx24123 out of reset */
168779392737SDarron Broad 			cx_write(MO_SRST_IO, 1);
1688363c35fcSSteven Toth 			core->dvbdev->ts_gen_cntrl = 0x02; /* Parallel IO */
168979392737SDarron Broad 			break;
169079392737SDarron Broad 		case 2: /* DVB-T Enabled */
1691363c35fcSSteven Toth 			/* Put the cx24116/cx24123 into reset */
1692363c35fcSSteven Toth 			cx_write(MO_SRST_IO, 0);
169379392737SDarron Broad 			/* enable the cx22702 pins */
1694363c35fcSSteven Toth 			cx_clear(MO_GP0_IO, 0x00000004);
1695363c35fcSSteven Toth 			core->dvbdev->ts_gen_cntrl = 0x0c; /* Serial IO */
169679392737SDarron Broad 			break;
1697363c35fcSSteven Toth 		}
169879392737SDarron Broad 		udelay(1000);
1699363c35fcSSteven Toth 		break;
1700363c35fcSSteven Toth 
1701f271a3afSistvan_v@mailbox.hu 	case CX88_BOARD_WINFAST_DTV2000H_PLUS:
1702f271a3afSistvan_v@mailbox.hu 		/* set RF input to AIR for DVB-T (GPIO 16) */
1703f271a3afSistvan_v@mailbox.hu 		cx_write(MO_GP2_IO, 0x0101);
1704f271a3afSistvan_v@mailbox.hu 		break;
1705f271a3afSistvan_v@mailbox.hu 
17066c5be74cSSteven Toth 	default:
17076c5be74cSSteven Toth 		err = -ENODEV;
17086c5be74cSSteven Toth 	}
17096c5be74cSSteven Toth 	return err;
17106c5be74cSSteven Toth }
17116c5be74cSSteven Toth 
17126c5be74cSSteven Toth /* CX8802 MPEG -> mini driver - We no longer have the hardware */
17136c5be74cSSteven Toth static int cx8802_dvb_advise_release(struct cx8802_driver *drv)
17146c5be74cSSteven Toth {
17156c5be74cSSteven Toth 	struct cx88_core *core = drv->core;
17166c5be74cSSteven Toth 	int err = 0;
17177b61ba8fSMauro Carvalho Chehab 
171832d83efcSHarvey Harrison 	dprintk(1, "%s\n", __func__);
17196c5be74cSSteven Toth 
17206a59d64cSTrent Piepho 	switch (core->boardnr) {
17216c5be74cSSteven Toth 	case CX88_BOARD_HAUPPAUGE_HVR1300:
17226c5be74cSSteven Toth 		/* Do Nothing, leave the cx22702 on the bus. */
17236c5be74cSSteven Toth 		break;
1724363c35fcSSteven Toth 	case CX88_BOARD_HAUPPAUGE_HVR3000:
1725363c35fcSSteven Toth 	case CX88_BOARD_HAUPPAUGE_HVR4000:
1726363c35fcSSteven Toth 		break;
17276c5be74cSSteven Toth 	default:
17286c5be74cSSteven Toth 		err = -ENODEV;
17296c5be74cSSteven Toth 	}
17306c5be74cSSteven Toth 	return err;
17316c5be74cSSteven Toth }
17326c5be74cSSteven Toth 
17336c5be74cSSteven Toth static int cx8802_dvb_probe(struct cx8802_driver *drv)
17346c5be74cSSteven Toth {
17356c5be74cSSteven Toth 	struct cx88_core *core = drv->core;
17366c5be74cSSteven Toth 	struct cx8802_dev *dev = drv->core->dvbdev;
1737cbd82441SDarron Broad 	int err;
17380b6b6302SHans Verkuil 	struct vb2_dvb_frontend *fe;
17396e0e12f1SAndy Walls 	int i;
17401da177e4SLinus Torvalds 
174132d83efcSHarvey Harrison 	dprintk(1, "%s\n", __func__);
17426c5be74cSSteven Toth 	dprintk(1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
17436a59d64cSTrent Piepho 		core->boardnr,
17446c5be74cSSteven Toth 		core->name,
17456c5be74cSSteven Toth 		core->pci_bus,
17466c5be74cSSteven Toth 		core->pci_slot);
17471da177e4SLinus Torvalds 
17481da177e4SLinus Torvalds 	err = -ENODEV;
17496a59d64cSTrent Piepho 	if (!(core->board.mpeg & CX88_MPEG_DVB))
17501da177e4SLinus Torvalds 		goto fail_core;
17511da177e4SLinus Torvalds 
1752ecf854dfSTrent Piepho 	/* If vp3054 isn't enabled, a stub will just return 0 */
1753fc40b261SChris Pascoe 	err = vp3054_i2c_probe(dev);
17547b61ba8fSMauro Carvalho Chehab 	if (err != 0)
17556e0e12f1SAndy Walls 		goto fail_core;
1756fc40b261SChris Pascoe 
17571da177e4SLinus Torvalds 	/* dvb stuff */
175865bc2fe8SMauro Carvalho Chehab 	pr_info("cx2388x based DVB/ATSC card\n");
1759363c35fcSSteven Toth 	dev->ts_gen_cntrl = 0x0c;
1760363c35fcSSteven Toth 
17616e0e12f1SAndy Walls 	err = cx8802_alloc_frontends(dev);
17626e0e12f1SAndy Walls 	if (err)
17636e0e12f1SAndy Walls 		goto fail_core;
1764cbd82441SDarron Broad 
1765363c35fcSSteven Toth 	for (i = 1; i <= core->board.num_frontends; i++) {
17660b6b6302SHans Verkuil 		struct vb2_queue *q;
17670b6b6302SHans Verkuil 
17680b6b6302SHans Verkuil 		fe = vb2_dvb_get_frontend(&core->dvbdev->frontends, i);
1769399426caSMauro Carvalho Chehab 		if (!fe) {
177065bc2fe8SMauro Carvalho Chehab 			pr_err("%s() failed to get frontend(%d)\n",
1771cbd82441SDarron Broad 			       __func__, i);
1772e546b1efSWei Yongjun 			err = -ENODEV;
1773cbd82441SDarron Broad 			goto fail_probe;
1774363c35fcSSteven Toth 		}
17750b6b6302SHans Verkuil 		q = &fe->dvb.dvbq;
17760b6b6302SHans Verkuil 		q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
17770b6b6302SHans Verkuil 		q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
17780b6b6302SHans Verkuil 		q->gfp_flags = GFP_DMA32;
17790b6b6302SHans Verkuil 		q->min_buffers_needed = 2;
17800b6b6302SHans Verkuil 		q->drv_priv = dev;
17810b6b6302SHans Verkuil 		q->buf_struct_size = sizeof(struct cx88_buffer);
17820b6b6302SHans Verkuil 		q->ops = &dvb_qops;
17830b6b6302SHans Verkuil 		q->mem_ops = &vb2_dma_sg_memops;
17840b6b6302SHans Verkuil 		q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
17850b6b6302SHans Verkuil 		q->lock = &core->lock;
17862bc46b3aSHans Verkuil 		q->dev = &dev->pci->dev;
17870b6b6302SHans Verkuil 
17880b6b6302SHans Verkuil 		err = vb2_queue_init(q);
17890b6b6302SHans Verkuil 		if (err < 0)
17900b6b6302SHans Verkuil 			goto fail_probe;
17910b6b6302SHans Verkuil 
17920b6b6302SHans Verkuil 		/* init struct vb2_dvb */
1793363c35fcSSteven Toth 		fe->dvb.name = dev->core->name;
1794363c35fcSSteven Toth 	}
17956e0e12f1SAndy Walls 
17961da177e4SLinus Torvalds 	err = dvb_register(dev);
1797cbd82441SDarron Broad 	if (err)
1798cbd82441SDarron Broad 		/* frontends/adapter de-allocated in dvb_register */
179965bc2fe8SMauro Carvalho Chehab 		pr_err("dvb_register failed (err = %d)\n", err);
1800cbd82441SDarron Broad 	return err;
1801cbd82441SDarron Broad fail_probe:
18020b6b6302SHans Verkuil 	vb2_dvb_dealloc_frontends(&core->dvbdev->frontends);
18031da177e4SLinus Torvalds fail_core:
18041da177e4SLinus Torvalds 	return err;
18051da177e4SLinus Torvalds }
18061da177e4SLinus Torvalds 
18076c5be74cSSteven Toth static int cx8802_dvb_remove(struct cx8802_driver *drv)
18081da177e4SLinus Torvalds {
18090fcd488dSDarron Broad 	struct cx88_core *core = drv->core;
18106c5be74cSSteven Toth 	struct cx8802_dev *dev = drv->core->dvbdev;
1811611900c1SSteven Toth 
18120fcd488dSDarron Broad 	dprintk(1, "%s\n", __func__);
18130fcd488dSDarron Broad 
18140b6b6302SHans Verkuil 	vb2_dvb_unregister_bus(&dev->frontends);
18151da177e4SLinus Torvalds 
1816fc40b261SChris Pascoe 	vp3054_i2c_remove(dev);
1817fc40b261SChris Pascoe 
1818e32fadc4SMauro Carvalho Chehab 	core->gate_ctrl = NULL;
1819e32fadc4SMauro Carvalho Chehab 
18206c5be74cSSteven Toth 	return 0;
18211da177e4SLinus Torvalds }
18221da177e4SLinus Torvalds 
18236c5be74cSSteven Toth static struct cx8802_driver cx8802_dvb_driver = {
18246c5be74cSSteven Toth 	.type_id        = CX88_MPEG_DVB,
18256c5be74cSSteven Toth 	.hw_access      = CX8802_DRVCTL_SHARED,
18266c5be74cSSteven Toth 	.probe          = cx8802_dvb_probe,
18276c5be74cSSteven Toth 	.remove         = cx8802_dvb_remove,
18286c5be74cSSteven Toth 	.advise_acquire = cx8802_dvb_advise_acquire,
18296c5be74cSSteven Toth 	.advise_release = cx8802_dvb_advise_release,
18301da177e4SLinus Torvalds };
18311da177e4SLinus Torvalds 
183231d0f845SPeter Huewe static int __init dvb_init(void)
18331da177e4SLinus Torvalds {
183465bc2fe8SMauro Carvalho Chehab 	pr_info("cx2388x dvb driver version %s loaded\n", CX88_VERSION);
18356c5be74cSSteven Toth 	return cx8802_register_driver(&cx8802_dvb_driver);
18361da177e4SLinus Torvalds }
18371da177e4SLinus Torvalds 
183831d0f845SPeter Huewe static void __exit dvb_fini(void)
18391da177e4SLinus Torvalds {
18406c5be74cSSteven Toth 	cx8802_unregister_driver(&cx8802_dvb_driver);
18411da177e4SLinus Torvalds }
18421da177e4SLinus Torvalds 
18431da177e4SLinus Torvalds module_init(dvb_init);
18441da177e4SLinus Torvalds module_exit(dvb_fini);
1845