162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * (c) 2005 Hartmut Hackmann
562306a36Sopenharmony_ci * (c) 2007 Michael Krufky
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/slab.h>
1062306a36Sopenharmony_ci#include <asm/types.h>
1162306a36Sopenharmony_ci#include <linux/dvb/frontend.h>
1262306a36Sopenharmony_ci#include <linux/videodev2.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include "tda827x.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic int debug;
1762306a36Sopenharmony_cimodule_param(debug, int, 0644);
1862306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define dprintk(args...) \
2162306a36Sopenharmony_ci	do {					    \
2262306a36Sopenharmony_ci		if (debug) printk(KERN_DEBUG "tda827x: " args); \
2362306a36Sopenharmony_ci	} while (0)
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistruct tda827x_priv {
2662306a36Sopenharmony_ci	int i2c_addr;
2762306a36Sopenharmony_ci	struct i2c_adapter *i2c_adap;
2862306a36Sopenharmony_ci	struct tda827x_config *cfg;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	unsigned int sgIF;
3162306a36Sopenharmony_ci	unsigned char lpsel;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	u32 frequency;
3462306a36Sopenharmony_ci	u32 bandwidth;
3562306a36Sopenharmony_ci};
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic void tda827x_set_std(struct dvb_frontend *fe,
3862306a36Sopenharmony_ci			    struct analog_parameters *params)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	struct tda827x_priv *priv = fe->tuner_priv;
4162306a36Sopenharmony_ci	char *mode;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	priv->lpsel = 0;
4462306a36Sopenharmony_ci	if (params->std & V4L2_STD_MN) {
4562306a36Sopenharmony_ci		priv->sgIF = 92;
4662306a36Sopenharmony_ci		priv->lpsel = 1;
4762306a36Sopenharmony_ci		mode = "MN";
4862306a36Sopenharmony_ci	} else if (params->std & V4L2_STD_B) {
4962306a36Sopenharmony_ci		priv->sgIF = 108;
5062306a36Sopenharmony_ci		mode = "B";
5162306a36Sopenharmony_ci	} else if (params->std & V4L2_STD_GH) {
5262306a36Sopenharmony_ci		priv->sgIF = 124;
5362306a36Sopenharmony_ci		mode = "GH";
5462306a36Sopenharmony_ci	} else if (params->std & V4L2_STD_PAL_I) {
5562306a36Sopenharmony_ci		priv->sgIF = 124;
5662306a36Sopenharmony_ci		mode = "I";
5762306a36Sopenharmony_ci	} else if (params->std & V4L2_STD_DK) {
5862306a36Sopenharmony_ci		priv->sgIF = 124;
5962306a36Sopenharmony_ci		mode = "DK";
6062306a36Sopenharmony_ci	} else if (params->std & V4L2_STD_SECAM_L) {
6162306a36Sopenharmony_ci		priv->sgIF = 124;
6262306a36Sopenharmony_ci		mode = "L";
6362306a36Sopenharmony_ci	} else if (params->std & V4L2_STD_SECAM_LC) {
6462306a36Sopenharmony_ci		priv->sgIF = 20;
6562306a36Sopenharmony_ci		mode = "LC";
6662306a36Sopenharmony_ci	} else {
6762306a36Sopenharmony_ci		priv->sgIF = 124;
6862306a36Sopenharmony_ci		mode = "xx";
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	if (params->mode == V4L2_TUNER_RADIO) {
7262306a36Sopenharmony_ci		priv->sgIF = 88; /* if frequency is 5.5 MHz */
7362306a36Sopenharmony_ci		dprintk("setting tda827x to radio FM\n");
7462306a36Sopenharmony_ci	} else
7562306a36Sopenharmony_ci		dprintk("setting tda827x to system %s\n", mode);
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/* ------------------------------------------------------------------ */
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistruct tda827x_data {
8262306a36Sopenharmony_ci	u32 lomax;
8362306a36Sopenharmony_ci	u8  spd;
8462306a36Sopenharmony_ci	u8  bs;
8562306a36Sopenharmony_ci	u8  bp;
8662306a36Sopenharmony_ci	u8  cp;
8762306a36Sopenharmony_ci	u8  gc3;
8862306a36Sopenharmony_ci	u8 div1p5;
8962306a36Sopenharmony_ci};
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic const struct tda827x_data tda827x_table[] = {
9262306a36Sopenharmony_ci	{ .lomax =  62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
9362306a36Sopenharmony_ci	{ .lomax =  66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
9462306a36Sopenharmony_ci	{ .lomax =  76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},
9562306a36Sopenharmony_ci	{ .lomax =  84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},
9662306a36Sopenharmony_ci	{ .lomax =  93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0},
9762306a36Sopenharmony_ci	{ .lomax =  98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0},
9862306a36Sopenharmony_ci	{ .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
9962306a36Sopenharmony_ci	{ .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1},
10062306a36Sopenharmony_ci	{ .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1},
10162306a36Sopenharmony_ci	{ .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
10262306a36Sopenharmony_ci	{ .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
10362306a36Sopenharmony_ci	{ .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0},
10462306a36Sopenharmony_ci	{ .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
10562306a36Sopenharmony_ci	{ .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
10662306a36Sopenharmony_ci	{ .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1},
10762306a36Sopenharmony_ci	{ .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1},
10862306a36Sopenharmony_ci	{ .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
10962306a36Sopenharmony_ci	{ .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
11062306a36Sopenharmony_ci	{ .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
11162306a36Sopenharmony_ci	{ .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
11262306a36Sopenharmony_ci	{ .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1},
11362306a36Sopenharmony_ci	{ .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1},
11462306a36Sopenharmony_ci	{ .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
11562306a36Sopenharmony_ci	{ .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
11662306a36Sopenharmony_ci	{ .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
11762306a36Sopenharmony_ci	{ .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0},
11862306a36Sopenharmony_ci	{ .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
11962306a36Sopenharmony_ci	{ .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0},
12062306a36Sopenharmony_ci	{ .lomax =         0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}
12162306a36Sopenharmony_ci};
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic int tuner_transfer(struct dvb_frontend *fe,
12462306a36Sopenharmony_ci			  struct i2c_msg *msg,
12562306a36Sopenharmony_ci			  const int size)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	int rc;
12862306a36Sopenharmony_ci	struct tda827x_priv *priv = fe->tuner_priv;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	if (fe->ops.i2c_gate_ctrl)
13162306a36Sopenharmony_ci		fe->ops.i2c_gate_ctrl(fe, 1);
13262306a36Sopenharmony_ci	rc = i2c_transfer(priv->i2c_adap, msg, size);
13362306a36Sopenharmony_ci	if (fe->ops.i2c_gate_ctrl)
13462306a36Sopenharmony_ci		fe->ops.i2c_gate_ctrl(fe, 0);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	if (rc >= 0 && rc != size)
13762306a36Sopenharmony_ci		return -EIO;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	return rc;
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic int tda827xo_set_params(struct dvb_frontend *fe)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
14562306a36Sopenharmony_ci	struct tda827x_priv *priv = fe->tuner_priv;
14662306a36Sopenharmony_ci	u8 buf[14];
14762306a36Sopenharmony_ci	int rc;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
15062306a36Sopenharmony_ci			       .buf = buf, .len = sizeof(buf) };
15162306a36Sopenharmony_ci	int i, tuner_freq, if_freq;
15262306a36Sopenharmony_ci	u32 N;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	dprintk("%s:\n", __func__);
15562306a36Sopenharmony_ci	if (c->bandwidth_hz == 0) {
15662306a36Sopenharmony_ci		if_freq = 5000000;
15762306a36Sopenharmony_ci	} else if (c->bandwidth_hz <= 6000000) {
15862306a36Sopenharmony_ci		if_freq = 4000000;
15962306a36Sopenharmony_ci	} else if (c->bandwidth_hz <= 7000000) {
16062306a36Sopenharmony_ci		if_freq = 4500000;
16162306a36Sopenharmony_ci	} else {	/* 8 MHz */
16262306a36Sopenharmony_ci		if_freq = 5000000;
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci	tuner_freq = c->frequency;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	i = 0;
16762306a36Sopenharmony_ci	while (tda827x_table[i].lomax < tuner_freq) {
16862306a36Sopenharmony_ci		if (tda827x_table[i + 1].lomax == 0)
16962306a36Sopenharmony_ci			break;
17062306a36Sopenharmony_ci		i++;
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	tuner_freq += if_freq;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2);
17662306a36Sopenharmony_ci	buf[0] = 0;
17762306a36Sopenharmony_ci	buf[1] = (N>>8) | 0x40;
17862306a36Sopenharmony_ci	buf[2] = N & 0xff;
17962306a36Sopenharmony_ci	buf[3] = 0;
18062306a36Sopenharmony_ci	buf[4] = 0x52;
18162306a36Sopenharmony_ci	buf[5] = (tda827x_table[i].spd << 6) + (tda827x_table[i].div1p5 << 5) +
18262306a36Sopenharmony_ci				(tda827x_table[i].bs << 3) +
18362306a36Sopenharmony_ci				tda827x_table[i].bp;
18462306a36Sopenharmony_ci	buf[6] = (tda827x_table[i].gc3 << 4) + 0x8f;
18562306a36Sopenharmony_ci	buf[7] = 0xbf;
18662306a36Sopenharmony_ci	buf[8] = 0x2a;
18762306a36Sopenharmony_ci	buf[9] = 0x05;
18862306a36Sopenharmony_ci	buf[10] = 0xff;
18962306a36Sopenharmony_ci	buf[11] = 0x00;
19062306a36Sopenharmony_ci	buf[12] = 0x00;
19162306a36Sopenharmony_ci	buf[13] = 0x40;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	msg.len = 14;
19462306a36Sopenharmony_ci	rc = tuner_transfer(fe, &msg, 1);
19562306a36Sopenharmony_ci	if (rc < 0)
19662306a36Sopenharmony_ci		goto err;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	msleep(500);
19962306a36Sopenharmony_ci	/* correct CP value */
20062306a36Sopenharmony_ci	buf[0] = 0x30;
20162306a36Sopenharmony_ci	buf[1] = 0x50 + tda827x_table[i].cp;
20262306a36Sopenharmony_ci	msg.len = 2;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	rc = tuner_transfer(fe, &msg, 1);
20562306a36Sopenharmony_ci	if (rc < 0)
20662306a36Sopenharmony_ci		goto err;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	priv->frequency = c->frequency;
20962306a36Sopenharmony_ci	priv->bandwidth = c->bandwidth_hz;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	return 0;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cierr:
21462306a36Sopenharmony_ci	printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n",
21562306a36Sopenharmony_ci	       __func__, priv->i2c_addr << 1);
21662306a36Sopenharmony_ci	return rc;
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic int tda827xo_sleep(struct dvb_frontend *fe)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	struct tda827x_priv *priv = fe->tuner_priv;
22262306a36Sopenharmony_ci	static u8 buf[] = { 0x30, 0xd0 };
22362306a36Sopenharmony_ci	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
22462306a36Sopenharmony_ci			       .buf = buf, .len = sizeof(buf) };
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	dprintk("%s:\n", __func__);
22762306a36Sopenharmony_ci	tuner_transfer(fe, &msg, 1);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	if (priv->cfg && priv->cfg->sleep)
23062306a36Sopenharmony_ci		priv->cfg->sleep(fe);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	return 0;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci/* ------------------------------------------------------------------ */
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic int tda827xo_set_analog_params(struct dvb_frontend *fe,
23862306a36Sopenharmony_ci				      struct analog_parameters *params)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	unsigned char tuner_reg[8];
24162306a36Sopenharmony_ci	unsigned char reg2[2];
24262306a36Sopenharmony_ci	u32 N;
24362306a36Sopenharmony_ci	int i;
24462306a36Sopenharmony_ci	struct tda827x_priv *priv = fe->tuner_priv;
24562306a36Sopenharmony_ci	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0 };
24662306a36Sopenharmony_ci	unsigned int freq = params->frequency;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	tda827x_set_std(fe, params);
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	if (params->mode == V4L2_TUNER_RADIO)
25162306a36Sopenharmony_ci		freq = freq / 1000;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	N = freq + priv->sgIF;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	i = 0;
25662306a36Sopenharmony_ci	while (tda827x_table[i].lomax < N * 62500) {
25762306a36Sopenharmony_ci		if (tda827x_table[i + 1].lomax == 0)
25862306a36Sopenharmony_ci			break;
25962306a36Sopenharmony_ci		i++;
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	N = N << tda827x_table[i].spd;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	tuner_reg[0] = 0;
26562306a36Sopenharmony_ci	tuner_reg[1] = (unsigned char)(N>>8);
26662306a36Sopenharmony_ci	tuner_reg[2] = (unsigned char) N;
26762306a36Sopenharmony_ci	tuner_reg[3] = 0x40;
26862306a36Sopenharmony_ci	tuner_reg[4] = 0x52 + (priv->lpsel << 5);
26962306a36Sopenharmony_ci	tuner_reg[5] = (tda827x_table[i].spd    << 6) +
27062306a36Sopenharmony_ci		       (tda827x_table[i].div1p5 << 5) +
27162306a36Sopenharmony_ci		       (tda827x_table[i].bs     << 3) + tda827x_table[i].bp;
27262306a36Sopenharmony_ci	tuner_reg[6] = 0x8f + (tda827x_table[i].gc3 << 4);
27362306a36Sopenharmony_ci	tuner_reg[7] = 0x8f;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	msg.buf = tuner_reg;
27662306a36Sopenharmony_ci	msg.len = 8;
27762306a36Sopenharmony_ci	tuner_transfer(fe, &msg, 1);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	msg.buf = reg2;
28062306a36Sopenharmony_ci	msg.len = 2;
28162306a36Sopenharmony_ci	reg2[0] = 0x80;
28262306a36Sopenharmony_ci	reg2[1] = 0;
28362306a36Sopenharmony_ci	tuner_transfer(fe, &msg, 1);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	reg2[0] = 0x60;
28662306a36Sopenharmony_ci	reg2[1] = 0xbf;
28762306a36Sopenharmony_ci	tuner_transfer(fe, &msg, 1);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	reg2[0] = 0x30;
29062306a36Sopenharmony_ci	reg2[1] = tuner_reg[4] + 0x80;
29162306a36Sopenharmony_ci	tuner_transfer(fe, &msg, 1);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	msleep(1);
29462306a36Sopenharmony_ci	reg2[0] = 0x30;
29562306a36Sopenharmony_ci	reg2[1] = tuner_reg[4] + 4;
29662306a36Sopenharmony_ci	tuner_transfer(fe, &msg, 1);
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	msleep(1);
29962306a36Sopenharmony_ci	reg2[0] = 0x30;
30062306a36Sopenharmony_ci	reg2[1] = tuner_reg[4];
30162306a36Sopenharmony_ci	tuner_transfer(fe, &msg, 1);
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	msleep(550);
30462306a36Sopenharmony_ci	reg2[0] = 0x30;
30562306a36Sopenharmony_ci	reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_table[i].cp;
30662306a36Sopenharmony_ci	tuner_transfer(fe, &msg, 1);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	reg2[0] = 0x60;
30962306a36Sopenharmony_ci	reg2[1] = 0x3f;
31062306a36Sopenharmony_ci	tuner_transfer(fe, &msg, 1);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	reg2[0] = 0x80;
31362306a36Sopenharmony_ci	reg2[1] = 0x08;   /* Vsync en */
31462306a36Sopenharmony_ci	tuner_transfer(fe, &msg, 1);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	priv->frequency = params->frequency;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	return 0;
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistatic void tda827xo_agcf(struct dvb_frontend *fe)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	struct tda827x_priv *priv = fe->tuner_priv;
32462306a36Sopenharmony_ci	unsigned char data[] = { 0x80, 0x0c };
32562306a36Sopenharmony_ci	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
32662306a36Sopenharmony_ci			       .buf = data, .len = 2};
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	tuner_transfer(fe, &msg, 1);
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci/* ------------------------------------------------------------------ */
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistruct tda827xa_data {
33462306a36Sopenharmony_ci	u32 lomax;
33562306a36Sopenharmony_ci	u8  svco;
33662306a36Sopenharmony_ci	u8  spd;
33762306a36Sopenharmony_ci	u8  scr;
33862306a36Sopenharmony_ci	u8  sbs;
33962306a36Sopenharmony_ci	u8  gc3;
34062306a36Sopenharmony_ci};
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_cistatic struct tda827xa_data tda827xa_dvbt[] = {
34362306a36Sopenharmony_ci	{ .lomax =  56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1},
34462306a36Sopenharmony_ci	{ .lomax =  67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
34562306a36Sopenharmony_ci	{ .lomax =  81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
34662306a36Sopenharmony_ci	{ .lomax =  97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1},
34762306a36Sopenharmony_ci	{ .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},
34862306a36Sopenharmony_ci	{ .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
34962306a36Sopenharmony_ci	{ .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
35062306a36Sopenharmony_ci	{ .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
35162306a36Sopenharmony_ci	{ .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
35262306a36Sopenharmony_ci	{ .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
35362306a36Sopenharmony_ci	{ .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
35462306a36Sopenharmony_ci	{ .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
35562306a36Sopenharmony_ci	{ .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
35662306a36Sopenharmony_ci	{ .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
35762306a36Sopenharmony_ci	{ .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
35862306a36Sopenharmony_ci	{ .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1},
35962306a36Sopenharmony_ci	{ .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
36062306a36Sopenharmony_ci	{ .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
36162306a36Sopenharmony_ci	{ .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
36262306a36Sopenharmony_ci	{ .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
36362306a36Sopenharmony_ci	{ .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
36462306a36Sopenharmony_ci	{ .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
36562306a36Sopenharmony_ci	{ .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
36662306a36Sopenharmony_ci	{ .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
36762306a36Sopenharmony_ci	{ .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
36862306a36Sopenharmony_ci	{ .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},
36962306a36Sopenharmony_ci	{ .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
37062306a36Sopenharmony_ci};
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic struct tda827xa_data tda827xa_dvbc[] = {
37362306a36Sopenharmony_ci	{ .lomax =  50125000, .svco = 2, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3},
37462306a36Sopenharmony_ci	{ .lomax =  58500000, .svco = 3, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3},
37562306a36Sopenharmony_ci	{ .lomax =  69250000, .svco = 0, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3},
37662306a36Sopenharmony_ci	{ .lomax =  83625000, .svco = 1, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3},
37762306a36Sopenharmony_ci	{ .lomax =  97500000, .svco = 2, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3},
37862306a36Sopenharmony_ci	{ .lomax = 100250000, .svco = 2, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1},
37962306a36Sopenharmony_ci	{ .lomax = 117000000, .svco = 3, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1},
38062306a36Sopenharmony_ci	{ .lomax = 138500000, .svco = 0, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1},
38162306a36Sopenharmony_ci	{ .lomax = 167250000, .svco = 1, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1},
38262306a36Sopenharmony_ci	{ .lomax = 187000000, .svco = 2, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1},
38362306a36Sopenharmony_ci	{ .lomax = 200500000, .svco = 2, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 1},
38462306a36Sopenharmony_ci	{ .lomax = 234000000, .svco = 3, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 3},
38562306a36Sopenharmony_ci	{ .lomax = 277000000, .svco = 0, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 3},
38662306a36Sopenharmony_ci	{ .lomax = 325000000, .svco = 1, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 1},
38762306a36Sopenharmony_ci	{ .lomax = 334500000, .svco = 1, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3},
38862306a36Sopenharmony_ci	{ .lomax = 401000000, .svco = 2, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3},
38962306a36Sopenharmony_ci	{ .lomax = 468000000, .svco = 3, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 1},
39062306a36Sopenharmony_ci	{ .lomax = 535000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
39162306a36Sopenharmony_ci	{ .lomax = 554000000, .svco = 0, .spd = 0, .scr = 2, .sbs = 3, .gc3 = 1},
39262306a36Sopenharmony_ci	{ .lomax = 638000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
39362306a36Sopenharmony_ci	{ .lomax = 669000000, .svco = 1, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1},
39462306a36Sopenharmony_ci	{ .lomax = 720000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
39562306a36Sopenharmony_ci	{ .lomax = 802000000, .svco = 2, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1},
39662306a36Sopenharmony_ci	{ .lomax = 835000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
39762306a36Sopenharmony_ci	{ .lomax = 885000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1},
39862306a36Sopenharmony_ci	{ .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1},
39962306a36Sopenharmony_ci	{ .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
40062306a36Sopenharmony_ci};
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic struct tda827xa_data tda827xa_analog[] = {
40362306a36Sopenharmony_ci	{ .lomax =  56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3},
40462306a36Sopenharmony_ci	{ .lomax =  67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
40562306a36Sopenharmony_ci	{ .lomax =  81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
40662306a36Sopenharmony_ci	{ .lomax =  97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3},
40762306a36Sopenharmony_ci	{ .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1},
40862306a36Sopenharmony_ci	{ .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
40962306a36Sopenharmony_ci	{ .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
41062306a36Sopenharmony_ci	{ .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
41162306a36Sopenharmony_ci	{ .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1},
41262306a36Sopenharmony_ci	{ .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1},
41362306a36Sopenharmony_ci	{ .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3},
41462306a36Sopenharmony_ci	{ .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3},
41562306a36Sopenharmony_ci	{ .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1},
41662306a36Sopenharmony_ci	{ .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},
41762306a36Sopenharmony_ci	{ .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3},
41862306a36Sopenharmony_ci	{ .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
41962306a36Sopenharmony_ci	{ .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1},
42062306a36Sopenharmony_ci	{ .lomax = 554000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1},
42162306a36Sopenharmony_ci	{ .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
42262306a36Sopenharmony_ci	{ .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
42362306a36Sopenharmony_ci	{ .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
42462306a36Sopenharmony_ci	{ .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
42562306a36Sopenharmony_ci	{ .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0},
42662306a36Sopenharmony_ci	{ .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0},
42762306a36Sopenharmony_ci	{ .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0},
42862306a36Sopenharmony_ci	{ .lomax =         0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
42962306a36Sopenharmony_ci};
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_cistatic int tda827xa_sleep(struct dvb_frontend *fe)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	struct tda827x_priv *priv = fe->tuner_priv;
43462306a36Sopenharmony_ci	static u8 buf[] = { 0x30, 0x90 };
43562306a36Sopenharmony_ci	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
43662306a36Sopenharmony_ci			       .buf = buf, .len = sizeof(buf) };
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	dprintk("%s:\n", __func__);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	tuner_transfer(fe, &msg, 1);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	if (priv->cfg && priv->cfg->sleep)
44362306a36Sopenharmony_ci		priv->cfg->sleep(fe);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	return 0;
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_cistatic void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
44962306a36Sopenharmony_ci			      struct analog_parameters *params)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	struct tda827x_priv *priv = fe->tuner_priv;
45262306a36Sopenharmony_ci	unsigned char buf[] = {0x22, 0x01};
45362306a36Sopenharmony_ci	int arg;
45462306a36Sopenharmony_ci	int gp_func;
45562306a36Sopenharmony_ci	struct i2c_msg msg = { .flags = 0, .buf = buf, .len = sizeof(buf) };
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	if (NULL == priv->cfg) {
45862306a36Sopenharmony_ci		dprintk("tda827x_config not defined, cannot set LNA gain!\n");
45962306a36Sopenharmony_ci		return;
46062306a36Sopenharmony_ci	}
46162306a36Sopenharmony_ci	msg.addr = priv->cfg->switch_addr;
46262306a36Sopenharmony_ci	if (priv->cfg->config) {
46362306a36Sopenharmony_ci		if (high)
46462306a36Sopenharmony_ci			dprintk("setting LNA to high gain\n");
46562306a36Sopenharmony_ci		else
46662306a36Sopenharmony_ci			dprintk("setting LNA to low gain\n");
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci	switch (priv->cfg->config) {
46962306a36Sopenharmony_ci	case TDA8290_LNA_OFF: /* no LNA */
47062306a36Sopenharmony_ci		break;
47162306a36Sopenharmony_ci	case TDA8290_LNA_GP0_HIGH_ON: /* switch is GPIO 0 of tda8290 */
47262306a36Sopenharmony_ci	case TDA8290_LNA_GP0_HIGH_OFF:
47362306a36Sopenharmony_ci		if (params == NULL) {
47462306a36Sopenharmony_ci			gp_func = 0;
47562306a36Sopenharmony_ci			arg  = 0;
47662306a36Sopenharmony_ci		} else {
47762306a36Sopenharmony_ci			/* turn Vsync on */
47862306a36Sopenharmony_ci			gp_func = 1;
47962306a36Sopenharmony_ci			if (params->std & V4L2_STD_MN)
48062306a36Sopenharmony_ci				arg = 1;
48162306a36Sopenharmony_ci			else
48262306a36Sopenharmony_ci				arg = 0;
48362306a36Sopenharmony_ci		}
48462306a36Sopenharmony_ci		if (fe->callback)
48562306a36Sopenharmony_ci			fe->callback(priv->i2c_adap->algo_data,
48662306a36Sopenharmony_ci				     DVB_FRONTEND_COMPONENT_TUNER,
48762306a36Sopenharmony_ci				     gp_func, arg);
48862306a36Sopenharmony_ci		buf[1] = high ? 0 : 1;
48962306a36Sopenharmony_ci		if (priv->cfg->config == TDA8290_LNA_GP0_HIGH_OFF)
49062306a36Sopenharmony_ci			buf[1] = high ? 1 : 0;
49162306a36Sopenharmony_ci		tuner_transfer(fe, &msg, 1);
49262306a36Sopenharmony_ci		break;
49362306a36Sopenharmony_ci	case TDA8290_LNA_ON_BRIDGE: /* switch with GPIO of saa713x */
49462306a36Sopenharmony_ci		if (fe->callback)
49562306a36Sopenharmony_ci			fe->callback(priv->i2c_adap->algo_data,
49662306a36Sopenharmony_ci				     DVB_FRONTEND_COMPONENT_TUNER, 0, high);
49762306a36Sopenharmony_ci		break;
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cistatic int tda827xa_set_params(struct dvb_frontend *fe)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
50462306a36Sopenharmony_ci	struct tda827x_priv *priv = fe->tuner_priv;
50562306a36Sopenharmony_ci	struct tda827xa_data *frequency_map = tda827xa_dvbt;
50662306a36Sopenharmony_ci	u8 buf[11];
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
50962306a36Sopenharmony_ci			       .buf = buf, .len = sizeof(buf) };
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	int i, tuner_freq, if_freq, rc;
51262306a36Sopenharmony_ci	u32 N;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	dprintk("%s:\n", __func__);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	tda827xa_lna_gain(fe, 1, NULL);
51762306a36Sopenharmony_ci	msleep(20);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	if (c->bandwidth_hz == 0) {
52062306a36Sopenharmony_ci		if_freq = 5000000;
52162306a36Sopenharmony_ci	} else if (c->bandwidth_hz <= 6000000) {
52262306a36Sopenharmony_ci		if_freq = 4000000;
52362306a36Sopenharmony_ci	} else if (c->bandwidth_hz <= 7000000) {
52462306a36Sopenharmony_ci		if_freq = 4500000;
52562306a36Sopenharmony_ci	} else {	/* 8 MHz */
52662306a36Sopenharmony_ci		if_freq = 5000000;
52762306a36Sopenharmony_ci	}
52862306a36Sopenharmony_ci	tuner_freq = c->frequency;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	switch (c->delivery_system) {
53162306a36Sopenharmony_ci	case SYS_DVBC_ANNEX_A:
53262306a36Sopenharmony_ci	case SYS_DVBC_ANNEX_C:
53362306a36Sopenharmony_ci		dprintk("%s select tda827xa_dvbc\n", __func__);
53462306a36Sopenharmony_ci		frequency_map = tda827xa_dvbc;
53562306a36Sopenharmony_ci		break;
53662306a36Sopenharmony_ci	default:
53762306a36Sopenharmony_ci		break;
53862306a36Sopenharmony_ci	}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	i = 0;
54162306a36Sopenharmony_ci	while (frequency_map[i].lomax < tuner_freq) {
54262306a36Sopenharmony_ci		if (frequency_map[i + 1].lomax == 0)
54362306a36Sopenharmony_ci			break;
54462306a36Sopenharmony_ci		i++;
54562306a36Sopenharmony_ci	}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	tuner_freq += if_freq;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	N = ((tuner_freq + 31250) / 62500) << frequency_map[i].spd;
55062306a36Sopenharmony_ci	buf[0] = 0;            // subaddress
55162306a36Sopenharmony_ci	buf[1] = N >> 8;
55262306a36Sopenharmony_ci	buf[2] = N & 0xff;
55362306a36Sopenharmony_ci	buf[3] = 0;
55462306a36Sopenharmony_ci	buf[4] = 0x16;
55562306a36Sopenharmony_ci	buf[5] = (frequency_map[i].spd << 5) + (frequency_map[i].svco << 3) +
55662306a36Sopenharmony_ci			frequency_map[i].sbs;
55762306a36Sopenharmony_ci	buf[6] = 0x4b + (frequency_map[i].gc3 << 4);
55862306a36Sopenharmony_ci	buf[7] = 0x1c;
55962306a36Sopenharmony_ci	buf[8] = 0x06;
56062306a36Sopenharmony_ci	buf[9] = 0x24;
56162306a36Sopenharmony_ci	buf[10] = 0x00;
56262306a36Sopenharmony_ci	msg.len = 11;
56362306a36Sopenharmony_ci	rc = tuner_transfer(fe, &msg, 1);
56462306a36Sopenharmony_ci	if (rc < 0)
56562306a36Sopenharmony_ci		goto err;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	buf[0] = 0x90;
56862306a36Sopenharmony_ci	buf[1] = 0xff;
56962306a36Sopenharmony_ci	buf[2] = 0x60;
57062306a36Sopenharmony_ci	buf[3] = 0x00;
57162306a36Sopenharmony_ci	buf[4] = 0x59;  // lpsel, for 6MHz + 2
57262306a36Sopenharmony_ci	msg.len = 5;
57362306a36Sopenharmony_ci	rc = tuner_transfer(fe, &msg, 1);
57462306a36Sopenharmony_ci	if (rc < 0)
57562306a36Sopenharmony_ci		goto err;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	buf[0] = 0xa0;
57862306a36Sopenharmony_ci	buf[1] = 0x40;
57962306a36Sopenharmony_ci	msg.len = 2;
58062306a36Sopenharmony_ci	rc = tuner_transfer(fe, &msg, 1);
58162306a36Sopenharmony_ci	if (rc < 0)
58262306a36Sopenharmony_ci		goto err;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	msleep(11);
58562306a36Sopenharmony_ci	msg.flags = I2C_M_RD;
58662306a36Sopenharmony_ci	rc = tuner_transfer(fe, &msg, 1);
58762306a36Sopenharmony_ci	if (rc < 0)
58862306a36Sopenharmony_ci		goto err;
58962306a36Sopenharmony_ci	msg.flags = 0;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	buf[1] >>= 4;
59262306a36Sopenharmony_ci	dprintk("tda8275a AGC2 gain is: %d\n", buf[1]);
59362306a36Sopenharmony_ci	if ((buf[1]) < 2) {
59462306a36Sopenharmony_ci		tda827xa_lna_gain(fe, 0, NULL);
59562306a36Sopenharmony_ci		buf[0] = 0x60;
59662306a36Sopenharmony_ci		buf[1] = 0x0c;
59762306a36Sopenharmony_ci		rc = tuner_transfer(fe, &msg, 1);
59862306a36Sopenharmony_ci		if (rc < 0)
59962306a36Sopenharmony_ci			goto err;
60062306a36Sopenharmony_ci	}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	buf[0] = 0xc0;
60362306a36Sopenharmony_ci	buf[1] = 0x99;    // lpsel, for 6MHz + 2
60462306a36Sopenharmony_ci	rc = tuner_transfer(fe, &msg, 1);
60562306a36Sopenharmony_ci	if (rc < 0)
60662306a36Sopenharmony_ci		goto err;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	buf[0] = 0x60;
60962306a36Sopenharmony_ci	buf[1] = 0x3c;
61062306a36Sopenharmony_ci	rc = tuner_transfer(fe, &msg, 1);
61162306a36Sopenharmony_ci	if (rc < 0)
61262306a36Sopenharmony_ci		goto err;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	/* correct CP value */
61562306a36Sopenharmony_ci	buf[0] = 0x30;
61662306a36Sopenharmony_ci	buf[1] = 0x10 + frequency_map[i].scr;
61762306a36Sopenharmony_ci	rc = tuner_transfer(fe, &msg, 1);
61862306a36Sopenharmony_ci	if (rc < 0)
61962306a36Sopenharmony_ci		goto err;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	msleep(163);
62262306a36Sopenharmony_ci	buf[0] = 0xc0;
62362306a36Sopenharmony_ci	buf[1] = 0x39;  // lpsel, for 6MHz + 2
62462306a36Sopenharmony_ci	rc = tuner_transfer(fe, &msg, 1);
62562306a36Sopenharmony_ci	if (rc < 0)
62662306a36Sopenharmony_ci		goto err;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	msleep(3);
62962306a36Sopenharmony_ci	/* freeze AGC1 */
63062306a36Sopenharmony_ci	buf[0] = 0x50;
63162306a36Sopenharmony_ci	buf[1] = 0x4f + (frequency_map[i].gc3 << 4);
63262306a36Sopenharmony_ci	rc = tuner_transfer(fe, &msg, 1);
63362306a36Sopenharmony_ci	if (rc < 0)
63462306a36Sopenharmony_ci		goto err;
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	priv->frequency = c->frequency;
63762306a36Sopenharmony_ci	priv->bandwidth = c->bandwidth_hz;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	return 0;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_cierr:
64262306a36Sopenharmony_ci	printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n",
64362306a36Sopenharmony_ci	       __func__, priv->i2c_addr << 1);
64462306a36Sopenharmony_ci	return rc;
64562306a36Sopenharmony_ci}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_cistatic int tda827xa_set_analog_params(struct dvb_frontend *fe,
64962306a36Sopenharmony_ci				      struct analog_parameters *params)
65062306a36Sopenharmony_ci{
65162306a36Sopenharmony_ci	unsigned char tuner_reg[11];
65262306a36Sopenharmony_ci	u32 N;
65362306a36Sopenharmony_ci	int i;
65462306a36Sopenharmony_ci	struct tda827x_priv *priv = fe->tuner_priv;
65562306a36Sopenharmony_ci	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
65662306a36Sopenharmony_ci			       .buf = tuner_reg, .len = sizeof(tuner_reg) };
65762306a36Sopenharmony_ci	unsigned int freq = params->frequency;
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	tda827x_set_std(fe, params);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	tda827xa_lna_gain(fe, 1, params);
66262306a36Sopenharmony_ci	msleep(10);
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	if (params->mode == V4L2_TUNER_RADIO)
66562306a36Sopenharmony_ci		freq = freq / 1000;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	N = freq + priv->sgIF;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	i = 0;
67062306a36Sopenharmony_ci	while (tda827xa_analog[i].lomax < N * 62500) {
67162306a36Sopenharmony_ci		if (tda827xa_analog[i + 1].lomax == 0)
67262306a36Sopenharmony_ci			break;
67362306a36Sopenharmony_ci		i++;
67462306a36Sopenharmony_ci	}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	N = N << tda827xa_analog[i].spd;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	tuner_reg[0] = 0;
67962306a36Sopenharmony_ci	tuner_reg[1] = (unsigned char)(N>>8);
68062306a36Sopenharmony_ci	tuner_reg[2] = (unsigned char) N;
68162306a36Sopenharmony_ci	tuner_reg[3] = 0;
68262306a36Sopenharmony_ci	tuner_reg[4] = 0x16;
68362306a36Sopenharmony_ci	tuner_reg[5] = (tda827xa_analog[i].spd << 5) +
68462306a36Sopenharmony_ci		       (tda827xa_analog[i].svco << 3) +
68562306a36Sopenharmony_ci			tda827xa_analog[i].sbs;
68662306a36Sopenharmony_ci	tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4);
68762306a36Sopenharmony_ci	tuner_reg[7] = 0x1c;
68862306a36Sopenharmony_ci	tuner_reg[8] = 4;
68962306a36Sopenharmony_ci	tuner_reg[9] = 0x20;
69062306a36Sopenharmony_ci	tuner_reg[10] = 0x00;
69162306a36Sopenharmony_ci	msg.len = 11;
69262306a36Sopenharmony_ci	tuner_transfer(fe, &msg, 1);
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	tuner_reg[0] = 0x90;
69562306a36Sopenharmony_ci	tuner_reg[1] = 0xff;
69662306a36Sopenharmony_ci	tuner_reg[2] = 0xe0;
69762306a36Sopenharmony_ci	tuner_reg[3] = 0;
69862306a36Sopenharmony_ci	tuner_reg[4] = 0x99 + (priv->lpsel << 1);
69962306a36Sopenharmony_ci	msg.len = 5;
70062306a36Sopenharmony_ci	tuner_transfer(fe, &msg, 1);
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	tuner_reg[0] = 0xa0;
70362306a36Sopenharmony_ci	tuner_reg[1] = 0xc0;
70462306a36Sopenharmony_ci	msg.len = 2;
70562306a36Sopenharmony_ci	tuner_transfer(fe, &msg, 1);
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	tuner_reg[0] = 0x30;
70862306a36Sopenharmony_ci	tuner_reg[1] = 0x10 + tda827xa_analog[i].scr;
70962306a36Sopenharmony_ci	tuner_transfer(fe, &msg, 1);
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	msg.flags = I2C_M_RD;
71262306a36Sopenharmony_ci	tuner_transfer(fe, &msg, 1);
71362306a36Sopenharmony_ci	msg.flags = 0;
71462306a36Sopenharmony_ci	tuner_reg[1] >>= 4;
71562306a36Sopenharmony_ci	dprintk("AGC2 gain is: %d\n", tuner_reg[1]);
71662306a36Sopenharmony_ci	if (tuner_reg[1] < 1)
71762306a36Sopenharmony_ci		tda827xa_lna_gain(fe, 0, params);
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	msleep(100);
72062306a36Sopenharmony_ci	tuner_reg[0] = 0x60;
72162306a36Sopenharmony_ci	tuner_reg[1] = 0x3c;
72262306a36Sopenharmony_ci	tuner_transfer(fe, &msg, 1);
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	msleep(163);
72562306a36Sopenharmony_ci	tuner_reg[0] = 0x50;
72662306a36Sopenharmony_ci	tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
72762306a36Sopenharmony_ci	tuner_transfer(fe, &msg, 1);
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	tuner_reg[0] = 0x80;
73062306a36Sopenharmony_ci	tuner_reg[1] = 0x28;
73162306a36Sopenharmony_ci	tuner_transfer(fe, &msg, 1);
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	tuner_reg[0] = 0xb0;
73462306a36Sopenharmony_ci	tuner_reg[1] = 0x01;
73562306a36Sopenharmony_ci	tuner_transfer(fe, &msg, 1);
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	tuner_reg[0] = 0xc0;
73862306a36Sopenharmony_ci	tuner_reg[1] = 0x19 + (priv->lpsel << 1);
73962306a36Sopenharmony_ci	tuner_transfer(fe, &msg, 1);
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	priv->frequency = params->frequency;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	return 0;
74462306a36Sopenharmony_ci}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_cistatic void tda827xa_agcf(struct dvb_frontend *fe)
74762306a36Sopenharmony_ci{
74862306a36Sopenharmony_ci	struct tda827x_priv *priv = fe->tuner_priv;
74962306a36Sopenharmony_ci	unsigned char data[] = {0x80, 0x2c};
75062306a36Sopenharmony_ci	struct i2c_msg msg = {.addr = priv->i2c_addr, .flags = 0,
75162306a36Sopenharmony_ci			      .buf = data, .len = 2};
75262306a36Sopenharmony_ci	tuner_transfer(fe, &msg, 1);
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci/* ------------------------------------------------------------------ */
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_cistatic void tda827x_release(struct dvb_frontend *fe)
75862306a36Sopenharmony_ci{
75962306a36Sopenharmony_ci	kfree(fe->tuner_priv);
76062306a36Sopenharmony_ci	fe->tuner_priv = NULL;
76162306a36Sopenharmony_ci}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_cistatic int tda827x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
76462306a36Sopenharmony_ci{
76562306a36Sopenharmony_ci	struct tda827x_priv *priv = fe->tuner_priv;
76662306a36Sopenharmony_ci	*frequency = priv->frequency;
76762306a36Sopenharmony_ci	return 0;
76862306a36Sopenharmony_ci}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_cistatic int tda827x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
77162306a36Sopenharmony_ci{
77262306a36Sopenharmony_ci	struct tda827x_priv *priv = fe->tuner_priv;
77362306a36Sopenharmony_ci	*bandwidth = priv->bandwidth;
77462306a36Sopenharmony_ci	return 0;
77562306a36Sopenharmony_ci}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_cistatic int tda827x_init(struct dvb_frontend *fe)
77862306a36Sopenharmony_ci{
77962306a36Sopenharmony_ci	struct tda827x_priv *priv = fe->tuner_priv;
78062306a36Sopenharmony_ci	dprintk("%s:\n", __func__);
78162306a36Sopenharmony_ci	if (priv->cfg && priv->cfg->init)
78262306a36Sopenharmony_ci		priv->cfg->init(fe);
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	return 0;
78562306a36Sopenharmony_ci}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_cistatic int tda827x_probe_version(struct dvb_frontend *fe);
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_cistatic int tda827x_initial_init(struct dvb_frontend *fe)
79062306a36Sopenharmony_ci{
79162306a36Sopenharmony_ci	int ret;
79262306a36Sopenharmony_ci	ret = tda827x_probe_version(fe);
79362306a36Sopenharmony_ci	if (ret)
79462306a36Sopenharmony_ci		return ret;
79562306a36Sopenharmony_ci	return fe->ops.tuner_ops.init(fe);
79662306a36Sopenharmony_ci}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_cistatic int tda827x_initial_sleep(struct dvb_frontend *fe)
79962306a36Sopenharmony_ci{
80062306a36Sopenharmony_ci	int ret;
80162306a36Sopenharmony_ci	ret = tda827x_probe_version(fe);
80262306a36Sopenharmony_ci	if (ret)
80362306a36Sopenharmony_ci		return ret;
80462306a36Sopenharmony_ci	return fe->ops.tuner_ops.sleep(fe);
80562306a36Sopenharmony_ci}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_cistatic const struct dvb_tuner_ops tda827xo_tuner_ops = {
80862306a36Sopenharmony_ci	.info = {
80962306a36Sopenharmony_ci		.name = "Philips TDA827X",
81062306a36Sopenharmony_ci		.frequency_min_hz  =  55 * MHz,
81162306a36Sopenharmony_ci		.frequency_max_hz  = 860 * MHz,
81262306a36Sopenharmony_ci		.frequency_step_hz = 250 * kHz
81362306a36Sopenharmony_ci	},
81462306a36Sopenharmony_ci	.release = tda827x_release,
81562306a36Sopenharmony_ci	.init = tda827x_initial_init,
81662306a36Sopenharmony_ci	.sleep = tda827x_initial_sleep,
81762306a36Sopenharmony_ci	.set_params = tda827xo_set_params,
81862306a36Sopenharmony_ci	.set_analog_params = tda827xo_set_analog_params,
81962306a36Sopenharmony_ci	.get_frequency = tda827x_get_frequency,
82062306a36Sopenharmony_ci	.get_bandwidth = tda827x_get_bandwidth,
82162306a36Sopenharmony_ci};
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_cistatic const struct dvb_tuner_ops tda827xa_tuner_ops = {
82462306a36Sopenharmony_ci	.info = {
82562306a36Sopenharmony_ci		.name = "Philips TDA827XA",
82662306a36Sopenharmony_ci		.frequency_min_hz  =  44 * MHz,
82762306a36Sopenharmony_ci		.frequency_max_hz  = 906 * MHz,
82862306a36Sopenharmony_ci		.frequency_step_hz = 62500
82962306a36Sopenharmony_ci	},
83062306a36Sopenharmony_ci	.release = tda827x_release,
83162306a36Sopenharmony_ci	.init = tda827x_init,
83262306a36Sopenharmony_ci	.sleep = tda827xa_sleep,
83362306a36Sopenharmony_ci	.set_params = tda827xa_set_params,
83462306a36Sopenharmony_ci	.set_analog_params = tda827xa_set_analog_params,
83562306a36Sopenharmony_ci	.get_frequency = tda827x_get_frequency,
83662306a36Sopenharmony_ci	.get_bandwidth = tda827x_get_bandwidth,
83762306a36Sopenharmony_ci};
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_cistatic int tda827x_probe_version(struct dvb_frontend *fe)
84062306a36Sopenharmony_ci{
84162306a36Sopenharmony_ci	u8 data;
84262306a36Sopenharmony_ci	int rc;
84362306a36Sopenharmony_ci	struct tda827x_priv *priv = fe->tuner_priv;
84462306a36Sopenharmony_ci	struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = I2C_M_RD,
84562306a36Sopenharmony_ci			       .buf = &data, .len = 1 };
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	rc = tuner_transfer(fe, &msg, 1);
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	if (rc < 0) {
85062306a36Sopenharmony_ci		printk("%s: could not read from tuner at addr: 0x%02x\n",
85162306a36Sopenharmony_ci		       __func__, msg.addr << 1);
85262306a36Sopenharmony_ci		return rc;
85362306a36Sopenharmony_ci	}
85462306a36Sopenharmony_ci	if ((data & 0x3c) == 0) {
85562306a36Sopenharmony_ci		dprintk("tda827x tuner found\n");
85662306a36Sopenharmony_ci		fe->ops.tuner_ops.init  = tda827x_init;
85762306a36Sopenharmony_ci		fe->ops.tuner_ops.sleep = tda827xo_sleep;
85862306a36Sopenharmony_ci		if (priv->cfg)
85962306a36Sopenharmony_ci			priv->cfg->agcf = tda827xo_agcf;
86062306a36Sopenharmony_ci	} else {
86162306a36Sopenharmony_ci		dprintk("tda827xa tuner found\n");
86262306a36Sopenharmony_ci		memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops));
86362306a36Sopenharmony_ci		if (priv->cfg)
86462306a36Sopenharmony_ci			priv->cfg->agcf = tda827xa_agcf;
86562306a36Sopenharmony_ci	}
86662306a36Sopenharmony_ci	return 0;
86762306a36Sopenharmony_ci}
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_cistruct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr,
87062306a36Sopenharmony_ci				    struct i2c_adapter *i2c,
87162306a36Sopenharmony_ci				    struct tda827x_config *cfg)
87262306a36Sopenharmony_ci{
87362306a36Sopenharmony_ci	struct tda827x_priv *priv = NULL;
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	dprintk("%s:\n", __func__);
87662306a36Sopenharmony_ci	priv = kzalloc(sizeof(struct tda827x_priv), GFP_KERNEL);
87762306a36Sopenharmony_ci	if (priv == NULL)
87862306a36Sopenharmony_ci		return NULL;
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	priv->i2c_addr = addr;
88162306a36Sopenharmony_ci	priv->i2c_adap = i2c;
88262306a36Sopenharmony_ci	priv->cfg = cfg;
88362306a36Sopenharmony_ci	memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops));
88462306a36Sopenharmony_ci	fe->tuner_priv = priv;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	dprintk("type set to %s\n", fe->ops.tuner_ops.info.name);
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	return fe;
88962306a36Sopenharmony_ci}
89062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tda827x_attach);
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ciMODULE_DESCRIPTION("DVB TDA827x driver");
89362306a36Sopenharmony_ciMODULE_AUTHOR("Hartmut Hackmann <hartmut.hackmann@t-online.de>");
89462306a36Sopenharmony_ciMODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
89562306a36Sopenharmony_ciMODULE_LICENSE("GPL");
896