162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Driver for Xceive XC4000 "QAM/8VSB single chip tuner"
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (c) 2007 Xceive Corporation
662306a36Sopenharmony_ci *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
762306a36Sopenharmony_ci *  Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
862306a36Sopenharmony_ci *  Copyright (c) 2009 Davide Ferri <d.ferri@zero11.it>
962306a36Sopenharmony_ci *  Copyright (c) 2010 Istvan Varga <istvan_v@mailbox.hu>
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <linux/moduleparam.h>
1462306a36Sopenharmony_ci#include <linux/videodev2.h>
1562306a36Sopenharmony_ci#include <linux/delay.h>
1662306a36Sopenharmony_ci#include <linux/dvb/frontend.h>
1762306a36Sopenharmony_ci#include <linux/i2c.h>
1862306a36Sopenharmony_ci#include <linux/mutex.h>
1962306a36Sopenharmony_ci#include <asm/unaligned.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <media/dvb_frontend.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "xc4000.h"
2462306a36Sopenharmony_ci#include "tuner-i2c.h"
2562306a36Sopenharmony_ci#include "xc2028-types.h"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic int debug;
2862306a36Sopenharmony_cimodule_param(debug, int, 0644);
2962306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "Debugging level (0 to 2, default: 0 (off)).");
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic int no_poweroff;
3262306a36Sopenharmony_cimodule_param(no_poweroff, int, 0644);
3362306a36Sopenharmony_ciMODULE_PARM_DESC(no_poweroff, "Power management (1: disabled, 2: enabled, 0 (default): use device-specific default mode).");
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic int audio_std;
3662306a36Sopenharmony_cimodule_param(audio_std, int, 0644);
3762306a36Sopenharmony_ciMODULE_PARM_DESC(audio_std, "Audio standard. XC4000 audio decoder explicitly needs to know what audio standard is needed for some video standards with audio A2 or NICAM. The valid settings are a sum of:\n"
3862306a36Sopenharmony_ci	" 1: use NICAM/B or A2/B instead of NICAM/A or A2/A\n"
3962306a36Sopenharmony_ci	" 2: use A2 instead of NICAM or BTSC\n"
4062306a36Sopenharmony_ci	" 4: use SECAM/K3 instead of K1\n"
4162306a36Sopenharmony_ci	" 8: use PAL-D/K audio for SECAM-D/K\n"
4262306a36Sopenharmony_ci	"16: use FM radio input 1 instead of input 2\n"
4362306a36Sopenharmony_ci	"32: use mono audio (the lower three bits are ignored)");
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic char firmware_name[30];
4662306a36Sopenharmony_cimodule_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0);
4762306a36Sopenharmony_ciMODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the default firmware name.");
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic DEFINE_MUTEX(xc4000_list_mutex);
5062306a36Sopenharmony_cistatic LIST_HEAD(hybrid_tuner_instance_list);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define dprintk(level, fmt, arg...) if (debug >= level) \
5362306a36Sopenharmony_ci	printk(KERN_INFO "%s: " fmt, "xc4000", ## arg)
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/* struct for storing firmware table */
5662306a36Sopenharmony_cistruct firmware_description {
5762306a36Sopenharmony_ci	unsigned int  type;
5862306a36Sopenharmony_ci	v4l2_std_id   id;
5962306a36Sopenharmony_ci	__u16         int_freq;
6062306a36Sopenharmony_ci	unsigned char *ptr;
6162306a36Sopenharmony_ci	unsigned int  size;
6262306a36Sopenharmony_ci};
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistruct firmware_properties {
6562306a36Sopenharmony_ci	unsigned int	type;
6662306a36Sopenharmony_ci	v4l2_std_id	id;
6762306a36Sopenharmony_ci	v4l2_std_id	std_req;
6862306a36Sopenharmony_ci	__u16		int_freq;
6962306a36Sopenharmony_ci	unsigned int	scode_table;
7062306a36Sopenharmony_ci	int		scode_nr;
7162306a36Sopenharmony_ci};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistruct xc4000_priv {
7462306a36Sopenharmony_ci	struct tuner_i2c_props i2c_props;
7562306a36Sopenharmony_ci	struct list_head hybrid_tuner_instance_list;
7662306a36Sopenharmony_ci	struct firmware_description *firm;
7762306a36Sopenharmony_ci	int	firm_size;
7862306a36Sopenharmony_ci	u32	if_khz;
7962306a36Sopenharmony_ci	u32	freq_hz, freq_offset;
8062306a36Sopenharmony_ci	u32	bandwidth;
8162306a36Sopenharmony_ci	u8	video_standard;
8262306a36Sopenharmony_ci	u8	rf_mode;
8362306a36Sopenharmony_ci	u8	default_pm;
8462306a36Sopenharmony_ci	u8	dvb_amplitude;
8562306a36Sopenharmony_ci	u8	set_smoothedcvbs;
8662306a36Sopenharmony_ci	u8	ignore_i2c_write_errors;
8762306a36Sopenharmony_ci	__u16	firm_version;
8862306a36Sopenharmony_ci	struct firmware_properties cur_fw;
8962306a36Sopenharmony_ci	__u16	hwmodel;
9062306a36Sopenharmony_ci	__u16	hwvers;
9162306a36Sopenharmony_ci	struct mutex	lock;
9262306a36Sopenharmony_ci};
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci#define XC4000_AUDIO_STD_B		 1
9562306a36Sopenharmony_ci#define XC4000_AUDIO_STD_A2		 2
9662306a36Sopenharmony_ci#define XC4000_AUDIO_STD_K3		 4
9762306a36Sopenharmony_ci#define XC4000_AUDIO_STD_L		 8
9862306a36Sopenharmony_ci#define XC4000_AUDIO_STD_INPUT1		16
9962306a36Sopenharmony_ci#define XC4000_AUDIO_STD_MONO		32
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci#define XC4000_DEFAULT_FIRMWARE "dvb-fe-xc4000-1.4.fw"
10262306a36Sopenharmony_ci#define XC4000_DEFAULT_FIRMWARE_NEW "dvb-fe-xc4000-1.4.1.fw"
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/* Misc Defines */
10562306a36Sopenharmony_ci#define MAX_TV_STANDARD			24
10662306a36Sopenharmony_ci#define XC_MAX_I2C_WRITE_LENGTH		64
10762306a36Sopenharmony_ci#define XC_POWERED_DOWN			0x80000000U
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci/* Signal Types */
11062306a36Sopenharmony_ci#define XC_RF_MODE_AIR			0
11162306a36Sopenharmony_ci#define XC_RF_MODE_CABLE		1
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci/* Product id */
11462306a36Sopenharmony_ci#define XC_PRODUCT_ID_FW_NOT_LOADED	0x2000
11562306a36Sopenharmony_ci#define XC_PRODUCT_ID_XC4000		0x0FA0
11662306a36Sopenharmony_ci#define XC_PRODUCT_ID_XC4100		0x1004
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci/* Registers (Write-only) */
11962306a36Sopenharmony_ci#define XREG_INIT         0x00
12062306a36Sopenharmony_ci#define XREG_VIDEO_MODE   0x01
12162306a36Sopenharmony_ci#define XREG_AUDIO_MODE   0x02
12262306a36Sopenharmony_ci#define XREG_RF_FREQ      0x03
12362306a36Sopenharmony_ci#define XREG_D_CODE       0x04
12462306a36Sopenharmony_ci#define XREG_DIRECTSITTING_MODE 0x05
12562306a36Sopenharmony_ci#define XREG_SEEK_MODE    0x06
12662306a36Sopenharmony_ci#define XREG_POWER_DOWN   0x08
12762306a36Sopenharmony_ci#define XREG_SIGNALSOURCE 0x0A
12862306a36Sopenharmony_ci#define XREG_SMOOTHEDCVBS 0x0E
12962306a36Sopenharmony_ci#define XREG_AMPLITUDE    0x10
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci/* Registers (Read-only) */
13262306a36Sopenharmony_ci#define XREG_ADC_ENV      0x00
13362306a36Sopenharmony_ci#define XREG_QUALITY      0x01
13462306a36Sopenharmony_ci#define XREG_FRAME_LINES  0x02
13562306a36Sopenharmony_ci#define XREG_HSYNC_FREQ   0x03
13662306a36Sopenharmony_ci#define XREG_LOCK         0x04
13762306a36Sopenharmony_ci#define XREG_FREQ_ERROR   0x05
13862306a36Sopenharmony_ci#define XREG_SNR          0x06
13962306a36Sopenharmony_ci#define XREG_VERSION      0x07
14062306a36Sopenharmony_ci#define XREG_PRODUCT_ID   0x08
14162306a36Sopenharmony_ci#define XREG_SIGNAL_LEVEL 0x0A
14262306a36Sopenharmony_ci#define XREG_NOISE_LEVEL  0x0B
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci/*
14562306a36Sopenharmony_ci   Basic firmware description. This will remain with
14662306a36Sopenharmony_ci   the driver for documentation purposes.
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci   This represents an I2C firmware file encoded as a
14962306a36Sopenharmony_ci   string of unsigned char. Format is as follows:
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci   char[0  ]=len0_MSB  -> len = len_MSB * 256 + len_LSB
15262306a36Sopenharmony_ci   char[1  ]=len0_LSB  -> length of first write transaction
15362306a36Sopenharmony_ci   char[2  ]=data0 -> first byte to be sent
15462306a36Sopenharmony_ci   char[3  ]=data1
15562306a36Sopenharmony_ci   char[4  ]=data2
15662306a36Sopenharmony_ci   char[   ]=...
15762306a36Sopenharmony_ci   char[M  ]=dataN  -> last byte to be sent
15862306a36Sopenharmony_ci   char[M+1]=len1_MSB  -> len = len_MSB * 256 + len_LSB
15962306a36Sopenharmony_ci   char[M+2]=len1_LSB  -> length of second write transaction
16062306a36Sopenharmony_ci   char[M+3]=data0
16162306a36Sopenharmony_ci   char[M+4]=data1
16262306a36Sopenharmony_ci   ...
16362306a36Sopenharmony_ci   etc.
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci   The [len] value should be interpreted as follows:
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci   len= len_MSB _ len_LSB
16862306a36Sopenharmony_ci   len=1111_1111_1111_1111   : End of I2C_SEQUENCE
16962306a36Sopenharmony_ci   len=0000_0000_0000_0000   : Reset command: Do hardware reset
17062306a36Sopenharmony_ci   len=0NNN_NNNN_NNNN_NNNN   : Normal transaction: number of bytes = {1:32767)
17162306a36Sopenharmony_ci   len=1WWW_WWWW_WWWW_WWWW   : Wait command: wait for {1:32767} ms
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci   For the RESET and WAIT commands, the two following bytes will contain
17462306a36Sopenharmony_ci   immediately the length of the following transaction.
17562306a36Sopenharmony_ci*/
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistruct XC_TV_STANDARD {
17862306a36Sopenharmony_ci	const char  *Name;
17962306a36Sopenharmony_ci	u16	    audio_mode;
18062306a36Sopenharmony_ci	u16	    video_mode;
18162306a36Sopenharmony_ci	u16	    int_freq;
18262306a36Sopenharmony_ci};
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci/* Tuner standards */
18562306a36Sopenharmony_ci#define XC4000_MN_NTSC_PAL_BTSC		0
18662306a36Sopenharmony_ci#define XC4000_MN_NTSC_PAL_A2		1
18762306a36Sopenharmony_ci#define XC4000_MN_NTSC_PAL_EIAJ		2
18862306a36Sopenharmony_ci#define XC4000_MN_NTSC_PAL_Mono		3
18962306a36Sopenharmony_ci#define XC4000_BG_PAL_A2		4
19062306a36Sopenharmony_ci#define XC4000_BG_PAL_NICAM		5
19162306a36Sopenharmony_ci#define XC4000_BG_PAL_MONO		6
19262306a36Sopenharmony_ci#define XC4000_I_PAL_NICAM		7
19362306a36Sopenharmony_ci#define XC4000_I_PAL_NICAM_MONO		8
19462306a36Sopenharmony_ci#define XC4000_DK_PAL_A2		9
19562306a36Sopenharmony_ci#define XC4000_DK_PAL_NICAM		10
19662306a36Sopenharmony_ci#define XC4000_DK_PAL_MONO		11
19762306a36Sopenharmony_ci#define XC4000_DK_SECAM_A2DK1		12
19862306a36Sopenharmony_ci#define XC4000_DK_SECAM_A2LDK3		13
19962306a36Sopenharmony_ci#define XC4000_DK_SECAM_A2MONO		14
20062306a36Sopenharmony_ci#define XC4000_DK_SECAM_NICAM		15
20162306a36Sopenharmony_ci#define XC4000_L_SECAM_NICAM		16
20262306a36Sopenharmony_ci#define XC4000_LC_SECAM_NICAM		17
20362306a36Sopenharmony_ci#define XC4000_DTV6			18
20462306a36Sopenharmony_ci#define XC4000_DTV8			19
20562306a36Sopenharmony_ci#define XC4000_DTV7_8			20
20662306a36Sopenharmony_ci#define XC4000_DTV7			21
20762306a36Sopenharmony_ci#define XC4000_FM_Radio_INPUT2		22
20862306a36Sopenharmony_ci#define XC4000_FM_Radio_INPUT1		23
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic struct XC_TV_STANDARD xc4000_standard[MAX_TV_STANDARD] = {
21162306a36Sopenharmony_ci	{"M/N-NTSC/PAL-BTSC",	0x0000, 0x80A0, 4500},
21262306a36Sopenharmony_ci	{"M/N-NTSC/PAL-A2",	0x0000, 0x80A0, 4600},
21362306a36Sopenharmony_ci	{"M/N-NTSC/PAL-EIAJ",	0x0040, 0x80A0, 4500},
21462306a36Sopenharmony_ci	{"M/N-NTSC/PAL-Mono",	0x0078, 0x80A0, 4500},
21562306a36Sopenharmony_ci	{"B/G-PAL-A2",		0x0000, 0x8159, 5640},
21662306a36Sopenharmony_ci	{"B/G-PAL-NICAM",	0x0004, 0x8159, 5740},
21762306a36Sopenharmony_ci	{"B/G-PAL-MONO",	0x0078, 0x8159, 5500},
21862306a36Sopenharmony_ci	{"I-PAL-NICAM",		0x0080, 0x8049, 6240},
21962306a36Sopenharmony_ci	{"I-PAL-NICAM-MONO",	0x0078, 0x8049, 6000},
22062306a36Sopenharmony_ci	{"D/K-PAL-A2",		0x0000, 0x8049, 6380},
22162306a36Sopenharmony_ci	{"D/K-PAL-NICAM",	0x0080, 0x8049, 6200},
22262306a36Sopenharmony_ci	{"D/K-PAL-MONO",	0x0078, 0x8049, 6500},
22362306a36Sopenharmony_ci	{"D/K-SECAM-A2 DK1",	0x0000, 0x8049, 6340},
22462306a36Sopenharmony_ci	{"D/K-SECAM-A2 L/DK3",	0x0000, 0x8049, 6000},
22562306a36Sopenharmony_ci	{"D/K-SECAM-A2 MONO",	0x0078, 0x8049, 6500},
22662306a36Sopenharmony_ci	{"D/K-SECAM-NICAM",	0x0080, 0x8049, 6200},
22762306a36Sopenharmony_ci	{"L-SECAM-NICAM",	0x8080, 0x0009, 6200},
22862306a36Sopenharmony_ci	{"L'-SECAM-NICAM",	0x8080, 0x4009, 6200},
22962306a36Sopenharmony_ci	{"DTV6",		0x00C0, 0x8002,    0},
23062306a36Sopenharmony_ci	{"DTV8",		0x00C0, 0x800B,    0},
23162306a36Sopenharmony_ci	{"DTV7/8",		0x00C0, 0x801B,    0},
23262306a36Sopenharmony_ci	{"DTV7",		0x00C0, 0x8007,    0},
23362306a36Sopenharmony_ci	{"FM Radio-INPUT2",	0x0008, 0x9800, 10700},
23462306a36Sopenharmony_ci	{"FM Radio-INPUT1",	0x0008, 0x9000, 10700}
23562306a36Sopenharmony_ci};
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val);
23862306a36Sopenharmony_cistatic int xc4000_tuner_reset(struct dvb_frontend *fe);
23962306a36Sopenharmony_cistatic void xc_debug_dump(struct xc4000_priv *priv);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic int xc_send_i2c_data(struct xc4000_priv *priv, u8 *buf, int len)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	struct i2c_msg msg = { .addr = priv->i2c_props.addr,
24462306a36Sopenharmony_ci			       .flags = 0, .buf = buf, .len = len };
24562306a36Sopenharmony_ci	if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
24662306a36Sopenharmony_ci		if (priv->ignore_i2c_write_errors == 0) {
24762306a36Sopenharmony_ci			printk(KERN_ERR "xc4000: I2C write failed (len=%i)\n",
24862306a36Sopenharmony_ci			       len);
24962306a36Sopenharmony_ci			if (len == 4) {
25062306a36Sopenharmony_ci				printk(KERN_ERR "bytes %*ph\n", 4, buf);
25162306a36Sopenharmony_ci			}
25262306a36Sopenharmony_ci			return -EREMOTEIO;
25362306a36Sopenharmony_ci		}
25462306a36Sopenharmony_ci	}
25562306a36Sopenharmony_ci	return 0;
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic int xc4000_tuner_reset(struct dvb_frontend *fe)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	struct xc4000_priv *priv = fe->tuner_priv;
26162306a36Sopenharmony_ci	int ret;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	if (fe->callback) {
26662306a36Sopenharmony_ci		ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
26762306a36Sopenharmony_ci					   fe->dvb->priv :
26862306a36Sopenharmony_ci					   priv->i2c_props.adap->algo_data,
26962306a36Sopenharmony_ci					   DVB_FRONTEND_COMPONENT_TUNER,
27062306a36Sopenharmony_ci					   XC4000_TUNER_RESET, 0);
27162306a36Sopenharmony_ci		if (ret) {
27262306a36Sopenharmony_ci			printk(KERN_ERR "xc4000: reset failed\n");
27362306a36Sopenharmony_ci			return -EREMOTEIO;
27462306a36Sopenharmony_ci		}
27562306a36Sopenharmony_ci	} else {
27662306a36Sopenharmony_ci		printk(KERN_ERR "xc4000: no tuner reset callback function, fatal\n");
27762306a36Sopenharmony_ci		return -EINVAL;
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci	return 0;
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic int xc_write_reg(struct xc4000_priv *priv, u16 regAddr, u16 i2cData)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	u8 buf[4];
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	buf[0] = (regAddr >> 8) & 0xFF;
28762306a36Sopenharmony_ci	buf[1] = regAddr & 0xFF;
28862306a36Sopenharmony_ci	buf[2] = (i2cData >> 8) & 0xFF;
28962306a36Sopenharmony_ci	buf[3] = i2cData & 0xFF;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	return xc_send_i2c_data(priv, buf, 4);
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	struct xc4000_priv *priv = fe->tuner_priv;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	int i, nbytes_to_send, result;
29962306a36Sopenharmony_ci	unsigned int len, pos, index;
30062306a36Sopenharmony_ci	u8 buf[XC_MAX_I2C_WRITE_LENGTH];
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	index = 0;
30362306a36Sopenharmony_ci	while ((i2c_sequence[index] != 0xFF) ||
30462306a36Sopenharmony_ci		(i2c_sequence[index + 1] != 0xFF)) {
30562306a36Sopenharmony_ci		len = i2c_sequence[index] * 256 + i2c_sequence[index+1];
30662306a36Sopenharmony_ci		if (len == 0x0000) {
30762306a36Sopenharmony_ci			/* RESET command */
30862306a36Sopenharmony_ci			/* NOTE: this is ignored, as the reset callback was */
30962306a36Sopenharmony_ci			/* already called by check_firmware() */
31062306a36Sopenharmony_ci			index += 2;
31162306a36Sopenharmony_ci		} else if (len & 0x8000) {
31262306a36Sopenharmony_ci			/* WAIT command */
31362306a36Sopenharmony_ci			msleep(len & 0x7FFF);
31462306a36Sopenharmony_ci			index += 2;
31562306a36Sopenharmony_ci		} else {
31662306a36Sopenharmony_ci			/* Send i2c data whilst ensuring individual transactions
31762306a36Sopenharmony_ci			 * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes.
31862306a36Sopenharmony_ci			 */
31962306a36Sopenharmony_ci			index += 2;
32062306a36Sopenharmony_ci			buf[0] = i2c_sequence[index];
32162306a36Sopenharmony_ci			buf[1] = i2c_sequence[index + 1];
32262306a36Sopenharmony_ci			pos = 2;
32362306a36Sopenharmony_ci			while (pos < len) {
32462306a36Sopenharmony_ci				if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2)
32562306a36Sopenharmony_ci					nbytes_to_send =
32662306a36Sopenharmony_ci						XC_MAX_I2C_WRITE_LENGTH;
32762306a36Sopenharmony_ci				else
32862306a36Sopenharmony_ci					nbytes_to_send = (len - pos + 2);
32962306a36Sopenharmony_ci				for (i = 2; i < nbytes_to_send; i++) {
33062306a36Sopenharmony_ci					buf[i] = i2c_sequence[index + pos +
33162306a36Sopenharmony_ci						i - 2];
33262306a36Sopenharmony_ci				}
33362306a36Sopenharmony_ci				result = xc_send_i2c_data(priv, buf,
33462306a36Sopenharmony_ci					nbytes_to_send);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci				if (result != 0)
33762306a36Sopenharmony_ci					return result;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci				pos += nbytes_to_send - 2;
34062306a36Sopenharmony_ci			}
34162306a36Sopenharmony_ci			index += len;
34262306a36Sopenharmony_ci		}
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci	return 0;
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cistatic int xc_set_tv_standard(struct xc4000_priv *priv,
34862306a36Sopenharmony_ci	u16 video_mode, u16 audio_mode)
34962306a36Sopenharmony_ci{
35062306a36Sopenharmony_ci	int ret;
35162306a36Sopenharmony_ci	dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, video_mode, audio_mode);
35262306a36Sopenharmony_ci	dprintk(1, "%s() Standard = %s\n",
35362306a36Sopenharmony_ci		__func__,
35462306a36Sopenharmony_ci		xc4000_standard[priv->video_standard].Name);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	/* Don't complain when the request fails because of i2c stretching */
35762306a36Sopenharmony_ci	priv->ignore_i2c_write_errors = 1;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	ret = xc_write_reg(priv, XREG_VIDEO_MODE, video_mode);
36062306a36Sopenharmony_ci	if (ret == 0)
36162306a36Sopenharmony_ci		ret = xc_write_reg(priv, XREG_AUDIO_MODE, audio_mode);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	priv->ignore_i2c_write_errors = 0;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	return ret;
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_cistatic int xc_set_signal_source(struct xc4000_priv *priv, u16 rf_mode)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
37162306a36Sopenharmony_ci		rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) {
37462306a36Sopenharmony_ci		rf_mode = XC_RF_MODE_CABLE;
37562306a36Sopenharmony_ci		printk(KERN_ERR
37662306a36Sopenharmony_ci			"%s(), Invalid mode, defaulting to CABLE",
37762306a36Sopenharmony_ci			__func__);
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci	return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode);
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cistatic const struct dvb_tuner_ops xc4000_tuner_ops;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic int xc_set_rf_frequency(struct xc4000_priv *priv, u32 freq_hz)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	u16 freq_code;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	dprintk(1, "%s(%u)\n", __func__, freq_hz);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	if ((freq_hz > xc4000_tuner_ops.info.frequency_max_hz) ||
39162306a36Sopenharmony_ci	    (freq_hz < xc4000_tuner_ops.info.frequency_min_hz))
39262306a36Sopenharmony_ci		return -EINVAL;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	freq_code = (u16)(freq_hz / 15625);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	/* WAS: Starting in firmware version 1.1.44, Xceive recommends using the
39762306a36Sopenharmony_ci	   FINERFREQ for all normal tuning (the doc indicates reg 0x03 should
39862306a36Sopenharmony_ci	   only be used for fast scanning for channel lock) */
39962306a36Sopenharmony_ci	/* WAS: XREG_FINERFREQ */
40062306a36Sopenharmony_ci	return xc_write_reg(priv, XREG_RF_FREQ, freq_code);
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cistatic int xc_get_adc_envelope(struct xc4000_priv *priv, u16 *adc_envelope)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	return xc4000_readreg(priv, XREG_ADC_ENV, adc_envelope);
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_cistatic int xc_get_frequency_error(struct xc4000_priv *priv, u32 *freq_error_hz)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	int result;
41162306a36Sopenharmony_ci	u16 regData;
41262306a36Sopenharmony_ci	u32 tmp;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	result = xc4000_readreg(priv, XREG_FREQ_ERROR, &regData);
41562306a36Sopenharmony_ci	if (result != 0)
41662306a36Sopenharmony_ci		return result;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	tmp = (u32)regData & 0xFFFFU;
41962306a36Sopenharmony_ci	tmp = (tmp < 0x8000U ? tmp : 0x10000U - tmp);
42062306a36Sopenharmony_ci	(*freq_error_hz) = tmp * 15625;
42162306a36Sopenharmony_ci	return result;
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic int xc_get_lock_status(struct xc4000_priv *priv, u16 *lock_status)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	return xc4000_readreg(priv, XREG_LOCK, lock_status);
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_cistatic int xc_get_version(struct xc4000_priv *priv,
43062306a36Sopenharmony_ci	u8 *hw_majorversion, u8 *hw_minorversion,
43162306a36Sopenharmony_ci	u8 *fw_majorversion, u8 *fw_minorversion)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	u16 data;
43462306a36Sopenharmony_ci	int result;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	result = xc4000_readreg(priv, XREG_VERSION, &data);
43762306a36Sopenharmony_ci	if (result != 0)
43862306a36Sopenharmony_ci		return result;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	(*hw_majorversion) = (data >> 12) & 0x0F;
44162306a36Sopenharmony_ci	(*hw_minorversion) = (data >>  8) & 0x0F;
44262306a36Sopenharmony_ci	(*fw_majorversion) = (data >>  4) & 0x0F;
44362306a36Sopenharmony_ci	(*fw_minorversion) = data & 0x0F;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	return 0;
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_cistatic int xc_get_hsync_freq(struct xc4000_priv *priv, u32 *hsync_freq_hz)
44962306a36Sopenharmony_ci{
45062306a36Sopenharmony_ci	u16 regData;
45162306a36Sopenharmony_ci	int result;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	result = xc4000_readreg(priv, XREG_HSYNC_FREQ, &regData);
45462306a36Sopenharmony_ci	if (result != 0)
45562306a36Sopenharmony_ci		return result;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	(*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
45862306a36Sopenharmony_ci	return result;
45962306a36Sopenharmony_ci}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_cistatic int xc_get_frame_lines(struct xc4000_priv *priv, u16 *frame_lines)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	return xc4000_readreg(priv, XREG_FRAME_LINES, frame_lines);
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic int xc_get_quality(struct xc4000_priv *priv, u16 *quality)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	return xc4000_readreg(priv, XREG_QUALITY, quality);
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_cistatic int xc_get_signal_level(struct xc4000_priv *priv, u16 *signal)
47262306a36Sopenharmony_ci{
47362306a36Sopenharmony_ci	return xc4000_readreg(priv, XREG_SIGNAL_LEVEL, signal);
47462306a36Sopenharmony_ci}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_cistatic int xc_get_noise_level(struct xc4000_priv *priv, u16 *noise)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	return xc4000_readreg(priv, XREG_NOISE_LEVEL, noise);
47962306a36Sopenharmony_ci}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_cistatic u16 xc_wait_for_lock(struct xc4000_priv *priv)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	u16	lock_state = 0;
48462306a36Sopenharmony_ci	int	watchdog_count = 40;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	while ((lock_state == 0) && (watchdog_count > 0)) {
48762306a36Sopenharmony_ci		xc_get_lock_status(priv, &lock_state);
48862306a36Sopenharmony_ci		if (lock_state != 1) {
48962306a36Sopenharmony_ci			msleep(5);
49062306a36Sopenharmony_ci			watchdog_count--;
49162306a36Sopenharmony_ci		}
49262306a36Sopenharmony_ci	}
49362306a36Sopenharmony_ci	return lock_state;
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cistatic int xc_tune_channel(struct xc4000_priv *priv, u32 freq_hz)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	int	found = 1;
49962306a36Sopenharmony_ci	int	result;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	dprintk(1, "%s(%u)\n", __func__, freq_hz);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	/* Don't complain when the request fails because of i2c stretching */
50462306a36Sopenharmony_ci	priv->ignore_i2c_write_errors = 1;
50562306a36Sopenharmony_ci	result = xc_set_rf_frequency(priv, freq_hz);
50662306a36Sopenharmony_ci	priv->ignore_i2c_write_errors = 0;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	if (result != 0)
50962306a36Sopenharmony_ci		return 0;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	/* wait for lock only in analog TV mode */
51262306a36Sopenharmony_ci	if ((priv->cur_fw.type & (FM | DTV6 | DTV7 | DTV78 | DTV8)) == 0) {
51362306a36Sopenharmony_ci		if (xc_wait_for_lock(priv) != 1)
51462306a36Sopenharmony_ci			found = 0;
51562306a36Sopenharmony_ci	}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	/* Wait for stats to stabilize.
51862306a36Sopenharmony_ci	 * Frame Lines needs two frame times after initial lock
51962306a36Sopenharmony_ci	 * before it is valid.
52062306a36Sopenharmony_ci	 */
52162306a36Sopenharmony_ci	msleep(debug ? 100 : 10);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	if (debug)
52462306a36Sopenharmony_ci		xc_debug_dump(priv);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	return found;
52762306a36Sopenharmony_ci}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_cistatic int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val)
53062306a36Sopenharmony_ci{
53162306a36Sopenharmony_ci	u8 buf[2] = { reg >> 8, reg & 0xff };
53262306a36Sopenharmony_ci	u8 bval[2] = { 0, 0 };
53362306a36Sopenharmony_ci	struct i2c_msg msg[2] = {
53462306a36Sopenharmony_ci		{ .addr = priv->i2c_props.addr,
53562306a36Sopenharmony_ci			.flags = 0, .buf = &buf[0], .len = 2 },
53662306a36Sopenharmony_ci		{ .addr = priv->i2c_props.addr,
53762306a36Sopenharmony_ci			.flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
53862306a36Sopenharmony_ci	};
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
54162306a36Sopenharmony_ci		printk(KERN_ERR "xc4000: I2C read failed\n");
54262306a36Sopenharmony_ci		return -EREMOTEIO;
54362306a36Sopenharmony_ci	}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	*val = (bval[0] << 8) | bval[1];
54662306a36Sopenharmony_ci	return 0;
54762306a36Sopenharmony_ci}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci#define dump_firm_type(t)	dump_firm_type_and_int_freq(t, 0)
55062306a36Sopenharmony_cistatic void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	if (type & BASE)
55362306a36Sopenharmony_ci		printk(KERN_CONT "BASE ");
55462306a36Sopenharmony_ci	if (type & INIT1)
55562306a36Sopenharmony_ci		printk(KERN_CONT "INIT1 ");
55662306a36Sopenharmony_ci	if (type & F8MHZ)
55762306a36Sopenharmony_ci		printk(KERN_CONT "F8MHZ ");
55862306a36Sopenharmony_ci	if (type & MTS)
55962306a36Sopenharmony_ci		printk(KERN_CONT "MTS ");
56062306a36Sopenharmony_ci	if (type & D2620)
56162306a36Sopenharmony_ci		printk(KERN_CONT "D2620 ");
56262306a36Sopenharmony_ci	if (type & D2633)
56362306a36Sopenharmony_ci		printk(KERN_CONT "D2633 ");
56462306a36Sopenharmony_ci	if (type & DTV6)
56562306a36Sopenharmony_ci		printk(KERN_CONT "DTV6 ");
56662306a36Sopenharmony_ci	if (type & QAM)
56762306a36Sopenharmony_ci		printk(KERN_CONT "QAM ");
56862306a36Sopenharmony_ci	if (type & DTV7)
56962306a36Sopenharmony_ci		printk(KERN_CONT "DTV7 ");
57062306a36Sopenharmony_ci	if (type & DTV78)
57162306a36Sopenharmony_ci		printk(KERN_CONT "DTV78 ");
57262306a36Sopenharmony_ci	if (type & DTV8)
57362306a36Sopenharmony_ci		printk(KERN_CONT "DTV8 ");
57462306a36Sopenharmony_ci	if (type & FM)
57562306a36Sopenharmony_ci		printk(KERN_CONT "FM ");
57662306a36Sopenharmony_ci	if (type & INPUT1)
57762306a36Sopenharmony_ci		printk(KERN_CONT "INPUT1 ");
57862306a36Sopenharmony_ci	if (type & LCD)
57962306a36Sopenharmony_ci		printk(KERN_CONT "LCD ");
58062306a36Sopenharmony_ci	if (type & NOGD)
58162306a36Sopenharmony_ci		printk(KERN_CONT "NOGD ");
58262306a36Sopenharmony_ci	if (type & MONO)
58362306a36Sopenharmony_ci		printk(KERN_CONT "MONO ");
58462306a36Sopenharmony_ci	if (type & ATSC)
58562306a36Sopenharmony_ci		printk(KERN_CONT "ATSC ");
58662306a36Sopenharmony_ci	if (type & IF)
58762306a36Sopenharmony_ci		printk(KERN_CONT "IF ");
58862306a36Sopenharmony_ci	if (type & LG60)
58962306a36Sopenharmony_ci		printk(KERN_CONT "LG60 ");
59062306a36Sopenharmony_ci	if (type & ATI638)
59162306a36Sopenharmony_ci		printk(KERN_CONT "ATI638 ");
59262306a36Sopenharmony_ci	if (type & OREN538)
59362306a36Sopenharmony_ci		printk(KERN_CONT "OREN538 ");
59462306a36Sopenharmony_ci	if (type & OREN36)
59562306a36Sopenharmony_ci		printk(KERN_CONT "OREN36 ");
59662306a36Sopenharmony_ci	if (type & TOYOTA388)
59762306a36Sopenharmony_ci		printk(KERN_CONT "TOYOTA388 ");
59862306a36Sopenharmony_ci	if (type & TOYOTA794)
59962306a36Sopenharmony_ci		printk(KERN_CONT "TOYOTA794 ");
60062306a36Sopenharmony_ci	if (type & DIBCOM52)
60162306a36Sopenharmony_ci		printk(KERN_CONT "DIBCOM52 ");
60262306a36Sopenharmony_ci	if (type & ZARLINK456)
60362306a36Sopenharmony_ci		printk(KERN_CONT "ZARLINK456 ");
60462306a36Sopenharmony_ci	if (type & CHINA)
60562306a36Sopenharmony_ci		printk(KERN_CONT "CHINA ");
60662306a36Sopenharmony_ci	if (type & F6MHZ)
60762306a36Sopenharmony_ci		printk(KERN_CONT "F6MHZ ");
60862306a36Sopenharmony_ci	if (type & INPUT2)
60962306a36Sopenharmony_ci		printk(KERN_CONT "INPUT2 ");
61062306a36Sopenharmony_ci	if (type & SCODE)
61162306a36Sopenharmony_ci		printk(KERN_CONT "SCODE ");
61262306a36Sopenharmony_ci	if (type & HAS_IF)
61362306a36Sopenharmony_ci		printk(KERN_CONT "HAS_IF_%d ", int_freq);
61462306a36Sopenharmony_ci}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_cistatic int seek_firmware(struct dvb_frontend *fe, unsigned int type,
61762306a36Sopenharmony_ci			 v4l2_std_id *id)
61862306a36Sopenharmony_ci{
61962306a36Sopenharmony_ci	struct xc4000_priv *priv = fe->tuner_priv;
62062306a36Sopenharmony_ci	int		i, best_i = -1;
62162306a36Sopenharmony_ci	unsigned int	best_nr_diffs = 255U;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	if (!priv->firm) {
62462306a36Sopenharmony_ci		printk(KERN_ERR "Error! firmware not loaded\n");
62562306a36Sopenharmony_ci		return -EINVAL;
62662306a36Sopenharmony_ci	}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	if (((type & ~SCODE) == 0) && (*id == 0))
62962306a36Sopenharmony_ci		*id = V4L2_STD_PAL;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	/* Seek for generic video standard match */
63262306a36Sopenharmony_ci	for (i = 0; i < priv->firm_size; i++) {
63362306a36Sopenharmony_ci		v4l2_std_id	id_diff_mask =
63462306a36Sopenharmony_ci			(priv->firm[i].id ^ (*id)) & (*id);
63562306a36Sopenharmony_ci		unsigned int	type_diff_mask =
63662306a36Sopenharmony_ci			(priv->firm[i].type ^ type)
63762306a36Sopenharmony_ci			& (BASE_TYPES | DTV_TYPES | LCD | NOGD | MONO | SCODE);
63862306a36Sopenharmony_ci		unsigned int	nr_diffs;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci		if (type_diff_mask
64162306a36Sopenharmony_ci		    & (BASE | INIT1 | FM | DTV6 | DTV7 | DTV78 | DTV8 | SCODE))
64262306a36Sopenharmony_ci			continue;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci		nr_diffs = hweight64(id_diff_mask) + hweight32(type_diff_mask);
64562306a36Sopenharmony_ci		if (!nr_diffs)	/* Supports all the requested standards */
64662306a36Sopenharmony_ci			goto found;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci		if (nr_diffs < best_nr_diffs) {
64962306a36Sopenharmony_ci			best_nr_diffs = nr_diffs;
65062306a36Sopenharmony_ci			best_i = i;
65162306a36Sopenharmony_ci		}
65262306a36Sopenharmony_ci	}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	/* FIXME: Would make sense to seek for type "hint" match ? */
65562306a36Sopenharmony_ci	if (best_i < 0) {
65662306a36Sopenharmony_ci		i = -ENOENT;
65762306a36Sopenharmony_ci		goto ret;
65862306a36Sopenharmony_ci	}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	if (best_nr_diffs > 0U) {
66162306a36Sopenharmony_ci		printk(KERN_WARNING
66262306a36Sopenharmony_ci		       "Selecting best matching firmware (%u bits differ) for type=(%x), id %016llx:\n",
66362306a36Sopenharmony_ci		       best_nr_diffs, type, (unsigned long long)*id);
66462306a36Sopenharmony_ci		i = best_i;
66562306a36Sopenharmony_ci	}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_cifound:
66862306a36Sopenharmony_ci	*id = priv->firm[i].id;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ciret:
67162306a36Sopenharmony_ci	if (debug) {
67262306a36Sopenharmony_ci		printk(KERN_DEBUG "%s firmware for type=",
67362306a36Sopenharmony_ci		       (i < 0) ? "Can't find" : "Found");
67462306a36Sopenharmony_ci		dump_firm_type(type);
67562306a36Sopenharmony_ci		printk(KERN_DEBUG "(%x), id %016llx.\n", type, (unsigned long long)*id);
67662306a36Sopenharmony_ci	}
67762306a36Sopenharmony_ci	return i;
67862306a36Sopenharmony_ci}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_cistatic int load_firmware(struct dvb_frontend *fe, unsigned int type,
68162306a36Sopenharmony_ci			 v4l2_std_id *id)
68262306a36Sopenharmony_ci{
68362306a36Sopenharmony_ci	struct xc4000_priv *priv = fe->tuner_priv;
68462306a36Sopenharmony_ci	int                pos, rc;
68562306a36Sopenharmony_ci	unsigned char      *p;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	pos = seek_firmware(fe, type, id);
68862306a36Sopenharmony_ci	if (pos < 0)
68962306a36Sopenharmony_ci		return pos;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	p = priv->firm[pos].ptr;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	/* Don't complain when the request fails because of i2c stretching */
69462306a36Sopenharmony_ci	priv->ignore_i2c_write_errors = 1;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	rc = xc_load_i2c_sequence(fe, p);
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	priv->ignore_i2c_write_errors = 0;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	return rc;
70162306a36Sopenharmony_ci}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_cistatic int xc4000_fwupload(struct dvb_frontend *fe)
70462306a36Sopenharmony_ci{
70562306a36Sopenharmony_ci	struct xc4000_priv *priv = fe->tuner_priv;
70662306a36Sopenharmony_ci	const struct firmware *fw   = NULL;
70762306a36Sopenharmony_ci	const unsigned char   *p, *endp;
70862306a36Sopenharmony_ci	int                   rc = 0;
70962306a36Sopenharmony_ci	int		      n, n_array;
71062306a36Sopenharmony_ci	char		      name[33];
71162306a36Sopenharmony_ci	const char	      *fname;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	if (firmware_name[0] != '\0') {
71462306a36Sopenharmony_ci		fname = firmware_name;
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci		dprintk(1, "Reading custom firmware %s\n", fname);
71762306a36Sopenharmony_ci		rc = request_firmware(&fw, fname,
71862306a36Sopenharmony_ci				      priv->i2c_props.adap->dev.parent);
71962306a36Sopenharmony_ci	} else {
72062306a36Sopenharmony_ci		fname = XC4000_DEFAULT_FIRMWARE_NEW;
72162306a36Sopenharmony_ci		dprintk(1, "Trying to read firmware %s\n", fname);
72262306a36Sopenharmony_ci		rc = request_firmware(&fw, fname,
72362306a36Sopenharmony_ci				      priv->i2c_props.adap->dev.parent);
72462306a36Sopenharmony_ci		if (rc == -ENOENT) {
72562306a36Sopenharmony_ci			fname = XC4000_DEFAULT_FIRMWARE;
72662306a36Sopenharmony_ci			dprintk(1, "Trying to read firmware %s\n", fname);
72762306a36Sopenharmony_ci			rc = request_firmware(&fw, fname,
72862306a36Sopenharmony_ci					      priv->i2c_props.adap->dev.parent);
72962306a36Sopenharmony_ci		}
73062306a36Sopenharmony_ci	}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	if (rc < 0) {
73362306a36Sopenharmony_ci		if (rc == -ENOENT)
73462306a36Sopenharmony_ci			printk(KERN_ERR "Error: firmware %s not found.\n", fname);
73562306a36Sopenharmony_ci		else
73662306a36Sopenharmony_ci			printk(KERN_ERR "Error %d while requesting firmware %s\n",
73762306a36Sopenharmony_ci			       rc, fname);
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci		return rc;
74062306a36Sopenharmony_ci	}
74162306a36Sopenharmony_ci	dprintk(1, "Loading Firmware: %s\n", fname);
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	p = fw->data;
74462306a36Sopenharmony_ci	endp = p + fw->size;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	if (fw->size < sizeof(name) - 1 + 2 + 2) {
74762306a36Sopenharmony_ci		printk(KERN_ERR "Error: firmware file %s has invalid size!\n",
74862306a36Sopenharmony_ci		       fname);
74962306a36Sopenharmony_ci		goto corrupt;
75062306a36Sopenharmony_ci	}
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	memcpy(name, p, sizeof(name) - 1);
75362306a36Sopenharmony_ci	name[sizeof(name) - 1] = '\0';
75462306a36Sopenharmony_ci	p += sizeof(name) - 1;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	priv->firm_version = get_unaligned_le16(p);
75762306a36Sopenharmony_ci	p += 2;
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	n_array = get_unaligned_le16(p);
76062306a36Sopenharmony_ci	p += 2;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	dprintk(1, "Loading %d firmware images from %s, type: %s, ver %d.%d\n",
76362306a36Sopenharmony_ci		n_array, fname, name,
76462306a36Sopenharmony_ci		priv->firm_version >> 8, priv->firm_version & 0xff);
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL);
76762306a36Sopenharmony_ci	if (priv->firm == NULL) {
76862306a36Sopenharmony_ci		printk(KERN_ERR "Not enough memory to load firmware file.\n");
76962306a36Sopenharmony_ci		rc = -ENOMEM;
77062306a36Sopenharmony_ci		goto done;
77162306a36Sopenharmony_ci	}
77262306a36Sopenharmony_ci	priv->firm_size = n_array;
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	n = -1;
77562306a36Sopenharmony_ci	while (p < endp) {
77662306a36Sopenharmony_ci		__u32 type, size;
77762306a36Sopenharmony_ci		v4l2_std_id id;
77862306a36Sopenharmony_ci		__u16 int_freq = 0;
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci		n++;
78162306a36Sopenharmony_ci		if (n >= n_array) {
78262306a36Sopenharmony_ci			printk(KERN_ERR "More firmware images in file than were expected!\n");
78362306a36Sopenharmony_ci			goto corrupt;
78462306a36Sopenharmony_ci		}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci		/* Checks if there's enough bytes to read */
78762306a36Sopenharmony_ci		if (endp - p < sizeof(type) + sizeof(id) + sizeof(size))
78862306a36Sopenharmony_ci			goto header;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci		type = get_unaligned_le32(p);
79162306a36Sopenharmony_ci		p += sizeof(type);
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci		id = get_unaligned_le64(p);
79462306a36Sopenharmony_ci		p += sizeof(id);
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci		if (type & HAS_IF) {
79762306a36Sopenharmony_ci			int_freq = get_unaligned_le16(p);
79862306a36Sopenharmony_ci			p += sizeof(int_freq);
79962306a36Sopenharmony_ci			if (endp - p < sizeof(size))
80062306a36Sopenharmony_ci				goto header;
80162306a36Sopenharmony_ci		}
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci		size = get_unaligned_le32(p);
80462306a36Sopenharmony_ci		p += sizeof(size);
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci		if (!size || size > endp - p) {
80762306a36Sopenharmony_ci			printk(KERN_ERR "Firmware type (%x), id %llx is corrupted (size=%zd, expected %d)\n",
80862306a36Sopenharmony_ci			       type, (unsigned long long)id,
80962306a36Sopenharmony_ci			       endp - p, size);
81062306a36Sopenharmony_ci			goto corrupt;
81162306a36Sopenharmony_ci		}
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci		priv->firm[n].ptr = kmemdup(p, size, GFP_KERNEL);
81462306a36Sopenharmony_ci		if (priv->firm[n].ptr == NULL) {
81562306a36Sopenharmony_ci			printk(KERN_ERR "Not enough memory to load firmware file.\n");
81662306a36Sopenharmony_ci			rc = -ENOMEM;
81762306a36Sopenharmony_ci			goto done;
81862306a36Sopenharmony_ci		}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci		if (debug) {
82162306a36Sopenharmony_ci			printk(KERN_DEBUG "Reading firmware type ");
82262306a36Sopenharmony_ci			dump_firm_type_and_int_freq(type, int_freq);
82362306a36Sopenharmony_ci			printk(KERN_DEBUG "(%x), id %llx, size=%d.\n",
82462306a36Sopenharmony_ci			       type, (unsigned long long)id, size);
82562306a36Sopenharmony_ci		}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci		priv->firm[n].type = type;
82862306a36Sopenharmony_ci		priv->firm[n].id   = id;
82962306a36Sopenharmony_ci		priv->firm[n].size = size;
83062306a36Sopenharmony_ci		priv->firm[n].int_freq = int_freq;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci		p += size;
83362306a36Sopenharmony_ci	}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	if (n + 1 != priv->firm_size) {
83662306a36Sopenharmony_ci		printk(KERN_ERR "Firmware file is incomplete!\n");
83762306a36Sopenharmony_ci		goto corrupt;
83862306a36Sopenharmony_ci	}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	goto done;
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ciheader:
84362306a36Sopenharmony_ci	printk(KERN_ERR "Firmware header is incomplete!\n");
84462306a36Sopenharmony_cicorrupt:
84562306a36Sopenharmony_ci	rc = -EINVAL;
84662306a36Sopenharmony_ci	printk(KERN_ERR "Error: firmware file is corrupted!\n");
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_cidone:
84962306a36Sopenharmony_ci	release_firmware(fw);
85062306a36Sopenharmony_ci	if (rc == 0)
85162306a36Sopenharmony_ci		dprintk(1, "Firmware files loaded.\n");
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	return rc;
85462306a36Sopenharmony_ci}
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_cistatic int load_scode(struct dvb_frontend *fe, unsigned int type,
85762306a36Sopenharmony_ci			 v4l2_std_id *id, __u16 int_freq, int scode)
85862306a36Sopenharmony_ci{
85962306a36Sopenharmony_ci	struct xc4000_priv *priv = fe->tuner_priv;
86062306a36Sopenharmony_ci	int		pos, rc;
86162306a36Sopenharmony_ci	unsigned char	*p;
86262306a36Sopenharmony_ci	u8		scode_buf[13];
86362306a36Sopenharmony_ci	u8		indirect_mode[5];
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	dprintk(1, "%s called int_freq=%d\n", __func__, int_freq);
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	if (!int_freq) {
86862306a36Sopenharmony_ci		pos = seek_firmware(fe, type, id);
86962306a36Sopenharmony_ci		if (pos < 0)
87062306a36Sopenharmony_ci			return pos;
87162306a36Sopenharmony_ci	} else {
87262306a36Sopenharmony_ci		for (pos = 0; pos < priv->firm_size; pos++) {
87362306a36Sopenharmony_ci			if ((priv->firm[pos].int_freq == int_freq) &&
87462306a36Sopenharmony_ci			    (priv->firm[pos].type & HAS_IF))
87562306a36Sopenharmony_ci				break;
87662306a36Sopenharmony_ci		}
87762306a36Sopenharmony_ci		if (pos == priv->firm_size)
87862306a36Sopenharmony_ci			return -ENOENT;
87962306a36Sopenharmony_ci	}
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	p = priv->firm[pos].ptr;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	if (priv->firm[pos].size != 12 * 16 || scode >= 16)
88462306a36Sopenharmony_ci		return -EINVAL;
88562306a36Sopenharmony_ci	p += 12 * scode;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	if (debug) {
88862306a36Sopenharmony_ci		tuner_info("Loading SCODE for type=");
88962306a36Sopenharmony_ci		dump_firm_type_and_int_freq(priv->firm[pos].type,
89062306a36Sopenharmony_ci					    priv->firm[pos].int_freq);
89162306a36Sopenharmony_ci		printk(KERN_CONT "(%x), id %016llx.\n", priv->firm[pos].type,
89262306a36Sopenharmony_ci		       (unsigned long long)*id);
89362306a36Sopenharmony_ci	}
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	scode_buf[0] = 0x00;
89662306a36Sopenharmony_ci	memcpy(&scode_buf[1], p, 12);
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	/* Enter direct-mode */
89962306a36Sopenharmony_ci	rc = xc_write_reg(priv, XREG_DIRECTSITTING_MODE, 0);
90062306a36Sopenharmony_ci	if (rc < 0) {
90162306a36Sopenharmony_ci		printk(KERN_ERR "failed to put device into direct mode!\n");
90262306a36Sopenharmony_ci		return -EIO;
90362306a36Sopenharmony_ci	}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	rc = xc_send_i2c_data(priv, scode_buf, 13);
90662306a36Sopenharmony_ci	if (rc != 0) {
90762306a36Sopenharmony_ci		/* Even if the send failed, make sure we set back to indirect
90862306a36Sopenharmony_ci		   mode */
90962306a36Sopenharmony_ci		printk(KERN_ERR "Failed to set scode %d\n", rc);
91062306a36Sopenharmony_ci	}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	/* Switch back to indirect-mode */
91362306a36Sopenharmony_ci	memset(indirect_mode, 0, sizeof(indirect_mode));
91462306a36Sopenharmony_ci	indirect_mode[4] = 0x88;
91562306a36Sopenharmony_ci	xc_send_i2c_data(priv, indirect_mode, sizeof(indirect_mode));
91662306a36Sopenharmony_ci	msleep(10);
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	return 0;
91962306a36Sopenharmony_ci}
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_cistatic int check_firmware(struct dvb_frontend *fe, unsigned int type,
92262306a36Sopenharmony_ci			  v4l2_std_id std, __u16 int_freq)
92362306a36Sopenharmony_ci{
92462306a36Sopenharmony_ci	struct xc4000_priv         *priv = fe->tuner_priv;
92562306a36Sopenharmony_ci	struct firmware_properties new_fw;
92662306a36Sopenharmony_ci	int			   rc = 0, is_retry = 0;
92762306a36Sopenharmony_ci	u16			   hwmodel;
92862306a36Sopenharmony_ci	v4l2_std_id		   std0;
92962306a36Sopenharmony_ci	u8			   hw_major = 0, hw_minor = 0, fw_major = 0, fw_minor = 0;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	dprintk(1, "%s called\n", __func__);
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	if (!priv->firm) {
93462306a36Sopenharmony_ci		rc = xc4000_fwupload(fe);
93562306a36Sopenharmony_ci		if (rc < 0)
93662306a36Sopenharmony_ci			return rc;
93762306a36Sopenharmony_ci	}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ciretry:
94062306a36Sopenharmony_ci	new_fw.type = type;
94162306a36Sopenharmony_ci	new_fw.id = std;
94262306a36Sopenharmony_ci	new_fw.std_req = std;
94362306a36Sopenharmony_ci	new_fw.scode_table = SCODE;
94462306a36Sopenharmony_ci	new_fw.scode_nr = 0;
94562306a36Sopenharmony_ci	new_fw.int_freq = int_freq;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	dprintk(1, "checking firmware, user requested type=");
94862306a36Sopenharmony_ci	if (debug) {
94962306a36Sopenharmony_ci		dump_firm_type(new_fw.type);
95062306a36Sopenharmony_ci		printk(KERN_CONT "(%x), id %016llx, ", new_fw.type,
95162306a36Sopenharmony_ci		       (unsigned long long)new_fw.std_req);
95262306a36Sopenharmony_ci		if (!int_freq)
95362306a36Sopenharmony_ci			printk(KERN_CONT "scode_tbl ");
95462306a36Sopenharmony_ci		else
95562306a36Sopenharmony_ci			printk(KERN_CONT "int_freq %d, ", new_fw.int_freq);
95662306a36Sopenharmony_ci		printk(KERN_CONT "scode_nr %d\n", new_fw.scode_nr);
95762306a36Sopenharmony_ci	}
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	/* No need to reload base firmware if it matches */
96062306a36Sopenharmony_ci	if (priv->cur_fw.type & BASE) {
96162306a36Sopenharmony_ci		dprintk(1, "BASE firmware not changed.\n");
96262306a36Sopenharmony_ci		goto skip_base;
96362306a36Sopenharmony_ci	}
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	/* Updating BASE - forget about all currently loaded firmware */
96662306a36Sopenharmony_ci	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	/* Reset is needed before loading firmware */
96962306a36Sopenharmony_ci	rc = xc4000_tuner_reset(fe);
97062306a36Sopenharmony_ci	if (rc < 0)
97162306a36Sopenharmony_ci		goto fail;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	/* BASE firmwares are all std0 */
97462306a36Sopenharmony_ci	std0 = 0;
97562306a36Sopenharmony_ci	rc = load_firmware(fe, BASE, &std0);
97662306a36Sopenharmony_ci	if (rc < 0) {
97762306a36Sopenharmony_ci		printk(KERN_ERR "Error %d while loading base firmware\n", rc);
97862306a36Sopenharmony_ci		goto fail;
97962306a36Sopenharmony_ci	}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	/* Load INIT1, if needed */
98262306a36Sopenharmony_ci	dprintk(1, "Load init1 firmware, if exists\n");
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	rc = load_firmware(fe, BASE | INIT1, &std0);
98562306a36Sopenharmony_ci	if (rc == -ENOENT)
98662306a36Sopenharmony_ci		rc = load_firmware(fe, BASE | INIT1, &std0);
98762306a36Sopenharmony_ci	if (rc < 0 && rc != -ENOENT) {
98862306a36Sopenharmony_ci		tuner_err("Error %d while loading init1 firmware\n",
98962306a36Sopenharmony_ci			  rc);
99062306a36Sopenharmony_ci		goto fail;
99162306a36Sopenharmony_ci	}
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ciskip_base:
99462306a36Sopenharmony_ci	/*
99562306a36Sopenharmony_ci	 * No need to reload standard specific firmware if base firmware
99662306a36Sopenharmony_ci	 * was not reloaded and requested video standards have not changed.
99762306a36Sopenharmony_ci	 */
99862306a36Sopenharmony_ci	if (priv->cur_fw.type == (BASE | new_fw.type) &&
99962306a36Sopenharmony_ci	    priv->cur_fw.std_req == std) {
100062306a36Sopenharmony_ci		dprintk(1, "Std-specific firmware already loaded.\n");
100162306a36Sopenharmony_ci		goto skip_std_specific;
100262306a36Sopenharmony_ci	}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	/* Reloading std-specific firmware forces a SCODE update */
100562306a36Sopenharmony_ci	priv->cur_fw.scode_table = 0;
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	/* Load the standard firmware */
100862306a36Sopenharmony_ci	rc = load_firmware(fe, new_fw.type, &new_fw.id);
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	if (rc < 0)
101162306a36Sopenharmony_ci		goto fail;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ciskip_std_specific:
101462306a36Sopenharmony_ci	if (priv->cur_fw.scode_table == new_fw.scode_table &&
101562306a36Sopenharmony_ci	    priv->cur_fw.scode_nr == new_fw.scode_nr) {
101662306a36Sopenharmony_ci		dprintk(1, "SCODE firmware already loaded.\n");
101762306a36Sopenharmony_ci		goto check_device;
101862306a36Sopenharmony_ci	}
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	/* Load SCODE firmware, if exists */
102162306a36Sopenharmony_ci	rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id,
102262306a36Sopenharmony_ci			new_fw.int_freq, new_fw.scode_nr);
102362306a36Sopenharmony_ci	if (rc != 0)
102462306a36Sopenharmony_ci		dprintk(1, "load scode failed %d\n", rc);
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_cicheck_device:
102762306a36Sopenharmony_ci	if (xc4000_readreg(priv, XREG_PRODUCT_ID, &hwmodel) < 0) {
102862306a36Sopenharmony_ci		printk(KERN_ERR "Unable to read tuner registers.\n");
102962306a36Sopenharmony_ci		goto fail;
103062306a36Sopenharmony_ci	}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	if (xc_get_version(priv, &hw_major, &hw_minor, &fw_major,
103362306a36Sopenharmony_ci			   &fw_minor) != 0) {
103462306a36Sopenharmony_ci		printk(KERN_ERR "Unable to read tuner registers.\n");
103562306a36Sopenharmony_ci		goto fail;
103662306a36Sopenharmony_ci	}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	dprintk(1, "Device is Xceive %d version %d.%d, firmware version %d.%d\n",
103962306a36Sopenharmony_ci		hwmodel, hw_major, hw_minor, fw_major, fw_minor);
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	/* Check firmware version against what we downloaded. */
104262306a36Sopenharmony_ci	if (priv->firm_version != ((fw_major << 8) | fw_minor)) {
104362306a36Sopenharmony_ci		printk(KERN_WARNING
104462306a36Sopenharmony_ci		       "Incorrect readback of firmware version %d.%d.\n",
104562306a36Sopenharmony_ci		       fw_major, fw_minor);
104662306a36Sopenharmony_ci		goto fail;
104762306a36Sopenharmony_ci	}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	/* Check that the tuner hardware model remains consistent over time. */
105062306a36Sopenharmony_ci	if (priv->hwmodel == 0 &&
105162306a36Sopenharmony_ci	    (hwmodel == XC_PRODUCT_ID_XC4000 ||
105262306a36Sopenharmony_ci	     hwmodel == XC_PRODUCT_ID_XC4100)) {
105362306a36Sopenharmony_ci		priv->hwmodel = hwmodel;
105462306a36Sopenharmony_ci		priv->hwvers = (hw_major << 8) | hw_minor;
105562306a36Sopenharmony_ci	} else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel ||
105662306a36Sopenharmony_ci		   priv->hwvers != ((hw_major << 8) | hw_minor)) {
105762306a36Sopenharmony_ci		printk(KERN_WARNING
105862306a36Sopenharmony_ci		       "Read invalid device hardware information - tuner hung?\n");
105962306a36Sopenharmony_ci		goto fail;
106062306a36Sopenharmony_ci	}
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	priv->cur_fw = new_fw;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	/*
106562306a36Sopenharmony_ci	 * By setting BASE in cur_fw.type only after successfully loading all
106662306a36Sopenharmony_ci	 * firmwares, we can:
106762306a36Sopenharmony_ci	 * 1. Identify that BASE firmware with type=0 has been loaded;
106862306a36Sopenharmony_ci	 * 2. Tell whether BASE firmware was just changed the next time through.
106962306a36Sopenharmony_ci	 */
107062306a36Sopenharmony_ci	priv->cur_fw.type |= BASE;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	return 0;
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_cifail:
107562306a36Sopenharmony_ci	memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
107662306a36Sopenharmony_ci	if (!is_retry) {
107762306a36Sopenharmony_ci		msleep(50);
107862306a36Sopenharmony_ci		is_retry = 1;
107962306a36Sopenharmony_ci		dprintk(1, "Retrying firmware load\n");
108062306a36Sopenharmony_ci		goto retry;
108162306a36Sopenharmony_ci	}
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	if (rc == -ENOENT)
108462306a36Sopenharmony_ci		rc = -EINVAL;
108562306a36Sopenharmony_ci	return rc;
108662306a36Sopenharmony_ci}
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_cistatic void xc_debug_dump(struct xc4000_priv *priv)
108962306a36Sopenharmony_ci{
109062306a36Sopenharmony_ci	u16	adc_envelope;
109162306a36Sopenharmony_ci	u32	freq_error_hz = 0;
109262306a36Sopenharmony_ci	u16	lock_status;
109362306a36Sopenharmony_ci	u32	hsync_freq_hz = 0;
109462306a36Sopenharmony_ci	u16	frame_lines;
109562306a36Sopenharmony_ci	u16	quality;
109662306a36Sopenharmony_ci	u16	signal = 0;
109762306a36Sopenharmony_ci	u16	noise = 0;
109862306a36Sopenharmony_ci	u8	hw_majorversion = 0, hw_minorversion = 0;
109962306a36Sopenharmony_ci	u8	fw_majorversion = 0, fw_minorversion = 0;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	xc_get_adc_envelope(priv, &adc_envelope);
110262306a36Sopenharmony_ci	dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope);
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	xc_get_frequency_error(priv, &freq_error_hz);
110562306a36Sopenharmony_ci	dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz);
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	xc_get_lock_status(priv, &lock_status);
110862306a36Sopenharmony_ci	dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n",
110962306a36Sopenharmony_ci		lock_status);
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci	xc_get_version(priv, &hw_majorversion, &hw_minorversion,
111262306a36Sopenharmony_ci		       &fw_majorversion, &fw_minorversion);
111362306a36Sopenharmony_ci	dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n",
111462306a36Sopenharmony_ci		hw_majorversion, hw_minorversion,
111562306a36Sopenharmony_ci		fw_majorversion, fw_minorversion);
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	if (priv->video_standard < XC4000_DTV6) {
111862306a36Sopenharmony_ci		xc_get_hsync_freq(priv, &hsync_freq_hz);
111962306a36Sopenharmony_ci		dprintk(1, "*** Horizontal sync frequency = %d Hz\n",
112062306a36Sopenharmony_ci			hsync_freq_hz);
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci		xc_get_frame_lines(priv, &frame_lines);
112362306a36Sopenharmony_ci		dprintk(1, "*** Frame lines = %d\n", frame_lines);
112462306a36Sopenharmony_ci	}
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	xc_get_quality(priv, &quality);
112762306a36Sopenharmony_ci	dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality);
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	xc_get_signal_level(priv, &signal);
113062306a36Sopenharmony_ci	dprintk(1, "*** Signal level = -%ddB (%d)\n", signal >> 8, signal);
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	xc_get_noise_level(priv, &noise);
113362306a36Sopenharmony_ci	dprintk(1, "*** Noise level = %ddB (%d)\n", noise >> 8, noise);
113462306a36Sopenharmony_ci}
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_cistatic int xc4000_set_params(struct dvb_frontend *fe)
113762306a36Sopenharmony_ci{
113862306a36Sopenharmony_ci	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
113962306a36Sopenharmony_ci	u32 delsys = c->delivery_system;
114062306a36Sopenharmony_ci	u32 bw = c->bandwidth_hz;
114162306a36Sopenharmony_ci	struct xc4000_priv *priv = fe->tuner_priv;
114262306a36Sopenharmony_ci	unsigned int type;
114362306a36Sopenharmony_ci	int	ret = -EREMOTEIO;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	dprintk(1, "%s() frequency=%d (Hz)\n", __func__, c->frequency);
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	mutex_lock(&priv->lock);
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	switch (delsys) {
115062306a36Sopenharmony_ci	case SYS_ATSC:
115162306a36Sopenharmony_ci		dprintk(1, "%s() VSB modulation\n", __func__);
115262306a36Sopenharmony_ci		priv->rf_mode = XC_RF_MODE_AIR;
115362306a36Sopenharmony_ci		priv->freq_offset = 1750000;
115462306a36Sopenharmony_ci		priv->video_standard = XC4000_DTV6;
115562306a36Sopenharmony_ci		type = DTV6;
115662306a36Sopenharmony_ci		break;
115762306a36Sopenharmony_ci	case SYS_DVBC_ANNEX_B:
115862306a36Sopenharmony_ci		dprintk(1, "%s() QAM modulation\n", __func__);
115962306a36Sopenharmony_ci		priv->rf_mode = XC_RF_MODE_CABLE;
116062306a36Sopenharmony_ci		priv->freq_offset = 1750000;
116162306a36Sopenharmony_ci		priv->video_standard = XC4000_DTV6;
116262306a36Sopenharmony_ci		type = DTV6;
116362306a36Sopenharmony_ci		break;
116462306a36Sopenharmony_ci	case SYS_DVBT:
116562306a36Sopenharmony_ci	case SYS_DVBT2:
116662306a36Sopenharmony_ci		dprintk(1, "%s() OFDM\n", __func__);
116762306a36Sopenharmony_ci		if (bw == 0) {
116862306a36Sopenharmony_ci			if (c->frequency < 400000000) {
116962306a36Sopenharmony_ci				priv->freq_offset = 2250000;
117062306a36Sopenharmony_ci			} else {
117162306a36Sopenharmony_ci				priv->freq_offset = 2750000;
117262306a36Sopenharmony_ci			}
117362306a36Sopenharmony_ci			priv->video_standard = XC4000_DTV7_8;
117462306a36Sopenharmony_ci			type = DTV78;
117562306a36Sopenharmony_ci		} else if (bw <= 6000000) {
117662306a36Sopenharmony_ci			priv->video_standard = XC4000_DTV6;
117762306a36Sopenharmony_ci			priv->freq_offset = 1750000;
117862306a36Sopenharmony_ci			type = DTV6;
117962306a36Sopenharmony_ci		} else if (bw <= 7000000) {
118062306a36Sopenharmony_ci			priv->video_standard = XC4000_DTV7;
118162306a36Sopenharmony_ci			priv->freq_offset = 2250000;
118262306a36Sopenharmony_ci			type = DTV7;
118362306a36Sopenharmony_ci		} else {
118462306a36Sopenharmony_ci			priv->video_standard = XC4000_DTV8;
118562306a36Sopenharmony_ci			priv->freq_offset = 2750000;
118662306a36Sopenharmony_ci			type = DTV8;
118762306a36Sopenharmony_ci		}
118862306a36Sopenharmony_ci		priv->rf_mode = XC_RF_MODE_AIR;
118962306a36Sopenharmony_ci		break;
119062306a36Sopenharmony_ci	default:
119162306a36Sopenharmony_ci		printk(KERN_ERR "xc4000 delivery system not supported!\n");
119262306a36Sopenharmony_ci		ret = -EINVAL;
119362306a36Sopenharmony_ci		goto fail;
119462306a36Sopenharmony_ci	}
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	priv->freq_hz = c->frequency - priv->freq_offset;
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	dprintk(1, "%s() frequency=%d (compensated)\n",
119962306a36Sopenharmony_ci		__func__, priv->freq_hz);
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	/* Make sure the correct firmware type is loaded */
120262306a36Sopenharmony_ci	if (check_firmware(fe, type, 0, priv->if_khz) != 0)
120362306a36Sopenharmony_ci		goto fail;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	priv->bandwidth = c->bandwidth_hz;
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	ret = xc_set_signal_source(priv, priv->rf_mode);
120862306a36Sopenharmony_ci	if (ret != 0) {
120962306a36Sopenharmony_ci		printk(KERN_ERR "xc4000: xc_set_signal_source(%d) failed\n",
121062306a36Sopenharmony_ci		       priv->rf_mode);
121162306a36Sopenharmony_ci		goto fail;
121262306a36Sopenharmony_ci	} else {
121362306a36Sopenharmony_ci		u16	video_mode, audio_mode;
121462306a36Sopenharmony_ci		video_mode = xc4000_standard[priv->video_standard].video_mode;
121562306a36Sopenharmony_ci		audio_mode = xc4000_standard[priv->video_standard].audio_mode;
121662306a36Sopenharmony_ci		if (type == DTV6 && priv->firm_version != 0x0102)
121762306a36Sopenharmony_ci			video_mode |= 0x0001;
121862306a36Sopenharmony_ci		ret = xc_set_tv_standard(priv, video_mode, audio_mode);
121962306a36Sopenharmony_ci		if (ret != 0) {
122062306a36Sopenharmony_ci			printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n");
122162306a36Sopenharmony_ci			/* DJH - do not return when it fails... */
122262306a36Sopenharmony_ci			/* goto fail; */
122362306a36Sopenharmony_ci		}
122462306a36Sopenharmony_ci	}
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	if (xc_write_reg(priv, XREG_D_CODE, 0) == 0)
122762306a36Sopenharmony_ci		ret = 0;
122862306a36Sopenharmony_ci	if (priv->dvb_amplitude != 0) {
122962306a36Sopenharmony_ci		if (xc_write_reg(priv, XREG_AMPLITUDE,
123062306a36Sopenharmony_ci				 (priv->firm_version != 0x0102 ||
123162306a36Sopenharmony_ci				  priv->dvb_amplitude != 134 ?
123262306a36Sopenharmony_ci				  priv->dvb_amplitude : 132)) != 0)
123362306a36Sopenharmony_ci			ret = -EREMOTEIO;
123462306a36Sopenharmony_ci	}
123562306a36Sopenharmony_ci	if (priv->set_smoothedcvbs != 0) {
123662306a36Sopenharmony_ci		if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0)
123762306a36Sopenharmony_ci			ret = -EREMOTEIO;
123862306a36Sopenharmony_ci	}
123962306a36Sopenharmony_ci	if (ret != 0) {
124062306a36Sopenharmony_ci		printk(KERN_ERR "xc4000: setting registers failed\n");
124162306a36Sopenharmony_ci		/* goto fail; */
124262306a36Sopenharmony_ci	}
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	xc_tune_channel(priv, priv->freq_hz);
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	ret = 0;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_cifail:
124962306a36Sopenharmony_ci	mutex_unlock(&priv->lock);
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	return ret;
125262306a36Sopenharmony_ci}
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_cistatic int xc4000_set_analog_params(struct dvb_frontend *fe,
125562306a36Sopenharmony_ci	struct analog_parameters *params)
125662306a36Sopenharmony_ci{
125762306a36Sopenharmony_ci	struct xc4000_priv *priv = fe->tuner_priv;
125862306a36Sopenharmony_ci	unsigned int type = 0;
125962306a36Sopenharmony_ci	int	ret = -EREMOTEIO;
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	if (params->mode == V4L2_TUNER_RADIO) {
126262306a36Sopenharmony_ci		dprintk(1, "%s() frequency=%d (in units of 62.5Hz)\n",
126362306a36Sopenharmony_ci			__func__, params->frequency);
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci		mutex_lock(&priv->lock);
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci		params->std = 0;
126862306a36Sopenharmony_ci		priv->freq_hz = params->frequency * 125L / 2;
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci		if (audio_std & XC4000_AUDIO_STD_INPUT1) {
127162306a36Sopenharmony_ci			priv->video_standard = XC4000_FM_Radio_INPUT1;
127262306a36Sopenharmony_ci			type = FM | INPUT1;
127362306a36Sopenharmony_ci		} else {
127462306a36Sopenharmony_ci			priv->video_standard = XC4000_FM_Radio_INPUT2;
127562306a36Sopenharmony_ci			type = FM | INPUT2;
127662306a36Sopenharmony_ci		}
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci		goto tune_channel;
127962306a36Sopenharmony_ci	}
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
128262306a36Sopenharmony_ci		__func__, params->frequency);
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	mutex_lock(&priv->lock);
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	/* params->frequency is in units of 62.5khz */
128762306a36Sopenharmony_ci	priv->freq_hz = params->frequency * 62500;
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	params->std &= V4L2_STD_ALL;
129062306a36Sopenharmony_ci	/* if std is not defined, choose one */
129162306a36Sopenharmony_ci	if (!params->std)
129262306a36Sopenharmony_ci		params->std = V4L2_STD_PAL_BG;
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	if (audio_std & XC4000_AUDIO_STD_MONO)
129562306a36Sopenharmony_ci		type = MONO;
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci	if (params->std & V4L2_STD_MN) {
129862306a36Sopenharmony_ci		params->std = V4L2_STD_MN;
129962306a36Sopenharmony_ci		if (audio_std & XC4000_AUDIO_STD_MONO) {
130062306a36Sopenharmony_ci			priv->video_standard = XC4000_MN_NTSC_PAL_Mono;
130162306a36Sopenharmony_ci		} else if (audio_std & XC4000_AUDIO_STD_A2) {
130262306a36Sopenharmony_ci			params->std |= V4L2_STD_A2;
130362306a36Sopenharmony_ci			priv->video_standard = XC4000_MN_NTSC_PAL_A2;
130462306a36Sopenharmony_ci		} else {
130562306a36Sopenharmony_ci			params->std |= V4L2_STD_BTSC;
130662306a36Sopenharmony_ci			priv->video_standard = XC4000_MN_NTSC_PAL_BTSC;
130762306a36Sopenharmony_ci		}
130862306a36Sopenharmony_ci		goto tune_channel;
130962306a36Sopenharmony_ci	}
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	if (params->std & V4L2_STD_PAL_BG) {
131262306a36Sopenharmony_ci		params->std = V4L2_STD_PAL_BG;
131362306a36Sopenharmony_ci		if (audio_std & XC4000_AUDIO_STD_MONO) {
131462306a36Sopenharmony_ci			priv->video_standard = XC4000_BG_PAL_MONO;
131562306a36Sopenharmony_ci		} else if (!(audio_std & XC4000_AUDIO_STD_A2)) {
131662306a36Sopenharmony_ci			if (!(audio_std & XC4000_AUDIO_STD_B)) {
131762306a36Sopenharmony_ci				params->std |= V4L2_STD_NICAM_A;
131862306a36Sopenharmony_ci				priv->video_standard = XC4000_BG_PAL_NICAM;
131962306a36Sopenharmony_ci			} else {
132062306a36Sopenharmony_ci				params->std |= V4L2_STD_NICAM_B;
132162306a36Sopenharmony_ci				priv->video_standard = XC4000_BG_PAL_NICAM;
132262306a36Sopenharmony_ci			}
132362306a36Sopenharmony_ci		} else {
132462306a36Sopenharmony_ci			if (!(audio_std & XC4000_AUDIO_STD_B)) {
132562306a36Sopenharmony_ci				params->std |= V4L2_STD_A2_A;
132662306a36Sopenharmony_ci				priv->video_standard = XC4000_BG_PAL_A2;
132762306a36Sopenharmony_ci			} else {
132862306a36Sopenharmony_ci				params->std |= V4L2_STD_A2_B;
132962306a36Sopenharmony_ci				priv->video_standard = XC4000_BG_PAL_A2;
133062306a36Sopenharmony_ci			}
133162306a36Sopenharmony_ci		}
133262306a36Sopenharmony_ci		goto tune_channel;
133362306a36Sopenharmony_ci	}
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	if (params->std & V4L2_STD_PAL_I) {
133662306a36Sopenharmony_ci		/* default to NICAM audio standard */
133762306a36Sopenharmony_ci		params->std = V4L2_STD_PAL_I | V4L2_STD_NICAM;
133862306a36Sopenharmony_ci		if (audio_std & XC4000_AUDIO_STD_MONO)
133962306a36Sopenharmony_ci			priv->video_standard = XC4000_I_PAL_NICAM_MONO;
134062306a36Sopenharmony_ci		else
134162306a36Sopenharmony_ci			priv->video_standard = XC4000_I_PAL_NICAM;
134262306a36Sopenharmony_ci		goto tune_channel;
134362306a36Sopenharmony_ci	}
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	if (params->std & V4L2_STD_PAL_DK) {
134662306a36Sopenharmony_ci		params->std = V4L2_STD_PAL_DK;
134762306a36Sopenharmony_ci		if (audio_std & XC4000_AUDIO_STD_MONO) {
134862306a36Sopenharmony_ci			priv->video_standard = XC4000_DK_PAL_MONO;
134962306a36Sopenharmony_ci		} else if (audio_std & XC4000_AUDIO_STD_A2) {
135062306a36Sopenharmony_ci			params->std |= V4L2_STD_A2;
135162306a36Sopenharmony_ci			priv->video_standard = XC4000_DK_PAL_A2;
135262306a36Sopenharmony_ci		} else {
135362306a36Sopenharmony_ci			params->std |= V4L2_STD_NICAM;
135462306a36Sopenharmony_ci			priv->video_standard = XC4000_DK_PAL_NICAM;
135562306a36Sopenharmony_ci		}
135662306a36Sopenharmony_ci		goto tune_channel;
135762306a36Sopenharmony_ci	}
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	if (params->std & V4L2_STD_SECAM_DK) {
136062306a36Sopenharmony_ci		/* default to A2 audio standard */
136162306a36Sopenharmony_ci		params->std = V4L2_STD_SECAM_DK | V4L2_STD_A2;
136262306a36Sopenharmony_ci		if (audio_std & XC4000_AUDIO_STD_L) {
136362306a36Sopenharmony_ci			type = 0;
136462306a36Sopenharmony_ci			priv->video_standard = XC4000_DK_SECAM_NICAM;
136562306a36Sopenharmony_ci		} else if (audio_std & XC4000_AUDIO_STD_MONO) {
136662306a36Sopenharmony_ci			priv->video_standard = XC4000_DK_SECAM_A2MONO;
136762306a36Sopenharmony_ci		} else if (audio_std & XC4000_AUDIO_STD_K3) {
136862306a36Sopenharmony_ci			params->std |= V4L2_STD_SECAM_K3;
136962306a36Sopenharmony_ci			priv->video_standard = XC4000_DK_SECAM_A2LDK3;
137062306a36Sopenharmony_ci		} else {
137162306a36Sopenharmony_ci			priv->video_standard = XC4000_DK_SECAM_A2DK1;
137262306a36Sopenharmony_ci		}
137362306a36Sopenharmony_ci		goto tune_channel;
137462306a36Sopenharmony_ci	}
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	if (params->std & V4L2_STD_SECAM_L) {
137762306a36Sopenharmony_ci		/* default to NICAM audio standard */
137862306a36Sopenharmony_ci		type = 0;
137962306a36Sopenharmony_ci		params->std = V4L2_STD_SECAM_L | V4L2_STD_NICAM;
138062306a36Sopenharmony_ci		priv->video_standard = XC4000_L_SECAM_NICAM;
138162306a36Sopenharmony_ci		goto tune_channel;
138262306a36Sopenharmony_ci	}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	if (params->std & V4L2_STD_SECAM_LC) {
138562306a36Sopenharmony_ci		/* default to NICAM audio standard */
138662306a36Sopenharmony_ci		type = 0;
138762306a36Sopenharmony_ci		params->std = V4L2_STD_SECAM_LC | V4L2_STD_NICAM;
138862306a36Sopenharmony_ci		priv->video_standard = XC4000_LC_SECAM_NICAM;
138962306a36Sopenharmony_ci		goto tune_channel;
139062306a36Sopenharmony_ci	}
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_citune_channel:
139362306a36Sopenharmony_ci	/* FIXME: it could be air. */
139462306a36Sopenharmony_ci	priv->rf_mode = XC_RF_MODE_CABLE;
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	if (check_firmware(fe, type, params->std,
139762306a36Sopenharmony_ci			   xc4000_standard[priv->video_standard].int_freq) != 0)
139862306a36Sopenharmony_ci		goto fail;
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	ret = xc_set_signal_source(priv, priv->rf_mode);
140162306a36Sopenharmony_ci	if (ret != 0) {
140262306a36Sopenharmony_ci		printk(KERN_ERR
140362306a36Sopenharmony_ci		       "xc4000: xc_set_signal_source(%d) failed\n",
140462306a36Sopenharmony_ci		       priv->rf_mode);
140562306a36Sopenharmony_ci		goto fail;
140662306a36Sopenharmony_ci	} else {
140762306a36Sopenharmony_ci		u16	video_mode, audio_mode;
140862306a36Sopenharmony_ci		video_mode = xc4000_standard[priv->video_standard].video_mode;
140962306a36Sopenharmony_ci		audio_mode = xc4000_standard[priv->video_standard].audio_mode;
141062306a36Sopenharmony_ci		if (priv->video_standard < XC4000_BG_PAL_A2) {
141162306a36Sopenharmony_ci			if (type & NOGD)
141262306a36Sopenharmony_ci				video_mode &= 0xFF7F;
141362306a36Sopenharmony_ci		} else if (priv->video_standard < XC4000_I_PAL_NICAM) {
141462306a36Sopenharmony_ci			if (priv->firm_version == 0x0102)
141562306a36Sopenharmony_ci				video_mode &= 0xFEFF;
141662306a36Sopenharmony_ci			if (audio_std & XC4000_AUDIO_STD_B)
141762306a36Sopenharmony_ci				video_mode |= 0x0080;
141862306a36Sopenharmony_ci		}
141962306a36Sopenharmony_ci		ret = xc_set_tv_standard(priv, video_mode, audio_mode);
142062306a36Sopenharmony_ci		if (ret != 0) {
142162306a36Sopenharmony_ci			printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n");
142262306a36Sopenharmony_ci			goto fail;
142362306a36Sopenharmony_ci		}
142462306a36Sopenharmony_ci	}
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	if (xc_write_reg(priv, XREG_D_CODE, 0) == 0)
142762306a36Sopenharmony_ci		ret = 0;
142862306a36Sopenharmony_ci	if (xc_write_reg(priv, XREG_AMPLITUDE, 1) != 0)
142962306a36Sopenharmony_ci		ret = -EREMOTEIO;
143062306a36Sopenharmony_ci	if (priv->set_smoothedcvbs != 0) {
143162306a36Sopenharmony_ci		if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0)
143262306a36Sopenharmony_ci			ret = -EREMOTEIO;
143362306a36Sopenharmony_ci	}
143462306a36Sopenharmony_ci	if (ret != 0) {
143562306a36Sopenharmony_ci		printk(KERN_ERR "xc4000: setting registers failed\n");
143662306a36Sopenharmony_ci		goto fail;
143762306a36Sopenharmony_ci	}
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	xc_tune_channel(priv, priv->freq_hz);
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	ret = 0;
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_cifail:
144462306a36Sopenharmony_ci	mutex_unlock(&priv->lock);
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	return ret;
144762306a36Sopenharmony_ci}
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_cistatic int xc4000_get_signal(struct dvb_frontend *fe, u16 *strength)
145062306a36Sopenharmony_ci{
145162306a36Sopenharmony_ci	struct xc4000_priv *priv = fe->tuner_priv;
145262306a36Sopenharmony_ci	u16 value = 0;
145362306a36Sopenharmony_ci	int rc;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	mutex_lock(&priv->lock);
145662306a36Sopenharmony_ci	rc = xc4000_readreg(priv, XREG_SIGNAL_LEVEL, &value);
145762306a36Sopenharmony_ci	mutex_unlock(&priv->lock);
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	if (rc < 0)
146062306a36Sopenharmony_ci		goto ret;
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	/* Information from real testing of DVB-T and radio part,
146362306a36Sopenharmony_ci	   coefficient for one dB is 0xff.
146462306a36Sopenharmony_ci	 */
146562306a36Sopenharmony_ci	tuner_dbg("Signal strength: -%ddB (%05d)\n", value >> 8, value);
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	/* all known digital modes */
146862306a36Sopenharmony_ci	if ((priv->video_standard == XC4000_DTV6) ||
146962306a36Sopenharmony_ci	    (priv->video_standard == XC4000_DTV7) ||
147062306a36Sopenharmony_ci	    (priv->video_standard == XC4000_DTV7_8) ||
147162306a36Sopenharmony_ci	    (priv->video_standard == XC4000_DTV8))
147262306a36Sopenharmony_ci		goto digital;
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	/* Analog mode has NOISE LEVEL important, signal
147562306a36Sopenharmony_ci	   depends only on gain of antenna and amplifiers,
147662306a36Sopenharmony_ci	   but it doesn't tell anything about real quality
147762306a36Sopenharmony_ci	   of reception.
147862306a36Sopenharmony_ci	 */
147962306a36Sopenharmony_ci	mutex_lock(&priv->lock);
148062306a36Sopenharmony_ci	rc = xc4000_readreg(priv, XREG_NOISE_LEVEL, &value);
148162306a36Sopenharmony_ci	mutex_unlock(&priv->lock);
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	tuner_dbg("Noise level: %ddB (%05d)\n", value >> 8, value);
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	/* highest noise level: 32dB */
148662306a36Sopenharmony_ci	if (value >= 0x2000) {
148762306a36Sopenharmony_ci		value = 0;
148862306a36Sopenharmony_ci	} else {
148962306a36Sopenharmony_ci		value = (~value << 3) & 0xffff;
149062306a36Sopenharmony_ci	}
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	goto ret;
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	/* Digital mode has SIGNAL LEVEL important and real
149562306a36Sopenharmony_ci	   noise level is stored in demodulator registers.
149662306a36Sopenharmony_ci	 */
149762306a36Sopenharmony_cidigital:
149862306a36Sopenharmony_ci	/* best signal: -50dB */
149962306a36Sopenharmony_ci	if (value <= 0x3200) {
150062306a36Sopenharmony_ci		value = 0xffff;
150162306a36Sopenharmony_ci	/* minimum: -114dB - should be 0x7200 but real zero is 0x713A */
150262306a36Sopenharmony_ci	} else if (value >= 0x713A) {
150362306a36Sopenharmony_ci		value = 0;
150462306a36Sopenharmony_ci	} else {
150562306a36Sopenharmony_ci		value = ~(value - 0x3200) << 2;
150662306a36Sopenharmony_ci	}
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ciret:
150962306a36Sopenharmony_ci	*strength = value;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	return rc;
151262306a36Sopenharmony_ci}
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_cistatic int xc4000_get_frequency(struct dvb_frontend *fe, u32 *freq)
151562306a36Sopenharmony_ci{
151662306a36Sopenharmony_ci	struct xc4000_priv *priv = fe->tuner_priv;
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	mutex_lock(&priv->lock);
151962306a36Sopenharmony_ci	*freq = priv->freq_hz + priv->freq_offset;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	if (debug) {
152262306a36Sopenharmony_ci		if ((priv->cur_fw.type
152362306a36Sopenharmony_ci		     & (BASE | FM | DTV6 | DTV7 | DTV78 | DTV8)) == BASE) {
152462306a36Sopenharmony_ci			u16	snr = 0;
152562306a36Sopenharmony_ci			if (xc4000_readreg(priv, XREG_SNR, &snr) == 0) {
152662306a36Sopenharmony_ci				mutex_unlock(&priv->lock);
152762306a36Sopenharmony_ci				dprintk(1, "%s() freq = %u, SNR = %d\n",
152862306a36Sopenharmony_ci					__func__, *freq, snr);
152962306a36Sopenharmony_ci				return 0;
153062306a36Sopenharmony_ci			}
153162306a36Sopenharmony_ci		}
153262306a36Sopenharmony_ci	}
153362306a36Sopenharmony_ci	mutex_unlock(&priv->lock);
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	return 0;
153862306a36Sopenharmony_ci}
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_cistatic int xc4000_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
154162306a36Sopenharmony_ci{
154262306a36Sopenharmony_ci	struct xc4000_priv *priv = fe->tuner_priv;
154362306a36Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	*bw = priv->bandwidth;
154662306a36Sopenharmony_ci	return 0;
154762306a36Sopenharmony_ci}
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_cistatic int xc4000_get_status(struct dvb_frontend *fe, u32 *status)
155062306a36Sopenharmony_ci{
155162306a36Sopenharmony_ci	struct xc4000_priv *priv = fe->tuner_priv;
155262306a36Sopenharmony_ci	u16	lock_status = 0;
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	mutex_lock(&priv->lock);
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	if (priv->cur_fw.type & BASE)
155762306a36Sopenharmony_ci		xc_get_lock_status(priv, &lock_status);
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	*status = (lock_status == 1 ?
156062306a36Sopenharmony_ci		   TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO : 0);
156162306a36Sopenharmony_ci	if (priv->cur_fw.type & (DTV6 | DTV7 | DTV78 | DTV8))
156262306a36Sopenharmony_ci		*status &= (~TUNER_STATUS_STEREO);
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	mutex_unlock(&priv->lock);
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	dprintk(2, "%s() lock_status = %d\n", __func__, lock_status);
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	return 0;
156962306a36Sopenharmony_ci}
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_cistatic int xc4000_sleep(struct dvb_frontend *fe)
157262306a36Sopenharmony_ci{
157362306a36Sopenharmony_ci	struct xc4000_priv *priv = fe->tuner_priv;
157462306a36Sopenharmony_ci	int	ret = 0;
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	mutex_lock(&priv->lock);
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	/* Avoid firmware reload on slow devices */
158162306a36Sopenharmony_ci	if ((no_poweroff == 2 ||
158262306a36Sopenharmony_ci	     (no_poweroff == 0 && priv->default_pm != 0)) &&
158362306a36Sopenharmony_ci	    (priv->cur_fw.type & BASE) != 0) {
158462306a36Sopenharmony_ci		/* force reset and firmware reload */
158562306a36Sopenharmony_ci		priv->cur_fw.type = XC_POWERED_DOWN;
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci		if (xc_write_reg(priv, XREG_POWER_DOWN, 0) != 0) {
158862306a36Sopenharmony_ci			printk(KERN_ERR
158962306a36Sopenharmony_ci			       "xc4000: %s() unable to shutdown tuner\n",
159062306a36Sopenharmony_ci			       __func__);
159162306a36Sopenharmony_ci			ret = -EREMOTEIO;
159262306a36Sopenharmony_ci		}
159362306a36Sopenharmony_ci		msleep(20);
159462306a36Sopenharmony_ci	}
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	mutex_unlock(&priv->lock);
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	return ret;
159962306a36Sopenharmony_ci}
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_cistatic int xc4000_init(struct dvb_frontend *fe)
160262306a36Sopenharmony_ci{
160362306a36Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	return 0;
160662306a36Sopenharmony_ci}
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_cistatic void xc4000_release(struct dvb_frontend *fe)
160962306a36Sopenharmony_ci{
161062306a36Sopenharmony_ci	struct xc4000_priv *priv = fe->tuner_priv;
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci	mutex_lock(&xc4000_list_mutex);
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci	if (priv)
161762306a36Sopenharmony_ci		hybrid_tuner_release_state(priv);
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci	mutex_unlock(&xc4000_list_mutex);
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	fe->tuner_priv = NULL;
162262306a36Sopenharmony_ci}
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_cistatic const struct dvb_tuner_ops xc4000_tuner_ops = {
162562306a36Sopenharmony_ci	.info = {
162662306a36Sopenharmony_ci		.name              = "Xceive XC4000",
162762306a36Sopenharmony_ci		.frequency_min_hz  =    1 * MHz,
162862306a36Sopenharmony_ci		.frequency_max_hz  = 1023 * MHz,
162962306a36Sopenharmony_ci		.frequency_step_hz =   50 * kHz,
163062306a36Sopenharmony_ci	},
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	.release	   = xc4000_release,
163362306a36Sopenharmony_ci	.init		   = xc4000_init,
163462306a36Sopenharmony_ci	.sleep		   = xc4000_sleep,
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	.set_params	   = xc4000_set_params,
163762306a36Sopenharmony_ci	.set_analog_params = xc4000_set_analog_params,
163862306a36Sopenharmony_ci	.get_frequency	   = xc4000_get_frequency,
163962306a36Sopenharmony_ci	.get_rf_strength   = xc4000_get_signal,
164062306a36Sopenharmony_ci	.get_bandwidth	   = xc4000_get_bandwidth,
164162306a36Sopenharmony_ci	.get_status	   = xc4000_get_status
164262306a36Sopenharmony_ci};
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_cistruct dvb_frontend *xc4000_attach(struct dvb_frontend *fe,
164562306a36Sopenharmony_ci				   struct i2c_adapter *i2c,
164662306a36Sopenharmony_ci				   struct xc4000_config *cfg)
164762306a36Sopenharmony_ci{
164862306a36Sopenharmony_ci	struct xc4000_priv *priv = NULL;
164962306a36Sopenharmony_ci	int	instance;
165062306a36Sopenharmony_ci	u16	id = 0;
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci	dprintk(1, "%s(%d-%04x)\n", __func__,
165362306a36Sopenharmony_ci		i2c ? i2c_adapter_id(i2c) : -1,
165462306a36Sopenharmony_ci		cfg ? cfg->i2c_address : -1);
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	mutex_lock(&xc4000_list_mutex);
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci	instance = hybrid_tuner_request_state(struct xc4000_priv, priv,
165962306a36Sopenharmony_ci					      hybrid_tuner_instance_list,
166062306a36Sopenharmony_ci					      i2c, cfg->i2c_address, "xc4000");
166162306a36Sopenharmony_ci	switch (instance) {
166262306a36Sopenharmony_ci	case 0:
166362306a36Sopenharmony_ci		goto fail;
166462306a36Sopenharmony_ci	case 1:
166562306a36Sopenharmony_ci		/* new tuner instance */
166662306a36Sopenharmony_ci		priv->bandwidth = 6000000;
166762306a36Sopenharmony_ci		/* set default configuration */
166862306a36Sopenharmony_ci		priv->if_khz = 4560;
166962306a36Sopenharmony_ci		priv->default_pm = 0;
167062306a36Sopenharmony_ci		priv->dvb_amplitude = 134;
167162306a36Sopenharmony_ci		priv->set_smoothedcvbs = 1;
167262306a36Sopenharmony_ci		mutex_init(&priv->lock);
167362306a36Sopenharmony_ci		fe->tuner_priv = priv;
167462306a36Sopenharmony_ci		break;
167562306a36Sopenharmony_ci	default:
167662306a36Sopenharmony_ci		/* existing tuner instance */
167762306a36Sopenharmony_ci		fe->tuner_priv = priv;
167862306a36Sopenharmony_ci		break;
167962306a36Sopenharmony_ci	}
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	if (cfg->if_khz != 0) {
168262306a36Sopenharmony_ci		/* copy configuration if provided by the caller */
168362306a36Sopenharmony_ci		priv->if_khz = cfg->if_khz;
168462306a36Sopenharmony_ci		priv->default_pm = cfg->default_pm;
168562306a36Sopenharmony_ci		priv->dvb_amplitude = cfg->dvb_amplitude;
168662306a36Sopenharmony_ci		priv->set_smoothedcvbs = cfg->set_smoothedcvbs;
168762306a36Sopenharmony_ci	}
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	/* Check if firmware has been loaded. It is possible that another
169062306a36Sopenharmony_ci	   instance of the driver has loaded the firmware.
169162306a36Sopenharmony_ci	 */
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci	if (instance == 1) {
169462306a36Sopenharmony_ci		if (xc4000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
169562306a36Sopenharmony_ci			goto fail;
169662306a36Sopenharmony_ci	} else {
169762306a36Sopenharmony_ci		id = ((priv->cur_fw.type & BASE) != 0 ?
169862306a36Sopenharmony_ci		      priv->hwmodel : XC_PRODUCT_ID_FW_NOT_LOADED);
169962306a36Sopenharmony_ci	}
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	switch (id) {
170262306a36Sopenharmony_ci	case XC_PRODUCT_ID_XC4000:
170362306a36Sopenharmony_ci	case XC_PRODUCT_ID_XC4100:
170462306a36Sopenharmony_ci		printk(KERN_INFO
170562306a36Sopenharmony_ci			"xc4000: Successfully identified at address 0x%02x\n",
170662306a36Sopenharmony_ci			cfg->i2c_address);
170762306a36Sopenharmony_ci		printk(KERN_INFO
170862306a36Sopenharmony_ci			"xc4000: Firmware has been loaded previously\n");
170962306a36Sopenharmony_ci		break;
171062306a36Sopenharmony_ci	case XC_PRODUCT_ID_FW_NOT_LOADED:
171162306a36Sopenharmony_ci		printk(KERN_INFO
171262306a36Sopenharmony_ci			"xc4000: Successfully identified at address 0x%02x\n",
171362306a36Sopenharmony_ci			cfg->i2c_address);
171462306a36Sopenharmony_ci		printk(KERN_INFO
171562306a36Sopenharmony_ci			"xc4000: Firmware has not been loaded previously\n");
171662306a36Sopenharmony_ci		break;
171762306a36Sopenharmony_ci	default:
171862306a36Sopenharmony_ci		printk(KERN_ERR
171962306a36Sopenharmony_ci			"xc4000: Device not found at addr 0x%02x (0x%x)\n",
172062306a36Sopenharmony_ci			cfg->i2c_address, id);
172162306a36Sopenharmony_ci		goto fail;
172262306a36Sopenharmony_ci	}
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	mutex_unlock(&xc4000_list_mutex);
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	memcpy(&fe->ops.tuner_ops, &xc4000_tuner_ops,
172762306a36Sopenharmony_ci		sizeof(struct dvb_tuner_ops));
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	if (instance == 1) {
173062306a36Sopenharmony_ci		int	ret;
173162306a36Sopenharmony_ci		mutex_lock(&priv->lock);
173262306a36Sopenharmony_ci		ret = xc4000_fwupload(fe);
173362306a36Sopenharmony_ci		mutex_unlock(&priv->lock);
173462306a36Sopenharmony_ci		if (ret != 0)
173562306a36Sopenharmony_ci			goto fail2;
173662306a36Sopenharmony_ci	}
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci	return fe;
173962306a36Sopenharmony_cifail:
174062306a36Sopenharmony_ci	mutex_unlock(&xc4000_list_mutex);
174162306a36Sopenharmony_cifail2:
174262306a36Sopenharmony_ci	xc4000_release(fe);
174362306a36Sopenharmony_ci	return NULL;
174462306a36Sopenharmony_ci}
174562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xc4000_attach);
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ciMODULE_AUTHOR("Steven Toth, Davide Ferri");
174862306a36Sopenharmony_ciMODULE_DESCRIPTION("Xceive xc4000 silicon tuner driver");
174962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
175062306a36Sopenharmony_ciMODULE_FIRMWARE(XC4000_DEFAULT_FIRMWARE_NEW);
175162306a36Sopenharmony_ciMODULE_FIRMWARE(XC4000_DEFAULT_FIRMWARE);
1752