xref: /openbmc/linux/drivers/media/tuners/m88rs6000t.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
233382911Snibble.max /*
333382911Snibble.max  * Driver for the internal tuner of Montage M88RS6000
433382911Snibble.max  *
533382911Snibble.max  * Copyright (C) 2014 Max nibble <nibble.max@gmail.com>
633382911Snibble.max  */
733382911Snibble.max 
833382911Snibble.max #include "m88rs6000t.h"
933382911Snibble.max #include <linux/regmap.h>
1033382911Snibble.max 
1133382911Snibble.max struct m88rs6000t_dev {
1233382911Snibble.max 	struct m88rs6000t_config cfg;
1333382911Snibble.max 	struct i2c_client *client;
1433382911Snibble.max 	struct regmap *regmap;
1533382911Snibble.max 	u32 frequency_khz;
1633382911Snibble.max };
1733382911Snibble.max 
1833382911Snibble.max struct m88rs6000t_reg_val {
1933382911Snibble.max 	u8 reg;
2033382911Snibble.max 	u8 val;
2133382911Snibble.max };
2233382911Snibble.max 
2333382911Snibble.max /* set demod main mclk and ts mclk */
m88rs6000t_set_demod_mclk(struct dvb_frontend * fe)2433382911Snibble.max static int m88rs6000t_set_demod_mclk(struct dvb_frontend *fe)
2533382911Snibble.max {
2633382911Snibble.max 	struct m88rs6000t_dev *dev = fe->tuner_priv;
2733382911Snibble.max 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
2833382911Snibble.max 	u8 reg11, reg15, reg16, reg1D, reg1E, reg1F;
2933382911Snibble.max 	u8 N, f0 = 0, f1 = 0, f2 = 0, f3 = 0;
3033382911Snibble.max 	u16 pll_div_fb;
3133382911Snibble.max 	u32 div, ts_mclk;
3233382911Snibble.max 	unsigned int utmp;
3333382911Snibble.max 	int ret;
3433382911Snibble.max 
3533382911Snibble.max 	/* select demod main mclk */
3633382911Snibble.max 	ret = regmap_read(dev->regmap, 0x15, &utmp);
3733382911Snibble.max 	if (ret)
3833382911Snibble.max 		goto err;
3933382911Snibble.max 	reg15 = utmp;
4033382911Snibble.max 	if (c->symbol_rate > 45010000) {
4133382911Snibble.max 		reg11 = 0x0E;
4233382911Snibble.max 		reg15 |= 0x02;
4333382911Snibble.max 		reg16 = 115; /* mclk = 110.25MHz */
4433382911Snibble.max 	} else {
4533382911Snibble.max 		reg11 = 0x0A;
4633382911Snibble.max 		reg15 &= ~0x02;
4733382911Snibble.max 		reg16 = 96; /* mclk = 96MHz */
4833382911Snibble.max 	}
4933382911Snibble.max 
5033382911Snibble.max 	/* set ts mclk */
5133382911Snibble.max 	if (c->delivery_system == SYS_DVBS)
5233382911Snibble.max 		ts_mclk = 96000;
5333382911Snibble.max 	else
5433382911Snibble.max 		ts_mclk = 144000;
5533382911Snibble.max 
5633382911Snibble.max 	pll_div_fb = (reg15 & 0x01) << 8;
5733382911Snibble.max 	pll_div_fb += reg16;
5833382911Snibble.max 	pll_div_fb += 32;
5933382911Snibble.max 
6033382911Snibble.max 	div = 36000 * pll_div_fb;
6133382911Snibble.max 	div /= ts_mclk;
6233382911Snibble.max 
6333382911Snibble.max 	if (div <= 32) {
6433382911Snibble.max 		N = 2;
6533382911Snibble.max 		f0 = 0;
6633382911Snibble.max 		f1 = div / 2;
6733382911Snibble.max 		f2 = div - f1;
6833382911Snibble.max 		f3 = 0;
6933382911Snibble.max 	} else if (div <= 48) {
7033382911Snibble.max 		N = 3;
7133382911Snibble.max 		f0 = div / 3;
7233382911Snibble.max 		f1 = (div - f0) / 2;
7333382911Snibble.max 		f2 = div - f0 - f1;
7433382911Snibble.max 		f3 = 0;
7533382911Snibble.max 	} else if (div <= 64) {
7633382911Snibble.max 		N = 4;
7733382911Snibble.max 		f0 = div / 4;
7833382911Snibble.max 		f1 = (div - f0) / 3;
7933382911Snibble.max 		f2 = (div - f0 - f1) / 2;
8033382911Snibble.max 		f3 = div - f0 - f1 - f2;
8133382911Snibble.max 	} else {
8233382911Snibble.max 		N = 4;
8333382911Snibble.max 		f0 = 16;
8433382911Snibble.max 		f1 = 16;
8533382911Snibble.max 		f2 = 16;
8633382911Snibble.max 		f3 = 16;
8733382911Snibble.max 	}
8833382911Snibble.max 
8933382911Snibble.max 	if (f0 == 16)
9033382911Snibble.max 		f0 = 0;
9133382911Snibble.max 	if (f1 == 16)
9233382911Snibble.max 		f1 = 0;
9333382911Snibble.max 	if (f2 == 16)
9433382911Snibble.max 		f2 = 0;
9533382911Snibble.max 	if (f3 == 16)
9633382911Snibble.max 		f3 = 0;
9733382911Snibble.max 
9833382911Snibble.max 	ret = regmap_read(dev->regmap, 0x1D, &utmp);
9933382911Snibble.max 	if (ret)
10033382911Snibble.max 		goto err;
10133382911Snibble.max 	reg1D = utmp;
10233382911Snibble.max 	reg1D &= ~0x03;
10333382911Snibble.max 	reg1D |= N - 1;
10433382911Snibble.max 	reg1E = ((f3 << 4) + f2) & 0xFF;
10533382911Snibble.max 	reg1F = ((f1 << 4) + f0) & 0xFF;
10633382911Snibble.max 
10733382911Snibble.max 	/* program and recalibrate demod PLL */
10833382911Snibble.max 	ret = regmap_write(dev->regmap, 0x05, 0x40);
10933382911Snibble.max 	if (ret)
11033382911Snibble.max 		goto err;
11133382911Snibble.max 	ret = regmap_write(dev->regmap, 0x11, 0x08);
11233382911Snibble.max 	if (ret)
11333382911Snibble.max 		goto err;
11433382911Snibble.max 	ret = regmap_write(dev->regmap, 0x15, reg15);
11533382911Snibble.max 	if (ret)
11633382911Snibble.max 		goto err;
11733382911Snibble.max 	ret = regmap_write(dev->regmap, 0x16, reg16);
11833382911Snibble.max 	if (ret)
11933382911Snibble.max 		goto err;
12033382911Snibble.max 	ret = regmap_write(dev->regmap, 0x1D, reg1D);
12133382911Snibble.max 	if (ret)
12233382911Snibble.max 		goto err;
12333382911Snibble.max 	ret = regmap_write(dev->regmap, 0x1E, reg1E);
12433382911Snibble.max 	if (ret)
12533382911Snibble.max 		goto err;
12633382911Snibble.max 	ret = regmap_write(dev->regmap, 0x1F, reg1F);
12733382911Snibble.max 	if (ret)
12833382911Snibble.max 		goto err;
12933382911Snibble.max 	ret = regmap_write(dev->regmap, 0x17, 0xc1);
13033382911Snibble.max 	if (ret)
13133382911Snibble.max 		goto err;
13233382911Snibble.max 	ret = regmap_write(dev->regmap, 0x17, 0x81);
13333382911Snibble.max 	if (ret)
13433382911Snibble.max 		goto err;
13533382911Snibble.max 	usleep_range(5000, 50000);
13633382911Snibble.max 	ret = regmap_write(dev->regmap, 0x05, 0x00);
13733382911Snibble.max 	if (ret)
13833382911Snibble.max 		goto err;
13933382911Snibble.max 	ret = regmap_write(dev->regmap, 0x11, reg11);
14033382911Snibble.max 	if (ret)
14133382911Snibble.max 		goto err;
14233382911Snibble.max 	usleep_range(5000, 50000);
14333382911Snibble.max err:
14433382911Snibble.max 	if (ret)
14533382911Snibble.max 		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
14633382911Snibble.max 	return ret;
14733382911Snibble.max }
14833382911Snibble.max 
m88rs6000t_set_pll_freq(struct m88rs6000t_dev * dev,u32 tuner_freq_MHz)14933382911Snibble.max static int m88rs6000t_set_pll_freq(struct m88rs6000t_dev *dev,
15033382911Snibble.max 			u32 tuner_freq_MHz)
15133382911Snibble.max {
15233382911Snibble.max 	u32 fcry_KHz, ulNDiv1, ulNDiv2, ulNDiv;
15333382911Snibble.max 	u8 refDiv, ucLoDiv1, ucLomod1, ucLoDiv2, ucLomod2, ucLoDiv, ucLomod;
15433382911Snibble.max 	u8 reg27, reg29, reg42, reg42buf;
15533382911Snibble.max 	unsigned int utmp;
15633382911Snibble.max 	int ret;
15733382911Snibble.max 
15833382911Snibble.max 	fcry_KHz = 27000; /* in kHz */
15933382911Snibble.max 	refDiv = 27;
16033382911Snibble.max 
16133382911Snibble.max 	ret = regmap_write(dev->regmap, 0x36, (refDiv - 8));
16233382911Snibble.max 	if (ret)
16333382911Snibble.max 		goto err;
16433382911Snibble.max 	ret = regmap_write(dev->regmap, 0x31, 0x00);
16533382911Snibble.max 	if (ret)
16633382911Snibble.max 		goto err;
16733382911Snibble.max 	ret = regmap_write(dev->regmap, 0x2c, 0x02);
16833382911Snibble.max 	if (ret)
16933382911Snibble.max 		goto err;
17033382911Snibble.max 
17133382911Snibble.max 	if (tuner_freq_MHz >= 1550) {
17233382911Snibble.max 		ucLoDiv1 = 2;
17333382911Snibble.max 		ucLomod1 = 0;
17433382911Snibble.max 		ucLoDiv2 = 2;
17533382911Snibble.max 		ucLomod2 = 0;
17633382911Snibble.max 	} else if (tuner_freq_MHz >= 1380) {
17733382911Snibble.max 		ucLoDiv1 = 3;
17833382911Snibble.max 		ucLomod1 = 16;
17933382911Snibble.max 		ucLoDiv2 = 2;
18033382911Snibble.max 		ucLomod2 = 0;
18133382911Snibble.max 	} else if (tuner_freq_MHz >= 1070) {
18233382911Snibble.max 		ucLoDiv1 = 3;
18333382911Snibble.max 		ucLomod1 = 16;
18433382911Snibble.max 		ucLoDiv2 = 3;
18533382911Snibble.max 		ucLomod2 = 16;
18633382911Snibble.max 	} else if (tuner_freq_MHz >= 1000) {
18733382911Snibble.max 		ucLoDiv1 = 3;
18833382911Snibble.max 		ucLomod1 = 16;
18933382911Snibble.max 		ucLoDiv2 = 4;
19033382911Snibble.max 		ucLomod2 = 64;
19133382911Snibble.max 	} else if (tuner_freq_MHz >= 775) {
19233382911Snibble.max 		ucLoDiv1 = 4;
19333382911Snibble.max 		ucLomod1 = 64;
19433382911Snibble.max 		ucLoDiv2 = 4;
19533382911Snibble.max 		ucLomod2 = 64;
19633382911Snibble.max 	} else if (tuner_freq_MHz >= 700) {
19733382911Snibble.max 		ucLoDiv1 = 6;
19833382911Snibble.max 		ucLomod1 = 48;
19933382911Snibble.max 		ucLoDiv2 = 4;
20033382911Snibble.max 		ucLomod2 = 64;
20133382911Snibble.max 	} else if (tuner_freq_MHz >= 520) {
20233382911Snibble.max 		ucLoDiv1 = 6;
20333382911Snibble.max 		ucLomod1 = 48;
20433382911Snibble.max 		ucLoDiv2 = 6;
20533382911Snibble.max 		ucLomod2 = 48;
20633382911Snibble.max 	} else {
20733382911Snibble.max 		ucLoDiv1 = 8;
20833382911Snibble.max 		ucLomod1 = 96;
20933382911Snibble.max 		ucLoDiv2 = 8;
21033382911Snibble.max 		ucLomod2 = 96;
21133382911Snibble.max 	}
21233382911Snibble.max 
21333382911Snibble.max 	ulNDiv1 = ((tuner_freq_MHz * ucLoDiv1 * 1000) * refDiv
21433382911Snibble.max 			/ fcry_KHz - 1024) / 2;
21533382911Snibble.max 	ulNDiv2 = ((tuner_freq_MHz * ucLoDiv2 * 1000) * refDiv
21633382911Snibble.max 			/ fcry_KHz - 1024) / 2;
21733382911Snibble.max 
21833382911Snibble.max 	reg27 = (((ulNDiv1 >> 8) & 0x0F) + ucLomod1) & 0x7F;
21933382911Snibble.max 	ret = regmap_write(dev->regmap, 0x27, reg27);
22033382911Snibble.max 	if (ret)
22133382911Snibble.max 		goto err;
22233382911Snibble.max 	ret = regmap_write(dev->regmap, 0x28, (u8)(ulNDiv1 & 0xFF));
22333382911Snibble.max 	if (ret)
22433382911Snibble.max 		goto err;
22533382911Snibble.max 	reg29 = (((ulNDiv2 >> 8) & 0x0F) + ucLomod2) & 0x7f;
22633382911Snibble.max 	ret = regmap_write(dev->regmap, 0x29, reg29);
22733382911Snibble.max 	if (ret)
22833382911Snibble.max 		goto err;
22933382911Snibble.max 	ret = regmap_write(dev->regmap, 0x2a, (u8)(ulNDiv2 & 0xFF));
23033382911Snibble.max 	if (ret)
23133382911Snibble.max 		goto err;
23233382911Snibble.max 	ret = regmap_write(dev->regmap, 0x2F, 0xf5);
23333382911Snibble.max 	if (ret)
23433382911Snibble.max 		goto err;
23533382911Snibble.max 	ret = regmap_write(dev->regmap, 0x30, 0x05);
23633382911Snibble.max 	if (ret)
23733382911Snibble.max 		goto err;
23833382911Snibble.max 	ret = regmap_write(dev->regmap, 0x08, 0x1f);
23933382911Snibble.max 	if (ret)
24033382911Snibble.max 		goto err;
24133382911Snibble.max 	ret = regmap_write(dev->regmap, 0x08, 0x3f);
24233382911Snibble.max 	if (ret)
24333382911Snibble.max 		goto err;
24433382911Snibble.max 	ret = regmap_write(dev->regmap, 0x09, 0x20);
24533382911Snibble.max 	if (ret)
24633382911Snibble.max 		goto err;
24733382911Snibble.max 	ret = regmap_write(dev->regmap, 0x09, 0x00);
24833382911Snibble.max 	if (ret)
24933382911Snibble.max 		goto err;
25033382911Snibble.max 	ret = regmap_write(dev->regmap, 0x3e, 0x11);
25133382911Snibble.max 	if (ret)
25233382911Snibble.max 		goto err;
25333382911Snibble.max 	ret = regmap_write(dev->regmap, 0x08, 0x2f);
25433382911Snibble.max 	if (ret)
25533382911Snibble.max 		goto err;
25633382911Snibble.max 	ret = regmap_write(dev->regmap, 0x08, 0x3f);
25733382911Snibble.max 	if (ret)
25833382911Snibble.max 		goto err;
25933382911Snibble.max 	ret = regmap_write(dev->regmap, 0x09, 0x10);
26033382911Snibble.max 	if (ret)
26133382911Snibble.max 		goto err;
26233382911Snibble.max 	ret = regmap_write(dev->regmap, 0x09, 0x00);
26333382911Snibble.max 	if (ret)
26433382911Snibble.max 		goto err;
26533382911Snibble.max 	usleep_range(2000, 50000);
26633382911Snibble.max 
26733382911Snibble.max 	ret = regmap_read(dev->regmap, 0x42, &utmp);
26833382911Snibble.max 	if (ret)
26933382911Snibble.max 		goto err;
27033382911Snibble.max 	reg42 = utmp;
27133382911Snibble.max 
27233382911Snibble.max 	ret = regmap_write(dev->regmap, 0x3e, 0x10);
27333382911Snibble.max 	if (ret)
27433382911Snibble.max 		goto err;
27533382911Snibble.max 	ret = regmap_write(dev->regmap, 0x08, 0x2f);
27633382911Snibble.max 	if (ret)
27733382911Snibble.max 		goto err;
27833382911Snibble.max 	ret = regmap_write(dev->regmap, 0x08, 0x3f);
27933382911Snibble.max 	if (ret)
28033382911Snibble.max 		goto err;
28133382911Snibble.max 	ret = regmap_write(dev->regmap, 0x09, 0x10);
28233382911Snibble.max 	if (ret)
28333382911Snibble.max 		goto err;
28433382911Snibble.max 	ret = regmap_write(dev->regmap, 0x09, 0x00);
28533382911Snibble.max 	if (ret)
28633382911Snibble.max 		goto err;
28733382911Snibble.max 	usleep_range(2000, 50000);
28833382911Snibble.max 
28933382911Snibble.max 	ret = regmap_read(dev->regmap, 0x42, &utmp);
29033382911Snibble.max 	if (ret)
29133382911Snibble.max 		goto err;
29233382911Snibble.max 	reg42buf = utmp;
29333382911Snibble.max 	if (reg42buf < reg42) {
29433382911Snibble.max 		ret = regmap_write(dev->regmap, 0x3e, 0x11);
29533382911Snibble.max 		if (ret)
29633382911Snibble.max 			goto err;
29733382911Snibble.max 	}
29833382911Snibble.max 	usleep_range(5000, 50000);
29933382911Snibble.max 
30033382911Snibble.max 	ret = regmap_read(dev->regmap, 0x2d, &utmp);
30133382911Snibble.max 	if (ret)
30233382911Snibble.max 		goto err;
30333382911Snibble.max 	ret = regmap_write(dev->regmap, 0x2d, utmp);
30433382911Snibble.max 	if (ret)
30533382911Snibble.max 		goto err;
30633382911Snibble.max 	ret = regmap_read(dev->regmap, 0x2e, &utmp);
30733382911Snibble.max 	if (ret)
30833382911Snibble.max 		goto err;
30933382911Snibble.max 	ret = regmap_write(dev->regmap, 0x2e, utmp);
31033382911Snibble.max 	if (ret)
31133382911Snibble.max 		goto err;
31233382911Snibble.max 
31333382911Snibble.max 	ret = regmap_read(dev->regmap, 0x27, &utmp);
31433382911Snibble.max 	if (ret)
31533382911Snibble.max 		goto err;
31633382911Snibble.max 	reg27 = utmp & 0x70;
31733382911Snibble.max 	ret = regmap_read(dev->regmap, 0x83, &utmp);
31833382911Snibble.max 	if (ret)
31933382911Snibble.max 		goto err;
32033382911Snibble.max 	if (reg27 == (utmp & 0x70)) {
32133382911Snibble.max 		ucLoDiv	= ucLoDiv1;
32233382911Snibble.max 		ulNDiv = ulNDiv1;
32333382911Snibble.max 		ucLomod = ucLomod1 / 16;
32433382911Snibble.max 	} else {
32533382911Snibble.max 		ucLoDiv	= ucLoDiv2;
32633382911Snibble.max 		ulNDiv = ulNDiv2;
32733382911Snibble.max 		ucLomod = ucLomod2 / 16;
32833382911Snibble.max 	}
32933382911Snibble.max 
33033382911Snibble.max 	if ((ucLoDiv == 3) || (ucLoDiv == 6)) {
33133382911Snibble.max 		refDiv = 18;
33233382911Snibble.max 		ret = regmap_write(dev->regmap, 0x36, (refDiv - 8));
33333382911Snibble.max 		if (ret)
33433382911Snibble.max 			goto err;
33533382911Snibble.max 		ulNDiv = ((tuner_freq_MHz * ucLoDiv * 1000) * refDiv
33633382911Snibble.max 				/ fcry_KHz - 1024) / 2;
33733382911Snibble.max 	}
33833382911Snibble.max 
33933382911Snibble.max 	reg27 = (0x80 + ((ucLomod << 4) & 0x70)
34033382911Snibble.max 			+ ((ulNDiv >> 8) & 0x0F)) & 0xFF;
34133382911Snibble.max 	ret = regmap_write(dev->regmap, 0x27, reg27);
34233382911Snibble.max 	if (ret)
34333382911Snibble.max 		goto err;
34433382911Snibble.max 	ret = regmap_write(dev->regmap, 0x28, (u8)(ulNDiv & 0xFF));
34533382911Snibble.max 	if (ret)
34633382911Snibble.max 		goto err;
34733382911Snibble.max 	ret = regmap_write(dev->regmap, 0x29, 0x80);
34833382911Snibble.max 	if (ret)
34933382911Snibble.max 		goto err;
35033382911Snibble.max 	ret = regmap_write(dev->regmap, 0x31, 0x03);
35133382911Snibble.max 	if (ret)
35233382911Snibble.max 		goto err;
35333382911Snibble.max 
35433382911Snibble.max 	if (ucLoDiv == 3)
35533382911Snibble.max 		utmp = 0xCE;
35633382911Snibble.max 	else
35733382911Snibble.max 		utmp = 0x8A;
35833382911Snibble.max 	ret = regmap_write(dev->regmap, 0x3b, utmp);
35933382911Snibble.max 	if (ret)
36033382911Snibble.max 		goto err;
36133382911Snibble.max 
36233382911Snibble.max 	dev->frequency_khz = fcry_KHz * (ulNDiv * 2 + 1024) / refDiv / ucLoDiv;
36333382911Snibble.max 
36433382911Snibble.max 	dev_dbg(&dev->client->dev,
36533382911Snibble.max 		"actual tune frequency=%d\n", dev->frequency_khz);
36633382911Snibble.max err:
36733382911Snibble.max 	if (ret)
36833382911Snibble.max 		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
36933382911Snibble.max 	return ret;
37033382911Snibble.max }
37133382911Snibble.max 
m88rs6000t_set_bb(struct m88rs6000t_dev * dev,u32 symbol_rate_KSs,s32 lpf_offset_KHz)37233382911Snibble.max static int m88rs6000t_set_bb(struct m88rs6000t_dev *dev,
37333382911Snibble.max 		u32 symbol_rate_KSs, s32 lpf_offset_KHz)
37433382911Snibble.max {
37533382911Snibble.max 	u32 f3dB;
37633382911Snibble.max 	u8  reg40;
37733382911Snibble.max 
37833382911Snibble.max 	f3dB = symbol_rate_KSs * 9 / 14 + 2000;
37933382911Snibble.max 	f3dB += lpf_offset_KHz;
38033382911Snibble.max 	f3dB = clamp_val(f3dB, 6000U, 43000U);
38133382911Snibble.max 	reg40 = f3dB / 1000;
38233382911Snibble.max 	return regmap_write(dev->regmap, 0x40, reg40);
38333382911Snibble.max }
38433382911Snibble.max 
m88rs6000t_set_params(struct dvb_frontend * fe)38533382911Snibble.max static int m88rs6000t_set_params(struct dvb_frontend *fe)
38633382911Snibble.max {
38733382911Snibble.max 	struct m88rs6000t_dev *dev = fe->tuner_priv;
38833382911Snibble.max 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
38933382911Snibble.max 	int ret;
39033382911Snibble.max 	s32 lpf_offset_KHz;
39133382911Snibble.max 	u32 realFreq, freq_MHz;
39233382911Snibble.max 
39333382911Snibble.max 	dev_dbg(&dev->client->dev,
39433382911Snibble.max 			"frequency=%d symbol_rate=%d\n",
39533382911Snibble.max 			c->frequency, c->symbol_rate);
39633382911Snibble.max 
39733382911Snibble.max 	if (c->symbol_rate < 5000000)
39833382911Snibble.max 		lpf_offset_KHz = 3000;
39933382911Snibble.max 	else
40033382911Snibble.max 		lpf_offset_KHz = 0;
40133382911Snibble.max 
40233382911Snibble.max 	realFreq = c->frequency + lpf_offset_KHz;
40333382911Snibble.max 	/* set tuner pll.*/
40433382911Snibble.max 	freq_MHz = (realFreq + 500) / 1000;
40533382911Snibble.max 	ret = m88rs6000t_set_pll_freq(dev, freq_MHz);
40633382911Snibble.max 	if (ret)
40733382911Snibble.max 		goto err;
40833382911Snibble.max 	ret = m88rs6000t_set_bb(dev, c->symbol_rate / 1000, lpf_offset_KHz);
40933382911Snibble.max 	if (ret)
41033382911Snibble.max 		goto err;
41133382911Snibble.max 	ret = regmap_write(dev->regmap, 0x00, 0x01);
41233382911Snibble.max 	if (ret)
41333382911Snibble.max 		goto err;
41433382911Snibble.max 	ret = regmap_write(dev->regmap, 0x00, 0x00);
41533382911Snibble.max 	if (ret)
41633382911Snibble.max 		goto err;
41733382911Snibble.max 	/* set demod mlck */
41833382911Snibble.max 	ret = m88rs6000t_set_demod_mclk(fe);
41933382911Snibble.max err:
42033382911Snibble.max 	if (ret)
42133382911Snibble.max 		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
42233382911Snibble.max 	return ret;
42333382911Snibble.max }
42433382911Snibble.max 
m88rs6000t_init(struct dvb_frontend * fe)42533382911Snibble.max static int m88rs6000t_init(struct dvb_frontend *fe)
42633382911Snibble.max {
42733382911Snibble.max 	struct m88rs6000t_dev *dev = fe->tuner_priv;
42833382911Snibble.max 	int ret;
42933382911Snibble.max 
43033382911Snibble.max 	dev_dbg(&dev->client->dev, "%s:\n", __func__);
43133382911Snibble.max 
43233382911Snibble.max 	ret = regmap_update_bits(dev->regmap, 0x11, 0x08, 0x08);
43333382911Snibble.max 	if (ret)
43433382911Snibble.max 		goto err;
43533382911Snibble.max 	usleep_range(5000, 50000);
43633382911Snibble.max 	ret = regmap_update_bits(dev->regmap, 0x10, 0x01, 0x01);
43733382911Snibble.max 	if (ret)
43833382911Snibble.max 		goto err;
43933382911Snibble.max 	usleep_range(10000, 50000);
44033382911Snibble.max 	ret = regmap_write(dev->regmap, 0x07, 0x7d);
44133382911Snibble.max err:
44233382911Snibble.max 	if (ret)
44333382911Snibble.max 		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
44433382911Snibble.max 	return ret;
44533382911Snibble.max }
44633382911Snibble.max 
m88rs6000t_sleep(struct dvb_frontend * fe)44733382911Snibble.max static int m88rs6000t_sleep(struct dvb_frontend *fe)
44833382911Snibble.max {
44933382911Snibble.max 	struct m88rs6000t_dev *dev = fe->tuner_priv;
45033382911Snibble.max 	int ret;
45133382911Snibble.max 
45233382911Snibble.max 	dev_dbg(&dev->client->dev, "%s:\n", __func__);
45333382911Snibble.max 
45433382911Snibble.max 	ret = regmap_write(dev->regmap, 0x07, 0x6d);
4552050d14cSMarkus Elfring 	if (ret) {
45633382911Snibble.max 		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
45733382911Snibble.max 		return ret;
45833382911Snibble.max 	}
4592050d14cSMarkus Elfring 	usleep_range(5000, 10000);
4602050d14cSMarkus Elfring 	return 0;
4612050d14cSMarkus Elfring }
46233382911Snibble.max 
m88rs6000t_get_frequency(struct dvb_frontend * fe,u32 * frequency)46333382911Snibble.max static int m88rs6000t_get_frequency(struct dvb_frontend *fe, u32 *frequency)
46433382911Snibble.max {
46533382911Snibble.max 	struct m88rs6000t_dev *dev = fe->tuner_priv;
46633382911Snibble.max 
46733382911Snibble.max 	dev_dbg(&dev->client->dev, "\n");
46833382911Snibble.max 
46933382911Snibble.max 	*frequency = dev->frequency_khz;
47033382911Snibble.max 	return 0;
47133382911Snibble.max }
47233382911Snibble.max 
m88rs6000t_get_if_frequency(struct dvb_frontend * fe,u32 * frequency)47333382911Snibble.max static int m88rs6000t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
47433382911Snibble.max {
47533382911Snibble.max 	struct m88rs6000t_dev *dev = fe->tuner_priv;
47633382911Snibble.max 
47733382911Snibble.max 	dev_dbg(&dev->client->dev, "\n");
47833382911Snibble.max 
47933382911Snibble.max 	*frequency = 0; /* Zero-IF */
48033382911Snibble.max 	return 0;
48133382911Snibble.max }
48233382911Snibble.max 
48333382911Snibble.max 
m88rs6000t_get_rf_strength(struct dvb_frontend * fe,u16 * strength)48433382911Snibble.max static int m88rs6000t_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
48533382911Snibble.max {
48633382911Snibble.max 	struct m88rs6000t_dev *dev = fe->tuner_priv;
48733382911Snibble.max 	unsigned int val, i;
48833382911Snibble.max 	int ret;
48933382911Snibble.max 	u16 gain;
49033382911Snibble.max 	u32 PGA2_cri_GS = 46, PGA2_crf_GS = 290, TIA_GS = 290;
49133382911Snibble.max 	u32 RF_GC = 1200, IF_GC = 1100, BB_GC = 300;
49233382911Snibble.max 	u32 PGA2_GC = 300, TIA_GC = 300, PGA2_cri = 0, PGA2_crf = 0;
49333382911Snibble.max 	u32 RFG = 0, IFG = 0, BBG = 0, PGA2G = 0, TIAG = 0;
49433382911Snibble.max 	u32 RFGS[13] = {0, 245, 266, 268, 270, 285,
49533382911Snibble.max 			298, 295, 283, 285, 285, 300, 300};
49633382911Snibble.max 	u32 IFGS[12] = {0, 300, 230, 270, 270, 285,
49733382911Snibble.max 			295, 285, 290, 295, 295, 310};
49833382911Snibble.max 	u32 BBGS[14] = {0, 286, 275, 290, 294, 300, 290,
49933382911Snibble.max 			290, 285, 283, 260, 295, 290, 260};
50033382911Snibble.max 
50133382911Snibble.max 	ret = regmap_read(dev->regmap, 0x5A, &val);
50233382911Snibble.max 	if (ret)
50333382911Snibble.max 		goto err;
50433382911Snibble.max 	RF_GC = val & 0x0f;
50533382911Snibble.max 
50633382911Snibble.max 	ret = regmap_read(dev->regmap, 0x5F, &val);
50733382911Snibble.max 	if (ret)
50833382911Snibble.max 		goto err;
50933382911Snibble.max 	IF_GC = val & 0x0f;
51033382911Snibble.max 
51133382911Snibble.max 	ret = regmap_read(dev->regmap, 0x3F, &val);
51233382911Snibble.max 	if (ret)
51333382911Snibble.max 		goto err;
51433382911Snibble.max 	TIA_GC = (val >> 4) & 0x07;
51533382911Snibble.max 
51633382911Snibble.max 	ret = regmap_read(dev->regmap, 0x77, &val);
51733382911Snibble.max 	if (ret)
51833382911Snibble.max 		goto err;
51933382911Snibble.max 	BB_GC = (val >> 4) & 0x0f;
52033382911Snibble.max 
52133382911Snibble.max 	ret = regmap_read(dev->regmap, 0x76, &val);
52233382911Snibble.max 	if (ret)
52333382911Snibble.max 		goto err;
52433382911Snibble.max 	PGA2_GC = val & 0x3f;
52533382911Snibble.max 	PGA2_cri = PGA2_GC >> 2;
52633382911Snibble.max 	PGA2_crf = PGA2_GC & 0x03;
52733382911Snibble.max 
5289baa3d64SColin Ian King 	for (i = 0; i <= RF_GC && i < ARRAY_SIZE(RFGS); i++)
52933382911Snibble.max 		RFG += RFGS[i];
53033382911Snibble.max 
53133382911Snibble.max 	if (RF_GC == 0)
53233382911Snibble.max 		RFG += 400;
53333382911Snibble.max 	if (RF_GC == 1)
53433382911Snibble.max 		RFG += 300;
53533382911Snibble.max 	if (RF_GC == 2)
53633382911Snibble.max 		RFG += 200;
53733382911Snibble.max 	if (RF_GC == 3)
53833382911Snibble.max 		RFG += 100;
53933382911Snibble.max 
5409baa3d64SColin Ian King 	for (i = 0; i <= IF_GC && i < ARRAY_SIZE(IFGS); i++)
54133382911Snibble.max 		IFG += IFGS[i];
54233382911Snibble.max 
54333382911Snibble.max 	TIAG = TIA_GC * TIA_GS;
54433382911Snibble.max 
5459baa3d64SColin Ian King 	for (i = 0; i <= BB_GC && i < ARRAY_SIZE(BBGS); i++)
54633382911Snibble.max 		BBG += BBGS[i];
54733382911Snibble.max 
54833382911Snibble.max 	PGA2G = PGA2_cri * PGA2_cri_GS + PGA2_crf * PGA2_crf_GS;
54933382911Snibble.max 
55033382911Snibble.max 	gain = RFG + IFG - TIAG + BBG + PGA2G;
55133382911Snibble.max 
55233382911Snibble.max 	/* scale value to 0x0000-0xffff */
55333382911Snibble.max 	gain = clamp_val(gain, 1000U, 10500U);
55433382911Snibble.max 	*strength = (10500 - gain) * 0xffff / (10500 - 1000);
55533382911Snibble.max err:
55633382911Snibble.max 	if (ret)
55733382911Snibble.max 		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
55833382911Snibble.max 	return ret;
55933382911Snibble.max }
56033382911Snibble.max 
56133382911Snibble.max static const struct dvb_tuner_ops m88rs6000t_tuner_ops = {
56233382911Snibble.max 	.info = {
56333382911Snibble.max 		.name             = "Montage M88RS6000 Internal Tuner",
564a3f90c75SMauro Carvalho Chehab 		.frequency_min_hz =  950 * MHz,
565a3f90c75SMauro Carvalho Chehab 		.frequency_max_hz = 2150 * MHz,
56633382911Snibble.max 	},
56733382911Snibble.max 
56833382911Snibble.max 	.init = m88rs6000t_init,
56933382911Snibble.max 	.sleep = m88rs6000t_sleep,
57033382911Snibble.max 	.set_params = m88rs6000t_set_params,
57133382911Snibble.max 	.get_frequency = m88rs6000t_get_frequency,
57233382911Snibble.max 	.get_if_frequency = m88rs6000t_get_if_frequency,
57333382911Snibble.max 	.get_rf_strength = m88rs6000t_get_rf_strength,
57433382911Snibble.max };
57533382911Snibble.max 
m88rs6000t_probe(struct i2c_client * client)5760be78933SUwe Kleine-König static int m88rs6000t_probe(struct i2c_client *client)
57733382911Snibble.max {
57833382911Snibble.max 	struct m88rs6000t_config *cfg = client->dev.platform_data;
57933382911Snibble.max 	struct dvb_frontend *fe = cfg->fe;
58033382911Snibble.max 	struct m88rs6000t_dev *dev;
58133382911Snibble.max 	int ret, i;
58233382911Snibble.max 	unsigned int utmp;
58333382911Snibble.max 	static const struct regmap_config regmap_config = {
58433382911Snibble.max 		.reg_bits = 8,
58533382911Snibble.max 		.val_bits = 8,
58633382911Snibble.max 	};
58733382911Snibble.max 	static const struct m88rs6000t_reg_val reg_vals[] = {
58833382911Snibble.max 		{0x10, 0xfb},
58933382911Snibble.max 		{0x24, 0x38},
59033382911Snibble.max 		{0x11, 0x0a},
59133382911Snibble.max 		{0x12, 0x00},
59233382911Snibble.max 		{0x2b, 0x1c},
59333382911Snibble.max 		{0x44, 0x48},
59433382911Snibble.max 		{0x54, 0x24},
59533382911Snibble.max 		{0x55, 0x06},
59633382911Snibble.max 		{0x59, 0x00},
59733382911Snibble.max 		{0x5b, 0x4c},
59833382911Snibble.max 		{0x60, 0x8b},
59933382911Snibble.max 		{0x61, 0xf4},
60033382911Snibble.max 		{0x65, 0x07},
60133382911Snibble.max 		{0x6d, 0x6f},
60233382911Snibble.max 		{0x6e, 0x31},
60333382911Snibble.max 		{0x3c, 0xf3},
60433382911Snibble.max 		{0x37, 0x0f},
60533382911Snibble.max 		{0x48, 0x28},
60633382911Snibble.max 		{0x49, 0xd8},
60733382911Snibble.max 		{0x70, 0x66},
60833382911Snibble.max 		{0x71, 0xCF},
60933382911Snibble.max 		{0x72, 0x81},
61033382911Snibble.max 		{0x73, 0xA7},
61133382911Snibble.max 		{0x74, 0x4F},
61233382911Snibble.max 		{0x75, 0xFC},
61333382911Snibble.max 	};
61433382911Snibble.max 
61533382911Snibble.max 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
61633382911Snibble.max 	if (!dev) {
61733382911Snibble.max 		ret = -ENOMEM;
61833382911Snibble.max 		dev_err(&client->dev, "kzalloc() failed\n");
61933382911Snibble.max 		goto err;
62033382911Snibble.max 	}
62133382911Snibble.max 
62233382911Snibble.max 	memcpy(&dev->cfg, cfg, sizeof(struct m88rs6000t_config));
62333382911Snibble.max 	dev->client = client;
62433382911Snibble.max 	dev->regmap = devm_regmap_init_i2c(client, &regmap_config);
62533382911Snibble.max 	if (IS_ERR(dev->regmap)) {
62633382911Snibble.max 		ret = PTR_ERR(dev->regmap);
62733382911Snibble.max 		goto err;
62833382911Snibble.max 	}
62933382911Snibble.max 
63033382911Snibble.max 	ret = regmap_update_bits(dev->regmap, 0x11, 0x08, 0x08);
63133382911Snibble.max 	if (ret)
63233382911Snibble.max 		goto err;
63333382911Snibble.max 	usleep_range(5000, 50000);
63433382911Snibble.max 	ret = regmap_update_bits(dev->regmap, 0x10, 0x01, 0x01);
63533382911Snibble.max 	if (ret)
63633382911Snibble.max 		goto err;
63733382911Snibble.max 	usleep_range(10000, 50000);
63833382911Snibble.max 	ret = regmap_write(dev->regmap, 0x07, 0x7d);
63933382911Snibble.max 	if (ret)
64033382911Snibble.max 		goto err;
64133382911Snibble.max 	ret = regmap_write(dev->regmap, 0x04, 0x01);
64233382911Snibble.max 	if (ret)
64333382911Snibble.max 		goto err;
64433382911Snibble.max 
64533382911Snibble.max 	/* check tuner chip id */
64633382911Snibble.max 	ret = regmap_read(dev->regmap, 0x01, &utmp);
64733382911Snibble.max 	if (ret)
64833382911Snibble.max 		goto err;
64933382911Snibble.max 	dev_info(&dev->client->dev, "chip_id=%02x\n", utmp);
65033382911Snibble.max 	if (utmp != 0x64) {
65133382911Snibble.max 		ret = -ENODEV;
65233382911Snibble.max 		goto err;
65333382911Snibble.max 	}
65433382911Snibble.max 
65533382911Snibble.max 	/* tuner init. */
65633382911Snibble.max 	ret = regmap_write(dev->regmap, 0x05, 0x40);
65733382911Snibble.max 	if (ret)
65833382911Snibble.max 		goto err;
65933382911Snibble.max 	ret = regmap_write(dev->regmap, 0x11, 0x08);
66033382911Snibble.max 	if (ret)
66133382911Snibble.max 		goto err;
66233382911Snibble.max 	ret = regmap_write(dev->regmap, 0x15, 0x6c);
66333382911Snibble.max 	if (ret)
66433382911Snibble.max 		goto err;
66533382911Snibble.max 	ret = regmap_write(dev->regmap, 0x17, 0xc1);
66633382911Snibble.max 	if (ret)
66733382911Snibble.max 		goto err;
66833382911Snibble.max 	ret = regmap_write(dev->regmap, 0x17, 0x81);
66933382911Snibble.max 	if (ret)
67033382911Snibble.max 		goto err;
67133382911Snibble.max 	usleep_range(10000, 50000);
67233382911Snibble.max 	ret = regmap_write(dev->regmap, 0x05, 0x00);
67333382911Snibble.max 	if (ret)
67433382911Snibble.max 		goto err;
67533382911Snibble.max 	ret = regmap_write(dev->regmap, 0x11, 0x0a);
67633382911Snibble.max 	if (ret)
67733382911Snibble.max 		goto err;
67833382911Snibble.max 
67933382911Snibble.max 	for (i = 0; i < ARRAY_SIZE(reg_vals); i++) {
68033382911Snibble.max 		ret = regmap_write(dev->regmap,
68133382911Snibble.max 				reg_vals[i].reg, reg_vals[i].val);
68233382911Snibble.max 		if (ret)
68333382911Snibble.max 			goto err;
68433382911Snibble.max 	}
68533382911Snibble.max 
68633382911Snibble.max 	dev_info(&dev->client->dev, "Montage M88RS6000 internal tuner successfully identified\n");
68733382911Snibble.max 
68833382911Snibble.max 	fe->tuner_priv = dev;
68933382911Snibble.max 	memcpy(&fe->ops.tuner_ops, &m88rs6000t_tuner_ops,
69033382911Snibble.max 			sizeof(struct dvb_tuner_ops));
69133382911Snibble.max 	i2c_set_clientdata(client, dev);
69233382911Snibble.max 	return 0;
69333382911Snibble.max err:
69433382911Snibble.max 	dev_dbg(&client->dev, "failed=%d\n", ret);
69533382911Snibble.max 	kfree(dev);
69633382911Snibble.max 	return ret;
69733382911Snibble.max }
69833382911Snibble.max 
m88rs6000t_remove(struct i2c_client * client)699ed5c2f5fSUwe Kleine-König static void m88rs6000t_remove(struct i2c_client *client)
70033382911Snibble.max {
70133382911Snibble.max 	struct m88rs6000t_dev *dev = i2c_get_clientdata(client);
70233382911Snibble.max 	struct dvb_frontend *fe = dev->cfg.fe;
70333382911Snibble.max 
70433382911Snibble.max 	dev_dbg(&client->dev, "\n");
70533382911Snibble.max 
70633382911Snibble.max 	memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
70733382911Snibble.max 	fe->tuner_priv = NULL;
70833382911Snibble.max 	kfree(dev);
70933382911Snibble.max }
71033382911Snibble.max 
71133382911Snibble.max static const struct i2c_device_id m88rs6000t_id[] = {
71233382911Snibble.max 	{"m88rs6000t", 0},
71333382911Snibble.max 	{}
71433382911Snibble.max };
71533382911Snibble.max MODULE_DEVICE_TABLE(i2c, m88rs6000t_id);
71633382911Snibble.max 
71733382911Snibble.max static struct i2c_driver m88rs6000t_driver = {
71833382911Snibble.max 	.driver = {
71933382911Snibble.max 		.name	= "m88rs6000t",
72033382911Snibble.max 	},
721*aaeb31c0SUwe Kleine-König 	.probe		= m88rs6000t_probe,
72233382911Snibble.max 	.remove		= m88rs6000t_remove,
72333382911Snibble.max 	.id_table	= m88rs6000t_id,
72433382911Snibble.max };
72533382911Snibble.max 
72633382911Snibble.max module_i2c_driver(m88rs6000t_driver);
72733382911Snibble.max 
72833382911Snibble.max MODULE_AUTHOR("Max nibble <nibble.max@gmail.com>");
72933382911Snibble.max MODULE_DESCRIPTION("Montage M88RS6000 internal tuner driver");
73033382911Snibble.max MODULE_LICENSE("GPL");
731