162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Driver for the internal tuner of Montage M88RS6000
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2014 Max nibble <nibble.max@gmail.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "m88rs6000t.h"
962306a36Sopenharmony_ci#include <linux/regmap.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_cistruct m88rs6000t_dev {
1262306a36Sopenharmony_ci	struct m88rs6000t_config cfg;
1362306a36Sopenharmony_ci	struct i2c_client *client;
1462306a36Sopenharmony_ci	struct regmap *regmap;
1562306a36Sopenharmony_ci	u32 frequency_khz;
1662306a36Sopenharmony_ci};
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistruct m88rs6000t_reg_val {
1962306a36Sopenharmony_ci	u8 reg;
2062306a36Sopenharmony_ci	u8 val;
2162306a36Sopenharmony_ci};
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/* set demod main mclk and ts mclk */
2462306a36Sopenharmony_cistatic int m88rs6000t_set_demod_mclk(struct dvb_frontend *fe)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	struct m88rs6000t_dev *dev = fe->tuner_priv;
2762306a36Sopenharmony_ci	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
2862306a36Sopenharmony_ci	u8 reg11, reg15, reg16, reg1D, reg1E, reg1F;
2962306a36Sopenharmony_ci	u8 N, f0 = 0, f1 = 0, f2 = 0, f3 = 0;
3062306a36Sopenharmony_ci	u16 pll_div_fb;
3162306a36Sopenharmony_ci	u32 div, ts_mclk;
3262306a36Sopenharmony_ci	unsigned int utmp;
3362306a36Sopenharmony_ci	int ret;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	/* select demod main mclk */
3662306a36Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x15, &utmp);
3762306a36Sopenharmony_ci	if (ret)
3862306a36Sopenharmony_ci		goto err;
3962306a36Sopenharmony_ci	reg15 = utmp;
4062306a36Sopenharmony_ci	if (c->symbol_rate > 45010000) {
4162306a36Sopenharmony_ci		reg11 = 0x0E;
4262306a36Sopenharmony_ci		reg15 |= 0x02;
4362306a36Sopenharmony_ci		reg16 = 115; /* mclk = 110.25MHz */
4462306a36Sopenharmony_ci	} else {
4562306a36Sopenharmony_ci		reg11 = 0x0A;
4662306a36Sopenharmony_ci		reg15 &= ~0x02;
4762306a36Sopenharmony_ci		reg16 = 96; /* mclk = 96MHz */
4862306a36Sopenharmony_ci	}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	/* set ts mclk */
5162306a36Sopenharmony_ci	if (c->delivery_system == SYS_DVBS)
5262306a36Sopenharmony_ci		ts_mclk = 96000;
5362306a36Sopenharmony_ci	else
5462306a36Sopenharmony_ci		ts_mclk = 144000;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	pll_div_fb = (reg15 & 0x01) << 8;
5762306a36Sopenharmony_ci	pll_div_fb += reg16;
5862306a36Sopenharmony_ci	pll_div_fb += 32;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	div = 36000 * pll_div_fb;
6162306a36Sopenharmony_ci	div /= ts_mclk;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	if (div <= 32) {
6462306a36Sopenharmony_ci		N = 2;
6562306a36Sopenharmony_ci		f0 = 0;
6662306a36Sopenharmony_ci		f1 = div / 2;
6762306a36Sopenharmony_ci		f2 = div - f1;
6862306a36Sopenharmony_ci		f3 = 0;
6962306a36Sopenharmony_ci	} else if (div <= 48) {
7062306a36Sopenharmony_ci		N = 3;
7162306a36Sopenharmony_ci		f0 = div / 3;
7262306a36Sopenharmony_ci		f1 = (div - f0) / 2;
7362306a36Sopenharmony_ci		f2 = div - f0 - f1;
7462306a36Sopenharmony_ci		f3 = 0;
7562306a36Sopenharmony_ci	} else if (div <= 64) {
7662306a36Sopenharmony_ci		N = 4;
7762306a36Sopenharmony_ci		f0 = div / 4;
7862306a36Sopenharmony_ci		f1 = (div - f0) / 3;
7962306a36Sopenharmony_ci		f2 = (div - f0 - f1) / 2;
8062306a36Sopenharmony_ci		f3 = div - f0 - f1 - f2;
8162306a36Sopenharmony_ci	} else {
8262306a36Sopenharmony_ci		N = 4;
8362306a36Sopenharmony_ci		f0 = 16;
8462306a36Sopenharmony_ci		f1 = 16;
8562306a36Sopenharmony_ci		f2 = 16;
8662306a36Sopenharmony_ci		f3 = 16;
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	if (f0 == 16)
9062306a36Sopenharmony_ci		f0 = 0;
9162306a36Sopenharmony_ci	if (f1 == 16)
9262306a36Sopenharmony_ci		f1 = 0;
9362306a36Sopenharmony_ci	if (f2 == 16)
9462306a36Sopenharmony_ci		f2 = 0;
9562306a36Sopenharmony_ci	if (f3 == 16)
9662306a36Sopenharmony_ci		f3 = 0;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x1D, &utmp);
9962306a36Sopenharmony_ci	if (ret)
10062306a36Sopenharmony_ci		goto err;
10162306a36Sopenharmony_ci	reg1D = utmp;
10262306a36Sopenharmony_ci	reg1D &= ~0x03;
10362306a36Sopenharmony_ci	reg1D |= N - 1;
10462306a36Sopenharmony_ci	reg1E = ((f3 << 4) + f2) & 0xFF;
10562306a36Sopenharmony_ci	reg1F = ((f1 << 4) + f0) & 0xFF;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	/* program and recalibrate demod PLL */
10862306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x05, 0x40);
10962306a36Sopenharmony_ci	if (ret)
11062306a36Sopenharmony_ci		goto err;
11162306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x11, 0x08);
11262306a36Sopenharmony_ci	if (ret)
11362306a36Sopenharmony_ci		goto err;
11462306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x15, reg15);
11562306a36Sopenharmony_ci	if (ret)
11662306a36Sopenharmony_ci		goto err;
11762306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x16, reg16);
11862306a36Sopenharmony_ci	if (ret)
11962306a36Sopenharmony_ci		goto err;
12062306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x1D, reg1D);
12162306a36Sopenharmony_ci	if (ret)
12262306a36Sopenharmony_ci		goto err;
12362306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x1E, reg1E);
12462306a36Sopenharmony_ci	if (ret)
12562306a36Sopenharmony_ci		goto err;
12662306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x1F, reg1F);
12762306a36Sopenharmony_ci	if (ret)
12862306a36Sopenharmony_ci		goto err;
12962306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x17, 0xc1);
13062306a36Sopenharmony_ci	if (ret)
13162306a36Sopenharmony_ci		goto err;
13262306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x17, 0x81);
13362306a36Sopenharmony_ci	if (ret)
13462306a36Sopenharmony_ci		goto err;
13562306a36Sopenharmony_ci	usleep_range(5000, 50000);
13662306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x05, 0x00);
13762306a36Sopenharmony_ci	if (ret)
13862306a36Sopenharmony_ci		goto err;
13962306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x11, reg11);
14062306a36Sopenharmony_ci	if (ret)
14162306a36Sopenharmony_ci		goto err;
14262306a36Sopenharmony_ci	usleep_range(5000, 50000);
14362306a36Sopenharmony_cierr:
14462306a36Sopenharmony_ci	if (ret)
14562306a36Sopenharmony_ci		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
14662306a36Sopenharmony_ci	return ret;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic int m88rs6000t_set_pll_freq(struct m88rs6000t_dev *dev,
15062306a36Sopenharmony_ci			u32 tuner_freq_MHz)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	u32 fcry_KHz, ulNDiv1, ulNDiv2, ulNDiv;
15362306a36Sopenharmony_ci	u8 refDiv, ucLoDiv1, ucLomod1, ucLoDiv2, ucLomod2, ucLoDiv, ucLomod;
15462306a36Sopenharmony_ci	u8 reg27, reg29, reg42, reg42buf;
15562306a36Sopenharmony_ci	unsigned int utmp;
15662306a36Sopenharmony_ci	int ret;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	fcry_KHz = 27000; /* in kHz */
15962306a36Sopenharmony_ci	refDiv = 27;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x36, (refDiv - 8));
16262306a36Sopenharmony_ci	if (ret)
16362306a36Sopenharmony_ci		goto err;
16462306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x31, 0x00);
16562306a36Sopenharmony_ci	if (ret)
16662306a36Sopenharmony_ci		goto err;
16762306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x2c, 0x02);
16862306a36Sopenharmony_ci	if (ret)
16962306a36Sopenharmony_ci		goto err;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	if (tuner_freq_MHz >= 1550) {
17262306a36Sopenharmony_ci		ucLoDiv1 = 2;
17362306a36Sopenharmony_ci		ucLomod1 = 0;
17462306a36Sopenharmony_ci		ucLoDiv2 = 2;
17562306a36Sopenharmony_ci		ucLomod2 = 0;
17662306a36Sopenharmony_ci	} else if (tuner_freq_MHz >= 1380) {
17762306a36Sopenharmony_ci		ucLoDiv1 = 3;
17862306a36Sopenharmony_ci		ucLomod1 = 16;
17962306a36Sopenharmony_ci		ucLoDiv2 = 2;
18062306a36Sopenharmony_ci		ucLomod2 = 0;
18162306a36Sopenharmony_ci	} else if (tuner_freq_MHz >= 1070) {
18262306a36Sopenharmony_ci		ucLoDiv1 = 3;
18362306a36Sopenharmony_ci		ucLomod1 = 16;
18462306a36Sopenharmony_ci		ucLoDiv2 = 3;
18562306a36Sopenharmony_ci		ucLomod2 = 16;
18662306a36Sopenharmony_ci	} else if (tuner_freq_MHz >= 1000) {
18762306a36Sopenharmony_ci		ucLoDiv1 = 3;
18862306a36Sopenharmony_ci		ucLomod1 = 16;
18962306a36Sopenharmony_ci		ucLoDiv2 = 4;
19062306a36Sopenharmony_ci		ucLomod2 = 64;
19162306a36Sopenharmony_ci	} else if (tuner_freq_MHz >= 775) {
19262306a36Sopenharmony_ci		ucLoDiv1 = 4;
19362306a36Sopenharmony_ci		ucLomod1 = 64;
19462306a36Sopenharmony_ci		ucLoDiv2 = 4;
19562306a36Sopenharmony_ci		ucLomod2 = 64;
19662306a36Sopenharmony_ci	} else if (tuner_freq_MHz >= 700) {
19762306a36Sopenharmony_ci		ucLoDiv1 = 6;
19862306a36Sopenharmony_ci		ucLomod1 = 48;
19962306a36Sopenharmony_ci		ucLoDiv2 = 4;
20062306a36Sopenharmony_ci		ucLomod2 = 64;
20162306a36Sopenharmony_ci	} else if (tuner_freq_MHz >= 520) {
20262306a36Sopenharmony_ci		ucLoDiv1 = 6;
20362306a36Sopenharmony_ci		ucLomod1 = 48;
20462306a36Sopenharmony_ci		ucLoDiv2 = 6;
20562306a36Sopenharmony_ci		ucLomod2 = 48;
20662306a36Sopenharmony_ci	} else {
20762306a36Sopenharmony_ci		ucLoDiv1 = 8;
20862306a36Sopenharmony_ci		ucLomod1 = 96;
20962306a36Sopenharmony_ci		ucLoDiv2 = 8;
21062306a36Sopenharmony_ci		ucLomod2 = 96;
21162306a36Sopenharmony_ci	}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	ulNDiv1 = ((tuner_freq_MHz * ucLoDiv1 * 1000) * refDiv
21462306a36Sopenharmony_ci			/ fcry_KHz - 1024) / 2;
21562306a36Sopenharmony_ci	ulNDiv2 = ((tuner_freq_MHz * ucLoDiv2 * 1000) * refDiv
21662306a36Sopenharmony_ci			/ fcry_KHz - 1024) / 2;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	reg27 = (((ulNDiv1 >> 8) & 0x0F) + ucLomod1) & 0x7F;
21962306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x27, reg27);
22062306a36Sopenharmony_ci	if (ret)
22162306a36Sopenharmony_ci		goto err;
22262306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x28, (u8)(ulNDiv1 & 0xFF));
22362306a36Sopenharmony_ci	if (ret)
22462306a36Sopenharmony_ci		goto err;
22562306a36Sopenharmony_ci	reg29 = (((ulNDiv2 >> 8) & 0x0F) + ucLomod2) & 0x7f;
22662306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x29, reg29);
22762306a36Sopenharmony_ci	if (ret)
22862306a36Sopenharmony_ci		goto err;
22962306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x2a, (u8)(ulNDiv2 & 0xFF));
23062306a36Sopenharmony_ci	if (ret)
23162306a36Sopenharmony_ci		goto err;
23262306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x2F, 0xf5);
23362306a36Sopenharmony_ci	if (ret)
23462306a36Sopenharmony_ci		goto err;
23562306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x30, 0x05);
23662306a36Sopenharmony_ci	if (ret)
23762306a36Sopenharmony_ci		goto err;
23862306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x08, 0x1f);
23962306a36Sopenharmony_ci	if (ret)
24062306a36Sopenharmony_ci		goto err;
24162306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x08, 0x3f);
24262306a36Sopenharmony_ci	if (ret)
24362306a36Sopenharmony_ci		goto err;
24462306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x09, 0x20);
24562306a36Sopenharmony_ci	if (ret)
24662306a36Sopenharmony_ci		goto err;
24762306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x09, 0x00);
24862306a36Sopenharmony_ci	if (ret)
24962306a36Sopenharmony_ci		goto err;
25062306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x3e, 0x11);
25162306a36Sopenharmony_ci	if (ret)
25262306a36Sopenharmony_ci		goto err;
25362306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x08, 0x2f);
25462306a36Sopenharmony_ci	if (ret)
25562306a36Sopenharmony_ci		goto err;
25662306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x08, 0x3f);
25762306a36Sopenharmony_ci	if (ret)
25862306a36Sopenharmony_ci		goto err;
25962306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x09, 0x10);
26062306a36Sopenharmony_ci	if (ret)
26162306a36Sopenharmony_ci		goto err;
26262306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x09, 0x00);
26362306a36Sopenharmony_ci	if (ret)
26462306a36Sopenharmony_ci		goto err;
26562306a36Sopenharmony_ci	usleep_range(2000, 50000);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x42, &utmp);
26862306a36Sopenharmony_ci	if (ret)
26962306a36Sopenharmony_ci		goto err;
27062306a36Sopenharmony_ci	reg42 = utmp;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x3e, 0x10);
27362306a36Sopenharmony_ci	if (ret)
27462306a36Sopenharmony_ci		goto err;
27562306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x08, 0x2f);
27662306a36Sopenharmony_ci	if (ret)
27762306a36Sopenharmony_ci		goto err;
27862306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x08, 0x3f);
27962306a36Sopenharmony_ci	if (ret)
28062306a36Sopenharmony_ci		goto err;
28162306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x09, 0x10);
28262306a36Sopenharmony_ci	if (ret)
28362306a36Sopenharmony_ci		goto err;
28462306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x09, 0x00);
28562306a36Sopenharmony_ci	if (ret)
28662306a36Sopenharmony_ci		goto err;
28762306a36Sopenharmony_ci	usleep_range(2000, 50000);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x42, &utmp);
29062306a36Sopenharmony_ci	if (ret)
29162306a36Sopenharmony_ci		goto err;
29262306a36Sopenharmony_ci	reg42buf = utmp;
29362306a36Sopenharmony_ci	if (reg42buf < reg42) {
29462306a36Sopenharmony_ci		ret = regmap_write(dev->regmap, 0x3e, 0x11);
29562306a36Sopenharmony_ci		if (ret)
29662306a36Sopenharmony_ci			goto err;
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci	usleep_range(5000, 50000);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x2d, &utmp);
30162306a36Sopenharmony_ci	if (ret)
30262306a36Sopenharmony_ci		goto err;
30362306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x2d, utmp);
30462306a36Sopenharmony_ci	if (ret)
30562306a36Sopenharmony_ci		goto err;
30662306a36Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x2e, &utmp);
30762306a36Sopenharmony_ci	if (ret)
30862306a36Sopenharmony_ci		goto err;
30962306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x2e, utmp);
31062306a36Sopenharmony_ci	if (ret)
31162306a36Sopenharmony_ci		goto err;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x27, &utmp);
31462306a36Sopenharmony_ci	if (ret)
31562306a36Sopenharmony_ci		goto err;
31662306a36Sopenharmony_ci	reg27 = utmp & 0x70;
31762306a36Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x83, &utmp);
31862306a36Sopenharmony_ci	if (ret)
31962306a36Sopenharmony_ci		goto err;
32062306a36Sopenharmony_ci	if (reg27 == (utmp & 0x70)) {
32162306a36Sopenharmony_ci		ucLoDiv	= ucLoDiv1;
32262306a36Sopenharmony_ci		ulNDiv = ulNDiv1;
32362306a36Sopenharmony_ci		ucLomod = ucLomod1 / 16;
32462306a36Sopenharmony_ci	} else {
32562306a36Sopenharmony_ci		ucLoDiv	= ucLoDiv2;
32662306a36Sopenharmony_ci		ulNDiv = ulNDiv2;
32762306a36Sopenharmony_ci		ucLomod = ucLomod2 / 16;
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	if ((ucLoDiv == 3) || (ucLoDiv == 6)) {
33162306a36Sopenharmony_ci		refDiv = 18;
33262306a36Sopenharmony_ci		ret = regmap_write(dev->regmap, 0x36, (refDiv - 8));
33362306a36Sopenharmony_ci		if (ret)
33462306a36Sopenharmony_ci			goto err;
33562306a36Sopenharmony_ci		ulNDiv = ((tuner_freq_MHz * ucLoDiv * 1000) * refDiv
33662306a36Sopenharmony_ci				/ fcry_KHz - 1024) / 2;
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	reg27 = (0x80 + ((ucLomod << 4) & 0x70)
34062306a36Sopenharmony_ci			+ ((ulNDiv >> 8) & 0x0F)) & 0xFF;
34162306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x27, reg27);
34262306a36Sopenharmony_ci	if (ret)
34362306a36Sopenharmony_ci		goto err;
34462306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x28, (u8)(ulNDiv & 0xFF));
34562306a36Sopenharmony_ci	if (ret)
34662306a36Sopenharmony_ci		goto err;
34762306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x29, 0x80);
34862306a36Sopenharmony_ci	if (ret)
34962306a36Sopenharmony_ci		goto err;
35062306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x31, 0x03);
35162306a36Sopenharmony_ci	if (ret)
35262306a36Sopenharmony_ci		goto err;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	if (ucLoDiv == 3)
35562306a36Sopenharmony_ci		utmp = 0xCE;
35662306a36Sopenharmony_ci	else
35762306a36Sopenharmony_ci		utmp = 0x8A;
35862306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x3b, utmp);
35962306a36Sopenharmony_ci	if (ret)
36062306a36Sopenharmony_ci		goto err;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	dev->frequency_khz = fcry_KHz * (ulNDiv * 2 + 1024) / refDiv / ucLoDiv;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	dev_dbg(&dev->client->dev,
36562306a36Sopenharmony_ci		"actual tune frequency=%d\n", dev->frequency_khz);
36662306a36Sopenharmony_cierr:
36762306a36Sopenharmony_ci	if (ret)
36862306a36Sopenharmony_ci		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
36962306a36Sopenharmony_ci	return ret;
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cistatic int m88rs6000t_set_bb(struct m88rs6000t_dev *dev,
37362306a36Sopenharmony_ci		u32 symbol_rate_KSs, s32 lpf_offset_KHz)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	u32 f3dB;
37662306a36Sopenharmony_ci	u8  reg40;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	f3dB = symbol_rate_KSs * 9 / 14 + 2000;
37962306a36Sopenharmony_ci	f3dB += lpf_offset_KHz;
38062306a36Sopenharmony_ci	f3dB = clamp_val(f3dB, 6000U, 43000U);
38162306a36Sopenharmony_ci	reg40 = f3dB / 1000;
38262306a36Sopenharmony_ci	return regmap_write(dev->regmap, 0x40, reg40);
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_cistatic int m88rs6000t_set_params(struct dvb_frontend *fe)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	struct m88rs6000t_dev *dev = fe->tuner_priv;
38862306a36Sopenharmony_ci	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
38962306a36Sopenharmony_ci	int ret;
39062306a36Sopenharmony_ci	s32 lpf_offset_KHz;
39162306a36Sopenharmony_ci	u32 realFreq, freq_MHz;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	dev_dbg(&dev->client->dev,
39462306a36Sopenharmony_ci			"frequency=%d symbol_rate=%d\n",
39562306a36Sopenharmony_ci			c->frequency, c->symbol_rate);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	if (c->symbol_rate < 5000000)
39862306a36Sopenharmony_ci		lpf_offset_KHz = 3000;
39962306a36Sopenharmony_ci	else
40062306a36Sopenharmony_ci		lpf_offset_KHz = 0;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	realFreq = c->frequency + lpf_offset_KHz;
40362306a36Sopenharmony_ci	/* set tuner pll.*/
40462306a36Sopenharmony_ci	freq_MHz = (realFreq + 500) / 1000;
40562306a36Sopenharmony_ci	ret = m88rs6000t_set_pll_freq(dev, freq_MHz);
40662306a36Sopenharmony_ci	if (ret)
40762306a36Sopenharmony_ci		goto err;
40862306a36Sopenharmony_ci	ret = m88rs6000t_set_bb(dev, c->symbol_rate / 1000, lpf_offset_KHz);
40962306a36Sopenharmony_ci	if (ret)
41062306a36Sopenharmony_ci		goto err;
41162306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x00, 0x01);
41262306a36Sopenharmony_ci	if (ret)
41362306a36Sopenharmony_ci		goto err;
41462306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x00, 0x00);
41562306a36Sopenharmony_ci	if (ret)
41662306a36Sopenharmony_ci		goto err;
41762306a36Sopenharmony_ci	/* set demod mlck */
41862306a36Sopenharmony_ci	ret = m88rs6000t_set_demod_mclk(fe);
41962306a36Sopenharmony_cierr:
42062306a36Sopenharmony_ci	if (ret)
42162306a36Sopenharmony_ci		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
42262306a36Sopenharmony_ci	return ret;
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cistatic int m88rs6000t_init(struct dvb_frontend *fe)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	struct m88rs6000t_dev *dev = fe->tuner_priv;
42862306a36Sopenharmony_ci	int ret;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	dev_dbg(&dev->client->dev, "%s:\n", __func__);
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	ret = regmap_update_bits(dev->regmap, 0x11, 0x08, 0x08);
43362306a36Sopenharmony_ci	if (ret)
43462306a36Sopenharmony_ci		goto err;
43562306a36Sopenharmony_ci	usleep_range(5000, 50000);
43662306a36Sopenharmony_ci	ret = regmap_update_bits(dev->regmap, 0x10, 0x01, 0x01);
43762306a36Sopenharmony_ci	if (ret)
43862306a36Sopenharmony_ci		goto err;
43962306a36Sopenharmony_ci	usleep_range(10000, 50000);
44062306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x07, 0x7d);
44162306a36Sopenharmony_cierr:
44262306a36Sopenharmony_ci	if (ret)
44362306a36Sopenharmony_ci		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
44462306a36Sopenharmony_ci	return ret;
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_cistatic int m88rs6000t_sleep(struct dvb_frontend *fe)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	struct m88rs6000t_dev *dev = fe->tuner_priv;
45062306a36Sopenharmony_ci	int ret;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	dev_dbg(&dev->client->dev, "%s:\n", __func__);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x07, 0x6d);
45562306a36Sopenharmony_ci	if (ret) {
45662306a36Sopenharmony_ci		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
45762306a36Sopenharmony_ci		return ret;
45862306a36Sopenharmony_ci	}
45962306a36Sopenharmony_ci	usleep_range(5000, 10000);
46062306a36Sopenharmony_ci	return 0;
46162306a36Sopenharmony_ci}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_cistatic int m88rs6000t_get_frequency(struct dvb_frontend *fe, u32 *frequency)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	struct m88rs6000t_dev *dev = fe->tuner_priv;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	dev_dbg(&dev->client->dev, "\n");
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	*frequency = dev->frequency_khz;
47062306a36Sopenharmony_ci	return 0;
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_cistatic int m88rs6000t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
47462306a36Sopenharmony_ci{
47562306a36Sopenharmony_ci	struct m88rs6000t_dev *dev = fe->tuner_priv;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	dev_dbg(&dev->client->dev, "\n");
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	*frequency = 0; /* Zero-IF */
48062306a36Sopenharmony_ci	return 0;
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_cistatic int m88rs6000t_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
48562306a36Sopenharmony_ci{
48662306a36Sopenharmony_ci	struct m88rs6000t_dev *dev = fe->tuner_priv;
48762306a36Sopenharmony_ci	unsigned int val, i;
48862306a36Sopenharmony_ci	int ret;
48962306a36Sopenharmony_ci	u16 gain;
49062306a36Sopenharmony_ci	u32 PGA2_cri_GS = 46, PGA2_crf_GS = 290, TIA_GS = 290;
49162306a36Sopenharmony_ci	u32 RF_GC = 1200, IF_GC = 1100, BB_GC = 300;
49262306a36Sopenharmony_ci	u32 PGA2_GC = 300, TIA_GC = 300, PGA2_cri = 0, PGA2_crf = 0;
49362306a36Sopenharmony_ci	u32 RFG = 0, IFG = 0, BBG = 0, PGA2G = 0, TIAG = 0;
49462306a36Sopenharmony_ci	u32 RFGS[13] = {0, 245, 266, 268, 270, 285,
49562306a36Sopenharmony_ci			298, 295, 283, 285, 285, 300, 300};
49662306a36Sopenharmony_ci	u32 IFGS[12] = {0, 300, 230, 270, 270, 285,
49762306a36Sopenharmony_ci			295, 285, 290, 295, 295, 310};
49862306a36Sopenharmony_ci	u32 BBGS[14] = {0, 286, 275, 290, 294, 300, 290,
49962306a36Sopenharmony_ci			290, 285, 283, 260, 295, 290, 260};
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x5A, &val);
50262306a36Sopenharmony_ci	if (ret)
50362306a36Sopenharmony_ci		goto err;
50462306a36Sopenharmony_ci	RF_GC = val & 0x0f;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x5F, &val);
50762306a36Sopenharmony_ci	if (ret)
50862306a36Sopenharmony_ci		goto err;
50962306a36Sopenharmony_ci	IF_GC = val & 0x0f;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x3F, &val);
51262306a36Sopenharmony_ci	if (ret)
51362306a36Sopenharmony_ci		goto err;
51462306a36Sopenharmony_ci	TIA_GC = (val >> 4) & 0x07;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x77, &val);
51762306a36Sopenharmony_ci	if (ret)
51862306a36Sopenharmony_ci		goto err;
51962306a36Sopenharmony_ci	BB_GC = (val >> 4) & 0x0f;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x76, &val);
52262306a36Sopenharmony_ci	if (ret)
52362306a36Sopenharmony_ci		goto err;
52462306a36Sopenharmony_ci	PGA2_GC = val & 0x3f;
52562306a36Sopenharmony_ci	PGA2_cri = PGA2_GC >> 2;
52662306a36Sopenharmony_ci	PGA2_crf = PGA2_GC & 0x03;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	for (i = 0; i <= RF_GC && i < ARRAY_SIZE(RFGS); i++)
52962306a36Sopenharmony_ci		RFG += RFGS[i];
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	if (RF_GC == 0)
53262306a36Sopenharmony_ci		RFG += 400;
53362306a36Sopenharmony_ci	if (RF_GC == 1)
53462306a36Sopenharmony_ci		RFG += 300;
53562306a36Sopenharmony_ci	if (RF_GC == 2)
53662306a36Sopenharmony_ci		RFG += 200;
53762306a36Sopenharmony_ci	if (RF_GC == 3)
53862306a36Sopenharmony_ci		RFG += 100;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	for (i = 0; i <= IF_GC && i < ARRAY_SIZE(IFGS); i++)
54162306a36Sopenharmony_ci		IFG += IFGS[i];
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	TIAG = TIA_GC * TIA_GS;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	for (i = 0; i <= BB_GC && i < ARRAY_SIZE(BBGS); i++)
54662306a36Sopenharmony_ci		BBG += BBGS[i];
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	PGA2G = PGA2_cri * PGA2_cri_GS + PGA2_crf * PGA2_crf_GS;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	gain = RFG + IFG - TIAG + BBG + PGA2G;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	/* scale value to 0x0000-0xffff */
55362306a36Sopenharmony_ci	gain = clamp_val(gain, 1000U, 10500U);
55462306a36Sopenharmony_ci	*strength = (10500 - gain) * 0xffff / (10500 - 1000);
55562306a36Sopenharmony_cierr:
55662306a36Sopenharmony_ci	if (ret)
55762306a36Sopenharmony_ci		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
55862306a36Sopenharmony_ci	return ret;
55962306a36Sopenharmony_ci}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_cistatic const struct dvb_tuner_ops m88rs6000t_tuner_ops = {
56262306a36Sopenharmony_ci	.info = {
56362306a36Sopenharmony_ci		.name             = "Montage M88RS6000 Internal Tuner",
56462306a36Sopenharmony_ci		.frequency_min_hz =  950 * MHz,
56562306a36Sopenharmony_ci		.frequency_max_hz = 2150 * MHz,
56662306a36Sopenharmony_ci	},
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	.init = m88rs6000t_init,
56962306a36Sopenharmony_ci	.sleep = m88rs6000t_sleep,
57062306a36Sopenharmony_ci	.set_params = m88rs6000t_set_params,
57162306a36Sopenharmony_ci	.get_frequency = m88rs6000t_get_frequency,
57262306a36Sopenharmony_ci	.get_if_frequency = m88rs6000t_get_if_frequency,
57362306a36Sopenharmony_ci	.get_rf_strength = m88rs6000t_get_rf_strength,
57462306a36Sopenharmony_ci};
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_cistatic int m88rs6000t_probe(struct i2c_client *client)
57762306a36Sopenharmony_ci{
57862306a36Sopenharmony_ci	struct m88rs6000t_config *cfg = client->dev.platform_data;
57962306a36Sopenharmony_ci	struct dvb_frontend *fe = cfg->fe;
58062306a36Sopenharmony_ci	struct m88rs6000t_dev *dev;
58162306a36Sopenharmony_ci	int ret, i;
58262306a36Sopenharmony_ci	unsigned int utmp;
58362306a36Sopenharmony_ci	static const struct regmap_config regmap_config = {
58462306a36Sopenharmony_ci		.reg_bits = 8,
58562306a36Sopenharmony_ci		.val_bits = 8,
58662306a36Sopenharmony_ci	};
58762306a36Sopenharmony_ci	static const struct m88rs6000t_reg_val reg_vals[] = {
58862306a36Sopenharmony_ci		{0x10, 0xfb},
58962306a36Sopenharmony_ci		{0x24, 0x38},
59062306a36Sopenharmony_ci		{0x11, 0x0a},
59162306a36Sopenharmony_ci		{0x12, 0x00},
59262306a36Sopenharmony_ci		{0x2b, 0x1c},
59362306a36Sopenharmony_ci		{0x44, 0x48},
59462306a36Sopenharmony_ci		{0x54, 0x24},
59562306a36Sopenharmony_ci		{0x55, 0x06},
59662306a36Sopenharmony_ci		{0x59, 0x00},
59762306a36Sopenharmony_ci		{0x5b, 0x4c},
59862306a36Sopenharmony_ci		{0x60, 0x8b},
59962306a36Sopenharmony_ci		{0x61, 0xf4},
60062306a36Sopenharmony_ci		{0x65, 0x07},
60162306a36Sopenharmony_ci		{0x6d, 0x6f},
60262306a36Sopenharmony_ci		{0x6e, 0x31},
60362306a36Sopenharmony_ci		{0x3c, 0xf3},
60462306a36Sopenharmony_ci		{0x37, 0x0f},
60562306a36Sopenharmony_ci		{0x48, 0x28},
60662306a36Sopenharmony_ci		{0x49, 0xd8},
60762306a36Sopenharmony_ci		{0x70, 0x66},
60862306a36Sopenharmony_ci		{0x71, 0xCF},
60962306a36Sopenharmony_ci		{0x72, 0x81},
61062306a36Sopenharmony_ci		{0x73, 0xA7},
61162306a36Sopenharmony_ci		{0x74, 0x4F},
61262306a36Sopenharmony_ci		{0x75, 0xFC},
61362306a36Sopenharmony_ci	};
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
61662306a36Sopenharmony_ci	if (!dev) {
61762306a36Sopenharmony_ci		ret = -ENOMEM;
61862306a36Sopenharmony_ci		dev_err(&client->dev, "kzalloc() failed\n");
61962306a36Sopenharmony_ci		goto err;
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	memcpy(&dev->cfg, cfg, sizeof(struct m88rs6000t_config));
62362306a36Sopenharmony_ci	dev->client = client;
62462306a36Sopenharmony_ci	dev->regmap = devm_regmap_init_i2c(client, &regmap_config);
62562306a36Sopenharmony_ci	if (IS_ERR(dev->regmap)) {
62662306a36Sopenharmony_ci		ret = PTR_ERR(dev->regmap);
62762306a36Sopenharmony_ci		goto err;
62862306a36Sopenharmony_ci	}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	ret = regmap_update_bits(dev->regmap, 0x11, 0x08, 0x08);
63162306a36Sopenharmony_ci	if (ret)
63262306a36Sopenharmony_ci		goto err;
63362306a36Sopenharmony_ci	usleep_range(5000, 50000);
63462306a36Sopenharmony_ci	ret = regmap_update_bits(dev->regmap, 0x10, 0x01, 0x01);
63562306a36Sopenharmony_ci	if (ret)
63662306a36Sopenharmony_ci		goto err;
63762306a36Sopenharmony_ci	usleep_range(10000, 50000);
63862306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x07, 0x7d);
63962306a36Sopenharmony_ci	if (ret)
64062306a36Sopenharmony_ci		goto err;
64162306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x04, 0x01);
64262306a36Sopenharmony_ci	if (ret)
64362306a36Sopenharmony_ci		goto err;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	/* check tuner chip id */
64662306a36Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x01, &utmp);
64762306a36Sopenharmony_ci	if (ret)
64862306a36Sopenharmony_ci		goto err;
64962306a36Sopenharmony_ci	dev_info(&dev->client->dev, "chip_id=%02x\n", utmp);
65062306a36Sopenharmony_ci	if (utmp != 0x64) {
65162306a36Sopenharmony_ci		ret = -ENODEV;
65262306a36Sopenharmony_ci		goto err;
65362306a36Sopenharmony_ci	}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	/* tuner init. */
65662306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x05, 0x40);
65762306a36Sopenharmony_ci	if (ret)
65862306a36Sopenharmony_ci		goto err;
65962306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x11, 0x08);
66062306a36Sopenharmony_ci	if (ret)
66162306a36Sopenharmony_ci		goto err;
66262306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x15, 0x6c);
66362306a36Sopenharmony_ci	if (ret)
66462306a36Sopenharmony_ci		goto err;
66562306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x17, 0xc1);
66662306a36Sopenharmony_ci	if (ret)
66762306a36Sopenharmony_ci		goto err;
66862306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x17, 0x81);
66962306a36Sopenharmony_ci	if (ret)
67062306a36Sopenharmony_ci		goto err;
67162306a36Sopenharmony_ci	usleep_range(10000, 50000);
67262306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x05, 0x00);
67362306a36Sopenharmony_ci	if (ret)
67462306a36Sopenharmony_ci		goto err;
67562306a36Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x11, 0x0a);
67662306a36Sopenharmony_ci	if (ret)
67762306a36Sopenharmony_ci		goto err;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(reg_vals); i++) {
68062306a36Sopenharmony_ci		ret = regmap_write(dev->regmap,
68162306a36Sopenharmony_ci				reg_vals[i].reg, reg_vals[i].val);
68262306a36Sopenharmony_ci		if (ret)
68362306a36Sopenharmony_ci			goto err;
68462306a36Sopenharmony_ci	}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	dev_info(&dev->client->dev, "Montage M88RS6000 internal tuner successfully identified\n");
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	fe->tuner_priv = dev;
68962306a36Sopenharmony_ci	memcpy(&fe->ops.tuner_ops, &m88rs6000t_tuner_ops,
69062306a36Sopenharmony_ci			sizeof(struct dvb_tuner_ops));
69162306a36Sopenharmony_ci	i2c_set_clientdata(client, dev);
69262306a36Sopenharmony_ci	return 0;
69362306a36Sopenharmony_cierr:
69462306a36Sopenharmony_ci	dev_dbg(&client->dev, "failed=%d\n", ret);
69562306a36Sopenharmony_ci	kfree(dev);
69662306a36Sopenharmony_ci	return ret;
69762306a36Sopenharmony_ci}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_cistatic void m88rs6000t_remove(struct i2c_client *client)
70062306a36Sopenharmony_ci{
70162306a36Sopenharmony_ci	struct m88rs6000t_dev *dev = i2c_get_clientdata(client);
70262306a36Sopenharmony_ci	struct dvb_frontend *fe = dev->cfg.fe;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	dev_dbg(&client->dev, "\n");
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
70762306a36Sopenharmony_ci	fe->tuner_priv = NULL;
70862306a36Sopenharmony_ci	kfree(dev);
70962306a36Sopenharmony_ci}
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_cistatic const struct i2c_device_id m88rs6000t_id[] = {
71262306a36Sopenharmony_ci	{"m88rs6000t", 0},
71362306a36Sopenharmony_ci	{}
71462306a36Sopenharmony_ci};
71562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, m88rs6000t_id);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_cistatic struct i2c_driver m88rs6000t_driver = {
71862306a36Sopenharmony_ci	.driver = {
71962306a36Sopenharmony_ci		.name	= "m88rs6000t",
72062306a36Sopenharmony_ci	},
72162306a36Sopenharmony_ci	.probe		= m88rs6000t_probe,
72262306a36Sopenharmony_ci	.remove		= m88rs6000t_remove,
72362306a36Sopenharmony_ci	.id_table	= m88rs6000t_id,
72462306a36Sopenharmony_ci};
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_cimodule_i2c_driver(m88rs6000t_driver);
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ciMODULE_AUTHOR("Max nibble <nibble.max@gmail.com>");
72962306a36Sopenharmony_ciMODULE_DESCRIPTION("Montage M88RS6000 internal tuner driver");
73062306a36Sopenharmony_ciMODULE_LICENSE("GPL");
731