18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Driver for the internal tuner of Montage M88RS6000
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2014 Max nibble <nibble.max@gmail.com>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include "m88rs6000t.h"
98c2ecf20Sopenharmony_ci#include <linux/regmap.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_cistruct m88rs6000t_dev {
128c2ecf20Sopenharmony_ci	struct m88rs6000t_config cfg;
138c2ecf20Sopenharmony_ci	struct i2c_client *client;
148c2ecf20Sopenharmony_ci	struct regmap *regmap;
158c2ecf20Sopenharmony_ci	u32 frequency_khz;
168c2ecf20Sopenharmony_ci};
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistruct m88rs6000t_reg_val {
198c2ecf20Sopenharmony_ci	u8 reg;
208c2ecf20Sopenharmony_ci	u8 val;
218c2ecf20Sopenharmony_ci};
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/* set demod main mclk and ts mclk */
248c2ecf20Sopenharmony_cistatic int m88rs6000t_set_demod_mclk(struct dvb_frontend *fe)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	struct m88rs6000t_dev *dev = fe->tuner_priv;
278c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
288c2ecf20Sopenharmony_ci	u8 reg11, reg15, reg16, reg1D, reg1E, reg1F;
298c2ecf20Sopenharmony_ci	u8 N, f0 = 0, f1 = 0, f2 = 0, f3 = 0;
308c2ecf20Sopenharmony_ci	u16 pll_div_fb;
318c2ecf20Sopenharmony_ci	u32 div, ts_mclk;
328c2ecf20Sopenharmony_ci	unsigned int utmp;
338c2ecf20Sopenharmony_ci	int ret;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	/* select demod main mclk */
368c2ecf20Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x15, &utmp);
378c2ecf20Sopenharmony_ci	if (ret)
388c2ecf20Sopenharmony_ci		goto err;
398c2ecf20Sopenharmony_ci	reg15 = utmp;
408c2ecf20Sopenharmony_ci	if (c->symbol_rate > 45010000) {
418c2ecf20Sopenharmony_ci		reg11 = 0x0E;
428c2ecf20Sopenharmony_ci		reg15 |= 0x02;
438c2ecf20Sopenharmony_ci		reg16 = 115; /* mclk = 110.25MHz */
448c2ecf20Sopenharmony_ci	} else {
458c2ecf20Sopenharmony_ci		reg11 = 0x0A;
468c2ecf20Sopenharmony_ci		reg15 &= ~0x02;
478c2ecf20Sopenharmony_ci		reg16 = 96; /* mclk = 96MHz */
488c2ecf20Sopenharmony_ci	}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	/* set ts mclk */
518c2ecf20Sopenharmony_ci	if (c->delivery_system == SYS_DVBS)
528c2ecf20Sopenharmony_ci		ts_mclk = 96000;
538c2ecf20Sopenharmony_ci	else
548c2ecf20Sopenharmony_ci		ts_mclk = 144000;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	pll_div_fb = (reg15 & 0x01) << 8;
578c2ecf20Sopenharmony_ci	pll_div_fb += reg16;
588c2ecf20Sopenharmony_ci	pll_div_fb += 32;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	div = 36000 * pll_div_fb;
618c2ecf20Sopenharmony_ci	div /= ts_mclk;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	if (div <= 32) {
648c2ecf20Sopenharmony_ci		N = 2;
658c2ecf20Sopenharmony_ci		f0 = 0;
668c2ecf20Sopenharmony_ci		f1 = div / 2;
678c2ecf20Sopenharmony_ci		f2 = div - f1;
688c2ecf20Sopenharmony_ci		f3 = 0;
698c2ecf20Sopenharmony_ci	} else if (div <= 48) {
708c2ecf20Sopenharmony_ci		N = 3;
718c2ecf20Sopenharmony_ci		f0 = div / 3;
728c2ecf20Sopenharmony_ci		f1 = (div - f0) / 2;
738c2ecf20Sopenharmony_ci		f2 = div - f0 - f1;
748c2ecf20Sopenharmony_ci		f3 = 0;
758c2ecf20Sopenharmony_ci	} else if (div <= 64) {
768c2ecf20Sopenharmony_ci		N = 4;
778c2ecf20Sopenharmony_ci		f0 = div / 4;
788c2ecf20Sopenharmony_ci		f1 = (div - f0) / 3;
798c2ecf20Sopenharmony_ci		f2 = (div - f0 - f1) / 2;
808c2ecf20Sopenharmony_ci		f3 = div - f0 - f1 - f2;
818c2ecf20Sopenharmony_ci	} else {
828c2ecf20Sopenharmony_ci		N = 4;
838c2ecf20Sopenharmony_ci		f0 = 16;
848c2ecf20Sopenharmony_ci		f1 = 16;
858c2ecf20Sopenharmony_ci		f2 = 16;
868c2ecf20Sopenharmony_ci		f3 = 16;
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	if (f0 == 16)
908c2ecf20Sopenharmony_ci		f0 = 0;
918c2ecf20Sopenharmony_ci	if (f1 == 16)
928c2ecf20Sopenharmony_ci		f1 = 0;
938c2ecf20Sopenharmony_ci	if (f2 == 16)
948c2ecf20Sopenharmony_ci		f2 = 0;
958c2ecf20Sopenharmony_ci	if (f3 == 16)
968c2ecf20Sopenharmony_ci		f3 = 0;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x1D, &utmp);
998c2ecf20Sopenharmony_ci	if (ret)
1008c2ecf20Sopenharmony_ci		goto err;
1018c2ecf20Sopenharmony_ci	reg1D = utmp;
1028c2ecf20Sopenharmony_ci	reg1D &= ~0x03;
1038c2ecf20Sopenharmony_ci	reg1D |= N - 1;
1048c2ecf20Sopenharmony_ci	reg1E = ((f3 << 4) + f2) & 0xFF;
1058c2ecf20Sopenharmony_ci	reg1F = ((f1 << 4) + f0) & 0xFF;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	/* program and recalibrate demod PLL */
1088c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x05, 0x40);
1098c2ecf20Sopenharmony_ci	if (ret)
1108c2ecf20Sopenharmony_ci		goto err;
1118c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x11, 0x08);
1128c2ecf20Sopenharmony_ci	if (ret)
1138c2ecf20Sopenharmony_ci		goto err;
1148c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x15, reg15);
1158c2ecf20Sopenharmony_ci	if (ret)
1168c2ecf20Sopenharmony_ci		goto err;
1178c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x16, reg16);
1188c2ecf20Sopenharmony_ci	if (ret)
1198c2ecf20Sopenharmony_ci		goto err;
1208c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x1D, reg1D);
1218c2ecf20Sopenharmony_ci	if (ret)
1228c2ecf20Sopenharmony_ci		goto err;
1238c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x1E, reg1E);
1248c2ecf20Sopenharmony_ci	if (ret)
1258c2ecf20Sopenharmony_ci		goto err;
1268c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x1F, reg1F);
1278c2ecf20Sopenharmony_ci	if (ret)
1288c2ecf20Sopenharmony_ci		goto err;
1298c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x17, 0xc1);
1308c2ecf20Sopenharmony_ci	if (ret)
1318c2ecf20Sopenharmony_ci		goto err;
1328c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x17, 0x81);
1338c2ecf20Sopenharmony_ci	if (ret)
1348c2ecf20Sopenharmony_ci		goto err;
1358c2ecf20Sopenharmony_ci	usleep_range(5000, 50000);
1368c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x05, 0x00);
1378c2ecf20Sopenharmony_ci	if (ret)
1388c2ecf20Sopenharmony_ci		goto err;
1398c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x11, reg11);
1408c2ecf20Sopenharmony_ci	if (ret)
1418c2ecf20Sopenharmony_ci		goto err;
1428c2ecf20Sopenharmony_ci	usleep_range(5000, 50000);
1438c2ecf20Sopenharmony_cierr:
1448c2ecf20Sopenharmony_ci	if (ret)
1458c2ecf20Sopenharmony_ci		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
1468c2ecf20Sopenharmony_ci	return ret;
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic int m88rs6000t_set_pll_freq(struct m88rs6000t_dev *dev,
1508c2ecf20Sopenharmony_ci			u32 tuner_freq_MHz)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	u32 fcry_KHz, ulNDiv1, ulNDiv2, ulNDiv;
1538c2ecf20Sopenharmony_ci	u8 refDiv, ucLoDiv1, ucLomod1, ucLoDiv2, ucLomod2, ucLoDiv, ucLomod;
1548c2ecf20Sopenharmony_ci	u8 reg27, reg29, reg42, reg42buf;
1558c2ecf20Sopenharmony_ci	unsigned int utmp;
1568c2ecf20Sopenharmony_ci	int ret;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	fcry_KHz = 27000; /* in kHz */
1598c2ecf20Sopenharmony_ci	refDiv = 27;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x36, (refDiv - 8));
1628c2ecf20Sopenharmony_ci	if (ret)
1638c2ecf20Sopenharmony_ci		goto err;
1648c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x31, 0x00);
1658c2ecf20Sopenharmony_ci	if (ret)
1668c2ecf20Sopenharmony_ci		goto err;
1678c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x2c, 0x02);
1688c2ecf20Sopenharmony_ci	if (ret)
1698c2ecf20Sopenharmony_ci		goto err;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	if (tuner_freq_MHz >= 1550) {
1728c2ecf20Sopenharmony_ci		ucLoDiv1 = 2;
1738c2ecf20Sopenharmony_ci		ucLomod1 = 0;
1748c2ecf20Sopenharmony_ci		ucLoDiv2 = 2;
1758c2ecf20Sopenharmony_ci		ucLomod2 = 0;
1768c2ecf20Sopenharmony_ci	} else if (tuner_freq_MHz >= 1380) {
1778c2ecf20Sopenharmony_ci		ucLoDiv1 = 3;
1788c2ecf20Sopenharmony_ci		ucLomod1 = 16;
1798c2ecf20Sopenharmony_ci		ucLoDiv2 = 2;
1808c2ecf20Sopenharmony_ci		ucLomod2 = 0;
1818c2ecf20Sopenharmony_ci	} else if (tuner_freq_MHz >= 1070) {
1828c2ecf20Sopenharmony_ci		ucLoDiv1 = 3;
1838c2ecf20Sopenharmony_ci		ucLomod1 = 16;
1848c2ecf20Sopenharmony_ci		ucLoDiv2 = 3;
1858c2ecf20Sopenharmony_ci		ucLomod2 = 16;
1868c2ecf20Sopenharmony_ci	} else if (tuner_freq_MHz >= 1000) {
1878c2ecf20Sopenharmony_ci		ucLoDiv1 = 3;
1888c2ecf20Sopenharmony_ci		ucLomod1 = 16;
1898c2ecf20Sopenharmony_ci		ucLoDiv2 = 4;
1908c2ecf20Sopenharmony_ci		ucLomod2 = 64;
1918c2ecf20Sopenharmony_ci	} else if (tuner_freq_MHz >= 775) {
1928c2ecf20Sopenharmony_ci		ucLoDiv1 = 4;
1938c2ecf20Sopenharmony_ci		ucLomod1 = 64;
1948c2ecf20Sopenharmony_ci		ucLoDiv2 = 4;
1958c2ecf20Sopenharmony_ci		ucLomod2 = 64;
1968c2ecf20Sopenharmony_ci	} else if (tuner_freq_MHz >= 700) {
1978c2ecf20Sopenharmony_ci		ucLoDiv1 = 6;
1988c2ecf20Sopenharmony_ci		ucLomod1 = 48;
1998c2ecf20Sopenharmony_ci		ucLoDiv2 = 4;
2008c2ecf20Sopenharmony_ci		ucLomod2 = 64;
2018c2ecf20Sopenharmony_ci	} else if (tuner_freq_MHz >= 520) {
2028c2ecf20Sopenharmony_ci		ucLoDiv1 = 6;
2038c2ecf20Sopenharmony_ci		ucLomod1 = 48;
2048c2ecf20Sopenharmony_ci		ucLoDiv2 = 6;
2058c2ecf20Sopenharmony_ci		ucLomod2 = 48;
2068c2ecf20Sopenharmony_ci	} else {
2078c2ecf20Sopenharmony_ci		ucLoDiv1 = 8;
2088c2ecf20Sopenharmony_ci		ucLomod1 = 96;
2098c2ecf20Sopenharmony_ci		ucLoDiv2 = 8;
2108c2ecf20Sopenharmony_ci		ucLomod2 = 96;
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	ulNDiv1 = ((tuner_freq_MHz * ucLoDiv1 * 1000) * refDiv
2148c2ecf20Sopenharmony_ci			/ fcry_KHz - 1024) / 2;
2158c2ecf20Sopenharmony_ci	ulNDiv2 = ((tuner_freq_MHz * ucLoDiv2 * 1000) * refDiv
2168c2ecf20Sopenharmony_ci			/ fcry_KHz - 1024) / 2;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	reg27 = (((ulNDiv1 >> 8) & 0x0F) + ucLomod1) & 0x7F;
2198c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x27, reg27);
2208c2ecf20Sopenharmony_ci	if (ret)
2218c2ecf20Sopenharmony_ci		goto err;
2228c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x28, (u8)(ulNDiv1 & 0xFF));
2238c2ecf20Sopenharmony_ci	if (ret)
2248c2ecf20Sopenharmony_ci		goto err;
2258c2ecf20Sopenharmony_ci	reg29 = (((ulNDiv2 >> 8) & 0x0F) + ucLomod2) & 0x7f;
2268c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x29, reg29);
2278c2ecf20Sopenharmony_ci	if (ret)
2288c2ecf20Sopenharmony_ci		goto err;
2298c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x2a, (u8)(ulNDiv2 & 0xFF));
2308c2ecf20Sopenharmony_ci	if (ret)
2318c2ecf20Sopenharmony_ci		goto err;
2328c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x2F, 0xf5);
2338c2ecf20Sopenharmony_ci	if (ret)
2348c2ecf20Sopenharmony_ci		goto err;
2358c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x30, 0x05);
2368c2ecf20Sopenharmony_ci	if (ret)
2378c2ecf20Sopenharmony_ci		goto err;
2388c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x08, 0x1f);
2398c2ecf20Sopenharmony_ci	if (ret)
2408c2ecf20Sopenharmony_ci		goto err;
2418c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x08, 0x3f);
2428c2ecf20Sopenharmony_ci	if (ret)
2438c2ecf20Sopenharmony_ci		goto err;
2448c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x09, 0x20);
2458c2ecf20Sopenharmony_ci	if (ret)
2468c2ecf20Sopenharmony_ci		goto err;
2478c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x09, 0x00);
2488c2ecf20Sopenharmony_ci	if (ret)
2498c2ecf20Sopenharmony_ci		goto err;
2508c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x3e, 0x11);
2518c2ecf20Sopenharmony_ci	if (ret)
2528c2ecf20Sopenharmony_ci		goto err;
2538c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x08, 0x2f);
2548c2ecf20Sopenharmony_ci	if (ret)
2558c2ecf20Sopenharmony_ci		goto err;
2568c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x08, 0x3f);
2578c2ecf20Sopenharmony_ci	if (ret)
2588c2ecf20Sopenharmony_ci		goto err;
2598c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x09, 0x10);
2608c2ecf20Sopenharmony_ci	if (ret)
2618c2ecf20Sopenharmony_ci		goto err;
2628c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x09, 0x00);
2638c2ecf20Sopenharmony_ci	if (ret)
2648c2ecf20Sopenharmony_ci		goto err;
2658c2ecf20Sopenharmony_ci	usleep_range(2000, 50000);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x42, &utmp);
2688c2ecf20Sopenharmony_ci	if (ret)
2698c2ecf20Sopenharmony_ci		goto err;
2708c2ecf20Sopenharmony_ci	reg42 = utmp;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x3e, 0x10);
2738c2ecf20Sopenharmony_ci	if (ret)
2748c2ecf20Sopenharmony_ci		goto err;
2758c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x08, 0x2f);
2768c2ecf20Sopenharmony_ci	if (ret)
2778c2ecf20Sopenharmony_ci		goto err;
2788c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x08, 0x3f);
2798c2ecf20Sopenharmony_ci	if (ret)
2808c2ecf20Sopenharmony_ci		goto err;
2818c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x09, 0x10);
2828c2ecf20Sopenharmony_ci	if (ret)
2838c2ecf20Sopenharmony_ci		goto err;
2848c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x09, 0x00);
2858c2ecf20Sopenharmony_ci	if (ret)
2868c2ecf20Sopenharmony_ci		goto err;
2878c2ecf20Sopenharmony_ci	usleep_range(2000, 50000);
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x42, &utmp);
2908c2ecf20Sopenharmony_ci	if (ret)
2918c2ecf20Sopenharmony_ci		goto err;
2928c2ecf20Sopenharmony_ci	reg42buf = utmp;
2938c2ecf20Sopenharmony_ci	if (reg42buf < reg42) {
2948c2ecf20Sopenharmony_ci		ret = regmap_write(dev->regmap, 0x3e, 0x11);
2958c2ecf20Sopenharmony_ci		if (ret)
2968c2ecf20Sopenharmony_ci			goto err;
2978c2ecf20Sopenharmony_ci	}
2988c2ecf20Sopenharmony_ci	usleep_range(5000, 50000);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x2d, &utmp);
3018c2ecf20Sopenharmony_ci	if (ret)
3028c2ecf20Sopenharmony_ci		goto err;
3038c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x2d, utmp);
3048c2ecf20Sopenharmony_ci	if (ret)
3058c2ecf20Sopenharmony_ci		goto err;
3068c2ecf20Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x2e, &utmp);
3078c2ecf20Sopenharmony_ci	if (ret)
3088c2ecf20Sopenharmony_ci		goto err;
3098c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x2e, utmp);
3108c2ecf20Sopenharmony_ci	if (ret)
3118c2ecf20Sopenharmony_ci		goto err;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x27, &utmp);
3148c2ecf20Sopenharmony_ci	if (ret)
3158c2ecf20Sopenharmony_ci		goto err;
3168c2ecf20Sopenharmony_ci	reg27 = utmp & 0x70;
3178c2ecf20Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x83, &utmp);
3188c2ecf20Sopenharmony_ci	if (ret)
3198c2ecf20Sopenharmony_ci		goto err;
3208c2ecf20Sopenharmony_ci	if (reg27 == (utmp & 0x70)) {
3218c2ecf20Sopenharmony_ci		ucLoDiv	= ucLoDiv1;
3228c2ecf20Sopenharmony_ci		ulNDiv = ulNDiv1;
3238c2ecf20Sopenharmony_ci		ucLomod = ucLomod1 / 16;
3248c2ecf20Sopenharmony_ci	} else {
3258c2ecf20Sopenharmony_ci		ucLoDiv	= ucLoDiv2;
3268c2ecf20Sopenharmony_ci		ulNDiv = ulNDiv2;
3278c2ecf20Sopenharmony_ci		ucLomod = ucLomod2 / 16;
3288c2ecf20Sopenharmony_ci	}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	if ((ucLoDiv == 3) || (ucLoDiv == 6)) {
3318c2ecf20Sopenharmony_ci		refDiv = 18;
3328c2ecf20Sopenharmony_ci		ret = regmap_write(dev->regmap, 0x36, (refDiv - 8));
3338c2ecf20Sopenharmony_ci		if (ret)
3348c2ecf20Sopenharmony_ci			goto err;
3358c2ecf20Sopenharmony_ci		ulNDiv = ((tuner_freq_MHz * ucLoDiv * 1000) * refDiv
3368c2ecf20Sopenharmony_ci				/ fcry_KHz - 1024) / 2;
3378c2ecf20Sopenharmony_ci	}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	reg27 = (0x80 + ((ucLomod << 4) & 0x70)
3408c2ecf20Sopenharmony_ci			+ ((ulNDiv >> 8) & 0x0F)) & 0xFF;
3418c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x27, reg27);
3428c2ecf20Sopenharmony_ci	if (ret)
3438c2ecf20Sopenharmony_ci		goto err;
3448c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x28, (u8)(ulNDiv & 0xFF));
3458c2ecf20Sopenharmony_ci	if (ret)
3468c2ecf20Sopenharmony_ci		goto err;
3478c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x29, 0x80);
3488c2ecf20Sopenharmony_ci	if (ret)
3498c2ecf20Sopenharmony_ci		goto err;
3508c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x31, 0x03);
3518c2ecf20Sopenharmony_ci	if (ret)
3528c2ecf20Sopenharmony_ci		goto err;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	if (ucLoDiv == 3)
3558c2ecf20Sopenharmony_ci		utmp = 0xCE;
3568c2ecf20Sopenharmony_ci	else
3578c2ecf20Sopenharmony_ci		utmp = 0x8A;
3588c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x3b, utmp);
3598c2ecf20Sopenharmony_ci	if (ret)
3608c2ecf20Sopenharmony_ci		goto err;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	dev->frequency_khz = fcry_KHz * (ulNDiv * 2 + 1024) / refDiv / ucLoDiv;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	dev_dbg(&dev->client->dev,
3658c2ecf20Sopenharmony_ci		"actual tune frequency=%d\n", dev->frequency_khz);
3668c2ecf20Sopenharmony_cierr:
3678c2ecf20Sopenharmony_ci	if (ret)
3688c2ecf20Sopenharmony_ci		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
3698c2ecf20Sopenharmony_ci	return ret;
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_cistatic int m88rs6000t_set_bb(struct m88rs6000t_dev *dev,
3738c2ecf20Sopenharmony_ci		u32 symbol_rate_KSs, s32 lpf_offset_KHz)
3748c2ecf20Sopenharmony_ci{
3758c2ecf20Sopenharmony_ci	u32 f3dB;
3768c2ecf20Sopenharmony_ci	u8  reg40;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	f3dB = symbol_rate_KSs * 9 / 14 + 2000;
3798c2ecf20Sopenharmony_ci	f3dB += lpf_offset_KHz;
3808c2ecf20Sopenharmony_ci	f3dB = clamp_val(f3dB, 6000U, 43000U);
3818c2ecf20Sopenharmony_ci	reg40 = f3dB / 1000;
3828c2ecf20Sopenharmony_ci	return regmap_write(dev->regmap, 0x40, reg40);
3838c2ecf20Sopenharmony_ci}
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_cistatic int m88rs6000t_set_params(struct dvb_frontend *fe)
3868c2ecf20Sopenharmony_ci{
3878c2ecf20Sopenharmony_ci	struct m88rs6000t_dev *dev = fe->tuner_priv;
3888c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
3898c2ecf20Sopenharmony_ci	int ret;
3908c2ecf20Sopenharmony_ci	s32 lpf_offset_KHz;
3918c2ecf20Sopenharmony_ci	u32 realFreq, freq_MHz;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	dev_dbg(&dev->client->dev,
3948c2ecf20Sopenharmony_ci			"frequency=%d symbol_rate=%d\n",
3958c2ecf20Sopenharmony_ci			c->frequency, c->symbol_rate);
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	if (c->symbol_rate < 5000000)
3988c2ecf20Sopenharmony_ci		lpf_offset_KHz = 3000;
3998c2ecf20Sopenharmony_ci	else
4008c2ecf20Sopenharmony_ci		lpf_offset_KHz = 0;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	realFreq = c->frequency + lpf_offset_KHz;
4038c2ecf20Sopenharmony_ci	/* set tuner pll.*/
4048c2ecf20Sopenharmony_ci	freq_MHz = (realFreq + 500) / 1000;
4058c2ecf20Sopenharmony_ci	ret = m88rs6000t_set_pll_freq(dev, freq_MHz);
4068c2ecf20Sopenharmony_ci	if (ret)
4078c2ecf20Sopenharmony_ci		goto err;
4088c2ecf20Sopenharmony_ci	ret = m88rs6000t_set_bb(dev, c->symbol_rate / 1000, lpf_offset_KHz);
4098c2ecf20Sopenharmony_ci	if (ret)
4108c2ecf20Sopenharmony_ci		goto err;
4118c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x00, 0x01);
4128c2ecf20Sopenharmony_ci	if (ret)
4138c2ecf20Sopenharmony_ci		goto err;
4148c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x00, 0x00);
4158c2ecf20Sopenharmony_ci	if (ret)
4168c2ecf20Sopenharmony_ci		goto err;
4178c2ecf20Sopenharmony_ci	/* set demod mlck */
4188c2ecf20Sopenharmony_ci	ret = m88rs6000t_set_demod_mclk(fe);
4198c2ecf20Sopenharmony_cierr:
4208c2ecf20Sopenharmony_ci	if (ret)
4218c2ecf20Sopenharmony_ci		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
4228c2ecf20Sopenharmony_ci	return ret;
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_cistatic int m88rs6000t_init(struct dvb_frontend *fe)
4268c2ecf20Sopenharmony_ci{
4278c2ecf20Sopenharmony_ci	struct m88rs6000t_dev *dev = fe->tuner_priv;
4288c2ecf20Sopenharmony_ci	int ret;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	dev_dbg(&dev->client->dev, "%s:\n", __func__);
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	ret = regmap_update_bits(dev->regmap, 0x11, 0x08, 0x08);
4338c2ecf20Sopenharmony_ci	if (ret)
4348c2ecf20Sopenharmony_ci		goto err;
4358c2ecf20Sopenharmony_ci	usleep_range(5000, 50000);
4368c2ecf20Sopenharmony_ci	ret = regmap_update_bits(dev->regmap, 0x10, 0x01, 0x01);
4378c2ecf20Sopenharmony_ci	if (ret)
4388c2ecf20Sopenharmony_ci		goto err;
4398c2ecf20Sopenharmony_ci	usleep_range(10000, 50000);
4408c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x07, 0x7d);
4418c2ecf20Sopenharmony_cierr:
4428c2ecf20Sopenharmony_ci	if (ret)
4438c2ecf20Sopenharmony_ci		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
4448c2ecf20Sopenharmony_ci	return ret;
4458c2ecf20Sopenharmony_ci}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_cistatic int m88rs6000t_sleep(struct dvb_frontend *fe)
4488c2ecf20Sopenharmony_ci{
4498c2ecf20Sopenharmony_ci	struct m88rs6000t_dev *dev = fe->tuner_priv;
4508c2ecf20Sopenharmony_ci	int ret;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	dev_dbg(&dev->client->dev, "%s:\n", __func__);
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x07, 0x6d);
4558c2ecf20Sopenharmony_ci	if (ret) {
4568c2ecf20Sopenharmony_ci		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
4578c2ecf20Sopenharmony_ci		return ret;
4588c2ecf20Sopenharmony_ci	}
4598c2ecf20Sopenharmony_ci	usleep_range(5000, 10000);
4608c2ecf20Sopenharmony_ci	return 0;
4618c2ecf20Sopenharmony_ci}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_cistatic int m88rs6000t_get_frequency(struct dvb_frontend *fe, u32 *frequency)
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	struct m88rs6000t_dev *dev = fe->tuner_priv;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	dev_dbg(&dev->client->dev, "\n");
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	*frequency = dev->frequency_khz;
4708c2ecf20Sopenharmony_ci	return 0;
4718c2ecf20Sopenharmony_ci}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_cistatic int m88rs6000t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	struct m88rs6000t_dev *dev = fe->tuner_priv;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	dev_dbg(&dev->client->dev, "\n");
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	*frequency = 0; /* Zero-IF */
4808c2ecf20Sopenharmony_ci	return 0;
4818c2ecf20Sopenharmony_ci}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_cistatic int m88rs6000t_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
4858c2ecf20Sopenharmony_ci{
4868c2ecf20Sopenharmony_ci	struct m88rs6000t_dev *dev = fe->tuner_priv;
4878c2ecf20Sopenharmony_ci	unsigned int val, i;
4888c2ecf20Sopenharmony_ci	int ret;
4898c2ecf20Sopenharmony_ci	u16 gain;
4908c2ecf20Sopenharmony_ci	u32 PGA2_cri_GS = 46, PGA2_crf_GS = 290, TIA_GS = 290;
4918c2ecf20Sopenharmony_ci	u32 RF_GC = 1200, IF_GC = 1100, BB_GC = 300;
4928c2ecf20Sopenharmony_ci	u32 PGA2_GC = 300, TIA_GC = 300, PGA2_cri = 0, PGA2_crf = 0;
4938c2ecf20Sopenharmony_ci	u32 RFG = 0, IFG = 0, BBG = 0, PGA2G = 0, TIAG = 0;
4948c2ecf20Sopenharmony_ci	u32 RFGS[13] = {0, 245, 266, 268, 270, 285,
4958c2ecf20Sopenharmony_ci			298, 295, 283, 285, 285, 300, 300};
4968c2ecf20Sopenharmony_ci	u32 IFGS[12] = {0, 300, 230, 270, 270, 285,
4978c2ecf20Sopenharmony_ci			295, 285, 290, 295, 295, 310};
4988c2ecf20Sopenharmony_ci	u32 BBGS[14] = {0, 286, 275, 290, 294, 300, 290,
4998c2ecf20Sopenharmony_ci			290, 285, 283, 260, 295, 290, 260};
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x5A, &val);
5028c2ecf20Sopenharmony_ci	if (ret)
5038c2ecf20Sopenharmony_ci		goto err;
5048c2ecf20Sopenharmony_ci	RF_GC = val & 0x0f;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x5F, &val);
5078c2ecf20Sopenharmony_ci	if (ret)
5088c2ecf20Sopenharmony_ci		goto err;
5098c2ecf20Sopenharmony_ci	IF_GC = val & 0x0f;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x3F, &val);
5128c2ecf20Sopenharmony_ci	if (ret)
5138c2ecf20Sopenharmony_ci		goto err;
5148c2ecf20Sopenharmony_ci	TIA_GC = (val >> 4) & 0x07;
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x77, &val);
5178c2ecf20Sopenharmony_ci	if (ret)
5188c2ecf20Sopenharmony_ci		goto err;
5198c2ecf20Sopenharmony_ci	BB_GC = (val >> 4) & 0x0f;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x76, &val);
5228c2ecf20Sopenharmony_ci	if (ret)
5238c2ecf20Sopenharmony_ci		goto err;
5248c2ecf20Sopenharmony_ci	PGA2_GC = val & 0x3f;
5258c2ecf20Sopenharmony_ci	PGA2_cri = PGA2_GC >> 2;
5268c2ecf20Sopenharmony_ci	PGA2_crf = PGA2_GC & 0x03;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	for (i = 0; i <= RF_GC && i < ARRAY_SIZE(RFGS); i++)
5298c2ecf20Sopenharmony_ci		RFG += RFGS[i];
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	if (RF_GC == 0)
5328c2ecf20Sopenharmony_ci		RFG += 400;
5338c2ecf20Sopenharmony_ci	if (RF_GC == 1)
5348c2ecf20Sopenharmony_ci		RFG += 300;
5358c2ecf20Sopenharmony_ci	if (RF_GC == 2)
5368c2ecf20Sopenharmony_ci		RFG += 200;
5378c2ecf20Sopenharmony_ci	if (RF_GC == 3)
5388c2ecf20Sopenharmony_ci		RFG += 100;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	for (i = 0; i <= IF_GC && i < ARRAY_SIZE(IFGS); i++)
5418c2ecf20Sopenharmony_ci		IFG += IFGS[i];
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	TIAG = TIA_GC * TIA_GS;
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	for (i = 0; i <= BB_GC && i < ARRAY_SIZE(BBGS); i++)
5468c2ecf20Sopenharmony_ci		BBG += BBGS[i];
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	PGA2G = PGA2_cri * PGA2_cri_GS + PGA2_crf * PGA2_crf_GS;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	gain = RFG + IFG - TIAG + BBG + PGA2G;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	/* scale value to 0x0000-0xffff */
5538c2ecf20Sopenharmony_ci	gain = clamp_val(gain, 1000U, 10500U);
5548c2ecf20Sopenharmony_ci	*strength = (10500 - gain) * 0xffff / (10500 - 1000);
5558c2ecf20Sopenharmony_cierr:
5568c2ecf20Sopenharmony_ci	if (ret)
5578c2ecf20Sopenharmony_ci		dev_dbg(&dev->client->dev, "failed=%d\n", ret);
5588c2ecf20Sopenharmony_ci	return ret;
5598c2ecf20Sopenharmony_ci}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_cistatic const struct dvb_tuner_ops m88rs6000t_tuner_ops = {
5628c2ecf20Sopenharmony_ci	.info = {
5638c2ecf20Sopenharmony_ci		.name             = "Montage M88RS6000 Internal Tuner",
5648c2ecf20Sopenharmony_ci		.frequency_min_hz =  950 * MHz,
5658c2ecf20Sopenharmony_ci		.frequency_max_hz = 2150 * MHz,
5668c2ecf20Sopenharmony_ci	},
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	.init = m88rs6000t_init,
5698c2ecf20Sopenharmony_ci	.sleep = m88rs6000t_sleep,
5708c2ecf20Sopenharmony_ci	.set_params = m88rs6000t_set_params,
5718c2ecf20Sopenharmony_ci	.get_frequency = m88rs6000t_get_frequency,
5728c2ecf20Sopenharmony_ci	.get_if_frequency = m88rs6000t_get_if_frequency,
5738c2ecf20Sopenharmony_ci	.get_rf_strength = m88rs6000t_get_rf_strength,
5748c2ecf20Sopenharmony_ci};
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_cistatic int m88rs6000t_probe(struct i2c_client *client,
5778c2ecf20Sopenharmony_ci		const struct i2c_device_id *id)
5788c2ecf20Sopenharmony_ci{
5798c2ecf20Sopenharmony_ci	struct m88rs6000t_config *cfg = client->dev.platform_data;
5808c2ecf20Sopenharmony_ci	struct dvb_frontend *fe = cfg->fe;
5818c2ecf20Sopenharmony_ci	struct m88rs6000t_dev *dev;
5828c2ecf20Sopenharmony_ci	int ret, i;
5838c2ecf20Sopenharmony_ci	unsigned int utmp;
5848c2ecf20Sopenharmony_ci	static const struct regmap_config regmap_config = {
5858c2ecf20Sopenharmony_ci		.reg_bits = 8,
5868c2ecf20Sopenharmony_ci		.val_bits = 8,
5878c2ecf20Sopenharmony_ci	};
5888c2ecf20Sopenharmony_ci	static const struct m88rs6000t_reg_val reg_vals[] = {
5898c2ecf20Sopenharmony_ci		{0x10, 0xfb},
5908c2ecf20Sopenharmony_ci		{0x24, 0x38},
5918c2ecf20Sopenharmony_ci		{0x11, 0x0a},
5928c2ecf20Sopenharmony_ci		{0x12, 0x00},
5938c2ecf20Sopenharmony_ci		{0x2b, 0x1c},
5948c2ecf20Sopenharmony_ci		{0x44, 0x48},
5958c2ecf20Sopenharmony_ci		{0x54, 0x24},
5968c2ecf20Sopenharmony_ci		{0x55, 0x06},
5978c2ecf20Sopenharmony_ci		{0x59, 0x00},
5988c2ecf20Sopenharmony_ci		{0x5b, 0x4c},
5998c2ecf20Sopenharmony_ci		{0x60, 0x8b},
6008c2ecf20Sopenharmony_ci		{0x61, 0xf4},
6018c2ecf20Sopenharmony_ci		{0x65, 0x07},
6028c2ecf20Sopenharmony_ci		{0x6d, 0x6f},
6038c2ecf20Sopenharmony_ci		{0x6e, 0x31},
6048c2ecf20Sopenharmony_ci		{0x3c, 0xf3},
6058c2ecf20Sopenharmony_ci		{0x37, 0x0f},
6068c2ecf20Sopenharmony_ci		{0x48, 0x28},
6078c2ecf20Sopenharmony_ci		{0x49, 0xd8},
6088c2ecf20Sopenharmony_ci		{0x70, 0x66},
6098c2ecf20Sopenharmony_ci		{0x71, 0xCF},
6108c2ecf20Sopenharmony_ci		{0x72, 0x81},
6118c2ecf20Sopenharmony_ci		{0x73, 0xA7},
6128c2ecf20Sopenharmony_ci		{0x74, 0x4F},
6138c2ecf20Sopenharmony_ci		{0x75, 0xFC},
6148c2ecf20Sopenharmony_ci	};
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
6178c2ecf20Sopenharmony_ci	if (!dev) {
6188c2ecf20Sopenharmony_ci		ret = -ENOMEM;
6198c2ecf20Sopenharmony_ci		dev_err(&client->dev, "kzalloc() failed\n");
6208c2ecf20Sopenharmony_ci		goto err;
6218c2ecf20Sopenharmony_ci	}
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	memcpy(&dev->cfg, cfg, sizeof(struct m88rs6000t_config));
6248c2ecf20Sopenharmony_ci	dev->client = client;
6258c2ecf20Sopenharmony_ci	dev->regmap = devm_regmap_init_i2c(client, &regmap_config);
6268c2ecf20Sopenharmony_ci	if (IS_ERR(dev->regmap)) {
6278c2ecf20Sopenharmony_ci		ret = PTR_ERR(dev->regmap);
6288c2ecf20Sopenharmony_ci		goto err;
6298c2ecf20Sopenharmony_ci	}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	ret = regmap_update_bits(dev->regmap, 0x11, 0x08, 0x08);
6328c2ecf20Sopenharmony_ci	if (ret)
6338c2ecf20Sopenharmony_ci		goto err;
6348c2ecf20Sopenharmony_ci	usleep_range(5000, 50000);
6358c2ecf20Sopenharmony_ci	ret = regmap_update_bits(dev->regmap, 0x10, 0x01, 0x01);
6368c2ecf20Sopenharmony_ci	if (ret)
6378c2ecf20Sopenharmony_ci		goto err;
6388c2ecf20Sopenharmony_ci	usleep_range(10000, 50000);
6398c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x07, 0x7d);
6408c2ecf20Sopenharmony_ci	if (ret)
6418c2ecf20Sopenharmony_ci		goto err;
6428c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x04, 0x01);
6438c2ecf20Sopenharmony_ci	if (ret)
6448c2ecf20Sopenharmony_ci		goto err;
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	/* check tuner chip id */
6478c2ecf20Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x01, &utmp);
6488c2ecf20Sopenharmony_ci	if (ret)
6498c2ecf20Sopenharmony_ci		goto err;
6508c2ecf20Sopenharmony_ci	dev_info(&dev->client->dev, "chip_id=%02x\n", utmp);
6518c2ecf20Sopenharmony_ci	if (utmp != 0x64) {
6528c2ecf20Sopenharmony_ci		ret = -ENODEV;
6538c2ecf20Sopenharmony_ci		goto err;
6548c2ecf20Sopenharmony_ci	}
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	/* tuner init. */
6578c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x05, 0x40);
6588c2ecf20Sopenharmony_ci	if (ret)
6598c2ecf20Sopenharmony_ci		goto err;
6608c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x11, 0x08);
6618c2ecf20Sopenharmony_ci	if (ret)
6628c2ecf20Sopenharmony_ci		goto err;
6638c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x15, 0x6c);
6648c2ecf20Sopenharmony_ci	if (ret)
6658c2ecf20Sopenharmony_ci		goto err;
6668c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x17, 0xc1);
6678c2ecf20Sopenharmony_ci	if (ret)
6688c2ecf20Sopenharmony_ci		goto err;
6698c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x17, 0x81);
6708c2ecf20Sopenharmony_ci	if (ret)
6718c2ecf20Sopenharmony_ci		goto err;
6728c2ecf20Sopenharmony_ci	usleep_range(10000, 50000);
6738c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x05, 0x00);
6748c2ecf20Sopenharmony_ci	if (ret)
6758c2ecf20Sopenharmony_ci		goto err;
6768c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x11, 0x0a);
6778c2ecf20Sopenharmony_ci	if (ret)
6788c2ecf20Sopenharmony_ci		goto err;
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(reg_vals); i++) {
6818c2ecf20Sopenharmony_ci		ret = regmap_write(dev->regmap,
6828c2ecf20Sopenharmony_ci				reg_vals[i].reg, reg_vals[i].val);
6838c2ecf20Sopenharmony_ci		if (ret)
6848c2ecf20Sopenharmony_ci			goto err;
6858c2ecf20Sopenharmony_ci	}
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	dev_info(&dev->client->dev, "Montage M88RS6000 internal tuner successfully identified\n");
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	fe->tuner_priv = dev;
6908c2ecf20Sopenharmony_ci	memcpy(&fe->ops.tuner_ops, &m88rs6000t_tuner_ops,
6918c2ecf20Sopenharmony_ci			sizeof(struct dvb_tuner_ops));
6928c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, dev);
6938c2ecf20Sopenharmony_ci	return 0;
6948c2ecf20Sopenharmony_cierr:
6958c2ecf20Sopenharmony_ci	dev_dbg(&client->dev, "failed=%d\n", ret);
6968c2ecf20Sopenharmony_ci	kfree(dev);
6978c2ecf20Sopenharmony_ci	return ret;
6988c2ecf20Sopenharmony_ci}
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_cistatic int m88rs6000t_remove(struct i2c_client *client)
7018c2ecf20Sopenharmony_ci{
7028c2ecf20Sopenharmony_ci	struct m88rs6000t_dev *dev = i2c_get_clientdata(client);
7038c2ecf20Sopenharmony_ci	struct dvb_frontend *fe = dev->cfg.fe;
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	dev_dbg(&client->dev, "\n");
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
7088c2ecf20Sopenharmony_ci	fe->tuner_priv = NULL;
7098c2ecf20Sopenharmony_ci	kfree(dev);
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	return 0;
7128c2ecf20Sopenharmony_ci}
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_cistatic const struct i2c_device_id m88rs6000t_id[] = {
7158c2ecf20Sopenharmony_ci	{"m88rs6000t", 0},
7168c2ecf20Sopenharmony_ci	{}
7178c2ecf20Sopenharmony_ci};
7188c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, m88rs6000t_id);
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_cistatic struct i2c_driver m88rs6000t_driver = {
7218c2ecf20Sopenharmony_ci	.driver = {
7228c2ecf20Sopenharmony_ci		.name	= "m88rs6000t",
7238c2ecf20Sopenharmony_ci	},
7248c2ecf20Sopenharmony_ci	.probe		= m88rs6000t_probe,
7258c2ecf20Sopenharmony_ci	.remove		= m88rs6000t_remove,
7268c2ecf20Sopenharmony_ci	.id_table	= m88rs6000t_id,
7278c2ecf20Sopenharmony_ci};
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_cimodule_i2c_driver(m88rs6000t_driver);
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ciMODULE_AUTHOR("Max nibble <nibble.max@gmail.com>");
7328c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Montage M88RS6000 internal tuner driver");
7338c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
734