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