162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Driver for Xceive XC5000 "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 */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/moduleparam.h>
1262306a36Sopenharmony_ci#include <linux/videodev2.h>
1362306a36Sopenharmony_ci#include <linux/delay.h>
1462306a36Sopenharmony_ci#include <linux/workqueue.h>
1562306a36Sopenharmony_ci#include <linux/dvb/frontend.h>
1662306a36Sopenharmony_ci#include <linux/i2c.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <media/dvb_frontend.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include "xc5000.h"
2162306a36Sopenharmony_ci#include "tuner-i2c.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic int debug;
2462306a36Sopenharmony_cimodule_param(debug, int, 0644);
2562306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic int no_poweroff;
2862306a36Sopenharmony_cimodule_param(no_poweroff, int, 0644);
2962306a36Sopenharmony_ciMODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n"
3062306a36Sopenharmony_ci	"\t\t1 keep device energized and with tuner ready all the times.\n"
3162306a36Sopenharmony_ci	"\t\tFaster, but consumes more power and keeps the device hotter");
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic DEFINE_MUTEX(xc5000_list_mutex);
3462306a36Sopenharmony_cistatic LIST_HEAD(hybrid_tuner_instance_list);
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define dprintk(level, fmt, arg...) if (debug >= level) \
3762306a36Sopenharmony_ci	printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistruct xc5000_priv {
4062306a36Sopenharmony_ci	struct tuner_i2c_props i2c_props;
4162306a36Sopenharmony_ci	struct list_head hybrid_tuner_instance_list;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	u32 if_khz;
4462306a36Sopenharmony_ci	u16 xtal_khz;
4562306a36Sopenharmony_ci	u32 freq_hz, freq_offset;
4662306a36Sopenharmony_ci	u32 bandwidth;
4762306a36Sopenharmony_ci	u8  video_standard;
4862306a36Sopenharmony_ci	unsigned int mode;
4962306a36Sopenharmony_ci	u8  rf_mode;
5062306a36Sopenharmony_ci	u8  radio_input;
5162306a36Sopenharmony_ci	u16  output_amp;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	int chip_id;
5462306a36Sopenharmony_ci	u16 pll_register_no;
5562306a36Sopenharmony_ci	u8 init_status_supported;
5662306a36Sopenharmony_ci	u8 fw_checksum_supported;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	struct dvb_frontend *fe;
5962306a36Sopenharmony_ci	struct delayed_work timer_sleep;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	const struct firmware   *firmware;
6262306a36Sopenharmony_ci};
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/* Misc Defines */
6562306a36Sopenharmony_ci#define MAX_TV_STANDARD			24
6662306a36Sopenharmony_ci#define XC_MAX_I2C_WRITE_LENGTH		64
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/* Time to suspend after the .sleep callback is called */
6962306a36Sopenharmony_ci#define XC5000_SLEEP_TIME		5000 /* ms */
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/* Signal Types */
7262306a36Sopenharmony_ci#define XC_RF_MODE_AIR			0
7362306a36Sopenharmony_ci#define XC_RF_MODE_CABLE		1
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci/* Product id */
7662306a36Sopenharmony_ci#define XC_PRODUCT_ID_FW_NOT_LOADED	0x2000
7762306a36Sopenharmony_ci#define XC_PRODUCT_ID_FW_LOADED	0x1388
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/* Registers */
8062306a36Sopenharmony_ci#define XREG_INIT         0x00
8162306a36Sopenharmony_ci#define XREG_VIDEO_MODE   0x01
8262306a36Sopenharmony_ci#define XREG_AUDIO_MODE   0x02
8362306a36Sopenharmony_ci#define XREG_RF_FREQ      0x03
8462306a36Sopenharmony_ci#define XREG_D_CODE       0x04
8562306a36Sopenharmony_ci#define XREG_IF_OUT       0x05
8662306a36Sopenharmony_ci#define XREG_SEEK_MODE    0x07
8762306a36Sopenharmony_ci#define XREG_POWER_DOWN   0x0A /* Obsolete */
8862306a36Sopenharmony_ci/* Set the output amplitude - SIF for analog, DTVP/DTVN for digital */
8962306a36Sopenharmony_ci#define XREG_OUTPUT_AMP   0x0B
9062306a36Sopenharmony_ci#define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */
9162306a36Sopenharmony_ci#define XREG_SMOOTHEDCVBS 0x0E
9262306a36Sopenharmony_ci#define XREG_XTALFREQ     0x0F
9362306a36Sopenharmony_ci#define XREG_FINERFREQ    0x10
9462306a36Sopenharmony_ci#define XREG_DDIMODE      0x11
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci#define XREG_ADC_ENV      0x00
9762306a36Sopenharmony_ci#define XREG_QUALITY      0x01
9862306a36Sopenharmony_ci#define XREG_FRAME_LINES  0x02
9962306a36Sopenharmony_ci#define XREG_HSYNC_FREQ   0x03
10062306a36Sopenharmony_ci#define XREG_LOCK         0x04
10162306a36Sopenharmony_ci#define XREG_FREQ_ERROR   0x05
10262306a36Sopenharmony_ci#define XREG_SNR          0x06
10362306a36Sopenharmony_ci#define XREG_VERSION      0x07
10462306a36Sopenharmony_ci#define XREG_PRODUCT_ID   0x08
10562306a36Sopenharmony_ci#define XREG_BUSY         0x09
10662306a36Sopenharmony_ci#define XREG_BUILD        0x0D
10762306a36Sopenharmony_ci#define XREG_TOTALGAIN    0x0F
10862306a36Sopenharmony_ci#define XREG_FW_CHECKSUM  0x12
10962306a36Sopenharmony_ci#define XREG_INIT_STATUS  0x13
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci/*
11262306a36Sopenharmony_ci   Basic firmware description. This will remain with
11362306a36Sopenharmony_ci   the driver for documentation purposes.
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci   This represents an I2C firmware file encoded as a
11662306a36Sopenharmony_ci   string of unsigned char. Format is as follows:
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci   char[0  ]=len0_MSB  -> len = len_MSB * 256 + len_LSB
11962306a36Sopenharmony_ci   char[1  ]=len0_LSB  -> length of first write transaction
12062306a36Sopenharmony_ci   char[2  ]=data0 -> first byte to be sent
12162306a36Sopenharmony_ci   char[3  ]=data1
12262306a36Sopenharmony_ci   char[4  ]=data2
12362306a36Sopenharmony_ci   char[   ]=...
12462306a36Sopenharmony_ci   char[M  ]=dataN  -> last byte to be sent
12562306a36Sopenharmony_ci   char[M+1]=len1_MSB  -> len = len_MSB * 256 + len_LSB
12662306a36Sopenharmony_ci   char[M+2]=len1_LSB  -> length of second write transaction
12762306a36Sopenharmony_ci   char[M+3]=data0
12862306a36Sopenharmony_ci   char[M+4]=data1
12962306a36Sopenharmony_ci   ...
13062306a36Sopenharmony_ci   etc.
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci   The [len] value should be interpreted as follows:
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci   len= len_MSB _ len_LSB
13562306a36Sopenharmony_ci   len=1111_1111_1111_1111   : End of I2C_SEQUENCE
13662306a36Sopenharmony_ci   len=0000_0000_0000_0000   : Reset command: Do hardware reset
13762306a36Sopenharmony_ci   len=0NNN_NNNN_NNNN_NNNN   : Normal transaction: number of bytes = {1:32767)
13862306a36Sopenharmony_ci   len=1WWW_WWWW_WWWW_WWWW   : Wait command: wait for {1:32767} ms
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci   For the RESET and WAIT commands, the two following bytes will contain
14162306a36Sopenharmony_ci   immediately the length of the following transaction.
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci*/
14462306a36Sopenharmony_cistruct XC_TV_STANDARD {
14562306a36Sopenharmony_ci	char *name;
14662306a36Sopenharmony_ci	u16 audio_mode;
14762306a36Sopenharmony_ci	u16 video_mode;
14862306a36Sopenharmony_ci};
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/* Tuner standards */
15162306a36Sopenharmony_ci#define MN_NTSC_PAL_BTSC	0
15262306a36Sopenharmony_ci#define MN_NTSC_PAL_A2		1
15362306a36Sopenharmony_ci#define MN_NTSC_PAL_EIAJ	2
15462306a36Sopenharmony_ci#define MN_NTSC_PAL_MONO	3
15562306a36Sopenharmony_ci#define BG_PAL_A2		4
15662306a36Sopenharmony_ci#define BG_PAL_NICAM		5
15762306a36Sopenharmony_ci#define BG_PAL_MONO		6
15862306a36Sopenharmony_ci#define I_PAL_NICAM		7
15962306a36Sopenharmony_ci#define I_PAL_NICAM_MONO	8
16062306a36Sopenharmony_ci#define DK_PAL_A2		9
16162306a36Sopenharmony_ci#define DK_PAL_NICAM		10
16262306a36Sopenharmony_ci#define DK_PAL_MONO		11
16362306a36Sopenharmony_ci#define DK_SECAM_A2DK1		12
16462306a36Sopenharmony_ci#define DK_SECAM_A2LDK3		13
16562306a36Sopenharmony_ci#define DK_SECAM_A2MONO		14
16662306a36Sopenharmony_ci#define L_SECAM_NICAM		15
16762306a36Sopenharmony_ci#define LC_SECAM_NICAM		16
16862306a36Sopenharmony_ci#define DTV6			17
16962306a36Sopenharmony_ci#define DTV8			18
17062306a36Sopenharmony_ci#define DTV7_8			19
17162306a36Sopenharmony_ci#define DTV7			20
17262306a36Sopenharmony_ci#define FM_RADIO_INPUT2		21
17362306a36Sopenharmony_ci#define FM_RADIO_INPUT1		22
17462306a36Sopenharmony_ci#define FM_RADIO_INPUT1_MONO	23
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic struct XC_TV_STANDARD xc5000_standard[MAX_TV_STANDARD] = {
17762306a36Sopenharmony_ci	{"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020},
17862306a36Sopenharmony_ci	{"M/N-NTSC/PAL-A2",   0x0600, 0x8020},
17962306a36Sopenharmony_ci	{"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020},
18062306a36Sopenharmony_ci	{"M/N-NTSC/PAL-Mono", 0x0478, 0x8020},
18162306a36Sopenharmony_ci	{"B/G-PAL-A2",        0x0A00, 0x8049},
18262306a36Sopenharmony_ci	{"B/G-PAL-NICAM",     0x0C04, 0x8049},
18362306a36Sopenharmony_ci	{"B/G-PAL-MONO",      0x0878, 0x8059},
18462306a36Sopenharmony_ci	{"I-PAL-NICAM",       0x1080, 0x8009},
18562306a36Sopenharmony_ci	{"I-PAL-NICAM-MONO",  0x0E78, 0x8009},
18662306a36Sopenharmony_ci	{"D/K-PAL-A2",        0x1600, 0x8009},
18762306a36Sopenharmony_ci	{"D/K-PAL-NICAM",     0x0E80, 0x8009},
18862306a36Sopenharmony_ci	{"D/K-PAL-MONO",      0x1478, 0x8009},
18962306a36Sopenharmony_ci	{"D/K-SECAM-A2 DK1",  0x1200, 0x8009},
19062306a36Sopenharmony_ci	{"D/K-SECAM-A2 L/DK3", 0x0E00, 0x8009},
19162306a36Sopenharmony_ci	{"D/K-SECAM-A2 MONO", 0x1478, 0x8009},
19262306a36Sopenharmony_ci	{"L-SECAM-NICAM",     0x8E82, 0x0009},
19362306a36Sopenharmony_ci	{"L'-SECAM-NICAM",    0x8E82, 0x4009},
19462306a36Sopenharmony_ci	{"DTV6",              0x00C0, 0x8002},
19562306a36Sopenharmony_ci	{"DTV8",              0x00C0, 0x800B},
19662306a36Sopenharmony_ci	{"DTV7/8",            0x00C0, 0x801B},
19762306a36Sopenharmony_ci	{"DTV7",              0x00C0, 0x8007},
19862306a36Sopenharmony_ci	{"FM Radio-INPUT2",   0x9802, 0x9002},
19962306a36Sopenharmony_ci	{"FM Radio-INPUT1",   0x0208, 0x9002},
20062306a36Sopenharmony_ci	{"FM Radio-INPUT1_MONO", 0x0278, 0x9002}
20162306a36Sopenharmony_ci};
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistruct xc5000_fw_cfg {
20562306a36Sopenharmony_ci	char *name;
20662306a36Sopenharmony_ci	u16 size;
20762306a36Sopenharmony_ci	u16 pll_reg;
20862306a36Sopenharmony_ci	u8 init_status_supported;
20962306a36Sopenharmony_ci	u8 fw_checksum_supported;
21062306a36Sopenharmony_ci};
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci#define XC5000A_FIRMWARE "dvb-fe-xc5000-1.6.114.fw"
21362306a36Sopenharmony_cistatic const struct xc5000_fw_cfg xc5000a_1_6_114 = {
21462306a36Sopenharmony_ci	.name = XC5000A_FIRMWARE,
21562306a36Sopenharmony_ci	.size = 12401,
21662306a36Sopenharmony_ci	.pll_reg = 0x806c,
21762306a36Sopenharmony_ci};
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci#define XC5000C_FIRMWARE "dvb-fe-xc5000c-4.1.30.7.fw"
22062306a36Sopenharmony_cistatic const struct xc5000_fw_cfg xc5000c_41_024_5 = {
22162306a36Sopenharmony_ci	.name = XC5000C_FIRMWARE,
22262306a36Sopenharmony_ci	.size = 16497,
22362306a36Sopenharmony_ci	.pll_reg = 0x13,
22462306a36Sopenharmony_ci	.init_status_supported = 1,
22562306a36Sopenharmony_ci	.fw_checksum_supported = 1,
22662306a36Sopenharmony_ci};
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic inline const struct xc5000_fw_cfg *xc5000_assign_firmware(int chip_id)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	switch (chip_id) {
23162306a36Sopenharmony_ci	default:
23262306a36Sopenharmony_ci	case XC5000A:
23362306a36Sopenharmony_ci		return &xc5000a_1_6_114;
23462306a36Sopenharmony_ci	case XC5000C:
23562306a36Sopenharmony_ci		return &xc5000c_41_024_5;
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force);
24062306a36Sopenharmony_cistatic int xc5000_is_firmware_loaded(struct dvb_frontend *fe);
24162306a36Sopenharmony_cistatic int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val);
24262306a36Sopenharmony_cistatic int xc5000_tuner_reset(struct dvb_frontend *fe);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	struct i2c_msg msg = { .addr = priv->i2c_props.addr,
24762306a36Sopenharmony_ci			       .flags = 0, .buf = buf, .len = len };
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
25062306a36Sopenharmony_ci		printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", len);
25162306a36Sopenharmony_ci		return -EREMOTEIO;
25262306a36Sopenharmony_ci	}
25362306a36Sopenharmony_ci	return 0;
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci#if 0
25762306a36Sopenharmony_ci/* This routine is never used because the only time we read data from the
25862306a36Sopenharmony_ci   i2c bus is when we read registers, and we want that to be an atomic i2c
25962306a36Sopenharmony_ci   transaction in case we are on a multi-master bus */
26062306a36Sopenharmony_cistatic int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	struct i2c_msg msg = { .addr = priv->i2c_props.addr,
26362306a36Sopenharmony_ci		.flags = I2C_M_RD, .buf = buf, .len = len };
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
26662306a36Sopenharmony_ci		printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", len);
26762306a36Sopenharmony_ci		return -EREMOTEIO;
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci	return 0;
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci#endif
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_cistatic int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	u8 buf[2] = { reg >> 8, reg & 0xff };
27662306a36Sopenharmony_ci	u8 bval[2] = { 0, 0 };
27762306a36Sopenharmony_ci	struct i2c_msg msg[2] = {
27862306a36Sopenharmony_ci		{ .addr = priv->i2c_props.addr,
27962306a36Sopenharmony_ci			.flags = 0, .buf = &buf[0], .len = 2 },
28062306a36Sopenharmony_ci		{ .addr = priv->i2c_props.addr,
28162306a36Sopenharmony_ci			.flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
28262306a36Sopenharmony_ci	};
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
28562306a36Sopenharmony_ci		printk(KERN_WARNING "xc5000: I2C read failed\n");
28662306a36Sopenharmony_ci		return -EREMOTEIO;
28762306a36Sopenharmony_ci	}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	*val = (bval[0] << 8) | bval[1];
29062306a36Sopenharmony_ci	return 0;
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic int xc5000_tuner_reset(struct dvb_frontend *fe)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
29662306a36Sopenharmony_ci	int ret;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	if (fe->callback) {
30162306a36Sopenharmony_ci		ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ?
30262306a36Sopenharmony_ci					   fe->dvb->priv :
30362306a36Sopenharmony_ci					   priv->i2c_props.adap->algo_data,
30462306a36Sopenharmony_ci					   DVB_FRONTEND_COMPONENT_TUNER,
30562306a36Sopenharmony_ci					   XC5000_TUNER_RESET, 0);
30662306a36Sopenharmony_ci		if (ret) {
30762306a36Sopenharmony_ci			printk(KERN_ERR "xc5000: reset failed\n");
30862306a36Sopenharmony_ci			return ret;
30962306a36Sopenharmony_ci		}
31062306a36Sopenharmony_ci	} else {
31162306a36Sopenharmony_ci		printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n");
31262306a36Sopenharmony_ci		return -EINVAL;
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci	return 0;
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic int xc_write_reg(struct xc5000_priv *priv, u16 reg_addr, u16 i2c_data)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	u8 buf[4];
32062306a36Sopenharmony_ci	int watch_dog_timer = 100;
32162306a36Sopenharmony_ci	int result;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	buf[0] = (reg_addr >> 8) & 0xFF;
32462306a36Sopenharmony_ci	buf[1] = reg_addr & 0xFF;
32562306a36Sopenharmony_ci	buf[2] = (i2c_data >> 8) & 0xFF;
32662306a36Sopenharmony_ci	buf[3] = i2c_data & 0xFF;
32762306a36Sopenharmony_ci	result = xc_send_i2c_data(priv, buf, 4);
32862306a36Sopenharmony_ci	if (result == 0) {
32962306a36Sopenharmony_ci		/* wait for busy flag to clear */
33062306a36Sopenharmony_ci		while ((watch_dog_timer > 0) && (result == 0)) {
33162306a36Sopenharmony_ci			result = xc5000_readreg(priv, XREG_BUSY, (u16 *)buf);
33262306a36Sopenharmony_ci			if (result == 0) {
33362306a36Sopenharmony_ci				if ((buf[0] == 0) && (buf[1] == 0)) {
33462306a36Sopenharmony_ci					/* busy flag cleared */
33562306a36Sopenharmony_ci					break;
33662306a36Sopenharmony_ci				} else {
33762306a36Sopenharmony_ci					msleep(5); /* wait 5 ms */
33862306a36Sopenharmony_ci					watch_dog_timer--;
33962306a36Sopenharmony_ci				}
34062306a36Sopenharmony_ci			}
34162306a36Sopenharmony_ci		}
34262306a36Sopenharmony_ci	}
34362306a36Sopenharmony_ci	if (watch_dog_timer <= 0)
34462306a36Sopenharmony_ci		result = -EREMOTEIO;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	return result;
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_cistatic int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
35062306a36Sopenharmony_ci{
35162306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	int i, nbytes_to_send, result;
35462306a36Sopenharmony_ci	unsigned int len, pos, index;
35562306a36Sopenharmony_ci	u8 buf[XC_MAX_I2C_WRITE_LENGTH];
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	index = 0;
35862306a36Sopenharmony_ci	while ((i2c_sequence[index] != 0xFF) ||
35962306a36Sopenharmony_ci		(i2c_sequence[index + 1] != 0xFF)) {
36062306a36Sopenharmony_ci		len = i2c_sequence[index] * 256 + i2c_sequence[index+1];
36162306a36Sopenharmony_ci		if (len == 0x0000) {
36262306a36Sopenharmony_ci			/* RESET command */
36362306a36Sopenharmony_ci			result = xc5000_tuner_reset(fe);
36462306a36Sopenharmony_ci			index += 2;
36562306a36Sopenharmony_ci			if (result != 0)
36662306a36Sopenharmony_ci				return result;
36762306a36Sopenharmony_ci		} else if (len & 0x8000) {
36862306a36Sopenharmony_ci			/* WAIT command */
36962306a36Sopenharmony_ci			msleep(len & 0x7FFF);
37062306a36Sopenharmony_ci			index += 2;
37162306a36Sopenharmony_ci		} else {
37262306a36Sopenharmony_ci			/* Send i2c data whilst ensuring individual transactions
37362306a36Sopenharmony_ci			 * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes.
37462306a36Sopenharmony_ci			 */
37562306a36Sopenharmony_ci			index += 2;
37662306a36Sopenharmony_ci			buf[0] = i2c_sequence[index];
37762306a36Sopenharmony_ci			buf[1] = i2c_sequence[index + 1];
37862306a36Sopenharmony_ci			pos = 2;
37962306a36Sopenharmony_ci			while (pos < len) {
38062306a36Sopenharmony_ci				if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2)
38162306a36Sopenharmony_ci					nbytes_to_send =
38262306a36Sopenharmony_ci						XC_MAX_I2C_WRITE_LENGTH;
38362306a36Sopenharmony_ci				else
38462306a36Sopenharmony_ci					nbytes_to_send = (len - pos + 2);
38562306a36Sopenharmony_ci				for (i = 2; i < nbytes_to_send; i++) {
38662306a36Sopenharmony_ci					buf[i] = i2c_sequence[index + pos +
38762306a36Sopenharmony_ci						i - 2];
38862306a36Sopenharmony_ci				}
38962306a36Sopenharmony_ci				result = xc_send_i2c_data(priv, buf,
39062306a36Sopenharmony_ci					nbytes_to_send);
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci				if (result != 0)
39362306a36Sopenharmony_ci					return result;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci				pos += nbytes_to_send - 2;
39662306a36Sopenharmony_ci			}
39762306a36Sopenharmony_ci			index += len;
39862306a36Sopenharmony_ci		}
39962306a36Sopenharmony_ci	}
40062306a36Sopenharmony_ci	return 0;
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_cistatic int xc_initialize(struct xc5000_priv *priv)
40462306a36Sopenharmony_ci{
40562306a36Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
40662306a36Sopenharmony_ci	return xc_write_reg(priv, XREG_INIT, 0);
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_cistatic int xc_set_tv_standard(struct xc5000_priv *priv,
41062306a36Sopenharmony_ci	u16 video_mode, u16 audio_mode, u8 radio_mode)
41162306a36Sopenharmony_ci{
41262306a36Sopenharmony_ci	int ret;
41362306a36Sopenharmony_ci	dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, video_mode, audio_mode);
41462306a36Sopenharmony_ci	if (radio_mode) {
41562306a36Sopenharmony_ci		dprintk(1, "%s() Standard = %s\n",
41662306a36Sopenharmony_ci			__func__,
41762306a36Sopenharmony_ci			xc5000_standard[radio_mode].name);
41862306a36Sopenharmony_ci	} else {
41962306a36Sopenharmony_ci		dprintk(1, "%s() Standard = %s\n",
42062306a36Sopenharmony_ci			__func__,
42162306a36Sopenharmony_ci			xc5000_standard[priv->video_standard].name);
42262306a36Sopenharmony_ci	}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	ret = xc_write_reg(priv, XREG_VIDEO_MODE, video_mode);
42562306a36Sopenharmony_ci	if (ret == 0)
42662306a36Sopenharmony_ci		ret = xc_write_reg(priv, XREG_AUDIO_MODE, audio_mode);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	return ret;
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_cistatic int xc_set_signal_source(struct xc5000_priv *priv, u16 rf_mode)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
43462306a36Sopenharmony_ci		rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) {
43762306a36Sopenharmony_ci		rf_mode = XC_RF_MODE_CABLE;
43862306a36Sopenharmony_ci		printk(KERN_ERR
43962306a36Sopenharmony_ci			"%s(), Invalid mode, defaulting to CABLE",
44062306a36Sopenharmony_ci			__func__);
44162306a36Sopenharmony_ci	}
44262306a36Sopenharmony_ci	return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode);
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic const struct dvb_tuner_ops xc5000_tuner_ops;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_cistatic int xc_set_rf_frequency(struct xc5000_priv *priv, u32 freq_hz)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	u16 freq_code;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	dprintk(1, "%s(%u)\n", __func__, freq_hz);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	if ((freq_hz > xc5000_tuner_ops.info.frequency_max_hz) ||
45462306a36Sopenharmony_ci		(freq_hz < xc5000_tuner_ops.info.frequency_min_hz))
45562306a36Sopenharmony_ci		return -EINVAL;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	freq_code = (u16)(freq_hz / 15625);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	/* Starting in firmware version 1.1.44, Xceive recommends using the
46062306a36Sopenharmony_ci	   FINERFREQ for all normal tuning (the doc indicates reg 0x03 should
46162306a36Sopenharmony_ci	   only be used for fast scanning for channel lock) */
46262306a36Sopenharmony_ci	return xc_write_reg(priv, XREG_FINERFREQ, freq_code);
46362306a36Sopenharmony_ci}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	u32 freq_code = (freq_khz * 1024)/1000;
46962306a36Sopenharmony_ci	dprintk(1, "%s(freq_khz = %d) freq_code = 0x%x\n",
47062306a36Sopenharmony_ci		__func__, freq_khz, freq_code);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	return xc_write_reg(priv, XREG_IF_OUT, freq_code);
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_cistatic int xc_get_adc_envelope(struct xc5000_priv *priv, u16 *adc_envelope)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	return xc5000_readreg(priv, XREG_ADC_ENV, adc_envelope);
47962306a36Sopenharmony_ci}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_cistatic int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	int result;
48462306a36Sopenharmony_ci	u16 reg_data;
48562306a36Sopenharmony_ci	u32 tmp;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	result = xc5000_readreg(priv, XREG_FREQ_ERROR, &reg_data);
48862306a36Sopenharmony_ci	if (result != 0)
48962306a36Sopenharmony_ci		return result;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	tmp = (u32)reg_data;
49262306a36Sopenharmony_ci	(*freq_error_hz) = (tmp * 15625) / 1000;
49362306a36Sopenharmony_ci	return result;
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cistatic int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	return xc5000_readreg(priv, XREG_LOCK, lock_status);
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cistatic int xc_get_version(struct xc5000_priv *priv,
50262306a36Sopenharmony_ci	u8 *hw_majorversion, u8 *hw_minorversion,
50362306a36Sopenharmony_ci	u8 *fw_majorversion, u8 *fw_minorversion)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	u16 data;
50662306a36Sopenharmony_ci	int result;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	result = xc5000_readreg(priv, XREG_VERSION, &data);
50962306a36Sopenharmony_ci	if (result != 0)
51062306a36Sopenharmony_ci		return result;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	(*hw_majorversion) = (data >> 12) & 0x0F;
51362306a36Sopenharmony_ci	(*hw_minorversion) = (data >>  8) & 0x0F;
51462306a36Sopenharmony_ci	(*fw_majorversion) = (data >>  4) & 0x0F;
51562306a36Sopenharmony_ci	(*fw_minorversion) = data & 0x0F;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	return 0;
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_cistatic int xc_get_buildversion(struct xc5000_priv *priv, u16 *buildrev)
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	return xc5000_readreg(priv, XREG_BUILD, buildrev);
52362306a36Sopenharmony_ci}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_cistatic int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz)
52662306a36Sopenharmony_ci{
52762306a36Sopenharmony_ci	u16 reg_data;
52862306a36Sopenharmony_ci	int result;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	result = xc5000_readreg(priv, XREG_HSYNC_FREQ, &reg_data);
53162306a36Sopenharmony_ci	if (result != 0)
53262306a36Sopenharmony_ci		return result;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	(*hsync_freq_hz) = ((reg_data & 0x0fff) * 763)/100;
53562306a36Sopenharmony_ci	return result;
53662306a36Sopenharmony_ci}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_cistatic int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines)
53962306a36Sopenharmony_ci{
54062306a36Sopenharmony_ci	return xc5000_readreg(priv, XREG_FRAME_LINES, frame_lines);
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic int xc_get_quality(struct xc5000_priv *priv, u16 *quality)
54462306a36Sopenharmony_ci{
54562306a36Sopenharmony_ci	return xc5000_readreg(priv, XREG_QUALITY, quality);
54662306a36Sopenharmony_ci}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_cistatic int xc_get_analogsnr(struct xc5000_priv *priv, u16 *snr)
54962306a36Sopenharmony_ci{
55062306a36Sopenharmony_ci	return xc5000_readreg(priv, XREG_SNR, snr);
55162306a36Sopenharmony_ci}
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_cistatic int xc_get_totalgain(struct xc5000_priv *priv, u16 *totalgain)
55462306a36Sopenharmony_ci{
55562306a36Sopenharmony_ci	return xc5000_readreg(priv, XREG_TOTALGAIN, totalgain);
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci#define XC_TUNE_ANALOG  0
55962306a36Sopenharmony_ci#define XC_TUNE_DIGITAL 1
56062306a36Sopenharmony_cistatic int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode)
56162306a36Sopenharmony_ci{
56262306a36Sopenharmony_ci	dprintk(1, "%s(%u)\n", __func__, freq_hz);
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	if (xc_set_rf_frequency(priv, freq_hz) != 0)
56562306a36Sopenharmony_ci		return -EREMOTEIO;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	return 0;
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_cistatic int xc_set_xtal(struct dvb_frontend *fe)
57162306a36Sopenharmony_ci{
57262306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
57362306a36Sopenharmony_ci	int ret = 0;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	switch (priv->chip_id) {
57662306a36Sopenharmony_ci	default:
57762306a36Sopenharmony_ci	case XC5000A:
57862306a36Sopenharmony_ci		/* 32.000 MHz xtal is default */
57962306a36Sopenharmony_ci		break;
58062306a36Sopenharmony_ci	case XC5000C:
58162306a36Sopenharmony_ci		switch (priv->xtal_khz) {
58262306a36Sopenharmony_ci		default:
58362306a36Sopenharmony_ci		case 32000:
58462306a36Sopenharmony_ci			/* 32.000 MHz xtal is default */
58562306a36Sopenharmony_ci			break;
58662306a36Sopenharmony_ci		case 31875:
58762306a36Sopenharmony_ci			/* 31.875 MHz xtal configuration */
58862306a36Sopenharmony_ci			ret = xc_write_reg(priv, 0x000f, 0x8081);
58962306a36Sopenharmony_ci			break;
59062306a36Sopenharmony_ci		}
59162306a36Sopenharmony_ci		break;
59262306a36Sopenharmony_ci	}
59362306a36Sopenharmony_ci	return ret;
59462306a36Sopenharmony_ci}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_cistatic int xc5000_fwupload(struct dvb_frontend *fe,
59762306a36Sopenharmony_ci			   const struct xc5000_fw_cfg *desired_fw,
59862306a36Sopenharmony_ci			   const struct firmware *fw)
59962306a36Sopenharmony_ci{
60062306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
60162306a36Sopenharmony_ci	int ret;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	/* request the firmware, this will block and timeout */
60462306a36Sopenharmony_ci	dprintk(1, "waiting for firmware upload (%s)...\n",
60562306a36Sopenharmony_ci		desired_fw->name);
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	priv->pll_register_no = desired_fw->pll_reg;
60862306a36Sopenharmony_ci	priv->init_status_supported = desired_fw->init_status_supported;
60962306a36Sopenharmony_ci	priv->fw_checksum_supported = desired_fw->fw_checksum_supported;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	dprintk(1, "firmware uploading...\n");
61362306a36Sopenharmony_ci	ret = xc_load_i2c_sequence(fe,  fw->data);
61462306a36Sopenharmony_ci	if (!ret) {
61562306a36Sopenharmony_ci		ret = xc_set_xtal(fe);
61662306a36Sopenharmony_ci		dprintk(1, "Firmware upload complete...\n");
61762306a36Sopenharmony_ci	} else
61862306a36Sopenharmony_ci		printk(KERN_ERR "xc5000: firmware upload failed...\n");
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	return ret;
62162306a36Sopenharmony_ci}
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_cistatic void xc_debug_dump(struct xc5000_priv *priv)
62462306a36Sopenharmony_ci{
62562306a36Sopenharmony_ci	u16 adc_envelope;
62662306a36Sopenharmony_ci	u32 freq_error_hz = 0;
62762306a36Sopenharmony_ci	u16 lock_status;
62862306a36Sopenharmony_ci	u32 hsync_freq_hz = 0;
62962306a36Sopenharmony_ci	u16 frame_lines;
63062306a36Sopenharmony_ci	u16 quality;
63162306a36Sopenharmony_ci	u16 snr;
63262306a36Sopenharmony_ci	u16 totalgain;
63362306a36Sopenharmony_ci	u8 hw_majorversion = 0, hw_minorversion = 0;
63462306a36Sopenharmony_ci	u8 fw_majorversion = 0, fw_minorversion = 0;
63562306a36Sopenharmony_ci	u16 fw_buildversion = 0;
63662306a36Sopenharmony_ci	u16 regval;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	/* Wait for stats to stabilize.
63962306a36Sopenharmony_ci	 * Frame Lines needs two frame times after initial lock
64062306a36Sopenharmony_ci	 * before it is valid.
64162306a36Sopenharmony_ci	 */
64262306a36Sopenharmony_ci	msleep(100);
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	xc_get_adc_envelope(priv,  &adc_envelope);
64562306a36Sopenharmony_ci	dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope);
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	xc_get_frequency_error(priv, &freq_error_hz);
64862306a36Sopenharmony_ci	dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz);
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	xc_get_lock_status(priv,  &lock_status);
65162306a36Sopenharmony_ci	dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n",
65262306a36Sopenharmony_ci		lock_status);
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	xc_get_version(priv,  &hw_majorversion, &hw_minorversion,
65562306a36Sopenharmony_ci		&fw_majorversion, &fw_minorversion);
65662306a36Sopenharmony_ci	xc_get_buildversion(priv,  &fw_buildversion);
65762306a36Sopenharmony_ci	dprintk(1, "*** HW: V%d.%d, FW: V %d.%d.%d\n",
65862306a36Sopenharmony_ci		hw_majorversion, hw_minorversion,
65962306a36Sopenharmony_ci		fw_majorversion, fw_minorversion, fw_buildversion);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	xc_get_hsync_freq(priv,  &hsync_freq_hz);
66262306a36Sopenharmony_ci	dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	xc_get_frame_lines(priv,  &frame_lines);
66562306a36Sopenharmony_ci	dprintk(1, "*** Frame lines = %d\n", frame_lines);
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	xc_get_quality(priv,  &quality);
66862306a36Sopenharmony_ci	dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality & 0x07);
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	xc_get_analogsnr(priv,  &snr);
67162306a36Sopenharmony_ci	dprintk(1, "*** Unweighted analog SNR = %d dB\n", snr & 0x3f);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	xc_get_totalgain(priv,  &totalgain);
67462306a36Sopenharmony_ci	dprintk(1, "*** Total gain = %d.%d dB\n", totalgain / 256,
67562306a36Sopenharmony_ci		(totalgain % 256) * 100 / 256);
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	if (priv->pll_register_no) {
67862306a36Sopenharmony_ci		if (!xc5000_readreg(priv, priv->pll_register_no, &regval))
67962306a36Sopenharmony_ci			dprintk(1, "*** PLL lock status = 0x%04x\n", regval);
68062306a36Sopenharmony_ci	}
68162306a36Sopenharmony_ci}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_cistatic int xc5000_tune_digital(struct dvb_frontend *fe)
68462306a36Sopenharmony_ci{
68562306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
68662306a36Sopenharmony_ci	int ret;
68762306a36Sopenharmony_ci	u32 bw = fe->dtv_property_cache.bandwidth_hz;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	ret = xc_set_signal_source(priv, priv->rf_mode);
69062306a36Sopenharmony_ci	if (ret != 0) {
69162306a36Sopenharmony_ci		printk(KERN_ERR
69262306a36Sopenharmony_ci			"xc5000: xc_set_signal_source(%d) failed\n",
69362306a36Sopenharmony_ci			priv->rf_mode);
69462306a36Sopenharmony_ci		return -EREMOTEIO;
69562306a36Sopenharmony_ci	}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	ret = xc_set_tv_standard(priv,
69862306a36Sopenharmony_ci		xc5000_standard[priv->video_standard].video_mode,
69962306a36Sopenharmony_ci		xc5000_standard[priv->video_standard].audio_mode, 0);
70062306a36Sopenharmony_ci	if (ret != 0) {
70162306a36Sopenharmony_ci		printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n");
70262306a36Sopenharmony_ci		return -EREMOTEIO;
70362306a36Sopenharmony_ci	}
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	ret = xc_set_IF_frequency(priv, priv->if_khz);
70662306a36Sopenharmony_ci	if (ret != 0) {
70762306a36Sopenharmony_ci		printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
70862306a36Sopenharmony_ci		       priv->if_khz);
70962306a36Sopenharmony_ci		return -EIO;
71062306a36Sopenharmony_ci	}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	dprintk(1, "%s() setting OUTPUT_AMP to 0x%x\n",
71362306a36Sopenharmony_ci		__func__, priv->output_amp);
71462306a36Sopenharmony_ci	xc_write_reg(priv, XREG_OUTPUT_AMP, priv->output_amp);
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL);
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	if (debug)
71962306a36Sopenharmony_ci		xc_debug_dump(priv);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	priv->bandwidth = bw;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	return 0;
72462306a36Sopenharmony_ci}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_cistatic int xc5000_set_digital_params(struct dvb_frontend *fe)
72762306a36Sopenharmony_ci{
72862306a36Sopenharmony_ci	int b;
72962306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
73062306a36Sopenharmony_ci	u32 bw = fe->dtv_property_cache.bandwidth_hz;
73162306a36Sopenharmony_ci	u32 freq = fe->dtv_property_cache.frequency;
73262306a36Sopenharmony_ci	u32 delsys  = fe->dtv_property_cache.delivery_system;
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	if (xc_load_fw_and_init_tuner(fe, 0) != 0) {
73562306a36Sopenharmony_ci		dprintk(1, "Unable to load firmware and init tuner\n");
73662306a36Sopenharmony_ci		return -EINVAL;
73762306a36Sopenharmony_ci	}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	dprintk(1, "%s() frequency=%d (Hz)\n", __func__, freq);
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	switch (delsys) {
74262306a36Sopenharmony_ci	case SYS_ATSC:
74362306a36Sopenharmony_ci		dprintk(1, "%s() VSB modulation\n", __func__);
74462306a36Sopenharmony_ci		priv->rf_mode = XC_RF_MODE_AIR;
74562306a36Sopenharmony_ci		priv->freq_offset = 1750000;
74662306a36Sopenharmony_ci		priv->video_standard = DTV6;
74762306a36Sopenharmony_ci		break;
74862306a36Sopenharmony_ci	case SYS_DVBC_ANNEX_B:
74962306a36Sopenharmony_ci		dprintk(1, "%s() QAM modulation\n", __func__);
75062306a36Sopenharmony_ci		priv->rf_mode = XC_RF_MODE_CABLE;
75162306a36Sopenharmony_ci		priv->freq_offset = 1750000;
75262306a36Sopenharmony_ci		priv->video_standard = DTV6;
75362306a36Sopenharmony_ci		break;
75462306a36Sopenharmony_ci	case SYS_ISDBT:
75562306a36Sopenharmony_ci		/* All ISDB-T are currently for 6 MHz bw */
75662306a36Sopenharmony_ci		if (!bw)
75762306a36Sopenharmony_ci			bw = 6000000;
75862306a36Sopenharmony_ci		/* fall to OFDM handling */
75962306a36Sopenharmony_ci		fallthrough;
76062306a36Sopenharmony_ci	case SYS_DMBTH:
76162306a36Sopenharmony_ci	case SYS_DVBT:
76262306a36Sopenharmony_ci	case SYS_DVBT2:
76362306a36Sopenharmony_ci		dprintk(1, "%s() OFDM\n", __func__);
76462306a36Sopenharmony_ci		switch (bw) {
76562306a36Sopenharmony_ci		case 6000000:
76662306a36Sopenharmony_ci			priv->video_standard = DTV6;
76762306a36Sopenharmony_ci			priv->freq_offset = 1750000;
76862306a36Sopenharmony_ci			break;
76962306a36Sopenharmony_ci		case 7000000:
77062306a36Sopenharmony_ci			priv->video_standard = DTV7;
77162306a36Sopenharmony_ci			priv->freq_offset = 2250000;
77262306a36Sopenharmony_ci			break;
77362306a36Sopenharmony_ci		case 8000000:
77462306a36Sopenharmony_ci			priv->video_standard = DTV8;
77562306a36Sopenharmony_ci			priv->freq_offset = 2750000;
77662306a36Sopenharmony_ci			break;
77762306a36Sopenharmony_ci		default:
77862306a36Sopenharmony_ci			printk(KERN_ERR "xc5000 bandwidth not set!\n");
77962306a36Sopenharmony_ci			return -EINVAL;
78062306a36Sopenharmony_ci		}
78162306a36Sopenharmony_ci		priv->rf_mode = XC_RF_MODE_AIR;
78262306a36Sopenharmony_ci		break;
78362306a36Sopenharmony_ci	case SYS_DVBC_ANNEX_A:
78462306a36Sopenharmony_ci	case SYS_DVBC_ANNEX_C:
78562306a36Sopenharmony_ci		dprintk(1, "%s() QAM modulation\n", __func__);
78662306a36Sopenharmony_ci		priv->rf_mode = XC_RF_MODE_CABLE;
78762306a36Sopenharmony_ci		if (bw <= 6000000) {
78862306a36Sopenharmony_ci			priv->video_standard = DTV6;
78962306a36Sopenharmony_ci			priv->freq_offset = 1750000;
79062306a36Sopenharmony_ci			b = 6;
79162306a36Sopenharmony_ci		} else if (bw <= 7000000) {
79262306a36Sopenharmony_ci			priv->video_standard = DTV7;
79362306a36Sopenharmony_ci			priv->freq_offset = 2250000;
79462306a36Sopenharmony_ci			b = 7;
79562306a36Sopenharmony_ci		} else {
79662306a36Sopenharmony_ci			priv->video_standard = DTV7_8;
79762306a36Sopenharmony_ci			priv->freq_offset = 2750000;
79862306a36Sopenharmony_ci			b = 8;
79962306a36Sopenharmony_ci		}
80062306a36Sopenharmony_ci		dprintk(1, "%s() Bandwidth %dMHz (%d)\n", __func__,
80162306a36Sopenharmony_ci			b, bw);
80262306a36Sopenharmony_ci		break;
80362306a36Sopenharmony_ci	default:
80462306a36Sopenharmony_ci		printk(KERN_ERR "xc5000: delivery system is not supported!\n");
80562306a36Sopenharmony_ci		return -EINVAL;
80662306a36Sopenharmony_ci	}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	priv->freq_hz = freq - priv->freq_offset;
80962306a36Sopenharmony_ci	priv->mode = V4L2_TUNER_DIGITAL_TV;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	dprintk(1, "%s() frequency=%d (compensated to %d)\n",
81262306a36Sopenharmony_ci		__func__, freq, priv->freq_hz);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	return xc5000_tune_digital(fe);
81562306a36Sopenharmony_ci}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_cistatic int xc5000_is_firmware_loaded(struct dvb_frontend *fe)
81862306a36Sopenharmony_ci{
81962306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
82062306a36Sopenharmony_ci	int ret;
82162306a36Sopenharmony_ci	u16 id;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	ret = xc5000_readreg(priv, XREG_PRODUCT_ID, &id);
82462306a36Sopenharmony_ci	if (!ret) {
82562306a36Sopenharmony_ci		if (id == XC_PRODUCT_ID_FW_NOT_LOADED)
82662306a36Sopenharmony_ci			ret = -ENOENT;
82762306a36Sopenharmony_ci		else
82862306a36Sopenharmony_ci			ret = 0;
82962306a36Sopenharmony_ci		dprintk(1, "%s() returns id = 0x%x\n", __func__, id);
83062306a36Sopenharmony_ci	} else {
83162306a36Sopenharmony_ci		dprintk(1, "%s() returns error %d\n", __func__, ret);
83262306a36Sopenharmony_ci	}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	return ret;
83562306a36Sopenharmony_ci}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_cistatic void xc5000_config_tv(struct dvb_frontend *fe,
83862306a36Sopenharmony_ci			     struct analog_parameters *params)
83962306a36Sopenharmony_ci{
84062306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci	dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
84362306a36Sopenharmony_ci		__func__, params->frequency);
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	/* Fix me: it could be air. */
84662306a36Sopenharmony_ci	priv->rf_mode = params->mode;
84762306a36Sopenharmony_ci	if (params->mode > XC_RF_MODE_CABLE)
84862306a36Sopenharmony_ci		priv->rf_mode = XC_RF_MODE_CABLE;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	/* params->frequency is in units of 62.5khz */
85162306a36Sopenharmony_ci	priv->freq_hz = params->frequency * 62500;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	/* FIX ME: Some video standards may have several possible audio
85462306a36Sopenharmony_ci		   standards. We simply default to one of them here.
85562306a36Sopenharmony_ci	 */
85662306a36Sopenharmony_ci	if (params->std & V4L2_STD_MN) {
85762306a36Sopenharmony_ci		/* default to BTSC audio standard */
85862306a36Sopenharmony_ci		priv->video_standard = MN_NTSC_PAL_BTSC;
85962306a36Sopenharmony_ci		return;
86062306a36Sopenharmony_ci	}
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	if (params->std & V4L2_STD_PAL_BG) {
86362306a36Sopenharmony_ci		/* default to NICAM audio standard */
86462306a36Sopenharmony_ci		priv->video_standard = BG_PAL_NICAM;
86562306a36Sopenharmony_ci		return;
86662306a36Sopenharmony_ci	}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	if (params->std & V4L2_STD_PAL_I) {
86962306a36Sopenharmony_ci		/* default to NICAM audio standard */
87062306a36Sopenharmony_ci		priv->video_standard = I_PAL_NICAM;
87162306a36Sopenharmony_ci		return;
87262306a36Sopenharmony_ci	}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	if (params->std & V4L2_STD_PAL_DK) {
87562306a36Sopenharmony_ci		/* default to NICAM audio standard */
87662306a36Sopenharmony_ci		priv->video_standard = DK_PAL_NICAM;
87762306a36Sopenharmony_ci		return;
87862306a36Sopenharmony_ci	}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	if (params->std & V4L2_STD_SECAM_DK) {
88162306a36Sopenharmony_ci		/* default to A2 DK1 audio standard */
88262306a36Sopenharmony_ci		priv->video_standard = DK_SECAM_A2DK1;
88362306a36Sopenharmony_ci		return;
88462306a36Sopenharmony_ci	}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	if (params->std & V4L2_STD_SECAM_L) {
88762306a36Sopenharmony_ci		priv->video_standard = L_SECAM_NICAM;
88862306a36Sopenharmony_ci		return;
88962306a36Sopenharmony_ci	}
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	if (params->std & V4L2_STD_SECAM_LC) {
89262306a36Sopenharmony_ci		priv->video_standard = LC_SECAM_NICAM;
89362306a36Sopenharmony_ci		return;
89462306a36Sopenharmony_ci	}
89562306a36Sopenharmony_ci}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_cistatic int xc5000_set_tv_freq(struct dvb_frontend *fe)
89862306a36Sopenharmony_ci{
89962306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
90062306a36Sopenharmony_ci	u16 pll_lock_status;
90162306a36Sopenharmony_ci	int ret;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_citune_channel:
90462306a36Sopenharmony_ci	ret = xc_set_signal_source(priv, priv->rf_mode);
90562306a36Sopenharmony_ci	if (ret != 0) {
90662306a36Sopenharmony_ci		printk(KERN_ERR
90762306a36Sopenharmony_ci			"xc5000: xc_set_signal_source(%d) failed\n",
90862306a36Sopenharmony_ci			priv->rf_mode);
90962306a36Sopenharmony_ci		return -EREMOTEIO;
91062306a36Sopenharmony_ci	}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	ret = xc_set_tv_standard(priv,
91362306a36Sopenharmony_ci		xc5000_standard[priv->video_standard].video_mode,
91462306a36Sopenharmony_ci		xc5000_standard[priv->video_standard].audio_mode, 0);
91562306a36Sopenharmony_ci	if (ret != 0) {
91662306a36Sopenharmony_ci		printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n");
91762306a36Sopenharmony_ci		return -EREMOTEIO;
91862306a36Sopenharmony_ci	}
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09);
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG);
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	if (debug)
92562306a36Sopenharmony_ci		xc_debug_dump(priv);
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	if (priv->pll_register_no != 0) {
92862306a36Sopenharmony_ci		msleep(20);
92962306a36Sopenharmony_ci		ret = xc5000_readreg(priv, priv->pll_register_no,
93062306a36Sopenharmony_ci				     &pll_lock_status);
93162306a36Sopenharmony_ci		if (ret)
93262306a36Sopenharmony_ci			return ret;
93362306a36Sopenharmony_ci		if (pll_lock_status > 63) {
93462306a36Sopenharmony_ci			/* PLL is unlocked, force reload of the firmware */
93562306a36Sopenharmony_ci			dprintk(1, "xc5000: PLL not locked (0x%x).  Reloading...\n",
93662306a36Sopenharmony_ci				pll_lock_status);
93762306a36Sopenharmony_ci			if (xc_load_fw_and_init_tuner(fe, 1) != 0) {
93862306a36Sopenharmony_ci				printk(KERN_ERR "xc5000: Unable to reload fw\n");
93962306a36Sopenharmony_ci				return -EREMOTEIO;
94062306a36Sopenharmony_ci			}
94162306a36Sopenharmony_ci			goto tune_channel;
94262306a36Sopenharmony_ci		}
94362306a36Sopenharmony_ci	}
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	return 0;
94662306a36Sopenharmony_ci}
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_cistatic int xc5000_config_radio(struct dvb_frontend *fe,
94962306a36Sopenharmony_ci			       struct analog_parameters *params)
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	dprintk(1, "%s() frequency=%d (in units of khz)\n",
95562306a36Sopenharmony_ci		__func__, params->frequency);
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	if (priv->radio_input == XC5000_RADIO_NOT_CONFIGURED) {
95862306a36Sopenharmony_ci		dprintk(1, "%s() radio input not configured\n", __func__);
95962306a36Sopenharmony_ci		return -EINVAL;
96062306a36Sopenharmony_ci	}
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	priv->freq_hz = params->frequency * 125 / 2;
96362306a36Sopenharmony_ci	priv->rf_mode = XC_RF_MODE_AIR;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	return 0;
96662306a36Sopenharmony_ci}
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_cistatic int xc5000_set_radio_freq(struct dvb_frontend *fe)
96962306a36Sopenharmony_ci{
97062306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
97162306a36Sopenharmony_ci	int ret;
97262306a36Sopenharmony_ci	u8 radio_input;
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	if (priv->radio_input == XC5000_RADIO_FM1)
97562306a36Sopenharmony_ci		radio_input = FM_RADIO_INPUT1;
97662306a36Sopenharmony_ci	else if  (priv->radio_input == XC5000_RADIO_FM2)
97762306a36Sopenharmony_ci		radio_input = FM_RADIO_INPUT2;
97862306a36Sopenharmony_ci	else if  (priv->radio_input == XC5000_RADIO_FM1_MONO)
97962306a36Sopenharmony_ci		radio_input = FM_RADIO_INPUT1_MONO;
98062306a36Sopenharmony_ci	else {
98162306a36Sopenharmony_ci		dprintk(1, "%s() unknown radio input %d\n", __func__,
98262306a36Sopenharmony_ci			priv->radio_input);
98362306a36Sopenharmony_ci		return -EINVAL;
98462306a36Sopenharmony_ci	}
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	ret = xc_set_tv_standard(priv, xc5000_standard[radio_input].video_mode,
98762306a36Sopenharmony_ci			       xc5000_standard[radio_input].audio_mode, radio_input);
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	if (ret != 0) {
99062306a36Sopenharmony_ci		printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n");
99162306a36Sopenharmony_ci		return -EREMOTEIO;
99262306a36Sopenharmony_ci	}
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	ret = xc_set_signal_source(priv, priv->rf_mode);
99562306a36Sopenharmony_ci	if (ret != 0) {
99662306a36Sopenharmony_ci		printk(KERN_ERR
99762306a36Sopenharmony_ci			"xc5000: xc_set_signal_source(%d) failed\n",
99862306a36Sopenharmony_ci			priv->rf_mode);
99962306a36Sopenharmony_ci		return -EREMOTEIO;
100062306a36Sopenharmony_ci	}
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	if ((priv->radio_input == XC5000_RADIO_FM1) ||
100362306a36Sopenharmony_ci				(priv->radio_input == XC5000_RADIO_FM2))
100462306a36Sopenharmony_ci		xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09);
100562306a36Sopenharmony_ci	else if  (priv->radio_input == XC5000_RADIO_FM1_MONO)
100662306a36Sopenharmony_ci		xc_write_reg(priv, XREG_OUTPUT_AMP, 0x06);
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG);
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	return 0;
101162306a36Sopenharmony_ci}
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_cistatic int xc5000_set_params(struct dvb_frontend *fe)
101462306a36Sopenharmony_ci{
101562306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	if (xc_load_fw_and_init_tuner(fe, 0) != 0) {
101862306a36Sopenharmony_ci		dprintk(1, "Unable to load firmware and init tuner\n");
101962306a36Sopenharmony_ci		return -EINVAL;
102062306a36Sopenharmony_ci	}
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	switch (priv->mode) {
102362306a36Sopenharmony_ci	case V4L2_TUNER_RADIO:
102462306a36Sopenharmony_ci		return xc5000_set_radio_freq(fe);
102562306a36Sopenharmony_ci	case V4L2_TUNER_ANALOG_TV:
102662306a36Sopenharmony_ci		return xc5000_set_tv_freq(fe);
102762306a36Sopenharmony_ci	case V4L2_TUNER_DIGITAL_TV:
102862306a36Sopenharmony_ci		return xc5000_tune_digital(fe);
102962306a36Sopenharmony_ci	}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	return 0;
103262306a36Sopenharmony_ci}
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_cistatic int xc5000_set_analog_params(struct dvb_frontend *fe,
103562306a36Sopenharmony_ci			     struct analog_parameters *params)
103662306a36Sopenharmony_ci{
103762306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
103862306a36Sopenharmony_ci	int ret;
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	if (priv->i2c_props.adap == NULL)
104162306a36Sopenharmony_ci		return -EINVAL;
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	switch (params->mode) {
104462306a36Sopenharmony_ci	case V4L2_TUNER_RADIO:
104562306a36Sopenharmony_ci		ret = xc5000_config_radio(fe, params);
104662306a36Sopenharmony_ci		if (ret)
104762306a36Sopenharmony_ci			return ret;
104862306a36Sopenharmony_ci		break;
104962306a36Sopenharmony_ci	case V4L2_TUNER_ANALOG_TV:
105062306a36Sopenharmony_ci		xc5000_config_tv(fe, params);
105162306a36Sopenharmony_ci		break;
105262306a36Sopenharmony_ci	default:
105362306a36Sopenharmony_ci		break;
105462306a36Sopenharmony_ci	}
105562306a36Sopenharmony_ci	priv->mode = params->mode;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	return xc5000_set_params(fe);
105862306a36Sopenharmony_ci}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_cistatic int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq)
106162306a36Sopenharmony_ci{
106262306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
106362306a36Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
106462306a36Sopenharmony_ci	*freq = priv->freq_hz + priv->freq_offset;
106562306a36Sopenharmony_ci	return 0;
106662306a36Sopenharmony_ci}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_cistatic int xc5000_get_if_frequency(struct dvb_frontend *fe, u32 *freq)
106962306a36Sopenharmony_ci{
107062306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
107162306a36Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
107262306a36Sopenharmony_ci	*freq = priv->if_khz * 1000;
107362306a36Sopenharmony_ci	return 0;
107462306a36Sopenharmony_ci}
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_cistatic int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw)
107762306a36Sopenharmony_ci{
107862306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
107962306a36Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	*bw = priv->bandwidth;
108262306a36Sopenharmony_ci	return 0;
108362306a36Sopenharmony_ci}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_cistatic int xc5000_get_status(struct dvb_frontend *fe, u32 *status)
108662306a36Sopenharmony_ci{
108762306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
108862306a36Sopenharmony_ci	u16 lock_status = 0;
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	xc_get_lock_status(priv, &lock_status);
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	dprintk(1, "%s() lock_status = 0x%08x\n", __func__, lock_status);
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	*status = lock_status;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	return 0;
109762306a36Sopenharmony_ci}
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_cistatic int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force)
110062306a36Sopenharmony_ci{
110162306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
110262306a36Sopenharmony_ci	const struct xc5000_fw_cfg *desired_fw = xc5000_assign_firmware(priv->chip_id);
110362306a36Sopenharmony_ci	const struct firmware *fw;
110462306a36Sopenharmony_ci	int ret, i;
110562306a36Sopenharmony_ci	u16 pll_lock_status;
110662306a36Sopenharmony_ci	u16 fw_ck;
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	cancel_delayed_work(&priv->timer_sleep);
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	if (!force && xc5000_is_firmware_loaded(fe) == 0)
111162306a36Sopenharmony_ci		return 0;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	if (!priv->firmware) {
111462306a36Sopenharmony_ci		ret = request_firmware(&fw, desired_fw->name,
111562306a36Sopenharmony_ci					priv->i2c_props.adap->dev.parent);
111662306a36Sopenharmony_ci		if (ret) {
111762306a36Sopenharmony_ci			pr_err("xc5000: Upload failed. rc %d\n", ret);
111862306a36Sopenharmony_ci			return ret;
111962306a36Sopenharmony_ci		}
112062306a36Sopenharmony_ci		dprintk(1, "firmware read %zu bytes.\n", fw->size);
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci		if (fw->size != desired_fw->size) {
112362306a36Sopenharmony_ci			pr_err("xc5000: Firmware file with incorrect size\n");
112462306a36Sopenharmony_ci			release_firmware(fw);
112562306a36Sopenharmony_ci			return -EINVAL;
112662306a36Sopenharmony_ci		}
112762306a36Sopenharmony_ci		priv->firmware = fw;
112862306a36Sopenharmony_ci	} else
112962306a36Sopenharmony_ci		fw = priv->firmware;
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	/* Try up to 5 times to load firmware */
113262306a36Sopenharmony_ci	for (i = 0; i < 5; i++) {
113362306a36Sopenharmony_ci		if (i)
113462306a36Sopenharmony_ci			printk(KERN_CONT " - retrying to upload firmware.\n");
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci		ret = xc5000_fwupload(fe, desired_fw, fw);
113762306a36Sopenharmony_ci		if (ret != 0)
113862306a36Sopenharmony_ci			goto err;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci		msleep(20);
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci		if (priv->fw_checksum_supported) {
114362306a36Sopenharmony_ci			if (xc5000_readreg(priv, XREG_FW_CHECKSUM, &fw_ck)) {
114462306a36Sopenharmony_ci				printk(KERN_ERR
114562306a36Sopenharmony_ci				       "xc5000: FW checksum reading failed.");
114662306a36Sopenharmony_ci				continue;
114762306a36Sopenharmony_ci			}
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci			if (!fw_ck) {
115062306a36Sopenharmony_ci				printk(KERN_ERR
115162306a36Sopenharmony_ci				       "xc5000: FW checksum failed = 0x%04x.",
115262306a36Sopenharmony_ci				       fw_ck);
115362306a36Sopenharmony_ci				continue;
115462306a36Sopenharmony_ci			}
115562306a36Sopenharmony_ci		}
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci		/* Start the tuner self-calibration process */
115862306a36Sopenharmony_ci		ret = xc_initialize(priv);
115962306a36Sopenharmony_ci		if (ret) {
116062306a36Sopenharmony_ci			printk(KERN_ERR "xc5000: Can't request self-calibration.");
116162306a36Sopenharmony_ci			continue;
116262306a36Sopenharmony_ci		}
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci		/* Wait for calibration to complete.
116562306a36Sopenharmony_ci		 * We could continue but XC5000 will clock stretch subsequent
116662306a36Sopenharmony_ci		 * I2C transactions until calibration is complete.  This way we
116762306a36Sopenharmony_ci		 * don't have to rely on clock stretching working.
116862306a36Sopenharmony_ci		 */
116962306a36Sopenharmony_ci		msleep(100);
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci		if (priv->init_status_supported) {
117262306a36Sopenharmony_ci			if (xc5000_readreg(priv, XREG_INIT_STATUS, &fw_ck)) {
117362306a36Sopenharmony_ci				printk(KERN_ERR
117462306a36Sopenharmony_ci				       "xc5000: FW failed reading init status.");
117562306a36Sopenharmony_ci				continue;
117662306a36Sopenharmony_ci			}
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci			if (!fw_ck) {
117962306a36Sopenharmony_ci				printk(KERN_ERR
118062306a36Sopenharmony_ci				       "xc5000: FW init status failed = 0x%04x.",
118162306a36Sopenharmony_ci				       fw_ck);
118262306a36Sopenharmony_ci				continue;
118362306a36Sopenharmony_ci			}
118462306a36Sopenharmony_ci		}
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci		if (priv->pll_register_no) {
118762306a36Sopenharmony_ci			ret = xc5000_readreg(priv, priv->pll_register_no,
118862306a36Sopenharmony_ci					     &pll_lock_status);
118962306a36Sopenharmony_ci			if (ret)
119062306a36Sopenharmony_ci				continue;
119162306a36Sopenharmony_ci			if (pll_lock_status > 63) {
119262306a36Sopenharmony_ci				/* PLL is unlocked, force reload of the firmware */
119362306a36Sopenharmony_ci				printk(KERN_ERR
119462306a36Sopenharmony_ci				       "xc5000: PLL not running after fwload.");
119562306a36Sopenharmony_ci				continue;
119662306a36Sopenharmony_ci			}
119762306a36Sopenharmony_ci		}
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci		/* Default to "CABLE" mode */
120062306a36Sopenharmony_ci		ret = xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE);
120162306a36Sopenharmony_ci		if (!ret)
120262306a36Sopenharmony_ci			break;
120362306a36Sopenharmony_ci		printk(KERN_ERR "xc5000: can't set to cable mode.");
120462306a36Sopenharmony_ci	}
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_cierr:
120762306a36Sopenharmony_ci	if (!ret)
120862306a36Sopenharmony_ci		printk(KERN_INFO "xc5000: Firmware %s loaded and running.\n",
120962306a36Sopenharmony_ci		       desired_fw->name);
121062306a36Sopenharmony_ci	else
121162306a36Sopenharmony_ci		printk(KERN_CONT " - too many retries. Giving up\n");
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	return ret;
121462306a36Sopenharmony_ci}
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_cistatic void xc5000_do_timer_sleep(struct work_struct *timer_sleep)
121762306a36Sopenharmony_ci{
121862306a36Sopenharmony_ci	struct xc5000_priv *priv =container_of(timer_sleep, struct xc5000_priv,
121962306a36Sopenharmony_ci					       timer_sleep.work);
122062306a36Sopenharmony_ci	struct dvb_frontend *fe = priv->fe;
122162306a36Sopenharmony_ci	int ret;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	/* According to Xceive technical support, the "powerdown" register
122662306a36Sopenharmony_ci	   was removed in newer versions of the firmware.  The "supported"
122762306a36Sopenharmony_ci	   way to sleep the tuner is to pull the reset pin low for 10ms */
122862306a36Sopenharmony_ci	ret = xc5000_tuner_reset(fe);
122962306a36Sopenharmony_ci	if (ret != 0)
123062306a36Sopenharmony_ci		printk(KERN_ERR
123162306a36Sopenharmony_ci			"xc5000: %s() unable to shutdown tuner\n",
123262306a36Sopenharmony_ci			__func__);
123362306a36Sopenharmony_ci}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_cistatic int xc5000_sleep(struct dvb_frontend *fe)
123662306a36Sopenharmony_ci{
123762306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	/* Avoid firmware reload on slow devices */
124262306a36Sopenharmony_ci	if (no_poweroff)
124362306a36Sopenharmony_ci		return 0;
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	schedule_delayed_work(&priv->timer_sleep,
124662306a36Sopenharmony_ci			      msecs_to_jiffies(XC5000_SLEEP_TIME));
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	return 0;
124962306a36Sopenharmony_ci}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_cistatic int xc5000_suspend(struct dvb_frontend *fe)
125262306a36Sopenharmony_ci{
125362306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
125462306a36Sopenharmony_ci	int ret;
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	cancel_delayed_work(&priv->timer_sleep);
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	ret = xc5000_tuner_reset(fe);
126162306a36Sopenharmony_ci	if (ret != 0)
126262306a36Sopenharmony_ci		printk(KERN_ERR
126362306a36Sopenharmony_ci			"xc5000: %s() unable to shutdown tuner\n",
126462306a36Sopenharmony_ci			__func__);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	return 0;
126762306a36Sopenharmony_ci}
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_cistatic int xc5000_resume(struct dvb_frontend *fe)
127062306a36Sopenharmony_ci{
127162306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	/* suspended before firmware is loaded.
127662306a36Sopenharmony_ci	   Avoid firmware load in resume path. */
127762306a36Sopenharmony_ci	if (!priv->firmware)
127862306a36Sopenharmony_ci		return 0;
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	return xc5000_set_params(fe);
128162306a36Sopenharmony_ci}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_cistatic int xc5000_init(struct dvb_frontend *fe)
128462306a36Sopenharmony_ci{
128562306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
128662306a36Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	if (xc_load_fw_and_init_tuner(fe, 0) != 0) {
128962306a36Sopenharmony_ci		printk(KERN_ERR "xc5000: Unable to initialise tuner\n");
129062306a36Sopenharmony_ci		return -EREMOTEIO;
129162306a36Sopenharmony_ci	}
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	if (debug)
129462306a36Sopenharmony_ci		xc_debug_dump(priv);
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	return 0;
129762306a36Sopenharmony_ci}
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_cistatic void xc5000_release(struct dvb_frontend *fe)
130062306a36Sopenharmony_ci{
130162306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	mutex_lock(&xc5000_list_mutex);
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	if (priv) {
130862306a36Sopenharmony_ci		cancel_delayed_work(&priv->timer_sleep);
130962306a36Sopenharmony_ci		if (priv->firmware) {
131062306a36Sopenharmony_ci			release_firmware(priv->firmware);
131162306a36Sopenharmony_ci			priv->firmware = NULL;
131262306a36Sopenharmony_ci		}
131362306a36Sopenharmony_ci		hybrid_tuner_release_state(priv);
131462306a36Sopenharmony_ci	}
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	mutex_unlock(&xc5000_list_mutex);
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	fe->tuner_priv = NULL;
131962306a36Sopenharmony_ci}
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_cistatic int xc5000_set_config(struct dvb_frontend *fe, void *priv_cfg)
132262306a36Sopenharmony_ci{
132362306a36Sopenharmony_ci	struct xc5000_priv *priv = fe->tuner_priv;
132462306a36Sopenharmony_ci	struct xc5000_config *p = priv_cfg;
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	dprintk(1, "%s()\n", __func__);
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	if (p->if_khz)
132962306a36Sopenharmony_ci		priv->if_khz = p->if_khz;
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	if (p->radio_input)
133262306a36Sopenharmony_ci		priv->radio_input = p->radio_input;
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	if (p->output_amp)
133562306a36Sopenharmony_ci		priv->output_amp = p->output_amp;
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	return 0;
133862306a36Sopenharmony_ci}
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_cistatic const struct dvb_tuner_ops xc5000_tuner_ops = {
134262306a36Sopenharmony_ci	.info = {
134362306a36Sopenharmony_ci		.name              = "Xceive XC5000",
134462306a36Sopenharmony_ci		.frequency_min_hz  =    1 * MHz,
134562306a36Sopenharmony_ci		.frequency_max_hz  = 1023 * MHz,
134662306a36Sopenharmony_ci		.frequency_step_hz =   50 * kHz,
134762306a36Sopenharmony_ci	},
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	.release	   = xc5000_release,
135062306a36Sopenharmony_ci	.init		   = xc5000_init,
135162306a36Sopenharmony_ci	.sleep		   = xc5000_sleep,
135262306a36Sopenharmony_ci	.suspend	   = xc5000_suspend,
135362306a36Sopenharmony_ci	.resume		   = xc5000_resume,
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	.set_config	   = xc5000_set_config,
135662306a36Sopenharmony_ci	.set_params	   = xc5000_set_digital_params,
135762306a36Sopenharmony_ci	.set_analog_params = xc5000_set_analog_params,
135862306a36Sopenharmony_ci	.get_frequency	   = xc5000_get_frequency,
135962306a36Sopenharmony_ci	.get_if_frequency  = xc5000_get_if_frequency,
136062306a36Sopenharmony_ci	.get_bandwidth	   = xc5000_get_bandwidth,
136162306a36Sopenharmony_ci	.get_status	   = xc5000_get_status
136262306a36Sopenharmony_ci};
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_cistruct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
136562306a36Sopenharmony_ci				   struct i2c_adapter *i2c,
136662306a36Sopenharmony_ci				   const struct xc5000_config *cfg)
136762306a36Sopenharmony_ci{
136862306a36Sopenharmony_ci	struct xc5000_priv *priv = NULL;
136962306a36Sopenharmony_ci	int instance;
137062306a36Sopenharmony_ci	u16 id = 0;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	dprintk(1, "%s(%d-%04x)\n", __func__,
137362306a36Sopenharmony_ci		i2c ? i2c_adapter_id(i2c) : -1,
137462306a36Sopenharmony_ci		cfg ? cfg->i2c_address : -1);
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	mutex_lock(&xc5000_list_mutex);
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	instance = hybrid_tuner_request_state(struct xc5000_priv, priv,
137962306a36Sopenharmony_ci					      hybrid_tuner_instance_list,
138062306a36Sopenharmony_ci					      i2c, cfg->i2c_address, "xc5000");
138162306a36Sopenharmony_ci	switch (instance) {
138262306a36Sopenharmony_ci	case 0:
138362306a36Sopenharmony_ci		goto fail;
138462306a36Sopenharmony_ci	case 1:
138562306a36Sopenharmony_ci		/* new tuner instance */
138662306a36Sopenharmony_ci		priv->bandwidth = 6000000;
138762306a36Sopenharmony_ci		fe->tuner_priv = priv;
138862306a36Sopenharmony_ci		priv->fe = fe;
138962306a36Sopenharmony_ci		INIT_DELAYED_WORK(&priv->timer_sleep, xc5000_do_timer_sleep);
139062306a36Sopenharmony_ci		break;
139162306a36Sopenharmony_ci	default:
139262306a36Sopenharmony_ci		/* existing tuner instance */
139362306a36Sopenharmony_ci		fe->tuner_priv = priv;
139462306a36Sopenharmony_ci		break;
139562306a36Sopenharmony_ci	}
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	if (priv->if_khz == 0) {
139862306a36Sopenharmony_ci		/* If the IF hasn't been set yet, use the value provided by
139962306a36Sopenharmony_ci		   the caller (occurs in hybrid devices where the analog
140062306a36Sopenharmony_ci		   call to xc5000_attach occurs before the digital side) */
140162306a36Sopenharmony_ci		priv->if_khz = cfg->if_khz;
140262306a36Sopenharmony_ci	}
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	if (priv->xtal_khz == 0)
140562306a36Sopenharmony_ci		priv->xtal_khz = cfg->xtal_khz;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	if (priv->radio_input == 0)
140862306a36Sopenharmony_ci		priv->radio_input = cfg->radio_input;
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci	/* don't override chip id if it's already been set
141162306a36Sopenharmony_ci	   unless explicitly specified */
141262306a36Sopenharmony_ci	if ((priv->chip_id == 0) || (cfg->chip_id))
141362306a36Sopenharmony_ci		/* use default chip id if none specified, set to 0 so
141462306a36Sopenharmony_ci		   it can be overridden if this is a hybrid driver */
141562306a36Sopenharmony_ci		priv->chip_id = (cfg->chip_id) ? cfg->chip_id : 0;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	/* don't override output_amp if it's already been set
141862306a36Sopenharmony_ci	   unless explicitly specified */
141962306a36Sopenharmony_ci	if ((priv->output_amp == 0) || (cfg->output_amp))
142062306a36Sopenharmony_ci		/* use default output_amp value if none specified */
142162306a36Sopenharmony_ci		priv->output_amp = (cfg->output_amp) ? cfg->output_amp : 0x8a;
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	/* Check if firmware has been loaded. It is possible that another
142462306a36Sopenharmony_ci	   instance of the driver has loaded the firmware.
142562306a36Sopenharmony_ci	 */
142662306a36Sopenharmony_ci	if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
142762306a36Sopenharmony_ci		goto fail;
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	switch (id) {
143062306a36Sopenharmony_ci	case XC_PRODUCT_ID_FW_LOADED:
143162306a36Sopenharmony_ci		printk(KERN_INFO
143262306a36Sopenharmony_ci			"xc5000: Successfully identified at address 0x%02x\n",
143362306a36Sopenharmony_ci			cfg->i2c_address);
143462306a36Sopenharmony_ci		printk(KERN_INFO
143562306a36Sopenharmony_ci			"xc5000: Firmware has been loaded previously\n");
143662306a36Sopenharmony_ci		break;
143762306a36Sopenharmony_ci	case XC_PRODUCT_ID_FW_NOT_LOADED:
143862306a36Sopenharmony_ci		printk(KERN_INFO
143962306a36Sopenharmony_ci			"xc5000: Successfully identified at address 0x%02x\n",
144062306a36Sopenharmony_ci			cfg->i2c_address);
144162306a36Sopenharmony_ci		printk(KERN_INFO
144262306a36Sopenharmony_ci			"xc5000: Firmware has not been loaded previously\n");
144362306a36Sopenharmony_ci		break;
144462306a36Sopenharmony_ci	default:
144562306a36Sopenharmony_ci		printk(KERN_ERR
144662306a36Sopenharmony_ci			"xc5000: Device not found at addr 0x%02x (0x%x)\n",
144762306a36Sopenharmony_ci			cfg->i2c_address, id);
144862306a36Sopenharmony_ci		goto fail;
144962306a36Sopenharmony_ci	}
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	mutex_unlock(&xc5000_list_mutex);
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops,
145462306a36Sopenharmony_ci		sizeof(struct dvb_tuner_ops));
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	return fe;
145762306a36Sopenharmony_cifail:
145862306a36Sopenharmony_ci	mutex_unlock(&xc5000_list_mutex);
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	xc5000_release(fe);
146162306a36Sopenharmony_ci	return NULL;
146262306a36Sopenharmony_ci}
146362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(xc5000_attach);
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ciMODULE_AUTHOR("Steven Toth");
146662306a36Sopenharmony_ciMODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver");
146762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
146862306a36Sopenharmony_ciMODULE_FIRMWARE(XC5000A_FIRMWARE);
146962306a36Sopenharmony_ciMODULE_FIRMWARE(XC5000C_FIRMWARE);
1470