162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * drxd_hard.c: DVB-T Demodulator Micronas DRX3975D-A2,DRX397xD-B1
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2003-2007 Micronas
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/kernel.h>
962306a36Sopenharmony_ci#include <linux/module.h>
1062306a36Sopenharmony_ci#include <linux/moduleparam.h>
1162306a36Sopenharmony_ci#include <linux/init.h>
1262306a36Sopenharmony_ci#include <linux/delay.h>
1362306a36Sopenharmony_ci#include <linux/firmware.h>
1462306a36Sopenharmony_ci#include <linux/i2c.h>
1562306a36Sopenharmony_ci#include <asm/div64.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <media/dvb_frontend.h>
1862306a36Sopenharmony_ci#include "drxd.h"
1962306a36Sopenharmony_ci#include "drxd_firm.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define DRX_FW_FILENAME_A2 "drxd-a2-1.1.fw"
2262306a36Sopenharmony_ci#define DRX_FW_FILENAME_B1 "drxd-b1-1.1.fw"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define CHUNK_SIZE 48
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define DRX_I2C_RMW           0x10
2762306a36Sopenharmony_ci#define DRX_I2C_BROADCAST     0x20
2862306a36Sopenharmony_ci#define DRX_I2C_CLEARCRC      0x80
2962306a36Sopenharmony_ci#define DRX_I2C_SINGLE_MASTER 0xC0
3062306a36Sopenharmony_ci#define DRX_I2C_MODEFLAGS     0xC0
3162306a36Sopenharmony_ci#define DRX_I2C_FLAGS         0xF0
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define DEFAULT_LOCK_TIMEOUT    1100
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define DRX_CHANNEL_AUTO 0
3662306a36Sopenharmony_ci#define DRX_CHANNEL_HIGH 1
3762306a36Sopenharmony_ci#define DRX_CHANNEL_LOW  2
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#define DRX_LOCK_MPEG  1
4062306a36Sopenharmony_ci#define DRX_LOCK_FEC   2
4162306a36Sopenharmony_ci#define DRX_LOCK_DEMOD 4
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/****************************************************************************/
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cienum CSCDState {
4662306a36Sopenharmony_ci	CSCD_INIT = 0,
4762306a36Sopenharmony_ci	CSCD_SET,
4862306a36Sopenharmony_ci	CSCD_SAVED
4962306a36Sopenharmony_ci};
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cienum CDrxdState {
5262306a36Sopenharmony_ci	DRXD_UNINITIALIZED = 0,
5362306a36Sopenharmony_ci	DRXD_STOPPED,
5462306a36Sopenharmony_ci	DRXD_STARTED
5562306a36Sopenharmony_ci};
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cienum AGC_CTRL_MODE {
5862306a36Sopenharmony_ci	AGC_CTRL_AUTO = 0,
5962306a36Sopenharmony_ci	AGC_CTRL_USER,
6062306a36Sopenharmony_ci	AGC_CTRL_OFF
6162306a36Sopenharmony_ci};
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cienum OperationMode {
6462306a36Sopenharmony_ci	OM_Default,
6562306a36Sopenharmony_ci	OM_DVBT_Diversity_Front,
6662306a36Sopenharmony_ci	OM_DVBT_Diversity_End
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistruct SCfgAgc {
7062306a36Sopenharmony_ci	enum AGC_CTRL_MODE ctrlMode;
7162306a36Sopenharmony_ci	u16 outputLevel;	/* range [0, ... , 1023], 1/n of fullscale range */
7262306a36Sopenharmony_ci	u16 settleLevel;	/* range [0, ... , 1023], 1/n of fullscale range */
7362306a36Sopenharmony_ci	u16 minOutputLevel;	/* range [0, ... , 1023], 1/n of fullscale range */
7462306a36Sopenharmony_ci	u16 maxOutputLevel;	/* range [0, ... , 1023], 1/n of fullscale range */
7562306a36Sopenharmony_ci	u16 speed;		/* range [0, ... , 1023], 1/n of fullscale range */
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	u16 R1;
7862306a36Sopenharmony_ci	u16 R2;
7962306a36Sopenharmony_ci	u16 R3;
8062306a36Sopenharmony_ci};
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistruct SNoiseCal {
8362306a36Sopenharmony_ci	int cpOpt;
8462306a36Sopenharmony_ci	short cpNexpOfs;
8562306a36Sopenharmony_ci	short tdCal2k;
8662306a36Sopenharmony_ci	short tdCal8k;
8762306a36Sopenharmony_ci};
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cienum app_env {
9062306a36Sopenharmony_ci	APPENV_STATIC = 0,
9162306a36Sopenharmony_ci	APPENV_PORTABLE = 1,
9262306a36Sopenharmony_ci	APPENV_MOBILE = 2
9362306a36Sopenharmony_ci};
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cienum EIFFilter {
9662306a36Sopenharmony_ci	IFFILTER_SAW = 0,
9762306a36Sopenharmony_ci	IFFILTER_DISCRETE = 1
9862306a36Sopenharmony_ci};
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistruct drxd_state {
10162306a36Sopenharmony_ci	struct dvb_frontend frontend;
10262306a36Sopenharmony_ci	struct dvb_frontend_ops ops;
10362306a36Sopenharmony_ci	struct dtv_frontend_properties props;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	const struct firmware *fw;
10662306a36Sopenharmony_ci	struct device *dev;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	struct i2c_adapter *i2c;
10962306a36Sopenharmony_ci	void *priv;
11062306a36Sopenharmony_ci	struct drxd_config config;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	int i2c_access;
11362306a36Sopenharmony_ci	int init_done;
11462306a36Sopenharmony_ci	struct mutex mutex;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	u8 chip_adr;
11762306a36Sopenharmony_ci	u16 hi_cfg_timing_div;
11862306a36Sopenharmony_ci	u16 hi_cfg_bridge_delay;
11962306a36Sopenharmony_ci	u16 hi_cfg_wakeup_key;
12062306a36Sopenharmony_ci	u16 hi_cfg_ctrl;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	u16 intermediate_freq;
12362306a36Sopenharmony_ci	u16 osc_clock_freq;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	enum CSCDState cscd_state;
12662306a36Sopenharmony_ci	enum CDrxdState drxd_state;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	u16 sys_clock_freq;
12962306a36Sopenharmony_ci	s16 osc_clock_deviation;
13062306a36Sopenharmony_ci	u16 expected_sys_clock_freq;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	u16 insert_rs_byte;
13362306a36Sopenharmony_ci	u16 enable_parallel;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	int operation_mode;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	struct SCfgAgc if_agc_cfg;
13862306a36Sopenharmony_ci	struct SCfgAgc rf_agc_cfg;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	struct SNoiseCal noise_cal;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	u32 fe_fs_add_incr;
14362306a36Sopenharmony_ci	u32 org_fe_fs_add_incr;
14462306a36Sopenharmony_ci	u16 current_fe_if_incr;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	u16 m_FeAgRegAgPwd;
14762306a36Sopenharmony_ci	u16 m_FeAgRegAgAgcSio;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	u16 m_EcOcRegOcModeLop;
15062306a36Sopenharmony_ci	u16 m_EcOcRegSncSncLvl;
15162306a36Sopenharmony_ci	u8 *m_InitAtomicRead;
15262306a36Sopenharmony_ci	u8 *m_HiI2cPatch;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	u8 *m_ResetCEFR;
15562306a36Sopenharmony_ci	u8 *m_InitFE_1;
15662306a36Sopenharmony_ci	u8 *m_InitFE_2;
15762306a36Sopenharmony_ci	u8 *m_InitCP;
15862306a36Sopenharmony_ci	u8 *m_InitCE;
15962306a36Sopenharmony_ci	u8 *m_InitEQ;
16062306a36Sopenharmony_ci	u8 *m_InitSC;
16162306a36Sopenharmony_ci	u8 *m_InitEC;
16262306a36Sopenharmony_ci	u8 *m_ResetECRAM;
16362306a36Sopenharmony_ci	u8 *m_InitDiversityFront;
16462306a36Sopenharmony_ci	u8 *m_InitDiversityEnd;
16562306a36Sopenharmony_ci	u8 *m_DisableDiversity;
16662306a36Sopenharmony_ci	u8 *m_StartDiversityFront;
16762306a36Sopenharmony_ci	u8 *m_StartDiversityEnd;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	u8 *m_DiversityDelay8MHZ;
17062306a36Sopenharmony_ci	u8 *m_DiversityDelay6MHZ;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	u8 *microcode;
17362306a36Sopenharmony_ci	u32 microcode_length;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	int type_A;
17662306a36Sopenharmony_ci	int PGA;
17762306a36Sopenharmony_ci	int diversity;
17862306a36Sopenharmony_ci	int tuner_mirrors;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	enum app_env app_env_default;
18162306a36Sopenharmony_ci	enum app_env app_env_diversity;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci};
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci/****************************************************************************/
18662306a36Sopenharmony_ci/* I2C **********************************************************************/
18762306a36Sopenharmony_ci/****************************************************************************/
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_cistatic int i2c_write(struct i2c_adapter *adap, u8 adr, u8 * data, int len)
19062306a36Sopenharmony_ci{
19162306a36Sopenharmony_ci	struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len };
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	if (i2c_transfer(adap, &msg, 1) != 1)
19462306a36Sopenharmony_ci		return -1;
19562306a36Sopenharmony_ci	return 0;
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_cistatic int i2c_read(struct i2c_adapter *adap,
19962306a36Sopenharmony_ci		    u8 adr, u8 *msg, int len, u8 *answ, int alen)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	struct i2c_msg msgs[2] = {
20262306a36Sopenharmony_ci		{
20362306a36Sopenharmony_ci			.addr = adr, .flags = 0,
20462306a36Sopenharmony_ci			.buf = msg, .len = len
20562306a36Sopenharmony_ci		}, {
20662306a36Sopenharmony_ci			.addr = adr, .flags = I2C_M_RD,
20762306a36Sopenharmony_ci			.buf = answ, .len = alen
20862306a36Sopenharmony_ci		}
20962306a36Sopenharmony_ci	};
21062306a36Sopenharmony_ci	if (i2c_transfer(adap, msgs, 2) != 2)
21162306a36Sopenharmony_ci		return -1;
21262306a36Sopenharmony_ci	return 0;
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic inline u32 MulDiv32(u32 a, u32 b, u32 c)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	u64 tmp64;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	tmp64 = (u64)a * (u64)b;
22062306a36Sopenharmony_ci	do_div(tmp64, c);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	return (u32) tmp64;
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic int Read16(struct drxd_state *state, u32 reg, u16 *data, u8 flags)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	u8 adr = state->config.demod_address;
22862306a36Sopenharmony_ci	u8 mm1[4] = { reg & 0xff, (reg >> 16) & 0xff,
22962306a36Sopenharmony_ci		flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff
23062306a36Sopenharmony_ci	};
23162306a36Sopenharmony_ci	u8 mm2[2];
23262306a36Sopenharmony_ci	if (i2c_read(state->i2c, adr, mm1, 4, mm2, 2) < 0)
23362306a36Sopenharmony_ci		return -1;
23462306a36Sopenharmony_ci	if (data)
23562306a36Sopenharmony_ci		*data = mm2[0] | (mm2[1] << 8);
23662306a36Sopenharmony_ci	return mm2[0] | (mm2[1] << 8);
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic int Read32(struct drxd_state *state, u32 reg, u32 *data, u8 flags)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	u8 adr = state->config.demod_address;
24262306a36Sopenharmony_ci	u8 mm1[4] = { reg & 0xff, (reg >> 16) & 0xff,
24362306a36Sopenharmony_ci		flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff
24462306a36Sopenharmony_ci	};
24562306a36Sopenharmony_ci	u8 mm2[4];
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	if (i2c_read(state->i2c, adr, mm1, 4, mm2, 4) < 0)
24862306a36Sopenharmony_ci		return -1;
24962306a36Sopenharmony_ci	if (data)
25062306a36Sopenharmony_ci		*data =
25162306a36Sopenharmony_ci		    mm2[0] | (mm2[1] << 8) | (mm2[2] << 16) | (mm2[3] << 24);
25262306a36Sopenharmony_ci	return 0;
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic int Write16(struct drxd_state *state, u32 reg, u16 data, u8 flags)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	u8 adr = state->config.demod_address;
25862306a36Sopenharmony_ci	u8 mm[6] = { reg & 0xff, (reg >> 16) & 0xff,
25962306a36Sopenharmony_ci		flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff,
26062306a36Sopenharmony_ci		data & 0xff, (data >> 8) & 0xff
26162306a36Sopenharmony_ci	};
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	if (i2c_write(state->i2c, adr, mm, 6) < 0)
26462306a36Sopenharmony_ci		return -1;
26562306a36Sopenharmony_ci	return 0;
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic int Write32(struct drxd_state *state, u32 reg, u32 data, u8 flags)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	u8 adr = state->config.demod_address;
27162306a36Sopenharmony_ci	u8 mm[8] = { reg & 0xff, (reg >> 16) & 0xff,
27262306a36Sopenharmony_ci		flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff,
27362306a36Sopenharmony_ci		data & 0xff, (data >> 8) & 0xff,
27462306a36Sopenharmony_ci		(data >> 16) & 0xff, (data >> 24) & 0xff
27562306a36Sopenharmony_ci	};
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	if (i2c_write(state->i2c, adr, mm, 8) < 0)
27862306a36Sopenharmony_ci		return -1;
27962306a36Sopenharmony_ci	return 0;
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic int write_chunk(struct drxd_state *state,
28362306a36Sopenharmony_ci		       u32 reg, u8 *data, u32 len, u8 flags)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	u8 adr = state->config.demod_address;
28662306a36Sopenharmony_ci	u8 mm[CHUNK_SIZE + 4] = { reg & 0xff, (reg >> 16) & 0xff,
28762306a36Sopenharmony_ci		flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff
28862306a36Sopenharmony_ci	};
28962306a36Sopenharmony_ci	int i;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	for (i = 0; i < len; i++)
29262306a36Sopenharmony_ci		mm[4 + i] = data[i];
29362306a36Sopenharmony_ci	if (i2c_write(state->i2c, adr, mm, 4 + len) < 0) {
29462306a36Sopenharmony_ci		printk(KERN_ERR "error in write_chunk\n");
29562306a36Sopenharmony_ci		return -1;
29662306a36Sopenharmony_ci	}
29762306a36Sopenharmony_ci	return 0;
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic int WriteBlock(struct drxd_state *state,
30162306a36Sopenharmony_ci		      u32 Address, u16 BlockSize, u8 *pBlock, u8 Flags)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	while (BlockSize > 0) {
30462306a36Sopenharmony_ci		u16 Chunk = BlockSize > CHUNK_SIZE ? CHUNK_SIZE : BlockSize;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci		if (write_chunk(state, Address, pBlock, Chunk, Flags) < 0)
30762306a36Sopenharmony_ci			return -1;
30862306a36Sopenharmony_ci		pBlock += Chunk;
30962306a36Sopenharmony_ci		Address += (Chunk >> 1);
31062306a36Sopenharmony_ci		BlockSize -= Chunk;
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci	return 0;
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_cistatic int WriteTable(struct drxd_state *state, u8 * pTable)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	int status = 0;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	if (!pTable)
32062306a36Sopenharmony_ci		return 0;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	while (!status) {
32362306a36Sopenharmony_ci		u16 Length;
32462306a36Sopenharmony_ci		u32 Address = pTable[0] | (pTable[1] << 8) |
32562306a36Sopenharmony_ci		    (pTable[2] << 16) | (pTable[3] << 24);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci		if (Address == 0xFFFFFFFF)
32862306a36Sopenharmony_ci			break;
32962306a36Sopenharmony_ci		pTable += sizeof(u32);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci		Length = pTable[0] | (pTable[1] << 8);
33262306a36Sopenharmony_ci		pTable += sizeof(u16);
33362306a36Sopenharmony_ci		if (!Length)
33462306a36Sopenharmony_ci			break;
33562306a36Sopenharmony_ci		status = WriteBlock(state, Address, Length * 2, pTable, 0);
33662306a36Sopenharmony_ci		pTable += (Length * 2);
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci	return status;
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci/****************************************************************************/
34262306a36Sopenharmony_ci/****************************************************************************/
34362306a36Sopenharmony_ci/****************************************************************************/
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_cistatic int ResetCEFR(struct drxd_state *state)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	return WriteTable(state, state->m_ResetCEFR);
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_cistatic int InitCP(struct drxd_state *state)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	return WriteTable(state, state->m_InitCP);
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_cistatic int InitCE(struct drxd_state *state)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	int status;
35862306a36Sopenharmony_ci	enum app_env AppEnv = state->app_env_default;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	do {
36162306a36Sopenharmony_ci		status = WriteTable(state, state->m_InitCE);
36262306a36Sopenharmony_ci		if (status < 0)
36362306a36Sopenharmony_ci			break;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci		if (state->operation_mode == OM_DVBT_Diversity_Front ||
36662306a36Sopenharmony_ci		    state->operation_mode == OM_DVBT_Diversity_End) {
36762306a36Sopenharmony_ci			AppEnv = state->app_env_diversity;
36862306a36Sopenharmony_ci		}
36962306a36Sopenharmony_ci		if (AppEnv == APPENV_STATIC) {
37062306a36Sopenharmony_ci			status = Write16(state, CE_REG_TAPSET__A, 0x0000, 0);
37162306a36Sopenharmony_ci			if (status < 0)
37262306a36Sopenharmony_ci				break;
37362306a36Sopenharmony_ci		} else if (AppEnv == APPENV_PORTABLE) {
37462306a36Sopenharmony_ci			status = Write16(state, CE_REG_TAPSET__A, 0x0001, 0);
37562306a36Sopenharmony_ci			if (status < 0)
37662306a36Sopenharmony_ci				break;
37762306a36Sopenharmony_ci		} else if (AppEnv == APPENV_MOBILE && state->type_A) {
37862306a36Sopenharmony_ci			status = Write16(state, CE_REG_TAPSET__A, 0x0002, 0);
37962306a36Sopenharmony_ci			if (status < 0)
38062306a36Sopenharmony_ci				break;
38162306a36Sopenharmony_ci		} else if (AppEnv == APPENV_MOBILE && !state->type_A) {
38262306a36Sopenharmony_ci			status = Write16(state, CE_REG_TAPSET__A, 0x0006, 0);
38362306a36Sopenharmony_ci			if (status < 0)
38462306a36Sopenharmony_ci				break;
38562306a36Sopenharmony_ci		}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci		/* start ce */
38862306a36Sopenharmony_ci		status = Write16(state, B_CE_REG_COMM_EXEC__A, 0x0001, 0);
38962306a36Sopenharmony_ci		if (status < 0)
39062306a36Sopenharmony_ci			break;
39162306a36Sopenharmony_ci	} while (0);
39262306a36Sopenharmony_ci	return status;
39362306a36Sopenharmony_ci}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_cistatic int StopOC(struct drxd_state *state)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	int status = 0;
39862306a36Sopenharmony_ci	u16 ocSyncLvl = 0;
39962306a36Sopenharmony_ci	u16 ocModeLop = state->m_EcOcRegOcModeLop;
40062306a36Sopenharmony_ci	u16 dtoIncLop = 0;
40162306a36Sopenharmony_ci	u16 dtoIncHip = 0;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	do {
40462306a36Sopenharmony_ci		/* Store output configuration */
40562306a36Sopenharmony_ci		status = Read16(state, EC_OC_REG_SNC_ISC_LVL__A, &ocSyncLvl, 0);
40662306a36Sopenharmony_ci		if (status < 0)
40762306a36Sopenharmony_ci			break;
40862306a36Sopenharmony_ci		/* CHK_ERROR(Read16(EC_OC_REG_OC_MODE_LOP__A, &ocModeLop)); */
40962306a36Sopenharmony_ci		state->m_EcOcRegSncSncLvl = ocSyncLvl;
41062306a36Sopenharmony_ci		/* m_EcOcRegOcModeLop = ocModeLop; */
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci		/* Flush FIFO (byte-boundary) at fixed rate */
41362306a36Sopenharmony_ci		status = Read16(state, EC_OC_REG_RCN_MAP_LOP__A, &dtoIncLop, 0);
41462306a36Sopenharmony_ci		if (status < 0)
41562306a36Sopenharmony_ci			break;
41662306a36Sopenharmony_ci		status = Read16(state, EC_OC_REG_RCN_MAP_HIP__A, &dtoIncHip, 0);
41762306a36Sopenharmony_ci		if (status < 0)
41862306a36Sopenharmony_ci			break;
41962306a36Sopenharmony_ci		status = Write16(state, EC_OC_REG_DTO_INC_LOP__A, dtoIncLop, 0);
42062306a36Sopenharmony_ci		if (status < 0)
42162306a36Sopenharmony_ci			break;
42262306a36Sopenharmony_ci		status = Write16(state, EC_OC_REG_DTO_INC_HIP__A, dtoIncHip, 0);
42362306a36Sopenharmony_ci		if (status < 0)
42462306a36Sopenharmony_ci			break;
42562306a36Sopenharmony_ci		ocModeLop &= ~(EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC__M);
42662306a36Sopenharmony_ci		ocModeLop |= EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC_STATIC;
42762306a36Sopenharmony_ci		status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, ocModeLop, 0);
42862306a36Sopenharmony_ci		if (status < 0)
42962306a36Sopenharmony_ci			break;
43062306a36Sopenharmony_ci		status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_HOLD, 0);
43162306a36Sopenharmony_ci		if (status < 0)
43262306a36Sopenharmony_ci			break;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci		msleep(1);
43562306a36Sopenharmony_ci		/* Output pins to '0' */
43662306a36Sopenharmony_ci		status = Write16(state, EC_OC_REG_OCR_MPG_UOS__A, EC_OC_REG_OCR_MPG_UOS__M, 0);
43762306a36Sopenharmony_ci		if (status < 0)
43862306a36Sopenharmony_ci			break;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci		/* Force the OC out of sync */
44162306a36Sopenharmony_ci		ocSyncLvl &= ~(EC_OC_REG_SNC_ISC_LVL_OSC__M);
44262306a36Sopenharmony_ci		status = Write16(state, EC_OC_REG_SNC_ISC_LVL__A, ocSyncLvl, 0);
44362306a36Sopenharmony_ci		if (status < 0)
44462306a36Sopenharmony_ci			break;
44562306a36Sopenharmony_ci		ocModeLop &= ~(EC_OC_REG_OC_MODE_LOP_PAR_ENA__M);
44662306a36Sopenharmony_ci		ocModeLop |= EC_OC_REG_OC_MODE_LOP_PAR_ENA_ENABLE;
44762306a36Sopenharmony_ci		ocModeLop |= 0x2;	/* Magically-out-of-sync */
44862306a36Sopenharmony_ci		status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, ocModeLop, 0);
44962306a36Sopenharmony_ci		if (status < 0)
45062306a36Sopenharmony_ci			break;
45162306a36Sopenharmony_ci		status = Write16(state, EC_OC_REG_COMM_INT_STA__A, 0x0, 0);
45262306a36Sopenharmony_ci		if (status < 0)
45362306a36Sopenharmony_ci			break;
45462306a36Sopenharmony_ci		status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_ACTIVE, 0);
45562306a36Sopenharmony_ci		if (status < 0)
45662306a36Sopenharmony_ci			break;
45762306a36Sopenharmony_ci	} while (0);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	return status;
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic int StartOC(struct drxd_state *state)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	int status = 0;
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	do {
46762306a36Sopenharmony_ci		/* Stop OC */
46862306a36Sopenharmony_ci		status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_HOLD, 0);
46962306a36Sopenharmony_ci		if (status < 0)
47062306a36Sopenharmony_ci			break;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci		/* Restore output configuration */
47362306a36Sopenharmony_ci		status = Write16(state, EC_OC_REG_SNC_ISC_LVL__A, state->m_EcOcRegSncSncLvl, 0);
47462306a36Sopenharmony_ci		if (status < 0)
47562306a36Sopenharmony_ci			break;
47662306a36Sopenharmony_ci		status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, state->m_EcOcRegOcModeLop, 0);
47762306a36Sopenharmony_ci		if (status < 0)
47862306a36Sopenharmony_ci			break;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci		/* Output pins active again */
48162306a36Sopenharmony_ci		status = Write16(state, EC_OC_REG_OCR_MPG_UOS__A, EC_OC_REG_OCR_MPG_UOS_INIT, 0);
48262306a36Sopenharmony_ci		if (status < 0)
48362306a36Sopenharmony_ci			break;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci		/* Start OC */
48662306a36Sopenharmony_ci		status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_ACTIVE, 0);
48762306a36Sopenharmony_ci		if (status < 0)
48862306a36Sopenharmony_ci			break;
48962306a36Sopenharmony_ci	} while (0);
49062306a36Sopenharmony_ci	return status;
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic int InitEQ(struct drxd_state *state)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	return WriteTable(state, state->m_InitEQ);
49662306a36Sopenharmony_ci}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_cistatic int InitEC(struct drxd_state *state)
49962306a36Sopenharmony_ci{
50062306a36Sopenharmony_ci	return WriteTable(state, state->m_InitEC);
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_cistatic int InitSC(struct drxd_state *state)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	return WriteTable(state, state->m_InitSC);
50662306a36Sopenharmony_ci}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_cistatic int InitAtomicRead(struct drxd_state *state)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	return WriteTable(state, state->m_InitAtomicRead);
51162306a36Sopenharmony_ci}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_cistatic int CorrectSysClockDeviation(struct drxd_state *state);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_cistatic int DRX_GetLockStatus(struct drxd_state *state, u32 * pLockStatus)
51662306a36Sopenharmony_ci{
51762306a36Sopenharmony_ci	u16 ScRaRamLock = 0;
51862306a36Sopenharmony_ci	const u16 mpeg_lock_mask = (SC_RA_RAM_LOCK_MPEG__M |
51962306a36Sopenharmony_ci				    SC_RA_RAM_LOCK_FEC__M |
52062306a36Sopenharmony_ci				    SC_RA_RAM_LOCK_DEMOD__M);
52162306a36Sopenharmony_ci	const u16 fec_lock_mask = (SC_RA_RAM_LOCK_FEC__M |
52262306a36Sopenharmony_ci				   SC_RA_RAM_LOCK_DEMOD__M);
52362306a36Sopenharmony_ci	const u16 demod_lock_mask = SC_RA_RAM_LOCK_DEMOD__M;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	int status;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	*pLockStatus = 0;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	status = Read16(state, SC_RA_RAM_LOCK__A, &ScRaRamLock, 0x0000);
53062306a36Sopenharmony_ci	if (status < 0) {
53162306a36Sopenharmony_ci		printk(KERN_ERR "Can't read SC_RA_RAM_LOCK__A status = %08x\n", status);
53262306a36Sopenharmony_ci		return status;
53362306a36Sopenharmony_ci	}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	if (state->drxd_state != DRXD_STARTED)
53662306a36Sopenharmony_ci		return 0;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	if ((ScRaRamLock & mpeg_lock_mask) == mpeg_lock_mask) {
53962306a36Sopenharmony_ci		*pLockStatus |= DRX_LOCK_MPEG;
54062306a36Sopenharmony_ci		CorrectSysClockDeviation(state);
54162306a36Sopenharmony_ci	}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	if ((ScRaRamLock & fec_lock_mask) == fec_lock_mask)
54462306a36Sopenharmony_ci		*pLockStatus |= DRX_LOCK_FEC;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	if ((ScRaRamLock & demod_lock_mask) == demod_lock_mask)
54762306a36Sopenharmony_ci		*pLockStatus |= DRX_LOCK_DEMOD;
54862306a36Sopenharmony_ci	return 0;
54962306a36Sopenharmony_ci}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci/****************************************************************************/
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_cistatic int SetCfgIfAgc(struct drxd_state *state, struct SCfgAgc *cfg)
55462306a36Sopenharmony_ci{
55562306a36Sopenharmony_ci	int status;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	if (cfg->outputLevel > DRXD_FE_CTRL_MAX)
55862306a36Sopenharmony_ci		return -1;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	if (cfg->ctrlMode == AGC_CTRL_USER) {
56162306a36Sopenharmony_ci		do {
56262306a36Sopenharmony_ci			u16 FeAgRegPm1AgcWri;
56362306a36Sopenharmony_ci			u16 FeAgRegAgModeLop;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci			status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &FeAgRegAgModeLop, 0);
56662306a36Sopenharmony_ci			if (status < 0)
56762306a36Sopenharmony_ci				break;
56862306a36Sopenharmony_ci			FeAgRegAgModeLop &= (~FE_AG_REG_AG_MODE_LOP_MODE_4__M);
56962306a36Sopenharmony_ci			FeAgRegAgModeLop |= FE_AG_REG_AG_MODE_LOP_MODE_4_STATIC;
57062306a36Sopenharmony_ci			status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, FeAgRegAgModeLop, 0);
57162306a36Sopenharmony_ci			if (status < 0)
57262306a36Sopenharmony_ci				break;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci			FeAgRegPm1AgcWri = (u16) (cfg->outputLevel &
57562306a36Sopenharmony_ci						  FE_AG_REG_PM1_AGC_WRI__M);
57662306a36Sopenharmony_ci			status = Write16(state, FE_AG_REG_PM1_AGC_WRI__A, FeAgRegPm1AgcWri, 0);
57762306a36Sopenharmony_ci			if (status < 0)
57862306a36Sopenharmony_ci				break;
57962306a36Sopenharmony_ci		} while (0);
58062306a36Sopenharmony_ci	} else if (cfg->ctrlMode == AGC_CTRL_AUTO) {
58162306a36Sopenharmony_ci		if (((cfg->maxOutputLevel) < (cfg->minOutputLevel)) ||
58262306a36Sopenharmony_ci		    ((cfg->maxOutputLevel) > DRXD_FE_CTRL_MAX) ||
58362306a36Sopenharmony_ci		    ((cfg->speed) > DRXD_FE_CTRL_MAX) ||
58462306a36Sopenharmony_ci		    ((cfg->settleLevel) > DRXD_FE_CTRL_MAX)
58562306a36Sopenharmony_ci		    )
58662306a36Sopenharmony_ci			return -1;
58762306a36Sopenharmony_ci		do {
58862306a36Sopenharmony_ci			u16 FeAgRegAgModeLop;
58962306a36Sopenharmony_ci			u16 FeAgRegEgcSetLvl;
59062306a36Sopenharmony_ci			u16 slope, offset;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci			/* == Mode == */
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci			status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &FeAgRegAgModeLop, 0);
59562306a36Sopenharmony_ci			if (status < 0)
59662306a36Sopenharmony_ci				break;
59762306a36Sopenharmony_ci			FeAgRegAgModeLop &= (~FE_AG_REG_AG_MODE_LOP_MODE_4__M);
59862306a36Sopenharmony_ci			FeAgRegAgModeLop |=
59962306a36Sopenharmony_ci			    FE_AG_REG_AG_MODE_LOP_MODE_4_DYNAMIC;
60062306a36Sopenharmony_ci			status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, FeAgRegAgModeLop, 0);
60162306a36Sopenharmony_ci			if (status < 0)
60262306a36Sopenharmony_ci				break;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci			/* == Settle level == */
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci			FeAgRegEgcSetLvl = (u16) ((cfg->settleLevel >> 1) &
60762306a36Sopenharmony_ci						  FE_AG_REG_EGC_SET_LVL__M);
60862306a36Sopenharmony_ci			status = Write16(state, FE_AG_REG_EGC_SET_LVL__A, FeAgRegEgcSetLvl, 0);
60962306a36Sopenharmony_ci			if (status < 0)
61062306a36Sopenharmony_ci				break;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci			/* == Min/Max == */
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci			slope = (u16) ((cfg->maxOutputLevel -
61562306a36Sopenharmony_ci					cfg->minOutputLevel) / 2);
61662306a36Sopenharmony_ci			offset = (u16) ((cfg->maxOutputLevel +
61762306a36Sopenharmony_ci					 cfg->minOutputLevel) / 2 - 511);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci			status = Write16(state, FE_AG_REG_GC1_AGC_RIC__A, slope, 0);
62062306a36Sopenharmony_ci			if (status < 0)
62162306a36Sopenharmony_ci				break;
62262306a36Sopenharmony_ci			status = Write16(state, FE_AG_REG_GC1_AGC_OFF__A, offset, 0);
62362306a36Sopenharmony_ci			if (status < 0)
62462306a36Sopenharmony_ci				break;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci			/* == Speed == */
62762306a36Sopenharmony_ci			{
62862306a36Sopenharmony_ci				const u16 maxRur = 8;
62962306a36Sopenharmony_ci				static const u16 slowIncrDecLUT[] = {
63062306a36Sopenharmony_ci					3, 4, 4, 5, 6 };
63162306a36Sopenharmony_ci				static const u16 fastIncrDecLUT[] = {
63262306a36Sopenharmony_ci					14, 15, 15, 16,
63362306a36Sopenharmony_ci					17, 18, 18, 19,
63462306a36Sopenharmony_ci					20, 21, 22, 23,
63562306a36Sopenharmony_ci					24, 26, 27, 28,
63662306a36Sopenharmony_ci					29, 31
63762306a36Sopenharmony_ci				};
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci				u16 fineSteps = (DRXD_FE_CTRL_MAX + 1) /
64062306a36Sopenharmony_ci				    (maxRur + 1);
64162306a36Sopenharmony_ci				u16 fineSpeed = (u16) (cfg->speed -
64262306a36Sopenharmony_ci						       ((cfg->speed /
64362306a36Sopenharmony_ci							 fineSteps) *
64462306a36Sopenharmony_ci							fineSteps));
64562306a36Sopenharmony_ci				u16 invRurCount = (u16) (cfg->speed /
64662306a36Sopenharmony_ci							 fineSteps);
64762306a36Sopenharmony_ci				u16 rurCount;
64862306a36Sopenharmony_ci				if (invRurCount > maxRur) {
64962306a36Sopenharmony_ci					rurCount = 0;
65062306a36Sopenharmony_ci					fineSpeed += fineSteps;
65162306a36Sopenharmony_ci				} else {
65262306a36Sopenharmony_ci					rurCount = maxRur - invRurCount;
65362306a36Sopenharmony_ci				}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci				/*
65662306a36Sopenharmony_ci				   fastInc = default *
65762306a36Sopenharmony_ci				   (2^(fineSpeed/fineSteps))
65862306a36Sopenharmony_ci				   => range[default...2*default>
65962306a36Sopenharmony_ci				   slowInc = default *
66062306a36Sopenharmony_ci				   (2^(fineSpeed/fineSteps))
66162306a36Sopenharmony_ci				 */
66262306a36Sopenharmony_ci				{
66362306a36Sopenharmony_ci					u16 fastIncrDec =
66462306a36Sopenharmony_ci					    fastIncrDecLUT[fineSpeed /
66562306a36Sopenharmony_ci							   ((fineSteps /
66662306a36Sopenharmony_ci							     (14 + 1)) + 1)];
66762306a36Sopenharmony_ci					u16 slowIncrDec =
66862306a36Sopenharmony_ci					    slowIncrDecLUT[fineSpeed /
66962306a36Sopenharmony_ci							   (fineSteps /
67062306a36Sopenharmony_ci							    (3 + 1))];
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci					status = Write16(state, FE_AG_REG_EGC_RUR_CNT__A, rurCount, 0);
67362306a36Sopenharmony_ci					if (status < 0)
67462306a36Sopenharmony_ci						break;
67562306a36Sopenharmony_ci					status = Write16(state, FE_AG_REG_EGC_FAS_INC__A, fastIncrDec, 0);
67662306a36Sopenharmony_ci					if (status < 0)
67762306a36Sopenharmony_ci						break;
67862306a36Sopenharmony_ci					status = Write16(state, FE_AG_REG_EGC_FAS_DEC__A, fastIncrDec, 0);
67962306a36Sopenharmony_ci					if (status < 0)
68062306a36Sopenharmony_ci						break;
68162306a36Sopenharmony_ci					status = Write16(state, FE_AG_REG_EGC_SLO_INC__A, slowIncrDec, 0);
68262306a36Sopenharmony_ci					if (status < 0)
68362306a36Sopenharmony_ci						break;
68462306a36Sopenharmony_ci					status = Write16(state, FE_AG_REG_EGC_SLO_DEC__A, slowIncrDec, 0);
68562306a36Sopenharmony_ci					if (status < 0)
68662306a36Sopenharmony_ci						break;
68762306a36Sopenharmony_ci				}
68862306a36Sopenharmony_ci			}
68962306a36Sopenharmony_ci		} while (0);
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	} else {
69262306a36Sopenharmony_ci		/* No OFF mode for IF control */
69362306a36Sopenharmony_ci		return -1;
69462306a36Sopenharmony_ci	}
69562306a36Sopenharmony_ci	return status;
69662306a36Sopenharmony_ci}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_cistatic int SetCfgRfAgc(struct drxd_state *state, struct SCfgAgc *cfg)
69962306a36Sopenharmony_ci{
70062306a36Sopenharmony_ci	int status = 0;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	if (cfg->outputLevel > DRXD_FE_CTRL_MAX)
70362306a36Sopenharmony_ci		return -1;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	if (cfg->ctrlMode == AGC_CTRL_USER) {
70662306a36Sopenharmony_ci		do {
70762306a36Sopenharmony_ci			u16 AgModeLop = 0;
70862306a36Sopenharmony_ci			u16 level = (cfg->outputLevel);
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci			if (level == DRXD_FE_CTRL_MAX)
71162306a36Sopenharmony_ci				level++;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci			status = Write16(state, FE_AG_REG_PM2_AGC_WRI__A, level, 0x0000);
71462306a36Sopenharmony_ci			if (status < 0)
71562306a36Sopenharmony_ci				break;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci			/*==== Mode ====*/
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci			/* Powerdown PD2, WRI source */
72062306a36Sopenharmony_ci			state->m_FeAgRegAgPwd &= ~(FE_AG_REG_AG_PWD_PWD_PD2__M);
72162306a36Sopenharmony_ci			state->m_FeAgRegAgPwd |=
72262306a36Sopenharmony_ci			    FE_AG_REG_AG_PWD_PWD_PD2_DISABLE;
72362306a36Sopenharmony_ci			status = Write16(state, FE_AG_REG_AG_PWD__A, state->m_FeAgRegAgPwd, 0x0000);
72462306a36Sopenharmony_ci			if (status < 0)
72562306a36Sopenharmony_ci				break;
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci			status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
72862306a36Sopenharmony_ci			if (status < 0)
72962306a36Sopenharmony_ci				break;
73062306a36Sopenharmony_ci			AgModeLop &= (~(FE_AG_REG_AG_MODE_LOP_MODE_5__M |
73162306a36Sopenharmony_ci					FE_AG_REG_AG_MODE_LOP_MODE_E__M));
73262306a36Sopenharmony_ci			AgModeLop |= (FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC |
73362306a36Sopenharmony_ci				      FE_AG_REG_AG_MODE_LOP_MODE_E_STATIC);
73462306a36Sopenharmony_ci			status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
73562306a36Sopenharmony_ci			if (status < 0)
73662306a36Sopenharmony_ci				break;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci			/* enable AGC2 pin */
73962306a36Sopenharmony_ci			{
74062306a36Sopenharmony_ci				u16 FeAgRegAgAgcSio = 0;
74162306a36Sopenharmony_ci				status = Read16(state, FE_AG_REG_AG_AGC_SIO__A, &FeAgRegAgAgcSio, 0x0000);
74262306a36Sopenharmony_ci				if (status < 0)
74362306a36Sopenharmony_ci					break;
74462306a36Sopenharmony_ci				FeAgRegAgAgcSio &=
74562306a36Sopenharmony_ci				    ~(FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M);
74662306a36Sopenharmony_ci				FeAgRegAgAgcSio |=
74762306a36Sopenharmony_ci				    FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_OUTPUT;
74862306a36Sopenharmony_ci				status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, FeAgRegAgAgcSio, 0x0000);
74962306a36Sopenharmony_ci				if (status < 0)
75062306a36Sopenharmony_ci					break;
75162306a36Sopenharmony_ci			}
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci		} while (0);
75462306a36Sopenharmony_ci	} else if (cfg->ctrlMode == AGC_CTRL_AUTO) {
75562306a36Sopenharmony_ci		u16 AgModeLop = 0;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci		do {
75862306a36Sopenharmony_ci			u16 level;
75962306a36Sopenharmony_ci			/* Automatic control */
76062306a36Sopenharmony_ci			/* Powerup PD2, AGC2 as output, TGC source */
76162306a36Sopenharmony_ci			(state->m_FeAgRegAgPwd) &=
76262306a36Sopenharmony_ci			    ~(FE_AG_REG_AG_PWD_PWD_PD2__M);
76362306a36Sopenharmony_ci			(state->m_FeAgRegAgPwd) |=
76462306a36Sopenharmony_ci			    FE_AG_REG_AG_PWD_PWD_PD2_DISABLE;
76562306a36Sopenharmony_ci			status = Write16(state, FE_AG_REG_AG_PWD__A, (state->m_FeAgRegAgPwd), 0x0000);
76662306a36Sopenharmony_ci			if (status < 0)
76762306a36Sopenharmony_ci				break;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci			status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
77062306a36Sopenharmony_ci			if (status < 0)
77162306a36Sopenharmony_ci				break;
77262306a36Sopenharmony_ci			AgModeLop &= (~(FE_AG_REG_AG_MODE_LOP_MODE_5__M |
77362306a36Sopenharmony_ci					FE_AG_REG_AG_MODE_LOP_MODE_E__M));
77462306a36Sopenharmony_ci			AgModeLop |= (FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC |
77562306a36Sopenharmony_ci				      FE_AG_REG_AG_MODE_LOP_MODE_E_DYNAMIC);
77662306a36Sopenharmony_ci			status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
77762306a36Sopenharmony_ci			if (status < 0)
77862306a36Sopenharmony_ci				break;
77962306a36Sopenharmony_ci			/* Settle level */
78062306a36Sopenharmony_ci			level = (((cfg->settleLevel) >> 4) &
78162306a36Sopenharmony_ci				 FE_AG_REG_TGC_SET_LVL__M);
78262306a36Sopenharmony_ci			status = Write16(state, FE_AG_REG_TGC_SET_LVL__A, level, 0x0000);
78362306a36Sopenharmony_ci			if (status < 0)
78462306a36Sopenharmony_ci				break;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci			/* Min/max: don't care */
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci			/* Speed: TODO */
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci			/* enable AGC2 pin */
79162306a36Sopenharmony_ci			{
79262306a36Sopenharmony_ci				u16 FeAgRegAgAgcSio = 0;
79362306a36Sopenharmony_ci				status = Read16(state, FE_AG_REG_AG_AGC_SIO__A, &FeAgRegAgAgcSio, 0x0000);
79462306a36Sopenharmony_ci				if (status < 0)
79562306a36Sopenharmony_ci					break;
79662306a36Sopenharmony_ci				FeAgRegAgAgcSio &=
79762306a36Sopenharmony_ci				    ~(FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M);
79862306a36Sopenharmony_ci				FeAgRegAgAgcSio |=
79962306a36Sopenharmony_ci				    FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_OUTPUT;
80062306a36Sopenharmony_ci				status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, FeAgRegAgAgcSio, 0x0000);
80162306a36Sopenharmony_ci				if (status < 0)
80262306a36Sopenharmony_ci					break;
80362306a36Sopenharmony_ci			}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci		} while (0);
80662306a36Sopenharmony_ci	} else {
80762306a36Sopenharmony_ci		u16 AgModeLop = 0;
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci		do {
81062306a36Sopenharmony_ci			/* No RF AGC control */
81162306a36Sopenharmony_ci			/* Powerdown PD2, AGC2 as output, WRI source */
81262306a36Sopenharmony_ci			(state->m_FeAgRegAgPwd) &=
81362306a36Sopenharmony_ci			    ~(FE_AG_REG_AG_PWD_PWD_PD2__M);
81462306a36Sopenharmony_ci			(state->m_FeAgRegAgPwd) |=
81562306a36Sopenharmony_ci			    FE_AG_REG_AG_PWD_PWD_PD2_ENABLE;
81662306a36Sopenharmony_ci			status = Write16(state, FE_AG_REG_AG_PWD__A, (state->m_FeAgRegAgPwd), 0x0000);
81762306a36Sopenharmony_ci			if (status < 0)
81862306a36Sopenharmony_ci				break;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci			status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
82162306a36Sopenharmony_ci			if (status < 0)
82262306a36Sopenharmony_ci				break;
82362306a36Sopenharmony_ci			AgModeLop &= (~(FE_AG_REG_AG_MODE_LOP_MODE_5__M |
82462306a36Sopenharmony_ci					FE_AG_REG_AG_MODE_LOP_MODE_E__M));
82562306a36Sopenharmony_ci			AgModeLop |= (FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC |
82662306a36Sopenharmony_ci				      FE_AG_REG_AG_MODE_LOP_MODE_E_STATIC);
82762306a36Sopenharmony_ci			status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
82862306a36Sopenharmony_ci			if (status < 0)
82962306a36Sopenharmony_ci				break;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci			/* set FeAgRegAgAgcSio AGC2 (RF) as input */
83262306a36Sopenharmony_ci			{
83362306a36Sopenharmony_ci				u16 FeAgRegAgAgcSio = 0;
83462306a36Sopenharmony_ci				status = Read16(state, FE_AG_REG_AG_AGC_SIO__A, &FeAgRegAgAgcSio, 0x0000);
83562306a36Sopenharmony_ci				if (status < 0)
83662306a36Sopenharmony_ci					break;
83762306a36Sopenharmony_ci				FeAgRegAgAgcSio &=
83862306a36Sopenharmony_ci				    ~(FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M);
83962306a36Sopenharmony_ci				FeAgRegAgAgcSio |=
84062306a36Sopenharmony_ci				    FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_INPUT;
84162306a36Sopenharmony_ci				status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, FeAgRegAgAgcSio, 0x0000);
84262306a36Sopenharmony_ci				if (status < 0)
84362306a36Sopenharmony_ci					break;
84462306a36Sopenharmony_ci			}
84562306a36Sopenharmony_ci		} while (0);
84662306a36Sopenharmony_ci	}
84762306a36Sopenharmony_ci	return status;
84862306a36Sopenharmony_ci}
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_cistatic int ReadIFAgc(struct drxd_state *state, u32 * pValue)
85162306a36Sopenharmony_ci{
85262306a36Sopenharmony_ci	int status = 0;
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	*pValue = 0;
85562306a36Sopenharmony_ci	if (state->if_agc_cfg.ctrlMode != AGC_CTRL_OFF) {
85662306a36Sopenharmony_ci		u16 Value;
85762306a36Sopenharmony_ci		status = Read16(state, FE_AG_REG_GC1_AGC_DAT__A, &Value, 0);
85862306a36Sopenharmony_ci		Value &= FE_AG_REG_GC1_AGC_DAT__M;
85962306a36Sopenharmony_ci		if (status >= 0) {
86062306a36Sopenharmony_ci			/*           3.3V
86162306a36Sopenharmony_ci			   |
86262306a36Sopenharmony_ci			   R1
86362306a36Sopenharmony_ci			   |
86462306a36Sopenharmony_ci			   Vin - R3 - * -- Vout
86562306a36Sopenharmony_ci			   |
86662306a36Sopenharmony_ci			   R2
86762306a36Sopenharmony_ci			   |
86862306a36Sopenharmony_ci			   GND
86962306a36Sopenharmony_ci			 */
87062306a36Sopenharmony_ci			u32 R1 = state->if_agc_cfg.R1;
87162306a36Sopenharmony_ci			u32 R2 = state->if_agc_cfg.R2;
87262306a36Sopenharmony_ci			u32 R3 = state->if_agc_cfg.R3;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci			u32 Vmax, Rpar, Vmin, Vout;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci			if (R2 == 0 && (R1 == 0 || R3 == 0))
87762306a36Sopenharmony_ci				return 0;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci			Vmax = (3300 * R2) / (R1 + R2);
88062306a36Sopenharmony_ci			Rpar = (R2 * R3) / (R3 + R2);
88162306a36Sopenharmony_ci			Vmin = (3300 * Rpar) / (R1 + Rpar);
88262306a36Sopenharmony_ci			Vout = Vmin + ((Vmax - Vmin) * Value) / 1024;
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci			*pValue = Vout;
88562306a36Sopenharmony_ci		}
88662306a36Sopenharmony_ci	}
88762306a36Sopenharmony_ci	return status;
88862306a36Sopenharmony_ci}
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_cistatic int load_firmware(struct drxd_state *state, const char *fw_name)
89162306a36Sopenharmony_ci{
89262306a36Sopenharmony_ci	const struct firmware *fw;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	if (request_firmware(&fw, fw_name, state->dev) < 0) {
89562306a36Sopenharmony_ci		printk(KERN_ERR "drxd: firmware load failure [%s]\n", fw_name);
89662306a36Sopenharmony_ci		return -EIO;
89762306a36Sopenharmony_ci	}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	state->microcode = kmemdup(fw->data, fw->size, GFP_KERNEL);
90062306a36Sopenharmony_ci	if (!state->microcode) {
90162306a36Sopenharmony_ci		release_firmware(fw);
90262306a36Sopenharmony_ci		return -ENOMEM;
90362306a36Sopenharmony_ci	}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci	state->microcode_length = fw->size;
90662306a36Sopenharmony_ci	release_firmware(fw);
90762306a36Sopenharmony_ci	return 0;
90862306a36Sopenharmony_ci}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_cistatic int DownloadMicrocode(struct drxd_state *state,
91162306a36Sopenharmony_ci			     const u8 *pMCImage, u32 Length)
91262306a36Sopenharmony_ci{
91362306a36Sopenharmony_ci	u8 *pSrc;
91462306a36Sopenharmony_ci	u32 Address;
91562306a36Sopenharmony_ci	u16 nBlocks;
91662306a36Sopenharmony_ci	u16 BlockSize;
91762306a36Sopenharmony_ci	int i, status = 0;
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	pSrc = (u8 *) pMCImage;
92062306a36Sopenharmony_ci	/* We're not using Flags */
92162306a36Sopenharmony_ci	/* Flags = (pSrc[0] << 8) | pSrc[1]; */
92262306a36Sopenharmony_ci	pSrc += sizeof(u16);
92362306a36Sopenharmony_ci	nBlocks = (pSrc[0] << 8) | pSrc[1];
92462306a36Sopenharmony_ci	pSrc += sizeof(u16);
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	for (i = 0; i < nBlocks; i++) {
92762306a36Sopenharmony_ci		Address = (pSrc[0] << 24) | (pSrc[1] << 16) |
92862306a36Sopenharmony_ci		    (pSrc[2] << 8) | pSrc[3];
92962306a36Sopenharmony_ci		pSrc += sizeof(u32);
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci		BlockSize = ((pSrc[0] << 8) | pSrc[1]) * sizeof(u16);
93262306a36Sopenharmony_ci		pSrc += sizeof(u16);
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci		/* We're not using Flags */
93562306a36Sopenharmony_ci		/* u16 Flags = (pSrc[0] << 8) | pSrc[1]; */
93662306a36Sopenharmony_ci		pSrc += sizeof(u16);
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci		/* We're not using BlockCRC */
93962306a36Sopenharmony_ci		/* u16 BlockCRC = (pSrc[0] << 8) | pSrc[1]; */
94062306a36Sopenharmony_ci		pSrc += sizeof(u16);
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci		status = WriteBlock(state, Address, BlockSize,
94362306a36Sopenharmony_ci				    pSrc, DRX_I2C_CLEARCRC);
94462306a36Sopenharmony_ci		if (status < 0)
94562306a36Sopenharmony_ci			break;
94662306a36Sopenharmony_ci		pSrc += BlockSize;
94762306a36Sopenharmony_ci	}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	return status;
95062306a36Sopenharmony_ci}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_cistatic int HI_Command(struct drxd_state *state, u16 cmd, u16 * pResult)
95362306a36Sopenharmony_ci{
95462306a36Sopenharmony_ci	u32 nrRetries = 0;
95562306a36Sopenharmony_ci	int status;
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	status = Write16(state, HI_RA_RAM_SRV_CMD__A, cmd, 0);
95862306a36Sopenharmony_ci	if (status < 0)
95962306a36Sopenharmony_ci		return status;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	do {
96262306a36Sopenharmony_ci		nrRetries += 1;
96362306a36Sopenharmony_ci		if (nrRetries > DRXD_MAX_RETRIES) {
96462306a36Sopenharmony_ci			status = -1;
96562306a36Sopenharmony_ci			break;
96662306a36Sopenharmony_ci		}
96762306a36Sopenharmony_ci		status = Read16(state, HI_RA_RAM_SRV_CMD__A, NULL, 0);
96862306a36Sopenharmony_ci	} while (status != 0);
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	if (status >= 0)
97162306a36Sopenharmony_ci		status = Read16(state, HI_RA_RAM_SRV_RES__A, pResult, 0);
97262306a36Sopenharmony_ci	return status;
97362306a36Sopenharmony_ci}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_cistatic int HI_CfgCommand(struct drxd_state *state)
97662306a36Sopenharmony_ci{
97762306a36Sopenharmony_ci	int status = 0;
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	mutex_lock(&state->mutex);
98062306a36Sopenharmony_ci	Write16(state, HI_RA_RAM_SRV_CFG_KEY__A, HI_RA_RAM_SRV_RST_KEY_ACT, 0);
98162306a36Sopenharmony_ci	Write16(state, HI_RA_RAM_SRV_CFG_DIV__A, state->hi_cfg_timing_div, 0);
98262306a36Sopenharmony_ci	Write16(state, HI_RA_RAM_SRV_CFG_BDL__A, state->hi_cfg_bridge_delay, 0);
98362306a36Sopenharmony_ci	Write16(state, HI_RA_RAM_SRV_CFG_WUP__A, state->hi_cfg_wakeup_key, 0);
98462306a36Sopenharmony_ci	Write16(state, HI_RA_RAM_SRV_CFG_ACT__A, state->hi_cfg_ctrl, 0);
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	Write16(state, HI_RA_RAM_SRV_CFG_KEY__A, HI_RA_RAM_SRV_RST_KEY_ACT, 0);
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	if ((state->hi_cfg_ctrl & HI_RA_RAM_SRV_CFG_ACT_PWD_EXE) ==
98962306a36Sopenharmony_ci	    HI_RA_RAM_SRV_CFG_ACT_PWD_EXE)
99062306a36Sopenharmony_ci		status = Write16(state, HI_RA_RAM_SRV_CMD__A,
99162306a36Sopenharmony_ci				 HI_RA_RAM_SRV_CMD_CONFIG, 0);
99262306a36Sopenharmony_ci	else
99362306a36Sopenharmony_ci		status = HI_Command(state, HI_RA_RAM_SRV_CMD_CONFIG, NULL);
99462306a36Sopenharmony_ci	mutex_unlock(&state->mutex);
99562306a36Sopenharmony_ci	return status;
99662306a36Sopenharmony_ci}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_cistatic int InitHI(struct drxd_state *state)
99962306a36Sopenharmony_ci{
100062306a36Sopenharmony_ci	state->hi_cfg_wakeup_key = (state->chip_adr);
100162306a36Sopenharmony_ci	/* port/bridge/power down ctrl */
100262306a36Sopenharmony_ci	state->hi_cfg_ctrl = HI_RA_RAM_SRV_CFG_ACT_SLV0_ON;
100362306a36Sopenharmony_ci	return HI_CfgCommand(state);
100462306a36Sopenharmony_ci}
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_cistatic int HI_ResetCommand(struct drxd_state *state)
100762306a36Sopenharmony_ci{
100862306a36Sopenharmony_ci	int status;
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	mutex_lock(&state->mutex);
101162306a36Sopenharmony_ci	status = Write16(state, HI_RA_RAM_SRV_RST_KEY__A,
101262306a36Sopenharmony_ci			 HI_RA_RAM_SRV_RST_KEY_ACT, 0);
101362306a36Sopenharmony_ci	if (status == 0)
101462306a36Sopenharmony_ci		status = HI_Command(state, HI_RA_RAM_SRV_CMD_RESET, NULL);
101562306a36Sopenharmony_ci	mutex_unlock(&state->mutex);
101662306a36Sopenharmony_ci	msleep(1);
101762306a36Sopenharmony_ci	return status;
101862306a36Sopenharmony_ci}
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_cistatic int DRX_ConfigureI2CBridge(struct drxd_state *state, int bEnableBridge)
102162306a36Sopenharmony_ci{
102262306a36Sopenharmony_ci	state->hi_cfg_ctrl &= (~HI_RA_RAM_SRV_CFG_ACT_BRD__M);
102362306a36Sopenharmony_ci	if (bEnableBridge)
102462306a36Sopenharmony_ci		state->hi_cfg_ctrl |= HI_RA_RAM_SRV_CFG_ACT_BRD_ON;
102562306a36Sopenharmony_ci	else
102662306a36Sopenharmony_ci		state->hi_cfg_ctrl |= HI_RA_RAM_SRV_CFG_ACT_BRD_OFF;
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	return HI_CfgCommand(state);
102962306a36Sopenharmony_ci}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci#define HI_TR_WRITE      0x9
103262306a36Sopenharmony_ci#define HI_TR_READ       0xA
103362306a36Sopenharmony_ci#define HI_TR_READ_WRITE 0xB
103462306a36Sopenharmony_ci#define HI_TR_BROADCAST  0x4
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci#if 0
103762306a36Sopenharmony_cistatic int AtomicReadBlock(struct drxd_state *state,
103862306a36Sopenharmony_ci			   u32 Addr, u16 DataSize, u8 *pData, u8 Flags)
103962306a36Sopenharmony_ci{
104062306a36Sopenharmony_ci	int status;
104162306a36Sopenharmony_ci	int i = 0;
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	/* Parameter check */
104462306a36Sopenharmony_ci	if ((!pData) || ((DataSize & 1) != 0))
104562306a36Sopenharmony_ci		return -1;
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci	mutex_lock(&state->mutex);
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	do {
105062306a36Sopenharmony_ci		/* Instruct HI to read n bytes */
105162306a36Sopenharmony_ci		/* TODO use proper names forthese egisters */
105262306a36Sopenharmony_ci		status = Write16(state, HI_RA_RAM_SRV_CFG_KEY__A, (HI_TR_FUNC_ADDR & 0xFFFF), 0);
105362306a36Sopenharmony_ci		if (status < 0)
105462306a36Sopenharmony_ci			break;
105562306a36Sopenharmony_ci		status = Write16(state, HI_RA_RAM_SRV_CFG_DIV__A, (u16) (Addr >> 16), 0);
105662306a36Sopenharmony_ci		if (status < 0)
105762306a36Sopenharmony_ci			break;
105862306a36Sopenharmony_ci		status = Write16(state, HI_RA_RAM_SRV_CFG_BDL__A, (u16) (Addr & 0xFFFF), 0);
105962306a36Sopenharmony_ci		if (status < 0)
106062306a36Sopenharmony_ci			break;
106162306a36Sopenharmony_ci		status = Write16(state, HI_RA_RAM_SRV_CFG_WUP__A, (u16) ((DataSize / 2) - 1), 0);
106262306a36Sopenharmony_ci		if (status < 0)
106362306a36Sopenharmony_ci			break;
106462306a36Sopenharmony_ci		status = Write16(state, HI_RA_RAM_SRV_CFG_ACT__A, HI_TR_READ, 0);
106562306a36Sopenharmony_ci		if (status < 0)
106662306a36Sopenharmony_ci			break;
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci		status = HI_Command(state, HI_RA_RAM_SRV_CMD_EXECUTE, 0);
106962306a36Sopenharmony_ci		if (status < 0)
107062306a36Sopenharmony_ci			break;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	} while (0);
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	if (status >= 0) {
107562306a36Sopenharmony_ci		for (i = 0; i < (DataSize / 2); i += 1) {
107662306a36Sopenharmony_ci			u16 word;
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci			status = Read16(state, (HI_RA_RAM_USR_BEGIN__A + i),
107962306a36Sopenharmony_ci					&word, 0);
108062306a36Sopenharmony_ci			if (status < 0)
108162306a36Sopenharmony_ci				break;
108262306a36Sopenharmony_ci			pData[2 * i] = (u8) (word & 0xFF);
108362306a36Sopenharmony_ci			pData[(2 * i) + 1] = (u8) (word >> 8);
108462306a36Sopenharmony_ci		}
108562306a36Sopenharmony_ci	}
108662306a36Sopenharmony_ci	mutex_unlock(&state->mutex);
108762306a36Sopenharmony_ci	return status;
108862306a36Sopenharmony_ci}
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_cistatic int AtomicReadReg32(struct drxd_state *state,
109162306a36Sopenharmony_ci			   u32 Addr, u32 *pData, u8 Flags)
109262306a36Sopenharmony_ci{
109362306a36Sopenharmony_ci	u8 buf[sizeof(u32)];
109462306a36Sopenharmony_ci	int status;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	if (!pData)
109762306a36Sopenharmony_ci		return -1;
109862306a36Sopenharmony_ci	status = AtomicReadBlock(state, Addr, sizeof(u32), buf, Flags);
109962306a36Sopenharmony_ci	*pData = (((u32) buf[0]) << 0) +
110062306a36Sopenharmony_ci	    (((u32) buf[1]) << 8) +
110162306a36Sopenharmony_ci	    (((u32) buf[2]) << 16) + (((u32) buf[3]) << 24);
110262306a36Sopenharmony_ci	return status;
110362306a36Sopenharmony_ci}
110462306a36Sopenharmony_ci#endif
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_cistatic int StopAllProcessors(struct drxd_state *state)
110762306a36Sopenharmony_ci{
110862306a36Sopenharmony_ci	return Write16(state, HI_COMM_EXEC__A,
110962306a36Sopenharmony_ci		       SC_COMM_EXEC_CTL_STOP, DRX_I2C_BROADCAST);
111062306a36Sopenharmony_ci}
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_cistatic int EnableAndResetMB(struct drxd_state *state)
111362306a36Sopenharmony_ci{
111462306a36Sopenharmony_ci	if (state->type_A) {
111562306a36Sopenharmony_ci		/* disable? monitor bus observe @ EC_OC */
111662306a36Sopenharmony_ci		Write16(state, EC_OC_REG_OC_MON_SIO__A, 0x0000, 0x0000);
111762306a36Sopenharmony_ci	}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	/* do inverse broadcast, followed by explicit write to HI */
112062306a36Sopenharmony_ci	Write16(state, HI_COMM_MB__A, 0x0000, DRX_I2C_BROADCAST);
112162306a36Sopenharmony_ci	Write16(state, HI_COMM_MB__A, 0x0000, 0x0000);
112262306a36Sopenharmony_ci	return 0;
112362306a36Sopenharmony_ci}
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_cistatic int InitCC(struct drxd_state *state)
112662306a36Sopenharmony_ci{
112762306a36Sopenharmony_ci	int status = 0;
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	if (state->osc_clock_freq == 0 ||
113062306a36Sopenharmony_ci	    state->osc_clock_freq > 20000 ||
113162306a36Sopenharmony_ci	    (state->osc_clock_freq % 4000) != 0) {
113262306a36Sopenharmony_ci		printk(KERN_ERR "invalid osc frequency %d\n", state->osc_clock_freq);
113362306a36Sopenharmony_ci		return -1;
113462306a36Sopenharmony_ci	}
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	status |= Write16(state, CC_REG_OSC_MODE__A, CC_REG_OSC_MODE_M20, 0);
113762306a36Sopenharmony_ci	status |= Write16(state, CC_REG_PLL_MODE__A,
113862306a36Sopenharmony_ci				CC_REG_PLL_MODE_BYPASS_PLL |
113962306a36Sopenharmony_ci				CC_REG_PLL_MODE_PUMP_CUR_12, 0);
114062306a36Sopenharmony_ci	status |= Write16(state, CC_REG_REF_DIVIDE__A,
114162306a36Sopenharmony_ci				state->osc_clock_freq / 4000, 0);
114262306a36Sopenharmony_ci	status |= Write16(state, CC_REG_PWD_MODE__A, CC_REG_PWD_MODE_DOWN_PLL,
114362306a36Sopenharmony_ci				0);
114462306a36Sopenharmony_ci	status |= Write16(state, CC_REG_UPDATE__A, CC_REG_UPDATE_KEY, 0);
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	return status;
114762306a36Sopenharmony_ci}
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_cistatic int ResetECOD(struct drxd_state *state)
115062306a36Sopenharmony_ci{
115162306a36Sopenharmony_ci	int status = 0;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	if (state->type_A)
115462306a36Sopenharmony_ci		status = Write16(state, EC_OD_REG_SYNC__A, 0x0664, 0);
115562306a36Sopenharmony_ci	else
115662306a36Sopenharmony_ci		status = Write16(state, B_EC_OD_REG_SYNC__A, 0x0664, 0);
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	if (!(status < 0))
115962306a36Sopenharmony_ci		status = WriteTable(state, state->m_ResetECRAM);
116062306a36Sopenharmony_ci	if (!(status < 0))
116162306a36Sopenharmony_ci		status = Write16(state, EC_OD_REG_COMM_EXEC__A, 0x0001, 0);
116262306a36Sopenharmony_ci	return status;
116362306a36Sopenharmony_ci}
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci/* Configure PGA switch */
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_cistatic int SetCfgPga(struct drxd_state *state, int pgaSwitch)
116862306a36Sopenharmony_ci{
116962306a36Sopenharmony_ci	int status;
117062306a36Sopenharmony_ci	u16 AgModeLop = 0;
117162306a36Sopenharmony_ci	u16 AgModeHip = 0;
117262306a36Sopenharmony_ci	do {
117362306a36Sopenharmony_ci		if (pgaSwitch) {
117462306a36Sopenharmony_ci			/* PGA on */
117562306a36Sopenharmony_ci			/* fine gain */
117662306a36Sopenharmony_ci			status = Read16(state, B_FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
117762306a36Sopenharmony_ci			if (status < 0)
117862306a36Sopenharmony_ci				break;
117962306a36Sopenharmony_ci			AgModeLop &= (~(B_FE_AG_REG_AG_MODE_LOP_MODE_C__M));
118062306a36Sopenharmony_ci			AgModeLop |= B_FE_AG_REG_AG_MODE_LOP_MODE_C_DYNAMIC;
118162306a36Sopenharmony_ci			status = Write16(state, B_FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
118262306a36Sopenharmony_ci			if (status < 0)
118362306a36Sopenharmony_ci				break;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci			/* coarse gain */
118662306a36Sopenharmony_ci			status = Read16(state, B_FE_AG_REG_AG_MODE_HIP__A, &AgModeHip, 0x0000);
118762306a36Sopenharmony_ci			if (status < 0)
118862306a36Sopenharmony_ci				break;
118962306a36Sopenharmony_ci			AgModeHip &= (~(B_FE_AG_REG_AG_MODE_HIP_MODE_J__M));
119062306a36Sopenharmony_ci			AgModeHip |= B_FE_AG_REG_AG_MODE_HIP_MODE_J_DYNAMIC;
119162306a36Sopenharmony_ci			status = Write16(state, B_FE_AG_REG_AG_MODE_HIP__A, AgModeHip, 0x0000);
119262306a36Sopenharmony_ci			if (status < 0)
119362306a36Sopenharmony_ci				break;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci			/* enable fine and coarse gain, enable AAF,
119662306a36Sopenharmony_ci			   no ext resistor */
119762306a36Sopenharmony_ci			status = Write16(state, B_FE_AG_REG_AG_PGA_MODE__A, B_FE_AG_REG_AG_PGA_MODE_PFY_PCY_AFY_REN, 0x0000);
119862306a36Sopenharmony_ci			if (status < 0)
119962306a36Sopenharmony_ci				break;
120062306a36Sopenharmony_ci		} else {
120162306a36Sopenharmony_ci			/* PGA off, bypass */
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci			/* fine gain */
120462306a36Sopenharmony_ci			status = Read16(state, B_FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
120562306a36Sopenharmony_ci			if (status < 0)
120662306a36Sopenharmony_ci				break;
120762306a36Sopenharmony_ci			AgModeLop &= (~(B_FE_AG_REG_AG_MODE_LOP_MODE_C__M));
120862306a36Sopenharmony_ci			AgModeLop |= B_FE_AG_REG_AG_MODE_LOP_MODE_C_STATIC;
120962306a36Sopenharmony_ci			status = Write16(state, B_FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
121062306a36Sopenharmony_ci			if (status < 0)
121162306a36Sopenharmony_ci				break;
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci			/* coarse gain */
121462306a36Sopenharmony_ci			status = Read16(state, B_FE_AG_REG_AG_MODE_HIP__A, &AgModeHip, 0x0000);
121562306a36Sopenharmony_ci			if (status < 0)
121662306a36Sopenharmony_ci				break;
121762306a36Sopenharmony_ci			AgModeHip &= (~(B_FE_AG_REG_AG_MODE_HIP_MODE_J__M));
121862306a36Sopenharmony_ci			AgModeHip |= B_FE_AG_REG_AG_MODE_HIP_MODE_J_STATIC;
121962306a36Sopenharmony_ci			status = Write16(state, B_FE_AG_REG_AG_MODE_HIP__A, AgModeHip, 0x0000);
122062306a36Sopenharmony_ci			if (status < 0)
122162306a36Sopenharmony_ci				break;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci			/* disable fine and coarse gain, enable AAF,
122462306a36Sopenharmony_ci			   no ext resistor */
122562306a36Sopenharmony_ci			status = Write16(state, B_FE_AG_REG_AG_PGA_MODE__A, B_FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN, 0x0000);
122662306a36Sopenharmony_ci			if (status < 0)
122762306a36Sopenharmony_ci				break;
122862306a36Sopenharmony_ci		}
122962306a36Sopenharmony_ci	} while (0);
123062306a36Sopenharmony_ci	return status;
123162306a36Sopenharmony_ci}
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_cistatic int InitFE(struct drxd_state *state)
123462306a36Sopenharmony_ci{
123562306a36Sopenharmony_ci	int status;
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	do {
123862306a36Sopenharmony_ci		status = WriteTable(state, state->m_InitFE_1);
123962306a36Sopenharmony_ci		if (status < 0)
124062306a36Sopenharmony_ci			break;
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci		if (state->type_A) {
124362306a36Sopenharmony_ci			status = Write16(state, FE_AG_REG_AG_PGA_MODE__A,
124462306a36Sopenharmony_ci					 FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN,
124562306a36Sopenharmony_ci					 0);
124662306a36Sopenharmony_ci		} else {
124762306a36Sopenharmony_ci			if (state->PGA)
124862306a36Sopenharmony_ci				status = SetCfgPga(state, 0);
124962306a36Sopenharmony_ci			else
125062306a36Sopenharmony_ci				status =
125162306a36Sopenharmony_ci				    Write16(state, B_FE_AG_REG_AG_PGA_MODE__A,
125262306a36Sopenharmony_ci					    B_FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN,
125362306a36Sopenharmony_ci					    0);
125462306a36Sopenharmony_ci		}
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci		if (status < 0)
125762306a36Sopenharmony_ci			break;
125862306a36Sopenharmony_ci		status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, state->m_FeAgRegAgAgcSio, 0x0000);
125962306a36Sopenharmony_ci		if (status < 0)
126062306a36Sopenharmony_ci			break;
126162306a36Sopenharmony_ci		status = Write16(state, FE_AG_REG_AG_PWD__A, state->m_FeAgRegAgPwd, 0x0000);
126262306a36Sopenharmony_ci		if (status < 0)
126362306a36Sopenharmony_ci			break;
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci		status = WriteTable(state, state->m_InitFE_2);
126662306a36Sopenharmony_ci		if (status < 0)
126762306a36Sopenharmony_ci			break;
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	} while (0);
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	return status;
127262306a36Sopenharmony_ci}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_cistatic int InitFT(struct drxd_state *state)
127562306a36Sopenharmony_ci{
127662306a36Sopenharmony_ci	/*
127762306a36Sopenharmony_ci	   norm OFFSET,  MB says =2 voor 8K en =3 voor 2K waarschijnlijk
127862306a36Sopenharmony_ci	   SC stuff
127962306a36Sopenharmony_ci	 */
128062306a36Sopenharmony_ci	return Write16(state, FT_REG_COMM_EXEC__A, 0x0001, 0x0000);
128162306a36Sopenharmony_ci}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_cistatic int SC_WaitForReady(struct drxd_state *state)
128462306a36Sopenharmony_ci{
128562306a36Sopenharmony_ci	int i;
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	for (i = 0; i < DRXD_MAX_RETRIES; i += 1) {
128862306a36Sopenharmony_ci		int status = Read16(state, SC_RA_RAM_CMD__A, NULL, 0);
128962306a36Sopenharmony_ci		if (status == 0)
129062306a36Sopenharmony_ci			return status;
129162306a36Sopenharmony_ci	}
129262306a36Sopenharmony_ci	return -1;
129362306a36Sopenharmony_ci}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_cistatic int SC_SendCommand(struct drxd_state *state, u16 cmd)
129662306a36Sopenharmony_ci{
129762306a36Sopenharmony_ci	int status = 0, ret;
129862306a36Sopenharmony_ci	u16 errCode;
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	status = Write16(state, SC_RA_RAM_CMD__A, cmd, 0);
130162306a36Sopenharmony_ci	if (status < 0)
130262306a36Sopenharmony_ci		return status;
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	SC_WaitForReady(state);
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	ret = Read16(state, SC_RA_RAM_CMD_ADDR__A, &errCode, 0);
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	if (ret < 0 || errCode == 0xFFFF) {
130962306a36Sopenharmony_ci		printk(KERN_ERR "Command Error\n");
131062306a36Sopenharmony_ci		status = -1;
131162306a36Sopenharmony_ci	}
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	return status;
131462306a36Sopenharmony_ci}
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_cistatic int SC_ProcStartCommand(struct drxd_state *state,
131762306a36Sopenharmony_ci			       u16 subCmd, u16 param0, u16 param1)
131862306a36Sopenharmony_ci{
131962306a36Sopenharmony_ci	int ret, status = 0;
132062306a36Sopenharmony_ci	u16 scExec;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	mutex_lock(&state->mutex);
132362306a36Sopenharmony_ci	do {
132462306a36Sopenharmony_ci		ret = Read16(state, SC_COMM_EXEC__A, &scExec, 0);
132562306a36Sopenharmony_ci		if (ret < 0 || scExec != 1) {
132662306a36Sopenharmony_ci			status = -1;
132762306a36Sopenharmony_ci			break;
132862306a36Sopenharmony_ci		}
132962306a36Sopenharmony_ci		SC_WaitForReady(state);
133062306a36Sopenharmony_ci		status |= Write16(state, SC_RA_RAM_CMD_ADDR__A, subCmd, 0);
133162306a36Sopenharmony_ci		status |= Write16(state, SC_RA_RAM_PARAM1__A, param1, 0);
133262306a36Sopenharmony_ci		status |= Write16(state, SC_RA_RAM_PARAM0__A, param0, 0);
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci		SC_SendCommand(state, SC_RA_RAM_CMD_PROC_START);
133562306a36Sopenharmony_ci	} while (0);
133662306a36Sopenharmony_ci	mutex_unlock(&state->mutex);
133762306a36Sopenharmony_ci	return status;
133862306a36Sopenharmony_ci}
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_cistatic int SC_SetPrefParamCommand(struct drxd_state *state,
134162306a36Sopenharmony_ci				  u16 subCmd, u16 param0, u16 param1)
134262306a36Sopenharmony_ci{
134362306a36Sopenharmony_ci	int status;
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	mutex_lock(&state->mutex);
134662306a36Sopenharmony_ci	do {
134762306a36Sopenharmony_ci		status = SC_WaitForReady(state);
134862306a36Sopenharmony_ci		if (status < 0)
134962306a36Sopenharmony_ci			break;
135062306a36Sopenharmony_ci		status = Write16(state, SC_RA_RAM_CMD_ADDR__A, subCmd, 0);
135162306a36Sopenharmony_ci		if (status < 0)
135262306a36Sopenharmony_ci			break;
135362306a36Sopenharmony_ci		status = Write16(state, SC_RA_RAM_PARAM1__A, param1, 0);
135462306a36Sopenharmony_ci		if (status < 0)
135562306a36Sopenharmony_ci			break;
135662306a36Sopenharmony_ci		status = Write16(state, SC_RA_RAM_PARAM0__A, param0, 0);
135762306a36Sopenharmony_ci		if (status < 0)
135862306a36Sopenharmony_ci			break;
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci		status = SC_SendCommand(state, SC_RA_RAM_CMD_SET_PREF_PARAM);
136162306a36Sopenharmony_ci		if (status < 0)
136262306a36Sopenharmony_ci			break;
136362306a36Sopenharmony_ci	} while (0);
136462306a36Sopenharmony_ci	mutex_unlock(&state->mutex);
136562306a36Sopenharmony_ci	return status;
136662306a36Sopenharmony_ci}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci#if 0
136962306a36Sopenharmony_cistatic int SC_GetOpParamCommand(struct drxd_state *state, u16 * result)
137062306a36Sopenharmony_ci{
137162306a36Sopenharmony_ci	int status = 0;
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	mutex_lock(&state->mutex);
137462306a36Sopenharmony_ci	do {
137562306a36Sopenharmony_ci		status = SC_WaitForReady(state);
137662306a36Sopenharmony_ci		if (status < 0)
137762306a36Sopenharmony_ci			break;
137862306a36Sopenharmony_ci		status = SC_SendCommand(state, SC_RA_RAM_CMD_GET_OP_PARAM);
137962306a36Sopenharmony_ci		if (status < 0)
138062306a36Sopenharmony_ci			break;
138162306a36Sopenharmony_ci		status = Read16(state, SC_RA_RAM_PARAM0__A, result, 0);
138262306a36Sopenharmony_ci		if (status < 0)
138362306a36Sopenharmony_ci			break;
138462306a36Sopenharmony_ci	} while (0);
138562306a36Sopenharmony_ci	mutex_unlock(&state->mutex);
138662306a36Sopenharmony_ci	return status;
138762306a36Sopenharmony_ci}
138862306a36Sopenharmony_ci#endif
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_cistatic int ConfigureMPEGOutput(struct drxd_state *state, int bEnableOutput)
139162306a36Sopenharmony_ci{
139262306a36Sopenharmony_ci	int status;
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	do {
139562306a36Sopenharmony_ci		u16 EcOcRegIprInvMpg = 0;
139662306a36Sopenharmony_ci		u16 EcOcRegOcModeLop = 0;
139762306a36Sopenharmony_ci		u16 EcOcRegOcModeHip = 0;
139862306a36Sopenharmony_ci		u16 EcOcRegOcMpgSio = 0;
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci		/*CHK_ERROR(Read16(state, EC_OC_REG_OC_MODE_LOP__A, &EcOcRegOcModeLop, 0)); */
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci		if (state->operation_mode == OM_DVBT_Diversity_Front) {
140362306a36Sopenharmony_ci			if (bEnableOutput) {
140462306a36Sopenharmony_ci				EcOcRegOcModeHip |=
140562306a36Sopenharmony_ci				    B_EC_OC_REG_OC_MODE_HIP_MPG_BUS_SRC_MONITOR;
140662306a36Sopenharmony_ci			} else
140762306a36Sopenharmony_ci				EcOcRegOcMpgSio |= EC_OC_REG_OC_MPG_SIO__M;
140862306a36Sopenharmony_ci			EcOcRegOcModeLop |=
140962306a36Sopenharmony_ci			    EC_OC_REG_OC_MODE_LOP_PAR_ENA_DISABLE;
141062306a36Sopenharmony_ci		} else {
141162306a36Sopenharmony_ci			EcOcRegOcModeLop = state->m_EcOcRegOcModeLop;
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci			if (bEnableOutput)
141462306a36Sopenharmony_ci				EcOcRegOcMpgSio &= (~(EC_OC_REG_OC_MPG_SIO__M));
141562306a36Sopenharmony_ci			else
141662306a36Sopenharmony_ci				EcOcRegOcMpgSio |= EC_OC_REG_OC_MPG_SIO__M;
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci			/* Don't Insert RS Byte */
141962306a36Sopenharmony_ci			if (state->insert_rs_byte) {
142062306a36Sopenharmony_ci				EcOcRegOcModeLop &=
142162306a36Sopenharmony_ci				    (~(EC_OC_REG_OC_MODE_LOP_PAR_ENA__M));
142262306a36Sopenharmony_ci				EcOcRegOcModeHip &=
142362306a36Sopenharmony_ci				    (~EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL__M);
142462306a36Sopenharmony_ci				EcOcRegOcModeHip |=
142562306a36Sopenharmony_ci				    EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_ENABLE;
142662306a36Sopenharmony_ci			} else {
142762306a36Sopenharmony_ci				EcOcRegOcModeLop |=
142862306a36Sopenharmony_ci				    EC_OC_REG_OC_MODE_LOP_PAR_ENA_DISABLE;
142962306a36Sopenharmony_ci				EcOcRegOcModeHip &=
143062306a36Sopenharmony_ci				    (~EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL__M);
143162306a36Sopenharmony_ci				EcOcRegOcModeHip |=
143262306a36Sopenharmony_ci				    EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_DISABLE;
143362306a36Sopenharmony_ci			}
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci			/* Mode = Parallel */
143662306a36Sopenharmony_ci			if (state->enable_parallel)
143762306a36Sopenharmony_ci				EcOcRegOcModeLop &=
143862306a36Sopenharmony_ci				    (~(EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE__M));
143962306a36Sopenharmony_ci			else
144062306a36Sopenharmony_ci				EcOcRegOcModeLop |=
144162306a36Sopenharmony_ci				    EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE_SERIAL;
144262306a36Sopenharmony_ci		}
144362306a36Sopenharmony_ci		/* Invert Data */
144462306a36Sopenharmony_ci		/* EcOcRegIprInvMpg |= 0x00FF; */
144562306a36Sopenharmony_ci		EcOcRegIprInvMpg &= (~(0x00FF));
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci		/* Invert Error ( we don't use the pin ) */
144862306a36Sopenharmony_ci		/*  EcOcRegIprInvMpg |= 0x0100; */
144962306a36Sopenharmony_ci		EcOcRegIprInvMpg &= (~(0x0100));
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci		/* Invert Start ( we don't use the pin ) */
145262306a36Sopenharmony_ci		/* EcOcRegIprInvMpg |= 0x0200; */
145362306a36Sopenharmony_ci		EcOcRegIprInvMpg &= (~(0x0200));
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci		/* Invert Valid ( we don't use the pin ) */
145662306a36Sopenharmony_ci		/* EcOcRegIprInvMpg |= 0x0400; */
145762306a36Sopenharmony_ci		EcOcRegIprInvMpg &= (~(0x0400));
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci		/* Invert Clock */
146062306a36Sopenharmony_ci		/* EcOcRegIprInvMpg |= 0x0800; */
146162306a36Sopenharmony_ci		EcOcRegIprInvMpg &= (~(0x0800));
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci		/* EcOcRegOcModeLop =0x05; */
146462306a36Sopenharmony_ci		status = Write16(state, EC_OC_REG_IPR_INV_MPG__A, EcOcRegIprInvMpg, 0);
146562306a36Sopenharmony_ci		if (status < 0)
146662306a36Sopenharmony_ci			break;
146762306a36Sopenharmony_ci		status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, EcOcRegOcModeLop, 0);
146862306a36Sopenharmony_ci		if (status < 0)
146962306a36Sopenharmony_ci			break;
147062306a36Sopenharmony_ci		status = Write16(state, EC_OC_REG_OC_MODE_HIP__A, EcOcRegOcModeHip, 0x0000);
147162306a36Sopenharmony_ci		if (status < 0)
147262306a36Sopenharmony_ci			break;
147362306a36Sopenharmony_ci		status = Write16(state, EC_OC_REG_OC_MPG_SIO__A, EcOcRegOcMpgSio, 0);
147462306a36Sopenharmony_ci		if (status < 0)
147562306a36Sopenharmony_ci			break;
147662306a36Sopenharmony_ci	} while (0);
147762306a36Sopenharmony_ci	return status;
147862306a36Sopenharmony_ci}
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_cistatic int SetDeviceTypeId(struct drxd_state *state)
148162306a36Sopenharmony_ci{
148262306a36Sopenharmony_ci	int status = 0;
148362306a36Sopenharmony_ci	u16 deviceId = 0;
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	do {
148662306a36Sopenharmony_ci		status = Read16(state, CC_REG_JTAGID_L__A, &deviceId, 0);
148762306a36Sopenharmony_ci		if (status < 0)
148862306a36Sopenharmony_ci			break;
148962306a36Sopenharmony_ci		/* TODO: why twice? */
149062306a36Sopenharmony_ci		status = Read16(state, CC_REG_JTAGID_L__A, &deviceId, 0);
149162306a36Sopenharmony_ci		if (status < 0)
149262306a36Sopenharmony_ci			break;
149362306a36Sopenharmony_ci		printk(KERN_INFO "drxd: deviceId = %04x\n", deviceId);
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci		state->type_A = 0;
149662306a36Sopenharmony_ci		state->PGA = 0;
149762306a36Sopenharmony_ci		state->diversity = 0;
149862306a36Sopenharmony_ci		if (deviceId == 0) {	/* on A2 only 3975 available */
149962306a36Sopenharmony_ci			state->type_A = 1;
150062306a36Sopenharmony_ci			printk(KERN_INFO "DRX3975D-A2\n");
150162306a36Sopenharmony_ci		} else {
150262306a36Sopenharmony_ci			deviceId >>= 12;
150362306a36Sopenharmony_ci			printk(KERN_INFO "DRX397%dD-B1\n", deviceId);
150462306a36Sopenharmony_ci			switch (deviceId) {
150562306a36Sopenharmony_ci			case 4:
150662306a36Sopenharmony_ci				state->diversity = 1;
150762306a36Sopenharmony_ci				fallthrough;
150862306a36Sopenharmony_ci			case 3:
150962306a36Sopenharmony_ci			case 7:
151062306a36Sopenharmony_ci				state->PGA = 1;
151162306a36Sopenharmony_ci				break;
151262306a36Sopenharmony_ci			case 6:
151362306a36Sopenharmony_ci				state->diversity = 1;
151462306a36Sopenharmony_ci				fallthrough;
151562306a36Sopenharmony_ci			case 5:
151662306a36Sopenharmony_ci			case 8:
151762306a36Sopenharmony_ci				break;
151862306a36Sopenharmony_ci			default:
151962306a36Sopenharmony_ci				status = -1;
152062306a36Sopenharmony_ci				break;
152162306a36Sopenharmony_ci			}
152262306a36Sopenharmony_ci		}
152362306a36Sopenharmony_ci	} while (0);
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	if (status < 0)
152662306a36Sopenharmony_ci		return status;
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	/* Init Table selection */
152962306a36Sopenharmony_ci	state->m_InitAtomicRead = DRXD_InitAtomicRead;
153062306a36Sopenharmony_ci	state->m_InitSC = DRXD_InitSC;
153162306a36Sopenharmony_ci	state->m_ResetECRAM = DRXD_ResetECRAM;
153262306a36Sopenharmony_ci	if (state->type_A) {
153362306a36Sopenharmony_ci		state->m_ResetCEFR = DRXD_ResetCEFR;
153462306a36Sopenharmony_ci		state->m_InitFE_1 = DRXD_InitFEA2_1;
153562306a36Sopenharmony_ci		state->m_InitFE_2 = DRXD_InitFEA2_2;
153662306a36Sopenharmony_ci		state->m_InitCP = DRXD_InitCPA2;
153762306a36Sopenharmony_ci		state->m_InitCE = DRXD_InitCEA2;
153862306a36Sopenharmony_ci		state->m_InitEQ = DRXD_InitEQA2;
153962306a36Sopenharmony_ci		state->m_InitEC = DRXD_InitECA2;
154062306a36Sopenharmony_ci		if (load_firmware(state, DRX_FW_FILENAME_A2))
154162306a36Sopenharmony_ci			return -EIO;
154262306a36Sopenharmony_ci	} else {
154362306a36Sopenharmony_ci		state->m_ResetCEFR = NULL;
154462306a36Sopenharmony_ci		state->m_InitFE_1 = DRXD_InitFEB1_1;
154562306a36Sopenharmony_ci		state->m_InitFE_2 = DRXD_InitFEB1_2;
154662306a36Sopenharmony_ci		state->m_InitCP = DRXD_InitCPB1;
154762306a36Sopenharmony_ci		state->m_InitCE = DRXD_InitCEB1;
154862306a36Sopenharmony_ci		state->m_InitEQ = DRXD_InitEQB1;
154962306a36Sopenharmony_ci		state->m_InitEC = DRXD_InitECB1;
155062306a36Sopenharmony_ci		if (load_firmware(state, DRX_FW_FILENAME_B1))
155162306a36Sopenharmony_ci			return -EIO;
155262306a36Sopenharmony_ci	}
155362306a36Sopenharmony_ci	if (state->diversity) {
155462306a36Sopenharmony_ci		state->m_InitDiversityFront = DRXD_InitDiversityFront;
155562306a36Sopenharmony_ci		state->m_InitDiversityEnd = DRXD_InitDiversityEnd;
155662306a36Sopenharmony_ci		state->m_DisableDiversity = DRXD_DisableDiversity;
155762306a36Sopenharmony_ci		state->m_StartDiversityFront = DRXD_StartDiversityFront;
155862306a36Sopenharmony_ci		state->m_StartDiversityEnd = DRXD_StartDiversityEnd;
155962306a36Sopenharmony_ci		state->m_DiversityDelay8MHZ = DRXD_DiversityDelay8MHZ;
156062306a36Sopenharmony_ci		state->m_DiversityDelay6MHZ = DRXD_DiversityDelay6MHZ;
156162306a36Sopenharmony_ci	} else {
156262306a36Sopenharmony_ci		state->m_InitDiversityFront = NULL;
156362306a36Sopenharmony_ci		state->m_InitDiversityEnd = NULL;
156462306a36Sopenharmony_ci		state->m_DisableDiversity = NULL;
156562306a36Sopenharmony_ci		state->m_StartDiversityFront = NULL;
156662306a36Sopenharmony_ci		state->m_StartDiversityEnd = NULL;
156762306a36Sopenharmony_ci		state->m_DiversityDelay8MHZ = NULL;
156862306a36Sopenharmony_ci		state->m_DiversityDelay6MHZ = NULL;
156962306a36Sopenharmony_ci	}
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	return status;
157262306a36Sopenharmony_ci}
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_cistatic int CorrectSysClockDeviation(struct drxd_state *state)
157562306a36Sopenharmony_ci{
157662306a36Sopenharmony_ci	int status;
157762306a36Sopenharmony_ci	s32 incr = 0;
157862306a36Sopenharmony_ci	s32 nomincr = 0;
157962306a36Sopenharmony_ci	u32 bandwidth = 0;
158062306a36Sopenharmony_ci	u32 sysClockInHz = 0;
158162306a36Sopenharmony_ci	u32 sysClockFreq = 0;	/* in kHz */
158262306a36Sopenharmony_ci	s16 oscClockDeviation;
158362306a36Sopenharmony_ci	s16 Diff;
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	do {
158662306a36Sopenharmony_ci		/* Retrieve bandwidth and incr, sanity check */
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci		/* These accesses should be AtomicReadReg32, but that
158962306a36Sopenharmony_ci		   causes trouble (at least for diversity */
159062306a36Sopenharmony_ci		status = Read32(state, LC_RA_RAM_IFINCR_NOM_L__A, ((u32 *) &nomincr), 0);
159162306a36Sopenharmony_ci		if (status < 0)
159262306a36Sopenharmony_ci			break;
159362306a36Sopenharmony_ci		status = Read32(state, FE_IF_REG_INCR0__A, (u32 *) &incr, 0);
159462306a36Sopenharmony_ci		if (status < 0)
159562306a36Sopenharmony_ci			break;
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci		if (state->type_A) {
159862306a36Sopenharmony_ci			if ((nomincr - incr < -500) || (nomincr - incr > 500))
159962306a36Sopenharmony_ci				break;
160062306a36Sopenharmony_ci		} else {
160162306a36Sopenharmony_ci			if ((nomincr - incr < -2000) || (nomincr - incr > 2000))
160262306a36Sopenharmony_ci				break;
160362306a36Sopenharmony_ci		}
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci		switch (state->props.bandwidth_hz) {
160662306a36Sopenharmony_ci		case 8000000:
160762306a36Sopenharmony_ci			bandwidth = DRXD_BANDWIDTH_8MHZ_IN_HZ;
160862306a36Sopenharmony_ci			break;
160962306a36Sopenharmony_ci		case 7000000:
161062306a36Sopenharmony_ci			bandwidth = DRXD_BANDWIDTH_7MHZ_IN_HZ;
161162306a36Sopenharmony_ci			break;
161262306a36Sopenharmony_ci		case 6000000:
161362306a36Sopenharmony_ci			bandwidth = DRXD_BANDWIDTH_6MHZ_IN_HZ;
161462306a36Sopenharmony_ci			break;
161562306a36Sopenharmony_ci		default:
161662306a36Sopenharmony_ci			return -1;
161762306a36Sopenharmony_ci		}
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci		/* Compute new sysclock value
162062306a36Sopenharmony_ci		   sysClockFreq = (((incr + 2^23)*bandwidth)/2^21)/1000 */
162162306a36Sopenharmony_ci		incr += (1 << 23);
162262306a36Sopenharmony_ci		sysClockInHz = MulDiv32(incr, bandwidth, 1 << 21);
162362306a36Sopenharmony_ci		sysClockFreq = (u32) (sysClockInHz / 1000);
162462306a36Sopenharmony_ci		/* rounding */
162562306a36Sopenharmony_ci		if ((sysClockInHz % 1000) > 500)
162662306a36Sopenharmony_ci			sysClockFreq++;
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci		/* Compute clock deviation in ppm */
162962306a36Sopenharmony_ci		oscClockDeviation = (u16) ((((s32) (sysClockFreq) -
163062306a36Sopenharmony_ci					     (s32)
163162306a36Sopenharmony_ci					     (state->expected_sys_clock_freq)) *
163262306a36Sopenharmony_ci					    1000000L) /
163362306a36Sopenharmony_ci					   (s32)
163462306a36Sopenharmony_ci					   (state->expected_sys_clock_freq));
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci		Diff = oscClockDeviation - state->osc_clock_deviation;
163762306a36Sopenharmony_ci		/*printk(KERN_INFO "sysclockdiff=%d\n", Diff); */
163862306a36Sopenharmony_ci		if (Diff >= -200 && Diff <= 200) {
163962306a36Sopenharmony_ci			state->sys_clock_freq = (u16) sysClockFreq;
164062306a36Sopenharmony_ci			if (oscClockDeviation != state->osc_clock_deviation) {
164162306a36Sopenharmony_ci				if (state->config.osc_deviation) {
164262306a36Sopenharmony_ci					state->config.osc_deviation(state->priv,
164362306a36Sopenharmony_ci								    oscClockDeviation,
164462306a36Sopenharmony_ci								    1);
164562306a36Sopenharmony_ci					state->osc_clock_deviation =
164662306a36Sopenharmony_ci					    oscClockDeviation;
164762306a36Sopenharmony_ci				}
164862306a36Sopenharmony_ci			}
164962306a36Sopenharmony_ci			/* switch OFF SRMM scan in SC */
165062306a36Sopenharmony_ci			status = Write16(state, SC_RA_RAM_SAMPLE_RATE_COUNT__A, DRXD_OSCDEV_DONT_SCAN, 0);
165162306a36Sopenharmony_ci			if (status < 0)
165262306a36Sopenharmony_ci				break;
165362306a36Sopenharmony_ci			/* overrule FE_IF internal value for
165462306a36Sopenharmony_ci			   proper re-locking */
165562306a36Sopenharmony_ci			status = Write16(state, SC_RA_RAM_IF_SAVE__AX, state->current_fe_if_incr, 0);
165662306a36Sopenharmony_ci			if (status < 0)
165762306a36Sopenharmony_ci				break;
165862306a36Sopenharmony_ci			state->cscd_state = CSCD_SAVED;
165962306a36Sopenharmony_ci		}
166062306a36Sopenharmony_ci	} while (0);
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci	return status;
166362306a36Sopenharmony_ci}
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_cistatic int DRX_Stop(struct drxd_state *state)
166662306a36Sopenharmony_ci{
166762306a36Sopenharmony_ci	int status;
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci	if (state->drxd_state != DRXD_STARTED)
167062306a36Sopenharmony_ci		return 0;
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	do {
167362306a36Sopenharmony_ci		if (state->cscd_state != CSCD_SAVED) {
167462306a36Sopenharmony_ci			u32 lock;
167562306a36Sopenharmony_ci			status = DRX_GetLockStatus(state, &lock);
167662306a36Sopenharmony_ci			if (status < 0)
167762306a36Sopenharmony_ci				break;
167862306a36Sopenharmony_ci		}
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci		status = StopOC(state);
168162306a36Sopenharmony_ci		if (status < 0)
168262306a36Sopenharmony_ci			break;
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci		state->drxd_state = DRXD_STOPPED;
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci		status = ConfigureMPEGOutput(state, 0);
168762306a36Sopenharmony_ci		if (status < 0)
168862306a36Sopenharmony_ci			break;
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci		if (state->type_A) {
169162306a36Sopenharmony_ci			/* Stop relevant processors off the device */
169262306a36Sopenharmony_ci			status = Write16(state, EC_OD_REG_COMM_EXEC__A, 0x0000, 0x0000);
169362306a36Sopenharmony_ci			if (status < 0)
169462306a36Sopenharmony_ci				break;
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci			status = Write16(state, SC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
169762306a36Sopenharmony_ci			if (status < 0)
169862306a36Sopenharmony_ci				break;
169962306a36Sopenharmony_ci			status = Write16(state, LC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
170062306a36Sopenharmony_ci			if (status < 0)
170162306a36Sopenharmony_ci				break;
170262306a36Sopenharmony_ci		} else {
170362306a36Sopenharmony_ci			/* Stop all processors except HI & CC & FE */
170462306a36Sopenharmony_ci			status = Write16(state, B_SC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
170562306a36Sopenharmony_ci			if (status < 0)
170662306a36Sopenharmony_ci				break;
170762306a36Sopenharmony_ci			status = Write16(state, B_LC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
170862306a36Sopenharmony_ci			if (status < 0)
170962306a36Sopenharmony_ci				break;
171062306a36Sopenharmony_ci			status = Write16(state, B_FT_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
171162306a36Sopenharmony_ci			if (status < 0)
171262306a36Sopenharmony_ci				break;
171362306a36Sopenharmony_ci			status = Write16(state, B_CP_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
171462306a36Sopenharmony_ci			if (status < 0)
171562306a36Sopenharmony_ci				break;
171662306a36Sopenharmony_ci			status = Write16(state, B_CE_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
171762306a36Sopenharmony_ci			if (status < 0)
171862306a36Sopenharmony_ci				break;
171962306a36Sopenharmony_ci			status = Write16(state, B_EQ_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
172062306a36Sopenharmony_ci			if (status < 0)
172162306a36Sopenharmony_ci				break;
172262306a36Sopenharmony_ci			status = Write16(state, EC_OD_REG_COMM_EXEC__A, 0x0000, 0);
172362306a36Sopenharmony_ci			if (status < 0)
172462306a36Sopenharmony_ci				break;
172562306a36Sopenharmony_ci		}
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	} while (0);
172862306a36Sopenharmony_ci	return status;
172962306a36Sopenharmony_ci}
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci#if 0	/* Currently unused */
173262306a36Sopenharmony_cistatic int SetOperationMode(struct drxd_state *state, int oMode)
173362306a36Sopenharmony_ci{
173462306a36Sopenharmony_ci	int status;
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci	do {
173762306a36Sopenharmony_ci		if (state->drxd_state != DRXD_STOPPED) {
173862306a36Sopenharmony_ci			status = -1;
173962306a36Sopenharmony_ci			break;
174062306a36Sopenharmony_ci		}
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci		if (oMode == state->operation_mode) {
174362306a36Sopenharmony_ci			status = 0;
174462306a36Sopenharmony_ci			break;
174562306a36Sopenharmony_ci		}
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci		if (oMode != OM_Default && !state->diversity) {
174862306a36Sopenharmony_ci			status = -1;
174962306a36Sopenharmony_ci			break;
175062306a36Sopenharmony_ci		}
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_ci		switch (oMode) {
175362306a36Sopenharmony_ci		case OM_DVBT_Diversity_Front:
175462306a36Sopenharmony_ci			status = WriteTable(state, state->m_InitDiversityFront);
175562306a36Sopenharmony_ci			break;
175662306a36Sopenharmony_ci		case OM_DVBT_Diversity_End:
175762306a36Sopenharmony_ci			status = WriteTable(state, state->m_InitDiversityEnd);
175862306a36Sopenharmony_ci			break;
175962306a36Sopenharmony_ci		case OM_Default:
176062306a36Sopenharmony_ci			/* We need to check how to
176162306a36Sopenharmony_ci			   get DRXD out of diversity */
176262306a36Sopenharmony_ci		default:
176362306a36Sopenharmony_ci			status = WriteTable(state, state->m_DisableDiversity);
176462306a36Sopenharmony_ci			break;
176562306a36Sopenharmony_ci		}
176662306a36Sopenharmony_ci	} while (0);
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci	if (!status)
176962306a36Sopenharmony_ci		state->operation_mode = oMode;
177062306a36Sopenharmony_ci	return status;
177162306a36Sopenharmony_ci}
177262306a36Sopenharmony_ci#endif
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_cistatic int StartDiversity(struct drxd_state *state)
177562306a36Sopenharmony_ci{
177662306a36Sopenharmony_ci	int status = 0;
177762306a36Sopenharmony_ci	u16 rcControl;
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci	do {
178062306a36Sopenharmony_ci		if (state->operation_mode == OM_DVBT_Diversity_Front) {
178162306a36Sopenharmony_ci			status = WriteTable(state, state->m_StartDiversityFront);
178262306a36Sopenharmony_ci			if (status < 0)
178362306a36Sopenharmony_ci				break;
178462306a36Sopenharmony_ci		} else if (state->operation_mode == OM_DVBT_Diversity_End) {
178562306a36Sopenharmony_ci			status = WriteTable(state, state->m_StartDiversityEnd);
178662306a36Sopenharmony_ci			if (status < 0)
178762306a36Sopenharmony_ci				break;
178862306a36Sopenharmony_ci			if (state->props.bandwidth_hz == 8000000) {
178962306a36Sopenharmony_ci				status = WriteTable(state, state->m_DiversityDelay8MHZ);
179062306a36Sopenharmony_ci				if (status < 0)
179162306a36Sopenharmony_ci					break;
179262306a36Sopenharmony_ci			} else {
179362306a36Sopenharmony_ci				status = WriteTable(state, state->m_DiversityDelay6MHZ);
179462306a36Sopenharmony_ci				if (status < 0)
179562306a36Sopenharmony_ci					break;
179662306a36Sopenharmony_ci			}
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci			status = Read16(state, B_EQ_REG_RC_SEL_CAR__A, &rcControl, 0);
179962306a36Sopenharmony_ci			if (status < 0)
180062306a36Sopenharmony_ci				break;
180162306a36Sopenharmony_ci			rcControl &= ~(B_EQ_REG_RC_SEL_CAR_FFTMODE__M);
180262306a36Sopenharmony_ci			rcControl |= B_EQ_REG_RC_SEL_CAR_DIV_ON |
180362306a36Sopenharmony_ci			    /*  combining enabled */
180462306a36Sopenharmony_ci			    B_EQ_REG_RC_SEL_CAR_MEAS_A_CC |
180562306a36Sopenharmony_ci			    B_EQ_REG_RC_SEL_CAR_PASS_A_CC |
180662306a36Sopenharmony_ci			    B_EQ_REG_RC_SEL_CAR_LOCAL_A_CC;
180762306a36Sopenharmony_ci			status = Write16(state, B_EQ_REG_RC_SEL_CAR__A, rcControl, 0);
180862306a36Sopenharmony_ci			if (status < 0)
180962306a36Sopenharmony_ci				break;
181062306a36Sopenharmony_ci		}
181162306a36Sopenharmony_ci	} while (0);
181262306a36Sopenharmony_ci	return status;
181362306a36Sopenharmony_ci}
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_cistatic int SetFrequencyShift(struct drxd_state *state,
181662306a36Sopenharmony_ci			     u32 offsetFreq, int channelMirrored)
181762306a36Sopenharmony_ci{
181862306a36Sopenharmony_ci	int negativeShift = (state->tuner_mirrors == channelMirrored);
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	/* Handle all mirroring
182162306a36Sopenharmony_ci	 *
182262306a36Sopenharmony_ci	 * Note: ADC mirroring (aliasing) is implictly handled by limiting
182362306a36Sopenharmony_ci	 * feFsRegAddInc to 28 bits below
182462306a36Sopenharmony_ci	 * (if the result before masking is more than 28 bits, this means
182562306a36Sopenharmony_ci	 *  that the ADC is mirroring.
182662306a36Sopenharmony_ci	 * The masking is in fact the aliasing of the ADC)
182762306a36Sopenharmony_ci	 *
182862306a36Sopenharmony_ci	 */
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	/* Compute register value, unsigned computation */
183162306a36Sopenharmony_ci	state->fe_fs_add_incr = MulDiv32(state->intermediate_freq +
183262306a36Sopenharmony_ci					 offsetFreq,
183362306a36Sopenharmony_ci					 1 << 28, state->sys_clock_freq);
183462306a36Sopenharmony_ci	/* Remove integer part */
183562306a36Sopenharmony_ci	state->fe_fs_add_incr &= 0x0FFFFFFFL;
183662306a36Sopenharmony_ci	if (negativeShift)
183762306a36Sopenharmony_ci		state->fe_fs_add_incr = ((1 << 28) - state->fe_fs_add_incr);
183862306a36Sopenharmony_ci
183962306a36Sopenharmony_ci	/* Save the frequency shift without tunerOffset compensation
184062306a36Sopenharmony_ci	   for CtrlGetChannel. */
184162306a36Sopenharmony_ci	state->org_fe_fs_add_incr = MulDiv32(state->intermediate_freq,
184262306a36Sopenharmony_ci					     1 << 28, state->sys_clock_freq);
184362306a36Sopenharmony_ci	/* Remove integer part */
184462306a36Sopenharmony_ci	state->org_fe_fs_add_incr &= 0x0FFFFFFFL;
184562306a36Sopenharmony_ci	if (negativeShift)
184662306a36Sopenharmony_ci		state->org_fe_fs_add_incr = ((1L << 28) -
184762306a36Sopenharmony_ci					     state->org_fe_fs_add_incr);
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci	return Write32(state, FE_FS_REG_ADD_INC_LOP__A,
185062306a36Sopenharmony_ci		       state->fe_fs_add_incr, 0);
185162306a36Sopenharmony_ci}
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_cistatic int SetCfgNoiseCalibration(struct drxd_state *state,
185462306a36Sopenharmony_ci				  struct SNoiseCal *noiseCal)
185562306a36Sopenharmony_ci{
185662306a36Sopenharmony_ci	u16 beOptEna;
185762306a36Sopenharmony_ci	int status = 0;
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci	do {
186062306a36Sopenharmony_ci		status = Read16(state, SC_RA_RAM_BE_OPT_ENA__A, &beOptEna, 0);
186162306a36Sopenharmony_ci		if (status < 0)
186262306a36Sopenharmony_ci			break;
186362306a36Sopenharmony_ci		if (noiseCal->cpOpt) {
186462306a36Sopenharmony_ci			beOptEna |= (1 << SC_RA_RAM_BE_OPT_ENA_CP_OPT);
186562306a36Sopenharmony_ci		} else {
186662306a36Sopenharmony_ci			beOptEna &= ~(1 << SC_RA_RAM_BE_OPT_ENA_CP_OPT);
186762306a36Sopenharmony_ci			status = Write16(state, CP_REG_AC_NEXP_OFFS__A, noiseCal->cpNexpOfs, 0);
186862306a36Sopenharmony_ci			if (status < 0)
186962306a36Sopenharmony_ci				break;
187062306a36Sopenharmony_ci		}
187162306a36Sopenharmony_ci		status = Write16(state, SC_RA_RAM_BE_OPT_ENA__A, beOptEna, 0);
187262306a36Sopenharmony_ci		if (status < 0)
187362306a36Sopenharmony_ci			break;
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci		if (!state->type_A) {
187662306a36Sopenharmony_ci			status = Write16(state, B_SC_RA_RAM_CO_TD_CAL_2K__A, noiseCal->tdCal2k, 0);
187762306a36Sopenharmony_ci			if (status < 0)
187862306a36Sopenharmony_ci				break;
187962306a36Sopenharmony_ci			status = Write16(state, B_SC_RA_RAM_CO_TD_CAL_8K__A, noiseCal->tdCal8k, 0);
188062306a36Sopenharmony_ci			if (status < 0)
188162306a36Sopenharmony_ci				break;
188262306a36Sopenharmony_ci		}
188362306a36Sopenharmony_ci	} while (0);
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	return status;
188662306a36Sopenharmony_ci}
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_cistatic int DRX_Start(struct drxd_state *state, s32 off)
188962306a36Sopenharmony_ci{
189062306a36Sopenharmony_ci	struct dtv_frontend_properties *p = &state->props;
189162306a36Sopenharmony_ci	int status;
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	u16 transmissionParams = 0;
189462306a36Sopenharmony_ci	u16 operationMode = 0;
189562306a36Sopenharmony_ci	u16 qpskTdTpsPwr = 0;
189662306a36Sopenharmony_ci	u16 qam16TdTpsPwr = 0;
189762306a36Sopenharmony_ci	u16 qam64TdTpsPwr = 0;
189862306a36Sopenharmony_ci	u32 feIfIncr = 0;
189962306a36Sopenharmony_ci	u32 bandwidth = 0;
190062306a36Sopenharmony_ci	int mirrorFreqSpect;
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci	u16 qpskSnCeGain = 0;
190362306a36Sopenharmony_ci	u16 qam16SnCeGain = 0;
190462306a36Sopenharmony_ci	u16 qam64SnCeGain = 0;
190562306a36Sopenharmony_ci	u16 qpskIsGainMan = 0;
190662306a36Sopenharmony_ci	u16 qam16IsGainMan = 0;
190762306a36Sopenharmony_ci	u16 qam64IsGainMan = 0;
190862306a36Sopenharmony_ci	u16 qpskIsGainExp = 0;
190962306a36Sopenharmony_ci	u16 qam16IsGainExp = 0;
191062306a36Sopenharmony_ci	u16 qam64IsGainExp = 0;
191162306a36Sopenharmony_ci	u16 bandwidthParam = 0;
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	if (off < 0)
191462306a36Sopenharmony_ci		off = (off - 500) / 1000;
191562306a36Sopenharmony_ci	else
191662306a36Sopenharmony_ci		off = (off + 500) / 1000;
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci	do {
191962306a36Sopenharmony_ci		if (state->drxd_state != DRXD_STOPPED)
192062306a36Sopenharmony_ci			return -1;
192162306a36Sopenharmony_ci		status = ResetECOD(state);
192262306a36Sopenharmony_ci		if (status < 0)
192362306a36Sopenharmony_ci			break;
192462306a36Sopenharmony_ci		if (state->type_A) {
192562306a36Sopenharmony_ci			status = InitSC(state);
192662306a36Sopenharmony_ci			if (status < 0)
192762306a36Sopenharmony_ci				break;
192862306a36Sopenharmony_ci		} else {
192962306a36Sopenharmony_ci			status = InitFT(state);
193062306a36Sopenharmony_ci			if (status < 0)
193162306a36Sopenharmony_ci				break;
193262306a36Sopenharmony_ci			status = InitCP(state);
193362306a36Sopenharmony_ci			if (status < 0)
193462306a36Sopenharmony_ci				break;
193562306a36Sopenharmony_ci			status = InitCE(state);
193662306a36Sopenharmony_ci			if (status < 0)
193762306a36Sopenharmony_ci				break;
193862306a36Sopenharmony_ci			status = InitEQ(state);
193962306a36Sopenharmony_ci			if (status < 0)
194062306a36Sopenharmony_ci				break;
194162306a36Sopenharmony_ci			status = InitSC(state);
194262306a36Sopenharmony_ci			if (status < 0)
194362306a36Sopenharmony_ci				break;
194462306a36Sopenharmony_ci		}
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci		/* Restore current IF & RF AGC settings */
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci		status = SetCfgIfAgc(state, &state->if_agc_cfg);
194962306a36Sopenharmony_ci		if (status < 0)
195062306a36Sopenharmony_ci			break;
195162306a36Sopenharmony_ci		status = SetCfgRfAgc(state, &state->rf_agc_cfg);
195262306a36Sopenharmony_ci		if (status < 0)
195362306a36Sopenharmony_ci			break;
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci		mirrorFreqSpect = (state->props.inversion == INVERSION_ON);
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_ci		switch (p->transmission_mode) {
195862306a36Sopenharmony_ci		default:	/* Not set, detect it automatically */
195962306a36Sopenharmony_ci			operationMode |= SC_RA_RAM_OP_AUTO_MODE__M;
196062306a36Sopenharmony_ci			fallthrough;	/* try first guess DRX_FFTMODE_8K */
196162306a36Sopenharmony_ci		case TRANSMISSION_MODE_8K:
196262306a36Sopenharmony_ci			transmissionParams |= SC_RA_RAM_OP_PARAM_MODE_8K;
196362306a36Sopenharmony_ci			if (state->type_A) {
196462306a36Sopenharmony_ci				status = Write16(state, EC_SB_REG_TR_MODE__A, EC_SB_REG_TR_MODE_8K, 0x0000);
196562306a36Sopenharmony_ci				if (status < 0)
196662306a36Sopenharmony_ci					break;
196762306a36Sopenharmony_ci				qpskSnCeGain = 99;
196862306a36Sopenharmony_ci				qam16SnCeGain = 83;
196962306a36Sopenharmony_ci				qam64SnCeGain = 67;
197062306a36Sopenharmony_ci			}
197162306a36Sopenharmony_ci			break;
197262306a36Sopenharmony_ci		case TRANSMISSION_MODE_2K:
197362306a36Sopenharmony_ci			transmissionParams |= SC_RA_RAM_OP_PARAM_MODE_2K;
197462306a36Sopenharmony_ci			if (state->type_A) {
197562306a36Sopenharmony_ci				status = Write16(state, EC_SB_REG_TR_MODE__A, EC_SB_REG_TR_MODE_2K, 0x0000);
197662306a36Sopenharmony_ci				if (status < 0)
197762306a36Sopenharmony_ci					break;
197862306a36Sopenharmony_ci				qpskSnCeGain = 97;
197962306a36Sopenharmony_ci				qam16SnCeGain = 71;
198062306a36Sopenharmony_ci				qam64SnCeGain = 65;
198162306a36Sopenharmony_ci			}
198262306a36Sopenharmony_ci			break;
198362306a36Sopenharmony_ci		}
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci		switch (p->guard_interval) {
198662306a36Sopenharmony_ci		case GUARD_INTERVAL_1_4:
198762306a36Sopenharmony_ci			transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_4;
198862306a36Sopenharmony_ci			break;
198962306a36Sopenharmony_ci		case GUARD_INTERVAL_1_8:
199062306a36Sopenharmony_ci			transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_8;
199162306a36Sopenharmony_ci			break;
199262306a36Sopenharmony_ci		case GUARD_INTERVAL_1_16:
199362306a36Sopenharmony_ci			transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_16;
199462306a36Sopenharmony_ci			break;
199562306a36Sopenharmony_ci		case GUARD_INTERVAL_1_32:
199662306a36Sopenharmony_ci			transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_32;
199762306a36Sopenharmony_ci			break;
199862306a36Sopenharmony_ci		default:	/* Not set, detect it automatically */
199962306a36Sopenharmony_ci			operationMode |= SC_RA_RAM_OP_AUTO_GUARD__M;
200062306a36Sopenharmony_ci			/* try first guess 1/4 */
200162306a36Sopenharmony_ci			transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_4;
200262306a36Sopenharmony_ci			break;
200362306a36Sopenharmony_ci		}
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci		switch (p->hierarchy) {
200662306a36Sopenharmony_ci		case HIERARCHY_1:
200762306a36Sopenharmony_ci			transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_A1;
200862306a36Sopenharmony_ci			if (state->type_A) {
200962306a36Sopenharmony_ci				status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0001, 0x0000);
201062306a36Sopenharmony_ci				if (status < 0)
201162306a36Sopenharmony_ci					break;
201262306a36Sopenharmony_ci				status = Write16(state, EC_SB_REG_ALPHA__A, 0x0001, 0x0000);
201362306a36Sopenharmony_ci				if (status < 0)
201462306a36Sopenharmony_ci					break;
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci				qpskTdTpsPwr = EQ_TD_TPS_PWR_UNKNOWN;
201762306a36Sopenharmony_ci				qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHA1;
201862306a36Sopenharmony_ci				qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHA1;
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci				qpskIsGainMan =
202162306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE;
202262306a36Sopenharmony_ci				qam16IsGainMan =
202362306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_16QAM_MAN__PRE;
202462306a36Sopenharmony_ci				qam64IsGainMan =
202562306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_64QAM_MAN__PRE;
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci				qpskIsGainExp =
202862306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE;
202962306a36Sopenharmony_ci				qam16IsGainExp =
203062306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_16QAM_EXP__PRE;
203162306a36Sopenharmony_ci				qam64IsGainExp =
203262306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_64QAM_EXP__PRE;
203362306a36Sopenharmony_ci			}
203462306a36Sopenharmony_ci			break;
203562306a36Sopenharmony_ci
203662306a36Sopenharmony_ci		case HIERARCHY_2:
203762306a36Sopenharmony_ci			transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_A2;
203862306a36Sopenharmony_ci			if (state->type_A) {
203962306a36Sopenharmony_ci				status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0002, 0x0000);
204062306a36Sopenharmony_ci				if (status < 0)
204162306a36Sopenharmony_ci					break;
204262306a36Sopenharmony_ci				status = Write16(state, EC_SB_REG_ALPHA__A, 0x0002, 0x0000);
204362306a36Sopenharmony_ci				if (status < 0)
204462306a36Sopenharmony_ci					break;
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci				qpskTdTpsPwr = EQ_TD_TPS_PWR_UNKNOWN;
204762306a36Sopenharmony_ci				qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHA2;
204862306a36Sopenharmony_ci				qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHA2;
204962306a36Sopenharmony_ci
205062306a36Sopenharmony_ci				qpskIsGainMan =
205162306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE;
205262306a36Sopenharmony_ci				qam16IsGainMan =
205362306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_MAN__PRE;
205462306a36Sopenharmony_ci				qam64IsGainMan =
205562306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_MAN__PRE;
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci				qpskIsGainExp =
205862306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE;
205962306a36Sopenharmony_ci				qam16IsGainExp =
206062306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_EXP__PRE;
206162306a36Sopenharmony_ci				qam64IsGainExp =
206262306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_EXP__PRE;
206362306a36Sopenharmony_ci			}
206462306a36Sopenharmony_ci			break;
206562306a36Sopenharmony_ci		case HIERARCHY_4:
206662306a36Sopenharmony_ci			transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_A4;
206762306a36Sopenharmony_ci			if (state->type_A) {
206862306a36Sopenharmony_ci				status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0003, 0x0000);
206962306a36Sopenharmony_ci				if (status < 0)
207062306a36Sopenharmony_ci					break;
207162306a36Sopenharmony_ci				status = Write16(state, EC_SB_REG_ALPHA__A, 0x0003, 0x0000);
207262306a36Sopenharmony_ci				if (status < 0)
207362306a36Sopenharmony_ci					break;
207462306a36Sopenharmony_ci
207562306a36Sopenharmony_ci				qpskTdTpsPwr = EQ_TD_TPS_PWR_UNKNOWN;
207662306a36Sopenharmony_ci				qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHA4;
207762306a36Sopenharmony_ci				qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHA4;
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci				qpskIsGainMan =
208062306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE;
208162306a36Sopenharmony_ci				qam16IsGainMan =
208262306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_MAN__PRE;
208362306a36Sopenharmony_ci				qam64IsGainMan =
208462306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_MAN__PRE;
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci				qpskIsGainExp =
208762306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE;
208862306a36Sopenharmony_ci				qam16IsGainExp =
208962306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_EXP__PRE;
209062306a36Sopenharmony_ci				qam64IsGainExp =
209162306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_EXP__PRE;
209262306a36Sopenharmony_ci			}
209362306a36Sopenharmony_ci			break;
209462306a36Sopenharmony_ci		case HIERARCHY_AUTO:
209562306a36Sopenharmony_ci		default:
209662306a36Sopenharmony_ci			/* Not set, detect it automatically, start with none */
209762306a36Sopenharmony_ci			operationMode |= SC_RA_RAM_OP_AUTO_HIER__M;
209862306a36Sopenharmony_ci			transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_NO;
209962306a36Sopenharmony_ci			if (state->type_A) {
210062306a36Sopenharmony_ci				status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0000, 0x0000);
210162306a36Sopenharmony_ci				if (status < 0)
210262306a36Sopenharmony_ci					break;
210362306a36Sopenharmony_ci				status = Write16(state, EC_SB_REG_ALPHA__A, 0x0000, 0x0000);
210462306a36Sopenharmony_ci				if (status < 0)
210562306a36Sopenharmony_ci					break;
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci				qpskTdTpsPwr = EQ_TD_TPS_PWR_QPSK;
210862306a36Sopenharmony_ci				qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHAN;
210962306a36Sopenharmony_ci				qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHAN;
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_ci				qpskIsGainMan =
211262306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_QPSK_MAN__PRE;
211362306a36Sopenharmony_ci				qam16IsGainMan =
211462306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_16QAM_MAN__PRE;
211562306a36Sopenharmony_ci				qam64IsGainMan =
211662306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_64QAM_MAN__PRE;
211762306a36Sopenharmony_ci
211862306a36Sopenharmony_ci				qpskIsGainExp =
211962306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_QPSK_EXP__PRE;
212062306a36Sopenharmony_ci				qam16IsGainExp =
212162306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_16QAM_EXP__PRE;
212262306a36Sopenharmony_ci				qam64IsGainExp =
212362306a36Sopenharmony_ci				    SC_RA_RAM_EQ_IS_GAIN_64QAM_EXP__PRE;
212462306a36Sopenharmony_ci			}
212562306a36Sopenharmony_ci			break;
212662306a36Sopenharmony_ci		}
212762306a36Sopenharmony_ci		if (status < 0)
212862306a36Sopenharmony_ci			break;
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci		switch (p->modulation) {
213162306a36Sopenharmony_ci		default:
213262306a36Sopenharmony_ci			operationMode |= SC_RA_RAM_OP_AUTO_CONST__M;
213362306a36Sopenharmony_ci			fallthrough;	/* try first guess DRX_CONSTELLATION_QAM64 */
213462306a36Sopenharmony_ci		case QAM_64:
213562306a36Sopenharmony_ci			transmissionParams |= SC_RA_RAM_OP_PARAM_CONST_QAM64;
213662306a36Sopenharmony_ci			if (state->type_A) {
213762306a36Sopenharmony_ci				status = Write16(state, EQ_REG_OT_CONST__A, 0x0002, 0x0000);
213862306a36Sopenharmony_ci				if (status < 0)
213962306a36Sopenharmony_ci					break;
214062306a36Sopenharmony_ci				status = Write16(state, EC_SB_REG_CONST__A, EC_SB_REG_CONST_64QAM, 0x0000);
214162306a36Sopenharmony_ci				if (status < 0)
214262306a36Sopenharmony_ci					break;
214362306a36Sopenharmony_ci				status = Write16(state, EC_SB_REG_SCALE_MSB__A, 0x0020, 0x0000);
214462306a36Sopenharmony_ci				if (status < 0)
214562306a36Sopenharmony_ci					break;
214662306a36Sopenharmony_ci				status = Write16(state, EC_SB_REG_SCALE_BIT2__A, 0x0008, 0x0000);
214762306a36Sopenharmony_ci				if (status < 0)
214862306a36Sopenharmony_ci					break;
214962306a36Sopenharmony_ci				status = Write16(state, EC_SB_REG_SCALE_LSB__A, 0x0002, 0x0000);
215062306a36Sopenharmony_ci				if (status < 0)
215162306a36Sopenharmony_ci					break;
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci				status = Write16(state, EQ_REG_TD_TPS_PWR_OFS__A, qam64TdTpsPwr, 0x0000);
215462306a36Sopenharmony_ci				if (status < 0)
215562306a36Sopenharmony_ci					break;
215662306a36Sopenharmony_ci				status = Write16(state, EQ_REG_SN_CEGAIN__A, qam64SnCeGain, 0x0000);
215762306a36Sopenharmony_ci				if (status < 0)
215862306a36Sopenharmony_ci					break;
215962306a36Sopenharmony_ci				status = Write16(state, EQ_REG_IS_GAIN_MAN__A, qam64IsGainMan, 0x0000);
216062306a36Sopenharmony_ci				if (status < 0)
216162306a36Sopenharmony_ci					break;
216262306a36Sopenharmony_ci				status = Write16(state, EQ_REG_IS_GAIN_EXP__A, qam64IsGainExp, 0x0000);
216362306a36Sopenharmony_ci				if (status < 0)
216462306a36Sopenharmony_ci					break;
216562306a36Sopenharmony_ci			}
216662306a36Sopenharmony_ci			break;
216762306a36Sopenharmony_ci		case QPSK:
216862306a36Sopenharmony_ci			transmissionParams |= SC_RA_RAM_OP_PARAM_CONST_QPSK;
216962306a36Sopenharmony_ci			if (state->type_A) {
217062306a36Sopenharmony_ci				status = Write16(state, EQ_REG_OT_CONST__A, 0x0000, 0x0000);
217162306a36Sopenharmony_ci				if (status < 0)
217262306a36Sopenharmony_ci					break;
217362306a36Sopenharmony_ci				status = Write16(state, EC_SB_REG_CONST__A, EC_SB_REG_CONST_QPSK, 0x0000);
217462306a36Sopenharmony_ci				if (status < 0)
217562306a36Sopenharmony_ci					break;
217662306a36Sopenharmony_ci				status = Write16(state, EC_SB_REG_SCALE_MSB__A, 0x0010, 0x0000);
217762306a36Sopenharmony_ci				if (status < 0)
217862306a36Sopenharmony_ci					break;
217962306a36Sopenharmony_ci				status = Write16(state, EC_SB_REG_SCALE_BIT2__A, 0x0000, 0x0000);
218062306a36Sopenharmony_ci				if (status < 0)
218162306a36Sopenharmony_ci					break;
218262306a36Sopenharmony_ci				status = Write16(state, EC_SB_REG_SCALE_LSB__A, 0x0000, 0x0000);
218362306a36Sopenharmony_ci				if (status < 0)
218462306a36Sopenharmony_ci					break;
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci				status = Write16(state, EQ_REG_TD_TPS_PWR_OFS__A, qpskTdTpsPwr, 0x0000);
218762306a36Sopenharmony_ci				if (status < 0)
218862306a36Sopenharmony_ci					break;
218962306a36Sopenharmony_ci				status = Write16(state, EQ_REG_SN_CEGAIN__A, qpskSnCeGain, 0x0000);
219062306a36Sopenharmony_ci				if (status < 0)
219162306a36Sopenharmony_ci					break;
219262306a36Sopenharmony_ci				status = Write16(state, EQ_REG_IS_GAIN_MAN__A, qpskIsGainMan, 0x0000);
219362306a36Sopenharmony_ci				if (status < 0)
219462306a36Sopenharmony_ci					break;
219562306a36Sopenharmony_ci				status = Write16(state, EQ_REG_IS_GAIN_EXP__A, qpskIsGainExp, 0x0000);
219662306a36Sopenharmony_ci				if (status < 0)
219762306a36Sopenharmony_ci					break;
219862306a36Sopenharmony_ci			}
219962306a36Sopenharmony_ci			break;
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_ci		case QAM_16:
220262306a36Sopenharmony_ci			transmissionParams |= SC_RA_RAM_OP_PARAM_CONST_QAM16;
220362306a36Sopenharmony_ci			if (state->type_A) {
220462306a36Sopenharmony_ci				status = Write16(state, EQ_REG_OT_CONST__A, 0x0001, 0x0000);
220562306a36Sopenharmony_ci				if (status < 0)
220662306a36Sopenharmony_ci					break;
220762306a36Sopenharmony_ci				status = Write16(state, EC_SB_REG_CONST__A, EC_SB_REG_CONST_16QAM, 0x0000);
220862306a36Sopenharmony_ci				if (status < 0)
220962306a36Sopenharmony_ci					break;
221062306a36Sopenharmony_ci				status = Write16(state, EC_SB_REG_SCALE_MSB__A, 0x0010, 0x0000);
221162306a36Sopenharmony_ci				if (status < 0)
221262306a36Sopenharmony_ci					break;
221362306a36Sopenharmony_ci				status = Write16(state, EC_SB_REG_SCALE_BIT2__A, 0x0004, 0x0000);
221462306a36Sopenharmony_ci				if (status < 0)
221562306a36Sopenharmony_ci					break;
221662306a36Sopenharmony_ci				status = Write16(state, EC_SB_REG_SCALE_LSB__A, 0x0000, 0x0000);
221762306a36Sopenharmony_ci				if (status < 0)
221862306a36Sopenharmony_ci					break;
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci				status = Write16(state, EQ_REG_TD_TPS_PWR_OFS__A, qam16TdTpsPwr, 0x0000);
222162306a36Sopenharmony_ci				if (status < 0)
222262306a36Sopenharmony_ci					break;
222362306a36Sopenharmony_ci				status = Write16(state, EQ_REG_SN_CEGAIN__A, qam16SnCeGain, 0x0000);
222462306a36Sopenharmony_ci				if (status < 0)
222562306a36Sopenharmony_ci					break;
222662306a36Sopenharmony_ci				status = Write16(state, EQ_REG_IS_GAIN_MAN__A, qam16IsGainMan, 0x0000);
222762306a36Sopenharmony_ci				if (status < 0)
222862306a36Sopenharmony_ci					break;
222962306a36Sopenharmony_ci				status = Write16(state, EQ_REG_IS_GAIN_EXP__A, qam16IsGainExp, 0x0000);
223062306a36Sopenharmony_ci				if (status < 0)
223162306a36Sopenharmony_ci					break;
223262306a36Sopenharmony_ci			}
223362306a36Sopenharmony_ci			break;
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_ci		}
223662306a36Sopenharmony_ci		if (status < 0)
223762306a36Sopenharmony_ci			break;
223862306a36Sopenharmony_ci
223962306a36Sopenharmony_ci		switch (DRX_CHANNEL_HIGH) {
224062306a36Sopenharmony_ci		default:
224162306a36Sopenharmony_ci		case DRX_CHANNEL_AUTO:
224262306a36Sopenharmony_ci		case DRX_CHANNEL_LOW:
224362306a36Sopenharmony_ci			transmissionParams |= SC_RA_RAM_OP_PARAM_PRIO_LO;
224462306a36Sopenharmony_ci			status = Write16(state, EC_SB_REG_PRIOR__A, EC_SB_REG_PRIOR_LO, 0x0000);
224562306a36Sopenharmony_ci			break;
224662306a36Sopenharmony_ci		case DRX_CHANNEL_HIGH:
224762306a36Sopenharmony_ci			transmissionParams |= SC_RA_RAM_OP_PARAM_PRIO_HI;
224862306a36Sopenharmony_ci			status = Write16(state, EC_SB_REG_PRIOR__A, EC_SB_REG_PRIOR_HI, 0x0000);
224962306a36Sopenharmony_ci			break;
225062306a36Sopenharmony_ci		}
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci		switch (p->code_rate_HP) {
225362306a36Sopenharmony_ci		case FEC_1_2:
225462306a36Sopenharmony_ci			transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_1_2;
225562306a36Sopenharmony_ci			if (state->type_A)
225662306a36Sopenharmony_ci				status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C1_2, 0x0000);
225762306a36Sopenharmony_ci			break;
225862306a36Sopenharmony_ci		default:
225962306a36Sopenharmony_ci			operationMode |= SC_RA_RAM_OP_AUTO_RATE__M;
226062306a36Sopenharmony_ci			fallthrough;
226162306a36Sopenharmony_ci		case FEC_2_3:
226262306a36Sopenharmony_ci			transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_2_3;
226362306a36Sopenharmony_ci			if (state->type_A)
226462306a36Sopenharmony_ci				status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C2_3, 0x0000);
226562306a36Sopenharmony_ci			break;
226662306a36Sopenharmony_ci		case FEC_3_4:
226762306a36Sopenharmony_ci			transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_3_4;
226862306a36Sopenharmony_ci			if (state->type_A)
226962306a36Sopenharmony_ci				status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C3_4, 0x0000);
227062306a36Sopenharmony_ci			break;
227162306a36Sopenharmony_ci		case FEC_5_6:
227262306a36Sopenharmony_ci			transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_5_6;
227362306a36Sopenharmony_ci			if (state->type_A)
227462306a36Sopenharmony_ci				status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C5_6, 0x0000);
227562306a36Sopenharmony_ci			break;
227662306a36Sopenharmony_ci		case FEC_7_8:
227762306a36Sopenharmony_ci			transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_7_8;
227862306a36Sopenharmony_ci			if (state->type_A)
227962306a36Sopenharmony_ci				status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C7_8, 0x0000);
228062306a36Sopenharmony_ci			break;
228162306a36Sopenharmony_ci		}
228262306a36Sopenharmony_ci		if (status < 0)
228362306a36Sopenharmony_ci			break;
228462306a36Sopenharmony_ci
228562306a36Sopenharmony_ci		/* First determine real bandwidth (Hz) */
228662306a36Sopenharmony_ci		/* Also set delay for impulse noise cruncher (only A2) */
228762306a36Sopenharmony_ci		/* Also set parameters for EC_OC fix, note
228862306a36Sopenharmony_ci		   EC_OC_REG_TMD_HIL_MAR is changed
228962306a36Sopenharmony_ci		   by SC for fix for some 8K,1/8 guard but is restored by
229062306a36Sopenharmony_ci		   InitEC and ResetEC
229162306a36Sopenharmony_ci		   functions */
229262306a36Sopenharmony_ci		switch (p->bandwidth_hz) {
229362306a36Sopenharmony_ci		case 0:
229462306a36Sopenharmony_ci			p->bandwidth_hz = 8000000;
229562306a36Sopenharmony_ci			fallthrough;
229662306a36Sopenharmony_ci		case 8000000:
229762306a36Sopenharmony_ci			/* (64/7)*(8/8)*1000000 */
229862306a36Sopenharmony_ci			bandwidth = DRXD_BANDWIDTH_8MHZ_IN_HZ;
229962306a36Sopenharmony_ci
230062306a36Sopenharmony_ci			bandwidthParam = 0;
230162306a36Sopenharmony_ci			status = Write16(state,
230262306a36Sopenharmony_ci					 FE_AG_REG_IND_DEL__A, 50, 0x0000);
230362306a36Sopenharmony_ci			break;
230462306a36Sopenharmony_ci		case 7000000:
230562306a36Sopenharmony_ci			/* (64/7)*(7/8)*1000000 */
230662306a36Sopenharmony_ci			bandwidth = DRXD_BANDWIDTH_7MHZ_IN_HZ;
230762306a36Sopenharmony_ci			bandwidthParam = 0x4807;	/*binary:0100 1000 0000 0111 */
230862306a36Sopenharmony_ci			status = Write16(state,
230962306a36Sopenharmony_ci					 FE_AG_REG_IND_DEL__A, 59, 0x0000);
231062306a36Sopenharmony_ci			break;
231162306a36Sopenharmony_ci		case 6000000:
231262306a36Sopenharmony_ci			/* (64/7)*(6/8)*1000000 */
231362306a36Sopenharmony_ci			bandwidth = DRXD_BANDWIDTH_6MHZ_IN_HZ;
231462306a36Sopenharmony_ci			bandwidthParam = 0x0F07;	/*binary: 0000 1111 0000 0111 */
231562306a36Sopenharmony_ci			status = Write16(state,
231662306a36Sopenharmony_ci					 FE_AG_REG_IND_DEL__A, 71, 0x0000);
231762306a36Sopenharmony_ci			break;
231862306a36Sopenharmony_ci		default:
231962306a36Sopenharmony_ci			status = -EINVAL;
232062306a36Sopenharmony_ci		}
232162306a36Sopenharmony_ci		if (status < 0)
232262306a36Sopenharmony_ci			break;
232362306a36Sopenharmony_ci
232462306a36Sopenharmony_ci		status = Write16(state, SC_RA_RAM_BAND__A, bandwidthParam, 0x0000);
232562306a36Sopenharmony_ci		if (status < 0)
232662306a36Sopenharmony_ci			break;
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_ci		{
232962306a36Sopenharmony_ci			u16 sc_config;
233062306a36Sopenharmony_ci			status = Read16(state, SC_RA_RAM_CONFIG__A, &sc_config, 0);
233162306a36Sopenharmony_ci			if (status < 0)
233262306a36Sopenharmony_ci				break;
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci			/* enable SLAVE mode in 2k 1/32 to
233562306a36Sopenharmony_ci			   prevent timing change glitches */
233662306a36Sopenharmony_ci			if ((p->transmission_mode == TRANSMISSION_MODE_2K) &&
233762306a36Sopenharmony_ci			    (p->guard_interval == GUARD_INTERVAL_1_32)) {
233862306a36Sopenharmony_ci				/* enable slave */
233962306a36Sopenharmony_ci				sc_config |= SC_RA_RAM_CONFIG_SLAVE__M;
234062306a36Sopenharmony_ci			} else {
234162306a36Sopenharmony_ci				/* disable slave */
234262306a36Sopenharmony_ci				sc_config &= ~SC_RA_RAM_CONFIG_SLAVE__M;
234362306a36Sopenharmony_ci			}
234462306a36Sopenharmony_ci			status = Write16(state, SC_RA_RAM_CONFIG__A, sc_config, 0);
234562306a36Sopenharmony_ci			if (status < 0)
234662306a36Sopenharmony_ci				break;
234762306a36Sopenharmony_ci		}
234862306a36Sopenharmony_ci
234962306a36Sopenharmony_ci		status = SetCfgNoiseCalibration(state, &state->noise_cal);
235062306a36Sopenharmony_ci		if (status < 0)
235162306a36Sopenharmony_ci			break;
235262306a36Sopenharmony_ci
235362306a36Sopenharmony_ci		if (state->cscd_state == CSCD_INIT) {
235462306a36Sopenharmony_ci			/* switch on SRMM scan in SC */
235562306a36Sopenharmony_ci			status = Write16(state, SC_RA_RAM_SAMPLE_RATE_COUNT__A, DRXD_OSCDEV_DO_SCAN, 0x0000);
235662306a36Sopenharmony_ci			if (status < 0)
235762306a36Sopenharmony_ci				break;
235862306a36Sopenharmony_ci/*            CHK_ERROR(Write16(SC_RA_RAM_SAMPLE_RATE_STEP__A, DRXD_OSCDEV_STEP, 0x0000));*/
235962306a36Sopenharmony_ci			state->cscd_state = CSCD_SET;
236062306a36Sopenharmony_ci		}
236162306a36Sopenharmony_ci
236262306a36Sopenharmony_ci		/* Now compute FE_IF_REG_INCR */
236362306a36Sopenharmony_ci		/*((( SysFreq/BandWidth)/2)/2) -1) * 2^23) =>
236462306a36Sopenharmony_ci		   ((SysFreq / BandWidth) * (2^21) ) - (2^23) */
236562306a36Sopenharmony_ci		feIfIncr = MulDiv32(state->sys_clock_freq * 1000,
236662306a36Sopenharmony_ci				    (1ULL << 21), bandwidth) - (1 << 23);
236762306a36Sopenharmony_ci		status = Write16(state, FE_IF_REG_INCR0__A, (u16) (feIfIncr & FE_IF_REG_INCR0__M), 0x0000);
236862306a36Sopenharmony_ci		if (status < 0)
236962306a36Sopenharmony_ci			break;
237062306a36Sopenharmony_ci		status = Write16(state, FE_IF_REG_INCR1__A, (u16) ((feIfIncr >> FE_IF_REG_INCR0__W) & FE_IF_REG_INCR1__M), 0x0000);
237162306a36Sopenharmony_ci		if (status < 0)
237262306a36Sopenharmony_ci			break;
237362306a36Sopenharmony_ci		/* Bandwidth setting done */
237462306a36Sopenharmony_ci
237562306a36Sopenharmony_ci		/* Mirror & frequency offset */
237662306a36Sopenharmony_ci		SetFrequencyShift(state, off, mirrorFreqSpect);
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ci		/* Start SC, write channel settings to SC */
237962306a36Sopenharmony_ci
238062306a36Sopenharmony_ci		/* Enable SC after setting all other parameters */
238162306a36Sopenharmony_ci		status = Write16(state, SC_COMM_STATE__A, 0, 0x0000);
238262306a36Sopenharmony_ci		if (status < 0)
238362306a36Sopenharmony_ci			break;
238462306a36Sopenharmony_ci		status = Write16(state, SC_COMM_EXEC__A, 1, 0x0000);
238562306a36Sopenharmony_ci		if (status < 0)
238662306a36Sopenharmony_ci			break;
238762306a36Sopenharmony_ci
238862306a36Sopenharmony_ci		/* Write SC parameter registers, operation mode */
238962306a36Sopenharmony_ci#if 1
239062306a36Sopenharmony_ci		operationMode = (SC_RA_RAM_OP_AUTO_MODE__M |
239162306a36Sopenharmony_ci				 SC_RA_RAM_OP_AUTO_GUARD__M |
239262306a36Sopenharmony_ci				 SC_RA_RAM_OP_AUTO_CONST__M |
239362306a36Sopenharmony_ci				 SC_RA_RAM_OP_AUTO_HIER__M |
239462306a36Sopenharmony_ci				 SC_RA_RAM_OP_AUTO_RATE__M);
239562306a36Sopenharmony_ci#endif
239662306a36Sopenharmony_ci		status = SC_SetPrefParamCommand(state, 0x0000, transmissionParams, operationMode);
239762306a36Sopenharmony_ci		if (status < 0)
239862306a36Sopenharmony_ci			break;
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_ci		/* Start correct processes to get in lock */
240162306a36Sopenharmony_ci		status = SC_ProcStartCommand(state, SC_RA_RAM_PROC_LOCKTRACK, SC_RA_RAM_SW_EVENT_RUN_NMASK__M, SC_RA_RAM_LOCKTRACK_MIN);
240262306a36Sopenharmony_ci		if (status < 0)
240362306a36Sopenharmony_ci			break;
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_ci		status = StartOC(state);
240662306a36Sopenharmony_ci		if (status < 0)
240762306a36Sopenharmony_ci			break;
240862306a36Sopenharmony_ci
240962306a36Sopenharmony_ci		if (state->operation_mode != OM_Default) {
241062306a36Sopenharmony_ci			status = StartDiversity(state);
241162306a36Sopenharmony_ci			if (status < 0)
241262306a36Sopenharmony_ci				break;
241362306a36Sopenharmony_ci		}
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_ci		state->drxd_state = DRXD_STARTED;
241662306a36Sopenharmony_ci	} while (0);
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_ci	return status;
241962306a36Sopenharmony_ci}
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_cistatic int CDRXD(struct drxd_state *state, u32 IntermediateFrequency)
242262306a36Sopenharmony_ci{
242362306a36Sopenharmony_ci	u32 ulRfAgcOutputLevel = 0xffffffff;
242462306a36Sopenharmony_ci	u32 ulRfAgcSettleLevel = 528;	/* Optimum value for MT2060 */
242562306a36Sopenharmony_ci	u32 ulRfAgcMinLevel = 0;	/* Currently unused */
242662306a36Sopenharmony_ci	u32 ulRfAgcMaxLevel = DRXD_FE_CTRL_MAX;	/* Currently unused */
242762306a36Sopenharmony_ci	u32 ulRfAgcSpeed = 0;	/* Currently unused */
242862306a36Sopenharmony_ci	u32 ulRfAgcMode = 0;	/*2;   Off */
242962306a36Sopenharmony_ci	u32 ulRfAgcR1 = 820;
243062306a36Sopenharmony_ci	u32 ulRfAgcR2 = 2200;
243162306a36Sopenharmony_ci	u32 ulRfAgcR3 = 150;
243262306a36Sopenharmony_ci	u32 ulIfAgcMode = 0;	/* Auto */
243362306a36Sopenharmony_ci	u32 ulIfAgcOutputLevel = 0xffffffff;
243462306a36Sopenharmony_ci	u32 ulIfAgcSettleLevel = 0xffffffff;
243562306a36Sopenharmony_ci	u32 ulIfAgcMinLevel = 0xffffffff;
243662306a36Sopenharmony_ci	u32 ulIfAgcMaxLevel = 0xffffffff;
243762306a36Sopenharmony_ci	u32 ulIfAgcSpeed = 0xffffffff;
243862306a36Sopenharmony_ci	u32 ulIfAgcR1 = 820;
243962306a36Sopenharmony_ci	u32 ulIfAgcR2 = 2200;
244062306a36Sopenharmony_ci	u32 ulIfAgcR3 = 150;
244162306a36Sopenharmony_ci	u32 ulClock = state->config.clock;
244262306a36Sopenharmony_ci	u32 ulSerialMode = 0;
244362306a36Sopenharmony_ci	u32 ulEcOcRegOcModeLop = 4;	/* Dynamic DTO source */
244462306a36Sopenharmony_ci	u32 ulHiI2cDelay = HI_I2C_DELAY;
244562306a36Sopenharmony_ci	u32 ulHiI2cBridgeDelay = HI_I2C_BRIDGE_DELAY;
244662306a36Sopenharmony_ci	u32 ulHiI2cPatch = 0;
244762306a36Sopenharmony_ci	u32 ulEnvironment = APPENV_PORTABLE;
244862306a36Sopenharmony_ci	u32 ulEnvironmentDiversity = APPENV_MOBILE;
244962306a36Sopenharmony_ci	u32 ulIFFilter = IFFILTER_SAW;
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci	state->if_agc_cfg.ctrlMode = AGC_CTRL_AUTO;
245262306a36Sopenharmony_ci	state->if_agc_cfg.outputLevel = 0;
245362306a36Sopenharmony_ci	state->if_agc_cfg.settleLevel = 140;
245462306a36Sopenharmony_ci	state->if_agc_cfg.minOutputLevel = 0;
245562306a36Sopenharmony_ci	state->if_agc_cfg.maxOutputLevel = 1023;
245662306a36Sopenharmony_ci	state->if_agc_cfg.speed = 904;
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ci	if (ulIfAgcMode == 1 && ulIfAgcOutputLevel <= DRXD_FE_CTRL_MAX) {
245962306a36Sopenharmony_ci		state->if_agc_cfg.ctrlMode = AGC_CTRL_USER;
246062306a36Sopenharmony_ci		state->if_agc_cfg.outputLevel = (u16) (ulIfAgcOutputLevel);
246162306a36Sopenharmony_ci	}
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci	if (ulIfAgcMode == 0 &&
246462306a36Sopenharmony_ci	    ulIfAgcSettleLevel <= DRXD_FE_CTRL_MAX &&
246562306a36Sopenharmony_ci	    ulIfAgcMinLevel <= DRXD_FE_CTRL_MAX &&
246662306a36Sopenharmony_ci	    ulIfAgcMaxLevel <= DRXD_FE_CTRL_MAX &&
246762306a36Sopenharmony_ci	    ulIfAgcSpeed <= DRXD_FE_CTRL_MAX) {
246862306a36Sopenharmony_ci		state->if_agc_cfg.ctrlMode = AGC_CTRL_AUTO;
246962306a36Sopenharmony_ci		state->if_agc_cfg.settleLevel = (u16) (ulIfAgcSettleLevel);
247062306a36Sopenharmony_ci		state->if_agc_cfg.minOutputLevel = (u16) (ulIfAgcMinLevel);
247162306a36Sopenharmony_ci		state->if_agc_cfg.maxOutputLevel = (u16) (ulIfAgcMaxLevel);
247262306a36Sopenharmony_ci		state->if_agc_cfg.speed = (u16) (ulIfAgcSpeed);
247362306a36Sopenharmony_ci	}
247462306a36Sopenharmony_ci
247562306a36Sopenharmony_ci	state->if_agc_cfg.R1 = (u16) (ulIfAgcR1);
247662306a36Sopenharmony_ci	state->if_agc_cfg.R2 = (u16) (ulIfAgcR2);
247762306a36Sopenharmony_ci	state->if_agc_cfg.R3 = (u16) (ulIfAgcR3);
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci	state->rf_agc_cfg.R1 = (u16) (ulRfAgcR1);
248062306a36Sopenharmony_ci	state->rf_agc_cfg.R2 = (u16) (ulRfAgcR2);
248162306a36Sopenharmony_ci	state->rf_agc_cfg.R3 = (u16) (ulRfAgcR3);
248262306a36Sopenharmony_ci
248362306a36Sopenharmony_ci	state->rf_agc_cfg.ctrlMode = AGC_CTRL_AUTO;
248462306a36Sopenharmony_ci	/* rest of the RFAgcCfg structure currently unused */
248562306a36Sopenharmony_ci	if (ulRfAgcMode == 1 && ulRfAgcOutputLevel <= DRXD_FE_CTRL_MAX) {
248662306a36Sopenharmony_ci		state->rf_agc_cfg.ctrlMode = AGC_CTRL_USER;
248762306a36Sopenharmony_ci		state->rf_agc_cfg.outputLevel = (u16) (ulRfAgcOutputLevel);
248862306a36Sopenharmony_ci	}
248962306a36Sopenharmony_ci
249062306a36Sopenharmony_ci	if (ulRfAgcMode == 0 &&
249162306a36Sopenharmony_ci	    ulRfAgcSettleLevel <= DRXD_FE_CTRL_MAX &&
249262306a36Sopenharmony_ci	    ulRfAgcMinLevel <= DRXD_FE_CTRL_MAX &&
249362306a36Sopenharmony_ci	    ulRfAgcMaxLevel <= DRXD_FE_CTRL_MAX &&
249462306a36Sopenharmony_ci	    ulRfAgcSpeed <= DRXD_FE_CTRL_MAX) {
249562306a36Sopenharmony_ci		state->rf_agc_cfg.ctrlMode = AGC_CTRL_AUTO;
249662306a36Sopenharmony_ci		state->rf_agc_cfg.settleLevel = (u16) (ulRfAgcSettleLevel);
249762306a36Sopenharmony_ci		state->rf_agc_cfg.minOutputLevel = (u16) (ulRfAgcMinLevel);
249862306a36Sopenharmony_ci		state->rf_agc_cfg.maxOutputLevel = (u16) (ulRfAgcMaxLevel);
249962306a36Sopenharmony_ci		state->rf_agc_cfg.speed = (u16) (ulRfAgcSpeed);
250062306a36Sopenharmony_ci	}
250162306a36Sopenharmony_ci
250262306a36Sopenharmony_ci	if (ulRfAgcMode == 2)
250362306a36Sopenharmony_ci		state->rf_agc_cfg.ctrlMode = AGC_CTRL_OFF;
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci	if (ulEnvironment <= 2)
250662306a36Sopenharmony_ci		state->app_env_default = (enum app_env)
250762306a36Sopenharmony_ci		    (ulEnvironment);
250862306a36Sopenharmony_ci	if (ulEnvironmentDiversity <= 2)
250962306a36Sopenharmony_ci		state->app_env_diversity = (enum app_env)
251062306a36Sopenharmony_ci		    (ulEnvironmentDiversity);
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_ci	if (ulIFFilter == IFFILTER_DISCRETE) {
251362306a36Sopenharmony_ci		/* discrete filter */
251462306a36Sopenharmony_ci		state->noise_cal.cpOpt = 0;
251562306a36Sopenharmony_ci		state->noise_cal.cpNexpOfs = 40;
251662306a36Sopenharmony_ci		state->noise_cal.tdCal2k = -40;
251762306a36Sopenharmony_ci		state->noise_cal.tdCal8k = -24;
251862306a36Sopenharmony_ci	} else {
251962306a36Sopenharmony_ci		/* SAW filter */
252062306a36Sopenharmony_ci		state->noise_cal.cpOpt = 1;
252162306a36Sopenharmony_ci		state->noise_cal.cpNexpOfs = 0;
252262306a36Sopenharmony_ci		state->noise_cal.tdCal2k = -21;
252362306a36Sopenharmony_ci		state->noise_cal.tdCal8k = -24;
252462306a36Sopenharmony_ci	}
252562306a36Sopenharmony_ci	state->m_EcOcRegOcModeLop = (u16) (ulEcOcRegOcModeLop);
252662306a36Sopenharmony_ci
252762306a36Sopenharmony_ci	state->chip_adr = (state->config.demod_address << 1) | 1;
252862306a36Sopenharmony_ci	switch (ulHiI2cPatch) {
252962306a36Sopenharmony_ci	case 1:
253062306a36Sopenharmony_ci		state->m_HiI2cPatch = DRXD_HiI2cPatch_1;
253162306a36Sopenharmony_ci		break;
253262306a36Sopenharmony_ci	case 3:
253362306a36Sopenharmony_ci		state->m_HiI2cPatch = DRXD_HiI2cPatch_3;
253462306a36Sopenharmony_ci		break;
253562306a36Sopenharmony_ci	default:
253662306a36Sopenharmony_ci		state->m_HiI2cPatch = NULL;
253762306a36Sopenharmony_ci	}
253862306a36Sopenharmony_ci
253962306a36Sopenharmony_ci	/* modify tuner and clock attributes */
254062306a36Sopenharmony_ci	state->intermediate_freq = (u16) (IntermediateFrequency / 1000);
254162306a36Sopenharmony_ci	/* expected system clock frequency in kHz */
254262306a36Sopenharmony_ci	state->expected_sys_clock_freq = 48000;
254362306a36Sopenharmony_ci	/* real system clock frequency in kHz */
254462306a36Sopenharmony_ci	state->sys_clock_freq = 48000;
254562306a36Sopenharmony_ci	state->osc_clock_freq = (u16) ulClock;
254662306a36Sopenharmony_ci	state->osc_clock_deviation = 0;
254762306a36Sopenharmony_ci	state->cscd_state = CSCD_INIT;
254862306a36Sopenharmony_ci	state->drxd_state = DRXD_UNINITIALIZED;
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_ci	state->PGA = 0;
255162306a36Sopenharmony_ci	state->type_A = 0;
255262306a36Sopenharmony_ci	state->tuner_mirrors = 0;
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_ci	/* modify MPEG output attributes */
255562306a36Sopenharmony_ci	state->insert_rs_byte = state->config.insert_rs_byte;
255662306a36Sopenharmony_ci	state->enable_parallel = (ulSerialMode != 1);
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci	/* Timing div, 250ns/Psys */
255962306a36Sopenharmony_ci	/* Timing div, = ( delay (nano seconds) * sysclk (kHz) )/ 1000 */
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci	state->hi_cfg_timing_div = (u16) ((state->sys_clock_freq / 1000) *
256262306a36Sopenharmony_ci					  ulHiI2cDelay) / 1000;
256362306a36Sopenharmony_ci	/* Bridge delay, uses oscilator clock */
256462306a36Sopenharmony_ci	/* Delay = ( delay (nano seconds) * oscclk (kHz) )/ 1000 */
256562306a36Sopenharmony_ci	state->hi_cfg_bridge_delay = (u16) ((state->osc_clock_freq / 1000) *
256662306a36Sopenharmony_ci					    ulHiI2cBridgeDelay) / 1000;
256762306a36Sopenharmony_ci
256862306a36Sopenharmony_ci	state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_CONSUMER;
256962306a36Sopenharmony_ci	/* state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_PRO; */
257062306a36Sopenharmony_ci	state->m_FeAgRegAgAgcSio = DRXD_DEF_AG_AGC_SIO;
257162306a36Sopenharmony_ci	return 0;
257262306a36Sopenharmony_ci}
257362306a36Sopenharmony_ci
257462306a36Sopenharmony_cistatic int DRXD_init(struct drxd_state *state, const u8 *fw, u32 fw_size)
257562306a36Sopenharmony_ci{
257662306a36Sopenharmony_ci	int status = 0;
257762306a36Sopenharmony_ci	u32 driverVersion;
257862306a36Sopenharmony_ci
257962306a36Sopenharmony_ci	if (state->init_done)
258062306a36Sopenharmony_ci		return 0;
258162306a36Sopenharmony_ci
258262306a36Sopenharmony_ci	CDRXD(state, state->config.IF ? state->config.IF : 36000000);
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci	do {
258562306a36Sopenharmony_ci		state->operation_mode = OM_Default;
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ci		status = SetDeviceTypeId(state);
258862306a36Sopenharmony_ci		if (status < 0)
258962306a36Sopenharmony_ci			break;
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_ci		/* Apply I2c address patch to B1 */
259262306a36Sopenharmony_ci		if (!state->type_A && state->m_HiI2cPatch) {
259362306a36Sopenharmony_ci			status = WriteTable(state, state->m_HiI2cPatch);
259462306a36Sopenharmony_ci			if (status < 0)
259562306a36Sopenharmony_ci				break;
259662306a36Sopenharmony_ci		}
259762306a36Sopenharmony_ci
259862306a36Sopenharmony_ci		if (state->type_A) {
259962306a36Sopenharmony_ci			/* HI firmware patch for UIO readout,
260062306a36Sopenharmony_ci			   avoid clearing of result register */
260162306a36Sopenharmony_ci			status = Write16(state, 0x43012D, 0x047f, 0);
260262306a36Sopenharmony_ci			if (status < 0)
260362306a36Sopenharmony_ci				break;
260462306a36Sopenharmony_ci		}
260562306a36Sopenharmony_ci
260662306a36Sopenharmony_ci		status = HI_ResetCommand(state);
260762306a36Sopenharmony_ci		if (status < 0)
260862306a36Sopenharmony_ci			break;
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_ci		status = StopAllProcessors(state);
261162306a36Sopenharmony_ci		if (status < 0)
261262306a36Sopenharmony_ci			break;
261362306a36Sopenharmony_ci		status = InitCC(state);
261462306a36Sopenharmony_ci		if (status < 0)
261562306a36Sopenharmony_ci			break;
261662306a36Sopenharmony_ci
261762306a36Sopenharmony_ci		state->osc_clock_deviation = 0;
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_ci		if (state->config.osc_deviation)
262062306a36Sopenharmony_ci			state->osc_clock_deviation =
262162306a36Sopenharmony_ci			    state->config.osc_deviation(state->priv, 0, 0);
262262306a36Sopenharmony_ci		{
262362306a36Sopenharmony_ci			/* Handle clock deviation */
262462306a36Sopenharmony_ci			s32 devB;
262562306a36Sopenharmony_ci			s32 devA = (s32) (state->osc_clock_deviation) *
262662306a36Sopenharmony_ci			    (s32) (state->expected_sys_clock_freq);
262762306a36Sopenharmony_ci			/* deviation in kHz */
262862306a36Sopenharmony_ci			s32 deviation = (devA / (1000000L));
262962306a36Sopenharmony_ci			/* rounding, signed */
263062306a36Sopenharmony_ci			if (devA > 0)
263162306a36Sopenharmony_ci				devB = (2);
263262306a36Sopenharmony_ci			else
263362306a36Sopenharmony_ci				devB = (-2);
263462306a36Sopenharmony_ci			if ((devB * (devA % 1000000L) > 1000000L)) {
263562306a36Sopenharmony_ci				/* add +1 or -1 */
263662306a36Sopenharmony_ci				deviation += (devB / 2);
263762306a36Sopenharmony_ci			}
263862306a36Sopenharmony_ci
263962306a36Sopenharmony_ci			state->sys_clock_freq =
264062306a36Sopenharmony_ci			    (u16) ((state->expected_sys_clock_freq) +
264162306a36Sopenharmony_ci				   deviation);
264262306a36Sopenharmony_ci		}
264362306a36Sopenharmony_ci		status = InitHI(state);
264462306a36Sopenharmony_ci		if (status < 0)
264562306a36Sopenharmony_ci			break;
264662306a36Sopenharmony_ci		status = InitAtomicRead(state);
264762306a36Sopenharmony_ci		if (status < 0)
264862306a36Sopenharmony_ci			break;
264962306a36Sopenharmony_ci
265062306a36Sopenharmony_ci		status = EnableAndResetMB(state);
265162306a36Sopenharmony_ci		if (status < 0)
265262306a36Sopenharmony_ci			break;
265362306a36Sopenharmony_ci		if (state->type_A) {
265462306a36Sopenharmony_ci			status = ResetCEFR(state);
265562306a36Sopenharmony_ci			if (status < 0)
265662306a36Sopenharmony_ci				break;
265762306a36Sopenharmony_ci		}
265862306a36Sopenharmony_ci		if (fw) {
265962306a36Sopenharmony_ci			status = DownloadMicrocode(state, fw, fw_size);
266062306a36Sopenharmony_ci			if (status < 0)
266162306a36Sopenharmony_ci				break;
266262306a36Sopenharmony_ci		} else {
266362306a36Sopenharmony_ci			status = DownloadMicrocode(state, state->microcode, state->microcode_length);
266462306a36Sopenharmony_ci			if (status < 0)
266562306a36Sopenharmony_ci				break;
266662306a36Sopenharmony_ci		}
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_ci		if (state->PGA) {
266962306a36Sopenharmony_ci			state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_PRO;
267062306a36Sopenharmony_ci			SetCfgPga(state, 0);	/* PGA = 0 dB */
267162306a36Sopenharmony_ci		} else {
267262306a36Sopenharmony_ci			state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_CONSUMER;
267362306a36Sopenharmony_ci		}
267462306a36Sopenharmony_ci
267562306a36Sopenharmony_ci		state->m_FeAgRegAgAgcSio = DRXD_DEF_AG_AGC_SIO;
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci		status = InitFE(state);
267862306a36Sopenharmony_ci		if (status < 0)
267962306a36Sopenharmony_ci			break;
268062306a36Sopenharmony_ci		status = InitFT(state);
268162306a36Sopenharmony_ci		if (status < 0)
268262306a36Sopenharmony_ci			break;
268362306a36Sopenharmony_ci		status = InitCP(state);
268462306a36Sopenharmony_ci		if (status < 0)
268562306a36Sopenharmony_ci			break;
268662306a36Sopenharmony_ci		status = InitCE(state);
268762306a36Sopenharmony_ci		if (status < 0)
268862306a36Sopenharmony_ci			break;
268962306a36Sopenharmony_ci		status = InitEQ(state);
269062306a36Sopenharmony_ci		if (status < 0)
269162306a36Sopenharmony_ci			break;
269262306a36Sopenharmony_ci		status = InitEC(state);
269362306a36Sopenharmony_ci		if (status < 0)
269462306a36Sopenharmony_ci			break;
269562306a36Sopenharmony_ci		status = InitSC(state);
269662306a36Sopenharmony_ci		if (status < 0)
269762306a36Sopenharmony_ci			break;
269862306a36Sopenharmony_ci
269962306a36Sopenharmony_ci		status = SetCfgIfAgc(state, &state->if_agc_cfg);
270062306a36Sopenharmony_ci		if (status < 0)
270162306a36Sopenharmony_ci			break;
270262306a36Sopenharmony_ci		status = SetCfgRfAgc(state, &state->rf_agc_cfg);
270362306a36Sopenharmony_ci		if (status < 0)
270462306a36Sopenharmony_ci			break;
270562306a36Sopenharmony_ci
270662306a36Sopenharmony_ci		state->cscd_state = CSCD_INIT;
270762306a36Sopenharmony_ci		status = Write16(state, SC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
270862306a36Sopenharmony_ci		if (status < 0)
270962306a36Sopenharmony_ci			break;
271062306a36Sopenharmony_ci		status = Write16(state, LC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
271162306a36Sopenharmony_ci		if (status < 0)
271262306a36Sopenharmony_ci			break;
271362306a36Sopenharmony_ci
271462306a36Sopenharmony_ci		driverVersion = (((VERSION_MAJOR / 10) << 4) +
271562306a36Sopenharmony_ci				 (VERSION_MAJOR % 10)) << 24;
271662306a36Sopenharmony_ci		driverVersion += (((VERSION_MINOR / 10) << 4) +
271762306a36Sopenharmony_ci				  (VERSION_MINOR % 10)) << 16;
271862306a36Sopenharmony_ci		driverVersion += ((VERSION_PATCH / 1000) << 12) +
271962306a36Sopenharmony_ci		    ((VERSION_PATCH / 100) << 8) +
272062306a36Sopenharmony_ci		    ((VERSION_PATCH / 10) << 4) + (VERSION_PATCH % 10);
272162306a36Sopenharmony_ci
272262306a36Sopenharmony_ci		status = Write32(state, SC_RA_RAM_DRIVER_VERSION__AX, driverVersion, 0);
272362306a36Sopenharmony_ci		if (status < 0)
272462306a36Sopenharmony_ci			break;
272562306a36Sopenharmony_ci
272662306a36Sopenharmony_ci		status = StopOC(state);
272762306a36Sopenharmony_ci		if (status < 0)
272862306a36Sopenharmony_ci			break;
272962306a36Sopenharmony_ci
273062306a36Sopenharmony_ci		state->drxd_state = DRXD_STOPPED;
273162306a36Sopenharmony_ci		state->init_done = 1;
273262306a36Sopenharmony_ci		status = 0;
273362306a36Sopenharmony_ci	} while (0);
273462306a36Sopenharmony_ci	return status;
273562306a36Sopenharmony_ci}
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_cistatic int DRXD_status(struct drxd_state *state, u32 *pLockStatus)
273862306a36Sopenharmony_ci{
273962306a36Sopenharmony_ci	DRX_GetLockStatus(state, pLockStatus);
274062306a36Sopenharmony_ci
274162306a36Sopenharmony_ci	/*if (*pLockStatus&DRX_LOCK_MPEG) */
274262306a36Sopenharmony_ci	if (*pLockStatus & DRX_LOCK_FEC) {
274362306a36Sopenharmony_ci		ConfigureMPEGOutput(state, 1);
274462306a36Sopenharmony_ci		/* Get status again, in case we have MPEG lock now */
274562306a36Sopenharmony_ci		/*DRX_GetLockStatus(state, pLockStatus); */
274662306a36Sopenharmony_ci	}
274762306a36Sopenharmony_ci
274862306a36Sopenharmony_ci	return 0;
274962306a36Sopenharmony_ci}
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci/****************************************************************************/
275262306a36Sopenharmony_ci/****************************************************************************/
275362306a36Sopenharmony_ci/****************************************************************************/
275462306a36Sopenharmony_ci
275562306a36Sopenharmony_cistatic int drxd_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
275662306a36Sopenharmony_ci{
275762306a36Sopenharmony_ci	struct drxd_state *state = fe->demodulator_priv;
275862306a36Sopenharmony_ci	u32 value;
275962306a36Sopenharmony_ci	int res;
276062306a36Sopenharmony_ci
276162306a36Sopenharmony_ci	res = ReadIFAgc(state, &value);
276262306a36Sopenharmony_ci	if (res < 0)
276362306a36Sopenharmony_ci		*strength = 0;
276462306a36Sopenharmony_ci	else
276562306a36Sopenharmony_ci		*strength = 0xffff - (value << 4);
276662306a36Sopenharmony_ci	return 0;
276762306a36Sopenharmony_ci}
276862306a36Sopenharmony_ci
276962306a36Sopenharmony_cistatic int drxd_read_status(struct dvb_frontend *fe, enum fe_status *status)
277062306a36Sopenharmony_ci{
277162306a36Sopenharmony_ci	struct drxd_state *state = fe->demodulator_priv;
277262306a36Sopenharmony_ci	u32 lock;
277362306a36Sopenharmony_ci
277462306a36Sopenharmony_ci	DRXD_status(state, &lock);
277562306a36Sopenharmony_ci	*status = 0;
277662306a36Sopenharmony_ci	/* No MPEG lock in V255 firmware, bug ? */
277762306a36Sopenharmony_ci#if 1
277862306a36Sopenharmony_ci	if (lock & DRX_LOCK_MPEG)
277962306a36Sopenharmony_ci		*status |= FE_HAS_LOCK;
278062306a36Sopenharmony_ci#else
278162306a36Sopenharmony_ci	if (lock & DRX_LOCK_FEC)
278262306a36Sopenharmony_ci		*status |= FE_HAS_LOCK;
278362306a36Sopenharmony_ci#endif
278462306a36Sopenharmony_ci	if (lock & DRX_LOCK_FEC)
278562306a36Sopenharmony_ci		*status |= FE_HAS_VITERBI | FE_HAS_SYNC;
278662306a36Sopenharmony_ci	if (lock & DRX_LOCK_DEMOD)
278762306a36Sopenharmony_ci		*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
278862306a36Sopenharmony_ci
278962306a36Sopenharmony_ci	return 0;
279062306a36Sopenharmony_ci}
279162306a36Sopenharmony_ci
279262306a36Sopenharmony_cistatic int drxd_init(struct dvb_frontend *fe)
279362306a36Sopenharmony_ci{
279462306a36Sopenharmony_ci	struct drxd_state *state = fe->demodulator_priv;
279562306a36Sopenharmony_ci
279662306a36Sopenharmony_ci	return DRXD_init(state, NULL, 0);
279762306a36Sopenharmony_ci}
279862306a36Sopenharmony_ci
279962306a36Sopenharmony_cistatic int drxd_config_i2c(struct dvb_frontend *fe, int onoff)
280062306a36Sopenharmony_ci{
280162306a36Sopenharmony_ci	struct drxd_state *state = fe->demodulator_priv;
280262306a36Sopenharmony_ci
280362306a36Sopenharmony_ci	if (state->config.disable_i2c_gate_ctrl == 1)
280462306a36Sopenharmony_ci		return 0;
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci	return DRX_ConfigureI2CBridge(state, onoff);
280762306a36Sopenharmony_ci}
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_cistatic int drxd_get_tune_settings(struct dvb_frontend *fe,
281062306a36Sopenharmony_ci				  struct dvb_frontend_tune_settings *sets)
281162306a36Sopenharmony_ci{
281262306a36Sopenharmony_ci	sets->min_delay_ms = 10000;
281362306a36Sopenharmony_ci	sets->max_drift = 0;
281462306a36Sopenharmony_ci	sets->step_size = 0;
281562306a36Sopenharmony_ci	return 0;
281662306a36Sopenharmony_ci}
281762306a36Sopenharmony_ci
281862306a36Sopenharmony_cistatic int drxd_read_ber(struct dvb_frontend *fe, u32 * ber)
281962306a36Sopenharmony_ci{
282062306a36Sopenharmony_ci	*ber = 0;
282162306a36Sopenharmony_ci	return 0;
282262306a36Sopenharmony_ci}
282362306a36Sopenharmony_ci
282462306a36Sopenharmony_cistatic int drxd_read_snr(struct dvb_frontend *fe, u16 * snr)
282562306a36Sopenharmony_ci{
282662306a36Sopenharmony_ci	*snr = 0;
282762306a36Sopenharmony_ci	return 0;
282862306a36Sopenharmony_ci}
282962306a36Sopenharmony_ci
283062306a36Sopenharmony_cistatic int drxd_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks)
283162306a36Sopenharmony_ci{
283262306a36Sopenharmony_ci	*ucblocks = 0;
283362306a36Sopenharmony_ci	return 0;
283462306a36Sopenharmony_ci}
283562306a36Sopenharmony_ci
283662306a36Sopenharmony_cistatic int drxd_sleep(struct dvb_frontend *fe)
283762306a36Sopenharmony_ci{
283862306a36Sopenharmony_ci	struct drxd_state *state = fe->demodulator_priv;
283962306a36Sopenharmony_ci
284062306a36Sopenharmony_ci	ConfigureMPEGOutput(state, 0);
284162306a36Sopenharmony_ci	return 0;
284262306a36Sopenharmony_ci}
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_cistatic int drxd_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
284562306a36Sopenharmony_ci{
284662306a36Sopenharmony_ci	return drxd_config_i2c(fe, enable);
284762306a36Sopenharmony_ci}
284862306a36Sopenharmony_ci
284962306a36Sopenharmony_cistatic int drxd_set_frontend(struct dvb_frontend *fe)
285062306a36Sopenharmony_ci{
285162306a36Sopenharmony_ci	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
285262306a36Sopenharmony_ci	struct drxd_state *state = fe->demodulator_priv;
285362306a36Sopenharmony_ci	s32 off = 0;
285462306a36Sopenharmony_ci
285562306a36Sopenharmony_ci	state->props = *p;
285662306a36Sopenharmony_ci	DRX_Stop(state);
285762306a36Sopenharmony_ci
285862306a36Sopenharmony_ci	if (fe->ops.tuner_ops.set_params) {
285962306a36Sopenharmony_ci		fe->ops.tuner_ops.set_params(fe);
286062306a36Sopenharmony_ci		if (fe->ops.i2c_gate_ctrl)
286162306a36Sopenharmony_ci			fe->ops.i2c_gate_ctrl(fe, 0);
286262306a36Sopenharmony_ci	}
286362306a36Sopenharmony_ci
286462306a36Sopenharmony_ci	msleep(200);
286562306a36Sopenharmony_ci
286662306a36Sopenharmony_ci	return DRX_Start(state, off);
286762306a36Sopenharmony_ci}
286862306a36Sopenharmony_ci
286962306a36Sopenharmony_cistatic void drxd_release(struct dvb_frontend *fe)
287062306a36Sopenharmony_ci{
287162306a36Sopenharmony_ci	struct drxd_state *state = fe->demodulator_priv;
287262306a36Sopenharmony_ci
287362306a36Sopenharmony_ci	kfree(state);
287462306a36Sopenharmony_ci}
287562306a36Sopenharmony_ci
287662306a36Sopenharmony_cistatic const struct dvb_frontend_ops drxd_ops = {
287762306a36Sopenharmony_ci	.delsys = { SYS_DVBT},
287862306a36Sopenharmony_ci	.info = {
287962306a36Sopenharmony_ci		 .name = "Micronas DRXD DVB-T",
288062306a36Sopenharmony_ci		 .frequency_min_hz =  47125 * kHz,
288162306a36Sopenharmony_ci		 .frequency_max_hz = 855250 * kHz,
288262306a36Sopenharmony_ci		 .frequency_stepsize_hz = 166667,
288362306a36Sopenharmony_ci		 .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
288462306a36Sopenharmony_ci		 FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
288562306a36Sopenharmony_ci		 FE_CAN_FEC_AUTO |
288662306a36Sopenharmony_ci		 FE_CAN_QAM_16 | FE_CAN_QAM_64 |
288762306a36Sopenharmony_ci		 FE_CAN_QAM_AUTO |
288862306a36Sopenharmony_ci		 FE_CAN_TRANSMISSION_MODE_AUTO |
288962306a36Sopenharmony_ci		 FE_CAN_GUARD_INTERVAL_AUTO |
289062306a36Sopenharmony_ci		 FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | FE_CAN_MUTE_TS},
289162306a36Sopenharmony_ci
289262306a36Sopenharmony_ci	.release = drxd_release,
289362306a36Sopenharmony_ci	.init = drxd_init,
289462306a36Sopenharmony_ci	.sleep = drxd_sleep,
289562306a36Sopenharmony_ci	.i2c_gate_ctrl = drxd_i2c_gate_ctrl,
289662306a36Sopenharmony_ci
289762306a36Sopenharmony_ci	.set_frontend = drxd_set_frontend,
289862306a36Sopenharmony_ci	.get_tune_settings = drxd_get_tune_settings,
289962306a36Sopenharmony_ci
290062306a36Sopenharmony_ci	.read_status = drxd_read_status,
290162306a36Sopenharmony_ci	.read_ber = drxd_read_ber,
290262306a36Sopenharmony_ci	.read_signal_strength = drxd_read_signal_strength,
290362306a36Sopenharmony_ci	.read_snr = drxd_read_snr,
290462306a36Sopenharmony_ci	.read_ucblocks = drxd_read_ucblocks,
290562306a36Sopenharmony_ci};
290662306a36Sopenharmony_ci
290762306a36Sopenharmony_cistruct dvb_frontend *drxd_attach(const struct drxd_config *config,
290862306a36Sopenharmony_ci				 void *priv, struct i2c_adapter *i2c,
290962306a36Sopenharmony_ci				 struct device *dev)
291062306a36Sopenharmony_ci{
291162306a36Sopenharmony_ci	struct drxd_state *state = NULL;
291262306a36Sopenharmony_ci
291362306a36Sopenharmony_ci	state = kzalloc(sizeof(*state), GFP_KERNEL);
291462306a36Sopenharmony_ci	if (!state)
291562306a36Sopenharmony_ci		return NULL;
291662306a36Sopenharmony_ci
291762306a36Sopenharmony_ci	state->ops = drxd_ops;
291862306a36Sopenharmony_ci	state->dev = dev;
291962306a36Sopenharmony_ci	state->config = *config;
292062306a36Sopenharmony_ci	state->i2c = i2c;
292162306a36Sopenharmony_ci	state->priv = priv;
292262306a36Sopenharmony_ci
292362306a36Sopenharmony_ci	mutex_init(&state->mutex);
292462306a36Sopenharmony_ci
292562306a36Sopenharmony_ci	if (Read16(state, 0, NULL, 0) < 0)
292662306a36Sopenharmony_ci		goto error;
292762306a36Sopenharmony_ci
292862306a36Sopenharmony_ci	state->frontend.ops = drxd_ops;
292962306a36Sopenharmony_ci	state->frontend.demodulator_priv = state;
293062306a36Sopenharmony_ci	ConfigureMPEGOutput(state, 0);
293162306a36Sopenharmony_ci	/* add few initialization to allow gate control */
293262306a36Sopenharmony_ci	CDRXD(state, state->config.IF ? state->config.IF : 36000000);
293362306a36Sopenharmony_ci	InitHI(state);
293462306a36Sopenharmony_ci
293562306a36Sopenharmony_ci	return &state->frontend;
293662306a36Sopenharmony_ci
293762306a36Sopenharmony_cierror:
293862306a36Sopenharmony_ci	printk(KERN_ERR "drxd: not found\n");
293962306a36Sopenharmony_ci	kfree(state);
294062306a36Sopenharmony_ci	return NULL;
294162306a36Sopenharmony_ci}
294262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(drxd_attach);
294362306a36Sopenharmony_ci
294462306a36Sopenharmony_ciMODULE_DESCRIPTION("DRXD driver");
294562306a36Sopenharmony_ciMODULE_AUTHOR("Micronas");
294662306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2947