18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci//
38c2ecf20Sopenharmony_ci// DVB device driver for em28xx
48c2ecf20Sopenharmony_ci//
58c2ecf20Sopenharmony_ci// (c) 2008-2011 Mauro Carvalho Chehab <mchehab@kernel.org>
68c2ecf20Sopenharmony_ci//
78c2ecf20Sopenharmony_ci// (c) 2008 Devin Heitmueller <devin.heitmueller@gmail.com>
88c2ecf20Sopenharmony_ci//	- Fixes for the driver to properly work with HVR-950
98c2ecf20Sopenharmony_ci//	- Fixes for the driver to properly work with Pinnacle PCTV HD Pro Stick
108c2ecf20Sopenharmony_ci//	- Fixes for the driver to properly work with AMD ATI TV Wonder HD 600
118c2ecf20Sopenharmony_ci//
128c2ecf20Sopenharmony_ci// (c) 2008 Aidan Thornton <makosoft@googlemail.com>
138c2ecf20Sopenharmony_ci//
148c2ecf20Sopenharmony_ci// (c) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
158c2ecf20Sopenharmony_ci//
168c2ecf20Sopenharmony_ci// Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by:
178c2ecf20Sopenharmony_ci//	(c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
188c2ecf20Sopenharmony_ci//	(c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
198c2ecf20Sopenharmony_ci//
208c2ecf20Sopenharmony_ci// This program is free software; you can redistribute it and/or modify
218c2ecf20Sopenharmony_ci// it under the terms of the GNU General Public License as published by
228c2ecf20Sopenharmony_ci// the Free Software Foundation version 2 of the License.
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include "em28xx.h"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include <linux/kernel.h>
278c2ecf20Sopenharmony_ci#include <linux/slab.h>
288c2ecf20Sopenharmony_ci#include <linux/usb.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#include <media/v4l2-common.h>
318c2ecf20Sopenharmony_ci#include <media/dvb_demux.h>
328c2ecf20Sopenharmony_ci#include <media/dvb_net.h>
338c2ecf20Sopenharmony_ci#include <media/dmxdev.h>
348c2ecf20Sopenharmony_ci#include <media/tuner.h>
358c2ecf20Sopenharmony_ci#include "tuner-simple.h"
368c2ecf20Sopenharmony_ci#include <linux/gpio.h>
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#include "lgdt330x.h"
398c2ecf20Sopenharmony_ci#include "lgdt3305.h"
408c2ecf20Sopenharmony_ci#include "lgdt3306a.h"
418c2ecf20Sopenharmony_ci#include "zl10353.h"
428c2ecf20Sopenharmony_ci#include "s5h1409.h"
438c2ecf20Sopenharmony_ci#include "mt2060.h"
448c2ecf20Sopenharmony_ci#include "mt352.h"
458c2ecf20Sopenharmony_ci#include "mt352_priv.h" /* FIXME */
468c2ecf20Sopenharmony_ci#include "tda1002x.h"
478c2ecf20Sopenharmony_ci#include "drx39xyj/drx39xxj.h"
488c2ecf20Sopenharmony_ci#include "tda18271.h"
498c2ecf20Sopenharmony_ci#include "s921.h"
508c2ecf20Sopenharmony_ci#include "drxd.h"
518c2ecf20Sopenharmony_ci#include "cxd2820r.h"
528c2ecf20Sopenharmony_ci#include "tda18271c2dd.h"
538c2ecf20Sopenharmony_ci#include "drxk.h"
548c2ecf20Sopenharmony_ci#include "tda10071.h"
558c2ecf20Sopenharmony_ci#include "tda18212.h"
568c2ecf20Sopenharmony_ci#include "a8293.h"
578c2ecf20Sopenharmony_ci#include "qt1010.h"
588c2ecf20Sopenharmony_ci#include "mb86a20s.h"
598c2ecf20Sopenharmony_ci#include "m88ds3103.h"
608c2ecf20Sopenharmony_ci#include "ts2020.h"
618c2ecf20Sopenharmony_ci#include "si2168.h"
628c2ecf20Sopenharmony_ci#include "si2157.h"
638c2ecf20Sopenharmony_ci#include "tc90522.h"
648c2ecf20Sopenharmony_ci#include "qm1d1c0042.h"
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@kernel.org>");
678c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
688c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC " - digital TV interface");
698c2ecf20Sopenharmony_ciMODULE_VERSION(EM28XX_VERSION);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic unsigned int debug;
728c2ecf20Sopenharmony_cimodule_param(debug, int, 0644);
738c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "enable debug messages [dvb]");
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci#define dprintk(level, fmt, arg...) do {				\
788c2ecf20Sopenharmony_ci	if (debug >= level)						\
798c2ecf20Sopenharmony_ci		dev_printk(KERN_DEBUG, &dev->intf->dev,			\
808c2ecf20Sopenharmony_ci			   "dvb: " fmt, ## arg);			\
818c2ecf20Sopenharmony_ci} while (0)
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistruct em28xx_dvb {
848c2ecf20Sopenharmony_ci	struct dvb_frontend        *fe[2];
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	/* feed count management */
878c2ecf20Sopenharmony_ci	struct mutex               lock;
888c2ecf20Sopenharmony_ci	int                        nfeeds;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	/* general boilerplate stuff */
918c2ecf20Sopenharmony_ci	struct dvb_adapter         adapter;
928c2ecf20Sopenharmony_ci	struct dvb_demux           demux;
938c2ecf20Sopenharmony_ci	struct dmxdev              dmxdev;
948c2ecf20Sopenharmony_ci	struct dmx_frontend        fe_hw;
958c2ecf20Sopenharmony_ci	struct dmx_frontend        fe_mem;
968c2ecf20Sopenharmony_ci	struct dvb_net             net;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	/* Due to DRX-K - probably need changes */
998c2ecf20Sopenharmony_ci	int (*gate_ctrl)(struct dvb_frontend *fe, int gate);
1008c2ecf20Sopenharmony_ci	struct semaphore      pll_mutex;
1018c2ecf20Sopenharmony_ci	bool			dont_attach_fe1;
1028c2ecf20Sopenharmony_ci	int			lna_gpio;
1038c2ecf20Sopenharmony_ci	struct i2c_client	*i2c_client_demod;
1048c2ecf20Sopenharmony_ci	struct i2c_client	*i2c_client_tuner;
1058c2ecf20Sopenharmony_ci	struct i2c_client	*i2c_client_sec;
1068c2ecf20Sopenharmony_ci};
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic inline void print_err_status(struct em28xx *dev,
1098c2ecf20Sopenharmony_ci				    int packet, int status)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	char *errmsg = "Unknown";
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	switch (status) {
1148c2ecf20Sopenharmony_ci	case -ENOENT:
1158c2ecf20Sopenharmony_ci		errmsg = "unlinked synchronously";
1168c2ecf20Sopenharmony_ci		break;
1178c2ecf20Sopenharmony_ci	case -ECONNRESET:
1188c2ecf20Sopenharmony_ci		errmsg = "unlinked asynchronously";
1198c2ecf20Sopenharmony_ci		break;
1208c2ecf20Sopenharmony_ci	case -ENOSR:
1218c2ecf20Sopenharmony_ci		errmsg = "Buffer error (overrun)";
1228c2ecf20Sopenharmony_ci		break;
1238c2ecf20Sopenharmony_ci	case -EPIPE:
1248c2ecf20Sopenharmony_ci		errmsg = "Stalled (device not responding)";
1258c2ecf20Sopenharmony_ci		break;
1268c2ecf20Sopenharmony_ci	case -EOVERFLOW:
1278c2ecf20Sopenharmony_ci		errmsg = "Babble (bad cable?)";
1288c2ecf20Sopenharmony_ci		break;
1298c2ecf20Sopenharmony_ci	case -EPROTO:
1308c2ecf20Sopenharmony_ci		errmsg = "Bit-stuff error (bad cable?)";
1318c2ecf20Sopenharmony_ci		break;
1328c2ecf20Sopenharmony_ci	case -EILSEQ:
1338c2ecf20Sopenharmony_ci		errmsg = "CRC/Timeout (could be anything)";
1348c2ecf20Sopenharmony_ci		break;
1358c2ecf20Sopenharmony_ci	case -ETIME:
1368c2ecf20Sopenharmony_ci		errmsg = "Device does not respond";
1378c2ecf20Sopenharmony_ci		break;
1388c2ecf20Sopenharmony_ci	}
1398c2ecf20Sopenharmony_ci	if (packet < 0) {
1408c2ecf20Sopenharmony_ci		dprintk(1, "URB status %d [%s].\n", status, errmsg);
1418c2ecf20Sopenharmony_ci	} else {
1428c2ecf20Sopenharmony_ci		dprintk(1, "URB packet %d, status %d [%s].\n",
1438c2ecf20Sopenharmony_ci			packet, status, errmsg);
1448c2ecf20Sopenharmony_ci	}
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic inline int em28xx_dvb_urb_data_copy(struct em28xx *dev, struct urb *urb)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	int xfer_bulk, num_packets, i;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	if (!dev)
1528c2ecf20Sopenharmony_ci		return 0;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	if (dev->disconnected)
1558c2ecf20Sopenharmony_ci		return 0;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	if (urb->status < 0)
1588c2ecf20Sopenharmony_ci		print_err_status(dev, -1, urb->status);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	xfer_bulk = usb_pipebulk(urb->pipe);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	if (xfer_bulk) /* bulk */
1638c2ecf20Sopenharmony_ci		num_packets = 1;
1648c2ecf20Sopenharmony_ci	else /* isoc */
1658c2ecf20Sopenharmony_ci		num_packets = urb->number_of_packets;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	for (i = 0; i < num_packets; i++) {
1688c2ecf20Sopenharmony_ci		if (xfer_bulk) {
1698c2ecf20Sopenharmony_ci			if (urb->status < 0) {
1708c2ecf20Sopenharmony_ci				print_err_status(dev, i, urb->status);
1718c2ecf20Sopenharmony_ci				if (urb->status != -EPROTO)
1728c2ecf20Sopenharmony_ci					continue;
1738c2ecf20Sopenharmony_ci			}
1748c2ecf20Sopenharmony_ci			if (!urb->actual_length)
1758c2ecf20Sopenharmony_ci				continue;
1768c2ecf20Sopenharmony_ci			dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
1778c2ecf20Sopenharmony_ci					 urb->actual_length);
1788c2ecf20Sopenharmony_ci		} else {
1798c2ecf20Sopenharmony_ci			if (urb->iso_frame_desc[i].status < 0) {
1808c2ecf20Sopenharmony_ci				print_err_status(dev, i,
1818c2ecf20Sopenharmony_ci						 urb->iso_frame_desc[i].status);
1828c2ecf20Sopenharmony_ci				if (urb->iso_frame_desc[i].status != -EPROTO)
1838c2ecf20Sopenharmony_ci					continue;
1848c2ecf20Sopenharmony_ci			}
1858c2ecf20Sopenharmony_ci			if (!urb->iso_frame_desc[i].actual_length)
1868c2ecf20Sopenharmony_ci				continue;
1878c2ecf20Sopenharmony_ci			dvb_dmx_swfilter(&dev->dvb->demux,
1888c2ecf20Sopenharmony_ci					 urb->transfer_buffer +
1898c2ecf20Sopenharmony_ci					 urb->iso_frame_desc[i].offset,
1908c2ecf20Sopenharmony_ci					 urb->iso_frame_desc[i].actual_length);
1918c2ecf20Sopenharmony_ci		}
1928c2ecf20Sopenharmony_ci	}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	return 0;
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic int em28xx_start_streaming(struct em28xx_dvb *dvb)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	int rc;
2008c2ecf20Sopenharmony_ci	struct em28xx_i2c_bus *i2c_bus = dvb->adapter.priv;
2018c2ecf20Sopenharmony_ci	struct em28xx *dev = i2c_bus->dev;
2028c2ecf20Sopenharmony_ci	struct usb_device *udev = interface_to_usbdev(dev->intf);
2038c2ecf20Sopenharmony_ci	int dvb_max_packet_size, packet_multiplier, dvb_alt;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	if (dev->dvb_xfer_bulk) {
2068c2ecf20Sopenharmony_ci		if (!dev->dvb_ep_bulk)
2078c2ecf20Sopenharmony_ci			return -ENODEV;
2088c2ecf20Sopenharmony_ci		dvb_max_packet_size = 512; /* USB 2.0 spec */
2098c2ecf20Sopenharmony_ci		packet_multiplier = EM28XX_DVB_BULK_PACKET_MULTIPLIER;
2108c2ecf20Sopenharmony_ci		dvb_alt = 0;
2118c2ecf20Sopenharmony_ci	} else { /* isoc */
2128c2ecf20Sopenharmony_ci		if (!dev->dvb_ep_isoc)
2138c2ecf20Sopenharmony_ci			return -ENODEV;
2148c2ecf20Sopenharmony_ci		dvb_max_packet_size = dev->dvb_max_pkt_size_isoc;
2158c2ecf20Sopenharmony_ci		if (dvb_max_packet_size < 0)
2168c2ecf20Sopenharmony_ci			return dvb_max_packet_size;
2178c2ecf20Sopenharmony_ci		packet_multiplier = EM28XX_DVB_NUM_ISOC_PACKETS;
2188c2ecf20Sopenharmony_ci		dvb_alt = dev->dvb_alt_isoc;
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	if (!dev->board.has_dual_ts)
2228c2ecf20Sopenharmony_ci		usb_set_interface(udev, dev->ifnum, dvb_alt);
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
2258c2ecf20Sopenharmony_ci	if (rc < 0)
2268c2ecf20Sopenharmony_ci		return rc;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	dprintk(1, "Using %d buffers each with %d x %d bytes, alternate %d\n",
2298c2ecf20Sopenharmony_ci		EM28XX_DVB_NUM_BUFS,
2308c2ecf20Sopenharmony_ci		packet_multiplier,
2318c2ecf20Sopenharmony_ci		dvb_max_packet_size, dvb_alt);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	return em28xx_init_usb_xfer(dev, EM28XX_DIGITAL_MODE,
2348c2ecf20Sopenharmony_ci				    dev->dvb_xfer_bulk,
2358c2ecf20Sopenharmony_ci				    EM28XX_DVB_NUM_BUFS,
2368c2ecf20Sopenharmony_ci				    dvb_max_packet_size,
2378c2ecf20Sopenharmony_ci				    packet_multiplier,
2388c2ecf20Sopenharmony_ci				    em28xx_dvb_urb_data_copy);
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic int em28xx_stop_streaming(struct em28xx_dvb *dvb)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	struct em28xx_i2c_bus *i2c_bus = dvb->adapter.priv;
2448c2ecf20Sopenharmony_ci	struct em28xx *dev = i2c_bus->dev;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	em28xx_stop_urbs(dev);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	return 0;
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_cistatic int em28xx_start_feed(struct dvb_demux_feed *feed)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	struct dvb_demux *demux  = feed->demux;
2548c2ecf20Sopenharmony_ci	struct em28xx_dvb *dvb = demux->priv;
2558c2ecf20Sopenharmony_ci	int rc, ret;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	if (!demux->dmx.frontend)
2588c2ecf20Sopenharmony_ci		return -EINVAL;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	mutex_lock(&dvb->lock);
2618c2ecf20Sopenharmony_ci	dvb->nfeeds++;
2628c2ecf20Sopenharmony_ci	rc = dvb->nfeeds;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	if (dvb->nfeeds == 1) {
2658c2ecf20Sopenharmony_ci		ret = em28xx_start_streaming(dvb);
2668c2ecf20Sopenharmony_ci		if (ret < 0)
2678c2ecf20Sopenharmony_ci			rc = ret;
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	mutex_unlock(&dvb->lock);
2718c2ecf20Sopenharmony_ci	return rc;
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cistatic int em28xx_stop_feed(struct dvb_demux_feed *feed)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	struct dvb_demux *demux  = feed->demux;
2778c2ecf20Sopenharmony_ci	struct em28xx_dvb *dvb = demux->priv;
2788c2ecf20Sopenharmony_ci	int err = 0;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	mutex_lock(&dvb->lock);
2818c2ecf20Sopenharmony_ci	dvb->nfeeds--;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	if (!dvb->nfeeds)
2848c2ecf20Sopenharmony_ci		err = em28xx_stop_streaming(dvb);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	mutex_unlock(&dvb->lock);
2878c2ecf20Sopenharmony_ci	return err;
2888c2ecf20Sopenharmony_ci}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */
2918c2ecf20Sopenharmony_cistatic int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv;
2948c2ecf20Sopenharmony_ci	struct em28xx *dev = i2c_bus->dev;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	if (acquire)
2978c2ecf20Sopenharmony_ci		return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
2988c2ecf20Sopenharmony_ci	else
2998c2ecf20Sopenharmony_ci		return em28xx_set_mode(dev, EM28XX_SUSPEND);
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic struct lgdt330x_config em2880_lgdt3303_dev = {
3058c2ecf20Sopenharmony_ci	.demod_chip = LGDT3303,
3068c2ecf20Sopenharmony_ci};
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistatic struct lgdt3305_config em2870_lgdt3304_dev = {
3098c2ecf20Sopenharmony_ci	.i2c_addr           = 0x0e,
3108c2ecf20Sopenharmony_ci	.demod_chip         = LGDT3304,
3118c2ecf20Sopenharmony_ci	.spectral_inversion = 1,
3128c2ecf20Sopenharmony_ci	.deny_i2c_rptr      = 1,
3138c2ecf20Sopenharmony_ci	.mpeg_mode          = LGDT3305_MPEG_PARALLEL,
3148c2ecf20Sopenharmony_ci	.tpclk_edge         = LGDT3305_TPCLK_FALLING_EDGE,
3158c2ecf20Sopenharmony_ci	.tpvalid_polarity   = LGDT3305_TP_VALID_HIGH,
3168c2ecf20Sopenharmony_ci	.vsb_if_khz         = 3250,
3178c2ecf20Sopenharmony_ci	.qam_if_khz         = 4000,
3188c2ecf20Sopenharmony_ci};
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_cistatic struct lgdt3305_config em2874_lgdt3305_dev = {
3218c2ecf20Sopenharmony_ci	.i2c_addr           = 0x0e,
3228c2ecf20Sopenharmony_ci	.demod_chip         = LGDT3305,
3238c2ecf20Sopenharmony_ci	.spectral_inversion = 1,
3248c2ecf20Sopenharmony_ci	.deny_i2c_rptr      = 0,
3258c2ecf20Sopenharmony_ci	.mpeg_mode          = LGDT3305_MPEG_SERIAL,
3268c2ecf20Sopenharmony_ci	.tpclk_edge         = LGDT3305_TPCLK_FALLING_EDGE,
3278c2ecf20Sopenharmony_ci	.tpvalid_polarity   = LGDT3305_TP_VALID_HIGH,
3288c2ecf20Sopenharmony_ci	.vsb_if_khz         = 3250,
3298c2ecf20Sopenharmony_ci	.qam_if_khz         = 4000,
3308c2ecf20Sopenharmony_ci};
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cistatic struct lgdt3305_config em2874_lgdt3305_nogate_dev = {
3338c2ecf20Sopenharmony_ci	.i2c_addr           = 0x0e,
3348c2ecf20Sopenharmony_ci	.demod_chip         = LGDT3305,
3358c2ecf20Sopenharmony_ci	.spectral_inversion = 1,
3368c2ecf20Sopenharmony_ci	.deny_i2c_rptr      = 1,
3378c2ecf20Sopenharmony_ci	.mpeg_mode          = LGDT3305_MPEG_SERIAL,
3388c2ecf20Sopenharmony_ci	.tpclk_edge         = LGDT3305_TPCLK_FALLING_EDGE,
3398c2ecf20Sopenharmony_ci	.tpvalid_polarity   = LGDT3305_TP_VALID_HIGH,
3408c2ecf20Sopenharmony_ci	.vsb_if_khz         = 3600,
3418c2ecf20Sopenharmony_ci	.qam_if_khz         = 3600,
3428c2ecf20Sopenharmony_ci};
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_cistatic struct s921_config sharp_isdbt = {
3458c2ecf20Sopenharmony_ci	.demod_address = 0x30 >> 1
3468c2ecf20Sopenharmony_ci};
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_cistatic struct zl10353_config em28xx_zl10353_with_xc3028 = {
3498c2ecf20Sopenharmony_ci	.demod_address = (0x1e >> 1),
3508c2ecf20Sopenharmony_ci	.no_tuner = 1,
3518c2ecf20Sopenharmony_ci	.parallel_ts = 1,
3528c2ecf20Sopenharmony_ci	.if2 = 45600,
3538c2ecf20Sopenharmony_ci};
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_cistatic struct s5h1409_config em28xx_s5h1409_with_xc3028 = {
3568c2ecf20Sopenharmony_ci	.demod_address = 0x32 >> 1,
3578c2ecf20Sopenharmony_ci	.output_mode   = S5H1409_PARALLEL_OUTPUT,
3588c2ecf20Sopenharmony_ci	.gpio          = S5H1409_GPIO_OFF,
3598c2ecf20Sopenharmony_ci	.inversion     = S5H1409_INVERSION_OFF,
3608c2ecf20Sopenharmony_ci	.status_mode   = S5H1409_DEMODLOCKING,
3618c2ecf20Sopenharmony_ci	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK
3628c2ecf20Sopenharmony_ci};
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_cistatic struct tda18271_std_map kworld_a340_std_map = {
3658c2ecf20Sopenharmony_ci	.atsc_6   = { .if_freq = 3250, .agc_mode = 3, .std = 0,
3668c2ecf20Sopenharmony_ci		      .if_lvl = 1, .rfagc_top = 0x37, },
3678c2ecf20Sopenharmony_ci	.qam_6    = { .if_freq = 4000, .agc_mode = 3, .std = 1,
3688c2ecf20Sopenharmony_ci		      .if_lvl = 1, .rfagc_top = 0x37, },
3698c2ecf20Sopenharmony_ci};
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_cistatic struct tda18271_config kworld_a340_config = {
3728c2ecf20Sopenharmony_ci	.std_map           = &kworld_a340_std_map,
3738c2ecf20Sopenharmony_ci};
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_cistatic struct tda18271_config kworld_ub435q_v2_config = {
3768c2ecf20Sopenharmony_ci	.std_map	= &kworld_a340_std_map,
3778c2ecf20Sopenharmony_ci	.gate		= TDA18271_GATE_DIGITAL,
3788c2ecf20Sopenharmony_ci};
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_cistatic struct tda18212_config kworld_ub435q_v3_config = {
3818c2ecf20Sopenharmony_ci	.if_atsc_vsb	= 3600,
3828c2ecf20Sopenharmony_ci	.if_atsc_qam	= 3600,
3838c2ecf20Sopenharmony_ci};
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_cistatic struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = {
3868c2ecf20Sopenharmony_ci	.demod_address = (0x1e >> 1),
3878c2ecf20Sopenharmony_ci	.no_tuner = 1,
3888c2ecf20Sopenharmony_ci	.disable_i2c_gate_ctrl = 1,
3898c2ecf20Sopenharmony_ci	.parallel_ts = 1,
3908c2ecf20Sopenharmony_ci	.if2 = 45600,
3918c2ecf20Sopenharmony_ci};
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_cistatic struct drxd_config em28xx_drxd = {
3948c2ecf20Sopenharmony_ci	.demod_address = 0x70,
3958c2ecf20Sopenharmony_ci	.demod_revision = 0xa2,
3968c2ecf20Sopenharmony_ci	.pll_type = DRXD_PLL_NONE,
3978c2ecf20Sopenharmony_ci	.clock = 12000,
3988c2ecf20Sopenharmony_ci	.insert_rs_byte = 1,
3998c2ecf20Sopenharmony_ci	.IF = 42800000,
4008c2ecf20Sopenharmony_ci	.disable_i2c_gate_ctrl = 1,
4018c2ecf20Sopenharmony_ci};
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_cistatic struct drxk_config terratec_h5_drxk = {
4048c2ecf20Sopenharmony_ci	.adr = 0x29,
4058c2ecf20Sopenharmony_ci	.single_master = 1,
4068c2ecf20Sopenharmony_ci	.no_i2c_bridge = 1,
4078c2ecf20Sopenharmony_ci	.microcode_name = "dvb-usb-terratec-h5-drxk.fw",
4088c2ecf20Sopenharmony_ci	.qam_demod_parameter_count = 2,
4098c2ecf20Sopenharmony_ci};
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_cistatic struct drxk_config hauppauge_930c_drxk = {
4128c2ecf20Sopenharmony_ci	.adr = 0x29,
4138c2ecf20Sopenharmony_ci	.single_master = 1,
4148c2ecf20Sopenharmony_ci	.no_i2c_bridge = 1,
4158c2ecf20Sopenharmony_ci	.microcode_name = "dvb-usb-hauppauge-hvr930c-drxk.fw",
4168c2ecf20Sopenharmony_ci	.chunk_size = 56,
4178c2ecf20Sopenharmony_ci	.qam_demod_parameter_count = 2,
4188c2ecf20Sopenharmony_ci};
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_cistatic struct drxk_config terratec_htc_stick_drxk = {
4218c2ecf20Sopenharmony_ci	.adr = 0x29,
4228c2ecf20Sopenharmony_ci	.single_master = 1,
4238c2ecf20Sopenharmony_ci	.no_i2c_bridge = 1,
4248c2ecf20Sopenharmony_ci	.microcode_name = "dvb-usb-terratec-htc-stick-drxk.fw",
4258c2ecf20Sopenharmony_ci	.chunk_size = 54,
4268c2ecf20Sopenharmony_ci	.qam_demod_parameter_count = 2,
4278c2ecf20Sopenharmony_ci	/* Required for the antenna_gpio to disable LNA. */
4288c2ecf20Sopenharmony_ci	.antenna_dvbt = true,
4298c2ecf20Sopenharmony_ci	/* The windows driver uses the same. This will disable LNA. */
4308c2ecf20Sopenharmony_ci	.antenna_gpio = 0x6,
4318c2ecf20Sopenharmony_ci};
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_cistatic struct drxk_config maxmedia_ub425_tc_drxk = {
4348c2ecf20Sopenharmony_ci	.adr = 0x29,
4358c2ecf20Sopenharmony_ci	.single_master = 1,
4368c2ecf20Sopenharmony_ci	.no_i2c_bridge = 1,
4378c2ecf20Sopenharmony_ci	.microcode_name = "dvb-demod-drxk-01.fw",
4388c2ecf20Sopenharmony_ci	.chunk_size = 62,
4398c2ecf20Sopenharmony_ci	.qam_demod_parameter_count = 2,
4408c2ecf20Sopenharmony_ci};
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic struct drxk_config pctv_520e_drxk = {
4438c2ecf20Sopenharmony_ci	.adr = 0x29,
4448c2ecf20Sopenharmony_ci	.single_master = 1,
4458c2ecf20Sopenharmony_ci	.microcode_name = "dvb-demod-drxk-pctv.fw",
4468c2ecf20Sopenharmony_ci	.qam_demod_parameter_count = 2,
4478c2ecf20Sopenharmony_ci	.chunk_size = 58,
4488c2ecf20Sopenharmony_ci	.antenna_dvbt = true, /* disable LNA */
4498c2ecf20Sopenharmony_ci	.antenna_gpio = (1 << 2), /* disable LNA */
4508c2ecf20Sopenharmony_ci};
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_cistatic int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
4538c2ecf20Sopenharmony_ci{
4548c2ecf20Sopenharmony_ci	struct em28xx_dvb *dvb = fe->sec_priv;
4558c2ecf20Sopenharmony_ci	int status;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	if (!dvb)
4588c2ecf20Sopenharmony_ci		return -EINVAL;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	if (enable) {
4618c2ecf20Sopenharmony_ci		down(&dvb->pll_mutex);
4628c2ecf20Sopenharmony_ci		status = dvb->gate_ctrl(fe, 1);
4638c2ecf20Sopenharmony_ci	} else {
4648c2ecf20Sopenharmony_ci		status = dvb->gate_ctrl(fe, 0);
4658c2ecf20Sopenharmony_ci		up(&dvb->pll_mutex);
4668c2ecf20Sopenharmony_ci	}
4678c2ecf20Sopenharmony_ci	return status;
4688c2ecf20Sopenharmony_ci}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_cistatic void hauppauge_hvr930c_init(struct em28xx *dev)
4718c2ecf20Sopenharmony_ci{
4728c2ecf20Sopenharmony_ci	int i;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	static const struct em28xx_reg_seq hauppauge_hvr930c_init[] = {
4758c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xff,	0xff,	0x65},
4768c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xfb,	0xff,	0x32},
4778c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xff,	0xff,	0xb8},
4788c2ecf20Sopenharmony_ci		{	-1,			-1,	-1,	-1},
4798c2ecf20Sopenharmony_ci	};
4808c2ecf20Sopenharmony_ci	static const struct em28xx_reg_seq hauppauge_hvr930c_end[] = {
4818c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xef,	0xff,	0x01},
4828c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xaf,	0xff,	0x65},
4838c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xef,	0xff,	0x76},
4848c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xef,	0xff,	0x01},
4858c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xcf,	0xff,	0x0b},
4868c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xef,	0xff,	0x40},
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xcf,	0xff,	0x65},
4898c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xef,	0xff,	0x65},
4908c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xcf,	0xff,	0x0b},
4918c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xef,	0xff,	0x65},
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci		{	-1,			-1,	-1,	-1},
4948c2ecf20Sopenharmony_ci	};
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	static const struct {
4978c2ecf20Sopenharmony_ci		unsigned char r[4];
4988c2ecf20Sopenharmony_ci		int len;
4998c2ecf20Sopenharmony_ci	} regs[] = {
5008c2ecf20Sopenharmony_ci		{{ 0x06, 0x02, 0x00, 0x31 }, 4},
5018c2ecf20Sopenharmony_ci		{{ 0x01, 0x02 }, 2},
5028c2ecf20Sopenharmony_ci		{{ 0x01, 0x02, 0x00, 0xc6 }, 4},
5038c2ecf20Sopenharmony_ci		{{ 0x01, 0x00 }, 2},
5048c2ecf20Sopenharmony_ci		{{ 0x01, 0x00, 0xff, 0xaf }, 4},
5058c2ecf20Sopenharmony_ci		{{ 0x01, 0x00, 0x03, 0xa0 }, 4},
5068c2ecf20Sopenharmony_ci		{{ 0x01, 0x00 }, 2},
5078c2ecf20Sopenharmony_ci		{{ 0x01, 0x00, 0x73, 0xaf }, 4},
5088c2ecf20Sopenharmony_ci		{{ 0x04, 0x00 }, 2},
5098c2ecf20Sopenharmony_ci		{{ 0x00, 0x04 }, 2},
5108c2ecf20Sopenharmony_ci		{{ 0x00, 0x04, 0x00, 0x0a }, 4},
5118c2ecf20Sopenharmony_ci		{{ 0x04, 0x14 }, 2},
5128c2ecf20Sopenharmony_ci		{{ 0x04, 0x14, 0x00, 0x00 }, 4},
5138c2ecf20Sopenharmony_ci	};
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	em28xx_gpio_set(dev, hauppauge_hvr930c_init);
5168c2ecf20Sopenharmony_ci	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
5178c2ecf20Sopenharmony_ci	usleep_range(10000, 11000);
5188c2ecf20Sopenharmony_ci	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44);
5198c2ecf20Sopenharmony_ci	usleep_range(10000, 11000);
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(regs); i++)
5248c2ecf20Sopenharmony_ci		i2c_master_send(&dev->i2c_client[dev->def_i2c_bus],
5258c2ecf20Sopenharmony_ci				regs[i].r, regs[i].len);
5268c2ecf20Sopenharmony_ci	em28xx_gpio_set(dev, hauppauge_hvr930c_end);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	msleep(100);
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44);
5318c2ecf20Sopenharmony_ci	msleep(30);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x45);
5348c2ecf20Sopenharmony_ci	usleep_range(10000, 11000);
5358c2ecf20Sopenharmony_ci}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_cistatic void terratec_h5_init(struct em28xx *dev)
5388c2ecf20Sopenharmony_ci{
5398c2ecf20Sopenharmony_ci	int i;
5408c2ecf20Sopenharmony_ci	static const struct em28xx_reg_seq terratec_h5_init[] = {
5418c2ecf20Sopenharmony_ci		{EM2820_R08_GPIO_CTRL,		0xff,	0xff,	10},
5428c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xf6,	0xff,	100},
5438c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xf2,	0xff,	50},
5448c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xf6,	0xff,	100},
5458c2ecf20Sopenharmony_ci		{	-1,			-1,	-1,	-1},
5468c2ecf20Sopenharmony_ci	};
5478c2ecf20Sopenharmony_ci	static const struct em28xx_reg_seq terratec_h5_end[] = {
5488c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xe6,	0xff,	100},
5498c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xa6,	0xff,	50},
5508c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xe6,	0xff,	100},
5518c2ecf20Sopenharmony_ci		{	-1,			-1,	-1,	-1},
5528c2ecf20Sopenharmony_ci	};
5538c2ecf20Sopenharmony_ci	static const struct {
5548c2ecf20Sopenharmony_ci		unsigned char r[4];
5558c2ecf20Sopenharmony_ci		int len;
5568c2ecf20Sopenharmony_ci	} regs[] = {
5578c2ecf20Sopenharmony_ci		{{ 0x06, 0x02, 0x00, 0x31 }, 4},
5588c2ecf20Sopenharmony_ci		{{ 0x01, 0x02 }, 2},
5598c2ecf20Sopenharmony_ci		{{ 0x01, 0x02, 0x00, 0xc6 }, 4},
5608c2ecf20Sopenharmony_ci		{{ 0x01, 0x00 }, 2},
5618c2ecf20Sopenharmony_ci		{{ 0x01, 0x00, 0xff, 0xaf }, 4},
5628c2ecf20Sopenharmony_ci		{{ 0x01, 0x00, 0x03, 0xa0 }, 4},
5638c2ecf20Sopenharmony_ci		{{ 0x01, 0x00 }, 2},
5648c2ecf20Sopenharmony_ci		{{ 0x01, 0x00, 0x73, 0xaf }, 4},
5658c2ecf20Sopenharmony_ci		{{ 0x04, 0x00 }, 2},
5668c2ecf20Sopenharmony_ci		{{ 0x00, 0x04 }, 2},
5678c2ecf20Sopenharmony_ci		{{ 0x00, 0x04, 0x00, 0x0a }, 4},
5688c2ecf20Sopenharmony_ci		{{ 0x04, 0x14 }, 2},
5698c2ecf20Sopenharmony_ci		{{ 0x04, 0x14, 0x00, 0x00 }, 4},
5708c2ecf20Sopenharmony_ci	};
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	em28xx_gpio_set(dev, terratec_h5_init);
5738c2ecf20Sopenharmony_ci	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
5748c2ecf20Sopenharmony_ci	usleep_range(10000, 11000);
5758c2ecf20Sopenharmony_ci	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x45);
5768c2ecf20Sopenharmony_ci	usleep_range(10000, 11000);
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(regs); i++)
5818c2ecf20Sopenharmony_ci		i2c_master_send(&dev->i2c_client[dev->def_i2c_bus],
5828c2ecf20Sopenharmony_ci				regs[i].r, regs[i].len);
5838c2ecf20Sopenharmony_ci	em28xx_gpio_set(dev, terratec_h5_end);
5848c2ecf20Sopenharmony_ci};
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_cistatic void terratec_htc_stick_init(struct em28xx *dev)
5878c2ecf20Sopenharmony_ci{
5888c2ecf20Sopenharmony_ci	int i;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	/*
5918c2ecf20Sopenharmony_ci	 * GPIO configuration:
5928c2ecf20Sopenharmony_ci	 * 0xff: unknown (does not affect DVB-T).
5938c2ecf20Sopenharmony_ci	 * 0xf6: DRX-K (demodulator).
5948c2ecf20Sopenharmony_ci	 * 0xe6: unknown (does not affect DVB-T).
5958c2ecf20Sopenharmony_ci	 * 0xb6: unknown (does not affect DVB-T).
5968c2ecf20Sopenharmony_ci	 */
5978c2ecf20Sopenharmony_ci	static const struct em28xx_reg_seq terratec_htc_stick_init[] = {
5988c2ecf20Sopenharmony_ci		{EM2820_R08_GPIO_CTRL,		0xff,	0xff,	10},
5998c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xf6,	0xff,	100},
6008c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xe6,	0xff,	50},
6018c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xf6,	0xff,	100},
6028c2ecf20Sopenharmony_ci		{	-1,			-1,	-1,	-1},
6038c2ecf20Sopenharmony_ci	};
6048c2ecf20Sopenharmony_ci	static const struct em28xx_reg_seq terratec_htc_stick_end[] = {
6058c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xb6,	0xff,	100},
6068c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xf6,	0xff,	50},
6078c2ecf20Sopenharmony_ci		{	-1,			-1,	-1,	-1},
6088c2ecf20Sopenharmony_ci	};
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	/*
6118c2ecf20Sopenharmony_ci	 * Init the analog decoder (not yet supported), but
6128c2ecf20Sopenharmony_ci	 * it's probably still a good idea.
6138c2ecf20Sopenharmony_ci	 */
6148c2ecf20Sopenharmony_ci	static const struct {
6158c2ecf20Sopenharmony_ci		unsigned char r[4];
6168c2ecf20Sopenharmony_ci		int len;
6178c2ecf20Sopenharmony_ci	} regs[] = {
6188c2ecf20Sopenharmony_ci		{{ 0x06, 0x02, 0x00, 0x31 }, 4},
6198c2ecf20Sopenharmony_ci		{{ 0x01, 0x02 }, 2},
6208c2ecf20Sopenharmony_ci		{{ 0x01, 0x02, 0x00, 0xc6 }, 4},
6218c2ecf20Sopenharmony_ci		{{ 0x01, 0x00 }, 2},
6228c2ecf20Sopenharmony_ci		{{ 0x01, 0x00, 0xff, 0xaf }, 4},
6238c2ecf20Sopenharmony_ci	};
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	em28xx_gpio_set(dev, terratec_htc_stick_init);
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
6288c2ecf20Sopenharmony_ci	usleep_range(10000, 11000);
6298c2ecf20Sopenharmony_ci	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44);
6308c2ecf20Sopenharmony_ci	usleep_range(10000, 11000);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(regs); i++)
6358c2ecf20Sopenharmony_ci		i2c_master_send(&dev->i2c_client[dev->def_i2c_bus],
6368c2ecf20Sopenharmony_ci				regs[i].r, regs[i].len);
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	em28xx_gpio_set(dev, terratec_htc_stick_end);
6398c2ecf20Sopenharmony_ci};
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_cistatic void terratec_htc_usb_xs_init(struct em28xx *dev)
6428c2ecf20Sopenharmony_ci{
6438c2ecf20Sopenharmony_ci	int i;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	static const struct em28xx_reg_seq terratec_htc_usb_xs_init[] = {
6468c2ecf20Sopenharmony_ci		{EM2820_R08_GPIO_CTRL,		0xff,	0xff,	10},
6478c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xb2,	0xff,	100},
6488c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xb2,	0xff,	50},
6498c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xb6,	0xff,	100},
6508c2ecf20Sopenharmony_ci		{	-1,			-1,	-1,	-1},
6518c2ecf20Sopenharmony_ci	};
6528c2ecf20Sopenharmony_ci	static const struct em28xx_reg_seq terratec_htc_usb_xs_end[] = {
6538c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xa6,	0xff,	100},
6548c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xa6,	0xff,	50},
6558c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xe6,	0xff,	100},
6568c2ecf20Sopenharmony_ci		{	-1,			-1,	-1,	-1},
6578c2ecf20Sopenharmony_ci	};
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	/*
6608c2ecf20Sopenharmony_ci	 * Init the analog decoder (not yet supported), but
6618c2ecf20Sopenharmony_ci	 * it's probably still a good idea.
6628c2ecf20Sopenharmony_ci	 */
6638c2ecf20Sopenharmony_ci	static const struct {
6648c2ecf20Sopenharmony_ci		unsigned char r[4];
6658c2ecf20Sopenharmony_ci		int len;
6668c2ecf20Sopenharmony_ci	} regs[] = {
6678c2ecf20Sopenharmony_ci		{{ 0x06, 0x02, 0x00, 0x31 }, 4},
6688c2ecf20Sopenharmony_ci		{{ 0x01, 0x02 }, 2},
6698c2ecf20Sopenharmony_ci		{{ 0x01, 0x02, 0x00, 0xc6 }, 4},
6708c2ecf20Sopenharmony_ci		{{ 0x01, 0x00 }, 2},
6718c2ecf20Sopenharmony_ci		{{ 0x01, 0x00, 0xff, 0xaf }, 4},
6728c2ecf20Sopenharmony_ci		{{ 0x01, 0x00, 0x03, 0xa0 }, 4},
6738c2ecf20Sopenharmony_ci		{{ 0x01, 0x00 }, 2},
6748c2ecf20Sopenharmony_ci		{{ 0x01, 0x00, 0x73, 0xaf }, 4},
6758c2ecf20Sopenharmony_ci		{{ 0x04, 0x00 }, 2},
6768c2ecf20Sopenharmony_ci		{{ 0x00, 0x04 }, 2},
6778c2ecf20Sopenharmony_ci		{{ 0x00, 0x04, 0x00, 0x0a }, 4},
6788c2ecf20Sopenharmony_ci		{{ 0x04, 0x14 }, 2},
6798c2ecf20Sopenharmony_ci		{{ 0x04, 0x14, 0x00, 0x00 }, 4},
6808c2ecf20Sopenharmony_ci	};
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	em28xx_gpio_set(dev, terratec_htc_usb_xs_init);
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40);
6878c2ecf20Sopenharmony_ci	usleep_range(10000, 11000);
6888c2ecf20Sopenharmony_ci	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44);
6898c2ecf20Sopenharmony_ci	usleep_range(10000, 11000);
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(regs); i++)
6948c2ecf20Sopenharmony_ci		i2c_master_send(&dev->i2c_client[dev->def_i2c_bus],
6958c2ecf20Sopenharmony_ci				regs[i].r, regs[i].len);
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	em28xx_gpio_set(dev, terratec_htc_usb_xs_end);
6988c2ecf20Sopenharmony_ci};
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_cistatic void pctv_520e_init(struct em28xx *dev)
7018c2ecf20Sopenharmony_ci{
7028c2ecf20Sopenharmony_ci	/*
7038c2ecf20Sopenharmony_ci	 * Init AVF4910B analog decoder. Looks like I2C traffic to
7048c2ecf20Sopenharmony_ci	 * digital demodulator and tuner are routed via AVF4910B.
7058c2ecf20Sopenharmony_ci	 */
7068c2ecf20Sopenharmony_ci	int i;
7078c2ecf20Sopenharmony_ci	static const struct {
7088c2ecf20Sopenharmony_ci		unsigned char r[4];
7098c2ecf20Sopenharmony_ci		int len;
7108c2ecf20Sopenharmony_ci	} regs[] = {
7118c2ecf20Sopenharmony_ci		{{ 0x06, 0x02, 0x00, 0x31 }, 4},
7128c2ecf20Sopenharmony_ci		{{ 0x01, 0x02 }, 2},
7138c2ecf20Sopenharmony_ci		{{ 0x01, 0x02, 0x00, 0xc6 }, 4},
7148c2ecf20Sopenharmony_ci		{{ 0x01, 0x00 }, 2},
7158c2ecf20Sopenharmony_ci		{{ 0x01, 0x00, 0xff, 0xaf }, 4},
7168c2ecf20Sopenharmony_ci		{{ 0x01, 0x00, 0x03, 0xa0 }, 4},
7178c2ecf20Sopenharmony_ci		{{ 0x01, 0x00 }, 2},
7188c2ecf20Sopenharmony_ci		{{ 0x01, 0x00, 0x73, 0xaf }, 4},
7198c2ecf20Sopenharmony_ci	};
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	dev->i2c_client[dev->def_i2c_bus].addr = 0x82 >> 1; /* 0x41 */
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(regs); i++)
7248c2ecf20Sopenharmony_ci		i2c_master_send(&dev->i2c_client[dev->def_i2c_bus],
7258c2ecf20Sopenharmony_ci				regs[i].r, regs[i].len);
7268c2ecf20Sopenharmony_ci};
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_cistatic int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe)
7298c2ecf20Sopenharmony_ci{
7308c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
7318c2ecf20Sopenharmony_ci	struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv;
7328c2ecf20Sopenharmony_ci	struct em28xx *dev = i2c_bus->dev;
7338c2ecf20Sopenharmony_ci#ifdef CONFIG_GPIOLIB
7348c2ecf20Sopenharmony_ci	struct em28xx_dvb *dvb = dev->dvb;
7358c2ecf20Sopenharmony_ci	int ret;
7368c2ecf20Sopenharmony_ci	unsigned long flags;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	if (c->lna == 1)
7398c2ecf20Sopenharmony_ci		flags = GPIOF_OUT_INIT_HIGH; /* enable LNA */
7408c2ecf20Sopenharmony_ci	else
7418c2ecf20Sopenharmony_ci		flags = GPIOF_OUT_INIT_LOW; /* disable LNA */
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	ret = gpio_request_one(dvb->lna_gpio, flags, NULL);
7448c2ecf20Sopenharmony_ci	if (ret)
7458c2ecf20Sopenharmony_ci		dev_err(&dev->intf->dev, "gpio request failed %d\n", ret);
7468c2ecf20Sopenharmony_ci	else
7478c2ecf20Sopenharmony_ci		gpio_free(dvb->lna_gpio);
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	return ret;
7508c2ecf20Sopenharmony_ci#else
7518c2ecf20Sopenharmony_ci	dev_warn(&dev->intf->dev, "%s: LNA control is disabled (lna=%u)\n",
7528c2ecf20Sopenharmony_ci		 KBUILD_MODNAME, c->lna);
7538c2ecf20Sopenharmony_ci	return 0;
7548c2ecf20Sopenharmony_ci#endif
7558c2ecf20Sopenharmony_ci}
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_cistatic int em28xx_pctv_292e_set_lna(struct dvb_frontend *fe)
7588c2ecf20Sopenharmony_ci{
7598c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
7608c2ecf20Sopenharmony_ci	struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv;
7618c2ecf20Sopenharmony_ci	struct em28xx *dev = i2c_bus->dev;
7628c2ecf20Sopenharmony_ci	u8 lna;
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	if (c->lna == 1)
7658c2ecf20Sopenharmony_ci		lna = 0x01;
7668c2ecf20Sopenharmony_ci	else
7678c2ecf20Sopenharmony_ci		lna = 0x00;
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	return em28xx_write_reg_bits(dev, EM2874_R80_GPIO_P0_CTRL, lna, 0x01);
7708c2ecf20Sopenharmony_ci}
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_cistatic int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe)
7738c2ecf20Sopenharmony_ci{
7748c2ecf20Sopenharmony_ci	/* Values extracted from a USB trace of the Terratec Windows driver */
7758c2ecf20Sopenharmony_ci	static u8 clock_config[]   = { CLOCK_CTL,  0x38, 0x2c };
7768c2ecf20Sopenharmony_ci	static u8 reset[]          = { RESET,      0x80 };
7778c2ecf20Sopenharmony_ci	static u8 adc_ctl_1_cfg[]  = { ADC_CTL_1,  0x40 };
7788c2ecf20Sopenharmony_ci	static u8 agc_cfg[]        = { AGC_TARGET, 0x28, 0xa0 };
7798c2ecf20Sopenharmony_ci	static u8 input_freq_cfg[] = { INPUT_FREQ_1, 0x31, 0xb8 };
7808c2ecf20Sopenharmony_ci	static u8 rs_err_cfg[]     = { RS_ERR_PER_1, 0x00, 0x4d };
7818c2ecf20Sopenharmony_ci	static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
7828c2ecf20Sopenharmony_ci	static u8 trl_nom_cfg[]    = { TRL_NOMINAL_RATE_1, 0x64, 0x00 };
7838c2ecf20Sopenharmony_ci	static u8 tps_given_cfg[]  = { TPS_GIVEN_1, 0x40, 0x80, 0x50 };
7848c2ecf20Sopenharmony_ci	static u8 tuner_go[]       = { TUNER_GO, 0x01};
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	mt352_write(fe, clock_config,   sizeof(clock_config));
7878c2ecf20Sopenharmony_ci	usleep_range(200, 250);
7888c2ecf20Sopenharmony_ci	mt352_write(fe, reset,          sizeof(reset));
7898c2ecf20Sopenharmony_ci	mt352_write(fe, adc_ctl_1_cfg,  sizeof(adc_ctl_1_cfg));
7908c2ecf20Sopenharmony_ci	mt352_write(fe, agc_cfg,        sizeof(agc_cfg));
7918c2ecf20Sopenharmony_ci	mt352_write(fe, input_freq_cfg, sizeof(input_freq_cfg));
7928c2ecf20Sopenharmony_ci	mt352_write(fe, rs_err_cfg,     sizeof(rs_err_cfg));
7938c2ecf20Sopenharmony_ci	mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
7948c2ecf20Sopenharmony_ci	mt352_write(fe, trl_nom_cfg,    sizeof(trl_nom_cfg));
7958c2ecf20Sopenharmony_ci	mt352_write(fe, tps_given_cfg,  sizeof(tps_given_cfg));
7968c2ecf20Sopenharmony_ci	mt352_write(fe, tuner_go,       sizeof(tuner_go));
7978c2ecf20Sopenharmony_ci	return 0;
7988c2ecf20Sopenharmony_ci}
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_cistatic void px_bcud_init(struct em28xx *dev)
8018c2ecf20Sopenharmony_ci{
8028c2ecf20Sopenharmony_ci	int i;
8038c2ecf20Sopenharmony_ci	static const struct {
8048c2ecf20Sopenharmony_ci		unsigned char r[4];
8058c2ecf20Sopenharmony_ci		int len;
8068c2ecf20Sopenharmony_ci	} regs1[] = {
8078c2ecf20Sopenharmony_ci		{{ 0x0e, 0x77 }, 2},
8088c2ecf20Sopenharmony_ci		{{ 0x0f, 0x77 }, 2},
8098c2ecf20Sopenharmony_ci		{{ 0x03, 0x90 }, 2},
8108c2ecf20Sopenharmony_ci	}, regs2[] = {
8118c2ecf20Sopenharmony_ci		{{ 0x07, 0x01 }, 2},
8128c2ecf20Sopenharmony_ci		{{ 0x08, 0x10 }, 2},
8138c2ecf20Sopenharmony_ci		{{ 0x13, 0x00 }, 2},
8148c2ecf20Sopenharmony_ci		{{ 0x17, 0x00 }, 2},
8158c2ecf20Sopenharmony_ci		{{ 0x03, 0x01 }, 2},
8168c2ecf20Sopenharmony_ci		{{ 0x10, 0xb1 }, 2},
8178c2ecf20Sopenharmony_ci		{{ 0x11, 0x40 }, 2},
8188c2ecf20Sopenharmony_ci		{{ 0x85, 0x7a }, 2},
8198c2ecf20Sopenharmony_ci		{{ 0x87, 0x04 }, 2},
8208c2ecf20Sopenharmony_ci	};
8218c2ecf20Sopenharmony_ci	static const struct em28xx_reg_seq gpio[] = {
8228c2ecf20Sopenharmony_ci		{EM28XX_R06_I2C_CLK,		0x40,	0xff,	300},
8238c2ecf20Sopenharmony_ci		{EM2874_R80_GPIO_P0_CTRL,	0xfd,	0xff,	60},
8248c2ecf20Sopenharmony_ci		{EM28XX_R15_RGAIN,		0x20,	0xff,	0},
8258c2ecf20Sopenharmony_ci		{EM28XX_R16_GGAIN,		0x20,	0xff,	0},
8268c2ecf20Sopenharmony_ci		{EM28XX_R17_BGAIN,		0x20,	0xff,	0},
8278c2ecf20Sopenharmony_ci		{EM28XX_R18_ROFFSET,		0x00,	0xff,	0},
8288c2ecf20Sopenharmony_ci		{EM28XX_R19_GOFFSET,		0x00,	0xff,	0},
8298c2ecf20Sopenharmony_ci		{EM28XX_R1A_BOFFSET,		0x00,	0xff,	0},
8308c2ecf20Sopenharmony_ci		{EM28XX_R23_UOFFSET,		0x00,	0xff,	0},
8318c2ecf20Sopenharmony_ci		{EM28XX_R24_VOFFSET,		0x00,	0xff,	0},
8328c2ecf20Sopenharmony_ci		{EM28XX_R26_COMPR,		0x00,	0xff,	0},
8338c2ecf20Sopenharmony_ci		{0x13,				0x08,	0xff,	0},
8348c2ecf20Sopenharmony_ci		{EM28XX_R12_VINENABLE,		0x27,	0xff,	0},
8358c2ecf20Sopenharmony_ci		{EM28XX_R0C_USBSUSP,		0x10,	0xff,	0},
8368c2ecf20Sopenharmony_ci		{EM28XX_R27_OUTFMT,		0x00,	0xff,	0},
8378c2ecf20Sopenharmony_ci		{EM28XX_R10_VINMODE,		0x00,	0xff,	0},
8388c2ecf20Sopenharmony_ci		{EM28XX_R11_VINCTRL,		0x11,	0xff,	0},
8398c2ecf20Sopenharmony_ci		{EM2874_R50_IR_CONFIG,		0x01,	0xff,	0},
8408c2ecf20Sopenharmony_ci		{EM2874_R5F_TS_ENABLE,		0x80,	0xff,	0},
8418c2ecf20Sopenharmony_ci		{EM28XX_R06_I2C_CLK,		0x46,	0xff,	0},
8428c2ecf20Sopenharmony_ci	};
8438c2ecf20Sopenharmony_ci	em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x46);
8448c2ecf20Sopenharmony_ci	/* sleeping ISDB-T */
8458c2ecf20Sopenharmony_ci	dev->dvb->i2c_client_demod->addr = 0x14;
8468c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(regs1); i++)
8478c2ecf20Sopenharmony_ci		i2c_master_send(dev->dvb->i2c_client_demod,
8488c2ecf20Sopenharmony_ci				regs1[i].r, regs1[i].len);
8498c2ecf20Sopenharmony_ci	/* sleeping ISDB-S */
8508c2ecf20Sopenharmony_ci	dev->dvb->i2c_client_demod->addr = 0x15;
8518c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(regs2); i++)
8528c2ecf20Sopenharmony_ci		i2c_master_send(dev->dvb->i2c_client_demod, regs2[i].r,
8538c2ecf20Sopenharmony_ci				regs2[i].len);
8548c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(gpio); i++) {
8558c2ecf20Sopenharmony_ci		em28xx_write_reg_bits(dev, gpio[i].reg, gpio[i].val,
8568c2ecf20Sopenharmony_ci				      gpio[i].mask);
8578c2ecf20Sopenharmony_ci		if (gpio[i].sleep > 0)
8588c2ecf20Sopenharmony_ci			msleep(gpio[i].sleep);
8598c2ecf20Sopenharmony_ci	}
8608c2ecf20Sopenharmony_ci};
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_cistatic struct mt352_config terratec_xs_mt352_cfg = {
8638c2ecf20Sopenharmony_ci	.demod_address = (0x1e >> 1),
8648c2ecf20Sopenharmony_ci	.no_tuner = 1,
8658c2ecf20Sopenharmony_ci	.if2 = 45600,
8668c2ecf20Sopenharmony_ci	.demod_init = em28xx_mt352_terratec_xs_init,
8678c2ecf20Sopenharmony_ci};
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_cistatic struct tda10023_config em28xx_tda10023_config = {
8708c2ecf20Sopenharmony_ci	.demod_address = 0x0c,
8718c2ecf20Sopenharmony_ci	.invert = 1,
8728c2ecf20Sopenharmony_ci};
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_cistatic struct cxd2820r_config em28xx_cxd2820r_config = {
8758c2ecf20Sopenharmony_ci	.i2c_address = (0xd8 >> 1),
8768c2ecf20Sopenharmony_ci	.ts_mode = CXD2820R_TS_SERIAL,
8778c2ecf20Sopenharmony_ci};
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_cistatic struct tda18271_config em28xx_cxd2820r_tda18271_config = {
8808c2ecf20Sopenharmony_ci	.output_opt = TDA18271_OUTPUT_LT_OFF,
8818c2ecf20Sopenharmony_ci	.gate = TDA18271_GATE_DIGITAL,
8828c2ecf20Sopenharmony_ci};
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_cistatic struct zl10353_config em28xx_zl10353_no_i2c_gate_dev = {
8858c2ecf20Sopenharmony_ci	.demod_address = (0x1e >> 1),
8868c2ecf20Sopenharmony_ci	.disable_i2c_gate_ctrl = 1,
8878c2ecf20Sopenharmony_ci	.no_tuner = 1,
8888c2ecf20Sopenharmony_ci	.parallel_ts = 1,
8898c2ecf20Sopenharmony_ci};
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_cistatic struct mt2060_config em28xx_mt2060_config = {
8928c2ecf20Sopenharmony_ci	.i2c_address = 0x60,
8938c2ecf20Sopenharmony_ci};
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_cistatic struct qt1010_config em28xx_qt1010_config = {
8968c2ecf20Sopenharmony_ci	.i2c_address = 0x62
8978c2ecf20Sopenharmony_ci};
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_cistatic const struct mb86a20s_config c3tech_duo_mb86a20s_config = {
9008c2ecf20Sopenharmony_ci	.demod_address = 0x10,
9018c2ecf20Sopenharmony_ci	.is_serial = true,
9028c2ecf20Sopenharmony_ci};
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_cistatic struct tda18271_std_map mb86a20s_tda18271_config = {
9058c2ecf20Sopenharmony_ci	.dvbt_6   = { .if_freq = 4000, .agc_mode = 3, .std = 4,
9068c2ecf20Sopenharmony_ci		      .if_lvl = 1, .rfagc_top = 0x37, },
9078c2ecf20Sopenharmony_ci};
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_cistatic struct tda18271_config c3tech_duo_tda18271_config = {
9108c2ecf20Sopenharmony_ci	.std_map = &mb86a20s_tda18271_config,
9118c2ecf20Sopenharmony_ci	.gate    = TDA18271_GATE_DIGITAL,
9128c2ecf20Sopenharmony_ci	.small_i2c = TDA18271_03_BYTE_CHUNK_INIT,
9138c2ecf20Sopenharmony_ci};
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_cistatic struct tda18271_std_map drx_j_std_map = {
9168c2ecf20Sopenharmony_ci	.atsc_6   = { .if_freq = 5000, .agc_mode = 3, .std = 0, .if_lvl = 1,
9178c2ecf20Sopenharmony_ci		      .rfagc_top = 0x37, },
9188c2ecf20Sopenharmony_ci	.qam_6    = { .if_freq = 5380, .agc_mode = 3, .std = 3, .if_lvl = 1,
9198c2ecf20Sopenharmony_ci		      .rfagc_top = 0x37, },
9208c2ecf20Sopenharmony_ci};
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_cistatic struct tda18271_config pinnacle_80e_dvb_config = {
9238c2ecf20Sopenharmony_ci	.std_map = &drx_j_std_map,
9248c2ecf20Sopenharmony_ci	.gate    = TDA18271_GATE_DIGITAL,
9258c2ecf20Sopenharmony_ci	.role    = TDA18271_MASTER,
9268c2ecf20Sopenharmony_ci};
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_cistatic struct lgdt3306a_config hauppauge_01595_lgdt3306a_config = {
9298c2ecf20Sopenharmony_ci	.qam_if_khz         = 4000,
9308c2ecf20Sopenharmony_ci	.vsb_if_khz         = 3250,
9318c2ecf20Sopenharmony_ci	.spectral_inversion = 0,
9328c2ecf20Sopenharmony_ci	.deny_i2c_rptr      = 0,
9338c2ecf20Sopenharmony_ci	.mpeg_mode          = LGDT3306A_MPEG_SERIAL,
9348c2ecf20Sopenharmony_ci	.tpclk_edge         = LGDT3306A_TPCLK_RISING_EDGE,
9358c2ecf20Sopenharmony_ci	.tpvalid_polarity   = LGDT3306A_TP_VALID_HIGH,
9368c2ecf20Sopenharmony_ci	.xtalMHz            = 25,
9378c2ecf20Sopenharmony_ci};
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_cistatic noinline_for_stack int em28xx_attach_xc3028(u8 addr, struct em28xx *dev)
9428c2ecf20Sopenharmony_ci{
9438c2ecf20Sopenharmony_ci	struct dvb_frontend *fe;
9448c2ecf20Sopenharmony_ci	struct xc2028_config cfg;
9458c2ecf20Sopenharmony_ci	struct xc2028_ctrl ctl;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	memset(&cfg, 0, sizeof(cfg));
9488c2ecf20Sopenharmony_ci	cfg.i2c_adap  = &dev->i2c_adap[dev->def_i2c_bus];
9498c2ecf20Sopenharmony_ci	cfg.i2c_addr  = addr;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	memset(&ctl, 0, sizeof(ctl));
9528c2ecf20Sopenharmony_ci	em28xx_setup_xc3028(dev, &ctl);
9538c2ecf20Sopenharmony_ci	cfg.ctrl  = &ctl;
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	if (!dev->dvb->fe[0]) {
9568c2ecf20Sopenharmony_ci		dev_err(&dev->intf->dev,
9578c2ecf20Sopenharmony_ci			"dvb frontend not attached. Can't attach xc3028\n");
9588c2ecf20Sopenharmony_ci		return -EINVAL;
9598c2ecf20Sopenharmony_ci	}
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	fe = dvb_attach(xc2028_attach, dev->dvb->fe[0], &cfg);
9628c2ecf20Sopenharmony_ci	if (!fe) {
9638c2ecf20Sopenharmony_ci		dev_err(&dev->intf->dev, "xc3028 attach failed\n");
9648c2ecf20Sopenharmony_ci		dvb_frontend_detach(dev->dvb->fe[0]);
9658c2ecf20Sopenharmony_ci		dev->dvb->fe[0] = NULL;
9668c2ecf20Sopenharmony_ci		return -EINVAL;
9678c2ecf20Sopenharmony_ci	}
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	dev_info(&dev->intf->dev, "xc3028 attached\n");
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	return 0;
9728c2ecf20Sopenharmony_ci}
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci/* ------------------------------------------------------------------ */
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_cistatic int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module,
9778c2ecf20Sopenharmony_ci			       struct em28xx *dev, struct device *device)
9788c2ecf20Sopenharmony_ci{
9798c2ecf20Sopenharmony_ci	int result;
9808c2ecf20Sopenharmony_ci	bool create_rf_connector = false;
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	mutex_init(&dvb->lock);
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	/* register adapter */
9858c2ecf20Sopenharmony_ci	result = dvb_register_adapter(&dvb->adapter,
9868c2ecf20Sopenharmony_ci				      dev_name(&dev->intf->dev), module,
9878c2ecf20Sopenharmony_ci				      device, adapter_nr);
9888c2ecf20Sopenharmony_ci	if (result < 0) {
9898c2ecf20Sopenharmony_ci		dev_warn(&dev->intf->dev,
9908c2ecf20Sopenharmony_ci			 "dvb_register_adapter failed (errno = %d)\n",
9918c2ecf20Sopenharmony_ci			 result);
9928c2ecf20Sopenharmony_ci		goto fail_adapter;
9938c2ecf20Sopenharmony_ci	}
9948c2ecf20Sopenharmony_ci#ifdef CONFIG_MEDIA_CONTROLLER_DVB
9958c2ecf20Sopenharmony_ci	dvb->adapter.mdev = dev->media_dev;
9968c2ecf20Sopenharmony_ci#endif
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ci	/* Ensure all frontends negotiate bus access */
9998c2ecf20Sopenharmony_ci	dvb->fe[0]->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
10008c2ecf20Sopenharmony_ci	if (dvb->fe[1])
10018c2ecf20Sopenharmony_ci		dvb->fe[1]->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	dvb->adapter.priv = &dev->i2c_bus[dev->def_i2c_bus];
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	/* register frontend */
10068c2ecf20Sopenharmony_ci	result = dvb_register_frontend(&dvb->adapter, dvb->fe[0]);
10078c2ecf20Sopenharmony_ci	if (result < 0) {
10088c2ecf20Sopenharmony_ci		dev_warn(&dev->intf->dev,
10098c2ecf20Sopenharmony_ci			 "dvb_register_frontend failed (errno = %d)\n",
10108c2ecf20Sopenharmony_ci			 result);
10118c2ecf20Sopenharmony_ci		goto fail_frontend0;
10128c2ecf20Sopenharmony_ci	}
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	/* register 2nd frontend */
10158c2ecf20Sopenharmony_ci	if (dvb->fe[1]) {
10168c2ecf20Sopenharmony_ci		result = dvb_register_frontend(&dvb->adapter, dvb->fe[1]);
10178c2ecf20Sopenharmony_ci		if (result < 0) {
10188c2ecf20Sopenharmony_ci			dev_warn(&dev->intf->dev,
10198c2ecf20Sopenharmony_ci				 "2nd dvb_register_frontend failed (errno = %d)\n",
10208c2ecf20Sopenharmony_ci				 result);
10218c2ecf20Sopenharmony_ci			goto fail_frontend1;
10228c2ecf20Sopenharmony_ci		}
10238c2ecf20Sopenharmony_ci	}
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	/* register demux stuff */
10268c2ecf20Sopenharmony_ci	dvb->demux.dmx.capabilities =
10278c2ecf20Sopenharmony_ci		DMX_TS_FILTERING | DMX_SECTION_FILTERING |
10288c2ecf20Sopenharmony_ci		DMX_MEMORY_BASED_FILTERING;
10298c2ecf20Sopenharmony_ci	dvb->demux.priv       = dvb;
10308c2ecf20Sopenharmony_ci	dvb->demux.filternum  = 256;
10318c2ecf20Sopenharmony_ci	dvb->demux.feednum    = 256;
10328c2ecf20Sopenharmony_ci	dvb->demux.start_feed = em28xx_start_feed;
10338c2ecf20Sopenharmony_ci	dvb->demux.stop_feed  = em28xx_stop_feed;
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	result = dvb_dmx_init(&dvb->demux);
10368c2ecf20Sopenharmony_ci	if (result < 0) {
10378c2ecf20Sopenharmony_ci		dev_warn(&dev->intf->dev,
10388c2ecf20Sopenharmony_ci			 "dvb_dmx_init failed (errno = %d)\n",
10398c2ecf20Sopenharmony_ci			 result);
10408c2ecf20Sopenharmony_ci		goto fail_dmx;
10418c2ecf20Sopenharmony_ci	}
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	dvb->dmxdev.filternum    = 256;
10448c2ecf20Sopenharmony_ci	dvb->dmxdev.demux        = &dvb->demux.dmx;
10458c2ecf20Sopenharmony_ci	dvb->dmxdev.capabilities = 0;
10468c2ecf20Sopenharmony_ci	result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
10478c2ecf20Sopenharmony_ci	if (result < 0) {
10488c2ecf20Sopenharmony_ci		dev_warn(&dev->intf->dev,
10498c2ecf20Sopenharmony_ci			 "dvb_dmxdev_init failed (errno = %d)\n",
10508c2ecf20Sopenharmony_ci			 result);
10518c2ecf20Sopenharmony_ci		goto fail_dmxdev;
10528c2ecf20Sopenharmony_ci	}
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	dvb->fe_hw.source = DMX_FRONTEND_0;
10558c2ecf20Sopenharmony_ci	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
10568c2ecf20Sopenharmony_ci	if (result < 0) {
10578c2ecf20Sopenharmony_ci		dev_warn(&dev->intf->dev,
10588c2ecf20Sopenharmony_ci			 "add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
10598c2ecf20Sopenharmony_ci			 result);
10608c2ecf20Sopenharmony_ci		goto fail_fe_hw;
10618c2ecf20Sopenharmony_ci	}
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci	dvb->fe_mem.source = DMX_MEMORY_FE;
10648c2ecf20Sopenharmony_ci	result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
10658c2ecf20Sopenharmony_ci	if (result < 0) {
10668c2ecf20Sopenharmony_ci		dev_warn(&dev->intf->dev,
10678c2ecf20Sopenharmony_ci			 "add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
10688c2ecf20Sopenharmony_ci			 result);
10698c2ecf20Sopenharmony_ci		goto fail_fe_mem;
10708c2ecf20Sopenharmony_ci	}
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
10738c2ecf20Sopenharmony_ci	if (result < 0) {
10748c2ecf20Sopenharmony_ci		dev_warn(&dev->intf->dev,
10758c2ecf20Sopenharmony_ci			 "connect_frontend failed (errno = %d)\n",
10768c2ecf20Sopenharmony_ci			 result);
10778c2ecf20Sopenharmony_ci		goto fail_fe_conn;
10788c2ecf20Sopenharmony_ci	}
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	/* register network adapter */
10818c2ecf20Sopenharmony_ci	dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	/* If the analog part won't create RF connectors, DVB will do it */
10848c2ecf20Sopenharmony_ci	if (!dev->has_video || dev->tuner_type == TUNER_ABSENT)
10858c2ecf20Sopenharmony_ci		create_rf_connector = true;
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	result = dvb_create_media_graph(&dvb->adapter, create_rf_connector);
10888c2ecf20Sopenharmony_ci	if (result < 0)
10898c2ecf20Sopenharmony_ci		goto fail_create_graph;
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci	return 0;
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_cifail_create_graph:
10948c2ecf20Sopenharmony_ci	dvb_net_release(&dvb->net);
10958c2ecf20Sopenharmony_cifail_fe_conn:
10968c2ecf20Sopenharmony_ci	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
10978c2ecf20Sopenharmony_cifail_fe_mem:
10988c2ecf20Sopenharmony_ci	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
10998c2ecf20Sopenharmony_cifail_fe_hw:
11008c2ecf20Sopenharmony_ci	dvb_dmxdev_release(&dvb->dmxdev);
11018c2ecf20Sopenharmony_cifail_dmxdev:
11028c2ecf20Sopenharmony_ci	dvb_dmx_release(&dvb->demux);
11038c2ecf20Sopenharmony_cifail_dmx:
11048c2ecf20Sopenharmony_ci	if (dvb->fe[1])
11058c2ecf20Sopenharmony_ci		dvb_unregister_frontend(dvb->fe[1]);
11068c2ecf20Sopenharmony_ci	dvb_unregister_frontend(dvb->fe[0]);
11078c2ecf20Sopenharmony_cifail_frontend1:
11088c2ecf20Sopenharmony_ci	if (dvb->fe[1])
11098c2ecf20Sopenharmony_ci		dvb_frontend_detach(dvb->fe[1]);
11108c2ecf20Sopenharmony_cifail_frontend0:
11118c2ecf20Sopenharmony_ci	dvb_frontend_detach(dvb->fe[0]);
11128c2ecf20Sopenharmony_ci	dvb_unregister_adapter(&dvb->adapter);
11138c2ecf20Sopenharmony_cifail_adapter:
11148c2ecf20Sopenharmony_ci	return result;
11158c2ecf20Sopenharmony_ci}
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_cistatic void em28xx_unregister_dvb(struct em28xx_dvb *dvb)
11188c2ecf20Sopenharmony_ci{
11198c2ecf20Sopenharmony_ci	dvb_net_release(&dvb->net);
11208c2ecf20Sopenharmony_ci	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
11218c2ecf20Sopenharmony_ci	dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
11228c2ecf20Sopenharmony_ci	dvb_dmxdev_release(&dvb->dmxdev);
11238c2ecf20Sopenharmony_ci	dvb_dmx_release(&dvb->demux);
11248c2ecf20Sopenharmony_ci	if (dvb->fe[1])
11258c2ecf20Sopenharmony_ci		dvb_unregister_frontend(dvb->fe[1]);
11268c2ecf20Sopenharmony_ci	dvb_unregister_frontend(dvb->fe[0]);
11278c2ecf20Sopenharmony_ci	if (dvb->fe[1] && !dvb->dont_attach_fe1)
11288c2ecf20Sopenharmony_ci		dvb_frontend_detach(dvb->fe[1]);
11298c2ecf20Sopenharmony_ci	dvb_frontend_detach(dvb->fe[0]);
11308c2ecf20Sopenharmony_ci	dvb_unregister_adapter(&dvb->adapter);
11318c2ecf20Sopenharmony_ci}
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_cistatic int em28174_dvb_init_pctv_460e(struct em28xx *dev)
11348c2ecf20Sopenharmony_ci{
11358c2ecf20Sopenharmony_ci	struct em28xx_dvb *dvb = dev->dvb;
11368c2ecf20Sopenharmony_ci	struct tda10071_platform_data tda10071_pdata = {};
11378c2ecf20Sopenharmony_ci	struct a8293_platform_data a8293_pdata = {};
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	/* attach demod + tuner combo */
11408c2ecf20Sopenharmony_ci	tda10071_pdata.clk = 40444000; /* 40.444 MHz */
11418c2ecf20Sopenharmony_ci	tda10071_pdata.i2c_wr_max = 64;
11428c2ecf20Sopenharmony_ci	tda10071_pdata.ts_mode = TDA10071_TS_SERIAL;
11438c2ecf20Sopenharmony_ci	tda10071_pdata.pll_multiplier = 20;
11448c2ecf20Sopenharmony_ci	tda10071_pdata.tuner_i2c_addr = 0x14;
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci	dvb->i2c_client_demod = dvb_module_probe("tda10071", "tda10071_cx24118",
11478c2ecf20Sopenharmony_ci						 &dev->i2c_adap[dev->def_i2c_bus],
11488c2ecf20Sopenharmony_ci						 0x55, &tda10071_pdata);
11498c2ecf20Sopenharmony_ci	if (!dvb->i2c_client_demod)
11508c2ecf20Sopenharmony_ci		return -ENODEV;
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	dvb->fe[0] = tda10071_pdata.get_dvb_frontend(dvb->i2c_client_demod);
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	/* attach SEC */
11558c2ecf20Sopenharmony_ci	a8293_pdata.dvb_frontend = dvb->fe[0];
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci	dvb->i2c_client_sec = dvb_module_probe("a8293", NULL,
11588c2ecf20Sopenharmony_ci					       &dev->i2c_adap[dev->def_i2c_bus],
11598c2ecf20Sopenharmony_ci					       0x08, &a8293_pdata);
11608c2ecf20Sopenharmony_ci	if (!dvb->i2c_client_sec) {
11618c2ecf20Sopenharmony_ci		dvb_module_release(dvb->i2c_client_demod);
11628c2ecf20Sopenharmony_ci		return -ENODEV;
11638c2ecf20Sopenharmony_ci	}
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	return 0;
11668c2ecf20Sopenharmony_ci}
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_cistatic int em28178_dvb_init_pctv_461e(struct em28xx *dev)
11698c2ecf20Sopenharmony_ci{
11708c2ecf20Sopenharmony_ci	struct em28xx_dvb *dvb = dev->dvb;
11718c2ecf20Sopenharmony_ci	struct i2c_adapter *i2c_adapter;
11728c2ecf20Sopenharmony_ci	struct m88ds3103_platform_data m88ds3103_pdata = {};
11738c2ecf20Sopenharmony_ci	struct ts2020_config ts2020_config = {};
11748c2ecf20Sopenharmony_ci	struct a8293_platform_data a8293_pdata = {};
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci	/* attach demod */
11778c2ecf20Sopenharmony_ci	m88ds3103_pdata.clk = 27000000;
11788c2ecf20Sopenharmony_ci	m88ds3103_pdata.i2c_wr_max = 33;
11798c2ecf20Sopenharmony_ci	m88ds3103_pdata.ts_mode = M88DS3103_TS_PARALLEL;
11808c2ecf20Sopenharmony_ci	m88ds3103_pdata.ts_clk = 16000;
11818c2ecf20Sopenharmony_ci	m88ds3103_pdata.ts_clk_pol = 1;
11828c2ecf20Sopenharmony_ci	m88ds3103_pdata.agc = 0x99;
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	dvb->i2c_client_demod = dvb_module_probe("m88ds3103", NULL,
11858c2ecf20Sopenharmony_ci						 &dev->i2c_adap[dev->def_i2c_bus],
11868c2ecf20Sopenharmony_ci						 0x68, &m88ds3103_pdata);
11878c2ecf20Sopenharmony_ci	if (!dvb->i2c_client_demod)
11888c2ecf20Sopenharmony_ci		return -ENODEV;
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	dvb->fe[0] = m88ds3103_pdata.get_dvb_frontend(dvb->i2c_client_demod);
11918c2ecf20Sopenharmony_ci	i2c_adapter = m88ds3103_pdata.get_i2c_adapter(dvb->i2c_client_demod);
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	/* attach tuner */
11948c2ecf20Sopenharmony_ci	ts2020_config.fe = dvb->fe[0];
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci	dvb->i2c_client_tuner = dvb_module_probe("ts2020", "ts2022",
11978c2ecf20Sopenharmony_ci						 i2c_adapter,
11988c2ecf20Sopenharmony_ci						 0x60, &ts2020_config);
11998c2ecf20Sopenharmony_ci	if (!dvb->i2c_client_tuner) {
12008c2ecf20Sopenharmony_ci		dvb_module_release(dvb->i2c_client_demod);
12018c2ecf20Sopenharmony_ci		return -ENODEV;
12028c2ecf20Sopenharmony_ci	}
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci	/* delegate signal strength measurement to tuner */
12058c2ecf20Sopenharmony_ci	dvb->fe[0]->ops.read_signal_strength =
12068c2ecf20Sopenharmony_ci			dvb->fe[0]->ops.tuner_ops.get_rf_strength;
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	/* attach SEC */
12098c2ecf20Sopenharmony_ci	a8293_pdata.dvb_frontend = dvb->fe[0];
12108c2ecf20Sopenharmony_ci	dvb->i2c_client_sec = dvb_module_probe("a8293", NULL,
12118c2ecf20Sopenharmony_ci					       &dev->i2c_adap[dev->def_i2c_bus],
12128c2ecf20Sopenharmony_ci					       0x08, &a8293_pdata);
12138c2ecf20Sopenharmony_ci	if (!dvb->i2c_client_sec) {
12148c2ecf20Sopenharmony_ci		dvb_module_release(dvb->i2c_client_tuner);
12158c2ecf20Sopenharmony_ci		dvb_module_release(dvb->i2c_client_demod);
12168c2ecf20Sopenharmony_ci		return -ENODEV;
12178c2ecf20Sopenharmony_ci	}
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	return 0;
12208c2ecf20Sopenharmony_ci}
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_cistatic int em28178_dvb_init_pctv_461e_v2(struct em28xx *dev)
12238c2ecf20Sopenharmony_ci{
12248c2ecf20Sopenharmony_ci	struct em28xx_dvb *dvb = dev->dvb;
12258c2ecf20Sopenharmony_ci	struct i2c_adapter *i2c_adapter;
12268c2ecf20Sopenharmony_ci	struct m88ds3103_platform_data m88ds3103_pdata = {};
12278c2ecf20Sopenharmony_ci	struct ts2020_config ts2020_config = {};
12288c2ecf20Sopenharmony_ci	struct a8293_platform_data a8293_pdata = {};
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	/* attach demod */
12318c2ecf20Sopenharmony_ci	m88ds3103_pdata.clk = 27000000;
12328c2ecf20Sopenharmony_ci	m88ds3103_pdata.i2c_wr_max = 33;
12338c2ecf20Sopenharmony_ci	m88ds3103_pdata.ts_mode = M88DS3103_TS_PARALLEL;
12348c2ecf20Sopenharmony_ci	m88ds3103_pdata.ts_clk = 16000;
12358c2ecf20Sopenharmony_ci	m88ds3103_pdata.ts_clk_pol = 0;
12368c2ecf20Sopenharmony_ci	m88ds3103_pdata.agc = 0x99;
12378c2ecf20Sopenharmony_ci	m88ds3103_pdata.agc_inv = 0;
12388c2ecf20Sopenharmony_ci	m88ds3103_pdata.spec_inv = 0;
12398c2ecf20Sopenharmony_ci	dvb->i2c_client_demod = dvb_module_probe("m88ds3103", "m88ds3103b",
12408c2ecf20Sopenharmony_ci						 &dev->i2c_adap[dev->def_i2c_bus],
12418c2ecf20Sopenharmony_ci						 0x6a, &m88ds3103_pdata);
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	if (!dvb->i2c_client_demod)
12448c2ecf20Sopenharmony_ci		return -ENODEV;
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	dvb->fe[0] = m88ds3103_pdata.get_dvb_frontend(dvb->i2c_client_demod);
12478c2ecf20Sopenharmony_ci	i2c_adapter = m88ds3103_pdata.get_i2c_adapter(dvb->i2c_client_demod);
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ci	/* attach tuner */
12508c2ecf20Sopenharmony_ci	ts2020_config.fe = dvb->fe[0];
12518c2ecf20Sopenharmony_ci	dvb->i2c_client_tuner = dvb_module_probe("ts2020", "ts2022",
12528c2ecf20Sopenharmony_ci						 i2c_adapter,
12538c2ecf20Sopenharmony_ci						 0x60, &ts2020_config);
12548c2ecf20Sopenharmony_ci	if (!dvb->i2c_client_tuner) {
12558c2ecf20Sopenharmony_ci		dvb_module_release(dvb->i2c_client_demod);
12568c2ecf20Sopenharmony_ci		return -ENODEV;
12578c2ecf20Sopenharmony_ci	}
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci	/* delegate signal strength measurement to tuner */
12608c2ecf20Sopenharmony_ci	dvb->fe[0]->ops.read_signal_strength =
12618c2ecf20Sopenharmony_ci			dvb->fe[0]->ops.tuner_ops.get_rf_strength;
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	/* attach SEC */
12648c2ecf20Sopenharmony_ci	a8293_pdata.dvb_frontend = dvb->fe[0];
12658c2ecf20Sopenharmony_ci	dvb->i2c_client_sec = dvb_module_probe("a8293", NULL,
12668c2ecf20Sopenharmony_ci					       &dev->i2c_adap[dev->def_i2c_bus],
12678c2ecf20Sopenharmony_ci					       0x08, &a8293_pdata);
12688c2ecf20Sopenharmony_ci	if (!dvb->i2c_client_sec) {
12698c2ecf20Sopenharmony_ci		dvb_module_release(dvb->i2c_client_tuner);
12708c2ecf20Sopenharmony_ci		dvb_module_release(dvb->i2c_client_demod);
12718c2ecf20Sopenharmony_ci		return -ENODEV;
12728c2ecf20Sopenharmony_ci	}
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci	return 0;
12758c2ecf20Sopenharmony_ci}
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_cistatic int em28178_dvb_init_pctv_292e(struct em28xx *dev)
12788c2ecf20Sopenharmony_ci{
12798c2ecf20Sopenharmony_ci	struct em28xx_dvb *dvb = dev->dvb;
12808c2ecf20Sopenharmony_ci	struct i2c_adapter *adapter;
12818c2ecf20Sopenharmony_ci	struct si2168_config si2168_config = {};
12828c2ecf20Sopenharmony_ci	struct si2157_config si2157_config = {};
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	/* attach demod */
12858c2ecf20Sopenharmony_ci	si2168_config.i2c_adapter = &adapter;
12868c2ecf20Sopenharmony_ci	si2168_config.fe = &dvb->fe[0];
12878c2ecf20Sopenharmony_ci	si2168_config.ts_mode = SI2168_TS_PARALLEL;
12888c2ecf20Sopenharmony_ci	si2168_config.spectral_inversion = true;
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci	dvb->i2c_client_demod = dvb_module_probe("si2168", NULL,
12918c2ecf20Sopenharmony_ci						 &dev->i2c_adap[dev->def_i2c_bus],
12928c2ecf20Sopenharmony_ci						 0x64, &si2168_config);
12938c2ecf20Sopenharmony_ci	if (!dvb->i2c_client_demod)
12948c2ecf20Sopenharmony_ci		return -ENODEV;
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci	/* attach tuner */
12978c2ecf20Sopenharmony_ci	si2157_config.fe = dvb->fe[0];
12988c2ecf20Sopenharmony_ci	si2157_config.if_port = 1;
12998c2ecf20Sopenharmony_ci#ifdef CONFIG_MEDIA_CONTROLLER_DVB
13008c2ecf20Sopenharmony_ci	si2157_config.mdev = dev->media_dev;
13018c2ecf20Sopenharmony_ci#endif
13028c2ecf20Sopenharmony_ci	dvb->i2c_client_tuner = dvb_module_probe("si2157", NULL,
13038c2ecf20Sopenharmony_ci						 adapter,
13048c2ecf20Sopenharmony_ci						 0x60, &si2157_config);
13058c2ecf20Sopenharmony_ci	if (!dvb->i2c_client_tuner) {
13068c2ecf20Sopenharmony_ci		dvb_module_release(dvb->i2c_client_demod);
13078c2ecf20Sopenharmony_ci		return -ENODEV;
13088c2ecf20Sopenharmony_ci	}
13098c2ecf20Sopenharmony_ci	dvb->fe[0]->ops.set_lna = em28xx_pctv_292e_set_lna;
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci	return 0;
13128c2ecf20Sopenharmony_ci}
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_cistatic int em28178_dvb_init_terratec_t2_stick_hd(struct em28xx *dev)
13158c2ecf20Sopenharmony_ci{
13168c2ecf20Sopenharmony_ci	struct em28xx_dvb *dvb = dev->dvb;
13178c2ecf20Sopenharmony_ci	struct i2c_adapter *adapter;
13188c2ecf20Sopenharmony_ci	struct si2168_config si2168_config = {};
13198c2ecf20Sopenharmony_ci	struct si2157_config si2157_config = {};
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci	/* attach demod */
13228c2ecf20Sopenharmony_ci	si2168_config.i2c_adapter = &adapter;
13238c2ecf20Sopenharmony_ci	si2168_config.fe = &dvb->fe[0];
13248c2ecf20Sopenharmony_ci	si2168_config.ts_mode = SI2168_TS_PARALLEL;
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci	dvb->i2c_client_demod = dvb_module_probe("si2168", NULL,
13278c2ecf20Sopenharmony_ci						 &dev->i2c_adap[dev->def_i2c_bus],
13288c2ecf20Sopenharmony_ci						 0x64, &si2168_config);
13298c2ecf20Sopenharmony_ci	if (!dvb->i2c_client_demod)
13308c2ecf20Sopenharmony_ci		return -ENODEV;
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	/* attach tuner */
13338c2ecf20Sopenharmony_ci	memset(&si2157_config, 0, sizeof(si2157_config));
13348c2ecf20Sopenharmony_ci	si2157_config.fe = dvb->fe[0];
13358c2ecf20Sopenharmony_ci	si2157_config.if_port = 0;
13368c2ecf20Sopenharmony_ci#ifdef CONFIG_MEDIA_CONTROLLER_DVB
13378c2ecf20Sopenharmony_ci	si2157_config.mdev = dev->media_dev;
13388c2ecf20Sopenharmony_ci#endif
13398c2ecf20Sopenharmony_ci	dvb->i2c_client_tuner = dvb_module_probe("si2157", "si2146",
13408c2ecf20Sopenharmony_ci						 adapter,
13418c2ecf20Sopenharmony_ci						 0x60, &si2157_config);
13428c2ecf20Sopenharmony_ci	if (!dvb->i2c_client_tuner) {
13438c2ecf20Sopenharmony_ci		dvb_module_release(dvb->i2c_client_demod);
13448c2ecf20Sopenharmony_ci		return -ENODEV;
13458c2ecf20Sopenharmony_ci	}
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	return 0;
13488c2ecf20Sopenharmony_ci}
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_cistatic int em28178_dvb_init_plex_px_bcud(struct em28xx *dev)
13518c2ecf20Sopenharmony_ci{
13528c2ecf20Sopenharmony_ci	struct em28xx_dvb *dvb = dev->dvb;
13538c2ecf20Sopenharmony_ci	struct tc90522_config tc90522_config = {};
13548c2ecf20Sopenharmony_ci	struct qm1d1c0042_config qm1d1c0042_config = {};
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	/* attach demod */
13578c2ecf20Sopenharmony_ci	dvb->i2c_client_demod = dvb_module_probe("tc90522", "tc90522sat",
13588c2ecf20Sopenharmony_ci						 &dev->i2c_adap[dev->def_i2c_bus],
13598c2ecf20Sopenharmony_ci						 0x15, &tc90522_config);
13608c2ecf20Sopenharmony_ci	if (!dvb->i2c_client_demod)
13618c2ecf20Sopenharmony_ci		return -ENODEV;
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci	/* attach tuner */
13648c2ecf20Sopenharmony_ci	qm1d1c0042_config.fe = tc90522_config.fe;
13658c2ecf20Sopenharmony_ci	qm1d1c0042_config.lpf = 1;
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	dvb->i2c_client_tuner = dvb_module_probe("qm1d1c0042", NULL,
13688c2ecf20Sopenharmony_ci						 tc90522_config.tuner_i2c,
13698c2ecf20Sopenharmony_ci						 0x61, &qm1d1c0042_config);
13708c2ecf20Sopenharmony_ci	if (!dvb->i2c_client_tuner) {
13718c2ecf20Sopenharmony_ci		dvb_module_release(dvb->i2c_client_demod);
13728c2ecf20Sopenharmony_ci		return -ENODEV;
13738c2ecf20Sopenharmony_ci	}
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	dvb->fe[0] = tc90522_config.fe;
13768c2ecf20Sopenharmony_ci	px_bcud_init(dev);
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	return 0;
13798c2ecf20Sopenharmony_ci}
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_cistatic int em28174_dvb_init_hauppauge_wintv_dualhd_dvb(struct em28xx *dev)
13828c2ecf20Sopenharmony_ci{
13838c2ecf20Sopenharmony_ci	struct em28xx_dvb *dvb = dev->dvb;
13848c2ecf20Sopenharmony_ci	struct i2c_adapter *adapter;
13858c2ecf20Sopenharmony_ci	struct si2168_config si2168_config = {};
13868c2ecf20Sopenharmony_ci	struct si2157_config si2157_config = {};
13878c2ecf20Sopenharmony_ci	unsigned char addr;
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	/* attach demod */
13908c2ecf20Sopenharmony_ci	si2168_config.i2c_adapter = &adapter;
13918c2ecf20Sopenharmony_ci	si2168_config.fe = &dvb->fe[0];
13928c2ecf20Sopenharmony_ci	si2168_config.ts_mode = SI2168_TS_SERIAL;
13938c2ecf20Sopenharmony_ci	si2168_config.spectral_inversion = true;
13948c2ecf20Sopenharmony_ci	addr = (dev->ts == PRIMARY_TS) ? 0x64 : 0x67;
13958c2ecf20Sopenharmony_ci
13968c2ecf20Sopenharmony_ci	dvb->i2c_client_demod = dvb_module_probe("si2168", NULL,
13978c2ecf20Sopenharmony_ci						 &dev->i2c_adap[dev->def_i2c_bus],
13988c2ecf20Sopenharmony_ci						 addr, &si2168_config);
13998c2ecf20Sopenharmony_ci	if (!dvb->i2c_client_demod)
14008c2ecf20Sopenharmony_ci		return -ENODEV;
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	/* attach tuner */
14038c2ecf20Sopenharmony_ci	memset(&si2157_config, 0, sizeof(si2157_config));
14048c2ecf20Sopenharmony_ci	si2157_config.fe = dvb->fe[0];
14058c2ecf20Sopenharmony_ci	si2157_config.if_port = 1;
14068c2ecf20Sopenharmony_ci#ifdef CONFIG_MEDIA_CONTROLLER_DVB
14078c2ecf20Sopenharmony_ci	si2157_config.mdev = dev->media_dev;
14088c2ecf20Sopenharmony_ci#endif
14098c2ecf20Sopenharmony_ci	addr = (dev->ts == PRIMARY_TS) ? 0x60 : 0x63;
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci	dvb->i2c_client_tuner = dvb_module_probe("si2157", NULL,
14128c2ecf20Sopenharmony_ci						 adapter,
14138c2ecf20Sopenharmony_ci						 addr, &si2157_config);
14148c2ecf20Sopenharmony_ci	if (!dvb->i2c_client_tuner) {
14158c2ecf20Sopenharmony_ci		dvb_module_release(dvb->i2c_client_demod);
14168c2ecf20Sopenharmony_ci		return -ENODEV;
14178c2ecf20Sopenharmony_ci	}
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci	return 0;
14208c2ecf20Sopenharmony_ci}
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_cistatic int em28174_dvb_init_hauppauge_wintv_dualhd_01595(struct em28xx *dev)
14238c2ecf20Sopenharmony_ci{
14248c2ecf20Sopenharmony_ci	struct em28xx_dvb *dvb = dev->dvb;
14258c2ecf20Sopenharmony_ci	struct i2c_adapter *adapter;
14268c2ecf20Sopenharmony_ci	struct lgdt3306a_config lgdt3306a_config =  {};
14278c2ecf20Sopenharmony_ci	struct si2157_config si2157_config = {};
14288c2ecf20Sopenharmony_ci	unsigned char addr;
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	/* attach demod */
14318c2ecf20Sopenharmony_ci	lgdt3306a_config = hauppauge_01595_lgdt3306a_config;
14328c2ecf20Sopenharmony_ci	lgdt3306a_config.fe = &dvb->fe[0];
14338c2ecf20Sopenharmony_ci	lgdt3306a_config.i2c_adapter = &adapter;
14348c2ecf20Sopenharmony_ci	addr = (dev->ts == PRIMARY_TS) ? 0x59 : 0x0e;
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	dvb->i2c_client_demod = dvb_module_probe("lgdt3306a", NULL,
14378c2ecf20Sopenharmony_ci						 &dev->i2c_adap[dev->def_i2c_bus],
14388c2ecf20Sopenharmony_ci						 addr, &lgdt3306a_config);
14398c2ecf20Sopenharmony_ci	if (!dvb->i2c_client_demod)
14408c2ecf20Sopenharmony_ci		return -ENODEV;
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci	/* attach tuner */
14438c2ecf20Sopenharmony_ci	si2157_config.fe = dvb->fe[0];
14448c2ecf20Sopenharmony_ci	si2157_config.if_port = 1;
14458c2ecf20Sopenharmony_ci	si2157_config.inversion = 1;
14468c2ecf20Sopenharmony_ci#ifdef CONFIG_MEDIA_CONTROLLER_DVB
14478c2ecf20Sopenharmony_ci	si2157_config.mdev = dev->media_dev;
14488c2ecf20Sopenharmony_ci#endif
14498c2ecf20Sopenharmony_ci	addr = (dev->ts == PRIMARY_TS) ? 0x60 : 0x62;
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci	dvb->i2c_client_tuner = dvb_module_probe("si2157", NULL,
14528c2ecf20Sopenharmony_ci						 adapter,
14538c2ecf20Sopenharmony_ci						 addr, &si2157_config);
14548c2ecf20Sopenharmony_ci	if (!dvb->i2c_client_tuner) {
14558c2ecf20Sopenharmony_ci		dvb_module_release(dvb->i2c_client_demod);
14568c2ecf20Sopenharmony_ci		return -ENODEV;
14578c2ecf20Sopenharmony_ci	}
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci	return 0;
14608c2ecf20Sopenharmony_ci}
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_cistatic int em28xx_dvb_init(struct em28xx *dev)
14638c2ecf20Sopenharmony_ci{
14648c2ecf20Sopenharmony_ci	int result = 0, dvb_alt = 0;
14658c2ecf20Sopenharmony_ci	struct em28xx_dvb *dvb;
14668c2ecf20Sopenharmony_ci	struct usb_device *udev;
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci	if (dev->is_audio_only) {
14698c2ecf20Sopenharmony_ci		/* Shouldn't initialize IR for this interface */
14708c2ecf20Sopenharmony_ci		return 0;
14718c2ecf20Sopenharmony_ci	}
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	if (!dev->board.has_dvb) {
14748c2ecf20Sopenharmony_ci		/* This device does not support the extension */
14758c2ecf20Sopenharmony_ci		return 0;
14768c2ecf20Sopenharmony_ci	}
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci	dev_info(&dev->intf->dev, "Binding DVB extension\n");
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci	dvb = kzalloc(sizeof(*dvb), GFP_KERNEL);
14818c2ecf20Sopenharmony_ci	if (!dvb)
14828c2ecf20Sopenharmony_ci		return -ENOMEM;
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	dev->dvb = dvb;
14858c2ecf20Sopenharmony_ci	dvb->fe[0] = NULL;
14868c2ecf20Sopenharmony_ci	dvb->fe[1] = NULL;
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci	/* pre-allocate DVB usb transfer buffers */
14898c2ecf20Sopenharmony_ci	if (dev->dvb_xfer_bulk) {
14908c2ecf20Sopenharmony_ci		result = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
14918c2ecf20Sopenharmony_ci					   dev->dvb_xfer_bulk,
14928c2ecf20Sopenharmony_ci					   EM28XX_DVB_NUM_BUFS,
14938c2ecf20Sopenharmony_ci					   512,
14948c2ecf20Sopenharmony_ci					   EM28XX_DVB_BULK_PACKET_MULTIPLIER);
14958c2ecf20Sopenharmony_ci	} else {
14968c2ecf20Sopenharmony_ci		result = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
14978c2ecf20Sopenharmony_ci					   dev->dvb_xfer_bulk,
14988c2ecf20Sopenharmony_ci					   EM28XX_DVB_NUM_BUFS,
14998c2ecf20Sopenharmony_ci					   dev->dvb_max_pkt_size_isoc,
15008c2ecf20Sopenharmony_ci					   EM28XX_DVB_NUM_ISOC_PACKETS);
15018c2ecf20Sopenharmony_ci	}
15028c2ecf20Sopenharmony_ci	if (result) {
15038c2ecf20Sopenharmony_ci		dev_err(&dev->intf->dev,
15048c2ecf20Sopenharmony_ci			"failed to pre-allocate USB transfer buffers for DVB.\n");
15058c2ecf20Sopenharmony_ci		kfree(dvb);
15068c2ecf20Sopenharmony_ci		dev->dvb = NULL;
15078c2ecf20Sopenharmony_ci		return result;
15088c2ecf20Sopenharmony_ci	}
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci	mutex_lock(&dev->lock);
15118c2ecf20Sopenharmony_ci	em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
15128c2ecf20Sopenharmony_ci	/* init frontend */
15138c2ecf20Sopenharmony_ci	switch (dev->model) {
15148c2ecf20Sopenharmony_ci	case EM2874_BOARD_LEADERSHIP_ISDBT:
15158c2ecf20Sopenharmony_ci		dvb->fe[0] = dvb_attach(s921_attach,
15168c2ecf20Sopenharmony_ci					&sharp_isdbt,
15178c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus]);
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci		if (!dvb->fe[0]) {
15208c2ecf20Sopenharmony_ci			result = -EINVAL;
15218c2ecf20Sopenharmony_ci			goto out_free;
15228c2ecf20Sopenharmony_ci		}
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_ci		break;
15258c2ecf20Sopenharmony_ci	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
15268c2ecf20Sopenharmony_ci	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
15278c2ecf20Sopenharmony_ci	case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
15288c2ecf20Sopenharmony_ci	case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
15298c2ecf20Sopenharmony_ci		dvb->fe[0] = dvb_attach(lgdt330x_attach,
15308c2ecf20Sopenharmony_ci					&em2880_lgdt3303_dev,
15318c2ecf20Sopenharmony_ci					0x0e,
15328c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus]);
15338c2ecf20Sopenharmony_ci		if (em28xx_attach_xc3028(0x61, dev) < 0) {
15348c2ecf20Sopenharmony_ci			result = -EINVAL;
15358c2ecf20Sopenharmony_ci			goto out_free;
15368c2ecf20Sopenharmony_ci		}
15378c2ecf20Sopenharmony_ci		break;
15388c2ecf20Sopenharmony_ci	case EM2880_BOARD_KWORLD_DVB_310U:
15398c2ecf20Sopenharmony_ci		dvb->fe[0] = dvb_attach(zl10353_attach,
15408c2ecf20Sopenharmony_ci					&em28xx_zl10353_with_xc3028,
15418c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus]);
15428c2ecf20Sopenharmony_ci		if (em28xx_attach_xc3028(0x61, dev) < 0) {
15438c2ecf20Sopenharmony_ci			result = -EINVAL;
15448c2ecf20Sopenharmony_ci			goto out_free;
15458c2ecf20Sopenharmony_ci		}
15468c2ecf20Sopenharmony_ci		break;
15478c2ecf20Sopenharmony_ci	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
15488c2ecf20Sopenharmony_ci	case EM2882_BOARD_TERRATEC_HYBRID_XS:
15498c2ecf20Sopenharmony_ci	case EM2880_BOARD_EMPIRE_DUAL_TV:
15508c2ecf20Sopenharmony_ci	case EM2882_BOARD_ZOLID_HYBRID_TV_STICK:
15518c2ecf20Sopenharmony_ci		dvb->fe[0] = dvb_attach(zl10353_attach,
15528c2ecf20Sopenharmony_ci					&em28xx_zl10353_xc3028_no_i2c_gate,
15538c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus]);
15548c2ecf20Sopenharmony_ci		if (em28xx_attach_xc3028(0x61, dev) < 0) {
15558c2ecf20Sopenharmony_ci			result = -EINVAL;
15568c2ecf20Sopenharmony_ci			goto out_free;
15578c2ecf20Sopenharmony_ci		}
15588c2ecf20Sopenharmony_ci		break;
15598c2ecf20Sopenharmony_ci	case EM2880_BOARD_TERRATEC_HYBRID_XS:
15608c2ecf20Sopenharmony_ci	case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
15618c2ecf20Sopenharmony_ci	case EM2881_BOARD_PINNACLE_HYBRID_PRO:
15628c2ecf20Sopenharmony_ci	case EM2882_BOARD_DIKOM_DK300:
15638c2ecf20Sopenharmony_ci	case EM2882_BOARD_KWORLD_VS_DVBT:
15648c2ecf20Sopenharmony_ci		/*
15658c2ecf20Sopenharmony_ci		 * Those boards could have either a zl10353 or a mt352.
15668c2ecf20Sopenharmony_ci		 * If the chip id isn't for zl10353, try mt352.
15678c2ecf20Sopenharmony_ci		 */
15688c2ecf20Sopenharmony_ci		dvb->fe[0] = dvb_attach(zl10353_attach,
15698c2ecf20Sopenharmony_ci					&em28xx_zl10353_xc3028_no_i2c_gate,
15708c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus]);
15718c2ecf20Sopenharmony_ci		if (!dvb->fe[0])
15728c2ecf20Sopenharmony_ci			dvb->fe[0] = dvb_attach(mt352_attach,
15738c2ecf20Sopenharmony_ci						&terratec_xs_mt352_cfg,
15748c2ecf20Sopenharmony_ci						&dev->i2c_adap[dev->def_i2c_bus]);
15758c2ecf20Sopenharmony_ci
15768c2ecf20Sopenharmony_ci		if (em28xx_attach_xc3028(0x61, dev) < 0) {
15778c2ecf20Sopenharmony_ci			result = -EINVAL;
15788c2ecf20Sopenharmony_ci			goto out_free;
15798c2ecf20Sopenharmony_ci		}
15808c2ecf20Sopenharmony_ci		break;
15818c2ecf20Sopenharmony_ci	case EM2870_BOARD_TERRATEC_XS_MT2060:
15828c2ecf20Sopenharmony_ci		dvb->fe[0] = dvb_attach(zl10353_attach,
15838c2ecf20Sopenharmony_ci					&em28xx_zl10353_no_i2c_gate_dev,
15848c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus]);
15858c2ecf20Sopenharmony_ci		if (dvb->fe[0]) {
15868c2ecf20Sopenharmony_ci			dvb_attach(mt2060_attach, dvb->fe[0],
15878c2ecf20Sopenharmony_ci				   &dev->i2c_adap[dev->def_i2c_bus],
15888c2ecf20Sopenharmony_ci				   &em28xx_mt2060_config, 1220);
15898c2ecf20Sopenharmony_ci		}
15908c2ecf20Sopenharmony_ci		break;
15918c2ecf20Sopenharmony_ci	case EM2870_BOARD_KWORLD_355U:
15928c2ecf20Sopenharmony_ci		dvb->fe[0] = dvb_attach(zl10353_attach,
15938c2ecf20Sopenharmony_ci					&em28xx_zl10353_no_i2c_gate_dev,
15948c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus]);
15958c2ecf20Sopenharmony_ci		if (dvb->fe[0])
15968c2ecf20Sopenharmony_ci			dvb_attach(qt1010_attach, dvb->fe[0],
15978c2ecf20Sopenharmony_ci				   &dev->i2c_adap[dev->def_i2c_bus],
15988c2ecf20Sopenharmony_ci				   &em28xx_qt1010_config);
15998c2ecf20Sopenharmony_ci		break;
16008c2ecf20Sopenharmony_ci	case EM2883_BOARD_KWORLD_HYBRID_330U:
16018c2ecf20Sopenharmony_ci	case EM2882_BOARD_EVGA_INDTUBE:
16028c2ecf20Sopenharmony_ci		dvb->fe[0] = dvb_attach(s5h1409_attach,
16038c2ecf20Sopenharmony_ci					&em28xx_s5h1409_with_xc3028,
16048c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus]);
16058c2ecf20Sopenharmony_ci		if (em28xx_attach_xc3028(0x61, dev) < 0) {
16068c2ecf20Sopenharmony_ci			result = -EINVAL;
16078c2ecf20Sopenharmony_ci			goto out_free;
16088c2ecf20Sopenharmony_ci		}
16098c2ecf20Sopenharmony_ci		break;
16108c2ecf20Sopenharmony_ci	case EM2882_BOARD_KWORLD_ATSC_315U:
16118c2ecf20Sopenharmony_ci		dvb->fe[0] = dvb_attach(lgdt330x_attach,
16128c2ecf20Sopenharmony_ci					&em2880_lgdt3303_dev,
16138c2ecf20Sopenharmony_ci					0x0e,
16148c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus]);
16158c2ecf20Sopenharmony_ci		if (dvb->fe[0]) {
16168c2ecf20Sopenharmony_ci			if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
16178c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus],
16188c2ecf20Sopenharmony_ci					0x61, TUNER_THOMSON_DTT761X)) {
16198c2ecf20Sopenharmony_ci				result = -EINVAL;
16208c2ecf20Sopenharmony_ci				goto out_free;
16218c2ecf20Sopenharmony_ci			}
16228c2ecf20Sopenharmony_ci		}
16238c2ecf20Sopenharmony_ci		break;
16248c2ecf20Sopenharmony_ci	case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
16258c2ecf20Sopenharmony_ci	case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
16268c2ecf20Sopenharmony_ci		dvb->fe[0] = dvb_attach(drxd_attach, &em28xx_drxd, NULL,
16278c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus],
16288c2ecf20Sopenharmony_ci					&dev->intf->dev);
16298c2ecf20Sopenharmony_ci		if (em28xx_attach_xc3028(0x61, dev) < 0) {
16308c2ecf20Sopenharmony_ci			result = -EINVAL;
16318c2ecf20Sopenharmony_ci			goto out_free;
16328c2ecf20Sopenharmony_ci		}
16338c2ecf20Sopenharmony_ci		break;
16348c2ecf20Sopenharmony_ci	case EM2870_BOARD_REDDO_DVB_C_USB_BOX:
16358c2ecf20Sopenharmony_ci		/* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */
16368c2ecf20Sopenharmony_ci		dvb->fe[0] = dvb_attach(tda10023_attach,
16378c2ecf20Sopenharmony_ci					&em28xx_tda10023_config,
16388c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus],
16398c2ecf20Sopenharmony_ci					0x48);
16408c2ecf20Sopenharmony_ci		if (dvb->fe[0]) {
16418c2ecf20Sopenharmony_ci			if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
16428c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus],
16438c2ecf20Sopenharmony_ci					0x60, TUNER_PHILIPS_CU1216L)) {
16448c2ecf20Sopenharmony_ci				result = -EINVAL;
16458c2ecf20Sopenharmony_ci				goto out_free;
16468c2ecf20Sopenharmony_ci			}
16478c2ecf20Sopenharmony_ci		}
16488c2ecf20Sopenharmony_ci		break;
16498c2ecf20Sopenharmony_ci	case EM2870_BOARD_KWORLD_A340:
16508c2ecf20Sopenharmony_ci		dvb->fe[0] = dvb_attach(lgdt3305_attach,
16518c2ecf20Sopenharmony_ci					&em2870_lgdt3304_dev,
16528c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus]);
16538c2ecf20Sopenharmony_ci		if (!dvb->fe[0]) {
16548c2ecf20Sopenharmony_ci			result = -EINVAL;
16558c2ecf20Sopenharmony_ci			goto out_free;
16568c2ecf20Sopenharmony_ci		}
16578c2ecf20Sopenharmony_ci		if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
16588c2ecf20Sopenharmony_ci				&dev->i2c_adap[dev->def_i2c_bus],
16598c2ecf20Sopenharmony_ci				&kworld_a340_config)) {
16608c2ecf20Sopenharmony_ci			dvb_frontend_detach(dvb->fe[0]);
16618c2ecf20Sopenharmony_ci			result = -EINVAL;
16628c2ecf20Sopenharmony_ci			goto out_free;
16638c2ecf20Sopenharmony_ci		}
16648c2ecf20Sopenharmony_ci		break;
16658c2ecf20Sopenharmony_ci	case EM28174_BOARD_PCTV_290E:
16668c2ecf20Sopenharmony_ci		/* set default GPIO0 for LNA, used if GPIOLIB is undefined */
16678c2ecf20Sopenharmony_ci		dvb->lna_gpio = CXD2820R_GPIO_E | CXD2820R_GPIO_O |
16688c2ecf20Sopenharmony_ci				CXD2820R_GPIO_L;
16698c2ecf20Sopenharmony_ci		dvb->fe[0] = dvb_attach(cxd2820r_attach,
16708c2ecf20Sopenharmony_ci					&em28xx_cxd2820r_config,
16718c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus],
16728c2ecf20Sopenharmony_ci					&dvb->lna_gpio);
16738c2ecf20Sopenharmony_ci		if (dvb->fe[0]) {
16748c2ecf20Sopenharmony_ci			/* FE 0 attach tuner */
16758c2ecf20Sopenharmony_ci			if (!dvb_attach(tda18271_attach,
16768c2ecf20Sopenharmony_ci					dvb->fe[0],
16778c2ecf20Sopenharmony_ci					0x60,
16788c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus],
16798c2ecf20Sopenharmony_ci					&em28xx_cxd2820r_tda18271_config)) {
16808c2ecf20Sopenharmony_ci				dvb_frontend_detach(dvb->fe[0]);
16818c2ecf20Sopenharmony_ci				result = -EINVAL;
16828c2ecf20Sopenharmony_ci				goto out_free;
16838c2ecf20Sopenharmony_ci			}
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ci#ifdef CONFIG_GPIOLIB
16868c2ecf20Sopenharmony_ci			/* enable LNA for DVB-T, DVB-T2 and DVB-C */
16878c2ecf20Sopenharmony_ci			result = gpio_request_one(dvb->lna_gpio,
16888c2ecf20Sopenharmony_ci						  GPIOF_OUT_INIT_LOW, NULL);
16898c2ecf20Sopenharmony_ci			if (result)
16908c2ecf20Sopenharmony_ci				dev_err(&dev->intf->dev,
16918c2ecf20Sopenharmony_ci					"gpio request failed %d\n",
16928c2ecf20Sopenharmony_ci					result);
16938c2ecf20Sopenharmony_ci			else
16948c2ecf20Sopenharmony_ci				gpio_free(dvb->lna_gpio);
16958c2ecf20Sopenharmony_ci
16968c2ecf20Sopenharmony_ci			result = 0; /* continue even set LNA fails */
16978c2ecf20Sopenharmony_ci#endif
16988c2ecf20Sopenharmony_ci			dvb->fe[0]->ops.set_lna = em28xx_pctv_290e_set_lna;
16998c2ecf20Sopenharmony_ci		}
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci		break;
17028c2ecf20Sopenharmony_ci	case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C:
17038c2ecf20Sopenharmony_ci	{
17048c2ecf20Sopenharmony_ci		struct xc5000_config cfg = {};
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ci		hauppauge_hvr930c_init(dev);
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci		dvb->fe[0] = dvb_attach(drxk_attach,
17098c2ecf20Sopenharmony_ci					&hauppauge_930c_drxk,
17108c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus]);
17118c2ecf20Sopenharmony_ci		if (!dvb->fe[0]) {
17128c2ecf20Sopenharmony_ci			result = -EINVAL;
17138c2ecf20Sopenharmony_ci			goto out_free;
17148c2ecf20Sopenharmony_ci		}
17158c2ecf20Sopenharmony_ci		/* FIXME: do we need a pll semaphore? */
17168c2ecf20Sopenharmony_ci		dvb->fe[0]->sec_priv = dvb;
17178c2ecf20Sopenharmony_ci		sema_init(&dvb->pll_mutex, 1);
17188c2ecf20Sopenharmony_ci		dvb->gate_ctrl = dvb->fe[0]->ops.i2c_gate_ctrl;
17198c2ecf20Sopenharmony_ci		dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci		/* Attach xc5000 */
17228c2ecf20Sopenharmony_ci		cfg.i2c_address  = 0x61;
17238c2ecf20Sopenharmony_ci		cfg.if_khz = 4000;
17248c2ecf20Sopenharmony_ci
17258c2ecf20Sopenharmony_ci		if (dvb->fe[0]->ops.i2c_gate_ctrl)
17268c2ecf20Sopenharmony_ci			dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1);
17278c2ecf20Sopenharmony_ci		if (!dvb_attach(xc5000_attach, dvb->fe[0],
17288c2ecf20Sopenharmony_ci				&dev->i2c_adap[dev->def_i2c_bus], &cfg)) {
17298c2ecf20Sopenharmony_ci			result = -EINVAL;
17308c2ecf20Sopenharmony_ci			goto out_free;
17318c2ecf20Sopenharmony_ci		}
17328c2ecf20Sopenharmony_ci		if (dvb->fe[0]->ops.i2c_gate_ctrl)
17338c2ecf20Sopenharmony_ci			dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0);
17348c2ecf20Sopenharmony_ci
17358c2ecf20Sopenharmony_ci		break;
17368c2ecf20Sopenharmony_ci	}
17378c2ecf20Sopenharmony_ci	case EM2884_BOARD_TERRATEC_H5:
17388c2ecf20Sopenharmony_ci		terratec_h5_init(dev);
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci		dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk,
17418c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus]);
17428c2ecf20Sopenharmony_ci		if (!dvb->fe[0]) {
17438c2ecf20Sopenharmony_ci			result = -EINVAL;
17448c2ecf20Sopenharmony_ci			goto out_free;
17458c2ecf20Sopenharmony_ci		}
17468c2ecf20Sopenharmony_ci		/* FIXME: do we need a pll semaphore? */
17478c2ecf20Sopenharmony_ci		dvb->fe[0]->sec_priv = dvb;
17488c2ecf20Sopenharmony_ci		sema_init(&dvb->pll_mutex, 1);
17498c2ecf20Sopenharmony_ci		dvb->gate_ctrl = dvb->fe[0]->ops.i2c_gate_ctrl;
17508c2ecf20Sopenharmony_ci		dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci		/* Attach tda18271 to DVB-C frontend */
17538c2ecf20Sopenharmony_ci		if (dvb->fe[0]->ops.i2c_gate_ctrl)
17548c2ecf20Sopenharmony_ci			dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1);
17558c2ecf20Sopenharmony_ci		if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0],
17568c2ecf20Sopenharmony_ci				&dev->i2c_adap[dev->def_i2c_bus], 0x60)) {
17578c2ecf20Sopenharmony_ci			result = -EINVAL;
17588c2ecf20Sopenharmony_ci			goto out_free;
17598c2ecf20Sopenharmony_ci		}
17608c2ecf20Sopenharmony_ci		if (dvb->fe[0]->ops.i2c_gate_ctrl)
17618c2ecf20Sopenharmony_ci			dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0);
17628c2ecf20Sopenharmony_ci
17638c2ecf20Sopenharmony_ci		break;
17648c2ecf20Sopenharmony_ci	case EM2884_BOARD_C3TECH_DIGITAL_DUO:
17658c2ecf20Sopenharmony_ci		dvb->fe[0] = dvb_attach(mb86a20s_attach,
17668c2ecf20Sopenharmony_ci					&c3tech_duo_mb86a20s_config,
17678c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus]);
17688c2ecf20Sopenharmony_ci		if (dvb->fe[0])
17698c2ecf20Sopenharmony_ci			dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
17708c2ecf20Sopenharmony_ci				   &dev->i2c_adap[dev->def_i2c_bus],
17718c2ecf20Sopenharmony_ci				   &c3tech_duo_tda18271_config);
17728c2ecf20Sopenharmony_ci		break;
17738c2ecf20Sopenharmony_ci	case EM28174_BOARD_PCTV_460E:
17748c2ecf20Sopenharmony_ci		result = em28174_dvb_init_pctv_460e(dev);
17758c2ecf20Sopenharmony_ci		if (result)
17768c2ecf20Sopenharmony_ci			goto out_free;
17778c2ecf20Sopenharmony_ci		break;
17788c2ecf20Sopenharmony_ci	case EM2874_BOARD_DELOCK_61959:
17798c2ecf20Sopenharmony_ci	case EM2874_BOARD_MAXMEDIA_UB425_TC:
17808c2ecf20Sopenharmony_ci		/* attach demodulator */
17818c2ecf20Sopenharmony_ci		dvb->fe[0] = dvb_attach(drxk_attach, &maxmedia_ub425_tc_drxk,
17828c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus]);
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci		if (dvb->fe[0]) {
17858c2ecf20Sopenharmony_ci			/* disable I2C-gate */
17868c2ecf20Sopenharmony_ci			dvb->fe[0]->ops.i2c_gate_ctrl = NULL;
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_ci			/* attach tuner */
17898c2ecf20Sopenharmony_ci			if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
17908c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus],
17918c2ecf20Sopenharmony_ci					&em28xx_cxd2820r_tda18271_config)) {
17928c2ecf20Sopenharmony_ci				dvb_frontend_detach(dvb->fe[0]);
17938c2ecf20Sopenharmony_ci				result = -EINVAL;
17948c2ecf20Sopenharmony_ci				goto out_free;
17958c2ecf20Sopenharmony_ci			}
17968c2ecf20Sopenharmony_ci		}
17978c2ecf20Sopenharmony_ci		break;
17988c2ecf20Sopenharmony_ci	case EM2884_BOARD_PCTV_510E:
17998c2ecf20Sopenharmony_ci	case EM2884_BOARD_PCTV_520E:
18008c2ecf20Sopenharmony_ci		pctv_520e_init(dev);
18018c2ecf20Sopenharmony_ci
18028c2ecf20Sopenharmony_ci		/* attach demodulator */
18038c2ecf20Sopenharmony_ci		dvb->fe[0] = dvb_attach(drxk_attach, &pctv_520e_drxk,
18048c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus]);
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci		if (dvb->fe[0]) {
18078c2ecf20Sopenharmony_ci			/* attach tuner */
18088c2ecf20Sopenharmony_ci			if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
18098c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus],
18108c2ecf20Sopenharmony_ci					&em28xx_cxd2820r_tda18271_config)) {
18118c2ecf20Sopenharmony_ci				dvb_frontend_detach(dvb->fe[0]);
18128c2ecf20Sopenharmony_ci				result = -EINVAL;
18138c2ecf20Sopenharmony_ci				goto out_free;
18148c2ecf20Sopenharmony_ci			}
18158c2ecf20Sopenharmony_ci		}
18168c2ecf20Sopenharmony_ci		break;
18178c2ecf20Sopenharmony_ci	case EM2884_BOARD_ELGATO_EYETV_HYBRID_2008:
18188c2ecf20Sopenharmony_ci	case EM2884_BOARD_CINERGY_HTC_STICK:
18198c2ecf20Sopenharmony_ci	case EM2884_BOARD_TERRATEC_H6:
18208c2ecf20Sopenharmony_ci		terratec_htc_stick_init(dev);
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci		/* attach demodulator */
18238c2ecf20Sopenharmony_ci		dvb->fe[0] = dvb_attach(drxk_attach, &terratec_htc_stick_drxk,
18248c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus]);
18258c2ecf20Sopenharmony_ci		if (!dvb->fe[0]) {
18268c2ecf20Sopenharmony_ci			result = -EINVAL;
18278c2ecf20Sopenharmony_ci			goto out_free;
18288c2ecf20Sopenharmony_ci		}
18298c2ecf20Sopenharmony_ci
18308c2ecf20Sopenharmony_ci		/* Attach the demodulator. */
18318c2ecf20Sopenharmony_ci		if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
18328c2ecf20Sopenharmony_ci				&dev->i2c_adap[dev->def_i2c_bus],
18338c2ecf20Sopenharmony_ci				&em28xx_cxd2820r_tda18271_config)) {
18348c2ecf20Sopenharmony_ci			result = -EINVAL;
18358c2ecf20Sopenharmony_ci			goto out_free;
18368c2ecf20Sopenharmony_ci		}
18378c2ecf20Sopenharmony_ci		break;
18388c2ecf20Sopenharmony_ci	case EM2884_BOARD_TERRATEC_HTC_USB_XS:
18398c2ecf20Sopenharmony_ci		terratec_htc_usb_xs_init(dev);
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ci		/* attach demodulator */
18428c2ecf20Sopenharmony_ci		dvb->fe[0] = dvb_attach(drxk_attach, &terratec_htc_stick_drxk,
18438c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus]);
18448c2ecf20Sopenharmony_ci		if (!dvb->fe[0]) {
18458c2ecf20Sopenharmony_ci			result = -EINVAL;
18468c2ecf20Sopenharmony_ci			goto out_free;
18478c2ecf20Sopenharmony_ci		}
18488c2ecf20Sopenharmony_ci
18498c2ecf20Sopenharmony_ci		/* Attach the demodulator. */
18508c2ecf20Sopenharmony_ci		if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
18518c2ecf20Sopenharmony_ci				&dev->i2c_adap[dev->def_i2c_bus],
18528c2ecf20Sopenharmony_ci				&em28xx_cxd2820r_tda18271_config)) {
18538c2ecf20Sopenharmony_ci			result = -EINVAL;
18548c2ecf20Sopenharmony_ci			goto out_free;
18558c2ecf20Sopenharmony_ci		}
18568c2ecf20Sopenharmony_ci		break;
18578c2ecf20Sopenharmony_ci	case EM2874_BOARD_KWORLD_UB435Q_V2:
18588c2ecf20Sopenharmony_ci		dvb->fe[0] = dvb_attach(lgdt3305_attach,
18598c2ecf20Sopenharmony_ci					&em2874_lgdt3305_dev,
18608c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus]);
18618c2ecf20Sopenharmony_ci		if (!dvb->fe[0]) {
18628c2ecf20Sopenharmony_ci			result = -EINVAL;
18638c2ecf20Sopenharmony_ci			goto out_free;
18648c2ecf20Sopenharmony_ci		}
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_ci		/* Attach the demodulator. */
18678c2ecf20Sopenharmony_ci		if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
18688c2ecf20Sopenharmony_ci				&dev->i2c_adap[dev->def_i2c_bus],
18698c2ecf20Sopenharmony_ci				&kworld_ub435q_v2_config)) {
18708c2ecf20Sopenharmony_ci			result = -EINVAL;
18718c2ecf20Sopenharmony_ci			goto out_free;
18728c2ecf20Sopenharmony_ci		}
18738c2ecf20Sopenharmony_ci		break;
18748c2ecf20Sopenharmony_ci	case EM2874_BOARD_KWORLD_UB435Q_V3:
18758c2ecf20Sopenharmony_ci	{
18768c2ecf20Sopenharmony_ci		struct i2c_adapter *adapter = &dev->i2c_adap[dev->def_i2c_bus];
18778c2ecf20Sopenharmony_ci
18788c2ecf20Sopenharmony_ci		dvb->fe[0] = dvb_attach(lgdt3305_attach,
18798c2ecf20Sopenharmony_ci					&em2874_lgdt3305_nogate_dev,
18808c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus]);
18818c2ecf20Sopenharmony_ci		if (!dvb->fe[0]) {
18828c2ecf20Sopenharmony_ci			result = -EINVAL;
18838c2ecf20Sopenharmony_ci			goto out_free;
18848c2ecf20Sopenharmony_ci		}
18858c2ecf20Sopenharmony_ci
18868c2ecf20Sopenharmony_ci		/* attach tuner */
18878c2ecf20Sopenharmony_ci		kworld_ub435q_v3_config.fe = dvb->fe[0];
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_ci		dvb->i2c_client_tuner = dvb_module_probe("tda18212", NULL,
18908c2ecf20Sopenharmony_ci							 adapter, 0x60,
18918c2ecf20Sopenharmony_ci							 &kworld_ub435q_v3_config);
18928c2ecf20Sopenharmony_ci		if (!dvb->i2c_client_tuner) {
18938c2ecf20Sopenharmony_ci			dvb_frontend_detach(dvb->fe[0]);
18948c2ecf20Sopenharmony_ci			result = -ENODEV;
18958c2ecf20Sopenharmony_ci			goto out_free;
18968c2ecf20Sopenharmony_ci		}
18978c2ecf20Sopenharmony_ci		break;
18988c2ecf20Sopenharmony_ci	}
18998c2ecf20Sopenharmony_ci	case EM2874_BOARD_PCTV_HD_MINI_80E:
19008c2ecf20Sopenharmony_ci		dvb->fe[0] = dvb_attach(drx39xxj_attach,
19018c2ecf20Sopenharmony_ci					&dev->i2c_adap[dev->def_i2c_bus]);
19028c2ecf20Sopenharmony_ci		if (dvb->fe[0]) {
19038c2ecf20Sopenharmony_ci			dvb->fe[0] = dvb_attach(tda18271_attach, dvb->fe[0],
19048c2ecf20Sopenharmony_ci						0x60,
19058c2ecf20Sopenharmony_ci						&dev->i2c_adap[dev->def_i2c_bus],
19068c2ecf20Sopenharmony_ci						&pinnacle_80e_dvb_config);
19078c2ecf20Sopenharmony_ci			if (!dvb->fe[0]) {
19088c2ecf20Sopenharmony_ci				result = -EINVAL;
19098c2ecf20Sopenharmony_ci				goto out_free;
19108c2ecf20Sopenharmony_ci			}
19118c2ecf20Sopenharmony_ci		}
19128c2ecf20Sopenharmony_ci		break;
19138c2ecf20Sopenharmony_ci	case EM28178_BOARD_PCTV_461E:
19148c2ecf20Sopenharmony_ci		result = em28178_dvb_init_pctv_461e(dev);
19158c2ecf20Sopenharmony_ci		if (result)
19168c2ecf20Sopenharmony_ci			goto out_free;
19178c2ecf20Sopenharmony_ci		break;
19188c2ecf20Sopenharmony_ci	case EM28178_BOARD_PCTV_461E_V2:
19198c2ecf20Sopenharmony_ci		result = em28178_dvb_init_pctv_461e_v2(dev);
19208c2ecf20Sopenharmony_ci		if (result)
19218c2ecf20Sopenharmony_ci			goto out_free;
19228c2ecf20Sopenharmony_ci		break;
19238c2ecf20Sopenharmony_ci	case EM28178_BOARD_PCTV_292E:
19248c2ecf20Sopenharmony_ci		result = em28178_dvb_init_pctv_292e(dev);
19258c2ecf20Sopenharmony_ci		if (result)
19268c2ecf20Sopenharmony_ci			goto out_free;
19278c2ecf20Sopenharmony_ci		break;
19288c2ecf20Sopenharmony_ci	case EM28178_BOARD_TERRATEC_T2_STICK_HD:
19298c2ecf20Sopenharmony_ci		result = em28178_dvb_init_terratec_t2_stick_hd(dev);
19308c2ecf20Sopenharmony_ci		if (result)
19318c2ecf20Sopenharmony_ci			goto out_free;
19328c2ecf20Sopenharmony_ci		break;
19338c2ecf20Sopenharmony_ci	case EM28178_BOARD_PLEX_PX_BCUD:
19348c2ecf20Sopenharmony_ci		result = em28178_dvb_init_plex_px_bcud(dev);
19358c2ecf20Sopenharmony_ci		if (result)
19368c2ecf20Sopenharmony_ci			goto out_free;
19378c2ecf20Sopenharmony_ci		break;
19388c2ecf20Sopenharmony_ci	case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB:
19398c2ecf20Sopenharmony_ci		result = em28174_dvb_init_hauppauge_wintv_dualhd_dvb(dev);
19408c2ecf20Sopenharmony_ci		if (result)
19418c2ecf20Sopenharmony_ci			goto out_free;
19428c2ecf20Sopenharmony_ci		break;
19438c2ecf20Sopenharmony_ci	case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595:
19448c2ecf20Sopenharmony_ci		result = em28174_dvb_init_hauppauge_wintv_dualhd_01595(dev);
19458c2ecf20Sopenharmony_ci		if (result)
19468c2ecf20Sopenharmony_ci			goto out_free;
19478c2ecf20Sopenharmony_ci		break;
19488c2ecf20Sopenharmony_ci	default:
19498c2ecf20Sopenharmony_ci		dev_err(&dev->intf->dev,
19508c2ecf20Sopenharmony_ci			"The frontend of your DVB/ATSC card isn't supported yet\n");
19518c2ecf20Sopenharmony_ci		break;
19528c2ecf20Sopenharmony_ci	}
19538c2ecf20Sopenharmony_ci	if (!dvb->fe[0]) {
19548c2ecf20Sopenharmony_ci		dev_err(&dev->intf->dev, "frontend initialization failed\n");
19558c2ecf20Sopenharmony_ci		result = -EINVAL;
19568c2ecf20Sopenharmony_ci		goto out_free;
19578c2ecf20Sopenharmony_ci	}
19588c2ecf20Sopenharmony_ci	/* define general-purpose callback pointer */
19598c2ecf20Sopenharmony_ci	dvb->fe[0]->callback = em28xx_tuner_callback;
19608c2ecf20Sopenharmony_ci	if (dvb->fe[1])
19618c2ecf20Sopenharmony_ci		dvb->fe[1]->callback = em28xx_tuner_callback;
19628c2ecf20Sopenharmony_ci
19638c2ecf20Sopenharmony_ci	/* register everything */
19648c2ecf20Sopenharmony_ci	result = em28xx_register_dvb(dvb, THIS_MODULE, dev, &dev->intf->dev);
19658c2ecf20Sopenharmony_ci
19668c2ecf20Sopenharmony_ci	if (result < 0)
19678c2ecf20Sopenharmony_ci		goto out_free;
19688c2ecf20Sopenharmony_ci
19698c2ecf20Sopenharmony_ci	if (dev->dvb_xfer_bulk) {
19708c2ecf20Sopenharmony_ci		dvb_alt = 0;
19718c2ecf20Sopenharmony_ci	} else { /* isoc */
19728c2ecf20Sopenharmony_ci		dvb_alt = dev->dvb_alt_isoc;
19738c2ecf20Sopenharmony_ci	}
19748c2ecf20Sopenharmony_ci
19758c2ecf20Sopenharmony_ci	udev = interface_to_usbdev(dev->intf);
19768c2ecf20Sopenharmony_ci	usb_set_interface(udev, dev->ifnum, dvb_alt);
19778c2ecf20Sopenharmony_ci	dev_info(&dev->intf->dev, "DVB extension successfully initialized\n");
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_ci	kref_get(&dev->ref);
19808c2ecf20Sopenharmony_ci
19818c2ecf20Sopenharmony_ciret:
19828c2ecf20Sopenharmony_ci	em28xx_set_mode(dev, EM28XX_SUSPEND);
19838c2ecf20Sopenharmony_ci	mutex_unlock(&dev->lock);
19848c2ecf20Sopenharmony_ci	return result;
19858c2ecf20Sopenharmony_ci
19868c2ecf20Sopenharmony_ciout_free:
19878c2ecf20Sopenharmony_ci	em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE);
19888c2ecf20Sopenharmony_ci	kfree(dvb);
19898c2ecf20Sopenharmony_ci	dev->dvb = NULL;
19908c2ecf20Sopenharmony_ci	goto ret;
19918c2ecf20Sopenharmony_ci}
19928c2ecf20Sopenharmony_ci
19938c2ecf20Sopenharmony_cistatic inline void prevent_sleep(struct dvb_frontend_ops *ops)
19948c2ecf20Sopenharmony_ci{
19958c2ecf20Sopenharmony_ci	ops->set_voltage = NULL;
19968c2ecf20Sopenharmony_ci	ops->sleep = NULL;
19978c2ecf20Sopenharmony_ci	ops->tuner_ops.sleep = NULL;
19988c2ecf20Sopenharmony_ci}
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_cistatic int em28xx_dvb_fini(struct em28xx *dev)
20018c2ecf20Sopenharmony_ci{
20028c2ecf20Sopenharmony_ci	struct em28xx_dvb *dvb;
20038c2ecf20Sopenharmony_ci
20048c2ecf20Sopenharmony_ci	if (dev->is_audio_only) {
20058c2ecf20Sopenharmony_ci		/* Shouldn't initialize IR for this interface */
20068c2ecf20Sopenharmony_ci		return 0;
20078c2ecf20Sopenharmony_ci	}
20088c2ecf20Sopenharmony_ci
20098c2ecf20Sopenharmony_ci	if (!dev->board.has_dvb) {
20108c2ecf20Sopenharmony_ci		/* This device does not support the extension */
20118c2ecf20Sopenharmony_ci		return 0;
20128c2ecf20Sopenharmony_ci	}
20138c2ecf20Sopenharmony_ci
20148c2ecf20Sopenharmony_ci	if (!dev->dvb)
20158c2ecf20Sopenharmony_ci		return 0;
20168c2ecf20Sopenharmony_ci
20178c2ecf20Sopenharmony_ci	dev_info(&dev->intf->dev, "Closing DVB extension\n");
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ci	dvb = dev->dvb;
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_ci	em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE);
20228c2ecf20Sopenharmony_ci
20238c2ecf20Sopenharmony_ci	if (dev->disconnected) {
20248c2ecf20Sopenharmony_ci		/*
20258c2ecf20Sopenharmony_ci		 * We cannot tell the device to sleep
20268c2ecf20Sopenharmony_ci		 * once it has been unplugged.
20278c2ecf20Sopenharmony_ci		 */
20288c2ecf20Sopenharmony_ci		if (dvb->fe[0]) {
20298c2ecf20Sopenharmony_ci			prevent_sleep(&dvb->fe[0]->ops);
20308c2ecf20Sopenharmony_ci			dvb->fe[0]->exit = DVB_FE_DEVICE_REMOVED;
20318c2ecf20Sopenharmony_ci		}
20328c2ecf20Sopenharmony_ci		if (dvb->fe[1]) {
20338c2ecf20Sopenharmony_ci			prevent_sleep(&dvb->fe[1]->ops);
20348c2ecf20Sopenharmony_ci			dvb->fe[1]->exit = DVB_FE_DEVICE_REMOVED;
20358c2ecf20Sopenharmony_ci		}
20368c2ecf20Sopenharmony_ci	}
20378c2ecf20Sopenharmony_ci
20388c2ecf20Sopenharmony_ci	em28xx_unregister_dvb(dvb);
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_ci	/* release I2C module bindings */
20418c2ecf20Sopenharmony_ci	dvb_module_release(dvb->i2c_client_sec);
20428c2ecf20Sopenharmony_ci	dvb_module_release(dvb->i2c_client_tuner);
20438c2ecf20Sopenharmony_ci	dvb_module_release(dvb->i2c_client_demod);
20448c2ecf20Sopenharmony_ci
20458c2ecf20Sopenharmony_ci	kfree(dvb);
20468c2ecf20Sopenharmony_ci	dev->dvb = NULL;
20478c2ecf20Sopenharmony_ci	kref_put(&dev->ref, em28xx_free_device);
20488c2ecf20Sopenharmony_ci
20498c2ecf20Sopenharmony_ci	return 0;
20508c2ecf20Sopenharmony_ci}
20518c2ecf20Sopenharmony_ci
20528c2ecf20Sopenharmony_cistatic int em28xx_dvb_suspend(struct em28xx *dev)
20538c2ecf20Sopenharmony_ci{
20548c2ecf20Sopenharmony_ci	int ret = 0;
20558c2ecf20Sopenharmony_ci
20568c2ecf20Sopenharmony_ci	if (dev->is_audio_only)
20578c2ecf20Sopenharmony_ci		return 0;
20588c2ecf20Sopenharmony_ci
20598c2ecf20Sopenharmony_ci	if (!dev->board.has_dvb)
20608c2ecf20Sopenharmony_ci		return 0;
20618c2ecf20Sopenharmony_ci
20628c2ecf20Sopenharmony_ci	dev_info(&dev->intf->dev, "Suspending DVB extension\n");
20638c2ecf20Sopenharmony_ci	if (dev->dvb) {
20648c2ecf20Sopenharmony_ci		struct em28xx_dvb *dvb = dev->dvb;
20658c2ecf20Sopenharmony_ci
20668c2ecf20Sopenharmony_ci		if (dvb->fe[0]) {
20678c2ecf20Sopenharmony_ci			ret = dvb_frontend_suspend(dvb->fe[0]);
20688c2ecf20Sopenharmony_ci			dev_info(&dev->intf->dev, "fe0 suspend %d\n", ret);
20698c2ecf20Sopenharmony_ci		}
20708c2ecf20Sopenharmony_ci		if (dvb->fe[1]) {
20718c2ecf20Sopenharmony_ci			dvb_frontend_suspend(dvb->fe[1]);
20728c2ecf20Sopenharmony_ci			dev_info(&dev->intf->dev, "fe1 suspend %d\n", ret);
20738c2ecf20Sopenharmony_ci		}
20748c2ecf20Sopenharmony_ci	}
20758c2ecf20Sopenharmony_ci
20768c2ecf20Sopenharmony_ci	return 0;
20778c2ecf20Sopenharmony_ci}
20788c2ecf20Sopenharmony_ci
20798c2ecf20Sopenharmony_cistatic int em28xx_dvb_resume(struct em28xx *dev)
20808c2ecf20Sopenharmony_ci{
20818c2ecf20Sopenharmony_ci	int ret = 0;
20828c2ecf20Sopenharmony_ci
20838c2ecf20Sopenharmony_ci	if (dev->is_audio_only)
20848c2ecf20Sopenharmony_ci		return 0;
20858c2ecf20Sopenharmony_ci
20868c2ecf20Sopenharmony_ci	if (!dev->board.has_dvb)
20878c2ecf20Sopenharmony_ci		return 0;
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_ci	dev_info(&dev->intf->dev, "Resuming DVB extension\n");
20908c2ecf20Sopenharmony_ci	if (dev->dvb) {
20918c2ecf20Sopenharmony_ci		struct em28xx_dvb *dvb = dev->dvb;
20928c2ecf20Sopenharmony_ci
20938c2ecf20Sopenharmony_ci		if (dvb->fe[0]) {
20948c2ecf20Sopenharmony_ci			ret = dvb_frontend_resume(dvb->fe[0]);
20958c2ecf20Sopenharmony_ci			dev_info(&dev->intf->dev, "fe0 resume %d\n", ret);
20968c2ecf20Sopenharmony_ci		}
20978c2ecf20Sopenharmony_ci
20988c2ecf20Sopenharmony_ci		if (dvb->fe[1]) {
20998c2ecf20Sopenharmony_ci			ret = dvb_frontend_resume(dvb->fe[1]);
21008c2ecf20Sopenharmony_ci			dev_info(&dev->intf->dev, "fe1 resume %d\n", ret);
21018c2ecf20Sopenharmony_ci		}
21028c2ecf20Sopenharmony_ci	}
21038c2ecf20Sopenharmony_ci
21048c2ecf20Sopenharmony_ci	return 0;
21058c2ecf20Sopenharmony_ci}
21068c2ecf20Sopenharmony_ci
21078c2ecf20Sopenharmony_cistatic struct em28xx_ops dvb_ops = {
21088c2ecf20Sopenharmony_ci	.id   = EM28XX_DVB,
21098c2ecf20Sopenharmony_ci	.name = "Em28xx dvb Extension",
21108c2ecf20Sopenharmony_ci	.init = em28xx_dvb_init,
21118c2ecf20Sopenharmony_ci	.fini = em28xx_dvb_fini,
21128c2ecf20Sopenharmony_ci	.suspend = em28xx_dvb_suspend,
21138c2ecf20Sopenharmony_ci	.resume = em28xx_dvb_resume,
21148c2ecf20Sopenharmony_ci};
21158c2ecf20Sopenharmony_ci
21168c2ecf20Sopenharmony_cistatic int __init em28xx_dvb_register(void)
21178c2ecf20Sopenharmony_ci{
21188c2ecf20Sopenharmony_ci	return em28xx_register_extension(&dvb_ops);
21198c2ecf20Sopenharmony_ci}
21208c2ecf20Sopenharmony_ci
21218c2ecf20Sopenharmony_cistatic void __exit em28xx_dvb_unregister(void)
21228c2ecf20Sopenharmony_ci{
21238c2ecf20Sopenharmony_ci	em28xx_unregister_extension(&dvb_ops);
21248c2ecf20Sopenharmony_ci}
21258c2ecf20Sopenharmony_ci
21268c2ecf20Sopenharmony_cimodule_init(em28xx_dvb_register);
21278c2ecf20Sopenharmony_cimodule_exit(em28xx_dvb_unregister);
2128