18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * ITE IT913X silicon tuner driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2011 Malcolm Priestley (tvboxspy@gmail.com)
68c2ecf20Sopenharmony_ci *  IT9137 Copyright (C) ITE Tech Inc.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include "it913x.h"
108c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
118c2ecf20Sopenharmony_ci#include <linux/regmap.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistruct it913x_dev {
148c2ecf20Sopenharmony_ci	struct platform_device *pdev;
158c2ecf20Sopenharmony_ci	struct regmap *regmap;
168c2ecf20Sopenharmony_ci	struct dvb_frontend *fe;
178c2ecf20Sopenharmony_ci	u8 chip_ver:2;
188c2ecf20Sopenharmony_ci	u8 role:2;
198c2ecf20Sopenharmony_ci	u16 xtal;
208c2ecf20Sopenharmony_ci	u8 fdiv;
218c2ecf20Sopenharmony_ci	u8 clk_mode;
228c2ecf20Sopenharmony_ci	u32 fn_min;
238c2ecf20Sopenharmony_ci	bool active;
248c2ecf20Sopenharmony_ci};
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic int it913x_init(struct dvb_frontend *fe)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	struct it913x_dev *dev = fe->tuner_priv;
298c2ecf20Sopenharmony_ci	struct platform_device *pdev = dev->pdev;
308c2ecf20Sopenharmony_ci	int ret;
318c2ecf20Sopenharmony_ci	unsigned int utmp;
328c2ecf20Sopenharmony_ci	u8 iqik_m_cal, nv_val, buf[2];
338c2ecf20Sopenharmony_ci	static const u8 nv[] = {48, 32, 24, 16, 12, 8, 6, 4, 2};
348c2ecf20Sopenharmony_ci	unsigned long timeout;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	dev_dbg(&pdev->dev, "role %u\n", dev->role);
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x80ec4c, 0x68);
398c2ecf20Sopenharmony_ci	if (ret)
408c2ecf20Sopenharmony_ci		goto err;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	usleep_range(10000, 100000);
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x80ec86, &utmp);
458c2ecf20Sopenharmony_ci	if (ret)
468c2ecf20Sopenharmony_ci		goto err;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	switch (utmp) {
498c2ecf20Sopenharmony_ci	case 0:
508c2ecf20Sopenharmony_ci		/* 12.000 MHz */
518c2ecf20Sopenharmony_ci		dev->clk_mode = utmp;
528c2ecf20Sopenharmony_ci		dev->xtal = 2000;
538c2ecf20Sopenharmony_ci		dev->fdiv = 3;
548c2ecf20Sopenharmony_ci		iqik_m_cal = 16;
558c2ecf20Sopenharmony_ci		break;
568c2ecf20Sopenharmony_ci	case 1:
578c2ecf20Sopenharmony_ci		/* 20.480 MHz */
588c2ecf20Sopenharmony_ci		dev->clk_mode = utmp;
598c2ecf20Sopenharmony_ci		dev->xtal = 640;
608c2ecf20Sopenharmony_ci		dev->fdiv = 1;
618c2ecf20Sopenharmony_ci		iqik_m_cal = 6;
628c2ecf20Sopenharmony_ci		break;
638c2ecf20Sopenharmony_ci	default:
648c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "unknown clock identifier %d\n", utmp);
658c2ecf20Sopenharmony_ci		goto err;
668c2ecf20Sopenharmony_ci	}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x80ed03,  &utmp);
698c2ecf20Sopenharmony_ci	if (ret)
708c2ecf20Sopenharmony_ci		goto err;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	else if (utmp < ARRAY_SIZE(nv))
738c2ecf20Sopenharmony_ci		nv_val = nv[utmp];
748c2ecf20Sopenharmony_ci	else
758c2ecf20Sopenharmony_ci		nv_val = 2;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	#define TIMEOUT 50
788c2ecf20Sopenharmony_ci	timeout = jiffies + msecs_to_jiffies(TIMEOUT);
798c2ecf20Sopenharmony_ci	while (!time_after(jiffies, timeout)) {
808c2ecf20Sopenharmony_ci		ret = regmap_bulk_read(dev->regmap, 0x80ed23, buf, 2);
818c2ecf20Sopenharmony_ci		if (ret)
828c2ecf20Sopenharmony_ci			goto err;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci		utmp = (buf[1] << 8) | (buf[0] << 0);
858c2ecf20Sopenharmony_ci		if (utmp)
868c2ecf20Sopenharmony_ci			break;
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	dev_dbg(&pdev->dev, "r_fbc_m_bdry took %u ms, val %u\n",
908c2ecf20Sopenharmony_ci			jiffies_to_msecs(jiffies) -
918c2ecf20Sopenharmony_ci			(jiffies_to_msecs(timeout) - TIMEOUT), utmp);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	dev->fn_min = dev->xtal * utmp;
948c2ecf20Sopenharmony_ci	dev->fn_min /= (dev->fdiv * nv_val);
958c2ecf20Sopenharmony_ci	dev->fn_min *= 1000;
968c2ecf20Sopenharmony_ci	dev_dbg(&pdev->dev, "fn_min %u\n", dev->fn_min);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	/*
998c2ecf20Sopenharmony_ci	 * Chip version BX never sets that flag so we just wait 50ms in that
1008c2ecf20Sopenharmony_ci	 * case. It is possible poll BX similarly than AX and then timeout in
1018c2ecf20Sopenharmony_ci	 * order to get 50ms delay, but that causes about 120 extra I2C
1028c2ecf20Sopenharmony_ci	 * messages. As for now, we just wait and reduce IO.
1038c2ecf20Sopenharmony_ci	 */
1048c2ecf20Sopenharmony_ci	if (dev->chip_ver == 1) {
1058c2ecf20Sopenharmony_ci		#define TIMEOUT 50
1068c2ecf20Sopenharmony_ci		timeout = jiffies + msecs_to_jiffies(TIMEOUT);
1078c2ecf20Sopenharmony_ci		while (!time_after(jiffies, timeout)) {
1088c2ecf20Sopenharmony_ci			ret = regmap_read(dev->regmap, 0x80ec82, &utmp);
1098c2ecf20Sopenharmony_ci			if (ret)
1108c2ecf20Sopenharmony_ci				goto err;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci			if (utmp)
1138c2ecf20Sopenharmony_ci				break;
1148c2ecf20Sopenharmony_ci		}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci		dev_dbg(&pdev->dev, "p_tsm_init_mode took %u ms, val %u\n",
1178c2ecf20Sopenharmony_ci				jiffies_to_msecs(jiffies) -
1188c2ecf20Sopenharmony_ci				(jiffies_to_msecs(timeout) - TIMEOUT), utmp);
1198c2ecf20Sopenharmony_ci	} else {
1208c2ecf20Sopenharmony_ci		msleep(50);
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x80ed81, iqik_m_cal);
1248c2ecf20Sopenharmony_ci	if (ret)
1258c2ecf20Sopenharmony_ci		goto err;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x80ec57, 0x00);
1288c2ecf20Sopenharmony_ci	if (ret)
1298c2ecf20Sopenharmony_ci		goto err;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x80ec58, 0x00);
1328c2ecf20Sopenharmony_ci	if (ret)
1338c2ecf20Sopenharmony_ci		goto err;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x80ec40, 0x01);
1368c2ecf20Sopenharmony_ci	if (ret)
1378c2ecf20Sopenharmony_ci		goto err;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	dev->active = true;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	return 0;
1428c2ecf20Sopenharmony_cierr:
1438c2ecf20Sopenharmony_ci	dev_dbg(&pdev->dev, "failed %d\n", ret);
1448c2ecf20Sopenharmony_ci	return ret;
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic int it913x_sleep(struct dvb_frontend *fe)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	struct it913x_dev *dev = fe->tuner_priv;
1508c2ecf20Sopenharmony_ci	struct platform_device *pdev = dev->pdev;
1518c2ecf20Sopenharmony_ci	int ret, len;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	dev_dbg(&pdev->dev, "role %u\n", dev->role);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	dev->active = false;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	ret  = regmap_bulk_write(dev->regmap, 0x80ec40, "\x00", 1);
1588c2ecf20Sopenharmony_ci	if (ret)
1598c2ecf20Sopenharmony_ci		goto err;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	/*
1628c2ecf20Sopenharmony_ci	 * Writing '0x00' to master tuner register '0x80ec08' causes slave tuner
1638c2ecf20Sopenharmony_ci	 * communication lost. Due to that, we cannot put master full sleep.
1648c2ecf20Sopenharmony_ci	 */
1658c2ecf20Sopenharmony_ci	if (dev->role == IT913X_ROLE_DUAL_MASTER)
1668c2ecf20Sopenharmony_ci		len = 4;
1678c2ecf20Sopenharmony_ci	else
1688c2ecf20Sopenharmony_ci		len = 15;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	dev_dbg(&pdev->dev, "role %u, len %d\n", dev->role, len);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	ret = regmap_bulk_write(dev->regmap, 0x80ec02,
1738c2ecf20Sopenharmony_ci			"\x3f\x1f\x3f\x3e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
1748c2ecf20Sopenharmony_ci			len);
1758c2ecf20Sopenharmony_ci	if (ret)
1768c2ecf20Sopenharmony_ci		goto err;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	ret = regmap_bulk_write(dev->regmap, 0x80ec12, "\x00\x00\x00\x00", 4);
1798c2ecf20Sopenharmony_ci	if (ret)
1808c2ecf20Sopenharmony_ci		goto err;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	ret = regmap_bulk_write(dev->regmap, 0x80ec17,
1838c2ecf20Sopenharmony_ci			"\x00\x00\x00\x00\x00\x00\x00\x00\x00", 9);
1848c2ecf20Sopenharmony_ci	if (ret)
1858c2ecf20Sopenharmony_ci		goto err;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	ret = regmap_bulk_write(dev->regmap, 0x80ec22,
1888c2ecf20Sopenharmony_ci			"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 10);
1898c2ecf20Sopenharmony_ci	if (ret)
1908c2ecf20Sopenharmony_ci		goto err;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	ret = regmap_bulk_write(dev->regmap, 0x80ec20, "\x00", 1);
1938c2ecf20Sopenharmony_ci	if (ret)
1948c2ecf20Sopenharmony_ci		goto err;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	ret = regmap_bulk_write(dev->regmap, 0x80ec3f, "\x01", 1);
1978c2ecf20Sopenharmony_ci	if (ret)
1988c2ecf20Sopenharmony_ci		goto err;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	return 0;
2018c2ecf20Sopenharmony_cierr:
2028c2ecf20Sopenharmony_ci	dev_dbg(&pdev->dev, "failed %d\n", ret);
2038c2ecf20Sopenharmony_ci	return ret;
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic int it913x_set_params(struct dvb_frontend *fe)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	struct it913x_dev *dev = fe->tuner_priv;
2098c2ecf20Sopenharmony_ci	struct platform_device *pdev = dev->pdev;
2108c2ecf20Sopenharmony_ci	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
2118c2ecf20Sopenharmony_ci	int ret;
2128c2ecf20Sopenharmony_ci	unsigned int utmp;
2138c2ecf20Sopenharmony_ci	u32 pre_lo_freq, t_cal_freq;
2148c2ecf20Sopenharmony_ci	u16 iqik_m_cal, n_div;
2158c2ecf20Sopenharmony_ci	u8 u8tmp, n, l_band, lna_band;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	dev_dbg(&pdev->dev, "role=%u, frequency %u, bandwidth_hz %u\n",
2188c2ecf20Sopenharmony_ci			dev->role, c->frequency, c->bandwidth_hz);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	if (!dev->active) {
2218c2ecf20Sopenharmony_ci		ret = -EINVAL;
2228c2ecf20Sopenharmony_ci		goto err;
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	if (c->frequency <=         74000000) {
2268c2ecf20Sopenharmony_ci		n_div = 48;
2278c2ecf20Sopenharmony_ci		n = 0;
2288c2ecf20Sopenharmony_ci	} else if (c->frequency <= 111000000) {
2298c2ecf20Sopenharmony_ci		n_div = 32;
2308c2ecf20Sopenharmony_ci		n = 1;
2318c2ecf20Sopenharmony_ci	} else if (c->frequency <= 148000000) {
2328c2ecf20Sopenharmony_ci		n_div = 24;
2338c2ecf20Sopenharmony_ci		n = 2;
2348c2ecf20Sopenharmony_ci	} else if (c->frequency <= 222000000) {
2358c2ecf20Sopenharmony_ci		n_div = 16;
2368c2ecf20Sopenharmony_ci		n = 3;
2378c2ecf20Sopenharmony_ci	} else if (c->frequency <= 296000000) {
2388c2ecf20Sopenharmony_ci		n_div = 12;
2398c2ecf20Sopenharmony_ci		n = 4;
2408c2ecf20Sopenharmony_ci	} else if (c->frequency <= 445000000) {
2418c2ecf20Sopenharmony_ci		n_div = 8;
2428c2ecf20Sopenharmony_ci		n = 5;
2438c2ecf20Sopenharmony_ci	} else if (c->frequency <= dev->fn_min) {
2448c2ecf20Sopenharmony_ci		n_div = 6;
2458c2ecf20Sopenharmony_ci		n = 6;
2468c2ecf20Sopenharmony_ci	} else if (c->frequency <= 950000000) {
2478c2ecf20Sopenharmony_ci		n_div = 4;
2488c2ecf20Sopenharmony_ci		n = 7;
2498c2ecf20Sopenharmony_ci	} else {
2508c2ecf20Sopenharmony_ci		n_div = 2;
2518c2ecf20Sopenharmony_ci		n = 0;
2528c2ecf20Sopenharmony_ci	}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	ret = regmap_read(dev->regmap, 0x80ed81, &utmp);
2558c2ecf20Sopenharmony_ci	if (ret)
2568c2ecf20Sopenharmony_ci		goto err;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	iqik_m_cal = utmp * n_div;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	if (utmp < 0x20) {
2618c2ecf20Sopenharmony_ci		if (dev->clk_mode == 0)
2628c2ecf20Sopenharmony_ci			iqik_m_cal = (iqik_m_cal * 9) >> 5;
2638c2ecf20Sopenharmony_ci		else
2648c2ecf20Sopenharmony_ci			iqik_m_cal >>= 1;
2658c2ecf20Sopenharmony_ci	} else {
2668c2ecf20Sopenharmony_ci		iqik_m_cal = 0x40 - iqik_m_cal;
2678c2ecf20Sopenharmony_ci		if (dev->clk_mode == 0)
2688c2ecf20Sopenharmony_ci			iqik_m_cal = ~((iqik_m_cal * 9) >> 5);
2698c2ecf20Sopenharmony_ci		else
2708c2ecf20Sopenharmony_ci			iqik_m_cal = ~(iqik_m_cal >> 1);
2718c2ecf20Sopenharmony_ci	}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	t_cal_freq = (c->frequency / 1000) * n_div * dev->fdiv;
2748c2ecf20Sopenharmony_ci	pre_lo_freq = t_cal_freq / dev->xtal;
2758c2ecf20Sopenharmony_ci	utmp = pre_lo_freq * dev->xtal;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	if ((t_cal_freq - utmp) >= (dev->xtal >> 1))
2788c2ecf20Sopenharmony_ci		pre_lo_freq++;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	pre_lo_freq += (u32) n << 13;
2818c2ecf20Sopenharmony_ci	/* Frequency OMEGA_IQIK_M_CAL_MID*/
2828c2ecf20Sopenharmony_ci	t_cal_freq = pre_lo_freq + (u32)iqik_m_cal;
2838c2ecf20Sopenharmony_ci	dev_dbg(&pdev->dev, "t_cal_freq %u, pre_lo_freq %u\n",
2848c2ecf20Sopenharmony_ci			t_cal_freq, pre_lo_freq);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	if (c->frequency <=         440000000) {
2878c2ecf20Sopenharmony_ci		l_band = 0;
2888c2ecf20Sopenharmony_ci		lna_band = 0;
2898c2ecf20Sopenharmony_ci	} else if (c->frequency <=  484000000) {
2908c2ecf20Sopenharmony_ci		l_band = 1;
2918c2ecf20Sopenharmony_ci		lna_band = 1;
2928c2ecf20Sopenharmony_ci	} else if (c->frequency <=  533000000) {
2938c2ecf20Sopenharmony_ci		l_band = 1;
2948c2ecf20Sopenharmony_ci		lna_band = 2;
2958c2ecf20Sopenharmony_ci	} else if (c->frequency <=  587000000) {
2968c2ecf20Sopenharmony_ci		l_band = 1;
2978c2ecf20Sopenharmony_ci		lna_band = 3;
2988c2ecf20Sopenharmony_ci	} else if (c->frequency <=  645000000) {
2998c2ecf20Sopenharmony_ci		l_band = 1;
3008c2ecf20Sopenharmony_ci		lna_band = 4;
3018c2ecf20Sopenharmony_ci	} else if (c->frequency <=  710000000) {
3028c2ecf20Sopenharmony_ci		l_band = 1;
3038c2ecf20Sopenharmony_ci		lna_band = 5;
3048c2ecf20Sopenharmony_ci	} else if (c->frequency <=  782000000) {
3058c2ecf20Sopenharmony_ci		l_band = 1;
3068c2ecf20Sopenharmony_ci		lna_band = 6;
3078c2ecf20Sopenharmony_ci	} else if (c->frequency <=  860000000) {
3088c2ecf20Sopenharmony_ci		l_band = 1;
3098c2ecf20Sopenharmony_ci		lna_band = 7;
3108c2ecf20Sopenharmony_ci	} else if (c->frequency <= 1492000000) {
3118c2ecf20Sopenharmony_ci		l_band = 1;
3128c2ecf20Sopenharmony_ci		lna_band = 0;
3138c2ecf20Sopenharmony_ci	} else if (c->frequency <= 1685000000) {
3148c2ecf20Sopenharmony_ci		l_band = 1;
3158c2ecf20Sopenharmony_ci		lna_band = 1;
3168c2ecf20Sopenharmony_ci	} else {
3178c2ecf20Sopenharmony_ci		ret = -EINVAL;
3188c2ecf20Sopenharmony_ci		goto err;
3198c2ecf20Sopenharmony_ci	}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	/* XXX: latest windows driver does not set that at all */
3228c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x80ee06, lna_band);
3238c2ecf20Sopenharmony_ci	if (ret)
3248c2ecf20Sopenharmony_ci		goto err;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	if (c->bandwidth_hz <=      5000000)
3278c2ecf20Sopenharmony_ci		u8tmp = 0;
3288c2ecf20Sopenharmony_ci	else if (c->bandwidth_hz <= 6000000)
3298c2ecf20Sopenharmony_ci		u8tmp = 2;
3308c2ecf20Sopenharmony_ci	else if (c->bandwidth_hz <= 7000000)
3318c2ecf20Sopenharmony_ci		u8tmp = 4;
3328c2ecf20Sopenharmony_ci	else
3338c2ecf20Sopenharmony_ci		u8tmp = 6;       /* 8000000 */
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x80ec56, u8tmp);
3368c2ecf20Sopenharmony_ci	if (ret)
3378c2ecf20Sopenharmony_ci		goto err;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	/* XXX: latest windows driver sets different value (a8 != 68) */
3408c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x80ec4c, 0xa0 | (l_band << 3));
3418c2ecf20Sopenharmony_ci	if (ret)
3428c2ecf20Sopenharmony_ci		goto err;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x80ec4d, (t_cal_freq >> 0) & 0xff);
3458c2ecf20Sopenharmony_ci	if (ret)
3468c2ecf20Sopenharmony_ci		goto err;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x80ec4e, (t_cal_freq >> 8) & 0xff);
3498c2ecf20Sopenharmony_ci	if (ret)
3508c2ecf20Sopenharmony_ci		goto err;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x80011e, (pre_lo_freq >> 0) & 0xff);
3538c2ecf20Sopenharmony_ci	if (ret)
3548c2ecf20Sopenharmony_ci		goto err;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	ret = regmap_write(dev->regmap, 0x80011f, (pre_lo_freq >> 8) & 0xff);
3578c2ecf20Sopenharmony_ci	if (ret)
3588c2ecf20Sopenharmony_ci		goto err;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	return 0;
3618c2ecf20Sopenharmony_cierr:
3628c2ecf20Sopenharmony_ci	dev_dbg(&pdev->dev, "failed %d\n", ret);
3638c2ecf20Sopenharmony_ci	return ret;
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_cistatic const struct dvb_tuner_ops it913x_tuner_ops = {
3678c2ecf20Sopenharmony_ci	.info = {
3688c2ecf20Sopenharmony_ci		.name             = "ITE IT913X",
3698c2ecf20Sopenharmony_ci		.frequency_min_hz = 174 * MHz,
3708c2ecf20Sopenharmony_ci		.frequency_max_hz = 862 * MHz,
3718c2ecf20Sopenharmony_ci	},
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	.init = it913x_init,
3748c2ecf20Sopenharmony_ci	.sleep = it913x_sleep,
3758c2ecf20Sopenharmony_ci	.set_params = it913x_set_params,
3768c2ecf20Sopenharmony_ci};
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic int it913x_probe(struct platform_device *pdev)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	struct it913x_platform_data *pdata = pdev->dev.platform_data;
3818c2ecf20Sopenharmony_ci	struct dvb_frontend *fe = pdata->fe;
3828c2ecf20Sopenharmony_ci	struct it913x_dev *dev;
3838c2ecf20Sopenharmony_ci	const struct platform_device_id *id = platform_get_device_id(pdev);
3848c2ecf20Sopenharmony_ci	int ret;
3858c2ecf20Sopenharmony_ci	char *chip_ver_str;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	dev = kzalloc(sizeof(struct it913x_dev), GFP_KERNEL);
3888c2ecf20Sopenharmony_ci	if (dev == NULL) {
3898c2ecf20Sopenharmony_ci		ret = -ENOMEM;
3908c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "kzalloc() failed\n");
3918c2ecf20Sopenharmony_ci		goto err;
3928c2ecf20Sopenharmony_ci	}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	dev->pdev = pdev;
3958c2ecf20Sopenharmony_ci	dev->regmap = pdata->regmap;
3968c2ecf20Sopenharmony_ci	dev->fe = pdata->fe;
3978c2ecf20Sopenharmony_ci	dev->chip_ver = id->driver_data;
3988c2ecf20Sopenharmony_ci	dev->role = pdata->role;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	fe->tuner_priv = dev;
4018c2ecf20Sopenharmony_ci	memcpy(&fe->ops.tuner_ops, &it913x_tuner_ops,
4028c2ecf20Sopenharmony_ci			sizeof(struct dvb_tuner_ops));
4038c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, dev);
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	if (dev->chip_ver == 1)
4068c2ecf20Sopenharmony_ci		chip_ver_str = "AX";
4078c2ecf20Sopenharmony_ci	else if (dev->chip_ver == 2)
4088c2ecf20Sopenharmony_ci		chip_ver_str = "BX";
4098c2ecf20Sopenharmony_ci	else
4108c2ecf20Sopenharmony_ci		chip_ver_str = "??";
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	dev_info(&pdev->dev, "ITE IT913X %s successfully attached\n",
4138c2ecf20Sopenharmony_ci		 chip_ver_str);
4148c2ecf20Sopenharmony_ci	dev_dbg(&pdev->dev, "chip_ver %u, role %u\n", dev->chip_ver, dev->role);
4158c2ecf20Sopenharmony_ci	return 0;
4168c2ecf20Sopenharmony_cierr:
4178c2ecf20Sopenharmony_ci	dev_dbg(&pdev->dev, "failed %d\n", ret);
4188c2ecf20Sopenharmony_ci	return ret;
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_cistatic int it913x_remove(struct platform_device *pdev)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci	struct it913x_dev *dev = platform_get_drvdata(pdev);
4248c2ecf20Sopenharmony_ci	struct dvb_frontend *fe = dev->fe;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	dev_dbg(&pdev->dev, "\n");
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
4298c2ecf20Sopenharmony_ci	fe->tuner_priv = NULL;
4308c2ecf20Sopenharmony_ci	kfree(dev);
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	return 0;
4338c2ecf20Sopenharmony_ci}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_cistatic const struct platform_device_id it913x_id_table[] = {
4368c2ecf20Sopenharmony_ci	{"it9133ax-tuner", 1},
4378c2ecf20Sopenharmony_ci	{"it9133bx-tuner", 2},
4388c2ecf20Sopenharmony_ci	{},
4398c2ecf20Sopenharmony_ci};
4408c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(platform, it913x_id_table);
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic struct platform_driver it913x_driver = {
4438c2ecf20Sopenharmony_ci	.driver = {
4448c2ecf20Sopenharmony_ci		.name	= "it913x",
4458c2ecf20Sopenharmony_ci		.suppress_bind_attrs	= true,
4468c2ecf20Sopenharmony_ci	},
4478c2ecf20Sopenharmony_ci	.probe		= it913x_probe,
4488c2ecf20Sopenharmony_ci	.remove		= it913x_remove,
4498c2ecf20Sopenharmony_ci	.id_table	= it913x_id_table,
4508c2ecf20Sopenharmony_ci};
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_cimodule_platform_driver(it913x_driver);
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ITE IT913X silicon tuner driver");
4558c2ecf20Sopenharmony_ciMODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
4568c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
457